1 /* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 4 -*-
2  * This Source Code Form is subject to the terms of the Mozilla Public
3  * License, v. 2.0. If a copy of the MPL was not distributed with this
4  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
5 
6 #ifndef GFX_DWRITEFONTLIST_H
7 #define GFX_DWRITEFONTLIST_H
8 
9 #include "mozilla/MemoryReporting.h"
10 #include "gfxDWriteCommon.h"
11 
12 #include "gfxFont.h"
13 #include "gfxUserFontSet.h"
14 #include "cairo-win32.h"
15 
16 #include "gfxPlatformFontList.h"
17 #include "gfxPlatform.h"
18 #include <algorithm>
19 
20 
21 /**
22  * gfxDWriteFontFamily is a class that describes one of the fonts on the
23  * users system.  It holds each gfxDWriteFontEntry (maps more directly to
24  * a font face) which holds font type, charset info and character map info.
25  */
26 class gfxDWriteFontEntry;
27 
28 /**
29  * \brief Class representing directwrite font family.
30  */
31 class gfxDWriteFontFamily : public gfxFontFamily
32 {
33 public:
34     /**
35      * Constructs a new DWriteFont Family.
36      *
37      * \param aName Name identifying the family
38      * \param aFamily IDWriteFontFamily object representing the directwrite
39      * family object.
40      */
gfxDWriteFontFamily(const nsAString & aName,IDWriteFontFamily * aFamily)41     gfxDWriteFontFamily(const nsAString& aName,
42                         IDWriteFontFamily *aFamily)
43       : gfxFontFamily(aName), mDWFamily(aFamily), mForceGDIClassic(false) {}
44     virtual ~gfxDWriteFontFamily();
45 
46     void FindStyleVariations(FontInfoData *aFontInfoData = nullptr) final;
47 
48     void LocalizedName(nsAString& aLocalizedName) final;
49 
50     void ReadFaceNames(gfxPlatformFontList *aPlatformFontList,
51                        bool aNeedFullnamePostscriptNames,
52                        FontInfoData *aFontInfoData = nullptr) final;
53 
SetForceGDIClassic(bool aForce)54     void SetForceGDIClassic(bool aForce) { mForceGDIClassic = aForce; }
55 
56     void AddSizeOfExcludingThis(mozilla::MallocSizeOf aMallocSizeOf,
57                                 FontListSizes* aSizes) const final;
58     void AddSizeOfIncludingThis(mozilla::MallocSizeOf aMallocSizeOf,
59                                 FontListSizes* aSizes) const final;
60 
61 protected:
62     /** This font family's directwrite fontfamily object */
63     RefPtr<IDWriteFontFamily> mDWFamily;
64     bool mForceGDIClassic;
65 };
66 
67 /**
68  * \brief Class representing DirectWrite FontEntry (a unique font style/family)
69  */
70 class gfxDWriteFontEntry : public gfxFontEntry
71 {
72 public:
73     /**
74      * Constructs a font entry.
75      *
76      * \param aFaceName The name of the corresponding font face.
77      * \param aFont DirectWrite font object
78      */
gfxDWriteFontEntry(const nsAString & aFaceName,IDWriteFont * aFont)79     gfxDWriteFontEntry(const nsAString& aFaceName,
80                               IDWriteFont *aFont)
81       : gfxFontEntry(aFaceName), mFont(aFont), mFontFile(nullptr),
82         mForceGDIClassic(false)
83     {
84         DWRITE_FONT_STYLE dwriteStyle = aFont->GetStyle();
85         mStyle = (dwriteStyle == DWRITE_FONT_STYLE_ITALIC ?
86                   NS_FONT_STYLE_ITALIC :
87                   (dwriteStyle == DWRITE_FONT_STYLE_OBLIQUE ?
88                    NS_FONT_STYLE_OBLIQUE : NS_FONT_STYLE_NORMAL));
89         mStretch = FontStretchFromDWriteStretch(aFont->GetStretch());
90         uint16_t weight = NS_ROUNDUP(aFont->GetWeight() - 50, 100);
91 
92         weight = std::max<uint16_t>(100, weight);
93         weight = std::min<uint16_t>(900, weight);
94         mWeight = weight;
95 
96         mIsCJK = UNINITIALIZED_VALUE;
97     }
98 
99     /**
100      * Constructs a font entry using a font. But with custom font values.
101      * This is used for creating correct font entries for @font-face with local
102      * font source.
103      *
104      * \param aFaceName The name of the corresponding font face.
105      * \param aFont DirectWrite font object
106      * \param aWeight Weight of the font
107      * \param aStretch Stretch of the font
108      * \param aStyle italic or oblique of font
109      */
gfxDWriteFontEntry(const nsAString & aFaceName,IDWriteFont * aFont,uint16_t aWeight,int16_t aStretch,uint8_t aStyle)110     gfxDWriteFontEntry(const nsAString& aFaceName,
111                               IDWriteFont *aFont,
112                               uint16_t aWeight,
113                               int16_t aStretch,
114                               uint8_t aStyle)
115       : gfxFontEntry(aFaceName), mFont(aFont), mFontFile(nullptr),
116         mForceGDIClassic(false)
117     {
118         mWeight = aWeight;
119         mStretch = aStretch;
120         mStyle = aStyle;
121         mIsLocalUserFont = true;
122         mIsCJK = UNINITIALIZED_VALUE;
123     }
124 
125     /**
126      * Constructs a font entry using a font file.
127      *
128      * \param aFaceName The name of the corresponding font face.
129      * \param aFontFile DirectWrite fontfile object
130      * \param aFontFileStream DirectWrite fontfile stream object
131      * \param aWeight Weight of the font
132      * \param aStretch Stretch of the font
133      * \param aStyle italic or oblique of font
134      */
gfxDWriteFontEntry(const nsAString & aFaceName,IDWriteFontFile * aFontFile,IDWriteFontFileStream * aFontFileStream,uint16_t aWeight,int16_t aStretch,uint8_t aStyle)135     gfxDWriteFontEntry(const nsAString& aFaceName,
136                               IDWriteFontFile *aFontFile,
137                               IDWriteFontFileStream *aFontFileStream,
138                               uint16_t aWeight,
139                               int16_t aStretch,
140                               uint8_t aStyle)
141       : gfxFontEntry(aFaceName), mFont(nullptr), mFontFile(aFontFile),
142         mFontFileStream(aFontFileStream), mForceGDIClassic(false)
143     {
144         mWeight = aWeight;
145         mStretch = aStretch;
146         mStyle = aStyle;
147         mIsDataUserFont = true;
148         mIsCJK = UNINITIALIZED_VALUE;
149     }
150 
151     virtual ~gfxDWriteFontEntry();
152 
153     virtual bool IsSymbolFont();
154 
155     virtual hb_blob_t* GetFontTable(uint32_t aTableTag) override;
156 
157     nsresult ReadCMAP(FontInfoData *aFontInfoData = nullptr);
158 
159     bool IsCJKFont();
160 
SetForceGDIClassic(bool aForce)161     void SetForceGDIClassic(bool aForce) { mForceGDIClassic = aForce; }
GetForceGDIClassic()162     bool GetForceGDIClassic() { return mForceGDIClassic; }
163 
164     virtual void AddSizeOfExcludingThis(mozilla::MallocSizeOf aMallocSizeOf,
165                                         FontListSizes* aSizes) const;
166     virtual void AddSizeOfIncludingThis(mozilla::MallocSizeOf aMallocSizeOf,
167                                         FontListSizes* aSizes) const;
168 
169 protected:
170     friend class gfxDWriteFont;
171     friend class gfxDWriteFontList;
172 
173     virtual nsresult CopyFontTable(uint32_t aTableTag,
174                                    nsTArray<uint8_t>& aBuffer) override;
175 
176     virtual gfxFont *CreateFontInstance(const gfxFontStyle *aFontStyle,
177                                         bool aNeedsBold);
178 
179     nsresult CreateFontFace(
180         IDWriteFontFace **aFontFace,
181         DWRITE_FONT_SIMULATIONS aSimulations = DWRITE_FONT_SIMULATIONS_NONE);
182 
183     static bool InitLogFont(IDWriteFont *aFont, LOGFONTW *aLogFont);
184 
185     /**
186      * A fontentry only needs to have either of these. If it has both only
187      * the IDWriteFont will be used.
188      */
189     RefPtr<IDWriteFont> mFont;
190     RefPtr<IDWriteFontFile> mFontFile;
191 
192     // For custom fonts, we hold a reference to the IDWriteFontFileStream for
193     // for the IDWriteFontFile, so that the data is available.
194     RefPtr<IDWriteFontFileStream> mFontFileStream;
195 
196     // font face corresponding to the mFont/mFontFile *without* any DWrite
197     // style simulations applied
198     RefPtr<IDWriteFontFace> mFontFace;
199 
200     DWRITE_FONT_FACE_TYPE mFaceType;
201 
202     int8_t mIsCJK;
203     bool mForceGDIClassic;
204 };
205 
206 // custom text renderer used to determine the fallback font for a given char
207 class DWriteFontFallbackRenderer final : public IDWriteTextRenderer
208 {
209 public:
DWriteFontFallbackRenderer(IDWriteFactory * aFactory)210     DWriteFontFallbackRenderer(IDWriteFactory *aFactory)
211         : mRefCount(0)
212     {
213         HRESULT hr = S_OK;
214 
215         hr = aFactory->GetSystemFontCollection(getter_AddRefs(mSystemFonts));
216         NS_ASSERTION(SUCCEEDED(hr), "GetSystemFontCollection failed!");
217     }
218 
~DWriteFontFallbackRenderer()219     ~DWriteFontFallbackRenderer()
220     {}
221 
222     // IDWriteTextRenderer methods
223     IFACEMETHOD(DrawGlyphRun)(
224         void* clientDrawingContext,
225         FLOAT baselineOriginX,
226         FLOAT baselineOriginY,
227         DWRITE_MEASURING_MODE measuringMode,
228         DWRITE_GLYPH_RUN const* glyphRun,
229         DWRITE_GLYPH_RUN_DESCRIPTION const* glyphRunDescription,
230         IUnknown* clientDrawingEffect
231         );
232 
IFACEMETHOD(DrawUnderline)233     IFACEMETHOD(DrawUnderline)(
234         void* clientDrawingContext,
235         FLOAT baselineOriginX,
236         FLOAT baselineOriginY,
237         DWRITE_UNDERLINE const* underline,
238         IUnknown* clientDrawingEffect
239         )
240     {
241         return E_NOTIMPL;
242     }
243 
244 
IFACEMETHOD(DrawStrikethrough)245     IFACEMETHOD(DrawStrikethrough)(
246         void* clientDrawingContext,
247         FLOAT baselineOriginX,
248         FLOAT baselineOriginY,
249         DWRITE_STRIKETHROUGH const* strikethrough,
250         IUnknown* clientDrawingEffect
251         )
252     {
253         return E_NOTIMPL;
254     }
255 
256 
IFACEMETHOD(DrawInlineObject)257     IFACEMETHOD(DrawInlineObject)(
258         void* clientDrawingContext,
259         FLOAT originX,
260         FLOAT originY,
261         IDWriteInlineObject* inlineObject,
262         BOOL isSideways,
263         BOOL isRightToLeft,
264         IUnknown* clientDrawingEffect
265         )
266     {
267         return E_NOTIMPL;
268     }
269 
270     // IDWritePixelSnapping methods
271 
IFACEMETHOD(IsPixelSnappingDisabled)272     IFACEMETHOD(IsPixelSnappingDisabled)(
273         void* clientDrawingContext,
274         BOOL* isDisabled
275         )
276     {
277         *isDisabled = FALSE;
278         return S_OK;
279     }
280 
IFACEMETHOD(GetCurrentTransform)281     IFACEMETHOD(GetCurrentTransform)(
282         void* clientDrawingContext,
283         DWRITE_MATRIX* transform
284         )
285     {
286         const DWRITE_MATRIX ident = {1.0, 0.0, 0.0, 1.0, 0.0, 0.0};
287         *transform = ident;
288         return S_OK;
289     }
290 
IFACEMETHOD(GetPixelsPerDip)291     IFACEMETHOD(GetPixelsPerDip)(
292         void* clientDrawingContext,
293         FLOAT* pixelsPerDip
294         )
295     {
296         *pixelsPerDip = 1.0f;
297         return S_OK;
298     }
299 
300     // IUnknown methods
301 
IFACEMETHOD_(unsigned long,AddRef)302     IFACEMETHOD_(unsigned long, AddRef) ()
303     {
304         return InterlockedIncrement(&mRefCount);
305     }
306 
IFACEMETHOD_(unsigned long,Release)307     IFACEMETHOD_(unsigned long,  Release) ()
308     {
309         unsigned long newCount = InterlockedDecrement(&mRefCount);
310         if (newCount == 0)
311         {
312             delete this;
313             return 0;
314         }
315 
316         return newCount;
317     }
318 
IFACEMETHOD(QueryInterface)319     IFACEMETHOD(QueryInterface) (IID const& riid, void** ppvObject)
320     {
321         if (__uuidof(IDWriteTextRenderer) == riid) {
322             *ppvObject = this;
323         } else if (__uuidof(IDWritePixelSnapping) == riid) {
324             *ppvObject = this;
325         } else if (__uuidof(IUnknown) == riid) {
326             *ppvObject = this;
327         } else {
328             *ppvObject = nullptr;
329             return E_FAIL;
330         }
331 
332         this->AddRef();
333         return S_OK;
334     }
335 
FallbackFamilyName()336     const nsString& FallbackFamilyName() { return mFamilyName; }
337 
338 protected:
339     long mRefCount;
340     RefPtr<IDWriteFontCollection> mSystemFonts;
341     nsString mFamilyName;
342 };
343 
344 
345 
346 class gfxDWriteFontList : public gfxPlatformFontList {
347 public:
348     gfxDWriteFontList();
349 
PlatformFontList()350     static gfxDWriteFontList* PlatformFontList() {
351         return static_cast<gfxDWriteFontList*>(sPlatformFontList);
352     }
353 
354     // initialize font lists
355     virtual nsresult InitFontListForPlatform() override;
356 
357     virtual gfxFontEntry* LookupLocalFont(const nsAString& aFontName,
358                                           uint16_t aWeight,
359                                           int16_t aStretch,
360                                           uint8_t aStyle);
361 
362     virtual gfxFontEntry* MakePlatformFont(const nsAString& aFontName,
363                                            uint16_t aWeight,
364                                            int16_t aStretch,
365                                            uint8_t aStyle,
366                                            const uint8_t* aFontData,
367                                            uint32_t aLength);
368 
369     bool GetStandardFamilyName(const nsAString& aFontName,
370                                  nsAString& aFamilyName);
371 
GetGDIInterop()372     IDWriteGdiInterop *GetGDIInterop() { return mGDIInterop; }
UseGDIFontTableAccess()373     bool UseGDIFontTableAccess() { return mGDIFontTableAccess; }
374 
375     bool FindAndAddFamilies(const nsAString& aFamily,
376                             nsTArray<gfxFontFamily*>* aOutput,
377                             gfxFontStyle* aStyle = nullptr,
378                             gfxFloat aDevToCssSize = 1.0) override;
379 
GetForceGDIClassicMaxFontSize()380     gfxFloat GetForceGDIClassicMaxFontSize() { return mForceGDIClassicMaxFontSize; }
381 
382     virtual void AddSizeOfExcludingThis(mozilla::MallocSizeOf aMallocSizeOf,
383                                         FontListSizes* aSizes) const;
384     virtual void AddSizeOfIncludingThis(mozilla::MallocSizeOf aMallocSizeOf,
385                                         FontListSizes* aSizes) const;
386 
387 protected:
388     virtual gfxFontFamily*
389     GetDefaultFontForPlatform(const gfxFontStyle* aStyle) override;
390 
391     // attempt to use platform-specific fallback for the given character,
392     // return null if no usable result found
393     gfxFontEntry*
394     PlatformGlobalFontFallback(const uint32_t aCh,
395                                Script aRunScript,
396                                const gfxFontStyle* aMatchStyle,
397                                gfxFontFamily** aMatchedFamily) override;
398 
399 private:
400     friend class gfxDWriteFontFamily;
401 
402     nsresult GetFontSubstitutes();
403 
404     void GetDirectWriteSubstitutes();
405 
UsesSystemFallback()406     virtual bool UsesSystemFallback() { return true; }
407 
408     void GetFontsFromCollection(IDWriteFontCollection* aCollection);
409 
410 #ifdef MOZ_BUNDLED_FONTS
411     already_AddRefed<IDWriteFontCollection>
412     CreateBundledFontsCollection(IDWriteFactory* aFactory);
413 #endif
414 
415     /**
416      * Fonts listed in the registry as substitutes but for which no actual
417      * font family is found.
418      */
419     nsTArray<nsString> mNonExistingFonts;
420 
421     /**
422      * Table of font substitutes, we grab this from the registry to get
423      * alternative font names.
424      */
425     FontFamilyTable mFontSubstitutes;
426 
427     virtual already_AddRefed<FontInfoData> CreateFontInfoData();
428 
429     gfxFloat mForceGDIClassicMaxFontSize;
430 
431     // whether to use GDI font table access routines
432     bool mGDIFontTableAccess;
433     RefPtr<IDWriteGdiInterop> mGDIInterop;
434 
435     RefPtr<DWriteFontFallbackRenderer> mFallbackRenderer;
436     RefPtr<IDWriteTextFormat>    mFallbackFormat;
437 
438     RefPtr<IDWriteFontCollection> mSystemFonts;
439 #ifdef MOZ_BUNDLED_FONTS
440     RefPtr<IDWriteFontCollection> mBundledFonts;
441 #endif
442 };
443 
444 
445 #endif /* GFX_DWRITEFONTLIST_H */
446