summaryrefslogtreecommitdiff
path: root/layout
diff options
context:
space:
mode:
authorFranklinDM <mrmineshafter17@gmail.com>2023-03-10 00:20:44 +0800
committerFranklinDM <mrmineshafter17@gmail.com>2023-03-10 19:14:24 +0800
commitde225cca0d256117e2a0da990fd8c50e79ac6a1c (patch)
tree537100f04f2d0c7060b39924ecb69b031da6a88f /layout
parent476dec2351c75e3bf7355fbe111c604f32e5b558 (diff)
downloaduxp-de225cca0d256117e2a0da990fd8c50e79ac6a1c.tar.gz
Issue #2137 - Part 1: Modify :not() selector to accept a complex selector list
Diffstat (limited to 'layout')
-rw-r--r--layout/style/StyleRule.cpp12
-rw-r--r--layout/style/nsCSSParser.cpp78
-rw-r--r--layout/style/nsCSSPseudoClassList.h5
-rw-r--r--layout/style/nsCSSPseudoClasses.cpp8
-rw-r--r--layout/style/nsCSSPseudoClasses.h1
-rw-r--r--layout/style/nsCSSRuleProcessor.cpp11
6 files changed, 80 insertions, 35 deletions
diff --git a/layout/style/StyleRule.cpp b/layout/style/StyleRule.cpp
index 815c6f96cc..9c6f73ffe1 100644
--- a/layout/style/StyleRule.cpp
+++ b/layout/style/StyleRule.cpp
@@ -908,9 +908,13 @@ nsCSSSelector::AppendToStringWithoutCombinatorsOrNegations
// has a ":" that can't be escaped and (b) all pseudo-classes at
// this point are known, and therefore we know they don't need
// escaping.
- aString.Append(temp);
+ if (!nsCSSPseudoClasses::IsHiddenFromSerialization(list->mType)) {
+ aString.Append(temp);
+ }
if (list->u.mMemory) {
- aString.Append(char16_t('('));
+ if (!nsCSSPseudoClasses::IsHiddenFromSerialization(list->mType)) {
+ aString.Append(char16_t('('));
+ }
if (nsCSSPseudoClasses::HasStringArg(list->mType)) {
nsStyleUtil::AppendEscapedCSSIdent(
nsDependentString(list->u.mString), aString);
@@ -939,7 +943,9 @@ nsCSSSelector::AppendToStringWithoutCombinatorsOrNegations
list->u.mSelectorList->ToString(tmp, aSheet);
aString.Append(tmp);
}
- aString.Append(char16_t(')'));
+ if (!nsCSSPseudoClasses::IsHiddenFromSerialization(list->mType)) {
+ aString.Append(char16_t(')'));
+ }
}
}
}
diff --git a/layout/style/nsCSSParser.cpp b/layout/style/nsCSSParser.cpp
index f9f198417f..f60b1c5287 100644
--- a/layout/style/nsCSSParser.cpp
+++ b/layout/style/nsCSSParser.cpp
@@ -67,6 +67,7 @@ static bool sWebkitPrefixedAliasesEnabled;
static bool sWebkitDevicePixelRatioEnabled;
static bool sMozGradientsEnabled;
static bool sControlCharVisibility;
+static bool sLegacyNegationPseudoClassEnabled;
const uint32_t
nsCSSProps::kParserVariantTable[eCSSProperty_COUNT_no_shorthands] = {
@@ -6144,7 +6145,6 @@ CSSParserImpl::ParsePseudoSelector(int32_t& aDataMask,
// is that of a function pseudo it better be a function token
if ((eCSSToken_Function == mToken.mType) !=
(isTree ||
- CSSPseudoClassType::negation == pseudoClassType ||
nsCSSPseudoClasses::HasStringArg(pseudoClassType) ||
nsCSSPseudoClasses::HasNthPairArg(pseudoClassType) ||
nsCSSPseudoClasses::HasSelectorListArg(pseudoClassType)) &&
@@ -6182,25 +6182,26 @@ CSSParserImpl::ParsePseudoSelector(int32_t& aDataMask,
}
}
- if (!parsingPseudoElement &&
- CSSPseudoClassType::negation == pseudoClassType) {
- if (aIsNegated) { // :not() can't be itself negated
- REPORT_UNEXPECTED_TOKEN(PEPseudoSelDoubleNot);
- UngetToken();
- return eSelectorParsingStatus_Error;
- }
- // CSS 3 Negation pseudo-class takes one simple selector as argument
- nsSelectorParsingStatus parsingStatus =
- ParseNegatedSimpleSelector(aDataMask, aSelector);
- if (eSelectorParsingStatus_Continue != parsingStatus) {
- return parsingStatus;
- }
- }
- else if (!parsingPseudoElement && isPseudoClass) {
+ if (!parsingPseudoElement && isPseudoClass) {
aDataMask |= SEL_MASK_PCLASS;
if (eCSSToken_Function == mToken.mType) {
nsSelectorParsingStatus parsingStatus;
- if (nsCSSPseudoClasses::HasStringArg(pseudoClassType)) {
+ if (sLegacyNegationPseudoClassEnabled &&
+ CSSPseudoClassType::negation == pseudoClassType) {
+ // :not() can't be itself negated
+ if (aIsNegated) {
+ REPORT_UNEXPECTED_TOKEN(PEPseudoSelDoubleNot);
+ UngetToken();
+ return eSelectorParsingStatus_Error;
+ }
+ // CSS 3 Negation pseudo-class takes one simple selector as argument
+ parsingStatus =
+ ParseNegatedSimpleSelector(aDataMask, aSelector);
+ if (eSelectorParsingStatus_Continue != parsingStatus) {
+ return parsingStatus;
+ }
+ }
+ else if (nsCSSPseudoClasses::HasStringArg(pseudoClassType)) {
parsingStatus =
ParsePseudoClassWithIdentArg(aSelector, pseudoClassType);
}
@@ -6578,8 +6579,6 @@ CSSParserImpl::ParsePseudoClassWithNthPairArg(nsCSSSelector& aSelector,
//
// Parse the argument of a pseudo-class that has a selector list argument.
-// Such selector lists cannot contain combinators, but can contain
-// anything that goes between a pair of combinators.
//
CSSParserImpl::nsSelectorParsingStatus
CSSParserImpl::ParsePseudoClassWithSelectorListArg(nsCSSSelector& aSelector,
@@ -6607,22 +6606,35 @@ CSSParserImpl::ParsePseudoClassWithSelectorListArg(nsCSSSelector& aSelector,
return eSelectorParsingStatus_Error; // our caller calls SkipUntil(')')
}
- for (nsCSSSelectorList *l = slist; l; l = l->mNext) {
- nsCSSSelector *s = l->mSelectors;
- if (s == nullptr) {
- MOZ_ASSERT(isForgiving,
- "unexpected empty selector in unforgiving selector list");
- break;
+ // Special handling for the :not() pseudo-class.
+ if (aType == CSSPseudoClassType::negation) {
+ nsCSSSelector* negations = &aSelector;
+ while (negations->mNegations) {
+ negations = negations->mNegations;
}
- // Check that none of the selectors in the list have combinators or
- // pseudo-elements.
- if ((!isForgiving && s->mNext) || s->IsPseudoElement()) {
- return eSelectorParsingStatus_Error; // our caller calls SkipUntil(')')
+ // XXX: Use a special internal-only pseudo-class to handle selector lists.
+ // TODO: This should only happen if we don't have a simple selector.
+ nsCSSSelector* newSel = new nsCSSSelector();
+ newSel->AddPseudoClass(CSSPseudoClassType::mozAnyPrivate, slist.forget());
+ negations->mNegations = newSel;
+ } else {
+ for (nsCSSSelectorList *l = slist; l; l = l->mNext) {
+ nsCSSSelector *s = l->mSelectors;
+ if (s == nullptr) {
+ MOZ_ASSERT(isForgiving,
+ "unexpected empty selector in unforgiving selector list");
+ break;
+ }
+ // Check that none of the selectors in the list have combinators or
+ // pseudo-elements.
+ if ((!isForgiving && s->mNext) || s->IsPseudoElement()) {
+ return eSelectorParsingStatus_Error; // our caller calls SkipUntil(')')
+ }
}
- }
- // Add the pseudo with the selector list parameter
- aSelector.AddPseudoClass(aType, slist.forget());
+ // Add the pseudo with the selector list parameter
+ aSelector.AddPseudoClass(aType, slist.forget());
+ }
// close the parenthesis
if (!ExpectSymbol(')', true)) {
@@ -17899,6 +17911,8 @@ nsCSSParser::Startup()
"layout.css.prefixes.gradients");
Preferences::AddBoolVarCache(&sControlCharVisibility,
"layout.css.control-characters.visible");
+ Preferences::AddBoolVarCache(&sLegacyNegationPseudoClassEnabled,
+ "layout.css.legacy-negation-pseudo.enabled");
}
nsCSSParser::nsCSSParser(mozilla::css::Loader* aLoader,
diff --git a/layout/style/nsCSSPseudoClassList.h b/layout/style/nsCSSPseudoClassList.h
index 740ebcc422..cbe3bd8f92 100644
--- a/layout/style/nsCSSPseudoClassList.h
+++ b/layout/style/nsCSSPseudoClassList.h
@@ -133,6 +133,11 @@ CSS_PSEUDO_CLASS(mozBrowserFrame, ":-moz-browser-frame",
// matching operation.
CSS_PSEUDO_CLASS(scope, ":scope", 0, "layout.css.scope-pseudo.enabled")
+// Matches selectors inside the selector list argument. Unlike :is(),
+// this is unforgiving and hidden from serialization.
+CSS_PSEUDO_CLASS(mozAnyPrivate, ":-moz-any-private",
+ CSS_PSEUDO_CLASS_ENABLED_IN_UA_SHEETS_AND_CHROME, "")
+
// :not needs to come at the end of the non-bit pseudo-class list, since
// it doesn't actually get directly matched on in SelectorMatches.
CSS_PSEUDO_CLASS(negation, ":not", 0, "")
diff --git a/layout/style/nsCSSPseudoClasses.cpp b/layout/style/nsCSSPseudoClasses.cpp
index 23517ef52c..0fc460a514 100644
--- a/layout/style/nsCSSPseudoClasses.cpp
+++ b/layout/style/nsCSSPseudoClasses.cpp
@@ -122,7 +122,9 @@ bool
nsCSSPseudoClasses::HasSelectorListArg(Type aType)
{
return HasForgivingSelectorListArg(aType) ||
+ aType == Type::negation ||
aType == Type::mozAny ||
+ aType == Type::mozAnyPrivate ||
aType == Type::host ||
aType == Type::hostContext;
}
@@ -133,6 +135,12 @@ nsCSSPseudoClasses::HasOptionalSelectorListArg(Type aType)
return aType == Type::host;
}
+bool
+nsCSSPseudoClasses::IsHiddenFromSerialization(Type aType)
+{
+ return aType == Type::mozAnyPrivate;
+}
+
void
nsCSSPseudoClasses::PseudoTypeToString(Type aType, nsAString& aString)
{
diff --git a/layout/style/nsCSSPseudoClasses.h b/layout/style/nsCSSPseudoClasses.h
index 99c05b019f..ff2da74ff0 100644
--- a/layout/style/nsCSSPseudoClasses.h
+++ b/layout/style/nsCSSPseudoClasses.h
@@ -62,6 +62,7 @@ public:
static bool HasForgivingSelectorListArg(Type aType);
static bool HasSelectorListArg(Type aType);
static bool HasOptionalSelectorListArg(Type aType);
+ static bool IsHiddenFromSerialization(Type aType);
static bool IsUserActionPseudoClass(Type aType);
// Should only be used on types other than Count and NotPseudoClass
diff --git a/layout/style/nsCSSRuleProcessor.cpp b/layout/style/nsCSSRuleProcessor.cpp
index f637a063a6..dc2157084b 100644
--- a/layout/style/nsCSSRuleProcessor.cpp
+++ b/layout/style/nsCSSRuleProcessor.cpp
@@ -1931,6 +1931,17 @@ static bool SelectorMatches(Element* aElement,
}
break;
+ case CSSPseudoClassType::mozAnyPrivate:
+ {
+ if (!SelectorListMatches(aElement,
+ pseudoClass,
+ aNodeMatchContext,
+ aTreeMatchContext)) {
+ return false;
+ }
+ }
+ break;
+
case CSSPseudoClassType::host:
{
// In order to match :host, the element must be a shadow root host,