summaryrefslogtreecommitdiffstats
path: root/gfx/thebes/gfxUserFontSet.h
diff options
context:
space:
mode:
Diffstat (limited to 'gfx/thebes/gfxUserFontSet.h')
-rw-r--r--gfx/thebes/gfxUserFontSet.h792
1 files changed, 792 insertions, 0 deletions
diff --git a/gfx/thebes/gfxUserFontSet.h b/gfx/thebes/gfxUserFontSet.h
new file mode 100644
index 0000000000..d67d10fbe6
--- /dev/null
+++ b/gfx/thebes/gfxUserFontSet.h
@@ -0,0 +1,792 @@
+/* -*- Mode: C++; tab-width: 20; 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/. */
+
+#ifndef GFX_USER_FONT_SET_H
+#define GFX_USER_FONT_SET_H
+
+#include <new>
+#include "PLDHashTable.h"
+#include "gfxFontEntry.h"
+#include "gfxFontUtils.h"
+#include "mozilla/AlreadyAddRefed.h"
+#include "mozilla/Attributes.h"
+#include "mozilla/FontPropertyTypes.h"
+#include "mozilla/MemoryReporting.h"
+#include "mozilla/RefPtr.h"
+#include "nsCOMPtr.h"
+#include "nsHashKeys.h"
+#include "nsIMemoryReporter.h"
+#include "nsIObserver.h"
+#include "nsIScriptError.h"
+#include "nsISupports.h"
+#include "nsRefPtrHashtable.h"
+#include "nsString.h"
+#include "nsTArray.h"
+#include "nscore.h"
+
+// Only needed for function bodies.
+#include <utility> // for move, forward
+#include "MainThreadUtils.h" // for NS_IsMainThread
+#include "gfxFontFeatures.h" // for gfxFontFeature
+#include "gfxFontSrcPrincipal.h" // for gfxFontSrcPrincipal
+#include "gfxFontSrcURI.h" // for gfxFontSrcURI
+#include "mozilla/Assertions.h" // for AssertionConditionType, MOZ_ASSERT_HELPER2, MOZ_ASSERT, MOZ_ASSERT_UNREACHABLE, MOZ_ASSER...
+#include "mozilla/HashFunctions.h" // for HashBytes, HashGeneric
+#include "mozilla/TimeStamp.h" // for TimeStamp
+#include "mozilla/gfx/FontVariation.h" // for FontVariation
+#include "nsDebug.h" // for NS_WARNING
+#include "nsIReferrerInfo.h" // for nsIReferrerInfo
+
+class gfxFont;
+class gfxUserFontSet;
+class nsIFontLoadCompleteCallback;
+class nsIRunnable;
+struct gfxFontStyle;
+struct gfxFontVariationAxis;
+struct gfxFontVariationInstance;
+template <class T>
+class nsMainThreadPtrHandle;
+
+namespace mozilla {
+class LogModule;
+class PostTraversalTask;
+enum class StyleFontDisplay : uint8_t;
+} // namespace mozilla
+class nsFontFaceLoader;
+
+// #define DEBUG_USERFONT_CACHE
+
+class gfxFontFaceBufferSource {
+ NS_INLINE_DECL_THREADSAFE_REFCOUNTING(gfxFontFaceBufferSource)
+ public:
+ virtual void TakeBuffer(uint8_t*& aBuffer, uint32_t& aLength) = 0;
+
+ protected:
+ virtual ~gfxFontFaceBufferSource() = default;
+};
+
+// parsed CSS @font-face rule information
+// lifetime: from when @font-face rule processed until font is loaded
+struct gfxFontFaceSrc {
+ enum SourceType { eSourceType_Local, eSourceType_URL, eSourceType_Buffer };
+
+ SourceType mSourceType;
+
+ // if url, whether to use the origin principal or not
+ bool mUseOriginPrincipal = false;
+
+ // Required font technologies.
+ mozilla::StyleFontFaceSourceTechFlags mTechFlags;
+
+ // Format hint, if any was specified.
+ mozilla::StyleFontFaceSourceFormatKeyword mFormatHint;
+
+ nsCString mLocalName; // full font name if local
+ RefPtr<gfxFontSrcURI> mURI; // uri if url
+ nsCOMPtr<nsIReferrerInfo> mReferrerInfo; // referrer info if url
+ RefPtr<gfxFontSrcPrincipal>
+ mOriginPrincipal; // principal if url and mUseOriginPrincipal
+
+ RefPtr<gfxFontFaceBufferSource> mBuffer;
+
+ // The principal that should be used for the load. Should only be used for
+ // URL sources.
+ already_AddRefed<gfxFontSrcPrincipal> LoadPrincipal(
+ const gfxUserFontSet&) const;
+};
+
+inline bool operator==(const gfxFontFaceSrc& a, const gfxFontFaceSrc& b) {
+ if (a.mSourceType != b.mSourceType) {
+ return false;
+ }
+ switch (a.mSourceType) {
+ case gfxFontFaceSrc::eSourceType_Local:
+ return a.mLocalName == b.mLocalName;
+ case gfxFontFaceSrc::eSourceType_URL: {
+ if (a.mUseOriginPrincipal != b.mUseOriginPrincipal) {
+ return false;
+ }
+ if (a.mUseOriginPrincipal) {
+ if (!a.mOriginPrincipal->Equals(b.mOriginPrincipal)) {
+ return false;
+ }
+ }
+ bool equals;
+ return a.mFormatHint == b.mFormatHint && a.mTechFlags == b.mTechFlags &&
+ (a.mURI == b.mURI || a.mURI->Equals(b.mURI)) &&
+ NS_SUCCEEDED(a.mReferrerInfo->Equals(b.mReferrerInfo, &equals)) &&
+ equals;
+ }
+ case gfxFontFaceSrc::eSourceType_Buffer:
+ return a.mBuffer == b.mBuffer;
+ }
+ NS_WARNING("unexpected mSourceType");
+ return false;
+}
+
+// Subclassed to store platform-specific code cleaned out when font entry is
+// deleted.
+// Lifetime: from when platform font is created until it is deactivated.
+// If the platform does not need to add any platform-specific code/data here,
+// then the gfxUserFontSet will allocate a base gfxUserFontData and attach
+// to the entry to track the basic user font info fields here.
+class gfxUserFontData {
+ public:
+ gfxUserFontData()
+ : mSrcIndex(0),
+ mMetaOrigLen(0),
+ mTechFlags(mozilla::StyleFontFaceSourceTechFlags::Empty()),
+ mFormatHint(mozilla::StyleFontFaceSourceFormatKeyword::None),
+ mCompression(kUnknownCompression),
+ mPrivate(false),
+ mIsBuffer(false) {}
+ virtual ~gfxUserFontData() = default;
+
+ size_t SizeOfIncludingThis(mozilla::MallocSizeOf aMallocSizeOf) const;
+
+ nsTArray<uint8_t> mMetadata; // woff metadata block (compressed), if any
+ RefPtr<gfxFontSrcURI> mURI; // URI of the source, if it was url()
+ RefPtr<gfxFontSrcPrincipal>
+ mPrincipal; // principal for the download, if url()
+ nsCString mLocalName; // font name used for the source, if local()
+ nsCString mRealName; // original fullname from the font resource
+ uint32_t mSrcIndex; // index in the rule's source list
+ uint32_t mMetaOrigLen; // length needed to decompress metadata
+ mozilla::StyleFontFaceSourceTechFlags mTechFlags; // required font tech
+ mozilla::StyleFontFaceSourceFormatKeyword
+ mFormatHint; // format hint for the source used, if any
+ uint8_t mCompression; // compression type
+ bool mPrivate; // whether font belongs to a private window
+ bool mIsBuffer; // whether the font source was a buffer
+
+ enum {
+ kUnknownCompression = 0,
+ kZlibCompression = 1,
+ kBrotliCompression = 2
+ };
+};
+
+// initially contains a set of userfont font entry objects, replaced with
+// platform/user fonts as downloaded
+
+class gfxUserFontFamily : public gfxFontFamily {
+ public:
+ friend class gfxUserFontSet;
+
+ explicit gfxUserFontFamily(const nsACString& aName)
+ : gfxFontFamily(aName, FontVisibility::Webfont) {}
+
+ virtual ~gfxUserFontFamily();
+
+ // add the given font entry to the end of the family's list
+ void AddFontEntry(gfxFontEntry* aFontEntry) {
+ mozilla::AutoWriteLock lock(mLock);
+ MOZ_ASSERT(!mIsSimpleFamily, "not valid for user-font families");
+ // keep ref while removing existing entry
+ RefPtr<gfxFontEntry> fe = aFontEntry;
+ // remove existing entry, if already present
+ mAvailableFonts.RemoveElement(aFontEntry);
+ // insert at the beginning so that the last-defined font is the first
+ // one in the fontlist used for matching, as per CSS Fonts spec
+ mAvailableFonts.InsertElementAt(0, aFontEntry);
+
+ if (aFontEntry->mFamilyName.IsEmpty()) {
+ aFontEntry->mFamilyName = Name();
+ } else {
+#ifdef DEBUG
+ nsCString thisName = Name();
+ nsCString entryName = aFontEntry->mFamilyName;
+ ToLowerCase(thisName);
+ ToLowerCase(entryName);
+ MOZ_ASSERT(thisName.Equals(entryName));
+#endif
+ }
+ ResetCharacterMap();
+ }
+
+ void RemoveFontEntry(gfxFontEntry* aFontEntry) {
+ mozilla::AutoWriteLock lock(mLock);
+ MOZ_ASSERT(!mIsSimpleFamily, "not valid for user-font families");
+ mAvailableFonts.RemoveElement(aFontEntry);
+ }
+
+ // Remove all font entries from the family
+ void DetachFontEntries() {
+ mozilla::AutoWriteLock lock(mLock);
+ mAvailableFonts.Clear();
+ }
+};
+
+class gfxUserFontEntry;
+class gfxOTSMessageContext;
+
+struct gfxUserFontAttributes {
+ using FontStretch = mozilla::FontStretch;
+ using StretchRange = mozilla::StretchRange;
+ using FontSlantStyle = mozilla::FontSlantStyle;
+ using SlantStyleRange = mozilla::SlantStyleRange;
+ using FontWeight = mozilla::FontWeight;
+ using WeightRange = mozilla::WeightRange;
+ using StyleFontFaceSourceListComponent =
+ mozilla::StyleFontFaceSourceListComponent;
+ using RangeFlags = gfxFontEntry::RangeFlags;
+
+ WeightRange mWeight = WeightRange(FontWeight::NORMAL);
+ StretchRange mStretch = StretchRange(FontStretch::NORMAL);
+ SlantStyleRange mStyle = SlantStyleRange(FontSlantStyle::NORMAL);
+ RangeFlags mRangeFlags = RangeFlags::eAutoWeight | RangeFlags::eAutoStretch |
+ RangeFlags::eAutoSlantStyle;
+ mozilla::StyleFontDisplay mFontDisplay = mozilla::StyleFontDisplay::Auto;
+ float mAscentOverride = -1.0;
+ float mDescentOverride = -1.0;
+ float mLineGapOverride = -1.0;
+ float mSizeAdjust = 1.0;
+ uint32_t mLanguageOverride = NO_FONT_LANGUAGE_OVERRIDE;
+ nsTArray<gfxFontFeature> mFeatureSettings;
+ nsTArray<gfxFontVariation> mVariationSettings;
+ RefPtr<gfxCharacterMap> mUnicodeRanges;
+
+ nsCString mFamilyName;
+ AutoTArray<StyleFontFaceSourceListComponent, 8> mSources;
+};
+
+class gfxUserFontSet {
+ friend class gfxUserFontEntry;
+ friend class gfxOTSMessageContext;
+
+ public:
+ using FontStretch = mozilla::FontStretch;
+ using StretchRange = mozilla::StretchRange;
+ using FontSlantStyle = mozilla::FontSlantStyle;
+ using SlantStyleRange = mozilla::SlantStyleRange;
+ using FontWeight = mozilla::FontWeight;
+ using WeightRange = mozilla::WeightRange;
+ using RangeFlags = gfxFontEntry::RangeFlags;
+
+ NS_INLINE_DECL_PURE_VIRTUAL_REFCOUNTING
+
+ gfxUserFontSet();
+
+ void Destroy();
+
+ // creates a font face without adding it to a particular family
+ // weight - [100, 900] (multiples of 100)
+ // stretch = [FontStretch::UltraCondensed(), FontStretch::UltraExpanded()]
+ // italic style = constants in gfxFontConstants.h, e.g. NS_FONT_STYLE_NORMAL
+ // language override = result of calling
+ // nsLayoutUtils::ParseFontLanguageOverride
+ // TODO: support for unicode ranges not yet implemented
+ virtual already_AddRefed<gfxUserFontEntry> CreateUserFontEntry(
+ nsTArray<gfxFontFaceSrc>&& aFontFaceSrcList,
+ gfxUserFontAttributes&& aAttr) = 0;
+
+ // creates a font face for the specified family, or returns an existing
+ // matching entry on the family if there is one
+ already_AddRefed<gfxUserFontEntry> FindOrCreateUserFontEntry(
+ nsTArray<gfxFontFaceSrc>&& aFontFaceSrcList,
+ gfxUserFontAttributes&& aAttr);
+
+ // add in a font face for which we have the gfxUserFontEntry already
+ void AddUserFontEntry(const nsCString& aFamilyName,
+ gfxUserFontEntry* aUserFontEntry);
+
+ // Look up and return the gfxUserFontFamily in mFontFamilies with
+ // the given name
+ virtual already_AddRefed<gfxUserFontFamily> LookupFamily(
+ const nsACString& aName) const;
+
+ virtual already_AddRefed<gfxFontSrcPrincipal> GetStandardFontLoadPrincipal()
+ const = 0;
+ virtual nsPresContext* GetPresContext() const = 0;
+
+ // check whether content policies allow the given URI to load.
+ virtual bool IsFontLoadAllowed(const gfxFontFaceSrc&) = 0;
+
+ // initialize the process that loads external font data, which upon
+ // completion will call FontDataDownloadComplete method
+ virtual nsresult StartLoad(gfxUserFontEntry* aUserFontEntry,
+ uint32_t aSrcIndex) = 0;
+
+ // generation - each time a face is loaded, generation is
+ // incremented so that the change can be recognized
+ uint64_t GetGeneration() { return mGeneration; }
+
+ // increment the generation on font load
+ void IncrementGeneration(bool aIsRebuild = false);
+
+ // Generation is bumped on font loads but that doesn't affect name-style
+ // mappings. Rebuilds do however affect name-style mappings so need to
+ // lookup fontlists again when that happens.
+ uint64_t GetRebuildGeneration() { return mRebuildGeneration; }
+
+ // rebuild if local rules have been used
+ void RebuildLocalRules();
+
+ // Discard any font entries created for src:local(), so that they will
+ // be reloaded next time they're needed. This is called when the platform
+ // font list has changed, which means local font entries that were set up
+ // may no longer be valid.
+ virtual void ForgetLocalFaces();
+
+ class UserFontCache {
+ public:
+ // Record a loaded user-font in the cache. This requires that the
+ // font-entry's userFontData has been set up already, as it relies
+ // on the URI and Principal recorded there.
+ static void CacheFont(gfxFontEntry* aFontEntry);
+
+ // The given gfxFontEntry is being destroyed, so remove any record that
+ // refers to it.
+ static void ForgetFont(gfxFontEntry* aFontEntry);
+
+ // Return the gfxFontEntry corresponding to a given URI and principal,
+ // and the features of the given userfont entry, or nullptr if none is
+ // available. The aPrivate flag is set for requests coming from private
+ // windows, so we can avoid leaking fonts cached in private windows mode out
+ // to normal windows.
+ static gfxFontEntry* GetFont(const gfxFontFaceSrc&,
+ const gfxUserFontEntry&);
+
+ // Clear everything so that we don't leak URIs and Principals.
+ static void Shutdown();
+
+ // Memory-reporting support.
+ class MemoryReporter final : public nsIMemoryReporter {
+ private:
+ ~MemoryReporter() = default;
+
+ public:
+ NS_DECL_ISUPPORTS
+ NS_DECL_NSIMEMORYREPORTER
+ };
+
+#ifdef DEBUG_USERFONT_CACHE
+ // dump contents
+ static void Dump();
+#endif
+
+ private:
+ // Helper that we use to observe the empty-cache notification
+ // from nsICacheService.
+ class Flusher : public nsIObserver {
+ virtual ~Flusher() = default;
+
+ public:
+ NS_DECL_ISUPPORTS
+ NS_DECL_NSIOBSERVER
+ Flusher() = default;
+ };
+
+ // Key used to look up entries in the user-font cache.
+ // Note that key comparison does *not* use the mFontEntry field
+ // as a whole; it only compares specific fields within the entry
+ // (weight/width/style/features) that could affect font selection
+ // or rendering, and that must match between a font-set's userfont
+ // entry and the corresponding "real" font entry.
+ struct Key {
+ RefPtr<gfxFontSrcURI> mURI;
+ RefPtr<gfxFontSrcPrincipal> mPrincipal; // use nullptr with data: URLs
+ // The font entry MUST notify the cache when it is destroyed
+ // (by calling ForgetFont()).
+ gfxFontEntry* MOZ_NON_OWNING_REF mFontEntry;
+ bool mPrivate;
+
+ Key(gfxFontSrcURI* aURI, gfxFontSrcPrincipal* aPrincipal,
+ gfxFontEntry* aFontEntry, bool aPrivate)
+ : mURI(aURI),
+ mPrincipal(aPrincipal),
+ mFontEntry(aFontEntry),
+ mPrivate(aPrivate) {}
+ };
+
+ class Entry : public PLDHashEntryHdr {
+ public:
+ typedef const Key& KeyType;
+ typedef const Key* KeyTypePointer;
+
+ explicit Entry(KeyTypePointer aKey)
+ : mURI(aKey->mURI),
+ mPrincipal(aKey->mPrincipal),
+ mFontEntry(aKey->mFontEntry),
+ mPrivate(aKey->mPrivate) {}
+
+ Entry(Entry&& aOther)
+ : PLDHashEntryHdr(std::move(aOther)),
+ mURI(std::move(aOther.mURI)),
+ mPrincipal(std::move(aOther.mPrincipal)),
+ mFontEntry(std::move(aOther.mFontEntry)),
+ mPrivate(std::move(aOther.mPrivate)) {}
+
+ ~Entry() = default;
+
+ bool KeyEquals(const KeyTypePointer aKey) const;
+
+ static KeyTypePointer KeyToPointer(KeyType aKey) { return &aKey; }
+
+ static PLDHashNumber HashKey(const KeyTypePointer aKey) {
+ PLDHashNumber principalHash =
+ aKey->mPrincipal ? aKey->mPrincipal->Hash() : 0;
+ return mozilla::HashGeneric(
+ principalHash + int(aKey->mPrivate), aKey->mURI->Hash(),
+ HashFeatures(aKey->mFontEntry->mFeatureSettings),
+ HashVariations(aKey->mFontEntry->mVariationSettings),
+ mozilla::HashString(aKey->mFontEntry->mFamilyName),
+ aKey->mFontEntry->Weight().AsScalar(),
+ aKey->mFontEntry->SlantStyle().AsScalar(),
+ aKey->mFontEntry->Stretch().AsScalar(),
+ aKey->mFontEntry->mRangeFlags, aKey->mFontEntry->mLanguageOverride);
+ }
+
+ enum { ALLOW_MEMMOVE = false };
+
+ gfxFontSrcURI* GetURI() const { return mURI; }
+ gfxFontSrcPrincipal* GetPrincipal() const { return mPrincipal; }
+ gfxFontEntry* GetFontEntry() const { return mFontEntry; }
+ bool IsPrivate() const { return mPrivate; }
+
+ void ReportMemory(nsIHandleReportCallback* aHandleReport,
+ nsISupports* aData, bool aAnonymize);
+
+#ifdef DEBUG_USERFONT_CACHE
+ void Dump();
+#endif
+
+ private:
+ static uint32_t HashFeatures(const nsTArray<gfxFontFeature>& aFeatures) {
+ return mozilla::HashBytes(aFeatures.Elements(),
+ aFeatures.Length() * sizeof(gfxFontFeature));
+ }
+
+ static uint32_t HashVariations(
+ const nsTArray<mozilla::gfx::FontVariation>& aVariations) {
+ return mozilla::HashBytes(
+ aVariations.Elements(),
+ aVariations.Length() * sizeof(mozilla::gfx::FontVariation));
+ }
+
+ RefPtr<gfxFontSrcURI> mURI;
+ RefPtr<gfxFontSrcPrincipal> mPrincipal; // or nullptr for data: URLs
+
+ // The "real" font entry corresponding to this downloaded font.
+ // The font entry MUST notify the cache when it is destroyed
+ // (by calling ForgetFont()).
+ gfxFontEntry* MOZ_NON_OWNING_REF mFontEntry;
+
+ // Whether this font was loaded from a private window.
+ bool mPrivate;
+ };
+
+ static nsTHashtable<Entry>* sUserFonts;
+ };
+
+ void SetLocalRulesUsed() { mLocalRulesUsed = true; }
+
+ static mozilla::LogModule* GetUserFontsLog();
+
+ // record statistics about font completion
+ virtual void RecordFontLoadDone(uint32_t aFontSize,
+ mozilla::TimeStamp aDoneTime) {}
+
+ void GetLoadStatistics(uint32_t& aLoadCount, uint64_t& aLoadSize) const {
+ aLoadCount = mDownloadCount;
+ aLoadSize = mDownloadSize;
+ }
+
+ protected:
+ // Protected destructor, to discourage deletion outside of Release():
+ virtual ~gfxUserFontSet();
+
+ // Return whether the font set is associated with a private-browsing tab.
+ virtual bool GetPrivateBrowsing() = 0;
+
+ // Return whether the font set is associated with a document that was
+ // shift-reloaded, for example, and thus should bypass the font cache.
+ virtual bool BypassCache() = 0;
+
+ // parse data for a data URL
+ virtual nsresult SyncLoadFontData(gfxUserFontEntry* aFontToLoad,
+ const gfxFontFaceSrc* aFontFaceSrc,
+ uint8_t*& aBuffer,
+ uint32_t& aBufferLength) = 0;
+
+ // report a problem of some kind (implemented in nsUserFontSet)
+ virtual nsresult LogMessage(gfxUserFontEntry* aUserFontEntry,
+ uint32_t aSrcIndex, const char* aMessage,
+ uint32_t aFlags = nsIScriptError::errorFlag,
+ nsresult aStatus = NS_OK) = 0;
+
+ // helper method for performing the actual userfont set rebuild
+ virtual void DoRebuildUserFontSet() = 0;
+
+ // helper method for FindOrCreateUserFontEntry
+ gfxUserFontEntry* FindExistingUserFontEntry(
+ gfxUserFontFamily* aFamily,
+ const nsTArray<gfxFontFaceSrc>& aFontFaceSrcList,
+ const gfxUserFontAttributes& aAttr);
+
+ // creates a new gfxUserFontFamily in mFontFamilies, or returns an existing
+ // family if there is one
+ virtual already_AddRefed<gfxUserFontFamily> GetFamily(
+ const nsACString& aFamilyName);
+
+ void ForgetLocalFace(gfxUserFontFamily* aFontFamily);
+
+ // font families defined by @font-face rules
+ nsRefPtrHashtable<nsCStringHashKey, gfxUserFontFamily> mFontFamilies;
+
+ uint64_t mGeneration; // bumped on any font load change
+ uint64_t mRebuildGeneration; // only bumped on rebuilds
+
+ // true when local names have been looked up, false otherwise
+ bool mLocalRulesUsed;
+
+ // true when rules using local names need to be redone
+ bool mRebuildLocalRules;
+
+ // performance stats
+ uint32_t mDownloadCount;
+ uint64_t mDownloadSize;
+};
+
+// acts a placeholder until the real font is downloaded
+
+class gfxUserFontEntry : public gfxFontEntry {
+ friend class mozilla::PostTraversalTask;
+ friend class gfxUserFontSet;
+ friend class nsUserFontSet;
+ friend class nsFontFaceLoader;
+ friend class gfxOTSMessageContext;
+
+ public:
+ enum UserFontLoadState {
+ STATUS_NOT_LOADED = 0,
+ STATUS_LOAD_PENDING,
+ STATUS_LOADING,
+ STATUS_LOADED,
+ STATUS_FAILED
+ };
+
+ gfxUserFontEntry(nsTArray<gfxFontFaceSrc>&& aFontFaceSrcList,
+ gfxUserFontAttributes&& aAttr);
+
+ ~gfxUserFontEntry() override;
+
+ // Update the attributes of the entry to the given values, without disturbing
+ // the associated platform font entry or in-progress downloads.
+ void UpdateAttributes(gfxUserFontAttributes&& aAttr);
+
+ // Return whether the entry matches the given list of attributes
+ bool Matches(const nsTArray<gfxFontFaceSrc>& aFontFaceSrcList,
+ const gfxUserFontAttributes& aAttr);
+
+ gfxFont* CreateFontInstance(const gfxFontStyle* aFontStyle) override;
+
+ gfxFontEntry* GetPlatformFontEntry() const { return mPlatformFontEntry; }
+
+ // is the font loading or loaded, or did it fail?
+ UserFontLoadState LoadState() const { return mUserFontLoadState; }
+
+ void LoadCanceled() {
+ MOZ_ASSERT(NS_IsMainThread());
+
+ mUserFontLoadState = STATUS_NOT_LOADED;
+ mFontDataLoadingState = NOT_LOADING;
+ mLoader = nullptr;
+ // Reset mCurrentSrcIndex so that all potential sources are re-considered.
+ mCurrentSrcIndex = 0;
+ mSeenLocalSource = false;
+ }
+
+ // whether to wait before using fallback font or not
+ bool WaitForUserFont() const {
+ return (mUserFontLoadState == STATUS_LOAD_PENDING ||
+ mUserFontLoadState == STATUS_LOADING) &&
+ mFontDataLoadingState < LOADING_SLOWLY;
+ }
+
+ // For userfonts, cmap is used to store the unicode range data,
+ // and is inert once set, so locking is not required here.
+ // no cmap ==> all codepoints permitted
+ bool CharacterInUnicodeRange(uint32_t ch) const {
+ if (const auto* map = GetUnicodeRangeMap()) {
+ return map->test(ch);
+ }
+ return true;
+ }
+
+ gfxCharacterMap* GetUnicodeRangeMap() const { return GetCharacterMap(); }
+ void SetUnicodeRangeMap(RefPtr<gfxCharacterMap>&& aCharMap) {
+ auto* oldCmap = GetUnicodeRangeMap();
+ if (oldCmap != aCharMap) {
+ auto* newCmap = aCharMap.forget().take();
+ if (mCharacterMap.compareExchange(oldCmap, newCmap)) {
+ NS_IF_RELEASE(oldCmap);
+ } else {
+ NS_IF_RELEASE(newCmap);
+ }
+ }
+ }
+
+ mozilla::StyleFontDisplay GetFontDisplay() const { return mFontDisplay; }
+
+ // load the font - starts the loading of sources which continues until
+ // a valid font resource is found or all sources fail
+ void Load();
+
+ // methods to expose some information to FontFaceSet::UserFontSet
+ // since we can't make that class a friend
+ void SetLoader(nsFontFaceLoader* aLoader) {
+ MOZ_ASSERT(NS_IsMainThread());
+ mLoader = aLoader;
+ }
+
+ nsFontFaceLoader* GetLoader() const {
+ MOZ_ASSERT(NS_IsMainThread());
+ return mLoader;
+ }
+
+ gfxFontSrcPrincipal* GetPrincipal() const { return mPrincipal; }
+ void GetFamilyNameAndURIForLogging(uint32_t aSrcIndex,
+ nsACString& aFamilyName, nsACString& aURI);
+
+ gfxFontEntry* Clone() const override {
+ MOZ_ASSERT_UNREACHABLE("cannot Clone user fonts");
+ return nullptr;
+ }
+
+ virtual already_AddRefed<gfxUserFontSet> GetUserFontSet() const = 0;
+
+ const nsTArray<gfxFontFaceSrc>& SourceList() const { return mSrcList; }
+
+ // Returns a weak reference to the requested source record, which is owned
+ // by the gfxUserFontEntry.
+ const gfxFontFaceSrc& SourceAt(uint32_t aSrcIndex) const {
+ return mSrcList[aSrcIndex];
+ }
+
+ // The variation-query APIs should not be called on placeholders.
+ bool HasVariations() override {
+ MOZ_ASSERT_UNREACHABLE("not meaningful for a userfont placeholder");
+ return false;
+ }
+ void GetVariationAxes(nsTArray<gfxFontVariationAxis>&) override {
+ MOZ_ASSERT_UNREACHABLE("not meaningful for a userfont placeholder");
+ }
+ void GetVariationInstances(nsTArray<gfxFontVariationInstance>&) override {
+ MOZ_ASSERT_UNREACHABLE("not meaningful for a userfont placeholder");
+ }
+
+ protected:
+ struct OTSMessage {
+ nsCString mMessage;
+ int mLevel; // see OTSContext in gfx/ots/include/opentype-sanitizer.h
+ };
+
+ const uint8_t* SanitizeOpenTypeData(const uint8_t* aData, uint32_t aLength,
+ uint32_t& aSanitaryLength,
+ gfxUserFontType& aFontType,
+ nsTArray<OTSMessage>& aMessages);
+
+ // attempt to load the next resource in the src list.
+ void LoadNextSrc();
+ void ContinueLoad();
+ void DoLoadNextSrc(bool aIsContinue);
+
+ // change the load state
+ virtual void SetLoadState(UserFontLoadState aLoadState);
+
+ // when download has been completed, pass back data here
+ // aDownloadStatus == NS_OK ==> download succeeded, error otherwise
+ // Ownership of aFontData is passed in here; the font set must
+ // ensure that it is eventually deleted with free().
+ void FontDataDownloadComplete(uint32_t aSrcIndex, const uint8_t* aFontData,
+ uint32_t aLength, nsresult aDownloadStatus,
+ nsIFontLoadCompleteCallback* aCallback);
+
+ // helper method for creating a platform font
+ // returns true if platform font creation successful
+ // Ownership of aFontData is passed in here; the font must
+ // ensure that it is eventually deleted with free().
+ bool LoadPlatformFontSync(uint32_t aSrcIndex, const uint8_t* aFontData,
+ uint32_t aLength);
+
+ void LoadPlatformFontAsync(uint32_t aSrcIndex, const uint8_t* aFontData,
+ uint32_t aLength,
+ nsIFontLoadCompleteCallback* aCallback);
+
+ // helper method for LoadPlatformFontAsync; runs on a background thread
+ void StartPlatformFontLoadOnBackgroundThread(
+ uint32_t aSrcIndex, const uint8_t* aFontData, uint32_t aLength,
+ nsMainThreadPtrHandle<nsIFontLoadCompleteCallback> aCallback);
+
+ // helper method for LoadPlatformFontAsync; runs on the main thread
+ void ContinuePlatformFontLoadOnMainThread(
+ uint32_t aSrcIndex, const uint8_t* aOriginalFontData,
+ uint32_t aOriginalLength, gfxUserFontType aFontType,
+ const uint8_t* aSanitizedFontData, uint32_t aSanitizedLength,
+ nsTArray<OTSMessage>&& aMessages,
+ nsMainThreadPtrHandle<nsIFontLoadCompleteCallback> aCallback);
+
+ // helper method for LoadPlatformFontSync and
+ // ContinuePlatformFontLoadOnMainThread; runs on the main thread
+ bool LoadPlatformFont(uint32_t aSrcIndex, const uint8_t* aOriginalFontData,
+ uint32_t aOriginalLength, gfxUserFontType aFontType,
+ const uint8_t* aSanitizedFontData,
+ uint32_t aSanitizedLength,
+ nsTArray<OTSMessage>&& aMessages);
+
+ // helper method for FontDataDownloadComplete and
+ // ContinuePlatformFontLoadOnMainThread; runs on the main thread
+ void FontLoadFailed(nsIFontLoadCompleteCallback* aCallback);
+
+ // store metadata and src details for current src into aFontEntry
+ void StoreUserFontData(gfxFontEntry* aFontEntry, uint32_t aSrcIndex,
+ bool aPrivate, const nsACString& aOriginalName,
+ FallibleTArray<uint8_t>* aMetadata,
+ uint32_t aMetaOrigLen, uint8_t aCompression);
+
+ // Clears and then adds to aResult all of the user font sets that this user
+ // font entry has been added to. This will at least include the owner of this
+ // user font entry.
+ virtual void GetUserFontSets(nsTArray<RefPtr<gfxUserFontSet>>& aResult);
+
+ // Calls IncrementGeneration() on all user font sets that contain this
+ // user font entry.
+ void IncrementGeneration();
+
+ // general load state
+ UserFontLoadState mUserFontLoadState;
+
+ // detailed load state while font data is loading
+ // used to determine whether to use fallback font or not
+ // note that code depends on the ordering of these values!
+ enum FontDataLoadingState {
+ NOT_LOADING = 0, // not started to load any font resources yet
+ LOADING_STARTED, // loading has started; hide fallback font
+ LOADING_ALMOST_DONE, // timeout happened but we're nearly done,
+ // so keep hiding fallback font
+ LOADING_SLOWLY, // timeout happened and we're not nearly done,
+ // so use the fallback font
+ LOADING_TIMED_OUT, // font load took too long
+ LOADING_FAILED // failed to load any source: use fallback
+ };
+ FontDataLoadingState mFontDataLoadingState;
+
+ bool mSeenLocalSource;
+ bool mUnsupportedFormat;
+ mozilla::StyleFontDisplay mFontDisplay; // timing of userfont fallback
+
+ RefPtr<gfxFontEntry> mPlatformFontEntry;
+ nsTArray<gfxFontFaceSrc> mSrcList;
+ uint32_t mCurrentSrcIndex; // index of src item to be loaded next
+ // This field is managed by the nsFontFaceLoader. In the destructor and
+ // Cancel() methods of nsFontFaceLoader this reference is nulled out.
+ nsFontFaceLoader* MOZ_NON_OWNING_REF
+ mLoader; // current loader for this entry, if any
+ RefPtr<gfxUserFontSet> mLoadingFontSet;
+ RefPtr<gfxFontSrcPrincipal> mPrincipal;
+};
+
+#endif /* GFX_USER_FONT_SET_H */