summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorFranklinDM <mrmineshafter17@gmail.com>2023-03-18 12:43:51 +0800
committerMoonchild <moonchild@palemoon.org>2023-03-23 12:18:00 +0100
commit9c5999c8bc7fb3598b7b572a57da4afbb0048a18 (patch)
tree7bf00eb3426e7eaa4ea0e149bcce88b824431727
parent8313fea7c5bbb54339bbde9b20024bc17c7341e8 (diff)
downloaduxp-9c5999c8bc7fb3598b7b572a57da4afbb0048a18.tar.gz
Issue #1592 - Part 4: Walk ::slotted()-containing rules for slottables
- Check against all selector parts and not the leftmost selector only for ::slotted() - Walk rules for ::slotted() regardless if the shadow root is opened/closed - Ensure that ::slotted() rules are walked in the right order - Fix ::slotted inheritance from topmost shadow root
-rw-r--r--dom/xbl/nsBindingManager.cpp39
-rw-r--r--layout/style/nsCSSRuleProcessor.cpp104
-rw-r--r--layout/style/nsRuleProcessorData.h8
3 files changed, 104 insertions, 47 deletions
diff --git a/dom/xbl/nsBindingManager.cpp b/dom/xbl/nsBindingManager.cpp
index 8f18f112af..c6dc58ec89 100644
--- a/dom/xbl/nsBindingManager.cpp
+++ b/dom/xbl/nsBindingManager.cpp
@@ -681,6 +681,45 @@ nsBindingManager::WalkRules(nsIStyleRuleProcessor::EnumFunc aFunc,
aData->mElementIsFeatureless = false;
aData->mTreeMatchContext.mOnlyMatchHostPseudo = false;
+ // Walk the rules in shadow root for ::slotted() pseudo-element rules
+ // if we have an assigned slot.
+ if (aData->mElement->GetAssignedSlot()) {
+ aData->mTreeMatchContext.mRestrictToSlottedPseudo = true;
+
+ AutoTArray<nsXBLBinding*, 2> stack;
+ bool foundTopmostScope = false;
+ for (nsIContent* parent = aData->mElement->GetFlattenedTreeParent();
+ parent;
+ parent = parent->GetFlattenedTreeParent()) {
+ ShadowRoot* currentShadow = parent->GetShadowRoot();
+ if (!currentShadow) {
+ continue;
+ }
+
+ nsXBLBinding* binding = currentShadow->GetAssociatedBinding();
+ if (!binding) {
+ continue;
+ }
+ stack.AppendElement(binding);
+
+ if (!foundTopmostScope) {
+ aData->mTreeMatchContext.mScopedRoot = parent;
+ foundTopmostScope = true;
+ }
+ }
+
+ while (!stack.IsEmpty()) {
+ uint32_t index = stack.Length() - 1;
+ nsXBLBinding* binding = stack.ElementAt(index);
+ stack.RemoveElementAt(index);
+
+ aData->mTreeMatchContext.mIsTopmostScope = (index == 0);
+ binding->WalkRules(aFunc, aData);
+ }
+
+ aData->mTreeMatchContext.mRestrictToSlottedPseudo = false;
+ }
+
// Walk the binding scope chain, starting with the binding attached to our
// content, up till we run out of scopes or we get cut off.
nsIContent *content = aData->mElement;
diff --git a/layout/style/nsCSSRuleProcessor.cpp b/layout/style/nsCSSRuleProcessor.cpp
index fb35b65bd6..a4a2e537c4 100644
--- a/layout/style/nsCSSRuleProcessor.cpp
+++ b/layout/style/nsCSSRuleProcessor.cpp
@@ -2665,6 +2665,12 @@ SelectorMatchesTree(Element* aPrevElement,
aTreeMatchContext.mCurrentStyleScope = styleScope;
}
selector = selector->mNext;
+ if (!selector &&
+ !aTreeMatchContext.mIsTopmostScope &&
+ aTreeMatchContext.mRestrictToSlottedPseudo &&
+ aTreeMatchContext.mScopedRoot != element) {
+ return false;
+ }
}
else {
// for adjacent sibling and child combinators, if we didn't find
@@ -2743,6 +2749,52 @@ static bool SelectorListMatches(Element* aElement,
aPreventComplexSelectors);
}
+static
+inline bool LookForTargetPseudo(nsCSSSelector* aSelector,
+ TreeMatchContext* aMatchContext,
+ nsRestyleHint* possibleChange) {
+ if (aMatchContext->mOnlyMatchHostPseudo) {
+ while (aSelector && aSelector->mNext != nullptr) {
+ aSelector = aSelector->mNext;
+ }
+
+ for (nsPseudoClassList* pseudoClass = aSelector->mPseudoClassList;
+ pseudoClass;
+ pseudoClass = pseudoClass->mNext) {
+ if (pseudoClass->mType == CSSPseudoClassType::host ||
+ pseudoClass->mType == CSSPseudoClassType::hostContext) {
+ if (possibleChange) {
+ // :host-context will walk ancestors looking for a match of a
+ // compound selector, thus any changes to ancestors may require
+ // restyling the subtree.
+ *possibleChange |= eRestyle_Subtree;
+ }
+ return true;
+ }
+ }
+ return false;
+ }
+ else if (aMatchContext->mRestrictToSlottedPseudo) {
+ for (nsCSSSelector* selector = aSelector;
+ selector;
+ selector = selector->mNext) {
+ if (!selector->mPseudoClassList) {
+ continue;
+ }
+ for (nsPseudoClassList* pseudoClass = selector->mPseudoClassList;
+ pseudoClass;
+ pseudoClass = pseudoClass->mNext) {
+ if (pseudoClass->mType == CSSPseudoClassType::slotted) {
+ return true;
+ }
+ }
+ }
+ return false;
+ }
+ // We're not restricted to a specific pseudo-class.
+ return true;
+}
+
static inline
void ContentEnumFunc(const RuleValue& value, nsCSSSelector* aSelector,
ElementDependentRuleProcessorData* data, NodeMatchContext& nodeContext,
@@ -2757,29 +2809,11 @@ void ContentEnumFunc(const RuleValue& value, nsCSSSelector* aSelector,
// We won't match; nothing else to do here
return;
}
- // If mOnlyMatchHostPseudo is set, then we only want to match against
- // selectors that contain a :host-context pseudo class.
- if (data->mTreeMatchContext.mOnlyMatchHostPseudo) {
- nsCSSSelector* selector = aSelector;
- while (selector && selector->mNext != nullptr) {
- selector = selector->mNext;
- }
- bool seenHostPseudo = false;
- for (nsPseudoClassList* pseudoClass = selector->mPseudoClassList;
- pseudoClass;
- pseudoClass = pseudoClass->mNext) {
- if (pseudoClass->mType == CSSPseudoClassType::host ||
- pseudoClass->mType == CSSPseudoClassType::hostContext) {
- seenHostPseudo = true;
- break;
- }
- }
-
- if (!seenHostPseudo) {
- return;
- }
+ if (!LookForTargetPseudo(aSelector, &data->mTreeMatchContext, nullptr)) {
+ return;
}
+
if (!data->mTreeMatchContext.SetStyleScopeForSelectorMatching(data->mElement,
data->mScope)) {
// The selector is for a rule in a scoped style sheet, and the subject
@@ -3122,35 +3156,11 @@ AttributeEnumFunc(nsCSSSelector* aSelector,
nsRestyleHint possibleChange =
RestyleHintForSelectorWithAttributeChange(aData->change,
aSelector, aRightmostSelector);
- // If mOnlyMatchHostPseudo is set, then we only want to match against
- // selectors that contain a :host-context pseudo class.
- if (data->mTreeMatchContext.mOnlyMatchHostPseudo) {
- nsCSSSelector* selector = aSelector;
- while (selector && selector->mNext != nullptr) {
- selector = selector->mNext;
- }
- bool seenHostPseudo = false;
- for (nsPseudoClassList* pseudoClass = selector->mPseudoClassList;
- pseudoClass;
- pseudoClass = pseudoClass->mNext) {
- if (pseudoClass->mType == CSSPseudoClassType::host ||
- pseudoClass->mType == CSSPseudoClassType::hostContext) {
- // :host-context will walk ancestors looking for a match of a compound
- // selector, thus any changes to ancestors may require restyling the
- // subtree.
- possibleChange |= eRestyle_Subtree;
- seenHostPseudo = true;
- break;
- }
- }
-
- if (!seenHostPseudo) {
- return;
- }
+ if (!LookForTargetPseudo(aSelector, &data->mTreeMatchContext, &possibleChange)) {
+ return;
}
-
// If, ignoring eRestyle_SomeDescendants, enumData->change already includes
// all the bits of possibleChange, don't bother calling SelectorMatches, since
// even if it returns false enumData->change won't change. If possibleChange
diff --git a/layout/style/nsRuleProcessorData.h b/layout/style/nsRuleProcessorData.h
index 938c2f9d35..07c885994f 100644
--- a/layout/style/nsRuleProcessorData.h
+++ b/layout/style/nsRuleProcessorData.h
@@ -371,6 +371,9 @@ struct MOZ_STACK_CLASS TreeMatchContext {
// match.
bool mOnlyMatchHostPseudo;
+ // Restrict matching to selectors that contain a :slotted() pseudo-class.
+ bool mRestrictToSlottedPseudo;
+
// Root of scoped stylesheet (set and unset by the supplier of the
// scoped stylesheet).
nsIContent* mScopedRoot;
@@ -403,6 +406,9 @@ struct MOZ_STACK_CLASS TreeMatchContext {
// for an HTML5 scoped style sheet.
bool mForScopedStyle;
+ // Whether we're currently in the topmost scope for shadow DOM.
+ bool mIsTopmostScope;
+
enum MatchVisited {
eNeverMatchVisited,
eMatchVisitedDefault
@@ -429,6 +435,7 @@ struct MOZ_STACK_CLASS TreeMatchContext {
, mVisitedHandling(aVisitedHandling)
, mDocument(aDocument)
, mOnlyMatchHostPseudo(false)
+ , mRestrictToSlottedPseudo(false)
, mScopedRoot(nullptr)
, mIsHTMLDocument(aDocument->IsHTMLDocument())
, mCompatMode(aDocument->GetCompatibilityMode())
@@ -436,6 +443,7 @@ struct MOZ_STACK_CLASS TreeMatchContext {
, mSkippingParentDisplayBasedStyleFixup(false)
, mForScopedStyle(false)
, mCurrentStyleScope(nullptr)
+ , mIsTopmostScope(false)
{
if (aMatchVisited != eNeverMatchVisited) {
nsILoadContext* loadContext = mDocument->GetLoadContext();