Support surrogate pairs when layouting text

The current framework does not consider surrogate pairs
when getting the index of the character. This bug becomes
visible when creating the text including Emojis. For
example cursor breaks up when it moves around the Emojis.

Our proposed solution will consider the surrogate pairs
when calculating the index. It will fix not only the Emoji
case, but also the letters that use surrogate pairs.

Change-Id: I4983f2e4df933c8af9d5f0cc27df871e8e10fed4
This commit is contained in:
Takako Ishibashi
2010-08-25 12:32:00 +02:00
committed by Johan Redestig
parent f3ee6f87a3
commit 12122bf792
3 changed files with 35 additions and 10 deletions

11
core/java/android/text/Layout.java Normal file → Executable file
View File

@@ -749,6 +749,9 @@ public abstract class Layout {
if (line == getLineCount() - 1)
max++;
if (line != getLineCount() - 1)
max = TextUtils.getOffsetBefore(mText, getLineEnd(line));
int best = min;
float bestdist = Math.abs(getPrimaryHorizontal(best) - horiz);
@@ -893,7 +896,7 @@ public abstract class Layout {
Directions dirs = getLineDirections(line);
if (line != getLineCount() - 1)
end--;
end = TextUtils.getOffsetBefore(mText, end);
float horiz = getPrimaryHorizontal(offset);
@@ -993,7 +996,7 @@ public abstract class Layout {
Directions dirs = getLineDirections(line);
if (line != getLineCount() - 1)
end--;
end = TextUtils.getOffsetBefore(mText, end);
float horiz = getPrimaryHorizontal(offset);
@@ -1564,7 +1567,8 @@ public abstract class Layout {
h = dir * nextTab(text, start, end, h * dir, tabs);
}
if (bm != null) {
if (j != there && bm != null) {
if (offset == start + j) return h;
workPaint.set(paint);
Styled.measureText(paint, workPaint, text,
j, j + 2, null);
@@ -1958,4 +1962,3 @@ public abstract class Layout {
new Directions(new short[] { 0, 32767 });
}

28
core/java/android/text/StaticLayout.java Normal file → Executable file
View File

@@ -313,7 +313,9 @@ extends Layout
class);
if (spanned == null) {
paint.getTextWidths(sub, i, next, widths);
final int actualNum = paint.getTextWidths(sub, i, next, widths);
if (next - i > actualNum)
adjustTextWidths(widths, sub, i, next, actualNum);
System.arraycopy(widths, 0, widths,
end - start + (i - start), next - i);
@@ -321,9 +323,11 @@ extends Layout
} else {
mWorkPaint.baselineShift = 0;
Styled.getTextWidths(paint, mWorkPaint,
spanned, i, next,
widths, fm);
final int actualNum = Styled.getTextWidths(paint, mWorkPaint,
spanned, i, next,
widths, fm);
if (next - i > actualNum)
adjustTextWidths(widths, spanned, i, next, actualNum);
System.arraycopy(widths, 0, widths,
end - start + (i - start), next - i);
@@ -966,6 +970,22 @@ extends Layout
return low;
}
private static void adjustTextWidths(float[] widths, CharSequence text,
int curPos, int nextPos, int actualNum) {
try {
int dstIndex = nextPos - curPos - 1;
for (int srcIndex = actualNum - 1; srcIndex >= 0; srcIndex--) {
final char c = text.charAt(dstIndex + curPos);
if (c >= 0xD800 && c <= 0xDFFF) {
widths[dstIndex--] = 0.0f;
}
widths[dstIndex--] = widths[srcIndex];
}
} catch (IndexOutOfBoundsException e) {
Log.e("text", "adjust text widths failed");
}
}
private int out(CharSequence text, int start, int end,
int above, int below, int top, int bottom, int v,
float spacingmult, float spacingadd,

6
core/java/android/text/Styled.java Normal file → Executable file
View File

@@ -203,9 +203,10 @@ public class Styled
}
}
int result;
if (replacement == null) {
workPaint.getFontMetricsInt(fmi);
workPaint.getTextWidths(text, start, end, widths);
result = workPaint.getTextWidths(text, start, end, widths);
} else {
int wid = replacement.getSize(workPaint, text, start, end, fmi);
@@ -214,8 +215,9 @@ public class Styled
for (int i = start + 1; i < end; i++)
widths[i - start] = 0;
}
result = end - start;
}
return end - start;
return result;
}
/**