Bumping manifests a=b2g-bump
[gecko.git] / dom / events / TextComposition.h
blobadedefe8a519f6d82cb89e2771ad585ede9b02c0
1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* vim: set ts=2 sw=2 et tw=80: */
3 /* This Source Code Form is subject to the terms of the Mozilla Public
4 * License, v. 2.0. If a copy of the MPL was not distributed with this
5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
7 #ifndef mozilla_TextComposition_h
8 #define mozilla_TextComposition_h
10 #include "nsCOMPtr.h"
11 #include "nsINode.h"
12 #include "nsIWeakReference.h"
13 #include "nsIWidget.h"
14 #include "nsTArray.h"
15 #include "nsThreadUtils.h"
16 #include "nsPresContext.h"
17 #include "mozilla/Attributes.h"
18 #include "mozilla/EventForwards.h"
19 #include "mozilla/TextRange.h"
21 class nsIEditor;
23 namespace mozilla {
25 class EventDispatchingCallback;
26 class IMEStateManager;
28 /**
29 * TextComposition represents a text composition. This class stores the
30 * composition event target and its presContext. At dispatching the event via
31 * this class, the instances use the stored event target.
34 class TextComposition MOZ_FINAL
36 friend class IMEStateManager;
38 NS_INLINE_DECL_REFCOUNTING(TextComposition)
40 public:
41 TextComposition(nsPresContext* aPresContext,
42 nsINode* aNode,
43 WidgetCompositionEvent* aCompositionEvent);
45 bool Destroyed() const { return !mPresContext; }
46 nsPresContext* GetPresContext() const { return mPresContext; }
47 nsINode* GetEventTargetNode() const { return mNode; }
48 // The latest CompositionEvent.data value except compositionstart event.
49 // This value is modified at dispatching compositionupdate.
50 const nsString& LastData() const { return mLastData; }
51 // The composition string which is already handled by the focused editor.
52 // I.e., this value must be same as the composition string on the focused
53 // editor. This value is modified at a call of
54 // EditorDidHandleCompositionChangeEvent().
55 // Note that mString and mLastData are different between dispatcing
56 // compositionupdate and compositionchange event handled by focused editor.
57 const nsString& String() const { return mString; }
58 // Returns the clauses and/or caret range of the composition string.
59 // This is modified at a call of EditorWillHandleCompositionChangeEvent().
60 // This may return null if there is no clauses and caret.
61 // XXX We should return |const TextRangeArray*| here, but it causes compile
62 // error due to inaccessible Release() method.
63 TextRangeArray* GetRanges() const { return mRanges; }
64 // Returns the widget which is proper to call NotifyIME().
65 nsIWidget* GetWidget() const
67 return mPresContext ? mPresContext->GetRootWidget() : nullptr;
69 // Returns true if the composition is started with synthesized event which
70 // came from nsDOMWindowUtils.
71 bool IsSynthesizedForTests() const { return mIsSynthesizedForTests; }
73 bool MatchesNativeContext(nsIWidget* aWidget) const;
75 /**
76 * This is called when IMEStateManager stops managing the instance.
78 void Destroy();
80 /**
81 * Request to commit (or cancel) the composition to IME. This method should
82 * be called only by IMEStateManager::NotifyIME().
84 nsresult RequestToCommit(nsIWidget* aWidget, bool aDiscard);
86 /**
87 * Send a notification to IME. It depends on the IME or platform spec what
88 * will occur (or not occur).
90 nsresult NotifyIME(widget::IMEMessage aMessage);
92 /**
93 * the offset of first composition string
95 uint32_t NativeOffsetOfStartComposition() const
97 return mCompositionStartOffset;
101 * the offset of first selected clause or start of of compositon
103 uint32_t OffsetOfTargetClause() const { return mCompositionTargetOffset; }
106 * Returns true if there is non-empty composition string and it's not fixed.
107 * Otherwise, false.
109 bool IsComposing() const { return mIsComposing; }
112 * Returns true while editor is handling an event which is modifying the
113 * composition string.
115 bool IsEditorHandlingEvent() const
117 return mIsEditorHandlingEvent;
121 * StartHandlingComposition() and EndHandlingComposition() are called by
122 * editor when it holds a TextComposition instance and release it.
124 void StartHandlingComposition(nsIEditor* aEditor);
125 void EndHandlingComposition(nsIEditor* aEditor);
128 * CompositionChangeEventHandlingMarker class should be created at starting
129 * to handle text event in focused editor. This calls
130 * EditorWillHandleCompositionChangeEvent() and
131 * EditorDidHandleCompositionChangeEvent() automatically.
133 class MOZ_STACK_CLASS CompositionChangeEventHandlingMarker
135 public:
136 CompositionChangeEventHandlingMarker(
137 TextComposition* aComposition,
138 const WidgetCompositionEvent* aCompositionChangeEvent)
139 : mComposition(aComposition)
141 mComposition->EditorWillHandleCompositionChangeEvent(
142 aCompositionChangeEvent);
145 ~CompositionChangeEventHandlingMarker()
147 mComposition->EditorDidHandleCompositionChangeEvent();
150 private:
151 nsRefPtr<TextComposition> mComposition;
152 CompositionChangeEventHandlingMarker();
153 CompositionChangeEventHandlingMarker(
154 const CompositionChangeEventHandlingMarker& aOther);
157 private:
158 // Private destructor, to discourage deletion outside of Release():
159 ~TextComposition()
161 // WARNING: mPresContext may be destroying, so, be careful if you touch it.
164 // This class holds nsPresContext weak. This instance shouldn't block
165 // destroying it. When the presContext is being destroyed, it's notified to
166 // IMEStateManager::OnDestroyPresContext(), and then, it destroy
167 // this instance.
168 nsPresContext* mPresContext;
169 nsCOMPtr<nsINode> mNode;
171 // This is the clause and caret range information which is managed by
172 // the focused editor. This may be null if there is no clauses or caret.
173 nsRefPtr<TextRangeArray> mRanges;
175 // mNativeContext stores a opaque pointer. This works as the "ID" for this
176 // composition. Don't access the instance, it may not be available.
177 void* mNativeContext;
179 // mEditorWeak is a weak reference to the focused editor handling composition.
180 nsWeakPtr mEditorWeak;
182 // mLastData stores the data attribute of the latest composition event (except
183 // the compositionstart event).
184 nsString mLastData;
186 // mString stores the composition text which has been handled by the focused
187 // editor.
188 nsString mString;
190 // Offset of the composition string from start of the editor
191 uint32_t mCompositionStartOffset;
192 // Offset of the selected clause of the composition string from start of the
193 // editor
194 uint32_t mCompositionTargetOffset;
196 // See the comment for IsSynthesizedForTests().
197 bool mIsSynthesizedForTests;
199 // See the comment for IsComposing().
200 bool mIsComposing;
202 // mIsEditorHandlingEvent is true while editor is modifying the composition
203 // string.
204 bool mIsEditorHandlingEvent;
206 // mIsRequestingCommit or mIsRequestingCancel is true *only* while we're
207 // requesting commit or canceling the composition. In other words, while
208 // one of these values is true, we're handling the request.
209 bool mIsRequestingCommit;
210 bool mIsRequestingCancel;
212 // mRequestedToCommitOrCancel is true *after* we requested IME to commit or
213 // cancel the composition. In other words, we already requested of IME that
214 // it commits or cancels current composition.
215 // NOTE: Before this is set true, both mIsRequestingCommit and
216 // mIsRequestingCancel are set false.
217 bool mRequestedToCommitOrCancel;
219 // mWasNativeCompositionEndEventDiscarded is true if this composition was
220 // requested commit or cancel itself but native compositionend event is
221 // discarded by PresShell due to not safe to dispatch events.
222 bool mWasNativeCompositionEndEventDiscarded;
224 // Hide the default constructor and copy constructor.
225 TextComposition() {}
226 TextComposition(const TextComposition& aOther);
229 * GetEditor() returns nsIEditor pointer of mEditorWeak.
231 already_AddRefed<nsIEditor> GetEditor() const;
234 * HasEditor() returns true if mEditorWeak holds nsIEditor instance which is
235 * alive. Otherwise, false.
237 bool HasEditor() const;
240 * EditorWillHandleCompositionChangeEvent() must be called before the focused
241 * editor handles the compositionchange event.
243 void EditorWillHandleCompositionChangeEvent(
244 const WidgetCompositionEvent* aCompositionChangeEvent);
247 * EditorDidHandleCompositionChangeEvent() must be called after the focused
248 * editor handles a compositionchange event.
250 void EditorDidHandleCompositionChangeEvent();
253 * IsValidStateForComposition() returns true if it's safe to dispatch an event
254 * to the DOM tree. Otherwise, false.
255 * WARNING: This doesn't check script blocker state. It should be checked
256 * before dispatching the first event.
258 bool IsValidStateForComposition(nsIWidget* aWidget) const;
261 * DispatchCompositionEvent() dispatches the aCompositionEvent to the mContent
262 * synchronously. The caller must ensure that it's safe to dispatch the event.
264 void DispatchCompositionEvent(WidgetCompositionEvent* aCompositionEvent,
265 nsEventStatus* aStatus,
266 EventDispatchingCallback* aCallBack,
267 bool aIsSynthesized);
270 * MaybeDispatchCompositionUpdate() may dispatch a compositionupdate event
271 * if aCompositionEvent changes composition string.
272 * @return Returns false if dispatching the compositionupdate event caused
273 * destroying this composition.
275 bool MaybeDispatchCompositionUpdate(
276 const WidgetCompositionEvent* aCompositionEvent);
279 * CloneAndDispatchAs() dispatches a composition event which is
280 * duplicateed from aCompositionEvent and set the aMessage.
282 * @return Returns BaseEventFlags which is the result of dispatched event.
284 BaseEventFlags CloneAndDispatchAs(
285 const WidgetCompositionEvent* aCompositionEvent,
286 uint32_t aMessage,
287 nsEventStatus* aStatus = nullptr,
288 EventDispatchingCallback* aCallBack = nullptr);
291 * If IME has already dispatched compositionend event but it was discarded
292 * by PresShell due to not safe to dispatch, this returns true.
294 bool WasNativeCompositionEndEventDiscarded() const
296 return mWasNativeCompositionEndEventDiscarded;
300 * OnCompositionEventDiscarded() is called when PresShell discards
301 * compositionupdate, compositionend or compositionchange event due to not
302 * safe to dispatch event.
304 void OnCompositionEventDiscarded(
305 const WidgetCompositionEvent* aCompositionEvent);
308 * Calculate composition offset then notify composition update to widget
310 void NotityUpdateComposition(const WidgetCompositionEvent* aCompositionEvent);
313 * CompositionEventDispatcher dispatches the specified composition (or text)
314 * event.
316 class CompositionEventDispatcher : public nsRunnable
318 public:
319 CompositionEventDispatcher(TextComposition* aTextComposition,
320 nsINode* aEventTarget,
321 uint32_t aEventMessage,
322 const nsAString& aData,
323 bool aIsSynthesizedEvent = false);
324 NS_IMETHOD Run() MOZ_OVERRIDE;
326 private:
327 nsRefPtr<TextComposition> mTextComposition;
328 nsCOMPtr<nsINode> mEventTarget;
329 uint32_t mEventMessage;
330 nsString mData;
331 bool mIsSynthesizedEvent;
333 CompositionEventDispatcher() {};
337 * DispatchCompositionEventRunnable() dispatches a composition event to the
338 * content. Be aware, if you use this method, nsPresShellEventCB isn't used.
339 * That means that nsIFrame::HandleEvent() is never called.
340 * WARNING: The instance which is managed by IMEStateManager may be
341 * destroyed by this method call.
343 * @param aEventMessage Must be one of composition events.
344 * @param aData Used for mData value.
345 * @param aIsSynthesizingCommit true if this is called for synthesizing
346 * commit or cancel composition. Otherwise,
347 * false.
349 void DispatchCompositionEventRunnable(uint32_t aEventMessage,
350 const nsAString& aData,
351 bool aIsSynthesizingCommit = false);
355 * TextCompositionArray manages the instances of TextComposition class.
356 * Managing with array is enough because only one composition is typically
357 * there. Even if user switches native IME context, it's very rare that
358 * second or more composition is started.
359 * It's assumed that this is used by IMEStateManager for storing all active
360 * compositions in the process. If the instance is it, each TextComposition
361 * in the array can be destroyed by calling some methods of itself.
364 class TextCompositionArray MOZ_FINAL :
365 public nsAutoTArray<nsRefPtr<TextComposition>, 2>
367 public:
368 index_type IndexOf(nsIWidget* aWidget);
369 index_type IndexOf(nsPresContext* aPresContext);
370 index_type IndexOf(nsPresContext* aPresContext, nsINode* aNode);
372 TextComposition* GetCompositionFor(nsIWidget* aWidget);
373 TextComposition* GetCompositionFor(nsPresContext* aPresContext,
374 nsINode* aNode);
375 TextComposition* GetCompositionInContent(nsPresContext* aPresContext,
376 nsIContent* aContent);
379 } // namespace mozilla
381 #endif // #ifndef mozilla_TextComposition_h