1 /* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 4 -*-
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/intl/LocaleService.h"
8 #include "mozilla/intl/MozLocale.h"
9 #include "mozilla/intl/OSPreferences.h"
11 #include "gfxPlatformFontList.h"
12 #include "gfxTextRun.h"
13 #include "gfxUserFontSet.h"
16 #include "nsGkAtoms.h"
17 #include "nsServiceManagerUtils.h"
18 #include "nsUnicharUtils.h"
19 #include "nsUnicodeRange.h"
20 #include "nsUnicodeProperties.h"
21 #include "nsXULAppAPI.h"
23 #include "mozilla/Attributes.h"
24 #include "mozilla/Likely.h"
25 #include "mozilla/MemoryReporting.h"
26 #include "mozilla/Mutex.h"
27 #include "mozilla/Preferences.h"
28 #include "mozilla/Telemetry.h"
29 #include "mozilla/TimeStamp.h"
30 #include "mozilla/dom/ContentParent.h"
31 #include "mozilla/gfx/2D.h"
35 using namespace mozilla
;
36 using mozilla::intl::LocaleService
;
37 using mozilla::intl::Locale
;
38 using mozilla::intl::OSPreferences
;
40 #define LOG_FONTLIST(args) MOZ_LOG(gfxPlatform::GetLog(eGfxLog_fontlist), \
41 LogLevel::Debug, args)
42 #define LOG_FONTLIST_ENABLED() MOZ_LOG_TEST( \
43 gfxPlatform::GetLog(eGfxLog_fontlist), \
45 #define LOG_FONTINIT(args) MOZ_LOG(gfxPlatform::GetLog(eGfxLog_fontinit), \
46 LogLevel::Debug, args)
47 #define LOG_FONTINIT_ENABLED() MOZ_LOG_TEST( \
48 gfxPlatform::GetLog(eGfxLog_fontinit), \
51 gfxPlatformFontList
*gfxPlatformFontList::sPlatformFontList
= nullptr;
53 // Character ranges that require complex-script shaping support in the font,
54 // and so should be masked out by ReadCMAP if the necessary layout tables
56 // Currently used by the Mac and FT2 implementations only, but probably should
57 // be supported on Windows as well.
58 const gfxFontEntry::ScriptRange
gfxPlatformFontList::sComplexScriptRanges
[] = {
59 // Actually, now that harfbuzz supports presentation-forms shaping for
60 // Arabic, we can render it without layout tables. So maybe we don't
61 // want to mask the basic Arabic block here?
62 // This affects the arabic-fallback-*.html reftests, which rely on
63 // loading a font that *doesn't* have any GSUB table.
64 { 0x0600, 0x06FF, { TRUETYPE_TAG('a','r','a','b'), 0, 0 } },
65 { 0x0700, 0x074F, { TRUETYPE_TAG('s','y','r','c'), 0, 0 } },
66 { 0x0750, 0x077F, { TRUETYPE_TAG('a','r','a','b'), 0, 0 } },
67 { 0x08A0, 0x08FF, { TRUETYPE_TAG('a','r','a','b'), 0, 0 } },
68 { 0x0900, 0x097F, { TRUETYPE_TAG('d','e','v','2'),
69 TRUETYPE_TAG('d','e','v','a'), 0 } },
70 { 0x0980, 0x09FF, { TRUETYPE_TAG('b','n','g','2'),
71 TRUETYPE_TAG('b','e','n','g'), 0 } },
72 { 0x0A00, 0x0A7F, { TRUETYPE_TAG('g','u','r','2'),
73 TRUETYPE_TAG('g','u','r','u'), 0 } },
74 { 0x0A80, 0x0AFF, { TRUETYPE_TAG('g','j','r','2'),
75 TRUETYPE_TAG('g','u','j','r'), 0 } },
76 { 0x0B00, 0x0B7F, { TRUETYPE_TAG('o','r','y','2'),
77 TRUETYPE_TAG('o','r','y','a'), 0 } },
78 { 0x0B80, 0x0BFF, { TRUETYPE_TAG('t','m','l','2'),
79 TRUETYPE_TAG('t','a','m','l'), 0 } },
80 { 0x0C00, 0x0C7F, { TRUETYPE_TAG('t','e','l','2'),
81 TRUETYPE_TAG('t','e','l','u'), 0 } },
82 { 0x0C80, 0x0CFF, { TRUETYPE_TAG('k','n','d','2'),
83 TRUETYPE_TAG('k','n','d','a'), 0 } },
84 { 0x0D00, 0x0D7F, { TRUETYPE_TAG('m','l','m','2'),
85 TRUETYPE_TAG('m','l','y','m'), 0 } },
86 { 0x0D80, 0x0DFF, { TRUETYPE_TAG('s','i','n','h'), 0, 0 } },
87 { 0x0E80, 0x0EFF, { TRUETYPE_TAG('l','a','o',' '), 0, 0 } },
88 { 0x0F00, 0x0FFF, { TRUETYPE_TAG('t','i','b','t'), 0, 0 } },
89 { 0x1000, 0x109f, { TRUETYPE_TAG('m','y','m','r'),
90 TRUETYPE_TAG('m','y','m','2'), 0 } },
91 { 0x1780, 0x17ff, { TRUETYPE_TAG('k','h','m','r'), 0, 0 } },
92 // Khmer Symbols (19e0..19ff) don't seem to need any special shaping
93 { 0xaa60, 0xaa7f, { TRUETYPE_TAG('m','y','m','r'),
94 TRUETYPE_TAG('m','y','m','2'), 0 } },
95 // Thai seems to be "renderable" without AAT morphing tables
96 { 0, 0, { 0, 0, 0 } } // terminator
99 // prefs for the font info loader
100 #define FONT_LOADER_DELAY_PREF "gfx.font_loader.delay"
101 #define FONT_LOADER_INTERVAL_PREF "gfx.font_loader.interval"
103 static const char* kObservedPrefs
[] = {
106 "intl.accept_languages", // hmmmm...
110 static const char kFontSystemWhitelistPref
[] = "font.system.whitelist";
112 // xxx - this can probably be eliminated by reworking pref font handling code
113 static const char *gPrefLangNames
[] = {
114 #define FONT_PREF_LANG(enum_id_, str_, atom_id_) str_
115 #include "gfxFontPrefLangList.h"
116 #undef FONT_PREF_LANG
119 static_assert(MOZ_ARRAY_LENGTH(gPrefLangNames
) == uint32_t(eFontPrefLang_Count
),
120 "size of pref lang name array doesn't match pref lang enum size");
122 class gfxFontListPrefObserver final
: public nsIObserver
{
123 ~gfxFontListPrefObserver() {}
130 FontListPrefChanged(const char* aPref
, void* aData
= nullptr)
132 // XXX this could be made to only clear out the cache for the prefs that were changed
133 // but it probably isn't that big a deal.
134 gfxPlatformFontList::PlatformFontList()->ClearLangGroupPrefFonts();
135 gfxFontCache::GetCache()->AgeAllGenerations();
138 static gfxFontListPrefObserver
* gFontListPrefObserver
= nullptr;
140 NS_IMPL_ISUPPORTS(gfxFontListPrefObserver
, nsIObserver
)
142 #define LOCALES_CHANGED_TOPIC "intl:system-locales-changed"
145 gfxFontListPrefObserver::Observe(nsISupports
*aSubject
,
147 const char16_t
*aData
)
149 NS_ASSERTION(!strcmp(aTopic
, LOCALES_CHANGED_TOPIC
), "invalid topic");
150 FontListPrefChanged(nullptr);
152 if (XRE_IsParentProcess()) {
153 gfxPlatform::ForceGlobalReflow();
158 MOZ_DEFINE_MALLOC_SIZE_OF(FontListMallocSizeOf
)
160 NS_IMPL_ISUPPORTS(gfxPlatformFontList::MemoryReporter
, nsIMemoryReporter
)
163 gfxPlatformFontList::MemoryReporter::CollectReports(
164 nsIHandleReportCallback
* aHandleReport
, nsISupports
* aData
, bool aAnonymize
)
167 sizes
.mFontListSize
= 0;
168 sizes
.mFontTableCacheSize
= 0;
169 sizes
.mCharMapsSize
= 0;
170 sizes
.mLoaderSize
= 0;
172 gfxPlatformFontList::PlatformFontList()->AddSizeOfIncludingThis(&FontListMallocSizeOf
,
176 "explicit/gfx/font-list", KIND_HEAP
, UNITS_BYTES
,
178 "Memory used to manage the list of font families and faces.");
181 "explicit/gfx/font-charmaps", KIND_HEAP
, UNITS_BYTES
,
183 "Memory used to record the character coverage of individual fonts.");
185 if (sizes
.mFontTableCacheSize
) {
187 "explicit/gfx/font-tables", KIND_HEAP
, UNITS_BYTES
,
188 sizes
.mFontTableCacheSize
,
189 "Memory used for cached font metrics and layout tables.");
192 if (sizes
.mLoaderSize
) {
194 "explicit/gfx/font-loader", KIND_HEAP
, UNITS_BYTES
,
196 "Memory used for (platform-specific) font loader.");
202 gfxPlatformFontList::gfxPlatformFontList(bool aNeedFullnamePostscriptNames
)
203 : mFontFamiliesMutex("gfxPlatformFontList::mFontFamiliesMutex"), mFontFamilies(64),
204 mOtherFamilyNames(16), mBadUnderlineFamilyNames(8), mSharedCmaps(8),
205 mStartIndex(0), mNumFamilies(0), mFontlistInitCount(0),
206 mFontFamilyWhitelistActive(false)
208 mOtherFamilyNamesInitialized
= false;
210 if (aNeedFullnamePostscriptNames
) {
211 mExtraNames
= MakeUnique
<ExtraNames
>();
213 mFaceNameListsInitialized
= false;
215 mLangService
= nsLanguageAtomService::GetService();
217 LoadBadUnderlineList();
219 // pref changes notification setup
220 NS_ASSERTION(!gFontListPrefObserver
,
221 "There has been font list pref observer already");
222 gFontListPrefObserver
= new gfxFontListPrefObserver();
223 NS_ADDREF(gFontListPrefObserver
);
225 Preferences::RegisterPrefixCallbacks(FontListPrefChanged
, kObservedPrefs
);
227 nsCOMPtr
<nsIObserverService
> obs
= services::GetObserverService();
229 obs
->AddObserver(gFontListPrefObserver
, LOCALES_CHANGED_TOPIC
, false);
232 // Only the parent process listens for whitelist changes; it will then
233 // notify its children to rebuild their font lists.
234 if (XRE_IsParentProcess()) {
235 Preferences::RegisterCallback(FontWhitelistPrefChanged
,
236 kFontSystemWhitelistPref
);
239 RegisterStrongMemoryReporter(new MemoryReporter());
242 gfxPlatformFontList::~gfxPlatformFontList()
244 mSharedCmaps
.Clear();
245 ClearLangGroupPrefFonts();
246 NS_ASSERTION(gFontListPrefObserver
, "There is no font list pref observer");
248 Preferences::UnregisterPrefixCallbacks(FontListPrefChanged
, kObservedPrefs
);
250 nsCOMPtr
<nsIObserverService
> obs
= services::GetObserverService();
252 obs
->RemoveObserver(gFontListPrefObserver
, LOCALES_CHANGED_TOPIC
);
255 if (XRE_IsParentProcess()) {
256 Preferences::UnregisterCallback(FontWhitelistPrefChanged
,
257 kFontSystemWhitelistPref
);
259 NS_RELEASE(gFontListPrefObserver
);
264 gfxPlatformFontList::FontWhitelistPrefChanged(const char *aPref
,
267 MOZ_ASSERT(XRE_IsParentProcess());
268 gfxPlatformFontList::PlatformFontList()->UpdateFontList();
269 mozilla::dom::ContentParent::NotifyUpdatedFonts();
272 // number of CSS generic font families
273 const uint32_t kNumGenerics
= 5;
276 gfxPlatformFontList::ApplyWhitelist()
278 nsTArray
<nsCString
> list
;
279 gfxFontUtils::GetPrefsFontList(kFontSystemWhitelistPref
, list
);
280 uint32_t numFonts
= list
.Length();
281 mFontFamilyWhitelistActive
= (numFonts
> 0);
282 if (!mFontFamilyWhitelistActive
) {
285 nsTHashtable
<nsCStringHashKey
> familyNamesWhitelist
;
286 for (uint32_t i
= 0; i
< numFonts
; i
++) {
288 ToLowerCase(list
[i
], key
);
289 familyNamesWhitelist
.PutEntry(key
);
291 for (auto iter
= mFontFamilies
.Iter(); !iter
.Done(); iter
.Next()) {
292 // Don't continue if we only have one font left.
293 if (mFontFamilies
.Count() == 1) {
296 nsAutoCString
fontFamilyName(iter
.Key());
297 ToLowerCase(fontFamilyName
);
298 if (!familyNamesWhitelist
.Contains(fontFamilyName
)) {
305 gfxPlatformFontList::AddWithLegacyFamilyName(const nsACString
& aLegacyName
,
306 gfxFontEntry
* aFontEntry
)
310 ToLowerCase(aLegacyName
, key
);
311 gfxFontFamily
* family
= mOtherFamilyNames
.GetWeak(key
);
313 family
= CreateFontFamily(aLegacyName
);
314 family
->SetHasStyles(true); // we don't want the family to search for
315 // faces, we're adding them directly here
316 mOtherFamilyNames
.Put(key
, family
);
319 family
->AddFontEntry(aFontEntry
->Clone());
324 gfxPlatformFontList::InitFontList()
326 mFontlistInitCount
++;
328 if (LOG_FONTINIT_ENABLED()) {
329 LOG_FONTINIT(("(fontinit) system fontlist initialization\n"));
332 // rebuilding fontlist so clear out font/word caches
333 gfxFontCache
*fontCache
= gfxFontCache::GetCache();
335 fontCache
->AgeAllGenerations();
336 fontCache
->FlushShapedWordCaches();
339 gfxPlatform::PurgeSkiaFontCache();
341 CancelInitOtherFamilyNamesTask();
342 MutexAutoLock
lock(mFontFamiliesMutex
);
343 mFontFamilies
.Clear();
344 mOtherFamilyNames
.Clear();
345 mOtherFamilyNamesInitialized
= false;
348 mExtraNames
->mFullnames
.Clear();
349 mExtraNames
->mPostscriptNames
.Clear();
351 mFaceNameListsInitialized
= false;
352 ClearLangGroupPrefFonts();
353 mReplacementCharFallbackFamily
= nullptr;
356 // initialize ranges of characters for which system-wide font search should be skipped
357 mCodepointsWithNoFonts
.reset();
358 mCodepointsWithNoFonts
.SetRange(0,0x1f); // C0 controls
359 mCodepointsWithNoFonts
.SetRange(0x7f,0x9f); // C1 controls
361 sPlatformFontList
= this;
363 nsresult rv
= InitFontListForPlatform();
373 gfxPlatformFontList::GenerateFontListKey(const nsACString
& aKeyName
, nsACString
& aResult
)
376 ToLowerCase(aResult
);
379 #define OTHERNAMES_TIMEOUT 200
382 gfxPlatformFontList::InitOtherFamilyNames(bool aDeferOtherFamilyNamesLoading
)
384 if (mOtherFamilyNamesInitialized
) {
388 // If the font loader delay has been set to zero, we don't defer loading
389 // additional family names (regardless of the aDefer... parameter), as we
390 // take this to mean availability of font info is to be prioritized over
391 // potential startup perf or main-thread jank.
392 // (This is used so we can reliably run reftests that depend on localized
393 // font-family names being available.)
394 if (aDeferOtherFamilyNamesLoading
&&
395 Preferences::GetUint(FONT_LOADER_DELAY_PREF
) > 0) {
396 if (!mPendingOtherFamilyNameTask
) {
397 RefPtr
<mozilla::CancelableRunnable
> task
= new InitOtherFamilyNamesRunnable();
398 mPendingOtherFamilyNameTask
= task
;
399 NS_IdleDispatchToCurrentThread(task
.forget());
402 InitOtherFamilyNamesInternal(false);
406 // time limit for loading facename lists (ms)
407 #define NAMELIST_TIMEOUT 200
410 gfxPlatformFontList::SearchFamiliesForFaceName(const nsACString
& aFaceName
)
412 TimeStamp start
= TimeStamp::Now();
413 bool timedOut
= false;
414 // if mFirstChar is not 0, only load facenames for families
415 // that start with this character
416 char16_t firstChar
= 0;
417 gfxFontEntry
*lookup
= nullptr;
419 // iterate over familes starting with the same letter
420 firstChar
= ToLowerCase(aFaceName
.CharAt(0));
422 for (auto iter
= mFontFamilies
.Iter(); !iter
.Done(); iter
.Next()) {
423 nsCStringHashKey::KeyType key
= iter
.Key();
424 RefPtr
<gfxFontFamily
>& family
= iter
.Data();
426 // when filtering, skip names that don't start with the filter character
427 if (firstChar
&& ToLowerCase(key
.CharAt(0)) != firstChar
) {
431 family
->ReadFaceNames(this, NeedFullnamePostscriptNames());
433 TimeDuration elapsed
= TimeStamp::Now() - start
;
434 if (elapsed
.ToMilliseconds() > NAMELIST_TIMEOUT
) {
440 lookup
= FindFaceName(aFaceName
);
442 TimeStamp end
= TimeStamp::Now();
443 Telemetry::AccumulateTimeDelta(Telemetry::FONTLIST_INITFACENAMELISTS
,
445 if (LOG_FONTINIT_ENABLED()) {
446 TimeDuration elapsed
= end
- start
;
447 LOG_FONTINIT(("(fontinit) SearchFamiliesForFaceName took %8.2f ms %s %s",
448 elapsed
.ToMilliseconds(),
449 (lookup
? "found name" : ""),
450 (timedOut
? "timeout" : "")));
457 gfxPlatformFontList::FindFaceName(const nsACString
& aFaceName
)
459 gfxFontEntry
*lookup
;
461 // lookup in name lookup tables, return null if not found
463 ((lookup
= mExtraNames
->mPostscriptNames
.GetWeak(aFaceName
)) ||
464 (lookup
= mExtraNames
->mFullnames
.GetWeak(aFaceName
)))) {
472 gfxPlatformFontList::LookupInFaceNameLists(const nsACString
& aFaceName
)
474 gfxFontEntry
*lookup
= nullptr;
476 // initialize facename lookup tables if needed
477 // note: this can terminate early or time out, in which case
478 // mFaceNameListsInitialized remains false
479 if (!mFaceNameListsInitialized
) {
480 lookup
= SearchFamiliesForFaceName(aFaceName
);
486 // lookup in name lookup tables, return null if not found
487 if (!(lookup
= FindFaceName(aFaceName
))) {
488 // names not completely initialized, so keep track of lookup misses
489 if (!mFaceNameListsInitialized
) {
490 if (!mFaceNamesMissed
) {
491 mFaceNamesMissed
= MakeUnique
<nsTHashtable
<nsCStringHashKey
>>(2);
493 mFaceNamesMissed
->PutEntry(aFaceName
);
501 gfxPlatformFontList::PreloadNamesList()
503 AutoTArray
<nsCString
, 10> preloadFonts
;
504 gfxFontUtils::GetPrefsFontList("font.preload-names-list", preloadFonts
);
506 uint32_t numFonts
= preloadFonts
.Length();
507 for (uint32_t i
= 0; i
< numFonts
; i
++) {
509 GenerateFontListKey(preloadFonts
[i
], key
);
511 // only search canonical names!
512 gfxFontFamily
*familyEntry
= mFontFamilies
.GetWeak(key
);
514 familyEntry
->ReadOtherFamilyNames(this);
521 gfxPlatformFontList::LoadBadUnderlineList()
523 AutoTArray
<nsCString
, 10> blacklist
;
524 gfxFontUtils::GetPrefsFontList("font.blacklist.underline_offset", blacklist
);
525 uint32_t numFonts
= blacklist
.Length();
526 for (uint32_t i
= 0; i
< numFonts
; i
++) {
528 GenerateFontListKey(blacklist
[i
], key
);
529 mBadUnderlineFamilyNames
.PutEntry(key
);
534 gfxPlatformFontList::UpdateFontList()
541 gfxPlatformFontList::GetFontList(nsAtom
*aLangGroup
,
542 const nsACString
& aGenericFamily
,
543 nsTArray
<nsString
>& aListOfFonts
)
545 MutexAutoLock
lock(mFontFamiliesMutex
);
546 for (auto iter
= mFontFamilies
.Iter(); !iter
.Done(); iter
.Next()) {
547 RefPtr
<gfxFontFamily
>& family
= iter
.Data();
548 if (family
->FilterForFontList(aLangGroup
, aGenericFamily
)) {
549 nsAutoCString localizedFamilyName
;
550 family
->LocalizedName(localizedFamilyName
);
551 aListOfFonts
.AppendElement(NS_ConvertUTF8toUTF16(localizedFamilyName
));
556 aListOfFonts
.Compact();
560 gfxPlatformFontList::GetFontFamilyList(nsTArray
<RefPtr
<gfxFontFamily
> >& aFamilyArray
)
562 for (auto iter
= mFontFamilies
.Iter(); !iter
.Done(); iter
.Next()) {
563 RefPtr
<gfxFontFamily
>& family
= iter
.Data();
564 aFamilyArray
.AppendElement(family
);
569 gfxPlatformFontList::SystemFindFontForChar(uint32_t aCh
, uint32_t aNextCh
,
571 const gfxFontStyle
* aStyle
)
573 gfxFontEntry
* fontEntry
= nullptr;
575 // is codepoint with no matching font? return null immediately
576 if (mCodepointsWithNoFonts
.test(aCh
)) {
580 // Try to short-circuit font fallback for U+FFFD, used to represent
581 // encoding errors: just use cached family from last time U+FFFD was seen.
582 // This helps speed up pages with lots of encoding errors, binary-as-text,
584 if (aCh
== 0xFFFD && mReplacementCharFallbackFamily
) {
586 mReplacementCharFallbackFamily
->FindFontForStyle(*aStyle
);
588 // this should never fail, as we must have found U+FFFD in order to set
589 // mReplacementCharFallbackFamily at all, but better play it safe
590 if (fontEntry
&& fontEntry
->HasCharacter(aCh
)) {
595 TimeStamp start
= TimeStamp::Now();
597 // search commonly available fonts
599 gfxFontFamily
*fallbackFamily
= nullptr;
600 fontEntry
= CommonFontFallback(aCh
, aNextCh
, aRunScript
, aStyle
,
603 // if didn't find a font, do system-wide fallback (except for specials)
604 uint32_t cmapCount
= 0;
607 fontEntry
= GlobalFontFallback(aCh
, aRunScript
, aStyle
, cmapCount
,
610 TimeDuration elapsed
= TimeStamp::Now() - start
;
612 LogModule
* log
= gfxPlatform::GetLog(eGfxLog_textrun
);
614 if (MOZ_UNLIKELY(MOZ_LOG_TEST(log
, LogLevel::Warning
))) {
615 uint32_t unicodeRange
= FindCharUnicodeRange(aCh
);
616 Script script
= mozilla::unicode::GetScriptCode(aCh
);
617 MOZ_LOG(log
, LogLevel::Warning
,\
618 ("(textrun-systemfallback-%s) char: u+%6.6x "
619 "unicode-range: %d script: %d match: [%s]"
620 " time: %dus cmaps: %d\n",
621 (common
? "common" : "global"), aCh
,
622 unicodeRange
, static_cast<int>(script
),
623 (fontEntry
? fontEntry
->Name().get() :
625 int32_t(elapsed
.ToMicroseconds()),
629 // no match? add to set of non-matching codepoints
631 mCodepointsWithNoFonts
.set(aCh
);
632 } else if (aCh
== 0xFFFD && fontEntry
&& fallbackFamily
) {
633 mReplacementCharFallbackFamily
= fallbackFamily
;
636 // track system fallback time
637 static bool first
= true;
638 int32_t intElapsed
= int32_t(first
? elapsed
.ToMilliseconds() :
639 elapsed
.ToMicroseconds());
640 Telemetry::Accumulate((first
? Telemetry::SYSTEM_FONT_FALLBACK_FIRST
:
641 Telemetry::SYSTEM_FONT_FALLBACK
),
645 // track the script for which fallback occurred (incremented one make it
647 Telemetry::Accumulate(Telemetry::SYSTEM_FONT_FALLBACK_SCRIPT
,
648 int(aRunScript
) + 1);
653 #define NUM_FALLBACK_FONTS 8
656 gfxPlatformFontList::CommonFontFallback(uint32_t aCh
, uint32_t aNextCh
,
658 const gfxFontStyle
* aMatchStyle
,
659 gfxFontFamily
** aMatchedFamily
)
661 AutoTArray
<const char*,NUM_FALLBACK_FONTS
> defaultFallbacks
;
662 uint32_t i
, numFallbacks
;
664 gfxPlatform::GetPlatform()->GetCommonFallbackFonts(aCh
, aNextCh
,
667 numFallbacks
= defaultFallbacks
.Length();
668 for (i
= 0; i
< numFallbacks
; i
++) {
669 nsAutoCString
familyName(defaultFallbacks
[i
]);
670 gfxFontFamily
*fallback
= FindFamilyByCanonicalName(familyName
);
675 gfxFontEntry
*fontEntry
;
677 // use first font in list that supports a given character
678 fontEntry
= fallback
->FindFontForStyle(*aMatchStyle
);
680 if (fontEntry
->HasCharacter(aCh
)) {
681 *aMatchedFamily
= fallback
;
684 // If we requested a styled font (bold and/or italic), and the char
685 // was not available, check other faces of the family.
686 if (!fontEntry
->IsNormalStyle()) {
687 // If style/weight/stretch was not Normal, see if we can
688 // fall back to a next-best face (e.g. Arial Black -> Bold,
689 // or Arial Narrow -> Regular).
690 GlobalFontMatch
data(aCh
, *aMatchStyle
);
691 fallback
->SearchAllFontsForChar(&data
);
692 if (data
.mBestMatch
) {
693 *aMatchedFamily
= fallback
;
694 return data
.mBestMatch
;
704 gfxPlatformFontList::GlobalFontFallback(const uint32_t aCh
,
706 const gfxFontStyle
* aMatchStyle
,
707 uint32_t& aCmapCount
,
708 gfxFontFamily
** aMatchedFamily
)
710 bool useCmaps
= IsFontFamilyWhitelistActive() ||
711 gfxPlatform::GetPlatform()->UseCmapsDuringSystemFallback();
713 // Allow platform-specific fallback code to try and find a usable font
715 PlatformGlobalFontFallback(aCh
, aRunScript
, aMatchStyle
,
722 // otherwise, try to find it among local fonts
723 GlobalFontMatch
data(aCh
, *aMatchStyle
);
725 // iterate over all font families to find a font that support the character
726 for (auto iter
= mFontFamilies
.Iter(); !iter
.Done(); iter
.Next()) {
727 RefPtr
<gfxFontFamily
>& family
= iter
.Data();
728 // evaluate all fonts in this family for a match
729 family
->FindFontForChar(&data
);
732 aCmapCount
= data
.mCmapsTested
;
733 *aMatchedFamily
= data
.mMatchedFamily
;
735 return data
.mBestMatch
;
739 gfxPlatformFontList::CheckFamily(gfxFontFamily
*aFamily
)
741 if (aFamily
&& !aFamily
->HasStyles()) {
742 aFamily
->FindStyleVariations();
743 aFamily
->CheckForSimpleFamily();
746 if (aFamily
&& aFamily
->GetFontList().Length() == 0) {
747 // failed to load any faces for this family, so discard it
749 GenerateFontListKey(aFamily
->Name(), key
);
750 mFontFamilies
.Remove(key
);
758 gfxPlatformFontList::FindAndAddFamilies(const nsACString
& aFamily
,
759 nsTArray
<FamilyAndGeneric
>* aOutput
,
760 FindFamiliesFlags aFlags
,
761 gfxFontStyle
* aStyle
,
762 gfxFloat aDevToCssSize
)
765 GenerateFontListKey(aFamily
, key
);
767 NS_ASSERTION(mFontFamilies
.Count() != 0, "system font list was not initialized correctly");
769 // lookup in canonical (i.e. English) family name list
770 gfxFontFamily
*familyEntry
= mFontFamilies
.GetWeak(key
);
772 // if not found, lookup in other family names list (mostly localized names)
774 familyEntry
= mOtherFamilyNames
.GetWeak(key
);
777 // if still not found and other family names not yet fully initialized,
778 // initialize the rest of the list and try again. this is done lazily
779 // since reading name table entries is expensive.
780 // although ASCII localized family names are possible they don't occur
781 // in practice so avoid pulling in names at startup
782 if (!familyEntry
&& !mOtherFamilyNamesInitialized
&& !IsASCII(aFamily
)) {
783 InitOtherFamilyNames(!(aFlags
& FindFamiliesFlags::eForceOtherFamilyNamesLoading
));
784 familyEntry
= mOtherFamilyNames
.GetWeak(key
);
785 if (!familyEntry
&& !mOtherFamilyNamesInitialized
&&
786 !(aFlags
& FindFamiliesFlags::eNoAddToNamesMissedWhenSearching
)) {
787 // localized family names load timed out, add name to list of
788 // names to check after localized names are loaded
789 if (!mOtherNamesMissed
) {
790 mOtherNamesMissed
= MakeUnique
<nsTHashtable
<nsCStringHashKey
>>(2);
792 mOtherNamesMissed
->PutEntry(key
);
796 familyEntry
= CheckFamily(familyEntry
);
798 // If we failed to find the requested family, check for a space in the
799 // name; if found, and if the "base" name (up to the last space) exists
800 // as a family, then this might be a legacy GDI-style family name for
801 // an additional weight/width. Try searching the faces of the base family
802 // and create any corresponding legacy families.
803 if (!familyEntry
&& !(aFlags
& FindFamiliesFlags::eNoSearchForLegacyFamilyNames
)) {
804 // We don't have nsAString::RFindChar, so look for a space manually
805 const char* data
= aFamily
.BeginReading();
806 int32_t index
= aFamily
.Length();
807 while (--index
> 0) {
808 if (data
[index
] == ' ') {
813 gfxFontFamily
* base
=
814 FindFamily(Substring(aFamily
, 0, index
),
815 FindFamiliesFlags::eNoSearchForLegacyFamilyNames
);
816 // If we found the "base" family name, and if it has members with
817 // legacy names, this will add corresponding font-family entries to
818 // the mOtherFamilyNames list; then retry the legacy-family search.
819 if (base
&& base
->CheckForLegacyFamilyNames(this)) {
820 familyEntry
= mOtherFamilyNames
.GetWeak(key
);
826 aOutput
->AppendElement(FamilyAndGeneric(familyEntry
));
834 gfxPlatformFontList::FindFontForFamily(const nsACString
& aFamily
,
835 const gfxFontStyle
* aStyle
)
837 gfxFontFamily
*familyEntry
= FindFamily(aFamily
);
840 return familyEntry
->FindFontForStyle(*aStyle
);
846 gfxPlatformFontList::AddOtherFamilyName(gfxFontFamily
*aFamilyEntry
, nsCString
& aOtherFamilyName
)
849 GenerateFontListKey(aOtherFamilyName
, key
);
851 if (!mOtherFamilyNames
.GetWeak(key
)) {
852 mOtherFamilyNames
.Put(key
, aFamilyEntry
);
853 LOG_FONTLIST(("(fontlist-otherfamily) canonical family: %s, "
854 "other family: %s\n",
855 aFamilyEntry
->Name().get(),
856 aOtherFamilyName
.get()));
857 if (mBadUnderlineFamilyNames
.Contains(key
))
858 aFamilyEntry
->SetBadUnderlineFamily();
863 gfxPlatformFontList::AddFullname(gfxFontEntry
*aFontEntry
, const nsCString
& aFullname
)
865 if (!mExtraNames
->mFullnames
.GetWeak(aFullname
)) {
866 mExtraNames
->mFullnames
.Put(aFullname
, aFontEntry
);
867 LOG_FONTLIST(("(fontlist-fullname) name: %s, fullname: %s\n",
868 aFontEntry
->Name().get(),
874 gfxPlatformFontList::AddPostscriptName(gfxFontEntry
*aFontEntry
,
875 const nsCString
& aPostscriptName
)
877 if (!mExtraNames
->mPostscriptNames
.GetWeak(aPostscriptName
)) {
878 mExtraNames
->mPostscriptNames
.Put(aPostscriptName
, aFontEntry
);
879 LOG_FONTLIST(("(fontlist-postscript) name: %s, psname: %s\n",
880 aFontEntry
->Name().get(),
881 aPostscriptName
.get()));
886 gfxPlatformFontList::GetStandardFamilyName(const nsCString
& aFontName
,
887 nsACString
& aFamilyName
)
889 aFamilyName
.Truncate();
890 gfxFontFamily
*ff
= FindFamily(aFontName
);
894 aFamilyName
= ff
->Name();
899 gfxPlatformFontList::GetDefaultFontFamily(const nsACString
& aLangGroup
,
900 const nsACString
& aGenericFamily
)
902 if (NS_WARN_IF(aLangGroup
.IsEmpty()) ||
903 NS_WARN_IF(aGenericFamily
.IsEmpty())) {
907 AutoTArray
<nsCString
,4> names
;
908 gfxFontUtils::AppendPrefsFontList(
909 NameListPref(aGenericFamily
, aLangGroup
).get(), names
);
911 for (const nsCString
& name
: names
) {
912 gfxFontFamily
* fontFamily
= FindFamily(name
);
921 gfxPlatformFontList::FindCharMap(gfxCharacterMap
*aCmap
)
924 gfxCharacterMap
*cmap
= AddCmap(aCmap
);
925 cmap
->mShared
= true;
929 // add a cmap to the shared cmap set
931 gfxPlatformFontList::AddCmap(const gfxCharacterMap
* aCharMap
)
933 CharMapHashKey
*found
=
934 mSharedCmaps
.PutEntry(const_cast<gfxCharacterMap
*>(aCharMap
));
935 return found
->GetKey();
938 // remove the cmap from the shared cmap set
940 gfxPlatformFontList::RemoveCmap(const gfxCharacterMap
* aCharMap
)
942 // skip lookups during teardown
943 if (mSharedCmaps
.Count() == 0) {
947 // cmap needs to match the entry *and* be the same ptr before removing
948 CharMapHashKey
*found
=
949 mSharedCmaps
.GetEntry(const_cast<gfxCharacterMap
*>(aCharMap
));
950 if (found
&& found
->GetKey() == aCharMap
) {
951 mSharedCmaps
.RemoveEntry(found
);
956 gfxPlatformFontList::ResolveGenericFontNames(
957 FontFamilyType aGenericType
,
958 eFontPrefLang aPrefLang
,
959 nsTArray
<RefPtr
<gfxFontFamily
>>* aGenericFamilies
)
961 const char* langGroupStr
= GetPrefLangName(aPrefLang
);
962 const char* generic
= GetGenericName(aGenericType
);
968 AutoTArray
<nsCString
,4> genericFamilies
;
970 // load family for "font.name.generic.lang"
971 gfxFontUtils::AppendPrefsFontList(
972 NamePref(generic
, langGroupStr
).get(), genericFamilies
);
974 // load fonts for "font.name-list.generic.lang"
975 gfxFontUtils::AppendPrefsFontList(
976 NameListPref(generic
, langGroupStr
).get(), genericFamilies
);
978 nsAtom
* langGroup
= GetLangGroupForPrefLang(aPrefLang
);
979 NS_ASSERTION(langGroup
, "null lang group for pref lang");
981 gfxPlatformFontList::GetFontFamiliesFromGenericFamilies(genericFamilies
,
985 #if 0 // dump out generic mappings
986 printf("%s ===> ", prefFontName
.get());
987 for (uint32_t k
= 0; k
< aGenericFamilies
->Length(); k
++) {
988 if (k
> 0) printf(", ");
989 printf("%s", aGenericFamilies
[k
]->Name().get());
996 gfxPlatformFontList::ResolveEmojiFontNames(
997 nsTArray
<RefPtr
<gfxFontFamily
>>* aGenericFamilies
)
999 // emoji preference has no lang name
1000 AutoTArray
<nsCString
,4> genericFamilies
;
1002 nsAutoCString
prefFontListName("font.name-list.emoji");
1003 gfxFontUtils::AppendPrefsFontList(prefFontListName
.get(), genericFamilies
);
1005 gfxPlatformFontList::GetFontFamiliesFromGenericFamilies(genericFamilies
,
1011 gfxPlatformFontList::GetFontFamiliesFromGenericFamilies(
1012 nsTArray
<nsCString
>& aGenericNameFamilies
,
1014 nsTArray
<RefPtr
<gfxFontFamily
>>* aGenericFamilies
)
1016 // lookup and add platform fonts uniquely
1017 for (const nsCString
& genericFamily
: aGenericNameFamilies
) {
1019 style
.language
= aLangGroup
;
1020 style
.systemFont
= false;
1021 AutoTArray
<FamilyAndGeneric
,10> families
;
1022 FindAndAddFamilies(genericFamily
,
1023 &families
, FindFamiliesFlags(0),
1025 for (const FamilyAndGeneric
& f
: families
) {
1026 if (!aGenericFamilies
->Contains(f
.mFamily
)) {
1027 aGenericFamilies
->AppendElement(f
.mFamily
);
1033 nsTArray
<RefPtr
<gfxFontFamily
>>*
1034 gfxPlatformFontList::GetPrefFontsLangGroup(mozilla::FontFamilyType aGenericType
,
1035 eFontPrefLang aPrefLang
)
1037 // treat -moz-fixed as monospace
1038 if (aGenericType
== eFamily_moz_fixed
) {
1039 aGenericType
= eFamily_monospace
;
1042 if (aGenericType
== eFamily_moz_emoji
) {
1043 // Emoji font has no lang
1044 PrefFontList
* prefFonts
= mEmojiPrefFont
.get();
1045 if (MOZ_UNLIKELY(!prefFonts
)) {
1046 prefFonts
= new PrefFontList
;
1047 ResolveEmojiFontNames(prefFonts
);
1048 mEmojiPrefFont
.reset(prefFonts
);
1053 PrefFontList
* prefFonts
=
1054 mLangGroupPrefFonts
[aPrefLang
][aGenericType
].get();
1055 if (MOZ_UNLIKELY(!prefFonts
)) {
1056 prefFonts
= new PrefFontList
;
1057 ResolveGenericFontNames(aGenericType
, aPrefLang
, prefFonts
);
1058 mLangGroupPrefFonts
[aPrefLang
][aGenericType
].reset(prefFonts
);
1064 gfxPlatformFontList::AddGenericFonts(mozilla::FontFamilyType aGenericType
,
1066 nsTArray
<FamilyAndGeneric
>& aFamilyList
)
1068 // map lang ==> langGroup
1069 nsAtom
* langGroup
= GetLangGroup(aLanguage
);
1071 // langGroup ==> prefLang
1072 eFontPrefLang prefLang
= GetFontPrefLangFor(langGroup
);
1074 // lookup pref fonts
1075 nsTArray
<RefPtr
<gfxFontFamily
>>* prefFonts
=
1076 GetPrefFontsLangGroup(aGenericType
, prefLang
);
1078 if (!prefFonts
->IsEmpty()) {
1079 aFamilyList
.SetCapacity(aFamilyList
.Length() + prefFonts
->Length());
1080 for (auto& f
: *prefFonts
) {
1081 aFamilyList
.AppendElement(FamilyAndGeneric(f
.get(), aGenericType
));
1086 static nsAtom
* PrefLangToLangGroups(uint32_t aIndex
)
1088 // static array here avoids static constructor
1089 static nsAtom
* gPrefLangToLangGroups
[] = {
1090 #define FONT_PREF_LANG(enum_id_, str_, atom_id_) nsGkAtoms::atom_id_
1091 #include "gfxFontPrefLangList.h"
1092 #undef FONT_PREF_LANG
1095 return aIndex
< ArrayLength(gPrefLangToLangGroups
)
1096 ? gPrefLangToLangGroups
[aIndex
]
1097 : nsGkAtoms::Unicode
;
1101 gfxPlatformFontList::GetFontPrefLangFor(const char* aLang
)
1103 if (!aLang
|| !aLang
[0]) {
1104 return eFontPrefLang_Others
;
1106 for (uint32_t i
= 0; i
< ArrayLength(gPrefLangNames
); ++i
) {
1107 if (!PL_strcasecmp(gPrefLangNames
[i
], aLang
)) {
1108 return eFontPrefLang(i
);
1111 return eFontPrefLang_Others
;
1115 gfxPlatformFontList::GetFontPrefLangFor(nsAtom
*aLang
)
1118 return eFontPrefLang_Others
;
1120 aLang
->ToUTF8String(lang
);
1121 return GetFontPrefLangFor(lang
.get());
1125 gfxPlatformFontList::GetLangGroupForPrefLang(eFontPrefLang aLang
)
1127 // the special CJK set pref lang should be resolved into separate
1128 // calls to individual CJK pref langs before getting here
1129 NS_ASSERTION(aLang
!= eFontPrefLang_CJKSet
, "unresolved CJK set pref lang");
1131 return PrefLangToLangGroups(uint32_t(aLang
));
1135 gfxPlatformFontList::GetPrefLangName(eFontPrefLang aLang
)
1137 if (uint32_t(aLang
) < ArrayLength(gPrefLangNames
)) {
1138 return gPrefLangNames
[uint32_t(aLang
)];
1144 gfxPlatformFontList::GetFontPrefLangFor(uint8_t aUnicodeRange
)
1146 switch (aUnicodeRange
) {
1147 case kRangeSetLatin
: return eFontPrefLang_Western
;
1148 case kRangeCyrillic
: return eFontPrefLang_Cyrillic
;
1149 case kRangeGreek
: return eFontPrefLang_Greek
;
1150 case kRangeHebrew
: return eFontPrefLang_Hebrew
;
1151 case kRangeArabic
: return eFontPrefLang_Arabic
;
1152 case kRangeThai
: return eFontPrefLang_Thai
;
1153 case kRangeKorean
: return eFontPrefLang_Korean
;
1154 case kRangeJapanese
: return eFontPrefLang_Japanese
;
1155 case kRangeSChinese
: return eFontPrefLang_ChineseCN
;
1156 case kRangeTChinese
: return eFontPrefLang_ChineseTW
;
1157 case kRangeDevanagari
: return eFontPrefLang_Devanagari
;
1158 case kRangeTamil
: return eFontPrefLang_Tamil
;
1159 case kRangeArmenian
: return eFontPrefLang_Armenian
;
1160 case kRangeBengali
: return eFontPrefLang_Bengali
;
1161 case kRangeCanadian
: return eFontPrefLang_Canadian
;
1162 case kRangeEthiopic
: return eFontPrefLang_Ethiopic
;
1163 case kRangeGeorgian
: return eFontPrefLang_Georgian
;
1164 case kRangeGujarati
: return eFontPrefLang_Gujarati
;
1165 case kRangeGurmukhi
: return eFontPrefLang_Gurmukhi
;
1166 case kRangeKhmer
: return eFontPrefLang_Khmer
;
1167 case kRangeMalayalam
: return eFontPrefLang_Malayalam
;
1168 case kRangeOriya
: return eFontPrefLang_Oriya
;
1169 case kRangeTelugu
: return eFontPrefLang_Telugu
;
1170 case kRangeKannada
: return eFontPrefLang_Kannada
;
1171 case kRangeSinhala
: return eFontPrefLang_Sinhala
;
1172 case kRangeTibetan
: return eFontPrefLang_Tibetan
;
1173 case kRangeSetCJK
: return eFontPrefLang_CJKSet
;
1174 default: return eFontPrefLang_Others
;
1179 gfxPlatformFontList::IsLangCJK(eFontPrefLang aLang
)
1182 case eFontPrefLang_Japanese
:
1183 case eFontPrefLang_ChineseTW
:
1184 case eFontPrefLang_ChineseCN
:
1185 case eFontPrefLang_ChineseHK
:
1186 case eFontPrefLang_Korean
:
1187 case eFontPrefLang_CJKSet
:
1195 gfxPlatformFontList::GetLangPrefs(eFontPrefLang aPrefLangs
[], uint32_t &aLen
, eFontPrefLang aCharLang
, eFontPrefLang aPageLang
)
1197 if (IsLangCJK(aCharLang
)) {
1198 AppendCJKPrefLangs(aPrefLangs
, aLen
, aCharLang
, aPageLang
);
1200 AppendPrefLang(aPrefLangs
, aLen
, aCharLang
);
1203 AppendPrefLang(aPrefLangs
, aLen
, eFontPrefLang_Others
);
1207 gfxPlatformFontList::AppendCJKPrefLangs(eFontPrefLang aPrefLangs
[], uint32_t &aLen
, eFontPrefLang aCharLang
, eFontPrefLang aPageLang
)
1209 // prefer the lang specified by the page *if* CJK
1210 if (IsLangCJK(aPageLang
)) {
1211 AppendPrefLang(aPrefLangs
, aLen
, aPageLang
);
1214 // if not set up, set up the default CJK order, based on accept lang settings and locale
1215 if (mCJKPrefLangs
.Length() == 0) {
1218 eFontPrefLang tempPrefLangs
[kMaxLenPrefLangList
];
1219 uint32_t tempLen
= 0;
1221 // Add the CJK pref fonts from accept languages, the order should be same order
1223 Preferences::GetLocalizedCString("intl.accept_languages", list
);
1224 if (!list
.IsEmpty()) {
1225 const char kComma
= ',';
1226 const char *p
, *p_end
;
1227 list
.BeginReading(p
);
1228 list
.EndReading(p_end
);
1230 while (nsCRT::IsAsciiSpace(*p
)) {
1236 const char *start
= p
;
1237 while (++p
!= p_end
&& *p
!= kComma
)
1239 nsAutoCString
lang(Substring(start
, p
));
1240 lang
.CompressWhitespace(false, true);
1241 eFontPrefLang fpl
= gfxPlatformFontList::GetFontPrefLangFor(lang
.get());
1243 case eFontPrefLang_Japanese
:
1244 case eFontPrefLang_Korean
:
1245 case eFontPrefLang_ChineseCN
:
1246 case eFontPrefLang_ChineseHK
:
1247 case eFontPrefLang_ChineseTW
:
1248 AppendPrefLang(tempPrefLangs
, tempLen
, fpl
);
1257 // Try using app's locale
1258 nsAutoCString localeStr
;
1259 LocaleService::GetInstance()->GetAppLocaleAsLangTag(localeStr
);
1262 Locale
locale(localeStr
);
1263 if (locale
.GetLanguage().Equals("ja")) {
1264 AppendPrefLang(tempPrefLangs
, tempLen
, eFontPrefLang_Japanese
);
1265 } else if (locale
.GetLanguage().Equals("zh")) {
1266 if (locale
.GetRegion().Equals("CN")) {
1267 AppendPrefLang(tempPrefLangs
, tempLen
, eFontPrefLang_ChineseCN
);
1268 } else if (locale
.GetRegion().Equals("TW")) {
1269 AppendPrefLang(tempPrefLangs
, tempLen
, eFontPrefLang_ChineseTW
);
1270 } else if (locale
.GetRegion().Equals("HK")) {
1271 AppendPrefLang(tempPrefLangs
, tempLen
, eFontPrefLang_ChineseHK
);
1273 } else if (locale
.GetLanguage().Equals("ko")) {
1274 AppendPrefLang(tempPrefLangs
, tempLen
, eFontPrefLang_Korean
);
1278 // Then add the known CJK prefs in order of system preferred locales
1279 AutoTArray
<nsCString
,5> prefLocales
;
1280 prefLocales
.AppendElement(NS_LITERAL_CSTRING("ja"));
1281 prefLocales
.AppendElement(NS_LITERAL_CSTRING("zh-CN"));
1282 prefLocales
.AppendElement(NS_LITERAL_CSTRING("zh-TW"));
1283 prefLocales
.AppendElement(NS_LITERAL_CSTRING("zh-HK"));
1284 prefLocales
.AppendElement(NS_LITERAL_CSTRING("ko"));
1286 AutoTArray
<nsCString
,16> sysLocales
;
1287 AutoTArray
<nsCString
,16> negLocales
;
1288 if (NS_SUCCEEDED(OSPreferences::GetInstance()->GetSystemLocales(sysLocales
))) {
1289 LocaleService::GetInstance()->NegotiateLanguages(
1290 sysLocales
, prefLocales
, NS_LITERAL_CSTRING(""),
1291 LocaleService::kLangNegStrategyFiltering
, negLocales
);
1292 for (const auto& localeStr
: negLocales
) {
1293 Locale
locale(localeStr
);
1295 if (locale
.GetLanguage().Equals("ja")) {
1296 AppendPrefLang(tempPrefLangs
, tempLen
,
1297 eFontPrefLang_Japanese
);
1298 } else if (locale
.GetLanguage().Equals("zh")) {
1299 if (locale
.GetRegion().Equals("CN")) {
1300 AppendPrefLang(tempPrefLangs
, tempLen
,
1301 eFontPrefLang_ChineseCN
);
1302 } else if (locale
.GetRegion().Equals("TW")) {
1303 AppendPrefLang(tempPrefLangs
, tempLen
,
1304 eFontPrefLang_ChineseTW
);
1305 } else if (locale
.GetRegion().Equals("HK")) {
1306 AppendPrefLang(tempPrefLangs
, tempLen
,
1307 eFontPrefLang_ChineseHK
);
1309 } else if (locale
.GetLanguage().Equals("ko")) {
1310 AppendPrefLang(tempPrefLangs
, tempLen
,
1311 eFontPrefLang_Korean
);
1316 // last resort... (the order is same as old gfx.)
1317 AppendPrefLang(tempPrefLangs
, tempLen
, eFontPrefLang_Japanese
);
1318 AppendPrefLang(tempPrefLangs
, tempLen
, eFontPrefLang_Korean
);
1319 AppendPrefLang(tempPrefLangs
, tempLen
, eFontPrefLang_ChineseCN
);
1320 AppendPrefLang(tempPrefLangs
, tempLen
, eFontPrefLang_ChineseHK
);
1321 AppendPrefLang(tempPrefLangs
, tempLen
, eFontPrefLang_ChineseTW
);
1323 // copy into the cached array
1325 for (j
= 0; j
< tempLen
; j
++) {
1326 mCJKPrefLangs
.AppendElement(tempPrefLangs
[j
]);
1330 // append in cached CJK langs
1331 uint32_t i
, numCJKlangs
= mCJKPrefLangs
.Length();
1333 for (i
= 0; i
< numCJKlangs
; i
++) {
1334 AppendPrefLang(aPrefLangs
, aLen
, (eFontPrefLang
) (mCJKPrefLangs
[i
]));
1340 gfxPlatformFontList::AppendPrefLang(eFontPrefLang aPrefLangs
[], uint32_t& aLen
, eFontPrefLang aAddLang
)
1342 if (aLen
>= kMaxLenPrefLangList
) return;
1346 while (i
< aLen
&& aPrefLangs
[i
] != aAddLang
) {
1351 aPrefLangs
[aLen
] = aAddLang
;
1356 mozilla::FontFamilyType
1357 gfxPlatformFontList::GetDefaultGeneric(eFontPrefLang aLang
)
1359 if (aLang
== eFontPrefLang_Emoji
) {
1360 return eFamily_moz_emoji
;
1363 // initialize lang group pref font defaults (i.e. serif/sans-serif)
1364 if (MOZ_UNLIKELY(mDefaultGenericsLangGroup
.IsEmpty())) {
1365 mDefaultGenericsLangGroup
.AppendElements(ArrayLength(gPrefLangNames
));
1366 for (uint32_t i
= 0; i
< ArrayLength(gPrefLangNames
); i
++) {
1367 nsAutoCString
prefDefaultFontType("font.default.");
1368 prefDefaultFontType
.Append(GetPrefLangName(eFontPrefLang(i
)));
1369 nsAutoCString serifOrSans
;
1370 Preferences::GetCString(prefDefaultFontType
.get(), serifOrSans
);
1371 if (serifOrSans
.EqualsLiteral("sans-serif")) {
1372 mDefaultGenericsLangGroup
[i
] = eFamily_sans_serif
;
1374 mDefaultGenericsLangGroup
[i
] = eFamily_serif
;
1379 if (uint32_t(aLang
) < ArrayLength(gPrefLangNames
)) {
1380 return mDefaultGenericsLangGroup
[uint32_t(aLang
)];
1382 return eFamily_serif
;
1387 gfxPlatformFontList::GetDefaultFont(const gfxFontStyle
* aStyle
)
1389 gfxFontFamily
* family
= GetDefaultFontForPlatform(aStyle
);
1393 // Something has gone wrong and we were unable to retrieve a default font
1394 // from the platform. (Likely the whitelist has blocked all potential
1395 // default fonts.) As a last resort, we return the first font listed in
1397 return mFontFamilies
.Iter().Data();
1401 gfxPlatformFontList::GetFontFamilyNames(nsTArray
<nsCString
>& aFontFamilyNames
)
1403 for (auto iter
= mFontFamilies
.Iter(); !iter
.Done(); iter
.Next()) {
1404 RefPtr
<gfxFontFamily
>& family
= iter
.Data();
1405 aFontFamilyNames
.AppendElement(family
->Name());
1410 gfxPlatformFontList::GetLangGroup(nsAtom
* aLanguage
)
1412 // map lang ==> langGroup
1413 nsAtom
*langGroup
= nullptr;
1415 langGroup
= mLangService
->GetLanguageGroup(aLanguage
);
1418 langGroup
= nsGkAtoms::Unicode
;
1423 /* static */ const char*
1424 gfxPlatformFontList::GetGenericName(FontFamilyType aGenericType
)
1426 static const char kGeneric_serif
[] = "serif";
1427 static const char kGeneric_sans_serif
[] = "sans-serif";
1428 static const char kGeneric_monospace
[] = "monospace";
1429 static const char kGeneric_cursive
[] = "cursive";
1430 static const char kGeneric_fantasy
[] = "fantasy";
1432 // type should be standard generic type at this point
1433 NS_ASSERTION(aGenericType
>= eFamily_serif
&&
1434 aGenericType
<= eFamily_fantasy
,
1435 "standard generic font family type required");
1437 // map generic type to string
1438 const char *generic
= nullptr;
1439 switch (aGenericType
) {
1441 generic
= kGeneric_serif
;
1443 case eFamily_sans_serif
:
1444 generic
= kGeneric_sans_serif
;
1446 case eFamily_monospace
:
1447 generic
= kGeneric_monospace
;
1449 case eFamily_cursive
:
1450 generic
= kGeneric_cursive
;
1452 case eFamily_fantasy
:
1453 generic
= kGeneric_fantasy
;
1463 gfxPlatformFontList::InitLoader()
1465 GetFontFamilyNames(mFontInfo
->mFontFamiliesToLoad
);
1467 mNumFamilies
= mFontInfo
->mFontFamiliesToLoad
.Length();
1468 memset(&(mFontInfo
->mLoadStats
), 0, sizeof(mFontInfo
->mLoadStats
));
1471 #define FONT_LOADER_MAX_TIMESLICE 100 // max time for one pass through RunLoader = 100ms
1474 gfxPlatformFontList::LoadFontInfo()
1476 TimeStamp start
= TimeStamp::Now();
1477 uint32_t i
, endIndex
= mNumFamilies
;
1478 bool loadCmaps
= !UsesSystemFallback() ||
1479 gfxPlatform::GetPlatform()->UseCmapsDuringSystemFallback();
1481 // for each font family, load in various font info
1482 for (i
= mStartIndex
; i
< endIndex
; i
++) {
1484 gfxFontFamily
*familyEntry
;
1485 GenerateFontListKey(mFontInfo
->mFontFamiliesToLoad
[i
], key
);
1487 // lookup in canonical (i.e. English) family name list
1488 if (!(familyEntry
= mFontFamilies
.GetWeak(key
))) {
1492 // read in face names
1493 familyEntry
->ReadFaceNames(this, NeedFullnamePostscriptNames(), mFontInfo
);
1495 // load the cmaps if needed
1497 familyEntry
->ReadAllCMAPs(mFontInfo
);
1500 // limit the time spent reading fonts in one pass
1501 TimeDuration elapsed
= TimeStamp::Now() - start
;
1502 if (elapsed
.ToMilliseconds() > FONT_LOADER_MAX_TIMESLICE
&&
1503 i
+ 1 != endIndex
) {
1509 mStartIndex
= endIndex
;
1510 bool done
= mStartIndex
>= mNumFamilies
;
1512 if (LOG_FONTINIT_ENABLED()) {
1513 TimeDuration elapsed
= TimeStamp::Now() - start
;
1514 LOG_FONTINIT(("(fontinit) fontloader load pass %8.2f ms done %s\n",
1515 elapsed
.ToMilliseconds(), (done
? "true" : "false")));
1519 mOtherFamilyNamesInitialized
= true;
1520 CancelInitOtherFamilyNamesTask();
1521 mFaceNameListsInitialized
= true;
1528 gfxPlatformFontList::CleanupLoader()
1530 mFontFamiliesToLoad
.Clear();
1532 bool rebuilt
= false, forceReflow
= false;
1534 // if had missed face names that are now available, force reflow all
1535 if (mFaceNamesMissed
) {
1536 for (auto it
= mFaceNamesMissed
->Iter(); !it
.Done(); it
.Next()) {
1537 if (FindFaceName(it
.Get()->GetKey())) {
1539 RebuildLocalFonts();
1543 mFaceNamesMissed
= nullptr;
1546 if (mOtherNamesMissed
) {
1547 for (auto it
= mOtherNamesMissed
->Iter(); !it
.Done(); it
.Next()) {
1548 if (FindFamily(it
.Get()->GetKey(),
1549 (FindFamiliesFlags::eForceOtherFamilyNamesLoading
|
1550 FindFamiliesFlags::eNoAddToNamesMissedWhenSearching
))) {
1552 ForceGlobalReflow();
1556 mOtherNamesMissed
= nullptr;
1559 if (LOG_FONTINIT_ENABLED() && mFontInfo
) {
1560 LOG_FONTINIT(("(fontinit) fontloader load thread took %8.2f ms "
1561 "%d families %d fonts %d cmaps "
1562 "%d facenames %d othernames %s %s",
1563 mLoadTime
.ToMilliseconds(),
1564 mFontInfo
->mLoadStats
.families
,
1565 mFontInfo
->mLoadStats
.fonts
,
1566 mFontInfo
->mLoadStats
.cmaps
,
1567 mFontInfo
->mLoadStats
.facenames
,
1568 mFontInfo
->mLoadStats
.othernames
,
1569 (rebuilt
? "(userfont sets rebuilt)" : ""),
1570 (forceReflow
? "(global reflow)" : "")));
1573 gfxFontInfoLoader::CleanupLoader();
1577 gfxPlatformFontList::GetPrefsAndStartLoader()
1580 std::max(1u, Preferences::GetUint(FONT_LOADER_DELAY_PREF
));
1582 std::max(1u, Preferences::GetUint(FONT_LOADER_INTERVAL_PREF
));
1584 StartLoader(delay
, interval
);
1588 gfxPlatformFontList::RebuildLocalFonts()
1590 for (auto it
= mUserFontSetList
.Iter(); !it
.Done(); it
.Next()) {
1591 it
.Get()->GetKey()->RebuildLocalRules();
1596 gfxPlatformFontList::ClearLangGroupPrefFonts()
1598 for (uint32_t i
= eFontPrefLang_First
;
1599 i
< eFontPrefLang_First
+ eFontPrefLang_Count
; i
++) {
1600 auto& prefFontsLangGroup
= mLangGroupPrefFonts
[i
];
1601 for (uint32_t j
= eFamily_generic_first
;
1602 j
< eFamily_generic_first
+ eFamily_generic_count
; j
++) {
1603 prefFontsLangGroup
[j
] = nullptr;
1606 mCJKPrefLangs
.Clear();
1607 mEmojiPrefFont
= nullptr;
1610 // Support for memory reporting
1612 // this is also used by subclasses that hold additional font tables
1614 gfxPlatformFontList::SizeOfFontFamilyTableExcludingThis(
1615 const FontFamilyTable
& aTable
,
1616 MallocSizeOf aMallocSizeOf
)
1618 size_t n
= aTable
.ShallowSizeOfExcludingThis(aMallocSizeOf
);
1619 for (auto iter
= aTable
.ConstIter(); !iter
.Done(); iter
.Next()) {
1620 // We don't count the size of the family here, because this is an
1621 // *extra* reference to a family that will have already been counted in
1623 n
+= iter
.Key().SizeOfExcludingThisIfUnshared(aMallocSizeOf
);
1629 gfxPlatformFontList::SizeOfFontEntryTableExcludingThis(
1630 const FontEntryTable
& aTable
,
1631 MallocSizeOf aMallocSizeOf
)
1633 size_t n
= aTable
.ShallowSizeOfExcludingThis(aMallocSizeOf
);
1634 for (auto iter
= aTable
.ConstIter(); !iter
.Done(); iter
.Next()) {
1635 // The font itself is counted by its owning family; here we only care
1636 // about the names stored in the hashtable keys.
1637 n
+= iter
.Key().SizeOfExcludingThisIfUnshared(aMallocSizeOf
);
1643 gfxPlatformFontList::AddSizeOfExcludingThis(MallocSizeOf aMallocSizeOf
,
1644 FontListSizes
* aSizes
) const
1646 aSizes
->mFontListSize
+=
1647 mFontFamilies
.ShallowSizeOfExcludingThis(aMallocSizeOf
);
1648 for (auto iter
= mFontFamilies
.ConstIter(); !iter
.Done(); iter
.Next()) {
1649 aSizes
->mFontListSize
+=
1650 iter
.Key().SizeOfExcludingThisIfUnshared(aMallocSizeOf
);
1651 iter
.Data()->AddSizeOfIncludingThis(aMallocSizeOf
, aSizes
);
1654 aSizes
->mFontListSize
+=
1655 SizeOfFontFamilyTableExcludingThis(mOtherFamilyNames
, aMallocSizeOf
);
1658 aSizes
->mFontListSize
+=
1659 SizeOfFontEntryTableExcludingThis(mExtraNames
->mFullnames
,
1661 aSizes
->mFontListSize
+=
1662 SizeOfFontEntryTableExcludingThis(mExtraNames
->mPostscriptNames
,
1666 for (uint32_t i
= eFontPrefLang_First
;
1667 i
< eFontPrefLang_First
+ eFontPrefLang_Count
; i
++) {
1668 auto& prefFontsLangGroup
= mLangGroupPrefFonts
[i
];
1669 for (uint32_t j
= eFamily_generic_first
;
1670 j
< eFamily_generic_first
+ eFamily_generic_count
; j
++) {
1671 PrefFontList
* pf
= prefFontsLangGroup
[j
].get();
1673 aSizes
->mFontListSize
+=
1674 pf
->ShallowSizeOfExcludingThis(aMallocSizeOf
);
1679 aSizes
->mFontListSize
+=
1680 mCodepointsWithNoFonts
.SizeOfExcludingThis(aMallocSizeOf
);
1681 aSizes
->mFontListSize
+=
1682 mFontFamiliesToLoad
.ShallowSizeOfExcludingThis(aMallocSizeOf
);
1684 aSizes
->mFontListSize
+=
1685 mBadUnderlineFamilyNames
.SizeOfExcludingThis(aMallocSizeOf
);
1687 aSizes
->mFontListSize
+=
1688 mSharedCmaps
.ShallowSizeOfExcludingThis(aMallocSizeOf
);
1689 for (auto iter
= mSharedCmaps
.ConstIter(); !iter
.Done(); iter
.Next()) {
1690 aSizes
->mCharMapsSize
+=
1691 iter
.Get()->GetKey()->SizeOfIncludingThis(aMallocSizeOf
);
1696 gfxPlatformFontList::AddSizeOfIncludingThis(MallocSizeOf aMallocSizeOf
,
1697 FontListSizes
* aSizes
) const
1699 aSizes
->mFontListSize
+= aMallocSizeOf(this);
1700 AddSizeOfExcludingThis(aMallocSizeOf
, aSizes
);
1704 gfxPlatformFontList::IsFontFamilyWhitelistActive()
1706 return mFontFamilyWhitelistActive
;
1710 gfxPlatformFontList::InitOtherFamilyNamesInternal(bool aDeferOtherFamilyNamesLoading
)
1712 if (mOtherFamilyNamesInitialized
) {
1716 if (aDeferOtherFamilyNamesLoading
) {
1717 TimeStamp start
= TimeStamp::Now();
1718 bool timedOut
= false;
1720 for (auto iter
= mFontFamilies
.Iter(); !iter
.Done(); iter
.Next()) {
1721 RefPtr
<gfxFontFamily
>& family
= iter
.Data();
1722 family
->ReadOtherFamilyNames(this);
1723 TimeDuration elapsed
= TimeStamp::Now() - start
;
1724 if (elapsed
.ToMilliseconds() > OTHERNAMES_TIMEOUT
) {
1731 mOtherFamilyNamesInitialized
= true;
1732 CancelInitOtherFamilyNamesTask();
1734 TimeStamp end
= TimeStamp::Now();
1735 Telemetry::AccumulateTimeDelta(Telemetry::FONTLIST_INITOTHERFAMILYNAMES
,
1738 if (LOG_FONTINIT_ENABLED()) {
1739 TimeDuration elapsed
= end
- start
;
1740 LOG_FONTINIT(("(fontinit) InitOtherFamilyNames took %8.2f ms %s",
1741 elapsed
.ToMilliseconds(),
1742 (timedOut
? "timeout" : "")));
1745 TimeStamp start
= TimeStamp::Now();
1747 for (auto iter
= mFontFamilies
.Iter(); !iter
.Done(); iter
.Next()) {
1748 RefPtr
<gfxFontFamily
>& family
= iter
.Data();
1749 family
->ReadOtherFamilyNames(this);
1752 mOtherFamilyNamesInitialized
= true;
1753 CancelInitOtherFamilyNamesTask();
1755 TimeStamp end
= TimeStamp::Now();
1756 Telemetry::AccumulateTimeDelta(Telemetry::FONTLIST_INITOTHERFAMILYNAMES_NO_DEFERRING
,
1759 if (LOG_FONTINIT_ENABLED()) {
1760 TimeDuration elapsed
= end
- start
;
1761 LOG_FONTINIT(("(fontinit) InitOtherFamilyNames without deferring took %8.2f ms",
1762 elapsed
.ToMilliseconds()));
1768 gfxPlatformFontList::CancelInitOtherFamilyNamesTask()
1770 if (mPendingOtherFamilyNameTask
) {
1771 mPendingOtherFamilyNameTask
->Cancel();
1772 mPendingOtherFamilyNameTask
= nullptr;