Bug 523288 part 3. Do a bit less work still in the RuleProcessorData constructor. r=dbaron
authorBoris Zbarsky <bzbarsky@mit.edu>
Thu, 10 Dec 2009 14:36:03 -0800
changeset 35532 a6508c37eb412b22e4e3b53a376788f54c423b1f
parent 35531 b3636bfdc6d938963b31a682aae2608011bfd137
child 35533 eb86d6432f02609e3f2e748103b5be2a1749a81e
push id10631
push userbzbarsky@mozilla.com
push dateThu, 10 Dec 2009 22:48:24 +0000
treeherdermozilla-central@08b48be6951b [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersdbaron
bugs523288
milestone1.9.3a1pre
Bug 523288 part 3. Do a bit less work still in the RuleProcessorData constructor. r=dbaron
layout/style/nsCSSRuleProcessor.cpp
layout/style/nsRuleProcessorData.h
--- a/layout/style/nsCSSRuleProcessor.cpp
+++ b/layout/style/nsCSSRuleProcessor.cpp
@@ -892,42 +892,31 @@ nsCSSRuleProcessor::HasSystemMetric(nsIA
   }
   return sSystemMetrics->IndexOf(aMetric) != sSystemMetrics->NoIndex;
 }
 
 RuleProcessorData::RuleProcessorData(nsPresContext* aPresContext,
                                      nsIContent* aContent, 
                                      nsRuleWalker* aRuleWalker,
                                      nsCompatibility* aCompat /*= nsnull*/)
