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