Add text alignment support to drawText().

This change also integrates better support for RTL text.

Change-Id: I6da8f5cf5dc28ca7cf1b22e27b0d853c919e8481
diff --git a/core/jni/android/graphics/TextLayout.cpp b/core/jni/android/graphics/TextLayout.cpp
index e2536ee..3de2c95 100644
--- a/core/jni/android/graphics/TextLayout.cpp
+++ b/core/jni/android/graphics/TextLayout.cpp
@@ -150,26 +150,22 @@
     return result;
 }
 
-// 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,
-                            jint bidiFlags, jfloat x, jfloat y,SkCanvas *canvas, SkPath *path) {
-
+bool TextLayout::prepareText(SkPaint *paint, const jchar* text, jsize len, jint bidiFlags,
+        const jchar** outText, int32_t* outBytes) {
     const jchar *workText = text;
     jchar *buffer = NULL;
     int dir = kDirection_LTR;
     if (needsLayout(text, len, bidiFlags)) {
         buffer =(jchar *) malloc(len * sizeof(jchar));
         if (!buffer) {
-            return;
+            return false;
         }
         UErrorCode status = U_ZERO_ERROR;
         len = layoutLine(text, len, bidiFlags, dir, buffer, status); // might change len, dir
         if (!U_SUCCESS(status)) {
             LOG(LOG_WARN, "LAYOUT", "drawText error %d\n", status);
             free(buffer);
-            return; // can't render
+            return false; // can't render
         }
 
         workText = buffer; // use the shaped text
@@ -180,10 +176,10 @@
 
     SkPaint::Align horiz = paint->getTextAlign();
     switch (horiz) {
-    case SkPaint::kLeft_Align: trimLeft = dir & kDirection_Mask; break;
-    case SkPaint::kCenter_Align: trimLeft = trimRight = true; break;
-    case SkPaint::kRight_Align: trimRight = !(dir & kDirection_Mask);
-    default: break;
+        case SkPaint::kLeft_Align: trimLeft = dir & kDirection_Mask; break;
+        case SkPaint::kCenter_Align: trimLeft = trimRight = true; break;
+        case SkPaint::kRight_Align: trimRight = !(dir & kDirection_Mask);
+        default: break;
     }
     const jchar* workLimit = workText + len;
 
@@ -198,16 +194,29 @@
         }
     }
 
-    int32_t workBytes = (workLimit - workText) << 1;
-    SkScalar x_ = SkFloatToScalar(x);
-    SkScalar y_ = SkFloatToScalar(y);
-    if (canvas) {
-        canvas->drawText(workText, workBytes, x_, y_, *paint);
-    } else {
-        paint->getTextPath(workText, workBytes, x_, y_, path);
-    }
-
+    *outBytes = (workLimit - workText) << 1;
+    *outText = workText;
+    
     free(buffer);
+    return true;
+}
+
+// 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,
+                            jint bidiFlags, jfloat x, jfloat y,SkCanvas *canvas, SkPath *path) {
+    const jchar *workText;
+    int32_t workBytes;
+    if (prepareText(paint, text, len, bidiFlags, &workText, &workBytes)) {
+        SkScalar x_ = SkFloatToScalar(x);
+        SkScalar y_ = SkFloatToScalar(y);
+        if (canvas) {
+            canvas->drawText(workText, workBytes, x_, y_, *paint);
+        } else {
+            paint->getTextPath(workText, workBytes, x_, y_, path);
+        }
+    }
 }
 
 void TextLayout::drawTextRun(SkPaint* paint, const jchar* chars,
diff --git a/core/jni/android/graphics/TextLayout.h b/core/jni/android/graphics/TextLayout.h
index c0d9f75..dc7208a 100644
--- a/core/jni/android/graphics/TextLayout.h
+++ b/core/jni/android/graphics/TextLayout.h
@@ -63,6 +63,9 @@
     static void drawTextOnPath(SkPaint* paint, const jchar* text, jsize len,
                                int bidiFlags, jfloat hOffset, jfloat vOffset,
                                SkPath* path, SkCanvas* canvas);
+                               
+   static bool prepareText(SkPaint *paint, const jchar* text, jsize len, jint bidiFlags,
+        const jchar** outText, int32_t* outBytes);
 
 private:
     static bool needsLayout(const jchar* text, jint len, jint bidiFlags);
diff --git a/core/jni/android_view_GLES20Canvas.cpp b/core/jni/android_view_GLES20Canvas.cpp
index 2f1dcb6..d2e7faf 100644
--- a/core/jni/android_view_GLES20Canvas.cpp
+++ b/core/jni/android_view_GLES20Canvas.cpp
@@ -33,6 +33,8 @@
 #include <Rect.h>
 #include <ui/Rect.h>
 
+#include "TextLayout.h"
+
 namespace android {
 
 using namespace uirenderer;
@@ -251,12 +253,20 @@
 // Text
 // ----------------------------------------------------------------------------
 
+static void renderText(OpenGLRenderer* renderer, const jchar* text, int count,
+        jfloat x, jfloat y, int flags, SkPaint* paint) {
+    const jchar *workText;
+    int32_t workBytes;
+    if (TextLayout::prepareText(paint, text, count, flags, &workText, &workBytes)) {
+        renderer->drawText((const char*) workText, workBytes, count, x, y, paint);
+    }
+}
+
 static void android_view_GLES20Canvas_drawTextArray(JNIEnv* env, jobject canvas,
         OpenGLRenderer* renderer, jcharArray text, int index, int count,
         jfloat x, jfloat y, int flags, SkPaint* paint) {
     jchar* textArray = env->GetCharArrayElements(text, NULL);
-    // TODO: Prepare the text for RTL
-    renderer->drawText((const char*) (textArray + index), count, x, y, paint);
+    renderText(renderer, textArray + index, count, x, y, flags, paint);
     env->ReleaseCharArrayElements(text, textArray, JNI_ABORT);
 }
 
@@ -264,8 +274,7 @@
         OpenGLRenderer* renderer, jstring text, int start, int end,
         jfloat x, jfloat y, int flags, SkPaint* paint) {
     const jchar* textArray = env->GetStringChars(text, NULL);
-    // TODO: Prepare the text for RTL
-    renderer->drawText((const char*) (textArray + start), end - start, x, y, paint);
+    renderText(renderer, textArray + start, end - start, x, y, flags, paint);
     env->ReleaseStringChars(text, textArray);
 }
 
diff --git a/libs/hwui/OpenGLRenderer.cpp b/libs/hwui/OpenGLRenderer.cpp
index c6a2e33..d30d718 100644
--- a/libs/hwui/OpenGLRenderer.cpp
+++ b/libs/hwui/OpenGLRenderer.cpp
@@ -525,7 +525,26 @@
     drawColorRect(left, top, right, bottom, color, mode);
 }
 
