Revert "Clean Paint.mBidiFlags as it is no longer used"

This reverts commit 6d9fe5bd22b531bfce69b146254a4791c76acddc.
diff --git a/core/java/android/text/GraphicsOperations.java b/core/java/android/text/GraphicsOperations.java
index 60545e5..831ccc5 100644
--- a/core/java/android/text/GraphicsOperations.java
+++ b/core/java/android/text/GraphicsOperations.java
@@ -38,7 +38,7 @@
      * {@hide}
      */
     void drawTextRun(Canvas c, int start, int end, int contextStart, int contextEnd,
-            float x, float y, Paint p);
+            float x, float y, int flags, Paint p);
 
    /**
      * Just like {@link Paint#measureText}.
@@ -55,12 +55,19 @@
      * @hide
      */
     float getTextRunAdvances(int start, int end, int contextStart, int contextEnd,
-            float[] advances, int advancesIndex, Paint paint);
+            int flags, float[] advances, int advancesIndex, Paint paint);
+
+    /**
+     * Just like {@link Paint#getTextRunAdvances}.
+     * @hide
+     */
+    float getTextRunAdvances(int start, int end, int contextStart, int contextEnd,
+            int flags, float[] advances, int advancesIndex, Paint paint, int reserved);
 
     /**
      * Just like {@link Paint#getTextRunCursor}.
      * @hide
      */
-    int getTextRunCursor(int contextStart, int contextEnd, int offset,
+    int getTextRunCursor(int contextStart, int contextEnd, int flags, int offset,
             int cursorOpt, Paint p);
 }
diff --git a/core/java/android/text/MeasuredText.java b/core/java/android/text/MeasuredText.java
index 0c881a4..bd9310c1 100644
--- a/core/java/android/text/MeasuredText.java
+++ b/core/java/android/text/MeasuredText.java
@@ -159,15 +159,18 @@
         mPos = p + len;
 
         if (mEasy) {
-            return paint.getTextRunAdvances(mChars, p, len, p, len, mWidths, p);
+            int flags = mDir == Layout.DIR_LEFT_TO_RIGHT
+                ? Canvas.DIRECTION_LTR : Canvas.DIRECTION_RTL;
+            return paint.getTextRunAdvances(mChars, p, len, p, len, flags, mWidths, p);
         }
 
         float totalAdvance = 0;
         int level = mLevels[p];
         for (int q = p, i = p + 1, e = p + len;; ++i) {
             if (i == e || mLevels[i] != level) {
+                int flags = (level & 0x1) == 0 ? Canvas.DIRECTION_LTR : Canvas.DIRECTION_RTL;
                 totalAdvance +=
-                        paint.getTextRunAdvances(mChars, q, i - q, q, i - q, mWidths, q);
+                        paint.getTextRunAdvances(mChars, q, i - q, q, i - q, flags, mWidths, q);
                 if (i == e) {
                     break;
                 }
diff --git a/core/java/android/text/SpannableStringBuilder.java b/core/java/android/text/SpannableStringBuilder.java
index 9e43671..0f30d25 100644
--- a/core/java/android/text/SpannableStringBuilder.java
+++ b/core/java/android/text/SpannableStringBuilder.java
@@ -1130,20 +1130,20 @@
      * {@hide}
      */
     public void drawTextRun(Canvas c, int start, int end, int contextStart, int contextEnd,
-            float x, float y, Paint p) {
+            float x, float y, int flags, Paint p) {
         checkRange("drawTextRun", start, end);
 
         int contextLen = contextEnd - contextStart;
         int len = end - start;
         if (contextEnd <= mGapStart) {
-            c.drawTextRun(mText, start, len, contextStart, contextLen, x, y, p);
+            c.drawTextRun(mText, start, len, contextStart, contextLen, x, y, flags, p);
         } else if (contextStart >= mGapStart) {
             c.drawTextRun(mText, start + mGapLength, len, contextStart + mGapLength,
-                    contextLen, x, y, p);
+                    contextLen, x, y, flags, p);
         } else {
             char[] buf = TextUtils.obtain(contextLen);
             getChars(contextStart, contextEnd, buf, 0);
-            c.drawTextRun(buf, start - contextStart, len, 0, contextLen, x, y, p);
+            c.drawTextRun(buf, start - contextStart, len, 0, contextLen, x, y, flags, p);
             TextUtils.recycle(buf);
         }
     }
@@ -1200,7 +1200,7 @@
      * Don't call this yourself -- exists for Paint to use internally.
      * {@hide}
      */
-    public float getTextRunAdvances(int start, int end, int contextStart, int contextEnd,
+    public float getTextRunAdvances(int start, int end, int contextStart, int contextEnd, int flags,
             float[] advances, int advancesPos, Paint p) {
 
         float ret;
@@ -1210,15 +1210,44 @@
 
         if (end <= mGapStart) {
             ret = p.getTextRunAdvances(mText, start, len, contextStart, contextLen,
-                    advances, advancesPos);
+                    flags, advances, advancesPos);
         } else if (start >= mGapStart) {
             ret = p.getTextRunAdvances(mText, start + mGapLength, len,
-                    contextStart + mGapLength, contextLen, advances, advancesPos);
+                    contextStart + mGapLength, contextLen, flags, advances, advancesPos);
         } else {
             char[] buf = TextUtils.obtain(contextLen);
             getChars(contextStart, contextEnd, buf, 0);
             ret = p.getTextRunAdvances(buf, start - contextStart, len,
-                    0, contextLen, advances, advancesPos);
+                    0, contextLen, flags, advances, advancesPos);
+            TextUtils.recycle(buf);
+        }
+
+        return ret;
+    }
+
+    /**
+     * Don't call this yourself -- exists for Paint to use internally.
+     * {@hide}
+     */
+    public float getTextRunAdvances(int start, int end, int contextStart, int contextEnd, int flags,
+            float[] advances, int advancesPos, Paint p, int reserved) {
+
+        float ret;
+
+        int contextLen = contextEnd - contextStart;
+        int len = end - start;
+
+        if (end <= mGapStart) {
+            ret = p.getTextRunAdvances(mText, start, len, contextStart, contextLen,
+                    flags, advances, advancesPos, reserved);
+        } else if (start >= mGapStart) {
+            ret = p.getTextRunAdvances(mText, start + mGapLength, len,
+                    contextStart + mGapLength, contextLen, flags, advances, advancesPos, reserved);
+        } else {
+            char[] buf = TextUtils.obtain(contextLen);
+            getChars(contextStart, contextEnd, buf, 0);
+            ret = p.getTextRunAdvances(buf, start - contextStart, len,
+                    0, contextLen, flags, advances, advancesPos, reserved);
             TextUtils.recycle(buf);
         }
 
@@ -1241,7 +1270,7 @@
      *
      * @param contextStart the start index of the context
      * @param contextEnd the (non-inclusive) end index of the context
-     * @param flags reserved
+     * @param flags either DIRECTION_RTL or DIRECTION_LTR
      * @param offset the cursor position to move from
      * @param cursorOpt how to move the cursor, one of CURSOR_AFTER,
      * CURSOR_AT_OR_AFTER, CURSOR_BEFORE,
@@ -1252,30 +1281,22 @@
      */
     @Deprecated
     public int getTextRunCursor(int contextStart, int contextEnd, int flags, int offset,
-                                int cursorOpt, Paint p) {
-        return getTextRunCursor(contextStart, contextEnd, offset, cursorOpt, p);
-    }
-
-    /**
-     * @hide
-     */
-    public int getTextRunCursor(int contextStart, int contextEnd, int offset,
-                                int cursorOpt, Paint p) {
+            int cursorOpt, Paint p) {
 
         int ret;
 
         int contextLen = contextEnd - contextStart;
         if (contextEnd <= mGapStart) {
             ret = p.getTextRunCursor(mText, contextStart, contextLen,
-                    offset, cursorOpt);
+                    flags, offset, cursorOpt);
         } else if (contextStart >= mGapStart) {
             ret = p.getTextRunCursor(mText, contextStart + mGapLength, contextLen,
-                    offset + mGapLength, cursorOpt) - mGapLength;
+                    flags, offset + mGapLength, cursorOpt) - mGapLength;
         } else {
             char[] buf = TextUtils.obtain(contextLen);
             getChars(contextStart, contextEnd, buf, 0);
             ret = p.getTextRunCursor(buf, 0, contextLen,
-                    offset - contextStart, cursorOpt) + contextStart;
+                    flags, offset - contextStart, cursorOpt) + contextStart;
             TextUtils.recycle(buf);
         }
 
diff --git a/core/java/android/text/TextLine.java b/core/java/android/text/TextLine.java
index e34a0ef..1fecf81 100644
--- a/core/java/android/text/TextLine.java
+++ b/core/java/android/text/TextLine.java
@@ -664,13 +664,14 @@
             }
         }
 
+        int flags = runIsRtl ? Paint.DIRECTION_RTL : Paint.DIRECTION_LTR;
         int cursorOpt = after ? Paint.CURSOR_AFTER : Paint.CURSOR_BEFORE;
         if (mCharsValid) {
             return wp.getTextRunCursor(mChars, spanStart, spanLimit - spanStart,
-                    offset, cursorOpt);
+                    flags, offset, cursorOpt);
         } else {
             return wp.getTextRunCursor(mText, mStart + spanStart,
-                    mStart + spanLimit, mStart + offset, cursorOpt) - mStart;
+                    mStart + spanLimit, flags, mStart + offset, cursorOpt) - mStart;
         }
     }
 
@@ -737,13 +738,15 @@
 
         int contextLen = contextEnd - contextStart;
         if (needWidth || (c != null && (wp.bgColor != 0 || wp.underlineColor != 0 || runIsRtl))) {
+            int flags = runIsRtl ? Paint.DIRECTION_RTL : Paint.DIRECTION_LTR;
             if (mCharsValid) {
                 ret = wp.getTextRunAdvances(mChars, start, runLen,
-                        contextStart, contextLen, null, 0);
+                        contextStart, contextLen, flags, null, 0);
             } else {
                 int delta = mStart;
-                ret = wp.getTextRunAdvances(mText, delta + start, delta + end,
-                        delta + contextStart, delta + contextEnd, null, 0);
+                ret = wp.getTextRunAdvances(mText, delta + start,
+                        delta + end, delta + contextStart, delta + contextEnd,
+                        flags, null, 0);
             }
         }
 
@@ -783,7 +786,8 @@
                 wp.setAntiAlias(previousAntiAlias);
             }
 
-            drawTextRun(c, wp, start, end, contextStart, contextEnd, x, y + wp.baselineShift);
+            drawTextRun(c, wp, start, end, contextStart, contextEnd, runIsRtl,
+                    x, y + wp.baselineShift);
         }
 
         return runIsRtl ? -ret : ret;
@@ -966,21 +970,23 @@
      * @param end the end of the run
      * @param contextStart the start of context for the run
      * @param contextEnd the end of the context for the run
+     * @param runIsRtl true if the run is right-to-left
      * @param x the x position of the left edge of the run
      * @param y the baseline of the run
      */
     private void drawTextRun(Canvas c, TextPaint wp, int start, int end,
-            int contextStart, int contextEnd, float x, int y) {
+            int contextStart, int contextEnd, boolean runIsRtl, float x, int y) {
 
+        int flags = runIsRtl ? Canvas.DIRECTION_RTL : Canvas.DIRECTION_LTR;
         if (mCharsValid) {
             int count = end - start;
             int contextCount = contextEnd - contextStart;
             c.drawTextRun(mChars, start, count, contextStart, contextCount,
-                    x, y, wp);
+                    x, y, flags, wp);
         } else {
             int delta = mStart;
             c.drawTextRun(mText, delta + start, delta + end,
-                    delta + contextStart, delta + contextEnd, x, y, wp);
+                    delta + contextStart, delta + contextEnd, x, y, flags, wp);
         }
     }
 
