diff options
Diffstat (limited to 'layout/style/nsCSSRuleProcessor.cpp')
-rw-r--r-- | layout/style/nsCSSRuleProcessor.cpp | 124 |
1 files changed, 108 insertions, 16 deletions
diff --git a/layout/style/nsCSSRuleProcessor.cpp b/layout/style/nsCSSRuleProcessor.cpp index aed26a1c01..04b4e3608e 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,17 @@ StateSelectorMatches(Element* aElement, return true; } +// Returns whether aSelector can match featureless elements. +static bool CanMatchFeaturelessElement(nsCSSSelector* aSelector) +{ + if (aSelector->HasFeatureSelectors()) { + return false; + } + + 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 +1676,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 +1879,9 @@ 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)) { - break; - } - } - if (!l) { + if (!AnySelectorInArgListMatches(aElement, pseudoClass, + aNodeMatchContext, + aTreeMatchContext)) { return false; } } @@ -2242,6 +2263,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 +2372,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 +2405,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 +2470,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 +2541,20 @@ 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; + + 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 +2614,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 +2897,24 @@ 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; + break; + } + } + + if (!seenHostPseudo) { + return; + } + } + // If, ignoring eRestyle_SomeDescendants, enumData->change already includes // all the bits of possibleChange, don't bother calling SelectorMatches, since @@ -3295,7 +3386,7 @@ 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) { @@ -3943,6 +4034,7 @@ TreeMatchContext::InitAncestors(Element *aElement) for (uint32_t i = ancestors.Length(); i-- != 0; ) { mAncestorFilter.PushAncestor(ancestors[i]); PushStyleScope(ancestors[i]); + PushShadowHost(ancestors[i]); } } } |