|
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 } |