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