Bug 525608 part 7. Make tree pseudos use a separate hashtable instead of riding along on the rulehash. r=dbaron
authorBoris Zbarsky <bzbarsky@mit.edu>
Fri, 11 Dec 2009 02:37:40 -0500
changeset 35558 c6665a0ce75dbce76df7fe8241c94117ab1c187e
parent 35557 95a7468a8a8e0828f00bc362d4b51f90d1078c5b
child 35559 9c8bd114fd20ae1ad6966602f92cea46c26d65d8
push idunknown
push userunknown
push dateunknown
reviewersdbaron
bugs525608
milestone1.9.3a1pre
Bug 525608 part 7. Make tree pseudos use a separate hashtable instead of riding along on the rulehash. 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
@@ -360,24 +360,22 @@ typedef void (*RuleEnumFunc)(nsICSSStyle
 class RuleHash {
 public:
   RuleHash(PRBool aQuirksMode);
   ~RuleHash();
   void PrependRule(RuleValue *aRuleInfo);
   void EnumerateAllRules(PRInt32 aNameSpace, nsIAtom* aTag, nsIAtom* aID,
                          const nsAttrValue* aClassList,
                          RuleEnumFunc aFunc, RuleProcessorData* aData);
-  void EnumerateTagRules(nsIAtom* aTag,
-                         RuleEnumFunc aFunc, void* aData);
   PLArenaPool& Arena() { return mArena; }
 
 protected:
   void PrependRuleToTable(PLDHashTable* aTable, const void* aKey,
                           RuleValue* aRuleInfo);
-  void PrependRuleToTagTable(const void* aKey, RuleValue* aRuleInfo);
+  void PrependRuleToTagTable(nsIAtom* aKey, RuleValue* aRuleInfo);
   void PrependUniversalRule(RuleValue* aRuleInfo);
 
   // All rule values in these hashtables are arena allocated
   PRInt32     mRuleCount;
   PLDHashTable mIdTable;
   PLDHashTable mClassTable;
   PLDHashTable mTagTable;
   PLDHashTable mNameSpaceTable;
@@ -391,47 +389,42 @@ protected:
 #ifdef RULE_HASH_STATS
   PRUint32    mUniversalSelectors;
   PRUint32    mNameSpaceSelectors;
   PRUint32    mTagSelectors;
   PRUint32    mClassSelectors;
   PRUint32    mIdSelectors;
 
   PRUint32    mElementsMatched;
-  PRUint32    mPseudosMatched;
 
   PRUint32    mElementUniversalCalls;
   PRUint32    mElementNameSpaceCalls;
   PRUint32    mElementTagCalls;
   PRUint32    mElementClassCalls;
   PRUint32    mElementIdCalls;
-
-  PRUint32    mPseudoTagCalls;
 #endif // RULE_HASH_STATS
 };
 
 RuleHash::RuleHash(PRBool aQuirksMode)
   : mRuleCount(0),
     mUniversalRules(nsnull),
     mEnumList(nsnull), mEnumListSize(0)
 #ifdef RULE_HASH_STATS
     ,
     mUniversalSelectors(0),
     mNameSpaceSelectors(0),
     mTagSelectors(0),
     mClassSelectors(0),
     mIdSelectors(0),
     mElementsMatched(0),
-    mPseudosMatched(0),
     mElementUniversalCalls(0),
     mElementNameSpaceCalls(0),
     mElementTagCalls(0),
     mElementClassCalls(0),
-    mElementIdCalls(0),
-    mPseudoTagCalls(0)
+    mElementIdCalls(0)
 #endif
 {
   MOZ_COUNT_CTOR(RuleHash);
   // Initialize our arena
   PL_INIT_ARENA_POOL(&mArena, "RuleHashArena", NS_RULEHASH_ARENA_BLOCK_SIZE);
 
   PL_DHashTableInit(&mTagTable, &RuleHash_TagTable_Ops, nsnull,
                     sizeof(RuleHashTagTableEntry), 64);
@@ -449,27 +442,24 @@ RuleHash::RuleHash(PRBool aQuirksMode)
 
 RuleHash::~RuleHash()
 {
   MOZ_COUNT_DTOR(RuleHash);
 #ifdef RULE_HASH_STATS
   printf(
 "RuleHash(%p):\n"
 "  Selectors: Universal (%u) NameSpace(%u) Tag(%u) Class(%u) Id(%u)\n"
-"  Content Nodes: Elements(%u) Pseudo-Elements(%u)\n"
+"  Content Nodes: Elements(%u)\n"
 "  Element Calls: Universal(%u) NameSpace(%u) Tag(%u) Class(%u) Id(%u)\n"
-"  Pseudo-Element Calls: Tag(%u)\n",
          static_cast<void*>(this),
          mUniversalSelectors, mNameSpaceSelectors, mTagSelectors,
            mClassSelectors, mIdSelectors,
          mElementsMatched,
-         mPseudosMatched,
          mElementUniversalCalls, mElementNameSpaceCalls, mElementTagCalls,
-           mElementClassCalls, mElementIdCalls,
-         mPseudoTagCalls);
+           mElementClassCalls, mElementIdCalls);
 #ifdef PRINT_UNIVERSAL_RULES
   {
     RuleValue* value = mUniversalRules;
     if (value) {
       printf("  Universal rules:\n");
       do {
         nsAutoString selectorText;
         PRUint32 lineNumber = value->mRule->GetLineNumber();
@@ -506,29 +496,36 @@ void RuleHash::PrependRuleToTable(PLDHas
   // Get a new or existing entry.
   RuleHashTableEntry *entry = static_cast<RuleHashTableEntry*>
                                          (PL_DHashTableOperate(aTable, aKey, PL_DHASH_ADD));
   if (!entry)
     return;
   entry->mRules = aRuleInfo->Add(mRuleCount++, entry->mRules);
 }
 
-void RuleHash::PrependRuleToTagTable(const void* aKey, RuleValue* aRuleInfo)
+static void
+DoPrependRuleToTagTable(PLDHashTable* aTable, nsIAtom* aKey,
+                        RuleValue* aRuleInfo, PRInt32 aBackwardsIndex)
 {
   // Get a new or exisiting entry
-   RuleHashTagTableEntry *entry = static_cast<RuleHashTagTableEntry*>
-                              (PL_DHashTableOperate(&mTagTable, aKey, PL_DHASH_ADD));
-   if (!entry)
-     return;
+  RuleHashTagTableEntry *entry = static_cast<RuleHashTagTableEntry*>
+    (PL_DHashTableOperate(aTable, aKey, PL_DHASH_ADD));
+  if (!entry)
+    return;
+
+  entry->mTag = aKey;
 
-   entry->mTag = const_cast<nsIAtom*>(static_cast<const nsIAtom*>(aKey));
+  // This may give the same rule two different rule counts, but that is OK
+  // because we never combine two different entries in a tag table.
+  entry->mRules = aRuleInfo->Add(aBackwardsIndex, entry->mRules);
+}
 
-   // This may give the same rule two different rule counts, but that is OK
-   // because we never combine two different entries in the tag table.
-   entry->mRules = aRuleInfo->Add(mRuleCount++, entry->mRules);
+void RuleHash::PrependRuleToTagTable(nsIAtom* aKey, RuleValue* aRuleInfo)
+{
+  DoPrependRuleToTagTable(&mTagTable, aKey, aRuleInfo, mRuleCount++);
 }
 
 void RuleHash::PrependUniversalRule(RuleValue *aRuleInfo)
 {
   mUniversalRules = aRuleInfo->Add(mRuleCount++, mUniversalRules);
 }
 
 void RuleHash::PrependRule(RuleValue *aRuleInfo)
@@ -666,32 +663,16 @@ void RuleHash::EnumerateAllRules(PRInt32
     RuleValue* value = mEnumList[0];
     do {
       (*aFunc)(value->mRule, value->mSelector, aData);
       value = value->mNext;
     } while (value);
   }
 }
 
-void RuleHash::EnumerateTagRules(nsIAtom* aTag, RuleEnumFunc aFunc, void* aData)
-{
-  RuleHashTableEntry *entry = static_cast<RuleHashTableEntry*>
-                                         (PL_DHashTableOperate(&mTagTable, aTag, PL_DHASH_LOOKUP));
-
-  RULE_HASH_STAT_INCREMENT(mPseudosMatched);
-  if (PL_DHASH_ENTRY_IS_BUSY(entry)) {
-    RuleValue *tagValue = entry->mRules;
-    do {
-      RULE_HASH_STAT_INCREMENT(mPseudoTagCalls);
-      (*aFunc)(tagValue->mRule, tagValue->mSelector, aData);
-      tagValue = tagValue->mNext;
-    } while (tagValue);
-  }
-}
-
 //--------------------------------
 
 // Attribute selectors hash table.
 struct AttributeSelectorEntry : public PLDHashEntryHdr {
   nsIAtom *mAttribute;
   nsTArray<nsCSSSelector*> *mSelectors;
 };
 
@@ -725,34 +706,42 @@ struct RuleCascadeData {
       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));
+#ifdef MOZ_XUL
+    PL_DHashTableInit(&mXULTreeRules, &RuleHash_TagTable_Ops, nsnull,
+                      sizeof(RuleHashTagTableEntry), 16);
+#endif
   }
 
   ~RuleCascadeData()
   {
     PL_DHashTableFinish(&mAttributeSelectors);
     PL_DHashTableFinish(&mAnonBoxRules);
+    PL_DHashTableFinish(&mXULTreeRules);
     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;
+#ifdef MOZ_XUL
+  PLDHashTable             mXULTreeRules;
+#endif
 
   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;
@@ -2085,78 +2074,44 @@ nsCSSRuleProcessor::RulesMatching(AnonBo
 #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;
-
-  NS_ASSERTION(aSelector->mLowercaseTag == data->mPseudoTag, "RuleHash failure");
-  PRBool matches = PR_TRUE;
-  if (data->mComparator)
-    data->mComparator->PseudoMatches(data->mPseudoTag, aSelector, &matches);
-
-  if (matches) {
-    nsCSSSelector *selector = aSelector->mNext;
-
-    if (selector) { // test next selector specially
-      if (PRUnichar('+') == selector->mOperator) {
-        return; // not valid here, can't match
-      }
-      if (SelectorMatches(*data, selector, 0, PR_TRUE)) {
-        selector = selector->mNext;
-      }
-      else {
-        if (PRUnichar('>') == selector->mOperator) {
-          return; // immediate parent didn't match
-        }
-      }
-    }
-
-    if (selector && 
-        (! SelectorMatchesTree(*data, selector, PR_TRUE))) {
-      return; // remaining selectors didn't match
-    }
-
-    // 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(aRule);
-    NS_ASSERTION(static_cast<nsIStyleRule*>(aRule) == iRule.get(),
-                 "Please fix QI so this performance optimization is valid");
-#endif
-    data->mRuleWalker->Forward(static_cast<nsIStyleRule*>(aRule));
-    // nsStyleSet will deal with the !important rule
-  }
-}
-
+#ifdef MOZ_XUL
 NS_IMETHODIMP
-nsCSSRuleProcessor::RulesMatching(PseudoRuleProcessorData* aData)
+nsCSSRuleProcessor::RulesMatching(XULTreeRuleProcessorData* aData)
 {
   NS_PRECONDITION(aData->mContent->IsNodeOfType(nsINode::eELEMENT),
                   "content must be element");
 
   RuleCascadeData* cascade = GetRuleCascade(aData->mPresContext);
 
-  if (cascade) {
-    cascade->mRuleHash.EnumerateTagRules(aData->mPseudoTag,
-                                         PseudoEnumFunc, aData);
+  if (cascade && cascade->mXULTreeRules.entryCount) {
+    RuleHashTagTableEntry* entry = static_cast<RuleHashTagTableEntry*>
+      (PL_DHashTableOperate(&cascade->mXULTreeRules, aData->mPseudoTag,
+                            PL_DHASH_LOOKUP));
+    if (PL_DHASH_ENTRY_IS_BUSY(entry)) {
+      for (RuleValue *value = entry->mRules; value; value = value->mNext) {
+        PRBool matches = PR_TRUE;
+        aData->mComparator->PseudoMatches(aData->mPseudoTag, value->mSelector,
+                                          &matches);
+        if (matches) {
+          ContentEnumFunc(value->mRule, value->mSelector->mNext,
+                          static_cast<RuleProcessorData*>(aData));
+        }
+      }
+    }
   }
   return NS_OK;
 }
+#endif
 
 inline PRBool
 IsSiblingOperator(PRUnichar oper)
 {
   return oper == PRUnichar('+') || oper == PRUnichar('~');
 }
 
 NS_IMETHODIMP
@@ -2402,19 +2357,19 @@ PRBool IsStateSelector(nsCSSSelector& aS
         (pseudoClass->mAtom == nsCSSPseudoClasses::defaultPseudo)) {
       return PR_TRUE;
     }
   }
   return PR_FALSE;
 }
 
 static PRBool
-AddRule(RuleValue* aRuleInfo, void* aCascade)
+AddRule(RuleValue* aRuleInfo, RuleCascadeData* aCascade)
 {
-  RuleCascadeData *cascade = static_cast<RuleCascadeData*>(aCascade);
+  RuleCascadeData * const cascade = aCascade;
 
   // Build the rule hash.
   nsCSSPseudoElements::Type pseudoType = aRuleInfo->mSelector->PseudoType();
   if (pseudoType < nsCSSPseudoElements::ePseudo_PseudoElementCount) {
     RuleHash*& ruleHash = cascade->mPseudoElementRuleHashes[pseudoType];
     if (!ruleHash) {
       ruleHash = new RuleHash(cascade->mQuirksMode);
       if (!ruleHash) {
@@ -2424,28 +2379,44 @@ 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;
+    NS_ASSERTION(!aRuleInfo->mSelector->mCasedTag &&
+                 !aRuleInfo->mSelector->mIDList &&
+                 !aRuleInfo->mSelector->mClassList &&
+                 !aRuleInfo->mSelector->mPseudoClassList &&
+                 !aRuleInfo->mSelector->mAttrList &&
+                 !aRuleInfo->mSelector->mNegations &&
+                 !aRuleInfo->mSelector->mNext &&
+                 aRuleInfo->mSelector->mNameSpace == kNameSpaceID_Unknown,
+                 "Parser messed up with anon box selector");
 
-    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 {
+    DoPrependRuleToTagTable(&cascade->mAnonBoxRules,
+                            aRuleInfo->mSelector->mLowercaseTag,
+                            aRuleInfo, 0);
+  }
+#ifdef MOZ_XUL
+  else if (pseudoType == nsCSSPseudoElements::ePseudo_XULTree) {
+    // Index doesn't matter here, since we'll just be walking these
+    // rules in order; just pass 0.
+    DoPrependRuleToTagTable(&cascade->mXULTreeRules,
+                            aRuleInfo->mSelector->mLowercaseTag,
+                            aRuleInfo, 0);
+  }
+#endif
+  else {
+    NS_ASSERTION(pseudoType == nsCSSPseudoElements::ePseudo_NotPseudoElement,
+                 "Unexpected pseudoType");
     cascade->mRuleHash.PrependRule(aRuleInfo);
   }
 
   nsTArray<nsCSSSelector*>* stateArray = &cascade->mStateSelectors;
   nsTArray<nsCSSSelector*>* classArray = &cascade->mClassSelectors;
   nsTArray<nsCSSSelector*>* idArray = &cascade->mIDSelectors;
   
   for (nsCSSSelector* selector = aRuleInfo->mSelector;
--- a/layout/style/nsCSSRuleProcessor.h
+++ b/layout/style/nsCSSRuleProcessor.h
@@ -90,17 +90,19 @@ public:
 
   // nsIStyleRuleProcessor
   NS_IMETHOD RulesMatching(ElementRuleProcessorData* aData);
 
   NS_IMETHOD RulesMatching(PseudoElementRuleProcessorData* aData);
 
   NS_IMETHOD RulesMatching(AnonBoxRuleProcessorData* aData);
 
-  NS_IMETHOD RulesMatching(PseudoRuleProcessorData* aData);
+#ifdef MOZ_XUL
+  NS_IMETHOD RulesMatching(XULTreeRuleProcessorData* aData);
+#endif
 
   NS_IMETHOD HasStateDependentStyle(StateRuleProcessorData* aData,
                                     nsReStyleHint* aResult);
 
   virtual nsReStyleHint
     HasAttributeDependentStyle(AttributeRuleProcessorData* aData);
 
   NS_IMETHOD MediumFeaturesChanged(nsPresContext* aPresContext,
--- a/layout/style/nsHTMLCSSStyleSheet.cpp
+++ b/layout/style/nsHTMLCSSStyleSheet.cpp
@@ -88,17 +88,19 @@ public:
 
   // nsIStyleRuleProcessor api
   NS_IMETHOD RulesMatching(ElementRuleProcessorData* aData);
 
   NS_IMETHOD RulesMatching(PseudoElementRuleProcessorData* aData);
 
   NS_IMETHOD RulesMatching(AnonBoxRuleProcessorData* aData);
 
-  NS_IMETHOD RulesMatching(PseudoRuleProcessorData* aData);
+#ifdef MOZ_XUL
+  NS_IMETHOD RulesMatching(XULTreeRuleProcessorData* aData);
+#endif
 
   NS_IMETHOD HasStateDependentStyle(StateRuleProcessorData* aData,
                                     nsReStyleHint* aResult);
 
   virtual nsReStyleHint
     HasAttributeDependentStyle(AttributeRuleProcessorData* aData);
   NS_IMETHOD MediumFeaturesChanged(nsPresContext* aPresContext,
                                   PRBool* aResult);
@@ -165,21 +167,23 @@ HTMLCSSStyleSheetImpl::RulesMatching(Pse
 }
 
 NS_IMETHODIMP
 HTMLCSSStyleSheetImpl::RulesMatching(AnonBoxRuleProcessorData* aData)
 {
   return NS_OK;
 }
 
+#ifdef MOZ_XUL
 NS_IMETHODIMP
-HTMLCSSStyleSheetImpl::RulesMatching(PseudoRuleProcessorData* aData)
+HTMLCSSStyleSheetImpl::RulesMatching(XULTreeRuleProcessorData* aData)
 {
   return NS_OK;
 }
+#endif
 
 NS_IMETHODIMP
 HTMLCSSStyleSheetImpl::Init(nsIURI* aURL, nsIDocument* aDocument)
 {
   NS_PRECONDITION(aURL && aDocument, "null ptr");
   if (! aURL || ! aDocument)
     return NS_ERROR_NULL_POINTER;
 
--- a/layout/style/nsHTMLStyleSheet.cpp
+++ b/layout/style/nsHTMLStyleSheet.cpp
@@ -576,22 +576,23 @@ nsHTMLStyleSheet::RulesMatching(AnonBoxR
     nsRuleWalker *ruleWalker = aData->mRuleWalker;
     if (ruleWalker) {
       ruleWalker->Forward(mTableColRule);
     }
   }
   return NS_OK;
 }
 
+#ifdef MOZ_XUL
 NS_IMETHODIMP
-nsHTMLStyleSheet::RulesMatching(PseudoRuleProcessorData* aData)
+nsHTMLStyleSheet::RulesMatching(XULTreeRuleProcessorData* aData)
 {
   return NS_OK;
 }
-
+#endif
 
   // 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
@@ -76,17 +76,19 @@ public:
 #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);
+#ifdef MOZ_XUL
+  NS_IMETHOD RulesMatching(XULTreeRuleProcessorData* aData);
+#endif
   NS_IMETHOD HasStateDependentStyle(StateRuleProcessorData* aData,
                                     nsReStyleHint* aResult);
   virtual nsReStyleHint
     HasAttributeDependentStyle(AttributeRuleProcessorData* aData);
   NS_IMETHOD MediumFeaturesChanged(nsPresContext* aPresContext,
                                    PRBool* aRulesChanged);
 
   nsresult Init(nsIURI* aURL, nsIDocument* aDocument);
--- a/layout/style/nsIStyleRuleProcessor.h
+++ b/layout/style/nsIStyleRuleProcessor.h
@@ -48,25 +48,28 @@
 #include "nsISupports.h"
 #include "nsChangeHint.h"
 #include "nsIContent.h"
 
 struct RuleProcessorData;
 struct ElementRuleProcessorData;
 struct PseudoElementRuleProcessorData;
 struct AnonBoxRuleProcessorData;
-struct PseudoRuleProcessorData;
+#ifdef MOZ_XUL
+struct XULTreeRuleProcessorData;
+#endif
 struct StateRuleProcessorData;
 struct AttributeRuleProcessorData;
 class nsPresContext;
 
-// IID for the nsIStyleRuleProcessor interface {a4ec760e-6bfb-4b9f-bd08-9d1c23b700f6}
+// IID for the nsIStyleRuleProcessor interface
+// {ec92bc0c-9518-48ea-9289-74e654659be9}
 #define NS_ISTYLE_RULE_PROCESSOR_IID     \
-{ 0xa4ec760e, 0x6bfb, 0x4b9f, \
- { 0xbd, 0x08, 0x9d, 0x1c, 0x23, 0xb7, 0x00, 0xf6 } }
+{ 0xec92bc0c, 0x9518, 0x48ea, \
+ { 0x92, 0x89, 0x74, 0xe6, 0x54, 0x65, 0x9b, 0xe9 } }
 
 /* The style rule processor interface is a mechanism to separate the matching
  * of style rules from style sheet instances.
  * Simple style sheets can and will act as their own processor. 
  * Sheets where rule ordering interlaces between multiple sheets, will need to 
  * share a single rule processor between them (CSS sheets do this for cascading order)
  *
  * @see nsIStyleRule (for significantly more detailed comments)
@@ -93,21 +96,23 @@ public:
    */
   NS_IMETHOD RulesMatching(PseudoElementRuleProcessorData* aData) = 0;
 
   /**
    * Just like the previous |RulesMatching|, except for a given anonymous box.
    */
   NS_IMETHOD RulesMatching(AnonBoxRuleProcessorData* aData) = 0;
 
+#ifdef MOZ_XUL
   /**
    * Just like the previous |RulesMatching|, except for a given content
-   * node <em>and pseudo</em>.
+   * node <em>and tree pseudo</em>.
    */
-  NS_IMETHOD RulesMatching(PseudoRuleProcessorData* aData) = 0;
+  NS_IMETHOD RulesMatching(XULTreeRuleProcessorData* aData) = 0;
+#endif
 
   /**
    * Return how (as described by nsReStyleHint) style can depend on a
    * change of the given content state on the given content node.  This
    * test is used for optimization only, and may err on the side of
    * reporting more dependencies than really exist.
    *
    * Event states are defined in nsIEventStateManager.h.
--- a/layout/style/nsRuleProcessorData.h
+++ b/layout/style/nsRuleProcessorData.h
@@ -206,34 +206,37 @@ struct AnonBoxRuleProcessorData {
     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)
+#ifdef MOZ_XUL
+struct XULTreeRuleProcessorData : public RuleProcessorData {
+  XULTreeRuleProcessorData(nsPresContext* aPresContext,
+                           nsIContent* aParentContent,
+                           nsRuleWalker* aRuleWalker,
+                           nsIAtom* aPseudoTag,
+                           nsICSSPseudoComparator* aComparator)
+    : RuleProcessorData(aPresContext, aParentContent, aRuleWalker),
+      mPseudoTag(aPseudoTag),
+      mComparator(aComparator)
   {
     NS_PRECONDITION(aPresContext, "null pointer");
     NS_PRECONDITION(aPseudoTag, "null pointer");
     NS_PRECONDITION(aRuleWalker, "null pointer");
-    mPseudoTag = aPseudoTag;
-    mComparator = aComparator;
+    NS_PRECONDITION(aComparator, "must have a comparator");
   }
 
   nsIAtom*                 mPseudoTag;
   nsICSSPseudoComparator*  mComparator;
 };
+#endif
 
 struct StateRuleProcessorData : public RuleProcessorData {
   StateRuleProcessorData(nsPresContext* aPresContext,
                          nsIContent* aContent,
                          PRInt32 aStateMask)
     : RuleProcessorData(aPresContext, aContent, nsnull),
       mStateMask(aStateMask)
   {
--- a/layout/style/nsStyleSet.cpp
+++ b/layout/style/nsStyleSet.cpp
@@ -406,22 +406,21 @@ nsStyleSet::EnableQuirkStyleSheet(PRBool
   // (potentially implied) happens multiple times.
   if (mRuleProcessors[eAgentSheet] && aEnable != oldEnabled) {
     static_cast<nsCSSRuleProcessor*>(static_cast<nsIStyleRuleProcessor*>(
       mRuleProcessors[eAgentSheet]))->AssertQuirksChangeOK();
   }
 #endif
 }
 
+template<class T>
 static PRBool
 EnumRulesMatching(nsIStyleRuleProcessor* aProcessor, void* aData)
 {
-  ElementRuleProcessorData* data =
-    static_cast<ElementRuleProcessorData*>(aData);
-
+  T* data = static_cast<T*>(aData);
   aProcessor->RulesMatching(data);
   return PR_TRUE;
 }
 
 /**
  * |GetContext| implements sharing of style contexts (not just the data
  * on the rule nodes) between siblings and cousins of the same
  * generation.  (It works for cousins of the same generation since
@@ -743,17 +742,18 @@ 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, aContent, &ruleWalker);
+    FileRules(EnumRulesMatching<ElementRuleProcessorData>, &data, aContent,
+              &ruleWalker);
     result = GetContext(presContext, aParentContext,
                         ruleWalker.GetCurrentNode(), nsnull,
                         nsCSSPseudoElements::ePseudo_NotPseudoElement).get();
   }
 
   return result;
 }
 
@@ -807,75 +807,16 @@ nsStyleSet::WalkRestrictionRule(nsCSSPse
   // This needs to match GetPseudoRestriction in nsRuleNode.cpp.
   aRuleWalker->SetLevel(eAgentSheet, PR_FALSE, PR_FALSE);
   if (aPseudoType == nsCSSPseudoElements::ePseudo_firstLetter)
     aRuleWalker->Forward(mFirstLetterRule);
   else if (aPseudoType == nsCSSPseudoElements::ePseudo_firstLine)
     aRuleWalker->Forward(mFirstLineRule);
 }
 
-static PRBool
-EnumPseudoRulesMatching(nsIStyleRuleProcessor* aProcessor, void* aData)
-{
-  PseudoRuleProcessorData* data =
-    static_cast<PseudoRuleProcessorData*>(aData);
-
-  aProcessor->RulesMatching(data);
-  return PR_TRUE;
-}
-
-already_AddRefed<nsStyleContext>
-nsStyleSet::ResolvePseudoStyleFor(nsIContent* aParentContent,
-                                  nsIAtom* aPseudoTag,
-                                  nsCSSPseudoElements::Type aPseudoType,
-                                  nsStyleContext* aParentContext,
-                                  nsICSSPseudoComparator* aComparator)
-{
-  NS_ENSURE_FALSE(mInShutdown, nsnull);
-
-  nsStyleContext*  result = nsnull;
-  nsPresContext *presContext = PresContext();
-
-  NS_ASSERTION(aPseudoTag, "must have pseudo tag");
-  NS_ASSERTION(!aParentContent ||
-               aParentContent->IsNodeOfType(nsINode::eELEMENT),
-               "content (if non-null) must be element");
-  NS_ASSERTION(aParentContent ||
-               nsCSSAnonBoxes::IsAnonBox(aPseudoTag),
-               "null content must correspond to anonymous box");
-  NS_ASSERTION(nsCSSAnonBoxes::IsAnonBox(aPseudoTag) ||
-               nsCSSPseudoElements::IsPseudoElement(aPseudoTag),
-               "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, aParentContent, &ruleWalker);
-
-    result = GetContext(presContext, aParentContext,
-                        ruleWalker.GetCurrentNode(), aPseudoTag,
-                        aPseudoType).get();
-  }
-
-  return result;
-}
-
-static PRBool
-EnumPseudoElementRulesMatching(nsIStyleRuleProcessor* aProcessor, void* aData)
-{
-  PseudoElementRuleProcessorData* data =
-    static_cast<PseudoElementRuleProcessorData*>(aData);
-
-  aProcessor->RulesMatching(data);
-  return PR_TRUE;
-}
-
 already_AddRefed<nsStyleContext>
 nsStyleSet::ResolvePseudoElementStyle(nsIContent* aParentContent,
                                       nsCSSPseudoElements::Type aType,
                                       nsStyleContext* aParentContext)
 {
   NS_ENSURE_FALSE(mInShutdown, nsnull);
 
   NS_ASSERTION(aType < nsCSSPseudoElements::ePseudo_PseudoElementCount,
@@ -884,17 +825,18 @@ 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, aParentContent, &ruleWalker);
+  FileRules(EnumRulesMatching<PseudoElementRuleProcessorData>, &data,
+            aParentContent, &ruleWalker);
 
   return GetContext(presContext, aParentContext, ruleWalker.GetCurrentNode(),
                     nsCSSPseudoElements::GetPseudoAtom(aType), aType);
 }
 
 already_AddRefed<nsStyleContext>
 nsStyleSet::ProbePseudoElementStyle(nsIContent* aParentContent,
                                     nsCSSPseudoElements::Type aType,
@@ -913,17 +855,18 @@ 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, aParentContent, &ruleWalker);
+  FileRules(EnumRulesMatching<PseudoElementRuleProcessorData>, &data,
+            aParentContent, &ruleWalker);
 
   nsRuleNode *ruleNode = ruleWalker.GetCurrentNode();
   if (ruleNode == adjustedRoot) {
     return nsnull;
   }
 
   nsRefPtr<nsStyleContext> result =
     GetContext(presContext, aParentContext, ruleNode, pseudoTag, aType);
@@ -941,26 +884,16 @@ 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)
@@ -969,22 +902,51 @@ nsStyleSet::ResolveAnonymousBoxStyle(nsI
 #endif
       ;
     NS_PRECONDITION(isAnonBox, "Unexpected pseudo");
 #endif
 
   nsRuleWalker ruleWalker(mRuleTree);
   nsPresContext *presContext = PresContext();
   AnonBoxRuleProcessorData data(presContext, aPseudoTag, &ruleWalker);
-  FileRules(EnumAnonBoxRulesMatching, &data, nsnull, &ruleWalker);
+  FileRules(EnumRulesMatching<AnonBoxRuleProcessorData>, &data, nsnull,
+            &ruleWalker);
 
   return GetContext(presContext, aParentContext, ruleWalker.GetCurrentNode(),
                     aPseudoTag, nsCSSPseudoElements::ePseudo_AnonBox);
 }
 
+#ifdef MOZ_XUL
+already_AddRefed<nsStyleContext>
+nsStyleSet::ResolveXULTreePseudoStyle(nsIContent* aParentContent,
+                                      nsIAtom* aPseudoTag,
+                                      nsStyleContext* aParentContext,
+                                      nsICSSPseudoComparator* aComparator)
+{
+  NS_ENSURE_FALSE(mInShutdown, nsnull);
+
+  NS_ASSERTION(aPseudoTag, "must have pseudo tag");
+  NS_ASSERTION(aParentContent->IsNodeOfType(nsINode::eELEMENT),
+               "content (if non-null) must be element");
+  NS_ASSERTION(nsCSSAnonBoxes::IsTreePseudoElement(aPseudoTag),
+               "Unexpected pseudo");
+
+  nsRuleWalker ruleWalker(mRuleTree);
+  nsPresContext *presContext = PresContext();
+
+  XULTreeRuleProcessorData data(presContext, aParentContent, &ruleWalker,
+                                aPseudoTag, aComparator);
+  FileRules(EnumRulesMatching<XULTreeRuleProcessorData>, &data, aParentContent,
+            &ruleWalker);
+
+  return GetContext(presContext, aParentContext, ruleWalker.GetCurrentNode(),
+                    aPseudoTag, nsCSSPseudoElements::ePseudo_XULTree);
+}
+#endif
+
 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
@@ -145,37 +145,19 @@ class nsStyleSet
 #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,
                             nsStyleContext* aParentContext,
-                            nsICSSPseudoComparator* aComparator) {
-    NS_PRECONDITION(nsCSSAnonBoxes::IsTreePseudoElement(aPseudoTag),
-                    "Unexpected pseudo");
-    return ResolvePseudoStyleFor(aParentContent, aPseudoTag,
-                                 nsCSSPseudoElements::ePseudo_XULTree,
-                                 aParentContext, aComparator);
-  }
+                            nsICSSPseudoComparator* aComparator);
 #endif
 
-private:
-  // get a style context for a pseudo-element (i.e.,
-  // |aPseudoTag == nsCOMPtr<nsIAtom>(do_GetAtom(":first-line"))|, in
-  // which case aParentContent must be non-null, or an anonymous box, in
-  // which case it may be null or non-null.
-  already_AddRefed<nsStyleContext>
-  ResolvePseudoStyleFor(nsIContent* aParentContent,
-                        nsIAtom* aPseudoTag,
-                        nsCSSPseudoElements::Type aPseudoType,
-                        nsStyleContext* aParentContext,
-                        nsICSSPseudoComparator* aComparator = nsnull);
-public:
   // Append all the currently-active font face rules to aArray.  Return
   // true for success and false for failure.
   PRBool AppendFontFaceRules(nsPresContext* aPresContext,
                              nsTArray<nsFontFaceRuleContainer>& aArray);
 
   // Begin ignoring style context destruction, to avoid lots of unnecessary
   // work on document teardown.
   void BeginShutdown(nsPresContext* aPresContext);
--- a/layout/style/nsTransitionManager.cpp
+++ b/layout/style/nsTransitionManager.cpp
@@ -762,21 +762,23 @@ nsTransitionManager::RulesMatching(Pseud
 }
 
 NS_IMETHODIMP
 nsTransitionManager::RulesMatching(AnonBoxRuleProcessorData* aData)
 {
   return NS_OK;
 }
 
+#ifdef MOZ_XUL
 NS_IMETHODIMP
-nsTransitionManager::RulesMatching(PseudoRuleProcessorData* aData)
+nsTransitionManager::RulesMatching(XULTreeRuleProcessorData* aData)
 {
   return NS_OK;
 }
+#endif
 
 NS_IMETHODIMP
 nsTransitionManager::HasStateDependentStyle(StateRuleProcessorData* aData,
                                             nsReStyleHint* aResult)
 {
   *aResult = nsReStyleHint(0);
   return NS_OK;
 }
--- a/layout/style/nsTransitionManager.h
+++ b/layout/style/nsTransitionManager.h
@@ -83,17 +83,19 @@ public:
 
   // 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);
+#ifdef MOZ_XUL
+  NS_IMETHOD RulesMatching(XULTreeRuleProcessorData* aData);
+#endif
   NS_IMETHOD HasStateDependentStyle(StateRuleProcessorData* aData,
                                     nsReStyleHint* aResult);
   virtual nsReStyleHint
     HasAttributeDependentStyle(AttributeRuleProcessorData* aData);
   NS_IMETHOD MediumFeaturesChanged(nsPresContext* aPresContext,
                                    PRBool* aRulesChanged);
 
   // nsARefreshObserver