diff --git a/core/java/android/view/GLES20Canvas.java b/core/java/android/view/GLES20Canvas.java
index 6c48e43..c369ebe 100644
--- a/core/java/android/view/GLES20Canvas.java
+++ b/core/java/android/view/GLES20Canvas.java
@@ -1162,14 +1162,14 @@
 
         int modifiers = setupModifiers(paint);
         try {
-            nDrawText(mRenderer, text, index, count, x, y, paint.mNativePaint);
+            nDrawText(mRenderer, text, index, count, x, y, paint.mBidiFlags, paint.mNativePaint);
         } finally {
             if (modifiers != MODIFIER_NONE) nResetModifiers(mRenderer, modifiers);
         }
     }
     
     private static native void nDrawText(int renderer, char[] text, int index, int count,
-            float x, float y, int paint);
+            float x, float y, int bidiFlags, int paint);
 
     @Override
     public void drawText(CharSequence text, int start, int end, float x, float y, Paint paint) {
@@ -1177,14 +1177,16 @@
         try {
             if (text instanceof String || text instanceof SpannedString ||
                     text instanceof SpannableString) {
-                nDrawText(mRenderer, text.toString(), start, end, x, y, paint.mNativePaint);
+                nDrawText(mRenderer, text.toString(), start, end, x, y, paint.mBidiFlags,
+                        paint.mNativePaint);
             } 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);
-                nDrawText(mRenderer, buf, 0, end - start, x, y, paint.mNativePaint);
+                nDrawText(mRenderer, buf, 0, end - start, x, y,
+                        paint.mBidiFlags, paint.mNativePaint);
                 TemporaryBuffer.recycle(buf);
             }
         } finally {
@@ -1200,20 +1202,21 @@
 
         int modifiers = setupModifiers(paint);
         try {
-            nDrawText(mRenderer, text, start, end, x, y, paint.mNativePaint);
+            nDrawText(mRenderer, text, start, end, x, y, paint.mBidiFlags, paint.mNativePaint);
         } finally {
             if (modifiers != MODIFIER_NONE) nResetModifiers(mRenderer, modifiers);
         }
     }
 
     private static native void nDrawText(int renderer, String text, int start, int end,
-            float x, float y, int paint);
+            float x, float y, int bidiFlags, int paint);
 
     @Override
     public void drawText(String text, float x, float y, Paint paint) {
         int modifiers = setupModifiers(paint);
         try {
-            nDrawText(mRenderer, text, 0, text.length(), x, y, paint.mNativePaint);
+            nDrawText(mRenderer, text, 0, text.length(), x, y, paint.mBidiFlags,
+                    paint.mNativePaint);
         } finally {
             if (modifiers != MODIFIER_NONE) nResetModifiers(mRenderer, modifiers);
         }
@@ -1229,14 +1232,14 @@
         int modifiers = setupModifiers(paint);
         try {
             nDrawTextOnPath(mRenderer, text, index, count, path.mNativePath, hOffset, vOffset,
-                    paint.mNativePaint);
+                    paint.mBidiFlags, paint.mNativePaint);
         } finally {
             if (modifiers != MODIFIER_NONE) nResetModifiers(mRenderer, modifiers);
         }
     }
 
     private static native void nDrawTextOnPath(int renderer, char[] text, int index, int count,
-            int path, float hOffset, float vOffset, int nativePaint);
+            int path, float hOffset, float vOffset, int bidiFlags, int nativePaint);
 
     @Override
     public void drawTextOnPath(String text, Path path, float hOffset, float vOffset, Paint paint) {
@@ -1245,25 +1248,28 @@
         int modifiers = setupModifiers(paint);
         try {
             nDrawTextOnPath(mRenderer, text, 0, text.length(), path.mNativePath, hOffset, vOffset,
-                    paint.mNativePaint);
+                    paint.mBidiFlags, paint.mNativePaint);
         } finally {
             if (modifiers != MODIFIER_NONE) nResetModifiers(mRenderer, modifiers);
         }
     }
 
     private static native void nDrawTextOnPath(int renderer, String text, int start, int end,
-            int path, float hOffset, float vOffset, int nativePaint);
+            int path, float hOffset, float vOffset, int bidiFlags, int nativePaint);
 
     @Override
     public void drawTextRun(char[] text, int index, int count, int contextIndex, int contextCount,
-            float x, float y, Paint paint) {
+            float x, float y, int dir, Paint paint) {
         if ((index | count | text.length - index - count) < 0) {
             throw new IndexOutOfBoundsException();
         }
+        if (dir != DIRECTION_LTR && dir != DIRECTION_RTL) {
+            throw new IllegalArgumentException("Unknown direction: " + dir);
+        }
 
         int modifiers = setupModifiers(paint);
         try {
-            nDrawTextRun(mRenderer, text, index, count, contextIndex, contextCount, x, y,
+            nDrawTextRun(mRenderer, text, index, count, contextIndex, contextCount, x, y, dir,
                     paint.mNativePaint);
         } finally {
             if (modifiers != MODIFIER_NONE) nResetModifiers(mRenderer, modifiers);
@@ -1271,31 +1277,32 @@
     }
 
     private static native void nDrawTextRun(int renderer, char[] text, int index, int count,
-            int contextIndex, int contextCount, float x, float y, int nativePaint);
+            int contextIndex, int contextCount, float x, float y, int dir, int nativePaint);
 
     @Override
     public void drawTextRun(CharSequence text, int start, int end, int contextStart, int contextEnd,
-            float x, float y, Paint paint) {
+            float x, float y, int dir, Paint paint) {
         if ((start | end | end - start | text.length() - end) < 0) {
             throw new IndexOutOfBoundsException();
         }
 
         int modifiers = setupModifiers(paint);
         try {
+            int flags = dir == 0 ? 0 : 1;
             if (text instanceof String || text instanceof SpannedString ||
                     text instanceof SpannableString) {
                 nDrawTextRun(mRenderer, text.toString(), start, end, contextStart,
-                        contextEnd, x, y, paint.mNativePaint);
+                        contextEnd, x, y, flags, paint.mNativePaint);
             } else if (text instanceof GraphicsOperations) {
                 ((GraphicsOperations) text).drawTextRun(this, start, end,
-                        contextStart, contextEnd, x, y, paint);
+                        contextStart, contextEnd, x, y, flags, paint);
             } else {
                 int contextLen = contextEnd - contextStart;
                 int len = end - start;
                 char[] buf = TemporaryBuffer.obtain(contextLen);
                 TextUtils.getChars(text, contextStart, contextEnd, buf, 0);
                 nDrawTextRun(mRenderer, buf, start - contextStart, len, 0, contextLen,
-                        x, y, paint.mNativePaint);
+                        x, y, flags, paint.mNativePaint);
                 TemporaryBuffer.recycle(buf);
             }
         } finally {
@@ -1304,7 +1311,7 @@
     }
 
     private static native void nDrawTextRun(int renderer, String text, int start, int end,
-            int contextStart, int contextEnd, float x, float y, int nativePaint);
+            int contextStart, int contextEnd, float x, float y, int flags, int nativePaint);
 
     @Override
     public void drawVertices(VertexMode mode, int vertexCount, float[] verts, int vertOffset,
diff --git a/core/java/android/view/GLES20RecordingCanvas.java b/core/java/android/view/GLES20RecordingCanvas.java
index 947cf44..7da2451 100644
--- a/core/java/android/view/GLES20RecordingCanvas.java
+++ b/core/java/android/view/GLES20RecordingCanvas.java
@@ -267,15 +267,15 @@
 
     @Override
     public void drawTextRun(char[] text, int index, int count, int contextIndex, int contextCount,
-            float x, float y, Paint paint) {
-        super.drawTextRun(text, index, count, contextIndex, contextCount, x, y, paint);
+            float x, float y, int dir, Paint paint) {
+        super.drawTextRun(text, index, count, contextIndex, contextCount, x, y, dir, paint);
         recordShaderBitmap(paint);
     }
 
     @Override
     public void drawTextRun(CharSequence text, int start, int end, int contextStart,
-            int contextEnd, float x, float y, Paint paint) {
-        super.drawTextRun(text, start, end, contextStart, contextEnd, x, y, paint);
+            int contextEnd, float x, float y, int dir, Paint paint) {
+        super.drawTextRun(text, start, end, contextStart, contextEnd, x, y, dir, paint);
         recordShaderBitmap(paint);
     }
 
diff --git a/core/java/android/widget/TextView.java b/core/java/android/widget/TextView.java
index adacef2..b084ac4 100644
--- a/core/java/android/widget/TextView.java
+++ b/core/java/android/widget/TextView.java
@@ -8813,11 +8813,11 @@
         }
 
         public void drawTextRun(Canvas c, int start, int end,
-                int contextStart, int contextEnd, float x, float y, Paint p) {
+                int contextStart, int contextEnd, float x, float y, int flags, Paint p) {
             int count = end - start;
             int contextCount = contextEnd - contextStart;
             c.drawTextRun(mChars, start + mStart, count, contextStart + mStart,
-                    contextCount, x, y, p);
+                    contextCount, x, y, flags, p);
         }
 
         public float measureText(int start, int end, Paint p) {
@@ -8829,20 +8829,30 @@
         }
 
         public float getTextRunAdvances(int start, int end, int contextStart,
-                int contextEnd, float[] advances, int advancesIndex,
+                int contextEnd, int flags, float[] advances, int advancesIndex,
                 Paint p) {
             int count = end - start;
             int contextCount = contextEnd - contextStart;
             return p.getTextRunAdvances(mChars, start + mStart, count,
-                    contextStart + mStart, contextCount, advances,
+                    contextStart + mStart, contextCount, flags, advances,
                     advancesIndex);
         }
 
-        public int getTextRunCursor(int contextStart, int contextEnd,
+        public float getTextRunAdvances(int start, int end, int contextStart,
+                int contextEnd, int flags, float[] advances, int advancesIndex,
+                Paint p, int reserved) {
+            int count = end - start;
+            int contextCount = contextEnd - contextStart;
+            return p.getTextRunAdvances(mChars, start + mStart, count,
+                    contextStart + mStart, contextCount, flags, advances,
+                    advancesIndex, reserved);
+        }
+
+        public int getTextRunCursor(int contextStart, int contextEnd, int flags,
                 int offset, int cursorOpt, Paint p) {
             int contextCount = contextEnd - contextStart;
             return p.getTextRunCursor(mChars, contextStart + mStart,
-                    contextCount, offset + mStart, cursorOpt);
+                    contextCount, flags, offset + mStart, cursorOpt);
         }
     }
 
diff --git a/core/jni/android/graphics/Canvas.cpp b/core/jni/android/graphics/Canvas.cpp
index 8be86b8..9a9f6c8 100644
--- a/core/jni/android/graphics/Canvas.cpp
+++ b/core/jni/android/graphics/Canvas.cpp
@@ -754,35 +754,35 @@
 
     static void drawText___CIIFFIPaint(JNIEnv* env, jobject, SkCanvas* canvas,
                                       jcharArray text, int index, int count,
-                                      jfloat x, jfloat y, SkPaint* paint) {
+                                      jfloat x, jfloat y, int flags, SkPaint* paint) {
         jchar* textArray = env->GetCharArrayElements(text, NULL);
-        drawTextWithGlyphs(canvas, textArray + index, 0, count, x, y, paint);
+        drawTextWithGlyphs(canvas, textArray + index, 0, count, x, y, flags, paint);
         env->ReleaseCharArrayElements(text, textArray, JNI_ABORT);
     }
 
     static void drawText__StringIIFFIPaint(JNIEnv* env, jobject,
                                           SkCanvas* canvas, jstring text,
                                           int start, int end,
-                                          jfloat x, jfloat y, SkPaint* paint) {
+                                          jfloat x, jfloat y, int flags, SkPaint* paint) {
         const jchar* textArray = env->GetStringChars(text, NULL);
-        drawTextWithGlyphs(canvas, textArray, start, end, x, y, paint);
+        drawTextWithGlyphs(canvas, textArray, start, end, x, y, flags, paint);
         env->ReleaseStringChars(text, textArray);
     }
 
     static void drawTextWithGlyphs(SkCanvas* canvas, const jchar* textArray,
             int start, int end,
-            jfloat x, jfloat y, SkPaint* paint) {
+            jfloat x, jfloat y, int flags, SkPaint* paint) {
 
         jint count = end - start;
-        drawTextWithGlyphs(canvas, textArray + start, 0, count, count, x, y, paint);
+        drawTextWithGlyphs(canvas, textArray + start, 0, count, count, x, y, flags, paint);
     }
 
     static void drawTextWithGlyphs(SkCanvas* canvas, const jchar* textArray,
             int start, int count, int contextCount,
-            jfloat x, jfloat y, SkPaint* paint) {
+            jfloat x, jfloat y, int flags, SkPaint* paint) {
 
         sp<TextLayoutValue> value = TextLayoutEngine::getInstance().getValue(paint,
-                textArray, start, count, contextCount);
+                textArray, start, count, contextCount, flags);
         if (value == NULL) {
             return;
         }
@@ -793,7 +793,7 @@
             x -= value->getTotalAdvance();
         }
         paint->setTextAlign(SkPaint::kLeft_Align);
-        doDrawGlyphsPos(canvas, value->getGlyphs(), value->getPos(), 0, value->getGlyphsCount(), x, y, paint);
+        doDrawGlyphsPos(canvas, value->getGlyphs(), value->getPos(), 0, value->getGlyphsCount(), x, y, flags, paint);
         doDrawTextDecorations(canvas, x, y, value->getTotalAdvance(), paint);
         paint->setTextAlign(align);
     }
@@ -835,8 +835,14 @@
     }
 }
 
+    static void doDrawGlyphs(SkCanvas* canvas, const jchar* glyphArray, int index, int count,
+            jfloat x, jfloat y, int flags, SkPaint* paint) {
+        // Beware: this needs Glyph encoding (already done on the Paint constructor)
+        canvas->drawText(glyphArray + index * 2, count * 2, x, y, *paint);
+    }
+
     static void doDrawGlyphsPos(SkCanvas* canvas, const jchar* glyphArray, const jfloat* posArray,
-            int index, int count, jfloat x, jfloat y, SkPaint* paint) {
+            int index, int count, jfloat x, jfloat y, int flags, SkPaint* paint) {
         SkPoint* posPtr = new SkPoint[count];
         for (int indx = 0; indx < count; indx++) {
             posPtr[indx].fX = SkFloatToScalar(x + posArray[indx * 2]);
@@ -853,7 +859,7 @@
 
         jchar* chars = env->GetCharArrayElements(text, NULL);
         drawTextWithGlyphs(canvas, chars + contextIndex, index - contextIndex,
-                count, contextCount, x, y, paint);
+                count, contextCount, x, y, dirFlags, paint);
         env->ReleaseCharArrayElements(text, chars, JNI_ABORT);
     }
 
@@ -866,7 +872,7 @@
         jint contextCount = contextEnd - contextStart;
         const jchar* chars = env->GetStringChars(text, NULL);
         drawTextWithGlyphs(canvas, chars + contextStart, start - contextStart,
-                count, contextCount, x, y, paint);
+                count, contextCount, x, y, dirFlags, paint);
         env->ReleaseStringChars(text, chars);
     }
 
@@ -929,19 +935,21 @@
 
     static void drawTextOnPath___CIIPathFFPaint(JNIEnv* env, jobject,
             SkCanvas* canvas, jcharArray text, int index, int count,
-            SkPath* path, jfloat hOffset, jfloat vOffset, SkPaint* paint) {
+            SkPath* path, jfloat hOffset, jfloat vOffset, jint bidiFlags, SkPaint* paint) {
 
         jchar* textArray = env->GetCharArrayElements(text, NULL);
-        TextLayout::drawTextOnPath(paint, textArray + index, count, hOffset, vOffset, path, canvas);
+        TextLayout::drawTextOnPath(paint, textArray + index, count, bidiFlags, hOffset, vOffset,
+                                   path, canvas);
         env->ReleaseCharArrayElements(text, textArray, 0);
     }
 
     static void drawTextOnPath__StringPathFFPaint(JNIEnv* env, jobject,
             SkCanvas* canvas, jstring text, SkPath* path,
-            jfloat hOffset, jfloat vOffset, SkPaint* paint) {
+            jfloat hOffset, jfloat vOffset, jint bidiFlags, SkPaint* paint) {
         const jchar* text_ = env->GetStringChars(text, NULL);
         int count = env->GetStringLength(text);
-        TextLayout::drawTextOnPath(paint, text_, count, hOffset, vOffset, path, canvas);
+        TextLayout::drawTextOnPath(paint, text_, count, bidiFlags, hOffset, vOffset,
+                                   path, canvas);
         env->ReleaseStringChars(text, text_);
     }
 
@@ -1051,21 +1059,21 @@
         (void*)SkCanvasGlue::drawBitmapMesh},
     {"nativeDrawVertices", "(III[FI[FI[II[SIII)V",
         (void*)SkCanvasGlue::drawVertices},
