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/. */
5 
6 #include "mozilla/Logging.h"
7 
8 #include "gfxPlatformFontList.h"
9 #include "gfxTextRun.h"
10 #include "gfxUserFontSet.h"
11 
12 #include "nsCRT.h"
13 #include "nsGkAtoms.h"
14 #include "nsILocaleService.h"
15 #include "nsServiceManagerUtils.h"
16 #include "nsUnicharUtils.h"
17 #include "nsUnicodeRange.h"
18 #include "nsUnicodeProperties.h"
19 
20 #include "mozilla/Attributes.h"
21 #include "mozilla/Likely.h"
22 #include "mozilla/MemoryReporting.h"
23 #include "mozilla/Preferences.h"
24 #include "mozilla/Telemetry.h"
25 #include "mozilla/TimeStamp.h"
26 #include "mozilla/gfx/2D.h"
27 
28 #include <locale.h>
29 
30 using namespace mozilla;
31 
32 #define LOG_FONTLIST(args) MOZ_LOG(gfxPlatform::GetLog(eGfxLog_fontlist), \
33                                LogLevel::Debug, args)
34 #define LOG_FONTLIST_ENABLED() MOZ_LOG_TEST( \
35                                    gfxPlatform::GetLog(eGfxLog_fontlist), \
36                                    LogLevel::Debug)
37 #define LOG_FONTINIT(args) MOZ_LOG(gfxPlatform::GetLog(eGfxLog_fontinit), \
38                                LogLevel::Debug, args)
39 #define LOG_FONTINIT_ENABLED() MOZ_LOG_TEST( \
40                                    gfxPlatform::GetLog(eGfxLog_fontinit), \
41                                    LogLevel::Debug)
42 
43 gfxPlatformFontList *gfxPlatformFontList::sPlatformFontList = nullptr;
44 
45 // Character ranges that require complex-script shaping support in the font,
46 // and so should be masked out by ReadCMAP if the necessary layout tables
47 // are not present.
48 // Currently used by the Mac and FT2 implementations only, but probably should
49 // be supported on Windows as well.
50 const gfxFontEntry::ScriptRange gfxPlatformFontList::sComplexScriptRanges[] = {
51     // Actually, now that harfbuzz supports presentation-forms shaping for
52     // Arabic, we can render it without layout tables. So maybe we don't
53     // want to mask the basic Arabic block here?
54     // This affects the arabic-fallback-*.html reftests, which rely on
55     // loading a font that *doesn't* have any GSUB table.
56     { 0x0600, 0x06FF, { TRUETYPE_TAG('a','r','a','b'), 0, 0 } },
57     { 0x0700, 0x074F, { TRUETYPE_TAG('s','y','r','c'), 0, 0 } },
58     { 0x0750, 0x077F, { TRUETYPE_TAG('a','r','a','b'), 0, 0 } },
59     { 0x08A0, 0x08FF, { TRUETYPE_TAG('a','r','a','b'), 0, 0 } },
60     { 0x0900, 0x097F, { TRUETYPE_TAG('d','e','v','2'),
61                         TRUETYPE_TAG('d','e','v','a'), 0 } },
62     { 0x0980, 0x09FF, { TRUETYPE_TAG('b','n','g','2'),
63                         TRUETYPE_TAG('b','e','n','g'), 0 } },
64     { 0x0A00, 0x0A7F, { TRUETYPE_TAG('g','u','r','2'),
65                         TRUETYPE_TAG('g','u','r','u'), 0 } },
66     { 0x0A80, 0x0AFF, { TRUETYPE_TAG('g','j','r','2'),
67                         TRUETYPE_TAG('g','u','j','r'), 0 } },
68     { 0x0B00, 0x0B7F, { TRUETYPE_TAG('o','r','y','2'),
69                         TRUETYPE_TAG('o','r','y','a'), 0 } },
70     { 0x0B80, 0x0BFF, { TRUETYPE_TAG('t','m','l','2'),
71                         TRUETYPE_TAG('t','a','m','l'), 0 } },
72     { 0x0C00, 0x0C7F, { TRUETYPE_TAG('t','e','l','2'),
73                         TRUETYPE_TAG('t','e','l','u'), 0 } },
74     { 0x0C80, 0x0CFF, { TRUETYPE_TAG('k','n','d','2'),
75                         TRUETYPE_TAG('k','n','d','a'), 0 } },
76     { 0x0D00, 0x0D7F, { TRUETYPE_TAG('m','l','m','2'),
77                         TRUETYPE_TAG('m','l','y','m'), 0 } },
78     { 0x0D80, 0x0DFF, { TRUETYPE_TAG('s','i','n','h'), 0, 0 } },
79     { 0x0E80, 0x0EFF, { TRUETYPE_TAG('l','a','o',' '), 0, 0 } },
80     { 0x0F00, 0x0FFF, { TRUETYPE_TAG('t','i','b','t'), 0, 0 } },
81     { 0x1000, 0x109f, { TRUETYPE_TAG('m','y','m','r'),
82                         TRUETYPE_TAG('m','y','m','2'), 0 } },
83     { 0x1780, 0x17ff, { TRUETYPE_TAG('k','h','m','r'), 0, 0 } },
84     // Khmer Symbols (19e0..19ff) don't seem to need any special shaping
85     { 0xaa60, 0xaa7f, { TRUETYPE_TAG('m','y','m','r'),
86                         TRUETYPE_TAG('m','y','m','2'), 0 } },
87     // Thai seems to be "renderable" without AAT morphing tables
88     { 0, 0, { 0, 0, 0 } } // terminator
89 };
90 
91 // prefs for the font info loader
92 #define FONT_LOADER_FAMILIES_PER_SLICE_PREF "gfx.font_loader.families_per_slice"
93 #define FONT_LOADER_DELAY_PREF              "gfx.font_loader.delay"
94 #define FONT_LOADER_INTERVAL_PREF           "gfx.font_loader.interval"
95 
96 static const char* kObservedPrefs[] = {
97     "font.",
98     "font.name-list.",
99     "intl.accept_languages",  // hmmmm...
100     nullptr
101 };
102 
103 static const char kFontSystemWhitelistPref[] = "font.system.whitelist";
104 
105 // xxx - this can probably be eliminated by reworking pref font handling code
106 static const char *gPrefLangNames[] = {
107     #define FONT_PREF_LANG(enum_id_, str_, atom_id_) str_
108     #include "gfxFontPrefLangList.h"
109     #undef FONT_PREF_LANG
110 };
111 
112 static_assert(MOZ_ARRAY_LENGTH(gPrefLangNames) == uint32_t(eFontPrefLang_Count),
113               "size of pref lang name array doesn't match pref lang enum size");
114 
115 class gfxFontListPrefObserver final : public nsIObserver {
~gfxFontListPrefObserver()116     ~gfxFontListPrefObserver() {}
117 public:
118     NS_DECL_ISUPPORTS
119     NS_DECL_NSIOBSERVER
120 };
121 
122 static gfxFontListPrefObserver* gFontListPrefObserver = nullptr;
123 
NS_IMPL_ISUPPORTS(gfxFontListPrefObserver,nsIObserver)124 NS_IMPL_ISUPPORTS(gfxFontListPrefObserver, nsIObserver)
125 
126 NS_IMETHODIMP
127 gfxFontListPrefObserver::Observe(nsISupports     *aSubject,
128                                  const char      *aTopic,
129                                  const char16_t *aData)
130 {
131     NS_ASSERTION(!strcmp(aTopic, NS_PREFBRANCH_PREFCHANGE_TOPIC_ID), "invalid topic");
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();
136     return NS_OK;
137 }
138 
139 MOZ_DEFINE_MALLOC_SIZE_OF(FontListMallocSizeOf)
140 
NS_IMPL_ISUPPORTS(gfxPlatformFontList::MemoryReporter,nsIMemoryReporter)141 NS_IMPL_ISUPPORTS(gfxPlatformFontList::MemoryReporter, nsIMemoryReporter)
142 
143 NS_IMETHODIMP
144 gfxPlatformFontList::MemoryReporter::CollectReports(
145     nsIHandleReportCallback* aHandleReport, nsISupports* aData, bool aAnonymize)
146 {
147     FontListSizes sizes;
148     sizes.mFontListSize = 0;
149     sizes.mFontTableCacheSize = 0;
150     sizes.mCharMapsSize = 0;
151 
152     gfxPlatformFontList::PlatformFontList()->AddSizeOfIncludingThis(&FontListMallocSizeOf,
153                                                                     &sizes);
154 
155     MOZ_COLLECT_REPORT(
156         "explicit/gfx/font-list", KIND_HEAP, UNITS_BYTES,
157         sizes.mFontListSize,
158         "Memory used to manage the list of font families and faces.");
159 
160     MOZ_COLLECT_REPORT(
161         "explicit/gfx/font-charmaps", KIND_HEAP, UNITS_BYTES,
162         sizes.mCharMapsSize,
163         "Memory used to record the character coverage of individual fonts.");
164 
165     if (sizes.mFontTableCacheSize) {
166         MOZ_COLLECT_REPORT(
167             "explicit/gfx/font-tables", KIND_HEAP, UNITS_BYTES,
168             sizes.mFontTableCacheSize,
169             "Memory used for cached font metrics and layout tables.");
170     }
171 
172     return NS_OK;
173 }
174 
gfxPlatformFontList(bool aNeedFullnamePostscriptNames)175 gfxPlatformFontList::gfxPlatformFontList(bool aNeedFullnamePostscriptNames)
176     : mFontFamilies(64), mOtherFamilyNames(16),
177       mBadUnderlineFamilyNames(8), mSharedCmaps(8),
178       mStartIndex(0), mIncrement(1), mNumFamilies(0), mFontlistInitCount(0),
179       mFontFamilyWhitelistActive(false)
180 {
181     mOtherFamilyNamesInitialized = false;
182 
183     if (aNeedFullnamePostscriptNames) {
184         mExtraNames = MakeUnique<ExtraNames>();
185     }
186     mFaceNameListsInitialized = false;
187 
188     LoadBadUnderlineList();
189 
190     // pref changes notification setup
191     NS_ASSERTION(!gFontListPrefObserver,
192                  "There has been font list pref observer already");
193     gFontListPrefObserver = new gfxFontListPrefObserver();
194     NS_ADDREF(gFontListPrefObserver);
195     Preferences::AddStrongObservers(gFontListPrefObserver, kObservedPrefs);
196 
197     Preferences::RegisterCallback(FontWhitelistPrefChanged,
198                                   kFontSystemWhitelistPref);
199 
200     RegisterStrongMemoryReporter(new MemoryReporter());
201 }
202 
~gfxPlatformFontList()203 gfxPlatformFontList::~gfxPlatformFontList()
204 {
205     mSharedCmaps.Clear();
206     ClearLangGroupPrefFonts();
207     NS_ASSERTION(gFontListPrefObserver, "There is no font list pref observer");
208     Preferences::RemoveObservers(gFontListPrefObserver, kObservedPrefs);
209     Preferences::UnregisterCallback(FontWhitelistPrefChanged,
210                                     kFontSystemWhitelistPref);
211     NS_RELEASE(gFontListPrefObserver);
212 }
213 
214 // number of CSS generic font families
215 const uint32_t kNumGenerics = 5;
216 
217 void
ApplyWhitelist()218 gfxPlatformFontList::ApplyWhitelist()
219 {
220     nsTArray<nsString> list;
221     gfxFontUtils::GetPrefsFontList(kFontSystemWhitelistPref, list);
222     uint32_t numFonts = list.Length();
223     mFontFamilyWhitelistActive = (numFonts > 0);
224     if (!mFontFamilyWhitelistActive) {
225         return;
226     }
227     nsTHashtable<nsStringHashKey> familyNamesWhitelist;
228     for (uint32_t i = 0; i < numFonts; i++) {
229         nsString key;
230         ToLowerCase(list[i], key);
231         familyNamesWhitelist.PutEntry(key);
232     }
233     for (auto iter = mFontFamilies.Iter(); !iter.Done(); iter.Next()) {
234         // Don't continue if we only have one font left.
235         if (mFontFamilies.Count() == 1) {
236             break;
237         }
238         nsString fontFamilyName(iter.Key());
239         ToLowerCase(fontFamilyName);
240         if (!familyNamesWhitelist.Contains(fontFamilyName)) {
241             iter.Remove();
242         }
243     }
244 }
245 
246 nsresult
InitFontList()247 gfxPlatformFontList::InitFontList()
248 {
249     mFontlistInitCount++;
250 
251     if (LOG_FONTINIT_ENABLED()) {
252         LOG_FONTINIT(("(fontinit) system fontlist initialization\n"));
253     }
254 
255     // rebuilding fontlist so clear out font/word caches
256     gfxFontCache *fontCache = gfxFontCache::GetCache();
257     if (fontCache) {
258         fontCache->AgeAllGenerations();
259         fontCache->FlushShapedWordCaches();
260     }
261 
262     gfxPlatform::PurgeSkiaFontCache();
263 
264     mFontFamilies.Clear();
265     mOtherFamilyNames.Clear();
266     mOtherFamilyNamesInitialized = false;
267     if (mExtraNames) {
268         mExtraNames->mFullnames.Clear();
269         mExtraNames->mPostscriptNames.Clear();
270     }
271     mFaceNameListsInitialized = false;
272     ClearLangGroupPrefFonts();
273     mReplacementCharFallbackFamily = nullptr;
274     CancelLoader();
275 
276     // initialize ranges of characters for which system-wide font search should be skipped
277     mCodepointsWithNoFonts.reset();
278     mCodepointsWithNoFonts.SetRange(0,0x1f);     // C0 controls
279     mCodepointsWithNoFonts.SetRange(0x7f,0x9f);  // C1 controls
280 
281     sPlatformFontList = this;
282 
283     nsresult rv = InitFontListForPlatform();
284     if (NS_FAILED(rv)) {
285         return rv;
286     }
287 
288     ApplyWhitelist();
289     return NS_OK;
290 }
291 
292 void
GenerateFontListKey(const nsAString & aKeyName,nsAString & aResult)293 gfxPlatformFontList::GenerateFontListKey(const nsAString& aKeyName, nsAString& aResult)
294 {
295     aResult = aKeyName;
296     ToLowerCase(aResult);
297 }
298 
299 #define OTHERNAMES_TIMEOUT 200
300 
301 void
InitOtherFamilyNames()302 gfxPlatformFontList::InitOtherFamilyNames()
303 {
304     if (mOtherFamilyNamesInitialized) {
305         return;
306     }
307 
308     TimeStamp start = TimeStamp::Now();
309     bool timedOut = false;
310 
311     for (auto iter = mFontFamilies.Iter(); !iter.Done(); iter.Next()) {
312         RefPtr<gfxFontFamily>& family = iter.Data();
313         family->ReadOtherFamilyNames(this);
314         TimeDuration elapsed = TimeStamp::Now() - start;
315         if (elapsed.ToMilliseconds() > OTHERNAMES_TIMEOUT) {
316             timedOut = true;
317             break;
318         }
319     }
320 
321     if (!timedOut) {
322         mOtherFamilyNamesInitialized = true;
323     }
324     TimeStamp end = TimeStamp::Now();
325     Telemetry::AccumulateTimeDelta(Telemetry::FONTLIST_INITOTHERFAMILYNAMES,
326                                    start, end);
327 
328     if (LOG_FONTINIT_ENABLED()) {
329         TimeDuration elapsed = end - start;
330         LOG_FONTINIT(("(fontinit) InitOtherFamilyNames took %8.2f ms %s",
331                       elapsed.ToMilliseconds(),
332                       (timedOut ? "timeout" : "")));
333     }
334 }
335 
336 // time limit for loading facename lists (ms)
337 #define NAMELIST_TIMEOUT  200
338 
339 gfxFontEntry*
SearchFamiliesForFaceName(const nsAString & aFaceName)340 gfxPlatformFontList::SearchFamiliesForFaceName(const nsAString& aFaceName)
341 {
342     TimeStamp start = TimeStamp::Now();
343     bool timedOut = false;
344     // if mFirstChar is not 0, only load facenames for families
345     // that start with this character
346     char16_t firstChar = 0;
347     gfxFontEntry *lookup = nullptr;
348 
349     // iterate over familes starting with the same letter
350     firstChar = ToLowerCase(aFaceName.CharAt(0));
351 
352     for (auto iter = mFontFamilies.Iter(); !iter.Done(); iter.Next()) {
353         nsStringHashKey::KeyType key = iter.Key();
354         RefPtr<gfxFontFamily>& family = iter.Data();
355 
356         // when filtering, skip names that don't start with the filter character
357         if (firstChar && ToLowerCase(key.CharAt(0)) != firstChar) {
358             continue;
359         }
360 
361         family->ReadFaceNames(this, NeedFullnamePostscriptNames());
362 
363         TimeDuration elapsed = TimeStamp::Now() - start;
364         if (elapsed.ToMilliseconds() > NAMELIST_TIMEOUT) {
365            timedOut = true;
366            break;
367         }
368     }
369 
370     lookup = FindFaceName(aFaceName);
371 
372     TimeStamp end = TimeStamp::Now();
373     Telemetry::AccumulateTimeDelta(Telemetry::FONTLIST_INITFACENAMELISTS,
374                                    start, end);
375     if (LOG_FONTINIT_ENABLED()) {
376         TimeDuration elapsed = end - start;
377         LOG_FONTINIT(("(fontinit) SearchFamiliesForFaceName took %8.2f ms %s %s",
378                       elapsed.ToMilliseconds(),
379                       (lookup ? "found name" : ""),
380                       (timedOut ? "timeout" : "")));
381     }
382 
383     return lookup;
384 }
385 
386 gfxFontEntry*
FindFaceName(const nsAString & aFaceName)387 gfxPlatformFontList::FindFaceName(const nsAString& aFaceName)
388 {
389     gfxFontEntry *lookup;
390 
391     // lookup in name lookup tables, return null if not found
392     if (mExtraNames &&
393         ((lookup = mExtraNames->mPostscriptNames.GetWeak(aFaceName)) ||
394          (lookup = mExtraNames->mFullnames.GetWeak(aFaceName)))) {
395         return lookup;
396     }
397 
398     return nullptr;
399 }
400 
401 gfxFontEntry*
LookupInFaceNameLists(const nsAString & aFaceName)402 gfxPlatformFontList::LookupInFaceNameLists(const nsAString& aFaceName)
403 {
404     gfxFontEntry *lookup = nullptr;
405 
406     // initialize facename lookup tables if needed
407     // note: this can terminate early or time out, in which case
408     //       mFaceNameListsInitialized remains false
409     if (!mFaceNameListsInitialized) {
410         lookup = SearchFamiliesForFaceName(aFaceName);
411         if (lookup) {
412             return lookup;
413         }
414     }
415 
416     // lookup in name lookup tables, return null if not found
417     if (!(lookup = FindFaceName(aFaceName))) {
418         // names not completely initialized, so keep track of lookup misses
419         if (!mFaceNameListsInitialized) {
420             if (!mFaceNamesMissed) {
421                 mFaceNamesMissed = MakeUnique<nsTHashtable<nsStringHashKey>>(2);
422             }
423             mFaceNamesMissed->PutEntry(aFaceName);
424         }
425     }
426 
427     return lookup;
428 }
429 
430 void
PreloadNamesList()431 gfxPlatformFontList::PreloadNamesList()
432 {
433     AutoTArray<nsString, 10> preloadFonts;
434     gfxFontUtils::GetPrefsFontList("font.preload-names-list", preloadFonts);
435 
436     uint32_t numFonts = preloadFonts.Length();
437     for (uint32_t i = 0; i < numFonts; i++) {
438         nsAutoString key;
439         GenerateFontListKey(preloadFonts[i], key);
440 
441         // only search canonical names!
442         gfxFontFamily *familyEntry = mFontFamilies.GetWeak(key);
443         if (familyEntry) {
444             familyEntry->ReadOtherFamilyNames(this);
445         }
446     }
447 
448 }
449 
450 void
LoadBadUnderlineList()451 gfxPlatformFontList::LoadBadUnderlineList()
452 {
453     AutoTArray<nsString, 10> blacklist;
454     gfxFontUtils::GetPrefsFontList("font.blacklist.underline_offset", blacklist);
455     uint32_t numFonts = blacklist.Length();
456     for (uint32_t i = 0; i < numFonts; i++) {
457         nsAutoString key;
458         GenerateFontListKey(blacklist[i], key);
459         mBadUnderlineFamilyNames.PutEntry(key);
460     }
461 }
462 
463 void
UpdateFontList()464 gfxPlatformFontList::UpdateFontList()
465 {
466     InitFontList();
467     RebuildLocalFonts();
468 }
469 
470 void
GetFontList(nsIAtom * aLangGroup,const nsACString & aGenericFamily,nsTArray<nsString> & aListOfFonts)471 gfxPlatformFontList::GetFontList(nsIAtom *aLangGroup,
472                                  const nsACString& aGenericFamily,
473                                  nsTArray<nsString>& aListOfFonts)
474 {
475     for (auto iter = mFontFamilies.Iter(); !iter.Done(); iter.Next()) {
476         RefPtr<gfxFontFamily>& family = iter.Data();
477         // use the first variation for now.  This data should be the same
478         // for all the variations and should probably be moved up to
479         // the Family
480         gfxFontStyle style;
481         style.language = aLangGroup;
482         bool needsBold;
483         RefPtr<gfxFontEntry> fontEntry = family->FindFontForStyle(style, needsBold);
484         NS_ASSERTION(fontEntry, "couldn't find any font entry in family");
485         if (!fontEntry) {
486             continue;
487         }
488 
489         /* skip symbol fonts */
490         if (fontEntry->IsSymbolFont()) {
491             continue;
492         }
493 
494         if (fontEntry->SupportsLangGroup(aLangGroup) &&
495             fontEntry->MatchesGenericFamily(aGenericFamily)) {
496             nsAutoString localizedFamilyName;
497             family->LocalizedName(localizedFamilyName);
498             aListOfFonts.AppendElement(localizedFamilyName);
499         }
500     }
501 
502     aListOfFonts.Sort();
503     aListOfFonts.Compact();
504 }
505 
506 void
GetFontFamilyList(nsTArray<RefPtr<gfxFontFamily>> & aFamilyArray)507 gfxPlatformFontList::GetFontFamilyList(nsTArray<RefPtr<gfxFontFamily> >& aFamilyArray)
508 {
509     for (auto iter = mFontFamilies.Iter(); !iter.Done(); iter.Next()) {
510         RefPtr<gfxFontFamily>& family = iter.Data();
511         aFamilyArray.AppendElement(family);
512     }
513 }
514 
515 gfxFontEntry*
SystemFindFontForChar(uint32_t aCh,uint32_t aNextCh,Script aRunScript,const gfxFontStyle * aStyle)516 gfxPlatformFontList::SystemFindFontForChar(uint32_t aCh, uint32_t aNextCh,
517                                            Script aRunScript,
518                                            const gfxFontStyle* aStyle)
519  {
520     gfxFontEntry* fontEntry = nullptr;
521 
522     // is codepoint with no matching font? return null immediately
523     if (mCodepointsWithNoFonts.test(aCh)) {
524         return nullptr;
525     }
526 
527     // Try to short-circuit font fallback for U+FFFD, used to represent
528     // encoding errors: just use cached family from last time U+FFFD was seen.
529     // This helps speed up pages with lots of encoding errors, binary-as-text,
530     // etc.
531     if (aCh == 0xFFFD && mReplacementCharFallbackFamily) {
532         bool needsBold;  // ignored in the system fallback case
533 
534         fontEntry =
535             mReplacementCharFallbackFamily->FindFontForStyle(*aStyle,
536                                                              needsBold);
537 
538         // this should never fail, as we must have found U+FFFD in order to set
539         // mReplacementCharFallbackFamily at all, but better play it safe
540         if (fontEntry && fontEntry->HasCharacter(aCh)) {
541             return fontEntry;
542         }
543     }
544 
545     TimeStamp start = TimeStamp::Now();
546 
547     // search commonly available fonts
548     bool common = true;
549     gfxFontFamily *fallbackFamily = nullptr;
550     fontEntry = CommonFontFallback(aCh, aNextCh, aRunScript, aStyle,
551                                    &fallbackFamily);
552 
553     // if didn't find a font, do system-wide fallback (except for specials)
554     uint32_t cmapCount = 0;
555     if (!fontEntry) {
556         common = false;
557         fontEntry = GlobalFontFallback(aCh, aRunScript, aStyle, cmapCount,
558                                        &fallbackFamily);
559     }
560     TimeDuration elapsed = TimeStamp::Now() - start;
561 
562     LogModule* log = gfxPlatform::GetLog(eGfxLog_textrun);
563 
564     if (MOZ_UNLIKELY(MOZ_LOG_TEST(log, LogLevel::Warning))) {
565         uint32_t unicodeRange = FindCharUnicodeRange(aCh);
566         Script script = mozilla::unicode::GetScriptCode(aCh);
567         MOZ_LOG(log, LogLevel::Warning,\
568                ("(textrun-systemfallback-%s) char: u+%6.6x "
569                  "unicode-range: %d script: %d match: [%s]"
570                 " time: %dus cmaps: %d\n",
571                 (common ? "common" : "global"), aCh,
572                  unicodeRange, script,
573                 (fontEntry ? NS_ConvertUTF16toUTF8(fontEntry->Name()).get() :
574                     "<none>"),
575                 int32_t(elapsed.ToMicroseconds()),
576                 cmapCount));
577     }
578 
579     // no match? add to set of non-matching codepoints
580     if (!fontEntry) {
581         mCodepointsWithNoFonts.set(aCh);
582     } else if (aCh == 0xFFFD && fontEntry && fallbackFamily) {
583         mReplacementCharFallbackFamily = fallbackFamily;
584     }
585 
586     // track system fallback time
587     static bool first = true;
588     int32_t intElapsed = int32_t(first ? elapsed.ToMilliseconds() :
589                                          elapsed.ToMicroseconds());
590     Telemetry::Accumulate((first ? Telemetry::SYSTEM_FONT_FALLBACK_FIRST :
591                                    Telemetry::SYSTEM_FONT_FALLBACK),
592                           intElapsed);
593     first = false;
594 
595     // track the script for which fallback occurred (incremented one make it
596     // 1-based)
597     Telemetry::Accumulate(Telemetry::SYSTEM_FONT_FALLBACK_SCRIPT,
598                           int(aRunScript) + 1);
599 
600     return fontEntry;
601 }
602 
603 #define NUM_FALLBACK_FONTS        8
604 
605 gfxFontEntry*
CommonFontFallback(uint32_t aCh,uint32_t aNextCh,Script aRunScript,const gfxFontStyle * aMatchStyle,gfxFontFamily ** aMatchedFamily)606 gfxPlatformFontList::CommonFontFallback(uint32_t aCh, uint32_t aNextCh,
607                                         Script aRunScript,
608                                         const gfxFontStyle* aMatchStyle,
609                                         gfxFontFamily** aMatchedFamily)
610 {
611     AutoTArray<const char*,NUM_FALLBACK_FONTS> defaultFallbacks;
612     uint32_t i, numFallbacks;
613 
614     gfxPlatform::GetPlatform()->GetCommonFallbackFonts(aCh, aNextCh,
615                                                        aRunScript,
616                                                        defaultFallbacks);
617     numFallbacks = defaultFallbacks.Length();
618     for (i = 0; i < numFallbacks; i++) {
619         nsAutoString familyName;
620         const char *fallbackFamily = defaultFallbacks[i];
621 
622         familyName.AppendASCII(fallbackFamily);
623         gfxFontFamily *fallback = FindFamilyByCanonicalName(familyName);
624         if (!fallback)
625             continue;
626 
627         gfxFontEntry *fontEntry;
628         bool needsBold;  // ignored in the system fallback case
629 
630         // use first font in list that supports a given character
631         fontEntry = fallback->FindFontForStyle(*aMatchStyle, needsBold);
632         if (fontEntry && fontEntry->HasCharacter(aCh)) {
633             *aMatchedFamily = fallback;
634             return fontEntry;
635         }
636     }
637 
638     return nullptr;
639 }
640 
641 gfxFontEntry*
GlobalFontFallback(const uint32_t aCh,Script aRunScript,const gfxFontStyle * aMatchStyle,uint32_t & aCmapCount,gfxFontFamily ** aMatchedFamily)642 gfxPlatformFontList::GlobalFontFallback(const uint32_t aCh,
643                                         Script aRunScript,
644                                         const gfxFontStyle* aMatchStyle,
645                                         uint32_t& aCmapCount,
646                                         gfxFontFamily** aMatchedFamily)
647 {
648     bool useCmaps = IsFontFamilyWhitelistActive() ||
649                     gfxPlatform::GetPlatform()->UseCmapsDuringSystemFallback();
650     if (!useCmaps) {
651         // Allow platform-specific fallback code to try and find a usable font
652         gfxFontEntry* fe =
653             PlatformGlobalFontFallback(aCh, aRunScript, aMatchStyle,
654                                        aMatchedFamily);
655         if (fe) {
656             return fe;
657         }
658     }
659 
660     // otherwise, try to find it among local fonts
661     GlobalFontMatch data(aCh, aRunScript, aMatchStyle);
662 
663     // iterate over all font families to find a font that support the character
664     for (auto iter = mFontFamilies.Iter(); !iter.Done(); iter.Next()) {
665       RefPtr<gfxFontFamily>& family = iter.Data();
666       // evaluate all fonts in this family for a match
667       family->FindFontForChar(&data);
668     }
669 
670     aCmapCount = data.mCmapsTested;
671     *aMatchedFamily = data.mMatchedFamily;
672 
673     return data.mBestMatch;
674 }
675 
676 gfxFontFamily*
CheckFamily(gfxFontFamily * aFamily)677 gfxPlatformFontList::CheckFamily(gfxFontFamily *aFamily)
678 {
679     if (aFamily && !aFamily->HasStyles()) {
680         aFamily->FindStyleVariations();
681         aFamily->CheckForSimpleFamily();
682     }
683 
684     if (aFamily && aFamily->GetFontList().Length() == 0) {
685         // failed to load any faces for this family, so discard it
686         nsAutoString key;
687         GenerateFontListKey(aFamily->Name(), key);
688         mFontFamilies.Remove(key);
689         return nullptr;
690     }
691 
692     return aFamily;
693 }
694 
695 bool
FindAndAddFamilies(const nsAString & aFamily,nsTArray<gfxFontFamily * > * aOutput,gfxFontStyle * aStyle,gfxFloat aDevToCssSize)696 gfxPlatformFontList::FindAndAddFamilies(const nsAString& aFamily,
697                                         nsTArray<gfxFontFamily*>* aOutput,
698                                         gfxFontStyle* aStyle,
699                                         gfxFloat aDevToCssSize)
700 {
701     nsAutoString key;
702     GenerateFontListKey(aFamily, key);
703 
704     NS_ASSERTION(mFontFamilies.Count() != 0, "system font list was not initialized correctly");
705 
706     // lookup in canonical (i.e. English) family name list
707     gfxFontFamily *familyEntry = mFontFamilies.GetWeak(key);
708 
709     // if not found, lookup in other family names list (mostly localized names)
710     if (!familyEntry) {
711         familyEntry = mOtherFamilyNames.GetWeak(key);
712     }
713 
714     // if still not found and other family names not yet fully initialized,
715     // initialize the rest of the list and try again.  this is done lazily
716     // since reading name table entries is expensive.
717     // although ASCII localized family names are possible they don't occur
718     // in practice so avoid pulling in names at startup
719     if (!familyEntry && !mOtherFamilyNamesInitialized && !IsASCII(aFamily)) {
720         InitOtherFamilyNames();
721         familyEntry = mOtherFamilyNames.GetWeak(key);
722         if (!familyEntry && !mOtherFamilyNamesInitialized) {
723             // localized family names load timed out, add name to list of
724             // names to check after localized names are loaded
725             if (!mOtherNamesMissed) {
726                 mOtherNamesMissed = MakeUnique<nsTHashtable<nsStringHashKey>>(2);
727             }
728             mOtherNamesMissed->PutEntry(key);
729         }
730     }
731 
732     familyEntry = CheckFamily(familyEntry);
733     if (familyEntry) {
734         aOutput->AppendElement(familyEntry);
735         return true;
736     }
737 
738     return false;
739 }
740 
741 gfxFontEntry*
FindFontForFamily(const nsAString & aFamily,const gfxFontStyle * aStyle,bool & aNeedsBold)742 gfxPlatformFontList::FindFontForFamily(const nsAString& aFamily, const gfxFontStyle* aStyle, bool& aNeedsBold)
743 {
744     gfxFontFamily *familyEntry = FindFamily(aFamily);
745 
746     aNeedsBold = false;
747 
748     if (familyEntry)
749         return familyEntry->FindFontForStyle(*aStyle, aNeedsBold);
750 
751     return nullptr;
752 }
753 
754 void
AddOtherFamilyName(gfxFontFamily * aFamilyEntry,nsAString & aOtherFamilyName)755 gfxPlatformFontList::AddOtherFamilyName(gfxFontFamily *aFamilyEntry, nsAString& aOtherFamilyName)
756 {
757     nsAutoString key;
758     GenerateFontListKey(aOtherFamilyName, key);
759 
760     if (!mOtherFamilyNames.GetWeak(key)) {
761         mOtherFamilyNames.Put(key, aFamilyEntry);
762         LOG_FONTLIST(("(fontlist-otherfamily) canonical family: %s, "
763                       "other family: %s\n",
764                       NS_ConvertUTF16toUTF8(aFamilyEntry->Name()).get(),
765                       NS_ConvertUTF16toUTF8(aOtherFamilyName).get()));
766         if (mBadUnderlineFamilyNames.Contains(key))
767             aFamilyEntry->SetBadUnderlineFamily();
768     }
769 }
770 
771 void
AddFullname(gfxFontEntry * aFontEntry,nsAString & aFullname)772 gfxPlatformFontList::AddFullname(gfxFontEntry *aFontEntry, nsAString& aFullname)
773 {
774     if (!mExtraNames->mFullnames.GetWeak(aFullname)) {
775         mExtraNames->mFullnames.Put(aFullname, aFontEntry);
776         LOG_FONTLIST(("(fontlist-fullname) name: %s, fullname: %s\n",
777                       NS_ConvertUTF16toUTF8(aFontEntry->Name()).get(),
778                       NS_ConvertUTF16toUTF8(aFullname).get()));
779     }
780 }
781 
782 void
AddPostscriptName(gfxFontEntry * aFontEntry,nsAString & aPostscriptName)783 gfxPlatformFontList::AddPostscriptName(gfxFontEntry *aFontEntry, nsAString& aPostscriptName)
784 {
785     if (!mExtraNames->mPostscriptNames.GetWeak(aPostscriptName)) {
786         mExtraNames->mPostscriptNames.Put(aPostscriptName, aFontEntry);
787         LOG_FONTLIST(("(fontlist-postscript) name: %s, psname: %s\n",
788                       NS_ConvertUTF16toUTF8(aFontEntry->Name()).get(),
789                       NS_ConvertUTF16toUTF8(aPostscriptName).get()));
790     }
791 }
792 
793 bool
GetStandardFamilyName(const nsAString & aFontName,nsAString & aFamilyName)794 gfxPlatformFontList::GetStandardFamilyName(const nsAString& aFontName, nsAString& aFamilyName)
795 {
796     aFamilyName.Truncate();
797     gfxFontFamily *ff = FindFamily(aFontName);
798     if (!ff) {
799         return false;
800     }
801     aFamilyName.Assign(ff->Name());
802     return true;
803 }
804 
805 gfxCharacterMap*
FindCharMap(gfxCharacterMap * aCmap)806 gfxPlatformFontList::FindCharMap(gfxCharacterMap *aCmap)
807 {
808     aCmap->CalcHash();
809     gfxCharacterMap *cmap = AddCmap(aCmap);
810     cmap->mShared = true;
811     return cmap;
812 }
813 
814 // add a cmap to the shared cmap set
815 gfxCharacterMap*
AddCmap(const gfxCharacterMap * aCharMap)816 gfxPlatformFontList::AddCmap(const gfxCharacterMap* aCharMap)
817 {
818     CharMapHashKey *found =
819         mSharedCmaps.PutEntry(const_cast<gfxCharacterMap*>(aCharMap));
820     return found->GetKey();
821 }
822 
823 // remove the cmap from the shared cmap set
824 void
RemoveCmap(const gfxCharacterMap * aCharMap)825 gfxPlatformFontList::RemoveCmap(const gfxCharacterMap* aCharMap)
826 {
827     // skip lookups during teardown
828     if (mSharedCmaps.Count() == 0) {
829         return;
830     }
831 
832     // cmap needs to match the entry *and* be the same ptr before removing
833     CharMapHashKey *found =
834         mSharedCmaps.GetEntry(const_cast<gfxCharacterMap*>(aCharMap));
835     if (found && found->GetKey() == aCharMap) {
836         mSharedCmaps.RemoveEntry(const_cast<gfxCharacterMap*>(aCharMap));
837     }
838 }
839 
840 void
ResolveGenericFontNames(FontFamilyType aGenericType,eFontPrefLang aPrefLang,nsTArray<RefPtr<gfxFontFamily>> * aGenericFamilies)841 gfxPlatformFontList::ResolveGenericFontNames(
842     FontFamilyType aGenericType,
843     eFontPrefLang aPrefLang,
844     nsTArray<RefPtr<gfxFontFamily>>* aGenericFamilies)
845 {
846     const char* langGroupStr = GetPrefLangName(aPrefLang);
847     const char* generic = GetGenericName(aGenericType);
848 
849     if (!generic) {
850         return;
851     }
852 
853     AutoTArray<nsString,4> genericFamilies;
854 
855     // load family for "font.name.generic.lang"
856     nsAutoCString prefFontName("font.name.");
857     prefFontName.Append(generic);
858     prefFontName.Append('.');
859     prefFontName.Append(langGroupStr);
860     gfxFontUtils::AppendPrefsFontList(prefFontName.get(), genericFamilies);
861 
862     // load fonts for "font.name-list.generic.lang"
863     nsAutoCString prefFontListName("font.name-list.");
864     prefFontListName.Append(generic);
865     prefFontListName.Append('.');
866     prefFontListName.Append(langGroupStr);
867     gfxFontUtils::AppendPrefsFontList(prefFontListName.get(), genericFamilies);
868 
869     nsIAtom* langGroup = GetLangGroupForPrefLang(aPrefLang);
870     NS_ASSERTION(langGroup, "null lang group for pref lang");
871 
872     // lookup and add platform fonts uniquely
873     for (const nsString& genericFamily : genericFamilies) {
874         gfxFontStyle style;
875         style.language = langGroup;
876         style.systemFont = false;
877         AutoTArray<gfxFontFamily*,10> families;
878         FindAndAddFamilies(genericFamily, &families, &style);
879         for (gfxFontFamily* f : families) {
880             if (!aGenericFamilies->Contains(f)) {
881                 aGenericFamilies->AppendElement(f);
882             }
883         }
884     }
885 
886 #if 0  // dump out generic mappings
887     printf("%s ===> ", prefFontName.get());
888     for (uint32_t k = 0; k < aGenericFamilies->Length(); k++) {
889         if (k > 0) printf(", ");
890         printf("%s", NS_ConvertUTF16toUTF8(aGenericFamilies[k]->Name()).get());
891     }
892     printf("\n");
893 #endif
894 }
895 
896 nsTArray<RefPtr<gfxFontFamily>>*
GetPrefFontsLangGroup(mozilla::FontFamilyType aGenericType,eFontPrefLang aPrefLang)897 gfxPlatformFontList::GetPrefFontsLangGroup(mozilla::FontFamilyType aGenericType,
898                                            eFontPrefLang aPrefLang)
899 {
900     // treat -moz-fixed as monospace
901     if (aGenericType == eFamily_moz_fixed) {
902         aGenericType = eFamily_monospace;
903     }
904 
905     PrefFontList* prefFonts =
906         mLangGroupPrefFonts[aPrefLang][aGenericType].get();
907     if (MOZ_UNLIKELY(!prefFonts)) {
908         prefFonts = new PrefFontList;
909         ResolveGenericFontNames(aGenericType, aPrefLang, prefFonts);
910         mLangGroupPrefFonts[aPrefLang][aGenericType].reset(prefFonts);
911     }
912     return prefFonts;
913 }
914 
915 void
AddGenericFonts(mozilla::FontFamilyType aGenericType,nsIAtom * aLanguage,nsTArray<gfxFontFamily * > & aFamilyList)916 gfxPlatformFontList::AddGenericFonts(mozilla::FontFamilyType aGenericType,
917                                      nsIAtom* aLanguage,
918                                      nsTArray<gfxFontFamily*>& aFamilyList)
919 {
920     // map lang ==> langGroup
921     nsIAtom* langGroup = GetLangGroup(aLanguage);
922 
923     // langGroup ==> prefLang
924     eFontPrefLang prefLang = GetFontPrefLangFor(langGroup);
925 
926     // lookup pref fonts
927     nsTArray<RefPtr<gfxFontFamily>>* prefFonts =
928         GetPrefFontsLangGroup(aGenericType, prefLang);
929 
930     if (!prefFonts->IsEmpty()) {
931         aFamilyList.AppendElements(*prefFonts);
932     }
933 }
934 
PrefLangToLangGroups(uint32_t aIndex)935 static nsIAtom* PrefLangToLangGroups(uint32_t aIndex)
936 {
937     // static array here avoids static constructor
938     static nsIAtom* gPrefLangToLangGroups[] = {
939         #define FONT_PREF_LANG(enum_id_, str_, atom_id_) nsGkAtoms::atom_id_
940         #include "gfxFontPrefLangList.h"
941         #undef FONT_PREF_LANG
942     };
943 
944     return aIndex < ArrayLength(gPrefLangToLangGroups)
945          ? gPrefLangToLangGroups[aIndex]
946          : nsGkAtoms::Unicode;
947 }
948 
949 eFontPrefLang
GetFontPrefLangFor(const char * aLang)950 gfxPlatformFontList::GetFontPrefLangFor(const char* aLang)
951 {
952     if (!aLang || !aLang[0]) {
953         return eFontPrefLang_Others;
954     }
955     for (uint32_t i = 0; i < ArrayLength(gPrefLangNames); ++i) {
956         if (!PL_strcasecmp(gPrefLangNames[i], aLang)) {
957             return eFontPrefLang(i);
958         }
959     }
960     return eFontPrefLang_Others;
961 }
962 
963 eFontPrefLang
GetFontPrefLangFor(nsIAtom * aLang)964 gfxPlatformFontList::GetFontPrefLangFor(nsIAtom *aLang)
965 {
966     if (!aLang)
967         return eFontPrefLang_Others;
968     nsAutoCString lang;
969     aLang->ToUTF8String(lang);
970     return GetFontPrefLangFor(lang.get());
971 }
972 
973 nsIAtom*
GetLangGroupForPrefLang(eFontPrefLang aLang)974 gfxPlatformFontList::GetLangGroupForPrefLang(eFontPrefLang aLang)
975 {
976     // the special CJK set pref lang should be resolved into separate
977     // calls to individual CJK pref langs before getting here
978     NS_ASSERTION(aLang != eFontPrefLang_CJKSet, "unresolved CJK set pref lang");
979 
980     return PrefLangToLangGroups(uint32_t(aLang));
981 }
982 
983 const char*
GetPrefLangName(eFontPrefLang aLang)984 gfxPlatformFontList::GetPrefLangName(eFontPrefLang aLang)
985 {
986     if (uint32_t(aLang) < ArrayLength(gPrefLangNames)) {
987         return gPrefLangNames[uint32_t(aLang)];
988     }
989     return nullptr;
990 }
991 
992 eFontPrefLang
GetFontPrefLangFor(uint8_t aUnicodeRange)993 gfxPlatformFontList::GetFontPrefLangFor(uint8_t aUnicodeRange)
994 {
995     switch (aUnicodeRange) {
996         case kRangeSetLatin:   return eFontPrefLang_Western;
997         case kRangeCyrillic:   return eFontPrefLang_Cyrillic;
998         case kRangeGreek:      return eFontPrefLang_Greek;
999         case kRangeHebrew:     return eFontPrefLang_Hebrew;
1000         case kRangeArabic:     return eFontPrefLang_Arabic;
1001         case kRangeThai:       return eFontPrefLang_Thai;
1002         case kRangeKorean:     return eFontPrefLang_Korean;
1003         case kRangeJapanese:   return eFontPrefLang_Japanese;
1004         case kRangeSChinese:   return eFontPrefLang_ChineseCN;
1005         case kRangeTChinese:   return eFontPrefLang_ChineseTW;
1006         case kRangeDevanagari: return eFontPrefLang_Devanagari;
1007         case kRangeTamil:      return eFontPrefLang_Tamil;
1008         case kRangeArmenian:   return eFontPrefLang_Armenian;
1009         case kRangeBengali:    return eFontPrefLang_Bengali;
1010         case kRangeCanadian:   return eFontPrefLang_Canadian;
1011         case kRangeEthiopic:   return eFontPrefLang_Ethiopic;
1012         case kRangeGeorgian:   return eFontPrefLang_Georgian;
1013         case kRangeGujarati:   return eFontPrefLang_Gujarati;
1014         case kRangeGurmukhi:   return eFontPrefLang_Gurmukhi;
1015         case kRangeKhmer:      return eFontPrefLang_Khmer;
1016         case kRangeMalayalam:  return eFontPrefLang_Malayalam;
1017         case kRangeOriya:      return eFontPrefLang_Oriya;
1018         case kRangeTelugu:     return eFontPrefLang_Telugu;
1019         case kRangeKannada:    return eFontPrefLang_Kannada;
1020         case kRangeSinhala:    return eFontPrefLang_Sinhala;
1021         case kRangeTibetan:    return eFontPrefLang_Tibetan;
1022         case kRangeSetCJK:     return eFontPrefLang_CJKSet;
1023         default:               return eFontPrefLang_Others;
1024     }
1025 }
1026 
1027 bool
IsLangCJK(eFontPrefLang aLang)1028 gfxPlatformFontList::IsLangCJK(eFontPrefLang aLang)
1029 {
1030     switch (aLang) {
1031         case eFontPrefLang_Japanese:
1032         case eFontPrefLang_ChineseTW:
1033         case eFontPrefLang_ChineseCN:
1034         case eFontPrefLang_ChineseHK:
1035         case eFontPrefLang_Korean:
1036         case eFontPrefLang_CJKSet:
1037             return true;
1038         default:
1039             return false;
1040     }
1041 }
1042 
1043 void
GetLangPrefs(eFontPrefLang aPrefLangs[],uint32_t & aLen,eFontPrefLang aCharLang,eFontPrefLang aPageLang)1044 gfxPlatformFontList::GetLangPrefs(eFontPrefLang aPrefLangs[], uint32_t &aLen, eFontPrefLang aCharLang, eFontPrefLang aPageLang)
1045 {
1046     if (IsLangCJK(aCharLang)) {
1047         AppendCJKPrefLangs(aPrefLangs, aLen, aCharLang, aPageLang);
1048     } else {
1049         AppendPrefLang(aPrefLangs, aLen, aCharLang);
1050     }
1051 
1052     AppendPrefLang(aPrefLangs, aLen, eFontPrefLang_Others);
1053 }
1054 
1055 void
AppendCJKPrefLangs(eFontPrefLang aPrefLangs[],uint32_t & aLen,eFontPrefLang aCharLang,eFontPrefLang aPageLang)1056 gfxPlatformFontList::AppendCJKPrefLangs(eFontPrefLang aPrefLangs[], uint32_t &aLen, eFontPrefLang aCharLang, eFontPrefLang aPageLang)
1057 {
1058     // prefer the lang specified by the page *if* CJK
1059     if (IsLangCJK(aPageLang)) {
1060         AppendPrefLang(aPrefLangs, aLen, aPageLang);
1061     }
1062 
1063     // if not set up, set up the default CJK order, based on accept lang settings and locale
1064     if (mCJKPrefLangs.Length() == 0) {
1065 
1066         // temp array
1067         eFontPrefLang tempPrefLangs[kMaxLenPrefLangList];
1068         uint32_t tempLen = 0;
1069 
1070         // Add the CJK pref fonts from accept languages, the order should be same order
1071         nsAdoptingCString list = Preferences::GetLocalizedCString("intl.accept_languages");
1072         if (!list.IsEmpty()) {
1073             const char kComma = ',';
1074             const char *p, *p_end;
1075             list.BeginReading(p);
1076             list.EndReading(p_end);
1077             while (p < p_end) {
1078                 while (nsCRT::IsAsciiSpace(*p)) {
1079                     if (++p == p_end)
1080                         break;
1081                 }
1082                 if (p == p_end)
1083                     break;
1084                 const char *start = p;
1085                 while (++p != p_end && *p != kComma)
1086                     /* nothing */ ;
1087                 nsAutoCString lang(Substring(start, p));
1088                 lang.CompressWhitespace(false, true);
1089                 eFontPrefLang fpl = gfxPlatformFontList::GetFontPrefLangFor(lang.get());
1090                 switch (fpl) {
1091                     case eFontPrefLang_Japanese:
1092                     case eFontPrefLang_Korean:
1093                     case eFontPrefLang_ChineseCN:
1094                     case eFontPrefLang_ChineseHK:
1095                     case eFontPrefLang_ChineseTW:
1096                         AppendPrefLang(tempPrefLangs, tempLen, fpl);
1097                         break;
1098                     default:
1099                         break;
1100                 }
1101                 p++;
1102             }
1103         }
1104 
1105         do { // to allow 'break' to abort this block if a call fails
1106             nsresult rv;
1107             nsCOMPtr<nsILocaleService> ls =
1108                 do_GetService(NS_LOCALESERVICE_CONTRACTID, &rv);
1109             if (NS_FAILED(rv))
1110                 break;
1111 
1112             nsCOMPtr<nsILocale> appLocale;
1113             rv = ls->GetApplicationLocale(getter_AddRefs(appLocale));
1114             if (NS_FAILED(rv))
1115                 break;
1116 
1117             nsString localeStr;
1118             rv = appLocale->
1119                 GetCategory(NS_LITERAL_STRING(NSILOCALE_MESSAGE), localeStr);
1120             if (NS_FAILED(rv))
1121                 break;
1122 
1123             const nsAString& lang = Substring(localeStr, 0, 2);
1124             if (lang.EqualsLiteral("ja")) {
1125                 AppendPrefLang(tempPrefLangs, tempLen, eFontPrefLang_Japanese);
1126             } else if (lang.EqualsLiteral("zh")) {
1127                 const nsAString& region = Substring(localeStr, 3, 2);
1128                 if (region.EqualsLiteral("CN")) {
1129                     AppendPrefLang(tempPrefLangs, tempLen, eFontPrefLang_ChineseCN);
1130                 } else if (region.EqualsLiteral("TW")) {
1131                     AppendPrefLang(tempPrefLangs, tempLen, eFontPrefLang_ChineseTW);
1132                 } else if (region.EqualsLiteral("HK")) {
1133                     AppendPrefLang(tempPrefLangs, tempLen, eFontPrefLang_ChineseHK);
1134                 }
1135             } else if (lang.EqualsLiteral("ko")) {
1136                 AppendPrefLang(tempPrefLangs, tempLen, eFontPrefLang_Korean);
1137             }
1138         } while (0);
1139 
1140         // last resort... (the order is same as old gfx.)
1141         AppendPrefLang(tempPrefLangs, tempLen, eFontPrefLang_Japanese);
1142         AppendPrefLang(tempPrefLangs, tempLen, eFontPrefLang_Korean);
1143         AppendPrefLang(tempPrefLangs, tempLen, eFontPrefLang_ChineseCN);
1144         AppendPrefLang(tempPrefLangs, tempLen, eFontPrefLang_ChineseHK);
1145         AppendPrefLang(tempPrefLangs, tempLen, eFontPrefLang_ChineseTW);
1146 
1147         // copy into the cached array
1148         uint32_t j;
1149         for (j = 0; j < tempLen; j++) {
1150             mCJKPrefLangs.AppendElement(tempPrefLangs[j]);
1151         }
1152     }
1153 
1154     // append in cached CJK langs
1155     uint32_t  i, numCJKlangs = mCJKPrefLangs.Length();
1156 
1157     for (i = 0; i < numCJKlangs; i++) {
1158         AppendPrefLang(aPrefLangs, aLen, (eFontPrefLang) (mCJKPrefLangs[i]));
1159     }
1160 
1161 }
1162 
1163 void
AppendPrefLang(eFontPrefLang aPrefLangs[],uint32_t & aLen,eFontPrefLang aAddLang)1164 gfxPlatformFontList::AppendPrefLang(eFontPrefLang aPrefLangs[], uint32_t& aLen, eFontPrefLang aAddLang)
1165 {
1166     if (aLen >= kMaxLenPrefLangList) return;
1167 
1168     // make sure
1169     uint32_t  i = 0;
1170     while (i < aLen && aPrefLangs[i] != aAddLang) {
1171         i++;
1172     }
1173 
1174     if (i == aLen) {
1175         aPrefLangs[aLen] = aAddLang;
1176         aLen++;
1177     }
1178 }
1179 
1180 mozilla::FontFamilyType
GetDefaultGeneric(eFontPrefLang aLang)1181 gfxPlatformFontList::GetDefaultGeneric(eFontPrefLang aLang)
1182 {
1183     // initialize lang group pref font defaults (i.e. serif/sans-serif)
1184     if (MOZ_UNLIKELY(mDefaultGenericsLangGroup.IsEmpty())) {
1185         mDefaultGenericsLangGroup.AppendElements(ArrayLength(gPrefLangNames));
1186         for (uint32_t i = 0; i < ArrayLength(gPrefLangNames); i++) {
1187             nsAutoCString prefDefaultFontType("font.default.");
1188             prefDefaultFontType.Append(GetPrefLangName(eFontPrefLang(i)));
1189             nsAdoptingCString serifOrSans =
1190                 Preferences::GetCString(prefDefaultFontType.get());
1191             if (serifOrSans.EqualsLiteral("sans-serif")) {
1192                 mDefaultGenericsLangGroup[i] = eFamily_sans_serif;
1193             } else {
1194                 mDefaultGenericsLangGroup[i] = eFamily_serif;
1195             }
1196         }
1197     }
1198 
1199     if (uint32_t(aLang) < ArrayLength(gPrefLangNames)) {
1200         return mDefaultGenericsLangGroup[uint32_t(aLang)];
1201     }
1202     return eFamily_serif;
1203 }
1204 
1205 
1206 gfxFontFamily*
GetDefaultFont(const gfxFontStyle * aStyle)1207 gfxPlatformFontList::GetDefaultFont(const gfxFontStyle* aStyle)
1208 {
1209     gfxFontFamily* family = GetDefaultFontForPlatform(aStyle);
1210     if (family) {
1211         return family;
1212     }
1213     // Something has gone wrong and we were unable to retrieve a default font
1214     // from the platform. (Likely the whitelist has blocked all potential
1215     // default fonts.) As a last resort, we return the first font listed in
1216     // mFontFamilies.
1217     return mFontFamilies.Iter().Data();
1218 }
1219 
1220 void
GetFontFamilyNames(nsTArray<nsString> & aFontFamilyNames)1221 gfxPlatformFontList::GetFontFamilyNames(nsTArray<nsString>& aFontFamilyNames)
1222 {
1223     for (auto iter = mFontFamilies.Iter(); !iter.Done(); iter.Next()) {
1224         RefPtr<gfxFontFamily>& family = iter.Data();
1225         aFontFamilyNames.AppendElement(family->Name());
1226     }
1227 }
1228 
1229 nsILanguageAtomService*
GetLangService()1230 gfxPlatformFontList::GetLangService()
1231 {
1232     if (!mLangService) {
1233         mLangService = do_GetService(NS_LANGUAGEATOMSERVICE_CONTRACTID);
1234     }
1235     NS_ASSERTION(mLangService, "no language service!");
1236     return mLangService;
1237 }
1238 
1239 nsIAtom*
GetLangGroup(nsIAtom * aLanguage)1240 gfxPlatformFontList::GetLangGroup(nsIAtom* aLanguage)
1241 {
1242     // map lang ==> langGroup
1243     nsIAtom *langGroup = nullptr;
1244     if (aLanguage) {
1245         nsresult rv;
1246         nsILanguageAtomService* langService = GetLangService();
1247         langGroup = langService->GetLanguageGroup(aLanguage, &rv);
1248     }
1249     if (!langGroup) {
1250         langGroup = nsGkAtoms::Unicode;
1251     }
1252     return langGroup;
1253 }
1254 
1255 /* static */ const char*
GetGenericName(FontFamilyType aGenericType)1256 gfxPlatformFontList::GetGenericName(FontFamilyType aGenericType)
1257 {
1258     static const char kGeneric_serif[] = "serif";
1259     static const char kGeneric_sans_serif[] = "sans-serif";
1260     static const char kGeneric_monospace[] = "monospace";
1261     static const char kGeneric_cursive[] = "cursive";
1262     static const char kGeneric_fantasy[] = "fantasy";
1263 
1264     // type should be standard generic type at this point
1265     NS_ASSERTION(aGenericType >= eFamily_serif &&
1266                  aGenericType <= eFamily_fantasy,
1267                  "standard generic font family type required");
1268 
1269     // map generic type to string
1270     const char *generic = nullptr;
1271     switch (aGenericType) {
1272         case eFamily_serif:
1273             generic = kGeneric_serif;
1274             break;
1275         case eFamily_sans_serif:
1276             generic = kGeneric_sans_serif;
1277             break;
1278         case eFamily_monospace:
1279             generic = kGeneric_monospace;
1280             break;
1281         case eFamily_cursive:
1282             generic = kGeneric_cursive;
1283             break;
1284         case eFamily_fantasy:
1285             generic = kGeneric_fantasy;
1286             break;
1287         default:
1288             break;
1289     }
1290 
1291     return generic;
1292 }
1293 
1294 // mapping of moz lang groups ==> default lang
1295 struct MozLangGroupData {
1296     nsIAtom* const& mozLangGroup;
1297     const char *defaultLang;
1298 };
1299 
1300 const MozLangGroupData MozLangGroups[] = {
1301     { nsGkAtoms::x_western,      "en" },
1302     { nsGkAtoms::x_cyrillic,     "ru" },
1303     { nsGkAtoms::x_devanagari,   "hi" },
1304     { nsGkAtoms::x_tamil,        "ta" },
1305     { nsGkAtoms::x_armn,         "hy" },
1306     { nsGkAtoms::x_beng,         "bn" },
1307     { nsGkAtoms::x_cans,         "iu" },
1308     { nsGkAtoms::x_ethi,         "am" },
1309     { nsGkAtoms::x_geor,         "ka" },
1310     { nsGkAtoms::x_gujr,         "gu" },
1311     { nsGkAtoms::x_guru,         "pa" },
1312     { nsGkAtoms::x_khmr,         "km" },
1313     { nsGkAtoms::x_knda,         "kn" },
1314     { nsGkAtoms::x_mlym,         "ml" },
1315     { nsGkAtoms::x_orya,         "or" },
1316     { nsGkAtoms::x_sinh,         "si" },
1317     { nsGkAtoms::x_tamil,        "ta" },
1318     { nsGkAtoms::x_telu,         "te" },
1319     { nsGkAtoms::x_tibt,         "bo" },
1320     { nsGkAtoms::Unicode,        0    }
1321 };
1322 
1323 bool
TryLangForGroup(const nsACString & aOSLang,nsIAtom * aLangGroup,nsACString & aFcLang)1324 gfxPlatformFontList::TryLangForGroup(const nsACString& aOSLang,
1325                                        nsIAtom* aLangGroup,
1326                                        nsACString& aFcLang)
1327 {
1328     // Truncate at '.' or '@' from aOSLang, and convert '_' to '-'.
1329     // aOSLang is in the form "language[_territory][.codeset][@modifier]".
1330     // fontconfig takes languages in the form "language-territory".
1331     // nsILanguageAtomService takes languages in the form language-subtag,
1332     // where subtag may be a territory.  fontconfig and nsILanguageAtomService
1333     // handle case-conversion for us.
1334     const char *pos, *end;
1335     aOSLang.BeginReading(pos);
1336     aOSLang.EndReading(end);
1337     aFcLang.Truncate();
1338     while (pos < end) {
1339         switch (*pos) {
1340             case '.':
1341             case '@':
1342                 end = pos;
1343                 break;
1344             case '_':
1345                 aFcLang.Append('-');
1346                 break;
1347             default:
1348                 aFcLang.Append(*pos);
1349         }
1350         ++pos;
1351     }
1352 
1353     nsILanguageAtomService* langService = GetLangService();
1354     nsIAtom *atom = langService->LookupLanguage(aFcLang);
1355     return atom == aLangGroup;
1356 }
1357 
1358 void
GetSampleLangForGroup(nsIAtom * aLanguage,nsACString & aLangStr,bool aCheckEnvironment)1359 gfxPlatformFontList::GetSampleLangForGroup(nsIAtom* aLanguage,
1360                                              nsACString& aLangStr,
1361                                              bool aCheckEnvironment)
1362 {
1363     aLangStr.Truncate();
1364     if (!aLanguage) {
1365         return;
1366     }
1367 
1368     // set up lang string
1369     const MozLangGroupData *mozLangGroup = nullptr;
1370 
1371     // -- look it up in the list of moz lang groups
1372     for (unsigned int i = 0; i < ArrayLength(MozLangGroups); ++i) {
1373         if (aLanguage == MozLangGroups[i].mozLangGroup) {
1374             mozLangGroup = &MozLangGroups[i];
1375             break;
1376         }
1377     }
1378 
1379     // -- not a mozilla lang group? Just return the BCP47 string
1380     //    representation of the lang group
1381     if (!mozLangGroup) {
1382         // Not a special mozilla language group.
1383         // Use aLanguage as a language code.
1384         aLanguage->ToUTF8String(aLangStr);
1385         return;
1386     }
1387 
1388     // -- check the environment for the user's preferred language that
1389     //    corresponds to this mozilla lang group.
1390     if (aCheckEnvironment) {
1391         const char *languages = getenv("LANGUAGE");
1392         if (languages) {
1393             const char separator = ':';
1394 
1395             for (const char *pos = languages; true; ++pos) {
1396                 if (*pos == '\0' || *pos == separator) {
1397                     if (languages < pos &&
1398                         TryLangForGroup(Substring(languages, pos),
1399                                         aLanguage, aLangStr))
1400                         return;
1401 
1402                     if (*pos == '\0')
1403                         break;
1404 
1405                     languages = pos + 1;
1406                 }
1407             }
1408         }
1409         const char *ctype = setlocale(LC_CTYPE, nullptr);
1410         if (ctype &&
1411             TryLangForGroup(nsDependentCString(ctype), aLanguage, aLangStr)) {
1412             return;
1413         }
1414     }
1415 
1416     if (mozLangGroup->defaultLang) {
1417         aLangStr.Assign(mozLangGroup->defaultLang);
1418     } else {
1419         aLangStr.Truncate();
1420     }
1421 }
1422 
1423 void
InitLoader()1424 gfxPlatformFontList::InitLoader()
1425 {
1426     GetFontFamilyNames(mFontInfo->mFontFamiliesToLoad);
1427     mStartIndex = 0;
1428     mNumFamilies = mFontInfo->mFontFamiliesToLoad.Length();
1429     memset(&(mFontInfo->mLoadStats), 0, sizeof(mFontInfo->mLoadStats));
1430 }
1431 
1432 #define FONT_LOADER_MAX_TIMESLICE 100  // max time for one pass through RunLoader = 100ms
1433 
1434 bool
LoadFontInfo()1435 gfxPlatformFontList::LoadFontInfo()
1436 {
1437     TimeStamp start = TimeStamp::Now();
1438     uint32_t i, endIndex = mNumFamilies;
1439     bool loadCmaps = !UsesSystemFallback() ||
1440         gfxPlatform::GetPlatform()->UseCmapsDuringSystemFallback();
1441 
1442     // for each font family, load in various font info
1443     for (i = mStartIndex; i < endIndex; i++) {
1444         nsAutoString key;
1445         gfxFontFamily *familyEntry;
1446         GenerateFontListKey(mFontInfo->mFontFamiliesToLoad[i], key);
1447 
1448         // lookup in canonical (i.e. English) family name list
1449         if (!(familyEntry = mFontFamilies.GetWeak(key))) {
1450             continue;
1451         }
1452 
1453         // read in face names
1454         familyEntry->ReadFaceNames(this, NeedFullnamePostscriptNames(), mFontInfo);
1455 
1456         // load the cmaps if needed
1457         if (loadCmaps) {
1458             familyEntry->ReadAllCMAPs(mFontInfo);
1459         }
1460 
1461         // limit the time spent reading fonts in one pass
1462         TimeDuration elapsed = TimeStamp::Now() - start;
1463         if (elapsed.ToMilliseconds() > FONT_LOADER_MAX_TIMESLICE &&
1464                 i + 1 != endIndex) {
1465             endIndex = i + 1;
1466             break;
1467         }
1468     }
1469 
1470     mStartIndex = endIndex;
1471     bool done = mStartIndex >= mNumFamilies;
1472 
1473     if (LOG_FONTINIT_ENABLED()) {
1474         TimeDuration elapsed = TimeStamp::Now() - start;
1475         LOG_FONTINIT(("(fontinit) fontloader load pass %8.2f ms done %s\n",
1476                       elapsed.ToMilliseconds(), (done ? "true" : "false")));
1477     }
1478 
1479     if (done) {
1480         mOtherFamilyNamesInitialized = true;
1481         mFaceNameListsInitialized = true;
1482     }
1483 
1484     return done;
1485 }
1486 
1487 void
CleanupLoader()1488 gfxPlatformFontList::CleanupLoader()
1489 {
1490     mFontFamiliesToLoad.Clear();
1491     mNumFamilies = 0;
1492     bool rebuilt = false, forceReflow = false;
1493 
1494     // if had missed face names that are now available, force reflow all
1495     if (mFaceNamesMissed) {
1496         for (auto it = mFaceNamesMissed->Iter(); !it.Done(); it.Next()) {
1497             if (FindFaceName(it.Get()->GetKey())) {
1498                 rebuilt = true;
1499                 RebuildLocalFonts();
1500                 break;
1501             }
1502         }
1503         mFaceNamesMissed = nullptr;
1504     }
1505 
1506     if (mOtherNamesMissed) {
1507         for (auto it = mOtherNamesMissed->Iter(); !it.Done(); it.Next()) {
1508             if (FindFamily(it.Get()->GetKey())) {
1509                 forceReflow = true;
1510                 ForceGlobalReflow();
1511                 break;
1512             }
1513         }
1514         mOtherNamesMissed = nullptr;
1515     }
1516 
1517     if (LOG_FONTINIT_ENABLED() && mFontInfo) {
1518         LOG_FONTINIT(("(fontinit) fontloader load thread took %8.2f ms "
1519                       "%d families %d fonts %d cmaps "
1520                       "%d facenames %d othernames %s %s",
1521                       mLoadTime.ToMilliseconds(),
1522                       mFontInfo->mLoadStats.families,
1523                       mFontInfo->mLoadStats.fonts,
1524                       mFontInfo->mLoadStats.cmaps,
1525                       mFontInfo->mLoadStats.facenames,
1526                       mFontInfo->mLoadStats.othernames,
1527                       (rebuilt ? "(userfont sets rebuilt)" : ""),
1528                       (forceReflow ? "(global reflow)" : "")));
1529     }
1530 
1531     gfxFontInfoLoader::CleanupLoader();
1532 }
1533 
1534 void
GetPrefsAndStartLoader()1535 gfxPlatformFontList::GetPrefsAndStartLoader()
1536 {
1537     mIncrement =
1538         std::max(1u, Preferences::GetUint(FONT_LOADER_FAMILIES_PER_SLICE_PREF));
1539 
1540     uint32_t delay =
1541         std::max(1u, Preferences::GetUint(FONT_LOADER_DELAY_PREF));
1542     uint32_t interval =
1543         std::max(1u, Preferences::GetUint(FONT_LOADER_INTERVAL_PREF));
1544 
1545     StartLoader(delay, interval);
1546 }
1547 
1548 void
ForceGlobalReflow()1549 gfxPlatformFontList::ForceGlobalReflow()
1550 {
1551     // modify a preference that will trigger reflow everywhere
1552     static const char kPrefName[] = "font.internaluseonly.changed";
1553     bool fontInternalChange = Preferences::GetBool(kPrefName, false);
1554     Preferences::SetBool(kPrefName, !fontInternalChange);
1555 }
1556 
1557 void
RebuildLocalFonts()1558 gfxPlatformFontList::RebuildLocalFonts()
1559 {
1560     for (auto it = mUserFontSetList.Iter(); !it.Done(); it.Next()) {
1561         it.Get()->GetKey()->RebuildLocalRules();
1562     }
1563 }
1564 
1565 void
ClearLangGroupPrefFonts()1566 gfxPlatformFontList::ClearLangGroupPrefFonts()
1567 {
1568     for (uint32_t i = eFontPrefLang_First;
1569          i < eFontPrefLang_First + eFontPrefLang_Count; i++) {
1570         auto& prefFontsLangGroup = mLangGroupPrefFonts[i];
1571         for (uint32_t j = eFamily_generic_first;
1572              j < eFamily_generic_first + eFamily_generic_count; j++) {
1573             prefFontsLangGroup[j] = nullptr;
1574         }
1575     }
1576 }
1577 
1578 // Support for memory reporting
1579 
1580 // this is also used by subclasses that hold additional font tables
1581 /*static*/ size_t
SizeOfFontFamilyTableExcludingThis(const FontFamilyTable & aTable,MallocSizeOf aMallocSizeOf)1582 gfxPlatformFontList::SizeOfFontFamilyTableExcludingThis(
1583     const FontFamilyTable& aTable,
1584     MallocSizeOf aMallocSizeOf)
1585 {
1586     size_t n = aTable.ShallowSizeOfExcludingThis(aMallocSizeOf);
1587     for (auto iter = aTable.ConstIter(); !iter.Done(); iter.Next()) {
1588         // We don't count the size of the family here, because this is an
1589         // *extra* reference to a family that will have already been counted in
1590         // the main list.
1591         n += iter.Key().SizeOfExcludingThisIfUnshared(aMallocSizeOf);
1592     }
1593     return n;
1594 }
1595 
1596 /*static*/ size_t
SizeOfFontEntryTableExcludingThis(const FontEntryTable & aTable,MallocSizeOf aMallocSizeOf)1597 gfxPlatformFontList::SizeOfFontEntryTableExcludingThis(
1598     const FontEntryTable& aTable,
1599     MallocSizeOf aMallocSizeOf)
1600 {
1601     size_t n = aTable.ShallowSizeOfExcludingThis(aMallocSizeOf);
1602     for (auto iter = aTable.ConstIter(); !iter.Done(); iter.Next()) {
1603         // The font itself is counted by its owning family; here we only care
1604         // about the names stored in the hashtable keys.
1605         n += iter.Key().SizeOfExcludingThisIfUnshared(aMallocSizeOf);
1606     }
1607     return n;
1608 }
1609 
1610 void
AddSizeOfExcludingThis(MallocSizeOf aMallocSizeOf,FontListSizes * aSizes) const1611 gfxPlatformFontList::AddSizeOfExcludingThis(MallocSizeOf aMallocSizeOf,
1612                                             FontListSizes* aSizes) const
1613 {
1614     aSizes->mFontListSize +=
1615         mFontFamilies.ShallowSizeOfExcludingThis(aMallocSizeOf);
1616     for (auto iter = mFontFamilies.ConstIter(); !iter.Done(); iter.Next()) {
1617         aSizes->mFontListSize +=
1618             iter.Key().SizeOfExcludingThisIfUnshared(aMallocSizeOf);
1619         iter.Data()->AddSizeOfIncludingThis(aMallocSizeOf, aSizes);
1620     }
1621 
1622     aSizes->mFontListSize +=
1623         SizeOfFontFamilyTableExcludingThis(mOtherFamilyNames, aMallocSizeOf);
1624 
1625     if (mExtraNames) {
1626         aSizes->mFontListSize +=
1627             SizeOfFontEntryTableExcludingThis(mExtraNames->mFullnames,
1628                                               aMallocSizeOf);
1629         aSizes->mFontListSize +=
1630             SizeOfFontEntryTableExcludingThis(mExtraNames->mPostscriptNames,
1631                                               aMallocSizeOf);
1632     }
1633 
1634     for (uint32_t i = eFontPrefLang_First;
1635          i < eFontPrefLang_First + eFontPrefLang_Count; i++) {
1636         auto& prefFontsLangGroup = mLangGroupPrefFonts[i];
1637         for (uint32_t j = eFamily_generic_first;
1638              j < eFamily_generic_first + eFamily_generic_count; j++) {
1639             PrefFontList* pf = prefFontsLangGroup[j].get();
1640             if (pf) {
1641                 aSizes->mFontListSize +=
1642                     pf->ShallowSizeOfExcludingThis(aMallocSizeOf);
1643             }
1644         }
1645     }
1646 
1647     aSizes->mFontListSize +=
1648         mCodepointsWithNoFonts.SizeOfExcludingThis(aMallocSizeOf);
1649     aSizes->mFontListSize +=
1650         mFontFamiliesToLoad.ShallowSizeOfExcludingThis(aMallocSizeOf);
1651 
1652     aSizes->mFontListSize +=
1653         mBadUnderlineFamilyNames.SizeOfExcludingThis(aMallocSizeOf);
1654 
1655     aSizes->mFontListSize +=
1656         mSharedCmaps.ShallowSizeOfExcludingThis(aMallocSizeOf);
1657     for (auto iter = mSharedCmaps.ConstIter(); !iter.Done(); iter.Next()) {
1658         aSizes->mCharMapsSize +=
1659             iter.Get()->GetKey()->SizeOfIncludingThis(aMallocSizeOf);
1660     }
1661 }
1662 
1663 void
AddSizeOfIncludingThis(MallocSizeOf aMallocSizeOf,FontListSizes * aSizes) const1664 gfxPlatformFontList::AddSizeOfIncludingThis(MallocSizeOf aMallocSizeOf,
1665                                             FontListSizes* aSizes) const
1666 {
1667     aSizes->mFontListSize += aMallocSizeOf(this);
1668     AddSizeOfExcludingThis(aMallocSizeOf, aSizes);
1669 }
1670 
1671 bool
IsFontFamilyWhitelistActive()1672 gfxPlatformFontList::IsFontFamilyWhitelistActive()
1673 {
1674     return mFontFamilyWhitelistActive;
1675 }
1676 
1677 #undef LOG
1678 #undef LOG_ENABLED
1679