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