Merge remote-tracking branch 'origin/tracking' into custom

This commit is contained in:
roytam1 2023-03-12 07:16:48 +08:00
commit 2b9187d8bf
10 changed files with 198 additions and 107 deletions

View file

@ -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@.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@.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@.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@.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@.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@"); pref("@GUAO_PREF@.gstatic.com","Mozilla/5.0 (%OS_SLICE% rv:71.0) @GK_SLICE@ Firefox/71.0 @APP_SLICE@");

View file

@ -578,6 +578,13 @@ ShadowRoot::ContentInserted(nsIDocument* aDocument,
if (slot && slot->GetContainingShadow() == this && if (slot && slot->GetContainingShadow() == this &&
slot->AssignedNodes().IsEmpty()) { slot->AssignedNodes().IsEmpty()) {
slot->EnqueueSlotChangeEvent(); 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 && if (slot && slot->GetContainingShadow() == this &&
slot->AssignedNodes().IsEmpty()) { slot->AssignedNodes().IsEmpty()) {
slot->EnqueueSlotChangeEvent(); 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();
} }
} }

View file

@ -2118,7 +2118,7 @@ Loader::LoadStyleLink(nsIContent* aElement,
PrepareSheet(sheet, aTitle, aMedia, nullptr, nullptr, *aIsAlternate, *aIsExplicitlyEnabled); 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); aElement->GetContainingShadow()->InsertSheet(sheet, aElement);
} else { } else {
rv = InsertSheetInDoc(sheet, aElement, mDocument); rv = InsertSheetInDoc(sheet, aElement, mDocument);

View file

@ -920,9 +920,13 @@ nsCSSSelector::AppendToStringWithoutCombinatorsOrNegations
// has a ":" that can't be escaped and (b) all pseudo-classes at // 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 // this point are known, and therefore we know they don't need
// escaping. // escaping.
if (!nsCSSPseudoClasses::IsHiddenFromSerialization(list->mType)) {
aString.Append(temp); aString.Append(temp);
}
if (list->u.mMemory) { if (list->u.mMemory) {
if (!nsCSSPseudoClasses::IsHiddenFromSerialization(list->mType)) {
aString.Append(char16_t('(')); aString.Append(char16_t('('));
}
if (nsCSSPseudoClasses::HasStringArg(list->mType)) { if (nsCSSPseudoClasses::HasStringArg(list->mType)) {
nsStyleUtil::AppendEscapedCSSIdent( nsStyleUtil::AppendEscapedCSSIdent(
nsDependentString(list->u.mString), aString); nsDependentString(list->u.mString), aString);
@ -951,9 +955,11 @@ nsCSSSelector::AppendToStringWithoutCombinatorsOrNegations
list->u.mSelectorList->ToString(tmp, aSheet); list->u.mSelectorList->ToString(tmp, aSheet);
aString.Append(tmp); aString.Append(tmp);
} }
if (!nsCSSPseudoClasses::IsHiddenFromSerialization(list->mType)) {
aString.Append(char16_t(')')); aString.Append(char16_t(')'));
} }
} }
}
} }
bool bool
@ -1042,6 +1048,10 @@ nsCSSSelectorList::ToString(nsAString& aResult, CSSStyleSheet* aSheet)
{ {
aResult.Truncate(); aResult.Truncate();
nsCSSSelectorList *p = this; nsCSSSelectorList *p = this;
// Don't append anything if we're an empty selector list.
if (!mSelectors) {
return;
}
for (;;) { for (;;) {
p->mSelectors->ToString(aResult, aSheet, true); p->mSelectors->ToString(aResult, aSheet, true);
p = p->mNext; p = p->mNext;

View file

@ -67,6 +67,7 @@ static bool sWebkitPrefixedAliasesEnabled;
static bool sWebkitDevicePixelRatioEnabled; static bool sWebkitDevicePixelRatioEnabled;
static bool sMozGradientsEnabled; static bool sMozGradientsEnabled;
static bool sControlCharVisibility; static bool sControlCharVisibility;
static bool sLegacyNegationPseudoClassEnabled;
const uint32_t const uint32_t
nsCSSProps::kParserVariantTable[eCSSProperty_COUNT_no_shorthands] = { nsCSSProps::kParserVariantTable[eCSSProperty_COUNT_no_shorthands] = {
@ -109,6 +110,19 @@ enum class GridTrackListFlags {
}; };
MOZ_MAKE_ENUM_CLASS_BITWISE_OPERATORS(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 { namespace {
// Rule processing function // Rule processing function
@ -758,21 +772,21 @@ protected:
// aPseudoElement and aPseudoElementArgs are the location where // aPseudoElement and aPseudoElementArgs are the location where
// pseudo-elements (as opposed to pseudo-classes) are stored; // pseudo-elements (as opposed to pseudo-classes) are stored;
// pseudo-classes are stored on aSelector. aPseudoElement and // pseudo-classes are stored on aSelector. aPseudoElement and
// aPseudoElementArgs must be non-null iff !aIsNegated. // aPseudoElementArgs must be non-null iff the eIsNegated flag of
// aFlags is not set.
nsSelectorParsingStatus ParsePseudoSelector(int32_t& aDataMask, nsSelectorParsingStatus ParsePseudoSelector(int32_t& aDataMask,
nsCSSSelector& aSelector, nsCSSSelector& aSelector,
bool aIsNegated, SelectorParsingFlags aFlags,
nsIAtom** aPseudoElement, nsIAtom** aPseudoElement,
nsAtomList** aPseudoElementArgs, nsAtomList** aPseudoElementArgs,
CSSPseudoElementType* aPseudoElementType, CSSPseudoElementType* aPseudoElementType);
bool aDisallowCombinators);
nsSelectorParsingStatus ParseAttributeSelector(int32_t& aDataMask, nsSelectorParsingStatus ParseAttributeSelector(int32_t& aDataMask,
nsCSSSelector& aSelector); nsCSSSelector& aSelector);
nsSelectorParsingStatus ParseTypeOrUniversalSelector(int32_t& aDataMask, nsSelectorParsingStatus ParseTypeOrUniversalSelector(int32_t& aDataMask,
nsCSSSelector& aSelector, nsCSSSelector& aSelector,
bool aIsNegated); SelectorParsingFlags aFlags);
nsSelectorParsingStatus ParsePseudoClassWithIdentArg(nsCSSSelector& aSelector, nsSelectorParsingStatus ParsePseudoClassWithIdentArg(nsCSSSelector& aSelector,
CSSPseudoClassType aType); CSSPseudoClassType aType);
@ -782,24 +796,22 @@ protected:
nsSelectorParsingStatus ParsePseudoClassWithSelectorListArg(nsCSSSelector& aSelector, nsSelectorParsingStatus ParsePseudoClassWithSelectorListArg(nsCSSSelector& aSelector,
CSSPseudoClassType aType, CSSPseudoClassType aType,
bool aDisallowCombinators); SelectorParsingFlags aFlags);
nsSelectorParsingStatus ParseNegatedSimpleSelector(int32_t& aDataMask, nsSelectorParsingStatus ParseNegatedSimpleSelector(int32_t& aDataMask,
nsCSSSelector& aSelector); nsCSSSelector& aSelector,
SelectorParsingFlags aFlags);
// If aStopChar is non-zero, the selector list is done when we hit // If aStopChar is non-zero, the selector list is done when we hit
// aStopChar. Otherwise, it's done when we hit EOF. // aStopChar. Otherwise, it's done when we hit EOF.
bool ParseSelectorList(nsCSSSelectorList*& aListHead, bool ParseSelectorList(nsCSSSelectorList*& aListHead,
char16_t aStopChar, char16_t aStopChar,
bool aIsForgiving, SelectorParsingFlags aFlags = SelectorParsingFlags::eNone);
bool aDisallowCombinators);
bool ParseSelectorGroup(nsCSSSelectorList*& aListHead, bool ParseSelectorGroup(nsCSSSelectorList*& aListHead,
bool aIsForgiving, SelectorParsingFlags aFlags);
bool aDisallowCombinators);
bool ParseSelector(nsCSSSelectorList* aList, bool ParseSelector(nsCSSSelectorList* aList,
char16_t aPrevCombinator, char16_t aPrevCombinator,
bool aIsForgiving, SelectorParsingFlags aFlags);
bool aDisallowCombinators);
enum { enum {
eParseDeclaration_InBraces = 1 << 0, eParseDeclaration_InBraces = 1 << 0,
@ -2339,7 +2351,7 @@ CSSParserImpl::ParseSelectorString(const nsSubstring& aSelectorString,
css::ErrorReporter reporter(scanner, mSheet, mChildLoader, aURI); css::ErrorReporter reporter(scanner, mSheet, mChildLoader, aURI);
InitScanner(scanner, reporter, aURI, aURI, nullptr); 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 // We deliberately do not call OUTPUT_ERROR here, because all our
// callers map a failure return to a JS exception, and if that JS // 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; nsCSSSelectorList* slist = nullptr;
uint32_t linenum, colnum; uint32_t linenum, colnum;
if (!GetNextTokenLocation(true, &linenum, &colnum) || if (!GetNextTokenLocation(true, &linenum, &colnum) ||
!ParseSelectorList(slist, char16_t('{'), false, false)) { !ParseSelectorList(slist, char16_t('{'))) {
REPORT_UNEXPECTED(PEBadSelectorRSIgnored); REPORT_UNEXPECTED(PEBadSelectorRSIgnored);
OUTPUT_ERROR(); OUTPUT_ERROR();
SkipRuleSet(aInsideBraces); SkipRuleSet(aInsideBraces);
@ -5492,12 +5504,11 @@ CSSParserImpl::ParseRuleSet(RuleAppendFunc aAppendFunc, void* aData,
bool bool
CSSParserImpl::ParseSelectorList(nsCSSSelectorList*& aListHead, CSSParserImpl::ParseSelectorList(nsCSSSelectorList*& aListHead,
char16_t aStopChar, char16_t aStopChar,
bool aIsForgiving, SelectorParsingFlags aFlags)
bool aDisallowCombinators)
{ {
nsCSSSelectorList* list = nullptr; nsCSSSelectorList* list = nullptr;
if (! ParseSelectorGroup(list, aIsForgiving, aDisallowCombinators)) { if (! ParseSelectorGroup(list, aFlags)) {
if (aIsForgiving) { if (aFlags & SelectorParsingFlags::eIsForgiving) {
// Initialize to an empty list if the first selector group was invalid // Initialize to an empty list if the first selector group was invalid
// and we're a forgiving selector list. // and we're a forgiving selector list.
list = new nsCSSSelectorList(); list = new nsCSSSelectorList();
@ -5527,16 +5538,17 @@ CSSParserImpl::ParseSelectorList(nsCSSSelectorList*& aListHead,
if (',' == tk->mSymbol) { if (',' == tk->mSymbol) {
nsCSSSelectorList* newList = nullptr; nsCSSSelectorList* newList = nullptr;
// Another selector group must follow // Another selector group must follow
if (! ParseSelectorGroup(newList, aIsForgiving, aDisallowCombinators)) { if (! ParseSelectorGroup(newList, aFlags)) {
// Ignore invalid selectors if we're a forgiving selector list. // Ignore invalid selectors if we're a forgiving selector list.
if (aIsForgiving) { if (aFlags & SelectorParsingFlags::eIsForgiving) {
continue; continue;
} }
break; break;
} }
// Replace the list head if: it's empty and we're a forgiving selector // 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. // 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, MOZ_ASSERT(newList->mSelectors,
"replacing empty list head with an empty selector list?"); "replacing empty list head with an empty selector list?");
aListHead = newList; aListHead = newList;
@ -5551,7 +5563,7 @@ CSSParserImpl::ParseSelectorList(nsCSSSelectorList*& aListHead,
} }
} }
if (!aIsForgiving) { if (!(aFlags & SelectorParsingFlags::eIsForgiving)) {
REPORT_UNEXPECTED_TOKEN(PESelectorListExtra); REPORT_UNEXPECTED_TOKEN(PESelectorListExtra);
UngetToken(); UngetToken();
break; break;
@ -5575,13 +5587,14 @@ static bool IsUniversalSelector(const nsCSSSelector& aSelector)
} }
bool bool
CSSParserImpl::ParseSelectorGroup(nsCSSSelectorList*& aList, bool aIsForgiving, bool aDisallowCombinators) CSSParserImpl::ParseSelectorGroup(nsCSSSelectorList*& aList,
SelectorParsingFlags aFlags)
{ {
char16_t combinator = 0; char16_t combinator = 0;
nsAutoPtr<nsCSSSelectorList> list(new nsCSSSelectorList()); nsAutoPtr<nsCSSSelectorList> list(new nsCSSSelectorList());
for (;;) { for (;;) {
if (!ParseSelector(list, combinator, aIsForgiving, aDisallowCombinators)) { if (!ParseSelector(list, combinator, aFlags)) {
return false; return false;
} }
@ -5617,7 +5630,7 @@ CSSParserImpl::ParseSelectorGroup(nsCSSSelectorList*& aList, bool aIsForgiving,
return false; return false;
} }
if (aIsForgiving && aDisallowCombinators) { if (aFlags & SelectorParsingFlags::eDisallowCombinators) {
return false; return false;
} }
} }
@ -5678,7 +5691,7 @@ CSSParserImpl::ParseClassSelector(int32_t& aDataMask,
CSSParserImpl::nsSelectorParsingStatus CSSParserImpl::nsSelectorParsingStatus
CSSParserImpl::ParseTypeOrUniversalSelector(int32_t& aDataMask, CSSParserImpl::ParseTypeOrUniversalSelector(int32_t& aDataMask,
nsCSSSelector& aSelector, nsCSSSelector& aSelector,
bool aIsNegated) SelectorParsingFlags aFlags)
{ {
nsAutoString buffer; nsAutoString buffer;
if (mToken.IsSymbol('*')) { // universal element selector, or universal namespace if (mToken.IsSymbol('*')) { // universal element selector, or universal namespace
@ -5782,10 +5795,12 @@ CSSParserImpl::ParseTypeOrUniversalSelector(int32_t& aDataMask,
} }
} }
else { else {
if (!(aFlags & SelectorParsingFlags::eInheritNamespace)) {
SetDefaultNamespaceOnSelector(aSelector); SetDefaultNamespaceOnSelector(aSelector);
} }
}
if (aIsNegated) { if (aFlags & SelectorParsingFlags::eIsNegated) {
// restore last token read in case of a negated type selector // restore last token read in case of a negated type selector
UngetToken(); UngetToken();
} }
@ -6041,15 +6056,15 @@ CSSParserImpl::ParseAttributeSelector(int32_t& aDataMask,
CSSParserImpl::nsSelectorParsingStatus CSSParserImpl::nsSelectorParsingStatus
CSSParserImpl::ParsePseudoSelector(int32_t& aDataMask, CSSParserImpl::ParsePseudoSelector(int32_t& aDataMask,
nsCSSSelector& aSelector, nsCSSSelector& aSelector,
bool aIsNegated, SelectorParsingFlags aFlags,
nsIAtom** aPseudoElement, nsIAtom** aPseudoElement,
nsAtomList** aPseudoElementArgs, nsAtomList** aPseudoElementArgs,
CSSPseudoElementType* aPseudoElementType, CSSPseudoElementType* aPseudoElementType)
bool aDisallowCombinators)
{ {
NS_ASSERTION(aIsNegated || (aPseudoElement && aPseudoElementArgs), bool isNegated = !!(aFlags & SelectorParsingFlags::eIsNegated);
NS_ASSERTION(isNegated || (aPseudoElement && aPseudoElementArgs),
"expected location to store pseudo element"); "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 " "negated selectors shouldn't have a place to store "
"pseudo elements"); "pseudo elements");
if (! GetToken(false)) { // premature eof if (! GetToken(false)) { // premature eof
@ -6152,7 +6167,6 @@ CSSParserImpl::ParsePseudoSelector(int32_t& aDataMask,
#ifdef MOZ_XUL #ifdef MOZ_XUL
isTree || isTree ||
#endif #endif
CSSPseudoClassType::negation == pseudoClassType ||
nsCSSPseudoClasses::HasStringArg(pseudoClassType) || nsCSSPseudoClasses::HasStringArg(pseudoClassType) ||
nsCSSPseudoClasses::HasNthPairArg(pseudoClassType) || nsCSSPseudoClasses::HasNthPairArg(pseudoClassType) ||
nsCSSPseudoClasses::HasSelectorListArg(pseudoClassType)) && nsCSSPseudoClasses::HasSelectorListArg(pseudoClassType)) &&
@ -6190,25 +6204,31 @@ CSSParserImpl::ParsePseudoSelector(int32_t& aDataMask,
} }
} }
if (!parsingPseudoElement && if (!parsingPseudoElement && isPseudoClass) {
aDataMask |= SEL_MASK_PCLASS;
if (eCSSToken_Function == mToken.mType) {
nsSelectorParsingStatus parsingStatus;
// Only the combinators restriction should be passed down the chain.
SelectorParsingFlags flags =
(aFlags & SelectorParsingFlags::eDisallowCombinators) ?
SelectorParsingFlags::eDisallowCombinators :
SelectorParsingFlags::eNone;
if (sLegacyNegationPseudoClassEnabled &&
CSSPseudoClassType::negation == pseudoClassType) { CSSPseudoClassType::negation == pseudoClassType) {
if (aIsNegated) { // :not() can't be itself negated // :not() can't be itself negated
if (isNegated) {
REPORT_UNEXPECTED_TOKEN(PEPseudoSelDoubleNot); REPORT_UNEXPECTED_TOKEN(PEPseudoSelDoubleNot);
UngetToken(); UngetToken();
return eSelectorParsingStatus_Error; return eSelectorParsingStatus_Error;
} }
// CSS 3 Negation pseudo-class takes one simple selector as argument // CSS 3 Negation pseudo-class takes one simple selector as argument
nsSelectorParsingStatus parsingStatus = parsingStatus =
ParseNegatedSimpleSelector(aDataMask, aSelector); ParseNegatedSimpleSelector(aDataMask, aSelector, flags);
if (eSelectorParsingStatus_Continue != parsingStatus) { if (eSelectorParsingStatus_Continue != parsingStatus) {
return parsingStatus; return parsingStatus;
} }
} }
else if (!parsingPseudoElement && isPseudoClass) { else if (nsCSSPseudoClasses::HasStringArg(pseudoClassType)) {
aDataMask |= SEL_MASK_PCLASS;
if (eCSSToken_Function == mToken.mType) {
nsSelectorParsingStatus parsingStatus;
if (nsCSSPseudoClasses::HasStringArg(pseudoClassType)) {
parsingStatus = parsingStatus =
ParsePseudoClassWithIdentArg(aSelector, pseudoClassType); ParsePseudoClassWithIdentArg(aSelector, pseudoClassType);
} }
@ -6221,7 +6241,7 @@ CSSParserImpl::ParsePseudoSelector(int32_t& aDataMask,
"unexpected pseudo with function token"); "unexpected pseudo with function token");
parsingStatus = ParsePseudoClassWithSelectorListArg(aSelector, parsingStatus = ParsePseudoClassWithSelectorListArg(aSelector,
pseudoClassType, pseudoClassType,
aDisallowCombinators); flags);
} }
if (eSelectorParsingStatus_Continue != parsingStatus) { if (eSelectorParsingStatus_Continue != parsingStatus) {
if (eSelectorParsingStatus_Error == parsingStatus) { if (eSelectorParsingStatus_Error == parsingStatus) {
@ -6237,11 +6257,18 @@ CSSParserImpl::ParsePseudoSelector(int32_t& aDataMask,
else if (isPseudoElement || isAnonBox) { else if (isPseudoElement || isAnonBox) {
// Pseudo-element. Make some more sanity checks. // 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); REPORT_UNEXPECTED_TOKEN(PEPseudoSelPEInNot);
UngetToken(); UngetToken();
return eSelectorParsingStatus_Error; 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 // CSS2 pseudo-elements and -moz-tree-* pseudo-elements are allowed
// to have a single ':' on them. Others (CSS3+ pseudo-elements and // to have a single ':' on them. Others (CSS3+ pseudo-elements and
// various -moz-* pseudo-elements) must have |parsingPseudoElement| // various -moz-* pseudo-elements) must have |parsingPseudoElement|
@ -6318,8 +6345,11 @@ CSSParserImpl::ParsePseudoSelector(int32_t& aDataMask,
// //
CSSParserImpl::nsSelectorParsingStatus CSSParserImpl::nsSelectorParsingStatus
CSSParserImpl::ParseNegatedSimpleSelector(int32_t& aDataMask, CSSParserImpl::ParseNegatedSimpleSelector(int32_t& aDataMask,
nsCSSSelector& aSelector) nsCSSSelector& aSelector,
SelectorParsingFlags aFlags)
{ {
aFlags |= SelectorParsingFlags::eIsNegated;
if (! GetToken(true)) { // premature eof if (! GetToken(true)) { // premature eof
REPORT_UNEXPECTED_EOF(PENegationEOF); REPORT_UNEXPECTED_EOF(PENegationEOF);
return eSelectorParsingStatus_Error; return eSelectorParsingStatus_Error;
@ -6352,9 +6382,8 @@ CSSParserImpl::ParseNegatedSimpleSelector(int32_t& aDataMask,
parsingStatus = ParseClassSelector(aDataMask, *newSel); parsingStatus = ParseClassSelector(aDataMask, *newSel);
} }
else if (mToken.IsSymbol(':')) { // :pseudo else if (mToken.IsSymbol(':')) { // :pseudo
parsingStatus = ParsePseudoSelector(aDataMask, *newSel, true, parsingStatus = ParsePseudoSelector(aDataMask, *newSel, aFlags,
nullptr, nullptr, nullptr, nullptr, nullptr, nullptr);
false);
} }
else if (mToken.IsSymbol('[')) { // [attribute else if (mToken.IsSymbol('[')) { // [attribute
parsingStatus = ParseAttributeSelector(aDataMask, *newSel); parsingStatus = ParseAttributeSelector(aDataMask, *newSel);
@ -6365,7 +6394,7 @@ CSSParserImpl::ParseNegatedSimpleSelector(int32_t& aDataMask,
} }
else { else {
// then it should be a type element or universal selector // then it should be a type element or universal selector
parsingStatus = ParseTypeOrUniversalSelector(aDataMask, *newSel, true); parsingStatus = ParseTypeOrUniversalSelector(aDataMask, *newSel, aFlags);
} }
if (eSelectorParsingStatus_Error == parsingStatus) { if (eSelectorParsingStatus_Error == parsingStatus) {
REPORT_UNEXPECTED_TOKEN(PENegationBadInner); 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. // 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::nsSelectorParsingStatus
CSSParserImpl::ParsePseudoClassWithSelectorListArg(nsCSSSelector& aSelector, CSSParserImpl::ParsePseudoClassWithSelectorListArg(nsCSSSelector& aSelector,
CSSPseudoClassType aType, CSSPseudoClassType aType,
bool aDisallowCombinators) SelectorParsingFlags aFlags)
{ {
bool isForgiving =
nsCSSPseudoClasses::HasForgivingSelectorListArg(aType);
bool isSingleSelector = bool isSingleSelector =
nsCSSPseudoClasses::HasSingleSelectorArg(aType); nsCSSPseudoClasses::HasSingleSelectorArg(aType);
if (isSingleSelector && !aDisallowCombinators) { if (nsCSSPseudoClasses::HasForgivingSelectorListArg(aType)) {
aDisallowCombinators = true; 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; nsAutoPtr<nsCSSSelectorList> slist;
if (! ParseSelectorList(*getter_Transfers(slist), if (! ParseSelectorList(*getter_Transfers(slist),
char16_t(')'), char16_t(')'),
isForgiving, aFlags)) {
aDisallowCombinators)) {
return eSelectorParsingStatus_Error; // our caller calls SkipUntil(')') return eSelectorParsingStatus_Error; // our caller calls SkipUntil(')')
} }
@ -6620,22 +6649,31 @@ CSSParserImpl::ParsePseudoClassWithSelectorListArg(nsCSSSelector& aSelector,
return eSelectorParsingStatus_Error; // our caller calls SkipUntil(')') return eSelectorParsingStatus_Error; // our caller calls SkipUntil(')')
} }
for (nsCSSSelectorList *l = slist; l; l = l->mNext) { // Special handling for the :not() pseudo-class.
nsCSSSelector *s = l->mSelectors; if (aType == CSSPseudoClassType::negation) {
if (s == nullptr) { nsCSSSelector* negations = &aSelector;
MOZ_ASSERT(isForgiving, while (negations->mNegations) {
"unexpected empty selector in unforgiving selector list"); negations = negations->mNegations;
break;
} }
// Check that none of the selectors in the list have combinators or // XXX: Use a special internal-only pseudo-class to handle selector lists
// pseudo-elements. // if we have: (a) a complex selector, (b) nested negation pseudo-class,
if ((!isForgiving && s->mNext) || s->IsPseudoElement()) { // or (c) more than one selector argument in the list.
return eSelectorParsingStatus_Error; // our caller calls SkipUntil(')') 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 // Add the pseudo with the selector list parameter
aSelector.AddPseudoClass(aType, slist.forget()); aSelector.AddPseudoClass(aType, slist.forget());
}
// close the parenthesis // close the parenthesis
if (!ExpectSymbol(')', true)) { if (!ExpectSymbol(')', true)) {
@ -6654,8 +6692,7 @@ CSSParserImpl::ParsePseudoClassWithSelectorListArg(nsCSSSelector& aSelector,
bool bool
CSSParserImpl::ParseSelector(nsCSSSelectorList* aList, CSSParserImpl::ParseSelector(nsCSSSelectorList* aList,
char16_t aPrevCombinator, char16_t aPrevCombinator,
bool aIsForgiving, SelectorParsingFlags aFlags)
bool aDisallowCombinators)
{ {
if (! GetToken(true)) { if (! GetToken(true)) {
REPORT_UNEXPECTED_EOF(PESelectorEOF); REPORT_UNEXPECTED_EOF(PESelectorEOF);
@ -6669,15 +6706,14 @@ CSSParserImpl::ParseSelector(nsCSSSelectorList* aList,
int32_t dataMask = 0; int32_t dataMask = 0;
nsSelectorParsingStatus parsingStatus = nsSelectorParsingStatus parsingStatus =
ParseTypeOrUniversalSelector(dataMask, *selector, false); ParseTypeOrUniversalSelector(dataMask, *selector, aFlags);
while (parsingStatus == eSelectorParsingStatus_Continue) { while (parsingStatus == eSelectorParsingStatus_Continue) {
if (mToken.IsSymbol(':')) { // :pseudo if (mToken.IsSymbol(':')) { // :pseudo
parsingStatus = ParsePseudoSelector(dataMask, *selector, false, parsingStatus = ParsePseudoSelector(dataMask, *selector, aFlags,
getter_AddRefs(pseudoElement), getter_AddRefs(pseudoElement),
getter_Transfers(pseudoElementArgs), getter_Transfers(pseudoElementArgs),
&pseudoElementType, &pseudoElementType);
aDisallowCombinators);
if (pseudoElement && if (pseudoElement &&
pseudoElementType != CSSPseudoElementType::AnonBox) { pseudoElementType != CSSPseudoElementType::AnonBox) {
// Pseudo-elements other than anonymous boxes are represented with // 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 // XXX(franklindm): We're effectively ignoring stray combinators
// and empty selector groups here for forgiving selector lists. // and empty selector groups here for forgiving selector lists.
// It doesn't seem right, but this is how tainted browsers do it. // It doesn't seem right, but this is how tainted browsers do it.
if (aIsForgiving) { if (aFlags & SelectorParsingFlags::eIsForgiving) {
return false; return false;
} }
if (selector->mNext) { if (selector->mNext) {
@ -17922,6 +17958,8 @@ nsCSSParser::Startup()
"layout.css.prefixes.gradients"); "layout.css.prefixes.gradients");
Preferences::AddBoolVarCache(&sControlCharVisibility, Preferences::AddBoolVarCache(&sControlCharVisibility,
"layout.css.control-characters.visible"); "layout.css.control-characters.visible");
Preferences::AddBoolVarCache(&sLegacyNegationPseudoClassEnabled,
"layout.css.legacy-negation-pseudo.enabled");
} }
nsCSSParser::nsCSSParser(mozilla::css::Loader* aLoader, nsCSSParser::nsCSSParser(mozilla::css::Loader* aLoader,

View file

@ -133,6 +133,11 @@ CSS_PSEUDO_CLASS(mozBrowserFrame, ":-moz-browser-frame",
// matching operation. // matching operation.
CSS_PSEUDO_CLASS(scope, ":scope", 0, "layout.css.scope-pseudo.enabled") 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 // :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. // it doesn't actually get directly matched on in SelectorMatches.
CSS_PSEUDO_CLASS(negation, ":not", 0, "") CSS_PSEUDO_CLASS(negation, ":not", 0, "")

View file

@ -122,7 +122,9 @@ bool
nsCSSPseudoClasses::HasSelectorListArg(Type aType) nsCSSPseudoClasses::HasSelectorListArg(Type aType)
{ {
return HasForgivingSelectorListArg(aType) || return HasForgivingSelectorListArg(aType) ||
aType == Type::negation ||
aType == Type::mozAny || aType == Type::mozAny ||
aType == Type::mozAnyPrivate ||
aType == Type::host || aType == Type::host ||
aType == Type::hostContext; aType == Type::hostContext;
} }
@ -133,6 +135,12 @@ nsCSSPseudoClasses::HasOptionalSelectorListArg(Type aType)
return aType == Type::host; return aType == Type::host;
} }
bool
nsCSSPseudoClasses::IsHiddenFromSerialization(Type aType)
{
return aType == Type::mozAnyPrivate;
}
void void
nsCSSPseudoClasses::PseudoTypeToString(Type aType, nsAString& aString) nsCSSPseudoClasses::PseudoTypeToString(Type aType, nsAString& aString)
{ {

View file

@ -62,6 +62,7 @@ public:
static bool HasForgivingSelectorListArg(Type aType); static bool HasForgivingSelectorListArg(Type aType);
static bool HasSelectorListArg(Type aType); static bool HasSelectorListArg(Type aType);
static bool HasOptionalSelectorListArg(Type aType); static bool HasOptionalSelectorListArg(Type aType);
static bool IsHiddenFromSerialization(Type aType);
static bool IsUserActionPseudoClass(Type aType); static bool IsUserActionPseudoClass(Type aType);
// Should only be used on types other than Count and NotPseudoClass // Should only be used on types other than Count and NotPseudoClass

View file

@ -1952,6 +1952,17 @@ static bool SelectorMatches(Element* aElement,
} }
break; break;
case CSSPseudoClassType::mozAnyPrivate:
{
if (!SelectorListMatches(aElement,
pseudoClass,
aNodeMatchContext,
aTreeMatchContext)) {
return false;
}
}
break;
case CSSPseudoClassType::host: case CSSPseudoClassType::host:
{ {
// In order to match :host, the element must be a shadow root host, // In order to match :host, the element must be a shadow root host,

View file

@ -2556,6 +2556,9 @@ pref("layout.css.prefixes.webkit", true);
// pref is set to false.) // pref is set to false.)
pref("layout.css.prefixes.device-pixel-ratio-webkit", 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? // Is support for the :is() and :where() selectors enabled?
pref("layout.css.is-where-pseudo.enabled", true); pref("layout.css.is-where-pseudo.enabled", true);