diff options
author | Doug Felt <dougfelt@google.com> | 2010-07-01 16:20:43 -0700 |
---|---|---|
committer | Doug Felt <dougfelt@google.com> | 2010-07-12 13:50:08 -0700 |
commit | f7cb1f75fdaedf996cab7c4690b080adc7bc5b97 (patch) | |
tree | 6f2fb5f1d5bdea5c385e1902a1f981b34323b326 /core/jni/android/graphics/Canvas.cpp | |
parent | c801768e4d29667a2608695449ebc2833ba0f200 (diff) | |
download | frameworks_base-f7cb1f75fdaedf996cab7c4690b080adc7bc5b97.zip frameworks_base-f7cb1f75fdaedf996cab7c4690b080adc7bc5b97.tar.gz frameworks_base-f7cb1f75fdaedf996cab7c4690b080adc7bc5b97.tar.bz2 |
Support bidi/shaping for getTextPath
Move layout-related code into separate class since it's needed by both
canvas and paint.
Change-Id: Iba89a1d94d7cca650255ffa3cbc952b988a51b54
Diffstat (limited to 'core/jni/android/graphics/Canvas.cpp')
-rw-r--r-- | core/jni/android/graphics/Canvas.cpp | 260 |
1 files changed, 12 insertions, 248 deletions
diff --git a/core/jni/android/graphics/Canvas.cpp b/core/jni/android/graphics/Canvas.cpp index 2e49c64..558f5ff 100644 --- a/core/jni/android/graphics/Canvas.cpp +++ b/core/jni/android/graphics/Canvas.cpp @@ -30,6 +30,8 @@ #include "SkBoundaryPatch.h" #include "SkMeshUtils.h" +#include "TextLayout.h" + #include "unicode/ubidi.h" #include "unicode/ushape.h" @@ -57,24 +59,6 @@ namespace android { class SkCanvasGlue { public: - enum { - kDirection_LTR = 0, - kDirection_RTL = 1 - }; - - enum { - kDirection_Mask = 0x1 - }; - - enum { - kBidi_LTR = 0, - kBidi_RTL = 1, - kBidi_Default_LTR = 2, - kBidi_Default_RTL = 3, - kBidi_Force_LTR = 4, - kBidi_Force_RTL = 5 - }; - static void finalizer(JNIEnv* env, jobject clazz, SkCanvas* canvas) { canvas->unref(); } @@ -767,192 +751,12 @@ public: indices, indexCount, *paint); } - /** - * Character-based Arabic shaping. - * - * We'll use harfbuzz and glyph-based shaping instead once we're set up for it. - * - * @context the text context - * @start the start of the text to render - * @count the length of the text to render, start + count must be <= contextCount - * @contextCount the length of the context - * @shaped where to put the shaped text, must have capacity for count uchars - * @return the length of the shaped text, or -1 if error - */ - static int shapeRtlText(const jchar* context, jsize start, jsize count, jsize contextCount, - jchar* shaped, UErrorCode &status) { - jchar buffer[contextCount]; - - // Use fixed length since we need to keep start and count valid - u_shapeArabic(context, 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); - - if (U_SUCCESS(status)) { - // trim out 0xffff following ligatures, if any - int end = 0; - for (int i = start, e = start + count; i < e; ++i) { - if (buffer[i] != 0xffff) { - buffer[end++] = buffer[i]; - } - } - count = end; - // LOG(LOG_INFO, "CSRTL", "start %d count %d ccount %d\n", start, count, contextCount); - ubidi_writeReverse(buffer, count, shaped, count, UBIDI_DO_MIRRORING | UBIDI_OUTPUT_REVERSE - | UBIDI_KEEP_BASE_COMBINING, &status); - if (U_SUCCESS(status)) { - return count; - } - } - - return -1; - } - - /** - * Basic character-based layout supporting rtl and arabic shaping. - * Runs bidi on the text and generates a reordered, shaped line in buffer, returning - * the length. - * @text the text - * @len the length of the text in uchars - * @dir receives the resolved paragraph direction - * @buffer the buffer to receive the reordered, shaped line. Must have capacity of - * at least len jchars. - * @flags line bidi flags - * @return the length of the reordered, shaped line, or -1 if error - */ - static jint layoutLine(const jchar* text, jint len, jint flags, int &dir, jchar* buffer, - UErrorCode &status) { - static int RTL_OPTS = UBIDI_DO_MIRRORING | UBIDI_KEEP_BASE_COMBINING | - UBIDI_REMOVE_BIDI_CONTROLS | UBIDI_OUTPUT_REVERSE; - - UBiDiLevel bidiReq = 0; - switch (flags) { - 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: memcpy(buffer, text, len * sizeof(jchar)); return len; - case kBidi_Force_RTL: return shapeRtlText(text, 0, len, len, buffer, status); - } - - int32_t result = -1; - - UBiDi* bidi = ubidi_open(); - if (bidi) { - ubidi_setPara(bidi, text, len, bidiReq, NULL, &status); - if (U_SUCCESS(status)) { - dir = ubidi_getParaLevel(bidi) & 0x1; // 0 if ltr, 1 if rtl - - int rc = ubidi_countRuns(bidi, &status); - if (U_SUCCESS(status)) { - // LOG(LOG_INFO, "LAYOUT", "para bidiReq=%d dir=%d rc=%d\n", bidiReq, dir, rc); - - int32_t slen = 0; - for (int i = 0; i < rc; ++i) { - int32_t start; - int32_t length; - UBiDiDirection runDir = ubidi_getVisualRun(bidi, i, &start, &length); - // LOG(LOG_INFO, "LAYOUT", " [%2d] runDir=%d start=%3d len=%3d\n", i, runDir, start, length); - if (runDir == UBIDI_RTL) { - slen += shapeRtlText(text + start, 0, length, length, buffer + slen, status); - } else { - memcpy(buffer + slen, text + start, length * sizeof(jchar)); - slen += length; - } - } - if (U_SUCCESS(status)) { - result = slen; - } - } - } - ubidi_close(bidi); - } - - return result; - } - - // 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. - static bool 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] >= 0x0590) { - return true; - } - } - return false; - } - - // Draws a paragraph of text on a single line, running bidi and shaping - static void drawText(JNIEnv* env, SkCanvas* canvas, const jchar* text, jsize len, - jfloat x, jfloat y, int bidiFlags, SkPaint* paint) { - - SkScalar x_ = SkFloatToScalar(x); - SkScalar y_ = SkFloatToScalar(y); - - SkPaint::Align horiz = paint->getTextAlign(); - - 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; - } - 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 - } - - workText = buffer; // use the shaped text - } - - bool trimLeft = false; - bool trimRight = false; - - 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; - } - const jchar* workLimit = workText + len; - - if (trimLeft) { - while (workText < workLimit && *workText == ' ') { - ++workText; - } - } - if (trimRight) { - while (workLimit > workText && *(workLimit - 1) == ' ') { - --workLimit; - } - } - int32_t workBytes = (workLimit - workText) << 1; - - canvas->drawText(workText, workBytes, x_, y_, *paint); - - free(buffer); - } static void drawText___CIIFFIPaint(JNIEnv* env, jobject, SkCanvas* canvas, jcharArray text, int index, int count, jfloat x, jfloat y, int flags, SkPaint* paint) { jchar* textArray = env->GetCharArrayElements(text, NULL); - drawText(env, canvas, textArray + index, count, x, y, flags, paint); + TextLayout::drawText(paint, textArray + index, count, flags, x, y, canvas); env->ReleaseCharArrayElements(text, textArray, JNI_ABORT); } @@ -961,41 +765,18 @@ public: int start, int end, jfloat x, jfloat y, int flags, SkPaint* paint) { const jchar* textArray = env->GetStringChars(text, NULL); - drawText(env, canvas, textArray + start, end - start, x, y, flags, paint); + TextLayout::drawText(paint, textArray + start, end - start, flags, x, y, canvas); env->ReleaseStringChars(text, textArray); } - // Draws a unidirectional run of text. - static void drawTextRun(JNIEnv* env, SkCanvas* canvas, const jchar* chars, - jint start, jint count, jint contextCount, - jfloat x, jfloat y, int dirFlags, SkPaint* paint) { - - SkScalar x_ = SkFloatToScalar(x); - SkScalar y_ = SkFloatToScalar(y); - - uint8_t rtl = dirFlags & 0x1; - if (rtl) { - SkAutoSTMalloc<80, jchar> buffer(contextCount); - UErrorCode status = U_ZERO_ERROR; - count = shapeRtlText(chars, start, count, contextCount, buffer.get(), status); - if (U_SUCCESS(status)) { - canvas->drawText(buffer.get(), count << 1, x_, y_, *paint); - } else { - LOG(LOG_WARN, "LAYOUT", "drawTextRun error %d\n", status); - } - } else { - canvas->drawText(chars + start, count << 1, x_, y_, *paint); - } - } - static void drawTextRun___CIIIIFFIPaint( JNIEnv* env, jobject, SkCanvas* canvas, jcharArray text, int index, int count, int contextIndex, int contextCount, jfloat x, jfloat y, int dirFlags, SkPaint* paint) { jchar* chars = env->GetCharArrayElements(text, NULL); - drawTextRun(env, canvas, chars + contextIndex, index - contextIndex, - count, contextCount, x, y, dirFlags, paint); + TextLayout::drawTextRun(paint, chars + contextIndex, index - contextIndex, + count, contextCount, dirFlags, x, y, canvas); env->ReleaseCharArrayElements(text, chars, JNI_ABORT); } @@ -1007,8 +788,8 @@ public: jint count = end - start; jint contextCount = contextEnd - contextStart; const jchar* chars = env->GetStringChars(text, NULL); - drawTextRun(env, canvas, chars + contextStart, start - contextStart, - count, contextCount, x, y, dirFlags, paint); + TextLayout::drawTextRun(paint, chars + contextStart, start - contextStart, + count, contextCount, dirFlags, x, y, canvas); env->ReleaseStringChars(text, chars); } @@ -1059,31 +840,13 @@ public: delete[] posPtr; } - static void drawTextOnPath(JNIEnv *env, SkCanvas* canvas, const jchar* text, int count, - int bidiFlags, SkPath* path, jfloat hOffset, jfloat vOffset, SkPaint* paint) { - - if (!needsLayout(text, count, bidiFlags)) { - canvas->drawTextOnPathHV(text, count << 1, *path, - SkFloatToScalar(hOffset), SkFloatToScalar(vOffset), *paint); - return; - } - - SkAutoSTMalloc<80, jchar> buffer(count); - int dir = kDirection_LTR; - UErrorCode status = U_ZERO_ERROR; - count = layoutLine(text, count, bidiFlags, dir, buffer.get(), status); - if (U_SUCCESS(status)) { - canvas->drawTextOnPathHV(buffer.get(), count << 1, *path, - SkFloatToScalar(hOffset), SkFloatToScalar(vOffset), *paint); - } - } - static void drawTextOnPath___CIIPathFFPaint(JNIEnv* env, jobject, SkCanvas* canvas, jcharArray text, int index, int count, SkPath* path, jfloat hOffset, jfloat vOffset, jint bidiFlags, SkPaint* paint) { jchar* textArray = env->GetCharArrayElements(text, NULL); - drawTextOnPath(env, canvas, textArray, count, bidiFlags, path, hOffset, vOffset, paint); + TextLayout::drawTextOnPath(paint, textArray, count, bidiFlags, hOffset, vOffset, + path, canvas); env->ReleaseCharArrayElements(text, textArray, 0); } @@ -1092,7 +855,8 @@ public: jfloat hOffset, jfloat vOffset, jint bidiFlags, SkPaint* paint) { const jchar* text_ = env->GetStringChars(text, NULL); int count = env->GetStringLength(text); - drawTextOnPath(env, canvas, text_, count, bidiFlags, path, hOffset, vOffset, paint); + TextLayout::drawTextOnPath(paint, text_, count, bidiFlags, hOffset, vOffset, + path, canvas); env->ReleaseStringChars(text, text_); } |