helper_zoom_out_with_mainthread_clamping.html (4428B)
1 <!DOCTYPE HTML> 2 <html> 3 <head> 4 <meta charset="utf-8"> 5 <meta name="viewport" content="width=device-width, minimum-scale=1.0"> 6 <title>Tests that zooming out in a way that triggers main-thread scroll re-clamping works properly</title> 7 <script src="/tests/SimpleTest/EventUtils.js"></script> 8 <script type="application/javascript" src="apz_test_utils.js"></script> 9 <script type="application/javascript" src="apz_test_native_event_utils.js"></script> 10 <script src="/tests/SimpleTest/paint_listener.js"></script> 11 </head> 12 <body> 13 <div style="width: 200vw; height: 2000px; background-color: linear-gradient(green,blue)"></div> 14 <script type="application/javascript"> 15 const utils = SpecialPowers.getDOMWindowUtils(window); 16 17 async function test() { 18 // Initial state 19 is(await getResolution(), 1.0, "should not be zoomed"); 20 21 // Zoom in and go to the bottom-right corner. This ensures the layout 22 // and visual scroll offsets are nonzero, which increases the chances 23 // that the scroll position layer alignment code will mutate the scroll 24 // position (see comment below). 25 utils.setResolutionAndScaleTo(5.0); 26 await promiseApzFlushedRepaints(); 27 utils.scrollToVisual(document.scrollingElement.clientWidth * 5, 28 document.scrollingElement.clientHeight * 5, 29 utils.UPDATE_TYPE_MAIN_THREAD, 30 utils.SCROLL_MODE_INSTANT); 31 await promiseApzFlushedRepaints(); 32 33 // Check that we're at the right place 34 is(await getResolution(), 5.0, "should be zoomed to 5.0"); 35 is(window.scrollX, window.scrollMaxX, "layout x-coord should be maxed"); 36 is(window.scrollY, window.scrollMaxY, "layout y-coord should be maxed"); 37 ok(visualViewport.offsetLeft > 0, "visual x-coord should be even further"); 38 ok(visualViewport.offsetTop > 0, "visual y-coord should be even further"); 39 40 // Zoom out. This will trigger repaint requests to the main thread, 41 // at various intermediate resolutions. The repaint requests will 42 // trigger reflows, which will trigger the root scrollframe to re-clamp 43 // and layer-align the scroll position as part of the post-reflow action. 44 // The test is checking that these mutations don't end up sending a scroll 45 // position update to APZ that interrupts the zoom action (see bug 1671284 46 // comment 9 for the exact mechanism). In order to maximize the chances of 47 // catching the bug, we wait for the main thread repaint after each of the 48 // pinch inputs. 49 50 let zoom_out = pinchZoomOutTouchSequenceAtCenter(); 51 // Do coordinate conversion up-front using the current resolution and 52 // visual viewport. 53 for (let entry of zoom_out) { 54 for (let i = 0; i < entry.length; i++) { 55 entry[i] = await coordinatesRelativeToScreen({ 56 offsetX: entry[i].x, 57 offsetY: entry[i].y, 58 target: document.body, 59 }); 60 } 61 } 62 // Dispatch the touch events, waiting for paints after each row in 63 // zoom_out. 64 let touchIds = [0, 1]; 65 for (let i = 0; i < zoom_out.length; i++) { 66 let entry = zoom_out[i]; 67 for (let j = 0; j < entry.length; j++) { 68 await new Promise(resolve => { 69 utils.sendNativeTouchPoint( 70 touchIds[j], 71 utils.TOUCH_CONTACT, 72 entry[j].x, 73 entry[j].y, 74 1, 75 90, 76 resolve 77 ); 78 }); 79 } 80 await promiseAllPaintsDone(); 81 82 // On the last row also do the touch-up events 83 if (i == zoom_out.length - 1) { 84 for (let j = 0; j < entry.length; j++) { 85 await new Promise(resolve => { 86 utils.sendNativeTouchPoint( 87 touchIds[j], 88 utils.TOUCH_REMOVE, 89 entry[j].x, 90 entry[j].y, 91 1, 92 90, 93 resolve 94 ); 95 }); 96 } 97 } 98 } 99 100 // Wait for everything to stabilize 101 await promiseApzFlushedRepaints(); 102 103 // Verify that the zoom completed and we're back at 1.0 resolution 104 isfuzzy(await getResolution(), 1.0, 0.0001, "should be back at initial resolution"); 105 } 106 107 waitUntilApzStable().then(test).then(subtestDone, subtestFailed); 108 </script> 109 </body> 110 </html>