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