|
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/ArrayUtils.h" |
|
7 #include "mozilla/MemoryReporting.h" |
|
8 |
|
9 #ifdef MOZ_LOGGING |
|
10 #define FORCE_PR_LOG /* Allow logging in the release build */ |
|
11 #endif /* MOZ_LOGGING */ |
|
12 |
|
13 #include "gfxDWriteFontList.h" |
|
14 #include "gfxDWriteFonts.h" |
|
15 #include "nsUnicharUtils.h" |
|
16 #include "nsILocaleService.h" |
|
17 #include "nsServiceManagerUtils.h" |
|
18 #include "nsCharSeparatedTokenizer.h" |
|
19 #include "mozilla/Preferences.h" |
|
20 #include "mozilla/Telemetry.h" |
|
21 |
|
22 #include "gfxGDIFontList.h" |
|
23 |
|
24 #include "nsIWindowsRegKey.h" |
|
25 |
|
26 #include "harfbuzz/hb.h" |
|
27 |
|
28 using namespace mozilla; |
|
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 |
|
36 #define LOG_FONTINIT(args) PR_LOG(gfxPlatform::GetLog(eGfxLog_fontinit), \ |
|
37 PR_LOG_DEBUG, args) |
|
38 #define LOG_FONTINIT_ENABLED() PR_LOG_TEST( \ |
|
39 gfxPlatform::GetLog(eGfxLog_fontinit), \ |
|
40 PR_LOG_DEBUG) |
|
41 |
|
42 #define LOG_CMAPDATA_ENABLED() PR_LOG_TEST( \ |
|
43 gfxPlatform::GetLog(eGfxLog_cmapdata), \ |
|
44 PR_LOG_DEBUG) |
|
45 |
|
46 static __inline void |
|
47 BuildKeyNameFromFontName(nsAString &aName) |
|
48 { |
|
49 if (aName.Length() >= LF_FACESIZE) |
|
50 aName.Truncate(LF_FACESIZE - 1); |
|
51 ToLowerCase(aName); |
|
52 } |
|
53 |
|
54 //////////////////////////////////////////////////////////////////////////////// |
|
55 // gfxDWriteFontFamily |
|
56 |
|
57 gfxDWriteFontFamily::~gfxDWriteFontFamily() |
|
58 { |
|
59 } |
|
60 |
|
61 static HRESULT |
|
62 GetDirectWriteFontName(IDWriteFont *aFont, nsAString& aFontName) |
|
63 { |
|
64 HRESULT hr; |
|
65 |
|
66 nsRefPtr<IDWriteLocalizedStrings> names; |
|
67 hr = aFont->GetFaceNames(getter_AddRefs(names)); |
|
68 if (FAILED(hr)) { |
|
69 return hr; |
|
70 } |
|
71 |
|
72 BOOL exists; |
|
73 nsAutoTArray<wchar_t,32> faceName; |
|
74 UINT32 englishIdx = 0; |
|
75 hr = names->FindLocaleName(L"en-us", &englishIdx, &exists); |
|
76 if (FAILED(hr)) { |
|
77 return hr; |
|
78 } |
|
79 |
|
80 if (!exists) { |
|
81 // No english found, use whatever is first in the list. |
|
82 englishIdx = 0; |
|
83 } |
|
84 UINT32 length; |
|
85 hr = names->GetStringLength(englishIdx, &length); |
|
86 if (FAILED(hr)) { |
|
87 return hr; |
|
88 } |
|
89 faceName.SetLength(length + 1); |
|
90 hr = names->GetString(englishIdx, faceName.Elements(), length + 1); |
|
91 if (FAILED(hr)) { |
|
92 return hr; |
|
93 } |
|
94 |
|
95 aFontName.Assign(faceName.Elements()); |
|
96 return S_OK; |
|
97 } |
|
98 |
|
99 // These strings are only defined in Win SDK 8+, so use #ifdef for now |
|
100 #if MOZ_WINSDK_TARGETVER > 0x08000000 |
|
101 #define FULLNAME_ID DWRITE_INFORMATIONAL_STRING_FULL_NAME |
|
102 #define PSNAME_ID DWRITE_INFORMATIONAL_STRING_POSTSCRIPT_NAME |
|
103 #else |
|
104 #define FULLNAME_ID DWRITE_INFORMATIONAL_STRING_ID(DWRITE_INFORMATIONAL_STRING_SAMPLE_TEXT + 1) |
|
105 #define PSNAME_ID DWRITE_INFORMATIONAL_STRING_ID(DWRITE_INFORMATIONAL_STRING_SAMPLE_TEXT + 2) |
|
106 #endif |
|
107 |
|
108 // for use in reading postscript or fullname |
|
109 static HRESULT |
|
110 GetDirectWriteFaceName(IDWriteFont *aFont, |
|
111 DWRITE_INFORMATIONAL_STRING_ID aWhichName, |
|
112 nsAString& aFontName) |
|
113 { |
|
114 HRESULT hr; |
|
115 |
|
116 BOOL exists; |
|
117 nsRefPtr<IDWriteLocalizedStrings> infostrings; |
|
118 hr = aFont->GetInformationalStrings(aWhichName, getter_AddRefs(infostrings), &exists); |
|
119 if (FAILED(hr) || !exists) { |
|
120 return E_FAIL; |
|
121 } |
|
122 |
|
123 nsAutoTArray<wchar_t,32> faceName; |
|
124 UINT32 englishIdx = 0; |
|
125 hr = infostrings->FindLocaleName(L"en-us", &englishIdx, &exists); |
|
126 if (FAILED(hr)) { |
|
127 return hr; |
|
128 } |
|
129 |
|
130 if (!exists) { |
|
131 // No english found, use whatever is first in the list. |
|
132 englishIdx = 0; |
|
133 } |
|
134 UINT32 length; |
|
135 hr = infostrings->GetStringLength(englishIdx, &length); |
|
136 if (FAILED(hr)) { |
|
137 return hr; |
|
138 } |
|
139 faceName.SetLength(length + 1); |
|
140 hr = infostrings->GetString(englishIdx, faceName.Elements(), length + 1); |
|
141 if (FAILED(hr)) { |
|
142 return hr; |
|
143 } |
|
144 |
|
145 aFontName.Assign(faceName.Elements()); |
|
146 return S_OK; |
|
147 } |
|
148 |
|
149 void |
|
150 gfxDWriteFontFamily::FindStyleVariations(FontInfoData *aFontInfoData) |
|
151 { |
|
152 HRESULT hr; |
|
153 if (mHasStyles) { |
|
154 return; |
|
155 } |
|
156 mHasStyles = true; |
|
157 |
|
158 gfxPlatformFontList *fp = gfxPlatformFontList::PlatformFontList(); |
|
159 |
|
160 bool skipFaceNames = mFaceNamesInitialized || |
|
161 !fp->NeedFullnamePostscriptNames(); |
|
162 bool fontInfoShouldHaveFaceNames = !mFaceNamesInitialized && |
|
163 fp->NeedFullnamePostscriptNames() && |
|
164 aFontInfoData; |
|
165 |
|
166 for (UINT32 i = 0; i < mDWFamily->GetFontCount(); i++) { |
|
167 nsRefPtr<IDWriteFont> font; |
|
168 hr = mDWFamily->GetFont(i, getter_AddRefs(font)); |
|
169 if (FAILED(hr)) { |
|
170 // This should never happen. |
|
171 NS_WARNING("Failed to get existing font from family."); |
|
172 continue; |
|
173 } |
|
174 |
|
175 if (font->GetSimulations() & DWRITE_FONT_SIMULATIONS_OBLIQUE) { |
|
176 // We don't want these. |
|
177 continue; |
|
178 } |
|
179 |
|
180 // name |
|
181 nsString fullID(mName); |
|
182 nsAutoString faceName; |
|
183 hr = GetDirectWriteFontName(font, faceName); |
|
184 if (FAILED(hr)) { |
|
185 continue; |
|
186 } |
|
187 fullID.Append(NS_LITERAL_STRING(" ")); |
|
188 fullID.Append(faceName); |
|
189 |
|
190 gfxDWriteFontEntry *fe = new gfxDWriteFontEntry(fullID, font); |
|
191 fe->SetForceGDIClassic(mForceGDIClassic); |
|
192 AddFontEntry(fe); |
|
193 |
|
194 // postscript/fullname if needed |
|
195 nsAutoString psname, fullname; |
|
196 if (fontInfoShouldHaveFaceNames) { |
|
197 aFontInfoData->GetFaceNames(fe->Name(), fullname, psname); |
|
198 if (!fullname.IsEmpty()) { |
|
199 fp->AddFullname(fe, fullname); |
|
200 } |
|
201 if (!psname.IsEmpty()) { |
|
202 fp->AddPostscriptName(fe, psname); |
|
203 } |
|
204 } else if (!skipFaceNames) { |
|
205 hr = GetDirectWriteFaceName(font, PSNAME_ID, psname); |
|
206 if (FAILED(hr)) { |
|
207 skipFaceNames = true; |
|
208 } else if (psname.Length() > 0) { |
|
209 fp->AddPostscriptName(fe, psname); |
|
210 } |
|
211 |
|
212 hr = GetDirectWriteFaceName(font, FULLNAME_ID, fullname); |
|
213 if (FAILED(hr)) { |
|
214 skipFaceNames = true; |
|
215 } else if (fullname.Length() > 0) { |
|
216 fp->AddFullname(fe, fullname); |
|
217 } |
|
218 } |
|
219 |
|
220 #ifdef PR_LOGGING |
|
221 if (LOG_FONTLIST_ENABLED()) { |
|
222 LOG_FONTLIST(("(fontlist) added (%s) to family (%s)" |
|
223 " with style: %s weight: %d stretch: %d psname: %s fullname: %s", |
|
224 NS_ConvertUTF16toUTF8(fe->Name()).get(), |
|
225 NS_ConvertUTF16toUTF8(Name()).get(), |
|
226 (fe->IsItalic()) ? "italic" : "normal", |
|
227 fe->Weight(), fe->Stretch(), |
|
228 NS_ConvertUTF16toUTF8(psname).get(), |
|
229 NS_ConvertUTF16toUTF8(fullname).get())); |
|
230 } |
|
231 #endif |
|
232 } |
|
233 |
|
234 // assume that if no error, all postscript/fullnames were initialized |
|
235 if (!skipFaceNames) { |
|
236 mFaceNamesInitialized = true; |
|
237 } |
|
238 |
|
239 if (!mAvailableFonts.Length()) { |
|
240 NS_WARNING("Family with no font faces in it."); |
|
241 } |
|
242 |
|
243 if (mIsBadUnderlineFamily) { |
|
244 SetBadUnderlineFonts(); |
|
245 } |
|
246 } |
|
247 |
|
248 void |
|
249 gfxDWriteFontFamily::ReadFaceNames(gfxPlatformFontList *aPlatformFontList, |
|
250 bool aNeedFullnamePostscriptNames) |
|
251 { |
|
252 // if all needed names have already been read, skip |
|
253 if (mOtherFamilyNamesInitialized && |
|
254 (mFaceNamesInitialized || !aNeedFullnamePostscriptNames)) { |
|
255 return; |
|
256 } |
|
257 |
|
258 // DirectWrite version of this will try to read |
|
259 // postscript/fullnames via DirectWrite API |
|
260 FindStyleVariations(); |
|
261 |
|
262 // fallback to looking up via name table |
|
263 if (!mOtherFamilyNamesInitialized || !mFaceNamesInitialized) { |
|
264 gfxFontFamily::ReadFaceNames(aPlatformFontList, |
|
265 aNeedFullnamePostscriptNames); |
|
266 } |
|
267 } |
|
268 |
|
269 void |
|
270 gfxDWriteFontFamily::LocalizedName(nsAString &aLocalizedName) |
|
271 { |
|
272 aLocalizedName.AssignLiteral("Unknown Font"); |
|
273 HRESULT hr; |
|
274 nsresult rv; |
|
275 nsCOMPtr<nsILocaleService> ls = do_GetService(NS_LOCALESERVICE_CONTRACTID, |
|
276 &rv); |
|
277 nsCOMPtr<nsILocale> locale; |
|
278 rv = ls->GetApplicationLocale(getter_AddRefs(locale)); |
|
279 nsString localeName; |
|
280 if (NS_SUCCEEDED(rv)) { |
|
281 rv = locale->GetCategory(NS_LITERAL_STRING(NSILOCALE_MESSAGE), |
|
282 localeName); |
|
283 } |
|
284 if (NS_FAILED(rv)) { |
|
285 localeName.AssignLiteral("en-us"); |
|
286 } |
|
287 |
|
288 nsRefPtr<IDWriteLocalizedStrings> names; |
|
289 |
|
290 hr = mDWFamily->GetFamilyNames(getter_AddRefs(names)); |
|
291 if (FAILED(hr)) { |
|
292 return; |
|
293 } |
|
294 UINT32 idx = 0; |
|
295 BOOL exists; |
|
296 hr = names->FindLocaleName(localeName.get(), |
|
297 &idx, |
|
298 &exists); |
|
299 if (FAILED(hr)) { |
|
300 return; |
|
301 } |
|
302 if (!exists) { |
|
303 // Use english is localized is not found. |
|
304 hr = names->FindLocaleName(L"en-us", &idx, &exists); |
|
305 if (FAILED(hr)) { |
|
306 return; |
|
307 } |
|
308 if (!exists) { |
|
309 // Use 0 index if english is not found. |
|
310 idx = 0; |
|
311 } |
|
312 } |
|
313 AutoFallibleTArray<WCHAR, 32> famName; |
|
314 UINT32 length; |
|
315 |
|
316 hr = names->GetStringLength(idx, &length); |
|
317 if (FAILED(hr)) { |
|
318 return; |
|
319 } |
|
320 |
|
321 if (!famName.SetLength(length + 1)) { |
|
322 // Eeep - running out of memory. Unlikely to end well. |
|
323 return; |
|
324 } |
|
325 |
|
326 hr = names->GetString(idx, famName.Elements(), length + 1); |
|
327 if (FAILED(hr)) { |
|
328 return; |
|
329 } |
|
330 |
|
331 aLocalizedName = nsDependentString(famName.Elements()); |
|
332 } |
|
333 |
|
334 void |
|
335 gfxDWriteFontFamily::AddSizeOfExcludingThis(MallocSizeOf aMallocSizeOf, |
|
336 FontListSizes* aSizes) const |
|
337 { |
|
338 gfxFontFamily::AddSizeOfExcludingThis(aMallocSizeOf, aSizes); |
|
339 // TODO: |
|
340 // This doesn't currently account for |mDWFamily| |
|
341 } |
|
342 |
|
343 void |
|
344 gfxDWriteFontFamily::AddSizeOfIncludingThis(MallocSizeOf aMallocSizeOf, |
|
345 FontListSizes* aSizes) const |
|
346 { |
|
347 aSizes->mFontListSize += aMallocSizeOf(this); |
|
348 AddSizeOfExcludingThis(aMallocSizeOf, aSizes); |
|
349 } |
|
350 |
|
351 //////////////////////////////////////////////////////////////////////////////// |
|
352 // gfxDWriteFontEntry |
|
353 |
|
354 gfxDWriteFontEntry::~gfxDWriteFontEntry() |
|
355 { |
|
356 } |
|
357 |
|
358 bool |
|
359 gfxDWriteFontEntry::IsSymbolFont() |
|
360 { |
|
361 if (mFont) { |
|
362 return mFont->IsSymbolFont(); |
|
363 } else { |
|
364 return false; |
|
365 } |
|
366 } |
|
367 |
|
368 static bool |
|
369 UsingArabicOrHebrewScriptSystemLocale() |
|
370 { |
|
371 LANGID langid = PRIMARYLANGID(::GetSystemDefaultLangID()); |
|
372 switch (langid) { |
|
373 case LANG_ARABIC: |
|
374 case LANG_DARI: |
|
375 case LANG_PASHTO: |
|
376 case LANG_PERSIAN: |
|
377 case LANG_SINDHI: |
|
378 case LANG_UIGHUR: |
|
379 case LANG_URDU: |
|
380 case LANG_HEBREW: |
|
381 return true; |
|
382 default: |
|
383 return false; |
|
384 } |
|
385 } |
|
386 |
|
387 nsresult |
|
388 gfxDWriteFontEntry::CopyFontTable(uint32_t aTableTag, |
|
389 FallibleTArray<uint8_t> &aBuffer) |
|
390 { |
|
391 gfxDWriteFontList *pFontList = gfxDWriteFontList::PlatformFontList(); |
|
392 |
|
393 // Don't use GDI table loading for symbol fonts or for |
|
394 // italic fonts in Arabic-script system locales because of |
|
395 // potential cmap discrepancies, see bug 629386. |
|
396 // Ditto for Hebrew, bug 837498. |
|
397 if (mFont && pFontList->UseGDIFontTableAccess() && |
|
398 !(mItalic && UsingArabicOrHebrewScriptSystemLocale()) && |
|
399 !mFont->IsSymbolFont()) |
|
400 { |
|
401 LOGFONTW logfont = { 0 }; |
|
402 if (!InitLogFont(mFont, &logfont)) |
|
403 return NS_ERROR_FAILURE; |
|
404 |
|
405 AutoDC dc; |
|
406 AutoSelectFont font(dc.GetDC(), &logfont); |
|
407 if (font.IsValid()) { |
|
408 uint32_t tableSize = |
|
409 ::GetFontData(dc.GetDC(), |
|
410 NativeEndian::swapToBigEndian(aTableTag), 0, |
|
411 nullptr, 0); |
|
412 if (tableSize != GDI_ERROR) { |
|
413 if (aBuffer.SetLength(tableSize)) { |
|
414 ::GetFontData(dc.GetDC(), |
|
415 NativeEndian::swapToBigEndian(aTableTag), 0, |
|
416 aBuffer.Elements(), aBuffer.Length()); |
|
417 return NS_OK; |
|
418 } |
|
419 return NS_ERROR_OUT_OF_MEMORY; |
|
420 } |
|
421 } |
|
422 return NS_ERROR_FAILURE; |
|
423 } |
|
424 |
|
425 nsRefPtr<IDWriteFontFace> fontFace; |
|
426 nsresult rv = CreateFontFace(getter_AddRefs(fontFace)); |
|
427 if (NS_FAILED(rv)) { |
|
428 return rv; |
|
429 } |
|
430 |
|
431 uint8_t *tableData; |
|
432 uint32_t len; |
|
433 void *tableContext = nullptr; |
|
434 BOOL exists; |
|
435 HRESULT hr = |
|
436 fontFace->TryGetFontTable(NativeEndian::swapToBigEndian(aTableTag), |
|
437 (const void**)&tableData, &len, |
|
438 &tableContext, &exists); |
|
439 if (FAILED(hr) || !exists) { |
|
440 return NS_ERROR_FAILURE; |
|
441 } |
|
442 |
|
443 if (aBuffer.SetLength(len)) { |
|
444 memcpy(aBuffer.Elements(), tableData, len); |
|
445 rv = NS_OK; |
|
446 } else { |
|
447 rv = NS_ERROR_OUT_OF_MEMORY; |
|
448 } |
|
449 |
|
450 if (tableContext) { |
|
451 fontFace->ReleaseFontTable(&tableContext); |
|
452 } |
|
453 |
|
454 return rv; |
|
455 } |
|
456 |
|
457 // Access to font tables packaged in hb_blob_t form |
|
458 |
|
459 // object attached to the Harfbuzz blob, used to release |
|
460 // the table when the blob is destroyed |
|
461 class FontTableRec { |
|
462 public: |
|
463 FontTableRec(IDWriteFontFace *aFontFace, void *aContext) |
|
464 : mFontFace(aFontFace), mContext(aContext) |
|
465 { } |
|
466 |
|
467 ~FontTableRec() { |
|
468 mFontFace->ReleaseFontTable(mContext); |
|
469 } |
|
470 |
|
471 private: |
|
472 nsRefPtr<IDWriteFontFace> mFontFace; |
|
473 void *mContext; |
|
474 }; |
|
475 |
|
476 static void |
|
477 DestroyBlobFunc(void* aUserData) |
|
478 { |
|
479 FontTableRec *ftr = static_cast<FontTableRec*>(aUserData); |
|
480 delete ftr; |
|
481 } |
|
482 |
|
483 hb_blob_t * |
|
484 gfxDWriteFontEntry::GetFontTable(uint32_t aTag) |
|
485 { |
|
486 // try to avoid potentially expensive DWrite call if we haven't actually |
|
487 // created the font face yet, by using the gfxFontEntry method that will |
|
488 // use CopyFontTable and then cache the data |
|
489 if (!mFontFace) { |
|
490 return gfxFontEntry::GetFontTable(aTag); |
|
491 } |
|
492 |
|
493 const void *data; |
|
494 UINT32 size; |
|
495 void *context; |
|
496 BOOL exists; |
|
497 HRESULT hr = mFontFace->TryGetFontTable(NativeEndian::swapToBigEndian(aTag), |
|
498 &data, &size, &context, &exists); |
|
499 if (SUCCEEDED(hr) && exists) { |
|
500 FontTableRec *ftr = new FontTableRec(mFontFace, context); |
|
501 return hb_blob_create(static_cast<const char*>(data), size, |
|
502 HB_MEMORY_MODE_READONLY, |
|
503 ftr, DestroyBlobFunc); |
|
504 } |
|
505 |
|
506 return nullptr; |
|
507 } |
|
508 |
|
509 nsresult |
|
510 gfxDWriteFontEntry::ReadCMAP(FontInfoData *aFontInfoData) |
|
511 { |
|
512 // attempt this once, if errors occur leave a blank cmap |
|
513 if (mCharacterMap) { |
|
514 return NS_OK; |
|
515 } |
|
516 |
|
517 nsRefPtr<gfxCharacterMap> charmap; |
|
518 nsresult rv; |
|
519 bool symbolFont; |
|
520 |
|
521 if (aFontInfoData && (charmap = GetCMAPFromFontInfo(aFontInfoData, |
|
522 mUVSOffset, |
|
523 symbolFont))) { |
|
524 rv = NS_OK; |
|
525 } else { |
|
526 uint32_t kCMAP = TRUETYPE_TAG('c','m','a','p'); |
|
527 charmap = new gfxCharacterMap(); |
|
528 AutoTable cmapTable(this, kCMAP); |
|
529 |
|
530 if (cmapTable) { |
|
531 bool unicodeFont = false, symbolFont = false; // currently ignored |
|
532 uint32_t cmapLen; |
|
533 const uint8_t* cmapData = |
|
534 reinterpret_cast<const uint8_t*>(hb_blob_get_data(cmapTable, |
|
535 &cmapLen)); |
|
536 rv = gfxFontUtils::ReadCMAP(cmapData, cmapLen, |
|
537 *charmap, mUVSOffset, |
|
538 unicodeFont, symbolFont); |
|
539 } else { |
|
540 rv = NS_ERROR_NOT_AVAILABLE; |
|
541 } |
|
542 } |
|
543 |
|
544 mHasCmapTable = NS_SUCCEEDED(rv); |
|
545 if (mHasCmapTable) { |
|
546 // Bug 969504: exclude U+25B6 from Segoe UI family, because it's used |
|
547 // by sites to represent a "Play" icon, but the glyph in Segoe UI Light |
|
548 // and Semibold on Windows 7 is too thin. (Ditto for leftward U+25C0.) |
|
549 // Fallback to Segoe UI Symbol is preferred. |
|
550 if (FamilyName().EqualsLiteral("Segoe UI")) { |
|
551 charmap->clear(0x25b6); |
|
552 charmap->clear(0x25c0); |
|
553 } |
|
554 gfxPlatformFontList *pfl = gfxPlatformFontList::PlatformFontList(); |
|
555 mCharacterMap = pfl->FindCharMap(charmap); |
|
556 } else { |
|
557 // if error occurred, initialize to null cmap |
|
558 mCharacterMap = new gfxCharacterMap(); |
|
559 } |
|
560 |
|
561 #ifdef PR_LOGGING |
|
562 LOG_FONTLIST(("(fontlist-cmap) name: %s, size: %d hash: %8.8x%s\n", |
|
563 NS_ConvertUTF16toUTF8(mName).get(), |
|
564 charmap->SizeOfIncludingThis(moz_malloc_size_of), |
|
565 charmap->mHash, mCharacterMap == charmap ? " new" : "")); |
|
566 if (LOG_CMAPDATA_ENABLED()) { |
|
567 char prefix[256]; |
|
568 sprintf(prefix, "(cmapdata) name: %.220s", |
|
569 NS_ConvertUTF16toUTF8(mName).get()); |
|
570 charmap->Dump(prefix, eGfxLog_cmapdata); |
|
571 } |
|
572 #endif |
|
573 |
|
574 return rv; |
|
575 } |
|
576 |
|
577 gfxFont * |
|
578 gfxDWriteFontEntry::CreateFontInstance(const gfxFontStyle* aFontStyle, |
|
579 bool aNeedsBold) |
|
580 { |
|
581 return new gfxDWriteFont(this, aFontStyle, aNeedsBold); |
|
582 } |
|
583 |
|
584 nsresult |
|
585 gfxDWriteFontEntry::CreateFontFace(IDWriteFontFace **aFontFace, |
|
586 DWRITE_FONT_SIMULATIONS aSimulations) |
|
587 { |
|
588 // initialize mFontFace if this hasn't been done before |
|
589 if (!mFontFace) { |
|
590 HRESULT hr; |
|
591 if (mFont) { |
|
592 hr = mFont->CreateFontFace(getter_AddRefs(mFontFace)); |
|
593 } else if (mFontFile) { |
|
594 IDWriteFontFile *fontFile = mFontFile.get(); |
|
595 hr = gfxWindowsPlatform::GetPlatform()->GetDWriteFactory()-> |
|
596 CreateFontFace(mFaceType, |
|
597 1, |
|
598 &fontFile, |
|
599 0, |
|
600 DWRITE_FONT_SIMULATIONS_NONE, |
|
601 getter_AddRefs(mFontFace)); |
|
602 } else { |
|
603 NS_NOTREACHED("invalid font entry"); |
|
604 return NS_ERROR_FAILURE; |
|
605 } |
|
606 if (FAILED(hr)) { |
|
607 return NS_ERROR_FAILURE; |
|
608 } |
|
609 } |
|
610 |
|
611 // check whether we need to add a DWrite simulated style |
|
612 if ((aSimulations & DWRITE_FONT_SIMULATIONS_BOLD) && |
|
613 !(mFontFace->GetSimulations() & DWRITE_FONT_SIMULATIONS_BOLD)) { |
|
614 // if so, we need to return not mFontFace itself but a version that |
|
615 // has the Bold simulation - unfortunately, DWrite doesn't provide |
|
616 // a simple API for this |
|
617 UINT32 numberOfFiles = 0; |
|
618 if (FAILED(mFontFace->GetFiles(&numberOfFiles, nullptr))) { |
|
619 return NS_ERROR_FAILURE; |
|
620 } |
|
621 nsAutoTArray<IDWriteFontFile*,1> files; |
|
622 files.AppendElements(numberOfFiles); |
|
623 if (FAILED(mFontFace->GetFiles(&numberOfFiles, files.Elements()))) { |
|
624 return NS_ERROR_FAILURE; |
|
625 } |
|
626 HRESULT hr = gfxWindowsPlatform::GetPlatform()->GetDWriteFactory()-> |
|
627 CreateFontFace(mFontFace->GetType(), |
|
628 numberOfFiles, |
|
629 files.Elements(), |
|
630 mFontFace->GetIndex(), |
|
631 aSimulations, |
|
632 aFontFace); |
|
633 for (UINT32 i = 0; i < numberOfFiles; ++i) { |
|
634 files[i]->Release(); |
|
635 } |
|
636 return FAILED(hr) ? NS_ERROR_FAILURE : NS_OK; |
|
637 } |
|
638 |
|
639 // no simulation: we can just add a reference to mFontFace and return that |
|
640 *aFontFace = mFontFace; |
|
641 (*aFontFace)->AddRef(); |
|
642 return NS_OK; |
|
643 } |
|
644 |
|
645 bool |
|
646 gfxDWriteFontEntry::InitLogFont(IDWriteFont *aFont, LOGFONTW *aLogFont) |
|
647 { |
|
648 HRESULT hr; |
|
649 |
|
650 BOOL isInSystemCollection; |
|
651 IDWriteGdiInterop *gdi = |
|
652 gfxDWriteFontList::PlatformFontList()->GetGDIInterop(); |
|
653 hr = gdi->ConvertFontToLOGFONT(aFont, aLogFont, &isInSystemCollection); |
|
654 return (FAILED(hr) ? false : true); |
|
655 } |
|
656 |
|
657 bool |
|
658 gfxDWriteFontEntry::IsCJKFont() |
|
659 { |
|
660 if (mIsCJK != UNINITIALIZED_VALUE) { |
|
661 return mIsCJK; |
|
662 } |
|
663 |
|
664 mIsCJK = false; |
|
665 |
|
666 const uint32_t kOS2Tag = TRUETYPE_TAG('O','S','/','2'); |
|
667 AutoFallibleTArray<uint8_t,128> buffer; |
|
668 if (CopyFontTable(kOS2Tag, buffer) != NS_OK) { |
|
669 return mIsCJK; |
|
670 } |
|
671 |
|
672 // ulCodePageRange bit definitions for the CJK codepages, |
|
673 // from http://www.microsoft.com/typography/otspec/os2.htm#cpr |
|
674 const uint32_t CJK_CODEPAGE_BITS = |
|
675 (1 << 17) | // codepage 932 - JIS/Japan |
|
676 (1 << 18) | // codepage 936 - Chinese (simplified) |
|
677 (1 << 19) | // codepage 949 - Korean Wansung |
|
678 (1 << 20) | // codepage 950 - Chinese (traditional) |
|
679 (1 << 21); // codepage 1361 - Korean Johab |
|
680 |
|
681 if (buffer.Length() >= offsetof(OS2Table, sxHeight)) { |
|
682 const OS2Table* os2 = |
|
683 reinterpret_cast<const OS2Table*>(buffer.Elements()); |
|
684 if ((uint32_t(os2->codePageRange1) & CJK_CODEPAGE_BITS) != 0) { |
|
685 mIsCJK = true; |
|
686 } |
|
687 } |
|
688 |
|
689 return mIsCJK; |
|
690 } |
|
691 |
|
692 void |
|
693 gfxDWriteFontEntry::AddSizeOfExcludingThis(MallocSizeOf aMallocSizeOf, |
|
694 FontListSizes* aSizes) const |
|
695 { |
|
696 gfxFontEntry::AddSizeOfExcludingThis(aMallocSizeOf, aSizes); |
|
697 // TODO: |
|
698 // This doesn't currently account for the |mFont| and |mFontFile| members |
|
699 } |
|
700 |
|
701 void |
|
702 gfxDWriteFontEntry::AddSizeOfIncludingThis(MallocSizeOf aMallocSizeOf, |
|
703 FontListSizes* aSizes) const |
|
704 { |
|
705 aSizes->mFontListSize += aMallocSizeOf(this); |
|
706 AddSizeOfExcludingThis(aMallocSizeOf, aSizes); |
|
707 } |
|
708 |
|
709 //////////////////////////////////////////////////////////////////////////////// |
|
710 // gfxDWriteFontList |
|
711 |
|
712 gfxDWriteFontList::gfxDWriteFontList() |
|
713 : mInitialized(false), mForceGDIClassicMaxFontSize(0.0) |
|
714 { |
|
715 } |
|
716 |
|
717 // bug 602792 - CJK systems default to large CJK fonts which cause excessive |
|
718 // I/O strain during cold startup due to dwrite caching bugs. Default to |
|
719 // Arial to avoid this. |
|
720 |
|
721 gfxFontFamily * |
|
722 gfxDWriteFontList::GetDefaultFont(const gfxFontStyle *aStyle) |
|
723 { |
|
724 nsAutoString resolvedName; |
|
725 |
|
726 // try Arial first |
|
727 if (ResolveFontName(NS_LITERAL_STRING("Arial"), resolvedName)) { |
|
728 return FindFamily(resolvedName); |
|
729 } |
|
730 |
|
731 // otherwise, use local default |
|
732 NONCLIENTMETRICSW ncm; |
|
733 ncm.cbSize = sizeof(ncm); |
|
734 BOOL status = ::SystemParametersInfoW(SPI_GETNONCLIENTMETRICS, |
|
735 sizeof(ncm), &ncm, 0); |
|
736 if (status) { |
|
737 if (ResolveFontName(nsDependentString(ncm.lfMessageFont.lfFaceName), |
|
738 resolvedName)) { |
|
739 return FindFamily(resolvedName); |
|
740 } |
|
741 } |
|
742 |
|
743 return nullptr; |
|
744 } |
|
745 |
|
746 gfxFontEntry * |
|
747 gfxDWriteFontList::LookupLocalFont(const gfxProxyFontEntry *aProxyEntry, |
|
748 const nsAString& aFullname) |
|
749 { |
|
750 gfxFontEntry *lookup; |
|
751 |
|
752 lookup = LookupInFaceNameLists(aFullname); |
|
753 if (!lookup) { |
|
754 return nullptr; |
|
755 } |
|
756 |
|
757 gfxDWriteFontEntry* dwriteLookup = static_cast<gfxDWriteFontEntry*>(lookup); |
|
758 gfxDWriteFontEntry *fe = |
|
759 new gfxDWriteFontEntry(lookup->Name(), |
|
760 dwriteLookup->mFont, |
|
761 aProxyEntry->Weight(), |
|
762 aProxyEntry->Stretch(), |
|
763 aProxyEntry->IsItalic()); |
|
764 fe->SetForceGDIClassic(dwriteLookup->GetForceGDIClassic()); |
|
765 return fe; |
|
766 } |
|
767 |
|
768 gfxFontEntry * |
|
769 gfxDWriteFontList::MakePlatformFont(const gfxProxyFontEntry *aProxyEntry, |
|
770 const uint8_t *aFontData, |
|
771 uint32_t aLength) |
|
772 { |
|
773 nsresult rv; |
|
774 nsAutoString uniqueName; |
|
775 rv = gfxFontUtils::MakeUniqueUserFontName(uniqueName); |
|
776 if (NS_FAILED(rv)) { |
|
777 NS_Free((void*)aFontData); |
|
778 return nullptr; |
|
779 } |
|
780 |
|
781 FallibleTArray<uint8_t> newFontData; |
|
782 |
|
783 rv = gfxFontUtils::RenameFont(uniqueName, aFontData, aLength, &newFontData); |
|
784 NS_Free((void*)aFontData); |
|
785 |
|
786 if (NS_FAILED(rv)) { |
|
787 return nullptr; |
|
788 } |
|
789 |
|
790 nsRefPtr<IDWriteFontFile> fontFile; |
|
791 HRESULT hr; |
|
792 |
|
793 /** |
|
794 * We pass in a pointer to a structure containing a pointer to the array |
|
795 * containing the font data and a unique identifier. DWrite will |
|
796 * internally copy what is at that pointer, and pass that to |
|
797 * CreateStreamFromKey. The array will be empty when the function |
|
798 * succesfully returns since it swaps out the data. |
|
799 */ |
|
800 ffReferenceKey key; |
|
801 key.mArray = &newFontData; |
|
802 nsCOMPtr<nsIUUIDGenerator> uuidgen = |
|
803 do_GetService("@mozilla.org/uuid-generator;1"); |
|
804 if (!uuidgen) { |
|
805 return nullptr; |
|
806 } |
|
807 |
|
808 rv = uuidgen->GenerateUUIDInPlace(&key.mGUID); |
|
809 |
|
810 if (NS_FAILED(rv)) { |
|
811 return nullptr; |
|
812 } |
|
813 |
|
814 hr = gfxWindowsPlatform::GetPlatform()->GetDWriteFactory()-> |
|
815 CreateCustomFontFileReference(&key, |
|
816 sizeof(key), |
|
817 gfxDWriteFontFileLoader::Instance(), |
|
818 getter_AddRefs(fontFile)); |
|
819 |
|
820 if (FAILED(hr)) { |
|
821 NS_WARNING("Failed to create custom font file reference."); |
|
822 return nullptr; |
|
823 } |
|
824 |
|
825 BOOL isSupported; |
|
826 DWRITE_FONT_FILE_TYPE fileType; |
|
827 UINT32 numFaces; |
|
828 |
|
829 gfxDWriteFontEntry *entry = |
|
830 new gfxDWriteFontEntry(uniqueName, |
|
831 fontFile, |
|
832 aProxyEntry->Weight(), |
|
833 aProxyEntry->Stretch(), |
|
834 aProxyEntry->IsItalic()); |
|
835 |
|
836 fontFile->Analyze(&isSupported, &fileType, &entry->mFaceType, &numFaces); |
|
837 if (!isSupported || numFaces > 1) { |
|
838 // We don't know how to deal with 0 faces either. |
|
839 delete entry; |
|
840 return nullptr; |
|
841 } |
|
842 |
|
843 return entry; |
|
844 } |
|
845 |
|
846 #ifdef DEBUG_DWRITE_STARTUP |
|
847 |
|
848 #define LOGREGISTRY(msg) LogRegistryEvent(msg) |
|
849 |
|
850 // for use when monitoring process |
|
851 static void LogRegistryEvent(const wchar_t *msg) |
|
852 { |
|
853 HKEY dummyKey; |
|
854 HRESULT hr; |
|
855 wchar_t buf[512]; |
|
856 |
|
857 wsprintfW(buf, L" log %s", msg); |
|
858 hr = RegOpenKeyExW(HKEY_LOCAL_MACHINE, buf, 0, KEY_READ, &dummyKey); |
|
859 if (SUCCEEDED(hr)) { |
|
860 RegCloseKey(dummyKey); |
|
861 } |
|
862 } |
|
863 #else |
|
864 |
|
865 #define LOGREGISTRY(msg) |
|
866 |
|
867 #endif |
|
868 |
|
869 nsresult |
|
870 gfxDWriteFontList::InitFontList() |
|
871 { |
|
872 LOGREGISTRY(L"InitFontList start"); |
|
873 |
|
874 mInitialized = false; |
|
875 |
|
876 LARGE_INTEGER frequency; // ticks per second |
|
877 LARGE_INTEGER t1, t2, t3; // ticks |
|
878 double elapsedTime, upTime; |
|
879 char nowTime[256], nowDate[256]; |
|
880 |
|
881 if (LOG_FONTINIT_ENABLED()) { |
|
882 GetTimeFormat(LOCALE_INVARIANT, TIME_FORCE24HOURFORMAT, |
|
883 nullptr, nullptr, nowTime, 256); |
|
884 GetDateFormat(LOCALE_INVARIANT, 0, nullptr, nullptr, nowDate, 256); |
|
885 } |
|
886 upTime = (double) GetTickCount(); |
|
887 QueryPerformanceFrequency(&frequency); |
|
888 QueryPerformanceCounter(&t1); |
|
889 |
|
890 HRESULT hr; |
|
891 gfxFontCache *fc = gfxFontCache::GetCache(); |
|
892 if (fc) { |
|
893 fc->AgeAllGenerations(); |
|
894 } |
|
895 |
|
896 mGDIFontTableAccess = Preferences::GetBool("gfx.font_rendering.directwrite.use_gdi_table_loading", false); |
|
897 |
|
898 gfxPlatformFontList::InitFontList(); |
|
899 |
|
900 mFontSubstitutes.Clear(); |
|
901 mNonExistingFonts.Clear(); |
|
902 |
|
903 QueryPerformanceCounter(&t2); |
|
904 |
|
905 hr = gfxWindowsPlatform::GetPlatform()->GetDWriteFactory()-> |
|
906 GetGdiInterop(getter_AddRefs(mGDIInterop)); |
|
907 if (FAILED(hr)) { |
|
908 return NS_ERROR_FAILURE; |
|
909 } |
|
910 |
|
911 LOGREGISTRY(L"InitFontList end"); |
|
912 |
|
913 QueryPerformanceCounter(&t3); |
|
914 |
|
915 if (LOG_FONTINIT_ENABLED()) { |
|
916 // determine dwrite version |
|
917 nsAutoString dwriteVers; |
|
918 gfxWindowsPlatform::GetDLLVersion(L"dwrite.dll", dwriteVers); |
|
919 LOG_FONTINIT(("InitFontList\n")); |
|
920 LOG_FONTINIT(("Start: %s %s\n", nowDate, nowTime)); |
|
921 LOG_FONTINIT(("Uptime: %9.3f s\n", upTime/1000)); |
|
922 LOG_FONTINIT(("dwrite version: %s\n", |
|
923 NS_ConvertUTF16toUTF8(dwriteVers).get())); |
|
924 } |
|
925 |
|
926 elapsedTime = (t3.QuadPart - t1.QuadPart) * 1000.0 / frequency.QuadPart; |
|
927 Telemetry::Accumulate(Telemetry::DWRITEFONT_INITFONTLIST_TOTAL, elapsedTime); |
|
928 LOG_FONTINIT(("Total time in InitFontList: %9.3f ms\n", elapsedTime)); |
|
929 elapsedTime = (t2.QuadPart - t1.QuadPart) * 1000.0 / frequency.QuadPart; |
|
930 Telemetry::Accumulate(Telemetry::DWRITEFONT_INITFONTLIST_INIT, elapsedTime); |
|
931 LOG_FONTINIT((" --- gfxPlatformFontList init: %9.3f ms\n", elapsedTime)); |
|
932 elapsedTime = (t3.QuadPart - t2.QuadPart) * 1000.0 / frequency.QuadPart; |
|
933 Telemetry::Accumulate(Telemetry::DWRITEFONT_INITFONTLIST_GDI, elapsedTime); |
|
934 LOG_FONTINIT((" --- GdiInterop object: %9.3f ms\n", elapsedTime)); |
|
935 |
|
936 return NS_OK; |
|
937 } |
|
938 |
|
939 nsresult |
|
940 gfxDWriteFontList::DelayedInitFontList() |
|
941 { |
|
942 LOGREGISTRY(L"DelayedInitFontList start"); |
|
943 |
|
944 LARGE_INTEGER frequency; // ticks per second |
|
945 LARGE_INTEGER t1, t2, t3; // ticks |
|
946 double elapsedTime, upTime; |
|
947 char nowTime[256], nowDate[256]; |
|
948 |
|
949 if (LOG_FONTINIT_ENABLED()) { |
|
950 GetTimeFormat(LOCALE_INVARIANT, TIME_FORCE24HOURFORMAT, |
|
951 nullptr, nullptr, nowTime, 256); |
|
952 GetDateFormat(LOCALE_INVARIANT, 0, nullptr, nullptr, nowDate, 256); |
|
953 } |
|
954 |
|
955 upTime = (double) GetTickCount(); |
|
956 QueryPerformanceFrequency(&frequency); |
|
957 QueryPerformanceCounter(&t1); |
|
958 |
|
959 HRESULT hr; |
|
960 |
|
961 LOGREGISTRY(L"calling GetSystemFontCollection"); |
|
962 nsRefPtr<IDWriteFontCollection> systemFonts; |
|
963 hr = gfxWindowsPlatform::GetPlatform()->GetDWriteFactory()-> |
|
964 GetSystemFontCollection(getter_AddRefs(systemFonts)); |
|
965 NS_ASSERTION(SUCCEEDED(hr), "GetSystemFontCollection failed!"); |
|
966 LOGREGISTRY(L"GetSystemFontCollection done"); |
|
967 |
|
968 if (FAILED(hr)) { |
|
969 return NS_ERROR_FAILURE; |
|
970 } |
|
971 |
|
972 QueryPerformanceCounter(&t2); |
|
973 |
|
974 for (UINT32 i = 0; i < systemFonts->GetFontFamilyCount(); i++) { |
|
975 nsRefPtr<IDWriteFontFamily> family; |
|
976 systemFonts->GetFontFamily(i, getter_AddRefs(family)); |
|
977 |
|
978 nsRefPtr<IDWriteLocalizedStrings> names; |
|
979 hr = family->GetFamilyNames(getter_AddRefs(names)); |
|
980 if (FAILED(hr)) { |
|
981 continue; |
|
982 } |
|
983 |
|
984 UINT32 englishIdx = 0; |
|
985 |
|
986 BOOL exists; |
|
987 hr = names->FindLocaleName(L"en-us", &englishIdx, &exists); |
|
988 if (FAILED(hr)) { |
|
989 continue; |
|
990 } |
|
991 if (!exists) { |
|
992 // Use 0 index if english is not found. |
|
993 englishIdx = 0; |
|
994 } |
|
995 |
|
996 AutoFallibleTArray<WCHAR, 32> enName; |
|
997 UINT32 length; |
|
998 |
|
999 hr = names->GetStringLength(englishIdx, &length); |
|
1000 if (FAILED(hr)) { |
|
1001 continue; |
|
1002 } |
|
1003 |
|
1004 if (!enName.SetLength(length + 1)) { |
|
1005 // Eeep - running out of memory. Unlikely to end well. |
|
1006 continue; |
|
1007 } |
|
1008 |
|
1009 hr = names->GetString(englishIdx, enName.Elements(), length + 1); |
|
1010 if (FAILED(hr)) { |
|
1011 continue; |
|
1012 } |
|
1013 |
|
1014 nsAutoString name(enName.Elements()); |
|
1015 BuildKeyNameFromFontName(name); |
|
1016 |
|
1017 nsRefPtr<gfxFontFamily> fam; |
|
1018 |
|
1019 if (mFontFamilies.GetWeak(name)) { |
|
1020 continue; |
|
1021 } |
|
1022 |
|
1023 nsDependentString familyName(enName.Elements()); |
|
1024 |
|
1025 fam = new gfxDWriteFontFamily(familyName, family); |
|
1026 if (!fam) { |
|
1027 continue; |
|
1028 } |
|
1029 |
|
1030 if (mBadUnderlineFamilyNames.Contains(name)) { |
|
1031 fam->SetBadUnderlineFamily(); |
|
1032 } |
|
1033 mFontFamilies.Put(name, fam); |
|
1034 |
|
1035 // now add other family name localizations, if present |
|
1036 uint32_t nameCount = names->GetCount(); |
|
1037 uint32_t nameIndex; |
|
1038 |
|
1039 for (nameIndex = 0; nameIndex < nameCount; nameIndex++) { |
|
1040 UINT32 nameLen; |
|
1041 AutoFallibleTArray<WCHAR, 32> localizedName; |
|
1042 |
|
1043 // only add other names |
|
1044 if (nameIndex == englishIdx) { |
|
1045 continue; |
|
1046 } |
|
1047 |
|
1048 hr = names->GetStringLength(nameIndex, &nameLen); |
|
1049 if (FAILED(hr)) { |
|
1050 continue; |
|
1051 } |
|
1052 |
|
1053 if (!localizedName.SetLength(nameLen + 1)) { |
|
1054 continue; |
|
1055 } |
|
1056 |
|
1057 hr = names->GetString(nameIndex, localizedName.Elements(), |
|
1058 nameLen + 1); |
|
1059 if (FAILED(hr)) { |
|
1060 continue; |
|
1061 } |
|
1062 |
|
1063 nsDependentString locName(localizedName.Elements()); |
|
1064 |
|
1065 if (!familyName.Equals(locName)) { |
|
1066 AddOtherFamilyName(fam, locName); |
|
1067 } |
|
1068 |
|
1069 } |
|
1070 |
|
1071 // at this point, all family names have been read in |
|
1072 fam->SetOtherFamilyNamesInitialized(); |
|
1073 } |
|
1074 |
|
1075 mOtherFamilyNamesInitialized = true; |
|
1076 GetFontSubstitutes(); |
|
1077 |
|
1078 // bug 642093 - DirectWrite does not support old bitmap (.fon) |
|
1079 // font files, but a few of these such as "Courier" and "MS Sans Serif" |
|
1080 // are frequently specified in shoddy CSS, without appropriate fallbacks. |
|
1081 // By mapping these to TrueType equivalents, we provide better consistency |
|
1082 // with both pre-DW systems and with IE9, which appears to do the same. |
|
1083 GetDirectWriteSubstitutes(); |
|
1084 |
|
1085 // bug 551313 - DirectWrite creates a Gill Sans family out of |
|
1086 // poorly named members of the Gill Sans MT family containing |
|
1087 // only Ultra Bold weights. This causes big problems for pages |
|
1088 // using Gill Sans which is usually only available on OSX |
|
1089 |
|
1090 nsAutoString nameGillSans(L"Gill Sans"); |
|
1091 nsAutoString nameGillSansMT(L"Gill Sans MT"); |
|
1092 BuildKeyNameFromFontName(nameGillSans); |
|
1093 BuildKeyNameFromFontName(nameGillSansMT); |
|
1094 |
|
1095 gfxFontFamily *gillSansFamily = mFontFamilies.GetWeak(nameGillSans); |
|
1096 gfxFontFamily *gillSansMTFamily = mFontFamilies.GetWeak(nameGillSansMT); |
|
1097 |
|
1098 if (gillSansFamily && gillSansMTFamily) { |
|
1099 gillSansFamily->FindStyleVariations(); |
|
1100 nsTArray<nsRefPtr<gfxFontEntry> >& faces = gillSansFamily->GetFontList(); |
|
1101 uint32_t i; |
|
1102 |
|
1103 bool allUltraBold = true; |
|
1104 for (i = 0; i < faces.Length(); i++) { |
|
1105 // does the face have 'Ultra Bold' in the name? |
|
1106 if (faces[i]->Name().Find(NS_LITERAL_STRING("Ultra Bold")) == -1) { |
|
1107 allUltraBold = false; |
|
1108 break; |
|
1109 } |
|
1110 } |
|
1111 |
|
1112 // if all the Gill Sans faces are Ultra Bold ==> move faces |
|
1113 // for Gill Sans into Gill Sans MT family |
|
1114 if (allUltraBold) { |
|
1115 |
|
1116 // add faces to Gill Sans MT |
|
1117 for (i = 0; i < faces.Length(); i++) { |
|
1118 gillSansMTFamily->AddFontEntry(faces[i]); |
|
1119 |
|
1120 #ifdef PR_LOGGING |
|
1121 if (LOG_FONTLIST_ENABLED()) { |
|
1122 gfxFontEntry *fe = faces[i]; |
|
1123 LOG_FONTLIST(("(fontlist) moved (%s) to family (%s)" |
|
1124 " with style: %s weight: %d stretch: %d", |
|
1125 NS_ConvertUTF16toUTF8(fe->Name()).get(), |
|
1126 NS_ConvertUTF16toUTF8(gillSansMTFamily->Name()).get(), |
|
1127 (fe->IsItalic()) ? "italic" : "normal", |
|
1128 fe->Weight(), fe->Stretch())); |
|
1129 } |
|
1130 #endif |
|
1131 } |
|
1132 |
|
1133 // remove Gills Sans |
|
1134 mFontFamilies.Remove(nameGillSans); |
|
1135 } |
|
1136 } |
|
1137 |
|
1138 nsAdoptingCString classicFamilies = |
|
1139 Preferences::GetCString("gfx.font_rendering.cleartype_params.force_gdi_classic_for_families"); |
|
1140 if (classicFamilies) { |
|
1141 nsCCharSeparatedTokenizer tokenizer(classicFamilies, ','); |
|
1142 while (tokenizer.hasMoreTokens()) { |
|
1143 NS_ConvertUTF8toUTF16 name(tokenizer.nextToken()); |
|
1144 BuildKeyNameFromFontName(name); |
|
1145 gfxFontFamily *family = mFontFamilies.GetWeak(name); |
|
1146 if (family) { |
|
1147 static_cast<gfxDWriteFontFamily*>(family)->SetForceGDIClassic(true); |
|
1148 } |
|
1149 } |
|
1150 } |
|
1151 mForceGDIClassicMaxFontSize = |
|
1152 Preferences::GetInt("gfx.font_rendering.cleartype_params.force_gdi_classic_max_size", |
|
1153 mForceGDIClassicMaxFontSize); |
|
1154 |
|
1155 GetPrefsAndStartLoader(); |
|
1156 |
|
1157 LOGREGISTRY(L"DelayedInitFontList end"); |
|
1158 |
|
1159 QueryPerformanceCounter(&t3); |
|
1160 |
|
1161 if (LOG_FONTINIT_ENABLED()) { |
|
1162 // determine dwrite version |
|
1163 nsAutoString dwriteVers; |
|
1164 gfxWindowsPlatform::GetDLLVersion(L"dwrite.dll", dwriteVers); |
|
1165 LOG_FONTINIT(("DelayedInitFontList\n")); |
|
1166 LOG_FONTINIT(("Start: %s %s\n", nowDate, nowTime)); |
|
1167 LOG_FONTINIT(("Uptime: %9.3f s\n", upTime/1000)); |
|
1168 LOG_FONTINIT(("dwrite version: %s\n", |
|
1169 NS_ConvertUTF16toUTF8(dwriteVers).get())); |
|
1170 } |
|
1171 |
|
1172 elapsedTime = (t3.QuadPart - t1.QuadPart) * 1000.0 / frequency.QuadPart; |
|
1173 Telemetry::Accumulate(Telemetry::DWRITEFONT_DELAYEDINITFONTLIST_TOTAL, elapsedTime); |
|
1174 Telemetry::Accumulate(Telemetry::DWRITEFONT_DELAYEDINITFONTLIST_COUNT, |
|
1175 systemFonts->GetFontFamilyCount()); |
|
1176 Telemetry::Accumulate(Telemetry::DWRITEFONT_DELAYEDINITFONTLIST_GDI_TABLE, mGDIFontTableAccess); |
|
1177 LOG_FONTINIT(( |
|
1178 "Total time in DelayedInitFontList: %9.3f ms (families: %d, %s)\n", |
|
1179 elapsedTime, systemFonts->GetFontFamilyCount(), |
|
1180 (mGDIFontTableAccess ? "gdi table access" : "dwrite table access"))); |
|
1181 |
|
1182 elapsedTime = (t2.QuadPart - t1.QuadPart) * 1000.0 / frequency.QuadPart; |
|
1183 Telemetry::Accumulate(Telemetry::DWRITEFONT_DELAYEDINITFONTLIST_COLLECT, elapsedTime); |
|
1184 LOG_FONTINIT((" --- GetSystemFontCollection: %9.3f ms\n", elapsedTime)); |
|
1185 |
|
1186 elapsedTime = (t3.QuadPart - t2.QuadPart) * 1000.0 / frequency.QuadPart; |
|
1187 Telemetry::Accumulate(Telemetry::DWRITEFONT_DELAYEDINITFONTLIST_ITERATE, elapsedTime); |
|
1188 LOG_FONTINIT((" --- iterate over families: %9.3f ms\n", elapsedTime)); |
|
1189 |
|
1190 return NS_OK; |
|
1191 } |
|
1192 |
|
1193 static void |
|
1194 RemoveCharsetFromFontSubstitute(nsAString &aName) |
|
1195 { |
|
1196 int32_t comma = aName.FindChar(char16_t(',')); |
|
1197 if (comma >= 0) |
|
1198 aName.Truncate(comma); |
|
1199 } |
|
1200 |
|
1201 #define MAX_VALUE_NAME 512 |
|
1202 #define MAX_VALUE_DATA 512 |
|
1203 |
|
1204 nsresult |
|
1205 gfxDWriteFontList::GetFontSubstitutes() |
|
1206 { |
|
1207 HKEY hKey; |
|
1208 DWORD i, rv, lenAlias, lenActual, valueType; |
|
1209 WCHAR aliasName[MAX_VALUE_NAME]; |
|
1210 WCHAR actualName[MAX_VALUE_DATA]; |
|
1211 |
|
1212 if (RegOpenKeyExW(HKEY_LOCAL_MACHINE, |
|
1213 L"SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\FontSubstitutes", |
|
1214 0, KEY_READ, &hKey) != ERROR_SUCCESS) |
|
1215 { |
|
1216 return NS_ERROR_FAILURE; |
|
1217 } |
|
1218 |
|
1219 for (i = 0, rv = ERROR_SUCCESS; rv != ERROR_NO_MORE_ITEMS; i++) { |
|
1220 aliasName[0] = 0; |
|
1221 lenAlias = ArrayLength(aliasName); |
|
1222 actualName[0] = 0; |
|
1223 lenActual = sizeof(actualName); |
|
1224 rv = RegEnumValueW(hKey, i, aliasName, &lenAlias, nullptr, &valueType, |
|
1225 (LPBYTE)actualName, &lenActual); |
|
1226 |
|
1227 if (rv != ERROR_SUCCESS || valueType != REG_SZ || lenAlias == 0) { |
|
1228 continue; |
|
1229 } |
|
1230 |
|
1231 if (aliasName[0] == WCHAR('@')) { |
|
1232 continue; |
|
1233 } |
|
1234 |
|
1235 nsAutoString substituteName((char16_t*) aliasName); |
|
1236 nsAutoString actualFontName((char16_t*) actualName); |
|
1237 RemoveCharsetFromFontSubstitute(substituteName); |
|
1238 BuildKeyNameFromFontName(substituteName); |
|
1239 RemoveCharsetFromFontSubstitute(actualFontName); |
|
1240 BuildKeyNameFromFontName(actualFontName); |
|
1241 gfxFontFamily *ff; |
|
1242 if (!actualFontName.IsEmpty() && |
|
1243 (ff = mFontFamilies.GetWeak(actualFontName))) { |
|
1244 mFontSubstitutes.Put(substituteName, ff); |
|
1245 } else { |
|
1246 mNonExistingFonts.AppendElement(substituteName); |
|
1247 } |
|
1248 } |
|
1249 return NS_OK; |
|
1250 } |
|
1251 |
|
1252 struct FontSubstitution { |
|
1253 const WCHAR* aliasName; |
|
1254 const WCHAR* actualName; |
|
1255 }; |
|
1256 |
|
1257 static const FontSubstitution sDirectWriteSubs[] = { |
|
1258 { L"MS Sans Serif", L"Microsoft Sans Serif" }, |
|
1259 { L"MS Serif", L"Times New Roman" }, |
|
1260 { L"Courier", L"Courier New" }, |
|
1261 { L"Small Fonts", L"Arial" }, |
|
1262 { L"Roman", L"Times New Roman" }, |
|
1263 { L"Script", L"Mistral" } |
|
1264 }; |
|
1265 |
|
1266 void |
|
1267 gfxDWriteFontList::GetDirectWriteSubstitutes() |
|
1268 { |
|
1269 for (uint32_t i = 0; i < ArrayLength(sDirectWriteSubs); ++i) { |
|
1270 const FontSubstitution& sub(sDirectWriteSubs[i]); |
|
1271 nsAutoString substituteName((char16_t*)sub.aliasName); |
|
1272 BuildKeyNameFromFontName(substituteName); |
|
1273 if (nullptr != mFontFamilies.GetWeak(substituteName)) { |
|
1274 // don't do the substitution if user actually has a usable font |
|
1275 // with this name installed |
|
1276 continue; |
|
1277 } |
|
1278 nsAutoString actualFontName((char16_t*)sub.actualName); |
|
1279 BuildKeyNameFromFontName(actualFontName); |
|
1280 gfxFontFamily *ff; |
|
1281 if (nullptr != (ff = mFontFamilies.GetWeak(actualFontName))) { |
|
1282 mFontSubstitutes.Put(substituteName, ff); |
|
1283 } else { |
|
1284 mNonExistingFonts.AppendElement(substituteName); |
|
1285 } |
|
1286 } |
|
1287 } |
|
1288 |
|
1289 bool |
|
1290 gfxDWriteFontList::GetStandardFamilyName(const nsAString& aFontName, |
|
1291 nsAString& aFamilyName) |
|
1292 { |
|
1293 gfxFontFamily *family = FindFamily(aFontName); |
|
1294 if (family) { |
|
1295 family->LocalizedName(aFamilyName); |
|
1296 return true; |
|
1297 } |
|
1298 |
|
1299 return false; |
|
1300 } |
|
1301 |
|
1302 gfxFontFamily* gfxDWriteFontList::FindFamily(const nsAString& aFamily) |
|
1303 { |
|
1304 if (!mInitialized) { |
|
1305 mInitialized = true; |
|
1306 DelayedInitFontList(); |
|
1307 } |
|
1308 |
|
1309 return gfxPlatformFontList::FindFamily(aFamily); |
|
1310 } |
|
1311 |
|
1312 void |
|
1313 gfxDWriteFontList::GetFontFamilyList(nsTArray<nsRefPtr<gfxFontFamily> >& aFamilyArray) |
|
1314 { |
|
1315 if (!mInitialized) { |
|
1316 mInitialized = true; |
|
1317 DelayedInitFontList(); |
|
1318 } |
|
1319 |
|
1320 return gfxPlatformFontList::GetFontFamilyList(aFamilyArray); |
|
1321 } |
|
1322 |
|
1323 bool |
|
1324 gfxDWriteFontList::ResolveFontName(const nsAString& aFontName, |
|
1325 nsAString& aResolvedFontName) |
|
1326 { |
|
1327 if (!mInitialized) { |
|
1328 mInitialized = true; |
|
1329 DelayedInitFontList(); |
|
1330 } |
|
1331 |
|
1332 nsAutoString keyName(aFontName); |
|
1333 BuildKeyNameFromFontName(keyName); |
|
1334 |
|
1335 gfxFontFamily *ff = mFontSubstitutes.GetWeak(keyName); |
|
1336 if (ff) { |
|
1337 aResolvedFontName = ff->Name(); |
|
1338 return true; |
|
1339 } |
|
1340 |
|
1341 if (mNonExistingFonts.Contains(keyName)) { |
|
1342 return false; |
|
1343 } |
|
1344 |
|
1345 return gfxPlatformFontList::ResolveFontName(aFontName, aResolvedFontName); |
|
1346 } |
|
1347 |
|
1348 void |
|
1349 gfxDWriteFontList::AddSizeOfExcludingThis(MallocSizeOf aMallocSizeOf, |
|
1350 FontListSizes* aSizes) const |
|
1351 { |
|
1352 gfxPlatformFontList::AddSizeOfExcludingThis(aMallocSizeOf, aSizes); |
|
1353 |
|
1354 aSizes->mFontListSize += |
|
1355 mFontSubstitutes.SizeOfExcludingThis(SizeOfFamilyNameEntryExcludingThis, |
|
1356 aMallocSizeOf); |
|
1357 |
|
1358 aSizes->mFontListSize += |
|
1359 mNonExistingFonts.SizeOfExcludingThis(aMallocSizeOf); |
|
1360 for (uint32_t i = 0; i < mNonExistingFonts.Length(); ++i) { |
|
1361 aSizes->mFontListSize += |
|
1362 mNonExistingFonts[i].SizeOfExcludingThisIfUnshared(aMallocSizeOf); |
|
1363 } |
|
1364 } |
|
1365 |
|
1366 void |
|
1367 gfxDWriteFontList::AddSizeOfIncludingThis(MallocSizeOf aMallocSizeOf, |
|
1368 FontListSizes* aSizes) const |
|
1369 { |
|
1370 aSizes->mFontListSize += aMallocSizeOf(this); |
|
1371 AddSizeOfExcludingThis(aMallocSizeOf, aSizes); |
|
1372 } |
|
1373 |
|
1374 static HRESULT GetFamilyName(IDWriteFont *aFont, nsString& aFamilyName) |
|
1375 { |
|
1376 HRESULT hr; |
|
1377 nsRefPtr<IDWriteFontFamily> family; |
|
1378 |
|
1379 // clean out previous value |
|
1380 aFamilyName.Truncate(); |
|
1381 |
|
1382 hr = aFont->GetFontFamily(getter_AddRefs(family)); |
|
1383 if (FAILED(hr)) { |
|
1384 return hr; |
|
1385 } |
|
1386 |
|
1387 nsRefPtr<IDWriteLocalizedStrings> familyNames; |
|
1388 |
|
1389 hr = family->GetFamilyNames(getter_AddRefs(familyNames)); |
|
1390 if (FAILED(hr)) { |
|
1391 return hr; |
|
1392 } |
|
1393 |
|
1394 UINT32 index = 0; |
|
1395 BOOL exists = false; |
|
1396 |
|
1397 hr = familyNames->FindLocaleName(L"en-us", &index, &exists); |
|
1398 if (FAILED(hr)) { |
|
1399 return hr; |
|
1400 } |
|
1401 |
|
1402 // If the specified locale doesn't exist, select the first on the list. |
|
1403 if (!exists) { |
|
1404 index = 0; |
|
1405 } |
|
1406 |
|
1407 AutoFallibleTArray<WCHAR, 32> name; |
|
1408 UINT32 length; |
|
1409 |
|
1410 hr = familyNames->GetStringLength(index, &length); |
|
1411 if (FAILED(hr)) { |
|
1412 return hr; |
|
1413 } |
|
1414 |
|
1415 if (!name.SetLength(length + 1)) { |
|
1416 return E_FAIL; |
|
1417 } |
|
1418 hr = familyNames->GetString(index, name.Elements(), length + 1); |
|
1419 if (FAILED(hr)) { |
|
1420 return hr; |
|
1421 } |
|
1422 |
|
1423 aFamilyName.Assign(name.Elements()); |
|
1424 return S_OK; |
|
1425 } |
|
1426 |
|
1427 // bug 705594 - the method below doesn't actually do any "drawing", it's only |
|
1428 // used to invoke the DirectWrite layout engine to determine the fallback font |
|
1429 // for a given character. |
|
1430 |
|
1431 IFACEMETHODIMP FontFallbackRenderer::DrawGlyphRun( |
|
1432 void* clientDrawingContext, |
|
1433 FLOAT baselineOriginX, |
|
1434 FLOAT baselineOriginY, |
|
1435 DWRITE_MEASURING_MODE measuringMode, |
|
1436 DWRITE_GLYPH_RUN const* glyphRun, |
|
1437 DWRITE_GLYPH_RUN_DESCRIPTION const* glyphRunDescription, |
|
1438 IUnknown* clientDrawingEffect |
|
1439 ) |
|
1440 { |
|
1441 if (!mSystemFonts) { |
|
1442 return E_FAIL; |
|
1443 } |
|
1444 |
|
1445 HRESULT hr = S_OK; |
|
1446 |
|
1447 nsRefPtr<IDWriteFont> font; |
|
1448 hr = mSystemFonts->GetFontFromFontFace(glyphRun->fontFace, |
|
1449 getter_AddRefs(font)); |
|
1450 if (FAILED(hr)) { |
|
1451 return hr; |
|
1452 } |
|
1453 |
|
1454 // copy the family name |
|
1455 hr = GetFamilyName(font, mFamilyName); |
|
1456 if (FAILED(hr)) { |
|
1457 return hr; |
|
1458 } |
|
1459 |
|
1460 // Arial is used as the default fallback font |
|
1461 // so if it matches ==> no font found |
|
1462 if (mFamilyName.EqualsLiteral("Arial")) { |
|
1463 mFamilyName.Truncate(); |
|
1464 return E_FAIL; |
|
1465 } |
|
1466 return hr; |
|
1467 } |
|
1468 |
|
1469 gfxFontEntry* |
|
1470 gfxDWriteFontList::GlobalFontFallback(const uint32_t aCh, |
|
1471 int32_t aRunScript, |
|
1472 const gfxFontStyle* aMatchStyle, |
|
1473 uint32_t& aCmapCount, |
|
1474 gfxFontFamily** aMatchedFamily) |
|
1475 { |
|
1476 bool useCmaps = gfxPlatform::GetPlatform()->UseCmapsDuringSystemFallback(); |
|
1477 |
|
1478 if (useCmaps) { |
|
1479 return gfxPlatformFontList::GlobalFontFallback(aCh, |
|
1480 aRunScript, |
|
1481 aMatchStyle, |
|
1482 aCmapCount, |
|
1483 aMatchedFamily); |
|
1484 } |
|
1485 |
|
1486 HRESULT hr; |
|
1487 |
|
1488 nsRefPtr<IDWriteFactory> dwFactory = |
|
1489 gfxWindowsPlatform::GetPlatform()->GetDWriteFactory(); |
|
1490 if (!dwFactory) { |
|
1491 return nullptr; |
|
1492 } |
|
1493 |
|
1494 // initialize fallback renderer |
|
1495 if (!mFallbackRenderer) { |
|
1496 mFallbackRenderer = new FontFallbackRenderer(dwFactory); |
|
1497 } |
|
1498 |
|
1499 // initialize text format |
|
1500 if (!mFallbackFormat) { |
|
1501 hr = dwFactory->CreateTextFormat(L"Arial", nullptr, |
|
1502 DWRITE_FONT_WEIGHT_REGULAR, |
|
1503 DWRITE_FONT_STYLE_NORMAL, |
|
1504 DWRITE_FONT_STRETCH_NORMAL, |
|
1505 72.0f, L"en-us", |
|
1506 getter_AddRefs(mFallbackFormat)); |
|
1507 if (FAILED(hr)) { |
|
1508 return nullptr; |
|
1509 } |
|
1510 } |
|
1511 |
|
1512 // set up string with fallback character |
|
1513 wchar_t str[16]; |
|
1514 uint32_t strLen; |
|
1515 |
|
1516 if (IS_IN_BMP(aCh)) { |
|
1517 str[0] = static_cast<wchar_t> (aCh); |
|
1518 str[1] = 0; |
|
1519 strLen = 1; |
|
1520 } else { |
|
1521 str[0] = static_cast<wchar_t> (H_SURROGATE(aCh)); |
|
1522 str[1] = static_cast<wchar_t> (L_SURROGATE(aCh)); |
|
1523 str[2] = 0; |
|
1524 strLen = 2; |
|
1525 } |
|
1526 |
|
1527 // set up layout |
|
1528 nsRefPtr<IDWriteTextLayout> fallbackLayout; |
|
1529 |
|
1530 hr = dwFactory->CreateTextLayout(str, strLen, mFallbackFormat, |
|
1531 200.0f, 200.0f, |
|
1532 getter_AddRefs(fallbackLayout)); |
|
1533 if (FAILED(hr)) { |
|
1534 return nullptr; |
|
1535 } |
|
1536 |
|
1537 // call the draw method to invoke the DirectWrite layout functions |
|
1538 // which determine the fallback font |
|
1539 hr = fallbackLayout->Draw(nullptr, mFallbackRenderer, 50.0f, 50.0f); |
|
1540 if (FAILED(hr)) { |
|
1541 return nullptr; |
|
1542 } |
|
1543 |
|
1544 gfxFontFamily *family = FindFamily(mFallbackRenderer->FallbackFamilyName()); |
|
1545 if (family) { |
|
1546 gfxFontEntry *fontEntry; |
|
1547 bool needsBold; // ignored in the system fallback case |
|
1548 fontEntry = family->FindFontForStyle(*aMatchStyle, needsBold); |
|
1549 if (fontEntry && fontEntry->TestCharacterMap(aCh)) { |
|
1550 *aMatchedFamily = family; |
|
1551 return fontEntry; |
|
1552 } |
|
1553 Telemetry::Accumulate(Telemetry::BAD_FALLBACK_FONT, true); |
|
1554 } |
|
1555 |
|
1556 return nullptr; |
|
1557 } |
|
1558 |
|
1559 // used to load system-wide font info on off-main thread |
|
1560 class DirectWriteFontInfo : public FontInfoData { |
|
1561 public: |
|
1562 DirectWriteFontInfo(bool aLoadOtherNames, |
|
1563 bool aLoadFaceNames, |
|
1564 bool aLoadCmaps) : |
|
1565 FontInfoData(aLoadOtherNames, aLoadFaceNames, aLoadCmaps) |
|
1566 {} |
|
1567 |
|
1568 virtual ~DirectWriteFontInfo() {} |
|
1569 |
|
1570 // loads font data for all members of a given family |
|
1571 virtual void LoadFontFamilyData(const nsAString& aFamilyName); |
|
1572 |
|
1573 nsRefPtr<IDWriteFontCollection> mSystemFonts; |
|
1574 }; |
|
1575 |
|
1576 void |
|
1577 DirectWriteFontInfo::LoadFontFamilyData(const nsAString& aFamilyName) |
|
1578 { |
|
1579 // lookup the family |
|
1580 nsAutoTArray<wchar_t, 32> famName; |
|
1581 |
|
1582 uint32_t len = aFamilyName.Length(); |
|
1583 famName.SetLength(len + 1); |
|
1584 memcpy(famName.Elements(), aFamilyName.BeginReading(), len * sizeof(char16_t)); |
|
1585 famName[len] = 0; |
|
1586 |
|
1587 HRESULT hr; |
|
1588 BOOL exists = false; |
|
1589 |
|
1590 uint32_t index; |
|
1591 hr = mSystemFonts->FindFamilyName(famName.Elements(), &index, &exists); |
|
1592 if (FAILED(hr) || !exists) { |
|
1593 return; |
|
1594 } |
|
1595 |
|
1596 nsRefPtr<IDWriteFontFamily> family; |
|
1597 mSystemFonts->GetFontFamily(index, getter_AddRefs(family)); |
|
1598 if (!family) { |
|
1599 return; |
|
1600 } |
|
1601 |
|
1602 // later versions of DirectWrite support querying the fullname/psname |
|
1603 bool loadFaceNamesUsingDirectWrite = mLoadFaceNames; |
|
1604 |
|
1605 for (uint32_t i = 0; i < family->GetFontCount(); i++) { |
|
1606 // get the font |
|
1607 nsRefPtr<IDWriteFont> dwFont; |
|
1608 hr = family->GetFont(i, getter_AddRefs(dwFont)); |
|
1609 if (FAILED(hr)) { |
|
1610 // This should never happen. |
|
1611 NS_WARNING("Failed to get existing font from family."); |
|
1612 continue; |
|
1613 } |
|
1614 |
|
1615 if (dwFont->GetSimulations() & DWRITE_FONT_SIMULATIONS_OBLIQUE) { |
|
1616 // We don't want these. |
|
1617 continue; |
|
1618 } |
|
1619 |
|
1620 mLoadStats.fonts++; |
|
1621 |
|
1622 // get the name of the face |
|
1623 nsString fullID(aFamilyName); |
|
1624 nsAutoString fontName; |
|
1625 hr = GetDirectWriteFontName(dwFont, fontName); |
|
1626 if (FAILED(hr)) { |
|
1627 continue; |
|
1628 } |
|
1629 fullID.Append(NS_LITERAL_STRING(" ")); |
|
1630 fullID.Append(fontName); |
|
1631 |
|
1632 FontFaceData fontData; |
|
1633 bool haveData = true; |
|
1634 nsRefPtr<IDWriteFontFace> dwFontFace; |
|
1635 |
|
1636 if (mLoadFaceNames) { |
|
1637 // try to load using DirectWrite first |
|
1638 if (loadFaceNamesUsingDirectWrite) { |
|
1639 hr = GetDirectWriteFaceName(dwFont, PSNAME_ID, fontData.mPostscriptName); |
|
1640 if (FAILED(hr)) { |
|
1641 loadFaceNamesUsingDirectWrite = false; |
|
1642 } |
|
1643 hr = GetDirectWriteFaceName(dwFont, FULLNAME_ID, fontData.mFullName); |
|
1644 if (FAILED(hr)) { |
|
1645 loadFaceNamesUsingDirectWrite = false; |
|
1646 } |
|
1647 } |
|
1648 |
|
1649 // if DirectWrite read fails, load directly from name table |
|
1650 if (!loadFaceNamesUsingDirectWrite) { |
|
1651 hr = dwFont->CreateFontFace(getter_AddRefs(dwFontFace)); |
|
1652 if (SUCCEEDED(hr)) { |
|
1653 uint32_t kNAME = |
|
1654 NativeEndian::swapToBigEndian(TRUETYPE_TAG('n','a','m','e')); |
|
1655 const char *nameData; |
|
1656 BOOL exists; |
|
1657 void* ctx; |
|
1658 uint32_t nameSize; |
|
1659 |
|
1660 hr = dwFontFace->TryGetFontTable( |
|
1661 kNAME, |
|
1662 (const void**)&nameData, &nameSize, &ctx, &exists); |
|
1663 |
|
1664 if (SUCCEEDED(hr) && nameData && nameSize > 0) { |
|
1665 gfxFontUtils::ReadCanonicalName(nameData, nameSize, |
|
1666 gfxFontUtils::NAME_ID_FULL, |
|
1667 fontData.mFullName); |
|
1668 gfxFontUtils::ReadCanonicalName(nameData, nameSize, |
|
1669 gfxFontUtils::NAME_ID_POSTSCRIPT, |
|
1670 fontData.mPostscriptName); |
|
1671 dwFontFace->ReleaseFontTable(ctx); |
|
1672 } |
|
1673 } |
|
1674 } |
|
1675 |
|
1676 haveData = !fontData.mPostscriptName.IsEmpty() || |
|
1677 !fontData.mFullName.IsEmpty(); |
|
1678 if (haveData) { |
|
1679 mLoadStats.facenames++; |
|
1680 } |
|
1681 } |
|
1682 |
|
1683 // cmaps |
|
1684 if (mLoadCmaps) { |
|
1685 if (!dwFontFace) { |
|
1686 hr = dwFont->CreateFontFace(getter_AddRefs(dwFontFace)); |
|
1687 if (!SUCCEEDED(hr)) { |
|
1688 continue; |
|
1689 } |
|
1690 } |
|
1691 |
|
1692 uint32_t kCMAP = |
|
1693 NativeEndian::swapToBigEndian(TRUETYPE_TAG('c','m','a','p')); |
|
1694 const uint8_t *cmapData; |
|
1695 BOOL exists; |
|
1696 void* ctx; |
|
1697 uint32_t cmapSize; |
|
1698 |
|
1699 hr = dwFontFace->TryGetFontTable(kCMAP, |
|
1700 (const void**)&cmapData, &cmapSize, &ctx, &exists); |
|
1701 |
|
1702 if (SUCCEEDED(hr)) { |
|
1703 bool cmapLoaded = false; |
|
1704 bool unicodeFont = false, symbolFont = false; |
|
1705 nsRefPtr<gfxCharacterMap> charmap = new gfxCharacterMap(); |
|
1706 uint32_t offset; |
|
1707 |
|
1708 if (cmapData && |
|
1709 cmapSize > 0 && |
|
1710 NS_SUCCEEDED( |
|
1711 gfxFontUtils::ReadCMAP(cmapData, cmapSize, *charmap, |
|
1712 offset, unicodeFont, symbolFont))) { |
|
1713 fontData.mCharacterMap = charmap; |
|
1714 fontData.mUVSOffset = offset; |
|
1715 fontData.mSymbolFont = symbolFont; |
|
1716 cmapLoaded = true; |
|
1717 mLoadStats.cmaps++; |
|
1718 } |
|
1719 dwFontFace->ReleaseFontTable(ctx); |
|
1720 haveData = haveData || cmapLoaded; |
|
1721 } |
|
1722 } |
|
1723 |
|
1724 // if have data, load |
|
1725 if (haveData) { |
|
1726 mFontFaceData.Put(fullID, fontData); |
|
1727 } |
|
1728 } |
|
1729 } |
|
1730 |
|
1731 already_AddRefed<FontInfoData> |
|
1732 gfxDWriteFontList::CreateFontInfoData() |
|
1733 { |
|
1734 bool loadCmaps = !UsesSystemFallback() || |
|
1735 gfxPlatform::GetPlatform()->UseCmapsDuringSystemFallback(); |
|
1736 |
|
1737 nsRefPtr<DirectWriteFontInfo> fi = |
|
1738 new DirectWriteFontInfo(false, NeedFullnamePostscriptNames(), loadCmaps); |
|
1739 gfxWindowsPlatform::GetPlatform()->GetDWriteFactory()-> |
|
1740 GetSystemFontCollection(getter_AddRefs(fi->mSystemFonts)); |
|
1741 |
|
1742 return fi.forget(); |
|
1743 } |