| Index: src/ports/SkRemotableFontMgr_win_dw.cpp
|
| ===================================================================
|
| --- src/ports/SkRemotableFontMgr_win_dw.cpp (revision 0)
|
| +++ src/ports/SkRemotableFontMgr_win_dw.cpp (working copy)
|
| @@ -0,0 +1,524 @@
|
| +/*
|
| + * 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 "SkDataTable.h"
|
| +#include "SkDWrite.h"
|
| +#include "SkDWriteFontFileStream.h"
|
| +#include "SkHRESULT.h"
|
| +#include "SkRemotableFontMgr.h"
|
| +#include "SkStream.h"
|
| +#include "SkString.h"
|
| +#include "SkTArray.h"
|
| +#include "SkThread.h"
|
| +#include "SkTScopedComPtr.h"
|
| +#include "SkTypeface_win.h"
|
| +#include "SkTypes.h"
|
| +#include "SkUtils.h"
|
| +
|
| +#include <dwrite.h>
|
| +
|
| +struct DWriteStyle {
|
| + explicit DWriteStyle(const SkFontStyle& pattern) {
|
| + switch (pattern.slant()) {
|
| + case SkFontStyle::kUpright_Slant:
|
| + fSlant = DWRITE_FONT_STYLE_NORMAL;
|
| + break;
|
| + case SkFontStyle::kItalic_Slant:
|
| + fSlant = DWRITE_FONT_STYLE_ITALIC;
|
| + break;
|
| + default:
|
| + SkASSERT(false);
|
| + }
|
| +
|
| + fWeight = (DWRITE_FONT_WEIGHT)pattern.weight();
|
| + fWidth = (DWRITE_FONT_STRETCH)pattern.width();
|
| + }
|
| + DWRITE_FONT_STYLE fSlant;
|
| + DWRITE_FONT_WEIGHT fWeight;
|
| + DWRITE_FONT_STRETCH fWidth;
|
| +};
|
| +
|
| +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() { }
|
| +
|
| + // This is actually a move!!!
|
| + explicit DataId(DataId& that)
|
| + : fLoader(that.fLoader), fKey(that.fKey), fKeySize(that.fKeySize)
|
| + {
|
| + that.fLoader = NULL;
|
| + that.fKey = NULL;
|
| + 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);
|
| +
|
| + SkAutoMutexAcquire ama(fDataIdCacheMutex);
|
| + int count = fDataIdCache.count();
|
| + 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:
|
| + SK_DECLARE_INST_COUNT(SkRemotableFontMgr_DirectWrite)
|
| +
|
| + /** 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));
|
| + }
|
| +
|
| + virtual SkDataTable* getFamilyNames() const SK_OVERRIDE {
|
| + int count = fFontCollection->GetFontFamilyCount();
|
| +
|
| + SkDataTableBuilder names(1024);
|
| + for (int index = 0; index < count; ++index) {
|
| + SkTScopedComPtr<IDWriteFontFamily> fontFamily;
|
| + HRNM(fFontCollection->GetFontFamily(index, &fontFamily),
|
| + "Could not get requested family.");
|
| +
|
| + SkTScopedComPtr<IDWriteLocalizedStrings> familyNames;
|
| + HRNM(fontFamily->GetFamilyNames(&familyNames), "Could not get family names.");
|
| +
|
| + SkString familyName;
|
| + sk_get_locale_string(familyNames.get(), fLocaleName.get(), &familyName);
|
| +
|
| + names.appendString(familyName);
|
| + }
|
| + return names.detachDataTable();
|
| + }
|
| +
|
| + 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, NULL));
|
| + 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
|
| + SkFontStyle::Slant slant;
|
| + switch (font->GetStyle()) {
|
| + case DWRITE_FONT_STYLE_NORMAL:
|
| + slant = SkFontStyle::kUpright_Slant;
|
| + break;
|
| + case DWRITE_FONT_STYLE_OBLIQUE:
|
| + case DWRITE_FONT_STYLE_ITALIC:
|
| + slant = SkFontStyle::kItalic_Slant;
|
| + break;
|
| + default:
|
| + SkASSERT(false);
|
| + }
|
| +
|
| + int weight = font->GetWeight();
|
| + int width = font->GetStretch();
|
| +
|
| + fontId->fFontStyle = SkFontStyle(weight, width, slant);
|
| + return S_OK;
|
| + }
|
| +
|
| + virtual SkRemotableFontIdentitySet* getIndex(int familyIndex) const SK_OVERRIDE {
|
| + SkTScopedComPtr<IDWriteFontFamily> fontFamily;
|
| + HRNM(fFontCollection->GetFontFamily(familyIndex, &fontFamily),
|
| + "Could not get requested family.");
|
| +
|
| + int count = fontFamily->GetFontCount();
|
| + SkFontIdentity* fontIds;
|
| + SkAutoTUnref<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.detach();
|
| + }
|
| +
|
| + virtual SkFontIdentity matchIndexStyle(int familyIndex,
|
| + const SkFontStyle& pattern) const SK_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), NULL, 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;
|
| + }
|
| +
|
| + virtual SkRemotableFontIdentitySet* matchName(const char familyName[]) const SK_OVERRIDE {
|
| + SkSMallocWCHAR dwFamilyName;
|
| + if (NULL == familyName) {
|
| + HR_GENERAL(getDefaultFontFamilyName(&dwFamilyName),
|
| + NULL, SkRemotableFontIdentitySet::NewEmpty());
|
| + } else {
|
| + HR_GENERAL(sk_cstring_to_wchar(familyName, &dwFamilyName),
|
| + NULL, 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 SK_OVERRIDE
|
| + {
|
| + SkFontIdentity identity = { SkFontIdentity::kInvalidDataId };
|
| +
|
| + SkSMallocWCHAR dwFamilyName;
|
| + if (NULL == familyName) {
|
| + HR_GENERAL(getDefaultFontFamilyName(&dwFamilyName), NULL, identity);
|
| + } else {
|
| + HR_GENERAL(sk_cstring_to_wchar(familyName, &dwFamilyName), NULL, 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;
|
| + }
|
| +
|
| + // IDWriteTextRenderer methods
|
| + virtual HRESULT STDMETHODCALLTYPE DrawGlyphRun(
|
| + void* clientDrawingContext,
|
| + FLOAT baselineOriginX,
|
| + FLOAT baselineOriginY,
|
| + DWRITE_MEASURING_MODE measuringMode,
|
| + DWRITE_GLYPH_RUN const* glyphRun,
|
| + DWRITE_GLYPH_RUN_DESCRIPTION const* glyphRunDescription,
|
| + IUnknown* clientDrawingEffect) SK_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;
|
| + }
|
| +
|
| + virtual HRESULT STDMETHODCALLTYPE DrawUnderline(
|
| + void* clientDrawingContext,
|
| + FLOAT baselineOriginX,
|
| + FLOAT baselineOriginY,
|
| + DWRITE_UNDERLINE const* underline,
|
| + IUnknown* clientDrawingEffect) SK_OVERRIDE
|
| + { return E_NOTIMPL; }
|
| +
|
| + virtual HRESULT STDMETHODCALLTYPE DrawStrikethrough(
|
| + void* clientDrawingContext,
|
| + FLOAT baselineOriginX,
|
| + FLOAT baselineOriginY,
|
| + DWRITE_STRIKETHROUGH const* strikethrough,
|
| + IUnknown* clientDrawingEffect) SK_OVERRIDE
|
| + { return E_NOTIMPL; }
|
| +
|
| + virtual HRESULT STDMETHODCALLTYPE DrawInlineObject(
|
| + void* clientDrawingContext,
|
| + FLOAT originX,
|
| + FLOAT originY,
|
| + IDWriteInlineObject* inlineObject,
|
| + BOOL isSideways,
|
| + BOOL isRightToLeft,
|
| + IUnknown* clientDrawingEffect) SK_OVERRIDE
|
| + { return E_NOTIMPL; }
|
| +
|
| + // IDWritePixelSnapping methods
|
| + virtual HRESULT STDMETHODCALLTYPE IsPixelSnappingDisabled(
|
| + void* clientDrawingContext,
|
| + BOOL* isDisabled) SK_OVERRIDE
|
| + {
|
| + *isDisabled = FALSE;
|
| + return S_OK;
|
| + }
|
| +
|
| + virtual HRESULT STDMETHODCALLTYPE GetCurrentTransform(
|
| + void* clientDrawingContext,
|
| + DWRITE_MATRIX* transform) SK_OVERRIDE
|
| + {
|
| + const DWRITE_MATRIX ident = {1.0, 0.0, 0.0, 1.0, 0.0, 0.0};
|
| + *transform = ident;
|
| + return S_OK;
|
| + }
|
| +
|
| + virtual HRESULT STDMETHODCALLTYPE GetPixelsPerDip(
|
| + void* clientDrawingContext,
|
| + FLOAT* pixelsPerDip) SK_OVERRIDE
|
| + {
|
| + *pixelsPerDip = 1.0f;
|
| + return S_OK;
|
| + }
|
| +
|
| + // IUnknown methods
|
| + virtual ULONG STDMETHODCALLTYPE AddRef() SK_OVERRIDE {
|
| + return InterlockedIncrement(&fRefCount);
|
| + }
|
| +
|
| + virtual ULONG STDMETHODCALLTYPE Release() SK_OVERRIDE {
|
| + ULONG newCount = InterlockedDecrement(&fRefCount);
|
| + if (0 == newCount) {
|
| + delete this;
|
| + }
|
| + return newCount;
|
| + }
|
| +
|
| + virtual HRESULT STDMETHODCALLTYPE QueryInterface(
|
| + IID const& riid, void** ppvObject) SK_OVERRIDE
|
| + {
|
| + if (__uuidof(IUnknown) == riid ||
|
| + __uuidof(IDWritePixelSnapping) == riid ||
|
| + __uuidof(IDWriteTextRenderer) == riid)
|
| + {
|
| + *ppvObject = this;
|
| + this->AddRef();
|
| + return S_OK;
|
| + }
|
| + *ppvObject = NULL;
|
| + return E_FAIL;
|
| + }
|
| +
|
| + const SkFontIdentity FallbackIdentity() { return fIdentity; }
|
| +
|
| + protected:
|
| + ULONG fRefCount;
|
| + SkAutoTUnref<const SkRemotableFontMgr_DirectWrite> fOuter;
|
| + UINT32 fCharacter;
|
| + SkFontIdentity fIdentity;
|
| + };
|
| +
|
| + virtual SkFontIdentity matchNameStyleCharacter(const char familyName[],
|
| + const SkFontStyle& pattern,
|
| + const char bpc47[],
|
| + SkUnichar character) const SK_OVERRIDE
|
| + {
|
| + SkFontIdentity identity = { SkFontIdentity::kInvalidDataId };
|
| +
|
| + IDWriteFactory* dwFactory = sk_get_dwrite_factory();
|
| + if (NULL == dwFactory) {
|
| + return identity;
|
| + }
|
| +
|
| + // TODO: use IDWriteFactory2::GetSystemFontFallback when available.
|
| +
|
| + const DWriteStyle dwStyle(pattern);
|
| +
|
| + SkSMallocWCHAR dwFamilyName;
|
| + if (NULL == familyName) {
|
| + HR_GENERAL(getDefaultFontFamilyName(&dwFamilyName), NULL, identity);
|
| + } else {
|
| + HR_GENERAL(sk_cstring_to_wchar(familyName, &dwFamilyName), NULL, identity);
|
| + }
|
| +
|
| + const SkSMallocWCHAR* dwBpc47;
|
| + SkSMallocWCHAR dwBpc47Local;
|
| + if (NULL == bpc47) {
|
| + dwBpc47 = &fLocaleName;
|
| + } else {
|
| + HR_GENERAL(sk_cstring_to_wchar(bpc47, &dwBpc47Local), NULL, identity);
|
| + dwBpc47 = &dwBpc47Local;
|
| + }
|
| +
|
| + SkTScopedComPtr<IDWriteTextFormat> fallbackFormat;
|
| + HR_GENERAL(dwFactory->CreateTextFormat(dwFamilyName,
|
| + fFontCollection.get(),
|
| + dwStyle.fWeight,
|
| + dwStyle.fSlant,
|
| + dwStyle.fWidth,
|
| + 72.0f,
|
| + *dwBpc47,
|
| + &fallbackFormat),
|
| + "Could not create text format.",
|
| + identity);
|
| +
|
| + WCHAR str[16];
|
| + UINT32 strLen = SkUTF16_FromUnichar(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(NULL, fontFallbackRenderer.get(), 50.0f, 50.0f),
|
| + "Could not draw layout with renderer.",
|
| + identity);
|
| +
|
| + return fontFallbackRenderer->FallbackIdentity();
|
| + }
|
| +
|
| + virtual SkStreamAsset* getData(int dataId) const SK_OVERRIDE {
|
| + SkAutoMutexAcquire ama(fDataIdCacheMutex);
|
| + if (dataId >= fDataIdCache.count()) {
|
| + return NULL;
|
| + }
|
| + 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 SkNEW_ARGS(SkDWriteFontFileStream, (fontFileStream.get()));
|
| + }
|
| +
|
| +private:
|
| + SkTScopedComPtr<IDWriteFontCollection> fFontCollection;
|
| + SkSMallocWCHAR fLocaleName;
|
| +
|
| + typedef SkRemotableFontMgr INHERITED;
|
| +};
|
| +
|
| +SkRemotableFontMgr* SkRemotableFontMgr_New_DirectWrite() {
|
| + IDWriteFactory* factory = sk_get_dwrite_factory();
|
| + if (NULL == factory) {
|
| + return NULL;
|
| + }
|
| +
|
| + SkTScopedComPtr<IDWriteFontCollection> sysFontCollection;
|
| + HRNM(factory->GetSystemFontCollection(&sysFontCollection, FALSE),
|
| + "Could not get system font collection.");
|
| +
|
| + WCHAR localeNameStorage[LOCALE_NAME_MAX_LENGTH];
|
| + WCHAR* localeName = NULL;
|
| + int localeNameLen = 0;
|
| +
|
| + // Dynamically load GetUserDefaultLocaleName function, as it is not available on XP.
|
| + SkGetUserDefaultLocaleNameProc getUserDefaultLocaleNameProc = NULL;
|
| + HRESULT hr = SkGetGetUserDefaultLocaleNameProc(&getUserDefaultLocaleNameProc);
|
| + if (NULL == getUserDefaultLocaleNameProc) {
|
| + SK_TRACEHR(hr, "Could not get GetUserDefaultLocaleName.");
|
| + } else {
|
| + localeNameLen = getUserDefaultLocaleNameProc(localeNameStorage, LOCALE_NAME_MAX_LENGTH);
|
| + if (localeNameLen) {
|
| + localeName = localeNameStorage;
|
| + };
|
| + }
|
| +
|
| + return SkNEW_ARGS(SkRemotableFontMgr_DirectWrite, (sysFontCollection.get(),
|
| + localeName, localeNameLen));
|
| +}
|
|
|