Bug 525608 part 5. Change anonymous box rule matching to just use a separate hashtable and not ever run SelectorMatches. r=dbaron
authorBoris Zbarsky <bzbarsky@mit.edu>
Thu, 10 Dec 2009 14:36:06 -0800
changeset 35540 62e1d35ef5b4f3073b226aad6da3e5825881b92b
parent 35539 732473bebf16066f0ee401a3de67ab6765f5751e
child 35541 2d249fba49feb531345b6c73a24a36bcc57a6418
push idunknown
push userunknown
push dateunknown
reviewersdbaron
bugs525608
milestone1.9.3a1pre
Bug 525608 part 5. Change anonymous box rule matching to just use a separate hashtable and not ever run SelectorMatches. r=dbaron
layout/style/nsCSSRuleProcessor.cpp
layout/style/nsCSSRuleProcessor.h
layout/style/nsHTMLCSSStyleSheet.cpp
layout/style/nsHTMLStyleSheet.cpp
layout/style/nsHTMLStyleSheet.h
layout/style/nsIStyleRuleProcessor.h
layout/style/nsRuleProcessorData.h
layout/style/nsStyleSet.cpp
layout/style/nsStyleSet.h
layout/style/nsTransitionManager.cpp
layout/style/nsTransitionManager.h
--- a/layout/style/nsCSSRuleProcessor.cpp
+++ b/layout/style/nsCSSRuleProcessor.cpp
@@ -722,33 +722,37 @@ struct RuleCascadeData {
     : mRuleHash(aQuirksMode),
       mStateSelectors(),
       mCacheKey(aMedium),
       mNext(nsnull),
       mQuirksMode(aQuirksMode)
   {
     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];
     }
   }
   RuleHash                 mRuleHash;
   RuleHash*
     mPseudoElementRuleHashes[nsCSSPseudoElements::ePseudo_PseudoElementCount];
   nsTArray<nsCSSSelector*> mStateSelectors;
   nsTArray<nsCSSSelector*> mClassSelectors;
   nsTArray<nsCSSSelector*> mIDSelectors;
   PLDHashTable             mAttributeSelectors;
+  PLDHashTable             mAnonBoxRules;
 
   nsTArray<nsFontFaceRuleContainer> mFontFaceRules;
 
   // Looks up or creates the appropriate list in |mAttributeSelectors|.
   // Returns null only on allocation failure.
   nsTArray<nsCSSSelector*>* AttributeListFor(nsIAtom* aAttribute);
 
   nsMediaQueryResultCacheKey mCacheKey;
@@ -2074,16 +2078,42 @@ nsCSSRuleProcessor::RulesMatching(Pseudo
                                   aData->mClasses,
                                   ContentEnumFunc,
                                   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)
 {
   PseudoRuleProcessorData* data = (PseudoRuleProcessorData*)aData;
 
   if (!aSelector->IsPseudoElement())
     return;
 
@@ -2413,16 +2443,28 @@ AddRule(RuleValue* aRuleInfo, void* aCas
       }
     }
     NS_ASSERTION(aRuleInfo->mSelector->mNext,
                  "Must have mNext; parser screwed up");
     NS_ASSERTION(aRuleInfo->mSelector->mNext->mOperator == '>',
                  "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);
   }
 
   nsTArray<nsCSSSelector*>* stateArray = &cascade->mStateSelectors;
   nsTArray<nsCSSSelector*>* classArray = &cascade->mClassSelectors;
   nsTArray<nsCSSSelector*>* idArray = &cascade->mIDSelectors;
   
--- a/layout/style/nsCSSRuleProcessor.h
+++ b/layout/style/nsCSSRuleProcessor.h
@@ -88,16 +88,18 @@ public:
   static PRBool SelectorListMatches(RuleProcessorData& aData,
                                     nsCSSSelectorList* aSelectorList);
 
   // 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);
 
   virtual nsReStyleHint
     HasAttributeDependentStyle(AttributeRuleProcessorData* aData);
 
