Patch 8.0.1369
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)
Files:      runtime/doc/options.txt, src/gui_dwrite.cpp, src/gui_dwrite.h,
            src/gui_w32.c


*** ../vim-8.0.1368/runtime/doc/options.txt     2017-12-01 20:35:54.864077110 
+0100
--- runtime/doc/options.txt     2017-12-05 13:18:55.511425089 +0100
***************
*** 6017,6025 ****
                  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
--- 6122,6131 ----
                  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 (except for scrlines):
!                 https://msdn.microsoft.com/en-us/library/dd368190.aspx
  
                For geom: structure of a device pixel.
                  0 - DWRITE_PIXEL_GEOMETRY_FLAT
***************
*** 6027,6033 ****
                  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
--- 6133,6139 ----
                  2 - DWRITE_PIXEL_GEOMETRY_BGR
  
                See this URL for detail:
!                 https://msdn.microsoft.com/en-us/library/dd368114.aspx
  
                For renmode: method of rendering glyphs.
                  0 - DWRITE_RENDERING_MODE_DEFAULT
***************
*** 6039,6045 ****
                  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
--- 6145,6151 ----
                  6 - DWRITE_RENDERING_MODE_OUTLINE
  
                See this URL for detail:
!                 https://msdn.microsoft.com/en-us/library/dd368118.aspx
  
                For taamode: antialiasing mode used for drawing text.
                  0 - D2D1_TEXT_ANTIALIAS_MODE_DEFAULT
***************
*** 6048,6054 ****
                  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
--- 6154,6178 ----
                  3 - D2D1_TEXT_ANTIALIAS_MODE_ALIASED
  
                See this URL for detail:
!                 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
***************
*** 6057,6069 ****
  <
                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.
  
                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
                    special made fonts (True-Type fonts which includes only
                    bitmap glyphs).
                  - 'taamode:3' will not work with some vector fonts.
--- 6181,6192 ----
  <
                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.
  
                NOTE: It is known that some fonts and options combination
                causes trouble on drawing glyphs.
  
!                 - '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.
*** ../vim-8.0.1368/src/gui_dwrite.cpp  2017-11-26 14:29:24.847931598 +0100
--- src/gui_dwrite.cpp  2017-12-05 13:18:55.511425089 +0100
***************
*** 263,276 ****
--- 263,286 ----
      }
  };
  
+ 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,297 ****
--- 302,311 ----
  
      virtual ~DWriteContext();
  
+     HRESULT CreateDeviceResources();
+ 
+     void DiscardDeviceResources();
+ 
      HRESULT CreateTextFormatFromLOGFONT(const LOGFONTW &logFont,
            IDWriteTextFormat **ppTextFormat);
  
***************
*** 299,315 ****
  
      void SetFont(HFONT hFont);
  
!     void BindDC(HDC hdc, RECT *rect);
  
!     void AssureDrawing();
  
      ID2D1Brush* SolidBrush(COLORREF color);
  
!     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);
  
!     void FillRect(RECT *rc, COLORREF color);
  
      void Flush();
  
--- 313,333 ----
  
      void SetFont(HFONT hFont);
  
!     void BindDC(HDC hdc, const RECT *rect);
  
!     HRESULT SetDrawingMode(DrawingMode mode);
  
      ID2D1Brush* SolidBrush(COLORREF color);
  
!     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);
  
!     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,570 ****
--- 579,592 ----
  
  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,608 ****
      _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))
      {
--- 606,612 ----
      _RPT2(_CRT_WARN, "D2D1CreateFactory: hr=%p p=%p\n", hr, mD2D1Factory);
  
      if (SUCCEEDED(hr))
!       hr = CreateDeviceResources();
  
      if (SUCCEEDED(hr))
      {
***************
*** 645,655 ****
--- 649,715 ----
      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,843 ****
        item.pTextFormat = mTextFormat;
        item.fontWeight = mFontWeight;
        item.fontStyle = mFontStyle;
      }
      mFontCache.put(item);
  }
  
      void
! DWriteContext::BindDC(HDC hdc, RECT *rect)
  {
      Flush();
      mRT->BindDC(hdc, rect);
      mRT->SetTransform(D2D1::IdentityMatrix());
      mHDC = hdc;
  }
  
