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:
Siarzhuk Zharski
2013-04-07 20:18:21 +02:00
parent b6fd91b409
commit 3d1492487d
6 changed files with 50 additions and 63 deletions
+18 -11
View File
@@ -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);
}
+2 -35
View File
@@ -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)
{
+4 -2
View File
@@ -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
+7 -7
View File
@@ -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;
+12 -7
View File
@@ -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);
+7 -1
View File
@@ -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;
}