diff options
author | Eran <eranmizra@gmail.com> | 2010-10-17 12:29:02 +0200 |
---|---|---|
committer | Eran <eranmizra@gmail.com> | 2010-10-17 12:42:43 +0200 |
commit | 767452685d8e58c97c3add0742bd462648d34909 (patch) | |
tree | 077c7373b9cf90924d7b96fcd929401160814e70 /core/java/android/text | |
parent | 0a17f45e0803d4c4e5cfa6b10d8fd265fd5a3a2f (diff) | |
download | frameworks_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-x | core/java/android/text/Layout.java | 35 | ||||
-rwxr-xr-x | core/java/android/text/StaticLayout.java | 110 |
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) { |