1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
3 /* This Source Code Form is subject to the terms of the Mozilla Public
4 * License, v. 2.0. If a copy of the MPL was not distributed with this
5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
7 #ifndef mozilla_dom_FontFaceSet_h
8 #define mozilla_dom_FontFaceSet_h
10 #include "mozilla/dom/FontFace.h"
11 #include "mozilla/dom/FontFaceSetBinding.h"
12 #include "mozilla/DOMEventTargetHelper.h"
13 #include "mozilla/FontPropertyTypes.h"
14 #include "gfxUserFontSet.h"
15 #include "nsICSSLoaderObserver.h"
16 #include "nsIDOMEventListener.h"
18 struct gfxFontFaceSrc
;
19 class gfxFontSrcPrincipal
;
20 class gfxUserFontEntry
;
21 class nsFontFaceLoader
;
23 class nsPIDOMWindowInner
;
24 struct RawServoFontFaceRule
;
27 class PostTraversalTask
;
33 } // namespace mozilla
38 class FontFaceSet final
: public DOMEventTargetHelper
,
39 public nsIDOMEventListener
,
40 public nsICSSLoaderObserver
{
41 friend class mozilla::PostTraversalTask
;
42 friend class UserFontSet
;
46 * A gfxUserFontSet that integrates with the layout and style systems to
47 * manage @font-face rules and handle network requests for font loading.
49 * We would combine this class and FontFaceSet into the one class if it were
50 * possible; it's not because FontFaceSet is cycle collected and
51 * gfxUserFontSet isn't (and can't be, as gfx classes don't use the cycle
52 * collector). So UserFontSet exists just to override the needed virtual
53 * methods from gfxUserFontSet and to forward them on FontFaceSet.
55 class UserFontSet final
: public gfxUserFontSet
{
56 friend class FontFaceSet
;
59 explicit UserFontSet(FontFaceSet
* aFontFaceSet
)
60 : mFontFaceSet(aFontFaceSet
) {}
62 FontFaceSet
* GetFontFaceSet() { return mFontFaceSet
; }
64 gfxFontSrcPrincipal
* GetStandardFontLoadPrincipal() const final
{
65 return mFontFaceSet
? mFontFaceSet
->mStandardFontLoadPrincipal
.get()
69 bool IsFontLoadAllowed(const gfxFontFaceSrc
&) final
;
71 void DispatchFontLoadViolations(
72 nsTArray
<nsCOMPtr
<nsIRunnable
>>& aViolations
) override
;
74 virtual nsresult
StartLoad(gfxUserFontEntry
* aUserFontEntry
,
75 uint32_t aSrcIndex
) override
;
77 void RecordFontLoadDone(uint32_t aFontSize
, TimeStamp aDoneTime
) override
;
79 bool BypassCache() final
{
80 return mFontFaceSet
&& mFontFaceSet
->mBypassCache
;
84 virtual bool GetPrivateBrowsing() override
;
85 virtual nsresult
SyncLoadFontData(gfxUserFontEntry
* aFontToLoad
,
86 const gfxFontFaceSrc
* aFontFaceSrc
,
88 uint32_t& aBufferLength
) override
;
89 virtual nsresult
LogMessage(gfxUserFontEntry
* aUserFontEntry
,
90 uint32_t aSrcIndex
, const char* aMessage
,
91 uint32_t aFlags
= nsIScriptError::errorFlag
,
92 nsresult aStatus
= NS_OK
) override
;
93 virtual void DoRebuildUserFontSet() override
;
94 already_AddRefed
<gfxUserFontEntry
> CreateUserFontEntry(
95 const nsTArray
<gfxFontFaceSrc
>& aFontFaceSrcList
, WeightRange aWeight
,
96 StretchRange aStretch
, SlantStyleRange aStyle
,
97 const nsTArray
<gfxFontFeature
>& aFeatureSettings
,
98 const nsTArray
<gfxFontVariation
>& aVariationSettings
,
99 uint32_t aLanguageOverride
, gfxCharacterMap
* aUnicodeRanges
,
100 StyleFontDisplay aFontDisplay
, RangeFlags aRangeFlags
,
101 float aAscentOverride
, float aDescentOverride
, float aLineGapOverride
,
102 float aSizeAdjust
) override
;
105 RefPtr
<FontFaceSet
> mFontFaceSet
;
108 NS_DECL_ISUPPORTS_INHERITED
109 NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(FontFaceSet
, DOMEventTargetHelper
)
110 NS_DECL_NSIDOMEVENTLISTENER
112 FontFaceSet(nsPIDOMWindowInner
* aWindow
, dom::Document
* aDocument
);
114 virtual JSObject
* WrapObject(JSContext
* aCx
,
115 JS::Handle
<JSObject
*> aGivenProto
) override
;
117 UserFontSet
* GetUserFontSet() { return mUserFontSet
; }
119 // Called by nsFontFaceLoader when the loader has completed normally.
120 // It's removed from the mLoaders set.
121 void RemoveLoader(nsFontFaceLoader
* aLoader
);
123 bool UpdateRules(const nsTArray
<nsFontFaceRuleContainer
>& aRules
);
125 nsPresContext
* GetPresContext();
127 // search for @font-face rule that matches a platform font entry
128 RawServoFontFaceRule
* FindRuleForEntry(gfxFontEntry
* aFontEntry
);
130 void IncrementGeneration(bool aIsRebuild
= false);
133 * Finds an existing entry in the user font cache or creates a new user
134 * font entry for the given FontFace object.
136 static already_AddRefed
<gfxUserFontEntry
>
137 FindOrCreateUserFontEntryFromFontFace(FontFace
* aFontFace
);
140 * Notification method called by a FontFace to indicate that its loading
141 * status has changed.
143 void OnFontFaceStatusChanged(FontFace
* aFontFace
);
146 * Notification method called by the nsPresContext to indicate that the
147 * refresh driver ticked and flushed style and layout.
153 * Returns whether the "layout.css.font-loading-api.enabled" pref is true.
155 static bool PrefEnabled();
157 // nsICSSLoaderObserver
158 NS_IMETHOD
StyleSheetLoaded(StyleSheet
* aSheet
, bool aWasDeferred
,
159 nsresult aStatus
) override
;
161 FontFace
* GetFontFaceAt(uint32_t aIndex
);
163 void FlushUserFontSet();
165 static nsPresContext
* GetPresContextFor(gfxUserFontSet
* aUserFontSet
) {
166 FontFaceSet
* set
= static_cast<UserFontSet
*>(aUserFontSet
)->mFontFaceSet
;
167 return set
? set
->GetPresContext() : nullptr;
170 void RefreshStandardFontLoadPrincipal();
172 void CopyNonRuleFacesTo(FontFaceSet
* aFontFaceSet
) const;
174 dom::Document
* Document() const { return mDocument
; }
176 // -- Web IDL --------------------------------------------------------------
178 IMPL_EVENT_HANDLER(loading
)
179 IMPL_EVENT_HANDLER(loadingdone
)
180 IMPL_EVENT_HANDLER(loadingerror
)
181 already_AddRefed
<dom::Promise
> Load(JSContext
* aCx
, const nsACString
& aFont
,
182 const nsAString
& aText
, ErrorResult
& aRv
);
183 bool Check(const nsACString
& aFont
, const nsAString
& aText
, ErrorResult
& aRv
);
184 dom::Promise
* GetReady(ErrorResult
& aRv
);
185 dom::FontFaceSetLoadStatus
Status();
187 void Add(FontFace
& aFontFace
, ErrorResult
& aRv
);
189 bool Delete(FontFace
& aFontFace
);
190 bool Has(FontFace
& aFontFace
);
192 already_AddRefed
<dom::FontFaceSetIterator
> Entries();
193 already_AddRefed
<dom::FontFaceSetIterator
> Values();
195 void ForEach(JSContext
* aCx
, FontFaceSetForEachCallback
& aCallback
,
196 JS::Handle
<JS::Value
> aThisArg
, ErrorResult
& aRv
);
198 // For ServoStyleSet to know ahead of time whether a font is loadable.
199 void CacheFontLoadability();
201 void MarkUserFontSetDirty();
207 * Returns whether the given FontFace is currently "in" the FontFaceSet.
209 bool HasAvailableFontFace(FontFace
* aFontFace
);
212 * Removes any listeners and observers.
216 void RemoveDOMContentLoadedListener();
219 * Returns whether there might be any pending font loads, which should cause
220 * the mReady Promise not to be resolved yet.
222 bool MightHavePendingFontLoads();
225 * Checks to see whether it is time to replace mReady and dispatch a
228 void CheckLoadingStarted();
231 * Checks to see whether it is time to resolve mReady and dispatch any
232 * "loadingdone" and "loadingerror" events.
234 void CheckLoadingFinished();
237 * Callback for invoking CheckLoadingFinished after going through the
238 * event loop. See OnFontFaceStatusChanged.
240 void CheckLoadingFinishedAfterDelay();
243 * Dispatches a FontFaceSetLoadEvent to this object.
245 void DispatchLoadingFinishedEvent(
246 const nsAString
& aType
, nsTArray
<OwningNonNull
<FontFace
>>&& aFontFaces
);
248 // Note: if you add new cycle collected objects to FontFaceRecord,
249 // make sure to update FontFaceSet's cycle collection macros
251 struct FontFaceRecord
{
252 RefPtr
<FontFace
> mFontFace
;
253 Maybe
<StyleOrigin
> mOrigin
; // only relevant for mRuleFaces entries
255 // When true, indicates that when finished loading, the FontFace should be
256 // included in the subsequent loadingdone/loadingerror event fired at the
258 bool mLoadEventShouldFire
;
261 static already_AddRefed
<gfxUserFontEntry
>
262 FindOrCreateUserFontEntryFromFontFace(const nsACString
& aFamilyName
,
263 FontFace
* aFontFace
, StyleOrigin
);
265 // search for @font-face rule that matches a userfont font entry
266 RawServoFontFaceRule
* FindRuleForUserFontEntry(
267 gfxUserFontEntry
* aUserFontEntry
);
269 nsresult
StartLoad(gfxUserFontEntry
* aUserFontEntry
, uint32_t aSrcIndex
);
270 gfxFontSrcPrincipal
* GetStandardFontLoadPrincipal();
271 nsresult
CheckFontLoad(const gfxFontFaceSrc
* aFontFaceSrc
,
272 gfxFontSrcPrincipal
** aPrincipal
, bool* aBypassCache
);
273 bool IsFontLoadAllowed(const gfxFontFaceSrc
& aSrc
);
275 void DispatchFontLoadViolations(nsTArray
<nsCOMPtr
<nsIRunnable
>>& aViolations
);
276 nsresult
SyncLoadFontData(gfxUserFontEntry
* aFontToLoad
,
277 const gfxFontFaceSrc
* aFontFaceSrc
,
278 uint8_t*& aBuffer
, uint32_t& aBufferLength
);
279 nsresult
LogMessage(gfxUserFontEntry
* aUserFontEntry
, uint32_t aSrcIndex
,
280 const char* aMessage
, uint32_t aFlags
, nsresult aStatus
);
282 void InsertRuleFontFace(FontFace
* aFontFace
, StyleOrigin aOrigin
,
283 nsTArray
<FontFaceRecord
>& aOldRecords
,
284 bool& aFontSetModified
);
285 void InsertNonRuleFontFace(FontFace
* aFontFace
, bool& aFontSetModified
);
288 bool HasRuleFontFace(FontFace
* aFontFace
);
292 * Returns whether we have any loading FontFace objects in the FontFaceSet.
294 bool HasLoadingFontFaces();
296 // Whether mReady is pending, or would be when created.
297 bool ReadyPromiseIsPending() const;
299 // Helper function for HasLoadingFontFaces.
300 void UpdateHasLoadingFontFaces();
302 void ParseFontShorthandForMatching(const nsACString
& aFont
,
303 RefPtr
<SharedFontList
>& aFamilyList
,
304 FontWeight
& aWeight
, FontStretch
& aStretch
,
305 FontSlantStyle
& aStyle
, ErrorResult
& aRv
);
306 void FindMatchingFontFaces(const nsACString
& aFont
, const nsAString
& aText
,
307 nsTArray
<FontFace
*>& aFontFaces
, ErrorResult
& aRv
);
309 void DispatchLoadingEventAndReplaceReadyPromise();
310 void DispatchCheckLoadingFinishedAfterDelay();
312 TimeStamp
GetNavigationStartTimeStamp();
314 RefPtr
<UserFontSet
> mUserFontSet
;
316 // The document this is a FontFaceSet for.
317 RefPtr
<dom::Document
> mDocument
;
319 // The document's node principal, which is the principal font loads for
320 // this FontFaceSet will generally use. (This principal is not used for
321 // @font-face rules in UA and user sheets, where the principal of the
322 // sheet is used instead.)
324 // This field is used from GetStandardFontLoadPrincipal. When on a
325 // style worker thread, we use mStandardFontLoadPrincipal assuming
328 // Because mDocument's principal can change over time,
329 // its value must be updated by a call to ResetStandardFontLoadPrincipal.
330 RefPtr
<gfxFontSrcPrincipal
> mStandardFontLoadPrincipal
;
332 // A Promise that is fulfilled once all of the FontFace objects
333 // in mRuleFaces and mNonRuleFaces that started or were loading at the
334 // time the Promise was created have finished loading. It is rejected if
335 // any of those fonts failed to load. mReady is replaced with
336 // a new Promise object whenever mReady is settled and another
337 // FontFace in mRuleFaces or mNonRuleFaces starts to load.
338 // Note that mReady is created lazily when GetReady() is called.
339 RefPtr
<dom::Promise
> mReady
;
340 // Whether the ready promise must be resolved when it's created.
341 bool mResolveLazilyCreatedReadyPromise
;
343 // Set of all loaders pointing to us. These are not strong pointers,
344 // but that's OK because nsFontFaceLoader always calls RemoveLoader on
345 // us before it dies (unless we die first).
346 nsTHashtable
<nsPtrHashKey
<nsFontFaceLoader
>> mLoaders
;
348 // The @font-face rule backed FontFace objects in the FontFaceSet.
349 nsTArray
<FontFaceRecord
> mRuleFaces
;
351 // The non rule backed FontFace objects that have been added to this
353 nsTArray
<FontFaceRecord
> mNonRuleFaces
;
355 // The overall status of the loading or loaded fonts in the FontFaceSet.
356 dom::FontFaceSetLoadStatus mStatus
;
358 // A map from gfxFontFaceSrc pointer identity to whether the load is allowed
359 // by CSP or other checks. We store this here because querying CSP off the
360 // main thread is not a great idea.
362 // We could use just the pointer and use this as a hash set, but then we'd
363 // have no way to verify that we've checked all the loads we should.
364 nsTHashMap
<nsPtrHashKey
<const gfxFontFaceSrc
>, bool> mAllowedFontLoads
;
366 // Whether mNonRuleFaces has changed since last time UpdateRules ran.
367 bool mNonRuleFacesDirty
;
369 // Whether any FontFace objects in mRuleFaces or mNonRuleFaces are
370 // loading. Only valid when mHasLoadingFontFacesIsDirty is false. Don't use
371 // this variable directly; call the HasLoadingFontFaces method instead.
372 bool mHasLoadingFontFaces
;
374 // This variable is only valid when mLoadingDirty is false.
375 bool mHasLoadingFontFacesIsDirty
;
377 // Whether CheckLoadingFinished calls should be ignored. See comment in
378 // OnFontFaceStatusChanged.
379 bool mDelayedLoadCheck
;
381 // Whether the docshell for our document indicated that loads should
385 // Whether the docshell for our document indicates that we are in private
387 bool mPrivateBrowsing
;
391 } // namespace mozilla
393 #endif // !defined(mozilla_dom_FontFaceSet_h)