]> granicus.if.org Git - vim/commitdiff
updated for version 7.4.393 v7.4.393
authorBram Moolenaar <Bram@vim.org>
Wed, 6 Aug 2014 12:52:30 +0000 (14:52 +0200)
committerBram Moolenaar <Bram@vim.org>
Wed, 6 Aug 2014 12:52:30 +0000 (14:52 +0200)
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)

16 files changed:
runtime/doc/eval.txt
runtime/doc/options.txt
runtime/doc/various.txt
src/Make_cyg.mak
src/Make_ming.mak
src/Make_mvc.mak
src/eval.c
src/gui_dwrite.cpp [new file with mode: 0644]
src/gui_dwrite.h [new file with mode: 0644]
src/gui_w32.c
src/gui_w48.c
src/option.c
src/option.h
src/proto/gui_w32.pro
src/version.c
src/vim.h

index cbd995da3d1624b1718b441172e2a014c9d7c766..62aa1670418cbb66e73f8124fd23d3f7e35f3167 100644 (file)
@@ -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.
index 90d4ca7a7092a9a8789f3500545b7f8b0161dfcb..5f4a06e7ef5d1243351bb9dc97a82483ed962e8f 100644 (file)
@@ -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
index b264e5be8ce1c82806fdc9023fc4076bbbec9d7a..a03a0bd94ae356e4c4708c3dac0ccc2530a04e45 100644 (file)
@@ -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|
index f3497980788541c9122de4b42b2284c0bbbc885e..24f19c9f2a7d5a4300026657620d0965ec0fdbda 100644 (file)
@@ -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
@@ -469,6 +474,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.
@@ -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
 
index f7088ad58edd6e847a8bb5255a4e5d1d325ff324..de1d88fe4c37dbef07bff92d5d407da9ae97fb98 100644 (file)
@@ -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
 
index 4a979e419bb6e9d9d78dcd5eb06374c8e76a4b16..24069b24e99116b8e87f1591c71ee8ab17d66623 100644 (file)
@@ -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)
index 4e512af648580558d9d6aa232d629220ce2f320b..ae8331d5aaa92a71e26f374dd075827f0b4e7250 100644 (file)
@@ -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 (file)
index 0000000..cf83c05
--- /dev/null
@@ -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 (file)
index 0000000..647f479
--- /dev/null
@@ -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*/
index 2d57fbb272f9392fda644257f1c9571d4c105857..b42817271c362eecf922e855e089dd28b7eef232 100644 (file)
 
 #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));
index 89b60908e59991b788ac0554056a5f1555656511..ae4c921c0d9ac9801cf8ea5d8141de60e670a117 100644 (file)
@@ -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);
 
index 05d8869eaa495efb71fb59125f5ffc57d03588a8..3e6164e5a6527950e1dcb24cbe3255ad8f87ac62 100644 (file)
@@ -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
     {
index edf905844021fdc33afc12b4520338721e4f72f1..696d70d6a29d3eb3e6be777ddb060c587c0490fd 100644 (file)
@@ -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' */
index a333233d781b52ce96c6b18484a25b2cd3c82a40..88fbf67c6237c6c7d5f766c775c03836136c1e09 100644 (file)
@@ -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));
index 6610ba110ea398fdfc95709146723b8598b8e429..fd9e275faa20a04dae9511dd3e6b1e213826128e 100644 (file)
@@ -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
@@ -734,6 +741,8 @@ static char *(features[]) =
 
 static int included_patches[] =
 {   /* Add new patch number below this line */
+/**/
+    393,
 /**/
     392,
 /**/
index 84e139c75a3536499ff8256224724813951e9022..887a76d1f461d8be7a5177f581bd2587969d7d6c 100644 (file)
--- a/src/vim.h
+++ b/src/vim.h
 # 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