bug 1112212 - Set flag in InputContext for IME-unaware webapps; r=masayuki
authorJim Chen <nchen@mozilla.com>
Tue, 16 Jun 2015 19:02:39 -0400
changeset 249201 9a77983bf7b07e9ceb3cea80bea09faa5165ca2b
parent 249200 872f35399f85dff87ee2cc57b989afa296052331
child 249202 860d548d92d0202485d68869f3ce3614becc1334
push id61171
push usernchen@mozilla.com
push dateTue, 16 Jun 2015 23:02:58 +0000
treeherdermozilla-inbound@0a03c1ef13d0 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersmasayuki
bugs1112212
milestone41.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
bug 1112212 - Set flag in InputContext for IME-unaware webapps; r=masayuki
dom/events/IMEStateManager.cpp
dom/events/IMEStateManager.h
modules/libpref/init/all.js
widget/nsIWidget.h
--- a/dom/events/IMEStateManager.cpp
+++ b/dom/events/IMEStateManager.cpp
@@ -4,16 +4,17 @@
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "mozilla/Logging.h"
 
 #include "mozilla/IMEStateManager.h"
 
 #include "mozilla/Attributes.h"
+#include "mozilla/EventListenerManager.h"
 #include "mozilla/EventStates.h"
 #include "mozilla/MouseEvents.h"
 #include "mozilla/Preferences.h"
 #include "mozilla/Services.h"
 #include "mozilla/TextComposition.h"
 #include "mozilla/TextEvents.h"
 #include "mozilla/dom/HTMLFormElement.h"
 #include "mozilla/dom/TabParent.h"
@@ -176,29 +177,35 @@ GetNotifyIMEMessageName(IMEMessage aMess
       return "unacceptable IME notification message";
   }
 }
 
 nsIContent* IMEStateManager::sContent = nullptr;
 nsPresContext* IMEStateManager::sPresContext = nullptr;
 bool IMEStateManager::sInstalledMenuKeyboardListener = false;
 bool IMEStateManager::sIsGettingNewIMEState = false;
+bool IMEStateManager::sCheckForIMEUnawareWebApps = false;
 
 // sActiveIMEContentObserver points to the currently active IMEContentObserver.
 // sActiveIMEContentObserver is null if there is no focused editor.
 IMEContentObserver* IMEStateManager::sActiveIMEContentObserver = nullptr;
 TextCompositionArray* IMEStateManager::sTextCompositions = nullptr;
 
 // static
 void
 IMEStateManager::Init()
 {
   if (!sISMLog) {
     sISMLog = PR_NewLogModule("IMEStateManager");
   }
+
+  Preferences::AddBoolVarCache(
+    &sCheckForIMEUnawareWebApps,
+    "intl.ime.hack.on_ime_unaware_apps.fire_key_events_for_composition",
+    false);
 }
 
 // static
 void
 IMEStateManager::Shutdown()
 {
   MOZ_LOG(sISMLog, LogLevel::Info,
     ("ISM: IMEStateManager::Shutdown(), "
@@ -807,16 +814,35 @@ public:
     }
     return NS_OK;
   }
 
 private:
   uint32_t mState;
 };
 
