patch 8.0.1343: MS-Windows: does not show colored emojis

Problem:    MS-Windows: does not show colored emojis.
Solution:   Implement colored emojis. Improve drawing speed. Make 'taamode'
            work. (Taro Muraoka, Yasuhiro Matsumoto, Ken Takata, close #2375)
diff --git a/src/gui_dwrite.cpp b/src/gui_dwrite.cpp
index 9873c67..bd76383 100644
--- a/src/gui_dwrite.cpp
+++ b/src/gui_dwrite.cpp
@@ -4,6 +4,7 @@
  *
  * Contributors:
  *  - Ken Takata
+ *  - Yasuhiro Matsumoto
  *
  * Copyright (C) 2013 MURAOKA Taro <koron.kaoriya@gmail.com>
  * THIS FILE IS DISTRIBUTED UNDER THE VIM LICENSE.
@@ -23,7 +24,21 @@
 #include <math.h>
 #include <d2d1.h>
 #include <d2d1helper.h>
-#include <dwrite.h>
+
+// Disable these macros to compile with old VC and newer SDK (V8.1 or later).
+#if defined(_MSC_VER) && (_MSC_VER < 1700)
+# define _COM_Outptr_ __out
+# define _In_reads_(s)
+# define _In_reads_opt_(s)
+# define _Maybenull_
+# define _Out_writes_(s)
+# define _Out_writes_opt_(s)
+# define _Out_writes_to_(x, y)
+# define _Out_writes_to_opt_(x, y)
+# define _Outptr_
+#endif
+
+#include <dwrite_2.h>
 
 #include "gui_dwrite.h"
 
@@ -79,16 +94,6 @@
     }
 }
 
-struct GdiTextRendererContext
-{
-    // const fields.
-    COLORREF color;
-    FLOAT cellWidth;
-
-    // working fields.
-    FLOAT offsetX;
-};
-
     static DWRITE_PIXEL_GEOMETRY
 ToPixelGeometry(int value)
 {
@@ -184,17 +189,151 @@
     }
 }
 
