Bug 1861709 replace AudioCallbackDriver::ThreadRunning() assertions that mean to...
[gecko.git] / layout / style / FontFaceImpl.cpp
blob7fb4ba1c0498863e05779a248160d079f8b0f7a1
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"
9 #include <algorithm>
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"
24 namespace mozilla {
25 namespace dom {
27 // -- FontFaceBufferSource ---------------------------------------------------
29 /**
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 {
34 public:
35 FontFaceBufferSource(uint8_t* aBuffer, uint32_t aLength)
36 : mBuffer(aBuffer), mLength(aLength) {}
38 void TakeBuffer(uint8_t*& aBuffer, uint32_t& aLength) override {
39 MOZ_ASSERT(mBuffer,
40 "only call TakeBuffer once on a given "
41 "FontFaceBufferSource object");
42 aBuffer = mBuffer;
43 aLength = mLength;
44 mBuffer = nullptr;
45 mLength = 0;
48 private:
49 ~FontFaceBufferSource() override {
50 if (mBuffer) {
51 free(mBuffer);
55 uint8_t* mBuffer;
56 uint32_t mLength;
59 // -- FontFaceImpl -----------------------------------------------------------
61 FontFaceImpl::FontFaceImpl(FontFace* aOwner, FontFaceSetImpl* aFontFaceSet)
62 : mOwner(aOwner),
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);
77 #ifdef DEBUG
78 void FontFaceImpl::AssertIsOnOwningThread() const {
79 mFontFaceSet->AssertIsOnOwningThread();
81 #endif
83 void FontFaceImpl::Destroy() {
84 mInFontFaceSet = false;
85 SetUserFontEntry(nullptr);
86 mOwner = nullptr;
89 static FontFaceLoadStatus LoadStateToStatus(
90 gfxUserFontEntry::UserFontLoadState aLoadState) {
91 switch (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);
110 obj->mRule = aRule;
111 obj->mSourceType = eSourceType_FontFaceRule;
112 obj->mInFontFaceSet = true;
113 return obj.forget();
116 void FontFaceImpl::InitializeSourceURL(const nsACString& aURL) {
117 MOZ_ASSERT(mOwner);
118 mSourceType = eSourceType_URLs;
120 IgnoredErrorResult rv;
121 SetDescriptor(eCSSFontDesc_Src, aURL, rv);
122 if (rv.Failed()) {
123 mOwner->MaybeReject(NS_ERROR_DOM_SYNTAX_ERR);
124 SetStatus(FontFaceLoadStatus::Error);
128 void FontFaceImpl::InitializeSourceBuffer(uint8_t* aBuffer, uint32_t aLength) {
129 MOZ_ASSERT(mOwner);
130 MOZ_ASSERT(!mBufferSource);
131 mSourceType = FontFaceImpl::eSourceType_Buffer;
133 if (aBuffer) {
134 mBufferSource = new FontFaceBufferSource(aBuffer, aLength);
137 SetStatus(FontFaceLoadStatus::Loading);
138 DoLoad();
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)) {
148 DescriptorUpdated();
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)) {
158 DescriptorUpdated();
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)) {
169 DescriptorUpdated();
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)) {
180 DescriptorUpdated();
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)) {
191 DescriptorUpdated();
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,
211 ErrorResult& aRv) {
212 mFontFaceSet->FlushUserFontSet();
213 if (SetDescriptor(eCSSFontDesc_FontFeatureSettings, aValue, aRv)) {
214 DescriptorUpdated();
218 void FontFaceImpl::GetVariationSettings(nsACString& aResult) {
219 GetDesc(eCSSFontDesc_FontVariationSettings, aResult);
222 void FontFaceImpl::SetVariationSettings(const nsACString& aValue,
223 ErrorResult& aRv) {
224 mFontFaceSet->FlushUserFontSet();
225 if (SetDescriptor(eCSSFontDesc_FontVariationSettings, aValue, aRv)) {
226 DescriptorUpdated();
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)) {
236 DescriptorUpdated();
240 void FontFaceImpl::GetAscentOverride(nsACString& aResult) {
241 GetDesc(eCSSFontDesc_AscentOverride, aResult);
244 void FontFaceImpl::SetAscentOverride(const nsACString& aValue,
245 ErrorResult& aRv) {
246 if (SetDescriptor(eCSSFontDesc_AscentOverride, aValue, aRv)) {
247 DescriptorUpdated();
251 void FontFaceImpl::GetDescentOverride(nsACString& aResult) {
252 GetDesc(eCSSFontDesc_DescentOverride, aResult);
255 void FontFaceImpl::SetDescentOverride(const nsACString& aValue,
256 ErrorResult& aRv) {
257 if (SetDescriptor(eCSSFontDesc_DescentOverride, aValue, aRv)) {
258 DescriptorUpdated();
262 void FontFaceImpl::GetLineGapOverride(nsACString& aResult) {
263 GetDesc(eCSSFontDesc_LineGapOverride, aResult);
266 void FontFaceImpl::SetLineGapOverride(const nsACString& aValue,
267 ErrorResult& aRv) {
268 if (SetDescriptor(eCSSFontDesc_LineGapOverride, aValue, aRv)) {
269 DescriptorUpdated();
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)) {
279 DescriptorUpdated();
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) {
287 return;
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
316 // effect.
317 if (mSourceType == eSourceType_Buffer ||
318 mStatus != FontFaceLoadStatus::Unloaded) {
319 return;
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
324 // here.
325 SetStatus(FontFaceLoadStatus::Loading);
327 DoLoad();
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);
341 if (newEntry) {
342 SetUserFontEntry(newEntry);
347 return mUserFontEntry;
350 void FontFaceImpl::DoLoad() {
351 if (!CreateUserFontEntry()) {
352 return;
355 if (!NS_IsMainThread()) {
356 NS_DispatchToMainThread(NS_NewRunnableFunction(
357 "FontFaceImpl::DoLoad",
358 [entry = RefPtr{mUserFontEntry}]() { entry->Load(); }));
359 return;
362 mUserFontEntry->Load();
365 void FontFaceImpl::SetStatus(FontFaceLoadStatus aStatus) {
366 gfxFontUtils::AssertSafeThreadOrServoFontMetricsLocked();
368 if (mStatus == aStatus) {
369 return;
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.
378 return;
381 mStatus = aStatus;
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(); });
399 return;
402 if (NS_WARN_IF(!mOwner)) {
403 return;
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);
411 } else {
412 mOwner->MaybeReject(NS_ERROR_DOM_NETWORK_ERR);
417 // Boolean result indicates whether the value of the descriptor was actually
418 // changed.
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");
424 if (HasRule()) {
425 return false;
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");
433 return false;
436 // FIXME(heycam): Should not allow modification of FontFaces that are
437 // CSS-connected and whose rule is read only.
438 bool changed;
439 if (!Servo_FontFaceRule_SetDescriptor(GetData(), aFontDesc, &aValue, url,
440 &changed)) {
441 aRv.ThrowSyntaxError("Invalid font descriptor");
442 return false;
445 if (!changed) {
446 return false;
449 if (aFontDesc == eCSSFontDesc_UnicodeRange) {
450 mUnicodeRangeDirty = true;
453 return 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);
467 return !rv.Failed();
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
492 // on the FontFace.
493 mDescriptors = Servo_FontFaceRule_CreateEmpty().Consume();
495 if (mOwner) {
496 mOwner->MaybeReject(NS_ERROR_DOM_SYNTAX_ERR);
499 SetStatus(FontFaceLoadStatus::Error);
500 return false;
503 return true;
506 void FontFaceImpl::GetDesc(nsCSSFontDesc aDescID, nsACString& aResult) const {
507 aResult.Truncate();
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) {
526 return;
529 if (mUserFontEntry) {
530 mUserFontEntry->RemoveFontFace(this);
533 auto* entry = static_cast<Entry*>(aEntry);
534 if (entry) {
535 entry->AddFontFace(this);
538 mUserFontEntry = entry;
540 if (!mUserFontEntry) {
541 return;
544 MOZ_ASSERT(mUserFontEntry->HasUserFontSet(mFontFaceSet),
545 "user font entry must be associated with the same user font set "
546 "as the FontFace");
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
557 // to Loading.
558 FontFaceLoadStatus newStatus = LoadStateToStatus(mUserFontEntry->LoadState());
559 if (newStatus > mStatus) {
560 SetStatus(newStatus);
564 bool FontFaceImpl::GetAttributes(gfxUserFontAttributes& aAttr) {
565 StyleLockedFontFaceRule* data = GetData();
566 if (!data) {
567 return false;
570 nsAtom* fontFamily = Servo_FontFaceRule_GetFamilyName(data);
571 if (!fontFamily) {
572 return false;
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);
596 break;
597 case StyleComputedFontStyleDescriptor::Tag::Italic:
598 aAttr.mStyle = SlantStyleRange(FontSlantStyle::ITALIC);
599 break;
600 case StyleComputedFontStyleDescriptor::Tag::Oblique:
601 aAttr.mStyle = SlantStyleRange(
602 FontSlantStyle::FromFloat(styleDesc.AsOblique()._0),
603 FontSlantStyle::FromFloat(styleDesc.AsOblique()._1));
604 break;
605 default:
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();
640 return true;
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) {
648 return true;
651 return false;
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();
663 mRule = nullptr;
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;
688 } else {
689 mOtherFontFaceSets.AppendElement(aFontFaceSet);
693 void FontFaceImpl::RemoveFontFaceSet(FontFaceSetImpl* aFontFaceSet) {
694 MOZ_ASSERT(IsInFontFaceSet(aFontFaceSet));
696 if (mFontFaceSet == aFontFaceSet) {
697 mInFontFaceSet = false;
698 } else {
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;
713 size_t len;
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);
723 charMap->Compact();
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.
727 mUnicodeRange =
728 gfxPlatformFontList::PlatformFontList()->FindCharMap(charMap);
729 } else {
730 mUnicodeRange = nullptr;
733 mUnicodeRangeDirty = false;
734 return mUnicodeRange;
737 // -- FontFaceImpl::Entry
738 // --------------------------------------------------------
740 /* virtual */
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);
758 } else {
759 setImpl->DispatchToOwningThread(
760 "FontFaceImpl::Entry::SetLoadState",
761 [self = RefPtr{impl}, status] { self->SetStatus(status); });
766 /* virtual */
767 void FontFaceImpl::Entry::GetUserFontSets(
768 nsTArray<RefPtr<gfxUserFontSet>>& aResult) {
769 MutexAutoLock lock(mMutex);
771 aResult.Clear();
773 if (mFontSet) {
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.
787 aResult.Sort();
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);
795 if (mFontSet) {
796 return do_AddRef(mFontSet);
798 if (NS_IsMainThread() && mLoadingFontSet) {
799 return do_AddRef(mLoadingFontSet);
801 return nullptr;
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.
808 if (mFontSet) {
809 auto* set = static_cast<FontFaceSetImpl*>(mFontSet);
810 for (FontFaceImpl* f : mFontFaces) {
811 if (f->mFontFaceSet == set || f->mOtherFontFaceSets.Contains(set)) {
812 return;
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;
821 } else {
822 mFontSet = nullptr;
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();
847 } // namespace dom
848 } // namespace mozilla