tor-browser

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

CoreTextFontList.cpp (67611B)


      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 "AppleUtils.h"
      7 #include "CoreTextFontList.h"
      8 #include "gfxFontConstants.h"
      9 #include "gfxMacFont.h"
     10 #include "gfxUserFontSet.h"
     11 
     12 #include "harfbuzz/hb.h"
     13 
     14 #include "MainThreadUtils.h"
     15 
     16 #include "mozilla/dom/ContentChild.h"
     17 #include "mozilla/dom/ContentParent.h"
     18 #include "mozilla/gfx/2D.h"
     19 #include "mozilla/Logging.h"
     20 #include "mozilla/Preferences.h"
     21 #include "mozilla/ProfilerLabels.h"
     22 #include "mozilla/Sprintf.h"
     23 #include "mozilla/StaticPrefs_gfx.h"
     24 #include "mozilla/glean/GfxMetrics.h"
     25 
     26 #include "nsAppDirectoryServiceDefs.h"
     27 #include "nsCharTraits.h"
     28 #include "nsComponentManagerUtils.h"
     29 #include "nsDirectoryServiceDefs.h"
     30 #include "nsDirectoryServiceUtils.h"
     31 #include "nsIDirectoryEnumerator.h"
     32 #include "nsServiceManagerUtils.h"
     33 #include "SharedFontList-impl.h"
     34 
     35 using namespace mozilla;
     36 using namespace mozilla::gfx;
     37 
     38 #ifdef MOZ_WIDGET_COCOA
     39 // Building with newer macOS SDKs can cause a bunch of font-family names to be
     40 // hidden from the Core Text API we use to enumerate available fonts. Because
     41 // some content still benefits from having these names recognized, we forcibly
     42 // include them in the list. Some day we might want to drop support for these.
     43 #  define USE_DEPRECATED_FONT_FAMILY_NAMES 1
     44 #endif
     45 
     46 #if USE_DEPRECATED_FONT_FAMILY_NAMES
     47 // List generated by diffing the arrays returned by
     48 // CTFontManagerCopyAvailableFontFamilyNames() when built with
     49 // MACOSX_DEPLOYMENT_TARGET=10.12 vs 11.0, to identify the font family names
     50 // that Core Text is treating as "deprecated" and hiding from the app on newer
     51 // systems.
     52 constexpr nsLiteralCString kDeprecatedFontFamilies[] = {
     53    // Dot-prefixed font families are supposed to be hidden from the
     54    // user-visible
     55    // font list anyhow, so we don't need to add them here.
     56    //  ".Al Bayan PUA"_ns,
     57    //  ".Al Nile PUA"_ns,
     58    //  ".Al Tarikh PUA"_ns,
     59    //  ".Apple Color Emoji UI"_ns,
     60    //  ".Apple SD Gothic NeoI"_ns,
     61    //  ".Aqua Kana"_ns,
     62    //  ".Arial Hebrew Desk Interface"_ns,
     63    //  ".Baghdad PUA"_ns,
     64    //  ".Beirut PUA"_ns,
     65    //  ".Damascus PUA"_ns,
     66    //  ".DecoType Naskh PUA"_ns,
     67    //  ".Diwan Kufi PUA"_ns,
     68    //  ".Farah PUA"_ns,
     69    //  ".Geeza Pro Interface"_ns,
     70    //  ".Geeza Pro PUA"_ns,
     71    //  ".Helvetica LT MM"_ns,
     72    //  ".Hiragino Kaku Gothic Interface"_ns,
     73    //  ".Hiragino Sans GB Interface"_ns,
     74    //  ".Keyboard"_ns,
     75    //  ".KufiStandardGK PUA"_ns,
     76    //  ".LastResort"_ns,
     77    //  ".Lucida Grande UI"_ns,
     78    //  ".Muna PUA"_ns,
     79    //  ".Nadeem PUA"_ns,
     80    //  ".New York"_ns,
     81    //  ".Noto Nastaliq Urdu UI"_ns,
     82    //  ".PingFang HK"_ns,
     83    //  ".PingFang SC"_ns,
     84    //  ".PingFang TC"_ns,
     85    //  ".Sana PUA"_ns,
     86    //  ".Savoye LET CC."_ns,
     87    //  ".SF Arabic"_ns,
     88    //  ".SF Compact Rounded"_ns,
     89    //  ".SF Compact"_ns,
     90    //  ".SF NS Mono"_ns,
     91    //  ".SF NS Rounded"_ns,
     92    //  ".SF NS"_ns,
     93    //  ".Times LT MM"_ns,
     94    "Hiragino Kaku Gothic Pro"_ns,
     95    "Hiragino Kaku Gothic ProN"_ns,
     96    "Hiragino Kaku Gothic Std"_ns,
     97    "Hiragino Kaku Gothic StdN"_ns,
     98    "Hiragino Maru Gothic Pro"_ns,
     99    "Hiragino Mincho Pro"_ns,
    100    "Iowan Old Style"_ns,
    101    "Noto Sans Adlam"_ns,
    102    "Noto Sans Armenian"_ns,
    103    "Noto Sans Avestan"_ns,
    104    "Noto Sans Bamum"_ns,
    105    "Noto Sans Bassa Vah"_ns,
    106    "Noto Sans Batak"_ns,
    107    "Noto Sans Bhaiksuki"_ns,
    108    "Noto Sans Brahmi"_ns,
    109    "Noto Sans Buginese"_ns,
    110    "Noto Sans Buhid"_ns,
    111    "Noto Sans Carian"_ns,
    112    "Noto Sans Caucasian Albanian"_ns,
    113    "Noto Sans Chakma"_ns,
    114    "Noto Sans Cham"_ns,
    115    "Noto Sans Coptic"_ns,
    116    "Noto Sans Cuneiform"_ns,
    117    "Noto Sans Cypriot"_ns,
    118    "Noto Sans Duployan"_ns,
    119    "Noto Sans Egyptian Hieroglyphs"_ns,
    120    "Noto Sans Elbasan"_ns,
    121    "Noto Sans Glagolitic"_ns,
    122    "Noto Sans Gothic"_ns,
    123    "Noto Sans Gunjala Gondi"_ns,
    124    "Noto Sans Hanifi Rohingya"_ns,
    125    "Noto Sans Hanunoo"_ns,
    126    "Noto Sans Hatran"_ns,
    127    "Noto Sans Imperial Aramaic"_ns,
    128    "Noto Sans Inscriptional Pahlavi"_ns,
    129    "Noto Sans Inscriptional Parthian"_ns,
    130    "Noto Sans Javanese"_ns,
    131    "Noto Sans Kaithi"_ns,
    132    "Noto Sans Kayah Li"_ns,
    133    "Noto Sans Kharoshthi"_ns,
    134    "Noto Sans Khojki"_ns,
    135    "Noto Sans Khudawadi"_ns,
    136    "Noto Sans Lepcha"_ns,
    137    "Noto Sans Limbu"_ns,
    138    "Noto Sans Linear A"_ns,
    139    "Noto Sans Linear B"_ns,
    140    "Noto Sans Lisu"_ns,
    141    "Noto Sans Lycian"_ns,
    142    "Noto Sans Lydian"_ns,
    143    "Noto Sans Mahajani"_ns,
    144    "Noto Sans Mandaic"_ns,
    145    "Noto Sans Manichaean"_ns,
    146    "Noto Sans Marchen"_ns,
    147    "Noto Sans Masaram Gondi"_ns,
    148    "Noto Sans Meetei Mayek"_ns,
    149    "Noto Sans Mende Kikakui"_ns,
    150    "Noto Sans Meroitic"_ns,
    151    "Noto Sans Miao"_ns,
    152    "Noto Sans Modi"_ns,
    153    "Noto Sans Mongolian"_ns,
    154    "Noto Sans Mro"_ns,
    155    "Noto Sans Multani"_ns,
    156    "Noto Sans Nabataean"_ns,
    157    "Noto Sans New Tai Lue"_ns,
    158    "Noto Sans Newa"_ns,
    159    "Noto Sans NKo"_ns,
    160    "Noto Sans Ol Chiki"_ns,
    161    "Noto Sans Old Hungarian"_ns,
    162    "Noto Sans Old Italic"_ns,
    163    "Noto Sans Old North Arabian"_ns,
    164    "Noto Sans Old Permic"_ns,
    165    "Noto Sans Old Persian"_ns,
    166    "Noto Sans Old South Arabian"_ns,
    167    "Noto Sans Old Turkic"_ns,
    168    "Noto Sans Osage"_ns,
    169    "Noto Sans Osmanya"_ns,
    170    "Noto Sans Pahawh Hmong"_ns,
    171    "Noto Sans Palmyrene"_ns,
    172    "Noto Sans Pau Cin Hau"_ns,
    173    "Noto Sans PhagsPa"_ns,
    174    "Noto Sans Phoenician"_ns,
    175    "Noto Sans Psalter Pahlavi"_ns,
    176    "Noto Sans Rejang"_ns,
    177    "Noto Sans Samaritan"_ns,
    178    "Noto Sans Saurashtra"_ns,
    179    "Noto Sans Sharada"_ns,
    180    "Noto Sans Siddham"_ns,
    181    "Noto Sans Sora Sompeng"_ns,
    182    "Noto Sans Sundanese"_ns,
    183    "Noto Sans Syloti Nagri"_ns,
    184    "Noto Sans Syriac"_ns,
    185    "Noto Sans Tagalog"_ns,
    186    "Noto Sans Tagbanwa"_ns,
    187    "Noto Sans Tai Le"_ns,
    188    "Noto Sans Tai Tham"_ns,
    189    "Noto Sans Tai Viet"_ns,
    190    "Noto Sans Takri"_ns,
    191    "Noto Sans Thaana"_ns,
    192    "Noto Sans Tifinagh"_ns,
    193    "Noto Sans Tirhuta"_ns,
    194    "Noto Sans Ugaritic"_ns,
    195    "Noto Sans Vai"_ns,
    196    "Noto Sans Wancho"_ns,
    197    "Noto Sans Warang Citi"_ns,
    198    "Noto Sans Yi"_ns,
    199    "Noto Sans Zawgyi"_ns,
    200    "Noto Serif Ahom"_ns,
    201    "Noto Serif Balinese"_ns,
    202    "Noto Serif Yezidi"_ns,
    203    "Athelas"_ns,
    204    "Courier"_ns,
    205    "Marion"_ns,
    206    "Seravek"_ns,
    207    "Superclarendon"_ns,
    208    "Times"_ns,
    209 };
    210 #endif  // USE_DEPRECATED_FONT_FAMILY_NAMES
    211 
    212 static void GetStringForCFString(CFStringRef aSrc, nsAString& aDest) {
    213  auto len = CFStringGetLength(aSrc);
    214  aDest.SetLength(len);
    215  CFStringGetCharacters(aSrc, CFRangeMake(0, len),
    216                        (UniChar*)aDest.BeginWriting());
    217 }
    218 
    219 static CFStringRef CreateCFStringForString(const nsACString& aSrc) {
    220  return CFStringCreateWithBytes(kCFAllocatorDefault,
    221                                 (const UInt8*)aSrc.BeginReading(),
    222                                 aSrc.Length(), kCFStringEncodingUTF8, false);
    223 }
    224 
    225 #define LOG_FONTLIST(args) \
    226  MOZ_LOG(gfxPlatform::GetLog(eGfxLog_fontlist), mozilla::LogLevel::Debug, args)
    227 #define LOG_FONTLIST_ENABLED() \
    228  MOZ_LOG_TEST(gfxPlatform::GetLog(eGfxLog_fontlist), mozilla::LogLevel::Debug)
    229 #define LOG_CMAPDATA_ENABLED() \
    230  MOZ_LOG_TEST(gfxPlatform::GetLog(eGfxLog_cmapdata), mozilla::LogLevel::Debug)
    231 
    232 #pragma mark -
    233 
    234 // Complex scripts will not render correctly unless appropriate AAT or OT
    235 // layout tables are present.
    236 // For OpenType, we also check that the GSUB table supports the relevant
    237 // script tag, to avoid using things like Arial Unicode MS for Lao (it has
    238 // the characters, but lacks OpenType support).
    239 
    240 // TODO: consider whether we should move this to gfxFontEntry and do similar
    241 // cmap-masking on other platforms to avoid using fonts that won't shape
    242 // properly.
    243 
    244 nsresult CTFontEntry::ReadCMAP(FontInfoData* aFontInfoData) {
    245  // attempt this once, if errors occur leave a blank cmap
    246  if (mCharacterMap || mShmemCharacterMap) {
    247    return NS_OK;
    248  }
    249 
    250  RefPtr<gfxCharacterMap> charmap;
    251  nsresult rv;
    252 
    253  uint32_t uvsOffset = 0;
    254  if (aFontInfoData &&
    255      (charmap = GetCMAPFromFontInfo(aFontInfoData, uvsOffset))) {
    256    rv = NS_OK;
    257  } else {
    258    uint32_t kCMAP = TRUETYPE_TAG('c', 'm', 'a', 'p');
    259    charmap = new gfxCharacterMap(256);
    260    AutoTable cmapTable(this, kCMAP);
    261 
    262    if (cmapTable) {
    263      uint32_t cmapLen;
    264      const uint8_t* cmapData = reinterpret_cast<const uint8_t*>(
    265          hb_blob_get_data(cmapTable, &cmapLen));
    266      rv = gfxFontUtils::ReadCMAP(cmapData, cmapLen, *charmap, uvsOffset);
    267    } else {
    268      rv = NS_ERROR_NOT_AVAILABLE;
    269    }
    270  }
    271  mUVSOffset.exchange(uvsOffset);
    272 
    273  if (NS_SUCCEEDED(rv) && !mIsDataUserFont && !HasGraphiteTables()) {
    274    // For downloadable fonts, trust the author and don't
    275    // try to munge the cmap based on script shaping support.
    276 
    277    // We also assume a Graphite font knows what it's doing,
    278    // and provides whatever shaping is needed for the
    279    // characters it supports, so only check/clear the
    280    // complex-script ranges for non-Graphite fonts
    281 
    282    // for layout support, check for the presence of mort/morx/kerx and/or
    283    // opentype layout tables
    284    bool hasAATLayout = HasFontTable(TRUETYPE_TAG('m', 'o', 'r', 'x')) ||
    285                        HasFontTable(TRUETYPE_TAG('m', 'o', 'r', 't'));
    286    bool hasAppleKerning = HasFontTable(TRUETYPE_TAG('k', 'e', 'r', 'x'));
    287    bool hasGSUB = HasFontTable(TRUETYPE_TAG('G', 'S', 'U', 'B'));
    288    bool hasGPOS = HasFontTable(TRUETYPE_TAG('G', 'P', 'O', 'S'));
    289    if ((hasAATLayout && !(hasGSUB || hasGPOS)) || hasAppleKerning) {
    290      mRequiresAAT = true;  // prefer CoreText if font has no OTL tables,
    291                            // or if it uses the Apple-specific 'kerx'
    292                            // variant of kerning table
    293    }
    294 
    295    for (const ScriptRange* sr = gfxPlatformFontList::sComplexScriptRanges;
    296         sr->rangeStart; sr++) {
    297      // check to see if the cmap includes complex script codepoints
    298      if (charmap->TestRange(sr->rangeStart, sr->rangeEnd)) {
    299        if (hasAATLayout) {
    300          // prefer CoreText for Apple's complex-script fonts,
    301          // even if they also have some OpenType tables
    302          // (e.g. Geeza Pro Bold on 10.6; see bug 614903)
    303          mRequiresAAT = true;
    304          // and don't mask off complex-script ranges, we assume
    305          // the AAT tables will provide the necessary shaping
    306          continue;
    307        }
    308 
    309        // We check for GSUB here, as GPOS alone would not be ok.
    310        if (hasGSUB && SupportsScriptInGSUB(sr->tags, sr->numTags)) {
    311          continue;
    312        }
    313 
    314        charmap->ClearRange(sr->rangeStart, sr->rangeEnd);
    315      }
    316    }
    317 
    318    // Bug 1360309, 1393624: several of Apple's Chinese fonts have spurious
    319    // blank glyphs for obscure Tibetan and Arabic-script codepoints.
    320    // Blocklist these so that font fallback will not use them.
    321    if (mRequiresAAT &&
    322        (FamilyName().EqualsLiteral("Songti SC") ||
    323         FamilyName().EqualsLiteral("Songti TC") ||
    324         FamilyName().EqualsLiteral("STSong") ||
    325         // Bug 1390980: on 10.11, the Kaiti fonts are also affected.
    326         FamilyName().EqualsLiteral("Kaiti SC") ||
    327         FamilyName().EqualsLiteral("Kaiti TC") ||
    328         FamilyName().EqualsLiteral("STKaiti"))) {
    329      charmap->ClearRange(0x0f6b, 0x0f70);
    330      charmap->ClearRange(0x0f8c, 0x0f8f);
    331      charmap->clear(0x0f98);
    332      charmap->clear(0x0fbd);
    333      charmap->ClearRange(0x0fcd, 0x0fff);
    334      charmap->clear(0x0620);
    335      charmap->clear(0x065f);
    336      charmap->ClearRange(0x06ee, 0x06ef);
    337      charmap->clear(0x06ff);
    338    }
    339  }
    340 
    341  bool setCharMap = true;
    342  if (NS_SUCCEEDED(rv)) {
    343    gfxPlatformFontList* pfl = gfxPlatformFontList::PlatformFontList();
    344    fontlist::FontList* sharedFontList = pfl->SharedFontList();
    345    if (!IsUserFont() && mShmemFace && mShmemFamily) {
    346      mShmemFace->SetCharacterMap(sharedFontList, charmap, mShmemFamily);
    347      if (TrySetShmemCharacterMap()) {
    348        setCharMap = false;
    349      }
    350    } else {
    351      charmap = pfl->FindCharMap(charmap);
    352    }
    353    mHasCmapTable = true;
    354  } else {
    355    // if error occurred, initialize to null cmap
    356    charmap = new gfxCharacterMap(0);
    357    mHasCmapTable = false;
    358  }
    359  if (setCharMap) {
    360    // Temporarily retain charmap, until the shared version is
    361    // ready for use.
    362    if (mCharacterMap.compareExchange(nullptr, charmap.get())) {
    363      charmap.get()->AddRef();
    364    }
    365  }
    366 
    367  LOG_FONTLIST(("(fontlist-cmap) name: %s, size: %zu hash: %8.8x%s\n",
    368                mName.get(), charmap->SizeOfIncludingThis(moz_malloc_size_of),
    369                charmap->mHash, mCharacterMap == charmap ? " new" : ""));
    370  if (LOG_CMAPDATA_ENABLED()) {
    371    char prefix[256];
    372    SprintfLiteral(prefix, "(cmapdata) name: %.220s", mName.get());
    373    charmap->Dump(prefix, eGfxLog_cmapdata);
    374  }
    375 
    376  return rv;
    377 }
    378 
    379 gfxFont* CTFontEntry::CreateFontInstance(const gfxFontStyle* aFontStyle) {
    380  RefPtr<UnscaledFontMac> unscaledFont(mUnscaledFont);
    381  if (!unscaledFont) {
    382    CGFontRef baseFont = GetFontRef();
    383    if (!baseFont) {
    384      return nullptr;
    385    }
    386    unscaledFont = new UnscaledFontMac(baseFont, mIsDataUserFont);
    387    mUnscaledFont = unscaledFont;
    388  }
    389 
    390  return new gfxMacFont(unscaledFont, this, aFontStyle);
    391 }
    392 
    393 bool CTFontEntry::HasVariations() {
    394  if (!mHasVariationsInitialized) {
    395    mHasVariationsInitialized = true;
    396    mHasVariations = gfxPlatform::HasVariationFontSupport() &&
    397                     HasFontTable(TRUETYPE_TAG('f', 'v', 'a', 'r'));
    398  }
    399 
    400  return mHasVariations;
    401 }
    402 
    403 void CTFontEntry::GetVariationAxes(
    404    nsTArray<gfxFontVariationAxis>& aVariationAxes) {
    405  // We could do this by creating a CTFont and calling CTFontCopyVariationAxes,
    406  // but it is expensive to instantiate a CTFont for every face just to set up
    407  // the axis information.
    408  // Instead we use gfxFontUtils to read the font tables directly.
    409  gfxFontUtils::GetVariationData(this, &aVariationAxes, nullptr);
    410 }
    411 
    412 void CTFontEntry::GetVariationInstances(
    413    nsTArray<gfxFontVariationInstance>& aInstances) {
    414  // Core Text doesn't offer API for this, so we use gfxFontUtils to read the
    415  // font tables directly.
    416  gfxFontUtils::GetVariationData(this, nullptr, &aInstances);
    417 }
    418 
    419 bool CTFontEntry::IsCFF() {
    420  if (!mIsCFFInitialized) {
    421    mIsCFFInitialized = true;
    422    mIsCFF = HasFontTable(TRUETYPE_TAG('C', 'F', 'F', ' '));
    423  }
    424 
    425  return mIsCFF;
    426 }
    427 
    428 CTFontEntry::CTFontEntry(const nsACString& aPostscriptName, WeightRange aWeight,
    429                         bool aIsStandardFace, double aSizeHint)
    430    : gfxFontEntry(aPostscriptName, aIsStandardFace),
    431      mFontRef(NULL),
    432      mSizeHint(aSizeHint),
    433      mFontRefInitialized(false),
    434      mRequiresAAT(false),
    435      mIsCFF(false),
    436      mIsCFFInitialized(false),
    437      mHasVariations(false),
    438      mHasVariationsInitialized(false),
    439      mHasAATSmallCaps(false),
    440      mHasAATSmallCapsInitialized(false) {
    441  mWeightRange = aWeight;
    442  mOpszAxis.mTag = 0;
    443 }
    444 
    445 CTFontEntry::CTFontEntry(const nsACString& aPostscriptName, CGFontRef aFontRef,
    446                         WeightRange aWeight, StretchRange aStretch,
    447                         SlantStyleRange aStyle, bool aIsDataUserFont,
    448                         bool aIsLocalUserFont)
    449    : gfxFontEntry(aPostscriptName, false),
    450      mFontRef(NULL),
    451      mSizeHint(0.0),
    452      mFontRefInitialized(false),
    453      mRequiresAAT(false),
    454      mIsCFF(false),
    455      mIsCFFInitialized(false),
    456      mHasVariations(false),
    457      mHasVariationsInitialized(false),
    458      mHasAATSmallCaps(false),
    459      mHasAATSmallCapsInitialized(false) {
    460  mFontRef = aFontRef;
    461  mFontRefInitialized = true;
    462  CFRetain(mFontRef);
    463 
    464  mWeightRange = aWeight;
    465  mStretchRange = aStretch;
    466  mFixedPitch = false;  // xxx - do we need this for downloaded fonts?
    467  mStyleRange = aStyle;
    468  mOpszAxis.mTag = 0;
    469 
    470  NS_ASSERTION(!(aIsDataUserFont && aIsLocalUserFont),
    471               "userfont is either a data font or a local font");
    472  mIsDataUserFont = aIsDataUserFont;
    473  mIsLocalUserFont = aIsLocalUserFont;
    474 }
    475 
    476 gfxFontEntry* CTFontEntry::Clone() const {
    477  MOZ_ASSERT(!IsUserFont(), "we can only clone installed fonts!");
    478  CTFontEntry* fe = new CTFontEntry(Name(), Weight(), mStandardFace, mSizeHint);
    479  fe->mStyleRange = mStyleRange;
    480  fe->mStretchRange = mStretchRange;
    481  fe->mFixedPitch = mFixedPitch;
    482  return fe;
    483 }
    484 
    485 CGFontRef CTFontEntry::GetFontRef() {
    486  {
    487    AutoReadLock lock(mLock);
    488    if (mFontRefInitialized) {
    489      return mFontRef;
    490    }
    491  }
    492  AutoWriteLock lock(mLock);
    493  if (!mFontRefInitialized) {
    494    // Cache the CGFontRef, to be released by our destructor.
    495    mFontRef = CreateOrCopyFontRef();
    496    mFontRefInitialized = true;
    497  }
    498  // Return a non-retained reference; caller does not need to release.
    499  return mFontRef;
    500 }
    501 
    502 CGFontRef CTFontEntry::CreateOrCopyFontRef() {
    503  if (mFontRef) {
    504    // We have a cached CGFont, just add a reference. Caller must
    505    // release, but we'll still own our reference.
    506    ::CGFontRetain(mFontRef);
    507    return mFontRef;
    508  }
    509 
    510  CrashReporter::AutoRecordAnnotation autoFontName(
    511      CrashReporter::Annotation::FontName, mName);
    512 
    513  // Create a new CGFont; caller will own the only reference to it.
    514  AutoCFTypeRef<CFStringRef> psname(CreateCFStringForString(mName));
    515  if (!psname) {
    516    return nullptr;
    517  }
    518 
    519  CGFontRef ref = CGFontCreateWithFontName(psname);
    520  return ref;  // Not saved in mFontRef; caller will own the reference
    521 }
    522 
    523 // For a logging build, we wrap the CFDataRef in a FontTableRec so that we can
    524 // use the MOZ_COUNT_[CD]TOR macros in it. A release build without logging
    525 // does not get this overhead.
    526 class FontTableRec {
    527 public:
    528  explicit FontTableRec(CFDataRef aDataRef) : mDataRef(aDataRef) {
    529    MOZ_COUNT_CTOR(FontTableRec);
    530  }
    531 
    532  ~FontTableRec() {
    533    MOZ_COUNT_DTOR(FontTableRec);
    534    CFRelease(mDataRef);
    535  }
    536 
    537 private:
    538  CFDataRef mDataRef;
    539 };
    540 
    541 /*static*/ void CTFontEntry::DestroyBlobFunc(void* aUserData) {
    542 #ifdef NS_BUILD_REFCNT_LOGGING
    543  FontTableRec* ftr = static_cast<FontTableRec*>(aUserData);
    544  delete ftr;
    545 #else
    546  CFRelease((CFDataRef)aUserData);
    547 #endif
    548 }
    549 
    550 hb_blob_t* CTFontEntry::GetFontTable(uint32_t aTag) {
    551  mLock.ReadLock();
    552  AutoCFTypeRef<CGFontRef> fontRef(CreateOrCopyFontRef());
    553  mLock.ReadUnlock();
    554  if (!fontRef) {
    555    return nullptr;
    556  }
    557 
    558  CFDataRef dataRef = ::CGFontCopyTableForTag(fontRef, aTag);
    559  if (dataRef) {
    560    return hb_blob_create((const char*)CFDataGetBytePtr(dataRef),
    561                          CFDataGetLength(dataRef), HB_MEMORY_MODE_READONLY,
    562 #ifdef NS_BUILD_REFCNT_LOGGING
    563                          new FontTableRec(dataRef),
    564 #else
    565                          (void*)dataRef,
    566 #endif
    567                          DestroyBlobFunc);
    568  }
    569 
    570  return nullptr;
    571 }
    572 
    573 bool CTFontEntry::HasFontTable(uint32_t aTableTag) {
    574  {
    575    // If we've already initialized mAvailableTables, we can return without
    576    // needing to take an exclusive lock.
    577    AutoReadLock lock(mLock);
    578    if (mAvailableTables.Count()) {
    579      return mAvailableTables.GetEntry(aTableTag);
    580    }
    581  }
    582 
    583  AutoWriteLock lock(mLock);
    584  if (mAvailableTables.Count() == 0) {
    585    AutoCFTypeRef<CGFontRef> fontRef(CreateOrCopyFontRef());
    586    if (!fontRef) {
    587      return false;
    588    }
    589    AutoCFTypeRef<CFArrayRef> tags(::CGFontCopyTableTags(fontRef));
    590    if (!tags) {
    591      return false;
    592    }
    593    int numTags = (int)CFArrayGetCount(tags);
    594    for (int t = 0; t < numTags; t++) {
    595      uint32_t tag = (uint32_t)(uintptr_t)CFArrayGetValueAtIndex(tags, t);
    596      mAvailableTables.PutEntry(tag);
    597    }
    598  }
    599 
    600  return mAvailableTables.GetEntry(aTableTag);
    601 }
    602 
    603 static bool CheckForAATSmallCaps(CFArrayRef aFeatures) {
    604  // Walk the array of feature descriptors from the font, and see whether
    605  // a small-caps feature setting is available.
    606  // Just bail out (returning false) if at any point we fail to find the
    607  // expected dictionary keys, etc; if the font has bad data, we don't even
    608  // try to search the rest of it.
    609  auto numFeatures = CFArrayGetCount(aFeatures);
    610  for (auto f = 0; f < numFeatures; ++f) {
    611    auto featureDict = (CFDictionaryRef)CFArrayGetValueAtIndex(aFeatures, f);
    612    if (!featureDict) {
    613      return false;
    614    }
    615    auto featureNum = (CFNumberRef)CFDictionaryGetValue(
    616        featureDict, CFSTR("CTFeatureTypeIdentifier"));
    617    if (!featureNum) {
    618      return false;
    619    }
    620    int16_t featureType;
    621    if (!CFNumberGetValue(featureNum, kCFNumberSInt16Type, &featureType)) {
    622      return false;
    623    }
    624    if (featureType == kLetterCaseType || featureType == kLowerCaseType) {
    625      // Which selector to look for, depending whether we've found the
    626      // legacy LetterCase feature or the new LowerCase one.
    627      const uint16_t smallCaps = (featureType == kLetterCaseType)
    628                                     ? kSmallCapsSelector
    629                                     : kLowerCaseSmallCapsSelector;
    630      auto selectors = (CFArrayRef)CFDictionaryGetValue(
    631          featureDict, CFSTR("CTFeatureTypeSelectors"));
    632      if (!selectors) {
    633        return false;
    634      }
    635      auto numSelectors = CFArrayGetCount(selectors);
    636      for (auto s = 0; s < numSelectors; s++) {
    637        auto selectorDict =
    638            (CFDictionaryRef)CFArrayGetValueAtIndex(selectors, s);
    639        if (!selectorDict) {
    640          return false;
    641        }
    642        auto selectorNum = (CFNumberRef)CFDictionaryGetValue(
    643            selectorDict, CFSTR("CTFeatureSelectorIdentifier"));
    644        if (!selectorNum) {
    645          return false;
    646        }
    647        int16_t selectorValue;
    648        if (!CFNumberGetValue(selectorNum, kCFNumberSInt16Type,
    649                              &selectorValue)) {
    650          return false;
    651        }
    652        if (selectorValue == smallCaps) {
    653          return true;
    654        }
    655      }
    656    }
    657  }
    658  return false;
    659 }
    660 
    661 bool CTFontEntry::SupportsOpenTypeFeature(Script aScript,
    662                                          uint32_t aFeatureTag) {
    663  // If we're going to shape with Core Text, we don't support added
    664  // OpenType features (aside from any CT applies by default), except
    665  // for 'smcp' which we map to an AAT feature selector.
    666  if (RequiresAATLayout()) {
    667    if (aFeatureTag != HB_TAG('s', 'm', 'c', 'p')) {
    668      return false;
    669    }
    670    if (mHasAATSmallCapsInitialized) {
    671      return mHasAATSmallCaps;
    672    }
    673    mHasAATSmallCapsInitialized = true;
    674    CGFontRef cgFont = GetFontRef();
    675    if (!cgFont) {
    676      return mHasAATSmallCaps;
    677    }
    678 
    679    CrashReporter::AutoRecordAnnotation autoFontName(
    680        CrashReporter::Annotation::FontName, FamilyName());
    681 
    682    AutoCFTypeRef<CTFontRef> ctFont(
    683        CTFontCreateWithGraphicsFont(cgFont, 0.0, nullptr, nullptr));
    684    if (ctFont) {
    685      AutoCFTypeRef<CFArrayRef> features(CTFontCopyFeatures(ctFont));
    686      if (features) {
    687        mHasAATSmallCaps = CheckForAATSmallCaps(features);
    688      }
    689    }
    690    return mHasAATSmallCaps;
    691  }
    692  return gfxFontEntry::SupportsOpenTypeFeature(aScript, aFeatureTag);
    693 }
    694 
    695 void CTFontEntry::AddSizeOfIncludingThis(MallocSizeOf aMallocSizeOf,
    696                                         FontListSizes* aSizes) const {
    697  aSizes->mFontListSize += aMallocSizeOf(this);
    698  AddSizeOfExcludingThis(aMallocSizeOf, aSizes);
    699 }
    700 
    701 static CTFontDescriptorRef CreateDescriptorForFamily(
    702    const nsACString& aFamilyName, bool aNormalized) {
    703  AutoCFTypeRef<CFStringRef> family(CreateCFStringForString(aFamilyName));
    704  const void* values[] = {family};
    705  const void* keys[] = {kCTFontFamilyNameAttribute};
    706  AutoCFTypeRef<CFDictionaryRef> attributes(CFDictionaryCreate(
    707      kCFAllocatorDefault, keys, values, 1, &kCFTypeDictionaryKeyCallBacks,
    708      &kCFTypeDictionaryValueCallBacks));
    709 
    710  // Not AutoCFTypeRef, because we might return it.
    711  CTFontDescriptorRef descriptor =
    712      CTFontDescriptorCreateWithAttributes(attributes);
    713 
    714  if (aNormalized) {
    715    CTFontDescriptorRef normalized =
    716        CTFontDescriptorCreateMatchingFontDescriptor(descriptor, nullptr);
    717    if (normalized) {
    718      CFRelease(descriptor);
    719      return normalized;
    720    }
    721  }
    722 
    723  return descriptor;
    724 }
    725 
    726 void CTFontFamily::LocalizedName(nsACString& aLocalizedName) {
    727  AutoCFTypeRef<CTFontDescriptorRef> descriptor(
    728      CreateDescriptorForFamily(mName, true));
    729  if (descriptor) {
    730    AutoCFTypeRef<CFStringRef> name(
    731        static_cast<CFStringRef>(CTFontDescriptorCopyLocalizedAttribute(
    732            descriptor, kCTFontFamilyNameAttribute, nullptr)));
    733    if (name) {
    734      nsAutoString localized;
    735      GetStringForCFString(name, localized);
    736      if (!localized.IsEmpty()) {
    737        CopyUTF16toUTF8(localized, aLocalizedName);
    738        return;
    739      }
    740    }
    741  }
    742 
    743  // failed to get localized name, just use the canonical one
    744  aLocalizedName = mName;
    745 }
    746 
    747 // Return the CSS weight value to use for the given face, overriding what
    748 // AppKit gives us (used to adjust families with bad weight values, see
    749 // bug 931426).
    750 // A return value of 0 indicates no override - use the existing weight.
    751 static inline int GetWeightOverride(const nsAString& aPSName) {
    752  nsAutoCString prefName("font.weight-override.");
    753  // The PostScript name is required to be ASCII; if it's not, the font is
    754  // broken anyway, so we really don't care that this is lossy.
    755  LossyAppendUTF16toASCII(aPSName, prefName);
    756  return Preferences::GetInt(prefName.get(), 0);
    757 }
    758 
    759 // The Core Text weight trait is documented as
    760 //
    761 //   ...a float value between -1.0 and 1.0 for normalized weight.
    762 //   The value of 0.0 corresponds to the regular or medium font weight.
    763 //
    764 // (https://developer.apple.com/documentation/coretext/kctfontweighttrait)
    765 //
    766 // CSS 'normal' font-weight is defined as 400, so we map 0.0 to this.
    767 // The exact mapping to use for other values is not well defined; the table
    768 // here is empirically determined by looking at what Core Text returns for
    769 // the various system fonts that have a range of weights.
    770 static inline int32_t CoreTextWeightToCSSWeight(CGFloat aCTWeight) {
    771  using Mapping = std::pair<CGFloat, int32_t>;
    772  constexpr Mapping kCoreTextToCSSWeights[] = {
    773      // clang-format off
    774      {-1.0, 1},
    775      {-0.8, 100},
    776      {-0.6, 200},
    777      {-0.4, 300},
    778      {0.0,  400},  // standard 'regular' weight
    779      {0.23, 500},
    780      {0.3,  600},
    781      {0.4,  700},  // standard 'bold' weight
    782      {0.56, 800},
    783      {0.62, 900},  // Core Text seems to return 0.62 for faces with both
    784                    // usWeightClass=800 and 900 in their OS/2 tables!
    785                    // We use 900 as there are also fonts that return 0.56,
    786                    // so we want an intermediate value for that.
    787      {1.0,  1000},
    788      // clang-format on
    789  };
    790  const auto* begin = &kCoreTextToCSSWeights[0];
    791  const auto* end = begin + std::size(kCoreTextToCSSWeights);
    792  auto m = std::upper_bound(begin, end, aCTWeight,
    793                            [](CGFloat aValue, const Mapping& aMapping) {
    794                              return aValue <= aMapping.first;
    795                            });
    796  if (m == end) {
    797    NS_WARNING("Core Text weight out of range");
    798    return 1000;
    799  }
    800  if (m->first == aCTWeight || m == begin) {
    801    return m->second;
    802  }
    803  // Interpolate between the preceding and found entries:
    804  const auto* prev = m - 1;
    805  const auto t = (aCTWeight - prev->first) / (m->first - prev->first);
    806  return NS_round(prev->second * (1.0 - t) + m->second * t);
    807 }
    808 
    809 // The Core Text width trait is documented as
    810 //
    811 //   ...a float between -1.0 and 1.0. The value of 0.0 corresponds to regular
    812 //   glyph spacing, and negative values represent condensed glyph spacing
    813 //
    814 // (https://developer.apple.com/documentation/coretext/kctfontweighttrait)
    815 //
    816 // CSS 'normal' font-stretch is 100%; 'ultra-expanded' is 200%, and 'ultra-
    817 // condensed' is 50%. We map the extremes of the Core Text trait to these
    818 // values, and interpolate in between these and normal.
    819 static inline FontStretch CoreTextWidthToCSSStretch(CGFloat aCTWidth) {
    820  if (aCTWidth >= 0.0) {
    821    return FontStretch::FromFloat(100.0 + aCTWidth * 100.0);
    822  }
    823  return FontStretch::FromFloat(100.0 + aCTWidth * 50.0);
    824 }
    825 
    826 void CTFontFamily::AddFace(CTFontDescriptorRef aFace) {
    827  AutoCFTypeRef<CFStringRef> psname(
    828      (CFStringRef)CTFontDescriptorCopyAttribute(aFace, kCTFontNameAttribute));
    829  AutoCFTypeRef<CFStringRef> facename(
    830      (CFStringRef)CTFontDescriptorCopyAttribute(aFace,
    831                                                 kCTFontStyleNameAttribute));
    832 
    833  AutoCFTypeRef<CFDictionaryRef> traitsDict(
    834      (CFDictionaryRef)CTFontDescriptorCopyAttribute(aFace,
    835                                                     kCTFontTraitsAttribute));
    836  CFNumberRef weight =
    837      (CFNumberRef)CFDictionaryGetValue(traitsDict, kCTFontWeightTrait);
    838  CFNumberRef width =
    839      (CFNumberRef)CFDictionaryGetValue(traitsDict, kCTFontWidthTrait);
    840  CFNumberRef symbolicTraits =
    841      (CFNumberRef)CFDictionaryGetValue(traitsDict, kCTFontSymbolicTrait);
    842 
    843  bool isStandardFace = false;
    844 
    845  // make a nsString
    846  nsAutoString postscriptFontName;
    847  GetStringForCFString(psname, postscriptFontName);
    848 
    849  int32_t cssWeight = GetWeightOverride(postscriptFontName);
    850  if (cssWeight) {
    851    // scale down and clamp, to get a value from 1..9
    852    cssWeight = ((cssWeight + 50) / 100);
    853    cssWeight = std::clamp(cssWeight, 1, 9);
    854    cssWeight *= 100;  // scale up to CSS values
    855  } else {
    856    CGFloat weightValue;
    857    CFNumberGetValue(weight, kCFNumberCGFloatType, &weightValue);
    858    cssWeight = CoreTextWeightToCSSWeight(weightValue);
    859  }
    860 
    861  if (kCFCompareEqualTo == CFStringCompare(facename, CFSTR("Regular"), 0) ||
    862      kCFCompareEqualTo == CFStringCompare(facename, CFSTR("Bold"), 0) ||
    863      kCFCompareEqualTo == CFStringCompare(facename, CFSTR("Italic"), 0) ||
    864      kCFCompareEqualTo == CFStringCompare(facename, CFSTR("Oblique"), 0) ||
    865      kCFCompareEqualTo == CFStringCompare(facename, CFSTR("Bold Italic"), 0) ||
    866      kCFCompareEqualTo ==
    867          CFStringCompare(facename, CFSTR("Bold Oblique"), 0)) {
    868    isStandardFace = true;
    869  }
    870 
    871  // create a font entry
    872  CTFontEntry* fontEntry = new CTFontEntry(
    873      NS_ConvertUTF16toUTF8(postscriptFontName),
    874      WeightRange(FontWeight::FromInt(cssWeight)), isStandardFace);
    875 
    876  CGFloat widthValue;
    877  CFNumberGetValue(width, kCFNumberCGFloatType, &widthValue);
    878  fontEntry->mStretchRange =
    879      StretchRange(CoreTextWidthToCSSStretch(widthValue));
    880 
    881  SInt32 traitsValue;
    882  CFNumberGetValue(symbolicTraits, kCFNumberSInt32Type, &traitsValue);
    883  if (traitsValue & kCTFontItalicTrait) {
    884    fontEntry->mStyleRange = SlantStyleRange(FontSlantStyle::ITALIC);
    885  }
    886 
    887  if (traitsValue & kCTFontMonoSpaceTrait) {
    888    fontEntry->mFixedPitch = true;
    889  }
    890 
    891  if (gfxPlatform::HasVariationFontSupport()) {
    892    fontEntry->SetupVariationRanges();
    893  }
    894 
    895  if (LOG_FONTLIST_ENABLED()) {
    896    nsAutoCString weightString;
    897    fontEntry->Weight().ToString(weightString);
    898    nsAutoCString stretchString;
    899    fontEntry->Stretch().ToString(stretchString);
    900    LOG_FONTLIST(
    901        ("(fontlist) added (%s) to family (%s)"
    902         " with style: %s weight: %s stretch: %s",
    903         fontEntry->Name().get(), Name().get(),
    904         fontEntry->IsItalic() ? "italic" : "normal", weightString.get(),
    905         stretchString.get()));
    906  }
    907 
    908  // insert into font entry array of family
    909  AddFontEntryLocked(fontEntry);
    910 }
    911 
    912 void CTFontFamily::FindStyleVariationsLocked(FontInfoData* aFontInfoData) {
    913  if (mHasStyles) {
    914    return;
    915  }
    916 
    917  AUTO_PROFILER_LABEL_DYNAMIC_NSCSTRING("CTFontFamily::FindStyleVariations",
    918                                        LAYOUT, mName);
    919 
    920  if (mForSystemFont) {
    921    MOZ_ASSERT(gfxPlatform::HasVariationFontSupport());
    922 
    923    auto addToFamily = [&](CTFontRef aFont) MOZ_REQUIRES(mLock) {
    924      AutoCFTypeRef<CFStringRef> psName(CTFontCopyPostScriptName(aFont));
    925      nsAutoString nameUTF16;
    926      nsAutoCString nameUTF8;
    927      GetStringForCFString(psName, nameUTF16);
    928      CopyUTF16toUTF8(nameUTF16, nameUTF8);
    929 
    930      auto* fe =
    931          new CTFontEntry(nameUTF8, WeightRange(FontWeight::NORMAL), true, 0.0);
    932 
    933      // Set the appropriate style, assuming it may not have a variation range.
    934      CTFontSymbolicTraits traits = CTFontGetSymbolicTraits(aFont);
    935      fe->mStyleRange = SlantStyleRange((traits & kCTFontTraitItalic)
    936                                            ? FontSlantStyle::ITALIC
    937                                            : FontSlantStyle::NORMAL);
    938 
    939      // Set up weight (and width, if present) ranges.
    940      fe->SetupVariationRanges();
    941      AddFontEntryLocked(fe);
    942    };
    943 
    944    addToFamily(mForSystemFont);
    945 
    946    // See if there is a corresponding italic face, and add it to the family.
    947    AutoCFTypeRef<CTFontRef> italicFont(CTFontCreateCopyWithSymbolicTraits(
    948        mForSystemFont, 0.0, nullptr, kCTFontTraitItalic, kCTFontTraitItalic));
    949    if (italicFont != mForSystemFont) {
    950      addToFamily(italicFont);
    951    }
    952 
    953    CFRelease(mForSystemFont);
    954    mForSystemFont = nullptr;
    955 
    956    SetHasStyles(true);
    957 
    958    return;
    959  }
    960 
    961  struct Context {
    962    CTFontFamily* family;
    963    const void* prevValue = nullptr;
    964  };
    965 
    966  auto addFaceFunc = [](const void* aValue, void* aContext) -> void {
    967    Context* context = (Context*)aContext;
    968    if (aValue == context->prevValue) {
    969      return;
    970    }
    971    context->prevValue = aValue;
    972    CTFontFamily* family = context->family;
    973    // Calling family->AddFace requires that family->mLock is held. We know
    974    // this will be true because FindStyleVariationsLocked already requires it,
    975    // but the thread-safety analysis can't track that through into the lambda
    976    // here, so we disable the check to avoid a spurious warning.
    977    MOZ_PUSH_IGNORE_THREAD_SAFETY;
    978    family->AddFace((CTFontDescriptorRef)aValue);
    979    MOZ_POP_THREAD_SAFETY;
    980  };
    981 
    982  AutoCFTypeRef<CTFontDescriptorRef> descriptor(
    983      CreateDescriptorForFamily(mName, false));
    984  AutoCFTypeRef<CFArrayRef> faces(
    985      CTFontDescriptorCreateMatchingFontDescriptors(descriptor, nullptr));
    986 
    987  if (faces) {
    988    Context context{this};
    989    CFArrayApplyFunction(faces, CFRangeMake(0, CFArrayGetCount(faces)),
    990                         addFaceFunc, &context);
    991  }
    992 
    993  SortAvailableFonts();
    994  SetHasStyles(true);
    995 
    996  if (mIsBadUnderlineFamily) {
    997    SetBadUnderlineFonts();
    998  }
    999 
   1000  CheckForSimpleFamily();
   1001 }
   1002 
   1003 /* CoreTextFontList */
   1004 #pragma mark -
   1005 
   1006 CoreTextFontList::CoreTextFontList()
   1007    : gfxPlatformFontList(false), mDefaultFont(nullptr) {
   1008 #ifdef MOZ_BUNDLED_FONTS
   1009  // We activate bundled fonts if the pref is > 0 (on) or < 0 (auto), only an
   1010  // explicit value of 0 (off) will disable them.
   1011  if (StaticPrefs::gfx_bundled_fonts_activate_AtStartup() != 0) {
   1012    auto timerId = glean::fontlist::bundledfonts_activate.Start();
   1013    ActivateBundledFonts();
   1014    glean::fontlist::bundledfonts_activate.StopAndAccumulate(
   1015        std::move(timerId));
   1016  }
   1017 #endif
   1018 
   1019  // Load the font-list preferences now, so that we don't have to do it from
   1020  // Init[Shared]FontListForPlatform, which may be called off-main-thread.
   1021  gfxFontUtils::GetPrefsFontList("font.preload-names-list", mPreloadFonts);
   1022 }
   1023 
   1024 CoreTextFontList::~CoreTextFontList() {
   1025  AutoLock lock(mLock);
   1026 
   1027  if (XRE_IsParentProcess()) {
   1028    CFNotificationCenterRemoveObserver(
   1029        CFNotificationCenterGetLocalCenter(), this,
   1030        kCTFontManagerRegisteredFontsChangedNotification, 0);
   1031  }
   1032 
   1033  if (mDefaultFont) {
   1034    CFRelease(mDefaultFont);
   1035  }
   1036 }
   1037 
   1038 void CoreTextFontList::AddFamily(const nsACString& aFamilyName,
   1039                                 FontVisibility aVisibility) {
   1040  nsAutoCString key;
   1041  ToLowerCase(aFamilyName, key);
   1042 
   1043  RefPtr<gfxFontFamily> familyEntry =
   1044      new CTFontFamily(aFamilyName, aVisibility);
   1045  mFontFamilies.InsertOrUpdate(key, RefPtr{familyEntry});
   1046 
   1047  // check the bad underline blocklist
   1048  if (mBadUnderlineFamilyNames.ContainsSorted(key)) {
   1049    familyEntry->SetBadUnderlineFamily();
   1050  }
   1051 }
   1052 
   1053 void CoreTextFontList::AddFamily(CFStringRef aFamily) {
   1054  // CTFontManager includes internal family names and LastResort; skip those.
   1055  if (!aFamily ||
   1056      CFStringCompare(aFamily, CFSTR("LastResort"),
   1057                      kCFCompareCaseInsensitive) == kCFCompareEqualTo ||
   1058      CFStringCompare(aFamily, CFSTR(".LastResort"),
   1059                      kCFCompareCaseInsensitive) == kCFCompareEqualTo) {
   1060    return;
   1061  }
   1062 
   1063  nsAutoString familyName;
   1064  GetStringForCFString(aFamily, familyName);
   1065 
   1066  NS_ConvertUTF16toUTF8 nameUtf8(familyName);
   1067  AddFamily(nameUtf8, GetVisibilityForFamily(nameUtf8));
   1068 }
   1069 
   1070 /* static */
   1071 void CoreTextFontList::ActivateFontsFromDir(
   1072    const nsACString& aDir, nsTHashSet<nsCStringHashKey>* aLoadedFamilies) {
   1073  AutoCFTypeRef<CFURLRef> directory(CFURLCreateFromFileSystemRepresentation(
   1074      kCFAllocatorDefault, (const UInt8*)nsPromiseFlatCString(aDir).get(),
   1075      aDir.Length(), true));
   1076  if (!directory) {
   1077    return;
   1078  }
   1079  AutoCFTypeRef<CFURLEnumeratorRef> enumerator(
   1080      CFURLEnumeratorCreateForDirectoryURL(kCFAllocatorDefault, directory,
   1081                                           kCFURLEnumeratorDefaultBehavior,
   1082                                           nullptr));
   1083  if (!enumerator) {
   1084    return;
   1085  }
   1086  AutoCFTypeRef<CFMutableArrayRef> urls(
   1087      CFArrayCreateMutable(kCFAllocatorDefault, 0, &kCFTypeArrayCallBacks));
   1088  if (!urls) {
   1089    return;
   1090  }
   1091 
   1092  CFURLRef url;
   1093  CFURLEnumeratorResult result;
   1094  do {
   1095    result = CFURLEnumeratorGetNextURL(enumerator, &url, nullptr);
   1096    if (result != kCFURLEnumeratorSuccess) {
   1097      continue;
   1098    }
   1099    CFArrayAppendValue(urls, url);
   1100 
   1101    if (!aLoadedFamilies) {
   1102      continue;
   1103    }
   1104    AutoCFTypeRef<CFArrayRef> descriptors(
   1105        CTFontManagerCreateFontDescriptorsFromURL(url));
   1106    if (!descriptors || !CFArrayGetCount(descriptors)) {
   1107      continue;
   1108    }
   1109    CTFontDescriptorRef desc =
   1110        (CTFontDescriptorRef)CFArrayGetValueAtIndex(descriptors, 0);
   1111    AutoCFTypeRef<CFStringRef> name((CFStringRef)CTFontDescriptorCopyAttribute(
   1112        desc, kCTFontFamilyNameAttribute));
   1113    nsAutoCString key;
   1114    key.SetLength((CFStringGetLength(name) + 1) * 3);
   1115    if (CFStringGetCString(name, key.BeginWriting(), key.Length(),
   1116                           kCFStringEncodingUTF8)) {
   1117      key.SetLength(strlen(key.get()));
   1118      aLoadedFamilies->Insert(key);
   1119    }
   1120  } while (result != kCFURLEnumeratorEnd);
   1121 
   1122  CTFontManagerRegisterFontURLs(urls, kCTFontManagerScopeProcess, false,
   1123                                nullptr);
   1124 }
   1125 
   1126 void CoreTextFontList::ReadSystemFontList(dom::SystemFontList* aList)
   1127    MOZ_NO_THREAD_SAFETY_ANALYSIS {
   1128  // Note: We rely on the records for mSystemFontFamilyName (if present) being
   1129  // *before* the main font list, so that name is known in the content process
   1130  // by the time we add the actual family records to the font list.
   1131  aList->entries().AppendElement(FontFamilyListEntry(
   1132      mSystemFontFamilyName, FontVisibility::Unknown, kSystemFontFamily));
   1133 
   1134  // Now collect the list of available families, with visibility attributes.
   1135  for (auto f = mFontFamilies.Iter(); !f.Done(); f.Next()) {
   1136    auto macFamily = f.Data().get();
   1137    aList->entries().AppendElement(FontFamilyListEntry(
   1138        macFamily->Name(), macFamily->Visibility(), kStandardFontFamily));
   1139  }
   1140 }
   1141 
   1142 void CoreTextFontList::PreloadNamesList() {
   1143  uint32_t numFonts = mPreloadFonts.Length();
   1144  for (uint32_t i = 0; i < numFonts; i++) {
   1145    nsAutoCString key;
   1146    GenerateFontListKey(mPreloadFonts[i], key);
   1147 
   1148    // only search canonical names!
   1149    gfxFontFamily* familyEntry = mFontFamilies.GetWeak(key);
   1150    if (familyEntry) {
   1151      familyEntry->ReadOtherFamilyNames(this);
   1152    }
   1153  }
   1154 }
   1155 
   1156 nsresult CoreTextFontList::InitFontListForPlatform() {
   1157  // The font registration thread was created early in startup, to give the
   1158  // system a head start on activating all the supplemental-language fonts.
   1159  // Here, we need to wait until it has finished its work.
   1160  gfxPlatformMac::WaitForFontRegistration();
   1161 
   1162  auto timer = glean::fontlist::mac_init_total.Measure();
   1163 
   1164  InitSystemFontNames();
   1165 
   1166  if (XRE_IsParentProcess()) {
   1167    static bool firstTime = true;
   1168    if (firstTime) {
   1169      CFNotificationCenterAddObserver(
   1170          CFNotificationCenterGetLocalCenter(), this,
   1171          RegisteredFontsChangedNotificationCallback,
   1172          kCTFontManagerRegisteredFontsChangedNotification, 0,
   1173          CFNotificationSuspensionBehaviorDeliverImmediately);
   1174      firstTime = false;
   1175    }
   1176 
   1177    // We're not a content process, so get the available fonts directly
   1178    // from Core Text.
   1179    AutoCFTypeRef<CFArrayRef> familyNames(
   1180        CTFontManagerCopyAvailableFontFamilyNames());
   1181    for (CFIndex i = 0; i < CFArrayGetCount(familyNames); i++) {
   1182      CFStringRef familyName =
   1183          (CFStringRef)CFArrayGetValueAtIndex(familyNames, i);
   1184      AddFamily(familyName);
   1185    }
   1186 #if USE_DEPRECATED_FONT_FAMILY_NAMES
   1187    for (const auto& name : kDeprecatedFontFamilies) {
   1188      if (DeprecatedFamilyIsAvailable(name)) {
   1189        AddFamily(name, GetVisibilityForFamily(name));
   1190      }
   1191    }
   1192 #endif
   1193  } else {
   1194    // Content process: use font list passed from the chrome process via
   1195    // the GetXPCOMProcessAttributes message, because it's much faster than
   1196    // querying Core Text again in the child.
   1197    auto& fontList = dom::ContentChild::GetSingleton()->SystemFontList();
   1198    for (FontFamilyListEntry& ffe : fontList.entries()) {
   1199      switch (ffe.entryType()) {
   1200        case kStandardFontFamily:
   1201          if (ffe.familyName() == mSystemFontFamilyName) {
   1202            continue;
   1203          }
   1204          AddFamily(ffe.familyName(), ffe.visibility());
   1205          break;
   1206        case kSystemFontFamily:
   1207          mSystemFontFamilyName = ffe.familyName();
   1208          break;
   1209      }
   1210    }
   1211    fontList.entries().Clear();
   1212  }
   1213 
   1214  InitSingleFaceList();
   1215 
   1216  // to avoid full search of font name tables, seed the other names table with
   1217  // localized names from some of the prefs fonts which are accessed via their
   1218  // localized names.  changes in the pref fonts will only cause a font lookup
   1219  // miss earlier. this is a simple optimization, it's not required for
   1220  // correctness
   1221  PreloadNamesList();
   1222 
   1223  // start the delayed cmap loader
   1224  GetPrefsAndStartLoader();
   1225 
   1226  return NS_OK;
   1227 }
   1228 
   1229 void CoreTextFontList::InitSharedFontListForPlatform() {
   1230  gfxPlatformMac::WaitForFontRegistration();
   1231 
   1232  InitSystemFontNames();
   1233 
   1234  if (XRE_IsParentProcess()) {
   1235    // Only the parent process listens for OS font-changed notifications;
   1236    // after rebuilding its list, it will update the content processes.
   1237    static bool firstTime = true;
   1238    if (firstTime) {
   1239      CFNotificationCenterAddObserver(
   1240          CFNotificationCenterGetLocalCenter(), this,
   1241          RegisteredFontsChangedNotificationCallback,
   1242          kCTFontManagerRegisteredFontsChangedNotification, 0,
   1243          CFNotificationSuspensionBehaviorDeliverImmediately);
   1244      firstTime = false;
   1245    }
   1246 
   1247    AutoCFTypeRef<CFArrayRef> familyNames(
   1248        CTFontManagerCopyAvailableFontFamilyNames());
   1249    nsTArray<fontlist::Family::InitData> families;
   1250    families.SetCapacity(CFArrayGetCount(familyNames)
   1251 #if USE_DEPRECATED_FONT_FAMILY_NAMES
   1252                         + std::size(kDeprecatedFontFamilies)
   1253 #endif
   1254    );
   1255    for (CFIndex i = 0; i < CFArrayGetCount(familyNames); ++i) {
   1256      nsAutoString name16;
   1257      CFStringRef familyName =
   1258          (CFStringRef)CFArrayGetValueAtIndex(familyNames, i);
   1259      GetStringForCFString(familyName, name16);
   1260      NS_ConvertUTF16toUTF8 name(name16);
   1261      nsAutoCString key;
   1262      GenerateFontListKey(name, key);
   1263      families.AppendElement(fontlist::Family::InitData(
   1264          key, name, fontlist::Family::kNoIndex, GetVisibilityForFamily(name)));
   1265    }
   1266 #if USE_DEPRECATED_FONT_FAMILY_NAMES
   1267    for (const nsACString& name : kDeprecatedFontFamilies) {
   1268      if (DeprecatedFamilyIsAvailable(name)) {
   1269        nsAutoCString key;
   1270        GenerateFontListKey(name, key);
   1271        families.AppendElement(
   1272            fontlist::Family::InitData(key, name, fontlist::Family::kNoIndex,
   1273                                       GetVisibilityForFamily(name)));
   1274      }
   1275    }
   1276 #endif
   1277    SharedFontList()->SetFamilyNames(families);
   1278    InitAliasesForSingleFaceList();
   1279    GetPrefsAndStartLoader();
   1280  }
   1281 }
   1282 
   1283 gfxFontFamily* CoreTextFontList::FindSystemFontFamily(
   1284    const nsACString& aFamily) {
   1285  nsAutoCString key;
   1286  GenerateFontListKey(aFamily, key);
   1287 
   1288  gfxFontFamily* familyEntry;
   1289  if ((familyEntry = mFontFamilies.GetWeak(key))) {
   1290    return CheckFamily(familyEntry);
   1291  }
   1292 
   1293  return nullptr;
   1294 }
   1295 
   1296 void CoreTextFontList::RegisteredFontsChangedNotificationCallback(
   1297    CFNotificationCenterRef center, void* observer, CFStringRef name,
   1298    const void* object, CFDictionaryRef userInfo) {
   1299  if (!CFEqual(name, kCTFontManagerRegisteredFontsChangedNotification)) {
   1300    return;
   1301  }
   1302 
   1303  CoreTextFontList* fl = static_cast<CoreTextFontList*>(observer);
   1304  if (!fl->IsInitialized()) {
   1305    return;
   1306  }
   1307 
   1308  // xxx - should be carefully pruning the list of fonts, not rebuilding it from
   1309  // scratch
   1310  fl->UpdateFontList();
   1311 
   1312  auto flags = gfxPlatform::GlobalReflowFlags::NeedsReframe |
   1313               gfxPlatform::GlobalReflowFlags::FontsChanged;
   1314  gfxPlatform::ForceGlobalReflow(flags);
   1315  dom::ContentParent::NotifyUpdatedFonts(true);
   1316 }
   1317 
   1318 gfxFontEntry* CoreTextFontList::PlatformGlobalFontFallback(
   1319    FontVisibilityProvider* aFontVisibilityProvider, const uint32_t aCh,
   1320    Script aRunScript, const gfxFontStyle* aMatchStyle,
   1321    FontFamily& aMatchedFamily) {
   1322  CFStringRef str;
   1323  UniChar ch[2];
   1324  CFIndex length = 1;
   1325 
   1326  if (IS_IN_BMP(aCh)) {
   1327    ch[0] = aCh;
   1328    str = CFStringCreateWithCharactersNoCopy(kCFAllocatorDefault, ch, 1,
   1329                                             kCFAllocatorNull);
   1330  } else {
   1331    ch[0] = H_SURROGATE(aCh);
   1332    ch[1] = L_SURROGATE(aCh);
   1333    str = CFStringCreateWithCharactersNoCopy(kCFAllocatorDefault, ch, 2,
   1334                                             kCFAllocatorNull);
   1335    length = 2;
   1336  }
   1337  if (!str) {
   1338    return nullptr;
   1339  }
   1340 
   1341  // use CoreText to find the fallback family
   1342 
   1343  gfxFontEntry* fontEntry = nullptr;
   1344  bool cantUseFallbackFont = false;
   1345 
   1346  if (!mDefaultFont) {
   1347    mDefaultFont = CTFontCreateWithName(CFSTR("LucidaGrande"), 12.f, NULL);
   1348  }
   1349 
   1350  AutoCFTypeRef<CTFontRef> fallback(
   1351      CTFontCreateForString(mDefaultFont, str, CFRangeMake(0, length)));
   1352 
   1353  if (fallback) {
   1354    AutoCFTypeRef<CFStringRef> familyNameRef(CTFontCopyFamilyName(fallback));
   1355 
   1356    if (familyNameRef &&
   1357        CFStringCompare(familyNameRef, CFSTR("LastResort"),
   1358                        kCFCompareCaseInsensitive) != kCFCompareEqualTo &&
   1359        CFStringCompare(familyNameRef, CFSTR(".LastResort"),
   1360                        kCFCompareCaseInsensitive) != kCFCompareEqualTo) {
   1361      AutoTArray<UniChar, 1024> buffer;
   1362      CFIndex familyNameLen = CFStringGetLength(familyNameRef);
   1363      buffer.SetLength(familyNameLen + 1);
   1364      CFStringGetCharacters(familyNameRef, CFRangeMake(0, familyNameLen),
   1365                            buffer.Elements());
   1366      buffer[familyNameLen] = 0;
   1367      NS_ConvertUTF16toUTF8 familyNameString(
   1368          reinterpret_cast<char16_t*>(buffer.Elements()), familyNameLen);
   1369 
   1370      if (SharedFontList()) {
   1371        fontlist::Family* family =
   1372            FindSharedFamily(aFontVisibilityProvider, familyNameString);
   1373        if (family) {
   1374          fontlist::Face* face =
   1375              family->FindFaceForStyle(SharedFontList(), *aMatchStyle);
   1376          if (face) {
   1377            fontEntry = GetOrCreateFontEntryLocked(face, family);
   1378          }
   1379          if (fontEntry) {
   1380            if (fontEntry->HasCharacter(aCh)) {
   1381              aMatchedFamily = FontFamily(family);
   1382            } else {
   1383              fontEntry = nullptr;
   1384              cantUseFallbackFont = true;
   1385            }
   1386          }
   1387        }
   1388      }
   1389 
   1390      // The macOS system font does not appear in the shared font list, so if
   1391      // we didn't find the fallback font above, we should also check for an
   1392      // unshared fontFamily in the system list.
   1393      if (!fontEntry) {
   1394        gfxFontFamily* family = FindSystemFontFamily(familyNameString);
   1395        if (family) {
   1396          fontEntry = family->FindFontForStyle(*aMatchStyle);
   1397          if (fontEntry) {
   1398            if (fontEntry->HasCharacter(aCh)) {
   1399              aMatchedFamily = FontFamily(family);
   1400            } else {
   1401              fontEntry = nullptr;
   1402              cantUseFallbackFont = true;
   1403            }
   1404          }
   1405        }
   1406      }
   1407    }
   1408  }
   1409 
   1410  if (cantUseFallbackFont) {
   1411    glean::fontlist::bad_fallback_font
   1412        .EnumGet(static_cast<glean::fontlist::BadFallbackFontLabel>(
   1413            cantUseFallbackFont))
   1414        .Add();
   1415  }
   1416 
   1417  CFRelease(str);
   1418 
   1419  return fontEntry;
   1420 }
   1421 
   1422 gfxFontEntry* CoreTextFontList::LookupLocalFont(
   1423    FontVisibilityProvider* aFontVisibilityProvider,
   1424    const nsACString& aFontName, WeightRange aWeightForEntry,
   1425    StretchRange aStretchForEntry, SlantStyleRange aStyleForEntry) {
   1426  if (aFontName.IsEmpty() || aFontName[0] == '.') {
   1427    return nullptr;
   1428  }
   1429 
   1430  AutoLock lock(mLock);
   1431 
   1432  CrashReporter::AutoRecordAnnotation autoFontName(
   1433      CrashReporter::Annotation::FontName, aFontName);
   1434 
   1435  AutoCFTypeRef<CFStringRef> faceName(CreateCFStringForString(aFontName));
   1436  if (!faceName) {
   1437    return nullptr;
   1438  }
   1439 
   1440  // lookup face based on postscript or full name
   1441  AutoCFTypeRef<CGFontRef> fontRef(CGFontCreateWithFontName(faceName));
   1442  if (!fontRef) {
   1443    return nullptr;
   1444  }
   1445 
   1446  // It's possible for CGFontCreateWithFontName to return a font that has been
   1447  // deactivated/uninstalled, or a font that is excluded from the font list due
   1448  // to CSS font-visibility restriction. So we need to check whether this font
   1449  // is allowed to be used.
   1450 
   1451  // CGFontRef doesn't offer a family-name API, so we go via a CTFontRef.
   1452  AutoCFTypeRef<CTFontRef> ctFont(
   1453      CTFontCreateWithGraphicsFont(fontRef, 0.0, nullptr, nullptr));
   1454  if (!ctFont) {
   1455    return nullptr;
   1456  }
   1457  AutoCFTypeRef<CFStringRef> name(CTFontCopyFamilyName(ctFont));
   1458  // Convert the family name to a key suitable for font-list lookup (8-bit,
   1459  // lowercased).
   1460  nsAutoCString key;
   1461  if (name) {
   1462    // CFStringGetLength is in UTF-16 code units. The maximum this count can
   1463    // expand when converted to UTF-8 is 3x. We add 1 to ensure there will also
   1464    // be space for null-termination of the resulting C string.
   1465    key.SetLength((CFStringGetLength(name) + 1) * 3);
   1466  }
   1467  if (!name || !CFStringGetCString(name, key.BeginWriting(), key.Length(),
   1468                                   kCFStringEncodingUTF8)) {
   1469    // This shouldn't ever happen, but if it does we just bail.
   1470    NS_WARNING("Failed to get family name?");
   1471    key.Truncate(0);
   1472  }
   1473  if (key.IsEmpty()) {
   1474    return nullptr;
   1475  }
   1476  // Reset our string length to match the actual C string we got, which will
   1477  // usually be much shorter than the maximal buffer we allocated.
   1478  key.Truncate(strlen(key.get()));
   1479  ToLowerCase(key);
   1480  // If the family can't be looked up, this font is not available for use.
   1481  FontFamily family = FindFamily(aFontVisibilityProvider, key);
   1482  if (family.IsNull()) {
   1483    return nullptr;
   1484  }
   1485 
   1486  return new CTFontEntry(aFontName, fontRef, aWeightForEntry, aStretchForEntry,
   1487                         aStyleForEntry, false, true);
   1488 }
   1489 
   1490 static void ReleaseData(void* info, const void* data, size_t size) {
   1491  free((void*)data);
   1492 }
   1493 
   1494 MOZ_DEFINE_MALLOC_SIZE_OF_ON_ALLOC(UserFontMallocSizeOfOnAlloc)
   1495 
   1496 gfxFontEntry* CoreTextFontList::MakePlatformFont(const nsACString& aFontName,
   1497                                                 WeightRange aWeightForEntry,
   1498                                                 StretchRange aStretchForEntry,
   1499                                                 SlantStyleRange aStyleForEntry,
   1500                                                 const uint8_t* aFontData,
   1501                                                 uint32_t aLength) {
   1502  NS_ASSERTION(aFontData, "MakePlatformFont called with null data");
   1503 
   1504  // create the font entry
   1505  nsAutoString uniqueName;
   1506 
   1507  nsresult rv = gfxFontUtils::MakeUniqueUserFontName(uniqueName);
   1508  if (NS_FAILED(rv)) {
   1509    return nullptr;
   1510  }
   1511 
   1512  CrashReporter::AutoRecordAnnotation autoFontName(
   1513      CrashReporter::Annotation::FontName, aFontName);
   1514 
   1515  AutoCFTypeRef<CGDataProviderRef> provider(::CGDataProviderCreateWithData(
   1516      nullptr, aFontData, aLength, &ReleaseData));
   1517  AutoCFTypeRef<CGFontRef> fontRef(::CGFontCreateWithDataProvider(provider));
   1518  if (!fontRef) {
   1519    return nullptr;
   1520  }
   1521 
   1522  auto newFontEntry = MakeUnique<CTFontEntry>(
   1523      NS_ConvertUTF16toUTF8(uniqueName), fontRef, aWeightForEntry,
   1524      aStretchForEntry, aStyleForEntry, true, false);
   1525 
   1526  // Record size for memory reporting purposes.
   1527  // The *OnAlloc function will also tell DMD about this block, as the
   1528  // OS font code may hold on to it for an extended period.
   1529  newFontEntry->mComputedSizeOfUserFont =
   1530      UserFontMallocSizeOfOnAlloc(aFontData);
   1531 
   1532  return newFontEntry.release();
   1533 }
   1534 
   1535 // Webkit code uses a system font meta name, so mimic that here
   1536 // WebCore/platform/graphics/mac/FontCacheMac.mm
   1537 static const char kSystemFont_system[] = "-apple-system";
   1538 
   1539 bool CoreTextFontList::FindAndAddFamiliesLocked(
   1540    FontVisibilityProvider* aFontVisibilityProvider,
   1541    StyleGenericFontFamily aGeneric, const nsACString& aFamily,
   1542    nsTArray<FamilyAndGeneric>* aOutput, FindFamiliesFlags aFlags,
   1543    gfxFontStyle* aStyle, nsAtom* aLanguage, gfxFloat aDevToCssSize) {
   1544  if (aFamily.EqualsLiteral(kSystemFont_system)) {
   1545    // Search for special system font name, -apple-system. This is not done via
   1546    // the shared fontlist because the hidden system font may not be included
   1547    // there; we create a separate gfxFontFamily to manage this family.
   1548    if (auto* fam = FindSystemFontFamily(mSystemFontFamilyName)) {
   1549      aOutput->AppendElement(fam);
   1550      return true;
   1551    }
   1552    return false;
   1553  }
   1554 
   1555  return gfxPlatformFontList::FindAndAddFamiliesLocked(
   1556      aFontVisibilityProvider, aGeneric, aFamily, aOutput, aFlags, aStyle,
   1557      aLanguage, aDevToCssSize);
   1558 }
   1559 
   1560 // used to load system-wide font info on off-main thread
   1561 class CTFontInfo final : public FontInfoData {
   1562 public:
   1563  CTFontInfo(bool aLoadOtherNames, bool aLoadFaceNames, bool aLoadCmaps,
   1564             RecursiveMutex& aLock)
   1565      : FontInfoData(aLoadOtherNames, aLoadFaceNames, aLoadCmaps),
   1566        mLock(aLock) {}
   1567 
   1568  virtual ~CTFontInfo() = default;
   1569 
   1570  virtual void Load() { FontInfoData::Load(); }
   1571 
   1572  // loads font data for all members of a given family
   1573  virtual void LoadFontFamilyData(const nsACString& aFamilyName);
   1574 
   1575  RecursiveMutex& mLock;
   1576 };
   1577 
   1578 void CTFontInfo::LoadFontFamilyData(const nsACString& aFamilyName) {
   1579  CrashReporter::AutoRecordAnnotation autoFontName(
   1580      CrashReporter::Annotation::FontName, aFamilyName);
   1581  // Prevent this from running concurrently with CGFont operations on the main
   1582  // thread, because the macOS font cache is fragile with concurrent access.
   1583  // This appears to be a vulnerability within CoreText in versions of macOS
   1584  // before macOS 13. In time, we can remove this lock.
   1585  RecursiveMutexAutoLock lock(mLock);
   1586 
   1587  // family name ==> CTFontDescriptor
   1588  AutoCFTypeRef<CFStringRef> family(CreateCFStringForString(aFamilyName));
   1589 
   1590  AutoCFTypeRef<CFMutableDictionaryRef> attr(
   1591      CFDictionaryCreateMutable(NULL, 0, &kCFTypeDictionaryKeyCallBacks,
   1592                                &kCFTypeDictionaryValueCallBacks));
   1593  CFDictionaryAddValue(attr, kCTFontFamilyNameAttribute, family);
   1594  AutoCFTypeRef<CTFontDescriptorRef> fd(
   1595      CTFontDescriptorCreateWithAttributes(attr));
   1596  AutoCFTypeRef<CFArrayRef> matchingFonts(
   1597      CTFontDescriptorCreateMatchingFontDescriptors(fd, NULL));
   1598  if (!matchingFonts) {
   1599    return;
   1600  }
   1601 
   1602  nsTArray<nsCString> otherFamilyNames;
   1603  bool hasOtherFamilyNames = true;
   1604 
   1605  // iterate over faces in the family
   1606  int f, numFaces = (int)CFArrayGetCount(matchingFonts);
   1607  CTFontDescriptorRef prevFace = nullptr;
   1608  for (f = 0; f < numFaces; f++) {
   1609    mLoadStats.fonts++;
   1610 
   1611    CTFontDescriptorRef faceDesc =
   1612        (CTFontDescriptorRef)CFArrayGetValueAtIndex(matchingFonts, f);
   1613    if (!faceDesc) {
   1614      continue;
   1615    }
   1616 
   1617    if (faceDesc == prevFace) {
   1618      continue;
   1619    }
   1620    prevFace = faceDesc;
   1621 
   1622    AutoCFTypeRef<CTFontRef> fontRef(
   1623        CTFontCreateWithFontDescriptor(faceDesc, 0.0, nullptr));
   1624    if (!fontRef) {
   1625      NS_WARNING("failed to create a CTFontRef");
   1626      continue;
   1627    }
   1628 
   1629    if (mLoadCmaps) {
   1630      // face name
   1631      AutoCFTypeRef<CFStringRef> faceName(
   1632          (CFStringRef)CTFontDescriptorCopyAttribute(faceDesc,
   1633                                                     kCTFontNameAttribute));
   1634 
   1635      AutoTArray<UniChar, 1024> buffer;
   1636      CFIndex len = CFStringGetLength(faceName);
   1637      buffer.SetLength(len + 1);
   1638      CFStringGetCharacters(faceName, CFRangeMake(0, len), buffer.Elements());
   1639      buffer[len] = 0;
   1640      NS_ConvertUTF16toUTF8 fontName(
   1641          reinterpret_cast<char16_t*>(buffer.Elements()), len);
   1642 
   1643      // load the cmap data
   1644      FontFaceData fontData;
   1645      AutoCFTypeRef<CFDataRef> cmapTable(CTFontCopyTable(
   1646          fontRef, kCTFontTableCmap, kCTFontTableOptionNoOptions));
   1647 
   1648      if (cmapTable) {
   1649        const uint8_t* cmapData = (const uint8_t*)CFDataGetBytePtr(cmapTable);
   1650        uint32_t cmapLen = CFDataGetLength(cmapTable);
   1651        RefPtr<gfxCharacterMap> charmap = new gfxCharacterMap(256);
   1652        uint32_t offset;
   1653        nsresult rv;
   1654 
   1655        rv = gfxFontUtils::ReadCMAP(cmapData, cmapLen, *charmap, offset);
   1656        if (NS_SUCCEEDED(rv)) {
   1657          fontData.mCharacterMap = charmap;
   1658          fontData.mUVSOffset = offset;
   1659          mLoadStats.cmaps++;
   1660        }
   1661      }
   1662 
   1663      mFontFaceData.InsertOrUpdate(fontName, fontData);
   1664    }
   1665 
   1666    if (mLoadOtherNames && hasOtherFamilyNames) {
   1667      AutoCFTypeRef<CFDataRef> nameTable(CTFontCopyTable(
   1668          fontRef, kCTFontTableName, kCTFontTableOptionNoOptions));
   1669 
   1670      if (nameTable) {
   1671        const char* nameData = (const char*)CFDataGetBytePtr(nameTable);
   1672        uint32_t nameLen = CFDataGetLength(nameTable);
   1673        gfxFontUtils::ReadOtherFamilyNamesForFace(
   1674            aFamilyName, nameData, nameLen, otherFamilyNames, false);
   1675        hasOtherFamilyNames = otherFamilyNames.Length() != 0;
   1676      }
   1677    }
   1678  }
   1679 
   1680  // if found other names, insert them in the hash table
   1681  if (otherFamilyNames.Length() != 0) {
   1682    mOtherFamilyNames.InsertOrUpdate(aFamilyName, otherFamilyNames);
   1683    mLoadStats.othernames += otherFamilyNames.Length();
   1684  }
   1685 }
   1686 
   1687 already_AddRefed<FontInfoData> CoreTextFontList::CreateFontInfoData() {
   1688  bool loadCmaps = !UsesSystemFallback() ||
   1689                   gfxPlatform::GetPlatform()->UseCmapsDuringSystemFallback();
   1690 
   1691  mLock.AssertCurrentThreadIn();
   1692  RefPtr<CTFontInfo> fi =
   1693      new CTFontInfo(true, NeedFullnamePostscriptNames(), loadCmaps, mLock);
   1694  return fi.forget();
   1695 }
   1696 
   1697 gfxFontFamily* CoreTextFontList::CreateFontFamily(
   1698    const nsACString& aName, FontVisibility aVisibility) const {
   1699  return new CTFontFamily(aName, aVisibility);
   1700 }
   1701 
   1702 gfxFontEntry* CoreTextFontList::CreateFontEntry(
   1703    fontlist::Face* aFace, const fontlist::Family* aFamily) {
   1704  CTFontEntry* fe = new CTFontEntry(
   1705      aFace->mDescriptor.AsString(SharedFontList()), aFace->mWeight, false,
   1706      0.0);  // XXX standardFace, sizeHint
   1707  fe->InitializeFrom(aFace, aFamily);
   1708  return fe;
   1709 }
   1710 
   1711 void CoreTextFontList::AddFaceInitData(
   1712    CTFontDescriptorRef aFontDesc, nsTArray<fontlist::Face::InitData>& aFaces,
   1713    bool aLoadCmaps) {
   1714  AutoCFTypeRef<CFStringRef> psname((CFStringRef)CTFontDescriptorCopyAttribute(
   1715      aFontDesc, kCTFontNameAttribute));
   1716  AutoCFTypeRef<CFStringRef> facename(
   1717      (CFStringRef)CTFontDescriptorCopyAttribute(aFontDesc,
   1718                                                 kCTFontStyleNameAttribute));
   1719  AutoCFTypeRef<CFDictionaryRef> traitsDict(
   1720      (CFDictionaryRef)CTFontDescriptorCopyAttribute(aFontDesc,
   1721                                                     kCTFontTraitsAttribute));
   1722 
   1723  CFNumberRef weight =
   1724      (CFNumberRef)CFDictionaryGetValue(traitsDict, kCTFontWeightTrait);
   1725  CFNumberRef width =
   1726      (CFNumberRef)CFDictionaryGetValue(traitsDict, kCTFontWidthTrait);
   1727  CFNumberRef symbolicTraits =
   1728      (CFNumberRef)CFDictionaryGetValue(traitsDict, kCTFontSymbolicTrait);
   1729 
   1730  // make a nsString
   1731  nsAutoString postscriptFontName;
   1732  GetStringForCFString(psname, postscriptFontName);
   1733 
   1734  int32_t cssWeight = PR_GetCurrentThread() == sInitFontListThread
   1735                          ? 0
   1736                          : GetWeightOverride(postscriptFontName);
   1737  if (cssWeight) {
   1738    // scale down and clamp, to get a value from 1..9
   1739    cssWeight = ((cssWeight + 50) / 100);
   1740    cssWeight = std::clamp(cssWeight, 1, 9);
   1741    cssWeight *= 100;  // scale up to CSS values
   1742  } else {
   1743    CGFloat weightValue;
   1744    CFNumberGetValue(weight, kCFNumberCGFloatType, &weightValue);
   1745    cssWeight = CoreTextWeightToCSSWeight(weightValue);
   1746  }
   1747 
   1748  CGFloat widthValue;
   1749  CFNumberGetValue(width, kCFNumberCGFloatType, &widthValue);
   1750  StretchRange stretch(CoreTextWidthToCSSStretch(widthValue));
   1751 
   1752  SlantStyleRange slantStyle(FontSlantStyle::NORMAL);
   1753  SInt32 traitsValue;
   1754  CFNumberGetValue(symbolicTraits, kCFNumberSInt32Type, &traitsValue);
   1755  if (traitsValue & kCTFontItalicTrait) {
   1756    slantStyle = SlantStyleRange(FontSlantStyle::ITALIC);
   1757  }
   1758 
   1759  bool fixedPitch = traitsValue & kCTFontMonoSpaceTrait;
   1760 
   1761  RefPtr<gfxCharacterMap> charmap;
   1762  if (aLoadCmaps) {
   1763    AutoCFTypeRef<CGFontRef> font(
   1764        CGFontCreateWithFontName(CFStringRef(psname)));
   1765    if (font) {
   1766      uint32_t kCMAP = TRUETYPE_TAG('c', 'm', 'a', 'p');
   1767      AutoCFTypeRef<CFDataRef> data(CGFontCopyTableForTag(font, kCMAP));
   1768      if (data) {
   1769        uint32_t offset;
   1770        charmap = new gfxCharacterMap(256);
   1771        gfxFontUtils::ReadCMAP(CFDataGetBytePtr(data), CFDataGetLength(data),
   1772                               *charmap, offset);
   1773      }
   1774    }
   1775  }
   1776 
   1777  // Ensure that a face named "Regular" goes to the front of the list, so it
   1778  // will take precedence over other faces with the same style attributes but
   1779  // a different name (such as "Outline").
   1780  auto data = fontlist::Face::InitData{
   1781      NS_ConvertUTF16toUTF8(postscriptFontName),
   1782      0,
   1783      fixedPitch,
   1784      WeightRange(FontWeight::FromInt(cssWeight)),
   1785      stretch,
   1786      slantStyle,
   1787      charmap,
   1788  };
   1789  if (kCFCompareEqualTo == CFStringCompare(facename, CFSTR("Regular"), 0)) {
   1790    aFaces.InsertElementAt(0, std::move(data));
   1791  } else {
   1792    aFaces.AppendElement(std::move(data));
   1793  }
   1794 }
   1795 
   1796 void CoreTextFontList::GetFacesInitDataForFamily(
   1797    const fontlist::Family* aFamily, nsTArray<fontlist::Face::InitData>& aFaces,
   1798    bool aLoadCmaps) const {
   1799  auto name = aFamily->Key().AsString(SharedFontList());
   1800  CrashReporter::AutoRecordAnnotation autoFontName(
   1801      CrashReporter::Annotation::FontName, name);
   1802 
   1803  struct Context {
   1804    nsTArray<fontlist::Face::InitData>& mFaces;
   1805    bool mLoadCmaps;
   1806    const void* prevValue = nullptr;
   1807  };
   1808  auto addFaceFunc = [](const void* aValue, void* aContext) -> void {
   1809    Context* context = (Context*)aContext;
   1810    if (aValue == context->prevValue) {
   1811      return;
   1812    }
   1813    context->prevValue = aValue;
   1814    CTFontDescriptorRef fontDesc = (CTFontDescriptorRef)aValue;
   1815    CoreTextFontList::AddFaceInitData(fontDesc, context->mFaces,
   1816                                      context->mLoadCmaps);
   1817  };
   1818 
   1819  AutoCFTypeRef<CTFontDescriptorRef> descriptor(
   1820      CreateDescriptorForFamily(name, false));
   1821  AutoCFTypeRef<CFArrayRef> faces(
   1822      CTFontDescriptorCreateMatchingFontDescriptors(descriptor, nullptr));
   1823 
   1824  if (faces) {
   1825    Context context{aFaces, aLoadCmaps};
   1826    CFArrayApplyFunction(faces, CFRangeMake(0, CFArrayGetCount(faces)),
   1827                         addFaceFunc, &context);
   1828  }
   1829 }
   1830 
   1831 void CoreTextFontList::ReadFaceNamesForFamily(
   1832    fontlist::Family* aFamily, bool aNeedFullnamePostscriptNames) {
   1833  if (!aFamily->IsInitialized()) {
   1834    if (!InitializeFamily(aFamily)) {
   1835      return;
   1836    }
   1837  }
   1838  const uint32_t kNAME = TRUETYPE_TAG('n', 'a', 'm', 'e');
   1839  fontlist::FontList* list = SharedFontList();
   1840  nsAutoCString canonicalName(aFamily->DisplayName().AsString(list));
   1841  const auto* facePtrs = aFamily->Faces(list);
   1842  for (uint32_t i = 0, n = aFamily->NumFaces(); i < n; i++) {
   1843    auto* face = facePtrs[i].ToPtr<const fontlist::Face>(list);
   1844    if (!face) {
   1845      continue;
   1846    }
   1847    nsAutoCString name(face->mDescriptor.AsString(list));
   1848    // We create a temporary CTFontEntry just to read family names from the
   1849    // 'name' table in the font resource. The style attributes here are ignored
   1850    // as this entry is not used for font style matching.
   1851    // The size hint might be used to select which face is accessed in the case
   1852    // of the macOS UI font; see CTFontEntry::GetFontRef(). We pass 16.0 in
   1853    // order to get a standard text-size face in this case, although it's
   1854    // unlikely to matter for the purpose of just reading family names.
   1855    auto fe = MakeUnique<CTFontEntry>(name, WeightRange(FontWeight::NORMAL),
   1856                                      false, 16.0);
   1857    if (!fe) {
   1858      continue;
   1859    }
   1860    gfxFontEntry::AutoTable nameTable(fe.get(), kNAME);
   1861    if (!nameTable) {
   1862      continue;
   1863    }
   1864    uint32_t dataLength;
   1865    const char* nameData = hb_blob_get_data(nameTable, &dataLength);
   1866    AutoTArray<nsCString, 4> otherFamilyNames;
   1867    gfxFontUtils::ReadOtherFamilyNamesForFace(
   1868        canonicalName, nameData, dataLength, otherFamilyNames, false);
   1869    for (const auto& alias : otherFamilyNames) {
   1870      nsAutoCString key;
   1871      GenerateFontListKey(alias, key);
   1872      auto aliasData = mAliasTable.GetOrInsertNew(key);
   1873      aliasData->InitFromFamily(aFamily, canonicalName);
   1874      aliasData->mFaces.AppendElement(facePtrs[i]);
   1875    }
   1876  }
   1877 }
   1878 
   1879 static CFStringRef CopyRealFamilyName(CTFontRef aFont) {
   1880  AutoCFTypeRef<CFStringRef> psName(CTFontCopyPostScriptName(aFont));
   1881  AutoCFTypeRef<CGFontRef> cgFont(
   1882      CGFontCreateWithFontName(CFStringRef(psName)));
   1883  if (!cgFont) {
   1884    return CTFontCopyFamilyName(aFont);
   1885  }
   1886  AutoCFTypeRef<CTFontRef> ctFont(
   1887      CTFontCreateWithGraphicsFont(cgFont, 0.0, nullptr, nullptr));
   1888  if (!ctFont) {
   1889    return CTFontCopyFamilyName(aFont);
   1890  }
   1891  return CTFontCopyFamilyName(ctFont);
   1892 }
   1893 
   1894 void CoreTextFontList::InitSystemFontNames() {
   1895  // text font family
   1896  AutoCFTypeRef<CTFontRef> font(CTFontCreateUIFontForLanguage(
   1897      kCTFontUIFontSystem, 0.0, nullptr));  // TODO: language
   1898  AutoCFTypeRef<CFStringRef> name(CopyRealFamilyName(font));
   1899 
   1900  nsAutoString familyName;
   1901  GetStringForCFString(name, familyName);
   1902  CopyUTF16toUTF8(familyName, mSystemFontFamilyName);
   1903 
   1904  // We store an in-process gfxFontFamily for the system font even if using the
   1905  // shared fontlist to manage "normal" fonts, because the hidden system fonts
   1906  // may be excluded from the font list altogether. This family will be
   1907  // populated based on the given NSFont.
   1908  RefPtr<gfxFontFamily> fam = new CTFontFamily(mSystemFontFamilyName, font);
   1909  if (fam) {
   1910    nsAutoCString key;
   1911    GenerateFontListKey(mSystemFontFamilyName, key);
   1912    mFontFamilies.InsertOrUpdate(key, std::move(fam));
   1913  }
   1914 }
   1915 
   1916 FontFamily CoreTextFontList::GetDefaultFontForPlatform(
   1917    FontVisibilityProvider* aFontVisibilityProvider, const gfxFontStyle* aStyle,
   1918    nsAtom* aLanguage) {
   1919  AutoCFTypeRef<CTFontRef> font(CTFontCreateUIFontForLanguage(
   1920      kCTFontUIFontUser, 0.0, nullptr));  // TODO: language
   1921  AutoCFTypeRef<CFStringRef> name(CTFontCopyFamilyName(font));
   1922 
   1923  nsAutoString familyName;
   1924  GetStringForCFString(name, familyName);
   1925 
   1926  return FindFamily(aFontVisibilityProvider, NS_ConvertUTF16toUTF8(familyName));
   1927 }
   1928 
   1929 #ifdef MOZ_BUNDLED_FONTS
   1930 void CoreTextFontList::ActivateBundledFonts() {
   1931  nsCOMPtr<nsIFile> localDir;
   1932  if (NS_FAILED(NS_GetSpecialDirectory(NS_GRE_DIR, getter_AddRefs(localDir)))) {
   1933    return;
   1934  }
   1935  if (NS_FAILED(localDir->Append(u"fonts"_ns))) {
   1936    return;
   1937  }
   1938  nsAutoCString path;
   1939  if (NS_FAILED(localDir->GetNativePath(path))) {
   1940    return;
   1941  }
   1942  ActivateFontsFromDir(path, &mBundledFamilies);
   1943 }
   1944 #endif