helper_overscroll_in_subscroller.html (4889B)
1 <!DOCTYPE HTML> 2 <meta charset="utf-8"> 3 <meta name="viewport" content="width=device-width, minimum-scale=1.0"> 4 <title> 5 Tests that the overscroll gutter in a sub scroll container is restored if it's 6 no longer target scroll container 7 </title> 8 <script src="apz_test_utils.js"></script> 9 <script src="apz_test_native_event_utils.js"></script> 10 <script src="/tests/SimpleTest/paint_listener.js"></script> 11 <style> 12 html { 13 overflow: scroll; 14 } 15 16 .content { 17 height: 500px; 18 width: 300px; 19 overflow-y: scroll; 20 background-color: red; 21 } 22 </style> 23 <!-- a sub scroll container --> 24 <div class="content"> 25 <div style="height:100vh; background-color: white;"></div> 26 </div> 27 <div style="height:200vh"></div> 28 <script> 29 document.documentElement.addEventListener( 30 "wheel", 31 e => { 32 if (!e.target.closest(`div[class="content"]`)) { 33 e.preventDefault(); 34 } 35 }, 36 { 37 passive: false, 38 } 39 ); 40 41 const subScroller = document.querySelector(`div[class="content"]`); 42 // Make the sub scroll container overscrollable at the top edge. 43 // A `waitUntilApzStable()` call below ensures that this scroll position 44 // has been informed into APZ before starting this test. 45 subScroller.scrollTop = 1; 46 47 // A utility function to collect overscrolled scroll container information. 48 function collectOverscrolledData() { 49 const apzData = SpecialPowers.DOMWindowUtils.getCompositorAPZTestData().additionalData; 50 return apzData.filter(data => { 51 return SpecialPowers.wrap(data).value.split(",").includes("overscrolled"); 52 }); 53 } 54 55 async function test() { 56 const oneScrollPromise = new Promise(resolve => { 57 subScroller.addEventListener("scroll", () => { 58 resolve(); 59 }, { once: true }); 60 }); 61 62 // Start a pan upward gesture to try oversrolling on the sub scroll 63 // container. 64 await NativePanHandler.promiseNativePanEvent( 65 subScroller, 66 100, 67 100, 68 0, 69 -NativePanHandler.delta, 70 NativePanHandler.beginPhase 71 ); 72 73 const rootScrollId = 74 SpecialPowers.DOMWindowUtils.getViewId(document.scrollingElement); 75 const subScrollId = 76 SpecialPowers.DOMWindowUtils.getViewId(subScroller); 77 78 await promiseApzFlushedRepaints(); 79 await oneScrollPromise; 80 81 let overscrolledData = collectOverscrolledData(); 82 ok(overscrolledData.length >= 1, 83 "There should be at least one overscrolled scroll container"); 84 ok(overscrolledData.every(data => SpecialPowers.wrap(data).key == subScrollId), 85 "The overscrolled scroll container should be the sub scroll container"); 86 87 let oneScrollEndPromise = new Promise(resolve => { 88 subScroller.addEventListener("scrollend", () => { 89 info("Received scrollend event"); 90 resolve(); 91 }, { once: true }); 92 }); 93 94 // Finish the pan upward gesture. 95 await NativePanHandler.promiseNativePanEvent( 96 subScroller, 97 100, 98 100, 99 0, 100 0, 101 NativePanHandler.endPhase 102 ); 103 104 await promiseApzFlushedRepaints(); 105 106 // Now do another pan upward gesture again. 107 await NativePanHandler.promiseNativePanEvent( 108 subScroller, 109 100, 110 100, 111 0, 112 -NativePanHandler.delta, 113 NativePanHandler.beginPhase 114 ); 115 116 // Wait two `apz-repaints-flushed`s to give a chance to overscroll the root 117 // scroll container. 118 await promiseApzFlushedRepaints(); 119 await promiseApzFlushedRepaints(); 120 121 overscrolledData = collectOverscrolledData(); 122 ok(overscrolledData.length >= 2, 123 "There should be at least two overscrolled scroll containers"); 124 ok(overscrolledData.some(data => SpecialPowers.wrap(data).key == rootScrollId), 125 "The root scroll container should be overscrolled"); 126 ok(overscrolledData.some(data => SpecialPowers.wrap(data).key == subScrollId), 127 "The sub scroll container should also be overscrolled"); 128 129 // While the root scroll container is still being overscrolled because the 130 // new pan gesture is still on-going, the sub scroll container should be 131 // restored. 132 // Wait for a scrollend event indicating that the subscroller's overscroll 133 // animation has completed. 134 await oneScrollEndPromise; 135 info("Got a scroll end event on the sub scroll container"); 136 137 await promiseApzFlushedRepaints(); 138 139 overscrolledData = collectOverscrolledData(); 140 ok(overscrolledData.length >= 1, 141 "There should be at least one overscrolled scroll container"); 142 ok(overscrolledData.every(data => SpecialPowers.wrap(data).key == rootScrollId), 143 "The root scroll container should still be overscrolled"); 144 145 // Finish the pan upward gesture. 146 await NativePanHandler.promiseNativePanEvent( 147 subScroller, 148 100, 149 100, 150 0, 151 0, 152 NativePanHandler.endPhase 153 ); 154 } 155 156 waitUntilApzStable() 157 .then(test) 158 .then(subtestDone, subtestFailed); 159 </script>