diff --git a/layout/style/nsCSSRuleProcessor.cpp b/layout/style/nsCSSRuleProcessor.cpp index 0326faceefb4..1204ac16b76d 100644 --- a/layout/style/nsCSSRuleProcessor.cpp +++ b/layout/style/nsCSSRuleProcessor.cpp @@ -727,12 +727,15 @@ struct RuleCascadeData { { PL_DHashTableInit(&mAttributeSelectors, &AttributeSelectorOps, nsnull, sizeof(AttributeSelectorEntry), 16); + PL_DHashTableInit(&mAnonBoxRules, &RuleHash_TagTable_Ops, nsnull, + sizeof(RuleHashTagTableEntry), 16); memset(mPseudoElementRuleHashes, 0, sizeof(mPseudoElementRuleHashes)); } ~RuleCascadeData() { PL_DHashTableFinish(&mAttributeSelectors); + PL_DHashTableFinish(&mAnonBoxRules); for (PRUint32 i = 0; i < NS_ARRAY_LENGTH(mPseudoElementRuleHashes); ++i) { delete mPseudoElementRuleHashes[i]; } @@ -744,6 +747,7 @@ struct RuleCascadeData { nsTArray mClassSelectors; nsTArray mIDSelectors; PLDHashTable mAttributeSelectors; + PLDHashTable mAnonBoxRules; nsTArray mFontFaceRules; @@ -2079,6 +2083,32 @@ nsCSSRuleProcessor::RulesMatching(PseudoElementRuleProcessorData* aData) return NS_OK; } +NS_IMETHODIMP +nsCSSRuleProcessor::RulesMatching(AnonBoxRuleProcessorData* aData) +{ + RuleCascadeData* cascade = GetRuleCascade(aData->mPresContext); + + if (cascade && cascade->mAnonBoxRules.entryCount) { + RuleHashTagTableEntry* entry = static_cast + (PL_DHashTableOperate(&cascade->mAnonBoxRules, aData->mPseudoTag, + PL_DHASH_LOOKUP)); + if (PL_DHASH_ENTRY_IS_BUSY(entry)) { + for (RuleValue *value = entry->mRules; value; value = value->mNext) { + // for performance, require that every implementation of + // nsICSSStyleRule return the same pointer for nsIStyleRule (why + // would anything multiply inherit nsIStyleRule anyway?) +#ifdef DEBUG + nsCOMPtr iRule = do_QueryInterface(value->mRule); + NS_ASSERTION(static_cast(value->mRule) == iRule.get(), + "Please fix QI so this performance optimization is valid"); +#endif + aData->mRuleWalker->Forward(static_cast(value->mRule)); + } + } + } + return NS_OK; +} + static void PseudoEnumFunc(nsICSSStyleRule* aRule, nsCSSSelector* aSelector, void* aData) { @@ -2418,6 +2448,18 @@ AddRule(RuleValue* aRuleInfo, void* aCascade) "Unexpected mNext combinator"); aRuleInfo->mSelector = aRuleInfo->mSelector->mNext; ruleHash->PrependRule(aRuleInfo); + } else if (pseudoType == nsCSSPseudoElements::ePseudo_AnonBox) { + RuleHashTagTableEntry *entry = static_cast + (PL_DHashTableOperate(&cascade->mAnonBoxRules, + aRuleInfo->mSelector->mLowercaseTag, + PL_DHASH_ADD)); + if (!entry) + return PR_FALSE; + + entry->mTag = aRuleInfo->mSelector->mLowercaseTag; + // Index doesn't matter here, since we'll just be walking these + // rules in order; just pass 0. + entry->mRules = aRuleInfo->Add(0, entry->mRules); } else { cascade->mRuleHash.PrependRule(aRuleInfo); } diff --git a/layout/style/nsCSSRuleProcessor.h b/layout/style/nsCSSRuleProcessor.h index f6c491514c09..e3b2626e657a 100644 --- a/layout/style/nsCSSRuleProcessor.h +++ b/layout/style/nsCSSRuleProcessor.h @@ -93,6 +93,8 @@ public: NS_IMETHOD RulesMatching(PseudoElementRuleProcessorData* aData); + NS_IMETHOD RulesMatching(AnonBoxRuleProcessorData* aData); + NS_IMETHOD RulesMatching(PseudoRuleProcessorData* aData); NS_IMETHOD HasStateDependentStyle(StateRuleProcessorData* aData, diff --git a/layout/style/nsHTMLCSSStyleSheet.cpp b/layout/style/nsHTMLCSSStyleSheet.cpp index 2005e44d8100..119cf1950671 100644 --- a/layout/style/nsHTMLCSSStyleSheet.cpp +++ b/layout/style/nsHTMLCSSStyleSheet.cpp @@ -91,6 +91,8 @@ public: NS_IMETHOD RulesMatching(PseudoElementRuleProcessorData* aData); + NS_IMETHOD RulesMatching(AnonBoxRuleProcessorData* aData); + NS_IMETHOD RulesMatching(PseudoRuleProcessorData* aData); NS_IMETHOD HasStateDependentStyle(StateRuleProcessorData* aData, @@ -164,6 +166,12 @@ HTMLCSSStyleSheetImpl::RulesMatching(PseudoElementRuleProcessorData* aData) return NS_OK; } +NS_IMETHODIMP +HTMLCSSStyleSheetImpl::RulesMatching(AnonBoxRuleProcessorData* aData) +{ + return NS_OK; +} + NS_IMETHODIMP HTMLCSSStyleSheetImpl::RulesMatching(PseudoRuleProcessorData* aData) { diff --git a/layout/style/nsHTMLStyleSheet.cpp b/layout/style/nsHTMLStyleSheet.cpp index 1c8143432c22..2183bdf1081c 100644 --- a/layout/style/nsHTMLStyleSheet.cpp +++ b/layout/style/nsHTMLStyleSheet.cpp @@ -569,7 +569,7 @@ nsHTMLStyleSheet::RulesMatching(PseudoElementRuleProcessorData* aData) } NS_IMETHODIMP -nsHTMLStyleSheet::RulesMatching(PseudoRuleProcessorData* aData) +nsHTMLStyleSheet::RulesMatching(AnonBoxRuleProcessorData* aData) { nsIAtom* pseudoTag = aData->mPseudoTag; if (pseudoTag == nsCSSAnonBoxes::tableCol) { @@ -581,6 +581,12 @@ nsHTMLStyleSheet::RulesMatching(PseudoRuleProcessorData* aData) return NS_OK; } +NS_IMETHODIMP +nsHTMLStyleSheet::RulesMatching(PseudoRuleProcessorData* aData) +{ + return NS_OK; +} + // nsIStyleSheet api NS_IMETHODIMP diff --git a/layout/style/nsHTMLStyleSheet.h b/layout/style/nsHTMLStyleSheet.h index ef675b9e954e..46b69abf7c9b 100644 --- a/layout/style/nsHTMLStyleSheet.h +++ b/layout/style/nsHTMLStyleSheet.h @@ -80,6 +80,7 @@ public: // nsIStyleRuleProcessor API NS_IMETHOD RulesMatching(ElementRuleProcessorData* aData); NS_IMETHOD RulesMatching(PseudoElementRuleProcessorData* aData); + NS_IMETHOD RulesMatching(AnonBoxRuleProcessorData* aData); NS_IMETHOD RulesMatching(PseudoRuleProcessorData* aData); NS_IMETHOD HasStateDependentStyle(StateRuleProcessorData* aData, nsReStyleHint* aResult); diff --git a/layout/style/nsIStyleRuleProcessor.h b/layout/style/nsIStyleRuleProcessor.h index 98b712970b6d..8acba443e7b4 100644 --- a/layout/style/nsIStyleRuleProcessor.h +++ b/layout/style/nsIStyleRuleProcessor.h @@ -52,6 +52,7 @@ struct RuleProcessorData; struct ElementRuleProcessorData; struct PseudoElementRuleProcessorData; +struct AnonBoxRuleProcessorData; struct PseudoRuleProcessorData; struct StateRuleProcessorData; struct AttributeRuleProcessorData; @@ -92,6 +93,11 @@ public: */ NS_IMETHOD RulesMatching(PseudoElementRuleProcessorData* aData) = 0; + /** + * Just like the previous |RulesMatching|, except for a given anonymous box. + */ + NS_IMETHOD RulesMatching(AnonBoxRuleProcessorData* aData) = 0; + /** * Just like the previous |RulesMatching|, except for a given content * node and pseudo. diff --git a/layout/style/nsRuleProcessorData.h b/layout/style/nsRuleProcessorData.h index 3f54da5a3b04..844c153e10a0 100644 --- a/layout/style/nsRuleProcessorData.h +++ b/layout/style/nsRuleProcessorData.h @@ -193,6 +193,24 @@ struct PseudoElementRuleProcessorData : public RuleProcessorData { nsCSSPseudoElements::Type mPseudoType; }; +struct AnonBoxRuleProcessorData { + AnonBoxRuleProcessorData(nsPresContext* aPresContext, + nsIAtom* aPseudoTag, + nsRuleWalker* aRuleWalker) + : mPresContext(aPresContext), + mPseudoTag(aPseudoTag), + mRuleWalker(aRuleWalker) + { + NS_PRECONDITION(mPresContext, "Must have prescontext"); + NS_PRECONDITION(aPseudoTag, "Must have pseudo tag"); + NS_PRECONDITION(aRuleWalker, "Must have rule walker"); + } + + nsPresContext* mPresContext; + nsIAtom* mPseudoTag; + nsRuleWalker* mRuleWalker; +}; + struct PseudoRuleProcessorData : public RuleProcessorData { PseudoRuleProcessorData(nsPresContext* aPresContext, nsIContent* aParentContent, diff --git a/layout/style/nsStyleSet.cpp b/layout/style/nsStyleSet.cpp index 9302dc0a433b..718998247cf3 100644 --- a/layout/style/nsStyleSet.cpp +++ b/layout/style/nsStyleSet.cpp @@ -531,7 +531,8 @@ nsStyleSet::AssertNoCSSRules(nsRuleNode* aCurrLevelNode, // Enumerate the rules in a way that cares about the order of the rules. void nsStyleSet::FileRules(nsIStyleRuleProcessor::EnumFunc aCollectorFunc, - RuleProcessorData* aData, nsRuleWalker* aRuleWalker) + void* aData, nsIContent* aContent, + nsRuleWalker* aRuleWalker) { // Cascading order: // [least important] @@ -564,7 +565,7 @@ nsStyleSet::FileRules(nsIStyleRuleProcessor::EnumFunc aCollectorFunc, aRuleWalker->SetLevel(eUserSheet, PR_FALSE, PR_TRUE); PRBool skipUserStyles = - aData->mContent && aData->mContent->IsInNativeAnonymousSubtree(); + aContent && aContent->IsInNativeAnonymousSubtree(); if (!skipUserStyles && mRuleProcessors[eUserSheet]) // NOTE: different (*aCollectorFunc)(mRuleProcessors[eUserSheet], aData); nsRuleNode* lastUserRN = aRuleWalker->GetCurrentNode(); @@ -577,9 +578,11 @@ nsStyleSet::FileRules(nsIStyleRuleProcessor::EnumFunc aCollectorFunc, aRuleWalker->SetLevel(eDocSheet, PR_FALSE, PR_TRUE); PRBool cutOffInheritance = PR_FALSE; - if (mBindingManager) { + if (mBindingManager && aContent) { // We can supply additional document-level sheets that should be walked. - mBindingManager->WalkRules(aCollectorFunc, aData, &cutOffInheritance); + mBindingManager->WalkRules(aCollectorFunc, + static_cast(aData), + &cutOffInheritance); } if (!skipUserStyles && !cutOffInheritance && mRuleProcessors[eDocSheet]) // NOTE: different @@ -746,7 +749,7 @@ nsStyleSet::ResolveStyleFor(nsIContent* aContent, if (aContent && presContext) { nsRuleWalker ruleWalker(mRuleTree); ElementRuleProcessorData data(presContext, aContent, &ruleWalker); - FileRules(EnumRulesMatching, &data, &ruleWalker); + FileRules(EnumRulesMatching, &data, aContent, &ruleWalker); result = GetContext(presContext, aParentContext, ruleWalker.GetCurrentNode(), nsnull, nsCSSPseudoElements::ePseudo_NotPseudoElement).get(); @@ -849,7 +852,7 @@ nsStyleSet::ResolvePseudoStyleFor(nsIContent* aParentContent, nsRuleWalker ruleWalker(mRuleTree); PseudoRuleProcessorData data(presContext, aParentContent, aPseudoTag, aComparator, &ruleWalker); - FileRules(EnumPseudoRulesMatching, &data, &ruleWalker); + FileRules(EnumPseudoRulesMatching, &data, aParentContent, &ruleWalker); result = GetContext(presContext, aParentContext, ruleWalker.GetCurrentNode(), aPseudoTag, @@ -887,7 +890,7 @@ nsStyleSet::ResolvePseudoElementStyle(nsIContent* aParentContent, PseudoElementRuleProcessorData data(presContext, aParentContent, &ruleWalker, aType); WalkRestrictionRule(aType, &ruleWalker); - FileRules(EnumPseudoElementRulesMatching, &data, &ruleWalker); + FileRules(EnumPseudoElementRulesMatching, &data, aParentContent, &ruleWalker); return GetContext(presContext, aParentContext, ruleWalker.GetCurrentNode(), nsCSSPseudoElements::GetPseudoAtom(aType), aType); @@ -916,7 +919,7 @@ nsStyleSet::ProbePseudoElementStyle(nsIContent* aParentContent, WalkRestrictionRule(aType, &ruleWalker); // not the root if there was a restriction rule nsRuleNode *adjustedRoot = ruleWalker.GetCurrentNode(); - FileRules(EnumPseudoElementRulesMatching, &data, &ruleWalker); + FileRules(EnumPseudoElementRulesMatching, &data, aParentContent, &ruleWalker); nsRuleNode *ruleNode = ruleWalker.GetCurrentNode(); if (ruleNode == adjustedRoot) { @@ -944,6 +947,40 @@ nsStyleSet::ProbePseudoElementStyle(nsIContent* aParentContent, return result.forget(); } +static PRBool +EnumAnonBoxRulesMatching(nsIStyleRuleProcessor* aProcessor, void* aData) +{ + AnonBoxRuleProcessorData* data = + static_cast(aData); + + aProcessor->RulesMatching(data); + return PR_TRUE; +} + +already_AddRefed +nsStyleSet::ResolveAnonymousBoxStyle(nsIAtom* aPseudoTag, + nsStyleContext* aParentContext) +{ + NS_ENSURE_FALSE(mInShutdown, nsnull); + +#ifdef DEBUG + PRBool isAnonBox = nsCSSAnonBoxes::IsAnonBox(aPseudoTag) +#ifdef MOZ_XUL + && !nsCSSAnonBoxes::IsTreePseudoElement(aPseudoTag) +#endif + ; + NS_PRECONDITION(isAnonBox, "Unexpected pseudo"); +#endif + + nsRuleWalker ruleWalker(mRuleTree); + nsPresContext *presContext = PresContext(); + AnonBoxRuleProcessorData data(presContext, aPseudoTag, &ruleWalker); + FileRules(EnumAnonBoxRulesMatching, &data, nsnull, &ruleWalker); + + return GetContext(presContext, aParentContext, ruleWalker.GetCurrentNode(), + aPseudoTag, nsCSSPseudoElements::ePseudo_AnonBox); +} + PRBool nsStyleSet::AppendFontFaceRules(nsPresContext* aPresContext, nsTArray& aArray) diff --git a/layout/style/nsStyleSet.h b/layout/style/nsStyleSet.h index 7e6eb6711a2d..671de095ebeb 100644 --- a/layout/style/nsStyleSet.h +++ b/layout/style/nsStyleSet.h @@ -140,20 +140,7 @@ class nsStyleSet // Get a style context for an anonymous box. aPseudoTag is the // pseudo-tag to use and must be non-null. already_AddRefed - ResolveAnonymousBoxStyle(nsIAtom* aPseudoTag, - nsStyleContext* aParentContext) { -#ifdef DEBUG - PRBool isAnonBox = nsCSSAnonBoxes::IsAnonBox(aPseudoTag) -#ifdef MOZ_XUL - && !nsCSSAnonBoxes::IsTreePseudoElement(aPseudoTag) -#endif - ; - NS_PRECONDITION(isAnonBox, "Unexpected pseudo"); -#endif - return ResolvePseudoStyleFor(nsnull, aPseudoTag, - nsCSSPseudoElements::ePseudo_AnonBox, - aParentContext); - } + ResolveAnonymousBoxStyle(nsIAtom* aPseudoTag, nsStyleContext* aParentContext); #ifdef MOZ_XUL // Get a style context for a XUL tree pseudo. aPseudoTag is the @@ -348,8 +335,11 @@ public: // Enumerate the rules in a way that cares about the order of the // rules. + // aContent is the node the rules are for. It might be null. aData + // is the closure to pass to aCollectorFunc. If aContent is not null, + // aData must be a RuleProcessorData* void FileRules(nsIStyleRuleProcessor::EnumFunc aCollectorFunc, - RuleProcessorData* aData, nsRuleWalker* aRuleWalker); + void* aData, nsIContent* aContent, nsRuleWalker* aRuleWalker); // Enumerate all the rules in a way that doesn't care about the order // of the rules and break out if the enumeration is halted. diff --git a/layout/style/nsTransitionManager.cpp b/layout/style/nsTransitionManager.cpp index a369b44f317d..ab65dff15ee0 100644 --- a/layout/style/nsTransitionManager.cpp +++ b/layout/style/nsTransitionManager.cpp @@ -761,6 +761,12 @@ nsTransitionManager::RulesMatching(PseudoElementRuleProcessorData* aData) return WalkTransitionRule(aData, aData->mPseudoType); } +NS_IMETHODIMP +nsTransitionManager::RulesMatching(AnonBoxRuleProcessorData* aData) +{ + return NS_OK; +} + NS_IMETHODIMP nsTransitionManager::RulesMatching(PseudoRuleProcessorData* aData) { diff --git a/layout/style/nsTransitionManager.h b/layout/style/nsTransitionManager.h index 706fcd23c2b6..e62e3fe50003 100644 --- a/layout/style/nsTransitionManager.h +++ b/layout/style/nsTransitionManager.h @@ -87,6 +87,7 @@ public: // nsIStyleRuleProcessor NS_IMETHOD RulesMatching(ElementRuleProcessorData* aData); NS_IMETHOD RulesMatching(PseudoElementRuleProcessorData* aData); + NS_IMETHOD RulesMatching(AnonBoxRuleProcessorData* aData); NS_IMETHOD RulesMatching(PseudoRuleProcessorData* aData); NS_IMETHOD HasStateDependentStyle(StateRuleProcessorData* aData, nsReStyleHint* aResult);