| <!DOCTYPE HTML> |
| <html> |
| <head> |
| <script> |
| if (window.testRunner) { |
| testRunner.dumpAsText(); |
| testRunner.waitUntilDone(); |
| } |
| |
| if (window.internals) |
| internals.settings.setPreferCompositingToLCDTextEnabled(false); |
| |
| function hasRepaint(layerTree) { |
| var layers = JSON.parse(layerTree).layers; |
| for (var i = 0; i < layers.length; ++i) { |
| var layer = layers[i]; |
| // Exclude repaint in the vertical scrollbar layer which always happens on scroll. |
| if (layer.name == "Vertical Scrollbar Layer") |
| continue; |
| if (layer.paintInvalidations) |
| return true; |
| } |
| return false; |
| } |
| |
| function rAF() { |
| return new Promise(function(resolve) { |
| requestAnimationFrame(resolve); |
| }); |
| } |
| |
| async function testScrollRepaint(description, expectsRepaint, scroller) { |
| var result = description + ":\n"; |
| |
| // Ensure that any dirtiness has been committed |
| await rAF(); |
| await rAF(); |
| |
| if (window.internals) |
| internals.startTrackingRepaints(document); |
| |
| scroller.scrollTop = 100; |
| |
| // Wait until the next frame reflecting the new scroll position. |
| await rAF(); |
| |
| if (window.internals) { |
| var layer_tree = internals.layerTreeAsText(document, internals.LAYER_TREE_INCLUDES_PAINT_INVALIDATIONS); |
| var repainted = hasRepaint(layer_tree); |
| var repaintedMessage = repainted ? "repainted" : "did not repaint"; |
| var expectedMessage = expectsRepaint ? " when expected" : " when unexpected"; |
| if (repainted == expectsRepaint) |
| result += "PASS " + repaintedMessage + expectedMessage + "\n"; |
| else |
| result += "FAIL " + repaintedMessage + expectedMessage + "\n" + layer_tree + "\n"; |
| internals.stopTrackingRepaints(document); |
| } |
| |
| // Do all cleanup here (so as not to affect repaint rects). |
| scroller.scrollTop = 0; |
| return result; |
| } |
| |
| async function testNoRepaint() { |
| return testScrollRepaint("Overflow scroll", false, container); |
| } |
| |
| async function testWithSelection() { |
| var selection = getSelection(); |
| |
| var range = document.createRange(); |
| range.selectNode(document.getElementById("selection-start")); |
| selection.addRange(range); |
| |
| range = document.createRange(); |
| range.selectNode(document.getElementById("selection-end")); |
| selection.addRange(range); |
| |
| var result = await testScrollRepaint("Overflow scroll with selection", false, container); |
| |
| getSelection().removeAllRanges(); |
| return result; |
| } |
| |
| async function testMarquee() { |
| container.style.display = "none"; |
| marquee.style.display = "block"; |
| var result = await testScrollRepaint("Marquee", false, marquee); |
| marquee.style.display = "none"; |
| container.style.display = "block"; |
| return result; |
| } |
| |
| async function testWithInlineChild() { |
| span.style.display = "inline"; |
| var result = await testScrollRepaint("Overflow scroll with inline child", false, container); |
| span.style.display = "none"; |
| return result; |
| } |
| |
| async function testOverflowHidden() { |
| container.style.overflow = "hidden"; |
| var result = testScrollRepaint("Overflow hidden", false, container); |
| container.style.overflow = "scroll"; |
| return result; |
| } |
| |
| async function doTests() { |
| marquee.stop(); |
| var result = await testNoRepaint(); |
| result += await testWithSelection(); |
| result += await testMarquee(); |
| result += await testWithInlineChild(); |
| result += await testOverflowHidden(); |
| if (window.testRunner) { |
| testRunner.setCustomTextOutput(result); |
| testRunner.notifyDone(); |
| } |
| } |
| |
| window.onload = doTests; |
| </script> |
| <style> |
| #target::selection { background-color: green; } |
| |
| #container { |
| width:100px; |
| height:300px; |
| border: 1px black solid; |
| overflow: scroll; |
| backface-visibility: hidden; |
| position: relative; |
| } |
| |
| #fixed { |
| width: 50px; |
| height: 50px; |
| position: fixed; |
| top: 200px; |
| left: 200px; |
| background-color: blue; |
| backface-visibility: hidden; |
| } |
| |
| .scrolled { |
| width: 50px; |
| height: 50px; |
| margin: 10px; |
| position: relative; |
| background-color: green; |
| backface-visibility: hidden; |
| } |
| |
| #span { |
| display: none; |
| } |
| |
| #description { |
| display: none; |
| } |
| |
| marquee { |
| width: 60px; |
| height: 60px; |
| backface-visibility: hidden; |
| position: relative; |
| display: none; |
| } |
| </style> |
| </head> |
| <body> |
| <pre id="description"> |
| This test ensures that if the only thing that scrolls is a composited layer, |
| we do not repaint. It passes if we repaint when we have to draw the selection |
| block gaps or if we have content that is not in a composited layer. It also |
| checks that we do not repaint when all the content is in a composited layer. |
| </pre> |
| <div id="container"> |
| <span id="span">Hello!</span> |
| <div id="fixed"></div> |
| <div class="scrolled" id="selection-start"></div> |
| <div class="scrolled" id="selection-end"></div> |
| <div class="scrolled"></div> |
| <div class="scrolled"></div> |
| <div class="scrolled"></div> |
| <div class="scrolled"></div> |
| <div class="scrolled"></div> |
| <div class="scrolled"></div> |
| <div class="scrolled"></div> |
| </div> |
| <marquee id="marquee" direction="up" scrollamount="1"> |
| <p>Lorem ipsum dolor amet</p> |
| <p>Lorem ipsum dolor amet</p> |
| <p>Lorem ipsum dolor amet</p> |
| <p>Lorem ipsum dolor amet</p> |
| <p>Lorem ipsum dolor amet</p> |
| <p>Lorem ipsum dolor amet</p> |
| <p>Lorem ipsum dolor amet</p> |
| </marquee> |
| </body> |
| </html> |