browser_test_APZ.js (9202B)
1 /* This Source Code Form is subject to the terms of the Mozilla Public 2 * License, v. 2.0. If a copy of the MPL was not distributed with this 3 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 4 5 "use strict"; 6 7 Services.scriptloader.loadSubScript( 8 "chrome://mochitests/content/browser/gfx/layers/apz/test/mochitest/apz_test_native_event_utils.js", 9 this 10 ); 11 12 add_setup(async function () { 13 await SpecialPowers.pushPrefEnv({ 14 set: [["test.wait300msAfterTabSwitch", true]], 15 }); 16 }); 17 18 /** 19 * Test accessible is hittestable before and after APZ. Also verify 20 * bounds change in the direction we expect. 21 * 22 * Note: the `display:inline-block` styling ensures elements that would 23 * otherwise span the entire page in width do not extend beyond their 24 * visual boundaries. Without it, we'd still "hit" items in the reduced 25 * visual viewport even though their content doesn't appear on screen. 26 */ 27 addAccessibleTask( 28 ` 29 <div id="test" role="button" style="background:green; min-height: 10vh; max-width: 10vh; display:inline-block;">I am square</div><br> 30 <div style="height: 70vh;">hello world I am large</div><br> 31 <h1 id="heading" style="display:inline-block;">I am a heading</h1> 32 `, 33 async function (browser, accDoc) { 34 const test = findAccessibleChildByID(accDoc, "test"); 35 36 info("Hittesting pre-APZ"); 37 let dpr = await getContentDPR(browser); 38 let [targetX, targetY, targetW, targetH] = Layout.getBounds(test, dpr); 39 let [x, y] = Layout.getBounds(accDoc, dpr); 40 await testChildAtPoint( 41 dpr, 42 targetX - x + targetW / 2, 43 targetY - y + targetH / 2, 44 accDoc, 45 test, // Direct Child 46 test // Deepest Child 47 ); 48 49 info("Pinch zooming..."); 50 await SpecialPowers.spawn(browser, [], async () => { 51 const visualScrollPromise = new Promise(resolve => { 52 content.window.visualViewport.addEventListener("scroll", resolve, { 53 once: true, 54 }); 55 }); 56 const utils = SpecialPowers.getDOMWindowUtils(content.window); 57 utils.setResolutionAndScaleTo(2); 58 utils.scrollToVisual( 59 200, 60 200, 61 utils.UPDATE_TYPE_MAIN_THREAD, 62 utils.SCROLL_MODE_INSTANT 63 ); 64 await visualScrollPromise; 65 }); 66 info("Hittesting post-APZ"); 67 dpr = await getContentDPR(browser); 68 let [newX, newY, newW, newH] = Layout.getBounds(test, dpr); 69 [x, y] = Layout.getBounds(accDoc, dpr); 70 // This shouldn't be in the viewport cache, because it is out of the 71 // visual viewport 72 await testChildAtPoint( 73 dpr, 74 newX - x + newW / 2, 75 newY - y + newH / 2, 76 accDoc, 77 null, // Direct Child 78 null // Deepest Child 79 ); 80 81 // We pinch zoom to the right of the square, 82 // which means its coords become off-screen 83 // (negative). 84 info("Verifying scaled bounds"); 85 Assert.less(newX, 0, "X coord should be smaller than 0"); 86 Assert.less(newY, 0, "Y coord should be smaller than 0"); 87 // Because we zoomed in, width and height should 88 // be larger than they were before. 89 Assert.greater(newW, targetW, "Width should be larger than old width"); 90 Assert.greater(newH, targetH, "Height should be larger than old height"); 91 }, 92 // APZ only happens on the top-level document, which means iframe tests 93 // will assert differently than classic remote doc tests. 94 { iframe: false, remoteIframe: false } 95 ); 96 97 /** 98 * Test accessible is hittestable before and after APZ with scroll. Also verify 99 * the viewport cache is cleared of "old" information. 100 */ 101 addAccessibleTask( 102 ` 103 <div id="test" role="button" style="background:green; min-height: 10vh; max-width: 10vh; display:inline-block;">I am square</div><br> 104 <div id="spacer" style="min-height: 70vh; display:inline-block;">hello world I am large</div><br> 105 <h1 id="heading" style="display:inline-block;">I am a heading</h1> 106 `, 107 async function (browser, accDoc) { 108 const test = findAccessibleChildByID(accDoc, "test"); 109 const heading = findAccessibleChildByID(accDoc, "heading"); 110 111 info("Hittesting pre-APZ"); 112 let dpr = await getContentDPR(browser); 113 let [targetX, targetY, targetW, targetH] = Layout.getBounds(test, dpr); 114 let [x, y] = Layout.getBounds(accDoc, dpr); 115 // Save these values for later, we'll need them to compare. 116 const origTestX = targetX - x + targetW / 2; 117 const origTestY = targetY - y + targetH / 2; 118 // Try hittesting the test node, which should succeed. 119 await testChildAtPoint( 120 dpr, 121 origTestX, 122 origTestY, 123 accDoc, 124 test, // Direct Child 125 test // Deepest Child 126 ); 127 128 // Now try hittesting the heading, we should get the heading and its internal 129 // text node. 130 [targetX, targetY, targetW, targetH] = Layout.getBounds(heading, dpr); 131 const origHeadingX = targetX - x + targetW / 2; 132 const origHeadingY = targetY - y + targetH / 2; 133 await testChildAtPoint( 134 dpr, 135 origHeadingX, 136 origHeadingY, 137 accDoc, 138 heading, // Direct Child 139 heading.firstChild // Deepest Child 140 ); 141 142 info("Pinch zooming..."); 143 await SpecialPowers.spawn(browser, [], async () => { 144 const visualScrollPromise = new Promise(resolve => { 145 content.window.visualViewport.addEventListener("scroll", resolve, { 146 once: true, 147 }); 148 }); 149 const utils = SpecialPowers.getDOMWindowUtils(content.window); 150 utils.setResolutionAndScaleTo(2); 151 utils.scrollToVisual( 152 200, 153 200, 154 utils.UPDATE_TYPE_MAIN_THREAD, 155 utils.SCROLL_MODE_INSTANT 156 ); 157 await visualScrollPromise; 158 }); 159 160 info("Hittesting post-APZ, pre-scroll"); 161 dpr = await getContentDPR(browser); 162 let [newX, newY, newW, newH] = Layout.getBounds(heading, dpr); 163 [x, y] = Layout.getBounds(accDoc, dpr); 164 // Try hittesting the heading, which should be outside 165 // the visual viewport. 166 info("Testing heading at new point"); 167 await testChildAtPoint( 168 dpr, 169 newX - x + newW / 2, 170 newY - y + newH / 2, 171 accDoc, 172 null, // Direct Child 173 null // Deepest Child 174 ); 175 176 info("Testing heading at old point"); 177 // To ensure the viewport cache has updated, and that the heading isn't 178 // stuck in its old location, test there too. If this fails, we know we're 179 // missing a viewport update. 180 await testChildAtPoint( 181 dpr, 182 origHeadingX, 183 origHeadingY, 184 accDoc, 185 accDoc, // Direct Child 186 accDoc // Deepest Child 187 ); 188 189 // Then try hittesting the original div, which should 190 // also be outside the visual viewport 191 [newX, newY, newW, newH] = Layout.getBounds(test, dpr); 192 info("testing test at new point"); 193 await testChildAtPoint( 194 dpr, 195 newX - x + newW / 2, 196 newY - y + newH / 2, 197 accDoc, 198 null, // Direct Child 199 null // Deepest Child 200 ); 201 info("testing test at old point"); 202 // If we still get the test div, the viewport cache is 203 // stale. 204 await testChildAtPoint( 205 dpr, 206 origTestX, 207 origTestY, 208 accDoc, 209 accDoc, // Direct Child 210 accDoc // Deepest Child 211 ); 212 213 info("Scrolling to bottom of page..."); 214 await SpecialPowers.spawn(browser, [], async () => { 215 const visualScrollPromise = new Promise(resolve => { 216 content.window.visualViewport.addEventListener("scroll", resolve, { 217 once: true, 218 }); 219 }); 220 const utils = SpecialPowers.getDOMWindowUtils(content.window); 221 utils.scrollToVisual( 222 0, 223 content.visualViewport.height, 224 utils.UPDATE_TYPE_MAIN_THREAD, 225 utils.SCROLL_MODE_INSTANT 226 ); 227 await visualScrollPromise; 228 }); 229 230 info("Hittesting post-APZ, post-scroll"); 231 dpr = await getContentDPR(browser); 232 [newX, newY, newW, newH] = Layout.getBounds(test, dpr); 233 [x, y] = Layout.getBounds(accDoc, dpr); 234 // We shouldn't get anything in the spot that the test acc 235 // previously occupied, it should be offscreen. 236 info("testing test at new point"); 237 await testChildAtPoint( 238 dpr, 239 newX - x + newW / 2, 240 newY - y + newH / 2, 241 accDoc, 242 null, // Direct Child 243 null // Deepest Child 244 ); 245 info("Testing test at old point"); 246 const spacer = findAccessibleChildByID(accDoc, "spacer"); 247 // "Spacer" takes up all the space above the heading, which means 248 // it occupies the region our test div originally did. We 249 // should find it here, if the viewport cache isn't stale. 250 await testChildAtPoint( 251 dpr, 252 origTestX, 253 origTestY, 254 accDoc, 255 spacer, // Direct Child 256 spacer // Deepest Child 257 ); 258 259 // We should be able to hittest the heading at the 260 // bottom of the page. 261 [newX, newY, newW, newH] = Layout.getBounds(heading, dpr); 262 info("Testing heading at new point"); 263 await testChildAtPoint( 264 dpr, 265 newX - x + newW / 2, 266 newY - y + newH / 2, 267 accDoc, 268 heading, // Direct Child 269 heading.firstChild // Deepest Child 270 ); 271 }, 272 // APZ only happens on the top-level document, which means iframe tests 273 // will assert differently than classic remote doc tests. 274 { iframe: false, remoteIframe: false } 275 );