diff options
author | FranklinDM <mrmineshafter17@gmail.com> | 2023-03-18 09:36:25 +0800 |
---|---|---|
committer | Moonchild <moonchild@palemoon.org> | 2023-03-23 12:17:59 +0100 |
commit | 5fc444a0b6e47fb3ab1168ad0cb49a95a38c9dfb (patch) | |
tree | 43eac09c4e676acf3e783fa423c2e15405cadba3 /layout/style | |
parent | d2be38e92b72b0cb53eb5c42acbde83a46e4a6b4 (diff) | |
download | uxp-5fc444a0b6e47fb3ab1168ad0cb49a95a38c9dfb.tar.gz |
Issue #1592 - Part 2: Parse ::slotted() pseudo-element as if it were a pseudo-class
- Block slot elements from being matched by ::slotted
- Ensure ::slotted() is serialized as a pseudo-element
- Add pref to control whether the pseudo-class is enabled
Diffstat (limited to 'layout/style')
-rw-r--r-- | layout/style/StyleRule.cpp | 5 | ||||
-rw-r--r-- | layout/style/nsCSSParser.cpp | 33 | ||||
-rw-r--r-- | layout/style/nsCSSPseudoClassList.h | 3 | ||||
-rw-r--r-- | layout/style/nsCSSPseudoClasses.cpp | 12 | ||||
-rw-r--r-- | layout/style/nsCSSPseudoClasses.h | 1 | ||||
-rw-r--r-- | layout/style/nsCSSPseudoElementList.h | 4 | ||||
-rw-r--r-- | layout/style/nsCSSRuleProcessor.cpp | 23 |
7 files changed, 78 insertions, 3 deletions
diff --git a/layout/style/StyleRule.cpp b/layout/style/StyleRule.cpp index 101bb0f4d7..1b8c31c4ad 100644 --- a/layout/style/StyleRule.cpp +++ b/layout/style/StyleRule.cpp @@ -903,6 +903,11 @@ nsCSSSelector::AppendToStringWithoutCombinatorsOrNegations // Append each pseudo-class in the linked list for (nsPseudoClassList* list = mPseudoClassList; list; list = list->mNext) { + // Serialize pseudo-elements that were treated as if they were a + // pseudo-class to the two colon syntax. + if (nsCSSPseudoClasses::IsHybridPseudoElement(list->mType)) { + aString.Append(char16_t(':')); + } nsCSSPseudoClasses::PseudoTypeToString(list->mType, temp); // This should not be escaped since (a) the pseudo-class string // has a ":" that can't be escaped and (b) all pseudo-classes at diff --git a/layout/style/nsCSSParser.cpp b/layout/style/nsCSSParser.cpp index 47ceab3f41..42c1733b77 100644 --- a/layout/style/nsCSSParser.cpp +++ b/layout/style/nsCSSParser.cpp @@ -6125,6 +6125,21 @@ CSSParserImpl::ParsePseudoSelector(int32_t& aDataMask, } } + // We handle the ::slotted() pseudo-element as if it it were a pseudo-class. + // This is because the spec allows it to be followed by ::after/::before, + // but our platform does not have a mechanism to handle multiple + // pseudo-elements. It would be tedious to refactor pseudo-element + // handling to accommodate for an edge case like this. + bool isSlotPseudo = false; + if (parsingPseudoElement && + pseudoElementType == CSSPseudoElementType::slotted) { + parsingPseudoElement = false; + pseudoElementType = CSSPseudoElementType::NotPseudo; + pseudoClassType = CSSPseudoClassType::slotted; + isSlotPseudo = true; + aFlags |= SelectorParsingFlags::eDisallowCombinators; + } + isTreePseudo = (pseudoElementType == CSSPseudoElementType::XULTree); // If a tree pseudo-element is using the function syntax, it will // get isTree set here and will pass the check below that only @@ -6198,6 +6213,8 @@ CSSParserImpl::ParsePseudoSelector(int32_t& aDataMask, } } + bool disallowPseudoElements = + !!(aFlags & SelectorParsingFlags::eDisallowPseudoElements); if (!parsingPseudoElement && isPseudoClass) { aDataMask |= SEL_MASK_PCLASS; if (eCSSToken_Function == mToken.mType) { @@ -6222,6 +6239,13 @@ CSSParserImpl::ParsePseudoSelector(int32_t& aDataMask, return parsingStatus; } } + else if (CSSPseudoClassType::slotted == pseudoClassType && + !isSlotPseudo) { + // Reject the :slotted() pseudo-class form. + REPORT_UNEXPECTED_TOKEN(PEPseudoSelNewStyleOnly); + UngetToken(); + return eSelectorParsingStatus_Error; + } else if (nsCSSPseudoClasses::HasStringArg(pseudoClassType)) { parsingStatus = ParsePseudoClassWithIdentArg(aSelector, pseudoClassType); @@ -6233,6 +6257,13 @@ CSSParserImpl::ParsePseudoSelector(int32_t& aDataMask, else { MOZ_ASSERT(nsCSSPseudoClasses::HasSelectorListArg(pseudoClassType), "unexpected pseudo with function token"); + // Ensure that the ::slotted() pseudo-element is rejected if + // pseudo-elements are disallowed. + if (CSSPseudoClassType::slotted == pseudoClassType && + disallowPseudoElements) { + UngetToken(); + return eSelectorParsingStatus_Error; + } parsingStatus = ParsePseudoClassWithSelectorListArg(aSelector, pseudoClassType, flags); @@ -6259,7 +6290,7 @@ CSSParserImpl::ParsePseudoSelector(int32_t& aDataMask, } // 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) { + if (disallowPseudoElements) { UngetToken(); return eSelectorParsingStatus_Error; } diff --git a/layout/style/nsCSSPseudoClassList.h b/layout/style/nsCSSPseudoClassList.h index cbe3bd8f92..6ec09714cc 100644 --- a/layout/style/nsCSSPseudoClassList.h +++ b/layout/style/nsCSSPseudoClassList.h @@ -93,6 +93,9 @@ CSS_PSEUDO_CLASS(nthLastChild, ":nth-last-child", 0, "") CSS_PSEUDO_CLASS(nthOfType, ":nth-of-type", 0, "") CSS_PSEUDO_CLASS(nthLastOfType, ":nth-last-of-type", 0, "") +// Match slot nodes. +CSS_PSEUDO_CLASS(slotted, ":slotted", 0, "layout.css.slotted-pseudo.enabled") + // Match nodes that are HTML but not XHTML CSS_PSEUDO_CLASS(mozIsHTML, ":-moz-is-html", 0, "") diff --git a/layout/style/nsCSSPseudoClasses.cpp b/layout/style/nsCSSPseudoClasses.cpp index 0fc460a514..3c9bbf9bd3 100644 --- a/layout/style/nsCSSPseudoClasses.cpp +++ b/layout/style/nsCSSPseudoClasses.cpp @@ -106,7 +106,8 @@ bool nsCSSPseudoClasses::HasSingleSelectorArg(Type aType) { return aType == Type::host || - aType == Type::hostContext; + aType == Type::hostContext || + aType == Type::slotted; } bool @@ -126,7 +127,8 @@ nsCSSPseudoClasses::HasSelectorListArg(Type aType) aType == Type::mozAny || aType == Type::mozAnyPrivate || aType == Type::host || - aType == Type::hostContext; + aType == Type::hostContext || + aType == Type::slotted; } bool @@ -169,3 +171,9 @@ nsCSSPseudoClasses::IsUserActionPseudoClass(Type aType) aType == Type::active || aType == Type::focus; } + +/* static */ bool +nsCSSPseudoClasses::IsHybridPseudoElement(Type aType) +{ + return aType == Type::slotted; +} diff --git a/layout/style/nsCSSPseudoClasses.h b/layout/style/nsCSSPseudoClasses.h index ff2da74ff0..e4738f64ba 100644 --- a/layout/style/nsCSSPseudoClasses.h +++ b/layout/style/nsCSSPseudoClasses.h @@ -64,6 +64,7 @@ public: static bool HasOptionalSelectorListArg(Type aType); static bool IsHiddenFromSerialization(Type aType); static bool IsUserActionPseudoClass(Type aType); + static bool IsHybridPseudoElement(Type aType); // Should only be used on types other than Count and NotPseudoClass static void PseudoTypeToString(Type aType, nsAString& aString); diff --git a/layout/style/nsCSSPseudoElementList.h b/layout/style/nsCSSPseudoElementList.h index b8393d3952..93ce44e788 100644 --- a/layout/style/nsCSSPseudoElementList.h +++ b/layout/style/nsCSSPseudoElementList.h @@ -28,6 +28,10 @@ CSS_PSEUDO_ELEMENT(after, ":after", CSS_PSEUDO_ELEMENT_IS_CSS2) CSS_PSEUDO_ELEMENT(before, ":before", CSS_PSEUDO_ELEMENT_IS_CSS2) +// XXX: ::slotted() is treated as if it were a pseudo-class, and +// is never parsed as a pseudo-element. +CSS_PSEUDO_ELEMENT(slotted, ":slotted", 0) + CSS_PSEUDO_ELEMENT(backdrop, ":backdrop", 0) CSS_PSEUDO_ELEMENT(firstLetter, ":first-letter", diff --git a/layout/style/nsCSSRuleProcessor.cpp b/layout/style/nsCSSRuleProcessor.cpp index 14ab270b86..953c84237d 100644 --- a/layout/style/nsCSSRuleProcessor.cpp +++ b/layout/style/nsCSSRuleProcessor.cpp @@ -1942,6 +1942,29 @@ static bool SelectorMatches(Element* aElement, } break; + case CSSPseudoClassType::slotted: + { + // Slot elements cannot be matched. + if (aElement->IsHTMLElement(nsGkAtoms::slot)) { + return false; + } + + // The current element must have an assigned slot. + if (!aElement->GetAssignedSlot()) { + return false; + } + + NodeMatchContext nodeContext(EventStates(), + aNodeMatchContext.mIsRelevantLink); + if (!SelectorListMatches(aElement, + pseudoClass, + nodeContext, + aTreeMatchContext)) { + return false; + } + } + break; + case CSSPseudoClassType::host: { ShadowRoot* shadow = aElement->GetShadowRoot(); |