]> granicus.if.org Git - vim/commitdiff
patch 8.0.1369: MS-Windows: drawing underline slow, mFallbackDC not updated v8.0.1369
authorBram Moolenaar <Bram@vim.org>
Tue, 5 Dec 2017 12:22:16 +0000 (13:22 +0100)
committerBram Moolenaar <Bram@vim.org>
Tue, 5 Dec 2017 12:22:16 +0000 (13:22 +0100)
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)

runtime/doc/options.txt
src/gui_dwrite.cpp
src/gui_dwrite.h
src/gui_w32.c
src/version.c

index 08bc78dcf48a9c8f3630f184db497d2cdcf55c91..822e37ef2e30a4a3fa28a69218b4ca509cd0bdc6 100644 (file)
@@ -6122,9 +6122,10 @@ A jump table for the options with a short description can be found at |Q_op|.
                  geom      pixelGeometry       int     0 - 2 (see below)
                  renmode   renderingMode       int     0 - 6 (see below)
                  taamode   textAntialiasMode   int     0 - 3 (see below)
+                 scrlines  Scroll Lines        int     >= 0  (see below)
 
-               See this URL for detail:
-                 http://msdn.microsoft.com/en-us/library/dd368190.aspx
+               See this URL for detail (except for scrlines):
+                 https://msdn.microsoft.com/en-us/library/dd368190.aspx
 
                For geom: structure of a device pixel.
                  0 - DWRITE_PIXEL_GEOMETRY_FLAT
@@ -6132,7 +6133,7 @@ A jump table for the options with a short description can be found at |Q_op|.
                  2 - DWRITE_PIXEL_GEOMETRY_BGR
 
                See this URL for detail:
-                 http://msdn.microsoft.com/en-us/library/dd368114.aspx
+                 https://msdn.microsoft.com/en-us/library/dd368114.aspx
 
                For renmode: method of rendering glyphs.
                  0 - DWRITE_RENDERING_MODE_DEFAULT
@@ -6144,7 +6145,7 @@ A jump table for the options with a short description can be found at |Q_op|.
                  6 - DWRITE_RENDERING_MODE_OUTLINE
 
                See this URL for detail:
-                 http://msdn.microsoft.com/en-us/library/dd368118.aspx
+                 https://msdn.microsoft.com/en-us/library/dd368118.aspx
 
                For taamode: antialiasing mode used for drawing text.
                  0 - D2D1_TEXT_ANTIALIAS_MODE_DEFAULT
@@ -6153,7 +6154,25 @@ A jump table for the options with a short description can be found at |Q_op|.
                  3 - D2D1_TEXT_ANTIALIAS_MODE_ALIASED
 
                See this URL for detail:
-                 http://msdn.microsoft.com/en-us/library/dd368170.aspx
+                 https://msdn.microsoft.com/en-us/library/dd368170.aspx
+
+               For scrlines: threshold for lines to be scrolled.
+                   0 - Always use scrolling. (default)
+                   1 - Use full page redrawing.
+                 > 1 - If the lines to be scrolled is grater or equal to the
+                       specified value, use redrawing.  Otherwise use
+                       scrolling.
+
+               If you feel scrolling a page (CTRL-F) is too slow with DirectX
+               renderer, try this "scrlines" option.
+               When set it "1", Vim uses full page redrawing instead of
+               scrolling.  Redrawing a page is faster than scrolling a
+               page in some environments.
+               After that, when you feel scrolling lines (CTRL-Y) becomes
+               slow, please try "2" or greater value for this option.
+               It works threshold line number to switch scrolling to
+               redrawing.  Scrolling a few lines might be faster than
+               redrawing a page in some environments.
 
                Example: >
                  set encoding=utf-8
@@ -6162,13 +6181,12 @@ A jump table for the options with a short description can be found at |Q_op|.
 <
                If select a raster font (Courier, Terminal or FixedSys which
                have ".fon" extension in file name) to 'guifont', it will be