+  : mPresContext(aPresContext),
+    mContent(aContent),
+    mRuleWalker(aRuleWalker),
+    mScopedRoot(nsnull),
+    mPreviousSiblingData(nsnull),
+    mParentData(nsnull),
+    mLanguage(nsnull),
+    mGotContentState(PR_FALSE),
+    mGotLinkInfo(PR_FALSE)
 {
   MOZ_COUNT_CTOR(RuleProcessorData);
 
   NS_ASSERTION(!aContent || aContent->IsNodeOfType(nsINode::eELEMENT),
                "non-element leaked into SelectorMatches");
 
-  mPresContext = aPresContext;
-  mContent = aContent;
-  mParentContent = nsnull;
-  mRuleWalker = aRuleWalker;
-  mScopedRoot = nsnull;
-
-  mContentTag = nsnull;
-  mContentID = nsnull;
-  mHasAttributes = PR_FALSE;
-  mIsHTMLContent = PR_FALSE;
-  mIsLink = PR_FALSE;
-  mGotLinkInfo = PR_FALSE;
-  mLinkState = eLinkState_Unknown;
-  mContentState = 0;
-  mGotContentState = PR_FALSE;
-  mNameSpaceID = kNameSpaceID_Unknown;
-  mPreviousSiblingData = nsnull;
-  mParentData = nsnull;
-  mLanguage = nsnull;
-  mClasses = nsnull;
   mNthIndices[0][0] = -2;
   mNthIndices[0][1] = -2;
   mNthIndices[1][0] = -2;
   mNthIndices[1][1] = -2;
 
   // get the compat. mode (unless it is provided)
   // XXXbz is passing in the compat mode really that much of an optimization?
   if (aCompat) {
@@ -935,36 +924,56 @@ RuleProcessorData::RuleProcessorData(nsP
   } else if (NS_LIKELY(mPresContext)) {
     mCompatMode = mPresContext->CompatibilityMode();
   } else {
     NS_ASSERTION(aContent, "Must have content");
     NS_ASSERTION(aContent->GetOwnerDoc(), "Must have document");
     mCompatMode = aContent->GetOwnerDoc()->GetCompatibilityMode();
   }
 
-  if (aContent) {
+  if (NS_LIKELY(aContent)) {
     NS_ASSERTION(aContent->GetOwnerDoc(), "Document-less node here?");
     
     // get the tag and parent
     mContentTag = aContent->Tag();
     mParentContent = aContent->GetParent();
 
-    // get the ID and classes for the content
-    mContentID = aContent->GetID();
-    mClasses = aContent->GetClasses();
-
     // see if there are attributes for the content
     mHasAttributes = aContent->GetAttrCount() > 0;
+    if (mHasAttributes) {
+      // get the ID and classes for the content
+      mContentID = aContent->GetID();
+      mClasses = aContent->GetClasses();
+    } else {
+      mContentID = nsnull;
+      mClasses = nsnull;
+    }
 
     // get the namespace
     mNameSpaceID = aContent->GetNameSpaceID();
 
-    // check for HTMLContent and Link status
+    // check for HTMLContent status
     mIsHTMLContent = (mNameSpaceID == kNameSpaceID_XHTML);
+    mIsHTML = mIsHTMLContent && aContent->IsInHTMLDocument();
+  } else {
+    mContentTag = nsnull;
+    mParentContent = nsnull;
+    mContentID = nsnull;
+    mClasses = nsnull;
+    mHasAttributes = PR_FALSE;
+    mNameSpaceID = kNameSpaceID_Unknown;
+    mIsHTMLContent = PR_FALSE;
+    mIsHTML = PR_FALSE;
   }
+
+  // No need to initialize mIsLink or mLinkState; the IsLink() accessor will
+  // handle that.
+
+  // No need to initialize mContentState; the ContentState() accessor will handle
+  // that.
 }
 
 RuleProcessorData::~RuleProcessorData()
 {
   MOZ_COUNT_DTOR(RuleProcessorData);
 
   // Destroy potentially long chains of previous sibling and parent data
   // without more than one level of recursion.
@@ -1022,16 +1031,17 @@ const nsString* RuleProcessorData::GetLa
   return mLanguage;
 }
 
 PRUint32
 RuleProcessorData::ContentState()
 {
   if (!mGotContentState) {
     mGotContentState = PR_TRUE;
+    mContentState = 0;
     if (mContent) {
       if (mPresContext) {
         mPresContext->EventStateManager()->GetContentState(mContent,
                                                            mContentState);
       } else {
         mContentState = mContent->IntrinsicState();
       }
     }
@@ -1039,16 +1049,18 @@ RuleProcessorData::ContentState()
   return mContentState;
 }
 
 PRBool
 RuleProcessorData::IsLink()
 {
   if (!mGotLinkInfo) {
     mGotLinkInfo = PR_TRUE;
+    mLinkState = eLinkState_Unknown;
+    mIsLink = PR_FALSE;
     if (mContent) {
       // if HTML content and it has some attributes, check for an HTML link
       // NOTE: optimization: cannot be a link if no attributes (since it needs
       // an href)
       nsILinkHandler* linkHandler =
         mPresContext ? mPresContext->GetLinkHandler() : nsnull;
       if (mIsHTMLContent && mHasAttributes) {
         // check if it is an HTML Link
@@ -1279,21 +1291,18 @@ static PRBool SelectorMatches(RuleProces
 
 {
   // namespace/tag match
   // optimization : bail out early if we can
   if ((kNameSpaceID_Unknown != aSelector->mNameSpace &&
        data.mNameSpaceID != aSelector->mNameSpace))
     return PR_FALSE;
 
-  const PRBool isHTML =
-    data.mIsHTMLContent && data.mContent->GetOwnerDoc()->IsHTML();
-
   if (aSelector->mLowercaseTag && 
-      (isHTML ? aSelector->mLowercaseTag : aSelector->mCasedTag) !=
+      (data.mIsHTML ? aSelector->mLowercaseTag : aSelector->mCasedTag) !=
         data.mContentTag) {
     return PR_FALSE;
   }
 
   nsAtomList* IDList = aSelector->mIDList;
   if (IDList) {
     // test for ID match
     if (aAttribute && aAttribute == data.mContent->GetIDAttributeName()) {
@@ -1629,17 +1638,17 @@ static PRBool SelectorMatches(RuleProces
           result = PR_TRUE;
         }
         else {
           NS_ASSERTION(nsCSSPseudoClasses::link == pseudoClass->mAtom ||
                        nsCSSPseudoClasses::visited == pseudoClass->mAtom,
                        "somebody changed IsLinkPseudo");
           NS_ASSERTION(data.LinkState() == eLinkState_Unvisited ||
                        data.LinkState() == eLinkState_Visited,
-                       "unexpected link state for mIsLink");
+                       "unexpected link state for IsLink()");
           if (aStateMask & NS_EVENT_STATE_VISITED) {
             result = PR_TRUE;
             if (aDependence)
               *aDependence = PR_TRUE;
           } else {
             result = ((eLinkState_Unvisited == data.LinkState()) ==
                       (nsCSSPseudoClasses::link == pseudoClass->mAtom));
           }
@@ -1709,17 +1718,17 @@ static PRBool SelectorMatches(RuleProces
     }
     else if (nsCSSPseudoClasses::mozReadWrite == pseudoClass->mAtom) {
       stateToCheck = NS_EVENT_STATE_MOZ_READWRITE;
     }
     else if (nsCSSPseudoClasses::indeterminate == pseudoClass->mAtom) {
       stateToCheck = NS_EVENT_STATE_INDETERMINATE;
     }
     else if (nsCSSPseudoClasses::mozIsHTML == pseudoClass->mAtom) {
-      result = data.mIsHTMLContent && data.mContent->IsInHTMLDocument();
+      result = data.mIsHTML;
     }
     else if (nsCSSPseudoClasses::mozLocaleDir == pseudoClass->mAtom) {
       nsIDocument* doc = data.mContent ? data.mContent->GetDocument() :
                                          data.mPresContext->Document();
 
       if (doc) {
         PRBool docIsRTL = doc && doc->IsDocumentRightToLeft();
 
@@ -1815,17 +1824,17 @@ static PRBool SelectorMatches(RuleProces
       NS_ASSERTION(data.mContent,
                    "Must have content if either data.mHasAttributes or "
                    "aAttribute is set!");
       result = PR_TRUE;
       nsAttrSelector* attr = aSelector->mAttrList;
       nsIAtom* matchAttribute;
 
       do {
-        matchAttribute = isHTML ? attr->mLowercaseAttr : attr->mCasedAttr;
+        matchAttribute = data.mIsHTML ? attr->mLowercaseAttr : attr->mCasedAttr;
         if (matchAttribute == aAttribute) {
           // XXX we should really have a namespace, not just an attr
           // name, in HasAttributeDependentStyle!
           result = PR_TRUE;
           if (aDependence)
             *aDependence = PR_TRUE;
         }
         else if (attr->mNameSpace == kNameSpaceID_Unknown) {
@@ -1850,47 +1859,47 @@ static PRBool SelectorMatches(RuleProces
             } else {
               nsAutoString value;
 #ifdef DEBUG
               PRBool hasAttr =
 #endif
                 data.mContent->GetAttr(attrName->NamespaceID(),
                                        attrName->LocalName(), value);
               NS_ASSERTION(hasAttr, "GetAttrNameAt lied");
-              result = AttrMatchesValue(attr, value, isHTML);
+              result = AttrMatchesValue(attr, value, data.mIsHTML);
             }
 
             // At this point |result| has been set by us
             // explicitly in this loop.  If it's PR_FALSE, we may still match
             // -- the content may have another attribute with the same name but
             // in a different namespace.  But if it's PR_TRUE, we are done (we
             // can short-circuit the boolean OR described above).
             if (result) {
               break;
             }
           }
         }
         else if (attr->mFunction == NS_ATTR_FUNC_EQUALS) {
           result =
             data.mContent->
               AttrValueIs(attr->mNameSpace, matchAttribute, attr->mValue,
-                          (!isHTML || attr->mCaseSensitive) ? eCaseMatters
-                                                            : eIgnoreCase);
+                          (!data.mIsHTML || attr->mCaseSensitive) ? eCaseMatters
+                                                                  : eIgnoreCase);
         }
         else if (!data.mContent->HasAttr(attr->mNameSpace, matchAttribute)) {
           result = PR_FALSE;
         }
         else if (attr->mFunction != NS_ATTR_FUNC_SET) {
           nsAutoString value;
 #ifdef DEBUG
           PRBool hasAttr =
 #endif
               data.mContent->GetAttr(attr->mNameSpace, matchAttribute, value);
           NS_ASSERTION(hasAttr, "HasAttr lied");
-          result = AttrMatchesValue(attr, value, isHTML);
+          result = AttrMatchesValue(attr, value, data.mIsHTML);
         }
         
         attr = attr->mNext;
       } while (attr && result);
     }
   }
 
   // apply SelectorMatches to the negated selectors in the chain
@@ -1933,17 +1942,17 @@ static PRBool SelectorMatchesTree(RulePr
     // for adjacent sibling combinators, the content to test against the
     // selector is the previous sibling *element*
     RuleProcessorData* data;
     if (PRUnichar('+') == selector->mOperator ||
         PRUnichar('~') == selector->mOperator) {
       data = prevdata->mPreviousSiblingData;
       if (!data) {
         nsIContent* content = prevdata->mContent;
-        nsIContent* parent = content->GetParent();
+        nsIContent* parent = prevdata->mParentContent;
         if (parent) {
           parent->SetFlags(NODE_HAS_SLOW_SELECTOR_NOAPPEND);
 
           PRInt32 index = parent->IndexOf(content);
           while (0 <= --index) {
             content = parent->GetChildAt(index);
             if (content->IsNodeOfType(nsINode::eELEMENT)) {
               data = RuleProcessorData::Create(prevdata->mPresContext, content,
@@ -1956,24 +1965,24 @@ static PRBool SelectorMatchesTree(RulePr
         }
       }
     }
     // for descendant combinators and child combinators, the content
     // to test against is the parent
     else {
       data = prevdata->mParentData;
       if (!data) {
-        nsIContent *content = prevdata->mContent->GetParent();
+        nsIContent *content = prevdata->mParentContent;
         // GetParent could return a document fragment; we only want
         // element parents.
         if (content && content->IsNodeOfType(nsINode::eELEMENT)) {
           data = RuleProcessorData::Create(prevdata->mPresContext, content,
                                            prevdata->mRuleWalker,
                                            prevdata->mCompatMode);
-          prevdata->mParentData = data;    
+          prevdata->mParentData = data;
         }
       }
     }
     if (! data) {
       return PR_FALSE;
     }
     if (SelectorMatches(*data, selector, 0, nsnull, aForStyling)) {
       // to avoid greedy matching, we need to recur if this is a
--- a/layout/style/nsRuleProcessorData.h
+++ b/layout/style/nsRuleProcessorData.h
@@ -125,17 +125,18 @@ public:
   nsPresContext*    mPresContext;
   nsIContent*       mContent;       // weak ref
   nsIContent*       mParentContent; // if content, content->GetParent(); weak ref
   nsRuleWalker*     mRuleWalker; // Used to add rules to our results.
   nsIContent*       mScopedRoot;    // Root of scoped stylesheet (set and unset by the supplier of the scoped stylesheet
   
   nsIAtom*          mContentTag;    // if content, then content->GetTag()
   nsIAtom*          mContentID;     // if styled content, then weak reference to styledcontent->GetID()
-  PRPackedBool      mIsHTMLContent; // if content, then does QI on HTMLContent, true or false
+  PRPackedBool      mIsHTMLContent; // if content, then whether it's IsHTML()
+  PRPackedBool      mIsHTML;        // if content then mIsHTMLContent && IsInHTMLDocument()
   PRPackedBool      mHasAttributes; // if content, content->GetAttrCount() > 0
   nsCompatibility   mCompatMode;    // Possibly remove use of this in SelectorMatches?
   PRInt32           mNameSpaceID;   // if content, content->GetNameSapce()
   const nsAttrValue* mClasses;      // if styled content, styledcontent->GetClasses()
   // mPreviousSiblingData and mParentData are always RuleProcessorData
   // and never a derived class.  They are allocated lazily, when
   // selectors require matching of prior siblings or ancestors.
   RuleProcessorData* mPreviousSiblingData;