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 nsACString
& aFamily
,
159 const UTF8StringOrArrayBufferOrArrayBufferView
& 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 UTF8StringOrArrayBufferOrArrayBufferView
& aSource
) {
180 if (aSource
.IsUTF8String()) {
181 IgnoredErrorResult rv
;
182 SetDescriptor(eCSSFontDesc_Src
, aSource
.GetAsUTF8String(), 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(nsACString
& aResult
) {
209 GetDesc(eCSSFontDesc_Family
, aResult
);
212 void FontFace::SetFamily(const nsACString
& aValue
, ErrorResult
& aRv
) {
213 mFontFaceSet
->FlushUserFontSet();
214 if (SetDescriptor(eCSSFontDesc_Family
, aValue
, aRv
)) {
219 void FontFace::GetStyle(nsACString
& aResult
) {
220 GetDesc(eCSSFontDesc_Style
, aResult
);
223 void FontFace::SetStyle(const nsACString
& aValue
, ErrorResult
& aRv
) {
224 if (SetDescriptor(eCSSFontDesc_Style
, aValue
, aRv
)) {
229 void FontFace::GetWeight(nsACString
& aResult
) {
230 GetDesc(eCSSFontDesc_Weight
, aResult
);
233 void FontFace::SetWeight(const nsACString
& aValue
, ErrorResult
& aRv
) {
234 mFontFaceSet
->FlushUserFontSet();
235 if (SetDescriptor(eCSSFontDesc_Weight
, aValue
, aRv
)) {
240 void FontFace::GetStretch(nsACString
& aResult
) {
241 GetDesc(eCSSFontDesc_Stretch
, aResult
);
244 void FontFace::SetStretch(const nsACString
& aValue
, ErrorResult
& aRv
) {
245 mFontFaceSet
->FlushUserFontSet();
246 if (SetDescriptor(eCSSFontDesc_Stretch
, aValue
, aRv
)) {
251 void FontFace::GetUnicodeRange(nsACString
& aResult
) {
252 GetDesc(eCSSFontDesc_UnicodeRange
, aResult
);
255 void FontFace::SetUnicodeRange(const nsACString
& aValue
, ErrorResult
& aRv
) {
256 mFontFaceSet
->FlushUserFontSet();
257 if (SetDescriptor(eCSSFontDesc_UnicodeRange
, aValue
, aRv
)) {
262 void FontFace::GetVariant(nsACString
& aResult
) {
263 // XXX Just expose the font-variant descriptor as "normal" until we
264 // support it properly (bug 1055385).
265 aResult
.AssignLiteral("normal");
268 void FontFace::SetVariant(const nsACString
& aValue
, ErrorResult
& aRv
) {
269 // XXX Ignore assignments to variant until we support font-variant
270 // descriptors (bug 1055385).
273 void FontFace::GetFeatureSettings(nsACString
& aResult
) {
274 GetDesc(eCSSFontDesc_FontFeatureSettings
, aResult
);
277 void FontFace::SetFeatureSettings(const nsACString
& aValue
, ErrorResult
& aRv
) {
278 mFontFaceSet
->FlushUserFontSet();
279 if (SetDescriptor(eCSSFontDesc_FontFeatureSettings
, aValue
, aRv
)) {
284 void FontFace::GetVariationSettings(nsACString
& aResult
) {
285 GetDesc(eCSSFontDesc_FontVariationSettings
, aResult
);
288 void FontFace::SetVariationSettings(const nsACString
& aValue
,
290 mFontFaceSet
->FlushUserFontSet();
291 if (SetDescriptor(eCSSFontDesc_FontVariationSettings
, aValue
, aRv
)) {
296 void FontFace::GetDisplay(nsACString
& aResult
) {
297 GetDesc(eCSSFontDesc_Display
, aResult
);
300 void FontFace::SetDisplay(const nsACString
& aValue
, ErrorResult
& aRv
) {
301 if (SetDescriptor(eCSSFontDesc_Display
, aValue
, aRv
)) {
306 void FontFace::GetAscentOverride(nsACString
& aResult
) {
307 GetDesc(eCSSFontDesc_AscentOverride
, aResult
);
310 void FontFace::SetAscentOverride(const nsACString
& aValue
, ErrorResult
& aRv
) {
311 if (SetDescriptor(eCSSFontDesc_AscentOverride
, aValue
, aRv
)) {
316 void FontFace::GetDescentOverride(nsACString
& aResult
) {
317 GetDesc(eCSSFontDesc_DescentOverride
, aResult
);
320 void FontFace::SetDescentOverride(const nsACString
& aValue
, ErrorResult
& aRv
) {
321 if (SetDescriptor(eCSSFontDesc_DescentOverride
, aValue
, aRv
)) {
326 void FontFace::GetLineGapOverride(nsACString
& aResult
) {
327 GetDesc(eCSSFontDesc_LineGapOverride
, aResult
);
330 void FontFace::SetLineGapOverride(const nsACString
& aValue
, ErrorResult
& aRv
) {
331 if (SetDescriptor(eCSSFontDesc_LineGapOverride
, aValue
, aRv
)) {
336 void FontFace::GetSizeAdjust(nsACString
& aResult
) {
337 GetDesc(eCSSFontDesc_SizeAdjust
, aResult
);
340 void FontFace::SetSizeAdjust(const nsACString
& aValue
, ErrorResult
& aRv
) {
341 if (SetDescriptor(eCSSFontDesc_SizeAdjust
, aValue
, aRv
)) {
346 void FontFace::DescriptorUpdated() {
347 // If we haven't yet initialized mUserFontEntry, no need to do anything here;
348 // we'll respect the updated descriptor when the time comes to create it.
349 if (!mUserFontEntry
) {
353 // Behind the scenes, this will actually update the existing entry and return
354 // it, rather than create a new one.
355 RefPtr
<gfxUserFontEntry
> newEntry
=
356 mFontFaceSet
->FindOrCreateUserFontEntryFromFontFace(this);
357 SetUserFontEntry(newEntry
);
359 if (mInFontFaceSet
) {
360 mFontFaceSet
->MarkUserFontSetDirty();
362 for (auto& set
: mOtherFontFaceSets
) {
363 set
->MarkUserFontSetDirty();
367 FontFaceLoadStatus
FontFace::Status() { return mStatus
; }
369 Promise
* FontFace::Load(ErrorResult
& aRv
) {
370 MOZ_ASSERT(NS_IsMainThread());
372 mFontFaceSet
->FlushUserFontSet();
377 aRv
.Throw(NS_ERROR_FAILURE
);
381 // Calling Load on a FontFace constructed with an ArrayBuffer data source,
382 // or on one that is already loading (or has finished loading), has no
384 if (mSourceType
== eSourceType_Buffer
||
385 mStatus
!= FontFaceLoadStatus::Unloaded
) {
389 // Calling the user font entry's Load method will end up setting our
390 // status to Loading, but the spec requires us to set it to Loading
392 SetStatus(FontFaceLoadStatus::Loading
);
399 gfxUserFontEntry
* FontFace::CreateUserFontEntry() {
400 if (!mUserFontEntry
) {
401 MOZ_ASSERT(!HasRule(),
402 "Rule backed FontFace objects should already have a user font "
403 "entry by the time Load() can be called on them");
405 RefPtr
<gfxUserFontEntry
> newEntry
=
406 mFontFaceSet
->FindOrCreateUserFontEntryFromFontFace(this);
408 SetUserFontEntry(newEntry
);
412 return mUserFontEntry
;
415 void FontFace::DoLoad() {
416 if (!CreateUserFontEntry()) {
419 mUserFontEntry
->Load();
422 Promise
* FontFace::GetLoaded(ErrorResult
& aRv
) {
423 MOZ_ASSERT(NS_IsMainThread());
428 aRv
.Throw(NS_ERROR_FAILURE
);
435 void FontFace::SetStatus(FontFaceLoadStatus aStatus
) {
436 AssertIsMainThreadOrServoFontMetricsLocked();
438 if (mStatus
== aStatus
) {
442 if (aStatus
< mStatus
) {
443 // We're being asked to go backwards in status! Normally, this shouldn't
444 // happen. But it can if the FontFace had a user font entry that had
445 // loaded, but then was given a new one by FontFaceSet::InsertRuleFontFace
446 // if we used a local() rule. For now, just ignore the request to
447 // go backwards in status.
453 if (mInFontFaceSet
) {
454 mFontFaceSet
->OnFontFaceStatusChanged(this);
457 for (FontFaceSet
* otherSet
: mOtherFontFaceSets
) {
458 otherSet
->OnFontFaceStatusChanged(this);
461 if (mStatus
== FontFaceLoadStatus::Loaded
) {
465 } else if (mStatus
== FontFaceLoadStatus::Error
) {
466 if (mSourceType
== eSourceType_Buffer
) {
467 Reject(NS_ERROR_DOM_SYNTAX_ERR
);
469 Reject(NS_ERROR_DOM_NETWORK_ERR
);
474 void FontFace::DoResolve() {
475 AssertIsMainThreadOrServoFontMetricsLocked();
477 if (ServoStyleSet
* ss
= ServoStyleSet::Current()) {
478 // See comments in Gecko_GetFontMetrics.
479 ss
->AppendTask(PostTraversalTask::ResolveFontFaceLoadedPromise(this));
483 mLoaded
->MaybeResolve(this);
486 void FontFace::DoReject(nsresult aResult
) {
487 AssertIsMainThreadOrServoFontMetricsLocked();
489 if (ServoStyleSet
* ss
= ServoStyleSet::Current()) {
490 // See comments in Gecko_GetFontMetrics.
492 PostTraversalTask::RejectFontFaceLoadedPromise(this, aResult
));
496 mLoaded
->MaybeReject(aResult
);
499 already_AddRefed
<URLExtraData
> FontFace::GetURLExtraData() const {
500 nsCOMPtr
<nsIGlobalObject
> global
= do_QueryInterface(mParent
);
501 nsCOMPtr
<nsIPrincipal
> principal
= global
->PrincipalOrNull();
503 nsCOMPtr
<nsPIDOMWindowInner
> window
= do_QueryInterface(mParent
);
504 nsCOMPtr
<nsIURI
> docURI
= window
->GetDocumentURI();
505 nsCOMPtr
<nsIURI
> base
= window
->GetDocBaseURI();
507 // We pass RP_Unset when creating ReferrerInfo object here because it's not
508 // going to result to change referer policy in a resource request.
509 nsCOMPtr
<nsIReferrerInfo
> referrerInfo
=
510 new ReferrerInfo(docURI
, ReferrerPolicy::_empty
);
512 RefPtr
<URLExtraData
> url
= new URLExtraData(base
, referrerInfo
, principal
);
516 // Boolean result indicates whether the value of the descriptor was actually
518 bool FontFace::SetDescriptor(nsCSSFontDesc aFontDesc
, const nsACString
& aValue
,
520 // FIXME We probably don't need to distinguish between this anymore
521 // since we have common backend now.
522 NS_ASSERTION(!HasRule(), "we don't handle rule backed FontFace objects yet");
527 // FIXME(heycam): Should not allow modification of FontFaces that are
528 // CSS-connected and whose rule is read only.
529 RefPtr
<URLExtraData
> url
= GetURLExtraData();
531 if (!Servo_FontFaceRule_SetDescriptor(GetData(), aFontDesc
, &aValue
, url
,
533 aRv
.ThrowSyntaxError("Invalid font descriptor");
541 if (aFontDesc
== eCSSFontDesc_UnicodeRange
) {
542 mUnicodeRangeDirty
= true;
548 bool FontFace::SetDescriptors(const nsACString
& aFamily
,
549 const FontFaceDescriptors
& aDescriptors
) {
550 MOZ_ASSERT(!HasRule());
551 MOZ_ASSERT(!mDescriptors
);
553 mDescriptors
= Servo_FontFaceRule_CreateEmpty().Consume();
555 // Helper to call SetDescriptor and return true on success, false on failure.
556 auto setDesc
= [=](nsCSSFontDesc aDesc
, const nsACString
& aVal
) -> bool {
557 IgnoredErrorResult rv
;
558 SetDescriptor(aDesc
, aVal
, rv
);
562 // Parse all of the mDescriptors in aInitializer, which are the values
563 // we got from the JS constructor.
564 if (!setDesc(eCSSFontDesc_Family
, aFamily
) ||
565 !setDesc(eCSSFontDesc_Style
, aDescriptors
.mStyle
) ||
566 !setDesc(eCSSFontDesc_Weight
, aDescriptors
.mWeight
) ||
567 !setDesc(eCSSFontDesc_Stretch
, aDescriptors
.mStretch
) ||
568 !setDesc(eCSSFontDesc_UnicodeRange
, aDescriptors
.mUnicodeRange
) ||
569 !setDesc(eCSSFontDesc_FontFeatureSettings
,
570 aDescriptors
.mFeatureSettings
) ||
571 (StaticPrefs::layout_css_font_variations_enabled() &&
572 !setDesc(eCSSFontDesc_FontVariationSettings
,
573 aDescriptors
.mVariationSettings
)) ||
574 !setDesc(eCSSFontDesc_Display
, aDescriptors
.mDisplay
) ||
575 (StaticPrefs::layout_css_font_metrics_overrides_enabled() &&
576 (!setDesc(eCSSFontDesc_AscentOverride
, aDescriptors
.mAscentOverride
) ||
577 !setDesc(eCSSFontDesc_DescentOverride
, aDescriptors
.mDescentOverride
) ||
578 !setDesc(eCSSFontDesc_LineGapOverride
,
579 aDescriptors
.mLineGapOverride
))) ||
580 (StaticPrefs::layout_css_size_adjust_enabled() &&
581 !setDesc(eCSSFontDesc_SizeAdjust
, aDescriptors
.mSizeAdjust
))) {
582 // XXX Handle font-variant once we support it (bug 1055385).
584 // If any of the descriptors failed to parse, none of them should be set
586 mDescriptors
= Servo_FontFaceRule_CreateEmpty().Consume();
588 Reject(NS_ERROR_DOM_SYNTAX_ERR
);
590 SetStatus(FontFaceLoadStatus::Error
);
597 void FontFace::GetDesc(nsCSSFontDesc aDescID
, nsACString
& aResult
) const {
599 Servo_FontFaceRule_GetDescriptorCssText(GetData(), aDescID
, &aResult
);
601 // Fill in a default value for missing descriptors.
602 if (aResult
.IsEmpty()) {
603 if (aDescID
== eCSSFontDesc_UnicodeRange
) {
604 aResult
.AssignLiteral("U+0-10FFFF");
605 } else if (aDescID
== eCSSFontDesc_Display
) {
606 aResult
.AssignLiteral("auto");
607 } else if (aDescID
!= eCSSFontDesc_Family
&& aDescID
!= eCSSFontDesc_Src
) {
608 aResult
.AssignLiteral("normal");
613 void FontFace::SetUserFontEntry(gfxUserFontEntry
* aEntry
) {
614 if (mUserFontEntry
) {
615 mUserFontEntry
->mFontFaces
.RemoveElement(this);
618 mUserFontEntry
= static_cast<Entry
*>(aEntry
);
619 if (mUserFontEntry
) {
620 mUserFontEntry
->mFontFaces
.AppendElement(this);
623 mUserFontEntry
->GetUserFontSet() == mFontFaceSet
->GetUserFontSet(),
624 "user font entry must be associated with the same user font set "
627 // Our newly assigned user font entry might be in the process of or
628 // finished loading, so set our status accordingly. But only do so
629 // if we're not going "backwards" in status, which could otherwise
630 // happen in this case:
632 // new FontFace("ABC", "url(x)").load();
634 // where the SetUserFontEntry call (from the after-initialization
635 // DoLoad call) comes after the author's call to load(), which set mStatus
637 FontFaceLoadStatus newStatus
=
638 LoadStateToStatus(mUserFontEntry
->LoadState());
639 if (newStatus
> mStatus
) {
640 SetStatus(newStatus
);
645 Maybe
<StyleComputedFontWeightRange
> FontFace::GetFontWeight() const {
646 StyleComputedFontWeightRange range
;
647 if (!Servo_FontFaceRule_GetFontWeight(GetData(), &range
)) {
653 Maybe
<StyleComputedFontStretchRange
> FontFace::GetFontStretch() const {
654 StyleComputedFontStretchRange range
;
655 if (!Servo_FontFaceRule_GetFontStretch(GetData(), &range
)) {
661 Maybe
<StyleComputedFontStyleDescriptor
> FontFace::GetFontStyle() const {
662 auto descriptor
= StyleComputedFontStyleDescriptor::Normal();
663 if (!Servo_FontFaceRule_GetFontStyle(GetData(), &descriptor
)) {
666 return Some(descriptor
);
669 Maybe
<StyleFontDisplay
> FontFace::GetFontDisplay() const {
670 StyleFontDisplay display
;
671 if (!Servo_FontFaceRule_GetFontDisplay(GetData(), &display
)) {
674 return Some(display
);
677 Maybe
<StyleFontLanguageOverride
> FontFace::GetFontLanguageOverride() const {
678 StyleFontLanguageOverride langOverride
;
679 if (!Servo_FontFaceRule_GetFontLanguageOverride(GetData(), &langOverride
)) {
682 return Some(langOverride
);
685 Maybe
<StylePercentage
> FontFace::GetAscentOverride() const {
686 StylePercentage ascent
{0};
687 if (!Servo_FontFaceRule_GetAscentOverride(GetData(), &ascent
)) {
693 Maybe
<StylePercentage
> FontFace::GetDescentOverride() const {
694 StylePercentage descent
{0};
695 if (!Servo_FontFaceRule_GetDescentOverride(GetData(), &descent
)) {
698 return Some(descent
);
701 Maybe
<StylePercentage
> FontFace::GetLineGapOverride() const {
702 StylePercentage lineGap
{0};
703 if (!Servo_FontFaceRule_GetLineGapOverride(GetData(), &lineGap
)) {
706 return Some(lineGap
);
709 Maybe
<StylePercentage
> FontFace::GetSizeAdjust() const {
710 StylePercentage sizeAdjust
;
711 if (!Servo_FontFaceRule_GetSizeAdjust(GetData(), &sizeAdjust
)) {
714 return Some(sizeAdjust
);
717 bool FontFace::HasLocalSrc() const {
718 AutoTArray
<StyleFontFaceSourceListComponent
, 8> components
;
719 GetSources(components
);
720 for (auto& component
: components
) {
721 if (component
.tag
== StyleFontFaceSourceListComponent::Tag::Local
) {
728 void FontFace::GetFontFeatureSettings(
729 nsTArray
<gfxFontFeature
>& aFeatures
) const {
730 Servo_FontFaceRule_GetFeatureSettings(GetData(), &aFeatures
);
733 void FontFace::GetFontVariationSettings(
734 nsTArray
<gfxFontVariation
>& aVariations
) const {
735 Servo_FontFaceRule_GetVariationSettings(GetData(), &aVariations
);
738 void FontFace::GetSources(
739 nsTArray
<StyleFontFaceSourceListComponent
>& aSources
) const {
740 Servo_FontFaceRule_GetSources(GetData(), &aSources
);
743 nsAtom
* FontFace::GetFamilyName() const {
744 return Servo_FontFaceRule_GetFamilyName(GetData());
747 void FontFace::DisconnectFromRule() {
748 MOZ_ASSERT(HasRule());
750 // Make a copy of the descriptors.
751 mDescriptors
= Servo_FontFaceRule_Clone(mRule
).Consume();
753 mInFontFaceSet
= false;
756 bool FontFace::HasFontData() const {
757 return mSourceType
== eSourceType_Buffer
&& mSourceBuffer
;
760 void FontFace::TakeBuffer(uint8_t*& aBuffer
, uint32_t& aLength
) {
761 MOZ_ASSERT(HasFontData());
763 aBuffer
= mSourceBuffer
;
764 aLength
= mSourceBufferLength
;
766 mSourceBuffer
= nullptr;
767 mSourceBufferLength
= 0;
770 already_AddRefed
<gfxFontFaceBufferSource
> FontFace::CreateBufferSource() {
771 RefPtr
<FontFaceBufferSource
> bufferSource
= new FontFaceBufferSource(this);
772 return bufferSource
.forget();
775 bool FontFace::IsInFontFaceSet(FontFaceSet
* aFontFaceSet
) const {
776 if (mFontFaceSet
== aFontFaceSet
) {
777 return mInFontFaceSet
;
779 return mOtherFontFaceSets
.Contains(aFontFaceSet
);
782 void FontFace::AddFontFaceSet(FontFaceSet
* aFontFaceSet
) {
783 MOZ_ASSERT(!IsInFontFaceSet(aFontFaceSet
));
785 if (mFontFaceSet
== aFontFaceSet
) {
786 mInFontFaceSet
= true;
788 mOtherFontFaceSets
.AppendElement(aFontFaceSet
);
792 void FontFace::RemoveFontFaceSet(FontFaceSet
* aFontFaceSet
) {
793 MOZ_ASSERT(IsInFontFaceSet(aFontFaceSet
));
795 if (mFontFaceSet
== aFontFaceSet
) {
796 mInFontFaceSet
= false;
798 mOtherFontFaceSets
.RemoveElement(aFontFaceSet
);
802 void FontFace::Reject(nsresult aResult
) {
803 AssertIsMainThreadOrServoFontMetricsLocked();
807 } else if (mLoadedRejection
== NS_OK
) {
808 mLoadedRejection
= aResult
;
812 void FontFace::EnsurePromise() {
813 MOZ_ASSERT(NS_IsMainThread());
819 nsCOMPtr
<nsIGlobalObject
> global
= do_QueryInterface(mParent
);
821 // If the pref is not set, don't create the Promise (which the page wouldn't
822 // be able to get to anyway) as it causes the window.FontFace constructor
824 if (global
&& FontFaceSet::PrefEnabled()) {
826 mLoaded
= Promise::Create(global
, rv
);
828 if (mStatus
== FontFaceLoadStatus::Loaded
) {
829 mLoaded
->MaybeResolve(this);
830 } else if (mLoadedRejection
!= NS_OK
) {
831 mLoaded
->MaybeReject(mLoadedRejection
);
836 gfxCharacterMap
* FontFace::GetUnicodeRangeAsCharacterMap() {
837 if (!mUnicodeRangeDirty
) {
838 return mUnicodeRange
;
842 const StyleUnicodeRange
* rangesPtr
=
843 Servo_FontFaceRule_GetUnicodeRanges(GetData(), &len
);
845 Span
<const StyleUnicodeRange
> ranges(rangesPtr
, len
);
846 if (!ranges
.IsEmpty()) {
847 RefPtr
<gfxCharacterMap
> charMap
= new gfxCharacterMap();
848 for (auto& range
: ranges
) {
849 charMap
->SetRange(range
.start
, range
.end
);
852 // As it's common for multiple font resources to have the same
853 // unicode-range list, look for an existing copy of this map to share,
854 // or add this one to the sharing cache if not already present.
856 gfxPlatformFontList::PlatformFontList()->FindCharMap(charMap
);
858 mUnicodeRange
= nullptr;
861 mUnicodeRangeDirty
= false;
862 return mUnicodeRange
;
865 // -- FontFace::Entry --------------------------------------------------------
868 void FontFace::Entry::SetLoadState(UserFontLoadState aLoadState
) {
869 gfxUserFontEntry::SetLoadState(aLoadState
);
871 for (size_t i
= 0; i
< mFontFaces
.Length(); i
++) {
872 mFontFaces
[i
]->SetStatus(LoadStateToStatus(aLoadState
));
877 void FontFace::Entry::GetUserFontSets(nsTArray
<gfxUserFontSet
*>& aResult
) {
880 for (FontFace
* f
: mFontFaces
) {
881 if (f
->mInFontFaceSet
) {
882 aResult
.AppendElement(f
->mFontFaceSet
->GetUserFontSet());
884 for (FontFaceSet
* s
: f
->mOtherFontFaceSets
) {
885 aResult
.AppendElement(s
->GetUserFontSet());
889 // Remove duplicates.
891 auto it
= std::unique(aResult
.begin(), aResult
.end());
892 aResult
.TruncateLength(it
- aResult
.begin());
896 } // namespace mozilla