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/. */
5 
6 #ifndef GFX_GDIFONTLIST_H
7 #define GFX_GDIFONTLIST_H
8 
9 #include "mozilla/FontPropertyTypes.h"
10 #include "mozilla/MemoryReporting.h"
11 #include "gfxWindowsPlatform.h"
12 #include "gfxPlatformFontList.h"
13 #include "nsGkAtoms.h"
14 #include "mozilla/gfx/UnscaledFontGDI.h"
15 
16 #include <windows.h>
17 
18 class AutoDC  // get the global device context, and auto-release it on
19               // destruction
20 {
21  public:
AutoDC()22   AutoDC() { mDC = ::GetDC(nullptr); }
23 
~AutoDC()24   ~AutoDC() { ::ReleaseDC(nullptr, mDC); }
25 
GetDC()26   HDC GetDC() { return mDC; }
27 
28  private:
29   HDC mDC;
30 };
31 
32 class AutoSelectFont  // select a font into the given DC, and auto-restore
33 {
34  public:
AutoSelectFont(HDC aDC,LOGFONTW * aLogFont)35   AutoSelectFont(HDC aDC, LOGFONTW* aLogFont) : mOwnsFont(false) {
36     mFont = ::CreateFontIndirectW(aLogFont);
37     if (mFont) {
38       mOwnsFont = true;
39       mDC = aDC;
40       mOldFont = (HFONT)::SelectObject(aDC, mFont);
41     } else {
42       mOldFont = nullptr;
43     }
44   }
45 
AutoSelectFont(HDC aDC,HFONT aFont)46   AutoSelectFont(HDC aDC, HFONT aFont) : mOwnsFont(false) {
47     mDC = aDC;
48     mFont = aFont;
49     mOldFont = (HFONT)::SelectObject(aDC, aFont);
50   }
51 
~AutoSelectFont()52   ~AutoSelectFont() {
53     if (mOldFont) {
54       ::SelectObject(mDC, mOldFont);
55       if (mOwnsFont) {
56         ::DeleteObject(mFont);
57       }
58     }
59   }
60 
IsValid()61   bool IsValid() const { return mFont != nullptr; }
62 
GetFont()63   HFONT GetFont() const { return mFont; }
64 
65  private:
66   HDC mDC;
67   HFONT mFont;
68   HFONT mOldFont;
69   bool mOwnsFont;
70 };
71 
72 /**
73  * List of different types of fonts we support on Windows.
74  * These can generally be lumped in to 3 categories where we have to
75  * do special things:  Really old fonts bitmap and vector fonts (device
76  * and raster), Type 1 fonts, and TrueType/OpenType fonts.
77  *
78  * This list is sorted in order from least prefered to most prefered.
79  * We prefer Type1 fonts over OpenType fonts to avoid falling back to
80  * things like Arial (opentype) when you ask for Helvetica (type1)
81  **/
82 enum gfxWindowsFontType {
83   GFX_FONT_TYPE_UNKNOWN = 0,
84   GFX_FONT_TYPE_DEVICE,
85   GFX_FONT_TYPE_RASTER,
86   GFX_FONT_TYPE_TRUETYPE,
87   GFX_FONT_TYPE_PS_OPENTYPE,
88   GFX_FONT_TYPE_TT_OPENTYPE,
89   GFX_FONT_TYPE_TYPE1
90 };
91 
92 // A single member of a font family (i.e. a single face, such as Times Italic)
93 // represented as a LOGFONT that will resolve to the correct face.
94 // This replaces FontEntry from gfxWindowsFonts.h/cpp.
95 class GDIFontEntry final : public gfxFontEntry {
96  public:
GetLogFont()97   LPLOGFONTW GetLogFont() { return &mLogFont; }
98 
99   nsresult ReadCMAP(FontInfoData* aFontInfoData = nullptr) override;
100 
101   void FillLogFont(LOGFONTW* aLogFont, LONG aWeight, gfxFloat aSize);
102 
DetermineFontType(const NEWTEXTMETRICW & metrics,DWORD fontType)103   static gfxWindowsFontType DetermineFontType(const NEWTEXTMETRICW& metrics,
104                                               DWORD fontType) {
105     gfxWindowsFontType feType;
106     if (metrics.ntmFlags & NTM_TYPE1)
107       feType = GFX_FONT_TYPE_TYPE1;
108     else if (metrics.ntmFlags & NTM_PS_OPENTYPE)
109       feType = GFX_FONT_TYPE_PS_OPENTYPE;
110     else if (metrics.ntmFlags & NTM_TT_OPENTYPE)
111       feType = GFX_FONT_TYPE_TT_OPENTYPE;
112     else if (fontType == TRUETYPE_FONTTYPE)
113       feType = GFX_FONT_TYPE_TRUETYPE;
114     else if (fontType == RASTER_FONTTYPE)
115       feType = GFX_FONT_TYPE_RASTER;
116     else if (fontType == DEVICE_FONTTYPE)
117       feType = GFX_FONT_TYPE_DEVICE;
118     else
119       feType = GFX_FONT_TYPE_UNKNOWN;
120 
121     return feType;
122   }
123 
IsType1()124   bool IsType1() const { return (mFontType == GFX_FONT_TYPE_TYPE1); }
125 
IsTrueType()126   bool IsTrueType() const {
127     return (mFontType == GFX_FONT_TYPE_TRUETYPE ||
128             mFontType == GFX_FONT_TYPE_PS_OPENTYPE ||
129             mFontType == GFX_FONT_TYPE_TT_OPENTYPE);
130   }
131 
SupportsRange(uint8_t range)132   virtual bool SupportsRange(uint8_t range) {
133     return mUnicodeRanges.test(range);
134   }
135 
SkipDuringSystemFallback()136   virtual bool SkipDuringSystemFallback() {
137     return !HasCmapTable();  // explicitly skip non-SFNT fonts
138   }
139 
140   virtual bool TestCharacterMap(uint32_t aCh);
141 
142   virtual void AddSizeOfIncludingThis(mozilla::MallocSizeOf aMallocSizeOf,
143                                       FontListSizes* aSizes) const;
144 
145   gfxFontEntry* Clone() const override;
146 
147   // GDI backend doesn't support font variations:
HasVariations()148   bool HasVariations() override { return false; }
GetVariationAxes(nsTArray<gfxFontVariationAxis> &)149   void GetVariationAxes(nsTArray<gfxFontVariationAxis>&) override {}
GetVariationInstances(nsTArray<gfxFontVariationInstance> &)150   void GetVariationInstances(nsTArray<gfxFontVariationInstance>&) override {}
151 
152   // create a font entry for a font with a given name
153   static GDIFontEntry* CreateFontEntry(const nsACString& aName,
154                                        gfxWindowsFontType aFontType,
155                                        SlantStyleRange aStyle,
156                                        WeightRange aWeight,
157                                        StretchRange aStretch,
158                                        gfxUserFontData* aUserFontData);
159 
160   gfxWindowsFontType mFontType;
161   bool mForceGDI;
162 
163   gfxSparseBitSet mUnicodeRanges;
164 
165  protected:
166   friend class gfxGDIFont;
167 
168   GDIFontEntry(const nsACString& aFaceName, gfxWindowsFontType aFontType,
169                SlantStyleRange aStyle, WeightRange aWeight,
170                StretchRange aStretch, gfxUserFontData* aUserFontData);
171 
172   void InitLogFont(const nsACString& aName, gfxWindowsFontType aFontType);
173 
174   gfxFont* CreateFontInstance(const gfxFontStyle* aFontStyle) override;
175 
176   virtual nsresult CopyFontTable(uint32_t aTableTag,
177                                  nsTArray<uint8_t>& aBuffer) override;
178 
179   already_AddRefed<mozilla::gfx::UnscaledFontGDI> LookupUnscaledFont(
180       HFONT aFont);
181 
182   LOGFONTW mLogFont;
183 
184   mozilla::ThreadSafeWeakPtr<mozilla::gfx::UnscaledFontGDI> mUnscaledFont;
185 };
186 
187 // a single font family, referencing one or more faces
188 class GDIFontFamily final : public gfxFontFamily {
189  public:
GDIFontFamily(const nsACString & aName,FontVisibility aVisibility)190   GDIFontFamily(const nsACString& aName, FontVisibility aVisibility)
191       : gfxFontFamily(aName, aVisibility),
192         mWindowsFamily(0),
193         mWindowsPitch(0),
194         mCharset() {}
195 
196   virtual void FindStyleVariations(FontInfoData* aFontInfoData = nullptr);
197 
FilterForFontList(nsAtom * aLangGroup,const nsACString & aGeneric)198   bool FilterForFontList(nsAtom* aLangGroup,
199                          const nsACString& aGeneric) const final {
200     return !IsSymbolFontFamily() && SupportsLangGroup(aLangGroup) &&
201            MatchesGenericFamily(aGeneric);
202   }
203 
204  protected:
205   friend class gfxGDIFontList;
206 
207   // helpers for FilterForFontList
IsSymbolFontFamily()208   bool IsSymbolFontFamily() const { return mCharset.test(SYMBOL_CHARSET); }
209 
MatchesGenericFamily(const nsACString & aGeneric)210   bool MatchesGenericFamily(const nsACString& aGeneric) const {
211     if (aGeneric.IsEmpty()) {
212       return true;
213     }
214 
215     // Japanese 'Mincho' fonts do not belong to FF_MODERN even if
216     // they are fixed pitch because they have variable stroke width.
217     if (mWindowsFamily == FF_ROMAN && mWindowsPitch & FIXED_PITCH) {
218       return aGeneric.EqualsLiteral("monospace");
219     }
220 
221     // Japanese 'Gothic' fonts do not belong to FF_SWISS even if
222     // they are variable pitch because they have constant stroke width.
223     if (mWindowsFamily == FF_MODERN && mWindowsPitch & VARIABLE_PITCH) {
224       return aGeneric.EqualsLiteral("sans-serif");
225     }
226 
227     // All other fonts will be grouped correctly using family...
228     switch (mWindowsFamily) {
229       case FF_DONTCARE:
230         return false;
231       case FF_ROMAN:
232         return aGeneric.EqualsLiteral("serif");
233       case FF_SWISS:
234         return aGeneric.EqualsLiteral("sans-serif");
235       case FF_MODERN:
236         return aGeneric.EqualsLiteral("monospace");
237       case FF_SCRIPT:
238         return aGeneric.EqualsLiteral("cursive");
239       case FF_DECORATIVE:
240         return aGeneric.EqualsLiteral("fantasy");
241     }
242 
243     return false;
244   }
245 
SupportsLangGroup(nsAtom * aLangGroup)246   bool SupportsLangGroup(nsAtom* aLangGroup) const {
247     if (!aLangGroup || aLangGroup == nsGkAtoms::Unicode) {
248       return true;
249     }
250 
251     int16_t bit = -1;
252 
253     /* map our langgroup names in to Windows charset bits */
254     if (aLangGroup == nsGkAtoms::x_western) {
255       bit = ANSI_CHARSET;
256     } else if (aLangGroup == nsGkAtoms::Japanese) {
257       bit = SHIFTJIS_CHARSET;
258     } else if (aLangGroup == nsGkAtoms::ko) {
259       bit = HANGEUL_CHARSET;
260     } else if (aLangGroup == nsGkAtoms::zh_cn) {
261       bit = GB2312_CHARSET;
262     } else if (aLangGroup == nsGkAtoms::zh_tw) {
263       bit = CHINESEBIG5_CHARSET;
264     } else if (aLangGroup == nsGkAtoms::el) {
265       bit = GREEK_CHARSET;
266     } else if (aLangGroup == nsGkAtoms::he) {
267       bit = HEBREW_CHARSET;
268     } else if (aLangGroup == nsGkAtoms::ar) {
269       bit = ARABIC_CHARSET;
270     } else if (aLangGroup == nsGkAtoms::x_cyrillic) {
271       bit = RUSSIAN_CHARSET;
272     } else if (aLangGroup == nsGkAtoms::th) {
273       bit = THAI_CHARSET;
274     }
275 
276     if (bit != -1) {
277       return mCharset.test(bit);
278     }
279 
280     return false;
281   }
282 
283   uint8_t mWindowsFamily;
284   uint8_t mWindowsPitch;
285 
286   gfxSparseBitSet mCharset;
287 
288  private:
289   static int CALLBACK FamilyAddStylesProc(const ENUMLOGFONTEXW* lpelfe,
290                                           const NEWTEXTMETRICEXW* nmetrics,
291                                           DWORD fontType, LPARAM data);
292 };
293 
294 class gfxGDIFontList final : public gfxPlatformFontList {
295  public:
PlatformFontList()296   static gfxGDIFontList* PlatformFontList() {
297     return static_cast<gfxGDIFontList*>(
298         gfxPlatformFontList::PlatformFontList());
299   }
300 
301   // initialize font lists
302   virtual nsresult InitFontListForPlatform() override;
303 
304   gfxFontFamily* CreateFontFamily(const nsACString& aName,
305                                   FontVisibility aVisibility) const override;
306 
307   bool FindAndAddFamilies(mozilla::StyleGenericFontFamily aGeneric,
308                           const nsACString& aFamily,
309                           nsTArray<FamilyAndGeneric>* aOutput,
310                           FindFamiliesFlags aFlags,
311                           gfxFontStyle* aStyle = nullptr,
312                           nsAtom* aLanguage = nullptr,
313                           gfxFloat aDevToCssSize = 1.0) override;
314 
315   virtual gfxFontEntry* LookupLocalFont(const nsACString& aFontName,
316                                         WeightRange aWeightForEntry,
317                                         StretchRange aStretchForEntry,
318                                         SlantStyleRange aStyleForEntry);
319 
320   virtual gfxFontEntry* MakePlatformFont(const nsACString& aFontName,
321                                          WeightRange aWeightForEntry,
322                                          StretchRange aStretchForEntry,
323                                          SlantStyleRange aStyleForEntry,
324                                          const uint8_t* aFontData,
325                                          uint32_t aLength);
326 
327   virtual void AddSizeOfExcludingThis(mozilla::MallocSizeOf aMallocSizeOf,
328                                       FontListSizes* aSizes) const;
329   virtual void AddSizeOfIncludingThis(mozilla::MallocSizeOf aMallocSizeOf,
330                                       FontListSizes* aSizes) const;
331 
332  protected:
333   FontFamily GetDefaultFontForPlatform(const gfxFontStyle* aStyle,
334                                        nsAtom* aLanguage = nullptr) override;
335 
336  private:
337   friend class gfxWindowsPlatform;
338 
339   gfxGDIFontList();
340 
341   nsresult GetFontSubstitutes();
342 
343   static int CALLBACK EnumFontFamExProc(ENUMLOGFONTEXW* lpelfe,
344                                         NEWTEXTMETRICEXW* lpntme,
345                                         DWORD fontType, LPARAM lParam);
346 
347   virtual already_AddRefed<FontInfoData> CreateFontInfoData();
348 
349 #ifdef MOZ_BUNDLED_FONTS
350   void ActivateBundledFonts();
351 #endif
352 
353   FontFamilyTable mFontSubstitutes;
354   nsTArray<nsCString> mNonExistingFonts;
355 };
356 
357 #endif /* GFX_GDIFONTLIST_H */
358