1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/dom/events/TextComposition.h Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,297 @@ 1.4 +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ 1.5 +/* vim: set ts=2 sw=2 et tw=80: */ 1.6 +/* This Source Code Form is subject to the terms of the Mozilla Public 1.7 + * License, v. 2.0. If a copy of the MPL was not distributed with this 1.8 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 1.9 + 1.10 +#ifndef mozilla_TextComposition_h 1.11 +#define mozilla_TextComposition_h 1.12 + 1.13 +#include "nsCOMPtr.h" 1.14 +#include "nsINode.h" 1.15 +#include "nsIWeakReference.h" 1.16 +#include "nsIWidget.h" 1.17 +#include "nsTArray.h" 1.18 +#include "nsThreadUtils.h" 1.19 +#include "nsPresContext.h" 1.20 +#include "mozilla/Attributes.h" 1.21 +#include "mozilla/EventForwards.h" 1.22 +#include "mozilla/TextRange.h" 1.23 + 1.24 +class nsIEditor; 1.25 + 1.26 +namespace mozilla { 1.27 + 1.28 +class EventDispatchingCallback; 1.29 +class IMEStateManager; 1.30 + 1.31 +/** 1.32 + * TextComposition represents a text composition. This class stores the 1.33 + * composition event target and its presContext. At dispatching the event via 1.34 + * this class, the instances use the stored event target. 1.35 + */ 1.36 + 1.37 +class TextComposition MOZ_FINAL 1.38 +{ 1.39 + friend class IMEStateManager; 1.40 + 1.41 + NS_INLINE_DECL_REFCOUNTING(TextComposition) 1.42 + 1.43 +public: 1.44 + TextComposition(nsPresContext* aPresContext, 1.45 + nsINode* aNode, 1.46 + WidgetGUIEvent* aEvent); 1.47 + 1.48 + bool Destroyed() const { return !mPresContext; } 1.49 + nsPresContext* GetPresContext() const { return mPresContext; } 1.50 + nsINode* GetEventTargetNode() const { return mNode; } 1.51 + // The latest CompositionEvent.data value except compositionstart event. 1.52 + // This value is modified at dispatching compositionupdate. 1.53 + const nsString& LastData() const { return mLastData; } 1.54 + // The composition string which is already handled by the focused editor. 1.55 + // I.e., this value must be same as the composition string on the focused 1.56 + // editor. This value is modified at a call of EditorDidHandleTextEvent(). 1.57 + // Note that mString and mLastData are different between dispatcing 1.58 + // compositionupdate and text event handled by focused editor. 1.59 + const nsString& String() const { return mString; } 1.60 + // Returns the clauses and/or caret range of the composition string. 1.61 + // This is modified at a call of EditorWillHandleTextEvent(). 1.62 + // This may return null if there is no clauses and caret. 1.63 + // XXX We should return |const TextRangeArray*| here, but it causes compile 1.64 + // error due to inaccessible Release() method. 1.65 + TextRangeArray* GetRanges() const { return mRanges; } 1.66 + // Returns true if the composition is started with synthesized event which 1.67 + // came from nsDOMWindowUtils. 1.68 + bool IsSynthesizedForTests() const { return mIsSynthesizedForTests; } 1.69 + 1.70 + bool MatchesNativeContext(nsIWidget* aWidget) const; 1.71 + 1.72 + /** 1.73 + * This is called when IMEStateManager stops managing the instance. 1.74 + */ 1.75 + void Destroy(); 1.76 + 1.77 + /** 1.78 + * SynthesizeCommit() dispatches compositionupdate, text and compositionend 1.79 + * events for emulating commit on the content. 1.80 + * 1.81 + * @param aDiscard true when committing with empty string. Otherwise, false. 1.82 + */ 1.83 + void SynthesizeCommit(bool aDiscard); 1.84 + 1.85 + /** 1.86 + * Send a notification to IME. It depends on the IME or platform spec what 1.87 + * will occur (or not occur). 1.88 + */ 1.89 + nsresult NotifyIME(widget::IMEMessage aMessage); 1.90 + 1.91 + /** 1.92 + * the offset of first selected clause or start of of compositon 1.93 + */ 1.94 + uint32_t OffsetOfTargetClause() const { return mCompositionTargetOffset; } 1.95 + 1.96 + /** 1.97 + * Returns true if there is non-empty composition string and it's not fixed. 1.98 + * Otherwise, false. 1.99 + */ 1.100 + bool IsComposing() const { return mIsComposing; } 1.101 + 1.102 + /** 1.103 + * Returns true while editor is handling an event which is modifying the 1.104 + * composition string. 1.105 + */ 1.106 + bool IsEditorHandlingEvent() const 1.107 + { 1.108 + return mIsEditorHandlingEvent; 1.109 + } 1.110 + 1.111 + /** 1.112 + * StartHandlingComposition() and EndHandlingComposition() are called by 1.113 + * editor when it holds a TextComposition instance and release it. 1.114 + */ 1.115 + void StartHandlingComposition(nsIEditor* aEditor); 1.116 + void EndHandlingComposition(nsIEditor* aEditor); 1.117 + 1.118 + /** 1.119 + * TextEventHandlingMarker class should be created at starting to handle text 1.120 + * event in focused editor. This calls EditorWillHandleTextEvent() and 1.121 + * EditorDidHandleTextEvent() automatically. 1.122 + */ 1.123 + class MOZ_STACK_CLASS TextEventHandlingMarker 1.124 + { 1.125 + public: 1.126 + TextEventHandlingMarker(TextComposition* aComposition, 1.127 + const WidgetTextEvent* aTextEvent) 1.128 + : mComposition(aComposition) 1.129 + { 1.130 + mComposition->EditorWillHandleTextEvent(aTextEvent); 1.131 + } 1.132 + 1.133 + ~TextEventHandlingMarker() 1.134 + { 1.135 + mComposition->EditorDidHandleTextEvent(); 1.136 + } 1.137 + 1.138 + private: 1.139 + nsRefPtr<TextComposition> mComposition; 1.140 + TextEventHandlingMarker(); 1.141 + TextEventHandlingMarker(const TextEventHandlingMarker& aOther); 1.142 + }; 1.143 + 1.144 +private: 1.145 + // Private destructor, to discourage deletion outside of Release(): 1.146 + ~TextComposition() 1.147 + { 1.148 + // WARNING: mPresContext may be destroying, so, be careful if you touch it. 1.149 + } 1.150 + 1.151 + // This class holds nsPresContext weak. This instance shouldn't block 1.152 + // destroying it. When the presContext is being destroyed, it's notified to 1.153 + // IMEStateManager::OnDestroyPresContext(), and then, it destroy 1.154 + // this instance. 1.155 + nsPresContext* mPresContext; 1.156 + nsCOMPtr<nsINode> mNode; 1.157 + 1.158 + // This is the clause and caret range information which is managed by 1.159 + // the focused editor. This may be null if there is no clauses or caret. 1.160 + nsRefPtr<TextRangeArray> mRanges; 1.161 + 1.162 + // mNativeContext stores a opaque pointer. This works as the "ID" for this 1.163 + // composition. Don't access the instance, it may not be available. 1.164 + void* mNativeContext; 1.165 + 1.166 + // mEditorWeak is a weak reference to the focused editor handling composition. 1.167 + nsWeakPtr mEditorWeak; 1.168 + 1.169 + // mLastData stores the data attribute of the latest composition event (except 1.170 + // the compositionstart event). 1.171 + nsString mLastData; 1.172 + 1.173 + // mString stores the composition text which has been handled by the focused 1.174 + // editor. 1.175 + nsString mString; 1.176 + 1.177 + // Offset of the composition string from start of the editor 1.178 + uint32_t mCompositionStartOffset; 1.179 + // Offset of the selected clause of the composition string from start of the 1.180 + // editor 1.181 + uint32_t mCompositionTargetOffset; 1.182 + 1.183 + // See the comment for IsSynthesizedForTests(). 1.184 + bool mIsSynthesizedForTests; 1.185 + 1.186 + // See the comment for IsComposing(). 1.187 + bool mIsComposing; 1.188 + 1.189 + // mIsEditorHandlingEvent is true while editor is modifying the composition 1.190 + // string. 1.191 + bool mIsEditorHandlingEvent; 1.192 + 1.193 + // Hide the default constructor and copy constructor. 1.194 + TextComposition() {} 1.195 + TextComposition(const TextComposition& aOther); 1.196 + 1.197 + /** 1.198 + * GetEditor() returns nsIEditor pointer of mEditorWeak. 1.199 + */ 1.200 + already_AddRefed<nsIEditor> GetEditor() const; 1.201 + 1.202 + /** 1.203 + * HasEditor() returns true if mEditorWeak holds nsIEditor instance which is 1.204 + * alive. Otherwise, false. 1.205 + */ 1.206 + bool HasEditor() const; 1.207 + 1.208 + /** 1.209 + * EditorWillHandleTextEvent() must be called before the focused editor 1.210 + * handles the text event. 1.211 + */ 1.212 + void EditorWillHandleTextEvent(const WidgetTextEvent* aTextEvent); 1.213 + 1.214 + /** 1.215 + * EditorDidHandleTextEvent() must be called after the focused editor handles 1.216 + * a text event. 1.217 + */ 1.218 + void EditorDidHandleTextEvent(); 1.219 + 1.220 + /** 1.221 + * DispatchEvent() dispatches the aEvent to the mContent synchronously. 1.222 + * The caller must ensure that it's safe to dispatch the event. 1.223 + */ 1.224 + void DispatchEvent(WidgetGUIEvent* aEvent, 1.225 + nsEventStatus* aStatus, 1.226 + EventDispatchingCallback* aCallBack); 1.227 + 1.228 + /** 1.229 + * Calculate composition offset then notify composition update to widget 1.230 + */ 1.231 + void NotityUpdateComposition(WidgetGUIEvent* aEvent); 1.232 + 1.233 + /** 1.234 + * CompositionEventDispatcher dispatches the specified composition (or text) 1.235 + * event. 1.236 + */ 1.237 + class CompositionEventDispatcher : public nsRunnable 1.238 + { 1.239 + public: 1.240 + CompositionEventDispatcher(nsPresContext* aPresContext, 1.241 + nsINode* aEventTarget, 1.242 + uint32_t aEventMessage, 1.243 + const nsAString& aData); 1.244 + NS_IMETHOD Run() MOZ_OVERRIDE; 1.245 + 1.246 + private: 1.247 + nsRefPtr<nsPresContext> mPresContext; 1.248 + nsCOMPtr<nsINode> mEventTarget; 1.249 + nsCOMPtr<nsIWidget> mWidget; 1.250 + uint32_t mEventMessage; 1.251 + nsString mData; 1.252 + 1.253 + CompositionEventDispatcher() {}; 1.254 + }; 1.255 + 1.256 + /** 1.257 + * DispatchCompositionEventRunnable() dispatches a composition or text event 1.258 + * to the content. Be aware, if you use this method, nsPresShellEventCB 1.259 + * isn't used. That means that nsIFrame::HandleEvent() is never called. 1.260 + * WARNING: The instance which is managed by IMEStateManager may be 1.261 + * destroyed by this method call. 1.262 + * 1.263 + * @param aEventMessage Must be one of composition event or text event. 1.264 + * @param aData Used for data value if aEventMessage is 1.265 + * NS_COMPOSITION_UPDATE or NS_COMPOSITION_END. 1.266 + * Used for theText value if aEventMessage is 1.267 + * NS_TEXT_TEXT. 1.268 + */ 1.269 + void DispatchCompositionEventRunnable(uint32_t aEventMessage, 1.270 + const nsAString& aData); 1.271 +}; 1.272 + 1.273 +/** 1.274 + * TextCompositionArray manages the instances of TextComposition class. 1.275 + * Managing with array is enough because only one composition is typically 1.276 + * there. Even if user switches native IME context, it's very rare that 1.277 + * second or more composition is started. 1.278 + * It's assumed that this is used by IMEStateManager for storing all active 1.279 + * compositions in the process. If the instance is it, each TextComposition 1.280 + * in the array can be destroyed by calling some methods of itself. 1.281 + */ 1.282 + 1.283 +class TextCompositionArray MOZ_FINAL : 1.284 + public nsAutoTArray<nsRefPtr<TextComposition>, 2> 1.285 +{ 1.286 +public: 1.287 + index_type IndexOf(nsIWidget* aWidget); 1.288 + index_type IndexOf(nsPresContext* aPresContext); 1.289 + index_type IndexOf(nsPresContext* aPresContext, nsINode* aNode); 1.290 + 1.291 + TextComposition* GetCompositionFor(nsIWidget* aWidget); 1.292 + TextComposition* GetCompositionFor(nsPresContext* aPresContext, 1.293 + nsINode* aNode); 1.294 + TextComposition* GetCompositionInContent(nsPresContext* aPresContext, 1.295 + nsIContent* aContent); 1.296 +}; 1.297 + 1.298 +} // namespace mozilla 1.299 + 1.300 +#endif // #ifndef mozilla_TextComposition_h