+class FontCache {
+public:
+    struct Item {
+	HFONT              hFont;
+	IDWriteTextFormat* pTextFormat;
+	DWRITE_FONT_WEIGHT fontWeight;
+	DWRITE_FONT_STYLE  fontStyle;
+	Item() : hFont(NULL), pTextFormat(NULL) {}
+    };
+
+private:
+    int mSize;
+    Item *mItems;
+
+public:
+    FontCache(int size = 2) :
+	mSize(size),
+	mItems(new Item[size])
+    {
+    }
+
+    ~FontCache()
+    {
+	for (int i = 0; i < mSize; ++i)
+	    SafeRelease(&mItems[i].pTextFormat);
+	delete[] mItems;
+    }
+
+    bool get(HFONT hFont, Item &item)
+    {
+	int n = find(hFont);
+	if (n < 0)
+	    return false;
+	item = mItems[n];
+	slide(n);
+	return true;
+    }
+
+    void put(const Item& item)
+    {
+	int n = find(item.hFont);
+	if (n < 0)
+	    n = mSize - 1;
+	if (mItems[n].pTextFormat != item.pTextFormat)
+	{
+	    SafeRelease(&mItems[n].pTextFormat);
+	    item.pTextFormat->AddRef();
+	}
+	mItems[n] = item;
+	slide(n);
+    }
+
+private:
+    int find(HFONT hFont)
+    {
+	for (int i = 0; i < mSize; ++i)
+	{
+	    if (mItems[i].hFont == hFont)
+		return i;
+	}
+	return -1;
+    }
+
+    void slide(int nextTop)
+    {
+	if (nextTop == 0)
+	    return;
+	Item tmp = mItems[nextTop];
+	for (int i = nextTop - 1; i >= 0; --i)
+	    mItems[i + 1] = mItems[i];
+	mItems[0] = tmp;
+    }
+};
+
+struct DWriteContext {
+    HDC mHDC;
+    bool mDrawing;
+    bool mFallbackDC;
+
+    ID2D1Factory *mD2D1Factory;
+
+    ID2D1DCRenderTarget *mRT;
+    ID2D1SolidColorBrush *mBrush;
+
+    IDWriteFactory *mDWriteFactory;
+    IDWriteFactory2 *mDWriteFactory2;
+
+    IDWriteGdiInterop *mGdiInterop;
+    IDWriteRenderingParams *mRenderingParams;
+
+    FontCache mFontCache;
+    IDWriteTextFormat *mTextFormat;
+    DWRITE_FONT_WEIGHT mFontWeight;
+    DWRITE_FONT_STYLE mFontStyle;
+
+    D2D1_TEXT_ANTIALIAS_MODE mTextAntialiasMode;
+
+    // METHODS
+
+    DWriteContext();
+
+    virtual ~DWriteContext();
+
+    HRESULT CreateTextFormatFromLOGFONT(const LOGFONTW &logFont,
+	    IDWriteTextFormat **ppTextFormat);
+
+    HRESULT SetFontByLOGFONT(const LOGFONTW &logFont);
+
+    void SetFont(HFONT hFont);
+
+    void BindDC(HDC hdc, RECT *rect);
+
+    void AssureDrawing();
+
+    ID2D1Brush* SolidBrush(COLORREF color);
+
+    void DrawText(const WCHAR* text, int len,
+	int x, int y, int w, int h, int cellWidth, COLORREF color,
+	UINT fuOptions, CONST RECT *lprc, CONST INT * lpDx);
+
+    void FillRect(RECT *rc, COLORREF color);
+
+    void Flush();
+
+    void SetRenderingParams(
+	    const DWriteRenderingParams *params);
+
+    DWriteRenderingParams *GetRenderingParams(
+	    DWriteRenderingParams *params);
+};
+
 class AdjustedGlyphRun : public DWRITE_GLYPH_RUN
 {
 private:
+    FLOAT &mAccum;
     FLOAT mDelta;
     FLOAT *mAdjustedAdvances;
 
 public:
     AdjustedGlyphRun(
 	    const DWRITE_GLYPH_RUN *glyphRun,
-	    FLOAT cellWidth) :
+	    FLOAT cellWidth,
+	    FLOAT &accum) :
 	DWRITE_GLYPH_RUN(*glyphRun),
+	mAccum(accum),
 	mDelta(0.0f),
 	mAdjustedAdvances(new FLOAT[glyphRun->glyphCount])
     {
@@ -209,45 +348,44 @@
 	glyphAdvances = mAdjustedAdvances;
     }
 
-    ~AdjustedGlyphRun(void)
+    ~AdjustedGlyphRun()
     {
+	mAccum += mDelta;
 	delete[] mAdjustedAdvances;
     }
 
-    FLOAT getDelta(void) const
-    {
-	return mDelta;
-    }
-
     static FLOAT adjustToCell(FLOAT value, FLOAT cellWidth)
     {
-	int cellCount = (int)floor(value / cellWidth + 0.5f);
+	int cellCount = int(floor(value / cellWidth + 0.5f));
 	if (cellCount < 1)
 	    cellCount = 1;
 	return cellCount * cellWidth;
     }
 };
 
