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