Bug 1240208 - use inputmode in XUL to get better hinting for IME and on-screen keyboards, r?masayuki draft
authorGijs Kruitbosch <gijskruitbosch@gmail.com>
Mon, 01 Feb 2016 17:57:29 +0000
changeset 327734 0b640769e92d9d8c01e972c2b526ea56cc56d1df
parent 327532 eebe1132e3eb08745e1cbd1100ccec0bf99f201b
child 513734 b77c81f4b4bd2c7671481065d553122c6a398de0
push id10276
push usergijskruitbosch@gmail.com
push dateMon, 01 Feb 2016 17:58:01 +0000
reviewersmasayuki
bugs1240208
milestone47.0a1
Bug 1240208 - use inputmode in XUL to get better hinting for IME and on-screen keyboards, r?masayuki
browser/base/content/urlbarBindings.xml
dom/events/IMEStateManager.cpp
widget/windows/TSFTextStore.cpp
widget/windows/TSFTextStore.h
widget/windows/WinIMEHandler.cpp
widget/windows/WinIMEHandler.h
--- a/browser/base/content/urlbarBindings.xml
+++ b/browser/base/content/urlbarBindings.xml
@@ -32,17 +32,18 @@ file, You can obtain one at http://mozil
         </children>
         <xul:hbox anonid="textbox-input-box"
                   class="textbox-input-box urlbar-input-box"
                   flex="1" xbl:inherits="tooltiptext=inputtooltiptext">
           <children/>
           <html:input anonid="input"
                       class="autocomplete-textbox urlbar-input textbox-input uri-element-right-align"
                       allowevents="true"
-                      xbl:inherits="tooltiptext=inputtooltiptext,value,type=inputtype,maxlength,disabled,size,readonly,placeholder,tabindex,accesskey"/>
+                      inputmode="url"
+                      xbl:inherits="tooltiptext=inputtooltiptext,value,maxlength,disabled,size,readonly,placeholder,tabindex,accesskey"/>
         </xul:hbox>
         <xul:dropmarker anonid="historydropmarker"
                         class="autocomplete-history-dropmarker urlbar-history-dropmarker"
                         tooltiptext="&urlbar.openHistoryPopup.tooltip;"
                         allowevents="true"
                         xbl:inherits="open,enablehistory,parentfocused=focused"/>
         <children includes="hbox"/>
       </xul:hbox>
--- a/dom/events/IMEStateManager.cpp
+++ b/dom/events/IMEStateManager.cpp
@@ -1029,17 +1029,18 @@ IMEStateManager::SetIMEState(const IMESt
         }
       }
       content->GetAttr(kNameSpaceID_None, nsGkAtoms::type,
                        context.mHTMLInputType);
     } else {
       context.mHTMLInputType.Assign(nsGkAtoms::textarea->GetUTF16String());
     }
 
-    if (Preferences::GetBool("dom.forms.inputmode", false)) {
+    if (Preferences::GetBool("dom.forms.inputmode", false) ||
+        nsContentUtils::IsChromeDoc(aContent->OwnerDoc())) {
       aContent->GetAttr(kNameSpaceID_None, nsGkAtoms::inputmode,
                         context.mHTMLInputInputmode);
     }
 
     aContent->GetAttr(kNameSpaceID_None, nsGkAtoms::moz_action_hint,
                       context.mActionHint);
 
     // Get the input content corresponding to the focused node,
--- a/widget/windows/TSFTextStore.cpp
+++ b/widget/windows/TSFTextStore.cpp
@@ -3023,20 +3023,31 @@ TSFTextStore::InsertEmbedded(DWORD dwFla
          ("TSF: 0x%p TSFTextStore::InsertEmbedded() called "
           "but not supported (E_NOTIMPL)", this));
 
   // embedded objects are not supported
   return E_NOTIMPL;
 }
 
 void
