summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rwxr-xr-xcore/java/android/text/Layout.java35
-rwxr-xr-xcore/java/android/text/StaticLayout.java110
-rw-r--r--graphics/java/android/graphics/Canvas.java166
3 files changed, 149 insertions, 162 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) {
diff --git a/graphics/java/android/graphics/Canvas.java b/graphics/java/android/graphics/Canvas.java
index 266dd58..1fc9975 100644
--- a/graphics/java/android/graphics/Canvas.java
+++ b/graphics/java/android/graphics/Canvas.java
@@ -1267,104 +1267,78 @@ public class Canvas {
}
return hasBidi;
}
+ /** @hide */
+ private static boolean isPunctuation(char c) {
+ return c<='\u002f' || c=='\u0040' || (c>'\u005a' && c<='\u0060') || (c>'\u007a' && c<='\u00BF');
+ }
+ /** @hide */
+ private static boolean isRTL(char c) {
+ return c>=FIRST_RIGHT_TO_LEFT && c<=LAST_RIGHT_TO_LEFT;
+ }
/**
* A lightweight BiDi processing to make all draw text work with RTL languages.
- * written from scratch by David Kohen (kohen dot d at gmail dot com) - 2010
* @hide
**/
- public static char[] bidiProcess(char[] text,int start,int srcCount) {
-
- boolean hasBidi=false;
- char[] destCharArray=new char[srcCount];
-
- char[] buf = TemporaryBuffer.obtain(srcCount);
- System.arraycopy(text,start, buf, 0, srcCount);
-
- // I'm doing the processing from the end of the string, since it worked well this way.
- int count=0,srcIndex=0;
- boolean rtlMode=true;
- for (int i=0;i<srcCount;i++){
- srcIndex=srcCount-1-i;
- if (buf[srcIndex]>=FIRST_RIGHT_TO_LEFT&&buf[srcIndex]<=LAST_RIGHT_TO_LEFT){
- destCharArray[i]=buf[srcIndex];
- // In rtl mode I'm mirroring glyphs.
- rtlMode=true;
+ private static char reverseParen(char c) {
+ switch (c) {
+ case '[':
+ c=']';
+ break;
+ case ']':
+ c='[';
+ break;
+ case '}':
+ c='{';
+ break;
+ case '{':
+ c='}';
+ break;
+ case '(':
+ c=')';
+ break;
+ case ')':
+ c='(';
+ break;
+ case '>':
+ c='<';
+ break;
+ case '<':
+ c='>';
+ break;
+ }
+ return c;
+ }
+ /** @hide */
+ public static char[] bidiProcess(char[] text,int start,int count) {
+ String cut=new String(text,start,count);
+ char[] tt=new char[count];
+ cut.getChars(0, count, tt, 0);
+ boolean hasRTL=false;
+ for (int ii=0; ii<count; ++ii)
+ if (isRTL(tt[ii])) {
+ hasRTL = true;
+ break;
}
- else {
- srcIndex=srcCount-1-i;
- if (count==0) {
- // Direction neutral characters
- if (buf[srcIndex]<='\u002f' ||
- (buf[srcIndex]>'\u0039' && buf[srcIndex]<='\u0040') ||
- (buf[srcIndex]>'\u005a' && buf[srcIndex]<='\u0060')||
- (buf[srcIndex]>'\u007a' && buf[srcIndex]<='\u00BF')) {
-
- if (rtlMode){
- switch (buf[srcIndex]) {
- case '[':
- destCharArray[i]=']';
- break;
- case ']':
- destCharArray[i]='[';
- break;
- case '}':
- destCharArray[i]='{';
- break;
- case '{':
- destCharArray[i]='}';
- break;
- case '(':
- destCharArray[i]=')';
- break;
- case ')':
- destCharArray[i]='(';
- break;
- case '>':
- destCharArray[i]='<';
- break;
- case '<':
- destCharArray[i]='>';
- break;
- default:
- destCharArray[i]=buf[srcIndex];
- break;
- }
- } else destCharArray[i]=buf[srcIndex];
- } else {
- // Handling LTR embedded strings.
- while (((srcIndex-count)>=0)&&((buf[srcIndex-count]<FIRST_RIGHT_TO_LEFT)||(buf[srcIndex-count]>LAST_RIGHT_TO_LEFT))){
- count++;
- }
- int index=0;
- int punctuationMarks=0;
-
- // Handling direction neutral characters in the middle of LTR
- while (count>0 && (srcIndex-(count)>=0) &&
- (buf[srcIndex-(count-1)]<='\u002f' ||
- (buf[srcIndex-(count-1)]>'\u0039' && buf[srcIndex-(count-1)]<='\u0040') ||
- (buf[srcIndex-(count-1)]>'\u005a' && buf[srcIndex-(count-1)]<='\u0060')||
- (buf[srcIndex-(count-1)]>'\u007a' && buf[srcIndex-(count-1)]<='\u00BF'))){
- destCharArray[i+(count-1)]=buf[srcIndex-(count-1)];
- count--;
- punctuationMarks++;
- }
-
- while (count>0){
- destCharArray[i+index]=buf[srcIndex-(count-1)];
- count--;
- index++;
- }
- count=index+punctuationMarks-1;
- }
- }
- else {
- // Avoiding spaghetti code and mangling of loop counter
- count--;
+ if (hasRTL) {
+ char[] rev=new char[count];
+ for(int ii=0; ii<count; ++ii)
+ rev[ii] = tt[count-ii-1];
+ // now copy reverse back over tt, but reverse again (fixing) any non-RTL sequences:
+ for(int ii=0; ii<count; ) {
+ if (isRTL(rev[ii]) || isPunctuation(rev[ii])) {
+ tt[ii] = reverseParen(rev[ii]);
+ ++ii;
+ } else {
+ int end=ii+1;
+ while (end<count && !isRTL(rev[end]) && !isPunctuation(rev[end]))
+ ++end;
+ int jj=end;
+ while (ii<end)
+ tt[ii++] = rev[--jj];
}
- rtlMode=false;
}
}
- return destCharArray;
+ return tt;
}
/** @hide **/
@@ -1525,10 +1499,10 @@ public class Canvas {
else if (text instanceof GraphicsOperations) {
((GraphicsOperations) text).drawText(this, start, end, x, y,
paint);
- }
- else {
- char[] buf = TemporaryBuffer.obtain(end - start);
- TextUtils.getChars(text, start, end, buf, 0);
+ }
+ else {
+ char[] buf = TemporaryBuffer.obtain(end - start);
+ TextUtils.getChars(text, start, end, buf, 0);
if (hasBidi) {
String reshapedText=ArabicReshape.reshape(new String(buf));
/* The reshaping may make the string smaller */
@@ -1536,8 +1510,8 @@ public class Canvas {
} else {
drawText(buf, 0, end - start, x, y, paint,false);
}
- TemporaryBuffer.recycle(buf);
- }
+ TemporaryBuffer.recycle(buf);
+ }
}
/**