diff options
-rw-r--r-- | dom/xbl/nsBindingManager.cpp | 2 | ||||
-rw-r--r-- | layout/style/nsCSSRuleProcessor.cpp | 51 | ||||
-rw-r--r-- | layout/style/nsRuleProcessorData.h | 5 |
3 files changed, 43 insertions, 15 deletions
diff --git a/dom/xbl/nsBindingManager.cpp b/dom/xbl/nsBindingManager.cpp index c6dc58ec89..b50c86c002 100644 --- a/dom/xbl/nsBindingManager.cpp +++ b/dom/xbl/nsBindingManager.cpp @@ -713,9 +713,11 @@ nsBindingManager::WalkRules(nsIStyleRuleProcessor::EnumFunc aFunc, nsXBLBinding* binding = stack.ElementAt(index); stack.RemoveElementAt(index); + aData->mTreeMatchContext.mForAssignedSlot = true; aData->mTreeMatchContext.mIsTopmostScope = (index == 0); binding->WalkRules(aFunc, aData); } + aData->mTreeMatchContext.mForAssignedSlot = false; aData->mTreeMatchContext.mRestrictToSlottedPseudo = false; } diff --git a/layout/style/nsCSSRuleProcessor.cpp b/layout/style/nsCSSRuleProcessor.cpp index a13b35214d..ff8b8ec032 100644 --- a/layout/style/nsCSSRuleProcessor.cpp +++ b/layout/style/nsCSSRuleProcessor.cpp @@ -48,6 +48,7 @@ #include "nsCSSRules.h" #include "nsStyleSet.h" #include "mozilla/dom/Element.h" +#include "mozilla/dom/HTMLSlotElement.h" #include "mozilla/dom/ShadowRoot.h" #include "nsNthIndexCache.h" #include "mozilla/ArrayUtils.h" @@ -684,6 +685,7 @@ void RuleHash::EnumerateAllRules(Element* aElement, ElementDependentRuleProcesso filter->AssertHasAllAncestors(aElement); } #endif + bool isForAssignedSlot = aData->mTreeMatchContext.mForAssignedSlot; // Merge the lists while there are still multiple lists to merge. while (valueCount > 1) { int32_t valueIndex = 0; @@ -696,6 +698,7 @@ void RuleHash::EnumerateAllRules(Element* aElement, ElementDependentRuleProcesso } } const RuleValue *cur = mEnumList[valueIndex].mCurValue; + aData->mTreeMatchContext.mForAssignedSlot = isForAssignedSlot; ContentEnumFunc(*cur, cur->mSelector, aData, aNodeContext, filter); cur++; if (cur == mEnumList[valueIndex].mEnd) { @@ -709,6 +712,7 @@ void RuleHash::EnumerateAllRules(Element* aElement, ElementDependentRuleProcesso for (const RuleValue *value = mEnumList[0].mCurValue, *end = mEnumList[0].mEnd; value != end; ++value) { + aData->mTreeMatchContext.mForAssignedSlot = isForAssignedSlot; ContentEnumFunc(*value, value->mSelector, aData, aNodeContext, filter); } } @@ -1706,24 +1710,29 @@ static bool SelectorMatches(Element* aElement, return false; } + Element* targetElement = aElement; + if (aTreeMatchContext.mForAssignedSlot) { + targetElement = aElement->GetAssignedSlot()->AsElement(); + } + // namespace/tag match // optimization : bail out early if we can if ((kNameSpaceID_Unknown != aSelector->mNameSpace && - aElement->GetNameSpaceID() != aSelector->mNameSpace)) + targetElement->GetNameSpaceID() != aSelector->mNameSpace)) return false; if (aSelector->mLowercaseTag) { nsIAtom* selectorTag = - (aTreeMatchContext.mIsHTMLDocument && aElement->IsHTMLElement()) ? + (aTreeMatchContext.mIsHTMLDocument && targetElement->IsHTMLElement()) ? aSelector->mLowercaseTag : aSelector->mCasedTag; - if (selectorTag != aElement->NodeInfo()->NameAtom()) { + if (selectorTag != targetElement->NodeInfo()->NameAtom()) { return false; } } nsAtomList* IDList = aSelector->mIDList; if (IDList) { - nsIAtom* id = aElement->GetID(); + nsIAtom* id = targetElement->GetID(); if (id) { // case sensitivity: bug 93371 const bool isCaseSensitive = @@ -1758,7 +1767,7 @@ static bool SelectorMatches(Element* aElement, nsAtomList* classList = aSelector->mClassList; if (classList) { // test for class match - const nsAttrValue *elementClasses = aElement->GetClasses(); + const nsAttrValue *elementClasses = targetElement->GetClasses(); if (!elementClasses) { // Element has no classes but we have a class selector return false; @@ -1948,6 +1957,10 @@ static bool SelectorMatches(Element* aElement, case CSSPseudoClassType::slotted: { + if (aTreeMatchContext.mForAssignedSlot) { + aTreeMatchContext.mForAssignedSlot = false; + } + // Slottables cannot be matched from the outer tree. if (isOutsideShadowTree) { return false; @@ -2349,7 +2362,7 @@ static bool SelectorMatches(Element* aElement, bool result = true; if (aSelector->mAttrList) { // test for attribute match - if (!aElement->HasAttrs()) { + if (!targetElement->HasAttrs()) { // if no attributes on the content, no match return false; } else { @@ -2359,7 +2372,7 @@ static bool SelectorMatches(Element* aElement, do { bool isHTML = - (aTreeMatchContext.mIsHTMLDocument && aElement->IsHTMLElement()); + (aTreeMatchContext.mIsHTMLDocument && targetElement->IsHTMLElement()); matchAttribute = isHTML ? attr->mLowercaseAttr : attr->mCasedAttr; if (attr->mNameSpace == kNameSpaceID_Unknown) { // Attr selector with a wildcard namespace. We have to examine all @@ -2371,7 +2384,7 @@ static bool SelectorMatches(Element* aElement, // actually has attributes in), short-circuiting if we ever match. result = false; const nsAttrName* attrName; - for (uint32_t i = 0; (attrName = aElement->GetAttrNameAt(i)); ++i) { + for (uint32_t i = 0; (attrName = targetElement->GetAttrNameAt(i)); ++i) { if (attrName->LocalName() != matchAttribute) { continue; } @@ -2382,7 +2395,7 @@ static bool SelectorMatches(Element* aElement, #ifdef DEBUG bool hasAttr = #endif - aElement->GetAttr(attrName->NamespaceID(), + targetElement->GetAttr(attrName->NamespaceID(), attrName->LocalName(), value); NS_ASSERTION(hasAttr, "GetAttrNameAt lied"); result = AttrMatchesValue(attr, value, isHTML); @@ -2400,12 +2413,12 @@ static bool SelectorMatches(Element* aElement, } else if (attr->mFunction == NS_ATTR_FUNC_EQUALS) { result = - aElement-> + targetElement-> AttrValueIs(attr->mNameSpace, matchAttribute, attr->mValue, attr->IsValueCaseSensitive(isHTML) ? eCaseMatters : eIgnoreCase); } - else if (!aElement->HasAttr(attr->mNameSpace, matchAttribute)) { + else if (!targetElement->HasAttr(attr->mNameSpace, matchAttribute)) { result = false; } else if (attr->mFunction != NS_ATTR_FUNC_SET) { @@ -2413,7 +2426,7 @@ static bool SelectorMatches(Element* aElement, #ifdef DEBUG bool hasAttr = #endif - aElement->GetAttr(attr->mNameSpace, matchAttribute, value); + targetElement->GetAttr(attr->mNameSpace, matchAttribute, value); NS_ASSERTION(hasAttr, "HasAttr lied"); result = AttrMatchesValue(attr, value, isHTML); } @@ -2428,7 +2441,7 @@ static bool SelectorMatches(Element* aElement, for (nsCSSSelector *negation = aSelector->mNegations; result && negation; negation = negation->mNegations) { bool dependence = false; - result = !SelectorMatches(aElement, negation, aNodeMatchContext, + result = !SelectorMatches(targetElement, negation, aNodeMatchContext, aTreeMatchContext, SelectorMatchesFlags::IS_PSEUDO_CLASS_ARGUMENT, &dependence); @@ -2822,7 +2835,9 @@ void ContentEnumFunc(const RuleValue& value, nsCSSSelector* aSelector, if (nodeContext.mIsRelevantLink) { data->mTreeMatchContext.SetHaveRelevantLink(); } - if (ancestorFilter && + // XXX: Ignore the ancestor filter if we're testing the assigned slot. + bool useAncestorFilter = !(data->mTreeMatchContext.mForAssignedSlot); + if (useAncestorFilter && ancestorFilter && !ancestorFilter->MightHaveMatchingAncestor<RuleValue::eMaxAncestorHashes>( value.mAncestorSelectorHashes)) { // We won't match; nothing else to do here @@ -2894,7 +2909,13 @@ nsCSSRuleProcessor::RulesMatching(ElementRuleProcessorData *aData) NodeMatchContext nodeContext(EventStates(), nsCSSRuleProcessor::IsLink(aData->mElement), aData->mElementIsFeatureless); - cascade->mRuleHash.EnumerateAllRules(aData->mElement, aData, nodeContext); + // Test against the assigned slot rather than the slottable if we're + // matching the ::slotted() pseudo. + Element* targetElement = aData->mElement; + if (aData->mTreeMatchContext.mForAssignedSlot) { + targetElement = aData->mElement->GetAssignedSlot()->AsElement(); + } + cascade->mRuleHash.EnumerateAllRules(targetElement, aData, nodeContext); } } diff --git a/layout/style/nsRuleProcessorData.h b/layout/style/nsRuleProcessorData.h index 07c885994f..94ec400cfc 100644 --- a/layout/style/nsRuleProcessorData.h +++ b/layout/style/nsRuleProcessorData.h @@ -409,6 +409,10 @@ struct MOZ_STACK_CLASS TreeMatchContext { // Whether we're currently in the topmost scope for shadow DOM. bool mIsTopmostScope; + // Whether we're testing for the assigned slot instead of the slottable + // when matching type/class/ID/attribute. + bool mForAssignedSlot; + enum MatchVisited { eNeverMatchVisited, eMatchVisitedDefault @@ -444,6 +448,7 @@ struct MOZ_STACK_CLASS TreeMatchContext { , mForScopedStyle(false) , mCurrentStyleScope(nullptr) , mIsTopmostScope(false) + , mForAssignedSlot(false) { if (aMatchVisited != eNeverMatchVisited) { nsILoadContext* loadContext = mDocument->GetLoadContext(); |