Repository: microsoft/terminal (language: cpp)

Issue:
Weird scrolling regression in the GDI renderer
### Windows Terminal version

Commit 75e462441d8ce2e32a363ea2f66ad3a035c50f90

### Windows build number

10.0.19044.1706

### Other Software

_No response_

### Steps to reproduce

1. Checkout commit ed27737233714dea77877624d1beeb49e2ccd36e or later.
2. Make sure you've got the GDI renderer enabled in the registry (i.e. `UseDx` is 0).
3. Build and run OpenConsole.
4. Perform a directory listing to make the viewport scroll.
5. Press enter a few times to scroll some more.

### Expected Behavior

Just normal scrolling.

### Actual Behavior

Random bits of the screen scrolling independently of each other. Here's an example of the sort of thing I end up with.

![image](https://user-images.githubusercontent.com/4181424/173161769-13c40604-05fe-4d73-9567-776203ec67f4.png)

I'm not sure how I hadn't noticed this before, but I think I've been using the DX renderer and only recently switched back to GDI (that's the only renderer that seems to be affected).

/cc @lhecker I think this might be PR #13025 again.


Discussion / hints:
Thanks for finding all these! Also, I have to confess: I think I just realized that despite the large changes to the GDI engine, I'm not sure I ever seriously tested it with `UseDx != 2`. 😨 I'll try to fix this as soon as I can.
Hmm... weird. I'm unable to reproduce the issue so far. I've tried it at 100%, 150% and 200% zoom scale. I've deleted all keys/values under `HKCU:\Console` before testing and I'm using a debug build of OpenConsole.
OK, let me try clear out my reg keys and see if I can narrow down a cause. But I can tell you my scale is 200% and I'm using a release build.
I tried deleting everything under HKCU\Console and I'm still seeing the problem. It couldn't be a Windows version thing could it? I'm assuming you're on Windows 11 and I'm still on 10.

But if you can't reproduce it, I'll try and look at the code and see if I can figure out where it's going wrong.
This could also be a difference due to our hardware. I could imagine that my Nvidia GPU might redraw the entire window according to the GDI information it has on every frame, whereas yours might strictly use the given dirty areas instead.

I do have a Windows 10 Hyper-V VM, which _seems_ to reproduce the issue.
I could've sworn that I saw "ghost characters" seldomly while scrolling slowly up and down, but they always disappeared within a split second. This makes it certainly very hard to debug. 😅
(This also explains why I didn't notice it during testing...)
I think I've found the culprit.

https://github.com/microsoft/terminal/blob/ed27737233714dea77877624d1beeb49e2ccd36e/src/renderer/gdi/paint.cpp#L124-L126

That `rcScrollLimit` used to be initialized as:

    RECT rcScrollLimit = { 0 };

But now it's not, so the left and top coordinates can end up with garbage values. I suspect it doesn't affect you because the debug build initializes everything on the stack to zero anyway.
Oh nice find! I actually tried it with a Release build as well...
I'll try to see if I can automate searching the large diff for similar mistakes somehow.
And I'll submit a PR for it as soon as possible. (I'll add you as `Co-Authored-By` if you don't mind. 🙂)

Fix patch:
diff --git a/src/interactivity/win32/WindowIme.cpp b/src/interactivity/win32/WindowIme.cpp
index 3fbfb6e5225..7bb29b76e81 100644
--- a/src/interactivity/win32/WindowIme.cpp
+++ b/src/interactivity/win32/WindowIme.cpp
@@ -42,7 +42,7 @@ RECT GetImeSuggestionWindowPos()
     ClientToScreen(ServiceLocator::LocateConsoleWindow()->GetWindowHandle(), &ptSuggestion);
 
     // Move into suggestion rectangle.
-    RECT rcSuggestion;
+    RECT rcSuggestion{};
     rcSuggestion.top = rcSuggestion.bottom = ptSuggestion.y;
     rcSuggestion.left = rcSuggestion.right = ptSuggestion.x;
 
diff --git a/src/interactivity/win32/window.cpp b/src/interactivity/win32/window.cpp
index b6c025b33b1..1b9209992c5 100644
--- a/src/interactivity/win32/window.cpp
+++ b/src/interactivity/win32/window.cpp
@@ -999,7 +999,7 @@ void Window::s_CalculateWindowRect(const til::size coordWindowInChars,
 
 til::rect Window::GetWindowRect() const noexcept
 {
-    RECT rc;
+    RECT rc{};
     ::GetWindowRect(GetWindowHandle(), &rc);
     return til::rect{ rc };
 }
diff --git a/src/renderer/dx/DxRenderer.cpp b/src/renderer/dx/DxRenderer.cpp
index 46749162d3c..386c8fb7925 100644
--- a/src/renderer/dx/DxRenderer.cpp
+++ b/src/renderer/dx/DxRenderer.cpp
@@ -640,7 +640,7 @@ try
         case SwapChainMode::ForHwnd:
         {
             // use the HWND's dimensions for the swap chain dimensions.
-            RECT rect;
+            RECT rect{};
             RETURN_IF_WIN32_BOOL_FALSE(GetClientRect(_hwndTarget, &rect));
 
             _swapChainDesc.Width = rect.right - rect.left;
@@ -1222,7 +1222,7 @@ CATCH_RETURN();
     {
     case SwapChainMode::ForHwnd:
     {
-        RECT clientRect;
+        RECT clientRect{};
         LOG_IF_WIN32_BOOL_FALSE(GetClientRect(_hwndTarget, &clientRect));
 
         return til::rect{ clientRect }.size();
diff --git a/src/renderer/gdi/paint.cpp b/src/renderer/gdi/paint.cpp
index ab4a38383fa..2f067fc5a1a 100644
--- a/src/renderer/gdi/paint.cpp
+++ b/src/renderer/gdi/paint.cpp
@@ -121,7 +121,7 @@ bool GdiEngine::FontHasWesternScript(HDC hdc)
     szGutter.cx = _szMemorySurface.cx % coordFontSize.X;
     szGutter.cy = _szMemorySurface.cy % coordFontSize.Y;
 
-    RECT rcScrollLimit;
+    RECT rcScrollLimit{};
     RETURN_IF_FAILED(LongSub(_szMemorySurface.cx, szGutter.cx, &rcScrollLimit.right));
     RETURN_IF_FAILED(LongSub(_szMemorySurface.cy, szGutter.cy, &rcScrollLimit.bottom));
 
diff --git a/src/renderer/gdi/state.cpp b/src/renderer/gdi/state.cpp
index ced04328a0d..f2da4bc0f6f 100644
--- a/src/renderer/gdi/state.cpp
+++ b/src/renderer/gdi/state.cpp
@@ -147,7 +147,7 @@ GdiEngine::~GdiEngine()
 #if DBG
     if (_debugWindow != INVALID_HANDLE_VALUE && _debugWindow != nullptr)
     {
-        RECT rc;
+        RECT rc{};
         THROW_IF_WIN32_BOOL_FALSE(GetWindowRect(_hwndTargetWindow, &rc));
 
         THROW_IF_WIN32_BOOL_FALSE(SetWindowPos(_debugWindow, nullptr, 0, 0, rc.right - rc.left, rc.bottom - rc.top, SWP_NOMOVE));


Test patch: