summaryrefslogtreecommitdiffstats
path: root/gfx/skia/skia/src/ports/SkRemotableFontMgr_win_dw.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'gfx/skia/skia/src/ports/SkRemotableFontMgr_win_dw.cpp')
-rw-r--r--gfx/skia/skia/src/ports/SkRemotableFontMgr_win_dw.cpp472
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)