tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

TextComposition.h (24885B)


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