353 lines
10 KiB
JavaScript
353 lines
10 KiB
JavaScript
/* 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();
|
|
});
|