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