1 <html xmlns=
"http://www.w3.org/1999/xhtml">
3 https://bugzilla.mozilla.org/show_bug.cgi?id=602759
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" />
13 <a target=
"_blank" href=
"https://bugzilla.mozilla.org/show_bug.cgi?id=602759">
14 Mozilla Bug
602759</a>
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();">
23 <script class=
"testbody" type=
"text/javascript">
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.
37 [ testConsolidateMatrix,
38 testConsolidateMatrixOneElem,
39 testConsolidateMatrixZeroElem,
40 testCreateSVGTransformFromMatrix,
46 for (var i =
0; i < tests.length; i++) {
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");
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");
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;
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");
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;
171 t = list.createSVGTransformFromMatrix(
"undefined");
172 } catch (e) { exception = e; }
174 "Failed to throw for string input to createSVGTransformFromMatrix");
177 t = list.createSVGTransformFromMatrix(SVGMatrix(t));
178 } catch (e) { exception = e; }
180 "Failed to throw for bad input to createSVGTransformFromMatrix");
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"
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;
213 roList.consolidate();
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");
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);
234 var m = createMatrix(
1,
2,
3,
4,
5,
6);
235 roTransform.setMatrix(m);
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");
245 ok(threw,
"Failed to throw exception when calling setMatrix on read-only"
250 roTransform.setTranslate(
2,
3);
254 ok(threw,
"Failed to throw when calling setTranslate on read-only"
259 roTransform.setScale(
2,
3);
263 ok(threw,
"Failed to throw when calling setScale on read-only transform");
267 roTransform.setRotate(
1,
2,
3);
271 ok(threw,
"Failed to throw when calling setRotate on read-only transform");
275 roTransform.setSkewX(
2);
279 ok(threw,
"Failed to throw when calling setSkewX on read-only transform");
283 roTransform.setSkewY(
2);
287 ok(threw,
"Failed to throw when calling setSkewY on read-only transform");
289 // Read-only SVGMatrix
290 var roMatrix = roTransform.matrix;
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");
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
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;
324 roTransform.setTranslate(
5,
3);
328 ok(exception === null,
329 "Unexpected exception " + exception +
" modifying orphaned transform");
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
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
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");
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)");
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);
389 {c: Infinity, m21: -Infinity},
391 {e:
1, m41:
1.00000001},
392 {f:
0, m42: Number.MIN_VALUE},
394 let exception = null;
396 list[
0].setMatrix(dict);
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);
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);
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));