-    {"native_drawText","(I[CIIFFI)V",
+    {"native_drawText","(I[CIIFFII)V",
         (void*) SkCanvasGlue::drawText___CIIFFIPaint},
-    {"native_drawText","(ILjava/lang/String;IIFFI)V",
+    {"native_drawText","(ILjava/lang/String;IIFFII)V",
         (void*) SkCanvasGlue::drawText__StringIIFFIPaint},
-    {"native_drawTextRun","(I[CIIIIFFI)V",
+    {"native_drawTextRun","(I[CIIIIFFII)V",
         (void*) SkCanvasGlue::drawTextRun___CIIIIFFIPaint},
-    {"native_drawTextRun","(ILjava/lang/String;IIIIFFI)V",
+    {"native_drawTextRun","(ILjava/lang/String;IIIIFFII)V",
         (void*) SkCanvasGlue::drawTextRun__StringIIIIFFIPaint},
     {"native_drawPosText","(I[CII[FI)V",
         (void*) SkCanvasGlue::drawPosText___CII_FPaint},
     {"native_drawPosText","(ILjava/lang/String;[FI)V",
         (void*) SkCanvasGlue::drawPosText__String_FPaint},
-    {"native_drawTextOnPath","(I[CIIIFFI)V",
+    {"native_drawTextOnPath","(I[CIIIFFII)V",
         (void*) SkCanvasGlue::drawTextOnPath___CIIPathFFPaint},
-    {"native_drawTextOnPath","(ILjava/lang/String;IFFI)V",
+    {"native_drawTextOnPath","(ILjava/lang/String;IFFII)V",
         (void*) SkCanvasGlue::drawTextOnPath__StringPathFFPaint},
     {"native_drawPicture", "(II)V", (void*) SkCanvasGlue::drawPicture},
 
diff --git a/core/jni/android/graphics/Paint.cpp b/core/jni/android/graphics/Paint.cpp
index e8304923..29a36de 100644
--- a/core/jni/android/graphics/Paint.cpp
+++ b/core/jni/android/graphics/Paint.cpp
@@ -401,7 +401,7 @@
         jfloat result = 0;
 
         TextLayout::getTextRunAdvances(paint, textArray, index, count, textLength,
-                NULL /* dont need all advances */, &result);
+                paint->getFlags(), NULL /* dont need all advances */, &result);
 
         env->ReleaseCharArrayElements(text, const_cast<jchar*>(textArray), JNI_ABORT);
         return result;
@@ -426,7 +426,7 @@
         jfloat width = 0;
 
         TextLayout::getTextRunAdvances(paint, textArray, start, count, textLength,
-                NULL /* dont need all advances */, &width);
+                paint->getFlags(), NULL /* dont need all advances */, &width);
 
         env->ReleaseStringChars(text, textArray);
         return width;
@@ -446,7 +446,7 @@
         jfloat width = 0;
 
         TextLayout::getTextRunAdvances(paint, textArray, 0, textLength, textLength,
-                NULL /* dont need all advances */, &width);
+                paint->getFlags(), NULL /* dont need all advances */, &width);
 
         env->ReleaseStringChars(text, textArray);
         return width;
@@ -473,7 +473,7 @@
         jfloat* widthsArray = autoWidths.ptr();
 
         TextLayout::getTextRunAdvances(paint, text, 0, count, count,
-                widthsArray, NULL /* dont need totalAdvance */);
+                paint->getFlags(), widthsArray, NULL /* dont need totalAdvance */);
 
         return count;
     }
@@ -494,8 +494,48 @@
         return count;
     }
 
+    static int doTextGlyphs(JNIEnv* env, SkPaint* paint, const jchar* text, jint start, jint count,
+            jint contextCount, jint flags, jcharArray glyphs) {
+        NPE_CHECK_RETURN_ZERO(env, paint);
+        NPE_CHECK_RETURN_ZERO(env, text);
+
+        if ((start | count | contextCount) < 0 || contextCount < count || !glyphs) {
+            doThrowAIOOBE(env);
+            return 0;
+        }
+        if (count == 0) {
+            return 0;
+        }
+        size_t glypthsLength = env->GetArrayLength(glyphs);
+        if ((size_t)count > glypthsLength) {
+            doThrowAIOOBE(env);
+            return 0;
+        }
+
+        jchar* glyphsArray = env->GetCharArrayElements(glyphs, NULL);
+
+        sp<TextLayoutValue> value = TextLayoutEngine::getInstance().getValue(paint,
+                text, start, count, contextCount, flags);
+        const jchar* shapedGlyphs = value->getGlyphs();
+        size_t glyphsCount = value->getGlyphsCount();
+        memcpy(glyphsArray, shapedGlyphs, sizeof(jchar) * glyphsCount);
+
+        env->ReleaseCharArrayElements(glyphs, glyphsArray, JNI_ABORT);
+        return glyphsCount;
+    }
+
+    static int getTextGlyphs__StringIIIII_C(JNIEnv* env, jobject clazz, SkPaint* paint,
+            jstring text, jint start, jint end, jint contextStart, jint contextEnd, jint flags,
+            jcharArray glyphs) {
+        const jchar* textArray = env->GetStringChars(text, NULL);
+        int count = doTextGlyphs(env, paint, textArray + contextStart, start - contextStart,
+                end - start, contextEnd - contextStart, flags, glyphs);
+        env->ReleaseStringChars(text, textArray);
+        return count;
+    }
+
     static jfloat doTextRunAdvances(JNIEnv *env, SkPaint *paint, const jchar *text,
-                                    jint start, jint count, jint contextCount,
+                                    jint start, jint count, jint contextCount, jint flags,
                                     jfloatArray advances, jint advancesIndex) {
         NPE_CHECK_RETURN_ZERO(env, paint);
         NPE_CHECK_RETURN_ZERO(env, text);
@@ -517,7 +557,7 @@
         jfloat advancesArray[count];
         jfloat totalAdvance = 0;
 
-        TextLayout::getTextRunAdvances(paint, text, start, count, contextCount,
+        TextLayout::getTextRunAdvances(paint, text, start, count, contextCount, flags,
                                        advancesArray, &totalAdvance);
 
         if (advances != NULL) {
@@ -526,23 +566,61 @@
         return totalAdvance;
     }
 
-    static float getTextRunAdvances___CIIII_FI(JNIEnv* env, jobject clazz, SkPaint* paint,
+    static jfloat doTextRunAdvancesICU(JNIEnv *env, SkPaint *paint, const jchar *text,
+                                    jint start, jint count, jint contextCount, jint flags,
+                                    jfloatArray advances, jint advancesIndex) {
+        NPE_CHECK_RETURN_ZERO(env, paint);
+        NPE_CHECK_RETURN_ZERO(env, text);
+
+        if ((start | count | contextCount | advancesIndex) < 0 || contextCount < count) {
+            doThrowAIOOBE(env);
+            return 0;
+        }
+        if (count == 0) {
+            return 0;
+        }
+        if (advances) {
+            size_t advancesLength = env->GetArrayLength(advances);
+            if ((size_t)count > advancesLength) {
+                doThrowAIOOBE(env);
+                return 0;
+            }
+        }
+
+        jfloat advancesArray[count];
+        jfloat totalAdvance = 0;
+
+        TextLayout::getTextRunAdvancesICU(paint, text, start, count, contextCount, flags,
+                                       advancesArray, totalAdvance);
+
+        if (advances != NULL) {
+            env->SetFloatArrayRegion(advances, advancesIndex, count, advancesArray);
+        }
+        return totalAdvance;
+    }
+
+    static float getTextRunAdvances___CIIIII_FII(JNIEnv* env, jobject clazz, SkPaint* paint,
             jcharArray text, jint index, jint count, jint contextIndex, jint contextCount,
-            jfloatArray advances, jint advancesIndex) {
+            jint flags, jfloatArray advances, jint advancesIndex, jint reserved) {
         jchar* textArray = env->GetCharArrayElements(text, NULL);
-        jfloat result = doTextRunAdvances(env, paint, textArray + contextIndex,
-                index - contextIndex, count, contextCount, advances, advancesIndex);
+        jfloat result = (reserved == 0) ?
+                doTextRunAdvances(env, paint, textArray + contextIndex, index - contextIndex,
+                        count, contextCount, flags, advances, advancesIndex) :
+                doTextRunAdvancesICU(env, paint, textArray + contextIndex, index - contextIndex,
+                        count, contextCount, flags, advances, advancesIndex);
         env->ReleaseCharArrayElements(text, textArray, JNI_ABORT);
         return result;
     }
 
-    static float getTextRunAdvances__StringIIII_FI(JNIEnv* env, jobject clazz, SkPaint* paint,
-            jstring text, jint start, jint end, jint contextStart, jint contextEnd,
-            jfloatArray advances, jint advancesIndex) {
+    static float getTextRunAdvances__StringIIIII_FII(JNIEnv* env, jobject clazz, SkPaint* paint,
+            jstring text, jint start, jint end, jint contextStart, jint contextEnd, jint flags,
+            jfloatArray advances, jint advancesIndex, jint reserved) {
         const jchar* textArray = env->GetStringChars(text, NULL);
-        jfloat result = doTextRunAdvances(env, paint, textArray + contextStart,
-                start - contextStart, end - start, contextEnd - contextStart,
-                advances, advancesIndex);
+        jfloat result = (reserved == 0) ?
+                doTextRunAdvances(env, paint, textArray + contextStart, start - contextStart,
+                        end - start, contextEnd - contextStart, flags, advances, advancesIndex) :
+                doTextRunAdvancesICU(env, paint, textArray + contextStart, start - contextStart,
+                        end - start, contextEnd - contextStart, flags, advances, advancesIndex);
         env->ReleaseStringChars(text, textArray);
         return result;
     }
@@ -551,7 +629,7 @@
             jint count, jint flags, jint offset, jint opt) {
         jfloat scalarArray[count];
 
-        TextLayout::getTextRunAdvances(paint, text, start, count, start + count,
+        TextLayout::getTextRunAdvances(paint, text, start, count, start + count, flags,
                 scalarArray, NULL /* dont need totalAdvance */);
 
         jint pos = offset - start;
@@ -610,21 +688,21 @@
     }
 
     static void getTextPath(JNIEnv* env, SkPaint* paint, const jchar* text, jint count,
-                            jfloat x, jfloat y, SkPath *path) {
-        TextLayout::getTextPath(paint, text, count, x, y, path);
+                            jint bidiFlags, jfloat x, jfloat y, SkPath *path) {
+        TextLayout::getTextPath(paint, text, count, bidiFlags, x, y, path);
     }
 
-    static void getTextPath___C(JNIEnv* env, jobject clazz, SkPaint* paint,
+    static void getTextPath___C(JNIEnv* env, jobject clazz, SkPaint* paint, jint bidiFlags,
             jcharArray text, int index, int count, jfloat x, jfloat y, SkPath* path) {
         const jchar* textArray = env->GetCharArrayElements(text, NULL);
-        getTextPath(env, paint, textArray + index, count, x, y, path);
+        getTextPath(env, paint, textArray + index, count, bidiFlags, x, y, path);
         env->ReleaseCharArrayElements(text, const_cast<jchar*>(textArray), JNI_ABORT);
     }
 
-    static void getTextPath__String(JNIEnv* env, jobject clazz, SkPaint* paint,
+    static void getTextPath__String(JNIEnv* env, jobject clazz, SkPaint* paint, jint bidiFlags,
             jstring text, int start, int end, jfloat x, jfloat y, SkPath* path) {
         const jchar* textArray = env->GetStringChars(text, NULL);
-        getTextPath(env, paint, textArray + start, end - start, x, y, path);
+        getTextPath(env, paint, textArray + start, end - start, bidiFlags, x, y, path);
         env->ReleaseStringChars(text, textArray);
     }
 
@@ -648,7 +726,7 @@
                          int count, float maxWidth, jfloatArray jmeasured,
                          SkPaint::TextBufferDirection tbd) {
         sp<TextLayoutValue> value = TextLayoutEngine::getInstance().getValue(&paint,
-                text, 0, count, count);
+                text, 0, count, count, paint.getFlags());
         if (value == NULL) {
             return 0;
         }
@@ -720,7 +798,7 @@
         SkIRect ir;
 
         sp<TextLayoutValue> value = TextLayoutEngine::getInstance().getValue(&paint,
-                text, 0, count, count);
+                text, 0, count, count, paint.getFlags());
         if (value == NULL) {
             return;
         }
@@ -808,15 +886,19 @@
     {"native_breakText","(Ljava/lang/String;ZF[F)I", (void*) SkPaintGlue::breakTextS},
     {"native_getTextWidths","(I[CII[F)I", (void*) SkPaintGlue::getTextWidths___CII_F},
     {"native_getTextWidths","(ILjava/lang/String;II[F)I", (void*) SkPaintGlue::getTextWidths__StringII_F},
-    {"native_getTextRunAdvances","(I[CIIII[FI)F",
-        (void*) SkPaintGlue::getTextRunAdvances___CIIII_FI},
-    {"native_getTextRunAdvances","(ILjava/lang/String;IIII[FI)F",
-        (void*) SkPaintGlue::getTextRunAdvances__StringIIII_FI},
-    {"native_getTextRunCursor", "(I[CIIII)I", (void*) SkPaintGlue::getTextRunCursor___C},
-    {"native_getTextRunCursor", "(ILjava/lang/String;IIII)I",
+    {"native_getTextRunAdvances","(I[CIIIII[FII)F",
+        (void*) SkPaintGlue::getTextRunAdvances___CIIIII_FII},
+    {"native_getTextRunAdvances","(ILjava/lang/String;IIIII[FII)F",
+        (void*) SkPaintGlue::getTextRunAdvances__StringIIIII_FII},
+
+
+    {"native_getTextGlyphs","(ILjava/lang/String;IIIII[C)I",
+        (void*) SkPaintGlue::getTextGlyphs__StringIIIII_C},
+    {"native_getTextRunCursor", "(I[CIIIII)I", (void*) SkPaintGlue::getTextRunCursor___C},
+    {"native_getTextRunCursor", "(ILjava/lang/String;IIIII)I",
         (void*) SkPaintGlue::getTextRunCursor__String},
-    {"native_getTextPath","(I[CIIFFI)V", (void*) SkPaintGlue::getTextPath___C},
-    {"native_getTextPath","(ILjava/lang/String;IIFFI)V", (void*) SkPaintGlue::getTextPath__String},
+    {"native_getTextPath","(II[CIIFFI)V", (void*) SkPaintGlue::getTextPath___C},
+    {"native_getTextPath","(IILjava/lang/String;IIFFI)V", (void*) SkPaintGlue::getTextPath__String},
     {"nativeGetStringBounds", "(ILjava/lang/String;IILandroid/graphics/Rect;)V",
                                         (void*) SkPaintGlue::getStringBounds },
     {"nativeGetCharArrayBounds", "(I[CIILandroid/graphics/Rect;)V",
diff --git a/core/jni/android/graphics/TextLayout.cpp b/core/jni/android/graphics/TextLayout.cpp
index b77236c..2beedad 100644
--- a/core/jni/android/graphics/TextLayout.cpp
+++ b/core/jni/android/graphics/TextLayout.cpp
@@ -28,13 +28,33 @@
 
 namespace android {
 
+// Returns true if we might need layout.  If bidiFlags force LTR, assume no layout, if
+// bidiFlags indicate there probably is RTL, assume we do, otherwise scan the text
+// looking for a character >= the first RTL character in unicode and assume we do if
+// we find one.
+bool TextLayout::needsLayout(const jchar* text, jint len, jint bidiFlags) {
+    if (bidiFlags == kBidi_Force_LTR) {
+        return false;
+    }
+    if ((bidiFlags == kBidi_RTL) || (bidiFlags == kBidi_Default_RTL) ||
+            bidiFlags == kBidi_Force_RTL) {
+        return true;
+    }
+    for (int i = 0; i < len; ++i) {
+        if (text[i] >= UNICODE_FIRST_RTL_CHAR) {
+            return true;
+        }
+    }
+    return false;
+}
+
 // Draws or gets the path of a paragraph of text on a single line, running bidi and shaping.
 // This will draw if canvas is not null, otherwise path must be non-null and it will create
 // a path representing the text that would have been drawn.
 void TextLayout::handleText(SkPaint *paint, const jchar* text, jsize len,
-                            jfloat x, jfloat y, SkPath *path) {
+                            jint bidiFlags, jfloat x, jfloat y, SkPath *path) {
     sp<TextLayoutValue> value = TextLayoutEngine::getInstance().getValue(paint,
-            text, 0, len, len);
+            text, 0, len, len, bidiFlags);
     if (value == NULL) {
         return ;
     }
@@ -45,10 +65,10 @@
 }
 
 void TextLayout::getTextRunAdvances(SkPaint* paint, const jchar* chars, jint start,
-                                    jint count, jint contextCount,
+                                    jint count, jint contextCount, jint dirFlags,
                                     jfloat* resultAdvances, jfloat* resultTotalAdvance) {
     sp<TextLayoutValue> value = TextLayoutEngine::getInstance().getValue(paint,
-            chars, start, count, contextCount);
+            chars, start, count, contextCount, dirFlags);
     if (value == NULL) {
         return ;
     }
@@ -60,20 +80,29 @@
     }
 }
 
-void TextLayout::getTextPath(SkPaint *paint, const jchar *text, jsize len,
-                             jfloat x, jfloat y, SkPath *path) {
-    handleText(paint, text, len, x, y, path);
+void TextLayout::getTextRunAdvancesICU(SkPaint* paint, const jchar* chars, jint start,
+                                    jint count, jint contextCount, jint dirFlags,
+                                    jfloat* resultAdvances, jfloat& resultTotalAdvance) {
+    // Compute advances and return them
+    computeAdvancesWithICU(paint, chars, start, count, contextCount, dirFlags,
+            resultAdvances, &resultTotalAdvance);
 }
 
+void TextLayout::getTextPath(SkPaint *paint, const jchar *text, jsize len,
+                             jint bidiFlags, jfloat x, jfloat y, SkPath *path) {
+    handleText(paint, text, len, bidiFlags, x, y, path);
+}
+
+
 void TextLayout::drawTextOnPath(SkPaint* paint, const jchar* text, int count,
-                                jfloat hOffset, jfloat vOffset,
+                                int bidiFlags, jfloat hOffset, jfloat vOffset,
                                 SkPath* path, SkCanvas* canvas) {
 
     SkScalar h_ = SkFloatToScalar(hOffset);
     SkScalar v_ = SkFloatToScalar(vOffset);
 
     sp<TextLayoutValue> value = TextLayoutEngine::getInstance().getValue(paint,
-            text, 0, count, count);
+            text, 0, count, count, bidiFlags);
     if (value == NULL) {
         return;
     }
@@ -82,4 +111,73 @@
     canvas->drawTextOnPathHV(value->getGlyphs(), value->getGlyphsCount() * 2, *path, h_, v_, *paint);
 }
 
+void TextLayout::computeAdvancesWithICU(SkPaint* paint, const UChar* chars,
+        size_t start, size_t count, size_t contextCount, int dirFlags,
+        jfloat* outAdvances, jfloat* outTotalAdvance) {
+    SkAutoSTMalloc<CHAR_BUFFER_SIZE, jchar> tempBuffer(contextCount);
+    jchar* buffer = tempBuffer.get();
+    SkScalar* scalarArray = (SkScalar*)outAdvances;
+
+    // this is where we'd call harfbuzz
+    // for now we just use ushape.c
+    size_t widths;
+    const jchar* text;
+    if (dirFlags & 0x1) { // rtl, call arabic shaping in case
+        UErrorCode status = U_ZERO_ERROR;
+        // Use fixed length since we need to keep start and count valid
+        u_shapeArabic(chars, contextCount, buffer, contextCount,
+                U_SHAPE_LENGTH_FIXED_SPACES_NEAR |
+                U_SHAPE_TEXT_DIRECTION_LOGICAL | U_SHAPE_LETTERS_SHAPE |
+                U_SHAPE_X_LAMALEF_SUB_ALTERNATE, &status);
+        // we shouldn't fail unless there's an out of memory condition,
+        // in which case we're hosed anyway
+        for (int i = start, e = i + count; i < e; ++i) {
+            if (buffer[i] == UNICODE_NOT_A_CHAR) {
+                buffer[i] = UNICODE_ZWSP; // zero-width-space for skia
+            }
+        }
+        text = buffer + start;
+        widths = paint->getTextWidths(text, count << 1, scalarArray);
+    } else {
+        text = chars + start;
+        widths = paint->getTextWidths(text, count << 1, scalarArray);
+    }
+
+    jfloat totalAdvance = 0;
+    if (widths < count) {
+#if DEBUG_ADVANCES
+    ALOGD("ICU -- count=%d", widths);
+#endif
+        // Skia operates on code points, not code units, so surrogate pairs return only
+        // one value. Expand the result so we have one value per UTF-16 code unit.
+
+        // Note, skia's getTextWidth gets confused if it encounters a surrogate pair,
+        // leaving the remaining widths zero.  Not nice.
+        for (size_t i = 0, p = 0; i < widths; ++i) {
+            totalAdvance += outAdvances[p++] = SkScalarToFloat(scalarArray[i]);
+            if (p < count &&
+                    text[p] >= UNICODE_FIRST_LOW_SURROGATE &&
+                    text[p] < UNICODE_FIRST_PRIVATE_USE &&
+                    text[p-1] >= UNICODE_FIRST_HIGH_SURROGATE &&
+                    text[p-1] < UNICODE_FIRST_LOW_SURROGATE) {
+                outAdvances[p++] = 0;
+            }
+#if DEBUG_ADVANCES
+            ALOGD("icu-adv = %f - total = %f", outAdvances[i], totalAdvance);
+#endif
+        }
+    } else {
+#if DEBUG_ADVANCES
+    ALOGD("ICU -- count=%d", count);
+#endif
+        for (size_t i = 0; i < count; i++) {
+            totalAdvance += outAdvances[i] = SkScalarToFloat(scalarArray[i]);
+#if DEBUG_ADVANCES
+            ALOGD("icu-adv = %f - total = %f", outAdvances[i], totalAdvance);
+#endif
+        }
+    }
+    *outTotalAdvance = totalAdvance;
+}
+
 }
diff --git a/core/jni/android/graphics/TextLayout.h b/core/jni/android/graphics/TextLayout.h
index fa388c8..a0f9402 100644
--- a/core/jni/android/graphics/TextLayout.h
+++ b/core/jni/android/graphics/TextLayout.h
@@ -42,6 +42,17 @@
 #define USE_TEXT_LAYOUT_CACHE 1
 
 enum {
+    kBidi_LTR = 0,
+    kBidi_RTL = 1,
+    kBidi_Default_LTR = 2,
+    kBidi_Default_RTL = 3,
+    kBidi_Force_LTR = 4,
+    kBidi_Force_RTL = 5,
+
+    kBidi_Mask = 0x7
+};
+
+enum {
     kDirection_LTR = 0,
     kDirection_RTL = 1,
 
@@ -52,18 +63,28 @@
 public:
 
     static void getTextRunAdvances(SkPaint* paint, const jchar* chars, jint start,
-                                   jint count, jint contextCount,
+                                   jint count, jint contextCount, jint dirFlags,
                                    jfloat* resultAdvances, jfloat* resultTotalAdvance);
 
+    static void getTextRunAdvancesICU(SkPaint* paint, const jchar* chars, jint start,
+                                   jint count, jint contextCount, jint dirFlags,
+                                   jfloat* resultAdvances, jfloat& resultTotalAdvance);
+
     static void getTextPath(SkPaint* paint, const jchar* text, jsize len,
-                            jfloat x, jfloat y, SkPath* path);
+                            jint bidiFlags, jfloat x, jfloat y, SkPath* path);
 
     static void drawTextOnPath(SkPaint* paint, const jchar* text, jsize len,
-                               jfloat hOffset, jfloat vOffset,
+                               int bidiFlags, jfloat hOffset, jfloat vOffset,
                                SkPath* path, SkCanvas* canvas);
 
 private:
+    static bool needsLayout(const jchar* text, jint len, jint bidiFlags);
+
     static void handleText(SkPaint* paint, const jchar* text, jsize len,
-                           jfloat x, jfloat y, SkPath* path);
+                           int bidiFlags, jfloat x, jfloat y, SkPath* path);
+
+    static void computeAdvancesWithICU(SkPaint* paint, const UChar* chars,
+            size_t start, size_t count, size_t contextCount, int dirFlags,
+            jfloat* outAdvances, jfloat* outTotalAdvance);
 };
 } // namespace android