-               drawn by GDI as a fallback.  This fallback will cause
-               significant slow down on drawing.
+               drawn by GDI as a fallback.
 
                NOTE: It is known that some fonts and options combination
                causes trouble on drawing glyphs.
 
-                 - 'rendmode:5' and 'renmode:6' will not work with some
+                 - 'renmode:5' and 'renmode:6' will not work with some
                    special made fonts (True-Type fonts which includes only
                    bitmap glyphs).
                  - 'taamode:3' will not work with some vector fonts.
index bd76383c5aed64f7968e9e38a1c8edf6d6f93251..e1d19db8da72b726f498922219e03e7f1a3ef3ed 100644 (file)
@@ -263,14 +263,24 @@ private:
     }
 };
 
+enum DrawingMode {
+    DM_GDI = 0,
+    DM_DIRECTX = 1,
+    DM_INTEROP = 2,
+};
+
 struct DWriteContext {
     HDC mHDC;
+    RECT mBindRect;
+    DrawingMode mDMode;
+    HDC mInteropHDC;
     bool mDrawing;
     bool mFallbackDC;
 
     ID2D1Factory *mD2D1Factory;
 
     ID2D1DCRenderTarget *mRT;
+    ID2D1GdiInteropRenderTarget *mGDIRT;
     ID2D1SolidColorBrush *mBrush;
 
     IDWriteFactory *mDWriteFactory;
@@ -292,6 +302,10 @@ struct DWriteContext {
 
     virtual ~DWriteContext();
 
+    HRESULT CreateDeviceResources();
+
+    void DiscardDeviceResources();
+
     HRESULT CreateTextFormatFromLOGFONT(const LOGFONTW &logFont,
            IDWriteTextFormat **ppTextFormat);
 
@@ -299,17 +313,21 @@ struct DWriteContext {
 
     void SetFont(HFONT hFont);
 
-    void BindDC(HDC hdc, RECT *rect);
+    void BindDC(HDC hdc, const RECT *rect);
 
-    void AssureDrawing();
+    HRESULT SetDrawingMode(DrawingMode mode);
 
     ID2D1Brush* SolidBrush(COLORREF color);
 
-    void DrawText(const WCHARtext, int len,
+    void DrawText(const WCHAR *text, int len,
        int x, int y, int w, int h, int cellWidth, COLORREF color,
-       UINT fuOptions, CONST RECT *lprc, CONST INT * lpDx);
+       UINT fuOptions, const RECT *lprc, const INT *lpDx);
 
-    void FillRect(RECT *rc, COLORREF color);
+    void FillRect(const RECT *rc, COLORREF color);
+
+    void DrawLine(int x1, int y1, int x2, int y2, COLORREF color);
+
+    void SetPixel(int x, int y, COLORREF color);
 
     void Flush();
 
@@ -561,10 +579,14 @@ private:
 
 DWriteContext::DWriteContext() :
     mHDC(NULL),
+    mBindRect(),
+    mDMode(DM_GDI),
+    mInteropHDC(NULL),
     mDrawing(false),
     mFallbackDC(false),
     mD2D1Factory(NULL),
     mRT(NULL),
+    mGDIRT(NULL),
     mBrush(NULL),
     mDWriteFactory(NULL),
     mDWriteFactory2(NULL),
@@ -584,25 +606,7 @@ DWriteContext::DWriteContext() :
     _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);
-    }
+       hr = CreateDeviceResources();
 
     if (SUCCEEDED(hr))
     {
@@ -645,10 +649,66 @@ DWriteContext::~DWriteContext()
     SafeRelease(&mDWriteFactory);
     SafeRelease(&mDWriteFactory2);
     SafeRelease(&mBrush);
+    SafeRelease(&mGDIRT);
     SafeRelease(&mRT);
     SafeRelease(&mD2D1Factory);
 }
 
+    HRESULT
+DWriteContext::CreateDeviceResources()
+{
+    HRESULT hr;
+
+    if (mRT != NULL)
+       return S_OK;
+
+    D2D1_RENDER_TARGET_PROPERTIES props = {
+       D2D1_RENDER_TARGET_TYPE_DEFAULT,
+       { DXGI_FORMAT_B8G8R8A8_UNORM, D2D1_ALPHA_MODE_IGNORE },
+       0, 0,
+       D2D1_RENDER_TARGET_USAGE_GDI_COMPATIBLE,
+       D2D1_FEATURE_LEVEL_DEFAULT
+    };
+    hr = mD2D1Factory->CreateDCRenderTarget(&props, &mRT);
+    _RPT2(_CRT_WARN, "CreateDCRenderTarget: hr=%p p=%p\n", hr, mRT);
+
+    if (SUCCEEDED(hr))
+    {
+       // This always succeeds.
+       mRT->QueryInterface(
+               __uuidof(ID2D1GdiInteropRenderTarget),
+               reinterpret_cast<void**>(&mGDIRT));
+       _RPT1(_CRT_WARN, "GdiInteropRenderTarget: p=%p\n", mGDIRT);
+    }
+
+    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))
+    {
+       if (mHDC != NULL)
+       {
+           mRT->BindDC(mHDC, &mBindRect);
+           mRT->SetTransform(D2D1::IdentityMatrix());
+       }
+    }
+
+    return hr;
+}
+
+    void
+DWriteContext::DiscardDeviceResources()
+{
+    SafeRelease(&mBrush);
+    SafeRelease(&mGDIRT);
+    SafeRelease(&mRT);
+}
+
     HRESULT
 DWriteContext::CreateTextFormatFromLOGFONT(const LOGFONTW &logFont,
        IDWriteTextFormat **ppTextFormat)
