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