summaryrefslogtreecommitdiffstats
path: root/layout/style/FontFaceSet.h
diff options
context:
space:
mode:
Diffstat (limited to 'layout/style/FontFaceSet.h')
-rw-r--r--layout/style/FontFaceSet.h356
1 files changed, 356 insertions, 0 deletions
diff --git a/layout/style/FontFaceSet.h b/layout/style/FontFaceSet.h
new file mode 100644
index 000000000..eafbd514e
--- /dev/null
+++ b/layout/style/FontFaceSet.h
@@ -0,0 +1,356 @@
+/* -*- Mode: C++; tab-width: 2; 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 mozilla_dom_FontFaceSet_h
+#define mozilla_dom_FontFaceSet_h
+
+#include "mozilla/dom/FontFace.h"
+#include "mozilla/dom/FontFaceSetBinding.h"
+#include "mozilla/DOMEventTargetHelper.h"
+#include "gfxUserFontSet.h"
+#include "nsCSSRules.h"
+#include "nsICSSLoaderObserver.h"
+
+struct gfxFontFaceSrc;
+class gfxUserFontEntry;
+class nsFontFaceLoader;
+class nsIPrincipal;
+class nsPIDOMWindowInner;
+
+namespace mozilla {
+namespace css {
+class FontFamilyListRefCnt;
+} // namespace css
+namespace dom {
+class FontFace;
+class Promise;
+} // namespace dom
+} // namespace mozilla
+
+namespace mozilla {
+namespace dom {
+
+class FontFaceSet final : public DOMEventTargetHelper
+ , public nsIDOMEventListener
+ , public nsICSSLoaderObserver
+{
+ friend class UserFontSet;
+
+public:
+ /**
+ * A gfxUserFontSet that integrates with the layout and style systems to
+ * manage @font-face rules and handle network requests for font loading.
+ *
+ * We would combine this class and FontFaceSet into the one class if it were
+ * possible; it's not because FontFaceSet is cycle collected and
+ * gfxUserFontSet isn't (and can't be, as gfx classes don't use the cycle
+ * collector). So UserFontSet exists just to override the needed virtual
+ * methods from gfxUserFontSet and to forward them on FontFaceSet.
+ */
+ class UserFontSet final : public gfxUserFontSet
+ {
+ friend class FontFaceSet;
+
+ public:
+ explicit UserFontSet(FontFaceSet* aFontFaceSet)
+ : mFontFaceSet(aFontFaceSet)
+ {
+ }
+
+ FontFaceSet* GetFontFaceSet() { return mFontFaceSet; }
+
+ virtual nsresult CheckFontLoad(const gfxFontFaceSrc* aFontFaceSrc,
+ nsIPrincipal** aPrincipal,
+ bool* aBypassCache) override;
+
+ virtual bool IsFontLoadAllowed(nsIURI* aFontLocation,
+ nsIPrincipal* aPrincipal) override;
+
+ virtual nsresult StartLoad(gfxUserFontEntry* aUserFontEntry,
+ const gfxFontFaceSrc* aFontFaceSrc) override;
+
+ void RecordFontLoadDone(uint32_t aFontSize,
+ mozilla::TimeStamp aDoneTime) override;
+
+ protected:
+ virtual bool GetPrivateBrowsing() override;
+ virtual nsresult SyncLoadFontData(gfxUserFontEntry* aFontToLoad,
+ const gfxFontFaceSrc* aFontFaceSrc,
+ uint8_t*& aBuffer,
+ uint32_t& aBufferLength) override;
+ virtual nsresult LogMessage(gfxUserFontEntry* aUserFontEntry,
+ const char* aMessage,
+ uint32_t aFlags = nsIScriptError::errorFlag,
+ nsresult aStatus = NS_OK) override;
+ virtual void DoRebuildUserFontSet() override;
+ virtual already_AddRefed<gfxUserFontEntry> CreateUserFontEntry(
+ const nsTArray<gfxFontFaceSrc>& aFontFaceSrcList,
+ uint32_t aWeight,
+ int32_t aStretch,
+ uint8_t aStyle,
+ const nsTArray<gfxFontFeature>& aFeatureSettings,
+ uint32_t aLanguageOverride,
+ gfxSparseBitSet* aUnicodeRanges,
+ uint8_t aFontDisplay) override;
+
+ private:
+ RefPtr<FontFaceSet> mFontFaceSet;
+ };
+
+ NS_DECL_ISUPPORTS_INHERITED
+ NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(FontFaceSet, DOMEventTargetHelper)
+ NS_DECL_NSIDOMEVENTLISTENER
+
+ FontFaceSet(nsPIDOMWindowInner* aWindow, nsIDocument* aDocument);
+
+ virtual JSObject* WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto) override;
+
+ UserFontSet* GetUserFontSet() { return mUserFontSet; }
+
+ // Called by nsFontFaceLoader when the loader has completed normally.
+ // It's removed from the mLoaders set.
+ void RemoveLoader(nsFontFaceLoader* aLoader);
+
+ bool UpdateRules(const nsTArray<nsFontFaceRuleContainer>& aRules);
+
+ nsPresContext* GetPresContext();
+
+ // search for @font-face rule that matches a platform font entry
+ nsCSSFontFaceRule* FindRuleForEntry(gfxFontEntry* aFontEntry);
+
+ void IncrementGeneration(bool aIsRebuild = false);
+
+ /**
+ * Finds an existing entry in the user font cache or creates a new user
+ * font entry for the given FontFace object.
+ */
+ static already_AddRefed<gfxUserFontEntry>
+ FindOrCreateUserFontEntryFromFontFace(FontFace* aFontFace);
+
+ /**
+ * Notification method called by a FontFace to indicate that its loading
+ * status has changed.
+ */
+ void OnFontFaceStatusChanged(FontFace* aFontFace);
+
+ /**
+ * Notification method called by the nsPresContext to indicate that the
+ * refresh driver ticked and flushed style and layout.
+ * were just flushed.
+ */
+ void DidRefresh();
+
+ /**
+ * Returns whether the "layout.css.font-loading-api.enabled" pref is true.
+ */
+ static bool PrefEnabled();
+
+ // nsICSSLoaderObserver
+ NS_IMETHOD StyleSheetLoaded(mozilla::StyleSheet* aSheet,
+ bool aWasAlternate,
+ nsresult aStatus) override;
+
+ FontFace* GetFontFaceAt(uint32_t aIndex);
+
+ void FlushUserFontSet();
+
+ static nsPresContext* GetPresContextFor(gfxUserFontSet* aUserFontSet)
+ {
+ FontFaceSet* set = static_cast<UserFontSet*>(aUserFontSet)->mFontFaceSet;
+ return set ? set->GetPresContext() : nullptr;
+ }
+
+ // -- Web IDL --------------------------------------------------------------
+
+ IMPL_EVENT_HANDLER(loading)
+ IMPL_EVENT_HANDLER(loadingdone)
+ IMPL_EVENT_HANDLER(loadingerror)
+ already_AddRefed<mozilla::dom::Promise> Load(JSContext* aCx,
+ const nsAString& aFont,
+ const nsAString& aText,
+ mozilla::ErrorResult& aRv);
+ bool Check(const nsAString& aFont,
+ const nsAString& aText,
+ mozilla::ErrorResult& aRv);
+ mozilla::dom::Promise* GetReady(mozilla::ErrorResult& aRv);
+ mozilla::dom::FontFaceSetLoadStatus Status();
+
+ FontFaceSet* Add(FontFace& aFontFace, mozilla::ErrorResult& aRv);
+ void Clear();
+ bool Delete(FontFace& aFontFace);
+ bool Has(FontFace& aFontFace);
+ uint32_t Size();
+ already_AddRefed<mozilla::dom::FontFaceSetIterator> Entries();
+ already_AddRefed<mozilla::dom::FontFaceSetIterator> Values();
+ void ForEach(JSContext* aCx, FontFaceSetForEachCallback& aCallback,
+ JS::Handle<JS::Value> aThisArg,
+ mozilla::ErrorResult& aRv);
+
+private:
+ ~FontFaceSet();
+
+ /**
+ * Returns whether the given FontFace is currently "in" the FontFaceSet.
+ */
+ bool HasAvailableFontFace(FontFace* aFontFace);
+
+ /**
+ * Removes any listeners and observers.
+ */
+ void Disconnect();
+
+ void RemoveDOMContentLoadedListener();
+
+ /**
+ * Returns whether there might be any pending font loads, which should cause
+ * the mReady Promise not to be resolved yet.
+ */
+ bool MightHavePendingFontLoads();
+
+ /**
+ * Checks to see whether it is time to replace mReady and dispatch a
+ * "loading" event.
+ */
+ void CheckLoadingStarted();
+
+ /**
+ * Checks to see whether it is time to resolve mReady and dispatch any
+ * "loadingdone" and "loadingerror" events.
+ */
+ void CheckLoadingFinished();
+
+ /**
+ * Callback for invoking CheckLoadingFinished after going through the
+ * event loop. See OnFontFaceStatusChanged.
+ */
+ void CheckLoadingFinishedAfterDelay();
+
+ /**
+ * Dispatches a FontFaceSetLoadEvent to this object.
+ */
+ void DispatchLoadingFinishedEvent(
+ const nsAString& aType,
+ const nsTArray<FontFace*>& aFontFaces);
+
+ // Note: if you add new cycle collected objects to FontFaceRecord,
+ // make sure to update FontFaceSet's cycle collection macros
+ // accordingly.
+ struct FontFaceRecord {
+ RefPtr<FontFace> mFontFace;
+ SheetType mSheetType; // only relevant for mRuleFaces entries
+
+ // When true, indicates that when finished loading, the FontFace should be
+ // included in the subsequent loadingdone/loadingerror event fired at the
+ // FontFaceSet.
+ bool mLoadEventShouldFire;
+ };
+
+ static already_AddRefed<gfxUserFontEntry> FindOrCreateUserFontEntryFromFontFace(
+ const nsAString& aFamilyName,
+ FontFace* aFontFace,
+ SheetType aSheetType);
+
+ // search for @font-face rule that matches a userfont font entry
+ nsCSSFontFaceRule* FindRuleForUserFontEntry(gfxUserFontEntry* aUserFontEntry);
+
+ nsresult StartLoad(gfxUserFontEntry* aUserFontEntry,
+ const gfxFontFaceSrc* aFontFaceSrc);
+ nsresult CheckFontLoad(const gfxFontFaceSrc* aFontFaceSrc,
+ nsIPrincipal** aPrincipal,
+ bool* aBypassCache);
+ bool IsFontLoadAllowed(nsIURI* aFontLocation, nsIPrincipal* aPrincipal);
+ bool GetPrivateBrowsing();
+ nsresult SyncLoadFontData(gfxUserFontEntry* aFontToLoad,
+ const gfxFontFaceSrc* aFontFaceSrc,
+ uint8_t*& aBuffer,
+ uint32_t& aBufferLength);
+ nsresult LogMessage(gfxUserFontEntry* aUserFontEntry,
+ const char* aMessage,
+ uint32_t aFlags,
+ nsresult aStatus);
+ void RebuildUserFontSet();
+
+ void InsertRuleFontFace(FontFace* aFontFace, SheetType aSheetType,
+ nsTArray<FontFaceRecord>& aOldRecords,
+ bool& aFontSetModified);
+ void InsertNonRuleFontFace(FontFace* aFontFace, bool& aFontSetModified);
+
+#ifdef DEBUG
+ bool HasRuleFontFace(FontFace* aFontFace);
+#endif
+
+ /**
+ * Returns whether we have any loading FontFace objects in the FontFaceSet.
+ */
+ bool HasLoadingFontFaces();
+
+ // Helper function for HasLoadingFontFaces.
+ void UpdateHasLoadingFontFaces();
+
+ void ParseFontShorthandForMatching(
+ const nsAString& aFont,
+ RefPtr<mozilla::css::FontFamilyListRefCnt>& aFamilyList,
+ uint32_t& aWeight,
+ int32_t& aStretch,
+ uint8_t& aStyle,
+ ErrorResult& aRv);
+ void FindMatchingFontFaces(const nsAString& aFont,
+ const nsAString& aText,
+ nsTArray<FontFace*>& aFontFaces,
+ mozilla::ErrorResult& aRv);
+
+ TimeStamp GetNavigationStartTimeStamp();
+
+ RefPtr<UserFontSet> mUserFontSet;
+
+ // The document this is a FontFaceSet for.
+ nsCOMPtr<nsIDocument> mDocument;
+
+ // A Promise that is fulfilled once all of the FontFace objects
+ // in mRuleFaces and mNonRuleFaces that started or were loading at the
+ // time the Promise was created have finished loading. It is rejected if
+ // any of those fonts failed to load. mReady is replaced with
+ // a new Promise object whenever mReady is settled and another
+ // FontFace in mRuleFaces or mNonRuleFaces starts to load.
+ // Note that mReady is created lazily when GetReady() is called.
+ RefPtr<mozilla::dom::Promise> mReady;
+ // Whether the ready promise must be resolved when it's created.
+ bool mResolveLazilyCreatedReadyPromise;
+
+ // 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< nsPtrHashKey<nsFontFaceLoader> > mLoaders;
+
+ // The @font-face rule backed FontFace objects in the FontFaceSet.
+ nsTArray<FontFaceRecord> mRuleFaces;
+
+ // The non rule backed FontFace objects that have been added to this
+ // FontFaceSet.
+ nsTArray<FontFaceRecord> mNonRuleFaces;
+
+ // The overall status of the loading or loaded fonts in the FontFaceSet.
+ mozilla::dom::FontFaceSetLoadStatus mStatus;
+
+ // Whether mNonRuleFaces has changed since last time UpdateRules ran.
+ bool mNonRuleFacesDirty;
+
+ // 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;
+
+ // This variable is only valid when mLoadingDirty is false.
+ bool mHasLoadingFontFacesIsDirty;
+
+ // Whether CheckLoadingFinished calls should be ignored. See comment in
+ // OnFontFaceStatusChanged.
+ bool mDelayedLoadCheck;
+};
+
+} // namespace dom
+} // namespace mozilla
+
+#endif // !defined(mozilla_dom_FontFaceSet_h)