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