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/FontFaceImpl.h"
10 #include "gfxFontUtils.h"
11 #include "gfxPlatformFontList.h"
12 #include "mozilla/dom/CSSFontFaceRule.h"
13 #include "mozilla/dom/FontFaceBinding.h"
14 #include "mozilla/dom/FontFaceSetImpl.h"
15 #include "mozilla/dom/TypedArray.h"
16 #include "mozilla/dom/UnionTypes.h"
17 #include "mozilla/ServoBindings.h"
18 #include "mozilla/ServoCSSParser.h"
19 #include "mozilla/ServoUtils.h"
20 #include "mozilla/StaticPrefs_layout.h"
21 #include "mozilla/dom/Document.h"
22 #include "nsStyleUtil.h"
27 // -- FontFaceBufferSource ---------------------------------------------------
30 * An object that wraps a FontFace object and exposes its ArrayBuffer
31 * or ArrayBufferView data in a form the user font set can consume.
33 class FontFaceBufferSource
: public gfxFontFaceBufferSource
{
35 FontFaceBufferSource(uint8_t* aBuffer
, uint32_t aLength
)
36 : mBuffer(aBuffer
), mLength(aLength
) {}
38 void TakeBuffer(uint8_t*& aBuffer
, uint32_t& aLength
) override
{
40 "only call TakeBuffer once on a given "
41 "FontFaceBufferSource object");
49 ~FontFaceBufferSource() override
{
59 // -- FontFaceImpl -----------------------------------------------------------
61 FontFaceImpl::FontFaceImpl(FontFace
* aOwner
, FontFaceSetImpl
* aFontFaceSet
)
63 mStatus(FontFaceLoadStatus::Unloaded
),
64 mSourceType(SourceType(0)),
65 mFontFaceSet(aFontFaceSet
),
66 mUnicodeRangeDirty(true),
67 mInFontFaceSet(false) {}
69 FontFaceImpl::~FontFaceImpl() {
70 // Assert that we don't drop any FontFace objects during a Servo traversal,
71 // since PostTraversalTask objects can hold raw pointers to FontFaces.
72 MOZ_ASSERT(!gfxFontUtils::IsInServoTraversal());
74 SetUserFontEntry(nullptr);
78 void FontFaceImpl::AssertIsOnOwningThread() const {
79 mFontFaceSet
->AssertIsOnOwningThread();
83 void FontFaceImpl::Destroy() {
84 mInFontFaceSet
= false;
85 SetUserFontEntry(nullptr);
89 static FontFaceLoadStatus
LoadStateToStatus(
90 gfxUserFontEntry::UserFontLoadState aLoadState
) {
92 case gfxUserFontEntry::UserFontLoadState::STATUS_NOT_LOADED
:
93 return FontFaceLoadStatus::Unloaded
;
94 case gfxUserFontEntry::UserFontLoadState::STATUS_LOAD_PENDING
:
95 case gfxUserFontEntry::UserFontLoadState::STATUS_LOADING
:
96 return FontFaceLoadStatus::Loading
;
97 case gfxUserFontEntry::UserFontLoadState::STATUS_LOADED
:
98 return FontFaceLoadStatus::Loaded
;
99 case gfxUserFontEntry::UserFontLoadState::STATUS_FAILED
:
100 return FontFaceLoadStatus::Error
;
102 MOZ_ASSERT_UNREACHABLE("invalid aLoadState value");
103 return FontFaceLoadStatus::Error
;
106 already_AddRefed
<FontFaceImpl
> FontFaceImpl::CreateForRule(
107 FontFace
* aOwner
, FontFaceSetImpl
* aFontFaceSet
,
108 StyleLockedFontFaceRule
* aRule
) {
109 RefPtr
<FontFaceImpl
> obj
= new FontFaceImpl(aOwner
, aFontFaceSet
);
111 obj
->mSourceType
= eSourceType_FontFaceRule
;
112 obj
->mInFontFaceSet
= true;
116 void FontFaceImpl::InitializeSourceURL(const nsACString
& aURL
) {
118 mSourceType
= eSourceType_URLs
;
120 IgnoredErrorResult rv
;
121 SetDescriptor(eCSSFontDesc_Src
, aURL
, rv
);
123 mOwner
->MaybeReject(NS_ERROR_DOM_SYNTAX_ERR
);
124 SetStatus(FontFaceLoadStatus::Error
);
128 void FontFaceImpl::InitializeSourceBuffer(uint8_t* aBuffer
, uint32_t aLength
) {
130 MOZ_ASSERT(!mBufferSource
);
131 mSourceType
= FontFaceImpl::eSourceType_Buffer
;
134 mBufferSource
= new FontFaceBufferSource(aBuffer
, aLength
);
137 SetStatus(FontFaceLoadStatus::Loading
);
141 void FontFaceImpl::GetFamily(nsACString
& aResult
) {
142 GetDesc(eCSSFontDesc_Family
, aResult
);
145 void FontFaceImpl::SetFamily(const nsACString
& aValue
, ErrorResult
& aRv
) {
146 mFontFaceSet
->FlushUserFontSet();
147 if (SetDescriptor(eCSSFontDesc_Family
, aValue
, aRv
)) {
152 void FontFaceImpl::GetStyle(nsACString
& aResult
) {
153 GetDesc(eCSSFontDesc_Style
, aResult
);
156 void FontFaceImpl::SetStyle(const nsACString
& aValue
, ErrorResult
& aRv
) {
157 if (SetDescriptor(eCSSFontDesc_Style
, aValue
, aRv
)) {
162 void FontFaceImpl::GetWeight(nsACString
& aResult
) {
163 GetDesc(eCSSFontDesc_Weight
, aResult
);
166 void FontFaceImpl::SetWeight(const nsACString
& aValue
, ErrorResult
& aRv
) {
167 mFontFaceSet
->FlushUserFontSet();
168 if (SetDescriptor(eCSSFontDesc_Weight
, aValue
, aRv
)) {
173 void FontFaceImpl::GetStretch(nsACString
& aResult
) {
174 GetDesc(eCSSFontDesc_Stretch
, aResult
);
177 void FontFaceImpl::SetStretch(const nsACString
& aValue
, ErrorResult
& aRv
) {
178 mFontFaceSet
->FlushUserFontSet();
179 if (SetDescriptor(eCSSFontDesc_Stretch
, aValue
, aRv
)) {
184 void FontFaceImpl::GetUnicodeRange(nsACString
& aResult
) {
185 GetDesc(eCSSFontDesc_UnicodeRange
, aResult
);
188 void FontFaceImpl::SetUnicodeRange(const nsACString
& aValue
, ErrorResult
& aRv
) {
189 mFontFaceSet
->FlushUserFontSet();
190 if (SetDescriptor(eCSSFontDesc_UnicodeRange
, aValue
, aRv
)) {
195 void FontFaceImpl::GetVariant(nsACString
& aResult
) {
196 // XXX Just expose the font-variant descriptor as "normal" until we
197 // support it properly (bug 1055385).
198 aResult
.AssignLiteral("normal");
201 void FontFaceImpl::SetVariant(const nsACString
& aValue
, ErrorResult
& aRv
) {
202 // XXX Ignore assignments to variant until we support font-variant
203 // descriptors (bug 1055385).
206 void FontFaceImpl::GetFeatureSettings(nsACString
& aResult
) {
207 GetDesc(eCSSFontDesc_FontFeatureSettings
, aResult
);
210 void FontFaceImpl::SetFeatureSettings(const nsACString
& aValue
,
212 mFontFaceSet
->FlushUserFontSet();
213 if (SetDescriptor(eCSSFontDesc_FontFeatureSettings
, aValue
, aRv
)) {
218 void FontFaceImpl::GetVariationSettings(nsACString
& aResult
) {
219 GetDesc(eCSSFontDesc_FontVariationSettings
, aResult
);
222 void FontFaceImpl::SetVariationSettings(const nsACString
& aValue
,
224 mFontFaceSet
->FlushUserFontSet();
225 if (SetDescriptor(eCSSFontDesc_FontVariationSettings
, aValue
, aRv
)) {
230 void FontFaceImpl::GetDisplay(nsACString
& aResult
) {
231 GetDesc(eCSSFontDesc_Display
, aResult
);
234 void FontFaceImpl::SetDisplay(const nsACString
& aValue
, ErrorResult
& aRv
) {
235 if (SetDescriptor(eCSSFontDesc_Display
, aValue
, aRv
)) {
240 void FontFaceImpl::GetAscentOverride(nsACString
& aResult
) {
241 GetDesc(eCSSFontDesc_AscentOverride
, aResult
);
244 void FontFaceImpl::SetAscentOverride(const nsACString
& aValue
,
246 if (SetDescriptor(eCSSFontDesc_AscentOverride
, aValue
, aRv
)) {
251 void FontFaceImpl::GetDescentOverride(nsACString
& aResult
) {
252 GetDesc(eCSSFontDesc_DescentOverride
, aResult
);
255 void FontFaceImpl::SetDescentOverride(const nsACString
& aValue
,
257 if (SetDescriptor(eCSSFontDesc_DescentOverride
, aValue
, aRv
)) {
262 void FontFaceImpl::GetLineGapOverride(nsACString
& aResult
) {
263 GetDesc(eCSSFontDesc_LineGapOverride
, aResult
);
266 void FontFaceImpl::SetLineGapOverride(const nsACString
& aValue
,
268 if (SetDescriptor(eCSSFontDesc_LineGapOverride
, aValue
, aRv
)) {
273 void FontFaceImpl::GetSizeAdjust(nsACString
& aResult
) {
274 GetDesc(eCSSFontDesc_SizeAdjust
, aResult
);
277 void FontFaceImpl::SetSizeAdjust(const nsACString
& aValue
, ErrorResult
& aRv
) {
278 if (SetDescriptor(eCSSFontDesc_SizeAdjust
, aValue
, aRv
)) {
283 void FontFaceImpl::DescriptorUpdated() {
284 // If we haven't yet initialized mUserFontEntry, no need to do anything here;
285 // we'll respect the updated descriptor when the time comes to create it.
286 if (!mUserFontEntry
) {
290 gfxUserFontAttributes attr
;
291 RefPtr
<gfxUserFontEntry
> newEntry
;
292 if (GetAttributes(attr
)) {
293 newEntry
= mFontFaceSet
->FindOrCreateUserFontEntryFromFontFace(
294 this, std::move(attr
), StyleOrigin::Author
);
296 SetUserFontEntry(newEntry
);
298 // Behind the scenes, this will actually update the existing entry and return
299 // it, rather than create a new one.
301 if (mInFontFaceSet
) {
302 mFontFaceSet
->MarkUserFontSetDirty();
304 for (auto& set
: mOtherFontFaceSets
) {
305 set
->MarkUserFontSetDirty();
309 FontFaceLoadStatus
FontFaceImpl::Status() { return mStatus
; }
311 void FontFaceImpl::Load(ErrorResult
& aRv
) {
312 mFontFaceSet
->FlushUserFontSet();
314 // Calling Load on a FontFace constructed with an ArrayBuffer data source,
315 // or on one that is already loading (or has finished loading), has no
317 if (mSourceType
== eSourceType_Buffer
||
318 mStatus
!= FontFaceLoadStatus::Unloaded
) {
322 // Calling the user font entry's Load method will end up setting our
323 // status to Loading, but the spec requires us to set it to Loading
325 SetStatus(FontFaceLoadStatus::Loading
);
330 gfxUserFontEntry
* FontFaceImpl::CreateUserFontEntry() {
331 if (!mUserFontEntry
) {
332 MOZ_ASSERT(!HasRule(),
333 "Rule backed FontFace objects should already have a user font "
334 "entry by the time Load() can be called on them");
336 gfxUserFontAttributes attr
;
337 if (GetAttributes(attr
)) {
338 RefPtr
<gfxUserFontEntry
> newEntry
=
339 mFontFaceSet
->FindOrCreateUserFontEntryFromFontFace(
340 this, std::move(attr
), StyleOrigin::Author
);
342 SetUserFontEntry(newEntry
);
347 return mUserFontEntry
;
350 void FontFaceImpl::DoLoad() {
351 if (!CreateUserFontEntry()) {
355 if (!NS_IsMainThread()) {
356 NS_DispatchToMainThread(NS_NewRunnableFunction(
357 "FontFaceImpl::DoLoad",
358 [entry
= RefPtr
{mUserFontEntry
}]() { entry
->Load(); }));
362 mUserFontEntry
->Load();
365 void FontFaceImpl::SetStatus(FontFaceLoadStatus aStatus
) {
366 gfxFontUtils::AssertSafeThreadOrServoFontMetricsLocked();
368 if (mStatus
== aStatus
) {
372 if (aStatus
< mStatus
) {
373 // We're being asked to go backwards in status! Normally, this shouldn't
374 // happen. But it can if the FontFace had a user font entry that had
375 // loaded, but then was given a new one by FontFaceSet::InsertRuleFontFace
376 // if we used a local() rule. For now, just ignore the request to
377 // go backwards in status.
383 if (mInFontFaceSet
) {
384 mFontFaceSet
->OnFontFaceStatusChanged(this);
387 for (FontFaceSetImpl
* otherSet
: mOtherFontFaceSets
) {
388 otherSet
->OnFontFaceStatusChanged(this);
391 UpdateOwnerPromise();
394 void FontFaceImpl::UpdateOwnerPromise() {
395 if (!mFontFaceSet
->IsOnOwningThread()) {
396 mFontFaceSet
->DispatchToOwningThread(
397 "FontFaceImpl::UpdateOwnerPromise",
398 [self
= RefPtr
{this}] { self
->UpdateOwnerPromise(); });
402 if (NS_WARN_IF(!mOwner
)) {
406 if (mStatus
== FontFaceLoadStatus::Loaded
) {
407 mOwner
->MaybeResolve();
408 } else if (mStatus
== FontFaceLoadStatus::Error
) {
409 if (mSourceType
== eSourceType_Buffer
) {
410 mOwner
->MaybeReject(NS_ERROR_DOM_SYNTAX_ERR
);
412 mOwner
->MaybeReject(NS_ERROR_DOM_NETWORK_ERR
);
417 // Boolean result indicates whether the value of the descriptor was actually
419 bool FontFaceImpl::SetDescriptor(nsCSSFontDesc aFontDesc
,
420 const nsACString
& aValue
, ErrorResult
& aRv
) {
421 // FIXME We probably don't need to distinguish between this anymore
422 // since we have common backend now.
423 NS_ASSERTION(!HasRule(), "we don't handle rule backed FontFace objects yet");
428 RefPtr
<URLExtraData
> url
= mFontFaceSet
->GetURLExtraData();
429 if (NS_WARN_IF(!url
)) {
430 // This should only happen on worker threads, where we failed to initialize
431 // the worker before it was shutdown.
432 aRv
.ThrowInvalidStateError("Missing URLExtraData");
436 // FIXME(heycam): Should not allow modification of FontFaces that are
437 // CSS-connected and whose rule is read only.
439 if (!Servo_FontFaceRule_SetDescriptor(GetData(), aFontDesc
, &aValue
, url
,
441 aRv
.ThrowSyntaxError("Invalid font descriptor");
449 if (aFontDesc
== eCSSFontDesc_UnicodeRange
) {
450 mUnicodeRangeDirty
= true;
456 bool FontFaceImpl::SetDescriptors(const nsACString
& aFamily
,
457 const FontFaceDescriptors
& aDescriptors
) {
458 MOZ_ASSERT(!HasRule());
459 MOZ_ASSERT(!mDescriptors
);
461 mDescriptors
= Servo_FontFaceRule_CreateEmpty().Consume();
463 // Helper to call SetDescriptor and return true on success, false on failure.
464 auto setDesc
= [=](nsCSSFontDesc aDesc
, const nsACString
& aVal
) -> bool {
465 IgnoredErrorResult rv
;
466 SetDescriptor(aDesc
, aVal
, rv
);
470 // Parse all of the mDescriptors in aInitializer, which are the values
471 // we got from the JS constructor.
472 if (!setDesc(eCSSFontDesc_Family
, aFamily
) ||
473 !setDesc(eCSSFontDesc_Style
, aDescriptors
.mStyle
) ||
474 !setDesc(eCSSFontDesc_Weight
, aDescriptors
.mWeight
) ||
475 !setDesc(eCSSFontDesc_Stretch
, aDescriptors
.mStretch
) ||
476 !setDesc(eCSSFontDesc_UnicodeRange
, aDescriptors
.mUnicodeRange
) ||
477 !setDesc(eCSSFontDesc_FontFeatureSettings
,
478 aDescriptors
.mFeatureSettings
) ||
479 (StaticPrefs::layout_css_font_variations_enabled() &&
480 !setDesc(eCSSFontDesc_FontVariationSettings
,
481 aDescriptors
.mVariationSettings
)) ||
482 !setDesc(eCSSFontDesc_Display
, aDescriptors
.mDisplay
) ||
483 ((!setDesc(eCSSFontDesc_AscentOverride
, aDescriptors
.mAscentOverride
) ||
484 !setDesc(eCSSFontDesc_DescentOverride
, aDescriptors
.mDescentOverride
) ||
485 !setDesc(eCSSFontDesc_LineGapOverride
,
486 aDescriptors
.mLineGapOverride
))) ||
487 (StaticPrefs::layout_css_size_adjust_enabled() &&
488 !setDesc(eCSSFontDesc_SizeAdjust
, aDescriptors
.mSizeAdjust
))) {
489 // XXX Handle font-variant once we support it (bug 1055385).
491 // If any of the descriptors failed to parse, none of them should be set
493 mDescriptors
= Servo_FontFaceRule_CreateEmpty().Consume();
496 mOwner
->MaybeReject(NS_ERROR_DOM_SYNTAX_ERR
);
499 SetStatus(FontFaceLoadStatus::Error
);
506 void FontFaceImpl::GetDesc(nsCSSFontDesc aDescID
, nsACString
& aResult
) const {
508 Servo_FontFaceRule_GetDescriptorCssText(GetData(), aDescID
, &aResult
);
510 // Fill in a default value for missing descriptors.
511 if (aResult
.IsEmpty()) {
512 if (aDescID
== eCSSFontDesc_UnicodeRange
) {
513 aResult
.AssignLiteral("U+0-10FFFF");
514 } else if (aDescID
== eCSSFontDesc_Display
) {
515 aResult
.AssignLiteral("auto");
516 } else if (aDescID
!= eCSSFontDesc_Family
&& aDescID
!= eCSSFontDesc_Src
) {
517 aResult
.AssignLiteral("normal");
522 void FontFaceImpl::SetUserFontEntry(gfxUserFontEntry
* aEntry
) {
523 AssertIsOnOwningThread();
525 if (mUserFontEntry
== aEntry
) {
529 if (mUserFontEntry
) {
530 mUserFontEntry
->RemoveFontFace(this);
533 auto* entry
= static_cast<Entry
*>(aEntry
);
535 entry
->AddFontFace(this);
538 mUserFontEntry
= entry
;
540 if (!mUserFontEntry
) {
544 MOZ_ASSERT(mUserFontEntry
->HasUserFontSet(mFontFaceSet
),
545 "user font entry must be associated with the same user font set "
548 // Our newly assigned user font entry might be in the process of or
549 // finished loading, so set our status accordingly. But only do so
550 // if we're not going "backwards" in status, which could otherwise
551 // happen in this case:
553 // new FontFace("ABC", "url(x)").load();
555 // where the SetUserFontEntry call (from the after-initialization
556 // DoLoad call) comes after the author's call to load(), which set mStatus
558 FontFaceLoadStatus newStatus
= LoadStateToStatus(mUserFontEntry
->LoadState());
559 if (newStatus
> mStatus
) {
560 SetStatus(newStatus
);
564 bool FontFaceImpl::GetAttributes(gfxUserFontAttributes
& aAttr
) {
565 StyleLockedFontFaceRule
* data
= GetData();
570 nsAtom
* fontFamily
= Servo_FontFaceRule_GetFamilyName(data
);
575 aAttr
.mFamilyName
= nsAtomCString(fontFamily
);
577 StyleComputedFontWeightRange weightRange
;
578 if (Servo_FontFaceRule_GetFontWeight(data
, &weightRange
)) {
579 aAttr
.mRangeFlags
&= ~gfxFontEntry::RangeFlags::eAutoWeight
;
580 aAttr
.mWeight
= WeightRange(FontWeight::FromFloat(weightRange
._0
),
581 FontWeight::FromFloat(weightRange
._1
));
584 StyleComputedFontStretchRange stretchRange
;
585 if (Servo_FontFaceRule_GetFontStretch(data
, &stretchRange
)) {
586 aAttr
.mRangeFlags
&= ~gfxFontEntry::RangeFlags::eAutoStretch
;
587 aAttr
.mStretch
= StretchRange(stretchRange
._0
, stretchRange
._1
);
590 auto styleDesc
= StyleComputedFontStyleDescriptor::Normal();
591 if (Servo_FontFaceRule_GetFontStyle(data
, &styleDesc
)) {
592 aAttr
.mRangeFlags
&= ~gfxFontEntry::RangeFlags::eAutoSlantStyle
;
593 switch (styleDesc
.tag
) {
594 case StyleComputedFontStyleDescriptor::Tag::Normal
:
595 aAttr
.mStyle
= SlantStyleRange(FontSlantStyle::NORMAL
);
597 case StyleComputedFontStyleDescriptor::Tag::Italic
:
598 aAttr
.mStyle
= SlantStyleRange(FontSlantStyle::ITALIC
);
600 case StyleComputedFontStyleDescriptor::Tag::Oblique
:
601 aAttr
.mStyle
= SlantStyleRange(
602 FontSlantStyle::FromFloat(styleDesc
.AsOblique()._0
),
603 FontSlantStyle::FromFloat(styleDesc
.AsOblique()._1
));
606 MOZ_ASSERT_UNREACHABLE("Unhandled tag");
610 StylePercentage ascent
{0};
611 if (Servo_FontFaceRule_GetAscentOverride(data
, &ascent
)) {
612 aAttr
.mAscentOverride
= ascent
._0
;
615 StylePercentage descent
{0};
616 if (Servo_FontFaceRule_GetDescentOverride(data
, &descent
)) {
617 aAttr
.mDescentOverride
= descent
._0
;
620 StylePercentage lineGap
{0};
621 if (Servo_FontFaceRule_GetLineGapOverride(data
, &lineGap
)) {
622 aAttr
.mLineGapOverride
= lineGap
._0
;
625 StylePercentage sizeAdjust
;
626 if (Servo_FontFaceRule_GetSizeAdjust(data
, &sizeAdjust
)) {
627 aAttr
.mSizeAdjust
= sizeAdjust
._0
;
630 StyleFontLanguageOverride langOverride
;
631 if (Servo_FontFaceRule_GetFontLanguageOverride(data
, &langOverride
)) {
632 aAttr
.mLanguageOverride
= langOverride
._0
;
635 Servo_FontFaceRule_GetFontDisplay(data
, &aAttr
.mFontDisplay
);
636 Servo_FontFaceRule_GetFeatureSettings(data
, &aAttr
.mFeatureSettings
);
637 Servo_FontFaceRule_GetVariationSettings(data
, &aAttr
.mVariationSettings
);
638 Servo_FontFaceRule_GetSources(data
, &aAttr
.mSources
);
639 aAttr
.mUnicodeRanges
= GetUnicodeRangeAsCharacterMap();
643 bool FontFaceImpl::HasLocalSrc() const {
644 AutoTArray
<StyleFontFaceSourceListComponent
, 8> components
;
645 Servo_FontFaceRule_GetSources(GetData(), &components
);
646 for (auto& component
: components
) {
647 if (component
.tag
== StyleFontFaceSourceListComponent::Tag::Local
) {
654 nsAtom
* FontFaceImpl::GetFamilyName() const {
655 return Servo_FontFaceRule_GetFamilyName(GetData());
658 void FontFaceImpl::DisconnectFromRule() {
659 MOZ_ASSERT(HasRule());
661 // Make a copy of the descriptors.
662 mDescriptors
= Servo_FontFaceRule_Clone(mRule
).Consume();
664 mInFontFaceSet
= false;
667 bool FontFaceImpl::HasFontData() const {
668 return mSourceType
== eSourceType_Buffer
&& mBufferSource
;
671 already_AddRefed
<gfxFontFaceBufferSource
> FontFaceImpl::TakeBufferSource() {
672 MOZ_ASSERT(mBufferSource
);
673 return mBufferSource
.forget();
676 bool FontFaceImpl::IsInFontFaceSet(FontFaceSetImpl
* aFontFaceSet
) const {
677 if (mFontFaceSet
== aFontFaceSet
) {
678 return mInFontFaceSet
;
680 return mOtherFontFaceSets
.Contains(aFontFaceSet
);
683 void FontFaceImpl::AddFontFaceSet(FontFaceSetImpl
* aFontFaceSet
) {
684 MOZ_ASSERT(!IsInFontFaceSet(aFontFaceSet
));
686 if (mFontFaceSet
== aFontFaceSet
) {
687 mInFontFaceSet
= true;
689 mOtherFontFaceSets
.AppendElement(aFontFaceSet
);
693 void FontFaceImpl::RemoveFontFaceSet(FontFaceSetImpl
* aFontFaceSet
) {
694 MOZ_ASSERT(IsInFontFaceSet(aFontFaceSet
));
696 if (mFontFaceSet
== aFontFaceSet
) {
697 mInFontFaceSet
= false;
699 mOtherFontFaceSets
.RemoveElement(aFontFaceSet
);
702 // The caller should be holding a strong reference to the FontFaceSetImpl.
703 if (mUserFontEntry
) {
704 mUserFontEntry
->CheckUserFontSet();
708 gfxCharacterMap
* FontFaceImpl::GetUnicodeRangeAsCharacterMap() {
709 if (!mUnicodeRangeDirty
) {
710 return mUnicodeRange
;
714 const StyleUnicodeRange
* rangesPtr
=
715 Servo_FontFaceRule_GetUnicodeRanges(GetData(), &len
);
717 Span
<const StyleUnicodeRange
> ranges(rangesPtr
, len
);
718 if (!ranges
.IsEmpty()) {
719 RefPtr
<gfxCharacterMap
> charMap
= new gfxCharacterMap();
720 for (auto& range
: ranges
) {
721 charMap
->SetRange(range
.start
, range
.end
);
724 // As it's common for multiple font resources to have the same
725 // unicode-range list, look for an existing copy of this map to share,
726 // or add this one to the sharing cache if not already present.
728 gfxPlatformFontList::PlatformFontList()->FindCharMap(charMap
);
730 mUnicodeRange
= nullptr;
733 mUnicodeRangeDirty
= false;
734 return mUnicodeRange
;
737 // -- FontFaceImpl::Entry
738 // --------------------------------------------------------
741 void FontFaceImpl::Entry::SetLoadState(UserFontLoadState aLoadState
) {
742 gfxUserFontEntry::SetLoadState(aLoadState
);
743 FontFaceLoadStatus status
= LoadStateToStatus(aLoadState
);
745 nsTArray
<RefPtr
<FontFaceImpl
>> fontFaces
;
747 MutexAutoLock
lock(mMutex
);
748 fontFaces
.SetCapacity(mFontFaces
.Length());
749 for (FontFaceImpl
* f
: mFontFaces
) {
750 fontFaces
.AppendElement(f
);
754 for (FontFaceImpl
* impl
: fontFaces
) {
755 auto* setImpl
= impl
->GetPrimaryFontFaceSet();
756 if (setImpl
->IsOnOwningThread()) {
757 impl
->SetStatus(status
);
759 setImpl
->DispatchToOwningThread(
760 "FontFaceImpl::Entry::SetLoadState",
761 [self
= RefPtr
{impl
}, status
] { self
->SetStatus(status
); });
767 void FontFaceImpl::Entry::GetUserFontSets(
768 nsTArray
<RefPtr
<gfxUserFontSet
>>& aResult
) {
769 MutexAutoLock
lock(mMutex
);
774 aResult
.AppendElement(mFontSet
);
777 for (FontFaceImpl
* f
: mFontFaces
) {
778 if (f
->mInFontFaceSet
) {
779 aResult
.AppendElement(f
->mFontFaceSet
);
781 for (FontFaceSetImpl
* s
: f
->mOtherFontFaceSets
) {
782 aResult
.AppendElement(s
);
786 // Remove duplicates.
788 auto it
= std::unique(aResult
.begin(), aResult
.end());
789 aResult
.TruncateLength(it
- aResult
.begin());
792 /* virtual */ already_AddRefed
<gfxUserFontSet
>
793 FontFaceImpl::Entry::GetUserFontSet() const {
794 MutexAutoLock
lock(mMutex
);
796 return do_AddRef(mFontSet
);
798 if (NS_IsMainThread() && mLoadingFontSet
) {
799 return do_AddRef(mLoadingFontSet
);
804 void FontFaceImpl::Entry::CheckUserFontSetLocked() {
805 // If this is the last font containing a strong reference to the set, we need
806 // to clear the reference as there is no longer anything guaranteeing the set
807 // will be kept alive.
809 auto* set
= static_cast<FontFaceSetImpl
*>(mFontSet
);
810 for (FontFaceImpl
* f
: mFontFaces
) {
811 if (f
->mFontFaceSet
== set
|| f
->mOtherFontFaceSets
.Contains(set
)) {
817 // If possible, promote the most recently added FontFace and its owning
818 // FontFaceSetImpl as the primary set.
819 if (!mFontFaces
.IsEmpty()) {
820 mFontSet
= mFontFaces
.LastElement()->mFontFaceSet
;
826 void FontFaceImpl::Entry::FindFontFaceOwners(nsTHashSet
<FontFace
*>& aOwners
) {
827 MutexAutoLock
lock(mMutex
);
828 for (FontFaceImpl
* f
: mFontFaces
) {
829 if (FontFace
* owner
= f
->GetOwner()) {
830 aOwners
.Insert(owner
);
835 void FontFaceImpl::Entry::AddFontFace(FontFaceImpl
* aFontFace
) {
836 MutexAutoLock
lock(mMutex
);
837 mFontFaces
.AppendElement(aFontFace
);
838 CheckUserFontSetLocked();
841 void FontFaceImpl::Entry::RemoveFontFace(FontFaceImpl
* aFontFace
) {
842 MutexAutoLock
lock(mMutex
);
843 mFontFaces
.RemoveElement(aFontFace
);
844 CheckUserFontSetLocked();
848 } // namespace mozilla