-class GdiTextRenderer FINAL : public IDWriteTextRenderer
+struct TextRendererContext {
+    // const fields.
+    COLORREF color;
+    FLOAT cellWidth;
+
+    // working fields.
+    FLOAT offsetX;
+};
+
+class TextRenderer FINAL : public IDWriteTextRenderer
 {
 public:
-    GdiTextRenderer(
-	    IDWriteBitmapRenderTarget* bitmapRenderTarget,
-	    IDWriteRenderingParams* renderingParams) :
+    TextRenderer(
+	    DWriteContext* pDWC) :
 	cRefCount_(0),
-	pRenderTarget_(bitmapRenderTarget),
-	pRenderingParams_(renderingParams)
+	pDWC_(pDWC)
     {
-	pRenderTarget_->AddRef();
-	pRenderingParams_->AddRef();
 	AddRef();
     }
 
     // add "virtual" to avoid a compiler warning
-    virtual ~GdiTextRenderer()
+    virtual ~TextRenderer()
     {
-	SafeRelease(&pRenderTarget_);
-	SafeRelease(&pRenderingParams_);
     }
 
     IFACEMETHOD(IsPixelSnappingDisabled)(
@@ -263,7 +401,8 @@
 	__out DWRITE_MATRIX* transform)
     {
 	// forward the render target's transform
-	pRenderTarget_->GetCurrentTransform(transform);
+	pDWC_->mRT->GetTransform(
+		reinterpret_cast<D2D1_MATRIX_3X2_F*>(transform));
 	return S_OK;
     }
 
@@ -271,43 +410,12 @@
 	__maybenull void* clientDrawingContext,
 	__out FLOAT* pixelsPerDip)
     {
-	*pixelsPerDip = pRenderTarget_->GetPixelsPerDip();
+	float dpiX, unused;
+	pDWC_->mRT->GetDpi(&dpiX, &unused);
+	*pixelsPerDip = dpiX / 96.0f;
 	return S_OK;
     }
 
-    IFACEMETHOD(DrawGlyphRun)(
-	__maybenull void* clientDrawingContext,
-	FLOAT baselineOriginX,
-	FLOAT baselineOriginY,
-	DWRITE_MEASURING_MODE measuringMode,
-	__in DWRITE_GLYPH_RUN const* glyphRun,
-	__in DWRITE_GLYPH_RUN_DESCRIPTION const* glyphRunDescription,
-	IUnknown* clientDrawingEffect)
-    {
-	HRESULT hr = S_OK;
-
-	GdiTextRendererContext *context =
-	    reinterpret_cast<GdiTextRendererContext*>(clientDrawingContext);
-
-	AdjustedGlyphRun adjustedGlyphRun(glyphRun, context->cellWidth);
-
-	// Pass on the drawing call to the render target to do the real work.
-	RECT dirtyRect = {0};
-
-	hr = pRenderTarget_->DrawGlyphRun(
-		baselineOriginX + context->offsetX,
-		baselineOriginY,
-		measuringMode,
-		&adjustedGlyphRun,
-		pRenderingParams_,
-		context->color,
-		&dirtyRect);
-
-	context->offsetX += adjustedGlyphRun.getDelta();
-
-	return hr;
-    }
-
     IFACEMETHOD(DrawUnderline)(
 	__maybenull void* clientDrawingContext,
 	FLOAT baselineOriginX,
@@ -340,6 +448,69 @@
 	return E_NOTIMPL;
     }
 
