Back to index

lightning-sunbird  0.9+nobinonly
nsCSSStyleRule.cpp
Go to the documentation of this file.
00001 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
00002 /* ***** BEGIN LICENSE BLOCK *****
00003  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
00004  *
00005  * The contents of this file are subject to the Mozilla Public License Version
00006  * 1.1 (the "License"); you may not use this file except in compliance with
00007  * the License. You may obtain a copy of the License at
00008  * http://www.mozilla.org/MPL/
00009  *
00010  * Software distributed under the License is distributed on an "AS IS" basis,
00011  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
00012  * for the specific language governing rights and limitations under the
00013  * License.
00014  *
00015  * The Original Code is mozilla.org code.
00016  *
00017  * The Initial Developer of the Original Code is
00018  * Netscape Communications Corporation.
00019  * Portions created by the Initial Developer are Copyright (C) 1998
00020  * the Initial Developer. All Rights Reserved.
00021  *
00022  * Contributor(s):
00023  *   David Hyatt <hyatt@netscape.com>
00024  *   Daniel Glazman <glazman@netscape.com>
00025  *
00026  * Alternatively, the contents of this file may be used under the terms of
00027  * either of the GNU General Public License Version 2 or later (the "GPL"),
00028  * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
00029  * in which case the provisions of the GPL or the LGPL are applicable instead
00030  * of those above. If you wish to allow use of your version of this file only
00031  * under the terms of either the GPL or the LGPL, and not to allow others to
00032  * use your version of this file under the terms of the MPL, indicate your
00033  * decision by deleting the provisions above and replace them with the notice
00034  * and other provisions required by the GPL or the LGPL. If you do not delete
00035  * the provisions above, a recipient may use your version of this file under
00036  * the terms of any one of the MPL, the GPL or the LGPL.
00037  *
00038  * ***** END LICENSE BLOCK ***** */
00039 #include "nsCOMPtr.h"
00040 #include "nsCSSRule.h"
00041 #include "nsICSSStyleRule.h"
00042 #include "nsICSSGroupRule.h"
00043 #include "nsCSSDeclaration.h"
00044 #include "nsICSSStyleSheet.h"
00045 #include "nsICSSParser.h"
00046 #include "nsICSSLoader.h"
00047 #include "nsIURL.h"
00048 #include "nsPresContext.h"
00049 #include "nsIDocument.h"
00050 #include "nsIDeviceContext.h"
00051 #include "nsIAtom.h"
00052 #include "nsCRT.h"
00053 #include "nsString.h"
00054 #include "nsStyleConsts.h"
00055 #include "nsStyleUtil.h"
00056 #include "nsHTMLAtoms.h"
00057 #include "nsUnitConversion.h"
00058 #include "nsIFontMetrics.h"
00059 #include "nsIDOMCSSStyleSheet.h"
00060 #include "nsICSSStyleRuleDOMWrapper.h"
00061 #include "nsIDOMCSSStyleDeclaration.h"
00062 #include "nsDOMCSSDeclaration.h"
00063 #include "nsINameSpaceManager.h"
00064 #include "nsXMLNameSpaceMap.h"
00065 #include "nsILookAndFeel.h"
00066 #include "nsRuleNode.h"
00067 #include "nsUnicharUtils.h"
00068 #include "nsCSSPseudoElements.h"
00069 
00070 #include "nsContentUtils.h"
00071 #include "nsContentErrors.h"
00072 
00073 #define NS_IF_CLONE(member_)                                                  \
00074   PR_BEGIN_MACRO                                                              \
00075     if (member_) {                                                            \
00076       result->member_ = member_->Clone();                                     \
00077       if (!result->member_) {                                                 \
00078         delete result;                                                        \
00079         return nsnull;                                                        \
00080       }                                                                       \
00081     }                                                                         \
00082   PR_END_MACRO
00083 
00084 #define NS_IF_DEEP_CLONE(type_, member_, args_)                               \
00085   PR_BEGIN_MACRO                                                              \
00086     type_ *dest = result;                                                     \
00087     for (type_ *src = member_; src; src = src->member_) {                     \
00088       type_ *clone = src->Clone args_;                                        \
00089       if (!clone) {                                                           \
00090         delete result;                                                        \
00091         return nsnull;                                                        \
00092       }                                                                       \
00093       dest->member_ = clone;                                                  \
00094       dest = clone;                                                           \
00095     }                                                                         \
00096   PR_END_MACRO
00097 
00098 #define NS_IF_DELETE(ptr)                                                     \
00099   PR_BEGIN_MACRO                                                              \
00100     if (ptr) {                                                                \
00101       delete ptr;                                                             \
00102       ptr = nsnull;                                                           \
00103     }                                                                         \
00104   PR_END_MACRO
00105 
00106 #define NS_IF_DEEP_DELETE(type_, member_)                                     \
00107   PR_BEGIN_MACRO                                                              \
00108     type_ *cur = member_;                                                     \
00109     member_ = nsnull;                                                         \
00110     while (cur) {                                                             \
00111       type_ *next = cur->member_;                                             \
00112       cur->member_ = nsnull;                                                  \
00113       delete cur;                                                             \
00114       cur = next;                                                             \
00115     }                                                                         \
00116   PR_END_MACRO
00117 
00118 #define NS_IF_NEGATED_START(bool,str)  \
00119   if (bool) { str.AppendLiteral(":not("); }
00120 
00121 #define NS_IF_NEGATED_END(bool,str)  \
00122   if (bool) { str.Append(PRUnichar(')')); }
00123 
00124 /* ************************************************************************** */
00125 
00126 MOZ_DECL_CTOR_COUNTER(nsAtomList)
00127 
00128 nsAtomList::nsAtomList(nsIAtom* aAtom)
00129   : mAtom(aAtom),
00130     mNext(nsnull)
00131 {
00132   MOZ_COUNT_CTOR(nsAtomList);
00133 }
00134 
00135 nsAtomList::nsAtomList(const nsString& aAtomValue)
00136   : mAtom(nsnull),
00137     mNext(nsnull)
00138 {
00139   MOZ_COUNT_CTOR(nsAtomList);
00140   mAtom = do_GetAtom(aAtomValue);
00141 }
00142 
00143 nsAtomList*
00144 nsAtomList::Clone(PRBool aDeep) const
00145 {
00146   nsAtomList *result = new nsAtomList(mAtom);
00147   if (!result)
00148     return nsnull;
00149 
00150   if (aDeep)
00151     NS_IF_DEEP_CLONE(nsAtomList, mNext, (PR_FALSE));
00152   return result;
00153 }
00154 
00155 nsAtomList::~nsAtomList(void)
00156 {
00157   MOZ_COUNT_DTOR(nsAtomList);
00158   NS_IF_DEEP_DELETE(nsAtomList, mNext);
00159 }
00160 
00161 MOZ_DECL_CTOR_COUNTER(nsAtomStringList)
00162 
00163 nsAtomStringList::nsAtomStringList(nsIAtom* aAtom, const PRUnichar* aString)
00164   : mAtom(aAtom),
00165     mString(nsnull),
00166     mNext(nsnull)
00167 {
00168   MOZ_COUNT_CTOR(nsAtomStringList);
00169   if (aString)
00170     mString = nsCRT::strdup(aString);
00171 }
00172 
00173 nsAtomStringList::nsAtomStringList(const nsString& aAtomValue,
00174                                    const PRUnichar* aString)
00175   : mAtom(nsnull),
00176     mString(nsnull),
00177     mNext(nsnull)
00178 {
00179   MOZ_COUNT_CTOR(nsAtomStringList);
00180   mAtom = do_GetAtom(aAtomValue);
00181   if (aString)
00182     mString = nsCRT::strdup(aString);
00183 }
00184 
00185 nsAtomStringList*
00186 nsAtomStringList::Clone(PRBool aDeep) const
00187 {
00188   nsAtomStringList *result = new nsAtomStringList(mAtom, mString);
00189 
00190   if (aDeep)
00191     NS_IF_DEEP_CLONE(nsAtomStringList, mNext, (PR_FALSE));
00192 
00193   return result;
00194 }
00195 
00196 nsAtomStringList::~nsAtomStringList(void)
00197 {
00198   MOZ_COUNT_DTOR(nsAtomStringList);
00199   if (mString)
00200     nsCRT::free(mString);
00201   NS_IF_DEEP_DELETE(nsAtomStringList, mNext);
00202 }
00203 
00204 MOZ_DECL_CTOR_COUNTER(nsAttrSelector)
00205 
00206 nsAttrSelector::nsAttrSelector(PRInt32 aNameSpace, const nsString& aAttr)
00207   : mNameSpace(aNameSpace),
00208     mAttr(nsnull),
00209     mFunction(NS_ATTR_FUNC_SET),
00210     mCaseSensitive(1),
00211     mValue(),
00212     mNext(nsnull)
00213 {
00214   MOZ_COUNT_CTOR(nsAttrSelector);
00215 
00216   mAttr = do_GetAtom(aAttr);
00217 }
00218 
00219 nsAttrSelector::nsAttrSelector(PRInt32 aNameSpace, const nsString& aAttr, PRUint8 aFunction, 
00220                                const nsString& aValue, PRBool aCaseSensitive)
00221   : mNameSpace(aNameSpace),
00222     mAttr(nsnull),
00223     mFunction(aFunction),
00224     mCaseSensitive(aCaseSensitive),
00225     mValue(aValue),
00226     mNext(nsnull)
00227 {
00228   MOZ_COUNT_CTOR(nsAttrSelector);
00229 
00230   mAttr = do_GetAtom(aAttr);
00231 }
00232 
00233 nsAttrSelector::nsAttrSelector(PRInt32 aNameSpace, nsIAtom* aAttr,
00234                                PRUint8 aFunction, const nsString& aValue,
00235                                PRBool aCaseSensitive)
00236   : mNameSpace(aNameSpace),
00237     mAttr(aAttr),
00238     mFunction(aFunction),
00239     mCaseSensitive(aCaseSensitive),
00240     mValue(aValue),
00241     mNext(nsnull)
00242 {
00243   MOZ_COUNT_CTOR(nsAttrSelector);
00244 }
00245 
00246 nsAttrSelector*
00247 nsAttrSelector::Clone(PRBool aDeep) const
00248 {
00249   nsAttrSelector *result =
00250     new nsAttrSelector(mNameSpace, mAttr, mFunction, mValue, mCaseSensitive);
00251 
00252   if (aDeep)
00253     NS_IF_DEEP_CLONE(nsAttrSelector, mNext, (PR_FALSE));
00254 
00255   return result;
00256 }
00257 
00258 nsAttrSelector::~nsAttrSelector(void)
00259 {
00260   MOZ_COUNT_DTOR(nsAttrSelector);
00261 
00262   NS_IF_DEEP_DELETE(nsAttrSelector, mNext);
00263 }
00264 
00265 // -- nsCSSSelector -------------------------------
00266 
00267 MOZ_DECL_CTOR_COUNTER(nsCSSSelector)
00268 
00269 nsCSSSelector::nsCSSSelector(void)
00270   : mNameSpace(kNameSpaceID_Unknown), mTag(nsnull), 
00271     mIDList(nsnull), 
00272     mClassList(nsnull), 
00273     mPseudoClassList(nsnull),
00274     mAttrList(nsnull), 
00275     mOperator(0),
00276     mNegations(nsnull),
00277     mNext(nsnull)
00278 {
00279   MOZ_COUNT_CTOR(nsCSSSelector);
00280 }
00281 
00282 nsCSSSelector*
00283 nsCSSSelector::Clone(PRBool aDeepNext, PRBool aDeepNegations) const
00284 {
00285   nsCSSSelector *result = new nsCSSSelector();
00286   if (!result)
00287     return nsnull;
00288 
00289   result->mNameSpace = mNameSpace;
00290   result->mTag = mTag;
00291   
00292   NS_IF_CLONE(mIDList);
00293   NS_IF_CLONE(mClassList);
00294   NS_IF_CLONE(mPseudoClassList);
00295   NS_IF_CLONE(mAttrList);
00296 
00297   // No need to worry about multiple levels of recursion since an
00298   // mNegations can't have an mNext.
00299   if (aDeepNegations) {
00300     NS_IF_DEEP_CLONE(nsCSSSelector, mNegations, (PR_TRUE, PR_FALSE));
00301   }
00302 
00303   if (aDeepNext) {
00304     NS_IF_DEEP_CLONE(nsCSSSelector, mNext, (PR_FALSE, PR_TRUE));
00305   }
00306 
00307   return result;
00308 }
00309 
00310 nsCSSSelector::~nsCSSSelector(void)  
00311 {
00312   MOZ_COUNT_DTOR(nsCSSSelector);
00313   Reset();
00314   // No need to worry about multiple levels of recursion since an
00315   // mNegations can't have an mNext.
00316   NS_IF_DEEP_DELETE(nsCSSSelector, mNext);
00317 }
00318 
00319 void nsCSSSelector::Reset(void)
00320 {
00321   mNameSpace = kNameSpaceID_Unknown;
00322   mTag = nsnull;
00323   NS_IF_DELETE(mIDList);
00324   NS_IF_DELETE(mClassList);
00325   NS_IF_DELETE(mPseudoClassList);
00326   NS_IF_DELETE(mAttrList);
00327   // No need to worry about multiple levels of recursion since an
00328   // mNegations can't have an mNext.
00329   NS_IF_DEEP_DELETE(nsCSSSelector, mNegations);
00330   mOperator = PRUnichar(0);
00331 }
00332 
00333 void nsCSSSelector::SetNameSpace(PRInt32 aNameSpace)
00334 {
00335   mNameSpace = aNameSpace;
00336 }
00337 
00338 void nsCSSSelector::SetTag(const nsString& aTag)
00339 {
00340   if (aTag.IsEmpty())
00341     mTag = nsnull;
00342   else
00343     mTag = do_GetAtom(aTag);
00344 }
00345 
00346 void nsCSSSelector::AddID(const nsString& aID)
00347 {
00348   if (!aID.IsEmpty()) {
00349     nsAtomList** list = &mIDList;
00350     while (nsnull != *list) {
00351       list = &((*list)->mNext);
00352     }
00353     *list = new nsAtomList(aID);
00354   }
00355 }
00356 
00357 void nsCSSSelector::AddClass(const nsString& aClass)
00358 {
00359   if (!aClass.IsEmpty()) {
00360     nsAtomList** list = &mClassList;
00361     while (nsnull != *list) {
00362       list = &((*list)->mNext);
00363     }
00364     *list = new nsAtomList(aClass);
00365   }
00366 }
00367 
00368 void nsCSSSelector::AddPseudoClass(const nsString& aPseudoClass,
00369                                    const PRUnichar* aString)
00370 {
00371   if (!aPseudoClass.IsEmpty()) {
00372     nsAtomStringList** list = &mPseudoClassList;
00373     while (nsnull != *list) {
00374       list = &((*list)->mNext);
00375     }
00376     *list = new nsAtomStringList(aPseudoClass, aString);
00377   }
00378 }
00379 
00380 void nsCSSSelector::AddPseudoClass(nsIAtom* aPseudoClass,
00381                                    const PRUnichar* aString)
00382 {
00383   if (nsnull != aPseudoClass) {
00384     nsAtomStringList** list = &mPseudoClassList;
00385     while (nsnull != *list) {
00386       list = &((*list)->mNext);
00387     }
00388     *list = new nsAtomStringList(aPseudoClass, aString);
00389   }
00390 }
00391 
00392 void nsCSSSelector::AddAttribute(PRInt32 aNameSpace, const nsString& aAttr)
00393 {
00394   if (!aAttr.IsEmpty()) {
00395     nsAttrSelector** list = &mAttrList;
00396     while (nsnull != *list) {
00397       list = &((*list)->mNext);
00398     }
00399     *list = new nsAttrSelector(aNameSpace, aAttr);
00400   }
00401 }
00402 
00403 void nsCSSSelector::AddAttribute(PRInt32 aNameSpace, const nsString& aAttr, PRUint8 aFunc, 
00404                                  const nsString& aValue, PRBool aCaseSensitive)
00405 {
00406   if (!aAttr.IsEmpty()) {
00407     nsAttrSelector** list = &mAttrList;
00408     while (nsnull != *list) {
00409       list = &((*list)->mNext);
00410     }
00411     *list = new nsAttrSelector(aNameSpace, aAttr, aFunc, aValue, aCaseSensitive);
00412   }
00413 }
00414 
00415 void nsCSSSelector::SetOperator(PRUnichar aOperator)
00416 {
00417   mOperator = aOperator;
00418 }
00419 
00420 PRInt32 nsCSSSelector::CalcWeight(void) const
00421 {
00422   PRInt32 weight = 0;
00423 
00424   if (nsnull != mTag) {
00425     weight += 0x000001;
00426   }
00427   nsAtomList* list = mIDList;
00428   while (nsnull != list) {
00429     weight += 0x010000;
00430     list = list->mNext;
00431   }
00432   list = mClassList;
00433   while (nsnull != list) {
00434     weight += 0x000100;
00435     list = list->mNext;
00436   }
00437   nsAtomStringList *plist = mPseudoClassList;
00438   while (nsnull != plist) {
00439     weight += 0x000100;
00440     plist = plist->mNext;
00441   }
00442   nsAttrSelector* attr = mAttrList;
00443   while (nsnull != attr) {
00444     weight += 0x000100;
00445     attr = attr->mNext;
00446   }
00447   if (nsnull != mNegations) {
00448     weight += mNegations->CalcWeight();
00449   }
00450   return weight;
00451 }
00452 
00453 // pseudo-elements are stored in the selectors' chain using fictional elements;
00454 // these fictional elements have mTag starting with a colon
00455 static PRBool IsPseudoElement(nsIAtom* aAtom)
00456 {
00457   if (aAtom) {
00458     const char* str;
00459     aAtom->GetUTF8String(&str);
00460     return str && (*str == ':');
00461   }
00462 
00463   return PR_FALSE;
00464 }
00465 
00466 void nsCSSSelector::AppendNegationToString(nsAString& aString)
00467 {
00468   aString.AppendLiteral(":not(");
00469 }
00470 
00471 //
00472 // Builds the textual representation of a selector. Called by DOM 2 CSS 
00473 // StyleRule:selectorText
00474 //
00475 void
00476 nsCSSSelector::ToString(nsAString& aString, nsICSSStyleSheet* aSheet,
00477                         PRBool aAppend) const
00478 {
00479   if (!aAppend)
00480    aString.Truncate();
00481    
00482   ToStringInternal(aString, aSheet, IsPseudoElement(mTag), 0);
00483 }
00484 
00485 void nsCSSSelector::ToStringInternal(nsAString& aString,
00486                                      nsICSSStyleSheet* aSheet,
00487                                      PRBool aIsPseudoElem,
00488                                      PRIntn aNegatedIndex) const
00489 {
00490   nsAutoString temp;
00491   PRBool aIsNegated = PRBool(0 < aNegatedIndex);
00492   PRBool isPseudoElement = IsPseudoElement(mTag);
00493   
00494   // selectors are linked from right-to-left, so the next selector in the linked list
00495   // actually precedes this one in the resulting string
00496   if (mNext) {
00497     mNext->ToStringInternal(aString, aSheet, IsPseudoElement(mTag), 0);
00498     if (!aIsNegated && !isPseudoElement) {
00499       // don't add a leading whitespace if we have a pseudo-element
00500       // or a negated simple selector
00501       aString.Append(PRUnichar(' '));
00502     }
00503   }
00504   if (1 < aNegatedIndex) {
00505     // the first mNegations does not contain a negated type element selector
00506     // or a negated universal selector
00507     NS_IF_NEGATED_START(aIsNegated, aString)
00508   }
00509 
00510   // For non-pseudo-element selectors or for lone pseudo-elements, deal with
00511   // namespace prefixes.
00512   if (!isPseudoElement || !mNext) {
00513     // append the namespace prefix if needed
00514     if (mNameSpace == kNameSpaceID_None) {
00515       // The only way to do this in CSS is to have an explicit namespace
00516       // of "none" specified in the sheet by having a '|' with nothing
00517       // before it.
00518       aString.Append(PRUnichar('|'));
00519     } else {
00520       if (aSheet) {
00521         nsXMLNameSpaceMap *sheetNS = aSheet->GetNameSpaceMap();
00522     
00523         // sheetNS is non-null if and only if we had an @namespace rule.  If it's
00524         // null, that means that the only namespaces we could have are the
00525         // wildcard namespace (which can be implicit in this case) and the "none"
00526         // namespace, which we handled above.  So no need to output anything when
00527         // sheetNS is null.
00528         if (sheetNS) {
00529           nsIAtom *prefixAtom = nsnull;
00530           // prefixAtom is non-null if and only if we have a prefix other than
00531           // '*'
00532           if (mNameSpace != kNameSpaceID_Unknown) {
00533             prefixAtom = sheetNS->FindPrefix(mNameSpace);
00534           }
00535           if (prefixAtom) {
00536             nsAutoString prefix;
00537             prefixAtom->ToString(prefix);
00538             aString.Append(prefix);
00539             aString.Append(PRUnichar('|'));
00540           } else if (mNameSpace == kNameSpaceID_Unknown) {
00541             // explicit *| or only non-default namespace rules and we're not
00542             // using any of those namespaces
00543             aString.AppendLiteral("*|");
00544           }
00545           // else we are in the default namespace and don't need to output
00546           // anything
00547         }
00548       }
00549     }
00550   }
00551       
00552   // smells like a universal selector
00553   if (!mTag && !mIDList && !mClassList) {
00554     if (1 != aNegatedIndex) {
00555       aString.Append(PRUnichar('*'));
00556     }
00557     if (1 < aNegatedIndex) {
00558       NS_IF_NEGATED_END(aIsNegated, aString)
00559     }
00560   } else {
00561     // Append the tag name, if there is one
00562     if (mTag) {
00563       if (isPseudoElement) {
00564         if (!mNext) {
00565           // Lone pseudo-element selector -- toss in a wildcard type selector
00566           aString.Append(PRUnichar('*'));
00567         }
00568         if (!nsCSSPseudoElements::IsCSS2PseudoElement(mTag)) {
00569           aString.Append(PRUnichar(':'));
00570         }
00571       }
00572       nsAutoString prefix;
00573       mTag->ToString(prefix);
00574       aString.Append(prefix);
00575       NS_IF_NEGATED_END(aIsNegated, aString)
00576     }
00577     // Append the id, if there is one
00578     if (mIDList) {
00579       nsAtomList* list = mIDList;
00580       while (list != nsnull) {
00581         list->mAtom->ToString(temp);
00582         NS_IF_NEGATED_START(aIsNegated, aString)
00583         aString.Append(PRUnichar('#'));
00584         aString.Append(temp);
00585         NS_IF_NEGATED_END(aIsNegated, aString)
00586         list = list->mNext;
00587       }
00588     }
00589     // Append each class in the linked list
00590     if (mClassList) {
00591       nsAtomList* list = mClassList;
00592       while (list != nsnull) {
00593         list->mAtom->ToString(temp);
00594         NS_IF_NEGATED_START(aIsNegated, aString)
00595         aString.Append(PRUnichar('.'));
00596         aString.Append(temp);
00597         NS_IF_NEGATED_END(aIsNegated, aString)
00598         list = list->mNext;
00599       }
00600     }
00601   }
00602 
00603   // Append each attribute selector in the linked list
00604   if (mAttrList) {
00605     nsAttrSelector* list = mAttrList;
00606     while (list != nsnull) {
00607       NS_IF_NEGATED_START(aIsNegated, aString)
00608       aString.Append(PRUnichar('['));
00609       // Append the namespace prefix
00610       if (list->mNameSpace > 0) {
00611         if (aSheet) {
00612           nsXMLNameSpaceMap *sheetNS = aSheet->GetNameSpaceMap();
00613           // will return null if namespace was the default
00614           nsIAtom *prefixAtom = sheetNS->FindPrefix(list->mNameSpace);
00615           if (prefixAtom) { 
00616             nsAutoString prefix;
00617             prefixAtom->ToString(prefix);
00618             aString.Append(prefix);
00619             aString.Append(PRUnichar('|'));
00620           }
00621         }
00622       }
00623       // Append the attribute name
00624       list->mAttr->ToString(temp);
00625       aString.Append(temp);
00626 
00627       if (list->mFunction != NS_ATTR_FUNC_SET) {
00628         // Append the function
00629         if (list->mFunction == NS_ATTR_FUNC_INCLUDES)
00630           aString.Append(PRUnichar('~'));
00631         else if (list->mFunction == NS_ATTR_FUNC_DASHMATCH)
00632           aString.Append(PRUnichar('|'));
00633         else if (list->mFunction == NS_ATTR_FUNC_BEGINSMATCH)
00634           aString.Append(PRUnichar('^'));
00635         else if (list->mFunction == NS_ATTR_FUNC_ENDSMATCH)
00636           aString.Append(PRUnichar('$'));
00637         else if (list->mFunction == NS_ATTR_FUNC_CONTAINSMATCH)
00638           aString.Append(PRUnichar('*'));
00639 
00640         aString.Append(PRUnichar('='));
00641       
00642         // Append the value
00643         nsAutoString escaped;
00644         nsStyleUtil::EscapeCSSString(list->mValue, escaped);
00645       
00646         aString.Append(PRUnichar('\"'));
00647         aString.Append(escaped);
00648         aString.Append(PRUnichar('\"'));
00649       }
00650 
00651       aString.Append(PRUnichar(']'));
00652       
00653       NS_IF_NEGATED_END(aIsNegated, aString)
00654       list = list->mNext;
00655     }
00656   }
00657 
00658   // Append each pseudo-class in the linked list
00659   if (mPseudoClassList) {
00660     nsAtomStringList* list = mPseudoClassList;
00661     while (list != nsnull) {
00662       list->mAtom->ToString(temp);
00663       NS_IF_NEGATED_START(aIsNegated, aString)
00664       aString.Append(temp);
00665       if (nsnull != list->mString) {
00666         aString.Append(PRUnichar('('));
00667         aString.Append(list->mString);
00668         aString.Append(PRUnichar(')'));
00669       }
00670       NS_IF_NEGATED_END(aIsNegated, aString)
00671       list = list->mNext;
00672     }
00673   }
00674 
00675   if (mNegations) {
00676     // chain all the negated selectors
00677     mNegations->ToStringInternal(aString, aSheet, PR_FALSE, aNegatedIndex + 1);
00678   }
00679 
00680   // Append the operator only if the selector is not negated and is not
00681   // a pseudo-element
00682   if (!aIsNegated && mOperator && !aIsPseudoElem) {
00683     aString.Append(PRUnichar(' '));
00684     aString.Append(mOperator);
00685   }
00686 }
00687 
00688 // -- nsCSSSelectorList -------------------------------
00689 
00690 MOZ_DECL_CTOR_COUNTER(nsCSSSelectorList)
00691 
00692 nsCSSSelectorList::nsCSSSelectorList(void)
00693   : mSelectors(nsnull),
00694     mWeight(0),
00695     mNext(nsnull)
00696 {
00697   MOZ_COUNT_CTOR(nsCSSSelectorList);
00698 }
00699 
00700 nsCSSSelectorList::~nsCSSSelectorList()
00701 {
00702   MOZ_COUNT_DTOR(nsCSSSelectorList);
00703   NS_IF_DELETE(mSelectors);
00704   NS_IF_DEEP_DELETE(nsCSSSelectorList, mNext);
00705 }
00706 
00707 void nsCSSSelectorList::AddSelector(const nsCSSSelector& aSelector)
00708 { // prepend to list
00709   nsCSSSelector* newSel = aSelector.Clone();
00710   if (newSel) {
00711     newSel->mNext = mSelectors;
00712     mSelectors = newSel;
00713   }
00714 }
00715 
00716 void
00717 nsCSSSelectorList::ToString(nsAString& aResult, nsICSSStyleSheet* aSheet)
00718 {
00719   aResult.Truncate();
00720   nsCSSSelectorList *p = this;
00721   for (;;) {
00722     p->mSelectors->ToString(aResult, aSheet, PR_TRUE);
00723     p = p->mNext;
00724     if (!p)
00725       break;
00726     aResult.AppendLiteral(", ");
00727   }
00728 }
00729 
00730 nsCSSSelectorList*
00731 nsCSSSelectorList::Clone(PRBool aDeep) const
00732 {
00733   nsCSSSelectorList *result = new nsCSSSelectorList();
00734   result->mWeight = mWeight;
00735   NS_IF_CLONE(mSelectors);
00736 
00737   if (aDeep) {
00738     NS_IF_DEEP_CLONE(nsCSSSelectorList, mNext, (PR_FALSE));
00739   }
00740   return result;
00741 }
00742 
00743 // -- CSSImportantRule -------------------------------
00744 
00745 class CSSStyleRuleImpl;
00746 
00747 class CSSImportantRule : public nsIStyleRule {
00748 public:
00749   CSSImportantRule(nsCSSDeclaration* aDeclaration);
00750 
00751   NS_DECL_ISUPPORTS
00752 
00753   // nsIStyleRule interface
00754   NS_IMETHOD MapRuleInfoInto(nsRuleData* aRuleData);
00755 #ifdef DEBUG
00756   NS_IMETHOD List(FILE* out = stdout, PRInt32 aIndent = 0) const;
00757 #endif
00758 
00759 protected:
00760   virtual ~CSSImportantRule(void);
00761 
00762   nsCSSDeclaration*  mDeclaration;
00763 
00764   friend class CSSStyleRuleImpl;
00765 };
00766 
00767 CSSImportantRule::CSSImportantRule(nsCSSDeclaration* aDeclaration)
00768   : mDeclaration(aDeclaration)
00769 {
00770 }
00771 
00772 CSSImportantRule::~CSSImportantRule(void)
00773 {
00774   mDeclaration = nsnull;
00775 }
00776 
00777 NS_IMPL_ISUPPORTS1(CSSImportantRule, nsIStyleRule)
00778 
00779 NS_IMETHODIMP
00780 CSSImportantRule::MapRuleInfoInto(nsRuleData* aRuleData)
00781 {
00782   // Check this at runtime because it might be hit in some out-of-memory cases.
00783   NS_ENSURE_TRUE(mDeclaration->HasImportantData(), NS_ERROR_UNEXPECTED);
00784 
00785   return mDeclaration->MapImportantRuleInfoInto(aRuleData);
00786 }
00787 
00788 #ifdef DEBUG
00789 NS_IMETHODIMP
00790 CSSImportantRule::List(FILE* out, PRInt32 aIndent) const
00791 {
00792   // Indent
00793   for (PRInt32 index = aIndent; --index >= 0; ) fputs("  ", out);
00794 
00795   fputs("! Important rule ", out);
00796   if (nsnull != mDeclaration) {
00797     mDeclaration->List(out);
00798   }
00799   else {
00800     fputs("{ null declaration }", out);
00801   }
00802   fputs("\n", out);
00803 
00804   return NS_OK;
00805 }
00806 #endif
00807 
00808 // --------------------------------------------------------
00809 
00810 class DOMCSSStyleRuleImpl;
00811 
00812 class DOMCSSDeclarationImpl : public nsDOMCSSDeclaration
00813 {
00814 public:
00815   DOMCSSDeclarationImpl(nsICSSStyleRule *aRule);
00816   virtual ~DOMCSSDeclarationImpl(void);
00817 
00818   NS_IMETHOD GetParentRule(nsIDOMCSSRule **aParent);
00819   virtual void DropReference(void);
00820   virtual nsresult GetCSSDeclaration(nsCSSDeclaration **aDecl,
00821                                      PRBool aAllocate);
00822   virtual nsresult GetCSSParsingEnvironment(nsIURI** aSheetURI,
00823                                             nsIURI** aBaseURI,
00824                                             nsICSSLoader** aCSSLoader,
00825                                             nsICSSParser** aCSSParser);
00826   virtual nsresult DeclarationChanged();
00827 
00828   // Override |AddRef| and |Release| for being a member of
00829   // |DOMCSSStyleRuleImpl|.
00830   NS_IMETHOD_(nsrefcnt) AddRef(void);
00831   NS_IMETHOD_(nsrefcnt) Release(void);
00832 
00833   friend class DOMCSSStyleRuleImpl;
00834 
00835 protected:
00836   // This reference is not reference-counted. The rule object tells us
00837   // when it's about to go away.
00838   nsICSSStyleRule *mRule;
00839 
00840   inline DOMCSSStyleRuleImpl* DomRule();
00841 
00842 private:
00843   // NOT TO BE IMPLEMENTED
00844   // This object cannot be allocated on its own.  It must be a member of
00845   // DOMCSSStyleRuleImpl.
00846   void* operator new(size_t size) CPP_THROW_NEW;
00847 };
00848 
00849 class DOMCSSStyleRuleImpl : public nsICSSStyleRuleDOMWrapper
00850 {
00851 public:
00852   DOMCSSStyleRuleImpl(nsICSSStyleRule *aRule);
00853   virtual ~DOMCSSStyleRuleImpl();
00854 
00855   NS_DECL_ISUPPORTS
00856   NS_DECL_NSIDOMCSSRULE
00857   NS_DECL_NSIDOMCSSSTYLERULE
00858 
00859   // nsICSSStyleRuleDOMWrapper
00860   NS_IMETHOD GetCSSStyleRule(nsICSSStyleRule **aResult);
00861 
00862   DOMCSSDeclarationImpl* DOMDeclaration() { return &mDOMDeclaration; }
00863 
00864   friend class DOMCSSDeclarationImpl;
00865 
00866 protected:
00867   DOMCSSDeclarationImpl mDOMDeclaration;
00868 
00869   nsICSSStyleRule* Rule() {
00870     return mDOMDeclaration.mRule;
00871   }
00872 };
00873 
00874 MOZ_DECL_CTOR_COUNTER(DOMCSSDeclarationImpl)
00875 
00876 DOMCSSDeclarationImpl::DOMCSSDeclarationImpl(nsICSSStyleRule *aRule)
00877   : mRule(aRule)
00878 {
00879   MOZ_COUNT_CTOR(DOMCSSDeclarationImpl);
00880 }
00881 
00882 DOMCSSDeclarationImpl::~DOMCSSDeclarationImpl(void)
00883 {
00884   NS_ASSERTION(!mRule, "DropReference not called.");
00885 
00886   MOZ_COUNT_DTOR(DOMCSSDeclarationImpl);
00887 }
00888 
00889 inline DOMCSSStyleRuleImpl* DOMCSSDeclarationImpl::DomRule()
00890 {
00891   return NS_REINTERPRET_CAST(DOMCSSStyleRuleImpl*,
00892            NS_REINTERPRET_CAST(char*, this) -
00893            offsetof(DOMCSSStyleRuleImpl, mDOMDeclaration));
00894 }
00895 
00896 NS_IMPL_ADDREF_USING_AGGREGATOR(DOMCSSDeclarationImpl, DomRule())
00897 NS_IMPL_RELEASE_USING_AGGREGATOR(DOMCSSDeclarationImpl, DomRule())
00898 
00899 void
00900 DOMCSSDeclarationImpl::DropReference(void)
00901 {
00902   mRule = nsnull;
00903 }
00904 
00905 nsresult
00906 DOMCSSDeclarationImpl::GetCSSDeclaration(nsCSSDeclaration **aDecl,
00907                                          PRBool aAllocate)
00908 {
00909   if (mRule) {
00910     *aDecl = mRule->GetDeclaration();
00911   }
00912   else {
00913     *aDecl = nsnull;
00914   }
00915 
00916   return NS_OK;
00917 }
00918 
00919 /*
00920  * This is a utility function.  It will only fail if it can't get a
00921  * parser.  This means it can return NS_OK without aURI or aCSSLoader
00922  * being initialized.
00923  */
00924 nsresult
00925 DOMCSSDeclarationImpl::GetCSSParsingEnvironment(nsIURI** aSheetURI, 
00926                                                 nsIURI** aBaseURI,
00927                                                 nsICSSLoader** aCSSLoader,
00928                                                 nsICSSParser** aCSSParser)
00929 {
00930   // null out the out params since some of them may not get initialized below
00931   *aSheetURI = nsnull;
00932   *aBaseURI = nsnull;
00933   *aCSSLoader = nsnull;
00934   *aCSSParser = nsnull;
00935   nsresult result;
00936   nsCOMPtr<nsIStyleSheet> sheet;
00937   if (mRule) {
00938     mRule->GetStyleSheet(*getter_AddRefs(sheet));
00939     if (sheet) {
00940       sheet->GetSheetURI(aSheetURI);
00941       sheet->GetBaseURI(aBaseURI);
00942       nsCOMPtr<nsIDocument> document;
00943       sheet->GetOwningDocument(*getter_AddRefs(document));
00944       if (document) {
00945         NS_ADDREF(*aCSSLoader = document->CSSLoader());
00946       }
00947     }
00948   }
00949   // XXXldb Why bother if |mRule| is null?
00950   if (*aCSSLoader) {
00951     result = (*aCSSLoader)->GetParserFor(nsnull, aCSSParser);
00952   } else {
00953     result = NS_NewCSSParser(aCSSParser);
00954   }
00955 
00956   return result;
00957 }
00958 
00959 NS_IMETHODIMP
00960 DOMCSSDeclarationImpl::GetParentRule(nsIDOMCSSRule **aParent)
00961 {
00962   NS_ENSURE_ARG_POINTER(aParent);
00963 
00964   if (!mRule) {
00965     *aParent = nsnull;
00966     return NS_OK;
00967   }
00968 
00969   return mRule->GetDOMRule(aParent);
00970 }
00971 
00972 nsresult
00973 DOMCSSDeclarationImpl::DeclarationChanged()
00974 {
00975   NS_PRECONDITION(mRule,
00976          "can only be called when |GetCSSDeclaration| returned a declaration");
00977 
00978   nsCOMPtr<nsIDocument> owningDoc;
00979   nsCOMPtr<nsIStyleSheet> sheet;
00980   mRule->GetStyleSheet(*getter_AddRefs(sheet));
00981   if (sheet) {
00982     sheet->GetOwningDocument(*getter_AddRefs(owningDoc));
00983   }
00984 
00985   mozAutoDocUpdate updateBatch(owningDoc, UPDATE_STYLE, PR_TRUE);
00986 
00987   nsCOMPtr<nsICSSStyleRule> oldRule = mRule;
00988   mRule = oldRule->DeclarationChanged(PR_TRUE).get();
00989   if (!mRule)
00990     return NS_ERROR_OUT_OF_MEMORY;
00991   nsrefcnt cnt = mRule->Release();
00992   if (cnt == 0) {
00993     NS_NOTREACHED("container didn't take ownership");
00994     mRule = nsnull;
00995     return NS_ERROR_UNEXPECTED;
00996   }
00997 
00998   if (owningDoc) {
00999     owningDoc->StyleRuleChanged(sheet, oldRule, mRule);
01000   }
01001   return NS_OK;
01002 }
01003 
01004 DOMCSSStyleRuleImpl::DOMCSSStyleRuleImpl(nsICSSStyleRule* aRule)
01005   : mDOMDeclaration(aRule)
01006 {
01007 }
01008 
01009 DOMCSSStyleRuleImpl::~DOMCSSStyleRuleImpl()
01010 {
01011 }
01012 
01013 NS_INTERFACE_MAP_BEGIN(DOMCSSStyleRuleImpl)
01014   NS_INTERFACE_MAP_ENTRY(nsICSSStyleRuleDOMWrapper)
01015   NS_INTERFACE_MAP_ENTRY(nsIDOMCSSStyleRule)
01016   NS_INTERFACE_MAP_ENTRY(nsIDOMCSSRule)
01017   NS_INTERFACE_MAP_ENTRY(nsISupports)
01018   NS_INTERFACE_MAP_ENTRY_CONTENT_CLASSINFO(CSSStyleRule)
01019 NS_INTERFACE_MAP_END
01020 
01021 NS_IMPL_ADDREF(DOMCSSStyleRuleImpl)
01022 NS_IMPL_RELEASE(DOMCSSStyleRuleImpl)
01023 
01024 NS_IMETHODIMP    
01025 DOMCSSStyleRuleImpl::GetType(PRUint16* aType)
01026 {
01027   *aType = nsIDOMCSSRule::STYLE_RULE;
01028   
01029   return NS_OK;
01030 }
01031 
01032 NS_IMETHODIMP    
01033 DOMCSSStyleRuleImpl::GetCssText(nsAString& aCssText)
01034 {
01035   if (!Rule()) {
01036     aCssText.Truncate();
01037     return NS_OK;
01038   }
01039   return Rule()->GetCssText(aCssText);
01040 }
01041 
01042 NS_IMETHODIMP    
01043 DOMCSSStyleRuleImpl::SetCssText(const nsAString& aCssText)
01044 {
01045   if (!Rule()) {
01046     return NS_OK;
01047   }
01048   return Rule()->SetCssText(aCssText);
01049 }
01050 
01051 NS_IMETHODIMP    
01052 DOMCSSStyleRuleImpl::GetParentStyleSheet(nsIDOMCSSStyleSheet** aSheet)
01053 {
01054   if (!Rule()) {
01055     *aSheet = nsnull;
01056     return NS_OK;
01057   }
01058   nsCOMPtr<nsICSSStyleSheet> sheet;
01059   Rule()->GetParentStyleSheet(getter_AddRefs(sheet));
01060   if (!sheet) {
01061     *aSheet = nsnull;
01062     return NS_OK;
01063   }
01064   return CallQueryInterface(sheet, aSheet);
01065 }
01066 
01067 NS_IMETHODIMP    
01068 DOMCSSStyleRuleImpl::GetParentRule(nsIDOMCSSRule** aParentRule)
01069 {
01070   if (!Rule()) {
01071     *aParentRule = nsnull;
01072     return NS_OK;
01073   }
01074   nsCOMPtr<nsICSSGroupRule> rule;
01075   Rule()->GetParentRule(getter_AddRefs(rule));
01076   if (!rule) {
01077     *aParentRule = nsnull;
01078     return NS_OK;
01079   }
01080   return rule->GetDOMRule(aParentRule);
01081 }
01082 
01083 NS_IMETHODIMP    
01084 DOMCSSStyleRuleImpl::GetSelectorText(nsAString& aSelectorText)
01085 {
01086   if (!Rule()) {
01087     aSelectorText.Truncate();
01088     return NS_OK;
01089   }
01090   return Rule()->GetSelectorText(aSelectorText);
01091 }
01092 
01093 NS_IMETHODIMP    
01094 DOMCSSStyleRuleImpl::SetSelectorText(const nsAString& aSelectorText)
01095 {
01096   if (!Rule()) {
01097     return NS_OK;
01098   }
01099   return Rule()->SetSelectorText(aSelectorText);
01100 }
01101 
01102 NS_IMETHODIMP    
01103 DOMCSSStyleRuleImpl::GetStyle(nsIDOMCSSStyleDeclaration** aStyle)
01104 {
01105   *aStyle = &mDOMDeclaration;
01106   NS_ADDREF(*aStyle);
01107   return NS_OK;
01108 }
01109 
01110 NS_IMETHODIMP
01111 DOMCSSStyleRuleImpl::GetCSSStyleRule(nsICSSStyleRule **aResult)
01112 {
01113   *aResult = Rule();
01114   NS_IF_ADDREF(*aResult);
01115   return NS_OK;
01116 }
01117 
01118 // -- nsCSSStyleRule -------------------------------
01119 
01120 class CSSStyleRuleImpl : public nsCSSRule,
01121                          public nsICSSStyleRule
01122 {
01123 public:
01124   CSSStyleRuleImpl(nsCSSSelectorList* aSelector,
01125                    nsCSSDeclaration *aDeclaration);
01126 private:
01127   // for |Clone|
01128   CSSStyleRuleImpl(const CSSStyleRuleImpl& aCopy); 
01129   // for |DeclarationChanged|
01130   CSSStyleRuleImpl(CSSStyleRuleImpl& aCopy,
01131                    nsCSSDeclaration *aDeclaration); 
01132 public:
01133 
01134   NS_DECL_ISUPPORTS_INHERITED
01135 
01136   virtual nsCSSSelectorList* Selector(void);
01137 
01138   virtual PRUint32 GetLineNumber(void) const;
01139   virtual void SetLineNumber(PRUint32 aLineNumber);
01140 
01141   virtual nsCSSDeclaration* GetDeclaration(void) const;
01142 
01143   virtual already_AddRefed<nsIStyleRule> GetImportantRule(void);
01144 
01145   NS_IMETHOD GetStyleSheet(nsIStyleSheet*& aSheet) const;
01146   NS_IMETHOD SetStyleSheet(nsICSSStyleSheet* aSheet);
01147   
01148   NS_IMETHOD SetParentRule(nsICSSGroupRule* aRule);
01149 
01150   virtual nsresult GetCssText(nsAString& aCssText);
01151   virtual nsresult SetCssText(const nsAString& aCssText);
01152   virtual nsresult GetParentStyleSheet(nsICSSStyleSheet** aSheet);
01153   virtual nsresult GetParentRule(nsICSSGroupRule** aParentRule);
01154   virtual nsresult GetSelectorText(nsAString& aSelectorText);
01155   virtual nsresult SetSelectorText(const nsAString& aSelectorText);
01156 
01157   NS_IMETHOD GetType(PRInt32& aType) const;
01158   NS_IMETHOD Clone(nsICSSRule*& aClone) const;
01159 
01160   NS_IMETHOD GetDOMRule(nsIDOMCSSRule** aDOMRule);
01161 
01162   virtual already_AddRefed<nsICSSStyleRule>
01163     DeclarationChanged(PRBool aHandleContainer);
01164 
01165   // The new mapping function.
01166   NS_IMETHOD MapRuleInfoInto(nsRuleData* aRuleData);
01167 
01168 #ifdef DEBUG
01169   NS_IMETHOD List(FILE* out = stdout, PRInt32 aIndent = 0) const;
01170 #endif
01171 
01172 private: 
01173   // These are not supported and are not implemented! 
01174   CSSStyleRuleImpl& operator=(const CSSStyleRuleImpl& aCopy); 
01175 
01176 protected:
01177   virtual ~CSSStyleRuleImpl(void);
01178 
01179 protected:
01180   nsCSSSelectorList*      mSelector; // null for style attribute
01181   nsCSSDeclaration*       mDeclaration;
01182   CSSImportantRule*       mImportantRule;
01183   DOMCSSStyleRuleImpl*    mDOMRule;                          
01184   PRUint32                mLineNumber;
01185 };
01186 
01187 CSSStyleRuleImpl::CSSStyleRuleImpl(nsCSSSelectorList* aSelector,
01188                                    nsCSSDeclaration* aDeclaration)
01189   : nsCSSRule(),
01190     mSelector(aSelector),
01191     mDeclaration(aDeclaration), 
01192     mImportantRule(nsnull),
01193     mDOMRule(nsnull),
01194     mLineNumber(0)
01195 {
01196   mDeclaration->AddRef();
01197 }
01198 
01199 // for |Clone|
01200 CSSStyleRuleImpl::CSSStyleRuleImpl(const CSSStyleRuleImpl& aCopy)
01201   : nsCSSRule(aCopy),
01202     mSelector(aCopy.mSelector ? aCopy.mSelector->Clone() : nsnull),
01203     mDeclaration(aCopy.mDeclaration->Clone()),
01204     mImportantRule(nsnull),
01205     mDOMRule(nsnull),
01206     mLineNumber(aCopy.mLineNumber)
01207 {
01208   if (mDeclaration)
01209     mDeclaration->AddRef();
01210   // rest is constructed lazily on existing data
01211 }
01212 
01213 // for |DeclarationChanged|
01214 CSSStyleRuleImpl::CSSStyleRuleImpl(CSSStyleRuleImpl& aCopy,
01215                                    nsCSSDeclaration* aDeclaration)
01216   : nsCSSRule(aCopy),
01217     mSelector(aCopy.mSelector),
01218     mDeclaration(aDeclaration),
01219     mImportantRule(nsnull),
01220     mDOMRule(aCopy.mDOMRule),
01221     mLineNumber(aCopy.mLineNumber)
01222 {
01223   // The DOM rule is replacing |aCopy| with |this|, so transfer
01224   // the reverse pointer as well (and transfer ownership).
01225   aCopy.mDOMRule = nsnull;
01226 
01227   NS_ASSERTION(aDeclaration == aCopy.mDeclaration, "declaration mismatch");
01228   // Transfer ownership of selector and declaration:
01229   aCopy.mSelector = nsnull;
01230 #if 0
01231   aCopy.mDeclaration = nsnull;
01232 #else
01233   // We ought to be able to transfer ownership of the selector and the
01234   // declaration since this rule should now be unused, but unfortunately
01235   // SetInlineStyleRule might use it before setting the new rule (see
01236   // stack in bug 209575).  So leave the declaration pointer on the old
01237   // rule.
01238   mDeclaration->AddRef();
01239 #endif
01240 }
01241 
01242 
01243 CSSStyleRuleImpl::~CSSStyleRuleImpl(void)
01244 {
01245   if (mSelector) {
01246     delete mSelector;
01247     mSelector = nsnull;
01248   }
01249   if (nsnull != mDeclaration) {
01250     mDeclaration->Release();
01251     mDeclaration = nsnull;
01252   }
01253   if (nsnull != mImportantRule) {
01254     NS_RELEASE(mImportantRule);
01255     mImportantRule = nsnull;
01256   }
01257   if (mDOMRule) {
01258     mDOMRule->DOMDeclaration()->DropReference();
01259     NS_RELEASE(mDOMRule);
01260   }
01261 }
01262 
01263 // QueryInterface implementation for CSSStyleRuleImpl
01264 NS_INTERFACE_MAP_BEGIN(CSSStyleRuleImpl)
01265   NS_INTERFACE_MAP_ENTRY(nsICSSStyleRule)
01266   NS_INTERFACE_MAP_ENTRY(nsICSSRule)
01267   NS_INTERFACE_MAP_ENTRY(nsIStyleRule)
01268   NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsICSSStyleRule)
01269 NS_INTERFACE_MAP_END
01270 
01271 NS_IMPL_ADDREF_INHERITED(CSSStyleRuleImpl, nsCSSRule)
01272 NS_IMPL_RELEASE_INHERITED(CSSStyleRuleImpl, nsCSSRule)
01273 
01274 nsCSSSelectorList* CSSStyleRuleImpl::Selector(void)
01275 {
01276   return mSelector;
01277 }
01278 
01279 PRUint32 CSSStyleRuleImpl::GetLineNumber(void) const
01280 {
01281   return mLineNumber;
01282 }
01283 
01284 void CSSStyleRuleImpl::SetLineNumber(PRUint32 aLineNumber)
01285 {
01286   mLineNumber = aLineNumber;
01287 }
01288 
01289 nsCSSDeclaration* CSSStyleRuleImpl::GetDeclaration(void) const
01290 {
01291   return mDeclaration;
01292 }
01293 
01294 already_AddRefed<nsIStyleRule> CSSStyleRuleImpl::GetImportantRule(void)
01295 {
01296   if (!mDeclaration->HasImportantData()) {
01297     NS_ASSERTION(!mImportantRule, "immutable, so should be no important rule");
01298     return nsnull;
01299   }
01300 
01301   if (!mImportantRule) {
01302     mImportantRule = new CSSImportantRule(mDeclaration);
01303     if (!mImportantRule)
01304       return nsnull;
01305     NS_ADDREF(mImportantRule);
01306   }
01307   NS_ADDREF(mImportantRule);
01308   return mImportantRule;
01309 }
01310 
01311 NS_IMETHODIMP
01312 CSSStyleRuleImpl::GetStyleSheet(nsIStyleSheet*& aSheet) const
01313 {
01314 // XXX What about inner, etc.
01315   return nsCSSRule::GetStyleSheet(aSheet);
01316 }
01317 
01318 NS_IMETHODIMP
01319 CSSStyleRuleImpl::SetStyleSheet(nsICSSStyleSheet* aSheet)
01320 {
01321   return nsCSSRule::SetStyleSheet(aSheet);
01322 }
01323 
01324 NS_IMETHODIMP
01325 CSSStyleRuleImpl::SetParentRule(nsICSSGroupRule* aRule)
01326 {
01327   return nsCSSRule::SetParentRule(aRule);
01328 }
01329 
01330 NS_IMETHODIMP
01331 CSSStyleRuleImpl::GetType(PRInt32& aType) const
01332 {
01333   aType = nsICSSRule::STYLE_RULE;
01334   return NS_OK;
01335 }
01336 
01337 NS_IMETHODIMP
01338 CSSStyleRuleImpl::Clone(nsICSSRule*& aClone) const
01339 {
01340   CSSStyleRuleImpl* clone = new CSSStyleRuleImpl(*this);
01341   if (!clone || !clone->mDeclaration || (!clone->mSelector != !mSelector)) {
01342     delete clone;
01343     aClone = nsnull;
01344     return NS_ERROR_OUT_OF_MEMORY;
01345   }
01346   return CallQueryInterface(clone, &aClone);
01347 }
01348 
01349 NS_IMETHODIMP
01350 CSSStyleRuleImpl::GetDOMRule(nsIDOMCSSRule** aDOMRule)
01351 {
01352   if (!mSheet) {
01353     // inline style rules aren't supposed to have a DOM rule object, only
01354     // a declaration.
01355     *aDOMRule = nsnull;
01356     return NS_OK;
01357   }
01358   if (!mDOMRule) {
01359     mDOMRule = new DOMCSSStyleRuleImpl(this);
01360     if (!mDOMRule) {
01361       *aDOMRule = nsnull;
01362       return NS_ERROR_OUT_OF_MEMORY;
01363     }
01364     NS_ADDREF(mDOMRule);
01365   }
01366   *aDOMRule = mDOMRule;
01367   NS_ADDREF(*aDOMRule);
01368   return NS_OK;
01369 }
01370 
01371 /* virtual */ already_AddRefed<nsICSSStyleRule>
01372 CSSStyleRuleImpl::DeclarationChanged(PRBool aHandleContainer)
01373 {
01374   CSSStyleRuleImpl* clone = new CSSStyleRuleImpl(*this, mDeclaration);
01375   if (!clone) {
01376     return nsnull;
01377   }
01378 
01379   NS_ADDREF(clone); // for return
01380 
01381   if (aHandleContainer) {
01382     NS_ASSERTION(mSheet, "rule must be in a sheet");
01383     if (mParentRule) {
01384       mSheet->ReplaceRuleInGroup(mParentRule, this, clone);
01385     } else {
01386       mSheet->ReplaceStyleRule(this, clone);
01387     }
01388   }
01389 
01390   return clone;
01391 }
01392 
01393 NS_IMETHODIMP
01394 CSSStyleRuleImpl::MapRuleInfoInto(nsRuleData* aRuleData)
01395 {
01396   return mDeclaration->MapRuleInfoInto(aRuleData);
01397 }
01398 
01399 #ifdef DEBUG
01400 NS_IMETHODIMP
01401 CSSStyleRuleImpl::List(FILE* out, PRInt32 aIndent) const
01402 {
01403   // Indent
01404   for (PRInt32 index = aIndent; --index >= 0; ) fputs("  ", out);
01405 
01406   nsAutoString buffer;
01407   if (mSelector)
01408     mSelector->ToString(buffer, mSheet);
01409 
01410   buffer.AppendLiteral(" ");
01411   fputs(NS_LossyConvertUCS2toASCII(buffer).get(), out);
01412   if (nsnull != mDeclaration) {
01413     mDeclaration->List(out);
01414   }
01415   else {
01416     fputs("{ null declaration }", out);
01417   }
01418   fputs("\n", out);
01419 
01420   return NS_OK;
01421 }
01422 #endif
01423 
01424 /* virtual */ nsresult
01425 CSSStyleRuleImpl::GetCssText(nsAString& aCssText)
01426 {
01427   if (mSelector) {
01428     mSelector->ToString(aCssText, mSheet);
01429     aCssText.Append(PRUnichar(' '));
01430   }
01431   aCssText.Append(PRUnichar('{'));
01432   aCssText.Append(PRUnichar(' '));
01433   if (mDeclaration)
01434   {
01435     nsAutoString   tempString;
01436     mDeclaration->ToString( tempString );
01437     aCssText.Append( tempString );
01438   }
01439   aCssText.Append(PRUnichar(' '));
01440   aCssText.Append(PRUnichar('}'));
01441   return NS_OK;
01442 }
01443 
01444 /* virtual */ nsresult    
01445 CSSStyleRuleImpl::SetCssText(const nsAString& aCssText)
01446 {
01447   // XXX TBI - need to re-parse rule & declaration
01448   return NS_OK;
01449 }
01450 
01451 /* virtual */ nsresult    
01452 CSSStyleRuleImpl::GetParentStyleSheet(nsICSSStyleSheet** aSheet)
01453 {
01454   *aSheet = mSheet;
01455   NS_IF_ADDREF(*aSheet);
01456   return NS_OK;
01457 }
01458 
01459 /* virtual */ nsresult    
01460 CSSStyleRuleImpl::GetParentRule(nsICSSGroupRule** aParentRule)
01461 {
01462   *aParentRule = mParentRule;
01463   NS_IF_ADDREF(*aParentRule);
01464   return NS_OK;
01465 }
01466 
01467 /* virtual */ nsresult    
01468 CSSStyleRuleImpl::GetSelectorText(nsAString& aSelectorText)
01469 {
01470   if (mSelector)
01471     mSelector->ToString(aSelectorText, mSheet);
01472   else
01473     aSelectorText.Truncate();
01474   return NS_OK;
01475 }
01476 
01477 /* virtual */ nsresult    
01478 CSSStyleRuleImpl::SetSelectorText(const nsAString& aSelectorText)
01479 {
01480   // XXX TBI - get a parser and re-parse the selectors, 
01481   // XXX then need to re-compute the cascade
01482   // XXX and dirty sheet
01483   return NS_OK;
01484 }
01485 
01486 nsresult
01487 NS_NewCSSStyleRule(nsICSSStyleRule** aInstancePtrResult,
01488                    nsCSSSelectorList* aSelector,
01489                    nsCSSDeclaration* aDeclaration)
01490 {
01491   NS_PRECONDITION(aDeclaration, "must have a declaration");
01492   CSSStyleRuleImpl *it = new CSSStyleRuleImpl(aSelector, aDeclaration);
01493   if (!it) {
01494     return NS_ERROR_OUT_OF_MEMORY;
01495   }
01496 
01497   return CallQueryInterface(it, aInstancePtrResult);
01498 }