summaryrefslogtreecommitdiffstats
path: root/dom/svg/test/test_SVGTransformList.xhtml
diff options
context:
space:
mode:
Diffstat (limited to 'dom/svg/test/test_SVGTransformList.xhtml')
-rw-r--r--dom/svg/test/test_SVGTransformList.xhtml461
1 files changed, 461 insertions, 0 deletions
diff --git a/dom/svg/test/test_SVGTransformList.xhtml b/dom/svg/test/test_SVGTransformList.xhtml
new file mode 100644
index 0000000000..3e1cd7b8bb
--- /dev/null
+++ b/dom/svg/test/test_SVGTransformList.xhtml
@@ -0,0 +1,461 @@
+<html xmlns="http://www.w3.org/1999/xhtml">
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=602759
+-->
+<head>
+ <title>Tests specific to SVGTransformList</title>
+ <script src="/tests/SimpleTest/SimpleTest.js"></script>
+ <script type="text/javascript" src="matrixUtils.js"></script>
+ <script type="text/javascript" src="MutationEventChecker.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
+</head>
+<body>
+<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=602759">
+ Mozilla Bug 602759</a>
+<p id="display"></p>
+<div id="content" style="display:none;">
+<svg id="svg" xmlns="http://www.w3.org/2000/svg" width="100" height="100"
+ onload="this.pauseAnimations();">
+ <g id="g"/>
+</svg>
+</div>
+<pre id="test">
+<script class="testbody" type="text/javascript">
+<![CDATA[
+
+SimpleTest.waitForExplicitFinish();
+
+/*
+This file runs a series of SVGTransformList specific tests. Generic SVGXxxList
+tests can be found in test_SVGxxxList.xhtml. Anything that can be generalized
+to other list types belongs there.
+*/
+
+function main() {
+ var g = $("g");
+ var tests =
+ [ testConsolidateMatrix,
+ testConsolidateMatrixOneElem,
+ testConsolidateMatrixZeroElem,
+ testCreateSVGTransformFromMatrix,
+ testReadOnly,
+ testOrphan,
+ testFailedSet,
+ testMutationEvents,
+ ];
+ for (var i = 0; i < tests.length; i++) {
+ tests[i](g);
+ }
+ SimpleTest.finish();
+}
+
+function testConsolidateMatrix(g) {
+ // This is the example from SVG 1.1 section 7.5
+ g.setAttribute("transform",
+ "translate(50 90) rotate(-45) translate(130 160)");
+ var list = g.transform.baseVal;
+ is(list.numberOfItems, 3, "Unexpected length of unconsolidated list");
+
+ // Sanity check -- take ref to first item in list and validate it
+ var first_item = list.getItem(0);
+ is(first_item.type, SVGTransform.SVG_TRANSFORM_TRANSLATE,
+ "Unexpected type of first item in list");
+ cmpMatrix(first_item.matrix, [1, 0, 0, 1, 50, 90],
+ "Unexpected value for first item in list");
+
+ // Consolidate
+ var consolidated = list.consolidate();
+ is(list.numberOfItems, 1, "Unexpected length of consolidated list");
+ ok(consolidated === list.getItem(0),
+ "Consolidate return value should be first item in list, not a copy");
+ is(consolidated.type, SVGTransform.SVG_TRANSFORM_MATRIX,
+ "Consolidated transform not of type matrix");
+ const angle = -Math.PI / 4;
+ roughCmpMatrix(consolidated.matrix,
+ [Math.cos(angle), Math.sin(angle),
+ -Math.sin(angle), Math.cos(angle),
+ 130 * Math.cos(angle) - 160 * Math.sin(angle) + 50,
+ 160 * Math.cos(angle) + 130 * Math.sin(angle) + 90],
+ "Unexpected result after consolidating matrices");
+
+ // Check ref to first item in list
+ // a) should not have changed
+ is(first_item.type, SVGTransform.SVG_TRANSFORM_TRANSLATE,
+ "Unexpected type of cached first item in list after consolidating");
+ cmpMatrix(first_item.matrix, [1, 0, 0, 1, 50, 90],
+ "Unexpected value for cached first item in list after consolidating");
+ // b) should still be usable
+ first_item.setScale(2, 3);
+ is(first_item.type, SVGTransform.SVG_TRANSFORM_SCALE,
+ "Cached first item in list not usable after consolidating");
+
+ // Check consolidated is live
+ // a) Changes to 'consolidated' affect list
+ consolidated.setSkewX(45);
+ is(list.getItem(0).type, SVGTransform.SVG_TRANSFORM_SKEWX,
+ "Changing return value from consolidate doesn't affect list");
+ // b) Changes to list affect 'consolidated'
+ list.getItem(0).setRotate(90, 0, 0);
+ is(consolidated.type, SVGTransform.SVG_TRANSFORM_ROTATE,
+ "Changing list doesn't affect return value from consolidate");
+}
+
+function testConsolidateMatrixOneElem(g) {
+ // Check that even if we only have one item in the list it becomes a matrix
+ // transform (as per the spec)
+ g.setAttribute("transform", "translate(50 90)");
+ var list = g.transform.baseVal;
+ is(list.numberOfItems, 1, "Unexpected length of unconsolidated list");
+ var first_item = list.getItem(0);
+ is(first_item.type, SVGTransform.SVG_TRANSFORM_TRANSLATE,
+ "Unexpected type of first item in list");
+ cmpMatrix(first_item.matrix, [1, 0, 0, 1, 50, 90],
+ "Unexpected value for first item in list");
+
+ // Consolidate
+ var consolidated = list.consolidate();
+ is(list.numberOfItems, 1, "Unexpected length of consolidated list");
+ ok(consolidated === list.getItem(0),
+ "Consolidate return value should be first item in list, not a copy");
+ is(consolidated.type, SVGTransform.SVG_TRANSFORM_MATRIX,
+ "Consolidated transform not of type matrix");
+ cmpMatrix(consolidated.matrix, [1, 0, 0, 1, 50, 90],
+ "Unexpected consolidated matrix value");
+}
+
+function testConsolidateMatrixZeroElem(g) {
+ // Check that zero items returns null
+ g.setAttribute("transform", "");
+ var list = g.transform.baseVal;
+ is(list.numberOfItems, 0, "Unexpected length of unconsolidated list");
+ var consolidated = list.consolidate();
+ ok(consolidated === null,
+ "consolidate() should return null for a zero-length transform list");
+}
+
+function testCreateSVGTransformFromMatrix(g) {
+ var m = createMatrix(1, 2, 3, 4, 5, 6);
+
+ // "Creates an SVGTransform object which is initialized to transform of type
+ // SVG_TRANSFORM_MATRIX and whose values are the given matrix. The values from
+ // the parameter matrix are copied, the matrix parameter is not adopted as
+ // SVGTransform::matrix."
+ var list = g.transform.baseVal;
+ list.clear();
+ var t = list.createSVGTransformFromMatrix(m);
+
+ // Check that list hasn't changed
+ is(list.numberOfItems, 0,
+ "Transform list changed after calling createSVGTransformFromMatrix");
+
+ // Check return value
+ is(t.type, SVGTransform.SVG_TRANSFORM_MATRIX,
+ "Returned transform not of type matrix");
+ cmpMatrix(t.matrix, [1, 2, 3, 4, 5, 6],
+ "Unexpected returned matrix value");
+
+ // Check values are copied
+ ok(t.matrix != m, "Matrix should be copied not adopted");
+ m.a = 2;
+ is(t.matrix.a, 1,
+ "Changing source matrix should not affect newly created transform");
+
+ // null should give us an identity matrix
+ t = list.createSVGTransformFromMatrix(null);
+ cmpMatrix(t.matrix, [1, 0, 0, 1, 0, 0],
+ "Unexpected returned matrix value");
+
+ // Try passing in bad values ("undefined" etc.)
+ let exception = null;
+ try {
+ t = list.createSVGTransformFromMatrix("undefined");
+ } catch (e) { exception = e; }
+ ok(exception,
+ "Failed to throw for string input to createSVGTransformFromMatrix");
+ exception = null;
+ try {
+ t = list.createSVGTransformFromMatrix(SVGMatrix(t));
+ } catch (e) { exception = e; }
+ ok(exception,
+ "Failed to throw for bad input to createSVGTransformFromMatrix");
+ exception = null;
+}
+
+function testReadOnly(g) {
+ var SVG_NS = "http://www.w3.org/2000/svg";
+
+ // Just some data to work with
+ g.setAttribute("transform", "translate(50 90)");
+
+ // baseVal / animVal are readonly attributes
+ // Create another (empty) transform list
+ var otherg = document.createElementNS(SVG_NS, "g");
+ g.parentNode.appendChild(otherg);
+ is(g.transform.baseVal.numberOfItems, 1,
+ "Unexpected number of items in transform list before attempting to set");
+ is(otherg.transform.baseVal.numberOfItems, 0,
+ "Unexpected number of items in source transform list before attempting to"
+ + " set");
+ // Attempt to set the base value and check nothing changes
+ g.transform.baseVal = otherg.transform.baseVal;
+ is(g.transform.baseVal.numberOfItems, 1,
+ "baseVal should be read-only but its value has changed");
+ is(otherg.transform.baseVal.numberOfItems, 0,
+ "baseVal changed after attempting to use it set another value");
+
+ // Read-only SVGTransformList:
+ // Standard list methods are covered in test_SVGxxxList.xhtml so here we
+ // just add tests for SVGTransformList-specific methods
+ var roList = g.transform.animVal;
+ // consolidate()
+ var threw = false;
+ try {
+ roList.consolidate();
+ } catch (e) {
+ is(e.name, "NoModificationAllowedError",
+ "Got unexpected exception " + e +
+ ", expected NoModificationAllowedError");
+ is(e.code, DOMException.NO_MODIFICATION_ALLOWED_ERR,
+ "Got unexpected exception " + e +
+ ", expected NO_MODIFICATION_ALLOWED_ERR");
+ threw = true;
+ }
+ ok(threw,
+ "Failed to throw exception when calling consolidate on read-only list");
+
+ // Read-only SVGTransform:
+ // read-only attributes are tested in test_transform.xhtml. Here we are
+ // concerned with methods that throw because this *object* is read-only
+ // (since it belongs to a read-only transform list)
+ var roTransform = roList.getItem(0);
+ // setMatrix
+ threw = false;
+ try {
+ var m = createMatrix(1, 2, 3, 4, 5, 6);
+ roTransform.setMatrix(m);
+ } catch (e) {
+ is(e.name, "NoModificationAllowedError",
+ "Got unexpected exception " + e +
+ ", expected NoModificationAllowedError");
+ is(e.code, DOMException.NO_MODIFICATION_ALLOWED_ERR,
+ "Got unexpected exception " + e +
+ ", expected NO_MODIFICATION_ALLOWED_ERR");
+ threw = true;
+ }
+ ok(threw, "Failed to throw exception when calling setMatrix on read-only"
+ + " transform");
+ // setTranslate
+ threw = false;
+ try {
+ roTransform.setTranslate(2, 3);
+ } catch (e) {
+ threw = true;
+ }
+ ok(threw, "Failed to throw when calling setTranslate on read-only"
+ + " transform");
+ // setScale
+ threw = false;
+ try {
+ roTransform.setScale(2, 3);
+ } catch (e) {
+ threw = true;
+ }
+ ok(threw, "Failed to throw when calling setScale on read-only transform");
+ // setRotate
+ threw = false;
+ try {
+ roTransform.setRotate(1, 2, 3);
+ } catch (e) {
+ threw = true;
+ }
+ ok(threw, "Failed to throw when calling setRotate on read-only transform");
+ // setSkewX
+ threw = false;
+ try {
+ roTransform.setSkewX(2);
+ } catch (e) {
+ threw = true;
+ }
+ ok(threw, "Failed to throw when calling setSkewX on read-only transform");
+ // setSkewY
+ threw = false;
+ try {
+ roTransform.setSkewY(2);
+ } catch (e) {
+ threw = true;
+ }
+ ok(threw, "Failed to throw when calling setSkewY on read-only transform");
+
+ // Read-only SVGMatrix
+ var roMatrix = roTransform.matrix;
+ threw = false;
+ try {
+ roMatrix.a = 1;
+ } catch (e) {
+ is(e.name, "NoModificationAllowedError",
+ "Got unexpected exception " + e +
+ ", expected NoModificationAllowedError");
+ is(e.code, DOMException.NO_MODIFICATION_ALLOWED_ERR,
+ "Got unexpected exception " + e +
+ ", expected NO_MODIFICATION_ALLOWED_ERR");
+ threw = true;
+ }
+ ok(threw, "Failed to throw exception when modifying read-only matrix");
+}
+
+function testOrphan(g) {
+ // Although this isn't defined, if a read-only object becomes orphaned
+ // (detached from it's parent), then presumably it should become editable
+ // again.
+
+ // As with the read-only test set a value to test with
+ g.setAttribute("transform", "translate(50 90)");
+
+ var roList = g.transform.animVal;
+ var roTransform = roList.getItem(0);
+ var roMatrix = roTransform.matrix;
+
+ // Orphan transform list contents by re-setting transform attribute
+ g.setAttribute("transform", "");
+
+ // Transform should now be editable
+ var exception = null;
+ try {
+ roTransform.setTranslate(5, 3);
+ } catch (e) {
+ exception = e;
+ }
+ ok(exception === null,
+ "Unexpected exception " + exception + " modifying orphaned transform");
+
+ // So should matrix
+ exception = null;
+ try {
+ roMatrix.a = 1;
+ } catch (e) {
+ exception = e;
+ }
+ ok(exception === null,
+ "Unexpected exception " + exception + " modifying orphaned matrix");
+}
+
+function testFailedSet(g) {
+ // Check that a parse failure results in the attribute being empty
+
+ // Set initial value
+ g.setAttribute("transform", "translate(50 90)");
+ var list = g.transform.baseVal;
+ is(list.numberOfItems, 1, "Unexpected initial length of list");
+
+ // Attempt to set bad value
+ g.setAttribute("transform", "translate(40 50) scale(a)");
+ is(list.numberOfItems, 0,
+ "Transform list should be empty after setting bad value");
+ is(g.transform.animVal.numberOfItems, 0,
+ "Animated transform list should also be empty after setting bad value");
+}
+
+function testMutationEvents(g) {
+ // Check mutation events
+
+ // Set initial value
+ g.setAttribute("transform", "translate(50 90)");
+ var list = g.transform.baseVal;
+ is(list.numberOfItems, 1, "Unexpected initial length of list");
+ var eventChecker = new MutationEventChecker;
+ eventChecker.watchAttr(g, "transform");
+
+ // consolidate
+ //
+ // Consolidate happens to generate two modification events in our
+ // implementation--it's not ideal but it's better than none
+ eventChecker.expect("modify modify modify");
+ g.setAttribute("transform", "translate(10 10) translate(10 10)");
+ list.consolidate();
+
+ // In the following, each of the operations is performed twice but only one
+ // mutation event is expected. This is to check that redundant mutation
+ // events are not sent.
+
+ // transform.setMatrix
+ eventChecker.expect("modify");
+ var mx = $("svg").createSVGMatrix();
+ list[0].setMatrix(mx);
+ list[0].setMatrix(mx);
+ [
+ {a: 1, m11: 2},
+ {a: Infinity},
+ {b: 0, m12: -1},
+ {c: Infinity, m21: -Infinity},
+ {d: 0, m22: NaN},
+ {e: 1, m41: 1.00000001},
+ {f: 0, m42: Number.MIN_VALUE},
+ ].forEach(dict => {
+ let exception = null;
+ try {
+ list[0].setMatrix(dict);
+ } catch (e) {
+ exception = e;
+ }
+ ok(exception,
+ "Failed to throw for invalid input to setMatrix");
+ });
+
+ // transform.setTranslate
+ eventChecker.expect("modify");
+ list[0].setTranslate(10, 10);
+ list[0].setTranslate(10, 10);
+
+ // transform.setScale
+ eventChecker.expect("modify");
+ list[0].setScale(2, 2);
+ list[0].setScale(2, 2);
+
+ // transform.setRotate
+ eventChecker.expect("modify");
+ list[0].setRotate(45, 1, 2);
+ list[0].setRotate(45, 1, 2);
+
+ // transform.setSkewX
+ eventChecker.expect("modify");
+ list[0].setSkewX(45);
+ list[0].setSkewX(45);
+
+ // transform.setSkewY
+ eventChecker.expect("modify");
+ list[0].setSkewY(25);
+ list[0].setSkewY(25);
+
+ // transform.matrix
+ eventChecker.expect("modify modify");
+ list[0].matrix.a = 1;
+ list[0].matrix.a = 1;
+ list[0].matrix.e = 5;
+ list[0].matrix.e = 5;
+
+ // setAttribute interaction
+ eventChecker.expect("modify");
+ list[0].setMatrix(mx);
+ eventChecker.expect("");
+ g.setAttribute("transform", "matrix(1, 0, 0, 1, 0, 0)");
+ list[0].setMatrix(mx);
+
+ // Attribute removal
+ eventChecker.expect("remove");
+ g.removeAttribute("transform");
+
+ // Non-existent attribute removal
+ eventChecker.expect("");
+ g.removeAttribute("transform");
+ g.removeAttributeNS(null, "transform");
+
+ eventChecker.finish();
+}
+
+window.addEventListener("load", main);
+
+]]>
+</script>
+</pre>
+</body>
+</html>