Bug 525608 part 5. Change anonymous box rule matching to just use a separate hashtable and not ever run SelectorMatches. r=dbaron

This commit is contained in:
Boris Zbarsky 2009-12-10 14:36:06 -08:00
parent e6128a1572
commit bdb94e5fc6
11 changed files with 141 additions and 24 deletions

View File

@ -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<nsCSSSelector*> mClassSelectors;
nsTArray<nsCSSSelector*> mIDSelectors;
PLDHashTable mAttributeSelectors;
PLDHashTable mAnonBoxRules;
nsTArray<nsFontFaceRuleContainer> 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<RuleHashTagTableEntry*>
(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<nsIStyleRule> iRule = do_QueryInterface(value->mRule);
NS_ASSERTION(static_cast<nsIStyleRule*>(value->mRule) == iRule.get(),
"Please fix QI so this performance optimization is valid");
#endif
aData->mRuleWalker->Forward(static_cast<nsIStyleRule*>(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<RuleHashTagTableEntry*>
(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);
}

View File

@ -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,

View File

@ -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)
{

View File

@ -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

View File

@ -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);

View File

@ -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 <em>and pseudo</em>.

View File

@ -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,

View File

@ -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<RuleProcessorData*>(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<AnonBoxRuleProcessorData*>(aData);
aProcessor->RulesMatching(data);
return PR_TRUE;
}
already_AddRefed<nsStyleContext>
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<nsFontFaceRuleContainer>& aArray)

View File

@ -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<nsStyleContext>
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.

View File

@ -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)
{

View File

@ -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);