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 WidgetGUIEvent
* aEvent
);
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 EditorDidHandleTextEvent().
54 // Note that mString and mLastData are different between dispatcing
55 // compositionupdate and text event handled by focused editor.
56 const nsString
& String() const { return mString
; }
57 // Returns the clauses and/or caret range of the composition string.
58 // This is modified at a call of EditorWillHandleTextEvent().
59 // This may return null if there is no clauses and caret.
60 // XXX We should return |const TextRangeArray*| here, but it causes compile
61 // error due to inaccessible Release() method.
62 TextRangeArray
* GetRanges() const { return mRanges
; }
63 // Returns true if the composition is started with synthesized event which
64 // came from nsDOMWindowUtils.
65 bool IsSynthesizedForTests() const { return mIsSynthesizedForTests
; }
67 bool MatchesNativeContext(nsIWidget
* aWidget
) const;
70 * This is called when IMEStateManager stops managing the instance.
75 * SynthesizeCommit() dispatches compositionupdate, text and compositionend
76 * events for emulating commit on the content.
78 * @param aDiscard true when committing with empty string. Otherwise, false.
80 void SynthesizeCommit(bool aDiscard
);
83 * Send a notification to IME. It depends on the IME or platform spec what
84 * will occur (or not occur).
86 nsresult
NotifyIME(widget::IMEMessage aMessage
);
89 * the offset of first selected clause or start of of compositon
91 uint32_t OffsetOfTargetClause() const { return mCompositionTargetOffset
; }
94 * Returns true if there is non-empty composition string and it's not fixed.
97 bool IsComposing() const { return mIsComposing
; }
100 * Returns true while editor is handling an event which is modifying the
101 * composition string.
103 bool IsEditorHandlingEvent() const
105 return mIsEditorHandlingEvent
;
109 * StartHandlingComposition() and EndHandlingComposition() are called by
110 * editor when it holds a TextComposition instance and release it.
112 void StartHandlingComposition(nsIEditor
* aEditor
);
113 void EndHandlingComposition(nsIEditor
* aEditor
);
116 * TextEventHandlingMarker class should be created at starting to handle text
117 * event in focused editor. This calls EditorWillHandleTextEvent() and
118 * EditorDidHandleTextEvent() automatically.
120 class MOZ_STACK_CLASS TextEventHandlingMarker
123 TextEventHandlingMarker(TextComposition
* aComposition
,
124 const WidgetTextEvent
* aTextEvent
)
125 : mComposition(aComposition
)
127 mComposition
->EditorWillHandleTextEvent(aTextEvent
);
130 ~TextEventHandlingMarker()
132 mComposition
->EditorDidHandleTextEvent();
136 nsRefPtr
<TextComposition
> mComposition
;
137 TextEventHandlingMarker();
138 TextEventHandlingMarker(const TextEventHandlingMarker
& aOther
);
142 // Private destructor, to discourage deletion outside of Release():
145 // WARNING: mPresContext may be destroying, so, be careful if you touch it.
148 // This class holds nsPresContext weak. This instance shouldn't block
149 // destroying it. When the presContext is being destroyed, it's notified to
150 // IMEStateManager::OnDestroyPresContext(), and then, it destroy
152 nsPresContext
* mPresContext
;
153 nsCOMPtr
<nsINode
> mNode
;
155 // This is the clause and caret range information which is managed by
156 // the focused editor. This may be null if there is no clauses or caret.
157 nsRefPtr
<TextRangeArray
> mRanges
;
159 // mNativeContext stores a opaque pointer. This works as the "ID" for this
160 // composition. Don't access the instance, it may not be available.
161 void* mNativeContext
;
163 // mEditorWeak is a weak reference to the focused editor handling composition.
164 nsWeakPtr mEditorWeak
;
166 // mLastData stores the data attribute of the latest composition event (except
167 // the compositionstart event).
170 // mString stores the composition text which has been handled by the focused
174 // Offset of the composition string from start of the editor
175 uint32_t mCompositionStartOffset
;
176 // Offset of the selected clause of the composition string from start of the
178 uint32_t mCompositionTargetOffset
;
180 // See the comment for IsSynthesizedForTests().
181 bool mIsSynthesizedForTests
;
183 // See the comment for IsComposing().
186 // mIsEditorHandlingEvent is true while editor is modifying the composition
188 bool mIsEditorHandlingEvent
;
190 // Hide the default constructor and copy constructor.
192 TextComposition(const TextComposition
& aOther
);
195 * GetEditor() returns nsIEditor pointer of mEditorWeak.
197 already_AddRefed
<nsIEditor
> GetEditor() const;
200 * HasEditor() returns true if mEditorWeak holds nsIEditor instance which is
201 * alive. Otherwise, false.
203 bool HasEditor() const;
206 * EditorWillHandleTextEvent() must be called before the focused editor
207 * handles the text event.
209 void EditorWillHandleTextEvent(const WidgetTextEvent
* aTextEvent
);
212 * EditorDidHandleTextEvent() must be called after the focused editor handles
215 void EditorDidHandleTextEvent();
218 * DispatchEvent() dispatches the aEvent to the mContent synchronously.
219 * The caller must ensure that it's safe to dispatch the event.
221 void DispatchEvent(WidgetGUIEvent
* aEvent
,
222 nsEventStatus
* aStatus
,
223 EventDispatchingCallback
* aCallBack
);
226 * Calculate composition offset then notify composition update to widget
228 void NotityUpdateComposition(WidgetGUIEvent
* aEvent
);
231 * CompositionEventDispatcher dispatches the specified composition (or text)
234 class CompositionEventDispatcher
: public nsRunnable
237 CompositionEventDispatcher(nsPresContext
* aPresContext
,
238 nsINode
* aEventTarget
,
239 uint32_t aEventMessage
,
240 const nsAString
& aData
);
241 NS_IMETHOD
Run() MOZ_OVERRIDE
;
244 nsRefPtr
<nsPresContext
> mPresContext
;
245 nsCOMPtr
<nsINode
> mEventTarget
;
246 nsCOMPtr
<nsIWidget
> mWidget
;
247 uint32_t mEventMessage
;
250 CompositionEventDispatcher() {};
254 * DispatchCompositionEventRunnable() dispatches a composition or text event
255 * to the content. Be aware, if you use this method, nsPresShellEventCB
256 * isn't used. That means that nsIFrame::HandleEvent() is never called.
257 * WARNING: The instance which is managed by IMEStateManager may be
258 * destroyed by this method call.
260 * @param aEventMessage Must be one of composition event or text event.
261 * @param aData Used for data value if aEventMessage is
262 * NS_COMPOSITION_UPDATE or NS_COMPOSITION_END.
263 * Used for theText value if aEventMessage is
266 void DispatchCompositionEventRunnable(uint32_t aEventMessage
,
267 const nsAString
& aData
);
271 * TextCompositionArray manages the instances of TextComposition class.
272 * Managing with array is enough because only one composition is typically
273 * there. Even if user switches native IME context, it's very rare that
274 * second or more composition is started.
275 * It's assumed that this is used by IMEStateManager for storing all active
276 * compositions in the process. If the instance is it, each TextComposition
277 * in the array can be destroyed by calling some methods of itself.
280 class TextCompositionArray MOZ_FINAL
:
281 public nsAutoTArray
<nsRefPtr
<TextComposition
>, 2>
284 index_type
IndexOf(nsIWidget
* aWidget
);
285 index_type
IndexOf(nsPresContext
* aPresContext
);
286 index_type
IndexOf(nsPresContext
* aPresContext
, nsINode
* aNode
);
288 TextComposition
* GetCompositionFor(nsIWidget
* aWidget
);
289 TextComposition
* GetCompositionFor(nsPresContext
* aPresContext
,
291 TextComposition
* GetCompositionInContent(nsPresContext
* aPresContext
,
292 nsIContent
* aContent
);
295 } // namespace mozilla
297 #endif // #ifndef mozilla_TextComposition_h