Title: [285202] trunk/Source/WebCore
Revision
285202
Author
an...@apple.com
Date
2021-11-03 03:59:18 -0700 (Wed, 03 Nov 2021)

Log Message

Use Style::ScopeOrdinal for finding the right scope for ::part matching
https://bugs.webkit.org/show_bug.cgi?id=232562

Reviewed by Simon Fraser.

We are already passing the scope ordinal to the selector checker so we can use it consistently to find
the right scope.

* css/SelectorChecker.cpp:
(WebCore::SelectorChecker::matchRecursively const):

Find the right scope based on the scope ordinal.
Simplify allowMultiplePseudoElements check, invalid cases are not allowed by the parser.

(WebCore::SelectorChecker::checkOne const):

Find the right scope based on the scope ordinal.

* css/SelectorChecker.h:
* dom/ShadowRoot.h:
* style/ElementRuleCollector.cpp:
(WebCore::Style::ElementRuleCollector::matchPartPseudoElementRulesForScope):

Compute the scope ordinal for nested scopes.
Make iterative instead of recursive.

(WebCore::Style::ElementRuleCollector::ruleMatches):
(WebCore::Style::ElementRuleCollector::matchAllRules):

Flush all remaining rules.

* style/ElementRuleCollector.h:
* style/StyleScope.cpp:
(WebCore::Style::Scope::forOrdinal):
(WebCore::Style::assignedSlotForScopeOrdinal):
(WebCore::Style::hostForScopeOrdinal):

Add helpers.

* style/StyleScope.h:
* style/StyleScopeOrdinal.h:
(WebCore::Style::operator--):

We now use values less than ContainingHost to present enclosing scopes, similar to slotted matching.

Modified Paths

Diff

Modified: trunk/Source/WebCore/ChangeLog (285201 => 285202)


--- trunk/Source/WebCore/ChangeLog	2021-11-03 10:36:59 UTC (rev 285201)
+++ trunk/Source/WebCore/ChangeLog	2021-11-03 10:59:18 UTC (rev 285202)
@@ -1,3 +1,50 @@
+2021-11-03  Antti Koivisto  <an...@apple.com>
+
+        Use Style::ScopeOrdinal for finding the right scope for ::part matching
+        https://bugs.webkit.org/show_bug.cgi?id=232562
+
+        Reviewed by Simon Fraser.
+
+        We are already passing the scope ordinal to the selector checker so we can use it consistently to find
+        the right scope.
+
+        * css/SelectorChecker.cpp:
+        (WebCore::SelectorChecker::matchRecursively const):
+
+        Find the right scope based on the scope ordinal.
+        Simplify allowMultiplePseudoElements check, invalid cases are not allowed by the parser.
+
+        (WebCore::SelectorChecker::checkOne const):
+
+        Find the right scope based on the scope ordinal.
+
+        * css/SelectorChecker.h:
+        * dom/ShadowRoot.h:
+        * style/ElementRuleCollector.cpp:
+        (WebCore::Style::ElementRuleCollector::matchPartPseudoElementRulesForScope):
+
+        Compute the scope ordinal for nested scopes.
+        Make iterative instead of recursive.
+
+        (WebCore::Style::ElementRuleCollector::ruleMatches):
+        (WebCore::Style::ElementRuleCollector::matchAllRules):
+
+        Flush all remaining rules.
+
+        * style/ElementRuleCollector.h:
+        * style/StyleScope.cpp:
+        (WebCore::Style::Scope::forOrdinal):
+        (WebCore::Style::assignedSlotForScopeOrdinal):
+        (WebCore::Style::hostForScopeOrdinal):
+
+        Add helpers.
+
+        * style/StyleScope.h:
+        * style/StyleScopeOrdinal.h:
+        (WebCore::Style::operator--):
+
+        We now use values less than ContainingHost to present enclosing scopes, similar to slotted matching.
+
 2021-11-02  Brady Eidson  <beid...@apple.com>
 
         Notifications on iOS enabled at compile-time, disabled at runtime

