summaryrefslogtreecommitdiff
path: root/layout
diff options
context:
space:
mode:
authorJeremy Andrews <athenian200@outlook.com>2021-11-04 05:49:36 -0500
committerMoonchild <moonchild@palemoon.org>2022-04-19 21:44:23 +0000
commitf82c95d1eb4cdb2c814700944c64b8836021b600 (patch)
tree1d1bb87e95d3aefd89aae6e7b70802540e5ef962 /layout
parent01747509f6b63a275e0b379f0527cecbbf7b943d (diff)
downloaduxp-f82c95d1eb4cdb2c814700944c64b8836021b600.tar.gz
Issue #1593 - Part 3: Add selector logic for :host and :host-context.
Diffstat (limited to 'layout')
-rw-r--r--layout/style/nsCSSPseudoClassList.h6
-rw-r--r--layout/style/nsCSSPseudoClasses.h7
-rw-r--r--layout/style/nsCSSRuleProcessor.cpp95
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,