https://git.reactos.org/?p=reactos.git;a=commitdiff;h=05053b6f18246a91aab8ba20ee456cef66996e3d

commit 05053b6f18246a91aab8ba20ee456cef66996e3d
Author:     Hermès Bélusca-Maïto <[email protected]>
AuthorDate: Sat Feb 22 19:18:44 2020 +0100
Commit:     Hermès Bélusca-Maïto <[email protected]>
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 */

Reply via email to