Modified: trunk/Source/WebCore/css/SelectorChecker.cpp (285201 => 285202)


--- trunk/Source/WebCore/css/SelectorChecker.cpp	2021-11-03 10:36:59 UTC (rev 285201)
+++ trunk/Source/WebCore/css/SelectorChecker.cpp	2021-11-03 10:59:18 UTC (rev 285202)
@@ -316,8 +316,7 @@
 
         nextContext.pseudoId = PseudoId::None;
 
-        bool nextIsPart = leftSelector->match() == CSSSelector::PseudoElement && leftSelector->pseudoElementType() == CSSSelector::PseudoElementPart;
-        bool allowMultiplePseudoElements = relation == CSSSelector::ShadowDescendant && nextIsPart;
+        bool allowMultiplePseudoElements = relation == CSSSelector::ShadowDescendant;
         // Virtual pseudo element is only effective in the rightmost fragment.
         if (!allowMultiplePseudoElements)
             nextContext.pseudoElementEffective = false;
@@ -409,11 +408,14 @@
         }
     case CSSSelector::ShadowDescendant:
     case CSSSelector::ShadowPartDescendant: {
-        // When matching foo::part(bar) we skip directly to the tree of element 'foo'.
-        auto* shadowHost = relation == CSSSelector::ShadowPartDescendant ? checkingContext.shadowHostInPartRuleScope : context.element->shadowHost();
-        if (!shadowHost)
+        // Continue matching in the scope where this rule came from.
+        auto* host = relation == CSSSelector::ShadowPartDescendant
+            ? Style::hostForScopeOrdinal(*context.element, checkingContext.styleScopeOrdinal)
+            : context.element->shadowHost();
+        if (!host)
             return MatchResult::fails(Match::SelectorFailsCompletely);
-        nextContext.element = shadowHost;
+
+        nextContext.element = host;
         nextContext.firstSelectorOfTheFragment = nextContext.selector;
         nextContext.isSubjectOrAdjacentElement = false;
         PseudoIdSet ignoreDynamicPseudo;
@@ -422,15 +424,10 @@
         return MatchResult::updateWithMatchType(result, matchType);
     }
     case CSSSelector::ShadowSlotted: {
-        auto* slot = context.element->assignedSlot();
+        // We continue matching in the scope where this rule came from.
+        auto slot = Style::assignedSlotForScopeOrdinal(*context.element, checkingContext.styleScopeOrdinal);
         if (!slot)
             return MatchResult::fails(Match::SelectorFailsCompletely);
-        // We continue matching in the scope where this rule came from.
-        auto scopeDepth = static_cast<int>(checkingContext.styleScopeOrdinal);
-        while (--scopeDepth && slot->assignedSlot())
-            slot = slot->assignedSlot();
-        if (scopeDepth)
-            return MatchResult::fails(Match::SelectorFailsCompletely);
 
         nextContext.element = slot;
         nextContext.firstSelectorOfTheFragment = nextContext.selector;
@@ -1171,11 +1168,13 @@
         case CSSSelector::PseudoElementPart: {
             auto translatePartNameToRuleScope = [&](AtomString partName) {
                 Vector<AtomString, 1> mappedNames { partName };
+                auto* ruleScopeHost = Style::hostForScopeOrdinal(*context.element, checkingContext.styleScopeOrdinal);
+
                 for (auto* shadowRoot = element.containingShadowRoot(); shadowRoot; shadowRoot = shadowRoot->host()->containingShadowRoot()) {
                     // Apply mappings up to the scope the rules are coming from.
-                    if (shadowRoot->host() == checkingContext.shadowHostInPartRuleScope)
+                    if (shadowRoot->host() == ruleScopeHost)
                         break;
-                    
+
                     Vector<AtomString, 1> newMappedNames;
                     for (auto& name : mappedNames)
                         newMappedNames.appendVector(shadowRoot->partMappings().get(name));

Modified: trunk/Source/WebCore/css/SelectorChecker.h (285201 => 285202)


--- trunk/Source/WebCore/css/SelectorChecker.h	2021-11-03 10:36:59 UTC (rev 285201)
+++ trunk/Source/WebCore/css/SelectorChecker.h	2021-11-03 10:59:18 UTC (rev 285202)
@@ -95,7 +95,6 @@
         AtomString nameForHightlightPseudoElement;
         const ContainerNode* scope { nullptr };
         bool isMatchingHostPseudoClass { false };
-        const Element* shadowHostInPartRuleScope { nullptr };
         Style::ScopeOrdinal styleScopeOrdinal { Style::ScopeOrdinal::Element };
 
         // FIXME: It would be nicer to have a separate object for return values. This requires some more work in the selector compiler.

Modified: trunk/Source/WebCore/dom/ShadowRoot.h (285201 => 285202)


--- trunk/Source/WebCore/dom/ShadowRoot.h	2021-11-03 10:36:59 UTC (rev 285201)
+++ trunk/Source/WebCore/dom/ShadowRoot.h	2021-11-03 10:59:18 UTC (rev 285202)
@@ -29,6 +29,7 @@
 #include "Document.h"
 #include "DocumentFragment.h"
 #include "Element.h"
+#include "StyleScopeOrdinal.h"
 #if ENABLE(PICTURE_IN_PICTURE_API)
 #include "HTMLVideoElement.h"
 #endif

Modified: trunk/Source/WebCore/style/ElementRuleCollector.cpp (285201 => 285202)


--- trunk/Source/WebCore/style/ElementRuleCollector.cpp	2021-11-03 10:36:59 UTC (rev 285201)
+++ trunk/Source/WebCore/style/ElementRuleCollector.cpp	2021-11-03 10:59:18 UTC (rev 285202)
@@ -306,21 +306,23 @@
 
 void ElementRuleCollector::matchPartPseudoElementRulesForScope(const ShadowRoot& scopeShadowRoot)
 {
-    auto& shadowHost = *scopeShadowRoot.host();
-    {
-        SetForScope<RefPtr<const Element>> partMatchingScope(m_shadowHostInPartRuleScope, &shadowHost);
+    auto* host = scopeShadowRoot.host();
+    auto styleScopeOrdinal = ScopeOrdinal::ContainingHost;
 
-        auto& hostAuthorRules = Scope::forNode(shadowHost).resolver().ruleSets().authorStyle();
-        MatchRequest hostAuthorRequest { &hostAuthorRules, ScopeOrdinal::ContainingHost };
-        collectMatchingRulesForList(&hostAuthorRules.partPseudoElementRules(), hostAuthorRequest);
-    }
+    for (; host; host = host->shadowHost(), --styleScopeOrdinal) {
+        auto& styleScope = Scope::forNode(*host);
+        if (!styleScope.resolver().ruleSets().isAuthorStyleDefined())
+            continue;
 
-    // Element may be exposed to styling from enclosing scopes via exportparts attributes.
-    if (scopeShadowRoot.partMappings().isEmpty())
-        return;
+        auto& hostAuthorRules = styleScope.resolver().ruleSets().authorStyle();
 
-    if (auto* parentScopeShadowRoot = shadowHost.containingShadowRoot())
-        matchPartPseudoElementRulesForScope(*parentScopeShadowRoot);
+        MatchRequest scopeMatchRequest(&hostAuthorRules, styleScopeOrdinal);
+        collectMatchingRulesForList(&hostAuthorRules.partPseudoElementRules(), scopeMatchRequest);
+
+        // Element may only be exposed to styling from enclosing scopes via exportparts attributes.
+        if (host->shadowRoot()->partMappings().isEmpty())
+            break;
+    }
 }
 
 void ElementRuleCollector::collectMatchingShadowPseudoElementRules(const MatchRequest& matchRequest)
@@ -431,7 +433,6 @@
     context.scrollbarState = m_pseudoElementRequest.scrollbarState;
     context.nameForHightlightPseudoElement = m_pseudoElementRequest.highlightName;
     context.isMatchingHostPseudoClass = m_isMatchingHostPseudoClass;
-    context.shadowHostInPartRuleScope = m_shadowHostInPartRuleScope.get();
     context.styleScopeOrdinal = styleScopeOrdinal;
 
     bool selectorMatches;
@@ -549,8 +550,8 @@
         // Inline style behaves as if it has higher specificity than any rule.
         addElementInlineStyleProperties(includeSMILProperties);
 
-        // Rules from the host scope override inline style.
-        transferMatchedRules(DeclarationOrigin::Author, ScopeOrdinal::ContainingHost);
+        // Rules from the host scopes override inline style.
+        transferMatchedRules(DeclarationOrigin::Author);
     }
 }
 

Modified: trunk/Source/WebCore/style/ElementRuleCollector.h (285201 => 285202)


--- trunk/Source/WebCore/style/ElementRuleCollector.h	2021-11-03 10:36:59 UTC (rev 285201)
+++ trunk/Source/WebCore/style/ElementRuleCollector.h	2021-11-03 10:59:18 UTC (rev 285202)
@@ -163,7 +163,6 @@
     PseudoElementRequest m_pseudoElementRequest { PseudoId::None };
     SelectorChecker::Mode m_mode { SelectorChecker::Mode::ResolvingStyle };
     bool m_isMatchingHostPseudoClass { false };
-    RefPtr<const Element> m_shadowHostInPartRuleScope;
 
     Vector<MatchedRule, 64> m_matchedRules;
     size_t m_matchedRuleTransferIndex { 0 };

Modified: trunk/Source/WebCore/style/StyleScope.cpp (285201 => 285202)


--- trunk/Source/WebCore/style/StyleScope.cpp	2021-11-03 10:36:59 UTC (rev 285201)
+++ trunk/Source/WebCore/style/StyleScope.cpp	2021-11-03 10:59:18 UTC (rev 285202)
@@ -185,31 +185,18 @@
 
 Scope* Scope::forOrdinal(Element& element, ScopeOrdinal ordinal)
 {
-    switch (ordinal) {
-    case ScopeOrdinal::Element:
+    if (ordinal == ScopeOrdinal::Element)
         return &forNode(element);
-    case ScopeOrdinal::ContainingHost: {
-        auto* containingShadowRoot = element.containingShadowRoot();
-        if (!containingShadowRoot)
-            return nullptr;
-        return &forNode(*containingShadowRoot->host());
-    }
-    case ScopeOrdinal::Shadow: {
+    if (ordinal == ScopeOrdinal::Shadow) {
         auto* shadowRoot = element.shadowRoot();
-        if (!shadowRoot)
-            return nullptr;
-        return &shadowRoot->styleScope();
+        return shadowRoot ? &shadowRoot->styleScope() : nullptr;
     }
-    default: {
-        ASSERT(ordinal >= ScopeOrdinal::FirstSlot);
-        auto slotIndex = ScopeOrdinal::FirstSlot;
-        for (auto* slot = element.assignedSlot(); slot; slot = slot->assignedSlot(), ++slotIndex) {
-            if (slotIndex == ordinal)
-                return &forNode(*slot);
-        }
-        return nullptr;
+    if (ordinal <= ScopeOrdinal::ContainingHost) {
+        auto* host = hostForScopeOrdinal(element, ordinal);
+        return host ? &forNode(*host) : nullptr;
     }
-    }
+    auto* slot = assignedSlotForScopeOrdinal(element, ordinal);
+    return slot ? &forNode(*slot) : nullptr;
 }
 
 void Scope::setPreferredStylesheetSetName(const String& name)
@@ -789,5 +776,23 @@
     return m_shadowRoot && m_shadowRoot->mode() == ShadowRootMode::UserAgent;
 }
 
+HTMLSlotElement* assignedSlotForScopeOrdinal(const Element& element, ScopeOrdinal scopeOrdinal)
+{
+    ASSERT(scopeOrdinal >= ScopeOrdinal::FirstSlot);
+    auto* slot = element.assignedSlot();
+    for (auto scopeDepth = ScopeOrdinal::FirstSlot; slot && scopeDepth != scopeOrdinal; ++scopeDepth)
+        slot = slot->assignedSlot();
+    return slot;
 }
+
+Element* hostForScopeOrdinal(const Element& element, ScopeOrdinal scopeOrdinal)
+{
+    ASSERT(scopeOrdinal <= ScopeOrdinal::ContainingHost);
+    auto* host = element.shadowHost();
+    for (auto scopeDepth = ScopeOrdinal::ContainingHost; host && scopeDepth != scopeOrdinal; --scopeDepth)
+        host = host->shadowHost();
+    return host;
 }
+
+}
+}

Modified: trunk/Source/WebCore/style/StyleScope.h (285201 => 285202)


--- trunk/Source/WebCore/style/StyleScope.h	2021-11-03 10:36:59 UTC (rev 285201)
+++ trunk/Source/WebCore/style/StyleScope.h	2021-11-03 10:59:18 UTC (rev 285202)
@@ -45,6 +45,7 @@
 class CSSStyleSheet;
 class Document;
 class Element;
+class HTMLSlotElement;
 class Node;
 class ProcessingInstruction;
 class StyleSheet;
@@ -203,6 +204,9 @@
     HashMap<ResolverSharingKey, Ref<Resolver>> m_sharedShadowTreeResolvers;
 };
 
