summaryrefslogtreecommitdiffstats
path: root/core/java/android/text
diff options
context:
space:
mode:
authorEran <eranmizra@gmail.com>2010-10-17 12:29:02 +0200
committerEran <eranmizra@gmail.com>2010-10-17 12:42:43 +0200
commit767452685d8e58c97c3add0742bd462648d34909 (patch)
tree077c7373b9cf90924d7b96fcd929401160814e70 /core/java/android/text
parent0a17f45e0803d4c4e5cfa6b10d8fd265fd5a3a2f (diff)
downloadframeworks_base-767452685d8e58c97c3add0742bd462648d34909.zip
frameworks_base-767452685d8e58c97c3add0742bd462648d34909.tar.gz
frameworks_base-767452685d8e58c97c3add0742bd462648d34909.tar.bz2
Fix RTL support, specifically fixes the combination of RTL text with numbers and LTR text.
Additionally changes the behavior to align any block with RTL text to the right. Tested heavily with hebrew. Fix by: Eran Mizrahi and Ron Regev Change-Id: I689a39d28efa6874e844669af29e895e93c6cd23
Diffstat (limited to 'core/java/android/text')
-rwxr-xr-xcore/java/android/text/Layout.java35
-rwxr-xr-xcore/java/android/text/StaticLayout.java110
2 files changed, 79 insertions, 66 deletions
diff --git a/core/java/android/text/Layout.java b/core/java/android/text/Layout.java
index 1211f41..112e007 100755
--- a/core/java/android/text/Layout.java
+++ b/core/java/android/text/Layout.java
@@ -1818,43 +1818,12 @@ public abstract class Layout {
// are left-to-right, the others are right-to-left. So, for example,
// a line that starts with a right-to-left run has 0 at mDirections[0],
// since the 'first' (ltr) run is zero length.
- //
- // The code currently assumes that each run is adjacent to the previous
- // one, progressing in the base line direction. This isn't sufficient
- // to handle nested runs, for example numeric text in an rtl context
- // in an ltr paragraph.
/* package */ Directions(short[] dirs) {
mDirections = dirs;
}
- static int baseDirection(Directions dir,int length) {
- if (dir == DIRS_ALL_LEFT_TO_RIGHT) {
- return DIR_LEFT_TO_RIGHT;
- } else if (dir == DIRS_ALL_RIGHT_TO_LEFT) {
- return DIR_RIGHT_TO_LEFT;
- }
-
- int sum=0;
- int lastSwitch=0;
- int i=0;
- while ((i+1) < dir.mDirections.length) {
- sum+=dir.mDirections[i];//-lastSwitch;
- sum-=dir.mDirections[i+1];//-dir.mDirections[i];
- lastSwitch=dir.mDirections[i+1];
- i+=2;
- }
-
- if ((i+1)==dir.mDirections.length) {
- sum+=dir.mDirections[i];//-lastSwitch);
- } else if (i==dir.mDirections.length) {
- sum-=length-lastSwitch;
- }
-
- if (sum>=0) {
- return DIR_LEFT_TO_RIGHT;
- } else {
- return DIR_RIGHT_TO_LEFT;
- }
+ boolean hasRTL() {
+ return mDirections.length>1 && mDirections[1]>0;
}
}
diff --git a/core/java/android/text/StaticLayout.java b/core/java/android/text/StaticLayout.java
index f8301d2..13768e4 100755
--- a/core/java/android/text/StaticLayout.java
+++ b/core/java/android/text/StaticLayout.java
@@ -233,10 +233,20 @@ extends Layout
}
}
+ if (!easy) {
+ // XXX put override flags, etc. into chdirs
+ dir = bidi(dir >= 0 ? DIR_REQUEST_DEFAULT_LTR : DIR_REQUEST_DEFAULT_RTL,
+ chs, chdirs, n, false);
+ }
+
// Ensure that none of the underlying characters are treated
// as viable breakpoints, and that the entire run gets the
// same bidi direction.
+ final byte SOR = dir == DIR_LEFT_TO_RIGHT ?
+ Character.DIRECTIONALITY_LEFT_TO_RIGHT :
+ Character.DIRECTIONALITY_RIGHT_TO_LEFT;
+
if (source instanceof Spanned) {
Spanned sp = (Spanned) source;
ReplacementSpan[] spans = sp.getSpans(start, end, ReplacementSpan.class);
@@ -246,14 +256,13 @@ extends Layout
int b = sp.getSpanEnd(spans[y]);
for (int x = a; x < b; x++) {
+ chdirs[x - start] = SOR;
chs[x - start] = '\uFFFC';
}
}
}
if (!easy) {
- // XXX put override flags, etc. into chdirs
- dir = bidi(dir, chs, chdirs, n, false);
// Do mirroring for right-to-left segments
@@ -638,26 +647,16 @@ extends Layout
* Determine primary paragraph direction if not specified
*/
if (dir != DIR_REQUEST_LTR && dir != DIR_REQUEST_RTL) {
- // set up default
- dir = dir >= 0 ? DIR_LEFT_TO_RIGHT : DIR_RIGHT_TO_LEFT;
+ // Heuristic - LTR unless paragraph contains any RTL chars
+ dir = DIR_LEFT_TO_RIGHT;
for (int j = 0; j < n; j++) {
- int d = chInfo[j];
-
- if (d == Character.DIRECTIONALITY_LEFT_TO_RIGHT) {
- dir = DIR_LEFT_TO_RIGHT;
- break;
- }
- if (d == Character.DIRECTIONALITY_RIGHT_TO_LEFT) {
+ if (chInfo[j] == Character.DIRECTIONALITY_RIGHT_TO_LEFT) {
dir = DIR_RIGHT_TO_LEFT;
break;
}
}
}
- final byte SOR = dir == DIR_LEFT_TO_RIGHT ?
- Character.DIRECTIONALITY_LEFT_TO_RIGHT :
- Character.DIRECTIONALITY_RIGHT_TO_LEFT;
-
/*
* XXX Explicit overrides should go here
*/
@@ -666,7 +665,11 @@ extends Layout
* Weak type resolution
*/
- // dump(chdirs, n, "initial");
+ final byte SOR = dir == DIR_LEFT_TO_RIGHT ?
+ Character.DIRECTIONALITY_LEFT_TO_RIGHT :
+ Character.DIRECTIONALITY_RIGHT_TO_LEFT;
+
+ // dump(chInfo, n, "initial");
// W1 non spacing marks
for (int j = 0; j < n; j++) {
@@ -678,7 +681,7 @@ extends Layout
}
}
- // dump(chdirs, n, "W1");
+ // dump(chInfo, n, "W1");
// W2 european numbers
byte cur = SOR;
@@ -693,11 +696,10 @@ extends Layout
if (cur ==
Character.DIRECTIONALITY_RIGHT_TO_LEFT_ARABIC)
chInfo[j] = Character.DIRECTIONALITY_ARABIC_NUMBER;
- else chInfo[j] = Character.DIRECTIONALITY_LEFT_TO_RIGHT;
}
}
- // dump(chdirs, n, "W2");
+ // dump(chInfo, n, "W2");
// W3 arabic letters
for (int j = 0; j < n; j++) {
@@ -705,7 +707,7 @@ extends Layout
chInfo[j] = Character.DIRECTIONALITY_RIGHT_TO_LEFT;
}
- // dump(chdirs, n, "W3");
+ // dump(chInfo, n, "W3");
// W4 single separator between numbers
for (int j = 1; j < n - 1; j++) {
@@ -713,6 +715,9 @@ extends Layout
byte prev = chInfo[j - 1];
byte next = chInfo[j + 1];
+ boolean isSpace = Character.isWhitespace(chs[j]);
+ boolean nextIsSpace = Character.isWhitespace(chs[j + 1]);
+
if (d == Character.DIRECTIONALITY_EUROPEAN_NUMBER_SEPARATOR) {
if (prev == Character.DIRECTIONALITY_EUROPEAN_NUMBER &&
next == Character.DIRECTIONALITY_EUROPEAN_NUMBER)
@@ -724,10 +729,31 @@ extends Layout
if (prev == Character.DIRECTIONALITY_ARABIC_NUMBER &&
next == Character.DIRECTIONALITY_ARABIC_NUMBER)
chInfo[j] = Character.DIRECTIONALITY_ARABIC_NUMBER;
+ // add condition for spaces following the separator
+ if (nextIsSpace &&
+ ( prev == Character.DIRECTIONALITY_EUROPEAN_NUMBER
+ || prev == Character.DIRECTIONALITY_ARABIC_NUMBER ) )
+ chInfo[j] = SOR;
+ }
+ // add condition if the separator is a space
+ else if (isSpace && prev != SOR &&
+ ( next == Character.DIRECTIONALITY_EUROPEAN_NUMBER
+ || next == Character.DIRECTIONALITY_ARABIC_NUMBER ) ) {
+ chInfo[j] = SOR;
+ for (int k=j+1; k < n; ++k) {
+ if (chInfo[k] == Character.DIRECTIONALITY_LEFT_TO_RIGHT) {
+ chInfo[j] = Character.DIRECTIONALITY_LEFT_TO_RIGHT;
+ break;
+ }
+ if (chInfo[k] == Character.DIRECTIONALITY_RIGHT_TO_LEFT) {
+ chInfo[j] = Character.DIRECTIONALITY_RIGHT_TO_LEFT;
+ break;
+ }
+ }
}
}
- // dump(chdirs, n, "W4");
+ // dump(chInfo, n, "W4");
// W5 european number terminators
boolean adjacent = false;
@@ -742,7 +768,7 @@ extends Layout
adjacent = false;
}
- //dump(chdirs, n, "W5");
+ //dump(chInfo, n, "W5");
// W5 european number terminators part 2,
// W6 separators and terminators
@@ -769,7 +795,7 @@ extends Layout
}
}
- // dump(chdirs, n, "W6");
+ // dump(chInfo, n, "W6");
// W7 strong direction of european numbers
cur = SOR;
@@ -785,7 +811,7 @@ extends Layout
chInfo[j] = Character.DIRECTIONALITY_LEFT_TO_RIGHT;
}
- // dump(chdirs, n, "W7");
+ // dump(chInfo, n, "W7");
// N1, N2 neutrals
cur = SOR;
@@ -795,9 +821,8 @@ extends Layout
if (d == Character.DIRECTIONALITY_LEFT_TO_RIGHT ||
d == Character.DIRECTIONALITY_RIGHT_TO_LEFT) {
cur = d;
- } else if (d == Character.DIRECTIONALITY_EUROPEAN_NUMBER) {
- cur = Character.DIRECTIONALITY_RIGHT_TO_LEFT;
- } else if (d == Character.DIRECTIONALITY_ARABIC_NUMBER) {
+ } else if (d == Character.DIRECTIONALITY_EUROPEAN_NUMBER ||
+ d == Character.DIRECTIONALITY_ARABIC_NUMBER) {
cur = Character.DIRECTIONALITY_LEFT_TO_RIGHT;
} else {
byte dd = SOR;
@@ -810,12 +835,10 @@ extends Layout
dd == Character.DIRECTIONALITY_RIGHT_TO_LEFT) {
break;
}
- if (dd == Character.DIRECTIONALITY_EUROPEAN_NUMBER) {
+ if (dd == Character.DIRECTIONALITY_EUROPEAN_NUMBER ||
+ dd == Character.DIRECTIONALITY_ARABIC_NUMBER) {
dd = Character.DIRECTIONALITY_LEFT_TO_RIGHT;
break;
- } else if (dd == Character.DIRECTIONALITY_ARABIC_NUMBER) {
- dd = Character.DIRECTIONALITY_RIGHT_TO_LEFT;
- break;
}
}
@@ -830,7 +853,7 @@ extends Layout
}
}
- // dump(chdirs, n, "final");
+ // dump(chInfo, n, "final");
// extra: enforce that all tabs and surrogate characters go the
// primary direction
@@ -844,6 +867,26 @@ extends Layout
}
}
+ // Deal specifically with special operators (like '+',etc.) ahead of numbers/english inside RTL paragraphs
+ for (int j = 0; j < n; j++) {
+ switch(chs[j]) {
+ case '+':
+ // For the following chars it is logical to apply the fix, but it appears
+ // it customary only for the "+" and we need to behave similarly to other devices:
+ //case '*':
+ //case '/':
+ //case '@':
+ //case '#':
+ //case '$':
+ //case '%':
+ //case '^':
+ //case '&':
+ //case '_':
+ //case '\\':
+ chInfo[j] = Character.DIRECTIONALITY_LEFT_TO_RIGHT;
+ }
+ }
+
return dir;
}
@@ -1268,7 +1311,8 @@ extends Layout
}
public int getParagraphDirection(int line) {
- return Directions.baseDirection(mLineDirections[line],getLineEnd(line)-getLineStart(line));
+ // LTR unless paragraph contains RTL chars (anywhere)
+ return mLineDirections[line].hasRTL() ? DIR_RIGHT_TO_LEFT : DIR_LEFT_TO_RIGHT;
}
public boolean getLineContainsTab(int line) {