https://git.reactos.org/?p=reactos.git;a=commitdiff;h=05053b6f18246a91aab8b…
commit 05053b6f18246a91aab8ba20ee456cef66996e3d
Author: Hermès Bélusca-Maïto <hermes.belusca-maito(a)reactos.org>
AuthorDate: Sat Feb 22 19:18:44 2020 +0100
Commit: Hermès Bélusca-Maïto <hermes.belusca-maito(a)reactos.org>
CommitDate: Sat Feb 22 19:50:18 2020 +0100
[CONSRV] ConDrvScrollConsoleScreenBuffer() fixes. (#2278)
- Reimplement ConDrvScrollConsoleScreenBuffer() with separate copy and
fill helper functions and calculate rectangles in such a way as to
never use X-Y coordinates pointing outside of the screen buffer.
- Add X-Y coordinates assertions in ConioCoordToPointer().
---
win32ss/user/winsrv/consrv/condrv/text.c | 231 ++++++++++++++++++++++++-------
1 file changed, 178 insertions(+), 53 deletions(-)
diff --git a/win32ss/user/winsrv/consrv/condrv/text.c
b/win32ss/user/winsrv/consrv/condrv/text.c
index 6f52d8c41c5..7108fcfdcc9 100644
--- a/win32ss/user/winsrv/consrv/condrv/text.c
+++ b/win32ss/user/winsrv/consrv/condrv/text.c
@@ -143,6 +143,8 @@ TEXTMODE_BUFFER_Destroy(IN OUT PCONSOLE_SCREEN_BUFFER Buffer)
PCHAR_INFO
ConioCoordToPointer(PTEXTMODE_SCREEN_BUFFER Buff, ULONG X, ULONG Y)
{
+ ASSERT(X < Buff->ScreenBufferSize.X);
+ ASSERT(Y < Buff->ScreenBufferSize.Y);
return &Buff->Buffer[((Y + Buff->VirtualY) % Buff->ScreenBufferSize.Y) *
Buff->ScreenBufferSize.X + X];
}
@@ -185,78 +187,166 @@ ConioComputeUpdateRect(IN PTEXTMODE_SCREEN_BUFFER Buff,
}
/*
- * Move from one rectangle to another. We must be careful about the order that
- * this is done, to avoid overwriting parts of the source before they are moved.
+ * Copy from one rectangle to another. We must be careful about the order of
+ * operations, to avoid overwriting parts of the source before they are copied.
*/
static VOID
-ConioMoveRegion(PTEXTMODE_SCREEN_BUFFER ScreenBuffer,
- PSMALL_RECT SrcRegion,
- PSMALL_RECT DstRegion,
- PSMALL_RECT ClipRegion,
- CHAR_INFO FillChar)
+ConioCopyRegion(
+ IN PTEXTMODE_SCREEN_BUFFER ScreenBuffer,
+ IN PSMALL_RECT SrcRegion,
+ IN PCOORD DstOrigin)
{
- UINT Width = ConioRectWidth(SrcRegion);
- UINT Height = ConioRectHeight(SrcRegion);
- INT SXOrg, SX, SY;
- INT DXOrg, DX, DY;
- INT XDelta, YDelta;
+ UINT Width, Height;
+ SHORT SY, DY;
+ SHORT YDelta;
+ PCHAR_INFO PtrSrc, PtrDst;
+#if 0
+ SHORT SXOrg, DXOrg;
+ SHORT SX, DX;
+ SHORT XDelta;
UINT i, j;
- CHAR_INFO Cell;
- PCHAR_INFO SRow, DRow;
+#endif
+
+ if (ConioIsRectEmpty(SrcRegion))
+ return;
+
+#if 0
+ ASSERT(SrcRegion->Left >= 0 && SrcRegion->Left <
ScreenBuffer->ScreenBufferSize.X);
+ ASSERT(SrcRegion->Right >= 0 && SrcRegion->Right <
ScreenBuffer->ScreenBufferSize.X);
+ ASSERT(SrcRegion->Top >= 0 && SrcRegion->Top <
ScreenBuffer->ScreenBufferSize.Y);
+ ASSERT(SrcRegion->Bottom >= 0 && SrcRegion->Bottom <
ScreenBuffer->ScreenBufferSize.Y);
+ // ASSERT(DstOrigin->X >= 0 && DstOrigin->X <
ScreenBuffer->ScreenBufferSize.X);
+ // ASSERT(DstOrigin->Y >= 0 && DstOrigin->Y <
ScreenBuffer->ScreenBufferSize.Y);
+#endif
+
+ /* If the source and destination regions are the same, just bail out */
+ if ((SrcRegion->Left == DstOrigin->X) && (SrcRegion->Top ==
DstOrigin->Y))
+ return;
SY = SrcRegion->Top;
- DY = DstRegion->Top;
+ DY = DstOrigin->Y;
YDelta = 1;
if (SY < DY)
{
/* Moving down: work from bottom up */
SY = SrcRegion->Bottom;
- DY = DstRegion->Bottom;
+ DY = DstOrigin->Y + (SrcRegion->Bottom - SrcRegion->Top);
YDelta = -1;
}
+#if 0
SXOrg = SrcRegion->Left;
- DXOrg = DstRegion->Left;
+ DXOrg = DstOrigin->X;
XDelta = 1;
if (SXOrg < DXOrg)
{
/* Moving right: work from right to left */
SXOrg = SrcRegion->Right;
- DXOrg = DstRegion->Right;
+ DXOrg = DstOrigin->X + (SrcRegion->Right - SrcRegion->Left);
XDelta = -1;
}
+#endif
- for (i = 0; i < Height; i++)
+ /* Loop through the source region */
+ Width = ConioRectWidth(SrcRegion);
+ Height = ConioRectHeight(SrcRegion);
+#if 0
+ for (i = 0; i < Height; ++i, SY += YDelta, DY += YDelta)
+#else
+ for (; Height-- > 0; SY += YDelta, DY += YDelta)
+#endif
{
- SRow = ConioCoordToPointer(ScreenBuffer, 0, SY);
- DRow = ConioCoordToPointer(ScreenBuffer, 0, DY);
-
+#if 0
SX = SXOrg;
DX = DXOrg;
- // TODO: Correctly support "moving" full-width characters.
+ PtrSrc = ConioCoordToPointer(ScreenBuffer, SX, SY);
+ PtrDst = ConioCoordToPointer(ScreenBuffer, DX, DY);
+#else
+ PtrSrc = ConioCoordToPointer(ScreenBuffer, SrcRegion->Left, SY);
+ PtrDst = ConioCoordToPointer(ScreenBuffer, DstOrigin->X, DY);
+#endif
- for (j = 0; j < Width; j++)
+ // TODO: Correctly support copying full-width characters.
+ // By construction the source region is supposed to contain valid
+ // (possibly fullwidth) characters, so for these after the copy
+ // we need to check the characters at the borders and adjust the
+ // attributes accordingly.
+
+#if 0
+ for (j = 0; j < Width; ++j, SX += XDelta, DX += XDelta)
{
- Cell = SRow[SX];
- if (SX >= ClipRegion->Left && SX <= ClipRegion->Right
&&
- SY >= ClipRegion->Top && SY <= ClipRegion->Bottom)
- {
- SRow[SX] = FillChar;
- }
- if (DX >= ClipRegion->Left && DX <= ClipRegion->Right
&&
- DY >= ClipRegion->Top && DY <= ClipRegion->Bottom)
+ *PtrDst = *PtrSrc;
+ PtrSrc += XDelta;
+ PtrDst += XDelta;
+ }
+#else
+ /* RtlMoveMemory() takes into account for the direction of the copy */
+ RtlMoveMemory(PtrDst, PtrSrc, Width * sizeof(CHAR_INFO));
+#endif
+ }
+}
+
+static VOID
+ConioFillRegion(
+ IN PTEXTMODE_SCREEN_BUFFER ScreenBuffer,
+ IN PSMALL_RECT Region,
+ IN PSMALL_RECT ExcludeRegion OPTIONAL,
+ IN CHAR_INFO FillChar)
+{
+ SHORT X, Y;
+ PCHAR_INFO Ptr;
+ // BOOLEAN bFullwidth;
+
+ /* Bail out if the region to fill is empty */
+ if (ConioIsRectEmpty(Region))
+ return;
+
+ /* Sanitize the exclusion region: if it's empty, ignore the region */
+ if (ExcludeRegion && ConioIsRectEmpty(ExcludeRegion))
+ ExcludeRegion = NULL;
+
+#if 0
+ ASSERT(Region->Left >= 0 && Region->Left <
ScreenBuffer->ScreenBufferSize.X);
+ ASSERT(Region->Right >= 0 && Region->Right <
ScreenBuffer->ScreenBufferSize.X);
+ ASSERT(Region->Top >= 0 && Region->Top <
ScreenBuffer->ScreenBufferSize.Y);
+ ASSERT(Region->Bottom >= 0 && Region->Bottom <
ScreenBuffer->ScreenBufferSize.Y);
+
+ if (ExcludeRegion)
+ {
+ ASSERT(ExcludeRegion->Left >= 0 && ExcludeRegion->Left <
ScreenBuffer->ScreenBufferSize.X);
+ ASSERT(ExcludeRegion->Right >= 0 && ExcludeRegion->Right <
ScreenBuffer->ScreenBufferSize.X);
+ ASSERT(ExcludeRegion->Top >= 0 && ExcludeRegion->Top <
ScreenBuffer->ScreenBufferSize.Y);
+ ASSERT(ExcludeRegion->Bottom >= 0 && ExcludeRegion->Bottom <
ScreenBuffer->ScreenBufferSize.Y);
+ }
+#endif
+
+ // bFullwidth = (ScreenBuffer->Header.Console->IsCJK &&
IS_FULL_WIDTH(FillChar.Char.UnicodeChar));
+
+ /* Loop through the destination region */
+ for (Y = Region->Top; Y <= Region->Bottom; ++Y)
+ {
+ Ptr = ConioCoordToPointer(ScreenBuffer, Region->Left, Y);
+ for (X = Region->Left; X <= Region->Right; ++X)
+ {
+ // TODO: Correctly support filling with full-width characters.
+
+ if (!ExcludeRegion ||
+ !(X >= ExcludeRegion->Left && X <=
ExcludeRegion->Right &&
+ Y >= ExcludeRegion->Top && Y <=
ExcludeRegion->Bottom))
{
- DRow[DX] = Cell;
+ /* We are outside the excluded region, fill the destination */
+ *Ptr = FillChar;
+ // Ptr->Attributes &= ~COMMON_LVB_SBCSDBCS;
}
- SX += XDelta;
- DX += XDelta;
+
+ ++Ptr;
}
- SY += YDelta;
- DY += YDelta;
}
}
+
+
// FIXME!
NTSTATUS NTAPI
ConDrvWriteConsoleInput(IN PCONSOLE Console,
@@ -1366,24 +1456,25 @@ ConDrvSetConsoleScreenBufferSize(IN PCONSOLE Console,
}
NTSTATUS NTAPI
-ConDrvScrollConsoleScreenBuffer(IN PCONSOLE Console,
- IN PTEXTMODE_SCREEN_BUFFER Buffer,
- IN BOOLEAN Unicode,
- IN PSMALL_RECT ScrollRectangle,
- IN BOOLEAN UseClipRectangle,
- IN PSMALL_RECT ClipRectangle OPTIONAL,
- IN PCOORD DestinationOrigin,
- IN CHAR_INFO FillChar)
+ConDrvScrollConsoleScreenBuffer(
+ IN PCONSOLE Console,
+ IN PTEXTMODE_SCREEN_BUFFER Buffer,
+ IN BOOLEAN Unicode,
+ IN PSMALL_RECT ScrollRectangle,
+ IN BOOLEAN UseClipRectangle,
+ IN PSMALL_RECT ClipRectangle OPTIONAL,
+ IN PCOORD DestinationOrigin,
+ IN CHAR_INFO FillChar)
{
COORD CapturedDestinationOrigin;
SMALL_RECT ScreenBuffer;
+ SMALL_RECT CapturedClipRectangle;
SMALL_RECT SrcRegion;
SMALL_RECT DstRegion;
SMALL_RECT UpdateRegion;
- SMALL_RECT CapturedClipRectangle;
if (Console == NULL || Buffer == NULL || ScrollRectangle == NULL ||
- (UseClipRectangle ? ClipRectangle == NULL : FALSE) || DestinationOrigin == NULL)
+ (UseClipRectangle && (ClipRectangle == NULL)) || DestinationOrigin ==
NULL)
{
return STATUS_INVALID_PARAMETER;
}
@@ -1404,14 +1495,14 @@ ConDrvScrollConsoleScreenBuffer(IN PCONSOLE Console,
/* If the source was clipped on the left or top, adjust the destination accordingly
*/
if (ScrollRectangle->Left < 0)
- {
CapturedDestinationOrigin.X -= ScrollRectangle->Left;
- }
if (ScrollRectangle->Top < 0)
- {
CapturedDestinationOrigin.Y -= ScrollRectangle->Top;
- }
+ /*
+ * If a clip rectangle is provided, clip it to the screen buffer,
+ * otherwise use the latter one as the clip rectangle.
+ */
if (UseClipRectangle)
{
CapturedClipRectangle = *ClipRectangle;
@@ -1425,14 +1516,44 @@ ConDrvScrollConsoleScreenBuffer(IN PCONSOLE Console,
CapturedClipRectangle = ScreenBuffer;
}
+ /*
+ * Windows compatibility: Do nothing if the intersection of the source region
+ * with the clip rectangle is empty, even if the intersection of destination
+ * region with the clip rectangle is NOT empty and therefore it would have
+ * been possible to copy contents to it...
+ */
+ if (!ConioGetIntersection(&UpdateRegion, &SrcRegion,
&CapturedClipRectangle))
+ {
+ return STATUS_SUCCESS;
+ }
+
+ /* Initialize the destination rectangle, of same size as the source rectangle */
ConioInitRect(&DstRegion,
CapturedDestinationOrigin.Y,
CapturedDestinationOrigin.X,
CapturedDestinationOrigin.Y + ConioRectHeight(&SrcRegion) - 1,
CapturedDestinationOrigin.X + ConioRectWidth(&SrcRegion ) - 1);
+ if (ConioGetIntersection(&DstRegion, &DstRegion,
&CapturedClipRectangle))
+ {
+ /*
+ * Build the region image, within the source region,
+ * of the destination region we should copy into.
+ */
+ SrcRegion.Left += DstRegion.Left - CapturedDestinationOrigin.X;
+ SrcRegion.Top += DstRegion.Top - CapturedDestinationOrigin.Y;
+ SrcRegion.Right = SrcRegion.Left + (DstRegion.Right - DstRegion.Left);
+ SrcRegion.Bottom = SrcRegion.Top + (DstRegion.Bottom - DstRegion.Top);
+
+ /* Do the copy */
+ CapturedDestinationOrigin.X = DstRegion.Left;
+ CapturedDestinationOrigin.Y = DstRegion.Top;
+ ConioCopyRegion(Buffer, &SrcRegion, &CapturedDestinationOrigin);
+ }
+
if (!Unicode)
{
+ /* Conversion from the ASCII char to the UNICODE char */
WCHAR tmp;
ConsoleOutputAnsiToUnicodeChar(Console, &tmp, &FillChar.Char.AsciiChar);
FillChar.Char.UnicodeChar = tmp;
@@ -1440,11 +1561,15 @@ ConDrvScrollConsoleScreenBuffer(IN PCONSOLE Console,
/* Sanitize the attribute */
FillChar.Attributes &= ~COMMON_LVB_SBCSDBCS;
- ConioMoveRegion(Buffer, &SrcRegion, &DstRegion, &CapturedClipRectangle,
FillChar);
+ /*
+ * Fill the intersection (== UpdateRegion) of the source region with the
+ * clip rectangle, excluding the destination region.
+ */
+ ConioFillRegion(Buffer, &UpdateRegion, &DstRegion, FillChar);
if ((PCONSOLE_SCREEN_BUFFER)Buffer == Console->ActiveBuffer)
{
- ConioGetUnion(&UpdateRegion, &SrcRegion, &DstRegion);
+ ConioGetUnion(&UpdateRegion, &UpdateRegion, &DstRegion);
if (ConioGetIntersection(&UpdateRegion, &UpdateRegion,
&CapturedClipRectangle))
{
/* Draw update region */