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
12 #include "nsIWeakReference.h"
13 #include "nsIWidget.h"
15 #include "nsThreadUtils.h"
16 #include "nsPresContext.h"
17 #include "mozilla/Attributes.h"
18 #include "mozilla/EventForwards.h"
19 #include "mozilla/TextRange.h"
25 class EventDispatchingCallback
;
26 class IMEStateManager
;
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
)
41 TextComposition(nsPresContext
* aPresContext
,
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;
76 * This is called when IMEStateManager stops managing the instance.
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
);
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
);
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.
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
136 CompositionChangeEventHandlingMarker(
137 TextComposition
* aComposition
,
138 const WidgetCompositionEvent
* aCompositionChangeEvent
)
139 : mComposition(aComposition
)
141 mComposition
->EditorWillHandleCompositionChangeEvent(
142 aCompositionChangeEvent
);
145 ~CompositionChangeEventHandlingMarker()
147 mComposition
->EditorDidHandleCompositionChangeEvent();
151 nsRefPtr
<TextComposition
> mComposition
;
152 CompositionChangeEventHandlingMarker();
153 CompositionChangeEventHandlingMarker(
154 const CompositionChangeEventHandlingMarker
& aOther
);
158 // Private destructor, to discourage deletion outside of Release():
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
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).
186 // mString stores the composition text which has been handled by the focused
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
194 uint32_t mCompositionTargetOffset
;
196 // See the comment for IsSynthesizedForTests().
197 bool mIsSynthesizedForTests
;
199 // See the comment for IsComposing().
202 // mIsEditorHandlingEvent is true while editor is modifying the composition
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.
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
,
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)
316 class CompositionEventDispatcher
: public nsRunnable
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
;
327 nsRefPtr
<TextComposition
> mTextComposition
;
328 nsCOMPtr
<nsINode
> mEventTarget
;
329 uint32_t mEventMessage
;
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,
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>
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
,
375 TextComposition
* GetCompositionInContent(nsPresContext
* aPresContext
,
376 nsIContent
* aContent
);
379 } // namespace mozilla
381 #endif // #ifndef mozilla_TextComposition_h