+static bool
+MayBeIMEUnawareWebApp(nsINode* aNode)
+{
+  bool haveKeyEventsListener = false;
+
+  while (aNode) {
+    EventListenerManager* const mgr = aNode->GetExistingListenerManager();
+    if (mgr) {
+      if (mgr->MayHaveInputOrCompositionEventListener()) {
+        return false;
+      }
+      haveKeyEventsListener |= mgr->MayHaveKeyEventListener();
+    }
+    aNode = aNode->GetParentNode();
+  }
+
+  return haveKeyEventsListener;
+}
+
 // static
 void
 IMEStateManager::SetIMEState(const IMEState& aState,
                              nsIContent* aContent,
                              nsIWidget* aWidget,
                              InputContextAction aAction)
 {
   MOZ_LOG(sISMLog, LogLevel::Info,
@@ -828,16 +854,18 @@ IMEStateManager::SetIMEState(const IMESt
      GetActionFocusChangeName(aAction.mFocusChange)));
 
   NS_ENSURE_TRUE_VOID(aWidget);
 
   InputContext oldContext = aWidget->GetInputContext();
 
   InputContext context;
   context.mIMEState = aState;
+  context.mMayBeIMEUnaware = context.mIMEState.IsEditable() &&
+    sCheckForIMEUnawareWebApps && MayBeIMEUnawareWebApp(aContent);
 
   if (aContent &&
       aContent->IsAnyOfHTMLElements(nsGkAtoms::input, nsGkAtoms::textarea)) {
     if (!aContent->IsHTMLElement(nsGkAtoms::textarea)) {
       // <input type=number> has an anonymous <input type=text> descendant
       // that gets focus whenever anyone tries to focus the number control. We
       // need to check if aContent is one of those anonymous text controls and,
       // if so, use the number control instead:
--- a/dom/events/IMEStateManager.h
+++ b/dom/events/IMEStateManager.h
@@ -164,16 +164,17 @@ protected:
   static bool IsEditable(nsINode* node);
 
   static bool IsIMEObserverNeeded(const IMEState& aState);
 
   static nsIContent*    sContent;
   static nsPresContext* sPresContext;
   static bool           sInstalledMenuKeyboardListener;
   static bool           sIsGettingNewIMEState;
+  static bool           sCheckForIMEUnawareWebApps;
 
   class MOZ_STACK_CLASS GettingNewIMEStateBlocker final
   {
   public:
     GettingNewIMEStateBlocker()
       : mOldValue(IMEStateManager::sIsGettingNewIMEState)
     {
       IMEStateManager::sIsGettingNewIMEState = true;
--- a/modules/libpref/init/all.js
+++ b/modules/libpref/init/all.js
@@ -1788,16 +1788,23 @@ pref("intl.charset.fallback.tld",       
 pref("intl.ellipsis",                       "chrome://global-platform/locale/intl.properties");
 pref("intl.locale.matchOS",                 false);
 // fallback charset list for Unicode conversion (converting from Unicode)
 // currently used for mail send only to handle symbol characters (e.g Euro, trademark, smartquotes)
 // for ISO-8859-1
 pref("intl.fallbackCharsetList.ISO-8859-1", "windows-1252");
 pref("font.language.group",                 "chrome://global/locale/intl.properties");
 
+// Android-specific pref to use key-events-only mode for IME-unaware webapps.
+#ifdef MOZ_WIDGET_ANDROID
+pref("intl.ime.hack.on_ime_unaware_apps.fire_key_events_for_composition", true);
+#else
+pref("intl.ime.hack.on_ime_unaware_apps.fire_key_events_for_composition", false);
+#endif
+
 // these locales have right-to-left UI
 pref("intl.uidirection.ar", "rtl");
 pref("intl.uidirection.he", "rtl");
 pref("intl.uidirection.fa", "rtl");
 pref("intl.uidirection.ug", "rtl");
 pref("intl.uidirection.ur", "rtl");
 
 // use en-US hyphenation by default for content tagged with plain lang="en"
--- a/widget/nsIWidget.h
+++ b/widget/nsIWidget.h
@@ -418,16 +418,17 @@ struct IMEState {
     return IsEditable() || mEnabled == PLUGIN;
   }
 };
 
 struct InputContext {
   InputContext()
     : mNativeIMEContext(nullptr)
     , mOrigin(XRE_IsParentProcess() ? ORIGIN_MAIN : ORIGIN_CONTENT)
+    , mMayBeIMEUnaware(false)
   {}
 
   bool IsPasswordEditor() const
   {
     return mHTMLInputType.LowerCaseEqualsLiteral("password");
   }
 
   IMEState mIMEState;
@@ -441,29 +442,33 @@ struct InputContext {
   /* A hint for the action that is performed when the input is submitted */
   nsString mActionHint;
 
   /* Native IME context for the widget.  This doesn't come from the argument of
      SetInputContext().  If there is only one context in the process, this may
      be nullptr. */
   void* mNativeIMEContext;
 
-
   /**
    * mOrigin indicates whether this focus event refers to main or remote content.
    */
   enum Origin
   {
     // Adjusting focus of content on the main process
     ORIGIN_MAIN,
     // Adjusting focus of content in a remote process
     ORIGIN_CONTENT
   };
   Origin mOrigin;
 
+  /* True if the webapp may be unaware of IME events such as input event or
+   * composiion events. This enables a key-events-only mode on Android for
+   * compatibility with webapps relying on key listeners. */
+  bool mMayBeIMEUnaware;
+
   bool IsOriginMainProcess() const
   {
     return mOrigin == ORIGIN_MAIN;
   }
 
   bool IsOriginContentProcess() const
   {
     return mOrigin == ORIGIN_CONTENT;