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
|
||||
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) {
|
||||
if (--x < 0) {
|
||||
// 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)
|
||||
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);
|
||||
}
|
||||
|
||||
@@ -606,14 +607,13 @@ BasicTerminalBuffer::Find(const char* _pattern, const TermPos& start,
|
||||
|
||||
|
||||
void
|
||||
BasicTerminalBuffer::InsertChar(UTF8Char c, uint32 width)
|
||||
BasicTerminalBuffer::InsertChar(UTF8Char c)
|
||||
{
|
||||
//debug_printf("BasicTerminalBuffer::InsertChar('%.*s' (%d), %#lx)\n",
|
||||
//(int)c.ByteCount(), c.bytes, c.bytes[0], attributes);
|
||||
if ((int32)width == FULL_WIDTH)
|
||||
fAttributes |= A_WIDTH;
|
||||
int32 width = c.IsFullWidth() ? FULL_WIDTH : HALF_WIDTH;
|
||||
|
||||
if (fSoftWrappedCursor || fCursor.x + (int32)width > fWidth)
|
||||
if (fSoftWrappedCursor || (fCursor.x + width) > fWidth)
|
||||
_SoftBreakLine();
|
||||
else
|
||||
_PadLineToCursor();
|
||||
@@ -625,7 +625,8 @@ BasicTerminalBuffer::InsertChar(UTF8Char c, uint32 width)
|
||||
|
||||
TerminalLine* line = _LineAt(fCursor.y);
|
||||
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)
|
||||
line->length = fCursor.x + width;
|
||||
@@ -645,10 +646,13 @@ BasicTerminalBuffer::InsertChar(UTF8Char c, uint32 width)
|
||||
|
||||
|
||||
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;
|
||||
width = FULL_WIDTH;
|
||||
}
|
||||
|
||||
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",
|
||||
i, line->length, line->attributes);
|
||||
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");
|
||||
for (int s = 28; s >= 0; s -= 4) {
|
||||
@@ -1762,7 +1768,8 @@ BasicTerminalBuffer::StartStopDebugCapture()
|
||||
struct tm* ts = gmtime(&timeStamp);
|
||||
str << ts->tm_hour << ts->tm_min << ts->tm_sec;
|
||||
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);
|
||||
|
||||
// insert chars/lines
|
||||
inline void InsertChar(UTF8Char c);
|
||||
void InsertChar(UTF8Char c, uint32 width);
|
||||
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 InsertChar(UTF8Char c);
|
||||
void FillScreen(UTF8Char c, uint32 attr);
|
||||
|
||||
void InsertCR();
|
||||
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
|
||||
BasicTerminalBuffer::EraseChars(int32 numChars)
|
||||
{
|
||||
|
||||
@@ -159,8 +159,10 @@ enum {
|
||||
static const int32 DEFAULT = -1;
|
||||
|
||||
// Font Width
|
||||
static const int HALF_WIDTH = 1;
|
||||
static const int FULL_WIDTH = 2;
|
||||
enum {
|
||||
HALF_WIDTH = 1,
|
||||
FULL_WIDTH = 2
|
||||
};
|
||||
|
||||
#define M_UTF8 -1
|
||||
|
||||
|
||||
@@ -481,7 +481,7 @@ TermParse::EscParse()
|
||||
dstbuf, &dstLen, &dummyState, '?');
|
||||
}
|
||||
|
||||
fBuffer->InsertChar(dstbuf, dstLen, width);
|
||||
fBuffer->InsertChar(UTF8Char(dstbuf, dstLen));
|
||||
break;
|
||||
|
||||
case CASE_PRINT_CS96:
|
||||
@@ -493,7 +493,7 @@ TermParse::EscParse()
|
||||
dstLen = sizeof(dstbuf);
|
||||
convert_to_utf8(B_EUC_CONVERSION, cbuf, &srcLen,
|
||||
dstbuf, &dstLen, &dummyState, '?');
|
||||
fBuffer->InsertChar(dstbuf, dstLen);
|
||||
fBuffer->InsertChar(UTF8Char(dstbuf, dstLen));
|
||||
break;
|
||||
|
||||
case CASE_LF:
|
||||
@@ -511,7 +511,7 @@ TermParse::EscParse()
|
||||
dstLen = sizeof(dstbuf);
|
||||
convert_to_utf8(currentEncoding, cbuf, &srcLen,
|
||||
dstbuf, &dstLen, &dummyState, '?');
|
||||
fBuffer->InsertChar(dstbuf, dstLen);
|
||||
fBuffer->InsertChar(UTF8Char(dstbuf, dstLen));
|
||||
break;
|
||||
|
||||
case CASE_SJIS_INSTRING:
|
||||
@@ -523,7 +523,7 @@ TermParse::EscParse()
|
||||
dstLen = sizeof(dstbuf);
|
||||
convert_to_utf8(currentEncoding, cbuf, &srcLen,
|
||||
dstbuf, &dstLen, &dummyState, '?');
|
||||
fBuffer->InsertChar(dstbuf, dstLen);
|
||||
fBuffer->InsertChar(UTF8Char(dstbuf, dstLen));
|
||||
break;
|
||||
|
||||
case CASE_UTF8_2BYTE:
|
||||
@@ -534,7 +534,7 @@ TermParse::EscParse()
|
||||
cbuf[1] = c;
|
||||
cbuf[2] = '\0';
|
||||
|
||||
fBuffer->InsertChar(cbuf, 2);
|
||||
fBuffer->InsertChar(UTF8Char(cbuf, 2));
|
||||
break;
|
||||
|
||||
case CASE_UTF8_3BYTE:
|
||||
@@ -549,7 +549,7 @@ TermParse::EscParse()
|
||||
break;
|
||||
cbuf[2] = c;
|
||||
cbuf[3] = '\0';
|
||||
fBuffer->InsertChar(cbuf, 3);
|
||||
fBuffer->InsertChar(UTF8Char(cbuf, 3));
|
||||
break;
|
||||
|
||||
case CASE_MBCS:
|
||||
@@ -1029,7 +1029,7 @@ TermParse::EscParse()
|
||||
|
||||
case CASE_DECALN:
|
||||
/* DECALN */
|
||||
fBuffer->FillScreen(UTF8Char('E'), 1, 0);
|
||||
fBuffer->FillScreen(UTF8Char('E'), 0);
|
||||
parsestate = groundtable;
|
||||
break;
|
||||
|
||||
|
||||
@@ -498,8 +498,9 @@ TermView::_ConvertFromTerminal(const TermPos &pos)
|
||||
inline void
|
||||
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),
|
||||
(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,
|
||||
//rect.right, rect.bottom);
|
||||
Invalidate(rect);
|
||||
@@ -1030,12 +1031,8 @@ TermView::_DrawCursor()
|
||||
if (fVisibleTextBuffer->GetChar(fCursor.y - firstVisible, fCursor.x,
|
||||
character, attr) == A_CHAR
|
||||
&& (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];
|
||||
int32 bytes = UTF8Char::ByteCount(character.bytes[0]);
|
||||
memcpy(buffer, character.bytes, bytes);
|
||||
@@ -1064,6 +1061,9 @@ TermView::_DrawCursor()
|
||||
SetHighColor(rgb_back);
|
||||
}
|
||||
|
||||
if (IS_WIDTH(attr) && fCursorStyle != IBEAM_CURSOR)
|
||||
rect.right += fFontWidth;
|
||||
|
||||
FillRect(rect);
|
||||
}
|
||||
}
|
||||
@@ -1287,8 +1287,13 @@ TermView::Draw(BRect updateRect)
|
||||
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))
|
||||
count = 2;
|
||||
count = FULL_WIDTH;
|
||||
|
||||
_DrawLinePart(fFontWidth * i, (int32)_LineOffset(j),
|
||||
attr, buf, count, insideSelection, false, this);
|
||||
|
||||
@@ -65,7 +65,13 @@ struct UTF8Char {
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user