layout/style/nsCSSStyleSheet.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 // vim:cindent:tabstop=2:expandtab:shiftwidth=2:
     3 /* This Source Code Form is subject to the terms of the Mozilla Public
     4  * License, v. 2.0. If a copy of the MPL was not distributed with this
     5  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
     7 /* representation of a CSS style sheet */
     9 #include "nsCSSStyleSheet.h"
    11 #include "nsIAtom.h"
    12 #include "nsCSSRuleProcessor.h"
    13 #include "mozilla/MemoryReporting.h"
    14 #include "mozilla/dom/Element.h"
    15 #include "mozilla/dom/MediaListBinding.h"
    16 #include "mozilla/css/NameSpaceRule.h"
    17 #include "mozilla/css/GroupRule.h"
    18 #include "mozilla/css/ImportRule.h"
    19 #include "nsIMediaList.h"
    20 #include "nsIDocument.h"
    21 #include "nsPresContext.h"
    22 #include "nsGkAtoms.h"
    23 #include "nsString.h"
    24 #include "nsTArray.h"
    25 #include "nsIDOMCSSStyleSheet.h"
    26 #include "nsICSSRuleList.h"
    27 #include "nsIDOMMediaList.h"
    28 #include "nsIDOMNode.h"
    29 #include "nsError.h"
    30 #include "nsCSSParser.h"
    31 #include "mozilla/css/Loader.h"
    32 #include "nsICSSLoaderObserver.h"
    33 #include "nsNameSpaceManager.h"
    34 #include "nsXMLNameSpaceMap.h"
    35 #include "nsCOMPtr.h"
    36 #include "nsContentUtils.h"
    37 #include "nsIScriptSecurityManager.h"
    38 #include "mozAutoDocUpdate.h"
    39 #include "nsRuleNode.h"
    40 #include "nsMediaFeatures.h"
    41 #include "nsDOMClassInfoID.h"
    42 #include "mozilla/Likely.h"
    43 #include "mozilla/dom/CSSStyleSheetBinding.h"
    44 #include "nsComponentManagerUtils.h"
    46 using namespace mozilla;
    47 using namespace mozilla::dom;
    50 // -------------------------------
    51 // Style Rule List for the DOM
    52 //
    53 class CSSRuleListImpl : public nsICSSRuleList
    54 {
    55 public:
    56   CSSRuleListImpl(nsCSSStyleSheet *aStyleSheet);
    58   NS_DECL_ISUPPORTS
    60   virtual nsIDOMCSSRule*
    61   IndexedGetter(uint32_t aIndex, bool& aFound) MOZ_OVERRIDE;
    62   virtual uint32_t
    63   Length() MOZ_OVERRIDE;
    65   void DropReference() { mStyleSheet = nullptr; }
    67 protected:
    68   virtual ~CSSRuleListImpl();
    70   nsCSSStyleSheet*  mStyleSheet;
    71 };
    73 CSSRuleListImpl::CSSRuleListImpl(nsCSSStyleSheet *aStyleSheet)
    74 {
    75   // Not reference counted to avoid circular references.
    76   // The style sheet will tell us when its going away.
    77   mStyleSheet = aStyleSheet;
    78 }
    80 CSSRuleListImpl::~CSSRuleListImpl()
    81 {
    82 }
    84 DOMCI_DATA(CSSRuleList, CSSRuleListImpl)
    86 // QueryInterface implementation for CSSRuleList
    87 NS_INTERFACE_MAP_BEGIN(CSSRuleListImpl)
    88   NS_INTERFACE_MAP_ENTRY(nsICSSRuleList)
    89   NS_INTERFACE_MAP_ENTRY(nsIDOMCSSRuleList)
    90   NS_INTERFACE_MAP_ENTRY(nsISupports)
    91   NS_DOM_INTERFACE_MAP_ENTRY_CLASSINFO(CSSRuleList)
    92 NS_INTERFACE_MAP_END
    95 NS_IMPL_ADDREF(CSSRuleListImpl)
    96 NS_IMPL_RELEASE(CSSRuleListImpl)
    99 uint32_t
   100 CSSRuleListImpl::Length()
   101 {
   102   if (!mStyleSheet) {
   103     return 0;
   104   }
   106   return SafeCast<uint32_t>(mStyleSheet->StyleRuleCount());
   107 }
   109 nsIDOMCSSRule*    
   110 CSSRuleListImpl::IndexedGetter(uint32_t aIndex, bool& aFound)
   111 {
   112   aFound = false;
   114   if (mStyleSheet) {
   115     // ensure rules have correct parent
   116     mStyleSheet->EnsureUniqueInner();
   117     css::Rule* rule = mStyleSheet->GetStyleRuleAt(aIndex);
   118     if (rule) {
   119       aFound = true;
   120       return rule->GetDOMRule();
   121     }
   122   }
   124   // Per spec: "Return Value ... null if ... not a valid index."
   125   return nullptr;
   126 }
   128 template <class Numeric>
   129 int32_t DoCompare(Numeric a, Numeric b)
   130 {
   131   if (a == b)
   132     return 0;
   133   if (a < b)
   134     return -1;
   135   return 1;
   136 }
   138 bool
   139 nsMediaExpression::Matches(nsPresContext *aPresContext,
   140                            const nsCSSValue& aActualValue) const
   141 {
   142   const nsCSSValue& actual = aActualValue;
   143   const nsCSSValue& required = mValue;
   145   // If we don't have the feature, the match fails.
   146   if (actual.GetUnit() == eCSSUnit_Null) {
   147     return false;
   148   }
   150   // If the expression had no value to match, the match succeeds,
   151   // unless the value is an integer 0 or a zero length.
   152   if (required.GetUnit() == eCSSUnit_Null) {
   153     if (actual.GetUnit() == eCSSUnit_Integer)
   154       return actual.GetIntValue() != 0;
   155     if (actual.IsLengthUnit())
   156       return actual.GetFloatValue() != 0;
   157     return true;
   158   }
   160   NS_ASSERTION(mFeature->mRangeType == nsMediaFeature::eMinMaxAllowed ||
   161                mRange == nsMediaExpression::eEqual, "yikes");
   162   int32_t cmp; // -1 (actual < required)
   163                //  0 (actual == required)
   164                //  1 (actual > required)
   165   switch (mFeature->mValueType) {
   166     case nsMediaFeature::eLength:
   167       {
   168         NS_ASSERTION(actual.IsLengthUnit(), "bad actual value");
   169         NS_ASSERTION(required.IsLengthUnit(), "bad required value");
   170         nscoord actualCoord = nsRuleNode::CalcLengthWithInitialFont(
   171                                 aPresContext, actual);
   172         nscoord requiredCoord = nsRuleNode::CalcLengthWithInitialFont(
   173                                   aPresContext, required);
   174         cmp = DoCompare(actualCoord, requiredCoord);
   175       }
   176       break;
   177     case nsMediaFeature::eInteger:
   178     case nsMediaFeature::eBoolInteger:
   179       {
   180         NS_ASSERTION(actual.GetUnit() == eCSSUnit_Integer,
   181                      "bad actual value");
   182         NS_ASSERTION(required.GetUnit() == eCSSUnit_Integer,
   183                      "bad required value");
   184         NS_ASSERTION(mFeature->mValueType != nsMediaFeature::eBoolInteger ||
   185                      actual.GetIntValue() == 0 || actual.GetIntValue() == 1,
   186                      "bad actual bool integer value");
   187         NS_ASSERTION(mFeature->mValueType != nsMediaFeature::eBoolInteger ||
   188                      required.GetIntValue() == 0 || required.GetIntValue() == 1,
   189                      "bad required bool integer value");
   190         cmp = DoCompare(actual.GetIntValue(), required.GetIntValue());
   191       }
   192       break;
   193     case nsMediaFeature::eFloat:
   194       {
   195         NS_ASSERTION(actual.GetUnit() == eCSSUnit_Number,
   196                      "bad actual value");
   197         NS_ASSERTION(required.GetUnit() == eCSSUnit_Number,
   198                      "bad required value");
   199         cmp = DoCompare(actual.GetFloatValue(), required.GetFloatValue());
   200       }
   201       break;
   202     case nsMediaFeature::eIntRatio:
   203       {
   204         NS_ASSERTION(actual.GetUnit() == eCSSUnit_Array &&
   205                      actual.GetArrayValue()->Count() == 2 &&
   206                      actual.GetArrayValue()->Item(0).GetUnit() ==
   207                        eCSSUnit_Integer &&
   208                      actual.GetArrayValue()->Item(1).GetUnit() ==
   209                        eCSSUnit_Integer,
   210                      "bad actual value");
   211         NS_ASSERTION(required.GetUnit() == eCSSUnit_Array &&
   212                      required.GetArrayValue()->Count() == 2 &&
   213                      required.GetArrayValue()->Item(0).GetUnit() ==
   214                        eCSSUnit_Integer &&
   215                      required.GetArrayValue()->Item(1).GetUnit() ==
   216                        eCSSUnit_Integer,
   217                      "bad required value");
   218         // Convert to int64_t so we can multiply without worry.  Note
   219         // that while the spec requires that both halves of |required|
   220         // be positive, the numerator or denominator of |actual| might
   221         // be zero (e.g., when testing 'aspect-ratio' on a 0-width or
   222         // 0-height iframe).
   223         int64_t actualNum = actual.GetArrayValue()->Item(0).GetIntValue(),
   224                 actualDen = actual.GetArrayValue()->Item(1).GetIntValue(),
   225                 requiredNum = required.GetArrayValue()->Item(0).GetIntValue(),
   226                 requiredDen = required.GetArrayValue()->Item(1).GetIntValue();
   227         cmp = DoCompare(actualNum * requiredDen, requiredNum * actualDen);
   228       }
   229       break;
   230     case nsMediaFeature::eResolution:
   231       {
   232         NS_ASSERTION(actual.GetUnit() == eCSSUnit_Inch ||
   233                      actual.GetUnit() == eCSSUnit_Pixel ||
   234                      actual.GetUnit() == eCSSUnit_Centimeter,
   235                      "bad actual value");
   236         NS_ASSERTION(required.GetUnit() == eCSSUnit_Inch ||
   237                      required.GetUnit() == eCSSUnit_Pixel ||
   238                      required.GetUnit() == eCSSUnit_Centimeter,
   239                      "bad required value");
   240         float actualDPI = actual.GetFloatValue();
   241         if (actual.GetUnit() == eCSSUnit_Centimeter) {
   242           actualDPI = actualDPI * 2.54f;
   243         } else if (actual.GetUnit() == eCSSUnit_Pixel) {
   244           actualDPI = actualDPI * 96.0f;
   245         }
   246         float requiredDPI = required.GetFloatValue();
   247         if (required.GetUnit() == eCSSUnit_Centimeter) {
   248           requiredDPI = requiredDPI * 2.54f;
   249         } else if (required.GetUnit() == eCSSUnit_Pixel) {
   250           requiredDPI = requiredDPI * 96.0f;
   251         }
   252         cmp = DoCompare(actualDPI, requiredDPI);
   253       }
   254       break;
   255     case nsMediaFeature::eEnumerated:
   256       {
   257         NS_ASSERTION(actual.GetUnit() == eCSSUnit_Enumerated,
   258                      "bad actual value");
   259         NS_ASSERTION(required.GetUnit() == eCSSUnit_Enumerated,
   260                      "bad required value");
   261         NS_ASSERTION(mFeature->mRangeType == nsMediaFeature::eMinMaxNotAllowed,
   262                      "bad range"); // we asserted above about mRange
   263         // We don't really need DoCompare, but it doesn't hurt (and
   264         // maybe the compiler will condense this case with eInteger).
   265         cmp = DoCompare(actual.GetIntValue(), required.GetIntValue());
   266       }
   267       break;
   268     case nsMediaFeature::eIdent:
   269       {
   270         NS_ASSERTION(actual.GetUnit() == eCSSUnit_Ident,
   271                      "bad actual value");
   272         NS_ASSERTION(required.GetUnit() == eCSSUnit_Ident,
   273                      "bad required value");
   274         NS_ASSERTION(mFeature->mRangeType == nsMediaFeature::eMinMaxNotAllowed,
   275                      "bad range"); 
   276         cmp = !(actual == required); // string comparison
   277       }
   278       break;
   279   }
   280   switch (mRange) {
   281     case nsMediaExpression::eMin:
   282       return cmp != -1;
   283     case nsMediaExpression::eMax:
   284       return cmp != 1;
   285     case nsMediaExpression::eEqual:
   286       return cmp == 0;
   287   }
   288   NS_NOTREACHED("unexpected mRange");
   289   return false;
   290 }
   292 void
   293 nsMediaQueryResultCacheKey::AddExpression(const nsMediaExpression* aExpression,
   294                                           bool aExpressionMatches)
   295 {
   296   const nsMediaFeature *feature = aExpression->mFeature;
   297   FeatureEntry *entry = nullptr;
   298   for (uint32_t i = 0; i < mFeatureCache.Length(); ++i) {
   299     if (mFeatureCache[i].mFeature == feature) {
   300       entry = &mFeatureCache[i];
   301       break;
   302     }
   303   }
   304   if (!entry) {
   305     entry = mFeatureCache.AppendElement();
   306     if (!entry) {
   307       return; /* out of memory */
   308     }
   309     entry->mFeature = feature;
   310   }
   312   ExpressionEntry eentry = { *aExpression, aExpressionMatches };
   313   entry->mExpressions.AppendElement(eentry);
   314 }
   316 bool
   317 nsMediaQueryResultCacheKey::Matches(nsPresContext* aPresContext) const
   318 {
   319   if (aPresContext->Medium() != mMedium) {
   320     return false;
   321   }
   323   for (uint32_t i = 0; i < mFeatureCache.Length(); ++i) {
   324     const FeatureEntry *entry = &mFeatureCache[i];
   325     nsCSSValue actual;
   326     nsresult rv =
   327       (entry->mFeature->mGetter)(aPresContext, entry->mFeature, actual);
   328     NS_ENSURE_SUCCESS(rv, false); // any better ideas?
   330     for (uint32_t j = 0; j < entry->mExpressions.Length(); ++j) {
   331       const ExpressionEntry &eentry = entry->mExpressions[j];
   332       if (eentry.mExpression.Matches(aPresContext, actual) !=
   333           eentry.mExpressionMatches) {
   334         return false;
   335       }
   336     }
   337   }
   339   return true;
   340 }
   342 void
   343 nsMediaQuery::AppendToString(nsAString& aString) const
   344 {
   345   if (mHadUnknownExpression) {
   346     aString.AppendLiteral("not all");
   347     return;
   348   }
   350   NS_ASSERTION(!mNegated || !mHasOnly, "can't have not and only");
   351   NS_ASSERTION(!mTypeOmitted || (!mNegated && !mHasOnly),
   352                "can't have not or only when type is omitted");
   353   if (!mTypeOmitted) {
   354     if (mNegated) {
   355       aString.AppendLiteral("not ");
   356     } else if (mHasOnly) {
   357       aString.AppendLiteral("only ");
   358     }
   359     aString.Append(nsDependentAtomString(mMediaType));
   360   }
   362   for (uint32_t i = 0, i_end = mExpressions.Length(); i < i_end; ++i) {
   363     if (i > 0 || !mTypeOmitted)
   364       aString.AppendLiteral(" and ");
   365     aString.AppendLiteral("(");
   367     const nsMediaExpression &expr = mExpressions[i];
   368     if (expr.mRange == nsMediaExpression::eMin) {
   369       aString.AppendLiteral("min-");
   370     } else if (expr.mRange == nsMediaExpression::eMax) {
   371       aString.AppendLiteral("max-");
   372     }
   374     const nsMediaFeature *feature = expr.mFeature;
   375     aString.Append(nsDependentAtomString(*feature->mName));
   377     if (expr.mValue.GetUnit() != eCSSUnit_Null) {
   378       aString.AppendLiteral(": ");
   379       switch (feature->mValueType) {
   380         case nsMediaFeature::eLength:
   381           NS_ASSERTION(expr.mValue.IsLengthUnit(), "bad unit");
   382           // Use 'width' as a property that takes length values
   383           // written in the normal way.
   384           expr.mValue.AppendToString(eCSSProperty_width, aString,
   385                                      nsCSSValue::eNormalized);
   386           break;
   387         case nsMediaFeature::eInteger:
   388         case nsMediaFeature::eBoolInteger:
   389           NS_ASSERTION(expr.mValue.GetUnit() == eCSSUnit_Integer,
   390                        "bad unit");
   391           // Use 'z-index' as a property that takes integer values
   392           // written without anything extra.
   393           expr.mValue.AppendToString(eCSSProperty_z_index, aString,
   394                                      nsCSSValue::eNormalized);
   395           break;
   396         case nsMediaFeature::eFloat:
   397           {
   398             NS_ASSERTION(expr.mValue.GetUnit() == eCSSUnit_Number,
   399                          "bad unit");
   400             // Use 'line-height' as a property that takes float values
   401             // written in the normal way.
   402             expr.mValue.AppendToString(eCSSProperty_line_height, aString,
   403                                        nsCSSValue::eNormalized);
   404           }
   405           break;
   406         case nsMediaFeature::eIntRatio:
   407           {
   408             NS_ASSERTION(expr.mValue.GetUnit() == eCSSUnit_Array,
   409                          "bad unit");
   410             nsCSSValue::Array *array = expr.mValue.GetArrayValue();
   411             NS_ASSERTION(array->Count() == 2, "unexpected length");
   412             NS_ASSERTION(array->Item(0).GetUnit() == eCSSUnit_Integer,
   413                          "bad unit");
   414             NS_ASSERTION(array->Item(1).GetUnit() == eCSSUnit_Integer,
   415                          "bad unit");
   416             array->Item(0).AppendToString(eCSSProperty_z_index, aString,
   417                                           nsCSSValue::eNormalized);
   418             aString.AppendLiteral("/");
   419             array->Item(1).AppendToString(eCSSProperty_z_index, aString,
   420                                           nsCSSValue::eNormalized);
   421           }
   422           break;
   423         case nsMediaFeature::eResolution:
   424           {
   425             aString.AppendFloat(expr.mValue.GetFloatValue());
   426             if (expr.mValue.GetUnit() == eCSSUnit_Inch) {
   427               aString.AppendLiteral("dpi");
   428             } else if (expr.mValue.GetUnit() == eCSSUnit_Pixel) {
   429               aString.AppendLiteral("dppx");
   430             } else {
   431               NS_ASSERTION(expr.mValue.GetUnit() == eCSSUnit_Centimeter,
   432                            "bad unit");
   433               aString.AppendLiteral("dpcm");
   434             }
   435           }
   436           break;
   437         case nsMediaFeature::eEnumerated:
   438           NS_ASSERTION(expr.mValue.GetUnit() == eCSSUnit_Enumerated,
   439                        "bad unit");
   440           AppendASCIItoUTF16(
   441               nsCSSProps::ValueToKeyword(expr.mValue.GetIntValue(),
   442                                          feature->mData.mKeywordTable),
   443               aString);
   444           break;
   445         case nsMediaFeature::eIdent:
   446           NS_ASSERTION(expr.mValue.GetUnit() == eCSSUnit_Ident,
   447                        "bad unit");
   448           aString.Append(expr.mValue.GetStringBufferValue());
   449           break;
   450       }
   451     }
   453     aString.AppendLiteral(")");
   454   }
   455 }
   457 nsMediaQuery*
   458 nsMediaQuery::Clone() const
   459 {
   460   return new nsMediaQuery(*this);
   461 }
   463 bool
   464 nsMediaQuery::Matches(nsPresContext* aPresContext,
   465                       nsMediaQueryResultCacheKey* aKey) const
   466 {
   467   if (mHadUnknownExpression)
   468     return false;
   470   bool match =
   471     mMediaType == aPresContext->Medium() || mMediaType == nsGkAtoms::all;
   472   for (uint32_t i = 0, i_end = mExpressions.Length(); match && i < i_end; ++i) {
   473     const nsMediaExpression &expr = mExpressions[i];
   474     nsCSSValue actual;
   475     nsresult rv =
   476       (expr.mFeature->mGetter)(aPresContext, expr.mFeature, actual);
   477     NS_ENSURE_SUCCESS(rv, false); // any better ideas?
   479     match = expr.Matches(aPresContext, actual);
   480     if (aKey) {
   481       aKey->AddExpression(&expr, match);
   482     }
   483   }
   485   return match == !mNegated;
   486 }
   488 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(nsMediaList)
   489   NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY
   490   NS_INTERFACE_MAP_ENTRY(nsIDOMMediaList)
   491   NS_INTERFACE_MAP_ENTRY(nsISupports)
   492 NS_INTERFACE_MAP_END
   494 NS_IMPL_CYCLE_COLLECTING_ADDREF(nsMediaList)
   495 NS_IMPL_CYCLE_COLLECTING_RELEASE(nsMediaList)
   497 NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE_0(nsMediaList)
   499 nsMediaList::nsMediaList()
   500   : mStyleSheet(nullptr)
   501 {
   502   SetIsDOMBinding();
   503 }
   505 nsMediaList::~nsMediaList()
   506 {
   507 }
   509 /* virtual */ JSObject*
   510 nsMediaList::WrapObject(JSContext* aCx)
   511 {
   512   return MediaListBinding::Wrap(aCx, this);
   513 }
   515 void
   516 nsMediaList::GetText(nsAString& aMediaText)
   517 {
   518   aMediaText.Truncate();
   520   for (int32_t i = 0, i_end = mArray.Length(); i < i_end; ++i) {
   521     nsMediaQuery* query = mArray[i];
   523     query->AppendToString(aMediaText);
   525     if (i + 1 < i_end) {
   526       aMediaText.AppendLiteral(", ");
   527     }
   528   }
   529 }
   531 // XXXbz this is so ill-defined in the spec, it's not clear quite what
   532 // it should be doing....
   533 void
   534 nsMediaList::SetText(const nsAString& aMediaText)
   535 {
   536   nsCSSParser parser;
   538   bool htmlMode = mStyleSheet && mStyleSheet->GetOwnerNode();
   540   parser.ParseMediaList(aMediaText, nullptr, 0, this, htmlMode);
   541 }
   543 bool
   544 nsMediaList::Matches(nsPresContext* aPresContext,
   545                      nsMediaQueryResultCacheKey* aKey)
   546 {
   547   for (int32_t i = 0, i_end = mArray.Length(); i < i_end; ++i) {
   548     if (mArray[i]->Matches(aPresContext, aKey)) {
   549       return true;
   550     }
   551   }
   552   return mArray.IsEmpty();
   553 }
   555 nsresult
   556 nsMediaList::SetStyleSheet(nsCSSStyleSheet *aSheet)
   557 {
   558   NS_ASSERTION(aSheet == mStyleSheet || !aSheet || !mStyleSheet,
   559                "multiple style sheets competing for one media list");
   560   mStyleSheet = aSheet;
   561   return NS_OK;
   562 }
   564 already_AddRefed<nsMediaList>
   565 nsMediaList::Clone()
   566 {
   567   nsRefPtr<nsMediaList> result = new nsMediaList();
   568   result->mArray.AppendElements(mArray.Length());
   569   for (uint32_t i = 0, i_end = mArray.Length(); i < i_end; ++i) {
   570     result->mArray[i] = mArray[i]->Clone();
   571     MOZ_ASSERT(result->mArray[i]);
   572   }
   573   return result.forget();
   574 }
   576 NS_IMETHODIMP
   577 nsMediaList::GetMediaText(nsAString& aMediaText)
   578 {
   579   GetText(aMediaText);
   580   return NS_OK;
   581 }
   583 // "sheet" should be an nsCSSStyleSheet and "doc" should be an
   584 // nsCOMPtr<nsIDocument>
   585 #define BEGIN_MEDIA_CHANGE(sheet, doc)                         \
   586   if (sheet) {                                                 \
   587     doc = sheet->GetOwningDocument();                          \
   588   }                                                            \
   589   mozAutoDocUpdate updateBatch(doc, UPDATE_STYLE, true);       \
   590   if (sheet) {                                                 \
   591     sheet->WillDirty();                                        \
   592   }
   594 #define END_MEDIA_CHANGE(sheet, doc)                           \
   595   if (sheet) {                                                 \
   596     sheet->DidDirty();                                         \
   597   }                                                            \
   598   /* XXXldb Pass something meaningful? */                      \
   599   if (doc) {                                                   \
   600     doc->StyleRuleChanged(sheet, nullptr, nullptr);              \
   601   }
   604 NS_IMETHODIMP
   605 nsMediaList::SetMediaText(const nsAString& aMediaText)
   606 {
   607   nsCOMPtr<nsIDocument> doc;
   609   BEGIN_MEDIA_CHANGE(mStyleSheet, doc)
   611   SetText(aMediaText);
   613   END_MEDIA_CHANGE(mStyleSheet, doc)
   615   return NS_OK;
   616 }
   618 NS_IMETHODIMP
   619 nsMediaList::GetLength(uint32_t* aLength)
   620 {
   621   NS_ENSURE_ARG_POINTER(aLength);
   623   *aLength = Length();
   624   return NS_OK;
   625 }
   627 NS_IMETHODIMP
   628 nsMediaList::Item(uint32_t aIndex, nsAString& aReturn)
   629 {
   630   bool dummy;
   631   IndexedGetter(aIndex, dummy, aReturn);
   632   return NS_OK;
   633 }
   635 void
   636 nsMediaList::IndexedGetter(uint32_t aIndex, bool& aFound, nsAString& aReturn)
   637 {
   638   if (aIndex < Length()) {
   639     aFound = true;
   640     aReturn.Truncate();
   641     mArray[aIndex]->AppendToString(aReturn);
   642   } else {
   643     aFound = false;
   644     SetDOMStringToNull(aReturn);
   645   }
   646 }
   648 NS_IMETHODIMP
   649 nsMediaList::DeleteMedium(const nsAString& aOldMedium)
   650 {
   651   nsresult rv = NS_OK;
   652   nsCOMPtr<nsIDocument> doc;
   654   BEGIN_MEDIA_CHANGE(mStyleSheet, doc)
   656   rv = Delete(aOldMedium);
   657   if (NS_FAILED(rv))
   658     return rv;
   660   END_MEDIA_CHANGE(mStyleSheet, doc)
   662   return rv;
   663 }
   665 NS_IMETHODIMP
   666 nsMediaList::AppendMedium(const nsAString& aNewMedium)
   667 {
   668   nsresult rv = NS_OK;
   669   nsCOMPtr<nsIDocument> doc;
   671   BEGIN_MEDIA_CHANGE(mStyleSheet, doc)
   673   rv = Append(aNewMedium);
   674   if (NS_FAILED(rv))
   675     return rv;
   677   END_MEDIA_CHANGE(mStyleSheet, doc)
   679   return rv;
   680 }
   682 nsresult
   683 nsMediaList::Delete(const nsAString& aOldMedium)
   684 {
   685   if (aOldMedium.IsEmpty())
   686     return NS_ERROR_DOM_NOT_FOUND_ERR;
   688   for (int32_t i = 0, i_end = mArray.Length(); i < i_end; ++i) {
   689     nsMediaQuery* query = mArray[i];
   691     nsAutoString buf;
   692     query->AppendToString(buf);
   693     if (buf == aOldMedium) {
   694       mArray.RemoveElementAt(i);
   695       return NS_OK;
   696     }
   697   }
   699   return NS_ERROR_DOM_NOT_FOUND_ERR;
   700 }
   702 nsresult
   703 nsMediaList::Append(const nsAString& aNewMedium)
   704 {
   705   if (aNewMedium.IsEmpty())
   706     return NS_ERROR_DOM_NOT_FOUND_ERR;
   708   Delete(aNewMedium);
   710   nsresult rv = NS_OK;
   711   nsTArray<nsAutoPtr<nsMediaQuery> > buf;
   712   mArray.SwapElements(buf);
   713   SetText(aNewMedium);
   714   if (mArray.Length() == 1) {
   715     nsMediaQuery *query = mArray[0].forget();
   716     if (!buf.AppendElement(query)) {
   717       delete query;
   718       rv = NS_ERROR_OUT_OF_MEMORY;
   719     }
   720   }
   722   mArray.SwapElements(buf);
   723   return rv;
   724 }
   726 // -------------------------------
   727 // CSS Style Sheet Inner Data Container
   728 //
   731 nsCSSStyleSheetInner::nsCSSStyleSheetInner(nsCSSStyleSheet* aPrimarySheet,
   732                                            CORSMode aCORSMode)
   733   : mSheets(),
   734     mCORSMode(aCORSMode),
   735     mComplete(false)
   736 #ifdef DEBUG
   737     , mPrincipalSet(false)
   738 #endif
   739 {
   740   MOZ_COUNT_CTOR(nsCSSStyleSheetInner);
   741   mSheets.AppendElement(aPrimarySheet);
   743   mPrincipal = do_CreateInstance("@mozilla.org/nullprincipal;1");
   744   if (!mPrincipal) {
   745     NS_RUNTIMEABORT("OOM");
   746   }
   747 }
   749 static bool SetStyleSheetReference(css::Rule* aRule, void* aSheet)
   750 {
   751   if (aRule) {
   752     aRule->SetStyleSheet(static_cast<nsCSSStyleSheet*>(aSheet));
   753   }
   754   return true;
   755 }
   757 struct ChildSheetListBuilder {
   758   nsRefPtr<nsCSSStyleSheet>* sheetSlot;
   759   nsCSSStyleSheet* parent;
   761   void SetParentLinks(nsCSSStyleSheet* aSheet) {
   762     aSheet->mParent = parent;
   763     aSheet->SetOwningDocument(parent->mDocument);
   764   }
   766   static void ReparentChildList(nsCSSStyleSheet* aPrimarySheet,
   767                                 nsCSSStyleSheet* aFirstChild)
   768   {
   769     for (nsCSSStyleSheet *child = aFirstChild; child; child = child->mNext) {
   770       child->mParent = aPrimarySheet;
   771       child->SetOwningDocument(aPrimarySheet->mDocument);
   772     }
   773   }
   774 };
   776 bool
   777 nsCSSStyleSheet::RebuildChildList(css::Rule* aRule, void* aBuilder)
   778 {
   779   int32_t type = aRule->GetType();
   780   if (type < css::Rule::IMPORT_RULE) {
   781     // Keep going till we get to the import rules.
   782     return true;
   783   }
   785   if (type != css::Rule::IMPORT_RULE) {
   786     // We're past all the import rules; stop the enumeration.
   787     return false;
   788   }
   790   ChildSheetListBuilder* builder =
   791     static_cast<ChildSheetListBuilder*>(aBuilder);
   793   // XXXbz We really need to decomtaminate all this stuff.  Is there a reason
   794   // that I can't just QI to ImportRule and get an nsCSSStyleSheet
   795   // directly from it?
   796   nsCOMPtr<nsIDOMCSSImportRule> importRule(do_QueryInterface(aRule));
   797   NS_ASSERTION(importRule, "GetType lied");
   799   nsCOMPtr<nsIDOMCSSStyleSheet> childSheet;
   800   importRule->GetStyleSheet(getter_AddRefs(childSheet));
   802   // Have to do this QI to be safe, since XPConnect can fake
   803   // nsIDOMCSSStyleSheets
   804   nsRefPtr<nsCSSStyleSheet> cssSheet = do_QueryObject(childSheet);
   805   if (!cssSheet) {
   806     return true;
   807   }
   809   (*builder->sheetSlot) = cssSheet;
   810   builder->SetParentLinks(*builder->sheetSlot);
   811   builder->sheetSlot = &(*builder->sheetSlot)->mNext;
   812   return true;
   813 }
   815 size_t
   816 nsCSSStyleSheet::SizeOfIncludingThis(MallocSizeOf aMallocSizeOf) const
   817 {
   818   size_t n = 0;
   819   const nsCSSStyleSheet* s = this;
   820   while (s) {
   821     n += aMallocSizeOf(s);
   823     // Each inner can be shared by multiple sheets.  So we only count the inner
   824     // if this sheet is the first one in the list of those sharing it.  As a
   825     // result, the first such sheet takes all the blame for the memory
   826     // consumption of the inner, which isn't ideal but it's better than
   827     // double-counting the inner.
   828     if (s->mInner->mSheets[0] == s) {
   829       n += s->mInner->SizeOfIncludingThis(aMallocSizeOf);
   830     }
   832     // Measurement of the following members may be added later if DMD finds it
   833     // is worthwhile:
   834     // - s->mTitle
   835     // - s->mMedia
   836     // - s->mRuleCollection
   837     // - s->mRuleProcessors
   838     //
   839     // The following members are not measured:
   840     // - s->mOwnerRule, because it's non-owning
   842     s = s->mNext;
   843   }
   844   return n;
   845 }
   847 nsCSSStyleSheetInner::nsCSSStyleSheetInner(nsCSSStyleSheetInner& aCopy,
   848                                            nsCSSStyleSheet* aPrimarySheet)
   849   : mSheets(),
   850     mSheetURI(aCopy.mSheetURI),
   851     mOriginalSheetURI(aCopy.mOriginalSheetURI),
   852     mBaseURI(aCopy.mBaseURI),
   853     mPrincipal(aCopy.mPrincipal),
   854     mCORSMode(aCopy.mCORSMode),
   855     mComplete(aCopy.mComplete)
   856 #ifdef DEBUG
   857     , mPrincipalSet(aCopy.mPrincipalSet)
   858 #endif
   859 {
   860   MOZ_COUNT_CTOR(nsCSSStyleSheetInner);
   861   AddSheet(aPrimarySheet);
   862   aCopy.mOrderedRules.EnumerateForwards(css::GroupRule::CloneRuleInto, &mOrderedRules);
   863   mOrderedRules.EnumerateForwards(SetStyleSheetReference, aPrimarySheet);
   865   ChildSheetListBuilder builder = { &mFirstChild, aPrimarySheet };
   866   mOrderedRules.EnumerateForwards(nsCSSStyleSheet::RebuildChildList, &builder);
   868   RebuildNameSpaces();
   869 }
   871 nsCSSStyleSheetInner::~nsCSSStyleSheetInner()
   872 {
   873   MOZ_COUNT_DTOR(nsCSSStyleSheetInner);
   874   mOrderedRules.EnumerateForwards(SetStyleSheetReference, nullptr);
   875 }
   877 nsCSSStyleSheetInner* 
   878 nsCSSStyleSheetInner::CloneFor(nsCSSStyleSheet* aPrimarySheet)
   879 {
   880   return new nsCSSStyleSheetInner(*this, aPrimarySheet);
   881 }
   883 void
   884 nsCSSStyleSheetInner::AddSheet(nsCSSStyleSheet* aSheet)
   885 {
   886   mSheets.AppendElement(aSheet);
   887 }
   889 void
   890 nsCSSStyleSheetInner::RemoveSheet(nsCSSStyleSheet* aSheet)
   891 {
   892   if (1 == mSheets.Length()) {
   893     NS_ASSERTION(aSheet == mSheets.ElementAt(0), "bad parent");
   894     delete this;
   895     return;
   896   }
   897   if (aSheet == mSheets.ElementAt(0)) {
   898     mSheets.RemoveElementAt(0);
   899     NS_ASSERTION(mSheets.Length(), "no parents");
   900     mOrderedRules.EnumerateForwards(SetStyleSheetReference,
   901                                     mSheets.ElementAt(0));
   903     ChildSheetListBuilder::ReparentChildList(mSheets[0], mFirstChild);
   904   }
   905   else {
   906     mSheets.RemoveElement(aSheet);
   907   }
   908 }
   910 static void
   911 AddNamespaceRuleToMap(css::Rule* aRule, nsXMLNameSpaceMap* aMap)
   912 {
   913   NS_ASSERTION(aRule->GetType() == css::Rule::NAMESPACE_RULE, "Bogus rule type");
   915   nsRefPtr<css::NameSpaceRule> nameSpaceRule = do_QueryObject(aRule);
   917   nsAutoString  urlSpec;
   918   nameSpaceRule->GetURLSpec(urlSpec);
   920   aMap->AddPrefix(nameSpaceRule->GetPrefix(), urlSpec);
   921 }
   923 static bool
   924 CreateNameSpace(css::Rule* aRule, void* aNameSpacePtr)
   925 {
   926   int32_t type = aRule->GetType();
   927   if (css::Rule::NAMESPACE_RULE == type) {
   928     AddNamespaceRuleToMap(aRule,
   929                           static_cast<nsXMLNameSpaceMap*>(aNameSpacePtr));
   930     return true;
   931   }
   932   // stop if not namespace, import or charset because namespace can't follow
   933   // anything else
   934   return (css::Rule::CHARSET_RULE == type || css::Rule::IMPORT_RULE == type);
   935 }
   937 void 
   938 nsCSSStyleSheetInner::RebuildNameSpaces()
   939 {
   940   // Just nuke our existing namespace map, if any
   941   if (NS_SUCCEEDED(CreateNamespaceMap())) {
   942     mOrderedRules.EnumerateForwards(CreateNameSpace, mNameSpaceMap);
   943   }
   944 }
   946 nsresult
   947 nsCSSStyleSheetInner::CreateNamespaceMap()
   948 {
   949   mNameSpaceMap = nsXMLNameSpaceMap::Create(false);
   950   NS_ENSURE_TRUE(mNameSpaceMap, NS_ERROR_OUT_OF_MEMORY);
   951   // Override the default namespace map behavior for the null prefix to
   952   // return the wildcard namespace instead of the null namespace.
   953   mNameSpaceMap->AddPrefix(nullptr, kNameSpaceID_Unknown);
   954   return NS_OK;
   955 }
   957 size_t
   958 nsCSSStyleSheetInner::SizeOfIncludingThis(MallocSizeOf aMallocSizeOf) const
   959 {
   960   size_t n = aMallocSizeOf(this);
   961   n += mOrderedRules.SizeOfExcludingThis(css::Rule::SizeOfCOMArrayElementIncludingThis,
   962                                          aMallocSizeOf);
   963   n += mFirstChild ? mFirstChild->SizeOfIncludingThis(aMallocSizeOf) : 0;
   965   // Measurement of the following members may be added later if DMD finds it is
   966   // worthwhile:
   967   // - mSheetURI
   968   // - mOriginalSheetURI
   969   // - mBaseURI
   970   // - mPrincipal
   971   // - mNameSpaceMap
   972   //
   973   // The following members are not measured:
   974   // - mSheets, because it's non-owning
   976   return n;
   977 }
   979 // -------------------------------
   980 // CSS Style Sheet
   981 //
   983 nsCSSStyleSheet::nsCSSStyleSheet(CORSMode aCORSMode)
   984   : mTitle(), 
   985     mParent(nullptr),
   986     mOwnerRule(nullptr),
   987     mDocument(nullptr),
   988     mOwningNode(nullptr),
   989     mDisabled(false),
   990     mDirty(false),
   991     mScopeElement(nullptr),
   992     mRuleProcessors(nullptr)
   993 {
   994   mInner = new nsCSSStyleSheetInner(this, aCORSMode);
   996   SetIsDOMBinding();
   997 }
   999 nsCSSStyleSheet::nsCSSStyleSheet(const nsCSSStyleSheet& aCopy,
  1000                                  nsCSSStyleSheet* aParentToUse,
  1001                                  css::ImportRule* aOwnerRuleToUse,
  1002                                  nsIDocument* aDocumentToUse,
  1003                                  nsINode* aOwningNodeToUse)
  1004   : mTitle(aCopy.mTitle),
  1005     mParent(aParentToUse),
  1006     mOwnerRule(aOwnerRuleToUse),
  1007     mDocument(aDocumentToUse),
  1008     mOwningNode(aOwningNodeToUse),
  1009     mDisabled(aCopy.mDisabled),
  1010     mDirty(aCopy.mDirty),
  1011     mScopeElement(nullptr),
  1012     mInner(aCopy.mInner),
  1013     mRuleProcessors(nullptr)
  1016   mInner->AddSheet(this);
  1018   if (mDirty) { // CSSOM's been there, force full copy now
  1019     NS_ASSERTION(mInner->mComplete, "Why have rules been accessed on an incomplete sheet?");
  1020     // FIXME: handle failure?
  1021     EnsureUniqueInner();
  1024   if (aCopy.mMedia) {
  1025     // XXX This is wrong; we should be keeping @import rules and
  1026     // sheets in sync!
  1027     mMedia = aCopy.mMedia->Clone();
  1030   SetIsDOMBinding();
  1033 nsCSSStyleSheet::~nsCSSStyleSheet()
  1035   for (nsCSSStyleSheet* child = mInner->mFirstChild;
  1036        child;
  1037        child = child->mNext) {
  1038     // XXXbz this is a little bogus; see the XXX comment where we
  1039     // declare mFirstChild.
  1040     if (child->mParent == this) {
  1041       child->mParent = nullptr;
  1042       child->mDocument = nullptr;
  1045   DropRuleCollection();
  1046   DropMedia();
  1047   mInner->RemoveSheet(this);
  1048   // XXX The document reference is not reference counted and should
  1049   // not be released. The document will let us know when it is going
  1050   // away.
  1051   if (mRuleProcessors) {
  1052     NS_ASSERTION(mRuleProcessors->Length() == 0, "destructing sheet with rule processor reference");
  1053     delete mRuleProcessors; // weak refs, should be empty here anyway
  1057 void
  1058 nsCSSStyleSheet::DropRuleCollection()
  1060   if (mRuleCollection) {
  1061     mRuleCollection->DropReference();
  1062     mRuleCollection = nullptr;
  1066 void
  1067 nsCSSStyleSheet::DropMedia()
  1069   if (mMedia) {
  1070     mMedia->SetStyleSheet(nullptr);
  1071     mMedia = nullptr;
  1075 void
  1076 nsCSSStyleSheet::UnlinkInner()
  1078   // We can only have a cycle through our inner if we have a unique inner,
  1079   // because otherwise there are no JS wrappers for anything in the inner.
  1080   if (mInner->mSheets.Length() != 1) {
  1081     return;
  1084   mInner->mOrderedRules.EnumerateForwards(SetStyleSheetReference, nullptr);
  1085   mInner->mOrderedRules.Clear();
  1087   // Have to be a bit careful with child sheets, because we want to
  1088   // drop their mNext pointers and null out their mParent and
  1089   // mDocument, but don't want to work with deleted objects.  And we
  1090   // don't want to do any addrefing in the process, just to make sure
  1091   // we don't confuse the cycle collector (though on the face of it,
  1092   // addref/release pairs during unlink should probably be ok).
  1093   nsRefPtr<nsCSSStyleSheet> child;
  1094   child.swap(mInner->mFirstChild);
  1095   while (child) {
  1096     MOZ_ASSERT(child->mParent == this, "We have a unique inner!");
  1097     child->mParent = nullptr;
  1098     child->mDocument = nullptr;
  1099     nsRefPtr<nsCSSStyleSheet> next;
  1100     // Null out child->mNext, but don't let it die yet
  1101     next.swap(child->mNext);
  1102     // Switch to looking at the old value of child->mNext next iteration
  1103     child.swap(next);
  1104     // "next" is now our previous value of child; it'll get released
  1105     // as we loop around.
  1109 void
  1110 nsCSSStyleSheet::TraverseInner(nsCycleCollectionTraversalCallback &cb)
  1112   // We can only have a cycle through our inner if we have a unique inner,
  1113   // because otherwise there are no JS wrappers for anything in the inner.
  1114   if (mInner->mSheets.Length() != 1) {
  1115     return;
  1118   nsRefPtr<nsCSSStyleSheet>* childSheetSlot = &mInner->mFirstChild;
  1119   while (*childSheetSlot) {
  1120     NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(cb, "child sheet");
  1121     cb.NoteXPCOMChild(NS_ISUPPORTS_CAST(nsIStyleSheet*, childSheetSlot->get()));
  1122     childSheetSlot = &(*childSheetSlot)->mNext;
  1125   const nsCOMArray<css::Rule>& rules = mInner->mOrderedRules;
  1126   for (int32_t i = 0, count = rules.Count(); i < count; ++i) {
  1127     NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(cb, "mOrderedRules[i]");
  1128     cb.NoteXPCOMChild(rules[i]->GetExistingDOMRule());
  1132 DOMCI_DATA(CSSStyleSheet, nsCSSStyleSheet)
  1134 // QueryInterface implementation for nsCSSStyleSheet
  1135 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(nsCSSStyleSheet)
  1136   NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY
  1137   NS_INTERFACE_MAP_ENTRY(nsIStyleSheet)
  1138   NS_INTERFACE_MAP_ENTRY(nsIDOMStyleSheet)
  1139   NS_INTERFACE_MAP_ENTRY(nsIDOMCSSStyleSheet)
  1140   NS_INTERFACE_MAP_ENTRY(nsICSSLoaderObserver)
  1141   NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIStyleSheet)
  1142   NS_DOM_INTERFACE_MAP_ENTRY_CLASSINFO(CSSStyleSheet)
  1143   if (aIID.Equals(NS_GET_IID(nsCSSStyleSheet)))
  1144     foundInterface = reinterpret_cast<nsISupports*>(this);
  1145   else
  1146 NS_INTERFACE_MAP_END
  1149 NS_IMPL_CYCLE_COLLECTING_ADDREF(nsCSSStyleSheet)
  1150 NS_IMPL_CYCLE_COLLECTING_RELEASE(nsCSSStyleSheet)
  1152 NS_IMPL_CYCLE_COLLECTION_CLASS(nsCSSStyleSheet)
  1154 NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(nsCSSStyleSheet)
  1155   tmp->DropMedia();
  1156   // We do not unlink mNext; our parent will handle that.  If we
  1157   // unlinked it here, our parent would not be able to walk its list
  1158   // of child sheets and null out the back-references to it, if we got
  1159   // unlinked before it does.
  1160   tmp->DropRuleCollection();
  1161   tmp->UnlinkInner();
  1162   tmp->mScopeElement = nullptr;
  1163   NS_IMPL_CYCLE_COLLECTION_UNLINK_PRESERVED_WRAPPER
  1164 NS_IMPL_CYCLE_COLLECTION_UNLINK_END
  1165 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(nsCSSStyleSheet)
  1166   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mMedia)
  1167   // We do not traverse mNext; our parent will handle that.  See
  1168   // comments in Unlink for why.
  1169   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mRuleCollection)
  1170   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mScopeElement)
  1171   tmp->TraverseInner(cb);
  1172   NS_IMPL_CYCLE_COLLECTION_TRAVERSE_SCRIPT_OBJECTS
  1173 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
  1174 NS_IMPL_CYCLE_COLLECTION_TRACE_WRAPPERCACHE(nsCSSStyleSheet)
  1176 nsresult
  1177 nsCSSStyleSheet::AddRuleProcessor(nsCSSRuleProcessor* aProcessor)
  1179   if (! mRuleProcessors) {
  1180     mRuleProcessors = new nsAutoTArray<nsCSSRuleProcessor*, 8>();
  1181     if (!mRuleProcessors)
  1182       return NS_ERROR_OUT_OF_MEMORY;
  1184   NS_ASSERTION(mRuleProcessors->NoIndex == mRuleProcessors->IndexOf(aProcessor),
  1185                "processor already registered");
  1186   mRuleProcessors->AppendElement(aProcessor); // weak ref
  1187   return NS_OK;
  1190 nsresult
  1191 nsCSSStyleSheet::DropRuleProcessor(nsCSSRuleProcessor* aProcessor)
  1193   if (!mRuleProcessors)
  1194     return NS_ERROR_FAILURE;
  1195   return mRuleProcessors->RemoveElement(aProcessor)
  1196            ? NS_OK
  1197            : NS_ERROR_FAILURE;
  1201 void
  1202 nsCSSStyleSheet::SetURIs(nsIURI* aSheetURI, nsIURI* aOriginalSheetURI,
  1203                          nsIURI* aBaseURI)
  1205   NS_PRECONDITION(aSheetURI && aBaseURI, "null ptr");
  1207   NS_ASSERTION(mInner->mOrderedRules.Count() == 0 && !mInner->mComplete,
  1208                "Can't call SetURL on sheets that are complete or have rules");
  1210   mInner->mSheetURI = aSheetURI;
  1211   mInner->mOriginalSheetURI = aOriginalSheetURI;
  1212   mInner->mBaseURI = aBaseURI;
  1215 void
  1216 nsCSSStyleSheet::SetPrincipal(nsIPrincipal* aPrincipal)
  1218   NS_PRECONDITION(!mInner->mPrincipalSet,
  1219                   "Should have an inner whose principal has not yet been set");
  1220   if (aPrincipal) {
  1221     mInner->mPrincipal = aPrincipal;
  1222 #ifdef DEBUG
  1223     mInner->mPrincipalSet = true;
  1224 #endif
  1228 /* virtual */ nsIURI*
  1229 nsCSSStyleSheet::GetSheetURI() const
  1231   return mInner->mSheetURI;
  1234 /* virtual */ nsIURI*
  1235 nsCSSStyleSheet::GetBaseURI() const
  1237   return mInner->mBaseURI;
  1240 /* virtual */ void
  1241 nsCSSStyleSheet::GetType(nsString& aType) const
  1243   aType.AssignLiteral("text/css");
  1246 bool
  1247 nsCSSStyleSheet::UseForPresentation(nsPresContext* aPresContext,
  1248                                     nsMediaQueryResultCacheKey& aKey) const
  1250   if (mMedia) {
  1251     return mMedia->Matches(aPresContext, &aKey);
  1253   return true;
  1257 void
  1258 nsCSSStyleSheet::SetMedia(nsMediaList* aMedia)
  1260   mMedia = aMedia;
  1263 /* virtual */ bool
  1264 nsCSSStyleSheet::HasRules() const
  1266   return StyleRuleCount() != 0;
  1269 /* virtual */ bool
  1270 nsCSSStyleSheet::IsApplicable() const
  1272   return !mDisabled && mInner->mComplete;
  1275 /* virtual */ void
  1276 nsCSSStyleSheet::SetEnabled(bool aEnabled)
  1278   // Internal method, so callers must handle BeginUpdate/EndUpdate
  1279   bool oldDisabled = mDisabled;
  1280   mDisabled = !aEnabled;
  1282   if (mInner->mComplete && oldDisabled != mDisabled) {
  1283     ClearRuleCascades();
  1285     if (mDocument) {
  1286       mDocument->SetStyleSheetApplicableState(this, !mDisabled);
  1291 /* virtual */ bool
  1292 nsCSSStyleSheet::IsComplete() const
  1294   return mInner->mComplete;
  1297 /* virtual */ void
  1298 nsCSSStyleSheet::SetComplete()
  1300   NS_ASSERTION(!mDirty, "Can't set a dirty sheet complete!");
  1301   mInner->mComplete = true;
  1302   if (mDocument && !mDisabled) {
  1303     // Let the document know
  1304     mDocument->BeginUpdate(UPDATE_STYLE);
  1305     mDocument->SetStyleSheetApplicableState(this, true);
  1306     mDocument->EndUpdate(UPDATE_STYLE);
  1310 /* virtual */ nsIStyleSheet*
  1311 nsCSSStyleSheet::GetParentSheet() const
  1313   return mParent;
  1316 /* virtual */ nsIDocument*
  1317 nsCSSStyleSheet::GetOwningDocument() const
  1319   return mDocument;
  1322 /* virtual */ void
  1323 nsCSSStyleSheet::SetOwningDocument(nsIDocument* aDocument)
  1324 { // not ref counted
  1325   mDocument = aDocument;
  1326   // Now set the same document on all our child sheets....
  1327   // XXXbz this is a little bogus; see the XXX comment where we
  1328   // declare mFirstChild.
  1329   for (nsCSSStyleSheet* child = mInner->mFirstChild;
  1330        child; child = child->mNext) {
  1331     if (child->mParent == this) {
  1332       child->SetOwningDocument(aDocument);
  1337 uint64_t
  1338 nsCSSStyleSheet::FindOwningWindowInnerID() const
  1340   uint64_t windowID = 0;
  1341   if (mDocument) {
  1342     windowID = mDocument->InnerWindowID();
  1345   if (windowID == 0 && mOwningNode) {
  1346     windowID = mOwningNode->OwnerDoc()->InnerWindowID();
  1349   if (windowID == 0 && mOwnerRule) {
  1350     nsCOMPtr<nsIStyleSheet> sheet = static_cast<css::Rule*>(mOwnerRule)->GetStyleSheet();
  1351     if (sheet) {
  1352       nsRefPtr<nsCSSStyleSheet> cssSheet = do_QueryObject(sheet);
  1353       if (cssSheet) {
  1354         windowID = cssSheet->FindOwningWindowInnerID();
  1359   if (windowID == 0 && mParent) {
  1360     windowID = mParent->FindOwningWindowInnerID();
  1363   return windowID;
  1366 void
  1367 nsCSSStyleSheet::AppendStyleSheet(nsCSSStyleSheet* aSheet)
  1369   NS_PRECONDITION(nullptr != aSheet, "null arg");
  1371   WillDirty();
  1372   nsRefPtr<nsCSSStyleSheet>* tail = &mInner->mFirstChild;
  1373   while (*tail) {
  1374     tail = &(*tail)->mNext;
  1376   *tail = aSheet;
  1378   // This is not reference counted. Our parent tells us when
  1379   // it's going away.
  1380   aSheet->mParent = this;
  1381   aSheet->mDocument = mDocument;
  1382   DidDirty();
  1385 void
  1386 nsCSSStyleSheet::InsertStyleSheetAt(nsCSSStyleSheet* aSheet, int32_t aIndex)
  1388   NS_PRECONDITION(nullptr != aSheet, "null arg");
  1390   WillDirty();
  1391   nsRefPtr<nsCSSStyleSheet>* tail = &mInner->mFirstChild;
  1392   while (*tail && aIndex) {
  1393     --aIndex;
  1394     tail = &(*tail)->mNext;
  1396   aSheet->mNext = *tail;
  1397   *tail = aSheet;
  1399   // This is not reference counted. Our parent tells us when
  1400   // it's going away.
  1401   aSheet->mParent = this;
  1402   aSheet->mDocument = mDocument;
  1403   DidDirty();
  1406 void
  1407 nsCSSStyleSheet::PrependStyleRule(css::Rule* aRule)
  1409   NS_PRECONDITION(nullptr != aRule, "null arg");
  1411   WillDirty();
  1412   mInner->mOrderedRules.InsertObjectAt(aRule, 0);
  1413   aRule->SetStyleSheet(this);
  1414   DidDirty();
  1416   if (css::Rule::NAMESPACE_RULE == aRule->GetType()) {
  1417     // no api to prepend a namespace (ugh), release old ones and re-create them all
  1418     mInner->RebuildNameSpaces();
  1422 void
  1423 nsCSSStyleSheet::AppendStyleRule(css::Rule* aRule)
  1425   NS_PRECONDITION(nullptr != aRule, "null arg");
  1427   WillDirty();
  1428   mInner->mOrderedRules.AppendObject(aRule);
  1429   aRule->SetStyleSheet(this);
  1430   DidDirty();
  1432   if (css::Rule::NAMESPACE_RULE == aRule->GetType()) {
  1433 #ifdef DEBUG
  1434     nsresult rv =
  1435 #endif
  1436       RegisterNamespaceRule(aRule);
  1437     NS_WARN_IF_FALSE(NS_SUCCEEDED(rv),
  1438                      "RegisterNamespaceRule returned error");
  1442 void
  1443 nsCSSStyleSheet::ReplaceStyleRule(css::Rule* aOld, css::Rule* aNew)
  1445   NS_PRECONDITION(mInner->mOrderedRules.Count() != 0, "can't have old rule");
  1446   NS_PRECONDITION(mInner->mComplete, "No replacing in an incomplete sheet!");
  1448   WillDirty();
  1449   int32_t index = mInner->mOrderedRules.IndexOf(aOld);
  1450   if (MOZ_UNLIKELY(index == -1)) {
  1451     NS_NOTREACHED("Couldn't find old rule");
  1452     return;
  1454   mInner->mOrderedRules.ReplaceObjectAt(aNew, index);
  1456   aNew->SetStyleSheet(this);
  1457   aOld->SetStyleSheet(nullptr);
  1458   DidDirty();
  1459   NS_ASSERTION(css::Rule::NAMESPACE_RULE != aNew->GetType(), "not yet implemented");
  1460   NS_ASSERTION(css::Rule::NAMESPACE_RULE != aOld->GetType(), "not yet implemented");
  1463 int32_t
  1464 nsCSSStyleSheet::StyleRuleCount() const
  1466   return mInner->mOrderedRules.Count();
  1469 css::Rule*
  1470 nsCSSStyleSheet::GetStyleRuleAt(int32_t aIndex) const
  1472   // Important: If this function is ever made scriptable, we must add
  1473   // a security check here. See GetCssRules below for an example.
  1474   return mInner->mOrderedRules.SafeObjectAt(aIndex);
  1477 int32_t
  1478 nsCSSStyleSheet::StyleSheetCount() const
  1480   // XXX Far from an ideal way to do this, but the hope is that
  1481   // it won't be done too often. If it is, we might want to 
  1482   // consider storing the children in an array.
  1483   int32_t count = 0;
  1485   const nsCSSStyleSheet* child = mInner->mFirstChild;
  1486   while (child) {
  1487     count++;
  1488     child = child->mNext;
  1491   return count;
  1494 nsCSSStyleSheet::EnsureUniqueInnerResult
  1495 nsCSSStyleSheet::EnsureUniqueInner()
  1497   mDirty = true;
  1499   NS_ABORT_IF_FALSE(mInner->mSheets.Length() != 0,
  1500                     "unexpected number of outers");
  1501   if (mInner->mSheets.Length() == 1) {
  1502     return eUniqueInner_AlreadyUnique;
  1504   nsCSSStyleSheetInner* clone = mInner->CloneFor(this);
  1505   MOZ_ASSERT(clone);
  1506   mInner->RemoveSheet(this);
  1507   mInner = clone;
  1509   // otherwise the rule processor has pointers to the old rules
  1510   ClearRuleCascades();
  1512   return eUniqueInner_ClonedInner;
  1515 void
  1516 nsCSSStyleSheet::AppendAllChildSheets(nsTArray<nsCSSStyleSheet*>& aArray)
  1518   for (nsCSSStyleSheet* child = mInner->mFirstChild; child;
  1519        child = child->mNext) {
  1520     aArray.AppendElement(child);
  1524 already_AddRefed<nsCSSStyleSheet>
  1525 nsCSSStyleSheet::Clone(nsCSSStyleSheet* aCloneParent,
  1526                        css::ImportRule* aCloneOwnerRule,
  1527                        nsIDocument* aCloneDocument,
  1528                        nsINode* aCloneOwningNode) const
  1530   nsRefPtr<nsCSSStyleSheet> clone = new nsCSSStyleSheet(*this,
  1531                                                         aCloneParent,
  1532                                                         aCloneOwnerRule,
  1533                                                         aCloneDocument,
  1534                                                         aCloneOwningNode);
  1535   return clone.forget();
  1538 #ifdef DEBUG
  1539 static void
  1540 ListRules(const nsCOMArray<css::Rule>& aRules, FILE* aOut, int32_t aIndent)
  1542   for (int32_t index = aRules.Count() - 1; index >= 0; --index) {
  1543     aRules.ObjectAt(index)->List(aOut, aIndent);
  1547 struct ListEnumData {
  1548   ListEnumData(FILE* aOut, int32_t aIndent)
  1549     : mOut(aOut),
  1550       mIndent(aIndent)
  1553   FILE*   mOut;
  1554   int32_t mIndent;
  1555 };
  1557 /* virtual */ void
  1558 nsCSSStyleSheet::List(FILE* out, int32_t aIndent) const
  1561   int32_t index;
  1563   // Indent
  1564   for (index = aIndent; --index >= 0; ) fputs("  ", out);
  1566   fputs("CSS Style Sheet: ", out);
  1567   nsAutoCString urlSpec;
  1568   nsresult rv = mInner->mSheetURI->GetSpec(urlSpec);
  1569   if (NS_SUCCEEDED(rv) && !urlSpec.IsEmpty()) {
  1570     fputs(urlSpec.get(), out);
  1573   if (mMedia) {
  1574     fputs(" media: ", out);
  1575     nsAutoString  buffer;
  1576     mMedia->GetText(buffer);
  1577     fputs(NS_ConvertUTF16toUTF8(buffer).get(), out);
  1579   fputs("\n", out);
  1581   for (const nsCSSStyleSheet*  child = mInner->mFirstChild;
  1582        child;
  1583        child = child->mNext) {
  1584     child->List(out, aIndent + 1);
  1587   fputs("Rules in source order:\n", out);
  1588   ListRules(mInner->mOrderedRules, out, aIndent);
  1590 #endif
  1592 void 
  1593 nsCSSStyleSheet::ClearRuleCascades()
  1595   if (mRuleProcessors) {
  1596     nsCSSRuleProcessor **iter = mRuleProcessors->Elements(),
  1597                        **end = iter + mRuleProcessors->Length();
  1598     for(; iter != end; ++iter) {
  1599       (*iter)->ClearRuleCascades();
  1602   if (mParent) {
  1603     nsCSSStyleSheet* parent = (nsCSSStyleSheet*)mParent;
  1604     parent->ClearRuleCascades();
  1608 void
  1609 nsCSSStyleSheet::WillDirty()
  1611   if (mInner->mComplete) {
  1612     EnsureUniqueInner();
  1616 void
  1617 nsCSSStyleSheet::DidDirty()
  1619   NS_ABORT_IF_FALSE(!mInner->mComplete || mDirty,
  1620                     "caller must have called WillDirty()");
  1621   ClearRuleCascades();
  1624 nsresult
  1625 nsCSSStyleSheet::SubjectSubsumesInnerPrincipal()
  1627   // Get the security manager and do the subsumes check
  1628   nsIScriptSecurityManager *securityManager =
  1629     nsContentUtils::GetSecurityManager();
  1631   nsCOMPtr<nsIPrincipal> subjectPrincipal;
  1632   nsresult rv = securityManager->GetSubjectPrincipal(getter_AddRefs(subjectPrincipal));
  1633   NS_ENSURE_SUCCESS(rv, rv);
  1635   if (!subjectPrincipal) {
  1636     return NS_ERROR_DOM_SECURITY_ERR;
  1639   bool subsumes;
  1640   rv = subjectPrincipal->Subsumes(mInner->mPrincipal, &subsumes);
  1641   NS_ENSURE_SUCCESS(rv, rv);
  1643   if (subsumes) {
  1644     return NS_OK;
  1647   if (!nsContentUtils::IsCallerChrome()) {
  1648     // Allow access only if CORS mode is not NONE
  1649     if (GetCORSMode() == CORS_NONE) {
  1650       return NS_ERROR_DOM_SECURITY_ERR;
  1653     // Now make sure we set the principal of our inner to the
  1654     // subjectPrincipal.  That means we need a unique inner, of
  1655     // course.  But we don't want to do that if we're not complete
  1656     // yet.  Luckily, all the callers of this method throw anyway if
  1657     // not complete, so we can just do that here too.
  1658     if (!mInner->mComplete) {
  1659       return NS_ERROR_DOM_INVALID_ACCESS_ERR;
  1662     WillDirty();
  1664     mInner->mPrincipal = subjectPrincipal;
  1666     DidDirty();
  1669   return NS_OK;
  1672 nsresult
  1673 nsCSSStyleSheet::RegisterNamespaceRule(css::Rule* aRule)
  1675   if (!mInner->mNameSpaceMap) {
  1676     nsresult rv = mInner->CreateNamespaceMap();
  1677     NS_ENSURE_SUCCESS(rv, rv);
  1680   AddNamespaceRuleToMap(aRule, mInner->mNameSpaceMap);
  1681   return NS_OK;
  1684   // nsIDOMStyleSheet interface
  1685 NS_IMETHODIMP    
  1686 nsCSSStyleSheet::GetType(nsAString& aType)
  1688   aType.AssignLiteral("text/css");
  1689   return NS_OK;
  1692 NS_IMETHODIMP    
  1693 nsCSSStyleSheet::GetDisabled(bool* aDisabled)
  1695   *aDisabled = Disabled();
  1696   return NS_OK;
  1699 NS_IMETHODIMP    
  1700 nsCSSStyleSheet::SetDisabled(bool aDisabled)
  1702   // DOM method, so handle BeginUpdate/EndUpdate
  1703   MOZ_AUTO_DOC_UPDATE(mDocument, UPDATE_STYLE, true);
  1704   nsCSSStyleSheet::SetEnabled(!aDisabled);
  1705   return NS_OK;
  1708 NS_IMETHODIMP
  1709 nsCSSStyleSheet::GetOwnerNode(nsIDOMNode** aOwnerNode)
  1711   nsCOMPtr<nsIDOMNode> ownerNode = do_QueryInterface(GetOwnerNode());
  1712   ownerNode.forget(aOwnerNode);
  1713   return NS_OK;
  1716 NS_IMETHODIMP
  1717 nsCSSStyleSheet::GetParentStyleSheet(nsIDOMStyleSheet** aParentStyleSheet)
  1719   NS_ENSURE_ARG_POINTER(aParentStyleSheet);
  1721   NS_IF_ADDREF(*aParentStyleSheet = mParent);
  1723   return NS_OK;
  1726 NS_IMETHODIMP
  1727 nsCSSStyleSheet::GetHref(nsAString& aHref)
  1729   if (mInner->mOriginalSheetURI) {
  1730     nsAutoCString str;
  1731     mInner->mOriginalSheetURI->GetSpec(str);
  1732     CopyUTF8toUTF16(str, aHref);
  1733   } else {
  1734     SetDOMStringToNull(aHref);
  1737   return NS_OK;
  1740 /* virtual */ void
  1741 nsCSSStyleSheet::GetTitle(nsString& aTitle) const
  1743   aTitle = mTitle;
  1746 NS_IMETHODIMP
  1747 nsCSSStyleSheet::GetTitle(nsAString& aTitle)
  1749   aTitle.Assign(mTitle);
  1750   return NS_OK;
  1753 NS_IMETHODIMP
  1754 nsCSSStyleSheet::GetMedia(nsIDOMMediaList** aMedia)
  1756   NS_ADDREF(*aMedia = Media());
  1757   return NS_OK;
  1760 nsMediaList*
  1761 nsCSSStyleSheet::Media()
  1763   if (!mMedia) {
  1764     mMedia = new nsMediaList();
  1765     mMedia->SetStyleSheet(this);
  1768   return mMedia;
  1771 NS_IMETHODIMP    
  1772 nsCSSStyleSheet::GetOwnerRule(nsIDOMCSSRule** aOwnerRule)
  1774   NS_IF_ADDREF(*aOwnerRule = GetOwnerRule());
  1775   return NS_OK;
  1778 nsIDOMCSSRule*
  1779 nsCSSStyleSheet::GetDOMOwnerRule() const
  1781   return mOwnerRule ? mOwnerRule->GetDOMRule() : nullptr;
  1784 NS_IMETHODIMP    
  1785 nsCSSStyleSheet::GetCssRules(nsIDOMCSSRuleList** aCssRules)
  1787   ErrorResult rv;
  1788   nsCOMPtr<nsIDOMCSSRuleList> rules = GetCssRules(rv);
  1789   rules.forget(aCssRules);
  1790   return rv.ErrorCode();
  1793 nsIDOMCSSRuleList*
  1794 nsCSSStyleSheet::GetCssRules(ErrorResult& aRv)
  1796   // No doing this on incomplete sheets!
  1797   if (!mInner->mComplete) {
  1798     aRv.Throw(NS_ERROR_DOM_INVALID_ACCESS_ERR);
  1799     return nullptr;
  1802   //-- Security check: Only scripts whose principal subsumes that of the
  1803   //   style sheet can access rule collections.
  1804   nsresult rv = SubjectSubsumesInnerPrincipal();
  1805   if (NS_FAILED(rv)) {
  1806     aRv.Throw(rv);
  1807     return nullptr;
  1810   // OK, security check passed, so get the rule collection
  1811   if (!mRuleCollection) {
  1812     mRuleCollection = new CSSRuleListImpl(this);
  1815   return mRuleCollection;
  1818 NS_IMETHODIMP    
  1819 nsCSSStyleSheet::InsertRule(const nsAString& aRule, 
  1820                             uint32_t aIndex, 
  1821                             uint32_t* aReturn)
  1823   //-- Security check: Only scripts whose principal subsumes that of the
  1824   //   style sheet can modify rule collections.
  1825   nsresult rv = SubjectSubsumesInnerPrincipal();
  1826   NS_ENSURE_SUCCESS(rv, rv);
  1828   return InsertRuleInternal(aRule, aIndex, aReturn);
  1831 static bool
  1832 RuleHasPendingChildSheet(css::Rule *cssRule)
  1834   nsCOMPtr<nsIDOMCSSImportRule> importRule(do_QueryInterface(cssRule));
  1835   NS_ASSERTION(importRule, "Rule which has type IMPORT_RULE and does not implement nsIDOMCSSImportRule!");
  1836   nsCOMPtr<nsIDOMCSSStyleSheet> childSheet;
  1837   importRule->GetStyleSheet(getter_AddRefs(childSheet));
  1838   nsRefPtr<nsCSSStyleSheet> cssSheet = do_QueryObject(childSheet);
  1839   return cssSheet != nullptr && !cssSheet->IsComplete();
  1842 nsresult
  1843 nsCSSStyleSheet::InsertRuleInternal(const nsAString& aRule, 
  1844                                     uint32_t aIndex, 
  1845                                     uint32_t* aReturn)
  1847   // No doing this if the sheet is not complete!
  1848   if (!mInner->mComplete) {
  1849     return NS_ERROR_DOM_INVALID_ACCESS_ERR;
  1852   WillDirty();
  1854   if (aIndex > uint32_t(mInner->mOrderedRules.Count()))
  1855     return NS_ERROR_DOM_INDEX_SIZE_ERR;
  1857   NS_ASSERTION(uint32_t(mInner->mOrderedRules.Count()) <= INT32_MAX,
  1858                "Too many style rules!");
  1860   // Hold strong ref to the CSSLoader in case the document update
  1861   // kills the document
  1862   nsRefPtr<css::Loader> loader;
  1863   if (mDocument) {
  1864     loader = mDocument->CSSLoader();
  1865     NS_ASSERTION(loader, "Document with no CSS loader!");
  1868   nsCSSParser css(loader, this);
  1870   mozAutoDocUpdate updateBatch(mDocument, UPDATE_STYLE, true);
  1872   nsRefPtr<css::Rule> rule;
  1873   nsresult result = css.ParseRule(aRule, mInner->mSheetURI, mInner->mBaseURI,
  1874                                   mInner->mPrincipal, getter_AddRefs(rule));
  1875   if (NS_FAILED(result))
  1876     return result;
  1878   // Hierarchy checking.
  1879   int32_t newType = rule->GetType();
  1881   // check that we're not inserting before a charset rule
  1882   css::Rule* nextRule = mInner->mOrderedRules.SafeObjectAt(aIndex);
  1883   if (nextRule) {
  1884     int32_t nextType = nextRule->GetType();
  1885     if (nextType == css::Rule::CHARSET_RULE) {
  1886       return NS_ERROR_DOM_HIERARCHY_REQUEST_ERR;
  1889     if (nextType == css::Rule::IMPORT_RULE &&
  1890         newType != css::Rule::CHARSET_RULE &&
  1891         newType != css::Rule::IMPORT_RULE) {
  1892       return NS_ERROR_DOM_HIERARCHY_REQUEST_ERR;
  1895     if (nextType == css::Rule::NAMESPACE_RULE &&
  1896         newType != css::Rule::CHARSET_RULE &&
  1897         newType != css::Rule::IMPORT_RULE &&
  1898         newType != css::Rule::NAMESPACE_RULE) {
  1899       return NS_ERROR_DOM_HIERARCHY_REQUEST_ERR;
  1903   if (aIndex != 0) {
  1904     // no inserting charset at nonzero position
  1905     if (newType == css::Rule::CHARSET_RULE) {
  1906       return NS_ERROR_DOM_HIERARCHY_REQUEST_ERR;
  1909     css::Rule* prevRule = mInner->mOrderedRules.SafeObjectAt(aIndex - 1);
  1910     int32_t prevType = prevRule->GetType();
  1912     if (newType == css::Rule::IMPORT_RULE &&
  1913         prevType != css::Rule::CHARSET_RULE &&
  1914         prevType != css::Rule::IMPORT_RULE) {
  1915       return NS_ERROR_DOM_HIERARCHY_REQUEST_ERR;
  1918     if (newType == css::Rule::NAMESPACE_RULE &&
  1919         prevType != css::Rule::CHARSET_RULE &&
  1920         prevType != css::Rule::IMPORT_RULE &&
  1921         prevType != css::Rule::NAMESPACE_RULE) {
  1922       return NS_ERROR_DOM_HIERARCHY_REQUEST_ERR;
  1926   bool insertResult = mInner->mOrderedRules.InsertObjectAt(rule, aIndex);
  1927   NS_ENSURE_TRUE(insertResult, NS_ERROR_OUT_OF_MEMORY);
  1928   DidDirty();
  1930   rule->SetStyleSheet(this);
  1932   int32_t type = rule->GetType();
  1933   if (type == css::Rule::NAMESPACE_RULE) {
  1934     // XXXbz does this screw up when inserting a namespace rule before
  1935     // another namespace rule that binds the same prefix to a different
  1936     // namespace?
  1937     result = RegisterNamespaceRule(rule);
  1938     NS_ENSURE_SUCCESS(result, result);
  1941   // We don't notify immediately for @import rules, but rather when
  1942   // the sheet the rule is importing is loaded (see StyleSheetLoaded)
  1943   if ((type != css::Rule::IMPORT_RULE || !RuleHasPendingChildSheet(rule)) &&
  1944       mDocument) {
  1945     mDocument->StyleRuleAdded(this, rule);
  1948   *aReturn = aIndex;
  1949   return NS_OK;
  1952 NS_IMETHODIMP    
  1953 nsCSSStyleSheet::DeleteRule(uint32_t aIndex)
  1955   // No doing this if the sheet is not complete!
  1956   if (!mInner->mComplete) {
  1957     return NS_ERROR_DOM_INVALID_ACCESS_ERR;
  1960   //-- Security check: Only scripts whose principal subsumes that of the
  1961   //   style sheet can modify rule collections.
  1962   nsresult rv = SubjectSubsumesInnerPrincipal();
  1963   NS_ENSURE_SUCCESS(rv, rv);
  1965   // XXX TBI: handle @rule types
  1966   mozAutoDocUpdate updateBatch(mDocument, UPDATE_STYLE, true);
  1968   WillDirty();
  1970   if (aIndex >= uint32_t(mInner->mOrderedRules.Count()))
  1971     return NS_ERROR_DOM_INDEX_SIZE_ERR;
  1973   NS_ASSERTION(uint32_t(mInner->mOrderedRules.Count()) <= INT32_MAX,
  1974                "Too many style rules!");
  1976   // Hold a strong ref to the rule so it doesn't die when we RemoveObjectAt
  1977   nsRefPtr<css::Rule> rule = mInner->mOrderedRules.ObjectAt(aIndex);
  1978   if (rule) {
  1979     mInner->mOrderedRules.RemoveObjectAt(aIndex);
  1980     if (mDocument && mDocument->StyleSheetChangeEventsEnabled()) {
  1981       // Force creation of the DOM rule, so that it can be put on the
  1982       // StyleRuleRemoved event object.
  1983       rule->GetDOMRule();
  1985     rule->SetStyleSheet(nullptr);
  1986     DidDirty();
  1988     if (mDocument) {
  1989       mDocument->StyleRuleRemoved(this, rule);
  1993   return NS_OK;
  1996 nsresult
  1997 nsCSSStyleSheet::DeleteRuleFromGroup(css::GroupRule* aGroup, uint32_t aIndex)
  1999   NS_ENSURE_ARG_POINTER(aGroup);
  2000   NS_ASSERTION(mInner->mComplete, "No deleting from an incomplete sheet!");
  2001   nsRefPtr<css::Rule> rule = aGroup->GetStyleRuleAt(aIndex);
  2002   NS_ENSURE_TRUE(rule, NS_ERROR_ILLEGAL_VALUE);
  2004   // check that the rule actually belongs to this sheet!
  2005   if (this != rule->GetStyleSheet()) {
  2006     return NS_ERROR_INVALID_ARG;
  2009   mozAutoDocUpdate updateBatch(mDocument, UPDATE_STYLE, true);
  2011   WillDirty();
  2013   nsresult result = aGroup->DeleteStyleRuleAt(aIndex);
  2014   NS_ENSURE_SUCCESS(result, result);
  2016   rule->SetStyleSheet(nullptr);
  2018   DidDirty();
  2020   if (mDocument) {
  2021     mDocument->StyleRuleRemoved(this, rule);
  2024   return NS_OK;
  2027 nsresult
  2028 nsCSSStyleSheet::InsertRuleIntoGroup(const nsAString & aRule,
  2029                                      css::GroupRule* aGroup,
  2030                                      uint32_t aIndex,
  2031                                      uint32_t* _retval)
  2033   NS_ASSERTION(mInner->mComplete, "No inserting into an incomplete sheet!");
  2034   // check that the group actually belongs to this sheet!
  2035   if (this != aGroup->GetStyleSheet()) {
  2036     return NS_ERROR_INVALID_ARG;
  2039   // Hold strong ref to the CSSLoader in case the document update
  2040   // kills the document
  2041   nsRefPtr<css::Loader> loader;
  2042   if (mDocument) {
  2043     loader = mDocument->CSSLoader();
  2044     NS_ASSERTION(loader, "Document with no CSS loader!");
  2047   nsCSSParser css(loader, this);
  2049   // parse and grab the rule
  2050   mozAutoDocUpdate updateBatch(mDocument, UPDATE_STYLE, true);
  2052   WillDirty();
  2054   nsRefPtr<css::Rule> rule;
  2055   nsresult result = css.ParseRule(aRule, mInner->mSheetURI, mInner->mBaseURI,
  2056                                   mInner->mPrincipal, getter_AddRefs(rule));
  2057   if (NS_FAILED(result))
  2058     return result;
  2060   switch (rule->GetType()) {
  2061     case css::Rule::STYLE_RULE:
  2062     case css::Rule::MEDIA_RULE:
  2063     case css::Rule::FONT_FACE_RULE:
  2064     case css::Rule::PAGE_RULE:
  2065     case css::Rule::KEYFRAMES_RULE:
  2066     case css::Rule::DOCUMENT_RULE:
  2067     case css::Rule::SUPPORTS_RULE:
  2068       // these types are OK to insert into a group
  2069       break;
  2070     case css::Rule::CHARSET_RULE:
  2071     case css::Rule::IMPORT_RULE:
  2072     case css::Rule::NAMESPACE_RULE:
  2073       // these aren't
  2074       return NS_ERROR_DOM_HIERARCHY_REQUEST_ERR;
  2075     default:
  2076       NS_NOTREACHED("unexpected rule type");
  2077       return NS_ERROR_DOM_HIERARCHY_REQUEST_ERR;
  2080   result = aGroup->InsertStyleRuleAt(aIndex, rule);
  2081   NS_ENSURE_SUCCESS(result, result);
  2082   DidDirty();
  2084   if (mDocument) {
  2085     mDocument->StyleRuleAdded(this, rule);
  2088   *_retval = aIndex;
  2089   return NS_OK;
  2092 nsresult
  2093 nsCSSStyleSheet::ReplaceRuleInGroup(css::GroupRule* aGroup,
  2094                                     css::Rule* aOld, css::Rule* aNew)
  2096   NS_PRECONDITION(mInner->mComplete, "No replacing in an incomplete sheet!");
  2097   NS_ASSERTION(this == aGroup->GetStyleSheet(), "group doesn't belong to this sheet");
  2099   WillDirty();
  2101   nsresult result = aGroup->ReplaceStyleRule(aOld, aNew);
  2102   DidDirty();
  2103   return result;
  2106 // nsICSSLoaderObserver implementation
  2107 NS_IMETHODIMP
  2108 nsCSSStyleSheet::StyleSheetLoaded(nsCSSStyleSheet* aSheet,
  2109                                   bool aWasAlternate,
  2110                                   nsresult aStatus)
  2112   if (aSheet->GetParentSheet() == nullptr) {
  2113     return NS_OK; // ignore if sheet has been detached already (see parseSheet)
  2115   NS_ASSERTION(this == aSheet->GetParentSheet(),
  2116                "We are being notified of a sheet load for a sheet that is not our child!");
  2118   if (mDocument && NS_SUCCEEDED(aStatus)) {
  2119     mozAutoDocUpdate updateBatch(mDocument, UPDATE_STYLE, true);
  2121     // XXXldb @import rules shouldn't even implement nsIStyleRule (but
  2122     // they do)!
  2123     mDocument->StyleRuleAdded(this, aSheet->GetOwnerRule());
  2126   return NS_OK;
  2129 nsresult
  2130 nsCSSStyleSheet::ParseSheet(const nsAString& aInput)
  2132   // Not doing this if the sheet is not complete!
  2133   if (!mInner->mComplete) {
  2134     return NS_ERROR_DOM_INVALID_ACCESS_ERR;
  2137   // Hold strong ref to the CSSLoader in case the document update
  2138   // kills the document
  2139   nsRefPtr<css::Loader> loader;
  2140   if (mDocument) {
  2141     loader = mDocument->CSSLoader();
  2142     NS_ASSERTION(loader, "Document with no CSS loader!");
  2143   } else {
  2144     loader = new css::Loader();
  2147   mozAutoDocUpdate updateBatch(mDocument, UPDATE_STYLE, true);
  2149   WillDirty();
  2151   // detach existing rules (including child sheets via import rules)
  2152   int ruleCount;
  2153   while ((ruleCount = mInner->mOrderedRules.Count()) != 0) {
  2154     nsRefPtr<css::Rule> rule = mInner->mOrderedRules.ObjectAt(ruleCount - 1);
  2155     mInner->mOrderedRules.RemoveObjectAt(ruleCount - 1);
  2156     rule->SetStyleSheet(nullptr);
  2157     if (mDocument) {
  2158       mDocument->StyleRuleRemoved(this, rule);
  2162   // nuke child sheets list and current namespace map
  2163   for (nsCSSStyleSheet* child = mInner->mFirstChild; child; child = child->mNext) {
  2164     NS_ASSERTION(child->mParent == this, "Child sheet is not parented to this!");
  2165     child->mParent = nullptr;
  2166     child->mDocument = nullptr;
  2168   mInner->mFirstChild = nullptr;
  2169   mInner->mNameSpaceMap = nullptr;
  2171   // allow unsafe rules if the style sheet's principal is the system principal
  2172   bool allowUnsafeRules = nsContentUtils::IsSystemPrincipal(mInner->mPrincipal);
  2174   nsCSSParser parser(loader, this);
  2175   nsresult rv = parser.ParseSheet(aInput, mInner->mSheetURI, mInner->mBaseURI,
  2176                                   mInner->mPrincipal, 1, allowUnsafeRules);
  2177   DidDirty(); // we are always 'dirty' here since we always remove rules first
  2178   NS_ENSURE_SUCCESS(rv, rv);
  2180   // notify document of all new rules
  2181   if (mDocument) {
  2182     for (int32_t index = 0; index < mInner->mOrderedRules.Count(); ++index) {
  2183       nsRefPtr<css::Rule> rule = mInner->mOrderedRules.ObjectAt(index);
  2184       if (rule->GetType() == css::Rule::IMPORT_RULE &&
  2185           RuleHasPendingChildSheet(rule)) {
  2186         continue; // notify when loaded (see StyleSheetLoaded)
  2188       mDocument->StyleRuleAdded(this, rule);
  2191   return NS_OK;
  2194 /* virtual */ nsIURI*
  2195 nsCSSStyleSheet::GetOriginalURI() const
  2197   return mInner->mOriginalSheetURI;
  2200 /* virtual */
  2201 JSObject*
  2202 nsCSSStyleSheet::WrapObject(JSContext* aCx)
  2204   return CSSStyleSheetBinding::Wrap(aCx, this);

mercurial