1 /* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 2 -*-
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"
9 #include "mozilla/Logging.h"
10 #include "mozilla/Sprintf.h"
12 #include "gfxGDIFontList.h"
13 #include "gfxWindowsPlatform.h"
14 #include "gfxUserFontSet.h"
15 #include "gfxFontUtils.h"
16 #include "gfxGDIFont.h"
18 #include "nsServiceManagerUtils.h"
20 #include "nsUnicharUtils.h"
22 #include "nsDirectoryServiceUtils.h"
23 #include "nsDirectoryServiceDefs.h"
24 #include "nsAppDirectoryServiceDefs.h"
25 #include "nsISimpleEnumerator.h"
26 #include "nsIWindowsRegKey.h"
27 #include "gfxFontConstants.h"
28 #include "GeckoProfiler.h"
30 #include "mozilla/MemoryReporting.h"
31 #include "mozilla/Telemetry.h"
35 using namespace mozilla
;
36 using namespace mozilla::gfx
;
38 #define ROUND(x) floor((x) + 0.5)
40 #define LOG_FONTLIST(args) \
41 MOZ_LOG(gfxPlatform::GetLog(eGfxLog_fontlist), LogLevel::Debug, args)
42 #define LOG_FONTLIST_ENABLED() \
43 MOZ_LOG_TEST(gfxPlatform::GetLog(eGfxLog_fontlist), LogLevel::Debug)
45 #define LOG_CMAPDATA_ENABLED() \
46 MOZ_LOG_TEST(gfxPlatform::GetLog(eGfxLog_cmapdata), LogLevel::Debug)
48 static __inline
void BuildKeyNameFromFontName(nsAString
& aName
) {
49 if (aName
.Length() >= LF_FACESIZE
) aName
.Truncate(LF_FACESIZE
- 1);
53 // Implementation of gfxPlatformFontList for Win32 GDI,
54 // using GDI font enumeration APIs to get the list of fonts
56 class WinUserFontData
: public gfxUserFontData
{
58 explicit WinUserFontData(HANDLE aFontRef
) : mFontRef(aFontRef
) {}
60 virtual ~WinUserFontData() {
61 DebugOnly
<BOOL
> success
;
62 success
= RemoveFontMemResourceEx(mFontRef
);
68 "error deleting font handle (%p) - RemoveFontMemResourceEx failed",
70 NS_ASSERTION(success
, buf
);
78 BYTE
FontTypeToOutPrecision(uint8_t fontType
) {
81 case GFX_FONT_TYPE_TT_OPENTYPE
:
82 case GFX_FONT_TYPE_TRUETYPE
:
83 ret
= OUT_TT_ONLY_PRECIS
;
85 case GFX_FONT_TYPE_PS_OPENTYPE
:
86 ret
= OUT_PS_ONLY_PRECIS
;
88 case GFX_FONT_TYPE_TYPE1
:
89 ret
= OUT_OUTLINE_PRECIS
;
91 case GFX_FONT_TYPE_RASTER
:
92 ret
= OUT_RASTER_PRECIS
;
94 case GFX_FONT_TYPE_DEVICE
:
95 ret
= OUT_DEVICE_PRECIS
;
98 ret
= OUT_DEFAULT_PRECIS
;
103 /***************************************************************
109 GDIFontEntry::GDIFontEntry(const nsACString
& aFaceName
,
110 gfxWindowsFontType aFontType
, SlantStyleRange aStyle
,
111 WeightRange aWeight
, StretchRange aStretch
,
112 gfxUserFontData
* aUserFontData
)
113 : gfxFontEntry(aFaceName
),
114 mFontType(aFontType
),
117 mUserFontData
.reset(aUserFontData
);
118 mStyleRange
= aStyle
;
119 mWeightRange
= aWeight
;
120 mStretchRange
= aStretch
;
121 if (IsType1()) mForceGDI
= true;
122 mIsDataUserFont
= aUserFontData
!= nullptr;
124 InitLogFont(aFaceName
, aFontType
);
127 gfxFontEntry
* GDIFontEntry::Clone() const {
128 MOZ_ASSERT(!IsUserFont(), "we can only clone installed fonts!");
129 return new GDIFontEntry(Name(), mFontType
, SlantStyle(), Weight(), Stretch(),
133 nsresult
GDIFontEntry::ReadCMAP(FontInfoData
* aFontInfoData
) {
134 AUTO_PROFILER_LABEL("GDIFontEntry::ReadCMAP", OTHER
);
136 // attempt this once, if errors occur leave a blank cmap
141 // skip non-SFNT fonts completely
142 if (mFontType
!= GFX_FONT_TYPE_PS_OPENTYPE
&&
143 mFontType
!= GFX_FONT_TYPE_TT_OPENTYPE
&&
144 mFontType
!= GFX_FONT_TYPE_TRUETYPE
) {
145 mCharacterMap
= new gfxCharacterMap();
146 mCharacterMap
->mBuildOnTheFly
= true;
147 return NS_ERROR_FAILURE
;
150 RefPtr
<gfxCharacterMap
> charmap
;
154 (charmap
= GetCMAPFromFontInfo(aFontInfoData
, mUVSOffset
))) {
157 uint32_t kCMAP
= TRUETYPE_TAG('c', 'm', 'a', 'p');
158 charmap
= new gfxCharacterMap();
159 AutoTArray
<uint8_t, 16384> cmap
;
160 rv
= CopyFontTable(kCMAP
, cmap
);
162 if (NS_SUCCEEDED(rv
)) {
163 rv
= gfxFontUtils::ReadCMAP(cmap
.Elements(), cmap
.Length(), *charmap
,
168 mHasCmapTable
= NS_SUCCEEDED(rv
);
170 gfxPlatformFontList
* pfl
= gfxPlatformFontList::PlatformFontList();
171 mCharacterMap
= pfl
->FindCharMap(charmap
);
173 // if error occurred, initialize to null cmap
174 mCharacterMap
= new gfxCharacterMap();
175 // For fonts where we failed to read the character map,
176 // we can take a slow path to look up glyphs character by character
177 mCharacterMap
->mBuildOnTheFly
= true;
180 LOG_FONTLIST(("(fontlist-cmap) name: %s, size: %d hash: %8.8x%s\n",
181 mName
.get(), charmap
->SizeOfIncludingThis(moz_malloc_size_of
),
182 charmap
->mHash
, mCharacterMap
== charmap
? " new" : ""));
183 if (LOG_CMAPDATA_ENABLED()) {
185 SprintfLiteral(prefix
, "(cmapdata) name: %.220s", mName
.get());
186 charmap
->Dump(prefix
, eGfxLog_cmapdata
);
192 gfxFont
* GDIFontEntry::CreateFontInstance(const gfxFontStyle
* aFontStyle
) {
193 return new gfxGDIFont(this, aFontStyle
);
196 nsresult
GDIFontEntry::CopyFontTable(uint32_t aTableTag
,
197 nsTArray
<uint8_t>& aBuffer
) {
199 return NS_ERROR_FAILURE
;
203 AutoSelectFont
font(dc
.GetDC(), &mLogFont
);
204 if (font
.IsValid()) {
205 uint32_t tableSize
= ::GetFontData(
206 dc
.GetDC(), NativeEndian::swapToBigEndian(aTableTag
), 0, nullptr, 0);
207 if (tableSize
!= GDI_ERROR
) {
208 if (aBuffer
.SetLength(tableSize
, fallible
)) {
209 ::GetFontData(dc
.GetDC(), NativeEndian::swapToBigEndian(aTableTag
), 0,
210 aBuffer
.Elements(), tableSize
);
213 return NS_ERROR_OUT_OF_MEMORY
;
216 return NS_ERROR_FAILURE
;
219 already_AddRefed
<UnscaledFontGDI
> GDIFontEntry::LookupUnscaledFont(
221 RefPtr
<UnscaledFontGDI
> unscaledFont(mUnscaledFont
);
224 GetObject(aFont
, sizeof(LOGFONT
), &lf
);
225 unscaledFont
= new UnscaledFontGDI(lf
);
226 mUnscaledFont
= unscaledFont
;
229 return unscaledFont
.forget();
232 void GDIFontEntry::FillLogFont(LOGFONTW
* aLogFont
, LONG aWeight
,
234 memcpy(aLogFont
, &mLogFont
, sizeof(LOGFONTW
));
236 aLogFont
->lfHeight
= (LONG
)-ROUND(aSize
);
238 if (aLogFont
->lfHeight
== 0) {
239 aLogFont
->lfHeight
= -1;
242 // If a non-zero weight is passed in, use this to override the original
243 // weight in the entry's logfont. This is used to control synthetic bolding
244 // for installed families with no bold face, and for downloaded fonts
245 // (but NOT for local user fonts, because it could cause a different,
246 // glyph-incompatible face to be used)
248 aLogFont
->lfWeight
= aWeight
;
251 // for non-local() user fonts, we never want to apply italics here;
252 // if the face is described as italic, we should use it as-is,
253 // and if it's not, but then the element is styled italic, we'll use
254 // a cairo transform to create fake italic (oblique)
255 if (mIsDataUserFont
) {
256 aLogFont
->lfItalic
= 0;
260 #define MISSING_GLYPH \
261 0x1F // glyph index returned for missing characters
262 // on WinXP with .fon fonts, but not Type1 (.pfb)
264 bool GDIFontEntry::TestCharacterMap(uint32_t aCh
) {
265 if (!mCharacterMap
) {
267 NS_ASSERTION(mCharacterMap
, "failed to initialize a character map");
270 if (mCharacterMap
->mBuildOnTheFly
) {
271 if (aCh
> 0xFFFF) return false;
273 // previous code was using the group style
274 gfxFontStyle fakeStyle
;
276 fakeStyle
.style
= FontSlantStyle::Italic();
278 fakeStyle
.weight
= Weight().Min();
280 RefPtr
<gfxFont
> tempFont
= FindOrMakeFont(&fakeStyle
, nullptr);
281 if (!tempFont
|| !tempFont
->Valid()) return false;
282 gfxGDIFont
* font
= static_cast<gfxGDIFont
*>(tempFont
.get());
284 HDC dc
= GetDC((HWND
) nullptr);
285 SetGraphicsMode(dc
, GM_ADVANCED
);
286 HFONT hfont
= font
->GetHFONT();
287 HFONT oldFont
= (HFONT
)SelectObject(dc
, hfont
);
289 wchar_t str
[1] = {(wchar_t)aCh
};
292 bool hasGlyph
= false;
294 // Bug 573038 - in some cases GetGlyphIndicesW returns 0xFFFF for a
295 // missing glyph or 0x1F in other cases to indicate the "invalid"
296 // glyph. Map both cases to "not found"
297 if (IsType1() || mForceGDI
) {
298 // Type1 fonts and uniscribe APIs don't get along.
299 // ScriptGetCMap will return E_HANDLE
301 GetGlyphIndicesW(dc
, str
, 1, glyph
, GGI_MARK_NONEXISTING_GLYPHS
);
302 if (ret
!= GDI_ERROR
&& glyph
[0] != 0xFFFF &&
303 (IsType1() || glyph
[0] != MISSING_GLYPH
)) {
307 // ScriptGetCMap works better than GetGlyphIndicesW
308 // for things like bitmap/vector fonts
309 SCRIPT_CACHE sc
= nullptr;
310 HRESULT rv
= ScriptGetCMap(dc
, &sc
, str
, 1, 0, glyph
);
311 if (rv
== S_OK
) hasGlyph
= true;
314 SelectObject(dc
, oldFont
);
315 ReleaseDC(nullptr, dc
);
318 mCharacterMap
->set(aCh
);
322 // font had a cmap so simply check that
323 return mCharacterMap
->test(aCh
);
329 void GDIFontEntry::InitLogFont(const nsACString
& aName
,
330 gfxWindowsFontType aFontType
) {
331 #define CLIP_TURNOFF_FONTASSOCIATION 0x40
333 mLogFont
.lfHeight
= -1;
335 // Fill in logFont structure
336 mLogFont
.lfWidth
= 0;
337 mLogFont
.lfEscapement
= 0;
338 mLogFont
.lfOrientation
= 0;
339 mLogFont
.lfUnderline
= FALSE
;
340 mLogFont
.lfStrikeOut
= FALSE
;
341 mLogFont
.lfCharSet
= DEFAULT_CHARSET
;
342 mLogFont
.lfOutPrecision
= FontTypeToOutPrecision(aFontType
);
343 mLogFont
.lfClipPrecision
= CLIP_TURNOFF_FONTASSOCIATION
;
344 mLogFont
.lfQuality
= DEFAULT_QUALITY
;
345 mLogFont
.lfPitchAndFamily
= DEFAULT_PITCH
| FF_DONTCARE
;
346 // always force lfItalic if we want it. Font selection code will
347 // do its best to give us an italic font entry, but if no face exists
348 // it may give us a regular one based on weight. Windows should
349 // do fake italic for us in that case.
350 mLogFont
.lfItalic
= !IsUpright();
351 mLogFont
.lfWeight
= Weight().Min().ToIntRounded();
353 NS_ConvertUTF8toUTF16
name(aName
);
354 int len
= std::min
<int>(name
.Length(), LF_FACESIZE
- 1);
355 memcpy(&mLogFont
.lfFaceName
, name
.BeginReading(), len
* sizeof(char16_t
));
356 mLogFont
.lfFaceName
[len
] = '\0';
359 GDIFontEntry
* GDIFontEntry::CreateFontEntry(const nsACString
& aName
,
360 gfxWindowsFontType aFontType
,
361 SlantStyleRange aStyle
,
363 StretchRange aStretch
,
364 gfxUserFontData
* aUserFontData
) {
365 // jtdfix - need to set charset, unicode ranges, pitch/family
367 GDIFontEntry
* fe
= new GDIFontEntry(aName
, aFontType
, aStyle
, aWeight
,
368 aStretch
, aUserFontData
);
373 void GDIFontEntry::AddSizeOfIncludingThis(MallocSizeOf aMallocSizeOf
,
374 FontListSizes
* aSizes
) const {
375 aSizes
->mFontListSize
+= aMallocSizeOf(this);
376 AddSizeOfExcludingThis(aMallocSizeOf
, aSizes
);
379 /***************************************************************
385 static bool ShouldIgnoreItalicStyle(const nsACString
& aName
) {
386 // Ignore italic style's "Meiryo" because "Meiryo (Bold) Italic" has
387 // non-italic style glyphs as Japanese characters. However, using it
388 // causes serious problem if web pages wants some elements to be
389 // different style from others only with font-style. For example,
390 // <em> and <i> should be rendered as italic in the default style.
391 return aName
.EqualsLiteral("Meiryo") ||
393 "\xe3\x83\xa1\xe3\x82\xa4\xe3\x83\xaa\xe3\x82\xaa");
396 int CALLBACK
GDIFontFamily::FamilyAddStylesProc(
397 const ENUMLOGFONTEXW
* lpelfe
, const NEWTEXTMETRICEXW
* nmetrics
,
398 DWORD fontType
, LPARAM data
) {
399 const NEWTEXTMETRICW
& metrics
= nmetrics
->ntmTm
;
400 LOGFONTW logFont
= lpelfe
->elfLogFont
;
401 GDIFontFamily
* ff
= reinterpret_cast<GDIFontFamily
*>(data
);
403 if (logFont
.lfItalic
&& ShouldIgnoreItalicStyle(ff
->mName
)) {
407 // Some fonts claim to support things > 900, but we don't so clamp the sizes
408 logFont
.lfWeight
= clamped(logFont
.lfWeight
, LONG(100), LONG(900));
410 gfxWindowsFontType feType
=
411 GDIFontEntry::DetermineFontType(metrics
, fontType
);
413 GDIFontEntry
* fe
= nullptr;
414 for (uint32_t i
= 0; i
< ff
->mAvailableFonts
.Length(); ++i
) {
415 fe
= static_cast<GDIFontEntry
*>(ff
->mAvailableFonts
[i
].get());
416 if (feType
> fe
->mFontType
) {
417 // if the new type is better than the old one, remove the old entries
418 ff
->mAvailableFonts
.RemoveElementAt(i
);
420 } else if (feType
< fe
->mFontType
) {
421 // otherwise if the new type is worse, skip it
426 for (uint32_t i
= 0; i
< ff
->mAvailableFonts
.Length(); ++i
) {
427 fe
= static_cast<GDIFontEntry
*>(ff
->mAvailableFonts
[i
].get());
428 // check if we already know about this face
429 if (fe
->Weight().Min() == FontWeight(int32_t(logFont
.lfWeight
)) &&
430 fe
->IsItalic() == (logFont
.lfItalic
== 0xFF)) {
431 // update the charset bit here since this could be different
432 // XXX Can we still do this now that we store mCharset
433 // on the font family rather than the font entry?
434 ff
->mCharset
.set(metrics
.tmCharSet
);
439 // We can't set the hasItalicFace flag correctly here,
440 // because we might not have seen the family's italic face(s) yet.
441 // So we'll set that flag for all members after loading all the faces.
442 auto italicStyle
= (logFont
.lfItalic
== 0xFF ? FontSlantStyle::Italic()
443 : FontSlantStyle::Normal());
444 fe
= GDIFontEntry::CreateFontEntry(
445 NS_ConvertUTF16toUTF8(lpelfe
->elfFullName
), feType
,
446 SlantStyleRange(italicStyle
),
447 WeightRange(FontWeight(int32_t(logFont
.lfWeight
))),
448 StretchRange(FontStretch::Normal()), nullptr);
451 ff
->AddFontEntry(fe
);
453 if (nmetrics
->ntmFontSig
.fsUsb
[0] != 0x00000000 &&
454 nmetrics
->ntmFontSig
.fsUsb
[1] != 0x00000000 &&
455 nmetrics
->ntmFontSig
.fsUsb
[2] != 0x00000000 &&
456 nmetrics
->ntmFontSig
.fsUsb
[3] != 0x00000000) {
457 // set the unicode ranges
459 for (uint32_t i
= 0; i
< 4; ++i
) {
460 DWORD range
= nmetrics
->ntmFontSig
.fsUsb
[i
];
461 for (uint32_t k
= 0; k
< 32; ++k
) {
462 fe
->mUnicodeRanges
.set(x
++, (range
& (1 << k
)) != 0);
467 if (LOG_FONTLIST_ENABLED()) {
469 ("(fontlist) added (%s) to family (%s)"
470 " with style: %s weight: %d stretch: normal",
471 fe
->Name().get(), ff
->Name().get(),
472 (logFont
.lfItalic
== 0xff) ? "italic" : "normal", logFont
.lfWeight
));
477 void GDIFontFamily::FindStyleVariations(FontInfoData
* aFontInfoData
) {
478 if (mHasStyles
) return;
481 HDC hdc
= GetDC(nullptr);
482 SetGraphicsMode(hdc
, GM_ADVANCED
);
485 memset(&logFont
, 0, sizeof(LOGFONTW
));
486 logFont
.lfCharSet
= DEFAULT_CHARSET
;
487 logFont
.lfPitchAndFamily
= 0;
488 NS_ConvertUTF8toUTF16
name(mName
);
489 uint32_t l
= std::min
<uint32_t>(name
.Length(), LF_FACESIZE
- 1);
490 memcpy(logFont
.lfFaceName
, name
.get(), l
* sizeof(char16_t
));
492 EnumFontFamiliesExW(hdc
, &logFont
,
493 (FONTENUMPROCW
)GDIFontFamily::FamilyAddStylesProc
,
495 if (LOG_FONTLIST_ENABLED() && mAvailableFonts
.Length() == 0) {
497 ("(fontlist) no styles available in family \"%s\"", mName
.get()));
500 ReleaseDC(nullptr, hdc
);
502 if (mIsBadUnderlineFamily
) {
503 SetBadUnderlineFonts();
507 /***************************************************************
513 gfxGDIFontList::gfxGDIFontList() : mFontSubstitutes(32) {
514 #ifdef MOZ_BUNDLED_FONTS
515 ActivateBundledFonts();
519 static void RemoveCharsetFromFontSubstitute(nsAString
& aName
) {
520 int32_t comma
= aName
.FindChar(char16_t(','));
521 if (comma
>= 0) aName
.Truncate(comma
);
524 #define MAX_VALUE_NAME 512
525 #define MAX_VALUE_DATA 512
527 nsresult
gfxGDIFontList::GetFontSubstitutes() {
529 DWORD i
, rv
, lenAlias
, lenActual
, valueType
;
530 WCHAR aliasName
[MAX_VALUE_NAME
];
531 WCHAR actualName
[MAX_VALUE_DATA
];
535 L
"SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\FontSubstitutes",
536 0, KEY_READ
, &hKey
) != ERROR_SUCCESS
) {
537 return NS_ERROR_FAILURE
;
540 for (i
= 0, rv
= ERROR_SUCCESS
; rv
!= ERROR_NO_MORE_ITEMS
; i
++) {
542 lenAlias
= ArrayLength(aliasName
);
544 lenActual
= sizeof(actualName
);
545 rv
= RegEnumValueW(hKey
, i
, aliasName
, &lenAlias
, nullptr, &valueType
,
546 (LPBYTE
)actualName
, &lenActual
);
548 if (rv
!= ERROR_SUCCESS
|| valueType
!= REG_SZ
|| lenAlias
== 0) {
552 if (aliasName
[0] == WCHAR('@')) {
556 nsAutoString
substituteName((char16_t
*)aliasName
);
557 nsAutoString
actualFontName((char16_t
*)actualName
);
558 RemoveCharsetFromFontSubstitute(substituteName
);
559 BuildKeyNameFromFontName(substituteName
);
560 RemoveCharsetFromFontSubstitute(actualFontName
);
561 BuildKeyNameFromFontName(actualFontName
);
563 NS_ConvertUTF16toUTF8
substitute(substituteName
);
564 NS_ConvertUTF16toUTF8
actual(actualFontName
);
565 if (!actual
.IsEmpty() && (ff
= mFontFamilies
.GetWeak(actual
))) {
566 mFontSubstitutes
.Put(substitute
, ff
);
568 mNonExistingFonts
.AppendElement(substitute
);
572 // "Courier" on a default Windows install is an ugly bitmap font.
573 // If there is no substitution for Courier in the registry
574 // substitute "Courier" with "Courier New".
575 nsAutoString substituteName
;
576 substituteName
.AssignLiteral("Courier");
577 BuildKeyNameFromFontName(substituteName
);
578 NS_ConvertUTF16toUTF8
substitute(substituteName
);
579 if (!mFontSubstitutes
.GetWeak(substitute
)) {
581 nsAutoString actualFontName
;
582 actualFontName
.AssignLiteral("Courier New");
583 BuildKeyNameFromFontName(actualFontName
);
584 NS_ConvertUTF16toUTF8
actual(actualFontName
);
585 ff
= mFontFamilies
.GetWeak(actual
);
587 mFontSubstitutes
.Put(substitute
, ff
);
593 nsresult
gfxGDIFontList::InitFontListForPlatform() {
594 Telemetry::AutoTimer
<Telemetry::GDI_INITFONTLIST_TOTAL
> timer
;
596 mFontSubstitutes
.Clear();
597 mNonExistingFonts
.Clear();
599 // iterate over available families
601 memset(&logfont
, 0, sizeof(logfont
));
602 logfont
.lfCharSet
= DEFAULT_CHARSET
;
605 (void)EnumFontFamiliesExW(hdc
.GetDC(), &logfont
,
606 (FONTENUMPROCW
)&EnumFontFamExProc
, 0, 0);
608 GetFontSubstitutes();
610 GetPrefsAndStartLoader();
615 int CALLBACK
gfxGDIFontList::EnumFontFamExProc(ENUMLOGFONTEXW
* lpelfe
,
616 NEWTEXTMETRICEXW
* lpntme
,
617 DWORD fontType
, LPARAM lParam
) {
618 const NEWTEXTMETRICW
& metrics
= lpntme
->ntmTm
;
619 const LOGFONTW
& lf
= lpelfe
->elfLogFont
;
621 if (lf
.lfFaceName
[0] == '@') {
625 nsAutoString
name(lf
.lfFaceName
);
626 BuildKeyNameFromFontName(name
);
628 NS_ConvertUTF16toUTF8
key(name
);
630 gfxGDIFontList
* fontList
= PlatformFontList();
632 if (!fontList
->mFontFamilies
.GetWeak(key
)) {
633 NS_ConvertUTF16toUTF8
faceName(lf
.lfFaceName
);
634 RefPtr
<GDIFontFamily
> family
= new GDIFontFamily(faceName
);
635 fontList
->mFontFamilies
.Put(key
, family
);
637 // if locale is such that CJK font names are the default coming from
638 // GDI, then if a family name is non-ASCII immediately read in other
639 // family names. This assures that MS Gothic, MS Mincho are all found
640 // before lookups begin.
641 if (!IsASCII(faceName
)) {
642 family
->ReadOtherFamilyNames(gfxPlatformFontList::PlatformFontList());
645 if (fontList
->mBadUnderlineFamilyNames
.ContainsSorted(key
)) {
646 family
->SetBadUnderlineFamily();
649 family
->mWindowsFamily
= lf
.lfPitchAndFamily
& 0xF0;
650 family
->mWindowsPitch
= lf
.lfPitchAndFamily
& 0x0F;
652 // mark the charset bit
653 family
->mCharset
.set(metrics
.tmCharSet
);
659 gfxFontEntry
* gfxGDIFontList::LookupLocalFont(const nsACString
& aFontName
,
660 WeightRange aWeightForEntry
,
661 StretchRange aStretchForEntry
,
662 SlantStyleRange aStyleForEntry
) {
663 gfxFontEntry
* lookup
;
665 lookup
= LookupInFaceNameLists(aFontName
);
670 bool isCFF
= false; // jtdfix -- need to determine this
672 // use the face name from the lookup font entry, which will be the localized
673 // face name which GDI mapping tables use (e.g. with the system locale set to
674 // Dutch, a fullname of 'Arial Bold' will find a font entry with the face name
675 // 'Arial Vet' which can be used as a key in GDI font lookups).
676 GDIFontEntry
* fe
= GDIFontEntry::CreateFontEntry(
678 gfxWindowsFontType(isCFF
? GFX_FONT_TYPE_PS_OPENTYPE
679 : GFX_FONT_TYPE_TRUETYPE
) /*type*/,
680 lookup
->SlantStyle(), lookup
->Weight(), aStretchForEntry
, nullptr);
682 if (!fe
) return nullptr;
684 fe
->mIsLocalUserFont
= true;
686 // make the new font entry match the userfont entry style characteristics
687 fe
->mWeightRange
= aWeightForEntry
;
688 fe
->mStyleRange
= aStyleForEntry
;
689 fe
->mStretchRange
= aStretchForEntry
;
694 // If aFontData contains only a MS/Symbol cmap subtable, not MS/Unicode,
695 // we modify the subtable header to mark it as Unicode instead, because
696 // otherwise GDI will refuse to load the font.
697 // NOTE that this function does not bounds-check every access to the font data.
698 // This is OK because we only use it on data that has already been validated
699 // by OTS, and therefore we will not hit out-of-bounds accesses here.
700 static bool FixupSymbolEncodedFont(uint8_t* aFontData
, uint32_t aLength
) {
702 AutoSwap_PRUint16 version
;
703 AutoSwap_PRUint16 numTables
;
705 struct CmapEncodingRecord
{
706 AutoSwap_PRUint16 platformID
;
707 AutoSwap_PRUint16 encodingID
;
708 AutoSwap_PRUint32 offset
;
710 const uint32_t kCMAP
= TRUETYPE_TAG('c', 'm', 'a', 'p');
711 const TableDirEntry
* dir
= gfxFontUtils::FindTableDirEntry(aFontData
, kCMAP
);
712 if (dir
&& uint32_t(dir
->length
) >= sizeof(CmapHeader
)) {
714 reinterpret_cast<CmapHeader
*>(aFontData
+ uint32_t(dir
->offset
));
715 CmapEncodingRecord
* encRec
=
716 reinterpret_cast<CmapEncodingRecord
*>(cmap
+ 1);
717 int32_t symbolSubtable
= -1;
718 for (uint32_t i
= 0; i
< (uint16_t)cmap
->numTables
; ++i
) {
719 if (uint16_t(encRec
[i
].platformID
) !=
720 gfxFontUtils::PLATFORM_ID_MICROSOFT
) {
721 continue; // only interested in MS platform
723 if (uint16_t(encRec
[i
].encodingID
) ==
724 gfxFontUtils::ENCODING_ID_MICROSOFT_UNICODEBMP
) {
725 // We've got a Microsoft/Unicode table, so don't interfere.
729 if (uint16_t(encRec
[i
].encodingID
) ==
730 gfxFontUtils::ENCODING_ID_MICROSOFT_SYMBOL
) {
731 // Found a symbol subtable; remember it for possible fixup,
732 // but if we subsequently find a Microsoft/Unicode subtable,
733 // we'll cancel this.
737 if (symbolSubtable
!= -1) {
738 // We found a windows/symbol cmap table, and no windows/unicode one;
739 // change the encoding ID so that AddFontMemResourceEx will accept it
740 encRec
[symbolSubtable
].encodingID
=
741 gfxFontUtils::ENCODING_ID_MICROSOFT_UNICODEBMP
;
748 gfxFontEntry
* gfxGDIFontList::MakePlatformFont(const nsACString
& aFontName
,
749 WeightRange aWeightForEntry
,
750 StretchRange aStretchForEntry
,
751 SlantStyleRange aStyleForEntry
,
752 const uint8_t* aFontData
,
754 // MakePlatformFont is responsible for deleting the font data with free
755 // so we set up a stack object to ensure it is freed even if we take an
757 struct FontDataDeleter
{
758 explicit FontDataDeleter(const uint8_t* aFontData
) : mFontData(aFontData
) {}
759 ~FontDataDeleter() { free((void*)mFontData
); }
760 const uint8_t* mFontData
;
762 FontDataDeleter
autoDelete(aFontData
);
764 bool isCFF
= gfxFontUtils::IsCffFont(aFontData
);
767 HANDLE fontRef
= nullptr;
769 nsAutoString uniqueName
;
770 rv
= gfxFontUtils::MakeUniqueUserFontName(uniqueName
);
771 if (NS_FAILED(rv
)) return nullptr;
773 FallibleTArray
<uint8_t> newFontData
;
775 rv
= gfxFontUtils::RenameFont(uniqueName
, aFontData
, aLength
, &newFontData
);
777 if (NS_FAILED(rv
)) return nullptr;
781 uint8_t* fontData
= reinterpret_cast<uint8_t*>(newFontData
.Elements());
782 uint32_t fontLength
= newFontData
.Length();
783 NS_ASSERTION(fontData
, "null font data after renaming");
785 // http://msdn.microsoft.com/en-us/library/ms533942(VS.85).aspx
786 // "A font that is added by AddFontMemResourceEx is always private
787 // to the process that made the call and is not enumerable."
789 AddFontMemResourceEx(fontData
, fontLength
, 0 /* reserved */, &numFonts
);
791 if (FixupSymbolEncodedFont(fontData
, fontLength
)) {
792 fontRef
= AddFontMemResourceEx(fontData
, fontLength
, 0, &numFonts
);
799 // only load fonts with a single face contained in the data
800 // AddFontMemResourceEx generates an additional face name for
801 // vertical text if the font supports vertical writing but since
802 // the font is referenced via the name this can be ignored
803 if (fontRef
&& numFonts
> 2) {
804 RemoveFontMemResourceEx(fontRef
);
808 // make a new font entry using the unique name
809 WinUserFontData
* winUserFontData
= new WinUserFontData(fontRef
);
810 GDIFontEntry
* fe
= GDIFontEntry::CreateFontEntry(
811 NS_ConvertUTF16toUTF8(uniqueName
),
812 gfxWindowsFontType(isCFF
? GFX_FONT_TYPE_PS_OPENTYPE
813 : GFX_FONT_TYPE_TRUETYPE
) /*type*/,
814 aStyleForEntry
, aWeightForEntry
, aStretchForEntry
, winUserFontData
);
817 fe
->mIsDataUserFont
= true;
823 bool gfxGDIFontList::FindAndAddFamilies(StyleGenericFontFamily aGeneric
,
824 const nsACString
& aFamily
,
825 nsTArray
<FamilyAndGeneric
>* aOutput
,
826 FindFamiliesFlags aFlags
,
827 gfxFontStyle
* aStyle
,
828 gfxFloat aDevToCssSize
) {
829 NS_ConvertUTF8toUTF16
key16(aFamily
);
830 BuildKeyNameFromFontName(key16
);
831 NS_ConvertUTF16toUTF8
keyName(key16
);
833 gfxFontFamily
* ff
= mFontSubstitutes
.GetWeak(keyName
);
835 aOutput
->AppendElement(FamilyAndGeneric(ff
, aGeneric
));
839 if (mNonExistingFonts
.Contains(keyName
)) {
843 return gfxPlatformFontList::FindAndAddFamilies(aGeneric
, aFamily
, aOutput
,
844 aFlags
, aStyle
, aDevToCssSize
);
847 FontFamily
gfxGDIFontList::GetDefaultFontForPlatform(
848 const gfxFontStyle
* aStyle
) {
851 // this really shouldn't fail to find a font....
852 NONCLIENTMETRICSW ncm
;
853 ncm
.cbSize
= sizeof(ncm
);
855 ::SystemParametersInfoW(SPI_GETNONCLIENTMETRICS
, sizeof(ncm
), &ncm
, 0);
857 ff
= FindFamily(NS_ConvertUTF16toUTF8(ncm
.lfMessageFont
.lfFaceName
));
863 // ...but just in case, try another (long-deprecated) approach as well
864 HGDIOBJ hGDI
= ::GetStockObject(DEFAULT_GUI_FONT
);
866 if (hGDI
&& ::GetObjectW(hGDI
, sizeof(logFont
), &logFont
)) {
867 ff
= FindFamily(NS_ConvertUTF16toUTF8(logFont
.lfFaceName
));
873 void gfxGDIFontList::AddSizeOfExcludingThis(MallocSizeOf aMallocSizeOf
,
874 FontListSizes
* aSizes
) const {
875 gfxPlatformFontList::AddSizeOfExcludingThis(aMallocSizeOf
, aSizes
);
876 aSizes
->mFontListSize
+=
877 SizeOfFontFamilyTableExcludingThis(mFontSubstitutes
, aMallocSizeOf
);
878 aSizes
->mFontListSize
+=
879 mNonExistingFonts
.ShallowSizeOfExcludingThis(aMallocSizeOf
);
880 for (uint32_t i
= 0; i
< mNonExistingFonts
.Length(); ++i
) {
881 aSizes
->mFontListSize
+=
882 mNonExistingFonts
[i
].SizeOfExcludingThisIfUnshared(aMallocSizeOf
);
886 void gfxGDIFontList::AddSizeOfIncludingThis(MallocSizeOf aMallocSizeOf
,
887 FontListSizes
* aSizes
) const {
888 aSizes
->mFontListSize
+= aMallocSizeOf(this);
889 AddSizeOfExcludingThis(aMallocSizeOf
, aSizes
);
892 // used to load system-wide font info on off-main thread
893 class GDIFontInfo
: public FontInfoData
{
895 GDIFontInfo(bool aLoadOtherNames
, bool aLoadFaceNames
, bool aLoadCmaps
)
896 : FontInfoData(aLoadOtherNames
, aLoadFaceNames
, aLoadCmaps
) {}
898 virtual ~GDIFontInfo() = default;
900 virtual void Load() {
901 mHdc
= GetDC(nullptr);
902 SetGraphicsMode(mHdc
, GM_ADVANCED
);
903 FontInfoData::Load();
904 ReleaseDC(nullptr, mHdc
);
907 // loads font data for all members of a given family
908 virtual void LoadFontFamilyData(const nsACString
& aFamilyName
);
910 // callback for GDI EnumFontFamiliesExW call
911 static int CALLBACK
EnumerateFontsForFamily(const ENUMLOGFONTEXW
* lpelfe
,
912 const NEWTEXTMETRICEXW
* nmetrics
,
913 DWORD fontType
, LPARAM data
);
918 struct EnumerateFontsForFamilyData
{
919 EnumerateFontsForFamilyData(const nsACString
& aFamilyName
,
920 GDIFontInfo
& aFontInfo
)
921 : mFamilyName(aFamilyName
), mFontInfo(aFontInfo
) {}
923 nsCString mFamilyName
;
924 nsTArray
<nsCString
> mOtherFamilyNames
;
925 GDIFontInfo
& mFontInfo
;
926 nsCString mPreviousFontName
;
929 int CALLBACK
GDIFontInfo::EnumerateFontsForFamily(
930 const ENUMLOGFONTEXW
* lpelfe
, const NEWTEXTMETRICEXW
* nmetrics
,
931 DWORD fontType
, LPARAM data
) {
932 EnumerateFontsForFamilyData
* famData
=
933 reinterpret_cast<EnumerateFontsForFamilyData
*>(data
);
934 HDC hdc
= famData
->mFontInfo
.mHdc
;
935 LOGFONTW logFont
= lpelfe
->elfLogFont
;
936 const NEWTEXTMETRICW
& metrics
= nmetrics
->ntmTm
;
938 AutoSelectFont
font(hdc
, &logFont
);
939 if (!font
.IsValid()) {
943 FontFaceData fontData
;
944 NS_ConvertUTF16toUTF8
fontName(lpelfe
->elfFullName
);
946 // callback called for each style-charset so return if style already seen
947 if (fontName
.Equals(famData
->mPreviousFontName
)) {
950 famData
->mPreviousFontName
= fontName
;
951 famData
->mFontInfo
.mLoadStats
.fonts
++;
953 // read name table info
954 bool nameDataLoaded
= false;
955 if (famData
->mFontInfo
.mLoadFaceNames
|| famData
->mFontInfo
.mLoadOtherNames
) {
957 NativeEndian::swapToBigEndian(TRUETYPE_TAG('n', 'a', 'm', 'e'));
959 AutoTArray
<uint8_t, 1024> nameData
;
961 nameSize
= ::GetFontData(hdc
, kNAME
, 0, nullptr, 0);
962 if (nameSize
!= GDI_ERROR
&& nameSize
> 0 &&
963 nameData
.SetLength(nameSize
, fallible
)) {
964 ::GetFontData(hdc
, kNAME
, 0, nameData
.Elements(), nameSize
);
967 if (famData
->mFontInfo
.mLoadFaceNames
) {
968 gfxFontUtils::ReadCanonicalName((const char*)(nameData
.Elements()),
969 nameSize
, gfxFontUtils::NAME_ID_FULL
,
971 gfxFontUtils::ReadCanonicalName(
972 (const char*)(nameData
.Elements()), nameSize
,
973 gfxFontUtils::NAME_ID_POSTSCRIPT
, fontData
.mPostscriptName
);
974 nameDataLoaded
= true;
975 famData
->mFontInfo
.mLoadStats
.facenames
++;
978 // other family names
979 if (famData
->mFontInfo
.mLoadOtherNames
) {
980 gfxFontUtils::ReadOtherFamilyNamesForFace(
981 famData
->mFamilyName
, (const char*)(nameData
.Elements()), nameSize
,
982 famData
->mOtherFamilyNames
, false);
988 bool cmapLoaded
= false;
989 gfxWindowsFontType feType
=
990 GDIFontEntry::DetermineFontType(metrics
, fontType
);
991 if (famData
->mFontInfo
.mLoadCmaps
&& (feType
== GFX_FONT_TYPE_PS_OPENTYPE
||
992 feType
== GFX_FONT_TYPE_TT_OPENTYPE
||
993 feType
== GFX_FONT_TYPE_TRUETYPE
)) {
995 NativeEndian::swapToBigEndian(TRUETYPE_TAG('c', 'm', 'a', 'p'));
997 AutoTArray
<uint8_t, 1024> cmapData
;
999 cmapSize
= ::GetFontData(hdc
, kCMAP
, 0, nullptr, 0);
1000 if (cmapSize
!= GDI_ERROR
&& cmapSize
> 0 &&
1001 cmapData
.SetLength(cmapSize
, fallible
)) {
1002 ::GetFontData(hdc
, kCMAP
, 0, cmapData
.Elements(), cmapSize
);
1003 bool cmapLoaded
= false;
1004 RefPtr
<gfxCharacterMap
> charmap
= new gfxCharacterMap();
1007 if (NS_SUCCEEDED(gfxFontUtils::ReadCMAP(cmapData
.Elements(), cmapSize
,
1008 *charmap
, offset
))) {
1009 fontData
.mCharacterMap
= charmap
;
1010 fontData
.mUVSOffset
= offset
;
1012 famData
->mFontInfo
.mLoadStats
.cmaps
++;
1017 if (cmapLoaded
|| nameDataLoaded
) {
1018 famData
->mFontInfo
.mFontFaceData
.Put(fontName
, fontData
);
1021 return famData
->mFontInfo
.mCanceled
? 0 : 1;
1024 void GDIFontInfo::LoadFontFamilyData(const nsACString
& aFamilyName
) {
1025 // iterate over the family
1027 memset(&logFont
, 0, sizeof(LOGFONTW
));
1028 logFont
.lfCharSet
= DEFAULT_CHARSET
;
1029 logFont
.lfPitchAndFamily
= 0;
1030 NS_ConvertUTF8toUTF16
name(aFamilyName
);
1031 uint32_t l
= std::min
<uint32_t>(name
.Length(), LF_FACESIZE
- 1);
1032 memcpy(logFont
.lfFaceName
, name
.BeginReading(), l
* sizeof(char16_t
));
1034 EnumerateFontsForFamilyData
data(aFamilyName
, *this);
1036 EnumFontFamiliesExW(mHdc
, &logFont
,
1037 (FONTENUMPROCW
)GDIFontInfo::EnumerateFontsForFamily
,
1038 (LPARAM
)(&data
), 0);
1040 // if found other names, insert them
1041 if (data
.mOtherFamilyNames
.Length() != 0) {
1042 mOtherFamilyNames
.Put(aFamilyName
, data
.mOtherFamilyNames
);
1043 mLoadStats
.othernames
+= data
.mOtherFamilyNames
.Length();
1047 already_AddRefed
<FontInfoData
> gfxGDIFontList::CreateFontInfoData() {
1048 bool loadCmaps
= !UsesSystemFallback() ||
1049 gfxPlatform::GetPlatform()->UseCmapsDuringSystemFallback();
1051 RefPtr
<GDIFontInfo
> fi
=
1052 new GDIFontInfo(true, NeedFullnamePostscriptNames(), loadCmaps
);
1057 gfxFontFamily
* gfxGDIFontList::CreateFontFamily(const nsACString
& aName
) const {
1058 return new GDIFontFamily(aName
);
1061 #ifdef MOZ_BUNDLED_FONTS
1063 void gfxGDIFontList::ActivateBundledFonts() {
1064 nsCOMPtr
<nsIFile
> localDir
;
1065 nsresult rv
= NS_GetSpecialDirectory(NS_GRE_DIR
, getter_AddRefs(localDir
));
1066 if (NS_FAILED(rv
)) {
1069 if (NS_FAILED(localDir
->Append(NS_LITERAL_STRING("fonts")))) {
1073 if (NS_FAILED(localDir
->IsDirectory(&isDir
)) || !isDir
) {
1077 nsCOMPtr
<nsIDirectoryEnumerator
> e
;
1078 rv
= localDir
->GetDirectoryEntries(getter_AddRefs(e
));
1079 if (NS_FAILED(rv
)) {
1083 nsCOMPtr
<nsIFile
> file
;
1084 while (NS_SUCCEEDED(e
->GetNextFile(getter_AddRefs(file
))) && file
) {
1086 if (NS_FAILED(file
->GetPath(path
))) {
1089 AddFontResourceExW(path
.get(), FR_PRIVATE
, nullptr);