summaryrefslogtreecommitdiffstats
path: root/dom/base/test/test_range_bounds.html
diff options
context:
space:
mode:
Diffstat (limited to 'dom/base/test/test_range_bounds.html')
-rw-r--r--dom/base/test/test_range_bounds.html305
1 files changed, 305 insertions, 0 deletions
diff --git a/dom/base/test/test_range_bounds.html b/dom/base/test/test_range_bounds.html
new file mode 100644
index 0000000000..657d315198
--- /dev/null
+++ b/dom/base/test/test_range_bounds.html
@@ -0,0 +1,305 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=421640
+-->
+<head>
+ <title>Test for Bug 396392</title>
+ <meta http-equiv="content-type" content="text/html; charset=UTF-8">
+ <script src="/tests/SimpleTest/SimpleTest.js"></script>
+ <script src="/tests/SimpleTest/EventUtils.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
+</head>
+<body>
+<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=396392">Mozilla Bug Range getClientRects and getBoundingClientRect</a>
+<div id="content" style="font-family:monospace;font-size:12px;width:100px">
+<p>000000<span>0</span></p><div>00000<span>0</span></div><p>0000<span>0000</span>0000</p><div><span>000000000000 00000000000000 000000</span></div><div>000000000000 00000000000003 100305</div>
+</div>
+<div id="mixeddir" style="font-family:monospace;font-size:12px;width:100px"><span>english <bdo id="bdo" dir="rtl">rtl-overide english</bdo> word</span></div>
+<div id="mixeddir2" style="font-family:monospace;font-size:12px"><span>english <bdo id="bdo2" dir="rtl">rtl-override english</bdo> word</span></div>
+<pre id="test">
+<script class="testbody" type="text/javascript">
+
+var isLTR = true;
+var isTransformed = false;
+
+function annotateName(name) {
+ return (isLTR ? 'isLTR ' : 'isRTL ') +
+ (isTransformed ? 'transformed ' : '') + name;
+}
+
+function isEmptyRect(rect, name) {
+ name = annotateName(name);
+ is(rect.left, 0, name+'empty rect should have left = 0');
+ is(rect.right, 0, name+'empty rect should have right = 0');
+ is(rect.top, 0, name+'empty rect should have top = 0');
+ is(rect.bottom, 0, name+'empty rect should have bottom = 0');
+ is(rect.width, 0, name+'empty rect should have width = 0');
+ is(rect.height, 0, name+'empty rect should have height = 0');
+}
+
+function isEmptyRectList(rectlist, name) {
+ name = annotateName(name);
+ is(rectlist.length, 0, name + 'empty rectlist should have zero rects');
+}
+
+// round coordinates to the nearest 1/256 of a pixel
+function roundCoord(x) {
+ return Math.round(x * 256) / 256;
+}
+
+function _getRect(r) {
+ if (r.length) //array
+ return "{left:"+roundCoord(r[0])+",right:"+roundCoord(r[1])+
+ ",top:" +roundCoord(r[2])+",bottom:"+roundCoord(r[3])+
+ ",width:"+roundCoord(r[4])+",height:"+roundCoord(r[5])+"}";
+ else
+ return "{left:"+roundCoord(r.left)+",right:"+roundCoord(r.right)+
+ ",top:"+roundCoord(r.top)+",bottom:"+roundCoord(r.bottom)+
+ ",width:"+roundCoord(r.width)+",height:"+roundCoord(r.height)+"}";
+}
+
+function runATest(obj) {
+ var range = document.createRange();
+ try {
+ range.setStart(obj.range[0],obj.range[1]);
+ if (obj.range.length>2) {
+ range.setEnd(obj.range[2]||obj.range[0], obj.range[3]);
+ }
+ //test getBoundingClientRect()
+ var rect = range.getBoundingClientRect();
+ var testname = 'range.getBoundingClientRect for ' + obj.name;
+ if (obj.rect) {
+ is(_getRect(rect),_getRect(obj.rect), annotateName(testname));
+ } else {
+ isEmptyRect(rect,testname+": ");
+ }
+ //test getClientRects()
+ var rectlist = range.getClientRects();
+ testname = 'range.getClientRects for ' + obj.name;
+ if (!obj.rectList) {
+ //rectList is not specified, use obj.rect to figure out rectList
+ obj.rectList = obj.rect?[obj.rect]:[];
+ }
+ if (!obj.rectList.length) {
+ isEmptyRectList(rectlist, testname+": ");
+ } else {
+ is(rectlist.length, obj.rectList.length,
+ annotateName(testname+' should return '+obj.rectList.length+' rects.'));
+ if(!obj.rectList.forEach){
+ //convert RectList to a real array
+ obj.rectList=Array.prototype.slice.call(obj.rectList, 0);
+ }
+ obj.rectList.forEach(function(r,i) {
+ is(_getRect(rectlist[i]),_getRect(r),
+ annotateName(testname+": item at "+i));
+ });
+ }
+ } finally {
+ range.detach();
+ }
+}
+/** Test for Bug 396392 **/
+function doTest(){
+ var root = document.getElementById('content');
+ var firstP = root.firstElementChild, spanInFirstP = firstP.childNodes[1],
+ firstDiv = root.childNodes[2], spanInFirstDiv = firstDiv.childNodes[1],
+ secondP = root.childNodes[3], spanInSecondP = secondP.childNodes[1],
+ secondDiv = root.childNodes[4], spanInSecondDiv = secondDiv.firstChild,
+ thirdDiv = root.childNodes[5];
+ var firstPRect = firstP.getBoundingClientRect(),
+ spanInFirstPRect = spanInFirstP.getBoundingClientRect(),
+ firstDivRect = firstDiv.getBoundingClientRect(),
+ spanInFirstDivRect = spanInFirstDiv.getBoundingClientRect(),
+ secondPRect = secondP.getBoundingClientRect(),
+ secondDivRect = secondDiv.getBoundingClientRect(),
+ spanInSecondPRect = spanInSecondP.getBoundingClientRect(),
+ spanInSecondDivRect = spanInSecondDiv.getBoundingClientRect(),
+ spanInSecondDivRectList = spanInSecondDiv.getClientRects();
+ var widthPerchar = spanInSecondPRect.width / spanInSecondP.firstChild.length;
+ var testcases = [
+ {name:'nodesNotInDocument', range:[document.createTextNode('abc'), 1],
+ rect:null},
+ {name:'collapsedInBlockNode', range:[firstP, 2], rect:null},
+ {name:'collapsedAtBeginningOfTextNode', range:[firstP.firstChild, 0],
+ rect:[spanInFirstPRect.left - 6 * widthPerchar,
+ spanInFirstPRect.left - 6 * widthPerchar, spanInFirstPRect.top,
+ spanInFirstPRect.bottom, 0, spanInFirstPRect.height]},
+ {name:'collapsedWithinTextNode', range:[firstP.firstChild, 1],
+ rect:[spanInFirstPRect.left - 5 * widthPerchar,
+ spanInFirstPRect.left - 5 * widthPerchar,
+ spanInFirstPRect.top, spanInFirstPRect.bottom, 0, spanInFirstPRect.height]},
+ {name:'collapsedAtEndOfTextNode', range:[firstP.firstChild, 6],
+ rect:[spanInFirstPRect.left, spanInFirstPRect.left,
+ spanInFirstPRect.top, spanInFirstPRect.bottom, 0, spanInFirstPRect.height]},
+ {name:'singleBlockNode', range:[root, 1, root, 2], rect:firstPRect},
+ {name:'twoBlockNodes', range:[root, 1, root, 3],
+ rect:[firstPRect.left, firstPRect.right, firstPRect.top,
+ firstDivRect.bottom, firstPRect.width,
+ firstDivRect.bottom - firstPRect.top],
+ rectList:[firstPRect, firstDivRect]},
+ {name:'endOfTextNodeToEndOfAnotherTextNodeInAnotherBlock',
+ range:[spanInFirstP.firstChild, 1, firstDiv.firstChild, 5],
+ rect:[spanInFirstDivRect.left - 5*widthPerchar, spanInFirstDivRect.left,
+ spanInFirstDivRect.top, spanInFirstDivRect.bottom, 5 * widthPerchar,
+ spanInFirstDivRect.height]},
+ {name:'startOfTextNodeToStartOfAnotherTextNodeInAnotherBlock',
+ range:[spanInFirstP.firstChild, 0, firstDiv.firstChild, 0],
+ rect:[spanInFirstPRect.left, spanInFirstPRect.left + widthPerchar, spanInFirstPRect.top,
+ spanInFirstPRect.bottom, widthPerchar, spanInFirstPRect.height]},
+ {name:'endPortionOfATextNode', range:[firstP.firstChild, 3,
+ firstP.firstChild, 6],
+ rect:[spanInFirstPRect.left - 3*widthPerchar, spanInFirstPRect.left,
+ spanInFirstPRect.top, spanInFirstPRect.bottom, 3*widthPerchar, spanInFirstPRect.height]},
+ {name:'startPortionOfATextNode', range:[firstP.firstChild, 0,
+ firstP.firstChild, 3],
+ rect:[spanInFirstPRect.left - 6*widthPerchar,
+ spanInFirstPRect.left - 3*widthPerchar, spanInFirstPRect.top,
+ spanInFirstPRect.bottom, 3 * widthPerchar, spanInFirstPRect.height]},
+ {name:'spanTextNodes', range:[secondP.firstChild, 1, secondP.lastChild, 1],
+ rect:[spanInSecondPRect.left - 3*widthPerchar, spanInSecondPRect.right +
+ widthPerchar, spanInSecondPRect.top, spanInSecondPRect.bottom,
+ spanInSecondPRect.width + 4*widthPerchar, spanInSecondPRect.height],
+ rectList:[[spanInSecondPRect.left - 3*widthPerchar, spanInSecondPRect.left,
+ spanInSecondPRect.top, spanInSecondPRect.bottom, 3 * widthPerchar,
+ spanInSecondPRect.height],
+ spanInSecondPRect,
+ [spanInSecondPRect.right, spanInSecondPRect.right + widthPerchar,
+ spanInSecondPRect.top, spanInSecondPRect.bottom, widthPerchar,
+ spanInSecondPRect.height]]}
+ ];
+ testcases.forEach(runATest);
+
+ // testcases that have different ranges in LTR and RTL
+ var directionDependentTestcases;
+ if (isLTR) {
+ directionDependentTestcases = [
+ {name:'spanAcrossLines',range:[spanInSecondDiv.firstChild, 1, spanInSecondDiv.firstChild, 30],
+ rect: spanInSecondDivRect,
+ rectList:[[spanInSecondDivRectList[0].left+widthPerchar,
+ spanInSecondDivRectList[0].right, spanInSecondDivRectList[0].top,
+ spanInSecondDivRectList[0].bottom, spanInSecondDivRectList[0].width - widthPerchar,
+ spanInSecondDivRectList[0].height],
+ spanInSecondDivRectList[1],
+ [spanInSecondDivRectList[2].left,
+ spanInSecondDivRectList[2].right - 4 * widthPerchar, spanInSecondDivRectList[2].top,
+ spanInSecondDivRectList[2].bottom,
+ spanInSecondDivRectList[2].width - 4 * widthPerchar,
+ spanInSecondDivRectList[2].height]]},
+ {name:'textAcrossLines',range:[thirdDiv.firstChild, 13, thirdDiv.firstChild, 28],
+ rect: [spanInSecondDivRectList[1].left, spanInSecondDivRectList[1].right,
+ spanInSecondDivRectList[1].top + secondDivRect.height,
+ spanInSecondDivRectList[1].bottom + secondDivRect.height,
+ spanInSecondDivRectList[1].width, spanInSecondDivRectList[1].height]}
+ ];
+ } else {
+ directionDependentTestcases = [
+ {name:'spanAcrossLines',range:[spanInSecondDiv.firstChild, 1, spanInSecondDiv.firstChild, 30],
+ rect: spanInSecondDivRect,
+ rectList:[[spanInSecondDivRectList[0].left+widthPerchar,
+ spanInSecondDivRectList[0].right, spanInSecondDivRectList[0].top,
+ spanInSecondDivRectList[0].bottom, spanInSecondDivRectList[0].width - widthPerchar,
+ spanInSecondDivRectList[0].height],
+ spanInSecondDivRectList[1],
+ spanInSecondDivRectList[2],
+ spanInSecondDivRectList[3],
+ [spanInSecondDivRectList[4].left,
+ spanInSecondDivRectList[4].right - 4 * widthPerchar,
+ spanInSecondDivRectList[4].top,
+ spanInSecondDivRectList[4].bottom,
+ spanInSecondDivRectList[4].width - 4 * widthPerchar,
+ spanInSecondDivRectList[4].height]]},
+ {name:'textAcrossLines',range:[thirdDiv.firstChild, 13, thirdDiv.firstChild, 28],
+ rect: [spanInSecondDivRectList[2].left, spanInSecondDivRectList[2].right,
+ spanInSecondDivRectList[2].top + secondDivRect.height,
+ spanInSecondDivRectList[2].bottom + secondDivRect.height,
+ spanInSecondDivRectList[2].width, spanInSecondDivRectList[2].height],
+ rectList:[[spanInSecondDivRectList[2].left, spanInSecondDivRectList[2].right,
+ spanInSecondDivRectList[2].top + secondDivRect.height,
+ spanInSecondDivRectList[2].bottom + secondDivRect.height,
+ spanInSecondDivRectList[2].width, spanInSecondDivRectList[2].height],
+ [spanInSecondDivRectList[2].left, spanInSecondDivRectList[2].left,
+ spanInSecondDivRectList[2].top + secondDivRect.height,
+ spanInSecondDivRectList[2].bottom + secondDivRect.height,
+ 0, spanInSecondDivRectList[2].height]]}
+ ];
+ }
+ directionDependentTestcases.forEach(runATest);
+}
+function testMixedDir(){
+ var root = document.getElementById('mixeddir');
+ var firstSpan = root.firstElementChild, firstSpanRect=firstSpan.getBoundingClientRect(),
+ firstSpanRectList = firstSpan.getClientRects();
+ runATest({name:'mixeddir',range:[firstSpan.firstChild,0,firstSpan.lastChild,firstSpan.lastChild.length],
+ rect: firstSpanRect, rectList:firstSpanRectList});
+
+ root = document.getElementById('mixeddir2');
+ firstSpan = root.firstElementChild;
+ firstSpanRect = firstSpan.getBoundingClientRect();
+ bdo = document.getElementById('bdo2');
+ bdoRect=bdo.getBoundingClientRect();
+ var widthPerChar = bdoRect.width / bdo.firstChild.length;
+ runATest({name:'mixeddirPartial', range:[firstSpan.firstChild, 3,
+ bdo.firstChild, 7],
+ rect: [firstSpanRect.left + 3*widthPerChar, bdoRect.right,
+ bdoRect.top, bdoRect.bottom,
+ (firstSpan.firstChild.length + bdo.firstChild.length - 3) *
+ widthPerChar,
+ bdoRect.height],
+ rectList:[[firstSpanRect.left + 3*widthPerChar,
+ bdoRect.left,
+ firstSpanRect.top, firstSpanRect.bottom,
+ (firstSpan.firstChild.length - 3) * widthPerChar,
+ firstSpanRect.height],
+ [bdoRect.right - 7 * widthPerChar, bdoRect.right,
+ bdoRect.top, bdoRect.bottom,
+ 7*widthPerChar, bdoRect.height]]});
+}
+
+function testShadowDOM() {
+ var ifr = document.createElement("iframe");
+ document.body.appendChild(ifr);
+ var doc = ifr.contentDocument;
+ var d = doc.createElement("div");
+ var sr = d.attachShadow({mode: "open"});
+ sr.innerHTML = "<div>inside shadow DOM</div>";
+ doc.body.appendChild(d);
+ var r = new ifr.contentWindow.Range();
+ r.selectNode(sr.firstChild);
+ var rect = r.getBoundingClientRect();
+ isnot(rect.width, 0, "Div element inside shadow shouldn't have zero size.");
+ isnot(rect.height, 0, "Div element inside shadow shouldn't have zero size.");
+}
+
+function test(){
+ //test ltr
+ doTest();
+
+ //test rtl
+ isLTR = false;
+ var root = document.getElementById('content');
+ root.dir = 'rtl';
+ doTest();
+ isLTR = true;
+ root.dir = 'ltr';
+
+ testMixedDir();
+
+ //test transforms
+ isTransformed = true;
+ root.style.transform = "translate(30px,50px)";
+ doTest();
+
+ testShadowDOM();
+ SimpleTest.finish();
+}
+
+window.onload = function() {
+ SimpleTest.waitForExplicitFinish();
+ setTimeout(test, 0);
+};
+
+</script>
+</pre>
+</body>
+</html>