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 "SkTypes.h"
8 #if defined(SK_BUILD_FOR_WIN32)
9
10 #include "SkDWrite.h"
11 #include "SkDWriteFontFileStream.h"
12 #include "SkDataTable.h"
13 #include "SkHRESULT.h"
14 #include "SkMutex.h"
15 #include "SkRemotableFontMgr.h"
16 #include "SkStream.h"
17 #include "SkString.h"
18 #include "SkTArray.h"
19 #include "SkTScopedComPtr.h"
20 #include "SkTypeface_win.h"
21 #include "SkTypes.h"
22 #include "SkUtils.h"
23
24 #include <dwrite.h>
25
26 class SK_API SkRemotableFontMgr_DirectWrite : public SkRemotableFontMgr {
27 private:
28 struct DataId {
29 IUnknown* fLoader; // In COM only IUnknown pointers may be safely used for identity.
30 void* fKey;
31 UINT32 fKeySize;
32
DataIdSkRemotableFontMgr_DirectWrite::DataId33 DataId() { }
34
DataIdSkRemotableFontMgr_DirectWrite::DataId35 DataId(DataId&& that) : fLoader(that.fLoader), fKey(that.fKey), fKeySize(that.fKeySize) {
36 that.fLoader = nullptr;
37 that.fKey = nullptr;
38 SkDEBUGCODE(that.fKeySize = 0xFFFFFFFF;)
39 }
40
~DataIdSkRemotableFontMgr_DirectWrite::DataId41 ~DataId() {
42 if (fLoader) {
43 fLoader->Release();
44 }
45 sk_free(fKey);
46 }
47 };
48
49 mutable SkTArray<DataId> fDataIdCache;
50 mutable SkMutex fDataIdCacheMutex;
51
FindOrAdd(IDWriteFontFileLoader * fontFileLoader,const void * refKey,UINT32 refKeySize) const52 int FindOrAdd(IDWriteFontFileLoader* fontFileLoader,
53 const void* refKey, UINT32 refKeySize) const
54 {
55 SkTScopedComPtr<IUnknown> fontFileLoaderId;
56 HR_GENERAL(fontFileLoader->QueryInterface(&fontFileLoaderId),
57 "Failed to re-convert to IDWriteFontFileLoader.",
58 SkFontIdentity::kInvalidDataId);
59
60 SkAutoMutexAcquire ama(fDataIdCacheMutex);
61 int count = fDataIdCache.count();
62 int i;
63 for (i = 0; i < count; ++i) {
64 const DataId& current = fDataIdCache[i];
65 if (fontFileLoaderId.get() == current.fLoader &&
66 refKeySize == current.fKeySize &&
67 0 == memcmp(refKey, current.fKey, refKeySize))
68 {
69 return i;
70 }
71 }
72 DataId& added = fDataIdCache.push_back();
73 added.fLoader = fontFileLoaderId.release(); // Ref is passed.
74 added.fKey = sk_malloc_throw(refKeySize);
75 memcpy(added.fKey, refKey, refKeySize);
76 added.fKeySize = refKeySize;
77
78 return i;
79 }
80
81 public:
82
83
84 /** localeNameLength must include the null terminator. */
SkRemotableFontMgr_DirectWrite(IDWriteFontCollection * fontCollection,WCHAR * localeName,int localeNameLength)85 SkRemotableFontMgr_DirectWrite(IDWriteFontCollection* fontCollection,
86 WCHAR* localeName, int localeNameLength)
87 : fFontCollection(SkRefComPtr(fontCollection))
88 , fLocaleName(localeNameLength)
89 {
90 memcpy(fLocaleName.get(), localeName, localeNameLength * sizeof(WCHAR));
91 }
92
getFamilyNames() const93 SkDataTable* getFamilyNames() const override {
94 int count = fFontCollection->GetFontFamilyCount();
95
96 SkDataTableBuilder names(1024);
97 for (int index = 0; index < count; ++index) {
98 SkTScopedComPtr<IDWriteFontFamily> fontFamily;
99 HRNM(fFontCollection->GetFontFamily(index, &fontFamily),
100 "Could not get requested family.");
101
102 SkTScopedComPtr<IDWriteLocalizedStrings> familyNames;
103 HRNM(fontFamily->GetFamilyNames(&familyNames), "Could not get family names.");
104
105 SkString familyName;
106 sk_get_locale_string(familyNames.get(), fLocaleName.get(), &familyName);
107
108 names.appendString(familyName);
109 }
110 return names.detachDataTable();
111 }
112
FontToIdentity(IDWriteFont * font,SkFontIdentity * fontId) const113 HRESULT FontToIdentity(IDWriteFont* font, SkFontIdentity* fontId) const {
114 SkTScopedComPtr<IDWriteFontFace> fontFace;
115 HRM(font->CreateFontFace(&fontFace), "Could not create font face.");
116
117 UINT32 numFiles;
118 HR(fontFace->GetFiles(&numFiles, nullptr));
119 if (numFiles > 1) {
120 return E_FAIL;
121 }
122
123 // data id
124 SkTScopedComPtr<IDWriteFontFile> fontFile;
125 HR(fontFace->GetFiles(&numFiles, &fontFile));
126
127 SkTScopedComPtr<IDWriteFontFileLoader> fontFileLoader;
128 HR(fontFile->GetLoader(&fontFileLoader));
129
130 const void* refKey;
131 UINT32 refKeySize;
132 HR(fontFile->GetReferenceKey(&refKey, &refKeySize));
133
134 fontId->fDataId = FindOrAdd(fontFileLoader.get(), refKey, refKeySize);
135
136 // index
137 fontId->fTtcIndex = fontFace->GetIndex();
138
139 // style
140 SkFontStyle::Slant slant;
141 switch (font->GetStyle()) {
142 case DWRITE_FONT_STYLE_NORMAL:
143 slant = SkFontStyle::kUpright_Slant;
144 break;
145 case DWRITE_FONT_STYLE_OBLIQUE:
146 case DWRITE_FONT_STYLE_ITALIC:
147 slant = SkFontStyle::kItalic_Slant;
148 break;
149 default:
150 SkASSERT(false);
151 }
152
153 int weight = font->GetWeight();
154 int width = font->GetStretch();
155
156 fontId->fFontStyle = SkFontStyle(weight, width, slant);
157 return S_OK;
158 }
159
getIndex(int familyIndex) const160 SkRemotableFontIdentitySet* getIndex(int familyIndex) const override {
161 SkTScopedComPtr<IDWriteFontFamily> fontFamily;
162 HRNM(fFontCollection->GetFontFamily(familyIndex, &fontFamily),
163 "Could not get requested family.");
164
165 int count = fontFamily->GetFontCount();
166 SkFontIdentity* fontIds;
167 SkAutoTUnref<SkRemotableFontIdentitySet> fontIdSet(
168 new SkRemotableFontIdentitySet(count, &fontIds));
169 for (int fontIndex = 0; fontIndex < count; ++fontIndex) {
170 SkTScopedComPtr<IDWriteFont> font;
171 HRNM(fontFamily->GetFont(fontIndex, &font), "Could not get font.");
172
173 HRN(FontToIdentity(font.get(), &fontIds[fontIndex]));
174 }
175 return fontIdSet.detach();
176 }
177
matchIndexStyle(int familyIndex,const SkFontStyle & pattern) const178 virtual SkFontIdentity matchIndexStyle(int familyIndex,
179 const SkFontStyle& pattern) const override
180 {
181 SkFontIdentity identity = { SkFontIdentity::kInvalidDataId };
182
183 SkTScopedComPtr<IDWriteFontFamily> fontFamily;
184 HR_GENERAL(fFontCollection->GetFontFamily(familyIndex, &fontFamily),
185 "Could not get requested family.",
186 identity);
187
188 const DWriteStyle dwStyle(pattern);
189 SkTScopedComPtr<IDWriteFont> font;
190 HR_GENERAL(fontFamily->GetFirstMatchingFont(dwStyle.fWeight, dwStyle.fWidth,
191 dwStyle.fSlant, &font),
192 "Could not match font in family.",
193 identity);
194
195 HR_GENERAL(FontToIdentity(font.get(), &identity), nullptr, identity);
196
197 return identity;
198 }
199
getDefaultFontFamilyName(SkSMallocWCHAR * name)200 static HRESULT getDefaultFontFamilyName(SkSMallocWCHAR* name) {
201 NONCLIENTMETRICSW metrics;
202 metrics.cbSize = sizeof(metrics);
203 if (0 == SystemParametersInfoW(SPI_GETNONCLIENTMETRICS,
204 sizeof(metrics),
205 &metrics,
206 0)) {
207 return E_UNEXPECTED;
208 }
209
210 size_t len = wcsnlen_s(metrics.lfMessageFont.lfFaceName, LF_FACESIZE) + 1;
211 if (0 != wcsncpy_s(name->reset(len), len, metrics.lfMessageFont.lfFaceName, _TRUNCATE)) {
212 return E_UNEXPECTED;
213 }
214
215 return S_OK;
216 }
217
matchName(const char familyName[]) const218 SkRemotableFontIdentitySet* matchName(const char familyName[]) const override {
219 SkSMallocWCHAR dwFamilyName;
220 if (nullptr == familyName) {
221 HR_GENERAL(getDefaultFontFamilyName(&dwFamilyName),
222 nullptr, SkRemotableFontIdentitySet::NewEmpty());
223 } else {
224 HR_GENERAL(sk_cstring_to_wchar(familyName, &dwFamilyName),
225 nullptr, SkRemotableFontIdentitySet::NewEmpty());
226 }
227
228 UINT32 index;
229 BOOL exists;
230 HR_GENERAL(fFontCollection->FindFamilyName(dwFamilyName.get(), &index, &exists),
231 "Failed while finding family by name.",
232 SkRemotableFontIdentitySet::NewEmpty());
233 if (!exists) {
234 return SkRemotableFontIdentitySet::NewEmpty();
235 }
236
237 return this->getIndex(index);
238 }
239
matchNameStyle(const char familyName[],const SkFontStyle & style) const240 virtual SkFontIdentity matchNameStyle(const char familyName[],
241 const SkFontStyle& style) const override
242 {
243 SkFontIdentity identity = { SkFontIdentity::kInvalidDataId };
244
245 SkSMallocWCHAR dwFamilyName;
246 if (nullptr == familyName) {
247 HR_GENERAL(getDefaultFontFamilyName(&dwFamilyName), nullptr, identity);
248 } else {
249 HR_GENERAL(sk_cstring_to_wchar(familyName, &dwFamilyName), nullptr, identity);
250 }
251
252 UINT32 index;
253 BOOL exists;
254 HR_GENERAL(fFontCollection->FindFamilyName(dwFamilyName.get(), &index, &exists),
255 "Failed while finding family by name.",
256 identity);
257 if (!exists) {
258 return identity;
259 }
260
261 return this->matchIndexStyle(index, style);
262 }
263
264 class FontFallbackRenderer : public IDWriteTextRenderer {
265 public:
FontFallbackRenderer(const SkRemotableFontMgr_DirectWrite * outer,UINT32 character)266 FontFallbackRenderer(const SkRemotableFontMgr_DirectWrite* outer, UINT32 character)
267 : fRefCount(1), fOuter(SkSafeRef(outer)), fCharacter(character) {
268 fIdentity.fDataId = SkFontIdentity::kInvalidDataId;
269 }
270
~FontFallbackRenderer()271 virtual ~FontFallbackRenderer() { }
272
273 // 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)274 virtual HRESULT STDMETHODCALLTYPE DrawGlyphRun(
275 void* clientDrawingContext,
276 FLOAT baselineOriginX,
277 FLOAT baselineOriginY,
278 DWRITE_MEASURING_MODE measuringMode,
279 DWRITE_GLYPH_RUN const* glyphRun,
280 DWRITE_GLYPH_RUN_DESCRIPTION const* glyphRunDescription,
281 IUnknown* clientDrawingEffect) override
282 {
283 SkTScopedComPtr<IDWriteFont> font;
284 HRM(fOuter->fFontCollection->GetFontFromFontFace(glyphRun->fontFace, &font),
285 "Could not get font from font face.");
286
287 // It is possible that the font passed does not actually have the requested character,
288 // due to no font being found and getting the fallback font.
289 // Check that the font actually contains the requested character.
290 BOOL exists;
291 HRM(font->HasCharacter(fCharacter, &exists), "Could not find character.");
292
293 if (exists) {
294 HR(fOuter->FontToIdentity(font.get(), &fIdentity));
295 }
296
297 return S_OK;
298 }
299
DrawUnderline(void * clientDrawingContext,FLOAT baselineOriginX,FLOAT baselineOriginY,DWRITE_UNDERLINE const * underline,IUnknown * clientDrawingEffect)300 virtual HRESULT STDMETHODCALLTYPE DrawUnderline(
301 void* clientDrawingContext,
302 FLOAT baselineOriginX,
303 FLOAT baselineOriginY,
304 DWRITE_UNDERLINE const* underline,
305 IUnknown* clientDrawingEffect) override
306 { return E_NOTIMPL; }
307
DrawStrikethrough(void * clientDrawingContext,FLOAT baselineOriginX,FLOAT baselineOriginY,DWRITE_STRIKETHROUGH const * strikethrough,IUnknown * clientDrawingEffect)308 virtual HRESULT STDMETHODCALLTYPE DrawStrikethrough(
309 void* clientDrawingContext,
310 FLOAT baselineOriginX,
311 FLOAT baselineOriginY,
312 DWRITE_STRIKETHROUGH const* strikethrough,
313 IUnknown* clientDrawingEffect) override
314 { return E_NOTIMPL; }
315
DrawInlineObject(void * clientDrawingContext,FLOAT originX,FLOAT originY,IDWriteInlineObject * inlineObject,BOOL isSideways,BOOL isRightToLeft,IUnknown * clientDrawingEffect)316 virtual HRESULT STDMETHODCALLTYPE DrawInlineObject(
317 void* clientDrawingContext,
318 FLOAT originX,
319 FLOAT originY,
320 IDWriteInlineObject* inlineObject,
321 BOOL isSideways,
322 BOOL isRightToLeft,
323 IUnknown* clientDrawingEffect) override
324 { return E_NOTIMPL; }
325
326 // IDWritePixelSnapping methods
IsPixelSnappingDisabled(void * clientDrawingContext,BOOL * isDisabled)327 virtual HRESULT STDMETHODCALLTYPE IsPixelSnappingDisabled(
328 void* clientDrawingContext,
329 BOOL* isDisabled) override
330 {
331 *isDisabled = FALSE;
332 return S_OK;
333 }
334
GetCurrentTransform(void * clientDrawingContext,DWRITE_MATRIX * transform)335 virtual HRESULT STDMETHODCALLTYPE GetCurrentTransform(
336 void* clientDrawingContext,
337 DWRITE_MATRIX* transform) override
338 {
339 const DWRITE_MATRIX ident = {1.0, 0.0, 0.0, 1.0, 0.0, 0.0};
340 *transform = ident;
341 return S_OK;
342 }
343
GetPixelsPerDip(void * clientDrawingContext,FLOAT * pixelsPerDip)344 virtual HRESULT STDMETHODCALLTYPE GetPixelsPerDip(
345 void* clientDrawingContext,
346 FLOAT* pixelsPerDip) override
347 {
348 *pixelsPerDip = 1.0f;
349 return S_OK;
350 }
351
352 // IUnknown methods
AddRef()353 ULONG STDMETHODCALLTYPE AddRef() override {
354 return InterlockedIncrement(&fRefCount);
355 }
356
Release()357 ULONG STDMETHODCALLTYPE Release() override {
358 ULONG newCount = InterlockedDecrement(&fRefCount);
359 if (0 == newCount) {
360 delete this;
361 }
362 return newCount;
363 }
364
QueryInterface(IID const & riid,void ** ppvObject)365 virtual HRESULT STDMETHODCALLTYPE QueryInterface(
366 IID const& riid, void** ppvObject) override
367 {
368 if (__uuidof(IUnknown) == riid ||
369 __uuidof(IDWritePixelSnapping) == riid ||
370 __uuidof(IDWriteTextRenderer) == riid)
371 {
372 *ppvObject = this;
373 this->AddRef();
374 return S_OK;
375 }
376 *ppvObject = nullptr;
377 return E_FAIL;
378 }
379
FallbackIdentity()380 const SkFontIdentity FallbackIdentity() { return fIdentity; }
381
382 protected:
383 ULONG fRefCount;
384 SkAutoTUnref<const SkRemotableFontMgr_DirectWrite> fOuter;
385 UINT32 fCharacter;
386 SkFontIdentity fIdentity;
387 };
388
matchNameStyleCharacter(const char familyName[],const SkFontStyle & pattern,const char * bcp47[],int bcp47Count,SkUnichar character) const389 virtual SkFontIdentity matchNameStyleCharacter(const char familyName[],
390 const SkFontStyle& pattern,
391 const char* bcp47[], int bcp47Count,
392 SkUnichar character) const override
393 {
394 SkFontIdentity identity = { SkFontIdentity::kInvalidDataId };
395
396 IDWriteFactory* dwFactory = sk_get_dwrite_factory();
397 if (nullptr == dwFactory) {
398 return identity;
399 }
400
401 // TODO: use IDWriteFactory2::GetSystemFontFallback when available.
402
403 const DWriteStyle dwStyle(pattern);
404
405 SkSMallocWCHAR dwFamilyName;
406 if (nullptr == familyName) {
407 HR_GENERAL(getDefaultFontFamilyName(&dwFamilyName), nullptr, identity);
408 } else {
409 HR_GENERAL(sk_cstring_to_wchar(familyName, &dwFamilyName), nullptr, identity);
410 }
411
412 const SkSMallocWCHAR* dwBcp47;
413 SkSMallocWCHAR dwBcp47Local;
414 if (bcp47Count < 1) {
415 dwBcp47 = &fLocaleName;
416 } else {
417 //TODO: support fallback stack.
418 HR_GENERAL(sk_cstring_to_wchar(bcp47[bcp47Count-1], &dwBcp47Local), nullptr, identity);
419 dwBcp47 = &dwBcp47Local;
420 }
421
422 SkTScopedComPtr<IDWriteTextFormat> fallbackFormat;
423 HR_GENERAL(dwFactory->CreateTextFormat(dwFamilyName,
424 fFontCollection.get(),
425 dwStyle.fWeight,
426 dwStyle.fSlant,
427 dwStyle.fWidth,
428 72.0f,
429 *dwBcp47,
430 &fallbackFormat),
431 "Could not create text format.",
432 identity);
433
434 WCHAR str[16];
435 UINT32 strLen = static_cast<UINT32>(
436 SkUTF16_FromUnichar(character, reinterpret_cast<uint16_t*>(str)));
437 SkTScopedComPtr<IDWriteTextLayout> fallbackLayout;
438 HR_GENERAL(dwFactory->CreateTextLayout(str, strLen, fallbackFormat.get(),
439 200.0f, 200.0f,
440 &fallbackLayout),
441 "Could not create text layout.",
442 identity);
443
444 SkTScopedComPtr<FontFallbackRenderer> fontFallbackRenderer(
445 new FontFallbackRenderer(this, character));
446
447 HR_GENERAL(fallbackLayout->Draw(nullptr, fontFallbackRenderer.get(), 50.0f, 50.0f),
448 "Could not draw layout with renderer.",
449 identity);
450
451 return fontFallbackRenderer->FallbackIdentity();
452 }
453
getData(int dataId) const454 SkStreamAsset* getData(int dataId) const override {
455 SkAutoMutexAcquire ama(fDataIdCacheMutex);
456 if (dataId >= fDataIdCache.count()) {
457 return nullptr;
458 }
459 const DataId& id = fDataIdCache[dataId];
460
461 SkTScopedComPtr<IDWriteFontFileLoader> loader;
462 HRNM(id.fLoader->QueryInterface(&loader), "QuerryInterface IDWriteFontFileLoader failed");
463
464 SkTScopedComPtr<IDWriteFontFileStream> fontFileStream;
465 HRNM(loader->CreateStreamFromKey(id.fKey, id.fKeySize, &fontFileStream),
466 "Could not create font file stream.");
467
468 return new SkDWriteFontFileStream(fontFileStream.get());
469 }
470
471 private:
472 SkTScopedComPtr<IDWriteFontCollection> fFontCollection;
473 SkSMallocWCHAR fLocaleName;
474
475 typedef SkRemotableFontMgr INHERITED;
476 };
477
SkRemotableFontMgr_New_DirectWrite()478 SkRemotableFontMgr* SkRemotableFontMgr_New_DirectWrite() {
479 IDWriteFactory* factory = sk_get_dwrite_factory();
480 if (nullptr == factory) {
481 return nullptr;
482 }
483
484 SkTScopedComPtr<IDWriteFontCollection> sysFontCollection;
485 HRNM(factory->GetSystemFontCollection(&sysFontCollection, FALSE),
486 "Could not get system font collection.");
487
488 WCHAR localeNameStorage[LOCALE_NAME_MAX_LENGTH];
489 WCHAR* localeName = nullptr;
490 int localeNameLen = 0;
491
492 // Dynamically load GetUserDefaultLocaleName function, as it is not available on XP.
493 SkGetUserDefaultLocaleNameProc getUserDefaultLocaleNameProc = nullptr;
494 HRESULT hr = SkGetGetUserDefaultLocaleNameProc(&getUserDefaultLocaleNameProc);
495 if (nullptr == getUserDefaultLocaleNameProc) {
496 SK_TRACEHR(hr, "Could not get GetUserDefaultLocaleName.");
497 } else {
498 localeNameLen = getUserDefaultLocaleNameProc(localeNameStorage, LOCALE_NAME_MAX_LENGTH);
499 if (localeNameLen) {
500 localeName = localeNameStorage;
501 };
502 }
503
504 return new SkRemotableFontMgr_DirectWrite(sysFontCollection.get(), localeName, localeNameLen);
505 }
506 #endif//defined(SK_BUILD_FOR_WIN32)
507