+    IFACEMETHOD(DrawGlyphRun)(
+	__maybenull void* clientDrawingContext,
+	FLOAT baselineOriginX,
+	FLOAT baselineOriginY,
+	DWRITE_MEASURING_MODE measuringMode,
+	__in DWRITE_GLYPH_RUN const* glyphRun,
+	__in DWRITE_GLYPH_RUN_DESCRIPTION const* glyphRunDescription,
+	IUnknown* clientDrawingEffect)
+    {
+	TextRendererContext *context =
+	    reinterpret_cast<TextRendererContext*>(clientDrawingContext);
+
+	AdjustedGlyphRun adjustedGlyphRun(glyphRun, context->cellWidth,
+		context->offsetX);
+
+	if (pDWC_->mDWriteFactory2 != NULL)
+	{
+	    IDWriteColorGlyphRunEnumerator *enumerator = NULL;
+	    HRESULT hr = pDWC_->mDWriteFactory2->TranslateColorGlyphRun(
+		baselineOriginX + context->offsetX,
+		baselineOriginY,
+		&adjustedGlyphRun,
+		NULL,
+		DWRITE_MEASURING_MODE_GDI_NATURAL,
+		NULL,
+		0,
+		&enumerator);
+	    if (SUCCEEDED(hr))
+	    {
+		// Draw by IDWriteFactory2 for color emoji
+		BOOL hasRun = TRUE;
+		enumerator->MoveNext(&hasRun);
+		while (hasRun)
+		{
+		    const DWRITE_COLOR_GLYPH_RUN* colorGlyphRun;
+		    enumerator->GetCurrentRun(&colorGlyphRun);
+
+		    pDWC_->mBrush->SetColor(colorGlyphRun->runColor);
+		    pDWC_->mRT->DrawGlyphRun(
+			    D2D1::Point2F(
+				colorGlyphRun->baselineOriginX,
+				colorGlyphRun->baselineOriginY),
+			    &colorGlyphRun->glyphRun,
+			    pDWC_->mBrush,
+			    DWRITE_MEASURING_MODE_NATURAL);
+		    enumerator->MoveNext(&hasRun);
+		}
+		SafeRelease(&enumerator);
+		return S_OK;
+	    }
+	}
+
+	// Draw by IDWriteFactory (without color emoji)
+	pDWC_->mRT->DrawGlyphRun(
+		D2D1::Point2F(
+		    baselineOriginX + context->offsetX,
+		    baselineOriginY),
+		&adjustedGlyphRun,
+		pDWC_->SolidBrush(context->color),
+		DWRITE_MEASURING_MODE_NATURAL);
+	return S_OK;
+    }
+
 public:
     IFACEMETHOD_(unsigned long, AddRef) ()
     {
@@ -385,80 +556,28 @@
 
 private:
     long cRefCount_;
-    IDWriteBitmapRenderTarget* pRenderTarget_;
-    IDWriteRenderingParams* pRenderingParams_;
-};
-
-struct DWriteContext {
-    FLOAT mDpiScaleX;
-    FLOAT mDpiScaleY;
-    bool mDrawing;
-
-    ID2D1Factory *mD2D1Factory;
-
-    ID2D1DCRenderTarget *mRT;
-    ID2D1SolidColorBrush *mBrush;
-
-    IDWriteFactory *mDWriteFactory;
-    IDWriteGdiInterop *mGdiInterop;
-    IDWriteRenderingParams *mRenderingParams;
-    IDWriteTextFormat *mTextFormat;
-
-    HFONT mLastHFont;
-    DWRITE_FONT_WEIGHT mFontWeight;
-    DWRITE_FONT_STYLE mFontStyle;
-
-    D2D1_TEXT_ANTIALIAS_MODE mTextAntialiasMode;
-
-    // METHODS
-
-    DWriteContext();
-
-    virtual ~DWriteContext();
-
-    HRESULT SetLOGFONT(const LOGFONTW &logFont, float fontSize);
-
-    void SetFont(HFONT hFont);
-
-    void SetFont(const LOGFONTW &logFont);
-
-    void DrawText(HDC hdc, const WCHAR* text, int len,
-	int x, int y, int w, int h, int cellWidth, COLORREF color);
-
-    float PixelsToDipsX(int x);
-
-    float PixelsToDipsY(int y);
-
-    void SetRenderingParams(
-	    const DWriteRenderingParams *params);
-
-    DWriteRenderingParams *GetRenderingParams(
-	    DWriteRenderingParams *params);
+    DWriteContext* pDWC_;
 };
 
 DWriteContext::DWriteContext() :
-    mDpiScaleX(1.f),
-    mDpiScaleY(1.f),
+    mHDC(NULL),
     mDrawing(false),
+    mFallbackDC(false),
     mD2D1Factory(NULL),
     mRT(NULL),
     mBrush(NULL),
     mDWriteFactory(NULL),
+    mDWriteFactory2(NULL),
     mGdiInterop(NULL),
     mRenderingParams(NULL),
+    mFontCache(8),
     mTextFormat(NULL),
