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/ArrayUtils.h"
7 #include "mozilla/FontPropertyTypes.h"
8 #include "mozilla/MemoryReporting.h"
9 #include "mozilla/intl/OSPreferences.h"
11 #include "gfxDWriteFontList.h"
12 #include "gfxDWriteFonts.h"
13 #include "nsUnicharUtils.h"
14 #include "nsPresContext.h"
15 #include "nsServiceManagerUtils.h"
16 #include "nsCharSeparatedTokenizer.h"
17 #include "mozilla/gfx/Logging.h"
18 #include "mozilla/Preferences.h"
19 #include "mozilla/ProfilerLabels.h"
20 #include "mozilla/Sprintf.h"
21 #include "mozilla/StaticPrefs_gfx.h"
22 #include "mozilla/Telemetry.h"
23 #include "mozilla/WindowsProcessMitigations.h"
24 #include "mozilla/WindowsVersion.h"
25 #include "nsDirectoryServiceUtils.h"
26 #include "nsDirectoryServiceDefs.h"
27 #include "nsAppDirectoryServiceDefs.h"
29 #include "gfxGDIFontList.h"
31 #include "SharedFontList-impl.h"
33 #include "harfbuzz/hb.h"
35 #include "StandardFonts-win10.inc"
37 using namespace mozilla
;
38 using namespace mozilla::gfx
;
39 using mozilla::intl::OSPreferences
;
41 #define LOG_FONTLIST(args) \
42 MOZ_LOG(gfxPlatform::GetLog(eGfxLog_fontlist), LogLevel::Debug, args)
43 #define LOG_FONTLIST_ENABLED() \
44 MOZ_LOG_TEST(gfxPlatform::GetLog(eGfxLog_fontlist), LogLevel::Debug)
46 #define LOG_FONTINIT(args) \
47 MOZ_LOG(gfxPlatform::GetLog(eGfxLog_fontinit), LogLevel::Debug, args)
48 #define LOG_FONTINIT_ENABLED() \
49 MOZ_LOG_TEST(gfxPlatform::GetLog(eGfxLog_fontinit), LogLevel::Debug)
51 #define LOG_CMAPDATA_ENABLED() \
52 MOZ_LOG_TEST(gfxPlatform::GetLog(eGfxLog_cmapdata), LogLevel::Debug)
54 static __inline
void BuildKeyNameFromFontName(nsACString
& aName
) {
58 ////////////////////////////////////////////////////////////////////////////////
59 // gfxDWriteFontFamily
61 gfxDWriteFontFamily::~gfxDWriteFontFamily() {}
63 static bool GetNameAsUtf8(nsACString
& aName
, IDWriteLocalizedStrings
* aStrings
,
65 AutoTArray
<WCHAR
, 32> name
;
67 HRESULT hr
= aStrings
->GetStringLength(aIndex
, &length
);
71 if (!name
.SetLength(length
+ 1, fallible
)) {
74 hr
= aStrings
->GetString(aIndex
, name
.Elements(), length
+ 1);
80 Substring(reinterpret_cast<const char16_t
*>(name
.Elements()),
86 static bool GetEnglishOrFirstName(nsACString
& aName
,
87 IDWriteLocalizedStrings
* aStrings
) {
88 UINT32 englishIdx
= 0;
90 HRESULT hr
= aStrings
->FindLocaleName(L
"en-us", &englishIdx
, &exists
);
91 if (FAILED(hr
) || !exists
) {
92 // Use 0 index if english is not found.
95 return GetNameAsUtf8(aName
, aStrings
, englishIdx
);
98 static HRESULT
GetDirectWriteFontName(IDWriteFont
* aFont
,
99 nsACString
& aFontName
) {
102 RefPtr
<IDWriteLocalizedStrings
> names
;
103 hr
= aFont
->GetFaceNames(getter_AddRefs(names
));
108 if (!GetEnglishOrFirstName(aFontName
, names
)) {
115 #define FULLNAME_ID DWRITE_INFORMATIONAL_STRING_FULL_NAME
116 #define PSNAME_ID DWRITE_INFORMATIONAL_STRING_POSTSCRIPT_NAME
118 // for use in reading postscript or fullname
119 static HRESULT
GetDirectWriteFaceName(IDWriteFont
* aFont
,
120 DWRITE_INFORMATIONAL_STRING_ID aWhichName
,
121 nsACString
& aFontName
) {
125 RefPtr
<IDWriteLocalizedStrings
> infostrings
;
126 hr
= aFont
->GetInformationalStrings(aWhichName
, getter_AddRefs(infostrings
),
128 if (FAILED(hr
) || !exists
) {
132 if (!GetEnglishOrFirstName(aFontName
, infostrings
)) {
139 void gfxDWriteFontFamily::FindStyleVariationsLocked(
140 FontInfoData
* aFontInfoData
) {
148 gfxPlatformFontList
* fp
= gfxPlatformFontList::PlatformFontList();
151 mFaceNamesInitialized
|| !fp
->NeedFullnamePostscriptNames();
152 bool fontInfoShouldHaveFaceNames
= !mFaceNamesInitialized
&&
153 fp
->NeedFullnamePostscriptNames() &&
156 for (UINT32 i
= 0; i
< mDWFamily
->GetFontCount(); i
++) {
157 RefPtr
<IDWriteFont
> font
;
158 hr
= mDWFamily
->GetFont(i
, getter_AddRefs(font
));
160 // This should never happen.
161 NS_WARNING("Failed to get existing font from family.");
165 if (font
->GetSimulations() != DWRITE_FONT_SIMULATIONS_NONE
) {
166 // We don't want these in the font list; we'll apply simulations
167 // on the fly when appropriate.
172 nsCString
fullID(mName
);
173 nsAutoCString faceName
;
174 hr
= GetDirectWriteFontName(font
, faceName
);
179 fullID
.Append(faceName
);
181 // Ignore italic style's "Meiryo" because "Meiryo (Bold) Italic" has
182 // non-italic style glyphs as Japanese characters. However, using it
183 // causes serious problem if web pages wants some elements to be
184 // different style from others only with font-style. For example,
185 // <em> and <i> should be rendered as italic in the default style.
186 if (fullID
.EqualsLiteral("Meiryo Italic") ||
187 fullID
.EqualsLiteral("Meiryo Bold Italic")) {
191 gfxDWriteFontEntry
* fe
=
192 new gfxDWriteFontEntry(fullID
, font
, mIsSystemFontFamily
);
193 fe
->SetForceGDIClassic(mForceGDIClassic
);
195 fe
->SetupVariationRanges();
197 AddFontEntryLocked(fe
);
199 // postscript/fullname if needed
200 nsAutoCString psname
, fullname
;
201 if (fontInfoShouldHaveFaceNames
) {
202 aFontInfoData
->GetFaceNames(fe
->Name(), fullname
, psname
);
203 if (!fullname
.IsEmpty()) {
204 fp
->AddFullname(fe
, fullname
);
206 if (!psname
.IsEmpty()) {
207 fp
->AddPostscriptName(fe
, psname
);
209 } else if (!skipFaceNames
) {
210 hr
= GetDirectWriteFaceName(font
, PSNAME_ID
, psname
);
212 skipFaceNames
= true;
213 } else if (psname
.Length() > 0) {
214 fp
->AddPostscriptName(fe
, psname
);
217 hr
= GetDirectWriteFaceName(font
, FULLNAME_ID
, fullname
);
219 skipFaceNames
= true;
220 } else if (fullname
.Length() > 0) {
221 fp
->AddFullname(fe
, fullname
);
225 if (LOG_FONTLIST_ENABLED()) {
226 nsAutoCString weightString
;
227 fe
->Weight().ToString(weightString
);
229 ("(fontlist) added (%s) to family (%s)"
230 " with style: %s weight: %s stretch: %d psname: %s fullname: %s",
231 fe
->Name().get(), Name().get(),
232 (fe
->IsItalic()) ? "italic"
233 : (fe
->IsOblique() ? "oblique" : "normal"),
234 weightString
.get(), fe
->Stretch().AsScalar(), psname
.get(),
239 // assume that if no error, all postscript/fullnames were initialized
240 if (!skipFaceNames
) {
241 mFaceNamesInitialized
= true;
244 if (!mAvailableFonts
.Length()) {
245 NS_WARNING("Family with no font faces in it.");
248 if (mIsBadUnderlineFamily
) {
249 SetBadUnderlineFonts();
252 CheckForSimpleFamily();
253 if (mIsSimpleFamily
) {
254 for (auto& f
: mAvailableFonts
) {
256 static_cast<gfxDWriteFontEntry
*>(f
.get())->mMayUseGDIAccess
= true;
262 void gfxDWriteFontFamily::ReadFaceNames(gfxPlatformFontList
* aPlatformFontList
,
263 bool aNeedFullnamePostscriptNames
,
264 FontInfoData
* aFontInfoData
) {
265 // if all needed names have already been read, skip
266 if (mOtherFamilyNamesInitialized
&&
267 (mFaceNamesInitialized
|| !aNeedFullnamePostscriptNames
)) {
271 // If we've been passed a FontInfoData, we skip the DWrite implementation
272 // here and fall back to the generic code which will use that info.
273 if (!aFontInfoData
) {
274 // DirectWrite version of this will try to read
275 // postscript/fullnames via DirectWrite API
276 FindStyleVariations();
279 // fallback to looking up via name table
280 if (!mOtherFamilyNamesInitialized
|| !mFaceNamesInitialized
) {
281 gfxFontFamily::ReadFaceNames(aPlatformFontList
,
282 aNeedFullnamePostscriptNames
, aFontInfoData
);
286 void gfxDWriteFontFamily::LocalizedName(nsACString
& aLocalizedName
) {
287 aLocalizedName
= Name(); // just return canonical name in case of failure
294 nsAutoCString locale
;
295 // We use system locale here because it's what user expects to see.
296 // See bug 1349454 for details.
297 RefPtr
<OSPreferences
> osprefs
= OSPreferences::GetInstanceAddRefed();
301 osprefs
->GetSystemLocale(locale
);
303 RefPtr
<IDWriteLocalizedStrings
> names
;
305 hr
= mDWFamily
->GetFamilyNames(getter_AddRefs(names
));
312 names
->FindLocaleName(NS_ConvertUTF8toUTF16(locale
).get(), &idx
, &exists
);
317 // Use english is localized is not found.
318 hr
= names
->FindLocaleName(L
"en-us", &idx
, &exists
);
323 // Use 0 index if english is not found.
327 AutoTArray
<WCHAR
, 32> famName
;
330 hr
= names
->GetStringLength(idx
, &length
);
335 if (!famName
.SetLength(length
+ 1, fallible
)) {
336 // Eeep - running out of memory. Unlikely to end well.
340 hr
= names
->GetString(idx
, famName
.Elements(), length
+ 1);
345 aLocalizedName
= NS_ConvertUTF16toUTF8((const char16_t
*)famName
.Elements(),
346 famName
.Length() - 1);
349 bool gfxDWriteFontFamily::IsSymbolFontFamily() const {
350 // Just check the first font in the family
351 if (mDWFamily
->GetFontCount() > 0) {
352 RefPtr
<IDWriteFont
> font
;
353 if (SUCCEEDED(mDWFamily
->GetFont(0, getter_AddRefs(font
)))) {
354 return font
->IsSymbolFont();
360 void gfxDWriteFontFamily::AddSizeOfExcludingThis(MallocSizeOf aMallocSizeOf
,
361 FontListSizes
* aSizes
) const {
362 gfxFontFamily::AddSizeOfExcludingThis(aMallocSizeOf
, aSizes
);
364 // This doesn't currently account for |mDWFamily|
367 void gfxDWriteFontFamily::AddSizeOfIncludingThis(MallocSizeOf aMallocSizeOf
,
368 FontListSizes
* aSizes
) const {
369 aSizes
->mFontListSize
+= aMallocSizeOf(this);
370 AddSizeOfExcludingThis(aMallocSizeOf
, aSizes
);
373 ////////////////////////////////////////////////////////////////////////////////
374 // gfxDWriteFontEntry
376 gfxFontEntry
* gfxDWriteFontEntry::Clone() const {
377 MOZ_ASSERT(!IsUserFont(), "we can only clone installed fonts!");
378 gfxDWriteFontEntry
* fe
= new gfxDWriteFontEntry(Name(), mFont
);
379 fe
->mWeightRange
= mWeightRange
;
380 fe
->mStretchRange
= mStretchRange
;
381 fe
->mStyleRange
= mStyleRange
;
385 gfxDWriteFontEntry::~gfxDWriteFontEntry() {}
387 static bool UsingArabicOrHebrewScriptSystemLocale() {
388 LANGID langid
= PRIMARYLANGID(::GetSystemDefaultLangID());
404 nsresult
gfxDWriteFontEntry::CopyFontTable(uint32_t aTableTag
,
405 nsTArray
<uint8_t>& aBuffer
) {
406 gfxDWriteFontList
* pFontList
= gfxDWriteFontList::PlatformFontList();
407 const uint32_t tagBE
= NativeEndian::swapToBigEndian(aTableTag
);
409 // Don't use GDI table loading for symbol fonts or for
410 // italic fonts in Arabic-script system locales because of
411 // potential cmap discrepancies, see bug 629386.
412 // Ditto for Hebrew, bug 837498.
413 if (mFont
&& mMayUseGDIAccess
&& pFontList
->UseGDIFontTableAccess() &&
414 !(!IsUpright() && UsingArabicOrHebrewScriptSystemLocale()) &&
415 !mFont
->IsSymbolFont()) {
416 LOGFONTW logfont
= {0};
417 if (InitLogFont(mFont
, &logfont
)) {
419 AutoSelectFont
font(dc
.GetDC(), &logfont
);
420 if (font
.IsValid()) {
421 uint32_t tableSize
= ::GetFontData(dc
.GetDC(), tagBE
, 0, nullptr, 0);
422 if (tableSize
!= GDI_ERROR
) {
423 if (aBuffer
.SetLength(tableSize
, fallible
)) {
424 ::GetFontData(dc
.GetDC(), tagBE
, 0, aBuffer
.Elements(),
428 return NS_ERROR_OUT_OF_MEMORY
;
434 RefPtr
<IDWriteFontFace
> fontFace
;
435 nsresult rv
= CreateFontFace(getter_AddRefs(fontFace
));
442 void* tableContext
= nullptr;
444 HRESULT hr
= fontFace
->TryGetFontTable(tagBE
, (const void**)&tableData
, &len
,
445 &tableContext
, &exists
);
446 if (FAILED(hr
) || !exists
) {
447 return NS_ERROR_FAILURE
;
450 if (aBuffer
.SetLength(len
, fallible
)) {
451 memcpy(aBuffer
.Elements(), tableData
, len
);
454 rv
= NS_ERROR_OUT_OF_MEMORY
;
458 fontFace
->ReleaseFontTable(&tableContext
);
464 // Access to font tables packaged in hb_blob_t form
466 // object attached to the Harfbuzz blob, used to release
467 // the table when the blob is destroyed
470 FontTableRec(IDWriteFontFace
* aFontFace
, void* aContext
)
471 : mFontFace(aFontFace
), mContext(aContext
) {
472 MOZ_COUNT_CTOR(FontTableRec
);
476 MOZ_COUNT_DTOR(FontTableRec
);
477 mFontFace
->ReleaseFontTable(mContext
);
481 RefPtr
<IDWriteFontFace
> mFontFace
;
485 static void DestroyBlobFunc(void* aUserData
) {
486 FontTableRec
* ftr
= static_cast<FontTableRec
*>(aUserData
);
490 hb_blob_t
* gfxDWriteFontEntry::GetFontTable(uint32_t aTag
) {
491 // try to avoid potentially expensive DWrite call if we haven't actually
492 // created the font face yet, by using the gfxFontEntry method that will
493 // use CopyFontTable and then cache the data
495 return gfxFontEntry::GetFontTable(aTag
);
502 HRESULT hr
= mFontFace
->TryGetFontTable(NativeEndian::swapToBigEndian(aTag
),
503 &data
, &size
, &context
, &exists
);
504 if (SUCCEEDED(hr
) && exists
) {
505 FontTableRec
* ftr
= new FontTableRec(mFontFace
, context
);
506 return hb_blob_create(static_cast<const char*>(data
), size
,
507 HB_MEMORY_MODE_READONLY
, ftr
, DestroyBlobFunc
);
513 nsresult
gfxDWriteFontEntry::ReadCMAP(FontInfoData
* aFontInfoData
) {
514 AUTO_PROFILER_LABEL("gfxDWriteFontEntry::ReadCMAP", GRAPHICS
);
516 // attempt this once, if errors occur leave a blank cmap
517 if (mCharacterMap
|| mShmemCharacterMap
) {
521 RefPtr
<gfxCharacterMap
> charmap
;
524 uint32_t uvsOffset
= 0;
526 (charmap
= GetCMAPFromFontInfo(aFontInfoData
, uvsOffset
))) {
529 uint32_t kCMAP
= TRUETYPE_TAG('c', 'm', 'a', 'p');
530 charmap
= new gfxCharacterMap();
531 AutoTable
cmapTable(this, kCMAP
);
535 const uint8_t* cmapData
= reinterpret_cast<const uint8_t*>(
536 hb_blob_get_data(cmapTable
, &cmapLen
));
537 rv
= gfxFontUtils::ReadCMAP(cmapData
, cmapLen
, *charmap
, uvsOffset
);
539 rv
= NS_ERROR_NOT_AVAILABLE
;
542 mUVSOffset
.exchange(uvsOffset
);
544 bool setCharMap
= true;
545 if (NS_SUCCEEDED(rv
)) {
546 // Bug 969504: exclude U+25B6 from Segoe UI family, because it's used
547 // by sites to represent a "Play" icon, but the glyph in Segoe UI Light
548 // and Semibold on Windows 7 is too thin. (Ditto for leftward U+25C0.)
549 // Fallback to Segoe UI Symbol is preferred.
550 if (FamilyName().EqualsLiteral("Segoe UI")) {
551 charmap
->clear(0x25b6);
552 charmap
->clear(0x25c0);
554 gfxPlatformFontList
* pfl
= gfxPlatformFontList::PlatformFontList();
555 fontlist::FontList
* sharedFontList
= pfl
->SharedFontList();
556 if (!IsUserFont() && mShmemFace
) {
557 mShmemFace
->SetCharacterMap(sharedFontList
, charmap
, mShmemFamily
);
558 if (TrySetShmemCharacterMap()) {
562 charmap
= pfl
->FindCharMap(charmap
);
564 mHasCmapTable
= true;
566 // if error occurred, initialize to null cmap
567 charmap
= new gfxCharacterMap();
568 mHasCmapTable
= false;
571 // Temporarily retain charmap, until the shared version is
573 if (mCharacterMap
.compareExchange(nullptr, charmap
.get())) {
574 charmap
.get()->AddRef();
578 LOG_FONTLIST(("(fontlist-cmap) name: %s, size: %zu hash: %8.8x%s\n",
579 mName
.get(), charmap
->SizeOfIncludingThis(moz_malloc_size_of
),
580 charmap
->mHash
, mCharacterMap
== charmap
? " new" : ""));
581 if (LOG_CMAPDATA_ENABLED()) {
583 SprintfLiteral(prefix
, "(cmapdata) name: %.220s", mName
.get());
584 charmap
->Dump(prefix
, eGfxLog_cmapdata
);
590 bool gfxDWriteFontEntry::HasVariations() {
591 if (mHasVariationsInitialized
) {
592 return mHasVariations
;
594 mHasVariationsInitialized
= true;
595 mHasVariations
= false;
597 if (!gfxPlatform::HasVariationFontSupport()) {
598 return mHasVariations
;
602 // CreateFontFace will initialize the mFontFace field, and also
603 // mFontFace5 if available on the current DWrite version.
604 RefPtr
<IDWriteFontFace
> fontFace
;
605 if (NS_FAILED(CreateFontFace(getter_AddRefs(fontFace
)))) {
606 return mHasVariations
;
610 mHasVariations
= mFontFace5
->HasVariations();
612 return mHasVariations
;
615 void gfxDWriteFontEntry::GetVariationAxes(
616 nsTArray
<gfxFontVariationAxis
>& aAxes
) {
617 if (!HasVariations()) {
620 // HasVariations() will have ensured the mFontFace5 interface is available;
621 // so we can get an IDWriteFontResource and ask it for the axis info.
622 RefPtr
<IDWriteFontResource
> resource
;
623 HRESULT hr
= mFontFace5
->GetFontResource(getter_AddRefs(resource
));
624 if (FAILED(hr
) || !resource
) {
628 uint32_t count
= resource
->GetFontAxisCount();
629 AutoTArray
<DWRITE_FONT_AXIS_VALUE
, 4> defaultValues
;
630 AutoTArray
<DWRITE_FONT_AXIS_RANGE
, 4> ranges
;
631 defaultValues
.SetLength(count
);
632 ranges
.SetLength(count
);
633 resource
->GetDefaultFontAxisValues(defaultValues
.Elements(), count
);
634 resource
->GetFontAxisRanges(ranges
.Elements(), count
);
635 for (uint32_t i
= 0; i
< count
; ++i
) {
636 gfxFontVariationAxis axis
;
637 MOZ_ASSERT(ranges
[i
].axisTag
== defaultValues
[i
].axisTag
);
638 DWRITE_FONT_AXIS_ATTRIBUTES attrs
= resource
->GetFontAxisAttributes(i
);
639 if (attrs
& DWRITE_FONT_AXIS_ATTRIBUTES_HIDDEN
) {
642 if (!(attrs
& DWRITE_FONT_AXIS_ATTRIBUTES_VARIABLE
)) {
645 // Extract the 4 chars of the tag from DWrite's packed version,
646 // and reassemble them in the order we use for TRUETYPE_TAG.
647 uint32_t t
= defaultValues
[i
].axisTag
;
648 axis
.mTag
= TRUETYPE_TAG(t
& 0xff, (t
>> 8) & 0xff, (t
>> 16) & 0xff,
650 // Try to get a human-friendly name (may not be present)
651 RefPtr
<IDWriteLocalizedStrings
> names
;
652 resource
->GetAxisNames(i
, getter_AddRefs(names
));
654 GetEnglishOrFirstName(axis
.mName
, names
);
656 axis
.mMinValue
= ranges
[i
].minValue
;
657 axis
.mMaxValue
= ranges
[i
].maxValue
;
658 axis
.mDefaultValue
= defaultValues
[i
].value
;
659 aAxes
.AppendElement(axis
);
663 void gfxDWriteFontEntry::GetVariationInstances(
664 nsTArray
<gfxFontVariationInstance
>& aInstances
) {
665 gfxFontUtils::GetVariationData(this, nullptr, &aInstances
);
668 gfxFont
* gfxDWriteFontEntry::CreateFontInstance(
669 const gfxFontStyle
* aFontStyle
) {
670 // We use the DirectWrite bold simulation for installed fonts, but NOT for
671 // webfonts; those will use multi-strike synthetic bold instead.
672 bool useBoldSim
= false;
673 if (aFontStyle
->NeedsSyntheticBold(this)) {
674 switch (StaticPrefs::gfx_font_rendering_directwrite_bold_simulation()) {
675 case 0: // never use the DWrite simulation
677 case 1: // use DWrite simulation for installed fonts except COLR fonts,
680 !mIsDataUserFont
&& !HasFontTable(TRUETYPE_TAG('C', 'O', 'L', 'R'));
682 default: // always use DWrite bold simulation, except for COLR fonts
683 useBoldSim
= !HasFontTable(TRUETYPE_TAG('C', 'O', 'L', 'R'));
687 DWRITE_FONT_SIMULATIONS sims
=
688 useBoldSim
? DWRITE_FONT_SIMULATIONS_BOLD
: DWRITE_FONT_SIMULATIONS_NONE
;
689 ThreadSafeWeakPtr
<UnscaledFontDWrite
>& unscaledFontPtr
=
690 useBoldSim
? mUnscaledFontBold
: mUnscaledFont
;
691 RefPtr
<UnscaledFontDWrite
> unscaledFont(unscaledFontPtr
);
693 RefPtr
<IDWriteFontFace
> fontFace
;
695 CreateFontFace(getter_AddRefs(fontFace
), nullptr, sims
, nullptr);
699 // Only pass in the underlying IDWriteFont if the unscaled font doesn't
700 // reflect a data font. This signals whether or not we can safely query
701 // a descriptor to represent the font for various transport use-cases.
703 new UnscaledFontDWrite(fontFace
, !mIsDataUserFont
? mFont
: nullptr);
704 unscaledFontPtr
= unscaledFont
;
706 RefPtr
<IDWriteFontFace
> fontFace
;
707 if (HasVariations()) {
708 // Get the variation settings needed to instantiate the fontEntry
709 // for a particular fontStyle.
710 AutoTArray
<gfxFontVariation
, 4> vars
;
711 GetVariationsForStyle(vars
, *aFontStyle
);
713 if (!vars
.IsEmpty()) {
715 CreateFontFace(getter_AddRefs(fontFace
), aFontStyle
, sims
, &vars
);
721 return new gfxDWriteFont(unscaledFont
, this, aFontStyle
, fontFace
);
724 nsresult
gfxDWriteFontEntry::CreateFontFace(
725 IDWriteFontFace
** aFontFace
, const gfxFontStyle
* aFontStyle
,
726 DWRITE_FONT_SIMULATIONS aSimulations
,
727 const nsTArray
<gfxFontVariation
>* aVariations
) {
728 // Convert an OpenType font tag from our uint32_t representation
729 // (as constructed by TRUETYPE_TAG(...)) to the order DWrite wants.
730 auto makeDWriteAxisTag
= [](uint32_t aTag
) {
731 return DWRITE_MAKE_FONT_AXIS_TAG((aTag
>> 24) & 0xff, (aTag
>> 16) & 0xff,
732 (aTag
>> 8) & 0xff, aTag
& 0xff);
736 // initialize mFontFace if this hasn't been done before
740 hr
= mFont
->CreateFontFace(getter_AddRefs(mFontFace
));
741 } else if (mFontFile
) {
742 IDWriteFontFile
* fontFile
= mFontFile
.get();
743 hr
= Factory::GetDWriteFactory()->CreateFontFace(
744 mFaceType
, 1, &fontFile
, 0, DWRITE_FONT_SIMULATIONS_NONE
,
745 getter_AddRefs(mFontFace
));
747 MOZ_ASSERT_UNREACHABLE("invalid font entry");
748 return NS_ERROR_FAILURE
;
751 return NS_ERROR_FAILURE
;
753 // Also get the IDWriteFontFace5 interface if we're running on a
754 // sufficiently new DWrite version where it is available.
756 mFontFace
->QueryInterface(__uuidof(IDWriteFontFace5
),
757 (void**)getter_AddRefs(mFontFace5
));
758 if (!mVariationSettings
.IsEmpty()) {
759 // If the font entry has variations specified, mFontFace5 will
760 // be a distinct face that has the variations applied.
761 RefPtr
<IDWriteFontResource
> resource
;
762 HRESULT hr
= mFontFace5
->GetFontResource(getter_AddRefs(resource
));
763 if (SUCCEEDED(hr
) && resource
) {
764 AutoTArray
<DWRITE_FONT_AXIS_VALUE
, 4> fontAxisValues
;
765 for (const auto& v
: mVariationSettings
) {
766 DWRITE_FONT_AXIS_VALUE axisValue
= {makeDWriteAxisTag(v
.mTag
),
768 fontAxisValues
.AppendElement(axisValue
);
770 resource
->CreateFontFace(
771 mFontFace
->GetSimulations(), fontAxisValues
.Elements(),
772 fontAxisValues
.Length(), getter_AddRefs(mFontFace5
));
778 // Do we need to modify DWrite simulations from what mFontFace has?
779 bool needSimulations
=
780 (aSimulations
& DWRITE_FONT_SIMULATIONS_BOLD
) &&
781 !(mFontFace
->GetSimulations() & DWRITE_FONT_SIMULATIONS_BOLD
);
783 // If the IDWriteFontFace5 interface is available, we can try using
784 // IDWriteFontResource to create a new modified face.
785 if (mFontFace5
&& (HasVariations() || needSimulations
)) {
786 RefPtr
<IDWriteFontResource
> resource
;
787 HRESULT hr
= mFontFace5
->GetFontResource(getter_AddRefs(resource
));
788 if (SUCCEEDED(hr
) && resource
) {
789 AutoTArray
<DWRITE_FONT_AXIS_VALUE
, 4> fontAxisValues
;
791 // Copy variation settings to DWrite's type.
793 for (const auto& v
: *aVariations
) {
794 DWRITE_FONT_AXIS_VALUE axisValue
= {makeDWriteAxisTag(v
.mTag
),
796 fontAxisValues
.AppendElement(axisValue
);
800 IDWriteFontFace5
* ff5
;
801 resource
->CreateFontFace(aSimulations
, fontAxisValues
.Elements(),
802 fontAxisValues
.Length(), &ff5
);
810 // Do we need to add DWrite simulations to the face?
811 if (needSimulations
) {
812 // if so, we need to return not mFontFace itself but a version that
813 // has the Bold simulation - unfortunately, old DWrite doesn't provide
814 // a simple API for this
815 UINT32 numberOfFiles
= 0;
816 if (FAILED(mFontFace
->GetFiles(&numberOfFiles
, nullptr))) {
817 return NS_ERROR_FAILURE
;
819 AutoTArray
<IDWriteFontFile
*, 1> files
;
820 files
.AppendElements(numberOfFiles
);
821 if (FAILED(mFontFace
->GetFiles(&numberOfFiles
, files
.Elements()))) {
822 return NS_ERROR_FAILURE
;
824 HRESULT hr
= Factory::GetDWriteFactory()->CreateFontFace(
825 mFontFace
->GetType(), numberOfFiles
, files
.Elements(),
826 mFontFace
->GetIndex(), aSimulations
, aFontFace
);
827 for (UINT32 i
= 0; i
< numberOfFiles
; ++i
) {
830 return FAILED(hr
) ? NS_ERROR_FAILURE
: NS_OK
;
833 MOZ_SEH_EXCEPT(EXCEPTION_EXECUTE_HANDLER
) {
834 gfxCriticalNote
<< "Exception occurred creating font face for "
838 // no simulation: we can just add a reference to mFontFace5 (if present)
839 // or mFontFace (otherwise) and return that
841 *aFontFace
= mFontFace5
;
843 *aFontFace
= mFontFace
;
845 (*aFontFace
)->AddRef();
849 bool gfxDWriteFontEntry::InitLogFont(IDWriteFont
* aFont
, LOGFONTW
* aLogFont
) {
852 BOOL isInSystemCollection
;
853 IDWriteGdiInterop
* gdi
=
854 gfxDWriteFontList::PlatformFontList()->GetGDIInterop();
855 hr
= gdi
->ConvertFontToLOGFONT(aFont
, aLogFont
, &isInSystemCollection
);
856 // If the font is not in the system collection, GDI will be unable to
857 // select it and load its tables, so we return false here to indicate
858 // failure, and let CopyFontTable fall back to DWrite native methods.
859 return (SUCCEEDED(hr
) && isInSystemCollection
);
862 bool gfxDWriteFontEntry::IsCJKFont() {
863 if (mIsCJK
!= UNINITIALIZED_VALUE
) {
869 const uint32_t kOS2Tag
= TRUETYPE_TAG('O', 'S', '/', '2');
870 gfxFontUtils::AutoHBBlob
blob(GetFontTable(kOS2Tag
));
876 const OS2Table
* os2
=
877 reinterpret_cast<const OS2Table
*>(hb_blob_get_data(blob
, &len
));
878 // ulCodePageRange bit definitions for the CJK codepages,
879 // from http://www.microsoft.com/typography/otspec/os2.htm#cpr
880 const uint32_t CJK_CODEPAGE_BITS
=
881 (1 << 17) | // codepage 932 - JIS/Japan
882 (1 << 18) | // codepage 936 - Chinese (simplified)
883 (1 << 19) | // codepage 949 - Korean Wansung
884 (1 << 20) | // codepage 950 - Chinese (traditional)
885 (1 << 21); // codepage 1361 - Korean Johab
886 if (len
>= offsetof(OS2Table
, sxHeight
)) {
887 if ((uint32_t(os2
->codePageRange1
) & CJK_CODEPAGE_BITS
) != 0) {
895 void gfxDWriteFontEntry::AddSizeOfExcludingThis(MallocSizeOf aMallocSizeOf
,
896 FontListSizes
* aSizes
) const {
897 gfxFontEntry::AddSizeOfExcludingThis(aMallocSizeOf
, aSizes
);
899 // This doesn't currently account for the |mFont| and |mFontFile| members
902 void gfxDWriteFontEntry::AddSizeOfIncludingThis(MallocSizeOf aMallocSizeOf
,
903 FontListSizes
* aSizes
) const {
904 aSizes
->mFontListSize
+= aMallocSizeOf(this);
905 AddSizeOfExcludingThis(aMallocSizeOf
, aSizes
);
908 ////////////////////////////////////////////////////////////////////////////////
911 gfxDWriteFontList::gfxDWriteFontList() : mForceGDIClassicMaxFontSize(0.0) {
912 CheckFamilyList(kBaseFonts
);
913 CheckFamilyList(kLangPackFonts
);
916 // bug 602792 - CJK systems default to large CJK fonts which cause excessive
917 // I/O strain during cold startup due to dwrite caching bugs. Default to
918 // Arial to avoid this.
920 FontFamily
gfxDWriteFontList::GetDefaultFontForPlatform(
921 nsPresContext
* aPresContext
, const gfxFontStyle
* aStyle
,
925 ff
= FindFamily(aPresContext
, "Arial"_ns
);
930 // otherwise, use local default
931 NONCLIENTMETRICSW ncm
;
932 ncm
.cbSize
= sizeof(ncm
);
934 ::SystemParametersInfoW(SPI_GETNONCLIENTMETRICS
, sizeof(ncm
), &ncm
, 0);
937 ff
= FindFamily(aPresContext
,
938 NS_ConvertUTF16toUTF8(ncm
.lfMessageFont
.lfFaceName
));
944 gfxFontEntry
* gfxDWriteFontList::LookupLocalFont(
945 nsPresContext
* aPresContext
, const nsACString
& aFontName
,
946 WeightRange aWeightForEntry
, StretchRange aStretchForEntry
,
947 SlantStyleRange aStyleForEntry
) {
948 AutoLock
lock(mLock
);
950 if (SharedFontList()) {
951 return LookupInSharedFaceNameList(aPresContext
, aFontName
, aWeightForEntry
,
952 aStretchForEntry
, aStyleForEntry
);
955 gfxFontEntry
* lookup
;
957 lookup
= LookupInFaceNameLists(aFontName
);
962 gfxDWriteFontEntry
* dwriteLookup
= static_cast<gfxDWriteFontEntry
*>(lookup
);
963 gfxDWriteFontEntry
* fe
=
964 new gfxDWriteFontEntry(lookup
->Name(), dwriteLookup
->mFont
,
965 aWeightForEntry
, aStretchForEntry
, aStyleForEntry
);
966 fe
->SetForceGDIClassic(dwriteLookup
->GetForceGDIClassic());
970 gfxFontEntry
* gfxDWriteFontList::MakePlatformFont(
971 const nsACString
& aFontName
, WeightRange aWeightForEntry
,
972 StretchRange aStretchForEntry
, SlantStyleRange aStyleForEntry
,
973 const uint8_t* aFontData
, uint32_t aLength
) {
974 RefPtr
<IDWriteFontFileStream
> fontFileStream
;
975 RefPtr
<IDWriteFontFile
> fontFile
;
976 HRESULT hr
= gfxDWriteFontFileLoader::CreateCustomFontFile(
977 aFontData
, aLength
, getter_AddRefs(fontFile
),
978 getter_AddRefs(fontFileStream
));
979 free((void*)aFontData
);
980 NS_ASSERTION(SUCCEEDED(hr
), "Failed to create font file reference");
985 nsAutoString uniqueName
;
986 nsresult rv
= gfxFontUtils::MakeUniqueUserFontName(uniqueName
);
987 NS_ASSERTION(NS_SUCCEEDED(rv
), "Failed to make unique user font name");
993 DWRITE_FONT_FILE_TYPE fileType
;
996 auto entry
= MakeUnique
<gfxDWriteFontEntry
>(
997 NS_ConvertUTF16toUTF8(uniqueName
), fontFile
, fontFileStream
,
998 aWeightForEntry
, aStretchForEntry
, aStyleForEntry
);
1000 hr
= fontFile
->Analyze(&isSupported
, &fileType
, &entry
->mFaceType
, &numFaces
);
1001 NS_ASSERTION(SUCCEEDED(hr
), "IDWriteFontFile::Analyze failed");
1005 NS_ASSERTION(isSupported
, "Unsupported font file");
1009 NS_ASSERTION(numFaces
== 1, "Font file does not contain exactly 1 face");
1010 if (numFaces
!= 1) {
1011 // We don't know how to deal with 0 faces either.
1015 return entry
.release();
1018 bool gfxDWriteFontList::UseGDIFontTableAccess() const {
1019 // Using GDI font table access for DWrite is controlled by a pref, but also we
1020 // must be able to make win32k calls.
1021 return mGDIFontTableAccess
&& !IsWin32kLockedDown();
1024 static void GetPostScriptNameFromNameTable(IDWriteFontFace
* aFace
,
1027 NativeEndian::swapToBigEndian(TRUETYPE_TAG('n', 'a', 'm', 'e'));
1032 if (SUCCEEDED(aFace
->TryGetFontTable(kNAME
, (const void**)&data
, &size
,
1033 &context
, &exists
)) &&
1035 if (NS_FAILED(gfxFontUtils::ReadCanonicalName(
1036 data
, size
, gfxFontUtils::NAME_ID_POSTSCRIPT
, aName
))) {
1039 aFace
->ReleaseFontTable(context
);
1043 gfxFontEntry
* gfxDWriteFontList::CreateFontEntry(
1044 fontlist::Face
* aFace
, const fontlist::Family
* aFamily
) {
1045 IDWriteFontCollection
* collection
=
1046 #ifdef MOZ_BUNDLED_FONTS
1047 aFamily
->IsBundled() ? mBundledFonts
: mSystemFonts
;
1051 RefPtr
<IDWriteFontFamily
> family
;
1052 bool foundExpectedFamily
= false;
1053 const nsCString
& familyName
=
1054 aFamily
->DisplayName().AsString(SharedFontList());
1056 // The DirectWrite calls here might throw exceptions, e.g. in case of disk
1057 // errors when trying to read the font file.
1059 if (aFamily
->Index() < collection
->GetFontFamilyCount()) {
1061 collection
->GetFontFamily(aFamily
->Index(), getter_AddRefs(family
));
1062 // Check that the family name is what we expected; if not, fall back to
1063 // search by name. It's sad we have to do this, but it is possible for
1064 // Windows to have given different versions of the system font collection
1065 // to the parent and child processes.
1066 if (SUCCEEDED(hr
) && family
) {
1067 RefPtr
<IDWriteLocalizedStrings
> names
;
1068 hr
= family
->GetFamilyNames(getter_AddRefs(names
));
1069 if (SUCCEEDED(hr
) && names
) {
1071 if (GetEnglishOrFirstName(name
, names
)) {
1072 foundExpectedFamily
= name
.Equals(familyName
);
1077 if (!foundExpectedFamily
) {
1078 // Try to get family by name instead of index (to deal with the case of
1079 // collection mismatch).
1082 NS_ConvertUTF8toUTF16
name16(familyName
);
1083 HRESULT hr
= collection
->FindFamilyName(
1084 reinterpret_cast<const WCHAR
*>(name16
.BeginReading()), &index
,
1086 if (FAILED(hr
) || !exists
|| index
== UINT_MAX
||
1087 FAILED(collection
->GetFontFamily(index
, getter_AddRefs(family
))) ||
1093 // Retrieve the required face by index within the family.
1094 RefPtr
<IDWriteFont
> font
;
1095 if (FAILED(family
->GetFont(aFace
->mIndex
, getter_AddRefs(font
))) || !font
) {
1099 // Retrieve the psName from the font, so we can check we've found the
1101 nsAutoCString psName
;
1102 if (FAILED(GetDirectWriteFaceName(font
, PSNAME_ID
, psName
))) {
1103 RefPtr
<IDWriteFontFace
> dwFontFace
;
1104 if (SUCCEEDED(font
->CreateFontFace(getter_AddRefs(dwFontFace
)))) {
1105 GetPostScriptNameFromNameTable(dwFontFace
, psName
);
1109 // If it doesn't match, DirectWrite must have shuffled the order of faces
1110 // returned for the family; search by name as a fallback.
1111 nsCString faceName
= aFace
->mDescriptor
.AsString(SharedFontList());
1112 if (psName
!= faceName
) {
1113 gfxWarning() << "Face name mismatch for index " << aFace
->mIndex
1114 << " in family " << familyName
.get() << ": expected "
1115 << faceName
.get() << ", found " << psName
.get();
1116 for (uint32_t i
= 0; i
< family
->GetFontCount(); ++i
) {
1117 if (i
== aFace
->mIndex
) {
1118 continue; // this was the face we already tried
1120 if (FAILED(family
->GetFont(i
, getter_AddRefs(font
))) || !font
) {
1121 return nullptr; // this font family is broken!
1123 if (FAILED(GetDirectWriteFaceName(font
, PSNAME_ID
, psName
))) {
1124 RefPtr
<IDWriteFontFace
> dwFontFace
;
1125 if (SUCCEEDED(font
->CreateFontFace(getter_AddRefs(dwFontFace
)))) {
1126 GetPostScriptNameFromNameTable(dwFontFace
, psName
);
1129 if (psName
== faceName
) {
1134 if (psName
!= faceName
) {
1138 auto fe
= new gfxDWriteFontEntry(faceName
, font
, !aFamily
->IsBundled());
1139 fe
->InitializeFrom(aFace
, aFamily
);
1140 fe
->mForceGDIClassic
= aFamily
->IsForceClassic();
1141 fe
->mMayUseGDIAccess
= aFamily
->IsSimple();
1144 MOZ_SEH_EXCEPT(EXCEPTION_EXECUTE_HANDLER
) {
1145 gfxCriticalNote
<< "Exception occurred while creating font entry for "
1146 << familyName
.get();
1151 FontVisibility
gfxDWriteFontList::GetVisibilityForFamily(
1152 const nsACString
& aName
) const {
1153 if (FamilyInList(aName
, kBaseFonts
)) {
1154 return FontVisibility::Base
;
1156 if (FamilyInList(aName
, kLangPackFonts
)) {
1157 return FontVisibility::LangPack
;
1159 return FontVisibility::User
;
1162 nsTArray
<std::pair
<const char**, uint32_t>>
1163 gfxDWriteFontList::GetFilteredPlatformFontLists() {
1164 nsTArray
<std::pair
<const char**, uint32_t>> fontLists
;
1166 fontLists
.AppendElement(std::make_pair(kBaseFonts
, ArrayLength(kBaseFonts
)));
1167 fontLists
.AppendElement(
1168 std::make_pair(kLangPackFonts
, ArrayLength(kLangPackFonts
)));
1173 void gfxDWriteFontList::AppendFamiliesFromCollection(
1174 IDWriteFontCollection
* aCollection
,
1175 nsTArray
<fontlist::Family::InitData
>& aFamilies
,
1176 const nsTArray
<nsCString
>* aForceClassicFams
) {
1177 auto allFacesUltraBold
= [](IDWriteFontFamily
* aFamily
) -> bool {
1178 for (UINT32 i
= 0; i
< aFamily
->GetFontCount(); i
++) {
1179 RefPtr
<IDWriteFont
> font
;
1180 HRESULT hr
= aFamily
->GetFont(i
, getter_AddRefs(font
));
1182 NS_WARNING("Failed to get existing font from family.");
1185 nsAutoCString faceName
;
1186 hr
= GetDirectWriteFontName(font
, faceName
);
1190 if (faceName
.Find("Ultra Bold"_ns
) == kNotFound
) {
1197 nsAutoCString locale
;
1198 OSPreferences::GetInstance()->GetSystemLocale(locale
);
1199 ToLowerCase(locale
);
1200 NS_ConvertUTF8toUTF16
loc16(locale
);
1202 for (unsigned i
= 0; i
< aCollection
->GetFontFamilyCount(); ++i
) {
1203 RefPtr
<IDWriteFontFamily
> family
;
1204 aCollection
->GetFontFamily(i
, getter_AddRefs(family
));
1205 RefPtr
<IDWriteLocalizedStrings
> localizedNames
;
1206 HRESULT hr
= family
->GetFamilyNames(getter_AddRefs(localizedNames
));
1208 gfxWarning() << "Failed to get names for font-family " << i
;
1212 auto addFamily
= [&](const nsACString
& name
, FontVisibility visibility
,
1213 bool altLocale
= false) {
1216 BuildKeyNameFromFontName(key
);
1217 bool bad
= mBadUnderlineFamilyNames
.ContainsSorted(key
);
1219 aForceClassicFams
&& aForceClassicFams
->ContainsSorted(key
);
1220 aFamilies
.AppendElement(fontlist::Family::InitData(
1221 key
, name
, i
, visibility
, aCollection
!= mSystemFonts
, bad
, classic
,
1225 auto visibilityForName
= [&](const nsACString
& aName
) -> FontVisibility
{
1226 // Special case: hide the "Gill Sans" family that contains only UltraBold
1227 // faces, as this leads to breakage on sites with CSS that targeted the
1228 // Gill Sans family as found on macOS. (Bug 551313, bug 1632738)
1229 // TODO (jfkthame): the ultrabold faces from Gill Sans should be treated
1230 // as belonging to the Gill Sans MT family.
1231 if (aName
.EqualsLiteral("Gill Sans") && allFacesUltraBold(family
)) {
1232 return FontVisibility::Hidden
;
1234 // Bundled fonts are always available, so only system fonts are checked
1235 // against the standard font names list.
1236 return aCollection
== mSystemFonts
? GetVisibilityForFamily(aName
)
1237 : FontVisibility::Base
;
1240 unsigned count
= localizedNames
->GetCount();
1242 // This is the common case: the great majority of fonts only provide an
1243 // en-US family name.
1245 if (!GetNameAsUtf8(name
, localizedNames
, 0)) {
1246 gfxWarning() << "GetNameAsUtf8 failed for index 0 in font-family " << i
;
1249 addFamily(name
, visibilityForName(name
));
1251 AutoTArray
<nsCString
, 4> names
;
1252 int sysLocIndex
= -1;
1253 FontVisibility visibility
= FontVisibility::User
;
1254 for (unsigned index
= 0; index
< count
; ++index
) {
1256 if (!GetNameAsUtf8(name
, localizedNames
, index
)) {
1257 gfxWarning() << "GetNameAsUtf8 failed for index " << index
1258 << " in font-family " << i
;
1261 if (names
.Contains(name
)) {
1264 if (sysLocIndex
== -1) {
1266 if (SUCCEEDED(localizedNames
->GetLocaleName(index
, buf
, 32))) {
1267 if (loc16
.Equals(buf
)) {
1268 sysLocIndex
= names
.Length();
1272 names
.AppendElement(name
);
1273 // We give the family the least-restrictive visibility of all its
1274 // localized names, so that the used visibility will not depend on
1275 // locale; with the exception that if any name is explicitly Hidden,
1276 // this hides the family as a whole.
1277 if (visibility
!= FontVisibility::Hidden
) {
1278 FontVisibility v
= visibilityForName(name
);
1279 if (v
== FontVisibility::Hidden
) {
1280 visibility
= FontVisibility::Hidden
;
1282 visibility
= std::min(visibility
, v
);
1286 // If we didn't find a name that matched the system locale, use the
1287 // first (which is most often en-US).
1288 if (sysLocIndex
== -1) {
1291 // Hack to work around EPSON fonts with bad names (tagged as MacRoman
1292 // but actually contain MacJapanese data): if we've chosen the first
1293 // name, *and* it is non-ASCII, *and* there is an alternative present,
1294 // use the next option instead as being more likely to be valid.
1295 if (sysLocIndex
== 0 && names
.Length() > 1 && !IsAscii(names
[0])) {
1298 for (unsigned index
= 0; index
< names
.Length(); ++index
) {
1299 addFamily(names
[index
], visibility
,
1300 index
!= static_cast<unsigned>(sysLocIndex
));
1306 void gfxDWriteFontList::GetFacesInitDataForFamily(
1307 const fontlist::Family
* aFamily
, nsTArray
<fontlist::Face::InitData
>& aFaces
,
1308 bool aLoadCmaps
) const {
1309 IDWriteFontCollection
* collection
=
1310 #ifdef MOZ_BUNDLED_FONTS
1311 aFamily
->IsBundled() ? mBundledFonts
: mSystemFonts
;
1318 RefPtr
<IDWriteFontFamily
> family
;
1319 collection
->GetFontFamily(aFamily
->Index(), getter_AddRefs(family
));
1320 for (unsigned i
= 0; i
< family
->GetFontCount(); ++i
) {
1321 RefPtr
<IDWriteFont
> dwFont
;
1322 family
->GetFont(i
, getter_AddRefs(dwFont
));
1323 if (!dwFont
|| dwFont
->GetSimulations() != DWRITE_FONT_SIMULATIONS_NONE
) {
1326 DWRITE_FONT_STYLE dwstyle
= dwFont
->GetStyle();
1327 // Ignore italic styles of Meiryo because "Meiryo (Bold) Italic" has
1328 // non-italic style glyphs as Japanese characters. However, using it
1329 // causes serious problem if web pages wants some elements to be
1330 // different style from others only with font-style. For example,
1331 // <em> and <i> should be rendered as italic in the default style.
1332 if (dwstyle
!= DWRITE_FONT_STYLE_NORMAL
&&
1333 aFamily
->Key().AsString(SharedFontList()).EqualsLiteral("meiryo")) {
1336 WeightRange
weight(FontWeight::FromInt(dwFont
->GetWeight()));
1337 StretchRange
stretch(FontStretchFromDWriteStretch(dwFont
->GetStretch()));
1338 // Try to read PSName as a unique face identifier; if this fails we'll get
1339 // it directly from the 'name' table, and if that also fails we consider
1340 // the face unusable.
1343 RefPtr
<gfxCharacterMap
> charmap
;
1344 if (FAILED(GetDirectWriteFaceName(dwFont
, PSNAME_ID
, name
)) ||
1346 RefPtr
<IDWriteFontFace
> dwFontFace
;
1347 if (SUCCEEDED(dwFont
->CreateFontFace(getter_AddRefs(dwFontFace
)))) {
1348 if (name
.IsEmpty()) {
1349 GetPostScriptNameFromNameTable(dwFontFace
, name
);
1352 NativeEndian::swapToBigEndian(TRUETYPE_TAG('c', 'm', 'a', 'p'));
1358 if (SUCCEEDED(dwFontFace
->TryGetFontTable(
1359 kCMAP
, (const void**)&data
, &size
, &context
, &exists
)) &&
1361 charmap
= new gfxCharacterMap();
1363 gfxFontUtils::ReadCMAP((const uint8_t*)data
, size
, *charmap
,
1365 dwFontFace
->ReleaseFontTable(context
);
1370 if (name
.IsEmpty()) {
1371 gfxWarning() << "Failed to get name for face " << i
<< " in family "
1372 << aFamily
->Key().AsString(SharedFontList()).get();
1375 SlantStyleRange
slant(
1376 dwstyle
== DWRITE_FONT_STYLE_NORMAL
? FontSlantStyle::NORMAL
1377 : dwstyle
== DWRITE_FONT_STYLE_ITALIC
? FontSlantStyle::ITALIC
1378 : FontSlantStyle::OBLIQUE
);
1379 aFaces
.AppendElement(fontlist::Face::InitData
{
1380 name
, uint16_t(i
), false, weight
, stretch
, slant
, charmap
});
1382 MOZ_SEH_EXCEPT(EXCEPTION_EXECUTE_HANDLER
) {
1383 // Exception (e.g. disk i/o error) occurred when DirectWrite tried to use
1384 // the font resource. We'll just skip the bad face.
1385 gfxCriticalNote
<< "Exception occurred reading faces for "
1386 << aFamily
->Key().AsString(SharedFontList()).get();
1391 bool gfxDWriteFontList::ReadFaceNames(const fontlist::Family
* aFamily
,
1392 const fontlist::Face
* aFace
,
1394 nsCString
& aFullName
) {
1395 IDWriteFontCollection
* collection
=
1396 #ifdef MOZ_BUNDLED_FONTS
1397 aFamily
->IsBundled() ? mBundledFonts
: mSystemFonts
;
1401 RefPtr
<IDWriteFontFamily
> family
;
1402 if (FAILED(collection
->GetFontFamily(aFamily
->Index(),
1403 getter_AddRefs(family
)))) {
1404 MOZ_ASSERT_UNREACHABLE("failed to get font-family");
1407 RefPtr
<IDWriteFont
> dwFont
;
1408 if (FAILED(family
->GetFont(aFace
->mIndex
, getter_AddRefs(dwFont
)))) {
1409 MOZ_ASSERT_UNREACHABLE("failed to get font from family");
1412 HRESULT ps
= GetDirectWriteFaceName(dwFont
, PSNAME_ID
, aPSName
);
1413 HRESULT full
= GetDirectWriteFaceName(dwFont
, FULLNAME_ID
, aFullName
);
1414 if (FAILED(ps
) || FAILED(full
) || aPSName
.IsEmpty() || aFullName
.IsEmpty()) {
1415 // We'll return true if either name was found, false if both fail.
1416 // Note that on older Win7 systems, GetDirectWriteFaceName may "succeed"
1417 // but return an empty string, so we have to check for non-empty strings
1418 // to be sure we actually got a usable name.
1420 // Initialize result to true if either name was already found.
1421 bool result
= (SUCCEEDED(ps
) && !aPSName
.IsEmpty()) ||
1422 (SUCCEEDED(full
) && !aFullName
.IsEmpty());
1423 RefPtr
<IDWriteFontFace
> dwFontFace
;
1424 if (FAILED(dwFont
->CreateFontFace(getter_AddRefs(dwFontFace
)))) {
1425 NS_WARNING("failed to create font face");
1432 if (FAILED(dwFontFace
->TryGetFontTable(
1433 NativeEndian::swapToBigEndian(TRUETYPE_TAG('n', 'a', 'm', 'e')),
1434 (const void**)&data
, &size
, &context
, &exists
)) ||
1436 NS_WARNING("failed to get name table");
1440 // Try to read the name table entries, and ensure result is true if either
1442 if (FAILED(ps
) || aPSName
.IsEmpty()) {
1443 if (NS_SUCCEEDED(gfxFontUtils::ReadCanonicalName(
1444 data
, size
, gfxFontUtils::NAME_ID_POSTSCRIPT
, aPSName
))) {
1447 NS_WARNING("failed to read psname");
1450 if (FAILED(full
) || aFullName
.IsEmpty()) {
1451 if (NS_SUCCEEDED(gfxFontUtils::ReadCanonicalName(
1452 data
, size
, gfxFontUtils::NAME_ID_FULL
, aFullName
))) {
1455 NS_WARNING("failed to read fullname");
1459 MOZ_SEH_EXCEPT(EXCEPTION_EXECUTE_HANDLER
) {
1460 gfxCriticalNote
<< "Exception occurred reading face names for "
1461 << aFamily
->Key().AsString(SharedFontList()).get();
1463 if (dwFontFace
&& context
) {
1464 dwFontFace
->ReleaseFontTable(context
);
1471 void gfxDWriteFontList::ReadFaceNamesForFamily(
1472 fontlist::Family
* aFamily
, bool aNeedFullnamePostscriptNames
) {
1473 if (!aFamily
->IsInitialized()) {
1474 if (!InitializeFamily(aFamily
)) {
1478 IDWriteFontCollection
* collection
=
1479 #ifdef MOZ_BUNDLED_FONTS
1480 aFamily
->IsBundled() ? mBundledFonts
: mSystemFonts
;
1484 RefPtr
<IDWriteFontFamily
> family
;
1485 if (FAILED(collection
->GetFontFamily(aFamily
->Index(),
1486 getter_AddRefs(family
)))) {
1489 fontlist::FontList
* list
= SharedFontList();
1490 const fontlist::Pointer
* facePtrs
= aFamily
->Faces(list
);
1491 nsAutoCString
familyName(aFamily
->DisplayName().AsString(list
));
1492 nsAutoCString
key(aFamily
->Key().AsString(list
));
1495 // Read PS-names and fullnames of the faces, and any alternate family names
1496 // (either localizations or legacy subfamily names)
1497 for (unsigned i
= 0; i
< aFamily
->NumFaces(); ++i
) {
1498 auto* face
= facePtrs
[i
].ToPtr
<fontlist::Face
>(list
);
1502 RefPtr
<IDWriteFont
> dwFont
;
1503 if (FAILED(family
->GetFont(face
->mIndex
, getter_AddRefs(dwFont
)))) {
1506 RefPtr
<IDWriteFontFace
> dwFontFace
;
1507 if (FAILED(dwFont
->CreateFontFace(getter_AddRefs(dwFontFace
)))) {
1515 if (FAILED(dwFontFace
->TryGetFontTable(
1516 NativeEndian::swapToBigEndian(TRUETYPE_TAG('n', 'a', 'm', 'e')),
1517 (const void**)&data
, &size
, &context
, &exists
)) ||
1522 AutoTArray
<nsCString
, 4> otherFamilyNames
;
1523 gfxFontUtils::ReadOtherFamilyNamesForFace(familyName
, data
, size
,
1524 otherFamilyNames
, false);
1525 for (const auto& alias
: otherFamilyNames
) {
1526 nsAutoCString
key(alias
);
1528 auto aliasData
= mAliasTable
.GetOrInsertNew(key
);
1529 aliasData
->InitFromFamily(aFamily
, familyName
);
1530 aliasData
->mFaces
.AppendElement(facePtrs
[i
]);
1533 nsAutoCString psname
, fullname
;
1534 // Bug 1854090: don't load PSname if the family name ends with ".tmp",
1535 // as some PDF-related software appears to pollute the font collection
1536 // with spurious re-encoded versions of standard fonts like Arial, fails
1537 // to alter the PSname, and thus can result in garbled rendering because
1538 // the wrong resource may be found via src:local(...).
1539 if (!StringEndsWith(key
, ".tmp"_ns
)) {
1540 if (NS_SUCCEEDED(gfxFontUtils::ReadCanonicalName(
1541 data
, size
, gfxFontUtils::NAME_ID_POSTSCRIPT
, psname
))) {
1542 ToLowerCase(psname
);
1543 mLocalNameTable
.InsertOrUpdate(
1544 psname
, fontlist::LocalFaceRec::InitData(key
, i
));
1547 if (NS_SUCCEEDED(gfxFontUtils::ReadCanonicalName(
1548 data
, size
, gfxFontUtils::NAME_ID_FULL
, fullname
))) {
1549 ToLowerCase(fullname
);
1550 if (fullname
!= psname
) {
1551 mLocalNameTable
.InsertOrUpdate(
1552 fullname
, fontlist::LocalFaceRec::InitData(key
, i
));
1556 dwFontFace
->ReleaseFontTable(context
);
1559 MOZ_SEH_EXCEPT(EXCEPTION_EXECUTE_HANDLER
) {
1560 gfxCriticalNote
<< "Exception occurred reading names for "
1561 << familyName
.get();
1565 enum DWriteInitError
{
1567 errSystemFontCollection
= 2,
1571 void gfxDWriteFontList::InitSharedFontListForPlatform() {
1572 mGDIFontTableAccess
= Preferences::GetBool(
1573 "gfx.font_rendering.directwrite.use_gdi_table_loading", false);
1574 mForceGDIClassicMaxFontSize
= Preferences::GetInt(
1575 "gfx.font_rendering.cleartype_params.force_gdi_classic_max_size",
1576 mForceGDIClassicMaxFontSize
);
1578 mSubstitutions
.Clear();
1579 mNonExistingFonts
.Clear();
1581 RefPtr
<IDWriteFactory
> factory
= Factory::GetDWriteFactory();
1582 HRESULT hr
= factory
->GetGdiInterop(getter_AddRefs(mGDIInterop
));
1584 Telemetry::Accumulate(Telemetry::DWRITEFONT_INIT_PROBLEM
,
1585 uint32_t(errGDIInterop
));
1586 mSharedFontList
.reset(nullptr);
1590 mSystemFonts
= Factory::GetDWriteSystemFonts(true);
1591 NS_ASSERTION(mSystemFonts
!= nullptr, "GetSystemFontCollection failed!");
1592 if (!mSystemFonts
) {
1593 Telemetry::Accumulate(Telemetry::DWRITEFONT_INIT_PROBLEM
,
1594 uint32_t(errSystemFontCollection
));
1595 mSharedFontList
.reset(nullptr);
1598 #ifdef MOZ_BUNDLED_FONTS
1599 // We activate bundled fonts if the pref is > 0 (on) or < 0 (auto), only an
1600 // explicit value of 0 (off) will disable them.
1601 TimeStamp start1
= TimeStamp::Now();
1602 if (StaticPrefs::gfx_bundled_fonts_activate_AtStartup() != 0) {
1603 mBundledFonts
= CreateBundledFontsCollection(factory
);
1605 TimeStamp end1
= TimeStamp::Now();
1608 if (XRE_IsParentProcess()) {
1609 nsAutoCString classicFamilies
;
1610 AutoTArray
<nsCString
, 16> forceClassicFams
;
1611 nsresult rv
= Preferences::GetCString(
1612 "gfx.font_rendering.cleartype_params.force_gdi_classic_for_families",
1614 if (NS_SUCCEEDED(rv
)) {
1616 nsCCharSeparatedTokenizer(classicFamilies
, ',').ToRange()) {
1617 BuildKeyNameFromFontName(name
);
1618 forceClassicFams
.AppendElement(name
);
1620 forceClassicFams
.Sort();
1622 nsTArray
<fontlist::Family::InitData
> families
;
1623 AppendFamiliesFromCollection(mSystemFonts
, families
, &forceClassicFams
);
1624 #ifdef MOZ_BUNDLED_FONTS
1625 if (mBundledFonts
) {
1626 TimeStamp start2
= TimeStamp::Now();
1627 AppendFamiliesFromCollection(mBundledFonts
, families
);
1628 TimeStamp end2
= TimeStamp::Now();
1629 Telemetry::Accumulate(
1630 Telemetry::FONTLIST_BUNDLEDFONTS_ACTIVATE
,
1631 (end1
- start1
).ToMilliseconds() + (end2
- start2
).ToMilliseconds());
1634 SharedFontList()->SetFamilyNames(families
);
1635 GetPrefsAndStartLoader();
1638 if (!SharedFontList()->Initialized()) {
1642 GetDirectWriteSubstitutes();
1643 GetFontSubstitutes();
1646 nsresult
gfxDWriteFontList::InitFontListForPlatform() {
1647 LARGE_INTEGER frequency
; // ticks per second
1648 LARGE_INTEGER t1
, t2
, t3
, t4
, t5
; // ticks
1649 double elapsedTime
, upTime
;
1650 char nowTime
[256], nowDate
[256];
1652 if (LOG_FONTINIT_ENABLED()) {
1653 GetTimeFormatA(LOCALE_INVARIANT
, TIME_FORCE24HOURFORMAT
, nullptr, nullptr,
1655 GetDateFormatA(LOCALE_INVARIANT
, 0, nullptr, nullptr, nowDate
, 256);
1656 upTime
= (double)GetTickCount();
1658 QueryPerformanceFrequency(&frequency
);
1659 QueryPerformanceCounter(&t1
); // start
1662 mGDIFontTableAccess
= Preferences::GetBool(
1663 "gfx.font_rendering.directwrite.use_gdi_table_loading", false);
1665 mFontSubstitutes
.Clear();
1666 mNonExistingFonts
.Clear();
1668 RefPtr
<IDWriteFactory
> factory
= Factory::GetDWriteFactory();
1670 hr
= factory
->GetGdiInterop(getter_AddRefs(mGDIInterop
));
1672 Telemetry::Accumulate(Telemetry::DWRITEFONT_INIT_PROBLEM
,
1673 uint32_t(errGDIInterop
));
1674 return NS_ERROR_FAILURE
;
1677 QueryPerformanceCounter(&t2
); // base-class/interop initialization
1679 mSystemFonts
= Factory::GetDWriteSystemFonts(true);
1680 NS_ASSERTION(mSystemFonts
!= nullptr, "GetSystemFontCollection failed!");
1682 if (!mSystemFonts
) {
1683 Telemetry::Accumulate(Telemetry::DWRITEFONT_INIT_PROBLEM
,
1684 uint32_t(errSystemFontCollection
));
1685 return NS_ERROR_FAILURE
;
1688 #ifdef MOZ_BUNDLED_FONTS
1689 // Get bundled fonts before the system collection, so that in the case of
1690 // duplicate names, we have recorded the family as bundled (and therefore
1691 // available regardless of visibility settings).
1692 // We activate bundled fonts if the pref is > 0 (on) or < 0 (auto), only an
1693 // explicit value of 0 (off) will disable them.
1694 if (StaticPrefs::gfx_bundled_fonts_activate_AtStartup() != 0) {
1695 TimeStamp start
= TimeStamp::Now();
1696 mBundledFonts
= CreateBundledFontsCollection(factory
);
1697 if (mBundledFonts
) {
1698 GetFontsFromCollection(mBundledFonts
);
1700 TimeStamp end
= TimeStamp::Now();
1701 Telemetry::Accumulate(Telemetry::FONTLIST_BUNDLEDFONTS_ACTIVATE
,
1702 (end
- start
).ToMilliseconds());
1705 const uint32_t kBundledCount
= mFontFamilies
.Count();
1707 QueryPerformanceCounter(&t3
); // system font collection
1709 GetFontsFromCollection(mSystemFonts
);
1711 // if no fonts found, something is out of whack, bail and use GDI backend
1712 NS_ASSERTION(mFontFamilies
.Count() > kBundledCount
,
1713 "no fonts found in the system fontlist -- holy crap batman!");
1714 if (mFontFamilies
.Count() == kBundledCount
) {
1715 Telemetry::Accumulate(Telemetry::DWRITEFONT_INIT_PROBLEM
,
1716 uint32_t(errNoFonts
));
1717 return NS_ERROR_FAILURE
;
1720 QueryPerformanceCounter(&t4
); // iterate over system fonts
1722 mOtherFamilyNamesInitialized
= true;
1723 GetFontSubstitutes();
1725 // bug 642093 - DirectWrite does not support old bitmap (.fon)
1726 // font files, but a few of these such as "Courier" and "MS Sans Serif"
1727 // are frequently specified in shoddy CSS, without appropriate fallbacks.
1728 // By mapping these to TrueType equivalents, we provide better consistency
1729 // with both pre-DW systems and with IE9, which appears to do the same.
1730 GetDirectWriteSubstitutes();
1732 // bug 551313 - DirectWrite creates a Gill Sans family out of
1733 // poorly named members of the Gill Sans MT family containing
1734 // only Ultra Bold weights. This causes big problems for pages
1735 // using Gill Sans which is usually only available on OSX
1737 nsAutoCString
nameGillSans("Gill Sans");
1738 nsAutoCString
nameGillSansMT("Gill Sans MT");
1739 BuildKeyNameFromFontName(nameGillSans
);
1740 BuildKeyNameFromFontName(nameGillSansMT
);
1742 gfxFontFamily
* gillSansFamily
= mFontFamilies
.GetWeak(nameGillSans
);
1743 gfxFontFamily
* gillSansMTFamily
= mFontFamilies
.GetWeak(nameGillSansMT
);
1745 if (gillSansFamily
&& gillSansMTFamily
) {
1746 gillSansFamily
->FindStyleVariations();
1748 gillSansFamily
->ReadLock();
1749 const auto& faces
= gillSansFamily
->GetFontList();
1751 bool allUltraBold
= true;
1752 for (const auto& face
: faces
) {
1753 // does the face have 'Ultra Bold' in the name?
1754 if (face
->Name().Find("Ultra Bold"_ns
) == -1) {
1755 allUltraBold
= false;
1760 // if all the Gill Sans faces are Ultra Bold ==> move faces
1761 // for Gill Sans into Gill Sans MT family
1763 // add faces to Gill Sans MT
1764 for (const auto& face
: faces
) {
1765 // change the entry's family name to match its adoptive family
1766 face
->mFamilyName
= gillSansMTFamily
->Name();
1767 gillSansMTFamily
->AddFontEntry(face
);
1769 if (LOG_FONTLIST_ENABLED()) {
1770 nsAutoCString weightString
;
1771 face
->Weight().ToString(weightString
);
1773 ("(fontlist) moved (%s) to family (%s)"
1774 " with style: %s weight: %s stretch: %d",
1775 face
->Name().get(), gillSansMTFamily
->Name().get(),
1776 (face
->IsItalic()) ? "italic"
1777 : (face
->IsOblique() ? "oblique" : "normal"),
1778 weightString
.get(), face
->Stretch().AsScalar()));
1781 gillSansFamily
->ReadUnlock();
1784 mFontFamilies
.Remove(nameGillSans
);
1786 gillSansFamily
->ReadUnlock();
1790 nsAutoCString classicFamilies
;
1791 nsresult rv
= Preferences::GetCString(
1792 "gfx.font_rendering.cleartype_params.force_gdi_classic_for_families",
1794 if (NS_SUCCEEDED(rv
)) {
1795 nsCCharSeparatedTokenizer
tokenizer(classicFamilies
, ',');
1796 while (tokenizer
.hasMoreTokens()) {
1797 nsAutoCString
name(tokenizer
.nextToken());
1798 BuildKeyNameFromFontName(name
);
1799 gfxFontFamily
* family
= mFontFamilies
.GetWeak(name
);
1801 static_cast<gfxDWriteFontFamily
*>(family
)->SetForceGDIClassic(true);
1805 mForceGDIClassicMaxFontSize
= Preferences::GetInt(
1806 "gfx.font_rendering.cleartype_params.force_gdi_classic_max_size",
1807 mForceGDIClassicMaxFontSize
);
1809 GetPrefsAndStartLoader();
1811 QueryPerformanceCounter(&t5
); // misc initialization
1813 if (LOG_FONTINIT_ENABLED()) {
1814 // determine dwrite version
1815 nsAutoString dwriteVers
;
1816 gfxWindowsPlatform::GetDLLVersion(L
"dwrite.dll", dwriteVers
);
1817 LOG_FONTINIT(("(fontinit) Start: %s %s\n", nowDate
, nowTime
));
1818 LOG_FONTINIT(("(fontinit) Uptime: %9.3f s\n", upTime
/ 1000));
1819 LOG_FONTINIT(("(fontinit) dwrite version: %s\n",
1820 NS_ConvertUTF16toUTF8(dwriteVers
).get()));
1823 elapsedTime
= (t5
.QuadPart
- t1
.QuadPart
) * 1000.0 / frequency
.QuadPart
;
1824 Telemetry::Accumulate(Telemetry::DWRITEFONT_DELAYEDINITFONTLIST_TOTAL
,
1826 Telemetry::Accumulate(Telemetry::DWRITEFONT_DELAYEDINITFONTLIST_COUNT
,
1827 mSystemFonts
->GetFontFamilyCount());
1829 "(fontinit) Total time in InitFontList: %9.3f ms (families: %d, %s)\n",
1830 elapsedTime
, mSystemFonts
->GetFontFamilyCount(),
1831 (mGDIFontTableAccess
? "gdi table access" : "dwrite table access")));
1833 elapsedTime
= (t2
.QuadPart
- t1
.QuadPart
) * 1000.0 / frequency
.QuadPart
;
1835 ("(fontinit) --- base/interop obj initialization init: %9.3f ms\n",
1838 elapsedTime
= (t3
.QuadPart
- t2
.QuadPart
) * 1000.0 / frequency
.QuadPart
;
1839 Telemetry::Accumulate(Telemetry::DWRITEFONT_DELAYEDINITFONTLIST_COLLECT
,
1842 ("(fontinit) --- GetSystemFontCollection: %9.3f ms\n", elapsedTime
));
1844 elapsedTime
= (t4
.QuadPart
- t3
.QuadPart
) * 1000.0 / frequency
.QuadPart
;
1846 ("(fontinit) --- iterate over families: %9.3f ms\n", elapsedTime
));
1848 elapsedTime
= (t5
.QuadPart
- t4
.QuadPart
) * 1000.0 / frequency
.QuadPart
;
1850 ("(fontinit) --- misc initialization: %9.3f ms\n", elapsedTime
));
1855 void gfxDWriteFontList::GetFontsFromCollection(
1856 IDWriteFontCollection
* aCollection
) {
1857 for (UINT32 i
= 0; i
< aCollection
->GetFontFamilyCount(); i
++) {
1858 RefPtr
<IDWriteFontFamily
> family
;
1859 aCollection
->GetFontFamily(i
, getter_AddRefs(family
));
1861 RefPtr
<IDWriteLocalizedStrings
> names
;
1862 HRESULT hr
= family
->GetFamilyNames(getter_AddRefs(names
));
1868 if (!GetEnglishOrFirstName(name
, names
)) {
1871 nsAutoCString
familyName(
1872 name
); // keep a copy before we lowercase it as a key
1874 BuildKeyNameFromFontName(name
);
1876 RefPtr
<gfxFontFamily
> fam
;
1878 if (mFontFamilies
.GetWeak(name
)) {
1882 FontVisibility visibility
= aCollection
== mSystemFonts
1883 ? GetVisibilityForFamily(familyName
)
1884 : FontVisibility::Base
;
1886 fam
= new gfxDWriteFontFamily(familyName
, visibility
, family
,
1887 aCollection
== mSystemFonts
);
1892 if (mBadUnderlineFamilyNames
.ContainsSorted(name
)) {
1893 fam
->SetBadUnderlineFamily();
1895 mFontFamilies
.InsertOrUpdate(name
, RefPtr
{fam
});
1897 // now add other family name localizations, if present
1898 uint32_t nameCount
= names
->GetCount();
1901 if (nameCount
> 1) {
1902 UINT32 englishIdx
= 0;
1904 // if this fails/doesn't exist, we'll have used name index 0,
1905 // so that's the one we'll want to skip here
1906 names
->FindLocaleName(L
"en-us", &englishIdx
, &exists
);
1907 AutoTArray
<nsCString
, 4> otherFamilyNames
;
1908 for (nameIndex
= 0; nameIndex
< nameCount
; nameIndex
++) {
1910 AutoTArray
<WCHAR
, 32> localizedName
;
1912 // only add other names
1913 if (nameIndex
== englishIdx
) {
1917 hr
= names
->GetStringLength(nameIndex
, &nameLen
);
1922 if (!localizedName
.SetLength(nameLen
+ 1, fallible
)) {
1926 hr
= names
->GetString(nameIndex
, localizedName
.Elements(), nameLen
+ 1);
1931 NS_ConvertUTF16toUTF8
locName(localizedName
.Elements());
1933 if (!familyName
.Equals(locName
)) {
1934 otherFamilyNames
.AppendElement(locName
);
1937 if (!otherFamilyNames
.IsEmpty()) {
1938 AddOtherFamilyNames(fam
, otherFamilyNames
);
1942 // at this point, all family names have been read in
1943 fam
->SetOtherFamilyNamesInitialized();
1947 static void RemoveCharsetFromFontSubstitute(nsACString
& aName
) {
1948 int32_t comma
= aName
.FindChar(',');
1949 if (comma
>= 0) aName
.Truncate(comma
);
1952 #define MAX_VALUE_NAME 512
1953 #define MAX_VALUE_DATA 512
1955 nsresult
gfxDWriteFontList::GetFontSubstitutes() {
1957 DWORD i
, rv
, lenAlias
, lenActual
, valueType
;
1958 WCHAR aliasName
[MAX_VALUE_NAME
];
1959 WCHAR actualName
[MAX_VALUE_DATA
];
1963 L
"SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\FontSubstitutes",
1964 0, KEY_READ
, &hKey
) != ERROR_SUCCESS
) {
1965 return NS_ERROR_FAILURE
;
1968 for (i
= 0, rv
= ERROR_SUCCESS
; rv
!= ERROR_NO_MORE_ITEMS
; i
++) {
1970 lenAlias
= ArrayLength(aliasName
);
1972 lenActual
= sizeof(actualName
);
1973 rv
= RegEnumValueW(hKey
, i
, aliasName
, &lenAlias
, nullptr, &valueType
,
1974 (LPBYTE
)actualName
, &lenActual
);
1976 if (rv
!= ERROR_SUCCESS
|| valueType
!= REG_SZ
|| lenAlias
== 0) {
1980 if (aliasName
[0] == WCHAR('@')) {
1984 NS_ConvertUTF16toUTF8
substituteName((char16_t
*)aliasName
);
1985 NS_ConvertUTF16toUTF8
actualFontName((char16_t
*)actualName
);
1986 RemoveCharsetFromFontSubstitute(substituteName
);
1987 BuildKeyNameFromFontName(substituteName
);
1988 RemoveCharsetFromFontSubstitute(actualFontName
);
1989 BuildKeyNameFromFontName(actualFontName
);
1990 if (SharedFontList()) {
1991 // Skip substitution if the original font is available, unless the option
1992 // to apply substitutions unconditionally is enabled.
1993 if (!StaticPrefs::gfx_windows_font_substitutes_always_AtStartup()) {
1994 // Font substitutions are recorded for the canonical family names; we
1995 // don't need FindFamily to consider localized aliases when searching.
1996 if (SharedFontList()->FindFamily(substituteName
,
1997 /*aPrimaryNameOnly*/ true)) {
2001 if (SharedFontList()->FindFamily(actualFontName
,
2002 /*aPrimaryNameOnly*/ true)) {
2003 mSubstitutions
.InsertOrUpdate(substituteName
,
2004 MakeUnique
<nsCString
>(actualFontName
));
2005 } else if (mSubstitutions
.Get(actualFontName
)) {
2006 mSubstitutions
.InsertOrUpdate(
2008 MakeUnique
<nsCString
>(*mSubstitutions
.Get(actualFontName
)));
2010 mNonExistingFonts
.AppendElement(substituteName
);
2014 if (!actualFontName
.IsEmpty() &&
2015 (ff
= mFontFamilies
.GetWeak(actualFontName
))) {
2016 mFontSubstitutes
.InsertOrUpdate(substituteName
, RefPtr
{ff
});
2018 mNonExistingFonts
.AppendElement(substituteName
);
2025 struct FontSubstitution
{
2026 const char* aliasName
;
2027 const char* actualName
;
2030 static const FontSubstitution sDirectWriteSubs
[] = {
2031 {"MS Sans Serif", "Microsoft Sans Serif"},
2032 {"MS Serif", "Times New Roman"},
2033 {"Courier", "Courier New"},
2034 {"Small Fonts", "Arial"},
2035 {"Roman", "Times New Roman"},
2036 {"Script", "Mistral"}};
2038 void gfxDWriteFontList::GetDirectWriteSubstitutes() {
2039 for (uint32_t i
= 0; i
< ArrayLength(sDirectWriteSubs
); ++i
) {
2040 const FontSubstitution
& sub(sDirectWriteSubs
[i
]);
2041 nsAutoCString
substituteName(sub
.aliasName
);
2042 BuildKeyNameFromFontName(substituteName
);
2043 if (SharedFontList()) {
2044 // Skip substitution if the original font is available, unless the option
2045 // to apply substitutions unconditionally is enabled.
2046 if (!StaticPrefs::gfx_windows_font_substitutes_always_AtStartup()) {
2047 // We don't need FindFamily to consider localized aliases when searching
2048 // for the DirectWrite substitutes, we know the canonical names.
2049 if (SharedFontList()->FindFamily(substituteName
,
2050 /*aPrimaryNameOnly*/ true)) {
2054 nsAutoCString
actualFontName(sub
.actualName
);
2055 BuildKeyNameFromFontName(actualFontName
);
2056 if (SharedFontList()->FindFamily(actualFontName
,
2057 /*aPrimaryNameOnly*/ true)) {
2058 mSubstitutions
.InsertOrUpdate(substituteName
,
2059 MakeUnique
<nsCString
>(actualFontName
));
2061 mNonExistingFonts
.AppendElement(substituteName
);
2064 if (nullptr != mFontFamilies
.GetWeak(substituteName
)) {
2065 // don't do the substitution if user actually has a usable font
2066 // with this name installed
2069 nsAutoCString
actualFontName(sub
.actualName
);
2070 BuildKeyNameFromFontName(actualFontName
);
2072 if (nullptr != (ff
= mFontFamilies
.GetWeak(actualFontName
))) {
2073 mFontSubstitutes
.InsertOrUpdate(substituteName
, RefPtr
{ff
});
2075 mNonExistingFonts
.AppendElement(substituteName
);
2081 bool gfxDWriteFontList::FindAndAddFamiliesLocked(
2082 nsPresContext
* aPresContext
, StyleGenericFontFamily aGeneric
,
2083 const nsACString
& aFamily
, nsTArray
<FamilyAndGeneric
>* aOutput
,
2084 FindFamiliesFlags aFlags
, gfxFontStyle
* aStyle
, nsAtom
* aLanguage
,
2085 gfxFloat aDevToCssSize
) {
2086 nsAutoCString
keyName(aFamily
);
2087 BuildKeyNameFromFontName(keyName
);
2089 if (SharedFontList()) {
2090 nsACString
* subst
= mSubstitutions
.Get(keyName
);
2095 gfxFontFamily
* ff
= mFontSubstitutes
.GetWeak(keyName
);
2096 FontVisibility level
=
2097 aPresContext
? aPresContext
->GetFontVisibility() : FontVisibility::User
;
2098 if (ff
&& IsVisibleToCSS(*ff
, level
)) {
2099 aOutput
->AppendElement(FamilyAndGeneric(ff
, aGeneric
));
2104 if (mNonExistingFonts
.Contains(keyName
)) {
2108 return gfxPlatformFontList::FindAndAddFamiliesLocked(
2109 aPresContext
, aGeneric
, keyName
, aOutput
, aFlags
, aStyle
, aLanguage
,
2113 void gfxDWriteFontList::AddSizeOfExcludingThis(MallocSizeOf aMallocSizeOf
,
2114 FontListSizes
* aSizes
) const {
2115 gfxPlatformFontList::AddSizeOfExcludingThis(aMallocSizeOf
, aSizes
);
2117 AutoLock
lock(mLock
);
2119 // We are a singleton, so include the font loader singleton's memory.
2120 MOZ_ASSERT(static_cast<const gfxPlatformFontList
*>(this) ==
2121 gfxPlatformFontList::PlatformFontList());
2122 gfxDWriteFontFileLoader
* loader
= static_cast<gfxDWriteFontFileLoader
*>(
2123 gfxDWriteFontFileLoader::Instance());
2124 aSizes
->mLoaderSize
+= loader
->SizeOfIncludingThis(aMallocSizeOf
);
2126 aSizes
->mFontListSize
+=
2127 SizeOfFontFamilyTableExcludingThis(mFontSubstitutes
, aMallocSizeOf
);
2129 aSizes
->mFontListSize
+=
2130 mNonExistingFonts
.ShallowSizeOfExcludingThis(aMallocSizeOf
);
2131 for (uint32_t i
= 0; i
< mNonExistingFonts
.Length(); ++i
) {
2132 aSizes
->mFontListSize
+=
2133 mNonExistingFonts
[i
].SizeOfExcludingThisIfUnshared(aMallocSizeOf
);
2137 void gfxDWriteFontList::AddSizeOfIncludingThis(MallocSizeOf aMallocSizeOf
,
2138 FontListSizes
* aSizes
) const {
2139 aSizes
->mFontListSize
+= aMallocSizeOf(this);
2140 AddSizeOfExcludingThis(aMallocSizeOf
, aSizes
);
2143 static HRESULT
GetFamilyName(IDWriteFont
* aFont
, nsCString
& aFamilyName
) {
2145 RefPtr
<IDWriteFontFamily
> family
;
2147 // clean out previous value
2148 aFamilyName
.Truncate();
2150 hr
= aFont
->GetFontFamily(getter_AddRefs(family
));
2155 RefPtr
<IDWriteLocalizedStrings
> familyNames
;
2157 hr
= family
->GetFamilyNames(getter_AddRefs(familyNames
));
2162 if (!GetEnglishOrFirstName(aFamilyName
, familyNames
)) {
2169 // bug 705594 - the method below doesn't actually do any "drawing", it's only
2170 // used to invoke the DirectWrite layout engine to determine the fallback font
2171 // for a given character.
2173 IFACEMETHODIMP
DWriteFontFallbackRenderer::DrawGlyphRun(
2174 void* clientDrawingContext
, FLOAT baselineOriginX
, FLOAT baselineOriginY
,
2175 DWRITE_MEASURING_MODE measuringMode
, DWRITE_GLYPH_RUN
const* glyphRun
,
2176 DWRITE_GLYPH_RUN_DESCRIPTION
const* glyphRunDescription
,
2177 IUnknown
* clientDrawingEffect
) {
2178 if (!mSystemFonts
) {
2184 RefPtr
<IDWriteFont
> font
;
2185 hr
= mSystemFonts
->GetFontFromFontFace(glyphRun
->fontFace
,
2186 getter_AddRefs(font
));
2191 // copy the family name
2192 hr
= GetFamilyName(font
, mFamilyName
);
2197 // Arial is used as the default fallback font
2198 // so if it matches ==> no font found
2199 if (mFamilyName
.EqualsLiteral("Arial")) {
2200 mFamilyName
.Truncate();
2206 gfxFontEntry
* gfxDWriteFontList::PlatformGlobalFontFallback(
2207 nsPresContext
* aPresContext
, const uint32_t aCh
, Script aRunScript
,
2208 const gfxFontStyle
* aMatchStyle
, FontFamily
& aMatchedFamily
) {
2211 RefPtr
<IDWriteFactory
> dwFactory
= Factory::GetDWriteFactory();
2216 // initialize fallback renderer
2217 if (!mFallbackRenderer
) {
2218 mFallbackRenderer
= new DWriteFontFallbackRenderer(dwFactory
);
2220 if (!mFallbackRenderer
->IsValid()) {
2224 // initialize text format
2225 if (!mFallbackFormat
) {
2226 hr
= dwFactory
->CreateTextFormat(
2227 L
"Arial", nullptr, DWRITE_FONT_WEIGHT_REGULAR
, DWRITE_FONT_STYLE_NORMAL
,
2228 DWRITE_FONT_STRETCH_NORMAL
, 72.0f
, L
"en-us",
2229 getter_AddRefs(mFallbackFormat
));
2235 // set up string with fallback character
2239 if (IS_IN_BMP(aCh
)) {
2240 str
[0] = static_cast<wchar_t>(aCh
);
2244 str
[0] = static_cast<wchar_t>(H_SURROGATE(aCh
));
2245 str
[1] = static_cast<wchar_t>(L_SURROGATE(aCh
));
2251 RefPtr
<IDWriteTextLayout
> fallbackLayout
;
2253 hr
= dwFactory
->CreateTextLayout(str
, strLen
, mFallbackFormat
, 200.0f
, 200.0f
,
2254 getter_AddRefs(fallbackLayout
));
2259 // call the draw method to invoke the DirectWrite layout functions
2260 // which determine the fallback font
2262 hr
= fallbackLayout
->Draw(nullptr, mFallbackRenderer
, 50.0f
, 50.0f
);
2267 MOZ_SEH_EXCEPT(EXCEPTION_EXECUTE_HANDLER
) {
2268 gfxCriticalNote
<< "Exception occurred during DWrite font fallback";
2273 FindFamily(aPresContext
, mFallbackRenderer
->FallbackFamilyName());
2274 if (!family
.IsNull()) {
2275 gfxFontEntry
* fontEntry
= nullptr;
2276 if (family
.mShared
) {
2278 family
.mShared
->FindFaceForStyle(SharedFontList(), *aMatchStyle
);
2280 fontEntry
= GetOrCreateFontEntry(face
, family
.mShared
);
2283 fontEntry
= family
.mUnshared
->FindFontForStyle(*aMatchStyle
);
2285 if (fontEntry
&& fontEntry
->HasCharacter(aCh
)) {
2286 aMatchedFamily
= family
;
2289 Telemetry::Accumulate(Telemetry::BAD_FALLBACK_FONT
, true);
2295 // used to load system-wide font info on off-main thread
2296 class DirectWriteFontInfo
: public FontInfoData
{
2298 DirectWriteFontInfo(bool aLoadOtherNames
, bool aLoadFaceNames
,
2299 bool aLoadCmaps
, IDWriteFontCollection
* aSystemFonts
2300 #ifdef MOZ_BUNDLED_FONTS
2302 IDWriteFontCollection
* aBundledFonts
2305 : FontInfoData(aLoadOtherNames
, aLoadFaceNames
, aLoadCmaps
),
2306 mSystemFonts(aSystemFonts
)
2307 #ifdef MOZ_BUNDLED_FONTS
2309 mBundledFonts(aBundledFonts
)
2314 virtual ~DirectWriteFontInfo() = default;
2316 // loads font data for all members of a given family
2317 virtual void LoadFontFamilyData(const nsACString
& aFamilyName
);
2320 RefPtr
<IDWriteFontCollection
> mSystemFonts
;
2321 #ifdef MOZ_BUNDLED_FONTS
2322 RefPtr
<IDWriteFontCollection
> mBundledFonts
;
2326 void DirectWriteFontInfo::LoadFontFamilyData(const nsACString
& aFamilyName
) {
2327 // lookup the family
2328 NS_ConvertUTF8toUTF16
famName(aFamilyName
);
2331 BOOL exists
= false;
2334 RefPtr
<IDWriteFontFamily
> family
;
2335 hr
= mSystemFonts
->FindFamilyName((const wchar_t*)famName
.get(), &index
,
2337 if (SUCCEEDED(hr
) && exists
) {
2338 mSystemFonts
->GetFontFamily(index
, getter_AddRefs(family
));
2344 #ifdef MOZ_BUNDLED_FONTS
2345 if (!family
&& mBundledFonts
) {
2346 hr
= mBundledFonts
->FindFamilyName((const wchar_t*)famName
.get(), &index
,
2348 if (SUCCEEDED(hr
) && exists
) {
2349 mBundledFonts
->GetFontFamily(index
, getter_AddRefs(family
));
2358 // later versions of DirectWrite support querying the fullname/psname
2359 bool loadFaceNamesUsingDirectWrite
= mLoadFaceNames
;
2361 for (uint32_t i
= 0; i
< family
->GetFontCount(); i
++) {
2363 RefPtr
<IDWriteFont
> dwFont
;
2364 hr
= family
->GetFont(i
, getter_AddRefs(dwFont
));
2366 // This should never happen.
2367 NS_WARNING("Failed to get existing font from family.");
2371 if (dwFont
->GetSimulations() != DWRITE_FONT_SIMULATIONS_NONE
) {
2372 // We don't want these in the font list; we'll apply simulations
2373 // on the fly when appropriate.
2379 // get the name of the face
2380 nsCString
fullID(aFamilyName
);
2381 nsAutoCString fontName
;
2382 hr
= GetDirectWriteFontName(dwFont
, fontName
);
2387 fullID
.Append(fontName
);
2389 FontFaceData fontData
;
2390 bool haveData
= true;
2391 RefPtr
<IDWriteFontFace
> dwFontFace
;
2393 if (mLoadFaceNames
) {
2394 // try to load using DirectWrite first
2395 if (loadFaceNamesUsingDirectWrite
) {
2397 GetDirectWriteFaceName(dwFont
, PSNAME_ID
, fontData
.mPostscriptName
);
2399 loadFaceNamesUsingDirectWrite
= false;
2401 hr
= GetDirectWriteFaceName(dwFont
, FULLNAME_ID
, fontData
.mFullName
);
2403 loadFaceNamesUsingDirectWrite
= false;
2407 // if DirectWrite read fails, load directly from name table
2408 if (!loadFaceNamesUsingDirectWrite
) {
2409 hr
= dwFont
->CreateFontFace(getter_AddRefs(dwFontFace
));
2410 if (SUCCEEDED(hr
)) {
2412 NativeEndian::swapToBigEndian(TRUETYPE_TAG('n', 'a', 'm', 'e'));
2413 const char* nameData
;
2418 hr
= dwFontFace
->TryGetFontTable(kNAME
, (const void**)&nameData
,
2419 &nameSize
, &ctx
, &exists
);
2420 if (SUCCEEDED(hr
) && nameData
&& nameSize
> 0) {
2422 gfxFontUtils::ReadCanonicalName(nameData
, nameSize
,
2423 gfxFontUtils::NAME_ID_FULL
,
2424 fontData
.mFullName
);
2425 gfxFontUtils::ReadCanonicalName(nameData
, nameSize
,
2426 gfxFontUtils::NAME_ID_POSTSCRIPT
,
2427 fontData
.mPostscriptName
);
2429 MOZ_SEH_EXCEPT(EXCEPTION_EXECUTE_HANDLER
) {
2430 gfxCriticalNote
<< "Exception occurred reading names for "
2431 << PromiseFlatCString(aFamilyName
).get();
2433 dwFontFace
->ReleaseFontTable(ctx
);
2439 !fontData
.mPostscriptName
.IsEmpty() || !fontData
.mFullName
.IsEmpty();
2441 mLoadStats
.facenames
++;
2448 hr
= dwFont
->CreateFontFace(getter_AddRefs(dwFontFace
));
2449 if (!SUCCEEDED(hr
)) {
2455 NativeEndian::swapToBigEndian(TRUETYPE_TAG('c', 'm', 'a', 'p'));
2456 const uint8_t* cmapData
;
2461 hr
= dwFontFace
->TryGetFontTable(kCMAP
, (const void**)&cmapData
,
2462 &cmapSize
, &ctx
, &exists
);
2464 if (SUCCEEDED(hr
) && exists
) {
2465 bool cmapLoaded
= false;
2466 RefPtr
<gfxCharacterMap
> charmap
= new gfxCharacterMap();
2469 if (cmapData
&& cmapSize
> 0 &&
2470 NS_SUCCEEDED(gfxFontUtils::ReadCMAP(cmapData
, cmapSize
, *charmap
,
2472 fontData
.mCharacterMap
= charmap
;
2473 fontData
.mUVSOffset
= offset
;
2478 MOZ_SEH_EXCEPT(EXCEPTION_EXECUTE_HANDLER
) {
2479 gfxCriticalNote
<< "Exception occurred reading cmaps for "
2480 << PromiseFlatCString(aFamilyName
).get();
2482 dwFontFace
->ReleaseFontTable(ctx
);
2483 haveData
= haveData
|| cmapLoaded
;
2487 // if have data, load
2489 mFontFaceData
.InsertOrUpdate(fullID
, fontData
);
2494 already_AddRefed
<FontInfoData
> gfxDWriteFontList::CreateFontInfoData() {
2495 bool loadCmaps
= !UsesSystemFallback() ||
2496 gfxPlatform::GetPlatform()->UseCmapsDuringSystemFallback();
2498 RefPtr
<DirectWriteFontInfo
> fi
= new DirectWriteFontInfo(
2499 false, NeedFullnamePostscriptNames(), loadCmaps
, mSystemFonts
2500 #ifdef MOZ_BUNDLED_FONTS
2509 gfxFontFamily
* gfxDWriteFontList::CreateFontFamily(
2510 const nsACString
& aName
, FontVisibility aVisibility
) const {
2511 return new gfxDWriteFontFamily(aName
, aVisibility
, nullptr);
2514 #ifdef MOZ_BUNDLED_FONTS
2516 # define IMPL_QI_FOR_DWRITE(_interface) \
2518 IFACEMETHOD(QueryInterface)(IID const& riid, void** ppvObject) { \
2519 if (__uuidof(_interface) == riid) { \
2520 *ppvObject = this; \
2521 } else if (__uuidof(IUnknown) == riid) { \
2522 *ppvObject = this; \
2524 *ppvObject = nullptr; \
2525 return E_NOINTERFACE; \
2531 class BundledFontFileEnumerator
: public IDWriteFontFileEnumerator
{
2532 IMPL_QI_FOR_DWRITE(IDWriteFontFileEnumerator
)
2534 NS_INLINE_DECL_REFCOUNTING(BundledFontFileEnumerator
)
2537 BundledFontFileEnumerator(IDWriteFactory
* aFactory
, nsIFile
* aFontDir
);
2539 IFACEMETHODIMP
MoveNext(BOOL
* hasCurrentFile
);
2541 IFACEMETHODIMP
GetCurrentFontFile(IDWriteFontFile
** fontFile
);
2544 BundledFontFileEnumerator() = delete;
2545 BundledFontFileEnumerator(const BundledFontFileEnumerator
&) = delete;
2546 BundledFontFileEnumerator
& operator=(const BundledFontFileEnumerator
&) =
2548 virtual ~BundledFontFileEnumerator() = default;
2550 RefPtr
<IDWriteFactory
> mFactory
;
2552 nsCOMPtr
<nsIFile
> mFontDir
;
2553 nsCOMPtr
<nsIDirectoryEnumerator
> mEntries
;
2554 nsCOMPtr
<nsISupports
> mCurrent
;
2557 BundledFontFileEnumerator::BundledFontFileEnumerator(IDWriteFactory
* aFactory
,
2559 : mFactory(aFactory
), mFontDir(aFontDir
) {
2560 mFontDir
->GetDirectoryEntries(getter_AddRefs(mEntries
));
2564 BundledFontFileEnumerator::MoveNext(BOOL
* aHasCurrentFile
) {
2565 bool hasMore
= false;
2567 if (NS_SUCCEEDED(mEntries
->HasMoreElements(&hasMore
)) && hasMore
) {
2568 if (NS_SUCCEEDED(mEntries
->GetNext(getter_AddRefs(mCurrent
)))) {
2573 *aHasCurrentFile
= hasMore
;
2578 BundledFontFileEnumerator::GetCurrentFontFile(IDWriteFontFile
** aFontFile
) {
2579 nsCOMPtr
<nsIFile
> file
= do_QueryInterface(mCurrent
);
2584 if (NS_FAILED(file
->GetPath(path
))) {
2587 return mFactory
->CreateFontFileReference((const WCHAR
*)path
.get(), nullptr,
2591 class BundledFontLoader
: public IDWriteFontCollectionLoader
{
2592 IMPL_QI_FOR_DWRITE(IDWriteFontCollectionLoader
)
2594 NS_INLINE_DECL_REFCOUNTING(BundledFontLoader
)
2597 BundledFontLoader() {}
2599 IFACEMETHODIMP
CreateEnumeratorFromKey(
2600 IDWriteFactory
* aFactory
, const void* aCollectionKey
,
2601 UINT32 aCollectionKeySize
,
2602 IDWriteFontFileEnumerator
** aFontFileEnumerator
);
2605 BundledFontLoader(const BundledFontLoader
&) = delete;
2606 BundledFontLoader
& operator=(const BundledFontLoader
&) = delete;
2607 virtual ~BundledFontLoader() = default;
2611 BundledFontLoader::CreateEnumeratorFromKey(
2612 IDWriteFactory
* aFactory
, const void* aCollectionKey
,
2613 UINT32 aCollectionKeySize
,
2614 IDWriteFontFileEnumerator
** aFontFileEnumerator
) {
2615 nsIFile
* fontDir
= *(nsIFile
**)aCollectionKey
;
2616 *aFontFileEnumerator
= new BundledFontFileEnumerator(aFactory
, fontDir
);
2617 NS_ADDREF(*aFontFileEnumerator
);
2621 already_AddRefed
<IDWriteFontCollection
>
2622 gfxDWriteFontList::CreateBundledFontsCollection(IDWriteFactory
* aFactory
) {
2623 nsCOMPtr
<nsIFile
> localDir
;
2624 nsresult rv
= NS_GetSpecialDirectory(NS_GRE_DIR
, getter_AddRefs(localDir
));
2625 if (NS_FAILED(rv
)) {
2628 if (NS_FAILED(localDir
->Append(u
"fonts"_ns
))) {
2632 if (NS_FAILED(localDir
->IsDirectory(&isDir
)) || !isDir
) {
2636 RefPtr
<BundledFontLoader
> loader
= new BundledFontLoader();
2637 if (FAILED(aFactory
->RegisterFontCollectionLoader(loader
))) {
2641 const void* key
= localDir
.get();
2642 RefPtr
<IDWriteFontCollection
> collection
;
2643 HRESULT hr
= aFactory
->CreateCustomFontCollection(loader
, &key
, sizeof(key
),
2644 getter_AddRefs(collection
));
2646 aFactory
->UnregisterFontCollectionLoader(loader
);
2651 return collection
.forget();