Files
sousa-gecko/layout/base/tests/test_getBoxQuads_convertPointRectQuad.html
T
Vincent Hilla adbbe5a328 Bug 1994668 - Change iframe initialization order in some cases to prepare for sync about:blank. r=dom-core,devtools-reviewers,cookie-reviewers,layout-reviewers,emz,ochameau,smaug,bvandersloot,emilio
Bug 543435 will make about:blank load synchronously when it is the initial
navigation. Many tests currently bind iframes to the DOM before fully
initializing them, which can cause issues.

- If src is set after binding, a blank document will fully load and fire its
  load event before the intended navigation.
- If a load listener is added after binding, it will miss the about:blank load.

This patch refactors several such cases to prevent issues with bug 543435. Some
test adjustments from bug 543435 are moved here, while most occurrences were
found via an automated scan for iframes with load listeners bound before
setting src.

Differential Revision: https://phabricator.services.mozilla.com/D268843
2025-10-17 21:42:06 +00:00

718 lines
33 KiB
HTML

<!DOCTYPE HTML>
<html>
<head>
<meta charset="utf-8">
<script src="/tests/SimpleTest/SimpleTest.js"></script>
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
</head>
<body onload="startTest()">
<p id="display"></p>
<script>
// Global variables we want eval() to be able to reference from anywhere
var f1d;
var text;
var suppressedText;
var suppressedText2;
var comment;
var fragment;
var openedWindow;
var zeroPoint;
var zeroRect;
var zeroQuad;
var notInDocument = document.createElement('div');
function isEval(expr, b) {
// we ignore an insignificant discrepancy in floating-point values
var exprVal = eval(expr);
if (exprVal != b && Math.abs(exprVal - b) < 0.0001) {
ok(true, expr + " (" + exprVal + " within 0.0001 of " + b + ")");
return;
}
is(exprVal, b, expr);
}
function isApprox(a, b, msg, options) {
if (a != b && 'tolerance' in options &&
Math.abs(a - b) < options.tolerance) {
ok(true, msg + "(" + a + " within " + options.tolerance + " of " + b + ")");
return;
}
is(a, b, msg);
}
function makeQuadsExpr(fromStr, options) {
var getBoxQuadsOptionParts = [];
if ('box' in options) {
getBoxQuadsOptionParts.push("box:'" + options.box + "'");
}
if ('toStr' in options) {
getBoxQuadsOptionParts.push("relativeTo:" + options.toStr);
}
return fromStr + ".getBoxQuads({" + getBoxQuadsOptionParts.join(',') + "})";
}
function makePointExpr(fromStr, options, x, y) {
var convertPointOptionParts = [];
if ('box' in options) {
convertPointOptionParts.push("fromBox:'" + options.box + "'");
}
if ('toBox' in options) {
convertPointOptionParts.push("toBox:'" + options.toBox + "'");
}
return ('toStr' in options ? options.toStr : "document") +
".convertPointFromNode(new DOMPoint(" + x + "," + y + ")," + fromStr + ",{" +
convertPointOptionParts.join(",") + "})";
}
function checkConvertPoints(fromStr, options, x1, y1, x2, y2, x3, y3, x4, y4) {
var selfQuads = eval(fromStr).getBoxQuads(
{box:options.box == "" ? "border" : options.box,
relativeTo:eval(fromStr)});
var boxWidth = selfQuads[0].getBounds().width;
var boxHeight = selfQuads[0].getBounds().height;
var convertTopLeftPointExpr = makePointExpr(fromStr, options, 0, 0);
var topLeft = eval(convertTopLeftPointExpr);
isApprox(topLeft.x, x1, convertTopLeftPointExpr + ".x", options);
isApprox(topLeft.y, y1, convertTopLeftPointExpr + ".y", options);
var convertTopRightPointExpr = makePointExpr(fromStr, options, boxWidth, 0);
var topRight = eval(convertTopRightPointExpr);
isApprox(topRight.x, x2, convertTopRightPointExpr + ".x", options);
isApprox(topRight.y, y2, convertTopRightPointExpr + ".y", options);
var convertBottomRightPointExpr = makePointExpr(fromStr, options, boxWidth, boxHeight);
var bottomRight = eval(convertBottomRightPointExpr);
isApprox(bottomRight.x, x3, convertBottomRightPointExpr + ".x", options);
isApprox(bottomRight.y, y3, convertBottomRightPointExpr + ".y", options);
var convertBottomLeftPointExpr = makePointExpr(fromStr, options, 0, boxHeight);
var bottomLeft = eval(convertBottomLeftPointExpr);
isApprox(bottomLeft.x, x4, convertBottomLeftPointExpr + ".x", options);
isApprox(bottomLeft.y, y4, convertBottomLeftPointExpr + ".y", options);
}
function checkConvertRect(fromStr, options, x1, y1, x2, y2, x3, y3, x4, y4) {
var selfQuads = eval(fromStr).getBoxQuads(
{box:options.box == "" ? "border" : options.box,
relativeTo:eval(fromStr)});
var boxWidth = selfQuads[0].getBounds().width;
var boxHeight = selfQuads[0].getBounds().height;
var convertPointOptionParts = [];
if ('box' in options) {
convertPointOptionParts.push("fromBox:'" + options.box + "'");
}
if ('toBox' in options) {
convertPointOptionParts.push("toBox:'" + options.toBox + "'");
}
var convertRectExpr = ('toStr' in options ? options.toStr : "document") +
".convertRectFromNode(new DOMRect(0,0," + boxWidth + "," + boxHeight + ")," +
fromStr + ",{" + convertPointOptionParts.join(",") + "})";
var quad = eval(convertRectExpr);
isApprox(quad.p1.x, x1, convertRectExpr + ".p1.x", options);
isApprox(quad.p1.y, y1, convertRectExpr + ".p1.y", options);
isApprox(quad.p2.x, x2, convertRectExpr + ".p2.x", options);
isApprox(quad.p2.y, y2, convertRectExpr + ".p2.y", options);
isApprox(quad.p3.x, x3, convertRectExpr + ".p3.x", options);
isApprox(quad.p3.y, y3, convertRectExpr + ".p3.y", options);
isApprox(quad.p4.x, x4, convertRectExpr + ".p4.x", options);
isApprox(quad.p4.y, y4, convertRectExpr + ".p4.y", options);
}
function checkConvertQuad(fromStr, options, x1, y1, x2, y2, x3, y3, x4, y4) {
var selfQuads = eval(fromStr).getBoxQuads(
{box:options.box == "" ? "border" : options.box,
relativeTo:eval(fromStr)});
var boxWidth = selfQuads[0].getBounds().width;
var boxHeight = selfQuads[0].getBounds().height;
var convertPointOptionParts = [];
if ('box' in options) {
convertPointOptionParts.push("fromBox:'" + options.box + "'");
}
if ('toBox' in options) {
convertPointOptionParts.push("toBox:'" + options.toBox + "'");
}
var convertQuadExpr = ('toStr' in options ? options.toStr : "document") +
".convertQuadFromNode(new DOMQuad(new DOMRect(0,0," + boxWidth + "," + boxHeight + "))," +
fromStr + ",{" + convertPointOptionParts.join(",") + "})";
var quad = eval(convertQuadExpr);
isApprox(quad.p1.x, x1, convertQuadExpr + ".p1.x", options);
isApprox(quad.p1.y, y1, convertQuadExpr + ".p1.y", options);
isApprox(quad.p2.x, x2, convertQuadExpr + ".p2.x", options);
isApprox(quad.p2.y, y2, convertQuadExpr + ".p2.y", options);
isApprox(quad.p3.x, x3, convertQuadExpr + ".p3.x", options);
isApprox(quad.p3.y, y3, convertQuadExpr + ".p3.y", options);
isApprox(quad.p4.x, x4, convertQuadExpr + ".p4.x", options);
isApprox(quad.p4.y, y4, convertQuadExpr + ".p4.y", options);
}
function checkQuadIsRect(fromStr, options, x, y, w, h) {
var quadsExpr = makeQuadsExpr(fromStr, options);
var quads = eval(quadsExpr);
is(quads.length, 1, quadsExpr + " checking quad count");
var q = quads[0];
isApprox(q.p1.x, x, quadsExpr + " checking quad.p1.x", options);
isApprox(q.p1.y, y, quadsExpr + " checking quad.p1.y", options);
isApprox(q.p2.x, x + w, quadsExpr + " checking quad.p2.x", options);
isApprox(q.p2.y, y, quadsExpr + " checking quad.p2.y", options);
isApprox(q.p3.x, x + w, quadsExpr + " checking quad.p3.x", options);
isApprox(q.p3.y, y + h, quadsExpr + " checking quad.p3.y", options);
isApprox(q.p4.x, x, quadsExpr + " checking quad.p4.x", options);
isApprox(q.p4.y, y + h, quadsExpr + " checking quad.p4.y", options);
isApprox(q.getBounds().left, x, quadsExpr + " checking quad.getBounds().left", options);
isApprox(q.getBounds().top, y, quadsExpr + " checking quad.getBounds().top", options);
isApprox(q.getBounds().width, w, quadsExpr + " checking quad.getBounds().width", options);
isApprox(q.getBounds().height, h, quadsExpr + " checking quad.getBounds().height", options);
checkConvertPoints(fromStr, options, x, y, x + w, y, x + w, y + h, x, y + h);
checkConvertRect(fromStr, options, x, y, x + w, y, x + w, y + h, x, y + h);
checkConvertQuad(fromStr, options, x, y, x + w, y, x + w, y + h, x, y + h);
}
function checkQuadIsQuad(fromStr, options, x1, y1, x2, y2, x3, y3, x4, y4) {
var quadsExpr = makeQuadsExpr(fromStr, options);
var quads = eval(quadsExpr);
is(quads.length, 1, quadsExpr + " checking quad count");
var q = quads[0];
isApprox(q.p1.x, x1, quadsExpr + " checking quad.p1.x", options);
isApprox(q.p1.y, y1, quadsExpr + " checking quad.p1.y", options);
isApprox(q.p2.x, x2, quadsExpr + " checking quad.p2.x", options);
isApprox(q.p2.y, y2, quadsExpr + " checking quad.p2.y", options);
isApprox(q.p3.x, x3, quadsExpr + " checking quad.p3.x", options);
isApprox(q.p3.y, y3, quadsExpr + " checking quad.p3.y", options);
isApprox(q.p4.x, x4, quadsExpr + " checking quad.p4.x", options);
isApprox(q.p4.y, y4, quadsExpr + " checking quad.p4.y", options);
isApprox(q.getBounds().left, Math.min(x1,x2,x3,x4), quadsExpr + " checking quad.getBounds().left", options);
isApprox(q.getBounds().top, Math.min(y1,y2,y3,y4), quadsExpr + " checking quad.getBounds().top", options);
isApprox(q.getBounds().right, Math.max(x1,x2,x3,x4), quadsExpr + " checking quad.getBounds().right", options);
isApprox(q.getBounds().bottom, Math.max(y1,y2,y3,y4), quadsExpr + " checking quad.getBounds().bottom", options);
checkConvertPoints(fromStr, options, x1, y1, x2, y2, x3, y3, x4, y4);
checkConvertRect(fromStr, options, x1, y1, x2, y2, x3, y3, x4, y4);
checkConvertQuad(fromStr, options, x1, y1, x2, y2, x3, y3, x4, y4);
}
function checkException(expr, name) {
try {
eval(expr);
ok(false, "Exception should have been thrown for " + expr);
} catch (ex) {
is(ex.name, name, "Checking exception type for " + expr);
}
}
function checkNotFound(fromStr, toStr, x1, y1, x2, y2) {
var convertPointExpr = toStr + ".convertPointFromNode(new DOMPoint(" + x1 +
"," + y1 + ")," + fromStr + ")";
checkException(convertPointExpr, "NotFoundError");
var convertRectExpr = toStr + ".convertRectFromNode(new DOMRect(" + x1 +
"," + y1 + "," + x2 + "," + y2 + ")," + fromStr + ")";
checkException(convertRectExpr, "NotFoundError");
var convertQuadExpr = toStr + ".convertQuadFromNode(new DOMQuad(new DOMRect(" + x1 +
"," + y1 + "," + x2 + "," + y2 + "))," + fromStr + ")";
checkException(convertQuadExpr, "NotFoundError");
}
</script>
<style>
em {
display:inline-block; height:10px; background:gray;
}
</style>
<div id="dContainer"
style="padding:13px 14px 15px 16px;
border-width:17px 18px 19px 20px; border-style:solid; border-color:yellow;
margin:21px 22px 23px 24px;">
<div id="d"
style="width:120px; height:90px; padding:1px 2px 3px 4px;
border-width:5px 6px 7px 8px; border-style:solid; border-color:yellow;
margin:9px 10px 11px 12px; background:blue;">
</div>
</div>
<div id="dUnrelated" style="width:50px; height:50px;"></div>
<iframe id="f1" style="width:50px; height:50px; border:0; background:lime;"
src="file_getBoxQuads_convertPointRectQuad_frame1.html">
</iframe>
<!--
It matters that the first part of this span is on the same line as the above <iframe>!
That ensures the first quad's X position is not equal to the anonymous block's X position.
-->
<span id="ibSplit"
><em id="ibSplitPart1" style="width:100px;"></em
><div style="width:110px; height:20px; background:black"></div
><em style="width:130px;"></em></span>
<table cellspacing="0" id="table" style="border:0; margin:8px; padding:0; background:orange">
<tbody style="padding:0; margin:0; border:0; background:blue">
<tr style="height:50px; padding:0; margin:0; border:0">
<td style="border:0; margin:0; padding:0">Cell</td>
</tr>
</tbody>
<caption style="height:40px; background:yellow">Caption</caption>
</table>
<div style="height:80px; column-count:2; column-fill:auto; border:2px solid black;">
<div style="height:20px;"></div>
<div id="colSplit" style="height:80px; background:blue; border:10px solid red; border-bottom-width:15px"></div>
</div>
<div style="width:200px; border:2px solid black;"
><em style="width:150px;"></em
><span id="inlineSplit" style="background:pink; border:10px solid red; border-right-width:15px"
><em style="width:20px; background:green"></em><em style="width:60px"></em
></span
></div>
<div style="width:200px; border:2px solid black;"
><em style="width:150px;"></em
><span id="textContainer">T
TextTextTextTextTextTextTextTextTextTextTextTextTextTextTextTextTextTextTextTextTextTextTextText</span
></div>
<div id="suppressedTextContainer"> </div>
<div id="suppressedTextContainer2"> </div>
<div id="commentContainer"><!-- COMMENT --></div>
<div id="displayNone" style="display:none"></div>
<div id="overflowHidden"
style="overflow:hidden; width:120px; height:90px; padding:1px 2px 3px 4px;
border-width:5px 6px 7px 8px; border-style:solid; border-color:yellow;
margin:9px 10px 11px 12px; background:blue;">
<div style="height:400px; background:lime;"></div>
</div>
<div id="overflowScroll"
style="overflow:scroll; width:120px; height:90px; padding:1px 2px 3px 4px;
border-width:5px 6px 7px 8px; border-style:solid; border-color:yellow;
margin:9px 10px 11px 12px; background:blue; background-clip:content-box;">
<div id="overflowScrollChild" style="height:400px;"></div>
</div>
<div id="scaleTransformContainer" style="width:200px; height:200px;">
<div id="scaleTransform"
style="transform:scale(2); transform-origin:top left; width:70px; height:80px; background:yellow"></div>
</div>
<div id="translateTransformContainer" style="width:200px; height:200px;">
<div id="translateTransform"
style="transform:translate(30px,40px); width:70px; height:80px; background:yellow"></div>
</div>
<div id="rotateTransformContainer" style="width:200px; height:200px;">
<div id="rotateTransform"
style="transform:rotate(90deg); width:70px; height:80px; background:yellow"></div>
</div>
<div id="flipTransformContainer" style="width:200px; height:200px;">
<div id="flipTransform"
style="transform:scaleY(-1); width:70px; height:80px; background:yellow"></div>
</div>
<div id="rot45TransformContainer" style="width:200px; height:200px;">
<div id="rot45Transform"
style="transform:rotate(45deg); width:100px; height:100px; background:yellow"></div>
</div>
<div id="singularTransform" style="transform:scale(0); width:200px; height:200px;">
<div id="singularTransformChild1" style="height:50px;"></div>
<div id="singularTransformChild2" style="height:50px;"></div>
</div>
<div id="threeDTransformContainer" style="perspective:600px; width:200px; height:200px">
<div id="threeDTransform" style="transform:rotateY(70deg); background:yellow; height:100px; perspective:600px">
<div id="threeDTransformChild" style="transform:rotateY(-70deg); background:blue; height:50px;"></div>
</div>
</div>
<div id="preserve3DTransformContainer" style="perspective:600px; width:200px; height:200px">
<div id="preserve3DTransform" style="transform:rotateY(70deg); transform-style:preserve-3d; background:yellow; height:100px;">
<div id="preserve3DTransformChild" style="transform:rotateY(-70deg); background:blue; height:50px;"></div>
</div>
</div>
<div id="svgContainer">
<svg id="svg" style="width:200px; height:200px; background:lightgray; border:7px solid blue; padding:4px">
<circle id="circle" cx="50" cy="50" r="20" fill="red" style="margin:20px; padding:10px; border:15px solid black"></circle>
<g transform="scale(2)">
<foreignObject x="50" y="20">
<div id="foreign" style="width:100px; height:60px; background:purple"></div>
</foreignObject>
</g>
</svg>
</div>
<script>
SimpleTest.waitForExplicitFinish();
window.scrollTo(0,0);
function startTest() {
SpecialPowers.pushPrefEnv({"set": [["layout.css.getBoxQuads.enabled", true],
["layout.css.convertFromNode.enabled", true]]}, grabFeatures);
}
// This is a bit of a hack but it works. Our Window object was set up while
// the prefs might have been false so it may not have the features we're
// testing. Create an <iframe> whose Window is initialized while the prefs are
// true, and we can steal the features from that Window.
// When these prefs are enabled on all builds by default, we can skip this step.
function grabFeatures() {
var x = document.createElement('iframe');
x.src = "about:blank";
function setupFeatures(w) {
for (var name of ["getBoxQuads", "convertQuadFromNode", "convertRectFromNode", "convertPointFromNode"]) {
w.Text.prototype[name] = x.contentWindow.Text.prototype[name];
w.Element.prototype[name] = x.contentWindow.Element.prototype[name];
w.Document.prototype[name] = x.contentWindow.Document.prototype[name];
}
for (var name of ["DOMPoint", "DOMQuad"]) {
w[name] = x.contentWindow[name];
}
}
x.onload = function() {
setupFeatures(window);
setupFeatures(f1.contentWindow);
runTest();
};
document.body.appendChild(x);
}
function runTest() {
zeroPoint = new DOMPoint(0,0);
zeroRect = new DOMRect(0,0,0,0);
zeroQuad = new DOMQuad(zeroRect);
// Setup globals
f1d = f1.contentWindow.f1d;
text = textContainer.firstChild;
suppressedText = suppressedTextContainer.firstChild;
suppressedText2 = suppressedTextContainer2.firstChild;
comment = commentContainer.firstChild;
fragment = document.createDocumentFragment();
// Test basic BoxQuadOptions.box.
var dX = d.getBoundingClientRect().left;
var dY = d.getBoundingClientRect().top;
var dW = d.getBoundingClientRect().width;
var dH = d.getBoundingClientRect().height;
checkQuadIsRect("d", {box:"content"},
dX + 4 + 8, dY + 1 + 5, 120, 90);
checkQuadIsRect("d", {box:"padding"},
dX + 8, dY + 5, 120 + 2 + 4, 90 + 1 + 3);
checkQuadIsRect("d", {box:"border"},
dX, dY, dW, dH);
checkQuadIsRect("d", {},
dX, dY, 120 + 2 + 4 + 6 + 8, 90 + 1 + 3 + 5 + 7);
checkQuadIsRect("d", {box:"margin"},
dX - 12, dY - 9, 120 + 2 + 4 + 6 + 8 + 10 + 12, 90 + 1 + 3 + 5 + 7 + 9 + 11);
// Test basic BoxQuadOptions.relativeTo
checkQuadIsRect("d", {toStr:"dContainer"},
12 + 16 + 20, 9 + 13 + 17, dW, dH);
// Test BoxQuadOptions.relativeTo relative to this document
checkQuadIsRect("d", {toStr:"document"},
dX, dY, dW, dH);
// Test BoxQuadOptions.relativeTo relative to a non-ancestor.
var dUnrelatedX = dUnrelated.getBoundingClientRect().left;
var dUnrelatedY = dUnrelated.getBoundingClientRect().top;
checkQuadIsRect("d", {toStr:"dUnrelated"},
dX - dUnrelatedX, dY - dUnrelatedY, dW, dH);
// Test BoxQuadOptions.relativeTo relative to an element in a different document (and the document)
var f1X = f1.getBoundingClientRect().left;
var f1Y = f1.getBoundingClientRect().top;
checkQuadIsRect("d", {toStr:"f1.contentWindow.f1d"},
dX - (f1X + 14), dY - (f1Y + 15), dW, dH);
checkQuadIsRect("d", {toStr:"f1.contentDocument"},
dX - f1X, dY - f1Y, dW, dH);
// Test one document relative to another
checkQuadIsRect("f1.contentDocument", {toStr:"document"},
f1X, f1Y, 50, 50);
// The box type is irrelevant for a document
checkQuadIsRect("f1.contentDocument", {toStr:"document",box:"content"},
f1X, f1Y, 50, 50);
checkQuadIsRect("f1.contentDocument", {toStr:"document",box:"margin"},
f1X, f1Y, 50, 50);
checkQuadIsRect("f1.contentDocument", {toStr:"document",box:"padding"},
f1X, f1Y, 50, 50);
// Test that anonymous boxes are correctly ignored when building quads.
var ibSplitPart1X = ibSplitPart1.getBoundingClientRect().left;
var ibSplitY = ibSplit.getBoundingClientRect().top;
isEval("ibSplit.getBoxQuads().length", 3);
isEval("ibSplit.getBoxQuads()[0].getBounds().left", ibSplitPart1X);
isEval("ibSplit.getBoxQuads()[0].getBounds().width", 100);
isEval("ibSplit.getBoxQuads()[1].getBounds().width", 110);
isEval("ibSplit.getBoxQuads()[2].getBounds().width", 130);
isEval("table.getBoxQuads().length", 2);
isEval("table.getBoxQuads()[0].getBounds().height", 50);
isEval("table.getBoxQuads()[1].getBounds().height", 40);
// Test that we skip anonymous boxes when finding the right box to be relative to.
checkQuadIsRect("d", {toStr:"ibSplit", tolerance:0.0001},
dX - ibSplitPart1X, dY - ibSplitY, dW, dH);
var tableX = table.getClientRects()[0].left;
var tableY = table.getClientRects()[0].top;
checkQuadIsRect("d", {toStr:"table"},
dX - tableX, dY - tableY, dW, dH);
isEval("ibSplit.convertPointFromNode(zeroPoint,d).x", dX - ibSplitPart1X);
isEval("table.convertPointFromNode(zeroPoint,d).x", dX - table.getClientRects()[0].left);
// Test boxes generated by block splitting. Check for borders being placed correctly.
var colSplitY = colSplit.getClientRects()[0].top;
isEval("colSplit.getBoxQuads().length", 2);
isEval("colSplit.getBoxQuads()[0].getBounds().top", colSplitY);
isEval("colSplit.getBoxQuads()[0].getBounds().height", 60);
isEval("colSplit.getBoxQuads()[1].getBounds().top", colSplitY - 20);
isEval("colSplit.getBoxQuads()[1].getBounds().height", 45);
isEval("colSplit.getBoxQuads({box:'content'}).length", 2);
// The first box for the block has the top border; the second box has the bottom border.
isEval("colSplit.getBoxQuads({box:'content'})[0].getBounds().top", colSplitY + 10);
isEval("colSplit.getBoxQuads({box:'content'})[0].getBounds().height", 50);
isEval("colSplit.getBoxQuads({box:'content'})[1].getBounds().top", colSplitY - 20);
isEval("colSplit.getBoxQuads({box:'content'})[1].getBounds().height", 30);
var inlineSplitX = inlineSplit.getClientRects()[0].left;
isEval("inlineSplit.getBoxQuads().length", 2);
isEval("inlineSplit.getBoxQuads()[0].getBounds().left", inlineSplitX);
isEval("inlineSplit.getBoxQuads()[0].getBounds().width", 30);
isEval("inlineSplit.getBoxQuads()[1].getBounds().left", inlineSplitX - 150);
isEval("inlineSplit.getBoxQuads()[1].getBounds().width", 75);
isEval("inlineSplit.getBoxQuads({box:'content'}).length", 2);
// The first box for the inline has the left border; the second box has the right border.
isEval("inlineSplit.getBoxQuads({box:'content'})[0].getBounds().left", inlineSplitX + 10);
isEval("inlineSplit.getBoxQuads({box:'content'})[0].getBounds().width", 20);
isEval("inlineSplit.getBoxQuads({box:'content'})[1].getBounds().left", inlineSplitX - 150);
isEval("inlineSplit.getBoxQuads({box:'content'})[1].getBounds().width", 60);
var textX = textContainer.getClientRects()[0].left;
isEval("text.getBoxQuads().length", 2);
isEval("text.getBoxQuads()[0].getBounds().left", textX);
isEval("text.getBoxQuads()[1].getBounds().left", textX - 150);
// Box types are irrelevant for text
isEval("text.getBoxQuads({box:'content'}).length", 2);
isEval("text.getBoxQuads({box:'content'})[0].getBounds().left", textX);
isEval("text.getBoxQuads({box:'content'})[1].getBounds().left", textX - 150);
isEval("text.getBoxQuads({box:'padding'}).length", 2);
isEval("text.getBoxQuads({box:'padding'})[0].getBounds().left", textX);
isEval("text.getBoxQuads({box:'padding'})[1].getBounds().left", textX - 150);
isEval("text.getBoxQuads({box:'margin'}).length", 2);
isEval("text.getBoxQuads({box:'margin'})[0].getBounds().left", textX);
isEval("text.getBoxQuads({box:'margin'})[1].getBounds().left", textX - 150);
// Test table margins
isEval("table.getBoxQuads({box:'margin'}).length", 1);
isEval("table.getBoxQuads({box:'margin'})[0].getBounds().height", 106);
// Check that a text node whose layout might have been optimized away gives
// correct results.
var suppressedTextContainerX = suppressedTextContainer.getBoundingClientRect().left;
isEval("suppressedText.getBoxQuads().length", 1);
isEval("suppressedText.getBoxQuads()[0].getBounds().left", suppressedTextContainerX);
isEval("suppressedText.getBoxQuads()[0].getBounds().width", 0);
var suppressedTextContainer2X = suppressedTextContainer2.getBoundingClientRect().left;
isEval("document.convertPointFromNode(zeroPoint,suppressedText2).x",
suppressedTextContainer2X);
checkException("comment.getBoxQuads()", "TypeError");
checkException("d.getBoxQuads({relativeTo:comment})", "TypeError");
checkException("comment.convertPointFromNode(zeroPoint,document)", "TypeError");
checkException("document.convertPointFromNode(zeroPoint,comment)", "TypeError");
checkException("comment.convertRectFromNode(zeroRect,document)", "TypeError");
checkException("document.convertRectFromNode(zeroRect,comment)", "TypeError");
checkException("comment.convertQuadFromNode(zeroQuad,document)", "TypeError");
checkException("document.convertQuadFromNode(zeroQuad,comment)", "TypeError");
checkException("fragment.getBoxQuads()", "TypeError");
checkException("d.getBoxQuads({relativeTo:fragment})", "TypeError");
checkException("fragment.convertPointFromNode(zeroPoint,document)", "TypeError");
checkException("document.convertPointFromNode(zeroPoint,fragment)", "TypeError");
checkException("fragment.convertRectFromNode(zeroRect,document)", "TypeError");
checkException("document.convertRectFromNode(zeroRect,fragment)", "TypeError");
checkException("fragment.convertQuadFromNode(zeroQuad,document)", "TypeError");
checkException("document.convertQuadFromNode(zeroQuad,fragment)", "TypeError");
isEval("displayNone.getBoxQuads().length", 0);
isEval("notInDocument.getBoxQuads().length", 0);
checkNotFound("displayNone", "document", 1, 2, 3, 4);
checkNotFound("notInDocument", "document", 1, 2, 3, 4);
checkNotFound("document", "displayNone", 1, 2, 3, 4);
checkNotFound("document", "notInDocument", 1, 2, 3, 4);
// Test an overflow:hidden version of d. overflow:hidden should not affect
// the quads, basically.
var oHX = overflowHidden.getBoundingClientRect().left;
var oHY = overflowHidden.getBoundingClientRect().top;
checkQuadIsRect("overflowHidden", {box:"content"},
oHX + 4 + 8, oHY + 1 + 5, 120, 90);
checkQuadIsRect("overflowHidden", {box:"padding"},
oHX + 8, oHY + 5, 120 + 2 + 4, 90 + 1 + 3);
checkQuadIsRect("overflowHidden", {box:"border"},
oHX, oHY, 120 + 2 + 4 + 6 + 8, 90 + 1 + 3 + 5 + 7);
checkQuadIsRect("overflowHidden", {},
oHX, oHY, 120 + 2 + 4 + 6 + 8, 90 + 1 + 3 + 5 + 7);
checkQuadIsRect("overflowHidden", {box:"margin"},
oHX - 12, oHY - 9, 120 + 2 + 4 + 6 + 8 + 10 + 12, 90 + 1 + 3 + 5 + 7 + 9 + 11);
// Test an overflow:scroll version of d. I assume that boxes aren't affected
// by the scrollbar although it's not clear that this is correct.
var oSX = overflowScroll.getBoundingClientRect().left;
var oSY = overflowScroll.getBoundingClientRect().top;
checkQuadIsRect("overflowScroll", {box:"content"},
oSX + 4 + 8, oSY + 1 + 5, 120, 90);
checkQuadIsRect("overflowScroll", {box:"padding"},
oSX + 8, oSY + 5, 120 + 2 + 4, 90 + 1 + 3);
checkQuadIsRect("overflowScroll", {box:"border"},
oSX, oSY, 120 + 2 + 4 + 6 + 8, 90 + 1 + 3 + 5 + 7);
checkQuadIsRect("overflowScroll", {},
oSX, oSY, 120 + 2 + 4 + 6 + 8, 90 + 1 + 3 + 5 + 7);
checkQuadIsRect("overflowScroll", {box:"margin"},
oSX - 12, oSY - 9, 120 + 2 + 4 + 6 + 8 + 10 + 12, 90 + 1 + 3 + 5 + 7 + 9 + 11);
// Test simple 2D transforms.
var stcX = scaleTransformContainer.getBoundingClientRect().left;
var stcY = scaleTransformContainer.getBoundingClientRect().top;
checkQuadIsRect("scaleTransform", {},
stcX, stcY, 140, 160);
var ttcX = translateTransformContainer.getBoundingClientRect().left;
var ttcY = translateTransformContainer.getBoundingClientRect().top;
checkQuadIsRect("translateTransform", {},
ttcX + 30, ttcY + 40, 70, 80);
// Test mapping into a transformed element.
checkQuadIsRect("scaleTransform", {toStr:"translateTransform"},
stcX - (ttcX + 30), stcY - (ttcY + 40), 140, 160);
// Test 90 degree rotation.
var rotatetcX = rotateTransformContainer.getBoundingClientRect().left;
var rotatetcY = rotateTransformContainer.getBoundingClientRect().top;
checkQuadIsQuad("rotateTransform", {},
rotatetcX + 75, rotatetcY + 5,
rotatetcX + 75, rotatetcY + 75,
rotatetcX - 5, rotatetcY + 75,
rotatetcX - 5, rotatetcY + 5);
// Test vertical flip.
var fliptcX = flipTransformContainer.getBoundingClientRect().left;
var fliptcY = flipTransformContainer.getBoundingClientRect().top;
checkQuadIsQuad("flipTransform", {},
fliptcX, fliptcY + 80,
fliptcX + 70, fliptcY + 80,
fliptcX + 70, fliptcY,
fliptcX, fliptcY);
// Test non-90deg rotation.
var rot45tcX = rot45TransformContainer.getBoundingClientRect().left;
var rot45tcY = rot45TransformContainer.getBoundingClientRect().top;
var halfDiagonal = 100/Math.sqrt(2);
checkQuadIsQuad("rot45Transform", {tolerance:0.01},
rot45tcX + 50, rot45tcY + 50 - halfDiagonal,
rot45tcX + 50 + halfDiagonal, rot45tcY + 50,
rot45tcX + 50, rot45tcY + 50 + halfDiagonal,
rot45tcX + 50 - halfDiagonal, rot45tcY + 50);
// Test singular transforms.
var singularTransformX = singularTransform.getBoundingClientRect().left;
var singularTransformY = singularTransform.getBoundingClientRect().top;
// They map everything to a point.
checkQuadIsRect("singularTransform", {},
singularTransformX, singularTransformY, 0, 0);
checkQuadIsRect("singularTransformChild2", {},
singularTransformX, singularTransformY, 0, 0);
// Mapping into an element with a singular transform from outside sets
// everything to zero.
checkQuadIsRect("d", {toStr:"singularTransform"},
0, 0, 0, 0);
// But mappings within a subtree of an element with a singular transform work.
checkQuadIsRect("singularTransformChild2", {toStr:"singularTransformChild1"},
0, 50, 200, 50);
// Test 3D transforms.
var t3tcX = threeDTransformContainer.getBoundingClientRect().left;
var t3tcY = threeDTransformContainer.getBoundingClientRect().top;
checkQuadIsQuad("threeDTransform", {tolerance:0.01},
t3tcX + 59.446714, t3tcY - 18.569847,
t3tcX + 129.570778, t3tcY + 13.540874,
t3tcX + 129.570778, t3tcY + 100,
t3tcX + 59.446714, t3tcY + 100);
// Test nested 3D transforms (without preserve-3d).
checkQuadIsQuad("threeDTransformChild", {tolerance:0.01},
t3tcX + 89.395061, t3tcY + 2.243033,
t3tcX + 113.041727, t3tcY - 2.758530,
t3tcX + 113.041727, t3tcY + 52.985921,
t3tcX + 89.395061, t3tcY + 47.571899);
// Test preserve-3D.
var p3dtcX = preserve3DTransformContainer.getBoundingClientRect().left;
var p3dtcY = preserve3DTransformContainer.getBoundingClientRect().top;
checkQuadIsRect("preserve3DTransformChild", {tolerance:0.01},
p3dtcX, p3dtcY, 200, 50,
{tolerance:0.0001});
// Test mapping back into preserve-3D.
checkQuadIsRect("d", {toStr:"preserve3DTransformChild",tolerance:0.01},
dX - p3dtcX, dY - p3dtcY, dW, dH);
// Test SVG.
var svgContainerX = svgContainer.getBoundingClientRect().left;
var svgContainerY = svgContainer.getBoundingClientRect().top;
checkQuadIsRect("circle", {},
svgContainerX + 41, svgContainerY + 41, 40, 40);
// Box types are ignored for SVG elements.
checkQuadIsRect("circle", {box:"content"},
svgContainerX + 41, svgContainerY + 41, 40, 40);
checkQuadIsRect("circle", {box:"padding"},
svgContainerX + 41, svgContainerY + 41, 40, 40);
checkQuadIsRect("circle", {box:"margin"},
svgContainerX + 41, svgContainerY + 41, 40, 40);
checkQuadIsRect("d", {toStr:"circle"},
dX - (svgContainerX + 41), dY - (svgContainerY + 41), dW, dH);
// Test foreignObject inside an SVG transform.
checkQuadIsRect("foreign", {},
svgContainerX + 111, svgContainerY + 51, 200, 120);
// Outer <svg> elements support padding and content boxes
checkQuadIsRect("svg", {box:"border"},
svgContainerX, svgContainerY, 222, 222);
checkQuadIsRect("svg", {box:"padding"},
svgContainerX + 7, svgContainerY + 7, 208, 208);
checkQuadIsRect("svg", {box:"content"},
svgContainerX + 11, svgContainerY + 11, 200, 200);
// XXX Test SVG text (probably broken; unclear what the best way is to handle it)
// Test that converting between nodes in different toplevel browsing contexts
// throws an exception.
try {
openedWindow = window.open("file_getBoxQuads_convertPointRectQuad_frame2.html","");
} catch (ex) {
// in some cases we can't open the window.
openedWindow = null;
}
if (openedWindow) {
openedWindow.addEventListener("load", function() {
checkException("openedWindow.d.getBoxQuads({relativeTo:document})", "NotFoundError");
checkException("document.getBoxQuads({relativeTo:openedWindow.d})", "NotFoundError");
checkException("openedWindow.d.convertPointFromNode(zeroPoint,document)", "NotFoundError");
checkException("document.convertPointFromNode(zeroPoint,openedWindow.d)", "NotFoundError");
checkException("openedWindow.d.convertRectFromNode(zeroRect,document)", "NotFoundError");
checkException("document.convertRectFromNode(zeroRect,openedWindow.d)", "NotFoundError");
checkException("openedWindow.d.convertQuadFromNode(zeroQuad,document)", "NotFoundError");
checkException("document.convertQuadFromNode(zeroQuad,openedWindow.d)", "NotFoundError");
openedWindow.close();
SimpleTest.finish();
});
} else {
SimpleTest.finish();
}
}
</script>
</body>
</html>