Bug 1370278 - used `getTransformToAncestor` in Grid Inspector highlighter; r=gl draft
authorMatteo Ferretti <mferretti@mozilla.com>
Thu, 08 Jun 2017 23:11:17 +0200
changeset 591218 a972e879a498077a13ea87653bf71b558ca6a65c
parent 591217 8191dc9bb34f36730cd6ab894f7de9685680886a
child 632470 2dee2be3f072d16f237932b733af17df849865b8
push id63005
push userbmo:zer0@mozilla.com
push dateThu, 08 Jun 2017 21:13:46 +0000
reviewersgl
bugs1370278
milestone55.0a1
Bug 1370278 - used `getTransformToAncestor` in Grid Inspector highlighter; r=gl Used the new chrome-only API to obtain the transformation matrix of the current node, relative to the inspected window's root element. That also includes all the transformations from the element's ancestor; plus the method is more robust and we can simplify the current code, removing also some hack. Deleted also the test for dom_matrix_2d, since one of the method was testing now doesn't exist anymore, and the second it's just a map to native method that has its own tests on platform. MozReview-Commit-ID: 35rs34RSMYA
devtools/server/actors/highlighters/css-grid.js
devtools/shared/layout/dom-matrix-2d.js
devtools/shared/tests/mochitest/chrome.ini
devtools/shared/tests/mochitest/test_dom_matrix_2d.html
--- a/devtools/server/actors/highlighters/css-grid.js
+++ b/devtools/server/actors/highlighters/css-grid.js
@@ -12,27 +12,26 @@ const {
   createNode,
   createSVGNode,
   moveInfobar,
 } = require("./utils/markup");
 const {
   getCurrentZoom,
   getDisplayPixelRatio,
   setIgnoreLayoutChanges,
-  getNodeBounds,
   getViewportDimensions,
 } = require("devtools/shared/layout/utils");
 const {
   identity,
   apply,
   translate,
   multiply,
   scale,
+  isIdentity,
   getNodeTransformationMatrix,
-  getNodeTransformOrigin
 } = require("devtools/shared/layout/dom-matrix-2d");
 const { stringifyGridFragments } = require("devtools/server/actors/utils/css-grid-utils");
 const { LocalizationHelper } = require("devtools/shared/l10n");
 
 const LAYOUT_STRINGS_URI = "devtools/client/locales/layout.properties";
 const LAYOUT_L10N = new LocalizationHelper(LAYOUT_STRINGS_URI);
 
 const CSS_GRID_ENABLED_PREF = "layout.css.grid.enabled";
@@ -1042,51 +1041,41 @@ CssGridHighlighter.prototype = extend(Au
    *   5. Any CSS transformation applied directly to the element (only 2D
    *      transformation; the 3D transformation are flattened, see `dom-matrix-2d` module
    *      for further details.)
    *
    *  The transformations of the element's ancestors are not currently computed (see
    *  bug 1355675).
    */
   updateCurrentMatrix() {
-    let origin = getNodeTransformOrigin(this.currentNode);
-    let bounds = getNodeBounds(this.win, this.currentNode);
-    let nodeMatrix = getNodeTransformationMatrix(this.currentNode);
     let computedStyle = this.currentNode.ownerGlobal.getComputedStyle(this.currentNode);
 
     let paddingTop = parseFloat(computedStyle.paddingTop);
     let paddingLeft = parseFloat(computedStyle.paddingLeft);
     let borderTop = parseFloat(computedStyle.borderTopWidth);
     let borderLeft = parseFloat(computedStyle.borderLeftWidth);
 
-    // Subtract padding and border values to compensate for top/left being moved by
-    // padding and / or borders.
-    let ox = origin[0] - paddingLeft - borderLeft;
-    let oy = origin[1] - paddingTop - borderTop;
+    let nodeMatrix = getNodeTransformationMatrix(this.currentNode,
+      this.win.document.documentElement);
 
     let m = identity();
 
-    // First, we scale based on the display's current pixel ratio.
-    m = multiply(m, scale(getDisplayPixelRatio(this.win)));
-    // Then we translate the origin to the node's top left corner.
-    m = multiply(m, translate(bounds.p1.x, bounds.p1.y));
-    // And scale based on the current zoom factor.
-    m = multiply(m, scale(getCurrentZoom(this.win)));
-    // Then translate the origin based on the node's padding and border values.
+    // First, we scale based on the device pixel ratio.
+    m = multiply(m, scale(this.win.devicePixelRatio));
+    // Then, we apply the current node's transformation matrix, relative to the
+    // inspected window's root element, but only if it's not a identity matrix.
+    if (isIdentity(nodeMatrix)) {
+      this.hasNodeTransformations = false;
+    } else {
+      m = multiply(m, nodeMatrix);
+      this.hasNodeTransformations = true;
+    }
+
+    // Finally, we translate the origin based on the node's padding and border values.
     m = multiply(m, translate(paddingLeft + borderLeft, paddingTop + borderTop));
-    // Finally, we can apply the current node's transformation matrix, taking in account
-    // the `transform-origin` property and the node's top and left padding.
-    if (nodeMatrix) {
-      m = multiply(m, translate(ox, oy));
-      m = multiply(m, nodeMatrix);
-      m = multiply(m, translate(-ox, -oy));
-      this.hasNodeTransformations = true;
-    } else {
-      this.hasNodeTransformations = false;
-    }
 
     this.currentMatrix = m;
   },
 
   getFirstRowLinePos(fragment) {
     return fragment.rows.lines[0].start;
   },
 
