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 <[email protected]>
+
+ 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 <[email protected]>
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);
}
+
}
+}