diff --git a/core/jni/android/graphics/TextLayoutCache.cpp b/core/jni/android/graphics/TextLayoutCache.cpp
index 1a8612e..1ace23e 100644
--- a/core/jni/android/graphics/TextLayoutCache.cpp
+++ b/core/jni/android/graphics/TextLayoutCache.cpp
@@ -87,7 +87,7 @@
  * Caching
  */
 sp<TextLayoutValue> TextLayoutCache::getValue(const SkPaint* paint,
-            const jchar* text, jint start, jint count, jint contextCount) {
+            const jchar* text, jint start, jint count, jint contextCount, jint dirFlags) {
     AutoMutex _l(mLock);
     nsecs_t startTime = 0;
     if (mDebugEnabled) {
@@ -95,7 +95,7 @@
     }
 
     // Create the key
-    TextLayoutCacheKey key(paint, text, start, count, contextCount);
+    TextLayoutCacheKey key(paint, text, start, count, contextCount, dirFlags);
 
     // Get value from cache if possible
     sp<TextLayoutValue> value = mCache.get(key);
@@ -111,7 +111,7 @@
         // Compute advances and store them
         mShaper->computeValues(value.get(), paint,
                 reinterpret_cast<const UChar*>(key.getText()), start, count,
-                size_t(contextCount));
+                size_t(contextCount), int(dirFlags));
 
         if (mDebugEnabled) {
             value->setElapsedTime(systemTime(SYSTEM_TIME_MONOTONIC) - startTime);
@@ -218,13 +218,14 @@
  * TextLayoutCacheKey
  */
 TextLayoutCacheKey::TextLayoutCacheKey(): start(0), count(0), contextCount(0),
-        typeface(NULL), textSize(0), textSkewX(0), textScaleX(0), flags(0),
+        dirFlags(0), typeface(NULL), textSize(0), textSkewX(0), textScaleX(0), flags(0),
         hinting(SkPaint::kNo_Hinting), variant(SkPaint::kDefault_Variant), language()  {
 }
 
 TextLayoutCacheKey::TextLayoutCacheKey(const SkPaint* paint, const UChar* text,
-        size_t start, size_t count, size_t contextCount) :
-            start(start), count(count), contextCount(contextCount) {
+        size_t start, size_t count, size_t contextCount, int dirFlags) :
+            start(start), count(count), contextCount(contextCount),
+            dirFlags(dirFlags) {
     textCopy.setTo(text, contextCount);
     typeface = paint->getTypeface();
     textSize = paint->getTextSize();
@@ -241,6 +242,7 @@
         start(other.start),
         count(other.count),
         contextCount(other.contextCount),
+        dirFlags(other.dirFlags),
         typeface(other.typeface),
         textSize(other.textSize),
         textSkewX(other.textSkewX),
@@ -279,6 +281,9 @@
     deltaInt = lhs.hinting - rhs.hinting;
     if (deltaInt != 0) return (deltaInt);
 
+    deltaInt = lhs.dirFlags - rhs.dirFlags;
+    if (deltaInt) return (deltaInt);
+
     deltaInt = lhs.variant - rhs.variant;
     if (deltaInt) return (deltaInt);
 
@@ -354,9 +359,9 @@
 }
 
 void TextLayoutShaper::computeValues(TextLayoutValue* value, const SkPaint* paint, const UChar* chars,
-        size_t start, size_t count, size_t contextCount) {
+        size_t start, size_t count, size_t contextCount, int dirFlags) {
 
-    computeValues(paint, chars, start, count, contextCount,
+    computeValues(paint, chars, start, count, contextCount, dirFlags,
             &value->mAdvances, &value->mTotalAdvance, &value->mGlyphs, &value->mPos);
 #if DEBUG_ADVANCES
     ALOGD("Advances - start = %d, count = %d, contextCount = %d, totalAdvance = %f", start, count,
@@ -365,7 +370,7 @@
 }
 
 void TextLayoutShaper::computeValues(const SkPaint* paint, const UChar* chars,
-        size_t start, size_t count, size_t contextCount,
+        size_t start, size_t count, size_t contextCount, int dirFlags,
         Vector<jfloat>* const outAdvances, jfloat* outTotalAdvance,
         Vector<jchar>* const outGlyphs, Vector<jfloat>* const outPos) {
         *outTotalAdvance = 0;
@@ -373,94 +378,110 @@
             return;
         }
 
-        UBiDiLevel bidiReq = UBIDI_DEFAULT_LTR;
+        UBiDiLevel bidiReq = 0;
+        bool forceLTR = false;
+        bool forceRTL = false;
+
+        switch (dirFlags & kBidi_Mask) {
+            case kBidi_LTR: bidiReq = 0; break; // no ICU constant, canonical LTR level
+            case kBidi_RTL: bidiReq = 1; break; // no ICU constant, canonical RTL level
+            case kBidi_Default_LTR: bidiReq = UBIDI_DEFAULT_LTR; break;
+            case kBidi_Default_RTL: bidiReq = UBIDI_DEFAULT_RTL; break;
+            case kBidi_Force_LTR: forceLTR = true; break; // every char is LTR
+            case kBidi_Force_RTL: forceRTL = true; break; // every char is RTL
+        }
+
         bool useSingleRun = false;
-        bool isRTL = false;
-
-        UBiDi* bidi = ubidi_open();
-        if (bidi) {
-            UErrorCode status = U_ZERO_ERROR;
+        bool isRTL = forceRTL;
+        if (forceLTR || forceRTL) {
+            useSingleRun = true;
+        } else {
+            UBiDi* bidi = ubidi_open();
+            if (bidi) {
+                UErrorCode status = U_ZERO_ERROR;
 #if DEBUG_GLYPHS
-            ALOGD("******** ComputeValues -- start");
-            ALOGD("      -- string = '%s'", String8(chars + start, count).string());
-            ALOGD("      -- start = %d", start);
-            ALOGD("      -- count = %d", count);
-            ALOGD("      -- contextCount = %d", contextCount);
-            ALOGD("      -- bidiReq = %d", bidiReq);
+                ALOGD("******** ComputeValues -- start");
+                ALOGD("      -- string = '%s'", String8(chars + start, count).string());
+                ALOGD("      -- start = %d", start);
+                ALOGD("      -- count = %d", count);
+                ALOGD("      -- contextCount = %d", contextCount);
+                ALOGD("      -- bidiReq = %d", bidiReq);
 #endif
-            ubidi_setPara(bidi, chars, contextCount, bidiReq, NULL, &status);
-            if (U_SUCCESS(status)) {
-                int paraDir = ubidi_getParaLevel(bidi) & kDirection_Mask; // 0 if ltr, 1 if rtl
-                ssize_t rc = ubidi_countRuns(bidi, &status);
+                ubidi_setPara(bidi, chars, contextCount, bidiReq, NULL, &status);
+                if (U_SUCCESS(status)) {
+                    int paraDir = ubidi_getParaLevel(bidi) & kDirection_Mask; // 0 if ltr, 1 if rtl
+                    ssize_t rc = ubidi_countRuns(bidi, &status);
 #if DEBUG_GLYPHS
-                ALOGD("      -- paraDir = %d", paraDir);
-                ALOGD("      -- run-count = %d", int(rc));
+                    ALOGD("      -- dirFlags = %d", dirFlags);
+                    ALOGD("      -- paraDir = %d", paraDir);
+                    ALOGD("      -- run-count = %d", int(rc));
 #endif
-                if (U_SUCCESS(status) && rc == 1) {
-                    // Normal case: one run, status is ok
-                    isRTL = (paraDir == 1);
-                    useSingleRun = true;
-                } else if (!U_SUCCESS(status) || rc < 1) {
-                    ALOGW("Need to force to single run -- string = '%s',"
-                            " status = %d, rc = %d",
-                            String8(chars + start, count).string(), status, int(rc));
-                    isRTL = (paraDir == 1);
-                    useSingleRun = true;
-                } else {
-                    int32_t end = start + count;
-                    for (size_t i = 0; i < size_t(rc); ++i) {
-                        int32_t startRun = -1;
-                        int32_t lengthRun = -1;
-                        UBiDiDirection runDir = ubidi_getVisualRun(bidi, i, &startRun, &lengthRun);
+                    if (U_SUCCESS(status) && rc == 1) {
+                        // Normal case: one run, status is ok
+                        isRTL = (paraDir == 1);
+                        useSingleRun = true;
+                    } else if (!U_SUCCESS(status) || rc < 1) {
+                        ALOGW("Need to force to single run -- string = '%s',"
+                                " status = %d, rc = %d",
+                                String8(chars + start, count).string(), status, int(rc));
+                        isRTL = (paraDir == 1);
+                        useSingleRun = true;
+                    } else {
+                        int32_t end = start + count;
+                        for (size_t i = 0; i < size_t(rc); ++i) {
+                            int32_t startRun = -1;
+                            int32_t lengthRun = -1;
+                            UBiDiDirection runDir = ubidi_getVisualRun(bidi, i, &startRun, &lengthRun);
 
-                        if (startRun == -1 || lengthRun == -1) {
-                            // Something went wrong when getting the visual run, need to clear
-                            // already computed data before doing a single run pass
-                            ALOGW("Visual run is not valid");
-                            outGlyphs->clear();
-                            outAdvances->clear();
-                            outPos->clear();
-                            *outTotalAdvance = 0;
-                            isRTL = (paraDir == 1);
-                            useSingleRun = true;
-                            break;
-                        }
+                            if (startRun == -1 || lengthRun == -1) {
+                                // Something went wrong when getting the visual run, need to clear
+                                // already computed data before doing a single run pass
+                                ALOGW("Visual run is not valid");
+                                outGlyphs->clear();
+                                outAdvances->clear();
+                                outPos->clear();
+                                *outTotalAdvance = 0;
+                                isRTL = (paraDir == 1);
+                                useSingleRun = true;
+                                break;
+                            }
 
-                        if (startRun >= end) {
-                            continue;
-                        }
-                        int32_t endRun = startRun + lengthRun;
-                        if (endRun <= int32_t(start)) {
-                            continue;
-                        }
-                        if (startRun < int32_t(start)) {
-                            startRun = int32_t(start);
-                        }
-                        if (endRun > end) {
-                            endRun = end;
-                        }
+                            if (startRun >= end) {
+                                continue;
+                            }
+                            int32_t endRun = startRun + lengthRun;
+                            if (endRun <= int32_t(start)) {
+                                continue;
+                            }
+                            if (startRun < int32_t(start)) {
+                                startRun = int32_t(start);
+                            }
+                            if (endRun > end) {
+                                endRun = end;
+                            }
 
-                        lengthRun = endRun - startRun;
-                        isRTL = (runDir == UBIDI_RTL);
+                            lengthRun = endRun - startRun;
+                            isRTL = (runDir == UBIDI_RTL);
 #if DEBUG_GLYPHS
-                        ALOGD("Processing Bidi Run = %d -- run-start = %d, run-len = %d, isRTL = %d",
-                                i, startRun, lengthRun, isRTL);
+                            ALOGD("Processing Bidi Run = %d -- run-start = %d, run-len = %d, isRTL = %d",
+                                    i, startRun, lengthRun, isRTL);
 #endif
-                        computeRunValues(paint, chars, startRun, lengthRun, contextCount, isRTL,
-                                outAdvances, outTotalAdvance, outGlyphs, outPos);
+                            computeRunValues(paint, chars, startRun, lengthRun, contextCount, isRTL,
+                                    outAdvances, outTotalAdvance, outGlyphs, outPos);
 
+                        }
                     }
+                } else {
+                    ALOGW("Cannot set Para");
+                    useSingleRun = true;
+                    isRTL = (bidiReq = 1) || (bidiReq = UBIDI_DEFAULT_RTL);
                 }
+                ubidi_close(bidi);
             } else {
-                ALOGW("Cannot set Para");
+                ALOGW("Cannot ubidi_open()");
                 useSingleRun = true;
                 isRTL = (bidiReq = 1) || (bidiReq = UBIDI_DEFAULT_RTL);
             }
-            ubidi_close(bidi);
-        } else {
-            ALOGW("Cannot ubidi_open()");
-            useSingleRun = true;
-            isRTL = (bidiReq = 1) || (bidiReq = UBIDI_DEFAULT_RTL);
         }
 
         // Default single run case
@@ -897,11 +918,11 @@
 }
 
 sp<TextLayoutValue> TextLayoutEngine::getValue(const SkPaint* paint, const jchar* text,
-        jint start, jint count, jint contextCount) {
+        jint start, jint count, jint contextCount, jint dirFlags) {
     sp<TextLayoutValue> value;
 #if USE_TEXT_LAYOUT_CACHE
     value = mTextLayoutCache->getValue(paint, text, start, count,
-            contextCount);
+            contextCount, dirFlags);
     if (value == NULL) {
         ALOGE("Cannot get TextLayoutCache value for text = '%s'",
                 String8(text + start, count).string());
@@ -909,7 +930,7 @@
 #else
     value = new TextLayoutValue(count);
     mShaper->computeValues(value.get(), paint,
-            reinterpret_cast<const UChar*>(text), start, count, contextCount);
+            reinterpret_cast<const UChar*>(text), start, count, contextCount, dirFlags);
 #endif
     return value;
 }
diff --git a/core/jni/android/graphics/TextLayoutCache.h b/core/jni/android/graphics/TextLayoutCache.h
index 6858c0e..f9b9900 100644
--- a/core/jni/android/graphics/TextLayoutCache.h
+++ b/core/jni/android/graphics/TextLayoutCache.h
@@ -70,7 +70,7 @@
     TextLayoutCacheKey();
 
     TextLayoutCacheKey(const SkPaint* paint, const UChar* text, size_t start, size_t count,
-            size_t contextCount);
+            size_t contextCount, int dirFlags);
 
     TextLayoutCacheKey(const TextLayoutCacheKey& other);
 
@@ -97,6 +97,7 @@
     size_t start;
     size_t count;
     size_t contextCount;
+    int dirFlags;
     SkTypeface* typeface;
     SkScalar textSize;
     SkScalar textSkewX;
@@ -180,7 +181,7 @@
     virtual ~TextLayoutShaper();
 
     void computeValues(TextLayoutValue* value, const SkPaint* paint, const UChar* chars,
-            size_t start, size_t count, size_t contextCount);
+            size_t start, size_t count, size_t contextCount, int dirFlags);
 
     void purgeCaches();
 
@@ -214,7 +215,7 @@
     size_t shapeFontRun(const SkPaint* paint);
 
     void computeValues(const SkPaint* paint, const UChar* chars,
-            size_t start, size_t count, size_t contextCount,
+            size_t start, size_t count, size_t contextCount, int dirFlags,
             Vector<jfloat>* const outAdvances, jfloat* outTotalAdvance,
             Vector<jchar>* const outGlyphs, Vector<jfloat>* const outPos);
 
@@ -251,7 +252,7 @@
     void operator()(TextLayoutCacheKey& text, sp<TextLayoutValue>& desc);
 
     sp<TextLayoutValue> getValue(const SkPaint* paint, const jchar* text, jint start,
-            jint count, jint contextCount);
+            jint count, jint contextCount, jint dirFlags);
 
     /**
      * Clear the cache
@@ -303,7 +304,7 @@
      * the call. Be careful of this when doing optimization.
      **/
     sp<TextLayoutValue> getValue(const SkPaint* paint, const jchar* text, jint start,
-            jint count, jint contextCount);
+            jint count, jint contextCount, jint dirFlags);
 
     void purgeCaches();
 
diff --git a/core/jni/android_view_GLES20Canvas.cpp b/core/jni/android_view_GLES20Canvas.cpp
index ba62f6d..10c92ba 100644
--- a/core/jni/android_view_GLES20Canvas.cpp
+++ b/core/jni/android_view_GLES20Canvas.cpp
@@ -568,9 +568,9 @@
 // ----------------------------------------------------------------------------
 
 static void renderText(OpenGLRenderer* renderer, const jchar* text, int count,
-        jfloat x, jfloat y, SkPaint* paint) {
+        jfloat x, jfloat y, int flags, SkPaint* paint) {
     sp<TextLayoutValue> value = TextLayoutEngine::getInstance().getValue(paint,
-            text, 0, count, count);
+            text, 0, count, count, flags);
     if (value == NULL) {
         return;
     }
@@ -584,9 +584,9 @@
 }
 
 static void renderTextOnPath(OpenGLRenderer* renderer, const jchar* text, int count,
-        SkPath* path, jfloat hOffset, jfloat vOffset, SkPaint* paint) {
+        SkPath* path, jfloat hOffset, jfloat vOffset, int flags, SkPaint* paint) {
     sp<TextLayoutValue> value = TextLayoutEngine::getInstance().getValue(paint,
-            text, 0, count, count);
+            text, 0, count, count, flags);
     if (value == NULL) {
         return;
     }
