diff options
author | Moonchild <moonchild@palemoon.org> | 2023-03-11 17:57:09 +0000 |
---|---|---|
committer | Moonchild <moonchild@palemoon.org> | 2023-03-11 17:57:09 +0000 |
commit | e848bea43f466c25eaca6e0aa074d1c89fb086d6 (patch) | |
tree | 8df2dc581e5bb1ad76710824b57c7d6541fd0c34 /layout | |
parent | 4c4bc3ca0f8e6e92c208ea182e7f899252e11fff (diff) | |
parent | 18c6aa0252602789d50c7eef94b2356e44d8e468 (diff) | |
download | uxp-e848bea43f466c25eaca6e0aa074d1c89fb086d6.tar.gz |
Merge pull request 'Modify :not() selector to accept a complex selector list' (#2151) from FranklinDM/UXP-contrib:work_css-not-selector-list-support into master
Reviewed-on: https://repo.palemoon.org/MoonchildProductions/UXP/pulls/2151
Diffstat (limited to 'layout')
-rw-r--r-- | layout/style/StyleRule.cpp | 12 | ||||
-rw-r--r-- | layout/style/nsCSSParser.cpp | 244 | ||||
-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, 175 insertions, 106 deletions
diff --git a/layout/style/StyleRule.cpp b/layout/style/StyleRule.cpp index 437806a1b8..101bb0f4d7 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..8c4f16f24d 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] = { @@ -109,6 +110,19 @@ enum class GridTrackListFlags { }; MOZ_MAKE_ENUM_CLASS_BITWISE_OPERATORS(GridTrackListFlags) +/** + * Additional information about a selector being parsed. + */ +enum class SelectorParsingFlags { + eNone = 0, + eIsNegated = 1 << 0, + eIsForgiving = 1 << 1, + eDisallowCombinators = 1 << 2, + eDisallowPseudoElements = 1 << 3, + eInheritNamespace = 1 << 4 +}; +MOZ_MAKE_ENUM_CLASS_BITWISE_OPERATORS(SelectorParsingFlags) + namespace { // Rule processing function @@ -759,21 +773,21 @@ protected: // aPseudoElement and aPseudoElementArgs are the location where // pseudo-elements (as opposed to pseudo-classes) are stored; // pseudo-classes are stored on aSelector. aPseudoElement and - // aPseudoElementArgs must be non-null iff !aIsNegated. - nsSelectorParsingStatus ParsePseudoSelector(int32_t& aDataMask, - nsCSSSelector& aSelector, - bool aIsNegated, - nsIAtom** aPseudoElement, - nsAtomList** aPseudoElementArgs, - CSSPseudoElementType* aPseudoElementType, - bool aDisallowCombinators); + // aPseudoElementArgs must be non-null iff the eIsNegated flag of + // aFlags is not set. + nsSelectorParsingStatus ParsePseudoSelector(int32_t& aDataMask, + nsCSSSelector& aSelector, + SelectorParsingFlags aFlags, + nsIAtom** aPseudoElement, + nsAtomList** aPseudoElementArgs, + CSSPseudoElementType* aPseudoElementType); nsSelectorParsingStatus ParseAttributeSelector(int32_t& aDataMask, nsCSSSelector& aSelector); - nsSelectorParsingStatus ParseTypeOrUniversalSelector(int32_t& aDataMask, - nsCSSSelector& aSelector, - bool aIsNegated); + nsSelectorParsingStatus ParseTypeOrUniversalSelector(int32_t& aDataMask, + nsCSSSelector& aSelector, + SelectorParsingFlags aFlags); nsSelectorParsingStatus ParsePseudoClassWithIdentArg(nsCSSSelector& aSelector, CSSPseudoClassType aType); @@ -783,24 +797,22 @@ protected: nsSelectorParsingStatus ParsePseudoClassWithSelectorListArg(nsCSSSelector& aSelector, CSSPseudoClassType aType, - bool aDisallowCombinators); + SelectorParsingFlags aFlags); - nsSelectorParsingStatus ParseNegatedSimpleSelector(int32_t& aDataMask, - nsCSSSelector& aSelector); + nsSelectorParsingStatus ParseNegatedSimpleSelector(int32_t& aDataMask, + nsCSSSelector& aSelector, + SelectorParsingFlags aFlags); // If aStopChar is non-zero, the selector list is done when we hit // aStopChar. Otherwise, it's done when we hit EOF. bool ParseSelectorList(nsCSSSelectorList*& aListHead, char16_t aStopChar, - bool aIsForgiving, - bool aDisallowCombinators); + SelectorParsingFlags aFlags = SelectorParsingFlags::eNone); bool ParseSelectorGroup(nsCSSSelectorList*& aListHead, - bool aIsForgiving, - bool aDisallowCombinators); + SelectorParsingFlags aFlags); bool ParseSelector(nsCSSSelectorList* aList, char16_t aPrevCombinator, - bool aIsForgiving, - bool aDisallowCombinators); + SelectorParsingFlags aFlags); enum { eParseDeclaration_InBraces = 1 << 0, @@ -2330,7 +2342,7 @@ CSSParserImpl::ParseSelectorString(const nsSubstring& aSelectorString, css::ErrorReporter reporter(scanner, mSheet, mChildLoader, aURI); InitScanner(scanner, reporter, aURI, aURI, nullptr); - bool success = ParseSelectorList(*aSelectorList, char16_t(0), false, false); + bool success = ParseSelectorList(*aSelectorList, char16_t(0)); // We deliberately do not call OUTPUT_ERROR here, because all our // callers map a failure return to a JS exception, and if that JS @@ -5453,7 +5465,7 @@ CSSParserImpl::ParseRuleSet(RuleAppendFunc aAppendFunc, void* aData, nsCSSSelectorList* slist = nullptr; uint32_t linenum, colnum; if (!GetNextTokenLocation(true, &linenum, &colnum) || - !ParseSelectorList(slist, char16_t('{'), false, false)) { + !ParseSelectorList(slist, char16_t('{'))) { REPORT_UNEXPECTED(PEBadSelectorRSIgnored); OUTPUT_ERROR(); SkipRuleSet(aInsideBraces); @@ -5490,12 +5502,11 @@ CSSParserImpl::ParseRuleSet(RuleAppendFunc aAppendFunc, void* aData, bool CSSParserImpl::ParseSelectorList(nsCSSSelectorList*& aListHead, char16_t aStopChar, - bool aIsForgiving, - bool aDisallowCombinators) + SelectorParsingFlags aFlags) { nsCSSSelectorList* list = nullptr; - if (! ParseSelectorGroup(list, aIsForgiving, aDisallowCombinators)) { - if (aIsForgiving) { + if (! ParseSelectorGroup(list, aFlags)) { + if (aFlags & SelectorParsingFlags::eIsForgiving) { // Initialize to an empty list if the first selector group was invalid // and we're a forgiving selector list. list = new nsCSSSelectorList(); @@ -5525,16 +5536,17 @@ CSSParserImpl::ParseSelectorList(nsCSSSelectorList*& aListHead, if (',' == tk->mSymbol) { nsCSSSelectorList* newList = nullptr; // Another selector group must follow - if (! ParseSelectorGroup(newList, aIsForgiving, aDisallowCombinators)) { + if (! ParseSelectorGroup(newList, aFlags)) { // Ignore invalid selectors if we're a forgiving selector list. - if (aIsForgiving) { + if (aFlags & SelectorParsingFlags::eIsForgiving) { continue; } break; } // Replace the list head if: it's empty and we're a forgiving selector // list. Otherwise, add the new list to the end of the selector list. - if (aIsForgiving && !aListHead->mSelectors) { + if ((aFlags & SelectorParsingFlags::eIsForgiving) && + !aListHead->mSelectors) { MOZ_ASSERT(newList->mSelectors, "replacing empty list head with an empty selector list?"); aListHead = newList; @@ -5549,7 +5561,7 @@ CSSParserImpl::ParseSelectorList(nsCSSSelectorList*& aListHead, } } - if (!aIsForgiving) { + if (!(aFlags & SelectorParsingFlags::eIsForgiving)) { REPORT_UNEXPECTED_TOKEN(PESelectorListExtra); UngetToken(); break; @@ -5573,13 +5585,14 @@ static bool IsUniversalSelector(const nsCSSSelector& aSelector) } bool -CSSParserImpl::ParseSelectorGroup(nsCSSSelectorList*& aList, bool aIsForgiving, bool aDisallowCombinators) +CSSParserImpl::ParseSelectorGroup(nsCSSSelectorList*& aList, + SelectorParsingFlags aFlags) { char16_t combinator = 0; nsAutoPtr<nsCSSSelectorList> list(new nsCSSSelectorList()); for (;;) { - if (!ParseSelector(list, combinator, aIsForgiving, aDisallowCombinators)) { + if (!ParseSelector(list, combinator, aFlags)) { return false; } @@ -5615,7 +5628,7 @@ CSSParserImpl::ParseSelectorGroup(nsCSSSelectorList*& aList, bool aIsForgiving, return false; } - if (aIsForgiving && aDisallowCombinators) { + if (aFlags & SelectorParsingFlags::eDisallowCombinators) { return false; } } @@ -5674,9 +5687,9 @@ CSSParserImpl::ParseClassSelector(int32_t& aDataMask, // namespace|type or namespace|* or *|* or * // CSSParserImpl::nsSelectorParsingStatus -CSSParserImpl::ParseTypeOrUniversalSelector(int32_t& aDataMask, - nsCSSSelector& aSelector, - bool aIsNegated) +CSSParserImpl::ParseTypeOrUniversalSelector(int32_t& aDataMask, + nsCSSSelector& aSelector, + SelectorParsingFlags aFlags) { nsAutoString buffer; if (mToken.IsSymbol('*')) { // universal element selector, or universal namespace @@ -5780,10 +5793,12 @@ CSSParserImpl::ParseTypeOrUniversalSelector(int32_t& aDataMask, } } else { - SetDefaultNamespaceOnSelector(aSelector); + if (!(aFlags & SelectorParsingFlags::eInheritNamespace)) { + SetDefaultNamespaceOnSelector(aSelector); + } } - if (aIsNegated) { + if (aFlags & SelectorParsingFlags::eIsNegated) { // restore last token read in case of a negated type selector UngetToken(); } @@ -6035,17 +6050,17 @@ CSSParserImpl::ParseAttributeSelector(int32_t& aDataMask, // Parse pseudo-classes and pseudo-elements // CSSParserImpl::nsSelectorParsingStatus -CSSParserImpl::ParsePseudoSelector(int32_t& aDataMask, - nsCSSSelector& aSelector, - bool aIsNegated, - nsIAtom** aPseudoElement, - nsAtomList** aPseudoElementArgs, - CSSPseudoElementType* aPseudoElementType, - bool aDisallowCombinators) -{ - NS_ASSERTION(aIsNegated || (aPseudoElement && aPseudoElementArgs), +CSSParserImpl::ParsePseudoSelector(int32_t& aDataMask, + nsCSSSelector& aSelector, + SelectorParsingFlags aFlags, + nsIAtom** aPseudoElement, + nsAtomList** aPseudoElementArgs, + CSSPseudoElementType* aPseudoElementType) +{ + bool isNegated = !!(aFlags & SelectorParsingFlags::eIsNegated); + NS_ASSERTION(isNegated || (aPseudoElement && aPseudoElementArgs), "expected location to store pseudo element"); - NS_ASSERTION(!aIsNegated || (!aPseudoElement && !aPseudoElementArgs), + NS_ASSERTION(!isNegated || (!aPseudoElement && !aPseudoElementArgs), "negated selectors shouldn't have a place to store " "pseudo elements"); if (! GetToken(false)) { // premature eof @@ -6144,7 +6159,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 +6196,31 @@ 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)) { + // Only the combinators restriction should be passed down the chain. + SelectorParsingFlags flags = + (aFlags & SelectorParsingFlags::eDisallowCombinators) ? + SelectorParsingFlags::eDisallowCombinators : + SelectorParsingFlags::eNone; + if (sLegacyNegationPseudoClassEnabled && + CSSPseudoClassType::negation == pseudoClassType) { + // :not() can't be itself negated + if (isNegated) { + REPORT_UNEXPECTED_TOKEN(PEPseudoSelDoubleNot); + UngetToken(); + return eSelectorParsingStatus_Error; + } + // CSS 3 Negation pseudo-class takes one simple selector as argument + parsingStatus = + ParseNegatedSimpleSelector(aDataMask, aSelector, flags); + if (eSelectorParsingStatus_Continue != parsingStatus) { + return parsingStatus; + } + } + else if (nsCSSPseudoClasses::HasStringArg(pseudoClassType)) { parsingStatus = ParsePseudoClassWithIdentArg(aSelector, pseudoClassType); } @@ -6213,7 +6233,7 @@ CSSParserImpl::ParsePseudoSelector(int32_t& aDataMask, "unexpected pseudo with function token"); parsingStatus = ParsePseudoClassWithSelectorListArg(aSelector, pseudoClassType, - aDisallowCombinators); + flags); } if (eSelectorParsingStatus_Continue != parsingStatus) { if (eSelectorParsingStatus_Error == parsingStatus) { @@ -6229,11 +6249,18 @@ CSSParserImpl::ParsePseudoSelector(int32_t& aDataMask, else if (isPseudoElement || isAnonBox) { // Pseudo-element. Make some more sanity checks. - if (aIsNegated) { // pseudo-elements can't be negated + // Pseudo-elements can't be negated. + if (isNegated) { REPORT_UNEXPECTED_TOKEN(PEPseudoSelPEInNot); UngetToken(); return eSelectorParsingStatus_Error; } + // Pseudo-elements might not be allowed from appearing + // (e.g. as an argument to the functional part of a pseudo-class). + if (aFlags & SelectorParsingFlags::eDisallowPseudoElements) { + UngetToken(); + return eSelectorParsingStatus_Error; + } // CSS2 pseudo-elements and -moz-tree-* pseudo-elements are allowed // to have a single ':' on them. Others (CSS3+ pseudo-elements and // various -moz-* pseudo-elements) must have |parsingPseudoElement| @@ -6304,9 +6331,12 @@ CSSParserImpl::ParsePseudoSelector(int32_t& aDataMask, // Parse the argument of a negation pseudo-class :not() // CSSParserImpl::nsSelectorParsingStatus -CSSParserImpl::ParseNegatedSimpleSelector(int32_t& aDataMask, - nsCSSSelector& aSelector) +CSSParserImpl::ParseNegatedSimpleSelector(int32_t& aDataMask, + nsCSSSelector& aSelector, + SelectorParsingFlags aFlags) { + aFlags |= SelectorParsingFlags::eIsNegated; + if (! GetToken(true)) { // premature eof REPORT_UNEXPECTED_EOF(PENegationEOF); return eSelectorParsingStatus_Error; @@ -6339,9 +6369,8 @@ CSSParserImpl::ParseNegatedSimpleSelector(int32_t& aDataMask, parsingStatus = ParseClassSelector(aDataMask, *newSel); } else if (mToken.IsSymbol(':')) { // :pseudo - parsingStatus = ParsePseudoSelector(aDataMask, *newSel, true, - nullptr, nullptr, nullptr, - false); + parsingStatus = ParsePseudoSelector(aDataMask, *newSel, aFlags, + nullptr, nullptr, nullptr); } else if (mToken.IsSymbol('[')) { // [attribute parsingStatus = ParseAttributeSelector(aDataMask, *newSel); @@ -6352,7 +6381,7 @@ CSSParserImpl::ParseNegatedSimpleSelector(int32_t& aDataMask, } else { // then it should be a type element or universal selector - parsingStatus = ParseTypeOrUniversalSelector(aDataMask, *newSel, true); + parsingStatus = ParseTypeOrUniversalSelector(aDataMask, *newSel, aFlags); } if (eSelectorParsingStatus_Error == parsingStatus) { REPORT_UNEXPECTED_TOKEN(PENegationBadInner); @@ -6578,28 +6607,28 @@ 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, CSSPseudoClassType aType, - bool aDisallowCombinators) + SelectorParsingFlags aFlags) { - bool isForgiving = - nsCSSPseudoClasses::HasForgivingSelectorListArg(aType); bool isSingleSelector = nsCSSPseudoClasses::HasSingleSelectorArg(aType); - if (isSingleSelector && !aDisallowCombinators) { - aDisallowCombinators = true; + if (nsCSSPseudoClasses::HasForgivingSelectorListArg(aType)) { + aFlags |= SelectorParsingFlags::eIsForgiving; + } else if (isSingleSelector || aType == CSSPseudoClassType::mozAny) { + aFlags |= SelectorParsingFlags::eDisallowCombinators; + } else if (aType == CSSPseudoClassType::negation) { + aFlags |= SelectorParsingFlags::eInheritNamespace; } + aFlags |= SelectorParsingFlags::eDisallowPseudoElements; nsAutoPtr<nsCSSSelectorList> slist; if (! ParseSelectorList(*getter_Transfers(slist), char16_t(')'), - isForgiving, - aDisallowCombinators)) { + aFlags)) { return eSelectorParsingStatus_Error; // our caller calls SkipUntil(')') } @@ -6607,23 +6636,32 @@ 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; - } - // 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(')') + // Special handling for the :not() pseudo-class. + if (aType == CSSPseudoClassType::negation) { + nsCSSSelector* negations = &aSelector; + while (negations->mNegations) { + negations = negations->mNegations; + } + // XXX: Use a special internal-only pseudo-class to handle selector lists + // if we have: (a) a complex selector, (b) nested negation pseudo-class, + // or (c) more than one selector argument in the list. + if (slist->mNext || + slist->mSelectors->mNext || + slist->mSelectors->mNegations) { + nsCSSSelector* newSel = new nsCSSSelector(); + newSel->AddPseudoClass(CSSPseudoClassType::mozAnyPrivate, + slist.forget()); + negations->mNegations = newSel; + } else { + // Otherwise, steal the first selector and add it directly to the + // end of aSelector.mNegations. + negations->mNegations = (slist.forget())->mSelectors; } + } else { + // 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)) { REPORT_UNEXPECTED_TOKEN(PEPseudoClassNoClose); @@ -6641,8 +6679,7 @@ CSSParserImpl::ParsePseudoClassWithSelectorListArg(nsCSSSelector& aSelector, bool CSSParserImpl::ParseSelector(nsCSSSelectorList* aList, char16_t aPrevCombinator, - bool aIsForgiving, - bool aDisallowCombinators) + SelectorParsingFlags aFlags) { if (! GetToken(true)) { REPORT_UNEXPECTED_EOF(PESelectorEOF); @@ -6656,15 +6693,14 @@ CSSParserImpl::ParseSelector(nsCSSSelectorList* aList, int32_t dataMask = 0; nsSelectorParsingStatus parsingStatus = - ParseTypeOrUniversalSelector(dataMask, *selector, false); + ParseTypeOrUniversalSelector(dataMask, *selector, aFlags); while (parsingStatus == eSelectorParsingStatus_Continue) { if (mToken.IsSymbol(':')) { // :pseudo - parsingStatus = ParsePseudoSelector(dataMask, *selector, false, + parsingStatus = ParsePseudoSelector(dataMask, *selector, aFlags, getter_AddRefs(pseudoElement), getter_Transfers(pseudoElementArgs), - &pseudoElementType, - aDisallowCombinators); + &pseudoElementType); if (pseudoElement && pseudoElementType != CSSPseudoElementType::AnonBox) { // Pseudo-elements other than anonymous boxes are represented with @@ -6720,7 +6756,7 @@ CSSParserImpl::ParseSelector(nsCSSSelectorList* aList, // XXX(franklindm): We're effectively ignoring stray combinators // and empty selector groups here for forgiving selector lists. // It doesn't seem right, but this is how tainted browsers do it. - if (aIsForgiving) { + if (aFlags & SelectorParsingFlags::eIsForgiving) { return false; } if (selector->mNext) { @@ -17899,6 +17935,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, |