-void OpenGLRenderer::drawText(const char* text, int count, float x, float y, SkPaint* paint) {
+void OpenGLRenderer::drawText(const char* text, int bytesCount, int count,
+        float x, float y, SkPaint* paint) {
+    if (text == NULL || count == 0 || (paint->getAlpha() == 0 && paint->getXfermode() == NULL)) {
+        return;
+    }
+
+    float length;
+    switch (paint->getTextAlign()) {
+        case SkPaint::kCenter_Align:
+            length = paint->measureText(text, bytesCount);
+            x -= length / 2.0f;
+            break;
+        case SkPaint::kRight_Align:
+            length = paint->measureText(text, bytesCount);
+            x -= length;
+            break;
+        default:
+            break;
+    }
+
     int alpha;
     SkXfermode::Mode mode;
     getAlphaAndMode(paint, &alpha, &mode);
@@ -551,7 +570,7 @@
     const Rect& clip = mSnapshot->getLocalClip();
 
     mFontRenderer.setFont(SkTypeface::UniqueID(paint->getTypeface()), paint->getTextSize());
-    mFontRenderer.renderText(paint, &clip, text, 0, count, count, x, y);
+    mFontRenderer.renderText(paint, &clip, text, 0, bytesCount, count, x, y);
 
     glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
 }
diff --git a/libs/hwui/OpenGLRenderer.h b/libs/hwui/OpenGLRenderer.h
index 43e568f..248c9c3 100644
--- a/libs/hwui/OpenGLRenderer.h
+++ b/libs/hwui/OpenGLRenderer.h
@@ -110,7 +110,7 @@
             float* positions, int count, SkShader::TileMode tileMode,
             SkMatrix* matrix, bool hasAlpha);
 
-    void drawText(const char* text, int count, float x, float y, SkPaint* paint);
+    void drawText(const char* text, int bytesCount, int count, float x, float y, SkPaint* paint);
 
 private:
     /**
diff --git a/tests/HwAccelerationTest/src/com/google/android/test/hwui/TextActivity.java b/tests/HwAccelerationTest/src/com/google/android/test/hwui/TextActivity.java
index 4a94630..3b5cf43 100644
--- a/tests/HwAccelerationTest/src/com/google/android/test/hwui/TextActivity.java
+++ b/tests/HwAccelerationTest/src/com/google/android/test/hwui/TextActivity.java
@@ -51,7 +51,13 @@
         protected void onDraw(Canvas canvas) {
             super.onDraw(canvas);
             canvas.drawRGB(255, 255, 255);
-            
+
+            canvas.drawText("Hello OpenGL renderer!", 100, 20, mMediumPaint);
+            mMediumPaint.setTextAlign(Paint.Align.CENTER);
+            canvas.drawText("Hello OpenGL renderer!", 100, 40, mMediumPaint);
+            mMediumPaint.setTextAlign(Paint.Align.RIGHT);
+            canvas.drawText("Hello OpenGL renderer!", 100, 60, mMediumPaint);
+            mMediumPaint.setTextAlign(Paint.Align.LEFT);
             canvas.drawText("Hello OpenGL renderer!", 100, 100, mMediumPaint);
             canvas.drawText("Hello OpenGL renderer!", 100, 200, mLargePaint);