@@ -599,9 +599,9 @@
 
 static void renderTextRun(OpenGLRenderer* renderer, const jchar* text,
         jint start, jint count, jint contextCount, jfloat x, jfloat y,
-        SkPaint* paint) {
+        int flags, SkPaint* paint) {
     sp<TextLayoutValue> value = TextLayoutEngine::getInstance().getValue(paint,
-            text, start, count, contextCount);
+            text, start, count, contextCount, flags);
     if (value == NULL) {
         return;
     }
@@ -616,62 +616,64 @@
 
 static void android_view_GLES20Canvas_drawTextArray(JNIEnv* env, jobject clazz,
         OpenGLRenderer* renderer, jcharArray text, jint index, jint count,
-        jfloat x, jfloat y, SkPaint* paint) {
+        jfloat x, jfloat y, jint flags, SkPaint* paint) {
     jchar* textArray = env->GetCharArrayElements(text, NULL);
-    renderText(renderer, textArray + index, count, x, y, paint);
+    renderText(renderer, textArray + index, count, x, y, flags, paint);
     env->ReleaseCharArrayElements(text, textArray, JNI_ABORT);
 }
 
 static void android_view_GLES20Canvas_drawText(JNIEnv* env, jobject clazz,
         OpenGLRenderer* renderer, jstring text, jint start, jint end,
-        jfloat x, jfloat y, SkPaint* paint) {
+        jfloat x, jfloat y, jint flags, SkPaint* paint) {
     const jchar* textArray = env->GetStringChars(text, NULL);
-    renderText(renderer, textArray + start, end - start, x, y, paint);
+    renderText(renderer, textArray + start, end - start, x, y, flags, paint);
     env->ReleaseStringChars(text, textArray);
 }
 
 static void android_view_GLES20Canvas_drawTextArrayOnPath(JNIEnv* env, jobject clazz,
         OpenGLRenderer* renderer, jcharArray text, jint index, jint count,
-        SkPath* path, jfloat hOffset, jfloat vOffset, SkPaint* paint) {
+        SkPath* path, jfloat hOffset, jfloat vOffset, jint flags, SkPaint* paint) {
     jchar* textArray = env->GetCharArrayElements(text, NULL);
     renderTextOnPath(renderer, textArray + index, count, path,
-            hOffset, vOffset, paint);
+            hOffset, vOffset, flags, paint);
     env->ReleaseCharArrayElements(text, textArray, JNI_ABORT);
 }
 
 static void android_view_GLES20Canvas_drawTextOnPath(JNIEnv* env, jobject clazz,
         OpenGLRenderer* renderer, jstring text, jint start, jint end,
-        SkPath* path, jfloat hOffset, jfloat vOffset, SkPaint* paint) {
+        SkPath* path, jfloat hOffset, jfloat vOffset, jint flags, SkPaint* paint) {
     const jchar* textArray = env->GetStringChars(text, NULL);
     renderTextOnPath(renderer, textArray + start, end - start, path,
-            hOffset, vOffset, paint);
+            hOffset, vOffset, flags, paint);
     env->ReleaseStringChars(text, textArray);
 }
 
 static void android_view_GLES20Canvas_drawTextRunArray(JNIEnv* env, jobject clazz,
         OpenGLRenderer* renderer, jcharArray text, jint index, jint count,
-        jint contextIndex, jint contextCount, jfloat x, jfloat y, SkPaint* paint) {
+        jint contextIndex, jint contextCount, jfloat x, jfloat y, jint dirFlags,
+        SkPaint* paint) {
     jchar* textArray = env->GetCharArrayElements(text, NULL);
     renderTextRun(renderer, textArray + contextIndex, index - contextIndex,
-            count, contextCount, x, y, paint);
+            count, contextCount, x, y, dirFlags, paint);
     env->ReleaseCharArrayElements(text, textArray, JNI_ABORT);
  }
 
 static void android_view_GLES20Canvas_drawTextRun(JNIEnv* env, jobject clazz,
         OpenGLRenderer* renderer, jstring text, jint start, jint end,
-        jint contextStart, int contextEnd, jfloat x, jfloat y, SkPaint* paint) {
+        jint contextStart, int contextEnd, jfloat x, jfloat y, jint dirFlags,
+        SkPaint* paint) {
     const jchar* textArray = env->GetStringChars(text, NULL);
     jint count = end - start;
     jint contextCount = contextEnd - contextStart;
     renderTextRun(renderer, textArray + contextStart, start - contextStart,
-            count, contextCount, x, y, paint);
+            count, contextCount, x, y, dirFlags, paint);
     env->ReleaseStringChars(text, textArray);
 }
 
 static void renderPosText(OpenGLRenderer* renderer, const jchar* text, int count,
-        const jfloat* positions, SkPaint* paint) {
+        const jfloat* positions, jint dirFlags, SkPaint* paint) {
     sp<TextLayoutValue> value = TextLayoutEngine::getInstance().getValue(paint,
-            text, 0, count, count);
+            text, 0, count, count, dirFlags);
     if (value == NULL) {
         return;
     }
