summaryrefslogtreecommitdiff
path: root/layout/style
diff options
context:
space:
mode:
Diffstat (limited to 'layout/style')
-rw-r--r--layout/style/StyleRule.cpp5
-rw-r--r--layout/style/nsCSSParser.cpp33
-rw-r--r--layout/style/nsCSSPseudoClassList.h3
-rw-r--r--layout/style/nsCSSPseudoClasses.cpp12
-rw-r--r--layout/style/nsCSSPseudoClasses.h1
-rw-r--r--layout/style/nsCSSPseudoElementList.h4
-rw-r--r--layout/style/nsCSSRuleProcessor.cpp23
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();