diff options
author | FranklinDM <mrmineshafter17@gmail.com> | 2023-03-10 00:20:44 +0800 |
---|---|---|
committer | FranklinDM <mrmineshafter17@gmail.com> | 2023-03-10 19:14:24 +0800 |
commit | de225cca0d256117e2a0da990fd8c50e79ac6a1c (patch) | |
tree | 537100f04f2d0c7060b39924ecb69b031da6a88f /layout | |
parent | 476dec2351c75e3bf7355fbe111c604f32e5b558 (diff) | |
download | uxp-de225cca0d256117e2a0da990fd8c50e79ac6a1c.tar.gz |
Issue #2137 - Part 1: Modify :not() selector to accept a complex selector list
Diffstat (limited to 'layout')
-rw-r--r-- | layout/style/StyleRule.cpp | 12 | ||||
-rw-r--r-- | layout/style/nsCSSParser.cpp | 78 | ||||
-rw-r--r-- | layout/style/nsCSSPseudoClassList.h | 5 | ||||
-rw-r--r-- | layout/style/nsCSSPseudoClasses.cpp | 8 | ||||
-rw-r--r-- | layout/style/nsCSSPseudoClasses.h | 1 | ||||
-rw-r--r-- | layout/style/nsCSSRuleProcessor.cpp | 11 |
6 files changed, 80 insertions, 35 deletions
diff --git a/layout/style/StyleRule.cpp b/layout/style/StyleRule.cpp index 815c6f96cc..9c6f73ffe1 100644 --- a/layout/style/StyleRule.cpp +++ b/layout/style/StyleRule.cpp @@ -908,9 +908,13 @@ nsCSSSelector::AppendToStringWithoutCombinatorsOrNegations // has a ":" that can't be escaped and (b) all pseudo-classes at // this point are known, and therefore we know they don't need // escaping. - aString.Append(temp); + if (!nsCSSPseudoClasses::IsHiddenFromSerialization(list->mType)) { + aString.Append(temp); + } if (list->u.mMemory) { - aString.Append(char16_t('(')); + if (!nsCSSPseudoClasses::IsHiddenFromSerialization(list->mType)) { + aString.Append(char16_t('(')); + } if (nsCSSPseudoClasses::HasStringArg(list->mType)) { nsStyleUtil::AppendEscapedCSSIdent( nsDependentString(list->u.mString), aString); @@ -939,7 +943,9 @@ nsCSSSelector::AppendToStringWithoutCombinatorsOrNegations list->u.mSelectorList->ToString(tmp, aSheet); aString.Append(tmp); } - aString.Append(char16_t(')')); + if (!nsCSSPseudoClasses::IsHiddenFromSerialization(list->mType)) { + aString.Append(char16_t(')')); + } } } } diff --git a/layout/style/nsCSSParser.cpp b/layout/style/nsCSSParser.cpp index f9f198417f..f60b1c5287 100644 --- a/layout/style/nsCSSParser.cpp +++ b/layout/style/nsCSSParser.cpp @@ -67,6 +67,7 @@ static bool sWebkitPrefixedAliasesEnabled; static bool sWebkitDevicePixelRatioEnabled; static bool sMozGradientsEnabled; static bool sControlCharVisibility; +static bool sLegacyNegationPseudoClassEnabled; const uint32_t nsCSSProps::kParserVariantTable[eCSSProperty_COUNT_no_shorthands] = { @@ -6144,7 +6145,6 @@ CSSParserImpl::ParsePseudoSelector(int32_t& aDataMask, // is that of a function pseudo it better be a function token if ((eCSSToken_Function == mToken.mType) != (isTree || - CSSPseudoClassType::negation == pseudoClassType || nsCSSPseudoClasses::HasStringArg(pseudoClassType) || nsCSSPseudoClasses::HasNthPairArg(pseudoClassType) || nsCSSPseudoClasses::HasSelectorListArg(pseudoClassType)) && @@ -6182,25 +6182,26 @@ CSSParserImpl::ParsePseudoSelector(int32_t& aDataMask, } } - if (!parsingPseudoElement && - CSSPseudoClassType::negation == pseudoClassType) { - if (aIsNegated) { // :not() can't be itself negated - REPORT_UNEXPECTED_TOKEN(PEPseudoSelDoubleNot); - UngetToken(); - return eSelectorParsingStatus_Error; - } - // CSS 3 Negation pseudo-class takes one simple selector as argument - nsSelectorParsingStatus parsingStatus = - ParseNegatedSimpleSelector(aDataMask, aSelector); - if (eSelectorParsingStatus_Continue != parsingStatus) { - return parsingStatus; - } - } - else if (!parsingPseudoElement && isPseudoClass) { + if (!parsingPseudoElement && isPseudoClass) { aDataMask |= SEL_MASK_PCLASS; if (eCSSToken_Function == mToken.mType) { nsSelectorParsingStatus parsingStatus; - if (nsCSSPseudoClasses::HasStringArg(pseudoClassType)) { + if (sLegacyNegationPseudoClassEnabled && + CSSPseudoClassType::negation == pseudoClassType) { + // :not() can't be itself negated + if (aIsNegated) { + REPORT_UNEXPECTED_TOKEN(PEPseudoSelDoubleNot); + UngetToken(); + return eSelectorParsingStatus_Error; + } + // CSS 3 Negation pseudo-class takes one simple selector as argument + parsingStatus = + ParseNegatedSimpleSelector(aDataMask, aSelector); + if (eSelectorParsingStatus_Continue != parsingStatus) { + return parsingStatus; + } + } + else if (nsCSSPseudoClasses::HasStringArg(pseudoClassType)) { parsingStatus = ParsePseudoClassWithIdentArg(aSelector, pseudoClassType); } @@ -6578,8 +6579,6 @@ CSSParserImpl::ParsePseudoClassWithNthPairArg(nsCSSSelector& aSelector, // // Parse the argument of a pseudo-class that has a selector list argument. -// Such selector lists cannot contain combinators, but can contain -// anything that goes between a pair of combinators. // CSSParserImpl::nsSelectorParsingStatus CSSParserImpl::ParsePseudoClassWithSelectorListArg(nsCSSSelector& aSelector, @@ -6607,22 +6606,35 @@ CSSParserImpl::ParsePseudoClassWithSelectorListArg(nsCSSSelector& aSelector, return eSelectorParsingStatus_Error; // our caller calls SkipUntil(')') } - for (nsCSSSelectorList *l = slist; l; l = l->mNext) { - nsCSSSelector *s = l->mSelectors; - if (s == nullptr) { - MOZ_ASSERT(isForgiving, - "unexpected empty selector in unforgiving selector list"); - break; + // Special handling for the :not() pseudo-class. + if (aType == CSSPseudoClassType::negation) { + nsCSSSelector* negations = &aSelector; + while (negations->mNegations) { + negations = negations->mNegations; } - // Check that none of the selectors in the list have combinators or - // pseudo-elements. - if ((!isForgiving && s->mNext) || s->IsPseudoElement()) { - return eSelectorParsingStatus_Error; // our caller calls SkipUntil(')') + // XXX: Use a special internal-only pseudo-class to handle selector lists. + // TODO: This should only happen if we don't have a simple selector. + nsCSSSelector* newSel = new nsCSSSelector(); + newSel->AddPseudoClass(CSSPseudoClassType::mozAnyPrivate, slist.forget()); + negations->mNegations = newSel; + } else { + for (nsCSSSelectorList *l = slist; l; l = l->mNext) { + nsCSSSelector *s = l->mSelectors; + if (s == nullptr) { + MOZ_ASSERT(isForgiving, + "unexpected empty selector in unforgiving selector list"); + break; + } + // Check that none of the selectors in the list have combinators or + // pseudo-elements. + if ((!isForgiving && s->mNext) || s->IsPseudoElement()) { + return eSelectorParsingStatus_Error; // our caller calls SkipUntil(')') + } } - } - // Add the pseudo with the selector list parameter - aSelector.AddPseudoClass(aType, slist.forget()); + // Add the pseudo with the selector list parameter + aSelector.AddPseudoClass(aType, slist.forget()); + } // close the parenthesis if (!ExpectSymbol(')', true)) { @@ -17899,6 +17911,8 @@ nsCSSParser::Startup() "layout.css.prefixes.gradients"); Preferences::AddBoolVarCache(&sControlCharVisibility, "layout.css.control-characters.visible"); + Preferences::AddBoolVarCache(&sLegacyNegationPseudoClassEnabled, + "layout.css.legacy-negation-pseudo.enabled"); } nsCSSParser::nsCSSParser(mozilla::css::Loader* aLoader, diff --git a/layout/style/nsCSSPseudoClassList.h b/layout/style/nsCSSPseudoClassList.h index 740ebcc422..cbe3bd8f92 100644 --- a/layout/style/nsCSSPseudoClassList.h +++ b/layout/style/nsCSSPseudoClassList.h @@ -133,6 +133,11 @@ CSS_PSEUDO_CLASS(mozBrowserFrame, ":-moz-browser-frame", // matching operation. CSS_PSEUDO_CLASS(scope, ":scope", 0, "layout.css.scope-pseudo.enabled") +// Matches selectors inside the selector list argument. Unlike :is(), +// this is unforgiving and hidden from serialization. +CSS_PSEUDO_CLASS(mozAnyPrivate, ":-moz-any-private", + CSS_PSEUDO_CLASS_ENABLED_IN_UA_SHEETS_AND_CHROME, "") + // :not needs to come at the end of the non-bit pseudo-class list, since // it doesn't actually get directly matched on in SelectorMatches. CSS_PSEUDO_CLASS(negation, ":not", 0, "") diff --git a/layout/style/nsCSSPseudoClasses.cpp b/layout/style/nsCSSPseudoClasses.cpp index 23517ef52c..0fc460a514 100644 --- a/layout/style/nsCSSPseudoClasses.cpp +++ b/layout/style/nsCSSPseudoClasses.cpp @@ -122,7 +122,9 @@ bool nsCSSPseudoClasses::HasSelectorListArg(Type aType) { return HasForgivingSelectorListArg(aType) || + aType == Type::negation || aType == Type::mozAny || + aType == Type::mozAnyPrivate || aType == Type::host || aType == Type::hostContext; } @@ -133,6 +135,12 @@ nsCSSPseudoClasses::HasOptionalSelectorListArg(Type aType) return aType == Type::host; } +bool +nsCSSPseudoClasses::IsHiddenFromSerialization(Type aType) +{ + return aType == Type::mozAnyPrivate; +} + void nsCSSPseudoClasses::PseudoTypeToString(Type aType, nsAString& aString) { diff --git a/layout/style/nsCSSPseudoClasses.h b/layout/style/nsCSSPseudoClasses.h index 99c05b019f..ff2da74ff0 100644 --- a/layout/style/nsCSSPseudoClasses.h +++ b/layout/style/nsCSSPseudoClasses.h @@ -62,6 +62,7 @@ public: static bool HasForgivingSelectorListArg(Type aType); static bool HasSelectorListArg(Type aType); static bool HasOptionalSelectorListArg(Type aType); + static bool IsHiddenFromSerialization(Type aType); static bool IsUserActionPseudoClass(Type aType); // Should only be used on types other than Count and NotPseudoClass diff --git a/layout/style/nsCSSRuleProcessor.cpp b/layout/style/nsCSSRuleProcessor.cpp index f637a063a6..dc2157084b 100644 --- a/layout/style/nsCSSRuleProcessor.cpp +++ b/layout/style/nsCSSRuleProcessor.cpp @@ -1931,6 +1931,17 @@ static bool SelectorMatches(Element* aElement, } break; + case CSSPseudoClassType::mozAnyPrivate: + { + if (!SelectorListMatches(aElement, + pseudoClass, + aNodeMatchContext, + aTreeMatchContext)) { + return false; + } + } + break; + case CSSPseudoClassType::host: { // In order to match :host, the element must be a shadow root host, |