summaryrefslogtreecommitdiffstats
path: root/layout/base/tests/test_getBoxQuads_convertPointRectQuad.html
diff options
context:
space:
mode:
Diffstat (limited to 'layout/base/tests/test_getBoxQuads_convertPointRectQuad.html')
-rw-r--r--layout/base/tests/test_getBoxQuads_convertPointRectQuad.html713
1 files changed, 713 insertions, 0 deletions
diff --git a/layout/base/tests/test_getBoxQuads_convertPointRectQuad.html b/layout/base/tests/test_getBoxQuads_convertPointRectQuad.html
new file mode 100644
index 000000000..7ec4f7b56
--- /dev/null
+++ b/layout/base/tests/test_getBoxQuads_convertPointRectQuad.html
@@ -0,0 +1,713 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+<meta charset="utf-8">
+<script type="application/javascript" 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) {
+ is(eval(expr), 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].bounds.width;
+ var boxHeight = selfQuads[0].bounds.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].bounds.width;
+ var boxHeight = selfQuads[0].bounds.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].bounds.width;
+ var boxHeight = selfQuads[0].bounds.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.bounds.left, x, quadsExpr + " checking quad.bounds.left", options);
+ isApprox(q.bounds.top, y, quadsExpr + " checking quad.bounds.top", options);
+ isApprox(q.bounds.width, w, quadsExpr + " checking quad.bounds.width", options);
+ isApprox(q.bounds.height, h, quadsExpr + " checking quad.bounds.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.bounds.left, Math.min(x1,x2,x3,x4), quadsExpr + " checking quad.bounds.left", options);
+ isApprox(q.bounds.top, Math.min(y1,y2,y3,y4), quadsExpr + " checking quad.bounds.top", options);
+ isApprox(q.bounds.right, Math.max(x1,x2,x3,x4), quadsExpr + " checking quad.bounds.right", options);
+ isApprox(q.bounds.bottom, Math.max(y1,y2,y3,y4), quadsExpr + " checking quad.bounds.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="data:text/html,<!DOCTYPE HTML><html style='padding:25px'><div id='f1d' style='position:absolute; left:14px; top:15px; width:16px; height:17px; background:pink'></div>">
+</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; -moz-column-count:2; -moz-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.DOMPoint.enabled", true],
+ ["layout.css.DOMQuad.enabled", true],
+ ["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";
+ document.body.appendChild(x);
+ 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();
+ };
+}
+
+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].bounds.left", ibSplitPart1X);
+ isEval("ibSplit.getBoxQuads()[0].bounds.width", 100);
+ isEval("ibSplit.getBoxQuads()[1].bounds.width", 110);
+ isEval("ibSplit.getBoxQuads()[2].bounds.width", 130);
+ isEval("table.getBoxQuads().length", 2);
+ isEval("table.getBoxQuads()[0].bounds.height", 50);
+ isEval("table.getBoxQuads()[1].bounds.height", 40);
+
+ // Test that we skip anonymous boxes when finding the right box to be relative to.
+ checkQuadIsRect("d", {toStr:"ibSplit"},
+ 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].bounds.top", colSplitY);
+ isEval("colSplit.getBoxQuads()[0].bounds.height", 60);
+ isEval("colSplit.getBoxQuads()[1].bounds.top", colSplitY - 20);
+ isEval("colSplit.getBoxQuads()[1].bounds.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].bounds.top", colSplitY + 10);
+ isEval("colSplit.getBoxQuads({box:'content'})[0].bounds.height", 50);
+ isEval("colSplit.getBoxQuads({box:'content'})[1].bounds.top", colSplitY - 20);
+ isEval("colSplit.getBoxQuads({box:'content'})[1].bounds.height", 30);
+
+ var inlineSplitX = inlineSplit.getClientRects()[0].left;
+ isEval("inlineSplit.getBoxQuads().length", 2);
+ isEval("inlineSplit.getBoxQuads()[0].bounds.left", inlineSplitX);
+ isEval("inlineSplit.getBoxQuads()[0].bounds.width", 30);
+ isEval("inlineSplit.getBoxQuads()[1].bounds.left", inlineSplitX - 150);
+ isEval("inlineSplit.getBoxQuads()[1].bounds.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].bounds.left", inlineSplitX + 10);
+ isEval("inlineSplit.getBoxQuads({box:'content'})[0].bounds.width", 20);
+ isEval("inlineSplit.getBoxQuads({box:'content'})[1].bounds.left", inlineSplitX - 150);
+ isEval("inlineSplit.getBoxQuads({box:'content'})[1].bounds.width", 60);
+
+ var textX = textContainer.getClientRects()[0].left;
+ isEval("text.getBoxQuads().length", 2);
+ isEval("text.getBoxQuads()[0].bounds.left", textX);
+ isEval("text.getBoxQuads()[1].bounds.left", textX - 150);
+ // Box types are irrelevant for text
+ isEval("text.getBoxQuads({box:'content'}).length", 2);
+ isEval("text.getBoxQuads({box:'content'})[0].bounds.left", textX);
+ isEval("text.getBoxQuads({box:'content'})[1].bounds.left", textX - 150);
+ isEval("text.getBoxQuads({box:'padding'}).length", 2);
+ isEval("text.getBoxQuads({box:'padding'})[0].bounds.left", textX);
+ isEval("text.getBoxQuads({box:'padding'})[1].bounds.left", textX - 150);
+ isEval("text.getBoxQuads({box:'margin'}).length", 2);
+ isEval("text.getBoxQuads({box:'margin'})[0].bounds.left", textX);
+ isEval("text.getBoxQuads({box:'margin'})[1].bounds.left", textX - 150);
+
+ // Test table margins
+ isEval("table.getBoxQuads({box:'margin'}).length", 1);
+ isEval("table.getBoxQuads({box:'margin'})[0].bounds.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].bounds.left", suppressedTextContainerX);
+ isEval("suppressedText.getBoxQuads()[0].bounds.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("data:text/html,<div id='d'>","");
+ } 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>