xref: /aosp_15_r20/external/skia/src/ports/SkFontMgr_win_dw.cpp (revision c8dee2aa9b3f27cf6c858bd81872bdeb2c07ed17)
1 /*
2  * Copyright 2014 Google Inc.
3  *
4  * Use of this source code is governed by a BSD-style license that can be
5  * found in the LICENSE file.
6  */
7 #include "src/utils/win/SkDWriteNTDDI_VERSION.h"
8 
9 #include "include/core/SkTypes.h"
10 #if defined(SK_BUILD_FOR_WIN)
11 
12 #include "include/core/SkFontMgr.h"
13 #include "include/core/SkStream.h"
14 #include "include/core/SkTypeface.h"
15 #include "include/core/SkTypes.h"
16 #include "include/private/base/SkMutex.h"
17 #include "include/private/base/SkTPin.h"
18 #include "src/base/SkEndian.h"
19 #include "src/base/SkUTF.h"
20 #include "src/core/SkFontDescriptor.h"
21 #include "src/core/SkTypefaceCache.h"
22 #include "src/ports/SkTypeface_win_dw.h"
23 #include "src/utils/win/SkDWrite.h"
24 #include "src/utils/win/SkDWriteFontFileStream.h"
25 #include "src/utils/win/SkHRESULT.h"
26 #include "src/utils/win/SkObjBase.h"
27 #include "src/utils/win/SkTScopedComPtr.h"
28 
29 #include <dwrite.h>
30 #include <dwrite_2.h>
31 #include <dwrite_3.h>
32 
33 using namespace skia_private;
34 
35 namespace {
36 
37 // Korean fonts Gulim, Dotum, Batang, Gungsuh have bitmap strikes that get
38 // artifically emboldened by Windows without antialiasing. Korean users prefer
39 // these over the synthetic boldening performed by Skia. So let's make an
40 // exception for fonts with bitmap strikes and allow passing through Windows
41 // simulations for those, until Skia provides more control over simulations in
42 // font matching, see https://crbug.com/1258378
HasBitmapStrikes(const SkTScopedComPtr<IDWriteFont> & font)43 bool HasBitmapStrikes(const SkTScopedComPtr<IDWriteFont>& font) {
44   SkTScopedComPtr<IDWriteFontFace> fontFace;
45   HRB(font->CreateFontFace(&fontFace));
46 
47   AutoDWriteTable ebdtTable(fontFace.get(),
48                             SkEndian_SwapBE32(SkSetFourByteTag('E', 'B', 'D', 'T')));
49   return ebdtTable.fExists;
50 }
51 
52 // Iterate calls to GetFirstMatchingFont incrementally removing bold or italic
53 // styling that can trigger the simulations. Implementing it this way gets us a
54 // IDWriteFont that can be used as before and has the correct information on its
55 // own style. Stripping simulations from IDWriteFontFace is possible via
56 // IDWriteFontList1, IDWriteFontFaceReference and CreateFontFace, but this way
57 // we won't have a matching IDWriteFont which is still used in get_style().
FirstMatchingFontWithoutSimulations(const SkTScopedComPtr<IDWriteFontFamily> & family,DWriteStyle dwStyle,SkTScopedComPtr<IDWriteFont> & font)58 HRESULT FirstMatchingFontWithoutSimulations(const SkTScopedComPtr<IDWriteFontFamily>& family,
59                                             DWriteStyle dwStyle,
60                                             SkTScopedComPtr<IDWriteFont>& font) {
61     bool noSimulations = false;
62     while (!noSimulations) {
63         SkTScopedComPtr<IDWriteFont> searchFont;
64         HR(family->GetFirstMatchingFont(
65                 dwStyle.fWeight, dwStyle.fWidth, dwStyle.fSlant, &searchFont));
66         DWRITE_FONT_SIMULATIONS simulations = searchFont->GetSimulations();
67         // If we still get simulations even though we're not asking for bold or
68         // italic, we can't help it and exit the loop.
69 
70 #ifdef SK_WIN_FONTMGR_NO_SIMULATIONS
71         noSimulations = simulations == DWRITE_FONT_SIMULATIONS_NONE ||
72                         (dwStyle.fWeight == DWRITE_FONT_WEIGHT_REGULAR &&
73                          dwStyle.fSlant == DWRITE_FONT_STYLE_NORMAL) ||
74                         HasBitmapStrikes(searchFont);
75 #else
76         noSimulations = true;
77 #endif
78         if (noSimulations) {
79             font = std::move(searchFont);
80             break;
81         }
82         if (simulations & DWRITE_FONT_SIMULATIONS_BOLD) {
83             dwStyle.fWeight = DWRITE_FONT_WEIGHT_REGULAR;
84             continue;
85         }
86         if (simulations & DWRITE_FONT_SIMULATIONS_OBLIQUE) {
87             dwStyle.fSlant = DWRITE_FONT_STYLE_NORMAL;
88             continue;
89         }
90     }
91     return S_OK;
92 }
93 }
94 
95 ////////////////////////////////////////////////////////////////////////////////
96 
97 class SkFontMgr_DirectWrite : public SkFontMgr {
98 public:
99     /** localeNameLength and defaultFamilyNameLength must include the null terminator. */
SkFontMgr_DirectWrite(IDWriteFactory * factory,IDWriteFontCollection * fontCollection,IDWriteFontFallback * fallback,const WCHAR * localeName,int localeNameLength,const WCHAR * defaultFamilyName,int defaultFamilyNameLength)100     SkFontMgr_DirectWrite(IDWriteFactory* factory, IDWriteFontCollection* fontCollection,
101                           IDWriteFontFallback* fallback,
102                           const WCHAR* localeName, int localeNameLength,
103                           const WCHAR* defaultFamilyName, int defaultFamilyNameLength)
104         : fFactory(SkRefComPtr(factory))
105         , fFontFallback(SkSafeRefComPtr(fallback))
106         , fFontCollection(SkRefComPtr(fontCollection))
107         , fLocaleName(localeNameLength)
108         , fDefaultFamilyName(defaultFamilyNameLength)
109     {
110         memcpy(fLocaleName.get(), localeName, localeNameLength * sizeof(WCHAR));
111         memcpy(fDefaultFamilyName.get(), defaultFamilyName, defaultFamilyNameLength*sizeof(WCHAR));
112     }
113 
114 protected:
115     int onCountFamilies() const override;
116     void onGetFamilyName(int index, SkString* familyName) const override;
117     sk_sp<SkFontStyleSet> onCreateStyleSet(int index) const override;
118     sk_sp<SkFontStyleSet> onMatchFamily(const char familyName[]) const override;
119     sk_sp<SkTypeface> onMatchFamilyStyle(const char familyName[],
120                                          const SkFontStyle& fontstyle) const override;
121     sk_sp<SkTypeface> onMatchFamilyStyleCharacter(const char familyName[], const SkFontStyle&,
122                                                   const char* bcp47[], int bcp47Count,
123                                                   SkUnichar character) const override;
124     sk_sp<SkTypeface> onMakeFromStreamIndex(std::unique_ptr<SkStreamAsset>, int ttcIndex) const override;
125     sk_sp<SkTypeface> onMakeFromStreamArgs(std::unique_ptr<SkStreamAsset>, const SkFontArguments&) const override;
126     sk_sp<SkTypeface> onMakeFromData(sk_sp<SkData>, int ttcIndex) const override;
127     sk_sp<SkTypeface> onMakeFromFile(const char path[], int ttcIndex) const override;
128     sk_sp<SkTypeface> onLegacyMakeTypeface(const char familyName[], SkFontStyle) const override;
129 
130 private:
131     HRESULT getByFamilyName(const WCHAR familyName[], IDWriteFontFamily** fontFamily) const;
132     sk_sp<SkTypeface> fallback(const WCHAR* dwFamilyName, DWriteStyle,
133                                const WCHAR* dwBcp47, UINT32 character) const;
134     sk_sp<SkTypeface> layoutFallback(const WCHAR* dwFamilyName, DWriteStyle,
135                                      const WCHAR* dwBcp47, UINT32 character) const;
136 
137     /** Creates a typeface using a typeface cache. */
138     sk_sp<SkTypeface> makeTypefaceFromDWriteFont(IDWriteFontFace* fontFace,
139                                                  IDWriteFont* font,
140                                                  IDWriteFontFamily* fontFamily) const;
141 
142     SkTScopedComPtr<IDWriteFactory> fFactory;
143     SkTScopedComPtr<IDWriteFontFallback> fFontFallback;
144     SkTScopedComPtr<IDWriteFontCollection> fFontCollection;
145     SkSMallocWCHAR fLocaleName;
146     SkSMallocWCHAR fDefaultFamilyName;
147     mutable SkMutex fTFCacheMutex;
148     mutable SkTypefaceCache fTFCache;
149 
150     friend class SkFontStyleSet_DirectWrite;
151     friend class FontFallbackRenderer;
152 };
153 
154 class SkFontStyleSet_DirectWrite : public SkFontStyleSet {
155 public:
SkFontStyleSet_DirectWrite(const SkFontMgr_DirectWrite * fontMgr,IDWriteFontFamily * fontFamily)156     SkFontStyleSet_DirectWrite(const SkFontMgr_DirectWrite* fontMgr,
157                                IDWriteFontFamily* fontFamily)
158         : fFontMgr(SkRef(fontMgr))
159         , fFontFamily(SkRefComPtr(fontFamily))
160     { }
161 
162     int count() override;
163     void getStyle(int index, SkFontStyle* fs, SkString* styleName) override;
164     sk_sp<SkTypeface> createTypeface(int index) override;
165     sk_sp<SkTypeface> matchStyle(const SkFontStyle& pattern) override;
166 
167 private:
168     sk_sp<const SkFontMgr_DirectWrite> fFontMgr;
169     SkTScopedComPtr<IDWriteFontFamily> fFontFamily;
170 };
171 
are_same(IUnknown * a,IUnknown * b,bool & same)172 static HRESULT are_same(IUnknown* a, IUnknown* b, bool& same) {
173     SkTScopedComPtr<IUnknown> iunkA;
174     HRM(a->QueryInterface(&iunkA), "Failed to QI<IUnknown> for a.");
175 
176     SkTScopedComPtr<IUnknown> iunkB;
177     HRM(b->QueryInterface(&iunkB), "Failed to QI<IUnknown> for b.");
178 
179     same = (iunkA.get() == iunkB.get());
180     return S_OK;
181 }
182 
183 struct ProtoDWriteTypeface {
184     IDWriteFontFace* fDWriteFontFace;
185     IDWriteFont* fDWriteFont;
186     IDWriteFontFamily* fDWriteFontFamily;
187 };
188 
FindByDWriteFont(SkTypeface * cached,void * ctx)189 static bool FindByDWriteFont(SkTypeface* cached, void* ctx) {
190     DWriteFontTypeface* cshFace = reinterpret_cast<DWriteFontTypeface*>(cached);
191     ProtoDWriteTypeface* ctxFace = reinterpret_cast<ProtoDWriteTypeface*>(ctx);
192 
193     // IDWriteFontFace5 introduced both Equals and HasVariations
194     SkTScopedComPtr<IDWriteFontFace5> cshFontFace5;
195     SkTScopedComPtr<IDWriteFontFace5> ctxFontFace5;
196     cshFace->fDWriteFontFace->QueryInterface(&cshFontFace5);
197     ctxFace->fDWriteFontFace->QueryInterface(&ctxFontFace5);
198     if (cshFontFace5 && ctxFontFace5) {
199         return cshFontFace5->Equals(ctxFontFace5.get());
200     }
201 
202     bool same;
203 
204     //Check to see if the two fonts are identical.
205     HRB(are_same(cshFace->fDWriteFont.get(), ctxFace->fDWriteFont, same));
206     if (same) {
207         return true;
208     }
209 
210     HRB(are_same(cshFace->fDWriteFontFace.get(), ctxFace->fDWriteFontFace, same));
211     if (same) {
212         return true;
213     }
214 
215     //Check if the two fonts share the same loader and have the same key.
216     UINT32 cshNumFiles;
217     UINT32 ctxNumFiles;
218     HRB(cshFace->fDWriteFontFace->GetFiles(&cshNumFiles, nullptr));
219     HRB(ctxFace->fDWriteFontFace->GetFiles(&ctxNumFiles, nullptr));
220     if (cshNumFiles != ctxNumFiles) {
221         return false;
222     }
223 
224     SkTScopedComPtr<IDWriteFontFile> cshFontFile;
225     SkTScopedComPtr<IDWriteFontFile> ctxFontFile;
226     HRB(cshFace->fDWriteFontFace->GetFiles(&cshNumFiles, &cshFontFile));
227     HRB(ctxFace->fDWriteFontFace->GetFiles(&ctxNumFiles, &ctxFontFile));
228 
229     //for (each file) { //we currently only admit fonts from one file.
230     SkTScopedComPtr<IDWriteFontFileLoader> cshFontFileLoader;
231     SkTScopedComPtr<IDWriteFontFileLoader> ctxFontFileLoader;
232     HRB(cshFontFile->GetLoader(&cshFontFileLoader));
233     HRB(ctxFontFile->GetLoader(&ctxFontFileLoader));
234     HRB(are_same(cshFontFileLoader.get(), ctxFontFileLoader.get(), same));
235     if (!same) {
236         return false;
237     }
238     //}
239 
240     const void* cshRefKey;
241     UINT32 cshRefKeySize;
242     const void* ctxRefKey;
243     UINT32 ctxRefKeySize;
244     HRB(cshFontFile->GetReferenceKey(&cshRefKey, &cshRefKeySize));
245     HRB(ctxFontFile->GetReferenceKey(&ctxRefKey, &ctxRefKeySize));
246     if (cshRefKeySize != ctxRefKeySize) {
247         return false;
248     }
249     if (0 != memcmp(cshRefKey, ctxRefKey, ctxRefKeySize)) {
250         return false;
251     }
252 
253     //TODO: better means than comparing name strings?
254     //NOTE: .ttc and fake bold/italic will end up here.
255     SkTScopedComPtr<IDWriteLocalizedStrings> cshFamilyNames;
256     SkTScopedComPtr<IDWriteLocalizedStrings> cshFaceNames;
257     HRB(cshFace->fDWriteFontFamily->GetFamilyNames(&cshFamilyNames));
258     HRB(cshFace->fDWriteFont->GetFaceNames(&cshFaceNames));
259     UINT32 cshFamilyNameLength;
260     UINT32 cshFaceNameLength;
261     HRB(cshFamilyNames->GetStringLength(0, &cshFamilyNameLength));
262     HRB(cshFaceNames->GetStringLength(0, &cshFaceNameLength));
263 
264     SkTScopedComPtr<IDWriteLocalizedStrings> ctxFamilyNames;
265     SkTScopedComPtr<IDWriteLocalizedStrings> ctxFaceNames;
266     HRB(ctxFace->fDWriteFontFamily->GetFamilyNames(&ctxFamilyNames));
267     HRB(ctxFace->fDWriteFont->GetFaceNames(&ctxFaceNames));
268     UINT32 ctxFamilyNameLength;
269     UINT32 ctxFaceNameLength;
270     HRB(ctxFamilyNames->GetStringLength(0, &ctxFamilyNameLength));
271     HRB(ctxFaceNames->GetStringLength(0, &ctxFaceNameLength));
272 
273     if (cshFamilyNameLength != ctxFamilyNameLength ||
274         cshFaceNameLength != ctxFaceNameLength)
275     {
276         return false;
277     }
278 
279     SkSMallocWCHAR cshFamilyName(cshFamilyNameLength+1);
280     SkSMallocWCHAR cshFaceName(cshFaceNameLength+1);
281     HRB(cshFamilyNames->GetString(0, cshFamilyName.get(), cshFamilyNameLength+1));
282     HRB(cshFaceNames->GetString(0, cshFaceName.get(), cshFaceNameLength+1));
283 
284     SkSMallocWCHAR ctxFamilyName(ctxFamilyNameLength+1);
285     SkSMallocWCHAR ctxFaceName(ctxFaceNameLength+1);
286     HRB(ctxFamilyNames->GetString(0, ctxFamilyName.get(), ctxFamilyNameLength+1));
287     HRB(ctxFaceNames->GetString(0, ctxFaceName.get(), ctxFaceNameLength+1));
288 
289     return wcscmp(cshFamilyName.get(), ctxFamilyName.get()) == 0 &&
290            wcscmp(cshFaceName.get(), ctxFaceName.get()) == 0;
291 }
292 
makeTypefaceFromDWriteFont(IDWriteFontFace * fontFace,IDWriteFont * font,IDWriteFontFamily * fontFamily) const293 sk_sp<SkTypeface> SkFontMgr_DirectWrite::makeTypefaceFromDWriteFont(
294         IDWriteFontFace* fontFace,
295         IDWriteFont* font,
296         IDWriteFontFamily* fontFamily) const {
297     SkAutoMutexExclusive ama(fTFCacheMutex);
298     ProtoDWriteTypeface spec = { fontFace, font, fontFamily };
299     sk_sp<SkTypeface> face = fTFCache.findByProcAndRef(FindByDWriteFont, &spec);
300     if (nullptr == face) {
301         face = DWriteFontTypeface::Make(fFactory.get(), fontFace, font, fontFamily, nullptr,
302                                         SkFontArguments::Palette{0, nullptr, 0});
303         if (face) {
304             fTFCache.add(face);
305         }
306     }
307     return face;
308 }
309 
onCountFamilies() const310 int SkFontMgr_DirectWrite::onCountFamilies() const {
311     return fFontCollection->GetFontFamilyCount();
312 }
313 
onGetFamilyName(int index,SkString * familyName) const314 void SkFontMgr_DirectWrite::onGetFamilyName(int index, SkString* familyName) const {
315     SkTScopedComPtr<IDWriteFontFamily> fontFamily;
316     HRVM(fFontCollection->GetFontFamily(index, &fontFamily), "Could not get requested family.");
317 
318     SkTScopedComPtr<IDWriteLocalizedStrings> familyNames;
319     HRVM(fontFamily->GetFamilyNames(&familyNames), "Could not get family names.");
320 
321     sk_get_locale_string(familyNames.get(), fLocaleName.get(), familyName);
322 }
323 
onCreateStyleSet(int index) const324 sk_sp<SkFontStyleSet> SkFontMgr_DirectWrite::onCreateStyleSet(int index) const {
325     SkTScopedComPtr<IDWriteFontFamily> fontFamily;
326     HRNM(fFontCollection->GetFontFamily(index, &fontFamily), "Could not get requested family.");
327 
328     return sk_sp<SkFontStyleSet>(new SkFontStyleSet_DirectWrite(this, fontFamily.get()));
329 }
330 
onMatchFamily(const char familyName[]) const331 sk_sp<SkFontStyleSet> SkFontMgr_DirectWrite::onMatchFamily(const char familyName[]) const {
332     if (!familyName) {
333         return nullptr;
334     }
335 
336     SkSMallocWCHAR dwFamilyName;
337     HRN(sk_cstring_to_wchar(familyName, &dwFamilyName));
338 
339     UINT32 index;
340     BOOL exists;
341     HRNM(fFontCollection->FindFamilyName(dwFamilyName.get(), &index, &exists),
342             "Failed while finding family by name.");
343     if (!exists) {
344         return nullptr;
345     }
346 
347     return this->onCreateStyleSet(index);
348 }
349 
onMatchFamilyStyle(const char familyName[],const SkFontStyle & fontstyle) const350 sk_sp<SkTypeface> SkFontMgr_DirectWrite::onMatchFamilyStyle(const char familyName[],
351                                                             const SkFontStyle& fontstyle) const {
352     sk_sp<SkFontStyleSet> sset(this->matchFamily(familyName));
353     return sset->matchStyle(fontstyle);
354 }
355 
356 class FontFallbackRenderer : public IDWriteTextRenderer {
357 public:
FontFallbackRenderer(const SkFontMgr_DirectWrite * outer,UINT32 character)358     FontFallbackRenderer(const SkFontMgr_DirectWrite* outer, UINT32 character)
359         : fRefCount(1), fOuter(SkSafeRef(outer)), fCharacter(character), fResolvedTypeface(nullptr) {
360     }
361 
362     // IUnknown methods
QueryInterface(IID const & riid,void ** ppvObject)363     SK_STDMETHODIMP QueryInterface(IID const& riid, void** ppvObject) override {
364         if (__uuidof(IUnknown) == riid ||
365             __uuidof(IDWritePixelSnapping) == riid ||
366             __uuidof(IDWriteTextRenderer) == riid)
367         {
368             *ppvObject = this;
369             this->AddRef();
370             return S_OK;
371         }
372         *ppvObject = nullptr;
373         return E_FAIL;
374     }
375 
AddRef()376     SK_STDMETHODIMP_(ULONG) AddRef() override {
377         return InterlockedIncrement(&fRefCount);
378     }
379 
Release()380     SK_STDMETHODIMP_(ULONG) Release() override {
381         ULONG newCount = InterlockedDecrement(&fRefCount);
382         if (0 == newCount) {
383             delete this;
384         }
385         return newCount;
386     }
387 
388     // IDWriteTextRenderer methods
DrawGlyphRun(void * clientDrawingContext,FLOAT baselineOriginX,FLOAT baselineOriginY,DWRITE_MEASURING_MODE measuringMode,DWRITE_GLYPH_RUN const * glyphRun,DWRITE_GLYPH_RUN_DESCRIPTION const * glyphRunDescription,IUnknown * clientDrawingEffect)389     SK_STDMETHODIMP DrawGlyphRun(
390         void* clientDrawingContext,
391         FLOAT baselineOriginX,
392         FLOAT baselineOriginY,
393         DWRITE_MEASURING_MODE measuringMode,
394         DWRITE_GLYPH_RUN const* glyphRun,
395         DWRITE_GLYPH_RUN_DESCRIPTION const* glyphRunDescription,
396         IUnknown* clientDrawingEffect) override
397     {
398         if (!glyphRun->fontFace) {
399             HRM(E_INVALIDARG, "Glyph run without font face.");
400         }
401 
402         SkTScopedComPtr<IDWriteFont> font;
403         HRM(fOuter->fFontCollection->GetFontFromFontFace(glyphRun->fontFace, &font),
404             "Could not get font from font face.");
405 
406         // It is possible that the font passed does not actually have the requested character,
407         // due to no font being found and getting the fallback font.
408         // Check that the font actually contains the requested character.
409         BOOL exists;
410         HRM(font->HasCharacter(fCharacter, &exists), "Could not find character.");
411 
412         if (exists) {
413             SkTScopedComPtr<IDWriteFontFamily> fontFamily;
414             HRM(font->GetFontFamily(&fontFamily), "Could not get family.");
415             fResolvedTypeface = fOuter->makeTypefaceFromDWriteFont(glyphRun->fontFace,
416                                                                    font.get(),
417                                                                    fontFamily.get());
418             fHasSimulations = (font->GetSimulations() != DWRITE_FONT_SIMULATIONS_NONE) &&
419                               !HasBitmapStrikes(font);
420         }
421 
422         return S_OK;
423     }
424 
DrawUnderline(void * clientDrawingContext,FLOAT baselineOriginX,FLOAT baselineOriginY,DWRITE_UNDERLINE const * underline,IUnknown * clientDrawingEffect)425     SK_STDMETHODIMP DrawUnderline(
426         void* clientDrawingContext,
427         FLOAT baselineOriginX,
428         FLOAT baselineOriginY,
429         DWRITE_UNDERLINE const* underline,
430         IUnknown* clientDrawingEffect) override
431     { return E_NOTIMPL; }
432 
DrawStrikethrough(void * clientDrawingContext,FLOAT baselineOriginX,FLOAT baselineOriginY,DWRITE_STRIKETHROUGH const * strikethrough,IUnknown * clientDrawingEffect)433     SK_STDMETHODIMP DrawStrikethrough(
434         void* clientDrawingContext,
435         FLOAT baselineOriginX,
436         FLOAT baselineOriginY,
437         DWRITE_STRIKETHROUGH const* strikethrough,
438         IUnknown* clientDrawingEffect) override
439     { return E_NOTIMPL; }
440 
DrawInlineObject(void * clientDrawingContext,FLOAT originX,FLOAT originY,IDWriteInlineObject * inlineObject,BOOL isSideways,BOOL isRightToLeft,IUnknown * clientDrawingEffect)441     SK_STDMETHODIMP DrawInlineObject(
442         void* clientDrawingContext,
443         FLOAT originX,
444         FLOAT originY,
445         IDWriteInlineObject* inlineObject,
446         BOOL isSideways,
447         BOOL isRightToLeft,
448         IUnknown* clientDrawingEffect) override
449     { return E_NOTIMPL; }
450 
451     // IDWritePixelSnapping methods
IsPixelSnappingDisabled(void * clientDrawingContext,BOOL * isDisabled)452     SK_STDMETHODIMP IsPixelSnappingDisabled(
453         void* clientDrawingContext,
454         BOOL* isDisabled) override
455     {
456         *isDisabled = FALSE;
457         return S_OK;
458     }
459 
GetCurrentTransform(void * clientDrawingContext,DWRITE_MATRIX * transform)460     SK_STDMETHODIMP GetCurrentTransform(
461         void* clientDrawingContext,
462         DWRITE_MATRIX* transform) override
463     {
464         const DWRITE_MATRIX ident = { 1.0, 0.0, 0.0, 1.0, 0.0, 0.0 };
465         *transform = ident;
466         return S_OK;
467     }
468 
GetPixelsPerDip(void * clientDrawingContext,FLOAT * pixelsPerDip)469     SK_STDMETHODIMP GetPixelsPerDip(
470         void* clientDrawingContext,
471         FLOAT* pixelsPerDip) override
472     {
473         *pixelsPerDip = 1.0f;
474         return S_OK;
475     }
476 
ConsumeFallbackTypeface()477     sk_sp<SkTypeface> ConsumeFallbackTypeface() { return std::move(fResolvedTypeface); }
478 
FallbackTypefaceHasSimulations()479     bool FallbackTypefaceHasSimulations() { return fHasSimulations; }
480 
481 private:
~FontFallbackRenderer()482     virtual ~FontFallbackRenderer() { }
483 
484     ULONG fRefCount;
485     sk_sp<const SkFontMgr_DirectWrite> fOuter;
486     UINT32 fCharacter;
487     sk_sp<SkTypeface> fResolvedTypeface;
488     bool fHasSimulations{false};
489 };
490 
491 class FontFallbackSource : public IDWriteTextAnalysisSource {
492 public:
FontFallbackSource(const WCHAR * string,UINT32 length,const WCHAR * locale,IDWriteNumberSubstitution * numberSubstitution)493     FontFallbackSource(const WCHAR* string, UINT32 length, const WCHAR* locale,
494                        IDWriteNumberSubstitution* numberSubstitution)
495         : fRefCount(1)
496         , fString(string)
497         , fLength(length)
498         , fLocale(locale)
499         , fNumberSubstitution(numberSubstitution)
500     { }
501 
502     // IUnknown methods
QueryInterface(IID const & riid,void ** ppvObject)503     SK_STDMETHODIMP QueryInterface(IID const& riid, void** ppvObject) override {
504         if (__uuidof(IUnknown) == riid ||
505             __uuidof(IDWriteTextAnalysisSource) == riid)
506         {
507             *ppvObject = this;
508             this->AddRef();
509             return S_OK;
510         }
511         *ppvObject = nullptr;
512         return E_FAIL;
513     }
514 
AddRef()515     SK_STDMETHODIMP_(ULONG) AddRef() override {
516         return InterlockedIncrement(&fRefCount);
517     }
518 
Release()519     SK_STDMETHODIMP_(ULONG) Release() override {
520         ULONG newCount = InterlockedDecrement(&fRefCount);
521         if (0 == newCount) {
522             delete this;
523         }
524         return newCount;
525     }
526 
527     // IDWriteTextAnalysisSource methods
GetTextAtPosition(UINT32 textPosition,WCHAR const ** textString,UINT32 * textLength)528     SK_STDMETHODIMP GetTextAtPosition(
529         UINT32 textPosition,
530         WCHAR const** textString,
531         UINT32* textLength) override
532     {
533         if (fLength <= textPosition) {
534             *textString = nullptr;
535             *textLength = 0;
536             return S_OK;
537         }
538         *textString = fString + textPosition;
539         *textLength = fLength - textPosition;
540         return S_OK;
541     }
542 
GetTextBeforePosition(UINT32 textPosition,WCHAR const ** textString,UINT32 * textLength)543     SK_STDMETHODIMP GetTextBeforePosition(
544         UINT32 textPosition,
545         WCHAR const** textString,
546         UINT32* textLength) override
547     {
548         if (textPosition < 1 || fLength <= textPosition) {
549             *textString = nullptr;
550             *textLength = 0;
551             return S_OK;
552         }
553         *textString = fString;
554         *textLength = textPosition;
555         return S_OK;
556     }
557 
GetParagraphReadingDirection()558     SK_STDMETHODIMP_(DWRITE_READING_DIRECTION) GetParagraphReadingDirection() override {
559         // TODO: this is also interesting.
560         return DWRITE_READING_DIRECTION_LEFT_TO_RIGHT;
561     }
562 
GetLocaleName(UINT32 textPosition,UINT32 * textLength,WCHAR const ** localeName)563     SK_STDMETHODIMP GetLocaleName(
564         UINT32 textPosition,
565         UINT32* textLength,
566         WCHAR const** localeName) override
567     {
568         *localeName = fLocale;
569         return S_OK;
570     }
571 
GetNumberSubstitution(UINT32 textPosition,UINT32 * textLength,IDWriteNumberSubstitution ** numberSubstitution)572     SK_STDMETHODIMP GetNumberSubstitution(
573         UINT32 textPosition,
574         UINT32* textLength,
575         IDWriteNumberSubstitution** numberSubstitution) override
576     {
577         *numberSubstitution = fNumberSubstitution;
578         return S_OK;
579     }
580 
581 private:
~FontFallbackSource()582     virtual ~FontFallbackSource() { }
583 
584     ULONG fRefCount;
585     const WCHAR* fString;
586     UINT32 fLength;
587     const WCHAR* fLocale;
588     IDWriteNumberSubstitution* fNumberSubstitution;
589 };
590 
onMatchFamilyStyleCharacter(const char familyName[],const SkFontStyle & style,const char * bcp47[],int bcp47Count,SkUnichar character) const591 sk_sp<SkTypeface> SkFontMgr_DirectWrite::onMatchFamilyStyleCharacter(
592     const char familyName[], const SkFontStyle& style,
593     const char* bcp47[], int bcp47Count,
594     SkUnichar character) const
595 {
596     DWriteStyle dwStyle(style);
597 
598     const WCHAR* dwFamilyName = nullptr;
599     SkSMallocWCHAR dwFamilyNameLocal;
600     if (familyName) {
601         HRN(sk_cstring_to_wchar(familyName, &dwFamilyNameLocal));
602         dwFamilyName = dwFamilyNameLocal;
603     }
604 
605     const SkSMallocWCHAR* dwBcp47;
606     SkSMallocWCHAR dwBcp47Local;
607     if (bcp47Count < 1) {
608         dwBcp47 = &fLocaleName;
609     } else {
610         // TODO: support fallback stack.
611         // TODO: DirectWrite supports 'zh-CN' or 'zh-Hans', but 'zh' misses completely
612         // and may produce a Japanese font.
613         HRN(sk_cstring_to_wchar(bcp47[bcp47Count - 1], &dwBcp47Local));
614         dwBcp47 = &dwBcp47Local;
615     }
616 
617     if (fFontFallback) {
618         return this->fallback(dwFamilyName, dwStyle, dwBcp47->get(), character);
619     }
620 
621     // LayoutFallback may use the system font collection for fallback.
622     return this->layoutFallback(dwFamilyName, dwStyle, dwBcp47->get(), character);
623 }
624 
fallback(const WCHAR * dwFamilyName,DWriteStyle dwStyle,const WCHAR * dwBcp47,UINT32 character) const625 sk_sp<SkTypeface> SkFontMgr_DirectWrite::fallback(const WCHAR* dwFamilyName,
626                                                   DWriteStyle dwStyle,
627                                                   const WCHAR* dwBcp47,
628                                                   UINT32 character) const {
629     WCHAR str[16];
630     UINT32 strLen = SkTo<UINT32>(SkUTF::ToUTF16(character, reinterpret_cast<uint16_t*>(str)));
631 
632     if (!fFontFallback) {
633         return nullptr;
634     }
635 
636     SkTScopedComPtr<IDWriteNumberSubstitution> numberSubstitution;
637     HRNM(fFactory->CreateNumberSubstitution(DWRITE_NUMBER_SUBSTITUTION_METHOD_NONE, dwBcp47,
638                                             TRUE, &numberSubstitution),
639          "Could not create number substitution.");
640     SkTScopedComPtr<FontFallbackSource> fontFallbackSource(
641         new FontFallbackSource(str, strLen, dwBcp47, numberSubstitution.get()));
642 
643     UINT32 mappedLength;
644     SkTScopedComPtr<IDWriteFont> font;
645     FLOAT scale;
646 
647     bool noSimulations = false;
648     while (!noSimulations) {
649         font.reset();
650         HRNM(fFontFallback->MapCharacters(fontFallbackSource.get(),
651                                           0,  // textPosition,
652                                           strLen,
653                                           fFontCollection.get(),
654                                           dwFamilyName,
655                                           dwStyle.fWeight,
656                                           dwStyle.fSlant,
657                                           dwStyle.fWidth,
658                                           &mappedLength,
659                                           &font,
660                                           &scale),
661              "Could not map characters");
662         if (!font.get()) {
663             return nullptr;
664         }
665 
666         DWRITE_FONT_SIMULATIONS simulations = font->GetSimulations();
667 
668 #ifdef SK_WIN_FONTMGR_NO_SIMULATIONS
669         noSimulations = simulations == DWRITE_FONT_SIMULATIONS_NONE || HasBitmapStrikes(font);
670 #else
671         noSimulations = true;
672 #endif
673 
674         if (simulations & DWRITE_FONT_SIMULATIONS_BOLD) {
675             dwStyle.fWeight = DWRITE_FONT_WEIGHT_REGULAR;
676             continue;
677         }
678 
679         if (simulations & DWRITE_FONT_SIMULATIONS_OBLIQUE) {
680             dwStyle.fSlant = DWRITE_FONT_STYLE_NORMAL;
681             continue;
682         }
683     }
684 
685     SkTScopedComPtr<IDWriteFontFace> fontFace;
686     HRNM(font->CreateFontFace(&fontFace), "Could not get font face from font.");
687 
688     SkTScopedComPtr<IDWriteFontFamily> fontFamily;
689     HRNM(font->GetFontFamily(&fontFamily), "Could not get family from font.");
690     return this->makeTypefaceFromDWriteFont(fontFace.get(), font.get(), fontFamily.get());
691 }
692 
layoutFallback(const WCHAR * dwFamilyName,DWriteStyle dwStyle,const WCHAR * dwBcp47,UINT32 character) const693 sk_sp<SkTypeface> SkFontMgr_DirectWrite::layoutFallback(const WCHAR* dwFamilyName,
694                                                         DWriteStyle dwStyle,
695                                                         const WCHAR* dwBcp47,
696                                                         UINT32 character) const
697 {
698     WCHAR str[16];
699     UINT32 strLen = SkTo<UINT32>(SkUTF::ToUTF16(character, reinterpret_cast<uint16_t*>(str)));
700 
701     bool noSimulations = false;
702     sk_sp<SkTypeface> returnTypeface(nullptr);
703     while (!noSimulations) {
704         SkTScopedComPtr<IDWriteTextFormat> fallbackFormat;
705         HRNM(fFactory->CreateTextFormat(dwFamilyName ? dwFamilyName : L"",
706                                         fFontCollection.get(),
707                                         dwStyle.fWeight,
708                                         dwStyle.fSlant,
709                                         dwStyle.fWidth,
710                                         72.0f,
711                                         dwBcp47,
712                                         &fallbackFormat),
713              "Could not create text format.");
714 
715         // No matter how the font collection is set on this IDWriteTextLayout, it is not possible to
716         // disable use of the system font collection in fallback.
717         SkTScopedComPtr<IDWriteTextLayout> fallbackLayout;
718         HRNM(fFactory->CreateTextLayout(
719                      str, strLen, fallbackFormat.get(), 200.0f, 200.0f, &fallbackLayout),
720              "Could not create text layout.");
721 
722         SkTScopedComPtr<FontFallbackRenderer> fontFallbackRenderer(
723                 new FontFallbackRenderer(this, character));
724 
725         HRNM(fallbackLayout->SetFontCollection(fFontCollection.get(), {0, strLen}),
726              "Could not set layout font collection.");
727         HRNM(fallbackLayout->Draw(nullptr, fontFallbackRenderer.get(), 50.0f, 50.0f),
728              "Could not draw layout with renderer.");
729 
730 #ifdef SK_WIN_FONTMGR_NO_SIMULATIONS
731         noSimulations = !fontFallbackRenderer->FallbackTypefaceHasSimulations();
732 #else
733         noSimulations = true;
734 #endif
735 
736         if (noSimulations) {
737             returnTypeface = fontFallbackRenderer->ConsumeFallbackTypeface();
738         }
739 
740         if (dwStyle.fWeight != DWRITE_FONT_WEIGHT_REGULAR) {
741             dwStyle.fWeight = DWRITE_FONT_WEIGHT_REGULAR;
742             continue;
743         }
744 
745         if (dwStyle.fSlant != DWRITE_FONT_STYLE_NORMAL) {
746             dwStyle.fSlant = DWRITE_FONT_STYLE_NORMAL;
747             continue;
748         }
749     }
750 
751     return returnTypeface;
752 }
753 
onMakeFromStreamIndex(std::unique_ptr<SkStreamAsset> stream,int ttcIndex) const754 sk_sp<SkTypeface> SkFontMgr_DirectWrite::onMakeFromStreamIndex(std::unique_ptr<SkStreamAsset> stream,
755                                                                int ttcIndex) const {
756     SkFontArguments args;
757     args.setCollectionIndex(ttcIndex);
758     return this->onMakeFromStreamArgs(std::move(stream), args);
759 }
760 
onMakeFromStreamArgs(std::unique_ptr<SkStreamAsset> stream,const SkFontArguments & args) const761 sk_sp<SkTypeface> SkFontMgr_DirectWrite::onMakeFromStreamArgs(std::unique_ptr<SkStreamAsset> stream,
762                                                               const SkFontArguments& args) const {
763     return DWriteFontTypeface::MakeFromStream(std::move(stream), args);
764 }
765 
onMakeFromData(sk_sp<SkData> data,int ttcIndex) const766 sk_sp<SkTypeface> SkFontMgr_DirectWrite::onMakeFromData(sk_sp<SkData> data, int ttcIndex) const {
767     return this->makeFromStream(std::make_unique<SkMemoryStream>(std::move(data)), ttcIndex);
768 }
769 
onMakeFromFile(const char path[],int ttcIndex) const770 sk_sp<SkTypeface> SkFontMgr_DirectWrite::onMakeFromFile(const char path[], int ttcIndex) const {
771     return this->makeFromStream(SkStream::MakeFromFile(path), ttcIndex);
772 }
773 
getByFamilyName(const WCHAR wideFamilyName[],IDWriteFontFamily ** fontFamily) const774 HRESULT SkFontMgr_DirectWrite::getByFamilyName(const WCHAR wideFamilyName[],
775                                                IDWriteFontFamily** fontFamily) const {
776     UINT32 index;
777     BOOL exists;
778     HR(fFontCollection->FindFamilyName(wideFamilyName, &index, &exists));
779 
780     if (exists) {
781         HR(fFontCollection->GetFontFamily(index, fontFamily));
782     }
783     return S_OK;
784 }
785 
onLegacyMakeTypeface(const char familyName[],SkFontStyle style) const786 sk_sp<SkTypeface> SkFontMgr_DirectWrite::onLegacyMakeTypeface(const char familyName[],
787                                                               SkFontStyle style) const {
788     SkTScopedComPtr<IDWriteFontFamily> fontFamily;
789     DWriteStyle dwStyle(style);
790     if (familyName) {
791         SkSMallocWCHAR dwFamilyName;
792         if (SUCCEEDED(sk_cstring_to_wchar(familyName, &dwFamilyName))) {
793             this->getByFamilyName(dwFamilyName, &fontFamily);
794             if (!fontFamily && fFontFallback) {
795                 return this->fallback(
796                         dwFamilyName, dwStyle, fLocaleName.get(), 32);
797             }
798         }
799     }
800 
801     if (!fontFamily) {
802         if (fFontFallback) {
803             return this->fallback(nullptr, dwStyle, fLocaleName.get(), 32);
804         }
805         // SPI_GETNONCLIENTMETRICS lfMessageFont can fail in Win8. (DisallowWin32kSystemCalls)
806         // layoutFallback causes DCHECK in Chromium. (Uses system font collection.)
807         HRNM(this->getByFamilyName(fDefaultFamilyName, &fontFamily),
808              "Could not create DWrite font family from LOGFONT.");
809     }
810 
811     if (!fontFamily) {
812         // Could not obtain the default font.
813         HRNM(fFontCollection->GetFontFamily(0, &fontFamily),
814              "Could not get default-default font family.");
815     }
816 
817     SkTScopedComPtr<IDWriteFont> font;
818     HRNM(FirstMatchingFontWithoutSimulations(fontFamily, dwStyle, font),
819          "No font found from family.");
820 
821     SkTScopedComPtr<IDWriteFontFace> fontFace;
822     HRNM(font->CreateFontFace(&fontFace), "Could not create font face.");
823 
824     return this->makeTypefaceFromDWriteFont(fontFace.get(), font.get(), fontFamily.get());
825 }
826 
827 ///////////////////////////////////////////////////////////////////////////////
828 
count()829 int SkFontStyleSet_DirectWrite::count() {
830     return fFontFamily->GetFontCount();
831 }
832 
createTypeface(int index)833 sk_sp<SkTypeface> SkFontStyleSet_DirectWrite::createTypeface(int index) {
834     SkTScopedComPtr<IDWriteFont> font;
835     HRNM(fFontFamily->GetFont(index, &font), "Could not get font.");
836 
837     SkTScopedComPtr<IDWriteFontFace> fontFace;
838     HRNM(font->CreateFontFace(&fontFace), "Could not create font face.");
839 
840     return fFontMgr->makeTypefaceFromDWriteFont(fontFace.get(), font.get(), fFontFamily.get());
841 }
842 
getStyle(int index,SkFontStyle * fs,SkString * styleName)843 void SkFontStyleSet_DirectWrite::getStyle(int index, SkFontStyle* fs, SkString* styleName) {
844     SkTScopedComPtr<IDWriteFont> font;
845     HRVM(fFontFamily->GetFont(index, &font), "Could not get font.");
846 
847     if (fs) {
848         SkTScopedComPtr<IDWriteFontFace> face;
849         HRVM(font->CreateFontFace(&face), "Could not get face.");
850         *fs = DWriteFontTypeface::GetStyle(font.get(), face.get());
851     }
852 
853     if (styleName) {
854         SkTScopedComPtr<IDWriteLocalizedStrings> faceNames;
855         if (SUCCEEDED(font->GetFaceNames(&faceNames))) {
856             sk_get_locale_string(faceNames.get(), fFontMgr->fLocaleName.get(), styleName);
857         }
858     }
859 }
860 
matchStyle(const SkFontStyle & pattern)861 sk_sp<SkTypeface> SkFontStyleSet_DirectWrite::matchStyle(const SkFontStyle& pattern) {
862     SkTScopedComPtr<IDWriteFont> font;
863     DWriteStyle dwStyle(pattern);
864 
865     HRNM(FirstMatchingFontWithoutSimulations(fFontFamily, dwStyle, font),
866          "No font found from family.");
867 
868     SkTScopedComPtr<IDWriteFontFace> fontFace;
869     HRNM(font->CreateFontFace(&fontFace), "Could not create font face.");
870 
871     return fFontMgr->makeTypefaceFromDWriteFont(fontFace.get(), font.get(), fFontFamily.get());
872 }
873 
874 ////////////////////////////////////////////////////////////////////////////////
875 #include "include/ports/SkTypeface_win.h"
876 
SkFontMgr_New_DirectWrite(IDWriteFactory * factory,IDWriteFontCollection * collection)877 sk_sp<SkFontMgr> SkFontMgr_New_DirectWrite(IDWriteFactory* factory,
878                                            IDWriteFontCollection* collection) {
879     return SkFontMgr_New_DirectWrite(factory, collection, nullptr);
880 }
881 
SkFontMgr_New_DirectWrite(IDWriteFactory * factory,IDWriteFontCollection * collection,IDWriteFontFallback * fallback)882 sk_sp<SkFontMgr> SkFontMgr_New_DirectWrite(IDWriteFactory* factory,
883                                            IDWriteFontCollection* collection,
884                                            IDWriteFontFallback* fallback) {
885     if (nullptr == factory) {
886         factory = sk_get_dwrite_factory();
887         if (nullptr == factory) {
888             return nullptr;
889         }
890     }
891 
892     SkTScopedComPtr<IDWriteFontCollection> systemFontCollection;
893     if (nullptr == collection) {
894         HRNM(factory->GetSystemFontCollection(&systemFontCollection, FALSE),
895              "Could not get system font collection.");
896         collection = systemFontCollection.get();
897     }
898 
899     // It is possible to have been provided a font fallback when factory2 is not available.
900     SkTScopedComPtr<IDWriteFontFallback> systemFontFallback;
901     if (nullptr == fallback) {
902         SkTScopedComPtr<IDWriteFactory2> factory2;
903         if (!SUCCEEDED(factory->QueryInterface(&factory2))) {
904             // IUnknown::QueryInterface states that if it fails, punk will be set to nullptr.
905             // http://blogs.msdn.com/b/oldnewthing/archive/2004/03/26/96777.aspx
906             SkASSERT_RELEASE(nullptr == factory2.get());
907         } else {
908             HRNM(factory2->GetSystemFontFallback(&systemFontFallback),
909                  "Could not get system fallback.");
910             fallback = systemFontFallback.get();
911         }
912     }
913 
914     const WCHAR* defaultFamilyName = L"";
915     int defaultFamilyNameLen = 1;
916     NONCLIENTMETRICSW metrics;
917     metrics.cbSize = sizeof(metrics);
918 
919     #ifndef SK_WINUWP
920     if (nullptr == fallback) {
921         if (SystemParametersInfoW(SPI_GETNONCLIENTMETRICS, sizeof(metrics), &metrics, 0)) {
922             defaultFamilyName = metrics.lfMessageFont.lfFaceName;
923             defaultFamilyNameLen = LF_FACESIZE;
924         }
925     }
926     #endif //SK_WINUWP
927 
928     WCHAR localeNameStorage[LOCALE_NAME_MAX_LENGTH];
929     const WCHAR* localeName = L"";
930     int localeNameLen = 1;
931 
932     // Dynamically load GetUserDefaultLocaleName function, as it is not available on XP.
933     SkGetUserDefaultLocaleNameProc getUserDefaultLocaleNameProc = nullptr;
934     HRESULT hr = SkGetGetUserDefaultLocaleNameProc(&getUserDefaultLocaleNameProc);
935     if (nullptr == getUserDefaultLocaleNameProc) {
936         SK_TRACEHR(hr, "Could not get GetUserDefaultLocaleName.");
937     } else {
938         int size = getUserDefaultLocaleNameProc(localeNameStorage, LOCALE_NAME_MAX_LENGTH);
939         if (size) {
940             localeName = localeNameStorage;
941             localeNameLen = size;
942         }
943     }
944 
945     return sk_make_sp<SkFontMgr_DirectWrite>(factory, collection, fallback,
946                                              localeName, localeNameLen,
947                                              defaultFamilyName, defaultFamilyNameLen);
948 }
949 
950 #endif//defined(SK_BUILD_FOR_WIN)
951