summaryrefslogtreecommitdiff
path: root/layout
diff options
context:
space:
mode:
authorMatt A. Tobin <email@mattatobin.com>2021-12-05 20:16:02 -0500
committerMatt A. Tobin <email@mattatobin.com>2021-12-05 20:16:02 -0500
commit31022b58f3c139e48636a8cf8cb2c36812c72114 (patch)
tree7bb6538d2514b65a438ff777b53f02dc4ea9caa7 /layout
parentb93e885e46986f57e6bdff55327511122a0a4786 (diff)
downloadaura-central-31022b58f3c139e48636a8cf8cb2c36812c72114.tar.gz
Issue %3024 - First pass support for :host and :host-context
Diffstat (limited to 'layout')
-rw-r--r--layout/style/StyleRule.cpp23
-rw-r--r--layout/style/StyleRule.h7
-rw-r--r--layout/style/nsCSSParser.cpp5
-rw-r--r--layout/style/nsCSSPseudoClassList.h6
-rw-r--r--layout/style/nsCSSPseudoClasses.h7
-rw-r--r--layout/style/nsCSSRuleProcessor.cpp230
-rw-r--r--layout/style/nsRuleProcessorData.h35
-rw-r--r--layout/style/nsStyleSet.cpp3
8 files changed, 291 insertions, 25 deletions
diff --git a/layout/style/StyleRule.cpp b/layout/style/StyleRule.cpp
index 6fad62f8b..c8f1a0a91 100644
--- a/layout/style/StyleRule.cpp
+++ b/layout/style/StyleRule.cpp
@@ -148,7 +148,8 @@ nsPseudoClassList::nsPseudoClassList(CSSPseudoClassType aType,
: mType(aType),
mNext(nullptr)
{
- NS_ASSERTION(nsCSSPseudoClasses::HasSelectorListArg(aType),
+ NS_ASSERTION(nsCSSPseudoClasses::HasSelectorListArg(aType) ||
+ nsCSSPseudoClasses::HasOptionalSelectorListArg(aType),
"unexpected pseudo-class");
NS_ASSERTION(aSelectorList, "selector list expected");
MOZ_COUNT_CTOR(nsPseudoClassList);
@@ -313,6 +314,7 @@ nsCSSSelector::nsCSSSelector(void)
mPseudoClassList(nullptr),
mAttrList(nullptr),
mNegations(nullptr),
+ mExplicitUniversal(false),
mNext(nullptr),
mNameSpace(kNameSpaceID_Unknown),
mOperator(0),
@@ -382,6 +384,17 @@ void nsCSSSelector::Reset(void)
mOperator = char16_t(0);
}
+bool nsCSSSelector::HasFeatureSelectors()
+{
+ return mExplicitUniversal || mLowercaseTag || mCasedTag ||
+ mIDList || mClassList || mAttrList;
+}
+
+void nsCSSSelector::SetHasExplicitUniversal()
+{
+ mExplicitUniversal = true;
+}
+
void nsCSSSelector::SetNameSpace(int32_t aNameSpace)
{
mNameSpace = aNameSpace;
@@ -742,9 +755,9 @@ nsCSSSelector::AppendToStringWithoutCombinatorsOrNegations
// Universal selector: avoid writing the universal selector when we
// can avoid it, especially since we're required to avoid it for the
// inside of :not()
- if (wroteNamespace ||
+ if (wroteNamespace || mExplicitUniversal ||
(!mIDList && !mClassList && !mPseudoClassList && !mAttrList &&
- (aIsNegated || !mNegations))) {
+ aIsNegated)) {
aString.Append(char16_t('*'));
}
} else {
@@ -752,9 +765,7 @@ nsCSSSelector::AppendToStringWithoutCombinatorsOrNegations
nsAutoString tag;
(isPseudoElement ? mLowercaseTag : mCasedTag)->ToString(tag);
if (isPseudoElement) {
- if (!mNext) {
- // Lone pseudo-element selector -- toss in a wildcard type selector
- // XXXldb Why?
+ if (mExplicitUniversal) {
aString.Append(char16_t('*'));
}
// While our atoms use one colon, most pseudo-elements require two
diff --git a/layout/style/StyleRule.h b/layout/style/StyleRule.h
index 907e55448..dbf4e0840 100644
--- a/layout/style/StyleRule.h
+++ b/layout/style/StyleRule.h
@@ -151,6 +151,8 @@ public:
nsCSSSelector* Clone() const { return Clone(true, true); }
void Reset(void);
+ bool HasFeatureSelectors();
+ void SetHasExplicitUniversal();
void SetNameSpace(int32_t aNameSpace);
void SetTag(const nsString& aTag);
void AddID(const nsString& aID);
@@ -231,9 +233,10 @@ public:
// the argument to functional pseudos
nsAttrSelector* mAttrList;
nsCSSSelector* mNegations;
- nsCSSSelector* mNext;
+ bool mExplicitUniversal; // True if universal selector explicitly
+ nsCSSSelector* mNext; // appears in the selector
int32_t mNameSpace;
- char16_t mOperator;
+ char mOperator;
private:
// The underlying type of CSSPseudoElementType is uint8_t and
// it packs well with mOperator. (char16_t + uint8_t is less than 32bits.)
diff --git a/layout/style/nsCSSParser.cpp b/layout/style/nsCSSParser.cpp
index 3d5edbd0e..2e2700c38 100644
--- a/layout/style/nsCSSParser.cpp
+++ b/layout/style/nsCSSParser.cpp
@@ -5639,6 +5639,7 @@ CSSParserImpl::ParseTypeOrUniversalSelector(int32_t& aDataMask,
aSelector.SetTag(mToken.mIdent);
}
else if (mToken.IsSymbol('*')) { // universal selector
+ aSelector.SetHasExplicitUniversal();
aDataMask |= SEL_MASK_ELEM;
// don't set tag
}
@@ -5650,6 +5651,7 @@ CSSParserImpl::ParseTypeOrUniversalSelector(int32_t& aDataMask,
}
else { // was universal element selector
SetDefaultNamespaceOnSelector(aSelector);
+ aSelector.SetHasExplicitUniversal();
aDataMask |= SEL_MASK_ELEM;
// don't set any tag in the selector
}
@@ -6089,7 +6091,8 @@ CSSParserImpl::ParsePseudoSelector(int32_t& aDataMask,
CSSPseudoClassType::negation == pseudoClassType ||
nsCSSPseudoClasses::HasStringArg(pseudoClassType) ||
nsCSSPseudoClasses::HasNthPairArg(pseudoClassType) ||
- nsCSSPseudoClasses::HasSelectorListArg(pseudoClassType))) {
+ nsCSSPseudoClasses::HasSelectorListArg(pseudoClassType)) &&
+ !nsCSSPseudoClasses::HasOptionalSelectorListArg(pseudoClassType)) {
// There are no other function pseudos
REPORT_UNEXPECTED_TOKEN(PEPseudoSelNonFunc);
UngetToken();
diff --git a/layout/style/nsCSSPseudoClassList.h b/layout/style/nsCSSPseudoClassList.h
index 7f620ec32..c57c28bc0 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 55e5bf9d2..05f67b05c 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 aed26a1c0..f49b9d325 100644
--- a/layout/style/nsCSSRuleProcessor.cpp
+++ b/layout/style/nsCSSRuleProcessor.cpp
@@ -48,6 +48,7 @@
#include "nsCSSRules.h"
#include "nsStyleSet.h"
#include "mozilla/dom/Element.h"
+#include "mozilla/dom/ShadowRoot.h"
#include "nsNthIndexCache.h"
#include "mozilla/ArrayUtils.h"
#include "mozilla/EventStates.h"
@@ -1321,9 +1322,17 @@ struct NodeMatchContext {
// mForStyling is false, we have to assume we don't know.)
const bool mIsRelevantLink;
- NodeMatchContext(EventStates aStateMask, bool aIsRelevantLink)
+ // If the node should be considered featureless (as specified in
+ // selectors 4), then mIsFeature should be set to true to prevent
+ // matching unless the selector is a special pseudo class or pseudo
+ // element that matches featureless elements.
+ const bool mIsFeatureless;
+
+ NodeMatchContext(EventStates aStateMask, bool aIsRelevantLink,
+ bool aIsFeatureless = false)
: mStateMask(aStateMask)
, mIsRelevantLink(aIsRelevantLink)
+ , mIsFeatureless(aIsFeatureless)
{
}
};
@@ -1610,6 +1619,11 @@ StateSelectorMatches(Element* aElement,
return true;
}
+static bool AnySelectorInArgListMatches(Element* aElement,
+ nsPseudoClassList* aList,
+ NodeMatchContext& aNodeMatchContext,
+ TreeMatchContext& aTreeMatchContext);
+
static bool
StateSelectorMatches(Element* aElement,
nsCSSSelector* aSelector,
@@ -1631,6 +1645,26 @@ StateSelectorMatches(Element* aElement,
return true;
}
+// Returns whether aSelector can match featureless elements.
+static bool CanMatchFeaturelessElement(nsCSSSelector* aSelector)
+{
+ if (aSelector->HasFeatureSelectors()) {
+ return false;
+ }
+
+ for (nsPseudoClassList* pseudoClass = aSelector->mPseudoClassList;
+ pseudoClass;
+ pseudoClass = pseudoClass->mNext) {
+ if (pseudoClass->mType == CSSPseudoClassType::host ||
+ pseudoClass->mType == CSSPseudoClassType::hostContext) {
+ return true;
+ }
+ }
+
+ return false;
+}
+
+
// |aDependence| has two functions:
// * when non-null, it indicates that we're processing a negation,
// which is done only when SelectorMatches calls itself recursively
@@ -1651,6 +1685,11 @@ static bool SelectorMatches(Element* aElement,
"is false since we don't know how to set it correctly in "
"Has(Attribute|State)DependentStyle");
+ if (aNodeMatchContext.mIsFeatureless &&
+ !CanMatchFeaturelessElement(aSelector)) {
+ return false;
+ }
+
// namespace/tag match
// optimization : bail out early if we can
if ((kNameSpaceID_Unknown != aSelector->mNameSpace &&
@@ -1849,18 +1888,89 @@ static bool SelectorMatches(Element* aElement,
case CSSPseudoClassType::any:
{
- nsCSSSelectorList *l;
- for (l = pseudoClass->u.mSelectors; l; l = l->mNext) {
- nsCSSSelector *s = l->mSelectors;
- MOZ_ASSERT(!s->mNext && !s->IsPseudoElement(),
- "parser failed");
- if (SelectorMatches(
- aElement, s, aNodeMatchContext, aTreeMatchContext,
- SelectorMatchesFlags::IS_PSEUDO_CLASS_ARGUMENT)) {
+ if (!AnySelectorInArgListMatches(aElement, pseudoClass,
+ aNodeMatchContext,
+ aTreeMatchContext)) {
+ return false;
+ }
+ }
+ 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.
+
+ // We match automatically if GetParent() and GetShadowRoot() have
+ // the same result. Without special casing this ahead of all other
+ // selector matching, it fails. Have not determined the cause.
+
+ if (aElement->GetParent() == aElement->GetShadowRoot()) {
+ break;
+ }
+
+ // Match if any selector in the argument list matches.
+
+ NodeMatchContext nodeContext(EventStates(),
+ nsCSSRuleProcessor::IsLink(aElement));
+ if (AnySelectorInArgListMatches(aElement, pseudoClass,
+ nodeContext,
+ aTreeMatchContext)) {
+ break;
+ }
+
+ // Finally, with the exception of the two above cases, make sure we
+ // don't match if GetContainingShadow() returns null. For whatever
+ // reason, we can't test for this case first.
+
+ if (aElement->GetContainingShadow() == nullptr) {
+ return false;
+ }
+
+ }
+ 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 (!l) {
+ if (!currentElement) {
return false;
}
}
@@ -2242,6 +2352,26 @@ static bool SelectorMatches(Element* aElement,
return result;
}
+static bool AnySelectorInArgListMatches(Element* aElement,
+ nsPseudoClassList* aList,
+ NodeMatchContext& aNodeMatchContext,
+ TreeMatchContext& aTreeMatchContext)
+{
+ nsCSSSelectorList *l;
+ for (l = aList->u.mSelectors; l; l = l->mNext) {
+ nsCSSSelector *s = l->mSelectors;
+ MOZ_ASSERT(!s->mNext && !s->IsPseudoElement(),
+ "parser failed");
+ if (SelectorMatches(
+ aElement, s, aNodeMatchContext, aTreeMatchContext,
+ SelectorMatchesFlags::IS_PSEUDO_CLASS_ARGUMENT)) {
+ break;
+ }
+ }
+
+ return !!l;
+}
+
#undef STATE_CHECK
#ifdef DEBUG
@@ -2331,7 +2461,9 @@ SelectorMatchesTree(Element* aPrevElement,
MOZ_ASSERT(!aSelector || !aSelector->IsPseudoElement());
nsCSSSelector* selector = aSelector;
Element* prevElement = aPrevElement;
+ bool crossedShadowRootBoundary = false;
while (selector) { // check compound selectors
+ bool contentIsFeatureless = false;
NS_ASSERTION(!selector->mNext ||
selector->mNext->mOperator != char16_t(0),
"compound selector without combinator");
@@ -2362,6 +2494,20 @@ SelectorMatchesTree(Element* aPrevElement,
// to test against is the parent
else {
nsIContent *content = prevElement->GetParent();
+
+ // In the shadow tree, the shadow host behaves as if it
+ // is a featureless parent of top-level elements of the shadow
+ // tree. Only cross shadow root boundary when the selector is the
+ // left most selector because ancestors of the host are not in
+ // the selector match list.
+ ShadowRoot* shadowRoot = content ?
+ ShadowRoot::FromNode(content) : nullptr;
+ if (shadowRoot && !selector->mNext && !crossedShadowRootBoundary) {
+ content = shadowRoot->GetHost();
+ crossedShadowRootBoundary = true;
+ contentIsFeatureless = true;
+ }
+
// GetParent could return a document fragment; we only want
// element parents.
if (content && content->IsElement()) {
@@ -2413,7 +2559,8 @@ SelectorMatchesTree(Element* aPrevElement,
}
const bool isRelevantLink = (aFlags & eLookForRelevantLink) &&
nsCSSRuleProcessor::IsLink(element);
- NodeMatchContext nodeContext(EventStates(), isRelevantLink);
+
+ NodeMatchContext nodeContext(EventStates(), isRelevantLink, contentIsFeatureless);
if (isRelevantLink) {
// If we find an ancestor of the matched node that is a link
// during the matching process, then it's the relevant link (see
@@ -2483,6 +2630,29 @@ 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 (!data->mTreeMatchContext.SetStyleScopeForSelectorMatching(data->mElement,
data->mScope)) {
// The selector is for a rule in a scoped style sheet, and the subject
@@ -2542,7 +2712,8 @@ nsCSSRuleProcessor::RulesMatching(ElementRuleProcessorData *aData)
if (cascade) {
NodeMatchContext nodeContext(EventStates(),
- nsCSSRuleProcessor::IsLink(aData->mElement));
+ nsCSSRuleProcessor::IsLink(aData->mElement),
+ aData->mElementIsFeatureless);
cascade->mRuleHash.EnumerateAllRules(aData->mElement, aData, nodeContext);
}
}
@@ -2824,6 +2995,34 @@ 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, ignoring eRestyle_SomeDescendants, enumData->change already includes
// all the bits of possibleChange, don't bother calling SelectorMatches, since
@@ -3295,10 +3494,12 @@ AddSelector(RuleCascadeData* aCascade,
}
}
- // Recur through any :-moz-any selectors
+ // 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,
@@ -3943,6 +4144,7 @@ TreeMatchContext::InitAncestors(Element *aElement)
for (uint32_t i = ancestors.Length(); i-- != 0; ) {
mAncestorFilter.PushAncestor(ancestors[i]);
PushStyleScope(ancestors[i]);
+ PushShadowHost(ancestors[i]);
}
}
}
diff --git a/layout/style/nsRuleProcessorData.h b/layout/style/nsRuleProcessorData.h
index fbaa768cc..f6d977100 100644
--- a/layout/style/nsRuleProcessorData.h
+++ b/layout/style/nsRuleProcessorData.h
@@ -164,6 +164,23 @@ struct MOZ_STACK_CLASS TreeMatchContext {
mStyleScopes.TruncateLength(mStyleScopes.Length() - 1);
}
}
+
+ void PushShadowHost(mozilla::dom::Element* aElement)
+ {
+ NS_PRECONDITION(aElement, "aElement must not be null");
+ if (aElement->GetShadowRoot()) {
+ mShadowHosts.AppendElement(aElement);
+ }
+ }
+
+ void PopShadowHost(mozilla::dom::Element* aElement)
+ {
+ NS_PRECONDITION(aElement, "aElement must not be null");
+ if (mShadowHosts.SafeLastElement(nullptr) == aElement) {
+ mShadowHosts.TruncateLength(mShadowHosts.Length() - 1);
+ }
+ }
+
bool PopStyleScopeForSelectorMatching(mozilla::dom::Element* aElement)
{
@@ -233,6 +250,7 @@ struct MOZ_STACK_CLASS TreeMatchContext {
MOZ_GUARD_OBJECT_NOTIFIER_PARAM)
: mPushedAncestor(false)
, mPushedStyleScope(false)
+ , mPushedShadowHost(false)
, mTreeMatchContext(aTreeMatchContext)
, mElement(nullptr)
{
@@ -245,8 +263,10 @@ struct MOZ_STACK_CLASS TreeMatchContext {
mElement = aElement;
mPushedAncestor = true;
mPushedStyleScope = true;
+ mPushedShadowHost = true;
mTreeMatchContext.mAncestorFilter.PushAncestor(aElement);
mTreeMatchContext.PushStyleScope(aElement);
+ mTreeMatchContext.PushShadowHost(aElement);
}
}
@@ -278,11 +298,15 @@ struct MOZ_STACK_CLASS TreeMatchContext {
if (mPushedStyleScope) {
mTreeMatchContext.PopStyleScope(mElement);
}
+ if (mPushedShadowHost) {
+ mTreeMatchContext.PopShadowHost(mElement);
+ }
}
private:
bool mPushedAncestor;
bool mPushedStyleScope;
+ bool mPushedShadowHost;
TreeMatchContext& mTreeMatchContext;
mozilla::dom::Element* mElement;
MOZ_DECL_USE_GUARD_OBJECT_NOTIFIER
@@ -342,6 +366,11 @@ struct MOZ_STACK_CLASS TreeMatchContext {
// The document we're working with.
nsIDocument* const mDocument;
+ // Only selectors that contain :host or :host-context pseudo class
+ // should be matched against elements. All other selectors should not
+ // match.
+ bool mOnlyMatchHostPseudo;
+
// Root of scoped stylesheet (set and unset by the supplier of the
// scoped stylesheet).
nsIContent* mScopedRoot;
@@ -383,6 +412,9 @@ struct MOZ_STACK_CLASS TreeMatchContext {
// <style scoped> child).
AutoTArray<mozilla::dom::Element*, 1> mStyleScopes;
+ // List of ancestor elements that are a shadow root host.
+ AutoTArray<mozilla::dom::Element*, 1> mShadowHosts;
+
// The current style scope element for selector matching.
mozilla::dom::Element* mCurrentStyleScope;
@@ -396,6 +428,7 @@ struct MOZ_STACK_CLASS TreeMatchContext {
, mHaveSpecifiedScope(false)
, mVisitedHandling(aVisitedHandling)
, mDocument(aDocument)
+ , mOnlyMatchHostPseudo(false)
, mScopedRoot(nullptr)
, mIsHTMLDocument(aDocument->IsHTMLDocument())
, mCompatMode(aDocument->GetCompatibilityMode())
@@ -437,6 +470,7 @@ struct MOZ_STACK_CLASS ElementDependentRuleProcessorData :
: RuleProcessorData(aPresContext, aRuleWalker)
, mElement(aElement)
, mTreeMatchContext(aTreeMatchContext)
+ , mElementIsFeatureless(false)
{
NS_ASSERTION(aElement, "null element leaked into SelectorMatches");
NS_ASSERTION(aElement->OwnerDoc(), "Document-less node here?");
@@ -446,6 +480,7 @@ struct MOZ_STACK_CLASS ElementDependentRuleProcessorData :
mozilla::dom::Element* const mElement; // weak ref, must not be null
TreeMatchContext& mTreeMatchContext;
+ bool mElementIsFeatureless;
};
struct MOZ_STACK_CLASS ElementRuleProcessorData :
diff --git a/layout/style/nsStyleSet.cpp b/layout/style/nsStyleSet.cpp
index 5890100eb..edf61d2f9 100644
--- a/layout/style/nsStyleSet.cpp
+++ b/layout/style/nsStyleSet.cpp
@@ -1311,8 +1311,9 @@ nsStyleSet::WalkRuleProcessors(nsIStyleRuleProcessor::EnumFunc aFunc,
if (mBindingManager) {
// We can supply additional document-level sheets that should be walked.
if (aWalkAllXBLStylesheets) {
- mBindingManager->WalkAllRules(aFunc, aData);
+ mBindingManager->WalkAllRules(aFunc, aData, false);
} else {
+ mBindingManager->WalkAllShadowRootHostRules(aFunc, aData);
mBindingManager->WalkRules(aFunc, aData, &cutOffInheritance);
}
}