зеркало из https://github.com/mozilla/gecko-dev.git
455 строки
14 KiB
HTML
455 строки
14 KiB
HTML
<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 type="text/javascript" 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 useable
|
|
first_item.setScale(2, 3);
|
|
is(first_item.type, SVGTransform.SVG_TRANSFORM_SCALE,
|
|
"Cached first item in list not useable 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");
|
|
|
|
// Try passing in bad values (null, "undefined" etc.)
|
|
var exception = null;
|
|
try {
|
|
t = list.createSVGTransformFromMatrix(null);
|
|
} catch(e) { exception = e; }
|
|
ok(exception,
|
|
"Failed to throw for null input to createSVGTransformFromMatrix");
|
|
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");
|
|
uexception = null;
|
|
|
|
// 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");
|
|
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);
|
|
|
|
// 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>
|