summaryrefslogtreecommitdiff
path: root/layout
diff options
context:
space:
mode:
Diffstat (limited to 'layout')
-rw-r--r--layout/style/StyleRule.cpp12
-rw-r--r--layout/style/nsCSSParser.cpp244
-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, 175 insertions, 106 deletions
diff --git a/layout/style/StyleRule.cpp b/layout/style/StyleRule.cpp
index 437806a1b8..101bb0f4d7 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..8c4f16f24d 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] = {
@@ -109,6 +110,19 @@ enum class GridTrackListFlags {
};
MOZ_MAKE_ENUM_CLASS_BITWISE_OPERATORS(GridTrackListFlags)
+/**
+ * Additional information about a selector being parsed.
+ */
+enum class SelectorParsingFlags {
+ eNone = 0,
+ eIsNegated = 1 << 0,
+ eIsForgiving = 1 << 1,
+ eDisallowCombinators = 1 << 2,
+ eDisallowPseudoElements = 1 << 3,
+ eInheritNamespace = 1 << 4
+};
+MOZ_MAKE_ENUM_CLASS_BITWISE_OPERATORS(SelectorParsingFlags)
+
namespace {
// Rule processing function
@@ -759,21 +773,21 @@ protected:
// aPseudoElement and aPseudoElementArgs are the location where
// pseudo-elements (as opposed to pseudo-classes) are stored;
// pseudo-classes are stored on aSelector. aPseudoElement and
- // aPseudoElementArgs must be non-null iff !aIsNegated.
- nsSelectorParsingStatus ParsePseudoSelector(int32_t& aDataMask,
- nsCSSSelector& aSelector,
- bool aIsNegated,
- nsIAtom** aPseudoElement,
- nsAtomList** aPseudoElementArgs,
- CSSPseudoElementType* aPseudoElementType,
- bool aDisallowCombinators);
+ // aPseudoElementArgs must be non-null iff the eIsNegated flag of
+ // aFlags is not set.
+ nsSelectorParsingStatus ParsePseudoSelector(int32_t& aDataMask,
+ nsCSSSelector& aSelector,
+ SelectorParsingFlags aFlags,
+ nsIAtom** aPseudoElement,
+ nsAtomList** aPseudoElementArgs,
+ CSSPseudoElementType* aPseudoElementType);
nsSelectorParsingStatus ParseAttributeSelector(int32_t& aDataMask,
nsCSSSelector& aSelector);
- nsSelectorParsingStatus ParseTypeOrUniversalSelector(int32_t& aDataMask,
- nsCSSSelector& aSelector,
- bool aIsNegated);
+ nsSelectorParsingStatus ParseTypeOrUniversalSelector(int32_t& aDataMask,
+ nsCSSSelector& aSelector,
+ SelectorParsingFlags aFlags);
nsSelectorParsingStatus ParsePseudoClassWithIdentArg(nsCSSSelector& aSelector,
CSSPseudoClassType aType);
@@ -783,24 +797,22 @@ protected:
nsSelectorParsingStatus ParsePseudoClassWithSelectorListArg(nsCSSSelector& aSelector,
CSSPseudoClassType aType,
- bool aDisallowCombinators);
+ SelectorParsingFlags aFlags);
- nsSelectorParsingStatus ParseNegatedSimpleSelector(int32_t& aDataMask,
- nsCSSSelector& aSelector);
+ nsSelectorParsingStatus ParseNegatedSimpleSelector(int32_t& aDataMask,
+ nsCSSSelector& aSelector,
+ SelectorParsingFlags aFlags);
// If aStopChar is non-zero, the selector list is done when we hit
// aStopChar. Otherwise, it's done when we hit EOF.
bool ParseSelectorList(nsCSSSelectorList*& aListHead,
char16_t aStopChar,
- bool aIsForgiving,
- bool aDisallowCombinators);
+ SelectorParsingFlags aFlags = SelectorParsingFlags::eNone);
bool ParseSelectorGroup(nsCSSSelectorList*& aListHead,
- bool aIsForgiving,
- bool aDisallowCombinators);
+ SelectorParsingFlags aFlags);
bool ParseSelector(nsCSSSelectorList* aList,
char16_t aPrevCombinator,
- bool aIsForgiving,
- bool aDisallowCombinators);
+ SelectorParsingFlags aFlags);
enum {
eParseDeclaration_InBraces = 1 << 0,
@@ -2330,7 +2342,7 @@ CSSParserImpl::ParseSelectorString(const nsSubstring& aSelectorString,
css::ErrorReporter reporter(scanner, mSheet, mChildLoader, aURI);
InitScanner(scanner, reporter, aURI, aURI, nullptr);
- bool success = ParseSelectorList(*aSelectorList, char16_t(0), false, false);
+ bool success = ParseSelectorList(*aSelectorList, char16_t(0));
// We deliberately do not call OUTPUT_ERROR here, because all our
// callers map a failure return to a JS exception, and if that JS
@@ -5453,7 +5465,7 @@ CSSParserImpl::ParseRuleSet(RuleAppendFunc aAppendFunc, void* aData,
nsCSSSelectorList* slist = nullptr;
uint32_t linenum, colnum;
if (!GetNextTokenLocation(true, &linenum, &colnum) ||
- !ParseSelectorList(slist, char16_t('{'), false, false)) {
+ !ParseSelectorList(slist, char16_t('{'))) {
REPORT_UNEXPECTED(PEBadSelectorRSIgnored);
OUTPUT_ERROR();
SkipRuleSet(aInsideBraces);
@@ -5490,12 +5502,11 @@ CSSParserImpl::ParseRuleSet(RuleAppendFunc aAppendFunc, void* aData,
bool
CSSParserImpl::ParseSelectorList(nsCSSSelectorList*& aListHead,
char16_t aStopChar,
- bool aIsForgiving,
- bool aDisallowCombinators)
+ SelectorParsingFlags aFlags)
{
nsCSSSelectorList* list = nullptr;
- if (! ParseSelectorGroup(list, aIsForgiving, aDisallowCombinators)) {
- if (aIsForgiving) {
+ if (! ParseSelectorGroup(list, aFlags)) {
+ if (aFlags & SelectorParsingFlags::eIsForgiving) {
// Initialize to an empty list if the first selector group was invalid
// and we're a forgiving selector list.
list = new nsCSSSelectorList();
@@ -5525,16 +5536,17 @@ CSSParserImpl::ParseSelectorList(nsCSSSelectorList*& aListHead,
if (',' == tk->mSymbol) {
nsCSSSelectorList* newList = nullptr;
// Another selector group must follow
- if (! ParseSelectorGroup(newList, aIsForgiving, aDisallowCombinators)) {
+ if (! ParseSelectorGroup(newList, aFlags)) {
// Ignore invalid selectors if we're a forgiving selector list.
- if (aIsForgiving) {
+ if (aFlags & SelectorParsingFlags::eIsForgiving) {
continue;
}
break;
}
// Replace the list head if: it's empty and we're a forgiving selector
// list. Otherwise, add the new list to the end of the selector list.
- if (aIsForgiving && !aListHead->mSelectors) {
+ if ((aFlags & SelectorParsingFlags::eIsForgiving) &&
+ !aListHead->mSelectors) {
MOZ_ASSERT(newList->mSelectors,
"replacing empty list head with an empty selector list?");
aListHead = newList;
@@ -5549,7 +5561,7 @@ CSSParserImpl::ParseSelectorList(nsCSSSelectorList*& aListHead,
}
}
- if (!aIsForgiving) {
+ if (!(aFlags & SelectorParsingFlags::eIsForgiving)) {
REPORT_UNEXPECTED_TOKEN(PESelectorListExtra);
UngetToken();
break;
@@ -5573,13 +5585,14 @@ static bool IsUniversalSelector(const nsCSSSelector& aSelector)
}
bool
-CSSParserImpl::ParseSelectorGroup(nsCSSSelectorList*& aList, bool aIsForgiving, bool aDisallowCombinators)
+CSSParserImpl::ParseSelectorGroup(nsCSSSelectorList*& aList,
+ SelectorParsingFlags aFlags)
{
char16_t combinator = 0;
nsAutoPtr<nsCSSSelectorList> list(new nsCSSSelectorList());
for (;;) {
- if (!ParseSelector(list, combinator, aIsForgiving, aDisallowCombinators)) {
+ if (!ParseSelector(list, combinator, aFlags)) {
return false;
}
@@ -5615,7 +5628,7 @@ CSSParserImpl::ParseSelectorGroup(nsCSSSelectorList*& aList, bool aIsForgiving,
return false;
}
- if (aIsForgiving && aDisallowCombinators) {
+ if (aFlags & SelectorParsingFlags::eDisallowCombinators) {
return false;
}
}
@@ -5674,9 +5687,9 @@ CSSParserImpl::ParseClassSelector(int32_t& aDataMask,
// namespace|type or namespace|* or *|* or *
//
CSSParserImpl::nsSelectorParsingStatus
-CSSParserImpl::ParseTypeOrUniversalSelector(int32_t& aDataMask,
- nsCSSSelector& aSelector,
- bool aIsNegated)
+CSSParserImpl::ParseTypeOrUniversalSelector(int32_t& aDataMask,
+ nsCSSSelector& aSelector,
+ SelectorParsingFlags aFlags)
{
nsAutoString buffer;
if (mToken.IsSymbol('*')) { // universal element selector, or universal namespace
@@ -5780,10 +5793,12 @@ CSSParserImpl::ParseTypeOrUniversalSelector(int32_t& aDataMask,
}
}
else {
- SetDefaultNamespaceOnSelector(aSelector);
+ if (!(aFlags & SelectorParsingFlags::eInheritNamespace)) {
+ SetDefaultNamespaceOnSelector(aSelector);
+ }
}
- if (aIsNegated) {
+ if (aFlags & SelectorParsingFlags::eIsNegated) {
// restore last token read in case of a negated type selector
UngetToken();
}
@@ -6035,17 +6050,17 @@ CSSParserImpl::ParseAttributeSelector(int32_t& aDataMask,
// Parse pseudo-classes and pseudo-elements
//
CSSParserImpl::nsSelectorParsingStatus
-CSSParserImpl::ParsePseudoSelector(int32_t& aDataMask,
- nsCSSSelector& aSelector,
- bool aIsNegated,
- nsIAtom** aPseudoElement,
- nsAtomList** aPseudoElementArgs,
- CSSPseudoElementType* aPseudoElementType,
- bool aDisallowCombinators)
-{
- NS_ASSERTION(aIsNegated || (aPseudoElement && aPseudoElementArgs),
+CSSParserImpl::ParsePseudoSelector(int32_t& aDataMask,
+ nsCSSSelector& aSelector,
+ SelectorParsingFlags aFlags,
+ nsIAtom** aPseudoElement,
+ nsAtomList** aPseudoElementArgs,
+ CSSPseudoElementType* aPseudoElementType)
+{
+ bool isNegated = !!(aFlags & SelectorParsingFlags::eIsNegated);
+ NS_ASSERTION(isNegated || (aPseudoElement && aPseudoElementArgs),
"expected location to store pseudo element");
- NS_ASSERTION(!aIsNegated || (!aPseudoElement && !aPseudoElementArgs),
+ NS_ASSERTION(!isNegated || (!aPseudoElement && !aPseudoElementArgs),
"negated selectors shouldn't have a place to store "
"pseudo elements");
if (! GetToken(false)) { // premature eof
@@ -6144,7 +6159,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 +6196,31 @@ 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)) {
+ // Only the combinators restriction should be passed down the chain.
+ SelectorParsingFlags flags =
+ (aFlags & SelectorParsingFlags::eDisallowCombinators) ?
+ SelectorParsingFlags::eDisallowCombinators :
+ SelectorParsingFlags::eNone;
+ if (sLegacyNegationPseudoClassEnabled &&
+ CSSPseudoClassType::negation == pseudoClassType) {
+ // :not() can't be itself negated
+ if (isNegated) {
+ REPORT_UNEXPECTED_TOKEN(PEPseudoSelDoubleNot);
+ UngetToken();
+ return eSelectorParsingStatus_Error;
+ }
+ // CSS 3 Negation pseudo-class takes one simple selector as argument
+ parsingStatus =
+ ParseNegatedSimpleSelector(aDataMask, aSelector, flags);
+ if (eSelectorParsingStatus_Continue != parsingStatus) {
+ return parsingStatus;
+ }
+ }
+ else if (nsCSSPseudoClasses::HasStringArg(pseudoClassType)) {
parsingStatus =
ParsePseudoClassWithIdentArg(aSelector, pseudoClassType);
}
@@ -6213,7 +6233,7 @@ CSSParserImpl::ParsePseudoSelector(int32_t& aDataMask,
"unexpected pseudo with function token");
parsingStatus = ParsePseudoClassWithSelectorListArg(aSelector,
pseudoClassType,
- aDisallowCombinators);
+ flags);
}
if (eSelectorParsingStatus_Continue != parsingStatus) {
if (eSelectorParsingStatus_Error == parsingStatus) {
@@ -6229,11 +6249,18 @@ CSSParserImpl::ParsePseudoSelector(int32_t& aDataMask,
else if (isPseudoElement || isAnonBox) {
// Pseudo-element. Make some more sanity checks.
- if (aIsNegated) { // pseudo-elements can't be negated
+ // Pseudo-elements can't be negated.
+ if (isNegated) {
REPORT_UNEXPECTED_TOKEN(PEPseudoSelPEInNot);
UngetToken();
return eSelectorParsingStatus_Error;
}
+ // 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) {
+ UngetToken();
+ return eSelectorParsingStatus_Error;
+ }
// CSS2 pseudo-elements and -moz-tree-* pseudo-elements are allowed
// to have a single ':' on them. Others (CSS3+ pseudo-elements and
// various -moz-* pseudo-elements) must have |parsingPseudoElement|
@@ -6304,9 +6331,12 @@ CSSParserImpl::ParsePseudoSelector(int32_t& aDataMask,
// Parse the argument of a negation pseudo-class :not()
//
CSSParserImpl::nsSelectorParsingStatus
-CSSParserImpl::ParseNegatedSimpleSelector(int32_t& aDataMask,
- nsCSSSelector& aSelector)
+CSSParserImpl::ParseNegatedSimpleSelector(int32_t& aDataMask,
+ nsCSSSelector& aSelector,
+ SelectorParsingFlags aFlags)
{
+ aFlags |= SelectorParsingFlags::eIsNegated;
+
if (! GetToken(true)) { // premature eof
REPORT_UNEXPECTED_EOF(PENegationEOF);
return eSelectorParsingStatus_Error;
@@ -6339,9 +6369,8 @@ CSSParserImpl::ParseNegatedSimpleSelector(int32_t& aDataMask,
parsingStatus = ParseClassSelector(aDataMask, *newSel);
}
else if (mToken.IsSymbol(':')) { // :pseudo
- parsingStatus = ParsePseudoSelector(aDataMask, *newSel, true,
- nullptr, nullptr, nullptr,
- false);
+ parsingStatus = ParsePseudoSelector(aDataMask, *newSel, aFlags,
+ nullptr, nullptr, nullptr);
}
else if (mToken.IsSymbol('[')) { // [attribute
parsingStatus = ParseAttributeSelector(aDataMask, *newSel);
@@ -6352,7 +6381,7 @@ CSSParserImpl::ParseNegatedSimpleSelector(int32_t& aDataMask,
}
else {
// then it should be a type element or universal selector
- parsingStatus = ParseTypeOrUniversalSelector(aDataMask, *newSel, true);
+ parsingStatus = ParseTypeOrUniversalSelector(aDataMask, *newSel, aFlags);
}
if (eSelectorParsingStatus_Error == parsingStatus) {
REPORT_UNEXPECTED_TOKEN(PENegationBadInner);
@@ -6578,28 +6607,28 @@ 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,
CSSPseudoClassType aType,
- bool aDisallowCombinators)
+ SelectorParsingFlags aFlags)
{
- bool isForgiving =
- nsCSSPseudoClasses::HasForgivingSelectorListArg(aType);
bool isSingleSelector =
nsCSSPseudoClasses::HasSingleSelectorArg(aType);
- if (isSingleSelector && !aDisallowCombinators) {
- aDisallowCombinators = true;
+ if (nsCSSPseudoClasses::HasForgivingSelectorListArg(aType)) {
+ aFlags |= SelectorParsingFlags::eIsForgiving;
+ } else if (isSingleSelector || aType == CSSPseudoClassType::mozAny) {
+ aFlags |= SelectorParsingFlags::eDisallowCombinators;
+ } else if (aType == CSSPseudoClassType::negation) {
+ aFlags |= SelectorParsingFlags::eInheritNamespace;
}
+ aFlags |= SelectorParsingFlags::eDisallowPseudoElements;
nsAutoPtr<nsCSSSelectorList> slist;
if (! ParseSelectorList(*getter_Transfers(slist),
char16_t(')'),
- isForgiving,
- aDisallowCombinators)) {
+ aFlags)) {
return eSelectorParsingStatus_Error; // our caller calls SkipUntil(')')
}
@@ -6607,23 +6636,32 @@ 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;
- }
- // 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(')')
+ // Special handling for the :not() pseudo-class.
+ if (aType == CSSPseudoClassType::negation) {
+ nsCSSSelector* negations = &aSelector;
+ while (negations->mNegations) {
+ negations = negations->mNegations;
+ }
+ // XXX: Use a special internal-only pseudo-class to handle selector lists
+ // if we have: (a) a complex selector, (b) nested negation pseudo-class,
+ // or (c) more than one selector argument in the list.
+ if (slist->mNext ||
+ slist->mSelectors->mNext ||
+ slist->mSelectors->mNegations) {
+ nsCSSSelector* newSel = new nsCSSSelector();
+ newSel->AddPseudoClass(CSSPseudoClassType::mozAnyPrivate,
+ slist.forget());
+ negations->mNegations = newSel;
+ } else {
+ // Otherwise, steal the first selector and add it directly to the
+ // end of aSelector.mNegations.
+ negations->mNegations = (slist.forget())->mSelectors;
}
+ } else {
+ // 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)) {
REPORT_UNEXPECTED_TOKEN(PEPseudoClassNoClose);
@@ -6641,8 +6679,7 @@ CSSParserImpl::ParsePseudoClassWithSelectorListArg(nsCSSSelector& aSelector,
bool
CSSParserImpl::ParseSelector(nsCSSSelectorList* aList,
char16_t aPrevCombinator,
- bool aIsForgiving,
- bool aDisallowCombinators)
+ SelectorParsingFlags aFlags)
{
if (! GetToken(true)) {
REPORT_UNEXPECTED_EOF(PESelectorEOF);
@@ -6656,15 +6693,14 @@ CSSParserImpl::ParseSelector(nsCSSSelectorList* aList,
int32_t dataMask = 0;
nsSelectorParsingStatus parsingStatus =
- ParseTypeOrUniversalSelector(dataMask, *selector, false);
+ ParseTypeOrUniversalSelector(dataMask, *selector, aFlags);
while (parsingStatus == eSelectorParsingStatus_Continue) {
if (mToken.IsSymbol(':')) { // :pseudo
- parsingStatus = ParsePseudoSelector(dataMask, *selector, false,
+ parsingStatus = ParsePseudoSelector(dataMask, *selector, aFlags,
getter_AddRefs(pseudoElement),
getter_Transfers(pseudoElementArgs),
- &pseudoElementType,
- aDisallowCombinators);
+ &pseudoElementType);
if (pseudoElement &&
pseudoElementType != CSSPseudoElementType::AnonBox) {
// Pseudo-elements other than anonymous boxes are represented with
@@ -6720,7 +6756,7 @@ CSSParserImpl::ParseSelector(nsCSSSelectorList* aList,
// XXX(franklindm): We're effectively ignoring stray combinators
// and empty selector groups here for forgiving selector lists.
// It doesn't seem right, but this is how tainted browsers do it.
- if (aIsForgiving) {
+ if (aFlags & SelectorParsingFlags::eIsForgiving) {
return false;
}
if (selector->mNext) {
@@ -17899,6 +17935,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,