Bug 774491 - Use cached x/y values and some arithmetic instead of also caching left/top values. r=mfinkle
authorMargaret Leibovic <margaret.leibovic@gmail.com>
Mon, 16 Jul 2012 15:31:00 -0700
changeset 99561 edd3c6776ae9871008da608e78713b463a07b197
parent 99560 9deb8edb5070643091049171c2188aba43b31afc
child 99562 e5b62d2de1230fec4a3527d9596bfc905ecdeac6
push id23140
push useremorley@mozilla.com
push dateWed, 18 Jul 2012 12:33:13 +0000
treeherdermozilla-central@134e66224b04 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersmfinkle
bugs774491
milestone17.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 774491 - Use cached x/y values and some arithmetic instead of also caching left/top values. r=mfinkle
mobile/android/chrome/content/browser.js
--- a/mobile/android/chrome/content/browser.js
+++ b/mobile/android/chrome/content/browser.js
@@ -1454,17 +1454,16 @@ var SelectionHandler = {
   set _end(aElement) {
     this._endRef = Cu.getWeakReference(aElement);
   },
 
   // Units in pixels
   HANDLE_WIDTH: 45,
   HANDLE_HEIGHT: 66,
   HANDLE_PADDING: 20,
-  HANDLE_HORIZONTAL_OFFSET: 5,
 
   init: function sh_init() {
     Services.obs.addObserver(this, "Gesture:SingleTap", false);
     Services.obs.addObserver(this, "Window:Resize", false);
     Services.obs.addObserver(this, "Tab:Selected", false);
     Services.obs.addObserver(this, "after-viewport-change", false);
   },
 
@@ -1492,16 +1491,17 @@ var SelectionHandler = {
         this.endSelection();
         break;
       }
       case "after-viewport-change": {
         let zoom = BrowserApp.selectedTab.getViewport().zoom;
         if (zoom != this._viewOffset.zoom) {
           this._viewOffset.zoom = zoom;
           this.updateCacheForSelection();
+          this.updateViewOffsetScroll();
           this.positionHandles(true);
         }
         break;
       }
     }
   },
 
   notifySelectionChanged: function sh_notifySelectionChanged(aDoc, aSel, aReason) {
@@ -1623,27 +1623,27 @@ var SelectionHandler = {
         });
         break;
       }
     }
   },
 
   // aX/aY are in top-level window browser coordinates
   moveSelection: function sh_moveSelection(aIsStartHandle, aX, aY) {
-    // Update the handle position as it's dragged
-    let leftTop = "left:" + (aX + this._viewOffset.scrollX - this._viewOffset.left) + "px;" +
-                  "top:" + (aY + this._viewOffset.scrollY - this._viewOffset.top) + "px;";
+    // Update the handle position as it's dragged. aX/aY correspond to the left/top of
+    // the handle elements, but the cached x/y correspond to the corners of the selection
+    // area, so we need to adjust the points accordingly.
     if (aIsStartHandle) {
-      this._start.style.cssText = this._start.style.cssText + leftTop;
-      this.cache.start.left = aX;
-      this.cache.start.top = aY;
+      this.cache.start.x = aX + this.HANDLE_PADDING + this.HANDLE_WIDTH / this._viewOffset.zoom;
+      this.cache.start.y = aY;
+      this.positionStartHandle();
     } else {
-      this._end.style.cssText = this._end.style.cssText + leftTop;
-      this.cache.end.left = aX;
-      this.cache.end.top = aY;
+      this.cache.end.x = aX + this.HANDLE_PADDING;
+      this.cache.end.y = aY;
+      this.positionEndHandle();
     }
 
     let cwu = this._view.QueryInterface(Ci.nsIInterfaceRequestor).getInterface(Ci.nsIDOMWindowUtils);
 
     // The handles work the same on both LTR and RTL pages, but the underlying selection
     // works differently, so we need to reverse how we send mouse events on RTL pages.
     if (this._isRTL) {
       // Position the caret at the end handle using a fake mouse click
@@ -1670,42 +1670,39 @@ var SelectionHandler = {
       let oldEnd = this._end;
 
       oldStart.setAttribute("anonid", "selection-handle-end");
       oldEnd.setAttribute("anonid", "selection-handle-start");
 
       this._start = oldEnd;
       this._end = oldStart;
 
-      // We need to update the cache for the new handles
-      this.updateCacheForHandleRects();
-
       // Re-send mouse events to update the selection corresponding to the new handles
       if (this._isRTL) {
         this._sendEndMouseEvents(cwu, false);
         this._sendStartMouseEvents(cwu, true);
       } else {
         this._sendStartMouseEvents(cwu, false);
         this._sendEndMouseEvents(cwu, true);
       }
     }
   },
 
   _sendStartMouseEvents: function sh_sendStartMouseEvents(cwu, useShift) {
-    let x = this.cache.start.left + this.HANDLE_PADDING + this.HANDLE_WIDTH;
+    let x = this.cache.start.x;
     // Send mouse events 1px above handle to avoid hitting the handle div (bad things happen in that case)
-    let y = this.cache.start.top - 1;
+    let y = this.cache.start.y - 1;
 
     this._sendMouseEvents(cwu, useShift, x, y);
   },
 
   _sendEndMouseEvents: function sh_sendEndMouseEvents(cwu, useShift) {
-    let x = this.cache.end.left + this.HANDLE_PADDING;
+    let x = this.cache.end.x;
     // Send mouse events 1px above handle to avoid hitting the handle div (bad things happen in that case)
-    let y = this.cache.end.top - 1;
+    let y = this.cache.end.y - 1;
 
     this._sendMouseEvents(cwu, useShift, x, y);
   },
 
   _sendMouseEvents: function sh_sendMouseEvents(cwu, useShift, x, y) {
     let element = cwu.elementFromPoint(x, y, false, true);
     // Don't send mouse events to the other handle
     if (element instanceof Ci.nsIDOMHTMLHtmlElement)
@@ -1793,75 +1790,72 @@ var SelectionHandler = {
     this.cache.start.x = start.x;
     this.cache.start.y = start.y;
     this.cache.end.x = end.x;
     this.cache.end.y = end.y;
 
     return selectionReversed;
   },
 
-  // Updates the cached client rect left/top values for the handles.
-  updateCacheForHandleRects: function sh_updateCacheForHandleRects() {
-    let start = this._start.getBoundingClientRect();
-    this.cache.start.left = start.left;
-    this.cache.start.top = start.top;
-
-    let end = this._end.getBoundingClientRect();
-    this.cache.end.left = end.left;
-    this.cache.end.top = end.top;
-  },
-
   updateViewOffsetScroll: function sh_updateViewOffsetScroll() {
     let cwu = this._view.QueryInterface(Ci.nsIInterfaceRequestor).getInterface(Ci.nsIDOMWindowUtils);
     let scrollX = {}, scrollY = {};
     cwu.getScrollXY(false, scrollX, scrollY);
 
     this._viewOffset.scrollX = scrollX.value;
     this._viewOffset.scrollY = scrollY.value;
   },
 
   // Adjust start/end positions to account for scroll, and account for the dimensions of the
   // handle elements to ensure the handles point exactly at the ends of the selection.
   positionHandles: function sh_positionHandles(adjustScale) {
-    let startCss = this._start.style.cssText;
-    let endCss = this._end.style.cssText;
-
     if (adjustScale) { 
       let heightWidth = "height:" + this.HANDLE_HEIGHT / this._viewOffset.zoom + "px;" + 
                         "width:" + this.HANDLE_WIDTH / this._viewOffset.zoom + "px;";
-
-      startCss += heightWidth;
-      endCss += heightWidth;
-    }
-
-    startCss += "left:" + (this.cache.start.x + this._viewOffset.scrollX - this._viewOffset.left -
-                           this.HANDLE_PADDING - this.HANDLE_HORIZONTAL_OFFSET - this.HANDLE_WIDTH / this._viewOffset.zoom) + "px;" +
-                "top:" + (this.cache.start.y + this._viewOffset.scrollY - this._viewOffset.top) + "px;";
-
-    endCss += "left:" + (this.cache.end.x + this._viewOffset.scrollX - this._viewOffset.left -
-                         this.HANDLE_PADDING + this.HANDLE_HORIZONTAL_OFFSET) + "px;" +
-              "top:" + (this.cache.end.y + this._viewOffset.scrollY - this._viewOffset.top) + "px;";
-
-    this._start.style.cssText = startCss;
-    this._end.style.cssText = endCss;
+      this.positionStartHandle(this._start.style.cssText + heightWidth);
+      this.positionEndHandle(this._end.style.cssText + heightWidth);
+    } else {
+      this.positionStartHandle();
+      this.positionEndHandle();
+    }
+  },
+
+  positionStartHandle: function sh_positionStartHandle(startCss) {
+    if (!startCss)
+      startCss = this._start.style.cssText;
+
+    let left = this.cache.start.x + this._viewOffset.scrollX - this._viewOffset.left -
+               this.HANDLE_PADDING - this.HANDLE_WIDTH / this._viewOffset.zoom;
+    let top = this.cache.start.y + this._viewOffset.scrollY - this._viewOffset.top;
+
+    this._start.style.cssText = startCss + "left:" + left + "px;" + "top:" + top + "px;";
+  },
+
+  positionEndHandle: function sh_positionEndHandle(endCss) {
+    if (!endCss)
+      endCss = this._end.style.cssText;
+
+    let left = this.cache.end.x + this._viewOffset.scrollX - this._viewOffset.left - this.HANDLE_PADDING;
+    let top = this.cache.end.y + this._viewOffset.scrollY - this._viewOffset.top;
+
+    this._end.style.cssText = endCss + "left:" + left + "px;" + "top:" + top + "px;";
   },
 
   showHandles: function sh_showHandles() {
     let doc = this._view.document;
     this._start = doc.getAnonymousElementByAttribute(doc.documentElement, "anonid", "selection-handle-start");
     this._end = doc.getAnonymousElementByAttribute(doc.documentElement, "anonid", "selection-handle-end");
 
     if (!this._start || !this._end) {
       Cu.reportError("SelectionHandler.showHandles: Couldn't find anonymous handle elements");
       this.endSelection();
       return;
     }
 
     this.positionHandles(true);
-    this.updateCacheForHandleRects();
 
     this._start.setAttribute("showing", "true");
     this._end.setAttribute("showing", "true");
 
     this._start.addEventListener("touchend", this, true);
     this._end.addEventListener("touchend", this, true);
 
     this._start.addEventListener("touchstart", this, true);
@@ -1903,17 +1897,17 @@ var SelectionHandler = {
         this._touchId = touch.identifier;
 
         // Keep track of what part of the handle the user touched
         let rect = aEvent.target.getBoundingClientRect();
         this._touchDelta = { x: touch.clientX - rect.left,
                              y: touch.clientY - rect.top };
 
         // Update the cache in case the page panned since last touch
-        this.updateCacheForHandleRects();
+        this.updateCacheForSelection();
         this.updateViewOffsetScroll();
 
         aEvent.target.addEventListener("touchmove", this, false);
         break;
 
       case "touchend":
         aEvent.target.removeEventListener("touchmove", this, false);