1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/content/base/test/test_range_bounds.html Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,275 @@ 1.4 +<!DOCTYPE HTML> 1.5 +<html> 1.6 +<!-- 1.7 +https://bugzilla.mozilla.org/show_bug.cgi?id=421640 1.8 +--> 1.9 +<head> 1.10 + <title>Test for Bug 396392</title> 1.11 + <meta http-equiv="content-type" content="text/html; charset=UTF-8"> 1.12 + <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script> 1.13 + <script type="text/javascript" src="/tests/SimpleTest/EventUtils.js"></script> 1.14 + <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" /> 1.15 +</head> 1.16 +<body> 1.17 +<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=396392">Mozilla Bug Range getClientRects and getBoundingClientRect</a> 1.18 +<div id="content" style="font-family:monospace;font-size:12px;width:100px"> 1.19 +<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> 1.20 +</div> 1.21 +<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> 1.22 +<div id="mixeddir2" style="font-family:monospace;font-size:12px"><span>english <bdo id="bdo2" dir="rtl">rtl-override english</bdo> word</span></div> 1.23 +<pre id="test"> 1.24 +<script class="testbody" type="text/javascript"> 1.25 + 1.26 +var isLTR=true; 1.27 +function isEmptyRect(rect, name) { 1.28 + name = (isLTR ? 'isLTR ' : 'isRTL ') + name; 1.29 + is(rect.left, 0, name+'empty rect should have left = 0'); 1.30 + is(rect.right, 0, name+'empty rect should have right = 0'); 1.31 + is(rect.top, 0, name+'empty rect should have top = 0'); 1.32 + is(rect.bottom, 0, name+'empty rect should have bottom = 0'); 1.33 + is(rect.width, 0, name+'empty rect should have width = 0'); 1.34 + is(rect.height, 0, name+'empty rect should have height = 0'); 1.35 +} 1.36 + 1.37 +function isEmptyRectList(rectlist, name) { 1.38 + name = (isLTR ? 'isLTR ' : 'isRTL ') + name; 1.39 + is(rectlist.length, 0, name + 'empty rectlist should have zero rects'); 1.40 +} 1.41 + 1.42 +// round coordinates to the nearest 1/256 of a pixel 1.43 +function roundCoord(x) { 1.44 + return Math.round(x * 256) / 256; 1.45 +} 1.46 + 1.47 +function _getRect(r) { 1.48 + if (r.length) //array 1.49 + return "{left:"+roundCoord(r[0])+",right:"+roundCoord(r[1])+ 1.50 + ",top:" +roundCoord(r[2])+",bottom:"+roundCoord(r[3])+ 1.51 + ",width:"+roundCoord(r[4])+",height:"+roundCoord(r[5])+"}"; 1.52 + else 1.53 + return "{left:"+roundCoord(r.left)+",right:"+roundCoord(r.right)+ 1.54 + ",top:"+roundCoord(r.top)+",bottom:"+roundCoord(r.bottom)+ 1.55 + ",width:"+roundCoord(r.width)+",height:"+roundCoord(r.height)+"}"; 1.56 +} 1.57 + 1.58 +function runATest(obj) { 1.59 + var range = document.createRange(); 1.60 + try { 1.61 + range.setStart(obj.range[0],obj.range[1]); 1.62 + if (obj.range.length>2) { 1.63 + range.setEnd(obj.range[2]||obj.range[0], obj.range[3]); 1.64 + } 1.65 + //test getBoundingClientRect() 1.66 + var rect = range.getBoundingClientRect(); 1.67 + var testname = (isLTR ? 'isLTR ' : 'isRTL ') + 1.68 + 'range.getBoundingClientRect for ' + obj.name; 1.69 + if (obj.rect) { 1.70 + is(_getRect(rect),_getRect(obj.rect), testname); 1.71 + } else { 1.72 + isEmptyRect(rect,testname+": "); 1.73 + } 1.74 + //test getClientRects() 1.75 + var rectlist = range.getClientRects(); 1.76 + testname = (isLTR ? 'isLTR ' : 'isRTL ') + 1.77 + 'range.getClientRects for '+obj.name; 1.78 + if (!obj.rectList) { 1.79 + //rectList is not specified, use obj.rect to figure out rectList 1.80 + obj.rectList = obj.rect?[obj.rect]:[]; 1.81 + } 1.82 + if (!obj.rectList.length) { 1.83 + isEmptyRectList(rectlist, testname+": "); 1.84 + } else { 1.85 + is(rectlist.length, obj.rectList.length, testname+' should return '+obj.rectList.length+' rects.'); 1.86 + if(!obj.rectList.forEach){ 1.87 + //convert RectList to a real array 1.88 + obj.rectList=Array.prototype.slice.call(obj.rectList, 0); 1.89 + } 1.90 + obj.rectList.forEach(function(rect,i) { 1.91 + is(_getRect(rectlist[i]),_getRect(rect),testname+": item at "+i); 1.92 + }); 1.93 + } 1.94 + } finally { 1.95 + range.detach(); 1.96 + } 1.97 +} 1.98 +/** Test for Bug 396392 **/ 1.99 +function doTest(){ 1.100 + var root = document.getElementById('content'); 1.101 + var firstP = root.firstElementChild, spanInFirstP = firstP.childNodes[1], 1.102 + firstDiv = root.childNodes[2], spanInFirstDiv = firstDiv.childNodes[1], 1.103 + secondP = root.childNodes[3], spanInSecondP = secondP.childNodes[1], 1.104 + secondDiv = root.childNodes[4], spanInSecondDiv = secondDiv.firstChild, 1.105 + thirdDiv = root.childNodes[5]; 1.106 + var firstPRect = firstP.getBoundingClientRect(), 1.107 + spanInFirstPRect = spanInFirstP.getBoundingClientRect(), 1.108 + firstDivRect = firstDiv.getBoundingClientRect(), 1.109 + spanInFirstDivRect = spanInFirstDiv.getBoundingClientRect(), 1.110 + secondPRect = secondP.getBoundingClientRect(), 1.111 + secondDivRect = secondDiv.getBoundingClientRect(), 1.112 + spanInSecondPRect = spanInSecondP.getBoundingClientRect(), 1.113 + spanInSecondDivRect = spanInSecondDiv.getBoundingClientRect(), 1.114 + spanInSecondDivRectList = spanInSecondDiv.getClientRects(); 1.115 + var widthPerchar = spanInSecondPRect.width / spanInSecondP.firstChild.length; 1.116 + var testcases = [ 1.117 + {name:'nodesNotInDocument', range:[document.createTextNode('abc'), 1], 1.118 + rect:null}, 1.119 + {name:'collapsedInBlockNode', range:[firstP, 2], rect:null}, 1.120 + {name:'collapsedAtBeginningOfTextNode', range:[firstP.firstChild, 0], 1.121 + rect:[spanInFirstPRect.left - 6 * widthPerchar, 1.122 + spanInFirstPRect.left - 6 * widthPerchar, spanInFirstPRect.top, 1.123 + spanInFirstPRect.bottom, 0, spanInFirstPRect.height]}, 1.124 + {name:'collapsedWithinTextNode', range:[firstP.firstChild, 1], 1.125 + rect:[spanInFirstPRect.left - 5 * widthPerchar, 1.126 + spanInFirstPRect.left - 5 * widthPerchar, 1.127 + spanInFirstPRect.top, spanInFirstPRect.bottom, 0, spanInFirstPRect.height]}, 1.128 + {name:'collapsedAtEndOfTextNode', range:[firstP.firstChild, 6], 1.129 + rect:[spanInFirstPRect.left, spanInFirstPRect.left, 1.130 + spanInFirstPRect.top, spanInFirstPRect.bottom, 0, spanInFirstPRect.height]}, 1.131 + {name:'singleBlockNode', range:[root, 1, root, 2], rect:firstPRect}, 1.132 + {name:'twoBlockNodes', range:[root, 1, root, 3], 1.133 + rect:[firstPRect.left, firstPRect.right, firstPRect.top, 1.134 + firstDivRect.bottom, firstPRect.width, 1.135 + firstDivRect.bottom - firstPRect.top], 1.136 + rectList:[firstPRect, firstDivRect]}, 1.137 + {name:'endOfTextNodeToEndOfAnotherTextNodeInAnotherBlock', 1.138 + range:[spanInFirstP.firstChild, 1, firstDiv.firstChild, 5], 1.139 + rect:[spanInFirstDivRect.left - 5*widthPerchar, spanInFirstDivRect.left, 1.140 + spanInFirstDivRect.top, spanInFirstDivRect.bottom, 5 * widthPerchar, 1.141 + spanInFirstDivRect.height]}, 1.142 + {name:'startOfTextNodeToStartOfAnotherTextNodeInAnotherBlock', 1.143 + range:[spanInFirstP.firstChild, 0, firstDiv.firstChild, 0], 1.144 + rect:[spanInFirstPRect.left, spanInFirstPRect.left + widthPerchar, spanInFirstPRect.top, 1.145 + spanInFirstPRect.bottom, widthPerchar, spanInFirstPRect.height]}, 1.146 + {name:'endPortionOfATextNode', range:[firstP.firstChild, 3, 1.147 + firstP.firstChild, 6], 1.148 + rect:[spanInFirstPRect.left - 3*widthPerchar, spanInFirstPRect.left, 1.149 + spanInFirstPRect.top, spanInFirstPRect.bottom, 3*widthPerchar, spanInFirstPRect.height]}, 1.150 + {name:'startPortionOfATextNode', range:[firstP.firstChild, 0, 1.151 + firstP.firstChild, 3], 1.152 + rect:[spanInFirstPRect.left - 6*widthPerchar, 1.153 + spanInFirstPRect.left - 3*widthPerchar, spanInFirstPRect.top, 1.154 + spanInFirstPRect.bottom, 3 * widthPerchar, spanInFirstPRect.height]}, 1.155 + {name:'spanTextNodes', range:[secondP.firstChild, 1, secondP.lastChild, 1], 1.156 + rect:[spanInSecondPRect.left - 3*widthPerchar, spanInSecondPRect.right + 1.157 + widthPerchar, spanInSecondPRect.top, spanInSecondPRect.bottom, 1.158 + spanInSecondPRect.width + 4*widthPerchar, spanInSecondPRect.height], 1.159 + rectList:[[spanInSecondPRect.left - 3*widthPerchar, spanInSecondPRect.left, 1.160 + spanInSecondPRect.top, spanInSecondPRect.bottom, 3 * widthPerchar, 1.161 + spanInSecondPRect.height], 1.162 + spanInSecondPRect, 1.163 + [spanInSecondPRect.right, spanInSecondPRect.right + widthPerchar, 1.164 + spanInSecondPRect.top, spanInSecondPRect.bottom, widthPerchar, 1.165 + spanInSecondPRect.height]]} 1.166 + ]; 1.167 + testcases.forEach(runATest); 1.168 + 1.169 + // testcases that have different ranges in LTR and RTL 1.170 + var directionDependentTestcases; 1.171 + if (isLTR) { 1.172 + directionDependentTestcases = [ 1.173 + {name:'spanAcrossLines',range:[spanInSecondDiv.firstChild, 1, spanInSecondDiv.firstChild, 30], 1.174 + rect: spanInSecondDivRect, 1.175 + rectList:[[spanInSecondDivRectList[0].left+widthPerchar, 1.176 + spanInSecondDivRectList[0].right, spanInSecondDivRectList[0].top, 1.177 + spanInSecondDivRectList[0].bottom, spanInSecondDivRectList[0].width - widthPerchar, 1.178 + spanInSecondDivRectList[0].height], 1.179 + spanInSecondDivRectList[1], 1.180 + [spanInSecondDivRectList[2].left, 1.181 + spanInSecondDivRectList[2].right - 4 * widthPerchar, spanInSecondDivRectList[2].top, 1.182 + spanInSecondDivRectList[2].bottom, 1.183 + spanInSecondDivRectList[2].width - 4 * widthPerchar, 1.184 + spanInSecondDivRectList[2].height]]}, 1.185 + {name:'textAcrossLines',range:[thirdDiv.firstChild, 13, thirdDiv.firstChild, 28], 1.186 + rect: [spanInSecondDivRectList[1].left, spanInSecondDivRectList[1].right, 1.187 + spanInSecondDivRectList[1].top + secondDivRect.height, 1.188 + spanInSecondDivRectList[1].bottom + secondDivRect.height, 1.189 + spanInSecondDivRectList[1].width, spanInSecondDivRectList[1].height]} 1.190 + ]; 1.191 + } else { 1.192 + directionDependentTestcases = [ 1.193 + {name:'spanAcrossLines',range:[spanInSecondDiv.firstChild, 1, spanInSecondDiv.firstChild, 30], 1.194 + rect: spanInSecondDivRect, 1.195 + rectList:[[spanInSecondDivRectList[0].left+widthPerchar, 1.196 + spanInSecondDivRectList[0].right, spanInSecondDivRectList[0].top, 1.197 + spanInSecondDivRectList[0].bottom, spanInSecondDivRectList[0].width - widthPerchar, 1.198 + spanInSecondDivRectList[0].height], 1.199 + spanInSecondDivRectList[1], 1.200 + spanInSecondDivRectList[2], 1.201 + spanInSecondDivRectList[3], 1.202 + [spanInSecondDivRectList[4].left, 1.203 + spanInSecondDivRectList[4].right - 4 * widthPerchar, 1.204 + spanInSecondDivRectList[4].top, 1.205 + spanInSecondDivRectList[4].bottom, 1.206 + spanInSecondDivRectList[4].width - 4 * widthPerchar, 1.207 + spanInSecondDivRectList[4].height]]}, 1.208 + {name:'textAcrossLines',range:[thirdDiv.firstChild, 13, thirdDiv.firstChild, 28], 1.209 + rect: [spanInSecondDivRectList[2].left, spanInSecondDivRectList[2].right, 1.210 + spanInSecondDivRectList[2].top + secondDivRect.height, 1.211 + spanInSecondDivRectList[2].bottom + secondDivRect.height, 1.212 + spanInSecondDivRectList[2].width, spanInSecondDivRectList[2].height], 1.213 + rectList:[[spanInSecondDivRectList[2].left, spanInSecondDivRectList[2].right, 1.214 + spanInSecondDivRectList[2].top + secondDivRect.height, 1.215 + spanInSecondDivRectList[2].bottom + secondDivRect.height, 1.216 + spanInSecondDivRectList[2].width, spanInSecondDivRectList[2].height], 1.217 + [spanInSecondDivRectList[2].left, spanInSecondDivRectList[2].left, 1.218 + spanInSecondDivRectList[2].top + secondDivRect.height, 1.219 + spanInSecondDivRectList[2].bottom + secondDivRect.height, 1.220 + 0, spanInSecondDivRectList[2].height]]} 1.221 + ]; 1.222 + } 1.223 + directionDependentTestcases.forEach(runATest); 1.224 +} 1.225 +function testMixedDir(){ 1.226 + var root = document.getElementById('mixeddir'); 1.227 + var firstSpan = root.firstElementChild, firstSpanRect=firstSpan.getBoundingClientRect(), 1.228 + firstSpanRectList = firstSpan.getClientRects(); 1.229 + runATest({name:'mixeddir',range:[firstSpan.firstChild,0,firstSpan.lastChild,firstSpan.lastChild.length], 1.230 + rect: firstSpanRect, rectList:firstSpanRectList}); 1.231 + 1.232 + root = document.getElementById('mixeddir2'); 1.233 + firstSpan = root.firstElementChild; 1.234 + firstSpanRect = firstSpan.getBoundingClientRect(); 1.235 + bdo = document.getElementById('bdo2'); 1.236 + bdoRect=bdo.getBoundingClientRect(); 1.237 + var widthPerChar = bdoRect.width / bdo.firstChild.length; 1.238 + runATest({name:'mixeddirPartial', range:[firstSpan.firstChild, 3, 1.239 + bdo.firstChild, 7], 1.240 + rect: [firstSpanRect.left + 3*widthPerChar, bdoRect.right, 1.241 + bdoRect.top, bdoRect.bottom, 1.242 + (firstSpan.firstChild.length + bdo.firstChild.length - 3) * 1.243 + widthPerChar, 1.244 + bdoRect.height], 1.245 + rectList:[[firstSpanRect.left + 3*widthPerChar, 1.246 + bdoRect.left, 1.247 + firstSpanRect.top, firstSpanRect.bottom, 1.248 + (firstSpan.firstChild.length - 3) * widthPerChar, 1.249 + firstSpanRect.height], 1.250 + [bdoRect.right - 7 * widthPerChar, bdoRect.right, 1.251 + bdoRect.top, bdoRect.bottom, 1.252 + 7*widthPerChar, bdoRect.height]]}); 1.253 +} 1.254 +function test(){ 1.255 + //test ltr 1.256 + doTest(); 1.257 + testMixedDir(); 1.258 + 1.259 + isLTR = false; 1.260 + var root = document.getElementById('content'); 1.261 + root.dir = 'rtl'; 1.262 + 1.263 + //test rtl 1.264 + doTest(); 1.265 + testMixedDir(); 1.266 + 1.267 + SimpleTest.finish(); 1.268 +} 1.269 + 1.270 +window.onload = function() { 1.271 + SimpleTest.waitForExplicitFinish(); 1.272 + setTimeout(test, 0); 1.273 +}; 1.274 + 1.275 +</script> 1.276 +</pre> 1.277 +</body> 1.278 +</html>