Bug 1383650 - Optimize attribute mapping by not parsing same thing twice r=longsonr

Geometry properties are the most used SVG attributes. When authors specify
them as attributes, we have to parse them in SVG side. So we don't want to
parse them in CSS side again, otherwise the introduced performance loss
is relatively high.

With this optimization, this feature implementation doesn't slow down
overall performace even if there are thousands of geometry elements.

Differential Revision: https://phabricator.services.mozilla.com/D30778

--HG--
extra : moz-landing-system : lando
This commit is contained in:
violet 2019-05-16 00:54:46 +00:00
Родитель a5f610a05c
Коммит 99366154e3
1 изменённых файлов: 32 добавлений и 1 удалений

Просмотреть файл

@ -1072,6 +1072,9 @@ class MOZ_STACK_CLASS MappedAttrParser {
void ParseMappedAttrValue(nsAtom* aMappedAttrName,
const nsAString& aMappedAttrValue);
void TellStyleAlreadyParsedResult(nsAtom const* aAtom,
SVGAnimatedLength const& aLength);
// If we've parsed any values for mapped attributes, this method returns the
// already_AddRefed css::Declaration that incorporates the parsed
// values. Otherwise, this method returns null.
@ -1159,6 +1162,18 @@ void MappedAttrParser::ParseMappedAttrValue(nsAtom* aMappedAttrName,
}
}
void MappedAttrParser::TellStyleAlreadyParsedResult(
nsAtom const* aAtom, SVGAnimatedLength const& aLength) {
if (!mDecl) {
mDecl = new DeclarationBlock();
}
nsCSSPropertyID propertyID =
nsCSSProps::LookupProperty(nsDependentAtomString(aAtom));
SVGElement::UpdateDeclarationBlockFromLength(*mDecl, propertyID, aLength,
SVGElement::ValToUse::Base);
}
already_AddRefed<DeclarationBlock> MappedAttrParser::GetDeclarationBlock() {
return mDecl.forget();
}
@ -1182,6 +1197,9 @@ void SVGElement::UpdateContentDeclarationBlock() {
MappedAttrParser mappedAttrParser(doc->CSSLoader(), doc->GetDocumentURI(),
GetBaseURI(), this);
bool lengthAffectsStyle =
SVGGeometryProperty::ElementMapsLengthsToStyle(this);
for (uint32_t i = 0; i < attrCount; ++i) {
const nsAttrName* attrName = mAttrs.AttrNameAt(i);
if (!attrName->IsAtom() || !IsAttributeMapped(attrName->Atom())) continue;
@ -1214,6 +1232,20 @@ void SVGElement::UpdateContentDeclarationBlock() {
}
}
if (lengthAffectsStyle) {
auto const* length = GetAnimatedLength(attrName->Atom());
if (length && length->HasBaseVal()) {
// This is an element with geometry property set via SVG attribute,
// and the attribute is already successfully parsed. We want to go
// through the optimized path to tell the style system the result
// directly, rather than let it parse the same thing again.
mappedAttrParser.TellStyleAlreadyParsedResult(attrName->Atom(),
*length);
continue;
}
}
nsAutoString value;
mAttrs.AttrAt(i)->ToString(value);
mappedAttrParser.ParseMappedAttrValue(attrName->Atom(), value);
@ -1457,7 +1489,6 @@ SVGAnimatedLength* SVGElement::GetAnimatedLength(const nsAtom* aAttrName) {
return &lengthInfo.mLengths[i];
}
}
MOZ_ASSERT(false, "no matching length found");
return nullptr;
}