Bug 925467: Part 1: Workaround to make OSK more consistent. r=jmathies
authorMarina Samuel <msamuel@mozilla.com>
Mon, 21 Oct 2013 13:02:02 -0400
changeset 165357 f826a7afb3ccd07275f15ac0a82f31658a71155b
parent 165356 5625142a40ce14ddfcedfc0012b2b5990e02d5f0
child 165358 418d0fbd33b055d86cb7907142b8945118c217b2
push id3066
push userakeybl@mozilla.com
push dateMon, 09 Dec 2013 19:58:46 +0000
treeherdermozilla-beta@a31a0dce83aa [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersjmathies
bugs925467
milestone27.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 925467: Part 1: Workaround to make OSK more consistent. r=jmathies
browser/metro/base/content/bindings/bindings.xml
browser/metro/base/content/browser-ui.js
browser/metro/base/content/contenthandlers/Content.js
browser/metro/base/content/contenthandlers/SelectionHandler.js
browser/metro/base/content/helperui/SelectionHelperUI.js
--- a/browser/metro/base/content/bindings/bindings.xml
+++ b/browser/metro/base/content/bindings/bindings.xml
@@ -189,18 +189,24 @@
         <![CDATA[
           let box = this.inputField.parentNode;
           box.showContextMenu(this, event, false);
         ]]>
       </handler>
       <handler event="click" phase="capturing">
         <![CDATA[
         if (event.mozInputSource == Ci.nsIDOMMouseEvent.MOZ_SOURCE_TOUCH) {
-          SelectionHelperUI.attachEditSession(ChromeSelectionHandler,
-                                              event.clientX, event.clientY);
+          if (typeof SelectionHelperUI != 'undefined') {
+            SelectionHelperUI.attachEditSession(ChromeSelectionHandler,
+                                                event.clientX, event.clientY);
+          } else {
+            // If we don't have access to SelectionHelperUI then we are using this
+            // binding for browser content (e.g. about:config)
+            Services.obs.notifyObservers(event, "attach_edit_session_to_content", "");
+          }
         }
       ]]>
       </handler>
     </handlers>
   </binding>
 
   <binding id="search-textbox" extends="chrome://global/content/bindings/textbox.xml#search-textbox">
     <implementation>
@@ -282,16 +288,22 @@
           ContextMenuUI.showContextMenu({ target: aTextbox, json: json });
         ]]></body>
       </method>
     </implementation>
     <handlers>
       <handler event="click" phase="capturing">
         <![CDATA[
           if (event.mozInputSource == Ci.nsIDOMMouseEvent.MOZ_SOURCE_TOUCH) {
-            SelectionHelperUI.attachEditSession(ChromeSelectionHandler,
-                                                event.clientX, event.clientY);
+            if (typeof SelectionHelperUI != 'undefined') {
+              SelectionHelperUI.attachEditSession(ChromeSelectionHandler,
+                                                  event.clientX, event.clientY);
+            } else {
+              // If we don't have access to SelectionHelperUI then we are using this
+              // binding for browser content (e.g. about:config)
+              Services.obs.notifyObservers(event, "attach_edit_session_to_content", "");
+            }
           }
         ]]>
       </handler>
     </handlers>
   </binding>
 </bindings>
