diff options
-rw-r--r-- | src/ports/SkFontMgr_win_dw.cpp | 201 | ||||
-rw-r--r-- | src/ports/SkRemotableFontMgr_win_dw.cpp | 21 | ||||
-rw-r--r-- | src/utils/win/SkDWrite.h | 25 |
3 files changed, 223 insertions, 24 deletions
diff --git a/src/ports/SkFontMgr_win_dw.cpp b/src/ports/SkFontMgr_win_dw.cpp index e5ddcac8c5..96acd170ae 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, diff --git a/src/ports/SkRemotableFontMgr_win_dw.cpp b/src/ports/SkRemotableFontMgr_win_dw.cpp index 5c3205d523..ad1efb7b12 100644 --- a/src/ports/SkRemotableFontMgr_win_dw.cpp +++ b/src/ports/SkRemotableFontMgr_win_dw.cpp @@ -21,27 +21,6 @@ #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 { diff --git a/src/utils/win/SkDWrite.h b/src/utils/win/SkDWrite.h index 5b566730e5..1716b83785 100644 --- a/src/utils/win/SkDWrite.h +++ b/src/utils/win/SkDWrite.h @@ -9,6 +9,7 @@ #define SkDWrite_DEFINED #include "SkTemplates.h" +#include "SkFontStyle.h" #include <dwrite.h> #include <winsdkver.h> @@ -80,4 +81,28 @@ public: const T* operator->() const { return reinterpret_cast<const T*>(fData); } }; +//////////////////////////////////////////////////////////////////////////////// +// Style conversion + +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; +}; + #endif |