Source code
Revision control
Copy as Markdown
Other Tools
Test Info:
- Manifest: dom/svg/test/mochitest.toml
<!DOCTYPE html>
<!--
-->
<head>
<title>Test that cached stroked bounds track the element they came from</title>
<script src="/tests/SimpleTest/SimpleTest.js"></script>
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
</head>
<body>
<p id="display">
</p>
<div id="content" style="display: none"></div>
<pre id="test">
<script class="testbody" type="application/javascript">//<![CDATA[
SimpleTest.waitForExplicitFinish();
const BASE_D = "M 20 20 L 120 20 L 120 120";
const BOTH = { fill: true, stroke: true };
function makePath() {
const g = document.createElementNS(SVGNS, "g");
const path = document.createElementNS(SVGNS, "path");
path.setAttribute("d", BASE_D);
path.setAttribute("fill", "none");
path.setAttribute("stroke", "black");
path.setAttribute("stroke-width", "10");
g.appendChild(path);
document.getElementById("svg").appendChild(g);
return path;
}
function bbox(element) {
const b = element.getBBox(BOTH);
return [b.x, b.y, b.width, b.height].join(",");
}
function clientRect(element) {
const r = element.getBoundingClientRect();
return [r.x, r.y, r.width, r.height].join(",");
}
// Applies aMutate to an element whose stroked bounds have already been
// queried (so any cache is populated) and to one that has never been queried,
// and checks that both report the same bounds afterwards. A cache that is not
// invalidated by aMutate shows up as a mismatch.
function checkTracksMutation(aMutate, aMsg) {
const warm = makePath();
bbox(warm);
aMutate(warm);
const warmBBox = bbox(warm);
const cold = makePath();
aMutate(cold);
const coldBBox = bbox(cold);
is(warmBBox, coldBBox, "stroked bbox tracks " + aMsg);
warm.parentNode.remove();
cold.parentNode.remove();
}
// The stroked bounds are cached in the path's own space, so querying them
// under one transform must not affect what a later query under a different
// transform reports.
function checkTracksTransform(aAngle) {
const warm = makePath();
for (let angle = 0; angle < 360; angle += 37) {
warm.parentNode.setAttribute("transform", `rotate(${angle} 100 100)`);
warm.getBoundingClientRect();
}
warm.parentNode.setAttribute("transform", `rotate(${aAngle} 100 100)`);
const warmRect = clientRect(warm);
const cold = makePath();
cold.parentNode.setAttribute("transform", `rotate(${aAngle} 100 100)`);
const coldRect = clientRect(cold);
is(warmRect, coldRect, `stroked client rect at ${aAngle} degrees`);
warm.parentNode.remove();
cold.parentNode.remove();
}
function run() {
// A no-op mutation exercises the cache-hit path: warm and cold must still
// agree, otherwise the checks below prove nothing.
checkTracksMutation(() => {}, "an unchanged element");
checkTracksMutation(p => p.setAttribute("d", "M 20 20 L 200 20 L 200 60"),
"a 'd' attribute change");
checkTracksMutation(p => { p.style.d = 'path("M 20 20 L 200 20")'; },
"a CSS 'd' change");
checkTracksMutation(p => p.setAttribute("stroke-width", "30"),
"a stroke-width change");
checkTracksMutation(p => p.setAttribute("stroke-linecap", "square"),
"a stroke-linecap change");
checkTracksMutation(p => p.setAttribute("stroke-linejoin", "round"),
"a stroke-linejoin change");
checkTracksMutation(p => {
p.setAttribute("stroke-linejoin", "miter");
p.setAttribute("stroke-miterlimit", "1");
}, "a stroke-miterlimit change");
// getBBox ignores dashing, so this must not move the bounds, cached or not.
const dashed = makePath();
const undashed = bbox(dashed);
dashed.setAttribute("stroke-dasharray", "5 5");
is(bbox(dashed), undashed, "stroked bbox ignores stroke-dasharray");
dashed.parentNode.remove();
for (const angle of [0, 30, 90, 137, 180, 360]) {
checkTracksTransform(angle);
}
SimpleTest.finish();
}
window.addEventListener("load", () => {
SpecialPowers.pushPrefEnv(
{ set: [["svg.Moz2D.strokeBounds.enabled", true],
["svg.bounds-caching.enabled", true]] }, run);
});
//]]></script>
</pre>
</body>
</html>