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 "mozilla/Logging.h"
7 #include "mozilla/gfx/Logging.h"
8 #include "mozilla/intl/Locale.h"
9 #include "mozilla/intl/LocaleService.h"
10 #include "mozilla/intl/OSPreferences.h"
12 #include "gfxPlatformFontList.h"
13 #include "gfxTextRun.h"
14 #include "gfxUserFontSet.h"
15 #include "SharedFontList-impl.h"
17 #include "GeckoProfiler.h"
19 #include "nsGkAtoms.h"
20 #include "nsPresContext.h"
21 #include "nsServiceManagerUtils.h"
22 #include "nsUnicharUtils.h"
23 #include "nsUnicodeProperties.h"
24 #include "nsXULAppAPI.h"
26 #include "mozilla/AppShutdown.h"
27 #include "mozilla/Attributes.h"
28 #include "mozilla/BinarySearch.h"
29 #include "mozilla/Likely.h"
30 #include "mozilla/MemoryReporting.h"
31 #include "mozilla/Mutex.h"
32 #include "mozilla/Preferences.h"
33 #include "mozilla/StaticPrefs_gfx.h"
34 #include "mozilla/StaticPrefs_layout.h"
35 #include "mozilla/Telemetry.h"
36 #include "mozilla/TimeStamp.h"
37 #include "mozilla/dom/BlobImpl.h"
38 #include "mozilla/dom/ContentChild.h"
39 #include "mozilla/dom/ContentParent.h"
40 #include "mozilla/dom/ContentProcessMessageManager.h"
41 #include "mozilla/dom/Document.h"
42 #include "mozilla/gfx/2D.h"
43 #include "mozilla/ipc/FileDescriptorUtils.h"
44 #include "mozilla/ResultExtensions.h"
45 #include "mozilla/TextUtils.h"
46 #include "mozilla/Unused.h"
48 #include "base/eintr_wrapper.h"
53 using namespace mozilla
;
54 using mozilla::intl::Locale
;
55 using mozilla::intl::LocaleParser
;
56 using mozilla::intl::LocaleService
;
57 using mozilla::intl::OSPreferences
;
59 #define LOG_FONTLIST(args) \
60 MOZ_LOG(gfxPlatform::GetLog(eGfxLog_fontlist), LogLevel::Debug, args)
61 #define LOG_FONTLIST_ENABLED() \
62 MOZ_LOG_TEST(gfxPlatform::GetLog(eGfxLog_fontlist), LogLevel::Debug)
63 #define LOG_FONTINIT(args) \
64 MOZ_LOG(gfxPlatform::GetLog(eGfxLog_fontinit), LogLevel::Debug, args)
65 #define LOG_FONTINIT_ENABLED() \
66 MOZ_LOG_TEST(gfxPlatform::GetLog(eGfxLog_fontinit), LogLevel::Debug)
68 gfxPlatformFontList
* gfxPlatformFontList::sPlatformFontList
= nullptr;
70 // Character ranges that require complex-script shaping support in the font,
71 // and so should be masked out by ReadCMAP if the necessary layout tables
73 // Currently used by the Mac and FT2 implementations only, but probably should
74 // be supported on Windows as well.
75 const gfxFontEntry::ScriptRange
gfxPlatformFontList::sComplexScriptRanges
[] = {
76 // Actually, now that harfbuzz supports presentation-forms shaping for
77 // Arabic, we can render it without layout tables. So maybe we don't
78 // want to mask the basic Arabic block here?
79 // This affects the arabic-fallback-*.html reftests, which rely on
80 // loading a font that *doesn't* have any GSUB table.
81 {0x0600, 0x060B, 1, {TRUETYPE_TAG('a', 'r', 'a', 'b'), 0, 0}},
82 // skip 060C Arabic comma, also used by N'Ko etc
83 {0x060D, 0x061A, 1, {TRUETYPE_TAG('a', 'r', 'a', 'b'), 0, 0}},
84 // skip 061B Arabic semicolon, also used by N'Ko etc
85 {0x061C, 0x061E, 1, {TRUETYPE_TAG('a', 'r', 'a', 'b'), 0, 0}},
86 // skip 061F Arabic question mark, also used by N'Ko etc
87 {0x0620, 0x063F, 1, {TRUETYPE_TAG('a', 'r', 'a', 'b'), 0, 0}},
88 // skip 0640 Arabic tatweel (for syriac, adlam, etc)
89 {0x0641, 0x06D3, 1, {TRUETYPE_TAG('a', 'r', 'a', 'b'), 0, 0}},
90 // skip 06D4 Arabic full stop (for hanifi rohingya)
91 {0x06D5, 0x06FF, 1, {TRUETYPE_TAG('a', 'r', 'a', 'b'), 0, 0}},
92 {0x0700, 0x074F, 1, {TRUETYPE_TAG('s', 'y', 'r', 'c'), 0, 0}},
93 {0x0750, 0x077F, 1, {TRUETYPE_TAG('a', 'r', 'a', 'b'), 0, 0}},
94 {0x08A0, 0x08FF, 1, {TRUETYPE_TAG('a', 'r', 'a', 'b'), 0, 0}},
98 {TRUETYPE_TAG('d', 'e', 'v', '2'), TRUETYPE_TAG('d', 'e', 'v', 'a'), 0}},
99 // skip 0964 DEVANAGARI DANDA and 0965 DEVANAGARI DOUBLE DANDA, shared by
100 // various other Indic writing systems
104 {TRUETYPE_TAG('d', 'e', 'v', '2'), TRUETYPE_TAG('d', 'e', 'v', 'a'), 0}},
108 {TRUETYPE_TAG('b', 'n', 'g', '2'), TRUETYPE_TAG('b', 'e', 'n', 'g'), 0}},
112 {TRUETYPE_TAG('g', 'u', 'r', '2'), TRUETYPE_TAG('g', 'u', 'r', 'u'), 0}},
116 {TRUETYPE_TAG('g', 'j', 'r', '2'), TRUETYPE_TAG('g', 'u', 'j', 'r'), 0}},
120 {TRUETYPE_TAG('o', 'r', 'y', '2'), TRUETYPE_TAG('o', 'r', 'y', 'a'), 0}},
124 {TRUETYPE_TAG('t', 'm', 'l', '2'), TRUETYPE_TAG('t', 'a', 'm', 'l'), 0}},
128 {TRUETYPE_TAG('t', 'e', 'l', '2'), TRUETYPE_TAG('t', 'e', 'l', 'u'), 0}},
132 {TRUETYPE_TAG('k', 'n', 'd', '2'), TRUETYPE_TAG('k', 'n', 'd', 'a'), 0}},
136 {TRUETYPE_TAG('m', 'l', 'm', '2'), TRUETYPE_TAG('m', 'l', 'y', 'm'), 0}},
137 {0x0D80, 0x0DFF, 1, {TRUETYPE_TAG('s', 'i', 'n', 'h'), 0, 0}},
138 {0x0E80, 0x0EFF, 1, {TRUETYPE_TAG('l', 'a', 'o', ' '), 0, 0}},
139 {0x0F00, 0x0FFF, 1, {TRUETYPE_TAG('t', 'i', 'b', 't'), 0, 0}},
143 {TRUETYPE_TAG('m', 'y', 'm', 'r'), TRUETYPE_TAG('m', 'y', 'm', '2'), 0}},
144 {0x1780, 0x17ff, 1, {TRUETYPE_TAG('k', 'h', 'm', 'r'), 0, 0}},
145 // Khmer Symbols (19e0..19ff) don't seem to need any special shaping
149 {TRUETYPE_TAG('m', 'y', 'm', 'r'), TRUETYPE_TAG('m', 'y', 'm', '2'), 0}},
150 // Thai seems to be "renderable" without AAT morphing tables
151 {0, 0, 0, {0, 0, 0}} // terminator
154 static const char* kObservedPrefs
[] = {
155 "font.", "font.name-list.", "intl.accept_languages", // hmmmm...
156 "browser.display.use_document_fonts.icon_font_allowlist", nullptr};
158 static const char kFontSystemWhitelistPref
[] = "font.system.whitelist";
160 static const char kCJKFallbackOrderPref
[] = "font.cjk_pref_fallback_order";
162 // Pref for the list of icon font families that still get to override the
163 // default font from prefs, even when use_document_fonts is disabled.
164 // (This is to enable ligature-based icon fonts to keep working.)
165 static const char kIconFontsPref
[] =
166 "browser.display.use_document_fonts.icon_font_allowlist";
168 // xxx - this can probably be eliminated by reworking pref font handling code
169 static const char* gPrefLangNames
[] = {
170 #define FONT_PREF_LANG(enum_id_, str_, atom_id_) str_
171 #include "gfxFontPrefLangList.h"
172 #undef FONT_PREF_LANG
175 static_assert(MOZ_ARRAY_LENGTH(gPrefLangNames
) == uint32_t(eFontPrefLang_Count
),
176 "size of pref lang name array doesn't match pref lang enum size");
178 class gfxFontListPrefObserver final
: public nsIObserver
{
179 ~gfxFontListPrefObserver() = default;
186 static void FontListPrefChanged(const char* aPref
, void* aData
= nullptr) {
187 // XXX this could be made to only clear out the cache for the prefs that were
188 // changed but it probably isn't that big a deal.
189 gfxPlatformFontList::PlatformFontList()->ClearLangGroupPrefFonts();
190 gfxPlatformFontList::PlatformFontList()->LoadIconFontOverrideList();
191 gfxFontCache::GetCache()->Flush();
194 static gfxFontListPrefObserver
* gFontListPrefObserver
= nullptr;
196 NS_IMPL_ISUPPORTS(gfxFontListPrefObserver
, nsIObserver
)
198 #define LOCALES_CHANGED_TOPIC "intl:system-locales-changed"
201 gfxFontListPrefObserver::Observe(nsISupports
* aSubject
, const char* aTopic
,
202 const char16_t
* aData
) {
203 NS_ASSERTION(!strcmp(aTopic
, LOCALES_CHANGED_TOPIC
), "invalid topic");
204 FontListPrefChanged(nullptr);
206 if (XRE_IsParentProcess()) {
207 gfxPlatform::ForceGlobalReflow(gfxPlatform::NeedsReframe::No
);
212 MOZ_DEFINE_MALLOC_SIZE_OF(FontListMallocSizeOf
)
214 NS_IMPL_ISUPPORTS(gfxPlatformFontList::MemoryReporter
, nsIMemoryReporter
)
217 gfxPlatformFontList::MemoryReporter::CollectReports(
218 nsIHandleReportCallback
* aHandleReport
, nsISupports
* aData
,
221 sizes
.mFontListSize
= 0;
222 sizes
.mFontTableCacheSize
= 0;
223 sizes
.mCharMapsSize
= 0;
224 sizes
.mLoaderSize
= 0;
225 sizes
.mSharedSize
= 0;
227 gfxPlatformFontList::PlatformFontList()->AddSizeOfIncludingThis(
228 &FontListMallocSizeOf
, &sizes
);
231 "explicit/gfx/font-list", KIND_HEAP
, UNITS_BYTES
, sizes
.mFontListSize
,
232 "Memory used to manage the list of font families and faces.");
235 "explicit/gfx/font-charmaps", KIND_HEAP
, UNITS_BYTES
, sizes
.mCharMapsSize
,
236 "Memory used to record the character coverage of individual fonts.");
238 if (sizes
.mFontTableCacheSize
) {
240 "explicit/gfx/font-tables", KIND_HEAP
, UNITS_BYTES
,
241 sizes
.mFontTableCacheSize
,
242 "Memory used for cached font metrics and layout tables.");
245 if (sizes
.mLoaderSize
) {
246 MOZ_COLLECT_REPORT("explicit/gfx/font-loader", KIND_HEAP
, UNITS_BYTES
,
248 "Memory used for (platform-specific) font loader.");
251 if (sizes
.mSharedSize
) {
253 "font-list-shmem", KIND_NONHEAP
, UNITS_BYTES
, sizes
.mSharedSize
,
254 "Shared memory for system font list and character coverage data.");
260 PRThread
* gfxPlatformFontList::sInitFontListThread
= nullptr;
262 static void InitFontListCallback(void* aFontList
) {
263 AUTO_PROFILER_REGISTER_THREAD("InitFontList");
264 PR_SetCurrentThreadName("InitFontList");
266 if (!static_cast<gfxPlatformFontList
*>(aFontList
)->InitFontList()) {
267 gfxPlatformFontList::Shutdown();
272 bool gfxPlatformFontList::Initialize(gfxPlatformFontList
* aList
) {
273 sPlatformFontList
= aList
;
274 if (XRE_IsParentProcess() &&
275 StaticPrefs::gfx_font_list_omt_enabled_AtStartup() &&
276 StaticPrefs::gfx_e10s_font_list_shared_AtStartup() &&
277 !gfxPlatform::InSafeMode()) {
278 sInitFontListThread
= PR_CreateThread(
279 PR_USER_THREAD
, InitFontListCallback
, aList
, PR_PRIORITY_NORMAL
,
280 PR_GLOBAL_THREAD
, PR_JOINABLE_THREAD
, 0);
283 if (aList
->InitFontList()) {
290 gfxPlatformFontList::gfxPlatformFontList(bool aNeedFullnamePostscriptNames
)
291 : mLock("gfxPlatformFontList lock"),
293 mOtherFamilyNames(16),
295 if (aNeedFullnamePostscriptNames
) {
296 mExtraNames
= MakeUnique
<ExtraNames
>();
299 mLangService
= nsLanguageAtomService::GetService();
301 LoadBadUnderlineList();
302 LoadIconFontOverrideList();
304 mFontPrefs
= MakeUnique
<FontPrefs
>();
306 gfxFontUtils::GetPrefsFontList(kFontSystemWhitelistPref
, mEnabledFontsList
);
307 mFontFamilyWhitelistActive
= !mEnabledFontsList
.IsEmpty();
309 // pref changes notification setup
310 NS_ASSERTION(!gFontListPrefObserver
,
311 "There has been font list pref observer already");
312 gFontListPrefObserver
= new gfxFontListPrefObserver();
313 NS_ADDREF(gFontListPrefObserver
);
315 Preferences::RegisterPrefixCallbacks(FontListPrefChanged
, kObservedPrefs
);
317 nsCOMPtr
<nsIObserverService
> obs
= services::GetObserverService();
319 obs
->AddObserver(gFontListPrefObserver
, LOCALES_CHANGED_TOPIC
, false);
322 // Only the parent process listens for whitelist changes; it will then
323 // notify its children to rebuild their font lists.
324 if (XRE_IsParentProcess()) {
325 Preferences::RegisterCallback(FontWhitelistPrefChanged
,
326 kFontSystemWhitelistPref
);
329 RegisterStrongMemoryReporter(new MemoryReporter());
331 // initialize lang group pref font defaults (i.e. serif/sans-serif)
332 mDefaultGenericsLangGroup
.AppendElements(ArrayLength(gPrefLangNames
));
333 for (uint32_t i
= 0; i
< ArrayLength(gPrefLangNames
); i
++) {
334 nsAutoCString
prefDefaultFontType("font.default.");
335 prefDefaultFontType
.Append(GetPrefLangName(eFontPrefLang(i
)));
336 nsAutoCString serifOrSans
;
337 Preferences::GetCString(prefDefaultFontType
.get(), serifOrSans
);
338 if (serifOrSans
.EqualsLiteral("sans-serif")) {
339 mDefaultGenericsLangGroup
[i
] = StyleGenericFontFamily::SansSerif
;
341 mDefaultGenericsLangGroup
[i
] = StyleGenericFontFamily::Serif
;
346 gfxPlatformFontList::~gfxPlatformFontList() {
347 // Note that gfxPlatformFontList::Shutdown() ensures that the init-font-list
348 // thread is finished before we come here.
350 AutoLock
lock(mLock
);
352 // We can't just do mSharedCmaps.Clear() here because removing each item from
353 // the table would drop its last reference, and its Release() method would
354 // then call back to MaybeRemoveCmap to search for it, which we can't do
355 // while in the middle of clearing the table.
356 // So we first clear the "shared" flag in each entry, so Release() won't try
357 // to re-find them in the table.
358 for (auto iter
= mSharedCmaps
.ConstIter(); !iter
.Done(); iter
.Next()) {
359 iter
.Get()->mCharMap
->ClearSharedFlag();
361 mSharedCmaps
.Clear();
363 ClearLangGroupPrefFontsLocked();
365 NS_ASSERTION(gFontListPrefObserver
, "There is no font list pref observer");
367 Preferences::UnregisterPrefixCallbacks(FontListPrefChanged
, kObservedPrefs
);
369 nsCOMPtr
<nsIObserverService
> obs
= services::GetObserverService();
371 obs
->RemoveObserver(gFontListPrefObserver
, LOCALES_CHANGED_TOPIC
);
374 if (XRE_IsParentProcess()) {
375 Preferences::UnregisterCallback(FontWhitelistPrefChanged
,
376 kFontSystemWhitelistPref
);
378 NS_RELEASE(gFontListPrefObserver
);
381 void gfxPlatformFontList::GetMissingFonts(nsCString
& aMissingFonts
) {
382 AutoLock
lock(mLock
);
384 auto fontLists
= GetFilteredPlatformFontLists();
386 if (!fontLists
.Length()) {
387 aMissingFonts
.Append("No font list available for this device.");
390 for (unsigned int i
= 0; i
< fontLists
.Length(); i
++) {
391 for (unsigned int j
= 0; j
< fontLists
[i
].second
; j
++) {
392 nsCString
key(fontLists
[i
].first
[j
]);
393 GenerateFontListKey(key
);
395 if (SharedFontList()) {
396 fontlist::Family
* family
= SharedFontList()->FindFamily(key
);
398 aMissingFonts
.Append(fontLists
[i
].first
[j
]);
399 aMissingFonts
.Append("|");
402 gfxFontFamily
* familyEntry
= mFontFamilies
.GetWeak(key
);
404 familyEntry
= mOtherFamilyNames
.GetWeak(key
);
407 aMissingFonts
.Append(fontLists
[i
].first
[j
]);
408 aMissingFonts
.Append("|");
416 void gfxPlatformFontList::FontWhitelistPrefChanged(const char* aPref
,
418 MOZ_ASSERT(XRE_IsParentProcess());
419 auto* pfl
= gfxPlatformFontList::PlatformFontList();
420 pfl
->UpdateFontList(true);
421 dom::ContentParent::NotifyUpdatedFonts(true);
424 void gfxPlatformFontList::ApplyWhitelist() {
425 uint32_t numFonts
= mEnabledFontsList
.Length();
426 if (!mFontFamilyWhitelistActive
) {
429 nsTHashSet
<nsCString
> familyNamesWhitelist
;
430 for (uint32_t i
= 0; i
< numFonts
; i
++) {
432 ToLowerCase(mEnabledFontsList
[i
], key
);
433 familyNamesWhitelist
.Insert(key
);
435 AutoTArray
<RefPtr
<gfxFontFamily
>, 128> accepted
;
436 bool whitelistedFontFound
= false;
437 for (const auto& entry
: mFontFamilies
) {
438 nsAutoCString
fontFamilyName(entry
.GetKey());
439 ToLowerCase(fontFamilyName
);
440 if (familyNamesWhitelist
.Contains(fontFamilyName
)) {
441 accepted
.AppendElement(entry
.GetData());
442 whitelistedFontFound
= true;
445 if (!whitelistedFontFound
) {
446 // No whitelisted fonts found! Ignore the whitelist.
449 // Replace the original full list with the accepted subset.
450 mFontFamilies
.Clear();
451 for (auto& f
: accepted
) {
452 nsAutoCString
fontFamilyName(f
->Name());
453 ToLowerCase(fontFamilyName
);
454 mFontFamilies
.InsertOrUpdate(fontFamilyName
, std::move(f
));
458 void gfxPlatformFontList::ApplyWhitelist(
459 nsTArray
<fontlist::Family::InitData
>& aFamilies
) {
460 mLock
.AssertCurrentThreadIn();
461 if (!mFontFamilyWhitelistActive
) {
464 nsTHashSet
<nsCString
> familyNamesWhitelist
;
465 for (const auto& item
: mEnabledFontsList
) {
467 ToLowerCase(item
, key
);
468 familyNamesWhitelist
.Insert(key
);
470 AutoTArray
<fontlist::Family::InitData
, 128> accepted
;
471 bool keptNonHidden
= false;
472 for (auto& f
: aFamilies
) {
473 if (familyNamesWhitelist
.Contains(f
.mKey
)) {
474 accepted
.AppendElement(f
);
475 if (f
.mVisibility
!= FontVisibility::Hidden
) {
476 keptNonHidden
= true;
480 if (!keptNonHidden
) {
481 // No (visible) families were whitelisted: ignore the whitelist
482 // and just leave the fontlist unchanged.
485 aFamilies
= std::move(accepted
);
488 bool gfxPlatformFontList::FamilyInList(const nsACString
& aName
,
489 const char* aList
[], size_t aCount
) {
491 return BinarySearchIf(
493 [&](const char* const aVal
) -> int {
494 return nsCaseInsensitiveUTF8StringComparator(
495 aName
.BeginReading(), aVal
, aName
.Length(), strlen(aVal
));
500 void gfxPlatformFontList::CheckFamilyList(const char* aList
[], size_t aCount
) {
502 MOZ_ASSERT(aCount
> 0, "empty font family list?");
503 const char* a
= aList
[0];
504 uint32_t aLen
= strlen(a
);
505 for (size_t i
= 1; i
< aCount
; ++i
) {
506 const char* b
= aList
[i
];
507 uint32_t bLen
= strlen(b
);
508 if (nsCaseInsensitiveUTF8StringComparator(a
, b
, aLen
, bLen
) >= 0) {
509 MOZ_CRASH_UNSAFE_PRINTF("incorrectly sorted font family list: %s >= %s",
518 bool gfxPlatformFontList::AddWithLegacyFamilyName(const nsACString
& aLegacyName
,
519 gfxFontEntry
* aFontEntry
,
520 FontVisibility aVisibility
) {
521 mLock
.AssertCurrentThreadIn();
524 ToLowerCase(aLegacyName
, key
);
526 .LookupOrInsertWith(key
,
528 RefPtr
<gfxFontFamily
> family
=
529 CreateFontFamily(aLegacyName
, aVisibility
);
530 // We don't want the family to search for faces,
531 // we're adding them directly here.
532 family
->SetHasStyles(true);
533 // And we don't want it to attempt to search for
534 // legacy names, because we've already done that
535 // (and this is the result).
536 family
->SetCheckedForLegacyFamilyNames(true);
540 ->AddFontEntry(aFontEntry
->Clone());
544 bool gfxPlatformFontList::InitFontList() {
545 // If the startup font-list-init thread is still running, we need to wait
546 // for it to finish before trying to reinitialize here.
547 if (sInitFontListThread
&& !IsInitFontListThread()) {
548 PR_JoinThread(sInitFontListThread
);
549 sInitFontListThread
= nullptr;
552 AutoLock
lock(mLock
);
554 if (LOG_FONTINIT_ENABLED()) {
555 LOG_FONTINIT(("(fontinit) system fontlist initialization\n"));
558 if (IsInitialized()) {
559 // Font-list reinitialization always occurs on the main thread, in response
560 // to a change notification; it's only the initial creation during startup
561 // that may be on another thread.
562 MOZ_ASSERT(NS_IsMainThread());
564 // Rebuilding fontlist so clear out font/word caches.
565 gfxFontCache
* fontCache
= gfxFontCache::GetCache();
567 fontCache
->FlushShapedWordCaches();
571 gfxPlatform::PurgeSkiaFontCache();
573 // There's no need to broadcast this reflow request to child processes, as
574 // ContentParent::NotifyUpdatedFonts deals with it by re-entering into this
575 // function on child processes.
576 ForceGlobalReflowLocked(gfxPlatform::NeedsReframe::Yes
,
577 gfxPlatform::BroadcastToChildren::No
);
580 mLocalNameTable
.Clear();
581 mIconFontsSet
.Clear();
583 CancelLoadCmapsTask();
584 mStartedLoadingCmapsFrom
= 0xffffffffu
;
586 CancelInitOtherFamilyNamesTask();
587 mFontFamilies
.Clear();
588 mOtherFamilyNames
.Clear();
589 mOtherFamilyNamesInitialized
= false;
592 mExtraNames
->mFullnames
.Clear();
593 mExtraNames
->mPostscriptNames
.Clear();
595 mFaceNameListsInitialized
= false;
596 ClearLangGroupPrefFontsLocked();
599 // Clear cached family records that will no longer be valid.
600 for (auto& f
: mReplacementCharFallbackFamily
) {
604 gfxFontUtils::GetPrefsFontList(kFontSystemWhitelistPref
, mEnabledFontsList
);
605 mFontFamilyWhitelistActive
= !mEnabledFontsList
.IsEmpty();
607 LoadIconFontOverrideList();
610 // From here, gfxPlatformFontList::IsInitialized will return true,
611 // unless InitFontListForPlatform() fails and we reset it below.
612 mFontlistInitCount
++;
614 InitializeCodepointsWithNoFonts();
616 // Try to initialize the cross-process shared font list if enabled by prefs,
617 // but not if we're running in Safe Mode.
618 if (StaticPrefs::gfx_e10s_font_list_shared_AtStartup() &&
619 !gfxPlatform::InSafeMode()) {
620 for (const auto& entry
: mFontEntries
.Values()) {
624 AutoWriteLock
lock(entry
->mLock
);
625 entry
->mShmemCharacterMap
= nullptr;
626 entry
->mShmemFace
= nullptr;
627 entry
->mFamilyName
.Truncate();
629 mFontEntries
.Clear();
630 mShmemCharMaps
.Clear();
631 bool oldSharedList
= mSharedFontList
!= nullptr;
632 mSharedFontList
.reset(new fontlist::FontList(mFontlistInitCount
));
633 InitSharedFontListForPlatform();
634 if (mSharedFontList
&& mSharedFontList
->Initialized()) {
635 if (mLocalNameTable
.Count()) {
636 SharedFontList()->SetLocalNames(mLocalNameTable
);
637 mLocalNameTable
.Clear();
640 // something went wrong, fall back to in-process list
641 gfxCriticalNote
<< "Failed to initialize shared font list, "
642 "falling back to in-process list.";
643 mSharedFontList
.reset(nullptr);
645 if (oldSharedList
&& XRE_IsParentProcess()) {
646 // notify all children of the change
647 if (NS_IsMainThread()) {
648 dom::ContentParent::NotifyUpdatedFonts(true);
650 NS_DispatchToMainThread(NS_NewRunnableFunction(
651 "NotifyUpdatedFonts callback",
652 [] { dom::ContentParent::NotifyUpdatedFonts(true); }));
657 if (!SharedFontList()) {
658 if (NS_FAILED(InitFontListForPlatform())) {
659 mFontlistInitCount
= 0;
665 // Set up mDefaultFontEntry as a "last resort" default that we can use
666 // to avoid crashing if the font list is otherwise unusable.
667 gfxFontStyle defStyle
;
668 FontFamily fam
= GetDefaultFontLocked(nullptr, &defStyle
);
671 auto face
= fam
.mShared
->FindFaceForStyle(SharedFontList(), defStyle
);
672 fe
= face
? GetOrCreateFontEntryLocked(face
, fam
.mShared
) : nullptr;
674 fe
= fam
.mUnshared
->FindFontForStyle(defStyle
);
676 mDefaultFontEntry
= fe
;
681 void gfxPlatformFontList::LoadIconFontOverrideList() {
682 mIconFontsSet
.Clear();
683 AutoTArray
<nsCString
, 20> iconFontsList
;
684 gfxFontUtils::GetPrefsFontList(kIconFontsPref
, iconFontsList
);
685 for (auto& name
: iconFontsList
) {
687 mIconFontsSet
.Insert(name
);
691 void gfxPlatformFontList::InitializeCodepointsWithNoFonts() {
692 auto& first
= mCodepointsWithNoFonts
[FontVisibility(0)];
693 for (auto& bitset
: mCodepointsWithNoFonts
) {
694 if (&bitset
== &first
) {
696 bitset
.SetRange(0, 0x1f); // C0 controls
697 bitset
.SetRange(0x7f, 0x9f); // C1 controls
698 bitset
.SetRange(0xE000, 0xF8FF); // PUA
699 bitset
.SetRange(0xF0000, 0x10FFFD); // Supplementary PUA
700 bitset
.SetRange(0xfdd0, 0xfdef); // noncharacters
701 for (unsigned i
= 0; i
<= 0x100000; i
+= 0x10000) {
702 bitset
.SetRange(i
+ 0xfffe, i
+ 0xffff); // noncharacters
711 void gfxPlatformFontList::FontListChanged() {
712 MOZ_ASSERT(!XRE_IsParentProcess());
713 AutoLock
lock(mLock
);
714 InitializeCodepointsWithNoFonts();
715 if (SharedFontList()) {
716 // If we're using a shared local face-name list, this may have changed
717 // such that existing font entries held by user font sets are no longer
718 // safe to use: ensure they all get flushed.
719 RebuildLocalFonts(/*aForgetLocalFaces*/ true);
721 ForceGlobalReflowLocked(gfxPlatform::NeedsReframe::Yes
);
724 void gfxPlatformFontList::GenerateFontListKey(const nsACString
& aKeyName
,
725 nsACString
& aResult
) {
727 ToLowerCase(aResult
);
730 void gfxPlatformFontList::GenerateFontListKey(nsACString
& aKeyName
) {
731 ToLowerCase(aKeyName
);
734 // Used if a stylo thread wants to trigger InitOtherFamilyNames in the main
735 // process: we can't do IPC from the stylo thread so we post this to the main
737 class InitOtherFamilyNamesForStylo
: public mozilla::Runnable
{
739 explicit InitOtherFamilyNamesForStylo(bool aDeferOtherFamilyNamesLoading
)
740 : Runnable("gfxPlatformFontList::InitOtherFamilyNamesForStylo"),
741 mDefer(aDeferOtherFamilyNamesLoading
) {}
743 NS_IMETHOD
Run() override
{
744 auto pfl
= gfxPlatformFontList::PlatformFontList();
745 auto list
= pfl
->SharedFontList();
749 bool initialized
= false;
750 dom::ContentChild::GetSingleton()->SendInitOtherFamilyNames(
751 list
->GetGeneration(), mDefer
, &initialized
);
752 pfl
->mOtherFamilyNamesInitialized
.compareExchange(false, initialized
);
760 #define OTHERNAMES_TIMEOUT 200
762 bool gfxPlatformFontList::InitOtherFamilyNames(
763 bool aDeferOtherFamilyNamesLoading
) {
764 if (mOtherFamilyNamesInitialized
) {
768 if (SharedFontList() && !XRE_IsParentProcess()) {
769 if (NS_IsMainThread()) {
771 dom::ContentChild::GetSingleton()->SendInitOtherFamilyNames(
772 SharedFontList()->GetGeneration(), aDeferOtherFamilyNamesLoading
,
774 mOtherFamilyNamesInitialized
.compareExchange(false, initialized
);
776 NS_DispatchToMainThread(
777 new InitOtherFamilyNamesForStylo(aDeferOtherFamilyNamesLoading
));
779 return mOtherFamilyNamesInitialized
;
782 // If the font loader delay has been set to zero, we don't defer loading
783 // additional family names (regardless of the aDefer... parameter), as we
784 // take this to mean availability of font info is to be prioritized over
785 // potential startup perf or main-thread jank.
786 // (This is used so we can reliably run reftests that depend on localized
787 // font-family names being available.)
788 if (aDeferOtherFamilyNamesLoading
&&
789 StaticPrefs::gfx_font_loader_delay() > 0) {
790 if (!mPendingOtherFamilyNameTask
) {
791 RefPtr
<mozilla::CancelableRunnable
> task
=
792 new InitOtherFamilyNamesRunnable();
793 mPendingOtherFamilyNameTask
= task
;
794 NS_DispatchToMainThreadQueue(task
.forget(), EventQueuePriority::Idle
);
797 InitOtherFamilyNamesInternal(false);
799 return mOtherFamilyNamesInitialized
;
802 // time limit for loading facename lists (ms)
803 #define NAMELIST_TIMEOUT 200
805 gfxFontEntry
* gfxPlatformFontList::SearchFamiliesForFaceName(
806 const nsACString
& aFaceName
) {
807 TimeStamp start
= TimeStamp::Now();
808 bool timedOut
= false;
809 // if mFirstChar is not 0, only load facenames for families
810 // that start with this character
811 char16_t firstChar
= 0;
812 gfxFontEntry
* lookup
= nullptr;
814 // iterate over familes starting with the same letter
815 firstChar
= ToLowerCase(aFaceName
.CharAt(0));
817 for (const auto& entry
: mFontFamilies
) {
818 nsCStringHashKey::KeyType key
= entry
.GetKey();
819 const RefPtr
<gfxFontFamily
>& family
= entry
.GetData();
821 // when filtering, skip names that don't start with the filter character
822 if (firstChar
&& ToLowerCase(key
.CharAt(0)) != firstChar
) {
826 family
->ReadFaceNames(this, NeedFullnamePostscriptNames());
828 TimeDuration elapsed
= TimeStamp::Now() - start
;
829 if (elapsed
.ToMilliseconds() > NAMELIST_TIMEOUT
) {
835 lookup
= FindFaceName(aFaceName
);
837 TimeStamp end
= TimeStamp::Now();
838 Telemetry::AccumulateTimeDelta(Telemetry::FONTLIST_INITFACENAMELISTS
, start
,
840 if (LOG_FONTINIT_ENABLED()) {
841 TimeDuration elapsed
= end
- start
;
842 LOG_FONTINIT(("(fontinit) SearchFamiliesForFaceName took %8.2f ms %s %s",
843 elapsed
.ToMilliseconds(), (lookup
? "found name" : ""),
844 (timedOut
? "timeout" : "")));
850 gfxFontEntry
* gfxPlatformFontList::FindFaceName(const nsACString
& aFaceName
) {
851 gfxFontEntry
* lookup
;
853 // lookup in name lookup tables, return null if not found
855 ((lookup
= mExtraNames
->mPostscriptNames
.GetWeak(aFaceName
)) ||
856 (lookup
= mExtraNames
->mFullnames
.GetWeak(aFaceName
)))) {
863 gfxFontEntry
* gfxPlatformFontList::LookupInFaceNameLists(
864 const nsACString
& aFaceName
) {
865 gfxFontEntry
* lookup
= nullptr;
867 // initialize facename lookup tables if needed
868 // note: this can terminate early or time out, in which case
869 // mFaceNameListsInitialized remains false
870 if (!mFaceNameListsInitialized
) {
871 lookup
= SearchFamiliesForFaceName(aFaceName
);
877 // lookup in name lookup tables, return null if not found
878 if (!(lookup
= FindFaceName(aFaceName
))) {
879 // names not completely initialized, so keep track of lookup misses
880 if (!mFaceNameListsInitialized
) {
881 if (!mFaceNamesMissed
) {
882 mFaceNamesMissed
= MakeUnique
<nsTHashSet
<nsCString
>>(2);
884 mFaceNamesMissed
->Insert(aFaceName
);
891 gfxFontEntry
* gfxPlatformFontList::LookupInSharedFaceNameList(
892 nsPresContext
* aPresContext
, const nsACString
& aFaceName
,
893 WeightRange aWeightForEntry
, StretchRange aStretchForEntry
,
894 SlantStyleRange aStyleForEntry
) {
895 nsAutoCString
keyName(aFaceName
);
896 ToLowerCase(keyName
);
897 fontlist::FontList
* list
= SharedFontList();
898 fontlist::Family
* family
= nullptr;
899 fontlist::Face
* face
= nullptr;
900 if (list
->NumLocalFaces()) {
901 fontlist::LocalFaceRec
* rec
= list
->FindLocalFace(keyName
);
903 auto* families
= list
->Families();
905 family
= &families
[rec
->mFamilyIndex
];
906 face
= family
->Faces(list
)[rec
->mFaceIndex
].ToPtr
<fontlist::Face
>(list
);
910 list
->SearchForLocalFace(keyName
, &family
, &face
);
912 if (!face
|| !family
) {
915 FontVisibility level
=
916 aPresContext
? aPresContext
->GetFontVisibility() : FontVisibility::User
;
917 if (!IsVisibleToCSS(*family
, level
)) {
919 aPresContext
->ReportBlockedFontFamily(*family
);
923 gfxFontEntry
* fe
= CreateFontEntry(face
, family
);
925 fe
->mIsLocalUserFont
= true;
926 fe
->mWeightRange
= aWeightForEntry
;
927 fe
->mStretchRange
= aStretchForEntry
;
928 fe
->mStyleRange
= aStyleForEntry
;
933 void gfxPlatformFontList::LoadBadUnderlineList() {
934 gfxFontUtils::GetPrefsFontList("font.blacklist.underline_offset",
935 mBadUnderlineFamilyNames
);
936 for (auto& fam
: mBadUnderlineFamilyNames
) {
939 mBadUnderlineFamilyNames
.Compact();
940 mBadUnderlineFamilyNames
.Sort();
943 void gfxPlatformFontList::UpdateFontList(bool aFullRebuild
) {
944 MOZ_ASSERT(NS_IsMainThread());
947 AutoLock
lock(mLock
);
950 // The font list isn't being fully rebuilt, we're just being notified that
951 // character maps have been updated and so font fallback needs to be re-
952 // done. We only care about this if we have previously encountered a
953 // fallback that required cmaps that were not yet available, and so we
954 // asked for the async cmap loader to run.
955 AutoLock
lock(mLock
);
956 if (mStartedLoadingCmapsFrom
!= 0xffffffffu
) {
957 InitializeCodepointsWithNoFonts();
958 mStartedLoadingCmapsFrom
= 0xffffffffu
;
959 ForceGlobalReflowLocked(gfxPlatform::NeedsReframe::No
);
964 bool gfxPlatformFontList::IsVisibleToCSS(const gfxFontFamily
& aFamily
,
965 FontVisibility aVisibility
) const {
966 return aFamily
.Visibility() <= aVisibility
|| IsFontFamilyWhitelistActive();
969 bool gfxPlatformFontList::IsVisibleToCSS(const fontlist::Family
& aFamily
,
970 FontVisibility aVisibility
) const {
971 return aFamily
.Visibility() <= aVisibility
|| IsFontFamilyWhitelistActive();
974 void gfxPlatformFontList::GetFontList(nsAtom
* aLangGroup
,
975 const nsACString
& aGenericFamily
,
976 nsTArray
<nsString
>& aListOfFonts
) {
977 AutoLock
lock(mLock
);
979 if (SharedFontList()) {
980 fontlist::FontList
* list
= SharedFontList();
981 const fontlist::Family
* families
= list
->Families();
983 for (uint32_t i
= 0; i
< list
->NumFamilies(); i
++) {
984 auto& f
= families
[i
];
985 if (!IsVisibleToCSS(f
, FontVisibility::User
) || f
.IsAltLocaleFamily()) {
988 // XXX TODO: filter families for aGenericFamily, if supported by
990 aListOfFonts
.AppendElement(
991 NS_ConvertUTF8toUTF16(list
->LocalizedFamilyName(&f
)));
997 for (const RefPtr
<gfxFontFamily
>& family
: mFontFamilies
.Values()) {
998 if (!IsVisibleToCSS(*family
, FontVisibility::User
)) {
1001 if (family
->FilterForFontList(aLangGroup
, aGenericFamily
)) {
1002 nsAutoCString localizedFamilyName
;
1003 family
->LocalizedName(localizedFamilyName
);
1004 aListOfFonts
.AppendElement(NS_ConvertUTF8toUTF16(localizedFamilyName
));
1008 aListOfFonts
.Sort();
1009 aListOfFonts
.Compact();
1012 void gfxPlatformFontList::GetFontFamilyList(
1013 nsTArray
<RefPtr
<gfxFontFamily
>>& aFamilyArray
) {
1014 AutoLock
lock(mLock
);
1015 MOZ_ASSERT(aFamilyArray
.IsEmpty());
1016 // This doesn't use ToArray, because the caller passes an AutoTArray.
1017 aFamilyArray
.SetCapacity(mFontFamilies
.Count());
1018 for (const auto& family
: mFontFamilies
.Values()) {
1019 aFamilyArray
.AppendElement(family
);
1023 already_AddRefed
<gfxFont
> gfxPlatformFontList::SystemFindFontForChar(
1024 nsPresContext
* aPresContext
, uint32_t aCh
, uint32_t aNextCh
,
1025 Script aRunScript
, eFontPresentation aPresentation
,
1026 const gfxFontStyle
* aStyle
, FontVisibility
* aVisibility
) {
1027 AutoLock
lock(mLock
);
1028 FontVisibility level
=
1029 aPresContext
? aPresContext
->GetFontVisibility() : FontVisibility::User
;
1030 MOZ_ASSERT(!mCodepointsWithNoFonts
[level
].test(aCh
),
1031 "don't call for codepoints already known to be unsupported");
1033 // Try to short-circuit font fallback for U+FFFD, used to represent
1034 // encoding errors: just use cached family from last time U+FFFD was seen.
1035 // This helps speed up pages with lots of encoding errors, binary-as-text,
1037 if (aCh
== 0xFFFD) {
1038 gfxFontEntry
* fontEntry
= nullptr;
1039 auto& fallbackFamily
= mReplacementCharFallbackFamily
[level
];
1040 if (fallbackFamily
.mShared
) {
1041 fontlist::Face
* face
=
1042 fallbackFamily
.mShared
->FindFaceForStyle(SharedFontList(), *aStyle
);
1044 fontEntry
= GetOrCreateFontEntryLocked(face
, fallbackFamily
.mShared
);
1045 *aVisibility
= fallbackFamily
.mShared
->Visibility();
1047 } else if (fallbackFamily
.mUnshared
) {
1048 fontEntry
= fallbackFamily
.mUnshared
->FindFontForStyle(*aStyle
);
1049 *aVisibility
= fallbackFamily
.mUnshared
->Visibility();
1052 // this should never fail, as we must have found U+FFFD in order to set
1053 // mReplacementCharFallbackFamily[...] at all, but better play it safe
1054 if (fontEntry
&& fontEntry
->HasCharacter(aCh
)) {
1055 return fontEntry
->FindOrMakeFont(aStyle
);
1059 TimeStamp start
= TimeStamp::Now();
1061 // search commonly available fonts
1063 FontFamily fallbackFamily
;
1064 RefPtr
<gfxFont
> candidate
=
1065 CommonFontFallback(aPresContext
, aCh
, aNextCh
, aRunScript
, aPresentation
,
1066 aStyle
, fallbackFamily
);
1067 RefPtr
<gfxFont
> font
;
1069 if (aPresentation
== eFontPresentation::Any
) {
1070 font
= std::move(candidate
);
1072 bool hasColorGlyph
= candidate
->HasColorGlyphFor(aCh
, aNextCh
);
1073 if (hasColorGlyph
== PrefersColor(aPresentation
)) {
1074 font
= std::move(candidate
);
1079 // If we didn't find a common font, or it was not the preferred type (color
1080 // or monochrome), do system-wide fallback (except for specials).
1081 uint32_t cmapCount
= 0;
1084 font
= GlobalFontFallback(aPresContext
, aCh
, aNextCh
, aRunScript
,
1085 aPresentation
, aStyle
, cmapCount
, fallbackFamily
);
1086 // If the font we found doesn't match the requested type, and we also found
1087 // a candidate above, prefer that one.
1088 if (font
&& aPresentation
!= eFontPresentation::Any
&& candidate
) {
1089 bool hasColorGlyph
= font
->HasColorGlyphFor(aCh
, aNextCh
);
1090 if (hasColorGlyph
!= PrefersColor(aPresentation
)) {
1091 font
= std::move(candidate
);
1095 TimeDuration elapsed
= TimeStamp::Now() - start
;
1097 LogModule
* log
= gfxPlatform::GetLog(eGfxLog_textrun
);
1099 if (MOZ_UNLIKELY(MOZ_LOG_TEST(log
, LogLevel::Warning
))) {
1100 Script script
= intl::UnicodeProperties::GetScriptCode(aCh
);
1101 MOZ_LOG(log
, LogLevel::Warning
,
1102 ("(textrun-systemfallback-%s) char: u+%6.6x "
1103 "script: %d match: [%s]"
1104 " time: %dus cmaps: %d\n",
1105 (common
? "common" : "global"), aCh
, static_cast<int>(script
),
1106 (font
? font
->GetFontEntry()->Name().get() : "<none>"),
1107 int32_t(elapsed
.ToMicroseconds()), cmapCount
));
1110 // no match? add to set of non-matching codepoints
1112 mCodepointsWithNoFonts
[level
].set(aCh
);
1114 *aVisibility
= fallbackFamily
.mShared
1115 ? fallbackFamily
.mShared
->Visibility()
1116 : fallbackFamily
.mUnshared
->Visibility();
1117 if (aCh
== 0xFFFD) {
1118 mReplacementCharFallbackFamily
[level
] = fallbackFamily
;
1122 // track system fallback time
1123 static bool first
= true;
1124 int32_t intElapsed
=
1125 int32_t(first
? elapsed
.ToMilliseconds() : elapsed
.ToMicroseconds());
1126 Telemetry::Accumulate((first
? Telemetry::SYSTEM_FONT_FALLBACK_FIRST
1127 : Telemetry::SYSTEM_FONT_FALLBACK
),
1131 // track the script for which fallback occurred (incremented one make it
1133 Telemetry::Accumulate(Telemetry::SYSTEM_FONT_FALLBACK_SCRIPT
,
1134 int(aRunScript
) + 1);
1136 return font
.forget();
1139 #define NUM_FALLBACK_FONTS 8
1141 already_AddRefed
<gfxFont
> gfxPlatformFontList::CommonFontFallback(
1142 nsPresContext
* aPresContext
, uint32_t aCh
, uint32_t aNextCh
,
1143 Script aRunScript
, eFontPresentation aPresentation
,
1144 const gfxFontStyle
* aMatchStyle
, FontFamily
& aMatchedFamily
) {
1145 AutoTArray
<const char*, NUM_FALLBACK_FONTS
> defaultFallbacks
;
1146 gfxPlatform::GetPlatform()->GetCommonFallbackFonts(
1147 aCh
, aRunScript
, aPresentation
, defaultFallbacks
);
1148 GlobalFontMatch
data(aCh
, aNextCh
, *aMatchStyle
, aPresentation
);
1149 FontVisibility level
=
1150 aPresContext
? aPresContext
->GetFontVisibility() : FontVisibility::User
;
1152 // If a color-emoji presentation is requested, we will check any font found
1153 // to see if it can provide this; if not, we'll remember it as a possible
1154 // candidate but search the remainder of the list for a better choice.
1155 RefPtr
<gfxFont
> candidateFont
;
1156 FontFamily candidateFamily
;
1157 auto check
= [&](gfxFontEntry
* aFontEntry
,
1158 FontFamily aFamily
) -> already_AddRefed
<gfxFont
> {
1159 RefPtr
<gfxFont
> font
= aFontEntry
->FindOrMakeFont(aMatchStyle
);
1160 if (aPresentation
< eFontPresentation::EmojiDefault
||
1161 font
->HasColorGlyphFor(aCh
, aNextCh
)) {
1162 aMatchedFamily
= aFamily
;
1163 return font
.forget();
1165 // We want a color glyph but this font only has monochrome; remember it
1166 // (unless we already have a candidate) but continue to search.
1167 if (!candidateFont
) {
1168 candidateFont
= std::move(font
);
1169 candidateFamily
= aFamily
;
1174 if (SharedFontList()) {
1175 for (const auto name
: defaultFallbacks
) {
1176 fontlist::Family
* family
=
1177 FindSharedFamily(aPresContext
, nsDependentCString(name
));
1178 if (!family
|| !IsVisibleToCSS(*family
, level
)) {
1181 // XXX(jfkthame) Should we fire the async cmap-loader here, or let it
1182 // always do a potential sync initialization of the family?
1183 family
->SearchAllFontsForChar(SharedFontList(), &data
);
1184 if (data
.mBestMatch
) {
1185 RefPtr
<gfxFont
> font
= check(data
.mBestMatch
, FontFamily(family
));
1187 return font
.forget();
1192 for (const auto name
: defaultFallbacks
) {
1193 gfxFontFamily
* fallback
=
1194 FindFamilyByCanonicalName(nsDependentCString(name
));
1195 if (!fallback
|| !IsVisibleToCSS(*fallback
, level
)) {
1198 fallback
->FindFontForChar(&data
);
1199 if (data
.mBestMatch
) {
1200 RefPtr
<gfxFont
> font
= check(data
.mBestMatch
, FontFamily(fallback
));
1202 return font
.forget();
1208 // If we had a candidate that supports the character, but doesn't have the
1209 // desired emoji-style glyph, we'll return it anyhow as nothing better was
1211 if (candidateFont
) {
1212 aMatchedFamily
= candidateFamily
;
1213 return candidateFont
.forget();
1219 already_AddRefed
<gfxFont
> gfxPlatformFontList::GlobalFontFallback(
1220 nsPresContext
* aPresContext
, uint32_t aCh
, uint32_t aNextCh
,
1221 Script aRunScript
, eFontPresentation aPresentation
,
1222 const gfxFontStyle
* aMatchStyle
, uint32_t& aCmapCount
,
1223 FontFamily
& aMatchedFamily
) {
1224 bool useCmaps
= IsFontFamilyWhitelistActive() ||
1225 gfxPlatform::GetPlatform()->UseCmapsDuringSystemFallback();
1226 FontVisibility level
=
1227 aPresContext
? aPresContext
->GetFontVisibility() : FontVisibility::User
;
1229 // Allow platform-specific fallback code to try and find a usable font
1230 gfxFontEntry
* fe
= PlatformGlobalFontFallback(aPresContext
, aCh
, aRunScript
,
1231 aMatchStyle
, aMatchedFamily
);
1233 if (aMatchedFamily
.mShared
) {
1234 if (IsVisibleToCSS(*aMatchedFamily
.mShared
, level
)) {
1235 RefPtr
<gfxFont
> font
= fe
->FindOrMakeFont(aMatchStyle
);
1237 if (aPresentation
== eFontPresentation::Any
) {
1238 return font
.forget();
1240 bool hasColorGlyph
= font
->HasColorGlyphFor(aCh
, aNextCh
);
1241 if (hasColorGlyph
== PrefersColor(aPresentation
)) {
1242 return font
.forget();
1247 if (IsVisibleToCSS(*aMatchedFamily
.mUnshared
, level
)) {
1248 RefPtr
<gfxFont
> font
= fe
->FindOrMakeFont(aMatchStyle
);
1250 if (aPresentation
== eFontPresentation::Any
) {
1251 return font
.forget();
1253 bool hasColorGlyph
= font
->HasColorGlyphFor(aCh
, aNextCh
);
1254 if (hasColorGlyph
== PrefersColor(aPresentation
)) {
1255 return font
.forget();
1263 // otherwise, try to find it among local fonts
1264 GlobalFontMatch
data(aCh
, aNextCh
, *aMatchStyle
, aPresentation
);
1265 if (SharedFontList()) {
1266 fontlist::Family
* families
= SharedFontList()->Families();
1268 for (uint32_t i
= 0; i
< SharedFontList()->NumFamilies(); i
++) {
1269 fontlist::Family
& family
= families
[i
];
1270 if (!IsVisibleToCSS(family
, level
)) {
1273 if (!family
.IsFullyInitialized() &&
1274 StaticPrefs::gfx_font_rendering_fallback_async() &&
1275 !XRE_IsParentProcess()) {
1276 // Start loading all the missing charmaps; but this is async,
1277 // so for now we just continue, ignoring this family.
1278 StartCmapLoadingFromFamily(i
);
1280 family
.SearchAllFontsForChar(SharedFontList(), &data
);
1281 if (data
.mMatchDistance
== 0.0) {
1282 // no better style match is possible, so stop searching
1287 if (data
.mBestMatch
) {
1288 aMatchedFamily
= FontFamily(data
.mMatchedSharedFamily
);
1289 return data
.mBestMatch
->FindOrMakeFont(aMatchStyle
);
1293 // iterate over all font families to find a font that support the
1295 for (const RefPtr
<gfxFontFamily
>& family
: mFontFamilies
.Values()) {
1296 if (!IsVisibleToCSS(*family
, level
)) {
1299 // evaluate all fonts in this family for a match
1300 family
->FindFontForChar(&data
);
1301 if (data
.mMatchDistance
== 0.0) {
1302 // no better style match is possible, so stop searching
1307 aCmapCount
= data
.mCmapsTested
;
1308 if (data
.mBestMatch
) {
1309 aMatchedFamily
= FontFamily(data
.mMatchedFamily
);
1310 return data
.mBestMatch
->FindOrMakeFont(aMatchStyle
);
1317 class StartCmapLoadingRunnable
: public mozilla::Runnable
{
1319 explicit StartCmapLoadingRunnable(uint32_t aStartIndex
)
1320 : Runnable("gfxPlatformFontList::StartCmapLoadingRunnable"),
1321 mStartIndex(aStartIndex
) {}
1323 NS_IMETHOD
Run() override
{
1324 auto* pfl
= gfxPlatformFontList::PlatformFontList();
1325 auto* list
= pfl
->SharedFontList();
1329 if (mStartIndex
>= list
->NumFamilies()) {
1332 if (XRE_IsParentProcess()) {
1333 pfl
->StartCmapLoading(list
->GetGeneration(), mStartIndex
);
1335 dom::ContentChild::GetSingleton()->SendStartCmapLoading(
1336 list
->GetGeneration(), mStartIndex
);
1342 uint32_t mStartIndex
;
1345 void gfxPlatformFontList::StartCmapLoadingFromFamily(uint32_t aStartIndex
) {
1346 AutoLock
lock(mLock
);
1347 if (aStartIndex
>= mStartedLoadingCmapsFrom
) {
1348 // We already initiated cmap-loading from here or earlier in the list;
1349 // no need to do it again here.
1352 mStartedLoadingCmapsFrom
= aStartIndex
;
1354 // If we're already on the main thread, don't bother dispatching a runnable
1355 // here to kick off the loading process, just do it directly.
1356 if (NS_IsMainThread()) {
1357 auto* list
= SharedFontList();
1358 if (XRE_IsParentProcess()) {
1359 StartCmapLoading(list
->GetGeneration(), aStartIndex
);
1361 dom::ContentChild::GetSingleton()->SendStartCmapLoading(
1362 list
->GetGeneration(), aStartIndex
);
1365 NS_DispatchToMainThread(new StartCmapLoadingRunnable(aStartIndex
));
1369 class LoadCmapsRunnable
: public CancelableRunnable
{
1370 class WillShutdownObserver
: public nsIObserver
{
1375 explicit WillShutdownObserver(LoadCmapsRunnable
* aRunnable
)
1376 : mRunnable(aRunnable
) {}
1379 nsCOMPtr
<nsIObserverService
> obs
= services::GetObserverService();
1381 obs
->RemoveObserver(this, NS_XPCOM_WILL_SHUTDOWN_OBSERVER_ID
);
1383 mRunnable
= nullptr;
1387 virtual ~WillShutdownObserver() = default;
1389 LoadCmapsRunnable
* mRunnable
;
1393 explicit LoadCmapsRunnable(uint32_t aGeneration
, uint32_t aFamilyIndex
)
1394 : CancelableRunnable("gfxPlatformFontList::LoadCmapsRunnable"),
1395 mGeneration(aGeneration
),
1396 mStartIndex(aFamilyIndex
),
1397 mIndex(aFamilyIndex
) {
1398 nsCOMPtr
<nsIObserverService
> obs
= services::GetObserverService();
1400 mObserver
= new WillShutdownObserver(this);
1401 obs
->AddObserver(mObserver
, NS_XPCOM_WILL_SHUTDOWN_OBSERVER_ID
, false);
1405 virtual ~LoadCmapsRunnable() {
1407 mObserver
->Remove();
1411 // Reset the current family index, if the value passed is earlier than our
1412 // original starting position. We don't "reset" if it would move the current
1413 // position forward, or back into the already-scanned range.
1414 // We could optimize further by remembering the current position reached,
1415 // and then skipping ahead from the original start, but it doesn't seem worth
1416 // extra complexity for a task that usually only happens once, and already-
1417 // processed families will be skipped pretty quickly in Run() anyhow.
1418 void MaybeResetIndex(uint32_t aFamilyIndex
) {
1419 if (aFamilyIndex
< mStartIndex
) {
1420 mStartIndex
= aFamilyIndex
;
1421 mIndex
= aFamilyIndex
;
1425 nsresult
Cancel() override
{
1430 NS_IMETHOD
Run() override
{
1434 auto* pfl
= gfxPlatformFontList::PlatformFontList();
1435 auto* list
= pfl
->SharedFontList();
1440 if (mGeneration
!= list
->GetGeneration()) {
1443 uint32_t numFamilies
= list
->NumFamilies();
1444 if (mIndex
>= numFamilies
) {
1447 auto* families
= list
->Families();
1448 // Skip any families that are already initialized.
1449 while (mIndex
< numFamilies
&& families
[mIndex
].IsFullyInitialized()) {
1452 // Fully process one family, and advance index.
1453 if (mIndex
< numFamilies
) {
1454 Unused
<< pfl
->InitializeFamily(&families
[mIndex
], true);
1457 // If there are more families to initialize, post ourselves back to the
1458 // idle queue to handle the next one; otherwise we're finished and we need
1459 // to notify content processes to update their rendering.
1460 if (mIndex
< numFamilies
) {
1461 RefPtr
<CancelableRunnable
> task
= this;
1462 NS_DispatchToMainThreadQueue(task
.forget(), EventQueuePriority::Idle
);
1465 pfl
->CancelLoadCmapsTask();
1466 pfl
->InitializeCodepointsWithNoFonts();
1467 dom::ContentParent::NotifyUpdatedFonts(false);
1474 uint32_t mGeneration
;
1475 uint32_t mStartIndex
;
1477 bool mIsCanceled
= false;
1479 RefPtr
<WillShutdownObserver
> mObserver
;
1482 NS_IMPL_ISUPPORTS(LoadCmapsRunnable::WillShutdownObserver
, nsIObserver
)
1485 LoadCmapsRunnable::WillShutdownObserver::Observe(nsISupports
* aSubject
,
1487 const char16_t
* aData
) {
1488 if (!nsCRT::strcmp(aTopic
, NS_XPCOM_WILL_SHUTDOWN_OBSERVER_ID
)) {
1490 mRunnable
->Cancel();
1493 MOZ_ASSERT_UNREACHABLE("unexpected notification topic");
1498 void gfxPlatformFontList::StartCmapLoading(uint32_t aGeneration
,
1499 uint32_t aStartIndex
) {
1500 MOZ_RELEASE_ASSERT(XRE_IsParentProcess());
1501 if (aGeneration
!= SharedFontList()->GetGeneration()) {
1504 if (AppShutdown::IsInOrBeyond(ShutdownPhase::AppShutdownConfirmed
)) {
1507 if (mLoadCmapsRunnable
) {
1508 // We already have a runnable; just make sure it covers the full range of
1510 static_cast<LoadCmapsRunnable
*>(mLoadCmapsRunnable
.get())
1511 ->MaybeResetIndex(aStartIndex
);
1514 mLoadCmapsRunnable
= new LoadCmapsRunnable(aGeneration
, aStartIndex
);
1515 RefPtr
<CancelableRunnable
> task
= mLoadCmapsRunnable
;
1516 NS_DispatchToMainThreadQueue(task
.forget(), EventQueuePriority::Idle
);
1519 gfxFontFamily
* gfxPlatformFontList::CheckFamily(gfxFontFamily
* aFamily
) {
1520 if (aFamily
&& !aFamily
->HasStyles()) {
1521 aFamily
->FindStyleVariations();
1524 if (aFamily
&& aFamily
->FontListLength() == 0) {
1525 // Failed to load any faces for this family, so discard it.
1527 GenerateFontListKey(aFamily
->Name(), key
);
1528 mFontFamilies
.Remove(key
);
1535 bool gfxPlatformFontList::FindAndAddFamilies(
1536 nsPresContext
* aPresContext
, StyleGenericFontFamily aGeneric
,
1537 const nsACString
& aFamily
, nsTArray
<FamilyAndGeneric
>* aOutput
,
1538 FindFamiliesFlags aFlags
, gfxFontStyle
* aStyle
, nsAtom
* aLanguage
,
1539 gfxFloat aDevToCssSize
) {
1540 AutoLock
lock(mLock
);
1543 auto initialLength
= aOutput
->Length();
1547 FindAndAddFamiliesLocked(aPresContext
, aGeneric
, aFamily
, aOutput
, aFlags
,
1548 aStyle
, aLanguage
, aDevToCssSize
);
1550 auto finalLength
= aOutput
->Length();
1551 // Validate the expectation that the output-array grows if we return true,
1552 // or remains the same (probably empty) if we return false.
1553 MOZ_ASSERT_IF(didFind
, finalLength
> initialLength
);
1554 MOZ_ASSERT_IF(!didFind
, finalLength
== initialLength
);
1560 bool gfxPlatformFontList::FindAndAddFamiliesLocked(
1561 nsPresContext
* aPresContext
, StyleGenericFontFamily aGeneric
,
1562 const nsACString
& aFamily
, nsTArray
<FamilyAndGeneric
>* aOutput
,
1563 FindFamiliesFlags aFlags
, gfxFontStyle
* aStyle
, nsAtom
* aLanguage
,
1564 gfxFloat aDevToCssSize
) {
1566 GenerateFontListKey(aFamily
, key
);
1568 bool allowHidden
= bool(aFlags
& FindFamiliesFlags::eSearchHiddenFamilies
);
1569 FontVisibility visibilityLevel
=
1570 aPresContext
? aPresContext
->GetFontVisibility() : FontVisibility::User
;
1572 // If this font lookup is the result of resolving a CSS generic (not a direct
1573 // font-family request by the page), and RFP settings allow generics to be
1574 // unrestricted, bump the effective visibility level applied here so as to
1575 // allow user-installed fonts to be used.
1576 if (visibilityLevel
< FontVisibility::User
&&
1577 aGeneric
!= StyleGenericFontFamily::None
&&
1578 !aPresContext
->Document()->ShouldResistFingerprinting(
1579 RFPTarget::FontVisibilityRestrictGenerics
)) {
1580 visibilityLevel
= FontVisibility::User
;
1583 if (SharedFontList()) {
1584 fontlist::Family
* family
= SharedFontList()->FindFamily(key
);
1585 // If not found, and other family names have not yet been initialized,
1586 // initialize the rest of the list and try again. This is done lazily
1587 // since reading name table entries is expensive.
1588 // Although ASCII localized family names are possible they don't occur
1589 // in practice, so avoid pulling in names at startup.
1590 if (!family
&& !mOtherFamilyNamesInitialized
) {
1591 bool triggerLoading
= true;
1593 !(aFlags
& FindFamiliesFlags::eForceOtherFamilyNamesLoading
);
1595 // If `key` is an ASCII name, only trigger loading if it includes a
1596 // space, and the "base" name (up to the last space) exists as a known
1597 // family, so that this might be a legacy styled-family name.
1598 const char* data
= key
.BeginReading();
1599 int32_t index
= key
.Length();
1600 while (--index
> 0) {
1601 if (data
[index
] == ' ') {
1606 !SharedFontList()->FindFamily(nsAutoCString(key
.get(), index
))) {
1607 triggerLoading
= false;
1610 if (triggerLoading
) {
1611 if (InitOtherFamilyNames(mayDefer
)) {
1612 family
= SharedFontList()->FindFamily(key
);
1615 if (!family
&& !mOtherFamilyNamesInitialized
&&
1616 !(aFlags
& FindFamiliesFlags::eNoAddToNamesMissedWhenSearching
)) {
1617 AddToMissedNames(key
);
1620 // Check whether the family we found is actually allowed to be looked up,
1621 // according to current font-visibility prefs.
1623 bool visible
= IsVisibleToCSS(*family
, visibilityLevel
);
1624 if (visible
|| (allowHidden
&& family
->IsHidden())) {
1625 aOutput
->AppendElement(FamilyAndGeneric(family
, aGeneric
));
1629 aPresContext
->ReportBlockedFontFamily(*family
);
1635 NS_ASSERTION(mFontFamilies
.Count() != 0,
1636 "system font list was not initialized correctly");
1638 auto isBlockedByVisibilityLevel
= [=](gfxFontFamily
* aFamily
) -> bool {
1639 bool visible
= IsVisibleToCSS(*aFamily
, visibilityLevel
);
1640 if (visible
|| (allowHidden
&& aFamily
->IsHidden())) {
1644 aPresContext
->ReportBlockedFontFamily(*aFamily
);
1649 // lookup in canonical (i.e. English) family name list
1650 gfxFontFamily
* familyEntry
= mFontFamilies
.GetWeak(key
);
1652 if (isBlockedByVisibilityLevel(familyEntry
)) {
1657 // if not found, lookup in other family names list (mostly localized names)
1659 familyEntry
= mOtherFamilyNames
.GetWeak(key
);
1662 if (isBlockedByVisibilityLevel(familyEntry
)) {
1667 // if still not found and other family names not yet fully initialized,
1668 // initialize the rest of the list and try again. this is done lazily
1669 // since reading name table entries is expensive.
1670 // although ASCII localized family names are possible they don't occur
1671 // in practice so avoid pulling in names at startup
1672 if (!familyEntry
&& !mOtherFamilyNamesInitialized
&& !IsAscii(aFamily
)) {
1673 InitOtherFamilyNames(
1674 !(aFlags
& FindFamiliesFlags::eForceOtherFamilyNamesLoading
));
1675 familyEntry
= mOtherFamilyNames
.GetWeak(key
);
1676 if (!familyEntry
&& !mOtherFamilyNamesInitialized
&&
1677 !(aFlags
& FindFamiliesFlags::eNoAddToNamesMissedWhenSearching
)) {
1678 // localized family names load timed out, add name to list of
1679 // names to check after localized names are loaded
1680 AddToMissedNames(key
);
1683 if (isBlockedByVisibilityLevel(familyEntry
)) {
1689 familyEntry
= CheckFamily(familyEntry
);
1691 // If we failed to find the requested family, check for a space in the
1692 // name; if found, and if the "base" name (up to the last space) exists
1693 // as a family, then this might be a legacy GDI-style family name for
1694 // an additional weight/width. Try searching the faces of the base family
1695 // and create any corresponding legacy families.
1697 !(aFlags
& FindFamiliesFlags::eNoSearchForLegacyFamilyNames
)) {
1698 // We don't have nsAString::RFindChar, so look for a space manually
1699 const char* data
= aFamily
.BeginReading();
1700 int32_t index
= aFamily
.Length();
1701 while (--index
> 0) {
1702 if (data
[index
] == ' ') {
1707 gfxFontFamily
* base
=
1708 FindUnsharedFamily(aPresContext
, Substring(aFamily
, 0, index
),
1709 FindFamiliesFlags::eNoSearchForLegacyFamilyNames
);
1710 // If we found the "base" family name, and if it has members with
1711 // legacy names, this will add corresponding font-family entries to
1712 // the mOtherFamilyNames list; then retry the legacy-family search.
1713 if (base
&& base
->CheckForLegacyFamilyNames(this)) {
1714 familyEntry
= mOtherFamilyNames
.GetWeak(key
);
1717 if (isBlockedByVisibilityLevel(familyEntry
)) {
1725 aOutput
->AppendElement(FamilyAndGeneric(familyEntry
, aGeneric
));
1732 void gfxPlatformFontList::AddToMissedNames(const nsCString
& aKey
) {
1733 if (!mOtherNamesMissed
) {
1734 mOtherNamesMissed
= MakeUnique
<nsTHashSet
<nsCString
>>(2);
1736 mOtherNamesMissed
->Insert(aKey
);
1739 fontlist::Family
* gfxPlatformFontList::FindSharedFamily(
1740 nsPresContext
* aPresContext
, const nsACString
& aFamily
,
1741 FindFamiliesFlags aFlags
, gfxFontStyle
* aStyle
, nsAtom
* aLanguage
,
1742 gfxFloat aDevToCss
) {
1743 if (!SharedFontList()) {
1746 AutoTArray
<FamilyAndGeneric
, 1> families
;
1747 if (!FindAndAddFamiliesLocked(aPresContext
, StyleGenericFontFamily::None
,
1748 aFamily
, &families
, aFlags
, aStyle
, aLanguage
,
1750 !families
[0].mFamily
.mShared
) {
1753 fontlist::Family
* family
= families
[0].mFamily
.mShared
;
1754 if (!family
->IsInitialized()) {
1755 if (!InitializeFamily(family
)) {
1762 class InitializeFamilyRunnable
: public mozilla::Runnable
{
1764 explicit InitializeFamilyRunnable(uint32_t aFamilyIndex
, bool aLoadCmaps
)
1765 : Runnable("gfxPlatformFontList::InitializeFamilyRunnable"),
1766 mIndex(aFamilyIndex
),
1767 mLoadCmaps(aLoadCmaps
) {}
1769 NS_IMETHOD
Run() override
{
1770 auto list
= gfxPlatformFontList::PlatformFontList()->SharedFontList();
1774 if (mIndex
>= list
->NumFamilies()) {
1775 // Out of range? Maybe the list got reinitialized since this request
1776 // was posted - just ignore it.
1779 dom::ContentChild::GetSingleton()->SendInitializeFamily(
1780 list
->GetGeneration(), mIndex
, mLoadCmaps
);
1789 bool gfxPlatformFontList::InitializeFamily(fontlist::Family
* aFamily
,
1791 MOZ_ASSERT(SharedFontList());
1792 auto list
= SharedFontList();
1793 if (!XRE_IsParentProcess()) {
1794 auto* families
= list
->Families();
1798 uint32_t index
= aFamily
- families
;
1799 if (index
>= list
->NumFamilies()) {
1802 if (NS_IsMainThread()) {
1803 dom::ContentChild::GetSingleton()->SendInitializeFamily(
1804 list
->GetGeneration(), index
, aLoadCmaps
);
1806 NS_DispatchToMainThread(new InitializeFamilyRunnable(index
, aLoadCmaps
));
1808 return aFamily
->IsInitialized();
1811 if (!aFamily
->IsInitialized()) {
1812 // The usual case: we're being asked to populate the face list.
1813 AutoTArray
<fontlist::Face::InitData
, 16> faceList
;
1814 GetFacesInitDataForFamily(aFamily
, faceList
, aLoadCmaps
);
1815 aFamily
->AddFaces(list
, faceList
);
1817 // The family's face list was already initialized, but if aLoadCmaps is
1818 // true we also want to eagerly load character maps. This is used when a
1819 // child process is doing SearchAllFontsForChar, to have the parent load
1820 // all the cmaps at once and reduce IPC traffic (and content-process file
1821 // access overhead, which is crippling for DirectWrite on Windows).
1823 auto* faces
= aFamily
->Faces(list
);
1825 for (size_t i
= 0; i
< aFamily
->NumFaces(); i
++) {
1826 auto* face
= faces
[i
].ToPtr
<fontlist::Face
>(list
);
1827 if (face
&& face
->mCharacterMap
.IsNull()) {
1828 // We don't want to cache this font entry, as the parent will most
1829 // likely never use it again; it's just to populate the charmap for
1830 // the benefit of the child process.
1831 RefPtr
<gfxFontEntry
> fe
= CreateFontEntry(face
, aFamily
);
1841 if (aLoadCmaps
&& aFamily
->IsInitialized()) {
1842 aFamily
->SetupFamilyCharMap(list
);
1845 return aFamily
->IsInitialized();
1848 gfxFontEntry
* gfxPlatformFontList::FindFontForFamily(
1849 nsPresContext
* aPresContext
, const nsACString
& aFamily
,
1850 const gfxFontStyle
* aStyle
) {
1851 AutoLock
lock(mLock
);
1854 GenerateFontListKey(aFamily
, key
);
1856 FontFamily family
= FindFamily(aPresContext
, key
);
1857 if (family
.IsNull()) {
1860 if (family
.mShared
) {
1861 auto face
= family
.mShared
->FindFaceForStyle(SharedFontList(), *aStyle
);
1865 return GetOrCreateFontEntryLocked(face
, family
.mShared
);
1867 return family
.mUnshared
->FindFontForStyle(*aStyle
);
1870 gfxFontEntry
* gfxPlatformFontList::GetOrCreateFontEntryLocked(
1871 fontlist::Face
* aFace
, const fontlist::Family
* aFamily
) {
1873 .LookupOrInsertWith(aFace
,
1874 [=] { return CreateFontEntry(aFace
, aFamily
); })
1878 void gfxPlatformFontList::AddOtherFamilyNames(
1879 gfxFontFamily
* aFamilyEntry
, const nsTArray
<nsCString
>& aOtherFamilyNames
) {
1880 AutoLock
lock(mLock
);
1882 for (const auto& name
: aOtherFamilyNames
) {
1884 GenerateFontListKey(name
, key
);
1886 mOtherFamilyNames
.LookupOrInsertWith(key
, [&] {
1888 ("(fontlist-otherfamily) canonical family: %s, other family: %s\n",
1889 aFamilyEntry
->Name().get(), name
.get()));
1890 if (mBadUnderlineFamilyNames
.ContainsSorted(key
)) {
1891 aFamilyEntry
->SetBadUnderlineFamily();
1893 return RefPtr
{aFamilyEntry
};
1898 void gfxPlatformFontList::AddFullnameLocked(gfxFontEntry
* aFontEntry
,
1899 const nsCString
& aFullname
) {
1900 mExtraNames
->mFullnames
.LookupOrInsertWith(aFullname
, [&] {
1901 LOG_FONTLIST(("(fontlist-fullname) name: %s, fullname: %s\n",
1902 aFontEntry
->Name().get(), aFullname
.get()));
1903 return RefPtr
{aFontEntry
};
1907 void gfxPlatformFontList::AddPostscriptNameLocked(
1908 gfxFontEntry
* aFontEntry
, const nsCString
& aPostscriptName
) {
1909 mExtraNames
->mPostscriptNames
.LookupOrInsertWith(aPostscriptName
, [&] {
1910 LOG_FONTLIST(("(fontlist-postscript) name: %s, psname: %s\n",
1911 aFontEntry
->Name().get(), aPostscriptName
.get()));
1912 return RefPtr
{aFontEntry
};
1916 bool gfxPlatformFontList::GetStandardFamilyName(const nsCString
& aFontName
,
1917 nsACString
& aFamilyName
) {
1918 AutoLock
lock(mLock
);
1919 FontFamily family
= FindFamily(nullptr, aFontName
);
1920 if (family
.IsNull()) {
1923 return GetLocalizedFamilyName(family
, aFamilyName
);
1926 bool gfxPlatformFontList::GetLocalizedFamilyName(const FontFamily
& aFamily
,
1927 nsACString
& aFamilyName
) {
1928 if (aFamily
.mShared
) {
1929 aFamilyName
= SharedFontList()->LocalizedFamilyName(aFamily
.mShared
);
1932 if (aFamily
.mUnshared
) {
1933 aFamily
.mUnshared
->LocalizedName(aFamilyName
);
1936 return false; // leaving the aFamilyName outparam untouched
1939 FamilyAndGeneric
gfxPlatformFontList::GetDefaultFontFamily(
1940 const nsACString
& aLangGroup
, const nsACString
& aGenericFamily
) {
1941 if (NS_WARN_IF(aLangGroup
.IsEmpty()) ||
1942 NS_WARN_IF(aGenericFamily
.IsEmpty())) {
1943 return FamilyAndGeneric();
1946 AutoLock
lock(mLock
);
1948 nsAutoCString value
;
1949 AutoTArray
<nsCString
, 4> names
;
1950 if (mFontPrefs
->LookupNameList(PrefName(aGenericFamily
, aLangGroup
), value
)) {
1951 gfxFontUtils::ParseFontList(value
, names
);
1954 for (const nsCString
& name
: names
) {
1955 FontFamily family
= FindFamily(nullptr, name
);
1956 if (!family
.IsNull()) {
1957 return FamilyAndGeneric(family
);
1961 return FamilyAndGeneric();
1964 ShmemCharMapHashEntry::ShmemCharMapHashEntry(const gfxSparseBitSet
* aCharMap
)
1965 : mList(gfxPlatformFontList::PlatformFontList()->SharedFontList()),
1966 mHash(aCharMap
->GetChecksum()) {
1967 size_t len
= SharedBitSet::RequiredSize(*aCharMap
);
1968 mCharMap
= mList
->Alloc(len
);
1969 SharedBitSet::Create(mCharMap
.ToPtr(mList
, len
), len
, *aCharMap
);
1972 fontlist::Pointer
gfxPlatformFontList::GetShmemCharMapLocked(
1973 const gfxSparseBitSet
* aCmap
) {
1974 auto* entry
= mShmemCharMaps
.GetEntry(aCmap
);
1976 entry
= mShmemCharMaps
.PutEntry(aCmap
);
1978 return entry
->GetCharMap();
1981 // Lookup aCmap in the shared cmap set, adding if not already present.
1982 // This is the only way for a reference to a gfxCharacterMap to be acquired
1983 // by another thread than its original creator.
1984 already_AddRefed
<gfxCharacterMap
> gfxPlatformFontList::FindCharMap(
1985 gfxCharacterMap
* aCmap
) {
1986 // Lock to prevent potentially racing against MaybeRemoveCmap.
1987 AutoLock
lock(mLock
);
1989 // Find existing entry or insert a new one (which will add a reference).
1991 aCmap
->mShared
= true; // Set the shared flag in preparation for adding
1992 // to the global table.
1993 RefPtr cmap
= mSharedCmaps
.PutEntry(aCmap
)->GetKey();
1995 // If we ended up finding a different, pre-existing entry, clear the
1996 // shared flag on this one so that it'll get deleted on Release().
1997 if (cmap
.get() != aCmap
) {
1998 aCmap
->mShared
= false;
2001 return cmap
.forget();
2004 // Potentially remove the charmap from the shared cmap set. This is called
2005 // when a user of the charmap drops a reference and the refcount goes to 1;
2006 // in that case, it is possible our shared set is the only remaining user
2007 // of the object, and we should remove it.
2008 // Note that aCharMap might have already been freed, so we must not try to
2009 // dereference it until we have checked that it's still present in our table.
2010 void gfxPlatformFontList::MaybeRemoveCmap(gfxCharacterMap
* aCharMap
) {
2011 // Lock so that nobody else can get a reference via FindCharMap while we're
2013 AutoLock
lock(mLock
);
2015 // Skip lookups during teardown.
2016 if (!mSharedCmaps
.Count()) {
2020 // aCharMap needs to match the entry and be the same ptr and still have a
2021 // refcount of exactly 1 (i.e. we hold the only reference) before removing.
2022 // If we're racing another thread, it might already have been removed, in
2023 // which case GetEntry will not find it and we won't try to dereference the
2024 // already-freed pointer.
2025 CharMapHashKey
* found
=
2026 mSharedCmaps
.GetEntry(const_cast<gfxCharacterMap
*>(aCharMap
));
2027 if (found
&& found
->GetKey() == aCharMap
&& aCharMap
->RefCount() == 1) {
2028 // Forget our reference to the object that's being deleted, without
2029 // calling Release() on it.
2030 Unused
<< found
->mCharMap
.forget();
2035 // Log this as a "Release" to keep leak-checking correct.
2036 NS_LOG_RELEASE(aCharMap
, 0, "gfxCharacterMap");
2038 mSharedCmaps
.RemoveEntry(found
);
2042 static void GetSystemUIFontFamilies([[maybe_unused
]] nsAtom
* aLangGroup
,
2043 nsTArray
<nsCString
>& aFamilies
) {
2044 // TODO: On macOS, use CTCreateUIFontForLanguage or such thing (though the
2045 // code below ends up using [NSFont systemFontOfSize: 0.0].
2047 gfxFontStyle fontStyle
;
2048 nsAutoString systemFontName
;
2049 if (!LookAndFeel::GetFont(StyleSystemFont::Menu
, systemFontName
, fontStyle
)) {
2052 systemFontName
.Trim("\"'");
2053 CopyUTF16toUTF8(systemFontName
, *aFamilies
.AppendElement());
2056 void gfxPlatformFontList::ResolveGenericFontNames(
2057 nsPresContext
* aPresContext
, StyleGenericFontFamily aGenericType
,
2058 eFontPrefLang aPrefLang
, PrefFontList
* aGenericFamilies
) {
2059 const char* langGroupStr
= GetPrefLangName(aPrefLang
);
2060 const char* generic
= GetGenericName(aGenericType
);
2066 AutoTArray
<nsCString
, 4> genericFamilies
;
2068 // load family for "font.name.generic.lang"
2069 PrefName
prefName(generic
, langGroupStr
);
2070 nsAutoCString value
;
2071 if (mFontPrefs
->LookupName(prefName
, value
)) {
2072 gfxFontUtils::ParseFontList(value
, genericFamilies
);
2075 // load fonts for "font.name-list.generic.lang"
2076 if (mFontPrefs
->LookupNameList(prefName
, value
)) {
2077 gfxFontUtils::ParseFontList(value
, genericFamilies
);
2080 nsAtom
* langGroup
= GetLangGroupForPrefLang(aPrefLang
);
2081 MOZ_ASSERT(langGroup
, "null lang group for pref lang");
2083 if (aGenericType
== StyleGenericFontFamily::SystemUi
) {
2084 GetSystemUIFontFamilies(langGroup
, genericFamilies
);
2087 GetFontFamiliesFromGenericFamilies(
2088 aPresContext
, aGenericType
, genericFamilies
, langGroup
, aGenericFamilies
);
2090 #if 0 // dump out generic mappings
2091 printf("%s ===> ", NamePref(generic
, langGroupStr
).get());
2092 for (uint32_t k
= 0; k
< aGenericFamilies
->Length(); k
++) {
2093 if (k
> 0) printf(", ");
2094 printf("%s", (*aGenericFamilies
)[k
].mIsShared
2095 ? (*aGenericFamilies
)[k
].mShared
->DisplayName().AsString(SharedFontList()).get()
2096 : (*aGenericFamilies
)[k
].mUnshared
->Name().get());
2102 void gfxPlatformFontList::ResolveEmojiFontNames(
2103 nsPresContext
* aPresContext
, PrefFontList
* aGenericFamilies
) {
2104 // emoji preference has no lang name
2105 AutoTArray
<nsCString
, 4> genericFamilies
;
2107 nsAutoCString value
;
2108 if (mFontPrefs
->LookupNameList(PrefName("emoji", ""), value
)) {
2109 gfxFontUtils::ParseFontList(value
, genericFamilies
);
2112 GetFontFamiliesFromGenericFamilies(
2113 aPresContext
, StyleGenericFontFamily::MozEmoji
, genericFamilies
, nullptr,
2117 void gfxPlatformFontList::GetFontFamiliesFromGenericFamilies(
2118 nsPresContext
* aPresContext
, StyleGenericFontFamily aGenericType
,
2119 nsTArray
<nsCString
>& aGenericNameFamilies
, nsAtom
* aLangGroup
,
2120 PrefFontList
* aGenericFamilies
) {
2121 // lookup and add platform fonts uniquely
2122 for (const nsCString
& genericFamily
: aGenericNameFamilies
) {
2123 AutoTArray
<FamilyAndGeneric
, 10> families
;
2124 FindAndAddFamiliesLocked(aPresContext
, aGenericType
, genericFamily
,
2125 &families
, FindFamiliesFlags(0), nullptr,
2127 for (const FamilyAndGeneric
& f
: families
) {
2128 if (!aGenericFamilies
->Contains(f
.mFamily
)) {
2129 aGenericFamilies
->AppendElement(f
.mFamily
);
2135 gfxPlatformFontList::PrefFontList
*
2136 gfxPlatformFontList::GetPrefFontsLangGroupLocked(
2137 nsPresContext
* aPresContext
, StyleGenericFontFamily aGenericType
,
2138 eFontPrefLang aPrefLang
) {
2139 if (aGenericType
== StyleGenericFontFamily::MozEmoji
||
2140 aPrefLang
== eFontPrefLang_Emoji
) {
2141 // Emoji font has no lang
2142 PrefFontList
* prefFonts
= mEmojiPrefFont
.get();
2143 if (MOZ_UNLIKELY(!prefFonts
)) {
2144 prefFonts
= new PrefFontList
;
2145 ResolveEmojiFontNames(aPresContext
, prefFonts
);
2146 mEmojiPrefFont
.reset(prefFonts
);
2151 auto index
= static_cast<size_t>(aGenericType
);
2152 PrefFontList
* prefFonts
= mLangGroupPrefFonts
[aPrefLang
][index
].get();
2153 if (MOZ_UNLIKELY(!prefFonts
)) {
2154 prefFonts
= new PrefFontList
;
2155 ResolveGenericFontNames(aPresContext
, aGenericType
, aPrefLang
, prefFonts
);
2156 mLangGroupPrefFonts
[aPrefLang
][index
].reset(prefFonts
);
2161 void gfxPlatformFontList::AddGenericFonts(
2162 nsPresContext
* aPresContext
, StyleGenericFontFamily aGenericType
,
2163 nsAtom
* aLanguage
, nsTArray
<FamilyAndGeneric
>& aFamilyList
) {
2164 AutoLock
lock(mLock
);
2166 // map lang ==> langGroup
2167 nsAtom
* langGroup
= GetLangGroup(aLanguage
);
2169 // langGroup ==> prefLang
2170 eFontPrefLang prefLang
= GetFontPrefLangFor(langGroup
);
2172 // lookup pref fonts
2173 PrefFontList
* prefFonts
=
2174 GetPrefFontsLangGroupLocked(aPresContext
, aGenericType
, prefLang
);
2176 if (!prefFonts
->IsEmpty()) {
2177 aFamilyList
.SetCapacity(aFamilyList
.Length() + prefFonts
->Length());
2178 for (auto& f
: *prefFonts
) {
2179 aFamilyList
.AppendElement(FamilyAndGeneric(f
, aGenericType
));
2184 static nsAtom
* PrefLangToLangGroups(uint32_t aIndex
) {
2185 // static array here avoids static constructor
2186 static nsAtom
* gPrefLangToLangGroups
[] = {
2187 #define FONT_PREF_LANG(enum_id_, str_, atom_id_) nsGkAtoms::atom_id_
2188 #include "gfxFontPrefLangList.h"
2189 #undef FONT_PREF_LANG
2192 return aIndex
< ArrayLength(gPrefLangToLangGroups
)
2193 ? gPrefLangToLangGroups
[aIndex
]
2194 : nsGkAtoms::Unicode
;
2197 eFontPrefLang
gfxPlatformFontList::GetFontPrefLangFor(const char* aLang
) {
2198 if (!aLang
|| !aLang
[0]) {
2199 return eFontPrefLang_Others
;
2201 for (uint32_t i
= 0; i
< ArrayLength(gPrefLangNames
); ++i
) {
2202 if (!nsCRT::strcasecmp(gPrefLangNames
[i
], aLang
)) {
2203 return eFontPrefLang(i
);
2206 return eFontPrefLang_Others
;
2209 eFontPrefLang
gfxPlatformFontList::GetFontPrefLangFor(nsAtom
* aLang
) {
2210 if (!aLang
) return eFontPrefLang_Others
;
2212 aLang
->ToUTF8String(lang
);
2213 return GetFontPrefLangFor(lang
.get());
2216 nsAtom
* gfxPlatformFontList::GetLangGroupForPrefLang(eFontPrefLang aLang
) {
2217 // the special CJK set pref lang should be resolved into separate
2218 // calls to individual CJK pref langs before getting here
2219 NS_ASSERTION(aLang
!= eFontPrefLang_CJKSet
, "unresolved CJK set pref lang");
2221 return PrefLangToLangGroups(uint32_t(aLang
));
2224 const char* gfxPlatformFontList::GetPrefLangName(eFontPrefLang aLang
) {
2225 if (uint32_t(aLang
) < ArrayLength(gPrefLangNames
)) {
2226 return gPrefLangNames
[uint32_t(aLang
)];
2231 eFontPrefLang
gfxPlatformFontList::GetFontPrefLangFor(uint32_t aCh
) {
2232 switch (ublock_getCode(aCh
)) {
2233 case UBLOCK_BASIC_LATIN
:
2234 case UBLOCK_LATIN_1_SUPPLEMENT
:
2235 case UBLOCK_LATIN_EXTENDED_A
:
2236 case UBLOCK_LATIN_EXTENDED_B
:
2237 case UBLOCK_IPA_EXTENSIONS
:
2238 case UBLOCK_SPACING_MODIFIER_LETTERS
:
2239 case UBLOCK_LATIN_EXTENDED_ADDITIONAL
:
2240 case UBLOCK_LATIN_EXTENDED_C
:
2241 case UBLOCK_LATIN_EXTENDED_D
:
2242 case UBLOCK_LATIN_EXTENDED_E
:
2243 case UBLOCK_PHONETIC_EXTENSIONS
:
2244 return eFontPrefLang_Western
;
2246 case UBLOCK_GREEK_EXTENDED
:
2247 return eFontPrefLang_Greek
;
2248 case UBLOCK_CYRILLIC
:
2249 case UBLOCK_CYRILLIC_SUPPLEMENT
:
2250 case UBLOCK_CYRILLIC_EXTENDED_A
:
2251 case UBLOCK_CYRILLIC_EXTENDED_B
:
2252 case UBLOCK_CYRILLIC_EXTENDED_C
:
2253 return eFontPrefLang_Cyrillic
;
2254 case UBLOCK_ARMENIAN
:
2255 return eFontPrefLang_Armenian
;
2257 return eFontPrefLang_Hebrew
;
2259 case UBLOCK_ARABIC_PRESENTATION_FORMS_A
:
2260 case UBLOCK_ARABIC_PRESENTATION_FORMS_B
:
2261 case UBLOCK_ARABIC_SUPPLEMENT
:
2262 case UBLOCK_ARABIC_EXTENDED_A
:
2263 case UBLOCK_ARABIC_MATHEMATICAL_ALPHABETIC_SYMBOLS
:
2264 return eFontPrefLang_Arabic
;
2265 case UBLOCK_DEVANAGARI
:
2266 case UBLOCK_DEVANAGARI_EXTENDED
:
2267 return eFontPrefLang_Devanagari
;
2268 case UBLOCK_BENGALI
:
2269 return eFontPrefLang_Bengali
;
2270 case UBLOCK_GURMUKHI
:
2271 return eFontPrefLang_Gurmukhi
;
2272 case UBLOCK_GUJARATI
:
2273 return eFontPrefLang_Gujarati
;
2275 return eFontPrefLang_Oriya
;
2277 return eFontPrefLang_Tamil
;
2279 return eFontPrefLang_Telugu
;
2280 case UBLOCK_KANNADA
:
2281 return eFontPrefLang_Kannada
;
2282 case UBLOCK_MALAYALAM
:
2283 return eFontPrefLang_Malayalam
;
2284 case UBLOCK_SINHALA
:
2285 case UBLOCK_SINHALA_ARCHAIC_NUMBERS
:
2286 return eFontPrefLang_Sinhala
;
2288 return eFontPrefLang_Thai
;
2289 case UBLOCK_TIBETAN
:
2290 return eFontPrefLang_Tibetan
;
2291 case UBLOCK_GEORGIAN
:
2292 case UBLOCK_GEORGIAN_SUPPLEMENT
:
2293 case UBLOCK_GEORGIAN_EXTENDED
:
2294 return eFontPrefLang_Georgian
;
2295 case UBLOCK_HANGUL_JAMO
:
2296 case UBLOCK_HANGUL_COMPATIBILITY_JAMO
:
2297 case UBLOCK_HANGUL_SYLLABLES
:
2298 case UBLOCK_HANGUL_JAMO_EXTENDED_A
:
2299 case UBLOCK_HANGUL_JAMO_EXTENDED_B
:
2300 return eFontPrefLang_Korean
;
2301 case UBLOCK_ETHIOPIC
:
2302 case UBLOCK_ETHIOPIC_EXTENDED
:
2303 case UBLOCK_ETHIOPIC_SUPPLEMENT
:
2304 case UBLOCK_ETHIOPIC_EXTENDED_A
:
2305 return eFontPrefLang_Ethiopic
;
2306 case UBLOCK_UNIFIED_CANADIAN_ABORIGINAL_SYLLABICS
:
2307 case UBLOCK_UNIFIED_CANADIAN_ABORIGINAL_SYLLABICS_EXTENDED
:
2308 return eFontPrefLang_Canadian
;
2310 case UBLOCK_KHMER_SYMBOLS
:
2311 return eFontPrefLang_Khmer
;
2312 case UBLOCK_CJK_RADICALS_SUPPLEMENT
:
2313 case UBLOCK_KANGXI_RADICALS
:
2314 case UBLOCK_IDEOGRAPHIC_DESCRIPTION_CHARACTERS
:
2315 case UBLOCK_CJK_SYMBOLS_AND_PUNCTUATION
:
2316 case UBLOCK_HIRAGANA
:
2317 case UBLOCK_KATAKANA
:
2318 case UBLOCK_BOPOMOFO
:
2320 case UBLOCK_BOPOMOFO_EXTENDED
:
2321 case UBLOCK_ENCLOSED_CJK_LETTERS_AND_MONTHS
:
2322 case UBLOCK_CJK_COMPATIBILITY
:
2323 case UBLOCK_CJK_UNIFIED_IDEOGRAPHS_EXTENSION_A
:
2324 case UBLOCK_CJK_UNIFIED_IDEOGRAPHS
:
2325 case UBLOCK_CJK_COMPATIBILITY_IDEOGRAPHS
:
2326 case UBLOCK_CJK_COMPATIBILITY_FORMS
:
2327 case UBLOCK_SMALL_FORM_VARIANTS
:
2328 case UBLOCK_HALFWIDTH_AND_FULLWIDTH_FORMS
:
2329 case UBLOCK_CJK_UNIFIED_IDEOGRAPHS_EXTENSION_B
:
2330 case UBLOCK_CJK_COMPATIBILITY_IDEOGRAPHS_SUPPLEMENT
:
2331 case UBLOCK_KATAKANA_PHONETIC_EXTENSIONS
:
2332 case UBLOCK_CJK_STROKES
:
2333 case UBLOCK_VERTICAL_FORMS
:
2334 case UBLOCK_CJK_UNIFIED_IDEOGRAPHS_EXTENSION_C
:
2335 case UBLOCK_KANA_SUPPLEMENT
:
2336 case UBLOCK_CJK_UNIFIED_IDEOGRAPHS_EXTENSION_D
:
2337 case UBLOCK_CJK_UNIFIED_IDEOGRAPHS_EXTENSION_E
:
2338 case UBLOCK_IDEOGRAPHIC_SYMBOLS_AND_PUNCTUATION
:
2339 case UBLOCK_CJK_UNIFIED_IDEOGRAPHS_EXTENSION_F
:
2340 case UBLOCK_KANA_EXTENDED_A
:
2341 return eFontPrefLang_CJKSet
;
2342 case UBLOCK_MATHEMATICAL_OPERATORS
:
2343 case UBLOCK_MATHEMATICAL_ALPHANUMERIC_SYMBOLS
:
2344 case UBLOCK_MISCELLANEOUS_MATHEMATICAL_SYMBOLS_A
:
2345 case UBLOCK_MISCELLANEOUS_MATHEMATICAL_SYMBOLS_B
:
2346 case UBLOCK_SUPPLEMENTAL_MATHEMATICAL_OPERATORS
:
2347 return eFontPrefLang_Mathematics
;
2349 return eFontPrefLang_Others
;
2353 bool gfxPlatformFontList::IsLangCJK(eFontPrefLang aLang
) {
2355 case eFontPrefLang_Japanese
:
2356 case eFontPrefLang_ChineseTW
:
2357 case eFontPrefLang_ChineseCN
:
2358 case eFontPrefLang_ChineseHK
:
2359 case eFontPrefLang_Korean
:
2360 case eFontPrefLang_CJKSet
:
2367 void gfxPlatformFontList::GetLangPrefs(eFontPrefLang aPrefLangs
[],
2368 uint32_t& aLen
, eFontPrefLang aCharLang
,
2369 eFontPrefLang aPageLang
) {
2370 AutoLock
lock(mLock
);
2371 if (IsLangCJK(aCharLang
)) {
2372 AppendCJKPrefLangs(aPrefLangs
, aLen
, aCharLang
, aPageLang
);
2374 AppendPrefLang(aPrefLangs
, aLen
, aCharLang
);
2377 AppendPrefLang(aPrefLangs
, aLen
, eFontPrefLang_Others
);
2380 void gfxPlatformFontList::AppendCJKPrefLangs(eFontPrefLang aPrefLangs
[],
2382 eFontPrefLang aCharLang
,
2383 eFontPrefLang aPageLang
) {
2384 // prefer the lang specified by the page *if* CJK
2385 if (IsLangCJK(aPageLang
)) {
2386 AppendPrefLang(aPrefLangs
, aLen
, aPageLang
);
2389 // if not set up, set up the default CJK order, based on accept lang
2390 // settings and locale
2391 if (mCJKPrefLangs
.Length() == 0) {
2393 eFontPrefLang tempPrefLangs
[kMaxLenPrefLangList
];
2394 uint32_t tempLen
= 0;
2396 // Add the CJK pref fonts from accept languages, the order should be same
2397 // order. We use gfxFontUtils::GetPrefsFontList to read the list even
2398 // though it's not actually a list of fonts but of lang codes; the format
2400 AutoTArray
<nsCString
, 5> list
;
2401 gfxFontUtils::GetPrefsFontList("intl.accept_languages", list
, true);
2402 for (const auto& lang
: list
) {
2403 eFontPrefLang fpl
= GetFontPrefLangFor(lang
.get());
2405 case eFontPrefLang_Japanese
:
2406 case eFontPrefLang_Korean
:
2407 case eFontPrefLang_ChineseCN
:
2408 case eFontPrefLang_ChineseHK
:
2409 case eFontPrefLang_ChineseTW
:
2410 AppendPrefLang(tempPrefLangs
, tempLen
, fpl
);
2417 // Try using app's locale
2418 nsAutoCString localeStr
;
2419 LocaleService::GetInstance()->GetAppLocaleAsBCP47(localeStr
);
2423 if (LocaleParser::TryParse(localeStr
, locale
).isOk() &&
2424 locale
.Canonicalize().isOk()) {
2425 if (locale
.Language().EqualTo("ja")) {
2426 AppendPrefLang(tempPrefLangs
, tempLen
, eFontPrefLang_Japanese
);
2427 } else if (locale
.Language().EqualTo("zh")) {
2428 if (locale
.Region().EqualTo("CN")) {
2429 AppendPrefLang(tempPrefLangs
, tempLen
, eFontPrefLang_ChineseCN
);
2430 } else if (locale
.Region().EqualTo("TW")) {
2431 AppendPrefLang(tempPrefLangs
, tempLen
, eFontPrefLang_ChineseTW
);
2432 } else if (locale
.Region().EqualTo("HK")) {
2433 AppendPrefLang(tempPrefLangs
, tempLen
, eFontPrefLang_ChineseHK
);
2435 } else if (locale
.Language().EqualTo("ko")) {
2436 AppendPrefLang(tempPrefLangs
, tempLen
, eFontPrefLang_Korean
);
2441 // Then add the known CJK prefs in order of system preferred locales
2442 AutoTArray
<nsCString
, 5> prefLocales
;
2443 prefLocales
.AppendElement("ja"_ns
);
2444 prefLocales
.AppendElement("zh-CN"_ns
);
2445 prefLocales
.AppendElement("zh-TW"_ns
);
2446 prefLocales
.AppendElement("zh-HK"_ns
);
2447 prefLocales
.AppendElement("ko"_ns
);
2449 AutoTArray
<nsCString
, 16> sysLocales
;
2450 AutoTArray
<nsCString
, 16> negLocales
;
2452 OSPreferences::GetInstance()->GetSystemLocales(sysLocales
))) {
2453 LocaleService::GetInstance()->NegotiateLanguages(
2454 sysLocales
, prefLocales
, ""_ns
,
2455 LocaleService::kLangNegStrategyFiltering
, negLocales
);
2456 for (const auto& localeStr
: negLocales
) {
2458 if (LocaleParser::TryParse(localeStr
, locale
).isOk() &&
2459 locale
.Canonicalize().isOk()) {
2460 if (locale
.Language().EqualTo("ja")) {
2461 AppendPrefLang(tempPrefLangs
, tempLen
, eFontPrefLang_Japanese
);
2462 } else if (locale
.Language().EqualTo("zh")) {
2463 if (locale
.Region().EqualTo("CN")) {
2464 AppendPrefLang(tempPrefLangs
, tempLen
, eFontPrefLang_ChineseCN
);
2465 } else if (locale
.Region().EqualTo("TW")) {
2466 AppendPrefLang(tempPrefLangs
, tempLen
, eFontPrefLang_ChineseTW
);
2467 } else if (locale
.Region().EqualTo("HK")) {
2468 AppendPrefLang(tempPrefLangs
, tempLen
, eFontPrefLang_ChineseHK
);
2470 } else if (locale
.Language().EqualTo("ko")) {
2471 AppendPrefLang(tempPrefLangs
, tempLen
, eFontPrefLang_Korean
);
2477 // Last resort... set up CJK font prefs in the order listed by the user-
2478 // configurable ordering pref.
2479 gfxFontUtils::GetPrefsFontList(kCJKFallbackOrderPref
, list
);
2480 for (const auto& item
: list
) {
2481 eFontPrefLang fpl
= GetFontPrefLangFor(item
.get());
2483 case eFontPrefLang_Japanese
:
2484 case eFontPrefLang_Korean
:
2485 case eFontPrefLang_ChineseCN
:
2486 case eFontPrefLang_ChineseHK
:
2487 case eFontPrefLang_ChineseTW
:
2488 AppendPrefLang(tempPrefLangs
, tempLen
, fpl
);
2495 // Truly-last resort... try Chinese font prefs before Japanese because
2496 // they tend to have more complete character coverage, and therefore less
2497 // risk of "ransom-note" effects.
2498 // (If the kCJKFallbackOrderPref was fully populated, as it is by default,
2499 // this will do nothing as all these values are already present.)
2500 AppendPrefLang(tempPrefLangs
, tempLen
, eFontPrefLang_ChineseCN
);
2501 AppendPrefLang(tempPrefLangs
, tempLen
, eFontPrefLang_ChineseHK
);
2502 AppendPrefLang(tempPrefLangs
, tempLen
, eFontPrefLang_ChineseTW
);
2503 AppendPrefLang(tempPrefLangs
, tempLen
, eFontPrefLang_Japanese
);
2504 AppendPrefLang(tempPrefLangs
, tempLen
, eFontPrefLang_Korean
);
2506 // copy into the cached array
2507 for (const auto lang
: Span
<eFontPrefLang
>(tempPrefLangs
, tempLen
)) {
2508 mCJKPrefLangs
.AppendElement(lang
);
2512 // append in cached CJK langs
2513 for (const auto lang
: mCJKPrefLangs
) {
2514 AppendPrefLang(aPrefLangs
, aLen
, eFontPrefLang(lang
));
2518 void gfxPlatformFontList::AppendPrefLang(eFontPrefLang aPrefLangs
[],
2520 eFontPrefLang aAddLang
) {
2521 if (aLen
>= kMaxLenPrefLangList
) {
2525 // If the lang is already present, just ignore the addition.
2526 for (const auto lang
: Span
<eFontPrefLang
>(aPrefLangs
, aLen
)) {
2527 if (lang
== aAddLang
) {
2532 aPrefLangs
[aLen
++] = aAddLang
;
2535 StyleGenericFontFamily
gfxPlatformFontList::GetDefaultGeneric(
2536 eFontPrefLang aLang
) {
2537 if (aLang
== eFontPrefLang_Emoji
) {
2538 return StyleGenericFontFamily::MozEmoji
;
2541 AutoLock
lock(mLock
);
2543 if (uint32_t(aLang
) < ArrayLength(gPrefLangNames
)) {
2544 return mDefaultGenericsLangGroup
[uint32_t(aLang
)];
2546 return StyleGenericFontFamily::Serif
;
2549 FontFamily
gfxPlatformFontList::GetDefaultFont(nsPresContext
* aPresContext
,
2550 const gfxFontStyle
* aStyle
) {
2551 AutoLock
lock(mLock
);
2552 return GetDefaultFontLocked(aPresContext
, aStyle
);
2555 FontFamily
gfxPlatformFontList::GetDefaultFontLocked(
2556 nsPresContext
* aPresContext
, const gfxFontStyle
* aStyle
) {
2557 FontFamily family
= GetDefaultFontForPlatform(aPresContext
, aStyle
);
2558 if (!family
.IsNull()) {
2561 // Something has gone wrong and we were unable to retrieve a default font
2562 // from the platform. (Likely the whitelist has blocked all potential
2563 // default fonts.) As a last resort, we return the first font in our list.
2564 if (SharedFontList()) {
2565 MOZ_RELEASE_ASSERT(SharedFontList()->NumFamilies() > 0);
2566 return FontFamily(SharedFontList()->Families());
2568 MOZ_RELEASE_ASSERT(mFontFamilies
.Count() > 0);
2569 return FontFamily(mFontFamilies
.ConstIter().Data());
2572 void gfxPlatformFontList::GetFontFamilyNames(
2573 nsTArray
<nsCString
>& aFontFamilyNames
) {
2574 if (SharedFontList()) {
2575 fontlist::FontList
* list
= SharedFontList();
2576 const fontlist::Family
* families
= list
->Families();
2578 for (uint32_t i
= 0, n
= list
->NumFamilies(); i
< n
; i
++) {
2579 const fontlist::Family
& family
= families
[i
];
2580 if (!family
.IsHidden()) {
2581 aFontFamilyNames
.AppendElement(family
.DisplayName().AsString(list
));
2586 for (const RefPtr
<gfxFontFamily
>& family
: mFontFamilies
.Values()) {
2587 if (!family
->IsHidden()) {
2588 aFontFamilyNames
.AppendElement(family
->Name());
2594 nsAtom
* gfxPlatformFontList::GetLangGroup(nsAtom
* aLanguage
) {
2595 // map lang ==> langGroup
2596 nsAtom
* langGroup
= nullptr;
2598 langGroup
= mLangService
->GetLanguageGroup(aLanguage
);
2601 langGroup
= nsGkAtoms::Unicode
;
2606 /* static */ const char* gfxPlatformFontList::GetGenericName(
2607 StyleGenericFontFamily aGenericType
) {
2608 // type should be standard generic type at this point
2609 // map generic type to string
2610 switch (aGenericType
) {
2611 case StyleGenericFontFamily::Serif
:
2613 case StyleGenericFontFamily::SansSerif
:
2614 return "sans-serif";
2615 case StyleGenericFontFamily::Monospace
:
2617 case StyleGenericFontFamily::Cursive
:
2619 case StyleGenericFontFamily::Fantasy
:
2621 case StyleGenericFontFamily::SystemUi
:
2623 case StyleGenericFontFamily::MozEmoji
:
2624 return "-moz-emoji";
2625 case StyleGenericFontFamily::None
:
2628 MOZ_ASSERT_UNREACHABLE("Unknown generic");
2632 void gfxPlatformFontList::InitLoader() {
2633 GetFontFamilyNames(mFontInfo
->mFontFamiliesToLoad
);
2635 mNumFamilies
= mFontInfo
->mFontFamiliesToLoad
.Length();
2636 memset(&(mFontInfo
->mLoadStats
), 0, sizeof(mFontInfo
->mLoadStats
));
2639 #define FONT_LOADER_MAX_TIMESLICE \
2640 20 // max time for one pass through RunLoader = 20ms
2642 bool gfxPlatformFontList::LoadFontInfo() {
2643 AutoLock
lock(mLock
);
2644 TimeStamp start
= TimeStamp::Now();
2645 uint32_t i
, endIndex
= mNumFamilies
;
2646 fontlist::FontList
* list
= SharedFontList();
2648 !list
&& (!UsesSystemFallback() ||
2649 gfxPlatform::GetPlatform()->UseCmapsDuringSystemFallback());
2651 // for each font family, load in various font info
2652 for (i
= mStartIndex
; i
< endIndex
; i
++) {
2654 GenerateFontListKey(mFontInfo
->mFontFamiliesToLoad
[i
], key
);
2657 fontlist::Family
* family
= list
->FindFamily(key
);
2661 ReadFaceNamesForFamily(family
, NeedFullnamePostscriptNames());
2663 // lookup in canonical (i.e. English) family name list
2664 gfxFontFamily
* familyEntry
= mFontFamilies
.GetWeak(key
);
2669 // read in face names
2670 familyEntry
->ReadFaceNames(this, NeedFullnamePostscriptNames(),
2673 // load the cmaps if needed
2675 familyEntry
->ReadAllCMAPs(mFontInfo
);
2679 // Limit the time spent reading fonts in one pass, unless the font-loader
2680 // delay was set to zero, in which case we run to completion even if it
2681 // causes some jank.
2682 if (StaticPrefs::gfx_font_loader_delay() > 0) {
2683 TimeDuration elapsed
= TimeStamp::Now() - start
;
2684 if (elapsed
.ToMilliseconds() > FONT_LOADER_MAX_TIMESLICE
&&
2685 i
+ 1 != endIndex
) {
2692 mStartIndex
= endIndex
;
2693 bool done
= mStartIndex
>= mNumFamilies
;
2695 if (LOG_FONTINIT_ENABLED()) {
2696 TimeDuration elapsed
= TimeStamp::Now() - start
;
2697 LOG_FONTINIT(("(fontinit) fontloader load pass %8.2f ms done %s\n",
2698 elapsed
.ToMilliseconds(), (done
? "true" : "false")));
2702 mOtherFamilyNamesInitialized
= true;
2703 CancelInitOtherFamilyNamesTask();
2704 mFaceNameListsInitialized
= true;
2710 void gfxPlatformFontList::CleanupLoader() {
2711 AutoLock
lock(mLock
);
2713 mFontFamiliesToLoad
.Clear();
2715 bool rebuilt
= false, forceReflow
= false;
2717 // if had missed face names that are now available, force reflow all
2718 if (mFaceNamesMissed
) {
2719 rebuilt
= std::any_of(mFaceNamesMissed
->cbegin(), mFaceNamesMissed
->cend(),
2720 [&](const auto& key
) {
2721 mLock
.AssertCurrentThreadIn();
2722 return FindFaceName(key
);
2725 RebuildLocalFonts();
2728 mFaceNamesMissed
= nullptr;
2731 if (mOtherNamesMissed
) {
2732 forceReflow
= std::any_of(
2733 mOtherNamesMissed
->cbegin(), mOtherNamesMissed
->cend(),
2734 [&](const auto& key
) {
2735 mLock
.AssertCurrentThreadIn();
2736 return FindUnsharedFamily(
2738 (FindFamiliesFlags::eForceOtherFamilyNamesLoading
|
2739 FindFamiliesFlags::eNoAddToNamesMissedWhenSearching
));
2742 ForceGlobalReflowLocked(gfxPlatform::NeedsReframe::No
);
2745 mOtherNamesMissed
= nullptr;
2748 if (LOG_FONTINIT_ENABLED() && mFontInfo
) {
2750 ("(fontinit) fontloader load thread took %8.2f ms "
2751 "%d families %d fonts %d cmaps "
2752 "%d facenames %d othernames %s %s",
2753 mLoadTime
.ToMilliseconds(), mFontInfo
->mLoadStats
.families
,
2754 mFontInfo
->mLoadStats
.fonts
, mFontInfo
->mLoadStats
.cmaps
,
2755 mFontInfo
->mLoadStats
.facenames
, mFontInfo
->mLoadStats
.othernames
,
2756 (rebuilt
? "(userfont sets rebuilt)" : ""),
2757 (forceReflow
? "(global reflow)" : "")));
2760 gfxFontInfoLoader::CleanupLoader();
2763 void gfxPlatformFontList::ForceGlobalReflowLocked(
2764 gfxPlatform::NeedsReframe aNeedsReframe
,
2765 gfxPlatform::BroadcastToChildren aBroadcastToChildren
) {
2766 if (!NS_IsMainThread()) {
2767 NS_DispatchToMainThread(NS_NewRunnableFunction(
2768 "gfxPlatformFontList::ForceGlobalReflowLocked",
2769 [aNeedsReframe
, aBroadcastToChildren
] {
2770 gfxPlatform::ForceGlobalReflow(aNeedsReframe
, aBroadcastToChildren
);
2775 AutoUnlock
unlock(mLock
);
2776 gfxPlatform::ForceGlobalReflow(aNeedsReframe
, aBroadcastToChildren
);
2779 void gfxPlatformFontList::GetPrefsAndStartLoader() {
2780 // If we're already in shutdown, there's no point in starting this, and it
2781 // could trigger an assertion if we try to use the Thread Manager too late.
2782 if (AppShutdown::IsInOrBeyond(ShutdownPhase::AppShutdownConfirmed
)) {
2785 uint32_t delay
= std::max(1u, StaticPrefs::gfx_font_loader_delay());
2786 if (NS_IsMainThread()) {
2789 NS_DispatchToMainThread(NS_NewRunnableFunction(
2790 "StartLoader callback", [delay
, fontList
= this] {
2792 fontList
->StartLoader(delay
);
2798 void gfxPlatformFontList::RebuildLocalFonts(bool aForgetLocalFaces
) {
2799 for (auto* fontset
: mUserFontSetList
) {
2800 if (aForgetLocalFaces
) {
2801 fontset
->ForgetLocalFaces();
2803 fontset
->RebuildLocalRules();
2807 void gfxPlatformFontList::ClearLangGroupPrefFontsLocked() {
2808 for (uint32_t i
= eFontPrefLang_First
;
2809 i
< eFontPrefLang_First
+ eFontPrefLang_Count
; i
++) {
2810 auto& prefFontsLangGroup
= mLangGroupPrefFonts
[i
];
2811 for (auto& pref
: prefFontsLangGroup
) {
2815 mCJKPrefLangs
.Clear();
2816 mEmojiPrefFont
= nullptr;
2818 // Create a new FontPrefs and replace the existing one.
2819 mFontPrefs
= MakeUnique
<FontPrefs
>();
2822 // Support for memory reporting
2824 // this is also used by subclasses that hold additional font tables
2826 size_t gfxPlatformFontList::SizeOfFontFamilyTableExcludingThis(
2827 const FontFamilyTable
& aTable
, MallocSizeOf aMallocSizeOf
) {
2828 return std::accumulate(
2829 aTable
.Keys().cbegin(), aTable
.Keys().cend(),
2830 aTable
.ShallowSizeOfExcludingThis(aMallocSizeOf
),
2831 [&](size_t oldValue
, const nsACString
& key
) {
2832 // We don't count the size of the family here, because this is an
2833 // *extra* reference to a family that will have already been counted in
2835 return oldValue
+ key
.SizeOfExcludingThisIfUnshared(aMallocSizeOf
);
2840 size_t gfxPlatformFontList::SizeOfFontEntryTableExcludingThis(
2841 const FontEntryTable
& aTable
, MallocSizeOf aMallocSizeOf
) {
2842 return std::accumulate(
2843 aTable
.Keys().cbegin(), aTable
.Keys().cend(),
2844 aTable
.ShallowSizeOfExcludingThis(aMallocSizeOf
),
2845 [&](size_t oldValue
, const nsACString
& key
) {
2846 // The font itself is counted by its owning family; here we only care
2847 // about the names stored in the hashtable keys.
2849 return oldValue
+ key
.SizeOfExcludingThisIfUnshared(aMallocSizeOf
);
2853 void gfxPlatformFontList::AddSizeOfExcludingThis(MallocSizeOf aMallocSizeOf
,
2854 FontListSizes
* aSizes
) const {
2855 AutoLock
lock(mLock
);
2857 aSizes
->mFontListSize
+=
2858 mFontFamilies
.ShallowSizeOfExcludingThis(aMallocSizeOf
);
2859 for (const auto& entry
: mFontFamilies
) {
2860 aSizes
->mFontListSize
+=
2861 entry
.GetKey().SizeOfExcludingThisIfUnshared(aMallocSizeOf
);
2862 entry
.GetData()->AddSizeOfIncludingThis(aMallocSizeOf
, aSizes
);
2865 aSizes
->mFontListSize
+=
2866 SizeOfFontFamilyTableExcludingThis(mOtherFamilyNames
, aMallocSizeOf
);
2869 aSizes
->mFontListSize
+= SizeOfFontEntryTableExcludingThis(
2870 mExtraNames
->mFullnames
, aMallocSizeOf
);
2871 aSizes
->mFontListSize
+= SizeOfFontEntryTableExcludingThis(
2872 mExtraNames
->mPostscriptNames
, aMallocSizeOf
);
2875 for (uint32_t i
= eFontPrefLang_First
;
2876 i
< eFontPrefLang_First
+ eFontPrefLang_Count
; i
++) {
2877 auto& prefFontsLangGroup
= mLangGroupPrefFonts
[i
];
2878 for (const UniquePtr
<PrefFontList
>& pf
: prefFontsLangGroup
) {
2880 aSizes
->mFontListSize
+= pf
->ShallowSizeOfExcludingThis(aMallocSizeOf
);
2885 for (const auto& bitset
: mCodepointsWithNoFonts
) {
2886 aSizes
->mFontListSize
+= bitset
.SizeOfExcludingThis(aMallocSizeOf
);
2888 aSizes
->mFontListSize
+=
2889 mFontFamiliesToLoad
.ShallowSizeOfExcludingThis(aMallocSizeOf
);
2891 aSizes
->mFontListSize
+=
2892 mBadUnderlineFamilyNames
.ShallowSizeOfExcludingThis(aMallocSizeOf
);
2893 for (const auto& i
: mBadUnderlineFamilyNames
) {
2894 aSizes
->mFontListSize
+= i
.SizeOfExcludingThisIfUnshared(aMallocSizeOf
);
2897 aSizes
->mFontListSize
+=
2898 mSharedCmaps
.ShallowSizeOfExcludingThis(aMallocSizeOf
);
2899 for (const auto& entry
: mSharedCmaps
) {
2900 aSizes
->mCharMapsSize
+= entry
.GetKey()->SizeOfIncludingThis(aMallocSizeOf
);
2903 aSizes
->mFontListSize
+=
2904 mFontEntries
.ShallowSizeOfExcludingThis(aMallocSizeOf
);
2905 for (const auto& entry
: mFontEntries
.Values()) {
2907 entry
->AddSizeOfIncludingThis(aMallocSizeOf
, aSizes
);
2911 if (SharedFontList()) {
2912 aSizes
->mFontListSize
+=
2913 SharedFontList()->SizeOfIncludingThis(aMallocSizeOf
);
2914 if (XRE_IsParentProcess()) {
2915 aSizes
->mSharedSize
+= SharedFontList()->AllocatedShmemSize();
2920 void gfxPlatformFontList::AddSizeOfIncludingThis(MallocSizeOf aMallocSizeOf
,
2921 FontListSizes
* aSizes
) const {
2922 aSizes
->mFontListSize
+= aMallocSizeOf(this);
2923 AddSizeOfExcludingThis(aMallocSizeOf
, aSizes
);
2926 void gfxPlatformFontList::InitOtherFamilyNamesInternal(
2927 bool aDeferOtherFamilyNamesLoading
) {
2928 if (mOtherFamilyNamesInitialized
) {
2932 AutoLock
lock(mLock
);
2934 if (aDeferOtherFamilyNamesLoading
) {
2935 TimeStamp start
= TimeStamp::Now();
2936 bool timedOut
= false;
2938 auto list
= SharedFontList();
2940 // If the gfxFontInfoLoader task is not yet running, kick it off now so
2941 // that it will load remaining names etc as soon as idle time permits.
2942 if (mState
== stateInitial
|| mState
== stateTimerOnDelay
) {
2947 for (const RefPtr
<gfxFontFamily
>& family
: mFontFamilies
.Values()) {
2948 family
->ReadOtherFamilyNames(this);
2949 TimeDuration elapsed
= TimeStamp::Now() - start
;
2950 if (elapsed
.ToMilliseconds() > OTHERNAMES_TIMEOUT
) {
2958 mOtherFamilyNamesInitialized
= true;
2959 CancelInitOtherFamilyNamesTask();
2961 TimeStamp end
= TimeStamp::Now();
2962 Telemetry::AccumulateTimeDelta(Telemetry::FONTLIST_INITOTHERFAMILYNAMES
,
2965 if (LOG_FONTINIT_ENABLED()) {
2966 TimeDuration elapsed
= end
- start
;
2967 LOG_FONTINIT(("(fontinit) InitOtherFamilyNames took %8.2f ms %s",
2968 elapsed
.ToMilliseconds(), (timedOut
? "timeout" : "")));
2971 TimeStamp start
= TimeStamp::Now();
2973 auto list
= SharedFontList();
2975 for (auto& f
: mozilla::Range
<fontlist::Family
>(list
->Families(),
2976 list
->NumFamilies())) {
2977 ReadFaceNamesForFamily(&f
, false);
2980 for (const RefPtr
<gfxFontFamily
>& family
: mFontFamilies
.Values()) {
2981 family
->ReadOtherFamilyNames(this);
2985 mOtherFamilyNamesInitialized
= true;
2986 CancelInitOtherFamilyNamesTask();
2988 TimeStamp end
= TimeStamp::Now();
2989 Telemetry::AccumulateTimeDelta(
2990 Telemetry::FONTLIST_INITOTHERFAMILYNAMES_NO_DEFERRING
, start
, end
);
2992 if (LOG_FONTINIT_ENABLED()) {
2993 TimeDuration elapsed
= end
- start
;
2995 ("(fontinit) InitOtherFamilyNames without deferring took %8.2f ms",
2996 elapsed
.ToMilliseconds()));
3001 void gfxPlatformFontList::CancelInitOtherFamilyNamesTask() {
3002 if (mPendingOtherFamilyNameTask
) {
3003 mPendingOtherFamilyNameTask
->Cancel();
3004 mPendingOtherFamilyNameTask
= nullptr;
3006 auto list
= SharedFontList();
3007 if (list
&& XRE_IsParentProcess()) {
3008 bool forceReflow
= false;
3009 if (!mAliasTable
.IsEmpty()) {
3010 list
->SetAliases(mAliasTable
);
3011 mAliasTable
.Clear();
3014 if (mLocalNameTable
.Count()) {
3015 list
->SetLocalNames(mLocalNameTable
);
3016 mLocalNameTable
.Clear();
3020 dom::ContentParent::BroadcastFontListChanged();
3025 void gfxPlatformFontList::ShareFontListShmBlockToProcess(
3026 uint32_t aGeneration
, uint32_t aIndex
, base::ProcessId aPid
,
3027 base::SharedMemoryHandle
* aOut
) {
3028 auto list
= SharedFontList();
3032 if (!aGeneration
|| list
->GetGeneration() == aGeneration
) {
3033 list
->ShareShmBlockToProcess(aIndex
, aPid
, aOut
);
3035 *aOut
= base::SharedMemory::NULLHandle();
3039 void gfxPlatformFontList::ShareFontListToProcess(
3040 nsTArray
<base::SharedMemoryHandle
>* aBlocks
, base::ProcessId aPid
) {
3041 auto list
= SharedFontList();
3043 list
->ShareBlocksToProcess(aBlocks
, aPid
);
3047 base::SharedMemoryHandle
gfxPlatformFontList::ShareShmBlockToProcess(
3048 uint32_t aIndex
, base::ProcessId aPid
) {
3049 MOZ_RELEASE_ASSERT(SharedFontList());
3050 return SharedFontList()->ShareBlockToProcess(aIndex
, aPid
);
3053 void gfxPlatformFontList::ShmBlockAdded(uint32_t aGeneration
, uint32_t aIndex
,
3054 base::SharedMemoryHandle aHandle
) {
3055 if (SharedFontList()) {
3056 AutoLock
lock(mLock
);
3057 SharedFontList()->ShmBlockAdded(aGeneration
, aIndex
, std::move(aHandle
));
3061 void gfxPlatformFontList::InitializeFamily(uint32_t aGeneration
,
3062 uint32_t aFamilyIndex
,
3064 auto list
= SharedFontList();
3069 if (list
->GetGeneration() != aGeneration
) {
3072 if (AppShutdown::IsInOrBeyond(ShutdownPhase::AppShutdownConfirmed
)) {
3075 if (aFamilyIndex
>= list
->NumFamilies()) {
3078 fontlist::Family
* family
= list
->Families() + aFamilyIndex
;
3079 if (!family
->IsInitialized() || aLoadCmaps
) {
3080 Unused
<< InitializeFamily(family
, aLoadCmaps
);
3084 void gfxPlatformFontList::SetCharacterMap(uint32_t aGeneration
,
3085 uint32_t aFamilyIndex
, bool aAlias
,
3086 uint32_t aFaceIndex
,
3087 const gfxSparseBitSet
& aMap
) {
3088 MOZ_ASSERT(XRE_IsParentProcess());
3089 auto list
= SharedFontList();
3094 if (list
->GetGeneration() != aGeneration
) {
3097 if (AppShutdown::IsInOrBeyond(ShutdownPhase::AppShutdownConfirmed
)) {
3101 const fontlist::Family
* family
;
3103 if (aFamilyIndex
>= list
->NumAliases()) {
3104 MOZ_ASSERT(false, "AliasFamily index out of range");
3107 family
= list
->AliasFamilies() + aFamilyIndex
;
3109 if (aFamilyIndex
>= list
->NumFamilies()) {
3110 MOZ_ASSERT(false, "Family index out of range");
3113 family
= list
->Families() + aFamilyIndex
;
3116 if (aFaceIndex
>= family
->NumFaces()) {
3117 MOZ_ASSERT(false, "Face index out of range");
3122 family
->Faces(list
)[aFaceIndex
].ToPtr
<fontlist::Face
>(list
)) {
3123 face
->mCharacterMap
= GetShmemCharMap(&aMap
);
3127 void gfxPlatformFontList::SetupFamilyCharMap(uint32_t aGeneration
,
3128 uint32_t aIndex
, bool aAlias
) {
3129 MOZ_ASSERT(XRE_IsParentProcess());
3130 auto list
= SharedFontList();
3135 if (list
->GetGeneration() != aGeneration
) {
3138 if (AppShutdown::IsInOrBeyond(ShutdownPhase::AppShutdownConfirmed
)) {
3143 if (aIndex
>= list
->NumAliases()) {
3144 MOZ_ASSERT(false, "AliasFamily index out of range");
3147 list
->AliasFamilies()[aIndex
].SetupFamilyCharMap(list
);
3151 if (aIndex
>= list
->NumFamilies()) {
3152 MOZ_ASSERT(false, "Family index out of range");
3155 list
->Families()[aIndex
].SetupFamilyCharMap(list
);
3158 bool gfxPlatformFontList::InitOtherFamilyNames(uint32_t aGeneration
,
3160 auto list
= SharedFontList();
3165 if (list
->GetGeneration() != aGeneration
) {
3168 if (AppShutdown::IsInOrBeyond(ShutdownPhase::AppShutdownConfirmed
)) {
3171 return InitOtherFamilyNames(aDefer
);
3174 uint32_t gfxPlatformFontList::GetGeneration() const {
3175 return SharedFontList() ? SharedFontList()->GetGeneration() : 0;
3178 gfxPlatformFontList::FontPrefs::FontPrefs() {
3179 // This must be created on the main thread, so that we can safely use the
3180 // Preferences service. Once created, it can be read from any thread.
3181 MOZ_ASSERT(NS_IsMainThread());
3185 void gfxPlatformFontList::FontPrefs::Init() {
3186 if (AppShutdown::IsInOrBeyond(ShutdownPhase::XPCOMShutdownFinal
)) {
3189 nsIPrefBranch
* prefRootBranch
= Preferences::GetRootBranch();
3190 if (!prefRootBranch
) {
3193 nsTArray
<nsCString
> prefNames
;
3194 if (NS_SUCCEEDED(prefRootBranch
->GetChildList(kNamePrefix
, prefNames
))) {
3195 for (auto& prefName
: prefNames
) {
3196 nsAutoCString value
;
3197 if (NS_SUCCEEDED(Preferences::GetCString(prefName
.get(), value
))) {
3198 nsAutoCString
pref(Substring(prefName
, sizeof(kNamePrefix
) - 1));
3199 mFontName
.InsertOrUpdate(pref
, value
);
3203 if (NS_SUCCEEDED(prefRootBranch
->GetChildList(kNameListPrefix
, prefNames
))) {
3204 for (auto& prefName
: prefNames
) {
3205 nsAutoCString value
;
3206 if (NS_SUCCEEDED(Preferences::GetCString(prefName
.get(), value
))) {
3207 nsAutoCString
pref(Substring(prefName
, sizeof(kNameListPrefix
) - 1));
3208 mFontNameList
.InsertOrUpdate(pref
, value
);
3212 mEmojiHasUserValue
= Preferences::HasUserValue("font.name-list.emoji");
3215 bool gfxPlatformFontList::FontPrefs::LookupName(const nsACString
& aPref
,
3216 nsACString
& aValue
) const {
3217 if (const auto& value
= mFontName
.Lookup(aPref
)) {
3224 bool gfxPlatformFontList::FontPrefs::LookupNameList(const nsACString
& aPref
,
3225 nsACString
& aValue
) const {
3226 if (const auto& value
= mFontNameList
.Lookup(aPref
)) {
3233 bool gfxPlatformFontList::IsKnownIconFontFamily(
3234 const nsAtom
* aFamilyName
) const {
3235 nsAtomCString
fam(aFamilyName
);
3237 return mIconFontsSet
.Contains(fam
);