!     void
! DWriteContext::AssureDrawing()
  {
!     if (mDrawing == false)
      {
!       mRT->BeginDraw();
!       mDrawing = true;
      }
  }
  
      ID2D1Brush*
--- 877,953 ----
        item.pTextFormat = mTextFormat;
        item.fontWeight = mFontWeight;
        item.fontStyle = mFontStyle;
+       mFallbackDC = false;
      }
+     else
+       mFallbackDC = true;
      mFontCache.put(item);
  }
  
      void
! DWriteContext::BindDC(HDC hdc, const RECT *rect)
  {
      Flush();
      mRT->BindDC(hdc, rect);
      mRT->SetTransform(D2D1::IdentityMatrix());
      mHDC = hdc;
+     mBindRect = *rect;
  }
  
!     HRESULT
! DWriteContext::SetDrawingMode(DrawingMode mode)
  {
!     HRESULT hr = S_OK;
! 
!     switch (mode)
      {
!       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,870 ****
  }
  
      void
! 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)
  {
      if (mFallbackDC)
      {
!       Flush();
!       ExtTextOutW(mHDC, x, y, fuOptions, lprc, text, len, lpDx);
        return;
      }
  
-     AssureDrawing();
- 
      HRESULT hr;
      IDWriteTextLayout *textLayout = NULL;
  
      hr = mDWriteFactory->CreateTextLayout(text, len, mTextFormat,
            FLOAT(w), FLOAT(h), &textLayout);
  
--- 959,989 ----
  }
  
      void
! 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)
  {
      if (mFallbackDC)
      {
!       // 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;
      }
  
      HRESULT hr;
      IDWriteTextLayout *textLayout = NULL;
  
+     SetDrawingMode(DM_DIRECTX);
+ 
      hr = mDWriteFactory->CreateTextLayout(text, len, mTextFormat,
            FLOAT(w), FLOAT(h), &textLayout);
  
***************
*** 883,908 ****
  }
  
      void
! DWriteContext::FillRect(RECT *rc, COLORREF color)
  {
!     AssureDrawing();
!     mRT->FillRectangle(
!           D2D1::RectF(FLOAT(rc->left), FLOAT(rc->top),
!               FLOAT(rc->right), FLOAT(rc->bottom)),
!           SolidBrush(color));
  }
  
      void
! DWriteContext::Flush()
  {
!     if (mDrawing)
      {
!       mRT->EndDraw();
!       mDrawing = false;
      }
  }
  
      void
  DWriteContext::SetRenderingParams(
        const DWriteRenderingParams *params)
  {
--- 1002,1078 ----
  }
  
      void
