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