123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287 |
- /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
- /* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
- /*
- * cache of re-usable nsCSSRuleProcessors for given sets of style sheets
- */
- #include "RuleProcessorCache.h"
- #include <algorithm>
- #include "nsCSSRuleProcessor.h"
- #include "nsThreadUtils.h"
- #include "CSSStyleSheet.h"
- using namespace mozilla;
- NS_IMPL_ISUPPORTS(RuleProcessorCache, nsIMemoryReporter)
- MOZ_DEFINE_MALLOC_SIZE_OF(RuleProcessorCacheMallocSizeOf)
- NS_IMETHODIMP
- RuleProcessorCache::CollectReports(nsIHandleReportCallback* aHandleReport,
- nsISupports* aData, bool aAnonymize)
- {
- MOZ_COLLECT_REPORT(
- "explicit/layout/rule-processor-cache", KIND_HEAP, UNITS_BYTES,
- SizeOfIncludingThis(RuleProcessorCacheMallocSizeOf),
- "Memory used for cached rule processors.");
- return NS_OK;
- }
- RuleProcessorCache::~RuleProcessorCache()
- {
- UnregisterWeakMemoryReporter(this);
- for (Entry& e : mEntries) {
- for (DocumentEntry& de : e.mDocumentEntries) {
- if (de.mRuleProcessor->GetExpirationState()->IsTracked()) {
- mExpirationTracker.RemoveObject(de.mRuleProcessor);
- }
- de.mRuleProcessor->SetInRuleProcessorCache(false);
- }
- }
- }
- void
- RuleProcessorCache::InitMemoryReporter()
- {
- RegisterWeakMemoryReporter(this);
- }
- /* static */ bool
- RuleProcessorCache::EnsureGlobal()
- {
- MOZ_ASSERT(NS_IsMainThread());
- if (gShutdown) {
- return false;
- }
- if (!gRuleProcessorCache) {
- gRuleProcessorCache = new RuleProcessorCache;
- gRuleProcessorCache->InitMemoryReporter();
- }
- return true;
- }
- /* static */ void
- RuleProcessorCache::RemoveSheet(CSSStyleSheet* aSheet)
- {
- if (!EnsureGlobal()) {
- return;
- }
- gRuleProcessorCache->DoRemoveSheet(aSheet);
- }
- #ifdef DEBUG
- /* static */ bool
- RuleProcessorCache::HasRuleProcessor(nsCSSRuleProcessor* aRuleProcessor)
- {
- if (!EnsureGlobal()) {
- return false;
- }
- return gRuleProcessorCache->DoHasRuleProcessor(aRuleProcessor);
- }
- #endif
- /* static */ void
- RuleProcessorCache::RemoveRuleProcessor(nsCSSRuleProcessor* aRuleProcessor)
- {
- if (!EnsureGlobal()) {
- return;
- }
- gRuleProcessorCache->DoRemoveRuleProcessor(aRuleProcessor);
- }
- /* static */ nsCSSRuleProcessor*
- RuleProcessorCache::GetRuleProcessor(const nsTArray<CSSStyleSheet*>& aSheets,
- nsPresContext* aPresContext)
- {
- if (!EnsureGlobal()) {
- return nullptr;
- }
- return gRuleProcessorCache->DoGetRuleProcessor(aSheets, aPresContext);
- }
- /* static */ void
- RuleProcessorCache::PutRuleProcessor(
- const nsTArray<CSSStyleSheet*>& aSheets,
- nsTArray<css::DocumentRule*>&& aDocumentRulesInSheets,
- const nsDocumentRuleResultCacheKey& aCacheKey,
- nsCSSRuleProcessor* aRuleProcessor)
- {
- if (!EnsureGlobal()) {
- return;
- }
- gRuleProcessorCache->DoPutRuleProcessor(aSheets, Move(aDocumentRulesInSheets),
- aCacheKey, aRuleProcessor);
- }
- /* static */ void
- RuleProcessorCache::StartTracking(nsCSSRuleProcessor* aRuleProcessor)
- {
- if (!EnsureGlobal()) {
- return;
- }
- return gRuleProcessorCache->DoStartTracking(aRuleProcessor);
- }
- /* static */ void
- RuleProcessorCache::StopTracking(nsCSSRuleProcessor* aRuleProcessor)
- {
- if (!EnsureGlobal()) {
- return;
- }
- return gRuleProcessorCache->DoStopTracking(aRuleProcessor);
- }
- void
- RuleProcessorCache::DoRemoveSheet(CSSStyleSheet* aSheet)
- {
- Entry* last = std::remove_if(mEntries.begin(), mEntries.end(),
- HasSheet_ThenRemoveRuleProcessors(this, aSheet));
- mEntries.TruncateLength(last - mEntries.begin());
- }
- nsCSSRuleProcessor*
- RuleProcessorCache::DoGetRuleProcessor(const nsTArray<CSSStyleSheet*>& aSheets,
- nsPresContext* aPresContext)
- {
- for (Entry& e : mEntries) {
- if (e.mSheets == aSheets) {
- for (DocumentEntry& de : e.mDocumentEntries) {
- if (de.mCacheKey.Matches(aPresContext, e.mDocumentRulesInSheets)) {
- return de.mRuleProcessor;
- }
- }
- // Entry::mSheets is unique; if we matched aSheets but didn't
- // find a matching DocumentEntry, we won't find one later in
- // mEntries.
- return nullptr;
- }
- }
- return nullptr;
- }
- void
- RuleProcessorCache::DoPutRuleProcessor(
- const nsTArray<CSSStyleSheet*>& aSheets,
- nsTArray<css::DocumentRule*>&& aDocumentRulesInSheets,
- const nsDocumentRuleResultCacheKey& aCacheKey,
- nsCSSRuleProcessor* aRuleProcessor)
- {
- MOZ_ASSERT(!aRuleProcessor->IsInRuleProcessorCache());
- Entry* entry = nullptr;
- for (Entry& e : mEntries) {
- if (e.mSheets == aSheets) {
- entry = &e;
- break;
- }
- }
- if (!entry) {
- entry = mEntries.AppendElement();
- entry->mSheets = aSheets;
- entry->mDocumentRulesInSheets = aDocumentRulesInSheets;
- for (CSSStyleSheet* sheet : aSheets) {
- sheet->SetInRuleProcessorCache();
- }
- } else {
- MOZ_ASSERT(entry->mDocumentRulesInSheets == aDocumentRulesInSheets,
- "DocumentRule array shouldn't have changed");
- }
- #ifdef DEBUG
- for (DocumentEntry& de : entry->mDocumentEntries) {
- MOZ_ASSERT(de.mCacheKey != aCacheKey,
- "should not have duplicate document cache keys");
- }
- #endif
- DocumentEntry* documentEntry = entry->mDocumentEntries.AppendElement();
- documentEntry->mCacheKey = aCacheKey;
- documentEntry->mRuleProcessor = aRuleProcessor;
- aRuleProcessor->SetInRuleProcessorCache(true);
- }
- #ifdef DEBUG
- bool
- RuleProcessorCache::DoHasRuleProcessor(nsCSSRuleProcessor* aRuleProcessor)
- {
- for (Entry& e : mEntries) {
- for (DocumentEntry& de : e.mDocumentEntries) {
- if (de.mRuleProcessor == aRuleProcessor) {
- return true;
- }
- }
- }
- return false;
- }
- #endif
- void
- RuleProcessorCache::DoRemoveRuleProcessor(nsCSSRuleProcessor* aRuleProcessor)
- {
- MOZ_ASSERT(aRuleProcessor->IsInRuleProcessorCache());
- aRuleProcessor->SetInRuleProcessorCache(false);
- mExpirationTracker.RemoveObjectIfTracked(aRuleProcessor);
- for (Entry& e : mEntries) {
- for (size_t i = 0; i < e.mDocumentEntries.Length(); i++) {
- if (e.mDocumentEntries[i].mRuleProcessor == aRuleProcessor) {
- e.mDocumentEntries.RemoveElementAt(i);
- return;
- }
- }
- }
- MOZ_ASSERT_UNREACHABLE("should have found rule processor");
- }
- void
- RuleProcessorCache::DoStartTracking(nsCSSRuleProcessor* aRuleProcessor)
- {
- mExpirationTracker.AddObject(aRuleProcessor);
- }
- void
- RuleProcessorCache::DoStopTracking(nsCSSRuleProcessor* aRuleProcessor)
- {
- mExpirationTracker.RemoveObjectIfTracked(aRuleProcessor);
- }
- size_t
- RuleProcessorCache::SizeOfIncludingThis(mozilla::MallocSizeOf aMallocSizeOf)
- {
- size_t n = aMallocSizeOf(this);
- int count = 0;
- n += mEntries.ShallowSizeOfExcludingThis(aMallocSizeOf);
- for (Entry& e : mEntries) {
- n += e.mDocumentEntries.ShallowSizeOfExcludingThis(aMallocSizeOf);
- for (DocumentEntry& de : e.mDocumentEntries) {
- count++;
- n += de.mRuleProcessor->SizeOfIncludingThis(aMallocSizeOf);
- }
- }
- return n;
- }
- void
- RuleProcessorCache::ExpirationTracker::RemoveObjectIfTracked(
- nsCSSRuleProcessor* aRuleProcessor)
- {
- if (aRuleProcessor->GetExpirationState()->IsTracked()) {
- RemoveObject(aRuleProcessor);
- }
- }
- bool RuleProcessorCache::gShutdown = false;
- mozilla::StaticRefPtr<RuleProcessorCache> RuleProcessorCache::gRuleProcessorCache;
|