FontFaceSet.h 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357
  1. /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
  2. /* This Source Code Form is subject to the terms of the Mozilla Public
  3. * License, v. 2.0. If a copy of the MPL was not distributed with this
  4. * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
  5. #ifndef mozilla_dom_FontFaceSet_h
  6. #define mozilla_dom_FontFaceSet_h
  7. #include "mozilla/dom/FontFace.h"
  8. #include "mozilla/dom/FontFaceSetBinding.h"
  9. #include "mozilla/DOMEventTargetHelper.h"
  10. #include "gfxUserFontSet.h"
  11. #include "nsCSSRules.h"
  12. #include "nsICSSLoaderObserver.h"
  13. struct gfxFontFaceSrc;
  14. class gfxUserFontEntry;
  15. class nsFontFaceLoader;
  16. class nsIPrincipal;
  17. class nsPIDOMWindowInner;
  18. namespace mozilla {
  19. namespace css {
  20. class FontFamilyListRefCnt;
  21. } // namespace css
  22. namespace dom {
  23. class FontFace;
  24. class Promise;
  25. } // namespace dom
  26. } // namespace mozilla
  27. namespace mozilla {
  28. namespace dom {
  29. class FontFaceSet final : public DOMEventTargetHelper
  30. , public nsIDOMEventListener
  31. , public nsICSSLoaderObserver
  32. {
  33. friend class UserFontSet;
  34. public:
  35. /**
  36. * A gfxUserFontSet that integrates with the layout and style systems to
  37. * manage @font-face rules and handle network requests for font loading.
  38. *
  39. * We would combine this class and FontFaceSet into the one class if it were
  40. * possible; it's not because FontFaceSet is cycle collected and
  41. * gfxUserFontSet isn't (and can't be, as gfx classes don't use the cycle
  42. * collector). So UserFontSet exists just to override the needed virtual
  43. * methods from gfxUserFontSet and to forward them on FontFaceSet.
  44. */
  45. class UserFontSet final : public gfxUserFontSet
  46. {
  47. friend class FontFaceSet;
  48. public:
  49. explicit UserFontSet(FontFaceSet* aFontFaceSet)
  50. : mFontFaceSet(aFontFaceSet)
  51. {
  52. }
  53. FontFaceSet* GetFontFaceSet() { return mFontFaceSet; }
  54. virtual nsresult CheckFontLoad(const gfxFontFaceSrc* aFontFaceSrc,
  55. nsIPrincipal** aPrincipal,
  56. bool* aBypassCache) override;
  57. virtual bool IsFontLoadAllowed(nsIURI* aFontLocation,
  58. nsIPrincipal* aPrincipal) override;
  59. virtual nsresult StartLoad(gfxUserFontEntry* aUserFontEntry,
  60. const gfxFontFaceSrc* aFontFaceSrc) override;
  61. void RecordFontLoadDone(uint32_t aFontSize,
  62. mozilla::TimeStamp aDoneTime) override;
  63. protected:
  64. virtual bool GetPrivateBrowsing() override;
  65. virtual nsresult SyncLoadFontData(gfxUserFontEntry* aFontToLoad,
  66. const gfxFontFaceSrc* aFontFaceSrc,
  67. uint8_t*& aBuffer,
  68. uint32_t& aBufferLength) override;
  69. virtual nsresult LogMessage(gfxUserFontEntry* aUserFontEntry,
  70. const char* aMessage,
  71. uint32_t aFlags = nsIScriptError::errorFlag,
  72. nsresult aStatus = NS_OK) override;
  73. virtual void DoRebuildUserFontSet() override;
  74. virtual already_AddRefed<gfxUserFontEntry> CreateUserFontEntry(
  75. const nsTArray<gfxFontFaceSrc>& aFontFaceSrcList,
  76. uint32_t aWeight,
  77. int32_t aStretch,
  78. uint8_t aStyle,
  79. const nsTArray<gfxFontFeature>& aFeatureSettings,
  80. uint32_t aLanguageOverride,
  81. gfxSparseBitSet* aUnicodeRanges,
  82. uint8_t aFontDisplay) override;
  83. private:
  84. RefPtr<FontFaceSet> mFontFaceSet;
  85. };
  86. NS_DECL_ISUPPORTS_INHERITED
  87. NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(FontFaceSet, DOMEventTargetHelper)
  88. NS_DECL_NSIDOMEVENTLISTENER
  89. FontFaceSet(nsPIDOMWindowInner* aWindow, nsIDocument* aDocument);
  90. virtual JSObject* WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto) override;
  91. UserFontSet* GetUserFontSet() { return mUserFontSet; }
  92. // Called by nsFontFaceLoader when the loader has completed normally.
  93. // It's removed from the mLoaders set.
  94. void RemoveLoader(nsFontFaceLoader* aLoader);
  95. bool UpdateRules(const nsTArray<nsFontFaceRuleContainer>& aRules);
  96. nsPresContext* GetPresContext();
  97. // search for @font-face rule that matches a platform font entry
  98. nsCSSFontFaceRule* FindRuleForEntry(gfxFontEntry* aFontEntry);
  99. void IncrementGeneration(bool aIsRebuild = false);
  100. /**
  101. * Finds an existing entry in the user font cache or creates a new user
  102. * font entry for the given FontFace object.
  103. */
  104. static already_AddRefed<gfxUserFontEntry>
  105. FindOrCreateUserFontEntryFromFontFace(FontFace* aFontFace);
  106. /**
  107. * Notification method called by a FontFace to indicate that its loading
  108. * status has changed.
  109. */
  110. void OnFontFaceStatusChanged(FontFace* aFontFace);
  111. /**
  112. * Notification method called by the nsPresContext to indicate that the
  113. * refresh driver ticked and flushed style and layout.
  114. * were just flushed.
  115. */
  116. void DidRefresh();
  117. /**
  118. * Returns whether the "layout.css.font-loading-api.enabled" pref is true.
  119. */
  120. static bool PrefEnabled();
  121. // nsICSSLoaderObserver
  122. NS_IMETHOD StyleSheetLoaded(mozilla::StyleSheet* aSheet,
  123. bool aWasAlternate,
  124. nsresult aStatus) override;
  125. FontFace* GetFontFaceAt(uint32_t aIndex);
  126. void FlushUserFontSet();
  127. static nsPresContext* GetPresContextFor(gfxUserFontSet* aUserFontSet)
  128. {
  129. FontFaceSet* set = static_cast<UserFontSet*>(aUserFontSet)->mFontFaceSet;
  130. return set ? set->GetPresContext() : nullptr;
  131. }
  132. // -- Web IDL --------------------------------------------------------------
  133. IMPL_EVENT_HANDLER(loading)
  134. IMPL_EVENT_HANDLER(loadingdone)
  135. IMPL_EVENT_HANDLER(loadingerror)
  136. already_AddRefed<mozilla::dom::Promise> Load(JSContext* aCx,
  137. const nsAString& aFont,
  138. const nsAString& aText,
  139. mozilla::ErrorResult& aRv);
  140. bool Check(const nsAString& aFont,
  141. const nsAString& aText,
  142. mozilla::ErrorResult& aRv);
  143. mozilla::dom::Promise* GetReady(mozilla::ErrorResult& aRv);
  144. mozilla::dom::FontFaceSetLoadStatus Status();
  145. FontFaceSet* Add(FontFace& aFontFace, mozilla::ErrorResult& aRv);
  146. void Clear();
  147. bool Delete(FontFace& aFontFace);
  148. bool Has(FontFace& aFontFace);
  149. uint32_t Size();
  150. already_AddRefed<mozilla::dom::FontFaceSetIterator> Entries();
  151. already_AddRefed<mozilla::dom::FontFaceSetIterator> Values();
  152. void ForEach(JSContext* aCx, FontFaceSetForEachCallback& aCallback,
  153. JS::Handle<JS::Value> aThisArg,
  154. mozilla::ErrorResult& aRv);
  155. private:
  156. ~FontFaceSet();
  157. /**
  158. * Returns whether the given FontFace is currently "in" the FontFaceSet.
  159. */
  160. bool HasAvailableFontFace(FontFace* aFontFace);
  161. /**
  162. * Removes any listeners and observers.
  163. */
  164. void Disconnect();
  165. void RemoveDOMContentLoadedListener();
  166. /**
  167. * Returns whether there might be any pending font loads, which should cause
  168. * the mReady Promise not to be resolved yet.
  169. */
  170. bool MightHavePendingFontLoads();
  171. /**
  172. * Checks to see whether it is time to replace mReady and dispatch a
  173. * "loading" event.
  174. */
  175. void CheckLoadingStarted();
  176. /**
  177. * Checks to see whether it is time to resolve mReady and dispatch any
  178. * "loadingdone" and "loadingerror" events.
  179. */
  180. void CheckLoadingFinished();
  181. /**
  182. * Callback for invoking CheckLoadingFinished after going through the
  183. * event loop. See OnFontFaceStatusChanged.
  184. */
  185. void CheckLoadingFinishedAfterDelay();
  186. /**
  187. * Dispatches a FontFaceSetLoadEvent to this object.
  188. */
  189. void DispatchLoadingFinishedEvent(
  190. const nsAString& aType,
  191. const nsTArray<FontFace*>& aFontFaces);
  192. // Note: if you add new cycle collected objects to FontFaceRecord,
  193. // make sure to update FontFaceSet's cycle collection macros
  194. // accordingly.
  195. struct FontFaceRecord {
  196. RefPtr<FontFace> mFontFace;
  197. SheetType mSheetType; // only relevant for mRuleFaces entries
  198. // When true, indicates that when finished loading, the FontFace should be
  199. // included in the subsequent loadingdone/loadingerror event fired at the
  200. // FontFaceSet.
  201. bool mLoadEventShouldFire;
  202. };
  203. static already_AddRefed<gfxUserFontEntry> FindOrCreateUserFontEntryFromFontFace(
  204. const nsAString& aFamilyName,
  205. FontFace* aFontFace,
  206. SheetType aSheetType);
  207. // search for @font-face rule that matches a userfont font entry
  208. nsCSSFontFaceRule* FindRuleForUserFontEntry(gfxUserFontEntry* aUserFontEntry);
  209. nsresult StartLoad(gfxUserFontEntry* aUserFontEntry,
  210. const gfxFontFaceSrc* aFontFaceSrc);
  211. nsresult CheckFontLoad(const gfxFontFaceSrc* aFontFaceSrc,
  212. nsIPrincipal** aPrincipal,
  213. bool* aBypassCache);
  214. bool IsFontLoadAllowed(nsIURI* aFontLocation, nsIPrincipal* aPrincipal);
  215. bool GetPrivateBrowsing();
  216. nsresult SyncLoadFontData(gfxUserFontEntry* aFontToLoad,
  217. const gfxFontFaceSrc* aFontFaceSrc,
  218. uint8_t*& aBuffer,
  219. uint32_t& aBufferLength);
  220. nsresult LogMessage(gfxUserFontEntry* aUserFontEntry,
  221. const char* aMessage,
  222. uint32_t aFlags,
  223. nsresult aStatus);
  224. void RebuildUserFontSet();
  225. void InsertRuleFontFace(FontFace* aFontFace, SheetType aSheetType,
  226. nsTArray<FontFaceRecord>& aOldRecords,
  227. bool& aFontSetModified);
  228. void InsertNonRuleFontFace(FontFace* aFontFace, bool& aFontSetModified);
  229. #ifdef DEBUG
  230. bool HasRuleFontFace(FontFace* aFontFace);
  231. #endif
  232. /**
  233. * Returns whether we have any loading FontFace objects in the FontFaceSet.
  234. */
  235. bool HasLoadingFontFaces();
  236. // Helper function for HasLoadingFontFaces.
  237. void UpdateHasLoadingFontFaces();
  238. void ParseFontShorthandForMatching(
  239. const nsAString& aFont,
  240. RefPtr<mozilla::css::FontFamilyListRefCnt>& aFamilyList,
  241. uint32_t& aWeight,
  242. int32_t& aStretch,
  243. uint8_t& aStyle,
  244. ErrorResult& aRv);
  245. void FindMatchingFontFaces(const nsAString& aFont,
  246. const nsAString& aText,
  247. nsTArray<FontFace*>& aFontFaces,
  248. mozilla::ErrorResult& aRv);
  249. TimeStamp GetNavigationStartTimeStamp();
  250. RefPtr<UserFontSet> mUserFontSet;
  251. // The document this is a FontFaceSet for.
  252. nsCOMPtr<nsIDocument> mDocument;
  253. // A Promise that is fulfilled once all of the FontFace objects
  254. // in mRuleFaces and mNonRuleFaces that started or were loading at the
  255. // time the Promise was created have finished loading. It is rejected if
  256. // any of those fonts failed to load. mReady is replaced with
  257. // a new Promise object whenever mReady is settled and another
  258. // FontFace in mRuleFaces or mNonRuleFaces starts to load.
  259. // Note that mReady is created lazily when GetReady() is called.
  260. RefPtr<mozilla::dom::Promise> mReady;
  261. // Whether the ready promise must be resolved when it's created.
  262. bool mResolveLazilyCreatedReadyPromise;
  263. // Set of all loaders pointing to us. These are not strong pointers,
  264. // but that's OK because nsFontFaceLoader always calls RemoveLoader on
  265. // us before it dies (unless we die first).
  266. nsTHashtable< nsPtrHashKey<nsFontFaceLoader> > mLoaders;
  267. // The @font-face rule backed FontFace objects in the FontFaceSet.
  268. nsTArray<FontFaceRecord> mRuleFaces;
  269. // The non rule backed FontFace objects that have been added to this
  270. // FontFaceSet.
  271. nsTArray<FontFaceRecord> mNonRuleFaces;
  272. // The overall status of the loading or loaded fonts in the FontFaceSet.
  273. mozilla::dom::FontFaceSetLoadStatus mStatus;
  274. // Whether mNonRuleFaces has changed since last time UpdateRules ran.
  275. bool mNonRuleFacesDirty;
  276. // Whether any FontFace objects in mRuleFaces or mNonRuleFaces are
  277. // loading. Only valid when mHasLoadingFontFacesIsDirty is false. Don't use
  278. // this variable directly; call the HasLoadingFontFaces method instead.
  279. bool mHasLoadingFontFaces;
  280. // This variable is only valid when mLoadingDirty is false.
  281. bool mHasLoadingFontFacesIsDirty;
  282. // Whether CheckLoadingFinished calls should be ignored. See comment in
  283. // OnFontFaceStatusChanged.
  284. bool mDelayedLoadCheck;
  285. };
  286. } // namespace dom
  287. } // namespace mozilla
  288. #endif // !defined(mozilla_dom_FontFaceSet_h)