@@ -689,7 +691,7 @@
     jchar* textArray = env->GetCharArrayElements(text, NULL);
     jfloat* positions = env->GetFloatArrayElements(pos, NULL);
 
-    renderPosText(renderer, textArray + index, count, positions, paint);
+    renderPosText(renderer, textArray + index, count, positions, kBidi_LTR, paint);
 
     env->ReleaseFloatArrayElements(pos, positions, JNI_ABORT);
     env->ReleaseCharArrayElements(text, textArray, JNI_ABORT);
@@ -701,7 +703,7 @@
     const jchar* textArray = env->GetStringChars(text, NULL);
     jfloat* positions = env->GetFloatArrayElements(pos, NULL);
 
-    renderPosText(renderer, textArray + start, end - start, positions, paint);
+    renderPosText(renderer, textArray + start, end - start, positions, kBidi_LTR, paint);
 
     env->ReleaseFloatArrayElements(pos, positions, JNI_ABORT);
     env->ReleaseStringChars(text, textArray);
@@ -1005,16 +1007,16 @@
     { "nSetupPaintFilter",  "(III)V",          (void*) android_view_GLES20Canvas_setupPaintFilter },
     { "nResetPaintFilter",  "(I)V",            (void*) android_view_GLES20Canvas_resetPaintFilter },
 
-    { "nDrawText",          "(I[CIIFFI)V",    (void*) android_view_GLES20Canvas_drawTextArray },
-    { "nDrawText",          "(ILjava/lang/String;IIFFI)V",
+    { "nDrawText",          "(I[CIIFFII)V",    (void*) android_view_GLES20Canvas_drawTextArray },
+    { "nDrawText",          "(ILjava/lang/String;IIFFII)V",
             (void*) android_view_GLES20Canvas_drawText },
 
-    { "nDrawTextOnPath",    "(I[CIIIFFI)V",   (void*) android_view_GLES20Canvas_drawTextArrayOnPath },
-    { "nDrawTextOnPath",    "(ILjava/lang/String;IIIFFI)V",
+    { "nDrawTextOnPath",    "(I[CIIIFFII)V",   (void*) android_view_GLES20Canvas_drawTextArrayOnPath },
+    { "nDrawTextOnPath",    "(ILjava/lang/String;IIIFFII)V",
             (void*) android_view_GLES20Canvas_drawTextOnPath },
 
-    { "nDrawTextRun",       "(I[CIIIIFFI)V",  (void*) android_view_GLES20Canvas_drawTextRunArray },
-    { "nDrawTextRun",       "(ILjava/lang/String;IIIIFFI)V",
+    { "nDrawTextRun",       "(I[CIIIIFFII)V",  (void*) android_view_GLES20Canvas_drawTextRunArray },
+    { "nDrawTextRun",       "(ILjava/lang/String;IIIIFFII)V",
             (void*) android_view_GLES20Canvas_drawTextRun },
 
     { "nDrawPosText",       "(I[CII[FI)V",     (void*) android_view_GLES20Canvas_drawPosTextArray },
diff --git a/graphics/java/android/graphics/Canvas.java b/graphics/java/android/graphics/Canvas.java
index 9bb90f1..4df5c24 100644
--- a/graphics/java/android/graphics/Canvas.java
+++ b/graphics/java/android/graphics/Canvas.java
@@ -62,6 +62,18 @@
     @SuppressWarnings({"UnusedDeclaration"})
     private int mSurfaceFormat;
 
+    /**
+     * Flag for drawTextRun indicating left-to-right run direction.
+     * @hide
+     */
+    public static final int DIRECTION_LTR = 0;
+    
+    /**
+     * Flag for drawTextRun indicating right-to-left run direction.
+     * @hide
+     */
+    public static final int DIRECTION_RTL = 1;
+
     // Maximum bitmap size as defined in Skia's native code
     // (see SkCanvas.cpp, SkDraw.cpp)
     private static final int MAXMIMUM_BITMAP_SIZE = 32766;
@@ -1333,7 +1345,8 @@
             (text.length - index - count)) < 0) {
             throw new IndexOutOfBoundsException();
         }
-        native_drawText(mNativeCanvas, text, index, count, x, y, paint.mNativePaint);
+        native_drawText(mNativeCanvas, text, index, count, x, y, paint.mBidiFlags,
+                paint.mNativePaint);
     }
 
     /**
@@ -1346,7 +1359,8 @@
      * @param paint The paint used for the text (e.g. color, size, style)
      */
     public void drawText(String text, float x, float y, Paint paint) {
-        native_drawText(mNativeCanvas, text, 0, text.length(), x, y, paint.mNativePaint);
+        native_drawText(mNativeCanvas, text, 0, text.length(), x, y, paint.mBidiFlags,
+                paint.mNativePaint);
     }
 
     /**
@@ -1364,7 +1378,8 @@
         if ((start | end | (end - start) | (text.length() - end)) < 0) {
             throw new IndexOutOfBoundsException();
         }
-        native_drawText(mNativeCanvas, text, start, end, x, y, paint.mNativePaint);
+        native_drawText(mNativeCanvas, text, start, end, x, y, paint.mBidiFlags,
+                paint.mNativePaint);
     }
 
     /**
@@ -1383,14 +1398,16 @@
     public void drawText(CharSequence text, int start, int end, float x, float y, Paint paint) {
         if (text instanceof String || text instanceof SpannedString ||
             text instanceof SpannableString) {
-            native_drawText(mNativeCanvas, text.toString(), start, end, x, y, paint.mNativePaint);
+            native_drawText(mNativeCanvas, text.toString(), start, end, x, y,
+                            paint.mBidiFlags, paint.mNativePaint);
         } 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);
-            native_drawText(mNativeCanvas, buf, 0, end - start, x, y, paint.mNativePaint);
+            native_drawText(mNativeCanvas, buf, 0, end - start, x, y,
+                    paint.mBidiFlags, paint.mNativePaint);
             TemporaryBuffer.recycle(buf);
         }
     }
@@ -1411,11 +1428,13 @@
      *         + count.
      * @param x the x position at which to draw the text
      * @param y the y position at which to draw the text
+     * @param dir the run direction, either {@link #DIRECTION_LTR} or
+     *         {@link #DIRECTION_RTL}.
      * @param paint the paint
      * @hide
      */
     public void drawTextRun(char[] text, int index, int count, int contextIndex, int contextCount,
-            float x, float y, Paint paint) {
+            float x, float y, int dir, Paint paint) {
 
         if (text == null) {
             throw new NullPointerException("text is null");
@@ -1426,9 +1445,12 @@
         if ((index | count | text.length - index - count) < 0) {
             throw new IndexOutOfBoundsException();
         }
+        if (dir != DIRECTION_LTR && dir != DIRECTION_RTL) {
+            throw new IllegalArgumentException("unknown dir: " + dir);
+        }
 
         native_drawTextRun(mNativeCanvas, text, index, count,
-                contextIndex, contextCount, x, y, paint.mNativePaint);
+                contextIndex, contextCount, x, y, dir, paint.mNativePaint);
     }
 
     /**
@@ -1444,11 +1466,12 @@
      *            position can be used for shaping context.
      * @param x the x position at which to draw the text
      * @param y the y position at which to draw the text
+     * @param dir the run direction, either 0 for LTR or 1 for RTL.
      * @param paint the paint
      * @hide
      */
     public void drawTextRun(CharSequence text, int start, int end, int contextStart, int contextEnd,
-            float x, float y, Paint paint) {
+            float x, float y, int dir, Paint paint) {
 
         if (text == null) {
             throw new NullPointerException("text is null");
@@ -1460,20 +1483,22 @@
             throw new IndexOutOfBoundsException();
         }
 
+        int flags = dir == 0 ? 0 : 1;
+
         if (text instanceof String || text instanceof SpannedString ||
                 text instanceof SpannableString) {
             native_drawTextRun(mNativeCanvas, text.toString(), start, end,
-                    contextStart, contextEnd, x, y, paint.mNativePaint);
+                    contextStart, contextEnd, x, y, flags, paint.mNativePaint);
         } else if (text instanceof GraphicsOperations) {
             ((GraphicsOperations) text).drawTextRun(this, start, end,
-                    contextStart, contextEnd, x, y, paint);
+                    contextStart, contextEnd, x, y, flags, paint);
         } else {
             int contextLen = contextEnd - contextStart;
             int len = end - start;
             char[] buf = TemporaryBuffer.obtain(contextLen);
             TextUtils.getChars(text, contextStart, contextEnd, buf, 0);
             native_drawTextRun(mNativeCanvas, buf, start - contextStart, len,
-                    0, contextLen, x, y, paint.mNativePaint);
+                    0, contextLen, x, y, flags, paint.mNativePaint);
             TemporaryBuffer.recycle(buf);
         }
     }
@@ -1539,7 +1564,8 @@
             throw new ArrayIndexOutOfBoundsException();
         }
         native_drawTextOnPath(mNativeCanvas, text, index, count,
-                              path.ni(), hOffset, vOffset, paint.mNativePaint);
+                              path.ni(), hOffset, vOffset,
+                              paint.mBidiFlags, paint.mNativePaint);
     }
 
     /**
@@ -1558,7 +1584,7 @@
     public void drawTextOnPath(String text, Path path, float hOffset, float vOffset, Paint paint) {
         if (text.length() > 0) {
             native_drawTextOnPath(mNativeCanvas, text, path.ni(), hOffset, vOffset,
-                    paint.mNativePaint);
+                    paint.mBidiFlags, paint.mNativePaint);
         }
     }
 
@@ -1720,18 +1746,18 @@
     
     private static native void native_drawText(int nativeCanvas, char[] text,
                                                int index, int count, float x,
-                                               float y, int paint);
+                                               float y, int flags, int paint);
     private static native void native_drawText(int nativeCanvas, String text,
                                                int start, int end, float x,
-                                               float y, int paint);
+                                               float y, int flags, int paint);
 
     private static native void native_drawTextRun(int nativeCanvas, String text,
             int start, int end, int contextStart, int contextEnd,
-            float x, float y, int paint);
+            float x, float y, int flags, int paint);
 
     private static native void native_drawTextRun(int nativeCanvas, char[] text,
             int start, int count, int contextStart, int contextCount,
-            float x, float y, int paint);
+            float x, float y, int flags, int paint);
 
     private static native void native_drawPosText(int nativeCanvas,
                                                   char[] text, int index,
@@ -1744,13 +1770,13 @@
                                                      char[] text, int index,
                                                      int count, int path,
                                                      float hOffset,
-                                                     float vOffset,
+                                                     float vOffset, int bidiFlags,
                                                      int paint);
     private static native void native_drawTextOnPath(int nativeCanvas,
                                                      String text, int path,
                                                      float hOffset, 
                                                      float vOffset, 
-                                                     int paint);
+                                                     int flags, int paint);
     private static native void native_drawPicture(int nativeCanvas,
                                                   int nativePicture);
     private static native void finalizer(int nativeCanvas);
diff --git a/graphics/java/android/graphics/Paint.java b/graphics/java/android/graphics/Paint.java
index fd45409..216dc6c 100644
--- a/graphics/java/android/graphics/Paint.java
+++ b/graphics/java/android/graphics/Paint.java
@@ -69,6 +69,11 @@
      */
     public int shadowColor;
 
+    /**
+     * @hide
+     */
+    public  int         mBidiFlags = BIDI_DEFAULT_LTR;
+    
     static final Style[] sStyleArray = {
         Style.FILL, Style.STROKE, Style.FILL_AND_STROKE
     };
