diff options
author | Jeremy Andrews <athenian200@outlook.com> | 2021-11-04 03:47:57 -0500 |
---|---|---|
committer | Moonchild <moonchild@palemoon.org> | 2022-04-19 21:42:11 +0000 |
commit | 22b8e6b79f5a566c7e106bf98d4125f5faa661f4 (patch) | |
tree | f97d9f663f056871bccd0a294bcb17059dd2067f /layout | |
parent | f9b28d20069b39b2e8a141415e4ac89b4808fbdd (diff) | |
download | uxp-22b8e6b79f5a566c7e106bf98d4125f5faa661f4.tar.gz |
Issue #1593 - Part 1: Import William Chen's patches w/o selector implementation,
fixed up.
Diffstat (limited to 'layout')
-rw-r--r-- | layout/style/StyleRule.cpp | 23 | ||||
-rw-r--r-- | layout/style/StyleRule.h | 7 | ||||
-rw-r--r-- | layout/style/nsCSSParser.cpp | 5 | ||||
-rw-r--r-- | layout/style/nsCSSRuleProcessor.cpp | 124 | ||||
-rw-r--r-- | layout/style/nsRuleProcessorData.h | 35 | ||||
-rw-r--r-- | layout/style/nsStyleSet.cpp | 3 |
6 files changed, 171 insertions, 26 deletions
diff --git a/layout/style/StyleRule.cpp b/layout/style/StyleRule.cpp index 6fad62f8b6..c8f1a0a91e 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 907e55448a..dbf4e08406 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 2ba1e9b7f3..70115d2a4a 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/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]); } } } diff --git a/layout/style/nsRuleProcessorData.h b/layout/style/nsRuleProcessorData.h index fbaa768cc9..f6d9771001 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 5890100eb0..edf61d2f98 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); } } |