tor-browser

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

IMEStateManager.cpp (110850B)


      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 #include "IMEStateManager.h"
      8 
      9 #include "IMEContentObserver.h"
     10 #include "mozilla/Attributes.h"
     11 #include "mozilla/AutoRestore.h"
     12 #include "mozilla/EditorBase.h"
     13 #include "mozilla/EventListenerManager.h"
     14 #include "mozilla/EventStateManager.h"
     15 #include "mozilla/HTMLEditor.h"
     16 #include "mozilla/Logging.h"
     17 #include "mozilla/MouseEvents.h"
     18 #include "mozilla/PresShell.h"
     19 #include "mozilla/RefPtr.h"
     20 #include "mozilla/StaticPrefs_dom.h"
     21 #include "mozilla/StaticPrefs_intl.h"
     22 #include "mozilla/TextComposition.h"
     23 #include "mozilla/TextEvents.h"
     24 #include "mozilla/ToString.h"
     25 #include "mozilla/dom/BrowserBridgeChild.h"
     26 #include "mozilla/dom/BrowserParent.h"
     27 #include "mozilla/dom/Document.h"
     28 #include "mozilla/dom/Element.h"
     29 #include "mozilla/dom/HTMLFormElement.h"
     30 #include "mozilla/dom/HTMLInputElement.h"
     31 #include "mozilla/dom/HTMLTextAreaElement.h"
     32 #include "mozilla/dom/MouseEventBinding.h"
     33 #include "mozilla/dom/UserActivation.h"
     34 #include "mozilla/widget/IMEData.h"
     35 #include "nsCOMPtr.h"
     36 #include "nsContentUtils.h"
     37 #include "nsFocusManager.h"
     38 #include "nsIContent.h"
     39 #include "nsIContentInlines.h"
     40 #include "nsIFormControl.h"
     41 #include "nsINode.h"
     42 #include "nsISupports.h"
     43 #include "nsIURI.h"
     44 #include "nsIURIMutator.h"
     45 #include "nsPresContext.h"
     46 #include "nsTextControlFrame.h"
     47 #include "nsThreadUtils.h"
     48 
     49 namespace mozilla {
     50 
     51 using namespace dom;
     52 using namespace widget;
     53 
     54 /**
     55 * When a method is called, log its arguments and/or related static variables
     56 * with LogLevel::Info.  However, if it puts too many logs like
     57 * OnDestroyPresContext(), should long only when the method actually does
     58 * something. In this case, the log should start with "<method name>".
     59 *
     60 * When a method quits due to unexpected situation, log the reason with
     61 * LogLevel::Error.  In this case, the log should start with
     62 * "<method name>(), FAILED".  The indent makes the log look easier.
     63 *
     64 * When a method does something only in some situations and it may be important
     65 * for debug, log the information with LogLevel::Debug.  In this case, the log
     66 * should start with "  <method name>(),".
     67 */
     68 LazyLogModule sISMLog("IMEStateManager");
     69 
     70 StaticRefPtr<Element> IMEStateManager::sFocusedElement;
     71 StaticRefPtr<nsPresContext> IMEStateManager::sFocusedPresContext;
     72 nsIWidget* IMEStateManager::sTextInputHandlingWidget = nullptr;
     73 nsIWidget* IMEStateManager::sFocusedIMEWidget = nullptr;
     74 StaticRefPtr<BrowserParent> IMEStateManager::sFocusedIMEBrowserParent;
     75 nsIWidget* IMEStateManager::sActiveInputContextWidget = nullptr;
     76 StaticRefPtr<IMEContentObserver> IMEStateManager::sActiveIMEContentObserver;
     77 TextCompositionArray* IMEStateManager::sTextCompositions = nullptr;
     78 InputContext::Origin IMEStateManager::sOrigin = InputContext::ORIGIN_MAIN;
     79 MOZ_RUNINIT InputContext IMEStateManager::sActiveChildInputContext;
     80 bool IMEStateManager::sInstalledMenuKeyboardListener = false;
     81 bool IMEStateManager::sIsGettingNewIMEState = false;
     82 bool IMEStateManager::sCleaningUpForStoppingIMEStateManagement = false;
     83 bool IMEStateManager::sIsActive = false;
     84 MOZ_RUNINIT Maybe<IMEStateManager::PendingFocusedBrowserSwitchingData>
     85    IMEStateManager::sPendingFocusedBrowserSwitchingData;
     86 
     87 class PseudoFocusChangeRunnable : public Runnable {
     88 public:
     89  explicit PseudoFocusChangeRunnable(bool aInstallingMenuKeyboardListener)
     90      : Runnable("PseudoFocusChangeRunnable"),
     91        mFocusedPresContext(IMEStateManager::sFocusedPresContext),
     92        mFocusedElement(IMEStateManager::sFocusedElement),
     93        mInstallMenuKeyboardListener(aInstallingMenuKeyboardListener) {}
     94 
     95  MOZ_CAN_RUN_SCRIPT_BOUNDARY NS_IMETHOD Run() override {
     96    IMEStateManager::SetMenubarPseudoFocus(this, mInstallMenuKeyboardListener,
     97                                           mFocusedPresContext);
     98    return NS_OK;
     99  }
    100 
    101 private:
    102  const RefPtr<nsPresContext> mFocusedPresContext;
    103  const RefPtr<Element> mFocusedElement;
    104  const bool mInstallMenuKeyboardListener;
    105 };
    106 
    107 StaticRefPtr<PseudoFocusChangeRunnable>
    108    IMEStateManager::sPseudoFocusChangeRunnable;
    109 
    110 // static
    111 void IMEStateManager::Init() {
    112  sOrigin = XRE_IsParentProcess() ? InputContext::ORIGIN_MAIN
    113                                  : InputContext::ORIGIN_CONTENT;
    114  ResetActiveChildInputContext();
    115 }
    116 
    117 // static
    118 void IMEStateManager::Shutdown() {
    119  MOZ_LOG(
    120      sISMLog, LogLevel::Info,
    121      ("Shutdown(), sTextCompositions=0x%p, sTextCompositions->Length()=%zu, "
    122       "sPendingFocusedBrowserSwitchingData.isSome()=%s",
    123       sTextCompositions, sTextCompositions ? sTextCompositions->Length() : 0,
    124       TrueOrFalse(sPendingFocusedBrowserSwitchingData.isSome())));
    125  MOZ_LOG(sISMLog, LogLevel::Debug,
    126          ("  Shutdown(), sFocusedElement=0x%p, sFocusedPresContext=0x%p, "
    127           "sTextInputHandlingWidget=0x%p, sFocusedIMEWidget=0x%p, "
    128           "sFocusedIMEBrowserParent=0x%p, sActiveInputContextWidget=0x%p, "
    129           "sActiveIMEContentObserver=0x%p",
    130           sFocusedElement.get(), sFocusedPresContext.get(),
    131           sTextInputHandlingWidget, sFocusedIMEWidget,
    132           sFocusedIMEBrowserParent.get(), sActiveInputContextWidget,
    133           sActiveIMEContentObserver.get()));
    134 
    135  sPendingFocusedBrowserSwitchingData.reset();
    136  MOZ_ASSERT(!sTextCompositions || !sTextCompositions->Length());
    137  delete sTextCompositions;
    138  sTextCompositions = nullptr;
    139  // All string instances in the global space need to be empty after XPCOM
    140  // shutdown.
    141  sActiveChildInputContext.ShutDown();
    142 }
    143 
    144 // static
    145 void IMEStateManager::OnFocusMovedBetweenBrowsers(BrowserParent* aBlur,
    146                                                  BrowserParent* aFocus) {
    147  MOZ_ASSERT(aBlur != aFocus);
    148  MOZ_ASSERT(XRE_IsParentProcess());
    149 
    150  if (sPendingFocusedBrowserSwitchingData.isSome()) {
    151    MOZ_ASSERT(aBlur ==
    152               sPendingFocusedBrowserSwitchingData.ref().mBrowserParentFocused);
    153    // If focus is not changed between browsers actually, we need to do
    154    // nothing here.  Let's cancel handling what this method does.
    155    if (sPendingFocusedBrowserSwitchingData.ref().mBrowserParentBlurred ==
    156        aFocus) {
    157      sPendingFocusedBrowserSwitchingData.reset();
    158      MOZ_LOG(sISMLog, LogLevel::Info,
    159              ("  OnFocusMovedBetweenBrowsers(), canceled all pending focus "
    160               "moves between browsers"));
    161      return;
    162    }
    163    aBlur = sPendingFocusedBrowserSwitchingData.ref().mBrowserParentBlurred;
    164    sPendingFocusedBrowserSwitchingData.ref().mBrowserParentFocused = aFocus;
    165    MOZ_ASSERT(aBlur != aFocus);
    166  }
    167 
    168  // If application was inactive, but is now activated, and the last focused
    169  // this is called by BrowserParent::UnsetTopLevelWebFocusAll() from
    170  // nsFocusManager::WindowRaised().  If a content has focus in a remote
    171  // process and it has composition, it may get focus back later and the
    172  // composition shouldn't be commited now.  Therefore, we should put off to
    173  // handle this until getting another call of this method or a call of
    174  //`OnFocusChangeInternal()`.
    175  if (aBlur && !aFocus && !sIsActive && sTextInputHandlingWidget &&
    176      sTextCompositions &&
    177      sTextCompositions->GetCompositionFor(sTextInputHandlingWidget)) {
    178    if (sPendingFocusedBrowserSwitchingData.isNothing()) {
    179      sPendingFocusedBrowserSwitchingData.emplace(aBlur, aFocus);
    180    }
    181    MOZ_LOG(sISMLog, LogLevel::Debug,
    182            ("  OnFocusMovedBetweenBrowsers(), put off to handle it until "
    183             "next OnFocusChangeInternal() call"));
    184    return;
    185  }
    186  sPendingFocusedBrowserSwitchingData.reset();
    187 
    188  const nsCOMPtr<nsIWidget> oldWidget = sTextInputHandlingWidget;
    189  // In the chrome-process case, we'll get sTextInputHandlingWidget from a
    190  // PresShell later.
    191  sTextInputHandlingWidget =
    192      aFocus ? nsCOMPtr<nsIWidget>(aFocus->GetTextInputHandlingWidget()).get()
    193             : nullptr;
    194  if (oldWidget && sTextCompositions) {
    195    RefPtr<TextComposition> composition =
    196        sTextCompositions->GetCompositionFor(oldWidget);
    197    if (composition) {
    198      MOZ_LOG(
    199          sISMLog, LogLevel::Debug,
    200          ("  OnFocusMovedBetweenBrowsers(), requesting to commit "
    201           "composition to "
    202           "the (previous) focused widget (would request=%s)",
    203           TrueOrFalse(
    204               !oldWidget->IMENotificationRequestsRef().WantDuringDeactive())));
    205      NotifyIME(REQUEST_TO_COMMIT_COMPOSITION, oldWidget,
    206                composition->GetBrowserParent());
    207    }
    208  }
    209 
    210  // The manager check is to avoid telling the content process to stop
    211  // IME state management after focus has already moved there between
    212  // two same-process-hosted out-of-process iframes.
    213  if (aBlur && (!aFocus || (aBlur->Manager() != aFocus->Manager()))) {
    214    MOZ_LOG(sISMLog, LogLevel::Debug,
    215            ("  OnFocusMovedBetweenBrowsers(), notifying previous "
    216             "focused child process of parent process or another child process "
    217             "getting focus"));
    218    aBlur->StopIMEStateManagement();
    219  }
    220 
    221  if (sActiveIMEContentObserver) {
    222    DestroyIMEContentObserver();
    223  }
    224 
    225  if (sFocusedIMEWidget) {
    226    // sFocusedIMEBrowserParent can be null, if IME focus hasn't been
    227    // taken before BrowserParent blur.
    228    // aBlur can be null when keyboard focus moves not actually
    229    // between tabs but an open menu is involved.
    230    MOZ_ASSERT(!sFocusedIMEBrowserParent || !aBlur ||
    231               (sFocusedIMEBrowserParent == aBlur));
    232    MOZ_LOG(sISMLog, LogLevel::Debug,
    233            ("  OnFocusMovedBetweenBrowsers(), notifying IME of blur"));
    234    NotifyIME(NOTIFY_IME_OF_BLUR, sFocusedIMEWidget, sFocusedIMEBrowserParent);
    235 
    236    MOZ_ASSERT(!sFocusedIMEBrowserParent);
    237    MOZ_ASSERT(!sFocusedIMEWidget);
    238 
    239  } else {
    240    MOZ_ASSERT(!sFocusedIMEBrowserParent);
    241  }
    242 
    243  // We deliberately don't null out sFocusedElement or sFocusedPresContext here.
    244  // When focus is in remote content, as far as layout in the chrome process is
    245  // concerned, the corresponding content is the top-level XUL browser. Changes
    246  // among out-of-process iframes don't change that, so dropping the pointer to
    247  // the XUL browser upon such a change would break IME handling.
    248 }
    249 
    250 // static
    251 void IMEStateManager::WidgetDestroyed(nsIWidget* aWidget) {
    252  MOZ_LOG(sISMLog, LogLevel::Debug,
    253          ("WidgetDestroyed(aWidget=0x%p), sFocusedIMEWidget=0x%p, "
    254           "sActiveInputContextWidget=0x%p, sFocusedIMEBrowserParent=0x%p",
    255           aWidget, sFocusedIMEWidget, sActiveInputContextWidget,
    256           sFocusedIMEBrowserParent.get()));
    257  if (sTextInputHandlingWidget == aWidget) {
    258    sTextInputHandlingWidget = nullptr;
    259  }
    260  if (sFocusedIMEWidget == aWidget) {
    261    if (sFocusedIMEBrowserParent) {
    262      OnFocusMovedBetweenBrowsers(sFocusedIMEBrowserParent, nullptr);
    263      MOZ_ASSERT(!sFocusedIMEBrowserParent);
    264    }
    265    sFocusedIMEWidget = nullptr;
    266  }
    267  if (sActiveInputContextWidget == aWidget) {
    268    sActiveInputContextWidget = nullptr;
    269  }
    270 }
    271 
    272 // static
    273 void IMEStateManager::WidgetOnQuit(nsIWidget* aWidget) {
    274  if (sFocusedIMEWidget == aWidget) {
    275    MOZ_LOG(
    276        sISMLog, LogLevel::Debug,
    277        ("WidgetOnQuit(aWidget=0x%p (available %s)), sFocusedIMEWidget=0x%p",
    278         aWidget, TrueOrFalse(aWidget && !aWidget->Destroyed()),
    279         sFocusedIMEWidget));
    280    // Notify IME of blur (which is done by IMEContentObserver::Destroy
    281    // automatically) when the widget still has IME focus before forgetting the
    282    // focused widget because the focused widget is required to clean up native
    283    // IME handler with sending blur notification.  Fortunately, the widget
    284    // has not been destroyed yet here since some methods to sending blur
    285    // notification won't work with destroyed widget.
    286    IMEStateManager::DestroyIMEContentObserver();
    287    // Finally, clean up the widget and related objects for avoiding to leak.
    288    IMEStateManager::WidgetDestroyed(aWidget);
    289  }
    290 }
    291 
    292 // static
    293 void IMEStateManager::StopIMEStateManagement() {
    294  MOZ_ASSERT(XRE_IsContentProcess());
    295  MOZ_LOG(sISMLog, LogLevel::Info, ("StopIMEStateManagement()"));
    296 
    297  // NOTE: Don't set input context from here since this has already lost
    298  //       the rights to change input context.
    299 
    300  // The requestee of this method in the main process must destroy its
    301  // active IMEContentObserver for making existing composition end and
    302  // make it be possible to start new composition in new focused process.
    303  // Therefore, we shouldn't notify the main process of any changes which
    304  // occurred after here.
    305  AutoRestore<bool> restoreStoppingIMEStateManagementState(
    306      sCleaningUpForStoppingIMEStateManagement);
    307  sCleaningUpForStoppingIMEStateManagement = true;
    308 
    309  if (sTextCompositions && sFocusedPresContext) {
    310    NotifyIME(REQUEST_TO_COMMIT_COMPOSITION, sFocusedPresContext, nullptr);
    311  }
    312  sActiveInputContextWidget = nullptr;
    313  sFocusedPresContext = nullptr;
    314  sFocusedElement = nullptr;
    315  sIsActive = false;
    316  DestroyIMEContentObserver();
    317 }
    318 
    319 // static
    320 void IMEStateManager::MaybeStartOffsetUpdatedInChild(nsIWidget* aWidget,
    321                                                     uint32_t aStartOffset) {
    322  if (NS_WARN_IF(!sTextCompositions)) {
    323    MOZ_LOG(sISMLog, LogLevel::Warning,
    324            ("MaybeStartOffsetUpdatedInChild(aWidget=0x%p, aStartOffset=%u), "
    325             "called when there is no composition",
    326             aWidget, aStartOffset));
    327    return;
    328  }
    329 
    330  TextComposition* const composition = GetTextCompositionFor(aWidget);
    331  if (NS_WARN_IF(!composition)) {
    332    MOZ_LOG(sISMLog, LogLevel::Warning,
    333            ("MaybeStartOffsetUpdatedInChild(aWidget=0x%p, aStartOffset=%u), "
    334             "called when there is no composition",
    335             aWidget, aStartOffset));
    336    return;
    337  }
    338 
    339  if (composition->NativeOffsetOfStartComposition() == aStartOffset) {
    340    return;
    341  }
    342 
    343  MOZ_LOG(
    344      sISMLog, LogLevel::Info,
    345      ("MaybeStartOffsetUpdatedInChild(aWidget=0x%p, aStartOffset=%u), "
    346       "old offset=%u",
    347       aWidget, aStartOffset, composition->NativeOffsetOfStartComposition()));
    348  composition->OnStartOffsetUpdatedInChild(aStartOffset);
    349 }
    350 
    351 // static
    352 nsresult IMEStateManager::OnDestroyPresContext(nsPresContext& aPresContext) {
    353  // First, if there is a composition in the aPresContext, clean up it.
    354  if (sTextCompositions) {
    355    TextCompositionArray::index_type i =
    356        sTextCompositions->IndexOf(&aPresContext);
    357    if (i != TextCompositionArray::NoIndex) {
    358      MOZ_LOG(sISMLog, LogLevel::Debug,
    359              ("  OnDestroyPresContext(), "
    360               "removing TextComposition instance from the array (index=%zu)",
    361               i));
    362      // there should be only one composition per presContext object.
    363      sTextCompositions->ElementAt(i)->Destroy();
    364      sTextCompositions->RemoveElementAt(i);
    365      if (sTextCompositions->IndexOf(&aPresContext) !=
    366          TextCompositionArray::NoIndex) {
    367        MOZ_LOG(sISMLog, LogLevel::Error,
    368                ("  OnDestroyPresContext(), FAILED to remove "
    369                 "TextComposition instance from the array"));
    370        MOZ_CRASH("Failed to remove TextComposition instance from the array");
    371      }
    372    }
    373  }
    374 
    375  if (&aPresContext != sFocusedPresContext) {
    376    return NS_OK;
    377  }
    378 
    379  MOZ_LOG(
    380      sISMLog, LogLevel::Info,
    381      ("OnDestroyPresContext(aPresContext=0x%p), "
    382       "sFocusedPresContext=0x%p, sFocusedElement=0x%p, sTextCompositions=0x%p",
    383       &aPresContext, sFocusedPresContext.get(), sFocusedElement.get(),
    384       sTextCompositions));
    385 
    386  DestroyIMEContentObserver();
    387 
    388  if (sTextInputHandlingWidget) {
    389    IMEState newState = GetNewIMEState(*sFocusedPresContext, nullptr);
    390    InputContextAction action(InputContextAction::CAUSE_UNKNOWN,
    391                              InputContextAction::LOST_FOCUS);
    392    InputContext::Origin origin =
    393        BrowserParent::GetFocused() ? InputContext::ORIGIN_CONTENT : sOrigin;
    394    OwningNonNull<nsIWidget> textInputHandlingWidget =
    395        *sTextInputHandlingWidget;
    396    SetIMEState(newState, nullptr, nullptr, textInputHandlingWidget, action,
    397                origin);
    398  }
    399  sTextInputHandlingWidget = nullptr;
    400  sFocusedElement = nullptr;
    401  sFocusedPresContext = nullptr;
    402  return NS_OK;
    403 }
    404 
    405 // static
    406 nsresult IMEStateManager::OnRemoveContent(nsPresContext& aPresContext,
    407                                          Element& aElement) {
    408  // First, if there is a composition in the aElement, clean up it.
    409  if (sTextCompositions) {
    410    const RefPtr<TextComposition> compositionInContent =
    411        sTextCompositions->GetCompositionInContent(&aPresContext, &aElement);
    412 
    413    if (compositionInContent) {
    414      MOZ_LOG(sISMLog, LogLevel::Debug,
    415              ("  OnRemoveContent(), composition is in the content"));
    416 
    417      // Try resetting the native IME state.  Be aware, typically, this method
    418      // is called during the content being removed.  Then, the native
    419      // composition events which are caused by following APIs are ignored due
    420      // to unsafe to run script (in PresShell::HandleEvent()).
    421      nsresult rv =
    422          compositionInContent->NotifyIME(REQUEST_TO_CANCEL_COMPOSITION);
    423      if (NS_FAILED(rv)) {
    424        compositionInContent->NotifyIME(REQUEST_TO_COMMIT_COMPOSITION);
    425      }
    426    }
    427  }
    428 
    429  if (!sFocusedPresContext ||
    430      // If focused element is a text control or an editing host, we need to
    431      // emulate "blur" on it when it's removed.
    432      (sFocusedElement && sFocusedElement != &aElement) ||
    433      // If it is (or was) in design mode, we need to emulate "blur" on the
    434      // document when the observing element (typically, <body>) is removed.
    435      (!sFocusedElement &&
    436       (!sActiveIMEContentObserver ||
    437        sActiveIMEContentObserver
    438                ->GetObservingEditingHostOrTextControlElement() !=
    439            &aElement))) {
    440    return NS_OK;
    441  }
    442  MOZ_ASSERT(sFocusedPresContext == &aPresContext);
    443 
    444  MOZ_LOG(
    445      sISMLog, LogLevel::Info,
    446      ("OnRemoveContent(aPresContext=0x%p, aElement=0x%p), "
    447       "sFocusedPresContext=0x%p, sFocusedElement=0x%p, sTextCompositions=0x%p",
    448       &aPresContext, &aElement, sFocusedPresContext.get(),
    449       sFocusedElement.get(), sTextCompositions));
    450 
    451  DestroyIMEContentObserver();
    452 
    453  // FYI: Don't clear sTextInputHandlingWidget and sFocusedPresContext because
    454  // the window/document keeps having focus.
    455  sFocusedElement = nullptr;
    456 
    457  // Current IME transaction should commit
    458  if (!sTextInputHandlingWidget) {
    459    return NS_OK;
    460  }
    461 
    462  IMEState newState = GetNewIMEState(*sFocusedPresContext, nullptr);
    463  InputContextAction action(InputContextAction::CAUSE_UNKNOWN,
    464                            InputContextAction::LOST_FOCUS);
    465  InputContext::Origin origin =
    466      BrowserParent::GetFocused() ? InputContext::ORIGIN_CONTENT : sOrigin;
    467  OwningNonNull<nsIWidget> textInputHandlingWidget = *sTextInputHandlingWidget;
    468  SetIMEState(newState, &aPresContext, nullptr, textInputHandlingWidget, action,
    469              origin);
    470  if (sFocusedPresContext != &aPresContext || sFocusedElement) {
    471    return NS_OK;  // Somebody already has focus, don't steal it.
    472  }
    473 
    474  if (IsIMEObserverNeeded(newState)) {
    475    // Initializing IMEContentObserver instance requires Selection, but its
    476    // ranges have not been adjusted for this removal.  Therefore, we need to
    477    // wait a moment.
    478    nsContentUtils::AddScriptRunner(NS_NewRunnableFunction(
    479        "IMEStateManager::RecreateIMEContentObserverWhenContentRemoved",
    480        [presContext = OwningNonNull{aPresContext}]() {
    481          MOZ_ASSERT(sFocusedPresContext == presContext);
    482          MOZ_ASSERT(!sFocusedElement);
    483          if (RefPtr<HTMLEditor> htmlEditor =
    484                  nsContentUtils::GetHTMLEditor(presContext)) {
    485            CreateIMEContentObserver(*htmlEditor, nullptr);
    486          }
    487        }));
    488  }
    489 
    490  return NS_OK;
    491 }
    492 
    493 // static
    494 void IMEStateManager::OnParentChainChangedOfObservingElement(
    495    IMEContentObserver& aObserver, nsIContent& aContent) {
    496  if (!sFocusedPresContext || sActiveIMEContentObserver != &aObserver) {
    497    return;
    498  }
    499  if (Element* const textControlElement =
    500          aObserver.GetObservingTextControlElement()) {
    501    // If a text control has focus, the parent chain changed is notified when
    502    // the anonymous <div> is removed since aObserver is observing it. However,
    503    // we want to be notified only when the focused element, i.e., the text
    504    // control itself, is removed.  So, when the text control element is not an
    505    // inclusive descendant of aContent, we don't need to handle this.
    506    MOZ_ASSERT(textControlElement->IsTextControlElement());
    507    if (!textControlElement->IsInclusiveDescendantOf(&aContent)) {
    508      return;
    509    }
    510  }
    511  const RefPtr<nsPresContext> presContext = aObserver.GetPresContext();
    512  const RefPtr<Element> editingHostOrTextControlElement =
    513      aObserver.GetObservingEditingHostOrTextControlElement();
    514  if (NS_WARN_IF(!presContext) ||
    515      NS_WARN_IF(!editingHostOrTextControlElement)) {
    516    return;
    517  }
    518  MOZ_LOG(sISMLog, LogLevel::Info,
    519          ("OnParentChainChangedOfObservingElement(aObserver=0x%p), "
    520           "sFocusedPresContext=0x%p, sFocusedElement=0x%p, "
    521           "aObserver->GetPresContext()=0x%p, "
    522           "aObserver->GetObservingEditingHostOrTextControlElement()=0x%p",
    523           &aObserver, sFocusedPresContext.get(), sFocusedElement.get(),
    524           presContext.get(), editingHostOrTextControlElement.get()));
    525  OnRemoveContent(*presContext, *editingHostOrTextControlElement);
    526 }
    527 
    528 // static
    529 void IMEStateManager::OnUpdateHTMLEditorRootElement(HTMLEditor& aHTMLEditor,
    530                                                    Element* aNewRootElement) {
    531  MOZ_LOG(
    532      sISMLog, LogLevel::Info,
    533      ("OnUpdateHTMLEditorRootElement(aHTMLEditor=0x%p, aNewRootElement=%s), "
    534       "sFocusedPresContext=0x%p, sFocusedElement=%s, "
    535       "sActiveIMEContentObserver=0x%p (GetObservingElement()=%s), "
    536       "sTextInputHandlingWidget=0x%p, aHTMLEditor.GetPresContext()=0x%p",
    537       &aHTMLEditor,
    538       aNewRootElement ? ToString(*aNewRootElement).c_str() : "nullptr",
    539       sFocusedPresContext.get(),
    540       ToString(RefPtr<Element>(sFocusedElement)).c_str(),
    541       sActiveIMEContentObserver.get(),
    542       sActiveIMEContentObserver
    543           ? ToString(RefPtr<Element>(
    544                          sActiveIMEContentObserver->GetObservingElement()))
    545                 .c_str()
    546           : "N/A",
    547       sTextInputHandlingWidget, aHTMLEditor.GetPresContext()));
    548 
    549  if (
    550      // Nothing to do if nobody has focus.
    551      !sFocusedPresContext || !sTextInputHandlingWidget ||
    552      // Nothing to do if an element has focus because we need to handle this
    553      // case only when no element has focus in the design mode.
    554      sFocusedElement ||
    555      // Nothing to do if the editable document does not have focus.
    556      sFocusedPresContext != aHTMLEditor.GetPresContext() ||
    557      // If it's not in the design mode, any mutation should be handled with a
    558      // focus change.
    559      !aHTMLEditor.IsInDesignMode() ||
    560      // Nothing to do if the active IMEContentObserver has already been
    561      // observing the new root element.
    562      (aNewRootElement && sActiveIMEContentObserver &&
    563       sActiveIMEContentObserver->GetObservingElement() == aNewRootElement)) {
    564    return;
    565  }
    566 
    567  OwningNonNull<nsPresContext> presContext = *sFocusedPresContext;
    568 
    569  DestroyIMEContentObserver();
    570 
    571  if (!aNewRootElement) {
    572    // When there is no element in the document, let's disable IME.
    573    IMEState newState = GetNewIMEState(*presContext, nullptr);
    574    MOZ_ASSERT(newState.mEnabled == IMEEnabled::Disabled);
    575    InputContextAction action(InputContextAction::CAUSE_UNKNOWN,
    576                              InputContextAction::LOST_FOCUS);
    577    InputContext::Origin origin =
    578        BrowserParent::GetFocused() ? InputContext::ORIGIN_CONTENT : sOrigin;
    579    OwningNonNull<nsIWidget> textInputHandlingWidget =
    580        *sTextInputHandlingWidget;
    581    SetIMEState(newState, presContext, nullptr, textInputHandlingWidget, action,
    582                origin);
    583    return;
    584  }
    585 
    586  MOZ_ASSERT(aNewRootElement);
    587  const IMEState newState = GetNewIMEState(*presContext, nullptr);
    588  // The caller wants to enable IME if there is at least one element in the most
    589  // cases.  However, IME may be disabled, e.g., the menubar key listener is now
    590  // installed, etc.  Therefore, if the new state is not "enabled", we should
    591  // not update the state in unexpected situations.
    592  if (MOZ_UNLIKELY(newState.mEnabled != IMEEnabled::Enabled)) {
    593    MOZ_LOG(sISMLog, LogLevel::Warning,
    594            ("  OnUpdateHTMLEditorRootElement(): WARNING, Not updating IME "
    595             "state because of the new IME state is not \"enabled\""));
    596    return;
    597  }
    598  InputContextAction action(InputContextAction::CAUSE_UNKNOWN,
    599                            InputContextAction::GOT_FOCUS);
    600  InputContext::Origin origin =
    601      BrowserParent::GetFocused() ? InputContext::ORIGIN_CONTENT : sOrigin;
    602  OwningNonNull<nsIWidget> textInputHandlingWidget = *sTextInputHandlingWidget;
    603  SetIMEState(newState, presContext, nullptr, textInputHandlingWidget, action,
    604              origin);
    605  // Somebody moved focus, don't keep handling this since we lost the rights
    606  // to touch IME state.
    607  if (sFocusedElement || sActiveIMEContentObserver) {
    608    MOZ_LOG(sISMLog, LogLevel::Warning,
    609            ("OnUpdateHTMLEditorRootElement(), WARNING: Somebody update focus "
    610             "during setting IME state, sFocusedElement=%s, "
    611             "sActiveIMEContentObserver=0x%p",
    612             ToString(RefPtr<Element>(sFocusedElement)).c_str(),
    613             sActiveIMEContentObserver.get()));
    614    return;
    615  }
    616 
    617  if (IsIMEObserverNeeded(newState)) {
    618    MOZ_ASSERT(sFocusedPresContext == presContext);
    619    MOZ_ASSERT(!sFocusedElement);
    620    CreateIMEContentObserver(aHTMLEditor, nullptr);
    621  }
    622 }
    623 
    624 // static
    625 bool IMEStateManager::CanHandleWith(const nsPresContext* aPresContext) {
    626  return aPresContext && aPresContext->GetPresShell() &&
    627         !aPresContext->PresShell()->IsDestroying();
    628 }
    629 
    630 // static
    631 nsresult IMEStateManager::OnChangeFocus(nsPresContext* aPresContext,
    632                                        Element* aElement,
    633                                        InputContextAction::Cause aCause) {
    634  MOZ_LOG(sISMLog, LogLevel::Info,
    635          ("OnChangeFocus(aPresContext=0x%p, aElement=0x%p, aCause=%s)",
    636           aPresContext, aElement, ToString(aCause).c_str()));
    637 
    638  InputContextAction action(aCause);
    639  return OnChangeFocusInternal(aPresContext, aElement, action);
    640 }
    641 
    642 // static
    643 nsresult IMEStateManager::OnChangeFocusInternal(nsPresContext* aPresContext,
    644                                                Element* aElement,
    645                                                InputContextAction aAction) {
    646  NS_ASSERTION(!aElement || aElement->GetPresContext(
    647                                Element::PresContextFor::eForComposedDoc) ==
    648                                aPresContext,
    649               "aPresContext does not match with one of aElement");
    650 
    651  bool remoteHasFocus = EventStateManager::IsRemoteTarget(aElement);
    652  // If we've handled focused content, we were inactive but now active,
    653  // a remote process has focus, and setting focus to same content in the main
    654  // process, it means that we're restoring focus without changing DOM focus
    655  // both in the main process and the remote process.
    656  const bool restoringContextForRemoteContent =
    657      XRE_IsParentProcess() && remoteHasFocus && !sIsActive && aPresContext &&
    658      sFocusedPresContext && sFocusedElement &&
    659      sFocusedPresContext.get() == aPresContext &&
    660      sFocusedElement.get() == aElement &&
    661      aAction.mFocusChange != InputContextAction::MENU_GOT_PSEUDO_FOCUS;
    662 
    663  MOZ_LOG(
    664      sISMLog, LogLevel::Info,
    665      ("OnChangeFocusInternal(aPresContext=0x%p (available: %s), "
    666       "aElement=0x%p (remote: %s), aAction={ mCause=%s, "
    667       "mFocusChange=%s }), sFocusedPresContext=0x%p (available: %s), "
    668       "sFocusedElement=0x%p, sTextInputHandlingWidget=0x%p (available: %s), "
    669       "BrowserParent::GetFocused()=0x%p, sActiveIMEContentObserver=0x%p, "
    670       "sInstalledMenuKeyboardListener=%s, sIsActive=%s, "
    671       "restoringContextForRemoteContent=%s",
    672       aPresContext, TrueOrFalse(CanHandleWith(aPresContext)), aElement,
    673       TrueOrFalse(remoteHasFocus), ToString(aAction.mCause).c_str(),
    674       ToString(aAction.mFocusChange).c_str(), sFocusedPresContext.get(),
    675       TrueOrFalse(CanHandleWith(sFocusedPresContext)), sFocusedElement.get(),
    676       sTextInputHandlingWidget,
    677       TrueOrFalse(sTextInputHandlingWidget &&
    678                   !sTextInputHandlingWidget->Destroyed()),
    679       BrowserParent::GetFocused(), sActiveIMEContentObserver.get(),
    680       TrueOrFalse(sInstalledMenuKeyboardListener), TrueOrFalse(sIsActive),
    681       TrueOrFalse(restoringContextForRemoteContent)));
    682  if (aElement) {
    683    MOZ_LOG(sISMLog, LogLevel::Debug,
    684            ("  aElement:        %s", ToString(*aElement).c_str()));
    685  }
    686  if (sFocusedElement) {
    687    MOZ_LOG(sISMLog, LogLevel::Debug,
    688            ("  sFocusedElement: %s", ToString(*sFocusedElement).c_str()));
    689  }
    690 
    691  sIsActive = !!aPresContext;
    692  if (sPendingFocusedBrowserSwitchingData.isSome()) {
    693    MOZ_ASSERT(XRE_IsParentProcess());
    694    RefPtr<Element> focusedElement = sFocusedElement;
    695    RefPtr<nsPresContext> focusedPresContext = sFocusedPresContext;
    696    RefPtr<BrowserParent> browserParentBlurred =
    697        sPendingFocusedBrowserSwitchingData.ref().mBrowserParentBlurred;
    698    RefPtr<BrowserParent> browserParentFocused =
    699        sPendingFocusedBrowserSwitchingData.ref().mBrowserParentFocused;
    700    OnFocusMovedBetweenBrowsers(browserParentBlurred, browserParentFocused);
    701    // If another call of this method happens during the
    702    // OnFocusMovedBetweenBrowsers call, we shouldn't take back focus to
    703    // the old one.
    704    if (focusedElement != sFocusedElement.get() ||
    705        focusedPresContext != sFocusedPresContext.get()) {
    706      MOZ_LOG(sISMLog, LogLevel::Debug,
    707              ("  OnChangeFocusInternal(aPresContext=0x%p, aElement=0x%p) "
    708               "stoped handling it because the focused content was changed to "
    709               "sFocusedPresContext=0x%p, sFocusedElement=0x%p by another call",
    710               aPresContext, aElement, sFocusedPresContext.get(),
    711               sFocusedElement.get()));
    712      return NS_OK;
    713    }
    714  }
    715 
    716  // If new aPresShell has been destroyed, this should handle the focus change
    717  // as nobody is getting focus.
    718  MOZ_ASSERT_IF(!aPresContext, !aElement);
    719  if (NS_WARN_IF(aPresContext && !CanHandleWith(aPresContext))) {
    720    MOZ_LOG(sISMLog, LogLevel::Warning,
    721            ("  OnChangeFocusInternal(), called with destroyed PresShell, "
    722             "handling this call as nobody getting focus"));
    723    aPresContext = nullptr;
    724    aElement = nullptr;
    725  } else if (!aPresContext) {
    726    aElement = nullptr;
    727  }
    728 
    729  const nsCOMPtr<nsIWidget> oldWidget = sTextInputHandlingWidget;
    730  const nsCOMPtr<nsIWidget> newWidget =
    731      aPresContext ? aPresContext->GetTextInputHandlingWidget() : nullptr;
    732  const bool focusActuallyChanging =
    733      (sFocusedElement != aElement || sFocusedPresContext != aPresContext ||
    734       oldWidget != newWidget ||
    735       (remoteHasFocus && !restoringContextForRemoteContent &&
    736        (aAction.mFocusChange != InputContextAction::MENU_GOT_PSEUDO_FOCUS)));
    737 
    738  // If old widget has composition, we may need to commit composition since
    739  // a native IME context is shared on all editors on some widgets or all
    740  // widgets (it depends on platforms).
    741  if (oldWidget && focusActuallyChanging && sTextCompositions) {
    742    RefPtr<TextComposition> composition =
    743        sTextCompositions->GetCompositionFor(oldWidget);
    744    if (composition) {
    745      // However, don't commit the composition if we're being inactivated
    746      // but the composition should be kept even during deactive.
    747      // Note that oldWidget and sFocusedIMEWidget may be different here (in
    748      // such case, sFocusedIMEWidget is perhaps nullptr).  For example, IME
    749      // may receive only blur notification but still has composition.
    750      // We need to clean up only the oldWidget's composition state here.
    751      if (aPresContext ||
    752          !oldWidget->IMENotificationRequestsRef().WantDuringDeactive()) {
    753        MOZ_LOG(
    754            sISMLog, LogLevel::Info,
    755            ("  OnChangeFocusInternal(), requesting to commit composition to "
    756             "the (previous) focused widget"));
    757        NotifyIME(REQUEST_TO_COMMIT_COMPOSITION, oldWidget,
    758                  composition->GetBrowserParent());
    759      }
    760    }
    761  }
    762 
    763  if (sActiveIMEContentObserver) {
    764    MOZ_ASSERT(!remoteHasFocus || XRE_IsContentProcess(),
    765               "IMEContentObserver should have been destroyed by "
    766               "OnFocusMovedBetweenBrowsers.");
    767    if (!aPresContext) {
    768      if (!sActiveIMEContentObserver->KeepAliveDuringDeactive()) {
    769        DestroyIMEContentObserver();
    770      }
    771    }
    772    // Otherwise, i.e., new focused content is in this process, let's check
    773    // whether the editable content for aElement has already been being observed
    774    // by the active IMEContentObserver.  If not, let's stop observing the
    775    // editable content which is being blurred.
    776    else if (!sActiveIMEContentObserver->IsObserving(*aPresContext, aElement)) {
    777      DestroyIMEContentObserver();
    778    }
    779  }
    780 
    781  if (!aPresContext) {
    782    MOZ_LOG(sISMLog, LogLevel::Debug,
    783            ("  OnChangeFocusInternal(), no nsPresContext is being activated"));
    784    return NS_OK;
    785  }
    786 
    787  if (NS_WARN_IF(!newWidget)) {
    788    MOZ_LOG(sISMLog, LogLevel::Error,
    789            ("  OnChangeFocusInternal(), FAILED due to no widget to manage its "
    790             "IME state"));
    791    return NS_OK;
    792  }
    793 
    794  // Update the cached widget since root view of the presContext may be
    795  // changed to different view.
    796  sTextInputHandlingWidget = newWidget;
    797 
    798  // If a child process has focus, we should disable IME state until the child
    799  // process actually gets focus because if user types keys before that they
    800  // are handled by IME.
    801  IMEState newState = remoteHasFocus ? IMEState(IMEEnabled::Disabled)
    802                                     : GetNewIMEState(*aPresContext, aElement);
    803  bool setIMEState = true;
    804 
    805  const auto CanSkipSettingContext = [&](const InputContext& aOldContext) {
    806    const auto IsChangingBrowsingMode = [&]() {
    807      const bool willBeInPrivateBrowsingMode =
    808          aPresContext && aPresContext->Document() &&
    809          aPresContext->Document()->IsInPrivateBrowsing();
    810      return willBeInPrivateBrowsingMode != aOldContext.mInPrivateBrowsing;
    811    };
    812    const auto IsChangingURI = [&]() {
    813      const nsCOMPtr<nsIURI> newURI =
    814          IMEStateManager::GetExposableURL(aPresContext);
    815      if (!newURI != !aOldContext.mURI) {
    816        return true;  // One is not exposable URI.
    817      }
    818      if (!newURI) {
    819        MOZ_ASSERT(!aOldContext.mURI);
    820        return false;  // Moved in non-exposable URIs.
    821      }
    822      bool same = false;
    823      return NS_FAILED(newURI->Equals(aOldContext.mURI, &same)) || !same;
    824    };
    825    return !IsChangingBrowsingMode() && !IsChangingURI();
    826  };
    827 
    828  if (remoteHasFocus && XRE_IsParentProcess()) {
    829    if (aAction.mFocusChange == InputContextAction::MENU_GOT_PSEUDO_FOCUS) {
    830      // If menu keyboard listener is installed, we need to disable IME now.
    831      setIMEState = true;
    832    } else if (aAction.mFocusChange ==
    833               InputContextAction::MENU_LOST_PSEUDO_FOCUS) {
    834      // If menu keyboard listener is uninstalled, we need to restore
    835      // input context which was set by the remote process.  However, if
    836      // the remote process hasn't been set input context yet, we need to
    837      // wait next SetInputContextForChildProcess() call.
    838      if (HasActiveChildSetInputContext()) {
    839        setIMEState = true;
    840        newState = sActiveChildInputContext.mIMEState;
    841      } else {
    842        setIMEState = false;
    843      }
    844    } else if (focusActuallyChanging) {
    845      InputContext context = newWidget->GetInputContext();
    846      if (context.mIMEState.mEnabled == IMEEnabled::Disabled &&
    847          context.mOrigin == InputContext::ORIGIN_CONTENT &&
    848          CanSkipSettingContext(context)) {
    849        setIMEState = false;
    850        MOZ_LOG(sISMLog, LogLevel::Debug,
    851                ("  OnChangeFocusInternal(), doesn't set IME state because "
    852                 "focused element (or document) is in a child process and the "
    853                 "IME state is already disabled by a remote process"));
    854      } else {
    855        // When new remote process gets focus, we should forget input context
    856        // coming from old focused remote process.
    857        ResetActiveChildInputContext();
    858        MOZ_LOG(sISMLog, LogLevel::Debug,
    859                ("  OnChangeFocusInternal(), will disable IME until new "
    860                 "focused element (or document) in the child process will get "
    861                 "focus actually"));
    862      }
    863    } else if (newWidget->GetInputContext().mOrigin !=
    864                   InputContext::ORIGIN_MAIN &&
    865               CanSkipSettingContext(newWidget->GetInputContext())) {
    866      // When focus is NOT changed actually, we shouldn't set IME state if
    867      // current input context was set by a remote process since that means
    868      // that the window is being activated and the child process may have
    869      // composition.  Then, we shouldn't commit the composition with making
    870      // IME state disabled.
    871      setIMEState = false;
    872      MOZ_LOG(
    873          sISMLog, LogLevel::Debug,
    874          ("  OnChangeFocusInternal(), doesn't set IME state because focused "
    875           "element (or document) is already in the child process"));
    876    }
    877  } else {
    878    // When this process gets focus, we should forget input context coming
    879    // from remote process.
    880    ResetActiveChildInputContext();
    881  }
    882 
    883  if (setIMEState) {
    884    if (!focusActuallyChanging) {
    885      // actual focus isn't changing, but if IME enabled state is changing,
    886      // we should do it.
    887      InputContext context = newWidget->GetInputContext();
    888      if (context.mIMEState.mEnabled == newState.mEnabled &&
    889          CanSkipSettingContext(context)) {
    890        MOZ_LOG(sISMLog, LogLevel::Debug,
    891                ("  OnChangeFocusInternal(), neither focus nor IME state is "
    892                 "changing"));
    893        return NS_OK;
    894      }
    895      aAction.mFocusChange = InputContextAction::FOCUS_NOT_CHANGED;
    896 
    897      // Even if focus isn't changing actually, we should commit current
    898      // composition here since the IME state is changing.
    899      if (sFocusedPresContext && oldWidget) {
    900        NotifyIME(REQUEST_TO_COMMIT_COMPOSITION, oldWidget,
    901                  sFocusedIMEBrowserParent);
    902      }
    903    } else if (aAction.mFocusChange == InputContextAction::FOCUS_NOT_CHANGED) {
    904      // If aElement isn't null or aElement is null but editable, somebody gets
    905      // focus.
    906      bool gotFocus = aElement || (newState.mEnabled == IMEEnabled::Enabled);
    907      aAction.mFocusChange = gotFocus ? InputContextAction::GOT_FOCUS
    908                                      : InputContextAction::LOST_FOCUS;
    909    }
    910 
    911    if (remoteHasFocus && HasActiveChildSetInputContext() &&
    912        aAction.mFocusChange == InputContextAction::MENU_LOST_PSEUDO_FOCUS) {
    913      // Restore the input context in the active remote process when
    914      // menu keyboard listener is uninstalled and active remote tab has
    915      // focus.
    916      SetInputContext(*newWidget, sActiveChildInputContext, aAction);
    917    } else {
    918      // Update IME state for new focus widget
    919      SetIMEState(newState, aPresContext, aElement, *newWidget, aAction,
    920                  remoteHasFocus ? InputContext::ORIGIN_CONTENT : sOrigin);
    921    }
    922  }
    923 
    924  sFocusedPresContext = aPresContext;
    925  sFocusedElement = aElement;
    926 
    927  // Don't call CreateIMEContentObserver() here  because it will be called from
    928  // the focus event handler of focused editor.
    929 
    930  MOZ_LOG(sISMLog, LogLevel::Debug,
    931          ("  OnChangeFocusInternal(), modified IME state for "
    932           "sFocusedPresContext=0x%p, sFocusedElement=0x%p",
    933           sFocusedPresContext.get(), sFocusedElement.get()));
    934 
    935  return NS_OK;
    936 }
    937 
    938 // static
    939 void IMEStateManager::OnInstalledMenuKeyboardListener(bool aInstalling) {
    940  MOZ_LOG(
    941      sISMLog, LogLevel::Info,
    942      ("OnInstalledMenuKeyboardListener(aInstalling=%s), "
    943       "nsContentUtils::IsSafeToRunScript()=%s, "
    944       "sInstalledMenuKeyboardListener=%s, BrowserParent::GetFocused()=0x%p, "
    945       "sActiveChildInputContext=%s, sFocusedPresContext=0x%p, "
    946       "sFocusedElement=0x%p, sPseudoFocusChangeRunnable=0x%p",
    947       TrueOrFalse(aInstalling),
    948       TrueOrFalse(nsContentUtils::IsSafeToRunScript()),
    949       TrueOrFalse(sInstalledMenuKeyboardListener), BrowserParent::GetFocused(),
    950       ToString(sActiveChildInputContext).c_str(), sFocusedPresContext.get(),
    951       sFocusedElement.get(), sPseudoFocusChangeRunnable.get()));
    952 
    953  // Update the state whether the menubar has pseudo focus or not immediately.
    954  // This will be referred by the runner which is created below.
    955  sInstalledMenuKeyboardListener = aInstalling;
    956  // However, this may be called when it's not safe to run script.  Therefore,
    957  // we need to create a runnable to notify IME of the pseudo focus change.
    958  if (sPseudoFocusChangeRunnable) {
    959    return;
    960  }
    961  sPseudoFocusChangeRunnable = new PseudoFocusChangeRunnable(aInstalling);
    962  nsContentUtils::AddScriptRunner(sPseudoFocusChangeRunnable);
    963 }
    964 
    965 // static
    966 void IMEStateManager::SetMenubarPseudoFocus(
    967    PseudoFocusChangeRunnable* aCaller, bool aSetPseudoFocus,
    968    nsPresContext* aFocusedPresContextAtRequested) {
    969  MOZ_LOG(
    970      sISMLog, LogLevel::Info,
    971      ("SetMenubarPseudoFocus(aCaller=0x%p, aSetPseudoFocus=%s, "
    972       "aFocusedPresContextAtRequested=0x%p), "
    973       "sInstalledMenuKeyboardListener=%s, sFocusedPresContext=0x%p, "
    974       "sFocusedElement=0x%p, sPseudoFocusChangeRunnable=0x%p",
    975       aCaller, TrueOrFalse(aSetPseudoFocus), aFocusedPresContextAtRequested,
    976       TrueOrFalse(sInstalledMenuKeyboardListener), sFocusedPresContext.get(),
    977       sFocusedElement.get(), sPseudoFocusChangeRunnable.get()));
    978 
    979  MOZ_ASSERT(sPseudoFocusChangeRunnable.get() == aCaller);
    980 
    981  // Clear the runnable first for nested call of
    982  // OnInstalledMenuKeyboardListener().
    983  RefPtr<PseudoFocusChangeRunnable> runningOne =
    984      sPseudoFocusChangeRunnable.forget();
    985  MOZ_ASSERT(!sPseudoFocusChangeRunnable);
    986 
    987  // If the requested state is still same, let's make the menubar get
    988  // pseudo focus with the latest focused PresContext and Element.
    989  // Note that this is no problem even after the focused element is changed
    990  // after aCaller is created because only sInstalledMenuKeyboardListener
    991  // manages the state and current focused PresContext and element should be
    992  // used only for restoring the focus from the menubar.  So, restoring
    993  // focus with the lasted one does make sense.
    994  if (sInstalledMenuKeyboardListener == aSetPseudoFocus) {
    995    InputContextAction action(InputContextAction::CAUSE_UNKNOWN,
    996                              aSetPseudoFocus
    997                                  ? InputContextAction::MENU_GOT_PSEUDO_FOCUS
    998                                  : InputContextAction::MENU_LOST_PSEUDO_FOCUS);
    999    RefPtr<nsPresContext> focusedPresContext = sFocusedPresContext;
   1000    RefPtr<Element> focusedElement = sFocusedElement;
   1001    OnChangeFocusInternal(focusedPresContext, focusedElement, action);
   1002    return;
   1003  }
   1004 
   1005  // If the requested state is different from current state, we don't need to
   1006  // make the menubar get and lose pseudo focus because of redundant. However,
   1007  // if there is a composition on the original focused element, we need to
   1008  // commit it because pseudo focus move should've caused it.
   1009  if (!aFocusedPresContextAtRequested) {
   1010    return;
   1011  }
   1012  RefPtr<TextComposition> composition =
   1013      GetTextCompositionFor(aFocusedPresContextAtRequested);
   1014  if (!composition) {
   1015    return;
   1016  }
   1017  if (nsCOMPtr<nsIWidget> widget =
   1018          aFocusedPresContextAtRequested->GetTextInputHandlingWidget()) {
   1019    composition->RequestToCommit(widget, false);
   1020  }
   1021 }
   1022 
   1023 // static
   1024 bool IMEStateManager::OnMouseButtonEventInEditor(
   1025    nsPresContext& aPresContext, Element* aElement,
   1026    WidgetMouseEvent& aMouseEvent) {
   1027  MOZ_LOG(sISMLog, LogLevel::Info,
   1028          ("OnMouseButtonEventInEditor(aPresContext=0x%p (available: %s), "
   1029           "aElement=0x%p, aMouseEvent=0x%p), sFocusedPresContext=0x%p, "
   1030           "sFocusedElement=0x%p",
   1031           &aPresContext, TrueOrFalse(CanHandleWith(&aPresContext)), aElement,
   1032           &aMouseEvent, sFocusedPresContext.get(), sFocusedElement.get()));
   1033 
   1034  if (sFocusedPresContext != &aPresContext || sFocusedElement != aElement) {
   1035    MOZ_LOG(sISMLog, LogLevel::Debug,
   1036            ("  OnMouseButtonEventInEditor(), "
   1037             "the mouse event isn't fired on the editor managed by ISM"));
   1038    return false;
   1039  }
   1040 
   1041  if (!sActiveIMEContentObserver) {
   1042    MOZ_LOG(sISMLog, LogLevel::Debug,
   1043            ("  OnMouseButtonEventInEditor(), "
   1044             "there is no active IMEContentObserver"));
   1045    return false;
   1046  }
   1047 
   1048  if (!sActiveIMEContentObserver->IsObserving(aPresContext, aElement)) {
   1049    MOZ_LOG(sISMLog, LogLevel::Debug,
   1050            ("  OnMouseButtonEventInEditor(), "
   1051             "the active IMEContentObserver isn't managing the editor"));
   1052    return false;
   1053  }
   1054 
   1055  OwningNonNull<IMEContentObserver> observer = *sActiveIMEContentObserver;
   1056  bool consumed = observer->OnMouseButtonEvent(aPresContext, aMouseEvent);
   1057  MOZ_LOG(sISMLog, LogLevel::Info,
   1058          ("  OnMouseButtonEventInEditor(), "
   1059           "mouse event (mMessage=%s, mButton=%d) is %s",
   1060           ToChar(aMouseEvent.mMessage), aMouseEvent.mButton,
   1061           consumed ? "consumed" : "not consumed"));
   1062  return consumed;
   1063 }
   1064 
   1065 // static
   1066 void IMEStateManager::OnClickInEditor(nsPresContext& aPresContext,
   1067                                      Element* aElement,
   1068                                      const WidgetMouseEvent& aMouseEvent) {
   1069  MOZ_LOG(sISMLog, LogLevel::Info,
   1070          ("OnClickInEditor(aPresContext=0x%p (available: %s), aElement=0x%p, "
   1071           "aMouseEvent=0x%p), sFocusedPresContext=0x%p, sFocusedElement=0x%p, "
   1072           "sTextInputHandlingWidget=0x%p (available: %s)",
   1073           &aPresContext, TrueOrFalse(CanHandleWith(&aPresContext)), aElement,
   1074           &aMouseEvent, sFocusedPresContext.get(), sFocusedElement.get(),
   1075           sTextInputHandlingWidget,
   1076           TrueOrFalse(sTextInputHandlingWidget &&
   1077                       !sTextInputHandlingWidget->Destroyed())));
   1078 
   1079  if (sFocusedPresContext != &aPresContext || sFocusedElement != aElement ||
   1080      NS_WARN_IF(!sFocusedPresContext) ||
   1081      NS_WARN_IF(!sTextInputHandlingWidget) ||
   1082      NS_WARN_IF(sTextInputHandlingWidget->Destroyed())) {
   1083    MOZ_LOG(sISMLog, LogLevel::Debug,
   1084            ("  OnClickInEditor(), "
   1085             "the mouse event isn't fired on the editor managed by ISM"));
   1086    return;
   1087  }
   1088 
   1089  const OwningNonNull<nsIWidget> textInputHandlingWidget =
   1090      *sTextInputHandlingWidget;
   1091  MOZ_ASSERT_IF(sFocusedPresContext->GetTextInputHandlingWidget(),
   1092                sFocusedPresContext->GetTextInputHandlingWidget() ==
   1093                    textInputHandlingWidget.get());
   1094 
   1095  if (!aMouseEvent.IsTrusted()) {
   1096    MOZ_LOG(sISMLog, LogLevel::Debug,
   1097            ("  OnClickInEditor(), "
   1098             "the mouse event isn't a trusted event"));
   1099    return;  // ignore untrusted event.
   1100  }
   1101 
   1102  if (aMouseEvent.mButton) {
   1103    MOZ_LOG(sISMLog, LogLevel::Debug,
   1104            ("  OnClickInEditor(), "
   1105             "the mouse event isn't a left mouse button event"));
   1106    return;  // not a left click event.
   1107  }
   1108 
   1109  if (aMouseEvent.mClickCount != 1) {
   1110    MOZ_LOG(sISMLog, LogLevel::Debug,
   1111            ("  OnClickInEditor(), "
   1112             "the mouse event isn't a single click event"));
   1113    return;  // should notify only first click event.
   1114  }
   1115 
   1116  MOZ_ASSERT_IF(aElement, !EventStateManager::IsRemoteTarget(aElement));
   1117  InputContextAction::Cause cause =
   1118      aMouseEvent.mInputSource == MouseEvent_Binding::MOZ_SOURCE_TOUCH
   1119          ? InputContextAction::CAUSE_TOUCH
   1120          : InputContextAction::CAUSE_MOUSE;
   1121 
   1122  InputContextAction action(cause, InputContextAction::FOCUS_NOT_CHANGED);
   1123  IMEState newState = GetNewIMEState(aPresContext, aElement);
   1124  // If the state is not editable, there should be no active IMEContentObserver.
   1125  // However, if this click sets focus to the editor, IMEContentObserver may
   1126  // have not been created yet.  Instead, if there is active IMEContentObserver,
   1127  // it should be editable.
   1128  MOZ_ASSERT_IF(!newState.IsEditable(), !sActiveIMEContentObserver);
   1129  MOZ_ASSERT_IF(sActiveIMEContentObserver, newState.IsEditable());
   1130  SetIMEState(newState, &aPresContext, aElement, textInputHandlingWidget,
   1131              action, sOrigin);
   1132 }
   1133 
   1134 // static
   1135 Element* IMEStateManager::GetFocusedElement() { return sFocusedElement; }
   1136 
   1137 // static
   1138 bool IMEStateManager::IsFocusedElement(const nsPresContext& aPresContext,
   1139                                       const Element* aFocusedElement) {
   1140  if (!sFocusedPresContext || &aPresContext != sFocusedPresContext) {
   1141    return false;
   1142  }
   1143 
   1144  if (sFocusedElement == aFocusedElement) {
   1145    return true;
   1146  }
   1147 
   1148  // If sFocusedElement is not nullptr, but aFocusedElement is nullptr, it does
   1149  // not have focus from point of view of IMEStateManager.
   1150  if (sFocusedElement) {
   1151    return false;
   1152  }
   1153 
   1154  // If the caller does not think that nobody has focus, but we know there is
   1155  // a focused content, the caller must be called with wrong content.
   1156  if (!aFocusedElement) {
   1157    return false;
   1158  }
   1159 
   1160  // If the aFocusedElement is in design mode, sFocusedElement may be nullptr.
   1161  if (aFocusedElement->IsInDesignMode()) {
   1162    MOZ_ASSERT(&aPresContext == sFocusedPresContext && !sFocusedElement);
   1163    return true;
   1164  }
   1165 
   1166  // Otherwise, only when aFocusedElement is the root element, it can have
   1167  // focus, but IMEStateManager::OnChangeFocus is called with nullptr for
   1168  // aFocusedElement if it was not editable.
   1169  // XXX In this case, should the caller update sFocusedElement?
   1170  return aFocusedElement->IsEditable() && sFocusedPresContext->Document() &&
   1171         sFocusedPresContext->Document()->GetRootElement() == aFocusedElement;
   1172 }
   1173 
   1174 // static
   1175 void IMEStateManager::OnFocusInEditor(nsPresContext& aPresContext,
   1176                                      Element* aElement,
   1177                                      EditorBase& aEditorBase) {
   1178  MOZ_LOG(sISMLog, LogLevel::Info,
   1179          ("OnFocusInEditor(aPresContext=0x%p (available: %s), aElement=0x%p, "
   1180           "aEditorBase=0x%p), sFocusedPresContext=0x%p, sFocusedElement=0x%p, "
   1181           "sActiveIMEContentObserver=0x%p",
   1182           &aPresContext, TrueOrFalse(CanHandleWith(&aPresContext)), aElement,
   1183           &aEditorBase, sFocusedPresContext.get(), sFocusedElement.get(),
   1184           sActiveIMEContentObserver.get()));
   1185  if (aElement) {
   1186    MOZ_LOG(sISMLog, LogLevel::Debug,
   1187            ("  aElement:        %s", ToString(*aElement).c_str()));
   1188  }
   1189  if (sFocusedElement) {
   1190    MOZ_LOG(sISMLog, LogLevel::Debug,
   1191            ("  sFocusedElement: %s", ToString(*sFocusedElement).c_str()));
   1192  }
   1193 
   1194  if (!IsFocusedElement(aPresContext, aElement)) {
   1195    MOZ_LOG(sISMLog, LogLevel::Debug,
   1196            ("  OnFocusInEditor(), "
   1197             "an editor not managed by ISM gets focus"));
   1198    return;
   1199  }
   1200  MOZ_ASSERT(sTextInputHandlingWidget);
   1201 
   1202  // If the IMEContentObserver instance isn't observing the editable content for
   1203  // aElement, we need to recreate the instance because the active observer is
   1204  // observing different content even if aElement keeps being focused.  E.g.,
   1205  // it's an <input> and editing host but was not a text control, but now, it's
   1206  // a text control.
   1207  if (sActiveIMEContentObserver) {
   1208    if (sActiveIMEContentObserver->IsObserving(aPresContext, aElement)) {
   1209      MOZ_LOG(sISMLog, LogLevel::Debug,
   1210              ("  OnFocusInEditor(), "
   1211               "the editable content for aEditorBase has already been being "
   1212               "observed by sActiveIMEContentObserver"));
   1213      return;
   1214    }
   1215    // If the IMEContentObserver has not finished initializing itself yet,
   1216    // we don't need to recreate it because the following
   1217    // TryToFlushPendingNotifications call must make it initialized.
   1218    const nsCOMPtr<nsIWidget> textInputHandlingWidget =
   1219        sTextInputHandlingWidget;
   1220    if (!sActiveIMEContentObserver->IsBeingInitializedFor(
   1221            aPresContext, aElement, aEditorBase)) {
   1222      DestroyIMEContentObserver();
   1223    }
   1224    if (NS_WARN_IF(!IsFocusedElement(aPresContext, aElement)) ||
   1225        NS_WARN_IF(!sTextInputHandlingWidget) ||
   1226        NS_WARN_IF(sTextInputHandlingWidget != textInputHandlingWidget)) {
   1227      MOZ_LOG(sISMLog, LogLevel::Error,
   1228              ("  OnFocusInEditor(), detected unexpected focus change with "
   1229               "re-initializing active IMEContentObserver"));
   1230      return;
   1231    }
   1232  }
   1233 
   1234  if (!sActiveIMEContentObserver && sTextInputHandlingWidget &&
   1235      IsIMEObserverNeeded(
   1236          sTextInputHandlingWidget->GetInputContext().mIMEState)) {
   1237    CreateIMEContentObserver(aEditorBase, aElement);
   1238    if (sActiveIMEContentObserver) {
   1239      MOZ_LOG(sISMLog, LogLevel::Debug,
   1240              ("  OnFocusInEditor(), new IMEContentObserver is created (0x%p)",
   1241               sActiveIMEContentObserver.get()));
   1242    }
   1243  }
   1244 
   1245  if (sActiveIMEContentObserver) {
   1246    sActiveIMEContentObserver->TryToFlushPendingNotifications(false);
   1247    MOZ_LOG(sISMLog, LogLevel::Debug,
   1248            ("  OnFocusInEditor(), trying to send pending notifications in "
   1249             "the active IMEContentObserver (0x%p)...",
   1250             sActiveIMEContentObserver.get()));
   1251  }
   1252 }
   1253 
   1254 // static
   1255 void IMEStateManager::OnEditorInitialized(EditorBase& aEditorBase) {
   1256  if (!sActiveIMEContentObserver ||
   1257      !sActiveIMEContentObserver->WasInitializedWith(aEditorBase)) {
   1258    return;
   1259  }
   1260 
   1261  MOZ_LOG(sISMLog, LogLevel::Info,
   1262          ("OnEditorInitialized(aEditorBase=0x%p)", &aEditorBase));
   1263 
   1264  sActiveIMEContentObserver->UnsuppressNotifyingIME();
   1265 }
   1266 
   1267 // static
   1268 void IMEStateManager::OnEditorDestroying(EditorBase& aEditorBase) {
   1269  if (!sActiveIMEContentObserver ||
   1270      !sActiveIMEContentObserver->WasInitializedWith(aEditorBase)) {
   1271    return;
   1272  }
   1273 
   1274  MOZ_LOG(sISMLog, LogLevel::Info,
   1275          ("OnEditorDestroying(aEditorBase=0x%p)", &aEditorBase));
   1276 
   1277  // The IMEContentObserver shouldn't notify IME of anything until reframing
   1278  // is finished.
   1279  sActiveIMEContentObserver->SuppressNotifyingIME();
   1280 }
   1281 
   1282 void IMEStateManager::OnReFocus(nsPresContext& aPresContext,
   1283                                Element& aElement) {
   1284  MOZ_LOG(sISMLog, LogLevel::Info,
   1285          ("OnReFocus(aPresContext=0x%p (available: %s), aElement=0x%p), "
   1286           "sActiveIMEContentObserver=0x%p, sFocusedElement=0x%p",
   1287           &aPresContext, TrueOrFalse(CanHandleWith(&aPresContext)), &aElement,
   1288           sActiveIMEContentObserver.get(), sFocusedElement.get()));
   1289  MOZ_LOG(sISMLog, LogLevel::Debug,
   1290          ("  aElement:        %s", ToString(aElement).c_str()));
   1291  if (sFocusedElement) {
   1292    MOZ_LOG(sISMLog, LogLevel::Debug,
   1293            ("  sFocusedElement: %s", ToString(*sFocusedElement).c_str()));
   1294  }
   1295 
   1296  if (NS_WARN_IF(!sTextInputHandlingWidget) ||
   1297      NS_WARN_IF(sTextInputHandlingWidget->Destroyed())) {
   1298    return;
   1299  }
   1300 
   1301  // Check if IME has focus.  If and only if IME has focus, we may need to
   1302  // update IME state of the widget to re-open VKB.  Otherwise, IME will open
   1303  // VKB at getting focus.
   1304  if (!sActiveIMEContentObserver ||
   1305      !sActiveIMEContentObserver->IsObserving(aPresContext, &aElement)) {
   1306    MOZ_LOG(sISMLog, LogLevel::Debug,
   1307            ("  OnReFocus(), editable content for aElement was not being "
   1308             "observed by the sActiveIMEContentObserver"));
   1309    return;
   1310  }
   1311 
   1312  MOZ_ASSERT(&aElement == sFocusedElement.get());
   1313 
   1314  if (!UserActivation::IsHandlingUserInput() ||
   1315      UserActivation::IsHandlingKeyboardInput()) {
   1316    return;
   1317  }
   1318 
   1319  const OwningNonNull<nsIWidget> textInputHandlingWidget =
   1320      *sTextInputHandlingWidget;
   1321 
   1322  // Don't update IME state during composition.
   1323  if (sTextCompositions) {
   1324    if (const TextComposition* composition =
   1325            sTextCompositions->GetCompositionFor(textInputHandlingWidget)) {
   1326      if (composition->IsComposing()) {
   1327        return;
   1328      }
   1329    }
   1330  }
   1331 
   1332  const InputContextAction action(InputContextAction::CAUSE_UNKNOWN,
   1333                                  InputContextAction::FOCUS_NOT_CHANGED);
   1334  const IMEState newState = GetNewIMEState(aPresContext, &aElement);
   1335  // If aElement has not had a primary frame for it,
   1336  if (MOZ_UNLIKELY(!newState.IsEditable())) {
   1337    if (sActiveIMEContentObserver->EditorIsTextEditor()) {
   1338      TextControlElement* const textControlElement =
   1339          TextControlElement::FromNode(aElement);
   1340      MOZ_ASSERT(textControlElement);
   1341      if (textControlElement &&
   1342          textControlElement->IsSingleLineTextControlOrTextArea()) {
   1343        nsTextControlFrame* const boundFrame =
   1344            textControlElement->GetTextControlState()->GetBoundFrame();
   1345        MOZ_ASSERT(!boundFrame);
   1346        MOZ_LOG(
   1347            sISMLog, LogLevel::Warning,
   1348            ("  OnReFocus(), Temporarily disabling IME for the focused element "
   1349             "because probably the TextControlState could not return "
   1350             "TextEditor (textControlFrame: %p, textEditor: %p)",
   1351             boundFrame,
   1352             textControlElement->GetTextControlState()->GetExtantTextEditor()));
   1353      }
   1354    } else {
   1355      HTMLEditor* const htmlEditor =
   1356          nsContentUtils::GetHTMLEditor(&aPresContext);
   1357 #ifdef DEBUG
   1358      MOZ_ASSERT(htmlEditor);
   1359      Result<IMEState, nsresult> stateOrError =
   1360          htmlEditor->GetPreferredIMEState();
   1361      MOZ_ASSERT(stateOrError.isOk());
   1362      MOZ_ASSERT(!stateOrError.inspect().IsEditable());
   1363 #endif  // #ifdef DEBUG
   1364      MOZ_LOG(sISMLog, LogLevel::Warning,
   1365              ("  OnRefocus(), Disabling IME for the focused element, "
   1366               "HTMLEditor=%p { IsReadonly()=%s }",
   1367               htmlEditor,
   1368               htmlEditor ? TrueOrFalse(htmlEditor->IsReadonly()) : "N/A"));
   1369    }
   1370  }
   1371  SetIMEState(newState, &aPresContext, &aElement, textInputHandlingWidget,
   1372              action, sOrigin);
   1373 }
   1374 
   1375 // static
   1376 void IMEStateManager::MaybeOnEditableStateDisabled(nsPresContext& aPresContext,
   1377                                                   dom::Element* aElement) {
   1378  MOZ_LOG(
   1379      sISMLog, LogLevel::Info,
   1380      ("MaybeOnEditableStateDisabled(aPresContext=0x%p, aElement=0x%p), "
   1381       "sFocusedPresContext=0x%p (available: %s), "
   1382       "sFocusedElement=0x%p, sTextInputHandlingWidget=0x%p (available: %s), "
   1383       "sActiveIMEContentObserver=0x%p, sIsGettingNewIMEState=%s",
   1384       &aPresContext, aElement, sFocusedPresContext.get(),
   1385       TrueOrFalse(CanHandleWith(sFocusedPresContext)), sFocusedElement.get(),
   1386       sTextInputHandlingWidget,
   1387       TrueOrFalse(sTextInputHandlingWidget &&
   1388                   !sTextInputHandlingWidget->Destroyed()),
   1389       sActiveIMEContentObserver.get(), TrueOrFalse(sIsGettingNewIMEState)));
   1390 
   1391  if (sIsGettingNewIMEState) {
   1392    MOZ_LOG(sISMLog, LogLevel::Debug,
   1393            ("  MaybeOnEditableStateDisabled(), "
   1394             "does nothing because of called while getting new IME state"));
   1395    return;
   1396  }
   1397 
   1398  if (&aPresContext != sFocusedPresContext || aElement != sFocusedElement) {
   1399    MOZ_LOG(sISMLog, LogLevel::Debug,
   1400            ("  MaybeOnEditableStateDisabled(), "
   1401             "does nothing because of another element already has focus"));
   1402    return;
   1403  }
   1404 
   1405  if (NS_WARN_IF(!sTextInputHandlingWidget) ||
   1406      NS_WARN_IF(sTextInputHandlingWidget->Destroyed())) {
   1407    MOZ_LOG(sISMLog, LogLevel::Error,
   1408            ("  MaybeOnEditableStateDisabled(), FAILED due to "
   1409             "the widget for the managing the nsPresContext has gone"));
   1410    return;
   1411  }
   1412 
   1413  const OwningNonNull<nsIWidget> textInputHandlingWidget =
   1414      *sTextInputHandlingWidget;
   1415  MOZ_ASSERT_IF(sFocusedPresContext->GetTextInputHandlingWidget(),
   1416                sFocusedPresContext->GetTextInputHandlingWidget() ==
   1417                    textInputHandlingWidget.get());
   1418 
   1419  const IMEState newIMEState = GetNewIMEState(aPresContext, aElement);
   1420  // If IME state becomes editable, HTMLEditor should also be initialized with
   1421  // same path as it gets focus.  Therefore, IMEStateManager::UpdateIMEState
   1422  // should be called by HTMLEditor instead.
   1423  if (newIMEState.IsEditable()) {
   1424    MOZ_LOG(sISMLog, LogLevel::Debug,
   1425            ("  MaybeOnEditableStateDisabled(), "
   1426             "does nothing because IME state does not become disabled"));
   1427    return;
   1428  }
   1429 
   1430  // Otherwise, disable IME on the widget and destroy active IMEContentObserver
   1431  // if there is.
   1432  const InputContext inputContext = textInputHandlingWidget->GetInputContext();
   1433  if (inputContext.mIMEState.mEnabled == newIMEState.mEnabled) {
   1434    MOZ_LOG(sISMLog, LogLevel::Debug,
   1435            ("  MaybeOnEditableStateDisabled(), "
   1436             "does nothing because IME state is not changed"));
   1437    return;
   1438  }
   1439 
   1440  if (sActiveIMEContentObserver) {
   1441    DestroyIMEContentObserver();
   1442  }
   1443 
   1444  InputContextAction action(InputContextAction::CAUSE_UNKNOWN,
   1445                            InputContextAction::FOCUS_NOT_CHANGED);
   1446  SetIMEState(newIMEState, &aPresContext, aElement, textInputHandlingWidget,
   1447              action, sOrigin);
   1448 }
   1449 
   1450 // static
   1451 void IMEStateManager::UpdateIMEState(const IMEState& aNewIMEState,
   1452                                     Element* aElement, EditorBase& aEditorBase,
   1453                                     const UpdateIMEStateOptions& aOptions) {
   1454  MOZ_LOG(
   1455      sISMLog, LogLevel::Info,
   1456      ("UpdateIMEState(aNewIMEState=%s, aElement=0x%p, aEditorBase=0x%p, "
   1457       "aOptions=0x%0x), sFocusedPresContext=0x%p (available: %s), "
   1458       "sFocusedElement=0x%p, sTextInputHandlingWidget=0x%p (available: %s), "
   1459       "sActiveIMEContentObserver=0x%p, sIsGettingNewIMEState=%s",
   1460       ToString(aNewIMEState).c_str(), aElement, &aEditorBase,
   1461       aOptions.serialize(), sFocusedPresContext.get(),
   1462       TrueOrFalse(CanHandleWith(sFocusedPresContext)), sFocusedElement.get(),
   1463       sTextInputHandlingWidget,
   1464       TrueOrFalse(sTextInputHandlingWidget &&
   1465                   !sTextInputHandlingWidget->Destroyed()),
   1466       sActiveIMEContentObserver.get(), TrueOrFalse(sIsGettingNewIMEState)));
   1467  if (aElement) {
   1468    MOZ_LOG(sISMLog, LogLevel::Debug,
   1469            ("  aElement:        %s", ToString(*aElement).c_str()));
   1470  }
   1471  if (sFocusedElement) {
   1472    MOZ_LOG(sISMLog, LogLevel::Debug,
   1473            ("  sFocusedElement: %s", ToString(*sFocusedElement).c_str()));
   1474  }
   1475 
   1476  if (sIsGettingNewIMEState) {
   1477    MOZ_LOG(sISMLog, LogLevel::Debug,
   1478            ("  UpdateIMEState(), "
   1479             "does nothing because of called while getting new IME state"));
   1480    return;
   1481  }
   1482 
   1483  RefPtr<PresShell> presShell(aEditorBase.GetPresShell());
   1484  if (NS_WARN_IF(!presShell)) {
   1485    MOZ_LOG(sISMLog, LogLevel::Error,
   1486            ("  UpdateIMEState(), FAILED due to "
   1487             "editor doesn't have PresShell"));
   1488    return;
   1489  }
   1490 
   1491  const RefPtr<nsPresContext> presContext =
   1492      aElement
   1493          ? aElement->GetPresContext(Element::PresContextFor::eForComposedDoc)
   1494          : aEditorBase.GetPresContext();
   1495  if (NS_WARN_IF(!presContext)) {
   1496    MOZ_LOG(sISMLog, LogLevel::Error,
   1497            ("  UpdateIMEState(), FAILED due to "
   1498             "editor doesn't have PresContext"));
   1499    return;
   1500  }
   1501 
   1502  // IMEStateManager::UpdateIMEState() should be called after
   1503  // IMEStateManager::OnChangeFocus() is called for setting focus to aElement
   1504  // and aEditorBase.  However, when aEditorBase is an HTMLEditor, this may be
   1505  // called by nsIEditor::PostCreate() before IMEStateManager::OnChangeFocus().
   1506  // Similarly, when aEditorBase is a TextEditor, this may be called by
   1507  // nsIEditor::SetFlags().  In such cases, this method should do nothing
   1508  // because input context should be updated when
   1509  // IMEStateManager::OnChangeFocus() is called later.
   1510  if (sFocusedPresContext != presContext) {
   1511    MOZ_LOG(sISMLog, LogLevel::Warning,
   1512            ("  UpdateIMEState(), does nothing due to "
   1513             "the editor hasn't managed by IMEStateManager yet"));
   1514    return;
   1515  }
   1516 
   1517  // If IMEStateManager doesn't manage any document, this cannot update IME
   1518  // state of any widget.
   1519  if (NS_WARN_IF(!sFocusedPresContext)) {
   1520    MOZ_LOG(sISMLog, LogLevel::Error,
   1521            ("  UpdateIMEState(), FAILED due to "
   1522             "no managing nsPresContext"));
   1523    return;
   1524  }
   1525 
   1526  if (NS_WARN_IF(!sTextInputHandlingWidget) ||
   1527      NS_WARN_IF(sTextInputHandlingWidget->Destroyed())) {
   1528    MOZ_LOG(sISMLog, LogLevel::Error,
   1529            ("  UpdateIMEState(), FAILED due to "
   1530             "the widget for the managing nsPresContext has gone"));
   1531    return;
   1532  }
   1533 
   1534  const OwningNonNull<nsIWidget> textInputHandlingWidget =
   1535      *sTextInputHandlingWidget;
   1536  MOZ_ASSERT_IF(sFocusedPresContext->GetTextInputHandlingWidget(),
   1537                sFocusedPresContext->GetTextInputHandlingWidget() ==
   1538                    textInputHandlingWidget.get());
   1539 
   1540  // TODO: Investigate if we could put off to initialize IMEContentObserver
   1541  //       later because a lot of callers need to be marked as
   1542  //       MOZ_CAN_RUN_SCRIPT otherwise.
   1543 
   1544  // If there is an active observer and we need an observer, we want to keep
   1545  // using the observer as far as possible because it's already notified IME of
   1546  // focus.  However, between the call of OnChangeFocus() and UpdateIMEState(),
   1547  // focus and/or IME state may have been changed.  If so, we need to update
   1548  // the observer for current situation.
   1549  const bool hasActiveObserverAndNeedObserver =
   1550      sActiveIMEContentObserver && IsIMEObserverNeeded(aNewIMEState);
   1551 
   1552  // If the active observer was not initialized with aEditorBase, it means
   1553  // that the old editor lost focus but new editor gets focus **without**
   1554  // focus move in the DOM tree.  This may happen with changing the type of
   1555  // <input> element, etc.  In this case, we need to let IME know a focus move
   1556  // with recreating IMEContentObserver because editable target has been
   1557  // changed.
   1558  const bool needToRecreateObserver =
   1559      hasActiveObserverAndNeedObserver &&
   1560      !sActiveIMEContentObserver->WasInitializedWith(aEditorBase);
   1561 
   1562  // If the active observer was initialized with same editor, we can/should
   1563  // keep using it for avoiding to notify IME of a focus change.  However, we
   1564  // may need to re-initialize it because it may have temporarily stopped
   1565  // observing the content.
   1566  if (hasActiveObserverAndNeedObserver && !needToRecreateObserver) {
   1567    MOZ_LOG(sISMLog, LogLevel::Debug,
   1568            ("  UpdateIMEState(), try to reinitialize the active "
   1569             "IMEContentObserver"));
   1570    OwningNonNull<IMEContentObserver> contentObserver =
   1571        *sActiveIMEContentObserver;
   1572    OwningNonNull<nsPresContext> presContext = *sFocusedPresContext;
   1573    if (!contentObserver->MaybeReinitialize(
   1574            textInputHandlingWidget, presContext, aElement, aEditorBase)) {
   1575      MOZ_LOG(sISMLog, LogLevel::Error,
   1576              ("  UpdateIMEState(), failed to reinitialize the active "
   1577               "IMEContentObserver"));
   1578    }
   1579    if (NS_WARN_IF(textInputHandlingWidget->Destroyed())) {
   1580      MOZ_LOG(sISMLog, LogLevel::Error,
   1581              ("  UpdateIMEState(), widget has gone during re-initializing "
   1582               "the active IMEContentObserver"));
   1583      return;
   1584    }
   1585  }
   1586 
   1587  // If there is no active IMEContentObserver or it isn't observing the
   1588  // editable content for aElement, we should recreate an observer.  E.g.,
   1589  // aElement which is an editing host may have been changed from/to a text
   1590  // control.
   1591  const bool createNewObserver =
   1592      IsIMEObserverNeeded(aNewIMEState) &&
   1593      (!sActiveIMEContentObserver || needToRecreateObserver ||
   1594       !sActiveIMEContentObserver->IsObserving(*sFocusedPresContext, aElement));
   1595  // If we're recreating new IMEContentObserver or new state does not need
   1596  // IMEContentObserver, destroy the active one.
   1597  const bool destroyCurrentObserver =
   1598      sActiveIMEContentObserver &&
   1599      (createNewObserver || !IsIMEObserverNeeded(aNewIMEState));
   1600 
   1601  // If IME state is changed, e.g., from "enabled" or "password" to "disabled",
   1602  // we cannot keep the composing state because the new "disabled" state does
   1603  // not support composition, and also from "enabled" to "password" and vice
   1604  // versa, IME may use different composing rules.  Therefore, for avoiding
   1605  // IME to be confused, we should fix the composition first.
   1606  const bool updateIMEState =
   1607      aOptions.contains(UpdateIMEStateOption::ForceUpdate) ||
   1608      (textInputHandlingWidget->GetInputContext().mIMEState.mEnabled !=
   1609       aNewIMEState.mEnabled);
   1610  if (NS_WARN_IF(textInputHandlingWidget->Destroyed())) {
   1611    MOZ_LOG(
   1612        sISMLog, LogLevel::Error,
   1613        ("  UpdateIMEState(), widget has gone during getting input context"));
   1614    return;
   1615  }
   1616 
   1617  if (updateIMEState &&
   1618      !aOptions.contains(UpdateIMEStateOption::DontCommitComposition)) {
   1619    NotifyIME(REQUEST_TO_COMMIT_COMPOSITION, textInputHandlingWidget,
   1620              sFocusedIMEBrowserParent);
   1621    if (NS_WARN_IF(textInputHandlingWidget->Destroyed())) {
   1622      MOZ_LOG(sISMLog, LogLevel::Error,
   1623              ("  UpdateIMEState(), widget has gone during committing "
   1624               "composition"));
   1625      return;
   1626    }
   1627    // FIXME: If committing composition changes IME state recursively, we should
   1628    //        not keep updating IME state here.  However, how can we manage it?
   1629    //        Is a generation of the state is required?
   1630  }
   1631 
   1632  // Notify IME of blur first.
   1633  if (destroyCurrentObserver) {
   1634    DestroyIMEContentObserver();
   1635    if (NS_WARN_IF(textInputHandlingWidget->Destroyed()) ||
   1636        NS_WARN_IF(sTextInputHandlingWidget != textInputHandlingWidget)) {
   1637      MOZ_LOG(sISMLog, LogLevel::Error,
   1638              ("  UpdateIMEState(), has set input context, but the widget is "
   1639               "not focused"));
   1640      return;
   1641    }
   1642  }
   1643 
   1644  // Then, notify our IME handler of new IME state.
   1645  if (updateIMEState) {
   1646    InputContextAction action(InputContextAction::CAUSE_UNKNOWN,
   1647                              InputContextAction::FOCUS_NOT_CHANGED);
   1648    RefPtr<nsPresContext> editorPresContext = aEditorBase.GetPresContext();
   1649    if (NS_WARN_IF(!editorPresContext)) {
   1650      MOZ_LOG(sISMLog, LogLevel::Error,
   1651              ("  UpdateIMEState(), nsPresContext for editor has already been "
   1652               "lost"));
   1653      return;
   1654    }
   1655    SetIMEState(aNewIMEState, editorPresContext, aElement,
   1656                textInputHandlingWidget, action, sOrigin);
   1657    if (NS_WARN_IF(textInputHandlingWidget->Destroyed()) ||
   1658        NS_WARN_IF(sTextInputHandlingWidget != textInputHandlingWidget)) {
   1659      MOZ_LOG(sISMLog, LogLevel::Error,
   1660              ("  UpdateIMEState(), has set input context, but the widget is "
   1661               "not focused"));
   1662      return;
   1663    }
   1664    if (NS_WARN_IF(
   1665            sTextInputHandlingWidget->GetInputContext().mIMEState.mEnabled !=
   1666            aNewIMEState.mEnabled)) {
   1667      MOZ_LOG(sISMLog, LogLevel::Error,
   1668              ("  UpdateIMEState(), has set input context, but IME enabled "
   1669               "state was overridden by somebody else"));
   1670      return;
   1671    }
   1672  }
   1673 
   1674  NS_ASSERTION(IsFocusedElement(*presContext, aElement),
   1675               "aElement does not match with sFocusedElement");
   1676 
   1677  // Finally, create new observer if required.
   1678  if (createNewObserver) {
   1679    if (!sActiveIMEContentObserver && sFocusedPresContext &&
   1680        sTextInputHandlingWidget) {
   1681      // XXX In this case, it might not be enough safe to notify IME of
   1682      //     anything.  So, don't try to flush pending notifications of
   1683      //     IMEContentObserver here.
   1684      CreateIMEContentObserver(aEditorBase, aElement);
   1685    } else {
   1686      MOZ_LOG(sISMLog, LogLevel::Error,
   1687              ("  UpdateIMEState(), wanted to create IMEContentObserver, but "
   1688               "lost focus"));
   1689    }
   1690  }
   1691 }
   1692 
   1693 // static
   1694 IMEState IMEStateManager::GetNewIMEState(const nsPresContext& aPresContext,
   1695                                         Element* aElement) {
   1696  MOZ_LOG(
   1697      sISMLog, LogLevel::Info,
   1698      ("GetNewIMEState(aPresContext=0x%p, aElement=0x%p), "
   1699       "sInstalledMenuKeyboardListener=%s",
   1700       &aPresContext, aElement, TrueOrFalse(sInstalledMenuKeyboardListener)));
   1701 
   1702  if (!CanHandleWith(&aPresContext)) {
   1703    MOZ_LOG(sISMLog, LogLevel::Debug,
   1704            ("  GetNewIMEState() returns IMEEnabled::Disabled because "
   1705             "the nsPresContext has been destroyed"));
   1706    return IMEState(IMEEnabled::Disabled);
   1707  }
   1708 
   1709  // On Printing or Print Preview, we don't need IME.
   1710  if (aPresContext.Type() == nsPresContext::eContext_PrintPreview ||
   1711      aPresContext.Type() == nsPresContext::eContext_Print) {
   1712    MOZ_LOG(sISMLog, LogLevel::Debug,
   1713            ("  GetNewIMEState() returns IMEEnabled::Disabled because "
   1714             "the nsPresContext is for print or print preview"));
   1715    return IMEState(IMEEnabled::Disabled);
   1716  }
   1717 
   1718  if (sInstalledMenuKeyboardListener) {
   1719    MOZ_LOG(sISMLog, LogLevel::Debug,
   1720            ("  GetNewIMEState() returns IMEEnabled::Disabled because "
   1721             "menu keyboard listener was installed"));
   1722    return IMEState(IMEEnabled::Disabled);
   1723  }
   1724 
   1725  if (!aElement) {
   1726    // Even if there are no focused content, the focused document might be
   1727    // editable, such case is design mode.
   1728    if (aPresContext.Document() && aPresContext.Document()->IsInDesignMode()) {
   1729      if (aPresContext.Document()->GetRootElement()) {
   1730        MOZ_LOG(sISMLog, LogLevel::Debug,
   1731                ("  GetNewIMEState() returns IMEEnabled::Enabled because "
   1732                 "design mode editor has focus"));
   1733        return IMEState(IMEEnabled::Enabled);
   1734      }
   1735      MOZ_LOG(sISMLog, LogLevel::Debug,
   1736              ("  GetNewIMEState() returns IMEEnabled::Disabled because "
   1737               "document is in the design mode but has no element"));
   1738      return IMEState(IMEEnabled::Disabled);
   1739    }
   1740    MOZ_LOG(sISMLog, LogLevel::Debug,
   1741            ("  GetNewIMEState() returns IMEEnabled::Disabled because "
   1742             "no content has focus"));
   1743    return IMEState(IMEEnabled::Disabled);
   1744  }
   1745 
   1746  // If aElement is in designMode, aElement should be the root node of the
   1747  // document.
   1748  if (aElement && aElement->IsInDesignMode()) {
   1749    MOZ_LOG(sISMLog, LogLevel::Debug,
   1750            ("  GetNewIMEState() returns IMEEnabled::Enabled because "
   1751             "a content node in design mode editor has focus"));
   1752    return IMEState(IMEEnabled::Enabled);
   1753  }
   1754 
   1755  // nsIContent::GetDesiredIMEState() may cause a call of UpdateIMEState()
   1756  // from EditorBase::PostCreate() because GetDesiredIMEState() needs to
   1757  // retrieve an editor instance for the element if it's editable element.
   1758  // For avoiding such nested IME state updates, we should set
   1759  // sIsGettingNewIMEState here and UpdateIMEState() should check it.
   1760  GettingNewIMEStateBlocker blocker;
   1761 
   1762  IMEState newIMEState = aElement->GetDesiredIMEState();
   1763  MOZ_LOG(sISMLog, LogLevel::Debug,
   1764          ("  GetNewIMEState() returns %s", ToString(newIMEState).c_str()));
   1765  return newIMEState;
   1766 }
   1767 
   1768 // static
   1769 void IMEStateManager::ResetActiveChildInputContext() {
   1770  sActiveChildInputContext.mIMEState.mEnabled = IMEEnabled::Unknown;
   1771 }
   1772 
   1773 // static
   1774 bool IMEStateManager::HasActiveChildSetInputContext() {
   1775  return sActiveChildInputContext.mIMEState.mEnabled != IMEEnabled::Unknown;
   1776 }
   1777 
   1778 // static
   1779 void IMEStateManager::SetInputContextForChildProcess(
   1780    BrowserParent* aBrowserParent, const InputContext& aInputContext,
   1781    const InputContextAction& aAction) {
   1782  MOZ_LOG(
   1783      sISMLog, LogLevel::Info,
   1784      ("SetInputContextForChildProcess(aBrowserParent=0x%p, "
   1785       "aInputContext=%s , aAction={ mCause=%s, mAction=%s }), "
   1786       "sFocusedPresContext=0x%p (available: %s), "
   1787       "sTextInputHandlingWidget=0x%p (available: %s), "
   1788       "BrowserParent::GetFocused()=0x%p, sInstalledMenuKeyboardListener=%s",
   1789       aBrowserParent, ToString(aInputContext).c_str(),
   1790       ToString(aAction.mCause).c_str(), ToString(aAction.mFocusChange).c_str(),
   1791       sFocusedPresContext.get(),
   1792       TrueOrFalse(CanHandleWith(sFocusedPresContext)),
   1793       sTextInputHandlingWidget,
   1794       TrueOrFalse(sTextInputHandlingWidget &&
   1795                   !sTextInputHandlingWidget->Destroyed()),
   1796       BrowserParent::GetFocused(),
   1797       TrueOrFalse(sInstalledMenuKeyboardListener)));
   1798 
   1799  if (aBrowserParent != BrowserParent::GetFocused()) {
   1800    MOZ_LOG(sISMLog, LogLevel::Error,
   1801            ("  SetInputContextForChildProcess(), FAILED, "
   1802             "because non-focused tab parent tries to set input context"));
   1803    return;
   1804  }
   1805 
   1806  if (NS_WARN_IF(!CanHandleWith(sFocusedPresContext))) {
   1807    MOZ_LOG(sISMLog, LogLevel::Error,
   1808            ("  SetInputContextForChildProcess(), FAILED, "
   1809             "due to no focused presContext"));
   1810    return;
   1811  }
   1812 
   1813  if (NS_WARN_IF(!sTextInputHandlingWidget) ||
   1814      NS_WARN_IF(sTextInputHandlingWidget->Destroyed())) {
   1815    MOZ_LOG(sISMLog, LogLevel::Error,
   1816            ("  SetInputContextForChildProcess(), FAILED, "
   1817             "due to the widget for the nsPresContext has gone"));
   1818    return;
   1819  }
   1820 
   1821  const OwningNonNull<nsIWidget> textInputHandlingWidget =
   1822      *sTextInputHandlingWidget;
   1823  MOZ_ASSERT_IF(sFocusedPresContext->GetTextInputHandlingWidget(),
   1824                sFocusedPresContext->GetTextInputHandlingWidget() ==
   1825                    textInputHandlingWidget.get());
   1826  MOZ_ASSERT(aInputContext.mOrigin == InputContext::ORIGIN_CONTENT);
   1827 
   1828  sActiveChildInputContext = aInputContext;
   1829  MOZ_ASSERT(HasActiveChildSetInputContext());
   1830 
   1831  // If input context is changed in remote process while menu keyboard listener
   1832  // is installed, this process shouldn't set input context now.  When it's
   1833  // uninstalled, input context should be restored from
   1834  // sActiveChildInputContext.
   1835  if (sInstalledMenuKeyboardListener) {
   1836    MOZ_LOG(sISMLog, LogLevel::Info,
   1837            ("  SetInputContextForChildProcess(), waiting to set input context "
   1838             "until menu keyboard listener is uninstalled"));
   1839    return;
   1840  }
   1841 
   1842  SetInputContext(textInputHandlingWidget, aInputContext, aAction);
   1843 }
   1844 
   1845 MOZ_CAN_RUN_SCRIPT static bool IsNextFocusableElementTextControl(
   1846    const Element* aInputContent) {
   1847  RefPtr<nsFocusManager> fm = nsFocusManager::GetFocusManager();
   1848  if (MOZ_UNLIKELY(!fm)) {
   1849    return false;
   1850  }
   1851  nsCOMPtr<nsIContent> nextContent;
   1852  const RefPtr<Element> inputContent = const_cast<Element*>(aInputContent);
   1853  const nsCOMPtr<nsPIDOMWindowOuter> outerWindow =
   1854      aInputContent->OwnerDoc()->GetWindow();
   1855  nsresult rv = fm->DetermineElementToMoveFocus(
   1856      outerWindow, inputContent, nsIFocusManager::MOVEFOCUS_FORWARD, true,
   1857      false, getter_AddRefs(nextContent));
   1858  if (NS_WARN_IF(NS_FAILED(rv)) || !nextContent) {
   1859    return false;
   1860  }
   1861  nextContent = nextContent->FindFirstNonChromeOnlyAccessContent();
   1862  const auto* nextControl = nsIFormControl::FromNode(nextContent);
   1863  if (!nextControl || !nextControl->IsTextControl(false)) {
   1864    return false;
   1865  }
   1866 
   1867  // XXX We don't consider next element is date/time control yet.
   1868  nsGenericHTMLElement* nextElement =
   1869      nsGenericHTMLElement::FromNodeOrNull(nextContent);
   1870  if (!nextElement) {
   1871    return false;
   1872  }
   1873 
   1874  // FIXME: Should probably use nsIFrame::IsFocusable if possible, to account
   1875  // for things like visibility: hidden or so.
   1876  if (!nextElement->IsFocusableWithoutStyle()) {
   1877    return false;
   1878  }
   1879 
   1880  // Check readonly attribute.
   1881  if (nextElement->IsHTMLElement(nsGkAtoms::textarea)) {
   1882    auto* textAreaElement = HTMLTextAreaElement::FromNode(nextElement);
   1883    return !textAreaElement->ReadOnly();
   1884  }
   1885 
   1886  // If neither textarea nor input, what element type?
   1887  MOZ_DIAGNOSTIC_ASSERT(nextElement->IsHTMLElement(nsGkAtoms::input));
   1888 
   1889  auto* inputElement = HTMLInputElement::FromNode(nextElement);
   1890  return !inputElement->ReadOnly();
   1891 }
   1892 
   1893 static void GetInputType(const IMEState& aState, const nsIContent& aContent,
   1894                         nsAString& aInputType) {
   1895  // NOTE: If you change here, you may need to update
   1896  //       widget::InputContext::GatNativeKeyBindings too.
   1897  if (aContent.IsHTMLElement(nsGkAtoms::input)) {
   1898    const HTMLInputElement* inputElement =
   1899        HTMLInputElement::FromNode(&aContent);
   1900    if (inputElement->HasBeenTypePassword() && aState.IsEditable()) {
   1901      aInputType.AssignLiteral("password");
   1902    } else {
   1903      inputElement->GetType(aInputType);
   1904    }
   1905  } else if (aContent.IsHTMLElement(nsGkAtoms::textarea)) {
   1906    aInputType.Assign(nsGkAtoms::textarea->GetUTF16String());
   1907  }
   1908 }
   1909 
   1910 MOZ_CAN_RUN_SCRIPT static void GetActionHint(const IMEState& aState,
   1911                                             const nsIContent& aContent,
   1912                                             nsAString& aActionHint) {
   1913  MOZ_ASSERT(aContent.IsHTMLElement());
   1914 
   1915  if (aState.IsEditable()) {
   1916    nsGenericHTMLElement::FromNode(&aContent)->GetEnterKeyHint(aActionHint);
   1917 
   1918    // If enterkeyhint is set, we don't infer action hint.
   1919    if (!aActionHint.IsEmpty()) {
   1920      return;
   1921    }
   1922  }
   1923 
   1924  if (!aContent.IsHTMLElement(nsGkAtoms::input)) {
   1925    return;
   1926  }
   1927 
   1928  // Get the input content corresponding to the focused node,
   1929  // which may be an anonymous child of the input content.
   1930  MOZ_ASSERT(&aContent == aContent.FindFirstNonChromeOnlyAccessContent());
   1931  const HTMLInputElement* inputElement = HTMLInputElement::FromNode(aContent);
   1932  if (!inputElement) {
   1933    return;
   1934  }
   1935 
   1936  // If we don't have an action hint and
   1937  // return won't submit the form, use "maybenext".
   1938  bool willSubmit = false;
   1939  bool isLastElement = false;
   1940  HTMLFormElement* formElement = inputElement->GetForm();
   1941  // is this a form and does it have a default submit element?
   1942  if (formElement) {
   1943    if (formElement->IsLastActiveElement(inputElement)) {
   1944      isLastElement = true;
   1945    }
   1946 
   1947    if (formElement->GetDefaultSubmitElement()) {
   1948      willSubmit = true;
   1949      // is this an html form...
   1950    } else {
   1951      // ... and does it only have a single text input element ?
   1952      if (!formElement->ImplicitSubmissionIsDisabled() ||
   1953          // ... or is this the last non-disabled element?
   1954          isLastElement) {
   1955        willSubmit = true;
   1956      }
   1957    }
   1958  }
   1959 
   1960  if (!isLastElement && formElement) {
   1961    // If next tabbable content in form is text control, hint should be "next"
   1962    // even there is submit in form.
   1963    // MOZ_KnownLive(inputElement) because it's an alias of aContent.
   1964    if (IsNextFocusableElementTextControl(MOZ_KnownLive(inputElement))) {
   1965      // This is focusable text control
   1966      // XXX What good hint for read only field?
   1967      aActionHint.AssignLiteral("maybenext");
   1968      return;
   1969    }
   1970  }
   1971 
   1972  if (!willSubmit) {
   1973    aActionHint.Truncate();
   1974    return;
   1975  }
   1976 
   1977  if (inputElement->ControlType() == FormControlType::InputSearch) {
   1978    aActionHint.AssignLiteral("search");
   1979    return;
   1980  }
   1981 
   1982  aActionHint.AssignLiteral("go");
   1983 }
   1984 
   1985 static void GetInputMode(const IMEState& aState, const nsIContent& aContent,
   1986                         nsAString& aInputMode) {
   1987  if (aState.IsEditable()) {
   1988    aContent.AsElement()->GetAttr(nsGkAtoms::inputmode, aInputMode);
   1989    if (aContent.IsHTMLElement(nsGkAtoms::input) &&
   1990        aInputMode.EqualsLiteral("mozAwesomebar")) {
   1991      if (!nsContentUtils::IsChromeDoc(aContent.OwnerDoc())) {
   1992        // mozAwesomebar should be allowed only in chrome
   1993        aInputMode.Truncate();
   1994      }
   1995    } else {
   1996      ToLowerCase(aInputMode);
   1997    }
   1998  }
   1999 }
   2000 
   2001 static void GetAutocapitalize(const IMEState& aState, const Element& aElement,
   2002                              const InputContext& aInputContext,
   2003                              nsAString& aAutocapitalize) {
   2004  if (aElement.IsHTMLElement() && aState.IsEditable() &&
   2005      aInputContext.IsAutocapitalizeSupported()) {
   2006    nsGenericHTMLElement::FromNode(&aElement)->GetAutocapitalize(
   2007        aAutocapitalize);
   2008  }
   2009 }
   2010 
   2011 static bool GetAutocorrect(const IMEState& aState, const Element& aElement,
   2012                           const InputContext& aInputContext) {
   2013  if (!StaticPrefs::dom_forms_autocorrect()) {
   2014 #ifdef ANDROID
   2015    // Autocorrect was on-by-default on Android by bug 806349, despite
   2016    // autocorrect preference.
   2017    return true;
   2018 #else
   2019    return false;
   2020 #endif
   2021  }
   2022 
   2023  if (aElement.IsHTMLElement() && aState.IsEditable()) {
   2024    if (nsContentUtils::IsChromeDoc(aElement.OwnerDoc()) &&
   2025        !aElement.HasAttr(nsGkAtoms::autocorrect)) {
   2026      // Since Chrome UI may not want to enable autocorrect by default such as
   2027      // bug 1881783.
   2028      return false;
   2029    }
   2030 
   2031    return nsGenericHTMLElement::FromNode(&aElement)->Autocorrect();
   2032  }
   2033  return true;
   2034 }
   2035 
   2036 // static
   2037 already_AddRefed<nsIURI> IMEStateManager::GetExposableURL(
   2038    const nsPresContext* aPresContext) {
   2039  if (!aPresContext) {
   2040    return nullptr;
   2041  }
   2042  nsIURI* uri = aPresContext->Document()->GetDocumentURI();
   2043  if (!uri) {
   2044    return nullptr;
   2045  }
   2046  // We don't need to and should not expose special URLs such as:
   2047  // about: Any apps like IME should work normally and constantly in any
   2048  //        default pages such as about:blank, about:home, etc in either
   2049  //        the main process or a content process.
   2050  // blob: This may contain big data.  If we copy it to the main process,
   2051  //       it may make the heap dirty which makes the process slower.
   2052  // chrome: Same as about, any apps should work normally and constantly in
   2053  //         any chrome documents.
   2054  // data: Any native apps in the environment shouldn't change the behavior
   2055  //       with the data URL's content and it may contain too big data.
   2056  // file: The file path may contain private things and we shouldn't let
   2057  //       other apps like IME know which one is touched by the user because
   2058  //       malicious text services may like files which are explicitly used
   2059  //       by the user better.
   2060  if (!net::SchemeIsHttpOrHttps(uri)) {
   2061    return nullptr;
   2062  }
   2063  // Note that we don't need to expose UserPass, Query and Reference to
   2064  // IME since they may contain sensitive data, but non-malicious text
   2065  // services must not require these data.
   2066  nsCOMPtr<nsIURI> exposableURL;
   2067  if (NS_FAILED(NS_MutateURI(uri)
   2068                    .SetQuery(""_ns)
   2069                    .SetRef(""_ns)
   2070                    .SetUserPass(""_ns)
   2071                    .Finalize(exposableURL))) {
   2072    return nullptr;
   2073  }
   2074 
   2075  return exposableURL.forget();
   2076 }
   2077 
   2078 // static
   2079 void IMEStateManager::SetIMEState(const IMEState& aState,
   2080                                  const nsPresContext* aPresContext,
   2081                                  Element* aElement, nsIWidget& aWidget,
   2082                                  InputContextAction aAction,
   2083                                  InputContext::Origin aOrigin) {
   2084  MOZ_LOG(sISMLog, LogLevel::Info,
   2085          ("SetIMEState(aState=%s, nsPresContext=0x%p, aElement=0x%p "
   2086           "(BrowserParent=0x%p), aWidget=0x%p, aAction={ mCause=%s, "
   2087           "mFocusChange=%s }, aOrigin=%s)",
   2088           ToString(aState).c_str(), aPresContext, aElement,
   2089           BrowserParent::GetFrom(aElement), &aWidget,
   2090           ToString(aAction.mCause).c_str(),
   2091           ToString(aAction.mFocusChange).c_str(), ToChar(aOrigin)));
   2092 
   2093  InputContext context;
   2094  context.mIMEState = aState;
   2095  context.mURI = IMEStateManager::GetExposableURL(aPresContext);
   2096  context.mOrigin = aOrigin;
   2097 
   2098  context.mHasHandledUserInput =
   2099      aPresContext && aPresContext->PresShell()->HasHandledUserInput();
   2100 
   2101  context.mInPrivateBrowsing = aPresContext && aPresContext->Document() &&
   2102                               aPresContext->Document()->IsInPrivateBrowsing();
   2103 
   2104  const RefPtr<Element> focusedElement =
   2105      aElement ? Element::FromNodeOrNull(
   2106                     aElement->FindFirstNonChromeOnlyAccessContent())
   2107               : nullptr;
   2108 
   2109  if (focusedElement && focusedElement->IsHTMLElement()) {
   2110    GetInputType(aState, *focusedElement, context.mHTMLInputType);
   2111    GetActionHint(aState, *focusedElement, context.mActionHint);
   2112    GetInputMode(aState, *focusedElement, context.mHTMLInputMode);
   2113    GetAutocapitalize(aState, *focusedElement, context,
   2114                      context.mAutocapitalize);
   2115    context.mAutocorrect = GetAutocorrect(aState, *focusedElement, context);
   2116  }
   2117 
   2118  if (aAction.mCause == InputContextAction::CAUSE_UNKNOWN &&
   2119      nsContentUtils::LegacyIsCallerChromeOrNativeCode()) {
   2120    aAction.mCause = InputContextAction::CAUSE_UNKNOWN_CHROME;
   2121  }
   2122 
   2123  if ((aAction.mCause == InputContextAction::CAUSE_UNKNOWN ||
   2124       aAction.mCause == InputContextAction::CAUSE_UNKNOWN_CHROME) &&
   2125      UserActivation::IsHandlingUserInput()) {
   2126    aAction.mCause =
   2127        UserActivation::IsHandlingKeyboardInput()
   2128            ? InputContextAction::CAUSE_UNKNOWN_DURING_KEYBOARD_INPUT
   2129            : InputContextAction::CAUSE_UNKNOWN_DURING_NON_KEYBOARD_INPUT;
   2130  }
   2131 
   2132  SetInputContext(aWidget, context, aAction);
   2133 }
   2134 
   2135 // static
   2136 void IMEStateManager::SetInputContext(nsIWidget& aWidget,
   2137                                      const InputContext& aInputContext,
   2138                                      const InputContextAction& aAction) {
   2139  MOZ_LOG(
   2140      sISMLog, LogLevel::Info,
   2141      ("SetInputContext(aWidget=0x%p, aInputContext=%s, "
   2142       "aAction={ mCause=%s, mAction=%s }), BrowserParent::GetFocused()=0x%p",
   2143       &aWidget, ToString(aInputContext).c_str(),
   2144       ToString(aAction.mCause).c_str(), ToString(aAction.mFocusChange).c_str(),
   2145       BrowserParent::GetFocused()));
   2146 
   2147  OwningNonNull<nsIWidget> widget = aWidget;
   2148  widget->SetInputContext(aInputContext, aAction);
   2149  sActiveInputContextWidget = widget;
   2150 }
   2151 
   2152 // static
   2153 void IMEStateManager::EnsureTextCompositionArray() {
   2154  if (sTextCompositions) {
   2155    return;
   2156  }
   2157  sTextCompositions = new TextCompositionArray();
   2158 }
   2159 
   2160 // static
   2161 void IMEStateManager::DispatchCompositionEvent(
   2162    nsINode* aEventTargetNode, nsPresContext* aPresContext,
   2163    BrowserParent* aBrowserParent, WidgetCompositionEvent* aCompositionEvent,
   2164    nsEventStatus* aStatus, EventDispatchingCallback* aCallBack,
   2165    bool aIsSynthesized) {
   2166  MOZ_LOG(
   2167      sISMLog, LogLevel::Info,
   2168      ("DispatchCompositionEvent(aNode=0x%p, "
   2169       "aPresContext=0x%p, aCompositionEvent={ mMessage=%s, "
   2170       "mNativeIMEContext={ mRawNativeIMEContext=0x%" PRIXPTR ", "
   2171       "mOriginProcessID=0x%" PRIX64 " }, mWidget(0x%p)={ "
   2172       "GetNativeIMEContext()={ mRawNativeIMEContext=0x%" PRIXPTR ", "
   2173       "mOriginProcessID=0x%" PRIX64 " }, Destroyed()=%s }, "
   2174       "mFlags={ mIsTrusted=%s, mPropagationStopped=%s } }, "
   2175       "aIsSynthesized=%s), browserParent=%p",
   2176       aEventTargetNode, aPresContext, ToChar(aCompositionEvent->mMessage),
   2177       aCompositionEvent->mNativeIMEContext.mRawNativeIMEContext,
   2178       aCompositionEvent->mNativeIMEContext.mOriginProcessID,
   2179       aCompositionEvent->mWidget.get(),
   2180       aCompositionEvent->mWidget->GetNativeIMEContext().mRawNativeIMEContext,
   2181       aCompositionEvent->mWidget->GetNativeIMEContext().mOriginProcessID,
   2182       TrueOrFalse(aCompositionEvent->mWidget->Destroyed()),
   2183       TrueOrFalse(aCompositionEvent->mFlags.mIsTrusted),
   2184       TrueOrFalse(aCompositionEvent->mFlags.mPropagationStopped),
   2185       TrueOrFalse(aIsSynthesized), aBrowserParent));
   2186 
   2187  if (NS_WARN_IF(!aCompositionEvent->IsTrusted()) ||
   2188      NS_WARN_IF(aCompositionEvent->PropagationStopped())) {
   2189    return;
   2190  }
   2191 
   2192  MOZ_ASSERT(aCompositionEvent->mMessage != eCompositionUpdate,
   2193             "compositionupdate event shouldn't be dispatched manually");
   2194 
   2195  EnsureTextCompositionArray();
   2196 
   2197  RefPtr<TextComposition> composition =
   2198      sTextCompositions->GetCompositionFor(aCompositionEvent);
   2199  if (!composition) {
   2200    // If synthesized event comes after delayed native composition events
   2201    // for request of commit or cancel, we should ignore it.
   2202    if (NS_WARN_IF(aIsSynthesized)) {
   2203      return;
   2204    }
   2205    MOZ_LOG(sISMLog, LogLevel::Debug,
   2206            ("  DispatchCompositionEvent(), "
   2207             "adding new TextComposition to the array"));
   2208    MOZ_ASSERT(aCompositionEvent->mMessage == eCompositionStart);
   2209    composition = new TextComposition(aPresContext, aEventTargetNode,
   2210                                      aBrowserParent, aCompositionEvent);
   2211    sTextCompositions->AppendElement(composition);
   2212  }
   2213 #ifdef DEBUG
   2214  else {
   2215    MOZ_ASSERT(aCompositionEvent->mMessage != eCompositionStart);
   2216  }
   2217 #endif  // #ifdef DEBUG
   2218 
   2219  // Dispatch the event on composing target.
   2220  composition->DispatchCompositionEvent(aCompositionEvent, aStatus, aCallBack,
   2221                                        aIsSynthesized);
   2222 
   2223  // WARNING: the |composition| might have been destroyed already.
   2224 
   2225  // Remove the ended composition from the array.
   2226  // NOTE: When TextComposition is synthesizing compositionend event for
   2227  //       emulating a commit, the instance shouldn't be removed from the array
   2228  //       because IME may perform it later.  Then, we need to ignore the
   2229  //       following commit events in TextComposition::DispatchEvent().
   2230  //       However, if commit or cancel for a request is performed synchronously
   2231  //       during not safe to dispatch events, PresShell must have discarded
   2232  //       compositionend event.  Then, the synthesized compositionend event is
   2233  //       the last event for the composition.  In this case, we need to
   2234  //       destroy the TextComposition with synthesized compositionend event.
   2235  if ((!aIsSynthesized ||
   2236       composition->WasNativeCompositionEndEventDiscarded()) &&
   2237      aCompositionEvent->CausesDOMCompositionEndEvent()) {
   2238    TextCompositionArray::index_type i =
   2239        sTextCompositions->IndexOf(aCompositionEvent->mWidget);
   2240    if (i != TextCompositionArray::NoIndex) {
   2241      MOZ_LOG(
   2242          sISMLog, LogLevel::Debug,
   2243          ("  DispatchCompositionEvent(), "
   2244           "removing TextComposition from the array since NS_COMPOSTION_END "
   2245           "was dispatched"));
   2246      sTextCompositions->ElementAt(i)->Destroy();
   2247      sTextCompositions->RemoveElementAt(i);
   2248    }
   2249  }
   2250 }
   2251 
   2252 // static
   2253 IMEContentObserver* IMEStateManager::GetActiveContentObserver() {
   2254  return sActiveIMEContentObserver;
   2255 }
   2256 
   2257 // static
   2258 nsIContent* IMEStateManager::GetRootContent(nsPresContext* aPresContext) {
   2259  Document* doc = aPresContext->Document();
   2260  if (NS_WARN_IF(!doc)) {
   2261    return nullptr;
   2262  }
   2263  return doc->GetRootElement();
   2264 }
   2265 
   2266 // static
   2267 void IMEStateManager::HandleSelectionEvent(
   2268    nsPresContext* aPresContext, nsIContent* aEventTargetContent,
   2269    WidgetSelectionEvent* aSelectionEvent) {
   2270  RefPtr<BrowserParent> browserParent = GetActiveBrowserParent();
   2271  if (!browserParent) {
   2272    browserParent = BrowserParent::GetFrom(aEventTargetContent
   2273                                               ? aEventTargetContent
   2274                                               : GetRootContent(aPresContext));
   2275  }
   2276 
   2277  MOZ_LOG(
   2278      sISMLog, LogLevel::Info,
   2279      ("HandleSelectionEvent(aPresContext=0x%p, "
   2280       "aEventTargetContent=0x%p, aSelectionEvent={ mMessage=%s, "
   2281       "mFlags={ mIsTrusted=%s } }), browserParent=%p",
   2282       aPresContext, aEventTargetContent, ToChar(aSelectionEvent->mMessage),
   2283       TrueOrFalse(aSelectionEvent->mFlags.mIsTrusted), browserParent.get()));
   2284 
   2285  if (!aSelectionEvent->IsTrusted()) {
   2286    return;
   2287  }
   2288 
   2289  RefPtr<TextComposition> composition =
   2290      sTextCompositions
   2291          ? sTextCompositions->GetCompositionFor(aSelectionEvent->mWidget)
   2292          : nullptr;
   2293  if (composition) {
   2294    // When there is a composition, TextComposition should guarantee that the
   2295    // selection event will be handled in same target as composition events.
   2296    composition->HandleSelectionEvent(aSelectionEvent);
   2297  } else {
   2298    // When there is no composition, the selection event should be handled
   2299    // in the aPresContext or browserParent.
   2300    TextComposition::HandleSelectionEvent(aPresContext, browserParent,
   2301                                          aSelectionEvent);
   2302  }
   2303 }
   2304 
   2305 // static
   2306 void IMEStateManager::OnCompositionEventDiscarded(
   2307    WidgetCompositionEvent* aCompositionEvent) {
   2308  // Note that this method is never called for synthesized events for emulating
   2309  // commit or cancel composition.
   2310 
   2311  MOZ_LOG(
   2312      sISMLog, LogLevel::Info,
   2313      ("OnCompositionEventDiscarded(aCompositionEvent={ "
   2314       "mMessage=%s, mNativeIMEContext={ mRawNativeIMEContext=0x%" PRIXPTR ", "
   2315       "mOriginProcessID=0x%" PRIX64 " }, mWidget(0x%p)={ "
   2316       "GetNativeIMEContext()={ mRawNativeIMEContext=0x%" PRIXPTR ", "
   2317       "mOriginProcessID=0x%" PRIX64 " }, Destroyed()=%s }, "
   2318       "mFlags={ mIsTrusted=%s } })",
   2319       ToChar(aCompositionEvent->mMessage),
   2320       aCompositionEvent->mNativeIMEContext.mRawNativeIMEContext,
   2321       aCompositionEvent->mNativeIMEContext.mOriginProcessID,
   2322       aCompositionEvent->mWidget.get(),
   2323       aCompositionEvent->mWidget->GetNativeIMEContext().mRawNativeIMEContext,
   2324       aCompositionEvent->mWidget->GetNativeIMEContext().mOriginProcessID,
   2325       TrueOrFalse(aCompositionEvent->mWidget->Destroyed()),
   2326       TrueOrFalse(aCompositionEvent->mFlags.mIsTrusted)));
   2327 
   2328  if (!aCompositionEvent->IsTrusted()) {
   2329    return;
   2330  }
   2331 
   2332  // Ignore compositionstart for now because sTextCompositions may not have
   2333  // been created yet.
   2334  if (aCompositionEvent->mMessage == eCompositionStart) {
   2335    return;
   2336  }
   2337 
   2338  RefPtr<TextComposition> composition =
   2339      sTextCompositions->GetCompositionFor(aCompositionEvent->mWidget);
   2340  if (!composition) {
   2341    // If the PresShell has been being destroyed during composition,
   2342    // a TextComposition instance for the composition was already removed from
   2343    // the array and destroyed in OnDestroyPresContext().  Therefore, we may
   2344    // fail to retrieve a TextComposition instance here.
   2345    MOZ_LOG(sISMLog, LogLevel::Info,
   2346            ("  OnCompositionEventDiscarded(), "
   2347             "TextComposition instance for the widget has already gone"));
   2348    return;
   2349  }
   2350  composition->OnCompositionEventDiscarded(aCompositionEvent);
   2351 }
   2352 
   2353 // static
   2354 nsresult IMEStateManager::NotifyIME(IMEMessage aMessage, nsIWidget* aWidget,
   2355                                    BrowserParent* aBrowserParent) {
   2356  return IMEStateManager::NotifyIME(IMENotification(aMessage), aWidget,
   2357                                    aBrowserParent);
   2358 }
   2359 
   2360 // static
   2361 nsresult IMEStateManager::NotifyIME(const IMENotification& aNotification,
   2362                                    nsIWidget* aWidget,
   2363                                    BrowserParent* aBrowserParent) {
   2364  MOZ_LOG(sISMLog, LogLevel::Info,
   2365          ("NotifyIME(aNotification={ mMessage=%s }, "
   2366           "aWidget=0x%p, aBrowserParent=0x%p), sFocusedIMEWidget=0x%p, "
   2367           "BrowserParent::GetFocused()=0x%p, sFocusedIMEBrowserParent=0x%p, "
   2368           "aBrowserParent == BrowserParent::GetFocused()=%s, "
   2369           "aBrowserParent == sFocusedIMEBrowserParent=%s, "
   2370           "CanSendNotificationToWidget()=%s",
   2371           ToChar(aNotification.mMessage), aWidget, aBrowserParent,
   2372           sFocusedIMEWidget, BrowserParent::GetFocused(),
   2373           sFocusedIMEBrowserParent.get(),
   2374           TrueOrFalse(aBrowserParent == BrowserParent::GetFocused()),
   2375           TrueOrFalse(aBrowserParent == sFocusedIMEBrowserParent),
   2376           TrueOrFalse(CanSendNotificationToWidget())));
   2377 
   2378  if (NS_WARN_IF(!aWidget)) {
   2379    MOZ_LOG(sISMLog, LogLevel::Error,
   2380            ("  NotifyIME(), FAILED due to no widget"));
   2381    return NS_ERROR_INVALID_ARG;
   2382  }
   2383 
   2384  switch (aNotification.mMessage) {
   2385    case NOTIFY_IME_OF_FOCUS: {
   2386      MOZ_ASSERT(CanSendNotificationToWidget());
   2387 
   2388      // If focus notification comes from a remote browser which already lost
   2389      // focus, we shouldn't accept the focus notification.  Then, following
   2390      // notifications from the process will be ignored.
   2391      if (aBrowserParent != BrowserParent::GetFocused()) {
   2392        MOZ_LOG(sISMLog, LogLevel::Warning,
   2393                ("  NotifyIME(), WARNING, the received focus notification is "
   2394                 "ignored, because its associated BrowserParent did not match"
   2395                 "the focused BrowserParent."));
   2396        return NS_OK;
   2397      }
   2398      // If IME focus is already set, first blur the currently-focused
   2399      // IME widget
   2400      if (sFocusedIMEWidget) {
   2401        // XXX Why don't we first request the previously-focused IME
   2402        // widget to commit the composition?
   2403        MOZ_ASSERT(
   2404            sFocusedIMEBrowserParent || aBrowserParent,
   2405            "This case shouldn't be caused by focus move in this process");
   2406        MOZ_LOG(sISMLog, LogLevel::Warning,
   2407                ("  NotifyIME(), WARNING, received focus notification with ")
   2408                 "non-null sFocusedIMEWidget. How come "
   2409                 "OnFocusMovedBetweenBrowsers did not blur it already?");
   2410        nsCOMPtr<nsIWidget> focusedIMEWidget(sFocusedIMEWidget);
   2411        sFocusedIMEWidget = nullptr;
   2412        sFocusedIMEBrowserParent = nullptr;
   2413        focusedIMEWidget->NotifyIME(IMENotification(NOTIFY_IME_OF_BLUR));
   2414      }
   2415 #ifdef DEBUG
   2416      if (aBrowserParent) {
   2417        nsCOMPtr<nsIWidget> browserParentWidget =
   2418            aBrowserParent->GetTextInputHandlingWidget();
   2419        MOZ_ASSERT(browserParentWidget == aWidget);
   2420      } else {
   2421        MOZ_ASSERT(sFocusedPresContext);
   2422        MOZ_ASSERT_IF(
   2423            sFocusedPresContext->GetTextInputHandlingWidget(),
   2424            sFocusedPresContext->GetTextInputHandlingWidget() == aWidget);
   2425      }
   2426 #endif
   2427      sFocusedIMEBrowserParent = aBrowserParent;
   2428      sFocusedIMEWidget = aWidget;
   2429      nsCOMPtr<nsIWidget> widget(aWidget);
   2430      MOZ_LOG(
   2431          sISMLog, LogLevel::Info,
   2432          ("  NotifyIME(), about to call widget->NotifyIME() for IME focus"));
   2433      return widget->NotifyIME(aNotification);
   2434    }
   2435    case NOTIFY_IME_OF_BLUR: {
   2436      if (aBrowserParent != sFocusedIMEBrowserParent) {
   2437        MOZ_LOG(sISMLog, LogLevel::Warning,
   2438                ("  NotifyIME(), WARNING, the received blur notification is "
   2439                 "ignored "
   2440                 "because it's not from current focused IME browser"));
   2441        return NS_OK;
   2442      }
   2443      if (!sFocusedIMEWidget) {
   2444        MOZ_LOG(
   2445            sISMLog, LogLevel::Error,
   2446            ("  NotifyIME(), WARNING, received blur notification but there is "
   2447             "no focused IME widget"));
   2448        return NS_OK;
   2449      }
   2450      if (NS_WARN_IF(sFocusedIMEWidget != aWidget)) {
   2451        MOZ_LOG(sISMLog, LogLevel::Warning,
   2452                ("  NotifyIME(), WARNING, the received blur notification is "
   2453                 "ignored "
   2454                 "because it's not for current focused IME widget"));
   2455        return NS_OK;
   2456      }
   2457      nsCOMPtr<nsIWidget> focusedIMEWidget(sFocusedIMEWidget);
   2458      sFocusedIMEWidget = nullptr;
   2459      sFocusedIMEBrowserParent = nullptr;
   2460      return CanSendNotificationToWidget()
   2461                 ? focusedIMEWidget->NotifyIME(
   2462                       IMENotification(NOTIFY_IME_OF_BLUR))
   2463                 : NS_OK;
   2464    }
   2465    case NOTIFY_IME_OF_SELECTION_CHANGE:
   2466    case NOTIFY_IME_OF_TEXT_CHANGE:
   2467    case NOTIFY_IME_OF_POSITION_CHANGE:
   2468    case NOTIFY_IME_OF_MOUSE_BUTTON_EVENT:
   2469    case NOTIFY_IME_OF_COMPOSITION_EVENT_HANDLED: {
   2470      if (aBrowserParent != sFocusedIMEBrowserParent) {
   2471        MOZ_LOG(
   2472            sISMLog, LogLevel::Warning,
   2473            ("  NotifyIME(), WARNING, the received content change notification "
   2474             "is ignored because it's not from current focused IME browser"));
   2475        return NS_OK;
   2476      }
   2477      if (!sFocusedIMEWidget) {
   2478        MOZ_LOG(
   2479            sISMLog, LogLevel::Warning,
   2480            ("  NotifyIME(), WARNING, the received content change notification "
   2481             "is ignored because there is no focused IME widget"));
   2482        return NS_OK;
   2483      }
   2484      if (NS_WARN_IF(sFocusedIMEWidget != aWidget)) {
   2485        MOZ_LOG(
   2486            sISMLog, LogLevel::Warning,
   2487            ("  NotifyIME(), WARNING, the received content change notification "
   2488             "is ignored because it's not for current focused IME widget"));
   2489        return NS_OK;
   2490      }
   2491      if (!CanSendNotificationToWidget()) {
   2492        return NS_OK;
   2493      }
   2494      nsCOMPtr<nsIWidget> widget(aWidget);
   2495      return widget->NotifyIME(aNotification);
   2496    }
   2497    default:
   2498      // Other notifications should be sent only when there is composition.
   2499      // So, we need to handle the others below.
   2500      break;
   2501  }
   2502 
   2503  if (!sTextCompositions) {
   2504    MOZ_LOG(sISMLog, LogLevel::Info,
   2505            ("  NotifyIME(), the request to IME is ignored because "
   2506             "there have been no compositions yet"));
   2507    return NS_OK;
   2508  }
   2509 
   2510  RefPtr<TextComposition> composition =
   2511      sTextCompositions->GetCompositionFor(aWidget);
   2512  if (!composition) {
   2513    MOZ_LOG(sISMLog, LogLevel::Info,
   2514            ("  NotifyIME(), the request to IME is ignored because "
   2515             "there is no active composition"));
   2516    return NS_OK;
   2517  }
   2518 
   2519  if (aBrowserParent != composition->GetBrowserParent()) {
   2520    MOZ_LOG(
   2521        sISMLog, LogLevel::Warning,
   2522        ("  NotifyIME(), WARNING, the request to IME is ignored because "
   2523         "it does not come from the remote browser which has the composition "
   2524         "on aWidget"));
   2525    return NS_OK;
   2526  }
   2527 
   2528  switch (aNotification.mMessage) {
   2529    case REQUEST_TO_COMMIT_COMPOSITION:
   2530      return composition->RequestToCommit(aWidget, false);
   2531    case REQUEST_TO_CANCEL_COMPOSITION:
   2532      return composition->RequestToCommit(aWidget, true);
   2533    default:
   2534      MOZ_CRASH("Unsupported notification");
   2535  }
   2536  MOZ_CRASH(
   2537      "Failed to handle the notification for non-synthesized composition");
   2538  return NS_ERROR_FAILURE;
   2539 }
   2540 
   2541 // static
   2542 nsresult IMEStateManager::NotifyIME(IMEMessage aMessage,
   2543                                    nsPresContext* aPresContext,
   2544                                    BrowserParent* aBrowserParent) {
   2545  MOZ_LOG(sISMLog, LogLevel::Info,
   2546          ("NotifyIME(aMessage=%s, aPresContext=0x%p, aBrowserParent=0x%p)",
   2547           ToChar(aMessage), aPresContext, aBrowserParent));
   2548  // This assertion is just for clarify which message may be set, so feel free
   2549  // to add other messages if you want.
   2550  MOZ_ASSERT(aMessage == REQUEST_TO_CANCEL_COMPOSITION ||
   2551             aMessage == REQUEST_TO_COMMIT_COMPOSITION ||
   2552             aMessage == NOTIFY_IME_OF_COMPOSITION_EVENT_HANDLED);
   2553  // However, these messages require additional information.  Therefore, this
   2554  // overload shouldn't be used for them.
   2555  MOZ_ASSERT(aMessage != NOTIFY_IME_OF_FOCUS &&
   2556             aMessage != NOTIFY_IME_OF_BLUR &&
   2557             aMessage != NOTIFY_IME_OF_TEXT_CHANGE &&
   2558             aMessage != NOTIFY_IME_OF_SELECTION_CHANGE &&
   2559             aMessage != NOTIFY_IME_OF_MOUSE_BUTTON_EVENT);
   2560 
   2561  if (NS_WARN_IF(!CanHandleWith(aPresContext))) {
   2562    return NS_ERROR_INVALID_ARG;
   2563  }
   2564 
   2565  nsCOMPtr<nsIWidget> widget =
   2566      aPresContext == sFocusedPresContext && sTextInputHandlingWidget
   2567          ? sTextInputHandlingWidget
   2568          : aPresContext->GetTextInputHandlingWidget();
   2569  if (NS_WARN_IF(!widget)) {
   2570    MOZ_LOG(sISMLog, LogLevel::Error,
   2571            ("  NotifyIME(), FAILED due to no widget for the nsPresContext"));
   2572    return NS_ERROR_NOT_AVAILABLE;
   2573  }
   2574  return NotifyIME(aMessage, widget, aBrowserParent);
   2575 }
   2576 
   2577 // static
   2578 bool IMEStateManager::IsIMEObserverNeeded(const IMEState& aState) {
   2579  return aState.IsEditable();
   2580 }
   2581 
   2582 // static
   2583 void IMEStateManager::DestroyIMEContentObserver() {
   2584  if (!sActiveIMEContentObserver) {
   2585    MOZ_LOG(sISMLog, LogLevel::Verbose,
   2586            ("DestroyIMEContentObserver() does nothing"));
   2587    return;
   2588  }
   2589 
   2590  MOZ_LOG(sISMLog, LogLevel::Info,
   2591          ("DestroyIMEContentObserver(), destroying "
   2592           "the active IMEContentObserver..."));
   2593  RefPtr<IMEContentObserver> tsm = sActiveIMEContentObserver.get();
   2594  sActiveIMEContentObserver = nullptr;
   2595  tsm->Destroy();
   2596 }
   2597 
   2598 // static
   2599 void IMEStateManager::CreateIMEContentObserver(EditorBase& aEditorBase,
   2600                                               Element* aFocusedElement) {
   2601  MOZ_ASSERT(!sActiveIMEContentObserver);
   2602  MOZ_ASSERT(sTextInputHandlingWidget);
   2603  MOZ_ASSERT(sFocusedPresContext);
   2604  MOZ_ASSERT(IsIMEObserverNeeded(
   2605      sTextInputHandlingWidget->GetInputContext().mIMEState));
   2606 
   2607  MOZ_LOG(sISMLog, LogLevel::Info,
   2608          ("CreateIMEContentObserver(aEditorBase=0x%p, aFocusedElement=0x%p), "
   2609           "sFocusedPresContext=0x%p, sFocusedElement=0x%p, "
   2610           "sTextInputHandlingWidget=0x%p (available: %s), "
   2611           "sActiveIMEContentObserver=0x%p, "
   2612           "sActiveIMEContentObserver->IsObserving(sFocusedPresContext, "
   2613           "sFocusedElement)=%s",
   2614           &aEditorBase, aFocusedElement, sFocusedPresContext.get(),
   2615           sFocusedElement.get(), sTextInputHandlingWidget,
   2616           TrueOrFalse(sTextInputHandlingWidget &&
   2617                       !sTextInputHandlingWidget->Destroyed()),
   2618           sActiveIMEContentObserver.get(),
   2619           TrueOrFalse(sActiveIMEContentObserver && sFocusedPresContext &&
   2620                       sActiveIMEContentObserver->IsObserving(
   2621                           *sFocusedPresContext, sFocusedElement))));
   2622 
   2623  if (NS_WARN_IF(sTextInputHandlingWidget->Destroyed())) {
   2624    MOZ_LOG(sISMLog, LogLevel::Error,
   2625            ("  CreateIMEContentObserver(), FAILED due to "
   2626             "the widget for the nsPresContext has gone"));
   2627    return;
   2628  }
   2629 
   2630  const OwningNonNull<nsIWidget> textInputHandlingWidget =
   2631      *sTextInputHandlingWidget;
   2632  MOZ_ASSERT_IF(sFocusedPresContext->GetTextInputHandlingWidget(),
   2633                sFocusedPresContext->GetTextInputHandlingWidget() ==
   2634                    textInputHandlingWidget.get());
   2635 
   2636  MOZ_LOG(sISMLog, LogLevel::Debug,
   2637          ("  CreateIMEContentObserver() is creating an "
   2638           "IMEContentObserver instance..."));
   2639  sActiveIMEContentObserver = new IMEContentObserver();
   2640 
   2641  // IMEContentObserver::Init() might create another IMEContentObserver
   2642  // instance.  So, sActiveIMEContentObserver would be replaced with new one.
   2643  // We should hold the current instance here.
   2644  OwningNonNull<IMEContentObserver> activeIMEContentObserver =
   2645      *sActiveIMEContentObserver;
   2646  OwningNonNull<nsPresContext> focusedPresContext = *sFocusedPresContext;
   2647  RefPtr<Element> focusedElement = aFocusedElement;
   2648  activeIMEContentObserver->Init(textInputHandlingWidget, focusedPresContext,
   2649                                 focusedElement, aEditorBase);
   2650 }
   2651 
   2652 // static
   2653 nsresult IMEStateManager::GetFocusSelectionAndRootElement(
   2654    Selection** aSelection, Element** aRootElement) {
   2655  if (!sActiveIMEContentObserver) {
   2656    return NS_ERROR_NOT_AVAILABLE;
   2657  }
   2658  return sActiveIMEContentObserver->GetSelectionAndRoot(aSelection,
   2659                                                        aRootElement);
   2660 }
   2661 
   2662 // static
   2663 TextComposition* IMEStateManager::GetTextCompositionFor(nsIWidget* aWidget) {
   2664  return sTextCompositions ? sTextCompositions->GetCompositionFor(aWidget)
   2665                           : nullptr;
   2666 }
   2667 
   2668 // static
   2669 TextComposition* IMEStateManager::GetTextCompositionFor(
   2670    const WidgetCompositionEvent* aCompositionEvent) {
   2671  return sTextCompositions
   2672             ? sTextCompositions->GetCompositionFor(aCompositionEvent)
   2673             : nullptr;
   2674 }
   2675 
   2676 // static
   2677 TextComposition* IMEStateManager::GetTextCompositionFor(
   2678    nsPresContext* aPresContext) {
   2679  return sTextCompositions ? sTextCompositions->GetCompositionFor(aPresContext)
   2680                           : nullptr;
   2681 }
   2682 
   2683 }  // namespace mozilla