diff options
author | Jeremy Andrews <athenian200@outlook.com> | 2021-11-04 05:49:36 -0500 |
---|---|---|
committer | Moonchild <moonchild@palemoon.org> | 2022-04-19 21:44:23 +0000 |
commit | f82c95d1eb4cdb2c814700944c64b8836021b600 (patch) | |
tree | 1d1bb87e95d3aefd89aae6e7b70802540e5ef962 | |
parent | 01747509f6b63a275e0b379f0527cecbbf7b943d (diff) | |
download | uxp-f82c95d1eb4cdb2c814700944c64b8836021b600.tar.gz |
Issue #1593 - Part 3: Add selector logic for :host and :host-context.
-rw-r--r-- | layout/style/nsCSSPseudoClassList.h | 6 | ||||
-rw-r--r-- | layout/style/nsCSSPseudoClasses.h | 7 | ||||
-rw-r--r-- | layout/style/nsCSSRuleProcessor.cpp | 95 |
3 files changed, 105 insertions, 3 deletions
diff --git a/layout/style/nsCSSPseudoClassList.h b/layout/style/nsCSSPseudoClassList.h index 7f620ec32f..c57c28bc0b 100644 --- a/layout/style/nsCSSPseudoClassList.h +++ b/layout/style/nsCSSPseudoClassList.h @@ -133,6 +133,12 @@ CSS_PSEUDO_CLASS(scope, ":scope", 0, "layout.css.scope-pseudo.enabled") // it doesn't actually get directly matched on in SelectorMatches. CSS_PSEUDO_CLASS(negation, ":not", 0, "") +// http://drafts.csswg.org/css-scoping/#selectordef-host-context +CSS_PSEUDO_CLASS(hostContext, ":host-context", 0, "dom.webcomponents.enabled") + +// http://drafts.csswg.org/css-scoping/#selectordef-host-context +CSS_PSEUDO_CLASS(host, ":host", 0, "dom.webcomponents.enabled") + // :dir(ltr) and :dir(rtl) match elements whose resolved // directionality in the markup language is ltr or rtl respectively. CSS_STATE_DEPENDENT_PSEUDO_CLASS(dir, ":dir", 0, "", diff --git a/layout/style/nsCSSPseudoClasses.h b/layout/style/nsCSSPseudoClasses.h index 55e5bf9d2e..05f67b05cd 100644 --- a/layout/style/nsCSSPseudoClasses.h +++ b/layout/style/nsCSSPseudoClasses.h @@ -59,7 +59,12 @@ public: static bool HasStringArg(Type aType); static bool HasNthPairArg(Type aType); static bool HasSelectorListArg(Type aType) { - return aType == Type::any; + return aType == Type::any || + aType == Type::host || + aType == Type::hostContext; + } + static bool HasOptionalSelectorListArg(Type aType) { + return aType == Type::host; } static bool IsUserActionPseudoClass(Type aType); diff --git a/layout/style/nsCSSRuleProcessor.cpp b/layout/style/nsCSSRuleProcessor.cpp index 04b4e3608e..a30d1cd098 100644 --- a/layout/style/nsCSSRuleProcessor.cpp +++ b/layout/style/nsCSSRuleProcessor.cpp @@ -1652,6 +1652,15 @@ static bool CanMatchFeaturelessElement(nsCSSSelector* aSelector) return false; } + for (nsPseudoClassList* pseudoClass = aSelector->mPseudoClassList; + pseudoClass; + pseudoClass = pseudoClass->mNext) { + if (pseudoClass->mType == CSSPseudoClassType::host || + pseudoClass->mType == CSSPseudoClassType::hostContext) { + return true; + } + } + return false; } @@ -1887,6 +1896,67 @@ static bool SelectorMatches(Element* aElement, } break; + case CSSPseudoClassType::host: + { + // In order to match :host, the element must be a shadow root host, + // we must be matching only against host pseudo selectors, and the + // selector's context must be the shadow root (the selector must be + // featureless, the left-most selector, and be in a shadow root + // style). The :host selector may also be be functional, with a + // compound selector. If this is the case, then also ensure that the + // host element matches against the compound + // selector. + return aElement->GetShadowRoot() && + aTreeMatchContext.mOnlyMatchHostPseudo && + !aSelector->HasFeatureSelectors() && + !aSelector->mNext && + (!pseudoClass->u.mSelectors || + AnySelectorInArgListMatches(aElement, pseudoClass, + aNodeMatchContext, + aTreeMatchContext)); + } + break; + + + case CSSPseudoClassType::hostContext: + { + // In order to match host-context, the element must be a + // shadow root host and the selector's context must be the + // shadow root (aTreeMatchContext.mScopedRoot is set to the + // host of the shadow root where the style is contained, + // thus the element must be mScopedRoot). If the UNKNOWN + // selector flag is set, relax the shadow root host + // requirement because this pseudo class walks through + // ancestors looking for a match, thus the selector can be + // dependant on aElement even though it is not the host. The + // dependency would otherwise be missed because when UNKNOWN + // is set, selector matching may not have started from the top. + if (!((aElement->GetShadowRoot() && + aElement == aTreeMatchContext.mScopedRoot) || + aSelectorFlags & SelectorMatchesFlags::UNKNOWN)) { + return false; + } + + Element* currentElement = aElement; + while (currentElement) { + NodeMatchContext nodeContext(EventStates(), + nsCSSRuleProcessor::IsLink(currentElement)); + if (AnySelectorInArgListMatches(currentElement, pseudoClass, + nodeContext, + aTreeMatchContext)) { + break; + } + + nsIContent* flattenedParent = currentElement->GetFlattenedTreeParent(); + currentElement = flattenedParent && flattenedParent->IsElement() ? + flattenedParent->AsElement() : nullptr; + } + if (!currentElement) { + return false; + } + } + break; + case CSSPseudoClassType::firstChild: if (!edgeChildMatches(aElement, aTreeMatchContext, true, false)) { return false; @@ -2550,6 +2620,15 @@ void ContentEnumFunc(const RuleValue& value, nsCSSSelector* aSelector, } 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; @@ -2906,7 +2985,17 @@ AttributeEnumFunc(nsCSSSelector* aSelector, } bool seenHostPseudo = false; - break; + 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; } } @@ -3389,7 +3478,9 @@ AddSelector(RuleCascadeData* aCascade, // Recur through any :-moz-any or :host-context selectors for (nsPseudoClassList* pseudoClass = negation->mPseudoClassList; pseudoClass; pseudoClass = pseudoClass->mNext) { - if (pseudoClass->mType == CSSPseudoClassType::any) { + if (pseudoClass->mType == CSSPseudoClassType::any || + pseudoClass->mType == CSSPseudoClassType::host || + pseudoClass->mType == CSSPseudoClassType::hostContext) { for (nsCSSSelectorList *l = pseudoClass->u.mSelectors; l; l = l->mNext) { nsCSSSelector *s = l->mSelectors; if (!AddSelector(aCascade, aSelectorInTopLevel, s, |