|
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/DebugOnly.h" |
|
7 #include <algorithm> |
|
8 |
|
9 #ifdef MOZ_LOGGING |
|
10 #define FORCE_PR_LOG /* Allow logging in the release build */ |
|
11 #endif |
|
12 #include "prlog.h" |
|
13 |
|
14 #include "gfxGDIFontList.h" |
|
15 #include "gfxWindowsPlatform.h" |
|
16 #include "gfxUserFontSet.h" |
|
17 #include "gfxFontUtils.h" |
|
18 #include "gfxGDIFont.h" |
|
19 |
|
20 #include "nsServiceManagerUtils.h" |
|
21 #include "nsTArray.h" |
|
22 #include "nsUnicharUtils.h" |
|
23 |
|
24 #include "nsDirectoryServiceUtils.h" |
|
25 #include "nsDirectoryServiceDefs.h" |
|
26 #include "nsAppDirectoryServiceDefs.h" |
|
27 #include "nsISimpleEnumerator.h" |
|
28 #include "nsIWindowsRegKey.h" |
|
29 #include "gfxFontConstants.h" |
|
30 |
|
31 #include "mozilla/MemoryReporting.h" |
|
32 #include "mozilla/Telemetry.h" |
|
33 #include "mozilla/WindowsVersion.h" |
|
34 |
|
35 #include <usp10.h> |
|
36 |
|
37 using namespace mozilla; |
|
38 |
|
39 #define ROUND(x) floor((x) + 0.5) |
|
40 |
|
41 |
|
42 #ifndef CLEARTYPE_QUALITY |
|
43 #define CLEARTYPE_QUALITY 5 |
|
44 #endif |
|
45 |
|
46 #ifdef PR_LOGGING |
|
47 #define LOG_FONTLIST(args) PR_LOG(gfxPlatform::GetLog(eGfxLog_fontlist), \ |
|
48 PR_LOG_DEBUG, args) |
|
49 #define LOG_FONTLIST_ENABLED() PR_LOG_TEST( \ |
|
50 gfxPlatform::GetLog(eGfxLog_fontlist), \ |
|
51 PR_LOG_DEBUG) |
|
52 |
|
53 #define LOG_CMAPDATA_ENABLED() PR_LOG_TEST( \ |
|
54 gfxPlatform::GetLog(eGfxLog_cmapdata), \ |
|
55 PR_LOG_DEBUG) |
|
56 |
|
57 #endif // PR_LOGGING |
|
58 |
|
59 static __inline void |
|
60 BuildKeyNameFromFontName(nsAString &aName) |
|
61 { |
|
62 if (aName.Length() >= LF_FACESIZE) |
|
63 aName.Truncate(LF_FACESIZE - 1); |
|
64 ToLowerCase(aName); |
|
65 } |
|
66 |
|
67 // Implementation of gfxPlatformFontList for Win32 GDI, |
|
68 // using GDI font enumeration APIs to get the list of fonts |
|
69 |
|
70 class WinUserFontData : public gfxUserFontData { |
|
71 public: |
|
72 WinUserFontData(HANDLE aFontRef) |
|
73 : mFontRef(aFontRef) |
|
74 { } |
|
75 |
|
76 virtual ~WinUserFontData() |
|
77 { |
|
78 DebugOnly<BOOL> success; |
|
79 success = RemoveFontMemResourceEx(mFontRef); |
|
80 #if DEBUG |
|
81 if (!success) { |
|
82 char buf[256]; |
|
83 sprintf(buf, "error deleting font handle (%p) - RemoveFontMemResourceEx failed", mFontRef); |
|
84 NS_ASSERTION(success, buf); |
|
85 } |
|
86 #endif |
|
87 } |
|
88 |
|
89 HANDLE mFontRef; |
|
90 }; |
|
91 |
|
92 BYTE |
|
93 FontTypeToOutPrecision(uint8_t fontType) |
|
94 { |
|
95 BYTE ret; |
|
96 switch (fontType) { |
|
97 case GFX_FONT_TYPE_TT_OPENTYPE: |
|
98 case GFX_FONT_TYPE_TRUETYPE: |
|
99 ret = OUT_TT_ONLY_PRECIS; |
|
100 break; |
|
101 case GFX_FONT_TYPE_PS_OPENTYPE: |
|
102 ret = OUT_PS_ONLY_PRECIS; |
|
103 break; |
|
104 case GFX_FONT_TYPE_TYPE1: |
|
105 ret = OUT_OUTLINE_PRECIS; |
|
106 break; |
|
107 case GFX_FONT_TYPE_RASTER: |
|
108 ret = OUT_RASTER_PRECIS; |
|
109 break; |
|
110 case GFX_FONT_TYPE_DEVICE: |
|
111 ret = OUT_DEVICE_PRECIS; |
|
112 break; |
|
113 default: |
|
114 ret = OUT_DEFAULT_PRECIS; |
|
115 } |
|
116 return ret; |
|
117 } |
|
118 |
|
119 /*************************************************************** |
|
120 * |
|
121 * GDIFontEntry |
|
122 * |
|
123 */ |
|
124 |
|
125 GDIFontEntry::GDIFontEntry(const nsAString& aFaceName, |
|
126 gfxWindowsFontType aFontType, |
|
127 bool aItalic, uint16_t aWeight, int16_t aStretch, |
|
128 gfxUserFontData *aUserFontData, |
|
129 bool aFamilyHasItalicFace) |
|
130 : gfxFontEntry(aFaceName), |
|
131 mWindowsFamily(0), mWindowsPitch(0), |
|
132 mFontType(aFontType), |
|
133 mForceGDI(false), |
|
134 mFamilyHasItalicFace(aFamilyHasItalicFace), |
|
135 mCharset(), mUnicodeRanges() |
|
136 { |
|
137 mUserFontData = aUserFontData; |
|
138 mItalic = aItalic; |
|
139 mWeight = aWeight; |
|
140 mStretch = aStretch; |
|
141 if (IsType1()) |
|
142 mForceGDI = true; |
|
143 mIsUserFont = aUserFontData != nullptr; |
|
144 |
|
145 InitLogFont(aFaceName, aFontType); |
|
146 } |
|
147 |
|
148 nsresult |
|
149 GDIFontEntry::ReadCMAP(FontInfoData *aFontInfoData) |
|
150 { |
|
151 // attempt this once, if errors occur leave a blank cmap |
|
152 if (mCharacterMap) { |
|
153 return NS_OK; |
|
154 } |
|
155 |
|
156 // skip non-SFNT fonts completely |
|
157 if (mFontType != GFX_FONT_TYPE_PS_OPENTYPE && |
|
158 mFontType != GFX_FONT_TYPE_TT_OPENTYPE && |
|
159 mFontType != GFX_FONT_TYPE_TRUETYPE) |
|
160 { |
|
161 mCharacterMap = new gfxCharacterMap(); |
|
162 mCharacterMap->mBuildOnTheFly = true; |
|
163 return NS_ERROR_FAILURE; |
|
164 } |
|
165 |
|
166 nsRefPtr<gfxCharacterMap> charmap; |
|
167 nsresult rv; |
|
168 bool unicodeFont = false, symbolFont = false; |
|
169 |
|
170 if (aFontInfoData && (charmap = GetCMAPFromFontInfo(aFontInfoData, |
|
171 mUVSOffset, |
|
172 symbolFont))) { |
|
173 mSymbolFont = symbolFont; |
|
174 rv = NS_OK; |
|
175 } else { |
|
176 uint32_t kCMAP = TRUETYPE_TAG('c','m','a','p'); |
|
177 charmap = new gfxCharacterMap(); |
|
178 AutoFallibleTArray<uint8_t,16384> cmap; |
|
179 rv = CopyFontTable(kCMAP, cmap); |
|
180 |
|
181 if (NS_SUCCEEDED(rv)) { |
|
182 rv = gfxFontUtils::ReadCMAP(cmap.Elements(), cmap.Length(), |
|
183 *charmap, mUVSOffset, |
|
184 unicodeFont, symbolFont); |
|
185 } |
|
186 mSymbolFont = symbolFont; |
|
187 } |
|
188 |
|
189 mHasCmapTable = NS_SUCCEEDED(rv); |
|
190 if (mHasCmapTable) { |
|
191 gfxPlatformFontList *pfl = gfxPlatformFontList::PlatformFontList(); |
|
192 mCharacterMap = pfl->FindCharMap(charmap); |
|
193 } else { |
|
194 // if error occurred, initialize to null cmap |
|
195 mCharacterMap = new gfxCharacterMap(); |
|
196 // For fonts where we failed to read the character map, |
|
197 // we can take a slow path to look up glyphs character by character |
|
198 mCharacterMap->mBuildOnTheFly = true; |
|
199 } |
|
200 |
|
201 #ifdef PR_LOGGING |
|
202 LOG_FONTLIST(("(fontlist-cmap) name: %s, size: %d hash: %8.8x%s\n", |
|
203 NS_ConvertUTF16toUTF8(mName).get(), |
|
204 charmap->SizeOfIncludingThis(moz_malloc_size_of), |
|
205 charmap->mHash, mCharacterMap == charmap ? " new" : "")); |
|
206 if (LOG_CMAPDATA_ENABLED()) { |
|
207 char prefix[256]; |
|
208 sprintf(prefix, "(cmapdata) name: %.220s", |
|
209 NS_ConvertUTF16toUTF8(mName).get()); |
|
210 charmap->Dump(prefix, eGfxLog_cmapdata); |
|
211 } |
|
212 #endif |
|
213 |
|
214 return rv; |
|
215 } |
|
216 |
|
217 bool |
|
218 GDIFontEntry::IsSymbolFont() |
|
219 { |
|
220 // initialize cmap first |
|
221 HasCmapTable(); |
|
222 return mSymbolFont; |
|
223 } |
|
224 |
|
225 gfxFont * |
|
226 GDIFontEntry::CreateFontInstance(const gfxFontStyle* aFontStyle, bool aNeedsBold) |
|
227 { |
|
228 bool isXP = !IsVistaOrLater(); |
|
229 |
|
230 bool useClearType = isXP && !aFontStyle->systemFont && |
|
231 (gfxWindowsPlatform::GetPlatform()->UseClearTypeAlways() || |
|
232 (mIsUserFont && !mIsLocalUserFont && |
|
233 gfxWindowsPlatform::GetPlatform()->UseClearTypeForDownloadableFonts())); |
|
234 |
|
235 return new gfxGDIFont(this, aFontStyle, aNeedsBold, |
|
236 (useClearType ? gfxFont::kAntialiasSubpixel |
|
237 : gfxFont::kAntialiasDefault)); |
|
238 } |
|
239 |
|
240 nsresult |
|
241 GDIFontEntry::CopyFontTable(uint32_t aTableTag, |
|
242 FallibleTArray<uint8_t>& aBuffer) |
|
243 { |
|
244 if (!IsTrueType()) { |
|
245 return NS_ERROR_FAILURE; |
|
246 } |
|
247 |
|
248 AutoDC dc; |
|
249 AutoSelectFont font(dc.GetDC(), &mLogFont); |
|
250 if (font.IsValid()) { |
|
251 uint32_t tableSize = |
|
252 ::GetFontData(dc.GetDC(), |
|
253 NativeEndian::swapToBigEndian(aTableTag), |
|
254 0, nullptr, 0); |
|
255 if (tableSize != GDI_ERROR) { |
|
256 if (aBuffer.SetLength(tableSize)) { |
|
257 ::GetFontData(dc.GetDC(), |
|
258 NativeEndian::swapToBigEndian(aTableTag), 0, |
|
259 aBuffer.Elements(), tableSize); |
|
260 return NS_OK; |
|
261 } |
|
262 return NS_ERROR_OUT_OF_MEMORY; |
|
263 } |
|
264 } |
|
265 return NS_ERROR_FAILURE; |
|
266 } |
|
267 |
|
268 void |
|
269 GDIFontEntry::FillLogFont(LOGFONTW *aLogFont, |
|
270 uint16_t aWeight, gfxFloat aSize, |
|
271 bool aUseCleartype) |
|
272 { |
|
273 memcpy(aLogFont, &mLogFont, sizeof(LOGFONTW)); |
|
274 |
|
275 aLogFont->lfHeight = (LONG)-ROUND(aSize); |
|
276 |
|
277 if (aLogFont->lfHeight == 0) { |
|
278 aLogFont->lfHeight = -1; |
|
279 } |
|
280 |
|
281 // If a non-zero weight is passed in, use this to override the original |
|
282 // weight in the entry's logfont. This is used to control synthetic bolding |
|
283 // for installed families with no bold face, and for downloaded fonts |
|
284 // (but NOT for local user fonts, because it could cause a different, |
|
285 // glyph-incompatible face to be used) |
|
286 if (aWeight) { |
|
287 aLogFont->lfWeight = aWeight; |
|
288 } |
|
289 |
|
290 // for non-local() user fonts, we never want to apply italics here; |
|
291 // if the face is described as italic, we should use it as-is, |
|
292 // and if it's not, but then the element is styled italic, we'll use |
|
293 // a cairo transform to create fake italic (oblique) |
|
294 if (IsUserFont() && !IsLocalUserFont()) { |
|
295 aLogFont->lfItalic = 0; |
|
296 } |
|
297 |
|
298 aLogFont->lfQuality = (aUseCleartype ? CLEARTYPE_QUALITY : DEFAULT_QUALITY); |
|
299 } |
|
300 |
|
301 #define MISSING_GLYPH 0x1F // glyph index returned for missing characters |
|
302 // on WinXP with .fon fonts, but not Type1 (.pfb) |
|
303 |
|
304 bool |
|
305 GDIFontEntry::TestCharacterMap(uint32_t aCh) |
|
306 { |
|
307 if (!mCharacterMap) { |
|
308 ReadCMAP(); |
|
309 NS_ASSERTION(mCharacterMap, "failed to initialize a character map"); |
|
310 } |
|
311 |
|
312 if (mCharacterMap->mBuildOnTheFly) { |
|
313 if (aCh > 0xFFFF) |
|
314 return false; |
|
315 |
|
316 // previous code was using the group style |
|
317 gfxFontStyle fakeStyle; |
|
318 if (mItalic) |
|
319 fakeStyle.style = NS_FONT_STYLE_ITALIC; |
|
320 fakeStyle.weight = mWeight * 100; |
|
321 |
|
322 nsRefPtr<gfxFont> tempFont = FindOrMakeFont(&fakeStyle, false); |
|
323 if (!tempFont || !tempFont->Valid()) |
|
324 return false; |
|
325 gfxGDIFont *font = static_cast<gfxGDIFont*>(tempFont.get()); |
|
326 |
|
327 HDC dc = GetDC((HWND)nullptr); |
|
328 SetGraphicsMode(dc, GM_ADVANCED); |
|
329 HFONT hfont = font->GetHFONT(); |
|
330 HFONT oldFont = (HFONT)SelectObject(dc, hfont); |
|
331 |
|
332 wchar_t str[1] = { aCh }; |
|
333 WORD glyph[1]; |
|
334 |
|
335 bool hasGlyph = false; |
|
336 |
|
337 // Bug 573038 - in some cases GetGlyphIndicesW returns 0xFFFF for a |
|
338 // missing glyph or 0x1F in other cases to indicate the "invalid" |
|
339 // glyph. Map both cases to "not found" |
|
340 if (IsType1() || mForceGDI) { |
|
341 // Type1 fonts and uniscribe APIs don't get along. |
|
342 // ScriptGetCMap will return E_HANDLE |
|
343 DWORD ret = GetGlyphIndicesW(dc, str, 1, |
|
344 glyph, GGI_MARK_NONEXISTING_GLYPHS); |
|
345 if (ret != GDI_ERROR |
|
346 && glyph[0] != 0xFFFF |
|
347 && (IsType1() || glyph[0] != MISSING_GLYPH)) |
|
348 { |
|
349 hasGlyph = true; |
|
350 } |
|
351 } else { |
|
352 // ScriptGetCMap works better than GetGlyphIndicesW |
|
353 // for things like bitmap/vector fonts |
|
354 SCRIPT_CACHE sc = nullptr; |
|
355 HRESULT rv = ScriptGetCMap(dc, &sc, str, 1, 0, glyph); |
|
356 if (rv == S_OK) |
|
357 hasGlyph = true; |
|
358 } |
|
359 |
|
360 SelectObject(dc, oldFont); |
|
361 ReleaseDC(nullptr, dc); |
|
362 |
|
363 if (hasGlyph) { |
|
364 mCharacterMap->set(aCh); |
|
365 return true; |
|
366 } |
|
367 } else { |
|
368 // font had a cmap so simply check that |
|
369 return mCharacterMap->test(aCh); |
|
370 } |
|
371 |
|
372 return false; |
|
373 } |
|
374 |
|
375 void |
|
376 GDIFontEntry::InitLogFont(const nsAString& aName, |
|
377 gfxWindowsFontType aFontType) |
|
378 { |
|
379 #define CLIP_TURNOFF_FONTASSOCIATION 0x40 |
|
380 |
|
381 mLogFont.lfHeight = -1; |
|
382 |
|
383 // Fill in logFont structure |
|
384 mLogFont.lfWidth = 0; |
|
385 mLogFont.lfEscapement = 0; |
|
386 mLogFont.lfOrientation = 0; |
|
387 mLogFont.lfUnderline = FALSE; |
|
388 mLogFont.lfStrikeOut = FALSE; |
|
389 mLogFont.lfCharSet = DEFAULT_CHARSET; |
|
390 mLogFont.lfOutPrecision = FontTypeToOutPrecision(aFontType); |
|
391 mLogFont.lfClipPrecision = CLIP_TURNOFF_FONTASSOCIATION; |
|
392 mLogFont.lfQuality = DEFAULT_QUALITY; |
|
393 mLogFont.lfPitchAndFamily = DEFAULT_PITCH | FF_DONTCARE; |
|
394 // always force lfItalic if we want it. Font selection code will |
|
395 // do its best to give us an italic font entry, but if no face exists |
|
396 // it may give us a regular one based on weight. Windows should |
|
397 // do fake italic for us in that case. |
|
398 mLogFont.lfItalic = mItalic; |
|
399 mLogFont.lfWeight = mWeight; |
|
400 |
|
401 int len = std::min<int>(aName.Length(), LF_FACESIZE - 1); |
|
402 memcpy(&mLogFont.lfFaceName, aName.BeginReading(), len * sizeof(char16_t)); |
|
403 mLogFont.lfFaceName[len] = '\0'; |
|
404 } |
|
405 |
|
406 GDIFontEntry* |
|
407 GDIFontEntry::CreateFontEntry(const nsAString& aName, |
|
408 gfxWindowsFontType aFontType, bool aItalic, |
|
409 uint16_t aWeight, int16_t aStretch, |
|
410 gfxUserFontData* aUserFontData, |
|
411 bool aFamilyHasItalicFace) |
|
412 { |
|
413 // jtdfix - need to set charset, unicode ranges, pitch/family |
|
414 |
|
415 GDIFontEntry *fe = new GDIFontEntry(aName, aFontType, aItalic, |
|
416 aWeight, aStretch, aUserFontData, |
|
417 aFamilyHasItalicFace); |
|
418 |
|
419 return fe; |
|
420 } |
|
421 |
|
422 void |
|
423 GDIFontEntry::AddSizeOfIncludingThis(MallocSizeOf aMallocSizeOf, |
|
424 FontListSizes* aSizes) const |
|
425 { |
|
426 aSizes->mFontListSize += aMallocSizeOf(this); |
|
427 AddSizeOfExcludingThis(aMallocSizeOf, aSizes); |
|
428 } |
|
429 |
|
430 /*************************************************************** |
|
431 * |
|
432 * GDIFontFamily |
|
433 * |
|
434 */ |
|
435 |
|
436 int CALLBACK |
|
437 GDIFontFamily::FamilyAddStylesProc(const ENUMLOGFONTEXW *lpelfe, |
|
438 const NEWTEXTMETRICEXW *nmetrics, |
|
439 DWORD fontType, LPARAM data) |
|
440 { |
|
441 const NEWTEXTMETRICW& metrics = nmetrics->ntmTm; |
|
442 LOGFONTW logFont = lpelfe->elfLogFont; |
|
443 GDIFontFamily *ff = reinterpret_cast<GDIFontFamily*>(data); |
|
444 |
|
445 // Some fonts claim to support things > 900, but we don't so clamp the sizes |
|
446 logFont.lfWeight = clamped(logFont.lfWeight, LONG(100), LONG(900)); |
|
447 |
|
448 gfxWindowsFontType feType = GDIFontEntry::DetermineFontType(metrics, fontType); |
|
449 |
|
450 GDIFontEntry *fe = nullptr; |
|
451 for (uint32_t i = 0; i < ff->mAvailableFonts.Length(); ++i) { |
|
452 fe = static_cast<GDIFontEntry*>(ff->mAvailableFonts[i].get()); |
|
453 if (feType > fe->mFontType) { |
|
454 // if the new type is better than the old one, remove the old entries |
|
455 ff->mAvailableFonts.RemoveElementAt(i); |
|
456 --i; |
|
457 } else if (feType < fe->mFontType) { |
|
458 // otherwise if the new type is worse, skip it |
|
459 return 1; |
|
460 } |
|
461 } |
|
462 |
|
463 for (uint32_t i = 0; i < ff->mAvailableFonts.Length(); ++i) { |
|
464 fe = static_cast<GDIFontEntry*>(ff->mAvailableFonts[i].get()); |
|
465 // check if we already know about this face |
|
466 if (fe->mWeight == logFont.lfWeight && |
|
467 fe->mItalic == (logFont.lfItalic == 0xFF)) { |
|
468 // update the charset bit here since this could be different |
|
469 fe->mCharset.set(metrics.tmCharSet); |
|
470 return 1; |
|
471 } |
|
472 } |
|
473 |
|
474 // We can't set the hasItalicFace flag correctly here, |
|
475 // because we might not have seen the family's italic face(s) yet. |
|
476 // So we'll set that flag for all members after loading all the faces. |
|
477 fe = GDIFontEntry::CreateFontEntry(nsDependentString(lpelfe->elfFullName), |
|
478 feType, (logFont.lfItalic == 0xFF), |
|
479 (uint16_t) (logFont.lfWeight), 0, |
|
480 nullptr, false); |
|
481 if (!fe) |
|
482 return 1; |
|
483 |
|
484 ff->AddFontEntry(fe); |
|
485 |
|
486 // mark the charset bit |
|
487 fe->mCharset.set(metrics.tmCharSet); |
|
488 |
|
489 fe->mWindowsFamily = logFont.lfPitchAndFamily & 0xF0; |
|
490 fe->mWindowsPitch = logFont.lfPitchAndFamily & 0x0F; |
|
491 |
|
492 if (nmetrics->ntmFontSig.fsUsb[0] != 0x00000000 && |
|
493 nmetrics->ntmFontSig.fsUsb[1] != 0x00000000 && |
|
494 nmetrics->ntmFontSig.fsUsb[2] != 0x00000000 && |
|
495 nmetrics->ntmFontSig.fsUsb[3] != 0x00000000) { |
|
496 |
|
497 // set the unicode ranges |
|
498 uint32_t x = 0; |
|
499 for (uint32_t i = 0; i < 4; ++i) { |
|
500 DWORD range = nmetrics->ntmFontSig.fsUsb[i]; |
|
501 for (uint32_t k = 0; k < 32; ++k) { |
|
502 fe->mUnicodeRanges.set(x++, (range & (1 << k)) != 0); |
|
503 } |
|
504 } |
|
505 } |
|
506 |
|
507 #ifdef PR_LOGGING |
|
508 if (LOG_FONTLIST_ENABLED()) { |
|
509 LOG_FONTLIST(("(fontlist) added (%s) to family (%s)" |
|
510 " with style: %s weight: %d stretch: %d", |
|
511 NS_ConvertUTF16toUTF8(fe->Name()).get(), |
|
512 NS_ConvertUTF16toUTF8(ff->Name()).get(), |
|
513 (logFont.lfItalic == 0xff) ? "italic" : "normal", |
|
514 logFont.lfWeight, fe->Stretch())); |
|
515 } |
|
516 #endif |
|
517 return 1; |
|
518 } |
|
519 |
|
520 void |
|
521 GDIFontFamily::FindStyleVariations(FontInfoData *aFontInfoData) |
|
522 { |
|
523 if (mHasStyles) |
|
524 return; |
|
525 mHasStyles = true; |
|
526 |
|
527 HDC hdc = GetDC(nullptr); |
|
528 SetGraphicsMode(hdc, GM_ADVANCED); |
|
529 |
|
530 LOGFONTW logFont; |
|
531 memset(&logFont, 0, sizeof(LOGFONTW)); |
|
532 logFont.lfCharSet = DEFAULT_CHARSET; |
|
533 logFont.lfPitchAndFamily = 0; |
|
534 uint32_t l = std::min<uint32_t>(mName.Length(), LF_FACESIZE - 1); |
|
535 memcpy(logFont.lfFaceName, mName.get(), l * sizeof(char16_t)); |
|
536 |
|
537 EnumFontFamiliesExW(hdc, &logFont, |
|
538 (FONTENUMPROCW)GDIFontFamily::FamilyAddStylesProc, |
|
539 (LPARAM)this, 0); |
|
540 #ifdef PR_LOGGING |
|
541 if (LOG_FONTLIST_ENABLED() && mAvailableFonts.Length() == 0) { |
|
542 LOG_FONTLIST(("(fontlist) no styles available in family \"%s\"", |
|
543 NS_ConvertUTF16toUTF8(mName).get())); |
|
544 } |
|
545 #endif |
|
546 |
|
547 ReleaseDC(nullptr, hdc); |
|
548 |
|
549 if (mIsBadUnderlineFamily) { |
|
550 SetBadUnderlineFonts(); |
|
551 } |
|
552 |
|
553 // check for existence of italic face(s); if present, set the |
|
554 // FamilyHasItalic flag on all faces so that we'll know *not* |
|
555 // to use GDI's fake-italic effect with them |
|
556 size_t count = mAvailableFonts.Length(); |
|
557 for (size_t i = 0; i < count; ++i) { |
|
558 if (mAvailableFonts[i]->IsItalic()) { |
|
559 for (uint32_t j = 0; j < count; ++j) { |
|
560 static_cast<GDIFontEntry*>(mAvailableFonts[j].get())-> |
|
561 mFamilyHasItalicFace = true; |
|
562 } |
|
563 break; |
|
564 } |
|
565 } |
|
566 } |
|
567 |
|
568 /*************************************************************** |
|
569 * |
|
570 * gfxGDIFontList |
|
571 * |
|
572 */ |
|
573 |
|
574 gfxGDIFontList::gfxGDIFontList() |
|
575 : mFontSubstitutes(50) |
|
576 { |
|
577 } |
|
578 |
|
579 static void |
|
580 RemoveCharsetFromFontSubstitute(nsAString &aName) |
|
581 { |
|
582 int32_t comma = aName.FindChar(char16_t(',')); |
|
583 if (comma >= 0) |
|
584 aName.Truncate(comma); |
|
585 } |
|
586 |
|
587 #define MAX_VALUE_NAME 512 |
|
588 #define MAX_VALUE_DATA 512 |
|
589 |
|
590 nsresult |
|
591 gfxGDIFontList::GetFontSubstitutes() |
|
592 { |
|
593 HKEY hKey; |
|
594 DWORD i, rv, lenAlias, lenActual, valueType; |
|
595 WCHAR aliasName[MAX_VALUE_NAME]; |
|
596 WCHAR actualName[MAX_VALUE_DATA]; |
|
597 |
|
598 if (RegOpenKeyExW(HKEY_LOCAL_MACHINE, |
|
599 L"SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\FontSubstitutes", |
|
600 0, KEY_READ, &hKey) != ERROR_SUCCESS) |
|
601 { |
|
602 return NS_ERROR_FAILURE; |
|
603 } |
|
604 |
|
605 for (i = 0, rv = ERROR_SUCCESS; rv != ERROR_NO_MORE_ITEMS; i++) { |
|
606 aliasName[0] = 0; |
|
607 lenAlias = ArrayLength(aliasName); |
|
608 actualName[0] = 0; |
|
609 lenActual = sizeof(actualName); |
|
610 rv = RegEnumValueW(hKey, i, aliasName, &lenAlias, nullptr, &valueType, |
|
611 (LPBYTE)actualName, &lenActual); |
|
612 |
|
613 if (rv != ERROR_SUCCESS || valueType != REG_SZ || lenAlias == 0) { |
|
614 continue; |
|
615 } |
|
616 |
|
617 if (aliasName[0] == WCHAR('@')) { |
|
618 continue; |
|
619 } |
|
620 |
|
621 nsAutoString substituteName((char16_t*) aliasName); |
|
622 nsAutoString actualFontName((char16_t*) actualName); |
|
623 RemoveCharsetFromFontSubstitute(substituteName); |
|
624 BuildKeyNameFromFontName(substituteName); |
|
625 RemoveCharsetFromFontSubstitute(actualFontName); |
|
626 BuildKeyNameFromFontName(actualFontName); |
|
627 gfxFontFamily *ff; |
|
628 if (!actualFontName.IsEmpty() && |
|
629 (ff = mFontFamilies.GetWeak(actualFontName))) { |
|
630 mFontSubstitutes.Put(substituteName, ff); |
|
631 } else { |
|
632 mNonExistingFonts.AppendElement(substituteName); |
|
633 } |
|
634 } |
|
635 |
|
636 // "Courier" on a default Windows install is an ugly bitmap font. |
|
637 // If there is no substitution for Courier in the registry |
|
638 // substitute "Courier" with "Courier New". |
|
639 nsAutoString substituteName; |
|
640 substituteName.AssignLiteral("Courier"); |
|
641 BuildKeyNameFromFontName(substituteName); |
|
642 if (!mFontSubstitutes.GetWeak(substituteName)) { |
|
643 gfxFontFamily *ff; |
|
644 nsAutoString actualFontName; |
|
645 actualFontName.AssignLiteral("Courier New"); |
|
646 BuildKeyNameFromFontName(actualFontName); |
|
647 ff = mFontFamilies.GetWeak(actualFontName); |
|
648 if (ff) { |
|
649 mFontSubstitutes.Put(substituteName, ff); |
|
650 } |
|
651 } |
|
652 return NS_OK; |
|
653 } |
|
654 |
|
655 nsresult |
|
656 gfxGDIFontList::InitFontList() |
|
657 { |
|
658 Telemetry::AutoTimer<Telemetry::GDI_INITFONTLIST_TOTAL> timer; |
|
659 gfxFontCache *fc = gfxFontCache::GetCache(); |
|
660 if (fc) |
|
661 fc->AgeAllGenerations(); |
|
662 |
|
663 // reset font lists |
|
664 gfxPlatformFontList::InitFontList(); |
|
665 |
|
666 mFontSubstitutes.Clear(); |
|
667 mNonExistingFonts.Clear(); |
|
668 |
|
669 // iterate over available families |
|
670 LOGFONTW logfont; |
|
671 memset(&logfont, 0, sizeof(logfont)); |
|
672 logfont.lfCharSet = DEFAULT_CHARSET; |
|
673 |
|
674 AutoDC hdc; |
|
675 int result = EnumFontFamiliesExW(hdc.GetDC(), &logfont, |
|
676 (FONTENUMPROCW)&EnumFontFamExProc, |
|
677 0, 0); |
|
678 |
|
679 GetFontSubstitutes(); |
|
680 |
|
681 GetPrefsAndStartLoader(); |
|
682 |
|
683 return NS_OK; |
|
684 } |
|
685 |
|
686 int CALLBACK |
|
687 gfxGDIFontList::EnumFontFamExProc(ENUMLOGFONTEXW *lpelfe, |
|
688 NEWTEXTMETRICEXW *lpntme, |
|
689 DWORD fontType, |
|
690 LPARAM lParam) |
|
691 { |
|
692 const LOGFONTW& lf = lpelfe->elfLogFont; |
|
693 |
|
694 if (lf.lfFaceName[0] == '@') { |
|
695 return 1; |
|
696 } |
|
697 |
|
698 nsAutoString name(lf.lfFaceName); |
|
699 BuildKeyNameFromFontName(name); |
|
700 |
|
701 gfxGDIFontList *fontList = PlatformFontList(); |
|
702 |
|
703 if (!fontList->mFontFamilies.GetWeak(name)) { |
|
704 nsDependentString faceName(lf.lfFaceName); |
|
705 nsRefPtr<gfxFontFamily> family = new GDIFontFamily(faceName); |
|
706 fontList->mFontFamilies.Put(name, family); |
|
707 |
|
708 // if locale is such that CJK font names are the default coming from |
|
709 // GDI, then if a family name is non-ASCII immediately read in other |
|
710 // family names. This assures that MS Gothic, MS Mincho are all found |
|
711 // before lookups begin. |
|
712 if (!IsASCII(faceName)) { |
|
713 family->ReadOtherFamilyNames(gfxPlatformFontList::PlatformFontList()); |
|
714 } |
|
715 |
|
716 if (fontList->mBadUnderlineFamilyNames.Contains(name)) |
|
717 family->SetBadUnderlineFamily(); |
|
718 } |
|
719 |
|
720 return 1; |
|
721 } |
|
722 |
|
723 gfxFontEntry* |
|
724 gfxGDIFontList::LookupLocalFont(const gfxProxyFontEntry *aProxyEntry, |
|
725 const nsAString& aFullname) |
|
726 { |
|
727 gfxFontEntry *lookup; |
|
728 |
|
729 lookup = LookupInFaceNameLists(aFullname); |
|
730 if (!lookup) { |
|
731 return nullptr; |
|
732 } |
|
733 |
|
734 bool isCFF = false; // jtdfix -- need to determine this |
|
735 |
|
736 // use the face name from the lookup font entry, which will be the localized |
|
737 // face name which GDI mapping tables use (e.g. with the system locale set to |
|
738 // Dutch, a fullname of 'Arial Bold' will find a font entry with the face name |
|
739 // 'Arial Vet' which can be used as a key in GDI font lookups). |
|
740 GDIFontEntry *fe = GDIFontEntry::CreateFontEntry(lookup->Name(), |
|
741 gfxWindowsFontType(isCFF ? GFX_FONT_TYPE_PS_OPENTYPE : GFX_FONT_TYPE_TRUETYPE) /*type*/, |
|
742 lookup->mItalic ? NS_FONT_STYLE_ITALIC : NS_FONT_STYLE_NORMAL, |
|
743 lookup->mWeight, aProxyEntry->mStretch, nullptr, |
|
744 static_cast<GDIFontEntry*>(lookup)->mFamilyHasItalicFace); |
|
745 |
|
746 if (!fe) |
|
747 return nullptr; |
|
748 |
|
749 fe->mIsUserFont = true; |
|
750 fe->mIsLocalUserFont = true; |
|
751 |
|
752 // make the new font entry match the proxy entry style characteristics |
|
753 fe->mWeight = (aProxyEntry->mWeight == 0 ? 400 : aProxyEntry->mWeight); |
|
754 fe->mItalic = aProxyEntry->mItalic; |
|
755 |
|
756 return fe; |
|
757 } |
|
758 |
|
759 gfxFontEntry* |
|
760 gfxGDIFontList::MakePlatformFont(const gfxProxyFontEntry *aProxyEntry, |
|
761 const uint8_t *aFontData, |
|
762 uint32_t aLength) |
|
763 { |
|
764 // MakePlatformFont is responsible for deleting the font data with NS_Free |
|
765 // so we set up a stack object to ensure it is freed even if we take an |
|
766 // early exit |
|
767 struct FontDataDeleter { |
|
768 FontDataDeleter(const uint8_t *aFontData) |
|
769 : mFontData(aFontData) { } |
|
770 ~FontDataDeleter() { NS_Free((void*)mFontData); } |
|
771 const uint8_t *mFontData; |
|
772 }; |
|
773 FontDataDeleter autoDelete(aFontData); |
|
774 |
|
775 bool isCFF = gfxFontUtils::IsCffFont(aFontData); |
|
776 |
|
777 nsresult rv; |
|
778 HANDLE fontRef = nullptr; |
|
779 |
|
780 nsAutoString uniqueName; |
|
781 rv = gfxFontUtils::MakeUniqueUserFontName(uniqueName); |
|
782 if (NS_FAILED(rv)) |
|
783 return nullptr; |
|
784 |
|
785 FallibleTArray<uint8_t> newFontData; |
|
786 |
|
787 rv = gfxFontUtils::RenameFont(uniqueName, aFontData, aLength, &newFontData); |
|
788 |
|
789 if (NS_FAILED(rv)) |
|
790 return nullptr; |
|
791 |
|
792 DWORD numFonts = 0; |
|
793 |
|
794 uint8_t *fontData = reinterpret_cast<uint8_t*> (newFontData.Elements()); |
|
795 uint32_t fontLength = newFontData.Length(); |
|
796 NS_ASSERTION(fontData, "null font data after renaming"); |
|
797 |
|
798 // http://msdn.microsoft.com/en-us/library/ms533942(VS.85).aspx |
|
799 // "A font that is added by AddFontMemResourceEx is always private |
|
800 // to the process that made the call and is not enumerable." |
|
801 fontRef = AddFontMemResourceEx(fontData, fontLength, |
|
802 0 /* reserved */, &numFonts); |
|
803 if (!fontRef) |
|
804 return nullptr; |
|
805 |
|
806 // only load fonts with a single face contained in the data |
|
807 // AddFontMemResourceEx generates an additional face name for |
|
808 // vertical text if the font supports vertical writing but since |
|
809 // the font is referenced via the name this can be ignored |
|
810 if (fontRef && numFonts > 2) { |
|
811 RemoveFontMemResourceEx(fontRef); |
|
812 return nullptr; |
|
813 } |
|
814 |
|
815 // make a new font entry using the unique name |
|
816 WinUserFontData *winUserFontData = new WinUserFontData(fontRef); |
|
817 uint16_t w = (aProxyEntry->mWeight == 0 ? 400 : aProxyEntry->mWeight); |
|
818 |
|
819 GDIFontEntry *fe = GDIFontEntry::CreateFontEntry(uniqueName, |
|
820 gfxWindowsFontType(isCFF ? GFX_FONT_TYPE_PS_OPENTYPE : GFX_FONT_TYPE_TRUETYPE) /*type*/, |
|
821 uint32_t(aProxyEntry->mItalic ? NS_FONT_STYLE_ITALIC : NS_FONT_STYLE_NORMAL), |
|
822 w, aProxyEntry->mStretch, winUserFontData, false); |
|
823 |
|
824 if (!fe) |
|
825 return fe; |
|
826 |
|
827 fe->mIsUserFont = true; |
|
828 |
|
829 // Uniscribe doesn't place CFF fonts loaded privately |
|
830 // via AddFontMemResourceEx on XP/Vista |
|
831 if (isCFF && !IsWin7OrLater()) { |
|
832 fe->mForceGDI = true; |
|
833 } |
|
834 |
|
835 return fe; |
|
836 } |
|
837 |
|
838 gfxFontFamily* |
|
839 gfxGDIFontList::GetDefaultFont(const gfxFontStyle* aStyle) |
|
840 { |
|
841 // this really shouldn't fail to find a font.... |
|
842 HGDIOBJ hGDI = ::GetStockObject(DEFAULT_GUI_FONT); |
|
843 LOGFONTW logFont; |
|
844 if (hGDI && ::GetObjectW(hGDI, sizeof(logFont), &logFont)) { |
|
845 nsAutoString resolvedName; |
|
846 if (ResolveFontName(nsDependentString(logFont.lfFaceName), resolvedName)) { |
|
847 return FindFamily(resolvedName); |
|
848 } |
|
849 } |
|
850 |
|
851 // ...but just in case, try another approach as well |
|
852 NONCLIENTMETRICSW ncm; |
|
853 ncm.cbSize = sizeof(ncm); |
|
854 BOOL status = ::SystemParametersInfoW(SPI_GETNONCLIENTMETRICS, |
|
855 sizeof(ncm), &ncm, 0); |
|
856 if (status) { |
|
857 nsAutoString resolvedName; |
|
858 if (ResolveFontName(nsDependentString(ncm.lfMessageFont.lfFaceName), resolvedName)) { |
|
859 return FindFamily(resolvedName); |
|
860 } |
|
861 } |
|
862 |
|
863 return nullptr; |
|
864 } |
|
865 |
|
866 |
|
867 bool |
|
868 gfxGDIFontList::ResolveFontName(const nsAString& aFontName, nsAString& aResolvedFontName) |
|
869 { |
|
870 nsAutoString keyName(aFontName); |
|
871 BuildKeyNameFromFontName(keyName); |
|
872 |
|
873 gfxFontFamily *ff = mFontSubstitutes.GetWeak(keyName); |
|
874 if (ff) { |
|
875 aResolvedFontName = ff->Name(); |
|
876 return true; |
|
877 } |
|
878 |
|
879 if (mNonExistingFonts.Contains(keyName)) |
|
880 return false; |
|
881 |
|
882 if (gfxPlatformFontList::ResolveFontName(aFontName, aResolvedFontName)) |
|
883 return true; |
|
884 |
|
885 return false; |
|
886 } |
|
887 |
|
888 void |
|
889 gfxGDIFontList::AddSizeOfExcludingThis(MallocSizeOf aMallocSizeOf, |
|
890 FontListSizes* aSizes) const |
|
891 { |
|
892 gfxPlatformFontList::AddSizeOfExcludingThis(aMallocSizeOf, aSizes); |
|
893 aSizes->mFontListSize += |
|
894 mFontSubstitutes.SizeOfExcludingThis(SizeOfFamilyNameEntryExcludingThis, |
|
895 aMallocSizeOf); |
|
896 aSizes->mFontListSize += |
|
897 mNonExistingFonts.SizeOfExcludingThis(aMallocSizeOf); |
|
898 for (uint32_t i = 0; i < mNonExistingFonts.Length(); ++i) { |
|
899 aSizes->mFontListSize += |
|
900 mNonExistingFonts[i].SizeOfExcludingThisIfUnshared(aMallocSizeOf); |
|
901 } |
|
902 } |
|
903 |
|
904 void |
|
905 gfxGDIFontList::AddSizeOfIncludingThis(MallocSizeOf aMallocSizeOf, |
|
906 FontListSizes* aSizes) const |
|
907 { |
|
908 aSizes->mFontListSize += aMallocSizeOf(this); |
|
909 AddSizeOfExcludingThis(aMallocSizeOf, aSizes); |
|
910 } |
|
911 |
|
912 // used to load system-wide font info on off-main thread |
|
913 class GDIFontInfo : public FontInfoData { |
|
914 public: |
|
915 GDIFontInfo(bool aLoadOtherNames, |
|
916 bool aLoadFaceNames, |
|
917 bool aLoadCmaps) : |
|
918 FontInfoData(aLoadOtherNames, aLoadFaceNames, aLoadCmaps) |
|
919 {} |
|
920 |
|
921 virtual ~GDIFontInfo() {} |
|
922 |
|
923 virtual void Load() { |
|
924 mHdc = GetDC(nullptr); |
|
925 SetGraphicsMode(mHdc, GM_ADVANCED); |
|
926 FontInfoData::Load(); |
|
927 ReleaseDC(nullptr, mHdc); |
|
928 } |
|
929 |
|
930 // loads font data for all members of a given family |
|
931 virtual void LoadFontFamilyData(const nsAString& aFamilyName); |
|
932 |
|
933 // callback for GDI EnumFontFamiliesExW call |
|
934 static int CALLBACK EnumerateFontsForFamily(const ENUMLOGFONTEXW *lpelfe, |
|
935 const NEWTEXTMETRICEXW *nmetrics, |
|
936 DWORD fontType, LPARAM data); |
|
937 |
|
938 HDC mHdc; |
|
939 }; |
|
940 |
|
941 struct EnumerateFontsForFamilyData { |
|
942 EnumerateFontsForFamilyData(const nsAString& aFamilyName, |
|
943 GDIFontInfo& aFontInfo) |
|
944 : mFamilyName(aFamilyName), mFontInfo(aFontInfo) |
|
945 {} |
|
946 |
|
947 nsString mFamilyName; |
|
948 nsTArray<nsString> mOtherFamilyNames; |
|
949 GDIFontInfo& mFontInfo; |
|
950 nsString mPreviousFontName; |
|
951 }; |
|
952 |
|
953 int CALLBACK GDIFontInfo::EnumerateFontsForFamily( |
|
954 const ENUMLOGFONTEXW *lpelfe, |
|
955 const NEWTEXTMETRICEXW *nmetrics, |
|
956 DWORD fontType, LPARAM data) |
|
957 { |
|
958 EnumerateFontsForFamilyData *famData = |
|
959 reinterpret_cast<EnumerateFontsForFamilyData*>(data); |
|
960 HDC hdc = famData->mFontInfo.mHdc; |
|
961 LOGFONTW logFont = lpelfe->elfLogFont; |
|
962 const NEWTEXTMETRICW& metrics = nmetrics->ntmTm; |
|
963 |
|
964 AutoSelectFont font(hdc, &logFont); |
|
965 if (!font.IsValid()) { |
|
966 return 1; |
|
967 } |
|
968 |
|
969 FontFaceData fontData; |
|
970 nsDependentString fontName(lpelfe->elfFullName); |
|
971 |
|
972 // callback called for each style-charset so return if style already seen |
|
973 if (fontName.Equals(famData->mPreviousFontName)) { |
|
974 return 1; |
|
975 } |
|
976 famData->mPreviousFontName = fontName; |
|
977 famData->mFontInfo.mLoadStats.fonts++; |
|
978 |
|
979 // read name table info |
|
980 bool nameDataLoaded = false; |
|
981 if (famData->mFontInfo.mLoadFaceNames || famData->mFontInfo.mLoadOtherNames) { |
|
982 uint32_t kNAME = |
|
983 NativeEndian::swapToBigEndian(TRUETYPE_TAG('n','a','m','e')); |
|
984 uint32_t nameSize; |
|
985 AutoFallibleTArray<uint8_t, 1024> nameData; |
|
986 |
|
987 nameSize = ::GetFontData(hdc, kNAME, 0, nullptr, 0); |
|
988 if (nameSize != GDI_ERROR && |
|
989 nameSize > 0 && |
|
990 nameData.SetLength(nameSize)) { |
|
991 ::GetFontData(hdc, kNAME, 0, nameData.Elements(), nameSize); |
|
992 |
|
993 // face names |
|
994 if (famData->mFontInfo.mLoadFaceNames) { |
|
995 gfxFontUtils::ReadCanonicalName((const char*)(nameData.Elements()), nameSize, |
|
996 gfxFontUtils::NAME_ID_FULL, |
|
997 fontData.mFullName); |
|
998 gfxFontUtils::ReadCanonicalName((const char*)(nameData.Elements()), nameSize, |
|
999 gfxFontUtils::NAME_ID_POSTSCRIPT, |
|
1000 fontData.mPostscriptName); |
|
1001 nameDataLoaded = true; |
|
1002 famData->mFontInfo.mLoadStats.facenames++; |
|
1003 } |
|
1004 |
|
1005 // other family names |
|
1006 if (famData->mFontInfo.mLoadOtherNames) { |
|
1007 gfxFontFamily::ReadOtherFamilyNamesForFace(famData->mFamilyName, |
|
1008 (const char*)(nameData.Elements()), |
|
1009 nameSize, |
|
1010 famData->mOtherFamilyNames, |
|
1011 false); |
|
1012 } |
|
1013 } |
|
1014 } |
|
1015 |
|
1016 // read cmap |
|
1017 bool cmapLoaded = false; |
|
1018 gfxWindowsFontType feType = |
|
1019 GDIFontEntry::DetermineFontType(metrics, fontType); |
|
1020 if (famData->mFontInfo.mLoadCmaps && |
|
1021 (feType == GFX_FONT_TYPE_PS_OPENTYPE || |
|
1022 feType == GFX_FONT_TYPE_TT_OPENTYPE || |
|
1023 feType == GFX_FONT_TYPE_TRUETYPE)) |
|
1024 { |
|
1025 uint32_t kCMAP = |
|
1026 NativeEndian::swapToBigEndian(TRUETYPE_TAG('c','m','a','p')); |
|
1027 uint32_t cmapSize; |
|
1028 AutoFallibleTArray<uint8_t, 1024> cmapData; |
|
1029 |
|
1030 cmapSize = ::GetFontData(hdc, kCMAP, 0, nullptr, 0); |
|
1031 if (cmapSize != GDI_ERROR && |
|
1032 cmapSize > 0 && |
|
1033 cmapData.SetLength(cmapSize)) { |
|
1034 ::GetFontData(hdc, kCMAP, 0, cmapData.Elements(), cmapSize); |
|
1035 bool cmapLoaded = false; |
|
1036 bool unicodeFont = false, symbolFont = false; |
|
1037 nsRefPtr<gfxCharacterMap> charmap = new gfxCharacterMap(); |
|
1038 uint32_t offset; |
|
1039 |
|
1040 if (NS_SUCCEEDED(gfxFontUtils::ReadCMAP(cmapData.Elements(), |
|
1041 cmapSize, *charmap, |
|
1042 offset, unicodeFont, |
|
1043 symbolFont))) { |
|
1044 fontData.mCharacterMap = charmap; |
|
1045 fontData.mUVSOffset = offset; |
|
1046 fontData.mSymbolFont = symbolFont; |
|
1047 cmapLoaded = true; |
|
1048 famData->mFontInfo.mLoadStats.cmaps++; |
|
1049 } |
|
1050 } |
|
1051 } |
|
1052 |
|
1053 if (cmapLoaded || nameDataLoaded) { |
|
1054 famData->mFontInfo.mFontFaceData.Put(fontName, fontData); |
|
1055 } |
|
1056 |
|
1057 return 1; |
|
1058 } |
|
1059 |
|
1060 void |
|
1061 GDIFontInfo::LoadFontFamilyData(const nsAString& aFamilyName) |
|
1062 { |
|
1063 // iterate over the family |
|
1064 LOGFONTW logFont; |
|
1065 memset(&logFont, 0, sizeof(LOGFONTW)); |
|
1066 logFont.lfCharSet = DEFAULT_CHARSET; |
|
1067 logFont.lfPitchAndFamily = 0; |
|
1068 uint32_t l = std::min<uint32_t>(aFamilyName.Length(), LF_FACESIZE - 1); |
|
1069 memcpy(logFont.lfFaceName, aFamilyName.BeginReading(), l * sizeof(char16_t)); |
|
1070 |
|
1071 EnumerateFontsForFamilyData data(aFamilyName, *this); |
|
1072 |
|
1073 EnumFontFamiliesExW(mHdc, &logFont, |
|
1074 (FONTENUMPROCW)GDIFontInfo::EnumerateFontsForFamily, |
|
1075 (LPARAM)(&data), 0); |
|
1076 |
|
1077 // if found other names, insert them |
|
1078 if (data.mOtherFamilyNames.Length() != 0) { |
|
1079 mOtherFamilyNames.Put(aFamilyName, data.mOtherFamilyNames); |
|
1080 mLoadStats.othernames += data.mOtherFamilyNames.Length(); |
|
1081 } |
|
1082 } |
|
1083 |
|
1084 already_AddRefed<FontInfoData> |
|
1085 gfxGDIFontList::CreateFontInfoData() |
|
1086 { |
|
1087 bool loadCmaps = !UsesSystemFallback() || |
|
1088 gfxPlatform::GetPlatform()->UseCmapsDuringSystemFallback(); |
|
1089 |
|
1090 nsRefPtr<GDIFontInfo> fi = |
|
1091 new GDIFontInfo(true, NeedFullnamePostscriptNames(), loadCmaps); |
|
1092 |
|
1093 return fi.forget(); |
|
1094 } |