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 file,
5
* You can obtain one at http://mozilla.org/MPL/2.0/. */
6
7
#include "FontFaceSet.h"
8
9
#include "gfxFontConstants.h"
10
#include "gfxFontSrcPrincipal.h"
11
#include "gfxFontSrcURI.h"
12
#include "mozilla/css/Loader.h"
13
#include "mozilla/dom/CSSFontFaceRule.h"
14
#include "mozilla/dom/Event.h"
15
#include "mozilla/dom/FontFaceSetBinding.h"
16
#include "mozilla/dom/FontFaceSetIterator.h"
17
#include "mozilla/dom/FontFaceSetLoadEvent.h"
18
#include "mozilla/dom/FontFaceSetLoadEventBinding.h"
19
#include "mozilla/dom/Promise.h"
20
#include "mozilla/FontPropertyTypes.h"
21
#include "mozilla/AsyncEventDispatcher.h"
22
#include "mozilla/BasePrincipal.h"
23
#include "mozilla/Logging.h"
24
#include "mozilla/Preferences.h"
25
#include "mozilla/PresShell.h"
26
#include "mozilla/PresShellInlines.h"
27
#include "mozilla/ServoBindings.h"
28
#include "mozilla/ServoCSSParser.h"
29
#include "mozilla/ServoStyleSet.h"
30
#include "mozilla/ServoUtils.h"
31
#include "mozilla/Sprintf.h"
32
#include "mozilla/StaticPrefs_layout.h"
33
#include "mozilla/Telemetry.h"
34
#include "mozilla/LoadInfo.h"
35
#include "nsAutoPtr.h"
36
#include "nsContentPolicyUtils.h"
37
#include "nsDeviceContext.h"
38
#include "nsFontFaceLoader.h"
39
#include "nsIClassOfService.h"
40
#include "nsIConsoleService.h"
41
#include "nsIContentPolicy.h"
42
#include "nsIDocShell.h"
43
#include "mozilla/dom/Document.h"
44
#include "nsILoadContext.h"
45
#include "nsINetworkPredictor.h"
46
#include "nsIPrincipal.h"
47
#include "nsISupportsPriority.h"
48
#include "nsIWebNavigation.h"
49
#include "nsNetUtil.h"
50
#include "nsIInputStream.h"
51
#include "nsLayoutUtils.h"
52
#include "nsPresContext.h"
53
#include "nsPrintfCString.h"
54
#include "nsUTF8Utils.h"
55
#include "nsDOMNavigationTiming.h"
56
#include "ReferrerInfo.h"
57
58
using namespace mozilla;
59
using namespace mozilla::css;
60
using namespace mozilla::dom;
61
62
#define LOG(args) \
63
MOZ_LOG(gfxUserFontSet::GetUserFontsLog(), mozilla::LogLevel::Debug, args)
64
#define LOG_ENABLED() \
65
MOZ_LOG_TEST(gfxUserFontSet::GetUserFontsLog(), LogLevel::Debug)
66
67
NS_IMPL_CYCLE_COLLECTION_CLASS(FontFaceSet)
68
69
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(FontFaceSet,
70
DOMEventTargetHelper)
71
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mDocument);
72
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mReady);
73
for (size_t i = 0; i < tmp->mRuleFaces.Length(); i++) {
74
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mRuleFaces[i].mFontFace);
75
}
76
for (size_t i = 0; i < tmp->mNonRuleFaces.Length(); i++) {
77
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mNonRuleFaces[i].mFontFace);
78
}
79
if (tmp->mUserFontSet) {
80
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mUserFontSet->mFontFaceSet);
81
}
82
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
83
84
NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN_INHERITED(FontFaceSet,
85
DOMEventTargetHelper)
86
tmp->Disconnect();
87
NS_IMPL_CYCLE_COLLECTION_UNLINK(mDocument);
88
NS_IMPL_CYCLE_COLLECTION_UNLINK(mReady);
89
for (size_t i = 0; i < tmp->mRuleFaces.Length(); i++) {
90
NS_IMPL_CYCLE_COLLECTION_UNLINK(mRuleFaces[i].mFontFace);
91
}
92
for (size_t i = 0; i < tmp->mNonRuleFaces.Length(); i++) {
93
NS_IMPL_CYCLE_COLLECTION_UNLINK(mNonRuleFaces[i].mFontFace);
94
}
95
if (tmp->mUserFontSet) {
96
NS_IMPL_CYCLE_COLLECTION_UNLINK(mUserFontSet->mFontFaceSet);
97
}
98
NS_IMPL_CYCLE_COLLECTION_UNLINK(mUserFontSet);
99
NS_IMPL_CYCLE_COLLECTION_UNLINK_END
100
101
NS_IMPL_ADDREF_INHERITED(FontFaceSet, DOMEventTargetHelper)
102
NS_IMPL_RELEASE_INHERITED(FontFaceSet, DOMEventTargetHelper)
103
104
NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(FontFaceSet)
105
NS_INTERFACE_MAP_ENTRY(nsIDOMEventListener)
106
NS_INTERFACE_MAP_ENTRY(nsICSSLoaderObserver)
107
NS_INTERFACE_MAP_END_INHERITING(DOMEventTargetHelper)
108
109
FontFaceSet::FontFaceSet(nsPIDOMWindowInner* aWindow, dom::Document* aDocument)
110
: DOMEventTargetHelper(aWindow),
111
mDocument(aDocument),
112
mStandardFontLoadPrincipal(
113
new gfxFontSrcPrincipal(mDocument->NodePrincipal())),
114
mResolveLazilyCreatedReadyPromise(false),
115
mStatus(FontFaceSetLoadStatus::Loaded),
116
mNonRuleFacesDirty(false),
117
mHasLoadingFontFaces(false),
118
mHasLoadingFontFacesIsDirty(false),
119
mDelayedLoadCheck(false),
120
mBypassCache(false),
121
mPrivateBrowsing(false) {
122
MOZ_ASSERT(mDocument, "We should get a valid document from the caller!");
123
124
mStandardFontLoadPrincipal =
125
new gfxFontSrcPrincipal(mDocument->NodePrincipal());
126
127
// Record the state of the "bypass cache" flags from the docshell now,
128
// since we want to look at them from style worker threads, and we can
129
// only get to the docshell through a weak pointer (which is only
130
// possible on the main thread).
131
//
132
// In theory the load type of a docshell could change after the document
133
// is loaded, but handling that doesn't seem too important.
134
if (nsCOMPtr<nsIDocShell> docShell = mDocument->GetDocShell()) {
135
uint32_t loadType;
136
uint32_t flags;
137
if ((NS_SUCCEEDED(docShell->GetLoadType(&loadType)) &&
138
((loadType >> 16) & nsIWebNavigation::LOAD_FLAGS_BYPASS_CACHE)) ||
139
(NS_SUCCEEDED(docShell->GetDefaultLoadFlags(&flags)) &&
140
(flags & nsIRequest::LOAD_BYPASS_CACHE))) {
141
mBypassCache = true;
142
}
143
}
144
145
// Same for the "private browsing" flag.
146
if (nsCOMPtr<nsILoadContext> loadContext = mDocument->GetLoadContext()) {
147
mPrivateBrowsing = loadContext->UsePrivateBrowsing();
148
}
149
150
if (!mDocument->DidFireDOMContentLoaded()) {
151
mDocument->AddSystemEventListener(NS_LITERAL_STRING("DOMContentLoaded"),
152
this, false, false);
153
} else {
154
// In some cases we can't rely on CheckLoadingFinished being called from
155
// the refresh driver. For example, documents in display:none iframes.
156
// Or if the document has finished loading and painting at the time that
157
// script requests document.fonts and causes us to get here.
158
CheckLoadingFinished();
159
}
160
161
mDocument->CSSLoader()->AddObserver(this);
162
163
mUserFontSet = new UserFontSet(this);
164
}
165
166
FontFaceSet::~FontFaceSet() {
167
// Assert that we don't drop any FontFaceSet objects during a Servo traversal,
168
// since PostTraversalTask objects can hold raw pointers to FontFaceSets.
169
MOZ_ASSERT(!ServoStyleSet::IsInServoTraversal());
170
171
Disconnect();
172
}
173
174
JSObject* FontFaceSet::WrapObject(JSContext* aContext,
175
JS::Handle<JSObject*> aGivenProto) {
176
return FontFaceSet_Binding::Wrap(aContext, this, aGivenProto);
177
}
178
179
void FontFaceSet::Disconnect() {
180
RemoveDOMContentLoadedListener();
181
182
if (mDocument && mDocument->CSSLoader()) {
183
// We're null checking CSSLoader() since FontFaceSet::Disconnect() might be
184
// being called during unlink, at which time the loader amy already have
185
// been unlinked from the document.
186
mDocument->CSSLoader()->RemoveObserver(this);
187
}
188
189
for (auto it = mLoaders.Iter(); !it.Done(); it.Next()) {
190
it.Get()->GetKey()->Cancel();
191
}
192
193
mLoaders.Clear();
194
}
195
196
void FontFaceSet::RemoveDOMContentLoadedListener() {
197
if (mDocument) {
198
mDocument->RemoveSystemEventListener(NS_LITERAL_STRING("DOMContentLoaded"),
199
this, false);
200
}
201
}
202
203
void FontFaceSet::ParseFontShorthandForMatching(
204
const nsAString& aFont, RefPtr<SharedFontList>& aFamilyList,
205
FontWeight& aWeight, FontStretch& aStretch, FontSlantStyle& aStyle,
206
ErrorResult& aRv) {
207
auto style = StyleComputedFontStyleDescriptor::Normal();
208
float stretch;
209
float weight;
210
211
RefPtr<URLExtraData> url = ServoCSSParser::GetURLExtraData(mDocument);
212
if (!ServoCSSParser::ParseFontShorthandForMatching(aFont, url, aFamilyList,
213
style, stretch, weight)) {
214
aRv.Throw(NS_ERROR_DOM_SYNTAX_ERR);
215
return;
216
}
217
218
switch (style.tag) {
219
case StyleComputedFontStyleDescriptor::Tag::Normal:
220
aStyle = FontSlantStyle::Normal();
221
break;
222
case StyleComputedFontStyleDescriptor::Tag::Italic:
223
aStyle = FontSlantStyle::Italic();
224
break;
225
case StyleComputedFontStyleDescriptor::Tag::Oblique:
226
MOZ_ASSERT(style.AsOblique()._0 == style.AsOblique()._1,
227
"We use ComputedFontStyleDescriptor just for convenience, "
228
"the two values should always match");
229
aStyle = FontSlantStyle::Oblique(style.AsOblique()._0);
230
break;
231
}
232
233
aWeight = FontWeight(weight);
234
aStretch = FontStretch::FromStyle(stretch);
235
}
236
237
static bool HasAnyCharacterInUnicodeRange(gfxUserFontEntry* aEntry,
238
const nsAString& aInput) {
239
const char16_t* p = aInput.Data();
240
const char16_t* end = p + aInput.Length();
241
242
while (p < end) {
243
uint32_t c = UTF16CharEnumerator::NextChar(&p, end);
244
if (aEntry->CharacterInUnicodeRange(c)) {
245
return true;
246
}
247
}
248
return false;
249
}
250
251
void FontFaceSet::FindMatchingFontFaces(const nsAString& aFont,
252
const nsAString& aText,
253
nsTArray<FontFace*>& aFontFaces,
254
ErrorResult& aRv) {
255
RefPtr<SharedFontList> familyList;
256
FontWeight weight;
257
FontStretch stretch;
258
FontSlantStyle italicStyle;
259
ParseFontShorthandForMatching(aFont, familyList, weight, stretch, italicStyle,
260
aRv);
261
if (aRv.Failed()) {
262
return;
263
}
264
265
gfxFontStyle style;
266
style.style = italicStyle;
267
style.weight = weight;
268
style.stretch = stretch;
269
270
nsTArray<FontFaceRecord>* arrays[2];
271
arrays[0] = &mNonRuleFaces;
272
arrays[1] = &mRuleFaces;
273
274
// Set of FontFaces that we want to return.
275
nsTHashtable<nsPtrHashKey<FontFace>> matchingFaces;
276
277
for (const FontFamilyName& fontFamilyName : familyList->mNames) {
278
if (!fontFamilyName.IsNamed()) {
279
continue;
280
}
281
282
RefPtr<gfxFontFamily> family =
283
mUserFontSet->LookupFamily(nsAtomCString(fontFamilyName.mName));
284
285
if (!family) {
286
continue;
287
}
288
289
AutoTArray<gfxFontEntry*, 4> entries;
290
family->FindAllFontsForStyle(style, entries);
291
292
for (gfxFontEntry* e : entries) {
293
FontFace::Entry* entry = static_cast<FontFace::Entry*>(e);
294
if (HasAnyCharacterInUnicodeRange(entry, aText)) {
295
for (FontFace* f : entry->GetFontFaces()) {
296
matchingFaces.PutEntry(f);
297
}
298
}
299
}
300
}
301
302
// Add all FontFaces in matchingFaces to aFontFaces, in the order
303
// they appear in the FontFaceSet.
304
for (nsTArray<FontFaceRecord>* array : arrays) {
305
for (FontFaceRecord& record : *array) {
306
FontFace* f = record.mFontFace;
307
if (matchingFaces.Contains(f)) {
308
aFontFaces.AppendElement(f);
309
}
310
}
311
}
312
}
313
314
TimeStamp FontFaceSet::GetNavigationStartTimeStamp() {
315
TimeStamp navStart;
316
RefPtr<nsDOMNavigationTiming> timing(mDocument->GetNavigationTiming());
317
if (timing) {
318
navStart = timing->GetNavigationStartTimeStamp();
319
}
320
return navStart;
321
}
322
323
already_AddRefed<Promise> FontFaceSet::Load(JSContext* aCx,
324
const nsAString& aFont,
325
const nsAString& aText,
326
ErrorResult& aRv) {
327
FlushUserFontSet();
328
329
nsTArray<RefPtr<Promise>> promises;
330
331
nsTArray<FontFace*> faces;
332
FindMatchingFontFaces(aFont, aText, faces, aRv);
333
if (aRv.Failed()) {
334
return nullptr;
335
}
336
337
for (FontFace* f : faces) {
338
RefPtr<Promise> promise = f->Load(aRv);
339
if (aRv.Failed()) {
340
return nullptr;
341
}
342
if (!promises.AppendElement(promise, fallible)) {
343
aRv.Throw(NS_ERROR_FAILURE);
344
return nullptr;
345
}
346
}
347
348
return Promise::All(aCx, promises, aRv);
349
}
350
351
bool FontFaceSet::Check(const nsAString& aFont, const nsAString& aText,
352
ErrorResult& aRv) {
353
FlushUserFontSet();
354
355
nsTArray<FontFace*> faces;
356
FindMatchingFontFaces(aFont, aText, faces, aRv);
357
if (aRv.Failed()) {
358
return false;
359
}
360
361
for (FontFace* f : faces) {
362
if (f->Status() != FontFaceLoadStatus::Loaded) {
363
return false;
364
}
365
}
366
367
return true;
368
}
369
370
bool FontFaceSet::ReadyPromiseIsPending() const {
371
return mReady ? mReady->State() == Promise::PromiseState::Pending
372
: !mResolveLazilyCreatedReadyPromise;
373
}
374
375
Promise* FontFaceSet::GetReady(ErrorResult& aRv) {
376
MOZ_ASSERT(NS_IsMainThread());
377
378
// There may be outstanding style changes that will trigger the loading of
379
// new fonts. We need to flush layout to initiate any such loads so that
380
// if mReady is currently resolved we replace it with a new pending Promise.
381
// (That replacement will happen under this flush call.)
382
if (!ReadyPromiseIsPending() && mDocument) {
383
mDocument->FlushPendingNotifications(FlushType::Layout);
384
}
385
386
if (!mReady) {
387
nsCOMPtr<nsIGlobalObject> global = GetParentObject();
388
mReady = Promise::Create(global, aRv);
389
if (!mReady) {
390
aRv.Throw(NS_ERROR_FAILURE);
391
return nullptr;
392
}
393
if (mResolveLazilyCreatedReadyPromise) {
394
mReady->MaybeResolve(this);
395
mResolveLazilyCreatedReadyPromise = false;
396
}
397
}
398
399
return mReady;
400
}
401
402
FontFaceSetLoadStatus FontFaceSet::Status() {
403
FlushUserFontSet();
404
return mStatus;
405
}
406
407
#ifdef DEBUG
408
bool FontFaceSet::HasRuleFontFace(FontFace* aFontFace) {
409
for (size_t i = 0; i < mRuleFaces.Length(); i++) {
410
if (mRuleFaces[i].mFontFace == aFontFace) {
411
return true;
412
}
413
}
414
return false;
415
}
416
#endif
417
418
static bool IsPdfJs(nsIPrincipal* aPrincipal) {
419
if (!aPrincipal) {
420
return false;
421
}
422
nsCOMPtr<nsIURI> uri;
423
aPrincipal->GetURI(getter_AddRefs(uri));
424
return uri && uri->GetSpecOrDefault().EqualsLiteral(
426
}
427
428
void FontFaceSet::Add(FontFace& aFontFace, ErrorResult& aRv) {
429
FlushUserFontSet();
430
431
if (aFontFace.IsInFontFaceSet(this)) {
432
return;
433
}
434
435
if (aFontFace.HasRule()) {
436
aRv.Throw(NS_ERROR_DOM_INVALID_MODIFICATION_ERR);
437
return;
438
}
439
440
aFontFace.AddFontFaceSet(this);
441
442
#ifdef DEBUG
443
for (const FontFaceRecord& rec : mNonRuleFaces) {
444
MOZ_ASSERT(rec.mFontFace != &aFontFace,
445
"FontFace should not occur in mNonRuleFaces twice");
446
}
447
#endif
448
449
FontFaceRecord* rec = mNonRuleFaces.AppendElement();
450
rec->mFontFace = &aFontFace;
451
rec->mOrigin = Nothing();
452
rec->mLoadEventShouldFire =
453
aFontFace.Status() == FontFaceLoadStatus::Unloaded ||
454
aFontFace.Status() == FontFaceLoadStatus::Loading;
455
456
mNonRuleFacesDirty = true;
457
MarkUserFontSetDirty();
458
mHasLoadingFontFacesIsDirty = true;
459
CheckLoadingStarted();
460
RefPtr<dom::Document> clonedDoc = mDocument->GetLatestStaticClone();
461
if (clonedDoc) {
462
// The document is printing, copy the font to the static clone as well.
463
nsCOMPtr<nsIPrincipal> principal = mDocument->GetPrincipal();
464
if (principal->IsSystemPrincipal() || IsPdfJs(principal)) {
465
ErrorResult rv;
466
clonedDoc->Fonts()->Add(aFontFace, rv);
467
MOZ_ASSERT(!rv.Failed());
468
}
469
}
470
}
471
472
void FontFaceSet::Clear() {
473
FlushUserFontSet();
474
475
if (mNonRuleFaces.IsEmpty()) {
476
return;
477
}
478
479
for (size_t i = 0; i < mNonRuleFaces.Length(); i++) {
480
FontFace* f = mNonRuleFaces[i].mFontFace;
481
f->RemoveFontFaceSet(this);
482
}
483
484
mNonRuleFaces.Clear();
485
mNonRuleFacesDirty = true;
486
MarkUserFontSetDirty();
487
mHasLoadingFontFacesIsDirty = true;
488
CheckLoadingFinished();
489
}
490
491
bool FontFaceSet::Delete(FontFace& aFontFace) {
492
FlushUserFontSet();
493
494
if (aFontFace.HasRule()) {
495
return false;
496
}
497
498
bool removed = false;
499
for (size_t i = 0; i < mNonRuleFaces.Length(); i++) {
500
if (mNonRuleFaces[i].mFontFace == &aFontFace) {
501
mNonRuleFaces.RemoveElementAt(i);
502
removed = true;
503
break;
504
}
505
}
506
if (!removed) {
507
return false;
508
}
509
510
aFontFace.RemoveFontFaceSet(this);
511
512
mNonRuleFacesDirty = true;
513
MarkUserFontSetDirty();
514
mHasLoadingFontFacesIsDirty = true;
515
CheckLoadingFinished();
516
return true;
517
}
518
519
bool FontFaceSet::HasAvailableFontFace(FontFace* aFontFace) {
520
return aFontFace->IsInFontFaceSet(this);
521
}
522
523
bool FontFaceSet::Has(FontFace& aFontFace) {
524
FlushUserFontSet();
525
526
return HasAvailableFontFace(&aFontFace);
527
}
528
529
FontFace* FontFaceSet::GetFontFaceAt(uint32_t aIndex) {
530
FlushUserFontSet();
531
532
if (aIndex < mRuleFaces.Length()) {
533
return mRuleFaces[aIndex].mFontFace;
534
}
535
536
aIndex -= mRuleFaces.Length();
537
if (aIndex < mNonRuleFaces.Length()) {
538
return mNonRuleFaces[aIndex].mFontFace;
539
}
540
541
return nullptr;
542
}
543
544
uint32_t FontFaceSet::Size() {
545
FlushUserFontSet();
546
547
// Web IDL objects can only expose array index properties up to INT32_MAX.
548
549
size_t total = mRuleFaces.Length() + mNonRuleFaces.Length();
550
return std::min<size_t>(total, INT32_MAX);
551
}
552
553
already_AddRefed<FontFaceSetIterator> FontFaceSet::Entries() {
554
RefPtr<FontFaceSetIterator> it = new FontFaceSetIterator(this, true);
555
return it.forget();
556
}
557
558
already_AddRefed<FontFaceSetIterator> FontFaceSet::Values() {
559
RefPtr<FontFaceSetIterator> it = new FontFaceSetIterator(this, false);
560
return it.forget();
561
}
562
563
void FontFaceSet::ForEach(JSContext* aCx, FontFaceSetForEachCallback& aCallback,
564
JS::Handle<JS::Value> aThisArg, ErrorResult& aRv) {
565
JS::Rooted<JS::Value> thisArg(aCx, aThisArg);
566
for (size_t i = 0; i < Size(); i++) {
567
RefPtr<FontFace> face = GetFontFaceAt(i);
568
aCallback.Call(thisArg, *face, *face, *this, aRv);
569
if (aRv.Failed()) {
570
return;
571
}
572
}
573
}
574
575
void FontFaceSet::RemoveLoader(nsFontFaceLoader* aLoader) {
576
mLoaders.RemoveEntry(aLoader);
577
}
578
579
nsresult FontFaceSet::StartLoad(gfxUserFontEntry* aUserFontEntry,
580
const gfxFontFaceSrc* aFontFaceSrc) {
581
nsresult rv;
582
583
nsCOMPtr<nsIStreamLoader> streamLoader;
584
nsCOMPtr<nsILoadGroup> loadGroup(mDocument->GetDocumentLoadGroup());
585
gfxFontSrcPrincipal* principal = aUserFontEntry->GetPrincipal();
586
587
uint32_t securityFlags = 0;
588
if (aFontFaceSrc->mURI->get()->SchemeIs("file")) {
589
securityFlags = nsILoadInfo::SEC_ALLOW_CROSS_ORIGIN_DATA_INHERITS;
590
} else {
591
securityFlags = nsILoadInfo::SEC_REQUIRE_CORS_DATA_INHERITS;
592
}
593
594
nsCOMPtr<nsIChannel> channel;
595
// Note we are calling NS_NewChannelWithTriggeringPrincipal() with both a
596
// node and a principal. This is because the document where the font is
597
// being loaded might have a different origin from the principal of the
598
// stylesheet that initiated the font load.
599
rv = NS_NewChannelWithTriggeringPrincipal(
600
getter_AddRefs(channel), aFontFaceSrc->mURI->get(), mDocument,
601
principal ? principal->get() : nullptr, securityFlags,
602
nsIContentPolicy::TYPE_FONT,
603
nullptr, // PerformanceStorage
604
loadGroup);
605
NS_ENSURE_SUCCESS(rv, rv);
606
607
RefPtr<nsFontFaceLoader> fontLoader = new nsFontFaceLoader(
608
aUserFontEntry, aFontFaceSrc->mURI->get(), this, channel);
609
mLoaders.PutEntry(fontLoader);
610
611
if (LOG_ENABLED()) {
612
nsCOMPtr<nsIURI> referrer =
613
aFontFaceSrc->mReferrerInfo
614
? aFontFaceSrc->mReferrerInfo->GetOriginalReferrer()
615
: nullptr;
616
LOG(
617
("userfonts (%p) download start - font uri: (%s) "
618
"referrer uri: (%s)\n",
619
fontLoader.get(), aFontFaceSrc->mURI->GetSpecOrDefault().get(),
620
referrer ? referrer->GetSpecOrDefault().get() : ""));
621
}
622
623
nsCOMPtr<nsIHttpChannel> httpChannel(do_QueryInterface(channel));
624
if (httpChannel) {
625
rv = httpChannel->SetReferrerInfo(aFontFaceSrc->mReferrerInfo);
626
Unused << NS_WARN_IF(NS_FAILED(rv));
627
628
rv = httpChannel->SetRequestHeader(
629
NS_LITERAL_CSTRING("Accept"),
630
NS_LITERAL_CSTRING("application/font-woff2;q=1.0,application/"
631
"font-woff;q=0.9,*/*;q=0.8"),
632
false);
633
NS_ENSURE_SUCCESS(rv, rv);
634
635
// For WOFF and WOFF2, we should tell servers/proxies/etc NOT to try
636
// and apply additional compression at the content-encoding layer
637
if (aFontFaceSrc->mFormatFlags & (gfxUserFontSet::FLAG_FORMAT_WOFF |
638
gfxUserFontSet::FLAG_FORMAT_WOFF2)) {
639
rv = httpChannel->SetRequestHeader(NS_LITERAL_CSTRING("Accept-Encoding"),
640
NS_LITERAL_CSTRING("identity"), false);
641
NS_ENSURE_SUCCESS(rv, rv);
642
}
643
}
644
nsCOMPtr<nsISupportsPriority> priorityChannel(do_QueryInterface(channel));
645
if (priorityChannel) {
646
priorityChannel->AdjustPriority(nsISupportsPriority::PRIORITY_HIGH);
647
}
648
649
nsCOMPtr<nsIClassOfService> cos(do_QueryInterface(channel));
650
if (cos) {
651
cos->AddClassFlags(nsIClassOfService::TailForbidden);
652
}
653
654
rv = NS_NewStreamLoader(getter_AddRefs(streamLoader), fontLoader, fontLoader);
655
NS_ENSURE_SUCCESS(rv, rv);
656
657
net::PredictorLearn(aFontFaceSrc->mURI->get(), mDocument->GetDocumentURI(),
658
nsINetworkPredictor::LEARN_LOAD_SUBRESOURCE, loadGroup);
659
660
rv = channel->AsyncOpen(streamLoader);
661
if (NS_FAILED(rv)) {
662
fontLoader->DropChannel(); // explicitly need to break ref cycle
663
}
664
665
if (NS_SUCCEEDED(rv)) {
666
fontLoader->StartedLoading(streamLoader);
667
// let the font entry remember the loader, in case we need to cancel it
668
aUserFontEntry->SetLoader(fontLoader);
669
}
670
671
return rv;
672
}
673
674
bool FontFaceSet::UpdateRules(const nsTArray<nsFontFaceRuleContainer>& aRules) {
675
MOZ_ASSERT(mUserFontSet);
676
677
// If there was a change to the mNonRuleFaces array, then there could
678
// have been a modification to the user font set.
679
bool modified = mNonRuleFacesDirty;
680
mNonRuleFacesDirty = false;
681
682
// reuse existing FontFace objects mapped to rules already
683
nsDataHashtable<nsPtrHashKey<RawServoFontFaceRule>, FontFace*> ruleFaceMap;
684
for (size_t i = 0, i_end = mRuleFaces.Length(); i < i_end; ++i) {
685
FontFace* f = mRuleFaces[i].mFontFace;
686
if (!f) {
687
continue;
688
}
689
ruleFaceMap.Put(f->GetRule(), f);
690
}
691
692
// The @font-face rules that make up the user font set have changed,
693
// so we need to update the set. However, we want to preserve existing
694
// font entries wherever possible, so that we don't discard and then
695
// re-download resources in the (common) case where at least some of the
696
// same rules are still present.
697
698
nsTArray<FontFaceRecord> oldRecords;
699
mRuleFaces.SwapElements(oldRecords);
700
701
// Remove faces from the font family records; we need to re-insert them
702
// because we might end up with faces in a different order even if they're
703
// the same font entries as before. (The order can affect font selection
704
// where multiple faces match the requested style, perhaps with overlapping
705
// unicode-range coverage.)
706
for (auto it = mUserFontSet->mFontFamilies.Iter(); !it.Done(); it.Next()) {
707
it.Data()->DetachFontEntries();
708
}
709
710
// Sometimes aRules has duplicate @font-face rules in it; we should make
711
// that not happen, but in the meantime, don't try to insert the same
712
// FontFace object more than once into mRuleFaces. We track which
713
// ones we've handled in this table.
714
nsTHashtable<nsPtrHashKey<RawServoFontFaceRule>> handledRules;
715
716
for (size_t i = 0, i_end = aRules.Length(); i < i_end; ++i) {
717
// Insert each FontFace objects for each rule into our list, migrating old
718
// font entries if possible rather than creating new ones; set modified to
719
// true if we detect that rule ordering has changed, or if a new entry is
720
// created.
721
RawServoFontFaceRule* rule = aRules[i].mRule;
722
if (!handledRules.EnsureInserted(rule)) {
723
// rule was already present in the hashtable
724
continue;
725
}
726
RefPtr<FontFace> f = ruleFaceMap.Get(rule);
727
if (!f.get()) {
728
f = FontFace::CreateForRule(GetParentObject(), this, rule);
729
}
730
InsertRuleFontFace(f, aRules[i].mOrigin, oldRecords, modified);
731
}
732
733
for (size_t i = 0, i_end = mNonRuleFaces.Length(); i < i_end; ++i) {
734
// Do the same for the non rule backed FontFace objects.
735
InsertNonRuleFontFace(mNonRuleFaces[i].mFontFace, modified);
736
}
737
738
// Remove any residual families that have no font entries (i.e., they were
739
// not defined at all by the updated set of @font-face rules).
740
for (auto it = mUserFontSet->mFontFamilies.Iter(); !it.Done(); it.Next()) {
741
if (it.Data()->GetFontList().IsEmpty()) {
742
it.Remove();
743
}
744
}
745
746
// If any FontFace objects for rules are left in the old list, note that the
747
// set has changed (even if the new set was built entirely by migrating old
748
// font entries).
749
if (oldRecords.Length() > 0) {
750
modified = true;
751
// Any in-progress loaders for obsolete rules should be cancelled,
752
// as the resource being downloaded will no longer be required.
753
// We need to explicitly remove any loaders here, otherwise the loaders
754
// will keep their "orphaned" font entries alive until they complete,
755
// even after the oldRules array is deleted.
756
//
757
// XXX Now that it is possible for the author to hold on to a rule backed
758
// FontFace object, we shouldn't cancel loading here; instead we should do
759
// it when the FontFace is GCed, if we can detect that.
760
size_t count = oldRecords.Length();
761
for (size_t i = 0; i < count; ++i) {
762
RefPtr<FontFace> f = oldRecords[i].mFontFace;
763
gfxUserFontEntry* userFontEntry = f->GetUserFontEntry();
764
if (userFontEntry) {
765
nsFontFaceLoader* loader = userFontEntry->GetLoader();
766
if (loader) {
767
loader->Cancel();
768
RemoveLoader(loader);
769
}
770
}
771
772
// Any left over FontFace objects should also cease being rule backed.
773
f->DisconnectFromRule();
774
}
775
}
776
777
if (modified) {
778
IncrementGeneration(true);
779
mHasLoadingFontFacesIsDirty = true;
780
CheckLoadingStarted();
781
CheckLoadingFinished();
782
}
783
784
// if local rules needed to be rebuilt, they have been rebuilt at this point
785
if (mUserFontSet->mRebuildLocalRules) {
786
mUserFontSet->mLocalRulesUsed = false;
787
mUserFontSet->mRebuildLocalRules = false;
788
}
789
790
if (LOG_ENABLED() && !mRuleFaces.IsEmpty()) {
791
LOG(("userfonts (%p) userfont rules update (%s) rule count: %d",
792
mUserFontSet.get(), (modified ? "modified" : "not modified"),
793
(int)(mRuleFaces.Length())));
794
}
795
796
return modified;
797
}
798
799
void FontFaceSet::IncrementGeneration(bool aIsRebuild) {
800
MOZ_ASSERT(mUserFontSet);
801
mUserFontSet->IncrementGeneration(aIsRebuild);
802
}
803
804
void FontFaceSet::InsertNonRuleFontFace(FontFace* aFontFace,
805
bool& aFontSetModified) {
806
nsAtom* fontFamily = aFontFace->GetFamilyName();
807
if (!fontFamily) {
808
// If there is no family name, this rule cannot contribute a
809
// usable font, so there is no point in processing it further.
810
return;
811
}
812
813
nsAtomCString family(fontFamily);
814
815
// Just create a new font entry if we haven't got one already.
816
if (!aFontFace->GetUserFontEntry()) {
817
// XXX Should we be checking mUserFontSet->mLocalRulesUsed like
818
// InsertRuleFontFace does?
819
RefPtr<gfxUserFontEntry> entry = FindOrCreateUserFontEntryFromFontFace(
820
family, aFontFace, StyleOrigin::Author);
821
if (!entry) {
822
return;
823
}
824
aFontFace->SetUserFontEntry(entry);
825
}
826
827
aFontSetModified = true;
828
mUserFontSet->AddUserFontEntry(family, aFontFace->GetUserFontEntry());
829
}
830
831
void FontFaceSet::InsertRuleFontFace(FontFace* aFontFace,
832
StyleOrigin aSheetType,
833
nsTArray<FontFaceRecord>& aOldRecords,
834
bool& aFontSetModified) {
835
nsAtom* fontFamily = aFontFace->GetFamilyName();
836
if (!fontFamily) {
837
// If there is no family name, this rule cannot contribute a
838
// usable font, so there is no point in processing it further.
839
return;
840
}
841
842
bool remove = false;
843
size_t removeIndex;
844
845
nsAtomCString family(fontFamily);
846
847
// This is a rule backed FontFace. First, we check in aOldRecords; if
848
// the FontFace for the rule exists there, just move it to the new record
849
// list, and put the entry into the appropriate family.
850
for (size_t i = 0; i < aOldRecords.Length(); ++i) {
851
FontFaceRecord& rec = aOldRecords[i];
852
853
if (rec.mFontFace == aFontFace && rec.mOrigin == Some(aSheetType)) {
854
// if local rules were used, don't use the old font entry
855
// for rules containing src local usage
856
if (mUserFontSet->mLocalRulesUsed && mUserFontSet->mRebuildLocalRules) {
857
if (aFontFace->HasLocalSrc()) {
858
// Remove the old record, but wait to see if we successfully create a
859
// new user font entry below.
860
remove = true;
861
removeIndex = i;
862
break;
863
}
864
}
865
866
gfxUserFontEntry* entry = rec.mFontFace->GetUserFontEntry();
867
MOZ_ASSERT(entry, "FontFace should have a gfxUserFontEntry by now");
868
869
mUserFontSet->AddUserFontEntry(family, entry);
870
871
MOZ_ASSERT(!HasRuleFontFace(rec.mFontFace),
872
"FontFace should not occur in mRuleFaces twice");
873
874
mRuleFaces.AppendElement(rec);
875
aOldRecords.RemoveElementAt(i);
876
// note the set has been modified if an old rule was skipped to find
877
// this one - something has been dropped, or ordering changed
878
if (i > 0) {
879
aFontSetModified = true;
880
}
881
return;
882
}
883
}
884
885
// this is a new rule:
886
RefPtr<gfxUserFontEntry> entry =
887
FindOrCreateUserFontEntryFromFontFace(family, aFontFace, aSheetType);
888
889
if (!entry) {
890
return;
891
}
892
893
if (remove) {
894
// Although we broke out of the aOldRecords loop above, since we found
895
// src local usage, and we're not using the old user font entry, we still
896
// are adding a record to mRuleFaces with the same FontFace object.
897
// Remove the old record so that we don't have the same FontFace listed
898
// in both mRuleFaces and oldRecords, which would cause us to call
899
// DisconnectFromRule on a FontFace that should still be rule backed.
900
aOldRecords.RemoveElementAt(removeIndex);
901
}
902
903
FontFaceRecord rec;
904
rec.mFontFace = aFontFace;
905
rec.mOrigin = Some(aSheetType);
906
rec.mLoadEventShouldFire =
907
aFontFace->Status() == FontFaceLoadStatus::Unloaded ||
908
aFontFace->Status() == FontFaceLoadStatus::Loading;
909
910
aFontFace->SetUserFontEntry(entry);
911
912
MOZ_ASSERT(!HasRuleFontFace(aFontFace),
913
"FontFace should not occur in mRuleFaces twice");
914
915
mRuleFaces.AppendElement(rec);
916
917
// this was a new rule and font entry, so note that the set was modified
918
aFontSetModified = true;
919
920
// Add the entry to the end of the list. If an existing userfont entry was
921
// returned by FindOrCreateUserFontEntryFromFontFace that was already stored
922
// on the family, gfxUserFontFamily::AddFontEntry(), which AddUserFontEntry
923
// calls, will automatically remove the earlier occurrence of the same
924
// userfont entry.
925
mUserFontSet->AddUserFontEntry(family, entry);
926
}
927
928
/* static */
929
already_AddRefed<gfxUserFontEntry>
930
FontFaceSet::FindOrCreateUserFontEntryFromFontFace(FontFace* aFontFace) {
931
nsAtom* fontFamily = aFontFace->GetFamilyName();
932
if (!fontFamily) {
933
// If there is no family name, this rule cannot contribute a
934
// usable font, so there is no point in processing it further.
935
return nullptr;
936
}
937
938
return FindOrCreateUserFontEntryFromFontFace(nsAtomCString(fontFamily),
939
aFontFace, StyleOrigin::Author);
940
}
941
942
static WeightRange GetWeightRangeForDescriptor(
943
const Maybe<StyleComputedFontWeightRange>& aVal,
944
gfxFontEntry::RangeFlags& aRangeFlags) {
945
if (!aVal) {
946
aRangeFlags |= gfxFontEntry::RangeFlags::eAutoWeight;
947
return WeightRange(FontWeight::Normal());
948
}
949
return WeightRange(FontWeight(aVal->_0), FontWeight(aVal->_1));
950
}
951
952
static SlantStyleRange GetStyleRangeForDescriptor(
953
const Maybe<StyleComputedFontStyleDescriptor>& aVal,
954
gfxFontEntry::RangeFlags& aRangeFlags) {
955
if (!aVal) {
956
aRangeFlags |= gfxFontEntry::RangeFlags::eAutoSlantStyle;
957
return SlantStyleRange(FontSlantStyle::Normal());
958
}
959
auto& val = *aVal;
960
switch (val.tag) {
961
case StyleComputedFontStyleDescriptor::Tag::Normal:
962
return SlantStyleRange(FontSlantStyle::Normal());
963
case StyleComputedFontStyleDescriptor::Tag::Italic:
964
return SlantStyleRange(FontSlantStyle::Italic());
965
case StyleComputedFontStyleDescriptor::Tag::Oblique:
966
return SlantStyleRange(FontSlantStyle::Oblique(val.AsOblique()._0),
967
FontSlantStyle::Oblique(val.AsOblique()._1));
968
}
969
MOZ_ASSERT_UNREACHABLE("How?");
970
return SlantStyleRange(FontSlantStyle::Normal());
971
}
972
973
static StretchRange GetStretchRangeForDescriptor(
974
const Maybe<StyleComputedFontStretchRange>& aVal,
975
gfxFontEntry::RangeFlags& aRangeFlags) {
976
if (!aVal) {
977
aRangeFlags |= gfxFontEntry::RangeFlags::eAutoStretch;
978
return StretchRange(FontStretch::Normal());
979
}
980
return StretchRange(FontStretch::FromStyle(aVal->_0),
981
FontStretch::FromStyle(aVal->_1));
982
}
983
984
// TODO(emilio): Should this take an nsAtom* aFamilyName instead?
985
//
986
// All callers have one handy.
987
/* static */
988
already_AddRefed<gfxUserFontEntry>
989
FontFaceSet::FindOrCreateUserFontEntryFromFontFace(
990
const nsACString& aFamilyName, FontFace* aFontFace, StyleOrigin aOrigin) {
991
FontFaceSet* set = aFontFace->GetPrimaryFontFaceSet();
992
993
uint32_t languageOverride = NO_FONT_LANGUAGE_OVERRIDE;
994
StyleFontDisplay fontDisplay = StyleFontDisplay::Auto;
995
996
gfxFontEntry::RangeFlags rangeFlags = gfxFontEntry::RangeFlags::eNoFlags;
997
998
// set up weight
999
WeightRange weight =
1000
GetWeightRangeForDescriptor(aFontFace->GetFontWeight(), rangeFlags);
1001
1002
// set up stretch
1003
StretchRange stretch =
1004
GetStretchRangeForDescriptor(aFontFace->GetFontStretch(), rangeFlags);
1005
1006
// set up font style
1007
SlantStyleRange italicStyle =
1008
GetStyleRangeForDescriptor(aFontFace->GetFontStyle(), rangeFlags);
1009
1010
// set up font display
1011
if (Maybe<StyleFontDisplay> display = aFontFace->GetFontDisplay()) {
1012
fontDisplay = *display;
1013
}
1014
1015
// set up font features
1016
nsTArray<gfxFontFeature> featureSettings;
1017
aFontFace->GetFontFeatureSettings(featureSettings);
1018
1019
// set up font variations
1020
nsTArray<gfxFontVariation> variationSettings;
1021
aFontFace->GetFontVariationSettings(variationSettings);
1022
1023
// set up font language override
1024
if (Maybe<StyleFontLanguageOverride> descriptor =
1025
aFontFace->GetFontLanguageOverride()) {
1026
languageOverride = descriptor->_0;
1027
}
1028
1029
// set up unicode-range
1030
gfxCharacterMap* unicodeRanges = aFontFace->GetUnicodeRangeAsCharacterMap();
1031
1032
RefPtr<gfxUserFontEntry> existingEntry = aFontFace->GetUserFontEntry();
1033
if (existingEntry) {
1034
// aFontFace already has a user font entry, so we update its attributes
1035
// rather than creating a new one.
1036
existingEntry->UpdateAttributes(
1037
weight, stretch, italicStyle, featureSettings, variationSettings,
1038
languageOverride, unicodeRanges, fontDisplay, rangeFlags);
1039
// If the family name has changed, remove the entry from its current family
1040
// and clear the mFamilyName field so it can be reset when added to a new
1041
// family.
1042
if (!existingEntry->mFamilyName.IsEmpty() &&
1043
existingEntry->mFamilyName != aFamilyName) {
1044
gfxUserFontFamily* family =
1045
set->GetUserFontSet()->LookupFamily(existingEntry->mFamilyName);
1046
if (family) {
1047
family->RemoveFontEntry(existingEntry);
1048
}
1049
existingEntry->mFamilyName.Truncate(0);
1050
}
1051
return existingEntry.forget();
1052
}
1053
1054
// set up src array
1055
nsTArray<gfxFontFaceSrc> srcArray;
1056
1057
if (aFontFace->HasFontData()) {
1058
gfxFontFaceSrc* face = srcArray.AppendElement();
1059
if (!face) {
1060
return nullptr;
1061
}
1062
1063
face->mSourceType = gfxFontFaceSrc::eSourceType_Buffer;
1064
face->mBuffer = aFontFace->CreateBufferSource();
1065
} else {
1066
AutoTArray<StyleFontFaceSourceListComponent, 8> sourceListComponents;
1067
aFontFace->GetSources(sourceListComponents);
1068
size_t len = sourceListComponents.Length();
1069
for (size_t i = 0; i < len; ++i) {
1070
gfxFontFaceSrc* face = srcArray.AppendElement();
1071
const auto& component = sourceListComponents[i];
1072
switch (component.tag) {
1073
case StyleFontFaceSourceListComponent::Tag::Local: {
1074
nsAtom* atom = component.AsLocal();
1075
face->mLocalName.Append(nsAtomCString(atom));
1076
face->mSourceType = gfxFontFaceSrc::eSourceType_Local;
1077
face->mURI = nullptr;
1078
face->mFormatFlags = 0;
1079
break;
1080
}
1081
case StyleFontFaceSourceListComponent::Tag::Url: {
1082
face->mSourceType = gfxFontFaceSrc::eSourceType_URL;
1083
const StyleCssUrl* url = component.AsUrl();
1084
nsIURI* uri = url->GetURI();
1085
face->mURI = uri ? new gfxFontSrcURI(uri) : nullptr;
1086
const URLExtraData& extraData = url->ExtraData();
1087
face->mReferrerInfo = extraData.ReferrerInfo();
1088
face->mOriginPrincipal =
1089
new gfxFontSrcPrincipal(extraData.Principal());
1090
1091
// agent and user stylesheets are treated slightly differently,
1092
// the same-site origin check and access control headers are
1093
// enforced against the sheet principal rather than the document
1094
// principal to allow user stylesheets to include @font-face rules
1095
face->mUseOriginPrincipal =
1096
aOrigin == StyleOrigin::User || aOrigin == StyleOrigin::UserAgent;
1097
1098
face->mLocalName.Truncate();
1099
face->mFormatFlags = 0;
1100
1101
while (i + 1 < len) {
1102
const auto& maybeFontFormat = sourceListComponents[i + 1];
1103
if (maybeFontFormat.tag !=
1104
StyleFontFaceSourceListComponent::Tag::FormatHint) {
1105
break;
1106
}
1107
1108
nsDependentCSubstring valueString(
1109
reinterpret_cast<const char*>(
1110
maybeFontFormat.format_hint.utf8_bytes),
1111
maybeFontFormat.format_hint.length);
1112
1113
if (valueString.LowerCaseEqualsASCII("woff")) {
1114
face->mFormatFlags |= gfxUserFontSet::FLAG_FORMAT_WOFF;
1115
} else if (valueString.LowerCaseEqualsASCII("woff2")) {
1116
face->mFormatFlags |= gfxUserFontSet::FLAG_FORMAT_WOFF2;
1117
} else if (valueString.LowerCaseEqualsASCII("opentype")) {
1118
face->mFormatFlags |= gfxUserFontSet::FLAG_FORMAT_OPENTYPE;
1119
} else if (valueString.LowerCaseEqualsASCII("truetype")) {
1120
face->mFormatFlags |= gfxUserFontSet::FLAG_FORMAT_TRUETYPE;
1121
} else if (valueString.LowerCaseEqualsASCII("truetype-aat")) {
1122
face->mFormatFlags |= gfxUserFontSet::FLAG_FORMAT_TRUETYPE_AAT;
1123
} else if (valueString.LowerCaseEqualsASCII("embedded-opentype")) {
1124
face->mFormatFlags |= gfxUserFontSet::FLAG_FORMAT_EOT;
1125
} else if (valueString.LowerCaseEqualsASCII("svg")) {
1126
face->mFormatFlags |= gfxUserFontSet::FLAG_FORMAT_SVG;
1127
} else if (StaticPrefs::layout_css_font_variations_enabled() &&
1128
valueString.LowerCaseEqualsASCII("woff-variations")) {
1129
face->mFormatFlags |= gfxUserFontSet::FLAG_FORMAT_WOFF_VARIATIONS;
1130
} else if (StaticPrefs::layout_css_font_variations_enabled() &&
1131
valueString.LowerCaseEqualsASCII("woff2-variations")) {
1132
face->mFormatFlags |=
1133
gfxUserFontSet::FLAG_FORMAT_WOFF2_VARIATIONS;
1134
} else if (StaticPrefs::layout_css_font_variations_enabled() &&
1135
valueString.LowerCaseEqualsASCII(
1136
"opentype-variations")) {
1137
face->mFormatFlags |=
1138
gfxUserFontSet::FLAG_FORMAT_OPENTYPE_VARIATIONS;
1139
} else if (StaticPrefs::layout_css_font_variations_enabled() &&
1140
valueString.LowerCaseEqualsASCII(
1141
"truetype-variations")) {
1142
face->mFormatFlags |=
1143
gfxUserFontSet::FLAG_FORMAT_TRUETYPE_VARIATIONS;
1144
} else {
1145
// unknown format specified, mark to distinguish from the
1146
// case where no format hints are specified
1147
face->mFormatFlags |= gfxUserFontSet::FLAG_FORMAT_UNKNOWN;
1148
}
1149
i++;
1150
}
1151
if (!face->mURI) {
1152
// if URI not valid, omit from src array
1153
srcArray.RemoveLastElement();
1154
NS_WARNING("null url in @font-face rule");
1155
continue;
1156
}
1157
break;
1158
}
1159
case StyleFontFaceSourceListComponent::Tag::FormatHint:
1160
MOZ_ASSERT_UNREACHABLE(
1161
"Should always come after a URL source, and be consumed already");
1162
break;
1163
}
1164
}
1165
}
1166
1167
if (srcArray.IsEmpty()) {
1168
return nullptr;
1169
}
1170
1171
RefPtr<gfxUserFontEntry> entry = set->mUserFontSet->FindOrCreateUserFontEntry(
1172
aFamilyName, srcArray, weight, stretch, italicStyle, featureSettings,
1173
variationSettings, languageOverride, unicodeRanges, fontDisplay,
1174
rangeFlags);
1175
1176
return entry.forget();
1177
}
1178
1179
RawServoFontFaceRule* FontFaceSet::FindRuleForEntry(gfxFontEntry* aFontEntry) {
1180
NS_ASSERTION(!aFontEntry->mIsUserFontContainer, "only platform font entries");
1181
for (uint32_t i = 0; i < mRuleFaces.Length(); ++i) {
1182
FontFace* f = mRuleFaces[i].mFontFace;
1183
gfxUserFontEntry* entry = f->GetUserFontEntry();
1184
if (entry && entry->GetPlatformFontEntry() == aFontEntry) {
1185
return f->GetRule();
1186
}
1187
}
1188
return nullptr;
1189
}
1190
1191
RawServoFontFaceRule* FontFaceSet::FindRuleForUserFontEntry(
1192
gfxUserFontEntry* aUserFontEntry) {
1193
for (uint32_t i = 0; i < mRuleFaces.Length(); ++i) {
1194
FontFace* f = mRuleFaces[i].mFontFace;
1195
if (f->GetUserFontEntry() == aUserFontEntry) {
1196
return f->GetRule();
1197
}
1198
}
1199
return nullptr;
1200
}
1201
1202
nsresult FontFaceSet::LogMessage(gfxUserFontEntry* aUserFontEntry,
1203
const char* aMessage, uint32_t aFlags,
1204
nsresult aStatus) {
1205
MOZ_ASSERT(NS_IsMainThread() ||
1206
ServoStyleSet::IsCurrentThreadInServoTraversal());
1207
1208
nsCOMPtr<nsIConsoleService> console(
1209
do_GetService(NS_CONSOLESERVICE_CONTRACTID));
1210
if (!console) {
1211
return NS_ERROR_NOT_AVAILABLE;
1212
}
1213
1214
nsAutoCString familyName;
1215
nsAutoCString fontURI;
1216
aUserFontEntry->GetFamilyNameAndURIForLogging(familyName, fontURI);
1217
1218
nsAutoCString weightString;
1219
aUserFontEntry->Weight().ToString(weightString);
1220
nsAutoCString stretchString;
1221
aUserFontEntry->Stretch().ToString(stretchString);
1222
nsPrintfCString message(
1223
"downloadable font: %s "
1224
"(font-family: \"%s\" style:%s weight:%s stretch:%s src index:%d)",
1225
aMessage, familyName.get(),
1226
aUserFontEntry->IsItalic() ? "italic" : "normal", // XXX todo: oblique?
1227
weightString.get(), stretchString.get(), aUserFontEntry->GetSrcIndex());
1228
1229
if (NS_FAILED(aStatus)) {
1230
message.AppendLiteral(": ");
1231
switch (aStatus) {
1232
case NS_ERROR_DOM_BAD_URI:
1233
message.AppendLiteral("bad URI or cross-site access not allowed");
1234
break;
1235
case NS_ERROR_CONTENT_BLOCKED:
1236
message.AppendLiteral("content blocked");
1237
break;
1238
default:
1239
message.AppendLiteral("status=");
1240
message.AppendInt(static_cast<uint32_t>(aStatus));
1241
break;
1242
}
1243
}
1244
message.AppendLiteral(" source: ");
1245
message.Append(fontURI);
1246
1247
LOG(("userfonts (%p) %s", mUserFontSet.get(), message.get()));
1248
1249
// try to give the user an indication of where the rule came from
1250
RawServoFontFaceRule* rule = FindRuleForUserFontEntry(aUserFontEntry);
1251
nsString href;
1252
nsString text;
1253
uint32_t line = 0;
1254
uint32_t column = 0;
1255
if (rule) {
1256
Servo_FontFaceRule_GetCssText(rule, &text);
1257
Servo_FontFaceRule_GetSourceLocation(rule, &line, &column);
1258
// FIXME We need to figure out an approach to get the style sheet
1259
// of this raw rule. See bug 1450903.
1260
#if 0
1261
StyleSheet* sheet = rule->GetStyleSheet();
1262
// if the style sheet is removed while the font is loading can be null
1263
if (sheet) {
1264
nsCString spec = sheet->GetSheetURI()->GetSpecOrDefault();
1265
CopyUTF8toUTF16(spec, href);
1266
} else {
1267
NS_WARNING("null parent stylesheet for @font-face rule");
1268
href.AssignLiteral("unknown");
1269
}
1270
#endif
1271
// Leave href empty if we don't know how to get the correct sheet.
1272
}
1273
1274
nsresult rv;
1275
nsCOMPtr<nsIScriptError> scriptError =
1276
do_CreateInstance(NS_SCRIPTERROR_CONTRACTID, &rv);
1277
NS_ENSURE_SUCCESS(rv, rv);
1278
1279
uint64_t innerWindowID = mDocument->InnerWindowID();
1280
rv = scriptError->InitWithWindowID(NS_ConvertUTF8toUTF16(message),
1281
href, // file
1282
text, // src line
1283
line, column,
1284
aFlags, // flags
1285
"CSS Loader", // category (make separate?)
1286
innerWindowID);
1287
if (NS_SUCCEEDED(rv)) {
1288
console->LogMessage(scriptError);
1289
}
1290
1291
return NS_OK;
1292
}
1293
1294
void FontFaceSet::CacheFontLoadability() {
1295
if (!mUserFontSet) {
1296
return;
1297
}
1298
1299
// TODO(emilio): We could do it a bit more incrementally maybe?
1300
for (auto iter = mUserFontSet->mFontFamilies.Iter(); !iter.Done();
1301
iter.Next()) {
1302
for (const gfxFontEntry* entry : iter.Data()->GetFontList()) {
1303
if (!entry->mIsUserFontContainer) {
1304
continue;
1305
}
1306
1307
const auto& sourceList =
1308
static_cast<const gfxUserFontEntry*>(entry)->SourceList();
1309
for (const gfxFontFaceSrc& src : sourceList) {
1310
if (src.mSourceType != gfxFontFaceSrc::eSourceType_URL) {
1311
continue;
1312
}
1313
mAllowedFontLoads.LookupForAdd(&src).OrInsert(
1314
[&] { return IsFontLoadAllowed(src); });
1315
}
1316
}
1317
}
1318
}
1319
1320
bool FontFaceSet::IsFontLoadAllowed(const gfxFontFaceSrc& aSrc) {
1321
MOZ_ASSERT(aSrc.mSourceType == gfxFontFaceSrc::eSourceType_URL);
1322
1323
if (ServoStyleSet::IsInServoTraversal()) {
1324
bool* entry = mAllowedFontLoads.GetValue(&aSrc);
1325
MOZ_DIAGNOSTIC_ASSERT(entry, "Missed an update?");
1326
return entry ? *entry : false;
1327
}
1328
1329
MOZ_ASSERT(NS_IsMainThread());
1330
1331
if (!mUserFontSet) {
1332
return false;
1333
}
1334
1335
gfxFontSrcPrincipal* gfxPrincipal = aSrc.mURI->InheritsSecurityContext()
1336
? nullptr
1337
: aSrc.LoadPrincipal(*mUserFontSet);
1338
1339
nsIPrincipal* principal = gfxPrincipal ? gfxPrincipal->get() : nullptr;
1340
1341
nsCOMPtr<nsILoadInfo> secCheckLoadInfo = new net::LoadInfo(
1342
mDocument->NodePrincipal(), // loading principal
1343
principal, // triggering principal
1344
mDocument, nsILoadInfo::SEC_ONLY_FOR_EXPLICIT_CONTENTSEC_CHECK,
1345
nsIContentPolicy::TYPE_FONT);
1346
1347
int16_t shouldLoad = nsIContentPolicy::ACCEPT;
1348
nsresult rv = NS_CheckContentLoadPolicy(aSrc.mURI->get(), secCheckLoadInfo,
1349
EmptyCString(), // mime type
1350
&shouldLoad,
1351
nsContentUtils::GetContentPolicy());
1352
1353
return NS_SUCCEEDED(rv) && NS_CP_ACCEPTED(shouldLoad);
1354
}
1355
1356
void FontFaceSet::DispatchFontLoadViolations(
1357
nsTArray<nsCOMPtr<nsIRunnable>>& aViolations) {
1358
if (XRE_IsContentProcess()) {
1359
nsCOMPtr<nsIEventTarget> eventTarget =
1360
mDocument->EventTargetFor(TaskCategory::Other);
1361
for (nsIRunnable* runnable : aViolations) {
1362
eventTarget->Dispatch(do_AddRef(runnable), NS_DISPATCH_NORMAL);
1363
}
1364
} else {
1365
for (nsIRunnable* runnable : aViolations) {
1366
NS_DispatchToMainThread(do_AddRef(runnable));
1367
}
1368
}
1369
}
1370
1371
nsresult FontFaceSet::SyncLoadFontData(gfxUserFontEntry* aFontToLoad,
1372
const gfxFontFaceSrc* aFontFaceSrc,
1373
uint8_t*& aBuffer,
1374
uint32_t& aBufferLength) {
1375
nsresult rv;
1376
1377
gfxFontSrcPrincipal* principal = aFontToLoad->GetPrincipal();
1378
1379
nsCOMPtr<nsIChannel> channel;
1380
// Note we are calling NS_NewChannelWithTriggeringPrincipal() with both a
1381
// node and a principal. This is because the document where the font is
1382
// being loaded might have a different origin from the principal of the
1383
// stylesheet that initiated the font load.
1384
// Further, we only get here for data: loads, so it doesn't really matter
1385
// whether we use SEC_ALLOW_CROSS_ORIGIN_DATA_INHERITS or not, to be more
1386
// restrictive we use SEC_REQUIRE_SAME_ORIGIN_DATA_INHERITS.
1387
rv = NS_NewChannelWithTriggeringPrincipal(
1388
getter_AddRefs(channel), aFontFaceSrc->mURI->get(), mDocument,
1389
principal ? principal->get() : nullptr,
1390
nsILoadInfo::SEC_REQUIRE_SAME_ORIGIN_DATA_INHERITS,
1391
nsIContentPolicy::TYPE_FONT);
1392
1393
NS_ENSURE_SUCCESS(rv, rv);
1394
1395
// blocking stream is OK for data URIs
1396
nsCOMPtr<nsIInputStream> stream;
1397
rv = channel->Open(getter_AddRefs(stream));
1398
NS_ENSURE_SUCCESS(rv, rv);
1399
1400
uint64_t bufferLength64;
1401
rv = stream->Available(&bufferLength64);
1402
NS_ENSURE_SUCCESS(rv, rv);
1403
if (bufferLength64 == 0) {
1404
return NS_ERROR_FAILURE;
1405
}
1406
if (bufferLength64 > UINT32_MAX) {
1407
return NS_ERROR_FILE_TOO_BIG;
1408
}
1409
aBufferLength = static_cast<uint32_t>(bufferLength64);
1410
1411
// read all the decoded data
1412
aBuffer = static_cast<uint8_t*>(malloc(sizeof(uint8_t) * aBufferLength));
1413
if (!aBuffer) {
1414
aBufferLength = 0;
1415
return NS_ERROR_OUT_OF_MEMORY;
1416
}
1417
1418
uint32_t numRead, totalRead = 0;
1419
while (NS_SUCCEEDED(
1420
rv = stream->Read(reinterpret_cast<char*>(aBuffer + totalRead),
1421
aBufferLength - totalRead, &numRead)) &&
1422
numRead != 0) {
1423
totalRead += numRead;
1424
if (totalRead > aBufferLength) {
1425
rv = NS_ERROR_FAILURE;
1426
break;
1427
}
1428
}
1429
1430
// make sure there's a mime type
1431
if (NS_SUCCEEDED(rv)) {
1432
nsAutoCString mimeType;
1433
rv = channel->GetContentType(mimeType);
1434
aBufferLength = totalRead;
1435
}
1436
1437
if (NS_FAILED(rv)) {
1438
free(aBuffer);
1439
aBuffer = nullptr;
1440
aBufferLength = 0;
1441
return rv;
1442
}
1443
1444
return NS_OK;
1445
}
1446
1447
void FontFaceSet::OnFontFaceStatusChanged(FontFace* aFontFace) {
1448
AssertIsMainThreadOrServoFontMetricsLocked();
1449
1450
MOZ_ASSERT(HasAvailableFontFace(aFontFace));
1451
1452
mHasLoadingFontFacesIsDirty = true;
1453
1454
if (aFontFace->Status() == FontFaceLoadStatus::Loading) {
1455
CheckLoadingStarted();
1456
} else {
1457
MOZ_ASSERT(aFontFace->Status() == FontFaceLoadStatus::Loaded ||
1458
aFontFace->Status() == FontFaceLoadStatus::Error);
1459
// When a font finishes downloading, nsPresContext::UserFontSetUpdated
1460
// will be called immediately afterwards to request a reflow of the
1461
// relevant elements in the document. We want to wait until the reflow
1462
// request has been done before the FontFaceSet is marked as Loaded so
1463
// that we don't briefly set the FontFaceSet to Loaded and then Loading
1464
// again once the reflow is pending. So we go around the event loop
1465
// and call CheckLoadingFinished() after the reflow has been queued.
1466
if (!mDelayedLoadCheck) {
1467
mDelayedLoadCheck = true;
1468
DispatchCheckLoadingFinishedAfterDelay();
1469
}
1470
}
1471
}
1472
1473
void FontFaceSet::DispatchCheckLoadingFinishedAfterDelay() {
1474
AssertIsMainThreadOrServoFontMetricsLocked();
1475
1476
if (ServoStyleSet* set = ServoStyleSet::Current()) {
1477
// See comments in Gecko_GetFontMetrics.
1478
//
1479
// We can't just dispatch the runnable below if we're not on the main
1480
// thread, since it needs to take a strong reference to the FontFaceSet,
1481
// and being a DOM object, FontFaceSet doesn't support thread-safe
1482
// refcounting.
1483
set->AppendTask(
1484
PostTraversalTask::DispatchFontFaceSetCheckLoadingFinishedAfterDelay(
1485
this));
1486
return;
1487
}
1488
1489
nsCOMPtr<nsIRunnable> checkTask =
1490
NewRunnableMethod("dom::FontFaceSet::CheckLoadingFinishedAfterDelay",
1491
this, &FontFaceSet::CheckLoadingFinishedAfterDelay);
1492
mDocument->Dispatch(TaskCategory::Other, checkTask.forget());
1493
}
1494
1495
void FontFaceSet::DidRefresh() { CheckLoadingFinished(); }
1496
1497
void FontFaceSet::CheckLoadingFinishedAfterDelay() {
1498
mDelayedLoadCheck = false;
1499
CheckLoadingFinished();
1500
}
1501
1502
void FontFaceSet::CheckLoadingStarted() {
1503
AssertIsMainThreadOrServoFontMetricsLocked();
1504
1505
if (!HasLoadingFontFaces()) {
1506
return;
1507
}
1508
1509
if (mStatus == FontFaceSetLoadStatus::Loading) {
1510
// We have already dispatched a loading event and replaced mReady
1511
// with a fresh, unresolved promise.
1512
return;
1513
}
1514
1515
mStatus = FontFaceSetLoadStatus::Loading;
1516
DispatchLoadingEventAndReplaceReadyPromise();
1517
}
1518
1519
void FontFaceSet::DispatchLoadingEventAndReplaceReadyPromise() {
1520
AssertIsMainThreadOrServoFontMetricsLocked();
1521
1522
if (ServoStyleSet* set = ServoStyleSet::Current()) {
1523
// See comments in Gecko_GetFontMetrics.
1524
//
1525
// We can't just dispatch the runnable below if we're not on the main
1526
// thread, since it needs to take a strong reference to the FontFaceSet,
1527
// and being a DOM object, FontFaceSet doesn't support thread-safe
1528
// refcounting. (Also, the Promise object creation must be done on
1529
// the main thread.)
1530
set->AppendTask(
1531
PostTraversalTask::DispatchLoadingEventAndReplaceReadyPromise(this));
1532
return;
1533
}
1534
1535
(new AsyncEventDispatcher(this, NS_LITERAL_STRING("loading"), CanBubble::eNo))
1536
->PostDOMEvent();
1537
1538
if (PrefEnabled()) {
1539
if (mReady && mReady->State() != Promise::PromiseState::Pending) {
1540
if (GetParentObject()) {
1541
ErrorResult rv;
1542
mReady = Promise::Create(GetParentObject(), rv);
1543
}
1544
}
1545
1546
// We may previously have been in a state where all fonts had finished
1547
// loading and we'd set mResolveLazilyCreatedReadyPromise to make sure that
1548
// if we lazily create mReady for a consumer that we resolve it before
1549
// returning it. We're now loading fonts, so we need to clear that flag.
1550
mResolveLazilyCreatedReadyPromise = false;
1551
}
1552
}
1553
1554
void FontFaceSet::UpdateHasLoadingFontFaces() {
1555
mHasLoadingFontFacesIsDirty = false;
1556
mHasLoadingFontFaces = false;
1557
for (size_t i = 0; i < mRuleFaces.Length(); i++) {
1558
FontFace* f = mRuleFaces[i].mFontFace;
1559
if (f->Status() == FontFaceLoadStatus::Loading) {
1560
mHasLoadingFontFaces = true;
1561
return;
1562
}
1563
}
1564
for (size_t i = 0; i < mNonRuleFaces.Length(); i++) {
1565
if (mNonRuleFaces[i].mFontFace->Status() == FontFaceLoadStatus::Loading) {
1566
mHasLoadingFontFaces = true;
1567
return;
1568
}
1569
}
1570
}
1571
1572
bool FontFaceSet::HasLoadingFontFaces() {
1573
if (mHasLoadingFontFacesIsDirty) {
1574
UpdateHasLoadingFontFaces();
1575
}
1576
return mHasLoadingFontFaces;
1577
}
1578
1579
bool FontFaceSet::MightHavePendingFontLoads() {
1580
// Check for FontFace objects in the FontFaceSet that are still loading.
1581
if (HasLoadingFontFaces()) {
1582
return true;
1583
}
1584
1585
// Check for pending restyles or reflows, as they might cause fonts to
1586
// load as new styles apply and text runs are rebuilt.
1587
nsPresContext* presContext = GetPresContext();
1588
if (presContext && presContext->HasPendingRestyleOrReflow()) {
1589
return true;
1590
}
1591
1592
if (mDocument) {
1593
// We defer resolving mReady until the document as fully loaded.
1594
if (!mDocument->DidFireDOMContentLoaded()) {
1595
return true;
1596
}
1597
1598
// And we also wait for any CSS style sheets to finish loading, as their
1599
// styles might cause new fonts to load.
1600
if (mDocument->CSSLoader()->HasPendingLoads()) {
1601
return true;
1602
}
1603
}
1604
1605
return false;
1606
}
1607
1608
void FontFaceSet::CheckLoadingFinished() {
1609
MOZ_ASSERT(NS_IsMainThread());
1610
1611
if (mDelayedLoadCheck) {
1612
// Wait until the runnable posted in OnFontFaceStatusChanged calls us.
1613
return;
1614
}
1615
1616
if (!ReadyPromiseIsPending()) {
1617
// We've already resolved mReady (or set the flag to do that lazily) and
1618
// dispatched the loadingdone/loadingerror events.
1619
return;
1620
}
1621
1622
if (MightHavePendingFontLoads()) {
1623
// We're not finished loading yet.
1624
return;
1625
}
1626
1627
mStatus = FontFaceSetLoadStatus::Loaded;
1628
if (mReady) {
1629
mReady->MaybeResolve(this);
1630
} else {
1631
mResolveLazilyCreatedReadyPromise = true;
1632
}
1633
1634
// Now dispatch the loadingdone/loadingerror events.
1635
nsTArray<OwningNonNull<FontFace>> loaded;
1636
nsTArray<OwningNonNull<FontFace>> failed;
1637
1638
for (size_t i = 0; i < mRuleFaces.Length(); i++) {
1639
if (!mRuleFaces[i].mLoadEventShouldFire) {
1640
continue;
1641
}
1642
FontFace* f = mRuleFaces[i].mFontFace;
1643
if (f->Status() == FontFaceLoadStatus::Loaded) {
1644
loaded.AppendElement(*f);
1645
mRuleFaces[i].mLoadEventShouldFire = false;
1646
} else if (f->Status() == FontFaceLoadStatus::Error) {
1647
failed.AppendElement(*f);
1648
mRuleFaces[i].mLoadEventShouldFire = false;
1649
}
1650
}
1651
1652
for (size_t i = 0; i < mNonRuleFaces.Length(); i++) {
1653
if (!mNonRuleFaces[i].mLoadEventShouldFire) {
1654
continue;
1655
}
1656
FontFace* f = mNonRuleFaces[i].mFontFace;
1657
if (f->Status() == FontFaceLoadStatus::Loaded) {
1658
loaded.AppendElement(*f);
1659
mNonRuleFaces[i].mLoadEventShouldFire = false;
1660
} else if (f->Status() == FontFaceLoadStatus::Error) {
1661
failed.AppendElement(*f);
1662
mNonRuleFaces[i].mLoadEventShouldFire = false;
1663
}
1664
}
1665
1666
DispatchLoadingFinishedEvent(NS_LITERAL_STRING("loadingdone"),
1667
std::move(loaded));
1668
1669
if (!failed.IsEmpty()) {
1670
DispatchLoadingFinishedEvent(NS_LITERAL_STRING("loadingerror"),
1671
std::move(failed));
1672
}
1673
}
1674
1675
void FontFaceSet::DispatchLoadingFinishedEvent(
1676
const nsAString& aType, nsTArray<OwningNonNull<FontFace>>&& aFontFaces) {
1677
FontFaceSetLoadEventInit init;
1678
init.mBubbles = false;
1679
init.mCancelable = false;
1680
init.mFontfaces.SwapElements(aFontFaces);
1681
RefPtr<FontFaceSetLoadEvent> event =
1682
FontFaceSetLoadEvent::Constructor(this, aType, init);
1683
(new AsyncEventDispatcher(this, event))->PostDOMEvent();
1684
}
1685
1686
// nsIDOMEventListener
1687
1688
NS_IMETHODIMP
1689
FontFaceSet::HandleEvent(Event* aEvent) {
1690
nsString type;
1691
aEvent->GetType(type);
1692
1693
if (!type.EqualsLiteral("DOMContentLoaded")) {
1694
return NS_ERROR_FAILURE;
1695
}
1696
1697
RemoveDOMContentLoadedListener();
1698
CheckLoadingFinished();
1699
1700
return NS_OK;
1701
}
1702
1703
/* static */
1704
bool FontFaceSet::PrefEnabled() {
1705
return StaticPrefs::layout_css_font_loading_api_enabled();
1706
}
1707
1708
// nsICSSLoaderObserver
1709
1710
NS_IMETHODIMP
1711
FontFaceSet::StyleSheetLoaded(StyleSheet* aSheet, bool aWasDeferred,
1712
nsresult aStatus) {
1713
CheckLoadingFinished();
1714
return NS_OK;
1715
}
1716
1717
void FontFaceSet::FlushUserFontSet() {
1718
if (mDocument) {
1719
mDocument->FlushUserFontSet();
1720
}
1721
}
1722
1723
void FontFaceSet::MarkUserFontSetDirty() {
1724
if (mDocument) {
1725
// Ensure we trigger at least a style flush, that will eventually flush the
1726
// user font set. Otherwise the font loads that that flush may cause could
1727
// never be triggered.
1728
if (PresShell* presShell = mDocument->GetPresShell()) {
1729
presShell->EnsureStyleFlush();
1730
}
1731
mDocument->MarkUserFontSetDirty();
1732
}
1733
}
1734
1735
nsPresContext* FontFaceSet::GetPresContext() {
1736
if (!mDocument) {
1737
return nullptr;
1738
}
1739
1740
return mDocument->GetPresContext();
1741
}
1742
1743
void FontFaceSet::RefreshStandardFontLoadPrincipal() {
1744
MOZ_ASSERT(NS_IsMainThread());
1745
mStandardFontLoadPrincipal =
1746
new gfxFontSrcPrincipal(mDocument->NodePrincipal());
1747
mAllowedFontLoads.Clear();
1748
if (mUserFontSet) {
1749
mUserFontSet->IncrementGeneration(false);
1750
}
1751
}
1752
1753
void FontFaceSet::CopyNonRuleFacesTo(FontFaceSet* aFontFaceSet) const {
1754
for (const FontFaceRecord& rec : mNonRuleFaces) {
1755
ErrorResult rv;
1756
RefPtr<FontFace> f = rec.mFontFace;
1757
aFontFaceSet->Add(*f, rv);
1758
MOZ_ASSERT(!rv.Failed());
1759
}
1760
}
1761
1762
// -- FontFaceSet::UserFontSet ------------------------------------------------
1763
1764
/* virtual */
1765
bool FontFaceSet::UserFontSet::IsFontLoadAllowed(const gfxFontFaceSrc& aSrc) {
1766
return mFontFaceSet && mFontFaceSet->IsFontLoadAllowed(aSrc);
1767
}
1768
1769
/* virtual */
1770
void FontFaceSet::UserFontSet::DispatchFontLoadViolations(
1771
nsTArray<nsCOMPtr<nsIRunnable>>& aViolations) {
1772
if (mFontFaceSet) {
1773
mFontFaceSet->DispatchFontLoadViolations(aViolations);
1774
}
1775
}
1776
1777
/* virtual */
1778
nsresult FontFaceSet::UserFontSet::StartLoad(
1779
gfxUserFontEntry* aUserFontEntry, const gfxFontFaceSrc* aFontFaceSrc) {
1780
if (!mFontFaceSet) {
1781
return NS_ERROR_FAILURE;
1782
}
1783
return mFontFaceSet->StartLoad(aUserFontEntry, aFontFaceSrc);
1784
}
1785
1786
void FontFaceSet::UserFontSet::RecordFontLoadDone(uint32_t aFontSize,
1787
TimeStamp aDoneTime) {
1788
mDownloadCount++;
1789
mDownloadSize += aFontSize;
1790
Telemetry::Accumulate(Telemetry::WEBFONT_SIZE, aFontSize / 1024);
1791
1792
if (!mFontFaceSet) {
1793
return;
1794
}
1795
1796
TimeStamp navStart = mFontFaceSet->GetNavigationStartTimeStamp();
1797
TimeStamp zero;
1798
if (navStart != zero) {
1799
Telemetry::AccumulateTimeDelta(Telemetry::WEBFONT_DOWNLOAD_TIME_AFTER_START,
1800
navStart, aDoneTime);
1801
}
1802
}
1803
1804
/* virtual */
1805
nsresult FontFaceSet::UserFontSet::LogMessage(gfxUserFontEntry* aUserFontEntry,
1806
const char* aMessage,
1807
uint32_t aFlags,
1808
nsresult aStatus) {
1809
if (!mFontFaceSet) {
1810
return NS_ERROR_FAILURE;
1811
}
1812
return mFontFaceSet->LogMessage(aUserFontEntry, aMessage, aFlags, aStatus);
1813
}
1814
1815
/* virtual */
1816
nsresult FontFaceSet::UserFontSet::SyncLoadFontData(
1817
gfxUserFontEntry* aFontToLoad, const gfxFontFaceSrc* aFontFaceSrc,
1818
uint8_t*& aBuffer, uint32_t& aBufferLength) {
1819
if (!mFontFaceSet) {
1820
return NS_ERROR_FAILURE;
1821
}
1822
return mFontFaceSet->SyncLoadFontData(aFontToLoad, aFontFaceSrc, aBuffer,
1823
aBufferLength);
1824
}
1825
1826
/* virtual */
1827
bool FontFaceSet::UserFontSet::GetPrivateBrowsing() {
1828
return mFontFaceSet && mFontFaceSet->mPrivateBrowsing;
1829
}
1830
1831
/* virtual */
1832
void FontFaceSet::UserFontSet::DoRebuildUserFontSet() {
1833
if (!mFontFaceSet) {
1834
return;
1835
}
1836
mFontFaceSet->MarkUserFontSetDirty();
1837
}
1838