Tue, 06 Jan 2015 21:39:09 +0100
Conditionally force memory storage according to privacy.thirdparty.isolate;
This solves Tor bug #9701, complying with disk avoidance documented in
https://www.torproject.org/projects/torbrowser/design/#disk-avoidance.
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/. */
6 #include "mozilla/DebugOnly.h"
7 #include <algorithm>
9 #ifdef MOZ_LOGGING
10 #define FORCE_PR_LOG /* Allow logging in the release build */
11 #endif
12 #include "prlog.h"
14 #include "gfxGDIFontList.h"
15 #include "gfxWindowsPlatform.h"
16 #include "gfxUserFontSet.h"
17 #include "gfxFontUtils.h"
18 #include "gfxGDIFont.h"
20 #include "nsServiceManagerUtils.h"
21 #include "nsTArray.h"
22 #include "nsUnicharUtils.h"
24 #include "nsDirectoryServiceUtils.h"
25 #include "nsDirectoryServiceDefs.h"
26 #include "nsAppDirectoryServiceDefs.h"
27 #include "nsISimpleEnumerator.h"
28 #include "nsIWindowsRegKey.h"
29 #include "gfxFontConstants.h"
31 #include "mozilla/MemoryReporting.h"
32 #include "mozilla/Telemetry.h"
33 #include "mozilla/WindowsVersion.h"
35 #include <usp10.h>
37 using namespace mozilla;
39 #define ROUND(x) floor((x) + 0.5)
42 #ifndef CLEARTYPE_QUALITY
43 #define CLEARTYPE_QUALITY 5
44 #endif
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)
53 #define LOG_CMAPDATA_ENABLED() PR_LOG_TEST( \
54 gfxPlatform::GetLog(eGfxLog_cmapdata), \
55 PR_LOG_DEBUG)
57 #endif // PR_LOGGING
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 }
67 // Implementation of gfxPlatformFontList for Win32 GDI,
68 // using GDI font enumeration APIs to get the list of fonts
70 class WinUserFontData : public gfxUserFontData {
71 public:
72 WinUserFontData(HANDLE aFontRef)
73 : mFontRef(aFontRef)
74 { }
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 }
89 HANDLE mFontRef;
90 };
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 }
119 /***************************************************************
120 *
121 * GDIFontEntry
122 *
123 */
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;
145 InitLogFont(aFaceName, aFontType);
146 }
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 }
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 }
166 nsRefPtr<gfxCharacterMap> charmap;
167 nsresult rv;
168 bool unicodeFont = false, symbolFont = false;
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);
181 if (NS_SUCCEEDED(rv)) {
182 rv = gfxFontUtils::ReadCMAP(cmap.Elements(), cmap.Length(),
183 *charmap, mUVSOffset,
184 unicodeFont, symbolFont);
185 }
186 mSymbolFont = symbolFont;
187 }
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 }
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
214 return rv;
215 }
217 bool
218 GDIFontEntry::IsSymbolFont()
219 {
220 // initialize cmap first
221 HasCmapTable();
222 return mSymbolFont;
223 }
225 gfxFont *
226 GDIFontEntry::CreateFontInstance(const gfxFontStyle* aFontStyle, bool aNeedsBold)
227 {
228 bool isXP = !IsVistaOrLater();
230 bool useClearType = isXP && !aFontStyle->systemFont &&
231 (gfxWindowsPlatform::GetPlatform()->UseClearTypeAlways() ||
232 (mIsUserFont && !mIsLocalUserFont &&
233 gfxWindowsPlatform::GetPlatform()->UseClearTypeForDownloadableFonts()));
235 return new gfxGDIFont(this, aFontStyle, aNeedsBold,
236 (useClearType ? gfxFont::kAntialiasSubpixel
237 : gfxFont::kAntialiasDefault));
238 }
240 nsresult
241 GDIFontEntry::CopyFontTable(uint32_t aTableTag,
242 FallibleTArray<uint8_t>& aBuffer)
243 {
244 if (!IsTrueType()) {
245 return NS_ERROR_FAILURE;
246 }
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 }
268 void
269 GDIFontEntry::FillLogFont(LOGFONTW *aLogFont,
270 uint16_t aWeight, gfxFloat aSize,
271 bool aUseCleartype)
272 {
273 memcpy(aLogFont, &mLogFont, sizeof(LOGFONTW));
275 aLogFont->lfHeight = (LONG)-ROUND(aSize);
277 if (aLogFont->lfHeight == 0) {
278 aLogFont->lfHeight = -1;
279 }
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 }
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 }
298 aLogFont->lfQuality = (aUseCleartype ? CLEARTYPE_QUALITY : DEFAULT_QUALITY);
299 }
301 #define MISSING_GLYPH 0x1F // glyph index returned for missing characters
302 // on WinXP with .fon fonts, but not Type1 (.pfb)
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 }
312 if (mCharacterMap->mBuildOnTheFly) {
313 if (aCh > 0xFFFF)
314 return false;
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;
322 nsRefPtr<gfxFont> tempFont = FindOrMakeFont(&fakeStyle, false);
323 if (!tempFont || !tempFont->Valid())
324 return false;
325 gfxGDIFont *font = static_cast<gfxGDIFont*>(tempFont.get());
327 HDC dc = GetDC((HWND)nullptr);
328 SetGraphicsMode(dc, GM_ADVANCED);
329 HFONT hfont = font->GetHFONT();
330 HFONT oldFont = (HFONT)SelectObject(dc, hfont);
332 wchar_t str[1] = { aCh };
333 WORD glyph[1];
335 bool hasGlyph = false;
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 }
360 SelectObject(dc, oldFont);
361 ReleaseDC(nullptr, dc);
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 }
372 return false;
373 }
375 void
376 GDIFontEntry::InitLogFont(const nsAString& aName,
377 gfxWindowsFontType aFontType)
378 {
379 #define CLIP_TURNOFF_FONTASSOCIATION 0x40
381 mLogFont.lfHeight = -1;
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;
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 }
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
415 GDIFontEntry *fe = new GDIFontEntry(aName, aFontType, aItalic,
416 aWeight, aStretch, aUserFontData,
417 aFamilyHasItalicFace);
419 return fe;
420 }
422 void
423 GDIFontEntry::AddSizeOfIncludingThis(MallocSizeOf aMallocSizeOf,
424 FontListSizes* aSizes) const
425 {
426 aSizes->mFontListSize += aMallocSizeOf(this);
427 AddSizeOfExcludingThis(aMallocSizeOf, aSizes);
428 }
430 /***************************************************************
431 *
432 * GDIFontFamily
433 *
434 */
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);
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));
448 gfxWindowsFontType feType = GDIFontEntry::DetermineFontType(metrics, fontType);
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 }
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 }
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;
484 ff->AddFontEntry(fe);
486 // mark the charset bit
487 fe->mCharset.set(metrics.tmCharSet);
489 fe->mWindowsFamily = logFont.lfPitchAndFamily & 0xF0;
490 fe->mWindowsPitch = logFont.lfPitchAndFamily & 0x0F;
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) {
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 }
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 }
520 void
521 GDIFontFamily::FindStyleVariations(FontInfoData *aFontInfoData)
522 {
523 if (mHasStyles)
524 return;
525 mHasStyles = true;
527 HDC hdc = GetDC(nullptr);
528 SetGraphicsMode(hdc, GM_ADVANCED);
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));
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
547 ReleaseDC(nullptr, hdc);
549 if (mIsBadUnderlineFamily) {
550 SetBadUnderlineFonts();
551 }
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 }
568 /***************************************************************
569 *
570 * gfxGDIFontList
571 *
572 */
574 gfxGDIFontList::gfxGDIFontList()
575 : mFontSubstitutes(50)
576 {
577 }
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 }
587 #define MAX_VALUE_NAME 512
588 #define MAX_VALUE_DATA 512
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];
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 }
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);
613 if (rv != ERROR_SUCCESS || valueType != REG_SZ || lenAlias == 0) {
614 continue;
615 }
617 if (aliasName[0] == WCHAR('@')) {
618 continue;
619 }
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 }
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 }
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();
663 // reset font lists
664 gfxPlatformFontList::InitFontList();
666 mFontSubstitutes.Clear();
667 mNonExistingFonts.Clear();
669 // iterate over available families
670 LOGFONTW logfont;
671 memset(&logfont, 0, sizeof(logfont));
672 logfont.lfCharSet = DEFAULT_CHARSET;
674 AutoDC hdc;
675 int result = EnumFontFamiliesExW(hdc.GetDC(), &logfont,
676 (FONTENUMPROCW)&EnumFontFamExProc,
677 0, 0);
679 GetFontSubstitutes();
681 GetPrefsAndStartLoader();
683 return NS_OK;
684 }
686 int CALLBACK
687 gfxGDIFontList::EnumFontFamExProc(ENUMLOGFONTEXW *lpelfe,
688 NEWTEXTMETRICEXW *lpntme,
689 DWORD fontType,
690 LPARAM lParam)
691 {
692 const LOGFONTW& lf = lpelfe->elfLogFont;
694 if (lf.lfFaceName[0] == '@') {
695 return 1;
696 }
698 nsAutoString name(lf.lfFaceName);
699 BuildKeyNameFromFontName(name);
701 gfxGDIFontList *fontList = PlatformFontList();
703 if (!fontList->mFontFamilies.GetWeak(name)) {
704 nsDependentString faceName(lf.lfFaceName);
705 nsRefPtr<gfxFontFamily> family = new GDIFontFamily(faceName);
706 fontList->mFontFamilies.Put(name, family);
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 }
716 if (fontList->mBadUnderlineFamilyNames.Contains(name))
717 family->SetBadUnderlineFamily();
718 }
720 return 1;
721 }
723 gfxFontEntry*
724 gfxGDIFontList::LookupLocalFont(const gfxProxyFontEntry *aProxyEntry,
725 const nsAString& aFullname)
726 {
727 gfxFontEntry *lookup;
729 lookup = LookupInFaceNameLists(aFullname);
730 if (!lookup) {
731 return nullptr;
732 }
734 bool isCFF = false; // jtdfix -- need to determine this
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);
746 if (!fe)
747 return nullptr;
749 fe->mIsUserFont = true;
750 fe->mIsLocalUserFont = true;
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;
756 return fe;
757 }
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);
775 bool isCFF = gfxFontUtils::IsCffFont(aFontData);
777 nsresult rv;
778 HANDLE fontRef = nullptr;
780 nsAutoString uniqueName;
781 rv = gfxFontUtils::MakeUniqueUserFontName(uniqueName);
782 if (NS_FAILED(rv))
783 return nullptr;
785 FallibleTArray<uint8_t> newFontData;
787 rv = gfxFontUtils::RenameFont(uniqueName, aFontData, aLength, &newFontData);
789 if (NS_FAILED(rv))
790 return nullptr;
792 DWORD numFonts = 0;
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");
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;
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 }
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);
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);
824 if (!fe)
825 return fe;
827 fe->mIsUserFont = true;
829 // Uniscribe doesn't place CFF fonts loaded privately
830 // via AddFontMemResourceEx on XP/Vista
831 if (isCFF && !IsWin7OrLater()) {
832 fe->mForceGDI = true;
833 }
835 return fe;
836 }
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 }
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 }
863 return nullptr;
864 }
867 bool
868 gfxGDIFontList::ResolveFontName(const nsAString& aFontName, nsAString& aResolvedFontName)
869 {
870 nsAutoString keyName(aFontName);
871 BuildKeyNameFromFontName(keyName);
873 gfxFontFamily *ff = mFontSubstitutes.GetWeak(keyName);
874 if (ff) {
875 aResolvedFontName = ff->Name();
876 return true;
877 }
879 if (mNonExistingFonts.Contains(keyName))
880 return false;
882 if (gfxPlatformFontList::ResolveFontName(aFontName, aResolvedFontName))
883 return true;
885 return false;
886 }
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 }
904 void
905 gfxGDIFontList::AddSizeOfIncludingThis(MallocSizeOf aMallocSizeOf,
906 FontListSizes* aSizes) const
907 {
908 aSizes->mFontListSize += aMallocSizeOf(this);
909 AddSizeOfExcludingThis(aMallocSizeOf, aSizes);
910 }
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 {}
921 virtual ~GDIFontInfo() {}
923 virtual void Load() {
924 mHdc = GetDC(nullptr);
925 SetGraphicsMode(mHdc, GM_ADVANCED);
926 FontInfoData::Load();
927 ReleaseDC(nullptr, mHdc);
928 }
930 // loads font data for all members of a given family
931 virtual void LoadFontFamilyData(const nsAString& aFamilyName);
933 // callback for GDI EnumFontFamiliesExW call
934 static int CALLBACK EnumerateFontsForFamily(const ENUMLOGFONTEXW *lpelfe,
935 const NEWTEXTMETRICEXW *nmetrics,
936 DWORD fontType, LPARAM data);
938 HDC mHdc;
939 };
941 struct EnumerateFontsForFamilyData {
942 EnumerateFontsForFamilyData(const nsAString& aFamilyName,
943 GDIFontInfo& aFontInfo)
944 : mFamilyName(aFamilyName), mFontInfo(aFontInfo)
945 {}
947 nsString mFamilyName;
948 nsTArray<nsString> mOtherFamilyNames;
949 GDIFontInfo& mFontInfo;
950 nsString mPreviousFontName;
951 };
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;
964 AutoSelectFont font(hdc, &logFont);
965 if (!font.IsValid()) {
966 return 1;
967 }
969 FontFaceData fontData;
970 nsDependentString fontName(lpelfe->elfFullName);
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++;
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;
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);
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 }
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 }
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;
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;
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 }
1053 if (cmapLoaded || nameDataLoaded) {
1054 famData->mFontInfo.mFontFaceData.Put(fontName, fontData);
1055 }
1057 return 1;
1058 }
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));
1071 EnumerateFontsForFamilyData data(aFamilyName, *this);
1073 EnumFontFamiliesExW(mHdc, &logFont,
1074 (FONTENUMPROCW)GDIFontInfo::EnumerateFontsForFamily,
1075 (LPARAM)(&data), 0);
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 }
1084 already_AddRefed<FontInfoData>
1085 gfxGDIFontList::CreateFontInfoData()
1086 {
1087 bool loadCmaps = !UsesSystemFallback() ||
1088 gfxPlatform::GetPlatform()->UseCmapsDuringSystemFallback();
1090 nsRefPtr<GDIFontInfo> fi =
1091 new GDIFontInfo(true, NeedFullnamePostscriptNames(), loadCmaps);
1093 return fi.forget();
1094 }