import from UXP: Issue #1592 - Part 4: Walk ::slotted()-containing rules for slottables (518c41fd)

This commit is contained in:
2023-03-24 09:45:18 +08:00
parent adae2cbc79
commit 732d496633
3 changed files with 104 additions and 47 deletions
+39
View File
@@ -682,6 +682,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;
+57 -47
View File
@@ -2656,6 +2656,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
@@ -2734,6 +2740,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,
@@ -2748,29 +2800,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
@@ -3115,35 +3149,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
+8
View File
@@ -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();