Loading core/jni/android/graphics/Canvas.cpp +188 −137 Original line number Diff line number Diff line Loading @@ -33,7 +33,6 @@ #include "unicode/ubidi.h" #include "unicode/ushape.h" // temporary for debugging #include <utils/Log.h> #define TIME_DRAWx Loading Loading @@ -769,120 +768,158 @@ public: } /** * 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 <= len * @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, static int shapeRtlText(const jchar* context, jsize start, jsize count, jsize contextCount, jchar* shaped, UErrorCode &status) { jchar buffer[contextCount]; // We'd rather use harfbuzz here. Use character based shaping for now. // 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)) { return 0; } 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) { continue; } 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; } static void drawText__(JNIEnv* env, SkCanvas* canvas, const jchar* text, jsize len, jfloat x, jfloat y, int flags, SkPaint* paint) { SkScalar x_ = SkFloatToScalar(x); SkScalar y_ = SkFloatToScalar(y); SkPaint::Align horiz = paint->getTextAlign(); bool needBidi = (flags == kBidi_RTL) || (flags == kBidi_Default_RTL); if (!needBidi && flags < kBidi_Force_LTR) { for (int i = 0; i < len; ++i) { if (text[i] >= 0x0590) { needBidi = TRUE; break; } } return -1; } int dir = (flags == kBidi_Force_RTL) ? kDirection_RTL : kDirection_LTR; // will be reset if we run bidi UErrorCode status = U_ZERO_ERROR; jchar *shaped = NULL; int32_t slen = 0; if (needBidi || (flags == kBidi_Force_RTL)) { shaped = (jchar *)malloc(len * sizeof(jchar)); if (!shaped) { status = U_MEMORY_ALLOCATION_ERROR; } else { if (needBidi) { /** * 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; jint lineDir = 0; UBiDiLevel bidiReq = 0; switch (flags) { case kBidi_LTR: lineDir = 0; break; // no ICU constant, canonical LTR level case kBidi_RTL: lineDir = 1; break; // no ICU constant, canonical RTL level case kBidi_Default_LTR: lineDir = UBIDI_DEFAULT_LTR; break; case kBidi_Default_RTL: lineDir = UBIDI_DEFAULT_RTL; break; 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(); ubidi_setPara(bidi, text, len, lineDir, NULL, &status); if (bidi) { ubidi_setPara(bidi, text, len, bidiReq, NULL, &status); if (U_SUCCESS(status)) { dir = ubidi_getParaLevel(bidi) & 0x1; 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 dir; jchar *buffer = NULL; for (int i = 0; i < rc; ++i) { dir = ubidi_getVisualRun(bidi, i, &start, &length); // fake shaping, except it doesn't shape, just mirrors and reverses // use harfbuzz when available if (dir == UBIDI_RTL) { slen += ubidi_writeReverse(text + start, length, shaped + slen, length, RTL_OPTS, &status); 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 { for (int i = 0; i < length; ++i) { shaped[slen + i] = text[start + i]; } memcpy(buffer + slen, text + start, length * sizeof(jchar)); slen += length; } } if (U_SUCCESS(status)) { result = slen; } } } ubidi_close(bidi); } } else { len = shapeRtlText__(text, 0, len, len, shaped, status); 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)) { char buffer[35]; sprintf(buffer, "DrawText bidi error %d", status); doThrowIAE(env, buffer); } else { 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; Loading @@ -892,7 +929,6 @@ public: case SkPaint::kRight_Align: trimRight = !(dir & kDirection_Mask); default: break; } const jchar* workText = shaped ? shaped : text; const jchar* workLimit = workText + len; if (trimLeft) { Loading @@ -908,18 +944,15 @@ public: int32_t workBytes = (workLimit - workText) << 1; canvas->drawText(workText, workBytes, x_, y_, *paint); } if (shaped) { free(shaped); } 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); drawText(env, canvas, textArray + index, count, x, y, flags, paint); env->ReleaseCharArrayElements(text, textArray, JNI_ABORT); } Loading @@ -928,27 +961,27 @@ 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); drawText(env, canvas, textArray + start, end - start, x, y, flags, paint); env->ReleaseStringChars(text, textArray); } // Draws a unidirectional run of text. static void drawTextRun__(JNIEnv* env, SkCanvas* canvas, const jchar* chars, static void drawTextRun(JNIEnv* env, SkCanvas* canvas, const jchar* chars, jint start, jint count, jint contextCount, jfloat x, jfloat y, int flags, SkPaint* paint) { jfloat x, jfloat y, int dirFlags, SkPaint* paint) { SkScalar x_ = SkFloatToScalar(x); SkScalar y_ = SkFloatToScalar(y); uint8_t rtl = flags & 0x1; uint8_t rtl = dirFlags & 0x1; if (rtl) { jchar context[contextCount]; SkAutoSTMalloc<80, jchar> buffer(contextCount); UErrorCode status = U_ZERO_ERROR; count = shapeRtlText__(chars, start, count, contextCount, context, status); count = shapeRtlText(chars, start, count, contextCount, buffer.get(), status); if (U_SUCCESS(status)) { canvas->drawText(context, count << 1, x_, y_, *paint); canvas->drawText(buffer.get(), count << 1, x_, y_, *paint); } else { doThrowIAE(env, "shaping error"); LOG(LOG_WARN, "LAYOUT", "drawTextRun error %d\n", status); } } else { canvas->drawText(chars + start, count << 1, x_, y_, *paint); Loading @@ -958,24 +991,24 @@ public: static void drawTextRun___CIIIIFFIPaint( JNIEnv* env, jobject, SkCanvas* canvas, jcharArray text, int index, int count, int contextIndex, int contextCount, jfloat x, jfloat y, int flags, SkPaint* paint) { 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, flags, paint); drawTextRun(env, canvas, chars + contextIndex, index - contextIndex, count, contextCount, x, y, dirFlags, paint); env->ReleaseCharArrayElements(text, chars, JNI_ABORT); } static void drawTextRun__StringIIIIFFIPaint( JNIEnv* env, jobject obj, SkCanvas* canvas, jstring text, jint start, jint end, jint contextStart, jint contextEnd, jfloat x, jfloat y, jint flags, SkPaint* paint) { jfloat x, jfloat y, jint dirFlags, SkPaint* paint) { 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, flags, paint); drawTextRun(env, canvas, chars + contextStart, start - contextStart, count, contextCount, x, y, dirFlags, paint); env->ReleaseStringChars(text, chars); } Loading Loading @@ -1004,7 +1037,8 @@ public: static void drawPosText__String_FPaint(JNIEnv* env, jobject, SkCanvas* canvas, jstring text, jfloatArray pos, SkPaint* paint) { jfloatArray pos, SkPaint* paint) { const void* text_ = text ? env->GetStringChars(text, NULL) : NULL; int byteLength = text ? env->GetStringLength(text) : 0; float* posArray = pos ? env->GetFloatArrayElements(pos, NULL) : NULL; Loading @@ -1025,23 +1059,40 @@ 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, SkPaint* paint) { SkPath* path, jfloat hOffset, jfloat vOffset, jint bidiFlags, SkPaint* paint) { jchar* textArray = env->GetCharArrayElements(text, NULL); canvas->drawTextOnPathHV(textArray + index, count << 1, *path, SkFloatToScalar(hOffset), SkFloatToScalar(vOffset), *paint); drawTextOnPath(env, canvas, textArray, count, bidiFlags, path, hOffset, vOffset, paint); 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 byteLength = env->GetStringLength(text) << 1; canvas->drawTextOnPathHV(text_, byteLength, *path, SkFloatToScalar(hOffset), SkFloatToScalar(vOffset), *paint); int count = env->GetStringLength(text); drawTextOnPath(env, canvas, text_, count, bidiFlags, path, hOffset, vOffset, paint); env->ReleaseStringChars(text, text_); } Loading Loading @@ -1155,9 +1206,9 @@ static JNINativeMethod gCanvasMethods[] = { (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}, Loading graphics/java/android/graphics/Canvas.java +8 −5 Original line number Diff line number Diff line Loading @@ -1505,7 +1505,7 @@ public class Canvas { } native_drawTextOnPath(mNativeCanvas, text, index, count, path.ni(), hOffset, vOffset, paint.mNativePaint); paint.mBidiFlags, paint.mNativePaint); } /** Loading @@ -1525,7 +1525,8 @@ public class Canvas { float vOffset, Paint paint) { if (text.length() > 0) { native_drawTextOnPath(mNativeCanvas, text, path.ni(), hOffset, vOffset, paint.mNativePaint); hOffset, vOffset, paint.mBidiFlags, paint.mNativePaint); } } Loading Loading @@ -1716,11 +1717,13 @@ public class Canvas { char[] text, int index, int count, int path, float hOffset, float vOffset, int paint); float vOffset, int bidiFlags, int paint); private static native void native_drawTextOnPath(int nativeCanvas, String text, int path, float hOffset, float vOffset, int paint); float vOffset, int flags, int paint); private static native void native_drawPicture(int nativeCanvas, int nativePicture); private static native void finalizer(int nativeCanvas); Loading Loading
core/jni/android/graphics/Canvas.cpp +188 −137 Original line number Diff line number Diff line Loading @@ -33,7 +33,6 @@ #include "unicode/ubidi.h" #include "unicode/ushape.h" // temporary for debugging #include <utils/Log.h> #define TIME_DRAWx Loading Loading @@ -769,120 +768,158 @@ public: } /** * 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 <= len * @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, static int shapeRtlText(const jchar* context, jsize start, jsize count, jsize contextCount, jchar* shaped, UErrorCode &status) { jchar buffer[contextCount]; // We'd rather use harfbuzz here. Use character based shaping for now. // 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)) { return 0; } 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) { continue; } 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; } static void drawText__(JNIEnv* env, SkCanvas* canvas, const jchar* text, jsize len, jfloat x, jfloat y, int flags, SkPaint* paint) { SkScalar x_ = SkFloatToScalar(x); SkScalar y_ = SkFloatToScalar(y); SkPaint::Align horiz = paint->getTextAlign(); bool needBidi = (flags == kBidi_RTL) || (flags == kBidi_Default_RTL); if (!needBidi && flags < kBidi_Force_LTR) { for (int i = 0; i < len; ++i) { if (text[i] >= 0x0590) { needBidi = TRUE; break; } } return -1; } int dir = (flags == kBidi_Force_RTL) ? kDirection_RTL : kDirection_LTR; // will be reset if we run bidi UErrorCode status = U_ZERO_ERROR; jchar *shaped = NULL; int32_t slen = 0; if (needBidi || (flags == kBidi_Force_RTL)) { shaped = (jchar *)malloc(len * sizeof(jchar)); if (!shaped) { status = U_MEMORY_ALLOCATION_ERROR; } else { if (needBidi) { /** * 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; jint lineDir = 0; UBiDiLevel bidiReq = 0; switch (flags) { case kBidi_LTR: lineDir = 0; break; // no ICU constant, canonical LTR level case kBidi_RTL: lineDir = 1; break; // no ICU constant, canonical RTL level case kBidi_Default_LTR: lineDir = UBIDI_DEFAULT_LTR; break; case kBidi_Default_RTL: lineDir = UBIDI_DEFAULT_RTL; break; 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(); ubidi_setPara(bidi, text, len, lineDir, NULL, &status); if (bidi) { ubidi_setPara(bidi, text, len, bidiReq, NULL, &status); if (U_SUCCESS(status)) { dir = ubidi_getParaLevel(bidi) & 0x1; 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 dir; jchar *buffer = NULL; for (int i = 0; i < rc; ++i) { dir = ubidi_getVisualRun(bidi, i, &start, &length); // fake shaping, except it doesn't shape, just mirrors and reverses // use harfbuzz when available if (dir == UBIDI_RTL) { slen += ubidi_writeReverse(text + start, length, shaped + slen, length, RTL_OPTS, &status); 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 { for (int i = 0; i < length; ++i) { shaped[slen + i] = text[start + i]; } memcpy(buffer + slen, text + start, length * sizeof(jchar)); slen += length; } } if (U_SUCCESS(status)) { result = slen; } } } ubidi_close(bidi); } } else { len = shapeRtlText__(text, 0, len, len, shaped, status); 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)) { char buffer[35]; sprintf(buffer, "DrawText bidi error %d", status); doThrowIAE(env, buffer); } else { 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; Loading @@ -892,7 +929,6 @@ public: case SkPaint::kRight_Align: trimRight = !(dir & kDirection_Mask); default: break; } const jchar* workText = shaped ? shaped : text; const jchar* workLimit = workText + len; if (trimLeft) { Loading @@ -908,18 +944,15 @@ public: int32_t workBytes = (workLimit - workText) << 1; canvas->drawText(workText, workBytes, x_, y_, *paint); } if (shaped) { free(shaped); } 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); drawText(env, canvas, textArray + index, count, x, y, flags, paint); env->ReleaseCharArrayElements(text, textArray, JNI_ABORT); } Loading @@ -928,27 +961,27 @@ 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); drawText(env, canvas, textArray + start, end - start, x, y, flags, paint); env->ReleaseStringChars(text, textArray); } // Draws a unidirectional run of text. static void drawTextRun__(JNIEnv* env, SkCanvas* canvas, const jchar* chars, static void drawTextRun(JNIEnv* env, SkCanvas* canvas, const jchar* chars, jint start, jint count, jint contextCount, jfloat x, jfloat y, int flags, SkPaint* paint) { jfloat x, jfloat y, int dirFlags, SkPaint* paint) { SkScalar x_ = SkFloatToScalar(x); SkScalar y_ = SkFloatToScalar(y); uint8_t rtl = flags & 0x1; uint8_t rtl = dirFlags & 0x1; if (rtl) { jchar context[contextCount]; SkAutoSTMalloc<80, jchar> buffer(contextCount); UErrorCode status = U_ZERO_ERROR; count = shapeRtlText__(chars, start, count, contextCount, context, status); count = shapeRtlText(chars, start, count, contextCount, buffer.get(), status); if (U_SUCCESS(status)) { canvas->drawText(context, count << 1, x_, y_, *paint); canvas->drawText(buffer.get(), count << 1, x_, y_, *paint); } else { doThrowIAE(env, "shaping error"); LOG(LOG_WARN, "LAYOUT", "drawTextRun error %d\n", status); } } else { canvas->drawText(chars + start, count << 1, x_, y_, *paint); Loading @@ -958,24 +991,24 @@ public: static void drawTextRun___CIIIIFFIPaint( JNIEnv* env, jobject, SkCanvas* canvas, jcharArray text, int index, int count, int contextIndex, int contextCount, jfloat x, jfloat y, int flags, SkPaint* paint) { 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, flags, paint); drawTextRun(env, canvas, chars + contextIndex, index - contextIndex, count, contextCount, x, y, dirFlags, paint); env->ReleaseCharArrayElements(text, chars, JNI_ABORT); } static void drawTextRun__StringIIIIFFIPaint( JNIEnv* env, jobject obj, SkCanvas* canvas, jstring text, jint start, jint end, jint contextStart, jint contextEnd, jfloat x, jfloat y, jint flags, SkPaint* paint) { jfloat x, jfloat y, jint dirFlags, SkPaint* paint) { 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, flags, paint); drawTextRun(env, canvas, chars + contextStart, start - contextStart, count, contextCount, x, y, dirFlags, paint); env->ReleaseStringChars(text, chars); } Loading Loading @@ -1004,7 +1037,8 @@ public: static void drawPosText__String_FPaint(JNIEnv* env, jobject, SkCanvas* canvas, jstring text, jfloatArray pos, SkPaint* paint) { jfloatArray pos, SkPaint* paint) { const void* text_ = text ? env->GetStringChars(text, NULL) : NULL; int byteLength = text ? env->GetStringLength(text) : 0; float* posArray = pos ? env->GetFloatArrayElements(pos, NULL) : NULL; Loading @@ -1025,23 +1059,40 @@ 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, SkPaint* paint) { SkPath* path, jfloat hOffset, jfloat vOffset, jint bidiFlags, SkPaint* paint) { jchar* textArray = env->GetCharArrayElements(text, NULL); canvas->drawTextOnPathHV(textArray + index, count << 1, *path, SkFloatToScalar(hOffset), SkFloatToScalar(vOffset), *paint); drawTextOnPath(env, canvas, textArray, count, bidiFlags, path, hOffset, vOffset, paint); 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 byteLength = env->GetStringLength(text) << 1; canvas->drawTextOnPathHV(text_, byteLength, *path, SkFloatToScalar(hOffset), SkFloatToScalar(vOffset), *paint); int count = env->GetStringLength(text); drawTextOnPath(env, canvas, text_, count, bidiFlags, path, hOffset, vOffset, paint); env->ReleaseStringChars(text, text_); } Loading Loading @@ -1155,9 +1206,9 @@ static JNINativeMethod gCanvasMethods[] = { (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}, Loading
graphics/java/android/graphics/Canvas.java +8 −5 Original line number Diff line number Diff line Loading @@ -1505,7 +1505,7 @@ public class Canvas { } native_drawTextOnPath(mNativeCanvas, text, index, count, path.ni(), hOffset, vOffset, paint.mNativePaint); paint.mBidiFlags, paint.mNativePaint); } /** Loading @@ -1525,7 +1525,8 @@ public class Canvas { float vOffset, Paint paint) { if (text.length() > 0) { native_drawTextOnPath(mNativeCanvas, text, path.ni(), hOffset, vOffset, paint.mNativePaint); hOffset, vOffset, paint.mBidiFlags, paint.mNativePaint); } } Loading Loading @@ -1716,11 +1717,13 @@ public class Canvas { char[] text, int index, int count, int path, float hOffset, float vOffset, int paint); float vOffset, int bidiFlags, int paint); private static native void native_drawTextOnPath(int nativeCanvas, String text, int path, float hOffset, float vOffset, int paint); float vOffset, int flags, int paint); private static native void native_drawPicture(int nativeCanvas, int nativePicture); private static native void finalizer(int nativeCanvas); Loading