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
8 #include "SkTypes.h"
9 #if defined(SK_BUILD_FOR_WIN32)
10
11 #include "SkDWrite.h"
12 #include "SkDWriteFontFileStream.h"
13 #include "SkFontMgr.h"
14 #include "SkHRESULT.h"
15 #include "SkMutex.h"
16 #include "SkStream.h"
17 #include "SkTScopedComPtr.h"
18 #include "SkTypeface.h"
19 #include "SkTypefaceCache.h"
20 #include "SkTypeface_win_dw.h"
21 #include "SkTypes.h"
22 #include "SkUtils.h"
23
24 #include <dwrite.h>
25 #include <dwrite_2.h>
26
27 ////////////////////////////////////////////////////////////////////////////////
28
29 class StreamFontFileLoader : public IDWriteFontFileLoader {
30 public:
31 // IUnknown methods
32 virtual HRESULT STDMETHODCALLTYPE QueryInterface(REFIID iid, void** ppvObject);
33 virtual ULONG STDMETHODCALLTYPE AddRef();
34 virtual ULONG STDMETHODCALLTYPE Release();
35
36 // IDWriteFontFileLoader methods
37 virtual HRESULT STDMETHODCALLTYPE CreateStreamFromKey(
38 void const* fontFileReferenceKey,
39 UINT32 fontFileReferenceKeySize,
40 IDWriteFontFileStream** fontFileStream);
41
42 // Takes ownership of stream.
Create(SkStreamAsset * stream,StreamFontFileLoader ** streamFontFileLoader)43 static HRESULT Create(SkStreamAsset* stream, StreamFontFileLoader** streamFontFileLoader) {
44 *streamFontFileLoader = new StreamFontFileLoader(stream);
45 if (nullptr == *streamFontFileLoader) {
46 return E_OUTOFMEMORY;
47 }
48 return S_OK;
49 }
50
51 std::unique_ptr<SkStreamAsset> fStream;
52
53 private:
StreamFontFileLoader(SkStreamAsset * stream)54 StreamFontFileLoader(SkStreamAsset* stream) : fStream(stream), fRefCount(1) { }
~StreamFontFileLoader()55 virtual ~StreamFontFileLoader() { }
56
57 ULONG fRefCount;
58 };
59
QueryInterface(REFIID iid,void ** ppvObject)60 HRESULT StreamFontFileLoader::QueryInterface(REFIID iid, void** ppvObject) {
61 if (iid == IID_IUnknown || iid == __uuidof(IDWriteFontFileLoader)) {
62 *ppvObject = this;
63 AddRef();
64 return S_OK;
65 } else {
66 *ppvObject = nullptr;
67 return E_NOINTERFACE;
68 }
69 }
70
AddRef()71 ULONG StreamFontFileLoader::AddRef() {
72 return InterlockedIncrement(&fRefCount);
73 }
74
Release()75 ULONG StreamFontFileLoader::Release() {
76 ULONG newCount = InterlockedDecrement(&fRefCount);
77 if (0 == newCount) {
78 delete this;
79 }
80 return newCount;
81 }
82
CreateStreamFromKey(void const * fontFileReferenceKey,UINT32 fontFileReferenceKeySize,IDWriteFontFileStream ** fontFileStream)83 HRESULT StreamFontFileLoader::CreateStreamFromKey(
84 void const* fontFileReferenceKey,
85 UINT32 fontFileReferenceKeySize,
86 IDWriteFontFileStream** fontFileStream)
87 {
88 SkTScopedComPtr<SkDWriteFontFileStreamWrapper> stream;
89 HR(SkDWriteFontFileStreamWrapper::Create(fStream->duplicate(), &stream));
90 *fontFileStream = stream.release();
91 return S_OK;
92 }
93
94 ////////////////////////////////////////////////////////////////////////////////
95
96 class StreamFontFileEnumerator : public IDWriteFontFileEnumerator {
97 public:
98 // IUnknown methods
99 virtual HRESULT STDMETHODCALLTYPE QueryInterface(REFIID iid, void** ppvObject);
100 virtual ULONG STDMETHODCALLTYPE AddRef();
101 virtual ULONG STDMETHODCALLTYPE Release();
102
103 // IDWriteFontFileEnumerator methods
104 virtual HRESULT STDMETHODCALLTYPE MoveNext(BOOL* hasCurrentFile);
105 virtual HRESULT STDMETHODCALLTYPE GetCurrentFontFile(IDWriteFontFile** fontFile);
106
Create(IDWriteFactory * factory,IDWriteFontFileLoader * fontFileLoader,StreamFontFileEnumerator ** streamFontFileEnumerator)107 static HRESULT Create(IDWriteFactory* factory, IDWriteFontFileLoader* fontFileLoader,
108 StreamFontFileEnumerator** streamFontFileEnumerator) {
109 *streamFontFileEnumerator = new StreamFontFileEnumerator(factory, fontFileLoader);
110 if (nullptr == *streamFontFileEnumerator) {
111 return E_OUTOFMEMORY;
112 }
113 return S_OK;
114 }
115 private:
116 StreamFontFileEnumerator(IDWriteFactory* factory, IDWriteFontFileLoader* fontFileLoader);
~StreamFontFileEnumerator()117 virtual ~StreamFontFileEnumerator() { }
118
119 ULONG fRefCount;
120
121 SkTScopedComPtr<IDWriteFactory> fFactory;
122 SkTScopedComPtr<IDWriteFontFile> fCurrentFile;
123 SkTScopedComPtr<IDWriteFontFileLoader> fFontFileLoader;
124 bool fHasNext;
125 };
126
StreamFontFileEnumerator(IDWriteFactory * factory,IDWriteFontFileLoader * fontFileLoader)127 StreamFontFileEnumerator::StreamFontFileEnumerator(IDWriteFactory* factory,
128 IDWriteFontFileLoader* fontFileLoader)
129 : fRefCount(1)
130 , fFactory(SkRefComPtr(factory))
131 , fCurrentFile()
132 , fFontFileLoader(SkRefComPtr(fontFileLoader))
133 , fHasNext(true)
134 { }
135
QueryInterface(REFIID iid,void ** ppvObject)136 HRESULT StreamFontFileEnumerator::QueryInterface(REFIID iid, void** ppvObject) {
137 if (iid == IID_IUnknown || iid == __uuidof(IDWriteFontFileEnumerator)) {
138 *ppvObject = this;
139 AddRef();
140 return S_OK;
141 } else {
142 *ppvObject = nullptr;
143 return E_NOINTERFACE;
144 }
145 }
146
AddRef()147 ULONG StreamFontFileEnumerator::AddRef() {
148 return InterlockedIncrement(&fRefCount);
149 }
150
Release()151 ULONG StreamFontFileEnumerator::Release() {
152 ULONG newCount = InterlockedDecrement(&fRefCount);
153 if (0 == newCount) {
154 delete this;
155 }
156 return newCount;
157 }
158
MoveNext(BOOL * hasCurrentFile)159 HRESULT StreamFontFileEnumerator::MoveNext(BOOL* hasCurrentFile) {
160 *hasCurrentFile = FALSE;
161
162 if (!fHasNext) {
163 return S_OK;
164 }
165 fHasNext = false;
166
167 UINT32 dummy = 0;
168 HR(fFactory->CreateCustomFontFileReference(
169 &dummy, //cannot be nullptr
170 sizeof(dummy), //even if this is 0
171 fFontFileLoader.get(),
172 &fCurrentFile));
173
174 *hasCurrentFile = TRUE;
175 return S_OK;
176 }
177
GetCurrentFontFile(IDWriteFontFile ** fontFile)178 HRESULT StreamFontFileEnumerator::GetCurrentFontFile(IDWriteFontFile** fontFile) {
179 if (fCurrentFile.get() == nullptr) {
180 *fontFile = nullptr;
181 return E_FAIL;
182 }
183
184 *fontFile = SkRefComPtr(fCurrentFile.get());
185 return S_OK;
186 }
187
188 ////////////////////////////////////////////////////////////////////////////////
189
190 class StreamFontCollectionLoader : public IDWriteFontCollectionLoader {
191 public:
192 // IUnknown methods
193 virtual HRESULT STDMETHODCALLTYPE QueryInterface(REFIID iid, void** ppvObject);
194 virtual ULONG STDMETHODCALLTYPE AddRef();
195 virtual ULONG STDMETHODCALLTYPE Release();
196
197 // IDWriteFontCollectionLoader methods
198 virtual HRESULT STDMETHODCALLTYPE CreateEnumeratorFromKey(
199 IDWriteFactory* factory,
200 void const* collectionKey,
201 UINT32 collectionKeySize,
202 IDWriteFontFileEnumerator** fontFileEnumerator);
203
Create(IDWriteFontFileLoader * fontFileLoader,StreamFontCollectionLoader ** streamFontCollectionLoader)204 static HRESULT Create(IDWriteFontFileLoader* fontFileLoader,
205 StreamFontCollectionLoader** streamFontCollectionLoader) {
206 *streamFontCollectionLoader = new StreamFontCollectionLoader(fontFileLoader);
207 if (nullptr == *streamFontCollectionLoader) {
208 return E_OUTOFMEMORY;
209 }
210 return S_OK;
211 }
212 private:
StreamFontCollectionLoader(IDWriteFontFileLoader * fontFileLoader)213 StreamFontCollectionLoader(IDWriteFontFileLoader* fontFileLoader)
214 : fRefCount(1)
215 , fFontFileLoader(SkRefComPtr(fontFileLoader))
216 { }
~StreamFontCollectionLoader()217 virtual ~StreamFontCollectionLoader() { }
218
219 ULONG fRefCount;
220 SkTScopedComPtr<IDWriteFontFileLoader> fFontFileLoader;
221 };
222
QueryInterface(REFIID iid,void ** ppvObject)223 HRESULT StreamFontCollectionLoader::QueryInterface(REFIID iid, void** ppvObject) {
224 if (iid == IID_IUnknown || iid == __uuidof(IDWriteFontCollectionLoader)) {
225 *ppvObject = this;
226 AddRef();
227 return S_OK;
228 } else {
229 *ppvObject = nullptr;
230 return E_NOINTERFACE;
231 }
232 }
233
AddRef()234 ULONG StreamFontCollectionLoader::AddRef() {
235 return InterlockedIncrement(&fRefCount);
236 }
237
Release()238 ULONG StreamFontCollectionLoader::Release() {
239 ULONG newCount = InterlockedDecrement(&fRefCount);
240 if (0 == newCount) {
241 delete this;
242 }
243 return newCount;
244 }
245
CreateEnumeratorFromKey(IDWriteFactory * factory,void const * collectionKey,UINT32 collectionKeySize,IDWriteFontFileEnumerator ** fontFileEnumerator)246 HRESULT StreamFontCollectionLoader::CreateEnumeratorFromKey(
247 IDWriteFactory* factory,
248 void const* collectionKey,
249 UINT32 collectionKeySize,
250 IDWriteFontFileEnumerator** fontFileEnumerator)
251 {
252 SkTScopedComPtr<StreamFontFileEnumerator> enumerator;
253 HR(StreamFontFileEnumerator::Create(factory, fFontFileLoader.get(), &enumerator));
254 *fontFileEnumerator = enumerator.release();
255 return S_OK;
256 }
257
258 ////////////////////////////////////////////////////////////////////////////////
259
260 class SkFontMgr_DirectWrite : public SkFontMgr {
261 public:
262 /** localeNameLength must include the null terminator. */
SkFontMgr_DirectWrite(IDWriteFactory * factory,IDWriteFontCollection * fontCollection,IDWriteFontFallback * fallback,WCHAR * localeName,int localeNameLength)263 SkFontMgr_DirectWrite(IDWriteFactory* factory, IDWriteFontCollection* fontCollection,
264 IDWriteFontFallback* fallback, WCHAR* localeName, int localeNameLength)
265 : fFactory(SkRefComPtr(factory))
266 , fFontFallback(SkSafeRefComPtr(fallback))
267 , fFontCollection(SkRefComPtr(fontCollection))
268 , fLocaleName(localeNameLength)
269 {
270 if (!SUCCEEDED(fFactory->QueryInterface(&fFactory2))) {
271 // IUnknown::QueryInterface states that if it fails, punk will be set to nullptr.
272 // http://blogs.msdn.com/b/oldnewthing/archive/2004/03/26/96777.aspx
273 SkASSERT_RELEASE(nullptr == fFactory2.get());
274 }
275 if (fFontFallback.get()) {
276 // factory must be provided if fallback is non-null, else the fallback will not be used.
277 SkASSERT(fFactory2.get());
278 }
279 memcpy(fLocaleName.get(), localeName, localeNameLength * sizeof(WCHAR));
280 }
281
282 protected:
283 int onCountFamilies() const override;
284 void onGetFamilyName(int index, SkString* familyName) const override;
285 SkFontStyleSet* onCreateStyleSet(int index) const override;
286 SkFontStyleSet* onMatchFamily(const char familyName[]) const override;
287 SkTypeface* onMatchFamilyStyle(const char familyName[],
288 const SkFontStyle& fontstyle) const override;
289 SkTypeface* onMatchFamilyStyleCharacter(const char familyName[], const SkFontStyle&,
290 const char* bcp47[], int bcp47Count,
291 SkUnichar character) const override;
292 SkTypeface* onMatchFaceStyle(const SkTypeface* familyMember,
293 const SkFontStyle& fontstyle) const override;
294 SkTypeface* onCreateFromStream(SkStreamAsset* stream, int ttcIndex) const override;
295 SkTypeface* onCreateFromData(SkData* data, int ttcIndex) const override;
296 SkTypeface* onCreateFromFile(const char path[], int ttcIndex) const override;
297 SkTypeface* onLegacyCreateTypeface(const char familyName[], SkFontStyle) const override;
298
299 private:
300 HRESULT getByFamilyName(const WCHAR familyName[], IDWriteFontFamily** fontFamily) const;
301 HRESULT getDefaultFontFamily(IDWriteFontFamily** fontFamily) const;
302
303 /** Creates a typeface using a typeface cache. */
304 SkTypeface* createTypefaceFromDWriteFont(IDWriteFontFace* fontFace,
305 IDWriteFont* font,
306 IDWriteFontFamily* fontFamily) const;
307
308 SkTScopedComPtr<IDWriteFactory> fFactory;
309 SkTScopedComPtr<IDWriteFactory2> fFactory2;
310 SkTScopedComPtr<IDWriteFontFallback> fFontFallback;
311 SkTScopedComPtr<IDWriteFontCollection> fFontCollection;
312 SkSMallocWCHAR fLocaleName;
313 mutable SkMutex fTFCacheMutex;
314 mutable SkTypefaceCache fTFCache;
315
316 friend class SkFontStyleSet_DirectWrite;
317 friend class FontFallbackRenderer;
318 };
319
320 class SkFontStyleSet_DirectWrite : public SkFontStyleSet {
321 public:
SkFontStyleSet_DirectWrite(const SkFontMgr_DirectWrite * fontMgr,IDWriteFontFamily * fontFamily)322 SkFontStyleSet_DirectWrite(const SkFontMgr_DirectWrite* fontMgr,
323 IDWriteFontFamily* fontFamily)
324 : fFontMgr(SkRef(fontMgr))
325 , fFontFamily(SkRefComPtr(fontFamily))
326 { }
327
328 int count() override;
329 void getStyle(int index, SkFontStyle* fs, SkString* styleName) override;
330 SkTypeface* createTypeface(int index) override;
331 SkTypeface* matchStyle(const SkFontStyle& pattern) override;
332
333 private:
334 sk_sp<const SkFontMgr_DirectWrite> fFontMgr;
335 SkTScopedComPtr<IDWriteFontFamily> fFontFamily;
336 };
337
are_same(IUnknown * a,IUnknown * b,bool & same)338 static HRESULT are_same(IUnknown* a, IUnknown* b, bool& same) {
339 SkTScopedComPtr<IUnknown> iunkA;
340 HRM(a->QueryInterface(&iunkA), "Failed to QI<IUnknown> for a.");
341
342 SkTScopedComPtr<IUnknown> iunkB;
343 HRM(b->QueryInterface(&iunkB), "Failed to QI<IUnknown> for b.");
344
345 same = (iunkA.get() == iunkB.get());
346 return S_OK;
347 }
348
349 struct ProtoDWriteTypeface {
350 IDWriteFontFace* fDWriteFontFace;
351 IDWriteFont* fDWriteFont;
352 IDWriteFontFamily* fDWriteFontFamily;
353 };
354
FindByDWriteFont(SkTypeface * cached,void * ctx)355 static bool FindByDWriteFont(SkTypeface* cached, void* ctx) {
356 DWriteFontTypeface* cshFace = reinterpret_cast<DWriteFontTypeface*>(cached);
357 ProtoDWriteTypeface* ctxFace = reinterpret_cast<ProtoDWriteTypeface*>(ctx);
358 bool same;
359
360 //Check to see if the two fonts are identical.
361 HRB(are_same(cshFace->fDWriteFont.get(), ctxFace->fDWriteFont, same));
362 if (same) {
363 return true;
364 }
365
366 HRB(are_same(cshFace->fDWriteFontFace.get(), ctxFace->fDWriteFontFace, same));
367 if (same) {
368 return true;
369 }
370
371 //Check if the two fonts share the same loader and have the same key.
372 UINT32 cshNumFiles;
373 UINT32 ctxNumFiles;
374 HRB(cshFace->fDWriteFontFace->GetFiles(&cshNumFiles, nullptr));
375 HRB(ctxFace->fDWriteFontFace->GetFiles(&ctxNumFiles, nullptr));
376 if (cshNumFiles != ctxNumFiles) {
377 return false;
378 }
379
380 SkTScopedComPtr<IDWriteFontFile> cshFontFile;
381 SkTScopedComPtr<IDWriteFontFile> ctxFontFile;
382 HRB(cshFace->fDWriteFontFace->GetFiles(&cshNumFiles, &cshFontFile));
383 HRB(ctxFace->fDWriteFontFace->GetFiles(&ctxNumFiles, &ctxFontFile));
384
385 //for (each file) { //we currently only admit fonts from one file.
386 SkTScopedComPtr<IDWriteFontFileLoader> cshFontFileLoader;
387 SkTScopedComPtr<IDWriteFontFileLoader> ctxFontFileLoader;
388 HRB(cshFontFile->GetLoader(&cshFontFileLoader));
389 HRB(ctxFontFile->GetLoader(&ctxFontFileLoader));
390 HRB(are_same(cshFontFileLoader.get(), ctxFontFileLoader.get(), same));
391 if (!same) {
392 return false;
393 }
394 //}
395
396 const void* cshRefKey;
397 UINT32 cshRefKeySize;
398 const void* ctxRefKey;
399 UINT32 ctxRefKeySize;
400 HRB(cshFontFile->GetReferenceKey(&cshRefKey, &cshRefKeySize));
401 HRB(ctxFontFile->GetReferenceKey(&ctxRefKey, &ctxRefKeySize));
402 if (cshRefKeySize != ctxRefKeySize) {
403 return false;
404 }
405 if (0 != memcmp(cshRefKey, ctxRefKey, ctxRefKeySize)) {
406 return false;
407 }
408
409 //TODO: better means than comparing name strings?
410 //NOTE: .ttc and fake bold/italic will end up here.
411 SkTScopedComPtr<IDWriteLocalizedStrings> cshFamilyNames;
412 SkTScopedComPtr<IDWriteLocalizedStrings> cshFaceNames;
413 HRB(cshFace->fDWriteFontFamily->GetFamilyNames(&cshFamilyNames));
414 HRB(cshFace->fDWriteFont->GetFaceNames(&cshFaceNames));
415 UINT32 cshFamilyNameLength;
416 UINT32 cshFaceNameLength;
417 HRB(cshFamilyNames->GetStringLength(0, &cshFamilyNameLength));
418 HRB(cshFaceNames->GetStringLength(0, &cshFaceNameLength));
419
420 SkTScopedComPtr<IDWriteLocalizedStrings> ctxFamilyNames;
421 SkTScopedComPtr<IDWriteLocalizedStrings> ctxFaceNames;
422 HRB(ctxFace->fDWriteFontFamily->GetFamilyNames(&ctxFamilyNames));
423 HRB(ctxFace->fDWriteFont->GetFaceNames(&ctxFaceNames));
424 UINT32 ctxFamilyNameLength;
425 UINT32 ctxFaceNameLength;
426 HRB(ctxFamilyNames->GetStringLength(0, &ctxFamilyNameLength));
427 HRB(ctxFaceNames->GetStringLength(0, &ctxFaceNameLength));
428
429 if (cshFamilyNameLength != ctxFamilyNameLength ||
430 cshFaceNameLength != ctxFaceNameLength)
431 {
432 return false;
433 }
434
435 SkSMallocWCHAR cshFamilyName(cshFamilyNameLength+1);
436 SkSMallocWCHAR cshFaceName(cshFaceNameLength+1);
437 HRB(cshFamilyNames->GetString(0, cshFamilyName.get(), cshFamilyNameLength+1));
438 HRB(cshFaceNames->GetString(0, cshFaceName.get(), cshFaceNameLength+1));
439
440 SkSMallocWCHAR ctxFamilyName(ctxFamilyNameLength+1);
441 SkSMallocWCHAR ctxFaceName(ctxFaceNameLength+1);
442 HRB(ctxFamilyNames->GetString(0, ctxFamilyName.get(), ctxFamilyNameLength+1));
443 HRB(ctxFaceNames->GetString(0, ctxFaceName.get(), ctxFaceNameLength+1));
444
445 return wcscmp(cshFamilyName.get(), ctxFamilyName.get()) == 0 &&
446 wcscmp(cshFaceName.get(), ctxFaceName.get()) == 0;
447 }
448
createTypefaceFromDWriteFont(IDWriteFontFace * fontFace,IDWriteFont * font,IDWriteFontFamily * fontFamily) const449 SkTypeface* SkFontMgr_DirectWrite::createTypefaceFromDWriteFont(
450 IDWriteFontFace* fontFace,
451 IDWriteFont* font,
452 IDWriteFontFamily* fontFamily) const {
453 SkAutoMutexAcquire ama(fTFCacheMutex);
454 ProtoDWriteTypeface spec = { fontFace, font, fontFamily };
455 SkTypeface* face = fTFCache.findByProcAndRef(FindByDWriteFont, &spec);
456 if (nullptr == face) {
457 face = DWriteFontTypeface::Create(fFactory.get(), fontFace, font, fontFamily);
458 if (face) {
459 fTFCache.add(face);
460 }
461 }
462 return face;
463 }
464
onCountFamilies() const465 int SkFontMgr_DirectWrite::onCountFamilies() const {
466 return fFontCollection->GetFontFamilyCount();
467 }
468
onGetFamilyName(int index,SkString * familyName) const469 void SkFontMgr_DirectWrite::onGetFamilyName(int index, SkString* familyName) const {
470 SkTScopedComPtr<IDWriteFontFamily> fontFamily;
471 HRVM(fFontCollection->GetFontFamily(index, &fontFamily), "Could not get requested family.");
472
473 SkTScopedComPtr<IDWriteLocalizedStrings> familyNames;
474 HRVM(fontFamily->GetFamilyNames(&familyNames), "Could not get family names.");
475
476 sk_get_locale_string(familyNames.get(), fLocaleName.get(), familyName);
477 }
478
onCreateStyleSet(int index) const479 SkFontStyleSet* SkFontMgr_DirectWrite::onCreateStyleSet(int index) const {
480 SkTScopedComPtr<IDWriteFontFamily> fontFamily;
481 HRNM(fFontCollection->GetFontFamily(index, &fontFamily), "Could not get requested family.");
482
483 return new SkFontStyleSet_DirectWrite(this, fontFamily.get());
484 }
485
onMatchFamily(const char familyName[]) const486 SkFontStyleSet* SkFontMgr_DirectWrite::onMatchFamily(const char familyName[]) const {
487 SkSMallocWCHAR dwFamilyName;
488 HRN(sk_cstring_to_wchar(familyName, &dwFamilyName));
489
490 UINT32 index;
491 BOOL exists;
492 HRNM(fFontCollection->FindFamilyName(dwFamilyName.get(), &index, &exists),
493 "Failed while finding family by name.");
494 if (!exists) {
495 return nullptr;
496 }
497
498 return this->onCreateStyleSet(index);
499 }
500
onMatchFamilyStyle(const char familyName[],const SkFontStyle & fontstyle) const501 SkTypeface* SkFontMgr_DirectWrite::onMatchFamilyStyle(const char familyName[],
502 const SkFontStyle& fontstyle) const {
503 sk_sp<SkFontStyleSet> sset(this->matchFamily(familyName));
504 return sset->matchStyle(fontstyle);
505 }
506
507 class FontFallbackRenderer : public IDWriteTextRenderer {
508 public:
FontFallbackRenderer(const SkFontMgr_DirectWrite * outer,UINT32 character)509 FontFallbackRenderer(const SkFontMgr_DirectWrite* outer, UINT32 character)
510 : fRefCount(1), fOuter(SkSafeRef(outer)), fCharacter(character), fResolvedTypeface(nullptr) {
511 }
512
~FontFallbackRenderer()513 virtual ~FontFallbackRenderer() { }
514
515 // 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)516 virtual HRESULT STDMETHODCALLTYPE DrawGlyphRun(
517 void* clientDrawingContext,
518 FLOAT baselineOriginX,
519 FLOAT baselineOriginY,
520 DWRITE_MEASURING_MODE measuringMode,
521 DWRITE_GLYPH_RUN const* glyphRun,
522 DWRITE_GLYPH_RUN_DESCRIPTION const* glyphRunDescription,
523 IUnknown* clientDrawingEffect) override
524 {
525 SkTScopedComPtr<IDWriteFont> font;
526 HRM(fOuter->fFontCollection->GetFontFromFontFace(glyphRun->fontFace, &font),
527 "Could not get font from font face.");
528
529 // It is possible that the font passed does not actually have the requested character,
530 // due to no font being found and getting the fallback font.
531 // Check that the font actually contains the requested character.
532 BOOL exists;
533 HRM(font->HasCharacter(fCharacter, &exists), "Could not find character.");
534
535 if (exists) {
536 SkTScopedComPtr<IDWriteFontFamily> fontFamily;
537 HRM(font->GetFontFamily(&fontFamily), "Could not get family.");
538 fResolvedTypeface = fOuter->createTypefaceFromDWriteFont(glyphRun->fontFace,
539 font.get(),
540 fontFamily.get());
541 }
542
543 return S_OK;
544 }
545
DrawUnderline(void * clientDrawingContext,FLOAT baselineOriginX,FLOAT baselineOriginY,DWRITE_UNDERLINE const * underline,IUnknown * clientDrawingEffect)546 virtual HRESULT STDMETHODCALLTYPE DrawUnderline(
547 void* clientDrawingContext,
548 FLOAT baselineOriginX,
549 FLOAT baselineOriginY,
550 DWRITE_UNDERLINE const* underline,
551 IUnknown* clientDrawingEffect) override
552 { return E_NOTIMPL; }
553
DrawStrikethrough(void * clientDrawingContext,FLOAT baselineOriginX,FLOAT baselineOriginY,DWRITE_STRIKETHROUGH const * strikethrough,IUnknown * clientDrawingEffect)554 virtual HRESULT STDMETHODCALLTYPE DrawStrikethrough(
555 void* clientDrawingContext,
556 FLOAT baselineOriginX,
557 FLOAT baselineOriginY,
558 DWRITE_STRIKETHROUGH const* strikethrough,
559 IUnknown* clientDrawingEffect) override
560 { return E_NOTIMPL; }
561
DrawInlineObject(void * clientDrawingContext,FLOAT originX,FLOAT originY,IDWriteInlineObject * inlineObject,BOOL isSideways,BOOL isRightToLeft,IUnknown * clientDrawingEffect)562 virtual HRESULT STDMETHODCALLTYPE DrawInlineObject(
563 void* clientDrawingContext,
564 FLOAT originX,
565 FLOAT originY,
566 IDWriteInlineObject* inlineObject,
567 BOOL isSideways,
568 BOOL isRightToLeft,
569 IUnknown* clientDrawingEffect) override
570 { return E_NOTIMPL; }
571
572 // IDWritePixelSnapping methods
IsPixelSnappingDisabled(void * clientDrawingContext,BOOL * isDisabled)573 virtual HRESULT STDMETHODCALLTYPE IsPixelSnappingDisabled(
574 void* clientDrawingContext,
575 BOOL* isDisabled) override
576 {
577 *isDisabled = FALSE;
578 return S_OK;
579 }
580
GetCurrentTransform(void * clientDrawingContext,DWRITE_MATRIX * transform)581 virtual HRESULT STDMETHODCALLTYPE GetCurrentTransform(
582 void* clientDrawingContext,
583 DWRITE_MATRIX* transform) override
584 {
585 const DWRITE_MATRIX ident = { 1.0, 0.0, 0.0, 1.0, 0.0, 0.0 };
586 *transform = ident;
587 return S_OK;
588 }
589
GetPixelsPerDip(void * clientDrawingContext,FLOAT * pixelsPerDip)590 virtual HRESULT STDMETHODCALLTYPE GetPixelsPerDip(
591 void* clientDrawingContext,
592 FLOAT* pixelsPerDip) override
593 {
594 *pixelsPerDip = 1.0f;
595 return S_OK;
596 }
597
598 // IUnknown methods
AddRef()599 ULONG STDMETHODCALLTYPE AddRef() override {
600 return InterlockedIncrement(&fRefCount);
601 }
602
Release()603 ULONG STDMETHODCALLTYPE Release() override {
604 ULONG newCount = InterlockedDecrement(&fRefCount);
605 if (0 == newCount) {
606 delete this;
607 }
608 return newCount;
609 }
610
QueryInterface(IID const & riid,void ** ppvObject)611 virtual HRESULT STDMETHODCALLTYPE QueryInterface(IID const& riid, void** ppvObject) override{
612 if (__uuidof(IUnknown) == riid ||
613 __uuidof(IDWritePixelSnapping) == riid ||
614 __uuidof(IDWriteTextRenderer) == riid)
615 {
616 *ppvObject = this;
617 this->AddRef();
618 return S_OK;
619 }
620 *ppvObject = nullptr;
621 return E_FAIL;
622 }
623
FallbackTypeface()624 SkTypeface* FallbackTypeface() { return fResolvedTypeface; }
625
626 protected:
627 ULONG fRefCount;
628 sk_sp<const SkFontMgr_DirectWrite> fOuter;
629 UINT32 fCharacter;
630 SkTypeface* fResolvedTypeface;
631 };
632
633 class FontFallbackSource : public IDWriteTextAnalysisSource {
634 public:
FontFallbackSource(const WCHAR * string,UINT32 length,const WCHAR * locale,IDWriteNumberSubstitution * numberSubstitution)635 FontFallbackSource(const WCHAR* string, UINT32 length, const WCHAR* locale,
636 IDWriteNumberSubstitution* numberSubstitution)
637 : fString(string)
638 , fLength(length)
639 , fLocale(locale)
640 , fNumberSubstitution(numberSubstitution)
641 { }
642
~FontFallbackSource()643 virtual ~FontFallbackSource() { }
644
645 // IDWriteTextAnalysisSource methods
GetTextAtPosition(UINT32 textPosition,WCHAR const ** textString,UINT32 * textLength)646 virtual HRESULT STDMETHODCALLTYPE GetTextAtPosition(
647 UINT32 textPosition,
648 WCHAR const** textString,
649 UINT32* textLength) override
650 {
651 if (fLength <= textPosition) {
652 *textString = nullptr;
653 *textLength = 0;
654 return S_OK;
655 }
656 *textString = fString + textPosition;
657 *textLength = fLength - textPosition;
658 return S_OK;
659 }
660
GetTextBeforePosition(UINT32 textPosition,WCHAR const ** textString,UINT32 * textLength)661 virtual HRESULT STDMETHODCALLTYPE GetTextBeforePosition(
662 UINT32 textPosition,
663 WCHAR const** textString,
664 UINT32* textLength) override
665 {
666 if (textPosition < 1 || fLength <= textPosition) {
667 *textString = nullptr;
668 *textLength = 0;
669 return S_OK;
670 }
671 *textString = fString;
672 *textLength = textPosition;
673 return S_OK;
674 }
675
GetParagraphReadingDirection()676 virtual DWRITE_READING_DIRECTION STDMETHODCALLTYPE GetParagraphReadingDirection() override {
677 // TODO: this is also interesting.
678 return DWRITE_READING_DIRECTION_LEFT_TO_RIGHT;
679 }
680
GetLocaleName(UINT32 textPosition,UINT32 * textLength,WCHAR const ** localeName)681 virtual HRESULT STDMETHODCALLTYPE GetLocaleName(
682 UINT32 textPosition,
683 UINT32* textLength,
684 WCHAR const** localeName) override
685 {
686 *localeName = fLocale;
687 return S_OK;
688 }
689
GetNumberSubstitution(UINT32 textPosition,UINT32 * textLength,IDWriteNumberSubstitution ** numberSubstitution)690 virtual HRESULT STDMETHODCALLTYPE GetNumberSubstitution(
691 UINT32 textPosition,
692 UINT32* textLength,
693 IDWriteNumberSubstitution** numberSubstitution) override
694 {
695 *numberSubstitution = fNumberSubstitution;
696 return S_OK;
697 }
698
699 // IUnknown methods
AddRef()700 ULONG STDMETHODCALLTYPE AddRef() override {
701 return InterlockedIncrement(&fRefCount);
702 }
703
Release()704 ULONG STDMETHODCALLTYPE Release() override {
705 ULONG newCount = InterlockedDecrement(&fRefCount);
706 if (0 == newCount) {
707 delete this;
708 }
709 return newCount;
710 }
711
QueryInterface(IID const & riid,void ** ppvObject)712 virtual HRESULT STDMETHODCALLTYPE QueryInterface(IID const& riid, void** ppvObject) override{
713 if (__uuidof(IUnknown) == riid ||
714 __uuidof(IDWriteTextAnalysisSource) == riid)
715 {
716 *ppvObject = this;
717 this->AddRef();
718 return S_OK;
719 }
720 *ppvObject = nullptr;
721 return E_FAIL;
722 }
723
724 protected:
725 ULONG fRefCount;
726 const WCHAR* fString;
727 UINT32 fLength;
728 const WCHAR* fLocale;
729 IDWriteNumberSubstitution* fNumberSubstitution;
730 };
731
onMatchFamilyStyleCharacter(const char familyName[],const SkFontStyle & style,const char * bcp47[],int bcp47Count,SkUnichar character) const732 SkTypeface* SkFontMgr_DirectWrite::onMatchFamilyStyleCharacter(const char familyName[],
733 const SkFontStyle& style,
734 const char* bcp47[], int bcp47Count,
735 SkUnichar character) const
736 {
737 const DWriteStyle dwStyle(style);
738
739 const WCHAR* dwFamilyName = nullptr;
740 SkSMallocWCHAR dwFamilyNameLocal;
741 if (familyName) {
742 HRN(sk_cstring_to_wchar(familyName, &dwFamilyNameLocal));
743 dwFamilyName = dwFamilyNameLocal;
744 }
745
746 WCHAR str[16];
747 UINT32 strLen = static_cast<UINT32>(
748 SkUTF16_FromUnichar(character, reinterpret_cast<uint16_t*>(str)));
749
750 const SkSMallocWCHAR* dwBcp47;
751 SkSMallocWCHAR dwBcp47Local;
752 if (bcp47Count < 1) {
753 dwBcp47 = &fLocaleName;
754 } else {
755 // TODO: support fallback stack.
756 // TODO: DirectWrite supports 'zh-CN' or 'zh-Hans', but 'zh' misses completely
757 // and may produce a Japanese font.
758 HRN(sk_cstring_to_wchar(bcp47[bcp47Count - 1], &dwBcp47Local));
759 dwBcp47 = &dwBcp47Local;
760 }
761
762 if (fFactory2.get()) {
763 SkTScopedComPtr<IDWriteFontFallback> systemFontFallback;
764 IDWriteFontFallback* fontFallback = fFontFallback.get();
765 if (!fontFallback) {
766 HRNM(fFactory2->GetSystemFontFallback(&systemFontFallback),
767 "Could not get system fallback.");
768 fontFallback = systemFontFallback.get();
769 }
770
771 SkTScopedComPtr<IDWriteNumberSubstitution> numberSubstitution;
772 HRNM(fFactory2->CreateNumberSubstitution(DWRITE_NUMBER_SUBSTITUTION_METHOD_NONE, nullptr, TRUE,
773 &numberSubstitution),
774 "Could not create number substitution.");
775 SkTScopedComPtr<FontFallbackSource> fontFallbackSource(
776 new FontFallbackSource(str, strLen, *dwBcp47, numberSubstitution.get()));
777
778 UINT32 mappedLength;
779 SkTScopedComPtr<IDWriteFont> font;
780 FLOAT scale;
781 HRNM(fontFallback->MapCharacters(fontFallbackSource.get(),
782 0, // textPosition,
783 strLen,
784 fFontCollection.get(),
785 dwFamilyName,
786 dwStyle.fWeight,
787 dwStyle.fSlant,
788 dwStyle.fWidth,
789 &mappedLength,
790 &font,
791 &scale),
792 "Could not map characters");
793 if (!font.get()) {
794 return nullptr;
795 }
796
797 SkTScopedComPtr<IDWriteFontFace> fontFace;
798 HRNM(font->CreateFontFace(&fontFace), "Could not get font face from font.");
799
800 SkTScopedComPtr<IDWriteFontFamily> fontFamily;
801 HRNM(font->GetFontFamily(&fontFamily), "Could not get family from font.");
802 return this->createTypefaceFromDWriteFont(fontFace.get(), font.get(), fontFamily.get());
803 }
804
805 SkTScopedComPtr<IDWriteTextFormat> fallbackFormat;
806 HRNM(fFactory->CreateTextFormat(dwFamilyName ? dwFamilyName : L"",
807 fFontCollection.get(),
808 dwStyle.fWeight,
809 dwStyle.fSlant,
810 dwStyle.fWidth,
811 72.0f,
812 *dwBcp47,
813 &fallbackFormat),
814 "Could not create text format.");
815
816 SkTScopedComPtr<IDWriteTextLayout> fallbackLayout;
817 HRNM(fFactory->CreateTextLayout(str, strLen, fallbackFormat.get(),
818 200.0f, 200.0f,
819 &fallbackLayout),
820 "Could not create text layout.");
821
822 SkTScopedComPtr<FontFallbackRenderer> fontFallbackRenderer(
823 new FontFallbackRenderer(this, character));
824
825 HRNM(fallbackLayout->Draw(nullptr, fontFallbackRenderer.get(), 50.0f, 50.0f),
826 "Could not draw layout with renderer.");
827
828 return fontFallbackRenderer->FallbackTypeface();
829 }
830
onMatchFaceStyle(const SkTypeface * familyMember,const SkFontStyle & fontstyle) const831 SkTypeface* SkFontMgr_DirectWrite::onMatchFaceStyle(const SkTypeface* familyMember,
832 const SkFontStyle& fontstyle) const {
833 SkString familyName;
834 SkFontStyleSet_DirectWrite sset(
835 this, ((DWriteFontTypeface*)familyMember)->fDWriteFontFamily.get()
836 );
837 return sset.matchStyle(fontstyle);
838 }
839
840 template <typename T> class SkAutoIDWriteUnregister {
841 public:
SkAutoIDWriteUnregister(IDWriteFactory * factory,T * unregister)842 SkAutoIDWriteUnregister(IDWriteFactory* factory, T* unregister)
843 : fFactory(factory), fUnregister(unregister)
844 { }
845
~SkAutoIDWriteUnregister()846 ~SkAutoIDWriteUnregister() {
847 if (fUnregister) {
848 unregister(fFactory, fUnregister);
849 }
850 }
851
detatch()852 T* detatch() {
853 T* old = fUnregister;
854 fUnregister = nullptr;
855 return old;
856 }
857
858 private:
unregister(IDWriteFactory * factory,IDWriteFontFileLoader * unregister)859 HRESULT unregister(IDWriteFactory* factory, IDWriteFontFileLoader* unregister) {
860 return factory->UnregisterFontFileLoader(unregister);
861 }
862
unregister(IDWriteFactory * factory,IDWriteFontCollectionLoader * unregister)863 HRESULT unregister(IDWriteFactory* factory, IDWriteFontCollectionLoader* unregister) {
864 return factory->UnregisterFontCollectionLoader(unregister);
865 }
866
867 IDWriteFactory* fFactory;
868 T* fUnregister;
869 };
870
onCreateFromStream(SkStreamAsset * stream,int ttcIndex) const871 SkTypeface* SkFontMgr_DirectWrite::onCreateFromStream(SkStreamAsset* stream, int ttcIndex) const {
872 SkTScopedComPtr<StreamFontFileLoader> fontFileLoader;
873 // This transfers ownership of stream to the new object.
874 HRN(StreamFontFileLoader::Create(stream, &fontFileLoader));
875 HRN(fFactory->RegisterFontFileLoader(fontFileLoader.get()));
876 SkAutoIDWriteUnregister<StreamFontFileLoader> autoUnregisterFontFileLoader(
877 fFactory.get(), fontFileLoader.get());
878
879 SkTScopedComPtr<StreamFontCollectionLoader> fontCollectionLoader;
880 HRN(StreamFontCollectionLoader::Create(fontFileLoader.get(), &fontCollectionLoader));
881 HRN(fFactory->RegisterFontCollectionLoader(fontCollectionLoader.get()));
882 SkAutoIDWriteUnregister<StreamFontCollectionLoader> autoUnregisterFontCollectionLoader(
883 fFactory.get(), fontCollectionLoader.get());
884
885 SkTScopedComPtr<IDWriteFontCollection> fontCollection;
886 HRN(fFactory->CreateCustomFontCollection(fontCollectionLoader.get(), nullptr, 0, &fontCollection));
887
888 // Find the first non-simulated font which has the given ttc index.
889 UINT32 familyCount = fontCollection->GetFontFamilyCount();
890 for (UINT32 familyIndex = 0; familyIndex < familyCount; ++familyIndex) {
891 SkTScopedComPtr<IDWriteFontFamily> fontFamily;
892 HRN(fontCollection->GetFontFamily(familyIndex, &fontFamily));
893
894 UINT32 fontCount = fontFamily->GetFontCount();
895 for (UINT32 fontIndex = 0; fontIndex < fontCount; ++fontIndex) {
896 SkTScopedComPtr<IDWriteFont> font;
897 HRN(fontFamily->GetFont(fontIndex, &font));
898 if (font->GetSimulations() != DWRITE_FONT_SIMULATIONS_NONE) {
899 continue;
900 }
901
902 SkTScopedComPtr<IDWriteFontFace> fontFace;
903 HRN(font->CreateFontFace(&fontFace));
904
905 UINT32 faceIndex = fontFace->GetIndex();
906 if (faceIndex == ttcIndex) {
907 return DWriteFontTypeface::Create(fFactory.get(),
908 fontFace.get(), font.get(), fontFamily.get(),
909 autoUnregisterFontFileLoader.detatch(),
910 autoUnregisterFontCollectionLoader.detatch());
911 }
912 }
913 }
914
915 return nullptr;
916 }
917
onCreateFromData(SkData * data,int ttcIndex) const918 SkTypeface* SkFontMgr_DirectWrite::onCreateFromData(SkData* data, int ttcIndex) const {
919 return this->createFromStream(new SkMemoryStream(sk_ref_sp(data)), ttcIndex);
920 }
921
onCreateFromFile(const char path[],int ttcIndex) const922 SkTypeface* SkFontMgr_DirectWrite::onCreateFromFile(const char path[], int ttcIndex) const {
923 return this->createFromStream(SkStream::MakeFromFile(path).release(), ttcIndex);
924 }
925
getByFamilyName(const WCHAR wideFamilyName[],IDWriteFontFamily ** fontFamily) const926 HRESULT SkFontMgr_DirectWrite::getByFamilyName(const WCHAR wideFamilyName[],
927 IDWriteFontFamily** fontFamily) const {
928 UINT32 index;
929 BOOL exists;
930 HR(fFontCollection->FindFamilyName(wideFamilyName, &index, &exists));
931
932 if (exists) {
933 HR(fFontCollection->GetFontFamily(index, fontFamily));
934 }
935 return S_OK;
936 }
937
getDefaultFontFamily(IDWriteFontFamily ** fontFamily) const938 HRESULT SkFontMgr_DirectWrite::getDefaultFontFamily(IDWriteFontFamily** fontFamily) const {
939 NONCLIENTMETRICSW metrics;
940 metrics.cbSize = sizeof(metrics);
941 if (0 == SystemParametersInfoW(SPI_GETNONCLIENTMETRICS, sizeof(metrics), &metrics, 0)) {
942 return E_UNEXPECTED;
943 }
944 HRM(this->getByFamilyName(metrics.lfMessageFont.lfFaceName, fontFamily),
945 "Could not create DWrite font family from LOGFONT.");
946 return S_OK;
947 }
948
onLegacyCreateTypeface(const char familyName[],SkFontStyle style) const949 SkTypeface* SkFontMgr_DirectWrite::onLegacyCreateTypeface(const char familyName[],
950 SkFontStyle style) const {
951 SkTScopedComPtr<IDWriteFontFamily> fontFamily;
952 if (familyName) {
953 SkSMallocWCHAR wideFamilyName;
954 if (SUCCEEDED(sk_cstring_to_wchar(familyName, &wideFamilyName))) {
955 this->getByFamilyName(wideFamilyName, &fontFamily);
956 }
957 }
958
959 if (nullptr == fontFamily.get()) {
960 // No family with given name, try default.
961 this->getDefaultFontFamily(&fontFamily);
962 }
963
964 if (nullptr == fontFamily.get()) {
965 // Could not obtain the default font.
966 HRNM(fFontCollection->GetFontFamily(0, &fontFamily),
967 "Could not get default-default font family.");
968 }
969
970 SkTScopedComPtr<IDWriteFont> font;
971 DWriteStyle dwStyle(style);
972 HRNM(fontFamily->GetFirstMatchingFont(dwStyle.fWeight, dwStyle.fWidth, dwStyle.fSlant, &font),
973 "Could not get matching font.");
974
975 SkTScopedComPtr<IDWriteFontFace> fontFace;
976 HRNM(font->CreateFontFace(&fontFace), "Could not create font face.");
977
978 return this->createTypefaceFromDWriteFont(fontFace.get(), font.get(), fontFamily.get());
979 }
980
981 ///////////////////////////////////////////////////////////////////////////////
982
count()983 int SkFontStyleSet_DirectWrite::count() {
984 return fFontFamily->GetFontCount();
985 }
986
createTypeface(int index)987 SkTypeface* SkFontStyleSet_DirectWrite::createTypeface(int index) {
988 SkTScopedComPtr<IDWriteFont> font;
989 HRNM(fFontFamily->GetFont(index, &font), "Could not get font.");
990
991 SkTScopedComPtr<IDWriteFontFace> fontFace;
992 HRNM(font->CreateFontFace(&fontFace), "Could not create font face.");
993
994 return fFontMgr->createTypefaceFromDWriteFont(fontFace.get(), font.get(), fFontFamily.get());
995 }
996
getStyle(int index,SkFontStyle * fs,SkString * styleName)997 void SkFontStyleSet_DirectWrite::getStyle(int index, SkFontStyle* fs, SkString* styleName) {
998 SkTScopedComPtr<IDWriteFont> font;
999 HRVM(fFontFamily->GetFont(index, &font), "Could not get font.");
1000
1001 if (fs) {
1002 *fs = get_style(font.get());
1003 }
1004
1005 if (styleName) {
1006 SkTScopedComPtr<IDWriteLocalizedStrings> faceNames;
1007 if (SUCCEEDED(font->GetFaceNames(&faceNames))) {
1008 sk_get_locale_string(faceNames.get(), fFontMgr->fLocaleName.get(), styleName);
1009 }
1010 }
1011 }
1012
matchStyle(const SkFontStyle & pattern)1013 SkTypeface* SkFontStyleSet_DirectWrite::matchStyle(const SkFontStyle& pattern) {
1014 SkTScopedComPtr<IDWriteFont> font;
1015 DWriteStyle dwStyle(pattern);
1016 // TODO: perhaps use GetMatchingFonts and get the least simulated?
1017 HRNM(fFontFamily->GetFirstMatchingFont(dwStyle.fWeight, dwStyle.fWidth, dwStyle.fSlant, &font),
1018 "Could not match font in family.");
1019
1020 SkTScopedComPtr<IDWriteFontFace> fontFace;
1021 HRNM(font->CreateFontFace(&fontFace), "Could not create font face.");
1022
1023 return fFontMgr->createTypefaceFromDWriteFont(fontFace.get(), font.get(),
1024 fFontFamily.get());
1025 }
1026
1027 ////////////////////////////////////////////////////////////////////////////////
1028 #include "SkTypeface_win.h"
1029
SkFontMgr_New_DirectWrite(IDWriteFactory * factory,IDWriteFontCollection * collection)1030 SK_API sk_sp<SkFontMgr> SkFontMgr_New_DirectWrite(IDWriteFactory* factory,
1031 IDWriteFontCollection* collection) {
1032 return SkFontMgr_New_DirectWrite(factory, collection, nullptr);
1033 }
1034
SkFontMgr_New_DirectWrite(IDWriteFactory * factory,IDWriteFontCollection * collection,IDWriteFontFallback * fallback)1035 SK_API sk_sp<SkFontMgr> SkFontMgr_New_DirectWrite(IDWriteFactory* factory,
1036 IDWriteFontCollection* collection,
1037 IDWriteFontFallback* fallback) {
1038 if (nullptr == factory) {
1039 factory = sk_get_dwrite_factory();
1040 if (nullptr == factory) {
1041 return nullptr;
1042 }
1043 }
1044
1045 SkTScopedComPtr<IDWriteFontCollection> systemFontCollection;
1046 if (nullptr == collection) {
1047 HRNM(factory->GetSystemFontCollection(&systemFontCollection, FALSE),
1048 "Could not get system font collection.");
1049 collection = systemFontCollection.get();
1050 }
1051
1052 WCHAR localeNameStorage[LOCALE_NAME_MAX_LENGTH];
1053 WCHAR* localeName = nullptr;
1054 int localeNameLen = 0;
1055
1056 // Dynamically load GetUserDefaultLocaleName function, as it is not available on XP.
1057 SkGetUserDefaultLocaleNameProc getUserDefaultLocaleNameProc = nullptr;
1058 HRESULT hr = SkGetGetUserDefaultLocaleNameProc(&getUserDefaultLocaleNameProc);
1059 if (nullptr == getUserDefaultLocaleNameProc) {
1060 SK_TRACEHR(hr, "Could not get GetUserDefaultLocaleName.");
1061 } else {
1062 localeNameLen = getUserDefaultLocaleNameProc(localeNameStorage, LOCALE_NAME_MAX_LENGTH);
1063 if (localeNameLen) {
1064 localeName = localeNameStorage;
1065 };
1066 }
1067
1068 return sk_make_sp<SkFontMgr_DirectWrite>(factory, collection, fallback,
1069 localeName, localeNameLen);
1070 }
1071
1072 #include "SkFontMgr_indirect.h"
SkFontMgr_New_DirectWriteRenderer(sk_sp<SkRemotableFontMgr> proxy)1073 SK_API sk_sp<SkFontMgr> SkFontMgr_New_DirectWriteRenderer(sk_sp<SkRemotableFontMgr> proxy) {
1074 sk_sp<SkFontMgr> impl(SkFontMgr_New_DirectWrite());
1075 if (!impl) {
1076 return nullptr;
1077 }
1078 return sk_make_sp<SkFontMgr_Indirect>(std::move(impl), std::move(proxy));
1079 }
1080 #endif//defined(SK_BUILD_FOR_WIN32)
1081