! DWriteContext::FillRect(const RECT *rc, COLORREF 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::DrawLine(int x1, int y1, int x2, int y2, COLORREF color)
  {
!     if (mDMode == DM_INTEROP)
      {
!       // 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,1006 ****
  }
  
      void
! DWriteContext_BindDC(DWriteContext *ctx, HDC hdc, RECT *rect)
  {
      if (ctx != NULL)
        ctx->BindDC(hdc, rect);
--- 1170,1176 ----
  }
  
      void
! DWriteContext_BindDC(DWriteContext *ctx, HDC hdc, const RECT *rect)
  {
      if (ctx != NULL)
        ctx->BindDC(hdc, rect);
***************
*** 1016,1022 ****
      void
  DWriteContext_DrawText(
        DWriteContext *ctx,
!       const WCHAR* text,
        int len,
        int x,
        int y,
--- 1186,1192 ----
      void
  DWriteContext_DrawText(
        DWriteContext *ctx,
!       const WCHAR *text,
        int len,
        int x,
        int y,
***************
*** 1025,1032 ****
        int cellWidth,
        COLORREF color,
        UINT fuOptions,
!       CONST RECT *lprc,
!       CONST INT * lpDx)
  {
      if (ctx != NULL)
        ctx->DrawText(text, len, x, y, w, h, cellWidth, color,
--- 1195,1202 ----
        int cellWidth,
        COLORREF color,
        UINT fuOptions,
!       const RECT *lprc,
!       const INT *lpDx)
  {
      if (ctx != NULL)
        ctx->DrawText(text, len, x, y, w, h, cellWidth, color,
***************
*** 1034,1046 ****
  }
  
      void
! DWriteContext_FillRect(DWriteContext *ctx, RECT *rc, COLORREF color)
  {
      if (ctx != NULL)
        ctx->FillRect(rc, color);
  }
  
      void
  DWriteContext_Flush(DWriteContext *ctx)
  {
      if (ctx != NULL)
--- 1204,1231 ----
  }
  
      void
! 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)
  {
      if (ctx != NULL)
*** ../vim-8.0.1368/src/gui_dwrite.h    2017-11-26 14:29:24.847931598 +0100
--- src/gui_dwrite.h    2017-12-05 13:18:55.511425089 +0100
***************
*** 55,65 ****
  void DWrite_Final(void);
  
  DWriteContext *DWriteContext_Open(void);
! void DWriteContext_BindDC(DWriteContext *ctx, HDC hdc, RECT *rect);
  void DWriteContext_SetFont(DWriteContext *ctx, HFONT hFont);
  void DWriteContext_DrawText(
        DWriteContext *ctx,
!       const WCHAR* text,
        int len,
        int x,
        int y,
--- 55,65 ----
  void DWrite_Final(void);
  
  DWriteContext *DWriteContext_Open(void);
! void DWriteContext_BindDC(DWriteContext *ctx, HDC hdc, const RECT *rect);
  void DWriteContext_SetFont(DWriteContext *ctx, HFONT hFont);
  void DWriteContext_DrawText(
        DWriteContext *ctx,
!       const WCHAR *text,
        int len,
        int x,
        int y,
***************
*** 68,76 ****
        int cellWidth,
        COLORREF color,
        UINT fuOptions,
!       CONST RECT *lprc,
!       CONST INT * lpDx);
! void DWriteContext_FillRect(DWriteContext *ctx, RECT *rc, COLORREF color);
  void DWriteContext_Flush(DWriteContext *ctx);
  void DWriteContext_Close(DWriteContext *ctx);
  
--- 68,79 ----
        int cellWidth,
        COLORREF color,
        UINT fuOptions,
!       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);
  
*** ../vim-8.0.1368/src/gui_w32.c       2017-11-27 23:24:04.837331762 +0100
--- src/gui_w32.c       2017-12-05 13:18:55.511425089 +0100
***************
*** 33,38 ****
--- 33,39 ----
  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,62 ****
--- 58,64 ----
      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,122 ****
--- 119,128 ----
            if (dx_taamode < 0 || dx_taamode > 3)
                return FAIL;
        }
+       else if (STRCMP(name, "scrlines") == 0)
+       {
+           dx_scrlines = atoi((char *)value);
+       }
        else
            return FAIL;
      }
***************
*** 147,152 ****
--- 153,159 ----
        }
      }
      s_directx_enabled = dx_enable;
+     s_directx_scrlines = dx_scrlines;
  
      return OK;
  #else
***************
*** 283,288 ****
--- 290,296 ----
  #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,614 ****
        blink_timer = (UINT) SetTimer(NULL, 0, (UINT)blink_ontime,
                                                    (TIMERPROC)_OnBlinkTimer);
      }
! #if defined(FEAT_DIRECTX)
!     if (IS_ENABLE_DIRECTX())
!       DWriteContext_Flush(s_dwc);
! #endif
  }
  
      static void
--- 613,619 ----
        blink_timer = (UINT) SetTimer(NULL, 0, (UINT)blink_ontime,
                                                    (TIMERPROC)_OnBlinkTimer);
      }
!     gui_mch_flush();
  }
  
      static void
***************
*** 634,640 ****
--- 639,648 ----
  {
      gui_mswin_rm_blink_timer();
      if (blink_state == BLINK_OFF)
+     {
        gui_update_cursor(TRUE, FALSE);
+       gui_mch_flush();
+     }
      blink_state = BLINK_NONE;
  }
  
***************
*** 654,659 ****
--- 662,668 ----
                                                    (TIMERPROC)_OnBlinkTimer);
        blink_state = BLINK_ON;
        gui_update_cursor(TRUE, FALSE);
+       gui_mch_flush();
      }
  }
  
