Backed out 3 changesets (bug 1918178) for causing reftest failures. a=backout
[gecko.git] / layout / style / FontFaceImpl.cpp
blobbaa4acdd06dcfcda511901e4f3383d9b6adb0885
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/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"
18 namespace mozilla {
19 namespace dom {
21 // -- FontFaceBufferSource ---------------------------------------------------
23 /**
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 {
28 public:
29 FontFaceBufferSource(uint8_t* aBuffer, uint32_t aLength)
30 : mBuffer(aBuffer), mLength(aLength) {}
32 void TakeBuffer(uint8_t*& aBuffer, uint32_t& aLength) override {
33 MOZ_ASSERT(mBuffer,
34 "only call TakeBuffer once on a given "
35 "FontFaceBufferSource object");
36 aBuffer = mBuffer;
37 aLength = mLength;
38 mBuffer = nullptr;
39 mLength = 0;
42 private:
43 ~FontFaceBufferSource() override {
44 if (mBuffer) {
45 free(mBuffer);
49 uint8_t* mBuffer;
50 uint32_t mLength;
53 // -- FontFaceImpl -----------------------------------------------------------
55 FontFaceImpl::FontFaceImpl(FontFace* aOwner, FontFaceSetImpl* aFontFaceSet)
56 : mOwner(aOwner),
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);
69 #ifdef DEBUG
70 void FontFaceImpl::AssertIsOnOwningThread() const {
71 mFontFaceSet->AssertIsOnOwningThread();
73 #endif
75 void FontFaceImpl::StopKeepingOwnerAlive() {
76 if (mKeepingOwnerAlive) {
77 mKeepingOwnerAlive = false;
78 MOZ_ASSERT(mOwner);
79 mOwner->Release();
83 void FontFaceImpl::Destroy() {
84 mInFontFaceSet = false;
85 SetUserFontEntry(nullptr);
86 StopKeepingOwnerAlive();
87 mOwner = nullptr;
90 static FontFaceLoadStatus LoadStateToStatus(
91 gfxUserFontEntry::UserFontLoadState aLoadState) {
92 switch (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);
111 obj->mRule = aRule;
112 obj->mSourceType = eSourceType_FontFaceRule;
113 obj->mInFontFaceSet = true;
114 return obj.forget();
117 void FontFaceImpl::InitializeSourceURL(const nsACString& aURL) {
118 MOZ_ASSERT(mOwner);
119 mSourceType = eSourceType_URLs;
121 IgnoredErrorResult rv;
122 SetDescriptor(eCSSFontDesc_Src, aURL, rv);
123 if (rv.Failed()) {
124 mOwner->MaybeReject(NS_ERROR_DOM_SYNTAX_ERR);
125 SetStatus(FontFaceLoadStatus::Error);
129 void FontFaceImpl::InitializeSourceBuffer(uint8_t* aBuffer, uint32_t aLength) {
130 MOZ_ASSERT(mOwner);
131 MOZ_ASSERT(!mBufferSource);
132 mSourceType = FontFaceImpl::eSourceType_Buffer;
134 if (aBuffer) {
135 mBufferSource = new FontFaceBufferSource(aBuffer, aLength);
138 SetStatus(FontFaceLoadStatus::Loading);
139 DoLoad();
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)) {
149 DescriptorUpdated();
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)) {
159 DescriptorUpdated();
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)) {
170 DescriptorUpdated();
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)) {
181 DescriptorUpdated();
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)) {
192 DescriptorUpdated();
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,
212 ErrorResult& aRv) {
213 mFontFaceSet->FlushUserFontSet();
214 if (SetDescriptor(eCSSFontDesc_FontFeatureSettings, aValue, aRv)) {
215 DescriptorUpdated();
219 void FontFaceImpl::GetVariationSettings(nsACString& aResult) {
220 GetDesc(eCSSFontDesc_FontVariationSettings, aResult);
223 void FontFaceImpl::SetVariationSettings(const nsACString& aValue,
224 ErrorResult& aRv) {
225 mFontFaceSet->FlushUserFontSet();
226 if (SetDescriptor(eCSSFontDesc_FontVariationSettings, aValue, aRv)) {
227 DescriptorUpdated();
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)) {
237 DescriptorUpdated();
241 void FontFaceImpl::GetAscentOverride(nsACString& aResult) {
242 GetDesc(eCSSFontDesc_AscentOverride, aResult);
245 void FontFaceImpl::SetAscentOverride(const nsACString& aValue,
246 ErrorResult& aRv) {
247 if (SetDescriptor(eCSSFontDesc_AscentOverride, aValue, aRv)) {
248 DescriptorUpdated();
252 void FontFaceImpl::GetDescentOverride(nsACString& aResult) {
253 GetDesc(eCSSFontDesc_DescentOverride, aResult);
256 void FontFaceImpl::SetDescentOverride(const nsACString& aValue,
257 ErrorResult& aRv) {
258 if (SetDescriptor(eCSSFontDesc_DescentOverride, aValue, aRv)) {
259 DescriptorUpdated();
263 void FontFaceImpl::GetLineGapOverride(nsACString& aResult) {
264 GetDesc(eCSSFontDesc_LineGapOverride, aResult);
267 void FontFaceImpl::SetLineGapOverride(const nsACString& aValue,
268 ErrorResult& aRv) {
269 if (SetDescriptor(eCSSFontDesc_LineGapOverride, aValue, aRv)) {
270 DescriptorUpdated();
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)) {
280 DescriptorUpdated();
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) {
288 return;
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
317 // effect.
318 if (mSourceType == eSourceType_Buffer ||
319 mStatus != FontFaceLoadStatus::Unloaded) {
320 return;
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
325 // here.
326 SetStatus(FontFaceLoadStatus::Loading);
328 DoLoad();
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);
342 if (newEntry) {
343 SetUserFontEntry(newEntry);
348 return mUserFontEntry;
351 void FontFaceImpl::DoLoad() {
352 if (!CreateUserFontEntry()) {
353 return;
355 mUserFontEntry->Load();
358 void FontFaceImpl::SetStatus(FontFaceLoadStatus aStatus) {
359 gfxFontUtils::AssertSafeThreadOrServoFontMetricsLocked();
361 if (mStatus == aStatus) {
362 return;
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.
371 return;
374 mStatus = aStatus;
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(); });
392 return;
395 if (NS_WARN_IF(!mOwner)) {
396 MOZ_DIAGNOSTIC_ASSERT(!mKeepingOwnerAlive);
397 return;
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);
405 } else {
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) {
414 mOwner->AddRef();
415 } else {
416 mOwner->Release();
421 // Boolean result indicates whether the value of the descriptor was actually
422 // changed.
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");
428 if (HasRule()) {
429 return false;
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");
437 return false;
440 // FIXME(heycam): Should not allow modification of FontFaces that are
441 // CSS-connected and whose rule is read only.
442 bool changed;
443 if (!Servo_FontFaceRule_SetDescriptor(GetData(), aFontDesc, &aValue, url,
444 &changed)) {
445 aRv.ThrowSyntaxError("Invalid font descriptor");
446 return false;
449 if (!changed) {
450 return false;
453 if (aFontDesc == eCSSFontDesc_UnicodeRange) {
454 mUnicodeRangeDirty = true;
457 return 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);
471 return !rv.Failed();
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
496 // on the FontFace.
497 mDescriptors = Servo_FontFaceRule_CreateEmpty().Consume();
499 if (mOwner) {
500 mOwner->MaybeReject(NS_ERROR_DOM_SYNTAX_ERR);
503 SetStatus(FontFaceLoadStatus::Error);
504 return false;
507 return true;
510 void FontFaceImpl::GetDesc(nsCSSFontDesc aDescID, nsACString& aResult) const {
511 aResult.Truncate();
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) {
530 return;
533 if (mUserFontEntry) {
534 mUserFontEntry->RemoveFontFace(this);
537 auto* entry = static_cast<Entry*>(aEntry);
538 if (entry) {
539 entry->AddFontFace(this);
542 mUserFontEntry = entry;
544 if (!mUserFontEntry) {
545 return;
548 MOZ_ASSERT(mUserFontEntry->HasUserFontSet(mFontFaceSet),
549 "user font entry must be associated with the same user font set "
550 "as the FontFace");
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
561 // to Loading.
562 FontFaceLoadStatus newStatus = LoadStateToStatus(mUserFontEntry->LoadState());
563 if (newStatus > mStatus) {
564 SetStatus(newStatus);
568 bool FontFaceImpl::GetAttributes(gfxUserFontAttributes& aAttr) {
569 StyleLockedFontFaceRule* data = GetData();
570 if (!data) {
571 return false;
574 nsAtom* fontFamily = Servo_FontFaceRule_GetFamilyName(data);
575 if (!fontFamily) {
576 return false;
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);
600 break;
601 case StyleComputedFontStyleDescriptor::Tag::Italic:
602 aAttr.mStyle = SlantStyleRange(FontSlantStyle::ITALIC);
603 break;
604 case StyleComputedFontStyleDescriptor::Tag::Oblique:
605 aAttr.mStyle = SlantStyleRange(
606 FontSlantStyle::FromFloat(styleDesc.AsOblique()._0),
607 FontSlantStyle::FromFloat(styleDesc.AsOblique()._1));
608 break;
609 default:
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();
644 return true;
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) {
652 return true;
655 return false;
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();
667 mRule = nullptr;
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;
693 } else {
694 mOtherFontFaceSets.AppendElement(aFontFaceSet);
698 if (mUserFontEntry) {
699 AutoWriteLock lock(mUserFontEntry->Lock());
700 doAddFontFaceSet();
701 } else {
702 doAddFontFaceSet();
706 void FontFaceImpl::RemoveFontFaceSet(FontFaceSetImpl* aFontFaceSet) {
707 MOZ_ASSERT(IsInFontFaceSet(aFontFaceSet));
709 auto doRemoveFontFaceSet = [&]() {
710 if (mFontFaceSet == aFontFaceSet) {
711 mInFontFaceSet = false;
712 } else {
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();
722 } else {
723 doRemoveFontFaceSet();
727 gfxCharacterMap* FontFaceImpl::GetUnicodeRangeAsCharacterMap() {
728 if (!mUnicodeRangeDirty) {
729 return mUnicodeRange;
732 size_t len;
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);
742 charMap->Compact();
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.
746 mUnicodeRange =
747 gfxPlatformFontList::PlatformFontList()->FindCharMap(charMap);
748 } else {
749 mUnicodeRange = nullptr;
752 mUnicodeRangeDirty = false;
753 return mUnicodeRange;
756 // -- FontFaceImpl::Entry
757 // --------------------------------------------------------
759 /* virtual */
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);
777 } else {
778 setImpl->DispatchToOwningThread(
779 "FontFaceImpl::Entry::SetLoadState",
780 [self = RefPtr{impl}, status] { self->SetStatus(status); });
785 /* virtual */
786 void FontFaceImpl::Entry::GetUserFontSets(
787 nsTArray<RefPtr<gfxUserFontSet>>& aResult) {
788 AutoReadLock lock(mLock);
790 aResult.Clear();
792 if (mFontSet) {
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.
806 aResult.Sort();
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);
814 if (mFontSet) {
815 return do_AddRef(mFontSet);
817 if (NS_IsMainThread() && mLoadingFontSet) {
818 return do_AddRef(mLoadingFontSet);
820 return nullptr;
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.
827 if (mFontSet) {
828 auto* set = static_cast<FontFaceSetImpl*>(mFontSet);
829 for (FontFaceImpl* f : mFontFaces) {
830 if (f->mFontFaceSet == set || f->mOtherFontFaceSets.Contains(set)) {
831 return;
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;
840 } else {
841 mFontSet = nullptr;
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();
866 } // namespace dom
867 } // namespace mozilla