1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
3 /* This Source Code Form is subject to the terms of the Mozilla Public
4 * License, v. 2.0. If a copy of the MPL was not distributed with this
5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
6
7 #include "mozilla/dom/FontFace.h"
8
9 #include <algorithm>
10 #include "gfxPlatformFontList.h"
11 #include "mozilla/dom/CSSFontFaceRule.h"
12 #include "mozilla/dom/FontFaceBinding.h"
13 #include "mozilla/dom/FontFaceSet.h"
14 #include "mozilla/dom/Promise.h"
15 #include "mozilla/dom/TypedArray.h"
16 #include "mozilla/dom/UnionTypes.h"
17 #include "mozilla/CycleCollectedJSContext.h"
18 #include "mozilla/ServoBindings.h"
19 #include "mozilla/ServoCSSParser.h"
20 #include "mozilla/ServoStyleSet.h"
21 #include "mozilla/ServoUtils.h"
22 #include "mozilla/StaticPrefs_layout.h"
23 #include "mozilla/dom/Document.h"
24 #include "nsStyleUtil.h"
25
26 namespace mozilla {
27 namespace dom {
28
29 // -- FontFaceBufferSource ---------------------------------------------------
30
31 /**
32 * An object that wraps a FontFace object and exposes its ArrayBuffer
33 * or ArrayBufferView data in a form the user font set can consume.
34 */
35 class FontFaceBufferSource : public gfxFontFaceBufferSource {
36 public:
FontFaceBufferSource(FontFace * aFontFace)37 explicit FontFaceBufferSource(FontFace* aFontFace) : mFontFace(aFontFace) {}
38 virtual void TakeBuffer(uint8_t*& aBuffer, uint32_t& aLength) override;
39
40 private:
41 RefPtr<FontFace> mFontFace;
42 };
43
TakeBuffer(uint8_t * & aBuffer,uint32_t & aLength)44 void FontFaceBufferSource::TakeBuffer(uint8_t*& aBuffer, uint32_t& aLength) {
45 MOZ_ASSERT(mFontFace,
46 "only call TakeBuffer once on a given "
47 "FontFaceBufferSource object");
48 mFontFace->TakeBuffer(aBuffer, aLength);
49 mFontFace = nullptr;
50 }
51
52 // -- Utility functions ------------------------------------------------------
53
54 template <typename T>
GetDataFrom(const T & aObject,uint8_t * & aBuffer,uint32_t & aLength)55 static void GetDataFrom(const T& aObject, uint8_t*& aBuffer,
56 uint32_t& aLength) {
57 MOZ_ASSERT(!aBuffer);
58 aObject.ComputeState();
59 // We use malloc here rather than a FallibleTArray or fallible
60 // operator new[] since the gfxUserFontEntry will be calling free
61 // on it.
62 aBuffer = (uint8_t*)malloc(aObject.Length());
63 if (!aBuffer) {
64 return;
65 }
66 memcpy((void*)aBuffer, aObject.Data(), aObject.Length());
67 aLength = aObject.Length();
68 }
69
70 // -- FontFace ---------------------------------------------------------------
71
72 NS_IMPL_CYCLE_COLLECTION_CLASS(FontFace)
73
74 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(FontFace)
75 NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mParent)
76 NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mLoaded)
77 NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mFontFaceSet)
78 NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mOtherFontFaceSets)
79 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
80
81 NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(FontFace)
82 NS_IMPL_CYCLE_COLLECTION_UNLINK(mParent)
83 NS_IMPL_CYCLE_COLLECTION_UNLINK(mLoaded)
84 NS_IMPL_CYCLE_COLLECTION_UNLINK(mFontFaceSet)
85 tmp->mInFontFaceSet = false;
86 tmp->SetUserFontEntry(nullptr);
NS_IMPL_CYCLE_COLLECTION_UNLINK(mOtherFontFaceSets)87 NS_IMPL_CYCLE_COLLECTION_UNLINK(mOtherFontFaceSets)
88 NS_IMPL_CYCLE_COLLECTION_UNLINK_PRESERVED_WRAPPER
89 NS_IMPL_CYCLE_COLLECTION_UNLINK_END
90
91 NS_IMPL_CYCLE_COLLECTION_TRACE_BEGIN(FontFace)
92 NS_IMPL_CYCLE_COLLECTION_TRACE_PRESERVED_WRAPPER
93 NS_IMPL_CYCLE_COLLECTION_TRACE_END
94
95 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(FontFace)
96 NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY
97 NS_INTERFACE_MAP_ENTRY(nsISupports)
98 NS_INTERFACE_MAP_END
99
100 NS_IMPL_CYCLE_COLLECTING_ADDREF(FontFace)
101 NS_IMPL_CYCLE_COLLECTING_RELEASE(FontFace)
102
103 FontFace::FontFace(nsISupports* aParent, FontFaceSet* aFontFaceSet)
104 : mParent(aParent),
105 mLoadedRejection(NS_OK),
106 mStatus(FontFaceLoadStatus::Unloaded),
107 mSourceType(SourceType(0)),
108 mSourceBuffer(nullptr),
109 mSourceBufferLength(0),
110 mFontFaceSet(aFontFaceSet),
111 mUnicodeRangeDirty(true),
112 mInFontFaceSet(false) {}
113
~FontFace()114 FontFace::~FontFace() {
115 // Assert that we don't drop any FontFace objects during a Servo traversal,
116 // since PostTraversalTask objects can hold raw pointers to FontFaces.
117 MOZ_ASSERT(!ServoStyleSet::IsInServoTraversal());
118
119 SetUserFontEntry(nullptr);
120
121 if (mSourceBuffer) {
122 free(mSourceBuffer);
123 }
124 }
125
WrapObject(JSContext * aCx,JS::Handle<JSObject * > aGivenProto)126 JSObject* FontFace::WrapObject(JSContext* aCx,
127 JS::Handle<JSObject*> aGivenProto) {
128 return FontFace_Binding::Wrap(aCx, this, aGivenProto);
129 }
130
LoadStateToStatus(gfxUserFontEntry::UserFontLoadState aLoadState)131 static FontFaceLoadStatus LoadStateToStatus(
132 gfxUserFontEntry::UserFontLoadState aLoadState) {
133 switch (aLoadState) {
134 case gfxUserFontEntry::UserFontLoadState::STATUS_NOT_LOADED:
135 return FontFaceLoadStatus::Unloaded;
136 case gfxUserFontEntry::UserFontLoadState::STATUS_LOAD_PENDING:
137 case gfxUserFontEntry::UserFontLoadState::STATUS_LOADING:
138 return FontFaceLoadStatus::Loading;
139 case gfxUserFontEntry::UserFontLoadState::STATUS_LOADED:
140 return FontFaceLoadStatus::Loaded;
141 case gfxUserFontEntry::UserFontLoadState::STATUS_FAILED:
142 return FontFaceLoadStatus::Error;
143 }
144 MOZ_ASSERT_UNREACHABLE("invalid aLoadState value");
145 return FontFaceLoadStatus::Error;
146 }
147
CreateForRule(nsISupports * aGlobal,FontFaceSet * aFontFaceSet,RawServoFontFaceRule * aRule)148 already_AddRefed<FontFace> FontFace::CreateForRule(
149 nsISupports* aGlobal, FontFaceSet* aFontFaceSet,
150 RawServoFontFaceRule* aRule) {
151 RefPtr<FontFace> obj = new FontFace(aGlobal, aFontFaceSet);
152 obj->mRule = aRule;
153 obj->mSourceType = eSourceType_FontFaceRule;
154 obj->mInFontFaceSet = true;
155 return obj.forget();
156 }
157
Constructor(const GlobalObject & aGlobal,const nsACString & aFamily,const UTF8StringOrArrayBufferOrArrayBufferView & aSource,const FontFaceDescriptors & aDescriptors,ErrorResult & aRv)158 already_AddRefed<FontFace> FontFace::Constructor(
159 const GlobalObject& aGlobal, const nsACString& aFamily,
160 const UTF8StringOrArrayBufferOrArrayBufferView& aSource,
161 const FontFaceDescriptors& aDescriptors, ErrorResult& aRv) {
162 nsISupports* global = aGlobal.GetAsSupports();
163 nsCOMPtr<nsPIDOMWindowInner> window = do_QueryInterface(global);
164 if (!window) {
165 aRv.Throw(NS_ERROR_FAILURE);
166 return nullptr;
167 }
168
169 Document* doc = window->GetDoc();
170 if (!doc) {
171 aRv.Throw(NS_ERROR_FAILURE);
172 return nullptr;
173 }
174
175 RefPtr<FontFace> obj = new FontFace(global, doc->Fonts());
176 if (!obj->SetDescriptors(aFamily, aDescriptors)) {
177 return obj.forget();
178 }
179
180 obj->InitializeSource(aSource);
181 return obj.forget();
182 }
183
InitializeSource(const UTF8StringOrArrayBufferOrArrayBufferView & aSource)184 void FontFace::InitializeSource(
185 const UTF8StringOrArrayBufferOrArrayBufferView& aSource) {
186 if (aSource.IsUTF8String()) {
187 IgnoredErrorResult rv;
188 SetDescriptor(eCSSFontDesc_Src, aSource.GetAsUTF8String(), rv);
189 if (rv.Failed()) {
190 Reject(NS_ERROR_DOM_SYNTAX_ERR);
191
192 SetStatus(FontFaceLoadStatus::Error);
193 return;
194 }
195
196 mSourceType = eSourceType_URLs;
197 return;
198 }
199
200 mSourceType = FontFace::eSourceType_Buffer;
201
202 if (aSource.IsArrayBuffer()) {
203 GetDataFrom(aSource.GetAsArrayBuffer(), mSourceBuffer, mSourceBufferLength);
204 } else {
205 MOZ_ASSERT(aSource.IsArrayBufferView());
206 GetDataFrom(aSource.GetAsArrayBufferView(), mSourceBuffer,
207 mSourceBufferLength);
208 }
209
210 SetStatus(FontFaceLoadStatus::Loading);
211 DoLoad();
212 }
213
GetFamily(nsACString & aResult)214 void FontFace::GetFamily(nsACString& aResult) {
215 GetDesc(eCSSFontDesc_Family, aResult);
216 }
217
SetFamily(const nsACString & aValue,ErrorResult & aRv)218 void FontFace::SetFamily(const nsACString& aValue, ErrorResult& aRv) {
219 mFontFaceSet->FlushUserFontSet();
220 if (SetDescriptor(eCSSFontDesc_Family, aValue, aRv)) {
221 DescriptorUpdated();
222 }
223 }
224
GetStyle(nsACString & aResult)225 void FontFace::GetStyle(nsACString& aResult) {
226 GetDesc(eCSSFontDesc_Style, aResult);
227 }
228
SetStyle(const nsACString & aValue,ErrorResult & aRv)229 void FontFace::SetStyle(const nsACString& aValue, ErrorResult& aRv) {
230 if (SetDescriptor(eCSSFontDesc_Style, aValue, aRv)) {
231 DescriptorUpdated();
232 }
233 }
234
GetWeight(nsACString & aResult)235 void FontFace::GetWeight(nsACString& aResult) {
236 GetDesc(eCSSFontDesc_Weight, aResult);
237 }
238
SetWeight(const nsACString & aValue,ErrorResult & aRv)239 void FontFace::SetWeight(const nsACString& aValue, ErrorResult& aRv) {
240 mFontFaceSet->FlushUserFontSet();
241 if (SetDescriptor(eCSSFontDesc_Weight, aValue, aRv)) {
242 DescriptorUpdated();
243 }
244 }
245
GetStretch(nsACString & aResult)246 void FontFace::GetStretch(nsACString& aResult) {
247 GetDesc(eCSSFontDesc_Stretch, aResult);
248 }
249
SetStretch(const nsACString & aValue,ErrorResult & aRv)250 void FontFace::SetStretch(const nsACString& aValue, ErrorResult& aRv) {
251 mFontFaceSet->FlushUserFontSet();
252 if (SetDescriptor(eCSSFontDesc_Stretch, aValue, aRv)) {
253 DescriptorUpdated();
254 }
255 }
256
GetUnicodeRange(nsACString & aResult)257 void FontFace::GetUnicodeRange(nsACString& aResult) {
258 GetDesc(eCSSFontDesc_UnicodeRange, aResult);
259 }
260
SetUnicodeRange(const nsACString & aValue,ErrorResult & aRv)261 void FontFace::SetUnicodeRange(const nsACString& aValue, ErrorResult& aRv) {
262 mFontFaceSet->FlushUserFontSet();
263 if (SetDescriptor(eCSSFontDesc_UnicodeRange, aValue, aRv)) {
264 DescriptorUpdated();
265 }
266 }
267
GetVariant(nsACString & aResult)268 void FontFace::GetVariant(nsACString& aResult) {
269 // XXX Just expose the font-variant descriptor as "normal" until we
270 // support it properly (bug 1055385).
271 aResult.AssignLiteral("normal");
272 }
273
SetVariant(const nsACString & aValue,ErrorResult & aRv)274 void FontFace::SetVariant(const nsACString& aValue, ErrorResult& aRv) {
275 // XXX Ignore assignments to variant until we support font-variant
276 // descriptors (bug 1055385).
277 }
278
GetFeatureSettings(nsACString & aResult)279 void FontFace::GetFeatureSettings(nsACString& aResult) {
280 GetDesc(eCSSFontDesc_FontFeatureSettings, aResult);
281 }
282
SetFeatureSettings(const nsACString & aValue,ErrorResult & aRv)283 void FontFace::SetFeatureSettings(const nsACString& aValue, ErrorResult& aRv) {
284 mFontFaceSet->FlushUserFontSet();
285 if (SetDescriptor(eCSSFontDesc_FontFeatureSettings, aValue, aRv)) {
286 DescriptorUpdated();
287 }
288 }
289
GetVariationSettings(nsACString & aResult)290 void FontFace::GetVariationSettings(nsACString& aResult) {
291 GetDesc(eCSSFontDesc_FontVariationSettings, aResult);
292 }
293
SetVariationSettings(const nsACString & aValue,ErrorResult & aRv)294 void FontFace::SetVariationSettings(const nsACString& aValue,
295 ErrorResult& aRv) {
296 mFontFaceSet->FlushUserFontSet();
297 if (SetDescriptor(eCSSFontDesc_FontVariationSettings, aValue, aRv)) {
298 DescriptorUpdated();
299 }
300 }
301
GetDisplay(nsACString & aResult)302 void FontFace::GetDisplay(nsACString& aResult) {
303 GetDesc(eCSSFontDesc_Display, aResult);
304 }
305
SetDisplay(const nsACString & aValue,ErrorResult & aRv)306 void FontFace::SetDisplay(const nsACString& aValue, ErrorResult& aRv) {
307 if (SetDescriptor(eCSSFontDesc_Display, aValue, aRv)) {
308 DescriptorUpdated();
309 }
310 }
311
GetAscentOverride(nsACString & aResult)312 void FontFace::GetAscentOverride(nsACString& aResult) {
313 GetDesc(eCSSFontDesc_AscentOverride, aResult);
314 }
315
SetAscentOverride(const nsACString & aValue,ErrorResult & aRv)316 void FontFace::SetAscentOverride(const nsACString& aValue, ErrorResult& aRv) {
317 if (SetDescriptor(eCSSFontDesc_AscentOverride, aValue, aRv)) {
318 DescriptorUpdated();
319 }
320 }
321
GetDescentOverride(nsACString & aResult)322 void FontFace::GetDescentOverride(nsACString& aResult) {
323 GetDesc(eCSSFontDesc_DescentOverride, aResult);
324 }
325
SetDescentOverride(const nsACString & aValue,ErrorResult & aRv)326 void FontFace::SetDescentOverride(const nsACString& aValue, ErrorResult& aRv) {
327 if (SetDescriptor(eCSSFontDesc_DescentOverride, aValue, aRv)) {
328 DescriptorUpdated();
329 }
330 }
331
GetLineGapOverride(nsACString & aResult)332 void FontFace::GetLineGapOverride(nsACString& aResult) {
333 GetDesc(eCSSFontDesc_LineGapOverride, aResult);
334 }
335
SetLineGapOverride(const nsACString & aValue,ErrorResult & aRv)336 void FontFace::SetLineGapOverride(const nsACString& aValue, ErrorResult& aRv) {
337 if (SetDescriptor(eCSSFontDesc_LineGapOverride, aValue, aRv)) {
338 DescriptorUpdated();
339 }
340 }
341
GetSizeAdjust(nsACString & aResult)342 void FontFace::GetSizeAdjust(nsACString& aResult) {
343 GetDesc(eCSSFontDesc_SizeAdjust, aResult);
344 }
345
SetSizeAdjust(const nsACString & aValue,ErrorResult & aRv)346 void FontFace::SetSizeAdjust(const nsACString& aValue, ErrorResult& aRv) {
347 if (SetDescriptor(eCSSFontDesc_SizeAdjust, aValue, aRv)) {
348 DescriptorUpdated();
349 }
350 }
351
DescriptorUpdated()352 void FontFace::DescriptorUpdated() {
353 // If we haven't yet initialized mUserFontEntry, no need to do anything here;
354 // we'll respect the updated descriptor when the time comes to create it.
355 if (!mUserFontEntry) {
356 return;
357 }
358
359 // Behind the scenes, this will actually update the existing entry and return
360 // it, rather than create a new one.
361 RefPtr<gfxUserFontEntry> newEntry =
362 mFontFaceSet->FindOrCreateUserFontEntryFromFontFace(this);
363 SetUserFontEntry(newEntry);
364
365 if (mInFontFaceSet) {
366 mFontFaceSet->MarkUserFontSetDirty();
367 }
368 for (auto& set : mOtherFontFaceSets) {
369 set->MarkUserFontSetDirty();
370 }
371 }
372
Status()373 FontFaceLoadStatus FontFace::Status() { return mStatus; }
374
Load(ErrorResult & aRv)375 Promise* FontFace::Load(ErrorResult& aRv) {
376 MOZ_ASSERT(NS_IsMainThread());
377
378 mFontFaceSet->FlushUserFontSet();
379
380 EnsurePromise();
381
382 if (!mLoaded) {
383 aRv.Throw(NS_ERROR_FAILURE);
384 return nullptr;
385 }
386
387 // Calling Load on a FontFace constructed with an ArrayBuffer data source,
388 // or on one that is already loading (or has finished loading), has no
389 // effect.
390 if (mSourceType == eSourceType_Buffer ||
391 mStatus != FontFaceLoadStatus::Unloaded) {
392 return mLoaded;
393 }
394
395 // Calling the user font entry's Load method will end up setting our
396 // status to Loading, but the spec requires us to set it to Loading
397 // here.
398 SetStatus(FontFaceLoadStatus::Loading);
399
400 DoLoad();
401
402 return mLoaded;
403 }
404
CreateUserFontEntry()405 gfxUserFontEntry* FontFace::CreateUserFontEntry() {
406 if (!mUserFontEntry) {
407 MOZ_ASSERT(!HasRule(),
408 "Rule backed FontFace objects should already have a user font "
409 "entry by the time Load() can be called on them");
410
411 RefPtr<gfxUserFontEntry> newEntry =
412 mFontFaceSet->FindOrCreateUserFontEntryFromFontFace(this);
413 if (newEntry) {
414 SetUserFontEntry(newEntry);
415 }
416 }
417
418 return mUserFontEntry;
419 }
420
DoLoad()421 void FontFace::DoLoad() {
422 if (!CreateUserFontEntry()) {
423 return;
424 }
425 mUserFontEntry->Load();
426 }
427
GetLoaded(ErrorResult & aRv)428 Promise* FontFace::GetLoaded(ErrorResult& aRv) {
429 MOZ_ASSERT(NS_IsMainThread());
430
431 EnsurePromise();
432
433 if (!mLoaded) {
434 aRv.Throw(NS_ERROR_FAILURE);
435 return nullptr;
436 }
437
438 return mLoaded;
439 }
440
SetStatus(FontFaceLoadStatus aStatus)441 void FontFace::SetStatus(FontFaceLoadStatus aStatus) {
442 AssertIsMainThreadOrServoFontMetricsLocked();
443
444 if (mStatus == aStatus) {
445 return;
446 }
447
448 if (aStatus < mStatus) {
449 // We're being asked to go backwards in status! Normally, this shouldn't
450 // happen. But it can if the FontFace had a user font entry that had
451 // loaded, but then was given a new one by FontFaceSet::InsertRuleFontFace
452 // if we used a local() rule. For now, just ignore the request to
453 // go backwards in status.
454 return;
455 }
456
457 mStatus = aStatus;
458
459 if (mInFontFaceSet) {
460 mFontFaceSet->OnFontFaceStatusChanged(this);
461 }
462
463 for (FontFaceSet* otherSet : mOtherFontFaceSets) {
464 otherSet->OnFontFaceStatusChanged(this);
465 }
466
467 if (mStatus == FontFaceLoadStatus::Loaded) {
468 if (mLoaded) {
469 DoResolve();
470 }
471 } else if (mStatus == FontFaceLoadStatus::Error) {
472 if (mSourceType == eSourceType_Buffer) {
473 Reject(NS_ERROR_DOM_SYNTAX_ERR);
474 } else {
475 Reject(NS_ERROR_DOM_NETWORK_ERR);
476 }
477 }
478 }
479
DoResolve()480 void FontFace::DoResolve() {
481 AssertIsMainThreadOrServoFontMetricsLocked();
482
483 if (ServoStyleSet* ss = ServoStyleSet::Current()) {
484 // See comments in Gecko_GetFontMetrics.
485 ss->AppendTask(PostTraversalTask::ResolveFontFaceLoadedPromise(this));
486 return;
487 }
488
489 mLoaded->MaybeResolve(this);
490 }
491
DoReject(nsresult aResult)492 void FontFace::DoReject(nsresult aResult) {
493 AssertIsMainThreadOrServoFontMetricsLocked();
494
495 if (ServoStyleSet* ss = ServoStyleSet::Current()) {
496 // See comments in Gecko_GetFontMetrics.
497 ss->AppendTask(
498 PostTraversalTask::RejectFontFaceLoadedPromise(this, aResult));
499 return;
500 }
501
502 mLoaded->MaybeReject(aResult);
503 }
504
GetURLExtraData() const505 already_AddRefed<URLExtraData> FontFace::GetURLExtraData() const {
506 nsCOMPtr<nsIGlobalObject> global = do_QueryInterface(mParent);
507 nsCOMPtr<nsIPrincipal> principal = global->PrincipalOrNull();
508
509 nsCOMPtr<nsPIDOMWindowInner> window = do_QueryInterface(mParent);
510 nsCOMPtr<nsIURI> docURI = window->GetDocumentURI();
511 nsCOMPtr<nsIURI> base = window->GetDocBaseURI();
512
513 // We pass RP_Unset when creating ReferrerInfo object here because it's not
514 // going to result to change referer policy in a resource request.
515 nsCOMPtr<nsIReferrerInfo> referrerInfo =
516 new ReferrerInfo(docURI, ReferrerPolicy::_empty);
517
518 RefPtr<URLExtraData> url = new URLExtraData(base, referrerInfo, principal);
519 return url.forget();
520 }
521
522 // Boolean result indicates whether the value of the descriptor was actually
523 // changed.
SetDescriptor(nsCSSFontDesc aFontDesc,const nsACString & aValue,ErrorResult & aRv)524 bool FontFace::SetDescriptor(nsCSSFontDesc aFontDesc, const nsACString& aValue,
525 ErrorResult& aRv) {
526 // FIXME We probably don't need to distinguish between this anymore
527 // since we have common backend now.
528 NS_ASSERTION(!HasRule(), "we don't handle rule backed FontFace objects yet");
529 if (HasRule()) {
530 return false;
531 }
532
533 // FIXME(heycam): Should not allow modification of FontFaces that are
534 // CSS-connected and whose rule is read only.
535 RefPtr<URLExtraData> url = GetURLExtraData();
536 bool changed;
537 if (!Servo_FontFaceRule_SetDescriptor(GetData(), aFontDesc, &aValue, url,
538 &changed)) {
539 aRv.ThrowSyntaxError("Invalid font descriptor");
540 return false;
541 }
542
543 if (!changed) {
544 return false;
545 }
546
547 if (aFontDesc == eCSSFontDesc_UnicodeRange) {
548 mUnicodeRangeDirty = true;
549 }
550
551 return true;
552 }
553
SetDescriptors(const nsACString & aFamily,const FontFaceDescriptors & aDescriptors)554 bool FontFace::SetDescriptors(const nsACString& aFamily,
555 const FontFaceDescriptors& aDescriptors) {
556 MOZ_ASSERT(!HasRule());
557 MOZ_ASSERT(!mDescriptors);
558
559 mDescriptors = Servo_FontFaceRule_CreateEmpty().Consume();
560
561 // Helper to call SetDescriptor and return true on success, false on failure.
562 auto setDesc = [=](nsCSSFontDesc aDesc, const nsACString& aVal) -> bool {
563 IgnoredErrorResult rv;
564 SetDescriptor(aDesc, aVal, rv);
565 return !rv.Failed();
566 };
567
568 // Parse all of the mDescriptors in aInitializer, which are the values
569 // we got from the JS constructor.
570 if (!setDesc(eCSSFontDesc_Family, aFamily) ||
571 !setDesc(eCSSFontDesc_Style, aDescriptors.mStyle) ||
572 !setDesc(eCSSFontDesc_Weight, aDescriptors.mWeight) ||
573 !setDesc(eCSSFontDesc_Stretch, aDescriptors.mStretch) ||
574 !setDesc(eCSSFontDesc_UnicodeRange, aDescriptors.mUnicodeRange) ||
575 !setDesc(eCSSFontDesc_FontFeatureSettings,
576 aDescriptors.mFeatureSettings) ||
577 (StaticPrefs::layout_css_font_variations_enabled() &&
578 !setDesc(eCSSFontDesc_FontVariationSettings,
579 aDescriptors.mVariationSettings)) ||
580 !setDesc(eCSSFontDesc_Display, aDescriptors.mDisplay) ||
581 (StaticPrefs::layout_css_font_metrics_overrides_enabled() &&
582 (!setDesc(eCSSFontDesc_AscentOverride, aDescriptors.mAscentOverride) ||
583 !setDesc(eCSSFontDesc_DescentOverride, aDescriptors.mDescentOverride) ||
584 !setDesc(eCSSFontDesc_LineGapOverride,
585 aDescriptors.mLineGapOverride))) ||
586 (StaticPrefs::layout_css_size_adjust_enabled() &&
587 !setDesc(eCSSFontDesc_SizeAdjust, aDescriptors.mSizeAdjust))) {
588 // XXX Handle font-variant once we support it (bug 1055385).
589
590 // If any of the descriptors failed to parse, none of them should be set
591 // on the FontFace.
592 mDescriptors = Servo_FontFaceRule_CreateEmpty().Consume();
593
594 Reject(NS_ERROR_DOM_SYNTAX_ERR);
595
596 SetStatus(FontFaceLoadStatus::Error);
597 return false;
598 }
599
600 return true;
601 }
602
GetDesc(nsCSSFontDesc aDescID,nsACString & aResult) const603 void FontFace::GetDesc(nsCSSFontDesc aDescID, nsACString& aResult) const {
604 aResult.Truncate();
605 Servo_FontFaceRule_GetDescriptorCssText(GetData(), aDescID, &aResult);
606
607 // Fill in a default value for missing descriptors.
608 if (aResult.IsEmpty()) {
609 if (aDescID == eCSSFontDesc_UnicodeRange) {
610 aResult.AssignLiteral("U+0-10FFFF");
611 } else if (aDescID == eCSSFontDesc_Display) {
612 aResult.AssignLiteral("auto");
613 } else if (aDescID != eCSSFontDesc_Family && aDescID != eCSSFontDesc_Src) {
614 aResult.AssignLiteral("normal");
615 }
616 }
617 }
618
SetUserFontEntry(gfxUserFontEntry * aEntry)619 void FontFace::SetUserFontEntry(gfxUserFontEntry* aEntry) {
620 if (mUserFontEntry) {
621 mUserFontEntry->mFontFaces.RemoveElement(this);
622 }
623
624 mUserFontEntry = static_cast<Entry*>(aEntry);
625 if (mUserFontEntry) {
626 mUserFontEntry->mFontFaces.AppendElement(this);
627
628 MOZ_ASSERT(
629 mUserFontEntry->GetUserFontSet() == mFontFaceSet->GetUserFontSet(),
630 "user font entry must be associated with the same user font set "
631 "as the FontFace");
632
633 // Our newly assigned user font entry might be in the process of or
634 // finished loading, so set our status accordingly. But only do so
635 // if we're not going "backwards" in status, which could otherwise
636 // happen in this case:
637 //
638 // new FontFace("ABC", "url(x)").load();
639 //
640 // where the SetUserFontEntry call (from the after-initialization
641 // DoLoad call) comes after the author's call to load(), which set mStatus
642 // to Loading.
643 FontFaceLoadStatus newStatus =
644 LoadStateToStatus(mUserFontEntry->LoadState());
645 if (newStatus > mStatus) {
646 SetStatus(newStatus);
647 }
648 }
649 }
650
GetFontWeight() const651 Maybe<StyleComputedFontWeightRange> FontFace::GetFontWeight() const {
652 StyleComputedFontWeightRange range;
653 if (!Servo_FontFaceRule_GetFontWeight(GetData(), &range)) {
654 return Nothing();
655 }
656 return Some(range);
657 }
658
GetFontStretch() const659 Maybe<StyleComputedFontStretchRange> FontFace::GetFontStretch() const {
660 StyleComputedFontStretchRange range;
661 if (!Servo_FontFaceRule_GetFontStretch(GetData(), &range)) {
662 return Nothing();
663 }
664 return Some(range);
665 }
666
GetFontStyle() const667 Maybe<StyleComputedFontStyleDescriptor> FontFace::GetFontStyle() const {
668 auto descriptor = StyleComputedFontStyleDescriptor::Normal();
669 if (!Servo_FontFaceRule_GetFontStyle(GetData(), &descriptor)) {
670 return Nothing();
671 }
672 return Some(descriptor);
673 }
674
GetFontDisplay() const675 Maybe<StyleFontDisplay> FontFace::GetFontDisplay() const {
676 StyleFontDisplay display;
677 if (!Servo_FontFaceRule_GetFontDisplay(GetData(), &display)) {
678 return Nothing();
679 }
680 return Some(display);
681 }
682
GetFontLanguageOverride() const683 Maybe<StyleFontLanguageOverride> FontFace::GetFontLanguageOverride() const {
684 StyleFontLanguageOverride langOverride;
685 if (!Servo_FontFaceRule_GetFontLanguageOverride(GetData(), &langOverride)) {
686 return Nothing();
687 }
688 return Some(langOverride);
689 }
690
GetAscentOverride() const691 Maybe<StylePercentage> FontFace::GetAscentOverride() const {
692 StylePercentage ascent{0};
693 if (!Servo_FontFaceRule_GetAscentOverride(GetData(), &ascent)) {
694 return Nothing();
695 }
696 return Some(ascent);
697 }
698
GetDescentOverride() const699 Maybe<StylePercentage> FontFace::GetDescentOverride() const {
700 StylePercentage descent{0};
701 if (!Servo_FontFaceRule_GetDescentOverride(GetData(), &descent)) {
702 return Nothing();
703 }
704 return Some(descent);
705 }
706
GetLineGapOverride() const707 Maybe<StylePercentage> FontFace::GetLineGapOverride() const {
708 StylePercentage lineGap{0};
709 if (!Servo_FontFaceRule_GetLineGapOverride(GetData(), &lineGap)) {
710 return Nothing();
711 }
712 return Some(lineGap);
713 }
714
GetSizeAdjust() const715 Maybe<StylePercentage> FontFace::GetSizeAdjust() const {
716 StylePercentage sizeAdjust;
717 if (!Servo_FontFaceRule_GetSizeAdjust(GetData(), &sizeAdjust)) {
718 return Nothing();
719 }
720 return Some(sizeAdjust);
721 }
722
HasLocalSrc() const723 bool FontFace::HasLocalSrc() const {
724 AutoTArray<StyleFontFaceSourceListComponent, 8> components;
725 GetSources(components);
726 for (auto& component : components) {
727 if (component.tag == StyleFontFaceSourceListComponent::Tag::Local) {
728 return true;
729 }
730 }
731 return false;
732 }
733
GetFontFeatureSettings(nsTArray<gfxFontFeature> & aFeatures) const734 void FontFace::GetFontFeatureSettings(
735 nsTArray<gfxFontFeature>& aFeatures) const {
736 Servo_FontFaceRule_GetFeatureSettings(GetData(), &aFeatures);
737 }
738
GetFontVariationSettings(nsTArray<gfxFontVariation> & aVariations) const739 void FontFace::GetFontVariationSettings(
740 nsTArray<gfxFontVariation>& aVariations) const {
741 Servo_FontFaceRule_GetVariationSettings(GetData(), &aVariations);
742 }
743
GetSources(nsTArray<StyleFontFaceSourceListComponent> & aSources) const744 void FontFace::GetSources(
745 nsTArray<StyleFontFaceSourceListComponent>& aSources) const {
746 Servo_FontFaceRule_GetSources(GetData(), &aSources);
747 }
748
GetFamilyName() const749 nsAtom* FontFace::GetFamilyName() const {
750 return Servo_FontFaceRule_GetFamilyName(GetData());
751 }
752
DisconnectFromRule()753 void FontFace::DisconnectFromRule() {
754 MOZ_ASSERT(HasRule());
755
756 // Make a copy of the descriptors.
757 mDescriptors = Servo_FontFaceRule_Clone(mRule).Consume();
758 mRule = nullptr;
759 mInFontFaceSet = false;
760 }
761
HasFontData() const762 bool FontFace::HasFontData() const {
763 return mSourceType == eSourceType_Buffer && mSourceBuffer;
764 }
765
TakeBuffer(uint8_t * & aBuffer,uint32_t & aLength)766 void FontFace::TakeBuffer(uint8_t*& aBuffer, uint32_t& aLength) {
767 MOZ_ASSERT(HasFontData());
768
769 aBuffer = mSourceBuffer;
770 aLength = mSourceBufferLength;
771
772 mSourceBuffer = nullptr;
773 mSourceBufferLength = 0;
774 }
775
CreateBufferSource()776 already_AddRefed<gfxFontFaceBufferSource> FontFace::CreateBufferSource() {
777 RefPtr<FontFaceBufferSource> bufferSource = new FontFaceBufferSource(this);
778 return bufferSource.forget();
779 }
780
IsInFontFaceSet(FontFaceSet * aFontFaceSet) const781 bool FontFace::IsInFontFaceSet(FontFaceSet* aFontFaceSet) const {
782 if (mFontFaceSet == aFontFaceSet) {
783 return mInFontFaceSet;
784 }
785 return mOtherFontFaceSets.Contains(aFontFaceSet);
786 }
787
AddFontFaceSet(FontFaceSet * aFontFaceSet)788 void FontFace::AddFontFaceSet(FontFaceSet* aFontFaceSet) {
789 MOZ_ASSERT(!IsInFontFaceSet(aFontFaceSet));
790
791 if (mFontFaceSet == aFontFaceSet) {
792 mInFontFaceSet = true;
793 } else {
794 mOtherFontFaceSets.AppendElement(aFontFaceSet);
795 }
796 }
797
RemoveFontFaceSet(FontFaceSet * aFontFaceSet)798 void FontFace::RemoveFontFaceSet(FontFaceSet* aFontFaceSet) {
799 MOZ_ASSERT(IsInFontFaceSet(aFontFaceSet));
800
801 if (mFontFaceSet == aFontFaceSet) {
802 mInFontFaceSet = false;
803 } else {
804 mOtherFontFaceSets.RemoveElement(aFontFaceSet);
805 }
806 }
807
Reject(nsresult aResult)808 void FontFace::Reject(nsresult aResult) {
809 AssertIsMainThreadOrServoFontMetricsLocked();
810
811 if (mLoaded) {
812 DoReject(aResult);
813 } else if (mLoadedRejection == NS_OK) {
814 mLoadedRejection = aResult;
815 }
816 }
817
EnsurePromise()818 void FontFace::EnsurePromise() {
819 MOZ_ASSERT(NS_IsMainThread());
820
821 if (mLoaded) {
822 return;
823 }
824
825 nsCOMPtr<nsIGlobalObject> global = do_QueryInterface(mParent);
826
827 // If the pref is not set, don't create the Promise (which the page wouldn't
828 // be able to get to anyway) as it causes the window.FontFace constructor
829 // to be created.
830 if (global && FontFaceSet::PrefEnabled()) {
831 ErrorResult rv;
832 mLoaded = Promise::Create(global, rv);
833
834 if (mStatus == FontFaceLoadStatus::Loaded) {
835 mLoaded->MaybeResolve(this);
836 } else if (mLoadedRejection != NS_OK) {
837 mLoaded->MaybeReject(mLoadedRejection);
838 }
839 }
840 }
841
GetUnicodeRangeAsCharacterMap()842 gfxCharacterMap* FontFace::GetUnicodeRangeAsCharacterMap() {
843 if (!mUnicodeRangeDirty) {
844 return mUnicodeRange;
845 }
846
847 size_t len;
848 const StyleUnicodeRange* rangesPtr =
849 Servo_FontFaceRule_GetUnicodeRanges(GetData(), &len);
850
851 Span<const StyleUnicodeRange> ranges(rangesPtr, len);
852 if (!ranges.IsEmpty()) {
853 RefPtr<gfxCharacterMap> charMap = new gfxCharacterMap();
854 for (auto& range : ranges) {
855 charMap->SetRange(range.start, range.end);
856 }
857 charMap->Compact();
858 // As it's common for multiple font resources to have the same
859 // unicode-range list, look for an existing copy of this map to share,
860 // or add this one to the sharing cache if not already present.
861 mUnicodeRange =
862 gfxPlatformFontList::PlatformFontList()->FindCharMap(charMap);
863 } else {
864 mUnicodeRange = nullptr;
865 }
866
867 mUnicodeRangeDirty = false;
868 return mUnicodeRange;
869 }
870
871 // -- FontFace::Entry --------------------------------------------------------
872
873 /* virtual */
SetLoadState(UserFontLoadState aLoadState)874 void FontFace::Entry::SetLoadState(UserFontLoadState aLoadState) {
875 gfxUserFontEntry::SetLoadState(aLoadState);
876
877 for (size_t i = 0; i < mFontFaces.Length(); i++) {
878 mFontFaces[i]->SetStatus(LoadStateToStatus(aLoadState));
879 }
880 }
881
882 /* virtual */
GetUserFontSets(nsTArray<gfxUserFontSet * > & aResult)883 void FontFace::Entry::GetUserFontSets(nsTArray<gfxUserFontSet*>& aResult) {
884 aResult.Clear();
885
886 for (FontFace* f : mFontFaces) {
887 if (f->mInFontFaceSet) {
888 aResult.AppendElement(f->mFontFaceSet->GetUserFontSet());
889 }
890 for (FontFaceSet* s : f->mOtherFontFaceSets) {
891 aResult.AppendElement(s->GetUserFontSet());
892 }
893 }
894
895 // Remove duplicates.
896 aResult.Sort();
897 auto it = std::unique(aResult.begin(), aResult.end());
898 aResult.TruncateLength(it - aResult.begin());
899 }
900
901 } // namespace dom
902 } // namespace mozilla
903