Bug 661746 - Part 2: Make selector matching work with const elements. r=bzbarsky
authorDavid Zbarsky <dzbarsky@gmail.com>
Mon, 14 Nov 2011 16:30:08 +1300
changeset 80218 1cb3705557d9d5cae86418bc2bb3402be7d5a62b
parent 80217 03970d1fc9191ff84c8d1ec538b56ba4ecda16b6
child 80219 61534874aed701ddc982605d4864229e6d19896c
push id323
push userrcampbell@mozilla.com
push dateTue, 15 Nov 2011 21:58:36 +0000
treeherderfx-team@3ea216303184 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersbzbarsky
bugs661746
milestone11.0a1
Bug 661746 - Part 2: Make selector matching work with const elements. r=bzbarsky
content/base/public/Element.h
content/base/public/nsIContent.h
content/base/public/nsINode.h
content/base/src/nsGenericDOMDataNode.cpp
content/base/src/nsGenericDOMDataNode.h
content/base/src/nsGenericElement.cpp
content/base/src/nsGenericElement.h
layout/style/nsCSSRuleProcessor.cpp
layout/style/nsCSSRuleProcessor.h
layout/style/nsNthIndexCache.cpp
layout/style/nsNthIndexCache.h
layout/style/nsStyleUtil.cpp
layout/style/nsStyleUtil.h
--- a/content/base/public/Element.h
+++ b/content/base/public/Element.h
@@ -190,9 +190,14 @@ private:
 } // namespace dom
 } // namespace mozilla
 
 inline mozilla::dom::Element* nsINode::AsElement() {
   NS_ASSERTION(IsElement(), "Not an element?");
   return static_cast<mozilla::dom::Element*>(this);
 }
 
+inline const mozilla::dom::Element* nsINode::AsElement() const {
+  NS_ASSERTION(IsElement(), "Not an element?");
+  return static_cast<const mozilla::dom::Element*>(this);
+}
+
 #endif // mozilla_dom_Element_h__
--- a/content/base/public/nsIContent.h
+++ b/content/base/public/nsIContent.h
@@ -513,17 +513,17 @@ public:
    * it is simply null;
    */
   virtual const nsTextFragment *GetText() = 0;
 
   /**
    * Get the length of the text content.
    * NOTE: This should not be called on elements.
    */
-  virtual PRUint32 TextLength() = 0;
+  virtual PRUint32 TextLength() const = 0;
 
   /**
    * Set the text to the given value. If aNotify is true then
    * the document is notified of the content change.
    * NOTE: For elements this always ASSERTS and returns NS_ERROR_FAILURE
    */
   virtual nsresult SetText(const PRUnichar* aBuffer, PRUint32 aLength,
                            bool aNotify) = 0;
@@ -545,17 +545,17 @@ public:
   {
     return SetText(aStr.BeginReading(), aStr.Length(), aNotify);
   }
 
   /**
    * Query method to see if the frame is nothing but whitespace
    * NOTE: Always returns false for elements
    */
-  virtual bool TextIsOnlyWhitespace() = 0;
+  virtual bool TextIsOnlyWhitespace() const = 0;
 
   /**
    * Append the text content to aResult.
    * NOTE: This asserts and returns for elements
    */
   virtual void AppendTextTo(nsAString& aResult) = 0;
 
   /**
--- a/content/base/public/nsINode.h
+++ b/content/base/public/nsINode.h
@@ -374,16 +374,17 @@ public:
     return GetBoolFlag(NodeIsElement);
   }
 
   /**
    * Return this node as an Element.  Should only be used for nodes
    * for which IsElement() is true.
    */
   mozilla::dom::Element* AsElement();
