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
--- 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>