Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit fcc13c17 authored by Steve Kondik's avatar Steve Kondik Committed by Gerrit Code Review
Browse files

Merge "Fix RTL support, specifically fixes the combination of RTL text with...

Merge "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." into froyo
parents 7f302107 76745268
Loading
Loading
Loading
Loading
+2 −33
Original line number Original line Diff line number Diff line
@@ -1818,43 +1818,12 @@ public abstract class Layout {
        // are left-to-right, the others are right-to-left.  So, for example,
        // 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],
        // a line that starts with a right-to-left run has 0 at mDirections[0],
        // since the 'first' (ltr) run is zero length.
        // 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) {
        /* package */ Directions(short[] dirs) {
            mDirections = dirs;
            mDirections = dirs;
        }
        }


        static int baseDirection(Directions dir,int length) {
        boolean hasRTL() {
            if (dir == DIRS_ALL_LEFT_TO_RIGHT) {
            return mDirections.length>1 && mDirections[1]>0;
                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;
            }
        }
        }
    }
    }


+77 −33
Original line number Original line Diff line number Diff line
@@ -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
            // Ensure that none of the underlying characters are treated
            // as viable breakpoints, and that the entire run gets the
            // as viable breakpoints, and that the entire run gets the
            // same bidi direction.
            // 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) {
            if (source instanceof Spanned) {
                Spanned sp = (Spanned) source;
                Spanned sp = (Spanned) source;
                ReplacementSpan[] spans = sp.getSpans(start, end, ReplacementSpan.class);
                ReplacementSpan[] spans = sp.getSpans(start, end, ReplacementSpan.class);
@@ -246,14 +256,13 @@ extends Layout
                    int b = sp.getSpanEnd(spans[y]);
                    int b = sp.getSpanEnd(spans[y]);


                    for (int x = a; x < b; x++) {
                    for (int x = a; x < b; x++) {
                        chdirs[x - start] = SOR;
                        chs[x - start] = '\uFFFC';
                        chs[x - start] = '\uFFFC';
                    }
                    }
                }
                }
            }
            }


            if (!easy) {
            if (!easy) {
                // XXX put override flags, etc. into chdirs
                dir = bidi(dir, chs, chdirs, n, false);


                // Do mirroring for right-to-left segments
                // Do mirroring for right-to-left segments


@@ -638,26 +647,16 @@ extends Layout
         * Determine primary paragraph direction if not specified
         * Determine primary paragraph direction if not specified
         */
         */
        if (dir != DIR_REQUEST_LTR && dir != DIR_REQUEST_RTL) {
        if (dir != DIR_REQUEST_LTR && dir != DIR_REQUEST_RTL) {
            // set up default
            // Heuristic - LTR unless paragraph contains any RTL chars
            dir = dir >= 0 ? DIR_LEFT_TO_RIGHT : DIR_RIGHT_TO_LEFT;
            for (int j = 0; j < n; j++) {
                int d = chInfo[j];

                if (d == Character.DIRECTIONALITY_LEFT_TO_RIGHT) {
            dir = DIR_LEFT_TO_RIGHT;
            dir = DIR_LEFT_TO_RIGHT;
                    break;
            for (int j = 0; j < n; j++) {
                }
                if (chInfo[j] == Character.DIRECTIONALITY_RIGHT_TO_LEFT) {
                if (d == Character.DIRECTIONALITY_RIGHT_TO_LEFT) {
                    dir = DIR_RIGHT_TO_LEFT;
                    dir = DIR_RIGHT_TO_LEFT;
                    break;
                    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
         * XXX Explicit overrides should go here
         */
         */
@@ -666,7 +665,11 @@ extends Layout
         * Weak type resolution
         * 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
        // W1 non spacing marks
        for (int j = 0; j < n; j++) {
        for (int j = 0; j < n; j++) {
@@ -678,7 +681,7 @@ extends Layout
            }
            }
        }
        }


        // dump(chdirs, n, "W1");
        // dump(chInfo, n, "W1");


        // W2 european numbers
        // W2 european numbers
        byte cur = SOR;
        byte cur = SOR;
@@ -693,11 +696,10 @@ extends Layout
                 if (cur ==
                 if (cur ==
                    Character.DIRECTIONALITY_RIGHT_TO_LEFT_ARABIC)
                    Character.DIRECTIONALITY_RIGHT_TO_LEFT_ARABIC)
                    chInfo[j] = Character.DIRECTIONALITY_ARABIC_NUMBER;
                    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
        // W3 arabic letters
        for (int j = 0; j < n; j++) {
        for (int j = 0; j < n; j++) {
@@ -705,7 +707,7 @@ extends Layout
                chInfo[j] = Character.DIRECTIONALITY_RIGHT_TO_LEFT;
                chInfo[j] = Character.DIRECTIONALITY_RIGHT_TO_LEFT;
        }
        }


        // dump(chdirs, n, "W3");
        // dump(chInfo, n, "W3");


        // W4 single separator between numbers
        // W4 single separator between numbers
        for (int j = 1; j < n - 1; j++) {
        for (int j = 1; j < n - 1; j++) {
@@ -713,6 +715,9 @@ extends Layout
            byte prev = chInfo[j - 1];
            byte prev = chInfo[j - 1];
            byte next = 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 (d == Character.DIRECTIONALITY_EUROPEAN_NUMBER_SEPARATOR) {
                if (prev == Character.DIRECTIONALITY_EUROPEAN_NUMBER &&
                if (prev == Character.DIRECTIONALITY_EUROPEAN_NUMBER &&
                    next == Character.DIRECTIONALITY_EUROPEAN_NUMBER)
                    next == Character.DIRECTIONALITY_EUROPEAN_NUMBER)
@@ -724,10 +729,31 @@ extends Layout
                if (prev == Character.DIRECTIONALITY_ARABIC_NUMBER &&
                if (prev == Character.DIRECTIONALITY_ARABIC_NUMBER &&
                    next == Character.DIRECTIONALITY_ARABIC_NUMBER)
                    next == Character.DIRECTIONALITY_ARABIC_NUMBER)
                    chInfo[j] = 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
        // W5 european number terminators
        boolean adjacent = false;
        boolean adjacent = false;
@@ -742,7 +768,7 @@ extends Layout
                adjacent = false;
                adjacent = false;
        }
        }


        //dump(chdirs, n, "W5");
        //dump(chInfo, n, "W5");


        // W5 european number terminators part 2,
        // W5 european number terminators part 2,
        // W6 separators and terminators
        // W6 separators and terminators
@@ -769,7 +795,7 @@ extends Layout
            }
            }
        }
        }


        // dump(chdirs, n, "W6");
        // dump(chInfo, n, "W6");


        // W7 strong direction of european numbers
        // W7 strong direction of european numbers
        cur = SOR;
        cur = SOR;
@@ -785,7 +811,7 @@ extends Layout
                chInfo[j] = Character.DIRECTIONALITY_LEFT_TO_RIGHT;
                chInfo[j] = Character.DIRECTIONALITY_LEFT_TO_RIGHT;
        }
        }


        // dump(chdirs, n, "W7");
        // dump(chInfo, n, "W7");


        // N1, N2 neutrals
        // N1, N2 neutrals
        cur = SOR;
        cur = SOR;
@@ -795,9 +821,8 @@ extends Layout
            if (d == Character.DIRECTIONALITY_LEFT_TO_RIGHT ||
            if (d == Character.DIRECTIONALITY_LEFT_TO_RIGHT ||
                d == Character.DIRECTIONALITY_RIGHT_TO_LEFT) {
                d == Character.DIRECTIONALITY_RIGHT_TO_LEFT) {
                cur = d;
                cur = d;
            } else if (d == Character.DIRECTIONALITY_EUROPEAN_NUMBER) {
            } else if (d == Character.DIRECTIONALITY_EUROPEAN_NUMBER ||
                cur = Character.DIRECTIONALITY_RIGHT_TO_LEFT;
                       d == Character.DIRECTIONALITY_ARABIC_NUMBER) {
            } else if (d == Character.DIRECTIONALITY_ARABIC_NUMBER) {
                cur = Character.DIRECTIONALITY_LEFT_TO_RIGHT;
                cur = Character.DIRECTIONALITY_LEFT_TO_RIGHT;
            } else {
            } else {
                byte dd = SOR;
                byte dd = SOR;
@@ -810,12 +835,10 @@ extends Layout
                        dd == Character.DIRECTIONALITY_RIGHT_TO_LEFT) {
                        dd == Character.DIRECTIONALITY_RIGHT_TO_LEFT) {
                        break;
                        break;
                    }
                    }
                    if (dd == Character.DIRECTIONALITY_EUROPEAN_NUMBER) {
                    if (dd == Character.DIRECTIONALITY_EUROPEAN_NUMBER ||
                        dd == Character.DIRECTIONALITY_ARABIC_NUMBER) {
                        dd = Character.DIRECTIONALITY_LEFT_TO_RIGHT;
                        dd = Character.DIRECTIONALITY_LEFT_TO_RIGHT;
                        break;
                        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
        // extra: enforce that all tabs and surrogate characters go the
        // primary direction
        // 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;
        return dir;
    }
    }


@@ -1268,7 +1311,8 @@ extends Layout
    }
    }


    public int getParagraphDirection(int line) {
    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) {
    public boolean getLineContainsTab(int line) {
+70 −96
Original line number Original line Diff line number Diff line
@@ -1267,104 +1267,78 @@ public class Canvas {
        }
        }
        return hasBidi;
        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.
    * 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 
    * @hide 
    **/
    **/
    public static char[] bidiProcess(char[] text,int start,int srcCount) {
    private static char reverseParen(char c) {

        switch (c) {
        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;
            }
            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 '[':
        case '[':
                                destCharArray[i]=']';
            c=']';
            break;
            break;
        case ']':
        case ']':
                                destCharArray[i]='[';
            c='[';
            break;
            break;
        case '}':
        case '}':
                                destCharArray[i]='{';
            c='{';
            break;
            break;
        case '{':
        case '{':
                                destCharArray[i]='}';
            c='}';
            break;
            break;
        case '(':
        case '(':
                                destCharArray[i]=')';
            c=')';
            break;
            break;
        case ')':
        case ')':
                                destCharArray[i]='(';
            c='(';
            break;
            break;
        case '>':
        case '>':
                                destCharArray[i]='<';
            c='<';
            break;
            break;
        case '<':
        case '<':
                                destCharArray[i]='>';
            c='>';
                                break;
                            default:
                                destCharArray[i]=buf[srcIndex];
            break;
            break;
        }
        }
                        } else destCharArray[i]=buf[srcIndex];
        return c;
                    } 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;
    }
    }
    /** @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 {
        if (hasRTL) {
                    // Avoiding spaghetti code and mangling of loop counter 
            char[] rev=new char[count];
                    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 **/
    /** @hide **/