diff --git a/application/basilisk/branding/shared/uaoverrides.inc b/application/basilisk/branding/shared/uaoverrides.inc index d0cb13b923..5e01a8f9f0 100644 --- a/application/basilisk/branding/shared/uaoverrides.inc +++ b/application/basilisk/branding/shared/uaoverrides.inc @@ -24,6 +24,7 @@ pref("@GUAO_PREF@.aol.com","Mozilla/5.0 (%OS_SLICE% rv:@GK_VERSION@) @GK_SLICE@ pref("@GUAO_PREF@.bing.com","Mozilla/5.0 (%OS_SLICE% rv:@GK_VERSION@) @GK_SLICE@ @FX_SLICE@ (Basilisk)"); pref("@GUAO_PREF@.chase.com","Mozilla/5.0 (%OS_SLICE% rv:79.0) @GK_SLICE@ Firefox/79.0"); pref("@GUAO_PREF@.dropbox.com","Mozilla/5.0 (%OS_SLICE% rv:68.9) @GK_SLICE@ Firefox/68.9 (Basilisk)"); +pref("@GUAO_PREF@.instagram.com","Mozilla/5.0 (%OS_SLICE% rv:68.0) @GK_SLICE@ Firefox/68.0"); pref("@GUAO_PREF@.google.com","Mozilla/5.0 (%OS_SLICE% rv:71.0) @GK_SLICE@ Firefox/71.0 @APP_SLICE@"); pref("@GUAO_PREF@.googlevideos.com","Mozilla/5.0 (%OS_SLICE% rv:38.9) @GK_SLICE@ @UXP_VERSION_SLICE@ Firefox/38.9 @APP_SLICE@"); pref("@GUAO_PREF@.gstatic.com","Mozilla/5.0 (%OS_SLICE% rv:71.0) @GK_SLICE@ Firefox/71.0 @APP_SLICE@"); diff --git a/dom/base/ShadowRoot.cpp b/dom/base/ShadowRoot.cpp index e31b97262c..92d5a2f2a9 100644 --- a/dom/base/ShadowRoot.cpp +++ b/dom/base/ShadowRoot.cpp @@ -578,6 +578,13 @@ ShadowRoot::ContentInserted(nsIDocument* aDocument, if (slot && slot->GetContainingShadow() == this && slot->AssignedNodes().IsEmpty()) { slot->EnqueueSlotChangeEvent(); + return; + } + + // XXX: The following makes the host destroy its frames and force a + // restyle for cases where the content isn't slotted. + if (aContainer == this) { + DistributionChanged(); } } @@ -614,6 +621,13 @@ ShadowRoot::ContentRemoved(nsIDocument* aDocument, if (slot && slot->GetContainingShadow() == this && slot->AssignedNodes().IsEmpty()) { slot->EnqueueSlotChangeEvent(); + return; + } + + // XXX: The following makes the host destroy its frames and force a + // restyle for cases where the content isn't slotted. + if (aContainer == this) { + DistributionChanged(); } } diff --git a/layout/style/Loader.cpp b/layout/style/Loader.cpp index 3d1e4826d5..48ca1739dc 100644 --- a/layout/style/Loader.cpp +++ b/layout/style/Loader.cpp @@ -2118,7 +2118,7 @@ Loader::LoadStyleLink(nsIContent* aElement, PrepareSheet(sheet, aTitle, aMedia, nullptr, nullptr, *aIsAlternate, *aIsExplicitlyEnabled); - if (aElement->HasFlag(NODE_IS_IN_SHADOW_TREE)) { + if (aElement && aElement->HasFlag(NODE_IS_IN_SHADOW_TREE)) { aElement->GetContainingShadow()->InsertSheet(sheet, aElement); } else { rv = InsertSheetInDoc(sheet, aElement, mDocument); diff --git a/layout/style/StyleRule.cpp b/layout/style/StyleRule.cpp index 2f08d88f14..0ae939098a 100644 --- a/layout/style/StyleRule.cpp +++ b/layout/style/StyleRule.cpp @@ -920,9 +920,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); @@ -951,7 +955,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(')')); + } } } } @@ -1042,6 +1048,10 @@ nsCSSSelectorList::ToString(nsAString& aResult, CSSStyleSheet* aSheet) { aResult.Truncate(); nsCSSSelectorList *p = this; + // Don't append anything if we're an empty selector list. + if (!mSelectors) { + return; + } for (;;) { p->mSelectors->ToString(aResult, aSheet, true); p = p->mNext; diff --git a/layout/style/nsCSSParser.cpp b/layout/style/nsCSSParser.cpp index a3fef2ca67..6f06b5b3e6 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 @@ -758,21 +772,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); @@ -782,24 +796,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, @@ -2339,7 +2351,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 @@ -5455,7 +5467,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); @@ -5492,12 +5504,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(); @@ -5527,16 +5538,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; @@ -5551,7 +5563,7 @@ CSSParserImpl::ParseSelectorList(nsCSSSelectorList*& aListHead, } } - if (!aIsForgiving) { + if (!(aFlags & SelectorParsingFlags::eIsForgiving)) { REPORT_UNEXPECTED_TOKEN(PESelectorListExtra); UngetToken(); break; @@ -5575,13 +5587,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 list(new nsCSSSelectorList()); for (;;) { - if (!ParseSelector(list, combinator, aIsForgiving, aDisallowCombinators)) { + if (!ParseSelector(list, combinator, aFlags)) { return false; } @@ -5617,7 +5630,7 @@ CSSParserImpl::ParseSelectorGroup(nsCSSSelectorList*& aList, bool aIsForgiving, return false; } - if (aIsForgiving && aDisallowCombinators) { + if (aFlags & SelectorParsingFlags::eDisallowCombinators) { return false; } } @@ -5676,9 +5689,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 @@ -5782,10 +5795,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(); } @@ -6039,17 +6054,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) +CSSParserImpl::ParsePseudoSelector(int32_t& aDataMask, + nsCSSSelector& aSelector, + SelectorParsingFlags aFlags, + nsIAtom** aPseudoElement, + nsAtomList** aPseudoElementArgs, + CSSPseudoElementType* aPseudoElementType) { - NS_ASSERTION(aIsNegated || (aPseudoElement && aPseudoElementArgs), + 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 @@ -6152,7 +6167,6 @@ CSSParserImpl::ParsePseudoSelector(int32_t& aDataMask, #ifdef MOZ_XUL isTree || #endif - CSSPseudoClassType::negation == pseudoClassType || nsCSSPseudoClasses::HasStringArg(pseudoClassType) || nsCSSPseudoClasses::HasNthPairArg(pseudoClassType) || nsCSSPseudoClasses::HasSelectorListArg(pseudoClassType)) && @@ -6190,25 +6204,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); } @@ -6221,7 +6241,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) { @@ -6237,11 +6257,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| @@ -6317,9 +6344,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; @@ -6352,9 +6382,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); @@ -6365,7 +6394,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); @@ -6591,28 +6620,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 slist; if (! ParseSelectorList(*getter_Transfers(slist), char16_t(')'), - isForgiving, - aDisallowCombinators)) { + aFlags)) { return eSelectorParsingStatus_Error; // our caller calls SkipUntil(')') } @@ -6620,23 +6649,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; + // 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 + // 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); @@ -6654,8 +6692,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); @@ -6669,15 +6706,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 @@ -6733,7 +6769,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) { @@ -17922,6 +17958,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 ebc3dad63e..692419b566 100644 --- a/layout/style/nsCSSRuleProcessor.cpp +++ b/layout/style/nsCSSRuleProcessor.cpp @@ -1952,6 +1952,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, diff --git a/modules/libpref/init/all.js b/modules/libpref/init/all.js index 9ac61802d9..c3d5c5e57a 100644 --- a/modules/libpref/init/all.js +++ b/modules/libpref/init/all.js @@ -2556,6 +2556,9 @@ pref("layout.css.prefixes.webkit", true); // pref is set to false.) pref("layout.css.prefixes.device-pixel-ratio-webkit", false); +// Is the legacy negation pseudo-class behavior enabled? +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);