@@ -817,27 +877,77 @@ DWriteContext::SetFont(HFONT hFont)
        item.pTextFormat = mTextFormat;
        item.fontWeight = mFontWeight;
        item.fontStyle = mFontStyle;
+       mFallbackDC = false;
     }
+    else
+       mFallbackDC = true;
     mFontCache.put(item);
 }
 
     void
-DWriteContext::BindDC(HDC hdc, RECT *rect)
+DWriteContext::BindDC(HDC hdc, const RECT *rect)
 {
     Flush();
     mRT->BindDC(hdc, rect);
     mRT->SetTransform(D2D1::IdentityMatrix());
     mHDC = hdc;
+    mBindRect = *rect;
 }
 
-    void
-DWriteContext::AssureDrawing()
+    HRESULT
+DWriteContext::SetDrawingMode(DrawingMode mode)
 {
-    if (mDrawing == false)
+    HRESULT hr = S_OK;
+
+    switch (mode)
     {
-       mRT->BeginDraw();
-       mDrawing = true;
+       default:
+       case DM_GDI:
+           if (mInteropHDC != NULL)
+           {
+               mGDIRT->ReleaseDC(NULL);
+               mInteropHDC = NULL;
+           }
+           if (mDrawing)
+           {
+               hr = mRT->EndDraw();
+               if (hr == D2DERR_RECREATE_TARGET)
+               {
+                   hr = S_OK;
+                   DiscardDeviceResources();
+                   CreateDeviceResources();
+               }
+               mDrawing = false;
+           }
+           break;
+
+       case DM_DIRECTX:
+           if (mInteropHDC != NULL)
+           {
+               mGDIRT->ReleaseDC(NULL);
+               mInteropHDC = NULL;
+           }
+           else if (mDrawing == false)
+           {
+               CreateDeviceResources();
+               mRT->BeginDraw();
+               mDrawing = true;
+           }
+           break;
+
+       case DM_INTEROP:
+           if (mDrawing == false)
+           {
+               CreateDeviceResources();
+               mRT->BeginDraw();
+               mDrawing = true;
+           }
+           if (mInteropHDC == NULL)
+               hr = mGDIRT->GetDC(D2D1_DC_INITIALIZE_MODE_COPY, &mInteropHDC);
+           break;
     }
+    mDMode = mode;
+    return hr;
 }
 
     ID2D1Brush*
