Implement onMatchFamilyStyleCharacter for DirectWrite.
Review URL: https://codereview.chromium.org/946603002
diff --git a/src/ports/SkFontMgr_win_dw.cpp b/src/ports/SkFontMgr_win_dw.cpp
index e5ddcac..96acd17 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 @@
mutable SkTypefaceCache fTFCache;
friend class SkFontStyleSet_DirectWrite;
+ friend class FontFallbackRenderer;
};
class SkFontStyleSet_DirectWrite : public SkFontStyleSet {
@@ -487,11 +489,204 @@
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 5c3205d..ad1efb7 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 5b56673..1716b83 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 @@
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