Skip to content

Commit

Permalink
[view-transitions] Resolving styles with a large set of named view-tr…
Browse files Browse the repository at this point in the history
…ansition elements is slow.

https://bugs.webkit.org/show_bug.cgi?id=274739
<rdar://128774070>

Reviewed by Antti Koivisto.

For every named element in a view transition, 4 styles are inserted in the UA style sheet.

View transitions currently restyle the entire view transition pseudo tree for changes to any of
them (since mutations are keyed to the owning element, which is the document element for the whole tree).

There are 4 named pseudo elements per view transition name, resulting in pretty slow O(n^2) restyling.

We can improve this somewhat by putting pseudo element selectors with a name argument (like
::view-transition-group(name)) into a hash map, so that we only need to iterate the somewhat-relevant ones.

* Source/WebCore/style/ElementRuleCollector.cpp:
(WebCore::Style::ElementRuleCollector::collectMatchingRules):
* Source/WebCore/style/RuleSet.cpp:
(WebCore::Style::RuleSet::addRule):
(WebCore::Style::RuleSet::traverseRuleDatas):
(WebCore::Style::RuleSet::shrinkToFit):
* Source/WebCore/style/RuleSet.h:
(WebCore::Style::RuleSet::namedPseudoElementRules const):

Canonical link: https://commits.webkit.org/279484@main
  • Loading branch information
mattwoodrow committed May 30, 2024
1 parent bd4296e commit 4a0a447
Show file tree
Hide file tree
Showing 3 changed files with 19 additions and 0 deletions.
2 changes: 2 additions & 0 deletions Source/WebCore/style/ElementRuleCollector.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -219,6 +219,8 @@ void ElementRuleCollector::collectMatchingRules(const MatchRequest& matchRequest
for (auto* rules : ruleVectors)
collectMatchingRulesForList(rules, matchRequest);
}
if (m_pseudoElementRequest && m_pseudoElementRequest->nameArgument() != nullAtom())
collectMatchingRulesForList(matchRequest.ruleSet.namedPseudoElementRules(m_pseudoElementRequest->nameArgument()), matchRequest);
if (element.isLink())
collectMatchingRulesForList(matchRequest.ruleSet.linkPseudoClassRules(), matchRequest);
if (matchesFocusPseudoClass(element))
Expand Down
15 changes: 15 additions & 0 deletions Source/WebCore/style/RuleSet.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -150,6 +150,7 @@ void RuleSet::addRule(RuleData&& ruleData, CascadeLayerIdentifier cascadeLayerId
const CSSSelector* customPseudoElementSelector = nullptr;
const CSSSelector* slottedPseudoElementSelector = nullptr;
const CSSSelector* partPseudoElementSelector = nullptr;
const CSSSelector* namedPseudoElementSelector = nullptr;
#if ENABLE(VIDEO)
const CSSSelector* cuePseudoElementSelector = nullptr;
#endif
Expand Down Expand Up @@ -204,6 +205,13 @@ void RuleSet::addRule(RuleData&& ruleData, CascadeLayerIdentifier cascadeLayerId
cuePseudoElementSelector = selector;
break;
#endif
case CSSSelector::PseudoElement::ViewTransitionGroup:
case CSSSelector::PseudoElement::ViewTransitionImagePair:
case CSSSelector::PseudoElement::ViewTransitionOld:
case CSSSelector::PseudoElement::ViewTransitionNew:
if (selector->argumentList()->first().identifier != starAtom())
namedPseudoElementSelector = selector;
break;
default:
break;
}
Expand Down Expand Up @@ -312,6 +320,11 @@ void RuleSet::addRule(RuleData&& ruleData, CascadeLayerIdentifier cascadeLayerId
return;
}

if (namedPseudoElementSelector) {
addToRuleSet(namedPseudoElementSelector->argumentList()->first().identifier, m_namedPseudoElementRules, ruleData);
return;
}

if (rootElementSelector) {
m_rootElementRules.append(ruleData);
return;
Expand Down Expand Up @@ -352,6 +365,7 @@ void RuleSet::traverseRuleDatas(Function&& function)
traverseMap(m_tagLocalNameRules);
traverseMap(m_tagLowercaseLocalNameRules);
traverseMap(m_userAgentPartRules);
traverseMap(m_namedPseudoElementRules);
traverseVector(m_linkPseudoClassRules);
#if ENABLE(VIDEO)
traverseVector(m_cuePseudoRules);
Expand Down Expand Up @@ -445,6 +459,7 @@ void RuleSet::shrinkToFit()
shrinkMapVectorsToFit(m_tagLocalNameRules);
shrinkMapVectorsToFit(m_tagLowercaseLocalNameRules);
shrinkMapVectorsToFit(m_userAgentPartRules);
shrinkMapVectorsToFit(m_namedPseudoElementRules);

m_linkPseudoClassRules.shrinkToFit();
#if ENABLE(VIDEO)
Expand Down
2 changes: 2 additions & 0 deletions Source/WebCore/style/RuleSet.h
Original file line number Diff line number Diff line change
Expand Up @@ -94,6 +94,7 @@ class RuleSet : public RefCounted<RuleSet> {
const RuleDataVector* tagRules(const AtomString& key, bool isHTMLName) const;
const RuleDataVector* userAgentPartRules(const AtomString& key) const { return m_userAgentPartRules.get(key); }
const RuleDataVector* linkPseudoClassRules() const { return &m_linkPseudoClassRules; }
const RuleDataVector* namedPseudoElementRules(const AtomString& key) const { return m_namedPseudoElementRules.get(key); }
#if ENABLE(VIDEO)
const RuleDataVector& cuePseudoRules() const { return m_cuePseudoRules; }
#endif
Expand Down Expand Up @@ -190,6 +191,7 @@ class RuleSet : public RefCounted<RuleSet> {
AtomRuleMap m_tagLocalNameRules;
AtomRuleMap m_tagLowercaseLocalNameRules;
AtomRuleMap m_userAgentPartRules;
AtomRuleMap m_namedPseudoElementRules;
RuleDataVector m_linkPseudoClassRules;
#if ENABLE(VIDEO)
RuleDataVector m_cuePseudoRules;
Expand Down

0 comments on commit 4a0a447

Please sign in to comment.