-TSFTextStore::SetInputScope(const nsString& aHTMLInputType)
+TSFTextStore::SetInputScope(const nsString& aHTMLInputType,
+                            const nsString& aHTMLInputInputMode)
 {
   mInputScopes.Clear();
   if (aHTMLInputType.IsEmpty() || aHTMLInputType.EqualsLiteral("text")) {
+    if (aHTMLInputInputMode.EqualsLiteral("url")) {
+      mInputScopes.AppendElement(IS_URL);
+    } else if (aHTMLInputInputMode.EqualsLiteral("email")) {
+      mInputScopes.AppendElement(IS_EMAIL_SMTPEMAILADDRESS);
+    } else if (aHTMLInputType.EqualsLiteral("tel")) {
+      mInputScopes.AppendElement(IS_TELEPHONE_FULLTELEPHONENUMBER);
+      mInputScopes.AppendElement(IS_TELEPHONE_LOCALNUMBER);
+    } else if (aHTMLInputType.EqualsLiteral("numeric")) {
+      mInputScopes.AppendElement(IS_NUMBER);
+    }
     return;
   }
   
   // http://www.whatwg.org/specs/web-apps/current-work/multipage/the-input-element.html
   if (aHTMLInputType.EqualsLiteral("url")) {
     mInputScopes.AppendElement(IS_URL);
   } else if (aHTMLInputType.EqualsLiteral("search")) {
     mInputScopes.AppendElement(IS_SEARCH);
@@ -4554,17 +4565,18 @@ TSFTextStore::CreateAndSetFocus(nsWindow
                                   sEnabledTextStore->mDocumentMgr,
                                   getter_AddRefs(prevFocusedDocumentMgr));
   if (NS_WARN_IF(FAILED(hr))) {
     MOZ_LOG(sTextStoreLog, LogLevel::Error,
            ("TSF:   TSFTextStore::CreateAndSetFocus() FAILED due to "
             "ITfTheadMgr::AssociateFocus() failure"));
     return false;
   }
-  sEnabledTextStore->SetInputScope(aContext.mHTMLInputType);
+  sEnabledTextStore->SetInputScope(aContext.mHTMLInputType,
+                                   aContext.mHTMLInputInputmode);
 
   if (sEnabledTextStore->mSink) {
     MOZ_LOG(sTextStoreLog, LogLevel::Info,
       ("TSF:   TSFTextStore::CreateAndSetFocus(), calling "
        "ITextStoreACPSink::OnLayoutChange(TS_LC_CREATE) for 0x%p...",
        sEnabledTextStore.get()));
     sEnabledTextStore->mSink->OnLayoutChange(TS_LC_CREATE,
                                              TEXTSTORE_DEFAULT_VIEW);
@@ -5291,17 +5303,18 @@ TSFTextStore::SetInputContext(nsWindowBa
           aWidget, GetIMEEnabledName(aContext.mIMEState.mEnabled),
           GetFocusChangeName(aAction.mFocusChange), sEnabledTextStore.get(),
           GetBoolName(ThinksHavingFocus())));
 
   NS_ENSURE_TRUE_VOID(IsInTSFMode());
 
   if (aAction.mFocusChange != InputContextAction::FOCUS_NOT_CHANGED) {
     if (sEnabledTextStore) {
-      sEnabledTextStore->SetInputScope(aContext.mHTMLInputType);
+      sEnabledTextStore->SetInputScope(aContext.mHTMLInputType,
+                                       aContext.mHTMLInputInputmode);
     }
     return;
   }
 
   // If focus isn't actually changed but the enabled state is changed,
   // emulate the focus move.
   if (!ThinksHavingFocus() && aContext.mIMEState.IsEditable()) {
     OnFocusChange(true, aWidget, aContext);
--- a/widget/windows/TSFTextStore.h
+++ b/widget/windows/TSFTextStore.h
@@ -297,17 +297,18 @@ protected:
   void     NotifyTSFOfTextChange(const TS_TEXTCHANGE& aTextChange);
   void     NotifyTSFOfSelectionChange();
   bool     NotifyTSFOfLayoutChange();
   void     NotifyTSFOfLayoutChangeAgain();
 
   HRESULT  HandleRequestAttrs(DWORD aFlags,
                               ULONG aFilterCount,
                               const TS_ATTRID* aFilterAttrs);
-  void     SetInputScope(const nsString& aHTMLInputType);
+  void     SetInputScope(const nsString& aHTMLInputType,
+                         const nsString& aHTMLInputInputmode);
 
   // Creates native caret over our caret.  This method only works on desktop
   // application.  Otherwise, this does nothing.
   void     CreateNativeCaret();
   // Destroys native caret if there is.
   void     MaybeDestroyNativeCaret();
 
   // Holds the pointer to our current win32 widget
--- a/widget/windows/WinIMEHandler.cpp
+++ b/widget/windows/WinIMEHandler.cpp
@@ -388,17 +388,17 @@ IMEHandler::OnDestroyWindow(nsWindow* aW
   }
 
 #ifdef NS_ENABLE_TSF
   // We need to do nothing here for TSF. Just restore the default context
   // if it's been disassociated.
   if (!sIsInTSFMode) {
     // MSDN says we need to set IS_DEFAULT to avoid memory leak when we use
     // SetInputScopes API. Use an empty string to do this.
-    SetInputScopeForIMM32(aWindow, EmptyString());
+    SetInputScopeForIMM32(aWindow, EmptyString(), EmptyString());
   }
 #endif // #ifdef NS_ENABLE_TSF
   AssociateIMEContext(aWindow, true);
 }
 
 // static
 void
 IMEHandler::SetInputContext(nsWindow* aWindow,
@@ -439,17 +439,18 @@ IMEHandler::SetInputContext(nsWindow* aW
       }
       if (adjustOpenState) {
         TSFTextStore::SetIMEOpenState(open);
       }
       return;
     }
   } else {
     // Set at least InputScope even when TextStore is not available.
-    SetInputScopeForIMM32(aWindow, aInputContext.mHTMLInputType);
+    SetInputScopeForIMM32(aWindow, aInputContext.mHTMLInputType,
+                          aInputContext.mHTMLInputInputmode);
   }
 #endif // #ifdef NS_ENABLE_TSF
 
   AssociateIMEContext(aWindow, enable);
 
   IMEContext context(aWindow);
   if (adjustOpenState) {
     context.SetOpenState(open);
@@ -512,28 +513,48 @@ IMEHandler::CurrentKeyboardLayoutHasIME(
 
   return IMMHandler::IsIMEAvailable();
 }
 #endif // #ifdef DEBUG
 
 // static
 void
 IMEHandler::SetInputScopeForIMM32(nsWindow* aWindow,
-                                  const nsAString& aHTMLInputType)
+                                  const nsAString& aHTMLInputType,
+                                  const nsAString& aHTMLInputInputmode)
 {
   if (sIsInTSFMode || !sSetInputScopes || aWindow->Destroyed()) {
     return;
   }
   UINT arraySize = 0;
   const InputScope* scopes = nullptr;
   // http://www.whatwg.org/specs/web-apps/current-work/multipage/the-input-element.html
   if (aHTMLInputType.IsEmpty() || aHTMLInputType.EqualsLiteral("text")) {
-    static const InputScope inputScopes[] = { IS_DEFAULT };
-    scopes = &inputScopes[0];
-    arraySize = ArrayLength(inputScopes);
+    if (aHTMLInputInputmode.EqualsLiteral("url")) {
+      static const InputScope inputScopes[] = { IS_URL };
+      scopes = &inputScopes[0];
+      arraySize = ArrayLength(inputScopes);
+    } else if (aHTMLInputInputmode.EqualsLiteral("email")) {
+      static const InputScope inputScopes[] = { IS_EMAIL_SMTPEMAILADDRESS };
+      scopes = &inputScopes[0];
+      arraySize = ArrayLength(inputScopes);
+    } else if (aHTMLInputInputmode.EqualsLiteral("tel")) {
+      static const InputScope inputScopes[] =
+        {IS_TELEPHONE_LOCALNUMBER, IS_TELEPHONE_FULLTELEPHONENUMBER};
+      scopes = &inputScopes[0];
+      arraySize = ArrayLength(inputScopes);
+    } else if (aHTMLInputInputmode.EqualsLiteral("numeric")) {
+      static const InputScope inputScopes[] = { IS_NUMBER };
+      scopes = &inputScopes[0];
+      arraySize = ArrayLength(inputScopes);
+    } else {
+      static const InputScope inputScopes[] = { IS_DEFAULT };
+      scopes = &inputScopes[0];
+      arraySize = ArrayLength(inputScopes);
+    }
   } else if (aHTMLInputType.EqualsLiteral("url")) {
     static const InputScope inputScopes[] = { IS_URL };
     scopes = &inputScopes[0];
     arraySize = ArrayLength(inputScopes);
   } else if (aHTMLInputType.EqualsLiteral("search")) {
     static const InputScope inputScopes[] = { IS_SEARCH };
     scopes = &inputScopes[0];
     arraySize = ArrayLength(inputScopes);
--- a/widget/windows/WinIMEHandler.h
+++ b/widget/windows/WinIMEHandler.h
@@ -126,17 +126,18 @@ private:
   static nsWindow* sFocusedWindow;
   static InputContextAction::Cause sLastContextActionCause;
 
   static bool sPluginHasFocus;
 
 #ifdef NS_ENABLE_TSF
   static decltype(SetInputScopes)* sSetInputScopes;
   static void SetInputScopeForIMM32(nsWindow* aWindow,
-                                    const nsAString& aHTMLInputType);
+                                    const nsAString& aHTMLInputType,
+                                    const nsAString& aHTMLInputInputmode);
   static bool sIsInTSFMode;
   // If sIMMEnabled is false, any IME messages are not handled in TSF mode.
   // Additionally, IME context is always disassociated from focused window.
   static bool sIsIMMEnabled;
 
   static bool IsTSFAvailable() { return (sIsInTSFMode && !sPluginHasFocus); }
   static bool IsIMMActive();