From e8e62a4a032a80409114a37908b5f18ab0080848 Mon Sep 17 00:00:00 2001 From: Romain Guy Date: Fri, 23 Jul 2010 18:55:21 -0700 Subject: [PATCH] Add text alignment support to drawText(). This change also integrates better support for RTL text. Change-Id: I6da8f5cf5dc28ca7cf1b22e27b0d853c919e8481 --- core/jni/android/graphics/TextLayout.cpp | 51 +++++++++++-------- core/jni/android/graphics/TextLayout.h | 3 ++ core/jni/android_view_GLES20Canvas.cpp | 17 +++++-- libs/hwui/OpenGLRenderer.cpp | 23 ++++++++- libs/hwui/OpenGLRenderer.h | 2 +- .../android/test/hwui/TextActivity.java | 8 ++- 6 files changed, 75 insertions(+), 29 deletions(-) diff --git a/core/jni/android/graphics/TextLayout.cpp b/core/jni/android/graphics/TextLayout.cpp index e2536eea36afd..3de2c9509ab78 100644 --- a/core/jni/android/graphics/TextLayout.cpp +++ b/core/jni/android/graphics/TextLayout.cpp @@ -150,26 +150,22 @@ jint TextLayout::layoutLine(const jchar* text, jint len, jint flags, int &dir, j 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 @@ void TextLayout::handleText(SkPaint *paint, const jchar* text, jsize len, 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 @@ void TextLayout::handleText(SkPaint *paint, const jchar* text, jsize len, } } - 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 c0d9f758a0bf5..dc7208af0a820 100644 --- a/core/jni/android/graphics/TextLayout.h +++ b/core/jni/android/graphics/TextLayout.h @@ -63,6 +63,9 @@ public: 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 2f1dcb650ff54..d2e7faf6f6061 100644 --- a/core/jni/android_view_GLES20Canvas.cpp +++ b/core/jni/android_view_GLES20Canvas.cpp @@ -33,6 +33,8 @@ #include #include +#include "TextLayout.h" + namespace android { using namespace uirenderer; @@ -251,12 +253,20 @@ static void android_view_GLES20Canvas_setupLinearShader(JNIEnv* env, jobject can // 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 @@ static void android_view_GLES20Canvas_drawText(JNIEnv* env, jobject canvas, 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 c6a2e33cff78c..d30d7180028e0 100644 --- a/libs/hwui/OpenGLRenderer.cpp +++ b/libs/hwui/OpenGLRenderer.cpp @@ -525,7 +525,26 @@ void OpenGLRenderer::drawRect(float left, float top, float right, float bottom, 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 @@ void OpenGLRenderer::drawText(const char* text, int count, float x, float y, SkP 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 43e568f91a626..248c9c3c1b6d8 100644 --- a/libs/hwui/OpenGLRenderer.h +++ b/libs/hwui/OpenGLRenderer.h @@ -110,7 +110,7 @@ public: 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 4a94630fc19c6..3b5cf43e1bb41 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 @@ public class TextActivity extends Activity { 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);