--- a/browser/metro/base/content/browser-ui.js
+++ b/browser/metro/base/content/browser-ui.js
@@ -107,16 +107,17 @@ var BrowserUI = {
     // Init core UI modules
     ContextUI.init();
     PanelUI.init();
     FlyoutPanelsUI.init();
     PageThumbs.init();
     NewTabUtils.init();
     SettingsCharm.init();
     NavButtonSlider.init();
+    SelectionHelperUI.init();
 
     // We can delay some initialization until after startup.  We wait until
     // the first page is shown, then dispatch a UIReadyDelayed event.
     messageManager.addMessageListener("pageshow", function onPageShow() {
       if (getBrowser().currentURI.spec == "about:blank")
         return;
 
       messageManager.removeMessageListener("pageshow", onPageShow);
--- a/browser/metro/base/content/contenthandlers/Content.js
+++ b/browser/metro/base/content/contenthandlers/Content.js
@@ -179,16 +179,22 @@ let Content = {
         // the autocomplete.  Perhaps the user used backspace or delete.
         if (!aEvent.target.value)
           this.formAssistant.close();
         else
           this.formAssistant.open(aEvent.target);
         break;
 
       case "click":
+        // Workaround for bug 925457: we sometimes don't recognize the
+        // correct tap target or are unable to identify if it's editable.
+        // Instead always save tap co-ordinates for the keyboard to look for
+        // when it is up.
+        SelectionHandler.onClickCoords(aEvent.clientX, aEvent.clientY);
+
         if (aEvent.eventPhase == aEvent.BUBBLING_PHASE)
           this._onClickBubble(aEvent);
         else
           this._onClickCapture(aEvent);
         break;
 
       case "DOMFormHasPassword":
         LoginManagerContent.onFormPassword(aEvent);
--- a/browser/metro/base/content/contenthandlers/SelectionHandler.js
+++ b/browser/metro/base/content/contenthandlers/SelectionHandler.js
@@ -3,16 +3,17 @@
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 dump("### SelectionHandler.js loaded\n");
 
 var SelectionHandler = {
   init: function init() {
     this.type = kContentSelector;
     this.snap = true;
+    this.lastYPos = this.lastXPos = null;
     addMessageListener("Browser:SelectionStart", this);
     addMessageListener("Browser:SelectionAttach", this);
     addMessageListener("Browser:SelectionEnd", this);
     addMessageListener("Browser:SelectionMoveStart", this);
     addMessageListener("Browser:SelectionMove", this);
     addMessageListener("Browser:SelectionMoveEnd", this);
     addMessageListener("Browser:SelectionUpdate", this);
     addMessageListener("Browser:SelectionClose", this);
@@ -335,16 +336,21 @@ var SelectionHandler = {
       raiseContent: result,
     });
   },
 
   _onPing: function _onPing(aId) {
     this.sendAsync("Content:SelectionHandlerPong", { id: aId });
   },
 
+  onClickCoords: function (xPos, yPos) {
+    this.lastXPos = xPos;
+    this.lastYPos = yPos;
+  },
+
   /*************************************************
    * Selection helpers
    */
 
   /*
    * _clearSelection
    *
    * Clear existing selection if it exists and reset our internla state.
@@ -407,19 +413,22 @@ var SelectionHandler = {
    * keyboard.
    *
    * @param aNewViewHeight the new content view height
    * @return 0 if no positioning is required or a positive val equal to the
    * distance content should be raised to center the target element.
    */
   _calcNewContentPosition: function _calcNewContentPosition(aNewViewHeight) {
     // We have no target element but the keyboard is up
-    // so lets not cover content
+    // so lets not cover content that is below the keyboard
     if (!this._cache || !this._cache.element) {
-      return Services.metro.keyboardHeight;
+      if (this.lastYPos != null && this.lastYPos > aNewViewHeight) {
+        return Services.metro.keyboardHeight;
+      }
+      return 0;
     }
 
     let position = Util.centerElementInView(aNewViewHeight, this._cache.element);
     if (position !== undefined) {
       return position;
     }
 
     // Special case: we are dealing with an input that is taller than the
@@ -518,17 +527,22 @@ var SelectionHandler = {
         this._onSelectionDebug(json);
         break;
 
       case "Browser:SelectionUpdate":
         this._onSelectionUpdate();
         break;
 
       case "Browser:RepositionInfoRequest":
-        this._repositionInfoRequest(json);
+        // This message is sent simultaneously with a tap event.
+        // Wait a bit to make sure we have the most up-to-date tap co-ordinates
+        // before a call to _calcNewContentPosition() which accesses them.
+        content.setTimeout (function () {
+          SelectionHandler._repositionInfoRequest(json);
+        }, 50);
         break;
 
       case "Browser:SelectionHandlerPing":
         this._onPing(json.id);
         break;
     }
   },
 
--- a/browser/metro/base/content/helperui/SelectionHelperUI.js
+++ b/browser/metro/base/content/helperui/SelectionHelperUI.js
@@ -339,16 +339,31 @@ var SelectionHelperUI = {
       return false;
     if ((this._caretMark && this._caretMark.dragging) ||
         (this._startMark && this._startMark.dragging) ||
         (this._endMark && this._endMark.dragging))
       return true;
     return false;
   },
 
+
+  /*
+   * Observers
+   */
+
+  observe: function (aSubject, aTopic, aData) {
+  switch (aTopic) {
+    case "attach_edit_session_to_content":
+      let event = aSubject;
+      SelectionHelperUI.attachEditSession(Browser.selectedTab.browser,
+                                          event.clientX, event.clientY);
+      break;
+    }
+  },
+
   /*
    * Public apis
    */
 
   /*
    * pingSelectionHandler
    * 
    * Ping the SelectionHandler and wait for the right response. Insures
@@ -490,16 +505,20 @@ var SelectionHelperUI = {
       clearSelection: clearSelection
     });
   },
 
   /*
    * Init and shutdown
    */
 
+  init: function () {
+    Services.obs.addObserver(this, "attach_edit_session_to_content", false);
+  },
+
   _init: function _init(aMsgTarget) {
     // store the target message manager
     this._msgTarget = aMsgTarget;
 
     // Init our list of available monocle ids
     this._setupMonocleIdArray();
 
     // Init selection rect info