@@ -849,22 +959,31 @@ DWriteContext::SolidBrush(COLORREF color)
 }
 
     void
-DWriteContext::DrawText(const WCHARtext, int len,
+DWriteContext::DrawText(const WCHAR *text, int len,
        int x, int y, int w, int h, int cellWidth, COLORREF color,
-       UINT fuOptions, CONST RECT *lprc, CONST INT * lpDx)
+       UINT fuOptions, const RECT *lprc, const INT *lpDx)
 {
     if (mFallbackDC)
     {
-       Flush();
-       ExtTextOutW(mHDC, x, y, fuOptions, lprc, text, len, lpDx);
+       // Fall back to GDI rendering.
+       HRESULT hr = SetDrawingMode(DM_INTEROP);
+       if (SUCCEEDED(hr))
+       {
+           HGDIOBJ hFont = ::GetCurrentObject(mHDC, OBJ_FONT);
+           HGDIOBJ hOldFont = ::SelectObject(mInteropHDC, hFont);
+           ::SetTextColor(mInteropHDC, color);
+           ::SetBkMode(mInteropHDC, ::GetBkMode(mHDC));
+           ::ExtTextOutW(mInteropHDC, x, y, fuOptions, lprc, text, len, lpDx);
+           ::SelectObject(mInteropHDC, hOldFont);
+       }
        return;
     }
 
-    AssureDrawing();
-
     HRESULT hr;
     IDWriteTextLayout *textLayout = NULL;
 
+    SetDrawingMode(DM_DIRECTX);
+
     hr = mDWriteFactory->CreateTextLayout(text, len, mTextFormat,
            FLOAT(w), FLOAT(h), &textLayout);
 
@@ -883,25 +1002,76 @@ DWriteContext::DrawText(const WCHAR* text, int len,
 }
 
     void
-DWriteContext::FillRect(RECT *rc, COLORREF color)
+DWriteContext::FillRect(const RECT *rc, COLORREF color)
 {
-    AssureDrawing();
-    mRT->FillRectangle(
-           D2D1::RectF(FLOAT(rc->left), FLOAT(rc->top),
-               FLOAT(rc->right), FLOAT(rc->bottom)),
-           SolidBrush(color));
+    if (mDMode == DM_INTEROP)
+    {
+       // GDI functions are used before this call.  Keep using GDI.
+       // (Switching to Direct2D causes terrible slowdown.)
+       HBRUSH hbr = ::CreateSolidBrush(color);
+       ::FillRect(mInteropHDC, rc, hbr);
+       ::DeleteObject(HGDIOBJ(hbr));
+    }
+    else
+    {
+       SetDrawingMode(DM_DIRECTX);
+       mRT->FillRectangle(
+               D2D1::RectF(FLOAT(rc->left), FLOAT(rc->top),
+                   FLOAT(rc->right), FLOAT(rc->bottom)),
+               SolidBrush(color));
+    }
 }
 
     void
-DWriteContext::Flush()
+DWriteContext::DrawLine(int x1, int y1, int x2, int y2, COLORREF color)
 {
-    if (mDrawing)
+    if (mDMode == DM_INTEROP)
     {
-       mRT->EndDraw();
-       mDrawing = false;
+       // GDI functions are used before this call.  Keep using GDI.
+       // (Switching to Direct2D causes terrible slowdown.)
+       HPEN hpen = ::CreatePen(PS_SOLID, 1, color);
+       HGDIOBJ old_pen = ::SelectObject(mInteropHDC, HGDIOBJ(hpen));
+       ::MoveToEx(mInteropHDC, x1, y1, NULL);
+       ::LineTo(mInteropHDC, x2, y2);
+       ::SelectObject(mInteropHDC, old_pen);
+       ::DeleteObject(HGDIOBJ(hpen));
+    }
+    else
+    {
+       SetDrawingMode(DM_DIRECTX);
+       mRT->DrawLine(
+               D2D1::Point2F(FLOAT(x1), FLOAT(y1) + 0.5f),
+               D2D1::Point2F(FLOAT(x2), FLOAT(y2) + 0.5f),
+               SolidBrush(color));
+    }
+}
+
+    void
+DWriteContext::SetPixel(int x, int y, COLORREF color)
+{
+    if (mDMode == DM_INTEROP)
+    {
+       // GDI functions are used before this call.  Keep using GDI.
+       // (Switching to Direct2D causes terrible slowdown.)
+       ::SetPixel(mInteropHDC, x, y, color);
+    }
+    else
+    {
+       SetDrawingMode(DM_DIRECTX);
+       // Direct2D doesn't have SetPixel API.  Use DrawLine instead.
+       mRT->DrawLine(
+               D2D1::Point2F(FLOAT(x), FLOAT(y) + 0.5f),
+               D2D1::Point2F(FLOAT(x+1), FLOAT(y) + 0.5f),
+               SolidBrush(color));
     }
 }
 
+    void
+DWriteContext::Flush()
+{
+    SetDrawingMode(DM_GDI);
+}
+
     void
 DWriteContext::SetRenderingParams(
        const DWriteRenderingParams *params)
@@ -1000,7 +1170,7 @@ DWriteContext_Open(void)
 }
 
     void