+  const mozilla::dom::Element* AsElement() const;
 
   /**
    * Get the number of children
    * @return the number of children
    */
   virtual PRUint32 GetChildCount() const = 0;
 
   /**
--- a/content/base/src/nsGenericDOMDataNode.cpp
+++ b/content/base/src/nsGenericDOMDataNode.cpp
@@ -844,17 +844,17 @@ nsGenericDOMDataNode::GetWholeText(nsASt
 
 const nsTextFragment *
 nsGenericDOMDataNode::GetText()
 {
   return &mText;
 }
 
 PRUint32
-nsGenericDOMDataNode::TextLength()
+nsGenericDOMDataNode::TextLength() const
 {
   return mText.GetLength();
 }
 
 nsresult
 nsGenericDOMDataNode::SetText(const PRUnichar* aBuffer,
                               PRUint32 aLength,
                               bool aNotify)
@@ -866,17 +866,17 @@ nsresult
 nsGenericDOMDataNode::AppendText(const PRUnichar* aBuffer,
                                  PRUint32 aLength,
                                  bool aNotify)
 {
   return SetTextInternal(mText.GetLength(), 0, aBuffer, aLength, aNotify);
 }
 
 bool
-nsGenericDOMDataNode::TextIsOnlyWhitespace()
+nsGenericDOMDataNode::TextIsOnlyWhitespace() const
 {
   if (mText.Is2b()) {
     // The fragment contains non-8bit characters and such characters
     // are never considered whitespace.
     return false;
   }
 
   const char* cp = mText.Get1b();
--- a/content/base/src/nsGenericDOMDataNode.h
+++ b/content/base/src/nsGenericDOMDataNode.h
@@ -206,27 +206,27 @@ public:
   virtual nsresult UnsetAttr(PRInt32 aNameSpaceID, nsIAtom* aAttribute,
                              bool aNotify);
   virtual bool GetAttr(PRInt32 aNameSpaceID, nsIAtom *aAttribute,
                          nsAString& aResult) const;
   virtual bool HasAttr(PRInt32 aNameSpaceID, nsIAtom *aAttribute) const;
   virtual const nsAttrName* GetAttrNameAt(PRUint32 aIndex) const;
   virtual PRUint32 GetAttrCount() const;
   virtual const nsTextFragment *GetText();
-  virtual PRUint32 TextLength();
+  virtual PRUint32 TextLength() const;
   virtual nsresult SetText(const PRUnichar* aBuffer, PRUint32 aLength,
                            bool aNotify);
   // Need to implement this here too to avoid hiding.
   nsresult SetText(const nsAString& aStr, bool aNotify)
   {
     return SetText(aStr.BeginReading(), aStr.Length(), aNotify);
   }
   virtual nsresult AppendText(const PRUnichar* aBuffer, PRUint32 aLength,
                               bool aNotify);
-  virtual bool TextIsOnlyWhitespace();
+  virtual bool TextIsOnlyWhitespace() const;
   virtual void AppendTextTo(nsAString& aResult);
   virtual void DestroyContent();
   virtual void SaveSubtreeState();
 
   virtual nsISMILAttr* GetAnimatedAttr(PRInt32 /*aNamespaceID*/, nsIAtom* /*aName*/)
   {
     return nsnull;
   }
--- a/content/base/src/nsGenericElement.cpp
+++ b/content/base/src/nsGenericElement.cpp
@@ -4884,17 +4884,17 @@ nsGenericElement::GetAttrCount() const
 
 const nsTextFragment*
 nsGenericElement::GetText()
 {
   return nsnull;
 }
 
 PRUint32
-nsGenericElement::TextLength()
+nsGenericElement::TextLength() const
 {
   // We can remove this assertion if it turns out to be useful to be able
   // to depend on this returning 0
   NS_NOTREACHED("called nsGenericElement::TextLength");
 
   return 0;
 }
 
@@ -4912,17 +4912,17 @@ nsGenericElement::AppendText(const PRUni
                              bool aNotify)
 {
   NS_ERROR("called nsGenericElement::AppendText");
 
   return NS_ERROR_FAILURE;
 }
 
 bool
-nsGenericElement::TextIsOnlyWhitespace()
+nsGenericElement::TextIsOnlyWhitespace() const
 {
   return false;
 }
 
 void
 nsGenericElement::AppendTextTo(nsAString& aResult)
 {
   // We can remove this assertion if it turns out to be useful to be able
--- a/content/base/src/nsGenericElement.h
+++ b/content/base/src/nsGenericElement.h
@@ -320,27 +320,27 @@ public:
                                   nsIAtom* aName,
                                   AttrValuesArray* aValues,
                                   nsCaseTreatment aCaseSensitive) const;
   virtual nsresult UnsetAttr(PRInt32 aNameSpaceID, nsIAtom* aAttribute,
                              bool aNotify);
   virtual const nsAttrName* GetAttrNameAt(PRUint32 aIndex) const;
   virtual PRUint32 GetAttrCount() const;
   virtual const nsTextFragment *GetText();
-  virtual PRUint32 TextLength();
+  virtual PRUint32 TextLength() const;
   virtual nsresult SetText(const PRUnichar* aBuffer, PRUint32 aLength,
                            bool aNotify);
   // Need to implement this here too to avoid hiding.
   nsresult SetText(const nsAString& aStr, bool aNotify)
   {
     return SetText(aStr.BeginReading(), aStr.Length(), aNotify);
   }
   virtual nsresult AppendText(const PRUnichar* aBuffer, PRUint32 aLength,
                               bool aNotify);
-  virtual bool TextIsOnlyWhitespace();
+  virtual bool TextIsOnlyWhitespace() const;
   virtual void AppendTextTo(nsAString& aResult);
   virtual nsIContent *GetBindingParent() const;
   virtual bool IsNodeOfType(PRUint32 aFlags) const;
   virtual bool IsLink(nsIURI** aURI) const;
 
   virtual PRUint32 GetScriptTypeID() const;
   NS_IMETHOD SetScriptTypeID(PRUint32 aLang);
 
