Skip to content
This repository has been archived by the owner on Jan 14, 2022. It is now read-only.

Commit

Permalink
Fix inserting characters into the middle of an East Asian wide char
Browse files Browse the repository at this point in the history
We currently assume that the column we're inserting a char into is the
start of a display character, and compute the length of the subsequence
of mText storing the column's contents accordingly.  This breaks,
however, when inserting into the second column spanned by an East Asian
wide character.

Detect this case and handle it specially when we need to find the start
of the next independent column's contents (such as when computing the
length of the existing sequence stored in this column).  Also, to
preserve column alignment, pad the column before with a space; if the
character being inserted is a wide character, clobber the next column's
contents too.

Fixes the second coming of #145, and potentially other
difficult-to-reproduce bugs concerning East Asian wide character support
as well.
  • Loading branch information
steven676 committed Jun 8, 2014
1 parent 7335c64 commit 9a47042
Showing 1 changed file with 70 additions and 26 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -875,9 +875,25 @@ public void setChar(int column, int codePoint) {
int charWidth = UnicodeTranscript.charWidth(codePoint);
int oldCharWidth = UnicodeTranscript.charWidth(text, pos);

if (charWidth == 2 && column == columns - 1) {
// A width 2 character doesn't fit in the last column.
codePoint = ' ';
charWidth = 1;
}

boolean wasExtraColForWideChar = false;
if (oldCharWidth == 2 && column > 0) {
/* If the previous screen column starts at the same offset in the
* array as this one, this column must be the second column used
* by an East Asian wide character */
wasExtraColForWideChar = (findStartOfColumn(column - 1) == pos);
}

// Get the number of elements in the mText array this column uses now
int oldLen;
if (column + oldCharWidth < columns) {
if (wasExtraColForWideChar && column + 1 < columns) {
oldLen = findStartOfColumn(column + 1) - pos;
} else if (column + oldCharWidth < columns) {
oldLen = findStartOfColumn(column+oldCharWidth) - pos;
} else {
oldLen = spaceUsed - pos;
Expand Down Expand Up @@ -927,44 +943,72 @@ public void setChar(int column, int codePoint) {
}

/*
* Handle cases where charWidth changes
* width 1 -> width 2: should clobber the contents of the next
* column (if next column contains wide char, need to pad with a space)
* width 2 -> width 1: pad with a space after the new character
* Handle cases where we need to pad with spaces to preserve column
* alignment
*
* width 2 -> width 1: pad with a space before or after the new
* character, depending on which of the two previously-occupied columns
* we wrote into
*
* inserting width 2 character into the second column of an existing
* width 2 character: pad with a space before the new character
*/
if (oldCharWidth == 2 && charWidth == 1) {
// Pad with a space
if (oldCharWidth == 2 && charWidth == 1 || wasExtraColForWideChar && charWidth == 2) {
int nextPos = pos + newLen;
char[] newText = text;
if (spaceUsed + 1 > text.length) {
// Array needs growing
char[] newText = new char[text.length + columns];
System.arraycopy(text, 0, newText, 0, nextPos);
newText = new char[text.length + columns];
System.arraycopy(text, 0, newText, 0, wasExtraColForWideChar ? pos : nextPos);
}

if (wasExtraColForWideChar) {
// Padding goes before the new character
System.arraycopy(text, pos, newText, pos + 1, spaceUsed - pos);
newText[pos] = ' ';
} else {
// Padding goes after the new character
System.arraycopy(text, nextPos, newText, nextPos + 1, spaceUsed - nextPos);
newText[nextPos] = ' ';
}

if (newText != text) {
// Update mText to point to the newly grown array
mText = text = newText;
} else {
System.arraycopy(text, nextPos, text, nextPos + 1, spaceUsed - nextPos);
}
text[nextPos] = ' ';

// Update space used
++offset[0];
spaceUsed = ++offset[0];

// Correct the offset for the next column to reflect width change
if (column == 0) {
offset[1] = (short) (newLen - 1);
} else if (column + 1 < columns) {
offset[column + 1] = (short) (offset[column] + newLen - 1);
// Correct the offset for the just-modified column to reflect
// width change
if (wasExtraColForWideChar) {
++offset[column];
++pos;
} else {
if (column == 0) {
offset[1] = (short) (newLen - 1);
} else if (column + 1 < columns) {
offset[column + 1] = (short) (offset[column] + newLen - 1);
}
++column;
}
++column;

++shift;
} else if (oldCharWidth == 1 && charWidth == 2) {
if (column == columns - 1) {
// A width 2 character doesn't fit in the last column.
text[pos] = ' ';
offset[0] = (short) (pos + 1);
shift = 0;
} else if (column == columns - 2) {
}

/*
* Handle cases where we need to clobber the contents of the next
* column in order to preserve column alignment
*
* width 1 -> width 2: should clobber the contents of the next
* column (if next column contains wide char, need to pad with a space)
*
* inserting width 2 character into the second column of an existing
* width 2 character: same
*/
if (oldCharWidth == 1 && charWidth == 2 || wasExtraColForWideChar && charWidth == 2) {
if (column == columns - 2) {
// Correct offset for the next column to reflect width change
offset[column + 1] = (short) (offset[column] - 1);

Expand Down

0 comments on commit 9a47042

Please sign in to comment.