• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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/SkMutex.h"
17 #include "include/private/SkTPin.h"
18 #include "src/core/SkEndian.h"
19 #include "src/core/SkFontDescriptor.h"
20 #include "src/core/SkTypefaceCache.h"
21 #include "src/ports/SkTypeface_win_dw.h"
22 #include "src/utils/SkUTF.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 ////////////////////////////////////////////////////////////////////////////////
34 
35 class StreamFontFileLoader : public IDWriteFontFileLoader {
36 public:
37     // IUnknown methods
38     SK_STDMETHODIMP QueryInterface(REFIID iid, void** ppvObject) override;
39     SK_STDMETHODIMP_(ULONG) AddRef() override;
40     SK_STDMETHODIMP_(ULONG) Release() override;
41 
42     // IDWriteFontFileLoader methods
43     SK_STDMETHODIMP CreateStreamFromKey(
44         void const* fontFileReferenceKey,
45         UINT32 fontFileReferenceKeySize,
46         IDWriteFontFileStream** fontFileStream) override;
47 
48     // Takes ownership of stream.
Create(std::unique_ptr<SkStreamAsset> stream,StreamFontFileLoader ** streamFontFileLoader)49     static HRESULT Create(std::unique_ptr<SkStreamAsset> stream,
50                           StreamFontFileLoader** streamFontFileLoader) {
51         *streamFontFileLoader = new StreamFontFileLoader(std::move(stream));
52         if (nullptr == *streamFontFileLoader) {
53             return E_OUTOFMEMORY;
54         }
55         return S_OK;
56     }
57 
58 private:
StreamFontFileLoader(std::unique_ptr<SkStreamAsset> stream)59     StreamFontFileLoader(std::unique_ptr<SkStreamAsset> stream)
60         : fStream(std::move(stream)), fRefCount(1)
61     {}
~StreamFontFileLoader()62     virtual ~StreamFontFileLoader() { }
63 
64     std::unique_ptr<SkStreamAsset> fStream;
65     ULONG fRefCount;
66 };
67 
QueryInterface(REFIID iid,void ** ppvObject)68 SK_STDMETHODIMP StreamFontFileLoader::QueryInterface(REFIID iid, void** ppvObject) {
69     if (iid == IID_IUnknown || iid == __uuidof(IDWriteFontFileLoader)) {
70         *ppvObject = this;
71         AddRef();
72         return S_OK;
73     } else {
74         *ppvObject = nullptr;
75         return E_NOINTERFACE;
76     }
77 }
78 
SK_STDMETHODIMP_(ULONG)79 SK_STDMETHODIMP_(ULONG) StreamFontFileLoader::AddRef() {
80     return InterlockedIncrement(&fRefCount);
81 }
82 
SK_STDMETHODIMP_(ULONG)83 SK_STDMETHODIMP_(ULONG) StreamFontFileLoader::Release() {
84     ULONG newCount = InterlockedDecrement(&fRefCount);
85     if (0 == newCount) {
86         delete this;
87     }
88     return newCount;
89 }
90 
CreateStreamFromKey(void const * fontFileReferenceKey,UINT32 fontFileReferenceKeySize,IDWriteFontFileStream ** fontFileStream)91 SK_STDMETHODIMP StreamFontFileLoader::CreateStreamFromKey(
92     void const* fontFileReferenceKey,
93     UINT32 fontFileReferenceKeySize,
94     IDWriteFontFileStream** fontFileStream)
95 {
96     SkTScopedComPtr<SkDWriteFontFileStreamWrapper> stream;
97     HR(SkDWriteFontFileStreamWrapper::Create(fStream->duplicate().release(), &stream));
98     *fontFileStream = stream.release();
99     return S_OK;
100 }
101 
102 ////////////////////////////////////////////////////////////////////////////////
103 
104 class StreamFontFileEnumerator : public IDWriteFontFileEnumerator {
105 public:
106     // IUnknown methods
107     SK_STDMETHODIMP QueryInterface(REFIID iid, void** ppvObject) override;
108     SK_STDMETHODIMP_(ULONG) AddRef() override;
109     SK_STDMETHODIMP_(ULONG) Release() override;
110 
111     // IDWriteFontFileEnumerator methods
112     SK_STDMETHODIMP MoveNext(BOOL* hasCurrentFile) override;
113     SK_STDMETHODIMP GetCurrentFontFile(IDWriteFontFile** fontFile) override;
114 
Create(IDWriteFactory * factory,IDWriteFontFileLoader * fontFileLoader,StreamFontFileEnumerator ** streamFontFileEnumerator)115     static HRESULT Create(IDWriteFactory* factory, IDWriteFontFileLoader* fontFileLoader,
116                           StreamFontFileEnumerator** streamFontFileEnumerator) {
117         *streamFontFileEnumerator = new StreamFontFileEnumerator(factory, fontFileLoader);
118         if (nullptr == *streamFontFileEnumerator) {
119             return E_OUTOFMEMORY;
120         }
121         return S_OK;
122     }
123 private:
124     StreamFontFileEnumerator(IDWriteFactory* factory, IDWriteFontFileLoader* fontFileLoader);
~StreamFontFileEnumerator()125     virtual ~StreamFontFileEnumerator() { }
126 
127     ULONG fRefCount;
128 
129     SkTScopedComPtr<IDWriteFactory> fFactory;
130     SkTScopedComPtr<IDWriteFontFile> fCurrentFile;
131     SkTScopedComPtr<IDWriteFontFileLoader> fFontFileLoader;
132     bool fHasNext;
133 };
134 
StreamFontFileEnumerator(IDWriteFactory * factory,IDWriteFontFileLoader * fontFileLoader)135 StreamFontFileEnumerator::StreamFontFileEnumerator(IDWriteFactory* factory,
136                                                    IDWriteFontFileLoader* fontFileLoader)
137     : fRefCount(1)
138     , fFactory(SkRefComPtr(factory))
139     , fCurrentFile()
140     , fFontFileLoader(SkRefComPtr(fontFileLoader))
141     , fHasNext(true)
142 { }
143 
QueryInterface(REFIID iid,void ** ppvObject)144 SK_STDMETHODIMP StreamFontFileEnumerator::QueryInterface(REFIID iid, void** ppvObject) {
145     if (iid == IID_IUnknown || iid == __uuidof(IDWriteFontFileEnumerator)) {
146         *ppvObject = this;
147         AddRef();
148         return S_OK;
149     } else {
150         *ppvObject = nullptr;
151         return E_NOINTERFACE;
152     }
153 }
154 
SK_STDMETHODIMP_(ULONG)155 SK_STDMETHODIMP_(ULONG) StreamFontFileEnumerator::AddRef() {
156     return InterlockedIncrement(&fRefCount);
157 }
158 
SK_STDMETHODIMP_(ULONG)159 SK_STDMETHODIMP_(ULONG) StreamFontFileEnumerator::Release() {
160     ULONG newCount = InterlockedDecrement(&fRefCount);
161     if (0 == newCount) {
162         delete this;
163     }
164     return newCount;
165 }
166 
MoveNext(BOOL * hasCurrentFile)167 SK_STDMETHODIMP StreamFontFileEnumerator::MoveNext(BOOL* hasCurrentFile) {
168     *hasCurrentFile = FALSE;
169 
170     if (!fHasNext) {
171         return S_OK;
172     }
173     fHasNext = false;
174 
175     UINT32 fontFileReferenceKey = 0;
176     HR(fFactory->CreateCustomFontFileReference(
177             &fontFileReferenceKey, //cannot be nullptr
178             sizeof(fontFileReferenceKey), //even if this is 0
179             fFontFileLoader.get(),
180             &fCurrentFile));
181 
182     *hasCurrentFile = TRUE;
183     return S_OK;
184 }
185 
GetCurrentFontFile(IDWriteFontFile ** fontFile)186 SK_STDMETHODIMP StreamFontFileEnumerator::GetCurrentFontFile(IDWriteFontFile** fontFile) {
187     if (fCurrentFile.get() == nullptr) {
188         *fontFile = nullptr;
189         return E_FAIL;
190     }
191 
192     *fontFile = SkRefComPtr(fCurrentFile.get());
193     return  S_OK;
194 }
195 
196 ////////////////////////////////////////////////////////////////////////////////
197 
198 class StreamFontCollectionLoader : public IDWriteFontCollectionLoader {
199 public:
200     // IUnknown methods
201     SK_STDMETHODIMP QueryInterface(REFIID iid, void** ppvObject) override;
202     SK_STDMETHODIMP_(ULONG) AddRef() override;
203     SK_STDMETHODIMP_(ULONG) Release() override;
204 
205     // IDWriteFontCollectionLoader methods
206     SK_STDMETHODIMP CreateEnumeratorFromKey(
207         IDWriteFactory* factory,
208         void const* collectionKey,
209         UINT32 collectionKeySize,
210         IDWriteFontFileEnumerator** fontFileEnumerator) override;
211 
Create(IDWriteFontFileLoader * fontFileLoader,StreamFontCollectionLoader ** streamFontCollectionLoader)212     static HRESULT Create(IDWriteFontFileLoader* fontFileLoader,
213                           StreamFontCollectionLoader** streamFontCollectionLoader) {
214         *streamFontCollectionLoader = new StreamFontCollectionLoader(fontFileLoader);
215         if (nullptr == *streamFontCollectionLoader) {
216             return E_OUTOFMEMORY;
217         }
218         return S_OK;
219     }
220 private:
StreamFontCollectionLoader(IDWriteFontFileLoader * fontFileLoader)221     StreamFontCollectionLoader(IDWriteFontFileLoader* fontFileLoader)
222         : fRefCount(1)
223         , fFontFileLoader(SkRefComPtr(fontFileLoader))
224     { }
~StreamFontCollectionLoader()225     virtual ~StreamFontCollectionLoader() { }
226 
227     ULONG fRefCount;
228     SkTScopedComPtr<IDWriteFontFileLoader> fFontFileLoader;
229 };
230 
QueryInterface(REFIID iid,void ** ppvObject)231 SK_STDMETHODIMP StreamFontCollectionLoader::QueryInterface(REFIID iid, void** ppvObject) {
232     if (iid == IID_IUnknown || iid == __uuidof(IDWriteFontCollectionLoader)) {
233         *ppvObject = this;
234         AddRef();
235         return S_OK;
236     } else {
237         *ppvObject = nullptr;
238         return E_NOINTERFACE;
239     }
240 }
241 
SK_STDMETHODIMP_(ULONG)242 SK_STDMETHODIMP_(ULONG) StreamFontCollectionLoader::AddRef() {
243     return InterlockedIncrement(&fRefCount);
244 }
245 
SK_STDMETHODIMP_(ULONG)246 SK_STDMETHODIMP_(ULONG) StreamFontCollectionLoader::Release() {
247     ULONG newCount = InterlockedDecrement(&fRefCount);
248     if (0 == newCount) {
249         delete this;
250     }
251     return newCount;
252 }
253 
CreateEnumeratorFromKey(IDWriteFactory * factory,void const * collectionKey,UINT32 collectionKeySize,IDWriteFontFileEnumerator ** fontFileEnumerator)254 SK_STDMETHODIMP StreamFontCollectionLoader::CreateEnumeratorFromKey(
255     IDWriteFactory* factory,
256     void const* collectionKey,
257     UINT32 collectionKeySize,
258     IDWriteFontFileEnumerator** fontFileEnumerator)
259 {
260     SkTScopedComPtr<StreamFontFileEnumerator> enumerator;
261     HR(StreamFontFileEnumerator::Create(factory, fFontFileLoader.get(), &enumerator));
262     *fontFileEnumerator = enumerator.release();
263     return S_OK;
264 }
265 
266 ////////////////////////////////////////////////////////////////////////////////
267 
268 namespace {
269 
270 // Korean fonts Gulim, Dotum, Batang, Gungsuh have bitmap strikes that get
271 // artifically emboldened by Windows without antialiasing. Korean users prefer
272 // these over the synthetic boldening performed by Skia. So let's make an
273 // exception for fonts with bitmap strikes and allow passing through Windows
274 // simulations for those, until Skia provides more control over simulations in
275 // font matching, see https://crbug.com/1258378
HasBitmapStrikes(const SkTScopedComPtr<IDWriteFont> & font)276 bool HasBitmapStrikes(const SkTScopedComPtr<IDWriteFont>& font) {
277   SkTScopedComPtr<IDWriteFontFace> fontFace;
278   HRB(font->CreateFontFace(&fontFace));
279 
280   AutoDWriteTable ebdtTable(fontFace.get(),
281                             SkEndian_SwapBE32(SkSetFourByteTag('E', 'B', 'D', 'T')));
282   return ebdtTable.fExists;
283 }
284 
285 // Iterate calls to GetFirstMatchingFont incrementally removing bold or italic
286 // styling that can trigger the simulations. Implementing it this way gets us a
287 // IDWriteFont that can be used as before and has the correct information on its
288 // own style. Stripping simulations from IDWriteFontFace is possible via
289 // IDWriteFontList1, IDWriteFontFaceReference and CreateFontFace, but this way
290 // we won't have a matching IDWriteFont which is still used in get_style().
FirstMatchingFontWithoutSimulations(const SkTScopedComPtr<IDWriteFontFamily> & family,DWriteStyle dwStyle,SkTScopedComPtr<IDWriteFont> & font)291 HRESULT FirstMatchingFontWithoutSimulations(const SkTScopedComPtr<IDWriteFontFamily>& family,
292                                             DWriteStyle dwStyle,
293                                             SkTScopedComPtr<IDWriteFont>& font) {
294     bool noSimulations = false;
295     while (!noSimulations) {
296         SkTScopedComPtr<IDWriteFont> searchFont;
297         HR(family->GetFirstMatchingFont(
298                 dwStyle.fWeight, dwStyle.fWidth, dwStyle.fSlant, &searchFont));
299         DWRITE_FONT_SIMULATIONS simulations = searchFont->GetSimulations();
300         // If we still get simulations even though we're not asking for bold or
301         // italic, we can't help it and exit the loop.
302 
303 #ifdef SK_WIN_FONTMGR_NO_SIMULATIONS
304         noSimulations = simulations == DWRITE_FONT_SIMULATIONS_NONE ||
305                         (dwStyle.fWeight == DWRITE_FONT_WEIGHT_REGULAR &&
306                          dwStyle.fSlant == DWRITE_FONT_STYLE_NORMAL) ||
307                         HasBitmapStrikes(searchFont);
308 #else
309         noSimulations = true;
310 #endif
311         if (noSimulations) {
312             font = std::move(searchFont);
313             break;
314         }
315         if (simulations & DWRITE_FONT_SIMULATIONS_BOLD) {
316             dwStyle.fWeight = DWRITE_FONT_WEIGHT_REGULAR;
317             continue;
318         }
319         if (simulations & DWRITE_FONT_SIMULATIONS_OBLIQUE) {
320             dwStyle.fSlant = DWRITE_FONT_STYLE_NORMAL;
321             continue;
322         }
323     }
324     return S_OK;
325 }
326 }
327 
328 ////////////////////////////////////////////////////////////////////////////////
329 
330 class SkFontMgr_DirectWrite : public SkFontMgr {
331 public:
332     /** 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)333     SkFontMgr_DirectWrite(IDWriteFactory* factory, IDWriteFontCollection* fontCollection,
334                           IDWriteFontFallback* fallback,
335                           const WCHAR* localeName, int localeNameLength,
336                           const WCHAR* defaultFamilyName, int defaultFamilyNameLength)
337         : fFactory(SkRefComPtr(factory))
338         , fFontFallback(SkSafeRefComPtr(fallback))
339         , fFontCollection(SkRefComPtr(fontCollection))
340         , fLocaleName(localeNameLength)
341         , fDefaultFamilyName(defaultFamilyNameLength)
342     {
343         memcpy(fLocaleName.get(), localeName, localeNameLength * sizeof(WCHAR));
344         memcpy(fDefaultFamilyName.get(), defaultFamilyName, defaultFamilyNameLength*sizeof(WCHAR));
345     }
346 
347 protected:
348     int onCountFamilies() const override;
349     void onGetFamilyName(int index, SkString* familyName) const override;
350     SkFontStyleSet* onCreateStyleSet(int index) const override;
351     SkFontStyleSet* onMatchFamily(const char familyName[]) const override;
352     SkTypeface* onMatchFamilyStyle(const char familyName[],
353                                    const SkFontStyle& fontstyle) const override;
354     SkTypeface* onMatchFamilyStyleCharacter(const char familyName[], const SkFontStyle&,
355                                             const char* bcp47[], int bcp47Count,
356                                             SkUnichar character) const override;
357     sk_sp<SkTypeface> onMakeFromStreamIndex(std::unique_ptr<SkStreamAsset>, int ttcIndex) const override;
358     sk_sp<SkTypeface> onMakeFromStreamArgs(std::unique_ptr<SkStreamAsset>, const SkFontArguments&) const override;
359     sk_sp<SkTypeface> onMakeFromData(sk_sp<SkData>, int ttcIndex) const override;
360     sk_sp<SkTypeface> onMakeFromFile(const char path[], int ttcIndex) const override;
361     sk_sp<SkTypeface> onLegacyMakeTypeface(const char familyName[], SkFontStyle) const override;
362 
363 private:
364     HRESULT getByFamilyName(const WCHAR familyName[], IDWriteFontFamily** fontFamily) const;
365     sk_sp<SkTypeface> fallback(const WCHAR* dwFamilyName, DWriteStyle,
366                                const WCHAR* dwBcp47, UINT32 character) const;
367     sk_sp<SkTypeface> layoutFallback(const WCHAR* dwFamilyName, DWriteStyle,
368                                      const WCHAR* dwBcp47, UINT32 character) const;
369 
370     /** Creates a typeface using a typeface cache. */
371     sk_sp<SkTypeface> makeTypefaceFromDWriteFont(IDWriteFontFace* fontFace,
372                                                  IDWriteFont* font,
373                                                  IDWriteFontFamily* fontFamily) const;
374 
375     SkTScopedComPtr<IDWriteFactory> fFactory;
376     SkTScopedComPtr<IDWriteFontFallback> fFontFallback;
377     SkTScopedComPtr<IDWriteFontCollection> fFontCollection;
378     SkSMallocWCHAR fLocaleName;
379     SkSMallocWCHAR fDefaultFamilyName;
380     mutable SkMutex fTFCacheMutex;
381     mutable SkTypefaceCache fTFCache;
382 
383     friend class SkFontStyleSet_DirectWrite;
384     friend class FontFallbackRenderer;
385 };
386 
387 class SkFontStyleSet_DirectWrite : public SkFontStyleSet {
388 public:
SkFontStyleSet_DirectWrite(const SkFontMgr_DirectWrite * fontMgr,IDWriteFontFamily * fontFamily)389     SkFontStyleSet_DirectWrite(const SkFontMgr_DirectWrite* fontMgr,
390                                IDWriteFontFamily* fontFamily)
391         : fFontMgr(SkRef(fontMgr))
392         , fFontFamily(SkRefComPtr(fontFamily))
393     { }
394 
395     int count() override;
396     void getStyle(int index, SkFontStyle* fs, SkString* styleName) override;
397     SkTypeface* createTypeface(int index) override;
398     SkTypeface* matchStyle(const SkFontStyle& pattern) override;
399 
400 private:
401     sk_sp<const SkFontMgr_DirectWrite> fFontMgr;
402     SkTScopedComPtr<IDWriteFontFamily> fFontFamily;
403 };
404 
are_same(IUnknown * a,IUnknown * b,bool & same)405 static HRESULT are_same(IUnknown* a, IUnknown* b, bool& same) {
406     SkTScopedComPtr<IUnknown> iunkA;
407     HRM(a->QueryInterface(&iunkA), "Failed to QI<IUnknown> for a.");
408 
409     SkTScopedComPtr<IUnknown> iunkB;
410     HRM(b->QueryInterface(&iunkB), "Failed to QI<IUnknown> for b.");
411 
412     same = (iunkA.get() == iunkB.get());
413     return S_OK;
414 }
415 
416 struct ProtoDWriteTypeface {
417     IDWriteFontFace* fDWriteFontFace;
418     IDWriteFont* fDWriteFont;
419     IDWriteFontFamily* fDWriteFontFamily;
420 };
421 
FindByDWriteFont(SkTypeface * cached,void * ctx)422 static bool FindByDWriteFont(SkTypeface* cached, void* ctx) {
423     DWriteFontTypeface* cshFace = reinterpret_cast<DWriteFontTypeface*>(cached);
424     ProtoDWriteTypeface* ctxFace = reinterpret_cast<ProtoDWriteTypeface*>(ctx);
425 
426     // IDWriteFontFace5 introduced both Equals and HasVariations
427     SkTScopedComPtr<IDWriteFontFace5> cshFontFace5;
428     SkTScopedComPtr<IDWriteFontFace5> ctxFontFace5;
429     cshFace->fDWriteFontFace->QueryInterface(&cshFontFace5);
430     ctxFace->fDWriteFontFace->QueryInterface(&ctxFontFace5);
431     if (cshFontFace5 && ctxFontFace5) {
432         return cshFontFace5->Equals(ctxFontFace5.get());
433     }
434 
435     bool same;
436 
437     //Check to see if the two fonts are identical.
438     HRB(are_same(cshFace->fDWriteFont.get(), ctxFace->fDWriteFont, same));
439     if (same) {
440         return true;
441     }
442 
443     HRB(are_same(cshFace->fDWriteFontFace.get(), ctxFace->fDWriteFontFace, same));
444     if (same) {
445         return true;
446     }
447 
448     //Check if the two fonts share the same loader and have the same key.
449     UINT32 cshNumFiles;
450     UINT32 ctxNumFiles;
451     HRB(cshFace->fDWriteFontFace->GetFiles(&cshNumFiles, nullptr));
452     HRB(ctxFace->fDWriteFontFace->GetFiles(&ctxNumFiles, nullptr));
453     if (cshNumFiles != ctxNumFiles) {
454         return false;
455     }
456 
457     SkTScopedComPtr<IDWriteFontFile> cshFontFile;
458     SkTScopedComPtr<IDWriteFontFile> ctxFontFile;
459     HRB(cshFace->fDWriteFontFace->GetFiles(&cshNumFiles, &cshFontFile));
460     HRB(ctxFace->fDWriteFontFace->GetFiles(&ctxNumFiles, &ctxFontFile));
461 
462     //for (each file) { //we currently only admit fonts from one file.
463     SkTScopedComPtr<IDWriteFontFileLoader> cshFontFileLoader;
464     SkTScopedComPtr<IDWriteFontFileLoader> ctxFontFileLoader;
465     HRB(cshFontFile->GetLoader(&cshFontFileLoader));
466     HRB(ctxFontFile->GetLoader(&ctxFontFileLoader));
467     HRB(are_same(cshFontFileLoader.get(), ctxFontFileLoader.get(), same));
468     if (!same) {
469         return false;
470     }
471     //}
472 
473     const void* cshRefKey;
474     UINT32 cshRefKeySize;
475     const void* ctxRefKey;
476     UINT32 ctxRefKeySize;
477     HRB(cshFontFile->GetReferenceKey(&cshRefKey, &cshRefKeySize));
478     HRB(ctxFontFile->GetReferenceKey(&ctxRefKey, &ctxRefKeySize));
479     if (cshRefKeySize != ctxRefKeySize) {
480         return false;
481     }
482     if (0 != memcmp(cshRefKey, ctxRefKey, ctxRefKeySize)) {
483         return false;
484     }
485 
486     //TODO: better means than comparing name strings?
487     //NOTE: .ttc and fake bold/italic will end up here.
488     SkTScopedComPtr<IDWriteLocalizedStrings> cshFamilyNames;
489     SkTScopedComPtr<IDWriteLocalizedStrings> cshFaceNames;
490     HRB(cshFace->fDWriteFontFamily->GetFamilyNames(&cshFamilyNames));
491     HRB(cshFace->fDWriteFont->GetFaceNames(&cshFaceNames));
492     UINT32 cshFamilyNameLength;
493     UINT32 cshFaceNameLength;
494     HRB(cshFamilyNames->GetStringLength(0, &cshFamilyNameLength));
495     HRB(cshFaceNames->GetStringLength(0, &cshFaceNameLength));
496 
497     SkTScopedComPtr<IDWriteLocalizedStrings> ctxFamilyNames;
498     SkTScopedComPtr<IDWriteLocalizedStrings> ctxFaceNames;
499     HRB(ctxFace->fDWriteFontFamily->GetFamilyNames(&ctxFamilyNames));
500     HRB(ctxFace->fDWriteFont->GetFaceNames(&ctxFaceNames));
501     UINT32 ctxFamilyNameLength;
502     UINT32 ctxFaceNameLength;
503     HRB(ctxFamilyNames->GetStringLength(0, &ctxFamilyNameLength));
504     HRB(ctxFaceNames->GetStringLength(0, &ctxFaceNameLength));
505 
506     if (cshFamilyNameLength != ctxFamilyNameLength ||
507         cshFaceNameLength != ctxFaceNameLength)
508     {
509         return false;
510     }
511 
512     SkSMallocWCHAR cshFamilyName(cshFamilyNameLength+1);
513     SkSMallocWCHAR cshFaceName(cshFaceNameLength+1);
514     HRB(cshFamilyNames->GetString(0, cshFamilyName.get(), cshFamilyNameLength+1));
515     HRB(cshFaceNames->GetString(0, cshFaceName.get(), cshFaceNameLength+1));
516 
517     SkSMallocWCHAR ctxFamilyName(ctxFamilyNameLength+1);
518     SkSMallocWCHAR ctxFaceName(ctxFaceNameLength+1);
519     HRB(ctxFamilyNames->GetString(0, ctxFamilyName.get(), ctxFamilyNameLength+1));
520     HRB(ctxFaceNames->GetString(0, ctxFaceName.get(), ctxFaceNameLength+1));
521 
522     return wcscmp(cshFamilyName.get(), ctxFamilyName.get()) == 0 &&
523            wcscmp(cshFaceName.get(), ctxFaceName.get()) == 0;
524 }
525 
makeTypefaceFromDWriteFont(IDWriteFontFace * fontFace,IDWriteFont * font,IDWriteFontFamily * fontFamily) const526 sk_sp<SkTypeface> SkFontMgr_DirectWrite::makeTypefaceFromDWriteFont(
527         IDWriteFontFace* fontFace,
528         IDWriteFont* font,
529         IDWriteFontFamily* fontFamily) const {
530     SkAutoMutexExclusive ama(fTFCacheMutex);
531     ProtoDWriteTypeface spec = { fontFace, font, fontFamily };
532     sk_sp<SkTypeface> face = fTFCache.findByProcAndRef(FindByDWriteFont, &spec);
533     if (nullptr == face) {
534         face = DWriteFontTypeface::Make(fFactory.get(), fontFace, font, fontFamily, nullptr);
535         if (face) {
536             fTFCache.add(face);
537         }
538     }
539     return face;
540 }
541 
onCountFamilies() const542 int SkFontMgr_DirectWrite::onCountFamilies() const {
543     return fFontCollection->GetFontFamilyCount();
544 }
545 
onGetFamilyName(int index,SkString * familyName) const546 void SkFontMgr_DirectWrite::onGetFamilyName(int index, SkString* familyName) const {
547     SkTScopedComPtr<IDWriteFontFamily> fontFamily;
548     HRVM(fFontCollection->GetFontFamily(index, &fontFamily), "Could not get requested family.");
549 
550     SkTScopedComPtr<IDWriteLocalizedStrings> familyNames;
551     HRVM(fontFamily->GetFamilyNames(&familyNames), "Could not get family names.");
552 
553     sk_get_locale_string(familyNames.get(), fLocaleName.get(), familyName);
554 }
555 
onCreateStyleSet(int index) const556 SkFontStyleSet* SkFontMgr_DirectWrite::onCreateStyleSet(int index) const {
557     SkTScopedComPtr<IDWriteFontFamily> fontFamily;
558     HRNM(fFontCollection->GetFontFamily(index, &fontFamily), "Could not get requested family.");
559 
560     return new SkFontStyleSet_DirectWrite(this, fontFamily.get());
561 }
562 
onMatchFamily(const char familyName[]) const563 SkFontStyleSet* SkFontMgr_DirectWrite::onMatchFamily(const char familyName[]) const {
564     if (!familyName) {
565         return nullptr;
566     }
567 
568     SkSMallocWCHAR dwFamilyName;
569     HRN(sk_cstring_to_wchar(familyName, &dwFamilyName));
570 
571     UINT32 index;
572     BOOL exists;
573     HRNM(fFontCollection->FindFamilyName(dwFamilyName.get(), &index, &exists),
574             "Failed while finding family by name.");
575     if (!exists) {
576         return nullptr;
577     }
578 
579     return this->onCreateStyleSet(index);
580 }
581 
onMatchFamilyStyle(const char familyName[],const SkFontStyle & fontstyle) const582 SkTypeface* SkFontMgr_DirectWrite::onMatchFamilyStyle(const char familyName[],
583                                                       const SkFontStyle& fontstyle) const {
584     sk_sp<SkFontStyleSet> sset(this->matchFamily(familyName));
585     return sset->matchStyle(fontstyle);
586 }
587 
588 class FontFallbackRenderer : public IDWriteTextRenderer {
589 public:
FontFallbackRenderer(const SkFontMgr_DirectWrite * outer,UINT32 character)590     FontFallbackRenderer(const SkFontMgr_DirectWrite* outer, UINT32 character)
591         : fRefCount(1), fOuter(SkSafeRef(outer)), fCharacter(character), fResolvedTypeface(nullptr) {
592     }
593 
594     // IUnknown methods
QueryInterface(IID const & riid,void ** ppvObject)595     SK_STDMETHODIMP QueryInterface(IID const& riid, void** ppvObject) override {
596         if (__uuidof(IUnknown) == riid ||
597             __uuidof(IDWritePixelSnapping) == riid ||
598             __uuidof(IDWriteTextRenderer) == riid)
599         {
600             *ppvObject = this;
601             this->AddRef();
602             return S_OK;
603         }
604         *ppvObject = nullptr;
605         return E_FAIL;
606     }
607 
AddRef()608     SK_STDMETHODIMP_(ULONG) AddRef() override {
609         return InterlockedIncrement(&fRefCount);
610     }
611 
Release()612     SK_STDMETHODIMP_(ULONG) Release() override {
613         ULONG newCount = InterlockedDecrement(&fRefCount);
614         if (0 == newCount) {
615             delete this;
616         }
617         return newCount;
618     }
619 
620     // 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)621     SK_STDMETHODIMP DrawGlyphRun(
622         void* clientDrawingContext,
623         FLOAT baselineOriginX,
624         FLOAT baselineOriginY,
625         DWRITE_MEASURING_MODE measuringMode,
626         DWRITE_GLYPH_RUN const* glyphRun,
627         DWRITE_GLYPH_RUN_DESCRIPTION const* glyphRunDescription,
628         IUnknown* clientDrawingEffect) override
629     {
630         if (!glyphRun->fontFace) {
631             HRM(E_INVALIDARG, "Glyph run without font face.");
632         }
633 
634         SkTScopedComPtr<IDWriteFont> font;
635         HRM(fOuter->fFontCollection->GetFontFromFontFace(glyphRun->fontFace, &font),
636             "Could not get font from font face.");
637 
638         // It is possible that the font passed does not actually have the requested character,
639         // due to no font being found and getting the fallback font.
640         // Check that the font actually contains the requested character.
641         BOOL exists;
642         HRM(font->HasCharacter(fCharacter, &exists), "Could not find character.");
643 
644         if (exists) {
645             SkTScopedComPtr<IDWriteFontFamily> fontFamily;
646             HRM(font->GetFontFamily(&fontFamily), "Could not get family.");
647             fResolvedTypeface = fOuter->makeTypefaceFromDWriteFont(glyphRun->fontFace,
648                                                                    font.get(),
649                                                                    fontFamily.get());
650             fHasSimulations = (font->GetSimulations() != DWRITE_FONT_SIMULATIONS_NONE) &&
651                               !HasBitmapStrikes(font);
652         }
653 
654         return S_OK;
655     }
656 
DrawUnderline(void * clientDrawingContext,FLOAT baselineOriginX,FLOAT baselineOriginY,DWRITE_UNDERLINE const * underline,IUnknown * clientDrawingEffect)657     SK_STDMETHODIMP DrawUnderline(
658         void* clientDrawingContext,
659         FLOAT baselineOriginX,
660         FLOAT baselineOriginY,
661         DWRITE_UNDERLINE const* underline,
662         IUnknown* clientDrawingEffect) override
663     { return E_NOTIMPL; }
664 
DrawStrikethrough(void * clientDrawingContext,FLOAT baselineOriginX,FLOAT baselineOriginY,DWRITE_STRIKETHROUGH const * strikethrough,IUnknown * clientDrawingEffect)665     SK_STDMETHODIMP DrawStrikethrough(
666         void* clientDrawingContext,
667         FLOAT baselineOriginX,
668         FLOAT baselineOriginY,
669         DWRITE_STRIKETHROUGH const* strikethrough,
670         IUnknown* clientDrawingEffect) override
671     { return E_NOTIMPL; }
672 
DrawInlineObject(void * clientDrawingContext,FLOAT originX,FLOAT originY,IDWriteInlineObject * inlineObject,BOOL isSideways,BOOL isRightToLeft,IUnknown * clientDrawingEffect)673     SK_STDMETHODIMP DrawInlineObject(
674         void* clientDrawingContext,
675         FLOAT originX,
676         FLOAT originY,
677         IDWriteInlineObject* inlineObject,
678         BOOL isSideways,
679         BOOL isRightToLeft,
680         IUnknown* clientDrawingEffect) override
681     { return E_NOTIMPL; }
682 
683     // IDWritePixelSnapping methods
IsPixelSnappingDisabled(void * clientDrawingContext,BOOL * isDisabled)684     SK_STDMETHODIMP IsPixelSnappingDisabled(
685         void* clientDrawingContext,
686         BOOL* isDisabled) override
687     {
688         *isDisabled = FALSE;
689         return S_OK;
690     }
691 
GetCurrentTransform(void * clientDrawingContext,DWRITE_MATRIX * transform)692     SK_STDMETHODIMP GetCurrentTransform(
693         void* clientDrawingContext,
694         DWRITE_MATRIX* transform) override
695     {
696         const DWRITE_MATRIX ident = { 1.0, 0.0, 0.0, 1.0, 0.0, 0.0 };
697         *transform = ident;
698         return S_OK;
699     }
700 
GetPixelsPerDip(void * clientDrawingContext,FLOAT * pixelsPerDip)701     SK_STDMETHODIMP GetPixelsPerDip(
702         void* clientDrawingContext,
703         FLOAT* pixelsPerDip) override
704     {
705         *pixelsPerDip = 1.0f;
706         return S_OK;
707     }
708 
ConsumeFallbackTypeface()709     sk_sp<SkTypeface> ConsumeFallbackTypeface() { return std::move(fResolvedTypeface); }
710 
FallbackTypefaceHasSimulations()711     bool FallbackTypefaceHasSimulations() { return fHasSimulations; }
712 
713 private:
~FontFallbackRenderer()714     virtual ~FontFallbackRenderer() { }
715 
716     ULONG fRefCount;
717     sk_sp<const SkFontMgr_DirectWrite> fOuter;
718     UINT32 fCharacter;
719     sk_sp<SkTypeface> fResolvedTypeface;
720     bool fHasSimulations{false};
721 };
722 
723 class FontFallbackSource : public IDWriteTextAnalysisSource {
724 public:
FontFallbackSource(const WCHAR * string,UINT32 length,const WCHAR * locale,IDWriteNumberSubstitution * numberSubstitution)725     FontFallbackSource(const WCHAR* string, UINT32 length, const WCHAR* locale,
726                        IDWriteNumberSubstitution* numberSubstitution)
727         : fRefCount(1)
728         , fString(string)
729         , fLength(length)
730         , fLocale(locale)
731         , fNumberSubstitution(numberSubstitution)
732     { }
733 
734     // IUnknown methods
QueryInterface(IID const & riid,void ** ppvObject)735     SK_STDMETHODIMP QueryInterface(IID const& riid, void** ppvObject) override {
736         if (__uuidof(IUnknown) == riid ||
737             __uuidof(IDWriteTextAnalysisSource) == riid)
738         {
739             *ppvObject = this;
740             this->AddRef();
741             return S_OK;
742         }
743         *ppvObject = nullptr;
744         return E_FAIL;
745     }
746 
AddRef()747     SK_STDMETHODIMP_(ULONG) AddRef() override {
748         return InterlockedIncrement(&fRefCount);
749     }
750 
Release()751     SK_STDMETHODIMP_(ULONG) Release() override {
752         ULONG newCount = InterlockedDecrement(&fRefCount);
753         if (0 == newCount) {
754             delete this;
755         }
756         return newCount;
757     }
758 
759     // IDWriteTextAnalysisSource methods
GetTextAtPosition(UINT32 textPosition,WCHAR const ** textString,UINT32 * textLength)760     SK_STDMETHODIMP GetTextAtPosition(
761         UINT32 textPosition,
762         WCHAR const** textString,
763         UINT32* textLength) override
764     {
765         if (fLength <= textPosition) {
766             *textString = nullptr;
767             *textLength = 0;
768             return S_OK;
769         }
770         *textString = fString + textPosition;
771         *textLength = fLength - textPosition;
772         return S_OK;
773     }
774 
GetTextBeforePosition(UINT32 textPosition,WCHAR const ** textString,UINT32 * textLength)775     SK_STDMETHODIMP GetTextBeforePosition(
776         UINT32 textPosition,
777         WCHAR const** textString,
778         UINT32* textLength) override
779     {
780         if (textPosition < 1 || fLength <= textPosition) {
781             *textString = nullptr;
782             *textLength = 0;
783             return S_OK;
784         }
785         *textString = fString;
786         *textLength = textPosition;
787         return S_OK;
788     }
789 
GetParagraphReadingDirection()790     SK_STDMETHODIMP_(DWRITE_READING_DIRECTION) GetParagraphReadingDirection() override {
791         // TODO: this is also interesting.
792         return DWRITE_READING_DIRECTION_LEFT_TO_RIGHT;
793     }
794 
GetLocaleName(UINT32 textPosition,UINT32 * textLength,WCHAR const ** localeName)795     SK_STDMETHODIMP GetLocaleName(
796         UINT32 textPosition,
797         UINT32* textLength,
798         WCHAR const** localeName) override
799     {
800         *localeName = fLocale;
801         return S_OK;
802     }
803 
GetNumberSubstitution(UINT32 textPosition,UINT32 * textLength,IDWriteNumberSubstitution ** numberSubstitution)804     SK_STDMETHODIMP GetNumberSubstitution(
805         UINT32 textPosition,
806         UINT32* textLength,
807         IDWriteNumberSubstitution** numberSubstitution) override
808     {
809         *numberSubstitution = fNumberSubstitution;
810         return S_OK;
811     }
812 
813 private:
~FontFallbackSource()814     virtual ~FontFallbackSource() { }
815 
816     ULONG fRefCount;
817     const WCHAR* fString;
818     UINT32 fLength;
819     const WCHAR* fLocale;
820     IDWriteNumberSubstitution* fNumberSubstitution;
821 };
822 
onMatchFamilyStyleCharacter(const char familyName[],const SkFontStyle & style,const char * bcp47[],int bcp47Count,SkUnichar character) const823 SkTypeface* SkFontMgr_DirectWrite::onMatchFamilyStyleCharacter(const char familyName[],
824                                                                const SkFontStyle& style,
825                                                                const char* bcp47[], int bcp47Count,
826                                                                SkUnichar character) const {
827     DWriteStyle dwStyle(style);
828 
829     const WCHAR* dwFamilyName = nullptr;
830     SkSMallocWCHAR dwFamilyNameLocal;
831     if (familyName) {
832         HRN(sk_cstring_to_wchar(familyName, &dwFamilyNameLocal));
833         dwFamilyName = dwFamilyNameLocal;
834     }
835 
836     const SkSMallocWCHAR* dwBcp47;
837     SkSMallocWCHAR dwBcp47Local;
838     if (bcp47Count < 1) {
839         dwBcp47 = &fLocaleName;
840     } else {
841         // TODO: support fallback stack.
842         // TODO: DirectWrite supports 'zh-CN' or 'zh-Hans', but 'zh' misses completely
843         // and may produce a Japanese font.
844         HRN(sk_cstring_to_wchar(bcp47[bcp47Count - 1], &dwBcp47Local));
845         dwBcp47 = &dwBcp47Local;
846     }
847 
848     if (fFontFallback) {
849         return this->fallback(dwFamilyName, dwStyle, dwBcp47->get(), character).release();
850     }
851 
852     // LayoutFallback may use the system font collection for fallback.
853     return this->layoutFallback(dwFamilyName, dwStyle, dwBcp47->get(), character).release();
854 }
855 
fallback(const WCHAR * dwFamilyName,DWriteStyle dwStyle,const WCHAR * dwBcp47,UINT32 character) const856 sk_sp<SkTypeface> SkFontMgr_DirectWrite::fallback(const WCHAR* dwFamilyName,
857                                                   DWriteStyle dwStyle,
858                                                   const WCHAR* dwBcp47,
859                                                   UINT32 character) const {
860     WCHAR str[16];
861     UINT32 strLen = SkTo<UINT32>(SkUTF::ToUTF16(character, reinterpret_cast<uint16_t*>(str)));
862 
863     if (!fFontFallback) {
864         return nullptr;
865     }
866 
867     SkTScopedComPtr<IDWriteNumberSubstitution> numberSubstitution;
868     HRNM(fFactory->CreateNumberSubstitution(DWRITE_NUMBER_SUBSTITUTION_METHOD_NONE, dwBcp47,
869                                             TRUE, &numberSubstitution),
870          "Could not create number substitution.");
871     SkTScopedComPtr<FontFallbackSource> fontFallbackSource(
872         new FontFallbackSource(str, strLen, dwBcp47, numberSubstitution.get()));
873 
874     UINT32 mappedLength;
875     SkTScopedComPtr<IDWriteFont> font;
876     FLOAT scale;
877 
878     bool noSimulations = false;
879     while (!noSimulations) {
880         font.reset();
881         HRNM(fFontFallback->MapCharacters(fontFallbackSource.get(),
882                                           0,  // textPosition,
883                                           strLen,
884                                           fFontCollection.get(),
885                                           dwFamilyName,
886                                           dwStyle.fWeight,
887                                           dwStyle.fSlant,
888                                           dwStyle.fWidth,
889                                           &mappedLength,
890                                           &font,
891                                           &scale),
892              "Could not map characters");
893         if (!font.get()) {
894             return nullptr;
895         }
896 
897         DWRITE_FONT_SIMULATIONS simulations = font->GetSimulations();
898 
899 #ifdef SK_WIN_FONTMGR_NO_SIMULATIONS
900         noSimulations = simulations == DWRITE_FONT_SIMULATIONS_NONE || HasBitmapStrikes(font);
901 #else
902         noSimulations = true;
903 #endif
904 
905         if (simulations & DWRITE_FONT_SIMULATIONS_BOLD) {
906             dwStyle.fWeight = DWRITE_FONT_WEIGHT_REGULAR;
907             continue;
908         }
909 
910         if (simulations & DWRITE_FONT_SIMULATIONS_OBLIQUE) {
911             dwStyle.fSlant = DWRITE_FONT_STYLE_NORMAL;
912             continue;
913         }
914     }
915 
916     SkTScopedComPtr<IDWriteFontFace> fontFace;
917     HRNM(font->CreateFontFace(&fontFace), "Could not get font face from font.");
918 
919     SkTScopedComPtr<IDWriteFontFamily> fontFamily;
920     HRNM(font->GetFontFamily(&fontFamily), "Could not get family from font.");
921     return this->makeTypefaceFromDWriteFont(fontFace.get(), font.get(), fontFamily.get());
922 }
923 
layoutFallback(const WCHAR * dwFamilyName,DWriteStyle dwStyle,const WCHAR * dwBcp47,UINT32 character) const924 sk_sp<SkTypeface> SkFontMgr_DirectWrite::layoutFallback(const WCHAR* dwFamilyName,
925                                                         DWriteStyle dwStyle,
926                                                         const WCHAR* dwBcp47,
927                                                         UINT32 character) const
928 {
929     WCHAR str[16];
930     UINT32 strLen = SkTo<UINT32>(SkUTF::ToUTF16(character, reinterpret_cast<uint16_t*>(str)));
931 
932     bool noSimulations = false;
933     sk_sp<SkTypeface> returnTypeface(nullptr);
934     while (!noSimulations) {
935         SkTScopedComPtr<IDWriteTextFormat> fallbackFormat;
936         HRNM(fFactory->CreateTextFormat(dwFamilyName ? dwFamilyName : L"",
937                                         fFontCollection.get(),
938                                         dwStyle.fWeight,
939                                         dwStyle.fSlant,
940                                         dwStyle.fWidth,
941                                         72.0f,
942                                         dwBcp47,
943                                         &fallbackFormat),
944              "Could not create text format.");
945 
946         // No matter how the font collection is set on this IDWriteTextLayout, it is not possible to
947         // disable use of the system font collection in fallback.
948         SkTScopedComPtr<IDWriteTextLayout> fallbackLayout;
949         HRNM(fFactory->CreateTextLayout(
950                      str, strLen, fallbackFormat.get(), 200.0f, 200.0f, &fallbackLayout),
951              "Could not create text layout.");
952 
953         SkTScopedComPtr<FontFallbackRenderer> fontFallbackRenderer(
954                 new FontFallbackRenderer(this, character));
955 
956         HRNM(fallbackLayout->SetFontCollection(fFontCollection.get(), {0, strLen}),
957              "Could not set layout font collection.");
958         HRNM(fallbackLayout->Draw(nullptr, fontFallbackRenderer.get(), 50.0f, 50.0f),
959              "Could not draw layout with renderer.");
960 
961 #ifdef SK_WIN_FONTMGR_NO_SIMULATIONS
962         noSimulations = !fontFallbackRenderer->FallbackTypefaceHasSimulations();
963 #else
964         noSimulations = true;
965 #endif
966 
967         if (noSimulations) {
968             returnTypeface = fontFallbackRenderer->ConsumeFallbackTypeface();
969         }
970 
971         if (dwStyle.fWeight != DWRITE_FONT_WEIGHT_REGULAR) {
972             dwStyle.fWeight = DWRITE_FONT_WEIGHT_REGULAR;
973             continue;
974         }
975 
976         if (dwStyle.fSlant != DWRITE_FONT_STYLE_NORMAL) {
977             dwStyle.fSlant = DWRITE_FONT_STYLE_NORMAL;
978             continue;
979         }
980     }
981 
982     return returnTypeface;
983 }
984 
985 template <typename T> class SkAutoIDWriteUnregister {
986 public:
SkAutoIDWriteUnregister(IDWriteFactory * factory,T * unregister)987     SkAutoIDWriteUnregister(IDWriteFactory* factory, T* unregister)
988         : fFactory(factory), fUnregister(unregister)
989     { }
990     SkAutoIDWriteUnregister(const SkAutoIDWriteUnregister&) = delete;
991     SkAutoIDWriteUnregister& operator=(const SkAutoIDWriteUnregister&) = delete;
992     SkAutoIDWriteUnregister(SkAutoIDWriteUnregister&&) = delete;
993     SkAutoIDWriteUnregister& operator=(SkAutoIDWriteUnregister&&) = delete;
994 
~SkAutoIDWriteUnregister()995     ~SkAutoIDWriteUnregister() {
996         if (fUnregister) {
997             unregister(fFactory, fUnregister);
998         }
999     }
1000 
detatch()1001     T* detatch() {
1002         T* old = fUnregister;
1003         fUnregister = nullptr;
1004         return old;
1005     }
1006 
1007 private:
unregister(IDWriteFactory * factory,IDWriteFontFileLoader * unregister)1008     HRESULT unregister(IDWriteFactory* factory, IDWriteFontFileLoader* unregister) {
1009         return factory->UnregisterFontFileLoader(unregister);
1010     }
1011 
unregister(IDWriteFactory * factory,IDWriteFontCollectionLoader * unregister)1012     HRESULT unregister(IDWriteFactory* factory, IDWriteFontCollectionLoader* unregister) {
1013         return factory->UnregisterFontCollectionLoader(unregister);
1014     }
1015 
1016     IDWriteFactory* fFactory;
1017     T* fUnregister;
1018 };
1019 
onMakeFromStreamIndex(std::unique_ptr<SkStreamAsset> stream,int ttcIndex) const1020 sk_sp<SkTypeface> SkFontMgr_DirectWrite::onMakeFromStreamIndex(std::unique_ptr<SkStreamAsset> stream,
1021                                                                int ttcIndex) const {
1022     SkFontArguments args;
1023     args.setCollectionIndex(ttcIndex);
1024     return this->onMakeFromStreamArgs(std::move(stream), args);
1025 }
1026 
apply_fontargument_variation(SkTScopedComPtr<IDWriteFontFace> & fontFace,const SkFontArguments & args)1027 static HRESULT apply_fontargument_variation(SkTScopedComPtr<IDWriteFontFace>& fontFace,
1028                                             const SkFontArguments& args)
1029 {
1030 #if defined(NTDDI_WIN10_RS3) && NTDDI_VERSION >= NTDDI_WIN10_RS3
1031 
1032     SkTScopedComPtr<IDWriteFontFace5> fontFace5;
1033     if (FAILED(fontFace->QueryInterface(&fontFace5)) || !fontFace5->HasVariations()) {
1034         return S_OK;
1035     }
1036 
1037     UINT32 fontAxisCount = fontFace5->GetFontAxisValueCount();
1038     UINT32 argsCoordCount = args.getVariationDesignPosition().coordinateCount;
1039     SkAutoSTMalloc<8, DWRITE_FONT_AXIS_VALUE> variation(fontAxisCount);
1040     SkTScopedComPtr<IDWriteFontResource> fontResource;
1041     HR(fontFace5->GetFontResource(&fontResource));
1042     HR(fontResource->GetDefaultFontAxisValues(variation, fontAxisCount));
1043 
1044     for (UINT32 fontAxisIndex = 0; fontAxisIndex < fontAxisCount; ++fontAxisIndex) {
1045         DWRITE_FONT_AXIS_VALUE& fontCoordinate = variation[fontAxisIndex];
1046 
1047         for (UINT32 argsCoordIndex = argsCoordCount; argsCoordIndex --> 0;) {
1048             const SkFontArguments::VariationPosition::Coordinate& argsCoordinate =
1049                 args.getVariationDesignPosition().coordinates[argsCoordIndex];
1050             if (SkEndian_SwapBE32(fontCoordinate.axisTag) == argsCoordinate.axis) {
1051                 fontCoordinate.value = argsCoordinate.value;
1052                 break;
1053             }
1054         }
1055     }
1056 
1057     SkTScopedComPtr<IDWriteFontFace5> fontFace5_Out;
1058     HR(fontResource->CreateFontFace(DWRITE_FONT_SIMULATIONS_NONE,
1059                                     variation.get(), fontAxisCount,
1060                                     &fontFace5_Out));
1061     fontFace.reset();
1062     HR(fontFace5_Out->QueryInterface(&fontFace));
1063 #endif
1064     return S_OK;
1065 }
onMakeFromStreamArgs(std::unique_ptr<SkStreamAsset> stream,const SkFontArguments & args) const1066 sk_sp<SkTypeface> SkFontMgr_DirectWrite::onMakeFromStreamArgs(std::unique_ptr<SkStreamAsset> stream,
1067                                                               const SkFontArguments& args) const {
1068     SkTScopedComPtr<StreamFontFileLoader> fontFileLoader;
1069     HRN(StreamFontFileLoader::Create(std::move(stream), &fontFileLoader));
1070     HRN(fFactory->RegisterFontFileLoader(fontFileLoader.get()));
1071     SkAutoIDWriteUnregister<StreamFontFileLoader> autoUnregisterFontFileLoader(
1072             fFactory.get(), fontFileLoader.get());
1073 
1074     SkTScopedComPtr<StreamFontCollectionLoader> fontCollectionLoader;
1075     HRN(StreamFontCollectionLoader::Create(fontFileLoader.get(), &fontCollectionLoader));
1076     HRN(fFactory->RegisterFontCollectionLoader(fontCollectionLoader.get()));
1077     SkAutoIDWriteUnregister<StreamFontCollectionLoader> autoUnregisterFontCollectionLoader(
1078             fFactory.get(), fontCollectionLoader.get());
1079 
1080     SkTScopedComPtr<IDWriteFontCollection> fontCollection;
1081     HRN(fFactory->CreateCustomFontCollection(fontCollectionLoader.get(), nullptr, 0,
1082                                              &fontCollection));
1083 
1084     // Find the first non-simulated font which has the given ttc index.
1085     UINT32 familyCount = fontCollection->GetFontFamilyCount();
1086     for (UINT32 familyIndex = 0; familyIndex < familyCount; ++familyIndex) {
1087         SkTScopedComPtr<IDWriteFontFamily> fontFamily;
1088         HRN(fontCollection->GetFontFamily(familyIndex, &fontFamily));
1089 
1090         UINT32 fontCount = fontFamily->GetFontCount();
1091         for (UINT32 fontIndex = 0; fontIndex < fontCount; ++fontIndex) {
1092             SkTScopedComPtr<IDWriteFont> font;
1093             HRN(fontFamily->GetFont(fontIndex, &font));
1094 
1095             // Skip if the current font is simulated
1096             if (font->GetSimulations() != DWRITE_FONT_SIMULATIONS_NONE) {
1097                 continue;
1098             }
1099             SkTScopedComPtr<IDWriteFontFace> fontFace;
1100             HRN(font->CreateFontFace(&fontFace));
1101             int faceIndex = fontFace->GetIndex();
1102             int ttcIndex = args.getCollectionIndex();
1103 
1104             // Skip if the current face index does not match the ttcIndex
1105             if (faceIndex != ttcIndex) {
1106                 continue;
1107             }
1108 
1109             apply_fontargument_variation(fontFace, args);
1110 
1111             return DWriteFontTypeface::Make(
1112                     fFactory.get(), fontFace.get(), font.get(), fontFamily.get(),
1113                     sk_make_sp<DWriteFontTypeface::Loaders>(
1114                         fFactory.get(),
1115                         autoUnregisterFontFileLoader.detatch(),
1116                         autoUnregisterFontCollectionLoader.detatch()));
1117         }
1118     }
1119 
1120     return nullptr;
1121 }
1122 
onMakeFromData(sk_sp<SkData> data,int ttcIndex) const1123 sk_sp<SkTypeface> SkFontMgr_DirectWrite::onMakeFromData(sk_sp<SkData> data, int ttcIndex) const {
1124     return this->makeFromStream(std::make_unique<SkMemoryStream>(std::move(data)), ttcIndex);
1125 }
1126 
onMakeFromFile(const char path[],int ttcIndex) const1127 sk_sp<SkTypeface> SkFontMgr_DirectWrite::onMakeFromFile(const char path[], int ttcIndex) const {
1128     return this->makeFromStream(SkStream::MakeFromFile(path), ttcIndex);
1129 }
1130 
getByFamilyName(const WCHAR wideFamilyName[],IDWriteFontFamily ** fontFamily) const1131 HRESULT SkFontMgr_DirectWrite::getByFamilyName(const WCHAR wideFamilyName[],
1132                                                IDWriteFontFamily** fontFamily) const {
1133     UINT32 index;
1134     BOOL exists;
1135     HR(fFontCollection->FindFamilyName(wideFamilyName, &index, &exists));
1136 
1137     if (exists) {
1138         HR(fFontCollection->GetFontFamily(index, fontFamily));
1139     }
1140     return S_OK;
1141 }
1142 
onLegacyMakeTypeface(const char familyName[],SkFontStyle style) const1143 sk_sp<SkTypeface> SkFontMgr_DirectWrite::onLegacyMakeTypeface(const char familyName[],
1144                                                               SkFontStyle style) const {
1145     SkTScopedComPtr<IDWriteFontFamily> fontFamily;
1146     DWriteStyle dwStyle(style);
1147     if (familyName) {
1148         SkSMallocWCHAR dwFamilyName;
1149         if (SUCCEEDED(sk_cstring_to_wchar(familyName, &dwFamilyName))) {
1150             this->getByFamilyName(dwFamilyName, &fontFamily);
1151             if (!fontFamily && fFontFallback) {
1152                 return this->fallback(
1153                         dwFamilyName, dwStyle, fLocaleName.get(), 32);
1154             }
1155         }
1156     }
1157 
1158     if (!fontFamily) {
1159         if (fFontFallback) {
1160             return this->fallback(nullptr, dwStyle, fLocaleName.get(), 32);
1161         }
1162         // SPI_GETNONCLIENTMETRICS lfMessageFont can fail in Win8. (DisallowWin32kSystemCalls)
1163         // layoutFallback causes DCHECK in Chromium. (Uses system font collection.)
1164         HRNM(this->getByFamilyName(fDefaultFamilyName, &fontFamily),
1165              "Could not create DWrite font family from LOGFONT.");
1166     }
1167 
1168     if (!fontFamily) {
1169         // Could not obtain the default font.
1170         HRNM(fFontCollection->GetFontFamily(0, &fontFamily),
1171              "Could not get default-default font family.");
1172     }
1173 
1174     SkTScopedComPtr<IDWriteFont> font;
1175     HRNM(FirstMatchingFontWithoutSimulations(fontFamily, dwStyle, font),
1176          "No font found from family.");
1177 
1178     SkTScopedComPtr<IDWriteFontFace> fontFace;
1179     HRNM(font->CreateFontFace(&fontFace), "Could not create font face.");
1180 
1181     return this->makeTypefaceFromDWriteFont(fontFace.get(), font.get(), fontFamily.get());
1182 }
1183 
1184 ///////////////////////////////////////////////////////////////////////////////
1185 
count()1186 int SkFontStyleSet_DirectWrite::count() {
1187     return fFontFamily->GetFontCount();
1188 }
1189 
createTypeface(int index)1190 SkTypeface* SkFontStyleSet_DirectWrite::createTypeface(int index) {
1191     SkTScopedComPtr<IDWriteFont> font;
1192     HRNM(fFontFamily->GetFont(index, &font), "Could not get font.");
1193 
1194     SkTScopedComPtr<IDWriteFontFace> fontFace;
1195     HRNM(font->CreateFontFace(&fontFace), "Could not create font face.");
1196 
1197     return fFontMgr->makeTypefaceFromDWriteFont(fontFace.get(), font.get(), fFontFamily.get()).release();
1198 }
1199 
getStyle(int index,SkFontStyle * fs,SkString * styleName)1200 void SkFontStyleSet_DirectWrite::getStyle(int index, SkFontStyle* fs, SkString* styleName) {
1201     SkTScopedComPtr<IDWriteFont> font;
1202     HRVM(fFontFamily->GetFont(index, &font), "Could not get font.");
1203 
1204     if (fs) {
1205         *fs = get_style(font.get());
1206     }
1207 
1208     if (styleName) {
1209         SkTScopedComPtr<IDWriteLocalizedStrings> faceNames;
1210         if (SUCCEEDED(font->GetFaceNames(&faceNames))) {
1211             sk_get_locale_string(faceNames.get(), fFontMgr->fLocaleName.get(), styleName);
1212         }
1213     }
1214 }
1215 
matchStyle(const SkFontStyle & pattern)1216 SkTypeface* SkFontStyleSet_DirectWrite::matchStyle(const SkFontStyle& pattern) {
1217     SkTScopedComPtr<IDWriteFont> font;
1218     DWriteStyle dwStyle(pattern);
1219 
1220     HRNM(FirstMatchingFontWithoutSimulations(fFontFamily, dwStyle, font),
1221          "No font found from family.");
1222 
1223     SkTScopedComPtr<IDWriteFontFace> fontFace;
1224     HRNM(font->CreateFontFace(&fontFace), "Could not create font face.");
1225 
1226     return fFontMgr->makeTypefaceFromDWriteFont(fontFace.get(), font.get(),
1227                                                 fFontFamily.get()).release();
1228 }
1229 
1230 ////////////////////////////////////////////////////////////////////////////////
1231 #include "include/ports/SkTypeface_win.h"
1232 
SkFontMgr_New_DirectWrite(IDWriteFactory * factory,IDWriteFontCollection * collection)1233 SK_API sk_sp<SkFontMgr> SkFontMgr_New_DirectWrite(IDWriteFactory* factory,
1234                                                   IDWriteFontCollection* collection) {
1235     return SkFontMgr_New_DirectWrite(factory, collection, nullptr);
1236 }
1237 
SkFontMgr_New_DirectWrite(IDWriteFactory * factory,IDWriteFontCollection * collection,IDWriteFontFallback * fallback)1238 SK_API sk_sp<SkFontMgr> SkFontMgr_New_DirectWrite(IDWriteFactory* factory,
1239                                                   IDWriteFontCollection* collection,
1240                                                   IDWriteFontFallback* fallback) {
1241     if (nullptr == factory) {
1242         factory = sk_get_dwrite_factory();
1243         if (nullptr == factory) {
1244             return nullptr;
1245         }
1246     }
1247 
1248     SkTScopedComPtr<IDWriteFontCollection> systemFontCollection;
1249     if (nullptr == collection) {
1250         HRNM(factory->GetSystemFontCollection(&systemFontCollection, FALSE),
1251              "Could not get system font collection.");
1252         collection = systemFontCollection.get();
1253     }
1254 
1255     // It is possible to have been provided a font fallback when factory2 is not available.
1256     SkTScopedComPtr<IDWriteFontFallback> systemFontFallback;
1257     if (nullptr == fallback) {
1258         SkTScopedComPtr<IDWriteFactory2> factory2;
1259         if (!SUCCEEDED(factory->QueryInterface(&factory2))) {
1260             // IUnknown::QueryInterface states that if it fails, punk will be set to nullptr.
1261             // http://blogs.msdn.com/b/oldnewthing/archive/2004/03/26/96777.aspx
1262             SkASSERT_RELEASE(nullptr == factory2.get());
1263         } else {
1264             HRNM(factory2->GetSystemFontFallback(&systemFontFallback),
1265                  "Could not get system fallback.");
1266             fallback = systemFontFallback.get();
1267         }
1268     }
1269 
1270     const WCHAR* defaultFamilyName = L"";
1271     int defaultFamilyNameLen = 1;
1272     NONCLIENTMETRICSW metrics;
1273     metrics.cbSize = sizeof(metrics);
1274 
1275     #ifndef SK_WINUWP
1276     if (nullptr == fallback) {
1277         if (SystemParametersInfoW(SPI_GETNONCLIENTMETRICS, sizeof(metrics), &metrics, 0)) {
1278             defaultFamilyName = metrics.lfMessageFont.lfFaceName;
1279             defaultFamilyNameLen = LF_FACESIZE;
1280         }
1281     }
1282     #endif //SK_WINUWP
1283 
1284     WCHAR localeNameStorage[LOCALE_NAME_MAX_LENGTH];
1285     const WCHAR* localeName = L"";
1286     int localeNameLen = 1;
1287 
1288     // Dynamically load GetUserDefaultLocaleName function, as it is not available on XP.
1289     SkGetUserDefaultLocaleNameProc getUserDefaultLocaleNameProc = nullptr;
1290     HRESULT hr = SkGetGetUserDefaultLocaleNameProc(&getUserDefaultLocaleNameProc);
1291     if (nullptr == getUserDefaultLocaleNameProc) {
1292         SK_TRACEHR(hr, "Could not get GetUserDefaultLocaleName.");
1293     } else {
1294         int size = getUserDefaultLocaleNameProc(localeNameStorage, LOCALE_NAME_MAX_LENGTH);
1295         if (size) {
1296             localeName = localeNameStorage;
1297             localeNameLen = size;
1298         }
1299     }
1300 
1301     return sk_make_sp<SkFontMgr_DirectWrite>(factory, collection, fallback,
1302                                              localeName, localeNameLen,
1303                                              defaultFamilyName, defaultFamilyNameLen);
1304 }
1305 
1306 #include "include/ports/SkFontMgr_indirect.h"
SkFontMgr_New_DirectWriteRenderer(sk_sp<SkRemotableFontMgr> proxy)1307 SK_API sk_sp<SkFontMgr> SkFontMgr_New_DirectWriteRenderer(sk_sp<SkRemotableFontMgr> proxy) {
1308     sk_sp<SkFontMgr> impl(SkFontMgr_New_DirectWrite());
1309     if (!impl) {
1310         return nullptr;
1311     }
1312     return sk_make_sp<SkFontMgr_Indirect>(std::move(impl), std::move(proxy));
1313 }
1314 #endif//defined(SK_BUILD_FOR_WIN)
1315