updated for version 7.4.393
Problem:    Text drawing on newer MS-Windows systems is suboptimal.  Some
            multi-byte characters are not displayed, even though the same font
            in Notepad can display them. (Srinath Avadhanula)
Solution:   Add the 'renderoptions' option to enable Direct-X drawing. (Taro
            Muraoka)
diff --git a/src/gui_dwrite.cpp b/src/gui_dwrite.cpp
new file mode 100644
index 0000000..cf83c05
--- /dev/null
+++ b/src/gui_dwrite.cpp
@@ -0,0 +1,901 @@
+/* vi:set ts=8 sts=4 sw=4 noet: */
+/*
+ * Author: MURAOKA Taro <koron.kaoriya@gmail.com>
+ *
+ * Contributors:
+ *  - Ken Takata
+ *
+ * Copyright (C) 2013 MURAOKA Taro <koron.kaoriya@gmail.com>
+ * THIS FILE IS DISTRIBUTED UNDER THE VIM LICENSE.
+ */
+
+#define WIN32_LEAN_AND_MEAN
+
+#ifndef DYNAMIC_DIRECTX
+# if WINVER < 0x0600
+#  error WINVER must be 0x0600 or above to use DirectWrite(DirectX)
+# endif
+#endif
+
+#include <windows.h>
+#include <crtdbg.h>
+#include <assert.h>
+#include <math.h>
+#include <d2d1.h>
+#include <d2d1helper.h>
+#include <dwrite.h>
+
+#include "gui_dwrite.h"
+
+#ifdef __MINGW32__
+# define __maybenull	SAL__maybenull
+# define __in		SAL__in
+# define __out		SAL__out
+#endif
+
+#ifdef DYNAMIC_DIRECTX
+extern "C" HINSTANCE vimLoadLib(char *name);
+
+typedef int (WINAPI *PGETUSERDEFAULTLOCALENAME)(LPWSTR, int);
+typedef HRESULT (WINAPI *PD2D1CREATEFACTORY)(D2D1_FACTORY_TYPE,
+	REFIID, const D2D1_FACTORY_OPTIONS *, void **);
+typedef HRESULT (WINAPI *PDWRITECREATEFACTORY)(DWRITE_FACTORY_TYPE,
+	REFIID, IUnknown **);
+
+static HINSTANCE hD2D1DLL = NULL;
+static HINSTANCE hDWriteDLL = NULL;
+
+static PGETUSERDEFAULTLOCALENAME pGetUserDefaultLocaleName = NULL;
+static PD2D1CREATEFACTORY pD2D1CreateFactory = NULL;
+static PDWRITECREATEFACTORY pDWriteCreateFactory = NULL;
+
+#define GetUserDefaultLocaleName	(*pGetUserDefaultLocaleName)
+#define D2D1CreateFactory		(*pD2D1CreateFactory)
+#define DWriteCreateFactory		(*pDWriteCreateFactory)
+
+    static void
+unload(HINSTANCE &hinst)
+{
+    if (hinst != NULL)
+    {
+	FreeLibrary(hinst);
+	hinst = NULL;
+    }
+}
+#endif // DYNAMIC_DIRECTX
+
+template <class T> inline void SafeRelease(T **ppT)
+{
+    if (*ppT)
+    {
+	(*ppT)->Release();
+	*ppT = NULL;
+    }
+}
+
+struct GdiTextRendererContext
+{
+    // const fields.
+    COLORREF color;
+    FLOAT cellWidth;
+
+    // working fields.
+    FLOAT offsetX;
+};
+
+    static DWRITE_PIXEL_GEOMETRY
+ToPixelGeometry(int value)
+{
+    switch (value)
+    {
+	default:
+	case 0:
+	    return DWRITE_PIXEL_GEOMETRY_FLAT;
+	case 1:
+	    return DWRITE_PIXEL_GEOMETRY_RGB;
+	case 2:
+	    return DWRITE_PIXEL_GEOMETRY_BGR;
+    }
+}
+
+    static int
+ToInt(DWRITE_PIXEL_GEOMETRY value)
+{
+    switch (value)
+    {
+	case DWRITE_PIXEL_GEOMETRY_FLAT:
+	    return 0;
+	case DWRITE_PIXEL_GEOMETRY_RGB:
+	    return 1;
+	case DWRITE_PIXEL_GEOMETRY_BGR:
+	    return 2;
+	default:
+	    return -1;
+    }
+}
+
+    static DWRITE_RENDERING_MODE
+ToRenderingMode(int value)
+{
+    switch (value)
+    {
+	default:
+	case 0:
+	    return DWRITE_RENDERING_MODE_DEFAULT;
+	case 1:
+	    return DWRITE_RENDERING_MODE_ALIASED;
+	case 2:
+	    return DWRITE_RENDERING_MODE_CLEARTYPE_GDI_CLASSIC;
+	case 3:
+	    return DWRITE_RENDERING_MODE_CLEARTYPE_GDI_NATURAL;
+	case 4:
+	    return DWRITE_RENDERING_MODE_CLEARTYPE_NATURAL;
+	case 5:
+	    return DWRITE_RENDERING_MODE_CLEARTYPE_NATURAL_SYMMETRIC;
+	case 6:
+	    return DWRITE_RENDERING_MODE_OUTLINE;
+    }
+}
+
+    static D2D1_TEXT_ANTIALIAS_MODE
+ToTextAntialiasMode(int value)
+{
+    switch (value)
+    {
+	default:
+	case 0:
+	    return D2D1_TEXT_ANTIALIAS_MODE_DEFAULT;
+	case 1:
+	    return D2D1_TEXT_ANTIALIAS_MODE_CLEARTYPE;
+	case 2:
+	    return D2D1_TEXT_ANTIALIAS_MODE_GRAYSCALE;
+	case 3:
+	    return D2D1_TEXT_ANTIALIAS_MODE_ALIASED;
+    }
+}
+
+    static int
+ToInt(DWRITE_RENDERING_MODE value)
+{
+    switch (value)
+    {
+	case DWRITE_RENDERING_MODE_DEFAULT:
+	    return 0;
+	case DWRITE_RENDERING_MODE_ALIASED:
+	    return 1;
+	case DWRITE_RENDERING_MODE_CLEARTYPE_GDI_CLASSIC:
+	    return 2;
+	case DWRITE_RENDERING_MODE_CLEARTYPE_GDI_NATURAL:
+	    return 3;
+	case DWRITE_RENDERING_MODE_CLEARTYPE_NATURAL:
+	    return 4;
+	case DWRITE_RENDERING_MODE_CLEARTYPE_NATURAL_SYMMETRIC:
+	    return 5;
+	case DWRITE_RENDERING_MODE_OUTLINE:
+	    return 6;
+	default:
+	    return -1;
+    }
+}
+
+class AdjustedGlyphRun : public DWRITE_GLYPH_RUN
+{
+private:
+    FLOAT mDelta;
+    FLOAT *mAdjustedAdvances;
+
+public:
+    AdjustedGlyphRun(
+	    const DWRITE_GLYPH_RUN *glyphRun,
+	    FLOAT cellWidth) :
+	DWRITE_GLYPH_RUN(*glyphRun),
+	mDelta(0.0f),
+	mAdjustedAdvances(new FLOAT[glyphRun->glyphCount])
+    {
+	assert(cellWidth != 0.0f);
+	for (UINT32 i = 0; i < glyphRun->glyphCount; ++i)
+	{
+	    FLOAT orig = glyphRun->glyphAdvances[i];
+	    FLOAT adjusted = adjustToCell(orig, cellWidth);
+	    mAdjustedAdvances[i] = adjusted;
+	    mDelta += adjusted - orig;
+	}
+	glyphAdvances = mAdjustedAdvances;
+    }
+
+    ~AdjustedGlyphRun(void)
+    {
+	delete[] mAdjustedAdvances;
+    }
+
+    FLOAT getDelta(void) const
+    {
+	return mDelta;
+    }
+
+    static FLOAT adjustToCell(FLOAT value, FLOAT cellWidth)
+    {
+	int cellCount = (int)floor(value / cellWidth + 0.5f);
+	if (cellCount < 1)
+	    cellCount = 1;
+	return cellCount * cellWidth;
+    }
+};
+
+class GdiTextRenderer : public IDWriteTextRenderer
+{
+public:
+    GdiTextRenderer(
+	    IDWriteBitmapRenderTarget* bitmapRenderTarget,
+	    IDWriteRenderingParams* renderingParams) :
+	cRefCount_(0),
+	pRenderTarget_(bitmapRenderTarget),
+	pRenderingParams_(renderingParams)
+    {
+	pRenderTarget_->AddRef();
+	pRenderingParams_->AddRef();
+	AddRef();
+    }
+
+    ~GdiTextRenderer()
+    {
+	SafeRelease(&pRenderTarget_);
+	SafeRelease(&pRenderingParams_);
+    }
+
+    IFACEMETHOD(IsPixelSnappingDisabled)(
+	__maybenull void* clientDrawingContext,
+	__out BOOL* isDisabled)
+    {
+	*isDisabled = FALSE;
+	return S_OK;
+    }
+
+    IFACEMETHOD(GetCurrentTransform)(
+	__maybenull void* clientDrawingContext,
+	__out DWRITE_MATRIX* transform)
+    {
+	//forward the render target's transform
+	pRenderTarget_->GetCurrentTransform(transform);
+	return S_OK;
+    }
+
+    IFACEMETHOD(GetPixelsPerDip)(
+	__maybenull void* clientDrawingContext,
+	__out FLOAT* pixelsPerDip)
+    {
+	*pixelsPerDip = pRenderTarget_->GetPixelsPerDip();
+	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,
+	FLOAT baselineOriginY,
+	__in DWRITE_UNDERLINE const* underline,
+	IUnknown* clientDrawingEffect)
+    {
+	return E_NOTIMPL;
+    }
+
+    IFACEMETHOD(DrawStrikethrough)(
+	__maybenull void* clientDrawingContext,
+	FLOAT baselineOriginX,
+	FLOAT baselineOriginY,
+	__in DWRITE_STRIKETHROUGH const* strikethrough,
+	IUnknown* clientDrawingEffect)
+    {
+	return E_NOTIMPL;
+    }
+
+    IFACEMETHOD(DrawInlineObject)(
+	__maybenull void* clientDrawingContext,
+	FLOAT originX,
+	FLOAT originY,
+	IDWriteInlineObject* inlineObject,
+	BOOL isSideways,
+	BOOL isRightToLeft,
+	IUnknown* clientDrawingEffect)
+    {
+	return E_NOTIMPL;
+    }
+
+public:
+    IFACEMETHOD_(unsigned long, AddRef) ()
+    {
+	return InterlockedIncrement(&cRefCount_);
+    }
+
+    IFACEMETHOD_(unsigned long, Release) ()
+    {
+	long newCount = InterlockedDecrement(&cRefCount_);
+
+	if (newCount == 0)
+	{
+	    delete this;
+	    return 0;
+	}
+	return newCount;
+    }
+
+    IFACEMETHOD(QueryInterface)(
+	IID const& riid,
+	void** ppvObject)
+    {
+	if (__uuidof(IDWriteTextRenderer) == riid)
+	{
+	    *ppvObject = this;
+	}
+	else if (__uuidof(IDWritePixelSnapping) == riid)
+	{
+	    *ppvObject = this;
+	}
+	else if (__uuidof(IUnknown) == riid)
+	{
+	    *ppvObject = this;
+	}
+	else
+	{
+	    *ppvObject = NULL;
+	    return E_FAIL;
+	}
+
+	return S_OK;
+    }
+
+private:
+    unsigned 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::DWriteContext() :
+    mDpiScaleX(1.f),
+    mDpiScaleY(1.f),
+    mDrawing(false),
+    mD2D1Factory(NULL),
+    mRT(NULL),
+    mBrush(NULL),
+    mDWriteFactory(NULL),
+    mGdiInterop(NULL),
+    mRenderingParams(NULL),
+    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));
+    _RPT2(_CRT_WARN, "D2D1CreateFactory: hr=%p p=%p\n", hr, mD2D1Factory);
+
+    if (SUCCEEDED(hr))
+    {
+	D2D1_RENDER_TARGET_PROPERTIES props = {
+	    D2D1_RENDER_TARGET_TYPE_DEFAULT,
+	    { DXGI_FORMAT_B8G8R8A8_UNORM, D2D1_ALPHA_MODE_IGNORE },
+	    0, 0,
+	    D2D1_RENDER_TARGET_USAGE_NONE,
+	    D2D1_FEATURE_LEVEL_DEFAULT
+	};
+	hr = mD2D1Factory->CreateDCRenderTarget(&props, &mRT);
+	_RPT2(_CRT_WARN, "CreateDCRenderTarget: hr=%p p=%p\n", hr, mRT);
+    }
+
+    if (SUCCEEDED(hr))
+    {
+	hr = mRT->CreateSolidColorBrush(
+		D2D1::ColorF(D2D1::ColorF::Black),
+		&mBrush);
+	_RPT2(_CRT_WARN, "CreateSolidColorBrush: hr=%p p=%p\n", hr, mBrush);
+    }
+
+    if (SUCCEEDED(hr))
+    {
+	hr = DWriteCreateFactory(
+		DWRITE_FACTORY_TYPE_SHARED,
+		__uuidof(IDWriteFactory),
+		reinterpret_cast<IUnknown**>(&mDWriteFactory));
+	_RPT2(_CRT_WARN, "DWriteCreateFactory: hr=%p p=%p\n", hr,
+		mDWriteFactory);
+    }
+
+    if (SUCCEEDED(hr))
+    {
+	hr = mDWriteFactory->GetGdiInterop(&mGdiInterop);
+	_RPT2(_CRT_WARN, "GetGdiInterop: hr=%p p=%p\n", hr, mGdiInterop);
+    }
+
+    if (SUCCEEDED(hr))
+    {
+	hr = mDWriteFactory->CreateRenderingParams(&mRenderingParams);
+	_RPT2(_CRT_WARN, "CreateRenderingParams: hr=%p p=%p\n", hr,
+		mRenderingParams);
+    }
+}
+
+DWriteContext::~DWriteContext()
+{
+    SafeRelease(&mTextFormat);
+    SafeRelease(&mRenderingParams);
+    SafeRelease(&mGdiInterop);
+    SafeRelease(&mDWriteFactory);
+    SafeRelease(&mBrush);
+    SafeRelease(&mRT);
+    SafeRelease(&mD2D1Factory);
+}
+
+    HRESULT
+DWriteContext::SetLOGFONT(const LOGFONTW &logFont, float fontSize)
+{
+    // Most of this function is copy from: http://msdn.microsoft.com/en-us/library/windows/desktop/dd941783(v=vs.85).aspx
+    HRESULT hr = S_OK;
+
+    IDWriteFont *font = NULL;
+    IDWriteFontFamily *fontFamily = NULL;
+    IDWriteLocalizedStrings *localizedFamilyNames = NULL;
+
+    if (SUCCEEDED(hr))
+    {
+	hr = mGdiInterop->CreateFontFromLOGFONT(&logFont, &font);
+    }
+
+    // Get the font family to which this font belongs.
+    if (SUCCEEDED(hr))
+    {
+	hr = font->GetFontFamily(&fontFamily);
+    }
+
+    // Get the family names. This returns an object that encapsulates one or
+    // more names with the same meaning but in different languages.
+    if (SUCCEEDED(hr))
+    {
+	hr = fontFamily->GetFamilyNames(&localizedFamilyNames);
+    }
+
+    // Get the family name at index zero. If we were going to display the name
+    // we'd want to try to find one that matched the use locale, but for
+    // purposes of creating a text format object any language will do.
+
+    wchar_t familyName[100];
+    if (SUCCEEDED(hr))
+    {
+	hr = localizedFamilyNames->GetString(0, familyName,
+		ARRAYSIZE(familyName));
+    }
+
+    if (SUCCEEDED(hr))
+    {
+	// If no font size was passed in use the lfHeight of the LOGFONT.
+	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);
+
+		// 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;
+	    }
+	}
+    }
+
+    // The text format includes a locale name. Ideally, this would be the
+    // language of the text, which may or may not be the same as the primary
+    // language of the user. However, for our purposes the user locale will do.
+    wchar_t localeName[LOCALE_NAME_MAX_LENGTH];
+    if (SUCCEEDED(hr))
+    {
+	if (GetUserDefaultLocaleName(localeName, LOCALE_NAME_MAX_LENGTH) == 0)
+	    hr = HRESULT_FROM_WIN32(GetLastError());
+    }
+
+    if (SUCCEEDED(hr))
+    {
+	// Create the text format object.
+	hr = mDWriteFactory->CreateTextFormat(
+		familyName,
+		NULL, // no custom font collection
+		font->GetWeight(),
+		font->GetStyle(),
+		font->GetStretch(),
+		fontSize,
+		localeName,
+		&mTextFormat);
+    }
+
+    if (SUCCEEDED(hr))
+    {
+	mFontWeight = static_cast<DWRITE_FONT_WEIGHT>(logFont.lfWeight);
+	mFontStyle = logFont.lfItalic ? DWRITE_FONT_STYLE_ITALIC
+	    : DWRITE_FONT_STYLE_NORMAL;
+    }
+
+    SafeRelease(&localizedFamilyNames);
+    SafeRelease(&fontFamily);
+    SafeRelease(&font);
+
+    return hr;
+}
+
+    void
+DWriteContext::SetFont(HFONT hFont)
+{
+    if (mLastHFont != hFont)
+    {
+	LOGFONTW lf;
+	if (GetObjectW(hFont, sizeof(lf), &lf))
+	{
+	    SetFont(lf);
+	    mLastHFont = hFont;
+	}
+    }
+}
+
+    void
+DWriteContext::SetFont(const LOGFONTW &logFont)
+{
+    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);
+}
+
+    void
+DWriteContext::DrawText(HDC hdc, const WCHAR* text, int len,
+	int x, int y, int w, int h, int cellWidth, COLORREF color)
+{
+    HRESULT hr = S_OK;
+    IDWriteBitmapRenderTarget *bmpRT = NULL;
+
+    // Skip when any fonts are not set.
+    if (mTextFormat == NULL)
+	return;
+
+    // Check possibility of zero divided error.
+    if (cellWidth == 0 || mDpiScaleX == 0.0f || mDpiScaleY == 0.0f)
+	return;
+
+    if (SUCCEEDED(hr))
+	hr = mGdiInterop->CreateBitmapRenderTarget(hdc, w, h, &bmpRT);
+
+    if (SUCCEEDED(hr))
+    {
+	IDWriteTextLayout *textLayout = NULL;
+
+	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, 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);
+    }
+
+    SafeRelease(&bmpRT);
+}
+
+    float
+DWriteContext::PixelsToDipsX(int x)
+{
+    return x / mDpiScaleX;
+}
+
+    float
+DWriteContext::PixelsToDipsY(int y)
+{
+    return y / mDpiScaleY;
+}
+
+    void
+DWriteContext::SetRenderingParams(
+	const DWriteRenderingParams *params)
+{
+    if (mDWriteFactory == NULL)
+	return;
+
+    IDWriteRenderingParams *renderingParams = NULL;
+    D2D1_TEXT_ANTIALIAS_MODE textAntialiasMode =
+	D2D1_TEXT_ANTIALIAS_MODE_DEFAULT;
+    HRESULT hr;
+    if (params != NULL)
+    {
+	hr = mDWriteFactory->CreateCustomRenderingParams(params->gamma,
+		params->enhancedContrast, params->clearTypeLevel,
+		ToPixelGeometry(params->pixelGeometry),
+		ToRenderingMode(params->renderingMode), &renderingParams);
+	textAntialiasMode = ToTextAntialiasMode(params->textAntialiasMode);
+    }
+    else
+	hr = mDWriteFactory->CreateRenderingParams(&renderingParams);
+    if (SUCCEEDED(hr) && renderingParams != NULL)
+    {
+	SafeRelease(&mRenderingParams);
+	mRenderingParams = renderingParams;
+	mTextAntialiasMode = textAntialiasMode;
+    }
+}
+
+    DWriteRenderingParams *
+DWriteContext::GetRenderingParams(
+	DWriteRenderingParams *params)
+{
+    if (params != NULL && mRenderingParams != NULL)
+    {
+	params->gamma = mRenderingParams->GetGamma();
+	params->enhancedContrast = mRenderingParams->GetEnhancedContrast();
+	params->clearTypeLevel = mRenderingParams->GetClearTypeLevel();
+	params->pixelGeometry = ToInt(mRenderingParams->GetPixelGeometry());
+	params->renderingMode = ToInt(mRenderingParams->GetRenderingMode());
+	params->textAntialiasMode = mTextAntialiasMode;
+    }
+    return params;
+}
+
+////////////////////////////////////////////////////////////////////////////
+// PUBLIC C INTERFACES
+
+    void
+DWrite_Init(void)
+{
+#ifdef DYNAMIC_DIRECTX
+    // Load libraries.
+    hD2D1DLL = vimLoadLib(const_cast<char*>("d2d1.dll"));
+    hDWriteDLL = vimLoadLib(const_cast<char*>("dwrite.dll"));
+    if (hD2D1DLL == NULL || hDWriteDLL == NULL)
+    {
+	DWrite_Final();
+	return;
+    }
+    // Get address of procedures.
+    pGetUserDefaultLocaleName = (PGETUSERDEFAULTLOCALENAME)GetProcAddress(
+	    GetModuleHandle("kernel32.dll"), "GetUserDefaultLocaleName");
+    pD2D1CreateFactory = (PD2D1CREATEFACTORY)GetProcAddress(hD2D1DLL,
+	    "D2D1CreateFactory");
+    pDWriteCreateFactory = (PDWRITECREATEFACTORY)GetProcAddress(hDWriteDLL,
+	    "DWriteCreateFactory");
+#endif
+}
+
+    void
+DWrite_Final(void)
+{
+#ifdef DYNAMIC_DIRECTX
+    pGetUserDefaultLocaleName = NULL;
+    pD2D1CreateFactory = NULL;
+    pDWriteCreateFactory = NULL;
+    unload(hDWriteDLL);
+    unload(hD2D1DLL);
+#endif
+}
+
+    DWriteContext *
+DWriteContext_Open(void)
+{
+#ifdef DYNAMIC_DIRECTX
+    if (pGetUserDefaultLocaleName == NULL || pD2D1CreateFactory == NULL
+	    || pDWriteCreateFactory == NULL)
+	return NULL;
+#endif
+    return new DWriteContext();
+}
+
+    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);
+    }
+}
+
+    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,
+	int y,
+	int w,
+	int h,
+	int cellWidth,
+	COLORREF color)
+{
+    if (ctx != NULL)
+	ctx->DrawText(hdc, text, len, x, y, w, h, cellWidth, color);
+}
+
+    void
+DWriteContext_EndDraw(DWriteContext *ctx)
+{
+    if (ctx != NULL && ctx->mRT != NULL)
+    {
+	ctx->mRT->EndDraw();
+	ctx->mDrawing = false;
+    }
+}
+
+    void
+DWriteContext_Close(DWriteContext *ctx)
+{
+    delete ctx;
+}
+
+    void
+DWriteContext_SetRenderingParams(
+	DWriteContext *ctx,
+	const DWriteRenderingParams *params)
+{
+    if (ctx != NULL)
+	ctx->SetRenderingParams(params);
+}
+
+    DWriteRenderingParams *
+DWriteContext_GetRenderingParams(
+	DWriteContext *ctx,
+	DWriteRenderingParams *params)
+{
+    if (ctx != NULL)
+	return ctx->GetRenderingParams(params);
+    else
+	return NULL;
+}