1
0
mirror of https://github.com/roytam1/UXP.git synced 2026-05-26 13:58:49 +00:00

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
This commit is contained in:
FranklinDM
2023-03-18 09:36:25 +08:00
committed by roytam1
parent ab63b7b946
commit 77ad970db6
8 changed files with 81 additions and 3 deletions
+5
View File
@@ -915,6 +915,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
+32 -1
View File
@@ -6121,6 +6121,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;
}
#ifdef MOZ_XUL
isTreePseudo = (pseudoElementType == CSSPseudoElementType::XULTree);
// If a tree pseudo-element is using the function syntax, it will
@@ -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;
}
+3
View File
@@ -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, "")
+10 -2
View File
@@ -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;
}
+1
View File
@@ -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);
+4
View File
@@ -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",
+23
View File
@@ -1963,6 +1963,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();
+3
View File
@@ -2557,6 +2557,9 @@ pref("layout.css.legacy-negation-pseudo.enabled", false);
// Is support for the :is() and :where() selectors enabled?
pref("layout.css.is-where-pseudo.enabled", true);
// Is support for the ::slotted() selector enabled?
pref("layout.css.slotted-pseudo.enabled", true);
// Is support for the :scope selector enabled?
pref("layout.css.scope-pseudo.enabled", true);