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 const gfxFontFaceSrc
* aFontFaceSrc
) 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
,
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
) override
;
103 RefPtr
<FontFaceSet
> mFontFaceSet
;
106 NS_DECL_ISUPPORTS_INHERITED
107 NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(FontFaceSet
, DOMEventTargetHelper
)
108 NS_DECL_NSIDOMEVENTLISTENER
110 FontFaceSet(nsPIDOMWindowInner
* aWindow
, dom::Document
* aDocument
);
112 virtual JSObject
* WrapObject(JSContext
* aCx
,
113 JS::Handle
<JSObject
*> aGivenProto
) override
;
115 UserFontSet
* GetUserFontSet() { return mUserFontSet
; }
117 // Called by nsFontFaceLoader when the loader has completed normally.
118 // It's removed from the mLoaders set.
119 void RemoveLoader(nsFontFaceLoader
* aLoader
);
121 bool UpdateRules(const nsTArray
<nsFontFaceRuleContainer
>& aRules
);
123 nsPresContext
* GetPresContext();
125 // search for @font-face rule that matches a platform font entry
126 RawServoFontFaceRule
* FindRuleForEntry(gfxFontEntry
* aFontEntry
);
128 void IncrementGeneration(bool aIsRebuild
= false);
131 * Finds an existing entry in the user font cache or creates a new user
132 * font entry for the given FontFace object.
134 static already_AddRefed
<gfxUserFontEntry
>
135 FindOrCreateUserFontEntryFromFontFace(FontFace
* aFontFace
);
138 * Notification method called by a FontFace to indicate that its loading
139 * status has changed.
141 void OnFontFaceStatusChanged(FontFace
* aFontFace
);
144 * Notification method called by the nsPresContext to indicate that the
145 * refresh driver ticked and flushed style and layout.
151 * Returns whether the "layout.css.font-loading-api.enabled" pref is true.
153 static bool PrefEnabled();
155 // nsICSSLoaderObserver
156 NS_IMETHOD
StyleSheetLoaded(StyleSheet
* aSheet
, bool aWasDeferred
,
157 nsresult aStatus
) override
;
159 FontFace
* GetFontFaceAt(uint32_t aIndex
);
161 void FlushUserFontSet();
163 static nsPresContext
* GetPresContextFor(gfxUserFontSet
* aUserFontSet
) {
164 FontFaceSet
* set
= static_cast<UserFontSet
*>(aUserFontSet
)->mFontFaceSet
;
165 return set
? set
->GetPresContext() : nullptr;
168 void RefreshStandardFontLoadPrincipal();
170 void CopyNonRuleFacesTo(FontFaceSet
* aFontFaceSet
) const;
172 dom::Document
* Document() const { return mDocument
; }
174 // -- Web IDL --------------------------------------------------------------
176 IMPL_EVENT_HANDLER(loading
)
177 IMPL_EVENT_HANDLER(loadingdone
)
178 IMPL_EVENT_HANDLER(loadingerror
)
179 already_AddRefed
<dom::Promise
> Load(JSContext
* aCx
, const nsACString
& aFont
,
180 const nsAString
& aText
, ErrorResult
& aRv
);
181 bool Check(const nsACString
& aFont
, const nsAString
& aText
, ErrorResult
& aRv
);
182 dom::Promise
* GetReady(ErrorResult
& aRv
);
183 dom::FontFaceSetLoadStatus
Status();
185 void Add(FontFace
& aFontFace
, ErrorResult
& aRv
);
187 bool Delete(FontFace
& aFontFace
);
188 bool Has(FontFace
& aFontFace
);
190 already_AddRefed
<dom::FontFaceSetIterator
> Entries();
191 already_AddRefed
<dom::FontFaceSetIterator
> Values();
193 void ForEach(JSContext
* aCx
, FontFaceSetForEachCallback
& aCallback
,
194 JS::Handle
<JS::Value
> aThisArg
, ErrorResult
& aRv
);
196 // For ServoStyleSet to know ahead of time whether a font is loadable.
197 void CacheFontLoadability();
199 void MarkUserFontSetDirty();
205 * Returns whether the given FontFace is currently "in" the FontFaceSet.
207 bool HasAvailableFontFace(FontFace
* aFontFace
);
210 * Removes any listeners and observers.
214 void RemoveDOMContentLoadedListener();
217 * Returns whether there might be any pending font loads, which should cause
218 * the mReady Promise not to be resolved yet.
220 bool MightHavePendingFontLoads();
223 * Checks to see whether it is time to replace mReady and dispatch a
226 void CheckLoadingStarted();
229 * Checks to see whether it is time to resolve mReady and dispatch any
230 * "loadingdone" and "loadingerror" events.
232 void CheckLoadingFinished();
235 * Callback for invoking CheckLoadingFinished after going through the
236 * event loop. See OnFontFaceStatusChanged.
238 void CheckLoadingFinishedAfterDelay();
241 * Dispatches a FontFaceSetLoadEvent to this object.
243 void DispatchLoadingFinishedEvent(
244 const nsAString
& aType
, nsTArray
<OwningNonNull
<FontFace
>>&& aFontFaces
);
246 // Note: if you add new cycle collected objects to FontFaceRecord,
247 // make sure to update FontFaceSet's cycle collection macros
249 struct FontFaceRecord
{
250 RefPtr
<FontFace
> mFontFace
;
251 Maybe
<StyleOrigin
> mOrigin
; // only relevant for mRuleFaces entries
253 // When true, indicates that when finished loading, the FontFace should be
254 // included in the subsequent loadingdone/loadingerror event fired at the
256 bool mLoadEventShouldFire
;
259 static already_AddRefed
<gfxUserFontEntry
>
260 FindOrCreateUserFontEntryFromFontFace(const nsACString
& aFamilyName
,
261 FontFace
* aFontFace
, StyleOrigin
);
263 // search for @font-face rule that matches a userfont font entry
264 RawServoFontFaceRule
* FindRuleForUserFontEntry(
265 gfxUserFontEntry
* aUserFontEntry
);
267 nsresult
StartLoad(gfxUserFontEntry
* aUserFontEntry
,
268 const gfxFontFaceSrc
* aFontFaceSrc
);
269 gfxFontSrcPrincipal
* GetStandardFontLoadPrincipal();
270 nsresult
CheckFontLoad(const gfxFontFaceSrc
* aFontFaceSrc
,
271 gfxFontSrcPrincipal
** aPrincipal
, bool* aBypassCache
);
272 bool IsFontLoadAllowed(const gfxFontFaceSrc
& aSrc
);
274 void DispatchFontLoadViolations(nsTArray
<nsCOMPtr
<nsIRunnable
>>& aViolations
);
275 nsresult
SyncLoadFontData(gfxUserFontEntry
* aFontToLoad
,
276 const gfxFontFaceSrc
* aFontFaceSrc
,
277 uint8_t*& aBuffer
, uint32_t& aBufferLength
);
278 nsresult
LogMessage(gfxUserFontEntry
* aUserFontEntry
, const char* aMessage
,
279 uint32_t aFlags
, nsresult aStatus
);
281 void InsertRuleFontFace(FontFace
* aFontFace
, StyleOrigin aOrigin
,
282 nsTArray
<FontFaceRecord
>& aOldRecords
,
283 bool& aFontSetModified
);
284 void InsertNonRuleFontFace(FontFace
* aFontFace
, bool& aFontSetModified
);
287 bool HasRuleFontFace(FontFace
* aFontFace
);
291 * Returns whether we have any loading FontFace objects in the FontFaceSet.
293 bool HasLoadingFontFaces();
295 // Whether mReady is pending, or would be when created.
296 bool ReadyPromiseIsPending() const;
298 // Helper function for HasLoadingFontFaces.
299 void UpdateHasLoadingFontFaces();
301 void ParseFontShorthandForMatching(const nsACString
& aFont
,
302 RefPtr
<SharedFontList
>& aFamilyList
,
303 FontWeight
& aWeight
, FontStretch
& aStretch
,
304 FontSlantStyle
& aStyle
, ErrorResult
& aRv
);
305 void FindMatchingFontFaces(const nsACString
& aFont
, const nsAString
& aText
,
306 nsTArray
<FontFace
*>& aFontFaces
, ErrorResult
& aRv
);
308 void DispatchLoadingEventAndReplaceReadyPromise();
309 void DispatchCheckLoadingFinishedAfterDelay();
311 TimeStamp
GetNavigationStartTimeStamp();
313 RefPtr
<UserFontSet
> mUserFontSet
;
315 // The document this is a FontFaceSet for.
316 RefPtr
<dom::Document
> mDocument
;
318 // The document's node principal, which is the principal font loads for
319 // this FontFaceSet will generally use. (This principal is not used for
320 // @font-face rules in UA and user sheets, where the principal of the
321 // sheet is used instead.)
323 // This field is used from GetStandardFontLoadPrincipal. When on a
324 // style worker thread, we use mStandardFontLoadPrincipal assuming
327 // Because mDocument's principal can change over time,
328 // its value must be updated by a call to ResetStandardFontLoadPrincipal.
329 RefPtr
<gfxFontSrcPrincipal
> mStandardFontLoadPrincipal
;
331 // A Promise that is fulfilled once all of the FontFace objects
332 // in mRuleFaces and mNonRuleFaces that started or were loading at the
333 // time the Promise was created have finished loading. It is rejected if
334 // any of those fonts failed to load. mReady is replaced with
335 // a new Promise object whenever mReady is settled and another
336 // FontFace in mRuleFaces or mNonRuleFaces starts to load.
337 // Note that mReady is created lazily when GetReady() is called.
338 RefPtr
<dom::Promise
> mReady
;
339 // Whether the ready promise must be resolved when it's created.
340 bool mResolveLazilyCreatedReadyPromise
;
342 // Set of all loaders pointing to us. These are not strong pointers,
343 // but that's OK because nsFontFaceLoader always calls RemoveLoader on
344 // us before it dies (unless we die first).
345 nsTHashtable
<nsPtrHashKey
<nsFontFaceLoader
>> mLoaders
;
347 // The @font-face rule backed FontFace objects in the FontFaceSet.
348 nsTArray
<FontFaceRecord
> mRuleFaces
;
350 // The non rule backed FontFace objects that have been added to this
352 nsTArray
<FontFaceRecord
> mNonRuleFaces
;
354 // The overall status of the loading or loaded fonts in the FontFaceSet.
355 dom::FontFaceSetLoadStatus mStatus
;
357 // A map from gfxFontFaceSrc pointer identity to whether the load is allowed
358 // by CSP or other checks. We store this here because querying CSP off the
359 // main thread is not a great idea.
361 // We could use just the pointer and use this as a hash set, but then we'd
362 // have no way to verify that we've checked all the loads we should.
363 nsTHashMap
<nsPtrHashKey
<const gfxFontFaceSrc
>, bool> mAllowedFontLoads
;
365 // Whether mNonRuleFaces has changed since last time UpdateRules ran.
366 bool mNonRuleFacesDirty
;
368 // Whether any FontFace objects in mRuleFaces or mNonRuleFaces are
369 // loading. Only valid when mHasLoadingFontFacesIsDirty is false. Don't use
370 // this variable directly; call the HasLoadingFontFaces method instead.
371 bool mHasLoadingFontFaces
;
373 // This variable is only valid when mLoadingDirty is false.
374 bool mHasLoadingFontFacesIsDirty
;
376 // Whether CheckLoadingFinished calls should be ignored. See comment in
377 // OnFontFaceStatusChanged.
378 bool mDelayedLoadCheck
;
380 // Whether the docshell for our document indicated that loads should
384 // Whether the docshell for our document indicates that we are in private
386 bool mPrivateBrowsing
;
390 } // namespace mozilla
392 #endif // !defined(mozilla_dom_FontFaceSet_h)