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_DWRITEFONTLIST_H
7 #define GFX_DWRITEFONTLIST_H
8 
9 #include "mozilla/FontPropertyTypes.h"
10 #include "mozilla/MathAlgorithms.h"
11 #include "mozilla/MemoryReporting.h"
12 #include "gfxDWriteCommon.h"
13 #include "dwrite_3.h"
14 
15 // Currently, we build with WINVER=0x601 (Win7), which means newer
16 // declarations in dwrite_3.h will not be visible. Also, we don't
17 // yet have the Fall Creators Update SDK available on build machines,
18 // so even with updated WINVER, some of the interfaces we need would
19 // not be present.
20 // To work around this, until the build environment is updated,
21 // we #include an extra header that contains copies of the relevant
22 // classes/interfaces we need.
23 #if !defined(__MINGW32__) && WINVER < 0x0A00
24 #  include "mozilla/gfx/dw-extra.h"
25 #endif
26 
27 #include "gfxFont.h"
28 #include "gfxUserFontSet.h"
29 #include "cairo-win32.h"
30 
31 #include "gfxPlatformFontList.h"
32 #include "gfxPlatform.h"
33 #include <algorithm>
34 
35 #include "mozilla/gfx/UnscaledFontDWrite.h"
36 
37 /**
38  * \brief Class representing directwrite font family.
39  *
40  * gfxDWriteFontFamily is a class that describes one of the font families on
41  * the user's system.  It holds each gfxDWriteFontEntry (maps more directly to
42  * a font face) which holds font type, charset info and character map info.
43  */
44 class gfxDWriteFontFamily final : public gfxFontFamily {
45  public:
46   typedef mozilla::FontStretch FontStretch;
47   typedef mozilla::FontSlantStyle FontSlantStyle;
48   typedef mozilla::FontWeight FontWeight;
49 
50   /**
51    * Constructs a new DWriteFont Family.
52    *
53    * \param aName Name identifying the family
54    * \param aFamily IDWriteFontFamily object representing the directwrite
55    * family object.
56    */
57   gfxDWriteFontFamily(const nsACString& aName, FontVisibility aVisibility,
58                       IDWriteFontFamily* aFamily,
59                       bool aIsSystemFontFamily = false)
gfxFontFamily(aName,aVisibility)60       : gfxFontFamily(aName, aVisibility),
61         mDWFamily(aFamily),
62         mIsSystemFontFamily(aIsSystemFontFamily),
63         mForceGDIClassic(false) {}
64   virtual ~gfxDWriteFontFamily();
65 
66   void FindStyleVariations(FontInfoData* aFontInfoData = nullptr) final;
67 
68   void LocalizedName(nsACString& aLocalizedName) final;
69 
70   void ReadFaceNames(gfxPlatformFontList* aPlatformFontList,
71                      bool aNeedFullnamePostscriptNames,
72                      FontInfoData* aFontInfoData = nullptr) final;
73 
SetForceGDIClassic(bool aForce)74   void SetForceGDIClassic(bool aForce) { mForceGDIClassic = aForce; }
75 
76   void AddSizeOfExcludingThis(mozilla::MallocSizeOf aMallocSizeOf,
77                               FontListSizes* aSizes) const final;
78   void AddSizeOfIncludingThis(mozilla::MallocSizeOf aMallocSizeOf,
79                               FontListSizes* aSizes) const final;
80 
FilterForFontList(nsAtom * aLangGroup,const nsACString & aGeneric)81   bool FilterForFontList(nsAtom* aLangGroup,
82                          const nsACString& aGeneric) const final {
83     return !IsSymbolFontFamily();
84   }
85 
86  protected:
87   // helper for FilterForFontList
88   bool IsSymbolFontFamily() const;
89 
90   /** This font family's directwrite fontfamily object */
91   RefPtr<IDWriteFontFamily> mDWFamily;
92   bool mIsSystemFontFamily;
93   bool mForceGDIClassic;
94 };
95 
96 /**
97  * \brief Class representing DirectWrite FontEntry (a unique font style/family)
98  */
99 class gfxDWriteFontEntry final : public gfxFontEntry {
100  public:
101   /**
102    * Constructs a font entry.
103    *
104    * \param aFaceName The name of the corresponding font face.
105    * \param aFont DirectWrite font object
106    */
107   gfxDWriteFontEntry(const nsACString& aFaceName, IDWriteFont* aFont,
108                      bool aIsSystemFont = false)
gfxFontEntry(aFaceName)109       : gfxFontEntry(aFaceName),
110         mFont(aFont),
111         mFontFile(nullptr),
112         mIsSystemFont(aIsSystemFont),
113         mForceGDIClassic(false),
114         mHasVariations(false),
115         mHasVariationsInitialized(false) {
116     DWRITE_FONT_STYLE dwriteStyle = aFont->GetStyle();
117     FontSlantStyle style = (dwriteStyle == DWRITE_FONT_STYLE_ITALIC
118                                 ? FontSlantStyle::Italic()
119                                 : (dwriteStyle == DWRITE_FONT_STYLE_OBLIQUE
120                                        ? FontSlantStyle::Oblique()
121                                        : FontSlantStyle::Normal()));
122     mStyleRange = SlantStyleRange(style);
123 
124     mStretchRange =
125         StretchRange(FontStretchFromDWriteStretch(aFont->GetStretch()));
126 
127     int weight = NS_ROUNDUP(aFont->GetWeight() - 50, 100);
128     weight = mozilla::Clamp(weight, 100, 900);
129     mWeightRange = WeightRange(FontWeight(weight));
130 
131     mIsCJK = UNINITIALIZED_VALUE;
132   }
133 
134   /**
135    * Constructs a font entry using a font. But with custom font values.
136    * This is used for creating correct font entries for @font-face with local
137    * font source.
138    *
139    * \param aFaceName The name of the corresponding font face.
140    * \param aFont DirectWrite font object
141    * \param aWeight Weight of the font
142    * \param aStretch Stretch of the font
143    * \param aStyle italic or oblique of font
144    */
gfxDWriteFontEntry(const nsACString & aFaceName,IDWriteFont * aFont,WeightRange aWeight,StretchRange aStretch,SlantStyleRange aStyle)145   gfxDWriteFontEntry(const nsACString& aFaceName, IDWriteFont* aFont,
146                      WeightRange aWeight, StretchRange aStretch,
147                      SlantStyleRange aStyle)
148       : gfxFontEntry(aFaceName),
149         mFont(aFont),
150         mFontFile(nullptr),
151         mIsSystemFont(false),
152         mForceGDIClassic(false),
153         mHasVariations(false),
154         mHasVariationsInitialized(false) {
155     mWeightRange = aWeight;
156     mStretchRange = aStretch;
157     mStyleRange = aStyle;
158     mIsLocalUserFont = true;
159     mIsCJK = UNINITIALIZED_VALUE;
160   }
161 
162   /**
163    * Constructs a font entry using a font file.
164    *
165    * \param aFaceName The name of the corresponding font face.
166    * \param aFontFile DirectWrite fontfile object
167    * \param aFontFileStream DirectWrite fontfile stream object
168    * \param aWeight Weight of the font
169    * \param aStretch Stretch of the font
170    * \param aStyle italic or oblique of font
171    */
gfxDWriteFontEntry(const nsACString & aFaceName,IDWriteFontFile * aFontFile,IDWriteFontFileStream * aFontFileStream,WeightRange aWeight,StretchRange aStretch,SlantStyleRange aStyle)172   gfxDWriteFontEntry(const nsACString& aFaceName, IDWriteFontFile* aFontFile,
173                      IDWriteFontFileStream* aFontFileStream,
174                      WeightRange aWeight, StretchRange aStretch,
175                      SlantStyleRange aStyle)
176       : gfxFontEntry(aFaceName),
177         mFont(nullptr),
178         mFontFile(aFontFile),
179         mFontFileStream(aFontFileStream),
180         mIsSystemFont(false),
181         mForceGDIClassic(false),
182         mHasVariations(false),
183         mHasVariationsInitialized(false) {
184     mWeightRange = aWeight;
185     mStretchRange = aStretch;
186     mStyleRange = aStyle;
187     mIsDataUserFont = true;
188     mIsCJK = UNINITIALIZED_VALUE;
189   }
190 
191   gfxFontEntry* Clone() const override;
192 
193   virtual ~gfxDWriteFontEntry();
194 
195   hb_blob_t* GetFontTable(uint32_t aTableTag) override;
196 
197   nsresult ReadCMAP(FontInfoData* aFontInfoData = nullptr);
198 
199   bool IsCJKFont();
200 
201   bool HasVariations() override;
202   void GetVariationAxes(nsTArray<gfxFontVariationAxis>& aAxes) override;
203   void GetVariationInstances(
204       nsTArray<gfxFontVariationInstance>& aInstances) override;
205 
SetForceGDIClassic(bool aForce)206   void SetForceGDIClassic(bool aForce) { mForceGDIClassic = aForce; }
GetForceGDIClassic()207   bool GetForceGDIClassic() { return mForceGDIClassic; }
208 
209   virtual void AddSizeOfExcludingThis(mozilla::MallocSizeOf aMallocSizeOf,
210                                       FontListSizes* aSizes) const;
211   virtual void AddSizeOfIncludingThis(mozilla::MallocSizeOf aMallocSizeOf,
212                                       FontListSizes* aSizes) const;
213 
214  protected:
215   friend class gfxDWriteFont;
216   friend class gfxDWriteFontList;
217   friend class gfxDWriteFontFamily;
218 
219   virtual nsresult CopyFontTable(uint32_t aTableTag,
220                                  nsTArray<uint8_t>& aBuffer) override;
221 
222   virtual gfxFont* CreateFontInstance(const gfxFontStyle* aFontStyle);
223 
224   nsresult CreateFontFace(
225       IDWriteFontFace** aFontFace, const gfxFontStyle* aFontStyle = nullptr,
226       DWRITE_FONT_SIMULATIONS aSimulations = DWRITE_FONT_SIMULATIONS_NONE,
227       const nsTArray<gfxFontVariation>* aVariations = nullptr);
228 
229   static bool InitLogFont(IDWriteFont* aFont, LOGFONTW* aLogFont);
230 
231   /**
232    * A fontentry only needs to have either of these. If it has both only
233    * the IDWriteFont will be used.
234    */
235   RefPtr<IDWriteFont> mFont;
236   RefPtr<IDWriteFontFile> mFontFile;
237 
238   // For custom fonts, we hold a reference to the IDWriteFontFileStream for
239   // for the IDWriteFontFile, so that the data is available.
240   RefPtr<IDWriteFontFileStream> mFontFileStream;
241 
242   // font face corresponding to the mFont/mFontFile *without* any DWrite
243   // style simulations applied
244   RefPtr<IDWriteFontFace> mFontFace;
245   // Extended fontface interface if supported, else null
246   RefPtr<IDWriteFontFace5> mFontFace5;
247 
248   DWRITE_FONT_FACE_TYPE mFaceType;
249 
250   int8_t mIsCJK;
251   bool mIsSystemFont;
252   bool mForceGDIClassic;
253   bool mHasVariations;
254   bool mHasVariationsInitialized;
255 
256   // Set to true only if the font belongs to a "simple" family where the
257   // faces can be reliably identified via a GDI LOGFONT structure.
258   bool mMayUseGDIAccess = false;
259 
260   mozilla::ThreadSafeWeakPtr<mozilla::gfx::UnscaledFontDWrite> mUnscaledFont;
261   mozilla::ThreadSafeWeakPtr<mozilla::gfx::UnscaledFontDWrite>
262       mUnscaledFontBold;
263 };
264 
265 // custom text renderer used to determine the fallback font for a given char
266 class DWriteFontFallbackRenderer final : public IDWriteTextRenderer {
267  public:
DWriteFontFallbackRenderer(IDWriteFactory * aFactory)268   explicit DWriteFontFallbackRenderer(IDWriteFactory* aFactory) : mRefCount(0) {
269     HRESULT hr = S_OK;
270 
271     hr = aFactory->GetSystemFontCollection(getter_AddRefs(mSystemFonts));
272     NS_ASSERTION(SUCCEEDED(hr), "GetSystemFontCollection failed!");
273   }
274 
~DWriteFontFallbackRenderer()275   ~DWriteFontFallbackRenderer() {}
276 
277   // If we don't have an mSystemFonts pointer, this renderer is unusable.
IsValid()278   bool IsValid() const { return mSystemFonts; }
279 
280   // IDWriteTextRenderer methods
281   IFACEMETHOD(DrawGlyphRun)
282   (void* clientDrawingContext, FLOAT baselineOriginX, FLOAT baselineOriginY,
283    DWRITE_MEASURING_MODE measuringMode, DWRITE_GLYPH_RUN const* glyphRun,
284    DWRITE_GLYPH_RUN_DESCRIPTION const* glyphRunDescription,
285    IUnknown* clientDrawingEffect);
286 
IFACEMETHOD(DrawUnderline)287   IFACEMETHOD(DrawUnderline)
288   (void* clientDrawingContext, FLOAT baselineOriginX, FLOAT baselineOriginY,
289    DWRITE_UNDERLINE const* underline, IUnknown* clientDrawingEffect) {
290     return E_NOTIMPL;
291   }
292 
IFACEMETHOD(DrawStrikethrough)293   IFACEMETHOD(DrawStrikethrough)
294   (void* clientDrawingContext, FLOAT baselineOriginX, FLOAT baselineOriginY,
295    DWRITE_STRIKETHROUGH const* strikethrough, IUnknown* clientDrawingEffect) {
296     return E_NOTIMPL;
297   }
298 
IFACEMETHOD(DrawInlineObject)299   IFACEMETHOD(DrawInlineObject)
300   (void* clientDrawingContext, FLOAT originX, FLOAT originY,
301    IDWriteInlineObject* inlineObject, BOOL isSideways, BOOL isRightToLeft,
302    IUnknown* clientDrawingEffect) {
303     return E_NOTIMPL;
304   }
305 
306   // IDWritePixelSnapping methods
307 
IFACEMETHOD(IsPixelSnappingDisabled)308   IFACEMETHOD(IsPixelSnappingDisabled)
309   (void* clientDrawingContext, BOOL* isDisabled) {
310     *isDisabled = FALSE;
311     return S_OK;
312   }
313 
IFACEMETHOD(GetCurrentTransform)314   IFACEMETHOD(GetCurrentTransform)
315   (void* clientDrawingContext, DWRITE_MATRIX* transform) {
316     const DWRITE_MATRIX ident = {1.0, 0.0, 0.0, 1.0, 0.0, 0.0};
317     *transform = ident;
318     return S_OK;
319   }
320 
IFACEMETHOD(GetPixelsPerDip)321   IFACEMETHOD(GetPixelsPerDip)
322   (void* clientDrawingContext, FLOAT* pixelsPerDip) {
323     *pixelsPerDip = 1.0f;
324     return S_OK;
325   }
326 
327   // IUnknown methods
328 
IFACEMETHOD_(unsigned long,AddRef)329   IFACEMETHOD_(unsigned long, AddRef)() {
330     return InterlockedIncrement(&mRefCount);
331   }
332 
IFACEMETHOD_(unsigned long,Release)333   IFACEMETHOD_(unsigned long, Release)() {
334     unsigned long newCount = InterlockedDecrement(&mRefCount);
335     if (newCount == 0) {
336       delete this;
337       return 0;
338     }
339 
340     return newCount;
341   }
342 
IFACEMETHOD(QueryInterface)343   IFACEMETHOD(QueryInterface)(IID const& riid, void** ppvObject) {
344     if (__uuidof(IDWriteTextRenderer) == riid) {
345       *ppvObject = this;
346     } else if (__uuidof(IDWritePixelSnapping) == riid) {
347       *ppvObject = this;
348     } else if (__uuidof(IUnknown) == riid) {
349       *ppvObject = this;
350     } else {
351       *ppvObject = nullptr;
352       return E_FAIL;
353     }
354 
355     this->AddRef();
356     return S_OK;
357   }
358 
FallbackFamilyName()359   const nsCString& FallbackFamilyName() { return mFamilyName; }
360 
361  protected:
362   long mRefCount;
363   RefPtr<IDWriteFontCollection> mSystemFonts;
364   nsCString mFamilyName;
365 };
366 
367 class gfxDWriteFontList final : public gfxPlatformFontList {
368  public:
369   gfxDWriteFontList();
370 
PlatformFontList()371   static gfxDWriteFontList* PlatformFontList() {
372     return static_cast<gfxDWriteFontList*>(
373         gfxPlatformFontList::PlatformFontList());
374   }
375 
376   // initialize font lists
377   nsresult InitFontListForPlatform() override;
378   void InitSharedFontListForPlatform() override;
379 
380   FontVisibility GetVisibilityForFamily(const nsACString& aName) const;
381 
382   gfxFontFamily* CreateFontFamily(const nsACString& aName,
383                                   FontVisibility aVisibility) const override;
384 
385   gfxFontEntry* CreateFontEntry(
386       mozilla::fontlist::Face* aFace,
387       const mozilla::fontlist::Family* aFamily) override;
388 
389   void ReadFaceNamesForFamily(mozilla::fontlist::Family* aFamily,
390                               bool aNeedFullnamePostscriptNames) override;
391 
392   bool ReadFaceNames(mozilla::fontlist::Family* aFamily,
393                      mozilla::fontlist::Face* aFace, nsCString& aPSName,
394                      nsCString& aFullName) override;
395 
396   void GetFacesInitDataForFamily(
397       const mozilla::fontlist::Family* aFamily,
398       nsTArray<mozilla::fontlist::Face::InitData>& aFaces,
399       bool aLoadCmaps) const override;
400 
401   gfxFontEntry* LookupLocalFont(const nsACString& aFontName,
402                                 WeightRange aWeightForEntry,
403                                 StretchRange aStretchForEntry,
404                                 SlantStyleRange aStyleForEntry) override;
405 
406   gfxFontEntry* MakePlatformFont(const nsACString& aFontName,
407                                  WeightRange aWeightForEntry,
408                                  StretchRange aStretchForEntry,
409                                  SlantStyleRange aStyleForEntry,
410                                  const uint8_t* aFontData,
411                                  uint32_t aLength) override;
412 
GetGDIInterop()413   IDWriteGdiInterop* GetGDIInterop() { return mGDIInterop; }
414   bool UseGDIFontTableAccess() const;
415 
416   bool FindAndAddFamilies(mozilla::StyleGenericFontFamily aGeneric,
417                           const nsACString& aFamily,
418                           nsTArray<FamilyAndGeneric>* aOutput,
419                           FindFamiliesFlags aFlags,
420                           gfxFontStyle* aStyle = nullptr,
421                           nsAtom* aLanguage = nullptr,
422                           gfxFloat aDevToCssSize = 1.0) override;
423 
GetForceGDIClassicMaxFontSize()424   gfxFloat GetForceGDIClassicMaxFontSize() {
425     return mForceGDIClassicMaxFontSize;
426   }
427 
428   virtual void AddSizeOfExcludingThis(mozilla::MallocSizeOf aMallocSizeOf,
429                                       FontListSizes* aSizes) const;
430   virtual void AddSizeOfIncludingThis(mozilla::MallocSizeOf aMallocSizeOf,
431                                       FontListSizes* aSizes) const;
432 
433  protected:
434   FontFamily GetDefaultFontForPlatform(const gfxFontStyle* aStyle,
435                                        nsAtom* aLanguage = nullptr) override;
436 
437   // attempt to use platform-specific fallback for the given character,
438   // return null if no usable result found
439   gfxFontEntry* PlatformGlobalFontFallback(const uint32_t aCh,
440                                            Script aRunScript,
441                                            const gfxFontStyle* aMatchStyle,
442                                            FontFamily& aMatchedFamily) override;
443 
444  private:
445   friend class gfxDWriteFontFamily;
446 
447   nsresult GetFontSubstitutes();
448 
449   void GetDirectWriteSubstitutes();
450 
UsesSystemFallback()451   virtual bool UsesSystemFallback() { return true; }
452 
453   void GetFontsFromCollection(IDWriteFontCollection* aCollection);
454 
455   void AppendFamiliesFromCollection(
456       IDWriteFontCollection* aCollection,
457       nsTArray<mozilla::fontlist::Family::InitData>& aFamilies,
458       const nsTArray<nsCString>* aForceClassicFams = nullptr);
459 
460 #ifdef MOZ_BUNDLED_FONTS
461   already_AddRefed<IDWriteFontCollection> CreateBundledFontsCollection(
462       IDWriteFactory* aFactory);
463 #endif
464 
465   /**
466    * Fonts listed in the registry as substitutes but for which no actual
467    * font family is found.
468    */
469   nsTArray<nsCString> mNonExistingFonts;
470 
471   /**
472    * Table of font substitutes, we grab this from the registry to get
473    * alternative font names.
474    */
475   FontFamilyTable mFontSubstitutes;
476   nsClassHashtable<nsCStringHashKey, nsCString> mSubstitutions;
477 
478   virtual already_AddRefed<FontInfoData> CreateFontInfoData();
479 
480   gfxFloat mForceGDIClassicMaxFontSize;
481 
482   // whether to use GDI font table access routines
483   bool mGDIFontTableAccess;
484   RefPtr<IDWriteGdiInterop> mGDIInterop;
485 
486   RefPtr<DWriteFontFallbackRenderer> mFallbackRenderer;
487   RefPtr<IDWriteTextFormat> mFallbackFormat;
488 
489   RefPtr<IDWriteFontCollection> mSystemFonts;
490 #ifdef MOZ_BUNDLED_FONTS
491   RefPtr<IDWriteFontCollection> mBundledFonts;
492 #endif
493 };
494 
495 #endif /* GFX_DWRITEFONTLIST_H */
496