diff --git a/layout/style/nsCSSRuleProcessor.cpp b/layout/style/nsCSSRuleProcessor.cpp index 2d01fd8bd12..318ebb97415 100644 --- a/layout/style/nsCSSRuleProcessor.cpp +++ b/layout/style/nsCSSRuleProcessor.cpp @@ -1925,20 +1925,19 @@ PRBool IsStateSelector(nsCSSSelector& aSelector) return PR_FALSE; } -PR_STATIC_CALLBACK(PRBool) -AddRule(void* aRuleInfo, void* aCascade) +static PRBool +AddRule(RuleValue* aRuleInfo, void* aCascade) { - RuleValue* ruleInfo = static_cast(aRuleInfo); RuleCascadeData *cascade = static_cast(aCascade); // Build the rule hash. - cascade->mRuleHash.PrependRule(ruleInfo); + cascade->mRuleHash.PrependRule(aRuleInfo); nsVoidArray* stateArray = &cascade->mStateSelectors; nsVoidArray* classArray = &cascade->mClassSelectors; nsVoidArray* idArray = &cascade->mIDSelectors; - for (nsCSSSelector* selector = ruleInfo->mSelector; + for (nsCSSSelector* selector = aRuleInfo->mSelector; selector; selector = selector->mNext) { // It's worth noting that this loop over negations isn't quite // optimal for two reasons. One, we could add something to one of @@ -1978,23 +1977,60 @@ AddRule(void* aRuleInfo, void* aCascade) return PR_TRUE; } -PR_STATIC_CALLBACK(PRIntn) -RuleArraysDestroy(nsHashKey *aKey, void *aData, void *aClosure) +struct PerWeightData { + PRInt32 mWeight; + RuleValue* mRules; // linked list (reverse order) +}; + +struct RuleByWeightEntry : public PLDHashEntryHdr { + PerWeightData data; // mWeight is key, mRules are value +}; + +PR_STATIC_CALLBACK(PLDHashNumber) +HashIntKey(PLDHashTable *table, const void *key) { - delete static_cast(aData); - return PR_TRUE; + return PLDHashNumber(NS_PTR_TO_INT32(key)); } +PR_STATIC_CALLBACK(PRBool) +MatchWeightEntry(PLDHashTable *table, const PLDHashEntryHdr *hdr, + const void *key) +{ + const RuleByWeightEntry *entry = (const RuleByWeightEntry *)hdr; + return entry->data.mWeight == NS_PTR_TO_INT32(key); +} + +static PLDHashTableOps gRulesByWeightOps = { + PL_DHashAllocTable, + PL_DHashFreeTable, + HashIntKey, + MatchWeightEntry, + PL_DHashMoveEntryStub, + PL_DHashClearEntryStub, + PL_DHashFinalizeStub, + NULL +}; + struct CascadeEnumData { CascadeEnumData(nsPresContext* aPresContext, PLArenaPool& aArena) : mPresContext(aPresContext), - mRuleArrays(nsnull, nsnull, RuleArraysDestroy, nsnull, 64), mArena(aArena) { + if (!PL_DHashTableInit(&mRulesByWeight, &gRulesByWeightOps, nsnull, + sizeof(RuleByWeightEntry), 64)) + mRulesByWeight.ops = nsnull; + } + + ~CascadeEnumData() + { + if (mRulesByWeight.ops) + PL_DHashTableFinish(&mRulesByWeight); } nsPresContext* mPresContext; - nsObjectHashtable mRuleArrays; // of nsAutoVoidArray + // Hooray, a manual PLDHashTable since nsClassHashtable doesn't + // provide a getter that gives me a *reference* to the value. + PLDHashTable mRulesByWeight; // of RuleValue* linked lists (?) PLArenaPool& mArena; }; @@ -2011,24 +2047,25 @@ InsertRuleByWeight(nsICSSRule* aRule, void* aData) for (nsCSSSelectorList *sel = styleRule->Selector(); sel; sel = sel->mNext) { PRInt32 weight = sel->mWeight; - nsPRUint32Key key(weight); - nsAutoVoidArray *rules = - static_cast(data->mRuleArrays.Get(&key)); - if (!rules) { - rules = new nsAutoVoidArray(); - if (!rules) return PR_FALSE; // out of memory - data->mRuleArrays.Put(&key, rules); - } + RuleByWeightEntry *entry = static_cast( + PL_DHashTableOperate(&data->mRulesByWeight, NS_INT32_TO_PTR(weight), + PL_DHASH_ADD)); + if (!entry) + return PR_FALSE; + entry->data.mWeight = weight; RuleValue *info = new (data->mArena) RuleValue(styleRule, sel->mSelectors); - rules->AppendElement(info); + // entry->data.mRules must be in backwards order. + info->mNext = entry->data.mRules; + entry->data.mRules = info; } } else if (nsICSSRule::MEDIA_RULE == type || nsICSSRule::DOCUMENT_RULE == type) { nsICSSGroupRule* groupRule = (nsICSSGroupRule*)aRule; if (groupRule->UseForPresentation(data->mPresContext)) - groupRule->EnumerateRulesForwards(InsertRuleByWeight, aData); + if (!groupRule->EnumerateRulesForwards(InsertRuleByWeight, aData)) + return PR_FALSE; } return PR_TRUE; } @@ -2050,48 +2087,43 @@ CascadeSheetRulesInto(nsICSSStyleSheet* aSheet, void* aData) } if (sheet->mInner) { - sheet->mInner->mOrderedRules.EnumerateForwards(InsertRuleByWeight, data); + if (!sheet->mInner->mOrderedRules.EnumerateForwards(InsertRuleByWeight, data)) + return PR_FALSE; } } return PR_TRUE; } -struct RuleArrayData { - PRInt32 mWeight; - nsVoidArray* mRuleArray; -}; - -PR_STATIC_CALLBACK(int) CompareArrayData(const void* aArg1, const void* aArg2, +PR_STATIC_CALLBACK(int) CompareWeightData(const void* aArg1, const void* aArg2, void* closure) { - const RuleArrayData* arg1 = static_cast(aArg1); - const RuleArrayData* arg2 = static_cast(aArg2); + const PerWeightData* arg1 = static_cast(aArg1); + const PerWeightData* arg2 = static_cast(aArg2); return arg1->mWeight - arg2->mWeight; // put lower weight first } -struct FillArrayData { - FillArrayData(RuleArrayData* aArrayData) : +struct FillWeightArrayData { + FillWeightArrayData(PerWeightData* aArrayData) : mIndex(0), - mArrayData(aArrayData) + mWeightArray(aArrayData) { } PRInt32 mIndex; - RuleArrayData* mArrayData; + PerWeightData* mWeightArray; }; -PR_STATIC_CALLBACK(PRBool) -FillArray(nsHashKey* aKey, void* aData, void* aClosure) + +PR_STATIC_CALLBACK(PLDHashOperator) +FillWeightArray(PLDHashTable *table, PLDHashEntryHdr *hdr, + PRUint32 number, void *arg) { - nsPRUint32Key* key = static_cast(aKey); - nsVoidArray* weightArray = static_cast(aData); - FillArrayData* data = static_cast(aClosure); + FillWeightArrayData* data = static_cast(arg); + const RuleByWeightEntry *entry = (const RuleByWeightEntry *)hdr; - RuleArrayData& ruleData = data->mArrayData[data->mIndex++]; - ruleData.mRuleArray = weightArray; - ruleData.mWeight = key->GetValue(); + data->mWeightArray[data->mIndex++] = entry->data; - return PR_TRUE; + return PL_DHASH_NEXT; } RuleCascadeData* @@ -2118,24 +2150,34 @@ nsCSSRuleProcessor::GetRuleCascade(nsPresContext* aPresContext) eCompatibility_NavQuirks == aPresContext->CompatibilityMode())); if (newCascade) { CascadeEnumData data(aPresContext, newCascade->mRuleHash.Arena()); - mSheets.EnumerateForwards(CascadeSheetRulesInto, &data); + if (!data.mRulesByWeight.ops) + return nsnull; + if (!mSheets.EnumerateForwards(CascadeSheetRulesInto, &data)) + return nsnull; - // Take the hashtable of arrays (keyed by weight, in order sort) and - // sort by weight and secondary sort by order. - PRInt32 arrayCount = data.mRuleArrays.Count(); - nsAutoArrayPtr arrayData(new RuleArrayData[arrayCount]); - FillArrayData faData(arrayData); - data.mRuleArrays.Enumerate(FillArray, &faData); - NS_QuickSort(arrayData, arrayCount, sizeof(RuleArrayData), - CompareArrayData, nsnull); + // Sort the hash table of per-weight linked lists by weight. + PRUint32 weightCount = data.mRulesByWeight.entryCount; + nsAutoArrayPtr weightArray(new PerWeightData[weightCount]); + FillWeightArrayData fwData(weightArray); + PL_DHashTableEnumerate(&data.mRulesByWeight, FillWeightArray, &fwData); + NS_QuickSort(weightArray, weightCount, sizeof(PerWeightData), + CompareWeightData, nsnull); // Put things into the rule hash backwards because it's easier to // build a singly linked list lowest-first that way. - for (PRInt32 i = arrayCount - 1; i >= 0; --i) { - if (!arrayData[i].mRuleArray->EnumerateBackwards(AddRule, - newCascade)) { - return nsnull; - } + // The primary sort is by weight... + PRUint32 i = weightCount; + while (i > 0) { + --i; + // and the secondary sort is by order. mRules are already backwards. + RuleValue *ruleValue = weightArray[i].mRules; + do { + // Calling |AddRule| reuses mNext! + RuleValue *next = ruleValue->mNext; + if (!AddRule(ruleValue, newCascade)) + return nsnull; + ruleValue = next; + } while (ruleValue); } *cascadep = newCascade; diff --git a/layout/style/nsCSSRules.cpp b/layout/style/nsCSSRules.cpp index 843c2d5f311..ce1fb1246fd 100644 --- a/layout/style/nsCSSRules.cpp +++ b/layout/style/nsCSSRules.cpp @@ -728,11 +728,11 @@ nsCSSGroupRule::GetStyleRuleAt(PRInt32 aIndex, nsICSSRule*& aRule) const return NS_OK; } -NS_IMETHODIMP +NS_IMETHODIMP_(PRBool) nsCSSGroupRule::EnumerateRulesForwards(RuleEnumFunc aFunc, void * aData) const { - const_cast(this)->mRules.EnumerateForwards(aFunc, aData); - return NS_OK; + return + const_cast(this)->mRules.EnumerateForwards(aFunc, aData); } /* diff --git a/layout/style/nsCSSRules.h b/layout/style/nsCSSRules.h index 7c739af516f..af3502186f4 100644 --- a/layout/style/nsCSSRules.h +++ b/layout/style/nsCSSRules.h @@ -84,7 +84,7 @@ public: NS_IMETHOD AppendStyleRule(nsICSSRule* aRule); NS_IMETHOD StyleRuleCount(PRInt32& aCount) const; NS_IMETHOD GetStyleRuleAt(PRInt32 aIndex, nsICSSRule*& aRule) const; - NS_IMETHOD EnumerateRulesForwards(RuleEnumFunc aFunc, void * aData) const; + NS_IMETHOD_(PRBool) EnumerateRulesForwards(RuleEnumFunc aFunc, void * aData) const; NS_IMETHOD DeleteStyleRuleAt(PRUint32 aIndex); NS_IMETHOD InsertStyleRulesAt(PRUint32 aIndex, nsCOMArray& aRules); diff --git a/layout/style/nsICSSGroupRule.h b/layout/style/nsICSSGroupRule.h index 69a44abb4e5..11b948d08b6 100644 --- a/layout/style/nsICSSGroupRule.h +++ b/layout/style/nsICSSGroupRule.h @@ -63,7 +63,7 @@ public: NS_IMETHOD GetStyleRuleAt(PRInt32 aIndex, nsICSSRule*& aRule) const = 0; typedef nsCOMArray::nsCOMArrayEnumFunc RuleEnumFunc; - NS_IMETHOD EnumerateRulesForwards(RuleEnumFunc aFunc, void * aData) const = 0; + NS_IMETHOD_(PRBool) EnumerateRulesForwards(RuleEnumFunc aFunc, void * aData) const = 0; /* * The next three methods should never be called unless you have first