gfx/thebes/gfxPlatformFontList.cpp

branch
TOR_BUG_9701
changeset 15
b8a032363ba2
equal deleted inserted replaced
-1:000000000000 0:3f53e61e0763
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 #ifdef MOZ_LOGGING
7 #define FORCE_PR_LOG /* Allow logging in the release build */
8 #endif
9 #include "prlog.h"
10
11 #include "gfxPlatformFontList.h"
12 #include "gfxUserFontSet.h"
13
14 #include "nsUnicharUtils.h"
15 #include "nsUnicodeRange.h"
16 #include "nsUnicodeProperties.h"
17
18 #include "mozilla/Attributes.h"
19 #include "mozilla/Likely.h"
20 #include "mozilla/MemoryReporting.h"
21 #include "mozilla/Preferences.h"
22 #include "mozilla/Telemetry.h"
23 #include "mozilla/TimeStamp.h"
24 #include "mozilla/gfx/2D.h"
25
26 using namespace mozilla;
27
28 #ifdef PR_LOGGING
29
30 #define LOG_FONTLIST(args) PR_LOG(gfxPlatform::GetLog(eGfxLog_fontlist), \
31 PR_LOG_DEBUG, args)
32 #define LOG_FONTLIST_ENABLED() PR_LOG_TEST( \
33 gfxPlatform::GetLog(eGfxLog_fontlist), \
34 PR_LOG_DEBUG)
35 #define LOG_FONTINIT(args) PR_LOG(gfxPlatform::GetLog(eGfxLog_fontinit), \
36 PR_LOG_DEBUG, args)
37 #define LOG_FONTINIT_ENABLED() PR_LOG_TEST( \
38 gfxPlatform::GetLog(eGfxLog_fontinit), \
39 PR_LOG_DEBUG)
40
41 #endif // PR_LOGGING
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 class gfxFontListPrefObserver MOZ_FINAL : public nsIObserver {
104 public:
105 NS_DECL_ISUPPORTS
106 NS_DECL_NSIOBSERVER
107 };
108
109 static gfxFontListPrefObserver* gFontListPrefObserver = nullptr;
110
111 NS_IMPL_ISUPPORTS(gfxFontListPrefObserver, nsIObserver)
112
113 NS_IMETHODIMP
114 gfxFontListPrefObserver::Observe(nsISupports *aSubject,
115 const char *aTopic,
116 const char16_t *aData)
117 {
118 NS_ASSERTION(!strcmp(aTopic, NS_PREFBRANCH_PREFCHANGE_TOPIC_ID), "invalid topic");
119 // XXX this could be made to only clear out the cache for the prefs that were changed
120 // but it probably isn't that big a deal.
121 gfxPlatformFontList::PlatformFontList()->ClearPrefFonts();
122 gfxFontCache::GetCache()->AgeAllGenerations();
123 return NS_OK;
124 }
125
126 MOZ_DEFINE_MALLOC_SIZE_OF(FontListMallocSizeOf)
127
128 NS_IMPL_ISUPPORTS(gfxPlatformFontList::MemoryReporter, nsIMemoryReporter)
129
130 NS_IMETHODIMP
131 gfxPlatformFontList::MemoryReporter::CollectReports
132 (nsIMemoryReporterCallback* aCb,
133 nsISupports* aClosure)
134 {
135 FontListSizes sizes;
136 sizes.mFontListSize = 0;
137 sizes.mFontTableCacheSize = 0;
138 sizes.mCharMapsSize = 0;
139
140 gfxPlatformFontList::PlatformFontList()->AddSizeOfIncludingThis(&FontListMallocSizeOf,
141 &sizes);
142
143 aCb->Callback(EmptyCString(),
144 NS_LITERAL_CSTRING("explicit/gfx/font-list"),
145 KIND_HEAP, UNITS_BYTES, sizes.mFontListSize,
146 NS_LITERAL_CSTRING("Memory used to manage the list of font families and faces."),
147 aClosure);
148
149 aCb->Callback(EmptyCString(),
150 NS_LITERAL_CSTRING("explicit/gfx/font-charmaps"),
151 KIND_HEAP, UNITS_BYTES, sizes.mCharMapsSize,
152 NS_LITERAL_CSTRING("Memory used to record the character coverage of individual fonts."),
153 aClosure);
154
155 if (sizes.mFontTableCacheSize) {
156 aCb->Callback(EmptyCString(),
157 NS_LITERAL_CSTRING("explicit/gfx/font-tables"),
158 KIND_HEAP, UNITS_BYTES, sizes.mFontTableCacheSize,
159 NS_LITERAL_CSTRING("Memory used for cached font metrics and layout tables."),
160 aClosure);
161 }
162
163 return NS_OK;
164 }
165
166 gfxPlatformFontList::gfxPlatformFontList(bool aNeedFullnamePostscriptNames)
167 : mFontFamilies(100), mOtherFamilyNames(30),
168 mPrefFonts(10), mBadUnderlineFamilyNames(10), mSharedCmaps(16),
169 mStartIndex(0), mIncrement(1), mNumFamilies(0)
170 {
171 mOtherFamilyNamesInitialized = false;
172
173 if (aNeedFullnamePostscriptNames) {
174 mExtraNames = new ExtraNames();
175 }
176 mFaceNameListsInitialized = false;
177
178 LoadBadUnderlineList();
179
180 // pref changes notification setup
181 NS_ASSERTION(!gFontListPrefObserver,
182 "There has been font list pref observer already");
183 gFontListPrefObserver = new gfxFontListPrefObserver();
184 NS_ADDREF(gFontListPrefObserver);
185 Preferences::AddStrongObservers(gFontListPrefObserver, kObservedPrefs);
186
187 RegisterStrongMemoryReporter(new MemoryReporter());
188 }
189
190 gfxPlatformFontList::~gfxPlatformFontList()
191 {
192 mSharedCmaps.Clear();
193 NS_ASSERTION(gFontListPrefObserver, "There is no font list pref observer");
194 Preferences::RemoveObservers(gFontListPrefObserver, kObservedPrefs);
195 NS_RELEASE(gFontListPrefObserver);
196 }
197
198 nsresult
199 gfxPlatformFontList::InitFontList()
200 {
201 mFontFamilies.Clear();
202 mOtherFamilyNames.Clear();
203 mOtherFamilyNamesInitialized = false;
204 if (mExtraNames) {
205 mExtraNames->mFullnames.Clear();
206 mExtraNames->mPostscriptNames.Clear();
207 }
208 mFaceNameListsInitialized = false;
209 mPrefFonts.Clear();
210 mReplacementCharFallbackFamily = nullptr;
211 CancelLoader();
212
213 // initialize ranges of characters for which system-wide font search should be skipped
214 mCodepointsWithNoFonts.reset();
215 mCodepointsWithNoFonts.SetRange(0,0x1f); // C0 controls
216 mCodepointsWithNoFonts.SetRange(0x7f,0x9f); // C1 controls
217
218 sPlatformFontList = this;
219
220 return NS_OK;
221 }
222
223 void
224 gfxPlatformFontList::GenerateFontListKey(const nsAString& aKeyName, nsAString& aResult)
225 {
226 aResult = aKeyName;
227 ToLowerCase(aResult);
228 }
229
230 struct InitOtherNamesData {
231 InitOtherNamesData(gfxPlatformFontList *aFontList,
232 TimeStamp aStartTime)
233 : mFontList(aFontList), mStartTime(aStartTime), mTimedOut(false)
234 {}
235
236 gfxPlatformFontList *mFontList;
237 TimeStamp mStartTime;
238 bool mTimedOut;
239 };
240
241 void
242 gfxPlatformFontList::InitOtherFamilyNames()
243 {
244 if (mOtherFamilyNamesInitialized) {
245 return;
246 }
247
248 TimeStamp start = TimeStamp::Now();
249
250 // iterate over all font families and read in other family names
251 InitOtherNamesData otherNamesData(this, start);
252
253 mFontFamilies.Enumerate(gfxPlatformFontList::InitOtherFamilyNamesProc,
254 &otherNamesData);
255
256 if (!otherNamesData.mTimedOut) {
257 mOtherFamilyNamesInitialized = true;
258 }
259 TimeStamp end = TimeStamp::Now();
260 Telemetry::AccumulateTimeDelta(Telemetry::FONTLIST_INITOTHERFAMILYNAMES,
261 start, end);
262
263 #ifdef PR_LOGGING
264 if (LOG_FONTINIT_ENABLED()) {
265 TimeDuration elapsed = end - start;
266 LOG_FONTINIT(("(fontinit) InitOtherFamilyNames took %8.2f ms %s",
267 elapsed.ToMilliseconds(),
268 (otherNamesData.mTimedOut ? "timeout" : "")));
269 }
270 #endif
271 }
272
273 #define OTHERNAMES_TIMEOUT 200
274
275 PLDHashOperator
276 gfxPlatformFontList::InitOtherFamilyNamesProc(nsStringHashKey::KeyType aKey,
277 nsRefPtr<gfxFontFamily>& aFamilyEntry,
278 void* userArg)
279 {
280 InitOtherNamesData *data = static_cast<InitOtherNamesData*>(userArg);
281
282 aFamilyEntry->ReadOtherFamilyNames(data->mFontList);
283 TimeDuration elapsed = TimeStamp::Now() - data->mStartTime;
284 if (elapsed.ToMilliseconds() > OTHERNAMES_TIMEOUT) {
285 data->mTimedOut = true;
286 return PL_DHASH_STOP;
287 }
288 return PL_DHASH_NEXT;
289 }
290
291 struct ReadFaceNamesData {
292 ReadFaceNamesData(gfxPlatformFontList *aFontList, TimeStamp aStartTime)
293 : mFontList(aFontList), mStartTime(aStartTime), mTimedOut(false)
294 {}
295
296 gfxPlatformFontList *mFontList;
297 TimeStamp mStartTime;
298 bool mTimedOut;
299
300 // if mFirstChar is not empty, only load facenames for families
301 // that start with this character
302 nsString mFirstChar;
303 };
304
305 gfxFontEntry*
306 gfxPlatformFontList::SearchFamiliesForFaceName(const nsAString& aFaceName)
307 {
308 TimeStamp start = TimeStamp::Now();
309 gfxFontEntry *lookup = nullptr;
310
311 ReadFaceNamesData faceNameListsData(this, start);
312
313 // iterate over familes starting with the same letter
314 faceNameListsData.mFirstChar.Assign(aFaceName.CharAt(0));
315 ToLowerCase(faceNameListsData.mFirstChar);
316 mFontFamilies.Enumerate(gfxPlatformFontList::ReadFaceNamesProc,
317 &faceNameListsData);
318 lookup = FindFaceName(aFaceName);
319
320 TimeStamp end = TimeStamp::Now();
321 Telemetry::AccumulateTimeDelta(Telemetry::FONTLIST_INITFACENAMELISTS,
322 start, end);
323 #ifdef PR_LOGGING
324 if (LOG_FONTINIT_ENABLED()) {
325 TimeDuration elapsed = end - start;
326 LOG_FONTINIT(("(fontinit) SearchFamiliesForFaceName took %8.2f ms %s %s",
327 elapsed.ToMilliseconds(),
328 (lookup ? "found name" : ""),
329 (faceNameListsData.mTimedOut ? "timeout" : "")));
330 }
331 #endif
332
333 return lookup;
334 }
335
336 // time limit for loading facename lists (ms)
337 #define NAMELIST_TIMEOUT 200
338
339 PLDHashOperator
340 gfxPlatformFontList::ReadFaceNamesProc(nsStringHashKey::KeyType aKey,
341 nsRefPtr<gfxFontFamily>& aFamilyEntry,
342 void* userArg)
343 {
344 ReadFaceNamesData *data = static_cast<ReadFaceNamesData*>(userArg);
345 gfxPlatformFontList *fc = data->mFontList;
346
347 // when filtering, skip names that don't start with the filter character
348 if (!(data->mFirstChar.IsEmpty())) {
349 char16_t firstChar = aKey.CharAt(0);
350 nsAutoString firstCharStr(&firstChar, 1);
351 ToLowerCase(firstCharStr);
352 if (!firstCharStr.Equals(data->mFirstChar)) {
353 return PL_DHASH_NEXT;
354 }
355 }
356 aFamilyEntry->ReadFaceNames(fc, fc->NeedFullnamePostscriptNames());
357
358 TimeDuration elapsed = TimeStamp::Now() - data->mStartTime;
359 if (elapsed.ToMilliseconds() > NAMELIST_TIMEOUT) {
360 data->mTimedOut = true;
361 return PL_DHASH_STOP;
362 }
363 return PL_DHASH_NEXT;
364 }
365
366 gfxFontEntry*
367 gfxPlatformFontList::FindFaceName(const nsAString& aFaceName)
368 {
369 gfxFontEntry *lookup;
370
371 // lookup in name lookup tables, return null if not found
372 if (mExtraNames &&
373 ((lookup = mExtraNames->mPostscriptNames.GetWeak(aFaceName)) ||
374 (lookup = mExtraNames->mFullnames.GetWeak(aFaceName)))) {
375 return lookup;
376 }
377
378 return nullptr;
379 }
380
381 gfxFontEntry*
382 gfxPlatformFontList::LookupInFaceNameLists(const nsAString& aFaceName)
383 {
384 gfxFontEntry *lookup = nullptr;
385
386 // initialize facename lookup tables if needed
387 // note: this can terminate early or time out, in which case
388 // mFaceNameListsInitialized remains false
389 if (!mFaceNameListsInitialized) {
390 lookup = SearchFamiliesForFaceName(aFaceName);
391 if (lookup) {
392 return lookup;
393 }
394 }
395
396 // lookup in name lookup tables, return null if not found
397 if (!(lookup = FindFaceName(aFaceName))) {
398 // names not completely initialized, so keep track of lookup misses
399 if (!mFaceNameListsInitialized) {
400 if (!mFaceNamesMissed) {
401 mFaceNamesMissed = new nsTHashtable<nsStringHashKey>(4);
402 }
403 mFaceNamesMissed->PutEntry(aFaceName);
404 }
405 }
406
407 return lookup;
408 }
409
410 void
411 gfxPlatformFontList::PreloadNamesList()
412 {
413 nsAutoTArray<nsString, 10> preloadFonts;
414 gfxFontUtils::GetPrefsFontList("font.preload-names-list", preloadFonts);
415
416 uint32_t numFonts = preloadFonts.Length();
417 for (uint32_t i = 0; i < numFonts; i++) {
418 nsAutoString key;
419 GenerateFontListKey(preloadFonts[i], key);
420
421 // only search canonical names!
422 gfxFontFamily *familyEntry = mFontFamilies.GetWeak(key);
423 if (familyEntry) {
424 familyEntry->ReadOtherFamilyNames(this);
425 }
426 }
427
428 }
429
430 void
431 gfxPlatformFontList::SetFixedPitch(const nsAString& aFamilyName)
432 {
433 gfxFontFamily *family = FindFamily(aFamilyName);
434 if (!family) return;
435
436 family->FindStyleVariations();
437 nsTArray<nsRefPtr<gfxFontEntry> >& fontlist = family->GetFontList();
438
439 uint32_t i, numFonts = fontlist.Length();
440
441 for (i = 0; i < numFonts; i++) {
442 fontlist[i]->mFixedPitch = 1;
443 }
444 }
445
446 void
447 gfxPlatformFontList::LoadBadUnderlineList()
448 {
449 nsAutoTArray<nsString, 10> blacklist;
450 gfxFontUtils::GetPrefsFontList("font.blacklist.underline_offset", blacklist);
451 uint32_t numFonts = blacklist.Length();
452 for (uint32_t i = 0; i < numFonts; i++) {
453 nsAutoString key;
454 GenerateFontListKey(blacklist[i], key);
455 mBadUnderlineFamilyNames.PutEntry(key);
456 }
457 }
458
459 bool
460 gfxPlatformFontList::ResolveFontName(const nsAString& aFontName, nsAString& aResolvedFontName)
461 {
462 gfxFontFamily *family = FindFamily(aFontName);
463 if (family) {
464 aResolvedFontName = family->Name();
465 return true;
466 }
467 return false;
468 }
469
470 static PLDHashOperator
471 RebuildLocalFonts(nsPtrHashKey<gfxUserFontSet>* aKey,
472 void* aClosure)
473 {
474 aKey->GetKey()->RebuildLocalRules();
475 return PL_DHASH_NEXT;
476 }
477
478 void
479 gfxPlatformFontList::UpdateFontList()
480 {
481 InitFontList();
482 mUserFontSetList.EnumerateEntries(RebuildLocalFonts, nullptr);
483 }
484
485 struct FontListData {
486 FontListData(nsIAtom *aLangGroup,
487 const nsACString& aGenericFamily,
488 nsTArray<nsString>& aListOfFonts) :
489 mLangGroup(aLangGroup), mGenericFamily(aGenericFamily),
490 mListOfFonts(aListOfFonts) {}
491 nsIAtom *mLangGroup;
492 const nsACString& mGenericFamily;
493 nsTArray<nsString>& mListOfFonts;
494 };
495
496 PLDHashOperator
497 gfxPlatformFontList::HashEnumFuncForFamilies(nsStringHashKey::KeyType aKey,
498 nsRefPtr<gfxFontFamily>& aFamilyEntry,
499 void *aUserArg)
500 {
501 FontListData *data = static_cast<FontListData*>(aUserArg);
502
503 // use the first variation for now. This data should be the same
504 // for all the variations and should probably be moved up to
505 // the Family
506 gfxFontStyle style;
507 style.language = data->mLangGroup;
508 bool needsBold;
509 nsRefPtr<gfxFontEntry> aFontEntry = aFamilyEntry->FindFontForStyle(style, needsBold);
510 NS_ASSERTION(aFontEntry, "couldn't find any font entry in family");
511 if (!aFontEntry)
512 return PL_DHASH_NEXT;
513
514 /* skip symbol fonts */
515 if (aFontEntry->IsSymbolFont())
516 return PL_DHASH_NEXT;
517
518 if (aFontEntry->SupportsLangGroup(data->mLangGroup) &&
519 aFontEntry->MatchesGenericFamily(data->mGenericFamily)) {
520 nsAutoString localizedFamilyName;
521 aFamilyEntry->LocalizedName(localizedFamilyName);
522 data->mListOfFonts.AppendElement(localizedFamilyName);
523 }
524
525 return PL_DHASH_NEXT;
526 }
527
528 void
529 gfxPlatformFontList::GetFontList(nsIAtom *aLangGroup,
530 const nsACString& aGenericFamily,
531 nsTArray<nsString>& aListOfFonts)
532 {
533 FontListData data(aLangGroup, aGenericFamily, aListOfFonts);
534
535 mFontFamilies.Enumerate(gfxPlatformFontList::HashEnumFuncForFamilies, &data);
536
537 aListOfFonts.Sort();
538 aListOfFonts.Compact();
539 }
540
541 struct FontFamilyListData {
542 FontFamilyListData(nsTArray<nsRefPtr<gfxFontFamily> >& aFamilyArray)
543 : mFamilyArray(aFamilyArray)
544 {}
545
546 static PLDHashOperator AppendFamily(nsStringHashKey::KeyType aKey,
547 nsRefPtr<gfxFontFamily>& aFamilyEntry,
548 void *aUserArg)
549 {
550 FontFamilyListData *data = static_cast<FontFamilyListData*>(aUserArg);
551 data->mFamilyArray.AppendElement(aFamilyEntry);
552 return PL_DHASH_NEXT;
553 }
554
555 nsTArray<nsRefPtr<gfxFontFamily> >& mFamilyArray;
556 };
557
558 void
559 gfxPlatformFontList::GetFontFamilyList(nsTArray<nsRefPtr<gfxFontFamily> >& aFamilyArray)
560 {
561 FontFamilyListData data(aFamilyArray);
562 mFontFamilies.Enumerate(FontFamilyListData::AppendFamily, &data);
563 }
564
565 gfxFontEntry*
566 gfxPlatformFontList::SystemFindFontForChar(const uint32_t aCh,
567 int32_t aRunScript,
568 const gfxFontStyle* aStyle)
569 {
570 gfxFontEntry* fontEntry = nullptr;
571
572 // is codepoint with no matching font? return null immediately
573 if (mCodepointsWithNoFonts.test(aCh)) {
574 return nullptr;
575 }
576
577 // Try to short-circuit font fallback for U+FFFD, used to represent
578 // encoding errors: just use cached family from last time U+FFFD was seen.
579 // This helps speed up pages with lots of encoding errors, binary-as-text,
580 // etc.
581 if (aCh == 0xFFFD && mReplacementCharFallbackFamily) {
582 bool needsBold; // ignored in the system fallback case
583
584 fontEntry =
585 mReplacementCharFallbackFamily->FindFontForStyle(*aStyle,
586 needsBold);
587
588 // this should never fail, as we must have found U+FFFD in order to set
589 // mReplacementCharFallbackFamily at all, but better play it safe
590 if (fontEntry && fontEntry->TestCharacterMap(aCh)) {
591 return fontEntry;
592 }
593 }
594
595 TimeStamp start = TimeStamp::Now();
596
597 // search commonly available fonts
598 bool common = true;
599 gfxFontFamily *fallbackFamily = nullptr;
600 fontEntry = CommonFontFallback(aCh, aRunScript, aStyle, &fallbackFamily);
601
602 // if didn't find a font, do system-wide fallback (except for specials)
603 uint32_t cmapCount = 0;
604 if (!fontEntry) {
605 common = false;
606 fontEntry = GlobalFontFallback(aCh, aRunScript, aStyle, cmapCount,
607 &fallbackFamily);
608 }
609 TimeDuration elapsed = TimeStamp::Now() - start;
610
611 #ifdef PR_LOGGING
612 PRLogModuleInfo *log = gfxPlatform::GetLog(eGfxLog_textrun);
613
614 if (MOZ_UNLIKELY(PR_LOG_TEST(log, PR_LOG_WARNING))) {
615 uint32_t unicodeRange = FindCharUnicodeRange(aCh);
616 int32_t script = mozilla::unicode::GetScriptCode(aCh);
617 PR_LOG(log, PR_LOG_WARNING,\
618 ("(textrun-systemfallback-%s) char: u+%6.6x "
619 "unicode-range: %d script: %d match: [%s]"
620 " time: %dus cmaps: %d\n",
621 (common ? "common" : "global"), aCh,
622 unicodeRange, script,
623 (fontEntry ? NS_ConvertUTF16toUTF8(fontEntry->Name()).get() :
624 "<none>"),
625 int32_t(elapsed.ToMicroseconds()),
626 cmapCount));
627 }
628 #endif
629
630 // no match? add to set of non-matching codepoints
631 if (!fontEntry) {
632 mCodepointsWithNoFonts.set(aCh);
633 } else if (aCh == 0xFFFD && fontEntry && fallbackFamily) {
634 mReplacementCharFallbackFamily = fallbackFamily;
635 }
636
637 // track system fallback time
638 static bool first = true;
639 int32_t intElapsed = int32_t(first ? elapsed.ToMilliseconds() :
640 elapsed.ToMicroseconds());
641 Telemetry::Accumulate((first ? Telemetry::SYSTEM_FONT_FALLBACK_FIRST :
642 Telemetry::SYSTEM_FONT_FALLBACK),
643 intElapsed);
644 first = false;
645
646 // track the script for which fallback occurred (incremented one make it
647 // 1-based)
648 Telemetry::Accumulate(Telemetry::SYSTEM_FONT_FALLBACK_SCRIPT, aRunScript + 1);
649
650 return fontEntry;
651 }
652
653 PLDHashOperator
654 gfxPlatformFontList::FindFontForCharProc(nsStringHashKey::KeyType aKey, nsRefPtr<gfxFontFamily>& aFamilyEntry,
655 void *userArg)
656 {
657 GlobalFontMatch *data = static_cast<GlobalFontMatch*>(userArg);
658
659 // evaluate all fonts in this family for a match
660 aFamilyEntry->FindFontForChar(data);
661
662 return PL_DHASH_NEXT;
663 }
664
665 #define NUM_FALLBACK_FONTS 8
666
667 gfxFontEntry*
668 gfxPlatformFontList::CommonFontFallback(const uint32_t aCh,
669 int32_t aRunScript,
670 const gfxFontStyle* aMatchStyle,
671 gfxFontFamily** aMatchedFamily)
672 {
673 nsAutoTArray<const char*,NUM_FALLBACK_FONTS> defaultFallbacks;
674 uint32_t i, numFallbacks;
675
676 gfxPlatform::GetPlatform()->GetCommonFallbackFonts(aCh, aRunScript,
677 defaultFallbacks);
678 numFallbacks = defaultFallbacks.Length();
679 for (i = 0; i < numFallbacks; i++) {
680 nsAutoString familyName;
681 const char *fallbackFamily = defaultFallbacks[i];
682
683 familyName.AppendASCII(fallbackFamily);
684 gfxFontFamily *fallback =
685 gfxPlatformFontList::PlatformFontList()->FindFamily(familyName);
686 if (!fallback)
687 continue;
688
689 gfxFontEntry *fontEntry;
690 bool needsBold; // ignored in the system fallback case
691
692 // use first font in list that supports a given character
693 fontEntry = fallback->FindFontForStyle(*aMatchStyle, needsBold);
694 if (fontEntry && fontEntry->TestCharacterMap(aCh)) {
695 *aMatchedFamily = fallback;
696 return fontEntry;
697 }
698 }
699
700 return nullptr;
701 }
702
703 gfxFontEntry*
704 gfxPlatformFontList::GlobalFontFallback(const uint32_t aCh,
705 int32_t aRunScript,
706 const gfxFontStyle* aMatchStyle,
707 uint32_t& aCmapCount,
708 gfxFontFamily** aMatchedFamily)
709 {
710 // otherwise, try to find it among local fonts
711 GlobalFontMatch data(aCh, aRunScript, aMatchStyle);
712
713 // iterate over all font families to find a font that support the character
714 mFontFamilies.Enumerate(gfxPlatformFontList::FindFontForCharProc, &data);
715
716 aCmapCount = data.mCmapsTested;
717 *aMatchedFamily = data.mMatchedFamily;
718
719 return data.mBestMatch;
720 }
721
722 #ifdef XP_WIN
723 #include <windows.h>
724
725 // crude hack for using when monitoring process
726 static void LogRegistryEvent(const wchar_t *msg)
727 {
728 HKEY dummyKey;
729 HRESULT hr;
730 wchar_t buf[512];
731
732 wsprintfW(buf, L" log %s", msg);
733 hr = RegOpenKeyExW(HKEY_LOCAL_MACHINE, buf, 0, KEY_READ, &dummyKey);
734 if (SUCCEEDED(hr)) {
735 RegCloseKey(dummyKey);
736 }
737 }
738 #endif
739
740 gfxFontFamily*
741 gfxPlatformFontList::CheckFamily(gfxFontFamily *aFamily)
742 {
743 if (aFamily && !aFamily->HasStyles()) {
744 aFamily->FindStyleVariations();
745 aFamily->CheckForSimpleFamily();
746 }
747
748 if (aFamily && aFamily->GetFontList().Length() == 0) {
749 // failed to load any faces for this family, so discard it
750 nsAutoString key;
751 GenerateFontListKey(aFamily->Name(), key);
752 mFontFamilies.Remove(key);
753 return nullptr;
754 }
755
756 return aFamily;
757 }
758
759 gfxFontFamily*
760 gfxPlatformFontList::FindFamily(const nsAString& aFamily)
761 {
762 nsAutoString key;
763 gfxFontFamily *familyEntry;
764 GenerateFontListKey(aFamily, key);
765
766 NS_ASSERTION(mFontFamilies.Count() != 0, "system font list was not initialized correctly");
767
768 // lookup in canonical (i.e. English) family name list
769 if ((familyEntry = mFontFamilies.GetWeak(key))) {
770 return CheckFamily(familyEntry);
771 }
772
773 // lookup in other family names list (mostly localized names)
774 if ((familyEntry = mOtherFamilyNames.GetWeak(key)) != nullptr) {
775 return CheckFamily(familyEntry);
776 }
777
778 // name not found and other family names not yet fully initialized so
779 // initialize the rest of the list and try again. this is done lazily
780 // since reading name table entries is expensive.
781 // although ASCII localized family names are possible they don't occur
782 // in practice so avoid pulling in names at startup
783 if (!mOtherFamilyNamesInitialized && !IsASCII(aFamily)) {
784 InitOtherFamilyNames();
785 if ((familyEntry = mOtherFamilyNames.GetWeak(key)) != nullptr) {
786 return CheckFamily(familyEntry);
787 } else if (!mOtherFamilyNamesInitialized) {
788 // localized family names load timed out, add name to list of
789 // names to check after localized names are loaded
790 if (!mOtherNamesMissed) {
791 mOtherNamesMissed = new nsTHashtable<nsStringHashKey>(4);
792 }
793 mOtherNamesMissed->PutEntry(key);
794 }
795 }
796
797 return nullptr;
798 }
799
800 gfxFontEntry*
801 gfxPlatformFontList::FindFontForFamily(const nsAString& aFamily, const gfxFontStyle* aStyle, bool& aNeedsBold)
802 {
803 gfxFontFamily *familyEntry = FindFamily(aFamily);
804
805 aNeedsBold = false;
806
807 if (familyEntry)
808 return familyEntry->FindFontForStyle(*aStyle, aNeedsBold);
809
810 return nullptr;
811 }
812
813 bool
814 gfxPlatformFontList::GetPrefFontFamilyEntries(eFontPrefLang aLangGroup, nsTArray<nsRefPtr<gfxFontFamily> > *array)
815 {
816 return mPrefFonts.Get(uint32_t(aLangGroup), array);
817 }
818
819 void
820 gfxPlatformFontList::SetPrefFontFamilyEntries(eFontPrefLang aLangGroup, nsTArray<nsRefPtr<gfxFontFamily> >& array)
821 {
822 mPrefFonts.Put(uint32_t(aLangGroup), array);
823 }
824
825 void
826 gfxPlatformFontList::AddOtherFamilyName(gfxFontFamily *aFamilyEntry, nsAString& aOtherFamilyName)
827 {
828 nsAutoString key;
829 GenerateFontListKey(aOtherFamilyName, key);
830
831 if (!mOtherFamilyNames.GetWeak(key)) {
832 mOtherFamilyNames.Put(key, aFamilyEntry);
833 #ifdef PR_LOGGING
834 LOG_FONTLIST(("(fontlist-otherfamily) canonical family: %s, "
835 "other family: %s\n",
836 NS_ConvertUTF16toUTF8(aFamilyEntry->Name()).get(),
837 NS_ConvertUTF16toUTF8(aOtherFamilyName).get()));
838 #endif
839 if (mBadUnderlineFamilyNames.Contains(key))
840 aFamilyEntry->SetBadUnderlineFamily();
841 }
842 }
843
844 void
845 gfxPlatformFontList::AddFullname(gfxFontEntry *aFontEntry, nsAString& aFullname)
846 {
847 if (!mExtraNames->mFullnames.GetWeak(aFullname)) {
848 mExtraNames->mFullnames.Put(aFullname, aFontEntry);
849 #ifdef PR_LOGGING
850 LOG_FONTLIST(("(fontlist-fullname) name: %s, fullname: %s\n",
851 NS_ConvertUTF16toUTF8(aFontEntry->Name()).get(),
852 NS_ConvertUTF16toUTF8(aFullname).get()));
853 #endif
854 }
855 }
856
857 void
858 gfxPlatformFontList::AddPostscriptName(gfxFontEntry *aFontEntry, nsAString& aPostscriptName)
859 {
860 if (!mExtraNames->mPostscriptNames.GetWeak(aPostscriptName)) {
861 mExtraNames->mPostscriptNames.Put(aPostscriptName, aFontEntry);
862 #ifdef PR_LOGGING
863 LOG_FONTLIST(("(fontlist-postscript) name: %s, psname: %s\n",
864 NS_ConvertUTF16toUTF8(aFontEntry->Name()).get(),
865 NS_ConvertUTF16toUTF8(aPostscriptName).get()));
866 #endif
867 }
868 }
869
870 bool
871 gfxPlatformFontList::GetStandardFamilyName(const nsAString& aFontName, nsAString& aFamilyName)
872 {
873 aFamilyName.Truncate();
874 ResolveFontName(aFontName, aFamilyName);
875 return !aFamilyName.IsEmpty();
876 }
877
878 gfxCharacterMap*
879 gfxPlatformFontList::FindCharMap(gfxCharacterMap *aCmap)
880 {
881 aCmap->CalcHash();
882 gfxCharacterMap *cmap = AddCmap(aCmap);
883 cmap->mShared = true;
884 return cmap;
885 }
886
887 // add a cmap to the shared cmap set
888 gfxCharacterMap*
889 gfxPlatformFontList::AddCmap(const gfxCharacterMap* aCharMap)
890 {
891 CharMapHashKey *found =
892 mSharedCmaps.PutEntry(const_cast<gfxCharacterMap*>(aCharMap));
893 return found->GetKey();
894 }
895
896 // remove the cmap from the shared cmap set
897 void
898 gfxPlatformFontList::RemoveCmap(const gfxCharacterMap* aCharMap)
899 {
900 // skip lookups during teardown
901 if (mSharedCmaps.Count() == 0) {
902 return;
903 }
904
905 // cmap needs to match the entry *and* be the same ptr before removing
906 CharMapHashKey *found =
907 mSharedCmaps.GetEntry(const_cast<gfxCharacterMap*>(aCharMap));
908 if (found && found->GetKey() == aCharMap) {
909 mSharedCmaps.RemoveEntry(const_cast<gfxCharacterMap*>(aCharMap));
910 }
911 }
912
913 static PLDHashOperator AppendFamilyToList(nsStringHashKey::KeyType aKey,
914 nsRefPtr<gfxFontFamily>& aFamilyEntry,
915 void *aUserArg)
916 {
917 nsTArray<nsString> *familyNames = static_cast<nsTArray<nsString> *>(aUserArg);
918 familyNames->AppendElement(aFamilyEntry->Name());
919 return PL_DHASH_NEXT;
920 }
921
922 void
923 gfxPlatformFontList::GetFontFamilyNames(nsTArray<nsString>& aFontFamilyNames)
924 {
925 mFontFamilies.Enumerate(AppendFamilyToList, &aFontFamilyNames);
926 }
927
928 void
929 gfxPlatformFontList::InitLoader()
930 {
931 GetFontFamilyNames(mFontInfo->mFontFamiliesToLoad);
932 mStartIndex = 0;
933 mNumFamilies = mFontInfo->mFontFamiliesToLoad.Length();
934 memset(&(mFontInfo->mLoadStats), 0, sizeof(mFontInfo->mLoadStats));
935 }
936
937 #define FONT_LOADER_MAX_TIMESLICE 100 // max time for one pass through RunLoader = 100ms
938
939 bool
940 gfxPlatformFontList::LoadFontInfo()
941 {
942 TimeStamp start = TimeStamp::Now();
943 uint32_t i, endIndex = mNumFamilies;
944 bool loadCmaps = !UsesSystemFallback() ||
945 gfxPlatform::GetPlatform()->UseCmapsDuringSystemFallback();
946
947 // for each font family, load in various font info
948 for (i = mStartIndex; i < endIndex; i++) {
949 nsAutoString key;
950 gfxFontFamily *familyEntry;
951 GenerateFontListKey(mFontInfo->mFontFamiliesToLoad[i], key);
952
953 // lookup in canonical (i.e. English) family name list
954 if (!(familyEntry = mFontFamilies.GetWeak(key))) {
955 continue;
956 }
957
958 // read in face names
959 familyEntry->ReadFaceNames(this, NeedFullnamePostscriptNames(), mFontInfo);
960
961 // load the cmaps if needed
962 if (loadCmaps) {
963 familyEntry->ReadAllCMAPs(mFontInfo);
964 }
965
966 // limit the time spent reading fonts in one pass
967 TimeDuration elapsed = TimeStamp::Now() - start;
968 if (elapsed.ToMilliseconds() > FONT_LOADER_MAX_TIMESLICE &&
969 i + 1 != endIndex) {
970 endIndex = i + 1;
971 break;
972 }
973 }
974
975 mStartIndex = endIndex;
976 bool done = mStartIndex >= mNumFamilies;
977
978 #ifdef PR_LOGGING
979 if (LOG_FONTINIT_ENABLED()) {
980 TimeDuration elapsed = TimeStamp::Now() - start;
981 LOG_FONTINIT(("(fontinit) fontloader load pass %8.2f ms done %s\n",
982 elapsed.ToMilliseconds(), (done ? "true" : "false")));
983 }
984 #endif
985
986 if (done) {
987 mOtherFamilyNamesInitialized = true;
988 mFaceNameListsInitialized = true;
989 }
990
991 return done;
992 }
993
994 struct LookupMissedFaceNamesData {
995 LookupMissedFaceNamesData(gfxPlatformFontList *aFontList)
996 : mFontList(aFontList), mFoundName(false) {}
997
998 gfxPlatformFontList *mFontList;
999 bool mFoundName;
1000 };
1001
1002 /*static*/ PLDHashOperator
1003 gfxPlatformFontList::LookupMissedFaceNamesProc(nsStringHashKey *aKey,
1004 void *aUserArg)
1005 {
1006 LookupMissedFaceNamesData *data =
1007 reinterpret_cast<LookupMissedFaceNamesData*>(aUserArg);
1008
1009 if (data->mFontList->FindFaceName(aKey->GetKey())) {
1010 data->mFoundName = true;
1011 return PL_DHASH_STOP;
1012 }
1013 return PL_DHASH_NEXT;
1014 }
1015
1016 struct LookupMissedOtherNamesData {
1017 LookupMissedOtherNamesData(gfxPlatformFontList *aFontList)
1018 : mFontList(aFontList), mFoundName(false) {}
1019
1020 gfxPlatformFontList *mFontList;
1021 bool mFoundName;
1022 };
1023
1024 /*static*/ PLDHashOperator
1025 gfxPlatformFontList::LookupMissedOtherNamesProc(nsStringHashKey *aKey,
1026 void *aUserArg)
1027 {
1028 LookupMissedOtherNamesData *data =
1029 reinterpret_cast<LookupMissedOtherNamesData*>(aUserArg);
1030
1031 if (data->mFontList->FindFamily(aKey->GetKey())) {
1032 data->mFoundName = true;
1033 return PL_DHASH_STOP;
1034 }
1035 return PL_DHASH_NEXT;
1036 }
1037
1038 void
1039 gfxPlatformFontList::CleanupLoader()
1040 {
1041 mFontFamiliesToLoad.Clear();
1042 mNumFamilies = 0;
1043 bool rebuilt = false, forceReflow = false;
1044
1045 // if had missed face names that are now available, force reflow all
1046 if (mFaceNamesMissed &&
1047 mFaceNamesMissed->Count() != 0) {
1048 LookupMissedFaceNamesData namedata(this);
1049 mFaceNamesMissed->EnumerateEntries(LookupMissedFaceNamesProc, &namedata);
1050 if (namedata.mFoundName) {
1051 rebuilt = true;
1052 mUserFontSetList.EnumerateEntries(RebuildLocalFonts, nullptr);
1053 }
1054 mFaceNamesMissed = nullptr;
1055 }
1056
1057 if (mOtherNamesMissed) {
1058 LookupMissedOtherNamesData othernamesdata(this);
1059 mOtherNamesMissed->EnumerateEntries(LookupMissedOtherNamesProc,
1060 &othernamesdata);
1061 mOtherNamesMissed = nullptr;
1062 if (othernamesdata.mFoundName) {
1063 forceReflow = true;
1064 ForceGlobalReflow();
1065 }
1066 }
1067
1068 #ifdef PR_LOGGING
1069 if (LOG_FONTINIT_ENABLED() && mFontInfo) {
1070 LOG_FONTINIT(("(fontinit) fontloader load thread took %8.2f ms "
1071 "%d families %d fonts %d cmaps "
1072 "%d facenames %d othernames %s %s",
1073 mLoadTime.ToMilliseconds(),
1074 mFontInfo->mLoadStats.families,
1075 mFontInfo->mLoadStats.fonts,
1076 mFontInfo->mLoadStats.cmaps,
1077 mFontInfo->mLoadStats.facenames,
1078 mFontInfo->mLoadStats.othernames,
1079 (rebuilt ? "(userfont sets rebuilt)" : ""),
1080 (forceReflow ? "(global reflow)" : "")));
1081 }
1082 #endif
1083
1084 gfxFontInfoLoader::CleanupLoader();
1085 }
1086
1087 void
1088 gfxPlatformFontList::GetPrefsAndStartLoader()
1089 {
1090 mIncrement =
1091 std::max(1u, Preferences::GetUint(FONT_LOADER_FAMILIES_PER_SLICE_PREF));
1092
1093 uint32_t delay =
1094 std::max(1u, Preferences::GetUint(FONT_LOADER_DELAY_PREF));
1095 uint32_t interval =
1096 std::max(1u, Preferences::GetUint(FONT_LOADER_INTERVAL_PREF));
1097
1098 StartLoader(delay, interval);
1099 }
1100
1101 void
1102 gfxPlatformFontList::ForceGlobalReflow()
1103 {
1104 // modify a preference that will trigger reflow everywhere
1105 static const char kPrefName[] = "font.internaluseonly.changed";
1106 bool fontInternalChange = Preferences::GetBool(kPrefName, false);
1107 Preferences::SetBool(kPrefName, !fontInternalChange);
1108 }
1109
1110 // Support for memory reporting
1111
1112 static size_t
1113 SizeOfFamilyEntryExcludingThis(const nsAString& aKey,
1114 const nsRefPtr<gfxFontFamily>& aFamily,
1115 MallocSizeOf aMallocSizeOf,
1116 void* aUserArg)
1117 {
1118 FontListSizes *sizes = static_cast<FontListSizes*>(aUserArg);
1119 aFamily->AddSizeOfExcludingThis(aMallocSizeOf, sizes);
1120
1121 sizes->mFontListSize += aKey.SizeOfExcludingThisIfUnshared(aMallocSizeOf);
1122
1123 // we return zero here because the measurements have been added directly
1124 // to the relevant fields of the FontListSizes record
1125 return 0;
1126 }
1127
1128 // this is also used by subclasses that hold additional hashes of family names
1129 /*static*/ size_t
1130 gfxPlatformFontList::SizeOfFamilyNameEntryExcludingThis
1131 (const nsAString& aKey,
1132 const nsRefPtr<gfxFontFamily>& aFamily,
1133 MallocSizeOf aMallocSizeOf,
1134 void* aUserArg)
1135 {
1136 // we don't count the size of the family here, because this is an *extra*
1137 // reference to a family that will have already been counted in the main list
1138 return aKey.SizeOfExcludingThisIfUnshared(aMallocSizeOf);
1139 }
1140
1141 static size_t
1142 SizeOfFontNameEntryExcludingThis(const nsAString& aKey,
1143 const nsRefPtr<gfxFontEntry>& aFont,
1144 MallocSizeOf aMallocSizeOf,
1145 void* aUserArg)
1146 {
1147 // the font itself is counted by its owning family; here we only care about
1148 // the name stored in the hashtable key
1149 return aKey.SizeOfExcludingThisIfUnshared(aMallocSizeOf);
1150 }
1151
1152 static size_t
1153 SizeOfPrefFontEntryExcludingThis
1154 (const uint32_t& aKey,
1155 const nsTArray<nsRefPtr<gfxFontFamily> >& aList,
1156 MallocSizeOf aMallocSizeOf,
1157 void* aUserArg)
1158 {
1159 // again, we only care about the size of the array itself; we don't follow
1160 // the refPtrs stored in it, because they point to entries already owned
1161 // and accounted-for by the main font list
1162 return aList.SizeOfExcludingThis(aMallocSizeOf);
1163 }
1164
1165 static size_t
1166 SizeOfStringEntryExcludingThis(nsStringHashKey* aHashEntry,
1167 MallocSizeOf aMallocSizeOf,
1168 void* aUserArg)
1169 {
1170 return aHashEntry->GetKey().SizeOfExcludingThisIfUnshared(aMallocSizeOf);
1171 }
1172
1173 static size_t
1174 SizeOfSharedCmapExcludingThis(CharMapHashKey* aHashEntry,
1175 MallocSizeOf aMallocSizeOf,
1176 void* aUserArg)
1177 {
1178 FontListSizes *sizes = static_cast<FontListSizes*>(aUserArg);
1179
1180 uint32_t size = aHashEntry->GetKey()->SizeOfIncludingThis(aMallocSizeOf);
1181 sizes->mCharMapsSize += size;
1182
1183 // we return zero here because the measurements have been added directly
1184 // to the relevant fields of the FontListSizes record
1185 return 0;
1186 }
1187
1188 void
1189 gfxPlatformFontList::AddSizeOfExcludingThis(MallocSizeOf aMallocSizeOf,
1190 FontListSizes* aSizes) const
1191 {
1192 aSizes->mFontListSize +=
1193 mFontFamilies.SizeOfExcludingThis(SizeOfFamilyEntryExcludingThis,
1194 aMallocSizeOf, aSizes);
1195
1196 aSizes->mFontListSize +=
1197 mOtherFamilyNames.SizeOfExcludingThis(SizeOfFamilyNameEntryExcludingThis,
1198 aMallocSizeOf);
1199
1200 if (mExtraNames) {
1201 aSizes->mFontListSize +=
1202 mExtraNames->mFullnames.SizeOfExcludingThis(SizeOfFontNameEntryExcludingThis,
1203 aMallocSizeOf);
1204 aSizes->mFontListSize +=
1205 mExtraNames->mPostscriptNames.SizeOfExcludingThis(SizeOfFontNameEntryExcludingThis,
1206 aMallocSizeOf);
1207 }
1208
1209 aSizes->mFontListSize +=
1210 mCodepointsWithNoFonts.SizeOfExcludingThis(aMallocSizeOf);
1211 aSizes->mFontListSize +=
1212 mFontFamiliesToLoad.SizeOfExcludingThis(aMallocSizeOf);
1213
1214 aSizes->mFontListSize +=
1215 mPrefFonts.SizeOfExcludingThis(SizeOfPrefFontEntryExcludingThis,
1216 aMallocSizeOf);
1217
1218 aSizes->mFontListSize +=
1219 mBadUnderlineFamilyNames.SizeOfExcludingThis(SizeOfStringEntryExcludingThis,
1220 aMallocSizeOf);
1221
1222 aSizes->mFontListSize +=
1223 mSharedCmaps.SizeOfExcludingThis(SizeOfSharedCmapExcludingThis,
1224 aMallocSizeOf, aSizes);
1225 }
1226
1227 void
1228 gfxPlatformFontList::AddSizeOfIncludingThis(MallocSizeOf aMallocSizeOf,
1229 FontListSizes* aSizes) const
1230 {
1231 aSizes->mFontListSize += aMallocSizeOf(this);
1232 AddSizeOfExcludingThis(aMallocSizeOf, aSizes);
1233 }

mercurial