mirror of
https://repo.dactyloidae.xyz/Dactyloidae/UXP.git
synced 2026-10-27 01:27:30 +09:00
Issue #2137 - Part 1: Modify :not() selector to accept a complex selector list
This commit is contained in:
parent
2249fbdf49
commit
82fa9fb80b
7 changed files with 83 additions and 35 deletions
|
|
@ -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.
|
||||||
aString.Append(temp);
|
if (!nsCSSPseudoClasses::IsHiddenFromSerialization(list->mType)) {
|
||||||
|
aString.Append(temp);
|
||||||
|
}
|
||||||
if (list->u.mMemory) {
|
if (list->u.mMemory) {
|
||||||
aString.Append(char16_t('('));
|
if (!nsCSSPseudoClasses::IsHiddenFromSerialization(list->mType)) {
|
||||||
|
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,7 +955,9 @@ nsCSSSelector::AppendToStringWithoutCombinatorsOrNegations
|
||||||
list->u.mSelectorList->ToString(tmp, aSheet);
|
list->u.mSelectorList->ToString(tmp, aSheet);
|
||||||
aString.Append(tmp);
|
aString.Append(tmp);
|
||||||
}
|
}
|
||||||
aString.Append(char16_t(')'));
|
if (!nsCSSPseudoClasses::IsHiddenFromSerialization(list->mType)) {
|
||||||
|
aString.Append(char16_t(')'));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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] = {
|
||||||
|
|
@ -6144,7 +6145,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)) &&
|
||||||
|
|
@ -6182,25 +6182,26 @@ CSSParserImpl::ParsePseudoSelector(int32_t& aDataMask,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!parsingPseudoElement &&
|
if (!parsingPseudoElement && isPseudoClass) {
|
||||||
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) {
|
|
||||||
aDataMask |= SEL_MASK_PCLASS;
|
aDataMask |= SEL_MASK_PCLASS;
|
||||||
if (eCSSToken_Function == mToken.mType) {
|
if (eCSSToken_Function == mToken.mType) {
|
||||||
nsSelectorParsingStatus parsingStatus;
|
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 =
|
parsingStatus =
|
||||||
ParsePseudoClassWithIdentArg(aSelector, pseudoClassType);
|
ParsePseudoClassWithIdentArg(aSelector, pseudoClassType);
|
||||||
}
|
}
|
||||||
|
|
@ -6583,8 +6584,6 @@ 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,
|
||||||
|
|
@ -6612,22 +6611,35 @@ 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.
|
// TODO: This should only happen if we don't have a simple selector.
|
||||||
if ((!isForgiving && s->mNext) || s->IsPseudoElement()) {
|
nsCSSSelector* newSel = new nsCSSSelector();
|
||||||
return eSelectorParsingStatus_Error; // our caller calls SkipUntil(')')
|
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
|
// 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)) {
|
||||||
|
|
@ -17891,6 +17903,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,
|
||||||
|
|
|
||||||
|
|
@ -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, "")
|
||||||
|
|
|
||||||
|
|
@ -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)
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
|
|
||||||
|
|
@ -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,
|
||||||
|
|
|
||||||
|
|
@ -2551,6 +2551,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);
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue