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/. */
7 #include "mozilla/dom/FontFace.h"
10 #include "mozilla/dom/CSSFontFaceRule.h"
11 #include "mozilla/dom/FontFaceBinding.h"
12 #include "mozilla/dom/FontFaceSet.h"
13 #include "mozilla/dom/Promise.h"
14 #include "mozilla/dom/TypedArray.h"
15 #include "mozilla/dom/UnionTypes.h"
16 #include "mozilla/CycleCollectedJSContext.h"
17 #include "mozilla/ServoBindings.h"
18 #include "mozilla/ServoCSSParser.h"
19 #include "mozilla/ServoStyleSet.h"
20 #include "mozilla/ServoUtils.h"
21 #include "mozilla/StaticPrefs_layout.h"
22 #include "mozilla/dom/Document.h"
23 #include "nsStyleUtil.h"
28 // -- FontFaceBufferSource ---------------------------------------------------
31 * An object that wraps a FontFace object and exposes its ArrayBuffer
32 * or ArrayBufferView data in a form the user font set can consume.
34 class FontFaceBufferSource
: public gfxFontFaceBufferSource
{
36 explicit FontFaceBufferSource(FontFace
* aFontFace
) : mFontFace(aFontFace
) {}
37 virtual void TakeBuffer(uint8_t*& aBuffer
, uint32_t& aLength
) override
;
40 RefPtr
<FontFace
> mFontFace
;
43 void FontFaceBufferSource::TakeBuffer(uint8_t*& aBuffer
, uint32_t& aLength
) {
45 "only call TakeBuffer once on a given "
46 "FontFaceBufferSource object");
47 mFontFace
->TakeBuffer(aBuffer
, aLength
);
51 // -- Utility functions ------------------------------------------------------
54 static void GetDataFrom(const T
& aObject
, uint8_t*& aBuffer
,
57 aObject
.ComputeState();
58 // We use malloc here rather than a FallibleTArray or fallible
59 // operator new[] since the gfxUserFontEntry will be calling free
61 aBuffer
= (uint8_t*)malloc(aObject
.Length());
65 memcpy((void*)aBuffer
, aObject
.Data(), aObject
.Length());
66 aLength
= aObject
.Length();
69 // -- FontFace ---------------------------------------------------------------
71 NS_IMPL_CYCLE_COLLECTION_CLASS(FontFace
)
73 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(FontFace
)
74 NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mParent
)
75 NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mLoaded
)
76 NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mFontFaceSet
)
77 NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mOtherFontFaceSets
)
78 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
80 NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(FontFace
)
81 NS_IMPL_CYCLE_COLLECTION_UNLINK(mParent
)
82 NS_IMPL_CYCLE_COLLECTION_UNLINK(mLoaded
)
83 NS_IMPL_CYCLE_COLLECTION_UNLINK(mFontFaceSet
)
84 tmp
->mInFontFaceSet
= false;
85 tmp
->SetUserFontEntry(nullptr);
86 NS_IMPL_CYCLE_COLLECTION_UNLINK(mOtherFontFaceSets
)
87 NS_IMPL_CYCLE_COLLECTION_UNLINK_PRESERVED_WRAPPER
88 NS_IMPL_CYCLE_COLLECTION_UNLINK_END
90 NS_IMPL_CYCLE_COLLECTION_TRACE_BEGIN(FontFace
)
91 NS_IMPL_CYCLE_COLLECTION_TRACE_PRESERVED_WRAPPER
92 NS_IMPL_CYCLE_COLLECTION_TRACE_END
94 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(FontFace
)
95 NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY
96 NS_INTERFACE_MAP_ENTRY(nsISupports
)
99 NS_IMPL_CYCLE_COLLECTING_ADDREF(FontFace
)
100 NS_IMPL_CYCLE_COLLECTING_RELEASE(FontFace
)
102 FontFace::FontFace(nsISupports
* aParent
, FontFaceSet
* aFontFaceSet
)
104 mLoadedRejection(NS_OK
),
105 mStatus(FontFaceLoadStatus::Unloaded
),
106 mSourceType(SourceType(0)),
107 mSourceBuffer(nullptr),
108 mSourceBufferLength(0),
109 mFontFaceSet(aFontFaceSet
),
110 mUnicodeRangeDirty(true),
111 mInFontFaceSet(false) {}
113 FontFace::~FontFace() {
114 // Assert that we don't drop any FontFace objects during a Servo traversal,
115 // since PostTraversalTask objects can hold raw pointers to FontFaces.
116 MOZ_ASSERT(!ServoStyleSet::IsInServoTraversal());
118 SetUserFontEntry(nullptr);
125 JSObject
* FontFace::WrapObject(JSContext
* aCx
,
126 JS::Handle
<JSObject
*> aGivenProto
) {
127 return FontFace_Binding::Wrap(aCx
, this, aGivenProto
);
130 static FontFaceLoadStatus
LoadStateToStatus(
131 gfxUserFontEntry::UserFontLoadState aLoadState
) {
132 switch (aLoadState
) {
133 case gfxUserFontEntry::UserFontLoadState::STATUS_NOT_LOADED
:
134 return FontFaceLoadStatus::Unloaded
;
135 case gfxUserFontEntry::UserFontLoadState::STATUS_LOAD_PENDING
:
136 case gfxUserFontEntry::UserFontLoadState::STATUS_LOADING
:
137 return FontFaceLoadStatus::Loading
;
138 case gfxUserFontEntry::UserFontLoadState::STATUS_LOADED
:
139 return FontFaceLoadStatus::Loaded
;
140 case gfxUserFontEntry::UserFontLoadState::STATUS_FAILED
:
141 return FontFaceLoadStatus::Error
;
143 MOZ_ASSERT_UNREACHABLE("invalid aLoadState value");
144 return FontFaceLoadStatus::Error
;
147 already_AddRefed
<FontFace
> FontFace::CreateForRule(
148 nsISupports
* aGlobal
, FontFaceSet
* aFontFaceSet
,
149 RawServoFontFaceRule
* aRule
) {
150 RefPtr
<FontFace
> obj
= new FontFace(aGlobal
, aFontFaceSet
);
152 obj
->mSourceType
= eSourceType_FontFaceRule
;
153 obj
->mInFontFaceSet
= true;
157 already_AddRefed
<FontFace
> FontFace::Constructor(
158 const GlobalObject
& aGlobal
, const nsAString
& aFamily
,
159 const StringOrArrayBufferOrArrayBufferView
& aSource
,
160 const FontFaceDescriptors
& aDescriptors
, ErrorResult
& aRv
) {
161 nsISupports
* global
= aGlobal
.GetAsSupports();
162 nsCOMPtr
<nsPIDOMWindowInner
> window
= do_QueryInterface(global
);
163 Document
* doc
= window
->GetDoc();
165 aRv
.Throw(NS_ERROR_FAILURE
);
169 RefPtr
<FontFace
> obj
= new FontFace(global
, doc
->Fonts());
170 if (!obj
->SetDescriptors(aFamily
, aDescriptors
)) {
174 obj
->InitializeSource(aSource
);
178 void FontFace::InitializeSource(
179 const StringOrArrayBufferOrArrayBufferView
& aSource
) {
180 if (aSource
.IsString()) {
181 IgnoredErrorResult rv
;
182 SetDescriptor(eCSSFontDesc_Src
, aSource
.GetAsString(), rv
);
184 Reject(NS_ERROR_DOM_SYNTAX_ERR
);
186 SetStatus(FontFaceLoadStatus::Error
);
190 mSourceType
= eSourceType_URLs
;
194 mSourceType
= FontFace::eSourceType_Buffer
;
196 if (aSource
.IsArrayBuffer()) {
197 GetDataFrom(aSource
.GetAsArrayBuffer(), mSourceBuffer
, mSourceBufferLength
);
199 MOZ_ASSERT(aSource
.IsArrayBufferView());
200 GetDataFrom(aSource
.GetAsArrayBufferView(), mSourceBuffer
,
201 mSourceBufferLength
);
204 SetStatus(FontFaceLoadStatus::Loading
);
208 void FontFace::GetFamily(nsString
& aResult
) {
209 mFontFaceSet
->FlushUserFontSet();
210 GetDesc(eCSSFontDesc_Family
, aResult
);
213 void FontFace::SetFamily(const nsAString
& aValue
, ErrorResult
& aRv
) {
214 mFontFaceSet
->FlushUserFontSet();
215 if (SetDescriptor(eCSSFontDesc_Family
, aValue
, aRv
)) {
220 void FontFace::GetStyle(nsString
& aResult
) {
221 mFontFaceSet
->FlushUserFontSet();
222 GetDesc(eCSSFontDesc_Style
, aResult
);
225 void FontFace::SetStyle(const nsAString
& aValue
, ErrorResult
& aRv
) {
226 mFontFaceSet
->FlushUserFontSet();
227 if (SetDescriptor(eCSSFontDesc_Style
, aValue
, aRv
)) {
232 void FontFace::GetWeight(nsString
& aResult
) {
233 mFontFaceSet
->FlushUserFontSet();
234 GetDesc(eCSSFontDesc_Weight
, aResult
);
237 void FontFace::SetWeight(const nsAString
& aValue
, ErrorResult
& aRv
) {
238 mFontFaceSet
->FlushUserFontSet();
239 if (SetDescriptor(eCSSFontDesc_Weight
, aValue
, aRv
)) {
244 void FontFace::GetStretch(nsString
& aResult
) {
245 mFontFaceSet
->FlushUserFontSet();
246 GetDesc(eCSSFontDesc_Stretch
, aResult
);
249 void FontFace::SetStretch(const nsAString
& aValue
, ErrorResult
& aRv
) {
250 mFontFaceSet
->FlushUserFontSet();
251 if (SetDescriptor(eCSSFontDesc_Stretch
, aValue
, aRv
)) {
256 void FontFace::GetUnicodeRange(nsString
& aResult
) {
257 mFontFaceSet
->FlushUserFontSet();
258 GetDesc(eCSSFontDesc_UnicodeRange
, aResult
);
261 void FontFace::SetUnicodeRange(const nsAString
& aValue
, ErrorResult
& aRv
) {
262 mFontFaceSet
->FlushUserFontSet();
263 if (SetDescriptor(eCSSFontDesc_UnicodeRange
, aValue
, aRv
)) {
268 void FontFace::GetVariant(nsString
& aResult
) {
269 mFontFaceSet
->FlushUserFontSet();
271 // XXX Just expose the font-variant descriptor as "normal" until we
272 // support it properly (bug 1055385).
273 aResult
.AssignLiteral("normal");
276 void FontFace::SetVariant(const nsAString
& aValue
, ErrorResult
& aRv
) {
277 mFontFaceSet
->FlushUserFontSet();
279 // XXX Ignore assignments to variant until we support font-variant
280 // descriptors (bug 1055385).
283 void FontFace::GetFeatureSettings(nsString
& aResult
) {
284 mFontFaceSet
->FlushUserFontSet();
285 GetDesc(eCSSFontDesc_FontFeatureSettings
, aResult
);
288 void FontFace::SetFeatureSettings(const nsAString
& aValue
, ErrorResult
& aRv
) {
289 mFontFaceSet
->FlushUserFontSet();
290 if (SetDescriptor(eCSSFontDesc_FontFeatureSettings
, aValue
, aRv
)) {
295 void FontFace::GetVariationSettings(nsString
& aResult
) {
296 mFontFaceSet
->FlushUserFontSet();
297 GetDesc(eCSSFontDesc_FontVariationSettings
, aResult
);
300 void FontFace::SetVariationSettings(const nsAString
& aValue
, ErrorResult
& aRv
) {
301 mFontFaceSet
->FlushUserFontSet();
302 if (SetDescriptor(eCSSFontDesc_FontVariationSettings
, aValue
, aRv
)) {
307 void FontFace::GetDisplay(nsString
& aResult
) {
308 mFontFaceSet
->FlushUserFontSet();
309 GetDesc(eCSSFontDesc_Display
, aResult
);
312 void FontFace::SetDisplay(const nsAString
& aValue
, ErrorResult
& aRv
) {
313 mFontFaceSet
->FlushUserFontSet();
314 if (SetDescriptor(eCSSFontDesc_Display
, aValue
, aRv
)) {
319 void FontFace::DescriptorUpdated() {
320 // If we haven't yet initialized mUserFontEntry, no need to do anything here;
321 // we'll respect the updated descriptor when the time comes to create it.
322 if (!mUserFontEntry
) {
326 // Behind the scenes, this will actually update the existing entry and return
327 // it, rather than create a new one.
328 RefPtr
<gfxUserFontEntry
> newEntry
=
329 mFontFaceSet
->FindOrCreateUserFontEntryFromFontFace(this);
330 SetUserFontEntry(newEntry
);
332 if (mInFontFaceSet
) {
333 mFontFaceSet
->MarkUserFontSetDirty();
335 for (auto& set
: mOtherFontFaceSets
) {
336 set
->MarkUserFontSetDirty();
340 FontFaceLoadStatus
FontFace::Status() { return mStatus
; }
342 Promise
* FontFace::Load(ErrorResult
& aRv
) {
343 MOZ_ASSERT(NS_IsMainThread());
345 mFontFaceSet
->FlushUserFontSet();
350 aRv
.Throw(NS_ERROR_FAILURE
);
354 // Calling Load on a FontFace constructed with an ArrayBuffer data source,
355 // or on one that is already loading (or has finished loading), has no
357 if (mSourceType
== eSourceType_Buffer
||
358 mStatus
!= FontFaceLoadStatus::Unloaded
) {
362 // Calling the user font entry's Load method will end up setting our
363 // status to Loading, but the spec requires us to set it to Loading
365 SetStatus(FontFaceLoadStatus::Loading
);
372 gfxUserFontEntry
* FontFace::CreateUserFontEntry() {
373 if (!mUserFontEntry
) {
374 MOZ_ASSERT(!HasRule(),
375 "Rule backed FontFace objects should already have a user font "
376 "entry by the time Load() can be called on them");
378 RefPtr
<gfxUserFontEntry
> newEntry
=
379 mFontFaceSet
->FindOrCreateUserFontEntryFromFontFace(this);
381 SetUserFontEntry(newEntry
);
385 return mUserFontEntry
;
388 void FontFace::DoLoad() {
389 if (!CreateUserFontEntry()) {
392 mUserFontEntry
->Load();
395 Promise
* FontFace::GetLoaded(ErrorResult
& aRv
) {
396 MOZ_ASSERT(NS_IsMainThread());
398 mFontFaceSet
->FlushUserFontSet();
403 aRv
.Throw(NS_ERROR_FAILURE
);
410 void FontFace::SetStatus(FontFaceLoadStatus aStatus
) {
411 AssertIsMainThreadOrServoFontMetricsLocked();
413 if (mStatus
== aStatus
) {
417 if (aStatus
< mStatus
) {
418 // We're being asked to go backwards in status! Normally, this shouldn't
419 // happen. But it can if the FontFace had a user font entry that had
420 // loaded, but then was given a new one by FontFaceSet::InsertRuleFontFace
421 // if we used a local() rule. For now, just ignore the request to
422 // go backwards in status.
428 if (mInFontFaceSet
) {
429 mFontFaceSet
->OnFontFaceStatusChanged(this);
432 for (FontFaceSet
* otherSet
: mOtherFontFaceSets
) {
433 otherSet
->OnFontFaceStatusChanged(this);
436 if (mStatus
== FontFaceLoadStatus::Loaded
) {
440 } else if (mStatus
== FontFaceLoadStatus::Error
) {
441 if (mSourceType
== eSourceType_Buffer
) {
442 Reject(NS_ERROR_DOM_SYNTAX_ERR
);
444 Reject(NS_ERROR_DOM_NETWORK_ERR
);
449 void FontFace::DoResolve() {
450 AssertIsMainThreadOrServoFontMetricsLocked();
452 if (ServoStyleSet
* ss
= ServoStyleSet::Current()) {
453 // See comments in Gecko_GetFontMetrics.
454 ss
->AppendTask(PostTraversalTask::ResolveFontFaceLoadedPromise(this));
458 mLoaded
->MaybeResolve(this);
461 void FontFace::DoReject(nsresult aResult
) {
462 AssertIsMainThreadOrServoFontMetricsLocked();
464 if (ServoStyleSet
* ss
= ServoStyleSet::Current()) {
465 // See comments in Gecko_GetFontMetrics.
467 PostTraversalTask::RejectFontFaceLoadedPromise(this, aResult
));
471 mLoaded
->MaybeReject(aResult
);
474 already_AddRefed
<URLExtraData
> FontFace::GetURLExtraData() const {
475 nsCOMPtr
<nsIGlobalObject
> global
= do_QueryInterface(mParent
);
476 nsCOMPtr
<nsIPrincipal
> principal
= global
->PrincipalOrNull();
478 nsCOMPtr
<nsPIDOMWindowInner
> window
= do_QueryInterface(mParent
);
479 nsCOMPtr
<nsIURI
> docURI
= window
->GetDocumentURI();
480 nsCOMPtr
<nsIURI
> base
= window
->GetDocBaseURI();
482 // We pass RP_Unset when creating ReferrerInfo object here because it's not
483 // going to result to change referer policy in a resource request.
484 nsCOMPtr
<nsIReferrerInfo
> referrerInfo
=
485 new ReferrerInfo(docURI
, ReferrerPolicy::_empty
);
487 RefPtr
<URLExtraData
> url
= new URLExtraData(base
, referrerInfo
, principal
);
491 // Boolean result indicates whether the value of the descriptor was actually
493 bool FontFace::SetDescriptor(nsCSSFontDesc aFontDesc
, const nsAString
& aValue
,
495 // FIXME We probably don't need to distinguish between this anymore
496 // since we have common backend now.
497 NS_ASSERTION(!HasRule(), "we don't handle rule backed FontFace objects yet");
502 // FIXME(heycam): Should not allow modification of FontFaces that are
503 // CSS-connected and whose rule is read only.
505 NS_ConvertUTF16toUTF8
value(aValue
);
506 RefPtr
<URLExtraData
> url
= GetURLExtraData();
508 if (!Servo_FontFaceRule_SetDescriptor(GetData(), aFontDesc
, &value
, url
,
510 aRv
.ThrowSyntaxError("Invalid font descriptor");
518 if (aFontDesc
== eCSSFontDesc_UnicodeRange
) {
519 mUnicodeRangeDirty
= true;
525 bool FontFace::SetDescriptors(const nsAString
& aFamily
,
526 const FontFaceDescriptors
& aDescriptors
) {
527 MOZ_ASSERT(!HasRule());
528 MOZ_ASSERT(!mDescriptors
);
530 mDescriptors
= Servo_FontFaceRule_CreateEmpty().Consume();
532 // Helper to call SetDescriptor and return true on success, false on failure.
533 auto setDesc
= [=](nsCSSFontDesc aDesc
, const nsAString
& aVal
) -> bool {
534 IgnoredErrorResult rv
;
535 SetDescriptor(aDesc
, aVal
, rv
);
539 // Parse all of the mDescriptors in aInitializer, which are the values
540 // we got from the JS constructor.
541 if (!setDesc(eCSSFontDesc_Family
, aFamily
) ||
542 !setDesc(eCSSFontDesc_Style
, aDescriptors
.mStyle
) ||
543 !setDesc(eCSSFontDesc_Weight
, aDescriptors
.mWeight
) ||
544 !setDesc(eCSSFontDesc_Stretch
, aDescriptors
.mStretch
) ||
545 !setDesc(eCSSFontDesc_UnicodeRange
, aDescriptors
.mUnicodeRange
) ||
546 !setDesc(eCSSFontDesc_FontFeatureSettings
,
547 aDescriptors
.mFeatureSettings
) ||
548 (StaticPrefs::layout_css_font_variations_enabled() &&
549 !setDesc(eCSSFontDesc_FontVariationSettings
,
550 aDescriptors
.mVariationSettings
)) ||
551 !setDesc(eCSSFontDesc_Display
, aDescriptors
.mDisplay
)) {
552 // XXX Handle font-variant once we support it (bug 1055385).
554 // If any of the descriptors failed to parse, none of them should be set
556 mDescriptors
= Servo_FontFaceRule_CreateEmpty().Consume();
558 Reject(NS_ERROR_DOM_SYNTAX_ERR
);
560 SetStatus(FontFaceLoadStatus::Error
);
567 void FontFace::GetDesc(nsCSSFontDesc aDescID
, nsString
& aResult
) const {
569 Servo_FontFaceRule_GetDescriptorCssText(GetData(), aDescID
, &aResult
);
571 // Fill in a default value for missing descriptors.
572 if (aResult
.IsEmpty()) {
573 if (aDescID
== eCSSFontDesc_UnicodeRange
) {
574 aResult
.AssignLiteral("U+0-10FFFF");
575 } else if (aDescID
== eCSSFontDesc_Display
) {
576 aResult
.AssignLiteral("auto");
577 } else if (aDescID
!= eCSSFontDesc_Family
&& aDescID
!= eCSSFontDesc_Src
) {
578 aResult
.AssignLiteral("normal");
583 void FontFace::SetUserFontEntry(gfxUserFontEntry
* aEntry
) {
584 if (mUserFontEntry
) {
585 mUserFontEntry
->mFontFaces
.RemoveElement(this);
588 mUserFontEntry
= static_cast<Entry
*>(aEntry
);
589 if (mUserFontEntry
) {
590 mUserFontEntry
->mFontFaces
.AppendElement(this);
593 mUserFontEntry
->GetUserFontSet() == mFontFaceSet
->GetUserFontSet(),
594 "user font entry must be associated with the same user font set "
597 // Our newly assigned user font entry might be in the process of or
598 // finished loading, so set our status accordingly. But only do so
599 // if we're not going "backwards" in status, which could otherwise
600 // happen in this case:
602 // new FontFace("ABC", "url(x)").load();
604 // where the SetUserFontEntry call (from the after-initialization
605 // DoLoad call) comes after the author's call to load(), which set mStatus
607 FontFaceLoadStatus newStatus
=
608 LoadStateToStatus(mUserFontEntry
->LoadState());
609 if (newStatus
> mStatus
) {
610 SetStatus(newStatus
);
615 Maybe
<StyleComputedFontWeightRange
> FontFace::GetFontWeight() const {
616 StyleComputedFontWeightRange range
;
617 if (!Servo_FontFaceRule_GetFontWeight(GetData(), &range
)) {
623 Maybe
<StyleComputedFontStretchRange
> FontFace::GetFontStretch() const {
624 StyleComputedFontStretchRange range
;
625 if (!Servo_FontFaceRule_GetFontStretch(GetData(), &range
)) {
631 Maybe
<StyleComputedFontStyleDescriptor
> FontFace::GetFontStyle() const {
632 auto descriptor
= StyleComputedFontStyleDescriptor::Normal();
633 if (!Servo_FontFaceRule_GetFontStyle(GetData(), &descriptor
)) {
636 return Some(descriptor
);
639 Maybe
<StyleFontDisplay
> FontFace::GetFontDisplay() const {
640 StyleFontDisplay display
;
641 if (!Servo_FontFaceRule_GetFontDisplay(GetData(), &display
)) {
644 return Some(display
);
647 Maybe
<StyleFontLanguageOverride
> FontFace::GetFontLanguageOverride() const {
648 StyleFontLanguageOverride langOverride
;
649 if (!Servo_FontFaceRule_GetFontLanguageOverride(GetData(), &langOverride
)) {
652 return Some(langOverride
);
655 bool FontFace::HasLocalSrc() const {
656 AutoTArray
<StyleFontFaceSourceListComponent
, 8> components
;
657 GetSources(components
);
658 for (auto& component
: components
) {
659 if (component
.tag
== StyleFontFaceSourceListComponent::Tag::Local
) {
666 void FontFace::GetFontFeatureSettings(
667 nsTArray
<gfxFontFeature
>& aFeatures
) const {
668 Servo_FontFaceRule_GetFeatureSettings(GetData(), &aFeatures
);
671 void FontFace::GetFontVariationSettings(
672 nsTArray
<gfxFontVariation
>& aVariations
) const {
673 Servo_FontFaceRule_GetVariationSettings(GetData(), &aVariations
);
676 void FontFace::GetSources(
677 nsTArray
<StyleFontFaceSourceListComponent
>& aSources
) const {
678 Servo_FontFaceRule_GetSources(GetData(), &aSources
);
681 nsAtom
* FontFace::GetFamilyName() const {
682 return Servo_FontFaceRule_GetFamilyName(GetData());
685 void FontFace::DisconnectFromRule() {
686 MOZ_ASSERT(HasRule());
688 // Make a copy of the descriptors.
689 mDescriptors
= Servo_FontFaceRule_Clone(mRule
).Consume();
691 mInFontFaceSet
= false;
694 bool FontFace::HasFontData() const {
695 return mSourceType
== eSourceType_Buffer
&& mSourceBuffer
;
698 void FontFace::TakeBuffer(uint8_t*& aBuffer
, uint32_t& aLength
) {
699 MOZ_ASSERT(HasFontData());
701 aBuffer
= mSourceBuffer
;
702 aLength
= mSourceBufferLength
;
704 mSourceBuffer
= nullptr;
705 mSourceBufferLength
= 0;
708 already_AddRefed
<gfxFontFaceBufferSource
> FontFace::CreateBufferSource() {
709 RefPtr
<FontFaceBufferSource
> bufferSource
= new FontFaceBufferSource(this);
710 return bufferSource
.forget();
713 bool FontFace::IsInFontFaceSet(FontFaceSet
* aFontFaceSet
) const {
714 if (mFontFaceSet
== aFontFaceSet
) {
715 return mInFontFaceSet
;
717 return mOtherFontFaceSets
.Contains(aFontFaceSet
);
720 void FontFace::AddFontFaceSet(FontFaceSet
* aFontFaceSet
) {
721 MOZ_ASSERT(!IsInFontFaceSet(aFontFaceSet
));
723 if (mFontFaceSet
== aFontFaceSet
) {
724 mInFontFaceSet
= true;
726 mOtherFontFaceSets
.AppendElement(aFontFaceSet
);
730 void FontFace::RemoveFontFaceSet(FontFaceSet
* aFontFaceSet
) {
731 MOZ_ASSERT(IsInFontFaceSet(aFontFaceSet
));
733 if (mFontFaceSet
== aFontFaceSet
) {
734 mInFontFaceSet
= false;
736 mOtherFontFaceSets
.RemoveElement(aFontFaceSet
);
740 void FontFace::Reject(nsresult aResult
) {
741 AssertIsMainThreadOrServoFontMetricsLocked();
745 } else if (mLoadedRejection
== NS_OK
) {
746 mLoadedRejection
= aResult
;
750 void FontFace::EnsurePromise() {
751 MOZ_ASSERT(NS_IsMainThread());
757 nsCOMPtr
<nsIGlobalObject
> global
= do_QueryInterface(mParent
);
759 // If the pref is not set, don't create the Promise (which the page wouldn't
760 // be able to get to anyway) as it causes the window.FontFace constructor
762 if (global
&& FontFaceSet::PrefEnabled()) {
764 mLoaded
= Promise::Create(global
, rv
);
766 if (mStatus
== FontFaceLoadStatus::Loaded
) {
767 mLoaded
->MaybeResolve(this);
768 } else if (mLoadedRejection
!= NS_OK
) {
769 mLoaded
->MaybeReject(mLoadedRejection
);
774 gfxCharacterMap
* FontFace::GetUnicodeRangeAsCharacterMap() {
775 if (!mUnicodeRangeDirty
) {
776 return mUnicodeRange
;
780 const StyleUnicodeRange
* rangesPtr
=
781 Servo_FontFaceRule_GetUnicodeRanges(GetData(), &len
);
783 Span
<const StyleUnicodeRange
> ranges(rangesPtr
, len
);
784 if (!ranges
.IsEmpty()) {
785 mUnicodeRange
= new gfxCharacterMap();
786 for (auto& range
: ranges
) {
787 mUnicodeRange
->SetRange(range
.start
, range
.end
);
790 mUnicodeRange
= nullptr;
793 mUnicodeRangeDirty
= false;
794 return mUnicodeRange
;
797 // -- FontFace::Entry --------------------------------------------------------
800 void FontFace::Entry::SetLoadState(UserFontLoadState aLoadState
) {
801 gfxUserFontEntry::SetLoadState(aLoadState
);
803 for (size_t i
= 0; i
< mFontFaces
.Length(); i
++) {
804 mFontFaces
[i
]->SetStatus(LoadStateToStatus(aLoadState
));
809 void FontFace::Entry::GetUserFontSets(nsTArray
<gfxUserFontSet
*>& aResult
) {
812 for (FontFace
* f
: mFontFaces
) {
813 if (f
->mInFontFaceSet
) {
814 aResult
.AppendElement(f
->mFontFaceSet
->GetUserFontSet());
816 for (FontFaceSet
* s
: f
->mOtherFontFaceSets
) {
817 aResult
.AppendElement(s
->GetUserFontSet());
821 // Remove duplicates.
823 auto it
= std::unique(aResult
.begin(), aResult
.end());
824 aResult
.TruncateLength(it
- aResult
.begin());
828 } // namespace mozilla