Source code

Revision control

Other Tools

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/. */
6
7
#ifndef mozilla_dom_FontFaceSet_h
8
#define mozilla_dom_FontFaceSet_h
9
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
17
struct gfxFontFaceSrc;
18
class gfxFontSrcPrincipal;
19
class gfxUserFontEntry;
20
class nsFontFaceLoader;
21
class nsIPrincipal;
22
class nsPIDOMWindowInner;
23
struct RawServoFontFaceRule;
24
25
namespace mozilla {
26
class PostTraversalTask;
27
class SharedFontList;
28
namespace dom {
29
class FontFace;
30
class Promise;
31
} // namespace dom
32
} // namespace mozilla
33
34
namespace mozilla {
35
namespace dom {
36
37
class FontFaceSet final : public DOMEventTargetHelper,
38
public nsIDOMEventListener,
39
public nsICSSLoaderObserver {
40
friend class mozilla::PostTraversalTask;
41
friend class UserFontSet;
42
43
public:
44
/**
45
* A gfxUserFontSet that integrates with the layout and style systems to
46
* manage @font-face rules and handle network requests for font loading.
47
*
48
* We would combine this class and FontFaceSet into the one class if it were
49
* possible; it's not because FontFaceSet is cycle collected and
50
* gfxUserFontSet isn't (and can't be, as gfx classes don't use the cycle
51
* collector). So UserFontSet exists just to override the needed virtual
52
* methods from gfxUserFontSet and to forward them on FontFaceSet.
53
*/
54
class UserFontSet final : public gfxUserFontSet {
55
friend class FontFaceSet;
56
57
public:
58
explicit UserFontSet(FontFaceSet* aFontFaceSet)
59
: mFontFaceSet(aFontFaceSet) {}
60
61
FontFaceSet* GetFontFaceSet() { return mFontFaceSet; }
62
63
gfxFontSrcPrincipal* GetStandardFontLoadPrincipal() const final {
64
return mFontFaceSet ? mFontFaceSet->mStandardFontLoadPrincipal.get()
65
: nullptr;
66
}
67
68
bool IsFontLoadAllowed(const gfxFontFaceSrc&) final;
69
70
void DispatchFontLoadViolations(
71
nsTArray<nsCOMPtr<nsIRunnable>>& aViolations) override;
72
73
virtual nsresult StartLoad(gfxUserFontEntry* aUserFontEntry,
74
const gfxFontFaceSrc* aFontFaceSrc) override;
75
76
void RecordFontLoadDone(uint32_t aFontSize, TimeStamp aDoneTime) override;
77
78
bool BypassCache() final {
79
return mFontFaceSet && mFontFaceSet->mBypassCache;
80
}
81
82
protected:
83
virtual bool GetPrivateBrowsing() override;
84
virtual nsresult SyncLoadFontData(gfxUserFontEntry* aFontToLoad,
85
const gfxFontFaceSrc* aFontFaceSrc,
86
uint8_t*& aBuffer,
87
uint32_t& aBufferLength) override;
88
virtual nsresult LogMessage(gfxUserFontEntry* aUserFontEntry,
89
const char* aMessage,
90
uint32_t aFlags = nsIScriptError::errorFlag,
91
nsresult aStatus = NS_OK) override;
92
virtual void DoRebuildUserFontSet() override;
93
already_AddRefed<gfxUserFontEntry> CreateUserFontEntry(
94
const nsTArray<gfxFontFaceSrc>& aFontFaceSrcList, WeightRange aWeight,
95
StretchRange aStretch, SlantStyleRange aStyle,
96
const nsTArray<gfxFontFeature>& aFeatureSettings,
97
const nsTArray<gfxFontVariation>& aVariationSettings,
98
uint32_t aLanguageOverride, gfxCharacterMap* aUnicodeRanges,
99
StyleFontDisplay aFontDisplay, RangeFlags aRangeFlags) override;
100
101
private:
102
RefPtr<FontFaceSet> mFontFaceSet;
103
};
104
105
NS_DECL_ISUPPORTS_INHERITED
106
NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(FontFaceSet, DOMEventTargetHelper)
107
NS_DECL_NSIDOMEVENTLISTENER
108
109
FontFaceSet(nsPIDOMWindowInner* aWindow, dom::Document* aDocument);
110
111
virtual JSObject* WrapObject(JSContext* aCx,
112
JS::Handle<JSObject*> aGivenProto) override;
113
114
UserFontSet* GetUserFontSet() { return mUserFontSet; }
115
116
// Called by nsFontFaceLoader when the loader has completed normally.
117
// It's removed from the mLoaders set.
118
void RemoveLoader(nsFontFaceLoader* aLoader);
119
120
bool UpdateRules(const nsTArray<nsFontFaceRuleContainer>& aRules);
121
122
nsPresContext* GetPresContext();
123
124
// search for @font-face rule that matches a platform font entry
125
RawServoFontFaceRule* FindRuleForEntry(gfxFontEntry* aFontEntry);
126
127
void IncrementGeneration(bool aIsRebuild = false);
128
129
/**
130
* Finds an existing entry in the user font cache or creates a new user
131
* font entry for the given FontFace object.
132
*/
133
static already_AddRefed<gfxUserFontEntry>
134
FindOrCreateUserFontEntryFromFontFace(FontFace* aFontFace);
135
136
/**
137
* Notification method called by a FontFace to indicate that its loading
138
* status has changed.
139
*/
140
void OnFontFaceStatusChanged(FontFace* aFontFace);
141
142
/**
143
* Notification method called by the nsPresContext to indicate that the
144
* refresh driver ticked and flushed style and layout.
145
* were just flushed.
146
*/
147
void DidRefresh();
148
149
/**
150
* Returns whether the "layout.css.font-loading-api.enabled" pref is true.
151
*/
152
static bool PrefEnabled();
153
154
// nsICSSLoaderObserver
155
NS_IMETHOD StyleSheetLoaded(StyleSheet* aSheet, bool aWasDeferred,
156
nsresult aStatus) override;
157
158
FontFace* GetFontFaceAt(uint32_t aIndex);
159
160
void FlushUserFontSet();
161
162
static nsPresContext* GetPresContextFor(gfxUserFontSet* aUserFontSet) {
163
FontFaceSet* set = static_cast<UserFontSet*>(aUserFontSet)->mFontFaceSet;
164
return set ? set->GetPresContext() : nullptr;
165
}
166
167
void RefreshStandardFontLoadPrincipal();
168
169
void CopyNonRuleFacesTo(FontFaceSet* aFontFaceSet) const;
170
171
dom::Document* Document() const { return mDocument; }
172
173
// -- Web IDL --------------------------------------------------------------
174
175
IMPL_EVENT_HANDLER(loading)
176
IMPL_EVENT_HANDLER(loadingdone)
177
IMPL_EVENT_HANDLER(loadingerror)
178
already_AddRefed<dom::Promise> Load(JSContext* aCx, const nsAString& aFont,
179
const nsAString& aText, ErrorResult& aRv);
180
bool Check(const nsAString& aFont, const nsAString& aText, ErrorResult& aRv);
181
dom::Promise* GetReady(ErrorResult& aRv);
182
dom::FontFaceSetLoadStatus Status();
183
184
void Add(FontFace& aFontFace, ErrorResult& aRv);
185
void Clear();
186
bool Delete(FontFace& aFontFace);
187
bool Has(FontFace& aFontFace);
188
uint32_t Size();
189
already_AddRefed<dom::FontFaceSetIterator> Entries();
190
already_AddRefed<dom::FontFaceSetIterator> Values();
191
MOZ_CAN_RUN_SCRIPT
192
void ForEach(JSContext* aCx, FontFaceSetForEachCallback& aCallback,
193
JS::Handle<JS::Value> aThisArg, ErrorResult& aRv);
194
195
// For ServoStyleSet to know ahead of time whether a font is loadable.
196
void CacheFontLoadability();
197
198
void MarkUserFontSetDirty();
199
200
private:
201
~FontFaceSet();
202
203
/**
204
* Returns whether the given FontFace is currently "in" the FontFaceSet.
205
*/
206
bool HasAvailableFontFace(FontFace* aFontFace);
207
208
/**
209
* Removes any listeners and observers.
210
*/
211
void Disconnect();
212
213
void RemoveDOMContentLoadedListener();
214
215
/**
216
* Returns whether there might be any pending font loads, which should cause
217
* the mReady Promise not to be resolved yet.
218
*/
219
bool MightHavePendingFontLoads();
220
221
/**
222
* Checks to see whether it is time to replace mReady and dispatch a
223
* "loading" event.
224
*/
225
void CheckLoadingStarted();
226
227
/**
228
* Checks to see whether it is time to resolve mReady and dispatch any
229
* "loadingdone" and "loadingerror" events.
230
*/
231
void CheckLoadingFinished();
232
233
/**
234
* Callback for invoking CheckLoadingFinished after going through the
235
* event loop. See OnFontFaceStatusChanged.
236
*/
237
void CheckLoadingFinishedAfterDelay();
238
239
/**
240
* Dispatches a FontFaceSetLoadEvent to this object.
241
*/
242
void DispatchLoadingFinishedEvent(
243
const nsAString& aType, nsTArray<OwningNonNull<FontFace>>&& aFontFaces);
244
245
// Note: if you add new cycle collected objects to FontFaceRecord,
246
// make sure to update FontFaceSet's cycle collection macros
247
// accordingly.
248
struct FontFaceRecord {
249
RefPtr<FontFace> mFontFace;
250
Maybe<StyleOrigin> mOrigin; // only relevant for mRuleFaces entries
251
252
// When true, indicates that when finished loading, the FontFace should be
253
// included in the subsequent loadingdone/loadingerror event fired at the
254
// FontFaceSet.
255
bool mLoadEventShouldFire;
256
};
257
258
static already_AddRefed<gfxUserFontEntry>
259
FindOrCreateUserFontEntryFromFontFace(const nsACString& aFamilyName,
260
FontFace* aFontFace, StyleOrigin);
261
262
// search for @font-face rule that matches a userfont font entry
263
RawServoFontFaceRule* FindRuleForUserFontEntry(
264
gfxUserFontEntry* aUserFontEntry);
265
266
nsresult StartLoad(gfxUserFontEntry* aUserFontEntry,
267
const gfxFontFaceSrc* aFontFaceSrc);
268
gfxFontSrcPrincipal* GetStandardFontLoadPrincipal();
269
nsresult CheckFontLoad(const gfxFontFaceSrc* aFontFaceSrc,
270
gfxFontSrcPrincipal** aPrincipal, bool* aBypassCache);
271
bool IsFontLoadAllowed(const gfxFontFaceSrc& aSrc);
272
273
void DispatchFontLoadViolations(nsTArray<nsCOMPtr<nsIRunnable>>& aViolations);
274
nsresult SyncLoadFontData(gfxUserFontEntry* aFontToLoad,
275
const gfxFontFaceSrc* aFontFaceSrc,
276
uint8_t*& aBuffer, uint32_t& aBufferLength);
277
nsresult LogMessage(gfxUserFontEntry* aUserFontEntry, const char* aMessage,
278
uint32_t aFlags, nsresult aStatus);
279
280
void InsertRuleFontFace(FontFace* aFontFace, StyleOrigin aOrigin,
281
nsTArray<FontFaceRecord>& aOldRecords,
282
bool& aFontSetModified);
283
void InsertNonRuleFontFace(FontFace* aFontFace, bool& aFontSetModified);
284
285
#ifdef DEBUG
286
bool HasRuleFontFace(FontFace* aFontFace);
287
#endif
288
289
/**
290
* Returns whether we have any loading FontFace objects in the FontFaceSet.
291
*/
292
bool HasLoadingFontFaces();
293
294
// Whether mReady is pending, or would be when created.
295
bool ReadyPromiseIsPending() const;
296
297
// Helper function for HasLoadingFontFaces.
298
void UpdateHasLoadingFontFaces();
299
300
void ParseFontShorthandForMatching(const nsAString& aFont,
301
RefPtr<SharedFontList>& aFamilyList,
302
FontWeight& aWeight, FontStretch& aStretch,
303
FontSlantStyle& aStyle, ErrorResult& aRv);
304
void FindMatchingFontFaces(const nsAString& aFont, const nsAString& aText,
305
nsTArray<FontFace*>& aFontFaces, ErrorResult& aRv);
306
307
void DispatchLoadingEventAndReplaceReadyPromise();
308
void DispatchCheckLoadingFinishedAfterDelay();
309
310
TimeStamp GetNavigationStartTimeStamp();
311
312
RefPtr<UserFontSet> mUserFontSet;
313
314
// The document this is a FontFaceSet for.
315
RefPtr<dom::Document> mDocument;
316
317
// The document's node principal, which is the principal font loads for
318
// this FontFaceSet will generally use. (This principal is not used for
319
// @font-face rules in UA and user sheets, where the principal of the
320
// sheet is used instead.)
321
//
322
// This field is used from GetStandardFontLoadPrincipal. When on a
323
// style worker thread, we use mStandardFontLoadPrincipal assuming
324
// it is up to date.
325
//
326
// Because mDocument's principal can change over time,
327
// its value must be updated by a call to ResetStandardFontLoadPrincipal.
328
RefPtr<gfxFontSrcPrincipal> mStandardFontLoadPrincipal;
329
330
// A Promise that is fulfilled once all of the FontFace objects
331
// in mRuleFaces and mNonRuleFaces that started or were loading at the
332
// time the Promise was created have finished loading. It is rejected if
333
// any of those fonts failed to load. mReady is replaced with
334
// a new Promise object whenever mReady is settled and another
335
// FontFace in mRuleFaces or mNonRuleFaces starts to load.
336
// Note that mReady is created lazily when GetReady() is called.
337
RefPtr<dom::Promise> mReady;
338
// Whether the ready promise must be resolved when it's created.
339
bool mResolveLazilyCreatedReadyPromise;
340
341
// Set of all loaders pointing to us. These are not strong pointers,
342
// but that's OK because nsFontFaceLoader always calls RemoveLoader on
343
// us before it dies (unless we die first).
344
nsTHashtable<nsPtrHashKey<nsFontFaceLoader>> mLoaders;
345
346
// The @font-face rule backed FontFace objects in the FontFaceSet.
347
nsTArray<FontFaceRecord> mRuleFaces;
348
349
// The non rule backed FontFace objects that have been added to this
350
// FontFaceSet.
351
nsTArray<FontFaceRecord> mNonRuleFaces;
352
353
// The overall status of the loading or loaded fonts in the FontFaceSet.
354
dom::FontFaceSetLoadStatus mStatus;
355
356
// A map from gfxFontFaceSrc pointer identity to whether the load is allowed
357
// by CSP or other checks. We store this here because querying CSP off the
358
// main thread is not a great idea.
359
//
360
// We could use just the pointer and use this as a hash set, but then we'd
361
// have no way to verify that we've checked all the loads we should.
362
nsDataHashtable<nsPtrHashKey<const gfxFontFaceSrc>, bool> mAllowedFontLoads;
363
364
// Whether mNonRuleFaces has changed since last time UpdateRules ran.
365
bool mNonRuleFacesDirty;
366
367
// Whether any FontFace objects in mRuleFaces or mNonRuleFaces are
368
// loading. Only valid when mHasLoadingFontFacesIsDirty is false. Don't use
369
// this variable directly; call the HasLoadingFontFaces method instead.
370
bool mHasLoadingFontFaces;
371
372
// This variable is only valid when mLoadingDirty is false.
373
bool mHasLoadingFontFacesIsDirty;
374
375
// Whether CheckLoadingFinished calls should be ignored. See comment in
376
// OnFontFaceStatusChanged.
377
bool mDelayedLoadCheck;
378
379
// Whether the docshell for our document indicated that loads should
380
// bypass the cache.
381
bool mBypassCache;
382
383
// Whether the docshell for our document indicates that we are in private
384
// browsing mode.
385
bool mPrivateBrowsing;
386
};
387
388
} // namespace dom
389
} // namespace mozilla
390
391
#endif // !defined(mozilla_dom_FontFaceSet_h)