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"
10 #define FORCE_PR_LOG /* Allow logging in the release build */
14 #include "gfxGDIFontList.h"
15 #include "gfxWindowsPlatform.h"
16 #include "gfxUserFontSet.h"
17 #include "gfxFontUtils.h"
18 #include "gfxGDIFont.h"
20 #include "nsServiceManagerUtils.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"
37 using namespace mozilla
;
39 #define ROUND(x) floor((x) + 0.5)
42 #ifndef CLEARTYPE_QUALITY
43 #define CLEARTYPE_QUALITY 5
47 #define LOG_FONTLIST(args) PR_LOG(gfxPlatform::GetLog(eGfxLog_fontlist), \
49 #define LOG_FONTLIST_ENABLED() PR_LOG_TEST( \
50 gfxPlatform::GetLog(eGfxLog_fontlist), \
53 #define LOG_CMAPDATA_ENABLED() PR_LOG_TEST( \
54 gfxPlatform::GetLog(eGfxLog_cmapdata), \
60 BuildKeyNameFromFontName(nsAString
&aName
)
62 if (aName
.Length() >= LF_FACESIZE
)
63 aName
.Truncate(LF_FACESIZE
- 1);
67 // Implementation of gfxPlatformFontList for Win32 GDI,
68 // using GDI font enumeration APIs to get the list of fonts
70 class WinUserFontData
: public gfxUserFontData
{
72 WinUserFontData(HANDLE aFontRef
)
76 virtual ~WinUserFontData()
78 DebugOnly
<BOOL
> success
;
79 success
= RemoveFontMemResourceEx(mFontRef
);
83 sprintf(buf
, "error deleting font handle (%p) - RemoveFontMemResourceEx failed", mFontRef
);
84 NS_ASSERTION(success
, buf
);
93 FontTypeToOutPrecision(uint8_t fontType
)
97 case GFX_FONT_TYPE_TT_OPENTYPE
:
98 case GFX_FONT_TYPE_TRUETYPE
:
99 ret
= OUT_TT_ONLY_PRECIS
;
101 case GFX_FONT_TYPE_PS_OPENTYPE
:
102 ret
= OUT_PS_ONLY_PRECIS
;
104 case GFX_FONT_TYPE_TYPE1
:
105 ret
= OUT_OUTLINE_PRECIS
;
107 case GFX_FONT_TYPE_RASTER
:
108 ret
= OUT_RASTER_PRECIS
;
110 case GFX_FONT_TYPE_DEVICE
:
111 ret
= OUT_DEVICE_PRECIS
;
114 ret
= OUT_DEFAULT_PRECIS
;
119 /***************************************************************
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
),
134 mFamilyHasItalicFace(aFamilyHasItalicFace
),
135 mCharset(), mUnicodeRanges()
137 mUserFontData
= aUserFontData
;
143 mIsUserFont
= aUserFontData
!= nullptr;
145 InitLogFont(aFaceName
, aFontType
);
149 GDIFontEntry::ReadCMAP(FontInfoData
*aFontInfoData
)
151 // attempt this once, if errors occur leave a blank cmap
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
)
161 mCharacterMap
= new gfxCharacterMap();
162 mCharacterMap
->mBuildOnTheFly
= true;
163 return NS_ERROR_FAILURE
;
166 nsRefPtr
<gfxCharacterMap
> charmap
;
168 bool unicodeFont
= false, symbolFont
= false;
170 if (aFontInfoData
&& (charmap
= GetCMAPFromFontInfo(aFontInfoData
,
173 mSymbolFont
= symbolFont
;
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
);
186 mSymbolFont
= symbolFont
;
189 mHasCmapTable
= NS_SUCCEEDED(rv
);
191 gfxPlatformFontList
*pfl
= gfxPlatformFontList::PlatformFontList();
192 mCharacterMap
= pfl
->FindCharMap(charmap
);
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;
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()) {
208 sprintf(prefix
, "(cmapdata) name: %.220s",
209 NS_ConvertUTF16toUTF8(mName
).get());
210 charmap
->Dump(prefix
, eGfxLog_cmapdata
);
218 GDIFontEntry::IsSymbolFont()
220 // initialize cmap first
226 GDIFontEntry::CreateFontInstance(const gfxFontStyle
* aFontStyle
, bool aNeedsBold
)
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
));
241 GDIFontEntry::CopyFontTable(uint32_t aTableTag
,
242 FallibleTArray
<uint8_t>& aBuffer
)
245 return NS_ERROR_FAILURE
;
249 AutoSelectFont
font(dc
.GetDC(), &mLogFont
);
250 if (font
.IsValid()) {
252 ::GetFontData(dc
.GetDC(),
253 NativeEndian::swapToBigEndian(aTableTag
),
255 if (tableSize
!= GDI_ERROR
) {
256 if (aBuffer
.SetLength(tableSize
)) {
257 ::GetFontData(dc
.GetDC(),
258 NativeEndian::swapToBigEndian(aTableTag
), 0,
259 aBuffer
.Elements(), tableSize
);
262 return NS_ERROR_OUT_OF_MEMORY
;
265 return NS_ERROR_FAILURE
;
269 GDIFontEntry::FillLogFont(LOGFONTW
*aLogFont
,
270 uint16_t aWeight
, gfxFloat aSize
,
273 memcpy(aLogFont
, &mLogFont
, sizeof(LOGFONTW
));
275 aLogFont
->lfHeight
= (LONG
)-ROUND(aSize
);
277 if (aLogFont
->lfHeight
== 0) {
278 aLogFont
->lfHeight
= -1;
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)
287 aLogFont
->lfWeight
= aWeight
;
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;
298 aLogFont
->lfQuality
= (aUseCleartype
? CLEARTYPE_QUALITY
: DEFAULT_QUALITY
);
301 #define MISSING_GLYPH 0x1F // glyph index returned for missing characters
302 // on WinXP with .fon fonts, but not Type1 (.pfb)
305 GDIFontEntry::TestCharacterMap(uint32_t aCh
)
307 if (!mCharacterMap
) {
309 NS_ASSERTION(mCharacterMap
, "failed to initialize a character map");
312 if (mCharacterMap
->mBuildOnTheFly
) {
316 // previous code was using the group style
317 gfxFontStyle fakeStyle
;
319 fakeStyle
.style
= NS_FONT_STYLE_ITALIC
;
320 fakeStyle
.weight
= mWeight
* 100;
322 nsRefPtr
<gfxFont
> tempFont
= FindOrMakeFont(&fakeStyle
, false);
323 if (!tempFont
|| !tempFont
->Valid())
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
};
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
);
346 && glyph
[0] != 0xFFFF
347 && (IsType1() || glyph
[0] != MISSING_GLYPH
))
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
);
360 SelectObject(dc
, oldFont
);
361 ReleaseDC(nullptr, dc
);
364 mCharacterMap
->set(aCh
);
368 // font had a cmap so simply check that
369 return mCharacterMap
->test(aCh
);
376 GDIFontEntry::InitLogFont(const nsAString
& aName
,
377 gfxWindowsFontType aFontType
)
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';
407 GDIFontEntry::CreateFontEntry(const nsAString
& aName
,
408 gfxWindowsFontType aFontType
, bool aItalic
,
409 uint16_t aWeight
, int16_t aStretch
,
410 gfxUserFontData
* aUserFontData
,
411 bool aFamilyHasItalicFace
)
413 // jtdfix - need to set charset, unicode ranges, pitch/family
415 GDIFontEntry
*fe
= new GDIFontEntry(aName
, aFontType
, aItalic
,
416 aWeight
, aStretch
, aUserFontData
,
417 aFamilyHasItalicFace
);
423 GDIFontEntry::AddSizeOfIncludingThis(MallocSizeOf aMallocSizeOf
,
424 FontListSizes
* aSizes
) const
426 aSizes
->mFontListSize
+= aMallocSizeOf(this);
427 AddSizeOfExcludingThis(aMallocSizeOf
, aSizes
);
430 /***************************************************************
437 GDIFontFamily::FamilyAddStylesProc(const ENUMLOGFONTEXW
*lpelfe
,
438 const NEWTEXTMETRICEXW
*nmetrics
,
439 DWORD fontType
, LPARAM data
)
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
);
457 } else if (feType
< fe
->mFontType
) {
458 // otherwise if the new type is worse, skip it
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
);
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,
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
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);
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()));
521 GDIFontFamily::FindStyleVariations(FontInfoData
*aFontInfoData
)
527 HDC hdc
= GetDC(nullptr);
528 SetGraphicsMode(hdc
, GM_ADVANCED
);
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
,
541 if (LOG_FONTLIST_ENABLED() && mAvailableFonts
.Length() == 0) {
542 LOG_FONTLIST(("(fontlist) no styles available in family \"%s\"",
543 NS_ConvertUTF16toUTF8(mName
).get()));
547 ReleaseDC(nullptr, hdc
);
549 if (mIsBadUnderlineFamily
) {
550 SetBadUnderlineFonts();
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;
568 /***************************************************************
574 gfxGDIFontList::gfxGDIFontList()
575 : mFontSubstitutes(32)
577 #ifdef MOZ_BUNDLED_FONTS
578 ActivateBundledFonts();
583 RemoveCharsetFromFontSubstitute(nsAString
&aName
)
585 int32_t comma
= aName
.FindChar(char16_t(','));
587 aName
.Truncate(comma
);
590 #define MAX_VALUE_NAME 512
591 #define MAX_VALUE_DATA 512
594 gfxGDIFontList::GetFontSubstitutes()
597 DWORD i
, rv
, lenAlias
, lenActual
, valueType
;
598 WCHAR aliasName
[MAX_VALUE_NAME
];
599 WCHAR actualName
[MAX_VALUE_DATA
];
601 if (RegOpenKeyExW(HKEY_LOCAL_MACHINE
,
602 L
"SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\FontSubstitutes",
603 0, KEY_READ
, &hKey
) != ERROR_SUCCESS
)
605 return NS_ERROR_FAILURE
;
608 for (i
= 0, rv
= ERROR_SUCCESS
; rv
!= ERROR_NO_MORE_ITEMS
; i
++) {
610 lenAlias
= ArrayLength(aliasName
);
612 lenActual
= sizeof(actualName
);
613 rv
= RegEnumValueW(hKey
, i
, aliasName
, &lenAlias
, nullptr, &valueType
,
614 (LPBYTE
)actualName
, &lenActual
);
616 if (rv
!= ERROR_SUCCESS
|| valueType
!= REG_SZ
|| lenAlias
== 0) {
620 if (aliasName
[0] == WCHAR('@')) {
624 nsAutoString
substituteName((char16_t
*) aliasName
);
625 nsAutoString
actualFontName((char16_t
*) actualName
);
626 RemoveCharsetFromFontSubstitute(substituteName
);
627 BuildKeyNameFromFontName(substituteName
);
628 RemoveCharsetFromFontSubstitute(actualFontName
);
629 BuildKeyNameFromFontName(actualFontName
);
631 if (!actualFontName
.IsEmpty() &&
632 (ff
= mFontFamilies
.GetWeak(actualFontName
))) {
633 mFontSubstitutes
.Put(substituteName
, ff
);
635 mNonExistingFonts
.AppendElement(substituteName
);
639 // "Courier" on a default Windows install is an ugly bitmap font.
640 // If there is no substitution for Courier in the registry
641 // substitute "Courier" with "Courier New".
642 nsAutoString substituteName
;
643 substituteName
.AssignLiteral("Courier");
644 BuildKeyNameFromFontName(substituteName
);
645 if (!mFontSubstitutes
.GetWeak(substituteName
)) {
647 nsAutoString actualFontName
;
648 actualFontName
.AssignLiteral("Courier New");
649 BuildKeyNameFromFontName(actualFontName
);
650 ff
= mFontFamilies
.GetWeak(actualFontName
);
652 mFontSubstitutes
.Put(substituteName
, ff
);
659 gfxGDIFontList::InitFontList()
661 Telemetry::AutoTimer
<Telemetry::GDI_INITFONTLIST_TOTAL
> timer
;
662 gfxFontCache
*fc
= gfxFontCache::GetCache();
664 fc
->AgeAllGenerations();
667 gfxPlatformFontList::InitFontList();
669 mFontSubstitutes
.Clear();
670 mNonExistingFonts
.Clear();
672 // iterate over available families
674 memset(&logfont
, 0, sizeof(logfont
));
675 logfont
.lfCharSet
= DEFAULT_CHARSET
;
678 int result
= EnumFontFamiliesExW(hdc
.GetDC(), &logfont
,
679 (FONTENUMPROCW
)&EnumFontFamExProc
,
682 GetFontSubstitutes();
684 GetPrefsAndStartLoader();
690 gfxGDIFontList::EnumFontFamExProc(ENUMLOGFONTEXW
*lpelfe
,
691 NEWTEXTMETRICEXW
*lpntme
,
695 const LOGFONTW
& lf
= lpelfe
->elfLogFont
;
697 if (lf
.lfFaceName
[0] == '@') {
701 nsAutoString
name(lf
.lfFaceName
);
702 BuildKeyNameFromFontName(name
);
704 gfxGDIFontList
*fontList
= PlatformFontList();
706 if (!fontList
->mFontFamilies
.GetWeak(name
)) {
707 nsDependentString
faceName(lf
.lfFaceName
);
708 nsRefPtr
<gfxFontFamily
> family
= new GDIFontFamily(faceName
);
709 fontList
->mFontFamilies
.Put(name
, family
);
711 // if locale is such that CJK font names are the default coming from
712 // GDI, then if a family name is non-ASCII immediately read in other
713 // family names. This assures that MS Gothic, MS Mincho are all found
714 // before lookups begin.
715 if (!IsASCII(faceName
)) {
716 family
->ReadOtherFamilyNames(gfxPlatformFontList::PlatformFontList());
719 if (fontList
->mBadUnderlineFamilyNames
.Contains(name
))
720 family
->SetBadUnderlineFamily();
727 gfxGDIFontList::LookupLocalFont(const gfxProxyFontEntry
*aProxyEntry
,
728 const nsAString
& aFullname
)
730 gfxFontEntry
*lookup
;
732 lookup
= LookupInFaceNameLists(aFullname
);
737 bool isCFF
= false; // jtdfix -- need to determine this
739 // use the face name from the lookup font entry, which will be the localized
740 // face name which GDI mapping tables use (e.g. with the system locale set to
741 // Dutch, a fullname of 'Arial Bold' will find a font entry with the face name
742 // 'Arial Vet' which can be used as a key in GDI font lookups).
743 GDIFontEntry
*fe
= GDIFontEntry::CreateFontEntry(lookup
->Name(),
744 gfxWindowsFontType(isCFF
? GFX_FONT_TYPE_PS_OPENTYPE
: GFX_FONT_TYPE_TRUETYPE
) /*type*/,
745 lookup
->mItalic
? NS_FONT_STYLE_ITALIC
: NS_FONT_STYLE_NORMAL
,
746 lookup
->mWeight
, aProxyEntry
->mStretch
, nullptr,
747 static_cast<GDIFontEntry
*>(lookup
)->mFamilyHasItalicFace
);
752 fe
->mIsUserFont
= true;
753 fe
->mIsLocalUserFont
= true;
755 // make the new font entry match the proxy entry style characteristics
756 fe
->mWeight
= (aProxyEntry
->mWeight
== 0 ? 400 : aProxyEntry
->mWeight
);
757 fe
->mItalic
= aProxyEntry
->mItalic
;
763 gfxGDIFontList::MakePlatformFont(const gfxProxyFontEntry
*aProxyEntry
,
764 const uint8_t *aFontData
,
767 // MakePlatformFont is responsible for deleting the font data with NS_Free
768 // so we set up a stack object to ensure it is freed even if we take an
770 struct FontDataDeleter
{
771 FontDataDeleter(const uint8_t *aFontData
)
772 : mFontData(aFontData
) { }
773 ~FontDataDeleter() { NS_Free((void*)mFontData
); }
774 const uint8_t *mFontData
;
776 FontDataDeleter
autoDelete(aFontData
);
778 bool isCFF
= gfxFontUtils::IsCffFont(aFontData
);
781 HANDLE fontRef
= nullptr;
783 nsAutoString uniqueName
;
784 rv
= gfxFontUtils::MakeUniqueUserFontName(uniqueName
);
788 FallibleTArray
<uint8_t> newFontData
;
790 rv
= gfxFontUtils::RenameFont(uniqueName
, aFontData
, aLength
, &newFontData
);
797 uint8_t *fontData
= reinterpret_cast<uint8_t*> (newFontData
.Elements());
798 uint32_t fontLength
= newFontData
.Length();
799 NS_ASSERTION(fontData
, "null font data after renaming");
801 // http://msdn.microsoft.com/en-us/library/ms533942(VS.85).aspx
802 // "A font that is added by AddFontMemResourceEx is always private
803 // to the process that made the call and is not enumerable."
804 fontRef
= AddFontMemResourceEx(fontData
, fontLength
,
805 0 /* reserved */, &numFonts
);
809 // only load fonts with a single face contained in the data
810 // AddFontMemResourceEx generates an additional face name for
811 // vertical text if the font supports vertical writing but since
812 // the font is referenced via the name this can be ignored
813 if (fontRef
&& numFonts
> 2) {
814 RemoveFontMemResourceEx(fontRef
);
818 // make a new font entry using the unique name
819 WinUserFontData
*winUserFontData
= new WinUserFontData(fontRef
);
820 uint16_t w
= (aProxyEntry
->mWeight
== 0 ? 400 : aProxyEntry
->mWeight
);
822 GDIFontEntry
*fe
= GDIFontEntry::CreateFontEntry(uniqueName
,
823 gfxWindowsFontType(isCFF
? GFX_FONT_TYPE_PS_OPENTYPE
: GFX_FONT_TYPE_TRUETYPE
) /*type*/,
824 uint32_t(aProxyEntry
->mItalic
? NS_FONT_STYLE_ITALIC
: NS_FONT_STYLE_NORMAL
),
825 w
, aProxyEntry
->mStretch
, winUserFontData
, false);
830 fe
->mIsUserFont
= true;
832 // Uniscribe doesn't place CFF fonts loaded privately
833 // via AddFontMemResourceEx on XP/Vista
834 if (isCFF
&& !IsWin7OrLater()) {
835 fe
->mForceGDI
= true;
842 gfxGDIFontList::FindFamily(const nsAString
& aFamily
, bool aUseSystemFonts
)
844 nsAutoString
keyName(aFamily
);
845 BuildKeyNameFromFontName(keyName
);
847 gfxFontFamily
*ff
= mFontSubstitutes
.GetWeak(keyName
);
852 if (mNonExistingFonts
.Contains(keyName
)) {
856 return gfxPlatformFontList::FindFamily(aFamily
);
860 gfxGDIFontList::GetDefaultFont(const gfxFontStyle
* aStyle
)
862 gfxFontFamily
*ff
= nullptr;
864 // this really shouldn't fail to find a font....
865 HGDIOBJ hGDI
= ::GetStockObject(DEFAULT_GUI_FONT
);
867 if (hGDI
&& ::GetObjectW(hGDI
, sizeof(logFont
), &logFont
)) {
868 ff
= FindFamily(nsDependentString(logFont
.lfFaceName
));
874 // ...but just in case, try another approach as well
875 NONCLIENTMETRICSW ncm
;
876 ncm
.cbSize
= sizeof(ncm
);
877 BOOL status
= ::SystemParametersInfoW(SPI_GETNONCLIENTMETRICS
,
878 sizeof(ncm
), &ncm
, 0);
880 ff
= FindFamily(nsDependentString(ncm
.lfMessageFont
.lfFaceName
));
887 gfxGDIFontList::AddSizeOfExcludingThis(MallocSizeOf aMallocSizeOf
,
888 FontListSizes
* aSizes
) const
890 gfxPlatformFontList::AddSizeOfExcludingThis(aMallocSizeOf
, aSizes
);
891 aSizes
->mFontListSize
+=
892 mFontSubstitutes
.SizeOfExcludingThis(SizeOfFamilyNameEntryExcludingThis
,
894 aSizes
->mFontListSize
+=
895 mNonExistingFonts
.SizeOfExcludingThis(aMallocSizeOf
);
896 for (uint32_t i
= 0; i
< mNonExistingFonts
.Length(); ++i
) {
897 aSizes
->mFontListSize
+=
898 mNonExistingFonts
[i
].SizeOfExcludingThisIfUnshared(aMallocSizeOf
);
903 gfxGDIFontList::AddSizeOfIncludingThis(MallocSizeOf aMallocSizeOf
,
904 FontListSizes
* aSizes
) const
906 aSizes
->mFontListSize
+= aMallocSizeOf(this);
907 AddSizeOfExcludingThis(aMallocSizeOf
, aSizes
);
910 // used to load system-wide font info on off-main thread
911 class GDIFontInfo
: public FontInfoData
{
913 GDIFontInfo(bool aLoadOtherNames
,
916 FontInfoData(aLoadOtherNames
, aLoadFaceNames
, aLoadCmaps
)
919 virtual ~GDIFontInfo() {}
921 virtual void Load() {
922 mHdc
= GetDC(nullptr);
923 SetGraphicsMode(mHdc
, GM_ADVANCED
);
924 FontInfoData::Load();
925 ReleaseDC(nullptr, mHdc
);
928 // loads font data for all members of a given family
929 virtual void LoadFontFamilyData(const nsAString
& aFamilyName
);
931 // callback for GDI EnumFontFamiliesExW call
932 static int CALLBACK
EnumerateFontsForFamily(const ENUMLOGFONTEXW
*lpelfe
,
933 const NEWTEXTMETRICEXW
*nmetrics
,
934 DWORD fontType
, LPARAM data
);
939 struct EnumerateFontsForFamilyData
{
940 EnumerateFontsForFamilyData(const nsAString
& aFamilyName
,
941 GDIFontInfo
& aFontInfo
)
942 : mFamilyName(aFamilyName
), mFontInfo(aFontInfo
)
945 nsString mFamilyName
;
946 nsTArray
<nsString
> mOtherFamilyNames
;
947 GDIFontInfo
& mFontInfo
;
948 nsString mPreviousFontName
;
951 int CALLBACK
GDIFontInfo::EnumerateFontsForFamily(
952 const ENUMLOGFONTEXW
*lpelfe
,
953 const NEWTEXTMETRICEXW
*nmetrics
,
954 DWORD fontType
, LPARAM data
)
956 EnumerateFontsForFamilyData
*famData
=
957 reinterpret_cast<EnumerateFontsForFamilyData
*>(data
);
958 HDC hdc
= famData
->mFontInfo
.mHdc
;
959 LOGFONTW logFont
= lpelfe
->elfLogFont
;
960 const NEWTEXTMETRICW
& metrics
= nmetrics
->ntmTm
;
962 AutoSelectFont
font(hdc
, &logFont
);
963 if (!font
.IsValid()) {
967 FontFaceData fontData
;
968 nsDependentString
fontName(lpelfe
->elfFullName
);
970 // callback called for each style-charset so return if style already seen
971 if (fontName
.Equals(famData
->mPreviousFontName
)) {
974 famData
->mPreviousFontName
= fontName
;
975 famData
->mFontInfo
.mLoadStats
.fonts
++;
977 // read name table info
978 bool nameDataLoaded
= false;
979 if (famData
->mFontInfo
.mLoadFaceNames
|| famData
->mFontInfo
.mLoadOtherNames
) {
981 NativeEndian::swapToBigEndian(TRUETYPE_TAG('n','a','m','e'));
983 AutoFallibleTArray
<uint8_t, 1024> nameData
;
985 nameSize
= ::GetFontData(hdc
, kNAME
, 0, nullptr, 0);
986 if (nameSize
!= GDI_ERROR
&&
988 nameData
.SetLength(nameSize
)) {
989 ::GetFontData(hdc
, kNAME
, 0, nameData
.Elements(), nameSize
);
992 if (famData
->mFontInfo
.mLoadFaceNames
) {
993 gfxFontUtils::ReadCanonicalName((const char*)(nameData
.Elements()), nameSize
,
994 gfxFontUtils::NAME_ID_FULL
,
996 gfxFontUtils::ReadCanonicalName((const char*)(nameData
.Elements()), nameSize
,
997 gfxFontUtils::NAME_ID_POSTSCRIPT
,
998 fontData
.mPostscriptName
);
999 nameDataLoaded
= true;
1000 famData
->mFontInfo
.mLoadStats
.facenames
++;
1003 // other family names
1004 if (famData
->mFontInfo
.mLoadOtherNames
) {
1005 gfxFontFamily::ReadOtherFamilyNamesForFace(famData
->mFamilyName
,
1006 (const char*)(nameData
.Elements()),
1008 famData
->mOtherFamilyNames
,
1015 bool cmapLoaded
= false;
1016 gfxWindowsFontType feType
=
1017 GDIFontEntry::DetermineFontType(metrics
, fontType
);
1018 if (famData
->mFontInfo
.mLoadCmaps
&&
1019 (feType
== GFX_FONT_TYPE_PS_OPENTYPE
||
1020 feType
== GFX_FONT_TYPE_TT_OPENTYPE
||
1021 feType
== GFX_FONT_TYPE_TRUETYPE
))
1024 NativeEndian::swapToBigEndian(TRUETYPE_TAG('c','m','a','p'));
1026 AutoFallibleTArray
<uint8_t, 1024> cmapData
;
1028 cmapSize
= ::GetFontData(hdc
, kCMAP
, 0, nullptr, 0);
1029 if (cmapSize
!= GDI_ERROR
&&
1031 cmapData
.SetLength(cmapSize
)) {
1032 ::GetFontData(hdc
, kCMAP
, 0, cmapData
.Elements(), cmapSize
);
1033 bool cmapLoaded
= false;
1034 bool unicodeFont
= false, symbolFont
= false;
1035 nsRefPtr
<gfxCharacterMap
> charmap
= new gfxCharacterMap();
1038 if (NS_SUCCEEDED(gfxFontUtils::ReadCMAP(cmapData
.Elements(),
1040 offset
, unicodeFont
,
1042 fontData
.mCharacterMap
= charmap
;
1043 fontData
.mUVSOffset
= offset
;
1044 fontData
.mSymbolFont
= symbolFont
;
1046 famData
->mFontInfo
.mLoadStats
.cmaps
++;
1051 if (cmapLoaded
|| nameDataLoaded
) {
1052 famData
->mFontInfo
.mFontFaceData
.Put(fontName
, fontData
);
1059 GDIFontInfo::LoadFontFamilyData(const nsAString
& aFamilyName
)
1061 // iterate over the family
1063 memset(&logFont
, 0, sizeof(LOGFONTW
));
1064 logFont
.lfCharSet
= DEFAULT_CHARSET
;
1065 logFont
.lfPitchAndFamily
= 0;
1066 uint32_t l
= std::min
<uint32_t>(aFamilyName
.Length(), LF_FACESIZE
- 1);
1067 memcpy(logFont
.lfFaceName
, aFamilyName
.BeginReading(), l
* sizeof(char16_t
));
1069 EnumerateFontsForFamilyData
data(aFamilyName
, *this);
1071 EnumFontFamiliesExW(mHdc
, &logFont
,
1072 (FONTENUMPROCW
)GDIFontInfo::EnumerateFontsForFamily
,
1073 (LPARAM
)(&data
), 0);
1075 // if found other names, insert them
1076 if (data
.mOtherFamilyNames
.Length() != 0) {
1077 mOtherFamilyNames
.Put(aFamilyName
, data
.mOtherFamilyNames
);
1078 mLoadStats
.othernames
+= data
.mOtherFamilyNames
.Length();
1082 already_AddRefed
<FontInfoData
>
1083 gfxGDIFontList::CreateFontInfoData()
1085 bool loadCmaps
= !UsesSystemFallback() ||
1086 gfxPlatform::GetPlatform()->UseCmapsDuringSystemFallback();
1088 nsRefPtr
<GDIFontInfo
> fi
=
1089 new GDIFontInfo(true, NeedFullnamePostscriptNames(), loadCmaps
);
1094 #ifdef MOZ_BUNDLED_FONTS
1097 gfxGDIFontList::ActivateBundledFonts()
1099 nsCOMPtr
<nsIFile
> localDir
;
1100 nsresult rv
= NS_GetSpecialDirectory(NS_GRE_DIR
, getter_AddRefs(localDir
));
1101 if (NS_FAILED(rv
)) {
1104 if (NS_FAILED(localDir
->Append(NS_LITERAL_STRING("fonts")))) {
1108 if (NS_FAILED(localDir
->IsDirectory(&isDir
)) || !isDir
) {
1112 nsCOMPtr
<nsISimpleEnumerator
> e
;
1113 rv
= localDir
->GetDirectoryEntries(getter_AddRefs(e
));
1114 if (NS_FAILED(rv
)) {
1119 while (NS_SUCCEEDED(e
->HasMoreElements(&hasMore
)) && hasMore
) {
1120 nsCOMPtr
<nsISupports
> entry
;
1121 if (NS_FAILED(e
->GetNext(getter_AddRefs(entry
)))) {
1124 nsCOMPtr
<nsIFile
> file
= do_QueryInterface(entry
);
1129 if (NS_FAILED(file
->GetNativePath(path
))) {
1132 AddFontResourceEx(path
.get(), FR_PRIVATE
, nullptr);