diff options
Diffstat (limited to 'gfx/thebes/gfxUserFontSet.h')
-rw-r--r-- | gfx/thebes/gfxUserFontSet.h | 792 |
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..42914d409f --- /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->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& aSaneLength, + gfxUserFontType& aFontType, + nsTArray<OTSMessage>& aMessages); + + // attempt to load the next resource in the src list. + void LoadNextSrc(); + void ContinueLoad(); + void DoLoadNextSrc(bool aForceAsync); + + // 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 */ |