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/FontFaceBinding.h"
13 #include "mozilla/dom/FontFaceSetImpl.h"
14 #include "mozilla/ServoCSSParser.h"
15 #include "mozilla/StaticPrefs_layout.h"
16 #include "mozilla/dom/Document.h"
21 // -- FontFaceBufferSource ---------------------------------------------------
24 * An object that wraps a FontFace object and exposes its ArrayBuffer
25 * or ArrayBufferView data in a form the user font set can consume.
27 class FontFaceBufferSource
: public gfxFontFaceBufferSource
{
29 FontFaceBufferSource(uint8_t* aBuffer
, uint32_t aLength
)
30 : mBuffer(aBuffer
), mLength(aLength
) {}
32 void TakeBuffer(uint8_t*& aBuffer
, uint32_t& aLength
) override
{
34 "only call TakeBuffer once on a given "
35 "FontFaceBufferSource object");
43 ~FontFaceBufferSource() override
{
53 // -- FontFaceImpl -----------------------------------------------------------
55 FontFaceImpl::FontFaceImpl(FontFace
* aOwner
, FontFaceSetImpl
* aFontFaceSet
)
57 mStatus(FontFaceLoadStatus::Unloaded
),
58 mSourceType(SourceType(0)),
59 mFontFaceSet(aFontFaceSet
) {}
61 FontFaceImpl::~FontFaceImpl() {
62 // Assert that we don't drop any FontFace objects during a Servo traversal,
63 // since PostTraversalTask objects can hold raw pointers to FontFaces.
64 MOZ_ASSERT(!gfxFontUtils::IsInServoTraversal());
66 SetUserFontEntry(nullptr);
70 void FontFaceImpl::AssertIsOnOwningThread() const {
71 mFontFaceSet
->AssertIsOnOwningThread();
75 void FontFaceImpl::StopKeepingOwnerAlive() {
76 if (mKeepingOwnerAlive
) {
77 mKeepingOwnerAlive
= false;
83 void FontFaceImpl::Destroy() {
84 mInFontFaceSet
= false;
85 SetUserFontEntry(nullptr);
86 StopKeepingOwnerAlive();
90 static FontFaceLoadStatus
LoadStateToStatus(
91 gfxUserFontEntry::UserFontLoadState aLoadState
) {
93 case gfxUserFontEntry::UserFontLoadState::STATUS_NOT_LOADED
:
94 return FontFaceLoadStatus::Unloaded
;
95 case gfxUserFontEntry::UserFontLoadState::STATUS_LOAD_PENDING
:
96 case gfxUserFontEntry::UserFontLoadState::STATUS_LOADING
:
97 return FontFaceLoadStatus::Loading
;
98 case gfxUserFontEntry::UserFontLoadState::STATUS_LOADED
:
99 return FontFaceLoadStatus::Loaded
;
100 case gfxUserFontEntry::UserFontLoadState::STATUS_FAILED
:
101 return FontFaceLoadStatus::Error
;
103 MOZ_ASSERT_UNREACHABLE("invalid aLoadState value");
104 return FontFaceLoadStatus::Error
;
107 already_AddRefed
<FontFaceImpl
> FontFaceImpl::CreateForRule(
108 FontFace
* aOwner
, FontFaceSetImpl
* aFontFaceSet
,
109 StyleLockedFontFaceRule
* aRule
) {
110 auto obj
= MakeRefPtr
<FontFaceImpl
>(aOwner
, aFontFaceSet
);
112 obj
->mSourceType
= eSourceType_FontFaceRule
;
113 obj
->mInFontFaceSet
= true;
117 void FontFaceImpl::InitializeSourceURL(const nsACString
& aURL
) {
119 mSourceType
= eSourceType_URLs
;
121 IgnoredErrorResult rv
;
122 SetDescriptor(eCSSFontDesc_Src
, aURL
, rv
);
124 mOwner
->MaybeReject(NS_ERROR_DOM_SYNTAX_ERR
);
125 SetStatus(FontFaceLoadStatus::Error
);
129 void FontFaceImpl::InitializeSourceBuffer(uint8_t* aBuffer
, uint32_t aLength
) {
131 MOZ_ASSERT(!mBufferSource
);
132 mSourceType
= FontFaceImpl::eSourceType_Buffer
;
135 mBufferSource
= new FontFaceBufferSource(aBuffer
, aLength
);
138 SetStatus(FontFaceLoadStatus::Loading
);
142 void FontFaceImpl::GetFamily(nsACString
& aResult
) {
143 GetDesc(eCSSFontDesc_Family
, aResult
);
146 void FontFaceImpl::SetFamily(const nsACString
& aValue
, ErrorResult
& aRv
) {
147 mFontFaceSet
->FlushUserFontSet();
148 if (SetDescriptor(eCSSFontDesc_Family
, aValue
, aRv
)) {
153 void FontFaceImpl::GetStyle(nsACString
& aResult
) {
154 GetDesc(eCSSFontDesc_Style
, aResult
);
157 void FontFaceImpl::SetStyle(const nsACString
& aValue
, ErrorResult
& aRv
) {
158 if (SetDescriptor(eCSSFontDesc_Style
, aValue
, aRv
)) {
163 void FontFaceImpl::GetWeight(nsACString
& aResult
) {
164 GetDesc(eCSSFontDesc_Weight
, aResult
);
167 void FontFaceImpl::SetWeight(const nsACString
& aValue
, ErrorResult
& aRv
) {
168 mFontFaceSet
->FlushUserFontSet();
169 if (SetDescriptor(eCSSFontDesc_Weight
, aValue
, aRv
)) {
174 void FontFaceImpl::GetStretch(nsACString
& aResult
) {
175 GetDesc(eCSSFontDesc_Stretch
, aResult
);
178 void FontFaceImpl::SetStretch(const nsACString
& aValue
, ErrorResult
& aRv
) {
179 mFontFaceSet
->FlushUserFontSet();
180 if (SetDescriptor(eCSSFontDesc_Stretch
, aValue
, aRv
)) {
185 void FontFaceImpl::GetUnicodeRange(nsACString
& aResult
) {
186 GetDesc(eCSSFontDesc_UnicodeRange
, aResult
);
189 void FontFaceImpl::SetUnicodeRange(const nsACString
& aValue
, ErrorResult
& aRv
) {
190 mFontFaceSet
->FlushUserFontSet();
191 if (SetDescriptor(eCSSFontDesc_UnicodeRange
, aValue
, aRv
)) {
196 void FontFaceImpl::GetVariant(nsACString
& aResult
) {
197 // XXX Just expose the font-variant descriptor as "normal" until we
198 // support it properly (bug 1055385).
199 aResult
.AssignLiteral("normal");
202 void FontFaceImpl::SetVariant(const nsACString
& aValue
, ErrorResult
& aRv
) {
203 // XXX Ignore assignments to variant until we support font-variant
204 // descriptors (bug 1055385).
207 void FontFaceImpl::GetFeatureSettings(nsACString
& aResult
) {
208 GetDesc(eCSSFontDesc_FontFeatureSettings
, aResult
);
211 void FontFaceImpl::SetFeatureSettings(const nsACString
& aValue
,
213 mFontFaceSet
->FlushUserFontSet();
214 if (SetDescriptor(eCSSFontDesc_FontFeatureSettings
, aValue
, aRv
)) {
219 void FontFaceImpl::GetVariationSettings(nsACString
& aResult
) {
220 GetDesc(eCSSFontDesc_FontVariationSettings
, aResult
);
223 void FontFaceImpl::SetVariationSettings(const nsACString
& aValue
,
225 mFontFaceSet
->FlushUserFontSet();
226 if (SetDescriptor(eCSSFontDesc_FontVariationSettings
, aValue
, aRv
)) {
231 void FontFaceImpl::GetDisplay(nsACString
& aResult
) {
232 GetDesc(eCSSFontDesc_Display
, aResult
);
235 void FontFaceImpl::SetDisplay(const nsACString
& aValue
, ErrorResult
& aRv
) {
236 if (SetDescriptor(eCSSFontDesc_Display
, aValue
, aRv
)) {
241 void FontFaceImpl::GetAscentOverride(nsACString
& aResult
) {
242 GetDesc(eCSSFontDesc_AscentOverride
, aResult
);
245 void FontFaceImpl::SetAscentOverride(const nsACString
& aValue
,
247 if (SetDescriptor(eCSSFontDesc_AscentOverride
, aValue
, aRv
)) {
252 void FontFaceImpl::GetDescentOverride(nsACString
& aResult
) {
253 GetDesc(eCSSFontDesc_DescentOverride
, aResult
);
256 void FontFaceImpl::SetDescentOverride(const nsACString
& aValue
,
258 if (SetDescriptor(eCSSFontDesc_DescentOverride
, aValue
, aRv
)) {
263 void FontFaceImpl::GetLineGapOverride(nsACString
& aResult
) {
264 GetDesc(eCSSFontDesc_LineGapOverride
, aResult
);
267 void FontFaceImpl::SetLineGapOverride(const nsACString
& aValue
,
269 if (SetDescriptor(eCSSFontDesc_LineGapOverride
, aValue
, aRv
)) {
274 void FontFaceImpl::GetSizeAdjust(nsACString
& aResult
) {
275 GetDesc(eCSSFontDesc_SizeAdjust
, aResult
);
278 void FontFaceImpl::SetSizeAdjust(const nsACString
& aValue
, ErrorResult
& aRv
) {
279 if (SetDescriptor(eCSSFontDesc_SizeAdjust
, aValue
, aRv
)) {
284 void FontFaceImpl::DescriptorUpdated() {
285 // If we haven't yet initialized mUserFontEntry, no need to do anything here;
286 // we'll respect the updated descriptor when the time comes to create it.
287 if (!mUserFontEntry
) {
291 gfxUserFontAttributes attr
;
292 RefPtr
<gfxUserFontEntry
> newEntry
;
293 if (GetAttributes(attr
)) {
294 newEntry
= mFontFaceSet
->FindOrCreateUserFontEntryFromFontFace(
295 this, std::move(attr
), StyleOrigin::Author
);
297 SetUserFontEntry(newEntry
);
299 // Behind the scenes, this will actually update the existing entry and return
300 // it, rather than create a new one.
302 if (mInFontFaceSet
) {
303 mFontFaceSet
->MarkUserFontSetDirty();
305 for (auto& set
: mOtherFontFaceSets
) {
306 set
->MarkUserFontSetDirty();
310 FontFaceLoadStatus
FontFaceImpl::Status() { return mStatus
; }
312 void FontFaceImpl::Load(ErrorResult
& aRv
) {
313 mFontFaceSet
->FlushUserFontSet();
315 // Calling Load on a FontFace constructed with an ArrayBuffer data source,
316 // or on one that is already loading (or has finished loading), has no
318 if (mSourceType
== eSourceType_Buffer
||
319 mStatus
!= FontFaceLoadStatus::Unloaded
) {
323 // Calling the user font entry's Load method will end up setting our
324 // status to Loading, but the spec requires us to set it to Loading
326 SetStatus(FontFaceLoadStatus::Loading
);
331 gfxUserFontEntry
* FontFaceImpl::CreateUserFontEntry() {
332 if (!mUserFontEntry
) {
333 MOZ_ASSERT(!HasRule(),
334 "Rule backed FontFace objects should already have a user font "
335 "entry by the time Load() can be called on them");
337 gfxUserFontAttributes attr
;
338 if (GetAttributes(attr
)) {
339 RefPtr
<gfxUserFontEntry
> newEntry
=
340 mFontFaceSet
->FindOrCreateUserFontEntryFromFontFace(
341 this, std::move(attr
), StyleOrigin::Author
);
343 SetUserFontEntry(newEntry
);
348 return mUserFontEntry
;
351 void FontFaceImpl::DoLoad() {
352 if (!CreateUserFontEntry()) {
355 mUserFontEntry
->Load();
358 void FontFaceImpl::SetStatus(FontFaceLoadStatus aStatus
) {
359 gfxFontUtils::AssertSafeThreadOrServoFontMetricsLocked();
361 if (mStatus
== aStatus
) {
365 if (aStatus
< mStatus
) {
366 // We're being asked to go backwards in status! Normally, this shouldn't
367 // happen. But it can if the FontFace had a user font entry that had
368 // loaded, but then was given a new one by FontFaceSet::InsertRuleFontFace
369 // if we used a local() rule. For now, just ignore the request to
370 // go backwards in status.
376 if (mInFontFaceSet
) {
377 mFontFaceSet
->OnFontFaceStatusChanged(this);
380 for (FontFaceSetImpl
* otherSet
: mOtherFontFaceSets
) {
381 otherSet
->OnFontFaceStatusChanged(this);
384 UpdateOwnerPromise();
387 void FontFaceImpl::UpdateOwnerPromise() {
388 if (!mFontFaceSet
->IsOnOwningThread()) {
389 mFontFaceSet
->DispatchToOwningThread(
390 "FontFaceImpl::UpdateOwnerPromise",
391 [self
= RefPtr
{this}] { self
->UpdateOwnerPromise(); });
395 if (NS_WARN_IF(!mOwner
)) {
396 MOZ_DIAGNOSTIC_ASSERT(!mKeepingOwnerAlive
);
400 if (mStatus
== FontFaceLoadStatus::Loaded
) {
401 mOwner
->MaybeResolve();
402 } else if (mStatus
== FontFaceLoadStatus::Error
) {
403 if (mSourceType
== eSourceType_Buffer
) {
404 mOwner
->MaybeReject(NS_ERROR_DOM_SYNTAX_ERR
);
406 mOwner
->MaybeReject(NS_ERROR_DOM_NETWORK_ERR
);
410 const bool shouldKeepOwnerAlive
= mStatus
== FontFaceLoadStatus::Loading
;
411 if (shouldKeepOwnerAlive
!= mKeepingOwnerAlive
) {
412 mKeepingOwnerAlive
= shouldKeepOwnerAlive
;
413 if (shouldKeepOwnerAlive
) {
421 // Boolean result indicates whether the value of the descriptor was actually
423 bool FontFaceImpl::SetDescriptor(nsCSSFontDesc aFontDesc
,
424 const nsACString
& aValue
, ErrorResult
& aRv
) {
425 // FIXME We probably don't need to distinguish between this anymore
426 // since we have common backend now.
427 NS_ASSERTION(!HasRule(), "we don't handle rule backed FontFace objects yet");
432 RefPtr
<URLExtraData
> url
= mFontFaceSet
->GetURLExtraData();
433 if (NS_WARN_IF(!url
)) {
434 // This should only happen on worker threads, where we failed to initialize
435 // the worker before it was shutdown.
436 aRv
.ThrowInvalidStateError("Missing URLExtraData");
440 // FIXME(heycam): Should not allow modification of FontFaces that are
441 // CSS-connected and whose rule is read only.
443 if (!Servo_FontFaceRule_SetDescriptor(GetData(), aFontDesc
, &aValue
, url
,
445 aRv
.ThrowSyntaxError("Invalid font descriptor");
453 if (aFontDesc
== eCSSFontDesc_UnicodeRange
) {
454 mUnicodeRangeDirty
= true;
460 bool FontFaceImpl::SetDescriptors(const nsACString
& aFamily
,
461 const FontFaceDescriptors
& aDescriptors
) {
462 MOZ_ASSERT(!HasRule());
463 MOZ_ASSERT(!mDescriptors
);
465 mDescriptors
= Servo_FontFaceRule_CreateEmpty().Consume();
467 // Helper to call SetDescriptor and return true on success, false on failure.
468 auto setDesc
= [=](nsCSSFontDesc aDesc
, const nsACString
& aVal
) -> bool {
469 IgnoredErrorResult rv
;
470 SetDescriptor(aDesc
, aVal
, rv
);
474 // Parse all of the mDescriptors in aInitializer, which are the values
475 // we got from the JS constructor.
476 if (!setDesc(eCSSFontDesc_Family
, aFamily
) ||
477 !setDesc(eCSSFontDesc_Style
, aDescriptors
.mStyle
) ||
478 !setDesc(eCSSFontDesc_Weight
, aDescriptors
.mWeight
) ||
479 !setDesc(eCSSFontDesc_Stretch
, aDescriptors
.mStretch
) ||
480 !setDesc(eCSSFontDesc_UnicodeRange
, aDescriptors
.mUnicodeRange
) ||
481 !setDesc(eCSSFontDesc_FontFeatureSettings
,
482 aDescriptors
.mFeatureSettings
) ||
483 (StaticPrefs::layout_css_font_variations_enabled() &&
484 !setDesc(eCSSFontDesc_FontVariationSettings
,
485 aDescriptors
.mVariationSettings
)) ||
486 !setDesc(eCSSFontDesc_Display
, aDescriptors
.mDisplay
) ||
487 ((!setDesc(eCSSFontDesc_AscentOverride
, aDescriptors
.mAscentOverride
) ||
488 !setDesc(eCSSFontDesc_DescentOverride
, aDescriptors
.mDescentOverride
) ||
489 !setDesc(eCSSFontDesc_LineGapOverride
,
490 aDescriptors
.mLineGapOverride
))) ||
491 (StaticPrefs::layout_css_size_adjust_enabled() &&
492 !setDesc(eCSSFontDesc_SizeAdjust
, aDescriptors
.mSizeAdjust
))) {
493 // XXX Handle font-variant once we support it (bug 1055385).
495 // If any of the descriptors failed to parse, none of them should be set
497 mDescriptors
= Servo_FontFaceRule_CreateEmpty().Consume();
500 mOwner
->MaybeReject(NS_ERROR_DOM_SYNTAX_ERR
);
503 SetStatus(FontFaceLoadStatus::Error
);
510 void FontFaceImpl::GetDesc(nsCSSFontDesc aDescID
, nsACString
& aResult
) const {
512 Servo_FontFaceRule_GetDescriptorCssText(GetData(), aDescID
, &aResult
);
514 // Fill in a default value for missing descriptors.
515 if (aResult
.IsEmpty()) {
516 if (aDescID
== eCSSFontDesc_UnicodeRange
) {
517 aResult
.AssignLiteral("U+0-10FFFF");
518 } else if (aDescID
== eCSSFontDesc_Display
) {
519 aResult
.AssignLiteral("auto");
520 } else if (aDescID
!= eCSSFontDesc_Family
&& aDescID
!= eCSSFontDesc_Src
) {
521 aResult
.AssignLiteral("normal");
526 void FontFaceImpl::SetUserFontEntry(gfxUserFontEntry
* aEntry
) {
527 AssertIsOnOwningThread();
529 if (mUserFontEntry
== aEntry
) {
533 if (mUserFontEntry
) {
534 mUserFontEntry
->RemoveFontFace(this);
537 auto* entry
= static_cast<Entry
*>(aEntry
);
539 entry
->AddFontFace(this);
542 mUserFontEntry
= entry
;
544 if (!mUserFontEntry
) {
548 MOZ_ASSERT(mUserFontEntry
->HasUserFontSet(mFontFaceSet
),
549 "user font entry must be associated with the same user font set "
552 // Our newly assigned user font entry might be in the process of or
553 // finished loading, so set our status accordingly. But only do so
554 // if we're not going "backwards" in status, which could otherwise
555 // happen in this case:
557 // new FontFace("ABC", "url(x)").load();
559 // where the SetUserFontEntry call (from the after-initialization
560 // DoLoad call) comes after the author's call to load(), which set mStatus
562 FontFaceLoadStatus newStatus
= LoadStateToStatus(mUserFontEntry
->LoadState());
563 if (newStatus
> mStatus
) {
564 SetStatus(newStatus
);
568 bool FontFaceImpl::GetAttributes(gfxUserFontAttributes
& aAttr
) {
569 StyleLockedFontFaceRule
* data
= GetData();
574 nsAtom
* fontFamily
= Servo_FontFaceRule_GetFamilyName(data
);
579 aAttr
.mFamilyName
= nsAtomCString(fontFamily
);
581 StyleComputedFontWeightRange weightRange
;
582 if (Servo_FontFaceRule_GetFontWeight(data
, &weightRange
)) {
583 aAttr
.mRangeFlags
&= ~gfxFontEntry::RangeFlags::eAutoWeight
;
584 aAttr
.mWeight
= WeightRange(FontWeight::FromFloat(weightRange
._0
),
585 FontWeight::FromFloat(weightRange
._1
));
588 StyleComputedFontStretchRange stretchRange
;
589 if (Servo_FontFaceRule_GetFontStretch(data
, &stretchRange
)) {
590 aAttr
.mRangeFlags
&= ~gfxFontEntry::RangeFlags::eAutoStretch
;
591 aAttr
.mStretch
= StretchRange(stretchRange
._0
, stretchRange
._1
);
594 auto styleDesc
= StyleComputedFontStyleDescriptor::Normal();
595 if (Servo_FontFaceRule_GetFontStyle(data
, &styleDesc
)) {
596 aAttr
.mRangeFlags
&= ~gfxFontEntry::RangeFlags::eAutoSlantStyle
;
597 switch (styleDesc
.tag
) {
598 case StyleComputedFontStyleDescriptor::Tag::Normal
:
599 aAttr
.mStyle
= SlantStyleRange(FontSlantStyle::NORMAL
);
601 case StyleComputedFontStyleDescriptor::Tag::Italic
:
602 aAttr
.mStyle
= SlantStyleRange(FontSlantStyle::ITALIC
);
604 case StyleComputedFontStyleDescriptor::Tag::Oblique
:
605 aAttr
.mStyle
= SlantStyleRange(
606 FontSlantStyle::FromFloat(styleDesc
.AsOblique()._0
),
607 FontSlantStyle::FromFloat(styleDesc
.AsOblique()._1
));
610 MOZ_ASSERT_UNREACHABLE("Unhandled tag");
614 StylePercentage ascent
{0};
615 if (Servo_FontFaceRule_GetAscentOverride(data
, &ascent
)) {
616 aAttr
.mAscentOverride
= ascent
._0
;
619 StylePercentage descent
{0};
620 if (Servo_FontFaceRule_GetDescentOverride(data
, &descent
)) {
621 aAttr
.mDescentOverride
= descent
._0
;
624 StylePercentage lineGap
{0};
625 if (Servo_FontFaceRule_GetLineGapOverride(data
, &lineGap
)) {
626 aAttr
.mLineGapOverride
= lineGap
._0
;
629 StylePercentage sizeAdjust
;
630 if (Servo_FontFaceRule_GetSizeAdjust(data
, &sizeAdjust
)) {
631 aAttr
.mSizeAdjust
= sizeAdjust
._0
;
634 StyleFontLanguageOverride langOverride
;
635 if (Servo_FontFaceRule_GetFontLanguageOverride(data
, &langOverride
)) {
636 aAttr
.mLanguageOverride
= langOverride
._0
;
639 Servo_FontFaceRule_GetFontDisplay(data
, &aAttr
.mFontDisplay
);
640 Servo_FontFaceRule_GetFeatureSettings(data
, &aAttr
.mFeatureSettings
);
641 Servo_FontFaceRule_GetVariationSettings(data
, &aAttr
.mVariationSettings
);
642 Servo_FontFaceRule_GetSources(data
, &aAttr
.mSources
);
643 aAttr
.mUnicodeRanges
= GetUnicodeRangeAsCharacterMap();
647 bool FontFaceImpl::HasLocalSrc() const {
648 AutoTArray
<StyleFontFaceSourceListComponent
, 8> components
;
649 Servo_FontFaceRule_GetSources(GetData(), &components
);
650 for (auto& component
: components
) {
651 if (component
.tag
== StyleFontFaceSourceListComponent::Tag::Local
) {
658 nsAtom
* FontFaceImpl::GetFamilyName() const {
659 return Servo_FontFaceRule_GetFamilyName(GetData());
662 void FontFaceImpl::DisconnectFromRule() {
663 MOZ_ASSERT(HasRule());
665 // Make a copy of the descriptors.
666 mDescriptors
= Servo_FontFaceRule_Clone(mRule
).Consume();
668 mInFontFaceSet
= false;
671 bool FontFaceImpl::HasFontData() const {
672 return mSourceType
== eSourceType_Buffer
&& mBufferSource
;
675 already_AddRefed
<gfxFontFaceBufferSource
> FontFaceImpl::TakeBufferSource() {
676 MOZ_ASSERT(mBufferSource
);
677 return mBufferSource
.forget();
680 bool FontFaceImpl::IsInFontFaceSet(FontFaceSetImpl
* aFontFaceSet
) const {
681 if (mFontFaceSet
== aFontFaceSet
) {
682 return mInFontFaceSet
;
684 return mOtherFontFaceSets
.Contains(aFontFaceSet
);
687 void FontFaceImpl::AddFontFaceSet(FontFaceSetImpl
* aFontFaceSet
) {
688 MOZ_ASSERT(!IsInFontFaceSet(aFontFaceSet
));
690 auto doAddFontFaceSet
= [&]() {
691 if (mFontFaceSet
== aFontFaceSet
) {
692 mInFontFaceSet
= true;
694 mOtherFontFaceSets
.AppendElement(aFontFaceSet
);
698 if (mUserFontEntry
) {
699 AutoWriteLock
lock(mUserFontEntry
->Lock());
706 void FontFaceImpl::RemoveFontFaceSet(FontFaceSetImpl
* aFontFaceSet
) {
707 MOZ_ASSERT(IsInFontFaceSet(aFontFaceSet
));
709 auto doRemoveFontFaceSet
= [&]() {
710 if (mFontFaceSet
== aFontFaceSet
) {
711 mInFontFaceSet
= false;
713 mOtherFontFaceSets
.RemoveElement(aFontFaceSet
);
717 if (mUserFontEntry
) {
718 AutoWriteLock
lock(mUserFontEntry
->Lock());
719 doRemoveFontFaceSet();
720 // The caller should be holding a strong reference to the FontFaceSetImpl.
721 mUserFontEntry
->CheckUserFontSetLocked();
723 doRemoveFontFaceSet();
727 gfxCharacterMap
* FontFaceImpl::GetUnicodeRangeAsCharacterMap() {
728 if (!mUnicodeRangeDirty
) {
729 return mUnicodeRange
;
733 const StyleUnicodeRange
* rangesPtr
=
734 Servo_FontFaceRule_GetUnicodeRanges(GetData(), &len
);
736 Span
<const StyleUnicodeRange
> ranges(rangesPtr
, len
);
737 if (!ranges
.IsEmpty()) {
738 auto charMap
= MakeRefPtr
<gfxCharacterMap
>();
739 for (auto& range
: ranges
) {
740 charMap
->SetRange(range
.start
, range
.end
);
743 // As it's common for multiple font resources to have the same
744 // unicode-range list, look for an existing copy of this map to share,
745 // or add this one to the sharing cache if not already present.
747 gfxPlatformFontList::PlatformFontList()->FindCharMap(charMap
);
749 mUnicodeRange
= nullptr;
752 mUnicodeRangeDirty
= false;
753 return mUnicodeRange
;
756 // -- FontFaceImpl::Entry
757 // --------------------------------------------------------
760 void FontFaceImpl::Entry::SetLoadState(UserFontLoadState aLoadState
) {
761 gfxUserFontEntry::SetLoadState(aLoadState
);
762 FontFaceLoadStatus status
= LoadStateToStatus(aLoadState
);
764 nsTArray
<RefPtr
<FontFaceImpl
>> fontFaces
;
766 AutoReadLock
lock(mLock
);
767 fontFaces
.SetCapacity(mFontFaces
.Length());
768 for (FontFaceImpl
* f
: mFontFaces
) {
769 fontFaces
.AppendElement(f
);
773 for (FontFaceImpl
* impl
: fontFaces
) {
774 auto* setImpl
= impl
->GetPrimaryFontFaceSet();
775 if (setImpl
->IsOnOwningThread()) {
776 impl
->SetStatus(status
);
778 setImpl
->DispatchToOwningThread(
779 "FontFaceImpl::Entry::SetLoadState",
780 [self
= RefPtr
{impl
}, status
] { self
->SetStatus(status
); });
786 void FontFaceImpl::Entry::GetUserFontSets(
787 nsTArray
<RefPtr
<gfxUserFontSet
>>& aResult
) {
788 AutoReadLock
lock(mLock
);
793 aResult
.AppendElement(mFontSet
);
796 for (FontFaceImpl
* f
: mFontFaces
) {
797 if (f
->mInFontFaceSet
) {
798 aResult
.AppendElement(f
->mFontFaceSet
);
800 for (FontFaceSetImpl
* s
: f
->mOtherFontFaceSets
) {
801 aResult
.AppendElement(s
);
805 // Remove duplicates.
807 auto it
= std::unique(aResult
.begin(), aResult
.end());
808 aResult
.TruncateLength(it
- aResult
.begin());
811 /* virtual */ already_AddRefed
<gfxUserFontSet
>
812 FontFaceImpl::Entry::GetUserFontSet() const {
813 AutoReadLock
lock(mLock
);
815 return do_AddRef(mFontSet
);
817 if (NS_IsMainThread() && mLoadingFontSet
) {
818 return do_AddRef(mLoadingFontSet
);
823 void FontFaceImpl::Entry::CheckUserFontSetLocked() {
824 // If this is the last font containing a strong reference to the set, we need
825 // to clear the reference as there is no longer anything guaranteeing the set
826 // will be kept alive.
828 auto* set
= static_cast<FontFaceSetImpl
*>(mFontSet
);
829 for (FontFaceImpl
* f
: mFontFaces
) {
830 if (f
->mFontFaceSet
== set
|| f
->mOtherFontFaceSets
.Contains(set
)) {
836 // If possible, promote the most recently added FontFace and its owning
837 // FontFaceSetImpl as the primary set.
838 if (!mFontFaces
.IsEmpty()) {
839 mFontSet
= mFontFaces
.LastElement()->mFontFaceSet
;
845 void FontFaceImpl::Entry::FindFontFaceOwners(nsTHashSet
<FontFace
*>& aOwners
) {
846 AutoReadLock
lock(mLock
);
847 for (FontFaceImpl
* f
: mFontFaces
) {
848 if (FontFace
* owner
= f
->GetOwner()) {
849 aOwners
.Insert(owner
);
854 void FontFaceImpl::Entry::AddFontFace(FontFaceImpl
* aFontFace
) {
855 AutoWriteLock
lock(mLock
);
856 mFontFaces
.AppendElement(aFontFace
);
857 CheckUserFontSetLocked();
860 void FontFaceImpl::Entry::RemoveFontFace(FontFaceImpl
* aFontFace
) {
861 AutoWriteLock
lock(mLock
);
862 mFontFaces
.RemoveElement(aFontFace
);
863 CheckUserFontSetLocked();
867 } // namespace mozilla