Bug 1635702 [wpt PR 23413] - Move some internal scroll anchoring tests to wpt, a...
[gecko.git] / layout / style / FontFace.cpp
blob2fc0a766e68598d72e32e50f4ad57bba1cb06cc0
1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
3 /* This Source Code Form is subject to the terms of the Mozilla Public
4 * License, v. 2.0. If a copy of the MPL was not distributed with this
5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
7 #include "mozilla/dom/FontFace.h"
9 #include <algorithm>
10 #include "mozilla/dom/CSSFontFaceRule.h"
11 #include "mozilla/dom/FontFaceBinding.h"
12 #include "mozilla/dom/FontFaceSet.h"
13 #include "mozilla/dom/Promise.h"
14 #include "mozilla/dom/TypedArray.h"
15 #include "mozilla/dom/UnionTypes.h"
16 #include "mozilla/CycleCollectedJSContext.h"
17 #include "mozilla/ServoBindings.h"
18 #include "mozilla/ServoCSSParser.h"
19 #include "mozilla/ServoStyleSet.h"
20 #include "mozilla/ServoUtils.h"
21 #include "mozilla/StaticPrefs_layout.h"
22 #include "mozilla/dom/Document.h"
23 #include "nsStyleUtil.h"
25 namespace mozilla {
26 namespace dom {
28 // -- FontFaceBufferSource ---------------------------------------------------
30 /**
31 * An object that wraps a FontFace object and exposes its ArrayBuffer
32 * or ArrayBufferView data in a form the user font set can consume.
34 class FontFaceBufferSource : public gfxFontFaceBufferSource {
35 public:
36 explicit FontFaceBufferSource(FontFace* aFontFace) : mFontFace(aFontFace) {}
37 virtual void TakeBuffer(uint8_t*& aBuffer, uint32_t& aLength) override;
39 private:
40 RefPtr<FontFace> mFontFace;
43 void FontFaceBufferSource::TakeBuffer(uint8_t*& aBuffer, uint32_t& aLength) {
44 MOZ_ASSERT(mFontFace,
45 "only call TakeBuffer once on a given "
46 "FontFaceBufferSource object");
47 mFontFace->TakeBuffer(aBuffer, aLength);
48 mFontFace = nullptr;
51 // -- Utility functions ------------------------------------------------------
53 template <typename T>
54 static void GetDataFrom(const T& aObject, uint8_t*& aBuffer,
55 uint32_t& aLength) {
56 MOZ_ASSERT(!aBuffer);
57 aObject.ComputeState();
58 // We use malloc here rather than a FallibleTArray or fallible
59 // operator new[] since the gfxUserFontEntry will be calling free
60 // on it.
61 aBuffer = (uint8_t*)malloc(aObject.Length());
62 if (!aBuffer) {
63 return;
65 memcpy((void*)aBuffer, aObject.Data(), aObject.Length());
66 aLength = aObject.Length();
69 // -- FontFace ---------------------------------------------------------------
71 NS_IMPL_CYCLE_COLLECTION_CLASS(FontFace)
73 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(FontFace)
74 NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mParent)
75 NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mLoaded)
76 NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mFontFaceSet)
77 NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mOtherFontFaceSets)
78 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
80 NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(FontFace)
81 NS_IMPL_CYCLE_COLLECTION_UNLINK(mParent)
82 NS_IMPL_CYCLE_COLLECTION_UNLINK(mLoaded)
83 NS_IMPL_CYCLE_COLLECTION_UNLINK(mFontFaceSet)
84 tmp->mInFontFaceSet = false;
85 tmp->SetUserFontEntry(nullptr);
86 NS_IMPL_CYCLE_COLLECTION_UNLINK(mOtherFontFaceSets)
87 NS_IMPL_CYCLE_COLLECTION_UNLINK_PRESERVED_WRAPPER
88 NS_IMPL_CYCLE_COLLECTION_UNLINK_END
90 NS_IMPL_CYCLE_COLLECTION_TRACE_BEGIN(FontFace)
91 NS_IMPL_CYCLE_COLLECTION_TRACE_PRESERVED_WRAPPER
92 NS_IMPL_CYCLE_COLLECTION_TRACE_END
94 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(FontFace)
95 NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY
96 NS_INTERFACE_MAP_ENTRY(nsISupports)
97 NS_INTERFACE_MAP_END
99 NS_IMPL_CYCLE_COLLECTING_ADDREF(FontFace)
100 NS_IMPL_CYCLE_COLLECTING_RELEASE(FontFace)
102 FontFace::FontFace(nsISupports* aParent, FontFaceSet* aFontFaceSet)
103 : mParent(aParent),
104 mLoadedRejection(NS_OK),
105 mStatus(FontFaceLoadStatus::Unloaded),
106 mSourceType(SourceType(0)),
107 mSourceBuffer(nullptr),
108 mSourceBufferLength(0),
109 mFontFaceSet(aFontFaceSet),
110 mUnicodeRangeDirty(true),
111 mInFontFaceSet(false) {}
113 FontFace::~FontFace() {
114 // Assert that we don't drop any FontFace objects during a Servo traversal,
115 // since PostTraversalTask objects can hold raw pointers to FontFaces.
116 MOZ_ASSERT(!ServoStyleSet::IsInServoTraversal());
118 SetUserFontEntry(nullptr);
120 if (mSourceBuffer) {
121 free(mSourceBuffer);
125 JSObject* FontFace::WrapObject(JSContext* aCx,
126 JS::Handle<JSObject*> aGivenProto) {
127 return FontFace_Binding::Wrap(aCx, this, aGivenProto);
130 static FontFaceLoadStatus LoadStateToStatus(
131 gfxUserFontEntry::UserFontLoadState aLoadState) {
132 switch (aLoadState) {
133 case gfxUserFontEntry::UserFontLoadState::STATUS_NOT_LOADED:
134 return FontFaceLoadStatus::Unloaded;
135 case gfxUserFontEntry::UserFontLoadState::STATUS_LOAD_PENDING:
136 case gfxUserFontEntry::UserFontLoadState::STATUS_LOADING:
137 return FontFaceLoadStatus::Loading;
138 case gfxUserFontEntry::UserFontLoadState::STATUS_LOADED:
139 return FontFaceLoadStatus::Loaded;
140 case gfxUserFontEntry::UserFontLoadState::STATUS_FAILED:
141 return FontFaceLoadStatus::Error;
143 MOZ_ASSERT_UNREACHABLE("invalid aLoadState value");
144 return FontFaceLoadStatus::Error;
147 already_AddRefed<FontFace> FontFace::CreateForRule(
148 nsISupports* aGlobal, FontFaceSet* aFontFaceSet,
149 RawServoFontFaceRule* aRule) {
150 RefPtr<FontFace> obj = new FontFace(aGlobal, aFontFaceSet);
151 obj->mRule = aRule;
152 obj->mSourceType = eSourceType_FontFaceRule;
153 obj->mInFontFaceSet = true;
154 return obj.forget();
157 already_AddRefed<FontFace> FontFace::Constructor(
158 const GlobalObject& aGlobal, const nsAString& aFamily,
159 const StringOrArrayBufferOrArrayBufferView& aSource,
160 const FontFaceDescriptors& aDescriptors, ErrorResult& aRv) {
161 nsISupports* global = aGlobal.GetAsSupports();
162 nsCOMPtr<nsPIDOMWindowInner> window = do_QueryInterface(global);
163 Document* doc = window->GetDoc();
164 if (!doc) {
165 aRv.Throw(NS_ERROR_FAILURE);
166 return nullptr;
169 RefPtr<FontFace> obj = new FontFace(global, doc->Fonts());
170 if (!obj->SetDescriptors(aFamily, aDescriptors)) {
171 return obj.forget();
174 obj->InitializeSource(aSource);
175 return obj.forget();
178 void FontFace::InitializeSource(
179 const StringOrArrayBufferOrArrayBufferView& aSource) {
180 if (aSource.IsString()) {
181 IgnoredErrorResult rv;
182 SetDescriptor(eCSSFontDesc_Src, aSource.GetAsString(), rv);
183 if (rv.Failed()) {
184 Reject(NS_ERROR_DOM_SYNTAX_ERR);
186 SetStatus(FontFaceLoadStatus::Error);
187 return;
190 mSourceType = eSourceType_URLs;
191 return;
194 mSourceType = FontFace::eSourceType_Buffer;
196 if (aSource.IsArrayBuffer()) {
197 GetDataFrom(aSource.GetAsArrayBuffer(), mSourceBuffer, mSourceBufferLength);
198 } else {
199 MOZ_ASSERT(aSource.IsArrayBufferView());
200 GetDataFrom(aSource.GetAsArrayBufferView(), mSourceBuffer,
201 mSourceBufferLength);
204 SetStatus(FontFaceLoadStatus::Loading);
205 DoLoad();
208 void FontFace::GetFamily(nsString& aResult) {
209 mFontFaceSet->FlushUserFontSet();
210 GetDesc(eCSSFontDesc_Family, aResult);
213 void FontFace::SetFamily(const nsAString& aValue, ErrorResult& aRv) {
214 mFontFaceSet->FlushUserFontSet();
215 if (SetDescriptor(eCSSFontDesc_Family, aValue, aRv)) {
216 DescriptorUpdated();
220 void FontFace::GetStyle(nsString& aResult) {
221 mFontFaceSet->FlushUserFontSet();
222 GetDesc(eCSSFontDesc_Style, aResult);
225 void FontFace::SetStyle(const nsAString& aValue, ErrorResult& aRv) {
226 mFontFaceSet->FlushUserFontSet();
227 if (SetDescriptor(eCSSFontDesc_Style, aValue, aRv)) {
228 DescriptorUpdated();
232 void FontFace::GetWeight(nsString& aResult) {
233 mFontFaceSet->FlushUserFontSet();
234 GetDesc(eCSSFontDesc_Weight, aResult);
237 void FontFace::SetWeight(const nsAString& aValue, ErrorResult& aRv) {
238 mFontFaceSet->FlushUserFontSet();
239 if (SetDescriptor(eCSSFontDesc_Weight, aValue, aRv)) {
240 DescriptorUpdated();
244 void FontFace::GetStretch(nsString& aResult) {
245 mFontFaceSet->FlushUserFontSet();
246 GetDesc(eCSSFontDesc_Stretch, aResult);
249 void FontFace::SetStretch(const nsAString& aValue, ErrorResult& aRv) {
250 mFontFaceSet->FlushUserFontSet();
251 if (SetDescriptor(eCSSFontDesc_Stretch, aValue, aRv)) {
252 DescriptorUpdated();
256 void FontFace::GetUnicodeRange(nsString& aResult) {
257 mFontFaceSet->FlushUserFontSet();
258 GetDesc(eCSSFontDesc_UnicodeRange, aResult);
261 void FontFace::SetUnicodeRange(const nsAString& aValue, ErrorResult& aRv) {
262 mFontFaceSet->FlushUserFontSet();
263 if (SetDescriptor(eCSSFontDesc_UnicodeRange, aValue, aRv)) {
264 DescriptorUpdated();
268 void FontFace::GetVariant(nsString& aResult) {
269 mFontFaceSet->FlushUserFontSet();
271 // XXX Just expose the font-variant descriptor as "normal" until we
272 // support it properly (bug 1055385).
273 aResult.AssignLiteral("normal");
276 void FontFace::SetVariant(const nsAString& aValue, ErrorResult& aRv) {
277 mFontFaceSet->FlushUserFontSet();
279 // XXX Ignore assignments to variant until we support font-variant
280 // descriptors (bug 1055385).
283 void FontFace::GetFeatureSettings(nsString& aResult) {
284 mFontFaceSet->FlushUserFontSet();
285 GetDesc(eCSSFontDesc_FontFeatureSettings, aResult);
288 void FontFace::SetFeatureSettings(const nsAString& aValue, ErrorResult& aRv) {
289 mFontFaceSet->FlushUserFontSet();
290 if (SetDescriptor(eCSSFontDesc_FontFeatureSettings, aValue, aRv)) {
291 DescriptorUpdated();
295 void FontFace::GetVariationSettings(nsString& aResult) {
296 mFontFaceSet->FlushUserFontSet();
297 GetDesc(eCSSFontDesc_FontVariationSettings, aResult);
300 void FontFace::SetVariationSettings(const nsAString& aValue, ErrorResult& aRv) {
301 mFontFaceSet->FlushUserFontSet();
302 if (SetDescriptor(eCSSFontDesc_FontVariationSettings, aValue, aRv)) {
303 DescriptorUpdated();
307 void FontFace::GetDisplay(nsString& aResult) {
308 mFontFaceSet->FlushUserFontSet();
309 GetDesc(eCSSFontDesc_Display, aResult);
312 void FontFace::SetDisplay(const nsAString& aValue, ErrorResult& aRv) {
313 mFontFaceSet->FlushUserFontSet();
314 if (SetDescriptor(eCSSFontDesc_Display, aValue, aRv)) {
315 DescriptorUpdated();
319 void FontFace::DescriptorUpdated() {
320 // If we haven't yet initialized mUserFontEntry, no need to do anything here;
321 // we'll respect the updated descriptor when the time comes to create it.
322 if (!mUserFontEntry) {
323 return;
326 // Behind the scenes, this will actually update the existing entry and return
327 // it, rather than create a new one.
328 RefPtr<gfxUserFontEntry> newEntry =
329 mFontFaceSet->FindOrCreateUserFontEntryFromFontFace(this);
330 SetUserFontEntry(newEntry);
332 if (mInFontFaceSet) {
333 mFontFaceSet->MarkUserFontSetDirty();
335 for (auto& set : mOtherFontFaceSets) {
336 set->MarkUserFontSetDirty();
340 FontFaceLoadStatus FontFace::Status() { return mStatus; }
342 Promise* FontFace::Load(ErrorResult& aRv) {
343 MOZ_ASSERT(NS_IsMainThread());
345 mFontFaceSet->FlushUserFontSet();
347 EnsurePromise();
349 if (!mLoaded) {
350 aRv.Throw(NS_ERROR_FAILURE);
351 return nullptr;
354 // Calling Load on a FontFace constructed with an ArrayBuffer data source,
355 // or on one that is already loading (or has finished loading), has no
356 // effect.
357 if (mSourceType == eSourceType_Buffer ||
358 mStatus != FontFaceLoadStatus::Unloaded) {
359 return mLoaded;
362 // Calling the user font entry's Load method will end up setting our
363 // status to Loading, but the spec requires us to set it to Loading
364 // here.
365 SetStatus(FontFaceLoadStatus::Loading);
367 DoLoad();
369 return mLoaded;
372 gfxUserFontEntry* FontFace::CreateUserFontEntry() {
373 if (!mUserFontEntry) {
374 MOZ_ASSERT(!HasRule(),
375 "Rule backed FontFace objects should already have a user font "
376 "entry by the time Load() can be called on them");
378 RefPtr<gfxUserFontEntry> newEntry =
379 mFontFaceSet->FindOrCreateUserFontEntryFromFontFace(this);
380 if (newEntry) {
381 SetUserFontEntry(newEntry);
385 return mUserFontEntry;
388 void FontFace::DoLoad() {
389 if (!CreateUserFontEntry()) {
390 return;
392 mUserFontEntry->Load();
395 Promise* FontFace::GetLoaded(ErrorResult& aRv) {
396 MOZ_ASSERT(NS_IsMainThread());
398 mFontFaceSet->FlushUserFontSet();
400 EnsurePromise();
402 if (!mLoaded) {
403 aRv.Throw(NS_ERROR_FAILURE);
404 return nullptr;
407 return mLoaded;
410 void FontFace::SetStatus(FontFaceLoadStatus aStatus) {
411 AssertIsMainThreadOrServoFontMetricsLocked();
413 if (mStatus == aStatus) {
414 return;
417 if (aStatus < mStatus) {
418 // We're being asked to go backwards in status! Normally, this shouldn't
419 // happen. But it can if the FontFace had a user font entry that had
420 // loaded, but then was given a new one by FontFaceSet::InsertRuleFontFace
421 // if we used a local() rule. For now, just ignore the request to
422 // go backwards in status.
423 return;
426 mStatus = aStatus;
428 if (mInFontFaceSet) {
429 mFontFaceSet->OnFontFaceStatusChanged(this);
432 for (FontFaceSet* otherSet : mOtherFontFaceSets) {
433 otherSet->OnFontFaceStatusChanged(this);
436 if (mStatus == FontFaceLoadStatus::Loaded) {
437 if (mLoaded) {
438 DoResolve();
440 } else if (mStatus == FontFaceLoadStatus::Error) {
441 if (mSourceType == eSourceType_Buffer) {
442 Reject(NS_ERROR_DOM_SYNTAX_ERR);
443 } else {
444 Reject(NS_ERROR_DOM_NETWORK_ERR);
449 void FontFace::DoResolve() {
450 AssertIsMainThreadOrServoFontMetricsLocked();
452 if (ServoStyleSet* ss = ServoStyleSet::Current()) {
453 // See comments in Gecko_GetFontMetrics.
454 ss->AppendTask(PostTraversalTask::ResolveFontFaceLoadedPromise(this));
455 return;
458 mLoaded->MaybeResolve(this);
461 void FontFace::DoReject(nsresult aResult) {
462 AssertIsMainThreadOrServoFontMetricsLocked();
464 if (ServoStyleSet* ss = ServoStyleSet::Current()) {
465 // See comments in Gecko_GetFontMetrics.
466 ss->AppendTask(
467 PostTraversalTask::RejectFontFaceLoadedPromise(this, aResult));
468 return;
471 mLoaded->MaybeReject(aResult);
474 already_AddRefed<URLExtraData> FontFace::GetURLExtraData() const {
475 nsCOMPtr<nsIGlobalObject> global = do_QueryInterface(mParent);
476 nsCOMPtr<nsIPrincipal> principal = global->PrincipalOrNull();
478 nsCOMPtr<nsPIDOMWindowInner> window = do_QueryInterface(mParent);
479 nsCOMPtr<nsIURI> docURI = window->GetDocumentURI();
480 nsCOMPtr<nsIURI> base = window->GetDocBaseURI();
482 // We pass RP_Unset when creating ReferrerInfo object here because it's not
483 // going to result to change referer policy in a resource request.
484 nsCOMPtr<nsIReferrerInfo> referrerInfo =
485 new ReferrerInfo(docURI, ReferrerPolicy::_empty);
487 RefPtr<URLExtraData> url = new URLExtraData(base, referrerInfo, principal);
488 return url.forget();
491 // Boolean result indicates whether the value of the descriptor was actually
492 // changed.
493 bool FontFace::SetDescriptor(nsCSSFontDesc aFontDesc, const nsAString& aValue,
494 ErrorResult& aRv) {
495 // FIXME We probably don't need to distinguish between this anymore
496 // since we have common backend now.
497 NS_ASSERTION(!HasRule(), "we don't handle rule backed FontFace objects yet");
498 if (HasRule()) {
499 return false;
502 // FIXME(heycam): Should not allow modification of FontFaces that are
503 // CSS-connected and whose rule is read only.
505 NS_ConvertUTF16toUTF8 value(aValue);
506 RefPtr<URLExtraData> url = GetURLExtraData();
507 bool changed;
508 if (!Servo_FontFaceRule_SetDescriptor(GetData(), aFontDesc, &value, url,
509 &changed)) {
510 aRv.ThrowSyntaxError("Invalid font descriptor");
511 return false;
514 if (!changed) {
515 return false;
518 if (aFontDesc == eCSSFontDesc_UnicodeRange) {
519 mUnicodeRangeDirty = true;
522 return true;
525 bool FontFace::SetDescriptors(const nsAString& aFamily,
526 const FontFaceDescriptors& aDescriptors) {
527 MOZ_ASSERT(!HasRule());
528 MOZ_ASSERT(!mDescriptors);
530 mDescriptors = Servo_FontFaceRule_CreateEmpty().Consume();
532 // Helper to call SetDescriptor and return true on success, false on failure.
533 auto setDesc = [=](nsCSSFontDesc aDesc, const nsAString& aVal) -> bool {
534 IgnoredErrorResult rv;
535 SetDescriptor(aDesc, aVal, rv);
536 return !rv.Failed();
539 // Parse all of the mDescriptors in aInitializer, which are the values
540 // we got from the JS constructor.
541 if (!setDesc(eCSSFontDesc_Family, aFamily) ||
542 !setDesc(eCSSFontDesc_Style, aDescriptors.mStyle) ||
543 !setDesc(eCSSFontDesc_Weight, aDescriptors.mWeight) ||
544 !setDesc(eCSSFontDesc_Stretch, aDescriptors.mStretch) ||
545 !setDesc(eCSSFontDesc_UnicodeRange, aDescriptors.mUnicodeRange) ||
546 !setDesc(eCSSFontDesc_FontFeatureSettings,
547 aDescriptors.mFeatureSettings) ||
548 (StaticPrefs::layout_css_font_variations_enabled() &&
549 !setDesc(eCSSFontDesc_FontVariationSettings,
550 aDescriptors.mVariationSettings)) ||
551 !setDesc(eCSSFontDesc_Display, aDescriptors.mDisplay)) {
552 // XXX Handle font-variant once we support it (bug 1055385).
554 // If any of the descriptors failed to parse, none of them should be set
555 // on the FontFace.
556 mDescriptors = Servo_FontFaceRule_CreateEmpty().Consume();
558 Reject(NS_ERROR_DOM_SYNTAX_ERR);
560 SetStatus(FontFaceLoadStatus::Error);
561 return false;
564 return true;
567 void FontFace::GetDesc(nsCSSFontDesc aDescID, nsString& aResult) const {
568 aResult.Truncate();
569 Servo_FontFaceRule_GetDescriptorCssText(GetData(), aDescID, &aResult);
571 // Fill in a default value for missing descriptors.
572 if (aResult.IsEmpty()) {
573 if (aDescID == eCSSFontDesc_UnicodeRange) {
574 aResult.AssignLiteral("U+0-10FFFF");
575 } else if (aDescID == eCSSFontDesc_Display) {
576 aResult.AssignLiteral("auto");
577 } else if (aDescID != eCSSFontDesc_Family && aDescID != eCSSFontDesc_Src) {
578 aResult.AssignLiteral("normal");
583 void FontFace::SetUserFontEntry(gfxUserFontEntry* aEntry) {
584 if (mUserFontEntry) {
585 mUserFontEntry->mFontFaces.RemoveElement(this);
588 mUserFontEntry = static_cast<Entry*>(aEntry);
589 if (mUserFontEntry) {
590 mUserFontEntry->mFontFaces.AppendElement(this);
592 MOZ_ASSERT(
593 mUserFontEntry->GetUserFontSet() == mFontFaceSet->GetUserFontSet(),
594 "user font entry must be associated with the same user font set "
595 "as the FontFace");
597 // Our newly assigned user font entry might be in the process of or
598 // finished loading, so set our status accordingly. But only do so
599 // if we're not going "backwards" in status, which could otherwise
600 // happen in this case:
602 // new FontFace("ABC", "url(x)").load();
604 // where the SetUserFontEntry call (from the after-initialization
605 // DoLoad call) comes after the author's call to load(), which set mStatus
606 // to Loading.
607 FontFaceLoadStatus newStatus =
608 LoadStateToStatus(mUserFontEntry->LoadState());
609 if (newStatus > mStatus) {
610 SetStatus(newStatus);
615 Maybe<StyleComputedFontWeightRange> FontFace::GetFontWeight() const {
616 StyleComputedFontWeightRange range;
617 if (!Servo_FontFaceRule_GetFontWeight(GetData(), &range)) {
618 return Nothing();
620 return Some(range);
623 Maybe<StyleComputedFontStretchRange> FontFace::GetFontStretch() const {
624 StyleComputedFontStretchRange range;
625 if (!Servo_FontFaceRule_GetFontStretch(GetData(), &range)) {
626 return Nothing();
628 return Some(range);
631 Maybe<StyleComputedFontStyleDescriptor> FontFace::GetFontStyle() const {
632 auto descriptor = StyleComputedFontStyleDescriptor::Normal();
633 if (!Servo_FontFaceRule_GetFontStyle(GetData(), &descriptor)) {
634 return Nothing();
636 return Some(descriptor);
639 Maybe<StyleFontDisplay> FontFace::GetFontDisplay() const {
640 StyleFontDisplay display;
641 if (!Servo_FontFaceRule_GetFontDisplay(GetData(), &display)) {
642 return Nothing();
644 return Some(display);
647 Maybe<StyleFontLanguageOverride> FontFace::GetFontLanguageOverride() const {
648 StyleFontLanguageOverride langOverride;
649 if (!Servo_FontFaceRule_GetFontLanguageOverride(GetData(), &langOverride)) {
650 return Nothing();
652 return Some(langOverride);
655 bool FontFace::HasLocalSrc() const {
656 AutoTArray<StyleFontFaceSourceListComponent, 8> components;
657 GetSources(components);
658 for (auto& component : components) {
659 if (component.tag == StyleFontFaceSourceListComponent::Tag::Local) {
660 return true;
663 return false;
666 void FontFace::GetFontFeatureSettings(
667 nsTArray<gfxFontFeature>& aFeatures) const {
668 Servo_FontFaceRule_GetFeatureSettings(GetData(), &aFeatures);
671 void FontFace::GetFontVariationSettings(
672 nsTArray<gfxFontVariation>& aVariations) const {
673 Servo_FontFaceRule_GetVariationSettings(GetData(), &aVariations);
676 void FontFace::GetSources(
677 nsTArray<StyleFontFaceSourceListComponent>& aSources) const {
678 Servo_FontFaceRule_GetSources(GetData(), &aSources);
681 nsAtom* FontFace::GetFamilyName() const {
682 return Servo_FontFaceRule_GetFamilyName(GetData());
685 void FontFace::DisconnectFromRule() {
686 MOZ_ASSERT(HasRule());
688 // Make a copy of the descriptors.
689 mDescriptors = Servo_FontFaceRule_Clone(mRule).Consume();
690 mRule = nullptr;
691 mInFontFaceSet = false;
694 bool FontFace::HasFontData() const {
695 return mSourceType == eSourceType_Buffer && mSourceBuffer;
698 void FontFace::TakeBuffer(uint8_t*& aBuffer, uint32_t& aLength) {
699 MOZ_ASSERT(HasFontData());
701 aBuffer = mSourceBuffer;
702 aLength = mSourceBufferLength;
704 mSourceBuffer = nullptr;
705 mSourceBufferLength = 0;
708 already_AddRefed<gfxFontFaceBufferSource> FontFace::CreateBufferSource() {
709 RefPtr<FontFaceBufferSource> bufferSource = new FontFaceBufferSource(this);
710 return bufferSource.forget();
713 bool FontFace::IsInFontFaceSet(FontFaceSet* aFontFaceSet) const {
714 if (mFontFaceSet == aFontFaceSet) {
715 return mInFontFaceSet;
717 return mOtherFontFaceSets.Contains(aFontFaceSet);
720 void FontFace::AddFontFaceSet(FontFaceSet* aFontFaceSet) {
721 MOZ_ASSERT(!IsInFontFaceSet(aFontFaceSet));
723 if (mFontFaceSet == aFontFaceSet) {
724 mInFontFaceSet = true;
725 } else {
726 mOtherFontFaceSets.AppendElement(aFontFaceSet);
730 void FontFace::RemoveFontFaceSet(FontFaceSet* aFontFaceSet) {
731 MOZ_ASSERT(IsInFontFaceSet(aFontFaceSet));
733 if (mFontFaceSet == aFontFaceSet) {
734 mInFontFaceSet = false;
735 } else {
736 mOtherFontFaceSets.RemoveElement(aFontFaceSet);
740 void FontFace::Reject(nsresult aResult) {
741 AssertIsMainThreadOrServoFontMetricsLocked();
743 if (mLoaded) {
744 DoReject(aResult);
745 } else if (mLoadedRejection == NS_OK) {
746 mLoadedRejection = aResult;
750 void FontFace::EnsurePromise() {
751 MOZ_ASSERT(NS_IsMainThread());
753 if (mLoaded) {
754 return;
757 nsCOMPtr<nsIGlobalObject> global = do_QueryInterface(mParent);
759 // If the pref is not set, don't create the Promise (which the page wouldn't
760 // be able to get to anyway) as it causes the window.FontFace constructor
761 // to be created.
762 if (global && FontFaceSet::PrefEnabled()) {
763 ErrorResult rv;
764 mLoaded = Promise::Create(global, rv);
766 if (mStatus == FontFaceLoadStatus::Loaded) {
767 mLoaded->MaybeResolve(this);
768 } else if (mLoadedRejection != NS_OK) {
769 mLoaded->MaybeReject(mLoadedRejection);
774 gfxCharacterMap* FontFace::GetUnicodeRangeAsCharacterMap() {
775 if (!mUnicodeRangeDirty) {
776 return mUnicodeRange;
779 size_t len;
780 const StyleUnicodeRange* rangesPtr =
781 Servo_FontFaceRule_GetUnicodeRanges(GetData(), &len);
783 Span<const StyleUnicodeRange> ranges(rangesPtr, len);
784 if (!ranges.IsEmpty()) {
785 mUnicodeRange = new gfxCharacterMap();
786 for (auto& range : ranges) {
787 mUnicodeRange->SetRange(range.start, range.end);
789 } else {
790 mUnicodeRange = nullptr;
793 mUnicodeRangeDirty = false;
794 return mUnicodeRange;
797 // -- FontFace::Entry --------------------------------------------------------
799 /* virtual */
800 void FontFace::Entry::SetLoadState(UserFontLoadState aLoadState) {
801 gfxUserFontEntry::SetLoadState(aLoadState);
803 for (size_t i = 0; i < mFontFaces.Length(); i++) {
804 mFontFaces[i]->SetStatus(LoadStateToStatus(aLoadState));
808 /* virtual */
809 void FontFace::Entry::GetUserFontSets(nsTArray<gfxUserFontSet*>& aResult) {
810 aResult.Clear();
812 for (FontFace* f : mFontFaces) {
813 if (f->mInFontFaceSet) {
814 aResult.AppendElement(f->mFontFaceSet->GetUserFontSet());
816 for (FontFaceSet* s : f->mOtherFontFaceSets) {
817 aResult.AppendElement(s->GetUserFontSet());
821 // Remove duplicates.
822 aResult.Sort();
823 auto it = std::unique(aResult.begin(), aResult.end());
824 aResult.TruncateLength(it - aResult.begin());
827 } // namespace dom
828 } // namespace mozilla