FontFaceImpl.cpp (27100B)
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/. */ 6 7 #include "mozilla/dom/FontFaceImpl.h" 8 9 #include <algorithm> 10 11 #include "gfxFontUtils.h" 12 #include "gfxPlatformFontList.h" 13 #include "mozilla/ServoCSSParser.h" 14 #include "mozilla/StaticPrefs_layout.h" 15 #include "mozilla/dom/Document.h" 16 #include "mozilla/dom/FontFaceBinding.h" 17 #include "mozilla/dom/FontFaceSetImpl.h" 18 19 namespace mozilla::dom { 20 21 // -- FontFaceBufferSource --------------------------------------------------- 22 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. 26 */ 27 class FontFaceBufferSource : public gfxFontFaceBufferSource { 28 public: 29 FontFaceBufferSource(uint8_t* aBuffer, uint32_t aLength) 30 : mBuffer(aBuffer), mLength(aLength) {} 31 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; 40 } 41 42 private: 43 ~FontFaceBufferSource() override { 44 if (mBuffer) { 45 free(mBuffer); 46 } 47 } 48 49 uint8_t* mBuffer; 50 uint32_t mLength; 51 }; 52 53 // -- FontFaceImpl ----------------------------------------------------------- 54 55 FontFaceImpl::FontFaceImpl(FontFace* aOwner, FontFaceSetImpl* aFontFaceSet) 56 : mOwner(aOwner), 57 mStatus(FontFaceLoadStatus::Unloaded), 58 mSourceType(SourceType(0)), 59 mFontFaceSet(aFontFaceSet) {} 60 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()); 65 66 SetUserFontEntry(nullptr); 67 } 68 69 #ifdef DEBUG 70 void FontFaceImpl::AssertIsOnOwningThread() const { 71 mFontFaceSet->AssertIsOnOwningThread(); 72 } 73 #endif 74 75 void FontFaceImpl::StopKeepingOwnerAlive() { 76 if (mKeepingOwnerAlive) { 77 mKeepingOwnerAlive = false; 78 MOZ_ASSERT(mOwner); 79 mOwner->Release(); 80 } 81 } 82 83 void FontFaceImpl::Destroy() { 84 mInFontFaceSet = false; 85 SetUserFontEntry(nullptr); 86 StopKeepingOwnerAlive(); 87 mOwner = nullptr; 88 } 89 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; 102 } 103 MOZ_ASSERT_UNREACHABLE("invalid aLoadState value"); 104 return FontFaceLoadStatus::Error; 105 } 106 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(); 115 } 116 117 void FontFaceImpl::InitializeSourceURL(const nsACString& aURL) { 118 MOZ_ASSERT(mOwner); 119 mSourceType = eSourceType_URLs; 120 121 IgnoredErrorResult rv; 122 SetDescriptor(eCSSFontDesc_Src, aURL, rv); 123 if (rv.Failed()) { 124 mOwner->MaybeReject(FontFaceLoadedRejectReason::Syntax, 125 nsPrintfCString("Invalid source url %s", 126 PromiseFlatCString(aURL).get())); 127 SetStatus(FontFaceLoadStatus::Error); 128 } 129 } 130 131 void FontFaceImpl::InitializeSourceBuffer(uint8_t* aBuffer, uint32_t aLength) { 132 MOZ_ASSERT(mOwner); 133 MOZ_ASSERT(!mBufferSource); 134 mSourceType = FontFaceImpl::eSourceType_Buffer; 135 136 if (aBuffer) { 137 mBufferSource = new FontFaceBufferSource(aBuffer, aLength); 138 } 139 140 SetStatus(FontFaceLoadStatus::Loading); 141 DoLoad(); 142 } 143 144 void FontFaceImpl::GetFamily(nsACString& aResult) { 145 GetDesc(eCSSFontDesc_Family, aResult); 146 } 147 148 void FontFaceImpl::SetFamily(const nsACString& aValue, ErrorResult& aRv) { 149 mFontFaceSet->FlushUserFontSet(); 150 if (SetDescriptor(eCSSFontDesc_Family, aValue, aRv)) { 151 DescriptorUpdated(); 152 } 153 } 154 155 void FontFaceImpl::GetStyle(nsACString& aResult) { 156 GetDesc(eCSSFontDesc_Style, aResult); 157 } 158 159 void FontFaceImpl::SetStyle(const nsACString& aValue, ErrorResult& aRv) { 160 if (SetDescriptor(eCSSFontDesc_Style, aValue, aRv)) { 161 DescriptorUpdated(); 162 } 163 } 164 165 void FontFaceImpl::GetWeight(nsACString& aResult) { 166 GetDesc(eCSSFontDesc_Weight, aResult); 167 } 168 169 void FontFaceImpl::SetWeight(const nsACString& aValue, ErrorResult& aRv) { 170 mFontFaceSet->FlushUserFontSet(); 171 if (SetDescriptor(eCSSFontDesc_Weight, aValue, aRv)) { 172 DescriptorUpdated(); 173 } 174 } 175 176 void FontFaceImpl::GetStretch(nsACString& aResult) { 177 GetDesc(eCSSFontDesc_Stretch, aResult); 178 } 179 180 void FontFaceImpl::SetStretch(const nsACString& aValue, ErrorResult& aRv) { 181 mFontFaceSet->FlushUserFontSet(); 182 if (SetDescriptor(eCSSFontDesc_Stretch, aValue, aRv)) { 183 DescriptorUpdated(); 184 } 185 } 186 187 void FontFaceImpl::GetUnicodeRange(nsACString& aResult) { 188 GetDesc(eCSSFontDesc_UnicodeRange, aResult); 189 } 190 191 void FontFaceImpl::SetUnicodeRange(const nsACString& aValue, ErrorResult& aRv) { 192 mFontFaceSet->FlushUserFontSet(); 193 if (SetDescriptor(eCSSFontDesc_UnicodeRange, aValue, aRv)) { 194 DescriptorUpdated(); 195 } 196 } 197 198 void FontFaceImpl::GetVariant(nsACString& aResult) { 199 // XXX Just expose the font-variant descriptor as "normal" until we 200 // support it properly (bug 1055385). 201 aResult.AssignLiteral("normal"); 202 } 203 204 void FontFaceImpl::SetVariant(const nsACString& aValue, ErrorResult& aRv) { 205 // XXX Ignore assignments to variant until we support font-variant 206 // descriptors (bug 1055385). 207 } 208 209 void FontFaceImpl::GetFeatureSettings(nsACString& aResult) { 210 GetDesc(eCSSFontDesc_FontFeatureSettings, aResult); 211 } 212 213 void FontFaceImpl::SetFeatureSettings(const nsACString& aValue, 214 ErrorResult& aRv) { 215 mFontFaceSet->FlushUserFontSet(); 216 if (SetDescriptor(eCSSFontDesc_FontFeatureSettings, aValue, aRv)) { 217 DescriptorUpdated(); 218 } 219 } 220 221 void FontFaceImpl::GetVariationSettings(nsACString& aResult) { 222 GetDesc(eCSSFontDesc_FontVariationSettings, aResult); 223 } 224 225 void FontFaceImpl::SetVariationSettings(const nsACString& aValue, 226 ErrorResult& aRv) { 227 mFontFaceSet->FlushUserFontSet(); 228 if (SetDescriptor(eCSSFontDesc_FontVariationSettings, aValue, aRv)) { 229 DescriptorUpdated(); 230 } 231 } 232 233 void FontFaceImpl::GetDisplay(nsACString& aResult) { 234 GetDesc(eCSSFontDesc_Display, aResult); 235 } 236 237 void FontFaceImpl::SetDisplay(const nsACString& aValue, ErrorResult& aRv) { 238 if (SetDescriptor(eCSSFontDesc_Display, aValue, aRv)) { 239 DescriptorUpdated(); 240 } 241 } 242 243 void FontFaceImpl::GetAscentOverride(nsACString& aResult) { 244 GetDesc(eCSSFontDesc_AscentOverride, aResult); 245 } 246 247 void FontFaceImpl::SetAscentOverride(const nsACString& aValue, 248 ErrorResult& aRv) { 249 if (SetDescriptor(eCSSFontDesc_AscentOverride, aValue, aRv)) { 250 DescriptorUpdated(); 251 } 252 } 253 254 void FontFaceImpl::GetDescentOverride(nsACString& aResult) { 255 GetDesc(eCSSFontDesc_DescentOverride, aResult); 256 } 257 258 void FontFaceImpl::SetDescentOverride(const nsACString& aValue, 259 ErrorResult& aRv) { 260 if (SetDescriptor(eCSSFontDesc_DescentOverride, aValue, aRv)) { 261 DescriptorUpdated(); 262 } 263 } 264 265 void FontFaceImpl::GetLineGapOverride(nsACString& aResult) { 266 GetDesc(eCSSFontDesc_LineGapOverride, aResult); 267 } 268 269 void FontFaceImpl::SetLineGapOverride(const nsACString& aValue, 270 ErrorResult& aRv) { 271 if (SetDescriptor(eCSSFontDesc_LineGapOverride, aValue, aRv)) { 272 DescriptorUpdated(); 273 } 274 } 275 276 void FontFaceImpl::GetSizeAdjust(nsACString& aResult) { 277 GetDesc(eCSSFontDesc_SizeAdjust, aResult); 278 } 279 280 void FontFaceImpl::SetSizeAdjust(const nsACString& aValue, ErrorResult& aRv) { 281 if (SetDescriptor(eCSSFontDesc_SizeAdjust, aValue, aRv)) { 282 DescriptorUpdated(); 283 } 284 } 285 286 void FontFaceImpl::DescriptorUpdated() { 287 // If we haven't yet initialized mUserFontEntry, no need to do anything here; 288 // we'll respect the updated descriptor when the time comes to create it. 289 if (!mUserFontEntry) { 290 return; 291 } 292 293 gfxUserFontAttributes attr; 294 RefPtr<gfxUserFontEntry> newEntry; 295 if (GetAttributes(attr)) { 296 newEntry = mFontFaceSet->FindOrCreateUserFontEntryFromFontFace( 297 this, std::move(attr), StyleOrigin::Author); 298 } 299 SetUserFontEntry(newEntry); 300 301 // Behind the scenes, this will actually update the existing entry and return 302 // it, rather than create a new one. 303 304 if (mInFontFaceSet) { 305 mFontFaceSet->MarkUserFontSetDirty(); 306 } 307 for (auto& set : mOtherFontFaceSets) { 308 set->MarkUserFontSetDirty(); 309 } 310 } 311 312 FontFaceLoadStatus FontFaceImpl::Status() { return mStatus; } 313 314 void FontFaceImpl::Load(ErrorResult& aRv) { 315 mFontFaceSet->FlushUserFontSet(); 316 317 // Calling Load on a FontFace constructed with an ArrayBuffer data source, 318 // or on one that is already loading (or has finished loading), has no 319 // effect. 320 if (mSourceType == eSourceType_Buffer || 321 mStatus != FontFaceLoadStatus::Unloaded) { 322 return; 323 } 324 325 // Calling the user font entry's Load method will end up setting our 326 // status to Loading, but the spec requires us to set it to Loading 327 // here. 328 SetStatus(FontFaceLoadStatus::Loading); 329 330 DoLoad(); 331 } 332 333 gfxUserFontEntry* FontFaceImpl::CreateUserFontEntry() { 334 if (!mUserFontEntry) { 335 MOZ_ASSERT(!HasRule(), 336 "Rule backed FontFace objects should already have a user font " 337 "entry by the time Load() can be called on them"); 338 339 gfxUserFontAttributes attr; 340 if (GetAttributes(attr)) { 341 RefPtr<gfxUserFontEntry> newEntry = 342 mFontFaceSet->FindOrCreateUserFontEntryFromFontFace( 343 this, std::move(attr), StyleOrigin::Author); 344 if (newEntry) { 345 SetUserFontEntry(newEntry); 346 } 347 } 348 } 349 350 return mUserFontEntry; 351 } 352 353 void FontFaceImpl::DoLoad() { 354 if (!CreateUserFontEntry()) { 355 return; 356 } 357 mUserFontEntry->Load(); 358 } 359 360 void FontFaceImpl::SetStatus(FontFaceLoadStatus aStatus) { 361 gfxFontUtils::AssertSafeThreadOrServoFontMetricsLocked(); 362 363 if (mStatus == aStatus) { 364 return; 365 } 366 367 if (aStatus < mStatus) { 368 // We're being asked to go backwards in status! Normally, this shouldn't 369 // happen. But it can if the FontFace had a user font entry that had 370 // loaded, but then was given a new one by FontFaceSet::InsertRuleFontFace 371 // if we used a local() rule. For now, just ignore the request to 372 // go backwards in status. 373 return; 374 } 375 376 mStatus = aStatus; 377 378 if (mInFontFaceSet) { 379 mFontFaceSet->OnFontFaceStatusChanged(this); 380 } 381 382 for (FontFaceSetImpl* otherSet : mOtherFontFaceSets) { 383 otherSet->OnFontFaceStatusChanged(this); 384 } 385 386 UpdateOwnerPromise(); 387 } 388 389 void FontFaceImpl::UpdateOwnerPromise() { 390 if (!mFontFaceSet->IsOnOwningThread()) { 391 mFontFaceSet->DispatchToOwningThread( 392 "FontFaceImpl::UpdateOwnerPromise", 393 [self = RefPtr{this}] { self->UpdateOwnerPromise(); }); 394 return; 395 } 396 397 if (NS_WARN_IF(!mOwner)) { 398 MOZ_DIAGNOSTIC_ASSERT(!mKeepingOwnerAlive); 399 return; 400 } 401 402 if (mStatus == FontFaceLoadStatus::Loaded) { 403 mOwner->MaybeResolve(); 404 } else if (mStatus == FontFaceLoadStatus::Error) { 405 if (mSourceType == eSourceType_Buffer) { 406 mOwner->MaybeReject(FontFaceLoadedRejectReason::Syntax, 407 nsCString("Invalid source buffer"_ns)); 408 } else { 409 mOwner->MaybeReject(FontFaceLoadedRejectReason::Network, nsCString()); 410 } 411 } 412 413 const bool shouldKeepOwnerAlive = mStatus == FontFaceLoadStatus::Loading; 414 if (shouldKeepOwnerAlive != mKeepingOwnerAlive) { 415 mKeepingOwnerAlive = shouldKeepOwnerAlive; 416 if (shouldKeepOwnerAlive) { 417 mOwner->AddRef(); 418 } else { 419 mOwner->Release(); 420 } 421 } 422 } 423 424 // Boolean result indicates whether the value of the descriptor was actually 425 // changed. 426 bool FontFaceImpl::SetDescriptor(nsCSSFontDesc aFontDesc, 427 const nsACString& aValue, ErrorResult& aRv) { 428 // FIXME We probably don't need to distinguish between this anymore 429 // since we have common backend now. 430 NS_ASSERTION(!HasRule(), "we don't handle rule backed FontFace objects yet"); 431 if (HasRule()) { 432 return false; 433 } 434 435 RefPtr<URLExtraData> url = mFontFaceSet->GetURLExtraData(); 436 if (NS_WARN_IF(!url)) { 437 // This should only happen on worker threads, where we failed to initialize 438 // the worker before it was shutdown. 439 aRv.ThrowInvalidStateError("Missing URLExtraData"); 440 return false; 441 } 442 443 // FIXME(heycam): Should not allow modification of FontFaces that are 444 // CSS-connected and whose rule is read only. 445 bool changed = false; 446 const bool valid = [&] { 447 if (Servo_FontFaceRule_SetDescriptor(GetData(), aFontDesc, &aValue, url, 448 &changed)) { 449 return true; 450 } 451 if (aFontDesc == eCSSFontDesc_Family) { 452 // TODO: Warn to the console? 453 nsAutoCString quoted; 454 nsStyleUtil::AppendQuotedCSSString(aValue, quoted, '"'); 455 if (Servo_FontFaceRule_SetDescriptor(GetData(), aFontDesc, "ed, url, 456 &changed)) { 457 return true; 458 } 459 } 460 aRv.ThrowSyntaxError( 461 nsPrintfCString("Invalid font descriptor %s: %s", 462 nsCSSProps::GetStringValue(aFontDesc).get(), 463 PromiseFlatCString(aValue).get())); 464 return false; 465 }(); 466 467 if (!valid || !changed) { 468 return false; 469 } 470 471 if (aFontDesc == eCSSFontDesc_UnicodeRange) { 472 mUnicodeRangeDirty = true; 473 } 474 475 return true; 476 } 477 478 bool FontFaceImpl::SetDescriptors(const nsACString& aFamily, 479 const FontFaceDescriptors& aDescriptors) { 480 MOZ_ASSERT(!HasRule()); 481 MOZ_ASSERT(!mDescriptors); 482 483 mDescriptors = Servo_FontFaceRule_CreateEmpty().Consume(); 484 485 nsCString errorMessage; 486 // Helper to call SetDescriptor and return true on success, false on failure. 487 auto setDesc = [&](nsCSSFontDesc aDesc, const nsACString& aVal) -> bool { 488 IgnoredErrorResult rv; 489 SetDescriptor(aDesc, aVal, rv); 490 if (!rv.Failed()) { 491 return true; 492 } 493 errorMessage = nsPrintfCString("Invalid font descriptor %s: %s", 494 nsCSSProps::GetStringValue(aDesc).get(), 495 PromiseFlatCString(aVal).get()); 496 return false; 497 }; 498 499 // Parse all of the mDescriptors in aInitializer, which are the values 500 // we got from the JS constructor. 501 if (!setDesc(eCSSFontDesc_Family, aFamily) || 502 !setDesc(eCSSFontDesc_Style, aDescriptors.mStyle) || 503 !setDesc(eCSSFontDesc_Weight, aDescriptors.mWeight) || 504 !setDesc(eCSSFontDesc_Stretch, aDescriptors.mStretch) || 505 !setDesc(eCSSFontDesc_UnicodeRange, aDescriptors.mUnicodeRange) || 506 !setDesc(eCSSFontDesc_FontFeatureSettings, 507 aDescriptors.mFeatureSettings) || 508 (StaticPrefs::layout_css_font_variations_enabled() && 509 !setDesc(eCSSFontDesc_FontVariationSettings, 510 aDescriptors.mVariationSettings)) || 511 !setDesc(eCSSFontDesc_Display, aDescriptors.mDisplay) || 512 ((!setDesc(eCSSFontDesc_AscentOverride, aDescriptors.mAscentOverride) || 513 !setDesc(eCSSFontDesc_DescentOverride, aDescriptors.mDescentOverride) || 514 !setDesc(eCSSFontDesc_LineGapOverride, 515 aDescriptors.mLineGapOverride))) || 516 !setDesc(eCSSFontDesc_SizeAdjust, aDescriptors.mSizeAdjust)) { 517 // XXX Handle font-variant once we support it (bug 1055385). 518 519 // If any of the descriptors failed to parse, none of them should be set 520 // on the FontFace. 521 mDescriptors = Servo_FontFaceRule_CreateEmpty().Consume(); 522 523 if (mOwner) { 524 mOwner->MaybeReject(FontFaceLoadedRejectReason::Syntax, 525 std::move(errorMessage)); 526 } 527 528 SetStatus(FontFaceLoadStatus::Error); 529 return false; 530 } 531 532 return true; 533 } 534 535 void FontFaceImpl::GetDesc(nsCSSFontDesc aDescID, nsACString& aResult) const { 536 aResult.Truncate(); 537 Servo_FontFaceRule_GetDescriptorCssText(GetData(), aDescID, &aResult); 538 539 // Fill in a default value for missing descriptors. 540 if (aResult.IsEmpty()) { 541 if (aDescID == eCSSFontDesc_UnicodeRange) { 542 aResult.AssignLiteral("U+0-10FFFF"); 543 } else if (aDescID == eCSSFontDesc_Display) { 544 aResult.AssignLiteral("auto"); 545 } else if (aDescID != eCSSFontDesc_Family && aDescID != eCSSFontDesc_Src) { 546 aResult.AssignLiteral("normal"); 547 } 548 } 549 } 550 551 void FontFaceImpl::SetUserFontEntry(gfxUserFontEntry* aEntry) { 552 AssertIsOnOwningThread(); 553 554 if (mUserFontEntry == aEntry) { 555 return; 556 } 557 558 if (mUserFontEntry) { 559 mUserFontEntry->RemoveFontFace(this); 560 } 561 562 auto* entry = static_cast<Entry*>(aEntry); 563 if (entry) { 564 entry->AddFontFace(this); 565 } 566 567 mUserFontEntry = entry; 568 569 if (!mUserFontEntry) { 570 return; 571 } 572 573 MOZ_ASSERT(mUserFontEntry->HasUserFontSet(mFontFaceSet), 574 "user font entry must be associated with the same user font set " 575 "as the FontFace"); 576 577 // Our newly assigned user font entry might be in the process of or 578 // finished loading, so set our status accordingly. But only do so 579 // if we're not going "backwards" in status, which could otherwise 580 // happen in this case: 581 // 582 // new FontFace("ABC", "url(x)").load(); 583 // 584 // where the SetUserFontEntry call (from the after-initialization 585 // DoLoad call) comes after the author's call to load(), which set mStatus 586 // to Loading. 587 FontFaceLoadStatus newStatus = LoadStateToStatus(mUserFontEntry->LoadState()); 588 if (newStatus > mStatus) { 589 SetStatus(newStatus); 590 } 591 } 592 593 bool FontFaceImpl::GetAttributes(gfxUserFontAttributes& aAttr) { 594 StyleLockedFontFaceRule* data = GetData(); 595 if (!data) { 596 return false; 597 } 598 return GetAttributesFromRule(data, aAttr, 599 Some(GetUnicodeRangeAsCharacterMap())); 600 } 601 602 static already_AddRefed<gfxCharacterMap> ComputeCharacterMap( 603 StyleLockedFontFaceRule* aData) { 604 size_t len; 605 const StyleUnicodeRange* rangesPtr = 606 Servo_FontFaceRule_GetUnicodeRanges(aData, &len); 607 608 Span<const StyleUnicodeRange> ranges(rangesPtr, len); 609 if (ranges.IsEmpty()) { 610 return nullptr; 611 } 612 // A single range covering the entire Unicode code space is equivalent to 613 // having no range at all. 614 if (ranges.Length() == 1 && ranges[0] == StyleUnicodeRange{0, 0x10ffff}) { 615 return nullptr; 616 } 617 auto charMap = MakeRefPtr<gfxCharacterMap>(256); 618 for (auto& range : ranges) { 619 charMap->SetRange(range.start, range.end); 620 } 621 charMap->Compact(); 622 // As it's common for multiple font resources to have the same 623 // unicode-range list, look for an existing copy of this map to share, 624 // or add this one to the sharing cache if not already present. 625 return gfxPlatformFontList::PlatformFontList()->FindCharMap(charMap); 626 } 627 628 bool FontFaceImpl::GetAttributesFromRule( 629 StyleLockedFontFaceRule* aData, gfxUserFontAttributes& aAttr, 630 const Maybe<gfxCharacterMap*>& aKnownCharMap) { 631 nsAtom* fontFamily = Servo_FontFaceRule_GetFamilyName(aData); 632 if (!fontFamily) { 633 return false; 634 } 635 636 aAttr.mFamilyName = nsAtomCString(fontFamily); 637 638 StyleComputedFontWeightRange weightRange; 639 if (Servo_FontFaceRule_GetFontWeight(aData, &weightRange)) { 640 aAttr.mRangeFlags &= ~gfxFontEntry::RangeFlags::eAutoWeight; 641 aAttr.mWeight = WeightRange(FontWeight::FromFloat(weightRange._0), 642 FontWeight::FromFloat(weightRange._1)); 643 } 644 645 StyleComputedFontStretchRange stretchRange; 646 if (Servo_FontFaceRule_GetFontStretch(aData, &stretchRange)) { 647 aAttr.mRangeFlags &= ~gfxFontEntry::RangeFlags::eAutoStretch; 648 aAttr.mStretch = StretchRange(stretchRange._0, stretchRange._1); 649 } 650 651 auto styleDesc = StyleComputedFontStyleDescriptor::Normal(); 652 if (Servo_FontFaceRule_GetFontStyle(aData, &styleDesc)) { 653 aAttr.mRangeFlags &= ~gfxFontEntry::RangeFlags::eAutoSlantStyle; 654 switch (styleDesc.tag) { 655 case StyleComputedFontStyleDescriptor::Tag::Italic: 656 aAttr.mStyle = SlantStyleRange(FontSlantStyle::ITALIC); 657 break; 658 case StyleComputedFontStyleDescriptor::Tag::Oblique: 659 aAttr.mStyle = SlantStyleRange( 660 FontSlantStyle::FromFloat(styleDesc.AsOblique()._0), 661 FontSlantStyle::FromFloat(styleDesc.AsOblique()._1)); 662 break; 663 default: 664 MOZ_ASSERT_UNREACHABLE("Unhandled tag"); 665 } 666 } 667 668 StylePercentage ascent{0}; 669 if (Servo_FontFaceRule_GetAscentOverride(aData, &ascent)) { 670 aAttr.mAscentOverride = ascent._0; 671 } 672 673 StylePercentage descent{0}; 674 if (Servo_FontFaceRule_GetDescentOverride(aData, &descent)) { 675 aAttr.mDescentOverride = descent._0; 676 } 677 678 StylePercentage lineGap{0}; 679 if (Servo_FontFaceRule_GetLineGapOverride(aData, &lineGap)) { 680 aAttr.mLineGapOverride = lineGap._0; 681 } 682 683 StylePercentage sizeAdjust; 684 if (Servo_FontFaceRule_GetSizeAdjust(aData, &sizeAdjust)) { 685 aAttr.mSizeAdjust = sizeAdjust._0; 686 } 687 688 StyleFontLanguageOverride langOverride; 689 if (Servo_FontFaceRule_GetFontLanguageOverride(aData, &langOverride)) { 690 aAttr.mLanguageOverride = langOverride._0; 691 } 692 693 Servo_FontFaceRule_GetFontDisplay(aData, &aAttr.mFontDisplay); 694 Servo_FontFaceRule_GetFeatureSettings(aData, &aAttr.mFeatureSettings); 695 Servo_FontFaceRule_GetVariationSettings(aData, &aAttr.mVariationSettings); 696 Servo_FontFaceRule_GetSources(aData, &aAttr.mSources); 697 if (aKnownCharMap) { 698 aAttr.mUnicodeRanges = aKnownCharMap.value(); 699 } else { 700 aAttr.mUnicodeRanges = ComputeCharacterMap(aData); 701 } 702 return true; 703 } 704 705 nsAtom* FontFaceImpl::GetFamilyName() const { 706 return Servo_FontFaceRule_GetFamilyName(GetData()); 707 } 708 709 void FontFaceImpl::DisconnectFromRule() { 710 MOZ_ASSERT(HasRule()); 711 712 // Make a copy of the descriptors. 713 mDescriptors = Servo_FontFaceRule_Clone(mRule).Consume(); 714 mRule = nullptr; 715 mInFontFaceSet = false; 716 } 717 718 bool FontFaceImpl::HasFontData() const { 719 return mSourceType == eSourceType_Buffer && mBufferSource; 720 } 721 722 already_AddRefed<gfxFontFaceBufferSource> FontFaceImpl::TakeBufferSource() { 723 MOZ_ASSERT(mBufferSource); 724 return mBufferSource.forget(); 725 } 726 727 bool FontFaceImpl::IsInFontFaceSet(FontFaceSetImpl* aFontFaceSet) const { 728 if (mFontFaceSet == aFontFaceSet) { 729 return mInFontFaceSet; 730 } 731 return mOtherFontFaceSets.Contains(aFontFaceSet); 732 } 733 734 void FontFaceImpl::AddFontFaceSet(FontFaceSetImpl* aFontFaceSet) { 735 MOZ_ASSERT(!IsInFontFaceSet(aFontFaceSet)); 736 737 auto doAddFontFaceSet = [&]() { 738 if (mFontFaceSet == aFontFaceSet) { 739 mInFontFaceSet = true; 740 } else { 741 mOtherFontFaceSets.AppendElement(aFontFaceSet); 742 } 743 }; 744 745 if (mUserFontEntry) { 746 AutoWriteLock lock(mUserFontEntry->Lock()); 747 doAddFontFaceSet(); 748 } else { 749 doAddFontFaceSet(); 750 } 751 } 752 753 void FontFaceImpl::RemoveFontFaceSet(FontFaceSetImpl* aFontFaceSet) { 754 MOZ_ASSERT(IsInFontFaceSet(aFontFaceSet)); 755 756 auto doRemoveFontFaceSet = [&]() { 757 if (mFontFaceSet == aFontFaceSet) { 758 mInFontFaceSet = false; 759 } else { 760 mOtherFontFaceSets.RemoveElement(aFontFaceSet); 761 } 762 }; 763 764 if (mUserFontEntry) { 765 AutoWriteLock lock(mUserFontEntry->Lock()); 766 doRemoveFontFaceSet(); 767 // The caller should be holding a strong reference to the FontFaceSetImpl. 768 mUserFontEntry->CheckUserFontSetLocked(); 769 } else { 770 doRemoveFontFaceSet(); 771 } 772 } 773 774 gfxCharacterMap* FontFaceImpl::GetUnicodeRangeAsCharacterMap() { 775 if (!mUnicodeRangeDirty) { 776 return mUnicodeRange; 777 } 778 mUnicodeRange = ComputeCharacterMap(GetData()); 779 mUnicodeRangeDirty = false; 780 return mUnicodeRange; 781 } 782 783 // -- FontFaceImpl::Entry 784 // -------------------------------------------------------- 785 786 /* virtual */ 787 void FontFaceImpl::Entry::SetLoadState(UserFontLoadState aLoadState) { 788 gfxUserFontEntry::SetLoadState(aLoadState); 789 FontFaceLoadStatus status = LoadStateToStatus(aLoadState); 790 791 nsTArray<RefPtr<FontFaceImpl>> fontFaces; 792 { 793 AutoReadLock lock(mLock); 794 fontFaces.SetCapacity(mFontFaces.Length()); 795 for (FontFaceImpl* f : mFontFaces) { 796 fontFaces.AppendElement(f); 797 } 798 } 799 800 for (FontFaceImpl* impl : fontFaces) { 801 auto* setImpl = impl->GetPrimaryFontFaceSet(); 802 if (setImpl->IsOnOwningThread()) { 803 impl->SetStatus(status); 804 } else { 805 setImpl->DispatchToOwningThread( 806 "FontFaceImpl::Entry::SetLoadState", 807 [self = RefPtr{impl}, status] { self->SetStatus(status); }); 808 } 809 } 810 } 811 812 /* virtual */ 813 void FontFaceImpl::Entry::GetUserFontSets( 814 nsTArray<RefPtr<gfxUserFontSet>>& aResult) { 815 AutoReadLock lock(mLock); 816 817 aResult.Clear(); 818 819 if (mFontSet) { 820 aResult.AppendElement(mFontSet); 821 } 822 823 for (FontFaceImpl* f : mFontFaces) { 824 if (f->mInFontFaceSet) { 825 aResult.AppendElement(f->mFontFaceSet); 826 } 827 for (FontFaceSetImpl* s : f->mOtherFontFaceSets) { 828 aResult.AppendElement(s); 829 } 830 } 831 832 // Remove duplicates. 833 aResult.Sort(); 834 auto it = std::unique(aResult.begin(), aResult.end()); 835 aResult.TruncateLength(it - aResult.begin()); 836 } 837 838 /* virtual */ already_AddRefed<gfxUserFontSet> 839 FontFaceImpl::Entry::GetUserFontSet() const { 840 AutoReadLock lock(mLock); 841 if (mFontSet) { 842 return do_AddRef(mFontSet); 843 } 844 if (NS_IsMainThread() && mLoadingFontSet) { 845 return do_AddRef(mLoadingFontSet); 846 } 847 return nullptr; 848 } 849 850 void FontFaceImpl::Entry::CheckUserFontSetLocked() { 851 // If this is the last font containing a strong reference to the set, we need 852 // to clear the reference as there is no longer anything guaranteeing the set 853 // will be kept alive. 854 if (mFontSet) { 855 auto* set = static_cast<FontFaceSetImpl*>(mFontSet); 856 for (FontFaceImpl* f : mFontFaces) { 857 if (f->mFontFaceSet == set || f->mOtherFontFaceSets.Contains(set)) { 858 return; 859 } 860 } 861 } 862 863 // If possible, promote the most recently added FontFace and its owning 864 // FontFaceSetImpl as the primary set. 865 if (!mFontFaces.IsEmpty()) { 866 mFontSet = mFontFaces.LastElement()->mFontFaceSet; 867 } else { 868 mFontSet = nullptr; 869 } 870 } 871 872 void FontFaceImpl::Entry::FindFontFaceOwners(nsTHashSet<FontFace*>& aOwners) { 873 AutoReadLock lock(mLock); 874 for (FontFaceImpl* f : mFontFaces) { 875 if (FontFace* owner = f->GetOwner()) { 876 aOwners.Insert(owner); 877 } 878 } 879 } 880 881 void FontFaceImpl::Entry::AddFontFace(FontFaceImpl* aFontFace) { 882 AutoWriteLock lock(mLock); 883 mFontFaces.AppendElement(aFontFace); 884 CheckUserFontSetLocked(); 885 } 886 887 void FontFaceImpl::Entry::RemoveFontFace(FontFaceImpl* aFontFace) { 888 AutoWriteLock lock(mLock); 889 mFontFaces.RemoveElement(aFontFace); 890 CheckUserFontSetLocked(); 891 } 892 893 } // namespace mozilla::dom