1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* vim: set ts=8 sts=2 et sw=2 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/. */
6 
7 #ifndef mozilla_TextComposition_h
8 #define mozilla_TextComposition_h
9 
10 #include "nsCOMPtr.h"
11 #include "nsINode.h"
12 #include "nsIWidget.h"
13 #include "nsTArray.h"
14 #include "nsThreadUtils.h"
15 #include "nsPresContext.h"
16 #include "mozilla/Attributes.h"
17 #include "mozilla/EventForwards.h"
18 #include "mozilla/RangeBoundary.h"
19 #include "mozilla/TextRange.h"
20 #include "mozilla/dom/BrowserParent.h"
21 #include "mozilla/dom/Text.h"
22 
23 namespace mozilla {
24 
25 class EditorBase;
26 class EventDispatchingCallback;
27 class IMEStateManager;
28 
29 /**
30  * TextComposition represents a text composition.  This class stores the
31  * composition event target and its presContext.  At dispatching the event via
32  * this class, the instances use the stored event target.
33  */
34 
35 class TextComposition final {
36   friend class IMEStateManager;
37 
38   NS_INLINE_DECL_REFCOUNTING(TextComposition)
39 
40  public:
41   typedef dom::BrowserParent BrowserParent;
42   typedef dom::Text Text;
43 
IsHandlingSelectionEvent()44   static bool IsHandlingSelectionEvent() { return sHandlingSelectionEvent; }
45 
46   TextComposition(nsPresContext* aPresContext, nsINode* aNode,
47                   BrowserParent* aBrowserParent,
48                   WidgetCompositionEvent* aCompositionEvent);
49 
Destroyed()50   bool Destroyed() const { return !mPresContext; }
GetPresContext()51   nsPresContext* GetPresContext() const { return mPresContext; }
GetEventTargetNode()52   nsINode* GetEventTargetNode() const { return mNode; }
53   // The text node which includes composition string.
GetContainerTextNode()54   Text* GetContainerTextNode() const { return mContainerTextNode; }
55   // The latest CompositionEvent.data value except compositionstart event.
56   // This value is modified at dispatching compositionupdate.
LastData()57   const nsString& LastData() const { return mLastData; }
58   // Returns commit string if it'll be commited as-is.
59   nsString CommitStringIfCommittedAsIs() const;
60   // The composition string which is already handled by the focused editor.
61   // I.e., this value must be same as the composition string on the focused
62   // editor.  This value is modified at a call of
63   // EditorDidHandleCompositionChangeEvent().
64   // Note that mString and mLastData are different between dispatcing
65   // compositionupdate and compositionchange event handled by focused editor.
String()66   const nsString& String() const { return mString; }
67   // The latest clauses range of the composition string.
68   // During compositionupdate event, GetRanges() returns old ranges.
69   // So if getting on compositionupdate, Use GetLastRange instead of GetRange().
GetLastRanges()70   TextRangeArray* GetLastRanges() const { return mLastRanges; }
71   // Returns the clauses and/or caret range of the composition string.
72   // This is modified at a call of EditorWillHandleCompositionChangeEvent().
73   // This may return null if there is no clauses and caret.
74   // XXX We should return |const TextRangeArray*| here, but it causes compile
75   //     error due to inaccessible Release() method.
GetRanges()76   TextRangeArray* GetRanges() const { return mRanges; }
77   // Returns the widget which is proper to call NotifyIME().
GetWidget()78   nsIWidget* GetWidget() const {
79     return mPresContext ? mPresContext->GetRootWidget() : nullptr;
80   }
81   // Returns the tab parent which has this composition in its remote process.
GetBrowserParent()82   BrowserParent* GetBrowserParent() const { return mBrowserParent; }
83   // Returns true if the composition is started with synthesized event which
84   // came from nsDOMWindowUtils.
IsSynthesizedForTests()85   bool IsSynthesizedForTests() const { return mIsSynthesizedForTests; }
86 
GetNativeIMEContext()87   const widget::NativeIMEContext& GetNativeIMEContext() const {
88     return mNativeContext;
89   }
90 
91   /**
92    * This is called when IMEStateManager stops managing the instance.
93    */
94   void Destroy();
95 
96   /**
97    * Request to commit (or cancel) the composition to IME.  This method should
98    * be called only by IMEStateManager::NotifyIME().
99    */
100   nsresult RequestToCommit(nsIWidget* aWidget, bool aDiscard);
101 
102   /**
103    * IsRequestingCommitOrCancelComposition() returns true if the instance is
104    * requesting widget to commit or cancel composition.
105    */
IsRequestingCommitOrCancelComposition()106   bool IsRequestingCommitOrCancelComposition() const {
107     return mIsRequestingCancel || mIsRequestingCommit;
108   }
109 
110   /**
111    * Send a notification to IME.  It depends on the IME or platform spec what
112    * will occur (or not occur).
113    */
114   nsresult NotifyIME(widget::IMEMessage aMessage);
115 
116   /**
117    * the offset of first composition string
118    */
NativeOffsetOfStartComposition()119   uint32_t NativeOffsetOfStartComposition() const {
120     return mCompositionStartOffset;
121   }
122 
123   /**
124    * the offset of first selected clause or start of composition
125    */
NativeOffsetOfTargetClause()126   uint32_t NativeOffsetOfTargetClause() const {
127     return mCompositionStartOffset + mTargetClauseOffsetInComposition;
128   }
129 
130   /**
131    * Return current composition start and end point in the DOM tree.
132    * Note that one of or both of those result container may be different
133    * from GetContainerTextNode() if the DOM tree was modified by the web
134    * app.  If there is no composition string the DOM tree, these return
135    * unset range boundaries.
136    */
137   RawRangeBoundary GetStartRef() const;
138   RawRangeBoundary GetEndRef() const;
139 
140   /**
141    * The offset of composition string in the text node.  If composition string
142    * hasn't been inserted in any text node yet, this returns UINT32_MAX.
143    */
XPOffsetInTextNode()144   uint32_t XPOffsetInTextNode() const {
145     return mCompositionStartOffsetInTextNode;
146   }
147 
148   /**
149    * The length of composition string in the text node.  If composition string
150    * hasn't been inserted in any text node yet, this returns 0.
151    */
XPLengthInTextNode()152   uint32_t XPLengthInTextNode() const {
153     return mCompositionLengthInTextNode == UINT32_MAX
154                ? 0
155                : mCompositionLengthInTextNode;
156   }
157 
158   /**
159    * The end offset of composition string in the text node.  If composition
160    * string hasn't been inserted in any text node yet, this returns UINT32_MAX.
161    */
XPEndOffsetInTextNode()162   uint32_t XPEndOffsetInTextNode() const {
163     if (mCompositionStartOffsetInTextNode == UINT32_MAX ||
164         mCompositionLengthInTextNode == UINT32_MAX) {
165       return UINT32_MAX;
166     }
167     return mCompositionStartOffsetInTextNode + mCompositionLengthInTextNode;
168   }
169 
170   /**
171    * Returns true if there is non-empty composition string and it's not fixed.
172    * Otherwise, false.
173    */
IsComposing()174   bool IsComposing() const { return mIsComposing; }
175 
176   /**
177    * Returns true while editor is handling an event which is modifying the
178    * composition string.
179    */
IsEditorHandlingEvent()180   bool IsEditorHandlingEvent() const { return mIsEditorHandlingEvent; }
181 
182   /**
183    * IsMovingToNewTextNode() returns true if editor detects the text node
184    * has been removed and still not insert the composition string into
185    * new text node.
186    */
IsMovingToNewTextNode()187   bool IsMovingToNewTextNode() const {
188     return !mContainerTextNode && mCompositionLengthInTextNode &&
189            mCompositionLengthInTextNode != UINT32_MAX;
190   }
191 
192   /**
193    * StartHandlingComposition() and EndHandlingComposition() are called by
194    * editor when it holds a TextComposition instance and release it.
195    */
196   void StartHandlingComposition(EditorBase* aEditorBase);
197   void EndHandlingComposition(EditorBase* aEditorBase);
198 
199   /**
200    * OnEditorDestroyed() is called when the editor is destroyed but there is
201    * active composition.
202    */
203   void OnEditorDestroyed();
204 
205   /**
206    * CompositionChangeEventHandlingMarker class should be created at starting
207    * to handle text event in focused editor.  This calls
208    * EditorWillHandleCompositionChangeEvent() and
209    * EditorDidHandleCompositionChangeEvent() automatically.
210    */
211   class MOZ_STACK_CLASS CompositionChangeEventHandlingMarker {
212    public:
CompositionChangeEventHandlingMarker(TextComposition * aComposition,const WidgetCompositionEvent * aCompositionChangeEvent)213     CompositionChangeEventHandlingMarker(
214         TextComposition* aComposition,
215         const WidgetCompositionEvent* aCompositionChangeEvent)
216         : mComposition(aComposition) {
217       mComposition->EditorWillHandleCompositionChangeEvent(
218           aCompositionChangeEvent);
219     }
220 
~CompositionChangeEventHandlingMarker()221     ~CompositionChangeEventHandlingMarker() {
222       mComposition->EditorDidHandleCompositionChangeEvent();
223     }
224 
225    private:
226     RefPtr<TextComposition> mComposition;
227     CompositionChangeEventHandlingMarker();
228     CompositionChangeEventHandlingMarker(
229         const CompositionChangeEventHandlingMarker& aOther);
230   };
231 
232   /**
233    * OnCreateCompositionTransaction() is called by
234    * CompositionTransaction::Create() immediately after creating
235    * new CompositionTransaction instance.
236    *
237    * @param aStringToInsert     The string to insert the text node actually.
238    *                            This may be different from the data of
239    *                            dispatching composition event because it may
240    *                            be replaced with different character for
241    *                            passwords, or truncated due to maxlength.
242    * @param aTextNode           The text node which includes composition string.
243    * @param aOffset             The offset of composition string in aTextNode.
244    */
OnCreateCompositionTransaction(const nsAString & aStringToInsert,Text * aTextNode,uint32_t aOffset)245   void OnCreateCompositionTransaction(const nsAString& aStringToInsert,
246                                       Text* aTextNode, uint32_t aOffset) {
247     if (!mContainerTextNode) {
248       mContainerTextNode = aTextNode;
249       mCompositionStartOffsetInTextNode = aOffset;
250       NS_WARNING_ASSERTION(mCompositionStartOffsetInTextNode != UINT32_MAX,
251                            "The text node is really too long.");
252     }
253 #ifdef DEBUG
254     else {
255       MOZ_ASSERT(aTextNode == mContainerTextNode);
256       MOZ_ASSERT(aOffset == mCompositionStartOffsetInTextNode);
257     }
258 #endif  // #ifdef DEBUG
259     mCompositionLengthInTextNode = aStringToInsert.Length();
260     NS_WARNING_ASSERTION(mCompositionLengthInTextNode != UINT32_MAX,
261                          "The string to insert is really too long.");
262   }
263 
264   /**
265    * OnTextNodeRemoved() is called when focused editor is reframed and
266    * mContainerTextNode may be (or have been) replaced with different text
267    * node, or just removes the text node due to empty.
268    */
OnTextNodeRemoved()269   void OnTextNodeRemoved() {
270     mContainerTextNode = nullptr;
271     // Don't reset mCompositionStartOffsetInTextNode nor
272     // mCompositionLengthInTextNode because editor needs them to restore
273     // composition in new text node.
274   }
275 
276  private:
277   // Private destructor, to discourage deletion outside of Release():
~TextComposition()278   ~TextComposition() {
279     // WARNING: mPresContext may be destroying, so, be careful if you touch it.
280   }
281 
282   // sHandlingSelectionEvent is true while TextComposition sends a selection
283   // event to ContentEventHandler.
284   static bool sHandlingSelectionEvent;
285 
286   // This class holds nsPresContext weak.  This instance shouldn't block
287   // destroying it.  When the presContext is being destroyed, it's notified to
288   // IMEStateManager::OnDestroyPresContext(), and then, it destroy
289   // this instance.
290   nsPresContext* mPresContext;
291   nsCOMPtr<nsINode> mNode;
292   RefPtr<BrowserParent> mBrowserParent;
293 
294   // The text node which includes the composition string.
295   RefPtr<Text> mContainerTextNode;
296 
297   // This is the clause and caret range information which is managed by
298   // the focused editor.  This may be null if there is no clauses or caret.
299   RefPtr<TextRangeArray> mRanges;
300   // Same as mRange, but mRange will have old data during compositionupdate.
301   // So this will be valied during compositionupdate.
302   RefPtr<TextRangeArray> mLastRanges;
303 
304   // mNativeContext stores a opaque pointer.  This works as the "ID" for this
305   // composition.  Don't access the instance, it may not be available.
306   widget::NativeIMEContext mNativeContext;
307 
308   // mEditorBaseWeak is a weak reference to the focused editor handling
309   // composition.
310   nsWeakPtr mEditorBaseWeak;
311 
312   // mLastData stores the data attribute of the latest composition event (except
313   // the compositionstart event).
314   nsString mLastData;
315 
316   // mString stores the composition text which has been handled by the focused
317   // editor.
318   nsString mString;
319 
320   // Offset of the composition string from start of the editor
321   uint32_t mCompositionStartOffset;
322   // Offset of the selected clause of the composition string from
323   // mCompositionStartOffset
324   uint32_t mTargetClauseOffsetInComposition;
325   // Offset of the composition string in mContainerTextNode.
326   // NOTE: This is NOT valid in the main process if focused editor is in a
327   //       remote process.
328   uint32_t mCompositionStartOffsetInTextNode;
329   // Length of the composition string in mContainerTextNode.  If this instance
330   // has already dispatched eCompositionCommit(AsIs) and
331   // EditorDidHandleCompositionChangeEvent() has already been called,
332   // this may be different from length of mString because committed string
333   // may be truncated by maxlength attribute of <input> or <textarea>.
334   // NOTE: This is NOT valid in the main process if focused editor is in a
335   //       remote process.
336   uint32_t mCompositionLengthInTextNode;
337 
338   // See the comment for IsSynthesizedForTests().
339   bool mIsSynthesizedForTests;
340 
341   // See the comment for IsComposing().
342   bool mIsComposing;
343 
344   // mIsEditorHandlingEvent is true while editor is modifying the composition
345   // string.
346   bool mIsEditorHandlingEvent;
347 
348   // mIsRequestingCommit or mIsRequestingCancel is true *only* while we're
349   // requesting commit or canceling the composition.  In other words, while
350   // one of these values is true, we're handling the request.
351   bool mIsRequestingCommit;
352   bool mIsRequestingCancel;
353 
354   // mRequestedToCommitOrCancel is true *after* we requested IME to commit or
355   // cancel the composition.  In other words, we already requested of IME that
356   // it commits or cancels current composition.
357   // NOTE: Before this is set to true, both mIsRequestingCommit and
358   //       mIsRequestingCancel are set to false.
359   bool mRequestedToCommitOrCancel;
360 
361   // Set to true if the instance dispatches an eCompositionChange event.
362   bool mHasDispatchedDOMTextEvent;
363 
364   // Before this dispatches commit event into the tree, this is set to true.
365   // So, this means if native IME already commits the composition.
366   bool mHasReceivedCommitEvent;
367 
368   // mWasNativeCompositionEndEventDiscarded is true if this composition was
369   // requested commit or cancel itself but native compositionend event is
370   // discarded by PresShell due to not safe to dispatch events.
371   bool mWasNativeCompositionEndEventDiscarded;
372 
373   // Allow control characters appear in composition string.
374   // When this is false, control characters except
375   // CHARACTER TABULATION (horizontal tab) are removed from
376   // both composition string and data attribute of compositionupdate
377   // and compositionend events.
378   bool mAllowControlCharacters;
379 
380   // mWasCompositionStringEmpty is true if the composition string was empty
381   // when DispatchCompositionEvent() is called.
382   bool mWasCompositionStringEmpty;
383 
384   // Hide the default constructor and copy constructor.
TextComposition()385   TextComposition()
386       : mPresContext(nullptr),
387         mNativeContext(nullptr),
388         mCompositionStartOffset(0),
389         mTargetClauseOffsetInComposition(0),
390         mCompositionStartOffsetInTextNode(UINT32_MAX),
391         mCompositionLengthInTextNode(UINT32_MAX),
392         mIsSynthesizedForTests(false),
393         mIsComposing(false),
394         mIsEditorHandlingEvent(false),
395         mIsRequestingCommit(false),
396         mIsRequestingCancel(false),
397         mRequestedToCommitOrCancel(false),
398         mHasReceivedCommitEvent(false),
399         mWasNativeCompositionEndEventDiscarded(false),
400         mAllowControlCharacters(false),
401         mWasCompositionStringEmpty(true) {}
402   TextComposition(const TextComposition& aOther);
403 
404   /**
405    * If we're requesting IME to commit or cancel composition, or we've already
406    * requested it, or we've already known this composition has been ended in
407    * IME, we don't need to request commit nor cancel composition anymore and
408    * shouldn't do so if we're in content process for not committing/canceling
409    * "current" composition in native IME.  So, when this returns true,
410    * RequestIMEToCommit() does nothing.
411    */
CanRequsetIMEToCommitOrCancelComposition()412   bool CanRequsetIMEToCommitOrCancelComposition() const {
413     return !mIsRequestingCommit && !mIsRequestingCancel &&
414            !mRequestedToCommitOrCancel && !mHasReceivedCommitEvent;
415   }
416 
417   /**
418    * GetEditorBase() returns EditorBase pointer of mEditorBaseWeak.
419    */
420   already_AddRefed<EditorBase> GetEditorBase() const;
421 
422   /**
423    * HasEditor() returns true if mEditorBaseWeak holds EditorBase instance
424    * which is alive.  Otherwise, false.
425    */
426   bool HasEditor() const;
427 
428   /**
429    * EditorWillHandleCompositionChangeEvent() must be called before the focused
430    * editor handles the compositionchange event.
431    */
432   void EditorWillHandleCompositionChangeEvent(
433       const WidgetCompositionEvent* aCompositionChangeEvent);
434 
435   /**
436    * EditorDidHandleCompositionChangeEvent() must be called after the focused
437    * editor handles a compositionchange event.
438    */
439   void EditorDidHandleCompositionChangeEvent();
440 
441   /**
442    * IsValidStateForComposition() returns true if it's safe to dispatch an event
443    * to the DOM tree.  Otherwise, false.
444    * WARNING: This doesn't check script blocker state.  It should be checked
445    *          before dispatching the first event.
446    */
447   bool IsValidStateForComposition(nsIWidget* aWidget) const;
448 
449   /**
450    * DispatchCompositionEvent() dispatches the aCompositionEvent to the mContent
451    * synchronously. The caller must ensure that it's safe to dispatch the event.
452    */
453   MOZ_CAN_RUN_SCRIPT void DispatchCompositionEvent(
454       WidgetCompositionEvent* aCompositionEvent, nsEventStatus* aStatus,
455       EventDispatchingCallback* aCallBack, bool aIsSynthesized);
456 
457   /**
458    * Simply calling EventDispatcher::Dispatch() with plugin event.
459    * If dispatching event has no orginal clone, aOriginalEvent can be null.
460    */
461   MOZ_CAN_RUN_SCRIPT void DispatchEvent(
462       WidgetCompositionEvent* aDispatchEvent, nsEventStatus* aStatus,
463       EventDispatchingCallback* aCallback,
464       const WidgetCompositionEvent* aOriginalEvent = nullptr);
465 
466   /**
467    * HandleSelectionEvent() sends the selection event to ContentEventHandler
468    * or dispatches it to the focused child process.
469    */
470   MOZ_CAN_RUN_SCRIPT
HandleSelectionEvent(WidgetSelectionEvent * aSelectionEvent)471   void HandleSelectionEvent(WidgetSelectionEvent* aSelectionEvent) {
472     RefPtr<nsPresContext> presContext(mPresContext);
473     RefPtr<BrowserParent> browserParent(mBrowserParent);
474     HandleSelectionEvent(presContext, browserParent, aSelectionEvent);
475   }
476   MOZ_CAN_RUN_SCRIPT
477   static void HandleSelectionEvent(nsPresContext* aPresContext,
478                                    BrowserParent* aBrowserParent,
479                                    WidgetSelectionEvent* aSelectionEvent);
480 
481   /**
482    * MaybeDispatchCompositionUpdate() may dispatch a compositionupdate event
483    * if aCompositionEvent changes composition string.
484    * @return Returns false if dispatching the compositionupdate event caused
485    *         destroying this composition.
486    */
487   MOZ_CAN_RUN_SCRIPT bool MaybeDispatchCompositionUpdate(
488       const WidgetCompositionEvent* aCompositionEvent);
489 
490   /**
491    * CloneAndDispatchAs() dispatches a composition event which is
492    * duplicateed from aCompositionEvent and set the aMessage.
493    *
494    * @return Returns BaseEventFlags which is the result of dispatched event.
495    */
496   MOZ_CAN_RUN_SCRIPT BaseEventFlags
497   CloneAndDispatchAs(const WidgetCompositionEvent* aCompositionEvent,
498                      EventMessage aMessage, nsEventStatus* aStatus = nullptr,
499                      EventDispatchingCallback* aCallBack = nullptr);
500 
501   /**
502    * If IME has already dispatched compositionend event but it was discarded
503    * by PresShell due to not safe to dispatch, this returns true.
504    */
WasNativeCompositionEndEventDiscarded()505   bool WasNativeCompositionEndEventDiscarded() const {
506     return mWasNativeCompositionEndEventDiscarded;
507   }
508 
509   /**
510    * OnCompositionEventDiscarded() is called when PresShell discards
511    * compositionupdate, compositionend or compositionchange event due to not
512    * safe to dispatch event.
513    */
514   void OnCompositionEventDiscarded(WidgetCompositionEvent* aCompositionEvent);
515 
516   /**
517    * OnCompositionEventDispatched() is called after a composition event is
518    * dispatched.
519    */
520   MOZ_CAN_RUN_SCRIPT void OnCompositionEventDispatched(
521       const WidgetCompositionEvent* aDispatchEvent);
522 
523   /**
524    * MaybeNotifyIMEOfCompositionEventHandled() notifies IME of composition
525    * event handled.  This should be called after dispatching a composition
526    * event which came from widget.
527    */
528   void MaybeNotifyIMEOfCompositionEventHandled(
529       const WidgetCompositionEvent* aCompositionEvent);
530 
531   /**
532    * GetSelectionStartOffset() returns normal selection start offset in the
533    * editor which has this composition.
534    * If it failed or lost focus, this would return 0.
535    */
536   MOZ_CAN_RUN_SCRIPT uint32_t GetSelectionStartOffset();
537 
538   /**
539    * OnStartOffsetUpdatedInChild() is called when composition start offset
540    * is updated in the child process.  I.e., this is called and never called
541    * if the composition is in this process.
542    * @param aStartOffset        New composition start offset with native
543    *                            linebreaks.
544    */
545   void OnStartOffsetUpdatedInChild(uint32_t aStartOffset);
546 
547   /**
548    * CompositionEventDispatcher dispatches the specified composition (or text)
549    * event.
550    */
551   class CompositionEventDispatcher : public Runnable {
552    public:
553     CompositionEventDispatcher(TextComposition* aTextComposition,
554                                nsINode* aEventTarget,
555                                EventMessage aEventMessage,
556                                const nsAString& aData,
557                                bool aIsSynthesizedEvent = false);
558     MOZ_CAN_RUN_SCRIPT_BOUNDARY NS_IMETHOD Run() override;
559 
560    private:
561     RefPtr<TextComposition> mTextComposition;
562     nsCOMPtr<nsINode> mEventTarget;
563     nsString mData;
564     EventMessage mEventMessage;
565     bool mIsSynthesizedEvent;
566 
CompositionEventDispatcher()567     CompositionEventDispatcher()
568         : Runnable("TextComposition::CompositionEventDispatcher"),
569           mEventMessage(eVoidEvent),
570           mIsSynthesizedEvent(false){};
571   };
572 
573   /**
574    * DispatchCompositionEventRunnable() dispatches a composition event to the
575    * content.  Be aware, if you use this method, nsPresShellEventCB isn't used.
576    * That means that nsIFrame::HandleEvent() is never called.
577    * WARNING: The instance which is managed by IMEStateManager may be
578    *          destroyed by this method call.
579    *
580    * @param aEventMessage       Must be one of composition events.
581    * @param aData               Used for mData value.
582    * @param aIsSynthesizingCommit   true if this is called for synthesizing
583    *                                commit or cancel composition.  Otherwise,
584    *                                false.
585    */
586   void DispatchCompositionEventRunnable(EventMessage aEventMessage,
587                                         const nsAString& aData,
588                                         bool aIsSynthesizingCommit = false);
589 };
590 
591 /**
592  * TextCompositionArray manages the instances of TextComposition class.
593  * Managing with array is enough because only one composition is typically
594  * there.  Even if user switches native IME context, it's very rare that
595  * second or more composition is started.
596  * It's assumed that this is used by IMEStateManager for storing all active
597  * compositions in the process.  If the instance is it, each TextComposition
598  * in the array can be destroyed by calling some methods of itself.
599  */
600 
601 class TextCompositionArray final
602     : public AutoTArray<RefPtr<TextComposition>, 2> {
603  public:
604   // Looking for per native IME context.
605   index_type IndexOf(const widget::NativeIMEContext& aNativeIMEContext);
606   index_type IndexOf(nsIWidget* aWidget);
607 
608   TextComposition* GetCompositionFor(nsIWidget* aWidget);
609   TextComposition* GetCompositionFor(
610       const WidgetCompositionEvent* aCompositionEvent);
611 
612   // Looking for per nsPresContext
613   index_type IndexOf(nsPresContext* aPresContext);
614   index_type IndexOf(nsPresContext* aPresContext, nsINode* aNode);
615 
616   TextComposition* GetCompositionFor(nsPresContext* aPresContext);
617   TextComposition* GetCompositionFor(nsPresContext* aPresContext,
618                                      nsINode* aNode);
619   TextComposition* GetCompositionInContent(nsPresContext* aPresContext,
620                                            nsIContent* aContent);
621 };
622 
623 }  // namespace mozilla
624 
625 #endif  // #ifndef mozilla_TextComposition_h
626