-    mLastHFont(NULL),
     mFontWeight(DWRITE_FONT_WEIGHT_NORMAL),
     mFontStyle(DWRITE_FONT_STYLE_NORMAL),
     mTextAntialiasMode(D2D1_TEXT_ANTIALIAS_MODE_DEFAULT)
 {
     HRESULT hr;
 
-    HDC screen = ::GetDC(0);
-    mDpiScaleX = ::GetDeviceCaps(screen, LOGPIXELSX) / 96.0f;
-    mDpiScaleY = ::GetDeviceCaps(screen, LOGPIXELSY) / 96.0f;
-    ::ReleaseDC(0, screen);
-
     hr = D2D1CreateFactory(D2D1_FACTORY_TYPE_SINGLE_THREADED,
 	    __uuidof(ID2D1Factory), NULL,
 	    reinterpret_cast<void**>(&mD2D1Factory));
@@ -497,6 +616,15 @@
 
     if (SUCCEEDED(hr))
     {
+	DWriteCreateFactory(
+		DWRITE_FACTORY_TYPE_SHARED,
+		__uuidof(IDWriteFactory2),
+		reinterpret_cast<IUnknown**>(&mDWriteFactory2));
+	_RPT1(_CRT_WARN, "IDWriteFactory2: %s\n", SUCCEEDED(hr) ? "available" : "not available");
+    }
+
+    if (SUCCEEDED(hr))
+    {
 	hr = mDWriteFactory->GetGdiInterop(&mGdiInterop);
 	_RPT2(_CRT_WARN, "GetGdiInterop: hr=%p p=%p\n", hr, mGdiInterop);
     }
@@ -515,20 +643,24 @@
     SafeRelease(&mRenderingParams);
     SafeRelease(&mGdiInterop);
     SafeRelease(&mDWriteFactory);
+    SafeRelease(&mDWriteFactory2);
     SafeRelease(&mBrush);
     SafeRelease(&mRT);
     SafeRelease(&mD2D1Factory);
 }
 
     HRESULT
-DWriteContext::SetLOGFONT(const LOGFONTW &logFont, float fontSize)
+DWriteContext::CreateTextFormatFromLOGFONT(const LOGFONTW &logFont,
+	IDWriteTextFormat **ppTextFormat)
 {
-    // Most of this function is copy from: http://msdn.microsoft.com/en-us/library/windows/desktop/dd941783(v=vs.85).aspx
+    // Most of this function is copied from: https://github.com/Microsoft/Windows-classic-samples/blob/master/Samples/Win7Samples/multimedia/DirectWrite/RenderTest/TextHelpers.cpp
     HRESULT hr = S_OK;
+    IDWriteTextFormat *pTextFormat = NULL;
 
     IDWriteFont *font = NULL;
     IDWriteFontFamily *fontFamily = NULL;
     IDWriteLocalizedStrings *localizedFamilyNames = NULL;
+    float fontSize = 0;
 
     if (SUCCEEDED(hr))
     {
@@ -561,33 +693,30 @@
 
     if (SUCCEEDED(hr))
     {
-	// If no font size was passed in use the lfHeight of the LOGFONT.
-	if (fontSize == 0)
+	// Use lfHeight of the LOGFONT as font size.
+	fontSize = float(logFont.lfHeight);
+
+	if (fontSize < 0)
 	{
-	    // Convert from pixels to DIPs.
-	    fontSize = PixelsToDipsY(logFont.lfHeight);
-	    if (fontSize < 0)
-	    {
-		// Negative lfHeight represents the size of the em unit.
-		fontSize = -fontSize;
-	    }
-	    else
-	    {
-		// Positive lfHeight represents the cell height (ascent +
-		// descent).
-		DWRITE_FONT_METRICS fontMetrics;
-		font->GetMetrics(&fontMetrics);
+	    // Negative lfHeight represents the size of the em unit.
+	    fontSize = -fontSize;
+	}
+	else
+	{
+	    // Positive lfHeight represents the cell height (ascent +
+	    // descent).
+	    DWRITE_FONT_METRICS fontMetrics;
+	    font->GetMetrics(&fontMetrics);
 
-		// Convert the cell height (ascent + descent) from design units
-		// to ems.
-		float cellHeight = static_cast<float>(
-			fontMetrics.ascent + fontMetrics.descent)
-					       / fontMetrics.designUnitsPerEm;
+	    // Convert the cell height (ascent + descent) from design units
+	    // to ems.
+	    float cellHeight = static_cast<float>(
+		    fontMetrics.ascent + fontMetrics.descent)
+		/ fontMetrics.designUnitsPerEm;
 
-		// Divide the font size by the cell height to get the font em
-		// size.
-		fontSize /= cellHeight;
-	    }
+	    // Divide the font size by the cell height to get the font em
+	    // size.
+	    fontSize /= cellHeight;
 	}
     }
 
@@ -612,123 +741,165 @@
 		font->GetStretch(),
 		fontSize,
 		localeName,
-		&mTextFormat);
+		&pTextFormat);
     }
 
     if (SUCCEEDED(hr))
