Fix support of East Asian Full Width characters
* Re-enable full-width characters detection and display; * Fix cursor drawing on full-width characters; * Fix debug dump for multi-byte characters; * Fix file permissions for debug capture log. Fixes #6717. Also may improve behaviour related to #6227.
This commit is contained in:
@@ -429,7 +429,8 @@ BasicTerminalBuffer::FindWord(const TermPos& pos,
|
|||||||
|
|
||||||
// find the beginning
|
// find the beginning
|
||||||
TermPos start(x, y);
|
TermPos start(x, y);
|
||||||
TermPos end(x + (IS_WIDTH(line->cells[x].attributes) ? 2 : 1), y);
|
TermPos end(x + (IS_WIDTH(line->cells[x].attributes)
|
||||||
|
? FULL_WIDTH : HALF_WIDTH), y);
|
||||||
while (true) {
|
while (true) {
|
||||||
if (--x < 0) {
|
if (--x < 0) {
|
||||||
// Hit the beginning of the line -- continue at the end of the
|
// Hit the beginning of the line -- continue at the end of the
|
||||||
@@ -470,7 +471,7 @@ BasicTerminalBuffer::FindWord(const TermPos& pos,
|
|||||||
if (classifier->Classify(line->cells[x].character) != type)
|
if (classifier->Classify(line->cells[x].character) != type)
|
||||||
break;
|
break;
|
||||||
|
|
||||||
x += IS_WIDTH(line->cells[x].attributes) ? 2 : 1;
|
x += IS_WIDTH(line->cells[x].attributes) ? FULL_WIDTH : HALF_WIDTH;
|
||||||
end.SetTo(x, y);
|
end.SetTo(x, y);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -606,14 +607,13 @@ BasicTerminalBuffer::Find(const char* _pattern, const TermPos& start,
|
|||||||
|
|
||||||
|
|
||||||
void
|
void
|
||||||
BasicTerminalBuffer::InsertChar(UTF8Char c, uint32 width)
|
BasicTerminalBuffer::InsertChar(UTF8Char c)
|
||||||
{
|
{
|
||||||
//debug_printf("BasicTerminalBuffer::InsertChar('%.*s' (%d), %#lx)\n",
|
//debug_printf("BasicTerminalBuffer::InsertChar('%.*s' (%d), %#lx)\n",
|
||||||
//(int)c.ByteCount(), c.bytes, c.bytes[0], attributes);
|
//(int)c.ByteCount(), c.bytes, c.bytes[0], attributes);
|
||||||
if ((int32)width == FULL_WIDTH)
|
int32 width = c.IsFullWidth() ? FULL_WIDTH : HALF_WIDTH;
|
||||||
fAttributes |= A_WIDTH;
|
|
||||||
|
|
||||||
if (fSoftWrappedCursor || fCursor.x + (int32)width > fWidth)
|
if (fSoftWrappedCursor || (fCursor.x + width) > fWidth)
|
||||||
_SoftBreakLine();
|
_SoftBreakLine();
|
||||||
else
|
else
|
||||||
_PadLineToCursor();
|
_PadLineToCursor();
|
||||||
@@ -625,7 +625,8 @@ BasicTerminalBuffer::InsertChar(UTF8Char c, uint32 width)
|
|||||||
|
|
||||||
TerminalLine* line = _LineAt(fCursor.y);
|
TerminalLine* line = _LineAt(fCursor.y);
|
||||||
line->cells[fCursor.x].character = c;
|
line->cells[fCursor.x].character = c;
|
||||||
line->cells[fCursor.x].attributes = fAttributes;
|
line->cells[fCursor.x].attributes
|
||||||
|
= fAttributes | (width == FULL_WIDTH ? A_WIDTH : 0);
|
||||||
|
|
||||||
if (line->length < fCursor.x + width)
|
if (line->length < fCursor.x + width)
|
||||||
line->length = fCursor.x + width;
|
line->length = fCursor.x + width;
|
||||||
@@ -645,10 +646,13 @@ BasicTerminalBuffer::InsertChar(UTF8Char c, uint32 width)
|
|||||||
|
|
||||||
|
|
||||||
void
|
void
|
||||||
BasicTerminalBuffer::FillScreen(UTF8Char c, uint32 width, uint32 attributes)
|
BasicTerminalBuffer::FillScreen(UTF8Char c, uint32 attributes)
|
||||||
{
|
{
|
||||||
if ((int32)width == FULL_WIDTH)
|
uint32 width = HALF_WIDTH;
|
||||||
|
if (c.IsFullWidth()) {
|
||||||
attributes |= A_WIDTH;
|
attributes |= A_WIDTH;
|
||||||
|
width = FULL_WIDTH;
|
||||||
|
}
|
||||||
|
|
||||||
fSoftWrappedCursor = false;
|
fSoftWrappedCursor = false;
|
||||||
|
|
||||||
@@ -1724,7 +1728,9 @@ BasicTerminalBuffer::MakeLinesSnapshots(time_t timeStamp, const char* fileName)
|
|||||||
fprintf(fileOut, "%02" B_PRId16 ":%02" B_PRId16 ":%08" B_PRIx32 ":\n",
|
fprintf(fileOut, "%02" B_PRId16 ":%02" B_PRId16 ":%08" B_PRIx32 ":\n",
|
||||||
i, line->length, line->attributes);
|
i, line->length, line->attributes);
|
||||||
for (int j = 0; j < line->length; j++)
|
for (int j = 0; j < line->length; j++)
|
||||||
fprintf(fileOut, "%c", line->cells[j].character.bytes[0]);
|
if (line->cells[j].character.bytes[0] != 0)
|
||||||
|
fwrite(line->cells[j].character.bytes, 1,
|
||||||
|
line->cells[j].character.ByteCount(), fileOut);
|
||||||
|
|
||||||
fprintf(fileOut, "\n");
|
fprintf(fileOut, "\n");
|
||||||
for (int s = 28; s >= 0; s -= 4) {
|
for (int s = 28; s >= 0; s -= 4) {
|
||||||
@@ -1762,7 +1768,8 @@ BasicTerminalBuffer::StartStopDebugCapture()
|
|||||||
struct tm* ts = gmtime(&timeStamp);
|
struct tm* ts = gmtime(&timeStamp);
|
||||||
str << ts->tm_hour << ts->tm_min << ts->tm_sec;
|
str << ts->tm_hour << ts->tm_min << ts->tm_sec;
|
||||||
str << ".Capture.log";
|
str << ".Capture.log";
|
||||||
fCaptureFile = open(str.String(), O_CREAT | O_WRONLY);
|
fCaptureFile = open(str.String(), O_CREAT | O_WRONLY,
|
||||||
|
S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -122,13 +122,8 @@ public:
|
|||||||
void CaptureChar(char ch);
|
void CaptureChar(char ch);
|
||||||
|
|
||||||
// insert chars/lines
|
// insert chars/lines
|
||||||
inline void InsertChar(UTF8Char c);
|
void InsertChar(UTF8Char c);
|
||||||
void InsertChar(UTF8Char c, uint32 width);
|
void FillScreen(UTF8Char c, uint32 attr);
|
||||||
inline void InsertChar(const char* c);
|
|
||||||
inline void InsertChar(const char* c, int32 length);
|
|
||||||
inline void InsertChar(const char* c, int32 length,
|
|
||||||
uint32 width);
|
|
||||||
void FillScreen(UTF8Char c, uint32 width, uint32 attr);
|
|
||||||
|
|
||||||
void InsertCR();
|
void InsertCR();
|
||||||
void InsertLF();
|
void InsertLF();
|
||||||
@@ -273,34 +268,6 @@ BasicTerminalBuffer::SetAttributes(uint32 attributes)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void
|
|
||||||
BasicTerminalBuffer::InsertChar(UTF8Char c)
|
|
||||||
{
|
|
||||||
return InsertChar(c, 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void
|
|
||||||
BasicTerminalBuffer::InsertChar(const char* c)
|
|
||||||
{
|
|
||||||
return InsertChar(UTF8Char(c), 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void
|
|
||||||
BasicTerminalBuffer::InsertChar(const char* c, int32 length)
|
|
||||||
{
|
|
||||||
return InsertChar(UTF8Char(c, length), 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void
|
|
||||||
BasicTerminalBuffer::InsertChar(const char* c, int32 length, uint32 width)
|
|
||||||
{
|
|
||||||
return InsertChar(UTF8Char(c, length), width);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void
|
void
|
||||||
BasicTerminalBuffer::EraseChars(int32 numChars)
|
BasicTerminalBuffer::EraseChars(int32 numChars)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -159,8 +159,10 @@ enum {
|
|||||||
static const int32 DEFAULT = -1;
|
static const int32 DEFAULT = -1;
|
||||||
|
|
||||||
// Font Width
|
// Font Width
|
||||||
static const int HALF_WIDTH = 1;
|
enum {
|
||||||
static const int FULL_WIDTH = 2;
|
HALF_WIDTH = 1,
|
||||||
|
FULL_WIDTH = 2
|
||||||
|
};
|
||||||
|
|
||||||
#define M_UTF8 -1
|
#define M_UTF8 -1
|
||||||
|
|
||||||
|
|||||||
@@ -481,7 +481,7 @@ TermParse::EscParse()
|
|||||||
dstbuf, &dstLen, &dummyState, '?');
|
dstbuf, &dstLen, &dummyState, '?');
|
||||||
}
|
}
|
||||||
|
|
||||||
fBuffer->InsertChar(dstbuf, dstLen, width);
|
fBuffer->InsertChar(UTF8Char(dstbuf, dstLen));
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case CASE_PRINT_CS96:
|
case CASE_PRINT_CS96:
|
||||||
@@ -493,7 +493,7 @@ TermParse::EscParse()
|
|||||||
dstLen = sizeof(dstbuf);
|
dstLen = sizeof(dstbuf);
|
||||||
convert_to_utf8(B_EUC_CONVERSION, cbuf, &srcLen,
|
convert_to_utf8(B_EUC_CONVERSION, cbuf, &srcLen,
|
||||||
dstbuf, &dstLen, &dummyState, '?');
|
dstbuf, &dstLen, &dummyState, '?');
|
||||||
fBuffer->InsertChar(dstbuf, dstLen);
|
fBuffer->InsertChar(UTF8Char(dstbuf, dstLen));
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case CASE_LF:
|
case CASE_LF:
|
||||||
@@ -511,7 +511,7 @@ TermParse::EscParse()
|
|||||||
dstLen = sizeof(dstbuf);
|
dstLen = sizeof(dstbuf);
|
||||||
convert_to_utf8(currentEncoding, cbuf, &srcLen,
|
convert_to_utf8(currentEncoding, cbuf, &srcLen,
|
||||||
dstbuf, &dstLen, &dummyState, '?');
|
dstbuf, &dstLen, &dummyState, '?');
|
||||||
fBuffer->InsertChar(dstbuf, dstLen);
|
fBuffer->InsertChar(UTF8Char(dstbuf, dstLen));
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case CASE_SJIS_INSTRING:
|
case CASE_SJIS_INSTRING:
|
||||||
@@ -523,7 +523,7 @@ TermParse::EscParse()
|
|||||||
dstLen = sizeof(dstbuf);
|
dstLen = sizeof(dstbuf);
|
||||||
convert_to_utf8(currentEncoding, cbuf, &srcLen,
|
convert_to_utf8(currentEncoding, cbuf, &srcLen,
|
||||||
dstbuf, &dstLen, &dummyState, '?');
|
dstbuf, &dstLen, &dummyState, '?');
|
||||||
fBuffer->InsertChar(dstbuf, dstLen);
|
fBuffer->InsertChar(UTF8Char(dstbuf, dstLen));
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case CASE_UTF8_2BYTE:
|
case CASE_UTF8_2BYTE:
|
||||||
@@ -534,7 +534,7 @@ TermParse::EscParse()
|
|||||||
cbuf[1] = c;
|
cbuf[1] = c;
|
||||||
cbuf[2] = '\0';
|
cbuf[2] = '\0';
|
||||||
|
|
||||||
fBuffer->InsertChar(cbuf, 2);
|
fBuffer->InsertChar(UTF8Char(cbuf, 2));
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case CASE_UTF8_3BYTE:
|
case CASE_UTF8_3BYTE:
|
||||||
@@ -549,7 +549,7 @@ TermParse::EscParse()
|
|||||||
break;
|
break;
|
||||||
cbuf[2] = c;
|
cbuf[2] = c;
|
||||||
cbuf[3] = '\0';
|
cbuf[3] = '\0';
|
||||||
fBuffer->InsertChar(cbuf, 3);
|
fBuffer->InsertChar(UTF8Char(cbuf, 3));
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case CASE_MBCS:
|
case CASE_MBCS:
|
||||||
@@ -1029,7 +1029,7 @@ TermParse::EscParse()
|
|||||||
|
|
||||||
case CASE_DECALN:
|
case CASE_DECALN:
|
||||||
/* DECALN */
|
/* DECALN */
|
||||||
fBuffer->FillScreen(UTF8Char('E'), 1, 0);
|
fBuffer->FillScreen(UTF8Char('E'), 0);
|
||||||
parsestate = groundtable;
|
parsestate = groundtable;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
|||||||
@@ -498,8 +498,9 @@ TermView::_ConvertFromTerminal(const TermPos &pos)
|
|||||||
inline void
|
inline void
|
||||||
TermView::_InvalidateTextRect(int32 x1, int32 y1, int32 x2, int32 y2)
|
TermView::_InvalidateTextRect(int32 x1, int32 y1, int32 x2, int32 y2)
|
||||||
{
|
{
|
||||||
|
// assume the worst case with full-width characters - invalidate 2 cells
|
||||||
BRect rect(x1 * fFontWidth, _LineOffset(y1),
|
BRect rect(x1 * fFontWidth, _LineOffset(y1),
|
||||||
(x2 + 1) * fFontWidth - 1, _LineOffset(y2 + 1) - 1);
|
(x2 + 1) * fFontWidth * 2 - 1, _LineOffset(y2 + 1) - 1);
|
||||||
//debug_printf("Invalidate((%f, %f) - (%f, %f))\n", rect.left, rect.top,
|
//debug_printf("Invalidate((%f, %f) - (%f, %f))\n", rect.left, rect.top,
|
||||||
//rect.right, rect.bottom);
|
//rect.right, rect.bottom);
|
||||||
Invalidate(rect);
|
Invalidate(rect);
|
||||||
@@ -1030,12 +1031,8 @@ TermView::_DrawCursor()
|
|||||||
if (fVisibleTextBuffer->GetChar(fCursor.y - firstVisible, fCursor.x,
|
if (fVisibleTextBuffer->GetChar(fCursor.y - firstVisible, fCursor.x,
|
||||||
character, attr) == A_CHAR
|
character, attr) == A_CHAR
|
||||||
&& (fCursorStyle == BLOCK_CURSOR || !cursorVisible)) {
|
&& (fCursorStyle == BLOCK_CURSOR || !cursorVisible)) {
|
||||||
int32 width;
|
|
||||||
if (IS_WIDTH(attr))
|
|
||||||
width = 2;
|
|
||||||
else
|
|
||||||
width = 1;
|
|
||||||
|
|
||||||
|
int32 width = IS_WIDTH(attr) ? FULL_WIDTH : HALF_WIDTH;
|
||||||
char buffer[5];
|
char buffer[5];
|
||||||
int32 bytes = UTF8Char::ByteCount(character.bytes[0]);
|
int32 bytes = UTF8Char::ByteCount(character.bytes[0]);
|
||||||
memcpy(buffer, character.bytes, bytes);
|
memcpy(buffer, character.bytes, bytes);
|
||||||
@@ -1064,6 +1061,9 @@ TermView::_DrawCursor()
|
|||||||
SetHighColor(rgb_back);
|
SetHighColor(rgb_back);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (IS_WIDTH(attr) && fCursorStyle != IBEAM_CURSOR)
|
||||||
|
rect.right += fFontWidth;
|
||||||
|
|
||||||
FillRect(rect);
|
FillRect(rect);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1287,8 +1287,13 @@ TermView::Draw(BRect updateRect)
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Note: full-width characters GetString()-ed always
|
||||||
|
// with count 1, so this hardcoding is safe. From the other
|
||||||
|
// side - drawing the whole string with one call render the
|
||||||
|
// characters not aligned to cells grid - that looks much more
|
||||||
|
// inaccurate for full-width strings than for half-width ones.
|
||||||
if (IS_WIDTH(attr))
|
if (IS_WIDTH(attr))
|
||||||
count = 2;
|
count = FULL_WIDTH;
|
||||||
|
|
||||||
_DrawLinePart(fFontWidth * i, (int32)_LineOffset(j),
|
_DrawLinePart(fFontWidth * i, (int32)_LineOffset(j),
|
||||||
attr, buf, count, insideSelection, false, this);
|
attr, buf, count, insideSelection, false, this);
|
||||||
|
|||||||
@@ -65,7 +65,13 @@ struct UTF8Char {
|
|||||||
|
|
||||||
bool IsFullWidth() const
|
bool IsFullWidth() const
|
||||||
{
|
{
|
||||||
// TODO: Implement!
|
switch (BUnicodeChar::EastAsianWidth(BUnicodeChar::FromUTF8(bytes))) {
|
||||||
|
case B_UNICODE_EA_FULLWIDTH:
|
||||||
|
case B_UNICODE_EA_WIDE:
|
||||||
|
return true;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user