--- a/devtools/shared/layout/dom-matrix-2d.js
+++ b/devtools/shared/layout/dom-matrix-2d.js
@@ -100,59 +100,44 @@ exports.multiply = multiply;
  */
 const apply = (M, P) => [
   M[0] * P[0] + M[1] * P[1] + M[2],
   M[3] * P[0] + M[4] * P[1] + M[5],
 ];
 exports.apply = apply;
 
 /**
- * Returns the transformation origin point for the given node.
+ * Returns `true` if the given matrix is a identity matrix.
  *
- * @param {DOMNode} node
- *        The node.
- * @return {Array}
- *        The transformation origin point.
+ * @param {Array} M
+ *        The matrix to check
+ * @return {Boolean}
+ *        `true` if the matrix passed is a identity matrix, `false` otherwise.
  */
-function getNodeTransformOrigin(node) {
-  let origin = node.ownerGlobal.getComputedStyle(node).transformOrigin;
-
-  return origin.split(/ /).map(parseFloat);
-}
-exports.getNodeTransformOrigin = getNodeTransformOrigin;
+const isIdentity = (M) =>
+  M[0] === 1 && M[1] === 0 && M[2] === 0 &&
+  M[3] === 0 && M[4] === 1 && M[5] === 0 &&
+  M[6] === 0 && M[7] === 0 && M[8] === 1;
+exports.isIdentity = isIdentity;
 
 /**
- * Returns the transformation matrix for the given node.
+ * Returns the transformation matrix for the given node, relative to the ancestor passed
+ * as second argument.
+ * If no ancestor is specified, it will returns the transformation matrix relative to the
+ * node's parent element.
  *
  * @param {DOMNode} node
  *        The node.
- * @return {Array}
+ * @param {DOMNode} ancestor
+ *        The ancestor of the node given.
+ ** @return {Array}
  *        The transformation matrix.
  */
