updated for version 7.4.393
Problem: Text drawing on newer MS-Windows systems is suboptimal. Some
multi-byte characters are not displayed, even though the same font
in Notepad can display them. (Srinath Avadhanula)
Solution: Add the 'renderoptions' option to enable Direct-X drawing. (Taro
Muraoka)
diff --git a/src/gui_w32.c b/src/gui_w32.c
index 2d57fbb..b428172 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, ¶m);
+ 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, ¶m);
+ }
+ }
+ 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 @@
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 @@
/* 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 @@
#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 @@
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 @@
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 @@
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 @@
*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 @@
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 @@
/* 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));