-    {
-	mFontWeight = static_cast<DWRITE_FONT_WEIGHT>(logFont.lfWeight);
-	mFontStyle = logFont.lfItalic ? DWRITE_FONT_STYLE_ITALIC
-	    : DWRITE_FONT_STYLE_NORMAL;
-    }
+	hr = pTextFormat->SetTextAlignment(DWRITE_TEXT_ALIGNMENT_LEADING);
+
+    if (SUCCEEDED(hr))
+	hr = pTextFormat->SetParagraphAlignment(
+		DWRITE_PARAGRAPH_ALIGNMENT_CENTER);
+
+    if (SUCCEEDED(hr))
+	hr = pTextFormat->SetWordWrapping(DWRITE_WORD_WRAPPING_NO_WRAP);
 
     SafeRelease(&localizedFamilyNames);
     SafeRelease(&fontFamily);
     SafeRelease(&font);
 
+    if (SUCCEEDED(hr))
+	*ppTextFormat = pTextFormat;
+    else
+	SafeRelease(&pTextFormat);
+
+    return hr;
+}
+
+    HRESULT
+DWriteContext::SetFontByLOGFONT(const LOGFONTW &logFont)
+{
+    HRESULT hr = S_OK;
+    IDWriteTextFormat *pTextFormat = NULL;
+
+    hr = CreateTextFormatFromLOGFONT(logFont, &pTextFormat);
+
+    if (SUCCEEDED(hr))
+    {
+	SafeRelease(&mTextFormat);
+	mTextFormat = pTextFormat;
+	mFontWeight = static_cast<DWRITE_FONT_WEIGHT>(logFont.lfWeight);
+	mFontStyle = logFont.lfItalic ? DWRITE_FONT_STYLE_ITALIC
+	    : DWRITE_FONT_STYLE_NORMAL;
+    }
+
     return hr;
 }
 
     void
 DWriteContext::SetFont(HFONT hFont)
 {
-    if (mLastHFont != hFont)
+    FontCache::Item item;
+    if (mFontCache.get(hFont, item))
     {
-	LOGFONTW lf;
-	if (GetObjectW(hFont, sizeof(lf), &lf))
+	if (item.pTextFormat != NULL)
 	{
-	    SetFont(lf);
-	    mLastHFont = hFont;
+	    item.pTextFormat->AddRef();
+	    SafeRelease(&mTextFormat);
+	    mTextFormat = item.pTextFormat;
+	    mFontWeight = item.fontWeight;
+	    mFontStyle = item.fontStyle;
+	    mFallbackDC = false;
 	}
+	else
+	    mFallbackDC = true;
+	return;
     }
+
+    HRESULT hr = E_FAIL;
+    LOGFONTW lf;
+    if (GetObjectW(hFont, sizeof(lf), &lf))
+	hr = SetFontByLOGFONT(lf);
+
+    item.hFont = hFont;
+    if (SUCCEEDED(hr))
+    {
+	item.pTextFormat = mTextFormat;
+	item.fontWeight = mFontWeight;
+	item.fontStyle = mFontStyle;
+    }
+    mFontCache.put(item);
 }
 
     void
