diff --git a/layout/style/nsCSSStyleRule.cpp b/layout/style/nsCSSStyleRule.cpp index 6dcc0f45271c..6da6dce981b1 100644 --- a/layout/style/nsCSSStyleRule.cpp +++ b/layout/style/nsCSSStyleRule.cpp @@ -75,6 +75,7 @@ #include "nsIPrincipal.h" #include "nsComponentManagerUtils.h" #include "nsCSSPseudoClasses.h" +#include "nsTArray.h" #include "nsContentUtils.h" #include "nsContentErrors.h" @@ -468,11 +469,6 @@ static PRBool IsPseudoElement(nsIAtom* aAtom) return PR_FALSE; } -void nsCSSSelector::AppendNegationToString(nsAString& aString) -{ - aString.AppendLiteral(":not("); -} - // // Builds the textual representation of a selector. Called by DOM 2 CSS // StyleRule:selectorText @@ -483,28 +479,58 @@ nsCSSSelector::ToString(nsAString& aString, nsICSSStyleSheet* aSheet, { if (!aAppend) aString.Truncate(); + + // selectors are linked from right-to-left, so the next selector in + // the linked list actually precedes this one in the resulting string + nsAutoTArray stack; + for (const nsCSSSelector *s = this; s; s = s->mNext) { + stack.AppendElement(s); + } - ToStringInternal(aString, aSheet, IsPseudoElement(mTag), PR_FALSE); + while (!stack.IsEmpty()) { + PRUint32 index = stack.Length() - 1; + const nsCSSSelector *s = stack.ElementAt(index); + stack.RemoveElementAt(index); + + s->AppendToStringWithoutCombinators(aString, aSheet); + + // Append the combinator, if needed. + if (!stack.IsEmpty()) { + const nsCSSSelector *next = stack.ElementAt(index - 1); + if (!IsPseudoElement(next->mTag)) { + aString.Append(PRUnichar(' ')); + PRUnichar oper = s->mOperator; + if (oper != PRUnichar(0)) { + aString.Append(oper); + aString.Append(PRUnichar(' ')); + } + } + } + } } -void nsCSSSelector::ToStringInternal(nsAString& aString, - nsICSSStyleSheet* aSheet, - PRBool aIsPseudoElem, - PRBool aIsNegated) const +void +nsCSSSelector::AppendToStringWithoutCombinators + (nsAString& aString, nsICSSStyleSheet* aSheet) const +{ + AppendToStringWithoutCombinatorsOrNegations(aString, aSheet, PR_FALSE); + + for (const nsCSSSelector* negation = mNegations; negation; + negation = negation->mNegations) { + aString.AppendLiteral(":not("); + negation->AppendToStringWithoutCombinatorsOrNegations(aString, aSheet, + PR_TRUE); + aString.Append(PRUnichar(')')); + } +} + +void +nsCSSSelector::AppendToStringWithoutCombinatorsOrNegations + (nsAString& aString, nsICSSStyleSheet* aSheet, + PRBool aIsNegated) const { nsAutoString temp; PRBool isPseudoElement = IsPseudoElement(mTag); - - // selectors are linked from right-to-left, so the next selector in the linked list - // actually precedes this one in the resulting string - if (mNext) { - mNext->ToStringInternal(aString, aSheet, IsPseudoElement(mTag), 0); - if (!aIsNegated && !isPseudoElement) { - // don't add a leading whitespace if we have a pseudo-element - // or a negated simple selector - aString.Append(PRUnichar(' ')); - } - } // For non-pseudo-element selectors or for lone pseudo-elements, deal with // namespace prefixes. @@ -697,22 +723,6 @@ void nsCSSSelector::ToStringInternal(nsAString& aString, list = list->mNext; } } - - if (!aIsNegated) { - for (nsCSSSelector* negation = mNegations; negation; - negation = negation->mNegations) { - aString.AppendLiteral(":not("); - negation->ToStringInternal(aString, aSheet, PR_FALSE, PR_TRUE); - aString.Append(PRUnichar(')')); - } - } - - // Append the operator only if the selector is not negated and is not - // a pseudo-element - if (!aIsNegated && mOperator && !aIsPseudoElem) { - aString.Append(PRUnichar(' ')); - aString.Append(mOperator); - } } PRBool diff --git a/layout/style/nsICSSStyleRule.h b/layout/style/nsICSSStyleRule.h index c76fb9de0708..4560b43eda5a 100644 --- a/layout/style/nsICSSStyleRule.h +++ b/layout/style/nsICSSStyleRule.h @@ -173,10 +173,12 @@ private: void AddPseudoClassInternal(nsPseudoClassList *aPseudoClass); nsCSSSelector* Clone(PRBool aDeepNext, PRBool aDeepNegations) const; - void AppendNegationToString(nsAString& aString); - void ToStringInternal(nsAString& aString, nsICSSStyleSheet* aSheet, - PRBool aIsPseudoElem, - PRBool aIsNegated) const; + void AppendToStringWithoutCombinators(nsAString& aString, + nsICSSStyleSheet* aSheet) const; + void AppendToStringWithoutCombinatorsOrNegations(nsAString& aString, + nsICSSStyleSheet* aSheet, + PRBool aIsNegated) + const; // Returns true if this selector can have a namespace specified (which // happens if and only if the default namespace would apply to this // selector).