1 /* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 2 -*-
2 * This Source Code Form is subject to the terms of the Mozilla Public
3 * License, v. 2.0. If a copy of the MPL was not distributed with this
4 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
6 #include "mozilla/Logging.h"
7 #include "mozilla/gfx/Logging.h"
8 #include "mozilla/intl/Locale.h"
9 #include "mozilla/intl/LocaleService.h"
10 #include "mozilla/intl/OSPreferences.h"
12 #include "gfxPlatformFontList.h"
13 #include "gfxTextRun.h"
14 #include "gfxUserFontSet.h"
15 #include "SharedFontList-impl.h"
17 #include "GeckoProfiler.h"
19 #include "nsGkAtoms.h"
20 #include "nsPresContext.h"
21 #include "nsServiceManagerUtils.h"
22 #include "nsUnicharUtils.h"
23 #include "nsUnicodeProperties.h"
24 #include "nsXULAppAPI.h"
26 #include "mozilla/AppShutdown.h"
27 #include "mozilla/Attributes.h"
28 #include "mozilla/BinarySearch.h"
29 #include "mozilla/Likely.h"
30 #include "mozilla/MemoryReporting.h"
31 #include "mozilla/Mutex.h"
32 #include "mozilla/Preferences.h"
33 #include "mozilla/StaticPrefs_gfx.h"
34 #include "mozilla/StaticPrefs_layout.h"
35 #include "mozilla/Telemetry.h"
36 #include "mozilla/TimeStamp.h"
37 #include "mozilla/dom/BlobImpl.h"
38 #include "mozilla/dom/ContentChild.h"
39 #include "mozilla/dom/ContentParent.h"
40 #include "mozilla/dom/ContentProcessMessageManager.h"
41 #include "mozilla/dom/Document.h"
42 #include "mozilla/gfx/2D.h"
43 #include "mozilla/ipc/FileDescriptorUtils.h"
44 #include "mozilla/ResultExtensions.h"
45 #include "mozilla/TextUtils.h"
46 #include "mozilla/Unused.h"
48 #include "base/eintr_wrapper.h"
53 using namespace mozilla
;
54 using mozilla::intl::Locale
;
55 using mozilla::intl::LocaleParser
;
56 using mozilla::intl::LocaleService
;
57 using mozilla::intl::OSPreferences
;
59 #define LOG_FONTLIST(args) \
60 MOZ_LOG(gfxPlatform::GetLog(eGfxLog_fontlist), LogLevel::Debug, args)
61 #define LOG_FONTLIST_ENABLED() \
62 MOZ_LOG_TEST(gfxPlatform::GetLog(eGfxLog_fontlist), LogLevel::Debug)
63 #define LOG_FONTINIT(args) \
64 MOZ_LOG(gfxPlatform::GetLog(eGfxLog_fontinit), LogLevel::Debug, args)
65 #define LOG_FONTINIT_ENABLED() \
66 MOZ_LOG_TEST(gfxPlatform::GetLog(eGfxLog_fontinit), LogLevel::Debug)
68 gfxPlatformFontList
* gfxPlatformFontList::sPlatformFontList
= nullptr;
70 // Character ranges that require complex-script shaping support in the font,
71 // and so should be masked out by ReadCMAP if the necessary layout tables
73 // Currently used by the Mac and FT2 implementations only, but probably should
74 // be supported on Windows as well.
75 const gfxFontEntry::ScriptRange
gfxPlatformFontList::sComplexScriptRanges
[] = {
76 // Actually, now that harfbuzz supports presentation-forms shaping for
77 // Arabic, we can render it without layout tables. So maybe we don't
78 // want to mask the basic Arabic block here?
79 // This affects the arabic-fallback-*.html reftests, which rely on
80 // loading a font that *doesn't* have any GSUB table.
81 {0x0600, 0x060B, 1, {TRUETYPE_TAG('a', 'r', 'a', 'b'), 0, 0}},
82 // skip 060C Arabic comma, also used by N'Ko etc
83 {0x060D, 0x061A, 1, {TRUETYPE_TAG('a', 'r', 'a', 'b'), 0, 0}},
84 // skip 061B Arabic semicolon, also used by N'Ko etc
85 {0x061C, 0x061E, 1, {TRUETYPE_TAG('a', 'r', 'a', 'b'), 0, 0}},
86 // skip 061F Arabic question mark, also used by N'Ko etc
87 {0x0620, 0x063F, 1, {TRUETYPE_TAG('a', 'r', 'a', 'b'), 0, 0}},
88 // skip 0640 Arabic tatweel (for syriac, adlam, etc)
89 {0x0641, 0x06D3, 1, {TRUETYPE_TAG('a', 'r', 'a', 'b'), 0, 0}},
90 // skip 06D4 Arabic full stop (for hanifi rohingya)
91 {0x06D5, 0x06FF, 1, {TRUETYPE_TAG('a', 'r', 'a', 'b'), 0, 0}},
92 {0x0700, 0x074F, 1, {TRUETYPE_TAG('s', 'y', 'r', 'c'), 0, 0}},
93 {0x0750, 0x077F, 1, {TRUETYPE_TAG('a', 'r', 'a', 'b'), 0, 0}},
94 {0x08A0, 0x08FF, 1, {TRUETYPE_TAG('a', 'r', 'a', 'b'), 0, 0}},
98 {TRUETYPE_TAG('d', 'e', 'v', '2'), TRUETYPE_TAG('d', 'e', 'v', 'a'), 0}},
99 // skip 0964 DEVANAGARI DANDA and 0965 DEVANAGARI DOUBLE DANDA, shared by
100 // various other Indic writing systems
104 {TRUETYPE_TAG('d', 'e', 'v', '2'), TRUETYPE_TAG('d', 'e', 'v', 'a'), 0}},
108 {TRUETYPE_TAG('b', 'n', 'g', '2'), TRUETYPE_TAG('b', 'e', 'n', 'g'), 0}},
112 {TRUETYPE_TAG('g', 'u', 'r', '2'), TRUETYPE_TAG('g', 'u', 'r', 'u'), 0}},
116 {TRUETYPE_TAG('g', 'j', 'r', '2'), TRUETYPE_TAG('g', 'u', 'j', 'r'), 0}},
120 {TRUETYPE_TAG('o', 'r', 'y', '2'), TRUETYPE_TAG('o', 'r', 'y', 'a'), 0}},
124 {TRUETYPE_TAG('t', 'm', 'l', '2'), TRUETYPE_TAG('t', 'a', 'm', 'l'), 0}},
128 {TRUETYPE_TAG('t', 'e', 'l', '2'), TRUETYPE_TAG('t', 'e', 'l', 'u'), 0}},
132 {TRUETYPE_TAG('k', 'n', 'd', '2'), TRUETYPE_TAG('k', 'n', 'd', 'a'), 0}},
136 {TRUETYPE_TAG('m', 'l', 'm', '2'), TRUETYPE_TAG('m', 'l', 'y', 'm'), 0}},
137 {0x0D80, 0x0DFF, 1, {TRUETYPE_TAG('s', 'i', 'n', 'h'), 0, 0}},
138 {0x0E80, 0x0EFF, 1, {TRUETYPE_TAG('l', 'a', 'o', ' '), 0, 0}},
139 {0x0F00, 0x0FFF, 1, {TRUETYPE_TAG('t', 'i', 'b', 't'), 0, 0}},
143 {TRUETYPE_TAG('m', 'y', 'm', 'r'), TRUETYPE_TAG('m', 'y', 'm', '2'), 0}},
144 {0x1780, 0x17ff, 1, {TRUETYPE_TAG('k', 'h', 'm', 'r'), 0, 0}},
145 // Khmer Symbols (19e0..19ff) don't seem to need any special shaping
149 {TRUETYPE_TAG('m', 'y', 'm', 'r'), TRUETYPE_TAG('m', 'y', 'm', '2'), 0}},
150 // Thai seems to be "renderable" without AAT morphing tables
151 {0, 0, 0, {0, 0, 0}} // terminator
154 static const char* kObservedPrefs
[] = {
155 "font.", "font.name-list.", "intl.accept_languages", // hmmmm...
156 "browser.display.use_document_fonts.icon_font_allowlist", nullptr};
158 static const char kFontSystemWhitelistPref
[] = "font.system.whitelist";
160 static const char kCJKFallbackOrderPref
[] = "font.cjk_pref_fallback_order";
162 // Pref for the list of icon font families that still get to override the
163 // default font from prefs, even when use_document_fonts is disabled.
164 // (This is to enable ligature-based icon fonts to keep working.)
165 static const char kIconFontsPref
[] =
166 "browser.display.use_document_fonts.icon_font_allowlist";
168 // xxx - this can probably be eliminated by reworking pref font handling code
169 static const char* gPrefLangNames
[] = {
170 #define FONT_PREF_LANG(enum_id_, str_, atom_id_) str_
171 #include "gfxFontPrefLangList.h"
172 #undef FONT_PREF_LANG
175 static_assert(MOZ_ARRAY_LENGTH(gPrefLangNames
) == uint32_t(eFontPrefLang_Count
),
176 "size of pref lang name array doesn't match pref lang enum size");
178 class gfxFontListPrefObserver final
: public nsIObserver
{
179 ~gfxFontListPrefObserver() = default;
186 static void FontListPrefChanged(const char* aPref
, void* aData
= nullptr) {
187 // XXX this could be made to only clear out the cache for the prefs that were
188 // changed but it probably isn't that big a deal.
189 gfxPlatformFontList::PlatformFontList()->ClearLangGroupPrefFonts();
190 gfxPlatformFontList::PlatformFontList()->LoadIconFontOverrideList();
191 gfxFontCache::GetCache()->Flush();
194 static gfxFontListPrefObserver
* gFontListPrefObserver
= nullptr;
196 NS_IMPL_ISUPPORTS(gfxFontListPrefObserver
, nsIObserver
)
198 #define LOCALES_CHANGED_TOPIC "intl:system-locales-changed"
201 gfxFontListPrefObserver::Observe(nsISupports
* aSubject
, const char* aTopic
,
202 const char16_t
* aData
) {
203 NS_ASSERTION(!strcmp(aTopic
, LOCALES_CHANGED_TOPIC
), "invalid topic");
204 FontListPrefChanged(nullptr);
206 if (XRE_IsParentProcess()) {
207 gfxPlatform::ForceGlobalReflow(gfxPlatform::NeedsReframe::No
);
212 MOZ_DEFINE_MALLOC_SIZE_OF(FontListMallocSizeOf
)
214 NS_IMPL_ISUPPORTS(gfxPlatformFontList::MemoryReporter
, nsIMemoryReporter
)
217 gfxPlatformFontList::MemoryReporter::CollectReports(
218 nsIHandleReportCallback
* aHandleReport
, nsISupports
* aData
,
221 sizes
.mFontListSize
= 0;
222 sizes
.mFontTableCacheSize
= 0;
223 sizes
.mCharMapsSize
= 0;
224 sizes
.mLoaderSize
= 0;
225 sizes
.mSharedSize
= 0;
227 gfxPlatformFontList::PlatformFontList()->AddSizeOfIncludingThis(
228 &FontListMallocSizeOf
, &sizes
);
231 "explicit/gfx/font-list", KIND_HEAP
, UNITS_BYTES
, sizes
.mFontListSize
,
232 "Memory used to manage the list of font families and faces.");
235 "explicit/gfx/font-charmaps", KIND_HEAP
, UNITS_BYTES
, sizes
.mCharMapsSize
,
236 "Memory used to record the character coverage of individual fonts.");
238 if (sizes
.mFontTableCacheSize
) {
240 "explicit/gfx/font-tables", KIND_HEAP
, UNITS_BYTES
,
241 sizes
.mFontTableCacheSize
,
242 "Memory used for cached font metrics and layout tables.");
245 if (sizes
.mLoaderSize
) {
246 MOZ_COLLECT_REPORT("explicit/gfx/font-loader", KIND_HEAP
, UNITS_BYTES
,
248 "Memory used for (platform-specific) font loader.");
251 if (sizes
.mSharedSize
) {
253 "font-list-shmem", KIND_NONHEAP
, UNITS_BYTES
, sizes
.mSharedSize
,
254 "Shared memory for system font list and character coverage data.");
260 PRThread
* gfxPlatformFontList::sInitFontListThread
= nullptr;
262 static void InitFontListCallback(void* aFontList
) {
263 AUTO_PROFILER_REGISTER_THREAD("InitFontList");
264 PR_SetCurrentThreadName("InitFontList");
266 if (!static_cast<gfxPlatformFontList
*>(aFontList
)->InitFontList()) {
267 gfxPlatformFontList::Shutdown();
272 bool gfxPlatformFontList::Initialize(gfxPlatformFontList
* aList
) {
273 sPlatformFontList
= aList
;
274 if (XRE_IsParentProcess() &&
275 StaticPrefs::gfx_font_list_omt_enabled_AtStartup() &&
276 StaticPrefs::gfx_e10s_font_list_shared_AtStartup() &&
277 !gfxPlatform::InSafeMode()) {
278 sInitFontListThread
= PR_CreateThread(
279 PR_USER_THREAD
, InitFontListCallback
, aList
, PR_PRIORITY_NORMAL
,
280 PR_GLOBAL_THREAD
, PR_JOINABLE_THREAD
, 0);
283 if (aList
->InitFontList()) {
290 gfxPlatformFontList::gfxPlatformFontList(bool aNeedFullnamePostscriptNames
)
291 : mLock("gfxPlatformFontList lock"),
293 mOtherFamilyNames(16),
295 if (aNeedFullnamePostscriptNames
) {
296 mExtraNames
= MakeUnique
<ExtraNames
>();
299 mLangService
= nsLanguageAtomService::GetService();
301 LoadBadUnderlineList();
302 LoadIconFontOverrideList();
304 mFontPrefs
= MakeUnique
<FontPrefs
>();
306 gfxFontUtils::GetPrefsFontList(kFontSystemWhitelistPref
, mEnabledFontsList
);
307 mFontFamilyWhitelistActive
= !mEnabledFontsList
.IsEmpty();
309 // pref changes notification setup
310 NS_ASSERTION(!gFontListPrefObserver
,
311 "There has been font list pref observer already");
312 gFontListPrefObserver
= new gfxFontListPrefObserver();
313 NS_ADDREF(gFontListPrefObserver
);
315 Preferences::RegisterPrefixCallbacks(FontListPrefChanged
, kObservedPrefs
);
317 nsCOMPtr
<nsIObserverService
> obs
= services::GetObserverService();
319 obs
->AddObserver(gFontListPrefObserver
, LOCALES_CHANGED_TOPIC
, false);
322 // Only the parent process listens for whitelist changes; it will then
323 // notify its children to rebuild their font lists.
324 if (XRE_IsParentProcess()) {
325 Preferences::RegisterCallback(FontWhitelistPrefChanged
,
326 kFontSystemWhitelistPref
);
329 RegisterStrongMemoryReporter(new MemoryReporter());
331 // initialize lang group pref font defaults (i.e. serif/sans-serif)
332 mDefaultGenericsLangGroup
.AppendElements(ArrayLength(gPrefLangNames
));
333 for (uint32_t i
= 0; i
< ArrayLength(gPrefLangNames
); i
++) {
334 nsAutoCString
prefDefaultFontType("font.default.");
335 prefDefaultFontType
.Append(GetPrefLangName(eFontPrefLang(i
)));
336 nsAutoCString serifOrSans
;
337 Preferences::GetCString(prefDefaultFontType
.get(), serifOrSans
);
338 if (serifOrSans
.EqualsLiteral("sans-serif")) {
339 mDefaultGenericsLangGroup
[i
] = StyleGenericFontFamily::SansSerif
;
341 mDefaultGenericsLangGroup
[i
] = StyleGenericFontFamily::Serif
;
346 gfxPlatformFontList::~gfxPlatformFontList() {
347 // Note that gfxPlatformFontList::Shutdown() ensures that the init-font-list
348 // thread is finished before we come here.
350 AutoLock
lock(mLock
);
352 // We can't just do mSharedCmaps.Clear() here because removing each item from
353 // the table would drop its last reference, and its Release() method would
354 // then call back to MaybeRemoveCmap to search for it, which we can't do
355 // while in the middle of clearing the table.
356 // So we first clear the "shared" flag in each entry, so Release() won't try
357 // to re-find them in the table.
358 for (auto iter
= mSharedCmaps
.ConstIter(); !iter
.Done(); iter
.Next()) {
359 iter
.Get()->mCharMap
->ClearSharedFlag();
361 mSharedCmaps
.Clear();
363 ClearLangGroupPrefFontsLocked();
365 NS_ASSERTION(gFontListPrefObserver
, "There is no font list pref observer");
367 Preferences::UnregisterPrefixCallbacks(FontListPrefChanged
, kObservedPrefs
);
369 nsCOMPtr
<nsIObserverService
> obs
= services::GetObserverService();
371 obs
->RemoveObserver(gFontListPrefObserver
, LOCALES_CHANGED_TOPIC
);
374 if (XRE_IsParentProcess()) {
375 Preferences::UnregisterCallback(FontWhitelistPrefChanged
,
376 kFontSystemWhitelistPref
);
378 NS_RELEASE(gFontListPrefObserver
);
381 void gfxPlatformFontList::GetMissingFonts(nsCString
& aMissingFonts
) {
382 AutoLock
lock(mLock
);
384 auto fontLists
= GetFilteredPlatformFontLists();
386 if (!fontLists
.Length()) {
387 aMissingFonts
.Append("No font list available for this device.");
390 for (unsigned int i
= 0; i
< fontLists
.Length(); i
++) {
391 for (unsigned int j
= 0; j
< fontLists
[i
].second
; j
++) {
392 nsCString
key(fontLists
[i
].first
[j
]);
393 GenerateFontListKey(key
);
395 if (SharedFontList()) {
396 fontlist::Family
* family
= SharedFontList()->FindFamily(key
);
398 aMissingFonts
.Append(fontLists
[i
].first
[j
]);
399 aMissingFonts
.Append("|");
402 gfxFontFamily
* familyEntry
= mFontFamilies
.GetWeak(key
);
404 familyEntry
= mOtherFamilyNames
.GetWeak(key
);
407 aMissingFonts
.Append(fontLists
[i
].first
[j
]);
408 aMissingFonts
.Append("|");
416 void gfxPlatformFontList::FontWhitelistPrefChanged(const char* aPref
,
418 MOZ_ASSERT(XRE_IsParentProcess());
419 auto* pfl
= gfxPlatformFontList::PlatformFontList();
420 pfl
->UpdateFontList(true);
421 dom::ContentParent::NotifyUpdatedFonts(true);
424 void gfxPlatformFontList::ApplyWhitelist() {
425 uint32_t numFonts
= mEnabledFontsList
.Length();
426 if (!mFontFamilyWhitelistActive
) {
429 nsTHashSet
<nsCString
> familyNamesWhitelist
;
430 for (uint32_t i
= 0; i
< numFonts
; i
++) {
432 ToLowerCase(mEnabledFontsList
[i
], key
);
433 familyNamesWhitelist
.Insert(key
);
435 AutoTArray
<RefPtr
<gfxFontFamily
>, 128> accepted
;
436 bool whitelistedFontFound
= false;
437 for (const auto& entry
: mFontFamilies
) {
438 if (entry
.GetData()->IsHidden()) {
439 // Hidden system fonts are exempt from whitelisting, but don't count
440 // towards determining whether we "kept" any (user-visible) fonts
441 accepted
.AppendElement(entry
.GetData());
444 nsAutoCString
fontFamilyName(entry
.GetKey());
445 ToLowerCase(fontFamilyName
);
446 if (familyNamesWhitelist
.Contains(fontFamilyName
)) {
447 accepted
.AppendElement(entry
.GetData());
448 whitelistedFontFound
= true;
451 if (!whitelistedFontFound
) {
452 // No whitelisted fonts found! Ignore the whitelist.
455 // Replace the original full list with the accepted subset.
456 mFontFamilies
.Clear();
457 for (auto& f
: accepted
) {
458 nsAutoCString
fontFamilyName(f
->Name());
459 ToLowerCase(fontFamilyName
);
460 mFontFamilies
.InsertOrUpdate(fontFamilyName
, std::move(f
));
464 void gfxPlatformFontList::ApplyWhitelist(
465 nsTArray
<fontlist::Family::InitData
>& aFamilies
) {
466 mLock
.AssertCurrentThreadIn();
467 if (!mFontFamilyWhitelistActive
) {
470 nsTHashSet
<nsCString
> familyNamesWhitelist
;
471 for (const auto& item
: mEnabledFontsList
) {
473 ToLowerCase(item
, key
);
474 familyNamesWhitelist
.Insert(key
);
476 AutoTArray
<fontlist::Family::InitData
, 128> accepted
;
477 bool keptNonHidden
= false;
478 for (auto& f
: aFamilies
) {
479 if (f
.mVisibility
== FontVisibility::Hidden
||
480 familyNamesWhitelist
.Contains(f
.mKey
)) {
481 accepted
.AppendElement(f
);
482 if (f
.mVisibility
!= FontVisibility::Hidden
) {
483 keptNonHidden
= true;
487 if (!keptNonHidden
) {
488 // No (visible) families were whitelisted: ignore the whitelist
489 // and just leave the fontlist unchanged.
492 aFamilies
= std::move(accepted
);
495 bool gfxPlatformFontList::FamilyInList(const nsACString
& aName
,
496 const char* aList
[], size_t aCount
) {
498 return BinarySearchIf(
500 [&](const char* const aVal
) -> int {
501 return nsCaseInsensitiveUTF8StringComparator(
502 aName
.BeginReading(), aVal
, aName
.Length(), strlen(aVal
));
507 void gfxPlatformFontList::CheckFamilyList(const char* aList
[], size_t aCount
) {
509 MOZ_ASSERT(aCount
> 0, "empty font family list?");
510 const char* a
= aList
[0];
511 uint32_t aLen
= strlen(a
);
512 for (size_t i
= 1; i
< aCount
; ++i
) {
513 const char* b
= aList
[i
];
514 uint32_t bLen
= strlen(b
);
515 if (nsCaseInsensitiveUTF8StringComparator(a
, b
, aLen
, bLen
) >= 0) {
516 MOZ_CRASH_UNSAFE_PRINTF("incorrectly sorted font family list: %s >= %s",
525 bool gfxPlatformFontList::AddWithLegacyFamilyName(const nsACString
& aLegacyName
,
526 gfxFontEntry
* aFontEntry
,
527 FontVisibility aVisibility
) {
528 mLock
.AssertCurrentThreadIn();
531 ToLowerCase(aLegacyName
, key
);
533 .LookupOrInsertWith(key
,
535 RefPtr
<gfxFontFamily
> family
=
536 CreateFontFamily(aLegacyName
, aVisibility
);
537 // We don't want the family to search for faces,
538 // we're adding them directly here.
539 family
->SetHasStyles(true);
540 // And we don't want it to attempt to search for
541 // legacy names, because we've already done that
542 // (and this is the result).
543 family
->SetCheckedForLegacyFamilyNames(true);
547 ->AddFontEntry(aFontEntry
->Clone());
551 bool gfxPlatformFontList::InitFontList() {
552 // If the startup font-list-init thread is still running, we need to wait
553 // for it to finish before trying to reinitialize here.
554 if (sInitFontListThread
&& !IsInitFontListThread()) {
555 PR_JoinThread(sInitFontListThread
);
556 sInitFontListThread
= nullptr;
559 AutoLock
lock(mLock
);
561 if (LOG_FONTINIT_ENABLED()) {
562 LOG_FONTINIT(("(fontinit) system fontlist initialization\n"));
565 if (IsInitialized()) {
566 // Font-list reinitialization always occurs on the main thread, in response
567 // to a change notification; it's only the initial creation during startup
568 // that may be on another thread.
569 MOZ_ASSERT(NS_IsMainThread());
571 // Rebuilding fontlist so clear out font/word caches.
572 gfxFontCache
* fontCache
= gfxFontCache::GetCache();
574 fontCache
->FlushShapedWordCaches();
578 gfxPlatform::PurgeSkiaFontCache();
580 // There's no need to broadcast this reflow request to child processes, as
581 // ContentParent::NotifyUpdatedFonts deals with it by re-entering into this
582 // function on child processes.
583 ForceGlobalReflowLocked(gfxPlatform::NeedsReframe::Yes
,
584 gfxPlatform::BroadcastToChildren::No
);
587 mLocalNameTable
.Clear();
588 mIconFontsSet
.Clear();
590 CancelLoadCmapsTask();
591 mStartedLoadingCmapsFrom
= 0xffffffffu
;
593 CancelInitOtherFamilyNamesTask();
594 mFontFamilies
.Clear();
595 mOtherFamilyNames
.Clear();
596 mOtherFamilyNamesInitialized
= false;
599 mExtraNames
->mFullnames
.Clear();
600 mExtraNames
->mPostscriptNames
.Clear();
602 mFaceNameListsInitialized
= false;
603 ClearLangGroupPrefFontsLocked();
606 // Clear cached family records that will no longer be valid.
607 for (auto& f
: mReplacementCharFallbackFamily
) {
611 gfxFontUtils::GetPrefsFontList(kFontSystemWhitelistPref
, mEnabledFontsList
);
612 mFontFamilyWhitelistActive
= !mEnabledFontsList
.IsEmpty();
614 LoadIconFontOverrideList();
617 // From here, gfxPlatformFontList::IsInitialized will return true,
618 // unless InitFontListForPlatform() fails and we reset it below.
619 mFontlistInitCount
++;
621 InitializeCodepointsWithNoFonts();
623 // Try to initialize the cross-process shared font list if enabled by prefs,
624 // but not if we're running in Safe Mode.
625 if (StaticPrefs::gfx_e10s_font_list_shared_AtStartup() &&
626 !gfxPlatform::InSafeMode()) {
627 for (const auto& entry
: mFontEntries
.Values()) {
631 AutoWriteLock
lock(entry
->mLock
);
632 entry
->mShmemCharacterMap
= nullptr;
633 entry
->mShmemFace
= nullptr;
634 entry
->mFamilyName
.Truncate();
636 mFontEntries
.Clear();
637 mShmemCharMaps
.Clear();
638 bool oldSharedList
= mSharedFontList
!= nullptr;
639 mSharedFontList
.reset(new fontlist::FontList(mFontlistInitCount
));
640 InitSharedFontListForPlatform();
641 if (mSharedFontList
&& mSharedFontList
->Initialized()) {
642 if (mLocalNameTable
.Count()) {
643 SharedFontList()->SetLocalNames(mLocalNameTable
);
644 mLocalNameTable
.Clear();
647 // something went wrong, fall back to in-process list
648 gfxCriticalNote
<< "Failed to initialize shared font list, "
649 "falling back to in-process list.";
650 mSharedFontList
.reset(nullptr);
652 if (oldSharedList
&& XRE_IsParentProcess()) {
653 // notify all children of the change
654 if (NS_IsMainThread()) {
655 dom::ContentParent::NotifyUpdatedFonts(true);
657 NS_DispatchToMainThread(NS_NewRunnableFunction(
658 "NotifyUpdatedFonts callback",
659 [] { dom::ContentParent::NotifyUpdatedFonts(true); }));
664 if (!SharedFontList()) {
665 if (NS_FAILED(InitFontListForPlatform())) {
666 mFontlistInitCount
= 0;
672 // Set up mDefaultFontEntry as a "last resort" default that we can use
673 // to avoid crashing if the font list is otherwise unusable.
674 gfxFontStyle defStyle
;
675 FontFamily fam
= GetDefaultFontLocked(nullptr, &defStyle
);
678 auto face
= fam
.mShared
->FindFaceForStyle(SharedFontList(), defStyle
);
679 fe
= face
? GetOrCreateFontEntryLocked(face
, fam
.mShared
) : nullptr;
681 fe
= fam
.mUnshared
->FindFontForStyle(defStyle
);
683 mDefaultFontEntry
= fe
;
688 void gfxPlatformFontList::LoadIconFontOverrideList() {
689 mIconFontsSet
.Clear();
690 AutoTArray
<nsCString
, 20> iconFontsList
;
691 gfxFontUtils::GetPrefsFontList(kIconFontsPref
, iconFontsList
);
692 for (auto& name
: iconFontsList
) {
694 mIconFontsSet
.Insert(name
);
698 void gfxPlatformFontList::InitializeCodepointsWithNoFonts() {
699 auto& first
= mCodepointsWithNoFonts
[FontVisibility(0)];
700 for (auto& bitset
: mCodepointsWithNoFonts
) {
701 if (&bitset
== &first
) {
703 bitset
.SetRange(0, 0x1f); // C0 controls
704 bitset
.SetRange(0x7f, 0x9f); // C1 controls
705 bitset
.SetRange(0xE000, 0xF8FF); // PUA
706 bitset
.SetRange(0xF0000, 0x10FFFD); // Supplementary PUA
707 bitset
.SetRange(0xfdd0, 0xfdef); // noncharacters
708 for (unsigned i
= 0; i
<= 0x100000; i
+= 0x10000) {
709 bitset
.SetRange(i
+ 0xfffe, i
+ 0xffff); // noncharacters
718 void gfxPlatformFontList::FontListChanged() {
719 MOZ_ASSERT(!XRE_IsParentProcess());
720 AutoLock
lock(mLock
);
721 InitializeCodepointsWithNoFonts();
722 if (SharedFontList()) {
723 // If we're using a shared local face-name list, this may have changed
724 // such that existing font entries held by user font sets are no longer
725 // safe to use: ensure they all get flushed.
726 RebuildLocalFonts(/*aForgetLocalFaces*/ true);
728 ForceGlobalReflowLocked(gfxPlatform::NeedsReframe::Yes
);
731 void gfxPlatformFontList::GenerateFontListKey(const nsACString
& aKeyName
,
732 nsACString
& aResult
) {
734 ToLowerCase(aResult
);
737 void gfxPlatformFontList::GenerateFontListKey(nsACString
& aKeyName
) {
738 ToLowerCase(aKeyName
);
741 // Used if a stylo thread wants to trigger InitOtherFamilyNames in the main
742 // process: we can't do IPC from the stylo thread so we post this to the main
744 class InitOtherFamilyNamesForStylo
: public mozilla::Runnable
{
746 explicit InitOtherFamilyNamesForStylo(bool aDeferOtherFamilyNamesLoading
)
747 : Runnable("gfxPlatformFontList::InitOtherFamilyNamesForStylo"),
748 mDefer(aDeferOtherFamilyNamesLoading
) {}
750 NS_IMETHOD
Run() override
{
751 auto pfl
= gfxPlatformFontList::PlatformFontList();
752 auto list
= pfl
->SharedFontList();
756 bool initialized
= false;
757 dom::ContentChild::GetSingleton()->SendInitOtherFamilyNames(
758 list
->GetGeneration(), mDefer
, &initialized
);
759 pfl
->mOtherFamilyNamesInitialized
.compareExchange(false, initialized
);
767 #define OTHERNAMES_TIMEOUT 200
769 bool gfxPlatformFontList::InitOtherFamilyNames(
770 bool aDeferOtherFamilyNamesLoading
) {
771 if (mOtherFamilyNamesInitialized
) {
775 if (SharedFontList() && !XRE_IsParentProcess()) {
776 if (NS_IsMainThread()) {
778 dom::ContentChild::GetSingleton()->SendInitOtherFamilyNames(
779 SharedFontList()->GetGeneration(), aDeferOtherFamilyNamesLoading
,
781 mOtherFamilyNamesInitialized
.compareExchange(false, initialized
);
783 NS_DispatchToMainThread(
784 new InitOtherFamilyNamesForStylo(aDeferOtherFamilyNamesLoading
));
786 return mOtherFamilyNamesInitialized
;
789 // If the font loader delay has been set to zero, we don't defer loading
790 // additional family names (regardless of the aDefer... parameter), as we
791 // take this to mean availability of font info is to be prioritized over
792 // potential startup perf or main-thread jank.
793 // (This is used so we can reliably run reftests that depend on localized
794 // font-family names being available.)
795 if (aDeferOtherFamilyNamesLoading
&&
796 StaticPrefs::gfx_font_loader_delay() > 0) {
797 if (!mPendingOtherFamilyNameTask
) {
798 RefPtr
<mozilla::CancelableRunnable
> task
=
799 new InitOtherFamilyNamesRunnable();
800 mPendingOtherFamilyNameTask
= task
;
801 NS_DispatchToMainThreadQueue(task
.forget(), EventQueuePriority::Idle
);
804 InitOtherFamilyNamesInternal(false);
806 return mOtherFamilyNamesInitialized
;
809 // time limit for loading facename lists (ms)
810 #define NAMELIST_TIMEOUT 200
812 gfxFontEntry
* gfxPlatformFontList::SearchFamiliesForFaceName(
813 const nsACString
& aFaceName
) {
814 TimeStamp start
= TimeStamp::Now();
815 bool timedOut
= false;
816 // if mFirstChar is not 0, only load facenames for families
817 // that start with this character
818 char16_t firstChar
= 0;
819 gfxFontEntry
* lookup
= nullptr;
821 // iterate over familes starting with the same letter
822 firstChar
= ToLowerCase(aFaceName
.CharAt(0));
824 for (const auto& entry
: mFontFamilies
) {
825 nsCStringHashKey::KeyType key
= entry
.GetKey();
826 const RefPtr
<gfxFontFamily
>& family
= entry
.GetData();
828 // when filtering, skip names that don't start with the filter character
829 if (firstChar
&& ToLowerCase(key
.CharAt(0)) != firstChar
) {
833 family
->ReadFaceNames(this, NeedFullnamePostscriptNames());
835 TimeDuration elapsed
= TimeStamp::Now() - start
;
836 if (elapsed
.ToMilliseconds() > NAMELIST_TIMEOUT
) {
842 lookup
= FindFaceName(aFaceName
);
844 TimeStamp end
= TimeStamp::Now();
845 Telemetry::AccumulateTimeDelta(Telemetry::FONTLIST_INITFACENAMELISTS
, start
,
847 if (LOG_FONTINIT_ENABLED()) {
848 TimeDuration elapsed
= end
- start
;
849 LOG_FONTINIT(("(fontinit) SearchFamiliesForFaceName took %8.2f ms %s %s",
850 elapsed
.ToMilliseconds(), (lookup
? "found name" : ""),
851 (timedOut
? "timeout" : "")));
857 gfxFontEntry
* gfxPlatformFontList::FindFaceName(const nsACString
& aFaceName
) {
858 gfxFontEntry
* lookup
;
860 // lookup in name lookup tables, return null if not found
862 ((lookup
= mExtraNames
->mPostscriptNames
.GetWeak(aFaceName
)) ||
863 (lookup
= mExtraNames
->mFullnames
.GetWeak(aFaceName
)))) {
870 gfxFontEntry
* gfxPlatformFontList::LookupInFaceNameLists(
871 const nsACString
& aFaceName
) {
872 gfxFontEntry
* lookup
= nullptr;
874 // initialize facename lookup tables if needed
875 // note: this can terminate early or time out, in which case
876 // mFaceNameListsInitialized remains false
877 if (!mFaceNameListsInitialized
) {
878 lookup
= SearchFamiliesForFaceName(aFaceName
);
884 // lookup in name lookup tables, return null if not found
885 if (!(lookup
= FindFaceName(aFaceName
))) {
886 // names not completely initialized, so keep track of lookup misses
887 if (!mFaceNameListsInitialized
) {
888 if (!mFaceNamesMissed
) {
889 mFaceNamesMissed
= MakeUnique
<nsTHashSet
<nsCString
>>(2);
891 mFaceNamesMissed
->Insert(aFaceName
);
898 gfxFontEntry
* gfxPlatformFontList::LookupInSharedFaceNameList(
899 nsPresContext
* aPresContext
, const nsACString
& aFaceName
,
900 WeightRange aWeightForEntry
, StretchRange aStretchForEntry
,
901 SlantStyleRange aStyleForEntry
) {
902 nsAutoCString
keyName(aFaceName
);
903 ToLowerCase(keyName
);
904 fontlist::FontList
* list
= SharedFontList();
905 fontlist::Family
* family
= nullptr;
906 fontlist::Face
* face
= nullptr;
907 if (list
->NumLocalFaces()) {
908 fontlist::LocalFaceRec
* rec
= list
->FindLocalFace(keyName
);
910 auto* families
= list
->Families();
912 family
= &families
[rec
->mFamilyIndex
];
913 face
= family
->Faces(list
)[rec
->mFaceIndex
].ToPtr
<fontlist::Face
>(list
);
917 list
->SearchForLocalFace(keyName
, &family
, &face
);
919 if (!face
|| !family
) {
922 FontVisibility level
=
923 aPresContext
? aPresContext
->GetFontVisibility() : FontVisibility::User
;
924 if (!IsVisibleToCSS(*family
, level
)) {
926 aPresContext
->ReportBlockedFontFamily(*family
);
930 gfxFontEntry
* fe
= CreateFontEntry(face
, family
);
932 fe
->mIsLocalUserFont
= true;
933 fe
->mWeightRange
= aWeightForEntry
;
934 fe
->mStretchRange
= aStretchForEntry
;
935 fe
->mStyleRange
= aStyleForEntry
;
940 void gfxPlatformFontList::LoadBadUnderlineList() {
941 gfxFontUtils::GetPrefsFontList("font.blacklist.underline_offset",
942 mBadUnderlineFamilyNames
);
943 for (auto& fam
: mBadUnderlineFamilyNames
) {
946 mBadUnderlineFamilyNames
.Compact();
947 mBadUnderlineFamilyNames
.Sort();
950 void gfxPlatformFontList::UpdateFontList(bool aFullRebuild
) {
951 MOZ_ASSERT(NS_IsMainThread());
954 AutoLock
lock(mLock
);
957 // The font list isn't being fully rebuilt, we're just being notified that
958 // character maps have been updated and so font fallback needs to be re-
959 // done. We only care about this if we have previously encountered a
960 // fallback that required cmaps that were not yet available, and so we
961 // asked for the async cmap loader to run.
962 AutoLock
lock(mLock
);
963 if (mStartedLoadingCmapsFrom
!= 0xffffffffu
) {
964 InitializeCodepointsWithNoFonts();
965 mStartedLoadingCmapsFrom
= 0xffffffffu
;
966 ForceGlobalReflowLocked(gfxPlatform::NeedsReframe::No
);
971 bool gfxPlatformFontList::IsVisibleToCSS(const gfxFontFamily
& aFamily
,
972 FontVisibility aVisibility
) const {
973 return aFamily
.Visibility() <= aVisibility
|| IsFontFamilyWhitelistActive();
976 bool gfxPlatformFontList::IsVisibleToCSS(const fontlist::Family
& aFamily
,
977 FontVisibility aVisibility
) const {
978 return aFamily
.Visibility() <= aVisibility
|| IsFontFamilyWhitelistActive();
981 void gfxPlatformFontList::GetFontList(nsAtom
* aLangGroup
,
982 const nsACString
& aGenericFamily
,
983 nsTArray
<nsString
>& aListOfFonts
) {
984 AutoLock
lock(mLock
);
986 if (SharedFontList()) {
987 fontlist::FontList
* list
= SharedFontList();
988 const fontlist::Family
* families
= list
->Families();
990 for (uint32_t i
= 0; i
< list
->NumFamilies(); i
++) {
991 auto& f
= families
[i
];
992 if (!IsVisibleToCSS(f
, FontVisibility::User
) || f
.IsAltLocaleFamily()) {
995 // XXX TODO: filter families for aGenericFamily, if supported by
997 aListOfFonts
.AppendElement(
998 NS_ConvertUTF8toUTF16(list
->LocalizedFamilyName(&f
)));
1004 for (const RefPtr
<gfxFontFamily
>& family
: mFontFamilies
.Values()) {
1005 if (!IsVisibleToCSS(*family
, FontVisibility::User
)) {
1008 if (family
->FilterForFontList(aLangGroup
, aGenericFamily
)) {
1009 nsAutoCString localizedFamilyName
;
1010 family
->LocalizedName(localizedFamilyName
);
1011 aListOfFonts
.AppendElement(NS_ConvertUTF8toUTF16(localizedFamilyName
));
1015 aListOfFonts
.Sort();
1016 aListOfFonts
.Compact();
1019 void gfxPlatformFontList::GetFontFamilyList(
1020 nsTArray
<RefPtr
<gfxFontFamily
>>& aFamilyArray
) {
1021 AutoLock
lock(mLock
);
1022 MOZ_ASSERT(aFamilyArray
.IsEmpty());
1023 // This doesn't use ToArray, because the caller passes an AutoTArray.
1024 aFamilyArray
.SetCapacity(mFontFamilies
.Count());
1025 for (const auto& family
: mFontFamilies
.Values()) {
1026 aFamilyArray
.AppendElement(family
);
1030 already_AddRefed
<gfxFont
> gfxPlatformFontList::SystemFindFontForChar(
1031 nsPresContext
* aPresContext
, uint32_t aCh
, uint32_t aNextCh
,
1032 Script aRunScript
, eFontPresentation aPresentation
,
1033 const gfxFontStyle
* aStyle
, FontVisibility
* aVisibility
) {
1034 AutoLock
lock(mLock
);
1035 FontVisibility level
=
1036 aPresContext
? aPresContext
->GetFontVisibility() : FontVisibility::User
;
1037 MOZ_ASSERT(!mCodepointsWithNoFonts
[level
].test(aCh
),
1038 "don't call for codepoints already known to be unsupported");
1040 // Try to short-circuit font fallback for U+FFFD, used to represent
1041 // encoding errors: just use cached family from last time U+FFFD was seen.
1042 // This helps speed up pages with lots of encoding errors, binary-as-text,
1044 if (aCh
== 0xFFFD) {
1045 gfxFontEntry
* fontEntry
= nullptr;
1046 auto& fallbackFamily
= mReplacementCharFallbackFamily
[level
];
1047 if (fallbackFamily
.mShared
) {
1048 fontlist::Face
* face
=
1049 fallbackFamily
.mShared
->FindFaceForStyle(SharedFontList(), *aStyle
);
1051 fontEntry
= GetOrCreateFontEntryLocked(face
, fallbackFamily
.mShared
);
1052 *aVisibility
= fallbackFamily
.mShared
->Visibility();
1054 } else if (fallbackFamily
.mUnshared
) {
1055 fontEntry
= fallbackFamily
.mUnshared
->FindFontForStyle(*aStyle
);
1056 *aVisibility
= fallbackFamily
.mUnshared
->Visibility();
1059 // this should never fail, as we must have found U+FFFD in order to set
1060 // mReplacementCharFallbackFamily[...] at all, but better play it safe
1061 if (fontEntry
&& fontEntry
->HasCharacter(aCh
)) {
1062 return fontEntry
->FindOrMakeFont(aStyle
);
1066 TimeStamp start
= TimeStamp::Now();
1068 // search commonly available fonts
1070 FontFamily fallbackFamily
;
1071 RefPtr
<gfxFont
> candidate
=
1072 CommonFontFallback(aPresContext
, aCh
, aNextCh
, aRunScript
, aPresentation
,
1073 aStyle
, fallbackFamily
);
1074 RefPtr
<gfxFont
> font
;
1076 if (aPresentation
== eFontPresentation::Any
) {
1077 font
= std::move(candidate
);
1079 bool hasColorGlyph
= candidate
->HasColorGlyphFor(aCh
, aNextCh
);
1080 if (hasColorGlyph
== PrefersColor(aPresentation
)) {
1081 font
= std::move(candidate
);
1086 // If we didn't find a common font, or it was not the preferred type (color
1087 // or monochrome), do system-wide fallback (except for specials).
1088 uint32_t cmapCount
= 0;
1091 font
= GlobalFontFallback(aPresContext
, aCh
, aNextCh
, aRunScript
,
1092 aPresentation
, aStyle
, cmapCount
, fallbackFamily
);
1093 // If the font we found doesn't match the requested type, and we also found
1094 // a candidate above, prefer that one.
1095 if (font
&& aPresentation
!= eFontPresentation::Any
&& candidate
) {
1096 bool hasColorGlyph
= font
->HasColorGlyphFor(aCh
, aNextCh
);
1097 if (hasColorGlyph
!= PrefersColor(aPresentation
)) {
1098 font
= std::move(candidate
);
1102 TimeDuration elapsed
= TimeStamp::Now() - start
;
1104 LogModule
* log
= gfxPlatform::GetLog(eGfxLog_textrun
);
1106 if (MOZ_UNLIKELY(MOZ_LOG_TEST(log
, LogLevel::Warning
))) {
1107 Script script
= intl::UnicodeProperties::GetScriptCode(aCh
);
1108 MOZ_LOG(log
, LogLevel::Warning
,
1109 ("(textrun-systemfallback-%s) char: u+%6.6x "
1110 "script: %d match: [%s]"
1111 " time: %dus cmaps: %d\n",
1112 (common
? "common" : "global"), aCh
, static_cast<int>(script
),
1113 (font
? font
->GetFontEntry()->Name().get() : "<none>"),
1114 int32_t(elapsed
.ToMicroseconds()), cmapCount
));
1117 // no match? add to set of non-matching codepoints
1119 mCodepointsWithNoFonts
[level
].set(aCh
);
1121 *aVisibility
= fallbackFamily
.mShared
1122 ? fallbackFamily
.mShared
->Visibility()
1123 : fallbackFamily
.mUnshared
->Visibility();
1124 if (aCh
== 0xFFFD) {
1125 mReplacementCharFallbackFamily
[level
] = fallbackFamily
;
1129 // track system fallback time
1130 static bool first
= true;
1131 int32_t intElapsed
=
1132 int32_t(first
? elapsed
.ToMilliseconds() : elapsed
.ToMicroseconds());
1133 Telemetry::Accumulate((first
? Telemetry::SYSTEM_FONT_FALLBACK_FIRST
1134 : Telemetry::SYSTEM_FONT_FALLBACK
),
1138 // track the script for which fallback occurred (incremented one make it
1140 Telemetry::Accumulate(Telemetry::SYSTEM_FONT_FALLBACK_SCRIPT
,
1141 int(aRunScript
) + 1);
1143 return font
.forget();
1146 #define NUM_FALLBACK_FONTS 8
1148 already_AddRefed
<gfxFont
> gfxPlatformFontList::CommonFontFallback(
1149 nsPresContext
* aPresContext
, uint32_t aCh
, uint32_t aNextCh
,
1150 Script aRunScript
, eFontPresentation aPresentation
,
1151 const gfxFontStyle
* aMatchStyle
, FontFamily
& aMatchedFamily
) {
1152 AutoTArray
<const char*, NUM_FALLBACK_FONTS
> defaultFallbacks
;
1153 gfxPlatform::GetPlatform()->GetCommonFallbackFonts(
1154 aCh
, aRunScript
, aPresentation
, defaultFallbacks
);
1155 GlobalFontMatch
data(aCh
, aNextCh
, *aMatchStyle
, aPresentation
);
1156 FontVisibility level
=
1157 aPresContext
? aPresContext
->GetFontVisibility() : FontVisibility::User
;
1159 // If a color-emoji presentation is requested, we will check any font found
1160 // to see if it can provide this; if not, we'll remember it as a possible
1161 // candidate but search the remainder of the list for a better choice.
1162 RefPtr
<gfxFont
> candidateFont
;
1163 FontFamily candidateFamily
;
1164 auto check
= [&](gfxFontEntry
* aFontEntry
,
1165 FontFamily aFamily
) -> already_AddRefed
<gfxFont
> {
1166 RefPtr
<gfxFont
> font
= aFontEntry
->FindOrMakeFont(aMatchStyle
);
1167 if (aPresentation
< eFontPresentation::EmojiDefault
||
1168 font
->HasColorGlyphFor(aCh
, aNextCh
)) {
1169 aMatchedFamily
= aFamily
;
1170 return font
.forget();
1172 // We want a color glyph but this font only has monochrome; remember it
1173 // (unless we already have a candidate) but continue to search.
1174 if (!candidateFont
) {
1175 candidateFont
= std::move(font
);
1176 candidateFamily
= aFamily
;
1181 if (SharedFontList()) {
1182 for (const auto name
: defaultFallbacks
) {
1183 fontlist::Family
* family
=
1184 FindSharedFamily(aPresContext
, nsDependentCString(name
));
1185 if (!family
|| !IsVisibleToCSS(*family
, level
)) {
1188 // XXX(jfkthame) Should we fire the async cmap-loader here, or let it
1189 // always do a potential sync initialization of the family?
1190 family
->SearchAllFontsForChar(SharedFontList(), &data
);
1191 if (data
.mBestMatch
) {
1192 RefPtr
<gfxFont
> font
= check(data
.mBestMatch
, FontFamily(family
));
1194 return font
.forget();
1199 for (const auto name
: defaultFallbacks
) {
1200 gfxFontFamily
* fallback
=
1201 FindFamilyByCanonicalName(nsDependentCString(name
));
1202 if (!fallback
|| !IsVisibleToCSS(*fallback
, level
)) {
1205 fallback
->FindFontForChar(&data
);
1206 if (data
.mBestMatch
) {
1207 RefPtr
<gfxFont
> font
= check(data
.mBestMatch
, FontFamily(fallback
));
1209 return font
.forget();
1215 // If we had a candidate that supports the character, but doesn't have the
1216 // desired emoji-style glyph, we'll return it anyhow as nothing better was
1218 if (candidateFont
) {
1219 aMatchedFamily
= candidateFamily
;
1220 return candidateFont
.forget();
1226 already_AddRefed
<gfxFont
> gfxPlatformFontList::GlobalFontFallback(
1227 nsPresContext
* aPresContext
, uint32_t aCh
, uint32_t aNextCh
,
1228 Script aRunScript
, eFontPresentation aPresentation
,
1229 const gfxFontStyle
* aMatchStyle
, uint32_t& aCmapCount
,
1230 FontFamily
& aMatchedFamily
) {
1231 bool useCmaps
= IsFontFamilyWhitelistActive() ||
1232 gfxPlatform::GetPlatform()->UseCmapsDuringSystemFallback();
1233 FontVisibility level
=
1234 aPresContext
? aPresContext
->GetFontVisibility() : FontVisibility::User
;
1236 // Allow platform-specific fallback code to try and find a usable font
1237 gfxFontEntry
* fe
= PlatformGlobalFontFallback(aPresContext
, aCh
, aRunScript
,
1238 aMatchStyle
, aMatchedFamily
);
1240 if (aMatchedFamily
.mShared
) {
1241 if (IsVisibleToCSS(*aMatchedFamily
.mShared
, level
)) {
1242 RefPtr
<gfxFont
> font
= fe
->FindOrMakeFont(aMatchStyle
);
1244 if (aPresentation
== eFontPresentation::Any
) {
1245 return font
.forget();
1247 bool hasColorGlyph
= font
->HasColorGlyphFor(aCh
, aNextCh
);
1248 if (hasColorGlyph
== PrefersColor(aPresentation
)) {
1249 return font
.forget();
1254 if (IsVisibleToCSS(*aMatchedFamily
.mUnshared
, level
)) {
1255 RefPtr
<gfxFont
> font
= fe
->FindOrMakeFont(aMatchStyle
);
1257 if (aPresentation
== eFontPresentation::Any
) {
1258 return font
.forget();
1260 bool hasColorGlyph
= font
->HasColorGlyphFor(aCh
, aNextCh
);
1261 if (hasColorGlyph
== PrefersColor(aPresentation
)) {
1262 return font
.forget();
1270 // otherwise, try to find it among local fonts
1271 GlobalFontMatch
data(aCh
, aNextCh
, *aMatchStyle
, aPresentation
);
1272 if (SharedFontList()) {
1273 fontlist::Family
* families
= SharedFontList()->Families();
1275 for (uint32_t i
= 0; i
< SharedFontList()->NumFamilies(); i
++) {
1276 fontlist::Family
& family
= families
[i
];
1277 if (!IsVisibleToCSS(family
, level
)) {
1280 if (!family
.IsFullyInitialized() &&
1281 StaticPrefs::gfx_font_rendering_fallback_async() &&
1282 !XRE_IsParentProcess()) {
1283 // Start loading all the missing charmaps; but this is async,
1284 // so for now we just continue, ignoring this family.
1285 StartCmapLoadingFromFamily(i
);
1287 family
.SearchAllFontsForChar(SharedFontList(), &data
);
1288 if (data
.mMatchDistance
== 0.0) {
1289 // no better style match is possible, so stop searching
1294 if (data
.mBestMatch
) {
1295 aMatchedFamily
= FontFamily(data
.mMatchedSharedFamily
);
1296 return data
.mBestMatch
->FindOrMakeFont(aMatchStyle
);
1300 // iterate over all font families to find a font that support the
1302 for (const RefPtr
<gfxFontFamily
>& family
: mFontFamilies
.Values()) {
1303 if (!IsVisibleToCSS(*family
, level
)) {
1306 // evaluate all fonts in this family for a match
1307 family
->FindFontForChar(&data
);
1308 if (data
.mMatchDistance
== 0.0) {
1309 // no better style match is possible, so stop searching
1314 aCmapCount
= data
.mCmapsTested
;
1315 if (data
.mBestMatch
) {
1316 aMatchedFamily
= FontFamily(data
.mMatchedFamily
);
1317 return data
.mBestMatch
->FindOrMakeFont(aMatchStyle
);
1324 class StartCmapLoadingRunnable
: public mozilla::Runnable
{
1326 explicit StartCmapLoadingRunnable(uint32_t aStartIndex
)
1327 : Runnable("gfxPlatformFontList::StartCmapLoadingRunnable"),
1328 mStartIndex(aStartIndex
) {}
1330 NS_IMETHOD
Run() override
{
1331 auto* pfl
= gfxPlatformFontList::PlatformFontList();
1332 auto* list
= pfl
->SharedFontList();
1336 if (mStartIndex
>= list
->NumFamilies()) {
1339 if (XRE_IsParentProcess()) {
1340 pfl
->StartCmapLoading(list
->GetGeneration(), mStartIndex
);
1342 dom::ContentChild::GetSingleton()->SendStartCmapLoading(
1343 list
->GetGeneration(), mStartIndex
);
1349 uint32_t mStartIndex
;
1352 void gfxPlatformFontList::StartCmapLoadingFromFamily(uint32_t aStartIndex
) {
1353 AutoLock
lock(mLock
);
1354 if (aStartIndex
>= mStartedLoadingCmapsFrom
) {
1355 // We already initiated cmap-loading from here or earlier in the list;
1356 // no need to do it again here.
1359 mStartedLoadingCmapsFrom
= aStartIndex
;
1361 // If we're already on the main thread, don't bother dispatching a runnable
1362 // here to kick off the loading process, just do it directly.
1363 if (NS_IsMainThread()) {
1364 auto* list
= SharedFontList();
1365 if (XRE_IsParentProcess()) {
1366 StartCmapLoading(list
->GetGeneration(), aStartIndex
);
1368 dom::ContentChild::GetSingleton()->SendStartCmapLoading(
1369 list
->GetGeneration(), aStartIndex
);
1372 NS_DispatchToMainThread(new StartCmapLoadingRunnable(aStartIndex
));
1376 class LoadCmapsRunnable
: public CancelableRunnable
{
1377 class WillShutdownObserver
: public nsIObserver
{
1382 explicit WillShutdownObserver(LoadCmapsRunnable
* aRunnable
)
1383 : mRunnable(aRunnable
) {}
1386 nsCOMPtr
<nsIObserverService
> obs
= services::GetObserverService();
1388 obs
->RemoveObserver(this, NS_XPCOM_WILL_SHUTDOWN_OBSERVER_ID
);
1390 mRunnable
= nullptr;
1394 virtual ~WillShutdownObserver() = default;
1396 LoadCmapsRunnable
* mRunnable
;
1400 explicit LoadCmapsRunnable(uint32_t aGeneration
, uint32_t aFamilyIndex
)
1401 : CancelableRunnable("gfxPlatformFontList::LoadCmapsRunnable"),
1402 mGeneration(aGeneration
),
1403 mStartIndex(aFamilyIndex
),
1404 mIndex(aFamilyIndex
) {
1405 nsCOMPtr
<nsIObserverService
> obs
= services::GetObserverService();
1407 mObserver
= new WillShutdownObserver(this);
1408 obs
->AddObserver(mObserver
, NS_XPCOM_WILL_SHUTDOWN_OBSERVER_ID
, false);
1412 virtual ~LoadCmapsRunnable() {
1414 mObserver
->Remove();
1418 // Reset the current family index, if the value passed is earlier than our
1419 // original starting position. We don't "reset" if it would move the current
1420 // position forward, or back into the already-scanned range.
1421 // We could optimize further by remembering the current position reached,
1422 // and then skipping ahead from the original start, but it doesn't seem worth
1423 // extra complexity for a task that usually only happens once, and already-
1424 // processed families will be skipped pretty quickly in Run() anyhow.
1425 void MaybeResetIndex(uint32_t aFamilyIndex
) {
1426 if (aFamilyIndex
< mStartIndex
) {
1427 mStartIndex
= aFamilyIndex
;
1428 mIndex
= aFamilyIndex
;
1432 nsresult
Cancel() override
{
1437 NS_IMETHOD
Run() override
{
1441 auto* pfl
= gfxPlatformFontList::PlatformFontList();
1442 auto* list
= pfl
->SharedFontList();
1447 if (mGeneration
!= list
->GetGeneration()) {
1450 uint32_t numFamilies
= list
->NumFamilies();
1451 if (mIndex
>= numFamilies
) {
1454 auto* families
= list
->Families();
1455 // Skip any families that are already initialized.
1456 while (mIndex
< numFamilies
&& families
[mIndex
].IsFullyInitialized()) {
1459 // Fully process one family, and advance index.
1460 if (mIndex
< numFamilies
) {
1461 Unused
<< pfl
->InitializeFamily(&families
[mIndex
], true);
1464 // If there are more families to initialize, post ourselves back to the
1465 // idle queue to handle the next one; otherwise we're finished and we need
1466 // to notify content processes to update their rendering.
1467 if (mIndex
< numFamilies
) {
1468 RefPtr
<CancelableRunnable
> task
= this;
1469 NS_DispatchToMainThreadQueue(task
.forget(), EventQueuePriority::Idle
);
1472 pfl
->CancelLoadCmapsTask();
1473 pfl
->InitializeCodepointsWithNoFonts();
1474 dom::ContentParent::NotifyUpdatedFonts(false);
1481 uint32_t mGeneration
;
1482 uint32_t mStartIndex
;
1484 bool mIsCanceled
= false;
1486 RefPtr
<WillShutdownObserver
> mObserver
;
1489 NS_IMPL_ISUPPORTS(LoadCmapsRunnable::WillShutdownObserver
, nsIObserver
)
1492 LoadCmapsRunnable::WillShutdownObserver::Observe(nsISupports
* aSubject
,
1494 const char16_t
* aData
) {
1495 if (!nsCRT::strcmp(aTopic
, NS_XPCOM_WILL_SHUTDOWN_OBSERVER_ID
)) {
1497 mRunnable
->Cancel();
1500 MOZ_ASSERT_UNREACHABLE("unexpected notification topic");
1505 void gfxPlatformFontList::StartCmapLoading(uint32_t aGeneration
,
1506 uint32_t aStartIndex
) {
1507 MOZ_RELEASE_ASSERT(XRE_IsParentProcess());
1508 if (aGeneration
!= SharedFontList()->GetGeneration()) {
1511 if (AppShutdown::IsInOrBeyond(ShutdownPhase::AppShutdownConfirmed
)) {
1514 if (mLoadCmapsRunnable
) {
1515 // We already have a runnable; just make sure it covers the full range of
1517 static_cast<LoadCmapsRunnable
*>(mLoadCmapsRunnable
.get())
1518 ->MaybeResetIndex(aStartIndex
);
1521 mLoadCmapsRunnable
= new LoadCmapsRunnable(aGeneration
, aStartIndex
);
1522 RefPtr
<CancelableRunnable
> task
= mLoadCmapsRunnable
;
1523 NS_DispatchToMainThreadQueue(task
.forget(), EventQueuePriority::Idle
);
1526 gfxFontFamily
* gfxPlatformFontList::CheckFamily(gfxFontFamily
* aFamily
) {
1527 if (aFamily
&& !aFamily
->HasStyles()) {
1528 aFamily
->FindStyleVariations();
1531 if (aFamily
&& aFamily
->FontListLength() == 0) {
1532 // Failed to load any faces for this family, so discard it.
1534 GenerateFontListKey(aFamily
->Name(), key
);
1535 mFontFamilies
.Remove(key
);
1542 bool gfxPlatformFontList::FindAndAddFamilies(
1543 nsPresContext
* aPresContext
, StyleGenericFontFamily aGeneric
,
1544 const nsACString
& aFamily
, nsTArray
<FamilyAndGeneric
>* aOutput
,
1545 FindFamiliesFlags aFlags
, gfxFontStyle
* aStyle
, nsAtom
* aLanguage
,
1546 gfxFloat aDevToCssSize
) {
1547 AutoLock
lock(mLock
);
1550 auto initialLength
= aOutput
->Length();
1554 FindAndAddFamiliesLocked(aPresContext
, aGeneric
, aFamily
, aOutput
, aFlags
,
1555 aStyle
, aLanguage
, aDevToCssSize
);
1557 auto finalLength
= aOutput
->Length();
1558 // Validate the expectation that the output-array grows if we return true,
1559 // or remains the same (probably empty) if we return false.
1560 MOZ_ASSERT_IF(didFind
, finalLength
> initialLength
);
1561 MOZ_ASSERT_IF(!didFind
, finalLength
== initialLength
);
1567 bool gfxPlatformFontList::FindAndAddFamiliesLocked(
1568 nsPresContext
* aPresContext
, StyleGenericFontFamily aGeneric
,
1569 const nsACString
& aFamily
, nsTArray
<FamilyAndGeneric
>* aOutput
,
1570 FindFamiliesFlags aFlags
, gfxFontStyle
* aStyle
, nsAtom
* aLanguage
,
1571 gfxFloat aDevToCssSize
) {
1573 GenerateFontListKey(aFamily
, key
);
1575 bool allowHidden
= bool(aFlags
& FindFamiliesFlags::eSearchHiddenFamilies
);
1576 FontVisibility visibilityLevel
=
1577 aPresContext
? aPresContext
->GetFontVisibility() : FontVisibility::User
;
1579 // If this font lookup is the result of resolving a CSS generic (not a direct
1580 // font-family request by the page), and RFP settings allow generics to be
1581 // unrestricted, bump the effective visibility level applied here so as to
1582 // allow user-installed fonts to be used.
1583 if (visibilityLevel
< FontVisibility::User
&&
1584 aGeneric
!= StyleGenericFontFamily::None
&&
1585 !aPresContext
->Document()->ShouldResistFingerprinting(
1586 RFPTarget::FontVisibilityRestrictGenerics
)) {
1587 visibilityLevel
= FontVisibility::User
;
1590 if (SharedFontList()) {
1591 fontlist::Family
* family
= SharedFontList()->FindFamily(key
);
1592 // If not found, and other family names have not yet been initialized,
1593 // initialize the rest of the list and try again. This is done lazily
1594 // since reading name table entries is expensive.
1595 // Although ASCII localized family names are possible they don't occur
1596 // in practice, so avoid pulling in names at startup.
1597 if (!family
&& !mOtherFamilyNamesInitialized
) {
1598 bool triggerLoading
= true;
1600 !(aFlags
& FindFamiliesFlags::eForceOtherFamilyNamesLoading
);
1602 // If `key` is an ASCII name, only trigger loading if it includes a
1603 // space, and the "base" name (up to the last space) exists as a known
1604 // family, so that this might be a legacy styled-family name.
1605 const char* data
= key
.BeginReading();
1606 int32_t index
= key
.Length();
1607 while (--index
> 0) {
1608 if (data
[index
] == ' ') {
1613 !SharedFontList()->FindFamily(nsAutoCString(key
.get(), index
))) {
1614 triggerLoading
= false;
1617 if (triggerLoading
) {
1618 if (InitOtherFamilyNames(mayDefer
)) {
1619 family
= SharedFontList()->FindFamily(key
);
1622 if (!family
&& !mOtherFamilyNamesInitialized
&&
1623 !(aFlags
& FindFamiliesFlags::eNoAddToNamesMissedWhenSearching
)) {
1624 AddToMissedNames(key
);
1627 // Check whether the family we found is actually allowed to be looked up,
1628 // according to current font-visibility prefs.
1630 bool visible
= IsVisibleToCSS(*family
, visibilityLevel
);
1631 if (visible
|| (allowHidden
&& family
->IsHidden())) {
1632 aOutput
->AppendElement(FamilyAndGeneric(family
, aGeneric
));
1636 aPresContext
->ReportBlockedFontFamily(*family
);
1642 NS_ASSERTION(mFontFamilies
.Count() != 0,
1643 "system font list was not initialized correctly");
1645 auto isBlockedByVisibilityLevel
= [=](gfxFontFamily
* aFamily
) -> bool {
1646 bool visible
= IsVisibleToCSS(*aFamily
, visibilityLevel
);
1647 if (visible
|| (allowHidden
&& aFamily
->IsHidden())) {
1651 aPresContext
->ReportBlockedFontFamily(*aFamily
);
1656 // lookup in canonical (i.e. English) family name list
1657 gfxFontFamily
* familyEntry
= mFontFamilies
.GetWeak(key
);
1659 if (isBlockedByVisibilityLevel(familyEntry
)) {
1664 // if not found, lookup in other family names list (mostly localized names)
1666 familyEntry
= mOtherFamilyNames
.GetWeak(key
);
1669 if (isBlockedByVisibilityLevel(familyEntry
)) {
1674 // if still not found and other family names not yet fully initialized,
1675 // initialize the rest of the list and try again. this is done lazily
1676 // since reading name table entries is expensive.
1677 // although ASCII localized family names are possible they don't occur
1678 // in practice so avoid pulling in names at startup
1679 if (!familyEntry
&& !mOtherFamilyNamesInitialized
&& !IsAscii(aFamily
)) {
1680 InitOtherFamilyNames(
1681 !(aFlags
& FindFamiliesFlags::eForceOtherFamilyNamesLoading
));
1682 familyEntry
= mOtherFamilyNames
.GetWeak(key
);
1683 if (!familyEntry
&& !mOtherFamilyNamesInitialized
&&
1684 !(aFlags
& FindFamiliesFlags::eNoAddToNamesMissedWhenSearching
)) {
1685 // localized family names load timed out, add name to list of
1686 // names to check after localized names are loaded
1687 AddToMissedNames(key
);
1690 if (isBlockedByVisibilityLevel(familyEntry
)) {
1696 familyEntry
= CheckFamily(familyEntry
);
1698 // If we failed to find the requested family, check for a space in the
1699 // name; if found, and if the "base" name (up to the last space) exists
1700 // as a family, then this might be a legacy GDI-style family name for
1701 // an additional weight/width. Try searching the faces of the base family
1702 // and create any corresponding legacy families.
1704 !(aFlags
& FindFamiliesFlags::eNoSearchForLegacyFamilyNames
)) {
1705 // We don't have nsAString::RFindChar, so look for a space manually
1706 const char* data
= aFamily
.BeginReading();
1707 int32_t index
= aFamily
.Length();
1708 while (--index
> 0) {
1709 if (data
[index
] == ' ') {
1714 gfxFontFamily
* base
=
1715 FindUnsharedFamily(aPresContext
, Substring(aFamily
, 0, index
),
1716 FindFamiliesFlags::eNoSearchForLegacyFamilyNames
);
1717 // If we found the "base" family name, and if it has members with
1718 // legacy names, this will add corresponding font-family entries to
1719 // the mOtherFamilyNames list; then retry the legacy-family search.
1720 if (base
&& base
->CheckForLegacyFamilyNames(this)) {
1721 familyEntry
= mOtherFamilyNames
.GetWeak(key
);
1724 if (isBlockedByVisibilityLevel(familyEntry
)) {
1732 aOutput
->AppendElement(FamilyAndGeneric(familyEntry
, aGeneric
));
1739 void gfxPlatformFontList::AddToMissedNames(const nsCString
& aKey
) {
1740 if (!mOtherNamesMissed
) {
1741 mOtherNamesMissed
= MakeUnique
<nsTHashSet
<nsCString
>>(2);
1743 mOtherNamesMissed
->Insert(aKey
);
1746 fontlist::Family
* gfxPlatformFontList::FindSharedFamily(
1747 nsPresContext
* aPresContext
, const nsACString
& aFamily
,
1748 FindFamiliesFlags aFlags
, gfxFontStyle
* aStyle
, nsAtom
* aLanguage
,
1749 gfxFloat aDevToCss
) {
1750 if (!SharedFontList()) {
1753 AutoTArray
<FamilyAndGeneric
, 1> families
;
1754 if (!FindAndAddFamiliesLocked(aPresContext
, StyleGenericFontFamily::None
,
1755 aFamily
, &families
, aFlags
, aStyle
, aLanguage
,
1757 !families
[0].mFamily
.mShared
) {
1760 fontlist::Family
* family
= families
[0].mFamily
.mShared
;
1761 if (!family
->IsInitialized()) {
1762 if (!InitializeFamily(family
)) {
1769 class InitializeFamilyRunnable
: public mozilla::Runnable
{
1771 explicit InitializeFamilyRunnable(uint32_t aFamilyIndex
, bool aLoadCmaps
)
1772 : Runnable("gfxPlatformFontList::InitializeFamilyRunnable"),
1773 mIndex(aFamilyIndex
),
1774 mLoadCmaps(aLoadCmaps
) {}
1776 NS_IMETHOD
Run() override
{
1777 auto list
= gfxPlatformFontList::PlatformFontList()->SharedFontList();
1781 if (mIndex
>= list
->NumFamilies()) {
1782 // Out of range? Maybe the list got reinitialized since this request
1783 // was posted - just ignore it.
1786 dom::ContentChild::GetSingleton()->SendInitializeFamily(
1787 list
->GetGeneration(), mIndex
, mLoadCmaps
);
1796 bool gfxPlatformFontList::InitializeFamily(fontlist::Family
* aFamily
,
1798 MOZ_ASSERT(SharedFontList());
1799 auto list
= SharedFontList();
1800 if (!XRE_IsParentProcess()) {
1801 auto* families
= list
->Families();
1805 uint32_t index
= aFamily
- families
;
1806 if (index
>= list
->NumFamilies()) {
1809 if (NS_IsMainThread()) {
1810 dom::ContentChild::GetSingleton()->SendInitializeFamily(
1811 list
->GetGeneration(), index
, aLoadCmaps
);
1813 NS_DispatchToMainThread(new InitializeFamilyRunnable(index
, aLoadCmaps
));
1815 return aFamily
->IsInitialized();
1818 if (!aFamily
->IsInitialized()) {
1819 // The usual case: we're being asked to populate the face list.
1820 AutoTArray
<fontlist::Face::InitData
, 16> faceList
;
1821 GetFacesInitDataForFamily(aFamily
, faceList
, aLoadCmaps
);
1822 aFamily
->AddFaces(list
, faceList
);
1824 // The family's face list was already initialized, but if aLoadCmaps is
1825 // true we also want to eagerly load character maps. This is used when a
1826 // child process is doing SearchAllFontsForChar, to have the parent load
1827 // all the cmaps at once and reduce IPC traffic (and content-process file
1828 // access overhead, which is crippling for DirectWrite on Windows).
1830 auto* faces
= aFamily
->Faces(list
);
1832 for (size_t i
= 0; i
< aFamily
->NumFaces(); i
++) {
1833 auto* face
= faces
[i
].ToPtr
<fontlist::Face
>(list
);
1834 if (face
&& face
->mCharacterMap
.IsNull()) {
1835 // We don't want to cache this font entry, as the parent will most
1836 // likely never use it again; it's just to populate the charmap for
1837 // the benefit of the child process.
1838 RefPtr
<gfxFontEntry
> fe
= CreateFontEntry(face
, aFamily
);
1848 if (aLoadCmaps
&& aFamily
->IsInitialized()) {
1849 aFamily
->SetupFamilyCharMap(list
);
1852 return aFamily
->IsInitialized();
1855 gfxFontEntry
* gfxPlatformFontList::FindFontForFamily(
1856 nsPresContext
* aPresContext
, const nsACString
& aFamily
,
1857 const gfxFontStyle
* aStyle
) {
1858 AutoLock
lock(mLock
);
1861 GenerateFontListKey(aFamily
, key
);
1863 FontFamily family
= FindFamily(aPresContext
, key
);
1864 if (family
.IsNull()) {
1867 if (family
.mShared
) {
1868 auto face
= family
.mShared
->FindFaceForStyle(SharedFontList(), *aStyle
);
1872 return GetOrCreateFontEntryLocked(face
, family
.mShared
);
1874 return family
.mUnshared
->FindFontForStyle(*aStyle
);
1877 gfxFontEntry
* gfxPlatformFontList::GetOrCreateFontEntryLocked(
1878 fontlist::Face
* aFace
, const fontlist::Family
* aFamily
) {
1880 .LookupOrInsertWith(aFace
,
1881 [=] { return CreateFontEntry(aFace
, aFamily
); })
1885 void gfxPlatformFontList::AddOtherFamilyNames(
1886 gfxFontFamily
* aFamilyEntry
, const nsTArray
<nsCString
>& aOtherFamilyNames
) {
1887 AutoLock
lock(mLock
);
1889 for (const auto& name
: aOtherFamilyNames
) {
1891 GenerateFontListKey(name
, key
);
1893 mOtherFamilyNames
.LookupOrInsertWith(key
, [&] {
1895 ("(fontlist-otherfamily) canonical family: %s, other family: %s\n",
1896 aFamilyEntry
->Name().get(), name
.get()));
1897 if (mBadUnderlineFamilyNames
.ContainsSorted(key
)) {
1898 aFamilyEntry
->SetBadUnderlineFamily();
1900 return RefPtr
{aFamilyEntry
};
1905 void gfxPlatformFontList::AddFullnameLocked(gfxFontEntry
* aFontEntry
,
1906 const nsCString
& aFullname
) {
1907 mExtraNames
->mFullnames
.LookupOrInsertWith(aFullname
, [&] {
1908 LOG_FONTLIST(("(fontlist-fullname) name: %s, fullname: %s\n",
1909 aFontEntry
->Name().get(), aFullname
.get()));
1910 return RefPtr
{aFontEntry
};
1914 void gfxPlatformFontList::AddPostscriptNameLocked(
1915 gfxFontEntry
* aFontEntry
, const nsCString
& aPostscriptName
) {
1916 mExtraNames
->mPostscriptNames
.LookupOrInsertWith(aPostscriptName
, [&] {
1917 LOG_FONTLIST(("(fontlist-postscript) name: %s, psname: %s\n",
1918 aFontEntry
->Name().get(), aPostscriptName
.get()));
1919 return RefPtr
{aFontEntry
};
1923 bool gfxPlatformFontList::GetStandardFamilyName(const nsCString
& aFontName
,
1924 nsACString
& aFamilyName
) {
1925 AutoLock
lock(mLock
);
1926 FontFamily family
= FindFamily(nullptr, aFontName
);
1927 if (family
.IsNull()) {
1930 return GetLocalizedFamilyName(family
, aFamilyName
);
1933 bool gfxPlatformFontList::GetLocalizedFamilyName(const FontFamily
& aFamily
,
1934 nsACString
& aFamilyName
) {
1935 if (aFamily
.mShared
) {
1936 aFamilyName
= SharedFontList()->LocalizedFamilyName(aFamily
.mShared
);
1939 if (aFamily
.mUnshared
) {
1940 aFamily
.mUnshared
->LocalizedName(aFamilyName
);
1943 return false; // leaving the aFamilyName outparam untouched
1946 FamilyAndGeneric
gfxPlatformFontList::GetDefaultFontFamily(
1947 const nsACString
& aLangGroup
, const nsACString
& aGenericFamily
) {
1948 if (NS_WARN_IF(aLangGroup
.IsEmpty()) ||
1949 NS_WARN_IF(aGenericFamily
.IsEmpty())) {
1950 return FamilyAndGeneric();
1953 AutoLock
lock(mLock
);
1955 nsAutoCString value
;
1956 AutoTArray
<nsCString
, 4> names
;
1957 if (mFontPrefs
->LookupNameList(PrefName(aGenericFamily
, aLangGroup
), value
)) {
1958 gfxFontUtils::ParseFontList(value
, names
);
1961 for (const nsCString
& name
: names
) {
1962 FontFamily family
= FindFamily(nullptr, name
);
1963 if (!family
.IsNull()) {
1964 return FamilyAndGeneric(family
);
1968 return FamilyAndGeneric();
1971 ShmemCharMapHashEntry::ShmemCharMapHashEntry(const gfxSparseBitSet
* aCharMap
)
1972 : mList(gfxPlatformFontList::PlatformFontList()->SharedFontList()),
1973 mHash(aCharMap
->GetChecksum()) {
1974 size_t len
= SharedBitSet::RequiredSize(*aCharMap
);
1975 mCharMap
= mList
->Alloc(len
);
1976 SharedBitSet::Create(mCharMap
.ToPtr(mList
, len
), len
, *aCharMap
);
1979 fontlist::Pointer
gfxPlatformFontList::GetShmemCharMapLocked(
1980 const gfxSparseBitSet
* aCmap
) {
1981 auto* entry
= mShmemCharMaps
.GetEntry(aCmap
);
1983 entry
= mShmemCharMaps
.PutEntry(aCmap
);
1985 return entry
->GetCharMap();
1988 // Lookup aCmap in the shared cmap set, adding if not already present.
1989 // This is the only way for a reference to a gfxCharacterMap to be acquired
1990 // by another thread than its original creator.
1991 already_AddRefed
<gfxCharacterMap
> gfxPlatformFontList::FindCharMap(
1992 gfxCharacterMap
* aCmap
) {
1993 // Lock to prevent potentially racing against MaybeRemoveCmap.
1994 AutoLock
lock(mLock
);
1996 // Find existing entry or insert a new one (which will add a reference).
1998 aCmap
->mShared
= true; // Set the shared flag in preparation for adding
1999 // to the global table.
2000 RefPtr cmap
= mSharedCmaps
.PutEntry(aCmap
)->GetKey();
2002 // If we ended up finding a different, pre-existing entry, clear the
2003 // shared flag on this one so that it'll get deleted on Release().
2004 if (cmap
.get() != aCmap
) {
2005 aCmap
->mShared
= false;
2008 return cmap
.forget();
2011 // Potentially remove the charmap from the shared cmap set. This is called
2012 // when a user of the charmap drops a reference and the refcount goes to 1;
2013 // in that case, it is possible our shared set is the only remaining user
2014 // of the object, and we should remove it.
2015 // Note that aCharMap might have already been freed, so we must not try to
2016 // dereference it until we have checked that it's still present in our table.
2017 void gfxPlatformFontList::MaybeRemoveCmap(gfxCharacterMap
* aCharMap
) {
2018 // Lock so that nobody else can get a reference via FindCharMap while we're
2020 AutoLock
lock(mLock
);
2022 // Skip lookups during teardown.
2023 if (!mSharedCmaps
.Count()) {
2027 // aCharMap needs to match the entry and be the same ptr and still have a
2028 // refcount of exactly 1 (i.e. we hold the only reference) before removing.
2029 // If we're racing another thread, it might already have been removed, in
2030 // which case GetEntry will not find it and we won't try to dereference the
2031 // already-freed pointer.
2032 CharMapHashKey
* found
=
2033 mSharedCmaps
.GetEntry(const_cast<gfxCharacterMap
*>(aCharMap
));
2034 if (found
&& found
->GetKey() == aCharMap
&& aCharMap
->RefCount() == 1) {
2035 // Forget our reference to the object that's being deleted, without
2036 // calling Release() on it.
2037 Unused
<< found
->mCharMap
.forget();
2042 // Log this as a "Release" to keep leak-checking correct.
2043 NS_LOG_RELEASE(aCharMap
, 0, "gfxCharacterMap");
2045 mSharedCmaps
.RemoveEntry(found
);
2049 static void GetSystemUIFontFamilies([[maybe_unused
]] nsAtom
* aLangGroup
,
2050 nsTArray
<nsCString
>& aFamilies
) {
2051 // TODO: On macOS, use CTCreateUIFontForLanguage or such thing (though the
2052 // code below ends up using [NSFont systemFontOfSize: 0.0].
2054 gfxFontStyle fontStyle
;
2055 nsAutoString systemFontName
;
2056 if (!LookAndFeel::GetFont(StyleSystemFont::Menu
, systemFontName
, fontStyle
)) {
2059 systemFontName
.Trim("\"'");
2060 CopyUTF16toUTF8(systemFontName
, *aFamilies
.AppendElement());
2063 void gfxPlatformFontList::ResolveGenericFontNames(
2064 nsPresContext
* aPresContext
, StyleGenericFontFamily aGenericType
,
2065 eFontPrefLang aPrefLang
, PrefFontList
* aGenericFamilies
) {
2066 const char* langGroupStr
= GetPrefLangName(aPrefLang
);
2067 const char* generic
= GetGenericName(aGenericType
);
2073 AutoTArray
<nsCString
, 4> genericFamilies
;
2075 // load family for "font.name.generic.lang"
2076 PrefName
prefName(generic
, langGroupStr
);
2077 nsAutoCString value
;
2078 if (mFontPrefs
->LookupName(prefName
, value
)) {
2079 gfxFontUtils::ParseFontList(value
, genericFamilies
);
2082 // load fonts for "font.name-list.generic.lang"
2083 if (mFontPrefs
->LookupNameList(prefName
, value
)) {
2084 gfxFontUtils::ParseFontList(value
, genericFamilies
);
2087 nsAtom
* langGroup
= GetLangGroupForPrefLang(aPrefLang
);
2088 MOZ_ASSERT(langGroup
, "null lang group for pref lang");
2090 if (aGenericType
== StyleGenericFontFamily::SystemUi
) {
2091 GetSystemUIFontFamilies(langGroup
, genericFamilies
);
2094 GetFontFamiliesFromGenericFamilies(
2095 aPresContext
, aGenericType
, genericFamilies
, langGroup
, aGenericFamilies
);
2097 #if 0 // dump out generic mappings
2098 printf("%s ===> ", NamePref(generic
, langGroupStr
).get());
2099 for (uint32_t k
= 0; k
< aGenericFamilies
->Length(); k
++) {
2100 if (k
> 0) printf(", ");
2101 printf("%s", (*aGenericFamilies
)[k
].mIsShared
2102 ? (*aGenericFamilies
)[k
].mShared
->DisplayName().AsString(SharedFontList()).get()
2103 : (*aGenericFamilies
)[k
].mUnshared
->Name().get());
2109 void gfxPlatformFontList::ResolveEmojiFontNames(
2110 nsPresContext
* aPresContext
, PrefFontList
* aGenericFamilies
) {
2111 // emoji preference has no lang name
2112 AutoTArray
<nsCString
, 4> genericFamilies
;
2114 nsAutoCString value
;
2115 if (mFontPrefs
->LookupNameList(PrefName("emoji", ""), value
)) {
2116 gfxFontUtils::ParseFontList(value
, genericFamilies
);
2119 GetFontFamiliesFromGenericFamilies(
2120 aPresContext
, StyleGenericFontFamily::MozEmoji
, genericFamilies
, nullptr,
2124 void gfxPlatformFontList::GetFontFamiliesFromGenericFamilies(
2125 nsPresContext
* aPresContext
, StyleGenericFontFamily aGenericType
,
2126 nsTArray
<nsCString
>& aGenericNameFamilies
, nsAtom
* aLangGroup
,
2127 PrefFontList
* aGenericFamilies
) {
2128 // lookup and add platform fonts uniquely
2129 for (const nsCString
& genericFamily
: aGenericNameFamilies
) {
2130 AutoTArray
<FamilyAndGeneric
, 10> families
;
2131 FindAndAddFamiliesLocked(aPresContext
, aGenericType
, genericFamily
,
2132 &families
, FindFamiliesFlags(0), nullptr,
2134 for (const FamilyAndGeneric
& f
: families
) {
2135 if (!aGenericFamilies
->Contains(f
.mFamily
)) {
2136 aGenericFamilies
->AppendElement(f
.mFamily
);
2142 gfxPlatformFontList::PrefFontList
*
2143 gfxPlatformFontList::GetPrefFontsLangGroupLocked(
2144 nsPresContext
* aPresContext
, StyleGenericFontFamily aGenericType
,
2145 eFontPrefLang aPrefLang
) {
2146 if (aGenericType
== StyleGenericFontFamily::MozEmoji
||
2147 aPrefLang
== eFontPrefLang_Emoji
) {
2148 // Emoji font has no lang
2149 PrefFontList
* prefFonts
= mEmojiPrefFont
.get();
2150 if (MOZ_UNLIKELY(!prefFonts
)) {
2151 prefFonts
= new PrefFontList
;
2152 ResolveEmojiFontNames(aPresContext
, prefFonts
);
2153 mEmojiPrefFont
.reset(prefFonts
);
2158 auto index
= static_cast<size_t>(aGenericType
);
2159 PrefFontList
* prefFonts
= mLangGroupPrefFonts
[aPrefLang
][index
].get();
2160 if (MOZ_UNLIKELY(!prefFonts
)) {
2161 prefFonts
= new PrefFontList
;
2162 ResolveGenericFontNames(aPresContext
, aGenericType
, aPrefLang
, prefFonts
);
2163 mLangGroupPrefFonts
[aPrefLang
][index
].reset(prefFonts
);
2168 void gfxPlatformFontList::AddGenericFonts(
2169 nsPresContext
* aPresContext
, StyleGenericFontFamily aGenericType
,
2170 nsAtom
* aLanguage
, nsTArray
<FamilyAndGeneric
>& aFamilyList
) {
2171 AutoLock
lock(mLock
);
2173 // map lang ==> langGroup
2174 nsAtom
* langGroup
= GetLangGroup(aLanguage
);
2176 // langGroup ==> prefLang
2177 eFontPrefLang prefLang
= GetFontPrefLangFor(langGroup
);
2179 // lookup pref fonts
2180 PrefFontList
* prefFonts
=
2181 GetPrefFontsLangGroupLocked(aPresContext
, aGenericType
, prefLang
);
2183 if (!prefFonts
->IsEmpty()) {
2184 aFamilyList
.SetCapacity(aFamilyList
.Length() + prefFonts
->Length());
2185 for (auto& f
: *prefFonts
) {
2186 aFamilyList
.AppendElement(FamilyAndGeneric(f
, aGenericType
));
2191 static nsAtom
* PrefLangToLangGroups(uint32_t aIndex
) {
2192 // static array here avoids static constructor
2193 static nsAtom
* gPrefLangToLangGroups
[] = {
2194 #define FONT_PREF_LANG(enum_id_, str_, atom_id_) nsGkAtoms::atom_id_
2195 #include "gfxFontPrefLangList.h"
2196 #undef FONT_PREF_LANG
2199 return aIndex
< ArrayLength(gPrefLangToLangGroups
)
2200 ? gPrefLangToLangGroups
[aIndex
]
2201 : nsGkAtoms::Unicode
;
2204 eFontPrefLang
gfxPlatformFontList::GetFontPrefLangFor(const char* aLang
) {
2205 if (!aLang
|| !aLang
[0]) {
2206 return eFontPrefLang_Others
;
2208 for (uint32_t i
= 0; i
< ArrayLength(gPrefLangNames
); ++i
) {
2209 if (!nsCRT::strcasecmp(gPrefLangNames
[i
], aLang
)) {
2210 return eFontPrefLang(i
);
2213 return eFontPrefLang_Others
;
2216 eFontPrefLang
gfxPlatformFontList::GetFontPrefLangFor(nsAtom
* aLang
) {
2217 if (!aLang
) return eFontPrefLang_Others
;
2219 aLang
->ToUTF8String(lang
);
2220 return GetFontPrefLangFor(lang
.get());
2223 nsAtom
* gfxPlatformFontList::GetLangGroupForPrefLang(eFontPrefLang aLang
) {
2224 // the special CJK set pref lang should be resolved into separate
2225 // calls to individual CJK pref langs before getting here
2226 NS_ASSERTION(aLang
!= eFontPrefLang_CJKSet
, "unresolved CJK set pref lang");
2228 return PrefLangToLangGroups(uint32_t(aLang
));
2231 const char* gfxPlatformFontList::GetPrefLangName(eFontPrefLang aLang
) {
2232 if (uint32_t(aLang
) < ArrayLength(gPrefLangNames
)) {
2233 return gPrefLangNames
[uint32_t(aLang
)];
2238 eFontPrefLang
gfxPlatformFontList::GetFontPrefLangFor(uint32_t aCh
) {
2239 switch (ublock_getCode(aCh
)) {
2240 case UBLOCK_BASIC_LATIN
:
2241 case UBLOCK_LATIN_1_SUPPLEMENT
:
2242 case UBLOCK_LATIN_EXTENDED_A
:
2243 case UBLOCK_LATIN_EXTENDED_B
:
2244 case UBLOCK_IPA_EXTENSIONS
:
2245 case UBLOCK_SPACING_MODIFIER_LETTERS
:
2246 case UBLOCK_LATIN_EXTENDED_ADDITIONAL
:
2247 case UBLOCK_LATIN_EXTENDED_C
:
2248 case UBLOCK_LATIN_EXTENDED_D
:
2249 case UBLOCK_LATIN_EXTENDED_E
:
2250 case UBLOCK_PHONETIC_EXTENSIONS
:
2251 return eFontPrefLang_Western
;
2253 case UBLOCK_GREEK_EXTENDED
:
2254 return eFontPrefLang_Greek
;
2255 case UBLOCK_CYRILLIC
:
2256 case UBLOCK_CYRILLIC_SUPPLEMENT
:
2257 case UBLOCK_CYRILLIC_EXTENDED_A
:
2258 case UBLOCK_CYRILLIC_EXTENDED_B
:
2259 case UBLOCK_CYRILLIC_EXTENDED_C
:
2260 return eFontPrefLang_Cyrillic
;
2261 case UBLOCK_ARMENIAN
:
2262 return eFontPrefLang_Armenian
;
2264 return eFontPrefLang_Hebrew
;
2266 case UBLOCK_ARABIC_PRESENTATION_FORMS_A
:
2267 case UBLOCK_ARABIC_PRESENTATION_FORMS_B
:
2268 case UBLOCK_ARABIC_SUPPLEMENT
:
2269 case UBLOCK_ARABIC_EXTENDED_A
:
2270 case UBLOCK_ARABIC_MATHEMATICAL_ALPHABETIC_SYMBOLS
:
2271 return eFontPrefLang_Arabic
;
2272 case UBLOCK_DEVANAGARI
:
2273 case UBLOCK_DEVANAGARI_EXTENDED
:
2274 return eFontPrefLang_Devanagari
;
2275 case UBLOCK_BENGALI
:
2276 return eFontPrefLang_Bengali
;
2277 case UBLOCK_GURMUKHI
:
2278 return eFontPrefLang_Gurmukhi
;
2279 case UBLOCK_GUJARATI
:
2280 return eFontPrefLang_Gujarati
;
2282 return eFontPrefLang_Oriya
;
2284 return eFontPrefLang_Tamil
;
2286 return eFontPrefLang_Telugu
;
2287 case UBLOCK_KANNADA
:
2288 return eFontPrefLang_Kannada
;
2289 case UBLOCK_MALAYALAM
:
2290 return eFontPrefLang_Malayalam
;
2291 case UBLOCK_SINHALA
:
2292 case UBLOCK_SINHALA_ARCHAIC_NUMBERS
:
2293 return eFontPrefLang_Sinhala
;
2295 return eFontPrefLang_Thai
;
2296 case UBLOCK_TIBETAN
:
2297 return eFontPrefLang_Tibetan
;
2298 case UBLOCK_GEORGIAN
:
2299 case UBLOCK_GEORGIAN_SUPPLEMENT
:
2300 case UBLOCK_GEORGIAN_EXTENDED
:
2301 return eFontPrefLang_Georgian
;
2302 case UBLOCK_HANGUL_JAMO
:
2303 case UBLOCK_HANGUL_COMPATIBILITY_JAMO
:
2304 case UBLOCK_HANGUL_SYLLABLES
:
2305 case UBLOCK_HANGUL_JAMO_EXTENDED_A
:
2306 case UBLOCK_HANGUL_JAMO_EXTENDED_B
:
2307 return eFontPrefLang_Korean
;
2308 case UBLOCK_ETHIOPIC
:
2309 case UBLOCK_ETHIOPIC_EXTENDED
:
2310 case UBLOCK_ETHIOPIC_SUPPLEMENT
:
2311 case UBLOCK_ETHIOPIC_EXTENDED_A
:
2312 return eFontPrefLang_Ethiopic
;
2313 case UBLOCK_UNIFIED_CANADIAN_ABORIGINAL_SYLLABICS
:
2314 case UBLOCK_UNIFIED_CANADIAN_ABORIGINAL_SYLLABICS_EXTENDED
:
2315 return eFontPrefLang_Canadian
;
2317 case UBLOCK_KHMER_SYMBOLS
:
2318 return eFontPrefLang_Khmer
;
2319 case UBLOCK_CJK_RADICALS_SUPPLEMENT
:
2320 case UBLOCK_KANGXI_RADICALS
:
2321 case UBLOCK_IDEOGRAPHIC_DESCRIPTION_CHARACTERS
:
2322 case UBLOCK_CJK_SYMBOLS_AND_PUNCTUATION
:
2323 case UBLOCK_HIRAGANA
:
2324 case UBLOCK_KATAKANA
:
2325 case UBLOCK_BOPOMOFO
:
2327 case UBLOCK_BOPOMOFO_EXTENDED
:
2328 case UBLOCK_ENCLOSED_CJK_LETTERS_AND_MONTHS
:
2329 case UBLOCK_CJK_COMPATIBILITY
:
2330 case UBLOCK_CJK_UNIFIED_IDEOGRAPHS_EXTENSION_A
:
2331 case UBLOCK_CJK_UNIFIED_IDEOGRAPHS
:
2332 case UBLOCK_CJK_COMPATIBILITY_IDEOGRAPHS
:
2333 case UBLOCK_CJK_COMPATIBILITY_FORMS
:
2334 case UBLOCK_SMALL_FORM_VARIANTS
:
2335 case UBLOCK_HALFWIDTH_AND_FULLWIDTH_FORMS
:
2336 case UBLOCK_CJK_UNIFIED_IDEOGRAPHS_EXTENSION_B
:
2337 case UBLOCK_CJK_COMPATIBILITY_IDEOGRAPHS_SUPPLEMENT
:
2338 case UBLOCK_KATAKANA_PHONETIC_EXTENSIONS
:
2339 case UBLOCK_CJK_STROKES
:
2340 case UBLOCK_VERTICAL_FORMS
:
2341 case UBLOCK_CJK_UNIFIED_IDEOGRAPHS_EXTENSION_C
:
2342 case UBLOCK_KANA_SUPPLEMENT
:
2343 case UBLOCK_CJK_UNIFIED_IDEOGRAPHS_EXTENSION_D
:
2344 case UBLOCK_CJK_UNIFIED_IDEOGRAPHS_EXTENSION_E
:
2345 case UBLOCK_IDEOGRAPHIC_SYMBOLS_AND_PUNCTUATION
:
2346 case UBLOCK_CJK_UNIFIED_IDEOGRAPHS_EXTENSION_F
:
2347 case UBLOCK_KANA_EXTENDED_A
:
2348 return eFontPrefLang_CJKSet
;
2349 case UBLOCK_MATHEMATICAL_OPERATORS
:
2350 case UBLOCK_MATHEMATICAL_ALPHANUMERIC_SYMBOLS
:
2351 case UBLOCK_MISCELLANEOUS_MATHEMATICAL_SYMBOLS_A
:
2352 case UBLOCK_MISCELLANEOUS_MATHEMATICAL_SYMBOLS_B
:
2353 case UBLOCK_SUPPLEMENTAL_MATHEMATICAL_OPERATORS
:
2354 return eFontPrefLang_Mathematics
;
2356 return eFontPrefLang_Others
;
2360 bool gfxPlatformFontList::IsLangCJK(eFontPrefLang aLang
) {
2362 case eFontPrefLang_Japanese
:
2363 case eFontPrefLang_ChineseTW
:
2364 case eFontPrefLang_ChineseCN
:
2365 case eFontPrefLang_ChineseHK
:
2366 case eFontPrefLang_Korean
:
2367 case eFontPrefLang_CJKSet
:
2374 void gfxPlatformFontList::GetLangPrefs(eFontPrefLang aPrefLangs
[],
2375 uint32_t& aLen
, eFontPrefLang aCharLang
,
2376 eFontPrefLang aPageLang
) {
2377 AutoLock
lock(mLock
);
2378 if (IsLangCJK(aCharLang
)) {
2379 AppendCJKPrefLangs(aPrefLangs
, aLen
, aCharLang
, aPageLang
);
2381 AppendPrefLang(aPrefLangs
, aLen
, aCharLang
);
2384 AppendPrefLang(aPrefLangs
, aLen
, eFontPrefLang_Others
);
2387 void gfxPlatformFontList::AppendCJKPrefLangs(eFontPrefLang aPrefLangs
[],
2389 eFontPrefLang aCharLang
,
2390 eFontPrefLang aPageLang
) {
2391 // prefer the lang specified by the page *if* CJK
2392 if (IsLangCJK(aPageLang
)) {
2393 AppendPrefLang(aPrefLangs
, aLen
, aPageLang
);
2396 // if not set up, set up the default CJK order, based on accept lang
2397 // settings and locale
2398 if (mCJKPrefLangs
.Length() == 0) {
2400 eFontPrefLang tempPrefLangs
[kMaxLenPrefLangList
];
2401 uint32_t tempLen
= 0;
2403 // Add the CJK pref fonts from accept languages, the order should be same
2404 // order. We use gfxFontUtils::GetPrefsFontList to read the list even
2405 // though it's not actually a list of fonts but of lang codes; the format
2407 AutoTArray
<nsCString
, 5> list
;
2408 gfxFontUtils::GetPrefsFontList("intl.accept_languages", list
, true);
2409 for (const auto& lang
: list
) {
2410 eFontPrefLang fpl
= GetFontPrefLangFor(lang
.get());
2412 case eFontPrefLang_Japanese
:
2413 case eFontPrefLang_Korean
:
2414 case eFontPrefLang_ChineseCN
:
2415 case eFontPrefLang_ChineseHK
:
2416 case eFontPrefLang_ChineseTW
:
2417 AppendPrefLang(tempPrefLangs
, tempLen
, fpl
);
2424 // Try using app's locale
2425 nsAutoCString localeStr
;
2426 LocaleService::GetInstance()->GetAppLocaleAsBCP47(localeStr
);
2430 if (LocaleParser::TryParse(localeStr
, locale
).isOk() &&
2431 locale
.Canonicalize().isOk()) {
2432 if (locale
.Language().EqualTo("ja")) {
2433 AppendPrefLang(tempPrefLangs
, tempLen
, eFontPrefLang_Japanese
);
2434 } else if (locale
.Language().EqualTo("zh")) {
2435 if (locale
.Region().EqualTo("CN")) {
2436 AppendPrefLang(tempPrefLangs
, tempLen
, eFontPrefLang_ChineseCN
);
2437 } else if (locale
.Region().EqualTo("TW")) {
2438 AppendPrefLang(tempPrefLangs
, tempLen
, eFontPrefLang_ChineseTW
);
2439 } else if (locale
.Region().EqualTo("HK")) {
2440 AppendPrefLang(tempPrefLangs
, tempLen
, eFontPrefLang_ChineseHK
);
2442 } else if (locale
.Language().EqualTo("ko")) {
2443 AppendPrefLang(tempPrefLangs
, tempLen
, eFontPrefLang_Korean
);
2448 // Then add the known CJK prefs in order of system preferred locales
2449 AutoTArray
<nsCString
, 5> prefLocales
;
2450 prefLocales
.AppendElement("ja"_ns
);
2451 prefLocales
.AppendElement("zh-CN"_ns
);
2452 prefLocales
.AppendElement("zh-TW"_ns
);
2453 prefLocales
.AppendElement("zh-HK"_ns
);
2454 prefLocales
.AppendElement("ko"_ns
);
2456 AutoTArray
<nsCString
, 16> sysLocales
;
2457 AutoTArray
<nsCString
, 16> negLocales
;
2459 OSPreferences::GetInstance()->GetSystemLocales(sysLocales
))) {
2460 LocaleService::GetInstance()->NegotiateLanguages(
2461 sysLocales
, prefLocales
, ""_ns
,
2462 LocaleService::kLangNegStrategyFiltering
, negLocales
);
2463 for (const auto& localeStr
: negLocales
) {
2465 if (LocaleParser::TryParse(localeStr
, locale
).isOk() &&
2466 locale
.Canonicalize().isOk()) {
2467 if (locale
.Language().EqualTo("ja")) {
2468 AppendPrefLang(tempPrefLangs
, tempLen
, eFontPrefLang_Japanese
);
2469 } else if (locale
.Language().EqualTo("zh")) {
2470 if (locale
.Region().EqualTo("CN")) {
2471 AppendPrefLang(tempPrefLangs
, tempLen
, eFontPrefLang_ChineseCN
);
2472 } else if (locale
.Region().EqualTo("TW")) {
2473 AppendPrefLang(tempPrefLangs
, tempLen
, eFontPrefLang_ChineseTW
);
2474 } else if (locale
.Region().EqualTo("HK")) {
2475 AppendPrefLang(tempPrefLangs
, tempLen
, eFontPrefLang_ChineseHK
);
2477 } else if (locale
.Language().EqualTo("ko")) {
2478 AppendPrefLang(tempPrefLangs
, tempLen
, eFontPrefLang_Korean
);
2484 // Last resort... set up CJK font prefs in the order listed by the user-
2485 // configurable ordering pref.
2486 gfxFontUtils::GetPrefsFontList(kCJKFallbackOrderPref
, list
);
2487 for (const auto& item
: list
) {
2488 eFontPrefLang fpl
= GetFontPrefLangFor(item
.get());
2490 case eFontPrefLang_Japanese
:
2491 case eFontPrefLang_Korean
:
2492 case eFontPrefLang_ChineseCN
:
2493 case eFontPrefLang_ChineseHK
:
2494 case eFontPrefLang_ChineseTW
:
2495 AppendPrefLang(tempPrefLangs
, tempLen
, fpl
);
2502 // Truly-last resort... try Chinese font prefs before Japanese because
2503 // they tend to have more complete character coverage, and therefore less
2504 // risk of "ransom-note" effects.
2505 // (If the kCJKFallbackOrderPref was fully populated, as it is by default,
2506 // this will do nothing as all these values are already present.)
2507 AppendPrefLang(tempPrefLangs
, tempLen
, eFontPrefLang_ChineseCN
);
2508 AppendPrefLang(tempPrefLangs
, tempLen
, eFontPrefLang_ChineseHK
);
2509 AppendPrefLang(tempPrefLangs
, tempLen
, eFontPrefLang_ChineseTW
);
2510 AppendPrefLang(tempPrefLangs
, tempLen
, eFontPrefLang_Japanese
);
2511 AppendPrefLang(tempPrefLangs
, tempLen
, eFontPrefLang_Korean
);
2513 // copy into the cached array
2514 for (const auto lang
: Span
<eFontPrefLang
>(tempPrefLangs
, tempLen
)) {
2515 mCJKPrefLangs
.AppendElement(lang
);
2519 // append in cached CJK langs
2520 for (const auto lang
: mCJKPrefLangs
) {
2521 AppendPrefLang(aPrefLangs
, aLen
, eFontPrefLang(lang
));
2525 void gfxPlatformFontList::AppendPrefLang(eFontPrefLang aPrefLangs
[],
2527 eFontPrefLang aAddLang
) {
2528 if (aLen
>= kMaxLenPrefLangList
) {
2532 // If the lang is already present, just ignore the addition.
2533 for (const auto lang
: Span
<eFontPrefLang
>(aPrefLangs
, aLen
)) {
2534 if (lang
== aAddLang
) {
2539 aPrefLangs
[aLen
++] = aAddLang
;
2542 StyleGenericFontFamily
gfxPlatformFontList::GetDefaultGeneric(
2543 eFontPrefLang aLang
) {
2544 if (aLang
== eFontPrefLang_Emoji
) {
2545 return StyleGenericFontFamily::MozEmoji
;
2548 AutoLock
lock(mLock
);
2550 if (uint32_t(aLang
) < ArrayLength(gPrefLangNames
)) {
2551 return mDefaultGenericsLangGroup
[uint32_t(aLang
)];
2553 return StyleGenericFontFamily::Serif
;
2556 FontFamily
gfxPlatformFontList::GetDefaultFont(nsPresContext
* aPresContext
,
2557 const gfxFontStyle
* aStyle
) {
2558 AutoLock
lock(mLock
);
2559 return GetDefaultFontLocked(aPresContext
, aStyle
);
2562 FontFamily
gfxPlatformFontList::GetDefaultFontLocked(
2563 nsPresContext
* aPresContext
, const gfxFontStyle
* aStyle
) {
2564 FontFamily family
= GetDefaultFontForPlatform(aPresContext
, aStyle
);
2565 if (!family
.IsNull()) {
2568 // Something has gone wrong and we were unable to retrieve a default font
2569 // from the platform. (Likely the whitelist has blocked all potential
2570 // default fonts.) As a last resort, we return the first font in our list.
2571 if (SharedFontList()) {
2572 MOZ_RELEASE_ASSERT(SharedFontList()->NumFamilies() > 0);
2573 return FontFamily(SharedFontList()->Families());
2575 MOZ_RELEASE_ASSERT(mFontFamilies
.Count() > 0);
2576 return FontFamily(mFontFamilies
.ConstIter().Data());
2579 void gfxPlatformFontList::GetFontFamilyNames(
2580 nsTArray
<nsCString
>& aFontFamilyNames
) {
2581 if (SharedFontList()) {
2582 fontlist::FontList
* list
= SharedFontList();
2583 const fontlist::Family
* families
= list
->Families();
2585 for (uint32_t i
= 0, n
= list
->NumFamilies(); i
< n
; i
++) {
2586 const fontlist::Family
& family
= families
[i
];
2587 if (!family
.IsHidden()) {
2588 aFontFamilyNames
.AppendElement(family
.DisplayName().AsString(list
));
2593 for (const RefPtr
<gfxFontFamily
>& family
: mFontFamilies
.Values()) {
2594 if (!family
->IsHidden()) {
2595 aFontFamilyNames
.AppendElement(family
->Name());
2601 nsAtom
* gfxPlatformFontList::GetLangGroup(nsAtom
* aLanguage
) {
2602 // map lang ==> langGroup
2603 nsAtom
* langGroup
= nullptr;
2605 langGroup
= mLangService
->GetLanguageGroup(aLanguage
);
2608 langGroup
= nsGkAtoms::Unicode
;
2613 /* static */ const char* gfxPlatformFontList::GetGenericName(
2614 StyleGenericFontFamily aGenericType
) {
2615 // type should be standard generic type at this point
2616 // map generic type to string
2617 switch (aGenericType
) {
2618 case StyleGenericFontFamily::Serif
:
2620 case StyleGenericFontFamily::SansSerif
:
2621 return "sans-serif";
2622 case StyleGenericFontFamily::Monospace
:
2624 case StyleGenericFontFamily::Cursive
:
2626 case StyleGenericFontFamily::Fantasy
:
2628 case StyleGenericFontFamily::SystemUi
:
2630 case StyleGenericFontFamily::MozEmoji
:
2631 return "-moz-emoji";
2632 case StyleGenericFontFamily::None
:
2635 MOZ_ASSERT_UNREACHABLE("Unknown generic");
2639 void gfxPlatformFontList::InitLoader() {
2640 GetFontFamilyNames(mFontInfo
->mFontFamiliesToLoad
);
2642 mNumFamilies
= mFontInfo
->mFontFamiliesToLoad
.Length();
2643 memset(&(mFontInfo
->mLoadStats
), 0, sizeof(mFontInfo
->mLoadStats
));
2646 #define FONT_LOADER_MAX_TIMESLICE \
2647 20 // max time for one pass through RunLoader = 20ms
2649 bool gfxPlatformFontList::LoadFontInfo() {
2650 AutoLock
lock(mLock
);
2651 TimeStamp start
= TimeStamp::Now();
2652 uint32_t i
, endIndex
= mNumFamilies
;
2653 fontlist::FontList
* list
= SharedFontList();
2655 !list
&& (!UsesSystemFallback() ||
2656 gfxPlatform::GetPlatform()->UseCmapsDuringSystemFallback());
2658 // for each font family, load in various font info
2659 for (i
= mStartIndex
; i
< endIndex
; i
++) {
2661 GenerateFontListKey(mFontInfo
->mFontFamiliesToLoad
[i
], key
);
2664 fontlist::Family
* family
= list
->FindFamily(key
);
2668 ReadFaceNamesForFamily(family
, NeedFullnamePostscriptNames());
2670 // lookup in canonical (i.e. English) family name list
2671 gfxFontFamily
* familyEntry
= mFontFamilies
.GetWeak(key
);
2676 // read in face names
2677 familyEntry
->ReadFaceNames(this, NeedFullnamePostscriptNames(),
2680 // load the cmaps if needed
2682 familyEntry
->ReadAllCMAPs(mFontInfo
);
2686 // Limit the time spent reading fonts in one pass, unless the font-loader
2687 // delay was set to zero, in which case we run to completion even if it
2688 // causes some jank.
2689 if (StaticPrefs::gfx_font_loader_delay() > 0) {
2690 TimeDuration elapsed
= TimeStamp::Now() - start
;
2691 if (elapsed
.ToMilliseconds() > FONT_LOADER_MAX_TIMESLICE
&&
2692 i
+ 1 != endIndex
) {
2699 mStartIndex
= endIndex
;
2700 bool done
= mStartIndex
>= mNumFamilies
;
2702 if (LOG_FONTINIT_ENABLED()) {
2703 TimeDuration elapsed
= TimeStamp::Now() - start
;
2704 LOG_FONTINIT(("(fontinit) fontloader load pass %8.2f ms done %s\n",
2705 elapsed
.ToMilliseconds(), (done
? "true" : "false")));
2709 mOtherFamilyNamesInitialized
= true;
2710 CancelInitOtherFamilyNamesTask();
2711 mFaceNameListsInitialized
= true;
2717 void gfxPlatformFontList::CleanupLoader() {
2718 AutoLock
lock(mLock
);
2720 mFontFamiliesToLoad
.Clear();
2722 bool rebuilt
= false, forceReflow
= false;
2724 // if had missed face names that are now available, force reflow all
2725 if (mFaceNamesMissed
) {
2726 rebuilt
= std::any_of(mFaceNamesMissed
->cbegin(), mFaceNamesMissed
->cend(),
2727 [&](const auto& key
) {
2728 mLock
.AssertCurrentThreadIn();
2729 return FindFaceName(key
);
2732 RebuildLocalFonts();
2735 mFaceNamesMissed
= nullptr;
2738 if (mOtherNamesMissed
) {
2739 forceReflow
= std::any_of(
2740 mOtherNamesMissed
->cbegin(), mOtherNamesMissed
->cend(),
2741 [&](const auto& key
) {
2742 mLock
.AssertCurrentThreadIn();
2743 return FindUnsharedFamily(
2745 (FindFamiliesFlags::eForceOtherFamilyNamesLoading
|
2746 FindFamiliesFlags::eNoAddToNamesMissedWhenSearching
));
2749 ForceGlobalReflowLocked(gfxPlatform::NeedsReframe::No
);
2752 mOtherNamesMissed
= nullptr;
2755 if (LOG_FONTINIT_ENABLED() && mFontInfo
) {
2757 ("(fontinit) fontloader load thread took %8.2f ms "
2758 "%d families %d fonts %d cmaps "
2759 "%d facenames %d othernames %s %s",
2760 mLoadTime
.ToMilliseconds(), mFontInfo
->mLoadStats
.families
,
2761 mFontInfo
->mLoadStats
.fonts
, mFontInfo
->mLoadStats
.cmaps
,
2762 mFontInfo
->mLoadStats
.facenames
, mFontInfo
->mLoadStats
.othernames
,
2763 (rebuilt
? "(userfont sets rebuilt)" : ""),
2764 (forceReflow
? "(global reflow)" : "")));
2767 gfxFontInfoLoader::CleanupLoader();
2770 void gfxPlatformFontList::ForceGlobalReflowLocked(
2771 gfxPlatform::NeedsReframe aNeedsReframe
,
2772 gfxPlatform::BroadcastToChildren aBroadcastToChildren
) {
2773 if (!NS_IsMainThread()) {
2774 NS_DispatchToMainThread(NS_NewRunnableFunction(
2775 "gfxPlatformFontList::ForceGlobalReflowLocked",
2776 [aNeedsReframe
, aBroadcastToChildren
] {
2777 gfxPlatform::ForceGlobalReflow(aNeedsReframe
, aBroadcastToChildren
);
2782 AutoUnlock
unlock(mLock
);
2783 gfxPlatform::ForceGlobalReflow(aNeedsReframe
, aBroadcastToChildren
);
2786 void gfxPlatformFontList::GetPrefsAndStartLoader() {
2787 // If we're already in shutdown, there's no point in starting this, and it
2788 // could trigger an assertion if we try to use the Thread Manager too late.
2789 if (AppShutdown::IsInOrBeyond(ShutdownPhase::AppShutdownConfirmed
)) {
2792 uint32_t delay
= std::max(1u, StaticPrefs::gfx_font_loader_delay());
2793 if (NS_IsMainThread()) {
2796 NS_DispatchToMainThread(NS_NewRunnableFunction(
2797 "StartLoader callback", [delay
, fontList
= this] {
2799 fontList
->StartLoader(delay
);
2805 void gfxPlatformFontList::RebuildLocalFonts(bool aForgetLocalFaces
) {
2806 for (auto* fontset
: mUserFontSetList
) {
2807 if (aForgetLocalFaces
) {
2808 fontset
->ForgetLocalFaces();
2810 fontset
->RebuildLocalRules();
2814 void gfxPlatformFontList::ClearLangGroupPrefFontsLocked() {
2815 for (uint32_t i
= eFontPrefLang_First
;
2816 i
< eFontPrefLang_First
+ eFontPrefLang_Count
; i
++) {
2817 auto& prefFontsLangGroup
= mLangGroupPrefFonts
[i
];
2818 for (auto& pref
: prefFontsLangGroup
) {
2822 mCJKPrefLangs
.Clear();
2823 mEmojiPrefFont
= nullptr;
2825 // Create a new FontPrefs and replace the existing one.
2826 mFontPrefs
= MakeUnique
<FontPrefs
>();
2829 // Support for memory reporting
2831 // this is also used by subclasses that hold additional font tables
2833 size_t gfxPlatformFontList::SizeOfFontFamilyTableExcludingThis(
2834 const FontFamilyTable
& aTable
, MallocSizeOf aMallocSizeOf
) {
2835 return std::accumulate(
2836 aTable
.Keys().cbegin(), aTable
.Keys().cend(),
2837 aTable
.ShallowSizeOfExcludingThis(aMallocSizeOf
),
2838 [&](size_t oldValue
, const nsACString
& key
) {
2839 // We don't count the size of the family here, because this is an
2840 // *extra* reference to a family that will have already been counted in
2842 return oldValue
+ key
.SizeOfExcludingThisIfUnshared(aMallocSizeOf
);
2847 size_t gfxPlatformFontList::SizeOfFontEntryTableExcludingThis(
2848 const FontEntryTable
& aTable
, MallocSizeOf aMallocSizeOf
) {
2849 return std::accumulate(
2850 aTable
.Keys().cbegin(), aTable
.Keys().cend(),
2851 aTable
.ShallowSizeOfExcludingThis(aMallocSizeOf
),
2852 [&](size_t oldValue
, const nsACString
& key
) {
2853 // The font itself is counted by its owning family; here we only care
2854 // about the names stored in the hashtable keys.
2856 return oldValue
+ key
.SizeOfExcludingThisIfUnshared(aMallocSizeOf
);
2860 void gfxPlatformFontList::AddSizeOfExcludingThis(MallocSizeOf aMallocSizeOf
,
2861 FontListSizes
* aSizes
) const {
2862 AutoLock
lock(mLock
);
2864 aSizes
->mFontListSize
+=
2865 mFontFamilies
.ShallowSizeOfExcludingThis(aMallocSizeOf
);
2866 for (const auto& entry
: mFontFamilies
) {
2867 aSizes
->mFontListSize
+=
2868 entry
.GetKey().SizeOfExcludingThisIfUnshared(aMallocSizeOf
);
2869 entry
.GetData()->AddSizeOfIncludingThis(aMallocSizeOf
, aSizes
);
2872 aSizes
->mFontListSize
+=
2873 SizeOfFontFamilyTableExcludingThis(mOtherFamilyNames
, aMallocSizeOf
);
2876 aSizes
->mFontListSize
+= SizeOfFontEntryTableExcludingThis(
2877 mExtraNames
->mFullnames
, aMallocSizeOf
);
2878 aSizes
->mFontListSize
+= SizeOfFontEntryTableExcludingThis(
2879 mExtraNames
->mPostscriptNames
, aMallocSizeOf
);
2882 for (uint32_t i
= eFontPrefLang_First
;
2883 i
< eFontPrefLang_First
+ eFontPrefLang_Count
; i
++) {
2884 auto& prefFontsLangGroup
= mLangGroupPrefFonts
[i
];
2885 for (const UniquePtr
<PrefFontList
>& pf
: prefFontsLangGroup
) {
2887 aSizes
->mFontListSize
+= pf
->ShallowSizeOfExcludingThis(aMallocSizeOf
);
2892 for (const auto& bitset
: mCodepointsWithNoFonts
) {
2893 aSizes
->mFontListSize
+= bitset
.SizeOfExcludingThis(aMallocSizeOf
);
2895 aSizes
->mFontListSize
+=
2896 mFontFamiliesToLoad
.ShallowSizeOfExcludingThis(aMallocSizeOf
);
2898 aSizes
->mFontListSize
+=
2899 mBadUnderlineFamilyNames
.ShallowSizeOfExcludingThis(aMallocSizeOf
);
2900 for (const auto& i
: mBadUnderlineFamilyNames
) {
2901 aSizes
->mFontListSize
+= i
.SizeOfExcludingThisIfUnshared(aMallocSizeOf
);
2904 aSizes
->mFontListSize
+=
2905 mSharedCmaps
.ShallowSizeOfExcludingThis(aMallocSizeOf
);
2906 for (const auto& entry
: mSharedCmaps
) {
2907 aSizes
->mCharMapsSize
+= entry
.GetKey()->SizeOfIncludingThis(aMallocSizeOf
);
2910 aSizes
->mFontListSize
+=
2911 mFontEntries
.ShallowSizeOfExcludingThis(aMallocSizeOf
);
2912 for (const auto& entry
: mFontEntries
.Values()) {
2914 entry
->AddSizeOfIncludingThis(aMallocSizeOf
, aSizes
);
2918 if (SharedFontList()) {
2919 aSizes
->mFontListSize
+=
2920 SharedFontList()->SizeOfIncludingThis(aMallocSizeOf
);
2921 if (XRE_IsParentProcess()) {
2922 aSizes
->mSharedSize
+= SharedFontList()->AllocatedShmemSize();
2927 void gfxPlatformFontList::AddSizeOfIncludingThis(MallocSizeOf aMallocSizeOf
,
2928 FontListSizes
* aSizes
) const {
2929 aSizes
->mFontListSize
+= aMallocSizeOf(this);
2930 AddSizeOfExcludingThis(aMallocSizeOf
, aSizes
);
2933 void gfxPlatformFontList::InitOtherFamilyNamesInternal(
2934 bool aDeferOtherFamilyNamesLoading
) {
2935 if (mOtherFamilyNamesInitialized
) {
2939 AutoLock
lock(mLock
);
2941 if (aDeferOtherFamilyNamesLoading
) {
2942 TimeStamp start
= TimeStamp::Now();
2943 bool timedOut
= false;
2945 auto list
= SharedFontList();
2947 // If the gfxFontInfoLoader task is not yet running, kick it off now so
2948 // that it will load remaining names etc as soon as idle time permits.
2949 if (mState
== stateInitial
|| mState
== stateTimerOnDelay
) {
2954 for (const RefPtr
<gfxFontFamily
>& family
: mFontFamilies
.Values()) {
2955 family
->ReadOtherFamilyNames(this);
2956 TimeDuration elapsed
= TimeStamp::Now() - start
;
2957 if (elapsed
.ToMilliseconds() > OTHERNAMES_TIMEOUT
) {
2965 mOtherFamilyNamesInitialized
= true;
2966 CancelInitOtherFamilyNamesTask();
2968 TimeStamp end
= TimeStamp::Now();
2969 Telemetry::AccumulateTimeDelta(Telemetry::FONTLIST_INITOTHERFAMILYNAMES
,
2972 if (LOG_FONTINIT_ENABLED()) {
2973 TimeDuration elapsed
= end
- start
;
2974 LOG_FONTINIT(("(fontinit) InitOtherFamilyNames took %8.2f ms %s",
2975 elapsed
.ToMilliseconds(), (timedOut
? "timeout" : "")));
2978 TimeStamp start
= TimeStamp::Now();
2980 auto list
= SharedFontList();
2982 for (auto& f
: mozilla::Range
<fontlist::Family
>(list
->Families(),
2983 list
->NumFamilies())) {
2984 ReadFaceNamesForFamily(&f
, false);
2987 for (const RefPtr
<gfxFontFamily
>& family
: mFontFamilies
.Values()) {
2988 family
->ReadOtherFamilyNames(this);
2992 mOtherFamilyNamesInitialized
= true;
2993 CancelInitOtherFamilyNamesTask();
2995 TimeStamp end
= TimeStamp::Now();
2996 Telemetry::AccumulateTimeDelta(
2997 Telemetry::FONTLIST_INITOTHERFAMILYNAMES_NO_DEFERRING
, start
, end
);
2999 if (LOG_FONTINIT_ENABLED()) {
3000 TimeDuration elapsed
= end
- start
;
3002 ("(fontinit) InitOtherFamilyNames without deferring took %8.2f ms",
3003 elapsed
.ToMilliseconds()));
3008 void gfxPlatformFontList::CancelInitOtherFamilyNamesTask() {
3009 if (mPendingOtherFamilyNameTask
) {
3010 mPendingOtherFamilyNameTask
->Cancel();
3011 mPendingOtherFamilyNameTask
= nullptr;
3013 auto list
= SharedFontList();
3014 if (list
&& XRE_IsParentProcess()) {
3015 bool forceReflow
= false;
3016 if (!mAliasTable
.IsEmpty()) {
3017 list
->SetAliases(mAliasTable
);
3018 mAliasTable
.Clear();
3021 if (mLocalNameTable
.Count()) {
3022 list
->SetLocalNames(mLocalNameTable
);
3023 mLocalNameTable
.Clear();
3027 dom::ContentParent::BroadcastFontListChanged();
3032 void gfxPlatformFontList::ShareFontListShmBlockToProcess(
3033 uint32_t aGeneration
, uint32_t aIndex
, base::ProcessId aPid
,
3034 base::SharedMemoryHandle
* aOut
) {
3035 auto list
= SharedFontList();
3039 if (!aGeneration
|| list
->GetGeneration() == aGeneration
) {
3040 list
->ShareShmBlockToProcess(aIndex
, aPid
, aOut
);
3042 *aOut
= base::SharedMemory::NULLHandle();
3046 void gfxPlatformFontList::ShareFontListToProcess(
3047 nsTArray
<base::SharedMemoryHandle
>* aBlocks
, base::ProcessId aPid
) {
3048 auto list
= SharedFontList();
3050 list
->ShareBlocksToProcess(aBlocks
, aPid
);
3054 base::SharedMemoryHandle
gfxPlatformFontList::ShareShmBlockToProcess(
3055 uint32_t aIndex
, base::ProcessId aPid
) {
3056 MOZ_RELEASE_ASSERT(SharedFontList());
3057 return SharedFontList()->ShareBlockToProcess(aIndex
, aPid
);
3060 void gfxPlatformFontList::ShmBlockAdded(uint32_t aGeneration
, uint32_t aIndex
,
3061 base::SharedMemoryHandle aHandle
) {
3062 if (SharedFontList()) {
3063 AutoLock
lock(mLock
);
3064 SharedFontList()->ShmBlockAdded(aGeneration
, aIndex
, std::move(aHandle
));
3068 void gfxPlatformFontList::InitializeFamily(uint32_t aGeneration
,
3069 uint32_t aFamilyIndex
,
3071 auto list
= SharedFontList();
3076 if (list
->GetGeneration() != aGeneration
) {
3079 if (AppShutdown::IsInOrBeyond(ShutdownPhase::AppShutdownConfirmed
)) {
3082 if (aFamilyIndex
>= list
->NumFamilies()) {
3085 fontlist::Family
* family
= list
->Families() + aFamilyIndex
;
3086 if (!family
->IsInitialized() || aLoadCmaps
) {
3087 Unused
<< InitializeFamily(family
, aLoadCmaps
);
3091 void gfxPlatformFontList::SetCharacterMap(uint32_t aGeneration
,
3092 uint32_t aFamilyIndex
, bool aAlias
,
3093 uint32_t aFaceIndex
,
3094 const gfxSparseBitSet
& aMap
) {
3095 MOZ_ASSERT(XRE_IsParentProcess());
3096 auto list
= SharedFontList();
3101 if (list
->GetGeneration() != aGeneration
) {
3104 if (AppShutdown::IsInOrBeyond(ShutdownPhase::AppShutdownConfirmed
)) {
3108 const fontlist::Family
* family
;
3110 if (aFamilyIndex
>= list
->NumAliases()) {
3111 MOZ_ASSERT(false, "AliasFamily index out of range");
3114 family
= list
->AliasFamilies() + aFamilyIndex
;
3116 if (aFamilyIndex
>= list
->NumFamilies()) {
3117 MOZ_ASSERT(false, "Family index out of range");
3120 family
= list
->Families() + aFamilyIndex
;
3123 if (aFaceIndex
>= family
->NumFaces()) {
3124 MOZ_ASSERT(false, "Face index out of range");
3129 family
->Faces(list
)[aFaceIndex
].ToPtr
<fontlist::Face
>(list
)) {
3130 face
->mCharacterMap
= GetShmemCharMap(&aMap
);
3134 void gfxPlatformFontList::SetupFamilyCharMap(uint32_t aGeneration
,
3135 uint32_t aIndex
, bool aAlias
) {
3136 MOZ_ASSERT(XRE_IsParentProcess());
3137 auto list
= SharedFontList();
3142 if (list
->GetGeneration() != aGeneration
) {
3145 if (AppShutdown::IsInOrBeyond(ShutdownPhase::AppShutdownConfirmed
)) {
3150 if (aIndex
>= list
->NumAliases()) {
3151 MOZ_ASSERT(false, "AliasFamily index out of range");
3154 list
->AliasFamilies()[aIndex
].SetupFamilyCharMap(list
);
3158 if (aIndex
>= list
->NumFamilies()) {
3159 MOZ_ASSERT(false, "Family index out of range");
3162 list
->Families()[aIndex
].SetupFamilyCharMap(list
);
3165 bool gfxPlatformFontList::InitOtherFamilyNames(uint32_t aGeneration
,
3167 auto list
= SharedFontList();
3172 if (list
->GetGeneration() != aGeneration
) {
3175 if (AppShutdown::IsInOrBeyond(ShutdownPhase::AppShutdownConfirmed
)) {
3178 return InitOtherFamilyNames(aDefer
);
3181 uint32_t gfxPlatformFontList::GetGeneration() const {
3182 return SharedFontList() ? SharedFontList()->GetGeneration() : 0;
3185 gfxPlatformFontList::FontPrefs::FontPrefs() {
3186 // This must be created on the main thread, so that we can safely use the
3187 // Preferences service. Once created, it can be read from any thread.
3188 MOZ_ASSERT(NS_IsMainThread());
3192 void gfxPlatformFontList::FontPrefs::Init() {
3193 if (AppShutdown::IsInOrBeyond(ShutdownPhase::XPCOMShutdownFinal
)) {
3196 nsIPrefBranch
* prefRootBranch
= Preferences::GetRootBranch();
3197 if (!prefRootBranch
) {
3200 nsTArray
<nsCString
> prefNames
;
3201 if (NS_SUCCEEDED(prefRootBranch
->GetChildList(kNamePrefix
, prefNames
))) {
3202 for (auto& prefName
: prefNames
) {
3203 nsAutoCString value
;
3204 if (NS_SUCCEEDED(Preferences::GetCString(prefName
.get(), value
))) {
3205 nsAutoCString
pref(Substring(prefName
, sizeof(kNamePrefix
) - 1));
3206 mFontName
.InsertOrUpdate(pref
, value
);
3210 if (NS_SUCCEEDED(prefRootBranch
->GetChildList(kNameListPrefix
, prefNames
))) {
3211 for (auto& prefName
: prefNames
) {
3212 nsAutoCString value
;
3213 if (NS_SUCCEEDED(Preferences::GetCString(prefName
.get(), value
))) {
3214 nsAutoCString
pref(Substring(prefName
, sizeof(kNameListPrefix
) - 1));
3215 mFontNameList
.InsertOrUpdate(pref
, value
);
3219 mEmojiHasUserValue
= Preferences::HasUserValue("font.name-list.emoji");
3222 bool gfxPlatformFontList::FontPrefs::LookupName(const nsACString
& aPref
,
3223 nsACString
& aValue
) const {
3224 if (const auto& value
= mFontName
.Lookup(aPref
)) {
3231 bool gfxPlatformFontList::FontPrefs::LookupNameList(const nsACString
& aPref
,
3232 nsACString
& aValue
) const {
3233 if (const auto& value
= mFontNameList
.Lookup(aPref
)) {
3240 bool gfxPlatformFontList::IsKnownIconFontFamily(
3241 const nsAtom
* aFamilyName
) const {
3242 nsAtomCString
fam(aFamilyName
);
3244 return mIconFontsSet
.Contains(fam
);