tor-browser

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

IMEStateManager.h (23206B)


      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_IMEStateManager_h_
      8 #define mozilla_IMEStateManager_h_
      9 
     10 #include "mozilla/AlreadyAddRefed.h"
     11 #include "mozilla/EventForwards.h"
     12 #include "mozilla/Maybe.h"
     13 #include "mozilla/StaticPtr.h"
     14 #include "mozilla/dom/BrowserParent.h"
     15 #include "nsIWidget.h"
     16 
     17 class nsIContent;
     18 class nsINode;
     19 class nsIURI;
     20 class nsPresContext;
     21 
     22 namespace mozilla {
     23 
     24 class EditorBase;
     25 class EventDispatchingCallback;
     26 class IMEContentObserver;
     27 class PseudoFocusChangeRunnable;
     28 class TextCompositionArray;
     29 class TextComposition;
     30 
     31 namespace dom {
     32 class Element;
     33 class Selection;
     34 }  // namespace dom
     35 
     36 /**
     37 * IMEStateManager manages InputContext (e.g., active editor type, IME enabled
     38 * state and IME open state) of nsIWidget instances, manages IMEContentObserver
     39 * and provides useful API for IME.
     40 */
     41 
     42 class IMEStateManager {
     43  using BrowserParent = dom::BrowserParent;
     44  using IMEMessage = widget::IMEMessage;
     45  using IMENotification = widget::IMENotification;
     46  using IMEState = widget::IMEState;
     47  using InputContext = widget::InputContext;
     48  using InputContextAction = widget::InputContextAction;
     49 
     50 public:
     51  static void Init();
     52  static void Shutdown();
     53 
     54  /**
     55   * GetActiveBrowserParent() returns a pointer to a BrowserParent instance
     56   * which is managed by the focused content (sFocusedElement).  If the focused
     57   * content isn't managing another process, this returns nullptr.
     58   */
     59  static BrowserParent* GetActiveBrowserParent() {
     60    // If menu has pseudo focus, we should ignore active child process.
     61    if (sInstalledMenuKeyboardListener) {
     62      return nullptr;
     63    }
     64    // If we know focused browser parent, use it for making any events related
     65    // to composition go to same content process.
     66    if (sFocusedIMEBrowserParent) {
     67      return sFocusedIMEBrowserParent;
     68    }
     69    return BrowserParent::GetFocused();
     70  }
     71 
     72  /**
     73   * DoesBrowserParentHaveIMEFocus() returns true when aBrowserParent has IME
     74   * focus, i.e., the BrowserParent sent "focus" notification but not yet sends
     75   * "blur". Note that this doesn't check if the remote processes are same
     76   * because if another BrowserParent has focus, committing composition causes
     77   * firing composition events in different BrowserParent.  (Anyway, such case
     78   * shouldn't occur.)
     79   */
     80  static bool DoesBrowserParentHaveIMEFocus(
     81      const BrowserParent* aBrowserParent) {
     82    MOZ_ASSERT(aBrowserParent);
     83    return sFocusedIMEBrowserParent == aBrowserParent;
     84  }
     85 
     86  /**
     87   * If CanSendNotificationToWidget() returns false (it should occur
     88   * only in a content process), we shouldn't notify the widget of
     89   * any focused editor changes since the content process was blurred.
     90   * Also, even if content process, widget has native text event dispatcher such
     91   * as Android, it still notify it.
     92   */
     93  static bool CanSendNotificationToWidget() {
     94 #ifdef MOZ_WIDGET_ANDROID
     95    return true;
     96 #else
     97    return !sCleaningUpForStoppingIMEStateManagement;
     98 #endif
     99  }
    100 
    101  /**
    102   * Focus moved between browsers from aBlur to aFocus. (nullptr means the
    103   * chrome process.)
    104   */
    105  static void OnFocusMovedBetweenBrowsers(BrowserParent* aBlur,
    106                                          BrowserParent* aFocus);
    107 
    108  /**
    109   * Called when aWidget is being deleted.
    110   */
    111  static void WidgetDestroyed(nsIWidget* aWidget);
    112 
    113  /**
    114   * Called when a widget exists when the app is quitting
    115   */
    116  static void WidgetOnQuit(nsIWidget* aWidget);
    117 
    118  /**
    119   * GetWidgetForActiveInputContext() returns a widget which IMEStateManager
    120   * is managing input context with.  If a widget instance needs to cache
    121   * the last input context for nsIWidget::GetInputContext() or something,
    122   * it should check if its cache is valid with this method before using it
    123   * because if this method returns another instance, it means that
    124   * IMEStateManager may have already changed shared input context via the
    125   * widget.
    126   */
    127  static nsIWidget* GetWidgetForActiveInputContext() {
    128    return sActiveInputContextWidget;
    129  }
    130 
    131  /**
    132   * Return a widget which is for handling text input. This should be valid
    133   * while an editable element has focus or an editable document has focus.
    134   */
    135  static nsIWidget* GetWidgetForTextInputHandling() {
    136    return sTextInputHandlingWidget;
    137  }
    138 
    139  /**
    140   * SetIMEContextForChildProcess() is called when aBrowserParent receives
    141   * SetInputContext() from the remote process.
    142   */
    143  static void SetInputContextForChildProcess(BrowserParent* aBrowserParent,
    144                                             const InputContext& aInputContext,
    145                                             const InputContextAction& aAction);
    146 
    147  /**
    148   * StopIMEStateManagement() is called when the process should stop managing
    149   * IME state.
    150   */
    151  static void StopIMEStateManagement();
    152 
    153  /**
    154   * MaybeStartOffsetUpdatedInChild() is called when composition start offset
    155   * is maybe updated in the child process.  I.e., even if it's not updated,
    156   * this is called and never called if the composition is in this process.
    157   * @param aWidget             The widget whose native IME context has the
    158   *                            composition.
    159   * @param aStartOffset        New composition start offset with native
    160   *                            linebreaks.
    161   */
    162  static void MaybeStartOffsetUpdatedInChild(nsIWidget* aWidget,
    163                                             uint32_t aStartOffset);
    164 
    165  MOZ_CAN_RUN_SCRIPT static nsresult OnDestroyPresContext(
    166      nsPresContext& aPresContext);
    167  MOZ_CAN_RUN_SCRIPT static nsresult OnRemoveContent(
    168      nsPresContext& aPresContext, dom::Element& aElement);
    169  /**
    170   * Called when the parent chain of the observing element of IMEContentObserver
    171   * is changed.
    172   *
    173   * @param aObserver   The IMEContentObserver which received the notification.
    174   * @param aContent    The topmost content which is changed.
    175   */
    176  MOZ_CAN_RUN_SCRIPT static void OnParentChainChangedOfObservingElement(
    177      IMEContentObserver& aObserver, nsIContent& aContent);
    178 
    179  /**
    180   * Called when HTMLEditor updates the root element which is <body> of the
    181   * document if there is (or the document element otherwise).
    182   */
    183  MOZ_CAN_RUN_SCRIPT static void OnUpdateHTMLEditorRootElement(
    184      HTMLEditor& aHTMLEditor, dom::Element* aNewRootElement);
    185 
    186  /**
    187   * OnChangeFocus() should be called when focused content is changed or
    188   * IME enabled state is changed.  If nobody has focus, set both aPresContext
    189   * and aContent nullptr.  E.g., all windows are deactivated.  Otherwise,
    190   * set focused element (even if it won't receive `focus`event) and
    191   * corresponding nsPresContext for it.  Then, IMEStateManager can avoid
    192   * handling delayed notifications from the others with verifying the
    193   * focused element.
    194   */
    195  MOZ_CAN_RUN_SCRIPT static nsresult OnChangeFocus(
    196      nsPresContext* aPresContext, dom::Element* aElement,
    197      InputContextAction::Cause aCause);
    198 
    199  /**
    200   * OnInstalledMenuKeyboardListener() is called when menu keyboard listener
    201   * is installed or uninstalled in the process.  So, even if menu keyboard
    202   * listener was installed in chrome process, this won't be called in content
    203   * processes.
    204   *
    205   * @param aInstalling     true if menu keyboard listener is installed.
    206   *                        Otherwise, i.e., menu keyboard listener is
    207   *                        uninstalled, false.
    208   */
    209  MOZ_CAN_RUN_SCRIPT static void OnInstalledMenuKeyboardListener(
    210      bool aInstalling);
    211 
    212  // These two methods manage focus and selection/text observers.
    213  // They are separate from OnChangeFocus above because this offers finer
    214  // control compared to having the two methods incorporated into OnChangeFocus
    215 
    216  // Get the focused editor's selection and root
    217  static nsresult GetFocusSelectionAndRootElement(dom::Selection** aSel,
    218                                                  dom::Element** aRootElement);
    219  // This method updates the current IME state.  However, if the enabled state
    220  // isn't changed by the new state, this method does nothing.
    221  // Note that this method changes the IME state of the active element in the
    222  // widget.  So, the caller must have focus.
    223  // XXX Changing this to MOZ_CAN_RUN_SCRIPT requires too many callers to be
    224  //     marked too.  Probably, we should initialize IMEContentObserver
    225  //     asynchronously.
    226  enum class UpdateIMEStateOption {
    227    ForceUpdate,
    228    DontCommitComposition,
    229  };
    230  using UpdateIMEStateOptions = EnumSet<UpdateIMEStateOption, uint32_t>;
    231  MOZ_CAN_RUN_SCRIPT static void UpdateIMEState(
    232      const IMEState& aNewIMEState, dom::Element* aElement,
    233      EditorBase& aEditorBase, const UpdateIMEStateOptions& aOptions = {});
    234 
    235  // This method is called when user operates mouse button in focused editor
    236  // and before the editor handles it.
    237  // Returns true if IME consumes the event.  Otherwise, false.
    238  MOZ_CAN_RUN_SCRIPT static bool OnMouseButtonEventInEditor(
    239      nsPresContext& aPresContext, dom::Element* aElement,
    240      WidgetMouseEvent& aMouseEvent);
    241 
    242  // This method is called when user clicked in an editor.
    243  // aElement must be:
    244  //   If the editor is for <input> or <textarea>, the element.
    245  //   If the editor is for contenteditable, the active editinghost.
    246  //   If the editor is for designMode, nullptr.
    247  MOZ_CAN_RUN_SCRIPT static void OnClickInEditor(
    248      nsPresContext& aPresContext, dom::Element* aElement,
    249      const WidgetMouseEvent& aMouseEvent);
    250 
    251  // This method is called when editor actually gets focus.
    252  // aContent must be:
    253  //   If the editor is for <input> or <textarea>, the element.
    254  //   If the editor is for contenteditable, the active editinghost.
    255  //   If the editor is for designMode, nullptr.
    256  static void OnFocusInEditor(nsPresContext& aPresContext,
    257                              dom::Element* aElement, EditorBase& aEditorBase);
    258 
    259  // This method is called when the editor is initialized.
    260  static void OnEditorInitialized(EditorBase& aEditorBase);
    261 
    262  // This method is called when the editor is (might be temporarily) being
    263  // destroyed.
    264  static void OnEditorDestroying(EditorBase& aEditorBase);
    265 
    266  // This method is called when focus is set to same content again.
    267  MOZ_CAN_RUN_SCRIPT static void OnReFocus(nsPresContext& aPresContext,
    268                                           dom::Element& aElement);
    269 
    270  // This method is called when designMode is set to "off" or an editing host
    271  // becomes not editable due to removing `contenteditable` attribute or setting
    272  // it to "false".
    273  MOZ_CAN_RUN_SCRIPT static void MaybeOnEditableStateDisabled(
    274      nsPresContext& aPresContext, dom::Element* aElement);
    275 
    276  /**
    277   * All composition events must be dispatched via DispatchCompositionEvent()
    278   * for storing the composition target and ensuring a set of composition
    279   * events must be fired the stored target.  If the stored composition event
    280   * target is destroying, this removes the stored composition automatically.
    281   */
    282  MOZ_CAN_RUN_SCRIPT static void DispatchCompositionEvent(
    283      nsINode* aEventTargetNode, nsPresContext* aPresContext,
    284      BrowserParent* aBrowserParent, WidgetCompositionEvent* aCompositionEvent,
    285      nsEventStatus* aStatus, EventDispatchingCallback* aCallBack,
    286      bool aIsSynthesized = false);
    287 
    288  /**
    289   * All selection events must be handled via HandleSelectionEvent()
    290   * because they must be handled by same target as composition events when
    291   * there is a composition.
    292   */
    293  MOZ_CAN_RUN_SCRIPT
    294  static void HandleSelectionEvent(nsPresContext* aPresContext,
    295                                   nsIContent* aEventTargetContent,
    296                                   WidgetSelectionEvent* aSelectionEvent);
    297 
    298  /**
    299   * This is called when PresShell ignores a composition event due to not safe
    300   * to dispatch events.
    301   */
    302  static void OnCompositionEventDiscarded(
    303      WidgetCompositionEvent* aCompositionEvent);
    304 
    305  /**
    306   * Get TextComposition from widget.
    307   */
    308  static TextComposition* GetTextCompositionFor(nsIWidget* aWidget);
    309 
    310  /**
    311   * Returns TextComposition instance for the event.
    312   */
    313  static TextComposition* GetTextCompositionFor(
    314      const WidgetCompositionEvent* aCompositionEvent);
    315 
    316  /**
    317   * Returns TextComposition instance for the pres context.
    318   * Be aware, even if another pres context which shares native IME context with
    319   * specified pres context has composition, this returns nullptr.
    320   */
    321  static TextComposition* GetTextCompositionFor(nsPresContext* aPresContext);
    322 
    323  /**
    324   * Send a notification to IME.  It depends on the IME or platform spec what
    325   * will occur (or not occur).
    326   */
    327  static nsresult NotifyIME(const IMENotification& aNotification,
    328                            nsIWidget* aWidget,
    329                            BrowserParent* aBrowserParent = nullptr);
    330  static nsresult NotifyIME(IMEMessage aMessage, nsIWidget* aWidget,
    331                            BrowserParent* aBrowserParent = nullptr);
    332  static nsresult NotifyIME(IMEMessage aMessage, nsPresContext* aPresContext,
    333                            BrowserParent* aBrowserParent = nullptr);
    334 
    335  /**
    336   * Returns active IMEContentObserver but may be nullptr if focused content
    337   * isn't editable or focus in a remote process.
    338   */
    339  static IMEContentObserver* GetActiveContentObserver();
    340 
    341  /**
    342   * Return focused element which was notified by a OnChangeFocus() call.
    343   */
    344  static dom::Element* GetFocusedElement();
    345 
    346 protected:
    347  MOZ_CAN_RUN_SCRIPT static nsresult OnChangeFocusInternal(
    348      nsPresContext* aPresContext, dom::Element* aElement,
    349      InputContextAction aAction);
    350  MOZ_CAN_RUN_SCRIPT static void SetIMEState(const IMEState& aState,
    351                                             const nsPresContext* aPresContext,
    352                                             dom::Element* aElement,
    353                                             nsIWidget& aWidget,
    354                                             InputContextAction aAction,
    355                                             InputContext::Origin aOrigin);
    356  static void SetInputContext(nsIWidget& aWidget,
    357                              const InputContext& aInputContext,
    358                              const InputContextAction& aAction);
    359  static IMEState GetNewIMEState(const nsPresContext& aPresContext,
    360                                 dom::Element* aElement);
    361 
    362  /**
    363   * Return a URI which is exposable via the native IME API to the system or
    364   * IME.
    365   */
    366  static already_AddRefed<nsIURI> GetExposableURL(
    367      const nsPresContext* aPresContext);
    368 
    369  static void EnsureTextCompositionArray();
    370 
    371  // XXX Changing this to MOZ_CAN_RUN_SCRIPT requires too many callers to be
    372  //     marked too.  Probably, we should initialize IMEContentObserver
    373  //     asynchronously.
    374  MOZ_CAN_RUN_SCRIPT_BOUNDARY static void CreateIMEContentObserver(
    375      EditorBase& aEditorBase, dom::Element* aFocusedElement);
    376 
    377  /**
    378   * Check whether the content matches or does not match with focus information
    379   * which is previously notified via OnChangeFocus();
    380   */
    381  [[nodiscard]] static bool IsFocusedElement(
    382      const nsPresContext& aPresContext, const dom::Element* aFocusedElement);
    383 
    384  static void DestroyIMEContentObserver();
    385 
    386  [[nodiscard]] static bool IsIMEObserverNeeded(const IMEState& aState);
    387 
    388  [[nodiscard]] static nsIContent* GetRootContent(nsPresContext* aPresContext);
    389 
    390  /**
    391   * CanHandleWith() returns false if it's destroyed.
    392   */
    393  [[nodiscard]] static bool CanHandleWith(const nsPresContext* aPresContext);
    394 
    395  /**
    396   * ResetActiveChildInputContext() resets sActiveChildInputContext.
    397   * So, HasActiveChildSetInputContext() will return false until a remote
    398   * process gets focus and set input context.
    399   */
    400  static void ResetActiveChildInputContext();
    401 
    402  /**
    403   * HasActiveChildSetInputContext() returns true if a remote tab has focus
    404   * and it has already set input context.  Otherwise, returns false.
    405   */
    406  static bool HasActiveChildSetInputContext();
    407 
    408  /**
    409   * This is the runner of OnInstalledMenuKeyboardListener(), called by
    410   * PseudoFocusChangeRunnable maybe asynchronously.
    411   *
    412   * @param aCaller             The caller instance, used only for debug.
    413   * @param aSetPseudoFocus     Whether the menu keyboard listener is installed
    414   *                            or uninstalled when
    415   *                            OnInstalledMenuKeyboardListener() is called and
    416   *                            the PseudoFocusChangeRunnable instance is
    417   *                            created.
    418   * @param aFocusedPresContextAtRequested
    419   *                            sFocusedPresContext when
    420   *                            OnInstalledMenuKeyboardListener() is called and
    421   *                            the PseudoFocusChangeRunnable instance is
    422   *                            created.
    423   */
    424  MOZ_CAN_RUN_SCRIPT static void SetMenubarPseudoFocus(
    425      PseudoFocusChangeRunnable* aCaller, bool aSetPseudoFocus,
    426      nsPresContext* aFocusedPresContextAtRequested);
    427 
    428  // sFocusedElement and sFocusedPresContext are the focused content and
    429  // PresContext.  If a document has focus but there is no focused element,
    430  // sFocusedElement may be nullptr.
    431  static StaticRefPtr<dom::Element> sFocusedElement;
    432  static StaticRefPtr<nsPresContext> sFocusedPresContext;
    433  // sTextInputHandlingWidget is cache for the result of
    434  // sFocusedPresContext->GetTextInputHandlingWidget().  Even after
    435  // sFocusedPresContext has gone, we need to clean up some IME state on the
    436  // widget if the widget is available.
    437  // Note that this is cleared when the widget is being destroyed.
    438  static nsIWidget* sTextInputHandlingWidget;
    439  // sFocusedIMEBrowserParent is the tab parent, which send "focus" notification
    440  // to sFocusedIMEWidget (and didn't yet sent "blur" notification).
    441  // Note that this is cleared when the widget is being destroyed.
    442  static nsIWidget* sFocusedIMEWidget;
    443  static StaticRefPtr<BrowserParent> sFocusedIMEBrowserParent;
    444  // sActiveInputContextWidget is the last widget whose SetInputContext() is
    445  // called.  This is important to reduce sync IPC cost with parent process.
    446  // If IMEStateManager set input context to different widget, PuppetWidget can
    447  // return cached input context safely.
    448  // Note that this is cleared when the widget is being destroyed.
    449  static nsIWidget* sActiveInputContextWidget;
    450  // sActiveIMEContentObserver points to the currently active
    451  // IMEContentObserver.  This is null if there is no focused editor.
    452  static StaticRefPtr<IMEContentObserver> sActiveIMEContentObserver;
    453 
    454  // All active compositions in the process are stored by this array.
    455  // When you get an item of this array and use it, please be careful.
    456  // The instances in this array can be destroyed automatically if you do
    457  // something to cause committing or canceling the composition.
    458  static TextCompositionArray* sTextCompositions;
    459 
    460  // Origin type of current process.
    461  static InputContext::Origin sOrigin;
    462 
    463  // sActiveChildInputContext is valid only when BrowserParent::GetFocused() is
    464  // not nullptr.  This stores last information of input context in the remote
    465  // process of BrowserParent::GetFocused().  I.e., they are set when
    466  // SetInputContextForChildProcess() is called.  This is necessary for
    467  // restoring IME state when menu keyboard listener is uninstalled.
    468  static InputContext sActiveChildInputContext;
    469 
    470  // sInstalledMenuKeyboardListener is true if menu keyboard listener is
    471  // installed in the process.
    472  static bool sInstalledMenuKeyboardListener;
    473 
    474  static bool sIsGettingNewIMEState;
    475  static bool sCheckForIMEUnawareWebApps;
    476 
    477  // Set to true only if this is an instance in a content process and
    478  // only while `IMEStateManager::StopIMEStateManagement()`.
    479  static bool sCleaningUpForStoppingIMEStateManagement;
    480 
    481  // Set to true when:
    482  // - In the main process, a window belonging to this app is active in the
    483  //   desktop.
    484  // - In a content process, the process has focus.
    485  //
    486  // This is updated by `OnChangeFocusInternal()` is called in the main
    487  // process.  Therefore, this indicates the active state which
    488  // `IMEStateManager` notified the focus change, there is timelag from
    489  // the `nsFocusManager`'s status update.  This allows that all methods
    490  // to handle something specially when they are called while the process
    491  // is being activated or inactivated.  E.g., `OnFocusMovedBetweenBrowsers()`
    492  // is called twice before `OnChangeFocusInternal()` when the main process
    493  // becomes active.  In this case, it wants to wait a following call of
    494  // `OnChangeFocusInternal()` to keep active composition.  See also below.
    495  static bool sIsActive;
    496 
    497  // While the application is being activated, `OnFocusMovedBetweenBrowsers()`
    498  // are called twice before `OnChangeFocusInternal()`.  First time, aBlur is
    499  // the last focused `BrowserParent` at deactivating and aFocus is always
    500  // `nullptr`.  Then, it'll be called again with actually focused
    501  // `BrowserParent` when a content in a remote process has focus.  If we need
    502  // to keep active composition while all windows are deactivated, we shouldn't
    503  // commit it at the first call since usually, the second call's aFocus
    504  // and the first call's aBlur are same `BrowserParent`.  For solving this
    505  // issue, we need to merge the given `BrowserParent`s of multiple calls of
    506  // `OnFocusMovedBetweenBrowsers()`. The following struct is the data for
    507  // calling `OnFocusMovedBetweenBrowsers()` later from
    508  // `OnChangeFocusInternal()`.  Note that focus can be moved even while the
    509  // main process is not active because JS can change focus.  In such case,
    510  // composition is committed at that time.  Therefore, this is required only
    511  // when the main process is activated and there is a composition in a remote
    512  // process.
    513  struct PendingFocusedBrowserSwitchingData final {
    514    RefPtr<BrowserParent> mBrowserParentBlurred;
    515    RefPtr<BrowserParent> mBrowserParentFocused;
    516 
    517    PendingFocusedBrowserSwitchingData() = delete;
    518    explicit PendingFocusedBrowserSwitchingData(BrowserParent* aBlur,
    519                                                BrowserParent* aFocus)
    520        : mBrowserParentBlurred(aBlur), mBrowserParentFocused(aFocus) {}
    521  };
    522  static Maybe<PendingFocusedBrowserSwitchingData>
    523      sPendingFocusedBrowserSwitchingData;
    524 
    525  class MOZ_STACK_CLASS GettingNewIMEStateBlocker final {
    526   public:
    527    GettingNewIMEStateBlocker()
    528        : mOldValue(IMEStateManager::sIsGettingNewIMEState) {
    529      IMEStateManager::sIsGettingNewIMEState = true;
    530    }
    531    ~GettingNewIMEStateBlocker() {
    532      IMEStateManager::sIsGettingNewIMEState = mOldValue;
    533    }
    534 
    535   private:
    536    bool mOldValue;
    537  };
    538 
    539  // OnInstalledMenuKeyboardListener may be called when it's not safe.
    540  // Therefore, it tries to update with adding this as a script runner.
    541  static StaticRefPtr<PseudoFocusChangeRunnable> sPseudoFocusChangeRunnable;
    542  friend class PseudoFocusChangeRunnable;
    543 };
    544 
    545 }  // namespace mozilla
    546 
    547 #endif  // mozilla_IMEStateManager_h_