layout/style/StyleRule.cpp

Wed, 31 Dec 2014 06:55:50 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Wed, 31 Dec 2014 06:55:50 +0100
changeset 2
7e26c7da4463
permissions
-rw-r--r--

Added tag UPSTREAM_283F7C6 for changeset ca08bd8f51b2

     1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
     2 /* This Source Code Form is subject to the terms of the Mozilla Public
     3  * License, v. 2.0. If a copy of the MPL was not distributed with this
     4  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
     6 /*
     7  * representation of CSS style rules (selectors+declaration), CSS
     8  * selectors, and DOM objects for style rules, selectors, and
     9  * declarations
    10  */
    12 #include "mozilla/css/StyleRule.h"
    14 #include "mozilla/MemoryReporting.h"
    15 #include "mozilla/css/GroupRule.h"
    16 #include "mozilla/css/Declaration.h"
    17 #include "nsCSSStyleSheet.h"
    18 #include "nsIDocument.h"
    19 #include "nsIAtom.h"
    20 #include "nsString.h"
    21 #include "nsStyleUtil.h"
    22 #include "nsICSSStyleRuleDOMWrapper.h"
    23 #include "nsDOMCSSDeclaration.h"
    24 #include "nsNameSpaceManager.h"
    25 #include "nsXMLNameSpaceMap.h"
    26 #include "nsCSSPseudoElements.h"
    27 #include "nsCSSPseudoClasses.h"
    28 #include "nsCSSAnonBoxes.h"
    29 #include "nsTArray.h"
    30 #include "nsDOMClassInfoID.h"
    31 #include "nsContentUtils.h"
    32 #include "nsError.h"
    33 #include "mozAutoDocUpdate.h"
    35 class nsIDOMCSSStyleDeclaration;
    36 class nsIDOMCSSStyleSheet;
    38 using namespace mozilla;
    40 #define NS_IF_CLONE(member_)                                                  \
    41   PR_BEGIN_MACRO                                                              \
    42     if (member_) {                                                            \
    43       result->member_ = member_->Clone();                                     \
    44       if (!result->member_) {                                                 \
    45         delete result;                                                        \
    46         return nullptr;                                                        \
    47       }                                                                       \
    48     }                                                                         \
    49   PR_END_MACRO
    51 #define NS_IF_DELETE(ptr)                                                     \
    52   PR_BEGIN_MACRO                                                              \
    53     delete ptr;                                                               \
    54     ptr = nullptr;                                                             \
    55   PR_END_MACRO
    57 /* ************************************************************************** */
    59 nsAtomList::nsAtomList(nsIAtom* aAtom)
    60   : mAtom(aAtom),
    61     mNext(nullptr)
    62 {
    63   MOZ_COUNT_CTOR(nsAtomList);
    64 }
    66 nsAtomList::nsAtomList(const nsString& aAtomValue)
    67   : mAtom(nullptr),
    68     mNext(nullptr)
    69 {
    70   MOZ_COUNT_CTOR(nsAtomList);
    71   mAtom = do_GetAtom(aAtomValue);
    72 }
    74 nsAtomList*
    75 nsAtomList::Clone(bool aDeep) const
    76 {
    77   nsAtomList *result = new nsAtomList(mAtom);
    78   if (!result)
    79     return nullptr;
    81   if (aDeep)
    82     NS_CSS_CLONE_LIST_MEMBER(nsAtomList, this, mNext, result, (false));
    83   return result;
    84 }
    86 size_t
    87 nsAtomList::SizeOfIncludingThis(mozilla::MallocSizeOf aMallocSizeOf) const
    88 {
    89   size_t n = 0;
    90   const nsAtomList* a = this;
    91   while (a) {
    92     n += aMallocSizeOf(a);
    94     // The following members aren't measured:
    95     // - a->mAtom, because it may be shared
    97     a = a->mNext;
    98   }
    99   return n;
   100 }
   102 nsAtomList::~nsAtomList(void)
   103 {
   104   MOZ_COUNT_DTOR(nsAtomList);
   105   NS_CSS_DELETE_LIST_MEMBER(nsAtomList, this, mNext);
   106 }
   108 nsPseudoClassList::nsPseudoClassList(nsCSSPseudoClasses::Type aType)
   109   : mType(aType),
   110     mNext(nullptr)
   111 {
   112   NS_ASSERTION(!nsCSSPseudoClasses::HasStringArg(aType) &&
   113                !nsCSSPseudoClasses::HasNthPairArg(aType),
   114                "unexpected pseudo-class");
   115   MOZ_COUNT_CTOR(nsPseudoClassList);
   116   u.mMemory = nullptr;
   117 }
   119 nsPseudoClassList::nsPseudoClassList(nsCSSPseudoClasses::Type aType,
   120                                      const char16_t* aString)
   121   : mType(aType),
   122     mNext(nullptr)
   123 {
   124   NS_ASSERTION(nsCSSPseudoClasses::HasStringArg(aType),
   125                "unexpected pseudo-class");
   126   NS_ASSERTION(aString, "string expected");
   127   MOZ_COUNT_CTOR(nsPseudoClassList);
   128   u.mString = NS_strdup(aString);
   129 }
   131 nsPseudoClassList::nsPseudoClassList(nsCSSPseudoClasses::Type aType,
   132                                      const int32_t* aIntPair)
   133   : mType(aType),
   134     mNext(nullptr)
   135 {
   136   NS_ASSERTION(nsCSSPseudoClasses::HasNthPairArg(aType),
   137                "unexpected pseudo-class");
   138   NS_ASSERTION(aIntPair, "integer pair expected");
   139   MOZ_COUNT_CTOR(nsPseudoClassList);
   140   u.mNumbers =
   141     static_cast<int32_t*>(nsMemory::Clone(aIntPair, sizeof(int32_t) * 2));
   142 }
   144 // adopts aSelectorList
   145 nsPseudoClassList::nsPseudoClassList(nsCSSPseudoClasses::Type aType,
   146                                      nsCSSSelectorList* aSelectorList)
   147   : mType(aType),
   148     mNext(nullptr)
   149 {
   150   NS_ASSERTION(nsCSSPseudoClasses::HasSelectorListArg(aType),
   151                "unexpected pseudo-class");
   152   NS_ASSERTION(aSelectorList, "selector list expected");
   153   MOZ_COUNT_CTOR(nsPseudoClassList);
   154   u.mSelectors = aSelectorList;
   155 }
   157 nsPseudoClassList*
   158 nsPseudoClassList::Clone(bool aDeep) const
   159 {
   160   nsPseudoClassList *result;
   161   if (!u.mMemory) {
   162     result = new nsPseudoClassList(mType);
   163   } else if (nsCSSPseudoClasses::HasStringArg(mType)) {
   164     result = new nsPseudoClassList(mType, u.mString);
   165   } else if (nsCSSPseudoClasses::HasNthPairArg(mType)) {
   166     result = new nsPseudoClassList(mType, u.mNumbers);
   167   } else {
   168     NS_ASSERTION(nsCSSPseudoClasses::HasSelectorListArg(mType),
   169                  "unexpected pseudo-class");
   170     // This constructor adopts its selector list argument.
   171     result = new nsPseudoClassList(mType, u.mSelectors->Clone());
   172   }
   174   if (aDeep)
   175     NS_CSS_CLONE_LIST_MEMBER(nsPseudoClassList, this, mNext, result,
   176                              (false));
   178   return result;
   179 }
   181 size_t
   182 nsPseudoClassList::SizeOfIncludingThis(mozilla::MallocSizeOf aMallocSizeOf) const
   183 {
   184   size_t n = 0;
   185   const nsPseudoClassList* p = this;
   186   while (p) {
   187     n += aMallocSizeOf(p);
   188     if (!p->u.mMemory) {
   189       // do nothing
   191     } else if (nsCSSPseudoClasses::HasStringArg(p->mType)) {
   192       n += aMallocSizeOf(p->u.mString);
   194     } else if (nsCSSPseudoClasses::HasNthPairArg(p->mType)) {
   195       n += aMallocSizeOf(p->u.mNumbers);
   197     } else {
   198       NS_ASSERTION(nsCSSPseudoClasses::HasSelectorListArg(p->mType),
   199                    "unexpected pseudo-class");
   200       n += p->u.mSelectors->SizeOfIncludingThis(aMallocSizeOf);
   201     }
   202     p = p->mNext;
   203   }
   204   return n;
   205 }
   207 nsPseudoClassList::~nsPseudoClassList(void)
   208 {
   209   MOZ_COUNT_DTOR(nsPseudoClassList);
   210   if (nsCSSPseudoClasses::HasSelectorListArg(mType)) {
   211     delete u.mSelectors;
   212   } else if (u.mMemory) {
   213     NS_Free(u.mMemory);
   214   }
   215   NS_CSS_DELETE_LIST_MEMBER(nsPseudoClassList, this, mNext);
   216 }
   218 nsAttrSelector::nsAttrSelector(int32_t aNameSpace, const nsString& aAttr)
   219   : mValue(),
   220     mNext(nullptr),
   221     mLowercaseAttr(nullptr),
   222     mCasedAttr(nullptr),
   223     mNameSpace(aNameSpace),
   224     mFunction(NS_ATTR_FUNC_SET),
   225     mCaseSensitive(1)
   226 {
   227   MOZ_COUNT_CTOR(nsAttrSelector);
   229   nsAutoString lowercase;
   230   nsContentUtils::ASCIIToLower(aAttr, lowercase);
   232   mCasedAttr = do_GetAtom(aAttr);
   233   mLowercaseAttr = do_GetAtom(lowercase);
   234 }
   236 nsAttrSelector::nsAttrSelector(int32_t aNameSpace, const nsString& aAttr, uint8_t aFunction, 
   237                                const nsString& aValue, bool aCaseSensitive)
   238   : mValue(aValue),
   239     mNext(nullptr),
   240     mLowercaseAttr(nullptr),
   241     mCasedAttr(nullptr),
   242     mNameSpace(aNameSpace),
   243     mFunction(aFunction),
   244     mCaseSensitive(aCaseSensitive)
   245 {
   246   MOZ_COUNT_CTOR(nsAttrSelector);
   248   nsAutoString lowercase;
   249   nsContentUtils::ASCIIToLower(aAttr, lowercase);
   251   mCasedAttr = do_GetAtom(aAttr);
   252   mLowercaseAttr = do_GetAtom(lowercase);
   253 }
   255 nsAttrSelector::nsAttrSelector(int32_t aNameSpace,  nsIAtom* aLowercaseAttr,
   256                                nsIAtom* aCasedAttr, uint8_t aFunction, 
   257                                const nsString& aValue, bool aCaseSensitive)
   258   : mValue(aValue),
   259     mNext(nullptr),
   260     mLowercaseAttr(aLowercaseAttr),
   261     mCasedAttr(aCasedAttr),
   262     mNameSpace(aNameSpace),
   263     mFunction(aFunction),
   264     mCaseSensitive(aCaseSensitive)
   265 {
   266   MOZ_COUNT_CTOR(nsAttrSelector);
   267 }
   269 nsAttrSelector*
   270 nsAttrSelector::Clone(bool aDeep) const
   271 {
   272   nsAttrSelector *result =
   273     new nsAttrSelector(mNameSpace, mLowercaseAttr, mCasedAttr, 
   274                        mFunction, mValue, mCaseSensitive);
   276   if (aDeep)
   277     NS_CSS_CLONE_LIST_MEMBER(nsAttrSelector, this, mNext, result, (false));
   279   return result;
   280 }
   282 nsAttrSelector::~nsAttrSelector(void)
   283 {
   284   MOZ_COUNT_DTOR(nsAttrSelector);
   286   NS_CSS_DELETE_LIST_MEMBER(nsAttrSelector, this, mNext);
   287 }
   289 // -- nsCSSSelector -------------------------------
   291 nsCSSSelector::nsCSSSelector(void)
   292   : mLowercaseTag(nullptr),
   293     mCasedTag(nullptr),
   294     mIDList(nullptr),
   295     mClassList(nullptr),
   296     mPseudoClassList(nullptr),
   297     mAttrList(nullptr),
   298     mNegations(nullptr),
   299     mNext(nullptr),
   300     mNameSpace(kNameSpaceID_Unknown),
   301     mOperator(0),
   302     mPseudoType(nsCSSPseudoElements::ePseudo_NotPseudoElement)
   303 {
   304   MOZ_COUNT_CTOR(nsCSSSelector);
   305   static_assert(nsCSSPseudoElements::ePseudo_MAX < INT16_MAX,
   306                 "nsCSSPseudoElements::Type values overflow mPseudoType");
   307 }
   309 nsCSSSelector*
   310 nsCSSSelector::Clone(bool aDeepNext, bool aDeepNegations) const
   311 {
   312   nsCSSSelector *result = new nsCSSSelector();
   313   if (!result)
   314     return nullptr;
   316   result->mNameSpace = mNameSpace;
   317   result->mLowercaseTag = mLowercaseTag;
   318   result->mCasedTag = mCasedTag;
   319   result->mOperator = mOperator;
   320   result->mPseudoType = mPseudoType;
   322   NS_IF_CLONE(mIDList);
   323   NS_IF_CLONE(mClassList);
   324   NS_IF_CLONE(mPseudoClassList);
   325   NS_IF_CLONE(mAttrList);
   327   // No need to worry about multiple levels of recursion since an
   328   // mNegations can't have an mNext.
   329   NS_ASSERTION(!mNegations || !mNegations->mNext,
   330                "mNegations can't have non-null mNext");
   331   if (aDeepNegations) {
   332     NS_CSS_CLONE_LIST_MEMBER(nsCSSSelector, this, mNegations, result,
   333                              (true, false));
   334   }
   336   if (aDeepNext) {
   337     NS_CSS_CLONE_LIST_MEMBER(nsCSSSelector, this, mNext, result,
   338                              (false, true));
   339   }
   341   return result;
   342 }
   344 nsCSSSelector::~nsCSSSelector(void)  
   345 {
   346   MOZ_COUNT_DTOR(nsCSSSelector);
   347   Reset();
   348   // No need to worry about multiple levels of recursion since an
   349   // mNegations can't have an mNext.
   350   NS_CSS_DELETE_LIST_MEMBER(nsCSSSelector, this, mNext);
   351 }
   353 void nsCSSSelector::Reset(void)
   354 {
   355   mNameSpace = kNameSpaceID_Unknown;
   356   mLowercaseTag = nullptr;
   357   mCasedTag = nullptr;
   358   NS_IF_DELETE(mIDList);
   359   NS_IF_DELETE(mClassList);
   360   NS_IF_DELETE(mPseudoClassList);
   361   NS_IF_DELETE(mAttrList);
   362   // No need to worry about multiple levels of recursion since an
   363   // mNegations can't have an mNext.
   364   NS_ASSERTION(!mNegations || !mNegations->mNext,
   365                "mNegations can't have non-null mNext");
   366   NS_CSS_DELETE_LIST_MEMBER(nsCSSSelector, this, mNegations);
   367   mOperator = char16_t(0);
   368 }
   370 void nsCSSSelector::SetNameSpace(int32_t aNameSpace)
   371 {
   372   mNameSpace = aNameSpace;
   373 }
   375 void nsCSSSelector::SetTag(const nsString& aTag)
   376 {
   377   if (aTag.IsEmpty()) {
   378     mLowercaseTag = mCasedTag =  nullptr;
   379     return;
   380   }
   382   mCasedTag = do_GetAtom(aTag);
   384   nsAutoString lowercase;
   385   nsContentUtils::ASCIIToLower(aTag, lowercase);
   386   mLowercaseTag = do_GetAtom(lowercase);
   387 }
   389 void nsCSSSelector::AddID(const nsString& aID)
   390 {
   391   if (!aID.IsEmpty()) {
   392     nsAtomList** list = &mIDList;
   393     while (nullptr != *list) {
   394       list = &((*list)->mNext);
   395     }
   396     *list = new nsAtomList(aID);
   397   }
   398 }
   400 void nsCSSSelector::AddClass(const nsString& aClass)
   401 {
   402   if (!aClass.IsEmpty()) {
   403     nsAtomList** list = &mClassList;
   404     while (nullptr != *list) {
   405       list = &((*list)->mNext);
   406     }
   407     *list = new nsAtomList(aClass);
   408   }
   409 }
   411 void nsCSSSelector::AddPseudoClass(nsCSSPseudoClasses::Type aType)
   412 {
   413   AddPseudoClassInternal(new nsPseudoClassList(aType));
   414 }
   416 void nsCSSSelector::AddPseudoClass(nsCSSPseudoClasses::Type aType,
   417                                    const char16_t* aString)
   418 {
   419   AddPseudoClassInternal(new nsPseudoClassList(aType, aString));
   420 }
   422 void nsCSSSelector::AddPseudoClass(nsCSSPseudoClasses::Type aType,
   423                                    const int32_t* aIntPair)
   424 {
   425   AddPseudoClassInternal(new nsPseudoClassList(aType, aIntPair));
   426 }
   428 void nsCSSSelector::AddPseudoClass(nsCSSPseudoClasses::Type aType,
   429                                    nsCSSSelectorList* aSelectorList)
   430 {
   431   // Take ownership of nsCSSSelectorList instead of copying.
   432   AddPseudoClassInternal(new nsPseudoClassList(aType, aSelectorList));
   433 }
   435 void nsCSSSelector::AddPseudoClassInternal(nsPseudoClassList *aPseudoClass)
   436 {
   437   nsPseudoClassList** list = &mPseudoClassList;
   438   while (nullptr != *list) {
   439     list = &((*list)->mNext);
   440   }
   441   *list = aPseudoClass;
   442 }
   444 void nsCSSSelector::AddAttribute(int32_t aNameSpace, const nsString& aAttr)
   445 {
   446   if (!aAttr.IsEmpty()) {
   447     nsAttrSelector** list = &mAttrList;
   448     while (nullptr != *list) {
   449       list = &((*list)->mNext);
   450     }
   451     *list = new nsAttrSelector(aNameSpace, aAttr);
   452   }
   453 }
   455 void nsCSSSelector::AddAttribute(int32_t aNameSpace, const nsString& aAttr, uint8_t aFunc, 
   456                                  const nsString& aValue, bool aCaseSensitive)
   457 {
   458   if (!aAttr.IsEmpty()) {
   459     nsAttrSelector** list = &mAttrList;
   460     while (nullptr != *list) {
   461       list = &((*list)->mNext);
   462     }
   463     *list = new nsAttrSelector(aNameSpace, aAttr, aFunc, aValue, aCaseSensitive);
   464   }
   465 }
   467 void nsCSSSelector::SetOperator(char16_t aOperator)
   468 {
   469   mOperator = aOperator;
   470 }
   472 int32_t nsCSSSelector::CalcWeightWithoutNegations() const
   473 {
   474   int32_t weight = 0;
   476 #ifdef MOZ_XUL
   477   MOZ_ASSERT(!(IsPseudoElement() &&
   478                PseudoType() != nsCSSPseudoElements::ePseudo_XULTree &&
   479                mClassList),
   480              "If non-XUL-tree pseudo-elements can have class selectors "
   481              "after them, specificity calculation must be updated");
   482 #else
   483   MOZ_ASSERT(!(IsPseudoElement() && mClassList),
   484              "If pseudo-elements can have class selectors "
   485              "after them, specificity calculation must be updated");
   486 #endif
   487   MOZ_ASSERT(!(IsPseudoElement() && (mIDList || mAttrList)),
   488              "If pseudo-elements can have id or attribute selectors "
   489              "after them, specificity calculation must be updated");
   491   if (nullptr != mCasedTag) {
   492     weight += 0x000001;
   493   }
   494   nsAtomList* list = mIDList;
   495   while (nullptr != list) {
   496     weight += 0x010000;
   497     list = list->mNext;
   498   }
   499   list = mClassList;
   500 #ifdef MOZ_XUL
   501   // XUL tree pseudo-elements abuse mClassList to store some private
   502   // data; ignore that.
   503   if (PseudoType() == nsCSSPseudoElements::ePseudo_XULTree) {
   504     list = nullptr;
   505   }
   506 #endif
   507   while (nullptr != list) {
   508     weight += 0x000100;
   509     list = list->mNext;
   510   }
   511   // FIXME (bug 561154):  This is incorrect for :-moz-any(), which isn't
   512   // really a pseudo-class.  In order to handle :-moz-any() correctly,
   513   // we need to compute specificity after we match, based on which
   514   // option we matched with (and thus also need to try the
   515   // highest-specificity options first).
   516   nsPseudoClassList *plist = mPseudoClassList;
   517   while (nullptr != plist) {
   518     weight += 0x000100;
   519     plist = plist->mNext;
   520   }
   521   nsAttrSelector* attr = mAttrList;
   522   while (nullptr != attr) {
   523     weight += 0x000100;
   524     attr = attr->mNext;
   525   }
   526   return weight;
   527 }
   529 int32_t nsCSSSelector::CalcWeight() const
   530 {
   531   // Loop over this selector and all its negations.
   532   int32_t weight = 0;
   533   for (const nsCSSSelector *n = this; n; n = n->mNegations) {
   534     weight += n->CalcWeightWithoutNegations();
   535   }
   536   return weight;
   537 }
   539 //
   540 // Builds the textual representation of a selector. Called by DOM 2 CSS 
   541 // StyleRule:selectorText
   542 //
   543 void
   544 nsCSSSelector::ToString(nsAString& aString, nsCSSStyleSheet* aSheet,
   545                         bool aAppend) const
   546 {
   547   if (!aAppend)
   548    aString.Truncate();
   550   // selectors are linked from right-to-left, so the next selector in
   551   // the linked list actually precedes this one in the resulting string
   552   nsAutoTArray<const nsCSSSelector*, 8> stack;
   553   for (const nsCSSSelector *s = this; s; s = s->mNext) {
   554     stack.AppendElement(s);
   555   }
   557   while (!stack.IsEmpty()) {
   558     uint32_t index = stack.Length() - 1;
   559     const nsCSSSelector *s = stack.ElementAt(index);
   560     stack.RemoveElementAt(index);
   562     s->AppendToStringWithoutCombinators(aString, aSheet);
   564     // Append the combinator, if needed.
   565     if (!stack.IsEmpty()) {
   566       const nsCSSSelector *next = stack.ElementAt(index - 1);
   567       char16_t oper = s->mOperator;
   568       if (next->IsPseudoElement()) {
   569         NS_ASSERTION(oper == char16_t(':'),
   570                      "improperly chained pseudo element");
   571       } else {
   572         NS_ASSERTION(oper != char16_t(0),
   573                      "compound selector without combinator");
   575         aString.Append(char16_t(' '));
   576         if (oper != char16_t(' ')) {
   577           aString.Append(oper);
   578           aString.Append(char16_t(' '));
   579         }
   580       }
   581     }
   582   }
   583 }
   585 void
   586 nsCSSSelector::AppendToStringWithoutCombinators
   587                    (nsAString& aString, nsCSSStyleSheet* aSheet) const
   588 {
   589   AppendToStringWithoutCombinatorsOrNegations(aString, aSheet, false);
   591   for (const nsCSSSelector* negation = mNegations; negation;
   592        negation = negation->mNegations) {
   593     aString.AppendLiteral(":not(");
   594     negation->AppendToStringWithoutCombinatorsOrNegations(aString, aSheet,
   595                                                           true);
   596     aString.Append(char16_t(')'));
   597   }
   598 }
   600 void
   601 nsCSSSelector::AppendToStringWithoutCombinatorsOrNegations
   602                    (nsAString& aString, nsCSSStyleSheet* aSheet,
   603                    bool aIsNegated) const
   604 {
   605   nsAutoString temp;
   606   bool isPseudoElement = IsPseudoElement();
   608   // For non-pseudo-element selectors or for lone pseudo-elements, deal with
   609   // namespace prefixes.
   610   bool wroteNamespace = false;
   611   if (!isPseudoElement || !mNext) {
   612     // append the namespace prefix if needed
   613     nsXMLNameSpaceMap *sheetNS = aSheet ? aSheet->GetNameSpaceMap() : nullptr;
   615     // sheetNS is non-null if and only if we had an @namespace rule.  If it's
   616     // null, that means that the only namespaces we could have are the
   617     // wildcard namespace (which can be implicit in this case) and the "none"
   618     // namespace, which then needs to be explicitly specified.
   619     if (!sheetNS) {
   620       NS_ASSERTION(mNameSpace == kNameSpaceID_Unknown ||
   621                    mNameSpace == kNameSpaceID_None,
   622                    "How did we get this namespace?");
   623       if (mNameSpace == kNameSpaceID_None) {
   624         aString.Append(char16_t('|'));
   625         wroteNamespace = true;
   626       }
   627     } else if (sheetNS->FindNameSpaceID(nullptr) == mNameSpace) {
   628       // We have the default namespace (possibly including the wildcard
   629       // namespace).  Do nothing.
   630       NS_ASSERTION(mNameSpace == kNameSpaceID_Unknown ||
   631                    CanBeNamespaced(aIsNegated),
   632                    "How did we end up with this namespace?");
   633     } else if (mNameSpace == kNameSpaceID_None) {
   634       NS_ASSERTION(CanBeNamespaced(aIsNegated),
   635                    "How did we end up with this namespace?");
   636       aString.Append(char16_t('|'));
   637       wroteNamespace = true;
   638     } else if (mNameSpace != kNameSpaceID_Unknown) {
   639       NS_ASSERTION(CanBeNamespaced(aIsNegated),
   640                    "How did we end up with this namespace?");
   641       nsIAtom *prefixAtom = sheetNS->FindPrefix(mNameSpace);
   642       NS_ASSERTION(prefixAtom, "how'd we get a non-default namespace "
   643                    "without a prefix?");
   644       nsStyleUtil::AppendEscapedCSSIdent(nsDependentAtomString(prefixAtom),
   645                                          aString);
   646       aString.Append(char16_t('|'));
   647       wroteNamespace = true;
   648     } else {
   649       // A selector for an element in any namespace, while the default
   650       // namespace is something else.  :not() is special in that the default
   651       // namespace is not implied for non-type selectors, so if this is a
   652       // negated non-type selector we don't need to output an explicit wildcard
   653       // namespace here, since those default to a wildcard namespace.
   654       if (CanBeNamespaced(aIsNegated)) {
   655         aString.AppendLiteral("*|");
   656         wroteNamespace = true;
   657       }
   658     }
   659   }
   661   if (!mLowercaseTag) {
   662     // Universal selector:  avoid writing the universal selector when we
   663     // can avoid it, especially since we're required to avoid it for the
   664     // inside of :not()
   665     if (wroteNamespace ||
   666         (!mIDList && !mClassList && !mPseudoClassList && !mAttrList &&
   667          (aIsNegated || !mNegations))) {
   668       aString.Append(char16_t('*'));
   669     }
   670   } else {
   671     // Append the tag name
   672     nsAutoString tag;
   673     (isPseudoElement ? mLowercaseTag : mCasedTag)->ToString(tag);
   674     if (isPseudoElement) {
   675       if (!mNext) {
   676         // Lone pseudo-element selector -- toss in a wildcard type selector
   677         // XXXldb Why?
   678         aString.Append(char16_t('*'));
   679       }
   680       if (!nsCSSPseudoElements::IsCSS2PseudoElement(mLowercaseTag)) {
   681         aString.Append(char16_t(':'));
   682       }
   683       // This should not be escaped since (a) the pseudo-element string
   684       // has a ":" that can't be escaped and (b) all pseudo-elements at
   685       // this point are known, and therefore we know they don't need
   686       // escaping.
   687       aString.Append(tag);
   688     } else {
   689       nsStyleUtil::AppendEscapedCSSIdent(tag, aString);
   690     }
   691   }
   693   // Append the id, if there is one
   694   if (mIDList) {
   695     nsAtomList* list = mIDList;
   696     while (list != nullptr) {
   697       list->mAtom->ToString(temp);
   698       aString.Append(char16_t('#'));
   699       nsStyleUtil::AppendEscapedCSSIdent(temp, aString);
   700       list = list->mNext;
   701     }
   702   }
   704   // Append each class in the linked list
   705   if (mClassList) {
   706     if (isPseudoElement) {
   707 #ifdef MOZ_XUL
   708       NS_ABORT_IF_FALSE(nsCSSAnonBoxes::IsTreePseudoElement(mLowercaseTag),
   709                         "must be tree pseudo-element");
   711       aString.Append(char16_t('('));
   712       for (nsAtomList* list = mClassList; list; list = list->mNext) {
   713         nsStyleUtil::AppendEscapedCSSIdent(nsDependentAtomString(list->mAtom), aString);
   714         aString.Append(char16_t(','));
   715       }
   716       // replace the final comma with a close-paren
   717       aString.Replace(aString.Length() - 1, 1, char16_t(')'));
   718 #else
   719       NS_ERROR("Can't happen");
   720 #endif
   721     } else {
   722       nsAtomList* list = mClassList;
   723       while (list != nullptr) {
   724         list->mAtom->ToString(temp);
   725         aString.Append(char16_t('.'));
   726         nsStyleUtil::AppendEscapedCSSIdent(temp, aString);
   727         list = list->mNext;
   728       }
   729     }
   730   }
   732   // Append each attribute selector in the linked list
   733   if (mAttrList) {
   734     nsAttrSelector* list = mAttrList;
   735     while (list != nullptr) {
   736       aString.Append(char16_t('['));
   737       // Append the namespace prefix
   738       if (list->mNameSpace == kNameSpaceID_Unknown) {
   739         aString.Append(char16_t('*'));
   740         aString.Append(char16_t('|'));
   741       } else if (list->mNameSpace != kNameSpaceID_None) {
   742         if (aSheet) {
   743           nsXMLNameSpaceMap *sheetNS = aSheet->GetNameSpaceMap();
   744           nsIAtom *prefixAtom = sheetNS->FindPrefix(list->mNameSpace);
   745           // Default namespaces don't apply to attribute selectors, so
   746           // we must have a useful prefix.
   747           NS_ASSERTION(prefixAtom,
   748                        "How did we end up with a namespace if the prefix "
   749                        "is unknown?");
   750           nsAutoString prefix;
   751           prefixAtom->ToString(prefix);
   752           nsStyleUtil::AppendEscapedCSSIdent(prefix, aString);
   753           aString.Append(char16_t('|'));
   754         }
   755       }
   756       // Append the attribute name
   757       list->mCasedAttr->ToString(temp);
   758       nsStyleUtil::AppendEscapedCSSIdent(temp, aString);
   760       if (list->mFunction != NS_ATTR_FUNC_SET) {
   761         // Append the function
   762         if (list->mFunction == NS_ATTR_FUNC_INCLUDES)
   763           aString.Append(char16_t('~'));
   764         else if (list->mFunction == NS_ATTR_FUNC_DASHMATCH)
   765           aString.Append(char16_t('|'));
   766         else if (list->mFunction == NS_ATTR_FUNC_BEGINSMATCH)
   767           aString.Append(char16_t('^'));
   768         else if (list->mFunction == NS_ATTR_FUNC_ENDSMATCH)
   769           aString.Append(char16_t('$'));
   770         else if (list->mFunction == NS_ATTR_FUNC_CONTAINSMATCH)
   771           aString.Append(char16_t('*'));
   773         aString.Append(char16_t('='));
   775         // Append the value
   776         nsStyleUtil::AppendEscapedCSSString(list->mValue, aString);
   777       }
   779       aString.Append(char16_t(']'));
   781       list = list->mNext;
   782     }
   783   }
   785   // Append each pseudo-class in the linked list
   786   for (nsPseudoClassList* list = mPseudoClassList; list; list = list->mNext) {
   787     nsCSSPseudoClasses::PseudoTypeToString(list->mType, temp);
   788     // This should not be escaped since (a) the pseudo-class string
   789     // has a ":" that can't be escaped and (b) all pseudo-classes at
   790     // this point are known, and therefore we know they don't need
   791     // escaping.
   792     aString.Append(temp);
   793     if (list->u.mMemory) {
   794       aString.Append(char16_t('('));
   795       if (nsCSSPseudoClasses::HasStringArg(list->mType)) {
   796         nsStyleUtil::AppendEscapedCSSIdent(
   797           nsDependentString(list->u.mString), aString);
   798       } else if (nsCSSPseudoClasses::HasNthPairArg(list->mType)) {
   799         int32_t a = list->u.mNumbers[0],
   800                 b = list->u.mNumbers[1];
   801         temp.Truncate();
   802         if (a != 0) {
   803           if (a == -1) {
   804             temp.Append(char16_t('-'));
   805           } else if (a != 1) {
   806             temp.AppendInt(a);
   807           }
   808           temp.Append(char16_t('n'));
   809         }
   810         if (b != 0 || a == 0) {
   811           if (b >= 0 && a != 0) // check a != 0 for whether we printed above
   812             temp.Append(char16_t('+'));
   813           temp.AppendInt(b);
   814         }
   815         aString.Append(temp);
   816       } else {
   817         NS_ASSERTION(nsCSSPseudoClasses::HasSelectorListArg(list->mType),
   818                      "unexpected pseudo-class");
   819         nsString tmp;
   820         list->u.mSelectors->ToString(tmp, aSheet);
   821         aString.Append(tmp);
   822       }
   823       aString.Append(char16_t(')'));
   824     }
   825   }
   826 }
   828 bool
   829 nsCSSSelector::CanBeNamespaced(bool aIsNegated) const
   830 {
   831   return !aIsNegated ||
   832          (!mIDList && !mClassList && !mPseudoClassList && !mAttrList);
   833 }
   835 size_t
   836 nsCSSSelector::SizeOfIncludingThis(mozilla::MallocSizeOf aMallocSizeOf) const
   837 {
   838   size_t n = 0;
   839   const nsCSSSelector* s = this;
   840   while (s) {
   841     n += aMallocSizeOf(s);
   843     #define MEASURE(x)   n += x ? x->SizeOfIncludingThis(aMallocSizeOf) : 0;
   845     MEASURE(s->mIDList);
   846     MEASURE(s->mClassList);
   847     MEASURE(s->mPseudoClassList);
   848     MEASURE(s->mNegations);
   850     // Measurement of the following members may be added later if DMD finds it is
   851     // worthwhile:
   852     // - s->mAttrList
   853     //
   854     // The following members aren't measured:
   855     // - s->mLowercaseTag, because it's an atom and therefore shared
   856     // - s->mCasedTag, because it's an atom and therefore shared
   858     s = s->mNext;
   859   }
   860   return n;
   861 }
   863 // -- nsCSSSelectorList -------------------------------
   865 nsCSSSelectorList::nsCSSSelectorList(void)
   866   : mSelectors(nullptr),
   867     mWeight(0),
   868     mNext(nullptr)
   869 {
   870   MOZ_COUNT_CTOR(nsCSSSelectorList);
   871 }
   873 nsCSSSelectorList::~nsCSSSelectorList()
   874 {
   875   MOZ_COUNT_DTOR(nsCSSSelectorList);
   876   delete mSelectors;
   877   NS_CSS_DELETE_LIST_MEMBER(nsCSSSelectorList, this, mNext);
   878 }
   880 nsCSSSelector*
   881 nsCSSSelectorList::AddSelector(char16_t aOperator)
   882 {
   883   nsCSSSelector* newSel = new nsCSSSelector();
   885   if (mSelectors) {
   886     NS_ASSERTION(aOperator != char16_t(0), "chaining without combinator");
   887     mSelectors->SetOperator(aOperator);
   888   } else {
   889     NS_ASSERTION(aOperator == char16_t(0), "combinator without chaining");
   890   }
   892   newSel->mNext = mSelectors;
   893   mSelectors = newSel;
   894   return newSel;
   895 }
   897 void
   898 nsCSSSelectorList::ToString(nsAString& aResult, nsCSSStyleSheet* aSheet)
   899 {
   900   aResult.Truncate();
   901   nsCSSSelectorList *p = this;
   902   for (;;) {
   903     p->mSelectors->ToString(aResult, aSheet, true);
   904     p = p->mNext;
   905     if (!p)
   906       break;
   907     aResult.AppendLiteral(", ");
   908   }
   909 }
   911 nsCSSSelectorList*
   912 nsCSSSelectorList::Clone(bool aDeep) const
   913 {
   914   nsCSSSelectorList *result = new nsCSSSelectorList();
   915   result->mWeight = mWeight;
   916   NS_IF_CLONE(mSelectors);
   918   if (aDeep) {
   919     NS_CSS_CLONE_LIST_MEMBER(nsCSSSelectorList, this, mNext, result,
   920                              (false));
   921   }
   922   return result;
   923 }
   925 size_t
   926 nsCSSSelectorList::SizeOfIncludingThis(mozilla::MallocSizeOf aMallocSizeOf) const
   927 {
   928   size_t n = 0;
   929   const nsCSSSelectorList* s = this;
   930   while (s) {
   931     n += aMallocSizeOf(s);
   932     n += s->mSelectors ? s->mSelectors->SizeOfIncludingThis(aMallocSizeOf) : 0;
   933     s = s->mNext;
   934   }
   935   return n;
   936 }
   938 // -- ImportantRule ----------------------------------
   940 namespace mozilla {
   941 namespace css {
   943 ImportantRule::ImportantRule(Declaration* aDeclaration)
   944   : mDeclaration(aDeclaration)
   945 {
   946 }
   948 ImportantRule::~ImportantRule()
   949 {
   950 }
   952 NS_IMPL_ISUPPORTS(ImportantRule, nsIStyleRule)
   954 /* virtual */ void
   955 ImportantRule::MapRuleInfoInto(nsRuleData* aRuleData)
   956 {
   957   mDeclaration->MapImportantRuleInfoInto(aRuleData);
   958 }
   960 #ifdef DEBUG
   961 /* virtual */ void
   962 ImportantRule::List(FILE* out, int32_t aIndent) const
   963 {
   964   // Indent
   965   for (int32_t index = aIndent; --index >= 0; ) fputs("  ", out);
   967   fprintf(out, "! Important declaration=%p\n",
   968           static_cast<void*>(mDeclaration));
   969 }
   970 #endif
   972 } // namespace css
   973 } // namespace mozilla
   975 // --------------------------------------------------------
   977 namespace mozilla {
   978 namespace css {
   979 class DOMCSSStyleRule;
   980 }
   981 }
   983 class DOMCSSDeclarationImpl : public nsDOMCSSDeclaration
   984 {
   985 public:
   986   DOMCSSDeclarationImpl(css::StyleRule *aRule);
   987   virtual ~DOMCSSDeclarationImpl(void);
   989   NS_IMETHOD GetParentRule(nsIDOMCSSRule **aParent) MOZ_OVERRIDE;
   990   void DropReference(void);
   991   virtual css::Declaration* GetCSSDeclaration(bool aAllocate) MOZ_OVERRIDE;
   992   virtual nsresult SetCSSDeclaration(css::Declaration* aDecl) MOZ_OVERRIDE;
   993   virtual void GetCSSParsingEnvironment(CSSParsingEnvironment& aCSSParseEnv) MOZ_OVERRIDE;
   994   virtual nsIDocument* DocToUpdate() MOZ_OVERRIDE;
   996   // Override |AddRef| and |Release| for being a member of
   997   // |DOMCSSStyleRule|.  Also, we need to forward QI for cycle
   998   // collection things to DOMCSSStyleRule.
   999   NS_DECL_ISUPPORTS_INHERITED
  1001   virtual nsINode *GetParentObject() MOZ_OVERRIDE
  1003     return mRule ? mRule->GetDocument() : nullptr;
  1006   friend class css::DOMCSSStyleRule;
  1008 protected:
  1009   // This reference is not reference-counted. The rule object tells us
  1010   // when it's about to go away.
  1011   css::StyleRule *mRule;
  1013   inline css::DOMCSSStyleRule* DomRule();
  1015 private:
  1016   // NOT TO BE IMPLEMENTED
  1017   // This object cannot be allocated on its own.  It must be a member of
  1018   // DOMCSSStyleRule.
  1019   void* operator new(size_t size) CPP_THROW_NEW;
  1020 };
  1022 namespace mozilla {
  1023 namespace css {
  1025 class DOMCSSStyleRule : public nsICSSStyleRuleDOMWrapper
  1027 public:
  1028   DOMCSSStyleRule(StyleRule *aRule);
  1029   virtual ~DOMCSSStyleRule();
  1031   NS_DECL_CYCLE_COLLECTING_ISUPPORTS
  1032   NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS(DOMCSSStyleRule)
  1033   NS_DECL_NSIDOMCSSRULE
  1034   NS_DECL_NSIDOMCSSSTYLERULE
  1036   // nsICSSStyleRuleDOMWrapper
  1037   NS_IMETHOD GetCSSStyleRule(StyleRule **aResult);
  1039   DOMCSSDeclarationImpl* DOMDeclaration() { return &mDOMDeclaration; }
  1041   friend class ::DOMCSSDeclarationImpl;
  1043 protected:
  1044   DOMCSSDeclarationImpl mDOMDeclaration;
  1046   StyleRule* Rule() {
  1047     return mDOMDeclaration.mRule;
  1049 };
  1051 } // namespace css
  1052 } // namespace mozilla
  1054 DOMCSSDeclarationImpl::DOMCSSDeclarationImpl(css::StyleRule *aRule)
  1055   : mRule(aRule)
  1057   MOZ_COUNT_CTOR(DOMCSSDeclarationImpl);
  1060 DOMCSSDeclarationImpl::~DOMCSSDeclarationImpl(void)
  1062   NS_ASSERTION(!mRule, "DropReference not called.");
  1064   MOZ_COUNT_DTOR(DOMCSSDeclarationImpl);
  1067 inline css::DOMCSSStyleRule* DOMCSSDeclarationImpl::DomRule()
  1069   return reinterpret_cast<css::DOMCSSStyleRule*>
  1070                          (reinterpret_cast<char*>(this) -
  1071            offsetof(css::DOMCSSStyleRule, mDOMDeclaration));
  1074 NS_IMPL_ADDREF_USING_AGGREGATOR(DOMCSSDeclarationImpl, DomRule())
  1075 NS_IMPL_RELEASE_USING_AGGREGATOR(DOMCSSDeclarationImpl, DomRule())
  1077 NS_INTERFACE_MAP_BEGIN(DOMCSSDeclarationImpl)
  1078   NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY
  1079   // We forward the cycle collection interfaces to DomRule(), which is
  1080   // never null (in fact, we're part of that object!)
  1081   if (aIID.Equals(NS_GET_IID(nsCycleCollectionISupports)) ||
  1082       aIID.Equals(NS_GET_IID(nsXPCOMCycleCollectionParticipant))) {
  1083     return DomRule()->QueryInterface(aIID, aInstancePtr);
  1085   else
  1086 NS_IMPL_QUERY_TAIL_INHERITING(nsDOMCSSDeclaration)
  1088 void
  1089 DOMCSSDeclarationImpl::DropReference(void)
  1091   mRule = nullptr;
  1094 css::Declaration*
  1095 DOMCSSDeclarationImpl::GetCSSDeclaration(bool aAllocate)
  1097   if (mRule) {
  1098     return mRule->GetDeclaration();
  1099   } else {
  1100     return nullptr;
  1104 void
  1105 DOMCSSDeclarationImpl::GetCSSParsingEnvironment(CSSParsingEnvironment& aCSSParseEnv)
  1107   GetCSSParsingEnvironmentForRule(mRule, aCSSParseEnv);
  1110 NS_IMETHODIMP
  1111 DOMCSSDeclarationImpl::GetParentRule(nsIDOMCSSRule **aParent)
  1113   NS_ENSURE_ARG_POINTER(aParent);
  1115   if (!mRule) {
  1116     *aParent = nullptr;
  1117     return NS_OK;
  1120   NS_IF_ADDREF(*aParent = mRule->GetDOMRule());
  1121   return NS_OK;
  1124 nsresult
  1125 DOMCSSDeclarationImpl::SetCSSDeclaration(css::Declaration* aDecl)
  1127   NS_PRECONDITION(mRule,
  1128          "can only be called when |GetCSSDeclaration| returned a declaration");
  1130   nsCOMPtr<nsIDocument> owningDoc;
  1131   nsCOMPtr<nsIStyleSheet> sheet = mRule->GetStyleSheet();
  1132   if (sheet) {
  1133     owningDoc = sheet->GetOwningDocument();
  1136   mozAutoDocUpdate updateBatch(owningDoc, UPDATE_STYLE, true);
  1138   nsRefPtr<css::StyleRule> oldRule = mRule;
  1139   mRule = oldRule->DeclarationChanged(aDecl, true).take();
  1140   if (!mRule)
  1141     return NS_ERROR_OUT_OF_MEMORY;
  1142   nsrefcnt cnt = mRule->Release();
  1143   if (cnt == 0) {
  1144     NS_NOTREACHED("container didn't take ownership");
  1145     mRule = nullptr;
  1146     return NS_ERROR_UNEXPECTED;
  1149   if (owningDoc) {
  1150     owningDoc->StyleRuleChanged(sheet, oldRule, mRule);
  1152   return NS_OK;
  1155 nsIDocument*
  1156 DOMCSSDeclarationImpl::DocToUpdate()
  1158   return nullptr;
  1161 // needs to be outside the namespace
  1162 DOMCI_DATA(CSSStyleRule, css::DOMCSSStyleRule)
  1164 namespace mozilla {
  1165 namespace css {
  1167 DOMCSSStyleRule::DOMCSSStyleRule(StyleRule* aRule)
  1168   : mDOMDeclaration(aRule)
  1172 DOMCSSStyleRule::~DOMCSSStyleRule()
  1176 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(DOMCSSStyleRule)
  1177   NS_INTERFACE_MAP_ENTRY(nsICSSStyleRuleDOMWrapper)
  1178   NS_INTERFACE_MAP_ENTRY(nsIDOMCSSStyleRule)
  1179   NS_INTERFACE_MAP_ENTRY(nsIDOMCSSRule)
  1180   NS_INTERFACE_MAP_ENTRY(nsISupports)
  1181   NS_DOM_INTERFACE_MAP_ENTRY_CLASSINFO(CSSStyleRule)
  1182 NS_INTERFACE_MAP_END
  1184 NS_IMPL_CYCLE_COLLECTING_ADDREF(DOMCSSStyleRule)
  1185 NS_IMPL_CYCLE_COLLECTING_RELEASE(DOMCSSStyleRule)
  1187 NS_IMPL_CYCLE_COLLECTION_CLASS(DOMCSSStyleRule)
  1189 NS_IMPL_CYCLE_COLLECTION_TRACE_BEGIN(DOMCSSStyleRule)
  1190   // Trace the wrapper for our declaration.  This just expands out
  1191   // NS_IMPL_CYCLE_COLLECTION_TRACE_PRESERVED_WRAPPER which we can't use
  1192   // directly because the wrapper is on the declaration, not on us.
  1193   tmp->DOMDeclaration()->TraceWrapper(aCallbacks, aClosure);
  1194 NS_IMPL_CYCLE_COLLECTION_TRACE_END
  1196 NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(DOMCSSStyleRule)
  1197   // Unlink the wrapper for our declaraton.  This just expands out
  1198   // NS_IMPL_CYCLE_COLLECTION_UNLINK_PRESERVED_WRAPPER which we can't use
  1199   // directly because the wrapper is on the declaration, not on us.
  1200   tmp->DOMDeclaration()->ReleaseWrapper(static_cast<nsISupports*>(p));
  1201 NS_IMPL_CYCLE_COLLECTION_UNLINK_END
  1203 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(DOMCSSStyleRule)
  1204   // Just NS_IMPL_CYCLE_COLLECTION_TRAVERSE_SCRIPT_OBJECTS here: that will call
  1205   // into our Trace hook, where we do the right thing with declarations
  1206   // already.
  1207   NS_IMPL_CYCLE_COLLECTION_TRAVERSE_SCRIPT_OBJECTS
  1208 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
  1210 NS_IMETHODIMP
  1211 DOMCSSStyleRule::GetType(uint16_t* aType)
  1213   *aType = nsIDOMCSSRule::STYLE_RULE;
  1215   return NS_OK;
  1218 NS_IMETHODIMP
  1219 DOMCSSStyleRule::GetCssText(nsAString& aCssText)
  1221   if (!Rule()) {
  1222     aCssText.Truncate();
  1223   } else {
  1224     Rule()->GetCssText(aCssText);
  1226   return NS_OK;
  1229 NS_IMETHODIMP
  1230 DOMCSSStyleRule::SetCssText(const nsAString& aCssText)
  1232   if (Rule()) {
  1233     Rule()->SetCssText(aCssText);
  1235   return NS_OK;
  1238 NS_IMETHODIMP
  1239 DOMCSSStyleRule::GetParentStyleSheet(nsIDOMCSSStyleSheet** aSheet)
  1241   if (!Rule()) {
  1242     *aSheet = nullptr;
  1243     return NS_OK;
  1245   return Rule()->GetParentStyleSheet(aSheet);
  1248 NS_IMETHODIMP
  1249 DOMCSSStyleRule::GetParentRule(nsIDOMCSSRule** aParentRule)
  1251   if (!Rule()) {
  1252     *aParentRule = nullptr;
  1253     return NS_OK;
  1255   return Rule()->GetParentRule(aParentRule);
  1258 NS_IMETHODIMP
  1259 DOMCSSStyleRule::GetSelectorText(nsAString& aSelectorText)
  1261   if (!Rule()) {
  1262     aSelectorText.Truncate();
  1263   } else {
  1264     Rule()->GetSelectorText(aSelectorText);
  1266   return NS_OK;
  1269 NS_IMETHODIMP
  1270 DOMCSSStyleRule::SetSelectorText(const nsAString& aSelectorText)
  1272   if (Rule()) {
  1273     Rule()->SetSelectorText(aSelectorText);
  1275   return NS_OK;
  1278 NS_IMETHODIMP
  1279 DOMCSSStyleRule::GetStyle(nsIDOMCSSStyleDeclaration** aStyle)
  1281   *aStyle = &mDOMDeclaration;
  1282   NS_ADDREF(*aStyle);
  1283   return NS_OK;
  1286 NS_IMETHODIMP
  1287 DOMCSSStyleRule::GetCSSStyleRule(StyleRule **aResult)
  1289   *aResult = Rule();
  1290   NS_IF_ADDREF(*aResult);
  1291   return NS_OK;
  1294 } // namespace css
  1295 } // namespace mozilla
  1297 // -- StyleRule ------------------------------------
  1299 namespace mozilla {
  1300 namespace css {
  1302 StyleRule::StyleRule(nsCSSSelectorList* aSelector,
  1303                      Declaration* aDeclaration)
  1304   : Rule(),
  1305     mSelector(aSelector),
  1306     mDeclaration(aDeclaration),
  1307     mImportantRule(nullptr),
  1308     mDOMRule(nullptr),
  1309     mLineNumber(0),
  1310     mColumnNumber(0),
  1311     mWasMatched(false)
  1313   NS_PRECONDITION(aDeclaration, "must have a declaration");
  1316 // for |Clone|
  1317 StyleRule::StyleRule(const StyleRule& aCopy)
  1318   : Rule(aCopy),
  1319     mSelector(aCopy.mSelector ? aCopy.mSelector->Clone() : nullptr),
  1320     mDeclaration(new Declaration(*aCopy.mDeclaration)),
  1321     mImportantRule(nullptr),
  1322     mDOMRule(nullptr),
  1323     mLineNumber(aCopy.mLineNumber),
  1324     mColumnNumber(aCopy.mColumnNumber),
  1325     mWasMatched(false)
  1327   // rest is constructed lazily on existing data
  1330 // for |SetCSSDeclaration|
  1331 StyleRule::StyleRule(StyleRule& aCopy,
  1332                      Declaration* aDeclaration)
  1333   : Rule(aCopy),
  1334     mSelector(aCopy.mSelector),
  1335     mDeclaration(aDeclaration),
  1336     mImportantRule(nullptr),
  1337     mDOMRule(aCopy.mDOMRule),
  1338     mLineNumber(aCopy.mLineNumber),
  1339     mColumnNumber(aCopy.mColumnNumber),
  1340     mWasMatched(false)
  1342   // The DOM rule is replacing |aCopy| with |this|, so transfer
  1343   // the reverse pointer as well (and transfer ownership).
  1344   aCopy.mDOMRule = nullptr;
  1346   // Similarly for the selector.
  1347   aCopy.mSelector = nullptr;
  1349   // We are probably replacing the old declaration with |aDeclaration|
  1350   // instead of taking ownership of the old declaration; only null out
  1351   // aCopy.mDeclaration if we are taking ownership.
  1352   if (mDeclaration == aCopy.mDeclaration) {
  1353     // This should only ever happen if the declaration was modifiable.
  1354     mDeclaration->AssertMutable();
  1355     aCopy.mDeclaration = nullptr;
  1359 StyleRule::~StyleRule()
  1361   delete mSelector;
  1362   delete mDeclaration;
  1363   NS_IF_RELEASE(mImportantRule);
  1364   if (mDOMRule) {
  1365     mDOMRule->DOMDeclaration()->DropReference();
  1366     NS_RELEASE(mDOMRule);
  1370 // QueryInterface implementation for StyleRule
  1371 NS_INTERFACE_MAP_BEGIN(StyleRule)
  1372   if (aIID.Equals(NS_GET_IID(mozilla::css::StyleRule))) {
  1373     *aInstancePtr = this;
  1374     NS_ADDREF_THIS();
  1375     return NS_OK;
  1377   else
  1378   NS_INTERFACE_MAP_ENTRY(nsIStyleRule)
  1379   NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIStyleRule)
  1380 NS_INTERFACE_MAP_END
  1382 NS_IMPL_ADDREF(StyleRule)
  1383 NS_IMPL_RELEASE(StyleRule)
  1385 void
  1386 StyleRule::RuleMatched()
  1388   if (!mWasMatched) {
  1389     NS_ABORT_IF_FALSE(!mImportantRule, "should not have important rule yet");
  1391     mWasMatched = true;
  1392     mDeclaration->SetImmutable();
  1393     if (mDeclaration->HasImportantData()) {
  1394       NS_ADDREF(mImportantRule = new ImportantRule(mDeclaration));
  1399 /* virtual */ int32_t
  1400 StyleRule::GetType() const
  1402   return Rule::STYLE_RULE;
  1405 /* virtual */ already_AddRefed<Rule>
  1406 StyleRule::Clone() const
  1408   nsRefPtr<Rule> clone = new StyleRule(*this);
  1409   return clone.forget();
  1412 /* virtual */ nsIDOMCSSRule*
  1413 StyleRule::GetDOMRule()
  1415   if (!mDOMRule) {
  1416     if (!GetStyleSheet()) {
  1417       // Inline style rules aren't supposed to have a DOM rule object, only
  1418       // a declaration.  But if we do have one already, from a style sheet
  1419       // rule that used to be in a document, we still want to return it.
  1420       return nullptr;
  1422     mDOMRule = new DOMCSSStyleRule(this);
  1423     NS_ADDREF(mDOMRule);
  1425   return mDOMRule;
  1428 /* virtual */ nsIDOMCSSRule*
  1429 StyleRule::GetExistingDOMRule()
  1431   return mDOMRule;
  1434 /* virtual */ already_AddRefed<StyleRule>
  1435 StyleRule::DeclarationChanged(Declaration* aDecl,
  1436                               bool aHandleContainer)
  1438   nsRefPtr<StyleRule> clone = new StyleRule(*this, aDecl);
  1440   if (aHandleContainer) {
  1441     nsCSSStyleSheet* sheet = GetStyleSheet();
  1442     if (mParentRule) {
  1443       if (sheet) {
  1444         sheet->ReplaceRuleInGroup(mParentRule, this, clone);
  1445       } else {
  1446         mParentRule->ReplaceStyleRule(this, clone);
  1448     } else if (sheet) {
  1449       sheet->ReplaceStyleRule(this, clone);
  1453   return clone.forget();
  1456 /* virtual */ void
  1457 StyleRule::MapRuleInfoInto(nsRuleData* aRuleData)
  1459   NS_ABORT_IF_FALSE(mWasMatched,
  1460                     "somebody forgot to call css::StyleRule::RuleMatched");
  1461   mDeclaration->MapNormalRuleInfoInto(aRuleData);
  1464 #ifdef DEBUG
  1465 /* virtual */ void
  1466 StyleRule::List(FILE* out, int32_t aIndent) const
  1468   // Indent
  1469   for (int32_t index = aIndent; --index >= 0; ) fputs("  ", out);
  1471   nsAutoString buffer;
  1472   if (mSelector)
  1473     mSelector->ToString(buffer, GetStyleSheet());
  1475   buffer.AppendLiteral(" ");
  1476   fputs(NS_LossyConvertUTF16toASCII(buffer).get(), out);
  1477   if (nullptr != mDeclaration) {
  1478     mDeclaration->List(out);
  1480   else {
  1481     fputs("{ null declaration }", out);
  1483   fputs("\n", out);
  1485 #endif
  1487 void
  1488 StyleRule::GetCssText(nsAString& aCssText)
  1490   if (mSelector) {
  1491     mSelector->ToString(aCssText, GetStyleSheet());
  1492     aCssText.Append(char16_t(' '));
  1494   aCssText.Append(char16_t('{'));
  1495   aCssText.Append(char16_t(' '));
  1496   if (mDeclaration)
  1498     nsAutoString   tempString;
  1499     mDeclaration->ToString( tempString );
  1500     aCssText.Append( tempString );
  1502   aCssText.Append(char16_t(' '));
  1503   aCssText.Append(char16_t('}'));
  1506 void
  1507 StyleRule::SetCssText(const nsAString& aCssText)
  1509   // XXX TBI - need to re-parse rule & declaration
  1512 void
  1513 StyleRule::GetSelectorText(nsAString& aSelectorText)
  1515   if (mSelector)
  1516     mSelector->ToString(aSelectorText, GetStyleSheet());
  1517   else
  1518     aSelectorText.Truncate();
  1521 void
  1522 StyleRule::SetSelectorText(const nsAString& aSelectorText)
  1524   // XXX TBI - get a parser and re-parse the selectors,
  1525   // XXX then need to re-compute the cascade
  1526   // XXX and dirty sheet
  1529 /* virtual */ size_t
  1530 StyleRule::SizeOfIncludingThis(mozilla::MallocSizeOf aMallocSizeOf) const
  1532   size_t n = aMallocSizeOf(this);
  1533   n += mSelector ? mSelector->SizeOfIncludingThis(aMallocSizeOf) : 0;
  1534   n += mDeclaration ? mDeclaration->SizeOfIncludingThis(aMallocSizeOf) : 0;
  1536   // Measurement of the following members may be added later if DMD finds it is
  1537   // worthwhile:
  1538   // - mImportantRule;
  1539   // - mDOMRule;
  1541   return n;
  1545 } // namespace css
  1546 } // namespace mozilla

mercurial