dom/smil/test/test_smilChangeAfterFrozen.xhtml

branch
TOR_BUG_3246
changeset 7
129ffea94266
equal deleted inserted replaced
-1:000000000000 0:e69da281c8b8
1 <html xmlns="http://www.w3.org/1999/xhtml">
2 <head>
3 <title>Test for SMIL when things change after an animation is frozen</title>
4 <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
5 <script type="text/javascript" src="smilTestUtils.js"></script>
6 <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
7 </head>
8 <body>
9 <a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=533291">Mozilla Bug 533291</a>
10 <p id="display"></p>
11 <!-- Bug 628848: The following should be display: none but we currently don't
12 handle percentage lengths properly when the whole fragment is display: none
13 -->
14 <div id="content" style="visibility: hidden">
15 <svg id="svg" xmlns="http://www.w3.org/2000/svg" width="120px" height="120px"
16 onload="this.pauseAnimations()">
17 <g id="circleParent">
18 <circle cx="0" cy="20" r="15" fill="blue" id="circle"/>
19 </g>
20 </svg>
21 </div>
22 <pre id="test">
23 <script class="testbody" type="text/javascript">
24 <![CDATA[
25 /** Test for SMIL values that are context-sensitive **/
26
27 /* See bugs 533291 and 562815.
28
29 The format of each test is basically:
30 1) create some animated and frozen state
31 2) test the animated values
32 3) change the context
33 4) test that context-sensitive animation values have changed
34
35 Ideally, after changing the context (3), the animated state would instantly
36 update. However, this is not currently the case for many situations.
37
38 For CSS properties we have bug 545282 - In animations involving 'inherit'
39 / 'currentColor', changes to inherited value / 'color' don't show up in
40 animated value immediately
41
42 For SVG lengths we have bug 508206 - Relative units used in
43 animation don't update immediately
44
45 (There are a few of todo_is's in the following tests so that if those bugs
46 are ever resolved we'll know to update this test case accordingly.)
47
48 So in between (3) and (4) we force a sample. This is currently done by
49 calling SVGSVGElement.setCurrentTime with the same current time which has the
50 side effect of forcing a sample.
51
52 What we *are* testing is that we're not too zealous with caching animation
53 values whilst in the frozen state. Normally we'd say, "Hey, we're frozen,
54 let's just use the same animation result as last time" but for some
55 context-sensitive animation values that doesn't work.
56 */
57
58 /* Global Variables */
59 const SVGNS = "http://www.w3.org/2000/svg";
60
61 // Animation parameters -- not used for <set> animation
62 const ANIM_DUR = "4s";
63 const TIME_ANIM_END = "4";
64 const TIME_AFTER_ANIM_END = "5";
65
66 const gSvg = document.getElementById("svg");
67 const gCircle = document.getElementById("circle");
68 const gCircleParent = document.getElementById("circleParent");
69
70 SimpleTest.waitForExplicitFinish();
71
72 // MAIN FUNCTION
73 // -------------
74
75 function main()
76 {
77 ok(gSvg.animationsPaused(), "should be paused by <svg> load handler");
78 is(gSvg.getCurrentTime(), 0, "should be paused at 0 in <svg> load handler");
79
80 const tests =
81 [ testBaseValueChange,
82 testCurrentColorChange,
83 testCurrentColorChangeUsingStyle,
84 testCurrentColorChangeOnFallback,
85 testInheritChange,
86 testInheritChangeUsingStyle,
87 testEmUnitChangeOnProp,
88 testEmUnitChangeOnPropBase,
89 testEmUnitChangeOnLength,
90 testPercentUnitChangeOnProp,
91 testPercentUnitChangeOnLength,
92 testRelativeFontSize,
93 testRelativeFontWeight,
94 testRelativeFont,
95 testCalcFontSize,
96 testDashArray,
97 testClip
98 ];
99
100 while (tests.length) {
101 tests.shift()();
102 }
103 SimpleTest.finish();
104 }
105
106 // HELPER FUNCTIONS
107 // ----------------
108 function createAnimSetTo(attrName, toVal)
109 {
110 var anim = document.createElementNS(SVGNS,"set");
111 anim.setAttribute("attributeName", attrName);
112 anim.setAttribute("to", toVal);
113 return gCircle.appendChild(anim);
114 }
115
116 function createAnimBy(attrName, byVal)
117 {
118 var anim = document.createElementNS(SVGNS,"animate");
119 anim.setAttribute("attributeName", attrName);
120 anim.setAttribute("dur", ANIM_DUR);
121 anim.setAttribute("begin","0s");
122 anim.setAttribute("by", byVal);
123 anim.setAttribute("fill", "freeze");
124 return gCircle.appendChild(anim);
125 }
126
127 function createAnimFromTo(attrName, fromVal, toVal)
128 {
129 var anim = document.createElementNS(SVGNS,"animate");
130 anim.setAttribute("attributeName", attrName);
131 anim.setAttribute("dur", ANIM_DUR);
132 anim.setAttribute("begin","0s");
133 anim.setAttribute("from", fromVal);
134 anim.setAttribute("to", toVal);
135 anim.setAttribute("fill", "freeze");
136 return gCircle.appendChild(anim);
137 }
138
139 // Common setup code for each test function: seek to 0, and make sure
140 // the previous test cleaned up its animations.
141 function setupTest() {
142 gSvg.setCurrentTime(0);
143 if (gCircle.firstChild) {
144 ok(false, "Previous test didn't clean up after itself.");
145 }
146 }
147
148 // THE TESTS
149 // ---------
150
151 function testBaseValueChange()
152 {
153 setupTest();
154 var anim = createAnimBy("cx", "50");
155 gSvg.setCurrentTime(TIME_ANIM_END);
156 is(gCircle.cx.animVal.value, 50,
157 "Checking animated cx as anim ends");
158
159 gSvg.setCurrentTime(TIME_AFTER_ANIM_END);
160 is(gCircle.cx.animVal.value, 50,
161 "Checking animated cx after anim ends");
162
163 gCircle.setAttribute("cx", 20);
164 is(gCircle.cx.animVal.value, 70,
165 "Checking animated cx after anim ends & after changing base val");
166
167 anim.parentNode.removeChild(anim); // clean up
168 }
169
170 function testCurrentColorChange()
171 {
172 gCircle.setAttribute("color", "red"); // At first: currentColor=red
173 var anim = createAnimSetTo("fill", "currentColor");
174
175 gSvg.setCurrentTime(0); // trigger synchronous sample
176 is(SMILUtil.getComputedStyleSimple(gCircle, "fill"), "rgb(255, 0, 0)",
177 "Checking animated fill=currentColor after animating");
178
179 gCircle.setAttribute("color", "lime"); // Change: currentColor=lime
180 // Bug 545282: We should really detect this change and update immediately but
181 // currently we don't until we get sampled again
182 todo_is(SMILUtil.getComputedStyleSimple(gCircle, "fill"), "rgb(0, 255, 0)",
183 "Checking animated fill=currentColor after updating context but before " +
184 "sampling");
185 gSvg.setCurrentTime(0);
186 is(SMILUtil.getComputedStyleSimple(gCircle, "fill"), "rgb(0, 255, 0)",
187 "Checking animated fill=currentColor after updating context");
188
189 // Clean up
190 gCircle.removeAttribute("color");
191 gCircle.removeChild(gCircle.firstChild);
192 }
193
194 function testCurrentColorChangeUsingStyle()
195 {
196 setupTest();
197 gCircle.setAttribute("style", "color: red"); // At first: currentColor=red
198 var anim = createAnimSetTo("fill", "currentColor");
199
200 gSvg.setCurrentTime(0);
201 is(SMILUtil.getComputedStyleSimple(gCircle, "fill"), "rgb(255, 0, 0)",
202 "Checking animated fill=currentColor after animating (using style attr)");
203
204 gCircle.setAttribute("style", "color: lime"); // Change: currentColor=lime
205 gSvg.setCurrentTime(0);
206 is(SMILUtil.getComputedStyleSimple(gCircle, "fill"), "rgb(0, 255, 0)",
207 "Checking animated fill=currentColor after updating context "
208 + "(using style attr)");
209
210 // Clean up
211 gCircle.removeAttribute("style");
212 gCircle.removeChild(gCircle.firstChild);
213 }
214
215 function getFallbackColor(pServerStr)
216 {
217 return pServerStr.substr(pServerStr.indexOf(" ")+1);
218 }
219
220 function testCurrentColorChangeOnFallback()
221 {
222 setupTest();
223 gCircle.setAttribute("color", "red"); // At first: currentColor=red
224 var anim = createAnimSetTo("fill", "url(#missingGrad) currentColor");
225
226 gSvg.setCurrentTime(0);
227 var fallback =
228 getFallbackColor(SMILUtil.getComputedStyleSimple(gCircle, "fill"));
229 is(fallback, "rgb(255, 0, 0)",
230 "Checking animated fallback fill=currentColor after animating");
231
232 gCircle.setAttribute("color", "lime"); // Change: currentColor=lime
233 gSvg.setCurrentTime(0);
234 fallback = getFallbackColor(SMILUtil.getComputedStyleSimple(gCircle, "fill"));
235 is(fallback, "rgb(0, 255, 0)",
236 "Checking animated fallback fill=currentColor after updating context");
237
238 gCircle.removeAttribute("style");
239 gCircle.removeChild(gCircle.firstChild);
240 }
241
242 function testInheritChange()
243 {
244 setupTest();
245 gCircleParent.setAttribute("fill", "red"); // At first: inherit=red
246 var anim = createAnimSetTo("fill", "inherit");
247
248 gSvg.setCurrentTime(0);
249 is(SMILUtil.getComputedStyleSimple(gCircle, "fill"), "rgb(255, 0, 0)",
250 "Checking animated fill=inherit after animating");
251
252 gCircleParent.setAttribute("fill", "lime"); // Change: inherit=lime
253 gSvg.setCurrentTime(0);
254 is(SMILUtil.getComputedStyleSimple(gCircle, "fill"), "rgb(0, 255, 0)",
255 "Checking animated fill=inherit after updating context");
256
257 gCircleParent.removeAttribute("fill");
258 gCircle.removeChild(gCircle.firstChild);
259 }
260
261 function testInheritChangeUsingStyle()
262 {
263 setupTest();
264 gCircleParent.setAttribute("style", "fill: red"); // At first: inherit=red
265 var anim = createAnimSetTo("fill", "inherit");
266
267 gSvg.setCurrentTime(0);
268 is(SMILUtil.getComputedStyleSimple(gCircle, "fill"), "rgb(255, 0, 0)",
269 "Checking animated fill=inherit after animating (using style attr)");
270
271 gCircleParent.setAttribute("style", "fill: lime"); // Change: inherit=lime
272 gSvg.setCurrentTime(0);
273 is(SMILUtil.getComputedStyleSimple(gCircle, "fill"), "rgb(0, 255, 0)",
274 "Checking animated fill=inherit after updating context "
275 + "(using style attr)");
276
277 gCircleParent.removeAttribute("style");
278 gCircle.removeChild(gCircle.firstChild);
279 }
280
281 function testEmUnitChangeOnProp()
282 {
283 setupTest();
284 gCircleParent.setAttribute("font-size", "10px"); // At first: font-size: 10px
285 var anim = createAnimSetTo("font-size", "2em");
286
287 gSvg.setCurrentTime(0);
288 is(SMILUtil.getComputedStyleSimple(gCircle, "font-size"), "20px",
289 "Checking animated font-size=2em after animating ends");
290
291 gCircleParent.setAttribute("font-size", "20px"); // Change: font-size: 20px
292 gSvg.setCurrentTime(0);
293 is(SMILUtil.getComputedStyleSimple(gCircle, "font-size"), "40px",
294 "Checking animated font-size=2em after updating context");
295
296 gCircleParent.removeAttribute("font-size");
297 gCircle.removeChild(gCircle.firstChild);
298 }
299
300 function testEmUnitChangeOnPropBase()
301 {
302 // Test the case where the base value for our animation sandwich is
303 // context-sensitive.
304 // Currently, this is taken care of by the compositor which keeps a cached
305 // base value and compares it with the current base value. This test then just
306 // serves as a regression test in case the compositor's behaviour changes.
307 setupTest();
308 gSvg.setAttribute("font-size", "10px"); // At first: font-size: 10px
309 gCircleParent.setAttribute("font-size", "1em"); // Base: 10px
310 var anim = createAnimBy("font-size", "10px");
311
312 gSvg.setCurrentTime(TIME_AFTER_ANIM_END);
313 is(SMILUtil.getComputedStyleSimple(gCircle, "font-size"), "20px",
314 "Checking animated font-size=20px after anim ends");
315
316 gSvg.setAttribute("font-size", "20px"); // Change: font-size: 20px
317 gSvg.setCurrentTime(TIME_AFTER_ANIM_END);
318 is(SMILUtil.getComputedStyleSimple(gCircle, "font-size"), "30px",
319 "Checking animated font-size=30px after updating context");
320
321 gCircleParent.removeAttribute("font-size");
322 gCircle.removeChild(gCircle.firstChild);
323 }
324
325 function testEmUnitChangeOnLength()
326 {
327 setupTest();
328 gCircleParent.setAttribute("font-size", "10px"); // At first: font-size: 10px
329 var anim = createAnimSetTo("cx", "2em");
330
331 gSvg.setCurrentTime(0);
332 is(gCircle.cx.animVal.value, 20,
333 "Checking animated length=2em after animating");
334
335 gCircleParent.setAttribute("font-size", "20px"); // Change: font-size: 20px
336 // Bug 508206: We should really detect this change and update immediately but
337 // currently we don't until we get sampled again
338 todo_is(gCircle.cx.animVal.value, 40,
339 "Checking animated length=2em after updating context but before sampling");
340
341 gSvg.setCurrentTime(0);
342 is(gCircle.cx.animVal.value, 40,
343 "Checking animated length=2em after updating context and after " +
344 "resampling");
345
346 gCircleParent.removeAttribute("font-size");
347 gCircle.removeChild(gCircle.firstChild);
348 }
349
350 function testPercentUnitChangeOnProp()
351 {
352 setupTest();
353 gCircleParent.setAttribute("font-size", "10px"); // At first: font-size: 10px
354 var anim = createAnimSetTo("font-size", "150%");
355
356 gSvg.setCurrentTime(0);
357 is(SMILUtil.getComputedStyleSimple(gCircle, "font-size"), "15px",
358 "Checking animated font-size=150% after animating");
359
360 gCircleParent.setAttribute("font-size", "20px"); // Change: font-size: 20px
361 gSvg.setCurrentTime(0);
362 is(SMILUtil.getComputedStyleSimple(gCircle, "font-size"), "30px",
363 "Checking animated font-size=150% after updating context");
364
365 gCircleParent.removeAttribute("font-size");
366 gCircle.removeChild(gCircle.firstChild);
367 }
368
369 function testPercentUnitChangeOnLength()
370 {
371 setupTest();
372 var oldHeight = gSvg.getAttribute("height");
373 gSvg.setAttribute("height", "100px"); // At first: viewport height: 100px
374 var anim = createAnimSetTo("cy", "100%");
375
376 gSvg.setCurrentTime(0); // Force synchronous sample so animation takes effect
377 // Due to bug 627594 (SVGLength.value for percent value lengths doesn't
378 // reflect updated viewport until reflow) the following will fail.
379 // Check that it does indeed fail so that when that bug is fixed this test
380 // can be updated.
381 todo_is(gCircle.cy.animVal.value, 100,
382 "Checking animated length=100% after animating but before reflow");
383 gSvg.forceRedraw();
384 // Even after doing a reflow though we'll still fail due to bug 508206
385 // (Relative units used in animation don't update immediately)
386 todo_is(gCircle.cy.animVal.value, 100,
387 "Checking animated length=100% after animating but before resampling");
388 gSvg.setCurrentTime(0);
389 // Now we should be up to date
390 is(gCircle.cy.animVal.value, 100,
391 "Checking animated length=100% after animating");
392
393 gSvg.setAttribute("height", "50px"); // Change: height: 50px
394 gSvg.forceRedraw(); // Bug 627594
395 gSvg.setCurrentTime(0); // Bug 508206
396 is(gCircle.cy.animVal.value, 50,
397 "Checking animated length=100% after updating context");
398
399 gSvg.setAttribute("height", oldHeight);
400 gCircle.removeChild(gCircle.firstChild);
401 }
402
403 function testRelativeFontSize()
404 {
405 setupTest();
406 gCircleParent.setAttribute("font-size", "10px"); // At first: font-size: 10px
407 var anim = createAnimSetTo("font-size", "larger");
408
409 gSvg.setCurrentTime(0);
410 var fsize = parseInt(SMILUtil.getComputedStyleSimple(gCircle, "font-size"));
411 // CSS 2 suggests a scaling factor of 1.2 so we should be looking at something
412 // around about 12 or so
413 ok(fsize > 10 && fsize < 20,
414 "Checking animated font-size > 10px after animating");
415
416 gCircleParent.setAttribute("font-size", "20px"); // Change: font-size: 20px
417 gSvg.setCurrentTime(0);
418 fsize = parseInt(SMILUtil.getComputedStyleSimple(gCircle, "font-size"));
419 ok(fsize > 20, "Checking animated font-size > 20px after updating context");
420
421 gCircleParent.removeAttribute("font-size");
422 gCircle.removeChild(gCircle.firstChild);
423 }
424
425 function testRelativeFontWeight()
426 {
427 setupTest();
428 gCircleParent.setAttribute("font-weight", "100"); // At first: font-weight 100
429 var anim = createAnimSetTo("font-weight", "bolder");
430 // CSS 2: 'bolder': Specifies the next weight that is assigned to a font
431 // that is darker than the inherited one. If there is no such weight, it
432 // simply results in the next darker numerical value (and the font remains
433 // unchanged), unless the inherited value was '900', in which case the
434 // resulting weight is also '900'.
435
436 gSvg.setCurrentTime(0);
437 var weight =
438 parseInt(SMILUtil.getComputedStyleSimple(gCircle, "font-weight"));
439 ok(weight > 100, "Checking animated font-weight > 100 after animating");
440
441 gCircleParent.setAttribute("font-weight", "800"); // Change: font-weight 800
442 gSvg.setCurrentTime(0);
443 weight = parseInt(SMILUtil.getComputedStyleSimple(gCircle, "font-weight"));
444 is(weight, 900,
445 "Checking animated font-weight = 900 after updating context");
446
447 gCircleParent.removeAttribute("font-weight");
448 gCircle.removeChild(gCircle.firstChild);
449 }
450
451 function testRelativeFont()
452 {
453 // Test a relative font-size as part of a 'font' spec since the code path
454 // is different in this case
455 // It turns out that, due to the way we store shorthand font properties, we
456 // don't need to worry about marking such values as context-sensitive since we
457 // seem to store them in their relative form. If, however, we change the way
458 // we store shorthand font properties in the future, this will serve as
459 // a useful regression test.
460 setupTest();
461 gCircleParent.setAttribute("font-size", "10px"); // At first: font-size: 10px
462 // We must be sure to set every part of the shorthand property to some
463 // non-context sensitive value because we want to test that even if only the
464 // font-size is relative we will update it appropriately.
465 var anim =
466 createAnimSetTo("font", "normal normal bold larger/normal sans-serif");
467
468 gSvg.setCurrentTime(0);
469 var fsize = parseInt(SMILUtil.getComputedStyleSimple(gCircle, "font-size"));
470 ok(fsize > 10 && fsize < 20,
471 "Checking size of shorthand 'font' > 10px after animating");
472
473 gCircleParent.setAttribute("font-size", "20px"); // Change: font-size: 20px
474 gSvg.setCurrentTime(0);
475 fsize = parseInt(SMILUtil.getComputedStyleSimple(gCircle, "font-size"));
476 ok(fsize > 20,
477 "Checking size of shorthand 'font' > 20px after updating context");
478
479 gCircleParent.removeAttribute("font-size");
480 gCircle.removeChild(gCircle.firstChild);
481 }
482
483 function testCalcFontSize()
484 {
485 setupTest();
486 gCircleParent.setAttribute("font-size", "10px"); // At first: font-size: 10px
487 var anim = createAnimSetTo("font-size", "-moz-calc(110% + 0.1em)");
488
489 gSvg.setCurrentTime(0);
490 var fsize = parseInt(SMILUtil.getComputedStyleSimple(gCircle, "font-size"));
491 // Font size should be 1.1 * 10px + 0.1 * 10px = 12
492 is(fsize, 12, "Checking animated calc font-size == 12px after animating");
493
494 gCircleParent.setAttribute("font-size", "20px"); // Change: font-size: 20px
495 gSvg.setCurrentTime(0);
496 fsize = parseInt(SMILUtil.getComputedStyleSimple(gCircle, "font-size"));
497 is(fsize, 24, "Checking animated calc font-size == 24px after updating " +
498 "context");
499
500 gCircleParent.removeAttribute("font-size");
501 gCircle.removeChild(gCircle.firstChild);
502 }
503
504 function testDashArray()
505 {
506 // stroke dasharrays don't currently convert units--but if someone ever fixes
507 // that, hopefully this test will fail and remind us not to cache percentage
508 // values in that case
509 setupTest();
510 var oldHeight = gSvg.getAttribute("height");
511 var oldWidth = gSvg.getAttribute("width");
512 gSvg.setAttribute("height", "100px"); // At first: viewport: 100x100px
513 gSvg.setAttribute("width", "100px");
514 var anim = createAnimFromTo("stroke-dasharray", "0 5", "0 50%");
515
516 gSvg.setCurrentTime(TIME_AFTER_ANIM_END);
517
518 // Now we should be up to date
519 is(SMILUtil.getComputedStyleSimple(gCircle, "stroke-dasharray"), "0, 50%",
520 "Checking animated stroke-dasharray after animating");
521
522 gSvg.setAttribute("height", "50px"); // Change viewport: 50x50px
523 gSvg.setAttribute("width", "50px");
524 gSvg.setCurrentTime(TIME_AFTER_ANIM_END);
525 is(SMILUtil.getComputedStyleSimple(gCircle, "stroke-dasharray"), "0, 50%",
526 "Checking animated stroke-dasharray after updating context");
527
528 gSvg.setAttribute("height", oldHeight);
529 gSvg.setAttribute("width", oldWidth);
530 gCircle.removeChild(gCircle.firstChild);
531 }
532
533 function testClip()
534 {
535 setupTest();
536 gCircleParent.setAttribute("font-size", "20px"); // At first: font-size: 20px
537
538 // The clip property only applies to elements that establish a new
539 // viewport so we need to create a nested svg and add animation to that
540 var nestedSVG = document.createElementNS(SVGNS, "svg");
541 nestedSVG.setAttribute("clip", "rect(0px 0px 0px 0px)");
542 gCircleParent.appendChild(nestedSVG);
543
544 var anim = createAnimSetTo("clip", "rect(1em 1em 1em 1em)");
545 // createAnimSetTo will make the animation a child of gCircle so we need to
546 // move it so it targets nestedSVG instead
547 nestedSVG.appendChild(anim);
548
549 gSvg.setCurrentTime(TIME_AFTER_ANIM_END);
550 is(SMILUtil.getComputedStyleSimple(nestedSVG, "clip"),
551 "rect(20px, 20px, 20px, 20px)",
552 "Checking animated clip rect after animating");
553
554 gCircleParent.setAttribute("font-size", "10px"); // Change: font-size: 10px
555 gSvg.setCurrentTime(TIME_AFTER_ANIM_END);
556 is(SMILUtil.getComputedStyleSimple(nestedSVG, "clip"),
557 "rect(10px, 10px, 10px, 10px)",
558 "Checking animated clip rect after updating context");
559
560 gCircleParent.removeAttribute("font-size");
561 gCircleParent.removeChild(nestedSVG);
562 }
563
564 window.addEventListener("load", main, false);
565 ]]>
566 </script>
567 </pre>
568 </body>
569 </html>

mercurial