--- a/layout/style/nsCSSRuleProcessor.cpp
+++ b/layout/style/nsCSSRuleProcessor.cpp
@@ -414,17 +414,17 @@ static const PLDHashTableOps RuleHash_Na
 
 struct NodeMatchContext;
 
 class RuleHash {
 public:
   RuleHash(bool aQuirksMode);
   ~RuleHash();
   void AppendRule(const RuleSelectorPair &aRuleInfo);
-  void EnumerateAllRules(Element* aElement, RuleProcessorData* aData,
+  void EnumerateAllRules(const Element* aElement, RuleProcessorData* aData,
                          NodeMatchContext& aNodeMatchContext);
   PLArenaPool& Arena() { return mArena; }
 
   PRInt64 SizeOf() const;
 
 protected:
   typedef nsTArray<RuleValue> RuleValueList;
   void AppendRuleToTable(PLDHashTable* aTable, const void* aKey,
@@ -626,17 +626,17 @@ void RuleHash::AppendRule(const RuleSele
 #define RULE_HASH_STAT_INCREMENT_LIST_COUNT(list_, var_) \
   PR_BEGIN_MACRO PR_END_MACRO
 #endif
 
 static inline
 void ContentEnumFunc(css::StyleRule* aRule, nsCSSSelector* aSelector,
                      RuleProcessorData* data, NodeMatchContext& nodeContext);
 
-void RuleHash::EnumerateAllRules(Element* aElement, RuleProcessorData* aData,
+void RuleHash::EnumerateAllRules(const Element* aElement, RuleProcessorData* aData,
                                  NodeMatchContext& aNodeContext)
 {
   PRInt32 nameSpace = aElement->GetNameSpaceID();
   nsIAtom* tag = aElement->Tag();
   nsIAtom* id = aElement->GetID();
   const nsAttrValue* classList = aElement->GetClasses();
 
   NS_ABORT_IF_FALSE(tag, "How could we not have a tag?");
@@ -1242,17 +1242,17 @@ nsCSSRuleProcessor::GetWindowsThemeIdent
   if (!sSystemMetrics)
     InitSystemMetrics();
   return sWinThemeId;
 }
 #endif
 
 /* static */
 nsEventStates
-nsCSSRuleProcessor::GetContentState(Element* aElement)
+nsCSSRuleProcessor::GetContentState(const Element* aElement)
 {
   nsEventStates state = aElement->State();
 
   // If we are not supposed to mark visited links as such, be sure to
   // flip the bits appropriately.  We want to do this here, rather
   // than in GetContentStateForVisitedHandling, so that we don't
   // expose that :visited support is disabled to the Web page.
   if (state.HasState(NS_EVENT_STATE_VISITED) &&
@@ -1262,26 +1262,26 @@ nsCSSRuleProcessor::GetContentState(Elem
     state &= ~NS_EVENT_STATE_VISITED;
     state |= NS_EVENT_STATE_UNVISITED;
   }
   return state;
 }
 
 /* static */
 bool
-nsCSSRuleProcessor::IsLink(Element* aElement)
+nsCSSRuleProcessor::IsLink(const Element* aElement)
 {
   nsEventStates state = aElement->State();
   return state.HasAtLeastOneOfStates(NS_EVENT_STATE_VISITED | NS_EVENT_STATE_UNVISITED);
 }
 
 /* static */
 nsEventStates
 nsCSSRuleProcessor::GetContentStateForVisitedHandling(
-                     Element* aElement,
+                     const Element* aElement,
                      nsRuleWalker::VisitedHandlingType aVisitedHandling,
                      bool aIsRelevantLink)
 {
   nsEventStates contentState = GetContentState(aElement);
   if (contentState.HasAtLeastOneOfStates(NS_EVENT_STATE_VISITED | NS_EVENT_STATE_UNVISITED)) {
     NS_ABORT_IF_FALSE(IsLink(aElement), "IsLink() should match state");
     contentState &= ~(NS_EVENT_STATE_VISITED | NS_EVENT_STATE_UNVISITED);
     if (aIsRelevantLink) {
@@ -1385,17 +1385,17 @@ inline bool IsQuirkEventSensitive(nsIAto
                  (nsGkAtoms::input == aContentTag)  ||
                  (nsGkAtoms::label == aContentTag)  ||
                  (nsGkAtoms::select == aContentTag) ||
                  (nsGkAtoms::textarea == aContentTag));
 }
 
 
 static inline bool
-IsSignificantChild(nsIContent* aChild, bool aTextIsSignificant,
+IsSignificantChild(const nsIContent* aChild, bool aTextIsSignificant,
                    bool aWhitespaceIsSignificant)
 {
   return nsStyleUtil::IsSignificantChild(aChild, aTextIsSignificant,
                                          aWhitespaceIsSignificant);
 }
 
 // This function is to be called once we have fetched a value for an attribute
 // whose namespace and name match those of aAttrSelector.  This function
@@ -1437,42 +1437,42 @@ static bool AttrMatchesValue(const nsAtt
       return FindInReadable(aAttrSelector->mValue, aValue, comparator);
     default:
       NS_NOTREACHED("Shouldn't be ending up here");
       return false;
   }
 }
 
 static inline bool
-edgeChildMatches(Element* aElement, TreeMatchContext& aTreeMatchContext,
+edgeChildMatches(const Element* aElement, TreeMatchContext& aTreeMatchContext,
                  bool checkFirst, bool checkLast)
 {
-  nsIContent *parent = aElement->GetParent();
+  const nsIContent *parent = aElement->GetParent();
   if (!parent) {
     return false;
   }
 
   if (aTreeMatchContext.mForStyling)
     aTreeMatchContext.RecordFlagsToAdd(parent, NODE_HAS_EDGE_CHILD_SELECTOR);
 
   return (!checkFirst ||
           aTreeMatchContext.mNthIndexCache.
             GetNthIndex(aElement, false, false, true) == 1) &&
          (!checkLast ||
           aTreeMatchContext.mNthIndexCache.
             GetNthIndex(aElement, false, true, true) == 1);
 }
 
 static inline bool
-nthChildGenericMatches(Element* aElement,
+nthChildGenericMatches(const Element* aElement,
                        TreeMatchContext& aTreeMatchContext,
                        nsPseudoClassList* pseudoClass,
                        bool isOfType, bool isFromEnd)
 {
-  nsIContent *parent = aElement->GetParent();
+  const nsIContent *parent = aElement->GetParent();
   if (!parent) {
     return false;
   }
 
   if (aTreeMatchContext.mForStyling) {
     if (isFromEnd)
       aTreeMatchContext.RecordFlagsToAdd(parent, NODE_HAS_SLOW_SELECTOR);
     else
@@ -1497,20 +1497,20 @@ nthChildGenericMatches(Element* aElement
   // Integer division in C does truncation (towards 0).  So
   // check that the result is nonnegative, and that there was no
   // truncation.
   const PRInt32 n = (index - b) / a;
   return n >= 0 && (a * n == index - b);
 }
 
 static inline bool
-edgeOfTypeMatches(Element* aElement, TreeMatchContext& aTreeMatchContext,
+edgeOfTypeMatches(const Element* aElement, TreeMatchContext& aTreeMatchContext,
                   bool checkFirst, bool checkLast)
 {
-  nsIContent *parent = aElement->GetParent();
+  const nsIContent *parent = aElement->GetParent();
   if (!parent) {
     return false;
   }
 
   if (aTreeMatchContext.mForStyling) {
     if (checkLast)
       aTreeMatchContext.RecordFlagsToAdd(parent, NODE_HAS_SLOW_SELECTOR);
     else
@@ -1521,21 +1521,21 @@ edgeOfTypeMatches(Element* aElement, Tre
           aTreeMatchContext.mNthIndexCache.
             GetNthIndex(aElement, true, false, true) == 1) &&
          (!checkLast ||
           aTreeMatchContext.mNthIndexCache.
             GetNthIndex(aElement, true, true, true) == 1);
 }
 
 static inline bool
-checkGenericEmptyMatches(Element* aElement,
+checkGenericEmptyMatches(const Element* aElement,
                          TreeMatchContext& aTreeMatchContext,
                          bool isWhitespaceSignificant)
 {
-  nsIContent *child = nsnull;
+  const nsIContent *child = nsnull;
   PRInt32 index = -1;
 
   if (aTreeMatchContext.mForStyling)
     aTreeMatchContext.RecordFlagsToAdd(aElement, NODE_HAS_EMPTY_SELECTOR);
 
   do {
     child = aElement->GetChildAt(++index);
     // stop at first non-comment (and non-whitespace for
@@ -1561,17 +1561,17 @@ static const nsEventStates sPseudoClassS
 PR_STATIC_ASSERT(NS_ARRAY_LENGTH(sPseudoClassStates) ==
                    nsCSSPseudoClasses::ePseudoClass_NotPseudoClass + 1);
 
 // |aDependence| has two functions:
 //  * when non-null, it indicates that we're processing a negation,
 //    which is done only when SelectorMatches calls itself recursively
 //  * what it points to should be set to true whenever a test is skipped
 //    because of aStateMask
-static bool SelectorMatches(Element* aElement,
+static bool SelectorMatches(const Element* aElement,
                               nsCSSSelector* aSelector,
                               NodeMatchContext& aNodeMatchContext,
                               TreeMatchContext& aTreeMatchContext,
                               bool* const aDependence = nsnull)
 
 {
   NS_PRECONDITION(!aSelector->IsPseudoElement(),
                   "Pseudo-element snuck into SelectorMatches?");
@@ -1682,17 +1682,17 @@ static bool SelectorMatches(Element* aEl
         if (!checkGenericEmptyMatches(aElement, aTreeMatchContext, false)) {
           return false;
         }
         break;
 
       case nsCSSPseudoClasses::ePseudoClass_mozEmptyExceptChildrenWithLocalname:
         {
           NS_ASSERTION(pseudoClass->u.mString, "Must have string!");
-          nsIContent *child = nsnull;
+          const nsIContent *child = nsnull;
           PRInt32 index = -1;
 
           if (aTreeMatchContext.mForStyling)
             // FIXME:  This isn't sufficient to handle:
             //   :-moz-empty-except-children-with-localname() + E
             //   :-moz-empty-except-children-with-localname() ~ E
             // because we don't know to restyle the grandparent of the
             // inserted/removed element (as in bug 534804 for :empty).
@@ -1727,17 +1727,17 @@ static bool SelectorMatches(Element* aEl
                                                nsDependentString(pseudoClass->u.mString),
                                                nsASCIICaseInsensitiveStringComparator())) {
               return false;
             }
             // This pseudo-class matched; move on to the next thing
             break;
           }
 
-          nsIDocument* doc = aTreeMatchContext.mDocument;
+          const nsIDocument* doc = aTreeMatchContext.mDocument;
           if (doc) {
             // Try to get the language from the HTTP header or if this
             // is missing as well from the preferences.
             // The content language can be a comma-separated list of
             // language codes.
             doc->GetContentLanguage(language);
 
             nsDependentString langString(pseudoClass->u.mString);
@@ -1801,18 +1801,18 @@ static bool SelectorMatches(Element* aEl
       case nsCSSPseudoClasses::ePseudoClass_firstChild:
         if (!edgeChildMatches(aElement, aTreeMatchContext, true, false)) {
           return false;
         }
         break;
 
       case nsCSSPseudoClasses::ePseudoClass_firstNode:
         {
-          nsIContent *firstNode = nsnull;
-          nsIContent *parent = aElement->GetParent();
+          const nsIContent *firstNode = nsnull;
+          const nsIContent *parent = aElement->GetParent();
           if (parent) {
             if (aTreeMatchContext.mForStyling)
               aTreeMatchContext.RecordFlagsToAdd(parent, NODE_HAS_EDGE_CHILD_SELECTOR);
 
             PRInt32 index = -1;
             do {
               firstNode = parent->GetChildAt(++index);
               // stop at first non-comment and non-whitespace node
@@ -1828,18 +1828,18 @@ static bool SelectorMatches(Element* aEl
       case nsCSSPseudoClasses::ePseudoClass_lastChild:
         if (!edgeChildMatches(aElement, aTreeMatchContext, false, true)) {
           return false;
         }
         break;
 
       case nsCSSPseudoClasses::ePseudoClass_lastNode:
         {
-          nsIContent *lastNode = nsnull;
-          nsIContent *parent = aElement->GetParent();
+          const nsIContent *lastNode = nsnull;
+          const nsIContent *parent = aElement->GetParent();
           if (parent) {
             if (aTreeMatchContext.mForStyling)
               aTreeMatchContext.RecordFlagsToAdd(parent, NODE_HAS_EDGE_CHILD_SELECTOR);
             
             PRUint32 index = parent->GetChildCount();
             do {
               lastNode = parent->GetChildAt(--index);
               // stop at first non-comment and non-whitespace node
@@ -1901,17 +1901,17 @@ static bool SelectorMatches(Element* aEl
         if (!nthChildGenericMatches(aElement, aTreeMatchContext, pseudoClass,
                                     true, true)) {
           return false;
         }
         break;
 
       case nsCSSPseudoClasses::ePseudoClass_mozHasHandlerRef:
         {
-          nsIContent *child = nsnull;
+          const nsIContent *child = nsnull;
           PRInt32 index = -1;
 
           do {
             child = aElement->GetChildAt(++index);
             if (child && child->IsHTML() &&
                 child->Tag() == nsGkAtoms::param &&
                 child->AttrValueIs(kNameSpaceID_None, nsGkAtoms::name,
                                    NS_LITERAL_STRING("pluginurl"),
@@ -1991,17 +1991,17 @@ static bool SelectorMatches(Element* aEl
         }
         break;
 
       case nsCSSPseudoClasses::ePseudoClass_mozTableBorderNonzero:
         {
           if (!aElement->IsHTML(nsGkAtoms::table)) {
             return false;
           }
-          nsGenericElement *ge = static_cast<nsGenericElement*>(aElement);
+          const nsGenericElement *ge = static_cast<const nsGenericElement*>(aElement);
           const nsAttrValue *val = ge->GetParsedAttr(nsGkAtoms::border);
           if (!val ||
               (val->Type() == nsAttrValue::eInteger &&
                val->GetIntegerValue() == 0)) {
             return false;
           }
         }
         break;
@@ -2145,54 +2145,54 @@ static bool SelectorMatches(Element* aEl
 
 // Right now, there are four operators:
 //   ' ', the descendant combinator, is greedy
 //   '~', the indirect adjacent sibling combinator, is greedy
 //   '+' and '>', the direct adjacent sibling and child combinators, are not
 #define NS_IS_GREEDY_OPERATOR(ch) \
   ((ch) == PRUnichar(' ') || (ch) == PRUnichar('~'))
 
-static bool SelectorMatchesTree(Element* aPrevElement,
+static bool SelectorMatchesTree(const Element* aPrevElement,
                                   nsCSSSelector* aSelector,
                                   TreeMatchContext& aTreeMatchContext,
                                   bool aLookForRelevantLink)
 {
   nsCSSSelector* selector = aSelector;
-  Element* prevElement = aPrevElement;
+  const Element* prevElement = aPrevElement;
   while (selector) { // check compound selectors
     NS_ASSERTION(!selector->mNext ||
                  selector->mNext->mOperator != PRUnichar(0),
                  "compound selector without combinator");
 
     // for adjacent sibling combinators, the content to test against the
     // selector is the previous sibling *element*
-    Element* element = nsnull;
+    const Element* element = nsnull;
     if (PRUnichar('+') == selector->mOperator ||
         PRUnichar('~') == selector->mOperator) {
       // The relevant link must be an ancestor of the node being matched.
       aLookForRelevantLink = false;
-      nsIContent* parent = prevElement->GetParent();
+      const nsIContent* parent = prevElement->GetParent();
       if (parent) {
         if (aTreeMatchContext.mForStyling)
           aTreeMatchContext.RecordFlagsToAdd(parent, NODE_HAS_SLOW_SELECTOR_LATER_SIBLINGS);
 
-        PRInt32 index = parent->IndexOf(prevElement);
-        while (0 <= --index) {
-          nsIContent* content = parent->GetChildAt(index);
-          if (content->IsElement()) {
-            element = content->AsElement();
+        for (const nsIContent* curr = prevElement->GetPreviousSibling();
+             curr;
+             curr = curr->GetPreviousSibling()) {
+          if (curr->IsElement()) {
+            element = curr->AsElement();
             break;
           }
         }
       }
     }
     // for descendant combinators and child combinators, the element
     // to test against is the parent
     else {
-      nsIContent *content = prevElement->GetParent();
+      const nsIContent *content = prevElement->GetParent();
       // GetParent could return a document fragment; we only want
       // element parents.
       if (content && content->IsElement()) {
         element = content->AsElement();
       }
     }
     if (!element) {
       return false;
@@ -3103,17 +3103,17 @@ nsCSSRuleProcessor::RefreshRuleCascade(n
       newCascade->mNext = mRuleCascades;
       mRuleCascades = newCascade.forget();
     }
   }
   return;
 }
 
 /* static */ bool
-nsCSSRuleProcessor::SelectorListMatches(Element* aElement,
+nsCSSRuleProcessor::SelectorListMatches(const Element* aElement,
                                         TreeMatchContext& aTreeMatchContext,
                                         nsCSSSelectorList* aSelectorList)
 {
   while (aSelectorList) {
     nsCSSSelector* sel = aSelectorList->mSelectors;
     NS_ASSERTION(sel, "Should have *some* selectors");
     NS_ASSERTION(!sel->IsPseudoElement(), "Shouldn't have been called");
     NodeMatchContext nodeContext(nsEventStates(), false);
--- a/layout/style/nsCSSRuleProcessor.h
+++ b/layout/style/nsCSSRuleProcessor.h
@@ -88,38 +88,38 @@ public:
 
   /*
    * Returns true if the given aElement matches one of the
    * selectors in aSelectorList.  Note that this method will assume
    * the given aElement is not a relevant link.  aSelectorList must not
    * include any pseudo-element selectors.  aSelectorList is allowed
    * to be null; in this case false will be returned.
    */
-  static bool SelectorListMatches(mozilla::dom::Element* aElement,
+  static bool SelectorListMatches(const mozilla::dom::Element* aElement,
                                     TreeMatchContext& aTreeMatchContext,
                                     nsCSSSelectorList* aSelectorList);
 
   /*
    * Helper to get the content state for a content node.  This may be
    * slightly adjusted from IntrinsicState().
    */
-  static nsEventStates GetContentState(mozilla::dom::Element* aElement);
+  static nsEventStates GetContentState(const mozilla::dom::Element* aElement);
 
   /*
    * Helper to get the content state for :visited handling for an element
    */
   static nsEventStates GetContentStateForVisitedHandling(
-             mozilla::dom::Element* aElement,
+             const mozilla::dom::Element* aElement,
              nsRuleWalker::VisitedHandlingType aVisitedHandling,
              bool aIsRelevantLink);
 
   /*
    * Helper to test whether a node is a link
    */
-  static bool IsLink(mozilla::dom::Element* aElement);
+  static bool IsLink(const mozilla::dom::Element* aElement);
 
   // nsIStyleRuleProcessor
   virtual void RulesMatching(ElementRuleProcessorData* aData);
 
   virtual void RulesMatching(PseudoElementRuleProcessorData* aData);
 
   virtual void RulesMatching(AnonBoxRuleProcessorData* aData);
 
--- a/layout/style/nsNthIndexCache.cpp
+++ b/layout/style/nsNthIndexCache.cpp
@@ -58,27 +58,27 @@ nsNthIndexCache::Reset()
 {
   mCaches[0][0].clear();
   mCaches[0][1].clear();
   mCaches[1][0].clear();
   mCaches[1][1].clear();
 }
 
 inline bool
-nsNthIndexCache::SiblingMatchesElement(nsIContent* aSibling, Element* aElement,
+nsNthIndexCache::SiblingMatchesElement(const nsIContent* aSibling, const Element* aElement,
                                        bool aIsOfType)
 {
   return aSibling->IsElement() &&
     (!aIsOfType ||
      aSibling->NodeInfo()->NameAndNamespaceEquals(aElement->NodeInfo()));
 }
 
 inline bool
-nsNthIndexCache::IndexDeterminedFromPreviousSibling(nsIContent* aSibling,
-                                                    Element* aChild,
+nsNthIndexCache::IndexDeterminedFromPreviousSibling(const nsIContent* aSibling,
+                                                    const Element* aChild,
                                                     bool aIsOfType,
                                                     bool aIsFromEnd,
                                                     const Cache& aCache,
                                                     PRInt32& aResult)
 {
   if (SiblingMatchesElement(aSibling, aChild, aIsOfType)) {
     Cache::Ptr siblingEntry = aCache.lookup(aSibling);
     if (siblingEntry) {
@@ -100,17 +100,17 @@ nsNthIndexCache::IndexDeterminedFromPrev
     
     ++aResult;
   }
 
   return false;
 }
 
 PRInt32
-nsNthIndexCache::GetNthIndex(Element* aChild, bool aIsOfType,
+nsNthIndexCache::GetNthIndex(const Element* aChild, bool aIsOfType,
                              bool aIsFromEnd, bool aCheckEdgeOnly)
 {
   NS_ASSERTION(aChild->GetParent(), "caller should check GetParent()");
 
   if (aChild->IsRootOfAnonymousSubtree()) {
     return 0;
   }
 
@@ -134,55 +134,55 @@ nsNthIndexCache::GetNthIndex(Element* aC
     return slot;
   }
   
   PRInt32 result = 1;
   if (aCheckEdgeOnly) {
     // The caller only cares whether or not the result is 1, so we can
     // stop as soon as we see any other elements that match us.
     if (aIsFromEnd) {
-      for (nsIContent *cur = aChild->GetNextSibling();
+      for (const nsIContent *cur = aChild->GetNextSibling();
            cur;
            cur = cur->GetNextSibling()) {
         if (SiblingMatchesElement(cur, aChild, aIsOfType)) {
           result = -1;
           break;
         }
       }
     } else {
-      for (nsIContent *cur = aChild->GetPreviousSibling();
+      for (const nsIContent *cur = aChild->GetPreviousSibling();
            cur;
            cur = cur->GetPreviousSibling()) {
         if (SiblingMatchesElement(cur, aChild, aIsOfType)) {
           result = -1;
           break;
         }
       }
     }
   } else {
     // In the common case, we already have a cached index for one of
     // our previous siblings, so check that first.
-    for (nsIContent *cur = aChild->GetPreviousSibling();
+    for (const nsIContent *cur = aChild->GetPreviousSibling();
          cur;
          cur = cur->GetPreviousSibling()) {
       if (IndexDeterminedFromPreviousSibling(cur, aChild, aIsOfType,
                                              aIsFromEnd, cache, result)) {
         slot = result;
         return result;
       }
     }
 
     // Now if aIsFromEnd we lose: need to actually compute our index,
     // since looking at previous siblings wouldn't have told us
     // anything about it.  Note that it doesn't make sense to do cache
     // lookups on our following siblings, since chances are the cache
     // is not primed for them.
     if (aIsFromEnd) {
       result = 1;
-      for (nsIContent *cur = aChild->GetNextSibling();
+      for (const nsIContent *cur = aChild->GetNextSibling();
            cur;
            cur = cur->GetNextSibling()) {
         if (SiblingMatchesElement(cur, aChild, aIsOfType)) {
           ++result;
         }
       }
     }
   }
--- a/layout/style/nsNthIndexCache.h
+++ b/layout/style/nsNthIndexCache.h
@@ -62,59 +62,61 @@ public:
 
   // Returns a 1-based index of the child in its parent.  If the child
   // is not in its parent's child list (i.e., it is anonymous content),
   // returns 0.
   // If aCheckEdgeOnly is true, the function will return 1 if the result
   // is 1, and something other than 1 (maybe or maybe not a valid
   // result) otherwise.
   // This must only be called on nodes which have a non-null parent.
-  PRInt32 GetNthIndex(Element* aChild, bool aIsOfType, bool aIsFromEnd,
+  PRInt32 GetNthIndex(const Element* aChild, bool aIsOfType, bool aIsFromEnd,
                       bool aCheckEdgeOnly);
 
   void Reset();
 
 private:
   /**
    * Returns true if aSibling and aElement should be considered in the same
    * list for nth-index purposes, taking aIsOfType into account.
    */
-  inline bool SiblingMatchesElement(nsIContent* aSibling, Element* aElement,
+  inline bool SiblingMatchesElement(const nsIContent* aSibling, 
+                                    const Element* aElement,
                                     bool aIsOfType);
 
   // This node's index for this cache.
   // If -2, needs to be computed.
   // If -1, needs to be computed but known not to be 1.
   // If 0, the node is not at any index in its parent.
   typedef PRInt32 CacheEntry;
 
   class SystemAllocPolicy {
   public:
     void *malloc_(size_t bytes) { return ::malloc(bytes); }
     void *realloc_(void *p, size_t bytes) { return ::realloc(p, bytes); }
     void free_(void *p) { ::free(p); }
     void reportAllocOverflow() const {}
   };
 
-  typedef js::HashMap<nsIContent*, CacheEntry, js::DefaultHasher<nsIContent*>,
+  typedef js::HashMap<const nsIContent*, CacheEntry,
+                      js::DefaultHasher<const nsIContent*>,
                       SystemAllocPolicy> Cache;
 
   /**
    * Returns true if aResult has been set to the correct value for aChild and
    * no more work needs to be done.  Returns false otherwise.
    *
    * aResult is an inout parameter.  The in value is the number of elements
    * that are in the half-open range (aSibling, aChild] (so including aChild
    * but not including aSibling) that match aChild.  The out value is the
    * correct index for aChild if this function returns true and the number of
    * elements in the closed range [aSibling, aChild] that match aChild
    * otherwise.
    */
-  inline bool IndexDeterminedFromPreviousSibling(nsIContent* aSibling,
-                                                 Element* aChild,
+  inline bool IndexDeterminedFromPreviousSibling(const nsIContent* aSibling,
+                                                 const Element* aChild,
                                                  bool aIsOfType,
                                                  bool aIsFromEnd,
                                                  const Cache& aCache,
                                                  PRInt32& aResult);
 
   // Caches of indices for :nth-child(), :nth-last-child(),
   // :nth-of-type(), :nth-last-of-type(), keyed by Element*.
   //
--- a/layout/style/nsStyleUtil.cpp
+++ b/layout/style/nsStyleUtil.cpp
@@ -500,17 +500,17 @@ nsStyleUtil::ColorComponentToFloat(PRUin
   if (FloatToColorComponent(rounded) != aAlpha) {
     // Use three decimal places.
     rounded = NS_roundf(float(aAlpha) * 1000.0f / 255.0f) / 1000.0f;
   }
   return rounded;
 }
 
 /* static */ bool
-nsStyleUtil::IsSignificantChild(nsIContent* aChild, bool aTextIsSignificant,
+nsStyleUtil::IsSignificantChild(const nsIContent* aChild, bool aTextIsSignificant,
                                 bool aWhitespaceIsSignificant)
 {
   NS_ASSERTION(!aWhitespaceIsSignificant || aTextIsSignificant,
                "Nonsensical arguments");
 
   bool isText = aChild->IsNodeOfType(nsINode::eTEXT);
 
   if (!isText && !aChild->IsNodeOfType(nsINode::eCOMMENT) &&
--- a/layout/style/nsStyleUtil.h
+++ b/layout/style/nsStyleUtil.h
@@ -107,15 +107,15 @@ public:
    *
    * Should be used only by serialization code.
    */
   static float ColorComponentToFloat(PRUint8 aAlpha);
 
   /*
    * Does this child count as significant for selector matching?
    */
-  static bool IsSignificantChild(nsIContent* aChild,
+  static bool IsSignificantChild(const nsIContent* aChild,
                                    bool aTextIsSignificant,
                                    bool aWhitespaceIsSignificant);
 };
 
 
 #endif /* nsStyleUtil_h___ */