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