***************
*** 1730,1736 ****
      int               h,
      guicolor_T        color)
  {
-     HBRUSH    hbr;
      RECT      rc;
  
      /*
--- 1739,1744 ----
***************
*** 1746,1759 ****
      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);
  }
  
  
--- 1754,1760 ----
      rc.right = rc.left + w;
      rc.bottom = rc.top + h;
  
!     fill_rect(&rc, NULL, color);
  }
  
  
***************
*** 3122,3134 ****
      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);
  #endif
  
      rc.left = FILL_X(gui.scroll_region_left);
--- 3123,3130 ----
      int           num_lines)
  {
      RECT      rc;
  #if defined(FEAT_DIRECTX)
!     int               use_redraw = 0;
  #endif
  
      rc.left = FILL_X(gui.scroll_region_left);
***************
*** 3136,3143 ****
      rc.top = FILL_Y(row);
      rc.bottom = FILL_Y(gui.scroll_region_bot + 1);
  
!     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
--- 3132,3155 ----
      rc.top = FILL_Y(row);
      rc.bottom = FILL_Y(gui.scroll_region_bot + 1);
  
! #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,3183 ****
      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);
  #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,
                                    &rc, &rc, NULL, NULL, get_scroll_flags());
  
      UpdateWindow(s_textArea);
  
--- 3173,3207 ----
      int               num_lines)
  {
      RECT      rc;
  #if defined(FEAT_DIRECTX)
!     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);
! 
! #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,5858 ****
--- 5877,5883 ----
                }
            }
            gui_update_cursor(TRUE, FALSE);
+           gui_mch_flush();
            lResult = 0;
            break;
      }
***************
*** 6181,6186 ****
--- 6206,6272 ----
  }
  #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,6206 ****
      static int        unibuflen = 0;
      int               n = 0;
  #endif
-     HPEN      hpen, old_pen;
      int               y;
  
      /*
--- 6286,6291 ----
***************
*** 6263,6273 ****
            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);
  
        SetBkMode(s_hdc, TRANSPARENT);
  
--- 6348,6354 ----
            brush_lru = !brush_lru;
        }
  
!       fill_rect(&rc, hbr, gui.currBgColor);
  
        SetBkMode(s_hdc, TRANSPARENT);
  
***************
*** 6462,6499 ****
                         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));
      }
  
      /* 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));
      }
  
      /* Undercurl */
--- 6543,6564 ----
                         foptions, pcliprect, (char *)text, len, padding);
      }
  
      /* Underline */
      if (flags & DRAW_UNDERL)
      {
        /* 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;
!       draw_line(FILL_X(col), y, FILL_X(col + len), y, gui.currFgColor);
      }
  
      /* Strikethrough */
      if (flags & DRAW_STRIKE)
      {
        y = FILL_Y(row + 1) - gui.char_height/2;
!       draw_line(FILL_X(col), y, FILL_X(col + len), y, gui.currSpColor);
      }
  
      /* Undercurl */
***************
*** 6507,6513 ****
        for (x = FILL_X(col); x < FILL_X(col + len); ++x)
        {
            offset = val[x % 8];
!           SetPixel(s_hdc, x, y - offset, gui.currSpColor);
        }
      }
  }
--- 6572,6578 ----
        for (x = FILL_X(col); x < FILL_X(col + len); ++x)
        {
            offset = val[x % 8];
!           set_pixel(x, y - offset, gui.currSpColor);
        }
      }
  }
***************
*** 6541,6559 ****
      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);
  }
  
  
--- 6606,6612 ----
      static void
  clear_rect(RECT *rcp)
  {
!     fill_rect(rcp, NULL, gui.back_pixel);
  }
  
  
*** ../vim-8.0.1368/src/version.c       2017-12-05 13:06:12.279454348 +0100
--- src/version.c       2017-12-05 13:19:34.047220806 +0100
***************
*** 773,774 ****
--- 773,776 ----
  {   /* Add new patch number below this line */
+ /**/
+     1369,
  /**/

-- 
hundred-and-one symptoms of being an internet addict:
81. At social functions you introduce your husband as "my domain server."

 /// Bram Moolenaar -- [email protected] -- http://www.Moolenaar.net   \\\
///        sponsor Vim, vote for features -- http://www.Vim.org/sponsor/ \\\
\\\  an exciting new programming language -- http://www.Zimbu.org        ///
 \\\            help me help AIDS victims -- http://ICCF-Holland.org    ///

-- 
-- 
You received this message from the "vim_dev" maillist.
Do not top-post! Type your reply below the text you are replying to.
For more information, visit http://www.vim.org/maillist.php

--- 
You received this message because you are subscribed to the Google Groups 
"vim_dev" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to [email protected].
For more options, visit https://groups.google.com/d/optout.

Raspunde prin e-mail lui