[CONSRV] Miscellaneous console fixes for CJK support and screenbuffer iteration. (#2278)

+ popup.c!DrawBox(): Factor out setting the attribute value.
This commit is contained in:
Hermès Bélusca-Maïto 2020-02-09 22:22:52 +01:00
parent ce3a0af4f0
commit d46e054368
No known key found for this signature in database
GPG key ID: 3B2539C65E7B93D0
4 changed files with 614 additions and 485 deletions

File diff suppressed because it is too large Load diff

View file

@ -510,7 +510,12 @@ ConioWriteConsole(PFRONTEND FrontEnd,
SMALL_RECT UpdateRect; SMALL_RECT UpdateRect;
SHORT CursorStartX, CursorStartY; SHORT CursorStartX, CursorStartY;
UINT ScrolledLines; UINT ScrolledLines;
BOOL bCJK = Console->IsCJK; BOOLEAN bFullwidth;
BOOLEAN bCJK = Console->IsCJK;
/* If nothing to write, bail out now */
if (Length == 0)
return STATUS_SUCCESS;
CursorStartX = Buff->CursorPosition.X; CursorStartX = Buff->CursorPosition.X;
CursorStartY = Buff->CursorPosition.Y; CursorStartY = Buff->CursorPosition.Y;
@ -532,28 +537,32 @@ ConioWriteConsole(PFRONTEND FrontEnd,
if (Buffer[i] == L'\r') if (Buffer[i] == L'\r')
{ {
Buff->CursorPosition.X = 0; Buff->CursorPosition.X = 0;
UpdateRect.Left = min(UpdateRect.Left, Buff->CursorPosition.X); CursorStartX = Buff->CursorPosition.X;
UpdateRect.Left = min(UpdateRect.Left , Buff->CursorPosition.X);
UpdateRect.Right = max(UpdateRect.Right, Buff->CursorPosition.X); UpdateRect.Right = max(UpdateRect.Right, Buff->CursorPosition.X);
continue; continue;
} }
/* --- LF --- */ /* --- LF --- */
else if (Buffer[i] == L'\n') else if (Buffer[i] == L'\n')
{ {
Buff->CursorPosition.X = 0; Buff->CursorPosition.X = 0; // TODO: Make this behaviour optional!
CursorStartX = Buff->CursorPosition.X;
ConioNextLine(Buff, &UpdateRect, &ScrolledLines); ConioNextLine(Buff, &UpdateRect, &ScrolledLines);
continue; continue;
} }
/* --- BS --- */ /* --- BS --- */
else if (Buffer[i] == L'\b') else if (Buffer[i] == L'\b')
{ {
/* Only handle BS if we're not on the first pos of the first line */ /* Only handle BS if we are not on the first position of the first line */
if (0 != Buff->CursorPosition.X || 0 != Buff->CursorPosition.Y) if (Buff->CursorPosition.X == 0 && Buff->CursorPosition.Y == 0)
continue;
if (Buff->CursorPosition.X == 0)
{ {
if (0 == Buff->CursorPosition.X) /* Slide virtual position up */
{
/* slide virtual position up */
Buff->CursorPosition.X = Buff->ScreenBufferSize.X - 1; Buff->CursorPosition.X = Buff->ScreenBufferSize.X - 1;
Buff->CursorPosition.Y--; Buff->CursorPosition.Y--;
// TODO? : Update CursorStartY = Buff->CursorPosition.Y;
UpdateRect.Top = min(UpdateRect.Top, Buff->CursorPosition.Y); UpdateRect.Top = min(UpdateRect.Top, Buff->CursorPosition.Y);
} }
else else
@ -561,22 +570,57 @@ ConioWriteConsole(PFRONTEND FrontEnd,
Buff->CursorPosition.X--; Buff->CursorPosition.X--;
} }
Ptr = ConioCoordToPointer(Buff, Buff->CursorPosition.X, Buff->CursorPosition.Y); Ptr = ConioCoordToPointer(Buff, Buff->CursorPosition.X, Buff->CursorPosition.Y);
Ptr->Char.UnicodeChar = L' ';
if (Ptr->Attributes & COMMON_LVB_LEADING_BYTE)
{
/*
* The cursor just moved on the leading byte of the same
* current character. We should go one position before to
* go to the actual previous character to erase.
*/
/* Only handle BS if we are not on the first position of the first line */
if (Buff->CursorPosition.X == 0 && Buff->CursorPosition.Y == 0)
continue;
if (Buff->CursorPosition.X == 0)
{
/* Slide virtual position up */
Buff->CursorPosition.X = Buff->ScreenBufferSize.X - 1;
Buff->CursorPosition.Y--;
// TODO? : Update CursorStartY = Buff->CursorPosition.Y;
UpdateRect.Top = min(UpdateRect.Top, Buff->CursorPosition.Y);
}
else
{
Buff->CursorPosition.X--;
}
Ptr = ConioCoordToPointer(Buff, Buff->CursorPosition.X, Buff->CursorPosition.Y);
}
if (Ptr->Attributes & COMMON_LVB_TRAILING_BYTE) if (Ptr->Attributes & COMMON_LVB_TRAILING_BYTE)
{ {
/* Delete a full-width character */ /* The cursor is on the trailing byte of a full-width character */
/* Delete its trailing byte... */
Ptr->Char.UnicodeChar = L' ';
if (Attrib)
Ptr->Attributes = Buff->ScreenDefaultAttrib; Ptr->Attributes = Buff->ScreenDefaultAttrib;
Ptr->Attributes &= ~COMMON_LVB_SBCSDBCS;
if (Buff->CursorPosition.X > 0) if (Buff->CursorPosition.X > 0)
Buff->CursorPosition.X--; Buff->CursorPosition.X--;
/* ... and now its leading byte */
Ptr = ConioCoordToPointer(Buff, Buff->CursorPosition.X, Buff->CursorPosition.Y); Ptr = ConioCoordToPointer(Buff, Buff->CursorPosition.X, Buff->CursorPosition.Y);
Ptr->Char.UnicodeChar = L' ';
} }
Ptr->Char.UnicodeChar = L' ';
if (Attrib)
Ptr->Attributes = Buff->ScreenDefaultAttrib; Ptr->Attributes = Buff->ScreenDefaultAttrib;
UpdateRect.Left = min(UpdateRect.Left, Buff->CursorPosition.X); Ptr->Attributes &= ~COMMON_LVB_SBCSDBCS;
UpdateRect.Left = min(UpdateRect.Left , Buff->CursorPosition.X);
UpdateRect.Right = max(UpdateRect.Right, Buff->CursorPosition.X); UpdateRect.Right = max(UpdateRect.Right, Buff->CursorPosition.X);
}
continue; continue;
} }
/* --- TAB --- */ /* --- TAB --- */
@ -584,28 +628,60 @@ ConioWriteConsole(PFRONTEND FrontEnd,
{ {
UINT EndX; UINT EndX;
Ptr = ConioCoordToPointer(Buff, Buff->CursorPosition.X, Buff->CursorPosition.Y);
if (Ptr->Attributes & COMMON_LVB_TRAILING_BYTE)
{
/*
* The cursor is on the trailing byte of a full-width character.
* Go back one position to be on its leading byte.
*/
if (Buff->CursorPosition.X > 0)
Buff->CursorPosition.X--;
Ptr = ConioCoordToPointer(Buff, Buff->CursorPosition.X, Buff->CursorPosition.Y);
}
UpdateRect.Left = min(UpdateRect.Left, Buff->CursorPosition.X); UpdateRect.Left = min(UpdateRect.Left, Buff->CursorPosition.X);
EndX = (Buff->CursorPosition.X + TAB_WIDTH) & ~(TAB_WIDTH - 1); EndX = (Buff->CursorPosition.X + TAB_WIDTH) & ~(TAB_WIDTH - 1);
EndX = min(EndX, (UINT)Buff->ScreenBufferSize.X); EndX = min(EndX, (UINT)Buff->ScreenBufferSize.X);
Ptr = ConioCoordToPointer(Buff, Buff->CursorPosition.X, Buff->CursorPosition.Y);
while ((UINT)Buff->CursorPosition.X < EndX) while ((UINT)Buff->CursorPosition.X < EndX)
{ {
Ptr->Char.UnicodeChar = L' '; Ptr->Char.UnicodeChar = L' ';
if (Attrib)
Ptr->Attributes = Buff->ScreenDefaultAttrib; Ptr->Attributes = Buff->ScreenDefaultAttrib;
Ptr->Attributes &= ~COMMON_LVB_SBCSDBCS;
++Ptr; ++Ptr;
Buff->CursorPosition.X++; Buff->CursorPosition.X++;
} }
UpdateRect.Right = max(UpdateRect.Right, Buff->CursorPosition.X - 1); if (Buff->CursorPosition.X < Buff->ScreenBufferSize.X)
if (Buff->CursorPosition.X == Buff->ScreenBufferSize.X) {
/* If the following cell is the trailing byte of a full-width character, reset it */
if (Ptr->Attributes & COMMON_LVB_TRAILING_BYTE)
{
Ptr->Char.UnicodeChar = L' ';
if (Attrib)
Ptr->Attributes = Buff->ScreenDefaultAttrib;
Ptr->Attributes &= ~COMMON_LVB_SBCSDBCS;
}
}
UpdateRect.Right = max(UpdateRect.Right, Buff->CursorPosition.X);
if (Buff->CursorPosition.X >= Buff->ScreenBufferSize.X)
{ {
if (Buff->Mode & ENABLE_WRAP_AT_EOL_OUTPUT) if (Buff->Mode & ENABLE_WRAP_AT_EOL_OUTPUT)
{ {
/* Wrapping mode: Go to next line */
Buff->CursorPosition.X = 0; Buff->CursorPosition.X = 0;
CursorStartX = Buff->CursorPosition.X;
ConioNextLine(Buff, &UpdateRect, &ScrolledLines); ConioNextLine(Buff, &UpdateRect, &ScrolledLines);
} }
else else
{ {
Buff->CursorPosition.X--; /* The cursor wraps back to its starting position on the same line */
Buff->CursorPosition.X = CursorStartX;
} }
} }
continue; continue;
@ -617,84 +693,126 @@ ConioWriteConsole(PFRONTEND FrontEnd,
continue; continue;
} }
} }
UpdateRect.Left = min(UpdateRect.Left, Buff->CursorPosition.X); UpdateRect.Left = min(UpdateRect.Left , Buff->CursorPosition.X);
UpdateRect.Right = max(UpdateRect.Right, Buff->CursorPosition.X); UpdateRect.Right = max(UpdateRect.Right, Buff->CursorPosition.X);
/* For Chinese, Japanese and Korean */ /* For Chinese, Japanese and Korean */
if (bCJK && Buffer[i] >= 0x80 && mk_wcwidth_cjk(Buffer[i]) == 2) bFullwidth = (bCJK && IS_FULL_WIDTH(Buffer[i]));
{
/* Buffer[i] is a fullwidth character */
if (Buff->CursorPosition.X > 0) /* Check whether we can insert the full-width character */
if (bFullwidth)
{ {
/* Kill the previous leading byte */ /* It spans two cells and should all fit on the current line */
Ptr = ConioCoordToPointer(Buff, Buff->CursorPosition.X - 1, Buff->CursorPosition.Y); if (Buff->CursorPosition.X >= Buff->ScreenBufferSize.X - 1)
if (Ptr->Attributes & COMMON_LVB_LEADING_BYTE)
{ {
Ptr->Char.UnicodeChar = L' ';
if (Attrib)
Ptr->Attributes &= ~COMMON_LVB_LEADING_BYTE;
}
}
if (Buff->CursorPosition.X == Buff->ScreenBufferSize.X - 1)
{
/* New line */
if (Buff->Mode & ENABLE_WRAP_AT_EOL_OUTPUT) if (Buff->Mode & ENABLE_WRAP_AT_EOL_OUTPUT)
{ {
/* Wrapping mode: Go to next line */
Buff->CursorPosition.X = 0; Buff->CursorPosition.X = 0;
CursorStartX = Buff->CursorPosition.X;
ConioNextLine(Buff, &UpdateRect, &ScrolledLines); ConioNextLine(Buff, &UpdateRect, &ScrolledLines);
} }
else else
{ {
/* The cursor wraps back to its starting position on the same line */
Buff->CursorPosition.X = CursorStartX; Buff->CursorPosition.X = CursorStartX;
} }
} }
/* Set leading */ /*
Ptr = ConioCoordToPointer(Buff, Buff->CursorPosition.X, Buff->CursorPosition.Y); * Now be sure we can fit the full-width character.
Ptr->Char.UnicodeChar = Buffer[i]; * If the screenbuffer is one cell wide we cannot display
if (Attrib) * the full-width character, so just skip it.
Ptr->Attributes = Buff->ScreenDefaultAttrib | COMMON_LVB_LEADING_BYTE; */
if (Buff->CursorPosition.X >= Buff->ScreenBufferSize.X - 1)
/* Set trailing */
Buff->CursorPosition.X++;
Ptr = ConioCoordToPointer(Buff, Buff->CursorPosition.X, Buff->CursorPosition.Y);
if (Attrib)
Ptr->Attributes = Buff->ScreenDefaultAttrib | COMMON_LVB_TRAILING_BYTE;
}
else
{ {
DPRINT1("Cannot display full-width character! CursorPosition.X = %d, ScreenBufferSize.X = %d\n",
Buff->CursorPosition.X, Buff->ScreenBufferSize.X);
continue;
}
}
Ptr = ConioCoordToPointer(Buff, Buff->CursorPosition.X, Buff->CursorPosition.Y); Ptr = ConioCoordToPointer(Buff, Buff->CursorPosition.X, Buff->CursorPosition.Y);
/*
* Check whether we are overwriting part of a full-width character,
* in which case we need to invalidate it.
*/
if (Ptr->Attributes & COMMON_LVB_TRAILING_BYTE)
{
/*
* The cursor is on the trailing byte of a full-width character.
* Go back one position to kill the previous leading byte.
*/
if (Buff->CursorPosition.X > 0)
{
Ptr = ConioCoordToPointer(Buff, Buff->CursorPosition.X - 1, Buff->CursorPosition.Y);
Ptr->Char.UnicodeChar = L' ';
if (Attrib)
Ptr->Attributes = Buff->ScreenDefaultAttrib;
Ptr->Attributes &= ~COMMON_LVB_SBCSDBCS;
}
Ptr = ConioCoordToPointer(Buff, Buff->CursorPosition.X, Buff->CursorPosition.Y);
}
/* Insert the character */
if (bFullwidth)
{
ASSERT(Buff->CursorPosition.X < Buff->ScreenBufferSize.X - 1);
/* Set the leading byte */
Ptr->Char.UnicodeChar = Buffer[i]; Ptr->Char.UnicodeChar = Buffer[i];
if (Attrib) if (Attrib)
Ptr->Attributes = Buff->ScreenDefaultAttrib; Ptr->Attributes = Buff->ScreenDefaultAttrib;
} Ptr->Attributes &= ~COMMON_LVB_SBCSDBCS;
Ptr->Attributes |= COMMON_LVB_LEADING_BYTE;
/* Set the trailing byte */
Buff->CursorPosition.X++; Buff->CursorPosition.X++;
if (Buff->CursorPosition.X == Buff->ScreenBufferSize.X) Ptr = ConioCoordToPointer(Buff, Buff->CursorPosition.X, Buff->CursorPosition.Y);
{ // Ptr->Char.UnicodeChar = Buffer[i]; // L' ';
if (Buff->Mode & ENABLE_WRAP_AT_EOL_OUTPUT) if (Attrib)
{ Ptr->Attributes = Buff->ScreenDefaultAttrib;
Buff->CursorPosition.X = 0; Ptr->Attributes &= ~COMMON_LVB_SBCSDBCS;
ConioNextLine(Buff, &UpdateRect, &ScrolledLines); Ptr->Attributes |= COMMON_LVB_TRAILING_BYTE;
} }
else else
{ {
Buff->CursorPosition.X = CursorStartX; Ptr->Char.UnicodeChar = Buffer[i];
} if (Attrib)
} Ptr->Attributes = Buff->ScreenDefaultAttrib;
Ptr->Attributes &= ~COMMON_LVB_SBCSDBCS;
} }
if (bCJK && Buff->CursorPosition.X > 0) ++Ptr;
Buff->CursorPosition.X++;
if (Buff->CursorPosition.X < Buff->ScreenBufferSize.X)
{ {
/* Delete trailing */ /* If the following cell is the trailing byte of a full-width character, reset it */
Ptr = ConioCoordToPointer(Buff, Buff->CursorPosition.X, Buff->CursorPosition.Y);
if (Ptr->Attributes & COMMON_LVB_TRAILING_BYTE) if (Ptr->Attributes & COMMON_LVB_TRAILING_BYTE)
{ {
Ptr->Char.UnicodeChar = L' '; Ptr->Char.UnicodeChar = L' ';
if (Attrib) if (Attrib)
Ptr->Attributes = Buff->ScreenDefaultAttrib; Ptr->Attributes = Buff->ScreenDefaultAttrib;
Ptr->Attributes &= ~COMMON_LVB_SBCSDBCS;
}
}
if (Buff->CursorPosition.X >= Buff->ScreenBufferSize.X)
{
if (Buff->Mode & ENABLE_WRAP_AT_EOL_OUTPUT)
{
/* Wrapping mode: Go to next line */
Buff->CursorPosition.X = 0;
CursorStartX = Buff->CursorPosition.X;
ConioNextLine(Buff, &UpdateRect, &ScrolledLines);
}
else
{
/* The cursor wraps back to its starting position on the same line */
Buff->CursorPosition.X = CursorStartX;
}
} }
} }

