tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

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, &quoted, 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