diff options
Diffstat (limited to 'testing/web-platform/tests/svg/types/scripted/SVGGraphicsElement.getScreenCTM.html')
-rw-r--r-- | testing/web-platform/tests/svg/types/scripted/SVGGraphicsElement.getScreenCTM.html | 245 |
1 files changed, 245 insertions, 0 deletions
diff --git a/testing/web-platform/tests/svg/types/scripted/SVGGraphicsElement.getScreenCTM.html b/testing/web-platform/tests/svg/types/scripted/SVGGraphicsElement.getScreenCTM.html new file mode 100644 index 0000000000..7e5dfc649f --- /dev/null +++ b/testing/web-platform/tests/svg/types/scripted/SVGGraphicsElement.getScreenCTM.html @@ -0,0 +1,245 @@ +<!DOCTYPE html> +<html> +<head> + <title>SVGGraphicsElement.getScreenCTM</title> + <metadata> + <link rel="help" href="https://svgwg.org/svg2-draft/types.html#InterfaceSVGGraphicsElement"/> + </metadata> + <script src="../../linking/scripted/testcommon.js"></script> + <script src="/resources/testharness.js"></script> + <script src="/resources/testharnessreport.js"></script> +</head> +<body> +<style> + body { + margin: 8px; + } + .absPosAtTopLeft { + position: absolute; + top: 0; + left: 0; + } + .absPosMegaOffset { + position: absolute; + left: 1px; + top: 2px; + margin-left: 3px; + margin-top: 4px; + padding-left: 5px; + padding-top: 6px; + } + .svgMegaOffset { + margin-left: 7px; + margin-top: 8px; + padding-left: 9px; + padding-top: 10px; + } +</style> +<div style="transform: translate(50px, 50px)"> + <svg id="svg1" width="150" height="150"> + <rect id="rect1" fill="lime" x="50" y="50" width="100" height="100"/> + </svg> +</div> +<script> +/* Utility function to append an unstyled div to the body, with the + * div containing a 200x120 SVG element. */ +function make_subtree() { + let container = document.createElement("div"); + // Pass in "null" for test param, since we don't want this <svg> element + // to get autoremoved at cleanup time. (It's easier to debug test failures + // if we leave it in the DOM, for manual inspection in devtools.) + let svg = createSVGElement(null, "svg", container, + {width: 200, height: 120}); + document.body.appendChild(container); + return container; +} + +/* Utility function for checking a CTM matrix's components: */ +function assert_ctm_equals(actualCTM, expectedCTM) { + // Check every component for which an expected value was provided: + for (let key in expectedCTM) { + let actualVal = actualCTM[key]; + let expectedVal = expectedCTM[key]; + + // Special-case: browsers sometimes get `-0` in CTMs which + // is ~fine since it's numerically equivalent; but assert_equals + // treats it as different, which is why it needs special handling here + // (pretending the -0 was in fact 0), to avoid a spurious test-failure. + if (Object.is(expectedVal, 0) && Object.is(actualVal, -0)) { + actualVal = 0; + } + assert_equals(actualVal, expectedVal, `CTM component ${key}`); + } +} + +test(function() { + let pt = DOMPoint.fromPoint({x: 58, y: 58}); + let screenCTM = svg1.getScreenCTM(); + assert_ctm_equals(screenCTM, { a: 1, b: 0, + c: 0, d: 1, + e: 58, f: 58 }); + + let transformedPoint = pt.matrixTransform(screenCTM.inverse()); + assert_equals(transformedPoint.x, 0); + assert_equals(transformedPoint.y, 0); +}, "<svg> should give correct screen CTM for transform:translate(...) on " + + "ancestor elem, combined with margin on <body>"); + +test(function() { + let screenCTM = document.getElementById("rect1").getScreenCTM(); + assert_ctm_equals(screenCTM, { a: 1, b: 0, + c: 0, d: 1, + e: 58, f: 58 }); +}, "<rect> should give correct screen CTM for transform:translate(...) on " + + "ancestor elem, combined with margin on <body>"); + +test(function() { + let container = make_subtree(); + let svg = container.firstChild; + container.style.transform = "scale(2,1)"; + + // First four CTM components should encode the scaleX=2 and scaleY=1. + // (The other two depend on where the SVG ended up on the page and + // are dependent on its in-flow position, so we're not bothering to + // check them here, but we will in the next part.) + let screenCTM = svg.getScreenCTM(); + assert_ctm_equals(screenCTM, { a: 2, b: 0, + c: 0, d: 1 }); + + // Now we make the container abspos so that we can reliably predict the + // position: + container.classList.add("absPosAtTopLeft"); + + // First four CTM components should still encode those same scale factors. + // The last two components should now encode a -100px translateX, since + // (starting with the SVG positioned at the screen's origin) we've scaled up + // the container by 2x in the horizontal axis, about its own center point, + // which shifts half of its original width (100px) off the left side of the + // screen. + screenCTM = svg.getScreenCTM(); + assert_ctm_equals(screenCTM, { a: 2, b: 0, + c: 0, d: 1, + e: -100, f: 0 }); +}, "<svg> should give correct screen CTM for transform:scale(2,1) on ancestor"); + +test(function() { + let container = make_subtree(); + let svg = container.firstChild; + + container.classList.add("absPosAtTopLeft"); + svg.style.transform = "scale(0.5)"; + + // First four CTM components should encode the scale(0.5). The last two + // components should encode a translation inwards by 1/4 of the <svg>'s + // size in each axis, since we're shrinking by 1/2 about the center point. + // (1/4 of the 200px width is 50px, and 1/4 of the 120px height is 30px) + let screenCTM = svg.getScreenCTM(); + assert_ctm_equals(screenCTM, { a: 0.5, b: 0, + c: 0, d: 0.5, + e: 50, f: 30 }); +}, "<svg> should give correct screen CTM for transform:scale(0.5) on self"); + +test(function() { + let container = make_subtree(); + let svg = container.firstChild; + + container.classList.add("absPosMegaOffset"); + container.style.transform = "translate(20px, 30px)"; + svg.classList.add("svgMegaOffset"); + svg.style.transform = "translate(40px, 50px)"; + + // Expecting CTM to have: + // * identity matrix for scale components + // * translateX component of 1+3+5+7+9+20+40 = 85 + // * translateY component of 2+4+6+8+10+30+50 = 110 + let screenCTM = svg.getScreenCTM(); + assert_ctm_equals(screenCTM, { a: 1, b: 0, + c: 0, d: 1, + e: 85, f: 110 }); +}, "<svg> should give correct screen CTM with many forms of offsets on " + + "ancestor and self"); + +test(function() { + let container = make_subtree(); + let svg = container.firstChild; + // Note: in cases where the SVG is rotated, we have to override + // the default 'vertical-align:baseline' to avoid having our flipped + // y-position be influenced by baseline-related offsets that come from + // the line box. + svg.style.verticalAlign = "top"; + container.classList.add("absPosAtTopLeft"); + + container.style.transform = "rotate(90deg)"; + svg.style.transform = "rotate(270deg)"; + let screenCTM = svg.getScreenCTM(); + assert_ctm_equals(screenCTM, { a: 1, b: 0, + c: 0, d: 1, + e: 0, f: 0 }); + + container.style.transform = "rotate(270deg)"; + svg.style.transform = "rotate(90deg)"; + screenCTM = svg.getScreenCTM(); + assert_ctm_equals(screenCTM, { a: 1, b: 0, + c: 0, d: 1, + e: 0, f: 0 }); + + container.style.transform = "rotate(180deg)"; + svg.style.transform = "rotate(180deg)"; + screenCTM = svg.getScreenCTM(); + assert_ctm_equals(screenCTM, { a: 1, b: 0, + c: 0, d: 1, + e: 0, f: 0 }); +}, "<svg> should give identity screen CTM with friendly rotations on " + + "ancestor and self that add up to 360deg"); + +test(function() { + let container = make_subtree(); + let svg = container.firstChild; + container.classList.add("absPosAtTopLeft"); + svg.classList.add("svgMegaOffset"); + container.style.transform = "rotate(180deg)"; + svg.style.verticalAlign = "top"; + + // Expecting CTM to have: + // * "flip" matrix for scale components (-1 instead of 1) + // * translateX component of 200px, which comes from our 200px width. + // * translateY component of 70px, which comes from our 120px height. + // Note that our "svgMegaOffset" offsets have no effect on our CTM, because + // they end up on the right side when the SVG rotates about its border-box's + // center point, so they don't influence where the SVG geometry actually ends + // up in the screen's coordinate space and are hence irrelevant to the CTM. + let screenCTM = svg.getScreenCTM(); + assert_ctm_equals(screenCTM, { a: -1, b: 0, + c: 0, d: -1, + e: 200, f: 120 }); +}, "<svg> should give correct screen CTM with many forms of offsets on " + + "self, and rotated self"); + +test(function() { + let container = make_subtree(); + let svg = container.firstChild; + container.classList.add("absPosAtTopLeft"); + container.style.transform = "rotate(180deg)"; + svg.classList.add("svgMegaOffset"); + svg.style.transform = "translate(40px, 50px)"; + svg.style.verticalAlign = "top"; + + // Expecting CTM to have: + // * "flip" matrix for scale components (-1 instead of 1) + // * translateX component of 160px, which comes from the 40px in our + // "translate(40px,50px), taken as a reduction from our 200px width. + // * translateY component of 70px, which comes from the 50px in our + // "translate(40px,50px), taken as a reduction from our 120px height. + // Note that our "svgMegaOffset" offsets have no effect on our CTM, because + // they end up on the right side when our ancestor rotates about its center + // point, so they end up irrelevant to our CTM. + let screenCTM = svg.getScreenCTM(); + assert_ctm_equals(screenCTM, { a: -1, b: 0, + c: 0, d: -1, + e: 160, f: 70 }); +}, "<svg> should give correct screen CTM with many forms of offsets on " + + "self, and rotated ancestor"); + +</script> +</body> +</html> |