Home | History | Annotate | Download | only in ports
      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 
     30 class StreamFontFileLoader : public IDWriteFontFileLoader {
     31 public:
     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 
     55 private:
     56     StreamFontFileLoader(std::unique_ptr<SkStreamAsset> stream)
     57         : fStream(std::move(stream)), fRefCount(1)
     58     {}
     59     virtual ~StreamFontFileLoader() { }
     60 
     61     ULONG fRefCount;
     62 };
     63 
     64 HRESULT 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 
     75 ULONG StreamFontFileLoader::AddRef() {
     76     return InterlockedIncrement(&fRefCount);
     77 }
     78 
     79 ULONG StreamFontFileLoader::Release() {
     80     ULONG newCount = InterlockedDecrement(&fRefCount);
     81     if (0 == newCount) {
     82         delete this;
     83     }
     84     return newCount;
     85 }
     86 
     87 HRESULT 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 
    100 class StreamFontFileEnumerator : public IDWriteFontFileEnumerator {
    101 public:
    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     }
    119 private:
    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 
    131 StreamFontFileEnumerator::StreamFontFileEnumerator(IDWriteFactory* factory,
    132                                                    IDWriteFontFileLoader* fontFileLoader)
    133     : fRefCount(1)
    134     , fFactory(SkRefComPtr(factory))
    135     , fCurrentFile()
    136     , fFontFileLoader(SkRefComPtr(fontFileLoader))
    137     , fHasNext(true)
    138 { }
    139 
    140 HRESULT 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 
    151 ULONG StreamFontFileEnumerator::AddRef() {
    152     return InterlockedIncrement(&fRefCount);
    153 }
    154 
    155 ULONG StreamFontFileEnumerator::Release() {
    156     ULONG newCount = InterlockedDecrement(&fRefCount);
    157     if (0 == newCount) {
    158         delete this;
    159     }
    160     return newCount;
    161 }
    162 
    163 HRESULT 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 
    182 HRESULT 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 
    194 class StreamFontCollectionLoader : public IDWriteFontCollectionLoader {
    195 public:
    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     }
    216 private:
    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 
    227 HRESULT 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 
    238 ULONG StreamFontCollectionLoader::AddRef() {
    239     return InterlockedIncrement(&fRefCount);
    240 }
    241 
    242 ULONG StreamFontCollectionLoader::Release() {
    243     ULONG newCount = InterlockedDecrement(&fRefCount);
    244     if (0 == newCount) {
    245         delete this;
    246     }
    247     return newCount;
    248 }
    249 
    250 HRESULT 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 
    264 class SkFontMgr_DirectWrite : public SkFontMgr {
    265 public:
    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 
    286 protected:
    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 
    303 private:
    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 
    324 class SkFontStyleSet_DirectWrite : public SkFontStyleSet {
    325 public:
    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 
    337 private:
    338     sk_sp<const SkFontMgr_DirectWrite> fFontMgr;
    339     SkTScopedComPtr<IDWriteFontFamily> fFontFamily;
    340 };
    341 
    342 static 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 
    353 struct ProtoDWriteTypeface {
    354     IDWriteFontFace* fDWriteFontFace;
    355     IDWriteFont* fDWriteFont;
    356     IDWriteFontFamily* fDWriteFontFamily;
    357 };
    358 
    359 static 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 
    453 sk_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 
    469 int SkFontMgr_DirectWrite::onCountFamilies() const {
    470     return fFontCollection->GetFontFamilyCount();
    471 }
    472 
    473 void 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 
    483 SkFontStyleSet* 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 
    490 SkFontStyleSet* 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 
    509 SkTypeface* 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 
    515 class FontFallbackRenderer : public IDWriteTextRenderer {
    516 public:
    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 
    634 protected:
    635     ULONG fRefCount;
    636     sk_sp<const SkFontMgr_DirectWrite> fOuter;
    637     UINT32 fCharacter;
    638     SkTypeface* fResolvedTypeface;
    639 };
    640 
    641 class FontFallbackSource : public IDWriteTextAnalysisSource {
    642 public:
    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 
    732 protected:
    733     ULONG fRefCount;
    734     const WCHAR* fString;
    735     UINT32 fLength;
    736     const WCHAR* fLocale;
    737     IDWriteNumberSubstitution* fNumberSubstitution;
    738 };
    739 
    740 SkTypeface* 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 
    839 SkTypeface* 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 
    848 template <typename T> class SkAutoIDWriteUnregister {
    849 public:
    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 
    866 private:
    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 
    879 sk_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 
    927 sk_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 
    931 sk_sp<SkTypeface> SkFontMgr_DirectWrite::onMakeFromFile(const char path[], int ttcIndex) const {
    932     return this->makeFromStream(SkStream::MakeFromFile(path), ttcIndex);
    933 }
    934 
    935 HRESULT 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 
    947 HRESULT 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 
    958 sk_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 
    992 int SkFontStyleSet_DirectWrite::count() {
    993     return fFontFamily->GetFontCount();
    994 }
    995 
    996 SkTypeface* 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 
   1006 void 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 
   1022 SkTypeface* 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 
   1039 SK_API sk_sp<SkFontMgr> SkFontMgr_New_DirectWrite(IDWriteFactory* factory,
   1040                                                   IDWriteFontCollection* collection) {
   1041     return SkFontMgr_New_DirectWrite(factory, collection, nullptr);
   1042 }
   1043 
   1044 SK_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"
   1082 SK_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