patch 8.0.1369: MS-Windows: drawing underline slow, mFallbackDC not updated

Problem:    MS-Windows: drawing underline, curl and strike-throw is slow,
            mFallbackDC not properly updated.
Solution:   Several performance improvements. (Ken Takata, Taro Muraoka,
            Yasuhiro Matsumoto, closes #2401)
diff --git a/src/gui_w32.c b/src/gui_w32.c
index 521279e..c3178ba 100644
--- a/src/gui_w32.c
+++ b/src/gui_w32.c
@@ -33,6 +33,7 @@
 static DWriteContext *s_dwc = NULL;
 static int s_directx_enabled = 0;
 static int s_directx_load_attempted = 0;
+static int s_directx_scrlines = 0;
 # define IS_ENABLE_DIRECTX() (s_directx_enabled && s_dwc != NULL)
 static int directx_enabled(void);
 static void directx_binddc(void);
@@ -57,6 +58,7 @@
     int	    dx_geom = 0;
     int	    dx_renmode = 0;
     int	    dx_taamode = 0;
+    int	    dx_scrlines = 0;
 
     /* parse string as rendering options. */
     for (p = s; p != NULL && *p != NUL; )
@@ -117,6 +119,10 @@
 	    if (dx_taamode < 0 || dx_taamode > 3)
 		return FAIL;
 	}
+	else if (STRCMP(name, "scrlines") == 0)
+	{
+	    dx_scrlines = atoi((char *)value);
+	}
 	else
 	    return FAIL;
     }
@@ -147,6 +153,7 @@
 	}
     }
     s_directx_enabled = dx_enable;
+    s_directx_scrlines = dx_scrlines;
 
     return OK;
 #else
@@ -283,6 +290,7 @@
 #endif
 
 static void _OnPaint( HWND hwnd);
+static void fill_rect(const RECT *rcp, HBRUSH hbr, COLORREF color);
 static void clear_rect(RECT *rcp);
 
 static WORD		s_dlgfntheight;		/* height of the dialog font */
@@ -605,10 +613,7 @@
 	blink_timer = (UINT) SetTimer(NULL, 0, (UINT)blink_ontime,
 						    (TIMERPROC)_OnBlinkTimer);
     }
-#if defined(FEAT_DIRECTX)
-    if (IS_ENABLE_DIRECTX())
-	DWriteContext_Flush(s_dwc);
-#endif
+    gui_mch_flush();
 }
 
     static void
@@ -634,7 +639,10 @@
 {
     gui_mswin_rm_blink_timer();
     if (blink_state == BLINK_OFF)
+    {
 	gui_update_cursor(TRUE, FALSE);
+	gui_mch_flush();
+    }
     blink_state = BLINK_NONE;
 }
 
@@ -654,6 +662,7 @@
 						    (TIMERPROC)_OnBlinkTimer);
 	blink_state = BLINK_ON;
 	gui_update_cursor(TRUE, FALSE);
+	gui_mch_flush();
     }
 }
 
