summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBram Moolenaar <Bram@vim.org>2014-08-06 14:52:30 +0200
committerBram Moolenaar <Bram@vim.org>2014-08-06 14:52:30 +0200
commitb5a7a8b5451c6fe8a2cc1d5d86c42d9b9a50ef98 (patch)
treef5616b152c67bfa1de710ca93fe6f883c9069b46
parent8c1329cb59e964797b8abdcf8d42af9877ea8daa (diff)
downloadvim-git-b5a7a8b5451c6fe8a2cc1d5d86c42d9b9a50ef98.tar.gz
updated for version 7.4.393v7.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)
-rw-r--r--runtime/doc/eval.txt1
-rw-r--r--runtime/doc/options.txt71
-rw-r--r--runtime/doc/various.txt1
-rw-r--r--src/Make_cyg.mak32
-rw-r--r--src/Make_ming.mak35
-rw-r--r--src/Make_mvc.mak21
-rw-r--r--src/eval.c3
-rw-r--r--src/gui_dwrite.cpp901
-rw-r--r--src/gui_dwrite.h85
-rw-r--r--src/gui_w32.c204
-rw-r--r--src/gui_w48.c21
-rw-r--r--src/option.c17
-rw-r--r--src/option.h3
-rw-r--r--src/proto/gui_w32.pro2
-rw-r--r--src/version.c9
-rw-r--r--src/vim.h7
16 files changed, 1390 insertions, 23 deletions
diff --git a/runtime/doc/eval.txt b/runtime/doc/eval.txt
index cbd995da3..62aa16704 100644
--- a/runtime/doc/eval.txt
+++ b/runtime/doc/eval.txt
@@ -6622,6 +6622,7 @@ dialog_con Compiled with console dialog support.
dialog_gui Compiled with GUI dialog support.
diff Compiled with |vimdiff| and 'diff' support.
digraphs Compiled with support for digraphs.
+directx Compiled with support for Direct-X and 'renderoptions'.
dnd Compiled with support for the "~ register |quote_~|.
dos16 16 bits DOS version of Vim.
dos32 32 bits DOS (DJGPP) version of Vim.
diff --git a/runtime/doc/options.txt b/runtime/doc/options.txt
index 90d4ca7a7..5f4a06e7e 100644
--- a/runtime/doc/options.txt
+++ b/runtime/doc/options.txt
@@ -5650,6 +5650,77 @@ A jump table for the options with a short description can be found at |Q_op|.
this option at the default "on". Only switch it off when working with
old Vi scripts.
+ *'renderoptions'* *'rop'*
+'renderoptions' 'rop' string (default: empty)
+ global
+ {not in Vi}
+ {only available when compiled with GUI and DIRECTX on
+ MS-Windows}
+ Select a text renderer and set its options. The options depend on the
+ renderer.
+
+ Syntax: >
+ set rop=type:{renderer}(,{name}:{value})*
+<
+ Currently, only one optional renderer is available.
+
+ render behavior ~
+ directx Vim will draw text using DirectX (DirectWrite). It makes
+ drawn glyphs more beautiful than default GDI.
+ It requires 'encoding' is "utf-8", and only works on
+ MS-Windows Vista or newer version.
+
+ Options:
+ name meaning type value ~
+ gamma gamma float 1.0 - 2.2 (maybe)
+ contrast enhancedContrast float (unknown)
+ level clearTypeLevel float (unknown)
+ geom pixelGeometry int 0 - 2 (see below)
+ renmode renderingMode int 0 - 6 (see below)
+ taamode textAntialiasMode int 0 - 3 (see below)
+
+ See this URL for detail:
+ http://msdn.microsoft.com/en-us/library/dd368190.aspx
+
+ For geom: structure of a device pixel.
+ 0 - DWRITE_PIXEL_GEOMETRY_FLAT
+ 1 - DWRITE_PIXEL_GEOMETRY_RGB
+ 2 - DWRITE_PIXEL_GEOMETRY_BGR
+
+ See this URL for detail:
+ http://msdn.microsoft.com/en-us/library/dd368114.aspx
+
+ For renmode: method of rendering glyphs.
+ 0 - DWRITE_RENDERING_MODE_DEFAULT
+ 1 - DWRITE_RENDERING_MODE_ALIASED
+ 2 - DWRITE_RENDERING_MODE_GDI_CLASSIC
+ 3 - DWRITE_RENDERING_MODE_GDI_NATURAL
+ 4 - DWRITE_RENDERING_MODE_NATURAL
+ 5 - DWRITE_RENDERING_MODE_NATURAL_SYMMETRIC
+ 6 - DWRITE_RENDERING_MODE_OUTLINE
+
+ See this URL for detail:
+ http://msdn.microsoft.com/en-us/library/dd368118.aspx
+
+ For taamode: antialiasing mode used for drawing text.
+ 0 - D2D1_TEXT_ANTIALIAS_MODE_DEFAULT
+ 1 - D2D1_TEXT_ANTIALIAS_MODE_CLEARTYPE
+ 2 - D2D1_TEXT_ANTIALIAS_MODE_GRAYSCALE
+ 3 - D2D1_TEXT_ANTIALIAS_MODE_ALIASED
+
+ See this URL for detail:
+ http://msdn.microsoft.com/en-us/library/dd368170.aspx
+
+ Example: >
+ set encoding=utf-8
+ set gfn=Ricty_Diminished:h12:cSHIFTJIS
+ set rop=type:directx
+<
+ If select a raster font (Courier, Terminal or FixedSys) to
+ 'guifont', it fallbacks to be drawn by GDI automatically.
+
+ Other render types are currently not supported.
+
*'report'*
'report' number (default 2)
global
diff --git a/runtime/doc/various.txt b/runtime/doc/various.txt
index b264e5be8..a03a0bd94 100644
--- a/runtime/doc/various.txt
+++ b/runtime/doc/various.txt
@@ -337,6 +337,7 @@ N *+dialog_con* Support for |:confirm| with console dialog.
N *+dialog_con_gui* Support for |:confirm| with GUI and console dialog.
N *+diff* |vimdiff| and 'diff'
N *+digraphs* |digraphs| *E196*
+m *+directx* Win32 GUI only: DirectX and |'renderoptions'|
*+dnd* Support for DnD into the "~ register |quote_~|.
B *+emacs_tags* |emacs-tags| files
N *+eval* expression evaluation |eval.txt|
diff --git a/src/Make_cyg.mak b/src/Make_cyg.mak
index f34979807..24f19c9f2 100644
--- a/src/Make_cyg.mak
+++ b/src/Make_cyg.mak
@@ -8,6 +8,7 @@
# Cygwin application use the Makefile (just like on Unix).
#
# GUI no or yes: set to yes if you want the GUI version (yes)
+# DIRECTX no or yes: set to yes if you want use DirectWrite (no)
# PERL define to path to Perl dir to get Perl support (not defined)
# PERL_VER define to version of Perl being used (56)
# DYNAMIC_PERL no or yes: set to yes to load the Perl DLL dynamically (yes)
@@ -88,6 +89,10 @@ ifndef ARCH
ARCH = i386
endif
+ifndef DIRECTX
+DIRECTX = no
+endif
+
ifndef WINVER
WINVER = 0x0500
endif
@@ -470,6 +475,15 @@ endif
endif
##############################
+ifeq (yes, $(DIRECTX))
+# Only allow DIRECTX for a GUI build.
+DEFINES += -DFEAT_DIRECTX -DDYNAMIC_DIRECTX
+EXTRA_OBJS += $(OUTDIR)/gui_dwrite.o
+EXTRA_LIBS += -ld2d1 -ldwrite
+USE_STDCPLUS = yes
+endif
+
+##############################
ifdef XPM
# Only allow XPM for a GUI build.
DEFINES += -DFEAT_XPM_W32
@@ -495,11 +509,7 @@ ifeq (yes, $(OLE))
DEFINES += -DFEAT_OLE
EXTRA_OBJS += $(OUTDIR)/if_ole.o
EXTRA_LIBS += -loleaut32
-ifeq (yes, $(STATIC_STDCPLUS))
-EXTRA_LIBS += -Wl,-Bstatic -lstdc++ -Wl,-Bdynamic
-else
-EXTRA_LIBS += -lstdc++
-endif
+USE_STDCPLUS = yes
endif
##############################
@@ -513,6 +523,15 @@ MKDIR = mkdir
DIRSLASH = \\
endif
+##############################
+ifeq (yes, $(USE_STDCPLUS))
+ifeq (yes, $(STATIC_STDCPLUS))
+EXTRA_LIBS += -Wl,-Bstatic -lstdc++ -Wl,-Bdynamic
+else
+EXTRA_LIBS += -lstdc++
+endif
+endif
+
#>>>>> end of choices
###########################################################################
@@ -643,6 +662,9 @@ $(OUTDIR)/ex_eval.o: ex_eval.c $(INCL) ex_cmds.h
$(OUTDIR)/gui_w32.o: gui_w32.c gui_w48.c $(INCL)
$(CC) -c $(CFLAGS) gui_w32.c -o $(OUTDIR)/gui_w32.o
+$(OUTDIR)/gui_dwrite.o: gui_dwrite.cpp $(INCL) gui_dwrite.h
+ $(CC) -c $(CFLAGS) gui_dwrite.cpp -o $(OUTDIR)/gui_dwrite.o
+
$(OUTDIR)/if_cscope.o: if_cscope.c $(INCL) if_cscope.h
$(CC) -c $(CFLAGS) if_cscope.c -o $(OUTDIR)/if_cscope.o
diff --git a/src/Make_ming.mak b/src/Make_ming.mak
index f7088ad58..de1d88fe4 100644
--- a/src/Make_ming.mak
+++ b/src/Make_ming.mak
@@ -31,6 +31,8 @@ DEBUG=no
OPTIMIZE=MAXSPEED
# set to yes to make gvim, no for vim
GUI=yes
+# set to yes if you want to use DirectWrite (DirectX)
+DIRECTX=no
# FEATURES=[TINY | SMALL | NORMAL | BIG | HUGE]
# Set to TINY to make minimal version (few features).
FEATURES=BIG
@@ -456,6 +458,14 @@ endif
endif
endif
+# DirectWrite (DirectX)
+ifeq ($(DIRECTX),yes)
+# Only allow DirectWrite for a GUI build.
+ifeq (yes, $(GUI))
+DEFINES += -DFEAT_DIRECTX -DDYNAMIC_DIRECTX
+endif
+endif
+
# Only allow XPM for a GUI build.
ifeq (yes, $(GUI))
@@ -593,6 +603,14 @@ OBJ += $(OUTDIR)/netbeans.o
LIB += -lwsock32
endif
endif
+ifeq ($(DIRECTX),yes)
+# Only allow DIRECTX for a GUI build.
+ifeq (yes, $(GUI))
+OBJ += $(OUTDIR)/gui_dwrite.o
+LIB += -ld2d1 -ldwrite
+USE_STDCPLUS = yes
+endif
+endif
ifdef XPM
# Only allow XPM for a GUI build.
ifeq (yes, $(GUI))
@@ -650,11 +668,7 @@ endif
ifeq (yes, $(OLE))
LIB += -loleaut32
OBJ += $(OUTDIR)/if_ole.o
-ifeq (yes, $(STATIC_STDCPLUS))
-LIB += -Wl,-Bstatic -lstdc++ -Wl,-Bdynamic
-else
-LIB += -lstdc++
-endif
+USE_STDCPLUS = yes
endif
ifeq (yes, $(MBYTE))
@@ -678,6 +692,14 @@ endif
DEFINES+=-DDYNAMIC_ICONV
endif
+ifeq (yes, $(USE_STDCPLUS))
+ifeq (yes, $(STATIC_STDCPLUS))
+LIB += -Wl,-Bstatic -lstdc++ -Wl,-Bdynamic
+else
+LIB += -lstdc++
+endif
+endif
+
all: $(TARGET) vimrun.exe xxd/xxd.exe install.exe uninstal.exe GvimExt/gvimext.dll
vimrun.exe: vimrun.c
@@ -751,6 +773,9 @@ $(OUTDIR)/ex_eval.o: ex_eval.c $(INCL) ex_cmds.h
$(OUTDIR)/gui_w32.o: gui_w32.c gui_w48.c $(INCL)
$(CC) -c $(CFLAGS) gui_w32.c -o $(OUTDIR)/gui_w32.o
+$(OUTDIR)/gui_dwrite.o: gui_dwrite.cpp $(INCL) gui_dwrite.h
+ $(CC) -c $(CFLAGS) gui_dwrite.cpp -o $(OUTDIR)/gui_dwrite.o
+
$(OUTDIR)/if_cscope.o: if_cscope.c $(INCL) if_cscope.h
$(CC) -c $(CFLAGS) if_cscope.c -o $(OUTDIR)/if_cscope.o
diff --git a/src/Make_mvc.mak b/src/Make_mvc.mak
index 4a979e419..24069b24e 100644
--- a/src/Make_mvc.mak
+++ b/src/Make_mvc.mak
@@ -24,6 +24,9 @@
#
# GUI interface: GUI=yes (default is no)
#
+# GUI with DirectWrite(DirectX): DIRECTX=yes
+# (default is no, requires GUI=yes)
+#
# OLE interface: OLE=yes (usually with GUI=yes)
#
# Multibyte support: MBYTE=yes (default is no)
@@ -168,6 +171,9 @@ OBJDIR = .\ObjG
!else
OBJDIR = .\ObjC
!endif
+!if "$(DIRECTX)" == "yes"
+OBJDIR = $(OBJDIR)X
+!endif
!if "$(OLE)" == "yes"
OBJDIR = $(OBJDIR)O
!endif
@@ -292,6 +298,13 @@ NBDEBUG_SRC = nbdebug.c
NETBEANS_LIB = WSock32.lib
!endif
+# DirectWrite(DirectX)
+!if "$(DIRECTX)" == "yes"
+DIRECTX_DEFS = -DFEAT_DIRECTX -DDYNAMIC_DIRECTX
+DIRECTX_INCL = gui_dwrite.h
+DIRECTX_OBJ = $(OUTDIR)\gui_dwrite.obj
+!endif
+
!ifndef XPM
# XPM is not set, use the included xpm files, depending on the architecture.
!if "$(CPU)" == "AMD64"
@@ -642,6 +655,12 @@ GUI_LIB = \
SUBSYSTEM = console
!endif
+!if "$(GUI)" == "yes" && "$(DIRECTX)" == "yes"
+CFLAGS = $(CFLAGS) $(DIRECTX_DEFS)
+GUI_INCL = $(GUI_INCL) $(DIRECTX_INCL)
+GUI_OBJ = $(GUI_OBJ) $(DIRECTX_OBJ)
+!endif
+
# iconv.dll library (dynamically loaded)
!ifndef ICONV
ICONV = yes
@@ -1107,6 +1126,8 @@ $(OUTDIR)/gui_beval.obj: $(OUTDIR) gui_beval.c $(INCL) $(GUI_INCL)
$(OUTDIR)/gui_w32.obj: $(OUTDIR) gui_w32.c gui_w48.c $(INCL) $(GUI_INCL)
+$(OUTDIR)/gui_dwrite.obj: $(OUTDIR) gui_dwrite.cpp $(INCL) $(GUI_INCL)
+
$(OUTDIR)/if_cscope.obj: $(OUTDIR) if_cscope.c $(INCL)
$(OUTDIR)/if_lua.obj: $(OUTDIR) if_lua.c $(INCL)
diff --git a/src/eval.c b/src/eval.c
index 4e512af64..ae8331d5a 100644
--- a/src/eval.c
+++ b/src/eval.c
@@ -12464,6 +12464,9 @@ f_has(argvars, rettv)
#ifdef FEAT_DIGRAPHS
"digraphs",
#endif
+#ifdef FEAT_DIRECTX
+ "directx",
+#endif
#ifdef FEAT_DND
"dnd",
#endif
diff --git a/src/gui_dwrite.cpp b/src/gui_dwrite.cpp
new file mode 100644
index 000000000..cf83c0504
--- /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;
+}
diff --git a/src/gui_dwrite.h b/src/gui_dwrite.h
new file mode 100644
index 000000000..647f479a6
--- /dev/null
+++ b/src/gui_dwrite.h
@@ -0,0 +1,85 @@
+/* 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.
+ */
+
+#ifndef GUI_DWRITE_H
+#define GUI_DWRITE_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+typedef struct DWriteContext DWriteContext;
+
+typedef struct DWriteRenderingParams {
+ float gamma;
+ float enhancedContrast;
+ float clearTypeLevel;
+ /*
+ * pixelGeometry:
+ * 0 - DWRITE_PIXEL_GEOMETRY_FLAT
+ * 1 - DWRITE_PIXEL_GEOMETRY_RGB
+ * 2 - DWRITE_PIXEL_GEOMETRY_BGR
+ */
+ int pixelGeometry;
+ /*
+ * renderingMode:
+ * 0 - DWRITE_RENDERING_MODE_DEFAULT
+ * 1 - DWRITE_RENDERING_MODE_ALIASED
+ * 2 - DWRITE_RENDERING_MODE_CLEARTYPE_GDI_CLASSIC
+ * 3 - DWRITE_RENDERING_MODE_CLEARTYPE_GDI_NATURAL
+ * 4 - DWRITE_RENDERING_MODE_CLEARTYPE_NATURAL
+ * 5 - DWRITE_RENDERING_MODE_CLEARTYPE_NATURAL_SYMMETRIC
+ * 6 - DWRITE_RENDERING_MODE_OUTLINE
+ */
+ int renderingMode;
+ /*
+ * antialiasMode:
+ * 0 - D2D1_TEXT_ANTIALIAS_MODE_DEFAULT
+ * 1 - D2D1_TEXT_ANTIALIAS_MODE_CLEARTYPE
+ * 2 - D2D1_TEXT_ANTIALIAS_MODE_GRAYSCALE
+ * 3 - D2D1_TEXT_ANTIALIAS_MODE_ALIASED
+ */
+ int textAntialiasMode;
+} DWriteRenderingParams;
+
+void DWrite_Init(void);
+void DWrite_Final(void);
+
+DWriteContext *DWriteContext_Open(void);
+void DWriteContext_BeginDraw(DWriteContext *ctx);
+void DWriteContext_BindDC(DWriteContext *ctx, HDC hdc, RECT *rect);
+void DWriteContext_SetFont(DWriteContext *ctx, HFONT 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);
+void DWriteContext_EndDraw(DWriteContext *ctx);
+void DWriteContext_Close(DWriteContext *ctx);
+
+void DWriteContext_SetRenderingParams(
+ DWriteContext *ctx,
+ const DWriteRenderingParams *params);
+
+DWriteRenderingParams *DWriteContext_GetRenderingParams(
+ DWriteContext *ctx,
+ DWriteRenderingParams *params);
+
+#ifdef __cplusplus
+}
+#endif
+#endif/*GUI_DWRITE_H*/
diff --git a/src/gui_w32.c b/src/gui_w32.c
index 2d57fbb27..b42817271 100644
--- a/src/gui_w32.c
+++ b/src/gui_w32.c
@@ -25,6 +25,145 @@
#include "vim.h"
+#if defined(FEAT_DIRECTX)
+# include "gui_dwrite.h"
+#endif
+
+#if defined(FEAT_DIRECTX) || defined(PROTO)
+static DWriteContext *s_dwc = NULL;
+static int s_directx_enabled = 0;
+static int s_directx_load_attempted = 0;
+# define IS_ENABLE_DIRECTX() (s_directx_enabled && s_dwc != NULL)
+
+ int
+directx_enabled(void)
+{
+ if (s_dwc != NULL)
+ return 1;
+ else if (s_directx_load_attempted)
+ return 0;
+ /* load DirectX */
+ DWrite_Init();
+ s_directx_load_attempted = 1;
+ s_dwc = DWriteContext_Open();
+ return s_dwc != NULL ? 1 : 0;
+}
+#endif
+
+#if defined(FEAT_RENDER_OPTIONS) || defined(PROTO)
+ int
+gui_mch_set_rendering_options(char_u *s)
+{
+#ifdef FEAT_DIRECTX
+ int retval = FAIL;
+ char_u *p, *q;
+
+ int dx_enable = 0;
+ int dx_flags = 0;
+ float dx_gamma = 0.0f;
+ float dx_contrast = 0.0f;
+ float dx_level = 0.0f;
+ int dx_geom = 0;
+ int dx_renmode = 0;
+ int dx_taamode = 0;
+
+ /* parse string as rendering options. */
+ for (p = s; p != NULL && *p != NUL; )
+ {
+ char_u item[256];
+ char_u name[128];
+ char_u value[128];
+
+ copy_option_part(&p, item, sizeof(item), ",");
+ if (p == NULL)
+ break;
+ q = &item[0];
+ copy_option_part(&q, name, sizeof(name), ":");
+ if (q == NULL)
+ return FAIL;
+ copy_option_part(&q, value, sizeof(value), ":");
+
+ if (STRCMP(name, "type") == 0)
+ {
+ if (STRCMP(value, "directx") == 0)
+ dx_enable = 1;
+ else
+ return FAIL;
+ }
+ else if (STRCMP(name, "gamma") == 0)
+ {
+ dx_flags |= 1 << 0;
+ dx_gamma = (float)atof(value);
+ }
+ else if (STRCMP(name, "contrast") == 0)
+ {
+ dx_flags |= 1 << 1;
+ dx_contrast = (float)atof(value);
+ }
+ else if (STRCMP(name, "level") == 0)
+ {
+ dx_flags |= 1 << 2;
+ dx_level = (float)atof(value);
+ }
+ else if (STRCMP(name, "geom") == 0)
+ {
+ dx_flags |= 1 << 3;
+ dx_geom = atoi(value);
+ if (dx_geom < 0 || dx_geom > 2)
+ return FAIL;
+ }
+ else if (STRCMP(name, "renmode") == 0)
+ {
+ dx_flags |= 1 << 4;
+ dx_renmode = atoi(value);
+ if (dx_renmode < 0 || dx_renmode > 6)
+ return FAIL;
+ }
+ else if (STRCMP(name, "taamode") == 0)
+ {
+ dx_flags |= 1 << 5;
+ dx_taamode = atoi(value);
+ if (dx_taamode < 0 || dx_taamode > 3)
+ return FAIL;
+ }
+ else
+ return FAIL;
+ }
+
+ /* Enable DirectX/DirectWrite */
+ if (dx_enable)
+ {
+ if (!directx_enabled())
+ return FAIL;
+ DWriteContext_SetRenderingParams(s_dwc, NULL);
+ if (dx_flags)
+ {
+ DWriteRenderingParams param;
+ DWriteContext_GetRenderingParams(s_dwc, &param);
+ if (dx_flags & (1 << 0))
+ param.gamma = dx_gamma;
+ if (dx_flags & (1 << 1))
+ param.enhancedContrast = dx_contrast;
+ if (dx_flags & (1 << 2))
+ param.clearTypeLevel = dx_level;
+ if (dx_flags & (1 << 3))
+ param.pixelGeometry = dx_geom;
+ if (dx_flags & (1 << 4))
+ param.renderingMode = dx_renmode;
+ if (dx_flags & (1 << 5))
+ param.textAntialiasMode = dx_taamode;
+ DWriteContext_SetRenderingParams(s_dwc, &param);
+ }
+ }
+ s_directx_enabled = dx_enable;
+
+ return OK;
+#else
+ return FAIL;
+#endif
+}
+#endif
+
/*
* These are new in Windows ME/XP, only defined in recent compilers.
*/
@@ -1624,6 +1763,11 @@ gui_mch_init(void)
set_vim_var_nr(VV_WINDOWID, HandleToLong(s_hwnd));
#endif
+#ifdef FEAT_RENDER_OPTIONS
+ if (p_rop)
+ (void)gui_mch_set_rendering_options(p_rop);
+#endif
+
theend:
/* Display any pending error messages */
display_errors();
@@ -1695,9 +1839,9 @@ gui_mch_set_shellsize(int width, int height,
/* compute the size of the outside of the window */
win_width = width + (GetSystemMetrics(SM_CXFRAME) +
- GetSystemMetrics(SM_CXPADDEDBORDER)) * 2;
+ GetSystemMetrics(SM_CXPADDEDBORDER)) * 2;
win_height = height + (GetSystemMetrics(SM_CYFRAME) +
- GetSystemMetrics(SM_CXPADDEDBORDER)) * 2
+ GetSystemMetrics(SM_CXPADDEDBORDER)) * 2
+ GetSystemMetrics(SM_CYCAPTION)
#ifdef FEAT_MENU
+ gui_mswin_get_menu_height(FALSE)
@@ -2239,6 +2383,9 @@ gui_mch_draw_string(
#endif
HPEN hpen, old_pen;
int y;
+#ifdef FEAT_DIRECTX
+ int font_is_ttf_or_vector = 0;
+#endif
#ifndef MSWIN16_FASTTEXT
/*
@@ -2326,6 +2473,20 @@ gui_mch_draw_string(
SetTextColor(s_hdc, gui.currFgColor);
SelectFont(s_hdc, gui.currFont);
+#ifdef FEAT_DIRECTX
+ if (IS_ENABLE_DIRECTX())
+ {
+ TEXTMETRIC tm;
+
+ GetTextMetrics(s_hdc, &tm);
+ if (tm.tmPitchAndFamily & (TMPF_TRUETYPE | TMPF_VECTOR))
+ {
+ font_is_ttf_or_vector = 1;
+ DWriteContext_SetFont(s_dwc, (HFONT)gui.currFont);
+ }
+ }
+#endif
+
if (pad_size != Columns || padding == NULL || padding[0] != gui.char_width)
{
vim_free(padding);
@@ -2360,6 +2521,14 @@ gui_mch_draw_string(
if (text[n] >= 0x80)
break;
+#if defined(FEAT_DIRECTX)
+ /* Quick hack to enable DirectWrite. To use DirectWrite (antialias), it is
+ * required that unicode drawing routine, currently. So this forces it
+ * enabled. */
+ if (enc_utf8 && IS_ENABLE_DIRECTX())
+ n = 0; /* Keep n < len, to enter block for unicode. */
+#endif
+
/* Check if the Unicode buffer exists and is big enough. Create it
* with the same length as the multi-byte string, the number of wide
* characters is always equal or smaller. */
@@ -2418,8 +2587,17 @@ gui_mch_draw_string(
i += utfc_ptr2len_len(text + i, len - i);
++clen;
}
- ExtTextOutW(s_hdc, TEXT_X(col), TEXT_Y(row),
- foptions, pcliprect, unicodebuf, wlen, unicodepdy);
+#if defined(FEAT_DIRECTX)
+ if (IS_ENABLE_DIRECTX() && font_is_ttf_or_vector)
+ {
+ DWriteContext_DrawText(s_dwc, s_hdc, unicodebuf, wlen,
+ TEXT_X(col), TEXT_Y(row), FILL_X(cells), FILL_Y(1),
+ gui.char_width, gui.currFgColor);
+ }
+ else
+#endif
+ ExtTextOutW(s_hdc, TEXT_X(col), TEXT_Y(row),
+ foptions, pcliprect, unicodebuf, wlen, unicodepdy);
len = cells; /* used for underlining */
}
else if ((enc_codepage > 0 && (int)GetACP() != enc_codepage) || enc_latin9)
@@ -2549,14 +2727,14 @@ gui_mch_get_screen_dimensions(int *screen_w, int *screen_h)
*screen_w = workarea_rect.right - workarea_rect.left
- (GetSystemMetrics(SM_CXFRAME) +
- GetSystemMetrics(SM_CXPADDEDBORDER)) * 2;
+ GetSystemMetrics(SM_CXPADDEDBORDER)) * 2;
/* FIXME: dirty trick: Because the gui_get_base_height() doesn't include
* the menubar for MSwin, we subtract it from the screen height, so that
* the window size can be made to fit on the screen. */
*screen_h = workarea_rect.bottom - workarea_rect.top
- (GetSystemMetrics(SM_CYFRAME) +
- GetSystemMetrics(SM_CXPADDEDBORDER)) * 2
+ GetSystemMetrics(SM_CXPADDEDBORDER)) * 2
- GetSystemMetrics(SM_CYCAPTION)
#ifdef FEAT_MENU
- gui_mswin_get_menu_height(FALSE)
@@ -3188,13 +3366,13 @@ gui_mch_dialog(
GetWindowRect(s_hwnd, &rect);
maxDialogWidth = rect.right - rect.left
- (GetSystemMetrics(SM_CXFRAME) +
- GetSystemMetrics(SM_CXPADDEDBORDER)) * 2;
+ GetSystemMetrics(SM_CXPADDEDBORDER)) * 2;
if (maxDialogWidth < DLG_MIN_MAX_WIDTH)
maxDialogWidth = DLG_MIN_MAX_WIDTH;
maxDialogHeight = rect.bottom - rect.top
- (GetSystemMetrics(SM_CYFRAME) +
- GetSystemMetrics(SM_CXPADDEDBORDER)) * 4
+ GetSystemMetrics(SM_CXPADDEDBORDER)) * 4
- GetSystemMetrics(SM_CYCAPTION);
if (maxDialogHeight < DLG_MIN_MAX_HEIGHT)
maxDialogHeight = DLG_MIN_MAX_HEIGHT;
@@ -3351,11 +3529,11 @@ gui_mch_dialog(
/* Restrict the size to a maximum. Causes a scrollbar to show up. */
if (dlgheight > maxDialogHeight)
{
- msgheight = msgheight - (dlgheight - maxDialogHeight);
- dlgheight = maxDialogHeight;
- scroll_flag = WS_VSCROLL;
- /* Make sure scrollbar doesn't appear in the middle of the dialog */
- messageWidth = dlgwidth - DLG_ICON_WIDTH - 3 * dlgPaddingX;
+ msgheight = msgheight - (dlgheight - maxDialogHeight);
+ dlgheight = maxDialogHeight;
+ scroll_flag = WS_VSCROLL;
+ /* Make sure scrollbar doesn't appear in the middle of the dialog */
+ messageWidth = dlgwidth - DLG_ICON_WIDTH - 3 * dlgPaddingX;
}
add_word(PixelToDialogY(dlgheight));
diff --git a/src/gui_w48.c b/src/gui_w48.c
index 89b60908e..ae4c921c0 100644
--- a/src/gui_w48.c
+++ b/src/gui_w48.c
@@ -2785,6 +2785,10 @@ _OnPaint(
out_flush(); /* make sure all output has been processed */
(void)BeginPaint(hwnd, &ps);
+#if defined(FEAT_DIRECTX)
+ if (IS_ENABLE_DIRECTX())
+ DWriteContext_BeginDraw(s_dwc);
+#endif
#ifdef FEAT_MBYTE
/* prevent multi-byte characters from misprinting on an invalid
@@ -2800,9 +2804,20 @@ _OnPaint(
#endif
if (!IsRectEmpty(&ps.rcPaint))
+ {
+#if defined(FEAT_DIRECTX)
+ if (IS_ENABLE_DIRECTX())
+ DWriteContext_BindDC(s_dwc, s_hdc, &ps.rcPaint);
+#endif
gui_redraw(ps.rcPaint.left, ps.rcPaint.top,
ps.rcPaint.right - ps.rcPaint.left + 1,
ps.rcPaint.bottom - ps.rcPaint.top + 1);
+ }
+
+#if defined(FEAT_DIRECTX)
+ if (IS_ENABLE_DIRECTX())
+ DWriteContext_EndDraw(s_dwc);
+#endif
EndPaint(hwnd, &ps);
}
}
@@ -3043,6 +3058,12 @@ gui_mch_insert_lines(
void
gui_mch_exit(int rc)
{
+#if defined(FEAT_DIRECTX)
+ DWriteContext_Close(s_dwc);
+ DWrite_Final();
+ s_dwc = NULL;
+#endif
+
ReleaseDC(s_textArea, s_hdc);
DeleteObject(s_brush);
diff --git a/src/option.c b/src/option.c
index 05d8869ea..3e6164e5a 100644
--- a/src/option.c
+++ b/src/option.c
@@ -2124,6 +2124,15 @@ static struct vimoption
{"remap", NULL, P_BOOL|P_VI_DEF,
(char_u *)&p_remap, PV_NONE,
{(char_u *)TRUE, (char_u *)0L} SCRIPTID_INIT},
+ {"renderoptions", "rop", P_STRING|P_COMMA|P_RCLR|P_VI_DEF,
+#ifdef FEAT_RENDER_OPTIONS
+ (char_u *)&p_rop, PV_NONE,
+ {(char_u *)"", (char_u *)0L}
+#else
+ (char_u *)NULL, PV_NONE,
+ {(char_u *)NULL, (char_u *)0L}
+#endif
+ SCRIPTID_INIT},
{"report", NULL, P_NUM|P_VI_DEF,
(char_u *)&p_report, PV_NONE,
{(char_u *)2L, (char_u *)0L} SCRIPTID_INIT},
@@ -6999,6 +7008,14 @@ did_set_string_option(opt_idx, varp, new_value_alloced, oldval, errbuf,
}
#endif
+#if defined(FEAT_RENDER_OPTIONS)
+ else if (varp == &p_rop && gui.in_use)
+ {
+ if (!gui_mch_set_rendering_options(p_rop))
+ errmsg = e_invarg;
+ }
+#endif
+
/* Options that are a list of flags. */
else
{
diff --git a/src/option.h b/src/option.h
index edf905844..696d70d6a 100644
--- a/src/option.h
+++ b/src/option.h
@@ -655,6 +655,9 @@ EXTERN long p_rdt; /* 'redrawtime' */
#endif
EXTERN int p_remap; /* 'remap' */
EXTERN long p_re; /* 'regexpengine' */
+#ifdef FEAT_RENDER_OPTIONS
+EXTERN char_u *p_rop; /* 'renderoptions' */
+#endif
EXTERN long p_report; /* 'report' */
#if defined(FEAT_WINDOWS) && defined(FEAT_QUICKFIX)
EXTERN long p_pvh; /* 'previewheight' */
diff --git a/src/proto/gui_w32.pro b/src/proto/gui_w32.pro
index a333233d7..88fbf67c6 100644
--- a/src/proto/gui_w32.pro
+++ b/src/proto/gui_w32.pro
@@ -1,4 +1,6 @@
/* gui_w32.c */
+int directx_enabled __ARGS((void));
+int gui_mch_set_rendering_options __ARGS((char_u *s));
void gui_mch_set_blinking __ARGS((long wait, long on, long off));
void gui_mch_stop_blink __ARGS((void));
void gui_mch_start_blink __ARGS((void));
diff --git a/src/version.c b/src/version.c
index 6610ba110..fd9e275fa 100644
--- a/src/version.c
+++ b/src/version.c
@@ -189,6 +189,13 @@ static char *(features[]) =
#else
"-digraphs",
#endif
+#ifdef FEAT_GUI_W32
+# ifdef FEAT_DIRECTX
+ "+directx",
+# else
+ "-directx",
+# endif
+#endif
#ifdef FEAT_DND
"+dnd",
#else
@@ -735,6 +742,8 @@ static char *(features[]) =
static int included_patches[] =
{ /* Add new patch number below this line */
/**/
+ 393,
+/**/
392,
/**/
391,
diff --git a/src/vim.h b/src/vim.h
index 84e139c75..887a76d1f 100644
--- a/src/vim.h
+++ b/src/vim.h
@@ -134,6 +134,13 @@
# endif
#endif
+/* Check support for rendering options */
+#ifdef FEAT_GUI
+# if defined(FEAT_DIRECTX)
+# define FEAT_RENDER_OPTIONS
+# endif
+#endif
+
/* Visual Studio 2005 has 'deprecated' many of the standard CRT functions */
#if _MSC_VER >= 1400
# define _CRT_SECURE_NO_DEPRECATE