Skip to content

The ScrollRegion clip rect is almost always wrong #2174

@j4james

Description

@j4james

Environment

Windows build number: Version 10.0.18362.175
Windows Terminal version (if applicable): Commit a08666b

It has to be a build that includes PR #1807, otherwise the scrolling probably wouldn't work at all.

Steps to reproduce

The issue manifests in a number of different ways, but one of the most obvious examples looks like this:

  1. Start the conhost: Host.exe

  2. In the properties, make sure that the Screen Buffer Height is larger than the Window Height.

  3. Open a WSL bash shell.

  4. Get a directory listing, or something that fills the screen with content.

  5. Execute the following escape sequence, which sets the background color to red, and deletes 4 lines from the top of the screen:

    printf "\e[41m\e[H\e[4M"
    

Expected behavior

The contents of the window should scroll up by 4 lines, revealing 4 blank red lines at the bottom of the screen.

Actual behavior

The blank lines are black rather than red. However, if you scroll down to the very end of the buffer, you'll see the 4 red lines there instead.

I believe the problem is that the call to ScrollRegion should have been passed a clip rect matching the window/viewport, but instead was given a rect encompassing the full buffer size.

In this case, the offending code is in the DoSrvPrivateModifyLinesImpl function, which calls the ScrollRegion function via the ScrollConsoleScreenBufferWImpl method:

terminal/src/host/getset.cpp

Lines 2055 to 2063 in 0e6f290

SMALL_RECT srClip = screenEdges;
srClip.Top = cursorPosition.Y;
LOG_IF_FAILED(ServiceLocator::LocateGlobals().api.ScrollConsoleScreenBufferWImpl(screenInfo,
srScroll,
coordDestination,
srClip,
UNICODE_SPACE,
screenInfo.GetAttributes().GetLegacyAttributes()));

The screenEdges rect (with which the srClip rect is initialised), is set here:

const auto screenEdges = screenInfo.GetBufferSize().ToInclusive();

Additional examples

The IL (insert lines) escape sequence is similarly affected. When you insert lines onto the screen, anything that scrolls off the bottom of the viewport should be lost, but it's actually just scrolled into the forward buffer, so if you scroll down you can still see it.

For example, execute the sequence below, and then scroll the viewport down to reveal the LAST LINE text that was shifted off screen (it should have been erased):

printf "\e[100BLAST LINE\e[H\e[4L"

The SU (scroll up) and SD (scroll down) escape sequences almost get it right. They're using the viewport as their clip rect, but they're using an exclusive range, where the ScrollRegion function expects an inclusive range, so they're off by one.

For example, if you fill the screen with content as with the first test case, then execute the following escape sequence, which scrolls up by 4 lines:

printf "\e[41m\e[H\e[4S"

That should reveal 4 blank red lines at the bottom of the screen, but actually only 3 of them are red - the fourth red line is off screen.

So far the only command I've found that gets the clip rect correct is the RI (reverse index) sequence.

Metadata

Metadata

Assignees

Labels

Area-VTVirtual Terminal sequence supportIssue-BugIt either shouldn't be doing this or needs an investigation.Needs-Tag-FixDoesn't match tag requirementsPriority-2A description (P2)Product-ConhostFor issues in the Console codebaseResolution-Fix-CommittedFix is checked in, but it might be 3-4 weeks until a release.

Type

No type

Projects

No projects

Milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions