| Index: src/ports/SkFontMgr_win_dw.cpp
|
| diff --git a/src/ports/SkFontMgr_win_dw.cpp b/src/ports/SkFontMgr_win_dw.cpp
|
| index e5ddcac8c59c2ed3d68136753ed6567f4133f399..96acd170ae73071371386b8bc611e02eb3721a01 100644
|
| --- a/src/ports/SkFontMgr_win_dw.cpp
|
| +++ b/src/ports/SkFontMgr_win_dw.cpp
|
| @@ -16,6 +16,7 @@
|
| #include "SkTypefaceCache.h"
|
| #include "SkTypeface_win_dw.h"
|
| #include "SkTypes.h"
|
| +#include "SkUtils.h"
|
|
|
| #include <dwrite.h>
|
|
|
| @@ -298,6 +299,7 @@ private:
|
| mutable SkTypefaceCache fTFCache;
|
|
|
| friend class SkFontStyleSet_DirectWrite;
|
| + friend class FontFallbackRenderer;
|
| };
|
|
|
| class SkFontStyleSet_DirectWrite : public SkFontStyleSet {
|
| @@ -487,11 +489,204 @@ SkTypeface* SkFontMgr_DirectWrite::onMatchFamilyStyle(const char familyName[],
|
| return sset->matchStyle(fontstyle);
|
| }
|
|
|
| +class FontFallbackRenderer : public IDWriteTextRenderer {
|
| +public:
|
| + FontFallbackRenderer(const SkFontMgr_DirectWrite* outer, UINT32 character)
|
| + : fRefCount(1), fOuter(SkSafeRef(outer)), fCharacter(character), fResolvedTypeface(NULL) {
|
| + }
|
| +
|
| + virtual ~FontFallbackRenderer() { }
|
| +
|
| + // 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) {
|
| + SkTScopedComPtr<IDWriteFontFamily> fontFamily;
|
| + HRM(font->GetFontFamily(&fontFamily), "Could not get family.");
|
| + fResolvedTypeface = fOuter->createTypefaceFromDWriteFont(glyphRun->fontFace,
|
| + font.get(),
|
| + fontFamily.get());
|
| + }
|
| +
|
| + 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
|
| + ULONG STDMETHODCALLTYPE AddRef() SK_OVERRIDE {
|
| + return InterlockedIncrement(&fRefCount);
|
| + }
|
| +
|
| + 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;
|
| + }
|
| +
|
| + SkTypeface* FallbackTypeface() { return fResolvedTypeface; }
|
| +
|
| +protected:
|
| + ULONG fRefCount;
|
| + SkAutoTUnref<const SkFontMgr_DirectWrite> fOuter;
|
| + UINT32 fCharacter;
|
| + SkTypeface* fResolvedTypeface;
|
| +};
|
| +
|
| +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;
|
| +}
|
| +
|
| SkTypeface* SkFontMgr_DirectWrite::onMatchFamilyStyleCharacter(const char familyName[],
|
| - const SkFontStyle&,
|
| + const SkFontStyle& style,
|
| const char* bcp47[], int bcp47Count,
|
| - SkUnichar character) const {
|
| - return NULL;
|
| + SkUnichar character) const
|
| +{
|
| + // TODO: use IDWriteFactory2::GetSystemFontFallback when available.
|
| +
|
| + const DWriteStyle dwStyle(style);
|
| +
|
| + SkSMallocWCHAR dwFamilyName;
|
| + if (NULL == familyName) {
|
| + HRN(getDefaultFontFamilyName(&dwFamilyName));
|
| + } else {
|
| + HRN(sk_cstring_to_wchar(familyName, &dwFamilyName));
|
| + }
|
| +
|
| + const SkSMallocWCHAR* dwBcp47;
|
| + SkSMallocWCHAR dwBcp47Local;
|
| + if (bcp47Count < 1) {
|
| + dwBcp47 = &fLocaleName;
|
| + } else {
|
| + // TODO: support fallback stack.
|
| + // TODO: DirectWrite supports 'zh-CN' or 'zh-Hans', but 'zh' misses completely
|
| + // and may produce a Japanese font.
|
| + HRN(sk_cstring_to_wchar(bcp47[bcp47Count - 1], &dwBcp47Local));
|
| + dwBcp47 = &dwBcp47Local;
|
| + }
|
| +
|
| + SkTScopedComPtr<IDWriteTextFormat> fallbackFormat;
|
| + HRNM(fFactory->CreateTextFormat(dwFamilyName,
|
| + fFontCollection.get(),
|
| + dwStyle.fWeight,
|
| + dwStyle.fSlant,
|
| + dwStyle.fWidth,
|
| + 72.0f,
|
| + *dwBcp47,
|
| + &fallbackFormat),
|
| + "Could not create text format.");
|
| +
|
| + WCHAR str[16];
|
| + UINT32 strLen = static_cast<UINT32>(
|
| + SkUTF16_FromUnichar(character, reinterpret_cast<uint16_t*>(str)));
|
| + SkTScopedComPtr<IDWriteTextLayout> fallbackLayout;
|
| + HRNM(fFactory->CreateTextLayout(str, strLen, fallbackFormat.get(),
|
| + 200.0f, 200.0f,
|
| + &fallbackLayout),
|
| + "Could not create text layout.");
|
| +
|
| + SkTScopedComPtr<FontFallbackRenderer> fontFallbackRenderer(
|
| + new FontFallbackRenderer(this, character));
|
| +
|
| + HRNM(fallbackLayout->Draw(NULL, fontFallbackRenderer.get(), 50.0f, 50.0f),
|
| + "Could not draw layout with renderer.");
|
| +
|
| + return fontFallbackRenderer->FallbackTypeface();
|
| }
|
|
|
| SkTypeface* SkFontMgr_DirectWrite::onMatchFaceStyle(const SkTypeface* familyMember,
|
|
|