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 "SkTypes.h"
9#if defined(SK_BUILD_FOR_WIN)
10
11#include "SkDWrite.h"
12#include "SkDWriteFontFileStream.h"
13#include "SkFontMgr.h"
14#include "SkHRESULT.h"
15#include "SkMakeUnique.h"
16#include "SkMutex.h"
17#include "SkStream.h"
18#include "SkTScopedComPtr.h"
19#include "SkTypeface.h"
20#include "SkTypefaceCache.h"
21#include "SkTypeface_win_dw.h"
22#include "SkTypes.h"
23#include "SkUtils.h"
24
25#include <dwrite.h>
26#include <dwrite_2.h>
27
28////////////////////////////////////////////////////////////////////////////////
29
30class StreamFontFileLoader : public IDWriteFontFileLoader {
31public:
32    // IUnknown methods
33    virtual HRESULT STDMETHODCALLTYPE QueryInterface(REFIID iid, void** ppvObject);
34    virtual ULONG STDMETHODCALLTYPE AddRef();
35    virtual ULONG STDMETHODCALLTYPE Release();
36
37    // IDWriteFontFileLoader methods
38    virtual HRESULT STDMETHODCALLTYPE CreateStreamFromKey(
39        void const* fontFileReferenceKey,
40        UINT32 fontFileReferenceKeySize,
41        IDWriteFontFileStream** fontFileStream);
42
43    // Takes ownership of stream.
44    static HRESULT Create(std::unique_ptr<SkStreamAsset> stream,
45                          StreamFontFileLoader** streamFontFileLoader) {
46        *streamFontFileLoader = new StreamFontFileLoader(std::move(stream));
47        if (nullptr == *streamFontFileLoader) {
48            return E_OUTOFMEMORY;
49        }
50        return S_OK;
51    }
52
53    std::unique_ptr<SkStreamAsset> fStream;
54
55private:
56    StreamFontFileLoader(std::unique_ptr<SkStreamAsset> stream)
57        : fStream(std::move(stream)), fRefCount(1)
58    {}
59    virtual ~StreamFontFileLoader() { }
60
61    ULONG fRefCount;
62};
63
64HRESULT StreamFontFileLoader::QueryInterface(REFIID iid, void** ppvObject) {
65    if (iid == IID_IUnknown || iid == __uuidof(IDWriteFontFileLoader)) {
66        *ppvObject = this;
67        AddRef();
68        return S_OK;
69    } else {
70        *ppvObject = nullptr;
71        return E_NOINTERFACE;
72    }
73}
74
75ULONG StreamFontFileLoader::AddRef() {
76    return InterlockedIncrement(&fRefCount);
77}
78
79ULONG StreamFontFileLoader::Release() {
80    ULONG newCount = InterlockedDecrement(&fRefCount);
81    if (0 == newCount) {
82        delete this;
83    }
84    return newCount;
85}
86
87HRESULT StreamFontFileLoader::CreateStreamFromKey(
88    void const* fontFileReferenceKey,
89    UINT32 fontFileReferenceKeySize,
90    IDWriteFontFileStream** fontFileStream)
91{
92    SkTScopedComPtr<SkDWriteFontFileStreamWrapper> stream;
93    HR(SkDWriteFontFileStreamWrapper::Create(fStream->duplicate().release(), &stream));
94    *fontFileStream = stream.release();
95    return S_OK;
96}
97
98////////////////////////////////////////////////////////////////////////////////
99
100class StreamFontFileEnumerator : public IDWriteFontFileEnumerator {
101public:
102    // IUnknown methods
103    virtual HRESULT STDMETHODCALLTYPE QueryInterface(REFIID iid, void** ppvObject);
104    virtual ULONG STDMETHODCALLTYPE AddRef();
105    virtual ULONG STDMETHODCALLTYPE Release();
106
107    // IDWriteFontFileEnumerator methods
108    virtual HRESULT STDMETHODCALLTYPE MoveNext(BOOL* hasCurrentFile);
109    virtual HRESULT STDMETHODCALLTYPE GetCurrentFontFile(IDWriteFontFile** fontFile);
110
111    static HRESULT Create(IDWriteFactory* factory, IDWriteFontFileLoader* fontFileLoader,
112                          StreamFontFileEnumerator** streamFontFileEnumerator) {
113        *streamFontFileEnumerator = new StreamFontFileEnumerator(factory, fontFileLoader);
114        if (nullptr == *streamFontFileEnumerator) {
115            return E_OUTOFMEMORY;
116        }
117        return S_OK;
118    }
119private:
120    StreamFontFileEnumerator(IDWriteFactory* factory, IDWriteFontFileLoader* fontFileLoader);
121    virtual ~StreamFontFileEnumerator() { }
122
123    ULONG fRefCount;
124
125    SkTScopedComPtr<IDWriteFactory> fFactory;
126    SkTScopedComPtr<IDWriteFontFile> fCurrentFile;
127    SkTScopedComPtr<IDWriteFontFileLoader> fFontFileLoader;
128    bool fHasNext;
129};
130
131StreamFontFileEnumerator::StreamFontFileEnumerator(IDWriteFactory* factory,
132                                                   IDWriteFontFileLoader* fontFileLoader)
133    : fRefCount(1)
134    , fFactory(SkRefComPtr(factory))
135    , fCurrentFile()
136    , fFontFileLoader(SkRefComPtr(fontFileLoader))
137    , fHasNext(true)
138{ }
139
140HRESULT StreamFontFileEnumerator::QueryInterface(REFIID iid, void** ppvObject) {
141    if (iid == IID_IUnknown || iid == __uuidof(IDWriteFontFileEnumerator)) {
142        *ppvObject = this;
143        AddRef();
144        return S_OK;
145    } else {
146        *ppvObject = nullptr;
147        return E_NOINTERFACE;
148    }
149}
150
151ULONG StreamFontFileEnumerator::AddRef() {
152    return InterlockedIncrement(&fRefCount);
153}
154
155ULONG StreamFontFileEnumerator::Release() {
156    ULONG newCount = InterlockedDecrement(&fRefCount);
157    if (0 == newCount) {
158        delete this;
159    }
160    return newCount;
161}
162
163HRESULT StreamFontFileEnumerator::MoveNext(BOOL* hasCurrentFile) {
164    *hasCurrentFile = FALSE;
165
166    if (!fHasNext) {
167        return S_OK;
168    }
169    fHasNext = false;
170
171    UINT32 dummy = 0;
172    HR(fFactory->CreateCustomFontFileReference(
173            &dummy, //cannot be nullptr
174            sizeof(dummy), //even if this is 0
175            fFontFileLoader.get(),
176            &fCurrentFile));
177
178    *hasCurrentFile = TRUE;
179    return S_OK;
180}
181
182HRESULT StreamFontFileEnumerator::GetCurrentFontFile(IDWriteFontFile** fontFile) {
183    if (fCurrentFile.get() == nullptr) {
184        *fontFile = nullptr;
185        return E_FAIL;
186    }
187
188    *fontFile = SkRefComPtr(fCurrentFile.get());
189    return  S_OK;
190}
191
192////////////////////////////////////////////////////////////////////////////////
193
194class StreamFontCollectionLoader : public IDWriteFontCollectionLoader {
195public:
196    // IUnknown methods
197    virtual HRESULT STDMETHODCALLTYPE QueryInterface(REFIID iid, void** ppvObject);
198    virtual ULONG STDMETHODCALLTYPE AddRef();
199    virtual ULONG STDMETHODCALLTYPE Release();
200
201    // IDWriteFontCollectionLoader methods
202    virtual HRESULT STDMETHODCALLTYPE CreateEnumeratorFromKey(
203        IDWriteFactory* factory,
204        void const* collectionKey,
205        UINT32 collectionKeySize,
206        IDWriteFontFileEnumerator** fontFileEnumerator);
207
208    static HRESULT Create(IDWriteFontFileLoader* fontFileLoader,
209                          StreamFontCollectionLoader** streamFontCollectionLoader) {
210        *streamFontCollectionLoader = new StreamFontCollectionLoader(fontFileLoader);
211        if (nullptr == *streamFontCollectionLoader) {
212            return E_OUTOFMEMORY;
213        }
214        return S_OK;
215    }
216private:
217    StreamFontCollectionLoader(IDWriteFontFileLoader* fontFileLoader)
218        : fRefCount(1)
219        , fFontFileLoader(SkRefComPtr(fontFileLoader))
220    { }
221    virtual ~StreamFontCollectionLoader() { }
222
223    ULONG fRefCount;
224    SkTScopedComPtr<IDWriteFontFileLoader> fFontFileLoader;
225};
226
227HRESULT StreamFontCollectionLoader::QueryInterface(REFIID iid, void** ppvObject) {
228    if (iid == IID_IUnknown || iid == __uuidof(IDWriteFontCollectionLoader)) {
229        *ppvObject = this;
230        AddRef();
231        return S_OK;
232    } else {
233        *ppvObject = nullptr;
234        return E_NOINTERFACE;
235    }
236}
237
238ULONG StreamFontCollectionLoader::AddRef() {
239    return InterlockedIncrement(&fRefCount);
240}
241
242ULONG StreamFontCollectionLoader::Release() {
243    ULONG newCount = InterlockedDecrement(&fRefCount);
244    if (0 == newCount) {
245        delete this;
246    }
247    return newCount;
248}
249
250HRESULT StreamFontCollectionLoader::CreateEnumeratorFromKey(
251    IDWriteFactory* factory,
252    void const* collectionKey,
253    UINT32 collectionKeySize,
254    IDWriteFontFileEnumerator** fontFileEnumerator)
255{
256    SkTScopedComPtr<StreamFontFileEnumerator> enumerator;
257    HR(StreamFontFileEnumerator::Create(factory, fFontFileLoader.get(), &enumerator));
258    *fontFileEnumerator = enumerator.release();
259    return S_OK;
260}
261
262////////////////////////////////////////////////////////////////////////////////
263
264class SkFontMgr_DirectWrite : public SkFontMgr {
265public:
266    /** localeNameLength must include the null terminator. */
267    SkFontMgr_DirectWrite(IDWriteFactory* factory, IDWriteFontCollection* fontCollection,
268                          IDWriteFontFallback* fallback, WCHAR* localeName, int localeNameLength)
269        : fFactory(SkRefComPtr(factory))
270        , fFontFallback(SkSafeRefComPtr(fallback))
271        , fFontCollection(SkRefComPtr(fontCollection))
272        , fLocaleName(localeNameLength)
273    {
274        if (!SUCCEEDED(fFactory->QueryInterface(&fFactory2))) {
275            // IUnknown::QueryInterface states that if it fails, punk will be set to nullptr.
276            // http://blogs.msdn.com/b/oldnewthing/archive/2004/03/26/96777.aspx
277            SkASSERT_RELEASE(nullptr == fFactory2.get());
278        }
279        if (fFontFallback.get()) {
280            // factory must be provided if fallback is non-null, else the fallback will not be used.
281            SkASSERT(fFactory2.get());
282        }
283        memcpy(fLocaleName.get(), localeName, localeNameLength * sizeof(WCHAR));
284    }
285
286protected:
287    int onCountFamilies() const override;
288    void onGetFamilyName(int index, SkString* familyName) const override;
289    SkFontStyleSet* onCreateStyleSet(int index) const override;
290    SkFontStyleSet* onMatchFamily(const char familyName[]) const override;
291    SkTypeface* onMatchFamilyStyle(const char familyName[],
292                                   const SkFontStyle& fontstyle) const override;
293    SkTypeface* onMatchFamilyStyleCharacter(const char familyName[], const SkFontStyle&,
294                                            const char* bcp47[], int bcp47Count,
295                                            SkUnichar character) const override;
296    SkTypeface* onMatchFaceStyle(const SkTypeface* familyMember,
297                                 const SkFontStyle& fontstyle) const override;
298    sk_sp<SkTypeface> onMakeFromStreamIndex(std::unique_ptr<SkStreamAsset>, int ttcIndex) const override;
299    sk_sp<SkTypeface> onMakeFromData(sk_sp<SkData>, int ttcIndex) const override;
300    sk_sp<SkTypeface> onMakeFromFile(const char path[], int ttcIndex) const override;
301    sk_sp<SkTypeface> onLegacyMakeTypeface(const char familyName[], SkFontStyle) const override;
302
303private:
304    HRESULT getByFamilyName(const WCHAR familyName[], IDWriteFontFamily** fontFamily) const;
305    HRESULT getDefaultFontFamily(IDWriteFontFamily** fontFamily) const;
306
307    /** Creates a typeface using a typeface cache. */
308    sk_sp<SkTypeface> makeTypefaceFromDWriteFont(IDWriteFontFace* fontFace,
309                                                 IDWriteFont* font,
310                                                 IDWriteFontFamily* fontFamily) const;
311
312    SkTScopedComPtr<IDWriteFactory> fFactory;
313    SkTScopedComPtr<IDWriteFactory2> fFactory2;
314    SkTScopedComPtr<IDWriteFontFallback> fFontFallback;
315    SkTScopedComPtr<IDWriteFontCollection> fFontCollection;
316    SkSMallocWCHAR fLocaleName;
317    mutable SkMutex fTFCacheMutex;
318    mutable SkTypefaceCache fTFCache;
319
320    friend class SkFontStyleSet_DirectWrite;
321    friend class FontFallbackRenderer;
322};
323
324class SkFontStyleSet_DirectWrite : public SkFontStyleSet {
325public:
326    SkFontStyleSet_DirectWrite(const SkFontMgr_DirectWrite* fontMgr,
327                               IDWriteFontFamily* fontFamily)
328        : fFontMgr(SkRef(fontMgr))
329        , fFontFamily(SkRefComPtr(fontFamily))
330    { }
331
332    int count() override;
333    void getStyle(int index, SkFontStyle* fs, SkString* styleName) override;
334    SkTypeface* createTypeface(int index) override;
335    SkTypeface* matchStyle(const SkFontStyle& pattern) override;
336
337private:
338    sk_sp<const SkFontMgr_DirectWrite> fFontMgr;
339    SkTScopedComPtr<IDWriteFontFamily> fFontFamily;
340};
341
342static HRESULT are_same(IUnknown* a, IUnknown* b, bool& same) {
343    SkTScopedComPtr<IUnknown> iunkA;
344    HRM(a->QueryInterface(&iunkA), "Failed to QI<IUnknown> for a.");
345
346    SkTScopedComPtr<IUnknown> iunkB;
347    HRM(b->QueryInterface(&iunkB), "Failed to QI<IUnknown> for b.");
348
349    same = (iunkA.get() == iunkB.get());
350    return S_OK;
351}
352
353struct ProtoDWriteTypeface {
354    IDWriteFontFace* fDWriteFontFace;
355    IDWriteFont* fDWriteFont;
356    IDWriteFontFamily* fDWriteFontFamily;
357};
358
359static bool FindByDWriteFont(SkTypeface* cached, void* ctx) {
360    DWriteFontTypeface* cshFace = reinterpret_cast<DWriteFontTypeface*>(cached);
361    ProtoDWriteTypeface* ctxFace = reinterpret_cast<ProtoDWriteTypeface*>(ctx);
362    bool same;
363
364    //Check to see if the two fonts are identical.
365    HRB(are_same(cshFace->fDWriteFont.get(), ctxFace->fDWriteFont, same));
366    if (same) {
367        return true;
368    }
369
370    HRB(are_same(cshFace->fDWriteFontFace.get(), ctxFace->fDWriteFontFace, same));
371    if (same) {
372        return true;
373    }
374
375    //Check if the two fonts share the same loader and have the same key.
376    UINT32 cshNumFiles;
377    UINT32 ctxNumFiles;
378    HRB(cshFace->fDWriteFontFace->GetFiles(&cshNumFiles, nullptr));
379    HRB(ctxFace->fDWriteFontFace->GetFiles(&ctxNumFiles, nullptr));
380    if (cshNumFiles != ctxNumFiles) {
381        return false;
382    }
383
384    SkTScopedComPtr<IDWriteFontFile> cshFontFile;
385    SkTScopedComPtr<IDWriteFontFile> ctxFontFile;
386    HRB(cshFace->fDWriteFontFace->GetFiles(&cshNumFiles, &cshFontFile));
387    HRB(ctxFace->fDWriteFontFace->GetFiles(&ctxNumFiles, &ctxFontFile));
388
389    //for (each file) { //we currently only admit fonts from one file.
390    SkTScopedComPtr<IDWriteFontFileLoader> cshFontFileLoader;
391    SkTScopedComPtr<IDWriteFontFileLoader> ctxFontFileLoader;
392    HRB(cshFontFile->GetLoader(&cshFontFileLoader));
393    HRB(ctxFontFile->GetLoader(&ctxFontFileLoader));
394    HRB(are_same(cshFontFileLoader.get(), ctxFontFileLoader.get(), same));
395    if (!same) {
396        return false;
397    }
398    //}
399
400    const void* cshRefKey;
401    UINT32 cshRefKeySize;
402    const void* ctxRefKey;
403    UINT32 ctxRefKeySize;
404    HRB(cshFontFile->GetReferenceKey(&cshRefKey, &cshRefKeySize));
405    HRB(ctxFontFile->GetReferenceKey(&ctxRefKey, &ctxRefKeySize));
406    if (cshRefKeySize != ctxRefKeySize) {
407        return false;
408    }
409    if (0 != memcmp(cshRefKey, ctxRefKey, ctxRefKeySize)) {
410        return false;
411    }
412
413    //TODO: better means than comparing name strings?
414    //NOTE: .ttc and fake bold/italic will end up here.
415    SkTScopedComPtr<IDWriteLocalizedStrings> cshFamilyNames;
416    SkTScopedComPtr<IDWriteLocalizedStrings> cshFaceNames;
417    HRB(cshFace->fDWriteFontFamily->GetFamilyNames(&cshFamilyNames));
418    HRB(cshFace->fDWriteFont->GetFaceNames(&cshFaceNames));
419    UINT32 cshFamilyNameLength;
420    UINT32 cshFaceNameLength;
421    HRB(cshFamilyNames->GetStringLength(0, &cshFamilyNameLength));
422    HRB(cshFaceNames->GetStringLength(0, &cshFaceNameLength));
423
424    SkTScopedComPtr<IDWriteLocalizedStrings> ctxFamilyNames;
425    SkTScopedComPtr<IDWriteLocalizedStrings> ctxFaceNames;
426    HRB(ctxFace->fDWriteFontFamily->GetFamilyNames(&ctxFamilyNames));
427    HRB(ctxFace->fDWriteFont->GetFaceNames(&ctxFaceNames));
428    UINT32 ctxFamilyNameLength;
429    UINT32 ctxFaceNameLength;
430    HRB(ctxFamilyNames->GetStringLength(0, &ctxFamilyNameLength));
431    HRB(ctxFaceNames->GetStringLength(0, &ctxFaceNameLength));
432
433    if (cshFamilyNameLength != ctxFamilyNameLength ||
434        cshFaceNameLength != ctxFaceNameLength)
435    {
436        return false;
437    }
438
439    SkSMallocWCHAR cshFamilyName(cshFamilyNameLength+1);
440    SkSMallocWCHAR cshFaceName(cshFaceNameLength+1);
441    HRB(cshFamilyNames->GetString(0, cshFamilyName.get(), cshFamilyNameLength+1));
442    HRB(cshFaceNames->GetString(0, cshFaceName.get(), cshFaceNameLength+1));
443
444    SkSMallocWCHAR ctxFamilyName(ctxFamilyNameLength+1);
445    SkSMallocWCHAR ctxFaceName(ctxFaceNameLength+1);
446    HRB(ctxFamilyNames->GetString(0, ctxFamilyName.get(), ctxFamilyNameLength+1));
447    HRB(ctxFaceNames->GetString(0, ctxFaceName.get(), ctxFaceNameLength+1));
448
449    return wcscmp(cshFamilyName.get(), ctxFamilyName.get()) == 0 &&
450           wcscmp(cshFaceName.get(), ctxFaceName.get()) == 0;
451}
452
453sk_sp<SkTypeface> SkFontMgr_DirectWrite::makeTypefaceFromDWriteFont(
454        IDWriteFontFace* fontFace,
455        IDWriteFont* font,
456        IDWriteFontFamily* fontFamily) const {
457    SkAutoMutexAcquire ama(fTFCacheMutex);
458    ProtoDWriteTypeface spec = { fontFace, font, fontFamily };
459    SkTypeface* face = fTFCache.findByProcAndRef(FindByDWriteFont, &spec);
460    if (nullptr == face) {
461        face = DWriteFontTypeface::Create(fFactory.get(), fontFace, font, fontFamily);
462        if (face) {
463            fTFCache.add(face);
464        }
465    }
466    return sk_sp<SkTypeface>(face);
467}
468
469int SkFontMgr_DirectWrite::onCountFamilies() const {
470    return fFontCollection->GetFontFamilyCount();
471}
472
473void SkFontMgr_DirectWrite::onGetFamilyName(int index, SkString* familyName) const {
474    SkTScopedComPtr<IDWriteFontFamily> fontFamily;
475    HRVM(fFontCollection->GetFontFamily(index, &fontFamily), "Could not get requested family.");
476
477    SkTScopedComPtr<IDWriteLocalizedStrings> familyNames;
478    HRVM(fontFamily->GetFamilyNames(&familyNames), "Could not get family names.");
479
480    sk_get_locale_string(familyNames.get(), fLocaleName.get(), familyName);
481}
482
483SkFontStyleSet* SkFontMgr_DirectWrite::onCreateStyleSet(int index) const {
484    SkTScopedComPtr<IDWriteFontFamily> fontFamily;
485    HRNM(fFontCollection->GetFontFamily(index, &fontFamily), "Could not get requested family.");
486
487    return new SkFontStyleSet_DirectWrite(this, fontFamily.get());
488}
489
490SkFontStyleSet* SkFontMgr_DirectWrite::onMatchFamily(const char familyName[]) const {
491    if (!familyName) {
492        return nullptr;
493    }
494
495    SkSMallocWCHAR dwFamilyName;
496    HRN(sk_cstring_to_wchar(familyName, &dwFamilyName));
497
498    UINT32 index;
499    BOOL exists;
500    HRNM(fFontCollection->FindFamilyName(dwFamilyName.get(), &index, &exists),
501            "Failed while finding family by name.");
502    if (!exists) {
503        return nullptr;
504    }
505
506    return this->onCreateStyleSet(index);
507}
508
509SkTypeface* SkFontMgr_DirectWrite::onMatchFamilyStyle(const char familyName[],
510                                                      const SkFontStyle& fontstyle) const {
511    sk_sp<SkFontStyleSet> sset(this->matchFamily(familyName));
512    return sset->matchStyle(fontstyle);
513}
514
515class FontFallbackRenderer : public IDWriteTextRenderer {
516public:
517    FontFallbackRenderer(const SkFontMgr_DirectWrite* outer, UINT32 character)
518        : fRefCount(1), fOuter(SkSafeRef(outer)), fCharacter(character), fResolvedTypeface(nullptr) {
519    }
520
521    virtual ~FontFallbackRenderer() { }
522
523    // IDWriteTextRenderer methods
524    virtual HRESULT STDMETHODCALLTYPE DrawGlyphRun(
525        void* clientDrawingContext,
526        FLOAT baselineOriginX,
527        FLOAT baselineOriginY,
528        DWRITE_MEASURING_MODE measuringMode,
529        DWRITE_GLYPH_RUN const* glyphRun,
530        DWRITE_GLYPH_RUN_DESCRIPTION const* glyphRunDescription,
531        IUnknown* clientDrawingEffect) override
532    {
533        SkTScopedComPtr<IDWriteFont> font;
534        HRM(fOuter->fFontCollection->GetFontFromFontFace(glyphRun->fontFace, &font),
535            "Could not get font from font face.");
536
537        // It is possible that the font passed does not actually have the requested character,
538        // due to no font being found and getting the fallback font.
539        // Check that the font actually contains the requested character.
540        BOOL exists;
541        HRM(font->HasCharacter(fCharacter, &exists), "Could not find character.");
542
543        if (exists) {
544            SkTScopedComPtr<IDWriteFontFamily> fontFamily;
545            HRM(font->GetFontFamily(&fontFamily), "Could not get family.");
546            fResolvedTypeface = fOuter->makeTypefaceFromDWriteFont(glyphRun->fontFace,
547                                                                   font.get(),
548                                                                   fontFamily.get()).release();
549        }
550
551        return S_OK;
552    }
553
554    virtual HRESULT STDMETHODCALLTYPE DrawUnderline(
555        void* clientDrawingContext,
556        FLOAT baselineOriginX,
557        FLOAT baselineOriginY,
558        DWRITE_UNDERLINE const* underline,
559        IUnknown* clientDrawingEffect) override
560    { return E_NOTIMPL; }
561
562    virtual HRESULT STDMETHODCALLTYPE DrawStrikethrough(
563        void* clientDrawingContext,
564        FLOAT baselineOriginX,
565        FLOAT baselineOriginY,
566        DWRITE_STRIKETHROUGH const* strikethrough,
567        IUnknown* clientDrawingEffect) override
568    { return E_NOTIMPL; }
569
570    virtual HRESULT STDMETHODCALLTYPE DrawInlineObject(
571        void* clientDrawingContext,
572        FLOAT originX,
573        FLOAT originY,
574        IDWriteInlineObject* inlineObject,
575        BOOL isSideways,
576        BOOL isRightToLeft,
577        IUnknown* clientDrawingEffect) override
578    { return E_NOTIMPL; }
579
580    // IDWritePixelSnapping methods
581    virtual HRESULT STDMETHODCALLTYPE IsPixelSnappingDisabled(
582        void* clientDrawingContext,
583        BOOL* isDisabled) override
584    {
585        *isDisabled = FALSE;
586        return S_OK;
587    }
588
589    virtual HRESULT STDMETHODCALLTYPE GetCurrentTransform(
590        void* clientDrawingContext,
591        DWRITE_MATRIX* transform) override
592    {
593        const DWRITE_MATRIX ident = { 1.0, 0.0, 0.0, 1.0, 0.0, 0.0 };
594        *transform = ident;
595        return S_OK;
596    }
597
598    virtual HRESULT STDMETHODCALLTYPE GetPixelsPerDip(
599        void* clientDrawingContext,
600        FLOAT* pixelsPerDip) override
601    {
602        *pixelsPerDip = 1.0f;
603        return S_OK;
604    }
605
606    // IUnknown methods
607    ULONG STDMETHODCALLTYPE AddRef() override {
608        return InterlockedIncrement(&fRefCount);
609    }
610
611    ULONG STDMETHODCALLTYPE Release() override {
612        ULONG newCount = InterlockedDecrement(&fRefCount);
613        if (0 == newCount) {
614            delete this;
615        }
616        return newCount;
617    }
618
619    virtual HRESULT STDMETHODCALLTYPE QueryInterface(IID const& riid, void** ppvObject) override{
620        if (__uuidof(IUnknown) == riid ||
621            __uuidof(IDWritePixelSnapping) == riid ||
622            __uuidof(IDWriteTextRenderer) == riid)
623        {
624            *ppvObject = this;
625            this->AddRef();
626            return S_OK;
627        }
628        *ppvObject = nullptr;
629        return E_FAIL;
630    }
631
632    SkTypeface* FallbackTypeface() { return fResolvedTypeface; }
633
634protected:
635    ULONG fRefCount;
636    sk_sp<const SkFontMgr_DirectWrite> fOuter;
637    UINT32 fCharacter;
638    SkTypeface* fResolvedTypeface;
639};
640
641class FontFallbackSource : public IDWriteTextAnalysisSource {
642public:
643    FontFallbackSource(const WCHAR* string, UINT32 length, const WCHAR* locale,
644                       IDWriteNumberSubstitution* numberSubstitution)
645        : fString(string)
646        , fLength(length)
647        , fLocale(locale)
648        , fNumberSubstitution(numberSubstitution)
649    { }
650
651    virtual ~FontFallbackSource() { }
652
653    // IDWriteTextAnalysisSource methods
654    virtual HRESULT STDMETHODCALLTYPE GetTextAtPosition(
655        UINT32 textPosition,
656        WCHAR const** textString,
657        UINT32* textLength) override
658    {
659        if (fLength <= textPosition) {
660            *textString = nullptr;
661            *textLength = 0;
662            return S_OK;
663        }
664        *textString = fString + textPosition;
665        *textLength = fLength - textPosition;
666        return S_OK;
667    }
668
669    virtual HRESULT STDMETHODCALLTYPE GetTextBeforePosition(
670        UINT32 textPosition,
671        WCHAR const** textString,
672        UINT32* textLength) override
673    {
674        if (textPosition < 1 || fLength <= textPosition) {
675            *textString = nullptr;
676            *textLength = 0;
677            return S_OK;
678        }
679        *textString = fString;
680        *textLength = textPosition;
681        return S_OK;
682    }
683
684    virtual DWRITE_READING_DIRECTION STDMETHODCALLTYPE GetParagraphReadingDirection() override {
685        // TODO: this is also interesting.
686        return DWRITE_READING_DIRECTION_LEFT_TO_RIGHT;
687    }
688
689    virtual HRESULT STDMETHODCALLTYPE GetLocaleName(
690        UINT32 textPosition,
691        UINT32* textLength,
692        WCHAR const** localeName) override
693    {
694        *localeName = fLocale;
695        return S_OK;
696    }
697
698    virtual HRESULT STDMETHODCALLTYPE GetNumberSubstitution(
699        UINT32 textPosition,
700        UINT32* textLength,
701        IDWriteNumberSubstitution** numberSubstitution) override
702    {
703        *numberSubstitution = fNumberSubstitution;
704        return S_OK;
705    }
706
707    // IUnknown methods
708    ULONG STDMETHODCALLTYPE AddRef() override {
709        return InterlockedIncrement(&fRefCount);
710    }
711
712    ULONG STDMETHODCALLTYPE Release() override {
713        ULONG newCount = InterlockedDecrement(&fRefCount);
714        if (0 == newCount) {
715            delete this;
716        }
717        return newCount;
718    }
719
720    virtual HRESULT STDMETHODCALLTYPE QueryInterface(IID const& riid, void** ppvObject) override{
721        if (__uuidof(IUnknown) == riid ||
722            __uuidof(IDWriteTextAnalysisSource) == riid)
723        {
724            *ppvObject = this;
725            this->AddRef();
726            return S_OK;
727        }
728        *ppvObject = nullptr;
729        return E_FAIL;
730    }
731
732protected:
733    ULONG fRefCount;
734    const WCHAR* fString;
735    UINT32 fLength;
736    const WCHAR* fLocale;
737    IDWriteNumberSubstitution* fNumberSubstitution;
738};
739
740SkTypeface* SkFontMgr_DirectWrite::onMatchFamilyStyleCharacter(const char familyName[],
741                                                               const SkFontStyle& style,
742                                                               const char* bcp47[], int bcp47Count,
743                                                               SkUnichar character) const
744{
745    const DWriteStyle dwStyle(style);
746
747    const WCHAR* dwFamilyName = nullptr;
748    SkSMallocWCHAR dwFamilyNameLocal;
749    if (familyName) {
750        HRN(sk_cstring_to_wchar(familyName, &dwFamilyNameLocal));
751        dwFamilyName = dwFamilyNameLocal;
752    }
753
754    WCHAR str[16];
755    UINT32 strLen = static_cast<UINT32>(
756        SkUTF16_FromUnichar(character, reinterpret_cast<uint16_t*>(str)));
757
758    const SkSMallocWCHAR* dwBcp47;
759    SkSMallocWCHAR dwBcp47Local;
760    if (bcp47Count < 1) {
761        dwBcp47 = &fLocaleName;
762    } else {
763        // TODO: support fallback stack.
764        // TODO: DirectWrite supports 'zh-CN' or 'zh-Hans', but 'zh' misses completely
765        // and may produce a Japanese font.
766        HRN(sk_cstring_to_wchar(bcp47[bcp47Count - 1], &dwBcp47Local));
767        dwBcp47 = &dwBcp47Local;
768    }
769
770    if (fFactory2.get()) {
771        SkTScopedComPtr<IDWriteFontFallback> systemFontFallback;
772        IDWriteFontFallback* fontFallback = fFontFallback.get();
773        if (!fontFallback) {
774            HRNM(fFactory2->GetSystemFontFallback(&systemFontFallback),
775                 "Could not get system fallback.");
776            fontFallback = systemFontFallback.get();
777        }
778
779        SkTScopedComPtr<IDWriteNumberSubstitution> numberSubstitution;
780        HRNM(fFactory2->CreateNumberSubstitution(DWRITE_NUMBER_SUBSTITUTION_METHOD_NONE, nullptr, TRUE,
781                                                 &numberSubstitution),
782             "Could not create number substitution.");
783        SkTScopedComPtr<FontFallbackSource> fontFallbackSource(
784            new FontFallbackSource(str, strLen, *dwBcp47, numberSubstitution.get()));
785
786        UINT32 mappedLength;
787        SkTScopedComPtr<IDWriteFont> font;
788        FLOAT scale;
789        HRNM(fontFallback->MapCharacters(fontFallbackSource.get(),
790                                         0, // textPosition,
791                                         strLen,
792                                         fFontCollection.get(),
793                                         dwFamilyName,
794                                         dwStyle.fWeight,
795                                         dwStyle.fSlant,
796                                         dwStyle.fWidth,
797                                         &mappedLength,
798                                         &font,
799                                         &scale),
800             "Could not map characters");
801        if (!font.get()) {
802            return nullptr;
803        }
804
805        SkTScopedComPtr<IDWriteFontFace> fontFace;
806        HRNM(font->CreateFontFace(&fontFace), "Could not get font face from font.");
807
808        SkTScopedComPtr<IDWriteFontFamily> fontFamily;
809        HRNM(font->GetFontFamily(&fontFamily), "Could not get family from font.");
810        return this->makeTypefaceFromDWriteFont(fontFace.get(), font.get(), fontFamily.get()).release();
811    }
812
813    SkTScopedComPtr<IDWriteTextFormat> fallbackFormat;
814    HRNM(fFactory->CreateTextFormat(dwFamilyName ? dwFamilyName : L"",
815                                    fFontCollection.get(),
816                                    dwStyle.fWeight,
817                                    dwStyle.fSlant,
818                                    dwStyle.fWidth,
819                                    72.0f,
820                                    *dwBcp47,
821                                    &fallbackFormat),
822         "Could not create text format.");
823
824    SkTScopedComPtr<IDWriteTextLayout> fallbackLayout;
825    HRNM(fFactory->CreateTextLayout(str, strLen, fallbackFormat.get(),
826                                    200.0f, 200.0f,
827                                    &fallbackLayout),
828         "Could not create text layout.");
829
830    SkTScopedComPtr<FontFallbackRenderer> fontFallbackRenderer(
831        new FontFallbackRenderer(this, character));
832
833    HRNM(fallbackLayout->Draw(nullptr, fontFallbackRenderer.get(), 50.0f, 50.0f),
834         "Could not draw layout with renderer.");
835
836    return fontFallbackRenderer->FallbackTypeface();
837}
838
839SkTypeface* SkFontMgr_DirectWrite::onMatchFaceStyle(const SkTypeface* familyMember,
840                                                    const SkFontStyle& fontstyle) const {
841    SkString familyName;
842    SkFontStyleSet_DirectWrite sset(
843        this, ((DWriteFontTypeface*)familyMember)->fDWriteFontFamily.get()
844    );
845    return sset.matchStyle(fontstyle);
846}
847
848template <typename T> class SkAutoIDWriteUnregister {
849public:
850    SkAutoIDWriteUnregister(IDWriteFactory* factory, T* unregister)
851        : fFactory(factory), fUnregister(unregister)
852    { }
853
854    ~SkAutoIDWriteUnregister() {
855        if (fUnregister) {
856            unregister(fFactory, fUnregister);
857        }
858    }
859
860    T* detatch() {
861        T* old = fUnregister;
862        fUnregister = nullptr;
863        return old;
864    }
865
866private:
867    HRESULT unregister(IDWriteFactory* factory, IDWriteFontFileLoader* unregister) {
868        return factory->UnregisterFontFileLoader(unregister);
869    }
870
871    HRESULT unregister(IDWriteFactory* factory, IDWriteFontCollectionLoader* unregister) {
872        return factory->UnregisterFontCollectionLoader(unregister);
873    }
874
875    IDWriteFactory* fFactory;
876    T* fUnregister;
877};
878
879sk_sp<SkTypeface> SkFontMgr_DirectWrite::onMakeFromStreamIndex(std::unique_ptr<SkStreamAsset> stream,
880                                                               int ttcIndex) const {
881    SkTScopedComPtr<StreamFontFileLoader> fontFileLoader;
882    // This transfers ownership of stream to the new object.
883    HRN(StreamFontFileLoader::Create(std::move(stream), &fontFileLoader));
884    HRN(fFactory->RegisterFontFileLoader(fontFileLoader.get()));
885    SkAutoIDWriteUnregister<StreamFontFileLoader> autoUnregisterFontFileLoader(
886        fFactory.get(), fontFileLoader.get());
887
888    SkTScopedComPtr<StreamFontCollectionLoader> fontCollectionLoader;
889    HRN(StreamFontCollectionLoader::Create(fontFileLoader.get(), &fontCollectionLoader));
890    HRN(fFactory->RegisterFontCollectionLoader(fontCollectionLoader.get()));
891    SkAutoIDWriteUnregister<StreamFontCollectionLoader> autoUnregisterFontCollectionLoader(
892        fFactory.get(), fontCollectionLoader.get());
893
894    SkTScopedComPtr<IDWriteFontCollection> fontCollection;
895    HRN(fFactory->CreateCustomFontCollection(fontCollectionLoader.get(), nullptr, 0, &fontCollection));
896
897    // Find the first non-simulated font which has the given ttc index.
898    UINT32 familyCount = fontCollection->GetFontFamilyCount();
899    for (UINT32 familyIndex = 0; familyIndex < familyCount; ++familyIndex) {
900        SkTScopedComPtr<IDWriteFontFamily> fontFamily;
901        HRN(fontCollection->GetFontFamily(familyIndex, &fontFamily));
902
903        UINT32 fontCount = fontFamily->GetFontCount();
904        for (UINT32 fontIndex = 0; fontIndex < fontCount; ++fontIndex) {
905            SkTScopedComPtr<IDWriteFont> font;
906            HRN(fontFamily->GetFont(fontIndex, &font));
907            if (font->GetSimulations() != DWRITE_FONT_SIMULATIONS_NONE) {
908                continue;
909            }
910
911            SkTScopedComPtr<IDWriteFontFace> fontFace;
912            HRN(font->CreateFontFace(&fontFace));
913
914            int faceIndex = fontFace->GetIndex();
915            if (faceIndex == ttcIndex) {
916                return sk_sp<SkTypeface>(DWriteFontTypeface::Create(fFactory.get(),
917                                                  fontFace.get(), font.get(), fontFamily.get(),
918                                                  autoUnregisterFontFileLoader.detatch(),
919                                                  autoUnregisterFontCollectionLoader.detatch()));
920            }
921        }
922    }
923
924    return nullptr;
925}
926
927sk_sp<SkTypeface> SkFontMgr_DirectWrite::onMakeFromData(sk_sp<SkData> data, int ttcIndex) const {
928    return this->makeFromStream(skstd::make_unique<SkMemoryStream>(std::move(data)), ttcIndex);
929}
930
931sk_sp<SkTypeface> SkFontMgr_DirectWrite::onMakeFromFile(const char path[], int ttcIndex) const {
932    return this->makeFromStream(SkStream::MakeFromFile(path), ttcIndex);
933}
934
935HRESULT SkFontMgr_DirectWrite::getByFamilyName(const WCHAR wideFamilyName[],
936                                               IDWriteFontFamily** fontFamily) const {
937    UINT32 index;
938    BOOL exists;
939    HR(fFontCollection->FindFamilyName(wideFamilyName, &index, &exists));
940
941    if (exists) {
942        HR(fFontCollection->GetFontFamily(index, fontFamily));
943    }
944    return S_OK;
945}
946
947HRESULT SkFontMgr_DirectWrite::getDefaultFontFamily(IDWriteFontFamily** fontFamily) const {
948    NONCLIENTMETRICSW metrics;
949    metrics.cbSize = sizeof(metrics);
950    if (0 == SystemParametersInfoW(SPI_GETNONCLIENTMETRICS, sizeof(metrics), &metrics, 0)) {
951        return E_UNEXPECTED;
952    }
953    HRM(this->getByFamilyName(metrics.lfMessageFont.lfFaceName, fontFamily),
954        "Could not create DWrite font family from LOGFONT.");
955    return S_OK;
956}
957
958sk_sp<SkTypeface> SkFontMgr_DirectWrite::onLegacyMakeTypeface(const char familyName[],
959                                                              SkFontStyle style) const {
960    SkTScopedComPtr<IDWriteFontFamily> fontFamily;
961    if (familyName) {
962        SkSMallocWCHAR wideFamilyName;
963        if (SUCCEEDED(sk_cstring_to_wchar(familyName, &wideFamilyName))) {
964            this->getByFamilyName(wideFamilyName, &fontFamily);
965        }
966    }
967
968    if (nullptr == fontFamily.get()) {
969        // No family with given name, try default.
970        this->getDefaultFontFamily(&fontFamily);
971    }
972
973    if (nullptr == fontFamily.get()) {
974        // Could not obtain the default font.
975        HRNM(fFontCollection->GetFontFamily(0, &fontFamily),
976             "Could not get default-default font family.");
977    }
978
979    SkTScopedComPtr<IDWriteFont> font;
980    DWriteStyle dwStyle(style);
981    HRNM(fontFamily->GetFirstMatchingFont(dwStyle.fWeight, dwStyle.fWidth, dwStyle.fSlant, &font),
982         "Could not get matching font.");
983
984    SkTScopedComPtr<IDWriteFontFace> fontFace;
985    HRNM(font->CreateFontFace(&fontFace), "Could not create font face.");
986
987    return this->makeTypefaceFromDWriteFont(fontFace.get(), font.get(), fontFamily.get());
988}
989
990///////////////////////////////////////////////////////////////////////////////
991
992int SkFontStyleSet_DirectWrite::count() {
993    return fFontFamily->GetFontCount();
994}
995
996SkTypeface* SkFontStyleSet_DirectWrite::createTypeface(int index) {
997    SkTScopedComPtr<IDWriteFont> font;
998    HRNM(fFontFamily->GetFont(index, &font), "Could not get font.");
999
1000    SkTScopedComPtr<IDWriteFontFace> fontFace;
1001    HRNM(font->CreateFontFace(&fontFace), "Could not create font face.");
1002
1003    return fFontMgr->makeTypefaceFromDWriteFont(fontFace.get(), font.get(), fFontFamily.get()).release();
1004}
1005
1006void SkFontStyleSet_DirectWrite::getStyle(int index, SkFontStyle* fs, SkString* styleName) {
1007    SkTScopedComPtr<IDWriteFont> font;
1008    HRVM(fFontFamily->GetFont(index, &font), "Could not get font.");
1009
1010    if (fs) {
1011        *fs = get_style(font.get());
1012    }
1013
1014    if (styleName) {
1015        SkTScopedComPtr<IDWriteLocalizedStrings> faceNames;
1016        if (SUCCEEDED(font->GetFaceNames(&faceNames))) {
1017            sk_get_locale_string(faceNames.get(), fFontMgr->fLocaleName.get(), styleName);
1018        }
1019    }
1020}
1021
1022SkTypeface* SkFontStyleSet_DirectWrite::matchStyle(const SkFontStyle& pattern) {
1023    SkTScopedComPtr<IDWriteFont> font;
1024    DWriteStyle dwStyle(pattern);
1025    // TODO: perhaps use GetMatchingFonts and get the least simulated?
1026    HRNM(fFontFamily->GetFirstMatchingFont(dwStyle.fWeight, dwStyle.fWidth, dwStyle.fSlant, &font),
1027         "Could not match font in family.");
1028
1029    SkTScopedComPtr<IDWriteFontFace> fontFace;
1030    HRNM(font->CreateFontFace(&fontFace), "Could not create font face.");
1031
1032    return fFontMgr->makeTypefaceFromDWriteFont(fontFace.get(), font.get(),
1033                                                fFontFamily.get()).release();
1034}
1035
1036////////////////////////////////////////////////////////////////////////////////
1037#include "SkTypeface_win.h"
1038
1039SK_API sk_sp<SkFontMgr> SkFontMgr_New_DirectWrite(IDWriteFactory* factory,
1040                                                  IDWriteFontCollection* collection) {
1041    return SkFontMgr_New_DirectWrite(factory, collection, nullptr);
1042}
1043
1044SK_API sk_sp<SkFontMgr> SkFontMgr_New_DirectWrite(IDWriteFactory* factory,
1045                                                  IDWriteFontCollection* collection,
1046                                                  IDWriteFontFallback* fallback) {
1047    if (nullptr == factory) {
1048        factory = sk_get_dwrite_factory();
1049        if (nullptr == factory) {
1050            return nullptr;
1051        }
1052    }
1053
1054    SkTScopedComPtr<IDWriteFontCollection> systemFontCollection;
1055    if (nullptr == collection) {
1056        HRNM(factory->GetSystemFontCollection(&systemFontCollection, FALSE),
1057             "Could not get system font collection.");
1058        collection = systemFontCollection.get();
1059    }
1060
1061    WCHAR localeNameStorage[LOCALE_NAME_MAX_LENGTH];
1062    WCHAR* localeName = nullptr;
1063    int localeNameLen = 0;
1064
1065    // Dynamically load GetUserDefaultLocaleName function, as it is not available on XP.
1066    SkGetUserDefaultLocaleNameProc getUserDefaultLocaleNameProc = nullptr;
1067    HRESULT hr = SkGetGetUserDefaultLocaleNameProc(&getUserDefaultLocaleNameProc);
1068    if (nullptr == getUserDefaultLocaleNameProc) {
1069        SK_TRACEHR(hr, "Could not get GetUserDefaultLocaleName.");
1070    } else {
1071        localeNameLen = getUserDefaultLocaleNameProc(localeNameStorage, LOCALE_NAME_MAX_LENGTH);
1072        if (localeNameLen) {
1073            localeName = localeNameStorage;
1074        };
1075    }
1076
1077    return sk_make_sp<SkFontMgr_DirectWrite>(factory, collection, fallback,
1078                                             localeName, localeNameLen);
1079}
1080
1081#include "SkFontMgr_indirect.h"
1082SK_API sk_sp<SkFontMgr> SkFontMgr_New_DirectWriteRenderer(sk_sp<SkRemotableFontMgr> proxy) {
1083    sk_sp<SkFontMgr> impl(SkFontMgr_New_DirectWrite());
1084    if (!impl) {
1085        return nullptr;
1086    }
1087    return sk_make_sp<SkFontMgr_Indirect>(std::move(impl), std::move(proxy));
1088}
1089#endif//defined(SK_BUILD_FOR_WIN)
1090