Bug 1943761 - Add class alignment to the mozsearch analysis file. r=asuth
[gecko.git] / dom / svg / test / test_SVGTransformList.xhtml
blob73c0327a48e87c3481dbe929f383a7b57dc402a3
1 <html xmlns="http://www.w3.org/1999/xhtml">
2 <!--
3 https://bugzilla.mozilla.org/show_bug.cgi?id=602759
4 -->
5 <head>
6 <title>Tests specific to SVGTransformList</title>
7 <script src="/tests/SimpleTest/SimpleTest.js"></script>
8 <script type="text/javascript" src="matrixUtils.js"></script>
9 <script type="text/javascript" src="MutationEventChecker.js"></script>
10 <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
11 </head>
12 <body>
13 <a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=602759">
14 Mozilla Bug 602759</a>
15 <p id="display"></p>
16 <div id="content" style="display:none;">
17 <svg id="svg" xmlns="http://www.w3.org/2000/svg" width="100" height="100"
18 onload="this.pauseAnimations();">
19 <g id="g"/>
20 </svg>
21 </div>
22 <pre id="test">
23 <script class="testbody" type="text/javascript">
24 <![CDATA[
26 SimpleTest.waitForExplicitFinish();
29 This file runs a series of SVGTransformList specific tests. Generic SVGXxxList
30 tests can be found in test_SVGxxxList.xhtml. Anything that can be generalized
31 to other list types belongs there.
34 function main() {
35 var g = $("g");
36 var tests =
37 [ testConsolidateMatrix,
38 testConsolidateMatrixOneElem,
39 testConsolidateMatrixZeroElem,
40 testCreateSVGTransformFromMatrix,
41 testReadOnly,
42 testOrphan,
43 testFailedSet,
44 testMutationEvents,
46 for (var i = 0; i < tests.length; i++) {
47 tests[i](g);
49 SimpleTest.finish();
52 function testConsolidateMatrix(g) {
53 // This is the example from SVG 1.1 section 7.5
54 g.setAttribute("transform",
55 "translate(50 90) rotate(-45) translate(130 160)");
56 var list = g.transform.baseVal;
57 is(list.numberOfItems, 3, "Unexpected length of unconsolidated list");
59 // Sanity check -- take ref to first item in list and validate it
60 var first_item = list.getItem(0);
61 is(first_item.type, SVGTransform.SVG_TRANSFORM_TRANSLATE,
62 "Unexpected type of first item in list");
63 cmpMatrix(first_item.matrix, [1, 0, 0, 1, 50, 90],
64 "Unexpected value for first item in list");
66 // Consolidate
67 var consolidated = list.consolidate();
68 is(list.numberOfItems, 1, "Unexpected length of consolidated list");
69 ok(consolidated === list.getItem(0),
70 "Consolidate return value should be first item in list, not a copy");
71 is(consolidated.type, SVGTransform.SVG_TRANSFORM_MATRIX,
72 "Consolidated transform not of type matrix");
73 const angle = -Math.PI / 4;
74 roughCmpMatrix(consolidated.matrix,
75 [Math.cos(angle), Math.sin(angle),
76 -Math.sin(angle), Math.cos(angle),
77 130 * Math.cos(angle) - 160 * Math.sin(angle) + 50,
78 160 * Math.cos(angle) + 130 * Math.sin(angle) + 90],
79 "Unexpected result after consolidating matrices");
81 // Check ref to first item in list
82 // a) should not have changed
83 is(first_item.type, SVGTransform.SVG_TRANSFORM_TRANSLATE,
84 "Unexpected type of cached first item in list after consolidating");
85 cmpMatrix(first_item.matrix, [1, 0, 0, 1, 50, 90],
86 "Unexpected value for cached first item in list after consolidating");
87 // b) should still be usable
88 first_item.setScale(2, 3);
89 is(first_item.type, SVGTransform.SVG_TRANSFORM_SCALE,
90 "Cached first item in list not usable after consolidating");
92 // Check consolidated is live
93 // a) Changes to 'consolidated' affect list
94 consolidated.setSkewX(45);
95 is(list.getItem(0).type, SVGTransform.SVG_TRANSFORM_SKEWX,
96 "Changing return value from consolidate doesn't affect list");
97 // b) Changes to list affect 'consolidated'
98 list.getItem(0).setRotate(90, 0, 0);
99 is(consolidated.type, SVGTransform.SVG_TRANSFORM_ROTATE,
100 "Changing list doesn't affect return value from consolidate");
103 function testConsolidateMatrixOneElem(g) {
104 // Check that even if we only have one item in the list it becomes a matrix
105 // transform (as per the spec)
106 g.setAttribute("transform", "translate(50 90)");
107 var list = g.transform.baseVal;
108 is(list.numberOfItems, 1, "Unexpected length of unconsolidated list");
109 var first_item = list.getItem(0);
110 is(first_item.type, SVGTransform.SVG_TRANSFORM_TRANSLATE,
111 "Unexpected type of first item in list");
112 cmpMatrix(first_item.matrix, [1, 0, 0, 1, 50, 90],
113 "Unexpected value for first item in list");
115 // Consolidate
116 var consolidated = list.consolidate();
117 is(list.numberOfItems, 1, "Unexpected length of consolidated list");
118 ok(consolidated === list.getItem(0),
119 "Consolidate return value should be first item in list, not a copy");
120 is(consolidated.type, SVGTransform.SVG_TRANSFORM_MATRIX,
121 "Consolidated transform not of type matrix");
122 cmpMatrix(consolidated.matrix, [1, 0, 0, 1, 50, 90],
123 "Unexpected consolidated matrix value");
126 function testConsolidateMatrixZeroElem(g) {
127 // Check that zero items returns null
128 g.setAttribute("transform", "");
129 var list = g.transform.baseVal;
130 is(list.numberOfItems, 0, "Unexpected length of unconsolidated list");
131 var consolidated = list.consolidate();
132 ok(consolidated === null,
133 "consolidate() should return null for a zero-length transform list");
136 function testCreateSVGTransformFromMatrix(g) {
137 var m = createMatrix(1, 2, 3, 4, 5, 6);
139 // "Creates an SVGTransform object which is initialized to transform of type
140 // SVG_TRANSFORM_MATRIX and whose values are the given matrix. The values from
141 // the parameter matrix are copied, the matrix parameter is not adopted as
142 // SVGTransform::matrix."
143 var list = g.transform.baseVal;
144 list.clear();
145 var t = list.createSVGTransformFromMatrix(m);
147 // Check that list hasn't changed
148 is(list.numberOfItems, 0,
149 "Transform list changed after calling createSVGTransformFromMatrix");
151 // Check return value
152 is(t.type, SVGTransform.SVG_TRANSFORM_MATRIX,
153 "Returned transform not of type matrix");
154 cmpMatrix(t.matrix, [1, 2, 3, 4, 5, 6],
155 "Unexpected returned matrix value");
157 // Check values are copied
158 ok(t.matrix != m, "Matrix should be copied not adopted");
159 m.a = 2;
160 is(t.matrix.a, 1,
161 "Changing source matrix should not affect newly created transform");
163 // null should give us an identity matrix
164 t = list.createSVGTransformFromMatrix(null);
165 cmpMatrix(t.matrix, [1, 0, 0, 1, 0, 0],
166 "Unexpected returned matrix value");
168 // Try passing in bad values ("undefined" etc.)
169 let exception = null;
170 try {
171 t = list.createSVGTransformFromMatrix("undefined");
172 } catch (e) { exception = e; }
173 ok(exception,
174 "Failed to throw for string input to createSVGTransformFromMatrix");
175 exception = null;
176 try {
177 t = list.createSVGTransformFromMatrix(SVGMatrix(t));
178 } catch (e) { exception = e; }
179 ok(exception,
180 "Failed to throw for bad input to createSVGTransformFromMatrix");
181 exception = null;
184 function testReadOnly(g) {
185 var SVG_NS = "http://www.w3.org/2000/svg";
187 // Just some data to work with
188 g.setAttribute("transform", "translate(50 90)");
190 // baseVal / animVal are readonly attributes
191 // Create another (empty) transform list
192 var otherg = document.createElementNS(SVG_NS, "g");
193 g.parentNode.appendChild(otherg);
194 is(g.transform.baseVal.numberOfItems, 1,
195 "Unexpected number of items in transform list before attempting to set");
196 is(otherg.transform.baseVal.numberOfItems, 0,
197 "Unexpected number of items in source transform list before attempting to"
198 + " set");
199 // Attempt to set the base value and check nothing changes
200 g.transform.baseVal = otherg.transform.baseVal;
201 is(g.transform.baseVal.numberOfItems, 1,
202 "baseVal should be read-only but its value has changed");
203 is(otherg.transform.baseVal.numberOfItems, 0,
204 "baseVal changed after attempting to use it set another value");
206 // Read-only SVGTransformList:
207 // Standard list methods are covered in test_SVGxxxList.xhtml so here we
208 // just add tests for SVGTransformList-specific methods
209 var roList = g.transform.animVal;
210 // consolidate()
211 var threw = false;
212 try {
213 roList.consolidate();
214 } catch (e) {
215 is(e.name, "NoModificationAllowedError",
216 "Got unexpected exception " + e +
217 ", expected NoModificationAllowedError");
218 is(e.code, DOMException.NO_MODIFICATION_ALLOWED_ERR,
219 "Got unexpected exception " + e +
220 ", expected NO_MODIFICATION_ALLOWED_ERR");
221 threw = true;
223 ok(threw,
224 "Failed to throw exception when calling consolidate on read-only list");
226 // Read-only SVGTransform:
227 // read-only attributes are tested in test_transform.xhtml. Here we are
228 // concerned with methods that throw because this *object* is read-only
229 // (since it belongs to a read-only transform list)
230 var roTransform = roList.getItem(0);
231 // setMatrix
232 threw = false;
233 try {
234 var m = createMatrix(1, 2, 3, 4, 5, 6);
235 roTransform.setMatrix(m);
236 } catch (e) {
237 is(e.name, "NoModificationAllowedError",
238 "Got unexpected exception " + e +
239 ", expected NoModificationAllowedError");
240 is(e.code, DOMException.NO_MODIFICATION_ALLOWED_ERR,
241 "Got unexpected exception " + e +
242 ", expected NO_MODIFICATION_ALLOWED_ERR");
243 threw = true;
245 ok(threw, "Failed to throw exception when calling setMatrix on read-only"
246 + " transform");
247 // setTranslate
248 threw = false;
249 try {
250 roTransform.setTranslate(2, 3);
251 } catch (e) {
252 threw = true;
254 ok(threw, "Failed to throw when calling setTranslate on read-only"
255 + " transform");
256 // setScale
257 threw = false;
258 try {
259 roTransform.setScale(2, 3);
260 } catch (e) {
261 threw = true;
263 ok(threw, "Failed to throw when calling setScale on read-only transform");
264 // setRotate
265 threw = false;
266 try {
267 roTransform.setRotate(1, 2, 3);
268 } catch (e) {
269 threw = true;
271 ok(threw, "Failed to throw when calling setRotate on read-only transform");
272 // setSkewX
273 threw = false;
274 try {
275 roTransform.setSkewX(2);
276 } catch (e) {
277 threw = true;
279 ok(threw, "Failed to throw when calling setSkewX on read-only transform");
280 // setSkewY
281 threw = false;
282 try {
283 roTransform.setSkewY(2);
284 } catch (e) {
285 threw = true;
287 ok(threw, "Failed to throw when calling setSkewY on read-only transform");
289 // Read-only SVGMatrix
290 var roMatrix = roTransform.matrix;
291 threw = false;
292 try {
293 roMatrix.a = 1;
294 } catch (e) {
295 is(e.name, "NoModificationAllowedError",
296 "Got unexpected exception " + e +
297 ", expected NoModificationAllowedError");
298 is(e.code, DOMException.NO_MODIFICATION_ALLOWED_ERR,
299 "Got unexpected exception " + e +
300 ", expected NO_MODIFICATION_ALLOWED_ERR");
301 threw = true;
303 ok(threw, "Failed to throw exception when modifying read-only matrix");
306 function testOrphan(g) {
307 // Although this isn't defined, if a read-only object becomes orphaned
308 // (detached from it's parent), then presumably it should become editable
309 // again.
311 // As with the read-only test set a value to test with
312 g.setAttribute("transform", "translate(50 90)");
314 var roList = g.transform.animVal;
315 var roTransform = roList.getItem(0);
316 var roMatrix = roTransform.matrix;
318 // Orphan transform list contents by re-setting transform attribute
319 g.setAttribute("transform", "");
321 // Transform should now be editable
322 var exception = null;
323 try {
324 roTransform.setTranslate(5, 3);
325 } catch (e) {
326 exception = e;
328 ok(exception === null,
329 "Unexpected exception " + exception + " modifying orphaned transform");
331 // So should matrix
332 exception = null;
333 try {
334 roMatrix.a = 1;
335 } catch (e) {
336 exception = e;
338 ok(exception === null,
339 "Unexpected exception " + exception + " modifying orphaned matrix");
342 function testFailedSet(g) {
343 // Check that a parse failure results in the attribute being empty
345 // Set initial value
346 g.setAttribute("transform", "translate(50 90)");
347 var list = g.transform.baseVal;
348 is(list.numberOfItems, 1, "Unexpected initial length of list");
350 // Attempt to set bad value
351 g.setAttribute("transform", "translate(40 50) scale(a)");
352 is(list.numberOfItems, 0,
353 "Transform list should be empty after setting bad value");
354 is(g.transform.animVal.numberOfItems, 0,
355 "Animated transform list should also be empty after setting bad value");
358 function testMutationEvents(g) {
359 // Check mutation events
361 // Set initial value
362 g.setAttribute("transform", "translate(50 90)");
363 var list = g.transform.baseVal;
364 is(list.numberOfItems, 1, "Unexpected initial length of list");
365 var eventChecker = new MutationEventChecker;
366 eventChecker.watchAttr(g, "transform");
368 // consolidate
370 // Consolidate happens to generate two modification events in our
371 // implementation--it's not ideal but it's better than none
372 eventChecker.expect("modify modify modify");
373 g.setAttribute("transform", "translate(10 10) translate(10 10)");
374 list.consolidate();
376 // In the following, each of the operations is performed twice but only one
377 // mutation event is expected. This is to check that redundant mutation
378 // events are not sent.
380 // transform.setMatrix
381 eventChecker.expect("modify");
382 var mx = $("svg").createSVGMatrix();
383 list[0].setMatrix(mx);
384 list[0].setMatrix(mx);
386 {a: 1, m11: 2},
387 {a: Infinity},
388 {b: 0, m12: -1},
389 {c: Infinity, m21: -Infinity},
390 {d: 0, m22: NaN},
391 {e: 1, m41: 1.00000001},
392 {f: 0, m42: Number.MIN_VALUE},
393 ].forEach(dict => {
394 let exception = null;
395 try {
396 list[0].setMatrix(dict);
397 } catch (e) {
398 exception = e;
400 ok(exception,
401 "Failed to throw for invalid input to setMatrix");
404 // transform.setTranslate
405 eventChecker.expect("modify");
406 list[0].setTranslate(10, 10);
407 list[0].setTranslate(10, 10);
409 // transform.setScale
410 eventChecker.expect("modify");
411 list[0].setScale(2, 2);
412 list[0].setScale(2, 2);
414 // transform.setRotate
415 eventChecker.expect("modify");
416 list[0].setRotate(45, 1, 2);
417 list[0].setRotate(45, 1, 2);
419 // transform.setSkewX
420 eventChecker.expect("modify");
421 list[0].setSkewX(45);
422 list[0].setSkewX(45);
424 // transform.setSkewY
425 eventChecker.expect("modify");
426 list[0].setSkewY(25);
427 list[0].setSkewY(25);
429 // transform.matrix
430 eventChecker.expect("modify modify");
431 list[0].matrix.a = 1;
432 list[0].matrix.a = 1;
433 list[0].matrix.e = 5;
434 list[0].matrix.e = 5;
436 // setAttribute interaction
437 eventChecker.expect("modify");
438 list[0].setMatrix(mx);
439 eventChecker.expect("");
440 g.setAttribute("transform", "matrix(1, 0, 0, 1, 0, 0)");
441 list[0].setMatrix(mx);
443 // Attribute removal
444 eventChecker.expect("remove");
445 g.removeAttribute("transform");
447 // Non-existent attribute removal
448 eventChecker.expect("");
449 g.removeAttribute("transform");
450 g.removeAttributeNS(null, "transform");
452 eventChecker.finish();
455 window.addEventListener("load",
456 () => SpecialPowers.pushPrefEnv({"set": [["dom.mutation_events.enabled", true]]}, main));
459 </script>
460 </pre>
461 </body>
462 </html>