| OLD | NEW |
| 1 <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" | 1 <!DOCTYPE html> |
| 2 "http://www.w3.org/TR/html4/loose.dtd"> | |
| 3 | 2 |
| 4 <html lang="en"> | 3 <html> |
| 5 <head> | 4 <head> |
| 6 <meta http-equiv="Content-Type" content="text/html; charset=utf-8"/> | 5 <style> |
| 7 <title>Opting into composited scrolling</title> | |
| 8 <style type="text/css" media="screen"> | |
| 9 .container { | 6 .container { |
| 10 width: 200px; | 7 width: 200px; |
| 11 height: 200px; | 8 height: 200px; |
| 12 overflow: scroll; | 9 overflow: scroll; |
| 13 margin: 20px; | 10 margin: 20px; |
| 14 border: 1px solid black; | 11 border: 1px solid black; |
| 12 background-color: #00FFFF; |
| 15 } | 13 } |
| 16 | 14 |
| 17 .scrolled { | 15 .scrolled { |
| 18 width: 180px; | 16 width: 180px; |
| 19 height: 90px; | 17 height: 30px; |
| 20 margin: 10px; | 18 margin: 10px; |
| 19 top: 70px; |
| 21 background-color: gray; | 20 background-color: gray; |
| 22 position: relative; | 21 position: relative; |
| 23 } | 22 } |
| 24 | 23 |
| 25 .positioned { | 24 .positioned { |
| 26 width: 120px; | 25 width: 120px; |
| 27 height: 240px; | 26 height: 240px; |
| 28 background-color: green; | |
| 29 position: absolute; | 27 position: absolute; |
| 30 } | 28 } |
| 31 | 29 |
| 30 #secondChild { |
| 31 background-color: #CC9999; |
| 32 top: 50px; |
| 33 } |
| 34 |
| 32 #predecessor { | 35 #predecessor { |
| 33 left: 20px; | 36 left: 20px; |
| 34 top: 20px; | 37 top: 20px; |
| 38 background-color: #990066; |
| 35 } | 39 } |
| 36 | 40 |
| 37 #successor { | 41 #successor { |
| 38 left: 160px; | 42 left: 20px; |
| 39 top: 20px; | 43 top: 20px; |
| 44 background-color: #000066; |
| 40 } | 45 } |
| 41 | 46 |
| 42 #descendant { | 47 #normalFlow { |
| 43 left: 90px; | 48 width: 180px; |
| 44 top: 20px; | 49 height: 30px; |
| 45 background-color: blue; | 50 margin: 10px; |
| 46 z-index: -20; | 51 background-color: yellow; |
| 47 } | 52 } |
| 48 </style> | 53 </style> |
| 49 <script type="text/javascript" charset="utf-8"> | 54 <script src="resources/automatically-opt-into-composited-scrolling.js"></scrip
t> |
| 50 var debugMode = false; | 55 <script> |
| 56 function testPermutation(count, ordering, hasPositionedAncestor, containerIs
Positioned) |
| 57 { |
| 58 if (!window.internals) |
| 59 return; |
| 51 | 60 |
| 52 if (window.testRunner) | 61 var container = document.getElementById('container'); |
| 53 testRunner.dumpAsText(); | |
| 54 | 62 |
| 55 if (window.internals) | 63 // Below, when we set webkitTransform to '', we want that to force an |
| 56 window.internals.settings.setAcceleratedCompositingForOverflowScrollEnable
d(true); | 64 // immediate, synchronous style recalculation. Querying the |
| 57 | 65 // document.body.offsetTop value should force this for us. |
| 58 function write(str) | 66 // Note that this step is also performed inside getStackingOrder() to make |
| 59 { | 67 // sure we have fresh values when we need them. |
| 60 var pre = document.getElementById('console'); | 68 container.style.webkitTransform = 'translateZ(0px)'; |
| 61 var text = document.createTextNode(str + '\n'); | |
| 62 pre.appendChild(text); | |
| 63 } | |
| 64 | |
| 65 var iteration = 0; | |
| 66 function printResult(expectedResult) | |
| 67 { | |
| 68 // Force a style recalc. | |
| 69 document.body.offsetTop; | 69 document.body.offsetTop; |
| 70 | 70 |
| 71 if (window.internals) { | 71 // container may be opting in automatically, so even if |
| 72 // Force a layout. | 72 // container.style.webkitTransform === '', we need to explicitly force it |
| 73 window.internals.boundingBox(container); | 73 // not to opt in to get our first stacking order list. To do this, we need |
| 74 var layerTree = window.internals.layerTreeAsText(document); | 74 // to disable compositing for overflow scroll entirely. |
| 75 // |
| 76 // Unfortunately this operation won't dirty any style bits, and we will |
| 77 // need to perform a full style recalc both here and below when we force |
| 78 // to promote, so that we reevaluate whether or not container can be |
| 79 // composited. To ensure that we perform the full style recalc, we need to |
| 80 // change a style property so the style is dirty, and force the style to |
| 81 // be cleaned with document.body.offsetTop (inside getStackingOrder()). |
| 82 window.internals.settings.setAcceleratedCompositingForOverflowScrollEnable
d(false); |
| 83 container.style.webkitTransform = ''; |
| 75 | 84 |
| 76 if (!layerTree == !expectedResult) | 85 var oldStackingOrder = getStackingOrder(container); |
| 77 write('Iteration ' + iteration.toString() + ': Passed') | 86 |
| 87 // force to promote. |
| 88 window.internals.settings.setAcceleratedCompositingForOverflowScrollEnable
d(true); |
| 89 container.style.webkitTransform = 'translateZ(0px)'; |
| 90 |
| 91 var newStackingOrder = getStackingOrder(container); |
| 92 |
| 93 var shouldOptIn = oldStackingOrder.length === newStackingOrder.length; |
| 94 for (var i = 0; i < oldStackingOrder.length; ++i) { |
| 95 if (oldStackingOrder[i] !== newStackingOrder[i]) { |
| 96 shouldOptIn = false; |
| 97 break; |
| 98 } |
| 99 } |
| 100 |
| 101 container.style.webkitTransform = ''; |
| 102 if (shouldOptIn !== didOptIn(container)) { |
| 103 if (shouldOptIn) |
| 104 write("FAIL - should've automatically opted in but didn't " + count); |
| 78 else | 105 else |
| 79 write('Iteration ' + iteration.toString() + ': FAILED') | 106 write('FAIL - automatically opted in and changed stacking order ' + co
unt); |
| 80 | 107 |
| 81 if (layerTree) { | 108 var additionalFailureInfo = "\tOrdering:"; |
| 82 write('Iteration ' + iteration.toString() + ', layer tree'); | 109 for(var i = 0; i < ordering.length; ++i) { |
| 83 if (debugMode) | 110 additionalFailureInfo += " " + ordering[i].id + " (z-index: " + orderi
ng[i].style.zIndex + ")"; |
| 84 write(layerTree); | 111 if(i < ordering.length - 1) |
| 85 } else | 112 additionalFailureInfo += ","; |
| 86 write('Iteration ' + iteration.toString() + ', no layer tree'); | 113 } |
| 114 |
| 115 additionalFailureInfo += "\n\thasPositionedAncestor: " + hasPositionedAn
cestor + "; containerIsPositioned: " + containerIsPositioned; |
| 116 write(additionalFailureInfo); |
| 117 } else { |
| 118 if (shouldOptIn) |
| 119 write("PASS iteration " + count + ": opted in, since doing so does not
change the stacking order."); |
| 120 else |
| 121 write("PASS iteration " + count + ": did not opt in, since doing so wo
uld change the stacking order."); |
| 87 } | 122 } |
| 88 iteration++; | |
| 89 } | 123 } |
| 90 | 124 |
| 91 function doTest() | 125 function doTest() |
| 92 { | 126 { |
| 93 var predecessor = document.getElementById('predecessor'); | 127 buildDom(); |
| 94 var successor = document.getElementById('successor'); | 128 permute(testPermutation); |
| 95 var container = document.getElementById('container'); | 129 } |
| 96 var firstChild = document.getElementById('firstChild'); | |
| 97 var secondChild = document.getElementById('secondChild'); | |
| 98 var descendant = document.getElementById('descendant'); | |
| 99 var count = 0; | |
| 100 | |
| 101 descendant.style.display = 'none'; | |
| 102 | |
| 103 // descendants in stacking order. | |
| 104 for (i = 0; i < 3; ++i) { | |
| 105 for (j = 0; j < 5; ++j) { | |
| 106 for (k = 0; k < 2; ++k) { | |
| 107 for (l = 0; l < 2; ++l) { | |
| 108 var minZIndex = 0; | |
| 109 var maxZIndex = 0; | |
| 110 if (i == 0) { | |
| 111 firstChild.style.zIndex = '1'; | |
| 112 secondChild.style.zIndex = '3'; | |
| 113 maxZIndex = 3; | |
| 114 } else if (i == 1) { | |
| 115 firstChild.style.zIndex = '-1'; | |
| 116 secondChild.style.zIndex = '-3'; | |
| 117 minZIndex = -3; | |
| 118 } else { | |
| 119 firstChild.style.zIndex = '-1'; | |
| 120 secondChild.style.zIndex = '3'; | |
| 121 minZIndex = -1; | |
| 122 maxZIndex = 3; | |
| 123 } | |
| 124 | |
| 125 var sibling = predecessor; | |
| 126 var toHide = successor; | |
| 127 if (k == 1) { | |
| 128 sibling = successor; | |
| 129 toHide = predecessor; | |
| 130 } | |
| 131 | |
| 132 // The result should be the same if the the element to hide is | |
| 133 // display:hidden or display:none. | |
| 134 if (l == 0) | |
| 135 toHide.style.display = 'none'; | |
| 136 else | |
| 137 toHide.style.display = 'hidden'; | |
| 138 | |
| 139 sibling.style.display = ''; | |
| 140 | |
| 141 if (j == 0) | |
| 142 sibling.style.zIndex = (maxZIndex + 1).toString(); | |
| 143 else if (j == 1) | |
| 144 sibling.style.zIndex = (minZIndex - 1).toString(); | |
| 145 else if (j == 2) | |
| 146 sibling.style.zIndex = maxZIndex.toString(); | |
| 147 else if (j == 3) | |
| 148 sibling.style.zIndex = minZIndex.toString(); | |
| 149 else | |
| 150 sibling.style.zIndex = ((minZIndex + maxZIndex) / 2).toString(); | |
| 151 | |
| 152 var areContiguous = false; | |
| 153 if (sibling.style.zIndex > maxZIndex || | |
| 154 sibling.style.zIndex < minZIndex) { | |
| 155 // sibling is outside the range of our descendants. | |
| 156 areContiguous = true; | |
| 157 } else if (sibling.style.zIndex < maxZIndex && | |
| 158 sibling.style.zIndex > minZIndex) { | |
| 159 // sibling is between our descendants. | |
| 160 areContiguous = false; | |
| 161 } else if (sibling.style.zIndex == minZIndex) { | |
| 162 if (minZIndex == 0) { | |
| 163 // sibling lies between us (normal flow) and our pos | |
| 164 // z-order descendants, so we are not contiguous. | |
| 165 areContiguous = false; | |
| 166 } else { | |
| 167 // sibling's zIndex matches the min; we're only ok if it | |
| 168 // appears first. | |
| 169 areContiguous = k == 0; | |
| 170 } | |
| 171 } else if (sibling.style.zIndex == maxZIndex) { | |
| 172 if (maxZIndex < 0) { | |
| 173 // sibling lies between us (normal flow) and neg z-order | |
| 174 // descendants, so we are not contiguous. | |
| 175 areContiguous = false; | |
| 176 } else if (maxZIndex == 0) { | |
| 177 // sibling is in the pos z-order list and does not affect | |
| 178 // us since we're in the normal flow list and our | |
| 179 // descandants are in the neg z-order list. | |
| 180 areContiguous = true; | |
| 181 } else { | |
| 182 // sibling's zIndex matches the max; we're only ok if it | |
| 183 // appears after. | |
| 184 areContiguous = k == 1; | |
| 185 } | |
| 186 } | |
| 187 | |
| 188 printResult(areContiguous); | |
| 189 } // for l | |
| 190 } // for k | |
| 191 } // for j | |
| 192 } // for i | |
| 193 | |
| 194 // Now check that we don't promote if we have an out of flow descendant. | |
| 195 // We need to hide the predecessor and successor so they don't interfere | |
| 196 // with this experiment. | |
| 197 predecessor.style.display = 'none'; | |
| 198 successor.style.display = 'none'; | |
| 199 for (i = 0; i < 3; ++i) { | |
| 200 if (i == 0) | |
| 201 descendant.style.display = 'hidden'; | |
| 202 else if (i == 1) | |
| 203 descendant.style.display = ''; | |
| 204 else | |
| 205 descendant.style.display = 'none'; | |
| 206 | |
| 207 // If the out of flow positioned descendant is visible, we cannot opt | |
| 208 // into composited scrolling. | |
| 209 printResult(i != 1); | |
| 210 count++; | |
| 211 } // for i | |
| 212 | |
| 213 } // function doTest | |
| 214 | 130 |
| 215 window.addEventListener('load', doTest, false); | 131 window.addEventListener('load', doTest, false); |
| 216 </script> | 132 </script> |
| 217 </head> | 133 </head> |
| 218 | 134 |
| 219 <body> | 135 <body> |
| 220 <div class="positioned" id="predecessor"></div> | |
| 221 <div class="container" id="container"> | |
| 222 <div class="scrolled" id="firstChild"></div> | |
| 223 <div class="scrolled" id="secondChild"></div> | |
| 224 <div class="positioned" id="descendant"></div> | |
| 225 </div> | |
| 226 <div class="positioned" id="successor"></div> | |
| 227 <pre id="console"></pre> | |
| 228 </body> | 136 </body> |
| 229 </html> | 137 </html> |
| 230 | |
| OLD | NEW |