diff options
Diffstat (limited to 'gfx/skia/skia/src/ports/SkRemotableFontMgr_win_dw.cpp')
-rw-r--r-- | gfx/skia/skia/src/ports/SkRemotableFontMgr_win_dw.cpp | 472 |
1 files changed, 472 insertions, 0 deletions
diff --git a/gfx/skia/skia/src/ports/SkRemotableFontMgr_win_dw.cpp b/gfx/skia/skia/src/ports/SkRemotableFontMgr_win_dw.cpp new file mode 100644 index 0000000000..2c2d8520f4 --- /dev/null +++ b/gfx/skia/skia/src/ports/SkRemotableFontMgr_win_dw.cpp @@ -0,0 +1,472 @@ +/* + * Copyright 2014 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ +#include "src/utils/win/SkDWriteNTDDI_VERSION.h" + +#include "include/core/SkTypes.h" +#if defined(SK_BUILD_FOR_WIN) + +#include "include/core/SkStream.h" +#include "include/core/SkString.h" +#include "include/core/SkTypes.h" +#include "include/ports/SkRemotableFontMgr.h" +#include "include/private/base/SkMutex.h" +#include "include/private/base/SkTArray.h" +#include "src/base/SkUTF.h" +#include "src/ports/SkTypeface_win_dw.h" +#include "src/utils/win/SkDWrite.h" +#include "src/utils/win/SkDWriteFontFileStream.h" +#include "src/utils/win/SkHRESULT.h" +#include "src/utils/win/SkObjBase.h" +#include "src/utils/win/SkTScopedComPtr.h" + +#include <dwrite.h> + +class SK_API SkRemotableFontMgr_DirectWrite : public SkRemotableFontMgr { +private: + struct DataId { + IUnknown* fLoader; // In COM only IUnknown pointers may be safely used for identity. + void* fKey; + UINT32 fKeySize; + + DataId() { } + + DataId(DataId&& that) : fLoader(that.fLoader), fKey(that.fKey), fKeySize(that.fKeySize) { + that.fLoader = nullptr; + that.fKey = nullptr; + SkDEBUGCODE(that.fKeySize = 0xFFFFFFFF;) + } + + ~DataId() { + if (fLoader) { + fLoader->Release(); + } + sk_free(fKey); + } + }; + + mutable SkTArray<DataId> fDataIdCache; + mutable SkMutex fDataIdCacheMutex; + + int FindOrAdd(IDWriteFontFileLoader* fontFileLoader, + const void* refKey, UINT32 refKeySize) const + { + SkTScopedComPtr<IUnknown> fontFileLoaderId; + HR_GENERAL(fontFileLoader->QueryInterface(&fontFileLoaderId), + "Failed to re-convert to IDWriteFontFileLoader.", + SkFontIdentity::kInvalidDataId); + + SkAutoMutexExclusive ama(fDataIdCacheMutex); + int count = fDataIdCache.size(); + int i; + for (i = 0; i < count; ++i) { + const DataId& current = fDataIdCache[i]; + if (fontFileLoaderId.get() == current.fLoader && + refKeySize == current.fKeySize && + 0 == memcmp(refKey, current.fKey, refKeySize)) + { + return i; + } + } + DataId& added = fDataIdCache.push_back(); + added.fLoader = fontFileLoaderId.release(); // Ref is passed. + added.fKey = sk_malloc_throw(refKeySize); + memcpy(added.fKey, refKey, refKeySize); + added.fKeySize = refKeySize; + + return i; + } + +public: + + + /** localeNameLength must include the null terminator. */ + SkRemotableFontMgr_DirectWrite(IDWriteFontCollection* fontCollection, + WCHAR* localeName, int localeNameLength) + : fFontCollection(SkRefComPtr(fontCollection)) + , fLocaleName(localeNameLength) + { + memcpy(fLocaleName.get(), localeName, localeNameLength * sizeof(WCHAR)); + } + + HRESULT FontToIdentity(IDWriteFont* font, SkFontIdentity* fontId) const { + SkTScopedComPtr<IDWriteFontFace> fontFace; + HRM(font->CreateFontFace(&fontFace), "Could not create font face."); + + UINT32 numFiles; + HR(fontFace->GetFiles(&numFiles, nullptr)); + if (numFiles > 1) { + return E_FAIL; + } + + // data id + SkTScopedComPtr<IDWriteFontFile> fontFile; + HR(fontFace->GetFiles(&numFiles, &fontFile)); + + SkTScopedComPtr<IDWriteFontFileLoader> fontFileLoader; + HR(fontFile->GetLoader(&fontFileLoader)); + + const void* refKey; + UINT32 refKeySize; + HR(fontFile->GetReferenceKey(&refKey, &refKeySize)); + + fontId->fDataId = FindOrAdd(fontFileLoader.get(), refKey, refKeySize); + + // index + fontId->fTtcIndex = fontFace->GetIndex(); + + // style + fontId->fFontStyle = get_style(font); + return S_OK; + } + + SkRemotableFontIdentitySet* getIndex(int familyIndex) const override { + SkTScopedComPtr<IDWriteFontFamily> fontFamily; + HRNM(fFontCollection->GetFontFamily(familyIndex, &fontFamily), + "Could not get requested family."); + + int count = fontFamily->GetFontCount(); + SkFontIdentity* fontIds; + sk_sp<SkRemotableFontIdentitySet> fontIdSet( + new SkRemotableFontIdentitySet(count, &fontIds)); + for (int fontIndex = 0; fontIndex < count; ++fontIndex) { + SkTScopedComPtr<IDWriteFont> font; + HRNM(fontFamily->GetFont(fontIndex, &font), "Could not get font."); + + HRN(FontToIdentity(font.get(), &fontIds[fontIndex])); + } + return fontIdSet.release(); + } + + virtual SkFontIdentity matchIndexStyle(int familyIndex, + const SkFontStyle& pattern) const override + { + SkFontIdentity identity = { SkFontIdentity::kInvalidDataId }; + + SkTScopedComPtr<IDWriteFontFamily> fontFamily; + HR_GENERAL(fFontCollection->GetFontFamily(familyIndex, &fontFamily), + "Could not get requested family.", + identity); + + const DWriteStyle dwStyle(pattern); + SkTScopedComPtr<IDWriteFont> font; + HR_GENERAL(fontFamily->GetFirstMatchingFont(dwStyle.fWeight, dwStyle.fWidth, + dwStyle.fSlant, &font), + "Could not match font in family.", + identity); + + HR_GENERAL(FontToIdentity(font.get(), &identity), nullptr, identity); + + return identity; + } + + static HRESULT getDefaultFontFamilyName(SkSMallocWCHAR* name) { + NONCLIENTMETRICSW metrics; + metrics.cbSize = sizeof(metrics); + if (0 == SystemParametersInfoW(SPI_GETNONCLIENTMETRICS, + sizeof(metrics), + &metrics, + 0)) { + return E_UNEXPECTED; + } + + size_t len = wcsnlen_s(metrics.lfMessageFont.lfFaceName, LF_FACESIZE) + 1; + if (0 != wcsncpy_s(name->reset(len), len, metrics.lfMessageFont.lfFaceName, _TRUNCATE)) { + return E_UNEXPECTED; + } + + return S_OK; + } + + SkRemotableFontIdentitySet* matchName(const char familyName[]) const override { + SkSMallocWCHAR dwFamilyName; + if (nullptr == familyName) { + HR_GENERAL(getDefaultFontFamilyName(&dwFamilyName), + nullptr, SkRemotableFontIdentitySet::NewEmpty()); + } else { + HR_GENERAL(sk_cstring_to_wchar(familyName, &dwFamilyName), + nullptr, SkRemotableFontIdentitySet::NewEmpty()); + } + + UINT32 index; + BOOL exists; + HR_GENERAL(fFontCollection->FindFamilyName(dwFamilyName.get(), &index, &exists), + "Failed while finding family by name.", + SkRemotableFontIdentitySet::NewEmpty()); + if (!exists) { + return SkRemotableFontIdentitySet::NewEmpty(); + } + + return this->getIndex(index); + } + + virtual SkFontIdentity matchNameStyle(const char familyName[], + const SkFontStyle& style) const override + { + SkFontIdentity identity = { SkFontIdentity::kInvalidDataId }; + + SkSMallocWCHAR dwFamilyName; + if (nullptr == familyName) { + HR_GENERAL(getDefaultFontFamilyName(&dwFamilyName), nullptr, identity); + } else { + HR_GENERAL(sk_cstring_to_wchar(familyName, &dwFamilyName), nullptr, identity); + } + + UINT32 index; + BOOL exists; + HR_GENERAL(fFontCollection->FindFamilyName(dwFamilyName.get(), &index, &exists), + "Failed while finding family by name.", + identity); + if (!exists) { + return identity; + } + + return this->matchIndexStyle(index, style); + } + + class FontFallbackRenderer : public IDWriteTextRenderer { + public: + FontFallbackRenderer(const SkRemotableFontMgr_DirectWrite* outer, UINT32 character) + : fRefCount(1), fOuter(SkSafeRef(outer)), fCharacter(character) { + fIdentity.fDataId = SkFontIdentity::kInvalidDataId; + } + + virtual ~FontFallbackRenderer() { } + + // IDWriteTextRenderer methods + SK_STDMETHODIMP DrawGlyphRun( + void* clientDrawingContext, + FLOAT baselineOriginX, + FLOAT baselineOriginY, + DWRITE_MEASURING_MODE measuringMode, + DWRITE_GLYPH_RUN const* glyphRun, + DWRITE_GLYPH_RUN_DESCRIPTION const* glyphRunDescription, + IUnknown* clientDrawingEffect) override + { + SkTScopedComPtr<IDWriteFont> font; + HRM(fOuter->fFontCollection->GetFontFromFontFace(glyphRun->fontFace, &font), + "Could not get font from font face."); + + // It is possible that the font passed does not actually have the requested character, + // due to no font being found and getting the fallback font. + // Check that the font actually contains the requested character. + BOOL exists; + HRM(font->HasCharacter(fCharacter, &exists), "Could not find character."); + + if (exists) { + HR(fOuter->FontToIdentity(font.get(), &fIdentity)); + } + + return S_OK; + } + + SK_STDMETHODIMP DrawUnderline( + void* clientDrawingContext, + FLOAT baselineOriginX, + FLOAT baselineOriginY, + DWRITE_UNDERLINE const* underline, + IUnknown* clientDrawingEffect) override + { return E_NOTIMPL; } + + SK_STDMETHODIMP DrawStrikethrough( + void* clientDrawingContext, + FLOAT baselineOriginX, + FLOAT baselineOriginY, + DWRITE_STRIKETHROUGH const* strikethrough, + IUnknown* clientDrawingEffect) override + { return E_NOTIMPL; } + + SK_STDMETHODIMP DrawInlineObject( + void* clientDrawingContext, + FLOAT originX, + FLOAT originY, + IDWriteInlineObject* inlineObject, + BOOL isSideways, + BOOL isRightToLeft, + IUnknown* clientDrawingEffect) override + { return E_NOTIMPL; } + + // IDWritePixelSnapping methods + SK_STDMETHODIMP IsPixelSnappingDisabled( + void* clientDrawingContext, + BOOL* isDisabled) override + { + *isDisabled = FALSE; + return S_OK; + } + + SK_STDMETHODIMP GetCurrentTransform( + void* clientDrawingContext, + DWRITE_MATRIX* transform) override + { + const DWRITE_MATRIX ident = {1.0, 0.0, 0.0, 1.0, 0.0, 0.0}; + *transform = ident; + return S_OK; + } + + SK_STDMETHODIMP GetPixelsPerDip( + void* clientDrawingContext, + FLOAT* pixelsPerDip) override + { + *pixelsPerDip = 1.0f; + return S_OK; + } + + // IUnknown methods + SK_STDMETHODIMP_(ULONG) AddRef() override { + return InterlockedIncrement(&fRefCount); + } + + SK_STDMETHODIMP_(ULONG) Release() override { + ULONG newCount = InterlockedDecrement(&fRefCount); + if (0 == newCount) { + delete this; + } + return newCount; + } + + SK_STDMETHODIMP QueryInterface( + IID const& riid, void** ppvObject) override + { + if (__uuidof(IUnknown) == riid || + __uuidof(IDWritePixelSnapping) == riid || + __uuidof(IDWriteTextRenderer) == riid) + { + *ppvObject = this; + this->AddRef(); + return S_OK; + } + *ppvObject = nullptr; + return E_FAIL; + } + + const SkFontIdentity FallbackIdentity() { return fIdentity; } + + protected: + ULONG fRefCount; + sk_sp<const SkRemotableFontMgr_DirectWrite> fOuter; + UINT32 fCharacter; + SkFontIdentity fIdentity; + }; + + virtual SkFontIdentity matchNameStyleCharacter(const char familyName[], + const SkFontStyle& pattern, + const char* bcp47[], int bcp47Count, + SkUnichar character) const override + { + SkFontIdentity identity = { SkFontIdentity::kInvalidDataId }; + + IDWriteFactory* dwFactory = sk_get_dwrite_factory(); + if (nullptr == dwFactory) { + return identity; + } + + // TODO: use IDWriteFactory2::GetSystemFontFallback when available. + + const DWriteStyle dwStyle(pattern); + + SkSMallocWCHAR dwFamilyName; + if (nullptr == familyName) { + HR_GENERAL(getDefaultFontFamilyName(&dwFamilyName), nullptr, identity); + } else { + HR_GENERAL(sk_cstring_to_wchar(familyName, &dwFamilyName), nullptr, identity); + } + + const SkSMallocWCHAR* dwBcp47; + SkSMallocWCHAR dwBcp47Local; + if (bcp47Count < 1) { + dwBcp47 = &fLocaleName; + } else { + //TODO: support fallback stack. + HR_GENERAL(sk_cstring_to_wchar(bcp47[bcp47Count-1], &dwBcp47Local), nullptr, identity); + dwBcp47 = &dwBcp47Local; + } + + SkTScopedComPtr<IDWriteTextFormat> fallbackFormat; + HR_GENERAL(dwFactory->CreateTextFormat(dwFamilyName, + fFontCollection.get(), + dwStyle.fWeight, + dwStyle.fSlant, + dwStyle.fWidth, + 72.0f, + *dwBcp47, + &fallbackFormat), + "Could not create text format.", + identity); + + WCHAR str[16]; + UINT32 strLen = static_cast<UINT32>( + SkUTF::ToUTF16(character, reinterpret_cast<uint16_t*>(str))); + SkTScopedComPtr<IDWriteTextLayout> fallbackLayout; + HR_GENERAL(dwFactory->CreateTextLayout(str, strLen, fallbackFormat.get(), + 200.0f, 200.0f, + &fallbackLayout), + "Could not create text layout.", + identity); + + SkTScopedComPtr<FontFallbackRenderer> fontFallbackRenderer( + new FontFallbackRenderer(this, character)); + + HR_GENERAL(fallbackLayout->Draw(nullptr, fontFallbackRenderer.get(), 50.0f, 50.0f), + "Could not draw layout with renderer.", + identity); + + return fontFallbackRenderer->FallbackIdentity(); + } + + SkStreamAsset* getData(int dataId) const override { + SkAutoMutexExclusive ama(fDataIdCacheMutex); + if (dataId >= fDataIdCache.size()) { + return nullptr; + } + const DataId& id = fDataIdCache[dataId]; + + SkTScopedComPtr<IDWriteFontFileLoader> loader; + HRNM(id.fLoader->QueryInterface(&loader), "QuerryInterface IDWriteFontFileLoader failed"); + + SkTScopedComPtr<IDWriteFontFileStream> fontFileStream; + HRNM(loader->CreateStreamFromKey(id.fKey, id.fKeySize, &fontFileStream), + "Could not create font file stream."); + + return new SkDWriteFontFileStream(fontFileStream.get()); + } + +private: + SkTScopedComPtr<IDWriteFontCollection> fFontCollection; + SkSMallocWCHAR fLocaleName; + + using INHERITED = SkRemotableFontMgr; +}; + +SkRemotableFontMgr* SkRemotableFontMgr_New_DirectWrite() { + IDWriteFactory* factory = sk_get_dwrite_factory(); + if (nullptr == factory) { + return nullptr; + } + + SkTScopedComPtr<IDWriteFontCollection> sysFontCollection; + HRNM(factory->GetSystemFontCollection(&sysFontCollection, FALSE), + "Could not get system font collection."); + + WCHAR localeNameStorage[LOCALE_NAME_MAX_LENGTH]; + WCHAR* localeName = nullptr; + int localeNameLen = 0; + + // Dynamically load GetUserDefaultLocaleName function, as it is not available on XP. + SkGetUserDefaultLocaleNameProc getUserDefaultLocaleNameProc = nullptr; + HRESULT hr = SkGetGetUserDefaultLocaleNameProc(&getUserDefaultLocaleNameProc); + if (nullptr == getUserDefaultLocaleNameProc) { + SK_TRACEHR(hr, "Could not get GetUserDefaultLocaleName."); + } else { + localeNameLen = getUserDefaultLocaleNameProc(localeNameStorage, LOCALE_NAME_MAX_LENGTH); + if (localeNameLen) { + localeName = localeNameStorage; + }; + } + + return new SkRemotableFontMgr_DirectWrite(sysFontCollection.get(), localeName, localeNameLen); +} +#endif//defined(SK_BUILD_FOR_WIN) |