Bug 656197 - Push state updates further out across beforesetattr/aftersetattr

* Remove the generic attr preparsing mechanism from BeforeSetAttr and just preparse class attributes directly in the one place that needs to do it
* Move calls to BeforeSetAttr to after AttributeWillChange
* Remove UpdateState calls in BeforeSetAttr
* Move calls to AfterSetAttr to before UpdateState when manipulating attributes
* Remove UpdateState calls from AfterSetAttr, since they are no longer needed there

Tag #1375
This commit is contained in:
Matt A. Tobin 2020-04-16 19:59:10 -04:00 committed by Roy Tam
commit 7a3f9be509
27 changed files with 84 additions and 117 deletions

View file

@ -1441,27 +1441,16 @@ nsSVGElement::WillChangeValue(nsIAtom* aName)
// We need an empty attr value:
// a) to pass to BeforeSetAttr when GetParsedAttr returns nullptr
// b) to store the old value in the case we have mutation listeners
// We can use the same value for both purposes since (a) happens before (b).
//
// We can use the same value for both purposes, because if GetParsedAttr
// returns non-null its return value is what will get passed to BeforeSetAttr,
// not matter what our mutation listener situation is.
//
// Also, we should be careful to always return this value to benefit from
// return value optimization.
nsAttrValue emptyOrOldAttrValue;
const nsAttrValue* attrValue = GetParsedAttr(aName);
// This is not strictly correct--the attribute value parameter for
// BeforeSetAttr should reflect the value that *will* be set but that implies
// allocating, e.g. an extra nsSVGLength2, and isn't necessary at the moment
// since no SVG elements overload BeforeSetAttr. For now we just pass the
// current value.
nsAttrValueOrString attrStringOrValue(attrValue ? *attrValue
: emptyOrOldAttrValue);
DebugOnly<nsresult> rv =
BeforeSetAttr(kNameSpaceID_None, aName, &attrStringOrValue,
kNotifyDocumentObservers);
// SVG elements aren't expected to overload BeforeSetAttr in such a way that
// it may fail. So long as this is the case we don't need to check and pass on
// the return value which simplifies the calling code significantly.
MOZ_ASSERT(NS_SUCCEEDED(rv), "Unexpected failure from BeforeSetAttr");
// We only need to set the old value if we have listeners since otherwise it
// isn't used.
if (attrValue &&
@ -1477,6 +1466,21 @@ nsSVGElement::WillChangeValue(nsIAtom* aName)
nsNodeUtils::AttributeWillChange(this, kNameSpaceID_None, aName, modType,
nullptr);
// This is not strictly correct--the attribute value parameter for
// BeforeSetAttr should reflect the value that *will* be set but that implies
// allocating, e.g. an extra nsSVGLength2, and isn't necessary at the moment
// since no SVG elements overload BeforeSetAttr. For now we just pass the
// current value.
nsAttrValueOrString attrStringOrValue(attrValue ? *attrValue
: emptyOrOldAttrValue);
DebugOnly<nsresult> rv =
BeforeSetAttr(kNameSpaceID_None, aName, &attrStringOrValue,
kNotifyDocumentObservers);
// SVG elements aren't expected to overload BeforeSetAttr in such a way that
// it may fail. So long as this is the case we don't need to check and pass on
// the return value which simplifies the calling code significantly.
MOZ_ASSERT(NS_SUCCEEDED(rv), "Unexpected failure from BeforeSetAttr");
return emptyOrOldAttrValue;
}