-DWriteContext_BindDC(DWriteContext *ctx, HDC hdc, RECT *rect)
+DWriteContext_BindDC(DWriteContext *ctx, HDC hdc, const RECT *rect)
 {
     if (ctx != NULL)
        ctx->BindDC(hdc, rect);
@@ -1016,7 +1186,7 @@ DWriteContext_SetFont(DWriteContext *ctx, HFONT hFont)
     void
 DWriteContext_DrawText(
        DWriteContext *ctx,
-       const WCHARtext,
+       const WCHAR *text,
        int len,
        int x,
        int y,
@@ -1025,8 +1195,8 @@ DWriteContext_DrawText(
        int cellWidth,
        COLORREF color,
        UINT fuOptions,
-       CONST RECT *lprc,
-       CONST INT * lpDx)
+       const RECT *lprc,
+       const INT *lpDx)
 {
     if (ctx != NULL)
        ctx->DrawText(text, len, x, y, w, h, cellWidth, color,
@@ -1034,12 +1204,27 @@ DWriteContext_DrawText(
 }
 
     void
-DWriteContext_FillRect(DWriteContext *ctx, RECT *rc, COLORREF color)
+DWriteContext_FillRect(DWriteContext *ctx, const RECT *rc, COLORREF color)
 {
     if (ctx != NULL)
        ctx->FillRect(rc, color);
 }
 
+    void
+DWriteContext_DrawLine(DWriteContext *ctx, int x1, int y1, int x2, int y2,
+       COLORREF color)
+{
+    if (ctx != NULL)
+       ctx->DrawLine(x1, y1, x2, y2, color);
+}
+
+    void
+DWriteContext_SetPixel(DWriteContext *ctx, int x, int y, COLORREF color)
+{
+    if (ctx != NULL)
+       ctx->SetPixel(x, y, color);
+}
+
     void
 DWriteContext_Flush(DWriteContext *ctx)
 {
index 8ab2864d852b15fa6a6eac849868ad36d5ee6a8f..9c98c4ce0dfc82d7cd50e2d9fa6d4ae224213082 100644 (file)
@@ -55,11 +55,11 @@ void DWrite_Init(void);
 void DWrite_Final(void);
 
 DWriteContext *DWriteContext_Open(void);
-void DWriteContext_BindDC(DWriteContext *ctx, HDC hdc, RECT *rect);
+void DWriteContext_BindDC(DWriteContext *ctx, HDC hdc, const RECT *rect);
 void DWriteContext_SetFont(DWriteContext *ctx, HFONT hFont);
 void DWriteContext_DrawText(
        DWriteContext *ctx,
-       const WCHARtext,
+       const WCHAR *text,
        int len,
        int x,
        int y,
@@ -68,9 +68,12 @@ void DWriteContext_DrawText(
        int cellWidth,
        COLORREF color,
        UINT fuOptions,
-       CONST RECT *lprc,
-       CONST INT * lpDx);
-void DWriteContext_FillRect(DWriteContext *ctx, RECT *rc, COLORREF color);
+       const RECT *lprc,
+       const INT *lpDx);
+void DWriteContext_FillRect(DWriteContext *ctx, const RECT *rc, COLORREF color);
+void DWriteContext_DrawLine(DWriteContext *ctx, int x1, int y1, int x2, int y2,
+       COLORREF color);
+void DWriteContext_SetPixel(DWriteContext *ctx, int x, int y, COLORREF color);
 void DWriteContext_Flush(DWriteContext *ctx);
 void DWriteContext_Close(DWriteContext *ctx);
 
index 521279ead929e0e1366739533af36e0ab480e33d..c3178ba5d38d5d2360f1a210c46c04fd22a8ba30 100644 (file)
@@ -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 @@ gui_mch_set_rendering_options(char_u *s)
     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 @@ gui_mch_set_rendering_options(char_u *s)
            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 @@ gui_mch_set_rendering_options(char_u *s)
        }
     }
     s_directx_enabled = dx_enable;
+    s_directx_scrlines = dx_scrlines;
 
     return OK;
 #else
@@ -283,6 +290,7 @@ typedef int UINT_PTR;
 #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 @@ _OnBlinkTimer(
        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_mch_stop_blink(void)
 {
     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 @@ gui_mch_start_blink(void)
                                                    (TIMERPROC)_OnBlinkTimer);
        blink_state = BLINK_ON;
        gui_update_cursor(TRUE, FALSE);
+       gui_mch_flush();
     }
 }
 
