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
);
382 void gfxPlatformFontList::FontWhitelistPrefChanged(const char* aPref
,
384 MOZ_ASSERT(XRE_IsParentProcess());
385 auto* pfl
= gfxPlatformFontList::PlatformFontList();
386 pfl
->UpdateFontList(true);
387 dom::ContentParent::NotifyUpdatedFonts(true);
390 void gfxPlatformFontList::ApplyWhitelist() {
391 uint32_t numFonts
= mEnabledFontsList
.Length();
392 if (!mFontFamilyWhitelistActive
) {
395 nsTHashSet
<nsCString
> familyNamesWhitelist
;
396 for (uint32_t i
= 0; i
< numFonts
; i
++) {
398 ToLowerCase(mEnabledFontsList
[i
], key
);
399 familyNamesWhitelist
.Insert(key
);
401 AutoTArray
<RefPtr
<gfxFontFamily
>, 128> accepted
;
402 bool whitelistedFontFound
= false;
403 for (const auto& entry
: mFontFamilies
) {
404 if (entry
.GetData()->IsHidden()) {
405 // Hidden system fonts are exempt from whitelisting, but don't count
406 // towards determining whether we "kept" any (user-visible) fonts
407 accepted
.AppendElement(entry
.GetData());
410 nsAutoCString
fontFamilyName(entry
.GetKey());
411 ToLowerCase(fontFamilyName
);
412 if (familyNamesWhitelist
.Contains(fontFamilyName
)) {
413 accepted
.AppendElement(entry
.GetData());
414 whitelistedFontFound
= true;
417 if (!whitelistedFontFound
) {
418 // No whitelisted fonts found! Ignore the whitelist.
421 // Replace the original full list with the accepted subset.
422 mFontFamilies
.Clear();
423 for (auto& f
: accepted
) {
424 nsAutoCString
fontFamilyName(f
->Name());
425 ToLowerCase(fontFamilyName
);
426 mFontFamilies
.InsertOrUpdate(fontFamilyName
, std::move(f
));
430 void gfxPlatformFontList::ApplyWhitelist(
431 nsTArray
<fontlist::Family::InitData
>& aFamilies
) {
432 mLock
.AssertCurrentThreadIn();
433 if (!mFontFamilyWhitelistActive
) {
436 nsTHashSet
<nsCString
> familyNamesWhitelist
;
437 for (const auto& item
: mEnabledFontsList
) {
439 ToLowerCase(item
, key
);
440 familyNamesWhitelist
.Insert(key
);
442 AutoTArray
<fontlist::Family::InitData
, 128> accepted
;
443 bool keptNonHidden
= false;
444 for (auto& f
: aFamilies
) {
445 if (f
.mVisibility
== FontVisibility::Hidden
||
446 familyNamesWhitelist
.Contains(f
.mKey
)) {
447 accepted
.AppendElement(f
);
448 if (f
.mVisibility
!= FontVisibility::Hidden
) {
449 keptNonHidden
= true;
453 if (!keptNonHidden
) {
454 // No (visible) families were whitelisted: ignore the whitelist
455 // and just leave the fontlist unchanged.
458 aFamilies
= std::move(accepted
);
461 bool gfxPlatformFontList::FamilyInList(const nsACString
& aName
,
462 const char* aList
[], size_t aCount
) {
464 return BinarySearchIf(
466 [&](const char* const aVal
) -> int {
467 return nsCaseInsensitiveUTF8StringComparator(
468 aName
.BeginReading(), aVal
, aName
.Length(), strlen(aVal
));
473 void gfxPlatformFontList::CheckFamilyList(const char* aList
[], size_t aCount
) {
475 MOZ_ASSERT(aCount
> 0, "empty font family list?");
476 const char* a
= aList
[0];
477 uint32_t aLen
= strlen(a
);
478 for (size_t i
= 1; i
< aCount
; ++i
) {
479 const char* b
= aList
[i
];
480 uint32_t bLen
= strlen(b
);
481 if (nsCaseInsensitiveUTF8StringComparator(a
, b
, aLen
, bLen
) >= 0) {
482 MOZ_CRASH_UNSAFE_PRINTF("incorrectly sorted font family list: %s >= %s",
491 bool gfxPlatformFontList::AddWithLegacyFamilyName(const nsACString
& aLegacyName
,
492 gfxFontEntry
* aFontEntry
,
493 FontVisibility aVisibility
) {
494 mLock
.AssertCurrentThreadIn();
497 ToLowerCase(aLegacyName
, key
);
499 .LookupOrInsertWith(key
,
501 RefPtr
<gfxFontFamily
> family
=
502 CreateFontFamily(aLegacyName
, aVisibility
);
503 // We don't want the family to search for faces,
504 // we're adding them directly here.
505 family
->SetHasStyles(true);
506 // And we don't want it to attempt to search for
507 // legacy names, because we've already done that
508 // (and this is the result).
509 family
->SetCheckedForLegacyFamilyNames(true);
513 ->AddFontEntry(aFontEntry
->Clone());
517 bool gfxPlatformFontList::InitFontList() {
518 // If the startup font-list-init thread is still running, we need to wait
519 // for it to finish before trying to reinitialize here.
520 if (sInitFontListThread
&& !IsInitFontListThread()) {
521 PR_JoinThread(sInitFontListThread
);
522 sInitFontListThread
= nullptr;
525 AutoLock
lock(mLock
);
527 if (LOG_FONTINIT_ENABLED()) {
528 LOG_FONTINIT(("(fontinit) system fontlist initialization\n"));
531 if (IsInitialized()) {
532 // Font-list reinitialization always occurs on the main thread, in response
533 // to a change notification; it's only the initial creation during startup
534 // that may be on another thread.
535 MOZ_ASSERT(NS_IsMainThread());
537 // Rebuilding fontlist so clear out font/word caches.
538 gfxFontCache
* fontCache
= gfxFontCache::GetCache();
540 fontCache
->FlushShapedWordCaches();
544 gfxPlatform::PurgeSkiaFontCache();
546 // There's no need to broadcast this reflow request to child processes, as
547 // ContentParent::NotifyUpdatedFonts deals with it by re-entering into this
548 // function on child processes.
549 ForceGlobalReflowLocked(gfxPlatform::NeedsReframe::Yes
,
550 gfxPlatform::BroadcastToChildren::No
);
553 mLocalNameTable
.Clear();
554 mIconFontsSet
.Clear();
556 CancelLoadCmapsTask();
557 mStartedLoadingCmapsFrom
= 0xffffffffu
;
559 CancelInitOtherFamilyNamesTask();
560 mFontFamilies
.Clear();
561 mOtherFamilyNames
.Clear();
562 mOtherFamilyNamesInitialized
= false;
565 mExtraNames
->mFullnames
.Clear();
566 mExtraNames
->mPostscriptNames
.Clear();
568 mFaceNameListsInitialized
= false;
569 ClearLangGroupPrefFontsLocked();
572 // Clear cached family records that will no longer be valid.
573 for (auto& f
: mReplacementCharFallbackFamily
) {
577 gfxFontUtils::GetPrefsFontList(kFontSystemWhitelistPref
, mEnabledFontsList
);
578 mFontFamilyWhitelistActive
= !mEnabledFontsList
.IsEmpty();
580 LoadIconFontOverrideList();
583 // From here, gfxPlatformFontList::IsInitialized will return true,
584 // unless InitFontListForPlatform() fails and we reset it below.
585 mFontlistInitCount
++;
587 InitializeCodepointsWithNoFonts();
589 // Try to initialize the cross-process shared font list if enabled by prefs,
590 // but not if we're running in Safe Mode.
591 if (StaticPrefs::gfx_e10s_font_list_shared_AtStartup() &&
592 !gfxPlatform::InSafeMode()) {
593 for (const auto& entry
: mFontEntries
.Values()) {
597 AutoWriteLock
lock(entry
->mLock
);
598 entry
->mShmemCharacterMap
= nullptr;
599 entry
->mShmemFace
= nullptr;
600 entry
->mFamilyName
.Truncate();
602 mFontEntries
.Clear();
603 mShmemCharMaps
.Clear();
604 bool oldSharedList
= mSharedFontList
!= nullptr;
605 mSharedFontList
.reset(new fontlist::FontList(mFontlistInitCount
));
606 InitSharedFontListForPlatform();
607 if (mSharedFontList
&& mSharedFontList
->Initialized()) {
608 if (mLocalNameTable
.Count()) {
609 SharedFontList()->SetLocalNames(mLocalNameTable
);
610 mLocalNameTable
.Clear();
613 // something went wrong, fall back to in-process list
614 gfxCriticalNote
<< "Failed to initialize shared font list, "
615 "falling back to in-process list.";
616 mSharedFontList
.reset(nullptr);
618 if (oldSharedList
&& XRE_IsParentProcess()) {
619 // notify all children of the change
620 if (NS_IsMainThread()) {
621 dom::ContentParent::NotifyUpdatedFonts(true);
623 NS_DispatchToMainThread(NS_NewRunnableFunction(
624 "NotifyUpdatedFonts callback",
625 [] { dom::ContentParent::NotifyUpdatedFonts(true); }));
630 if (!SharedFontList()) {
631 if (NS_FAILED(InitFontListForPlatform())) {
632 mFontlistInitCount
= 0;
638 // Set up mDefaultFontEntry as a "last resort" default that we can use
639 // to avoid crashing if the font list is otherwise unusable.
640 gfxFontStyle defStyle
;
641 FontFamily fam
= GetDefaultFontLocked(nullptr, &defStyle
);
644 auto face
= fam
.mShared
->FindFaceForStyle(SharedFontList(), defStyle
);
645 fe
= face
? GetOrCreateFontEntryLocked(face
, fam
.mShared
) : nullptr;
647 fe
= fam
.mUnshared
->FindFontForStyle(defStyle
);
649 mDefaultFontEntry
= fe
;
654 void gfxPlatformFontList::LoadIconFontOverrideList() {
655 mIconFontsSet
.Clear();
656 AutoTArray
<nsCString
, 20> iconFontsList
;
657 gfxFontUtils::GetPrefsFontList(kIconFontsPref
, iconFontsList
);
658 for (auto& name
: iconFontsList
) {
660 mIconFontsSet
.Insert(name
);
664 void gfxPlatformFontList::InitializeCodepointsWithNoFonts() {
665 auto& first
= mCodepointsWithNoFonts
[FontVisibility(0)];
666 for (auto& bitset
: mCodepointsWithNoFonts
) {
667 if (&bitset
== &first
) {
669 bitset
.SetRange(0, 0x1f); // C0 controls
670 bitset
.SetRange(0x7f, 0x9f); // C1 controls
671 bitset
.SetRange(0xE000, 0xF8FF); // PUA
672 bitset
.SetRange(0xF0000, 0x10FFFD); // Supplementary PUA
673 bitset
.SetRange(0xfdd0, 0xfdef); // noncharacters
674 for (unsigned i
= 0; i
<= 0x100000; i
+= 0x10000) {
675 bitset
.SetRange(i
+ 0xfffe, i
+ 0xffff); // noncharacters
684 void gfxPlatformFontList::FontListChanged() {
685 MOZ_ASSERT(!XRE_IsParentProcess());
686 AutoLock
lock(mLock
);
687 InitializeCodepointsWithNoFonts();
688 if (SharedFontList()) {
689 // If we're using a shared local face-name list, this may have changed
690 // such that existing font entries held by user font sets are no longer
691 // safe to use: ensure they all get flushed.
692 RebuildLocalFonts(/*aForgetLocalFaces*/ true);
694 ForceGlobalReflowLocked(gfxPlatform::NeedsReframe::Yes
);
697 void gfxPlatformFontList::GenerateFontListKey(const nsACString
& aKeyName
,
698 nsACString
& aResult
) {
700 ToLowerCase(aResult
);
703 // Used if a stylo thread wants to trigger InitOtherFamilyNames in the main
704 // process: we can't do IPC from the stylo thread so we post this to the main
706 class InitOtherFamilyNamesForStylo
: public mozilla::Runnable
{
708 explicit InitOtherFamilyNamesForStylo(bool aDeferOtherFamilyNamesLoading
)
709 : Runnable("gfxPlatformFontList::InitOtherFamilyNamesForStylo"),
710 mDefer(aDeferOtherFamilyNamesLoading
) {}
712 NS_IMETHOD
Run() override
{
713 auto pfl
= gfxPlatformFontList::PlatformFontList();
714 auto list
= pfl
->SharedFontList();
718 bool initialized
= false;
719 dom::ContentChild::GetSingleton()->SendInitOtherFamilyNames(
720 list
->GetGeneration(), mDefer
, &initialized
);
721 pfl
->mOtherFamilyNamesInitialized
.compareExchange(false, initialized
);
729 #define OTHERNAMES_TIMEOUT 200
731 bool gfxPlatformFontList::InitOtherFamilyNames(
732 bool aDeferOtherFamilyNamesLoading
) {
733 if (mOtherFamilyNamesInitialized
) {
737 if (SharedFontList() && !XRE_IsParentProcess()) {
738 if (NS_IsMainThread()) {
740 dom::ContentChild::GetSingleton()->SendInitOtherFamilyNames(
741 SharedFontList()->GetGeneration(), aDeferOtherFamilyNamesLoading
,
743 mOtherFamilyNamesInitialized
.compareExchange(false, initialized
);
745 NS_DispatchToMainThread(
746 new InitOtherFamilyNamesForStylo(aDeferOtherFamilyNamesLoading
));
748 return mOtherFamilyNamesInitialized
;
751 // If the font loader delay has been set to zero, we don't defer loading
752 // additional family names (regardless of the aDefer... parameter), as we
753 // take this to mean availability of font info is to be prioritized over
754 // potential startup perf or main-thread jank.
755 // (This is used so we can reliably run reftests that depend on localized
756 // font-family names being available.)
757 if (aDeferOtherFamilyNamesLoading
&&
758 StaticPrefs::gfx_font_loader_delay_AtStartup() > 0) {
759 if (!mPendingOtherFamilyNameTask
) {
760 RefPtr
<mozilla::CancelableRunnable
> task
=
761 new InitOtherFamilyNamesRunnable();
762 mPendingOtherFamilyNameTask
= task
;
763 NS_DispatchToMainThreadQueue(task
.forget(), EventQueuePriority::Idle
);
766 InitOtherFamilyNamesInternal(false);
768 return mOtherFamilyNamesInitialized
;
771 // time limit for loading facename lists (ms)
772 #define NAMELIST_TIMEOUT 200
774 gfxFontEntry
* gfxPlatformFontList::SearchFamiliesForFaceName(
775 const nsACString
& aFaceName
) {
776 TimeStamp start
= TimeStamp::Now();
777 bool timedOut
= false;
778 // if mFirstChar is not 0, only load facenames for families
779 // that start with this character
780 char16_t firstChar
= 0;
781 gfxFontEntry
* lookup
= nullptr;
783 // iterate over familes starting with the same letter
784 firstChar
= ToLowerCase(aFaceName
.CharAt(0));
786 for (const auto& entry
: mFontFamilies
) {
787 nsCStringHashKey::KeyType key
= entry
.GetKey();
788 const RefPtr
<gfxFontFamily
>& family
= entry
.GetData();
790 // when filtering, skip names that don't start with the filter character
791 if (firstChar
&& ToLowerCase(key
.CharAt(0)) != firstChar
) {
795 family
->ReadFaceNames(this, NeedFullnamePostscriptNames());
797 TimeDuration elapsed
= TimeStamp::Now() - start
;
798 if (elapsed
.ToMilliseconds() > NAMELIST_TIMEOUT
) {
804 lookup
= FindFaceName(aFaceName
);
806 TimeStamp end
= TimeStamp::Now();
807 Telemetry::AccumulateTimeDelta(Telemetry::FONTLIST_INITFACENAMELISTS
, start
,
809 if (LOG_FONTINIT_ENABLED()) {
810 TimeDuration elapsed
= end
- start
;
811 LOG_FONTINIT(("(fontinit) SearchFamiliesForFaceName took %8.2f ms %s %s",
812 elapsed
.ToMilliseconds(), (lookup
? "found name" : ""),
813 (timedOut
? "timeout" : "")));
819 gfxFontEntry
* gfxPlatformFontList::FindFaceName(const nsACString
& aFaceName
) {
820 gfxFontEntry
* lookup
;
822 // lookup in name lookup tables, return null if not found
824 ((lookup
= mExtraNames
->mPostscriptNames
.GetWeak(aFaceName
)) ||
825 (lookup
= mExtraNames
->mFullnames
.GetWeak(aFaceName
)))) {
832 gfxFontEntry
* gfxPlatformFontList::LookupInFaceNameLists(
833 const nsACString
& aFaceName
) {
834 gfxFontEntry
* lookup
= nullptr;
836 // initialize facename lookup tables if needed
837 // note: this can terminate early or time out, in which case
838 // mFaceNameListsInitialized remains false
839 if (!mFaceNameListsInitialized
) {
840 lookup
= SearchFamiliesForFaceName(aFaceName
);
846 // lookup in name lookup tables, return null if not found
847 if (!(lookup
= FindFaceName(aFaceName
))) {
848 // names not completely initialized, so keep track of lookup misses
849 if (!mFaceNameListsInitialized
) {
850 if (!mFaceNamesMissed
) {
851 mFaceNamesMissed
= MakeUnique
<nsTHashSet
<nsCString
>>(2);
853 mFaceNamesMissed
->Insert(aFaceName
);
860 gfxFontEntry
* gfxPlatformFontList::LookupInSharedFaceNameList(
861 nsPresContext
* aPresContext
, const nsACString
& aFaceName
,
862 WeightRange aWeightForEntry
, StretchRange aStretchForEntry
,
863 SlantStyleRange aStyleForEntry
) {
864 nsAutoCString
keyName(aFaceName
);
865 ToLowerCase(keyName
);
866 fontlist::FontList
* list
= SharedFontList();
867 fontlist::Family
* family
= nullptr;
868 fontlist::Face
* face
= nullptr;
869 if (list
->NumLocalFaces()) {
870 fontlist::LocalFaceRec
* rec
= list
->FindLocalFace(keyName
);
872 auto* families
= list
->Families();
874 family
= &families
[rec
->mFamilyIndex
];
875 face
= family
->Faces(list
)[rec
->mFaceIndex
].ToPtr
<fontlist::Face
>(list
);
879 list
->SearchForLocalFace(keyName
, &family
, &face
);
881 if (!face
|| !family
) {
884 FontVisibility level
=
885 aPresContext
? aPresContext
->GetFontVisibility() : FontVisibility::User
;
886 if (!IsVisibleToCSS(*family
, level
)) {
888 aPresContext
->ReportBlockedFontFamily(*family
);
892 gfxFontEntry
* fe
= CreateFontEntry(face
, family
);
894 fe
->mIsLocalUserFont
= true;
895 fe
->mWeightRange
= aWeightForEntry
;
896 fe
->mStretchRange
= aStretchForEntry
;
897 fe
->mStyleRange
= aStyleForEntry
;
902 void gfxPlatformFontList::LoadBadUnderlineList() {
903 gfxFontUtils::GetPrefsFontList("font.blacklist.underline_offset",
904 mBadUnderlineFamilyNames
);
905 for (auto& fam
: mBadUnderlineFamilyNames
) {
908 mBadUnderlineFamilyNames
.Compact();
909 mBadUnderlineFamilyNames
.Sort();
912 void gfxPlatformFontList::UpdateFontList(bool aFullRebuild
) {
913 MOZ_ASSERT(NS_IsMainThread());
916 AutoLock
lock(mLock
);
919 // The font list isn't being fully rebuilt, we're just being notified that
920 // character maps have been updated and so font fallback needs to be re-
921 // done. We only care about this if we have previously encountered a
922 // fallback that required cmaps that were not yet available, and so we
923 // asked for the async cmap loader to run.
924 AutoLock
lock(mLock
);
925 if (mStartedLoadingCmapsFrom
!= 0xffffffffu
) {
926 InitializeCodepointsWithNoFonts();
927 mStartedLoadingCmapsFrom
= 0xffffffffu
;
928 ForceGlobalReflowLocked(gfxPlatform::NeedsReframe::No
);
933 bool gfxPlatformFontList::IsVisibleToCSS(const gfxFontFamily
& aFamily
,
934 FontVisibility aVisibility
) const {
935 return aFamily
.Visibility() <= aVisibility
|| IsFontFamilyWhitelistActive();
938 bool gfxPlatformFontList::IsVisibleToCSS(const fontlist::Family
& aFamily
,
939 FontVisibility aVisibility
) const {
940 return aFamily
.Visibility() <= aVisibility
|| IsFontFamilyWhitelistActive();
943 void gfxPlatformFontList::GetFontList(nsAtom
* aLangGroup
,
944 const nsACString
& aGenericFamily
,
945 nsTArray
<nsString
>& aListOfFonts
) {
946 AutoLock
lock(mLock
);
948 if (SharedFontList()) {
949 fontlist::FontList
* list
= SharedFontList();
950 const fontlist::Family
* families
= list
->Families();
952 for (uint32_t i
= 0; i
< list
->NumFamilies(); i
++) {
953 auto& f
= families
[i
];
954 if (!IsVisibleToCSS(f
, FontVisibility::User
) || f
.IsAltLocaleFamily()) {
957 // XXX TODO: filter families for aGenericFamily, if supported by
959 aListOfFonts
.AppendElement(
960 NS_ConvertUTF8toUTF16(list
->LocalizedFamilyName(&f
)));
966 for (const RefPtr
<gfxFontFamily
>& family
: mFontFamilies
.Values()) {
967 if (!IsVisibleToCSS(*family
, FontVisibility::User
)) {
970 if (family
->FilterForFontList(aLangGroup
, aGenericFamily
)) {
971 nsAutoCString localizedFamilyName
;
972 family
->LocalizedName(localizedFamilyName
);
973 aListOfFonts
.AppendElement(NS_ConvertUTF8toUTF16(localizedFamilyName
));
978 aListOfFonts
.Compact();
981 void gfxPlatformFontList::GetFontFamilyList(
982 nsTArray
<RefPtr
<gfxFontFamily
>>& aFamilyArray
) {
983 AutoLock
lock(mLock
);
984 MOZ_ASSERT(aFamilyArray
.IsEmpty());
985 // This doesn't use ToArray, because the caller passes an AutoTArray.
986 aFamilyArray
.SetCapacity(mFontFamilies
.Count());
987 for (const auto& family
: mFontFamilies
.Values()) {
988 aFamilyArray
.AppendElement(family
);
992 already_AddRefed
<gfxFont
> gfxPlatformFontList::SystemFindFontForChar(
993 nsPresContext
* aPresContext
, uint32_t aCh
, uint32_t aNextCh
,
994 Script aRunScript
, eFontPresentation aPresentation
,
995 const gfxFontStyle
* aStyle
, FontVisibility
* aVisibility
) {
996 AutoLock
lock(mLock
);
997 FontVisibility level
=
998 aPresContext
? aPresContext
->GetFontVisibility() : FontVisibility::User
;
999 MOZ_ASSERT(!mCodepointsWithNoFonts
[level
].test(aCh
),
1000 "don't call for codepoints already known to be unsupported");
1002 // Try to short-circuit font fallback for U+FFFD, used to represent
1003 // encoding errors: just use cached family from last time U+FFFD was seen.
1004 // This helps speed up pages with lots of encoding errors, binary-as-text,
1006 if (aCh
== 0xFFFD) {
1007 gfxFontEntry
* fontEntry
= nullptr;
1008 auto& fallbackFamily
= mReplacementCharFallbackFamily
[level
];
1009 if (fallbackFamily
.mShared
) {
1010 fontlist::Face
* face
=
1011 fallbackFamily
.mShared
->FindFaceForStyle(SharedFontList(), *aStyle
);
1013 fontEntry
= GetOrCreateFontEntryLocked(face
, fallbackFamily
.mShared
);
1014 *aVisibility
= fallbackFamily
.mShared
->Visibility();
1016 } else if (fallbackFamily
.mUnshared
) {
1017 fontEntry
= fallbackFamily
.mUnshared
->FindFontForStyle(*aStyle
);
1018 *aVisibility
= fallbackFamily
.mUnshared
->Visibility();
1021 // this should never fail, as we must have found U+FFFD in order to set
1022 // mReplacementCharFallbackFamily[...] at all, but better play it safe
1023 if (fontEntry
&& fontEntry
->HasCharacter(aCh
)) {
1024 return fontEntry
->FindOrMakeFont(aStyle
);
1028 TimeStamp start
= TimeStamp::Now();
1030 // search commonly available fonts
1032 FontFamily fallbackFamily
;
1033 RefPtr
<gfxFont
> candidate
=
1034 CommonFontFallback(aPresContext
, aCh
, aNextCh
, aRunScript
, aPresentation
,
1035 aStyle
, fallbackFamily
);
1036 RefPtr
<gfxFont
> font
;
1038 if (aPresentation
== eFontPresentation::Any
) {
1039 font
= std::move(candidate
);
1041 bool hasColorGlyph
= candidate
->HasColorGlyphFor(aCh
, aNextCh
);
1042 if (hasColorGlyph
== PrefersColor(aPresentation
)) {
1043 font
= std::move(candidate
);
1048 // If we didn't find a common font, or it was not the preferred type (color
1049 // or monochrome), do system-wide fallback (except for specials).
1050 uint32_t cmapCount
= 0;
1053 font
= GlobalFontFallback(aPresContext
, aCh
, aNextCh
, aRunScript
,
1054 aPresentation
, aStyle
, cmapCount
, fallbackFamily
);
1055 // If the font we found doesn't match the requested type, and we also found
1056 // a candidate above, prefer that one.
1057 if (font
&& aPresentation
!= eFontPresentation::Any
&& candidate
) {
1058 bool hasColorGlyph
= font
->HasColorGlyphFor(aCh
, aNextCh
);
1059 if (hasColorGlyph
!= PrefersColor(aPresentation
)) {
1060 font
= std::move(candidate
);
1064 TimeDuration elapsed
= TimeStamp::Now() - start
;
1066 LogModule
* log
= gfxPlatform::GetLog(eGfxLog_textrun
);
1068 if (MOZ_UNLIKELY(MOZ_LOG_TEST(log
, LogLevel::Warning
))) {
1069 Script script
= intl::UnicodeProperties::GetScriptCode(aCh
);
1070 MOZ_LOG(log
, LogLevel::Warning
,
1071 ("(textrun-systemfallback-%s) char: u+%6.6x "
1072 "script: %d match: [%s]"
1073 " time: %dus cmaps: %d\n",
1074 (common
? "common" : "global"), aCh
, static_cast<int>(script
),
1075 (font
? font
->GetFontEntry()->Name().get() : "<none>"),
1076 int32_t(elapsed
.ToMicroseconds()), cmapCount
));
1079 // no match? add to set of non-matching codepoints
1081 mCodepointsWithNoFonts
[level
].set(aCh
);
1083 *aVisibility
= fallbackFamily
.mShared
1084 ? fallbackFamily
.mShared
->Visibility()
1085 : fallbackFamily
.mUnshared
->Visibility();
1086 if (aCh
== 0xFFFD) {
1087 mReplacementCharFallbackFamily
[level
] = fallbackFamily
;
1091 // track system fallback time
1092 static bool first
= true;
1093 int32_t intElapsed
=
1094 int32_t(first
? elapsed
.ToMilliseconds() : elapsed
.ToMicroseconds());
1095 Telemetry::Accumulate((first
? Telemetry::SYSTEM_FONT_FALLBACK_FIRST
1096 : Telemetry::SYSTEM_FONT_FALLBACK
),
1100 // track the script for which fallback occurred (incremented one make it
1102 Telemetry::Accumulate(Telemetry::SYSTEM_FONT_FALLBACK_SCRIPT
,
1103 int(aRunScript
) + 1);
1105 return font
.forget();
1108 #define NUM_FALLBACK_FONTS 8
1110 already_AddRefed
<gfxFont
> gfxPlatformFontList::CommonFontFallback(
1111 nsPresContext
* aPresContext
, uint32_t aCh
, uint32_t aNextCh
,
1112 Script aRunScript
, eFontPresentation aPresentation
,
1113 const gfxFontStyle
* aMatchStyle
, FontFamily
& aMatchedFamily
) {
1114 AutoTArray
<const char*, NUM_FALLBACK_FONTS
> defaultFallbacks
;
1115 gfxPlatform::GetPlatform()->GetCommonFallbackFonts(
1116 aCh
, aRunScript
, aPresentation
, defaultFallbacks
);
1117 GlobalFontMatch
data(aCh
, aNextCh
, *aMatchStyle
, aPresentation
);
1118 FontVisibility level
=
1119 aPresContext
? aPresContext
->GetFontVisibility() : FontVisibility::User
;
1121 // If a color-emoji presentation is requested, we will check any font found
1122 // to see if it can provide this; if not, we'll remember it as a possible
1123 // candidate but search the remainder of the list for a better choice.
1124 RefPtr
<gfxFont
> candidateFont
;
1125 FontFamily candidateFamily
;
1126 auto check
= [&](gfxFontEntry
* aFontEntry
,
1127 FontFamily aFamily
) -> already_AddRefed
<gfxFont
> {
1128 RefPtr
<gfxFont
> font
= aFontEntry
->FindOrMakeFont(aMatchStyle
);
1129 if (aPresentation
< eFontPresentation::EmojiDefault
||
1130 font
->HasColorGlyphFor(aCh
, aNextCh
)) {
1131 aMatchedFamily
= aFamily
;
1132 return font
.forget();
1134 // We want a color glyph but this font only has monochrome; remember it
1135 // (unless we already have a candidate) but continue to search.
1136 if (!candidateFont
) {
1137 candidateFont
= std::move(font
);
1138 candidateFamily
= aFamily
;
1143 if (SharedFontList()) {
1144 for (const auto name
: defaultFallbacks
) {
1145 fontlist::Family
* family
=
1146 FindSharedFamily(aPresContext
, nsDependentCString(name
));
1147 if (!family
|| !IsVisibleToCSS(*family
, level
)) {
1150 // XXX(jfkthame) Should we fire the async cmap-loader here, or let it
1151 // always do a potential sync initialization of the family?
1152 family
->SearchAllFontsForChar(SharedFontList(), &data
);
1153 if (data
.mBestMatch
) {
1154 RefPtr
<gfxFont
> font
= check(data
.mBestMatch
, FontFamily(family
));
1156 return font
.forget();
1161 for (const auto name
: defaultFallbacks
) {
1162 gfxFontFamily
* fallback
=
1163 FindFamilyByCanonicalName(nsDependentCString(name
));
1164 if (!fallback
|| !IsVisibleToCSS(*fallback
, level
)) {
1167 fallback
->FindFontForChar(&data
);
1168 if (data
.mBestMatch
) {
1169 RefPtr
<gfxFont
> font
= check(data
.mBestMatch
, FontFamily(fallback
));
1171 return font
.forget();
1177 // If we had a candidate that supports the character, but doesn't have the
1178 // desired emoji-style glyph, we'll return it anyhow as nothing better was
1180 if (candidateFont
) {
1181 aMatchedFamily
= candidateFamily
;
1182 return candidateFont
.forget();
1188 already_AddRefed
<gfxFont
> gfxPlatformFontList::GlobalFontFallback(
1189 nsPresContext
* aPresContext
, uint32_t aCh
, uint32_t aNextCh
,
1190 Script aRunScript
, eFontPresentation aPresentation
,
1191 const gfxFontStyle
* aMatchStyle
, uint32_t& aCmapCount
,
1192 FontFamily
& aMatchedFamily
) {
1193 bool useCmaps
= IsFontFamilyWhitelistActive() ||
1194 gfxPlatform::GetPlatform()->UseCmapsDuringSystemFallback();
1195 FontVisibility level
=
1196 aPresContext
? aPresContext
->GetFontVisibility() : FontVisibility::User
;
1198 // Allow platform-specific fallback code to try and find a usable font
1199 gfxFontEntry
* fe
= PlatformGlobalFontFallback(aPresContext
, aCh
, aRunScript
,
1200 aMatchStyle
, aMatchedFamily
);
1202 if (aMatchedFamily
.mShared
) {
1203 if (IsVisibleToCSS(*aMatchedFamily
.mShared
, level
)) {
1204 RefPtr
<gfxFont
> font
= fe
->FindOrMakeFont(aMatchStyle
);
1206 if (aPresentation
== eFontPresentation::Any
) {
1207 return font
.forget();
1209 bool hasColorGlyph
= font
->HasColorGlyphFor(aCh
, aNextCh
);
1210 if (hasColorGlyph
== PrefersColor(aPresentation
)) {
1211 return font
.forget();
1216 if (IsVisibleToCSS(*aMatchedFamily
.mUnshared
, level
)) {
1217 RefPtr
<gfxFont
> font
= fe
->FindOrMakeFont(aMatchStyle
);
1219 if (aPresentation
== eFontPresentation::Any
) {
1220 return font
.forget();
1222 bool hasColorGlyph
= font
->HasColorGlyphFor(aCh
, aNextCh
);
1223 if (hasColorGlyph
== PrefersColor(aPresentation
)) {
1224 return font
.forget();
1232 // otherwise, try to find it among local fonts
1233 GlobalFontMatch
data(aCh
, aNextCh
, *aMatchStyle
, aPresentation
);
1234 if (SharedFontList()) {
1235 fontlist::Family
* families
= SharedFontList()->Families();
1237 for (uint32_t i
= 0; i
< SharedFontList()->NumFamilies(); i
++) {
1238 fontlist::Family
& family
= families
[i
];
1239 if (!IsVisibleToCSS(family
, level
)) {
1242 if (!family
.IsFullyInitialized() &&
1243 StaticPrefs::gfx_font_rendering_fallback_async() &&
1244 !XRE_IsParentProcess()) {
1245 // Start loading all the missing charmaps; but this is async,
1246 // so for now we just continue, ignoring this family.
1247 StartCmapLoadingFromFamily(i
);
1249 family
.SearchAllFontsForChar(SharedFontList(), &data
);
1250 if (data
.mMatchDistance
== 0.0) {
1251 // no better style match is possible, so stop searching
1256 if (data
.mBestMatch
) {
1257 aMatchedFamily
= FontFamily(data
.mMatchedSharedFamily
);
1258 return data
.mBestMatch
->FindOrMakeFont(aMatchStyle
);
1262 // iterate over all font families to find a font that support the
1264 for (const RefPtr
<gfxFontFamily
>& family
: mFontFamilies
.Values()) {
1265 if (!IsVisibleToCSS(*family
, level
)) {
1268 // evaluate all fonts in this family for a match
1269 family
->FindFontForChar(&data
);
1270 if (data
.mMatchDistance
== 0.0) {
1271 // no better style match is possible, so stop searching
1276 aCmapCount
= data
.mCmapsTested
;
1277 if (data
.mBestMatch
) {
1278 aMatchedFamily
= FontFamily(data
.mMatchedFamily
);
1279 return data
.mBestMatch
->FindOrMakeFont(aMatchStyle
);
1286 class StartCmapLoadingRunnable
: public mozilla::Runnable
{
1288 explicit StartCmapLoadingRunnable(uint32_t aStartIndex
)
1289 : Runnable("gfxPlatformFontList::StartCmapLoadingRunnable"),
1290 mStartIndex(aStartIndex
) {}
1292 NS_IMETHOD
Run() override
{
1293 auto* pfl
= gfxPlatformFontList::PlatformFontList();
1294 auto* list
= pfl
->SharedFontList();
1298 if (mStartIndex
>= list
->NumFamilies()) {
1301 if (XRE_IsParentProcess()) {
1302 pfl
->StartCmapLoading(list
->GetGeneration(), mStartIndex
);
1304 dom::ContentChild::GetSingleton()->SendStartCmapLoading(
1305 list
->GetGeneration(), mStartIndex
);
1311 uint32_t mStartIndex
;
1314 void gfxPlatformFontList::StartCmapLoadingFromFamily(uint32_t aStartIndex
) {
1315 AutoLock
lock(mLock
);
1316 if (aStartIndex
>= mStartedLoadingCmapsFrom
) {
1317 // We already initiated cmap-loading from here or earlier in the list;
1318 // no need to do it again here.
1321 mStartedLoadingCmapsFrom
= aStartIndex
;
1323 // If we're already on the main thread, don't bother dispatching a runnable
1324 // here to kick off the loading process, just do it directly.
1325 if (NS_IsMainThread()) {
1326 auto* list
= SharedFontList();
1327 if (XRE_IsParentProcess()) {
1328 StartCmapLoading(list
->GetGeneration(), aStartIndex
);
1330 dom::ContentChild::GetSingleton()->SendStartCmapLoading(
1331 list
->GetGeneration(), aStartIndex
);
1334 NS_DispatchToMainThread(new StartCmapLoadingRunnable(aStartIndex
));
1338 class LoadCmapsRunnable
: public CancelableRunnable
{
1339 class WillShutdownObserver
: public nsIObserver
{
1344 explicit WillShutdownObserver(LoadCmapsRunnable
* aRunnable
)
1345 : mRunnable(aRunnable
) {}
1348 nsCOMPtr
<nsIObserverService
> obs
= services::GetObserverService();
1350 obs
->RemoveObserver(this, NS_XPCOM_WILL_SHUTDOWN_OBSERVER_ID
);
1352 mRunnable
= nullptr;
1356 virtual ~WillShutdownObserver() = default;
1358 LoadCmapsRunnable
* mRunnable
;
1362 explicit LoadCmapsRunnable(uint32_t aGeneration
, uint32_t aFamilyIndex
)
1363 : CancelableRunnable("gfxPlatformFontList::LoadCmapsRunnable"),
1364 mGeneration(aGeneration
),
1365 mStartIndex(aFamilyIndex
),
1366 mIndex(aFamilyIndex
) {
1367 nsCOMPtr
<nsIObserverService
> obs
= services::GetObserverService();
1369 mObserver
= new WillShutdownObserver(this);
1370 obs
->AddObserver(mObserver
, NS_XPCOM_WILL_SHUTDOWN_OBSERVER_ID
, false);
1374 virtual ~LoadCmapsRunnable() {
1376 mObserver
->Remove();
1380 // Reset the current family index, if the value passed is earlier than our
1381 // original starting position. We don't "reset" if it would move the current
1382 // position forward, or back into the already-scanned range.
1383 // We could optimize further by remembering the current position reached,
1384 // and then skipping ahead from the original start, but it doesn't seem worth
1385 // extra complexity for a task that usually only happens once, and already-
1386 // processed families will be skipped pretty quickly in Run() anyhow.
1387 void MaybeResetIndex(uint32_t aFamilyIndex
) {
1388 if (aFamilyIndex
< mStartIndex
) {
1389 mStartIndex
= aFamilyIndex
;
1390 mIndex
= aFamilyIndex
;
1394 nsresult
Cancel() override
{
1399 NS_IMETHOD
Run() override
{
1403 auto* pfl
= gfxPlatformFontList::PlatformFontList();
1404 auto* list
= pfl
->SharedFontList();
1409 if (mGeneration
!= list
->GetGeneration()) {
1412 uint32_t numFamilies
= list
->NumFamilies();
1413 if (mIndex
>= numFamilies
) {
1416 auto* families
= list
->Families();
1417 // Skip any families that are already initialized.
1418 while (mIndex
< numFamilies
&& families
[mIndex
].IsFullyInitialized()) {
1421 // Fully process one family, and advance index.
1422 if (mIndex
< numFamilies
) {
1423 Unused
<< pfl
->InitializeFamily(&families
[mIndex
], true);
1426 // If there are more families to initialize, post ourselves back to the
1427 // idle queue to handle the next one; otherwise we're finished and we need
1428 // to notify content processes to update their rendering.
1429 if (mIndex
< numFamilies
) {
1430 RefPtr
<CancelableRunnable
> task
= this;
1431 NS_DispatchToMainThreadQueue(task
.forget(), EventQueuePriority::Idle
);
1434 pfl
->CancelLoadCmapsTask();
1435 pfl
->InitializeCodepointsWithNoFonts();
1436 dom::ContentParent::NotifyUpdatedFonts(false);
1443 uint32_t mGeneration
;
1444 uint32_t mStartIndex
;
1446 bool mIsCanceled
= false;
1448 RefPtr
<WillShutdownObserver
> mObserver
;
1451 NS_IMPL_ISUPPORTS(LoadCmapsRunnable::WillShutdownObserver
, nsIObserver
)
1454 LoadCmapsRunnable::WillShutdownObserver::Observe(nsISupports
* aSubject
,
1456 const char16_t
* aData
) {
1457 if (!nsCRT::strcmp(aTopic
, NS_XPCOM_WILL_SHUTDOWN_OBSERVER_ID
)) {
1459 mRunnable
->Cancel();
1462 MOZ_ASSERT_UNREACHABLE("unexpected notification topic");
1467 void gfxPlatformFontList::StartCmapLoading(uint32_t aGeneration
,
1468 uint32_t aStartIndex
) {
1469 MOZ_RELEASE_ASSERT(XRE_IsParentProcess());
1470 if (aGeneration
!= SharedFontList()->GetGeneration()) {
1473 if (AppShutdown::IsInOrBeyond(ShutdownPhase::AppShutdownConfirmed
)) {
1476 if (mLoadCmapsRunnable
) {
1477 // We already have a runnable; just make sure it covers the full range of
1479 static_cast<LoadCmapsRunnable
*>(mLoadCmapsRunnable
.get())
1480 ->MaybeResetIndex(aStartIndex
);
1483 mLoadCmapsRunnable
= new LoadCmapsRunnable(aGeneration
, aStartIndex
);
1484 RefPtr
<CancelableRunnable
> task
= mLoadCmapsRunnable
;
1485 NS_DispatchToMainThreadQueue(task
.forget(), EventQueuePriority::Idle
);
1488 gfxFontFamily
* gfxPlatformFontList::CheckFamily(gfxFontFamily
* aFamily
) {
1489 if (aFamily
&& !aFamily
->HasStyles()) {
1490 aFamily
->FindStyleVariations();
1493 if (aFamily
&& aFamily
->FontListLength() == 0) {
1494 // Failed to load any faces for this family, so discard it.
1496 GenerateFontListKey(aFamily
->Name(), key
);
1497 mFontFamilies
.Remove(key
);
1504 bool gfxPlatformFontList::FindAndAddFamilies(
1505 nsPresContext
* aPresContext
, StyleGenericFontFamily aGeneric
,
1506 const nsACString
& aFamily
, nsTArray
<FamilyAndGeneric
>* aOutput
,
1507 FindFamiliesFlags aFlags
, gfxFontStyle
* aStyle
, nsAtom
* aLanguage
,
1508 gfxFloat aDevToCssSize
) {
1509 AutoLock
lock(mLock
);
1512 auto initialLength
= aOutput
->Length();
1516 FindAndAddFamiliesLocked(aPresContext
, aGeneric
, aFamily
, aOutput
, aFlags
,
1517 aStyle
, aLanguage
, aDevToCssSize
);
1519 auto finalLength
= aOutput
->Length();
1520 // Validate the expectation that the output-array grows if we return true,
1521 // or remains the same (probably empty) if we return false.
1522 MOZ_ASSERT_IF(didFind
, finalLength
> initialLength
);
1523 MOZ_ASSERT_IF(!didFind
, finalLength
== initialLength
);
1529 bool gfxPlatformFontList::FindAndAddFamiliesLocked(
1530 nsPresContext
* aPresContext
, StyleGenericFontFamily aGeneric
,
1531 const nsACString
& aFamily
, nsTArray
<FamilyAndGeneric
>* aOutput
,
1532 FindFamiliesFlags aFlags
, gfxFontStyle
* aStyle
, nsAtom
* aLanguage
,
1533 gfxFloat aDevToCssSize
) {
1535 GenerateFontListKey(aFamily
, key
);
1537 bool allowHidden
= bool(aFlags
& FindFamiliesFlags::eSearchHiddenFamilies
);
1538 FontVisibility visibilityLevel
=
1539 aPresContext
? aPresContext
->GetFontVisibility() : FontVisibility::User
;
1541 // If this font lookup is the result of resolving a CSS generic (not a direct
1542 // font-family request by the page), and RFP settings allow generics to be
1543 // unrestricted, bump the effective visibility level applied here so as to
1544 // allow user-installed fonts to be used.
1545 if (visibilityLevel
< FontVisibility::User
&&
1546 aGeneric
!= StyleGenericFontFamily::None
&&
1547 !aPresContext
->Document()->ShouldResistFingerprinting(
1548 RFPTarget::FontVisibilityRestrictGenerics
)) {
1549 visibilityLevel
= FontVisibility::User
;
1552 if (SharedFontList()) {
1553 fontlist::Family
* family
= SharedFontList()->FindFamily(key
);
1554 // If not found, and other family names have not yet been initialized,
1555 // initialize the rest of the list and try again. This is done lazily
1556 // since reading name table entries is expensive.
1557 // Although ASCII localized family names are possible they don't occur
1558 // in practice, so avoid pulling in names at startup.
1559 if (!family
&& !mOtherFamilyNamesInitialized
) {
1560 bool triggerLoading
= true;
1562 !(aFlags
& FindFamiliesFlags::eForceOtherFamilyNamesLoading
);
1564 // If `key` is an ASCII name, only trigger loading if it includes a
1565 // space, and the "base" name (up to the last space) exists as a known
1566 // family, so that this might be a legacy styled-family name.
1567 const char* data
= key
.BeginReading();
1568 int32_t index
= key
.Length();
1569 while (--index
> 0) {
1570 if (data
[index
] == ' ') {
1575 !SharedFontList()->FindFamily(nsAutoCString(key
.get(), index
))) {
1576 triggerLoading
= false;
1579 if (triggerLoading
) {
1580 if (InitOtherFamilyNames(mayDefer
)) {
1581 family
= SharedFontList()->FindFamily(key
);
1584 if (!family
&& !mOtherFamilyNamesInitialized
&&
1585 !(aFlags
& FindFamiliesFlags::eNoAddToNamesMissedWhenSearching
)) {
1586 AddToMissedNames(key
);
1589 // Check whether the family we found is actually allowed to be looked up,
1590 // according to current font-visibility prefs.
1592 bool visible
= IsVisibleToCSS(*family
, visibilityLevel
);
1593 if (visible
|| (allowHidden
&& family
->IsHidden())) {
1594 aOutput
->AppendElement(FamilyAndGeneric(family
, aGeneric
));
1598 aPresContext
->ReportBlockedFontFamily(*family
);
1604 NS_ASSERTION(mFontFamilies
.Count() != 0,
1605 "system font list was not initialized correctly");
1607 auto isBlockedByVisibilityLevel
= [=](gfxFontFamily
* aFamily
) -> bool {
1608 bool visible
= IsVisibleToCSS(*aFamily
, visibilityLevel
);
1609 if (visible
|| (allowHidden
&& aFamily
->IsHidden())) {
1613 aPresContext
->ReportBlockedFontFamily(*aFamily
);
1618 // lookup in canonical (i.e. English) family name list
1619 gfxFontFamily
* familyEntry
= mFontFamilies
.GetWeak(key
);
1621 if (isBlockedByVisibilityLevel(familyEntry
)) {
1626 // if not found, lookup in other family names list (mostly localized names)
1628 familyEntry
= mOtherFamilyNames
.GetWeak(key
);
1631 if (isBlockedByVisibilityLevel(familyEntry
)) {
1636 // if still not found and other family names not yet fully initialized,
1637 // initialize the rest of the list and try again. this is done lazily
1638 // since reading name table entries is expensive.
1639 // although ASCII localized family names are possible they don't occur
1640 // in practice so avoid pulling in names at startup
1641 if (!familyEntry
&& !mOtherFamilyNamesInitialized
&& !IsAscii(aFamily
)) {
1642 InitOtherFamilyNames(
1643 !(aFlags
& FindFamiliesFlags::eForceOtherFamilyNamesLoading
));
1644 familyEntry
= mOtherFamilyNames
.GetWeak(key
);
1645 if (!familyEntry
&& !mOtherFamilyNamesInitialized
&&
1646 !(aFlags
& FindFamiliesFlags::eNoAddToNamesMissedWhenSearching
)) {
1647 // localized family names load timed out, add name to list of
1648 // names to check after localized names are loaded
1649 AddToMissedNames(key
);
1652 if (isBlockedByVisibilityLevel(familyEntry
)) {
1658 familyEntry
= CheckFamily(familyEntry
);
1660 // If we failed to find the requested family, check for a space in the
1661 // name; if found, and if the "base" name (up to the last space) exists
1662 // as a family, then this might be a legacy GDI-style family name for
1663 // an additional weight/width. Try searching the faces of the base family
1664 // and create any corresponding legacy families.
1666 !(aFlags
& FindFamiliesFlags::eNoSearchForLegacyFamilyNames
)) {
1667 // We don't have nsAString::RFindChar, so look for a space manually
1668 const char* data
= aFamily
.BeginReading();
1669 int32_t index
= aFamily
.Length();
1670 while (--index
> 0) {
1671 if (data
[index
] == ' ') {
1676 gfxFontFamily
* base
=
1677 FindUnsharedFamily(aPresContext
, Substring(aFamily
, 0, index
),
1678 FindFamiliesFlags::eNoSearchForLegacyFamilyNames
);
1679 // If we found the "base" family name, and if it has members with
1680 // legacy names, this will add corresponding font-family entries to
1681 // the mOtherFamilyNames list; then retry the legacy-family search.
1682 if (base
&& base
->CheckForLegacyFamilyNames(this)) {
1683 familyEntry
= mOtherFamilyNames
.GetWeak(key
);
1686 if (isBlockedByVisibilityLevel(familyEntry
)) {
1694 aOutput
->AppendElement(FamilyAndGeneric(familyEntry
, aGeneric
));
1701 void gfxPlatformFontList::AddToMissedNames(const nsCString
& aKey
) {
1702 if (!mOtherNamesMissed
) {
1703 mOtherNamesMissed
= MakeUnique
<nsTHashSet
<nsCString
>>(2);
1705 mOtherNamesMissed
->Insert(aKey
);
1708 fontlist::Family
* gfxPlatformFontList::FindSharedFamily(
1709 nsPresContext
* aPresContext
, const nsACString
& aFamily
,
1710 FindFamiliesFlags aFlags
, gfxFontStyle
* aStyle
, nsAtom
* aLanguage
,
1711 gfxFloat aDevToCss
) {
1712 if (!SharedFontList()) {
1715 AutoTArray
<FamilyAndGeneric
, 1> families
;
1716 if (!FindAndAddFamiliesLocked(aPresContext
, StyleGenericFontFamily::None
,
1717 aFamily
, &families
, aFlags
, aStyle
, aLanguage
,
1719 !families
[0].mFamily
.mShared
) {
1722 fontlist::Family
* family
= families
[0].mFamily
.mShared
;
1723 if (!family
->IsInitialized()) {
1724 if (!InitializeFamily(family
)) {
1731 class InitializeFamilyRunnable
: public mozilla::Runnable
{
1733 explicit InitializeFamilyRunnable(uint32_t aFamilyIndex
, bool aLoadCmaps
)
1734 : Runnable("gfxPlatformFontList::InitializeFamilyRunnable"),
1735 mIndex(aFamilyIndex
),
1736 mLoadCmaps(aLoadCmaps
) {}
1738 NS_IMETHOD
Run() override
{
1739 auto list
= gfxPlatformFontList::PlatformFontList()->SharedFontList();
1743 if (mIndex
>= list
->NumFamilies()) {
1744 // Out of range? Maybe the list got reinitialized since this request
1745 // was posted - just ignore it.
1748 dom::ContentChild::GetSingleton()->SendInitializeFamily(
1749 list
->GetGeneration(), mIndex
, mLoadCmaps
);
1758 bool gfxPlatformFontList::InitializeFamily(fontlist::Family
* aFamily
,
1760 MOZ_ASSERT(SharedFontList());
1761 auto list
= SharedFontList();
1762 if (!XRE_IsParentProcess()) {
1763 auto* families
= list
->Families();
1767 uint32_t index
= aFamily
- families
;
1768 if (index
>= list
->NumFamilies()) {
1771 if (NS_IsMainThread()) {
1772 dom::ContentChild::GetSingleton()->SendInitializeFamily(
1773 list
->GetGeneration(), index
, aLoadCmaps
);
1775 NS_DispatchToMainThread(new InitializeFamilyRunnable(index
, aLoadCmaps
));
1777 return aFamily
->IsInitialized();
1780 if (!aFamily
->IsInitialized()) {
1781 // The usual case: we're being asked to populate the face list.
1782 AutoTArray
<fontlist::Face::InitData
, 16> faceList
;
1783 GetFacesInitDataForFamily(aFamily
, faceList
, aLoadCmaps
);
1784 aFamily
->AddFaces(list
, faceList
);
1786 // The family's face list was already initialized, but if aLoadCmaps is
1787 // true we also want to eagerly load character maps. This is used when a
1788 // child process is doing SearchAllFontsForChar, to have the parent load
1789 // all the cmaps at once and reduce IPC traffic (and content-process file
1790 // access overhead, which is crippling for DirectWrite on Windows).
1792 auto* faces
= aFamily
->Faces(list
);
1794 for (size_t i
= 0; i
< aFamily
->NumFaces(); i
++) {
1795 auto* face
= faces
[i
].ToPtr
<fontlist::Face
>(list
);
1796 if (face
&& face
->mCharacterMap
.IsNull()) {
1797 // We don't want to cache this font entry, as the parent will most
1798 // likely never use it again; it's just to populate the charmap for
1799 // the benefit of the child process.
1800 RefPtr
<gfxFontEntry
> fe
= CreateFontEntry(face
, aFamily
);
1810 if (aLoadCmaps
&& aFamily
->IsInitialized()) {
1811 aFamily
->SetupFamilyCharMap(list
);
1814 return aFamily
->IsInitialized();
1817 gfxFontEntry
* gfxPlatformFontList::FindFontForFamily(
1818 nsPresContext
* aPresContext
, const nsACString
& aFamily
,
1819 const gfxFontStyle
* aStyle
) {
1820 AutoLock
lock(mLock
);
1823 GenerateFontListKey(aFamily
, key
);
1825 FontFamily family
= FindFamily(aPresContext
, key
);
1826 if (family
.IsNull()) {
1829 if (family
.mShared
) {
1830 auto face
= family
.mShared
->FindFaceForStyle(SharedFontList(), *aStyle
);
1834 return GetOrCreateFontEntryLocked(face
, family
.mShared
);
1836 return family
.mUnshared
->FindFontForStyle(*aStyle
);
1839 gfxFontEntry
* gfxPlatformFontList::GetOrCreateFontEntryLocked(
1840 fontlist::Face
* aFace
, const fontlist::Family
* aFamily
) {
1842 .LookupOrInsertWith(aFace
,
1843 [=] { return CreateFontEntry(aFace
, aFamily
); })
1847 void gfxPlatformFontList::AddOtherFamilyNames(
1848 gfxFontFamily
* aFamilyEntry
, const nsTArray
<nsCString
>& aOtherFamilyNames
) {
1849 AutoLock
lock(mLock
);
1851 for (const auto& name
: aOtherFamilyNames
) {
1853 GenerateFontListKey(name
, key
);
1855 mOtherFamilyNames
.LookupOrInsertWith(key
, [&] {
1857 ("(fontlist-otherfamily) canonical family: %s, other family: %s\n",
1858 aFamilyEntry
->Name().get(), name
.get()));
1859 if (mBadUnderlineFamilyNames
.ContainsSorted(key
)) {
1860 aFamilyEntry
->SetBadUnderlineFamily();
1862 return RefPtr
{aFamilyEntry
};
1867 void gfxPlatformFontList::AddFullnameLocked(gfxFontEntry
* aFontEntry
,
1868 const nsCString
& aFullname
) {
1869 mExtraNames
->mFullnames
.LookupOrInsertWith(aFullname
, [&] {
1870 LOG_FONTLIST(("(fontlist-fullname) name: %s, fullname: %s\n",
1871 aFontEntry
->Name().get(), aFullname
.get()));
1872 return RefPtr
{aFontEntry
};
1876 void gfxPlatformFontList::AddPostscriptNameLocked(
1877 gfxFontEntry
* aFontEntry
, const nsCString
& aPostscriptName
) {
1878 mExtraNames
->mPostscriptNames
.LookupOrInsertWith(aPostscriptName
, [&] {
1879 LOG_FONTLIST(("(fontlist-postscript) name: %s, psname: %s\n",
1880 aFontEntry
->Name().get(), aPostscriptName
.get()));
1881 return RefPtr
{aFontEntry
};
1885 bool gfxPlatformFontList::GetStandardFamilyName(const nsCString
& aFontName
,
1886 nsACString
& aFamilyName
) {
1887 AutoLock
lock(mLock
);
1888 FontFamily family
= FindFamily(nullptr, aFontName
);
1889 if (family
.IsNull()) {
1892 return GetLocalizedFamilyName(family
, aFamilyName
);
1895 bool gfxPlatformFontList::GetLocalizedFamilyName(const FontFamily
& aFamily
,
1896 nsACString
& aFamilyName
) {
1897 if (aFamily
.mShared
) {
1898 aFamilyName
= SharedFontList()->LocalizedFamilyName(aFamily
.mShared
);
1901 if (aFamily
.mUnshared
) {
1902 aFamily
.mUnshared
->LocalizedName(aFamilyName
);
1905 return false; // leaving the aFamilyName outparam untouched
1908 FamilyAndGeneric
gfxPlatformFontList::GetDefaultFontFamily(
1909 const nsACString
& aLangGroup
, const nsACString
& aGenericFamily
) {
1910 if (NS_WARN_IF(aLangGroup
.IsEmpty()) ||
1911 NS_WARN_IF(aGenericFamily
.IsEmpty())) {
1912 return FamilyAndGeneric();
1915 AutoLock
lock(mLock
);
1917 nsAutoCString value
;
1918 AutoTArray
<nsCString
, 4> names
;
1919 if (mFontPrefs
->LookupNameList(PrefName(aGenericFamily
, aLangGroup
), value
)) {
1920 gfxFontUtils::ParseFontList(value
, names
);
1923 for (const nsCString
& name
: names
) {
1924 FontFamily family
= FindFamily(nullptr, name
);
1925 if (!family
.IsNull()) {
1926 return FamilyAndGeneric(family
);
1930 return FamilyAndGeneric();
1933 ShmemCharMapHashEntry::ShmemCharMapHashEntry(const gfxSparseBitSet
* aCharMap
)
1934 : mList(gfxPlatformFontList::PlatformFontList()->SharedFontList()),
1935 mHash(aCharMap
->GetChecksum()) {
1936 size_t len
= SharedBitSet::RequiredSize(*aCharMap
);
1937 mCharMap
= mList
->Alloc(len
);
1938 SharedBitSet::Create(mCharMap
.ToPtr(mList
, len
), len
, *aCharMap
);
1941 fontlist::Pointer
gfxPlatformFontList::GetShmemCharMapLocked(
1942 const gfxSparseBitSet
* aCmap
) {
1943 auto* entry
= mShmemCharMaps
.GetEntry(aCmap
);
1945 entry
= mShmemCharMaps
.PutEntry(aCmap
);
1947 return entry
->GetCharMap();
1950 // Lookup aCmap in the shared cmap set, adding if not already present.
1951 // This is the only way for a reference to a gfxCharacterMap to be acquired
1952 // by another thread than its original creator.
1953 already_AddRefed
<gfxCharacterMap
> gfxPlatformFontList::FindCharMap(
1954 gfxCharacterMap
* aCmap
) {
1955 // Lock to prevent potentially racing against MaybeRemoveCmap.
1956 AutoLock
lock(mLock
);
1958 // Find existing entry or insert a new one (which will add a reference).
1960 aCmap
->mShared
= true; // Set the shared flag in preparation for adding
1961 // to the global table.
1962 RefPtr cmap
= mSharedCmaps
.PutEntry(aCmap
)->GetKey();
1964 // If we ended up finding a different, pre-existing entry, clear the
1965 // shared flag on this one so that it'll get deleted on Release().
1966 if (cmap
.get() != aCmap
) {
1967 aCmap
->mShared
= false;
1970 return cmap
.forget();
1973 // Potentially remove the charmap from the shared cmap set. This is called
1974 // when a user of the charmap drops a reference and the refcount goes to 1;
1975 // in that case, it is possible our shared set is the only remaining user
1976 // of the object, and we should remove it.
1977 // Note that aCharMap might have already been freed, so we must not try to
1978 // dereference it until we have checked that it's still present in our table.
1979 void gfxPlatformFontList::MaybeRemoveCmap(gfxCharacterMap
* aCharMap
) {
1980 // Lock so that nobody else can get a reference via FindCharMap while we're
1982 AutoLock
lock(mLock
);
1984 // Skip lookups during teardown.
1985 if (!mSharedCmaps
.Count()) {
1989 // aCharMap needs to match the entry and be the same ptr and still have a
1990 // refcount of exactly 1 (i.e. we hold the only reference) before removing.
1991 // If we're racing another thread, it might already have been removed, in
1992 // which case GetEntry will not find it and we won't try to dereference the
1993 // already-freed pointer.
1994 CharMapHashKey
* found
=
1995 mSharedCmaps
.GetEntry(const_cast<gfxCharacterMap
*>(aCharMap
));
1996 if (found
&& found
->GetKey() == aCharMap
&& aCharMap
->RefCount() == 1) {
1997 // Forget our reference to the object that's being deleted, without
1998 // calling Release() on it.
1999 Unused
<< found
->mCharMap
.forget();
2004 // Log this as a "Release" to keep leak-checking correct.
2005 NS_LOG_RELEASE(aCharMap
, 0, "gfxCharacterMap");
2007 mSharedCmaps
.RemoveEntry(found
);
2011 static void GetSystemUIFontFamilies([[maybe_unused
]] nsAtom
* aLangGroup
,
2012 nsTArray
<nsCString
>& aFamilies
) {
2013 // TODO: On macOS, use CTCreateUIFontForLanguage or such thing (though the
2014 // code below ends up using [NSFont systemFontOfSize: 0.0].
2016 gfxFontStyle fontStyle
;
2017 nsAutoString systemFontName
;
2018 if (!LookAndFeel::GetFont(StyleSystemFont::Menu
, systemFontName
, fontStyle
)) {
2021 systemFontName
.Trim("\"'");
2022 CopyUTF16toUTF8(systemFontName
, *aFamilies
.AppendElement());
2025 void gfxPlatformFontList::ResolveGenericFontNames(
2026 nsPresContext
* aPresContext
, StyleGenericFontFamily aGenericType
,
2027 eFontPrefLang aPrefLang
, PrefFontList
* aGenericFamilies
) {
2028 const char* langGroupStr
= GetPrefLangName(aPrefLang
);
2029 const char* generic
= GetGenericName(aGenericType
);
2035 AutoTArray
<nsCString
, 4> genericFamilies
;
2037 // load family for "font.name.generic.lang"
2038 PrefName
prefName(generic
, langGroupStr
);
2039 nsAutoCString value
;
2040 if (mFontPrefs
->LookupName(prefName
, value
)) {
2041 gfxFontUtils::ParseFontList(value
, genericFamilies
);
2044 // load fonts for "font.name-list.generic.lang"
2045 if (mFontPrefs
->LookupNameList(prefName
, value
)) {
2046 gfxFontUtils::ParseFontList(value
, genericFamilies
);
2049 nsAtom
* langGroup
= GetLangGroupForPrefLang(aPrefLang
);
2050 MOZ_ASSERT(langGroup
, "null lang group for pref lang");
2052 if (aGenericType
== StyleGenericFontFamily::SystemUi
) {
2053 GetSystemUIFontFamilies(langGroup
, genericFamilies
);
2056 GetFontFamiliesFromGenericFamilies(
2057 aPresContext
, aGenericType
, genericFamilies
, langGroup
, aGenericFamilies
);
2059 #if 0 // dump out generic mappings
2060 printf("%s ===> ", NamePref(generic
, langGroupStr
).get());
2061 for (uint32_t k
= 0; k
< aGenericFamilies
->Length(); k
++) {
2062 if (k
> 0) printf(", ");
2063 printf("%s", (*aGenericFamilies
)[k
].mIsShared
2064 ? (*aGenericFamilies
)[k
].mShared
->DisplayName().AsString(SharedFontList()).get()
2065 : (*aGenericFamilies
)[k
].mUnshared
->Name().get());
2071 void gfxPlatformFontList::ResolveEmojiFontNames(
2072 nsPresContext
* aPresContext
, PrefFontList
* aGenericFamilies
) {
2073 // emoji preference has no lang name
2074 AutoTArray
<nsCString
, 4> genericFamilies
;
2076 nsAutoCString value
;
2077 if (mFontPrefs
->LookupNameList(PrefName("emoji", ""), value
)) {
2078 gfxFontUtils::ParseFontList(value
, genericFamilies
);
2081 GetFontFamiliesFromGenericFamilies(
2082 aPresContext
, StyleGenericFontFamily::MozEmoji
, genericFamilies
, nullptr,
2086 void gfxPlatformFontList::GetFontFamiliesFromGenericFamilies(
2087 nsPresContext
* aPresContext
, StyleGenericFontFamily aGenericType
,
2088 nsTArray
<nsCString
>& aGenericNameFamilies
, nsAtom
* aLangGroup
,
2089 PrefFontList
* aGenericFamilies
) {
2090 // lookup and add platform fonts uniquely
2091 for (const nsCString
& genericFamily
: aGenericNameFamilies
) {
2092 AutoTArray
<FamilyAndGeneric
, 10> families
;
2093 FindAndAddFamiliesLocked(aPresContext
, aGenericType
, genericFamily
,
2094 &families
, FindFamiliesFlags(0), nullptr,
2096 for (const FamilyAndGeneric
& f
: families
) {
2097 if (!aGenericFamilies
->Contains(f
.mFamily
)) {
2098 aGenericFamilies
->AppendElement(f
.mFamily
);
2104 gfxPlatformFontList::PrefFontList
*
2105 gfxPlatformFontList::GetPrefFontsLangGroupLocked(
2106 nsPresContext
* aPresContext
, StyleGenericFontFamily aGenericType
,
2107 eFontPrefLang aPrefLang
) {
2108 if (aGenericType
== StyleGenericFontFamily::MozEmoji
||
2109 aPrefLang
== eFontPrefLang_Emoji
) {
2110 // Emoji font has no lang
2111 PrefFontList
* prefFonts
= mEmojiPrefFont
.get();
2112 if (MOZ_UNLIKELY(!prefFonts
)) {
2113 prefFonts
= new PrefFontList
;
2114 ResolveEmojiFontNames(aPresContext
, prefFonts
);
2115 mEmojiPrefFont
.reset(prefFonts
);
2120 auto index
= static_cast<size_t>(aGenericType
);
2121 PrefFontList
* prefFonts
= mLangGroupPrefFonts
[aPrefLang
][index
].get();
2122 if (MOZ_UNLIKELY(!prefFonts
)) {
2123 prefFonts
= new PrefFontList
;
2124 ResolveGenericFontNames(aPresContext
, aGenericType
, aPrefLang
, prefFonts
);
2125 mLangGroupPrefFonts
[aPrefLang
][index
].reset(prefFonts
);
2130 void gfxPlatformFontList::AddGenericFonts(
2131 nsPresContext
* aPresContext
, StyleGenericFontFamily aGenericType
,
2132 nsAtom
* aLanguage
, nsTArray
<FamilyAndGeneric
>& aFamilyList
) {
2133 AutoLock
lock(mLock
);
2135 // map lang ==> langGroup
2136 nsAtom
* langGroup
= GetLangGroup(aLanguage
);
2138 // langGroup ==> prefLang
2139 eFontPrefLang prefLang
= GetFontPrefLangFor(langGroup
);
2141 // lookup pref fonts
2142 PrefFontList
* prefFonts
=
2143 GetPrefFontsLangGroupLocked(aPresContext
, aGenericType
, prefLang
);
2145 if (!prefFonts
->IsEmpty()) {
2146 aFamilyList
.SetCapacity(aFamilyList
.Length() + prefFonts
->Length());
2147 for (auto& f
: *prefFonts
) {
2148 aFamilyList
.AppendElement(FamilyAndGeneric(f
, aGenericType
));
2153 static nsAtom
* PrefLangToLangGroups(uint32_t aIndex
) {
2154 // static array here avoids static constructor
2155 static nsAtom
* gPrefLangToLangGroups
[] = {
2156 #define FONT_PREF_LANG(enum_id_, str_, atom_id_) nsGkAtoms::atom_id_
2157 #include "gfxFontPrefLangList.h"
2158 #undef FONT_PREF_LANG
2161 return aIndex
< ArrayLength(gPrefLangToLangGroups
)
2162 ? gPrefLangToLangGroups
[aIndex
]
2163 : nsGkAtoms::Unicode
;
2166 eFontPrefLang
gfxPlatformFontList::GetFontPrefLangFor(const char* aLang
) {
2167 if (!aLang
|| !aLang
[0]) {
2168 return eFontPrefLang_Others
;
2170 for (uint32_t i
= 0; i
< ArrayLength(gPrefLangNames
); ++i
) {
2171 if (!nsCRT::strcasecmp(gPrefLangNames
[i
], aLang
)) {
2172 return eFontPrefLang(i
);
2175 return eFontPrefLang_Others
;
2178 eFontPrefLang
gfxPlatformFontList::GetFontPrefLangFor(nsAtom
* aLang
) {
2179 if (!aLang
) return eFontPrefLang_Others
;
2181 aLang
->ToUTF8String(lang
);
2182 return GetFontPrefLangFor(lang
.get());
2185 nsAtom
* gfxPlatformFontList::GetLangGroupForPrefLang(eFontPrefLang aLang
) {
2186 // the special CJK set pref lang should be resolved into separate
2187 // calls to individual CJK pref langs before getting here
2188 NS_ASSERTION(aLang
!= eFontPrefLang_CJKSet
, "unresolved CJK set pref lang");
2190 return PrefLangToLangGroups(uint32_t(aLang
));
2193 const char* gfxPlatformFontList::GetPrefLangName(eFontPrefLang aLang
) {
2194 if (uint32_t(aLang
) < ArrayLength(gPrefLangNames
)) {
2195 return gPrefLangNames
[uint32_t(aLang
)];
2200 eFontPrefLang
gfxPlatformFontList::GetFontPrefLangFor(uint32_t aCh
) {
2201 switch (ublock_getCode(aCh
)) {
2202 case UBLOCK_BASIC_LATIN
:
2203 case UBLOCK_LATIN_1_SUPPLEMENT
:
2204 case UBLOCK_LATIN_EXTENDED_A
:
2205 case UBLOCK_LATIN_EXTENDED_B
:
2206 case UBLOCK_IPA_EXTENSIONS
:
2207 case UBLOCK_SPACING_MODIFIER_LETTERS
:
2208 case UBLOCK_LATIN_EXTENDED_ADDITIONAL
:
2209 case UBLOCK_LATIN_EXTENDED_C
:
2210 case UBLOCK_LATIN_EXTENDED_D
:
2211 case UBLOCK_LATIN_EXTENDED_E
:
2212 case UBLOCK_PHONETIC_EXTENSIONS
:
2213 return eFontPrefLang_Western
;
2215 case UBLOCK_GREEK_EXTENDED
:
2216 return eFontPrefLang_Greek
;
2217 case UBLOCK_CYRILLIC
:
2218 case UBLOCK_CYRILLIC_SUPPLEMENT
:
2219 case UBLOCK_CYRILLIC_EXTENDED_A
:
2220 case UBLOCK_CYRILLIC_EXTENDED_B
:
2221 case UBLOCK_CYRILLIC_EXTENDED_C
:
2222 return eFontPrefLang_Cyrillic
;
2223 case UBLOCK_ARMENIAN
:
2224 return eFontPrefLang_Armenian
;
2226 return eFontPrefLang_Hebrew
;
2228 case UBLOCK_ARABIC_PRESENTATION_FORMS_A
:
2229 case UBLOCK_ARABIC_PRESENTATION_FORMS_B
:
2230 case UBLOCK_ARABIC_SUPPLEMENT
:
2231 case UBLOCK_ARABIC_EXTENDED_A
:
2232 case UBLOCK_ARABIC_MATHEMATICAL_ALPHABETIC_SYMBOLS
:
2233 return eFontPrefLang_Arabic
;
2234 case UBLOCK_DEVANAGARI
:
2235 case UBLOCK_DEVANAGARI_EXTENDED
:
2236 return eFontPrefLang_Devanagari
;
2237 case UBLOCK_BENGALI
:
2238 return eFontPrefLang_Bengali
;
2239 case UBLOCK_GURMUKHI
:
2240 return eFontPrefLang_Gurmukhi
;
2241 case UBLOCK_GUJARATI
:
2242 return eFontPrefLang_Gujarati
;
2244 return eFontPrefLang_Oriya
;
2246 return eFontPrefLang_Tamil
;
2248 return eFontPrefLang_Telugu
;
2249 case UBLOCK_KANNADA
:
2250 return eFontPrefLang_Kannada
;
2251 case UBLOCK_MALAYALAM
:
2252 return eFontPrefLang_Malayalam
;
2253 case UBLOCK_SINHALA
:
2254 case UBLOCK_SINHALA_ARCHAIC_NUMBERS
:
2255 return eFontPrefLang_Sinhala
;
2257 return eFontPrefLang_Thai
;
2258 case UBLOCK_TIBETAN
:
2259 return eFontPrefLang_Tibetan
;
2260 case UBLOCK_GEORGIAN
:
2261 case UBLOCK_GEORGIAN_SUPPLEMENT
:
2262 case UBLOCK_GEORGIAN_EXTENDED
:
2263 return eFontPrefLang_Georgian
;
2264 case UBLOCK_HANGUL_JAMO
:
2265 case UBLOCK_HANGUL_COMPATIBILITY_JAMO
:
2266 case UBLOCK_HANGUL_SYLLABLES
:
2267 case UBLOCK_HANGUL_JAMO_EXTENDED_A
:
2268 case UBLOCK_HANGUL_JAMO_EXTENDED_B
:
2269 return eFontPrefLang_Korean
;
2270 case UBLOCK_ETHIOPIC
:
2271 case UBLOCK_ETHIOPIC_EXTENDED
:
2272 case UBLOCK_ETHIOPIC_SUPPLEMENT
:
2273 case UBLOCK_ETHIOPIC_EXTENDED_A
:
2274 return eFontPrefLang_Ethiopic
;
2275 case UBLOCK_UNIFIED_CANADIAN_ABORIGINAL_SYLLABICS
:
2276 case UBLOCK_UNIFIED_CANADIAN_ABORIGINAL_SYLLABICS_EXTENDED
:
2277 return eFontPrefLang_Canadian
;
2279 case UBLOCK_KHMER_SYMBOLS
:
2280 return eFontPrefLang_Khmer
;
2281 case UBLOCK_CJK_RADICALS_SUPPLEMENT
:
2282 case UBLOCK_KANGXI_RADICALS
:
2283 case UBLOCK_IDEOGRAPHIC_DESCRIPTION_CHARACTERS
:
2284 case UBLOCK_CJK_SYMBOLS_AND_PUNCTUATION
:
2285 case UBLOCK_HIRAGANA
:
2286 case UBLOCK_KATAKANA
:
2287 case UBLOCK_BOPOMOFO
:
2289 case UBLOCK_BOPOMOFO_EXTENDED
:
2290 case UBLOCK_ENCLOSED_CJK_LETTERS_AND_MONTHS
:
2291 case UBLOCK_CJK_COMPATIBILITY
:
2292 case UBLOCK_CJK_UNIFIED_IDEOGRAPHS_EXTENSION_A
:
2293 case UBLOCK_CJK_UNIFIED_IDEOGRAPHS
:
2294 case UBLOCK_CJK_COMPATIBILITY_IDEOGRAPHS
:
2295 case UBLOCK_CJK_COMPATIBILITY_FORMS
:
2296 case UBLOCK_SMALL_FORM_VARIANTS
:
2297 case UBLOCK_HALFWIDTH_AND_FULLWIDTH_FORMS
:
2298 case UBLOCK_CJK_UNIFIED_IDEOGRAPHS_EXTENSION_B
:
2299 case UBLOCK_CJK_COMPATIBILITY_IDEOGRAPHS_SUPPLEMENT
:
2300 case UBLOCK_KATAKANA_PHONETIC_EXTENSIONS
:
2301 case UBLOCK_CJK_STROKES
:
2302 case UBLOCK_VERTICAL_FORMS
:
2303 case UBLOCK_CJK_UNIFIED_IDEOGRAPHS_EXTENSION_C
:
2304 case UBLOCK_KANA_SUPPLEMENT
:
2305 case UBLOCK_CJK_UNIFIED_IDEOGRAPHS_EXTENSION_D
:
2306 case UBLOCK_CJK_UNIFIED_IDEOGRAPHS_EXTENSION_E
:
2307 case UBLOCK_IDEOGRAPHIC_SYMBOLS_AND_PUNCTUATION
:
2308 case UBLOCK_CJK_UNIFIED_IDEOGRAPHS_EXTENSION_F
:
2309 case UBLOCK_KANA_EXTENDED_A
:
2310 return eFontPrefLang_CJKSet
;
2311 case UBLOCK_MATHEMATICAL_OPERATORS
:
2312 case UBLOCK_MATHEMATICAL_ALPHANUMERIC_SYMBOLS
:
2313 case UBLOCK_MISCELLANEOUS_MATHEMATICAL_SYMBOLS_A
:
2314 case UBLOCK_MISCELLANEOUS_MATHEMATICAL_SYMBOLS_B
:
2315 case UBLOCK_SUPPLEMENTAL_MATHEMATICAL_OPERATORS
:
2316 return eFontPrefLang_Mathematics
;
2318 return eFontPrefLang_Others
;
2322 bool gfxPlatformFontList::IsLangCJK(eFontPrefLang aLang
) {
2324 case eFontPrefLang_Japanese
:
2325 case eFontPrefLang_ChineseTW
:
2326 case eFontPrefLang_ChineseCN
:
2327 case eFontPrefLang_ChineseHK
:
2328 case eFontPrefLang_Korean
:
2329 case eFontPrefLang_CJKSet
:
2336 void gfxPlatformFontList::GetLangPrefs(eFontPrefLang aPrefLangs
[],
2337 uint32_t& aLen
, eFontPrefLang aCharLang
,
2338 eFontPrefLang aPageLang
) {
2339 AutoLock
lock(mLock
);
2340 if (IsLangCJK(aCharLang
)) {
2341 AppendCJKPrefLangs(aPrefLangs
, aLen
, aCharLang
, aPageLang
);
2343 AppendPrefLang(aPrefLangs
, aLen
, aCharLang
);
2346 AppendPrefLang(aPrefLangs
, aLen
, eFontPrefLang_Others
);
2349 void gfxPlatformFontList::AppendCJKPrefLangs(eFontPrefLang aPrefLangs
[],
2351 eFontPrefLang aCharLang
,
2352 eFontPrefLang aPageLang
) {
2353 // prefer the lang specified by the page *if* CJK
2354 if (IsLangCJK(aPageLang
)) {
2355 AppendPrefLang(aPrefLangs
, aLen
, aPageLang
);
2358 // if not set up, set up the default CJK order, based on accept lang
2359 // settings and locale
2360 if (mCJKPrefLangs
.Length() == 0) {
2362 eFontPrefLang tempPrefLangs
[kMaxLenPrefLangList
];
2363 uint32_t tempLen
= 0;
2365 // Add the CJK pref fonts from accept languages, the order should be same
2366 // order. We use gfxFontUtils::GetPrefsFontList to read the list even
2367 // though it's not actually a list of fonts but of lang codes; the format
2369 AutoTArray
<nsCString
, 5> list
;
2370 gfxFontUtils::GetPrefsFontList("intl.accept_languages", list
, true);
2371 for (const auto& lang
: list
) {
2372 eFontPrefLang fpl
= GetFontPrefLangFor(lang
.get());
2374 case eFontPrefLang_Japanese
:
2375 case eFontPrefLang_Korean
:
2376 case eFontPrefLang_ChineseCN
:
2377 case eFontPrefLang_ChineseHK
:
2378 case eFontPrefLang_ChineseTW
:
2379 AppendPrefLang(tempPrefLangs
, tempLen
, fpl
);
2386 // Try using app's locale
2387 nsAutoCString localeStr
;
2388 LocaleService::GetInstance()->GetAppLocaleAsBCP47(localeStr
);
2392 if (LocaleParser::TryParse(localeStr
, locale
).isOk() &&
2393 locale
.Canonicalize().isOk()) {
2394 if (locale
.Language().EqualTo("ja")) {
2395 AppendPrefLang(tempPrefLangs
, tempLen
, eFontPrefLang_Japanese
);
2396 } else if (locale
.Language().EqualTo("zh")) {
2397 if (locale
.Region().EqualTo("CN")) {
2398 AppendPrefLang(tempPrefLangs
, tempLen
, eFontPrefLang_ChineseCN
);
2399 } else if (locale
.Region().EqualTo("TW")) {
2400 AppendPrefLang(tempPrefLangs
, tempLen
, eFontPrefLang_ChineseTW
);
2401 } else if (locale
.Region().EqualTo("HK")) {
2402 AppendPrefLang(tempPrefLangs
, tempLen
, eFontPrefLang_ChineseHK
);
2404 } else if (locale
.Language().EqualTo("ko")) {
2405 AppendPrefLang(tempPrefLangs
, tempLen
, eFontPrefLang_Korean
);
2410 // Then add the known CJK prefs in order of system preferred locales
2411 AutoTArray
<nsCString
, 5> prefLocales
;
2412 prefLocales
.AppendElement("ja"_ns
);
2413 prefLocales
.AppendElement("zh-CN"_ns
);
2414 prefLocales
.AppendElement("zh-TW"_ns
);
2415 prefLocales
.AppendElement("zh-HK"_ns
);
2416 prefLocales
.AppendElement("ko"_ns
);
2418 AutoTArray
<nsCString
, 16> sysLocales
;
2419 AutoTArray
<nsCString
, 16> negLocales
;
2421 OSPreferences::GetInstance()->GetSystemLocales(sysLocales
))) {
2422 LocaleService::GetInstance()->NegotiateLanguages(
2423 sysLocales
, prefLocales
, ""_ns
,
2424 LocaleService::kLangNegStrategyFiltering
, negLocales
);
2425 for (const auto& localeStr
: negLocales
) {
2427 if (LocaleParser::TryParse(localeStr
, locale
).isOk() &&
2428 locale
.Canonicalize().isOk()) {
2429 if (locale
.Language().EqualTo("ja")) {
2430 AppendPrefLang(tempPrefLangs
, tempLen
, eFontPrefLang_Japanese
);
2431 } else if (locale
.Language().EqualTo("zh")) {
2432 if (locale
.Region().EqualTo("CN")) {
2433 AppendPrefLang(tempPrefLangs
, tempLen
, eFontPrefLang_ChineseCN
);
2434 } else if (locale
.Region().EqualTo("TW")) {
2435 AppendPrefLang(tempPrefLangs
, tempLen
, eFontPrefLang_ChineseTW
);
2436 } else if (locale
.Region().EqualTo("HK")) {
2437 AppendPrefLang(tempPrefLangs
, tempLen
, eFontPrefLang_ChineseHK
);
2439 } else if (locale
.Language().EqualTo("ko")) {
2440 AppendPrefLang(tempPrefLangs
, tempLen
, eFontPrefLang_Korean
);
2446 // Last resort... set up CJK font prefs in the order listed by the user-
2447 // configurable ordering pref.
2448 gfxFontUtils::GetPrefsFontList(kCJKFallbackOrderPref
, list
);
2449 for (const auto& item
: list
) {
2450 eFontPrefLang fpl
= GetFontPrefLangFor(item
.get());
2452 case eFontPrefLang_Japanese
:
2453 case eFontPrefLang_Korean
:
2454 case eFontPrefLang_ChineseCN
:
2455 case eFontPrefLang_ChineseHK
:
2456 case eFontPrefLang_ChineseTW
:
2457 AppendPrefLang(tempPrefLangs
, tempLen
, fpl
);
2464 // Truly-last resort... try Chinese font prefs before Japanese because
2465 // they tend to have more complete character coverage, and therefore less
2466 // risk of "ransom-note" effects.
2467 // (If the kCJKFallbackOrderPref was fully populated, as it is by default,
2468 // this will do nothing as all these values are already present.)
2469 AppendPrefLang(tempPrefLangs
, tempLen
, eFontPrefLang_ChineseCN
);
2470 AppendPrefLang(tempPrefLangs
, tempLen
, eFontPrefLang_ChineseHK
);
2471 AppendPrefLang(tempPrefLangs
, tempLen
, eFontPrefLang_ChineseTW
);
2472 AppendPrefLang(tempPrefLangs
, tempLen
, eFontPrefLang_Japanese
);
2473 AppendPrefLang(tempPrefLangs
, tempLen
, eFontPrefLang_Korean
);
2475 // copy into the cached array
2476 for (const auto lang
: Span
<eFontPrefLang
>(tempPrefLangs
, tempLen
)) {
2477 mCJKPrefLangs
.AppendElement(lang
);
2481 // append in cached CJK langs
2482 for (const auto lang
: mCJKPrefLangs
) {
2483 AppendPrefLang(aPrefLangs
, aLen
, eFontPrefLang(lang
));
2487 void gfxPlatformFontList::AppendPrefLang(eFontPrefLang aPrefLangs
[],
2489 eFontPrefLang aAddLang
) {
2490 if (aLen
>= kMaxLenPrefLangList
) {
2494 // If the lang is already present, just ignore the addition.
2495 for (const auto lang
: Span
<eFontPrefLang
>(aPrefLangs
, aLen
)) {
2496 if (lang
== aAddLang
) {
2501 aPrefLangs
[aLen
++] = aAddLang
;
2504 StyleGenericFontFamily
gfxPlatformFontList::GetDefaultGeneric(
2505 eFontPrefLang aLang
) {
2506 if (aLang
== eFontPrefLang_Emoji
) {
2507 return StyleGenericFontFamily::MozEmoji
;
2510 AutoLock
lock(mLock
);
2512 if (uint32_t(aLang
) < ArrayLength(gPrefLangNames
)) {
2513 return mDefaultGenericsLangGroup
[uint32_t(aLang
)];
2515 return StyleGenericFontFamily::Serif
;
2518 FontFamily
gfxPlatformFontList::GetDefaultFont(nsPresContext
* aPresContext
,
2519 const gfxFontStyle
* aStyle
) {
2520 AutoLock
lock(mLock
);
2521 return GetDefaultFontLocked(aPresContext
, aStyle
);
2524 FontFamily
gfxPlatformFontList::GetDefaultFontLocked(
2525 nsPresContext
* aPresContext
, const gfxFontStyle
* aStyle
) {
2526 FontFamily family
= GetDefaultFontForPlatform(aPresContext
, aStyle
);
2527 if (!family
.IsNull()) {
2530 // Something has gone wrong and we were unable to retrieve a default font
2531 // from the platform. (Likely the whitelist has blocked all potential
2532 // default fonts.) As a last resort, we return the first font in our list.
2533 if (SharedFontList()) {
2534 MOZ_RELEASE_ASSERT(SharedFontList()->NumFamilies() > 0);
2535 return FontFamily(SharedFontList()->Families());
2537 MOZ_RELEASE_ASSERT(mFontFamilies
.Count() > 0);
2538 return FontFamily(mFontFamilies
.ConstIter().Data());
2541 void gfxPlatformFontList::GetFontFamilyNames(
2542 nsTArray
<nsCString
>& aFontFamilyNames
) {
2543 if (SharedFontList()) {
2544 fontlist::FontList
* list
= SharedFontList();
2545 const fontlist::Family
* families
= list
->Families();
2547 for (uint32_t i
= 0, n
= list
->NumFamilies(); i
< n
; i
++) {
2548 const fontlist::Family
& family
= families
[i
];
2549 if (!family
.IsHidden()) {
2550 aFontFamilyNames
.AppendElement(family
.DisplayName().AsString(list
));
2555 for (const RefPtr
<gfxFontFamily
>& family
: mFontFamilies
.Values()) {
2556 if (!family
->IsHidden()) {
2557 aFontFamilyNames
.AppendElement(family
->Name());
2563 nsAtom
* gfxPlatformFontList::GetLangGroup(nsAtom
* aLanguage
) {
2564 // map lang ==> langGroup
2565 nsAtom
* langGroup
= nullptr;
2567 langGroup
= mLangService
->GetLanguageGroup(aLanguage
);
2570 langGroup
= nsGkAtoms::Unicode
;
2575 /* static */ const char* gfxPlatformFontList::GetGenericName(
2576 StyleGenericFontFamily aGenericType
) {
2577 // type should be standard generic type at this point
2578 // map generic type to string
2579 switch (aGenericType
) {
2580 case StyleGenericFontFamily::Serif
:
2582 case StyleGenericFontFamily::SansSerif
:
2583 return "sans-serif";
2584 case StyleGenericFontFamily::Monospace
:
2586 case StyleGenericFontFamily::Cursive
:
2588 case StyleGenericFontFamily::Fantasy
:
2590 case StyleGenericFontFamily::SystemUi
:
2592 case StyleGenericFontFamily::MozEmoji
:
2593 return "-moz-emoji";
2594 case StyleGenericFontFamily::None
:
2597 MOZ_ASSERT_UNREACHABLE("Unknown generic");
2601 void gfxPlatformFontList::InitLoader() {
2602 GetFontFamilyNames(mFontInfo
->mFontFamiliesToLoad
);
2604 mNumFamilies
= mFontInfo
->mFontFamiliesToLoad
.Length();
2605 memset(&(mFontInfo
->mLoadStats
), 0, sizeof(mFontInfo
->mLoadStats
));
2608 #define FONT_LOADER_MAX_TIMESLICE \
2609 20 // max time for one pass through RunLoader = 20ms
2611 bool gfxPlatformFontList::LoadFontInfo() {
2612 AutoLock
lock(mLock
);
2613 TimeStamp start
= TimeStamp::Now();
2614 uint32_t i
, endIndex
= mNumFamilies
;
2615 fontlist::FontList
* list
= SharedFontList();
2617 !list
&& (!UsesSystemFallback() ||
2618 gfxPlatform::GetPlatform()->UseCmapsDuringSystemFallback());
2620 // for each font family, load in various font info
2621 for (i
= mStartIndex
; i
< endIndex
; i
++) {
2623 GenerateFontListKey(mFontInfo
->mFontFamiliesToLoad
[i
], key
);
2626 fontlist::Family
* family
= list
->FindFamily(key
);
2630 ReadFaceNamesForFamily(family
, NeedFullnamePostscriptNames());
2632 // lookup in canonical (i.e. English) family name list
2633 gfxFontFamily
* familyEntry
= mFontFamilies
.GetWeak(key
);
2638 // read in face names
2639 familyEntry
->ReadFaceNames(this, NeedFullnamePostscriptNames(),
2642 // load the cmaps if needed
2644 familyEntry
->ReadAllCMAPs(mFontInfo
);
2648 // Limit the time spent reading fonts in one pass, unless the font-loader
2649 // delay was set to zero, in which case we run to completion even if it
2650 // causes some jank.
2651 if (StaticPrefs::gfx_font_loader_delay_AtStartup() > 0) {
2652 TimeDuration elapsed
= TimeStamp::Now() - start
;
2653 if (elapsed
.ToMilliseconds() > FONT_LOADER_MAX_TIMESLICE
&&
2654 i
+ 1 != endIndex
) {
2661 mStartIndex
= endIndex
;
2662 bool done
= mStartIndex
>= mNumFamilies
;
2664 if (LOG_FONTINIT_ENABLED()) {
2665 TimeDuration elapsed
= TimeStamp::Now() - start
;
2666 LOG_FONTINIT(("(fontinit) fontloader load pass %8.2f ms done %s\n",
2667 elapsed
.ToMilliseconds(), (done
? "true" : "false")));
2671 mOtherFamilyNamesInitialized
= true;
2672 CancelInitOtherFamilyNamesTask();
2673 mFaceNameListsInitialized
= true;
2679 void gfxPlatformFontList::CleanupLoader() {
2680 AutoLock
lock(mLock
);
2682 mFontFamiliesToLoad
.Clear();
2684 bool rebuilt
= false, forceReflow
= false;
2686 // if had missed face names that are now available, force reflow all
2687 if (mFaceNamesMissed
) {
2688 rebuilt
= std::any_of(mFaceNamesMissed
->cbegin(), mFaceNamesMissed
->cend(),
2689 [&](const auto& key
) {
2690 mLock
.AssertCurrentThreadIn();
2691 return FindFaceName(key
);
2694 RebuildLocalFonts();
2697 mFaceNamesMissed
= nullptr;
2700 if (mOtherNamesMissed
) {
2701 forceReflow
= std::any_of(
2702 mOtherNamesMissed
->cbegin(), mOtherNamesMissed
->cend(),
2703 [&](const auto& key
) {
2704 mLock
.AssertCurrentThreadIn();
2705 return FindUnsharedFamily(
2707 (FindFamiliesFlags::eForceOtherFamilyNamesLoading
|
2708 FindFamiliesFlags::eNoAddToNamesMissedWhenSearching
));
2711 ForceGlobalReflowLocked(gfxPlatform::NeedsReframe::No
);
2714 mOtherNamesMissed
= nullptr;
2717 if (LOG_FONTINIT_ENABLED() && mFontInfo
) {
2719 ("(fontinit) fontloader load thread took %8.2f ms "
2720 "%d families %d fonts %d cmaps "
2721 "%d facenames %d othernames %s %s",
2722 mLoadTime
.ToMilliseconds(), mFontInfo
->mLoadStats
.families
,
2723 mFontInfo
->mLoadStats
.fonts
, mFontInfo
->mLoadStats
.cmaps
,
2724 mFontInfo
->mLoadStats
.facenames
, mFontInfo
->mLoadStats
.othernames
,
2725 (rebuilt
? "(userfont sets rebuilt)" : ""),
2726 (forceReflow
? "(global reflow)" : "")));
2729 gfxFontInfoLoader::CleanupLoader();
2732 void gfxPlatformFontList::ForceGlobalReflowLocked(
2733 gfxPlatform::NeedsReframe aNeedsReframe
,
2734 gfxPlatform::BroadcastToChildren aBroadcastToChildren
) {
2735 if (!NS_IsMainThread()) {
2736 NS_DispatchToMainThread(NS_NewRunnableFunction(
2737 "gfxPlatformFontList::ForceGlobalReflowLocked",
2738 [aNeedsReframe
, aBroadcastToChildren
] {
2739 gfxPlatform::ForceGlobalReflow(aNeedsReframe
, aBroadcastToChildren
);
2744 AutoUnlock
unlock(mLock
);
2745 gfxPlatform::ForceGlobalReflow(aNeedsReframe
, aBroadcastToChildren
);
2748 void gfxPlatformFontList::GetPrefsAndStartLoader() {
2749 // If we're already in shutdown, there's no point in starting this, and it
2750 // could trigger an assertion if we try to use the Thread Manager too late.
2751 if (AppShutdown::IsInOrBeyond(ShutdownPhase::AppShutdownConfirmed
)) {
2754 uint32_t delay
= std::max(1u, StaticPrefs::gfx_font_loader_delay_AtStartup());
2755 if (NS_IsMainThread()) {
2758 NS_DispatchToMainThread(NS_NewRunnableFunction(
2759 "StartLoader callback", [delay
, fontList
= this] {
2761 fontList
->StartLoader(delay
);
2767 void gfxPlatformFontList::RebuildLocalFonts(bool aForgetLocalFaces
) {
2768 for (auto* fontset
: mUserFontSetList
) {
2769 if (aForgetLocalFaces
) {
2770 fontset
->ForgetLocalFaces();
2772 fontset
->RebuildLocalRules();
2776 void gfxPlatformFontList::ClearLangGroupPrefFontsLocked() {
2777 for (uint32_t i
= eFontPrefLang_First
;
2778 i
< eFontPrefLang_First
+ eFontPrefLang_Count
; i
++) {
2779 auto& prefFontsLangGroup
= mLangGroupPrefFonts
[i
];
2780 for (auto& pref
: prefFontsLangGroup
) {
2784 mCJKPrefLangs
.Clear();
2785 mEmojiPrefFont
= nullptr;
2787 // Create a new FontPrefs and replace the existing one.
2788 mFontPrefs
= MakeUnique
<FontPrefs
>();
2791 // Support for memory reporting
2793 // this is also used by subclasses that hold additional font tables
2795 size_t gfxPlatformFontList::SizeOfFontFamilyTableExcludingThis(
2796 const FontFamilyTable
& aTable
, MallocSizeOf aMallocSizeOf
) {
2797 return std::accumulate(
2798 aTable
.Keys().cbegin(), aTable
.Keys().cend(),
2799 aTable
.ShallowSizeOfExcludingThis(aMallocSizeOf
),
2800 [&](size_t oldValue
, const nsACString
& key
) {
2801 // We don't count the size of the family here, because this is an
2802 // *extra* reference to a family that will have already been counted in
2804 return oldValue
+ key
.SizeOfExcludingThisIfUnshared(aMallocSizeOf
);
2809 size_t gfxPlatformFontList::SizeOfFontEntryTableExcludingThis(
2810 const FontEntryTable
& aTable
, MallocSizeOf aMallocSizeOf
) {
2811 return std::accumulate(
2812 aTable
.Keys().cbegin(), aTable
.Keys().cend(),
2813 aTable
.ShallowSizeOfExcludingThis(aMallocSizeOf
),
2814 [&](size_t oldValue
, const nsACString
& key
) {
2815 // The font itself is counted by its owning family; here we only care
2816 // about the names stored in the hashtable keys.
2818 return oldValue
+ key
.SizeOfExcludingThisIfUnshared(aMallocSizeOf
);
2822 void gfxPlatformFontList::AddSizeOfExcludingThis(MallocSizeOf aMallocSizeOf
,
2823 FontListSizes
* aSizes
) const {
2824 AutoLock
lock(mLock
);
2826 aSizes
->mFontListSize
+=
2827 mFontFamilies
.ShallowSizeOfExcludingThis(aMallocSizeOf
);
2828 for (const auto& entry
: mFontFamilies
) {
2829 aSizes
->mFontListSize
+=
2830 entry
.GetKey().SizeOfExcludingThisIfUnshared(aMallocSizeOf
);
2831 entry
.GetData()->AddSizeOfIncludingThis(aMallocSizeOf
, aSizes
);
2834 aSizes
->mFontListSize
+=
2835 SizeOfFontFamilyTableExcludingThis(mOtherFamilyNames
, aMallocSizeOf
);
2838 aSizes
->mFontListSize
+= SizeOfFontEntryTableExcludingThis(
2839 mExtraNames
->mFullnames
, aMallocSizeOf
);
2840 aSizes
->mFontListSize
+= SizeOfFontEntryTableExcludingThis(
2841 mExtraNames
->mPostscriptNames
, aMallocSizeOf
);
2844 for (uint32_t i
= eFontPrefLang_First
;
2845 i
< eFontPrefLang_First
+ eFontPrefLang_Count
; i
++) {
2846 auto& prefFontsLangGroup
= mLangGroupPrefFonts
[i
];
2847 for (const UniquePtr
<PrefFontList
>& pf
: prefFontsLangGroup
) {
2849 aSizes
->mFontListSize
+= pf
->ShallowSizeOfExcludingThis(aMallocSizeOf
);
2854 for (const auto& bitset
: mCodepointsWithNoFonts
) {
2855 aSizes
->mFontListSize
+= bitset
.SizeOfExcludingThis(aMallocSizeOf
);
2857 aSizes
->mFontListSize
+=
2858 mFontFamiliesToLoad
.ShallowSizeOfExcludingThis(aMallocSizeOf
);
2860 aSizes
->mFontListSize
+=
2861 mBadUnderlineFamilyNames
.ShallowSizeOfExcludingThis(aMallocSizeOf
);
2862 for (const auto& i
: mBadUnderlineFamilyNames
) {
2863 aSizes
->mFontListSize
+= i
.SizeOfExcludingThisIfUnshared(aMallocSizeOf
);
2866 aSizes
->mFontListSize
+=
2867 mSharedCmaps
.ShallowSizeOfExcludingThis(aMallocSizeOf
);
2868 for (const auto& entry
: mSharedCmaps
) {
2869 aSizes
->mCharMapsSize
+= entry
.GetKey()->SizeOfIncludingThis(aMallocSizeOf
);
2872 aSizes
->mFontListSize
+=
2873 mFontEntries
.ShallowSizeOfExcludingThis(aMallocSizeOf
);
2874 for (const auto& entry
: mFontEntries
.Values()) {
2876 entry
->AddSizeOfIncludingThis(aMallocSizeOf
, aSizes
);
2880 if (SharedFontList()) {
2881 aSizes
->mFontListSize
+=
2882 SharedFontList()->SizeOfIncludingThis(aMallocSizeOf
);
2883 if (XRE_IsParentProcess()) {
2884 aSizes
->mSharedSize
+= SharedFontList()->AllocatedShmemSize();
2889 void gfxPlatformFontList::AddSizeOfIncludingThis(MallocSizeOf aMallocSizeOf
,
2890 FontListSizes
* aSizes
) const {
2891 aSizes
->mFontListSize
+= aMallocSizeOf(this);
2892 AddSizeOfExcludingThis(aMallocSizeOf
, aSizes
);
2895 void gfxPlatformFontList::InitOtherFamilyNamesInternal(
2896 bool aDeferOtherFamilyNamesLoading
) {
2897 if (mOtherFamilyNamesInitialized
) {
2901 AutoLock
lock(mLock
);
2903 if (aDeferOtherFamilyNamesLoading
) {
2904 TimeStamp start
= TimeStamp::Now();
2905 bool timedOut
= false;
2907 auto list
= SharedFontList();
2909 // If the gfxFontInfoLoader task is not yet running, kick it off now so
2910 // that it will load remaining names etc as soon as idle time permits.
2911 if (mState
== stateInitial
|| mState
== stateTimerOnDelay
) {
2916 for (const RefPtr
<gfxFontFamily
>& family
: mFontFamilies
.Values()) {
2917 family
->ReadOtherFamilyNames(this);
2918 TimeDuration elapsed
= TimeStamp::Now() - start
;
2919 if (elapsed
.ToMilliseconds() > OTHERNAMES_TIMEOUT
) {
2927 mOtherFamilyNamesInitialized
= true;
2928 CancelInitOtherFamilyNamesTask();
2930 TimeStamp end
= TimeStamp::Now();
2931 Telemetry::AccumulateTimeDelta(Telemetry::FONTLIST_INITOTHERFAMILYNAMES
,
2934 if (LOG_FONTINIT_ENABLED()) {
2935 TimeDuration elapsed
= end
- start
;
2936 LOG_FONTINIT(("(fontinit) InitOtherFamilyNames took %8.2f ms %s",
2937 elapsed
.ToMilliseconds(), (timedOut
? "timeout" : "")));
2940 TimeStamp start
= TimeStamp::Now();
2942 auto list
= SharedFontList();
2944 for (auto& f
: mozilla::Range
<fontlist::Family
>(list
->Families(),
2945 list
->NumFamilies())) {
2946 ReadFaceNamesForFamily(&f
, false);
2949 for (const RefPtr
<gfxFontFamily
>& family
: mFontFamilies
.Values()) {
2950 family
->ReadOtherFamilyNames(this);
2954 mOtherFamilyNamesInitialized
= true;
2955 CancelInitOtherFamilyNamesTask();
2957 TimeStamp end
= TimeStamp::Now();
2958 Telemetry::AccumulateTimeDelta(
2959 Telemetry::FONTLIST_INITOTHERFAMILYNAMES_NO_DEFERRING
, start
, end
);
2961 if (LOG_FONTINIT_ENABLED()) {
2962 TimeDuration elapsed
= end
- start
;
2964 ("(fontinit) InitOtherFamilyNames without deferring took %8.2f ms",
2965 elapsed
.ToMilliseconds()));
2970 void gfxPlatformFontList::CancelInitOtherFamilyNamesTask() {
2971 if (mPendingOtherFamilyNameTask
) {
2972 mPendingOtherFamilyNameTask
->Cancel();
2973 mPendingOtherFamilyNameTask
= nullptr;
2975 auto list
= SharedFontList();
2976 if (list
&& XRE_IsParentProcess()) {
2977 bool forceReflow
= false;
2978 if (!mAliasTable
.IsEmpty()) {
2979 list
->SetAliases(mAliasTable
);
2980 mAliasTable
.Clear();
2983 if (mLocalNameTable
.Count()) {
2984 list
->SetLocalNames(mLocalNameTable
);
2985 mLocalNameTable
.Clear();
2989 dom::ContentParent::BroadcastFontListChanged();
2994 void gfxPlatformFontList::ShareFontListShmBlockToProcess(
2995 uint32_t aGeneration
, uint32_t aIndex
, base::ProcessId aPid
,
2996 base::SharedMemoryHandle
* aOut
) {
2997 auto list
= SharedFontList();
3001 if (!aGeneration
|| list
->GetGeneration() == aGeneration
) {
3002 list
->ShareShmBlockToProcess(aIndex
, aPid
, aOut
);
3004 *aOut
= base::SharedMemory::NULLHandle();
3008 void gfxPlatformFontList::ShareFontListToProcess(
3009 nsTArray
<base::SharedMemoryHandle
>* aBlocks
, base::ProcessId aPid
) {
3010 auto list
= SharedFontList();
3012 list
->ShareBlocksToProcess(aBlocks
, aPid
);
3016 base::SharedMemoryHandle
gfxPlatformFontList::ShareShmBlockToProcess(
3017 uint32_t aIndex
, base::ProcessId aPid
) {
3018 MOZ_RELEASE_ASSERT(SharedFontList());
3019 return SharedFontList()->ShareBlockToProcess(aIndex
, aPid
);
3022 void gfxPlatformFontList::ShmBlockAdded(uint32_t aGeneration
, uint32_t aIndex
,
3023 base::SharedMemoryHandle aHandle
) {
3024 if (SharedFontList()) {
3025 AutoLock
lock(mLock
);
3026 SharedFontList()->ShmBlockAdded(aGeneration
, aIndex
, std::move(aHandle
));
3030 void gfxPlatformFontList::InitializeFamily(uint32_t aGeneration
,
3031 uint32_t aFamilyIndex
,
3033 auto list
= SharedFontList();
3038 if (list
->GetGeneration() != aGeneration
) {
3041 if (AppShutdown::IsInOrBeyond(ShutdownPhase::AppShutdownConfirmed
)) {
3044 if (aFamilyIndex
>= list
->NumFamilies()) {
3047 fontlist::Family
* family
= list
->Families() + aFamilyIndex
;
3048 if (!family
->IsInitialized() || aLoadCmaps
) {
3049 Unused
<< InitializeFamily(family
, aLoadCmaps
);
3053 void gfxPlatformFontList::SetCharacterMap(uint32_t aGeneration
,
3054 uint32_t aFamilyIndex
, bool aAlias
,
3055 uint32_t aFaceIndex
,
3056 const gfxSparseBitSet
& aMap
) {
3057 MOZ_ASSERT(XRE_IsParentProcess());
3058 auto list
= SharedFontList();
3063 if (list
->GetGeneration() != aGeneration
) {
3066 if (AppShutdown::IsInOrBeyond(ShutdownPhase::AppShutdownConfirmed
)) {
3070 const fontlist::Family
* family
;
3072 if (aFamilyIndex
>= list
->NumAliases()) {
3073 MOZ_ASSERT(false, "AliasFamily index out of range");
3076 family
= list
->AliasFamilies() + aFamilyIndex
;
3078 if (aFamilyIndex
>= list
->NumFamilies()) {
3079 MOZ_ASSERT(false, "Family index out of range");
3082 family
= list
->Families() + aFamilyIndex
;
3085 if (aFaceIndex
>= family
->NumFaces()) {
3086 MOZ_ASSERT(false, "Face index out of range");
3091 family
->Faces(list
)[aFaceIndex
].ToPtr
<fontlist::Face
>(list
)) {
3092 face
->mCharacterMap
= GetShmemCharMap(&aMap
);
3096 void gfxPlatformFontList::SetupFamilyCharMap(uint32_t aGeneration
,
3097 uint32_t aIndex
, bool aAlias
) {
3098 MOZ_ASSERT(XRE_IsParentProcess());
3099 auto list
= SharedFontList();
3104 if (list
->GetGeneration() != aGeneration
) {
3107 if (AppShutdown::IsInOrBeyond(ShutdownPhase::AppShutdownConfirmed
)) {
3112 if (aIndex
>= list
->NumAliases()) {
3113 MOZ_ASSERT(false, "AliasFamily index out of range");
3116 list
->AliasFamilies()[aIndex
].SetupFamilyCharMap(list
);
3120 if (aIndex
>= list
->NumFamilies()) {
3121 MOZ_ASSERT(false, "Family index out of range");
3124 list
->Families()[aIndex
].SetupFamilyCharMap(list
);
3127 bool gfxPlatformFontList::InitOtherFamilyNames(uint32_t aGeneration
,
3129 auto list
= SharedFontList();
3134 if (list
->GetGeneration() != aGeneration
) {
3137 if (AppShutdown::IsInOrBeyond(ShutdownPhase::AppShutdownConfirmed
)) {
3140 return InitOtherFamilyNames(aDefer
);
3143 uint32_t gfxPlatformFontList::GetGeneration() const {
3144 return SharedFontList() ? SharedFontList()->GetGeneration() : 0;
3147 gfxPlatformFontList::FontPrefs::FontPrefs() {
3148 // This must be created on the main thread, so that we can safely use the
3149 // Preferences service. Once created, it can be read from any thread.
3150 MOZ_ASSERT(NS_IsMainThread());
3154 void gfxPlatformFontList::FontPrefs::Init() {
3155 if (AppShutdown::IsInOrBeyond(ShutdownPhase::XPCOMShutdownFinal
)) {
3158 nsIPrefBranch
* prefRootBranch
= Preferences::GetRootBranch();
3159 if (!prefRootBranch
) {
3162 nsTArray
<nsCString
> prefNames
;
3163 if (NS_SUCCEEDED(prefRootBranch
->GetChildList(kNamePrefix
, prefNames
))) {
3164 for (auto& prefName
: prefNames
) {
3165 nsAutoCString value
;
3166 if (NS_SUCCEEDED(Preferences::GetCString(prefName
.get(), value
))) {
3167 nsAutoCString
pref(Substring(prefName
, sizeof(kNamePrefix
) - 1));
3168 mFontName
.InsertOrUpdate(pref
, value
);
3172 if (NS_SUCCEEDED(prefRootBranch
->GetChildList(kNameListPrefix
, prefNames
))) {
3173 for (auto& prefName
: prefNames
) {
3174 nsAutoCString value
;
3175 if (NS_SUCCEEDED(Preferences::GetCString(prefName
.get(), value
))) {
3176 nsAutoCString
pref(Substring(prefName
, sizeof(kNameListPrefix
) - 1));
3177 mFontNameList
.InsertOrUpdate(pref
, value
);
3181 mEmojiHasUserValue
= Preferences::HasUserValue("font.name-list.emoji");
3184 bool gfxPlatformFontList::FontPrefs::LookupName(const nsACString
& aPref
,
3185 nsACString
& aValue
) const {
3186 if (const auto& value
= mFontName
.Lookup(aPref
)) {
3193 bool gfxPlatformFontList::FontPrefs::LookupNameList(const nsACString
& aPref
,
3194 nsACString
& aValue
) const {
3195 if (const auto& value
= mFontNameList
.Lookup(aPref
)) {
3202 bool gfxPlatformFontList::IsKnownIconFontFamily(
3203 const nsAtom
* aFamilyName
) const {
3204 nsAtomCString
fam(aFamilyName
);
3206 return mIconFontsSet
.Contains(fam
);