Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

2463 lines
85 KiB

/*++
Copyright (c) 1985 - 1999, Microsoft Corporation
Module Name:
_output.h
Abstract:
Performance critical routine for Single Binary
Each function will be created with two flavors FE and non FE
Author:
KazuM Jun.11.1997
Revision History:
--*/
#define WWSB_NEUTRAL_FILE 1
#if !defined(FE_SB)
#error This header file should be included with FE_SB
#endif
#if !defined(WWSB_FE) && !defined(WWSB_NOFE)
#error Either WWSB_FE and WWSB_NOFE must be defined.
#endif
#if defined(WWSB_FE) && defined(WWSB_NOFE)
#error Both WWSB_FE and WWSB_NOFE defined.
#endif
#include "dispatch.h"
#if defined(WWSB_FE)
#pragma alloc_text(FE_TEXT, FE_StreamWriteToScreenBuffer)
#pragma alloc_text(FE_TEXT, FE_WriteRectToScreenBuffer)
#pragma alloc_text(FE_TEXT, FE_WriteRegionToScreen)
#pragma alloc_text(FE_TEXT, FE_WriteToScreen)
#pragma alloc_text(FE_TEXT, FE_WriteOutputString)
#pragma alloc_text(FE_TEXT, FE_FillOutput)
#pragma alloc_text(FE_TEXT, FE_FillRectangle)
#pragma alloc_text(FE_TEXT, FE_PolyTextOutCandidate)
#pragma alloc_text(FE_TEXT, FE_ConsolePolyTextOut)
#endif
#if defined(WWSB_NOFE)
VOID
SB_StreamWriteToScreenBuffer(
IN PWCHAR String,
IN SHORT StringLength,
IN PSCREEN_INFORMATION ScreenInfo
)
#else
VOID
FE_StreamWriteToScreenBuffer(
IN PWCHAR String,
IN SHORT StringLength,
IN PSCREEN_INFORMATION ScreenInfo,
IN PCHAR StringA
)
#endif
{
SHORT RowIndex;
PROW Row;
PWCHAR Char;
COORD TargetPoint;
DBGOUTPUT(("StreamWriteToScreenBuffer\n"));
#ifdef WWSB_FE
ASSERT(ScreenInfo->Flags & CONSOLE_TEXTMODE_BUFFER);
#endif
ScreenInfo->BufferInfo.TextInfo.Flags |= TEXT_VALID_HINT;
TargetPoint = ScreenInfo->BufferInfo.TextInfo.CursorPosition;
RowIndex = (ScreenInfo->BufferInfo.TextInfo.FirstRow+TargetPoint.Y) % ScreenInfo->ScreenBufferSize.Y;
Row = &ScreenInfo->BufferInfo.TextInfo.Rows[RowIndex];
DBGOUTPUT(("RowIndex = %x, Row = %x, TargetPoint = (%x,%x)\n",
RowIndex, Row, TargetPoint.X, TargetPoint.Y));
//
// copy chars
//
#ifdef WWSB_FE
BisectWrite(StringLength,TargetPoint,ScreenInfo);
if (TargetPoint.Y == ScreenInfo->ScreenBufferSize.Y-1 &&
TargetPoint.X+StringLength >= ScreenInfo->ScreenBufferSize.X &&
*(StringA+ScreenInfo->ScreenBufferSize.X-TargetPoint.X-1) & ATTR_LEADING_BYTE
) {
*(String+ScreenInfo->ScreenBufferSize.X-TargetPoint.X-1) = UNICODE_SPACE;
*(StringA+ScreenInfo->ScreenBufferSize.X-TargetPoint.X-1) = 0;
if (StringLength > ScreenInfo->ScreenBufferSize.X-TargetPoint.X-1) {
*(String+ScreenInfo->ScreenBufferSize.X-TargetPoint.X) = UNICODE_SPACE;
*(StringA+ScreenInfo->ScreenBufferSize.X-TargetPoint.X) = 0;
}
}
RtlCopyMemory(&Row->CharRow.KAttrs[TargetPoint.X],StringA,StringLength*sizeof(CHAR));
#endif
RtlCopyMemory(&Row->CharRow.Chars[TargetPoint.X],String,StringLength*sizeof(WCHAR));
// recalculate first and last non-space char
Row->CharRow.OldLeft = Row->CharRow.Left;
if (TargetPoint.X < Row->CharRow.Left) {
PWCHAR LastChar = &Row->CharRow.Chars[ScreenInfo->ScreenBufferSize.X];
for (Char=&Row->CharRow.Chars[TargetPoint.X];Char < LastChar && *Char==(WCHAR)' ';Char++)
;
Row->CharRow.Left = (SHORT)(Char-Row->CharRow.Chars);
}
Row->CharRow.OldRight = Row->CharRow.Right;
if ((TargetPoint.X+StringLength) >= Row->CharRow.Right) {
PWCHAR FirstChar = Row->CharRow.Chars;
for (Char=&Row->CharRow.Chars[TargetPoint.X+StringLength-1];*Char==(WCHAR)' ' && Char >= FirstChar;Char--)
;
Row->CharRow.Right = (SHORT)(Char+1-FirstChar);
}
//
// see if attr string is different. if so, allocate a new
// attr buffer and merge the two strings.
//
if (Row->AttrRow.Length != 1 ||
Row->AttrRow.Attrs->Attr != ScreenInfo->Attributes) {
PATTR_PAIR NewAttrs;
WORD NewAttrsLength;
ATTR_PAIR Attrs;
Attrs.Length = StringLength;
Attrs.Attr = ScreenInfo->Attributes;
if (!NT_SUCCESS(MergeAttrStrings(Row->AttrRow.Attrs,
Row->AttrRow.Length,
&Attrs,
1,
&NewAttrs,
&NewAttrsLength,
TargetPoint.X,
(SHORT)(TargetPoint.X+StringLength-1),
Row,
ScreenInfo
))) {
return;
}
if (Row->AttrRow.Length > 1) {
ConsoleHeapFree(Row->AttrRow.Attrs);
}
else {
ASSERT(Row->AttrRow.Attrs == &Row->AttrRow.AttrPair);
}
Row->AttrRow.Attrs = NewAttrs;
Row->AttrRow.Length = NewAttrsLength;
Row->CharRow.OldLeft = INVALID_OLD_LENGTH;
Row->CharRow.OldRight = INVALID_OLD_LENGTH;
}
ResetTextFlags(ScreenInfo,
TargetPoint.X,
TargetPoint.Y,
TargetPoint.X + StringLength - 1,
TargetPoint.Y);
}
#define CHAR_OF_PCI(p) (((PCHAR_INFO)(p))->Char.AsciiChar)
#define WCHAR_OF_PCI(p) (((PCHAR_INFO)(p))->Char.UnicodeChar)
#define ATTR_OF_PCI(p) (((PCHAR_INFO)(p))->Attributes)
#define SIZEOF_CI_CELL sizeof(CHAR_INFO)
#define CHAR_OF_VGA(p) (p[0])
#define ATTR_OF_VGA(p) (p[1])
#ifdef i386
#define SIZEOF_VGA_CELL 2
#else // risc
#define SIZEOF_VGA_CELL 4
#endif
#define COMMON_LVB_MASK 0x33
#define ATTR_OF_COMMON_LVB(p) (ATTR_OF_VGA(p) + (((p[2] & ~COMMON_LVB_MASK)) << 8))
#define SIZEOF_COMMON_LVB_CELL 4
VOID
WWSB_WriteRectToScreenBuffer(
PBYTE Source,
COORD SourceSize,
PSMALL_RECT SourceRect,
PSCREEN_INFORMATION ScreenInfo,
COORD TargetPoint,
IN UINT Codepage
)
/*++
Routine Description:
This routine copies a rectangular region to the screen buffer.
no clipping is done.
The source should contain Unicode or UnicodeOem chars.
Arguments:
Source - pointer to source buffer (a real VGA buffer or CHAR_INFO[])
SourceSize - dimensions of source buffer
SourceRect - rectangle in source buffer to copy
ScreenInfo - pointer to screen info
TargetPoint - upper left coordinates of target rectangle
Codepage - codepage to translate real VGA buffer from,
0xFFFFFFF if Source is CHAR_INFO[] (not requiring translation)
Return Value:
none.
--*/
{
PBYTE SourcePtr;
SHORT i,j;
SHORT XSize,YSize;
BOOLEAN WholeSource;
SHORT RowIndex;
PROW Row;
PWCHAR Char;
ATTR_PAIR Attrs[80];
PATTR_PAIR AttrBuf;
PATTR_PAIR Attr;
SHORT AttrLength;
BOOL bVGABuffer;
ULONG ulCellSize;
#ifdef WWSB_FE
PCHAR AttrP;
#endif
DBGOUTPUT(("WriteRectToScreenBuffer\n"));
#ifdef WWSB_FE
ASSERT(ScreenInfo->Flags & CONSOLE_TEXTMODE_BUFFER);
#endif
ScreenInfo->BufferInfo.TextInfo.Flags |= TEXT_VALID_HINT;
XSize = (SHORT)(SourceRect->Right - SourceRect->Left + 1);
YSize = (SHORT)(SourceRect->Bottom - SourceRect->Top + 1);
AttrBuf = Attrs;
if (XSize > 80) {
AttrBuf = ConsoleHeapAlloc(TMP_TAG, XSize * sizeof(ATTR_PAIR));
if (AttrBuf == NULL) {
return;
}
}
bVGABuffer = (Codepage != 0xFFFFFFFF);
if (bVGABuffer) {
#ifdef WWSB_FE
ulCellSize = (ScreenInfo->Console->fVDMVideoMode) ? SIZEOF_COMMON_LVB_CELL : SIZEOF_VGA_CELL;
#else
ulCellSize = SIZEOF_VGA_CELL;
#endif
} else {
ulCellSize = SIZEOF_CI_CELL;
}
SourcePtr = Source;
WholeSource = FALSE;
if (XSize == SourceSize.X) {
ASSERT (SourceRect->Left == 0);
if (SourceRect->Top != 0) {
SourcePtr += SCREEN_BUFFER_POINTER(SourceRect->Left,
SourceRect->Top,
SourceSize.X,
ulCellSize);
}
WholeSource = TRUE;
}
RowIndex = (ScreenInfo->BufferInfo.TextInfo.FirstRow+TargetPoint.Y) % ScreenInfo->ScreenBufferSize.Y;
for (i=0;i<YSize;i++) {
if (!WholeSource) {
SourcePtr = Source + SCREEN_BUFFER_POINTER(SourceRect->Left,
SourceRect->Top+i,
SourceSize.X,
ulCellSize);
}
//
// copy the chars and attrs into their respective arrays
//
#ifdef WWSB_FE
if (! bVGABuffer) {
COORD TPoint;
TPoint.X = TargetPoint.X;
TPoint.Y = TargetPoint.Y + i;
BisectWrite(XSize,TPoint,ScreenInfo);
if (TPoint.Y == ScreenInfo->ScreenBufferSize.Y-1 &&
TPoint.X+XSize-1 >= ScreenInfo->ScreenBufferSize.X &&
ATTR_OF_PCI(SourcePtr+ScreenInfo->ScreenBufferSize.X-TPoint.X-1) & COMMON_LVB_LEADING_BYTE)
{
WCHAR_OF_PCI(SourcePtr+ScreenInfo->ScreenBufferSize.X-TPoint.X-1) = UNICODE_SPACE;
ATTR_OF_PCI(SourcePtr+ScreenInfo->ScreenBufferSize.X-TPoint.X-1) &= ~COMMON_LVB_SBCSDBCS;
if (XSize-1 > ScreenInfo->ScreenBufferSize.X-TPoint.X-1) {
WCHAR_OF_PCI(SourcePtr+ScreenInfo->ScreenBufferSize.X-TPoint.X) = UNICODE_SPACE;
ATTR_OF_PCI(SourcePtr+ScreenInfo->ScreenBufferSize.X-TPoint.X) &= ~COMMON_LVB_SBCSDBCS;
}
}
}
#endif
Row = &ScreenInfo->BufferInfo.TextInfo.Rows[RowIndex];
Char = &Row->CharRow.Chars[TargetPoint.X];
#ifdef WWSB_FE
AttrP = &Row->CharRow.KAttrs[TargetPoint.X];
#endif
Attr = AttrBuf;
Attr->Length = 0;
AttrLength = 1;
/*
* Two version of the following loop to keep it fast:
* one for VGA buffers, one for CHAR_INFO buffers.
*/
if (bVGABuffer) {
#ifdef WWSB_FE
Attr->Attr = (ScreenInfo->Console->fVDMVideoMode) ? ATTR_OF_COMMON_LVB(SourcePtr) : ATTR_OF_VGA(SourcePtr);
#else
Attr->Attr = ATTR_OF_VGA(SourcePtr);
#endif
for (j = SourceRect->Left;
j <= SourceRect->Right;
j++,
#ifdef WWSB_FE
SourcePtr += (ScreenInfo->Console->fVDMVideoMode) ? SIZEOF_COMMON_LVB_CELL : SIZEOF_VGA_CELL
#else
SourcePtr += SIZEOF_VGA_CELL
#endif
) {
#ifdef WWSB_FE
UCHAR TmpBuff[2];
if (IsDBCSLeadByteConsole(CHAR_OF_VGA(SourcePtr),&ScreenInfo->Console->OutputCPInfo)) {
if (j+1 > SourceRect->Right) {
*Char = UNICODE_SPACE;
*AttrP = 0;
}
else {
TmpBuff[0] = CHAR_OF_VGA(SourcePtr);
TmpBuff[1] = CHAR_OF_VGA((SourcePtr + ((ScreenInfo->Console->fVDMVideoMode) ? SIZEOF_COMMON_LVB_CELL : SIZEOF_VGA_CELL)));
ConvertOutputToUnicode(Codepage,
TmpBuff,
2,
Char,
2);
Char++;
j++;
*AttrP++ = ATTR_LEADING_BYTE;
*Char++ = *(Char-1);
*AttrP++ = ATTR_TRAILING_BYTE;
if (ScreenInfo->Console->fVDMVideoMode) {
if (Attr->Attr == ATTR_OF_COMMON_LVB(SourcePtr)) {
Attr->Length += 1;
}
else {
Attr++;
Attr->Length = 1;
Attr->Attr = ATTR_OF_COMMON_LVB(SourcePtr);
AttrLength += 1;
}
}
else
{
if (Attr->Attr == ATTR_OF_VGA(SourcePtr)) {
Attr->Length += 1;
}
else {
Attr++;
Attr->Length = 1;
Attr->Attr = ATTR_OF_VGA(SourcePtr);
AttrLength += 1;
}
}
SourcePtr += (ScreenInfo->Console->fVDMVideoMode) ? SIZEOF_COMMON_LVB_CELL : SIZEOF_VGA_CELL;
}
}
else {
ConvertOutputToUnicode(Codepage,
&CHAR_OF_VGA(SourcePtr),
1,
Char,
1);
Char++;
*AttrP++ = 0;
}
#else
*Char++ = SB_CharToWcharGlyph(Codepage, CHAR_OF_VGA(SourcePtr));
#endif
#ifdef WWSB_FE
if (ScreenInfo->Console->fVDMVideoMode) {
if (Attr->Attr == ATTR_OF_COMMON_LVB(SourcePtr)) {
Attr->Length += 1;
}
else {
Attr++;
Attr->Length = 1;
Attr->Attr = ATTR_OF_COMMON_LVB(SourcePtr);
AttrLength += 1;
}
}
else
#endif
if (Attr->Attr == ATTR_OF_VGA(SourcePtr)) {
Attr->Length += 1;
}
else {
Attr++;
Attr->Length = 1;
Attr->Attr = ATTR_OF_VGA(SourcePtr);
AttrLength += 1;
}
}
} else {
#ifdef WWSB_FE
Attr->Attr = ATTR_OF_PCI(SourcePtr) & ~COMMON_LVB_SBCSDBCS;
#else
Attr->Attr = ATTR_OF_PCI(SourcePtr);
#endif
for (j = SourceRect->Left;
j <= SourceRect->Right;
j++, SourcePtr += SIZEOF_CI_CELL) {
*Char++ = WCHAR_OF_PCI(SourcePtr);
#ifdef WWSB_FE
// MSKK Apr.02.1993 V-HirotS For KAttr
*AttrP++ = (CHAR)((ATTR_OF_PCI(SourcePtr) & COMMON_LVB_SBCSDBCS) >>8);
#endif
#ifdef WWSB_FE
if (Attr->Attr == (ATTR_OF_PCI(SourcePtr) & ~COMMON_LVB_SBCSDBCS))
#else
if (Attr->Attr == ATTR_OF_PCI(SourcePtr))
#endif
{
Attr->Length += 1;
}
else {
Attr++;
Attr->Length = 1;
#ifdef WWSB_FE
// MSKK Apr.02.1993 V-HirotS For KAttr
Attr->Attr = ATTR_OF_PCI(SourcePtr) & ~COMMON_LVB_SBCSDBCS;
#else
Attr->Attr = ATTR_OF_PCI(SourcePtr);
#endif
AttrLength += 1;
}
}
}
// recalculate first and last non-space char
Row->CharRow.OldLeft = Row->CharRow.Left;
if (TargetPoint.X < Row->CharRow.Left) {
PWCHAR LastChar = &Row->CharRow.Chars[ScreenInfo->ScreenBufferSize.X];
for (Char=&Row->CharRow.Chars[TargetPoint.X];Char < LastChar && *Char==(WCHAR)' ';Char++)
;
Row->CharRow.Left = (SHORT)(Char-Row->CharRow.Chars);
}
Row->CharRow.OldRight = Row->CharRow.Right;
if ((TargetPoint.X+XSize) >= Row->CharRow.Right) {
SHORT LastNonSpace;
PWCHAR FirstChar = Row->CharRow.Chars;
LastNonSpace = (SHORT)(TargetPoint.X+XSize-1);
for (Char=&Row->CharRow.Chars[(TargetPoint.X+XSize-1)];*Char==(WCHAR)' ' && Char >= FirstChar;Char--)
LastNonSpace--;
//
// if the attributes change after the last non-space, make the
// index of the last attribute change + 1 the length. otherwise
// make the length one more than the last non-space.
//
Row->CharRow.Right = (SHORT)(LastNonSpace+1);
}
//
// see if attr string is different. if so, allocate a new
// attr buffer and merge the two strings.
//
if (AttrLength != Row->AttrRow.Length ||
memcmp(Row->AttrRow.Attrs,AttrBuf,AttrLength*sizeof(*Attr))) {
PATTR_PAIR NewAttrs;
WORD NewAttrsLength;
if (!NT_SUCCESS(MergeAttrStrings(Row->AttrRow.Attrs,
Row->AttrRow.Length,
AttrBuf,
AttrLength,
&NewAttrs,
&NewAttrsLength,
TargetPoint.X,
(SHORT)(TargetPoint.X+XSize-1),
Row,
ScreenInfo
))) {
if (XSize > 80) {
ConsoleHeapFree(AttrBuf);
}
ResetTextFlags(ScreenInfo,
TargetPoint.X,
TargetPoint.Y,
(SHORT)(TargetPoint.X + XSize - 1),
(SHORT)(TargetPoint.Y + YSize - 1));
return;
}
if (Row->AttrRow.Length > 1) {
ConsoleHeapFree(Row->AttrRow.Attrs);
}
else {
ASSERT(Row->AttrRow.Attrs == &Row->AttrRow.AttrPair);
}
Row->AttrRow.Attrs = NewAttrs;
Row->AttrRow.Length = NewAttrsLength;
Row->CharRow.OldLeft = INVALID_OLD_LENGTH;
Row->CharRow.OldRight = INVALID_OLD_LENGTH;
}
if (++RowIndex == ScreenInfo->ScreenBufferSize.Y) {
RowIndex = 0;
}
}
ResetTextFlags(ScreenInfo,
TargetPoint.X,
TargetPoint.Y,
(SHORT)(TargetPoint.X + XSize - 1),
(SHORT)(TargetPoint.Y + YSize - 1));
if (XSize > 80) {
ConsoleHeapFree(AttrBuf);
}
}
VOID
WWSB_WriteRegionToScreen(
IN PSCREEN_INFORMATION ScreenInfo,
IN PSMALL_RECT Region
)
{
COORD Window;
int i,j;
PATTR_PAIR Attr;
RECT TextRect;
SHORT RowIndex;
SHORT CountOfAttr;
PROW Row;
BOOL OneLine, SimpleWrite; // one line && one attribute per line
PCONSOLE_INFORMATION Console = ScreenInfo->Console;
PWCHAR TransBufferCharacter = NULL ;
#ifdef WWSB_FE
BOOL DoubleColorDbcs;
SHORT CountOfAttrOriginal;
SHORT RegionRight;
BOOL LocalEUDCFlag;
SMALL_RECT CaTextRect;
PCONVERSIONAREA_INFORMATION ConvAreaInfo = ScreenInfo->ConvScreenInfo;
#endif
DBGOUTPUT(("WriteRegionToScreen\n"));
#ifdef WWSB_FE
if (ConvAreaInfo) {
CaTextRect.Left = Region->Left - ScreenInfo->Console->CurrentScreenBuffer->Window.Left - ConvAreaInfo->CaInfo.coordConView.X;
CaTextRect.Right = CaTextRect.Left + (Region->Right - Region->Left);
CaTextRect.Top = Region->Top - ScreenInfo->Console->CurrentScreenBuffer->Window.Top - ConvAreaInfo->CaInfo.coordConView.Y;
CaTextRect.Bottom = CaTextRect.Top + (Region->Bottom - Region->Top);
}
if (Region->Left && (ScreenInfo->BisectFlag & BISECT_LEFT)) {
Region->Left--;
}
if (Region->Right+1 < ScreenInfo->ScreenBufferSize.X && (ScreenInfo->BisectFlag & BISECT_RIGHT)) {
Region->Right++;
}
ScreenInfo->BisectFlag &= ~(BISECT_LEFT | BISECT_RIGHT);
Console->ConsoleIme.ScrollWaitCountDown = Console->ConsoleIme.ScrollWaitTimeout;
#endif
if (Console->FullScreenFlags == 0) {
//
// if we have a selection, turn it off.
//
InvertSelection(Console, TRUE);
ASSERT(ScreenInfo->Flags & CONSOLE_TEXTMODE_BUFFER);
if (WWSB_PolyTextOutCandidate(ScreenInfo,Region)) {
WWSB_ConsolePolyTextOut(ScreenInfo,Region);
}
else {
#ifdef WWSB_FE
if (ConvAreaInfo) {
Window.Y = Region->Top - Console->CurrentScreenBuffer->Window.Top;
Window.X = Region->Left - Console->CurrentScreenBuffer->Window.Left;
}
else {
#endif
Window.Y = Region->Top - ScreenInfo->Window.Top;
Window.X = Region->Left - ScreenInfo->Window.Left;
#ifdef WWSB_FE
}
#endif
#ifdef WWSB_FE
RowIndex = (ConvAreaInfo ? CaTextRect.Top :
(ScreenInfo->BufferInfo.TextInfo.FirstRow+Region->Top) % ScreenInfo->ScreenBufferSize.Y
);
RegionRight = Region->Right;
#else
RowIndex = (ScreenInfo->BufferInfo.TextInfo.FirstRow+Region->Top) % ScreenInfo->ScreenBufferSize.Y;
#endif
OneLine = (Region->Top==Region->Bottom);
TransBufferCharacter = ConsoleHeapAlloc(TMP_DBCS_TAG,
(ScreenInfo->ScreenBufferSize.X * sizeof(WCHAR)) + sizeof(WCHAR));
if (TransBufferCharacter == NULL) {
RIPMSG0(RIP_WARNING, "WriteRegionToScreen cannot allocate memory");
return;
}
for (i=Region->Top;i<=Region->Bottom;i++,Window.Y++) {
#ifdef WWSB_FE
DoubleColorDbcs = FALSE;
Region->Right = RegionRight;
#endif
//
// copy the chars and attrs from their respective arrays
//
Row = &ScreenInfo->BufferInfo.TextInfo.Rows[RowIndex];
if (Row->AttrRow.Length == 1) {
Attr = Row->AttrRow.Attrs;
CountOfAttr = ScreenInfo->ScreenBufferSize.X;
SimpleWrite = TRUE;
} else {
SimpleWrite = FALSE;
FindAttrIndex(Row->AttrRow.Attrs,
#ifdef WWSB_FE
(SHORT)(ConvAreaInfo ? CaTextRect.Left : Region->Left),
#else
Region->Left,
#endif
&Attr,
&CountOfAttr
);
}
if (Console->LastAttributes != Attr->Attr) {
TEXTCOLOR_CALL;
#ifdef WWSB_FE
if (Attr->Attr & COMMON_LVB_REVERSE_VIDEO)
{
SetBkColor(Console->hDC, ConvertAttrToRGB(Console, LOBYTE(Attr->Attr)));
SetTextColor(Console->hDC, ConvertAttrToRGB(Console, LOBYTE(Attr->Attr >> 4)));
}
else{
#endif
SetTextColor(Console->hDC, ConvertAttrToRGB(Console, LOBYTE(Attr->Attr)));
SetBkColor(Console->hDC, ConvertAttrToRGB(Console, LOBYTE(Attr->Attr >> 4)));
#ifdef WWSB_FE
}
#endif
Console->LastAttributes = Attr->Attr;
}
TextRect.top = Window.Y*SCR_FONTSIZE(ScreenInfo).Y;
TextRect.bottom = TextRect.top + SCR_FONTSIZE(ScreenInfo).Y;
for (j=Region->Left;j<=Region->Right;) {
SHORT NumberOfChars;
int TextLeft;
SHORT LeftChar,RightChar;
if (CountOfAttr > (SHORT)(Region->Right - j + 1)) {
CountOfAttr = (SHORT)(Region->Right - j + 1);
}
#ifdef WWSB_FE
CountOfAttrOriginal = CountOfAttr;
LocalEUDCFlag = FALSE;
if((ScreenInfo->Console->Flags & CONSOLE_VDM_REGISTERED &&
((PEUDC_INFORMATION)(ScreenInfo->Console->EudcInformation))->LocalVDMEudcMode)){
LocalEUDCFlag = CheckEudcRangeInString(
Console,
&Row->CharRow.Chars[ConvAreaInfo ?
CaTextRect.Left + (j-Region->Left) : j],
CountOfAttr,
&CountOfAttr);
}
if (!(ScreenInfo->Flags & CONSOLE_OEMFONT_DISPLAY) &&
!(ScreenInfo->Console->FullScreenFlags & CONSOLE_FULLSCREEN) &&
((PEUDC_INFORMATION)(ScreenInfo->Console->EudcInformation))->LocalKeisenEudcMode
) {
SHORT k;
PWCHAR Char2;
Char2 = &Row->CharRow.Chars[ConvAreaInfo ? CaTextRect.Left + (j-Region->Left) : j];
for ( k = 0 ; k < CountOfAttr ; k++,Char2++){
if (*Char2 < UNICODE_SPACE){
CountOfAttr = k ;
LocalEUDCFlag = TRUE;
break;
}
}
}
#endif
//
// make the bounding rect smaller, if we can. the TEXT_VALID_HINT
// flag gets set each time we write to the screen buffer. it gets
// turned off any time we get asked to redraw the screen
// and we don't know exactly what needs to be redrawn
// (i.e. paint messages).
//
// we have the left and right bounds of the text on the
// line. the opaqueing rectangle and the number of
// chars get set according to those values.
//
// if there's more than one attr per line (!SimpleWrite)
// we bail on the opaqueing rect.
//
if (ScreenInfo->BufferInfo.TextInfo.Flags & TEXT_VALID_HINT && SimpleWrite) {
if (Row->CharRow.OldLeft != INVALID_OLD_LENGTH) {
TextRect.left = (max(min(Row->CharRow.Left,Row->CharRow.OldLeft),j)-ScreenInfo->Window.Left) *
SCR_FONTSIZE(ScreenInfo).X;
} else {
TextRect.left = Window.X*SCR_FONTSIZE(ScreenInfo).X;
}
if (Row->CharRow.OldRight != INVALID_OLD_LENGTH) {
TextRect.right = (min(max(Row->CharRow.Right,Row->CharRow.OldRight),j+CountOfAttr)-ScreenInfo->Window.Left) *
SCR_FONTSIZE(ScreenInfo).X;
} else {
TextRect.right = TextRect.left + CountOfAttr*SCR_FONTSIZE(ScreenInfo).X;
}
LeftChar = max(Row->CharRow.Left,j);
RightChar = min(Row->CharRow.Right,j+CountOfAttr);
NumberOfChars = RightChar - LeftChar;
TextLeft = (LeftChar-ScreenInfo->Window.Left)*SCR_FONTSIZE(ScreenInfo).X;
} else {
#ifdef WWSB_FE
LeftChar = ConvAreaInfo ? CaTextRect.Left + (j-Region->Left) : j;
#else
LeftChar = (SHORT)j;
#endif
TextRect.left = Window.X*SCR_FONTSIZE(ScreenInfo).X;
TextRect.right = TextRect.left + CountOfAttr*SCR_FONTSIZE(ScreenInfo).X;
#ifdef WWSB_FE
if (ConvAreaInfo)
NumberOfChars = (Row->CharRow.Right > (SHORT)((CaTextRect.Left+(j-Region->Left)) + CountOfAttr)) ?
(CountOfAttr) : (SHORT)(Row->CharRow.Right-(CaTextRect.Left+(j-Region->Left)));
else
#endif
NumberOfChars = (Row->CharRow.Right > (SHORT)(j + CountOfAttr)) ? (CountOfAttr) : (SHORT)(Row->CharRow.Right-j);
TextLeft = TextRect.left;
}
if (NumberOfChars < 0)
{
NumberOfChars = 0;
#ifdef WWSB_FE
TextRect.left = Window.X*SCR_FONTSIZE(ScreenInfo).X;
TextRect.right = TextRect.left + CountOfAttr*SCR_FONTSIZE(ScreenInfo).X;
#endif
}
TEXTOUT_CALL;
#ifdef WWSB_FE
/*
* Text out everything (i.e. SBCS/DBCS, Common LVB attribute, Local EUDC)
*/
TextOutEverything(Console,
ScreenInfo,
(SHORT)j,
&Region->Right,
&CountOfAttr,
CountOfAttrOriginal,
&DoubleColorDbcs,
LocalEUDCFlag,
Row,
Attr,
LeftChar,
RightChar,
TextLeft,
TextRect,
NumberOfChars);
#else
NumberOfChars =
(SHORT)RemoveDbcsMarkAll(ScreenInfo,
Row,
&LeftChar,
&TextRect,
&TextLeft,
TransBufferCharacter,
NumberOfChars);
ExtTextOutW(Console->hDC,
TextLeft,
TextRect.top,
ETO_OPAQUE,
&TextRect,
TransBufferCharacter,
NumberOfChars,
NULL
);
#endif
if (OneLine && SimpleWrite) {
break;
}
j+=CountOfAttr;
if (j <= Region->Right) {
Window.X += CountOfAttr;
#ifdef WWSB_FE
if (CountOfAttr < CountOfAttrOriginal){
CountOfAttr = CountOfAttrOriginal - CountOfAttr;
}
else {
#endif
Attr++;
CountOfAttr = Attr->Length;
#ifdef WWSB_FE
}
#endif
#ifdef WWSB_FE
if (Attr->Attr & COMMON_LVB_REVERSE_VIDEO)
{
SetBkColor(Console->hDC, ConvertAttrToRGB(Console, LOBYTE(Attr->Attr)));
SetTextColor(Console->hDC, ConvertAttrToRGB(Console, LOBYTE(Attr->Attr >> 4)));
}
else{
#endif
SetTextColor(Console->hDC, ConvertAttrToRGB(Console, LOBYTE(Attr->Attr)));
SetBkColor(Console->hDC, ConvertAttrToRGB(Console, LOBYTE(Attr->Attr >> 4)));
#ifdef WWSB_FE
}
#endif
Console->LastAttributes = Attr->Attr;
}
}
Window.X = Region->Left - ScreenInfo->Window.Left;
if (++RowIndex == ScreenInfo->ScreenBufferSize.Y) {
RowIndex = 0;
}
}
GdiFlush();
ConsoleHeapFree(TransBufferCharacter);
}
//
// if we have a selection, turn it on.
//
InvertSelection(Console, FALSE);
}
#ifdef i386
else if (Console->FullScreenFlags & CONSOLE_FULLSCREEN_HARDWARE) {
#ifdef WWSB_FE
if (! ScreenInfo->ConvScreenInfo) {
if (ScreenInfo->Console->CurrentScreenBuffer == ScreenInfo) {
WWSB_WriteRegionToScreenHW(ScreenInfo,Region);
}
}
else if (ScreenInfo->Console->CurrentScreenBuffer->Flags & CONSOLE_TEXTMODE_BUFFER)
#endif
WWSB_WriteRegionToScreenHW(ScreenInfo,Region);
}
#endif
#ifdef WWSB_FE
{
SMALL_RECT TmpRegion;
if (ScreenInfo->BisectFlag & BISECT_TOP) {
ScreenInfo->BisectFlag &= ~BISECT_TOP;
if (Region->Top) {
TmpRegion.Top = Region->Top-1;
TmpRegion.Bottom = Region->Top-1;
TmpRegion.Left = ScreenInfo->ScreenBufferSize.X-1;
TmpRegion.Right = ScreenInfo->ScreenBufferSize.X-1;
WWSB_WriteRegionToScreen(ScreenInfo,&TmpRegion);
}
}
if (ScreenInfo->BisectFlag & BISECT_BOTTOM) {
ScreenInfo->BisectFlag &= ~BISECT_BOTTOM;
if (Region->Bottom+1 < ScreenInfo->ScreenBufferSize.Y) {
TmpRegion.Top = Region->Bottom+1;
TmpRegion.Bottom = Region->Bottom+1;
TmpRegion.Left = 0;
TmpRegion.Right = 0;
WWSB_WriteRegionToScreen(ScreenInfo,&TmpRegion);
}
}
}
#endif
}
VOID
WWSB_WriteToScreen(
IN PSCREEN_INFORMATION ScreenInfo,
IN PSMALL_RECT Region
)
/*++
Routine Description:
This routine writes a screen buffer region to the screen.
Arguments:
ScreenInfo - Pointer to screen buffer information.
Region - Region to write in screen buffer coordinates. Region is
inclusive
Return Value:
none.
--*/
{
SMALL_RECT ClippedRegion;
DBGOUTPUT(("WriteToScreen\n"));
//
// update to screen, if we're not iconic. we're marked as
// iconic if we're fullscreen, so check for fullscreen.
//
if (!ACTIVE_SCREEN_BUFFER(ScreenInfo) ||
(ScreenInfo->Console->Flags & (CONSOLE_IS_ICONIC | CONSOLE_NO_WINDOW) &&
ScreenInfo->Console->FullScreenFlags == 0)) {
return;
}
// clip region
ClippedRegion.Left = max(Region->Left, ScreenInfo->Window.Left);
ClippedRegion.Top = max(Region->Top, ScreenInfo->Window.Top);
ClippedRegion.Right = min(Region->Right, ScreenInfo->Window.Right);
ClippedRegion.Bottom = min(Region->Bottom, ScreenInfo->Window.Bottom);
if (ClippedRegion.Right < ClippedRegion.Left ||
ClippedRegion.Bottom < ClippedRegion.Top) {
return;
}
if (ScreenInfo->Flags & CONSOLE_GRAPHICS_BUFFER) {
if (ScreenInfo->Console->FullScreenFlags == 0) {
WriteRegionToScreenBitMap(ScreenInfo, &ClippedRegion);
}
} else {
ConsoleHideCursor(ScreenInfo);
WWSB_WriteRegionToScreen(ScreenInfo, &ClippedRegion);
#ifdef WWSB_FE
if (!(ScreenInfo->Console->ConsoleIme.ScrollFlag & HIDE_FOR_SCROLL))
{
PCONVERSIONAREA_INFORMATION ConvAreaInfo;
if (! ScreenInfo->Console->CurrentScreenBuffer->ConvScreenInfo) {
WriteConvRegionToScreen(ScreenInfo,
ScreenInfo->Console->ConsoleIme.ConvAreaRoot,
Region);
}
else if (ConvAreaInfo = ScreenInfo->Console->ConsoleIme.ConvAreaRoot) {
do {
if (ConvAreaInfo->ScreenBuffer == ScreenInfo)
break;
} while (ConvAreaInfo = ConvAreaInfo->ConvAreaNext);
if (ConvAreaInfo) {
WriteConvRegionToScreen(ScreenInfo,
ConvAreaInfo->ConvAreaNext,
Region);
}
}
}
#endif
ConsoleShowCursor(ScreenInfo);
}
}
NTSTATUS
WWSB_WriteOutputString(
IN PSCREEN_INFORMATION ScreenInfo,
IN PVOID Buffer,
IN COORD WriteCoord,
IN ULONG StringType,
IN OUT PULONG NumRecords, // this value is valid even for error cases
OUT PULONG NumColumns OPTIONAL
)
/*++
Routine Description:
This routine writes a string of characters or attributes to the
screen buffer.
Arguments:
ScreenInfo - Pointer to screen buffer information.
Buffer - Buffer to write from.
WriteCoord - Screen buffer coordinate to begin writing to.
StringType
One of the following:
CONSOLE_ASCII - write a string of ascii characters.
CONSOLE_REAL_UNICODE - write a string of real unicode characters.
CONSOLE_FALSE_UNICODE - write a string of false unicode characters.
CONSOLE_ATTRIBUTE - write a string of attributes.
NumRecords - On input, the number of elements to write. On output,
the number of elements written.
NumColumns - receives the number of columns output, which could be more
than NumRecords (FE fullwidth chars)
Return Value:
--*/
{
ULONG NumWritten;
SHORT X,Y,LeftX;
SMALL_RECT WriteRegion;
PROW Row;
PWCHAR Char;
SHORT RowIndex;
SHORT j;
PWCHAR TransBuffer;
#ifdef WWSB_NOFE
WCHAR SingleChar;
#endif
UINT Codepage;
#ifdef WWSB_FE
PBYTE AttrP;
PBYTE TransBufferA;
PBYTE BufferA;
ULONG NumRecordsSavedForUnicode;
BOOL fLocalHeap = FALSE;
#endif
DBGOUTPUT(("WriteOutputString\n"));
#ifdef WWSB_FE
ASSERT(ScreenInfo->Flags & CONSOLE_TEXTMODE_BUFFER);
#endif
if (*NumRecords == 0)
return STATUS_SUCCESS;
NumWritten = 0;
X=WriteCoord.X;
Y=WriteCoord.Y;
if (X>=ScreenInfo->ScreenBufferSize.X ||
X<0 ||
Y>=ScreenInfo->ScreenBufferSize.Y ||
Y<0) {
*NumRecords = 0;
return STATUS_SUCCESS;
}
ScreenInfo->BufferInfo.TextInfo.Flags |= TEXT_VALID_HINT;
RowIndex = (ScreenInfo->BufferInfo.TextInfo.FirstRow+WriteCoord.Y) % ScreenInfo->ScreenBufferSize.Y;
if (StringType == CONSOLE_ASCII) {
#ifdef WWSB_FE
PCHAR TmpBuf;
PWCHAR TmpTrans;
ULONG i;
PCHAR TmpTransA;
#endif
if ((ScreenInfo->Flags & CONSOLE_OEMFONT_DISPLAY) &&
!(ScreenInfo->Console->FullScreenFlags & CONSOLE_FULLSCREEN)) {
if (ScreenInfo->Console->OutputCP != WINDOWSCP)
Codepage = USACP;
else
Codepage = WINDOWSCP;
} else {
Codepage = ScreenInfo->Console->OutputCP;
}
#ifdef WWSB_FE
if (*NumRecords > (ULONG)(ScreenInfo->ScreenBufferSize.X * ScreenInfo->ScreenBufferSize.Y)) {
TransBuffer = ConsoleHeapAlloc(TMP_DBCS_TAG, *NumRecords * 2 * sizeof(WCHAR));
if (TransBuffer == NULL) {
return STATUS_NO_MEMORY;
}
TransBufferA = ConsoleHeapAlloc(TMP_DBCS_TAG, *NumRecords * 2 * sizeof(CHAR));
if (TransBufferA == NULL) {
ConsoleHeapFree(TransBuffer);
return STATUS_NO_MEMORY;
}
fLocalHeap = TRUE;
}
else {
TransBuffer = ScreenInfo->BufferInfo.TextInfo.DbcsScreenBuffer.TransBufferCharacter;
TransBufferA = ScreenInfo->BufferInfo.TextInfo.DbcsScreenBuffer.TransBufferAttribute;
}
TmpBuf = Buffer;
TmpTrans = TransBuffer;
TmpTransA = TransBufferA; // MSKK Apr.02.1993 V-HirotS For KAttr
for (i=0; i < *NumRecords;) {
if (IsDBCSLeadByteConsole(*TmpBuf,&ScreenInfo->Console->OutputCPInfo)) {
if (i+1 >= *NumRecords) {
*TmpTrans = UNICODE_SPACE;
*TmpTransA = 0;
i++;
}
else {
ConvertOutputToUnicode(Codepage,
TmpBuf,
2,
TmpTrans,
2);
*(TmpTrans+1) = *TmpTrans;
TmpTrans += 2;
TmpBuf += 2;
*TmpTransA++ = ATTR_LEADING_BYTE;
*TmpTransA++ = ATTR_TRAILING_BYTE;
i += 2;
}
}
else {
ConvertOutputToUnicode(Codepage,
TmpBuf,
1,
TmpTrans,
1);
TmpTrans++;
TmpBuf++;
*TmpTransA++ = 0; // MSKK APr.02.1993 V-HirotS For KAttr
i++;
}
}
BufferA = TransBufferA;
Buffer = TransBuffer;
#else
if (*NumRecords == 1) {
TransBuffer = NULL;
SingleChar = SB_CharToWcharGlyph(Codepage, *((char *)Buffer));
Buffer = &SingleChar;
} else {
TransBuffer = ConsoleHeapAlloc(TMP_TAG, *NumRecords * sizeof(WCHAR));
if (TransBuffer == NULL) {
return STATUS_NO_MEMORY;
}
ConvertOutputToUnicode(Codepage, Buffer, *NumRecords,
TransBuffer, *NumRecords);
Buffer = TransBuffer;
}
#endif
} else if (StringType == CONSOLE_REAL_UNICODE &&
(ScreenInfo->Flags & CONSOLE_OEMFONT_DISPLAY) &&
!(ScreenInfo->Console->FullScreenFlags & CONSOLE_FULLSCREEN)) {
RealUnicodeToFalseUnicode(Buffer,
*NumRecords,
ScreenInfo->Console->OutputCP
);
}
#ifdef WWSB_FE
if ((StringType == CONSOLE_REAL_UNICODE) || (StringType == CONSOLE_FALSE_UNICODE)) {
PWCHAR TmpBuf;
PWCHAR TmpTrans;
PCHAR TmpTransA;
ULONG i,j;
WCHAR c;
/* Avoid overflow into TransBufferCharacter , TransBufferAttribute
* because, if hit by IsConsoleFullWidth()
* then one unicde character needs two spaces on TransBuffer.
*/
if ((*NumRecords*2) > (ULONG)(ScreenInfo->ScreenBufferSize.X * ScreenInfo->ScreenBufferSize.Y)) {
TransBuffer = ConsoleHeapAlloc(TMP_DBCS_TAG, *NumRecords * 2 * sizeof(WCHAR));
if (TransBuffer == NULL) {
return STATUS_NO_MEMORY;
}
TransBufferA = ConsoleHeapAlloc(TMP_DBCS_TAG, *NumRecords * 2 * sizeof(CHAR));
if (TransBufferA == NULL) {
ConsoleHeapFree(TransBuffer);
return STATUS_NO_MEMORY;
}
fLocalHeap = TRUE;
}
else {
TransBuffer = ScreenInfo->BufferInfo.TextInfo.DbcsScreenBuffer.TransBufferCharacter;
TransBufferA = ScreenInfo->BufferInfo.TextInfo.DbcsScreenBuffer.TransBufferAttribute;
}
TmpBuf = Buffer;
TmpTrans = TransBuffer;
TmpTransA = TransBufferA;
for (i=0,j=0; i < *NumRecords; i++,j++) {
*TmpTrans++ = c = *TmpBuf++;
*TmpTransA = 0;
if (IsConsoleFullWidth(ScreenInfo->Console->hDC,
ScreenInfo->Console->OutputCP,c)) {
*TmpTransA++ = ATTR_LEADING_BYTE;
*TmpTrans++ = c;
*TmpTransA = ATTR_TRAILING_BYTE;
j++;
}
TmpTransA++;
}
NumRecordsSavedForUnicode = *NumRecords;
*NumRecords = j;
Buffer = TransBuffer;
BufferA = TransBufferA;
}
#endif
if ((StringType == CONSOLE_REAL_UNICODE) ||
(StringType == CONSOLE_FALSE_UNICODE) ||
(StringType == CONSOLE_ASCII)) {
while (TRUE) {
LeftX = X;
//
// copy the chars into their arrays
//
Row = &ScreenInfo->BufferInfo.TextInfo.Rows[RowIndex];
Char = &Row->CharRow.Chars[X];
#ifdef WWSB_FE
AttrP = &Row->CharRow.KAttrs[X];
#endif
if ((ULONG)(ScreenInfo->ScreenBufferSize.X - X) >= (*NumRecords - NumWritten)) {
/*
* The text will not hit the right hand edge, copy it all
*/
#ifdef WWSB_FE
COORD TPoint;
TPoint.X = X;
TPoint.Y = Y;
BisectWrite((SHORT)(*NumRecords-NumWritten),TPoint,ScreenInfo);
if (TPoint.Y == ScreenInfo->ScreenBufferSize.Y-1 &&
(SHORT)(TPoint.X+*NumRecords-NumWritten) >= ScreenInfo->ScreenBufferSize.X &&
*((PCHAR)BufferA+ScreenInfo->ScreenBufferSize.X-TPoint.X-1) & ATTR_LEADING_BYTE
) {
*((PWCHAR)Buffer+ScreenInfo->ScreenBufferSize.X-TPoint.X-1) = UNICODE_SPACE;
*((PCHAR)BufferA+ScreenInfo->ScreenBufferSize.X-TPoint.X-1) = 0;
if ((SHORT)(*NumRecords-NumWritten) > (SHORT)(ScreenInfo->ScreenBufferSize.X-TPoint.X-1)) {
*((PWCHAR)Buffer+ScreenInfo->ScreenBufferSize.X-TPoint.X) = UNICODE_SPACE;
*((PCHAR)BufferA+ScreenInfo->ScreenBufferSize.X-TPoint.X) = 0;
}
}
RtlCopyMemory(AttrP,BufferA,(*NumRecords - NumWritten) * sizeof(CHAR));
#endif
RtlCopyMemory(Char,Buffer,(*NumRecords - NumWritten) * sizeof(WCHAR));
X=(SHORT)(X+*NumRecords - NumWritten-1);
NumWritten = *NumRecords;
}
else {
/*
* The text will hit the right hand edge, copy only that much
*/
#ifdef WWSB_FE
COORD TPoint;
TPoint.X = X;
TPoint.Y = Y;
BisectWrite((SHORT)(ScreenInfo->ScreenBufferSize.X-X),TPoint,ScreenInfo);
if (TPoint.Y == ScreenInfo->ScreenBufferSize.Y-1 &&
TPoint.X+ScreenInfo->ScreenBufferSize.X-X >= ScreenInfo->ScreenBufferSize.X &&
*((PCHAR)BufferA+ScreenInfo->ScreenBufferSize.X-TPoint.X-1) & ATTR_LEADING_BYTE
) {
*((PWCHAR)Buffer+ScreenInfo->ScreenBufferSize.X-TPoint.X-1) = UNICODE_SPACE;
*((PCHAR)BufferA+ScreenInfo->ScreenBufferSize.X-TPoint.X-1) = 0;
if (ScreenInfo->ScreenBufferSize.X-X > ScreenInfo->ScreenBufferSize.X-TPoint.X-1) {
*((PWCHAR)Buffer+ScreenInfo->ScreenBufferSize.X-TPoint.X) = UNICODE_SPACE;
*((PCHAR)BufferA+ScreenInfo->ScreenBufferSize.X-TPoint.X) = 0;
}
}
RtlCopyMemory(AttrP,BufferA,(ScreenInfo->ScreenBufferSize.X - X) * sizeof(CHAR));
BufferA = (PVOID)((PBYTE)BufferA + ((ScreenInfo->ScreenBufferSize.X - X) * sizeof(CHAR)));
#endif
RtlCopyMemory(Char,Buffer,(ScreenInfo->ScreenBufferSize.X - X) * sizeof(WCHAR));
Buffer = (PVOID)((PBYTE)Buffer + ((ScreenInfo->ScreenBufferSize.X - X) * sizeof(WCHAR)));
NumWritten += ScreenInfo->ScreenBufferSize.X - X;
X = (SHORT)(ScreenInfo->ScreenBufferSize.X-1);
}
// recalculate first and last non-space char
Row->CharRow.OldLeft = Row->CharRow.Left;
if (LeftX < Row->CharRow.Left) {
PWCHAR LastChar = &Row->CharRow.Chars[ScreenInfo->ScreenBufferSize.X];
for (Char=&Row->CharRow.Chars[LeftX];Char < LastChar && *Char==(WCHAR)' ';Char++)
;
Row->CharRow.Left = (SHORT)(Char-Row->CharRow.Chars);
}
Row->CharRow.OldRight = Row->CharRow.Right;
if ((X+1) >= Row->CharRow.Right) {
WORD LastNonSpace;
PWCHAR FirstChar = Row->CharRow.Chars;
LastNonSpace = X;
for (Char=&Row->CharRow.Chars[X];*Char==(WCHAR)' ' && Char >= FirstChar;Char--)
LastNonSpace--;
Row->CharRow.Right = (SHORT)(LastNonSpace+1);
}
if (++RowIndex == ScreenInfo->ScreenBufferSize.Y) {
RowIndex = 0;
}
if (NumWritten < *NumRecords) {
/*
* The string hit the right hand edge, so wrap around to the
* next line by going back round the while loop, unless we
* are at the end of the buffer - in which case we simply
* abandon the remainder of the output string!
*/
X = 0;
Y++;
if (Y >= ScreenInfo->ScreenBufferSize.Y) {
break; // abandon output, string is truncated
}
} else {
break;
}
}
} else if (StringType == CONSOLE_ATTRIBUTE) {
PWORD SourcePtr=Buffer;
PATTR_PAIR AttrBuf;
ATTR_PAIR Attrs[80];
PATTR_PAIR Attr;
SHORT AttrLength;
AttrBuf = Attrs;
if (ScreenInfo->ScreenBufferSize.X > 80) {
AttrBuf = ConsoleHeapAlloc(TMP_TAG, ScreenInfo->ScreenBufferSize.X * sizeof(ATTR_PAIR));
if (AttrBuf == NULL)
return STATUS_NO_MEMORY;
}
#ifdef WWSB_FE
{
COORD TPoint;
TPoint.X = X;
TPoint.Y = Y;
if ((ULONG)(ScreenInfo->ScreenBufferSize.X - X) >= (*NumRecords - NumWritten)) {
BisectWriteAttr((SHORT)(*NumRecords-NumWritten),TPoint,ScreenInfo);
}
else{
BisectWriteAttr((SHORT)(ScreenInfo->ScreenBufferSize.X-X),TPoint,ScreenInfo);
}
}
#endif
while (TRUE) {
//
// copy the attrs into the screen buffer arrays
//
Row = &ScreenInfo->BufferInfo.TextInfo.Rows[RowIndex];
Attr = AttrBuf;
Attr->Length = 0;
#ifdef WWSB_FE
Attr->Attr = *SourcePtr & ~COMMON_LVB_SBCSDBCS;
#else
Attr->Attr = *SourcePtr;
#endif
AttrLength = 1;
for (j=X;j<ScreenInfo->ScreenBufferSize.X;j++,SourcePtr++) {
#ifdef WWSB_FE
if (Attr->Attr == (*SourcePtr & ~COMMON_LVB_SBCSDBCS))
#else
if (Attr->Attr == *SourcePtr)
#endif
{
Attr->Length += 1;
}
else {
Attr++;
Attr->Length = 1;
#ifdef WWSB_FE
Attr->Attr = *SourcePtr & ~COMMON_LVB_SBCSDBCS;
#else
Attr->Attr = *SourcePtr;
#endif
AttrLength += 1;
}
NumWritten++;
X++;
if (NumWritten == *NumRecords) {
break;
}
}
X--;
// recalculate last non-space char
//
// see if attr string is different. if so, allocate a new
// attr buffer and merge the two strings.
//
if (AttrLength != Row->AttrRow.Length ||
memcmp(Row->AttrRow.Attrs,AttrBuf,AttrLength*sizeof(*Attr))) {
PATTR_PAIR NewAttrs;
WORD NewAttrsLength;
if (!NT_SUCCESS(MergeAttrStrings(Row->AttrRow.Attrs,
Row->AttrRow.Length,
AttrBuf,
AttrLength,
&NewAttrs,
&NewAttrsLength,
(SHORT)((Y == WriteCoord.Y) ? WriteCoord.X : 0),
X,
Row,
ScreenInfo
))) {
if (ScreenInfo->ScreenBufferSize.X > 80) {
ConsoleHeapFree(AttrBuf);
}
ResetTextFlags(ScreenInfo,
WriteCoord.X,
WriteCoord.Y,
X,
Y);
return STATUS_NO_MEMORY;
}
if (Row->AttrRow.Length > 1) {
ConsoleHeapFree(Row->AttrRow.Attrs);
}
else {
ASSERT(Row->AttrRow.Attrs == &Row->AttrRow.AttrPair);
}
Row->AttrRow.Attrs = NewAttrs;
Row->AttrRow.Length = NewAttrsLength;
Row->CharRow.OldLeft = INVALID_OLD_LENGTH;
Row->CharRow.OldRight = INVALID_OLD_LENGTH;
}
if (++RowIndex == ScreenInfo->ScreenBufferSize.Y) {
RowIndex = 0;
}
if (NumWritten < *NumRecords) {
X = 0;
Y++;
if (Y>=ScreenInfo->ScreenBufferSize.Y) {
break;
}
} else {
break;
}
}
ResetTextFlags(ScreenInfo,
WriteCoord.X,
WriteCoord.Y,
X,
Y);
if (ScreenInfo->ScreenBufferSize.X > 80) {
ConsoleHeapFree(AttrBuf);
}
} else {
*NumRecords = 0;
return STATUS_INVALID_PARAMETER;
}
if ((StringType == CONSOLE_ASCII) && (TransBuffer != NULL)) {
#ifdef WWSB_FE
if (fLocalHeap) {
ConsoleHeapFree(TransBuffer);
ConsoleHeapFree(TransBufferA);
}
#else
ConsoleHeapFree(TransBuffer);
#endif
}
#ifdef WWSB_FE
else if ((StringType == CONSOLE_FALSE_UNICODE) || (StringType == CONSOLE_REAL_UNICODE)) {
if (fLocalHeap) {
ConsoleHeapFree(TransBuffer);
ConsoleHeapFree(TransBufferA);
}
NumWritten = NumRecordsSavedForUnicode - (*NumRecords - NumWritten);
}
#endif
//
// determine write region. if we're still on the same line we started
// on, left X is the X we started with and right X is the one we're on
// now. otherwise, left X is 0 and right X is the rightmost column of
// the screen buffer.
//
// then update the screen.
//
WriteRegion.Top = WriteCoord.Y;
WriteRegion.Bottom = Y;
if (Y != WriteCoord.Y) {
WriteRegion.Left = 0;
WriteRegion.Right = (SHORT)(ScreenInfo->ScreenBufferSize.X-1);
}
else {
WriteRegion.Left = WriteCoord.X;
WriteRegion.Right = X;
}
WWSB_WriteToScreen(ScreenInfo,&WriteRegion);
if (NumColumns) {
*NumColumns = X + (WriteCoord.Y - Y) * ScreenInfo->ScreenBufferSize.X - WriteCoord.X + 1;
}
*NumRecords = NumWritten;
return STATUS_SUCCESS;
}
NTSTATUS
WWSB_FillOutput(
IN PSCREEN_INFORMATION ScreenInfo,
IN WORD Element,
IN COORD WriteCoord,
IN ULONG ElementType,
IN OUT PULONG Length // this value is valid even for error cases
)
/*++
Routine Description:
This routine fills the screen buffer with the specified character or
attribute.
Arguments:
ScreenInfo - Pointer to screen buffer information.
Element - Element to write.
WriteCoord - Screen buffer coordinate to begin writing to.
ElementType
CONSOLE_ASCII - element is an ascii character.
CONSOLE_REAL_UNICODE - element is a real unicode character. These will
get converted to False Unicode as required.
CONSOLE_FALSE_UNICODE - element is a False Unicode character.
CONSOLE_ATTRIBUTE - element is an attribute.
Length - On input, the number of elements to write. On output,
the number of elements written.
Return Value:
--*/
{
ULONG NumWritten;
SHORT X,Y,LeftX;
SMALL_RECT WriteRegion;
PROW Row;
PWCHAR Char;
SHORT RowIndex;
SHORT j;
#ifdef WWSB_FE
PCHAR AttrP;
#endif
DBGOUTPUT(("FillOutput\n"));
if (*Length == 0)
return STATUS_SUCCESS;
NumWritten = 0;
X=WriteCoord.X;
Y=WriteCoord.Y;
if (X>=ScreenInfo->ScreenBufferSize.X ||
X<0 ||
Y>=ScreenInfo->ScreenBufferSize.Y ||
Y<0) {
*Length = 0;
return STATUS_SUCCESS;
}
#ifdef WWSB_FE
ASSERT(ScreenInfo->Flags & CONSOLE_TEXTMODE_BUFFER);
#endif
ScreenInfo->BufferInfo.TextInfo.Flags |= TEXT_VALID_HINT;
RowIndex = (ScreenInfo->BufferInfo.TextInfo.FirstRow+WriteCoord.Y) % ScreenInfo->ScreenBufferSize.Y;
if (ElementType == CONSOLE_ASCII) {
UINT Codepage;
if ((ScreenInfo->Flags & CONSOLE_OEMFONT_DISPLAY) &&
((ScreenInfo->Console->FullScreenFlags & CONSOLE_FULLSCREEN) == 0)) {
if (ScreenInfo->Console->OutputCP != WINDOWSCP)
Codepage = USACP;
else
Codepage = WINDOWSCP;
} else {
Codepage = ScreenInfo->Console->OutputCP;
}
#ifdef WWSB_FE
if (ScreenInfo->FillOutDbcsLeadChar == 0){
if (IsDBCSLeadByteConsole((CHAR)Element,&ScreenInfo->Console->OutputCPInfo)) {
ScreenInfo->FillOutDbcsLeadChar = (CHAR)Element;
*Length = 0;
return STATUS_SUCCESS;
}else{
CHAR Char=(CHAR)Element;
ConvertOutputToUnicode(Codepage,
&Char,
1,
&Element,
1);
}
}else{
CHAR Char[2];
Char[0]=ScreenInfo->FillOutDbcsLeadChar;
Char[1]=(BYTE)Element;
ScreenInfo->FillOutDbcsLeadChar = 0;
ConvertOutputToUnicode(Codepage,
Char,
2,
&Element,
2);
}
#else
Element = SB_CharToWchar(Codepage, (CHAR)Element);
#endif
} else if (ElementType == CONSOLE_REAL_UNICODE &&
(ScreenInfo->Flags & CONSOLE_OEMFONT_DISPLAY) &&
!(ScreenInfo->Console->FullScreenFlags & CONSOLE_FULLSCREEN)) {
RealUnicodeToFalseUnicode(&Element,
1,
ScreenInfo->Console->OutputCP
);
}
if ((ElementType == CONSOLE_ASCII) ||
(ElementType == CONSOLE_REAL_UNICODE) ||
(ElementType == CONSOLE_FALSE_UNICODE)) {
#ifdef WWSB_FE
DWORD StartPosFlag ;
StartPosFlag = 0;
#endif
while (TRUE) {
//
// copy the chars into their arrays
//
LeftX = X;
Row = &ScreenInfo->BufferInfo.TextInfo.Rows[RowIndex];
Char = &Row->CharRow.Chars[X];
#ifdef WWSB_FE
AttrP = &Row->CharRow.KAttrs[X];
#endif
if ((ULONG)(ScreenInfo->ScreenBufferSize.X - X) >= (*Length - NumWritten)) {
#ifdef WWSB_FE
{
COORD TPoint;
TPoint.X = X;
TPoint.Y = Y;
BisectWrite((SHORT)(*Length-NumWritten),TPoint,ScreenInfo);
}
#endif
#ifdef WWSB_FE
if (IsConsoleFullWidth(ScreenInfo->Console->hDC,
ScreenInfo->Console->OutputCP,(WCHAR)Element)) {
for (j=0;j<(SHORT)(*Length - NumWritten);j++) {
*Char++ = (WCHAR)Element;
*AttrP &= ~ATTR_DBCSSBCS_BYTE;
if(StartPosFlag++ & 1)
*AttrP++ |= ATTR_TRAILING_BYTE;
else
*AttrP++ |= ATTR_LEADING_BYTE;
}
if(StartPosFlag & 1){
*(Char-1) = UNICODE_SPACE;
*(AttrP-1) &= ~ATTR_DBCSSBCS_BYTE;
}
}
else {
#endif
for (j=0;j<(SHORT)(*Length - NumWritten);j++) {
*Char++ = (WCHAR)Element;
#ifdef WWSB_FE
*AttrP++ &= ~ATTR_DBCSSBCS_BYTE;
#endif
}
#ifdef WWSB_FE
}
#endif
X=(SHORT)(X+*Length - NumWritten - 1);
NumWritten = *Length;
}
else {
#ifdef WWSB_FE
{
COORD TPoint;
TPoint.X = X;
TPoint.Y = Y;
BisectWrite((SHORT)(ScreenInfo->ScreenBufferSize.X-X),TPoint,ScreenInfo);
}
#endif
#ifdef WWSB_FE
if (IsConsoleFullWidth(ScreenInfo->Console->hDC,
ScreenInfo->Console->OutputCP,(WCHAR)Element)) {
for (j=0;j<ScreenInfo->ScreenBufferSize.X - X;j++) {
*Char++ = (WCHAR)Element;
*AttrP &= ~ATTR_DBCSSBCS_BYTE;
if(StartPosFlag++ & 1)
*AttrP++ |= ATTR_TRAILING_BYTE;
else
*AttrP++ |= ATTR_LEADING_BYTE;
}
}
else {
#endif
for (j=0;j<ScreenInfo->ScreenBufferSize.X - X;j++) {
*Char++ = (WCHAR)Element;
#ifdef WWSB_FE
*AttrP++ &= ~ATTR_DBCSSBCS_BYTE;
#endif
}
#ifdef WWSB_FE
}
#endif
NumWritten += ScreenInfo->ScreenBufferSize.X - X;
X = (SHORT)(ScreenInfo->ScreenBufferSize.X-1);
}
// recalculate first and last non-space char
Row->CharRow.OldLeft = Row->CharRow.Left;
if (LeftX < Row->CharRow.Left) {
if (Element == UNICODE_SPACE) {
Row->CharRow.Left = X+1;
} else {
Row->CharRow.Left = LeftX;
}
}
Row->CharRow.OldRight = Row->CharRow.Right;
if ((X+1) >= Row->CharRow.Right) {
if (Element == UNICODE_SPACE) {
Row->CharRow.Right = LeftX;
} else {
Row->CharRow.Right = X+1;
}
}
if (++RowIndex == ScreenInfo->ScreenBufferSize.Y) {
RowIndex = 0;
}
if (NumWritten < *Length) {
X = 0;
Y++;
if (Y>=ScreenInfo->ScreenBufferSize.Y) {
break;
}
} else {
break;
}
}
} else if (ElementType == CONSOLE_ATTRIBUTE) {
ATTR_PAIR Attr;
#ifdef WWSB_FE
COORD TPoint;
TPoint.X = X;
TPoint.Y = Y;
if ((ULONG)(ScreenInfo->ScreenBufferSize.X - X) >= (*Length - NumWritten)) {
BisectWriteAttr((SHORT)(*Length-NumWritten),TPoint,ScreenInfo);
}
else{
BisectWriteAttr((SHORT)(ScreenInfo->ScreenBufferSize.X-X),TPoint,ScreenInfo);
}
#endif
while (TRUE) {
//
// copy the attrs into the screen buffer arrays
//
Row = &ScreenInfo->BufferInfo.TextInfo.Rows[RowIndex];
if ((ULONG)(ScreenInfo->ScreenBufferSize.X - X) >= (*Length - NumWritten)) {
X=(SHORT)(X+*Length - NumWritten - 1);
NumWritten = *Length;
}
else {
NumWritten += ScreenInfo->ScreenBufferSize.X - X;
X = (SHORT)(ScreenInfo->ScreenBufferSize.X-1);
}
// recalculate last non-space char
//
// merge the two attribute strings.
//
Attr.Length = (SHORT)((Y == WriteCoord.Y) ? (X-WriteCoord.X+1) : (X+1));
#ifdef WWSB_FE
Attr.Attr = Element & ~COMMON_LVB_SBCSDBCS;
#else
Attr.Attr = Element;
#endif
if (1 != Row->AttrRow.Length ||
memcmp(Row->AttrRow.Attrs,&Attr,sizeof(Attr))) {
PATTR_PAIR NewAttrs;
WORD NewAttrsLength;
if (!NT_SUCCESS(MergeAttrStrings(Row->AttrRow.Attrs,
Row->AttrRow.Length,
&Attr,
1,
&NewAttrs,
&NewAttrsLength,
(SHORT)(X-Attr.Length+1),
X,
Row,
ScreenInfo
))) {
ResetTextFlags(ScreenInfo,
WriteCoord.X,
WriteCoord.Y,
X,
Y);
return STATUS_NO_MEMORY;
}
if (Row->AttrRow.Length > 1) {
ConsoleHeapFree(Row->AttrRow.Attrs);
}
else {
ASSERT(Row->AttrRow.Attrs == &Row->AttrRow.AttrPair);
}
Row->AttrRow.Attrs = NewAttrs;
Row->AttrRow.Length = NewAttrsLength;
Row->CharRow.OldLeft = INVALID_OLD_LENGTH;
Row->CharRow.OldRight = INVALID_OLD_LENGTH;
}
if (++RowIndex == ScreenInfo->ScreenBufferSize.Y) {
RowIndex = 0;
}
if (NumWritten < *Length) {
X = 0;
Y++;
if (Y>=ScreenInfo->ScreenBufferSize.Y) {
break;
}
} else {
break;
}
}
ResetTextFlags(ScreenInfo,
WriteCoord.X,
WriteCoord.Y,
X,
Y);
} else {
*Length = 0;
return STATUS_INVALID_PARAMETER;
}
//
// determine write region. if we're still on the same line we started
// on, left X is the X we started with and right X is the one we're on
// now. otherwise, left X is 0 and right X is the rightmost column of
// the screen buffer.
//
// then update the screen.
//
#ifdef WWSB_FE
if (ScreenInfo->ConvScreenInfo) {
WriteRegion.Top = WriteCoord.Y + ScreenInfo->Window.Left + ScreenInfo->ConvScreenInfo->CaInfo.coordConView.Y;
WriteRegion.Bottom = Y + ScreenInfo->Window.Left + ScreenInfo->ConvScreenInfo->CaInfo.coordConView.Y;
if (Y != WriteCoord.Y) {
WriteRegion.Left = 0;
WriteRegion.Right = (SHORT)(ScreenInfo->Console->CurrentScreenBuffer->ScreenBufferSize.X-1);
}
else {
WriteRegion.Left = WriteCoord.X + ScreenInfo->Window.Top + ScreenInfo->ConvScreenInfo->CaInfo.coordConView.X;
WriteRegion.Right = X + ScreenInfo->Window.Top + ScreenInfo->ConvScreenInfo->CaInfo.coordConView.X;
}
WriteConvRegionToScreen(ScreenInfo->Console->CurrentScreenBuffer,
ScreenInfo->ConvScreenInfo,
&WriteRegion
);
ScreenInfo->BisectFlag &= ~(BISECT_LEFT | BISECT_RIGHT | BISECT_TOP | BISECT_BOTTOM);
*Length = NumWritten;
return STATUS_SUCCESS;
}
#endif
WriteRegion.Top = WriteCoord.Y;
WriteRegion.Bottom = Y;
if (Y != WriteCoord.Y) {
WriteRegion.Left = 0;
WriteRegion.Right = (SHORT)(ScreenInfo->ScreenBufferSize.X-1);
}
else {
WriteRegion.Left = WriteCoord.X;
WriteRegion.Right = X;
}
WWSB_WriteToScreen(ScreenInfo,&WriteRegion);
*Length = NumWritten;
return STATUS_SUCCESS;
}
VOID
WWSB_FillRectangle(
IN CHAR_INFO Fill,
IN OUT PSCREEN_INFORMATION ScreenInfo,
IN PSMALL_RECT TargetRect
)
/*++
Routine Description:
This routine fills a rectangular region in the screen
buffer. no clipping is done.
Arguments:
Fill - element to copy to each element in target rect
ScreenInfo - pointer to screen info
TargetRect - rectangle in screen buffer to fill
Return Value:
--*/
{
SHORT i,j;
SHORT XSize;
SHORT RowIndex;
PROW Row;
PWCHAR Char;
ATTR_PAIR Attr;
#ifdef WWSB_FE
PCHAR AttrP;
BOOL Width;
#endif
DBGOUTPUT(("FillRectangle\n"));
#ifdef WWFE_SB
ASSERT(ScreenInfo->Flags & CONSOLE_TEXTMODE_BUFFER);
#endif
XSize = (SHORT)(TargetRect->Right - TargetRect->Left + 1);
ScreenInfo->BufferInfo.TextInfo.Flags |= TEXT_VALID_HINT;
RowIndex = (ScreenInfo->BufferInfo.TextInfo.FirstRow+TargetRect->Top) % ScreenInfo->ScreenBufferSize.Y;
for (i=TargetRect->Top;i<=TargetRect->Bottom;i++) {
//
// copy the chars and attrs into their respective arrays
//
#ifdef WWSB_FE
{
COORD TPoint;
TPoint.X = TargetRect->Left;
TPoint.Y = i;
BisectWrite(XSize,TPoint,ScreenInfo);
Width = IsConsoleFullWidth(ScreenInfo->Console->hDC,
ScreenInfo->Console->OutputCP,Fill.Char.UnicodeChar);
}
#endif
Row = &ScreenInfo->BufferInfo.TextInfo.Rows[RowIndex];
Char = &Row->CharRow.Chars[TargetRect->Left];
#ifdef WWSB_FE
AttrP = &Row->CharRow.KAttrs[TargetRect->Left];
#endif
for (j=0;j<XSize;j++) {
#ifdef WWSB_FE
if (Width){
if (j < XSize-1){
*Char++ = Fill.Char.UnicodeChar;
*Char++ = Fill.Char.UnicodeChar;
*AttrP++ = ATTR_LEADING_BYTE;
*AttrP++ = ATTR_TRAILING_BYTE;
j++;
}
else{
*Char++ = UNICODE_SPACE;
*AttrP++ = 0 ;
}
}
else{
#endif
*Char++ = Fill.Char.UnicodeChar;
#ifdef WWSB_FE
*AttrP++ = 0 ;
}
#endif
}
// recalculate first and last non-space char
Row->CharRow.OldLeft = Row->CharRow.Left;
if (TargetRect->Left < Row->CharRow.Left) {
if (Fill.Char.UnicodeChar == UNICODE_SPACE) {
Row->CharRow.Left = (SHORT)(TargetRect->Right+1);
}
else {
Row->CharRow.Left = (SHORT)(TargetRect->Left);
}
}
Row->CharRow.OldRight = Row->CharRow.Right;
if (TargetRect->Right >= Row->CharRow.Right) {
if (Fill.Char.UnicodeChar == UNICODE_SPACE) {
Row->CharRow.Right = (SHORT)(TargetRect->Left);
}
else {
Row->CharRow.Right = (SHORT)(TargetRect->Right+1);
}
}
Attr.Length = XSize;
Attr.Attr = Fill.Attributes;
//
// merge the two attribute strings.
//
if (1 != Row->AttrRow.Length ||
memcmp(Row->AttrRow.Attrs,&Attr,sizeof(Attr))) {
PATTR_PAIR NewAttrs;
WORD NewAttrsLength;
if (!NT_SUCCESS(MergeAttrStrings(Row->AttrRow.Attrs,
Row->AttrRow.Length,
&Attr,
1,
&NewAttrs,
&NewAttrsLength,
TargetRect->Left,
TargetRect->Right,
Row,
ScreenInfo
))) {
ResetTextFlags(ScreenInfo,
TargetRect->Left,
TargetRect->Top,
TargetRect->Right,
TargetRect->Bottom);
return;
}
if (Row->AttrRow.Length > 1) {
ConsoleHeapFree(Row->AttrRow.Attrs);
}
else {
ASSERT(Row->AttrRow.Attrs == &Row->AttrRow.AttrPair);
}
Row->AttrRow.Attrs = NewAttrs;
Row->AttrRow.Length = NewAttrsLength;
Row->CharRow.OldLeft = INVALID_OLD_LENGTH;
Row->CharRow.OldRight = INVALID_OLD_LENGTH;
}
if (++RowIndex == ScreenInfo->ScreenBufferSize.Y) {
RowIndex = 0;
}
}
ResetTextFlags(ScreenInfo,
TargetRect->Left,
TargetRect->Top,
TargetRect->Right,
TargetRect->Bottom);
}
BOOL
WWSB_PolyTextOutCandidate(
IN PSCREEN_INFORMATION ScreenInfo,
IN PSMALL_RECT Region
)
/*
This function returns TRUE if the input region is reasonable to
pass to ConsolePolyTextOut. The criteria are that there is only
one attribute per line.
*/
{
SHORT RowIndex;
PROW Row;
SHORT i;
#ifdef WWSB_FE
if((ScreenInfo->Console->Flags & CONSOLE_VDM_REGISTERED &&
((PEUDC_INFORMATION)(ScreenInfo->Console->EudcInformation))->LocalVDMEudcMode)){
return FALSE;
}
if (!(ScreenInfo->Flags & CONSOLE_OEMFONT_DISPLAY) &&
!(ScreenInfo->Console->FullScreenFlags & CONSOLE_FULLSCREEN) &&
((PEUDC_INFORMATION)(ScreenInfo->Console->EudcInformation))->LocalKeisenEudcMode
) {
return FALSE;
}
ASSERT(ScreenInfo->Flags & CONSOLE_TEXTMODE_BUFFER);
if (ScreenInfo->BufferInfo.TextInfo.Flags & CONSOLE_CONVERSION_AREA_REDRAW) {
return FALSE;
}
#endif
if (ScreenInfo->BufferInfo.TextInfo.Flags & SINGLE_ATTRIBUTES_PER_LINE) {
return TRUE;
}
//
// make sure there is only one attr per line.
//
RowIndex = (ScreenInfo->BufferInfo.TextInfo.FirstRow+Region->Top) % ScreenInfo->ScreenBufferSize.Y;
for (i=Region->Top;i<=Region->Bottom;i++) {
Row = &ScreenInfo->BufferInfo.TextInfo.Rows[RowIndex];
if (Row->AttrRow.Length != 1) {
return FALSE;
}
if (++RowIndex == ScreenInfo->ScreenBufferSize.Y) {
RowIndex = 0;
}
}
return TRUE;
}
#define MAX_POLY_LINES 80
#define VERY_BIG_NUMBER 0x0FFFFFFF
#ifdef WWSB_FE
typedef struct _KEISEN_INFORMATION {
COORD Coord;
WORD n;
} KEISEN_INFORMATION, *PKEISEN_INFORMATION;
#endif
VOID
WWSB_ConsolePolyTextOut(
IN PSCREEN_INFORMATION ScreenInfo,
IN PSMALL_RECT Region
)
/*
This function calls PolyTextOut. The only restriction is that
there can't be more than one attribute per line in the region.
*/
{
PROW Row,LastRow;
SHORT i,k;
WORD Attr;
POLYTEXTW TextInfo[MAX_POLY_LINES];
RECT TextRect;
RECTL BoundingRect;
int xSize = SCR_FONTSIZE(ScreenInfo).X;
int ySize = SCR_FONTSIZE(ScreenInfo).Y;
ULONG Flags = ScreenInfo->BufferInfo.TextInfo.Flags;
int WindowLeft = ScreenInfo->Window.Left;
int RegionLeft = Region->Left;
int RegionRight = Region->Right + 1;
int DefaultLeft = (RegionLeft - WindowLeft) * xSize;
int DefaultRight = (RegionRight - WindowLeft) * xSize;
PCONSOLE_INFORMATION Console = ScreenInfo->Console;
PWCHAR TransPolyTextOut = NULL ;
#ifdef WWSB_FE
KEISEN_INFORMATION KeisenInfo[MAX_POLY_LINES];
SHORT j;
WORD OldAttr;
#endif
//
// initialize the text rect and window position.
//
TextRect.top = (Region->Top - ScreenInfo->Window.Top) * ySize;
// TextRect.bottom is invalid.
BoundingRect.top = TextRect.top;
BoundingRect.left = VERY_BIG_NUMBER;
BoundingRect.right = 0;
//
// copy the chars and attrs from their respective arrays
//
Row = &ScreenInfo->BufferInfo.TextInfo.Rows
[ScreenInfo->BufferInfo.TextInfo.FirstRow+Region->Top];
LastRow = &ScreenInfo->BufferInfo.TextInfo.Rows[ScreenInfo->ScreenBufferSize.Y];
if (Row >= LastRow)
Row -= ScreenInfo->ScreenBufferSize.Y;
Attr = Row->AttrRow.AttrPair.Attr;
if (Console->LastAttributes != Attr) {
#ifdef WWSB_FE
if (Attr & COMMON_LVB_REVERSE_VIDEO)
{
SetBkColor(Console->hDC, ConvertAttrToRGB(Console, LOBYTE(Attr)));
SetTextColor(Console->hDC, ConvertAttrToRGB(Console, LOBYTE(Attr >> 4)));
}
else{
#endif
SetTextColor(Console->hDC, ConvertAttrToRGB(Console, LOBYTE(Attr)));
SetBkColor(Console->hDC, ConvertAttrToRGB(Console, LOBYTE(Attr >> 4)));
#ifdef WWSB_FE
}
#endif
Console->LastAttributes = Attr;
}
TransPolyTextOut = ConsoleHeapAlloc(TMP_DBCS_TAG,
ScreenInfo->ScreenBufferSize.X * MAX_POLY_LINES * sizeof(WCHAR));
if (TransPolyTextOut == NULL) {
RIPMSG0(RIP_WARNING, "ConsoleTextOut cannot allocate memory");
return;
}
for (i=Region->Top;i<=Region->Bottom;) {
PWCHAR TmpChar;
TmpChar = TransPolyTextOut;
for(k=0;i<=Region->Bottom&&k<MAX_POLY_LINES;i++) {
SHORT NumberOfChars;
SHORT LeftChar,RightChar;
//
// make the bounding rect smaller, if we can. the TEXT_VALID_HINT
// flag gets set each time we write to the screen buffer. it gets
// turned off any time we get asked to redraw the screen
// and we don't know exactly what needs to be redrawn
// (i.e. paint messages).
//
// we have the left and right bounds of the text on the
// line. the opaqueing rectangle and the number of
// chars get set according to those values.
//
TextRect.left = DefaultLeft;
TextRect.right = DefaultRight;
if (Flags & TEXT_VALID_HINT)
{
// We compute an opaquing interval. If A is the old interval of text,
// B is the new interval, and R is the Region, then the opaquing interval
// must be R*(A+B), where * represents intersection and + represents union.
if (Row->CharRow.OldLeft != INVALID_OLD_LENGTH)
{
// The min determines the left of (A+B). The max intersects that with
// the left of the region.
TextRect.left = (
max
(
min
(
Row->CharRow.Left,
Row->CharRow.OldLeft
),
RegionLeft
)
-WindowLeft
) * xSize;
}
if (Row->CharRow.OldRight != INVALID_OLD_LENGTH)
{
// The max determines the right of (A+B). The min intersects that with
// the right of the region.
TextRect.right = (
min
(
max
(
Row->CharRow.Right,
Row->CharRow.OldRight
),
RegionRight
)
-WindowLeft
) * xSize;
}
}
//
// We've got to draw any new text that appears in the region, so we just
// intersect the new text interval with the region.
//
LeftChar = max(Row->CharRow.Left,RegionLeft);
RightChar = min(Row->CharRow.Right,RegionRight);
NumberOfChars = RightChar - LeftChar;
#ifdef WWSB_FE
if (Row->CharRow.KAttrs[RightChar-1] & ATTR_LEADING_BYTE){
if(TextRect.right <= ScreenInfo->Window.Right*xSize) {
TextRect.right += xSize;
}
}
#endif
//
// Empty rows are represented by CharRow.Right=0, CharRow.Left=MAX, so we
// may have NumberOfChars<0 at this point if there is no text that needs
// drawing. (I.e. the intersection was empty.)
//
if (NumberOfChars < 0) {
NumberOfChars = 0;
LeftChar = 0;
RightChar = 0;
}
//
// We may also have TextRect.right<TextRect.left if the screen
// is already cleared, and we really don't need to do anything at all.
//
if (TextRect.right > TextRect.left)
{
NumberOfChars = (SHORT)RemoveDbcsMarkAll(ScreenInfo,Row,&LeftChar,&TextRect,NULL,TmpChar,NumberOfChars);
TextInfo[k].x = (LeftChar-WindowLeft) * xSize;
TextInfo[k].y = TextRect.top;
TextRect.bottom = TextRect.top + ySize;
TextInfo[k].n = NumberOfChars;
TextInfo[k].lpstr = TmpChar;
#ifdef WWSB_FE
if (CheckBisectStringW(ScreenInfo,
Console->OutputCP,
TmpChar,
NumberOfChars,
(TextRect.right-max(TextRect.left,TextInfo[k].x))/xSize
)
) {
TextRect.right += xSize;
}
#endif
TmpChar += NumberOfChars;
TextInfo[k].rcl = TextRect;
TextInfo[k].pdx = NULL;
TextInfo[k].uiFlags = ETO_OPAQUE;
#ifdef WWSB_FE
KeisenInfo[k].n = DefaultRight-DefaultLeft ;
KeisenInfo[k].Coord.Y = (WORD)TextRect.top;
KeisenInfo[k].Coord.X = (WORD)DefaultLeft;
#endif
k++;
if (BoundingRect.left > TextRect.left) {
BoundingRect.left = TextRect.left;
}
if (BoundingRect.right < TextRect.right) {
BoundingRect.right = TextRect.right;
}
}
// Advance the high res bounds.
TextRect.top += ySize;
// Advance the row pointer.
if (++Row >= LastRow)
Row = ScreenInfo->BufferInfo.TextInfo.Rows;
// Draw now if the attributes are about to change.
#ifdef WWSB_FE
OldAttr = Attr ;
#endif
if (Attr != Row->AttrRow.AttrPair.Attr) {
Attr = Row->AttrRow.AttrPair.Attr;
i++;
break;
}
}
if (k)
{
BoundingRect.bottom = TextRect.top;
ASSERT(BoundingRect.left != VERY_BIG_NUMBER);
ASSERT(BoundingRect.left <= BoundingRect.right);
ASSERT(BoundingRect.top <= BoundingRect.bottom);
GdiConsoleTextOut(Console->hDC,
TextInfo,
k,
&BoundingRect);
#ifdef WWSB_FE
for ( j = 0 ; j < k ; j++){
RECT TextRect;
TextRect.left = KeisenInfo[j].Coord.X;
TextRect.top = KeisenInfo[j].Coord.Y;
TextRect.right = KeisenInfo[j].n + TextRect.left;
TextRect.bottom = KeisenInfo[j].Coord.Y + ySize;
TextOutCommonLVB(ScreenInfo->Console, OldAttr, TextRect);
}
#endif
}
if (Console->LastAttributes != Attr) {
#ifdef WWSB_FE
if (Attr & COMMON_LVB_REVERSE_VIDEO)
{
SetBkColor(Console->hDC, ConvertAttrToRGB(Console, LOBYTE(Attr)));
SetTextColor(Console->hDC, ConvertAttrToRGB(Console, LOBYTE(Attr >> 4)));
}
else{
#endif
SetTextColor(Console->hDC, ConvertAttrToRGB(Console, LOBYTE(Attr)));
SetBkColor(Console->hDC, ConvertAttrToRGB(Console, LOBYTE(Attr >> 4)));
#ifdef WWSB_FE
}
#endif
Console->LastAttributes = Attr;
BoundingRect.top = TextRect.top;
BoundingRect.left = VERY_BIG_NUMBER;
BoundingRect.right = 0;
}
}
GdiFlush();
ConsoleHeapFree(TransPolyTextOut);
}