browser_test_simple_transform.js (7484B)
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 loadScripts({ name: "role.js", dir: MOCHITESTS_DIR }); 8 9 add_setup(async function () { 10 await SpecialPowers.pushPrefEnv({ 11 set: [["test.wait300msAfterTabSwitch", true]], 12 }); 13 }); 14 15 // test basic translation 16 addAccessibleTask( 17 `<p id="translate">hello world</p>`, 18 async function (browser, iframeDocAcc) { 19 ok(iframeDocAcc, "IFRAME document accessible is present"); 20 await testBoundsWithContent(iframeDocAcc, "translate", browser); 21 22 await invokeContentTask(browser, [], () => { 23 let p = content.document.getElementById("translate"); 24 p.style = "transform: translate(100px, 100px);"; 25 }); 26 27 await waitForContentPaint(browser); 28 await testBoundsWithContent(iframeDocAcc, "translate", browser); 29 }, 30 { topLevel: true, iframe: true, remoteIframe: true } 31 ); 32 33 // Test translation with two children. 34 addAccessibleTask( 35 ` 36 <div role="main" style="translate: 0 300px;"> 37 <p id="p1">hello</p> 38 <p id="p2">world</p> 39 </div> 40 `, 41 async function (browser, docAcc) { 42 await testBoundsWithContent(docAcc, "p1", browser); 43 await testBoundsWithContent(docAcc, "p2", browser); 44 }, 45 { topLevel: true, iframe: true, remoteIframe: true } 46 ); 47 48 // test basic rotation 49 addAccessibleTask( 50 `<p id="rotate">hello world</p>`, 51 async function (browser, iframeDocAcc) { 52 ok(iframeDocAcc, "IFRAME document accessible is present"); 53 await testBoundsWithContent(iframeDocAcc, "rotate", browser); 54 55 await invokeContentTask(browser, [], () => { 56 let p = content.document.getElementById("rotate"); 57 p.style = "transform: rotate(-40deg);"; 58 }); 59 60 await waitForContentPaint(browser); 61 await testBoundsWithContent(iframeDocAcc, "rotate", browser); 62 }, 63 { topLevel: true, iframe: true, remoteIframe: true } 64 ); 65 66 // test basic scale 67 addAccessibleTask( 68 `<p id="scale">hello world</p>`, 69 async function (browser, iframeDocAcc) { 70 ok(iframeDocAcc, "IFRAME document accessible is present"); 71 await testBoundsWithContent(iframeDocAcc, "scale", browser); 72 73 await invokeContentTask(browser, [], () => { 74 let p = content.document.getElementById("scale"); 75 p.style = "transform: scale(2);"; 76 }); 77 78 await waitForContentPaint(browser); 79 await testBoundsWithContent(iframeDocAcc, "scale", browser); 80 }, 81 { topLevel: true, iframe: true, remoteIframe: true } 82 ); 83 84 // Test will-change: transform with no transform. 85 addAccessibleTask( 86 ` 87 <div id="willChangeTop" style="will-change: transform;"> 88 <p>hello</p> 89 <p id="willChangeTopP2">world</p> 90 </div> 91 <div role="group"> 92 <div id="willChangeInner" style="will-change: transform;"> 93 <p>hello</p> 94 <p id="willChangeInnerP2">world</p> 95 </div> 96 </div> 97 `, 98 async function (browser, docAcc) { 99 // Even though willChangeTop has no transform, it has 100 // will-change: transform, which means nsIFrame::IsTransformed returns 101 // true. We don't cache identity matrices, but because there is an offset 102 // to the root frame, layout includes this in the returned transform 103 // matrix. That means we get a non-identity matrix and thus we cache it. 104 // This is why we only test the identity matrix cache optimization for 105 // willChangeInner. 106 let hasTransform; 107 try { 108 const willChangeInner = findAccessibleChildByID( 109 docAcc, 110 "willChangeInner" 111 ); 112 willChangeInner.cache.getStringProperty("transform"); 113 hasTransform = true; 114 } catch (e) { 115 hasTransform = false; 116 } 117 ok(!hasTransform, "willChangeInner has no cached transform"); 118 await testBoundsWithContent(docAcc, "willChangeTopP2", browser); 119 await testBoundsWithContent(docAcc, "willChangeInnerP2", browser); 120 }, 121 { topLevel: true, iframe: true, remoteIframe: true } 122 ); 123 124 // Verify that a transform forces creation of an accessible. 125 addAccessibleTask( 126 ` 127 <div id="container"> 128 <div style="transform:translate(100px,100px);"> 129 <p>test</p> 130 </div> 131 </div> 132 133 <div id="div-presentational" role="presentation" style="transform:translate(100px,100px);"> 134 <p>test</p> 135 </div> 136 `, 137 async function (browser, docAcc) { 138 const tree = { TEXT_CONTAINER: [{ PARAGRAPH: [{ TEXT_LEAF: [] }] }] }; 139 140 const divWithTransform = findAccessibleChildByID( 141 docAcc, 142 "container" 143 ).firstChild; 144 testAccessibleTree(divWithTransform, tree); 145 // testBoundsWithContent takes an id, but divWithTransform doesn't have one, 146 // so we can't test the bounds for it. 147 148 // An accessible should still be created, even if the role is "presentation." 149 const divPresentational = findAccessibleChildByID( 150 docAcc, 151 "div-presentational" 152 ); 153 testAccessibleTree(divPresentational, tree); 154 await testBoundsWithContent(docAcc, "div-presentational", browser); 155 }, 156 { topLevel: true, iframe: true, remoteIframe: true } 157 ); 158 159 // Verify that adding a transform on the fly forces creation of an accessible. 160 addAccessibleTask( 161 ` 162 <div id="div-to-transform" role="none" style="position: absolute; width: 300px; height: 300px;"> 163 <p>test</p> 164 </div> 165 `, 166 async function (browser, docAcc) { 167 let divToTransform = findAccessibleChildByID(docAcc, "div-to-transform"); 168 ok(!divToTransform, "There should not be a div accessible."); 169 170 // Translate the div. 171 await invokeContentTask(browser, [], () => { 172 let div = content.document.getElementById("div-to-transform"); 173 div.style.transform = "translate(100%, 100%)"; 174 }); 175 await waitForContentPaint(browser); 176 177 // Verify that the SECTION accessible appeared after we gave it a transform. 178 divToTransform = findAccessibleChildByID(docAcc, "div-to-transform"); 179 const tree = { 180 TEXT_CONTAINER: [{ PARAGRAPH: [{ TEXT_LEAF: [] }] }], 181 }; 182 testAccessibleTree(divToTransform, tree); 183 184 // Verify that the bounds of the div are correctly modified. 185 await testBoundsWithContent(docAcc, "div-to-transform", browser); 186 }, 187 { topLevel: true, iframe: true, remoteIframe: true } 188 ); 189 190 // Test translated, position: absolute Accessible in a container. 191 addAccessibleTask( 192 ` 193 <div id="container"> 194 <div id="transform" style="position: absolute; transform: translate(100px, 100px);"> 195 <p id="p">test</p> 196 </div> 197 </div> 198 `, 199 async function (browser, docAcc) { 200 await testBoundsWithContent(docAcc, "transform", browser); 201 await testBoundsWithContent(docAcc, "p", browser); 202 }, 203 { topLevel: true, iframe: true, remoteIframe: true } 204 ); 205 206 // Test bounds of a rotated element after scroll. 207 addAccessibleTask( 208 ` 209 <div id="scrollable" style="transform: rotate(180deg); overflow: scroll; height: 500px;"> 210 <p id="test">hello world</p><hr style="height: 100vh;"> 211 </div> 212 `, 213 async function (browser, docAcc) { 214 info( 215 "Testing that the unscrolled bounds of a transformed element are correct." 216 ); 217 await testBoundsWithContent(docAcc, "test", browser); 218 219 await invokeContentTask(browser, [], () => { 220 // Scroll the scrollable region down (scrolls up due to the transform). 221 let elem = content.document.getElementById("scrollable"); 222 elem.scrollTo(0, elem.scrollHeight); 223 }); 224 225 info( 226 "Testing that the scrolled bounds of a transformed element are correct." 227 ); 228 await testBoundsWithContent(docAcc, "test", browser); 229 }, 230 { topLevel: true, iframe: true, remoteIframe: true } 231 );