@@ -115,6 +120,74 @@
     public static final int HINTING_ON = 0x1;
 
     /**
+     * Bidi flag to set LTR paragraph direction.
+     * 
+     * @hide
+     */
+    public static final int BIDI_LTR = 0x0;
+
+    /**
+     * Bidi flag to set RTL paragraph direction.
+     * 
+     * @hide
+     */
+    public static final int BIDI_RTL = 0x1;
+
+    /**
+     * Bidi flag to detect paragraph direction via heuristics, defaulting to
+     * LTR.
+     * 
+     * @hide
+     */
+    public static final int BIDI_DEFAULT_LTR = 0x2;
+
+    /**
+     * Bidi flag to detect paragraph direction via heuristics, defaulting to
+     * RTL.
+     * 
+     * @hide
+     */
+    public static final int BIDI_DEFAULT_RTL = 0x3;
+
+    /**
+     * Bidi flag to override direction to all LTR (ignore bidi).
+     * 
+     * @hide
+     */
+    public static final int BIDI_FORCE_LTR = 0x4;
+
+    /**
+     * Bidi flag to override direction to all RTL (ignore bidi).
+     * 
+     * @hide
+     */
+    public static final int BIDI_FORCE_RTL = 0x5;
+
+    /**
+     * Maximum Bidi flag value.
+     * @hide
+     */
+    private static final int BIDI_MAX_FLAG_VALUE = BIDI_FORCE_RTL;
+
+    /**
+     * Mask for bidi flags.
+     * @hide
+     */
+    private static final int BIDI_FLAG_MASK = 0x7;
+
+    /**
+     * Flag for getTextRunAdvances indicating left-to-right run direction.
+     * @hide
+     */
+    public static final int DIRECTION_LTR = 0;
+
+    /**
+     * Flag for getTextRunAdvances indicating right-to-left run direction.
+     * @hide
+     */
+    public static final int DIRECTION_RTL = 1;
+
+    /**
      * Option for getTextRunCursor to compute the valid cursor after
      * offset or the limit of the context, whichever is less.
      * @hide
@@ -322,6 +395,7 @@
         shadowRadius = 0;
         shadowColor = 0;
 
+        mBidiFlags = BIDI_DEFAULT_LTR;
         setTextLocale(Locale.getDefault());
     }
     
@@ -361,6 +435,7 @@
         shadowRadius = paint.shadowRadius;
         shadowColor = paint.shadowColor;
 
+        mBidiFlags = paint.mBidiFlags;
         mLocale = paint.mLocale;
     }
 
@@ -377,6 +452,29 @@
     }
 
     /**
+     * Return the bidi flags on the paint.
+     * 
+     * @return the bidi flags on the paint
+     * @hide
+     */
+    public int getBidiFlags() {
+        return mBidiFlags;
+    }
+
+    /**
+     * Set the bidi flags on the paint.
+     * @hide
+     */
+    public void setBidiFlags(int flags) {
+        // only flag value is the 3-bit BIDI control setting
+        flags &= BIDI_FLAG_MASK;
+        if (flags > BIDI_MAX_FLAG_VALUE) {
+            throw new IllegalArgumentException("unknown bidi flag: " + flags);
+        }
+        mBidiFlags = flags;
+    }
+
+    /**
      * Return the paint's flags. Use the Flag enum to test flag values.
      * 
      * @return the paint's flags (see enums ending in _Flag for bit masks)
@@ -1570,19 +1668,76 @@
     }
 
     /**
+     * Return the glyph Ids for the characters in the string.
+     *
+     * @param text   The text to measure
+     * @param start  The index of the first char to to measure
+     * @param end    The end of the text slice to measure
+     * @param contextStart the index of the first character to use for shaping context,
+     * must be <= start
+     * @param contextEnd the index past the last character to use for shaping context,
+     * must be >= end
+     * @param flags the flags to control the advances, either {@link #DIRECTION_LTR}
+     * or {@link #DIRECTION_RTL}
+     * @param glyphs array to receive the glyph Ids of the characters.
+     *               Must be at least a large as the text.
+     * @return       the number of glyphs in the returned array
+     *
+     * @hide
+     *
+     * Used only for BiDi / RTL Tests
+     */
+    public int getTextGlyphs(String text, int start, int end, int contextStart, int contextEnd,
+            int flags, char[] glyphs) {
+        if (text == null) {
+            throw new IllegalArgumentException("text cannot be null");
+        }
+        if (flags != DIRECTION_LTR && flags != DIRECTION_RTL) {
+            throw new IllegalArgumentException("unknown flags value: " + flags);
+        }
+        if ((start | end | contextStart | contextEnd | (end - start)
+                | (start - contextStart) | (contextEnd - end) | (text.length() - end)
+                | (text.length() - contextEnd)) < 0) {
+            throw new IndexOutOfBoundsException();
+        }
+        if (end - start > glyphs.length) {
+            throw new ArrayIndexOutOfBoundsException();
+        }
+        return native_getTextGlyphs(mNativePaint, text, start, end, contextStart, contextEnd,
+                flags, glyphs);
+    }
+
+    /**
      * Convenience overload that takes a char array instead of a
      * String.
      *
-     * @see #getTextRunAdvances(String, int, int, int, int, float[], int)
+     * @see #getTextRunAdvances(String, int, int, int, int, int, float[], int)
      * @hide
      */
     public float getTextRunAdvances(char[] chars, int index, int count,
-            int contextIndex, int contextCount, float[] advances,
+            int contextIndex, int contextCount, int flags, float[] advances,
             int advancesIndex) {
+        return getTextRunAdvances(chars, index, count, contextIndex, contextCount, flags,
+                advances, advancesIndex, 0 /* use Harfbuzz*/);
+    }
+
+    /**
+     * Convenience overload that takes a char array instead of a
+     * String.
+     *
+     * @see #getTextRunAdvances(String, int, int, int, int, int, float[], int, int)
+     * @hide
+     */
+    public float getTextRunAdvances(char[] chars, int index, int count,
+            int contextIndex, int contextCount, int flags, float[] advances,
+            int advancesIndex, int reserved) {
 
         if (chars == null) {
             throw new IllegalArgumentException("text cannot be null");
         }
+        if (flags != DIRECTION_LTR && flags != DIRECTION_RTL) {
+            throw new IllegalArgumentException("unknown flags value: " + flags);
+        }
         if ((index | count | contextIndex | contextCount | advancesIndex
                 | (index - contextIndex) | (contextCount - count)
                 | ((contextIndex + contextCount) - (index + count))
@@ -1597,13 +1752,13 @@
         }
         if (!mHasCompatScaling) {
             return native_getTextRunAdvances(mNativePaint, chars, index, count,
-                    contextIndex, contextCount, advances, advancesIndex);
+                    contextIndex, contextCount, flags, advances, advancesIndex, reserved);
         }
 
         final float oldSize = getTextSize();
         setTextSize(oldSize * mCompatScaling);
         float res = native_getTextRunAdvances(mNativePaint, chars, index, count,
-                contextIndex, contextCount, advances, advancesIndex);
+                contextIndex, contextCount, flags, advances, advancesIndex, reserved);
         setTextSize(oldSize);
 
         if (advances != null) {
@@ -1618,12 +1773,26 @@
      * Convenience overload that takes a CharSequence instead of a
      * String.
      *
-     * @see #getTextRunAdvances(String, int, int, int, int, float[], int)
+     * @see #getTextRunAdvances(String, int, int, int, int, int, float[], int)
      * @hide
      */
     public float getTextRunAdvances(CharSequence text, int start, int end,
-            int contextStart, int contextEnd, float[] advances,
+            int contextStart, int contextEnd, int flags, float[] advances,
             int advancesIndex) {
+        return getTextRunAdvances(text, start, end, contextStart, contextEnd, flags,
+                advances, advancesIndex, 0 /* use Harfbuzz */);
+    }
+
+    /**
+     * Convenience overload that takes a CharSequence instead of a
+     * String.
+     *
+     * @see #getTextRunAdvances(String, int, int, int, int, int, float[], int)
+     * @hide
+     */
+    public float getTextRunAdvances(CharSequence text, int start, int end,
+            int contextStart, int contextEnd, int flags, float[] advances,
+            int advancesIndex, int reserved) {
 
         if (text == null) {
             throw new IllegalArgumentException("text cannot be null");
@@ -1638,16 +1807,16 @@
 
         if (text instanceof String) {
             return getTextRunAdvances((String) text, start, end,
-                    contextStart, contextEnd, advances, advancesIndex);
+                    contextStart, contextEnd, flags, advances, advancesIndex, reserved);
         }
         if (text instanceof SpannedString ||
             text instanceof SpannableString) {
             return getTextRunAdvances(text.toString(), start, end,
-                    contextStart, contextEnd, advances, advancesIndex);
+                    contextStart, contextEnd, flags, advances, advancesIndex, reserved);
         }
         if (text instanceof GraphicsOperations) {
             return ((GraphicsOperations) text).getTextRunAdvances(start, end,
-                    contextStart, contextEnd, advances, advancesIndex, this);
+                    contextStart, contextEnd, flags, advances, advancesIndex, this);
         }
         if (text.length() == 0 || end == start) {
             return 0f;
@@ -1658,7 +1827,7 @@
         char[] buf = TemporaryBuffer.obtain(contextLen);
         TextUtils.getChars(text, contextStart, contextEnd, buf, 0);
         float result = getTextRunAdvances(buf, start - contextStart, len,
-                0, contextLen, advances, advancesIndex);
+                0, contextLen, flags, advances, advancesIndex, reserved);
         TemporaryBuffer.recycle(buf);
         return result;
     }
@@ -1695,6 +1864,8 @@
      * must be <= start
      * @param contextEnd the index past the last character to use for shaping context,
      * must be >= end
