diff --git a/dom/base/Element.cpp b/dom/base/Element.cpp index f4ab994e87..99120db433 100644 --- a/dom/base/Element.cpp +++ b/dom/base/Element.cpp @@ -3438,9 +3438,9 @@ Element::Closest(const nsAString& aSelector, ErrorResult& aResult) matchingContext.AddScopeElement(this); for (nsINode* node = this; node; node = node->GetParentNode()) { if (node->IsElement() && - nsCSSRuleProcessor::SelectorListMatches(node->AsElement(), - matchingContext, - selectorList)) { + nsCSSRuleProcessor::RestrictedSelectorListMatches(node->AsElement(), + matchingContext, + selectorList)) { return node->AsElement(); } } @@ -3464,8 +3464,9 @@ Element::Matches(const nsAString& aSelector, ErrorResult& aError) TreeMatchContext::eNeverMatchVisited); matchingContext.SetHasSpecifiedScope(); matchingContext.AddScopeElement(this); - return nsCSSRuleProcessor::SelectorListMatches(this, matchingContext, - selectorList); + return nsCSSRuleProcessor::RestrictedSelectorListMatches(this, + matchingContext, + selectorList); } static const nsAttrValue::EnumTable kCORSAttributeTable[] = { diff --git a/dom/base/nsINode.cpp b/dom/base/nsINode.cpp index db8986c4e8..749a3ee4a2 100644 --- a/dom/base/nsINode.cpp +++ b/dom/base/nsINode.cpp @@ -2879,9 +2879,9 @@ FindMatchingElementsWithId(const nsAString& aId, nsINode* aRoot, // We have an element with the right id and it's a strict descendant // of aRoot. Make sure it really matches the selector. if (!aMatchInfo || - nsCSSRuleProcessor::SelectorListMatches(element, - aMatchInfo->mMatchContext, - aMatchInfo->mSelectorList)) { + nsCSSRuleProcessor::RestrictedSelectorListMatches(element, + aMatchInfo->mMatchContext, + aMatchInfo->mSelectorList)) { aList.AppendElement(element); if (onlyFirstMatch) { return; @@ -2932,9 +2932,9 @@ FindMatchingElements(nsINode* aRoot, nsCSSSelectorList* aSelectorList, T &aList, cur; cur = cur->GetNextNode(aRoot)) { if (cur->IsElement() && - nsCSSRuleProcessor::SelectorListMatches(cur->AsElement(), - matchingContext, - aSelectorList)) { + nsCSSRuleProcessor::RestrictedSelectorListMatches(cur->AsElement(), + matchingContext, + aSelectorList)) { if (onlyFirstMatch) { aList.AppendElement(cur->AsElement()); return; diff --git a/dom/crypto/WebCryptoTask.cpp b/dom/crypto/WebCryptoTask.cpp index 186587454d..4a755edbec 100644 --- a/dom/crypto/WebCryptoTask.cpp +++ b/dom/crypto/WebCryptoTask.cpp @@ -1740,6 +1740,10 @@ private: return NS_ERROR_DOM_SYNTAX_ERR; } + if (pubKey->keyType != rsaKey) { + return NS_ERROR_DOM_DATA_ERR; + } + // Extract relevant information from the public key mModulusLength = 8 * pubKey->u.rsa.modulus.len; if (!mPublicExponent.Assign(&pubKey->u.rsa.publicExponent)) { @@ -1873,6 +1877,10 @@ private: } if (mFormat.EqualsLiteral(WEBCRYPTO_KEY_FORMAT_SPKI)) { + if (pubKey->keyType != ecKey) { + return NS_ERROR_DOM_DATA_ERR; + } + if (!CheckEncodedECParameters(&pubKey->u.ec.DEREncodedParams)) { return NS_ERROR_DOM_OPERATION_ERR; } diff --git a/js/src/vm/ErrorObject.cpp b/js/src/vm/ErrorObject.cpp index 2fa36089ed..7c966e0fe5 100644 --- a/js/src/vm/ErrorObject.cpp +++ b/js/src/vm/ErrorObject.cpp @@ -557,34 +557,30 @@ FindErrorInstanceOrPrototype(JSContext* cx, HandleObject obj, MutableHandleObjec // (new NYI).stack // to continue returning stacks that are useless, but at least don't throw. - RootedObject target(cx, CheckedUnwrap(obj)); - if (!target) { - JS_ReportErrorASCII(cx, "Permission denied to access object"); - return false; - } - - RootedObject proto(cx); - while (!IsErrorProtoKey(StandardProtoKeyOrNull(target))) { - if (!GetPrototype(cx, target, &proto)) - return false; - - if (!proto) { - // We walked the whole prototype chain and did not find an Error - // object. - JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_INCOMPATIBLE_PROTO, - js_Error_str, "(get stack)", obj->getClass()->name); - return false; - } - - target = CheckedUnwrap(proto); + RootedObject curr(cx, obj); + RootedObject target(cx); + do { + target = CheckedUnwrap(curr); if (!target) { JS_ReportErrorASCII(cx, "Permission denied to access object"); return false; } - } + + if (IsErrorProtoKey(StandardProtoKeyOrNull(target))) { + result.set(target); + return true; + } - result.set(target); - return true; + if (!GetPrototype(cx, target, &curr)) { + return false; + } + } while (curr); + + // We walked the whole prototype chain and did not find an Error + // object. + JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_INCOMPATIBLE_PROTO, + js_Error_str, "(get stack)", obj->getClass()->name); + return false; } diff --git a/layout/inspector/inDOMUtils.cpp b/layout/inspector/inDOMUtils.cpp index 800201ce21..f2b52aed21 100644 --- a/layout/inspector/inDOMUtils.cpp +++ b/layout/inspector/inDOMUtils.cpp @@ -465,7 +465,7 @@ inDOMUtils::SelectorMatchesElement(nsIDOMElement* aElement, } // We have a matching pseudo element, now remove it so we can compare - // directly against |element| when proceeding into SelectorListMatches. + // directly against |element| when proceeding into RestrictedSelectorListMatches. // It's OK to do this - we just cloned sel and nothing else is using it. sel->RemoveRightmostSelector(); } @@ -476,8 +476,9 @@ inDOMUtils::SelectorMatchesElement(nsIDOMElement* aElement, nsRuleWalker::eRelevantLinkUnvisited, element->OwnerDoc(), TreeMatchContext::eNeverMatchVisited); - *aMatches = nsCSSRuleProcessor::SelectorListMatches(element, matchingContext, - sel); + *aMatches = nsCSSRuleProcessor::RestrictedSelectorListMatches(element, + matchingContext, + sel); return NS_OK; } diff --git a/layout/style/StyleRule.cpp b/layout/style/StyleRule.cpp index 8fe19bb34a..2f08d88f14 100644 --- a/layout/style/StyleRule.cpp +++ b/layout/style/StyleRule.cpp @@ -149,11 +149,11 @@ nsPseudoClassList::nsPseudoClassList(CSSPseudoClassType aType, mNext(nullptr) { NS_ASSERTION(nsCSSPseudoClasses::HasSelectorListArg(aType) || - nsCSSPseudoClasses::HasOptionalSelectorListArg(aType), + nsCSSPseudoClasses::HasOptionalSelectorListArg(aType), "unexpected pseudo-class"); NS_ASSERTION(aSelectorList, "selector list expected"); MOZ_COUNT_CTOR(nsPseudoClassList); - u.mSelectors = aSelectorList; + u.mSelectorList = aSelectorList; } nsPseudoClassList* @@ -170,7 +170,7 @@ nsPseudoClassList::Clone(bool aDeep) const NS_ASSERTION(nsCSSPseudoClasses::HasSelectorListArg(mType), "unexpected pseudo-class"); // This constructor adopts its selector list argument. - result = new nsPseudoClassList(mType, u.mSelectors->Clone()); + result = new nsPseudoClassList(mType, u.mSelectorList->Clone()); } if (aDeep) @@ -199,7 +199,7 @@ nsPseudoClassList::SizeOfIncludingThis(mozilla::MallocSizeOf aMallocSizeOf) cons } else { NS_ASSERTION(nsCSSPseudoClasses::HasSelectorListArg(p->mType), "unexpected pseudo-class"); - n += p->u.mSelectors->SizeOfIncludingThis(aMallocSizeOf); + n += p->u.mSelectorList->SizeOfIncludingThis(aMallocSizeOf); } p = p->mNext; } @@ -210,7 +210,7 @@ nsPseudoClassList::~nsPseudoClassList(void) { MOZ_COUNT_DTOR(nsPseudoClassList); if (nsCSSPseudoClasses::HasSelectorListArg(mType)) { - delete u.mSelectors; + delete u.mSelectorList; } else if (u.mMemory) { free(u.mMemory); } @@ -537,14 +537,35 @@ int32_t nsCSSSelector::CalcWeightWithoutNegations() const weight += 0x000100; list = list->mNext; } - // FIXME (bug 561154): This is incorrect for :-moz-any(), which isn't - // really a pseudo-class. In order to handle :-moz-any() correctly, - // we need to compute specificity after we match, based on which - // option we matched with (and thus also need to try the - // highest-specificity options first). nsPseudoClassList *plist = mPseudoClassList; while (nullptr != plist) { - weight += 0x000100; + int pseudoClassWeight = 0x000100; + // XXX(franklindm): Check for correctness. + if (nsCSSPseudoClasses::HasSelectorListArg(plist->mType) && + plist->mType != CSSPseudoClassType::mozAny) { + // The specificity of :host() and :host-context is that of a + // pseudo-class, plus the specificity of its argument. + if (plist->mType != CSSPseudoClassType::host && + plist->mType != CSSPseudoClassType::hostContext) { + pseudoClassWeight = 0; + } + // The specificity of the :where() pseudo-class is always zero. + if (plist->mType != CSSPseudoClassType::where) { + // The specificity of the :is() pseudo-class is replaced by the + // specificity of its most specific argument. + nsCSSSelectorList* slist = plist->u.mSelectorList; + while (slist) { + int currentWeight = slist->mSelectors ? + slist->mWeight : + 0; + if (currentWeight > pseudoClassWeight) { + pseudoClassWeight = currentWeight; + } + slist = slist->mNext; + } + } + } + weight += pseudoClassWeight; plist = plist->mNext; } nsAttrSelector* attr = mAttrList; @@ -927,7 +948,7 @@ nsCSSSelector::AppendToStringWithoutCombinatorsOrNegations NS_ASSERTION(nsCSSPseudoClasses::HasSelectorListArg(list->mType), "unexpected pseudo-class"); nsString tmp; - list->u.mSelectors->ToString(tmp, aSheet); + list->u.mSelectorList->ToString(tmp, aSheet); aString.Append(tmp); } aString.Append(char16_t(')')); diff --git a/layout/style/StyleRule.h b/layout/style/StyleRule.h index dbf4e08406..d619b5090b 100644 --- a/layout/style/StyleRule.h +++ b/layout/style/StyleRule.h @@ -77,7 +77,7 @@ public: void* mMemory; // mString and mNumbers use moz_xmalloc/free char16_t* mString; int32_t* mNumbers; - nsCSSSelectorList* mSelectors; + nsCSSSelectorList* mSelectorList; } u; CSSPseudoClassType mType; nsPseudoClassList* mNext; diff --git a/layout/style/nsCSSParser.cpp b/layout/style/nsCSSParser.cpp index 37c06a1883..0d031e9cac 100644 --- a/layout/style/nsCSSParser.cpp +++ b/layout/style/nsCSSParser.cpp @@ -780,7 +780,8 @@ protected: CSSPseudoClassType aType); nsSelectorParsingStatus ParsePseudoClassWithSelectorListArg(nsCSSSelector& aSelector, - CSSPseudoClassType aType); + CSSPseudoClassType aType, + bool aIsForgiving); nsSelectorParsingStatus ParseNegatedSimpleSelector(int32_t& aDataMask, nsCSSSelector& aSelector); @@ -788,9 +789,13 @@ protected: // 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 ParseSelectorGroup(nsCSSSelectorList*& aListHead); - bool ParseSelector(nsCSSSelectorList* aList, char16_t aPrevCombinator); + char16_t aStopChar, + bool aIsForgiving); + bool ParseSelectorGroup(nsCSSSelectorList*& aListHead, + bool aIsForgiving); + bool ParseSelector(nsCSSSelectorList* aList, + char16_t aPrevCombinator, + bool aIsForgiving); enum { eParseDeclaration_InBraces = 1 << 0, @@ -2329,7 +2334,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)); + bool success = ParseSelectorList(*aSelectorList, char16_t(0), false); // We deliberately do not call OUTPUT_ERROR here, because all our // callers map a failure return to a JS exception, and if that JS @@ -5411,7 +5416,7 @@ CSSParserImpl::ParseRuleSet(RuleAppendFunc aAppendFunc, void* aData, nsCSSSelectorList* slist = nullptr; uint32_t linenum, colnum; if (!GetNextTokenLocation(true, &linenum, &colnum) || - !ParseSelectorList(slist, char16_t('{'))) { + !ParseSelectorList(slist, char16_t('{'), false)) { REPORT_UNEXPECTED(PEBadSelectorRSIgnored); OUTPUT_ERROR(); SkipRuleSet(aInsideBraces); @@ -5447,13 +5452,20 @@ CSSParserImpl::ParseRuleSet(RuleAppendFunc aAppendFunc, void* aData, bool CSSParserImpl::ParseSelectorList(nsCSSSelectorList*& aListHead, - char16_t aStopChar) + char16_t aStopChar, + bool aIsForgiving) { nsCSSSelectorList* list = nullptr; - if (! ParseSelectorGroup(list)) { - // must have at least one selector group - aListHead = nullptr; - return false; + if (! ParseSelectorGroup(list, aIsForgiving)) { + if (aIsForgiving) { + // Initialize to an empty list if the first selector group was invalid + // and we're a forgiving selector list. + list = new nsCSSSelectorList(); + } else { + // must have at least one selector group + aListHead = nullptr; + return false; + } } NS_ASSERTION(nullptr != list, "no selector list"); aListHead = list; @@ -5475,11 +5487,22 @@ CSSParserImpl::ParseSelectorList(nsCSSSelectorList*& aListHead, if (',' == tk->mSymbol) { nsCSSSelectorList* newList = nullptr; // Another selector group must follow - if (! ParseSelectorGroup(newList)) { + if (! ParseSelectorGroup(newList, aIsForgiving)) { + // Ignore invalid selectors if we're a forgiving selector list. + if (aIsForgiving) { + continue; + } break; } - // add new list to the end of the selector list - list->mNext = newList; + // 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) { + MOZ_ASSERT(newList->mSelectors, + "replacing empty list head with an empty selector list?"); + aListHead = newList; + } else { + list->mNext = newList; + } list = newList; continue; } else if (aStopChar == tk->mSymbol && aStopChar != char16_t(0)) { @@ -5487,9 +5510,12 @@ CSSParserImpl::ParseSelectorList(nsCSSSelectorList*& aListHead, return true; } } - REPORT_UNEXPECTED_TOKEN(PESelectorListExtra); - UngetToken(); - break; + + if (!aIsForgiving) { + REPORT_UNEXPECTED_TOKEN(PESelectorListExtra); + UngetToken(); + break; + } } delete aListHead; @@ -5509,13 +5535,13 @@ static bool IsUniversalSelector(const nsCSSSelector& aSelector) } bool -CSSParserImpl::ParseSelectorGroup(nsCSSSelectorList*& aList) +CSSParserImpl::ParseSelectorGroup(nsCSSSelectorList*& aList, bool aIsForgiving) { char16_t combinator = 0; nsAutoPtr list(new nsCSSSelectorList()); for (;;) { - if (!ParseSelector(list, combinator)) { + if (!ParseSelector(list, combinator, aIsForgiving)) { return false; } @@ -6148,8 +6174,11 @@ CSSParserImpl::ParsePseudoSelector(int32_t& aDataMask, else { MOZ_ASSERT(nsCSSPseudoClasses::HasSelectorListArg(pseudoClassType), "unexpected pseudo with function token"); + bool isForgiving = + nsCSSPseudoClasses::HasForgivingSelectorListArg(pseudoClassType); parsingStatus = ParsePseudoClassWithSelectorListArg(aSelector, - pseudoClassType); + pseudoClassType, + isForgiving); } if (eSelectorParsingStatus_Continue != parsingStatus) { if (eSelectorParsingStatus_Error == parsingStatus) { @@ -6523,18 +6552,29 @@ CSSParserImpl::ParsePseudoClassWithNthPairArg(nsCSSSelector& aSelector, // CSSParserImpl::nsSelectorParsingStatus CSSParserImpl::ParsePseudoClassWithSelectorListArg(nsCSSSelector& aSelector, - CSSPseudoClassType aType) + CSSPseudoClassType aType, + bool aIsForgiving) { nsAutoPtr slist; - if (! ParseSelectorList(*getter_Transfers(slist), char16_t(')'))) { + if (! ParseSelectorList(*getter_Transfers(slist), char16_t(')'), aIsForgiving)) { + return eSelectorParsingStatus_Error; // our caller calls SkipUntil(')') + } + + if (nsCSSPseudoClasses::HasSingleSelectorArg(aType) && + slist->mNext) { return eSelectorParsingStatus_Error; // our caller calls SkipUntil(')') } - // Check that none of the selectors in the list have combinators or - // pseudo-elements. for (nsCSSSelectorList *l = slist; l; l = l->mNext) { nsCSSSelector *s = l->mSelectors; - if (s->mNext || s->IsPseudoElement()) { + if (s == nullptr) { + MOZ_ASSERT(aIsForgiving, + "unexpected empty selector in unforgiving selector list"); + break; + } + // Check that none of the selectors in the list have combinators or + // pseudo-elements. + if ((!aIsForgiving && s->mNext) || s->IsPseudoElement()) { return eSelectorParsingStatus_Error; // our caller calls SkipUntil(')') } } @@ -6558,7 +6598,8 @@ CSSParserImpl::ParsePseudoClassWithSelectorListArg(nsCSSSelector& aSelector, */ bool CSSParserImpl::ParseSelector(nsCSSSelectorList* aList, - char16_t aPrevCombinator) + char16_t aPrevCombinator, + bool aIsForgiving) { if (! GetToken(true)) { REPORT_UNEXPECTED_EOF(PESelectorEOF); @@ -6632,6 +6673,12 @@ CSSParserImpl::ParseSelector(nsCSSSelectorList* aList, } if (!dataMask) { + // 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) { + return false; + } if (selector->mNext) { REPORT_UNEXPECTED(PESelectorGroupExtraCombinator); } else { diff --git a/layout/style/nsCSSPseudoClassList.h b/layout/style/nsCSSPseudoClassList.h index c57c28bc0b..740ebcc422 100644 --- a/layout/style/nsCSSPseudoClassList.h +++ b/layout/style/nsCSSPseudoClassList.h @@ -74,7 +74,11 @@ CSS_PSEUDO_CLASS(mozEmptyExceptChildrenWithLocalname, ":-moz-empty-except-childr CSS_PSEUDO_CLASS(lang, ":lang", 0, "") CSS_PSEUDO_CLASS(mozBoundElement, ":-moz-bound-element", 0, "") CSS_PSEUDO_CLASS(root, ":root", 0, "") -CSS_PSEUDO_CLASS(any, ":-moz-any", 0, "") +CSS_PSEUDO_CLASS(mozAny, ":-moz-any", 0, "") +CSS_PSEUDO_CLASS(is, ":is", 0, "layout.css.is-where-pseudo.enabled") +CSS_PSEUDO_CLASS(matches, ":matches", 0, "layout.css.is-where-pseudo.enabled") +CSS_PSEUDO_CLASS(any, ":any", 0, "layout.css.is-where-pseudo.enabled") +CSS_PSEUDO_CLASS(where, ":where", 0, "layout.css.is-where-pseudo.enabled") CSS_PSEUDO_CLASS(firstChild, ":first-child", 0, "") CSS_PSEUDO_CLASS(firstNode, ":-moz-first-node", 0, "") diff --git a/layout/style/nsCSSPseudoClasses.cpp b/layout/style/nsCSSPseudoClasses.cpp index a174525b1c..928326e399 100644 --- a/layout/style/nsCSSPseudoClasses.cpp +++ b/layout/style/nsCSSPseudoClasses.cpp @@ -102,6 +102,13 @@ nsCSSPseudoClasses::HasNthPairArg(Type aType) aType == Type::nthLastOfType; } +bool +nsCSSPseudoClasses::HasSingleSelectorArg(Type aType) +{ + return aType == Type::host || + aType == Type::hostContext; +} + void nsCSSPseudoClasses::PseudoTypeToString(Type aType, nsAString& aString) { diff --git a/layout/style/nsCSSPseudoClasses.h b/layout/style/nsCSSPseudoClasses.h index 05f67b05cd..76fcef3f78 100644 --- a/layout/style/nsCSSPseudoClasses.h +++ b/layout/style/nsCSSPseudoClasses.h @@ -58,10 +58,18 @@ public: static Type GetPseudoType(nsIAtom* aAtom, EnabledState aEnabledState); static bool HasStringArg(Type aType); static bool HasNthPairArg(Type aType); + static bool HasSingleSelectorArg(Type aType); + static bool HasForgivingSelectorListArg(Type aType) { + return aType == Type::is || + aType == Type::matches || + aType == Type::any || + aType == Type::where; + } static bool HasSelectorListArg(Type aType) { - return aType == Type::any || - aType == Type::host || - aType == Type::hostContext; + return HasForgivingSelectorListArg(aType) || + aType == Type::mozAny || + aType == Type::host || + aType == Type::hostContext; } static bool HasOptionalSelectorListArg(Type aType) { return aType == Type::host; diff --git a/layout/style/nsCSSRuleProcessor.cpp b/layout/style/nsCSSRuleProcessor.cpp index dbd0e099b0..de4ee0fc3b 100644 --- a/layout/style/nsCSSRuleProcessor.cpp +++ b/layout/style/nsCSSRuleProcessor.cpp @@ -1337,8 +1337,8 @@ struct NodeMatchContext { // node being matched that is itself or an ancestor.) // // Always false when TreeMatchContext::mForStyling is false. (We - // could figure it out for SelectorListMatches, but we're starting - // from the middle of the selector list when doing + // could figure it out for RestrictedSelectorListMatches, but we're + // starting from the middle of the selector list when doing // Has{Attribute,State}DependentStyle, so we can't tell. So when // mForStyling is false, we have to assume we don't know.) const bool mIsRelevantLink; @@ -1640,10 +1640,20 @@ StateSelectorMatches(Element* aElement, return true; } -static bool AnySelectorInArgListMatches(Element* aElement, - nsPseudoClassList* aList, - NodeMatchContext& aNodeMatchContext, - TreeMatchContext& aTreeMatchContext); +static bool SelectorListMatches(Element* aElement, + nsCSSSelectorList* aList, + NodeMatchContext& aNodeMatchContext, + TreeMatchContext& aTreeMatchContext, + SelectorMatchesFlags aSelectorFlags, + bool aIsForgiving = false, + bool aPreventComplexSelectors = false); + +static bool SelectorListMatches(Element* aElement, + nsPseudoClassList* aList, + NodeMatchContext& aNodeMatchContext, + TreeMatchContext& aTreeMatchContext, + bool aIsForgiving = false, + bool aPreventComplexSelectors = false); static bool StateSelectorMatches(Element* aElement, @@ -1907,11 +1917,32 @@ static bool SelectorMatches(Element* aElement, } break; + case CSSPseudoClassType::is: + case CSSPseudoClassType::matches: case CSSPseudoClassType::any: + case CSSPseudoClassType::where: { - if (!AnySelectorInArgListMatches(aElement, pseudoClass, - aNodeMatchContext, - aTreeMatchContext)) { + if (!SelectorListMatches(aElement, + pseudoClass, + aNodeMatchContext, + aTreeMatchContext, + true)) { + return false; + } + } + break; + + case CSSPseudoClassType::mozAny: + { + // XXX: For compatibility, we retain :-moz-any()'s original behavior, + // which is to be unforgiving and reject complex selectors in + // its selector list argument. + if (!SelectorListMatches(aElement, + pseudoClass, + aNodeMatchContext, + aTreeMatchContext, + false, + true)) { return false; } } @@ -1929,20 +1960,23 @@ static bool SelectorMatches(Element* aElement, // selector. // We match automatically if GetParent() and GetShadowRoot() have - // the same result. Without special casing this ahead of all other - // selector matching, it fails. Have not determined the cause. - - if (aElement->GetParent() == aElement->GetShadowRoot()) { + // the same result iff our selector list is empty. Without special + // casing this ahead of all other selector matching, it fails. + // Have not determined the cause. + if (!pseudoClass->u.mSelectorList && + aElement->GetParent() == aElement->GetShadowRoot()) { break; } // Match if any selector in the argument list matches. - + // FIXME: What this effectively does is bypass the "featureless" + // selector check under SelectorMatches. NodeMatchContext nodeContext(EventStates(), - nsCSSRuleProcessor::IsLink(aElement)); - if (AnySelectorInArgListMatches(aElement, pseudoClass, - nodeContext, - aTreeMatchContext)) { + aNodeMatchContext.mIsRelevantLink); + if (SelectorListMatches(aElement, + pseudoClass, + nodeContext, + aTreeMatchContext)) { break; } @@ -1981,9 +2015,10 @@ static bool SelectorMatches(Element* aElement, while (currentElement) { NodeMatchContext nodeContext(EventStates(), nsCSSRuleProcessor::IsLink(currentElement)); - if (AnySelectorInArgListMatches(currentElement, pseudoClass, - nodeContext, - aTreeMatchContext)) { + if (SelectorListMatches(currentElement, + pseudoClass, + nodeContext, + aTreeMatchContext)) { break; } @@ -2373,26 +2408,6 @@ static bool SelectorMatches(Element* aElement, return result; } -static bool AnySelectorInArgListMatches(Element* aElement, - nsPseudoClassList* aList, - NodeMatchContext& aNodeMatchContext, - TreeMatchContext& aTreeMatchContext) -{ - nsCSSSelectorList *l; - for (l = aList->u.mSelectors; l; l = l->mNext) { - nsCSSSelector *s = l->mSelectors; - MOZ_ASSERT(!s->mNext && !s->IsPseudoElement(), - "parser failed"); - if (SelectorMatches( - aElement, s, aNodeMatchContext, aTreeMatchContext, - SelectorMatchesFlags::IS_PSEUDO_CLASS_ARGUMENT)) { - break; - } - } - - return !!l; -} - #undef STATE_CHECK #ifdef DEBUG @@ -2401,7 +2416,7 @@ HasPseudoClassSelectorArgsWithCombinators(nsCSSSelector* aSelector) { for (nsPseudoClassList* p = aSelector->mPseudoClassList; p; p = p->mNext) { if (nsCSSPseudoClasses::HasSelectorListArg(p->mType)) { - for (nsCSSSelectorList* l = p->u.mSelectors; l; l = l->mNext) { + for (nsCSSSelectorList* l = p->u.mSelectorList; l; l = l->mNext) { if (l->mSelectors->mNext) { return true; } @@ -2637,6 +2652,70 @@ SelectorMatchesTree(Element* aPrevElement, return true; // all the selectors matched. } +static bool SelectorListMatches(Element* aElement, + nsCSSSelectorList* aList, + NodeMatchContext& aNodeMatchContext, + TreeMatchContext& aTreeMatchContext, + SelectorMatchesFlags aSelectorFlags, + bool aIsForgiving, + bool aPreventComplexSelectors) +{ + while (aList) { + nsCSSSelector *selector = aList->mSelectors; + // Forgiving selector lists are allowed to be empty, but they + // don't match anything. + if (!selector && aIsForgiving) { + return false; + } + NS_ASSERTION(selector, "Should have *some* selectors"); + NS_ASSERTION(!selector->IsPseudoElement(), "Shouldn't have been called"); + if (aPreventComplexSelectors) { + NS_ASSERTION(!selector->mNext, "Shouldn't have complex selectors"); + } + if (SelectorMatches(aElement, + selector, + aNodeMatchContext, + aTreeMatchContext, + aSelectorFlags)) { + nsCSSSelector* next = selector->mNext; + SelectorMatchesTreeFlags selectorTreeFlags = SelectorMatchesTreeFlags(0); + // Try to look for the closest ancestor link element if we're processing + // the selector list argument of a pseudo-class. + if (!aNodeMatchContext.mIsRelevantLink && + (aSelectorFlags & SelectorMatchesFlags::IS_PSEUDO_CLASS_ARGUMENT)) { + selectorTreeFlags = eLookForRelevantLink; + } + + if (!next || + SelectorMatchesTree(aElement, + next, + aTreeMatchContext, + selectorTreeFlags)) { + return true; + } + } + + aList = aList->mNext; + } + + return false; +} + +static bool SelectorListMatches(Element* aElement, + nsPseudoClassList* aList, + NodeMatchContext& aNodeMatchContext, + TreeMatchContext& aTreeMatchContext, + bool aIsForgiving, + bool aPreventComplexSelectors) +{ + return SelectorListMatches(aElement, + aList->u.mSelectorList, + aNodeMatchContext, + aTreeMatchContext, + SelectorMatchesFlags::IS_PSEUDO_CLASS_ARGUMENT, + aIsForgiving); +} + static inline void ContentEnumFunc(const RuleValue& value, nsCSSSelector* aSelector, ElementDependentRuleProcessorData* data, NodeMatchContext& nodeContext, @@ -3517,13 +3596,11 @@ AddSelector(RuleCascadeData* aCascade, } } - // Recur through any :-moz-any or :host-context selectors + // Recur through any pseudo-class that has a selector list argument. for (nsPseudoClassList* pseudoClass = negation->mPseudoClassList; pseudoClass; pseudoClass = pseudoClass->mNext) { - if (pseudoClass->mType == CSSPseudoClassType::any || - pseudoClass->mType == CSSPseudoClassType::host || - pseudoClass->mType == CSSPseudoClassType::hostContext) { - for (nsCSSSelectorList *l = pseudoClass->u.mSelectors; l; l = l->mNext) { + if (nsCSSPseudoClasses::HasSelectorListArg(pseudoClass->mType)) { + for (nsCSSSelectorList *l = pseudoClass->u.mSelectorList; l; l = l->mNext) { nsCSSSelector *s = l->mSelectors; if (!AddSelector(aCascade, aSelectorInTopLevel, s, aRightmostSelector)) { @@ -4075,33 +4152,20 @@ nsCSSRuleProcessor::RefreshRuleCascade(nsPresContext* aPresContext) } /* static */ bool -nsCSSRuleProcessor::SelectorListMatches(Element* aElement, - TreeMatchContext& aTreeMatchContext, - nsCSSSelectorList* aSelectorList) +nsCSSRuleProcessor::RestrictedSelectorListMatches(Element* aElement, + TreeMatchContext& aTreeMatchContext, + nsCSSSelectorList* aSelectorList) { MOZ_ASSERT(!aTreeMatchContext.mForScopedStyle, "mCurrentStyleScope will need to be saved and restored after the " "SelectorMatchesTree call"); - while (aSelectorList) { - nsCSSSelector* sel = aSelectorList->mSelectors; - NS_ASSERTION(sel, "Should have *some* selectors"); - NS_ASSERTION(!sel->IsPseudoElement(), "Shouldn't have been called"); - NodeMatchContext nodeContext(EventStates(), false); - if (SelectorMatches(aElement, sel, nodeContext, aTreeMatchContext, - SelectorMatchesFlags::NONE)) { - nsCSSSelector* next = sel->mNext; - if (!next || - SelectorMatchesTree(aElement, next, aTreeMatchContext, - SelectorMatchesTreeFlags(0))) { - return true; - } - } - - aSelectorList = aSelectorList->mNext; - } - - return false; + NodeMatchContext nodeContext(EventStates(), false); + return SelectorListMatches(aElement, + aSelectorList, + nodeContext, + aTreeMatchContext, + SelectorMatchesFlags::NONE); } void diff --git a/layout/style/nsCSSRuleProcessor.h b/layout/style/nsCSSRuleProcessor.h index e207a71afe..af077f842b 100644 --- a/layout/style/nsCSSRuleProcessor.h +++ b/layout/style/nsCSSRuleProcessor.h @@ -92,9 +92,9 @@ public: * include any pseudo-element selectors. aSelectorList is allowed * to be null; in this case false will be returned. */ - static bool SelectorListMatches(mozilla::dom::Element* aElement, - TreeMatchContext& aTreeMatchContext, - nsCSSSelectorList* aSelectorList); + static bool RestrictedSelectorListMatches(mozilla::dom::Element* aElement, + TreeMatchContext& aTreeMatchContext, + nsCSSSelectorList* aSelectorList); /* * Helper to get the content state for a content node. This may be diff --git a/mailnews/base/prefs/content/accountcreation/emailWizard.js b/mailnews/base/prefs/content/accountcreation/emailWizard.js index 2e4a44e2a0..5a594b16f7 100644 --- a/mailnews/base/prefs/content/accountcreation/emailWizard.js +++ b/mailnews/base/prefs/content/accountcreation/emailWizard.js @@ -1006,6 +1006,50 @@ EmailConfigWizard.prototype = this.validateManualEditComplete(); }, + /** + * Checks whether OAuth2 is supported by current incoming hostname. + */ + checkIncomingSupportsOAuth2 : function() { +#ifdef MOZ_MAILNEWS_OAUTH2 + var config = this.getUserConfig(); + + // If the hostname supports OAuth2 and imap is enabled, enable OAuth2. + let iDetails = OAuth2Providers.getHostnameDetails(config.incoming.hostname); + gEmailWizardLogger.info("OAuth2 details for incoming hostname " + + config.incoming.hostname + " is " + iDetails); + e("in-authMethod-oauth2").hidden = !(iDetails && e("incoming_protocol").value == 1); + if (!e("in-authMethod-oauth2").hidden) { + config.oauthSettings = {}; + [config.oauthSettings.issuer, config.oauthSettings.scope] = iDetails; + // oauthsettings are not stored nor changable in the user interface, so just + // store them in the base configuration. + this._currentConfig.oauthSettings = config.oauthSettings; + } +#endif + }, + + /** + * Checks whether OAuth2 is supported by current outgoing hostname. + */ + checkOutgoingSupportsOAuth2 : function() { +#ifdef MOZ_MAILNEWS_OAUTH2 + var config = this.getUserConfig(); + + // If the hostname supports OAuth2 and imap is enabled, enable OAuth2. + let oDetails = OAuth2Providers.getHostnameDetails(config.outgoing.hostname); + gEmailWizardLogger.info("OAuth2 details for outgoing hostname " + + config.outgoing.hostname + " is " + oDetails); + e("out-authMethod-oauth2").hidden = !oDetails; + if (!e("out-authMethod-oauth2").hidden) { + config.oauthSettings = {}; + [config.oauthSettings.issuer, config.oauthSettings.scope] = oDetails; + // oauthsettings are not stored nor changable in the user interface, so just + // store them in the base configuration. + this._currentConfig.oauthSettings = config.oauthSettings; + } +#endif + }, + /** * Fills the manual edit textfields with the provided config. * @param config {AccountConfig} The config to present to user @@ -1034,20 +1078,7 @@ EmailConfigWizard.prototype = } this.fillPortDropdown(config.incoming.type); -#ifdef MOZ_MAILNEWS_OAUTH2 - // If the hostname supports OAuth2 and imap is enabled, enable OAuth2. - let iDetails = OAuth2Providers.getHostnameDetails(config.incoming.hostname); - gEmailWizardLogger.info("OAuth2 details for incoming hostname " + - config.incoming.hostname + " is " + iDetails); - e("in-authMethod-oauth2").hidden = !(iDetails && e("incoming_protocol").value == 1); - if (!e("in-authMethod-oauth2").hidden) { - config.oauthSettings = {}; - [config.oauthSettings.issuer, config.oauthSettings.scope] = iDetails; - // oauthsettings are not stored nor changable in the user interface, so just - // store them in the base configuration. - this._currentConfig.oauthSettings = config.oauthSettings; - } -#endif + this.checkIncomingSupportsOAuth2(); // outgoing server e("outgoing_hostname").value = config.outgoing.hostname; @@ -1065,20 +1096,7 @@ EmailConfigWizard.prototype = this.adjustOutgoingPortToSSLAndProtocol(config); } -#ifdef MOZ_MAILNEWS_OAUTH2 - // If the hostname supports OAuth2 and imap is enabled, enable OAuth2. - let oDetails = OAuth2Providers.getHostnameDetails(config.outgoing.hostname); - gEmailWizardLogger.info("OAuth2 details for outgoing hostname " + - config.outgoing.hostname + " is " + oDetails); - e("out-authMethod-oauth2").hidden = !oDetails; - if (!e("out-authMethod-oauth2").hidden) { - config.oauthSettings = {}; - [config.oauthSettings.issuer, config.oauthSettings.scope] = oDetails; - // oauthsettings are not stored nor changable in the user interface, so just - // store them in the base configuration. - this._currentConfig.oauthSettings = config.oauthSettings; - } -#endif + this.checkOutgoingSupportsOAuth2(); // populate fields even if existingServerKey, in case user changes back if (config.outgoing.existingServerKey) { diff --git a/mailnews/base/prefs/content/accountcreation/emailWizard.xul b/mailnews/base/prefs/content/accountcreation/emailWizard.xul index 261545671e..f61cd509ea 100644 --- a/mailnews/base/prefs/content/accountcreation/emailWizard.xul +++ b/mailnews/base/prefs/content/accountcreation/emailWizard.xul @@ -276,6 +276,7 @@ diff --git a/modules/libpref/init/all.js b/modules/libpref/init/all.js index 85a1aee4cb..47c6348128 100644 --- a/modules/libpref/init/all.js +++ b/modules/libpref/init/all.js @@ -2558,6 +2558,9 @@ pref("layout.css.prefixes.webkit", true); // pref is set to false.) pref("layout.css.prefixes.device-pixel-ratio-webkit", false); +// Is support for the :is() and :where() selectors enabled? +pref("layout.css.is-where-pseudo.enabled", true); + // Is support for the :scope selector enabled? pref("layout.css.scope-pseudo.enabled", true);