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