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:
@@ -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
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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, "")
|
||||
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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",
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
Reference in New Issue
Block a user