-function getNodeTransformationMatrix(node) {
-  let t = node.ownerGlobal.getComputedStyle(node).transform;
-
-  if (t === "none") {
-    return null;
-  }
-
-  // We're assuming is a 2d matrix.
-  let m = t.substring(t.indexOf("(") + 1, t.length - 1).split(/,\s*/).map(Number);
-  let [a, b, c, d, e, f] = m;
-
-  // If the length is 16, it's a 3d matrix: in that case we'll extrapolate only the values
-  // we need for the 2D transformation; this cover the scenario where 3D CSS properties
-  // are used only for HW acceleration on 2D transformation.
-  if (m.length === 16) {
-    c = m[4];
-    d = m[5];
-    e = m[12];
-    f = m[13];
-  }
+function getNodeTransformationMatrix(node, ancestor = node.parentElement) {
+  let { a, b, c, d, e, f } = node.getTransformToAncestor(ancestor);
 
   return [
     a, c, e,
     b, d, f,
     0, 0, 1
   ];
 }
-
 exports.getNodeTransformationMatrix = getNodeTransformationMatrix;
--- a/devtools/shared/tests/mochitest/chrome.ini
+++ b/devtools/shared/tests/mochitest/chrome.ini
@@ -1,8 +1,7 @@
 [DEFAULT]
 tags = devtools
 skip-if = os == 'android'
 
 [test_css-logic-getCssPath.html]
-[test_dom_matrix_2d.html]
 [test_eventemitter_basic.html]
 skip-if = os == 'linux' && debug # Bug 1205739
deleted file mode 100644
--- a/devtools/shared/tests/mochitest/test_dom_matrix_2d.html
+++ /dev/null
@@ -1,88 +0,0 @@
-<!DOCTYPE html>
-<!--
-  Any copyright is dedicated to the Public Domain.
-  http://creativecommons.org/publicdomain/zero/1.0/
--->
-
-<html>
-  <!--
-  https://bugzilla.mozilla.org/show_bug.cgi?id=1297072
-  -->
-  <head>
-    <meta charset="utf8">
-    <title>Testing 2d matrix utility functions for DOM</title>
-
-    <script type="application/javascript"
-            src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
-    <link rel="stylesheet" type="text/css"
-          href="chrome://mochikit/content/tests/SimpleTest/test.css">
-    <style>
-      #element {
-        position: absolute;
-        top: 20px;
-        left: 10px;
-        width: 320px;
-        height: 200px;
-        background: salmon;
-      }
-    </style>
-  </head>
-
-  <body>
-    <div id="element"></div>
-
-    <script type="application/javascript">
-      "use strict";
-
-      const { utils: Cu } = Components;
-      const { require } = Cu.import("resource://devtools/shared/Loader.jsm", {});
-      const {
-        getNodeTransformationMatrix,
-        getNodeTransformOrigin
-      } = require("devtools/shared/layout/dom-matrix-2d");
-
-      let element = document.getElementById("element");
-
-      testNodeTransformOrigin(element);
-      testNodeTransformationMatrix(element);
-
-      function testNodeTransformOrigin(node) {
-        isDeeply(getNodeTransformOrigin(node), [160, 100],
-          "Default Transform Origin is correct.");
-
-        node.style.transformOrigin = "left 10%";
-        isDeeply(getNodeTransformOrigin(node), [0, 20],
-          "Transform Origin is properly computed.");
-
-        node.style.transformOrigin = "invalid";
-        isDeeply(getNodeTransformOrigin(node), [0, 20],
-          "Invalid values are ignored.");
-
-        node.style.transformOrigin = "left 5px -3px";
-        isDeeply(getNodeTransformOrigin(node), [0, 5, -3],
-          "3D coordinates and negative numbers are properly computed.");
-      }
-
-      function testNodeTransformationMatrix(node) {
-        is(getNodeTransformationMatrix(node), null,
-          "Default Transformation Matrix is `null`");
-
-        node.style.transform = "translate(10%, 20px)";
-        isDeeply(getNodeTransformationMatrix(node), [ 1, 0, 32, 0, 1, 20, 0, 0, 1 ],
-          "Transformation Matrix properly computed with translation.");
-
-        node.style.transform = "translate(10%, 20px) scale(2)";
-        isDeeply(getNodeTransformationMatrix(node), [ 2, 0, 32, 0, 2, 20, 0, 0, 1 ],
-          "Transformation Matrix properly translated and scaled.");
-
-        node.style.transform = "scale(2) translate(10%, 20px)";
-        isDeeply(getNodeTransformationMatrix(node), [ 2, 0, 64, 0, 2, 40, 0, 0, 1 ],
-          "Transformation Matrix properly scaled and translated.");
-
-        node.style.transform = "translate3d(12px, 50%, 3em)";
-        isDeeply(getNodeTransformationMatrix(node), [ 1, 0, 12, 0, 1, 100, 0, 0, 1 ],
-          "3D Transformation Matrix are handled for 2D values.");
-      }
-    </script>
-  </body>
-</html>