Bug 1843044 - Make the default theme work with dark color schemes. r=dao,pbz
[gecko.git] / gfx / thebes / CoreTextFontList.cpp
blob2e7a4de1e3d1875c4e0dea86b1da9bb755faef18
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/. */
6 #include "AppleUtils.h"
7 #include "CoreTextFontList.h"
8 #include "gfxFontConstants.h"
9 #include "gfxMacFont.h"
10 #include "gfxUserFontSet.h"
12 #include "harfbuzz/hb.h"
14 #include "MainThreadUtils.h"
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/Telemetry.h"
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"
35 using namespace mozilla;
36 using namespace mozilla::gfx;
38 // List generated by diffing the arrays returned by
39 // CTFontManagerCopyAvailableFontFamilyNames() when built with
40 // MACOSX_DEPLOYMENT_TARGET=10.12 vs 11.0, to identify the font family names
41 // that Core Text is treating as "deprecated" and hiding from the app on newer
42 // systems.
43 constexpr nsLiteralCString kDeprecatedFontFamilies[] = {
44 // Dot-prefixed font families are supposed to be hidden from the
45 // user-visible
46 // font list anyhow, so we don't need to add them here.
47 // ".Al Bayan PUA"_ns,
48 // ".Al Nile PUA"_ns,
49 // ".Al Tarikh PUA"_ns,
50 // ".Apple Color Emoji UI"_ns,
51 // ".Apple SD Gothic NeoI"_ns,
52 // ".Aqua Kana"_ns,
53 // ".Arial Hebrew Desk Interface"_ns,
54 // ".Baghdad PUA"_ns,
55 // ".Beirut PUA"_ns,
56 // ".Damascus PUA"_ns,
57 // ".DecoType Naskh PUA"_ns,
58 // ".Diwan Kufi PUA"_ns,
59 // ".Farah PUA"_ns,
60 // ".Geeza Pro Interface"_ns,
61 // ".Geeza Pro PUA"_ns,
62 // ".Helvetica LT MM"_ns,
63 // ".Hiragino Kaku Gothic Interface"_ns,
64 // ".Hiragino Sans GB Interface"_ns,
65 // ".Keyboard"_ns,
66 // ".KufiStandardGK PUA"_ns,
67 // ".LastResort"_ns,
68 // ".Lucida Grande UI"_ns,
69 // ".Muna PUA"_ns,
70 // ".Nadeem PUA"_ns,
71 // ".New York"_ns,
72 // ".Noto Nastaliq Urdu UI"_ns,
73 // ".PingFang HK"_ns,
74 // ".PingFang SC"_ns,
75 // ".PingFang TC"_ns,
76 // ".Sana PUA"_ns,
77 // ".Savoye LET CC."_ns,
78 // ".SF Arabic"_ns,
79 // ".SF Compact Rounded"_ns,
80 // ".SF Compact"_ns,
81 // ".SF NS Mono"_ns,
82 // ".SF NS Rounded"_ns,
83 // ".SF NS"_ns,
84 // ".Times LT MM"_ns,
85 "Hiragino Kaku Gothic Pro"_ns,
86 "Hiragino Kaku Gothic ProN"_ns,
87 "Hiragino Kaku Gothic Std"_ns,
88 "Hiragino Kaku Gothic StdN"_ns,
89 "Hiragino Maru Gothic Pro"_ns,
90 "Hiragino Mincho Pro"_ns,
91 "Iowan Old Style"_ns,
92 "Noto Sans Adlam"_ns,
93 "Noto Sans Armenian"_ns,
94 "Noto Sans Avestan"_ns,
95 "Noto Sans Bamum"_ns,
96 "Noto Sans Bassa Vah"_ns,
97 "Noto Sans Batak"_ns,
98 "Noto Sans Bhaiksuki"_ns,
99 "Noto Sans Brahmi"_ns,
100 "Noto Sans Buginese"_ns,
101 "Noto Sans Buhid"_ns,
102 "Noto Sans Carian"_ns,
103 "Noto Sans Caucasian Albanian"_ns,
104 "Noto Sans Chakma"_ns,
105 "Noto Sans Cham"_ns,
106 "Noto Sans Coptic"_ns,
107 "Noto Sans Cuneiform"_ns,
108 "Noto Sans Cypriot"_ns,
109 "Noto Sans Duployan"_ns,
110 "Noto Sans Egyptian Hieroglyphs"_ns,
111 "Noto Sans Elbasan"_ns,
112 "Noto Sans Glagolitic"_ns,
113 "Noto Sans Gothic"_ns,
114 "Noto Sans Gunjala Gondi"_ns,
115 "Noto Sans Hanifi Rohingya"_ns,
116 "Noto Sans Hanunoo"_ns,
117 "Noto Sans Hatran"_ns,
118 "Noto Sans Imperial Aramaic"_ns,
119 "Noto Sans Inscriptional Pahlavi"_ns,
120 "Noto Sans Inscriptional Parthian"_ns,
121 "Noto Sans Javanese"_ns,
122 "Noto Sans Kaithi"_ns,
123 "Noto Sans Kayah Li"_ns,
124 "Noto Sans Kharoshthi"_ns,
125 "Noto Sans Khojki"_ns,
126 "Noto Sans Khudawadi"_ns,
127 "Noto Sans Lepcha"_ns,
128 "Noto Sans Limbu"_ns,
129 "Noto Sans Linear A"_ns,
130 "Noto Sans Linear B"_ns,
131 "Noto Sans Lisu"_ns,
132 "Noto Sans Lycian"_ns,
133 "Noto Sans Lydian"_ns,
134 "Noto Sans Mahajani"_ns,
135 "Noto Sans Mandaic"_ns,
136 "Noto Sans Manichaean"_ns,
137 "Noto Sans Marchen"_ns,
138 "Noto Sans Masaram Gondi"_ns,
139 "Noto Sans Meetei Mayek"_ns,
140 "Noto Sans Mende Kikakui"_ns,
141 "Noto Sans Meroitic"_ns,
142 "Noto Sans Miao"_ns,
143 "Noto Sans Modi"_ns,
144 "Noto Sans Mongolian"_ns,
145 "Noto Sans Mro"_ns,
146 "Noto Sans Multani"_ns,
147 "Noto Sans Nabataean"_ns,
148 "Noto Sans New Tai Lue"_ns,
149 "Noto Sans Newa"_ns,
150 "Noto Sans NKo"_ns,
151 "Noto Sans Ol Chiki"_ns,
152 "Noto Sans Old Hungarian"_ns,
153 "Noto Sans Old Italic"_ns,
154 "Noto Sans Old North Arabian"_ns,
155 "Noto Sans Old Permic"_ns,
156 "Noto Sans Old Persian"_ns,
157 "Noto Sans Old South Arabian"_ns,
158 "Noto Sans Old Turkic"_ns,
159 "Noto Sans Osage"_ns,
160 "Noto Sans Osmanya"_ns,
161 "Noto Sans Pahawh Hmong"_ns,
162 "Noto Sans Palmyrene"_ns,
163 "Noto Sans Pau Cin Hau"_ns,
164 "Noto Sans PhagsPa"_ns,
165 "Noto Sans Phoenician"_ns,
166 "Noto Sans Psalter Pahlavi"_ns,
167 "Noto Sans Rejang"_ns,
168 "Noto Sans Samaritan"_ns,
169 "Noto Sans Saurashtra"_ns,
170 "Noto Sans Sharada"_ns,
171 "Noto Sans Siddham"_ns,
172 "Noto Sans Sora Sompeng"_ns,
173 "Noto Sans Sundanese"_ns,
174 "Noto Sans Syloti Nagri"_ns,
175 "Noto Sans Syriac"_ns,
176 "Noto Sans Tagalog"_ns,
177 "Noto Sans Tagbanwa"_ns,
178 "Noto Sans Tai Le"_ns,
179 "Noto Sans Tai Tham"_ns,
180 "Noto Sans Tai Viet"_ns,
181 "Noto Sans Takri"_ns,
182 "Noto Sans Thaana"_ns,
183 "Noto Sans Tifinagh"_ns,
184 "Noto Sans Tirhuta"_ns,
185 "Noto Sans Ugaritic"_ns,
186 "Noto Sans Vai"_ns,
187 "Noto Sans Wancho"_ns,
188 "Noto Sans Warang Citi"_ns,
189 "Noto Sans Yi"_ns,
190 "Noto Sans Zawgyi"_ns,
191 "Noto Serif Ahom"_ns,
192 "Noto Serif Balinese"_ns,
193 "Noto Serif Yezidi"_ns,
194 "Athelas"_ns,
195 "Courier"_ns,
196 "Marion"_ns,
197 "Seravek"_ns,
198 "Superclarendon"_ns,
199 "Times"_ns,
202 static void GetStringForCFString(CFStringRef aSrc, nsAString& aDest) {
203 auto len = CFStringGetLength(aSrc);
204 aDest.SetLength(len);
205 CFStringGetCharacters(aSrc, CFRangeMake(0, len),
206 (UniChar*)aDest.BeginWriting());
209 static CFStringRef CreateCFStringForString(const nsACString& aSrc) {
210 return CFStringCreateWithBytes(kCFAllocatorDefault,
211 (const UInt8*)aSrc.BeginReading(),
212 aSrc.Length(), kCFStringEncodingUTF8, false);
215 #define LOG_FONTLIST(args) \
216 MOZ_LOG(gfxPlatform::GetLog(eGfxLog_fontlist), mozilla::LogLevel::Debug, args)
217 #define LOG_FONTLIST_ENABLED() \
218 MOZ_LOG_TEST(gfxPlatform::GetLog(eGfxLog_fontlist), mozilla::LogLevel::Debug)
219 #define LOG_CMAPDATA_ENABLED() \
220 MOZ_LOG_TEST(gfxPlatform::GetLog(eGfxLog_cmapdata), mozilla::LogLevel::Debug)
222 #pragma mark -
224 // Complex scripts will not render correctly unless appropriate AAT or OT
225 // layout tables are present.
226 // For OpenType, we also check that the GSUB table supports the relevant
227 // script tag, to avoid using things like Arial Unicode MS for Lao (it has
228 // the characters, but lacks OpenType support).
230 // TODO: consider whether we should move this to gfxFontEntry and do similar
231 // cmap-masking on other platforms to avoid using fonts that won't shape
232 // properly.
234 nsresult CTFontEntry::ReadCMAP(FontInfoData* aFontInfoData) {
235 // attempt this once, if errors occur leave a blank cmap
236 if (mCharacterMap || mShmemCharacterMap) {
237 return NS_OK;
240 RefPtr<gfxCharacterMap> charmap;
241 nsresult rv;
243 uint32_t uvsOffset = 0;
244 if (aFontInfoData &&
245 (charmap = GetCMAPFromFontInfo(aFontInfoData, uvsOffset))) {
246 rv = NS_OK;
247 } else {
248 uint32_t kCMAP = TRUETYPE_TAG('c', 'm', 'a', 'p');
249 charmap = new gfxCharacterMap();
250 AutoTable cmapTable(this, kCMAP);
252 if (cmapTable) {
253 uint32_t cmapLen;
254 const uint8_t* cmapData = reinterpret_cast<const uint8_t*>(
255 hb_blob_get_data(cmapTable, &cmapLen));
256 rv = gfxFontUtils::ReadCMAP(cmapData, cmapLen, *charmap, uvsOffset);
257 } else {
258 rv = NS_ERROR_NOT_AVAILABLE;
261 mUVSOffset.exchange(uvsOffset);
263 if (NS_SUCCEEDED(rv) && !mIsDataUserFont && !HasGraphiteTables()) {
264 // For downloadable fonts, trust the author and don't
265 // try to munge the cmap based on script shaping support.
267 // We also assume a Graphite font knows what it's doing,
268 // and provides whatever shaping is needed for the
269 // characters it supports, so only check/clear the
270 // complex-script ranges for non-Graphite fonts
272 // for layout support, check for the presence of mort/morx/kerx and/or
273 // opentype layout tables
274 bool hasAATLayout = HasFontTable(TRUETYPE_TAG('m', 'o', 'r', 'x')) ||
275 HasFontTable(TRUETYPE_TAG('m', 'o', 'r', 't'));
276 bool hasAppleKerning = HasFontTable(TRUETYPE_TAG('k', 'e', 'r', 'x'));
277 bool hasGSUB = HasFontTable(TRUETYPE_TAG('G', 'S', 'U', 'B'));
278 bool hasGPOS = HasFontTable(TRUETYPE_TAG('G', 'P', 'O', 'S'));
279 if ((hasAATLayout && !(hasGSUB || hasGPOS)) || hasAppleKerning) {
280 mRequiresAAT = true; // prefer CoreText if font has no OTL tables,
281 // or if it uses the Apple-specific 'kerx'
282 // variant of kerning table
285 for (const ScriptRange* sr = gfxPlatformFontList::sComplexScriptRanges;
286 sr->rangeStart; sr++) {
287 // check to see if the cmap includes complex script codepoints
288 if (charmap->TestRange(sr->rangeStart, sr->rangeEnd)) {
289 if (hasAATLayout) {
290 // prefer CoreText for Apple's complex-script fonts,
291 // even if they also have some OpenType tables
292 // (e.g. Geeza Pro Bold on 10.6; see bug 614903)
293 mRequiresAAT = true;
294 // and don't mask off complex-script ranges, we assume
295 // the AAT tables will provide the necessary shaping
296 continue;
299 // We check for GSUB here, as GPOS alone would not be ok.
300 if (hasGSUB && SupportsScriptInGSUB(sr->tags, sr->numTags)) {
301 continue;
304 charmap->ClearRange(sr->rangeStart, sr->rangeEnd);
308 // Bug 1360309, 1393624: several of Apple's Chinese fonts have spurious
309 // blank glyphs for obscure Tibetan and Arabic-script codepoints.
310 // Blocklist these so that font fallback will not use them.
311 if (mRequiresAAT &&
312 (FamilyName().EqualsLiteral("Songti SC") ||
313 FamilyName().EqualsLiteral("Songti TC") ||
314 FamilyName().EqualsLiteral("STSong") ||
315 // Bug 1390980: on 10.11, the Kaiti fonts are also affected.
316 FamilyName().EqualsLiteral("Kaiti SC") ||
317 FamilyName().EqualsLiteral("Kaiti TC") ||
318 FamilyName().EqualsLiteral("STKaiti"))) {
319 charmap->ClearRange(0x0f6b, 0x0f70);
320 charmap->ClearRange(0x0f8c, 0x0f8f);
321 charmap->clear(0x0f98);
322 charmap->clear(0x0fbd);
323 charmap->ClearRange(0x0fcd, 0x0fff);
324 charmap->clear(0x0620);
325 charmap->clear(0x065f);
326 charmap->ClearRange(0x06ee, 0x06ef);
327 charmap->clear(0x06ff);
331 bool setCharMap = true;
332 if (NS_SUCCEEDED(rv)) {
333 gfxPlatformFontList* pfl = gfxPlatformFontList::PlatformFontList();
334 fontlist::FontList* sharedFontList = pfl->SharedFontList();
335 if (!IsUserFont() && mShmemFace) {
336 mShmemFace->SetCharacterMap(sharedFontList, charmap); // async
337 if (TrySetShmemCharacterMap()) {
338 setCharMap = false;
340 } else {
341 charmap = pfl->FindCharMap(charmap);
343 mHasCmapTable = true;
344 } else {
345 // if error occurred, initialize to null cmap
346 charmap = new gfxCharacterMap();
347 mHasCmapTable = false;
349 if (setCharMap) {
350 // Temporarily retain charmap, until the shared version is
351 // ready for use.
352 if (mCharacterMap.compareExchange(nullptr, charmap.get())) {
353 charmap.get()->AddRef();
357 LOG_FONTLIST(("(fontlist-cmap) name: %s, size: %zu hash: %8.8x%s\n",
358 mName.get(), charmap->SizeOfIncludingThis(moz_malloc_size_of),
359 charmap->mHash, mCharacterMap == charmap ? " new" : ""));
360 if (LOG_CMAPDATA_ENABLED()) {
361 char prefix[256];
362 SprintfLiteral(prefix, "(cmapdata) name: %.220s", mName.get());
363 charmap->Dump(prefix, eGfxLog_cmapdata);
366 return rv;
369 gfxFont* CTFontEntry::CreateFontInstance(const gfxFontStyle* aFontStyle) {
370 RefPtr<UnscaledFontMac> unscaledFont(mUnscaledFont);
371 if (!unscaledFont) {
372 CGFontRef baseFont = GetFontRef();
373 if (!baseFont) {
374 return nullptr;
376 unscaledFont = new UnscaledFontMac(baseFont, mIsDataUserFont);
377 mUnscaledFont = unscaledFont;
380 return new gfxMacFont(unscaledFont, this, aFontStyle);
383 bool CTFontEntry::HasVariations() {
384 if (!mHasVariationsInitialized) {
385 mHasVariationsInitialized = true;
386 mHasVariations = gfxPlatform::HasVariationFontSupport() &&
387 HasFontTable(TRUETYPE_TAG('f', 'v', 'a', 'r'));
390 return mHasVariations;
393 void CTFontEntry::GetVariationAxes(
394 nsTArray<gfxFontVariationAxis>& aVariationAxes) {
395 // We could do this by creating a CTFont and calling CTFontCopyVariationAxes,
396 // but it is expensive to instantiate a CTFont for every face just to set up
397 // the axis information.
398 // Instead we use gfxFontUtils to read the font tables directly.
399 gfxFontUtils::GetVariationData(this, &aVariationAxes, nullptr);
402 void CTFontEntry::GetVariationInstances(
403 nsTArray<gfxFontVariationInstance>& aInstances) {
404 // Core Text doesn't offer API for this, so we use gfxFontUtils to read the
405 // font tables directly.
406 gfxFontUtils::GetVariationData(this, nullptr, &aInstances);
409 bool CTFontEntry::IsCFF() {
410 if (!mIsCFFInitialized) {
411 mIsCFFInitialized = true;
412 mIsCFF = HasFontTable(TRUETYPE_TAG('C', 'F', 'F', ' '));
415 return mIsCFF;
418 CTFontEntry::CTFontEntry(const nsACString& aPostscriptName, WeightRange aWeight,
419 bool aIsStandardFace, double aSizeHint)
420 : gfxFontEntry(aPostscriptName, aIsStandardFace),
421 mFontRef(NULL),
422 mSizeHint(aSizeHint),
423 mFontRefInitialized(false),
424 mRequiresAAT(false),
425 mIsCFF(false),
426 mIsCFFInitialized(false),
427 mHasVariations(false),
428 mHasVariationsInitialized(false),
429 mHasAATSmallCaps(false),
430 mHasAATSmallCapsInitialized(false) {
431 mWeightRange = aWeight;
432 mOpszAxis.mTag = 0;
435 CTFontEntry::CTFontEntry(const nsACString& aPostscriptName, CGFontRef aFontRef,
436 WeightRange aWeight, StretchRange aStretch,
437 SlantStyleRange aStyle, bool aIsDataUserFont,
438 bool aIsLocalUserFont)
439 : gfxFontEntry(aPostscriptName, false),
440 mFontRef(NULL),
441 mSizeHint(0.0),
442 mFontRefInitialized(false),
443 mRequiresAAT(false),
444 mIsCFF(false),
445 mIsCFFInitialized(false),
446 mHasVariations(false),
447 mHasVariationsInitialized(false),
448 mHasAATSmallCaps(false),
449 mHasAATSmallCapsInitialized(false) {
450 mFontRef = aFontRef;
451 mFontRefInitialized = true;
452 CFRetain(mFontRef);
454 mWeightRange = aWeight;
455 mStretchRange = aStretch;
456 mFixedPitch = false; // xxx - do we need this for downloaded fonts?
457 mStyleRange = aStyle;
458 mOpszAxis.mTag = 0;
460 NS_ASSERTION(!(aIsDataUserFont && aIsLocalUserFont),
461 "userfont is either a data font or a local font");
462 mIsDataUserFont = aIsDataUserFont;
463 mIsLocalUserFont = aIsLocalUserFont;
466 gfxFontEntry* CTFontEntry::Clone() const {
467 MOZ_ASSERT(!IsUserFont(), "we can only clone installed fonts!");
468 CTFontEntry* fe = new CTFontEntry(Name(), Weight(), mStandardFace, mSizeHint);
469 fe->mStyleRange = mStyleRange;
470 fe->mStretchRange = mStretchRange;
471 fe->mFixedPitch = mFixedPitch;
472 return fe;
475 CGFontRef CTFontEntry::GetFontRef() {
476 if (!mFontRefInitialized) {
477 // Cache the CGFontRef, to be released by our destructor.
478 mFontRef = CreateOrCopyFontRef();
479 mFontRefInitialized = true;
481 // Return a non-retained reference; caller does not need to release.
482 return mFontRef;
485 CGFontRef CTFontEntry::CreateOrCopyFontRef() {
486 if (mFontRef) {
487 // We have a cached CGFont, just add a reference. Caller must
488 // release, but we'll still own our reference.
489 ::CGFontRetain(mFontRef);
490 return mFontRef;
493 CrashReporter::AutoAnnotateCrashReport autoFontName(
494 CrashReporter::Annotation::FontName, mName);
496 // Create a new CGFont; caller will own the only reference to it.
497 AutoCFRelease<CFStringRef> psname = CreateCFStringForString(mName);
498 if (!psname) {
499 return nullptr;
502 CGFontRef ref = CGFontCreateWithFontName(psname);
503 return ref; // Not saved in mFontRef; caller will own the reference
506 // For a logging build, we wrap the CFDataRef in a FontTableRec so that we can
507 // use the MOZ_COUNT_[CD]TOR macros in it. A release build without logging
508 // does not get this overhead.
509 class FontTableRec {
510 public:
511 explicit FontTableRec(CFDataRef aDataRef) : mDataRef(aDataRef) {
512 MOZ_COUNT_CTOR(FontTableRec);
515 ~FontTableRec() {
516 MOZ_COUNT_DTOR(FontTableRec);
517 CFRelease(mDataRef);
520 private:
521 CFDataRef mDataRef;
524 /*static*/ void CTFontEntry::DestroyBlobFunc(void* aUserData) {
525 #ifdef NS_BUILD_REFCNT_LOGGING
526 FontTableRec* ftr = static_cast<FontTableRec*>(aUserData);
527 delete ftr;
528 #else
529 CFRelease((CFDataRef)aUserData);
530 #endif
533 hb_blob_t* CTFontEntry::GetFontTable(uint32_t aTag) {
534 AutoCFRelease<CGFontRef> fontRef = CreateOrCopyFontRef();
535 if (!fontRef) {
536 return nullptr;
539 CFDataRef dataRef = ::CGFontCopyTableForTag(fontRef, aTag);
540 if (dataRef) {
541 return hb_blob_create((const char*)CFDataGetBytePtr(dataRef),
542 CFDataGetLength(dataRef), HB_MEMORY_MODE_READONLY,
543 #ifdef NS_BUILD_REFCNT_LOGGING
544 new FontTableRec(dataRef),
545 #else
546 (void*)dataRef,
547 #endif
548 DestroyBlobFunc);
551 return nullptr;
554 bool CTFontEntry::HasFontTable(uint32_t aTableTag) {
555 if (mAvailableTables.Count() == 0) {
556 AutoCFRelease<CGFontRef> fontRef = CreateOrCopyFontRef();
557 if (!fontRef) {
558 return false;
560 AutoCFRelease<CFArrayRef> tags = ::CGFontCopyTableTags(fontRef);
561 if (!tags) {
562 return false;
564 int numTags = (int)CFArrayGetCount(tags);
565 for (int t = 0; t < numTags; t++) {
566 uint32_t tag = (uint32_t)(uintptr_t)CFArrayGetValueAtIndex(tags, t);
567 mAvailableTables.PutEntry(tag);
571 return mAvailableTables.GetEntry(aTableTag);
574 static bool CheckForAATSmallCaps(CFArrayRef aFeatures) {
575 // Walk the array of feature descriptors from the font, and see whether
576 // a small-caps feature setting is available.
577 // Just bail out (returning false) if at any point we fail to find the
578 // expected dictionary keys, etc; if the font has bad data, we don't even
579 // try to search the rest of it.
580 auto numFeatures = CFArrayGetCount(aFeatures);
581 for (auto f = 0; f < numFeatures; ++f) {
582 auto featureDict = (CFDictionaryRef)CFArrayGetValueAtIndex(aFeatures, f);
583 if (!featureDict) {
584 return false;
586 auto featureNum = (CFNumberRef)CFDictionaryGetValue(
587 featureDict, CFSTR("CTFeatureTypeIdentifier"));
588 if (!featureNum) {
589 return false;
591 int16_t featureType;
592 if (!CFNumberGetValue(featureNum, kCFNumberSInt16Type, &featureType)) {
593 return false;
595 if (featureType == kLetterCaseType || featureType == kLowerCaseType) {
596 // Which selector to look for, depending whether we've found the
597 // legacy LetterCase feature or the new LowerCase one.
598 const uint16_t smallCaps = (featureType == kLetterCaseType)
599 ? kSmallCapsSelector
600 : kLowerCaseSmallCapsSelector;
601 auto selectors = (CFArrayRef)CFDictionaryGetValue(
602 featureDict, CFSTR("CTFeatureTypeSelectors"));
603 if (!selectors) {
604 return false;
606 auto numSelectors = CFArrayGetCount(selectors);
607 for (auto s = 0; s < numSelectors; s++) {
608 auto selectorDict =
609 (CFDictionaryRef)CFArrayGetValueAtIndex(selectors, s);
610 if (!selectorDict) {
611 return false;
613 auto selectorNum = (CFNumberRef)CFDictionaryGetValue(
614 selectorDict, CFSTR("CTFeatureSelectorIdentifier"));
615 if (!selectorNum) {
616 return false;
618 int16_t selectorValue;
619 if (!CFNumberGetValue(selectorNum, kCFNumberSInt16Type,
620 &selectorValue)) {
621 return false;
623 if (selectorValue == smallCaps) {
624 return true;
629 return false;
632 bool CTFontEntry::SupportsOpenTypeFeature(Script aScript,
633 uint32_t aFeatureTag) {
634 // If we're going to shape with Core Text, we don't support added
635 // OpenType features (aside from any CT applies by default), except
636 // for 'smcp' which we map to an AAT feature selector.
637 if (RequiresAATLayout()) {
638 if (aFeatureTag != HB_TAG('s', 'm', 'c', 'p')) {
639 return false;
641 if (mHasAATSmallCapsInitialized) {
642 return mHasAATSmallCaps;
644 mHasAATSmallCapsInitialized = true;
645 CGFontRef cgFont = GetFontRef();
646 if (!cgFont) {
647 return mHasAATSmallCaps;
650 CrashReporter::AutoAnnotateCrashReport autoFontName(
651 CrashReporter::Annotation::FontName, FamilyName());
653 AutoCFRelease<CTFontRef> ctFont =
654 CTFontCreateWithGraphicsFont(cgFont, 0.0, nullptr, nullptr);
655 if (ctFont) {
656 AutoCFRelease<CFArrayRef> features = CTFontCopyFeatures(ctFont);
657 if (features) {
658 mHasAATSmallCaps = CheckForAATSmallCaps(features);
661 return mHasAATSmallCaps;
663 return gfxFontEntry::SupportsOpenTypeFeature(aScript, aFeatureTag);
666 void CTFontEntry::AddSizeOfIncludingThis(MallocSizeOf aMallocSizeOf,
667 FontListSizes* aSizes) const {
668 aSizes->mFontListSize += aMallocSizeOf(this);
669 AddSizeOfExcludingThis(aMallocSizeOf, aSizes);
672 static CTFontDescriptorRef CreateDescriptorForFamily(
673 const nsACString& aFamilyName, bool aNormalized) {
674 AutoCFRelease<CFStringRef> family = CreateCFStringForString(aFamilyName);
675 const void* values[] = {family};
676 const void* keys[] = {kCTFontFamilyNameAttribute};
677 AutoCFRelease<CFDictionaryRef> attributes = CFDictionaryCreate(
678 kCFAllocatorDefault, keys, values, 1, &kCFTypeDictionaryKeyCallBacks,
679 &kCFTypeDictionaryValueCallBacks);
681 // Not AutoCFRelease, because we might return it.
682 CTFontDescriptorRef descriptor =
683 CTFontDescriptorCreateWithAttributes(attributes);
685 if (aNormalized) {
686 CTFontDescriptorRef normalized =
687 CTFontDescriptorCreateMatchingFontDescriptor(descriptor, nullptr);
688 if (normalized) {
689 CFRelease(descriptor);
690 return normalized;
694 return descriptor;
697 void CTFontFamily::LocalizedName(nsACString& aLocalizedName) {
698 AutoCFRelease<CTFontDescriptorRef> descriptor =
699 CreateDescriptorForFamily(mName, true);
700 if (descriptor) {
701 AutoCFRelease<CFStringRef> name =
702 static_cast<CFStringRef>(CTFontDescriptorCopyLocalizedAttribute(
703 descriptor, kCTFontFamilyNameAttribute, nullptr));
704 if (name) {
705 nsAutoString localized;
706 GetStringForCFString(name, localized);
707 if (!localized.IsEmpty()) {
708 CopyUTF16toUTF8(localized, aLocalizedName);
709 return;
714 // failed to get localized name, just use the canonical one
715 aLocalizedName = mName;
718 // Return the CSS weight value to use for the given face, overriding what
719 // AppKit gives us (used to adjust families with bad weight values, see
720 // bug 931426).
721 // A return value of 0 indicates no override - use the existing weight.
722 static inline int GetWeightOverride(const nsAString& aPSName) {
723 nsAutoCString prefName("font.weight-override.");
724 // The PostScript name is required to be ASCII; if it's not, the font is
725 // broken anyway, so we really don't care that this is lossy.
726 LossyAppendUTF16toASCII(aPSName, prefName);
727 return Preferences::GetInt(prefName.get(), 0);
730 // The Core Text weight trait is documented as
732 // ...a float value between -1.0 and 1.0 for normalized weight.
733 // The value of 0.0 corresponds to the regular or medium font weight.
735 // (https://developer.apple.com/documentation/coretext/kctfontweighttrait)
737 // CSS 'normal' font-weight is defined as 400, so we map 0.0 to this.
738 // The exact mapping to use for other values is not well defined; for now,
739 // we arbitrarily map the smallest value (-1.0) to CSS weight 100, and the
740 // largest (+1.0) to CSS weight 900, interpolating linearly between normal
741 // and each of these endpoints.
742 static inline int32_t CoreTextWeightToCSSWeight(CGFloat aCTWeight) {
743 if (aCTWeight >= 0.0) {
744 return 400 + NS_round(aCTWeight * 500);
746 return 400 + NS_round(aCTWeight * 300);
749 // The Core Text width trait is documented as
751 // ...a float between -1.0 and 1.0. The value of 0.0 corresponds to regular
752 // glyph spacing, and negative values represent condensed glyph spacing
754 // (https://developer.apple.com/documentation/coretext/kctfontweighttrait)
756 // CSS 'normal' font-stretch is 100%; 'ultra-expanded' is 200%, and 'ultra-
757 // condensed' is 50%. We map the extremes of the Core Text trait to these
758 // values, and interpolate in between these and normal.
759 static inline FontStretch CoreTextWidthToCSSStretch(CGFloat aCTWidth) {
760 if (aCTWidth >= 0.0) {
761 return FontStretch::FromFloat(100.0 + aCTWidth * 100.0);
763 return FontStretch::FromFloat(100.0 + aCTWidth * 50.0);
766 void CTFontFamily::AddFace(CTFontDescriptorRef aFace) {
767 AutoCFRelease<CFStringRef> psname =
768 (CFStringRef)CTFontDescriptorCopyAttribute(aFace, kCTFontNameAttribute);
769 AutoCFRelease<CFStringRef> facename =
770 (CFStringRef)CTFontDescriptorCopyAttribute(aFace,
771 kCTFontStyleNameAttribute);
773 AutoCFRelease<CFDictionaryRef> traitsDict =
774 (CFDictionaryRef)CTFontDescriptorCopyAttribute(aFace,
775 kCTFontTraitsAttribute);
776 CFNumberRef weight =
777 (CFNumberRef)CFDictionaryGetValue(traitsDict, kCTFontWeightTrait);
778 CFNumberRef width =
779 (CFNumberRef)CFDictionaryGetValue(traitsDict, kCTFontWidthTrait);
780 CFNumberRef symbolicTraits =
781 (CFNumberRef)CFDictionaryGetValue(traitsDict, kCTFontSymbolicTrait);
783 bool isStandardFace = false;
785 // make a nsString
786 nsAutoString postscriptFontName;
787 GetStringForCFString(psname, postscriptFontName);
789 int32_t cssWeight = GetWeightOverride(postscriptFontName);
790 if (cssWeight) {
791 // scale down and clamp, to get a value from 1..9
792 cssWeight = ((cssWeight + 50) / 100);
793 cssWeight = std::max(1, std::min(cssWeight, 9));
794 cssWeight *= 100; // scale up to CSS values
795 } else {
796 CGFloat weightValue;
797 CFNumberGetValue(weight, kCFNumberCGFloatType, &weightValue);
798 cssWeight = CoreTextWeightToCSSWeight(weightValue);
801 if (kCFCompareEqualTo == CFStringCompare(facename, CFSTR("Regular"), 0) ||
802 kCFCompareEqualTo == CFStringCompare(facename, CFSTR("Bold"), 0) ||
803 kCFCompareEqualTo == CFStringCompare(facename, CFSTR("Italic"), 0) ||
804 kCFCompareEqualTo == CFStringCompare(facename, CFSTR("Oblique"), 0) ||
805 kCFCompareEqualTo == CFStringCompare(facename, CFSTR("Bold Italic"), 0) ||
806 kCFCompareEqualTo ==
807 CFStringCompare(facename, CFSTR("Bold Oblique"), 0)) {
808 isStandardFace = true;
811 // create a font entry
812 CTFontEntry* fontEntry = new CTFontEntry(
813 NS_ConvertUTF16toUTF8(postscriptFontName),
814 WeightRange(FontWeight::FromInt(cssWeight)), isStandardFace);
816 CGFloat widthValue;
817 CFNumberGetValue(width, kCFNumberCGFloatType, &widthValue);
818 fontEntry->mStretchRange =
819 StretchRange(CoreTextWidthToCSSStretch(widthValue));
821 SInt32 traitsValue;
822 CFNumberGetValue(symbolicTraits, kCFNumberSInt32Type, &traitsValue);
823 if (traitsValue & kCTFontItalicTrait) {
824 fontEntry->mStyleRange = SlantStyleRange(FontSlantStyle::ITALIC);
827 if (traitsValue & kCTFontMonoSpaceTrait) {
828 fontEntry->mFixedPitch = true;
831 if (gfxPlatform::HasVariationFontSupport()) {
832 fontEntry->SetupVariationRanges();
835 if (LOG_FONTLIST_ENABLED()) {
836 nsAutoCString weightString;
837 fontEntry->Weight().ToString(weightString);
838 nsAutoCString stretchString;
839 fontEntry->Stretch().ToString(stretchString);
840 LOG_FONTLIST(
841 ("(fontlist) added (%s) to family (%s)"
842 " with style: %s weight: %s stretch: %s",
843 fontEntry->Name().get(), Name().get(),
844 fontEntry->IsItalic() ? "italic" : "normal", weightString.get(),
845 stretchString.get()));
848 // insert into font entry array of family
849 AddFontEntryLocked(fontEntry);
852 void CTFontFamily::FindStyleVariationsLocked(FontInfoData* aFontInfoData) {
853 if (mHasStyles) {
854 return;
857 AUTO_PROFILER_LABEL_DYNAMIC_NSCSTRING("CTFontFamily::FindStyleVariations",
858 LAYOUT, mName);
860 auto addFaceFunc = [](const void* aValue, void* aContext) -> void {
861 CTFontFamily* family = (CTFontFamily*)aContext;
862 // Calling family->AddFace requires that family->mLock is held. We know
863 // this will be true because FindStyleVariationsLocked already requires it,
864 // but the thread-safety analysis can't track that through into the lambda
865 // here, so we disable the check to avoid a spurious warning.
866 MOZ_PUSH_IGNORE_THREAD_SAFETY;
867 family->AddFace((CTFontDescriptorRef)aValue);
868 MOZ_POP_THREAD_SAFETY;
871 AutoCFRelease<CTFontDescriptorRef> descriptor =
872 CreateDescriptorForFamily(mName, false);
873 AutoCFRelease<CFArrayRef> faces =
874 CTFontDescriptorCreateMatchingFontDescriptors(descriptor, nullptr);
876 if (faces) {
877 CFArrayApplyFunction(faces, CFRangeMake(0, CFArrayGetCount(faces)),
878 addFaceFunc, this);
881 SortAvailableFonts();
882 SetHasStyles(true);
884 if (mIsBadUnderlineFamily) {
885 SetBadUnderlineFonts();
888 CheckForSimpleFamily();
891 /* CoreTextFontList */
892 #pragma mark -
894 CoreTextFontList::CoreTextFontList()
895 : gfxPlatformFontList(false),
896 mDefaultFont(nullptr),
897 mUseSizeSensitiveSystemFont(false) {
898 #ifdef MOZ_BUNDLED_FONTS
899 // We activate bundled fonts if the pref is > 0 (on) or < 0 (auto), only an
900 // explicit value of 0 (off) will disable them.
901 if (StaticPrefs::gfx_bundled_fonts_activate_AtStartup() != 0) {
902 TimeStamp start = TimeStamp::Now();
903 ActivateBundledFonts();
904 TimeStamp end = TimeStamp::Now();
905 Telemetry::Accumulate(Telemetry::FONTLIST_BUNDLEDFONTS_ACTIVATE,
906 (end - start).ToMilliseconds());
908 #endif
910 // Load the font-list preferences now, so that we don't have to do it from
911 // Init[Shared]FontListForPlatform, which may be called off-main-thread.
912 gfxFontUtils::GetPrefsFontList("font.preload-names-list", mPreloadFonts);
915 CoreTextFontList::~CoreTextFontList() {
916 AutoLock lock(mLock);
918 if (XRE_IsParentProcess()) {
919 CFNotificationCenterRemoveObserver(
920 CFNotificationCenterGetLocalCenter(), this,
921 kCTFontManagerRegisteredFontsChangedNotification, 0);
924 if (mDefaultFont) {
925 CFRelease(mDefaultFont);
929 void CoreTextFontList::AddFamily(const nsACString& aFamilyName,
930 FontVisibility aVisibility) {
931 double sizeHint = 0.0;
932 if (aVisibility == FontVisibility::Hidden && mUseSizeSensitiveSystemFont &&
933 mSystemDisplayFontFamilyName.Equals(aFamilyName)) {
934 sizeHint = 128.0;
937 nsAutoCString key;
938 ToLowerCase(aFamilyName, key);
940 RefPtr<gfxFontFamily> familyEntry =
941 new CTFontFamily(aFamilyName, aVisibility, sizeHint);
942 mFontFamilies.InsertOrUpdate(key, RefPtr{familyEntry});
944 // check the bad underline blocklist
945 if (mBadUnderlineFamilyNames.ContainsSorted(key)) {
946 familyEntry->SetBadUnderlineFamily();
950 void CoreTextFontList::AddFamily(CFStringRef aFamily) {
951 // CTFontManager includes internal family names and LastResort; skip those.
952 if (!aFamily ||
953 CFStringCompare(aFamily, CFSTR("LastResort"),
954 kCFCompareCaseInsensitive) == kCFCompareEqualTo ||
955 CFStringCompare(aFamily, CFSTR(".LastResort"),
956 kCFCompareCaseInsensitive) == kCFCompareEqualTo) {
957 return;
960 nsAutoString familyName;
961 GetStringForCFString(aFamily, familyName);
963 NS_ConvertUTF16toUTF8 nameUtf8(familyName);
964 AddFamily(nameUtf8, GetVisibilityForFamily(nameUtf8));
967 /* static */
968 void CoreTextFontList::ActivateFontsFromDir(
969 const nsACString& aDir, nsTHashSet<nsCStringHashKey>* aLoadedFamilies) {
970 AutoCFRelease<CFURLRef> directory = CFURLCreateFromFileSystemRepresentation(
971 kCFAllocatorDefault, (const UInt8*)nsPromiseFlatCString(aDir).get(),
972 aDir.Length(), true);
973 if (!directory) {
974 return;
976 AutoCFRelease<CFURLEnumeratorRef> enumerator =
977 CFURLEnumeratorCreateForDirectoryURL(kCFAllocatorDefault, directory,
978 kCFURLEnumeratorDefaultBehavior,
979 nullptr);
980 if (!enumerator) {
981 return;
983 AutoCFRelease<CFMutableArrayRef> urls =
984 CFArrayCreateMutable(kCFAllocatorDefault, 0, &kCFTypeArrayCallBacks);
985 if (!urls) {
986 return;
989 CFURLRef url;
990 CFURLEnumeratorResult result;
991 do {
992 result = CFURLEnumeratorGetNextURL(enumerator, &url, nullptr);
993 if (result != kCFURLEnumeratorSuccess) {
994 continue;
996 CFArrayAppendValue(urls, url);
998 if (!aLoadedFamilies) {
999 continue;
1001 AutoCFRelease<CFArrayRef> descriptors =
1002 CTFontManagerCreateFontDescriptorsFromURL(url);
1003 if (!descriptors || !CFArrayGetCount(descriptors)) {
1004 continue;
1006 CTFontDescriptorRef desc =
1007 (CTFontDescriptorRef)CFArrayGetValueAtIndex(descriptors, 0);
1008 AutoCFRelease<CFStringRef> name =
1009 (CFStringRef)CTFontDescriptorCopyAttribute(desc,
1010 kCTFontFamilyNameAttribute);
1011 nsAutoCString key;
1012 key.SetLength((CFStringGetLength(name) + 1) * 3);
1013 if (CFStringGetCString(name, key.BeginWriting(), key.Length(),
1014 kCFStringEncodingUTF8)) {
1015 key.SetLength(strlen(key.get()));
1016 aLoadedFamilies->Insert(key);
1018 } while (result != kCFURLEnumeratorEnd);
1020 CTFontManagerRegisterFontsForURLs(urls, kCTFontManagerScopeProcess, nullptr);
1023 void CoreTextFontList::ReadSystemFontList(dom::SystemFontList* aList)
1024 MOZ_NO_THREAD_SAFETY_ANALYSIS {
1025 // Note: We rely on the records for mSystemTextFontFamilyName and
1026 // mSystemDisplayFontFamilyName (if present) being *before* the main
1027 // font list, so that those names are known in the content process
1028 // by the time we add the actual family records to the font list.
1029 aList->entries().AppendElement(
1030 FontFamilyListEntry(mSystemTextFontFamilyName, FontVisibility::Unknown,
1031 kTextSizeSystemFontFamily));
1032 if (mUseSizeSensitiveSystemFont) {
1033 aList->entries().AppendElement(FontFamilyListEntry(
1034 mSystemDisplayFontFamilyName, FontVisibility::Unknown,
1035 kDisplaySizeSystemFontFamily));
1037 // Now collect the list of available families, with visibility attributes.
1038 for (auto f = mFontFamilies.Iter(); !f.Done(); f.Next()) {
1039 auto macFamily = f.Data().get();
1040 aList->entries().AppendElement(FontFamilyListEntry(
1041 macFamily->Name(), macFamily->Visibility(), kStandardFontFamily));
1045 void CoreTextFontList::PreloadNamesList() {
1046 uint32_t numFonts = mPreloadFonts.Length();
1047 for (uint32_t i = 0; i < numFonts; i++) {
1048 nsAutoCString key;
1049 GenerateFontListKey(mPreloadFonts[i], key);
1051 // only search canonical names!
1052 gfxFontFamily* familyEntry = mFontFamilies.GetWeak(key);
1053 if (familyEntry) {
1054 familyEntry->ReadOtherFamilyNames(this);
1059 nsresult CoreTextFontList::InitFontListForPlatform() {
1060 // The font registration thread was created early in startup, to give the
1061 // system a head start on activating all the supplemental-language fonts.
1062 // Here, we need to wait until it has finished its work.
1063 gfxPlatformMac::WaitForFontRegistration();
1065 Telemetry::AutoTimer<Telemetry::MAC_INITFONTLIST_TOTAL> timer;
1067 InitSystemFontNames();
1069 if (XRE_IsParentProcess()) {
1070 static bool firstTime = true;
1071 if (firstTime) {
1072 CFNotificationCenterAddObserver(
1073 CFNotificationCenterGetLocalCenter(), this,
1074 RegisteredFontsChangedNotificationCallback,
1075 kCTFontManagerRegisteredFontsChangedNotification, 0,
1076 CFNotificationSuspensionBehaviorDeliverImmediately);
1077 firstTime = false;
1080 // We're not a content process, so get the available fonts directly
1081 // from Core Text.
1082 AutoCFRelease<CFArrayRef> familyNames =
1083 CTFontManagerCopyAvailableFontFamilyNames();
1084 for (CFIndex i = 0; i < CFArrayGetCount(familyNames); i++) {
1085 CFStringRef familyName =
1086 (CFStringRef)CFArrayGetValueAtIndex(familyNames, i);
1087 AddFamily(familyName);
1089 for (const auto& name : kDeprecatedFontFamilies) {
1090 if (DeprecatedFamilyIsAvailable(name)) {
1091 AddFamily(name, GetVisibilityForFamily(name));
1094 } else {
1095 // Content process: use font list passed from the chrome process via
1096 // the GetXPCOMProcessAttributes message, because it's much faster than
1097 // querying Core Text again in the child.
1098 auto& fontList = dom::ContentChild::GetSingleton()->SystemFontList();
1099 for (FontFamilyListEntry& ffe : fontList.entries()) {
1100 switch (ffe.entryType()) {
1101 case kStandardFontFamily:
1102 if (ffe.familyName() == mSystemTextFontFamilyName ||
1103 ffe.familyName() == mSystemDisplayFontFamilyName) {
1104 continue;
1106 AddFamily(ffe.familyName(), ffe.visibility());
1107 break;
1108 case kTextSizeSystemFontFamily:
1109 mSystemTextFontFamilyName = ffe.familyName();
1110 break;
1111 case kDisplaySizeSystemFontFamily:
1112 mSystemDisplayFontFamilyName = ffe.familyName();
1113 mUseSizeSensitiveSystemFont = true;
1114 break;
1117 fontList.entries().Clear();
1120 InitSingleFaceList();
1122 // to avoid full search of font name tables, seed the other names table with
1123 // localized names from some of the prefs fonts which are accessed via their
1124 // localized names. changes in the pref fonts will only cause a font lookup
1125 // miss earlier. this is a simple optimization, it's not required for
1126 // correctness
1127 PreloadNamesList();
1129 // start the delayed cmap loader
1130 GetPrefsAndStartLoader();
1132 return NS_OK;
1135 void CoreTextFontList::InitSharedFontListForPlatform() {
1136 gfxPlatformMac::WaitForFontRegistration();
1138 InitSystemFontNames();
1140 if (XRE_IsParentProcess()) {
1141 // Only the parent process listens for OS font-changed notifications;
1142 // after rebuilding its list, it will update the content processes.
1143 static bool firstTime = true;
1144 if (firstTime) {
1145 CFNotificationCenterAddObserver(
1146 CFNotificationCenterGetLocalCenter(), this,
1147 RegisteredFontsChangedNotificationCallback,
1148 kCTFontManagerRegisteredFontsChangedNotification, 0,
1149 CFNotificationSuspensionBehaviorDeliverImmediately);
1150 firstTime = false;
1153 AutoCFRelease<CFArrayRef> familyNames =
1154 CTFontManagerCopyAvailableFontFamilyNames();
1155 nsTArray<fontlist::Family::InitData> families;
1156 families.SetCapacity(CFArrayGetCount(familyNames) +
1157 ArrayLength(kDeprecatedFontFamilies));
1158 for (CFIndex i = 0; i < CFArrayGetCount(familyNames); ++i) {
1159 nsAutoString name16;
1160 CFStringRef familyName =
1161 (CFStringRef)CFArrayGetValueAtIndex(familyNames, i);
1162 GetStringForCFString(familyName, name16);
1163 NS_ConvertUTF16toUTF8 name(name16);
1164 nsAutoCString key;
1165 GenerateFontListKey(name, key);
1166 families.AppendElement(fontlist::Family::InitData(
1167 key, name, fontlist::Family::kNoIndex, GetVisibilityForFamily(name)));
1169 for (const nsACString& name : kDeprecatedFontFamilies) {
1170 if (DeprecatedFamilyIsAvailable(name)) {
1171 nsAutoCString key;
1172 GenerateFontListKey(name, key);
1173 families.AppendElement(
1174 fontlist::Family::InitData(key, name, fontlist::Family::kNoIndex,
1175 GetVisibilityForFamily(name)));
1178 SharedFontList()->SetFamilyNames(families);
1179 InitAliasesForSingleFaceList();
1180 GetPrefsAndStartLoader();
1184 gfxFontFamily* CoreTextFontList::FindSystemFontFamily(
1185 const nsACString& aFamily) {
1186 nsAutoCString key;
1187 GenerateFontListKey(aFamily, key);
1189 gfxFontFamily* familyEntry;
1190 if ((familyEntry = mFontFamilies.GetWeak(key))) {
1191 return CheckFamily(familyEntry);
1194 return nullptr;
1197 void CoreTextFontList::RegisteredFontsChangedNotificationCallback(
1198 CFNotificationCenterRef center, void* observer, CFStringRef name,
1199 const void* object, CFDictionaryRef userInfo) {
1200 if (!CFEqual(name, kCTFontManagerRegisteredFontsChangedNotification)) {
1201 return;
1204 CoreTextFontList* fl = static_cast<CoreTextFontList*>(observer);
1205 if (!fl->IsInitialized()) {
1206 return;
1209 // xxx - should be carefully pruning the list of fonts, not rebuilding it from
1210 // scratch
1211 fl->UpdateFontList();
1213 gfxPlatform::ForceGlobalReflow(gfxPlatform::NeedsReframe::Yes);
1214 dom::ContentParent::NotifyUpdatedFonts(true);
1217 gfxFontEntry* CoreTextFontList::PlatformGlobalFontFallback(
1218 nsPresContext* aPresContext, const uint32_t aCh, Script aRunScript,
1219 const gfxFontStyle* aMatchStyle, FontFamily& aMatchedFamily) {
1220 CFStringRef str;
1221 UniChar ch[2];
1222 CFIndex length = 1;
1224 if (IS_IN_BMP(aCh)) {
1225 ch[0] = aCh;
1226 str = CFStringCreateWithCharactersNoCopy(kCFAllocatorDefault, ch, 1,
1227 kCFAllocatorNull);
1228 } else {
1229 ch[0] = H_SURROGATE(aCh);
1230 ch[1] = L_SURROGATE(aCh);
1231 str = CFStringCreateWithCharactersNoCopy(kCFAllocatorDefault, ch, 2,
1232 kCFAllocatorNull);
1233 length = 2;
1235 if (!str) {
1236 return nullptr;
1239 // use CoreText to find the fallback family
1241 gfxFontEntry* fontEntry = nullptr;
1242 bool cantUseFallbackFont = false;
1244 if (!mDefaultFont) {
1245 mDefaultFont = CTFontCreateWithName(CFSTR("LucidaGrande"), 12.f, NULL);
1248 AutoCFRelease<CTFontRef> fallback =
1249 CTFontCreateForString(mDefaultFont, str, CFRangeMake(0, length));
1251 if (fallback) {
1252 AutoCFRelease<CFStringRef> familyNameRef = CTFontCopyFamilyName(fallback);
1254 if (familyNameRef &&
1255 CFStringCompare(familyNameRef, CFSTR("LastResort"),
1256 kCFCompareCaseInsensitive) != kCFCompareEqualTo &&
1257 CFStringCompare(familyNameRef, CFSTR(".LastResort"),
1258 kCFCompareCaseInsensitive) != kCFCompareEqualTo) {
1259 AutoTArray<UniChar, 1024> buffer;
1260 CFIndex familyNameLen = CFStringGetLength(familyNameRef);
1261 buffer.SetLength(familyNameLen + 1);
1262 CFStringGetCharacters(familyNameRef, CFRangeMake(0, familyNameLen),
1263 buffer.Elements());
1264 buffer[familyNameLen] = 0;
1265 NS_ConvertUTF16toUTF8 familyNameString(
1266 reinterpret_cast<char16_t*>(buffer.Elements()), familyNameLen);
1268 if (SharedFontList()) {
1269 fontlist::Family* family =
1270 FindSharedFamily(aPresContext, familyNameString);
1271 if (family) {
1272 fontlist::Face* face =
1273 family->FindFaceForStyle(SharedFontList(), *aMatchStyle);
1274 if (face) {
1275 fontEntry = GetOrCreateFontEntryLocked(face, family);
1277 if (fontEntry) {
1278 if (fontEntry->HasCharacter(aCh)) {
1279 aMatchedFamily = FontFamily(family);
1280 } else {
1281 fontEntry = nullptr;
1282 cantUseFallbackFont = true;
1288 // The macOS system font does not appear in the shared font list, so if
1289 // we didn't find the fallback font above, we should also check for an
1290 // unshared fontFamily in the system list.
1291 if (!fontEntry) {
1292 gfxFontFamily* family = FindSystemFontFamily(familyNameString);
1293 if (family) {
1294 fontEntry = family->FindFontForStyle(*aMatchStyle);
1295 if (fontEntry) {
1296 if (fontEntry->HasCharacter(aCh)) {
1297 aMatchedFamily = FontFamily(family);
1298 } else {
1299 fontEntry = nullptr;
1300 cantUseFallbackFont = true;
1308 if (cantUseFallbackFont) {
1309 Telemetry::Accumulate(Telemetry::BAD_FALLBACK_FONT, cantUseFallbackFont);
1312 CFRelease(str);
1314 return fontEntry;
1317 gfxFontEntry* CoreTextFontList::LookupLocalFont(
1318 nsPresContext* aPresContext, const nsACString& aFontName,
1319 WeightRange aWeightForEntry, StretchRange aStretchForEntry,
1320 SlantStyleRange aStyleForEntry) {
1321 if (aFontName.IsEmpty() || aFontName[0] == '.') {
1322 return nullptr;
1325 AutoLock lock(mLock);
1327 CrashReporter::AutoAnnotateCrashReport autoFontName(
1328 CrashReporter::Annotation::FontName, aFontName);
1330 AutoCFRelease<CFStringRef> faceName = CreateCFStringForString(aFontName);
1331 if (!faceName) {
1332 return nullptr;
1335 // lookup face based on postscript or full name
1336 AutoCFRelease<CGFontRef> fontRef = CGFontCreateWithFontName(faceName);
1337 if (!fontRef) {
1338 return nullptr;
1341 // It's possible for CGFontCreateWithFontName to return a font that has been
1342 // deactivated/uninstalled, or a font that is excluded from the font list due
1343 // to CSS font-visibility restriction. So we need to check whether this font
1344 // is allowed to be used.
1346 // CGFontRef doesn't offer a family-name API, so we go via a CTFontRef.
1347 AutoCFRelease<CTFontRef> ctFont =
1348 CTFontCreateWithGraphicsFont(fontRef, 0.0, nullptr, nullptr);
1349 if (!ctFont) {
1350 return nullptr;
1352 AutoCFRelease<CFStringRef> name = CTFontCopyFamilyName(ctFont);
1354 // Convert the family name to a key suitable for font-list lookup (8-bit,
1355 // lowercased).
1356 nsAutoCString key;
1357 // CFStringGetLength is in UTF-16 code units. The maximum this count can
1358 // expand when converted to UTF-8 is 3x. We add 1 to ensure there will also be
1359 // space for null-termination of the resulting C string.
1360 key.SetLength((CFStringGetLength(name) + 1) * 3);
1361 if (!CFStringGetCString(name, key.BeginWriting(), key.Length(),
1362 kCFStringEncodingUTF8)) {
1363 // This shouldn't ever happen, but if it does we just bail.
1364 NS_WARNING("Failed to get family name?");
1365 key.Truncate(0);
1367 if (key.IsEmpty()) {
1368 return nullptr;
1370 // Reset our string length to match the actual C string we got, which will
1371 // usually be much shorter than the maximal buffer we allocated.
1372 key.Truncate(strlen(key.get()));
1373 ToLowerCase(key);
1374 // If the family can't be looked up, this font is not available for use.
1375 FontFamily family = FindFamily(aPresContext, key);
1376 if (family.IsNull()) {
1377 return nullptr;
1380 return new CTFontEntry(aFontName, fontRef, aWeightForEntry, aStretchForEntry,
1381 aStyleForEntry, false, true);
1384 static void ReleaseData(void* info, const void* data, size_t size) {
1385 free((void*)data);
1388 gfxFontEntry* CoreTextFontList::MakePlatformFont(const nsACString& aFontName,
1389 WeightRange aWeightForEntry,
1390 StretchRange aStretchForEntry,
1391 SlantStyleRange aStyleForEntry,
1392 const uint8_t* aFontData,
1393 uint32_t aLength) {
1394 NS_ASSERTION(aFontData, "MakePlatformFont called with null data");
1396 // create the font entry
1397 nsAutoString uniqueName;
1399 nsresult rv = gfxFontUtils::MakeUniqueUserFontName(uniqueName);
1400 if (NS_FAILED(rv)) {
1401 return nullptr;
1404 CrashReporter::AutoAnnotateCrashReport autoFontName(
1405 CrashReporter::Annotation::FontName, aFontName);
1407 AutoCFRelease<CGDataProviderRef> provider =
1408 ::CGDataProviderCreateWithData(nullptr, aFontData, aLength, &ReleaseData);
1409 AutoCFRelease<CGFontRef> fontRef = ::CGFontCreateWithDataProvider(provider);
1410 if (!fontRef) {
1411 return nullptr;
1414 auto newFontEntry = MakeUnique<CTFontEntry>(
1415 NS_ConvertUTF16toUTF8(uniqueName), fontRef, aWeightForEntry,
1416 aStretchForEntry, aStyleForEntry, true, false);
1417 return newFontEntry.release();
1420 // Webkit code uses a system font meta name, so mimic that here
1421 // WebCore/platform/graphics/mac/FontCacheMac.mm
1422 static const char kSystemFont_system[] = "-apple-system";
1424 // System fonts under OSX 10.11 use a combination of two families, one
1425 // for text sizes and another for larger, display sizes. Each has a
1426 // different number of weights. There aren't efficient API's for looking
1427 // this information up, so hard code the logic here but confirm via
1428 // debug assertions that the logic is correct.
1430 const CGFloat kTextDisplayCrossover = 20.0; // use text family below this size
1432 bool CoreTextFontList::FindAndAddFamiliesLocked(
1433 nsPresContext* aPresContext, StyleGenericFontFamily aGeneric,
1434 const nsACString& aFamily, nsTArray<FamilyAndGeneric>* aOutput,
1435 FindFamiliesFlags aFlags, gfxFontStyle* aStyle, nsAtom* aLanguage,
1436 gfxFloat aDevToCssSize) {
1437 if (aFamily.EqualsLiteral(kSystemFont_system)) {
1438 // Search for special system font name, -apple-system. This is not done via
1439 // the shared fontlist on Catalina or later, because the hidden system font
1440 // may not be included there; we create a separate gfxFontFamily to manage
1441 // this family.
1442 const nsCString& systemFontFamilyName =
1443 mUseSizeSensitiveSystemFont && aStyle &&
1444 (aStyle->size * aDevToCssSize) >= kTextDisplayCrossover
1445 ? mSystemDisplayFontFamilyName
1446 : mSystemTextFontFamilyName;
1447 if (auto* fam = FindSystemFontFamily(systemFontFamilyName)) {
1448 aOutput->AppendElement(fam);
1449 return true;
1451 return false;
1454 return gfxPlatformFontList::FindAndAddFamiliesLocked(
1455 aPresContext, aGeneric, aFamily, aOutput, aFlags, aStyle, aLanguage,
1456 aDevToCssSize);
1459 // used to load system-wide font info on off-main thread
1460 class CTFontInfo final : public FontInfoData {
1461 public:
1462 CTFontInfo(bool aLoadOtherNames, bool aLoadFaceNames, bool aLoadCmaps,
1463 RecursiveMutex& aLock)
1464 : FontInfoData(aLoadOtherNames, aLoadFaceNames, aLoadCmaps),
1465 mLock(aLock) {}
1467 virtual ~CTFontInfo() = default;
1469 virtual void Load() { FontInfoData::Load(); }
1471 // loads font data for all members of a given family
1472 virtual void LoadFontFamilyData(const nsACString& aFamilyName);
1474 RecursiveMutex& mLock;
1477 void CTFontInfo::LoadFontFamilyData(const nsACString& aFamilyName) {
1478 CrashReporter::AutoAnnotateCrashReport autoFontName(
1479 CrashReporter::Annotation::FontName, aFamilyName);
1480 // Prevent this from running concurrently with CGFont operations on the main
1481 // thread, because the macOS font cache is fragile with concurrent access.
1482 // This appears to be a vulnerability within CoreText in versions of macOS
1483 // before macOS 13. In time, we can remove this lock.
1484 RecursiveMutexAutoLock lock(mLock);
1486 // family name ==> CTFontDescriptor
1487 AutoCFRelease<CFStringRef> family = CreateCFStringForString(aFamilyName);
1489 AutoCFRelease<CFMutableDictionaryRef> attr =
1490 CFDictionaryCreateMutable(NULL, 0, &kCFTypeDictionaryKeyCallBacks,
1491 &kCFTypeDictionaryValueCallBacks);
1492 CFDictionaryAddValue(attr, kCTFontFamilyNameAttribute, family);
1493 AutoCFRelease<CTFontDescriptorRef> fd =
1494 CTFontDescriptorCreateWithAttributes(attr);
1495 AutoCFRelease<CFArrayRef> matchingFonts =
1496 CTFontDescriptorCreateMatchingFontDescriptors(fd, NULL);
1497 if (!matchingFonts) {
1498 return;
1501 nsTArray<nsCString> otherFamilyNames;
1502 bool hasOtherFamilyNames = true;
1504 // iterate over faces in the family
1505 int f, numFaces = (int)CFArrayGetCount(matchingFonts);
1506 for (f = 0; f < numFaces; f++) {
1507 mLoadStats.fonts++;
1509 CTFontDescriptorRef faceDesc =
1510 (CTFontDescriptorRef)CFArrayGetValueAtIndex(matchingFonts, f);
1511 if (!faceDesc) {
1512 continue;
1514 AutoCFRelease<CTFontRef> fontRef =
1515 CTFontCreateWithFontDescriptor(faceDesc, 0.0, nullptr);
1516 if (!fontRef) {
1517 NS_WARNING("failed to create a CTFontRef");
1518 continue;
1521 if (mLoadCmaps) {
1522 // face name
1523 AutoCFRelease<CFStringRef> faceName =
1524 (CFStringRef)CTFontDescriptorCopyAttribute(faceDesc,
1525 kCTFontNameAttribute);
1527 AutoTArray<UniChar, 1024> buffer;
1528 CFIndex len = CFStringGetLength(faceName);
1529 buffer.SetLength(len + 1);
1530 CFStringGetCharacters(faceName, CFRangeMake(0, len), buffer.Elements());
1531 buffer[len] = 0;
1532 NS_ConvertUTF16toUTF8 fontName(
1533 reinterpret_cast<char16_t*>(buffer.Elements()), len);
1535 // load the cmap data
1536 FontFaceData fontData;
1537 AutoCFRelease<CFDataRef> cmapTable = CTFontCopyTable(
1538 fontRef, kCTFontTableCmap, kCTFontTableOptionNoOptions);
1540 if (cmapTable) {
1541 const uint8_t* cmapData = (const uint8_t*)CFDataGetBytePtr(cmapTable);
1542 uint32_t cmapLen = CFDataGetLength(cmapTable);
1543 RefPtr<gfxCharacterMap> charmap = new gfxCharacterMap();
1544 uint32_t offset;
1545 nsresult rv;
1547 rv = gfxFontUtils::ReadCMAP(cmapData, cmapLen, *charmap, offset);
1548 if (NS_SUCCEEDED(rv)) {
1549 fontData.mCharacterMap = charmap;
1550 fontData.mUVSOffset = offset;
1551 mLoadStats.cmaps++;
1555 mFontFaceData.InsertOrUpdate(fontName, fontData);
1558 if (mLoadOtherNames && hasOtherFamilyNames) {
1559 AutoCFRelease<CFDataRef> nameTable = CTFontCopyTable(
1560 fontRef, kCTFontTableName, kCTFontTableOptionNoOptions);
1562 if (nameTable) {
1563 const char* nameData = (const char*)CFDataGetBytePtr(nameTable);
1564 uint32_t nameLen = CFDataGetLength(nameTable);
1565 gfxFontUtils::ReadOtherFamilyNamesForFace(
1566 aFamilyName, nameData, nameLen, otherFamilyNames, false);
1567 hasOtherFamilyNames = otherFamilyNames.Length() != 0;
1572 // if found other names, insert them in the hash table
1573 if (otherFamilyNames.Length() != 0) {
1574 mOtherFamilyNames.InsertOrUpdate(aFamilyName, otherFamilyNames);
1575 mLoadStats.othernames += otherFamilyNames.Length();
1579 already_AddRefed<FontInfoData> CoreTextFontList::CreateFontInfoData() {
1580 bool loadCmaps = !UsesSystemFallback() ||
1581 gfxPlatform::GetPlatform()->UseCmapsDuringSystemFallback();
1583 mLock.AssertCurrentThreadIn();
1584 RefPtr<CTFontInfo> fi =
1585 new CTFontInfo(true, NeedFullnamePostscriptNames(), loadCmaps, mLock);
1586 return fi.forget();
1589 gfxFontFamily* CoreTextFontList::CreateFontFamily(
1590 const nsACString& aName, FontVisibility aVisibility) const {
1591 return new CTFontFamily(aName, aVisibility);
1594 gfxFontEntry* CoreTextFontList::CreateFontEntry(
1595 fontlist::Face* aFace, const fontlist::Family* aFamily) {
1596 CTFontEntry* fe = new CTFontEntry(
1597 aFace->mDescriptor.AsString(SharedFontList()), aFace->mWeight, false,
1598 0.0); // XXX standardFace, sizeHint
1599 fe->InitializeFrom(aFace, aFamily);
1600 return fe;
1603 void CoreTextFontList::AddFaceInitData(
1604 CTFontDescriptorRef aFontDesc, nsTArray<fontlist::Face::InitData>& aFaces,
1605 bool aLoadCmaps) {
1606 AutoCFRelease<CFStringRef> psname =
1607 (CFStringRef)CTFontDescriptorCopyAttribute(aFontDesc,
1608 kCTFontNameAttribute);
1609 AutoCFRelease<CFStringRef> facename =
1610 (CFStringRef)CTFontDescriptorCopyAttribute(aFontDesc,
1611 kCTFontStyleNameAttribute);
1612 AutoCFRelease<CFDictionaryRef> traitsDict =
1613 (CFDictionaryRef)CTFontDescriptorCopyAttribute(aFontDesc,
1614 kCTFontTraitsAttribute);
1616 CFNumberRef weight =
1617 (CFNumberRef)CFDictionaryGetValue(traitsDict, kCTFontWeightTrait);
1618 CFNumberRef width =
1619 (CFNumberRef)CFDictionaryGetValue(traitsDict, kCTFontWidthTrait);
1620 CFNumberRef symbolicTraits =
1621 (CFNumberRef)CFDictionaryGetValue(traitsDict, kCTFontSymbolicTrait);
1623 // make a nsString
1624 nsAutoString postscriptFontName;
1625 GetStringForCFString(psname, postscriptFontName);
1627 int32_t cssWeight = PR_GetCurrentThread() == sInitFontListThread
1629 : GetWeightOverride(postscriptFontName);
1630 if (cssWeight) {
1631 // scale down and clamp, to get a value from 1..9
1632 cssWeight = ((cssWeight + 50) / 100);
1633 cssWeight = std::max(1, std::min(cssWeight, 9));
1634 cssWeight *= 100; // scale up to CSS values
1635 } else {
1636 CGFloat weightValue;
1637 CFNumberGetValue(weight, kCFNumberCGFloatType, &weightValue);
1638 cssWeight = CoreTextWeightToCSSWeight(weightValue);
1641 CGFloat widthValue;
1642 CFNumberGetValue(width, kCFNumberCGFloatType, &widthValue);
1643 StretchRange stretch(CoreTextWidthToCSSStretch(widthValue));
1645 SlantStyleRange slantStyle(FontSlantStyle::NORMAL);
1646 SInt32 traitsValue;
1647 CFNumberGetValue(symbolicTraits, kCFNumberSInt32Type, &traitsValue);
1648 if (traitsValue & kCTFontItalicTrait) {
1649 slantStyle = SlantStyleRange(FontSlantStyle::ITALIC);
1652 bool fixedPitch = traitsValue & kCTFontMonoSpaceTrait;
1654 RefPtr<gfxCharacterMap> charmap;
1655 if (aLoadCmaps) {
1656 AutoCFRelease<CGFontRef> font =
1657 CGFontCreateWithFontName(CFStringRef(psname));
1658 if (font) {
1659 uint32_t kCMAP = TRUETYPE_TAG('c', 'm', 'a', 'p');
1660 AutoCFRelease<CFDataRef> data = CGFontCopyTableForTag(font, kCMAP);
1661 if (data) {
1662 uint32_t offset;
1663 charmap = new gfxCharacterMap();
1664 gfxFontUtils::ReadCMAP(CFDataGetBytePtr(data), CFDataGetLength(data),
1665 *charmap, offset);
1670 // Ensure that a face named "Regular" goes to the front of the list, so it
1671 // will take precedence over other faces with the same style attributes but
1672 // a different name (such as "Outline").
1673 auto data = fontlist::Face::InitData{
1674 NS_ConvertUTF16toUTF8(postscriptFontName),
1676 fixedPitch,
1677 WeightRange(FontWeight::FromInt(cssWeight)),
1678 stretch,
1679 slantStyle,
1680 charmap,
1682 if (kCFCompareEqualTo == CFStringCompare(facename, CFSTR("Regular"), 0)) {
1683 aFaces.InsertElementAt(0, std::move(data));
1684 } else {
1685 aFaces.AppendElement(std::move(data));
1689 void CoreTextFontList::GetFacesInitDataForFamily(
1690 const fontlist::Family* aFamily, nsTArray<fontlist::Face::InitData>& aFaces,
1691 bool aLoadCmaps) const {
1692 auto name = aFamily->Key().AsString(SharedFontList());
1693 CrashReporter::AutoAnnotateCrashReport autoFontName(
1694 CrashReporter::Annotation::FontName, name);
1696 struct Context {
1697 nsTArray<fontlist::Face::InitData>& mFaces;
1698 bool mLoadCmaps;
1700 auto addFaceFunc = [](const void* aValue, void* aContext) -> void {
1701 CTFontDescriptorRef fontDesc = (CTFontDescriptorRef)aValue;
1702 Context* context = (Context*)aContext;
1703 CoreTextFontList::AddFaceInitData(fontDesc, context->mFaces,
1704 context->mLoadCmaps);
1707 AutoCFRelease<CTFontDescriptorRef> descriptor =
1708 CreateDescriptorForFamily(name, false);
1709 AutoCFRelease<CFArrayRef> faces =
1710 CTFontDescriptorCreateMatchingFontDescriptors(descriptor, nullptr);
1712 if (faces) {
1713 Context context{aFaces, aLoadCmaps};
1714 CFArrayApplyFunction(faces, CFRangeMake(0, CFArrayGetCount(faces)),
1715 addFaceFunc, &context);
1719 void CoreTextFontList::ReadFaceNamesForFamily(
1720 fontlist::Family* aFamily, bool aNeedFullnamePostscriptNames) {
1721 if (!aFamily->IsInitialized()) {
1722 if (!InitializeFamily(aFamily)) {
1723 return;
1726 const uint32_t kNAME = TRUETYPE_TAG('n', 'a', 'm', 'e');
1727 fontlist::FontList* list = SharedFontList();
1728 nsAutoCString canonicalName(aFamily->DisplayName().AsString(list));
1729 const auto* facePtrs = aFamily->Faces(list);
1730 for (uint32_t i = 0, n = aFamily->NumFaces(); i < n; i++) {
1731 auto* face = facePtrs[i].ToPtr<const fontlist::Face>(list);
1732 if (!face) {
1733 continue;
1735 nsAutoCString name(face->mDescriptor.AsString(list));
1736 // We create a temporary CTFontEntry just to read family names from the
1737 // 'name' table in the font resource. The style attributes here are ignored
1738 // as this entry is not used for font style matching.
1739 // The size hint might be used to select which face is accessed in the case
1740 // of the macOS UI font; see CTFontEntry::GetFontRef(). We pass 16.0 in
1741 // order to get a standard text-size face in this case, although it's
1742 // unlikely to matter for the purpose of just reading family names.
1743 auto fe = MakeUnique<CTFontEntry>(name, WeightRange(FontWeight::NORMAL),
1744 false, 16.0);
1745 if (!fe) {
1746 continue;
1748 gfxFontEntry::AutoTable nameTable(fe.get(), kNAME);
1749 if (!nameTable) {
1750 continue;
1752 uint32_t dataLength;
1753 const char* nameData = hb_blob_get_data(nameTable, &dataLength);
1754 AutoTArray<nsCString, 4> otherFamilyNames;
1755 gfxFontUtils::ReadOtherFamilyNamesForFace(
1756 canonicalName, nameData, dataLength, otherFamilyNames, false);
1757 for (const auto& alias : otherFamilyNames) {
1758 nsAutoCString key;
1759 GenerateFontListKey(alias, key);
1760 auto aliasData = mAliasTable.GetOrInsertNew(key);
1761 aliasData->InitFromFamily(aFamily, canonicalName);
1762 aliasData->mFaces.AppendElement(facePtrs[i]);
1767 #ifdef MOZ_BUNDLED_FONTS
1768 void CoreTextFontList::ActivateBundledFonts() {
1769 nsCOMPtr<nsIFile> localDir;
1770 if (NS_FAILED(NS_GetSpecialDirectory(NS_GRE_DIR, getter_AddRefs(localDir)))) {
1771 return;
1773 if (NS_FAILED(localDir->Append(u"fonts"_ns))) {
1774 return;
1776 nsAutoCString path;
1777 if (NS_FAILED(localDir->GetNativePath(path))) {
1778 return;
1780 ActivateFontsFromDir(path, &mBundledFamilies);
1782 #endif