mirror of
https://github.com/reactos/reactos.git
synced 2025-06-10 04:14:53 +00:00
[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().
This commit is contained in:
parent
d46e054368
commit
05053b6f18
1 changed files with 180 additions and 55 deletions
|
@ -143,6 +143,8 @@ TEXTMODE_BUFFER_Destroy(IN OUT PCONSOLE_SCREEN_BUFFER Buffer)
|
||||||
PCHAR_INFO
|
PCHAR_INFO
|
||||||
ConioCoordToPointer(PTEXTMODE_SCREEN_BUFFER Buff, ULONG X, ULONG Y)
|
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];
|
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
|
* Copy from one rectangle to another. We must be careful about the order of
|
||||||
* this is done, to avoid overwriting parts of the source before they are moved.
|
* operations, to avoid overwriting parts of the source before they are copied.
|
||||||
*/
|
*/
|
||||||
static VOID
|
static VOID
|
||||||
ConioMoveRegion(PTEXTMODE_SCREEN_BUFFER ScreenBuffer,
|
ConioCopyRegion(
|
||||||
PSMALL_RECT SrcRegion,
|
IN PTEXTMODE_SCREEN_BUFFER ScreenBuffer,
|
||||||
PSMALL_RECT DstRegion,
|
IN PSMALL_RECT SrcRegion,
|
||||||
PSMALL_RECT ClipRegion,
|
IN PCOORD DstOrigin)
|
||||||
CHAR_INFO FillChar)
|
|
||||||
{
|
{
|
||||||
UINT Width = ConioRectWidth(SrcRegion);
|
UINT Width, Height;
|
||||||
UINT Height = ConioRectHeight(SrcRegion);
|
SHORT SY, DY;
|
||||||
INT SXOrg, SX, SY;
|
SHORT YDelta;
|
||||||
INT DXOrg, DX, DY;
|
PCHAR_INFO PtrSrc, PtrDst;
|
||||||
INT XDelta, YDelta;
|
#if 0
|
||||||
|
SHORT SXOrg, DXOrg;
|
||||||
|
SHORT SX, DX;
|
||||||
|
SHORT XDelta;
|
||||||
UINT i, j;
|
UINT i, j;
|
||||||
CHAR_INFO Cell;
|
#endif
|
||||||
PCHAR_INFO SRow, DRow;
|
|
||||||
|
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;
|
SY = SrcRegion->Top;
|
||||||
DY = DstRegion->Top;
|
DY = DstOrigin->Y;
|
||||||
YDelta = 1;
|
YDelta = 1;
|
||||||
if (SY < DY)
|
if (SY < DY)
|
||||||
{
|
{
|
||||||
/* Moving down: work from bottom up */
|
/* Moving down: work from bottom up */
|
||||||
SY = SrcRegion->Bottom;
|
SY = SrcRegion->Bottom;
|
||||||
DY = DstRegion->Bottom;
|
DY = DstOrigin->Y + (SrcRegion->Bottom - SrcRegion->Top);
|
||||||
YDelta = -1;
|
YDelta = -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if 0
|
||||||
SXOrg = SrcRegion->Left;
|
SXOrg = SrcRegion->Left;
|
||||||
DXOrg = DstRegion->Left;
|
DXOrg = DstOrigin->X;
|
||||||
XDelta = 1;
|
XDelta = 1;
|
||||||
if (SXOrg < DXOrg)
|
if (SXOrg < DXOrg)
|
||||||
{
|
{
|
||||||
/* Moving right: work from right to left */
|
/* Moving right: work from right to left */
|
||||||
SXOrg = SrcRegion->Right;
|
SXOrg = SrcRegion->Right;
|
||||||
DXOrg = DstRegion->Right;
|
DXOrg = DstOrigin->X + (SrcRegion->Right - SrcRegion->Left);
|
||||||
XDelta = -1;
|
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);
|
#if 0
|
||||||
DRow = ConioCoordToPointer(ScreenBuffer, 0, DY);
|
|
||||||
|
|
||||||
SX = SXOrg;
|
SX = SXOrg;
|
||||||
DX = DXOrg;
|
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];
|
*PtrDst = *PtrSrc;
|
||||||
if (SX >= ClipRegion->Left && SX <= ClipRegion->Right &&
|
PtrSrc += XDelta;
|
||||||
SY >= ClipRegion->Top && SY <= ClipRegion->Bottom)
|
PtrDst += XDelta;
|
||||||
{
|
|
||||||
SRow[SX] = FillChar;
|
|
||||||
}
|
|
||||||
if (DX >= ClipRegion->Left && DX <= ClipRegion->Right &&
|
|
||||||
DY >= ClipRegion->Top && DY <= ClipRegion->Bottom)
|
|
||||||
{
|
|
||||||
DRow[DX] = Cell;
|
|
||||||
}
|
|
||||||
SX += XDelta;
|
|
||||||
DX += XDelta;
|
|
||||||
}
|
}
|
||||||
SY += YDelta;
|
#else
|
||||||
DY += YDelta;
|
/* 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))
|
||||||
|
{
|
||||||
|
/* We are outside the excluded region, fill the destination */
|
||||||
|
*Ptr = FillChar;
|
||||||
|
// Ptr->Attributes &= ~COMMON_LVB_SBCSDBCS;
|
||||||
|
}
|
||||||
|
|
||||||
|
++Ptr;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// FIXME!
|
// FIXME!
|
||||||
NTSTATUS NTAPI
|
NTSTATUS NTAPI
|
||||||
ConDrvWriteConsoleInput(IN PCONSOLE Console,
|
ConDrvWriteConsoleInput(IN PCONSOLE Console,
|
||||||
|
@ -1366,24 +1456,25 @@ ConDrvSetConsoleScreenBufferSize(IN PCONSOLE Console,
|
||||||
}
|
}
|
||||||
|
|
||||||
NTSTATUS NTAPI
|
NTSTATUS NTAPI
|
||||||
ConDrvScrollConsoleScreenBuffer(IN PCONSOLE Console,
|
ConDrvScrollConsoleScreenBuffer(
|
||||||
IN PTEXTMODE_SCREEN_BUFFER Buffer,
|
IN PCONSOLE Console,
|
||||||
IN BOOLEAN Unicode,
|
IN PTEXTMODE_SCREEN_BUFFER Buffer,
|
||||||
IN PSMALL_RECT ScrollRectangle,
|
IN BOOLEAN Unicode,
|
||||||
IN BOOLEAN UseClipRectangle,
|
IN PSMALL_RECT ScrollRectangle,
|
||||||
IN PSMALL_RECT ClipRectangle OPTIONAL,
|
IN BOOLEAN UseClipRectangle,
|
||||||
IN PCOORD DestinationOrigin,
|
IN PSMALL_RECT ClipRectangle OPTIONAL,
|
||||||
IN CHAR_INFO FillChar)
|
IN PCOORD DestinationOrigin,
|
||||||
|
IN CHAR_INFO FillChar)
|
||||||
{
|
{
|
||||||
COORD CapturedDestinationOrigin;
|
COORD CapturedDestinationOrigin;
|
||||||
SMALL_RECT ScreenBuffer;
|
SMALL_RECT ScreenBuffer;
|
||||||
|
SMALL_RECT CapturedClipRectangle;
|
||||||
SMALL_RECT SrcRegion;
|
SMALL_RECT SrcRegion;
|
||||||
SMALL_RECT DstRegion;
|
SMALL_RECT DstRegion;
|
||||||
SMALL_RECT UpdateRegion;
|
SMALL_RECT UpdateRegion;
|
||||||
SMALL_RECT CapturedClipRectangle;
|
|
||||||
|
|
||||||
if (Console == NULL || Buffer == NULL || ScrollRectangle == NULL ||
|
if (Console == NULL || Buffer == NULL || ScrollRectangle == NULL ||
|
||||||
(UseClipRectangle ? ClipRectangle == NULL : FALSE) || DestinationOrigin == NULL)
|
(UseClipRectangle && (ClipRectangle == NULL)) || DestinationOrigin == NULL)
|
||||||
{
|
{
|
||||||
return STATUS_INVALID_PARAMETER;
|
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 the source was clipped on the left or top, adjust the destination accordingly */
|
||||||
if (ScrollRectangle->Left < 0)
|
if (ScrollRectangle->Left < 0)
|
||||||
{
|
|
||||||
CapturedDestinationOrigin.X -= ScrollRectangle->Left;
|
CapturedDestinationOrigin.X -= ScrollRectangle->Left;
|
||||||
}
|
|
||||||
if (ScrollRectangle->Top < 0)
|
if (ScrollRectangle->Top < 0)
|
||||||
{
|
|
||||||
CapturedDestinationOrigin.Y -= ScrollRectangle->Top;
|
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)
|
if (UseClipRectangle)
|
||||||
{
|
{
|
||||||
CapturedClipRectangle = *ClipRectangle;
|
CapturedClipRectangle = *ClipRectangle;
|
||||||
|
@ -1425,14 +1516,44 @@ ConDrvScrollConsoleScreenBuffer(IN PCONSOLE Console,
|
||||||
CapturedClipRectangle = ScreenBuffer;
|
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,
|
ConioInitRect(&DstRegion,
|
||||||
CapturedDestinationOrigin.Y,
|
CapturedDestinationOrigin.Y,
|
||||||
CapturedDestinationOrigin.X,
|
CapturedDestinationOrigin.X,
|
||||||
CapturedDestinationOrigin.Y + ConioRectHeight(&SrcRegion) - 1,
|
CapturedDestinationOrigin.Y + ConioRectHeight(&SrcRegion) - 1,
|
||||||
CapturedDestinationOrigin.X + ConioRectWidth(&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)
|
if (!Unicode)
|
||||||
{
|
{
|
||||||
|
/* Conversion from the ASCII char to the UNICODE char */
|
||||||
WCHAR tmp;
|
WCHAR tmp;
|
||||||
ConsoleOutputAnsiToUnicodeChar(Console, &tmp, &FillChar.Char.AsciiChar);
|
ConsoleOutputAnsiToUnicodeChar(Console, &tmp, &FillChar.Char.AsciiChar);
|
||||||
FillChar.Char.UnicodeChar = tmp;
|
FillChar.Char.UnicodeChar = tmp;
|
||||||
|
@ -1440,11 +1561,15 @@ ConDrvScrollConsoleScreenBuffer(IN PCONSOLE Console,
|
||||||
/* Sanitize the attribute */
|
/* Sanitize the attribute */
|
||||||
FillChar.Attributes &= ~COMMON_LVB_SBCSDBCS;
|
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)
|
if ((PCONSOLE_SCREEN_BUFFER)Buffer == Console->ActiveBuffer)
|
||||||
{
|
{
|
||||||
ConioGetUnion(&UpdateRegion, &SrcRegion, &DstRegion);
|
ConioGetUnion(&UpdateRegion, &UpdateRegion, &DstRegion);
|
||||||
if (ConioGetIntersection(&UpdateRegion, &UpdateRegion, &CapturedClipRectangle))
|
if (ConioGetIntersection(&UpdateRegion, &UpdateRegion, &CapturedClipRectangle))
|
||||||
{
|
{
|
||||||
/* Draw update region */
|
/* Draw update region */
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue