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