summaryrefslogtreecommitdiffstats
path: root/devtools/client/shared/test/browser_layoutHelpers_getBoxQuads1.js
diff options
context:
space:
mode:
Diffstat (limited to 'devtools/client/shared/test/browser_layoutHelpers_getBoxQuads1.js')
-rw-r--r--devtools/client/shared/test/browser_layoutHelpers_getBoxQuads1.js353
1 files changed, 353 insertions, 0 deletions
diff --git a/devtools/client/shared/test/browser_layoutHelpers_getBoxQuads1.js b/devtools/client/shared/test/browser_layoutHelpers_getBoxQuads1.js
new file mode 100644
index 0000000000..a8119df3fd
--- /dev/null
+++ b/devtools/client/shared/test/browser_layoutHelpers_getBoxQuads1.js
@@ -0,0 +1,353 @@
+/* Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/publicdomain/zero/1.0/ */
+
+// Tests getAdjustedQuads works properly in a variety of use cases including
+// iframes, scroll and zoom
+
+"use strict";
+
+const TEST_URI = TEST_URI_ROOT + "doc_layoutHelpers_getBoxQuads1.html";
+
+add_task(async function () {
+ const tab = await addTab(TEST_URI);
+
+ info("Running tests");
+
+ await SpecialPowers.spawn(tab.linkedBrowser, [], async function () {
+ // This function allows the Content Task to easily call `FullZoom` API in
+ // the parent process.
+ function sendCommand(cmd) {
+ return SpecialPowers.spawnChrome([cmd], async data => {
+ const window = this.browsingContext.topChromeWindow;
+ switch (data) {
+ case "zoom-enlarge":
+ window.FullZoom.enlarge();
+ break;
+ case "zoom-reset":
+ await window.FullZoom.reset();
+ break;
+ case "zoom-reduce":
+ window.FullZoom.reduce();
+ break;
+ }
+ });
+ }
+
+ const doc = content.document;
+
+ const { require } = ChromeUtils.importESModule(
+ "resource://devtools/shared/loader/Loader.sys.mjs"
+ );
+ const {
+ getAdjustedQuads,
+ } = require("resource://devtools/shared/layout/utils.js");
+
+ Assert.strictEqual(
+ typeof getAdjustedQuads,
+ "function",
+ "getAdjustedQuads is defined"
+ );
+
+ returnsTheRightDataStructure();
+ isEmptyForMissingNode();
+ isEmptyForHiddenNodes();
+ defaultsToBorderBoxIfNoneProvided();
+ returnsLikeGetBoxQuadsInSimpleCase();
+ takesIframesOffsetsIntoAccount();
+ takesScrollingIntoAccount();
+ await takesZoomIntoAccount();
+ returnsMultipleItemsForWrappingInlineElements();
+
+ function returnsTheRightDataStructure() {
+ info("Checks that the returned data contains bounds and 4 points");
+
+ const node = doc.querySelector("body");
+ const [res] = getAdjustedQuads(doc.defaultView, node, "content");
+
+ ok("bounds" in res, "The returned data has a bounds property");
+ ok("p1" in res, "The returned data has a p1 property");
+ ok("p2" in res, "The returned data has a p2 property");
+ ok("p3" in res, "The returned data has a p3 property");
+ ok("p4" in res, "The returned data has a p4 property");
+
+ for (const boundProp of [
+ "bottom",
+ "top",
+ "right",
+ "left",
+ "width",
+ "height",
+ "x",
+ "y",
+ ]) {
+ ok(
+ boundProp in res.bounds,
+ "The bounds has a " + boundProp + " property"
+ );
+ }
+
+ for (const point of ["p1", "p2", "p3", "p4"]) {
+ for (const pointProp of ["x", "y", "z", "w"]) {
+ ok(
+ pointProp in res[point],
+ point + " has a " + pointProp + " property"
+ );
+ }
+ }
+ }
+
+ function isEmptyForMissingNode() {
+ info("Checks that null is returned for invalid nodes");
+
+ for (const input of [null, undefined, "", 0]) {
+ is(
+ getAdjustedQuads(doc.defaultView, input).length,
+ 0,
+ "A 0-length array is returned for input " + input
+ );
+ }
+ }
+
+ function isEmptyForHiddenNodes() {
+ info("Checks that null is returned for nodes that aren't rendered");
+
+ const style = doc.querySelector("#styles");
+ is(
+ getAdjustedQuads(doc.defaultView, style).length,
+ 0,
+ "null is returned for a <style> node"
+ );
+
+ const hidden = doc.querySelector("#hidden-node");
+ is(
+ getAdjustedQuads(doc.defaultView, hidden).length,
+ 0,
+ "null is returned for a hidden node"
+ );
+ }
+
+ function defaultsToBorderBoxIfNoneProvided() {
+ info(
+ "Checks that if no boxtype is passed, then border is the default one"
+ );
+
+ const node = doc.querySelector("#simple-node-with-margin-padding-border");
+ const [withBoxType] = getAdjustedQuads(doc.defaultView, node, "border");
+ const [withoutBoxType] = getAdjustedQuads(doc.defaultView, node);
+
+ for (const boundProp of [
+ "bottom",
+ "top",
+ "right",
+ "left",
+ "width",
+ "height",
+ "x",
+ "y",
+ ]) {
+ is(
+ withBoxType.bounds[boundProp],
+ withoutBoxType.bounds[boundProp],
+ boundProp + " bound is equal with or without the border box type"
+ );
+ }
+
+ for (const point of ["p1", "p2", "p3", "p4"]) {
+ for (const pointProp of ["x", "y", "z", "w"]) {
+ is(
+ withBoxType[point][pointProp],
+ withoutBoxType[point][pointProp],
+ point +
+ "." +
+ pointProp +
+ " is equal with or without the border box type"
+ );
+ }
+ }
+ }
+
+ function returnsLikeGetBoxQuadsInSimpleCase() {
+ info(
+ "Checks that for an element in the main frame, without scroll nor zoom" +
+ "that the returned value is similar to the returned value of getBoxQuads"
+ );
+
+ const node = doc.querySelector("#simple-node-with-margin-padding-border");
+
+ for (const region of ["content", "padding", "border", "margin"]) {
+ const expected = node.getBoxQuads({
+ box: region,
+ })[0];
+ const [actual] = getAdjustedQuads(doc.defaultView, node, region);
+
+ for (const boundProp of [
+ "bottom",
+ "top",
+ "right",
+ "left",
+ "width",
+ "height",
+ "x",
+ "y",
+ ]) {
+ is(
+ actual.bounds[boundProp],
+ expected.getBounds()[boundProp],
+ boundProp +
+ " bound is equal to the one returned by getBoxQuads for " +
+ region +
+ " box"
+ );
+ }
+
+ for (const point of ["p1", "p2", "p3", "p4"]) {
+ for (const pointProp of ["x", "y", "z", "w"]) {
+ is(
+ actual[point][pointProp],
+ expected[point][pointProp],
+ point +
+ "." +
+ pointProp +
+ " is equal to the one returned by getBoxQuads for " +
+ region +
+ " box"
+ );
+ }
+ }
+ }
+ }
+
+ function takesIframesOffsetsIntoAccount() {
+ info(
+ "Checks that the quad returned for a node inside iframes that have " +
+ "margins takes those offsets into account"
+ );
+
+ const rootIframe = doc.querySelector("iframe");
+ const subIframe = rootIframe.contentDocument.querySelector("iframe");
+ const innerNode = subIframe.contentDocument.querySelector("#inner-node");
+
+ const [quad] = getAdjustedQuads(doc.defaultView, innerNode, "content");
+
+ // rootIframe margin + subIframe margin + node margin + node border + node padding
+ const p1x = 10 + 10 + 10 + 10 + 10;
+ is(quad.p1.x, p1x, "The inner node's p1 x position is correct");
+
+ // Same as p1x + the inner node width
+ const p2x = p1x + 100;
+ is(quad.p2.x, p2x, "The inner node's p2 x position is correct");
+ }
+
+ function takesScrollingIntoAccount() {
+ info(
+ "Checks that the quad returned for a node inside multiple scrolled " +
+ "containers takes the scroll values into account"
+ );
+
+ // For info, the container being tested here is absolutely positioned at 0 0
+ // to simplify asserting the coordinates
+
+ info("Scroll the container nodes down");
+ const scrolledNode = doc.querySelector("#scrolled-node");
+ scrolledNode.scrollTop = 100;
+ const subScrolledNode = doc.querySelector("#sub-scrolled-node");
+ subScrolledNode.scrollTop = 200;
+ const innerNode = doc.querySelector("#inner-scrolled-node");
+
+ let [quad] = getAdjustedQuads(doc.defaultView, innerNode, "content");
+ is(
+ quad.p1.x,
+ 0,
+ "p1.x of the scrolled node is correct after scrolling down"
+ );
+ is(
+ quad.p1.y,
+ -300,
+ "p1.y of the scrolled node is correct after scrolling down"
+ );
+
+ info("Scrolling back up");
+ scrolledNode.scrollTop = 0;
+ subScrolledNode.scrollTop = 0;
+
+ [quad] = getAdjustedQuads(doc.defaultView, innerNode, "content");
+ is(
+ quad.p1.x,
+ 0,
+ "p1.x of the scrolled node is correct after scrolling up"
+ );
+ is(
+ quad.p1.y,
+ 0,
+ "p1.y of the scrolled node is correct after scrolling up"
+ );
+ }
+
+ async function takesZoomIntoAccount() {
+ info(
+ "Checks that if the page is zoomed in/out, the quad returned is correct"
+ );
+
+ // Hard-coding coordinates in this zoom test is a bad idea as it can vary
+ // depending on the platform, so we simply test that zooming in produces a
+ // bigger quad and zooming out produces a smaller quad
+
+ const node = doc.querySelector("#simple-node-with-margin-padding-border");
+ const [defaultQuad] = getAdjustedQuads(doc.defaultView, node);
+
+ info("Zoom in");
+ await sendCommand("zoom-enlarge");
+ const [zoomedInQuad] = getAdjustedQuads(doc.defaultView, node);
+
+ Assert.greater(
+ zoomedInQuad.bounds.width,
+ defaultQuad.bounds.width,
+ "The zoomed in quad is bigger than the default one"
+ );
+ Assert.greater(
+ zoomedInQuad.bounds.height,
+ defaultQuad.bounds.height,
+ "The zoomed in quad is bigger than the default one"
+ );
+
+ info("Zoom out");
+ await sendCommand("zoom-reset");
+ await sendCommand("zoom-reduce");
+
+ const [zoomedOutQuad] = getAdjustedQuads(doc.defaultView, node);
+
+ Assert.less(
+ zoomedOutQuad.bounds.width,
+ defaultQuad.bounds.width,
+ "The zoomed out quad is smaller than the default one"
+ );
+ Assert.less(
+ zoomedOutQuad.bounds.height,
+ defaultQuad.bounds.height,
+ "The zoomed out quad is smaller than the default one"
+ );
+
+ await sendCommand("zoom-reset");
+ }
+
+ function returnsMultipleItemsForWrappingInlineElements() {
+ info(
+ "Checks that several quads are returned " +
+ "for inline elements that span line-breaks"
+ );
+
+ const node = doc.querySelector("#inline");
+ const quads = getAdjustedQuads(doc.defaultView, node, "content");
+ // At least 3 because of the 2 <br />, maybe more depending on the window size.
+ Assert.greaterOrEqual(quads.length, 3, "Multiple quads were returned");
+
+ is(
+ quads.length,
+ node.getBoxQuads().length,
+ "The same number of boxes as getBoxQuads was returned"
+ );
+ }
+ });
+
+ gBrowser.removeCurrentTab();
+});