LCOV - code coverage report
Current view: top level - layout/style - CSSStyleSheet.cpp (source / functions) Hit Total Coverage
Test: output.info Lines: 130 414 31.4 %
Date: 2017-07-14 16:53:18 Functions: 23 54 42.6 %
Legend: Lines: hit not hit

          Line data    Source code
       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/. */
       6             : 
       7             : /* representation of a CSS style sheet */
       8             : 
       9             : #include "mozilla/CSSStyleSheet.h"
      10             : 
      11             : #include "nsIAtom.h"
      12             : #include "nsCSSRuleProcessor.h"
      13             : #include "mozilla/MemoryReporting.h"
      14             : #include "mozilla/dom/Element.h"
      15             : #include "mozilla/css/NameSpaceRule.h"
      16             : #include "mozilla/css/GroupRule.h"
      17             : #include "mozilla/css/ImportRule.h"
      18             : #include "nsCSSRules.h"
      19             : #include "nsMediaList.h"
      20             : #include "nsIDocument.h"
      21             : #include "nsPresContext.h"
      22             : #include "nsGkAtoms.h"
      23             : #include "nsQueryObject.h"
      24             : #include "nsString.h"
      25             : #include "nsStyleSet.h"
      26             : #include "nsTArray.h"
      27             : #include "nsIDOMCSSStyleSheet.h"
      28             : #include "mozilla/dom/CSSRuleList.h"
      29             : #include "nsIDOMMediaList.h"
      30             : #include "nsIDOMNode.h"
      31             : #include "nsError.h"
      32             : #include "nsCSSParser.h"
      33             : #include "mozilla/css/Loader.h"
      34             : #include "nsNameSpaceManager.h"
      35             : #include "nsXMLNameSpaceMap.h"
      36             : #include "nsCOMPtr.h"
      37             : #include "nsContentUtils.h"
      38             : #include "nsIScriptSecurityManager.h"
      39             : #include "mozAutoDocUpdate.h"
      40             : #include "nsRuleNode.h"
      41             : #include "nsMediaFeatures.h"
      42             : #include "nsDOMClassInfoID.h"
      43             : #include "mozilla/Likely.h"
      44             : #include "nsComponentManagerUtils.h"
      45             : #include "NullPrincipal.h"
      46             : #include "mozilla/RuleProcessorCache.h"
      47             : #include "nsIStyleSheetLinkingElement.h"
      48             : #include "nsDOMWindowUtils.h"
      49             : 
      50             : using namespace mozilla;
      51             : using namespace mozilla::dom;
      52             : 
      53             : // -------------------------------
      54             : // Style Rule List for the DOM
      55             : //
      56             : class CSSRuleListImpl final : public CSSRuleList
      57             : {
      58             : public:
      59             :   explicit CSSRuleListImpl(CSSStyleSheet *aStyleSheet);
      60             : 
      61             :   virtual CSSStyleSheet* GetParentObject() override;
      62             : 
      63             :   virtual css::Rule*
      64             :   IndexedGetter(uint32_t aIndex, bool& aFound) override;
      65             :   virtual uint32_t
      66             :   Length() override;
      67             : 
      68           0 :   void DropReference() { mStyleSheet = nullptr; }
      69             : 
      70             : protected:
      71             :   virtual ~CSSRuleListImpl();
      72             : 
      73             :   CSSStyleSheet*  mStyleSheet;
      74             : };
      75             : 
      76           0 : CSSRuleListImpl::CSSRuleListImpl(CSSStyleSheet *aStyleSheet)
      77             : {
      78             :   // Not reference counted to avoid circular references.
      79             :   // The style sheet will tell us when its going away.
      80           0 :   mStyleSheet = aStyleSheet;
      81           0 : }
      82             : 
      83           0 : CSSRuleListImpl::~CSSRuleListImpl()
      84             : {
      85           0 : }
      86             : 
      87             : CSSStyleSheet*
      88           0 : CSSRuleListImpl::GetParentObject()
      89             : {
      90           0 :   return mStyleSheet;
      91             : }
      92             : 
      93             : uint32_t
      94           0 : CSSRuleListImpl::Length()
      95             : {
      96           0 :   if (!mStyleSheet) {
      97           0 :     return 0;
      98             :   }
      99             : 
     100           0 :   return AssertedCast<uint32_t>(mStyleSheet->StyleRuleCount());
     101             : }
     102             : 
     103             : css::Rule*
     104           0 : CSSRuleListImpl::IndexedGetter(uint32_t aIndex, bool& aFound)
     105             : {
     106           0 :   aFound = false;
     107             : 
     108           0 :   if (mStyleSheet) {
     109             :     // ensure rules have correct parent
     110           0 :     mStyleSheet->EnsureUniqueInner();
     111           0 :     css::Rule* rule = mStyleSheet->GetStyleRuleAt(aIndex);
     112           0 :     if (rule) {
     113           0 :       aFound = true;
     114           0 :       return rule;
     115             :     }
     116             :   }
     117             : 
     118             :   // Per spec: "Return Value ... null if ... not a valid index."
     119           0 :   return nullptr;
     120             : }
     121             : 
     122             : namespace mozilla {
     123             : 
     124             : // -------------------------------
     125             : // CSS Style Sheet Inner Data Container
     126             : //
     127             : 
     128             : 
     129          60 : CSSStyleSheetInner::CSSStyleSheetInner(CORSMode aCORSMode,
     130             :                                        ReferrerPolicy aReferrerPolicy,
     131          60 :                                        const SRIMetadata& aIntegrity)
     132          60 :   : StyleSheetInfo(aCORSMode, aReferrerPolicy, aIntegrity)
     133             : {
     134          60 :   MOZ_COUNT_CTOR(CSSStyleSheetInner);
     135          60 : }
     136             : 
     137             : bool
     138           0 : CSSStyleSheet::RebuildChildList(css::Rule* aRule,
     139             :                                 ChildSheetListBuilder* aBuilder)
     140             : {
     141           0 :   int32_t type = aRule->GetType();
     142           0 :   if (type < css::Rule::IMPORT_RULE) {
     143             :     // Keep going till we get to the import rules.
     144           0 :     return true;
     145             :   }
     146             : 
     147           0 :   if (type != css::Rule::IMPORT_RULE) {
     148             :     // We're past all the import rules; stop the enumeration.
     149           0 :     return false;
     150             :   }
     151             : 
     152             :   // XXXbz We really need to decomtaminate all this stuff.  Is there a reason
     153             :   // that I can't just QI to ImportRule and get a CSSStyleSheet
     154             :   // directly from it?
     155           0 :   nsCOMPtr<nsIDOMCSSImportRule> importRule(do_QueryInterface(aRule));
     156           0 :   NS_ASSERTION(importRule, "GetType lied");
     157             : 
     158           0 :   nsCOMPtr<nsIDOMCSSStyleSheet> childSheet;
     159           0 :   importRule->GetStyleSheet(getter_AddRefs(childSheet));
     160             : 
     161             :   // Have to do this QI to be safe, since XPConnect can fake
     162             :   // nsIDOMCSSStyleSheets
     163           0 :   RefPtr<CSSStyleSheet> sheet = do_QueryObject(childSheet);
     164           0 :   if (!sheet) {
     165           0 :     return true;
     166             :   }
     167             : 
     168           0 :   (*aBuilder->sheetSlot) = sheet;
     169           0 :   aBuilder->SetParentLinks(*aBuilder->sheetSlot);
     170           0 :   aBuilder->sheetSlot = &(*aBuilder->sheetSlot)->mNext;
     171           0 :   return true;
     172             : }
     173             : 
     174             : size_t
     175           5 : CSSStyleSheet::SizeOfIncludingThis(MallocSizeOf aMallocSizeOf) const
     176             : {
     177           5 :   size_t n = StyleSheet::SizeOfIncludingThis(aMallocSizeOf);
     178           5 :   const CSSStyleSheet* s = this;
     179          15 :   while (s) {
     180             :     // Each inner can be shared by multiple sheets.  So we only count the inner
     181             :     // if this sheet is the last one in the list of those sharing it.  As a
     182             :     // result, the last such sheet takes all the blame for the memory
     183             :     // consumption of the inner, which isn't ideal but it's better than
     184             :     // double-counting the inner.  We use last instead of first since the first
     185             :     // sheet may be held in the nsXULPrototypeCache and not used in a window at
     186             :     // all.
     187           5 :     if (s->Inner()->mSheets.LastElement() == s) {
     188           5 :       n += s->Inner()->SizeOfIncludingThis(aMallocSizeOf);
     189             :     }
     190             : 
     191             :     // Measurement of the following members may be added later if DMD finds it
     192             :     // is worthwhile:
     193             :     // - s->mRuleCollection
     194             :     // - s->mRuleProcessors
     195             :     //
     196             :     // The following members are not measured:
     197             :     // - s->mOwnerRule, because it's non-owning
     198             :     // - s->mScopeElement, because it's non-owning
     199             : 
     200           5 :     s = s->mNext ? s->mNext->AsGecko() : nullptr;
     201             :   }
     202           5 :   return n;
     203             : }
     204             : 
     205           0 : CSSStyleSheetInner::CSSStyleSheetInner(CSSStyleSheetInner& aCopy,
     206           0 :                                        CSSStyleSheet* aPrimarySheet)
     207           0 :   : StyleSheetInfo(aCopy, aPrimarySheet)
     208             : {
     209           0 :   MOZ_COUNT_CTOR(CSSStyleSheetInner);
     210           0 :   for (css::Rule* rule : aCopy.mOrderedRules) {
     211           0 :     RefPtr<css::Rule> clone = rule->Clone();
     212           0 :     mOrderedRules.AppendObject(clone);
     213           0 :     clone->SetStyleSheet(aPrimarySheet);
     214             :   }
     215             : 
     216           0 :   StyleSheet::ChildSheetListBuilder builder = { &mFirstChild, aPrimarySheet };
     217           0 :   for (css::Rule* rule : mOrderedRules) {
     218           0 :     if (!CSSStyleSheet::RebuildChildList(rule, &builder)) {
     219           0 :       break;
     220             :     }
     221             :   }
     222             : 
     223           0 :   RebuildNameSpaces();
     224           0 : }
     225             : 
     226           0 : CSSStyleSheetInner::~CSSStyleSheetInner()
     227             : {
     228           0 :   MOZ_COUNT_DTOR(CSSStyleSheetInner);
     229           0 :   for (css::Rule* rule : mOrderedRules) {
     230           0 :     rule->SetStyleSheet(nullptr);
     231             :   }
     232           0 : }
     233             : 
     234             : StyleSheetInfo*
     235           0 : CSSStyleSheetInner::CloneFor(StyleSheet* aPrimarySheet)
     236             : {
     237             :   return new CSSStyleSheetInner(*this,
     238           0 :                                 static_cast<CSSStyleSheet*>(aPrimarySheet));
     239             : }
     240             : 
     241             : void
     242           0 : CSSStyleSheetInner::RemoveSheet(StyleSheet* aSheet)
     243             : {
     244           0 :   if (aSheet == mSheets.ElementAt(0) && mSheets.Length() > 1) {
     245           0 :     StyleSheet* sheet = mSheets[1];
     246           0 :     for (css::Rule* rule : mOrderedRules) {
     247           0 :       rule->SetStyleSheet(sheet);
     248             :     }
     249             :   }
     250             : 
     251             :   // Don't do anything after this call, because superclass implementation
     252             :   // may delete this.
     253           0 :   StyleSheetInfo::RemoveSheet(aSheet);
     254           0 : }
     255             : 
     256             : static void
     257          64 : AddNamespaceRuleToMap(css::Rule* aRule, nsXMLNameSpaceMap* aMap)
     258             : {
     259          64 :   NS_ASSERTION(aRule->GetType() == css::Rule::NAMESPACE_RULE, "Bogus rule type");
     260             : 
     261         128 :   RefPtr<css::NameSpaceRule> nameSpaceRule = do_QueryObject(aRule);
     262             : 
     263         128 :   nsAutoString  urlSpec;
     264          64 :   nameSpaceRule->GetURLSpec(urlSpec);
     265             : 
     266          64 :   aMap->AddPrefix(nameSpaceRule->GetPrefix(), urlSpec);
     267          64 : }
     268             : 
     269             : void
     270           0 : CSSStyleSheetInner::RebuildNameSpaces()
     271             : {
     272             :   // Just nuke our existing namespace map, if any
     273           0 :   if (NS_SUCCEEDED(CreateNamespaceMap())) {
     274           0 :     for (css::Rule* rule : mOrderedRules) {
     275           0 :       switch (rule->GetType()) {
     276             :         case css::Rule::NAMESPACE_RULE:
     277           0 :           AddNamespaceRuleToMap(rule, mNameSpaceMap);
     278           0 :           continue;
     279             :         case css::Rule::CHARSET_RULE:
     280             :         case css::Rule::IMPORT_RULE:
     281           0 :           continue;
     282             :       }
     283           0 :       break;
     284             :     }
     285             :   }
     286           0 : }
     287             : 
     288             : nsresult
     289          39 : CSSStyleSheetInner::CreateNamespaceMap()
     290             : {
     291          39 :   mNameSpaceMap = nsXMLNameSpaceMap::Create(false);
     292          39 :   NS_ENSURE_TRUE(mNameSpaceMap, NS_ERROR_OUT_OF_MEMORY);
     293             :   // Override the default namespace map behavior for the null prefix to
     294             :   // return the wildcard namespace instead of the null namespace.
     295          39 :   mNameSpaceMap->AddPrefix(nullptr, kNameSpaceID_Unknown);
     296          39 :   return NS_OK;
     297             : }
     298             : 
     299             : size_t
     300           5 : CSSStyleSheetInner::SizeOfIncludingThis(MallocSizeOf aMallocSizeOf) const
     301             : {
     302           5 :   size_t n = aMallocSizeOf(this);
     303           5 :   n += mOrderedRules.ShallowSizeOfExcludingThis(aMallocSizeOf);
     304          19 :   for (size_t i = 0; i < mOrderedRules.Length(); i++) {
     305          14 :     n += mOrderedRules[i]->SizeOfIncludingThis(aMallocSizeOf);
     306             :   }
     307           5 :   n += mFirstChild ? mFirstChild->SizeOfIncludingThis(aMallocSizeOf) : 0;
     308             : 
     309             :   // Measurement of the following members may be added later if DMD finds it is
     310             :   // worthwhile:
     311             :   // - mSheetURI
     312             :   // - mOriginalSheetURI
     313             :   // - mBaseURI
     314             :   // - mPrincipal
     315             :   // - mNameSpaceMap
     316             :   //
     317             :   // The following members are not measured:
     318             :   // - mSheets, because it's non-owning
     319             : 
     320           5 :   return n;
     321             : }
     322             : 
     323             : // -------------------------------
     324             : // CSS Style Sheet
     325             : //
     326             : 
     327           2 : CSSStyleSheet::CSSStyleSheet(css::SheetParsingMode aParsingMode,
     328           2 :                              CORSMode aCORSMode, ReferrerPolicy aReferrerPolicy)
     329             :   : StyleSheet(StyleBackendType::Gecko, aParsingMode),
     330             :     mInRuleProcessorCache(false),
     331             :     mScopeElement(nullptr),
     332           2 :     mRuleProcessors(nullptr)
     333             : {
     334           2 :   mInner = new CSSStyleSheetInner(aCORSMode, aReferrerPolicy,
     335           6 :                                   SRIMetadata());
     336           2 :   mInner->AddSheet(this);
     337           2 : }
     338             : 
     339          58 : CSSStyleSheet::CSSStyleSheet(css::SheetParsingMode aParsingMode,
     340             :                              CORSMode aCORSMode,
     341             :                              ReferrerPolicy aReferrerPolicy,
     342          58 :                              const SRIMetadata& aIntegrity)
     343             :   : StyleSheet(StyleBackendType::Gecko, aParsingMode),
     344             :     mInRuleProcessorCache(false),
     345             :     mScopeElement(nullptr),
     346          58 :     mRuleProcessors(nullptr)
     347             : {
     348          58 :   mInner = new CSSStyleSheetInner(aCORSMode, aReferrerPolicy,
     349          58 :                                   aIntegrity);
     350          58 :   mInner->AddSheet(this);
     351          58 : }
     352             : 
     353          15 : CSSStyleSheet::CSSStyleSheet(const CSSStyleSheet& aCopy,
     354             :                              CSSStyleSheet* aParentToUse,
     355             :                              dom::CSSImportRule* aOwnerRuleToUse,
     356             :                              nsIDocument* aDocumentToUse,
     357          15 :                              nsINode* aOwningNodeToUse)
     358             :   : StyleSheet(aCopy,
     359             :                aParentToUse,
     360             :                aOwnerRuleToUse,
     361             :                aDocumentToUse,
     362             :                aOwningNodeToUse)
     363             :   , mInRuleProcessorCache(false)
     364             :   , mScopeElement(nullptr)
     365          15 :   , mRuleProcessors(nullptr)
     366             : {
     367          15 :   if (mDirty) { // CSSOM's been there, force full copy now
     368           0 :     NS_ASSERTION(mInner->mComplete,
     369             :                  "Why have rules been accessed on an incomplete sheet?");
     370             :     // FIXME: handle failure?
     371             :     //
     372             :     // NOTE: It's important to call this from the subclass, since it could
     373             :     // access uninitialized members otherwise.
     374           0 :     EnsureUniqueInner();
     375             :   }
     376          15 : }
     377             : 
     378           0 : CSSStyleSheet::~CSSStyleSheet()
     379             : {
     380           0 : }
     381             : 
     382             : void
     383           0 : CSSStyleSheet::LastRelease()
     384             : {
     385           0 :   DropRuleCollection();
     386             :   // XXX The document reference is not reference counted and should
     387             :   // not be released. The document will let us know when it is going
     388             :   // away.
     389           0 :   if (mRuleProcessors) {
     390           0 :     NS_ASSERTION(mRuleProcessors->Length() == 0, "destructing sheet with rule processor reference");
     391           0 :     delete mRuleProcessors; // weak refs, should be empty here anyway
     392           0 :     mRuleProcessors = nullptr;
     393             :   }
     394           0 :   if (mInRuleProcessorCache) {
     395           0 :     RuleProcessorCache::RemoveSheet(this);
     396             :   }
     397           0 : }
     398             : 
     399             : void
     400           0 : CSSStyleSheet::DropRuleCollection()
     401             : {
     402           0 :   if (mRuleCollection) {
     403           0 :     mRuleCollection->DropReference();
     404           0 :     mRuleCollection = nullptr;
     405             :   }
     406           0 : }
     407             : 
     408             : void
     409           0 : CSSStyleSheet::UnlinkInner()
     410             : {
     411             :   // We can only have a cycle through our inner if we have a unique inner,
     412             :   // because otherwise there are no JS wrappers for anything in the inner.
     413           0 :   if (mInner->mSheets.Length() != 1) {
     414           0 :     return;
     415             :   }
     416             : 
     417           0 :   for (css::Rule* rule : Inner()->mOrderedRules) {
     418           0 :     rule->SetStyleSheet(nullptr);
     419             :   }
     420           0 :   Inner()->mOrderedRules.Clear();
     421             : 
     422           0 :   StyleSheet::UnlinkInner();
     423             : }
     424             : 
     425             : void
     426           0 : CSSStyleSheet::TraverseInner(nsCycleCollectionTraversalCallback &cb)
     427             : {
     428             :   // We can only have a cycle through our inner if we have a unique inner,
     429             :   // because otherwise there are no JS wrappers for anything in the inner.
     430           0 :   if (mInner->mSheets.Length() != 1) {
     431           0 :     return;
     432             :   }
     433             : 
     434           0 :   const nsCOMArray<css::Rule>& rules = Inner()->mOrderedRules;
     435           0 :   for (int32_t i = 0, count = rules.Count(); i < count; ++i) {
     436           0 :     if (!rules[i]->IsCCLeaf()) {
     437           0 :       NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(cb, "mOrderedRules[i]");
     438           0 :       cb.NoteXPCOMChild(rules[i]);
     439             :     }
     440             :   }
     441             : 
     442           0 :   StyleSheet::TraverseInner(cb);
     443             : }
     444             : 
     445             : // QueryInterface implementation for CSSStyleSheet
     446          75 : NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION_INHERITED(CSSStyleSheet)
     447           0 :   NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIDOMCSSStyleSheet)
     448           0 :   if (aIID.Equals(NS_GET_IID(CSSStyleSheet)))
     449           0 :     foundInterface = reinterpret_cast<nsISupports*>(this);
     450             :   else
     451           0 : NS_INTERFACE_MAP_END_INHERITING(StyleSheet)
     452             : 
     453         776 : NS_IMPL_ADDREF_INHERITED(CSSStyleSheet, StyleSheet)
     454         410 : NS_IMPL_RELEASE_INHERITED(CSSStyleSheet, StyleSheet)
     455             : 
     456             : NS_IMPL_CYCLE_COLLECTION_CLASS(CSSStyleSheet)
     457             : 
     458           0 : NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(CSSStyleSheet)
     459             :   // We do not unlink mNext; our parent will handle that.  If we
     460             :   // unlinked it here, our parent would not be able to walk its list
     461             :   // of child sheets and null out the back-references to it, if we got
     462             :   // unlinked before it does.
     463           0 :   tmp->DropRuleCollection();
     464           0 :   tmp->mScopeElement = nullptr;
     465           0 : NS_IMPL_CYCLE_COLLECTION_UNLINK_END_INHERITED(StyleSheet)
     466           0 : NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(CSSStyleSheet, StyleSheet)
     467             :   // We do not traverse mNext; our parent will handle that.  See
     468             :   // comments in Unlink for why.
     469           0 :   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mRuleCollection)
     470           0 :   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mScopeElement)
     471           0 : NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
     472             : 
     473             : nsresult
     474         144 : CSSStyleSheet::AddRuleProcessor(nsCSSRuleProcessor* aProcessor)
     475             : {
     476         144 :   if (! mRuleProcessors) {
     477          70 :     mRuleProcessors = new AutoTArray<nsCSSRuleProcessor*, 8>();
     478          70 :     if (!mRuleProcessors)
     479           0 :       return NS_ERROR_OUT_OF_MEMORY;
     480             :   }
     481         144 :   NS_ASSERTION(mRuleProcessors->NoIndex == mRuleProcessors->IndexOf(aProcessor),
     482             :                "processor already registered");
     483         144 :   mRuleProcessors->AppendElement(aProcessor); // weak ref
     484         144 :   return NS_OK;
     485             : }
     486             : 
     487             : nsresult
     488          31 : CSSStyleSheet::DropRuleProcessor(nsCSSRuleProcessor* aProcessor)
     489             : {
     490          31 :   if (!mRuleProcessors)
     491           0 :     return NS_ERROR_FAILURE;
     492          31 :   return mRuleProcessors->RemoveElement(aProcessor)
     493          31 :            ? NS_OK
     494          31 :            : NS_ERROR_FAILURE;
     495             : }
     496             : 
     497             : bool
     498         144 : CSSStyleSheet::UseForPresentation(nsPresContext* aPresContext,
     499             :                                   nsMediaQueryResultCacheKey& aKey) const
     500             : {
     501         144 :   if (mMedia) {
     502           8 :     MOZ_ASSERT(aPresContext);
     503           8 :     auto media = static_cast<nsMediaList*>(mMedia.get());
     504           8 :     return media->Matches(aPresContext, &aKey);
     505             :   }
     506         136 :   return true;
     507             : }
     508             : 
     509             : 
     510             : bool
     511         161 : CSSStyleSheet::HasRules() const
     512             : {
     513         161 :   return StyleRuleCount() != 0;
     514             : }
     515             : 
     516             : void
     517           0 : CSSStyleSheet::EnabledStateChangedInternal()
     518             : {
     519           0 :   ClearRuleCascades();
     520           0 : }
     521             : 
     522             : void
     523        3074 : CSSStyleSheet::AppendStyleRule(css::Rule* aRule)
     524             : {
     525        3074 :   NS_PRECONDITION(nullptr != aRule, "null arg");
     526             : 
     527        3074 :   WillDirty();
     528        3074 :   Inner()->mOrderedRules.AppendObject(aRule);
     529        3074 :   aRule->SetStyleSheet(this);
     530        3074 :   DidDirty();
     531             : 
     532        3074 :   if (css::Rule::NAMESPACE_RULE == aRule->GetType()) {
     533             : #ifdef DEBUG
     534             :     nsresult rv =
     535             : #endif
     536          64 :       RegisterNamespaceRule(aRule);
     537          64 :     NS_WARNING_ASSERTION(NS_SUCCEEDED(rv),
     538             :                          "RegisterNamespaceRule returned error");
     539             :   }
     540        3074 : }
     541             : 
     542             : int32_t
     543         221 : CSSStyleSheet::StyleRuleCount() const
     544             : {
     545         221 :   return Inner()->mOrderedRules.Count();
     546             : }
     547             : 
     548             : css::Rule*
     549           0 : CSSStyleSheet::GetStyleRuleAt(int32_t aIndex) const
     550             : {
     551             :   // Important: If this function is ever made scriptable, we must add
     552             :   // a security check here. See GetCssRules below for an example.
     553           0 :   return Inner()->mOrderedRules.SafeObjectAt(aIndex);
     554             : }
     555             : 
     556             : already_AddRefed<StyleSheet>
     557          15 : CSSStyleSheet::Clone(StyleSheet* aCloneParent,
     558             :                      dom::CSSImportRule* aCloneOwnerRule,
     559             :                      nsIDocument* aCloneDocument,
     560             :                      nsINode* aCloneOwningNode) const
     561             : {
     562             :   RefPtr<StyleSheet> clone = new CSSStyleSheet(*this,
     563             :     static_cast<CSSStyleSheet*>(aCloneParent),
     564             :     aCloneOwnerRule,
     565             :     aCloneDocument,
     566          30 :     aCloneOwningNode);
     567          30 :   return clone.forget();
     568             : }
     569             : 
     570             : #ifdef DEBUG
     571             : static void
     572           0 : ListRules(const nsCOMArray<css::Rule>& aRules, FILE* aOut, int32_t aIndent)
     573             : {
     574           0 :   for (int32_t index = aRules.Count() - 1; index >= 0; --index) {
     575           0 :     aRules.ObjectAt(index)->List(aOut, aIndent);
     576             :   }
     577           0 : }
     578             : 
     579             : void
     580           0 : CSSStyleSheet::List(FILE* out, int32_t aIndent) const
     581             : {
     582           0 :   StyleSheet::List(out, aIndent);
     583             : 
     584           0 :   fprintf_stderr(out, "%s", "Rules in source order:\n");
     585           0 :   ListRules(Inner()->mOrderedRules, out, aIndent);
     586           0 : }
     587             : #endif
     588             : 
     589             : void
     590        3152 : CSSStyleSheet::ClearRuleCascades()
     591             : {
     592             :   // We might be in ClearRuleCascadesInternal because we had a modification
     593             :   // to the sheet that resulted in an nsCSSSelector being destroyed.
     594             :   // Tell the RestyleManager for each document we're used in
     595             :   // so that they can drop any nsCSSSelector pointers (used for
     596             :   // eRestyle_SomeDescendants) in their mPendingRestyles.
     597        3152 :   for (StyleSetHandle setHandle : mStyleSets) {
     598           0 :     setHandle->AsGecko()->ClearSelectors();
     599             :   }
     600             : 
     601        3152 :   bool removedSheetFromRuleProcessorCache = false;
     602        3152 :   if (mRuleProcessors) {
     603           0 :     nsCSSRuleProcessor **iter = mRuleProcessors->Elements(),
     604           0 :                        **end = iter + mRuleProcessors->Length();
     605           0 :     for(; iter != end; ++iter) {
     606           0 :       if (!removedSheetFromRuleProcessorCache && (*iter)->IsShared()) {
     607             :         // Since the sheet has been modified, we need to remove all
     608             :         // RuleProcessorCache entries that contain this sheet, as the
     609             :         // list of @-moz-document rules might have changed.
     610           0 :         RuleProcessorCache::RemoveSheet(this);
     611           0 :         removedSheetFromRuleProcessorCache = true;
     612             :       }
     613           0 :       (*iter)->ClearRuleCascades();
     614             :     }
     615             :   }
     616             : 
     617        3152 :   if (mParent) {
     618          73 :     static_cast<CSSStyleSheet*>(mParent)->ClearRuleCascades();
     619             :   }
     620        3152 : }
     621             : 
     622             : void
     623        3079 : CSSStyleSheet::DidDirty()
     624             : {
     625        3079 :   MOZ_ASSERT(!mInner->mComplete || mDirty,
     626             :              "caller must have called WillDirty()");
     627        3079 :   ClearRuleCascades();
     628        3079 : }
     629             : 
     630             : nsresult
     631          64 : CSSStyleSheet::RegisterNamespaceRule(css::Rule* aRule)
     632             : {
     633          64 :   if (!Inner()->mNameSpaceMap) {
     634          39 :     nsresult rv = Inner()->CreateNamespaceMap();
     635          39 :     NS_ENSURE_SUCCESS(rv, rv);
     636             :   }
     637             : 
     638          64 :   AddNamespaceRuleToMap(aRule, Inner()->mNameSpaceMap);
     639          64 :   return NS_OK;
     640             : }
     641             : 
     642             : void
     643          73 : CSSStyleSheet::SetScopeElement(dom::Element* aScopeElement)
     644             : {
     645          73 :   mScopeElement = aScopeElement;
     646          73 : }
     647             : 
     648             : CSSRuleList*
     649           0 : CSSStyleSheet::GetCssRulesInternal()
     650             : {
     651           0 :   if (!mRuleCollection) {
     652           0 :     mRuleCollection = new CSSRuleListImpl(this);
     653             :   }
     654           0 :   return mRuleCollection;
     655             : }
     656             : 
     657             : uint32_t
     658           0 : CSSStyleSheet::InsertRuleInternal(const nsAString& aRule,
     659             :                                   uint32_t aIndex,
     660             :                                   ErrorResult& aRv)
     661             : {
     662           0 :   MOZ_ASSERT(mInner->mComplete);
     663             : 
     664           0 :   WillDirty();
     665             : 
     666           0 :   if (aIndex > uint32_t(Inner()->mOrderedRules.Count())) {
     667           0 :     aRv.Throw(NS_ERROR_DOM_INDEX_SIZE_ERR);
     668           0 :     return 0;
     669             :   }
     670             : 
     671           0 :   NS_ASSERTION(uint32_t(Inner()->mOrderedRules.Count()) <= INT32_MAX,
     672             :                "Too many style rules!");
     673             : 
     674             :   // Hold strong ref to the CSSLoader in case the document update
     675             :   // kills the document
     676           0 :   RefPtr<css::Loader> loader;
     677           0 :   if (mDocument) {
     678           0 :     loader = mDocument->CSSLoader();
     679           0 :     NS_ASSERTION(loader, "Document with no CSS loader!");
     680             :   }
     681             : 
     682           0 :   nsCSSParser css(loader, this);
     683             : 
     684           0 :   mozAutoDocUpdate updateBatch(mDocument, UPDATE_STYLE, true);
     685             : 
     686           0 :   RefPtr<css::Rule> rule;
     687           0 :   aRv = css.ParseRule(aRule, mInner->mSheetURI, mInner->mBaseURI,
     688           0 :                       mInner->mPrincipal, getter_AddRefs(rule));
     689           0 :   if (NS_WARN_IF(aRv.Failed())) {
     690           0 :     return 0;
     691             :   }
     692             : 
     693             :   // Hierarchy checking.
     694           0 :   int32_t newType = rule->GetType();
     695             : 
     696             :   // check that we're not inserting before a charset rule
     697           0 :   css::Rule* nextRule = Inner()->mOrderedRules.SafeObjectAt(aIndex);
     698           0 :   if (nextRule) {
     699           0 :     int32_t nextType = nextRule->GetType();
     700           0 :     if (nextType == css::Rule::CHARSET_RULE) {
     701           0 :       aRv.Throw(NS_ERROR_DOM_HIERARCHY_REQUEST_ERR);
     702           0 :       return 0;
     703             :     }
     704             : 
     705           0 :     if (nextType == css::Rule::IMPORT_RULE &&
     706           0 :         newType != css::Rule::CHARSET_RULE &&
     707             :         newType != css::Rule::IMPORT_RULE) {
     708           0 :       aRv.Throw(NS_ERROR_DOM_HIERARCHY_REQUEST_ERR);
     709           0 :       return 0;
     710             :     }
     711             : 
     712           0 :     if (nextType == css::Rule::NAMESPACE_RULE &&
     713           0 :         newType != css::Rule::CHARSET_RULE &&
     714           0 :         newType != css::Rule::IMPORT_RULE &&
     715             :         newType != css::Rule::NAMESPACE_RULE) {
     716           0 :       aRv.Throw(NS_ERROR_DOM_HIERARCHY_REQUEST_ERR);
     717           0 :       return 0;
     718             :     }
     719             :   }
     720             : 
     721           0 :   if (aIndex != 0) {
     722             :     // no inserting charset at nonzero position
     723           0 :     if (newType == css::Rule::CHARSET_RULE) {
     724           0 :       aRv.Throw(NS_ERROR_DOM_HIERARCHY_REQUEST_ERR);
     725           0 :       return 0;
     726             :     }
     727             : 
     728           0 :     css::Rule* prevRule = Inner()->mOrderedRules.SafeObjectAt(aIndex - 1);
     729           0 :     int32_t prevType = prevRule->GetType();
     730             : 
     731           0 :     if (newType == css::Rule::IMPORT_RULE &&
     732           0 :         prevType != css::Rule::CHARSET_RULE &&
     733             :         prevType != css::Rule::IMPORT_RULE) {
     734           0 :       aRv.Throw(NS_ERROR_DOM_HIERARCHY_REQUEST_ERR);
     735           0 :       return 0;
     736             :     }
     737             : 
     738           0 :     if (newType == css::Rule::NAMESPACE_RULE &&
     739           0 :         prevType != css::Rule::CHARSET_RULE &&
     740           0 :         prevType != css::Rule::IMPORT_RULE &&
     741             :         prevType != css::Rule::NAMESPACE_RULE) {
     742           0 :       aRv.Throw(NS_ERROR_DOM_HIERARCHY_REQUEST_ERR);
     743           0 :       return 0;
     744             :     }
     745             :   }
     746             : 
     747           0 :   if (!Inner()->mOrderedRules.InsertObjectAt(rule, aIndex)) {
     748           0 :     aRv.Throw(NS_ERROR_OUT_OF_MEMORY);
     749           0 :     return 0;
     750             :   }
     751             : 
     752           0 :   DidDirty();
     753             : 
     754           0 :   rule->SetStyleSheet(this);
     755             : 
     756           0 :   int32_t type = rule->GetType();
     757           0 :   if (type == css::Rule::NAMESPACE_RULE) {
     758             :     // XXXbz does this screw up when inserting a namespace rule before
     759             :     // another namespace rule that binds the same prefix to a different
     760             :     // namespace?
     761           0 :     aRv = RegisterNamespaceRule(rule);
     762           0 :     if (NS_WARN_IF(aRv.Failed())) {
     763           0 :       return 0;
     764             :     }
     765             :   }
     766             : 
     767             :   // We don't notify immediately for @import rules, but rather when
     768             :   // the sheet the rule is importing is loaded (see StyleSheetLoaded)
     769           0 :   if ((type != css::Rule::IMPORT_RULE || !RuleHasPendingChildSheet(rule)) &&
     770           0 :       mDocument) {
     771           0 :     mDocument->StyleRuleAdded(this, rule);
     772             :   }
     773             : 
     774           0 :   return aIndex;
     775             : }
     776             : 
     777             : void
     778           0 : CSSStyleSheet::DeleteRuleInternal(uint32_t aIndex, ErrorResult& aRv)
     779             : {
     780             :   // XXX TBI: handle @rule types
     781           0 :   mozAutoDocUpdate updateBatch(mDocument, UPDATE_STYLE, true);
     782             : 
     783           0 :   WillDirty();
     784             : 
     785           0 :   if (aIndex >= uint32_t(Inner()->mOrderedRules.Count())) {
     786           0 :     aRv.Throw(NS_ERROR_DOM_INDEX_SIZE_ERR);
     787           0 :     return;
     788             :   }
     789             : 
     790           0 :   NS_ASSERTION(uint32_t(Inner()->mOrderedRules.Count()) <= INT32_MAX,
     791             :                "Too many style rules!");
     792             : 
     793             :   // Hold a strong ref to the rule so it doesn't die when we RemoveObjectAt
     794           0 :   RefPtr<css::Rule> rule = Inner()->mOrderedRules.ObjectAt(aIndex);
     795           0 :   if (rule) {
     796           0 :     Inner()->mOrderedRules.RemoveObjectAt(aIndex);
     797           0 :     rule->SetStyleSheet(nullptr);
     798           0 :     DidDirty();
     799             : 
     800           0 :     if (mDocument) {
     801           0 :       mDocument->StyleRuleRemoved(this, rule);
     802             :     }
     803             :   }
     804             : }
     805             : 
     806             : nsresult
     807           0 : CSSStyleSheet::InsertRuleIntoGroupInternal(const nsAString& aRule,
     808             :                                            css::GroupRule* aGroup,
     809             :                                            uint32_t aIndex)
     810             : {
     811             :   // Hold strong ref to the CSSLoader in case the document update
     812             :   // kills the document
     813           0 :   RefPtr<css::Loader> loader;
     814           0 :   if (mDocument) {
     815           0 :     loader = mDocument->CSSLoader();
     816           0 :     NS_ASSERTION(loader, "Document with no CSS loader!");
     817             :   }
     818             : 
     819           0 :   nsCSSParser css(loader, this);
     820             : 
     821           0 :   RefPtr<css::Rule> rule;
     822           0 :   nsresult result = css.ParseRule(aRule, mInner->mSheetURI, mInner->mBaseURI,
     823           0 :                                   mInner->mPrincipal, getter_AddRefs(rule));
     824           0 :   if (NS_FAILED(result))
     825           0 :     return result;
     826             : 
     827           0 :   switch (rule->GetType()) {
     828             :     case css::Rule::STYLE_RULE:
     829             :     case css::Rule::MEDIA_RULE:
     830             :     case css::Rule::FONT_FACE_RULE:
     831             :     case css::Rule::PAGE_RULE:
     832             :     case css::Rule::KEYFRAMES_RULE:
     833             :     case css::Rule::COUNTER_STYLE_RULE:
     834             :     case css::Rule::DOCUMENT_RULE:
     835             :     case css::Rule::SUPPORTS_RULE:
     836             :       // these types are OK to insert into a group
     837           0 :       break;
     838             :     case css::Rule::CHARSET_RULE:
     839             :     case css::Rule::IMPORT_RULE:
     840             :     case css::Rule::NAMESPACE_RULE:
     841             :       // these aren't
     842           0 :       return NS_ERROR_DOM_HIERARCHY_REQUEST_ERR;
     843             :     default:
     844           0 :       NS_NOTREACHED("unexpected rule type");
     845           0 :       return NS_ERROR_DOM_HIERARCHY_REQUEST_ERR;
     846             :   }
     847             : 
     848           0 :   return aGroup->InsertStyleRuleAt(aIndex, rule);
     849             : }
     850             : 
     851             : // nsICSSLoaderObserver implementation
     852             : NS_IMETHODIMP
     853           0 : CSSStyleSheet::StyleSheetLoaded(StyleSheet* aSheet,
     854             :                                 bool aWasAlternate,
     855             :                                 nsresult aStatus)
     856             : {
     857           0 :   MOZ_ASSERT(aSheet->IsGecko(),
     858             :              "why we were called back with a ServoStyleSheet?");
     859             : 
     860           0 :   CSSStyleSheet* sheet = aSheet->AsGecko();
     861             : 
     862           0 :   if (sheet->GetParentSheet() == nullptr) {
     863           0 :     return NS_OK; // ignore if sheet has been detached already (see parseSheet)
     864             :   }
     865           0 :   NS_ASSERTION(this == sheet->GetParentSheet(),
     866             :                "We are being notified of a sheet load for a sheet that is not our child!");
     867             : 
     868           0 :   if (mDocument && NS_SUCCEEDED(aStatus)) {
     869           0 :     mozAutoDocUpdate updateBatch(mDocument, UPDATE_STYLE, true);
     870             : 
     871             :     // XXXldb @import rules shouldn't even implement nsIStyleRule (but
     872             :     // they do)!
     873           0 :     mDocument->StyleRuleAdded(this, sheet->GetOwnerRule());
     874             :   }
     875             : 
     876           0 :   return NS_OK;
     877             : }
     878             : 
     879             : nsresult
     880           2 : CSSStyleSheet::ReparseSheet(const nsAString& aInput)
     881             : {
     882             :   // Not doing this if the sheet is not complete!
     883           2 :   if (!mInner->mComplete) {
     884           0 :     return NS_ERROR_DOM_INVALID_ACCESS_ERR;
     885             :   }
     886             : 
     887             :   // Hold strong ref to the CSSLoader in case the document update
     888             :   // kills the document
     889           4 :   RefPtr<css::Loader> loader;
     890           2 :   if (mDocument) {
     891           0 :     loader = mDocument->CSSLoader();
     892           0 :     NS_ASSERTION(loader, "Document with no CSS loader!");
     893             :   } else {
     894           2 :     loader = new css::Loader(StyleBackendType::Gecko, nullptr);
     895             :   }
     896             : 
     897           4 :   mozAutoDocUpdate updateBatch(mDocument, UPDATE_STYLE, true);
     898             : 
     899           2 :   WillDirty();
     900             : 
     901             :   // detach existing rules (including child sheets via import rules)
     902           4 :   css::LoaderReusableStyleSheets reusableSheets;
     903             :   int ruleCount;
     904           2 :   while ((ruleCount = Inner()->mOrderedRules.Count()) != 0) {
     905           0 :     RefPtr<css::Rule> rule = Inner()->mOrderedRules.ObjectAt(ruleCount - 1);
     906           0 :     Inner()->mOrderedRules.RemoveObjectAt(ruleCount - 1);
     907           0 :     rule->SetStyleSheet(nullptr);
     908           0 :     if (rule->GetType() == css::Rule::IMPORT_RULE) {
     909           0 :       nsCOMPtr<nsIDOMCSSImportRule> importRule(do_QueryInterface(rule));
     910           0 :       NS_ASSERTION(importRule, "GetType lied");
     911             : 
     912           0 :       nsCOMPtr<nsIDOMCSSStyleSheet> childSheet;
     913           0 :       importRule->GetStyleSheet(getter_AddRefs(childSheet));
     914             : 
     915           0 :       RefPtr<CSSStyleSheet> cssSheet = do_QueryObject(childSheet);
     916           0 :       if (cssSheet && cssSheet->GetOriginalURI()) {
     917           0 :         reusableSheets.AddReusableSheet(cssSheet);
     918             :       }
     919             :     }
     920           0 :     if (mDocument) {
     921           0 :       mDocument->StyleRuleRemoved(this, rule);
     922             :     }
     923             :   }
     924             : 
     925             :   // nuke child sheets list and current namespace map
     926           2 :   for (StyleSheet* child = GetFirstChild(); child; ) {
     927           0 :     NS_ASSERTION(child->mParent == this, "Child sheet is not parented to this!");
     928           0 :     StyleSheet* next = child->mNext;
     929           0 :     child->mParent = nullptr;
     930           0 :     child->SetAssociatedDocument(nullptr, NotOwnedByDocument);
     931           0 :     child->mNext = nullptr;
     932           0 :     child = next;
     933             :   }
     934           2 :   SheetInfo().mFirstChild = nullptr;
     935           2 :   Inner()->mNameSpaceMap = nullptr;
     936             : 
     937           2 :   uint32_t lineNumber = 1;
     938           2 :   if (mOwningNode) {
     939           0 :     nsCOMPtr<nsIStyleSheetLinkingElement> link = do_QueryInterface(mOwningNode);
     940           0 :     if (link) {
     941           0 :       lineNumber = link->GetLineNumber();
     942             :     }
     943             :   }
     944             : 
     945           4 :   nsCSSParser parser(loader, this);
     946           2 :   nsresult rv = parser.ParseSheet(aInput, mInner->mSheetURI, mInner->mBaseURI,
     947           4 :                                   mInner->mPrincipal, lineNumber, &reusableSheets);
     948           2 :   DidDirty(); // we are always 'dirty' here since we always remove rules first
     949           2 :   NS_ENSURE_SUCCESS(rv, rv);
     950             : 
     951             :   // notify document of all new rules
     952           2 :   if (mDocument) {
     953           0 :     for (int32_t index = 0; index < Inner()->mOrderedRules.Count(); ++index) {
     954           0 :       RefPtr<css::Rule> rule = Inner()->mOrderedRules.ObjectAt(index);
     955           0 :       if (rule->GetType() == css::Rule::IMPORT_RULE &&
     956           0 :           RuleHasPendingChildSheet(rule)) {
     957           0 :         continue; // notify when loaded (see StyleSheetLoaded)
     958             :       }
     959           0 :       mDocument->StyleRuleAdded(this, rule);
     960             :     }
     961             :   }
     962           2 :   return NS_OK;
     963             : }
     964             : 
     965             : } // namespace mozilla

Generated by: LCOV version 1.13