file_domwindowutils_animation.html (7849B)
1 <!DOCTYPE html> 2 <html> 3 <head> 4 <meta charset="UTF-8"> 5 <title>DOMWindowUtils test with animation</title> 6 <script src="/tests/SimpleTest/paint_listener.js"></script> 7 <script src="/tests/dom/animation/test/testcommon.js"></script> 8 </head> 9 <body> 10 <script type="application/javascript"> 11 12 const SimpleTest = window.opener.SimpleTest; 13 const utils = SpecialPowers.getDOMWindowUtils(window); 14 const next = window.opener.next; 15 const is = window.opener.is; 16 const ok = window.opener.ok; 17 18 function addStyle(rules) { 19 const extraStyle = document.createElement("style"); 20 document.head.appendChild(extraStyle); 21 rules.forEach(rule => { 22 extraStyle.sheet.insertRule(rule, extraStyle.sheet.cssRules.length); 23 }); 24 } 25 26 function deleteStyle() { 27 document.head.querySelector("style").remove(); 28 } 29 30 31 let propertyIndex = 0; 32 33 function test_getUnanimatedComputedStyle() { 34 const name = `--property-${++propertyIndex}`; 35 CSS.registerProperty({ 36 name, 37 syntax: "<length>", 38 initialValue: "2px", 39 inherits: false, 40 }); 41 [ 42 { 43 property: "opacity", 44 keyframes: [1, 0], 45 expectedInitialStyle: "1", 46 expectedDuringTransitionStyle: "0", 47 isDiscrete: false, 48 }, 49 { 50 property: name, 51 keyframes: ["1px", "10px"], 52 expectedInitialStyle: "2px", 53 expectedDuringTransitionStyle: "2px", 54 isDiscrete: true, 55 }, 56 { 57 property: "clear", 58 keyframes: ["left", "inline-end"], 59 expectedInitialStyle: "none", 60 expectedDuringTransitionStyle: "inline-end", 61 isDiscrete: true, 62 }, 63 ].forEach(testcase => { 64 const { property, keyframes, expectedInitialStyle, 65 expectedDuringTransitionStyle, isDiscrete } = testcase; 66 67 [null, "unset", "initial", "inherit"].forEach(initialStyle => { 68 const scriptAnimation = target => { 69 return target.animate({ [property]: keyframes }, 1000); 70 } 71 checkUnanimatedComputedStyle(property, initialStyle, null, 72 expectedInitialStyle, expectedInitialStyle, 73 scriptAnimation, "script animation"); 74 75 const cssAnimationStyle = `@keyframes cssanimation {` 76 + ` from { ${property}: ${ keyframes[0] }; }` 77 + ` to { ${property}: ${ keyframes[1] }; } }`; 78 addStyle([cssAnimationStyle]); 79 const cssAnimation = target => { 80 target.style.animation = "cssanimation 1s"; 81 return target.getAnimations()[0]; 82 } 83 checkUnanimatedComputedStyle(property, initialStyle, null, 84 expectedInitialStyle, expectedInitialStyle, 85 cssAnimation, "CSS Animations"); 86 deleteStyle(); 87 88 // We don't support discrete animations for CSS Transitions yet. 89 // (bug 1320854) 90 if (!isDiscrete) { 91 const cssTransition = target => { 92 target.style[property] = keyframes[0]; 93 target.style.transition = 94 `${ property } 1s`; 95 window.getComputedStyle(target)[property]; 96 target.style[property] = keyframes[1]; 97 return target.getAnimations()[0]; 98 } 99 checkUnanimatedComputedStyle(property, initialStyle, null, 100 expectedInitialStyle, 101 expectedDuringTransitionStyle, 102 cssTransition, "CSS Transitions"); 103 } 104 105 addStyle([cssAnimationStyle, 106 ".pseudo::before { content: '' }", 107 ".animation::before { animation: cssanimation 1s }"]); 108 const pseudoAnimation = target => { 109 target.classList.add("animation"); 110 return target.getAnimations({ subtree: true })[0]; 111 } 112 checkUnanimatedComputedStyle(property, initialStyle, "::before", 113 expectedInitialStyle, expectedInitialStyle, 114 pseudoAnimation, "Animation at pseudo"); 115 deleteStyle(); 116 }); 117 }); 118 119 const div = document.createElement("div"); 120 document.body.appendChild(div); 121 122 SimpleTest.doesThrow( 123 () => utils.getUnanimatedComputedStyle(div, null, "background", utils.FLUSH_NONE), 124 "NS_ERROR_INVALID_ARG", 125 "Shorthand property should throw"); 126 127 SimpleTest.doesThrow( 128 () => utils.getUnanimatedComputedStyle(div, null, "invalid", utils.FLUSH_NONE), 129 "NS_ERROR_INVALID_ARG", 130 "Invalid property should throw"); 131 132 SimpleTest.doesThrow( 133 () => utils.getUnanimatedComputedStyle(null, null, "opacity", utils.FLUSH_NONE), 134 "NS_ERROR_INVALID_ARG", 135 "Null element should throw"); 136 137 SimpleTest.doesThrow( 138 () => utils.getUnanimatedComputedStyle(div, null, "opacity", utils.FLUSH_LAYOUT), 139 "NS_ERROR_INVALID_ARG", 140 "FLUSH_LAYOUT option should throw"); 141 142 SimpleTest.doesThrow( 143 () => utils.getUnanimatedComputedStyle(div, "::before", "opacity", utils.FLUSH_NONE), 144 "NS_ERROR_FAILURE", 145 "Non-existent pseudo should throw"); 146 147 // Flush styles since getUnanimatedComputedStyle flushes pending styles even 148 // with FLUSH_NONE option if the element hasn't yet styled. 149 getComputedStyle(div).opacity; 150 151 div.style.opacity = "0"; 152 is(utils.getUnanimatedComputedStyle(div, null, "opacity", utils.FLUSH_NONE), 153 "1", 154 "getUnanimatedComputedStyle with FLUSH_NONE should not flush pending styles"); 155 156 is(utils.getUnanimatedComputedStyle(div, null, "opacity", utils.FLUSH_STYLE), 157 "0", 158 "getUnanimatedComputedStyle with FLUSH_STYLE should flush pending styles"); 159 160 div.remove(); 161 162 test_needsFlushWithThrottledAnimations(); 163 } 164 165 function checkUnanimatedComputedStyle(property, initialStyle, pseudoType, 166 expectedBeforeAnimation, 167 expectedDuringAnimation, 168 animate, animationType) { 169 const div = document.createElement("div"); 170 document.body.appendChild(div); 171 172 if (initialStyle) { 173 div.style[property] = initialStyle; 174 } 175 if (pseudoType) { 176 div.classList.add("pseudo"); 177 } 178 179 is(utils.getUnanimatedComputedStyle(div, pseudoType, property, utils.FLUSH_STYLE), 180 expectedBeforeAnimation, 181 `'${ property }' property with '${ initialStyle }' style ` 182 + `should be '${ expectedBeforeAnimation }' ` 183 + `before animating by ${ animationType }`); 184 185 const animation = animate(div); 186 animation.currentTime = 500; 187 is(utils.getUnanimatedComputedStyle(div, pseudoType, property, utils.FLUSH_STYLE), 188 expectedDuringAnimation, 189 `'${ property }' property with '${ initialStyle }' style ` 190 + `should be '${ expectedDuringAnimation }' ` 191 + `even while animating by ${ animationType }`); 192 193 div.remove(); 194 } 195 196 function test_needsFlushWithThrottledAnimations() { 197 const div = document.createElement("div"); 198 div.style = "width: 100px; height: 100px; background-color: blue;"; 199 document.body.appendChild(div); 200 201 const animation = div.animate({ opacity: [ 0, 1 ] }, 202 { duration: 100000, iterations: Infinity }); 203 waitForAnimationReadyToRestyle(animation).then(() => { 204 ok(SpecialPowers.wrap(animation).isRunningOnCompositor, 205 "Opacity animation should run on the compositor"); 206 207 // FIXME! Bug 1442861: We should make sure needsFlush() returns true 208 // before flusing layout. 209 //ok(utils.needsFlush(SpecialPowers.Ci.nsIDOMWindowUtils.FLUSH_STYLE), 210 // "needsFlush should return true if there is an animation on the compositor"); 211 212 // Flush layout. 213 document.documentElement.getBoundingClientRect(); 214 215 ok(!utils.needsFlush(SpecialPowers.Ci.nsIDOMWindowUtils.FLUSH_STYLE), 216 "needsFlush should return false after flushing layout"); 217 218 div.remove(); 219 next(); 220 window.close(); 221 }); 222 } 223 224 window.addEventListener("load", test_getUnanimatedComputedStyle); 225 226 </script> 227 </body> 228 </html>