Skip to content

Commit

Permalink
Inline style should always be cacheable in matched declarations cache
Browse files Browse the repository at this point in the history
https://bugs.webkit.org/show_bug.cgi?id=260254
rdar://113960228

Reviewed by Alan Baradlay.

Mutable inline style (created by modification via JS wrapper) prevents style caching
in the matched declarations cache. This patch turns any mutable style immutable during
style resolution so we can cache it. Due to deduplication the cache entries can be reused
accross elements and mutations.

* Source/WebCore/dom/ElementData.cpp:
(WebCore::UniqueElementData::UniqueElementData):
* Source/WebCore/dom/ElementData.h:

Save the immutable style in UniqueElementData.

* Source/WebCore/dom/StyledElement.cpp:
(WebCore::StyledElement::styleAttributeChanged):
(WebCore::StyledElement::invalidateStyleAttribute):

Take care to invalidate the cached immutable copy.

(WebCore::StyledElement::inlineStyleForStyleResolution const):

The accessor constructs ImmutableStyleProperties lazily on demand.

* Source/WebCore/dom/StyledElement.h:
* Source/WebCore/style/ElementRuleCollector.cpp:
(WebCore::Style::ElementRuleCollector::addElementInlineStyleProperties):

Allow caching.

Canonical link: https://commits.webkit.org/267035@main
  • Loading branch information
anttijk committed Aug 18, 2023
1 parent e78360b commit 5326da2
Show file tree
Hide file tree
Showing 5 changed files with 34 additions and 5 deletions.
2 changes: 2 additions & 0 deletions Source/WebCore/dom/ElementData.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -136,6 +136,7 @@ UniqueElementData::UniqueElementData()
UniqueElementData::UniqueElementData(const UniqueElementData& other)
: ElementData(other, true)
, m_presentationalHintStyle(other.m_presentationalHintStyle)
, m_inlineStyleForStyleResolution(other.m_inlineStyleForStyleResolution)
, m_attributeVector(other.m_attributeVector)
{
if (other.m_inlineStyle)
Expand All @@ -149,6 +150,7 @@ UniqueElementData::UniqueElementData(const ShareableElementData& other)
// An ShareableElementData should never have a mutable inline StyleProperties attached.
ASSERT(!other.m_inlineStyle || !other.m_inlineStyle->isMutable());
m_inlineStyle = other.m_inlineStyle;
m_inlineStyleForStyleResolution = downcast<ImmutableStyleProperties>(other.m_inlineStyle);
}

Ref<UniqueElementData> ElementData::makeUniqueCopy() const
Expand Down
1 change: 1 addition & 0 deletions Source/WebCore/dom/ElementData.h
Original file line number Diff line number Diff line change
Expand Up @@ -222,6 +222,7 @@ class UniqueElementData : public ElementData {
static ptrdiff_t attributeVectorMemoryOffset() { return OBJECT_OFFSETOF(UniqueElementData, m_attributeVector); }

mutable RefPtr<ImmutableStyleProperties> m_presentationalHintStyle;
mutable RefPtr<ImmutableStyleProperties> m_inlineStyleForStyleResolution;
typedef Vector<Attribute, 4> AttributeVector;
AttributeVector m_attributeVector;
};
Expand Down
26 changes: 26 additions & 0 deletions Source/WebCore/dom/StyledElement.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -155,6 +155,9 @@ void StyledElement::styleAttributeChanged(const AtomString& newStyleString, Attr

elementData()->setStyleAttributeIsDirty(false);

if (auto* uniqueElementData = dynamicDowncast<UniqueElementData>(*elementData()))
uniqueElementData->m_inlineStyleForStyleResolution = nullptr;

invalidateStyleInternal();
InspectorInstrumentation::didInvalidateStyleAttr(*this);
}
Expand All @@ -167,6 +170,10 @@ void StyledElement::invalidateStyleAttribute()
}

elementData()->setStyleAttributeIsDirty(true);

if (auto* uniqueElementData = dynamicDowncast<UniqueElementData>(*elementData()))
uniqueElementData->m_inlineStyleForStyleResolution = nullptr;

invalidateStyleInternal();

// In the rare case of selectors like "[style] ~ div" we need to synchronize immediately to invalidate.
Expand Down Expand Up @@ -319,4 +326,23 @@ void StyledElement::addPropertyToPresentationalHintStyle(MutableStyleProperties&
style.setProperty(propertyID, value, false, CSSParserContext(document()));
}

const ImmutableStyleProperties* StyledElement::inlineStyleForStyleResolution() const
{
if (!elementData())
return nullptr;

auto* inlineStyle = elementData()->m_inlineStyle.get();
if (!inlineStyle)
return nullptr;

if (auto* immutableStyle = dynamicDowncast<ImmutableStyleProperties>(*inlineStyle))
return immutableStyle;

auto& uniqueElementData = downcast<UniqueElementData>(*elementData());
if (!uniqueElementData.m_inlineStyleForStyleResolution)
uniqueElementData.m_inlineStyleForStyleResolution = inlineStyle->immutableCopyIfNeeded();

return uniqueElementData.m_inlineStyleForStyleResolution.get();
}

}
4 changes: 3 additions & 1 deletion Source/WebCore/dom/StyledElement.h
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,9 @@ class StyledElement : public Element {
void invalidateStyleAttribute();

const StyleProperties* inlineStyle() const { return elementData() ? elementData()->m_inlineStyle.get() : nullptr; }

// Use immutable style for style resolution for efficient caching.
const ImmutableStyleProperties* inlineStyleForStyleResolution() const;

bool setInlineStyleProperty(CSSPropertyID, CSSValueID identifier, bool important = false);
bool setInlineStyleProperty(CSSPropertyID, CSSPropertyID identifier, bool important = false);
WEBCORE_EXPORT bool setInlineStyleProperty(CSSPropertyID, double value, CSSUnitType, bool important = false);
Expand Down
6 changes: 2 additions & 4 deletions Source/WebCore/style/ElementRuleCollector.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -636,10 +636,8 @@ void ElementRuleCollector::addElementInlineStyleProperties(bool includeSMILPrope
if (!is<StyledElement>(element()))
return;

if (auto* inlineStyle = downcast<StyledElement>(element()).inlineStyle()) {
bool isInlineStyleCacheable = !inlineStyle->isMutable();
addElementStyleProperties(inlineStyle, RuleSet::cascadeLayerPriorityForUnlayered, isInlineStyleCacheable, FromStyleAttribute::Yes);
}
if (auto* inlineStyle = downcast<StyledElement>(element()).inlineStyleForStyleResolution())
addElementStyleProperties(inlineStyle, RuleSet::cascadeLayerPriorityForUnlayered, true, FromStyleAttribute::Yes);

if (includeSMILProperties && is<SVGElement>(element()))
addElementStyleProperties(downcast<SVGElement>(element()).animatedSMILStyleProperties(), RuleSet::cascadeLayerPriorityForUnlayered, false /* isCacheable */);
Expand Down

0 comments on commit 5326da2

Please sign in to comment.