diff options
Diffstat (limited to 'layout/style/SharedStyleSheetCache.h')
-rw-r--r-- | layout/style/SharedStyleSheetCache.h | 145 |
1 files changed, 145 insertions, 0 deletions
diff --git a/layout/style/SharedStyleSheetCache.h b/layout/style/SharedStyleSheetCache.h new file mode 100644 index 0000000000..8d134caf66 --- /dev/null +++ b/layout/style/SharedStyleSheetCache.h @@ -0,0 +1,145 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim: set ts=8 sts=2 et sw=2 tw=80: */ +/* 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/. */ + +#ifndef mozilla_SharedStyleSheetCache_h__ +#define mozilla_SharedStyleSheetCache_h__ + +// The shared style sheet cache is a cache that allows us to share sheets across +// documents. +// +// It's generally a singleton, but it is different from GlobalStyleSheetCache in +// the sense that: +// +// * It needs to be cycle-collectable, as it can keep alive style sheets from +// various documents. +// +// * It is conceptually a singleton, but given its cycle-collectable nature, we +// might re-create it. + +#include "mozilla/PrincipalHashKey.h" +#include "mozilla/WeakPtr.h" +#include "mozilla/css/Loader.h" +#include "nsDataHashtable.h" +#include "nsIMemoryReporter.h" +#include "nsRefPtrHashtable.h" +#include "nsURIHashKey.h" + +namespace mozilla { + +namespace css { +class SheetLoadData; +} + +class SharedStyleSheetCache final : public nsIMemoryReporter { + public: + NS_DECL_ISUPPORTS + NS_DECL_NSIMEMORYREPORTER + + SharedStyleSheetCache(const SharedStyleSheetCache&) = delete; + SharedStyleSheetCache(SharedStyleSheetCache&&) = delete; + + static already_AddRefed<SharedStyleSheetCache> Get() { + if (sInstance) { + return do_AddRef(sInstance); + } + return Create(); + } + + public: + // TODO(emilio): Maybe cache inline sheets here rather than in the loader? + // But that is a bit dubious, because for inline sheets, the sheet URI is the + // document URI, so it is basically document-specific... Maybe we can cache + // the RawServoStyleSheetContents or something, but... + + // A cache hit or miss. It is a miss if the `StyleSheet` is null. + using CacheResult = std::tuple<RefPtr<StyleSheet>, css::Loader::SheetState>; + CacheResult Lookup(css::Loader&, const SheetLoadDataHashKey&, bool aSyncLoad); + + // Tries to coalesce with an already existing load. The sheet state must be + // the one that Lookup returned, if it returned a sheet. + // + // TODO(emilio): Maybe try to merge this with the lookup? Most consumers could + // have a data there already. + MOZ_MUST_USE bool CoalesceLoad(const SheetLoadDataHashKey&, + css::SheetLoadData& aNewLoad, + css::Loader::SheetState aExistingLoadState); + + size_t SizeOfIncludingThis(MallocSizeOf) const; + + // Puts the load into the "loading" set. + void LoadStarted(const SheetLoadDataHashKey&, css::SheetLoadData&); + // Puts a load into the "pending" set. + void DeferSheetLoad(const SheetLoadDataHashKey&, css::SheetLoadData&); + + enum class StartLoads { + Always, + IfNonAlternate, + }; + + void StartDeferredLoadsForLoader(css::Loader&, StartLoads); + void CancelLoadsForLoader(css::Loader&); + + // This has to be static because it's also called for loaders that don't have + // a sheet cache (loaders that are not owned by a document). + static void LoadCompleted(SharedStyleSheetCache*, css::SheetLoadData&, + nsresult); + + // Register a loader into the cache. This has the effect of keeping alive all + // stylesheets for the origin of the loader's document until UnregisterLoader + // is called. + void RegisterLoader(css::Loader&); + + // Unregister a loader from the cache. + // + // If this is the loader for the last document of a given origin, then all the + // stylesheets for that document will be removed from the cache. This needs to + // be called when the document goes away, or when its principal changes. + void UnregisterLoader(css::Loader&); + + static void Clear(nsIPrincipal* aForPrincipal = nullptr); + + private: + static already_AddRefed<SharedStyleSheetCache> Create(); + void CancelDeferredLoadsForLoader(css::Loader&); + + static void LoadCompletedInternal(SharedStyleSheetCache*, css::SheetLoadData&, + nsTArray<RefPtr<css::SheetLoadData>>&); + void InsertIntoCompleteCacheIfNeeded(css::SheetLoadData&); + + SharedStyleSheetCache() = default; + + ~SharedStyleSheetCache(); + + struct CompleteSheet { + uint32_t mExpirationTime = 0; + UniquePtr<StyleUseCounters> mUseCounters; + RefPtr<StyleSheet> mSheet; + + bool Expired() const; + }; + + void WillStartPendingLoad(css::SheetLoadData&); + + nsDataHashtable<SheetLoadDataHashKey, CompleteSheet> mCompleteSheets; + nsRefPtrHashtable<SheetLoadDataHashKey, css::SheetLoadData> mPendingDatas; + // The SheetLoadData pointers in mLoadingDatas below are weak references that + // get cleaned up when StreamLoader::OnStopRequest gets called. + // + // Note that we hold on to all sheet loads, even if in the end they happen not + // to be cacheable. + nsDataHashtable<SheetLoadDataHashKey, WeakPtr<css::SheetLoadData>> + mLoadingDatas; + + // An origin-to-number-of-registered-documents count, in order to manage cache + // eviction as described in RegisterLoader / UnregisterLoader. + nsDataHashtable<PrincipalHashKey, uint32_t> mLoaderPrincipalRefCnt; + + static SharedStyleSheetCache* sInstance; +}; + +} // namespace mozilla + +#endif |