Bug 856151 - do some houskeeping in browser bindings, and define a set of browser/client coordinate conversion helpers. r=mbrubeck
authorJim Mathies <jmathies@mozilla.com>
Fri, 05 Apr 2013 05:33:41 -0500
changeset 127776 a5aa2d31e8e9a9ef9dd4b0eb60690452fd0ad351
parent 127775 842c175f344c4df1f33c9852a12134d4fa6d64e0
child 127777 5722966a3126e7d5e47476457fcb78a105034272
push id24512
push userryanvm@gmail.com
push dateFri, 05 Apr 2013 20:13:49 +0000
treeherdermozilla-central@139b6ba547fa [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersmbrubeck
bugs856151
milestone23.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 856151 - do some houskeeping in browser bindings, and define a set of browser/client coordinate conversion helpers. r=mbrubeck
browser/metro/base/content/bindings/browser.xml
browser/metro/base/content/browser.js
--- a/browser/metro/base/content/bindings/browser.xml
+++ b/browser/metro/base/content/bindings/browser.xml
@@ -4,22 +4,61 @@
    - 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/. -->
 
 <!DOCTYPE bindings [
   <!ENTITY % findBarDTD SYSTEM "chrome://global/locale/findbar.dtd" >
   %findBarDTD;
 ]>
 
-<bindings id="remoteBrowserBindings"
+<bindings id="browser-bindings"
           xmlns="http://www.mozilla.org/xbl"
           xmlns:xul="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
 
   <binding id="local-browser" extends="chrome://global/content/bindings/browser.xml#browser">
-    <implementation type="application/javascript" implements="nsIAccessibleProvider, nsIObserver, nsIDOMEventListener, nsIMessageListener">
+    <implementation type="application/javascript"
+      implements="nsIAccessibleProvider, nsIObserver, nsIDOMEventListener, nsIMessageListener">
+
+      <constructor>
+        <![CDATA[
+          this._frameLoader =
+            this.QueryInterface(Components.interfaces.nsIFrameLoaderOwner).frameLoader;
+          this._contentViewManager =
+            this._frameLoader.QueryInterface(Components.interfaces.nsIContentViewManager);
+
+          let prefService =
+            Components.classes["@mozilla.org/preferences-service;1"]
+                      .getService(Components.interfaces.nsIPrefBranch);
+          this._cacheRatioWidth =
+            Math.max(1, prefService.getIntPref("toolkit.browser.cacheRatioWidth") / 1000);
+          this._cacheRatioHeight =
+            Math.max(1, prefService.getIntPref("toolkit.browser.cacheRatioHeight") / 1000);
+
+          if (this._contentViewPrototype) {
+            this._contentViewPrototype.kDieTime = prefService.getIntPref("toolkit.browser.contentViewExpire");
+          }
+
+          this.messageManager.loadFrameScript("chrome://browser/content/bindings/browser.js", true);
+          this.messageManager.addMessageListener("DOMTitleChanged", this._messageListenerLocal);
+          this.messageManager.addMessageListener("DOMLinkAdded", this._messageListenerLocal);
+          this.messageManager.addMessageListener("pageshow", this._messageListenerLocal);
+          this.messageManager.addMessageListener("pagehide", this._messageListenerLocal);
+          this.messageManager.addMessageListener("DOMPopupBlocked", this._messageListenerLocal);
+          this.messageManager.addMessageListener("MozScrolledAreaChanged", this._messageListenerLocal);
+          this.messageManager.addMessageListener("Content:UpdateDisplayPort", this._messageListenerLocal);
+
+          this._webProgress._init();
+
+          // Remove event listeners added by toolkit <browser> binding.
+          this.removeEventListener("pageshow", this.onPageShow, true);
+          this.removeEventListener("pagehide", this.onPageHide, true);
+          this.removeEventListener("DOMPopupBlocked", this.onPopupBlocked, true);
+        ]]>
+      </constructor>
+
       <field name="_securityUI">null</field>
       <property name="securityUI">
         <getter><![CDATA[
           return this._securityUI || {};
         ]]></getter>
         <setter><![CDATA[
           this._securityUI = val;
         ]]></setter>
@@ -42,16 +81,230 @@
                 readonly="true"/>
 
       <field name="_contentTitle">null</field>
 
       <field name="_ios">
          Components.classes["@mozilla.org/network/io-service;1"].getService(Components.interfaces.nsIIOService);
       </field>
 
+      <!--
+        * Point Conversion Routines - browsers may be shifted by UI such that
+        * a client point in an event does not coincide with a css position.
+        * Examples include the notification bar, which pushes the browser down,
+        * or deck movement when forms are positioned above the keyboard.
+        *
+        * Client to browser conversion:
+        *
+        * ptClientToBrowser
+        *  Convert client coordinates in device pixels to page-relative
+        *  coordinates in CSS pixels.
+        *
+        * @param aClientX, aClientY - client coordinates to convert.
+        * @param aIgnoreScroll ignore root frame scroll.
+        * @param aIgnoreScale ignore current scale factor.
+        * @return { x: converted x coordinate, y: converted y coordinate }
+        *
+        * xctob, yctob
+        *  Convert individual x and y coordinates.
+        *
+        * @param aX or aY - browser coordinate
+        * @param aIgnoreScroll ignore root frame scroll.
+        * @param aIgnoreScale ignore current scale factor.
+        * @return converted coordinate
+        *
+        * Browser to client conversion:
+        *
+        * ptBrowserToClient
+        *  Convert browser coordinates in css pixels to client (screen) coordinates
+        *  in device pixels. Useful in positioning UI elements at event targets.
+        *
+        * @param aBrowserX, aBrowserY - browser coordinates to convert.
+        * @param aIgnoreScroll ignore root frame scroll.
+        * @param aIgnoreScale ignore current scale factor.
+        * @return { x: converted x coordinate, y: converted y coordinate }
+        *
+        * msgBrowserToClient
+        *  Converts a message manager message with coordinates stored in
+        *  aMessage.json.xPos, aMessage.json.yPos.
+        *
+        * @param aMessage - message manager message
+        * @param aIgnoreScroll ignore root frame scroll.
+        * @param aIgnoreScale ignore current scale factor.
+        * @return { x: converted x coordinate, y: converted y coordinate }
+        *
+        * rectBrowserToClient
+        *  Converts a rect (left, top, right, bottom).
+        *
+        * @param aMessage - message manager message
+        * @param aIgnoreScroll ignore root frame scroll.
+        * @param aIgnoreScale ignore current scale factor.
+        * @return { left:, top:, right:, bottom: }
+        *
+        * xbtoc, ybtoc
+        *  Convert individual x and y coordinates.
+        *
+        * @param aX or aY - client coordinate
+        * @param aIgnoreScroll ignore root frame scroll.
+        * @param aIgnoreScale ignore current scale factor.
+        * @return converted coordinate
+      -->
+      <method name="ptClientToBrowser">
+        <parameter name="aClientX"/>
+        <parameter name="aClientY"/>
+        <parameter name="aIgnoreScroll"/>
+        <parameter name="aIgnoreScale"/>
+        <body>
+          <![CDATA[
+            let ignoreScroll = aIgnoreScroll || false;
+            let ignoreScale = aIgnoreScale || false;
+
+            let bcr = this.getBoundingClientRect();
+
+            let scrollX = 0;
+            let scrollY = 0;
+            if (!ignoreScroll) {
+              let scroll = this.getRootView().getPosition();
+              scrollX = scroll.x;
+              scrollY = scroll.y;
+            }
+
+            let scale = 1;
+            if (!ignoreScale) {
+              scale = this.scale;
+            }
+
+            return {
+              x: (aClientX + scrollX - bcr.left) / scale,
+              y: (aClientY + scrollY - bcr.top) / scale
+            };
+          ]]>
+        </body>
+      </method>
+
+      <method name="xctob">
+        <parameter name="aX"/>
+        <parameter name="aIgnoreScroll"/>
+        <parameter name="aIgnoreScale"/>
+        <body>
+          <![CDATA[
+            let y = 0;
+            let result = this.ptClientToBrowser(aX, y, aIgnoreScroll, aIgnoreScale);
+            return result.x;
+          ]]>
+        </body>
+      </method>
+
+      <method name="yctob">
+        <parameter name="aY"/>
+        <parameter name="aIgnoreScroll"/>
+        <parameter name="aIgnoreScale"/>
+        <body>
+          <![CDATA[
+            let x = 0;
+            let result = this.ptClientToBrowser(x, aY, aIgnoreScroll, aIgnoreScale);
+            return result.y;
+          ]]>
+        </body>
+      </method>
+
+      <method name="ptBrowserToClient">
+        <parameter name="aBrowserX"/>
+        <parameter name="aBrowserY"/>
+        <parameter name="aIgnoreScroll"/>
+        <parameter name="aIgnoreScale"/>
+        <body>
+          <![CDATA[
+            let ignoreScroll = aIgnoreScroll || false;
+            let ignoreScale = aIgnoreScale || false;
+
+            let bcr = this.getBoundingClientRect();
+
+            let scrollX = 0;
+            let scrollY = 0;
+            if (!ignoreScroll) {
+              let scroll = this.getRootView().getPosition();
+              scrollX = scroll.x;
+              scrollY = scroll.y;
+            }
+
+            let scale = 1;
+            if (!ignoreScale) {
+              scale = this.scale;
+            }
+
+            return {
+              x: (aBrowserX * scale - scrollX + bcr.left),
+              y: (aBrowserY * scale - scrollY + bcr.top)
+            };
+          ]]>
+        </body>
+      </method>
+
+      <method name="msgBrowserToClient">
+        <parameter name="aMessage"/>
+        <parameter name="aIgnoreScroll"/>
+        <parameter name="aIgnoreScale"/>
+        <body>
+          <![CDATA[
+            let x = aMessage.json.xPos;
+            let y = aMessage.json.yPos;
+            return this.ptBrowserToClient(x, y, aIgnoreScroll, aIgnoreScale);
+          ]]>
+        </body>
+      </method>
+
+      <method name="rectBrowserToClient">
+        <parameter name="aRect"/>
+        <parameter name="aIgnoreScroll"/>
+        <parameter name="aIgnoreScale"/>
+        <body>
+          <![CDATA[
+            let left = aRect.left;
+            let top = aRect.top;
+            let right = aRect.right;
+            let bottom = aRect.bottom;
+            let a = this.ptBrowserToClient(left, top, aIgnoreScroll, aIgnoreScale);
+            let b = this.ptBrowserToClient(right, bottom, aIgnoreScroll, aIgnoreScale);
+            return {
+              left: a.x,
+              top: a.y,
+              right: b.x,
+              bottom: b.y
+            };
+          ]]>
+        </body>
+      </method>
+
+      <method name="xbtoc">
+        <parameter name="aX"/>
+        <parameter name="aIgnoreScroll"/>
+        <parameter name="aIgnoreScale"/>
+        <body>
+          <![CDATA[
+            let y = 0;
+            let result = this.ptBrowserToClient(aX, y, aIgnoreScroll, aIgnoreScale);
+            return result.x;
+          ]]>
+        </body>
+      </method>
+
+      <method name="ybtoc">
+        <parameter name="aY"/>
+        <parameter name="aIgnoreScroll"/>
+        <parameter name="aIgnoreScale"/>
+        <body>
+          <![CDATA[
+            let x = 0;
+            let result = this.ptBrowserToClient(x, aY, aIgnoreScroll, aIgnoreScale);
+            return result.y;
+          ]]>
+        </body>
+      </method>
+
       <field name="_messageListenerLocal"><![CDATA[
         ({
           self: this,
           receiveMessage: function receiveMessage(aMessage) {
             let self = this.self;
             let json = aMessage.json;
 
             switch (aMessage.name) {
@@ -491,76 +744,16 @@
 
           toString: function() {
             return "[View Local]";
           }
         })
         ]]>
       </field>
 
-      <!-- Change client coordinates in device pixels to page-relative ones in CSS px. -->
-      <!-- (Does not take into account sub frame scroll) -->
-      <method name="transformClientToBrowser">
-        <parameter name="clientX"/>
-        <parameter name="clientY"/>
-        <body>
-          <![CDATA[
-            let bcr = this.getBoundingClientRect();
-            let scroll = this.getRootView().getPosition();
-            return { x: (clientX + scroll.x - bcr.left) / this.scale,
-                     y: (clientY + scroll.y - bcr.top) / this.scale };
-          ]]>
-        </body>
-      </method>
-
-      <method name="transformBrowserToClient">
-        <parameter name="browserX"/>
-        <parameter name="browserY"/>
-        <body>
-          <![CDATA[
-            let bcr = this.getBoundingClientRect();
-            let scroll = this.getRootView().getPosition();
-            return { x: (browserX * this.scale - scroll.x + bcr.left) ,
-                     y: (browserY * this.scale - scroll.y + bcr.top)};
-          ]]>
-        </body>
-      </method>
-
-      <constructor>
-        <![CDATA[
-          this._frameLoader = this.QueryInterface(Components.interfaces.nsIFrameLoaderOwner).frameLoader;
-          this._contentViewManager = this._frameLoader.QueryInterface(Components.interfaces.nsIContentViewManager);
-
-          let prefService = Components.classes["@mozilla.org/preferences-service;1"]
-                                              .getService(Components.interfaces.nsIPrefBranch);
-
-          this._cacheRatioWidth = Math.max(1, prefService.getIntPref("toolkit.browser.cacheRatioWidth") / 1000);
-          this._cacheRatioHeight = Math.max(1, prefService.getIntPref("toolkit.browser.cacheRatioHeight") / 1000);
-
-          if (this._contentViewPrototype)
-            this._contentViewPrototype.kDieTime = prefService.getIntPref("toolkit.browser.contentViewExpire");
-
-          this.messageManager.loadFrameScript("chrome://browser/content/bindings/browser.js", true);
-          this.messageManager.addMessageListener("DOMTitleChanged", this._messageListenerLocal);
-          this.messageManager.addMessageListener("DOMLinkAdded", this._messageListenerLocal);
-          this.messageManager.addMessageListener("pageshow", this._messageListenerLocal);
-          this.messageManager.addMessageListener("pagehide", this._messageListenerLocal);
-          this.messageManager.addMessageListener("DOMPopupBlocked", this._messageListenerLocal);
-          this.messageManager.addMessageListener("MozScrolledAreaChanged", this._messageListenerLocal);
-          this.messageManager.addMessageListener("Content:UpdateDisplayPort", this._messageListenerLocal);
-
-          this._webProgress._init();
-
-          // Remove event listeners added by toolkit <browser> binding.
-          this.removeEventListener("pageshow", this.onPageShow, true);
-          this.removeEventListener("pagehide", this.onPageHide, true);
-          this.removeEventListener("DOMPopupBlocked", this.onPopupBlocked, true);
-        ]]>
-      </constructor>
-
       <method name="updateWindowId">
          <parameter name="aNewId"/>
          <body><![CDATA[
             if (this.contentWindowId != aNewId) {
                this.contentWindowId = aNewId;
                return true;
             }
             return false;
--- a/browser/metro/base/content/browser.js
+++ b/browser/metro/base/content/browser.js
@@ -738,19 +738,19 @@ var Browser = {
     let zoomValues = ZoomManager.zoomValues;
     let i = zoomValues.indexOf(ZoomManager.snap(zoomLevel)) + (aDirection < 0 ? 1 : -1);
     if (i >= 0 && i < zoomValues.length)
       zoomLevel = zoomValues[i];
 
     zoomLevel = tab.clampZoomLevel(zoomLevel);
 
     let browserRect = browser.getBoundingClientRect();
-    let center = browser.transformClientToBrowser(browserRect.width / 2,
-                                                  browserRect.height / 2);
-    let rect = this._getZoomRectForPoint(center.x, center.y, zoomLevel);
+    let center = browser.ptClientToBrowser(browserRect.width / 2,
+                                           browserRect.height / 2);
+    let rect = this._getZoomRectForPoint(center.xPos, center.yPos, zoomLevel);
     AnimatedZoom.animateTo(rect);
   },
 
   /** Rect should be in browser coordinates. */
   _getZoomLevelForRect: function _getZoomLevelForRect(rect) {
     const margin = 15;
     return this.selectedTab.clampZoomLevel(ContentAreaObserver.width / (rect.width + margin * 2));
   },