/* -*- 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_dom_FontFaceSetImpl_h #define mozilla_dom_FontFaceSetImpl_h #include "mozilla/dom/FontFace.h" #include "mozilla/dom/FontFaceSetBinding.h" #include "mozilla/DOMEventTargetHelper.h" #include "mozilla/FontPropertyTypes.h" #include "mozilla/RecursiveMutex.h" #include "gfxUserFontSet.h" #include "nsICSSLoaderObserver.h" #include "nsIDOMEventListener.h" #include struct gfxFontFaceSrc; class gfxFontSrcPrincipal; class gfxUserFontEntry; class nsFontFaceLoader; class nsIChannel; class nsIPrincipal; class nsPIDOMWindowInner; namespace mozilla { struct StyleLockedFontFaceRule; class PostTraversalTask; class Runnable; class SharedFontList; namespace dom { class FontFace; } // namespace dom } // namespace mozilla namespace mozilla::dom { class FontFaceSetImpl : public nsISupports, public gfxUserFontSet { NS_DECL_THREADSAFE_ISUPPORTS public: // gfxUserFontSet already_AddRefed GetStandardFontLoadPrincipal() const final; void RecordFontLoadDone(uint32_t aFontSize, TimeStamp aDoneTime) override; bool BypassCache() final { return mBypassCache; } void ForgetLocalFaces() final; protected: virtual nsresult CreateChannelForSyncLoadFontData( nsIChannel** aOutChannel, gfxUserFontEntry* aFontToLoad, const gfxFontFaceSrc* aFontFaceSrc) = 0; // gfxUserFontSet bool GetPrivateBrowsing() override { return mPrivateBrowsing; } nsresult SyncLoadFontData(gfxUserFontEntry* aFontToLoad, const gfxFontFaceSrc* aFontFaceSrc, uint8_t*& aBuffer, uint32_t& aBufferLength) override; nsresult LogMessage(gfxUserFontEntry* aUserFontEntry, uint32_t aSrcIndex, const char* aMessage, uint32_t aFlags = nsIScriptError::errorFlag, nsresult aStatus = NS_OK) override; void DoRebuildUserFontSet() override; already_AddRefed CreateUserFontEntry( nsTArray&& aFontFaceSrcList, gfxUserFontAttributes&& aAttr) override; already_AddRefed GetFamily( const nsACString& aFamilyName) final; explicit FontFaceSetImpl(FontFaceSet* aOwner); void DestroyLoaders(); public: virtual void Destroy(); virtual bool IsOnOwningThread() = 0; #ifdef DEBUG virtual void AssertIsOnOwningThread() = 0; #else void AssertIsOnOwningThread() {} #endif virtual void DispatchToOwningThread(const char* aName, std::function&& aFunc) = 0; // Called by nsFontFaceLoader when the loader has completed normally. // It's removed from the mLoaders set. virtual void RemoveLoader(nsFontFaceLoader* aLoader); virtual bool UpdateRules(const nsTArray& aRules) { MOZ_ASSERT_UNREACHABLE("Not implemented!"); return false; } // search for @font-face rule that matches a platform font entry virtual StyleLockedFontFaceRule* FindRuleForEntry(gfxFontEntry* aFontEntry) { MOZ_ASSERT_UNREACHABLE("Not implemented!"); return nullptr; } /** * Finds an existing entry in the user font cache or creates a new user * font entry for the given FontFace object. */ static already_AddRefed FindOrCreateUserFontEntryFromFontFace(FontFaceImpl* aFontFace, gfxUserFontAttributes&& aAttr, StyleOrigin); /** * Notification method called by a FontFace to indicate that its loading * status has changed. */ virtual void OnFontFaceStatusChanged(FontFaceImpl* aFontFace); /** * Notification method called by the nsPresContext to indicate that the * refresh driver ticked and flushed style and layout. * were just flushed. */ virtual void DidRefresh() { MOZ_ASSERT_UNREACHABLE("Not implemented!"); } virtual void FlushUserFontSet() = 0; static nsPresContext* GetPresContextFor(gfxUserFontSet* aUserFontSet) { const auto* set = static_cast(aUserFontSet); return set ? set->GetPresContext() : nullptr; } virtual void RefreshStandardFontLoadPrincipal(); virtual dom::Document* GetDocument() const { return nullptr; } virtual already_AddRefed GetURLExtraData() = 0; // -- Web IDL -------------------------------------------------------------- virtual void EnsureReady() {} dom::FontFaceSetLoadStatus Status(); virtual bool Add(FontFaceImpl* aFontFace, ErrorResult& aRv); virtual void Clear(); virtual bool Delete(FontFaceImpl* aFontFace); // For ServoStyleSet to know ahead of time whether a font is loadable. virtual void CacheFontLoadability() { MOZ_ASSERT_UNREACHABLE("Not implemented!"); } virtual void MarkUserFontSetDirty() {} /** * Checks to see whether it is time to resolve mReady and dispatch any * "loadingdone" and "loadingerror" events. */ virtual void CheckLoadingFinished(); virtual void FindMatchingFontFaces(const nsACString& aFont, const nsAString& aText, nsTArray& aFontFaces, ErrorResult& aRv); virtual void DispatchCheckLoadingFinishedAfterDelay(); protected: ~FontFaceSetImpl() override; virtual uint64_t GetInnerWindowID() = 0; /** * Returns whether the given FontFace is currently "in" the FontFaceSet. */ bool HasAvailableFontFace(FontFaceImpl* aFontFace); /** * Returns whether there might be any pending font loads, which should cause * the mReady Promise not to be resolved yet. */ virtual bool MightHavePendingFontLoads(); /** * Checks to see whether it is time to replace mReady and dispatch a * "loading" event. */ void CheckLoadingStarted(); /** * Callback for invoking CheckLoadingFinished after going through the * event loop. See OnFontFaceStatusChanged. */ void CheckLoadingFinishedAfterDelay(); void OnLoadingStarted(); void OnLoadingFinished(); // Note: if you add new cycle collected objects to FontFaceRecord, // make sure to update FontFaceSet's cycle collection macros // accordingly. struct FontFaceRecord { RefPtr mFontFace; Maybe mOrigin; // only relevant for mRuleFaces entries }; // search for @font-face rule that matches a userfont font entry virtual StyleLockedFontFaceRule* FindRuleForUserFontEntry( gfxUserFontEntry* aUserFontEntry) { return nullptr; } virtual void FindMatchingFontFaces( const nsTHashSet& aMatchingFaces, nsTArray& aFontFaces); class UpdateUserFontEntryRunnable; void UpdateUserFontEntry(gfxUserFontEntry* aEntry, gfxUserFontAttributes&& aAttr); nsresult CheckFontLoad(const gfxFontFaceSrc* aFontFaceSrc, gfxFontSrcPrincipal** aPrincipal, bool* aBypassCache); void InsertNonRuleFontFace(FontFaceImpl* aFontFace); /** * Returns whether we have any loading FontFace objects in the FontFaceSet. */ bool HasLoadingFontFaces(); // Whether mReady is pending, or would be when created. bool ReadyPromiseIsPending() const; // Helper function for HasLoadingFontFaces. virtual void UpdateHasLoadingFontFaces(); void ParseFontShorthandForMatching(const nsACString& aFont, StyleFontFamilyList& aFamilyList, FontWeight& aWeight, FontStretch& aStretch, FontSlantStyle& aStyle, ErrorResult& aRv); virtual TimeStamp GetNavigationStartTimeStamp() = 0; mutable RecursiveMutex mMutex; FontFaceSet* MOZ_NON_OWNING_REF mOwner MOZ_GUARDED_BY(mMutex); // The document's node principal, which is the principal font loads for // this FontFaceSet will generally use. (This principal is not used for // @font-face rules in UA and user sheets, where the principal of the // sheet is used instead.) // // This field is used from GetStandardFontLoadPrincipal. When on a // style worker thread, we use mStandardFontLoadPrincipal assuming // it is up to date. // // Because mDocument's principal can change over time, // its value must be updated by a call to ResetStandardFontLoadPrincipal. mutable RefPtr mStandardFontLoadPrincipal MOZ_GUARDED_BY(mMutex); // Set of all loaders pointing to us. These are not strong pointers, // but that's OK because nsFontFaceLoader always calls RemoveLoader on // us before it dies (unless we die first). nsTHashtable> mLoaders MOZ_GUARDED_BY(mMutex); // The non rule backed FontFace objects that have been added to this // FontFaceSet. nsTArray mNonRuleFaces MOZ_GUARDED_BY(mMutex); // The overall status of the loading or loaded fonts in the FontFaceSet. dom::FontFaceSetLoadStatus mStatus MOZ_GUARDED_BY(mMutex); // A map from gfxFontFaceSrc pointer identity to whether the load is allowed // by CSP or other checks. We store this here because querying CSP off the // main thread is not a great idea. // // We could use just the pointer and use this as a hash set, but then we'd // have no way to verify that we've checked all the loads we should. nsTHashMap, bool> mAllowedFontLoads MOZ_GUARDED_BY(mMutex); // Whether mNonRuleFaces has changed since last time UpdateRules ran. bool mNonRuleFacesDirty MOZ_GUARDED_BY(mMutex); // Whether any FontFace objects in mRuleFaces or mNonRuleFaces are // loading. Only valid when mHasLoadingFontFacesIsDirty is false. Don't use // this variable directly; call the HasLoadingFontFaces method instead. bool mHasLoadingFontFaces MOZ_GUARDED_BY(mMutex); // This variable is only valid when mLoadingDirty is false. bool mHasLoadingFontFacesIsDirty MOZ_GUARDED_BY(mMutex); // Whether CheckLoadingFinished calls should be ignored. See comment in // OnFontFaceStatusChanged. bool mDelayedLoadCheck MOZ_GUARDED_BY(mMutex); // Whether the docshell for our document indicated that loads should // bypass the cache. bool mBypassCache; // Whether the docshell for our document indicates that we are in private // browsing mode. bool mPrivateBrowsing; }; } // namespace mozilla::dom #endif // !defined(mozilla_dom_FontFaceSetImpl_h)