--- a/layout/style/nsHTMLCSSStyleSheet.cpp
+++ b/layout/style/nsHTMLCSSStyleSheet.cpp
@@ -86,16 +86,18 @@ public:
   NS_IMETHOD GetOwningDocument(nsIDocument*& aDocument) const;
   NS_IMETHOD SetOwningDocument(nsIDocument* aDocument);
 
   // 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);
 
   virtual nsReStyleHint
     HasAttributeDependentStyle(AttributeRuleProcessorData* aData);
   NS_IMETHOD MediumFeaturesChanged(nsPresContext* aPresContext,
@@ -160,16 +162,22 @@ HTMLCSSStyleSheetImpl::RulesMatching(Ele
 
 NS_IMETHODIMP
 HTMLCSSStyleSheetImpl::RulesMatching(PseudoElementRuleProcessorData* aData)
 {
   return NS_OK;
 }
 
 NS_IMETHODIMP
+HTMLCSSStyleSheetImpl::RulesMatching(AnonBoxRuleProcessorData* aData)
+{
+  return NS_OK;
+}
+
+NS_IMETHODIMP
 HTMLCSSStyleSheetImpl::RulesMatching(PseudoRuleProcessorData* aData)
 {
   return NS_OK;
 }
 
 NS_IMETHODIMP
 HTMLCSSStyleSheetImpl::Init(nsIURI* aURL, nsIDocument* aDocument)
 {
--- a/layout/style/nsHTMLStyleSheet.cpp
+++ b/layout/style/nsHTMLStyleSheet.cpp
@@ -564,28 +564,34 @@ nsHTMLStyleSheet::MediumFeaturesChanged(
 
 NS_IMETHODIMP
 nsHTMLStyleSheet::RulesMatching(PseudoElementRuleProcessorData* aData)
 {
   return NS_OK;
 }
 
 NS_IMETHODIMP
-nsHTMLStyleSheet::RulesMatching(PseudoRuleProcessorData* aData)
+nsHTMLStyleSheet::RulesMatching(AnonBoxRuleProcessorData* aData)
 {
   nsIAtom* pseudoTag = aData->mPseudoTag;
   if (pseudoTag == nsCSSAnonBoxes::tableCol) {
     nsRuleWalker *ruleWalker = aData->mRuleWalker;
     if (ruleWalker) {
       ruleWalker->Forward(mTableColRule);
     }
   }
   return NS_OK;
 }
 
+NS_IMETHODIMP
+nsHTMLStyleSheet::RulesMatching(PseudoRuleProcessorData* aData)
+{
+  return NS_OK;
+}
+
 
   // nsIStyleSheet api
 NS_IMETHODIMP
 nsHTMLStyleSheet::GetSheetURI(nsIURI** aSheetURI) const
 {
   *aSheetURI = mURL;
   NS_IF_ADDREF(*aSheetURI);
   return NS_OK;
--- a/layout/style/nsHTMLStyleSheet.h
+++ b/layout/style/nsHTMLStyleSheet.h
@@ -75,16 +75,17 @@ public:
   NS_IMETHOD SetOwningDocument(nsIDocument* aDocumemt);
 #ifdef DEBUG
   virtual void List(FILE* out = stdout, PRInt32 aIndent = 0) const;
 #endif
 
   // 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);
   virtual nsReStyleHint
     HasAttributeDependentStyle(AttributeRuleProcessorData* aData);
   NS_IMETHOD MediumFeaturesChanged(nsPresContext* aPresContext,
                                    PRBool* aRulesChanged);
 
--- a/layout/style/nsIStyleRuleProcessor.h
+++ b/layout/style/nsIStyleRuleProcessor.h
@@ -47,16 +47,17 @@
 
 #include "nsISupports.h"
 #include "nsChangeHint.h"
 #include "nsIContent.h"
 
 struct RuleProcessorData;
 struct ElementRuleProcessorData;
 struct PseudoElementRuleProcessorData;
+struct AnonBoxRuleProcessorData;
 struct PseudoRuleProcessorData;
 struct StateRuleProcessorData;
 struct AttributeRuleProcessorData;
 class nsPresContext;
 
 // IID for the nsIStyleRuleProcessor interface {a4ec760e-6bfb-4b9f-bd08-9d1c23b700f6}
 #define NS_ISTYLE_RULE_PROCESSOR_IID     \
 { 0xa4ec760e, 0x6bfb, 0x4b9f, \
@@ -88,16 +89,21 @@ public:
 
   /**
    * Just like the previous |RulesMatching|, except for a given content
    * node <em>and pseudo-element</em>.
    */
   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>.
    */
   NS_IMETHOD RulesMatching(PseudoRuleProcessorData* aData) = 0;
 
   /**
    * Return how (as described by nsReStyleHint) style can depend on a
    * change of the given content state on the given content node.  This
--- a/layout/style/nsRuleProcessorData.h
+++ b/layout/style/nsRuleProcessorData.h
@@ -188,16 +188,34 @@ struct PseudoElementRuleProcessorData : 
                       nsCSSPseudoElements::ePseudo_PseudoElementCount,
                     "null pointer");
     NS_PRECONDITION(aRuleWalker, "null pointer");
   }
 
   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,
                           nsIAtom* aPseudoTag,
                           nsICSSPseudoComparator* aComparator,
                           nsRuleWalker* aRuleWalker)
   : RuleProcessorData(aPresContext, aParentContent, aRuleWalker)
   {
--- a/layout/style/nsStyleSet.cpp
+++ b/layout/style/nsStyleSet.cpp
@@ -526,17 +526,18 @@ nsStyleSet::AssertNoCSSRules(nsRuleNode*
     NS_ASSERTION(!cssRule || !cssRule->Selector(), "Unexpected CSS rule");
   }
 }
 #endif
 
 // 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]
   //  1. UA normal rules                    = Agent        normal
   //  2. Presentation hints                 = PresHint     normal
   //  3. User normal rules                  = User         normal
   //  4. HTML Presentation hints            = HTMLPresHint normal
   //  5. Author normal rules                = Document     normal
@@ -559,32 +560,34 @@ nsStyleSet::FileRules(nsIStyleRuleProces
 
   aRuleWalker->SetLevel(ePresHintSheet, PR_FALSE, PR_FALSE);
   if (mRuleProcessors[ePresHintSheet])
     (*aCollectorFunc)(mRuleProcessors[ePresHintSheet], aData);
   nsRuleNode* lastPresHintRN = aRuleWalker->GetCurrentNode();
 
   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();
   PRBool haveImportantUserRules = !aRuleWalker->GetCheckForImportantRules();
 
   aRuleWalker->SetLevel(eHTMLPresHintSheet, PR_FALSE, PR_FALSE);
   if (mRuleProcessors[eHTMLPresHintSheet])
     (*aCollectorFunc)(mRuleProcessors[eHTMLPresHintSheet], aData);
   nsRuleNode* lastHTMLPresHintRN = aRuleWalker->GetCurrentNode();
   
   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
     (*aCollectorFunc)(mRuleProcessors[eDocSheet], aData);
   aRuleWalker->SetLevel(eStyleAttrSheet, PR_FALSE,
                         aRuleWalker->GetCheckForImportantRules());
   if (mRuleProcessors[eStyleAttrSheet])
     (*aCollectorFunc)(mRuleProcessors[eStyleAttrSheet], aData);
@@ -741,17 +744,17 @@ nsStyleSet::ResolveStyleFor(nsIContent* 
 
   NS_ASSERTION(aContent, "must have content");
   NS_ASSERTION(aContent->IsNodeOfType(nsINode::eELEMENT),
                "content must be element");
 
   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();
   }
 
   return result;
 }
 
@@ -844,17 +847,17 @@ nsStyleSet::ResolvePseudoStyleFor(nsICon
                "aPseudoTag must be pseudo-element or anonymous box");
   NS_ASSERTION(nsCSSPseudoElements::GetPseudoType(aPseudoTag) == aPseudoType,
                "Incorrect pseudo type");
 
   if (aPseudoTag && presContext) {
     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,
                         aPseudoType).get();
   }
 
   return result;
 }
@@ -882,17 +885,17 @@ nsStyleSet::ResolvePseudoElementStyle(ns
                aParentContent->IsNodeOfType(nsINode::eELEMENT),
                "aParentContent must be element");
 
   nsRuleWalker ruleWalker(mRuleTree);
   nsPresContext *presContext = PresContext();
   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);
 }
 
 already_AddRefed<nsStyleContext>
 nsStyleSet::ProbePseudoElementStyle(nsIContent* aParentContent,
                                     nsCSSPseudoElements::Type aType,
@@ -911,17 +914,17 @@ nsStyleSet::ProbePseudoElementStyle(nsIC
   nsPresContext *presContext = PresContext();
 
   nsRuleWalker ruleWalker(mRuleTree);
   PseudoElementRuleProcessorData data(presContext, aParentContent, &ruleWalker,
                                       aType);
   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) {
     return nsnull;
   }
 
   nsRefPtr<nsStyleContext> result =
     GetContext(presContext, aParentContext, ruleNode, pseudoTag, aType);
@@ -939,16 +942,50 @@ nsStyleSet::ProbePseudoElementStyle(nsIC
         content->ContentCount() == 0) {
       result = nsnull;
     }
   }
   
   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)
 {
   NS_ENSURE_FALSE(mInShutdown, PR_FALSE);
 
   for (PRUint32 i = 0; i < NS_ARRAY_LENGTH(gCSSSheetTypes); ++i) {
     nsCSSRuleProcessor *ruleProc = static_cast<nsCSSRuleProcessor*>
--- a/layout/style/nsStyleSet.h
+++ b/layout/style/nsStyleSet.h
@@ -135,30 +135,17 @@ class nsStyleSet
   already_AddRefed<nsStyleContext>
   ProbePseudoElementStyle(nsIContent* aParentContent,
                           nsCSSPseudoElements::Type aType,
                           nsStyleContext* aParentContext);
   
   // 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
   // pseudo-tag to use and must be non-null.  aParentContent must be
   // non-null.  aComparator must be non-null.
   already_AddRefed<nsStyleContext>
   ResolveXULTreePseudoStyle(nsIContent* aParentContent,
                             nsIAtom* aPseudoTag,
@@ -343,18 +330,21 @@ public:
   // just asserts that there are no CSS rules between aCurrLevelNode and
   // aLastPrevLevelNode.  Mostly useful for the preshint levels.
   void AssertNoCSSRules(nsRuleNode* aCurrLevelNode,
                         nsRuleNode* aLastPrevLevelNode);
 #endif
   
   // 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.
   void WalkRuleProcessors(nsIStyleRuleProcessor::EnumFunc aFunc,
                           RuleProcessorData* aData);
 
   already_AddRefed<nsStyleContext> GetContext(nsPresContext* aPresContext,
                                               nsStyleContext* aParentContext,
--- a/layout/style/nsTransitionManager.cpp
+++ b/layout/style/nsTransitionManager.cpp
@@ -757,16 +757,22 @@ nsTransitionManager::RulesMatching(Pseud
 
   // Note:  If we're the only thing keeping a pseudo-element frame alive
   // (per ProbePseudoStyleContext), we still want to keep it alive, so
   // this is ok.
   return WalkTransitionRule(aData, aData->mPseudoType);
 }
 
 NS_IMETHODIMP
+nsTransitionManager::RulesMatching(AnonBoxRuleProcessorData* aData)
+{
+  return NS_OK;
+}
+
+NS_IMETHODIMP
 nsTransitionManager::RulesMatching(PseudoRuleProcessorData* aData)
 {
   return NS_OK;
 }
 
 NS_IMETHODIMP
 nsTransitionManager::HasStateDependentStyle(StateRuleProcessorData* aData,
                                             nsReStyleHint* aResult)
--- a/layout/style/nsTransitionManager.h
+++ b/layout/style/nsTransitionManager.h
@@ -82,16 +82,17 @@ public:
                         nsStyleContext *aNewStyleContext);
 
   // nsISupports
   NS_DECL_ISUPPORTS_INHERITED
 
   // 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);
   virtual nsReStyleHint
     HasAttributeDependentStyle(AttributeRuleProcessorData* aData);
   NS_IMETHOD MediumFeaturesChanged(nsPresContext* aPresContext,
                                    PRBool* aRulesChanged);