tor-browser

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

gfxFontEntry.cpp (77631B)


      1 /* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
      2 /* This Source Code Form is subject to the terms of the Mozilla Public
      3 * License, v. 2.0. If a copy of the MPL was not distributed with this
      4 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
      5 
      6 #include "gfxFontEntry.h"
      7 
      8 #include "mozilla/FontPropertyTypes.h"
      9 
     10 #include "mozilla/Logging.h"
     11 
     12 #include "gfxTextRun.h"
     13 #include "gfxPlatform.h"
     14 #include "nsGkAtoms.h"
     15 
     16 #include "gfxTypes.h"
     17 #include "gfxContext.h"
     18 #include "gfxFontConstants.h"
     19 #include "gfxGraphiteShaper.h"
     20 #include "gfxHarfBuzzShaper.h"
     21 #include "gfxUserFontSet.h"
     22 #include "gfxPlatformFontList.h"
     23 #include "nsUnicodeProperties.h"
     24 #include "nsMathUtils.h"
     25 #include "nsBidiUtils.h"
     26 #include "nsStyleConsts.h"
     27 #include "mozilla/AppUnits.h"
     28 #include "mozilla/Likely.h"
     29 #include "mozilla/MemoryReporting.h"
     30 #include "mozilla/Preferences.h"
     31 #include "mozilla/ProfilerLabels.h"
     32 #include "mozilla/Services.h"
     33 #include "mozilla/StaticPrefs_layout.h"
     34 #include "gfxSVGGlyphs.h"
     35 #include "gfx2DGlue.h"
     36 
     37 #include "harfbuzz/hb.h"
     38 #include "harfbuzz/hb-ot.h"
     39 #include "graphite2/Font.h"
     40 
     41 #include "ThebesRLBox.h"
     42 
     43 #include <algorithm>
     44 
     45 using namespace mozilla;
     46 using namespace mozilla::gfx;
     47 using namespace mozilla::unicode;
     48 
     49 void gfxCharacterMap::NotifyMaybeReleased(gfxCharacterMap* aCmap) {
     50  // Tell gfxPlatformFontList that a charmap's refcount was decremented,
     51  // so it should check whether the object is to be deleted.
     52  gfxPlatformFontList::PlatformFontList()->MaybeRemoveCmap(aCmap);
     53 }
     54 
     55 gfxFontEntry::gfxFontEntry(const nsACString& aName, bool aIsStandardFace)
     56    : mName(aName),
     57      mLock("gfxFontEntry lock"),
     58      mFeatureInfoLock("gfxFontEntry featureInfo mutex"),
     59      mFixedPitch(false),
     60      mIsBadUnderlineFont(false),
     61      mIsUserFontContainer(false),
     62      mIsDataUserFont(false),
     63      mIsLocalUserFont(false),
     64      mStandardFace(aIsStandardFace),
     65      mIgnoreGDEF(false),
     66      mIgnoreGSUB(false),
     67      mSkipDefaultFeatureSpaceCheck(false),
     68      mSVGInitialized(false),
     69      mHasCmapTable(false),
     70      mGrFaceInitialized(false),
     71      mCheckedForColorGlyph(false),
     72      mCheckedForVariationAxes(false),
     73      mSpaceGlyphIsInvisible(LazyFlag::Uninitialized),
     74      mHasGraphiteTables(LazyFlag::Uninitialized),
     75      mHasGraphiteSpaceContextuals(LazyFlag::Uninitialized),
     76      mHasColorBitmapTable(LazyFlag::Uninitialized),
     77      mNeedsMaskForShadow(LazyFlag::Uninitialized),
     78      mHasSpaceFeatures(SpaceFeatures::Uninitialized) {
     79  mTrakTable.exchange(kTrakTableUninitialized);
     80  memset(&mDefaultSubSpaceFeatures, 0, sizeof(mDefaultSubSpaceFeatures));
     81  memset(&mNonDefaultSubSpaceFeatures, 0, sizeof(mNonDefaultSubSpaceFeatures));
     82 }
     83 
     84 gfxFontEntry::~gfxFontEntry() {
     85  // Should not be dropped by stylo
     86  MOZ_ASSERT(!gfxFontUtils::IsInServoTraversal());
     87 
     88  hb_blob_destroy(mCOLR.exchange(nullptr));
     89  hb_blob_destroy(mCPAL.exchange(nullptr));
     90 
     91  if (TrakTableInitialized()) {
     92    // Only if it was initialized, so that we don't try to call hb_blob_destroy
     93    // on the kTrakTableUninitialized flag value!
     94    hb_blob_destroy(mTrakTable.exchange(nullptr));
     95  }
     96 
     97  // For downloaded fonts, we need to tell the user font cache that this
     98  // entry is being deleted.
     99  if (mIsDataUserFont) {
    100    gfxUserFontSet::UserFontCache::ForgetFont(this);
    101  }
    102 
    103  if (mFeatureInputs) {
    104    for (auto iter = mFeatureInputs->Iter(); !iter.Done(); iter.Next()) {
    105      hb_set_t*& set = iter.Data();
    106      hb_set_destroy(set);
    107    }
    108  }
    109 
    110  mFontTableCache.reset(nullptr);
    111 
    112  delete mSVGGlyphs.exchange(nullptr);
    113  delete[] mUVSData.exchange(nullptr);
    114 
    115  gfxCharacterMap* cmap = mCharacterMap.exchange(nullptr);
    116  NS_IF_RELEASE(cmap);
    117 
    118  // By the time the entry is destroyed, all font instances that were
    119  // using it should already have been deleted, and so the HB and/or Gr
    120  // face objects should have been released.
    121  MOZ_ASSERT(!mHBFace);
    122  MOZ_ASSERT(!mGrFaceInitialized);
    123 }
    124 
    125 // Only used during initialization, before any other thread has a chance to see
    126 // the entry, so locking not required.
    127 void gfxFontEntry::InitializeFrom(fontlist::Face* aFace,
    128                                  const fontlist::Family* aFamily) {
    129  mShmemFace = aFace;
    130  mShmemFamily = aFamily;
    131  mStyleRange = aFace->mStyle;
    132  mWeightRange = aFace->mWeight;
    133  mStretchRange = aFace->mStretch;
    134  mFixedPitch = aFace->mFixedPitch;
    135  mIsBadUnderlineFont = aFamily->IsBadUnderlineFamily();
    136  auto* list = gfxPlatformFontList::PlatformFontList()->SharedFontList();
    137  mFamilyName = aFamily->DisplayName().AsString(list);
    138  mHasCmapTable = TrySetShmemCharacterMap();
    139 }
    140 
    141 bool gfxFontEntry::TrySetShmemCharacterMap() {
    142  MOZ_ASSERT(mShmemFace);
    143  auto list = gfxPlatformFontList::PlatformFontList()->SharedFontList();
    144  auto* shmemCmap = mShmemFace->mCharacterMap.ToPtr<const SharedBitSet>(list);
    145  mShmemCharacterMap.exchange(shmemCmap);
    146  return shmemCmap != nullptr;
    147 }
    148 
    149 bool gfxFontEntry::TestCharacterMap(uint32_t aCh) {
    150  if (!mCharacterMap && !mShmemCharacterMap) {
    151    ReadCMAP();
    152    MOZ_ASSERT(mCharacterMap || mShmemCharacterMap,
    153               "failed to initialize character map");
    154  }
    155  return mShmemCharacterMap ? GetShmemCharacterMap()->test(aCh)
    156                            : GetCharacterMap()->test(aCh);
    157 }
    158 
    159 void gfxFontEntry::EnsureUVSMapInitialized() {
    160  // mUVSOffset will not be initialized
    161  // until cmap is initialized.
    162  if (!mCharacterMap && !mShmemCharacterMap) {
    163    ReadCMAP();
    164    NS_ASSERTION(mCharacterMap || mShmemCharacterMap,
    165                 "failed to initialize character map");
    166  }
    167 
    168  if (!mUVSOffset) {
    169    return;
    170  }
    171 
    172  if (!mUVSData) {
    173    nsresult rv = NS_ERROR_NOT_AVAILABLE;
    174    const uint32_t kCmapTag = TRUETYPE_TAG('c', 'm', 'a', 'p');
    175    AutoTable cmapTable(this, kCmapTag);
    176    if (cmapTable) {
    177      const uint8_t* uvsData = nullptr;
    178      unsigned int cmapLen;
    179      const char* cmapData = hb_blob_get_data(cmapTable, &cmapLen);
    180      rv = gfxFontUtils::ReadCMAPTableFormat14(
    181          (const uint8_t*)cmapData + mUVSOffset, cmapLen - mUVSOffset, uvsData);
    182      if (NS_SUCCEEDED(rv)) {
    183        if (!mUVSData.compareExchange(nullptr, uvsData)) {
    184          delete uvsData;
    185        }
    186      }
    187    }
    188    if (NS_FAILED(rv)) {
    189      mUVSOffset = 0;  // don't try to read the table again
    190    }
    191  }
    192 }
    193 
    194 uint16_t gfxFontEntry::GetUVSGlyph(uint32_t aCh, uint32_t aVS) {
    195  EnsureUVSMapInitialized();
    196 
    197  if (const auto* uvsData = GetUVSData()) {
    198    return gfxFontUtils::MapUVSToGlyphFormat14(uvsData, aCh, aVS);
    199  }
    200 
    201  return 0;
    202 }
    203 
    204 bool gfxFontEntry::SupportsScriptInGSUB(const hb_tag_t* aScriptTags,
    205                                        uint32_t aNumTags) {
    206  auto face(GetHBFace());
    207 
    208  unsigned int index;
    209  hb_tag_t chosenScript;
    210  bool found = hb_ot_layout_table_select_script(
    211      face, TRUETYPE_TAG('G', 'S', 'U', 'B'), aNumTags, aScriptTags, &index,
    212      &chosenScript);
    213 
    214  return found && chosenScript != TRUETYPE_TAG('D', 'F', 'L', 'T');
    215 }
    216 
    217 nsresult gfxFontEntry::ReadCMAP(FontInfoData* aFontInfoData) {
    218  MOZ_ASSERT(false, "using default no-op implementation of ReadCMAP");
    219  RefPtr<gfxCharacterMap> cmap = new gfxCharacterMap(0);
    220  if (mCharacterMap.compareExchange(nullptr, cmap.get())) {
    221    cmap.forget().leak();  // mCharacterMap now owns the reference
    222  }
    223  return NS_OK;
    224 }
    225 
    226 nsCString gfxFontEntry::RealFaceName() {
    227  AutoTable nameTable(this, TRUETYPE_TAG('n', 'a', 'm', 'e'));
    228  if (nameTable) {
    229    nsAutoCString name;
    230    nsresult rv = gfxFontUtils::GetFullNameFromTable(nameTable, name);
    231    if (NS_SUCCEEDED(rv)) {
    232      return std::move(name);
    233    }
    234  }
    235  return Name();
    236 }
    237 
    238 already_AddRefed<gfxFont> gfxFontEntry::FindOrMakeFont(
    239    const gfxFontStyle* aStyle, gfxCharacterMap* aUnicodeRangeMap) {
    240  RefPtr<gfxFont> font =
    241      gfxFontCache::GetCache()->Lookup(this, aStyle, aUnicodeRangeMap);
    242  if (font) {
    243    return font.forget();
    244  }
    245 
    246  gfxFont* newFont = CreateFontInstance(aStyle);
    247  if (!newFont) {
    248    return nullptr;
    249  }
    250  if (!newFont->Valid()) {
    251    newFont->Destroy();
    252    return nullptr;
    253  }
    254  newFont->SetUnicodeRangeMap(aUnicodeRangeMap);
    255  return gfxFontCache::GetCache()->MaybeInsert(newFont);
    256 }
    257 
    258 uint16_t gfxFontEntry::UnitsPerEm() {
    259  {
    260    AutoReadLock lock(mLock);
    261    if (mUnitsPerEm) {
    262      return mUnitsPerEm;
    263    }
    264  }
    265 
    266  AutoTable headTable(this, TRUETYPE_TAG('h', 'e', 'a', 'd'));
    267  AutoWriteLock lock(mLock);
    268 
    269  if (!mUnitsPerEm) {
    270    if (headTable) {
    271      uint32_t len;
    272      const HeadTable* head =
    273          reinterpret_cast<const HeadTable*>(hb_blob_get_data(headTable, &len));
    274      if (len >= sizeof(HeadTable)) {
    275        if (int16_t(head->xMax) > int16_t(head->xMin) &&
    276            int16_t(head->yMax) > int16_t(head->yMin)) {
    277          mXMin = head->xMin;
    278          mYMin = head->yMin;
    279          mXMax = head->xMax;
    280          mYMax = head->yMax;
    281        }
    282        mUnitsPerEm = head->unitsPerEm;
    283      }
    284    }
    285 
    286    // if we didn't find a usable 'head' table, or if the value was
    287    // outside the valid range, record it as invalid
    288    if (mUnitsPerEm < kMinUPEM || mUnitsPerEm > kMaxUPEM) {
    289      mUnitsPerEm = kInvalidUPEM;
    290    }
    291  }
    292 
    293  return mUnitsPerEm;
    294 }
    295 
    296 bool gfxFontEntry::HasSVGGlyph(uint32_t aGlyphId) {
    297  MOZ_ASSERT(mSVGInitialized,
    298             "SVG data has not yet been loaded. TryGetSVGData() first.");
    299  return GetSVGGlyphs()->HasSVGGlyph(aGlyphId);
    300 }
    301 
    302 bool gfxFontEntry::GetSVGGlyphExtents(DrawTarget* aDrawTarget,
    303                                      uint32_t aGlyphId, gfxFloat aSize,
    304                                      gfxRect* aResult) {
    305  MOZ_ASSERT(mSVGInitialized,
    306             "SVG data has not yet been loaded. TryGetSVGData() first.");
    307  MOZ_ASSERT(mUnitsPerEm >= kMinUPEM && mUnitsPerEm <= kMaxUPEM,
    308             "font has invalid unitsPerEm");
    309 
    310  gfxMatrix svgToApp(aSize / mUnitsPerEm, 0, 0, aSize / mUnitsPerEm, 0, 0);
    311  return GetSVGGlyphs()->GetGlyphExtents(aGlyphId, svgToApp, aResult);
    312 }
    313 
    314 void gfxFontEntry::RenderSVGGlyph(gfxContext* aContext, uint32_t aGlyphId,
    315                                  SVGContextPaint* aContextPaint) {
    316  MOZ_ASSERT(mSVGInitialized,
    317             "SVG data has not yet been loaded. TryGetSVGData() first.");
    318  GetSVGGlyphs()->RenderGlyph(aContext, aGlyphId, aContextPaint);
    319 }
    320 
    321 bool gfxFontEntry::TryGetSVGData(const gfxFont* aFont) {
    322  if (!gfxPlatform::GetPlatform()->OpenTypeSVGEnabled()) {
    323    return false;
    324  }
    325 
    326  // We don't support SVG-in-OT glyphs in offscreen-canvas worker threads.
    327  if (!NS_IsMainThread()) {
    328    return false;
    329  }
    330 
    331  if (!mSVGInitialized) {
    332    // If UnitsPerEm is not known/valid, we can't use SVG glyphs
    333    if (UnitsPerEm() == kInvalidUPEM) {
    334      mSVGInitialized = true;
    335      return false;
    336    }
    337 
    338    // We don't use AutoTable here because we'll pass ownership of this
    339    // blob to the gfxSVGGlyphs, once we've confirmed the table exists
    340    hb_blob_t* svgTable = GetFontTable(TRUETYPE_TAG('S', 'V', 'G', ' '));
    341    if (!svgTable) {
    342      mSVGInitialized = true;
    343      return false;
    344    }
    345 
    346    // gfxSVGGlyphs will hb_blob_destroy() the table when it is finished
    347    // with it.
    348    auto* svgGlyphs = new gfxSVGGlyphs(svgTable, this);
    349    if (!mSVGGlyphs.compareExchange(nullptr, svgGlyphs)) {
    350      delete svgGlyphs;
    351    }
    352    mSVGInitialized = true;
    353  }
    354 
    355  if (GetSVGGlyphs() && aFont) {
    356    AutoWriteLock lock(mLock);
    357    if (!mFontsUsingSVGGlyphs.Contains(aFont)) {
    358      mFontsUsingSVGGlyphs.AppendElement(aFont);
    359    }
    360  }
    361 
    362  return !!GetSVGGlyphs();
    363 }
    364 
    365 void gfxFontEntry::NotifyFontDestroyed(gfxFont* aFont) {
    366  AutoWriteLock lock(mLock);
    367  mFontsUsingSVGGlyphs.RemoveElement(aFont);
    368 }
    369 
    370 void gfxFontEntry::NotifyGlyphsChanged() {
    371  AutoReadLock lock(mLock);
    372  for (uint32_t i = 0, count = mFontsUsingSVGGlyphs.Length(); i < count; ++i) {
    373    const gfxFont* font = mFontsUsingSVGGlyphs[i];
    374    font->NotifyGlyphsChanged();
    375  }
    376 }
    377 
    378 bool gfxFontEntry::TryGetColorGlyphs() {
    379  if (mCheckedForColorGlyph) {
    380    return mCOLR && mCPAL;
    381  }
    382 
    383  auto* colr = GetFontTable(TRUETYPE_TAG('C', 'O', 'L', 'R'));
    384  auto* cpal = colr ? GetFontTable(TRUETYPE_TAG('C', 'P', 'A', 'L')) : nullptr;
    385 
    386  if (colr && cpal && gfx::COLRFonts::ValidateColorGlyphs(colr, cpal)) {
    387    if (!mCOLR.compareExchange(nullptr, colr)) {
    388      hb_blob_destroy(colr);
    389    }
    390    if (!mCPAL.compareExchange(nullptr, cpal)) {
    391      hb_blob_destroy(cpal);
    392    }
    393  } else {
    394    hb_blob_destroy(colr);
    395    hb_blob_destroy(cpal);
    396  }
    397 
    398  mCheckedForColorGlyph = true;
    399  return mCOLR && mCPAL;
    400 }
    401 
    402 /**
    403 * FontTableBlobData
    404 *
    405 * See FontTableHashEntry for the general strategy.
    406 */
    407 
    408 class gfxFontEntry::FontTableBlobData {
    409 public:
    410  explicit FontTableBlobData(nsTArray<uint8_t>&& aBuffer)
    411      : mTableData(std::move(aBuffer)), mFontEntry(nullptr), mHashKey(0) {
    412    MOZ_COUNT_CTOR(FontTableBlobData);
    413  }
    414 
    415  ~FontTableBlobData() {
    416    MOZ_COUNT_DTOR(FontTableBlobData);
    417    if (mFontEntry && mHashKey) {
    418      AutoWriteLock lock(mFontEntry->mLock);
    419      mFontEntry->mFontTableCache->RemoveEntry(mHashKey);
    420    }
    421  }
    422 
    423  // Useful for creating blobs
    424  const char* GetTable() const {
    425    return reinterpret_cast<const char*>(mTableData.Elements());
    426  }
    427  uint32_t GetTableLength() const { return mTableData.Length(); }
    428 
    429  // Tell this FontTableBlobData to remove the HashEntry when this is
    430  // destroyed.
    431  void ManageHashEntry(gfxFontEntry* aFontEntry, uint32_t aHashKey) {
    432    mFontEntry = aFontEntry;
    433    mHashKey = aHashKey;
    434  }
    435 
    436  // Disconnect from the HashEntry (because the blob has already been
    437  // removed from the hashtable).
    438  void ForgetHashEntry() {
    439    mFontEntry = nullptr;
    440    mHashKey = 0;
    441  }
    442 
    443  size_t SizeOfExcludingThis(MallocSizeOf aMallocSizeOf) const {
    444    return mTableData.ShallowSizeOfExcludingThis(aMallocSizeOf);
    445  }
    446  size_t SizeOfIncludingThis(MallocSizeOf aMallocSizeOf) const {
    447    return aMallocSizeOf(this) + SizeOfExcludingThis(aMallocSizeOf);
    448  }
    449 
    450 private:
    451  // The font table data block
    452  const nsTArray<uint8_t> mTableData;
    453 
    454  // The blob destroy function needs to know the owning font entry
    455  // so that it can take the font-entry's lock while modifying the
    456  // hashtable; and the hashtable key, so that it can remove the entry.
    457  gfxFontEntry* mFontEntry;
    458  uint32_t mHashKey;
    459 
    460  // not implemented
    461  FontTableBlobData(const FontTableBlobData&);
    462 };
    463 
    464 hb_blob_t* gfxFontEntry::FontTableHashEntry::ShareTableAndGetBlob(
    465    nsTArray<uint8_t>&& aTable, gfxFontEntry* aFontEntry) {
    466  Clear();
    467  // adopts elements of aTable
    468  mSharedBlobData = new FontTableBlobData(std::move(aTable));
    469 
    470  mBlob = hb_blob_create(
    471      mSharedBlobData->GetTable(), mSharedBlobData->GetTableLength(),
    472      HB_MEMORY_MODE_READONLY, mSharedBlobData, DeleteFontTableBlobData);
    473  if (mBlob == hb_blob_get_empty()) {
    474    // The FontTableBlobData was destroyed during hb_blob_create().
    475    // The (empty) blob will still be held in the hashtable with a strong
    476    // reference.
    477    mSharedBlobData = nullptr;
    478    return hb_blob_reference(mBlob);
    479  }
    480 
    481  // Tell the FontTableBlobData to remove this hash entry when destroyed.
    482  // The hashtable does not keep a strong reference.
    483  mSharedBlobData->ManageHashEntry(aFontEntry, GetKey());
    484  return mBlob;
    485 }
    486 
    487 void gfxFontEntry::FontTableHashEntry::Clear() {
    488  // If the FontTableBlobData is managing the hash entry, then the blob is
    489  // not owned by this HashEntry; otherwise there is strong reference to the
    490  // blob that must be removed.
    491  if (mSharedBlobData) {
    492    mSharedBlobData->ForgetHashEntry();
    493    mSharedBlobData = nullptr;
    494  } else {
    495    hb_blob_destroy(mBlob);
    496  }
    497  mBlob = nullptr;
    498 }
    499 
    500 // a hb_destroy_func for hb_blob_create
    501 
    502 /* static */
    503 void gfxFontEntry::FontTableHashEntry::DeleteFontTableBlobData(
    504    void* aBlobData) {
    505  delete static_cast<FontTableBlobData*>(aBlobData);
    506 }
    507 
    508 hb_blob_t* gfxFontEntry::FontTableHashEntry::GetBlob() const {
    509  return hb_blob_reference(mBlob);
    510 }
    511 
    512 bool gfxFontEntry::GetExistingFontTable(uint32_t aTag, hb_blob_t** aBlob) {
    513  AutoReadLock lock(mLock);
    514 
    515  if (MOZ_UNLIKELY(!mFontTableCache)) {
    516    return false;
    517  }
    518 
    519  if (const auto* entry = mFontTableCache->GetEntry(aTag)) {
    520    *aBlob = entry->GetBlob();
    521    return true;
    522  }
    523 
    524  return false;
    525 }
    526 
    527 hb_blob_t* gfxFontEntry::ShareFontTableAndGetBlob(uint32_t aTag,
    528                                                  nsTArray<uint8_t>* aBuffer) {
    529  AutoWriteLock lock(mLock);
    530 
    531  if (MOZ_UNLIKELY(!mFontTableCache)) {
    532    mFontTableCache = MakeUnique<FontTableCache>(8);
    533  }
    534 
    535  FontTableHashEntry* entry;
    536  if (MOZ_UNLIKELY(entry = mFontTableCache->GetEntry(aTag))) {
    537    // We must have been racing with another GetFontTable for the same table,
    538    // and it won the race and filled in the entry before we took the lock.
    539    // Ignore `aBuffer` and return a reference to the existing blob.
    540    return entry->GetBlob();
    541  }
    542 
    543  // Infallible PutEntry call, so `entry` will be non-null.
    544  entry = mFontTableCache->PutEntry(aTag);
    545 
    546  if (!aBuffer) {
    547    // ensure the entry is null
    548    entry->Clear();
    549    return nullptr;
    550  }
    551 
    552  return entry->ShareTableAndGetBlob(std::move(*aBuffer), this);
    553 }
    554 
    555 already_AddRefed<gfxCharacterMap> gfxFontEntry::GetCMAPFromFontInfo(
    556    FontInfoData* aFontInfoData, uint32_t& aUVSOffset) {
    557  if (!aFontInfoData || !aFontInfoData->mLoadCmaps) {
    558    return nullptr;
    559  }
    560 
    561  return aFontInfoData->GetCMAP(mName, aUVSOffset);
    562 }
    563 
    564 hb_blob_t* gfxFontEntry::GetFontTable(uint32_t aTag) {
    565  hb_blob_t* blob;
    566  if (GetExistingFontTable(aTag, &blob)) {
    567    return blob;
    568  }
    569 
    570  nsTArray<uint8_t> buffer;
    571  bool haveTable = NS_SUCCEEDED(CopyFontTable(aTag, buffer));
    572 
    573  return ShareFontTableAndGetBlob(aTag, haveTable ? &buffer : nullptr);
    574 }
    575 
    576 // callback for HarfBuzz to get a font table (in hb_blob_t form)
    577 // from the font entry (passed as aUserData)
    578 /*static*/
    579 hb_blob_t* gfxFontEntry::HBGetTable(hb_face_t* face, uint32_t aTag,
    580                                    void* aUserData) {
    581  gfxFontEntry* fontEntry = static_cast<gfxFontEntry*>(aUserData);
    582 
    583  // bug 589682 - ignore the GDEF table in buggy fonts (applies to
    584  // Italic and BoldItalic faces of Times New Roman)
    585  if (aTag == TRUETYPE_TAG('G', 'D', 'E', 'F') && fontEntry->IgnoreGDEF()) {
    586    return nullptr;
    587  }
    588 
    589  // bug 721719 - ignore the GSUB table in buggy fonts (applies to Roboto,
    590  // at least on some Android ICS devices; set in gfxFT2FontList.cpp)
    591  if (aTag == TRUETYPE_TAG('G', 'S', 'U', 'B') && fontEntry->IgnoreGSUB()) {
    592    return nullptr;
    593  }
    594 
    595  return fontEntry->GetFontTable(aTag);
    596 }
    597 
    598 static thread_local gfxFontEntry* tl_grGetFontTableCallbackData = nullptr;
    599 
    600 class gfxFontEntryCallbacks {
    601 public:
    602  static tainted_gr<const void*> GrGetTable(
    603      rlbox_sandbox_gr& sandbox, tainted_gr<const void*> /* aAppFaceHandle */,
    604      tainted_gr<unsigned int> aName, tainted_gr<unsigned int*> aLen) {
    605    gfxFontEntry* fontEntry = tl_grGetFontTableCallbackData;
    606    *aLen = 0;
    607    tainted_gr<const void*> ret = nullptr;
    608 
    609    if (fontEntry) {
    610      unsigned int fontTableKey = aName.unverified_safe_because(
    611          "This is only being used to index into a hashmap, which is robust "
    612          "for any value. No checks needed.");
    613      gfxFontUtils::AutoHBBlob blob(fontEntry->GetFontTable(fontTableKey));
    614 
    615      if (blob) {
    616        unsigned int blobLength;
    617        const void* tableData = hb_blob_get_data(blob, &blobLength);
    618        // tableData is read-only data shared with the sandbox.
    619        // Making a copy in sandbox memory
    620        tainted_gr<void*> t_tableData = rlbox::sandbox_reinterpret_cast<void*>(
    621            sandbox.malloc_in_sandbox<char>(blobLength));
    622        if (t_tableData) {
    623          rlbox::memcpy(sandbox, t_tableData, tableData, blobLength);
    624          *aLen = blobLength;
    625          ret = rlbox::sandbox_const_cast<const void*>(t_tableData);
    626        }
    627      }
    628    }
    629 
    630    return ret;
    631  }
    632 
    633  static void GrReleaseTable(rlbox_sandbox_gr& sandbox,
    634                             tainted_gr<const void*> /* aAppFaceHandle */,
    635                             tainted_gr<const void*> aTableBuffer) {
    636    sandbox.free_in_sandbox(aTableBuffer);
    637  }
    638 
    639  static tainted_gr<float> GrGetAdvance(rlbox_sandbox_gr& sandbox,
    640                                        tainted_gr<const void*> appFontHandle,
    641                                        tainted_gr<uint16_t> glyphid) {
    642    tainted_opaque_gr<float> ret = gfxGraphiteShaper::GrGetAdvance(
    643        sandbox, appFontHandle.to_opaque(), glyphid.to_opaque());
    644    return rlbox::from_opaque(ret);
    645  }
    646 };
    647 
    648 struct gfxFontEntry::GrSandboxData {
    649  rlbox_sandbox_gr sandbox;
    650  sandbox_callback_gr<const void* (*)(const void*, unsigned int, unsigned int*)>
    651      grGetTableCallback;
    652  sandbox_callback_gr<void (*)(const void*, const void*)>
    653      grReleaseTableCallback;
    654  // Text Shapers register a callback to get glyph advances
    655  sandbox_callback_gr<float (*)(const void*, uint16_t)>
    656      grGetGlyphAdvanceCallback;
    657 
    658  GrSandboxData() {
    659 #if defined(MOZ_WASM_SANDBOXING_GRAPHITE)
    660    sandbox.create_sandbox(/* shouldAbortOnFailure = */ true,
    661                           /* custom capacity = */ nullptr,
    662                           "rlbox_wasm2c_graphite");
    663 #else
    664    sandbox.create_sandbox();
    665 #endif
    666    grGetTableCallback =
    667        sandbox.register_callback(gfxFontEntryCallbacks::GrGetTable);
    668    grReleaseTableCallback =
    669        sandbox.register_callback(gfxFontEntryCallbacks::GrReleaseTable);
    670    grGetGlyphAdvanceCallback =
    671        sandbox.register_callback(gfxFontEntryCallbacks::GrGetAdvance);
    672  }
    673 
    674  ~GrSandboxData() {
    675    grGetTableCallback.unregister();
    676    grReleaseTableCallback.unregister();
    677    grGetGlyphAdvanceCallback.unregister();
    678    sandbox.destroy_sandbox();
    679  }
    680 };
    681 
    682 rlbox_sandbox_gr* gfxFontEntry::GetGrSandbox() {
    683  AutoReadLock lock(mLock);
    684  MOZ_ASSERT(mSandboxData != nullptr);
    685  return &mSandboxData->sandbox;
    686 }
    687 
    688 sandbox_callback_gr<float (*)(const void*, uint16_t)>*
    689 gfxFontEntry::GetGrSandboxAdvanceCallbackHandle() {
    690  AutoReadLock lock(mLock);
    691  MOZ_ASSERT(mSandboxData != nullptr);
    692  return &mSandboxData->grGetGlyphAdvanceCallback;
    693 }
    694 
    695 tainted_opaque_gr<gr_face*> gfxFontEntry::GetGrFace() {
    696  if (!mGrFaceInitialized) {
    697    // When possible, the below code will use WASM as a sandboxing mechanism.
    698    // At this time the wasm sandbox does not support threads.
    699    // If Thebes is updated to make callst to the sandbox on multiple threaads,
    700    // we need to make sure the underlying sandbox supports threading.
    701    MOZ_ASSERT(NS_IsMainThread());
    702 
    703    mSandboxData = new GrSandboxData();
    704 
    705    auto p_faceOps = mSandboxData->sandbox.malloc_in_sandbox<gr_face_ops>();
    706    if (!p_faceOps) {
    707      MOZ_CRASH("Graphite sandbox memory allocation failed");
    708    }
    709    p_faceOps->size = sizeof(*p_faceOps);
    710    p_faceOps->get_table = mSandboxData->grGetTableCallback;
    711    p_faceOps->release_table = mSandboxData->grReleaseTableCallback;
    712 
    713    tl_grGetFontTableCallbackData = this;
    714    auto face = sandbox_invoke(
    715        mSandboxData->sandbox, gr_make_face_with_ops,
    716        // For security, we do not pass the callback data to this arg, and use
    717        // a TLS var instead. However, gr_make_face_with_ops expects this to
    718        // be a non null ptr. Therefore,  we should pass some dummy non null
    719        // pointer which will be passed to callbacks, but never used. Let's just
    720        // pass p_faceOps again, as this is a non-null tainted pointer.
    721        p_faceOps /* appFaceHandle */, p_faceOps, gr_face_default);
    722    tl_grGetFontTableCallbackData = nullptr;
    723    mGrFace = face.to_opaque();
    724    mGrFaceInitialized = true;
    725    mSandboxData->sandbox.free_in_sandbox(p_faceOps);
    726  }
    727  ++mGrFaceRefCnt;
    728  return mGrFace;
    729 }
    730 
    731 void gfxFontEntry::ReleaseGrFace(tainted_opaque_gr<gr_face*> aFace) {
    732  MOZ_ASSERT(
    733      (rlbox::from_opaque(aFace) == rlbox::from_opaque(mGrFace))
    734          .unverified_safe_because(
    735              "This is safe as the only thing we are doing is comparing "
    736              "addresses of two tainted pointers. Furthermore this is used "
    737              "merely as a debugging aid in the debug builds. This function is "
    738              "called only from the trusted Firefox code rather than the "
    739              "untrusted libGraphite."));  // sanity-check
    740  MOZ_ASSERT(mGrFaceRefCnt > 0);
    741  if (--mGrFaceRefCnt == 0) {
    742    auto t_mGrFace = rlbox::from_opaque(mGrFace);
    743 
    744    tl_grGetFontTableCallbackData = this;
    745    sandbox_invoke(mSandboxData->sandbox, gr_face_destroy, t_mGrFace);
    746    tl_grGetFontTableCallbackData = nullptr;
    747 
    748    t_mGrFace = nullptr;
    749    mGrFace = t_mGrFace.to_opaque();
    750 
    751    delete mSandboxData;
    752    mSandboxData = nullptr;
    753 
    754    mGrFaceInitialized = false;
    755  }
    756 }
    757 
    758 void gfxFontEntry::DisconnectSVG() {
    759  if (mSVGInitialized && mSVGGlyphs) {
    760    mSVGGlyphs = nullptr;
    761    mSVGInitialized = false;
    762  }
    763 }
    764 
    765 bool gfxFontEntry::HasFontTable(uint32_t aTableTag) {
    766  AutoTable table(this, aTableTag);
    767  return table && hb_blob_get_length(table) > 0;
    768 }
    769 
    770 tainted_boolean_hint gfxFontEntry::HasGraphiteSpaceContextuals() {
    771  LazyFlag flag = mHasGraphiteSpaceContextuals;
    772  if (flag == LazyFlag::Uninitialized) {
    773    auto face = GetGrFace();
    774    auto t_face = rlbox::from_opaque(face);
    775    if (t_face) {
    776      tainted_gr<const gr_faceinfo*> faceInfo =
    777          sandbox_invoke(mSandboxData->sandbox, gr_face_info, t_face, 0);
    778      // Comparison with a value in sandboxed memory returns a
    779      // tainted_boolean_hint, i.e. a "hint", since the value could be changed
    780      // maliciously at any moment.
    781      tainted_boolean_hint is_not_none =
    782          faceInfo->space_contextuals != gr_faceinfo::gr_space_none;
    783      flag = is_not_none.unverified_safe_because(
    784                 "Note ideally mHasGraphiteSpaceContextuals would be "
    785                 "tainted_boolean_hint, but RLBox does not yet support "
    786                 "bitfields, so it is not wrapped. However, its value is only "
    787                 "ever accessed through this function which returns a "
    788                 "tainted_boolean_hint, so unwrapping temporarily is safe. "
    789                 "We remove the wrapper now and re-add it below.")
    790                 ? LazyFlag::Yes
    791                 : LazyFlag::No;
    792    }
    793    ReleaseGrFace(face);  // always balance GetGrFace, even if face is null
    794    mHasGraphiteSpaceContextuals = flag;
    795  }
    796 
    797  return tainted_boolean_hint(flag == LazyFlag::Yes);
    798 }
    799 
    800 #define FEATURE_SCRIPT_MASK 0x000000ff  // script index replaces low byte of tag
    801 
    802 static_assert(int(intl::Script::NUM_SCRIPT_CODES) <= FEATURE_SCRIPT_MASK,
    803              "Too many script codes");
    804 
    805 // high-order three bytes of tag with script in low-order byte
    806 #define SCRIPT_FEATURE(s, tag)        \
    807  (((~FEATURE_SCRIPT_MASK) & (tag)) | \
    808   ((FEATURE_SCRIPT_MASK) & static_cast<uint32_t>(s)))
    809 
    810 bool gfxFontEntry::SupportsOpenTypeFeature(Script aScript,
    811                                           uint32_t aFeatureTag) {
    812  MutexAutoLock lock(mFeatureInfoLock);
    813  if (!mSupportedFeatures) {
    814    mSupportedFeatures = MakeUnique<nsTHashMap<nsUint32HashKey, bool>>();
    815  }
    816 
    817  // note: high-order three bytes *must* be unique for each feature
    818  // listed below (see SCRIPT_FEATURE macro def'n)
    819  NS_ASSERTION(aFeatureTag == HB_TAG('s', 'm', 'c', 'p') ||
    820                   aFeatureTag == HB_TAG('c', '2', 's', 'c') ||
    821                   aFeatureTag == HB_TAG('p', 'c', 'a', 'p') ||
    822                   aFeatureTag == HB_TAG('c', '2', 'p', 'c') ||
    823                   aFeatureTag == HB_TAG('s', 'u', 'p', 's') ||
    824                   aFeatureTag == HB_TAG('s', 'u', 'b', 's') ||
    825                   aFeatureTag == HB_TAG('v', 'e', 'r', 't') ||
    826                   aFeatureTag == HB_TAG('r', 't', 'l', 'm'),
    827               "use of unknown feature tag");
    828 
    829  // note: graphite feature support uses the last script index
    830  NS_ASSERTION(int(aScript) < FEATURE_SCRIPT_MASK - 1,
    831               "need to bump the size of the feature shift");
    832 
    833  uint32_t scriptFeature = SCRIPT_FEATURE(aScript, aFeatureTag);
    834  return mSupportedFeatures->LookupOrInsertWith(scriptFeature, [&] {
    835    bool result = false;
    836    auto face(GetHBFace());
    837 
    838    if (hb_ot_layout_has_substitution(face)) {
    839      hb_script_t hbScript =
    840          gfxHarfBuzzShaper::GetHBScriptUsedForShaping(aScript);
    841 
    842      // Get the OpenType tag(s) that match this script code
    843      unsigned int scriptCount = 4;
    844      hb_tag_t scriptTags[4];
    845      hb_ot_tags_from_script_and_language(hbScript, HB_LANGUAGE_INVALID,
    846                                          &scriptCount, scriptTags, nullptr,
    847                                          nullptr);
    848 
    849      // Append DEFAULT to the returned tags, if room
    850      if (scriptCount < 4) {
    851        scriptTags[scriptCount++] = HB_OT_TAG_DEFAULT_SCRIPT;
    852      }
    853 
    854      // Now check for 'smcp' under the first of those scripts that is present
    855      const hb_tag_t kGSUB = HB_TAG('G', 'S', 'U', 'B');
    856      result = std::any_of(scriptTags, scriptTags + scriptCount,
    857                           [&](const hb_tag_t& scriptTag) {
    858                             unsigned int scriptIndex;
    859                             return hb_ot_layout_table_find_script(
    860                                        face, kGSUB, scriptTag, &scriptIndex) &&
    861                                    hb_ot_layout_language_find_feature(
    862                                        face, kGSUB, scriptIndex,
    863                                        HB_OT_LAYOUT_DEFAULT_LANGUAGE_INDEX,
    864                                        aFeatureTag, nullptr);
    865                           });
    866    }
    867 
    868    return result;
    869  });
    870 }
    871 
    872 const hb_set_t* gfxFontEntry::InputsForOpenTypeFeature(Script aScript,
    873                                                       uint32_t aFeatureTag) {
    874  MutexAutoLock lock(mFeatureInfoLock);
    875  if (!mFeatureInputs) {
    876    mFeatureInputs = MakeUnique<nsTHashMap<nsUint32HashKey, hb_set_t*>>();
    877  }
    878 
    879  NS_ASSERTION(aFeatureTag == HB_TAG('s', 'u', 'p', 's') ||
    880                   aFeatureTag == HB_TAG('s', 'u', 'b', 's') ||
    881                   aFeatureTag == HB_TAG('v', 'e', 'r', 't') ||
    882                   aFeatureTag == HB_TAG('r', 't', 'l', 'm'),
    883               "use of unknown feature tag");
    884 
    885  uint32_t scriptFeature = SCRIPT_FEATURE(aScript, aFeatureTag);
    886  hb_set_t* inputGlyphs;
    887  if (mFeatureInputs->Get(scriptFeature, &inputGlyphs)) {
    888    return inputGlyphs;
    889  }
    890 
    891  inputGlyphs = hb_set_create();
    892 
    893  auto face(GetHBFace());
    894 
    895  if (hb_ot_layout_has_substitution(face)) {
    896    hb_script_t hbScript =
    897        gfxHarfBuzzShaper::GetHBScriptUsedForShaping(aScript);
    898 
    899    // Get the OpenType tag(s) that match this script code
    900    unsigned int scriptCount = 4;
    901    hb_tag_t scriptTags[5];  // space for null terminator
    902    hb_ot_tags_from_script_and_language(hbScript, HB_LANGUAGE_INVALID,
    903                                        &scriptCount, scriptTags, nullptr,
    904                                        nullptr);
    905 
    906    // Append DEFAULT to the returned tags, if room
    907    if (scriptCount < 4) {
    908      scriptTags[scriptCount++] = HB_OT_TAG_DEFAULT_SCRIPT;
    909    }
    910    scriptTags[scriptCount++] = 0;
    911 
    912    const hb_tag_t kGSUB = HB_TAG('G', 'S', 'U', 'B');
    913    hb_tag_t features[2] = {aFeatureTag, HB_TAG_NONE};
    914    hb_set_t* featurelookups = hb_set_create();
    915    hb_ot_layout_collect_lookups(face, kGSUB, scriptTags, nullptr, features,
    916                                 featurelookups);
    917    hb_codepoint_t index = -1;
    918    while (hb_set_next(featurelookups, &index)) {
    919      hb_ot_layout_lookup_collect_glyphs(face, kGSUB, index, nullptr,
    920                                         inputGlyphs, nullptr, nullptr);
    921    }
    922    hb_set_destroy(featurelookups);
    923  }
    924 
    925  mFeatureInputs->InsertOrUpdate(scriptFeature, inputGlyphs);
    926  return inputGlyphs;
    927 }
    928 
    929 bool gfxFontEntry::SupportsGraphiteFeature(uint32_t aFeatureTag) {
    930  MutexAutoLock lock(mFeatureInfoLock);
    931 
    932  if (!mSupportedFeatures) {
    933    mSupportedFeatures = MakeUnique<nsTHashMap<nsUint32HashKey, bool>>();
    934  }
    935 
    936  // note: high-order three bytes *must* be unique for each feature
    937  // listed below (see SCRIPT_FEATURE macro def'n)
    938  NS_ASSERTION(aFeatureTag == HB_TAG('s', 'm', 'c', 'p') ||
    939                   aFeatureTag == HB_TAG('c', '2', 's', 'c') ||
    940                   aFeatureTag == HB_TAG('p', 'c', 'a', 'p') ||
    941                   aFeatureTag == HB_TAG('c', '2', 'p', 'c') ||
    942                   aFeatureTag == HB_TAG('s', 'u', 'p', 's') ||
    943                   aFeatureTag == HB_TAG('s', 'u', 'b', 's'),
    944               "use of unknown feature tag");
    945 
    946  // graphite feature check uses the last script slot
    947  uint32_t scriptFeature = SCRIPT_FEATURE(FEATURE_SCRIPT_MASK, aFeatureTag);
    948  bool result;
    949  if (mSupportedFeatures->Get(scriptFeature, &result)) {
    950    return result;
    951  }
    952 
    953  auto face = GetGrFace();
    954  auto t_face = rlbox::from_opaque(face);
    955  result = t_face ? sandbox_invoke(mSandboxData->sandbox, gr_face_find_fref,
    956                                   t_face, aFeatureTag) != nullptr
    957                  : false;
    958  ReleaseGrFace(face);
    959 
    960  mSupportedFeatures->InsertOrUpdate(scriptFeature, result);
    961 
    962  return result;
    963 }
    964 
    965 void gfxFontEntry::GetFeatureInfo(nsTArray<gfxFontFeatureInfo>& aFeatureInfo) {
    966  // TODO: implement alternative code path for graphite fonts
    967 
    968  auto autoFace(GetHBFace());
    969  // Expose the raw hb_face_t to be captured by the lambdas (not the
    970  // AutoHBFace wrapper).
    971  hb_face_t* face = autoFace;
    972 
    973  // Get the list of features for a specific <script,langSys> pair and
    974  // append them to aFeatureInfo.
    975  auto collectForLang = [=, &aFeatureInfo](
    976                            hb_tag_t aTableTag, unsigned int aScript,
    977                            hb_tag_t aScriptTag, unsigned int aLang,
    978                            hb_tag_t aLangTag) {
    979    unsigned int featCount = hb_ot_layout_language_get_feature_tags(
    980        face, aTableTag, aScript, aLang, 0, nullptr, nullptr);
    981    AutoTArray<hb_tag_t, 32> featTags;
    982    featTags.SetLength(featCount);
    983    hb_ot_layout_language_get_feature_tags(face, aTableTag, aScript, aLang, 0,
    984                                           &featCount, featTags.Elements());
    985    MOZ_ASSERT(featCount <= featTags.Length());
    986    // Just in case HB didn't fill featTags (i.e. in case it returned fewer
    987    // tags than it promised), we truncate at the length it says it filled:
    988    featTags.SetLength(featCount);
    989    for (hb_tag_t t : featTags) {
    990      aFeatureInfo.AppendElement(gfxFontFeatureInfo{t, aScriptTag, aLangTag});
    991    }
    992  };
    993 
    994  // Iterate over the language systems supported by a given script,
    995  // and call collectForLang for each of them.
    996  auto collectForScript = [=](hb_tag_t aTableTag, unsigned int aScript,
    997                              hb_tag_t aScriptTag) {
    998    collectForLang(aTableTag, aScript, aScriptTag,
    999                   HB_OT_LAYOUT_DEFAULT_LANGUAGE_INDEX,
   1000                   HB_TAG('d', 'f', 'l', 't'));
   1001    unsigned int langCount = hb_ot_layout_script_get_language_tags(
   1002        face, aTableTag, aScript, 0, nullptr, nullptr);
   1003    AutoTArray<hb_tag_t, 32> langTags;
   1004    langTags.SetLength(langCount);
   1005    hb_ot_layout_script_get_language_tags(face, aTableTag, aScript, 0,
   1006                                          &langCount, langTags.Elements());
   1007    MOZ_ASSERT(langCount <= langTags.Length());
   1008    langTags.SetLength(langCount);
   1009    for (unsigned int lang = 0; lang < langCount; ++lang) {
   1010      collectForLang(aTableTag, aScript, aScriptTag, lang, langTags[lang]);
   1011    }
   1012  };
   1013 
   1014  // Iterate over the scripts supported by a table (GSUB or GPOS), and call
   1015  // collectForScript for each of them.
   1016  auto collectForTable = [=](hb_tag_t aTableTag) {
   1017    unsigned int scriptCount = hb_ot_layout_table_get_script_tags(
   1018        face, aTableTag, 0, nullptr, nullptr);
   1019    AutoTArray<hb_tag_t, 32> scriptTags;
   1020    scriptTags.SetLength(scriptCount);
   1021    hb_ot_layout_table_get_script_tags(face, aTableTag, 0, &scriptCount,
   1022                                       scriptTags.Elements());
   1023    MOZ_ASSERT(scriptCount <= scriptTags.Length());
   1024    scriptTags.SetLength(scriptCount);
   1025    for (unsigned int script = 0; script < scriptCount; ++script) {
   1026      collectForScript(aTableTag, script, scriptTags[script]);
   1027    }
   1028  };
   1029 
   1030  // Collect all OpenType Layout features, both substitution and positioning,
   1031  // supported by the font resource.
   1032  collectForTable(HB_TAG('G', 'S', 'U', 'B'));
   1033  collectForTable(HB_TAG('G', 'P', 'O', 'S'));
   1034 }
   1035 
   1036 typedef struct {
   1037  AutoSwap_PRUint32 version;
   1038  AutoSwap_PRUint16 format;
   1039  AutoSwap_PRUint16 horizOffset;
   1040  AutoSwap_PRUint16 vertOffset;
   1041  AutoSwap_PRUint16 reserved;
   1042  //  TrackData horizData;
   1043  //  TrackData vertData;
   1044 } TrakHeader;
   1045 
   1046 typedef struct {
   1047  AutoSwap_PRUint16 nTracks;
   1048  AutoSwap_PRUint16 nSizes;
   1049  AutoSwap_PRUint32 sizeTableOffset;
   1050  //  trackTableEntry trackTable[];
   1051  //  fixed32 sizeTable[];
   1052 } TrackData;
   1053 
   1054 typedef struct {
   1055  AutoSwap_PRUint32 track;
   1056  AutoSwap_PRUint16 nameIndex;
   1057  AutoSwap_PRUint16 offset;
   1058 } TrackTableEntry;
   1059 
   1060 bool gfxFontEntry::HasTrackingTable() {
   1061  if (!TrakTableInitialized()) {
   1062    hb_blob_t* trak = GetFontTable(TRUETYPE_TAG('t', 'r', 'a', 'k'));
   1063    if (trak) {
   1064      // mTrakTable itself is atomic, but we also want to set the auxiliary
   1065      // pointers mTrakValues and mTrakSizeTable, so we take a lock here to
   1066      // avoid racing with another thread also initializing the same values.
   1067      AutoWriteLock lock(mLock);
   1068      if (!mTrakTable.compareExchange(kTrakTableUninitialized, trak)) {
   1069        hb_blob_destroy(trak);
   1070      } else if (!ParseTrakTable()) {
   1071        hb_blob_destroy(mTrakTable.exchange(nullptr));
   1072      }
   1073    } else {
   1074      mTrakTable.exchange(nullptr);
   1075    }
   1076  }
   1077  return GetTrakTable() != nullptr;
   1078 }
   1079 
   1080 bool gfxFontEntry::ParseTrakTable() {
   1081  // Check table validity and set up the subtable pointers we need;
   1082  // if 'trak' table is invalid, or doesn't contain a 'normal' track,
   1083  // return false to tell the caller not to try using it.
   1084  unsigned int len;
   1085  const char* data = hb_blob_get_data(GetTrakTable(), &len);
   1086  if (len < sizeof(TrakHeader)) {
   1087    return false;
   1088  }
   1089  auto trak = reinterpret_cast<const TrakHeader*>(data);
   1090  uint16_t horizOffset = trak->horizOffset;
   1091  if (trak->version != 0x00010000 || uint16_t(trak->format) != 0 ||
   1092      horizOffset == 0 || uint16_t(trak->reserved) != 0) {
   1093    return false;
   1094  }
   1095  // Find the horizontal trackData, and check it doesn't overrun the buffer.
   1096  if (horizOffset > len - sizeof(TrackData)) {
   1097    return false;
   1098  }
   1099  auto trackData = reinterpret_cast<const TrackData*>(data + horizOffset);
   1100  uint16_t nTracks = trackData->nTracks;
   1101  mNumTrakSizes = trackData->nSizes;
   1102  if (nTracks == 0 || mNumTrakSizes < 2) {
   1103    return false;
   1104  }
   1105  uint32_t sizeTableOffset = trackData->sizeTableOffset;
   1106  // Find the trackTable, and check it doesn't overrun the buffer.
   1107  if (horizOffset >
   1108      len - (sizeof(TrackData) + nTracks * sizeof(TrackTableEntry))) {
   1109    return false;
   1110  }
   1111  auto trackTable = reinterpret_cast<const TrackTableEntry*>(
   1112      data + horizOffset + sizeof(TrackData));
   1113  // Look for 'normal' tracking, bail out if no such track is present.
   1114  unsigned trackIndex;
   1115  for (trackIndex = 0; trackIndex < nTracks; ++trackIndex) {
   1116    if (trackTable[trackIndex].track == 0x00000000) {
   1117      break;
   1118    }
   1119  }
   1120  if (trackIndex == nTracks) {
   1121    return false;
   1122  }
   1123  // Find list of tracking values, and check they won't overrun.
   1124  uint16_t offset = trackTable[trackIndex].offset;
   1125  if (offset > len - mNumTrakSizes * sizeof(uint16_t)) {
   1126    return false;
   1127  }
   1128  mTrakValues = reinterpret_cast<const AutoSwap_PRInt16*>(data + offset);
   1129  // Find the size subtable, and check it doesn't overrun the buffer.
   1130  mTrakSizeTable =
   1131      reinterpret_cast<const AutoSwap_PRInt32*>(data + sizeTableOffset);
   1132  if (mTrakSizeTable + mNumTrakSizes >
   1133      reinterpret_cast<const AutoSwap_PRInt32*>(data + len)) {
   1134    return false;
   1135  }
   1136  return true;
   1137 }
   1138 
   1139 gfxFloat gfxFontEntry::TrackingForCSSPx(gfxFloat aSize) const {
   1140  // No locking because this does read-only access of fields that are inert
   1141  // once initialized.
   1142  MOZ_ASSERT(TrakTableInitialized() && mTrakTable && mTrakValues &&
   1143             mTrakSizeTable);
   1144 
   1145  // Find index of first sizeTable entry that is >= the requested size.
   1146  int32_t fixedSize = int32_t(aSize * 65536.0);  // float -> 16.16 fixed-point
   1147  unsigned sizeIndex;
   1148  for (sizeIndex = 0; sizeIndex < mNumTrakSizes; ++sizeIndex) {
   1149    if (mTrakSizeTable[sizeIndex] >= fixedSize) {
   1150      break;
   1151    }
   1152  }
   1153  // Return the tracking value for the requested size, or an interpolated
   1154  // value if the exact size isn't found.
   1155  if (sizeIndex == mNumTrakSizes) {
   1156    // Request is larger than last entry in the table, so just use that.
   1157    // (We don't attempt to extrapolate more extreme tracking values than
   1158    // the largest or smallest present in the table.)
   1159    return int16_t(mTrakValues[mNumTrakSizes - 1]);
   1160  }
   1161  if (sizeIndex == 0 || mTrakSizeTable[sizeIndex] == fixedSize) {
   1162    // Found an exact match, or size was smaller than the first entry.
   1163    return int16_t(mTrakValues[sizeIndex]);
   1164  }
   1165  // Requested size falls between two entries: interpolate value.
   1166  double s0 = mTrakSizeTable[sizeIndex - 1] / 65536.0;  // 16.16 -> float
   1167  double s1 = mTrakSizeTable[sizeIndex] / 65536.0;
   1168  double t = (aSize - s0) / (s1 - s0);
   1169  return (1.0 - t) * int16_t(mTrakValues[sizeIndex - 1]) +
   1170         t * int16_t(mTrakValues[sizeIndex]);
   1171 }
   1172 
   1173 void gfxFontEntry::SetupVariationRanges() {
   1174  // No locking because this is done during initialization before any other
   1175  // thread has access to the entry.
   1176  if (!gfxPlatform::HasVariationFontSupport() ||
   1177      !StaticPrefs::layout_css_font_variations_enabled() || !HasVariations() ||
   1178      IsUserFont()) {
   1179    return;
   1180  }
   1181  AutoTArray<gfxFontVariationAxis, 4> axes;
   1182  GetVariationAxes(axes);
   1183  for (const auto& axis : axes) {
   1184    switch (axis.mTag) {
   1185      case HB_TAG('w', 'g', 'h', 't'):
   1186        // If the axis range looks like it doesn't fit the CSS font-weight
   1187        // scale, we don't hook up the high-level property, and we mark
   1188        // the face (in mRangeFlags) as having non-standard weight. This
   1189        // means we won't map CSS font-weight to the axis. Setting 'wght'
   1190        // with font-variation-settings will still work.
   1191        // Strictly speaking, the min value should be checked against 1.0,
   1192        // not 0.0, but we'll allow font makers that amount of leeway, as
   1193        // in practice a number of fonts seem to use 0..1000.
   1194        if (axis.mMinValue >= 0.0f && axis.mMaxValue <= 1000.0f &&
   1195            // If axis.mMaxValue is less than the default weight we already
   1196            // set up, assume the axis has a non-standard range (like Skia)
   1197            // and don't try to map it.
   1198            Weight().Min() <= FontWeight::FromFloat(axis.mMaxValue)) {
   1199          if (FontWeight::FromFloat(axis.mDefaultValue) != Weight().Min()) {
   1200            mStandardFace = false;
   1201          }
   1202          mWeightRange =
   1203              WeightRange(FontWeight::FromFloat(std::max(1.0f, axis.mMinValue)),
   1204                          FontWeight::FromFloat(axis.mMaxValue));
   1205        } else {
   1206          mRangeFlags |= RangeFlags::eNonCSSWeight;
   1207        }
   1208        break;
   1209 
   1210      case HB_TAG('w', 'd', 't', 'h'):
   1211        if (axis.mMinValue >= 0.0f && axis.mMaxValue <= 1000.0f &&
   1212            Stretch().Min() <= FontStretch::FromFloat(axis.mMaxValue)) {
   1213          if (FontStretch::FromFloat(axis.mDefaultValue) != Stretch().Min()) {
   1214            mStandardFace = false;
   1215          }
   1216          mStretchRange = StretchRange(FontStretch::FromFloat(axis.mMinValue),
   1217                                       FontStretch::FromFloat(axis.mMaxValue));
   1218        } else {
   1219          mRangeFlags |= RangeFlags::eNonCSSStretch;
   1220        }
   1221        break;
   1222 
   1223      case HB_TAG('s', 'l', 'n', 't'):
   1224        if (axis.mMinValue >= -90.0f && axis.mMaxValue <= 90.0f) {
   1225          if (FontSlantStyle::FromFloat(axis.mDefaultValue) !=
   1226              SlantStyle().Min()) {
   1227            mStandardFace = false;
   1228          }
   1229          // OpenType and CSS measure angles in opposite directions, so we
   1230          // have to flip signs and swap min/max when setting up the CSS
   1231          // font-style range here.
   1232          mStyleRange =
   1233              SlantStyleRange(FontSlantStyle::FromFloat(-axis.mMaxValue),
   1234                              FontSlantStyle::FromFloat(-axis.mMinValue));
   1235        }
   1236        break;
   1237 
   1238      case HB_TAG('i', 't', 'a', 'l'):
   1239        if (axis.mMinValue <= 0.0f && axis.mMaxValue >= 1.0f) {
   1240          if (axis.mDefaultValue != 0.0f) {
   1241            mStandardFace = false;
   1242          }
   1243          mStyleRange =
   1244              SlantStyleRange(FontSlantStyle::NORMAL, FontSlantStyle::ITALIC);
   1245        }
   1246        break;
   1247 
   1248      default:
   1249        continue;
   1250    }
   1251  }
   1252 }
   1253 
   1254 void gfxFontEntry::CheckForVariationAxes() {
   1255  if (mCheckedForVariationAxes) {
   1256    return;
   1257  }
   1258  mCheckedForVariationAxes = true;
   1259  if (HasVariations()) {
   1260    AutoTArray<gfxFontVariationAxis, 4> axes;
   1261    GetVariationAxes(axes);
   1262    for (const auto& axis : axes) {
   1263      if (axis.mTag == HB_TAG('w', 'g', 'h', 't') && axis.mMaxValue >= 600.0f) {
   1264        mRangeFlags |= RangeFlags::eBoldVariableWeight;
   1265      } else if (axis.mTag == HB_TAG('i', 't', 'a', 'l') &&
   1266                 axis.mMaxValue >= 1.0f) {
   1267        mRangeFlags |= RangeFlags::eItalicVariation;
   1268      } else if (axis.mTag == HB_TAG('s', 'l', 'n', 't')) {
   1269        mRangeFlags |= RangeFlags::eSlantVariation;
   1270      } else if (axis.mTag == HB_TAG('o', 'p', 's', 'z')) {
   1271        mRangeFlags |= RangeFlags::eOpticalSize;
   1272      }
   1273    }
   1274  }
   1275 }
   1276 
   1277 bool gfxFontEntry::HasBoldVariableWeight() {
   1278  MOZ_ASSERT(!mIsUserFontContainer,
   1279             "should not be called for user-font containers!");
   1280  CheckForVariationAxes();
   1281  return bool(mRangeFlags & RangeFlags::eBoldVariableWeight);
   1282 }
   1283 
   1284 bool gfxFontEntry::HasItalicVariation() {
   1285  MOZ_ASSERT(!mIsUserFontContainer,
   1286             "should not be called for user-font containers!");
   1287  CheckForVariationAxes();
   1288  return bool(mRangeFlags & RangeFlags::eItalicVariation);
   1289 }
   1290 
   1291 bool gfxFontEntry::HasSlantVariation() {
   1292  MOZ_ASSERT(!mIsUserFontContainer,
   1293             "should not be called for user-font containers!");
   1294  CheckForVariationAxes();
   1295  return bool(mRangeFlags & RangeFlags::eSlantVariation);
   1296 }
   1297 
   1298 bool gfxFontEntry::HasOpticalSize() {
   1299  MOZ_ASSERT(!mIsUserFontContainer,
   1300             "should not be called for user-font containers!");
   1301  CheckForVariationAxes();
   1302  return bool(mRangeFlags & RangeFlags::eOpticalSize);
   1303 }
   1304 
   1305 void gfxFontEntry::GetVariationsForStyle(nsTArray<gfxFontVariation>& aResult,
   1306                                         const gfxFontStyle& aStyle) {
   1307  if (!gfxPlatform::HasVariationFontSupport() ||
   1308      !StaticPrefs::layout_css_font_variations_enabled()) {
   1309    return;
   1310  }
   1311 
   1312  if (!HasVariations()) {
   1313    return;
   1314  }
   1315 
   1316  // Resolve high-level CSS properties from the requested style
   1317  // (font-{style,weight,stretch}) to the appropriate variations.
   1318  // The value used is clamped to the range available in the font face,
   1319  // unless the face is a user font where no explicit descriptor was
   1320  // given, indicated by the corresponding 'auto' range-flag.
   1321 
   1322  // We don't do these mappings if the font entry has weight and/or stretch
   1323  // ranges that do not appear to use the CSS property scale. Some older
   1324  // fonts created for QuickDrawGX/AAT may use "normalized" values where the
   1325  // standard variation is 1.0 rather than 400.0 (weight) or 100.0 (stretch).
   1326 
   1327  if (!(mRangeFlags & RangeFlags::eNonCSSWeight)) {
   1328    float weight = (IsUserFont() && (mRangeFlags & RangeFlags::eAutoWeight))
   1329                       ? aStyle.weight.ToFloat()
   1330                       : Weight().Clamp(aStyle.weight).ToFloat();
   1331    aResult.AppendElement(gfxFontVariation{HB_TAG('w', 'g', 'h', 't'), weight});
   1332  }
   1333 
   1334  if (!(mRangeFlags & RangeFlags::eNonCSSStretch)) {
   1335    float stretch = (IsUserFont() && (mRangeFlags & RangeFlags::eAutoStretch))
   1336                        ? aStyle.stretch.ToFloat()
   1337                        : Stretch().Clamp(aStyle.stretch).ToFloat();
   1338    aResult.AppendElement(
   1339        gfxFontVariation{HB_TAG('w', 'd', 't', 'h'), stretch});
   1340  }
   1341 
   1342  if (aStyle.style.IsItalic() && SupportsItalic()) {
   1343    // The 'ital' axis is normally a binary toggle; intermediate values
   1344    // can only be set using font-variation-settings.
   1345    aResult.AppendElement(gfxFontVariation{HB_TAG('i', 't', 'a', 'l'), 1.0f});
   1346  } else if (HasSlantVariation()) {
   1347    // Figure out what slant angle we should try to match from the
   1348    // requested style.
   1349    float angle = aStyle.style.SlantAngle();
   1350    // Clamp to the available range, unless the face is a user font
   1351    // with no explicit descriptor.
   1352    if (!(IsUserFont() && (mRangeFlags & RangeFlags::eAutoSlantStyle))) {
   1353      angle = SlantStyle().Clamp(FontSlantStyle::FromFloat(angle)).SlantAngle();
   1354    }
   1355    // OpenType and CSS measure angles in opposite directions, so we have to
   1356    // invert the sign of the CSS oblique value when setting OpenType 'slnt'.
   1357    aResult.AppendElement(gfxFontVariation{HB_TAG('s', 'l', 'n', 't'), -angle});
   1358  }
   1359 
   1360  struct TagEquals {
   1361    bool Equals(const gfxFontVariation& aIter, uint32_t aTag) const {
   1362      return aIter.mTag == aTag;
   1363    }
   1364  };
   1365 
   1366  auto replaceOrAppend = [&aResult](const gfxFontVariation& aSetting) {
   1367    auto index = aResult.IndexOf(aSetting.mTag, 0, TagEquals());
   1368    if (index == aResult.NoIndex) {
   1369      aResult.AppendElement(aSetting);
   1370    } else {
   1371      aResult[index].mValue = aSetting.mValue;
   1372    }
   1373  };
   1374 
   1375  // The low-level font-variation-settings descriptor from @font-face,
   1376  // if present, takes precedence over automatic variation settings
   1377  // from high-level properties.
   1378  for (const auto& v : mVariationSettings) {
   1379    replaceOrAppend(v);
   1380  }
   1381 
   1382  // And the low-level font-variation-settings property takes precedence
   1383  // over the descriptor.
   1384  for (const auto& v : aStyle.variationSettings) {
   1385    replaceOrAppend(v);
   1386  }
   1387 
   1388  // If there's no explicit opsz in the settings, apply 'auto' value.
   1389  if (HasOpticalSize() && aStyle.autoOpticalSize >= 0.0f) {
   1390    const uint32_t kOpszTag = HB_TAG('o', 'p', 's', 'z');
   1391    auto index = aResult.IndexOf(kOpszTag, 0, TagEquals());
   1392    if (index == aResult.NoIndex) {
   1393      float value = aStyle.autoOpticalSize * mSizeAdjust;
   1394      aResult.AppendElement(gfxFontVariation{kOpszTag, value});
   1395    }
   1396  }
   1397 }
   1398 
   1399 size_t gfxFontEntry::FontTableHashEntry::SizeOfExcludingThis(
   1400    mozilla::MallocSizeOf aMallocSizeOf) const {
   1401  size_t n = 0;
   1402  if (mBlob) {
   1403    n += aMallocSizeOf(mBlob);
   1404  }
   1405  if (mSharedBlobData) {
   1406    n += mSharedBlobData->SizeOfIncludingThis(aMallocSizeOf);
   1407  }
   1408  return n;
   1409 }
   1410 
   1411 void gfxFontEntry::AddSizeOfExcludingThis(MallocSizeOf aMallocSizeOf,
   1412                                          FontListSizes* aSizes) const {
   1413  aSizes->mFontListSize += mName.SizeOfExcludingThisIfUnshared(aMallocSizeOf);
   1414 
   1415  // cmaps are shared so only non-shared cmaps are included here
   1416  if (mCharacterMap && GetCharacterMap()->mBuildOnTheFly) {
   1417    aSizes->mCharMapsSize +=
   1418        GetCharacterMap()->SizeOfIncludingThis(aMallocSizeOf);
   1419  }
   1420  {
   1421    AutoReadLock lock(mLock);
   1422    if (mFontTableCache) {
   1423      aSizes->mFontTableCacheSize +=
   1424          mFontTableCache->SizeOfIncludingThis(aMallocSizeOf);
   1425    }
   1426  }
   1427 
   1428  // If the font has UVS data, we count that as part of the character map.
   1429  if (mUVSData) {
   1430    aSizes->mCharMapsSize += aMallocSizeOf(GetUVSData());
   1431  }
   1432 
   1433  // The following, if present, are essentially cached forms of font table
   1434  // data, so we'll accumulate them together with the basic table cache.
   1435  if (mUserFontData) {
   1436    aSizes->mFontTableCacheSize +=
   1437        mUserFontData->SizeOfIncludingThis(aMallocSizeOf);
   1438  }
   1439  if (mSVGGlyphs) {
   1440    aSizes->mFontTableCacheSize +=
   1441        GetSVGGlyphs()->SizeOfIncludingThis(aMallocSizeOf);
   1442  }
   1443 
   1444  {
   1445    MutexAutoLock lock(mFeatureInfoLock);
   1446    if (mSupportedFeatures) {
   1447      aSizes->mFontTableCacheSize +=
   1448          mSupportedFeatures->ShallowSizeOfIncludingThis(aMallocSizeOf);
   1449    }
   1450    if (mFeatureInputs) {
   1451      aSizes->mFontTableCacheSize +=
   1452          mFeatureInputs->ShallowSizeOfIncludingThis(aMallocSizeOf);
   1453      // XXX Can't this simply be
   1454      // aSizes->mFontTableCacheSize += 8192 * mFeatureInputs->Count();
   1455      for (auto iter = mFeatureInputs->ConstIter(); !iter.Done(); iter.Next()) {
   1456        // There's no API to get the real size of an hb_set, so we'll use
   1457        // an approximation based on knowledge of the implementation.
   1458        aSizes->mFontTableCacheSize += 8192;  // vector of 64K bits
   1459      }
   1460    }
   1461  }
   1462  // We don't include the size of mCOLR/mCPAL here, because (depending on the
   1463  // font backend implementation) they will either wrap blocks of data owned
   1464  // by the system (and potentially shared), or tables that are in our font
   1465  // table cache and therefore already counted.
   1466 }
   1467 
   1468 void gfxFontEntry::AddSizeOfIncludingThis(MallocSizeOf aMallocSizeOf,
   1469                                          FontListSizes* aSizes) const {
   1470  aSizes->mFontListSize += aMallocSizeOf(this);
   1471  AddSizeOfExcludingThis(aMallocSizeOf, aSizes);
   1472 }
   1473 
   1474 // This is used to report the size of an individual downloaded font in the
   1475 // user font cache. (Fonts that are part of the platform font list accumulate
   1476 // their sizes to the font list's reporter using the AddSizeOf... methods
   1477 // above.)
   1478 size_t gfxFontEntry::ComputedSizeOfExcludingThis(MallocSizeOf aMallocSizeOf) {
   1479  FontListSizes s = {0};
   1480  AddSizeOfExcludingThis(aMallocSizeOf, &s);
   1481 
   1482  // When reporting memory used for the main platform font list,
   1483  // where we're typically summing the totals for a few hundred font faces,
   1484  // we report the fields of FontListSizes separately.
   1485  // But for downloaded user fonts, the actual resource data (added by the
   1486  // subclass) will dominate, and the minor overhead of these pieces isn't
   1487  // worth splitting out for an individual font.
   1488  return s.mFontListSize + s.mFontTableCacheSize + s.mCharMapsSize;
   1489 }
   1490 
   1491 //////////////////////////////////////////////////////////////////////////////
   1492 //
   1493 // class gfxFontFamily
   1494 //
   1495 //////////////////////////////////////////////////////////////////////////////
   1496 
   1497 // We consider faces with mStandardFace == true to be "greater than" those with
   1498 // false, because during style matching, later entries are preferred.
   1499 class FontEntryStandardFaceComparator {
   1500 public:
   1501  bool Equals(const RefPtr<gfxFontEntry>& a,
   1502              const RefPtr<gfxFontEntry>& b) const {
   1503    return a->mStandardFace == b->mStandardFace;
   1504  }
   1505  bool LessThan(const RefPtr<gfxFontEntry>& a,
   1506                const RefPtr<gfxFontEntry>& b) const {
   1507    return (a->mStandardFace == false && b->mStandardFace == true);
   1508  }
   1509 };
   1510 
   1511 void gfxFontFamily::SortAvailableFonts() {
   1512  MOZ_ASSERT(mLock.LockedForWritingByCurrentThread());
   1513  mAvailableFonts.Sort(FontEntryStandardFaceComparator());
   1514 }
   1515 
   1516 bool gfxFontFamily::HasOtherFamilyNames() {
   1517  // need to read in other family names to determine this
   1518  if (!mOtherFamilyNamesInitialized) {
   1519    ReadOtherFamilyNames(
   1520        gfxPlatformFontList::PlatformFontList());  // sets mHasOtherFamilyNames
   1521  }
   1522  return mHasOtherFamilyNames;
   1523 }
   1524 
   1525 gfxFontEntry* gfxFontFamily::FindFontForStyle(const gfxFontStyle& aFontStyle,
   1526                                              bool aIgnoreSizeTolerance) {
   1527  AutoTArray<gfxFontEntry*, 4> matched;
   1528  FindAllFontsForStyle(aFontStyle, matched, aIgnoreSizeTolerance);
   1529  if (!matched.IsEmpty()) {
   1530    return matched[0];
   1531  }
   1532  return nullptr;
   1533 }
   1534 
   1535 static inline double WeightStyleStretchDistance(
   1536    gfxFontEntry* aFontEntry, const gfxFontStyle& aTargetStyle) {
   1537  double stretchDist =
   1538      StretchDistance(aFontEntry->Stretch(), aTargetStyle.stretch);
   1539  double styleDist = StyleDistance(
   1540      aFontEntry->SlantStyle(), aTargetStyle.style,
   1541      aTargetStyle.synthesisStyle != StyleFontSynthesisStyle::ObliqueOnly);
   1542  double weightDist = WeightDistance(aFontEntry->Weight(), aTargetStyle.weight);
   1543 
   1544  // Sanity-check that the distances are within the expected range
   1545  // (update if implementation of the distance functions is changed).
   1546  MOZ_ASSERT(stretchDist >= 0.0 && stretchDist <= 2000.0);
   1547  MOZ_ASSERT(styleDist >= 0.0 && styleDist <= 900.0);
   1548  MOZ_ASSERT(weightDist >= 0.0 && weightDist <= 1600.0);
   1549 
   1550  // weight/style/stretch priority: stretch >> style >> weight
   1551  // so we multiply the stretch and style values to make them dominate
   1552  // the result
   1553  return stretchDist * kStretchFactor + styleDist * kStyleFactor +
   1554         weightDist * kWeightFactor;
   1555 }
   1556 
   1557 void gfxFontFamily::FindAllFontsForStyle(
   1558    const gfxFontStyle& aFontStyle, nsTArray<gfxFontEntry*>& aFontEntryList,
   1559    bool aIgnoreSizeTolerance) {
   1560  if (!mHasStyles) {
   1561    FindStyleVariations();  // collect faces for the family, if not already
   1562                            // done
   1563  }
   1564 
   1565  AutoReadLock lock(mLock);
   1566 
   1567  NS_ASSERTION(mAvailableFonts.Length() > 0, "font family with no faces!");
   1568  NS_ASSERTION(aFontEntryList.IsEmpty(), "non-empty fontlist passed in");
   1569 
   1570  gfxFontEntry* fe = nullptr;
   1571 
   1572  // If the family has only one face, we simply return it; no further
   1573  // checking needed
   1574  uint32_t count = mAvailableFonts.Length();
   1575  if (count == 1) {
   1576    fe = mAvailableFonts[0];
   1577    aFontEntryList.AppendElement(fe);
   1578    return;
   1579  }
   1580 
   1581  // Most families are "simple", having just Regular/Bold/Italic/BoldItalic,
   1582  // or some subset of these. In this case, we have exactly 4 entries in
   1583  // mAvailableFonts, stored in the above order; note that some of the entries
   1584  // may be nullptr. We can then pick the required entry based on whether the
   1585  // request is for bold or non-bold, italic or non-italic, without running the
   1586  // more complex matching algorithm used for larger families with many weights
   1587  // and/or widths.
   1588 
   1589  if (mIsSimpleFamily) {
   1590    // Family has no more than the "standard" 4 faces, at fixed indexes;
   1591    // calculate which one we want.
   1592    // Note that we cannot simply return it as not all 4 faces are necessarily
   1593    // present.
   1594    bool wantBold = aFontStyle.weight >= FontWeight::FromInt(600);
   1595    bool wantItalic = !aFontStyle.style.IsNormal();
   1596    uint8_t faceIndex =
   1597        (wantItalic ? kItalicMask : 0) | (wantBold ? kBoldMask : 0);
   1598 
   1599    // if the desired style is available, return it directly
   1600    fe = mAvailableFonts[faceIndex];
   1601    if (fe) {
   1602      aFontEntryList.AppendElement(fe);
   1603      return;
   1604    }
   1605 
   1606    // order to check fallback faces in a simple family, depending on requested
   1607    // style
   1608    static const uint8_t simpleFallbacks[4][3] = {
   1609        {kBoldFaceIndex, kItalicFaceIndex,
   1610         kBoldItalicFaceIndex},  // fallbacks for Regular
   1611        {kRegularFaceIndex, kBoldItalicFaceIndex, kItalicFaceIndex},  // Bold
   1612        {kBoldItalicFaceIndex, kRegularFaceIndex, kBoldFaceIndex},    // Italic
   1613        {kItalicFaceIndex, kBoldFaceIndex, kRegularFaceIndex}  // BoldItalic
   1614    };
   1615    const uint8_t* order = simpleFallbacks[faceIndex];
   1616 
   1617    for (uint8_t trial = 0; trial < 3; ++trial) {
   1618      // check remaining faces in order of preference to find the first that
   1619      // actually exists
   1620      fe = mAvailableFonts[order[trial]];
   1621      if (fe) {
   1622        aFontEntryList.AppendElement(fe);
   1623        return;
   1624      }
   1625    }
   1626 
   1627    // this can't happen unless we have totally broken the font-list manager!
   1628    MOZ_ASSERT_UNREACHABLE("no face found in simple font family!");
   1629  }
   1630 
   1631  // Pick the font(s) that are closest to the desired weight, style, and
   1632  // stretch. Iterate over all fonts, measuring the weight/style distance.
   1633  // Because of unicode-range values, there may be more than one font for a
   1634  // given but the 99% use case is only a single font entry per
   1635  // weight/style/stretch distance value. To optimize this, only add entries
   1636  // to the matched font array when another entry already has the same
   1637  // weight/style/stretch distance and add the last matched font entry. For
   1638  // normal platform fonts with a single font entry for each
   1639  // weight/style/stretch combination, only the last matched font entry will
   1640  // be added.
   1641 
   1642  double minDistance = INFINITY;
   1643  gfxFontEntry* matched = nullptr;
   1644  // Iterate in reverse order so that faces like 'Bold' are matched before
   1645  // matching style-distance faces such as 'Bold Outline' (see bug 1185812;
   1646  // note that faces are sorted with "standard" faces later in the list.
   1647  for (uint32_t i = count; i > 0;) {
   1648    fe = mAvailableFonts[--i];
   1649    // weight/style/stretch priority: stretch >> style >> weight
   1650    double distance = WeightStyleStretchDistance(fe, aFontStyle);
   1651    if (distance < minDistance) {
   1652      matched = fe;
   1653      if (!aFontEntryList.IsEmpty()) {
   1654        aFontEntryList.Clear();
   1655      }
   1656      minDistance = distance;
   1657    } else if (distance == minDistance) {
   1658      if (matched && matched != fe) {
   1659        aFontEntryList.AppendElement(matched);
   1660      }
   1661      matched = fe;
   1662    }
   1663  }
   1664 
   1665  NS_ASSERTION(matched, "didn't match a font within a family");
   1666 
   1667  if (matched) {
   1668    aFontEntryList.AppendElement(matched);
   1669  }
   1670 }
   1671 
   1672 void gfxFontFamily::CheckForSimpleFamily() {
   1673  MOZ_ASSERT(mLock.LockedForWritingByCurrentThread());
   1674  // already checked this family
   1675  if (mIsSimpleFamily) {
   1676    return;
   1677  }
   1678 
   1679  uint32_t count = mAvailableFonts.Length();
   1680  if (count > 4 || count == 0) {
   1681    return;  // can't be "simple" if there are >4 faces;
   1682             // if none then the family is unusable anyway
   1683  }
   1684 
   1685  if (count == 1) {
   1686    mIsSimpleFamily = true;
   1687    return;
   1688  }
   1689 
   1690  StretchRange firstStretch = mAvailableFonts[0]->Stretch();
   1691  if (!firstStretch.IsSingle()) {
   1692    return;  // family with variation fonts is not considered "simple"
   1693  }
   1694 
   1695  gfxFontEntry* faces[4] = {0};
   1696  for (uint8_t i = 0; i < count; ++i) {
   1697    gfxFontEntry* fe = mAvailableFonts[i];
   1698    if (fe->Stretch() != firstStretch || fe->IsOblique()) {
   1699      // simple families don't have varying font-stretch or oblique
   1700      return;
   1701    }
   1702    if (!fe->Weight().IsSingle() || !fe->SlantStyle().IsSingle()) {
   1703      return;  // family with variation fonts is not considered "simple"
   1704    }
   1705    uint8_t faceIndex = (fe->IsItalic() ? kItalicMask : 0) |
   1706                        (fe->SupportsBold() ? kBoldMask : 0);
   1707    if (faces[faceIndex]) {
   1708      return;  // two faces resolve to the same slot; family isn't "simple"
   1709    }
   1710    faces[faceIndex] = fe;
   1711  }
   1712 
   1713  // we have successfully slotted the available faces into the standard
   1714  // 4-face framework
   1715  mAvailableFonts.SetLength(4);
   1716  for (uint8_t i = 0; i < 4; ++i) {
   1717    if (mAvailableFonts[i].get() != faces[i]) {
   1718      mAvailableFonts[i].swap(faces[i]);
   1719    }
   1720  }
   1721 
   1722  mIsSimpleFamily = true;
   1723 }
   1724 
   1725 #ifdef DEBUG
   1726 bool gfxFontFamily::ContainsFace(gfxFontEntry* aFontEntry) {
   1727  AutoReadLock lock(mLock);
   1728 
   1729  uint32_t i, numFonts = mAvailableFonts.Length();
   1730  for (i = 0; i < numFonts; i++) {
   1731    if (mAvailableFonts[i] == aFontEntry) {
   1732      return true;
   1733    }
   1734    // userfonts contain the actual real font entry
   1735    if (mAvailableFonts[i] && mAvailableFonts[i]->mIsUserFontContainer) {
   1736      gfxUserFontEntry* ufe =
   1737          static_cast<gfxUserFontEntry*>(mAvailableFonts[i].get());
   1738      if (ufe->GetPlatformFontEntry() == aFontEntry) {
   1739        return true;
   1740      }
   1741    }
   1742  }
   1743  return false;
   1744 }
   1745 #endif
   1746 
   1747 void gfxFontFamily::LocalizedName(nsACString& aLocalizedName) {
   1748  // just return the primary name; subclasses should override
   1749  aLocalizedName = mName;
   1750 }
   1751 
   1752 void gfxFontFamily::FindFontForChar(GlobalFontMatch* aMatchData) {
   1753  gfxPlatformFontList::PlatformFontList()->mLock.AssertCurrentThreadIn();
   1754 
   1755  {
   1756    AutoReadLock lock(mLock);
   1757    if (mFamilyCharacterMapInitialized && !TestCharacterMap(aMatchData->mCh)) {
   1758      // none of the faces in the family support the required char,
   1759      // so bail out immediately
   1760      return;
   1761    }
   1762  }
   1763 
   1764  nsCString charAndName;
   1765  if (profiler_thread_is_being_profiled(
   1766          Combine(ThreadProfilingFeatures::Sampling,
   1767                  ThreadProfilingFeatures::Markers))) {
   1768    charAndName = nsPrintfCString("\\u%x %s", aMatchData->mCh, mName.get());
   1769  }
   1770  AUTO_PROFILER_LABEL_DYNAMIC_NSCSTRING("gfxFontFamily::FindFontForChar",
   1771                                        LAYOUT, charAndName);
   1772 
   1773  AutoTArray<gfxFontEntry*, 4> entries;
   1774  FindAllFontsForStyle(aMatchData->mStyle, entries,
   1775                       /*aIgnoreSizeTolerance*/ true);
   1776  if (entries.IsEmpty()) {
   1777    return;
   1778  }
   1779 
   1780  gfxFontEntry* fe = nullptr;
   1781  float distance = INFINITY;
   1782 
   1783  for (auto e : entries) {
   1784    if (e->SkipDuringSystemFallback()) {
   1785      continue;
   1786    }
   1787 
   1788    aMatchData->mCmapsTested++;
   1789    if (e->HasCharacter(aMatchData->mCh)) {
   1790      aMatchData->mCount++;
   1791 
   1792      LogModule* log = gfxPlatform::GetLog(eGfxLog_textrun);
   1793 
   1794      if (MOZ_UNLIKELY(MOZ_LOG_TEST(log, LogLevel::Debug))) {
   1795        intl::Script script =
   1796            intl::UnicodeProperties::GetScriptCode(aMatchData->mCh);
   1797        MOZ_LOG(log, LogLevel::Debug,
   1798                ("(textrun-systemfallback-fonts) char: u+%6.6x "
   1799                 "script: %d match: [%s]\n",
   1800                 aMatchData->mCh, int(script), e->Name().get()));
   1801      }
   1802 
   1803      fe = e;
   1804      distance = WeightStyleStretchDistance(fe, aMatchData->mStyle);
   1805      if (aMatchData->mPresentation != FontPresentation::Any) {
   1806        RefPtr<gfxFont> font = fe->FindOrMakeFont(&aMatchData->mStyle);
   1807        if (!font) {
   1808          continue;
   1809        }
   1810        bool hasColorGlyph =
   1811            font->HasColorGlyphFor(aMatchData->mCh, aMatchData->mNextCh);
   1812        if (hasColorGlyph != PrefersColor(aMatchData->mPresentation)) {
   1813          distance += kPresentationMismatch;
   1814        }
   1815      }
   1816      break;
   1817    }
   1818  }
   1819 
   1820  if (!fe && !aMatchData->mStyle.IsNormalStyle()) {
   1821    // If style/weight/stretch was not Normal, see if we can
   1822    // fall back to a next-best face (e.g. Arial Black -> Bold,
   1823    // or Arial Narrow -> Regular).
   1824    GlobalFontMatch data(aMatchData->mCh, aMatchData->mNextCh,
   1825                         aMatchData->mStyle, aMatchData->mPresentation);
   1826    SearchAllFontsForChar(&data);
   1827    if (!data.mBestMatch) {
   1828      return;
   1829    }
   1830    fe = data.mBestMatch;
   1831    distance = data.mMatchDistance;
   1832  }
   1833 
   1834  if (!fe) {
   1835    return;
   1836  }
   1837 
   1838  if (distance < aMatchData->mMatchDistance ||
   1839      (distance == aMatchData->mMatchDistance &&
   1840       Compare(fe->Name(), aMatchData->mBestMatch->Name()) > 0)) {
   1841    aMatchData->mBestMatch = fe;
   1842    aMatchData->mMatchedFamily = this;
   1843    aMatchData->mMatchDistance = distance;
   1844  }
   1845 }
   1846 
   1847 void gfxFontFamily::SearchAllFontsForChar(GlobalFontMatch* aMatchData) {
   1848  if (!mFamilyCharacterMapInitialized) {
   1849    ReadAllCMAPs();
   1850  }
   1851  AutoReadLock lock(mLock);
   1852  if (!mFamilyCharacterMap.test(aMatchData->mCh)) {
   1853    return;
   1854  }
   1855  uint32_t numFonts = mAvailableFonts.Length();
   1856  for (uint32_t i = numFonts; i > 0;) {
   1857    gfxFontEntry* fe = mAvailableFonts[--i];
   1858    if (fe && fe->HasCharacter(aMatchData->mCh)) {
   1859      float distance = WeightStyleStretchDistance(fe, aMatchData->mStyle);
   1860      if (aMatchData->mPresentation != FontPresentation::Any) {
   1861        RefPtr<gfxFont> font = fe->FindOrMakeFont(&aMatchData->mStyle);
   1862        if (!font) {
   1863          continue;
   1864        }
   1865        bool hasColorGlyph =
   1866            font->HasColorGlyphFor(aMatchData->mCh, aMatchData->mNextCh);
   1867        if (hasColorGlyph != PrefersColor(aMatchData->mPresentation)) {
   1868          distance += kPresentationMismatch;
   1869        }
   1870      }
   1871      if (distance < aMatchData->mMatchDistance ||
   1872          (distance == aMatchData->mMatchDistance &&
   1873           Compare(fe->Name(), aMatchData->mBestMatch->Name()) > 0)) {
   1874        aMatchData->mBestMatch = fe;
   1875        aMatchData->mMatchedFamily = this;
   1876        aMatchData->mMatchDistance = distance;
   1877      }
   1878    }
   1879  }
   1880 }
   1881 
   1882 /*virtual*/
   1883 gfxFontFamily::~gfxFontFamily() {
   1884  // Should not be dropped by stylo, but the InitFontList thread might use
   1885  // a transient gfxFontFamily and that's OK.
   1886  MOZ_ASSERT(!gfxFontUtils::IsInServoTraversal());
   1887 }
   1888 
   1889 // returns true if other names were found, false otherwise
   1890 bool gfxFontFamily::ReadOtherFamilyNamesForFace(
   1891    gfxPlatformFontList* aPlatformFontList, hb_blob_t* aNameTable,
   1892    bool useFullName) {
   1893  uint32_t dataLength;
   1894  const char* nameData = hb_blob_get_data(aNameTable, &dataLength);
   1895  AutoTArray<nsCString, 4> otherFamilyNames;
   1896 
   1897  gfxFontUtils::ReadOtherFamilyNamesForFace(mName, nameData, dataLength,
   1898                                            otherFamilyNames, useFullName);
   1899 
   1900  if (!otherFamilyNames.IsEmpty()) {
   1901    aPlatformFontList->AddOtherFamilyNames(this, otherFamilyNames);
   1902  }
   1903 
   1904  return !otherFamilyNames.IsEmpty();
   1905 }
   1906 
   1907 void gfxFontFamily::ReadOtherFamilyNames(
   1908    gfxPlatformFontList* aPlatformFontList) {
   1909  AutoWriteLock lock(mLock);
   1910  if (mOtherFamilyNamesInitialized) {
   1911    return;
   1912  }
   1913 
   1914  mOtherFamilyNamesInitialized = true;
   1915 
   1916  FindStyleVariationsLocked();
   1917 
   1918  // read in other family names for the first face in the list
   1919  uint32_t i, numFonts = mAvailableFonts.Length();
   1920  const uint32_t kNAME = TRUETYPE_TAG('n', 'a', 'm', 'e');
   1921 
   1922  for (i = 0; i < numFonts; ++i) {
   1923    gfxFontEntry* fe = mAvailableFonts[i];
   1924    if (!fe) {
   1925      continue;
   1926    }
   1927    gfxFontEntry::AutoTable nameTable(fe, kNAME);
   1928    if (!nameTable) {
   1929      continue;
   1930    }
   1931    mHasOtherFamilyNames =
   1932        ReadOtherFamilyNamesForFace(aPlatformFontList, nameTable);
   1933    break;
   1934  }
   1935 
   1936  // read in other names for the first face in the list with the assumption
   1937  // that if extra names don't exist in that face then they don't exist in
   1938  // other faces for the same font
   1939  if (!mHasOtherFamilyNames) {
   1940    return;
   1941  }
   1942 
   1943  // read in names for all faces, needed to catch cases where fonts have
   1944  // family names for individual weights (e.g. Hiragino Kaku Gothic Pro W6)
   1945  for (; i < numFonts; i++) {
   1946    gfxFontEntry* fe = mAvailableFonts[i];
   1947    if (!fe) {
   1948      continue;
   1949    }
   1950    gfxFontEntry::AutoTable nameTable(fe, kNAME);
   1951    if (!nameTable) {
   1952      continue;
   1953    }
   1954    ReadOtherFamilyNamesForFace(aPlatformFontList, nameTable);
   1955  }
   1956 }
   1957 
   1958 static bool LookForLegacyFamilyName(const nsACString& aCanonicalName,
   1959                                    const char* aNameData, uint32_t aDataLength,
   1960                                    nsACString& aLegacyName /* outparam */) {
   1961  const gfxFontUtils::NameHeader* nameHeader =
   1962      reinterpret_cast<const gfxFontUtils::NameHeader*>(aNameData);
   1963 
   1964  uint32_t nameCount = nameHeader->count;
   1965  if (nameCount * sizeof(gfxFontUtils::NameRecord) > aDataLength) {
   1966    NS_WARNING("invalid font (name records)");
   1967    return false;
   1968  }
   1969 
   1970  const gfxFontUtils::NameRecord* nameRecord =
   1971      reinterpret_cast<const gfxFontUtils::NameRecord*>(
   1972          aNameData + sizeof(gfxFontUtils::NameHeader));
   1973  uint32_t stringsBase = uint32_t(nameHeader->stringOffset);
   1974 
   1975  for (uint32_t i = 0; i < nameCount; i++, nameRecord++) {
   1976    uint32_t nameLen = nameRecord->length;
   1977    uint32_t nameOff = nameRecord->offset;
   1978 
   1979    if (stringsBase + nameOff + nameLen > aDataLength) {
   1980      NS_WARNING("invalid font (name table strings)");
   1981      return false;
   1982    }
   1983 
   1984    if (uint16_t(nameRecord->nameID) == gfxFontUtils::NAME_ID_FAMILY) {
   1985      bool ok = gfxFontUtils::DecodeFontName(
   1986          aNameData + stringsBase + nameOff, nameLen,
   1987          uint32_t(nameRecord->platformID), uint32_t(nameRecord->encodingID),
   1988          uint32_t(nameRecord->languageID), aLegacyName);
   1989      // It's only a legacy name if it case-insensitively differs from the
   1990      // canonical name (otherwise it would map to the same key).
   1991      if (ok && !aLegacyName.Equals(aCanonicalName,
   1992                                    nsCaseInsensitiveCStringComparator)) {
   1993        return true;
   1994      }
   1995    }
   1996  }
   1997  return false;
   1998 }
   1999 
   2000 bool gfxFontFamily::CheckForLegacyFamilyNames(gfxPlatformFontList* aFontList) {
   2001  aFontList->mLock.AssertCurrentThreadIn();
   2002  if (mCheckedForLegacyFamilyNames) {
   2003    // we already did this, so there's nothing more to add
   2004    return false;
   2005  }
   2006  mCheckedForLegacyFamilyNames = true;
   2007  bool added = false;
   2008  const uint32_t kNAME = TRUETYPE_TAG('n', 'a', 'm', 'e');
   2009  AutoTArray<RefPtr<gfxFontEntry>, 16> faces;
   2010  {
   2011    // Take a local copy of the array of font entries, because it's possible
   2012    // AddWithLegacyFamilyName will mutate it (and it needs to be able to take
   2013    // an exclusive lock on the family to do so, so we release the read lock
   2014    // here).
   2015    AutoReadLock lock(mLock);
   2016    faces.AppendElements(mAvailableFonts);
   2017  }
   2018  for (const auto& fe : faces) {
   2019    if (!fe) {
   2020      continue;
   2021    }
   2022    gfxFontEntry::AutoTable nameTable(fe, kNAME);
   2023    if (!nameTable) {
   2024      continue;
   2025    }
   2026    nsAutoCString legacyName;
   2027    uint32_t dataLength;
   2028    const char* nameData = hb_blob_get_data(nameTable, &dataLength);
   2029    if (LookForLegacyFamilyName(Name(), nameData, dataLength, legacyName)) {
   2030      if (aFontList->AddWithLegacyFamilyName(legacyName, fe, mVisibility)) {
   2031        added = true;
   2032      }
   2033    }
   2034  }
   2035  return added;
   2036 }
   2037 
   2038 void gfxFontFamily::ReadFaceNames(gfxPlatformFontList* aPlatformFontList,
   2039                                  bool aNeedFullnamePostscriptNames,
   2040                                  FontInfoData* aFontInfoData) {
   2041  aPlatformFontList->mLock.AssertCurrentThreadIn();
   2042 
   2043  // if all needed names have already been read, skip
   2044  if (mOtherFamilyNamesInitialized &&
   2045      (mFaceNamesInitialized || !aNeedFullnamePostscriptNames)) {
   2046    return;
   2047  }
   2048 
   2049  AutoWriteLock lock(mLock);
   2050 
   2051  bool asyncFontLoaderDisabled = false;
   2052 
   2053  if (!mOtherFamilyNamesInitialized && aFontInfoData &&
   2054      aFontInfoData->mLoadOtherNames && !asyncFontLoaderDisabled) {
   2055    const auto* otherFamilyNames = aFontInfoData->GetOtherFamilyNames(mName);
   2056    if (otherFamilyNames && otherFamilyNames->Length()) {
   2057      aPlatformFontList->AddOtherFamilyNames(this, *otherFamilyNames);
   2058    }
   2059    mOtherFamilyNamesInitialized = true;
   2060  }
   2061 
   2062  // if all needed data has been initialized, return
   2063  if (mOtherFamilyNamesInitialized &&
   2064      (mFaceNamesInitialized || !aNeedFullnamePostscriptNames)) {
   2065    return;
   2066  }
   2067 
   2068  FindStyleVariationsLocked(aFontInfoData);
   2069 
   2070  // check again, as style enumeration code may have loaded names
   2071  if (mOtherFamilyNamesInitialized &&
   2072      (mFaceNamesInitialized || !aNeedFullnamePostscriptNames)) {
   2073    return;
   2074  }
   2075 
   2076  uint32_t i, numFonts = mAvailableFonts.Length();
   2077  const uint32_t kNAME = TRUETYPE_TAG('n', 'a', 'm', 'e');
   2078 
   2079  bool firstTime = true, readAllFaces = false;
   2080  for (i = 0; i < numFonts; ++i) {
   2081    gfxFontEntry* fe = mAvailableFonts[i];
   2082    if (!fe) {
   2083      continue;
   2084    }
   2085 
   2086    nsAutoCString fullname, psname;
   2087    bool foundFaceNames = false;
   2088    if (!mFaceNamesInitialized && aNeedFullnamePostscriptNames &&
   2089        aFontInfoData && aFontInfoData->mLoadFaceNames) {
   2090      aFontInfoData->GetFaceNames(fe->Name(), fullname, psname);
   2091      if (!fullname.IsEmpty()) {
   2092        aPlatformFontList->AddFullnameLocked(fe, fullname);
   2093      }
   2094      if (!psname.IsEmpty()) {
   2095        aPlatformFontList->AddPostscriptNameLocked(fe, psname);
   2096      }
   2097      foundFaceNames = true;
   2098 
   2099      // found everything needed? skip to next font
   2100      if (mOtherFamilyNamesInitialized) {
   2101        continue;
   2102      }
   2103    }
   2104 
   2105    // load directly from the name table
   2106    gfxFontEntry::AutoTable nameTable(fe, kNAME);
   2107    if (!nameTable) {
   2108      continue;
   2109    }
   2110 
   2111    if (aNeedFullnamePostscriptNames && !foundFaceNames) {
   2112      if (gfxFontUtils::ReadCanonicalName(nameTable, gfxFontUtils::NAME_ID_FULL,
   2113                                          fullname) == NS_OK) {
   2114        aPlatformFontList->AddFullnameLocked(fe, fullname);
   2115      }
   2116 
   2117      if (gfxFontUtils::ReadCanonicalName(
   2118              nameTable, gfxFontUtils::NAME_ID_POSTSCRIPT, psname) == NS_OK) {
   2119        aPlatformFontList->AddPostscriptNameLocked(fe, psname);
   2120      }
   2121    }
   2122 
   2123    if (!mOtherFamilyNamesInitialized && (firstTime || readAllFaces)) {
   2124      bool foundOtherName =
   2125          ReadOtherFamilyNamesForFace(aPlatformFontList, nameTable);
   2126 
   2127      // if the first face has a different name, scan all faces, otherwise
   2128      // assume the family doesn't have other names
   2129      if (firstTime && foundOtherName) {
   2130        mHasOtherFamilyNames = true;
   2131        readAllFaces = true;
   2132      }
   2133      firstTime = false;
   2134    }
   2135 
   2136    // if not reading in any more names, skip other faces
   2137    if (!readAllFaces && !aNeedFullnamePostscriptNames) {
   2138      break;
   2139    }
   2140  }
   2141 
   2142  mFaceNamesInitialized = true;
   2143  mOtherFamilyNamesInitialized = true;
   2144 }
   2145 
   2146 gfxFontEntry* gfxFontFamily::FindFont(const nsACString& aFontName,
   2147                                      const nsCStringComparator& aCmp) const {
   2148  // find the font using a simple linear search
   2149  AutoReadLock lock(mLock);
   2150  uint32_t numFonts = mAvailableFonts.Length();
   2151  for (uint32_t i = numFonts; i > 0;) {
   2152    gfxFontEntry* fe = mAvailableFonts[--i].get();
   2153    if (fe && fe->Name().Equals(aFontName, aCmp)) {
   2154      return fe;
   2155    }
   2156  }
   2157  return nullptr;
   2158 }
   2159 
   2160 void gfxFontFamily::ReadAllCMAPs(FontInfoData* aFontInfoData) {
   2161  AutoTArray<RefPtr<gfxFontEntry>, 16> faces;
   2162  {
   2163    AutoWriteLock lock(mLock);
   2164    FindStyleVariationsLocked(aFontInfoData);
   2165    faces.AppendElements(mAvailableFonts);
   2166  }
   2167 
   2168  gfxSparseBitSet familyMap;
   2169  for (auto& face : faces) {
   2170    // don't try to load cmaps for downloadable fonts not yet loaded
   2171    if (!face || face->mIsUserFontContainer) {
   2172      continue;
   2173    }
   2174    face->ReadCMAP(aFontInfoData);
   2175    familyMap.Union(*(face->GetCharacterMap()));
   2176  }
   2177 
   2178  AutoWriteLock lock(mLock);
   2179  if (!mFamilyCharacterMapInitialized) {
   2180    familyMap.Compact();
   2181    mFamilyCharacterMap = std::move(familyMap);
   2182    mFamilyCharacterMapInitialized = true;
   2183  }
   2184 }
   2185 
   2186 void gfxFontFamily::AddSizeOfExcludingThis(MallocSizeOf aMallocSizeOf,
   2187                                           FontListSizes* aSizes) const {
   2188  AutoReadLock lock(mLock);
   2189  aSizes->mFontListSize += mName.SizeOfExcludingThisIfUnshared(aMallocSizeOf);
   2190  aSizes->mCharMapsSize +=
   2191      mFamilyCharacterMap.SizeOfExcludingThis(aMallocSizeOf);
   2192 
   2193  aSizes->mFontListSize +=
   2194      mAvailableFonts.ShallowSizeOfExcludingThis(aMallocSizeOf);
   2195  for (uint32_t i = 0; i < mAvailableFonts.Length(); ++i) {
   2196    gfxFontEntry* fe = mAvailableFonts[i];
   2197    if (fe) {
   2198      fe->AddSizeOfIncludingThis(aMallocSizeOf, aSizes);
   2199    }
   2200  }
   2201 }
   2202 
   2203 void gfxFontFamily::AddSizeOfIncludingThis(MallocSizeOf aMallocSizeOf,
   2204                                           FontListSizes* aSizes) const {
   2205  aSizes->mFontListSize += aMallocSizeOf(this);
   2206  AddSizeOfExcludingThis(aMallocSizeOf, aSizes);
   2207 }