+     * @param flags the flags to control the advances, either {@link #DIRECTION_LTR}
+     * or {@link #DIRECTION_RTL}
      * @param advances array to receive the advances, must have room for all advances,
      * can be null if only total advance is needed
      * @param advancesIndex the position in advances at which to put the
@@ -1704,11 +1875,63 @@
      * @hide
      */
     public float getTextRunAdvances(String text, int start, int end, int contextStart,
-            int contextEnd, float[] advances, int advancesIndex) {
+            int contextEnd, int flags, float[] advances, int advancesIndex) {
+        return getTextRunAdvances(text, start, end, contextStart, contextEnd, flags,
+                advances, advancesIndex, 0 /* use Harfbuzz*/);
+    }
+
+    /**
+     * Returns the total advance width for the characters in the run
+     * between start and end, and if advances is not null, the advance
+     * assigned to each of these characters (java chars).
+     *
+     * <p>The trailing surrogate in a valid surrogate pair is assigned
+     * an advance of 0.  Thus the number of returned advances is
+     * always equal to count, not to the number of unicode codepoints
+     * represented by the run.
+     *
+     * <p>In the case of conjuncts or combining marks, the total
+     * advance is assigned to the first logical character, and the
+     * following characters are assigned an advance of 0.
+     *
+     * <p>This generates the sum of the advances of glyphs for
+     * characters in a reordered cluster as the width of the first
+     * logical character in the cluster, and 0 for the widths of all
+     * other characters in the cluster.  In effect, such clusters are
+     * treated like conjuncts.
+     *
+     * <p>The shaping bounds limit the amount of context available
+     * outside start and end that can be used for shaping analysis.
+     * These bounds typically reflect changes in bidi level or font
+     * metrics across which shaping does not occur.
+     *
+     * @param text the text to measure. Cannot be null.
+     * @param start the index of the first character to measure
+     * @param end the index past the last character to measure
+     * @param contextStart the index of the first character to use for shaping context,
+     * must be <= start
+     * @param contextEnd the index past the last character to use for shaping context,
+     * must be >= end
+     * @param flags the flags to control the advances, either {@link #DIRECTION_LTR}
+     * or {@link #DIRECTION_RTL}
+     * @param advances array to receive the advances, must have room for all advances,
+     * can be null if only total advance is needed
+     * @param advancesIndex the position in advances at which to put the
+     * advance corresponding to the character at start
+     * @param reserved int reserved value
+     * @return the total advance
+     *
+     * @hide
+     */
+    public float getTextRunAdvances(String text, int start, int end, int contextStart,
+            int contextEnd, int flags, float[] advances, int advancesIndex, int reserved) {
 
         if (text == null) {
             throw new IllegalArgumentException("text cannot be null");
         }
+        if (flags != DIRECTION_LTR && flags != DIRECTION_RTL) {
+            throw new IllegalArgumentException("unknown flags value: " + flags);
+        }
         if ((start | end | contextStart | contextEnd | advancesIndex | (end - start)
                 | (start - contextStart) | (contextEnd - end)
                 | (text.length() - contextEnd)
@@ -1723,13 +1946,13 @@
 
         if (!mHasCompatScaling) {
             return native_getTextRunAdvances(mNativePaint, text, start, end,
-                    contextStart, contextEnd, advances, advancesIndex);
+                    contextStart, contextEnd, flags, advances, advancesIndex, reserved);
         }
 
         final float oldSize = getTextSize();
         setTextSize(oldSize * mCompatScaling);
         float totalAdvance = native_getTextRunAdvances(mNativePaint, text, start, end,
-                contextStart, contextEnd, advances, advancesIndex);
+                contextStart, contextEnd, flags, advances, advancesIndex, reserved);
         setTextSize(oldSize);
 
         if (advances != null) {
@@ -1758,6 +1981,7 @@
      * @param text the text
      * @param contextStart the start of the context
      * @param contextLength the length of the context
+     * @param flags either {@link #DIRECTION_RTL} or {@link #DIRECTION_LTR}
      * @param offset the cursor position to move from
      * @param cursorOpt how to move the cursor, one of {@link #CURSOR_AFTER},
      * {@link #CURSOR_AT_OR_AFTER}, {@link #CURSOR_BEFORE},
@@ -1766,7 +1990,7 @@
      * @hide
      */
     public int getTextRunCursor(char[] text, int contextStart, int contextLength,
-            int offset, int cursorOpt) {
+            int flags, int offset, int cursorOpt) {
         int contextEnd = contextStart + contextLength;
         if (((contextStart | contextEnd | offset | (contextEnd - contextStart)
                 | (offset - contextStart) | (contextEnd - offset)
@@ -1776,7 +2000,7 @@
         }
 
         return native_getTextRunCursor(mNativePaint, text,
-                contextStart, contextLength, offset, cursorOpt);
+                contextStart, contextLength, flags, offset, cursorOpt);
     }
 
     /**
@@ -1797,6 +2021,7 @@
      * @param text the text
      * @param contextStart the start of the context
      * @param contextEnd the end of the context
+     * @param flags either {@link #DIRECTION_RTL} or {@link #DIRECTION_LTR}
      * @param offset the cursor position to move from
      * @param cursorOpt how to move the cursor, one of {@link #CURSOR_AFTER},
      * {@link #CURSOR_AT_OR_AFTER}, {@link #CURSOR_BEFORE},
@@ -1805,22 +2030,22 @@
      * @hide
      */
     public int getTextRunCursor(CharSequence text, int contextStart,
-           int contextEnd, int offset, int cursorOpt) {
+           int contextEnd, int flags, int offset, int cursorOpt) {
 
         if (text instanceof String || text instanceof SpannedString ||
                 text instanceof SpannableString) {
             return getTextRunCursor(text.toString(), contextStart, contextEnd,
-                    offset, cursorOpt);
+                    flags, offset, cursorOpt);
         }
         if (text instanceof GraphicsOperations) {
             return ((GraphicsOperations) text).getTextRunCursor(
-                    contextStart, contextEnd, offset, cursorOpt, this);
+                    contextStart, contextEnd, flags, offset, cursorOpt, this);
         }
 
         int contextLen = contextEnd - contextStart;
         char[] buf = TemporaryBuffer.obtain(contextLen);
         TextUtils.getChars(text, contextStart, contextEnd, buf, 0);
-        int result = getTextRunCursor(buf, 0, contextLen, offset - contextStart, cursorOpt);
+        int result = getTextRunCursor(buf, 0, contextLen, flags, offset - contextStart, cursorOpt);
         TemporaryBuffer.recycle(buf);
         return result;
     }
@@ -1843,6 +2068,7 @@
      * @param text the text
      * @param contextStart the start of the context
      * @param contextEnd the end of the context
+     * @param flags either {@link #DIRECTION_RTL} or {@link #DIRECTION_LTR}
      * @param offset the cursor position to move from
      * @param cursorOpt how to move the cursor, one of {@link #CURSOR_AFTER},
      * {@link #CURSOR_AT_OR_AFTER}, {@link #CURSOR_BEFORE},
@@ -1860,7 +2086,7 @@
         }
 
         return native_getTextRunCursor(mNativePaint, text,
-                contextStart, contextEnd, offset, cursorOpt);
+                contextStart, contextEnd, flags, offset, cursorOpt);
     }
 
     /**
@@ -1881,7 +2107,7 @@
         if ((index | count) < 0 || index + count > text.length) {
             throw new ArrayIndexOutOfBoundsException();
         }
-        native_getTextPath(mNativePaint, text, index, count, x, y,
+        native_getTextPath(mNativePaint, mBidiFlags, text, index, count, x, y, 
                 path.ni());
     }
 
@@ -1903,7 +2129,7 @@
         if ((start | end | (end - start) | (text.length() - end)) < 0) {
             throw new IndexOutOfBoundsException();
         }
-        native_getTextPath(mNativePaint, text, start, end, x, y,
+        native_getTextPath(mNativePaint, mBidiFlags, text, start, end, x, y, 
                 path.ni());
     }
     
@@ -1995,22 +2221,26 @@
     private static native int native_getTextWidths(int native_object,
                             String text, int start, int end, float[] widths);
 
+    private static native int native_getTextGlyphs(int native_object,
+            String text, int start, int end, int contextStart, int contextEnd,
+            int flags, char[] glyphs);
+
     private static native float native_getTextRunAdvances(int native_object,
             char[] text, int index, int count, int contextIndex, int contextCount,
-            float[] advances, int advancesIndex);
+            int flags, float[] advances, int advancesIndex, int reserved);
     private static native float native_getTextRunAdvances(int native_object,
             String text, int start, int end, int contextStart, int contextEnd,
-            float[] advances, int advancesIndex);
+            int flags, float[] advances, int advancesIndex, int reserved);
 
     private native int native_getTextRunCursor(int native_object, char[] text,
-            int contextStart, int contextLength, int offset, int cursorOpt);
+            int contextStart, int contextLength, int flags, int offset, int cursorOpt);
     private native int native_getTextRunCursor(int native_object, String text,
-            int contextStart, int contextEnd, int offset, int cursorOpt);
+            int contextStart, int contextEnd, int flags, int offset, int cursorOpt);
 
-    private static native void native_getTextPath(int native_object, char[] text,
-            int index, int count, float x, float y, int path);
-    private static native void native_getTextPath(int native_object, String text,
-            int start, int end, float x, float y, int path);
+    private static native void native_getTextPath(int native_object, int bidiFlags,
+                char[] text, int index, int count, float x, float y, int path);
+    private static native void native_getTextPath(int native_object, int bidiFlags,
+                String text, int start, int end, float x, float y, int path);
     private static native void nativeGetStringBounds(int nativePaint,
                                 String text, int start, int end, Rect bounds);
     private static native void nativeGetCharArrayBounds(int nativePaint,
diff --git a/tests/BiDiTests/res/layout/canvas.xml b/tests/BiDiTests/res/layout/canvas.xml
new file mode 100644
index 0000000..0319a83
--- /dev/null
+++ b/tests/BiDiTests/res/layout/canvas.xml
@@ -0,0 +1,40 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2011 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+
+<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
+        android:id="@+id/canvas"
+        android:layout_width="fill_parent"
+        android:layout_height="fill_parent">
+
+    <LinearLayout android:orientation="vertical"
+                  android:layout_width="match_parent"
+                  android:layout_height="match_parent">
+
+        <SeekBar android:id="@+id/seekbar"
+                 android:layout_height="wrap_content"
+                 android:layout_width="match_parent"
+                />
+
+        <view class="com.android.bidi.BiDiTestView"
+              android:id="@+id/testview"
+              android:layout_width="match_parent"
+              android:layout_height="wrap_content"
+              android:background="#FF0000"
+                />
+
+    </LinearLayout>
+
+</FrameLayout>
\ No newline at end of file
diff --git a/tests/BiDiTests/src/com/android/bidi/BiDiTestActivity.java b/tests/BiDiTests/src/com/android/bidi/BiDiTestActivity.java
index b88a885..209597e 100644
--- a/tests/BiDiTests/src/com/android/bidi/BiDiTestActivity.java
+++ b/tests/BiDiTests/src/com/android/bidi/BiDiTestActivity.java
@@ -101,6 +101,7 @@
 
         addItem(result, "Basic", BiDiTestBasic.class, R.id.basic);
 
+        addItem(result, "Canvas", BiDiTestCanvas.class, R.id.canvas);
         addItem(result, "Canvas2", BiDiTestCanvas2.class, R.id.canvas2);
 
         addItem(result, "TextView LTR", BiDiTestTextViewLtr.class, R.id.textview_ltr);
diff --git a/tests/BiDiTests/src/com/android/bidi/BiDiTestCanvas.java b/tests/BiDiTests/src/com/android/bidi/BiDiTestCanvas.java
new file mode 100644
index 0000000..33ed731
--- /dev/null
+++ b/tests/BiDiTests/src/com/android/bidi/BiDiTestCanvas.java
@@ -0,0 +1,67 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.bidi;
+
+import android.app.Fragment;
+import android.os.Bundle;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.SeekBar;
+
+import static com.android.bidi.BiDiTestConstants.FONT_MAX_SIZE;
+import static com.android.bidi.BiDiTestConstants.FONT_MIN_SIZE;
+
+public class BiDiTestCanvas extends Fragment {
+
+    static final int INIT_TEXT_SIZE = (FONT_MAX_SIZE - FONT_MIN_SIZE) / 2;
+
+    private BiDiTestView testView;
+    private SeekBar textSizeSeekBar;
+    private View currentView;
+
+    @Override
+    public View onCreateView(LayoutInflater inflater, ViewGroup container,
+            Bundle savedInstanceState) {
+        currentView = inflater.inflate(R.layout.canvas, container, false);
+        return currentView;
+    }
+
+    @Override
+    public void onViewCreated(View view, Bundle savedInstanceState) {
+        super.onViewCreated(view, savedInstanceState);
+
+        testView = (BiDiTestView) currentView.findViewById(R.id.testview);
+        testView.setCurrentTextSize(INIT_TEXT_SIZE);
+
+        textSizeSeekBar = (SeekBar) currentView.findViewById(R.id.seekbar);
+        textSizeSeekBar.setProgress(INIT_TEXT_SIZE);
+        textSizeSeekBar.setMax(FONT_MAX_SIZE - FONT_MIN_SIZE);
+
+        textSizeSeekBar.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() {
+            public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {
+                testView.setCurrentTextSize(FONT_MIN_SIZE + progress);
+            }
+
+            public void onStartTrackingTouch(SeekBar seekBar) {
+            }
+
+            public void onStopTrackingTouch(SeekBar seekBar) {
+            }
+        });
+    }
+}
diff --git a/tests/BiDiTests/src/com/android/bidi/BiDiTestView.java b/tests/BiDiTests/src/com/android/bidi/BiDiTestView.java
new file mode 100644
index 0000000..0b1974a
--- /dev/null
+++ b/tests/BiDiTests/src/com/android/bidi/BiDiTestView.java
@@ -0,0 +1,212 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.bidi;
+
+import android.content.Context;
+import android.graphics.Canvas;
+import android.graphics.Color;
+import android.graphics.Paint;
+import android.graphics.Rect;
+import android.text.TextPaint;
+import android.util.AttributeSet;
+import android.util.Log;
+import android.view.View;
+
+public class BiDiTestView extends View {
+
+    private static final String TAG = "BiDiTestView";
+
+    private static final int BORDER_PADDING = 4;
+    private static final int TEXT_PADDING = 16;
+    private static final int TEXT_SIZE = 16;
+    private static final int ORIGIN = 80;
+
+    private static final float DEFAULT_ITALIC_SKEW_X = -0.25f;
+
+    private Rect rect = new Rect();
+
+    private String NORMAL_TEXT;
+    private String NORMAL_LONG_TEXT;
+    private String NORMAL_LONG_TEXT_2;
+    private String NORMAL_LONG_TEXT_3;
+    private String ITALIC_TEXT;
+    private String BOLD_TEXT;
+    private String BOLD_ITALIC_TEXT;
+    private String ARABIC_TEXT;
+    private String CHINESE_TEXT;
+    private String MIXED_TEXT_1;
+    private String HEBREW_TEXT;
+    private String RTL_TEXT;
+    private String THAI_TEXT;
+
+    private int currentTextSize;
+
+    public BiDiTestView(Context context) {
+        super(context);
+        init(context);
+    }
+
+    public BiDiTestView(Context context, AttributeSet attrs) {
+        super(context, attrs);
+        init(context);
+    }
+
+    public BiDiTestView(Context context, AttributeSet attrs, int defStyle) {
+        super(context, attrs, defStyle);
+        init(context);
+    }
+
+    private void init(Context context) {
+        NORMAL_TEXT = context.getString(R.string.normal_text);
+        NORMAL_LONG_TEXT = context.getString(R.string.normal_long_text);
+        NORMAL_LONG_TEXT_2 = context.getString(R.string.normal_long_text_2);
+        NORMAL_LONG_TEXT_3 = context.getString(R.string.normal_long_text_3);
+        ITALIC_TEXT = context.getString(R.string.italic_text);
+        BOLD_TEXT = context.getString(R.string.bold_text);
+        BOLD_ITALIC_TEXT = context.getString(R.string.bold_italic_text);
+        ARABIC_TEXT = context.getString(R.string.arabic_text);
+        CHINESE_TEXT = context.getString(R.string.chinese_text);
+        MIXED_TEXT_1 = context.getString(R.string.mixed_text_1);
+        HEBREW_TEXT = context.getString(R.string.hebrew_text);
+        RTL_TEXT = context.getString(R.string.rtl);
+        THAI_TEXT = context.getString(R.string.pointer_location);
+    }
+
+    public void setCurrentTextSize(int size) {
+        currentTextSize = size;
+        invalidate();
+    }
+
+    @Override
+    public void onDraw(Canvas canvas) {
+        drawInsideRect(canvas, new Paint(), Color.BLACK);
+
+        int deltaX = 0;
+
+        deltaX  = testString(canvas, NORMAL_TEXT, ORIGIN, ORIGIN,
+                false, false,  Paint.DIRECTION_LTR, currentTextSize);
+
+        deltaX += testString(canvas, ITALIC_TEXT, ORIGIN + deltaX, ORIGIN,
+                true, false,  Paint.DIRECTION_LTR, currentTextSize);
+
+        deltaX += testString(canvas, BOLD_TEXT, ORIGIN + deltaX, ORIGIN,
+                false, true,  Paint.DIRECTION_LTR, currentTextSize);
+
+        deltaX += testString(canvas, BOLD_ITALIC_TEXT, ORIGIN + deltaX, ORIGIN,
+                true, true,  Paint.DIRECTION_LTR, currentTextSize);
+
+        // Test with a long string
+        deltaX = testString(canvas, NORMAL_LONG_TEXT, ORIGIN, ORIGIN + 2 * currentTextSize,
+                false, false,  Paint.DIRECTION_LTR, currentTextSize);
+
+        // Test with a long string
+        deltaX = testString(canvas, NORMAL_LONG_TEXT_2, ORIGIN, ORIGIN + 4 * currentTextSize,
+                false, false,  Paint.DIRECTION_LTR, currentTextSize);
+
+        // Test with a long string
+        deltaX = testString(canvas, NORMAL_LONG_TEXT_3, ORIGIN, ORIGIN + 6 * currentTextSize,
+                false, false,  Paint.DIRECTION_LTR, currentTextSize);
+
+        // Test Arabic ligature
+        deltaX = testString(canvas, ARABIC_TEXT, ORIGIN, ORIGIN + 8 * currentTextSize,
+                false, false,  Paint.DIRECTION_RTL, currentTextSize);
+
+        // Test Chinese
+        deltaX = testString(canvas, CHINESE_TEXT, ORIGIN, ORIGIN + 10 * currentTextSize,
+                false, false,  Paint.DIRECTION_LTR, currentTextSize);
+
+        // Test Mixed (English and Arabic)
+        deltaX = testString(canvas, MIXED_TEXT_1, ORIGIN, ORIGIN + 12 * currentTextSize,
+                false, false,  Paint.DIRECTION_LTR, currentTextSize);
+
+        // Test Hebrew
+        deltaX = testString(canvas, RTL_TEXT, ORIGIN, ORIGIN + 14 * currentTextSize,
+                false, false,  Paint.DIRECTION_RTL, currentTextSize);
+
+        // Test Thai
+        deltaX = testString(canvas, THAI_TEXT, ORIGIN, ORIGIN + 16 * currentTextSize,
+                false, false,  Paint.DIRECTION_LTR, currentTextSize);
+    }
+
+    private int testString(Canvas canvas, String text, int x, int y,
+            boolean isItalic, boolean isBold, int dir, int textSize) {
+
+        TextPaint paint = new TextPaint();
+        paint.setAntiAlias(true);
+
+        // Set paint properties
+        boolean oldFakeBold = paint.isFakeBoldText();
+        paint.setFakeBoldText(isBold);
+
+        float oldTextSkewX = paint.getTextSkewX();
+        if (isItalic) {
+            paint.setTextSkewX(DEFAULT_ITALIC_SKEW_X);
+        }
+
+        paint.setTextSize(textSize);
+        paint.setColor(Color.WHITE);
+        canvas.drawText(text, x, y, paint);
+
+        int length = text.length();
+        float[] advances = new float[length];
+        float textWidthHB = paint.getTextRunAdvances(text, 0, length, 0, length, dir, advances, 0);
+        setPaintDir(paint, dir);
+        float textWidthICU = paint.getTextRunAdvances(text, 0, length, 0, length, dir, advances, 0,
+                1 /* use ICU */);
+
+        logAdvances(text, textWidthHB, textWidthICU, advances);
+        drawMetricsAroundText(canvas, x, y, textWidthHB, textWidthICU, textSize, Color.RED, Color.GREEN);
+
+        // Restore old paint properties
+        paint.setFakeBoldText(oldFakeBold);
+        paint.setTextSkewX(oldTextSkewX);
+
+        return (int) Math.ceil(textWidthHB) + TEXT_PADDING;
+    }
+
+    private void setPaintDir(Paint paint, int dir) {
+        Log.v(TAG, "Setting Paint dir=" + dir);
+        paint.setBidiFlags(dir);
+    }
+
+    private void drawInsideRect(Canvas canvas, Paint paint, int color) {
+        paint.setColor(color);
+        int width = getWidth();
+        int height = getHeight();
+        rect.set(BORDER_PADDING, BORDER_PADDING, width - BORDER_PADDING, height - BORDER_PADDING);
+        canvas.drawRect(rect, paint);
+    }
+
+    private void drawMetricsAroundText(Canvas canvas, int x, int y, float textWidthHB,
+            float textWidthICU, int textSize, int color, int colorICU) {
+        Paint paint = new Paint();
+        paint.setColor(color);
+        canvas.drawLine(x, y - textSize, x, y + 8, paint);
+        canvas.drawLine(x, y + 8, x + textWidthHB, y + 8, paint);
+        canvas.drawLine(x + textWidthHB, y - textSize, x + textWidthHB, y + 8, paint);
+        paint.setColor(colorICU);
+        canvas.drawLine(x + textWidthICU, y - textSize, x + textWidthICU, y + 8, paint);
+    }
+
+    private void logAdvances(String text, float textWidth, float textWidthICU, float[] advances) {
+        Log.v(TAG, "Advances for text: " + text + " total= " + textWidth + " - totalICU= " + textWidthICU);
+//        int length = advances.length;
+//        for(int n=0; n<length; n++){
+//            Log.v(TAG, "adv[" + n + "]=" + advances[n]);
+//        }
+    }
+}