• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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