-DWriteContext::SetFont(const LOGFONTW &logFont)
+DWriteContext::BindDC(HDC hdc, RECT *rect)
 {
-    SafeRelease(&mTextFormat);
-    mLastHFont = NULL;
-
-    HRESULT hr = SetLOGFONT(logFont, 0.f);
-
-    if (SUCCEEDED(hr))
-	hr = mTextFormat->SetTextAlignment(DWRITE_TEXT_ALIGNMENT_LEADING);
-
-    if (SUCCEEDED(hr))
-	hr = mTextFormat->SetParagraphAlignment(
-		DWRITE_PARAGRAPH_ALIGNMENT_CENTER);
-
-    if (SUCCEEDED(hr))
-	hr = mTextFormat->SetWordWrapping(DWRITE_WORD_WRAPPING_NO_WRAP);
+    Flush();
+    mRT->BindDC(hdc, rect);
+    mRT->SetTransform(D2D1::IdentityMatrix());
+    mHDC = hdc;
 }
 
     void
-DWriteContext::DrawText(HDC hdc, const WCHAR* text, int len,
-	int x, int y, int w, int h, int cellWidth, COLORREF color)
+DWriteContext::AssureDrawing()
 {
-    HRESULT hr = S_OK;
-    IDWriteBitmapRenderTarget *bmpRT = NULL;
+    if (mDrawing == false)
+    {
+	mRT->BeginDraw();
+	mDrawing = true;
+    }
+}
 
-    // Skip when any fonts are not set.
-    if (mTextFormat == NULL)
+    ID2D1Brush*
+DWriteContext::SolidBrush(COLORREF color)
+{
+    mBrush->SetColor(D2D1::ColorF(UINT32(GetRValue(color)) << 16 |
+		UINT32(GetGValue(color)) << 8 | UINT32(GetBValue(color))));
+    return mBrush;
+}
+
+    void
+DWriteContext::DrawText(const WCHAR* text, int len,
+	int x, int y, int w, int h, int cellWidth, COLORREF color,
+	UINT fuOptions, CONST RECT *lprc, CONST INT * lpDx)
+{
+    if (mFallbackDC)
+    {
+	Flush();
+	ExtTextOutW(mHDC, x, y, fuOptions, lprc, text, len, lpDx);
 	return;
+    }
 
-    // Check possibility of zero divided error.
-    if (cellWidth == 0 || mDpiScaleX == 0.0f || mDpiScaleY == 0.0f)
-	return;
+    AssureDrawing();
 
-    if (SUCCEEDED(hr))
-	hr = mGdiInterop->CreateBitmapRenderTarget(hdc, w, h, &bmpRT);
+    HRESULT hr;
+    IDWriteTextLayout *textLayout = NULL;
+
+    hr = mDWriteFactory->CreateTextLayout(text, len, mTextFormat,
+	    FLOAT(w), FLOAT(h), &textLayout);
 
     if (SUCCEEDED(hr))
     {
-	IDWriteTextLayout *textLayout = NULL;
+	DWRITE_TEXT_RANGE textRange = { 0, UINT32(len) };
+	textLayout->SetFontWeight(mFontWeight, textRange);
+	textLayout->SetFontStyle(mFontStyle, textRange);
 
-	HDC memdc = bmpRT->GetMemoryDC();
-	BitBlt(memdc, 0, 0, w, h, hdc, x, y, SRCCOPY);
-
-	hr = mDWriteFactory->CreateGdiCompatibleTextLayout(
-		text, len, mTextFormat, PixelsToDipsX(w),
-		PixelsToDipsY(h), mDpiScaleX, NULL, TRUE, &textLayout);
-
-	if (SUCCEEDED(hr))
-	{
-	    DWRITE_TEXT_RANGE textRange = { 0, (UINT32)len };
-	    textLayout->SetFontWeight(mFontWeight, textRange);
-	    textLayout->SetFontStyle(mFontStyle, textRange);
-	}
-
-	if (SUCCEEDED(hr))
-	{
-	    GdiTextRenderer *renderer = new GdiTextRenderer(bmpRT,
-		    mRenderingParams);
-	    GdiTextRendererContext data = {
-		color,
-		PixelsToDipsX(cellWidth),
-		0.0f
-	    };
-	    textLayout->Draw(&data, renderer, 0, 0);
-	    SafeRelease(&renderer);
-	}
-
-	BitBlt(hdc, x, y, w, h, memdc, 0, 0, SRCCOPY);
-
-	SafeRelease(&textLayout);
+	TextRenderer renderer(this);
+	TextRendererContext context = { color, FLOAT(cellWidth), 0.0f };
+	textLayout->Draw(&context, &renderer, FLOAT(x), FLOAT(y));
     }
 
-    SafeRelease(&bmpRT);
+    SafeRelease(&textLayout);
 }
 
