/* * 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. */ static VOID ConioMoveRegion(PTEXTMODE_SCREEN_BUFFER ScreenBuffer, PSMALL_RECT SrcRegion, PSMALL_RECT DstRegion, PSMALL_RECT ClipRegion, CHAR_INFO FillChar) { int Width = ConioRectWidth(SrcRegion); int Height = ConioRectHeight(SrcRegion); int SX, SY; int DX, DY; int XDelta, YDelta; int i, j; SY = SrcRegion->Top; DY = DstRegion->Top; YDelta = 1; if (SY < DY) { /* Moving down: work from bottom up */ SY = SrcRegion->Bottom; DY = DstRegion->Bottom; YDelta = -1; } for (i = 0; i < Height; i++) { PCHAR_INFO SRow = ConioCoordToPointer(ScreenBuffer, 0, SY); PCHAR_INFO DRow = ConioCoordToPointer(ScreenBuffer, 0, DY); SX = SrcRegion->Left; DX = DstRegion->Left; XDelta = 1; if (SX < DX) { /* Moving right: work from right to left */ SX = SrcRegion->Right; DX = DstRegion->Right; XDelta = -1; } for (j = 0; j < Width; j++) { CHAR_INFO 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) { DRow[DX] = Cell; } SX += XDelta; DX += XDelta; } SY += YDelta; DY += YDelta; } }
static VOID WINAPI TuiDrawRegion(IN OUT PFRONTEND This, SMALL_RECT* Region) { DWORD BytesReturned; PCONSOLE_SCREEN_BUFFER Buff = Console->ActiveBuffer; PCONSOLE_DRAW ConsoleDraw; UINT ConsoleDrawSize; if (ActiveConsole->Console != Console || GetType(Buff) != TEXTMODE_BUFFER) return; ConsoleDrawSize = sizeof(CONSOLE_DRAW) + (ConioRectWidth(Region) * ConioRectHeight(Region)) * 2; ConsoleDraw = ConsoleAllocHeap(0, ConsoleDrawSize); if (NULL == ConsoleDraw) { DPRINT1("ConsoleAllocHeap failed\n"); return; } ConsoleDraw->X = Region->Left; ConsoleDraw->Y = Region->Top; ConsoleDraw->SizeX = ConioRectWidth(Region); ConsoleDraw->SizeY = ConioRectHeight(Region); ConsoleDraw->CursorX = Buff->CursorPosition.X; ConsoleDraw->CursorY = Buff->CursorPosition.Y; TuiCopyRect((PCHAR)(ConsoleDraw + 1), (PTEXTMODE_SCREEN_BUFFER)Buff, Region); if (!DeviceIoControl(ConsoleDeviceHandle, IOCTL_CONSOLE_DRAW, NULL, 0, ConsoleDraw, ConsoleDrawSize, &BytesReturned, NULL)) { DPRINT1("Failed to draw console\n"); ConsoleFreeHeap(ConsoleDraw); return; } ConsoleFreeHeap(ConsoleDraw); }
static VOID FASTCALL TuiCopyRect(PCHAR Dest, PTEXTMODE_SCREEN_BUFFER Buff, SMALL_RECT* Region) { UINT SrcDelta, DestDelta; LONG i; PCHAR_INFO Src, SrcEnd; Src = ConioCoordToPointer(Buff, Region->Left, Region->Top); SrcDelta = Buff->ScreenBufferSize.X * sizeof(CHAR_INFO); SrcEnd = Buff->Buffer + Buff->ScreenBufferSize.Y * Buff->ScreenBufferSize.X * sizeof(CHAR_INFO); DestDelta = ConioRectWidth(Region) * 2 /* 2 == sizeof(CHAR) + sizeof(BYTE) */; for (i = Region->Top; i <= Region->Bottom; i++) { ConsoleUnicodeCharToAnsiChar(Buff->Header.Console, (PCHAR)Dest, &Src->Char.UnicodeChar); *(PBYTE)(Dest + 1) = (BYTE)Src->Attributes; Src += SrcDelta; if (SrcEnd <= Src) { Src -= Buff->ScreenBufferSize.Y * Buff->ScreenBufferSize.X * sizeof(CHAR_INFO); } Dest += DestDelta; } }
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) { COORD CapturedDestinationOrigin; SMALL_RECT ScreenBuffer; 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) { return STATUS_INVALID_PARAMETER; } /* Validity check */ ASSERT(Console == Buffer->Header.Console); CapturedDestinationOrigin = *DestinationOrigin; /* Make sure the source rectangle is inside the screen buffer */ ConioInitRect(&ScreenBuffer, 0, 0, Buffer->ScreenBufferSize.Y - 1, Buffer->ScreenBufferSize.X - 1); if (!ConioGetIntersection(&SrcRegion, &ScreenBuffer, ScrollRectangle)) { return STATUS_SUCCESS; } /* 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 (UseClipRectangle) { CapturedClipRectangle = *ClipRectangle; if (!ConioGetIntersection(&CapturedClipRectangle, &CapturedClipRectangle, &ScreenBuffer)) { return STATUS_SUCCESS; } } else { CapturedClipRectangle = ScreenBuffer; } ConioInitRect(&DstRegion, CapturedDestinationOrigin.Y, CapturedDestinationOrigin.X, CapturedDestinationOrigin.Y + ConioRectHeight(&SrcRegion) - 1, CapturedDestinationOrigin.X + ConioRectWidth(&SrcRegion ) - 1); if (!Unicode) { WCHAR tmp; ConsoleOutputAnsiToUnicodeChar(Console, &tmp, &FillChar.Char.AsciiChar); FillChar.Char.UnicodeChar = tmp; } ConioMoveRegion(Buffer, &SrcRegion, &DstRegion, &CapturedClipRectangle, FillChar); if ((PCONSOLE_SCREEN_BUFFER)Buffer == Console->ActiveBuffer) { ConioGetUnion(&UpdateRegion, &SrcRegion, &DstRegion); if (ConioGetIntersection(&UpdateRegion, &UpdateRegion, &CapturedClipRectangle)) { /* Draw update region */ TermDrawRegion(Console, &UpdateRegion); } } return STATUS_SUCCESS; }
NTSTATUS NTAPI ConDrvWriteConsoleOutput(IN PCONSOLE Console, IN PTEXTMODE_SCREEN_BUFFER Buffer, IN BOOLEAN Unicode, IN PCHAR_INFO CharInfo/*Buffer*/, IN PCOORD BufferSize, IN PCOORD BufferCoord, IN OUT PSMALL_RECT WriteRegion) { SHORT i, X, Y, SizeX, SizeY; SMALL_RECT ScreenBuffer; PCHAR_INFO CurCharInfo; SMALL_RECT CapturedWriteRegion; PCHAR_INFO Ptr; if (Console == NULL || Buffer == NULL || CharInfo == NULL || BufferSize == NULL || BufferCoord == NULL || WriteRegion == NULL) { return STATUS_INVALID_PARAMETER; } /* Validity check */ ASSERT(Console == Buffer->Header.Console); CapturedWriteRegion = *WriteRegion; SizeX = min(BufferSize->X - BufferCoord->X, ConioRectWidth(&CapturedWriteRegion)); SizeY = min(BufferSize->Y - BufferCoord->Y, ConioRectHeight(&CapturedWriteRegion)); CapturedWriteRegion.Right = CapturedWriteRegion.Left + SizeX - 1; CapturedWriteRegion.Bottom = CapturedWriteRegion.Top + SizeY - 1; /* Make sure WriteRegion is inside the screen buffer */ ConioInitRect(&ScreenBuffer, 0, 0, Buffer->ScreenBufferSize.Y - 1, Buffer->ScreenBufferSize.X - 1); if (!ConioGetIntersection(&CapturedWriteRegion, &ScreenBuffer, &CapturedWriteRegion)) { /* * It is okay to have a WriteRegion completely outside * the screen buffer. No data is written then. */ return STATUS_SUCCESS; } for (i = 0, Y = CapturedWriteRegion.Top; Y <= CapturedWriteRegion.Bottom; i++, Y++) { CurCharInfo = CharInfo + (i + BufferCoord->Y) * BufferSize->X + BufferCoord->X; Ptr = ConioCoordToPointer(Buffer, CapturedWriteRegion.Left, Y); for (X = CapturedWriteRegion.Left; X <= CapturedWriteRegion.Right; X++) { if (Unicode) { Ptr->Char.UnicodeChar = CurCharInfo->Char.UnicodeChar; } else { ConsoleAnsiCharToUnicodeChar(Console, &Ptr->Char.UnicodeChar, &CurCharInfo->Char.AsciiChar); } Ptr->Attributes = CurCharInfo->Attributes; ++Ptr; ++CurCharInfo; } } ConioDrawRegion(Console, &CapturedWriteRegion); WriteRegion->Left = CapturedWriteRegion.Left; WriteRegion->Top = CapturedWriteRegion.Top ; WriteRegion->Right = CapturedWriteRegion.Left + SizeX - 1; WriteRegion->Bottom = CapturedWriteRegion.Top + SizeY - 1; return STATUS_SUCCESS; }
NTSTATUS NTAPI ConDrvReadConsoleOutput(IN PCONSOLE Console, IN PTEXTMODE_SCREEN_BUFFER Buffer, IN BOOLEAN Unicode, OUT PCHAR_INFO CharInfo/*Buffer*/, IN PCOORD BufferSize, IN PCOORD BufferCoord, IN OUT PSMALL_RECT ReadRegion) { PCHAR_INFO CurCharInfo; SHORT SizeX, SizeY; SMALL_RECT CapturedReadRegion; SMALL_RECT ScreenRect; DWORD i; PCHAR_INFO Ptr; LONG X, Y; UINT CodePage; if (Console == NULL || Buffer == NULL || CharInfo == NULL || BufferSize == NULL || BufferCoord == NULL || ReadRegion == NULL) { return STATUS_INVALID_PARAMETER; } /* Validity check */ ASSERT(Console == Buffer->Header.Console); CapturedReadRegion = *ReadRegion; /* FIXME: Is this correct? */ CodePage = Console->OutputCodePage; SizeX = min(BufferSize->X - BufferCoord->X, ConioRectWidth(&CapturedReadRegion)); SizeY = min(BufferSize->Y - BufferCoord->Y, ConioRectHeight(&CapturedReadRegion)); CapturedReadRegion.Right = CapturedReadRegion.Left + SizeX; CapturedReadRegion.Bottom = CapturedReadRegion.Top + SizeY; ConioInitRect(&ScreenRect, 0, 0, Buffer->ScreenBufferSize.Y, Buffer->ScreenBufferSize.X); if (!ConioGetIntersection(&CapturedReadRegion, &ScreenRect, &CapturedReadRegion)) { return STATUS_SUCCESS; } for (i = 0, Y = CapturedReadRegion.Top; Y < CapturedReadRegion.Bottom; ++i, ++Y) { CurCharInfo = CharInfo + (i * BufferSize->X); Ptr = ConioCoordToPointer(Buffer, CapturedReadRegion.Left, Y); for (X = CapturedReadRegion.Left; X < CapturedReadRegion.Right; ++X) { if (Unicode) { CurCharInfo->Char.UnicodeChar = Ptr->Char.UnicodeChar; } else { // ConsoleUnicodeCharToAnsiChar(Console, &CurCharInfo->Char.AsciiChar, &Ptr->Char.UnicodeChar); WideCharToMultiByte(CodePage, 0, &Ptr->Char.UnicodeChar, 1, &CurCharInfo->Char.AsciiChar, 1, NULL, NULL); } CurCharInfo->Attributes = Ptr->Attributes; ++Ptr; ++CurCharInfo; } } ReadRegion->Left = CapturedReadRegion.Left; ReadRegion->Top = CapturedReadRegion.Top ; ReadRegion->Right = CapturedReadRegion.Left + SizeX - 1; ReadRegion->Bottom = CapturedReadRegion.Top + SizeY - 1; return STATUS_SUCCESS; }