Bug 1730256 [wpt PR 30555] - Move getWindowSegments to visualViewport.segments, a...
[gecko.git] / layout / style / FontFace.cpp
blob9a216843e48e2c642457307d47eb52a14288032c
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 nsACString& aFamily,
159 const UTF8StringOrArrayBufferOrArrayBufferView& 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 UTF8StringOrArrayBufferOrArrayBufferView& aSource) {
180 if (aSource.IsUTF8String()) {
181 IgnoredErrorResult rv;
182 SetDescriptor(eCSSFontDesc_Src, aSource.GetAsUTF8String(), 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(nsACString& aResult) {
209 GetDesc(eCSSFontDesc_Family, aResult);
212 void FontFace::SetFamily(const nsACString& aValue, ErrorResult& aRv) {
213 mFontFaceSet->FlushUserFontSet();
214 if (SetDescriptor(eCSSFontDesc_Family, aValue, aRv)) {
215 DescriptorUpdated();
219 void FontFace::GetStyle(nsACString& aResult) {
220 GetDesc(eCSSFontDesc_Style, aResult);
223 void FontFace::SetStyle(const nsACString& aValue, ErrorResult& aRv) {
224 if (SetDescriptor(eCSSFontDesc_Style, aValue, aRv)) {
225 DescriptorUpdated();
229 void FontFace::GetWeight(nsACString& aResult) {
230 GetDesc(eCSSFontDesc_Weight, aResult);
233 void FontFace::SetWeight(const nsACString& aValue, ErrorResult& aRv) {
234 mFontFaceSet->FlushUserFontSet();
235 if (SetDescriptor(eCSSFontDesc_Weight, aValue, aRv)) {
236 DescriptorUpdated();
240 void FontFace::GetStretch(nsACString& aResult) {
241 GetDesc(eCSSFontDesc_Stretch, aResult);
244 void FontFace::SetStretch(const nsACString& aValue, ErrorResult& aRv) {
245 mFontFaceSet->FlushUserFontSet();
246 if (SetDescriptor(eCSSFontDesc_Stretch, aValue, aRv)) {
247 DescriptorUpdated();
251 void FontFace::GetUnicodeRange(nsACString& aResult) {
252 GetDesc(eCSSFontDesc_UnicodeRange, aResult);
255 void FontFace::SetUnicodeRange(const nsACString& aValue, ErrorResult& aRv) {
256 mFontFaceSet->FlushUserFontSet();
257 if (SetDescriptor(eCSSFontDesc_UnicodeRange, aValue, aRv)) {
258 DescriptorUpdated();
262 void FontFace::GetVariant(nsACString& aResult) {
263 // XXX Just expose the font-variant descriptor as "normal" until we
264 // support it properly (bug 1055385).
265 aResult.AssignLiteral("normal");
268 void FontFace::SetVariant(const nsACString& aValue, ErrorResult& aRv) {
269 // XXX Ignore assignments to variant until we support font-variant
270 // descriptors (bug 1055385).
273 void FontFace::GetFeatureSettings(nsACString& aResult) {
274 GetDesc(eCSSFontDesc_FontFeatureSettings, aResult);
277 void FontFace::SetFeatureSettings(const nsACString& aValue, ErrorResult& aRv) {
278 mFontFaceSet->FlushUserFontSet();
279 if (SetDescriptor(eCSSFontDesc_FontFeatureSettings, aValue, aRv)) {
280 DescriptorUpdated();
284 void FontFace::GetVariationSettings(nsACString& aResult) {
285 GetDesc(eCSSFontDesc_FontVariationSettings, aResult);
288 void FontFace::SetVariationSettings(const nsACString& aValue,
289 ErrorResult& aRv) {
290 mFontFaceSet->FlushUserFontSet();
291 if (SetDescriptor(eCSSFontDesc_FontVariationSettings, aValue, aRv)) {
292 DescriptorUpdated();
296 void FontFace::GetDisplay(nsACString& aResult) {
297 GetDesc(eCSSFontDesc_Display, aResult);
300 void FontFace::SetDisplay(const nsACString& aValue, ErrorResult& aRv) {
301 if (SetDescriptor(eCSSFontDesc_Display, aValue, aRv)) {
302 DescriptorUpdated();
306 void FontFace::GetAscentOverride(nsACString& aResult) {
307 GetDesc(eCSSFontDesc_AscentOverride, aResult);
310 void FontFace::SetAscentOverride(const nsACString& aValue, ErrorResult& aRv) {
311 if (SetDescriptor(eCSSFontDesc_AscentOverride, aValue, aRv)) {
312 DescriptorUpdated();
316 void FontFace::GetDescentOverride(nsACString& aResult) {
317 GetDesc(eCSSFontDesc_DescentOverride, aResult);
320 void FontFace::SetDescentOverride(const nsACString& aValue, ErrorResult& aRv) {
321 if (SetDescriptor(eCSSFontDesc_DescentOverride, aValue, aRv)) {
322 DescriptorUpdated();
326 void FontFace::GetLineGapOverride(nsACString& aResult) {
327 GetDesc(eCSSFontDesc_LineGapOverride, aResult);
330 void FontFace::SetLineGapOverride(const nsACString& aValue, ErrorResult& aRv) {
331 if (SetDescriptor(eCSSFontDesc_LineGapOverride, aValue, aRv)) {
332 DescriptorUpdated();
336 void FontFace::GetSizeAdjust(nsACString& aResult) {
337 GetDesc(eCSSFontDesc_SizeAdjust, aResult);
340 void FontFace::SetSizeAdjust(const nsACString& aValue, ErrorResult& aRv) {
341 if (SetDescriptor(eCSSFontDesc_SizeAdjust, aValue, aRv)) {
342 DescriptorUpdated();
346 void FontFace::DescriptorUpdated() {
347 // If we haven't yet initialized mUserFontEntry, no need to do anything here;
348 // we'll respect the updated descriptor when the time comes to create it.
349 if (!mUserFontEntry) {
350 return;
353 // Behind the scenes, this will actually update the existing entry and return
354 // it, rather than create a new one.
355 RefPtr<gfxUserFontEntry> newEntry =
356 mFontFaceSet->FindOrCreateUserFontEntryFromFontFace(this);
357 SetUserFontEntry(newEntry);
359 if (mInFontFaceSet) {
360 mFontFaceSet->MarkUserFontSetDirty();
362 for (auto& set : mOtherFontFaceSets) {
363 set->MarkUserFontSetDirty();
367 FontFaceLoadStatus FontFace::Status() { return mStatus; }
369 Promise* FontFace::Load(ErrorResult& aRv) {
370 MOZ_ASSERT(NS_IsMainThread());
372 mFontFaceSet->FlushUserFontSet();
374 EnsurePromise();
376 if (!mLoaded) {
377 aRv.Throw(NS_ERROR_FAILURE);
378 return nullptr;
381 // Calling Load on a FontFace constructed with an ArrayBuffer data source,
382 // or on one that is already loading (or has finished loading), has no
383 // effect.
384 if (mSourceType == eSourceType_Buffer ||
385 mStatus != FontFaceLoadStatus::Unloaded) {
386 return mLoaded;
389 // Calling the user font entry's Load method will end up setting our
390 // status to Loading, but the spec requires us to set it to Loading
391 // here.
392 SetStatus(FontFaceLoadStatus::Loading);
394 DoLoad();
396 return mLoaded;
399 gfxUserFontEntry* FontFace::CreateUserFontEntry() {
400 if (!mUserFontEntry) {
401 MOZ_ASSERT(!HasRule(),
402 "Rule backed FontFace objects should already have a user font "
403 "entry by the time Load() can be called on them");
405 RefPtr<gfxUserFontEntry> newEntry =
406 mFontFaceSet->FindOrCreateUserFontEntryFromFontFace(this);
407 if (newEntry) {
408 SetUserFontEntry(newEntry);
412 return mUserFontEntry;
415 void FontFace::DoLoad() {
416 if (!CreateUserFontEntry()) {
417 return;
419 mUserFontEntry->Load();
422 Promise* FontFace::GetLoaded(ErrorResult& aRv) {
423 MOZ_ASSERT(NS_IsMainThread());
425 EnsurePromise();
427 if (!mLoaded) {
428 aRv.Throw(NS_ERROR_FAILURE);
429 return nullptr;
432 return mLoaded;
435 void FontFace::SetStatus(FontFaceLoadStatus aStatus) {
436 AssertIsMainThreadOrServoFontMetricsLocked();
438 if (mStatus == aStatus) {
439 return;
442 if (aStatus < mStatus) {
443 // We're being asked to go backwards in status! Normally, this shouldn't
444 // happen. But it can if the FontFace had a user font entry that had
445 // loaded, but then was given a new one by FontFaceSet::InsertRuleFontFace
446 // if we used a local() rule. For now, just ignore the request to
447 // go backwards in status.
448 return;
451 mStatus = aStatus;
453 if (mInFontFaceSet) {
454 mFontFaceSet->OnFontFaceStatusChanged(this);
457 for (FontFaceSet* otherSet : mOtherFontFaceSets) {
458 otherSet->OnFontFaceStatusChanged(this);
461 if (mStatus == FontFaceLoadStatus::Loaded) {
462 if (mLoaded) {
463 DoResolve();
465 } else if (mStatus == FontFaceLoadStatus::Error) {
466 if (mSourceType == eSourceType_Buffer) {
467 Reject(NS_ERROR_DOM_SYNTAX_ERR);
468 } else {
469 Reject(NS_ERROR_DOM_NETWORK_ERR);
474 void FontFace::DoResolve() {
475 AssertIsMainThreadOrServoFontMetricsLocked();
477 if (ServoStyleSet* ss = ServoStyleSet::Current()) {
478 // See comments in Gecko_GetFontMetrics.
479 ss->AppendTask(PostTraversalTask::ResolveFontFaceLoadedPromise(this));
480 return;
483 mLoaded->MaybeResolve(this);
486 void FontFace::DoReject(nsresult aResult) {
487 AssertIsMainThreadOrServoFontMetricsLocked();
489 if (ServoStyleSet* ss = ServoStyleSet::Current()) {
490 // See comments in Gecko_GetFontMetrics.
491 ss->AppendTask(
492 PostTraversalTask::RejectFontFaceLoadedPromise(this, aResult));
493 return;
496 mLoaded->MaybeReject(aResult);
499 already_AddRefed<URLExtraData> FontFace::GetURLExtraData() const {
500 nsCOMPtr<nsIGlobalObject> global = do_QueryInterface(mParent);
501 nsCOMPtr<nsIPrincipal> principal = global->PrincipalOrNull();
503 nsCOMPtr<nsPIDOMWindowInner> window = do_QueryInterface(mParent);
504 nsCOMPtr<nsIURI> docURI = window->GetDocumentURI();
505 nsCOMPtr<nsIURI> base = window->GetDocBaseURI();
507 // We pass RP_Unset when creating ReferrerInfo object here because it's not
508 // going to result to change referer policy in a resource request.
509 nsCOMPtr<nsIReferrerInfo> referrerInfo =
510 new ReferrerInfo(docURI, ReferrerPolicy::_empty);
512 RefPtr<URLExtraData> url = new URLExtraData(base, referrerInfo, principal);
513 return url.forget();
516 // Boolean result indicates whether the value of the descriptor was actually
517 // changed.
518 bool FontFace::SetDescriptor(nsCSSFontDesc aFontDesc, const nsACString& aValue,
519 ErrorResult& aRv) {
520 // FIXME We probably don't need to distinguish between this anymore
521 // since we have common backend now.
522 NS_ASSERTION(!HasRule(), "we don't handle rule backed FontFace objects yet");
523 if (HasRule()) {
524 return false;
527 // FIXME(heycam): Should not allow modification of FontFaces that are
528 // CSS-connected and whose rule is read only.
529 RefPtr<URLExtraData> url = GetURLExtraData();
530 bool changed;
531 if (!Servo_FontFaceRule_SetDescriptor(GetData(), aFontDesc, &aValue, url,
532 &changed)) {
533 aRv.ThrowSyntaxError("Invalid font descriptor");
534 return false;
537 if (!changed) {
538 return false;
541 if (aFontDesc == eCSSFontDesc_UnicodeRange) {
542 mUnicodeRangeDirty = true;
545 return true;
548 bool FontFace::SetDescriptors(const nsACString& aFamily,
549 const FontFaceDescriptors& aDescriptors) {
550 MOZ_ASSERT(!HasRule());
551 MOZ_ASSERT(!mDescriptors);
553 mDescriptors = Servo_FontFaceRule_CreateEmpty().Consume();
555 // Helper to call SetDescriptor and return true on success, false on failure.
556 auto setDesc = [=](nsCSSFontDesc aDesc, const nsACString& aVal) -> bool {
557 IgnoredErrorResult rv;
558 SetDescriptor(aDesc, aVal, rv);
559 return !rv.Failed();
562 // Parse all of the mDescriptors in aInitializer, which are the values
563 // we got from the JS constructor.
564 if (!setDesc(eCSSFontDesc_Family, aFamily) ||
565 !setDesc(eCSSFontDesc_Style, aDescriptors.mStyle) ||
566 !setDesc(eCSSFontDesc_Weight, aDescriptors.mWeight) ||
567 !setDesc(eCSSFontDesc_Stretch, aDescriptors.mStretch) ||
568 !setDesc(eCSSFontDesc_UnicodeRange, aDescriptors.mUnicodeRange) ||
569 !setDesc(eCSSFontDesc_FontFeatureSettings,
570 aDescriptors.mFeatureSettings) ||
571 (StaticPrefs::layout_css_font_variations_enabled() &&
572 !setDesc(eCSSFontDesc_FontVariationSettings,
573 aDescriptors.mVariationSettings)) ||
574 !setDesc(eCSSFontDesc_Display, aDescriptors.mDisplay) ||
575 (StaticPrefs::layout_css_font_metrics_overrides_enabled() &&
576 (!setDesc(eCSSFontDesc_AscentOverride, aDescriptors.mAscentOverride) ||
577 !setDesc(eCSSFontDesc_DescentOverride, aDescriptors.mDescentOverride) ||
578 !setDesc(eCSSFontDesc_LineGapOverride,
579 aDescriptors.mLineGapOverride))) ||
580 (StaticPrefs::layout_css_size_adjust_enabled() &&
581 !setDesc(eCSSFontDesc_SizeAdjust, aDescriptors.mSizeAdjust))) {
582 // XXX Handle font-variant once we support it (bug 1055385).
584 // If any of the descriptors failed to parse, none of them should be set
585 // on the FontFace.
586 mDescriptors = Servo_FontFaceRule_CreateEmpty().Consume();
588 Reject(NS_ERROR_DOM_SYNTAX_ERR);
590 SetStatus(FontFaceLoadStatus::Error);
591 return false;
594 return true;
597 void FontFace::GetDesc(nsCSSFontDesc aDescID, nsACString& aResult) const {
598 aResult.Truncate();
599 Servo_FontFaceRule_GetDescriptorCssText(GetData(), aDescID, &aResult);
601 // Fill in a default value for missing descriptors.
602 if (aResult.IsEmpty()) {
603 if (aDescID == eCSSFontDesc_UnicodeRange) {
604 aResult.AssignLiteral("U+0-10FFFF");
605 } else if (aDescID == eCSSFontDesc_Display) {
606 aResult.AssignLiteral("auto");
607 } else if (aDescID != eCSSFontDesc_Family && aDescID != eCSSFontDesc_Src) {
608 aResult.AssignLiteral("normal");
613 void FontFace::SetUserFontEntry(gfxUserFontEntry* aEntry) {
614 if (mUserFontEntry) {
615 mUserFontEntry->mFontFaces.RemoveElement(this);
618 mUserFontEntry = static_cast<Entry*>(aEntry);
619 if (mUserFontEntry) {
620 mUserFontEntry->mFontFaces.AppendElement(this);
622 MOZ_ASSERT(
623 mUserFontEntry->GetUserFontSet() == mFontFaceSet->GetUserFontSet(),
624 "user font entry must be associated with the same user font set "
625 "as the FontFace");
627 // Our newly assigned user font entry might be in the process of or
628 // finished loading, so set our status accordingly. But only do so
629 // if we're not going "backwards" in status, which could otherwise
630 // happen in this case:
632 // new FontFace("ABC", "url(x)").load();
634 // where the SetUserFontEntry call (from the after-initialization
635 // DoLoad call) comes after the author's call to load(), which set mStatus
636 // to Loading.
637 FontFaceLoadStatus newStatus =
638 LoadStateToStatus(mUserFontEntry->LoadState());
639 if (newStatus > mStatus) {
640 SetStatus(newStatus);
645 Maybe<StyleComputedFontWeightRange> FontFace::GetFontWeight() const {
646 StyleComputedFontWeightRange range;
647 if (!Servo_FontFaceRule_GetFontWeight(GetData(), &range)) {
648 return Nothing();
650 return Some(range);
653 Maybe<StyleComputedFontStretchRange> FontFace::GetFontStretch() const {
654 StyleComputedFontStretchRange range;
655 if (!Servo_FontFaceRule_GetFontStretch(GetData(), &range)) {
656 return Nothing();
658 return Some(range);
661 Maybe<StyleComputedFontStyleDescriptor> FontFace::GetFontStyle() const {
662 auto descriptor = StyleComputedFontStyleDescriptor::Normal();
663 if (!Servo_FontFaceRule_GetFontStyle(GetData(), &descriptor)) {
664 return Nothing();
666 return Some(descriptor);
669 Maybe<StyleFontDisplay> FontFace::GetFontDisplay() const {
670 StyleFontDisplay display;
671 if (!Servo_FontFaceRule_GetFontDisplay(GetData(), &display)) {
672 return Nothing();
674 return Some(display);
677 Maybe<StyleFontLanguageOverride> FontFace::GetFontLanguageOverride() const {
678 StyleFontLanguageOverride langOverride;
679 if (!Servo_FontFaceRule_GetFontLanguageOverride(GetData(), &langOverride)) {
680 return Nothing();
682 return Some(langOverride);
685 Maybe<StylePercentage> FontFace::GetAscentOverride() const {
686 StylePercentage ascent{0};
687 if (!Servo_FontFaceRule_GetAscentOverride(GetData(), &ascent)) {
688 return Nothing();
690 return Some(ascent);
693 Maybe<StylePercentage> FontFace::GetDescentOverride() const {
694 StylePercentage descent{0};
695 if (!Servo_FontFaceRule_GetDescentOverride(GetData(), &descent)) {
696 return Nothing();
698 return Some(descent);
701 Maybe<StylePercentage> FontFace::GetLineGapOverride() const {
702 StylePercentage lineGap{0};
703 if (!Servo_FontFaceRule_GetLineGapOverride(GetData(), &lineGap)) {
704 return Nothing();
706 return Some(lineGap);
709 Maybe<StylePercentage> FontFace::GetSizeAdjust() const {
710 StylePercentage sizeAdjust;
711 if (!Servo_FontFaceRule_GetSizeAdjust(GetData(), &sizeAdjust)) {
712 return Nothing();
714 return Some(sizeAdjust);
717 bool FontFace::HasLocalSrc() const {
718 AutoTArray<StyleFontFaceSourceListComponent, 8> components;
719 GetSources(components);
720 for (auto& component : components) {
721 if (component.tag == StyleFontFaceSourceListComponent::Tag::Local) {
722 return true;
725 return false;
728 void FontFace::GetFontFeatureSettings(
729 nsTArray<gfxFontFeature>& aFeatures) const {
730 Servo_FontFaceRule_GetFeatureSettings(GetData(), &aFeatures);
733 void FontFace::GetFontVariationSettings(
734 nsTArray<gfxFontVariation>& aVariations) const {
735 Servo_FontFaceRule_GetVariationSettings(GetData(), &aVariations);
738 void FontFace::GetSources(
739 nsTArray<StyleFontFaceSourceListComponent>& aSources) const {
740 Servo_FontFaceRule_GetSources(GetData(), &aSources);
743 nsAtom* FontFace::GetFamilyName() const {
744 return Servo_FontFaceRule_GetFamilyName(GetData());
747 void FontFace::DisconnectFromRule() {
748 MOZ_ASSERT(HasRule());
750 // Make a copy of the descriptors.
751 mDescriptors = Servo_FontFaceRule_Clone(mRule).Consume();
752 mRule = nullptr;
753 mInFontFaceSet = false;
756 bool FontFace::HasFontData() const {
757 return mSourceType == eSourceType_Buffer && mSourceBuffer;
760 void FontFace::TakeBuffer(uint8_t*& aBuffer, uint32_t& aLength) {
761 MOZ_ASSERT(HasFontData());
763 aBuffer = mSourceBuffer;
764 aLength = mSourceBufferLength;
766 mSourceBuffer = nullptr;
767 mSourceBufferLength = 0;
770 already_AddRefed<gfxFontFaceBufferSource> FontFace::CreateBufferSource() {
771 RefPtr<FontFaceBufferSource> bufferSource = new FontFaceBufferSource(this);
772 return bufferSource.forget();
775 bool FontFace::IsInFontFaceSet(FontFaceSet* aFontFaceSet) const {
776 if (mFontFaceSet == aFontFaceSet) {
777 return mInFontFaceSet;
779 return mOtherFontFaceSets.Contains(aFontFaceSet);
782 void FontFace::AddFontFaceSet(FontFaceSet* aFontFaceSet) {
783 MOZ_ASSERT(!IsInFontFaceSet(aFontFaceSet));
785 if (mFontFaceSet == aFontFaceSet) {
786 mInFontFaceSet = true;
787 } else {
788 mOtherFontFaceSets.AppendElement(aFontFaceSet);
792 void FontFace::RemoveFontFaceSet(FontFaceSet* aFontFaceSet) {
793 MOZ_ASSERT(IsInFontFaceSet(aFontFaceSet));
795 if (mFontFaceSet == aFontFaceSet) {
796 mInFontFaceSet = false;
797 } else {
798 mOtherFontFaceSets.RemoveElement(aFontFaceSet);
802 void FontFace::Reject(nsresult aResult) {
803 AssertIsMainThreadOrServoFontMetricsLocked();
805 if (mLoaded) {
806 DoReject(aResult);
807 } else if (mLoadedRejection == NS_OK) {
808 mLoadedRejection = aResult;
812 void FontFace::EnsurePromise() {
813 MOZ_ASSERT(NS_IsMainThread());
815 if (mLoaded) {
816 return;
819 nsCOMPtr<nsIGlobalObject> global = do_QueryInterface(mParent);
821 // If the pref is not set, don't create the Promise (which the page wouldn't
822 // be able to get to anyway) as it causes the window.FontFace constructor
823 // to be created.
824 if (global && FontFaceSet::PrefEnabled()) {
825 ErrorResult rv;
826 mLoaded = Promise::Create(global, rv);
828 if (mStatus == FontFaceLoadStatus::Loaded) {
829 mLoaded->MaybeResolve(this);
830 } else if (mLoadedRejection != NS_OK) {
831 mLoaded->MaybeReject(mLoadedRejection);
836 gfxCharacterMap* FontFace::GetUnicodeRangeAsCharacterMap() {
837 if (!mUnicodeRangeDirty) {
838 return mUnicodeRange;
841 size_t len;
842 const StyleUnicodeRange* rangesPtr =
843 Servo_FontFaceRule_GetUnicodeRanges(GetData(), &len);
845 Span<const StyleUnicodeRange> ranges(rangesPtr, len);
846 if (!ranges.IsEmpty()) {
847 RefPtr<gfxCharacterMap> charMap = new gfxCharacterMap();
848 for (auto& range : ranges) {
849 charMap->SetRange(range.start, range.end);
851 charMap->Compact();
852 // As it's common for multiple font resources to have the same
853 // unicode-range list, look for an existing copy of this map to share,
854 // or add this one to the sharing cache if not already present.
855 mUnicodeRange =
856 gfxPlatformFontList::PlatformFontList()->FindCharMap(charMap);
857 } else {
858 mUnicodeRange = nullptr;
861 mUnicodeRangeDirty = false;
862 return mUnicodeRange;
865 // -- FontFace::Entry --------------------------------------------------------
867 /* virtual */
868 void FontFace::Entry::SetLoadState(UserFontLoadState aLoadState) {
869 gfxUserFontEntry::SetLoadState(aLoadState);
871 for (size_t i = 0; i < mFontFaces.Length(); i++) {
872 mFontFaces[i]->SetStatus(LoadStateToStatus(aLoadState));
876 /* virtual */
877 void FontFace::Entry::GetUserFontSets(nsTArray<gfxUserFontSet*>& aResult) {
878 aResult.Clear();
880 for (FontFace* f : mFontFaces) {
881 if (f->mInFontFaceSet) {
882 aResult.AppendElement(f->mFontFaceSet->GetUserFontSet());
884 for (FontFaceSet* s : f->mOtherFontFaceSets) {
885 aResult.AppendElement(s->GetUserFontSet());
889 // Remove duplicates.
890 aResult.Sort();
891 auto it = std::unique(aResult.begin(), aResult.end());
892 aResult.TruncateLength(it - aResult.begin());
895 } // namespace dom
896 } // namespace mozilla