-    float
-DWriteContext::PixelsToDipsX(int x)
+    void
+DWriteContext::FillRect(RECT *rc, COLORREF color)
 {
-    return x / mDpiScaleX;
+    AssureDrawing();
+    mRT->FillRectangle(
+	    D2D1::RectF(FLOAT(rc->left), FLOAT(rc->top),
+		FLOAT(rc->right), FLOAT(rc->bottom)),
+	    SolidBrush(color));
 }
 
-    float
-DWriteContext::PixelsToDipsY(int y)
+    void
+DWriteContext::Flush()
 {
-    return y / mDpiScaleY;
+    if (mDrawing)
+    {
+	mRT->EndDraw();
+	mDrawing = false;
+    }
 }
 
     void
@@ -757,6 +928,10 @@
 	SafeRelease(&mRenderingParams);
 	mRenderingParams = renderingParams;
 	mTextAntialiasMode = textAntialiasMode;
+
+	Flush();
+	mRT->SetTextRenderingParams(mRenderingParams);
+	mRT->SetTextAntialiasMode(mTextAntialiasMode);
     }
 }
 
@@ -825,39 +1000,22 @@
 }
 
     void
-DWriteContext_BeginDraw(DWriteContext *ctx)
-{
-    if (ctx != NULL && ctx->mRT != NULL)
-    {
-	ctx->mRT->BeginDraw();
-	ctx->mRT->SetTransform(D2D1::IdentityMatrix());
-	ctx->mDrawing = true;
-    }
-}
-
-    void
 DWriteContext_BindDC(DWriteContext *ctx, HDC hdc, RECT *rect)
 {
-    if (ctx != NULL && ctx->mRT != NULL)
-    {
-	ctx->mRT->BindDC(hdc, rect);
-	ctx->mRT->SetTextAntialiasMode(ctx->mTextAntialiasMode);
-    }
+    if (ctx != NULL)
+	ctx->BindDC(hdc, rect);
 }
 
     void
 DWriteContext_SetFont(DWriteContext *ctx, HFONT hFont)
 {
     if (ctx != NULL)
-    {
 	ctx->SetFont(hFont);
-    }
 }
 
     void
 DWriteContext_DrawText(
 	DWriteContext *ctx,
-	HDC hdc,
 	const WCHAR* text,
 	int len,
 	int x,
@@ -865,20 +1023,28 @@
 	int w,
 	int h,
 	int cellWidth,
-	COLORREF color)
+	COLORREF color,
+	UINT fuOptions,
+	CONST RECT *lprc,
+	CONST INT * lpDx)
 {
     if (ctx != NULL)
-	ctx->DrawText(hdc, text, len, x, y, w, h, cellWidth, color);
+	ctx->DrawText(text, len, x, y, w, h, cellWidth, color,
+		fuOptions, lprc, lpDx);
 }
 
     void
-DWriteContext_EndDraw(DWriteContext *ctx)
+DWriteContext_FillRect(DWriteContext *ctx, RECT *rc, COLORREF color)
 {
-    if (ctx != NULL && ctx->mRT != NULL)
-    {
-	ctx->mRT->EndDraw();
-	ctx->mDrawing = false;
-    }
+    if (ctx != NULL)
+	ctx->FillRect(rc, color);
+}
+
+    void
+DWriteContext_Flush(DWriteContext *ctx)
+{
+    if (ctx != NULL)
+	ctx->Flush();
 }
 
     void