@@ -1730,7 +1739,6 @@ gui_mch_draw_part_cursor(
     int                h,
     guicolor_T color)
 {
-    HBRUSH     hbr;
     RECT       rc;
 
     /*
@@ -1746,14 +1754,7 @@ gui_mch_draw_part_cursor(
     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 @@ gui_mch_delete_lines(
     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 @@ gui_mch_delete_lines(
     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 @@ gui_mch_insert_lines(
     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 @@ _OnImeNotify(HWND hWnd, DWORD dwCommand, DWORD dwData UNUSED)
                }
            }
            gui_update_cursor(TRUE, FALSE);
+           gui_mch_flush();
            lResult = 0;
            break;
     }
@@ -6181,6 +6206,67 @@ RevOut( HDC s_hdc,
 }
 #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 @@ gui_mch_draw_string(
     static int unibuflen = 0;
     int                n = 0;
 #endif
-    HPEN       hpen, old_pen;
     int                y;
 
     /*
@@ -6263,11 +6348,7 @@ gui_mch_draw_string(
            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 @@ gui_mch_draw_string(
                         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 @@ gui_mch_draw_string(
        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 @@ gui_mch_flush(void)
     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);
 }
 
 
index 76f4a5cfbf68d65c14c7bb68247c6dda44c63d23..892882f33095dd8f164b09f81bdc37b150b9f516 100644 (file)
@@ -771,6 +771,8 @@ static char *(features[]) =
 
 static int included_patches[] =
 {   /* Add new patch number below this line */
+/**/
+    1369,
 /**/
     1368,
 /**/