diff options
author | FranklinDM <mrmineshafter17@gmail.com> | 2023-03-19 18:48:24 +0800 |
---|---|---|
committer | Moonchild <moonchild@palemoon.org> | 2023-03-23 12:18:01 +0100 |
commit | 7c82808510e2cc164ef1e030bbff847416424d28 (patch) | |
tree | 95dd17a9b43a32a628a8fcade37e09408258334e /layout | |
parent | c5cb2983e64aa7c2da2b3d504e1298d3a6b42522 (diff) | |
download | uxp-7c82808510e2cc164ef1e030bbff847416424d28.tar.gz |
Issue #1592 - Part 6: Allow pseudo-classes with a forgiving selector list argument to follow pseudo-elements
Pseudo-classes with a forgiving selector list argument are allowed to follow a pseudo-element, but must treat any selector that is not of the same type as invalid. It doesn't make any sense, but that's the behavior of other tainted browsers.
Diffstat (limited to 'layout')
-rw-r--r-- | layout/style/nsCSSParser.cpp | 62 |
1 files changed, 49 insertions, 13 deletions
diff --git a/layout/style/nsCSSParser.cpp b/layout/style/nsCSSParser.cpp index db29dc6441..1483eb0a11 100644 --- a/layout/style/nsCSSParser.cpp +++ b/layout/style/nsCSSParser.cpp @@ -119,7 +119,8 @@ enum class SelectorParsingFlags { eIsForgiving = 1 << 1, eDisallowCombinators = 1 << 2, eDisallowPseudoElements = 1 << 3, - eInheritNamespace = 1 << 4 + eInheritNamespace = 1 << 4, + eForceEmptyList = 1 << 5 }; MOZ_MAKE_ENUM_CLASS_BITWISE_OPERATORS(SelectorParsingFlags) @@ -6107,6 +6108,8 @@ CSSParserImpl::ParsePseudoSelector(int32_t& aDataMask, nsCSSPseudoClasses::GetPseudoType(pseudo, enabledState); bool pseudoClassIsUserAction = nsCSSPseudoClasses::IsUserActionPseudoClass(pseudoClassType); + bool pseudoClassHasForgivingSelectorListArg = + nsCSSPseudoClasses::HasForgivingSelectorListArg(pseudoClassType); if (nsCSSAnonBoxes::IsNonElement(pseudo)) { // Non-element anonymous boxes should not match any rule. @@ -6199,6 +6202,7 @@ CSSParserImpl::ParsePseudoSelector(int32_t& aDataMask, return eSelectorParsingStatus_Error; } + bool forceEmptyList = false; if (aSelector.IsPseudoElement() || aSelector.IsHybridPseudoElement()) { CSSPseudoElementType type = aSelector.IsPseudoElement() ? aSelector.PseudoType() : @@ -6216,13 +6220,20 @@ CSSParserImpl::ParsePseudoSelector(int32_t& aDataMask, return eSelectorParsingStatus_Error; } - if (isPseudoClass && - (!supportsUserAction || !pseudoClassIsUserAction)) { - // CSS 4 Selectors says that pseudo-elements can only be followed by - // a user action pseudo-class. - REPORT_UNEXPECTED_TOKEN(PEPseudoClassNotUserAction); - UngetToken(); - return eSelectorParsingStatus_Error; + if (isPseudoClass) { + if (pseudoClassHasForgivingSelectorListArg) { + // XXX: Pseudo-classes with a forgiving selector list argument are + // allowed to follow a pseudo-element, but must treat any selector + // that is not of the same type as invalid. It doesn't make any + // sense, but that's the behavior of other tainted browsers. + forceEmptyList = true; + } else if (!supportsUserAction || !pseudoClassIsUserAction) { + // CSS 4 Selectors says that pseudo-elements can only be followed by + // a user action pseudo-class. + REPORT_UNEXPECTED_TOKEN(PEPseudoClassNotUserAction); + UngetToken(); + return eSelectorParsingStatus_Error; + } } else if (isPseudoElement && (!supportsTreeAbiding || !pseudoElementIsTreeAbiding)) { REPORT_UNEXPECTED_TOKEN(PEPseudoClassNotUserAction); @@ -6235,13 +6246,30 @@ CSSParserImpl::ParsePseudoSelector(int32_t& aDataMask, !!(aFlags & SelectorParsingFlags::eDisallowPseudoElements); if (!parsingPseudoElement && isPseudoClass) { aDataMask |= SEL_MASK_PCLASS; + + // Only pseudo-classes with a forgiving selector list argument + // are allowed if we're forced to be empty. + if ((aFlags & SelectorParsingFlags::eForceEmptyList) && + !pseudoClassHasForgivingSelectorListArg) { + if (eCSSToken_Function == mToken.mType) { + SkipUntil(')'); + } + return eSelectorParsingStatus_Continue; + } + if (eCSSToken_Function == mToken.mType) { nsSelectorParsingStatus parsingStatus; - // Only the combinators restriction should be passed down the chain. - SelectorParsingFlags flags = - (aFlags & SelectorParsingFlags::eDisallowCombinators) ? - SelectorParsingFlags::eDisallowCombinators : - SelectorParsingFlags::eNone; + + // Pass only a few parsing flags down the chain. + SelectorParsingFlags flags = SelectorParsingFlags::eNone; + if (aFlags & SelectorParsingFlags::eDisallowCombinators) { + flags |= SelectorParsingFlags::eDisallowCombinators; + } + if (aFlags & SelectorParsingFlags::eForceEmptyList || + forceEmptyList) { + flags |= SelectorParsingFlags::eForceEmptyList; + } + if (sLegacyNegationPseudoClassEnabled && CSSPseudoClassType::negation == pseudoClassType) { // :not() can't be itself negated @@ -6801,6 +6829,14 @@ CSSParserImpl::ParseSelector(nsCSSSelectorList* aList, } } + // Treat every other selector as invalid. + if ((aFlags & SelectorParsingFlags::eForceEmptyList) && + (selector->mIDList || selector->mClassList || + selector->mAttrList || selector->mNegations || + !selector->mPseudoClassList)) { + return false; + } + if (parsingStatus == eSelectorParsingStatus_Error) { return false; } |