Skip to content

Commit 05053b6

Browse files
committed
[CONSRV] ConDrvScrollConsoleScreenBuffer() fixes. (reactos#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().
1 parent d46e054 commit 05053b6

File tree

1 file changed

+178
-53
lines changed
  • win32ss/user/winsrv/consrv/condrv

1 file changed

+178
-53
lines changed

win32ss/user/winsrv/consrv/condrv/text.c

Lines changed: 178 additions & 53 deletions
Original file line numberDiff line numberDiff line change
@@ -143,6 +143,8 @@ TEXTMODE_BUFFER_Destroy(IN OUT PCONSOLE_SCREEN_BUFFER Buffer)
143143
PCHAR_INFO
144144
ConioCoordToPointer(PTEXTMODE_SCREEN_BUFFER Buff, ULONG X, ULONG Y)
145145
{
146+
ASSERT(X < Buff->ScreenBufferSize.X);
147+
ASSERT(Y < Buff->ScreenBufferSize.Y);
146148
return &Buff->Buffer[((Y + Buff->VirtualY) % Buff->ScreenBufferSize.Y) * Buff->ScreenBufferSize.X + X];
147149
}
148150

@@ -185,78 +187,166 @@ ConioComputeUpdateRect(IN PTEXTMODE_SCREEN_BUFFER Buff,
185187
}
186188

187189
/*
188-
* Move from one rectangle to another. We must be careful about the order that
189-
* this is done, to avoid overwriting parts of the source before they are moved.
190+
* Copy from one rectangle to another. We must be careful about the order of
191+
* operations, to avoid overwriting parts of the source before they are copied.
190192
*/
191193
static VOID
192-
ConioMoveRegion(PTEXTMODE_SCREEN_BUFFER ScreenBuffer,
193-
PSMALL_RECT SrcRegion,
194-
PSMALL_RECT DstRegion,
195-
PSMALL_RECT ClipRegion,
196-
CHAR_INFO FillChar)
194+
ConioCopyRegion(
195+
IN PTEXTMODE_SCREEN_BUFFER ScreenBuffer,
196+
IN PSMALL_RECT SrcRegion,
197+
IN PCOORD DstOrigin)
197198
{
198-
UINT Width = ConioRectWidth(SrcRegion);
199-
UINT Height = ConioRectHeight(SrcRegion);
200-
INT SXOrg, SX, SY;
201-
INT DXOrg, DX, DY;
202-
INT XDelta, YDelta;
199+
UINT Width, Height;
200+
SHORT SY, DY;
201+
SHORT YDelta;
202+
PCHAR_INFO PtrSrc, PtrDst;
203+
#if 0
204+
SHORT SXOrg, DXOrg;
205+
SHORT SX, DX;
206+
SHORT XDelta;
203207
UINT i, j;
204-
CHAR_INFO Cell;
205-
PCHAR_INFO SRow, DRow;
208+
#endif
209+
210+
if (ConioIsRectEmpty(SrcRegion))
211+
return;
212+
213+
#if 0
214+
ASSERT(SrcRegion->Left >= 0 && SrcRegion->Left < ScreenBuffer->ScreenBufferSize.X);
215+
ASSERT(SrcRegion->Right >= 0 && SrcRegion->Right < ScreenBuffer->ScreenBufferSize.X);
216+
ASSERT(SrcRegion->Top >= 0 && SrcRegion->Top < ScreenBuffer->ScreenBufferSize.Y);
217+
ASSERT(SrcRegion->Bottom >= 0 && SrcRegion->Bottom < ScreenBuffer->ScreenBufferSize.Y);
218+
// ASSERT(DstOrigin->X >= 0 && DstOrigin->X < ScreenBuffer->ScreenBufferSize.X);
219+
// ASSERT(DstOrigin->Y >= 0 && DstOrigin->Y < ScreenBuffer->ScreenBufferSize.Y);
220+
#endif
221+
222+
/* If the source and destination regions are the same, just bail out */
223+
if ((SrcRegion->Left == DstOrigin->X) && (SrcRegion->Top == DstOrigin->Y))
224+
return;
206225

207226
SY = SrcRegion->Top;
208-
DY = DstRegion->Top;
227+
DY = DstOrigin->Y;
209228
YDelta = 1;
210229
if (SY < DY)
211230
{
212231
/* Moving down: work from bottom up */
213232
SY = SrcRegion->Bottom;
214-
DY = DstRegion->Bottom;
233+
DY = DstOrigin->Y + (SrcRegion->Bottom - SrcRegion->Top);
215234
YDelta = -1;
216235
}
217236

237+
#if 0
218238
SXOrg = SrcRegion->Left;
219-
DXOrg = DstRegion->Left;
239+
DXOrg = DstOrigin->X;
220240
XDelta = 1;
221241
if (SXOrg < DXOrg)
222242
{
223243
/* Moving right: work from right to left */
224244
SXOrg = SrcRegion->Right;
225-
DXOrg = DstRegion->Right;
245+
DXOrg = DstOrigin->X + (SrcRegion->Right - SrcRegion->Left);
226246
XDelta = -1;
227247
}
248+
#endif
228249

229-
for (i = 0; i < Height; i++)
250+
/* Loop through the source region */
251+
Width = ConioRectWidth(SrcRegion);
252+
Height = ConioRectHeight(SrcRegion);
253+
#if 0
254+
for (i = 0; i < Height; ++i, SY += YDelta, DY += YDelta)
255+
#else
256+
for (; Height-- > 0; SY += YDelta, DY += YDelta)
257+
#endif
230258
{
231-
SRow = ConioCoordToPointer(ScreenBuffer, 0, SY);
232-
DRow = ConioCoordToPointer(ScreenBuffer, 0, DY);
233-
259+
#if 0
234260
SX = SXOrg;
235261
DX = DXOrg;
236262

237-
// TODO: Correctly support "moving" full-width characters.
263+
PtrSrc = ConioCoordToPointer(ScreenBuffer, SX, SY);
264+
PtrDst = ConioCoordToPointer(ScreenBuffer, DX, DY);
265+
#else
266+
PtrSrc = ConioCoordToPointer(ScreenBuffer, SrcRegion->Left, SY);
267+
PtrDst = ConioCoordToPointer(ScreenBuffer, DstOrigin->X, DY);
268+
#endif
238269

239-
for (j = 0; j < Width; j++)
270+
// TODO: Correctly support copying full-width characters.
271+
// By construction the source region is supposed to contain valid
272+
// (possibly fullwidth) characters, so for these after the copy
273+
// we need to check the characters at the borders and adjust the
274+
// attributes accordingly.
275+
276+
#if 0
277+
for (j = 0; j < Width; ++j, SX += XDelta, DX += XDelta)
240278
{
241-
Cell = SRow[SX];
242-
if (SX >= ClipRegion->Left && SX <= ClipRegion->Right &&
243-
SY >= ClipRegion->Top && SY <= ClipRegion->Bottom)
244-
{
245-
SRow[SX] = FillChar;
246-
}
247-
if (DX >= ClipRegion->Left && DX <= ClipRegion->Right &&
248-
DY >= ClipRegion->Top && DY <= ClipRegion->Bottom)
279+
*PtrDst = *PtrSrc;
280+
PtrSrc += XDelta;
281+
PtrDst += XDelta;
282+
}
283+
#else
284+
/* RtlMoveMemory() takes into account for the direction of the copy */
285+
RtlMoveMemory(PtrDst, PtrSrc, Width * sizeof(CHAR_INFO));
286+
#endif
287+
}
288+
}
289+
290+
static VOID
291+
ConioFillRegion(
292+
IN PTEXTMODE_SCREEN_BUFFER ScreenBuffer,
293+
IN PSMALL_RECT Region,
294+
IN PSMALL_RECT ExcludeRegion OPTIONAL,
295+
IN CHAR_INFO FillChar)
296+
{
297+
SHORT X, Y;
298+
PCHAR_INFO Ptr;
299+
// BOOLEAN bFullwidth;
300+
301+
/* Bail out if the region to fill is empty */
302+
if (ConioIsRectEmpty(Region))
303+
return;
304+
305+
/* Sanitize the exclusion region: if it's empty, ignore the region */
306+
if (ExcludeRegion && ConioIsRectEmpty(ExcludeRegion))
307+
ExcludeRegion = NULL;
308+
309+
#if 0
310+
ASSERT(Region->Left >= 0 && Region->Left < ScreenBuffer->ScreenBufferSize.X);
311+
ASSERT(Region->Right >= 0 && Region->Right < ScreenBuffer->ScreenBufferSize.X);
312+
ASSERT(Region->Top >= 0 && Region->Top < ScreenBuffer->ScreenBufferSize.Y);
313+
ASSERT(Region->Bottom >= 0 && Region->Bottom < ScreenBuffer->ScreenBufferSize.Y);
314+
315+
if (ExcludeRegion)
316+
{
317+
ASSERT(ExcludeRegion->Left >= 0 && ExcludeRegion->Left < ScreenBuffer->ScreenBufferSize.X);
318+
ASSERT(ExcludeRegion->Right >= 0 && ExcludeRegion->Right < ScreenBuffer->ScreenBufferSize.X);
319+
ASSERT(ExcludeRegion->Top >= 0 && ExcludeRegion->Top < ScreenBuffer->ScreenBufferSize.Y);
320+
ASSERT(ExcludeRegion->Bottom >= 0 && ExcludeRegion->Bottom < ScreenBuffer->ScreenBufferSize.Y);
321+
}
322+
#endif
323+
324+
// bFullwidth = (ScreenBuffer->Header.Console->IsCJK && IS_FULL_WIDTH(FillChar.Char.UnicodeChar));
325+
326+
/* Loop through the destination region */
327+
for (Y = Region->Top; Y <= Region->Bottom; ++Y)
328+
{
329+
Ptr = ConioCoordToPointer(ScreenBuffer, Region->Left, Y);
330+
for (X = Region->Left; X <= Region->Right; ++X)
331+
{
332+
// TODO: Correctly support filling with full-width characters.
333+
334+
if (!ExcludeRegion ||
335+
!(X >= ExcludeRegion->Left && X <= ExcludeRegion->Right &&
336+
Y >= ExcludeRegion->Top && Y <= ExcludeRegion->Bottom))
249337
{
250-
DRow[DX] = Cell;
338+
/* We are outside the excluded region, fill the destination */
339+
*Ptr = FillChar;
340+
// Ptr->Attributes &= ~COMMON_LVB_SBCSDBCS;
251341
}
252-
SX += XDelta;
253-
DX += XDelta;
342+
343+
++Ptr;
254344
}
255-
SY += YDelta;
256-
DY += YDelta;
257345
}
258346
}
259347

348+
349+
260350
// FIXME!
261351
NTSTATUS NTAPI
262352
ConDrvWriteConsoleInput(IN PCONSOLE Console,
@@ -1366,24 +1456,25 @@ ConDrvSetConsoleScreenBufferSize(IN PCONSOLE Console,
13661456
}
13671457

13681458
NTSTATUS NTAPI
1369-
ConDrvScrollConsoleScreenBuffer(IN PCONSOLE Console,
1370-
IN PTEXTMODE_SCREEN_BUFFER Buffer,
1371-
IN BOOLEAN Unicode,
1372-
IN PSMALL_RECT ScrollRectangle,
1373-
IN BOOLEAN UseClipRectangle,
1374-
IN PSMALL_RECT ClipRectangle OPTIONAL,
1375-
IN PCOORD DestinationOrigin,
1376-
IN CHAR_INFO FillChar)
1459+
ConDrvScrollConsoleScreenBuffer(
1460+
IN PCONSOLE Console,
1461+
IN PTEXTMODE_SCREEN_BUFFER Buffer,
1462+
IN BOOLEAN Unicode,
1463+
IN PSMALL_RECT ScrollRectangle,
1464+
IN BOOLEAN UseClipRectangle,
1465+
IN PSMALL_RECT ClipRectangle OPTIONAL,
1466+
IN PCOORD DestinationOrigin,
1467+
IN CHAR_INFO FillChar)
13771468
{
13781469
COORD CapturedDestinationOrigin;
13791470
SMALL_RECT ScreenBuffer;
1471+
SMALL_RECT CapturedClipRectangle;
13801472
SMALL_RECT SrcRegion;
13811473
SMALL_RECT DstRegion;
13821474
SMALL_RECT UpdateRegion;
1383-
SMALL_RECT CapturedClipRectangle;
13841475

13851476
if (Console == NULL || Buffer == NULL || ScrollRectangle == NULL ||
1386-
(UseClipRectangle ? ClipRectangle == NULL : FALSE) || DestinationOrigin == NULL)
1477+
(UseClipRectangle && (ClipRectangle == NULL)) || DestinationOrigin == NULL)
13871478
{
13881479
return STATUS_INVALID_PARAMETER;
13891480
}
@@ -1404,14 +1495,14 @@ ConDrvScrollConsoleScreenBuffer(IN PCONSOLE Console,
14041495

14051496
/* If the source was clipped on the left or top, adjust the destination accordingly */
14061497
if (ScrollRectangle->Left < 0)
1407-
{
14081498
CapturedDestinationOrigin.X -= ScrollRectangle->Left;
1409-
}
14101499
if (ScrollRectangle->Top < 0)
1411-
{
14121500
CapturedDestinationOrigin.Y -= ScrollRectangle->Top;
1413-
}
14141501

1502+
/*
1503+
* If a clip rectangle is provided, clip it to the screen buffer,
1504+
* otherwise use the latter one as the clip rectangle.
1505+
*/
14151506
if (UseClipRectangle)
14161507
{
14171508
CapturedClipRectangle = *ClipRectangle;
@@ -1425,26 +1516,60 @@ ConDrvScrollConsoleScreenBuffer(IN PCONSOLE Console,
14251516
CapturedClipRectangle = ScreenBuffer;
14261517
}
14271518

1519+
/*
1520+
* Windows compatibility: Do nothing if the intersection of the source region
1521+
* with the clip rectangle is empty, even if the intersection of destination
1522+
* region with the clip rectangle is NOT empty and therefore it would have
1523+
* been possible to copy contents to it...
1524+
*/
1525+
if (!ConioGetIntersection(&UpdateRegion, &SrcRegion, &CapturedClipRectangle))
1526+
{
1527+
return STATUS_SUCCESS;
1528+
}
1529+
1530+
/* Initialize the destination rectangle, of same size as the source rectangle */
14281531
ConioInitRect(&DstRegion,
14291532
CapturedDestinationOrigin.Y,
14301533
CapturedDestinationOrigin.X,
14311534
CapturedDestinationOrigin.Y + ConioRectHeight(&SrcRegion) - 1,
14321535
CapturedDestinationOrigin.X + ConioRectWidth(&SrcRegion ) - 1);
14331536

1537+
if (ConioGetIntersection(&DstRegion, &DstRegion, &CapturedClipRectangle))
1538+
{
1539+
/*
1540+
* Build the region image, within the source region,
1541+
* of the destination region we should copy into.
1542+
*/
1543+
SrcRegion.Left += DstRegion.Left - CapturedDestinationOrigin.X;
1544+
SrcRegion.Top += DstRegion.Top - CapturedDestinationOrigin.Y;
1545+
SrcRegion.Right = SrcRegion.Left + (DstRegion.Right - DstRegion.Left);
1546+
SrcRegion.Bottom = SrcRegion.Top + (DstRegion.Bottom - DstRegion.Top);
1547+
1548+
/* Do the copy */
1549+
CapturedDestinationOrigin.X = DstRegion.Left;
1550+
CapturedDestinationOrigin.Y = DstRegion.Top;
1551+
ConioCopyRegion(Buffer, &SrcRegion, &CapturedDestinationOrigin);
1552+
}
1553+
14341554
if (!Unicode)
14351555
{
1556+
/* Conversion from the ASCII char to the UNICODE char */
14361557
WCHAR tmp;
14371558
ConsoleOutputAnsiToUnicodeChar(Console, &tmp, &FillChar.Char.AsciiChar);
14381559
FillChar.Char.UnicodeChar = tmp;
14391560
}
14401561
/* Sanitize the attribute */
14411562
FillChar.Attributes &= ~COMMON_LVB_SBCSDBCS;
14421563

1443-
ConioMoveRegion(Buffer, &SrcRegion, &DstRegion, &CapturedClipRectangle, FillChar);
1564+
/*
1565+
* Fill the intersection (== UpdateRegion) of the source region with the
1566+
* clip rectangle, excluding the destination region.
1567+
*/
1568+
ConioFillRegion(Buffer, &UpdateRegion, &DstRegion, FillChar);
14441569

14451570
if ((PCONSOLE_SCREEN_BUFFER)Buffer == Console->ActiveBuffer)
14461571
{
1447-
ConioGetUnion(&UpdateRegion, &SrcRegion, &DstRegion);
1572+
ConioGetUnion(&UpdateRegion, &UpdateRegion, &DstRegion);
14481573
if (ConioGetIntersection(&UpdateRegion, &UpdateRegion, &CapturedClipRectangle))
14491574
{
14501575
/* Draw update region */

0 commit comments

Comments
 (0)