@@ -1730,7 +1739,6 @@
     int		h,
     guicolor_T	color)
 {
-    HBRUSH	hbr;
     RECT	rc;
 
     /*
@@ -1746,14 +1754,7 @@
     rc.right = rc.left + w;
     rc.bottom = rc.top + h;
 
-#if defined(FEAT_DIRECTX)
-    if (IS_ENABLE_DIRECTX())
-	DWriteContext_Flush(s_dwc);
-#endif
-
-    hbr = CreateSolidBrush(color);
-    FillRect(s_hdc, &rc, hbr);
-    DeleteBrush(hbr);
+    fill_rect(&rc, NULL, color);
 }
 
 
@@ -3122,13 +3123,8 @@
     int	    num_lines)
 {
     RECT	rc;
-
-    intel_gpu_workaround();
-
 #if defined(FEAT_DIRECTX)
-    // Commit drawing queue before ScrollWindowEx.
-    if (IS_ENABLE_DIRECTX())
-	DWriteContext_Flush(s_dwc);
+    int		use_redraw = 0;
 #endif
 
     rc.left = FILL_X(gui.scroll_region_left);
@@ -3136,8 +3132,24 @@
     rc.top = FILL_Y(row);
     rc.bottom = FILL_Y(gui.scroll_region_bot + 1);
 
-    ScrollWindowEx(s_textArea, 0, -num_lines * gui.char_height,
+#if defined(FEAT_DIRECTX)
+    if (IS_ENABLE_DIRECTX())
+    {
+	if (s_directx_scrlines > 0 && s_directx_scrlines <= num_lines)
+	{
+	    RedrawWindow(s_textArea, &rc, NULL, RDW_INVALIDATE);
+	    use_redraw = 1;
+	}
+	else
+	    DWriteContext_Flush(s_dwc);
+    }
+    if (!use_redraw)
+#endif
+    {
+	intel_gpu_workaround();
+	ScrollWindowEx(s_textArea, 0, -num_lines * gui.char_height,
 				    &rc, &rc, NULL, NULL, get_scroll_flags());
+    }
 
     UpdateWindow(s_textArea);
     /* This seems to be required to avoid the cursor disappearing when
@@ -3161,23 +3173,35 @@
     int		num_lines)
 {
     RECT	rc;
-
-    intel_gpu_workaround();
-
 #if defined(FEAT_DIRECTX)
-    // Commit drawing queue before ScrollWindowEx.
-    if (IS_ENABLE_DIRECTX())
-	DWriteContext_Flush(s_dwc);
+    int		use_redraw = 0;
 #endif
 
     rc.left = FILL_X(gui.scroll_region_left);
     rc.right = FILL_X(gui.scroll_region_right + 1);
     rc.top = FILL_Y(row);
     rc.bottom = FILL_Y(gui.scroll_region_bot + 1);
-    /* The SW_INVALIDATE is required when part of the window is covered or
-     * off-screen.  How do we avoid it when it's not needed? */
-    ScrollWindowEx(s_textArea, 0, num_lines * gui.char_height,
+
+#if defined(FEAT_DIRECTX)
+    if (IS_ENABLE_DIRECTX())
+    {
+	if (s_directx_scrlines > 0 && s_directx_scrlines <= num_lines)
+	{
+	    RedrawWindow(s_textArea, &rc, NULL, RDW_INVALIDATE);
+	    use_redraw = 1;
+	}
+	else
+	    DWriteContext_Flush(s_dwc);
+    }
+    if (!use_redraw)
+#endif
+    {
+	intel_gpu_workaround();
+	/* The SW_INVALIDATE is required when part of the window is covered or
+	 * off-screen.  How do we avoid it when it's not needed? */
+	ScrollWindowEx(s_textArea, 0, num_lines * gui.char_height,
 				    &rc, &rc, NULL, NULL, get_scroll_flags());
+    }
 
     UpdateWindow(s_textArea);
 
@@ -5853,6 +5877,7 @@
 		}
 	    }
 	    gui_update_cursor(TRUE, FALSE);
+	    gui_mch_flush();
 	    lResult = 0;
 	    break;
     }
@@ -6181,6 +6206,67 @@
 }
 #endif
 
+    static void
+draw_line(
+    int		x1,
+    int	    	y1,
+    int	    	x2,
+    int	    	y2,
+    COLORREF	color)
+{
+#if defined(FEAT_DIRECTX)
+    if (IS_ENABLE_DIRECTX())
+	DWriteContext_DrawLine(s_dwc, x1, y1, x2, y2, color);
+    else
+#endif
+    {
+	HPEN	hpen = CreatePen(PS_SOLID, 1, color);
+	HPEN	old_pen = SelectObject(s_hdc, hpen);
+	MoveToEx(s_hdc, x1, y1, NULL);
+	/* Note: LineTo() excludes the last pixel in the line. */
+	LineTo(s_hdc, x2, y2);
+	DeleteObject(SelectObject(s_hdc, old_pen));
+    }
+}
+
+    static void
+set_pixel(
+    int		x,
+    int	    	y,
+    COLORREF	color)
+{
+#if defined(FEAT_DIRECTX)
+    if (IS_ENABLE_DIRECTX())
+	DWriteContext_SetPixel(s_dwc, x, y, color);
+    else
+#endif
+	SetPixel(s_hdc, x, y, color);
+}
+
+    static void
+fill_rect(
+    const RECT	*rcp,
+    HBRUSH    	hbr,
+    COLORREF	color)
+{
+#if defined(FEAT_DIRECTX)
+    if (IS_ENABLE_DIRECTX())
+	DWriteContext_FillRect(s_dwc, rcp, color);
+    else
+#endif
+    {
+	HBRUSH	hbr2;
+
+	if (hbr == NULL)
+	    hbr2 = CreateSolidBrush(color);
+	else
+	    hbr2 = hbr;
+	FillRect(s_hdc, rcp, hbr2);
+	if (hbr == NULL)
+	    DeleteBrush(hbr2);
+    }
+}
+
     void
 gui_mch_draw_string(
     int		row,
@@ -6200,7 +6286,6 @@
     static int	unibuflen = 0;
     int		n = 0;
 #endif
-    HPEN	hpen, old_pen;
     int		y;
 
     /*
@@ -6263,11 +6348,7 @@
 	    brush_lru = !brush_lru;
 	}
 
-#if defined(FEAT_DIRECTX)
-	if (IS_ENABLE_DIRECTX())
-	    DWriteContext_FillRect(s_dwc, &rc, gui.currBgColor);
-#endif
-	FillRect(s_hdc, &rc, hbr);
+	fill_rect(&rc, hbr, gui.currBgColor);
 
 	SetBkMode(s_hdc, TRANSPARENT);
 
@@ -6462,38 +6543,22 @@
 			 foptions, pcliprect, (char *)text, len, padding);
     }
 
-#if defined(FEAT_DIRECTX)
-    if (IS_ENABLE_DIRECTX() &&
-	    (flags & (DRAW_UNDERL | DRAW_STRIKE | DRAW_UNDERC | DRAW_CURSOR)))
-	DWriteContext_Flush(s_dwc);
-#endif
-
     /* Underline */
     if (flags & DRAW_UNDERL)
     {
-	hpen = CreatePen(PS_SOLID, 1, gui.currFgColor);
-	old_pen = SelectObject(s_hdc, hpen);
 	/* When p_linespace is 0, overwrite the bottom row of pixels.
 	 * Otherwise put the line just below the character. */
 	y = FILL_Y(row + 1) - 1;
 	if (p_linespace > 1)
 	    y -= p_linespace - 1;
-	MoveToEx(s_hdc, FILL_X(col), y, NULL);
-	/* Note: LineTo() excludes the last pixel in the line. */
-	LineTo(s_hdc, FILL_X(col + len), y);
-	DeleteObject(SelectObject(s_hdc, old_pen));
+	draw_line(FILL_X(col), y, FILL_X(col + len), y, gui.currFgColor);
     }
 
     /* Strikethrough */
     if (flags & DRAW_STRIKE)
     {
-	hpen = CreatePen(PS_SOLID, 1, gui.currSpColor);
-	old_pen = SelectObject(s_hdc, hpen);
 	y = FILL_Y(row + 1) - gui.char_height/2;
-	MoveToEx(s_hdc, FILL_X(col), y, NULL);
-	/* Note: LineTo() excludes the last pixel in the line. */
-	LineTo(s_hdc, FILL_X(col + len), y);
-	DeleteObject(SelectObject(s_hdc, old_pen));
+	draw_line(FILL_X(col), y, FILL_X(col + len), y, gui.currSpColor);
     }
 
     /* Undercurl */
@@ -6507,7 +6572,7 @@
 	for (x = FILL_X(col); x < FILL_X(col + len); ++x)
 	{
 	    offset = val[x % 8];
-	    SetPixel(s_hdc, x, y - offset, gui.currSpColor);
+	    set_pixel(x, y - offset, gui.currSpColor);
 	}
     }
 }
@@ -6541,19 +6606,7 @@
     static void
 clear_rect(RECT *rcp)
 {
-    HBRUSH  hbr;
-
-#if defined(FEAT_DIRECTX)
-    if (IS_ENABLE_DIRECTX())
-    {
-	DWriteContext_FillRect(s_dwc, rcp, gui.back_pixel);
-	return;
-    }
-#endif
-
-    hbr = CreateSolidBrush(gui.back_pixel);
-    FillRect(s_hdc, rcp, hbr);
-    DeleteBrush(hbr);
+    fill_rect(rcp, NULL, gui.back_pixel);
 }