View file

@ -372,4 +372,9 @@ NTSTATUS ConioResizeBuffer(PCONSOLE /*PCONSRV_CONSOLE*/ Console,
/* wcwidth.c */ /* wcwidth.c */
int mk_wcwidth_cjk(wchar_t ucs); int mk_wcwidth_cjk(wchar_t ucs);
// NOTE: The check against 0x80 is to avoid calling the helper function
// for characters that we already know are not full-width.
#define IS_FULL_WIDTH(wch) \
(((USHORT)(wch) >= 0x0080) && (mk_wcwidth_cjk(wch) == 2))
/* EOF */ /* EOF */

View file

@ -58,9 +58,9 @@ DrawBox(PTEXTMODE_SCREEN_BUFFER Buffer,
/* Set screen attributes */ /* Set screen attributes */
coPos.X = xLeft; coPos.X = xLeft;
Code.Attribute = Buffer->PopupDefaultAttrib;
for (coPos.Y = yTop; coPos.Y < yTop + Height; coPos.Y++) for (coPos.Y = yTop; coPos.Y < yTop + Height; coPos.Y++)
{ {
Code.Attribute = Buffer->PopupDefaultAttrib;
ConDrvFillConsoleOutput(Buffer->Header.Console, ConDrvFillConsoleOutput(Buffer->Header.Console,
Buffer, Buffer,
CODE_ATTRIBUTE, CODE_ATTRIBUTE,