bug 1499360: marionette: convert in-view centre point to css pixels; r=whimboo
authorAndreas Tolfsen <ato@sny.no>
Mon, 22 Oct 2018 14:21:27 +0000
changeset 442329 ae99f2ef94642b9ec79b4eb92a9a27c2fd192d39
parent 442328 62096eab37f8886dc6feeadd7c64474e30807232
child 442330 d51f52d435daa3f87b398a7ca69879da8306b54a
push id71450
push useratolfsen@mozilla.com
push dateMon, 22 Oct 2018 14:27:56 +0000
treeherderautoland@6afa28099f1e [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerswhimboo
bugs1499360
milestone64.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 1499360: marionette: convert in-view centre point to css pixels; r=whimboo When the in-view centre point contains a floating point, we need to ensure to convert it to CSS pixels before passing it on to Gecko internals such as DOMElement.elementsFromPoint and DOMWindowUtils.sendMouseEvent. For example, with a click target that is a 1x1 square, the in-view centre point prior to this patch was calculated to (0.5,0.5). elementsFromPoint will (correctly?) round this coordinate down and return the paint tree for the DOM element at (0,0) coordinates. By contrast, sendMouseEvent will click coordinates (1,1) because it rounds up. To make sure we all speak the same language internally, we round the centre point down. Differential Revision: https://phabricator.services.mozilla.com/D8880
testing/marionette/element.js
--- a/testing/marionette/element.js
+++ b/testing/marionette/element.js
@@ -1135,45 +1135,62 @@ element.isVisible = function(el, x = und
 element.isObscured = function(el) {
   let tree = element.getPointerInteractablePaintTree(el);
   return !el.contains(tree[0]);
 };
 
 // TODO(ato): Only used by deprecated action API
 // https://bugzil.la/1354578
 /**
- * Calculate the in-view centre point of the area of the given DOM client
- * rectangle that is inside the viewport.
+ * Calculates the in-view centre point of an element's client rect.
+ *
+ * The portion of an element that is said to be _in view_, is the
+ * intersection of two squares: the first square being the initial
+ * viewport, and the second a DOM element.  From this square we
+ * calculate the in-view _centre point_ and convert it into CSS pixels.
+ *
+ * Although Gecko's system internals allow click points to be
+ * given in floating point precision, the DOM operates in CSS pixels.
+ * When the in-view centre point is later used to retrieve a coordinate's
+ * paint tree, we need to ensure to operate in the same language.
+ *
+ * As a word of warning, there appears to be inconsistencies between
+ * how `DOMElement.elementsFromPoint` and `DOMWindowUtils.sendMouseEvent`
+ * internally rounds (ceils/floors) coordinates.
  *
  * @param {DOMRect} rect
  *     Element off a DOMRect sequence produced by calling
- *     <code>getClientRects</code> on an {@link Element}.
+ *     `getClientRects` on an {@link Element}.
  * @param {WindowProxy} win
  *     Current window global.
  *
  * @return {Map.<string, number>}
  *     X and Y coordinates that denotes the in-view centre point of
- *     <var>rect</var>.
+ *     `rect`.
  */
 element.getInViewCentrePoint = function(rect, win) {
-  const {max, min} = Math;
+  const {floor, max, min} = Math;
 
-  let x = {
+  // calculate the intersection of the rect that is inside the viewport
+  let visible = {
     left: max(0, min(rect.x, rect.x + rect.width)),
     right: min(win.innerWidth, max(rect.x, rect.x + rect.width)),
-  };
-  let y = {
     top: max(0, min(rect.y, rect.y + rect.height)),
     bottom: min(win.innerHeight, max(rect.y, rect.y + rect.height)),
   };
 
-  return {
-    x: (x.left + x.right) / 2,
-    y: (y.top + y.bottom) / 2,
-  };
+  // arrive at the centre point of the visible rectangle
+  let x = (visible.left + visible.right) / 2.0;
+  let y = (visible.top + visible.bottom) / 2.0;
+
+  // convert to CSS pixels, as centre point can be float
+  x = floor(x);
+  y = floor(y);
+
+  return {x, y};
 };
 
 /**
  * Produces a pointer-interactable elements tree from a given element.
  *
  * The tree is defined by the paint order found at the centre point of
  * the element's rectangle that is inside the viewport, excluding the size
  * of any rendered scrollbars.