LCOV - code coverage report
Current view: top level - layout/style - RuleProcessorCache.cpp (source / functions) Hit Total Coverage
Test: output.info Lines: 66 125 52.8 %
Date: 2017-07-14 16:53:18 Functions: 16 24 66.7 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
       2             : /* vim: set ts=8 sts=2 et sw=2 tw=80: */
       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             : /*
       8             :  * cache of re-usable nsCSSRuleProcessors for given sets of style sheets
       9             :  */
      10             : 
      11             : #include "RuleProcessorCache.h"
      12             : 
      13             : #include <algorithm>
      14             : #include "mozilla/CSSStyleSheet.h"
      15             : #include "nsCSSRuleProcessor.h"
      16             : #include "nsThreadUtils.h"
      17             : 
      18             : using namespace mozilla;
      19             : 
      20           8 : NS_IMPL_ISUPPORTS(RuleProcessorCache, nsIMemoryReporter)
      21             : 
      22           0 : MOZ_DEFINE_MALLOC_SIZE_OF(RuleProcessorCacheMallocSizeOf)
      23             : 
      24             : NS_IMETHODIMP
      25           0 : RuleProcessorCache::CollectReports(nsIHandleReportCallback* aHandleReport,
      26             :                                    nsISupports* aData, bool aAnonymize)
      27             : {
      28           0 :   MOZ_COLLECT_REPORT(
      29             :     "explicit/layout/rule-processor-cache", KIND_HEAP, UNITS_BYTES,
      30             :     SizeOfIncludingThis(RuleProcessorCacheMallocSizeOf),
      31           0 :     "Memory used for cached rule processors.");
      32             : 
      33           0 :   return NS_OK;
      34             : }
      35             : 
      36           0 : RuleProcessorCache::~RuleProcessorCache()
      37             : {
      38           0 :   UnregisterWeakMemoryReporter(this);
      39             : 
      40           0 :   for (Entry& e : mEntries) {
      41           0 :     for (DocumentEntry& de : e.mDocumentEntries) {
      42           0 :       if (de.mRuleProcessor->GetExpirationState()->IsTracked()) {
      43           0 :         mExpirationTracker.RemoveObject(de.mRuleProcessor);
      44             :       }
      45           0 :       de.mRuleProcessor->SetInRuleProcessorCache(false);
      46             :     }
      47             :   }
      48           0 : }
      49             : 
      50             : void
      51           2 : RuleProcessorCache::InitMemoryReporter()
      52             : {
      53           2 :   RegisterWeakMemoryReporter(this);
      54           2 : }
      55             : 
      56             : /* static */ bool
      57          72 : RuleProcessorCache::EnsureGlobal()
      58             : {
      59          72 :   MOZ_ASSERT(NS_IsMainThread());
      60             : 
      61          72 :   if (gShutdown) {
      62           0 :     return false;
      63             :   }
      64             : 
      65          72 :   if (!gRuleProcessorCache) {
      66           2 :     gRuleProcessorCache = new RuleProcessorCache;
      67           2 :     gRuleProcessorCache->InitMemoryReporter();
      68             :   }
      69          72 :   return true;
      70             : }
      71             : 
      72             : /* static */ void
      73           0 : RuleProcessorCache::RemoveSheet(CSSStyleSheet* aSheet)
      74             : {
      75           0 :   if (!EnsureGlobal()) {
      76           0 :     return;
      77             :   }
      78           0 :   gRuleProcessorCache->DoRemoveSheet(aSheet);
      79             : }
      80             : 
      81             : #ifdef DEBUG
      82             : /* static */ bool
      83          15 : RuleProcessorCache::HasRuleProcessor(nsCSSRuleProcessor* aRuleProcessor)
      84             : {
      85          15 :   if (!EnsureGlobal()) {
      86           0 :     return false;
      87             :   }
      88          15 :   return gRuleProcessorCache->DoHasRuleProcessor(aRuleProcessor);
      89             : }
      90             : #endif
      91             : 
      92             : /* static */ void
      93           0 : RuleProcessorCache::RemoveRuleProcessor(nsCSSRuleProcessor* aRuleProcessor)
      94             : {
      95           0 :   if (!EnsureGlobal()) {
      96           0 :     return;
      97             :   }
      98           0 :   gRuleProcessorCache->DoRemoveRuleProcessor(aRuleProcessor);
      99             : }
     100             : 
     101             : /* static */ nsCSSRuleProcessor*
     102          34 : RuleProcessorCache::GetRuleProcessor(const nsTArray<CSSStyleSheet*>& aSheets,
     103             :                                      nsPresContext* aPresContext)
     104             : {
     105          34 :   if (!EnsureGlobal()) {
     106           0 :     return nullptr;
     107             :   }
     108          34 :   return gRuleProcessorCache->DoGetRuleProcessor(aSheets, aPresContext);
     109             : }
     110             : 
     111             : /* static */ void
     112          10 : RuleProcessorCache::PutRuleProcessor(
     113             :     const nsTArray<CSSStyleSheet*>& aSheets,
     114             :     nsTArray<css::DocumentRule*>&& aDocumentRulesInSheets,
     115             :     const nsDocumentRuleResultCacheKey& aCacheKey,
     116             :     nsCSSRuleProcessor* aRuleProcessor)
     117             : {
     118          10 :   if (!EnsureGlobal()) {
     119           0 :     return;
     120             :   }
     121          10 :   gRuleProcessorCache->DoPutRuleProcessor(aSheets, Move(aDocumentRulesInSheets),
     122          10 :                                           aCacheKey, aRuleProcessor);
     123             : }
     124             : 
     125             : /* static */ void
     126           3 : RuleProcessorCache::StartTracking(nsCSSRuleProcessor* aRuleProcessor)
     127             : {
     128           3 :   if (!EnsureGlobal()) {
     129           0 :     return;
     130             :   }
     131           3 :   return gRuleProcessorCache->DoStartTracking(aRuleProcessor);
     132             : }
     133             : 
     134             : /* static */ void
     135          10 : RuleProcessorCache::StopTracking(nsCSSRuleProcessor* aRuleProcessor)
     136             : {
     137          10 :   if (!EnsureGlobal()) {
     138           0 :     return;
     139             :   }
     140          10 :   return gRuleProcessorCache->DoStopTracking(aRuleProcessor);
     141             : }
     142             : 
     143             : void
     144           0 : RuleProcessorCache::DoRemoveSheet(CSSStyleSheet* aSheet)
     145             : {
     146           0 :   auto last = std::remove_if(mEntries.begin(), mEntries.end(),
     147           0 :                              HasSheet_ThenRemoveRuleProcessors(this, aSheet));
     148           0 :   mEntries.TruncateLength(last - mEntries.begin());
     149           0 : }
     150             : 
     151             : nsCSSRuleProcessor*
     152          34 : RuleProcessorCache::DoGetRuleProcessor(const nsTArray<CSSStyleSheet*>& aSheets,
     153             :                                        nsPresContext* aPresContext)
     154             : {
     155         145 :   for (Entry& e : mEntries) {
     156         135 :     if (e.mSheets == aSheets) {
     157          24 :       for (DocumentEntry& de : e.mDocumentEntries) {
     158          24 :         if (de.mCacheKey.Matches(aPresContext, e.mDocumentRulesInSheets)) {
     159          24 :           return de.mRuleProcessor;
     160             :         }
     161             :       }
     162             :       // Entry::mSheets is unique; if we matched aSheets but didn't
     163             :       // find a matching DocumentEntry, we won't find one later in
     164             :       // mEntries.
     165           0 :       return nullptr;
     166             :     }
     167             :   }
     168          10 :   return nullptr;
     169             : }
     170             : 
     171             : void
     172          10 : RuleProcessorCache::DoPutRuleProcessor(
     173             :     const nsTArray<CSSStyleSheet*>& aSheets,
     174             :     nsTArray<css::DocumentRule*>&& aDocumentRulesInSheets,
     175             :     const nsDocumentRuleResultCacheKey& aCacheKey,
     176             :     nsCSSRuleProcessor* aRuleProcessor)
     177             : {
     178          10 :   MOZ_ASSERT(!aRuleProcessor->IsInRuleProcessorCache());
     179             : 
     180          10 :   Entry* entry = nullptr;
     181          39 :   for (Entry& e : mEntries) {
     182          29 :     if (e.mSheets == aSheets) {
     183           0 :       entry = &e;
     184           0 :       break;
     185             :     }
     186             :   }
     187             : 
     188          10 :   if (!entry) {
     189          10 :     entry = mEntries.AppendElement();
     190          10 :     entry->mSheets = aSheets;
     191          10 :     entry->mDocumentRulesInSheets = aDocumentRulesInSheets;
     192          79 :     for (CSSStyleSheet* sheet : aSheets) {
     193          69 :       sheet->SetInRuleProcessorCache();
     194             :     }
     195             :   } else {
     196           0 :     MOZ_ASSERT(entry->mDocumentRulesInSheets == aDocumentRulesInSheets,
     197             :                "DocumentRule array shouldn't have changed");
     198             :   }
     199             : 
     200             : #ifdef DEBUG
     201          10 :   for (DocumentEntry& de : entry->mDocumentEntries) {
     202           0 :     MOZ_ASSERT(de.mCacheKey != aCacheKey,
     203             :                "should not have duplicate document cache keys");
     204             :   }
     205             : #endif
     206             : 
     207          10 :   DocumentEntry* documentEntry = entry->mDocumentEntries.AppendElement();
     208          10 :   documentEntry->mCacheKey = aCacheKey;
     209          10 :   documentEntry->mRuleProcessor = aRuleProcessor;
     210          10 :   aRuleProcessor->SetInRuleProcessorCache(true);
     211          10 : }
     212             : 
     213             : #ifdef DEBUG
     214             : bool
     215          15 : RuleProcessorCache::DoHasRuleProcessor(nsCSSRuleProcessor* aRuleProcessor)
     216             : {
     217         135 :   for (Entry& e : mEntries) {
     218         240 :     for (DocumentEntry& de : e.mDocumentEntries) {
     219         120 :       if (de.mRuleProcessor == aRuleProcessor) {
     220           0 :         return true;
     221             :       }
     222             :     }
     223             :   }
     224          15 :   return false;
     225             : }
     226             : #endif
     227             : 
     228             : void
     229           0 : RuleProcessorCache::DoRemoveRuleProcessor(nsCSSRuleProcessor* aRuleProcessor)
     230             : {
     231           0 :   MOZ_ASSERT(aRuleProcessor->IsInRuleProcessorCache());
     232             : 
     233           0 :   aRuleProcessor->SetInRuleProcessorCache(false);
     234           0 :   mExpirationTracker.RemoveObjectIfTracked(aRuleProcessor);
     235           0 :   for (Entry& e : mEntries) {
     236           0 :     for (size_t i = 0; i < e.mDocumentEntries.Length(); i++) {
     237           0 :       if (e.mDocumentEntries[i].mRuleProcessor == aRuleProcessor) {
     238           0 :         e.mDocumentEntries.RemoveElementAt(i);
     239           0 :         return;
     240             :       }
     241             :     }
     242             :   }
     243             : 
     244           0 :   MOZ_ASSERT_UNREACHABLE("should have found rule processor");
     245             : }
     246             : 
     247             : void
     248           3 : RuleProcessorCache::DoStartTracking(nsCSSRuleProcessor* aRuleProcessor)
     249             : {
     250           3 :   mExpirationTracker.AddObject(aRuleProcessor);
     251           3 : }
     252             : 
     253             : void
     254          10 : RuleProcessorCache::DoStopTracking(nsCSSRuleProcessor* aRuleProcessor)
     255             : {
     256          10 :   mExpirationTracker.RemoveObjectIfTracked(aRuleProcessor);
     257          10 : }
     258             : 
     259             : size_t
     260           0 : RuleProcessorCache::SizeOfIncludingThis(mozilla::MallocSizeOf aMallocSizeOf)
     261             : {
     262           0 :   size_t n = aMallocSizeOf(this);
     263             : 
     264           0 :   int count = 0;
     265           0 :   n += mEntries.ShallowSizeOfExcludingThis(aMallocSizeOf);
     266           0 :   for (Entry& e : mEntries) {
     267           0 :     n += e.mDocumentEntries.ShallowSizeOfExcludingThis(aMallocSizeOf);
     268           0 :     for (DocumentEntry& de : e.mDocumentEntries) {
     269           0 :       count++;
     270           0 :       n += de.mRuleProcessor->SizeOfIncludingThis(aMallocSizeOf);
     271             :     }
     272             :   }
     273             : 
     274           0 :   return n;
     275             : }
     276             : 
     277             : void
     278          10 : RuleProcessorCache::ExpirationTracker::RemoveObjectIfTracked(
     279             :     nsCSSRuleProcessor* aRuleProcessor)
     280             : {
     281          10 :   if (aRuleProcessor->GetExpirationState()->IsTracked()) {
     282           0 :     RemoveObject(aRuleProcessor);
     283             :   }
     284          10 : }
     285             : 
     286             : bool RuleProcessorCache::gShutdown = false;
     287           3 : mozilla::StaticRefPtr<RuleProcessorCache> RuleProcessorCache::gRuleProcessorCache;

Generated by: LCOV version 1.13