Bug 1683652 - Clear cached path when reframed. r=longsonr

The issue here is caused (a bit surprisingly) by the counter-reset
declaration.

The underlying issue is that counter-reset causes us to rebuild the
frame tree for the whole `<body>`, in order to rebuild the counter tree.

That makes the geometry frame not get its updated style (because the
frame goes away), and the next frame getting constructed getting a null
aOldComputedStyle (as expected, as it's a new frame).

We can't rely on the cached path not to change while there's no frame,
so clear it out when there's no old style.

The test is a simpler version of the test-case, where instead of
`counter-reset`, I use `display: none` to trigger the bogus codepath.

Differential Revision: https://phabricator.services.mozilla.com/D100237
This commit is contained in:
Emilio Cobos Álvarez 2020-12-21 14:34:18 +00:00
parent fdedcdeece
commit 4ec02c259b
3 changed files with 54 additions and 31 deletions

View File

@ -151,12 +151,11 @@ already_AddRefed<Path> SVGCircleElement::BuildPath(PathBuilder* aBuilder) {
bool SVGCircleElement::IsLengthChangedViaCSS(const ComputedStyle& aNewStyle,
const ComputedStyle& aOldStyle) {
auto *newSVGReset = aNewStyle.StyleSVGReset(),
*oldSVGReset = aOldStyle.StyleSVGReset();
const auto& newSVGReset = *aNewStyle.StyleSVGReset();
const auto& oldSVGReset = *aOldStyle.StyleSVGReset();
return newSVGReset->mCx != oldSVGReset->mCx ||
newSVGReset->mCy != oldSVGReset->mCy ||
newSVGReset->mR != oldSVGReset->mR;
return newSVGReset.mCx != oldSVGReset.mCx ||
newSVGReset.mCy != oldSVGReset.mCy || newSVGReset.mR != oldSVGReset.mR;
}
nsCSSPropertyID SVGCircleElement::GetCSSPropertyIdForAttrEnum(

View File

@ -136,37 +136,37 @@ nsresult SVGGeometryFrame::AttributeChanged(int32_t aNameSpaceID,
/* virtual */
void SVGGeometryFrame::DidSetComputedStyle(ComputedStyle* aOldComputedStyle) {
nsIFrame::DidSetComputedStyle(aOldComputedStyle);
auto* element = static_cast<SVGGeometryElement*>(GetContent());
if (!aOldComputedStyle) {
element->ClearAnyCachedPath();
return;
}
if (aOldComputedStyle) {
SVGGeometryElement* element =
static_cast<SVGGeometryElement*>(GetContent());
const auto* oldStyleSVG = aOldComputedStyle->StyleSVG();
if (!SVGContentUtils::ShapeTypeHasNoCorners(GetContent())) {
if (StyleSVG()->mStrokeLinecap != oldStyleSVG->mStrokeLinecap &&
element->IsSVGElement(nsGkAtoms::path)) {
// If the stroke-linecap changes to or from "butt" then our element
// needs to update its cached Moz2D Path, since SVGPathData::BuildPath
// decides whether or not to insert little lines into the path for zero
// length subpaths base on that property.
const auto* oldStyleSVG = aOldComputedStyle->StyleSVG();
if (!SVGContentUtils::ShapeTypeHasNoCorners(GetContent())) {
if (StyleSVG()->mStrokeLinecap != oldStyleSVG->mStrokeLinecap &&
element->IsSVGElement(nsGkAtoms::path)) {
// If the stroke-linecap changes to or from "butt" then our element
// needs to update its cached Moz2D Path, since SVGPathData::BuildPath
// decides whether or not to insert little lines into the path for zero
// length subpaths base on that property.
element->ClearAnyCachedPath();
} else if (HasAnyStateBits(NS_STATE_SVG_CLIPPATH_CHILD)) {
if (StyleSVG()->mClipRule != oldStyleSVG->mClipRule) {
// Moz2D Path objects are fill-rule specific.
// For clipPath we use clip-rule as the path's fill-rule.
element->ClearAnyCachedPath();
}
} else {
if (StyleSVG()->mFillRule != oldStyleSVG->mFillRule) {
// Moz2D Path objects are fill-rule specific.
element->ClearAnyCachedPath();
} else if (HasAnyStateBits(NS_STATE_SVG_CLIPPATH_CHILD)) {
if (StyleSVG()->mClipRule != oldStyleSVG->mClipRule) {
// Moz2D Path objects are fill-rule specific.
// For clipPath we use clip-rule as the path's fill-rule.
element->ClearAnyCachedPath();
}
} else {
if (StyleSVG()->mFillRule != oldStyleSVG->mFillRule) {
// Moz2D Path objects are fill-rule specific.
element->ClearAnyCachedPath();
}
}
}
}
if (element->IsGeometryChangedViaCSS(*Style(), *aOldComputedStyle)) {
element->ClearAnyCachedPath();
}
if (element->IsGeometryChangedViaCSS(*Style(), *aOldComputedStyle)) {
element->ClearAnyCachedPath();
}
}

View File

@ -0,0 +1,24 @@
<svg width="340" height="140"
xmlns="http://www.w3.org/2000/svg"
xmlns:html="http://www.w3.org/1999/xhtml">
<title>Circle coordinates and radius specified by properties</title>
<html:link rel="help" href="https://svgwg.org/svg2-draft/geometry.html"/>
<html:link rel="help" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1683652"/>
<html:link rel="match" href="circle-ref.svg"/>
<style>
circle {
cx: 204px;
cy: 56px;
r: 5px;
fill: blue;
}
</style>
<circle />
<script><![CDATA[
let circle = document.querySelector("circle");
circle.parentNode.style.display = "none";
circle.getTotalLength();
circle.parentNode.style.display = "";
circle.style.r = "65px";
]]></script>
</svg>

After

Width:  |  Height:  |  Size: 752 B