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