helper_visual_scrollbars_pagescroll.html (5183B)
1 <!DOCTYPE HTML> 2 <html> 3 <head> 4 <meta charset="utf-8"> 5 <meta name="viewport" content="width=device-width"> 6 <title>Clicking on the scrollbar track in quick succession should scroll the right amount</title> 7 <script type="application/javascript" src="apz_test_native_event_utils.js"></script> 8 <script type="application/javascript" src="apz_test_utils.js"></script> 9 <script src="/tests/SimpleTest/paint_listener.js"></script> 10 <script src="/tests/SimpleTest/EventUtils.js"></script> 11 12 <script type="application/javascript"> 13 14 // A helper to synthesize a native mouse click on a scrollbar track, 15 // and wait long enough such that subsequent ticking of the refresh 16 // driver will progress any resulting scroll animation. 17 // In particular, just `await promiseNativeMouseEventWithApz(...)` 18 // is not enough, it waits for the synthesization messages to arrive 19 // in the parent process, but the native events may still be in the 20 // OS event queue. Instead, we need to wait for a synthesized event 21 // to arrive at content. While we're synthesizing a "click", if the 22 // target is a scrollbar the window only gets the "mousedown" and 23 // "mouseup", not a "click". Waiting for the "mousedown" is not enough 24 // (the "mouseup" can still be stuck in the event queue), so we wait 25 // for "mouseup". 26 async function promiseNativeMouseClickOnScrollbarTrack(anchor, xOffset, yOffset) { 27 await promiseNativeMouseEventWithAPZAndWaitForEvent({ 28 type: "click", 29 target: anchor, 30 offsetX: xOffset, 31 offsetY: yOffset, 32 eventTypeToWait: "mouseup" 33 }); 34 } 35 36 async function test() { 37 var scroller = document.documentElement; 38 var verticalScrollbarWidth = window.innerWidth - scroller.clientWidth; 39 40 if (verticalScrollbarWidth == 0) { 41 ok(true, "Scrollbar width is zero on this platform, test is useless here"); 42 return; 43 } 44 45 // The anchor is the fixed-pos div that we use to calculate coordinates to 46 // click on the scrollbar. That way we don't have to recompute coordinates 47 // as the page scrolls. The anchor is at the bottom-right corner of the 48 // content area. 49 var anchor = document.getElementById('anchor'); 50 51 var xoffset = (verticalScrollbarWidth / 2); 52 // Get a y-coord near the bottom of the vertical scrollbar track. Assume the 53 // vertical thumb is near the top of the scrollback track (since scroll 54 // position starts off at zero) and won't get in the way. Also assume the 55 // down arrow button, if there is one, is square. 56 var yoffset = 0 - verticalScrollbarWidth - 5; 57 58 // Take control of the refresh driver 59 let utils = SpecialPowers.getDOMWindowUtils(window); 60 utils.advanceTimeAndRefresh(0); 61 62 // Click at the bottom of the scrollbar track to trigger a page-down kind of 63 // scroll. This should use "desktop zooming" scrollbar code which should 64 // trigger an APZ scroll animation. 65 await promiseNativeMouseClickOnScrollbarTrack(anchor, xoffset, yoffset); 66 67 // Run 1000 frames, that should be enough to let the scroll animation start 68 // and run to completion. We check that it scrolled at least half the visible 69 // height, since we expect about a full screen height minus a few lines. 70 for (let i = 0; i < 1000; i++) { 71 utils.advanceTimeAndRefresh(16); 72 } 73 await promiseOnlyApzControllerFlushed(); 74 75 let pageScrollAmount = scroller.scrollTop; 76 ok(pageScrollAmount > scroller.clientHeight / 2, 77 `Scroll offset is ${pageScrollAmount}, should be near clientHeight ${scroller.clientHeight}`); 78 79 // Now we do two clicks in quick succession, but with a few frames in between 80 // to verify the scroll animation from the first click is active before the 81 // second click happens. 82 await promiseNativeMouseClickOnScrollbarTrack(anchor, xoffset, yoffset); 83 for (let i = 0; i < 5; i++) { 84 utils.advanceTimeAndRefresh(16); 85 } 86 await promiseOnlyApzControllerFlushed(); 87 let curPos = scroller.scrollTop; 88 ok(curPos > pageScrollAmount, `Scroll offset has increased to ${curPos}`); 89 ok(curPos < pageScrollAmount * 2, "Second page-scroll is not yet complete"); 90 await promiseNativeMouseClickOnScrollbarTrack(anchor, xoffset, yoffset); 91 92 // Run to completion and check that we are around 3x pageScrollAmount, with 93 // some allowance for fractional rounding. 94 for (let i = 0; i < 1000; i++) { 95 utils.advanceTimeAndRefresh(16); 96 } 97 await promiseOnlyApzControllerFlushed(); 98 curPos = scroller.scrollTop; 99 ok(Math.abs(curPos - (pageScrollAmount * 3)) < 3, 100 `Final scroll offset ${curPos} is close to 3x${pageScrollAmount}`); 101 102 utils.restoreNormalRefresh(); 103 } 104 105 waitUntilApzStable() 106 .then(test) 107 .then(subtestDone, subtestFailed); 108 109 </script> 110 </head> 111 <body> 112 <div style="position:fixed; bottom: 0; right: 0; width: 1px; height: 1px" id="anchor"></div> 113 <div style="height: 300vh; margin-bottom: 10000px; background-image: linear-gradient(red,blue)"></div> 114 The above div is sized to 3x screen height so the linear gradient is more steep in terms of 115 color/pixel. We only scroll a few pages worth so we don't need the gradient all the way down. 116 And then we use a bottom-margin to make the page really big so the scrollthumb is 117 relatively small, giving us lots of space to click on the scrolltrack. 118 </body> 119 </html>