+HTMLSlotElement* assignedSlotForScopeOrdinal(const Element&, ScopeOrdinal);
+Element* hostForScopeOrdinal(const Element&, ScopeOrdinal);
+
 inline bool Scope::hasPendingSheets() const
 {
     return hasPendingSheetsBeforeBody() || !m_elementsInBodyWithPendingSheets.isEmpty();

Modified: trunk/Source/WebCore/style/StyleScopeOrdinal.h (285201 => 285202)


--- trunk/Source/WebCore/style/StyleScopeOrdinal.h	2021-11-03 10:36:59 UTC (rev 285201)
+++ trunk/Source/WebCore/style/StyleScopeOrdinal.h	2021-11-03 10:59:18 UTC (rev 285202)
@@ -30,7 +30,7 @@
 // This is used to identify style scopes that can affect an element.
 // Scopes are in tree-of-trees order. Styles from earlier scopes win over later ones (modulo !important).
 enum class ScopeOrdinal : int {
-    ContainingHost = -1, // ::part rules and author-exposed UA pseudo classes from the host tree scope.
+    ContainingHost = -1, // ::part rules and author-exposed UA pseudo classes from the host tree scope. Values less than ContainingHost indicate enclosing scopes.
     Element = 0, // Normal rules in the same tree where the element is.
     FirstSlot = 1, // ::slotted rules in the parent's shadow tree. Values greater than FirstSlot indicate subsequent slots in the chain.
     Shadow = std::numeric_limits<int>::max(), // :host rules in element's own shadow tree.
@@ -42,5 +42,11 @@
     return ordinal = static_cast<ScopeOrdinal>(static_cast<int>(ordinal) + 1);
 }
 
+inline ScopeOrdinal& operator--(ScopeOrdinal& ordinal)
+{
+    ASSERT(ordinal < ScopeOrdinal::Shadow);
+    return ordinal = static_cast<ScopeOrdinal>(static_cast<int>(ordinal) - 1);
 }
+
 }
+}
_______________________________________________
webkit-changes mailing list
webkit-changes@lists.webkit.org
https://lists.webkit.org/mailman/listinfo/webkit-changes

Reply via email to