diff options
-rw-r--r-- | core/jni/android/graphics/Canvas.cpp | 60 | ||||
-rw-r--r-- | core/jni/android/graphics/RtlProperties.h | 2 | ||||
-rw-r--r-- | core/jni/android/graphics/TextLayout.h | 34 | ||||
-rw-r--r-- | core/jni/android/graphics/TextLayoutCache.cpp | 119 | ||||
-rw-r--r-- | core/jni/android/graphics/TextLayoutCache.h | 4 | ||||
-rw-r--r-- | tests/BiDiTests/AndroidManifest.xml | 3 | ||||
-rw-r--r-- | tests/BiDiTests/res/values/strings.xml | 3 | ||||
-rw-r--r-- | tests/BiDiTests/src/com/android/bidi/BiDiTestView.java | 28 |
8 files changed, 192 insertions, 61 deletions
diff --git a/core/jni/android/graphics/Canvas.cpp b/core/jni/android/graphics/Canvas.cpp index b2caa98..207c72f 100644 --- a/core/jni/android/graphics/Canvas.cpp +++ b/core/jni/android/graphics/Canvas.cpp @@ -756,26 +756,36 @@ public: env->ReleaseStringChars(text, textArray); } + static void logGlyphs(sp<TextLayoutCacheValue> value) { + LOGD("drawTextWithGlyphs -- got glyphs - count=%d", value->getGlyphsCount()); + for (size_t i = 0; i < value->getGlyphsCount(); i++) { + LOGD(" glyphs[%d]=%d", i, value->getGlyphs()[i]); + } + } + + static void drawTextWithGlyphs(SkCanvas* canvas, const jchar* textArray, + int start, int end, + jfloat x, jfloat y, int flags, SkPaint* paint) { + + jint count = end - start; + sp<TextLayoutCacheValue> value = gTextLayoutCache.getValue( + paint, textArray, start, count, count, flags); + if (value == NULL) { + LOGE("drawTextWithGlyphs -- cannot get Cache value"); + return ; + } +#if DEBUG_GLYPHS + logGlyphs(value); +#endif + doDrawGlyphs(canvas, value->getGlyphs(), 0, value->getGlyphsCount(), + x, y, flags, paint); + } + static void drawTextWithGlyphs___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); -#if RTL_USE_HARFBUZZ && USE_TEXT_LAYOUT_CACHE - sp<TextLayoutCacheValue> value = gTextLayoutCache.getValue( - paint, textArray + index, 0, count, count, flags); - if (value != NULL) { -#if DEBUG_GLYPHS - LOGD("drawTextWithGlyphs -- got glyphs - count=%d", value->getGlyphsCount()); - for (size_t i = 0; i < value->getGlyphsCount(); i++) { - LOGD(" glyphs[%d]=%d", i, value->getGlyphs()[i]); - } -#endif - doDrawGlyphs(canvas, value->getGlyphs(), 0, value->getGlyphsCount(), - x, y, flags, paint); - } -#else - TextLayout::drawText(paint, textArray + index, count, flags, x, y, canvas); -#endif + drawTextWithGlyphs(canvas, textArray + index, 0, count, x, y, flags, paint); env->ReleaseCharArrayElements(text, textArray, JNI_ABORT); } @@ -785,23 +795,7 @@ public: jfloat x, jfloat y, int flags, SkPaint* paint) { const jchar* textArray = env->GetStringChars(text, NULL); -#if RTL_USE_HARFBUZZ && USE_TEXT_LAYOUT_CACHE - size_t count = end - start; - sp<TextLayoutCacheValue> value = gTextLayoutCache.getValue( - paint, textArray, start, count, count, flags); - if (value != NULL) { -#if DEBUG_GLYPHS - LOGD("drawTextWithGlyphs -- got glyphs - count=%d", value->getGlyphsCount()); - for (size_t i = 0; i < value->getGlyphsCount(); i++) { - LOGD(" glyphs[%d]=%d", i, value->getGlyphs()[i]); - } -#endif - doDrawGlyphs(canvas, value->getGlyphs(), 0, value->getGlyphsCount(), - x, y, flags, paint); - } -#else - TextLayout::drawText(paint, textArray + start, end - start, flags, x, y, canvas); -#endif + drawTextWithGlyphs(canvas, textArray, start, end, x, y, flags, paint); env->ReleaseStringChars(text, textArray); } diff --git a/core/jni/android/graphics/RtlProperties.h b/core/jni/android/graphics/RtlProperties.h index a41c91b..4fac89a 100644 --- a/core/jni/android/graphics/RtlProperties.h +++ b/core/jni/android/graphics/RtlProperties.h @@ -52,7 +52,7 @@ static RtlDebugLevel readRtlDebugLevel() { #define DEBUG_ADVANCES 0 // Define if we want (1) to have Glyphs debug values or not (0) -#define DEBUG_GLYPHS 0 +#define DEBUG_GLYPHS 1 } // namespace android #endif // ANDROID_RTL_PROPERTIES_H diff --git a/core/jni/android/graphics/TextLayout.h b/core/jni/android/graphics/TextLayout.h index f203b75..9bb1b92 100644 --- a/core/jni/android/graphics/TextLayout.h +++ b/core/jni/android/graphics/TextLayout.h @@ -46,26 +46,26 @@ namespace android { static TextLayoutCache gTextLayoutCache; #endif -class TextLayout { -public: - - enum { - kDirection_LTR = 0, - kDirection_RTL = 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 +}; - kDirection_Mask = 0x1 - }; +enum { + kDirection_LTR = 0, + kDirection_RTL = 1, - enum { - kBidi_LTR = 0, - kBidi_RTL = 1, - kBidi_Default_LTR = 2, - kBidi_Default_RTL = 3, - kBidi_Force_LTR = 4, - kBidi_Force_RTL = 5, + kDirection_Mask = 0x1 +}; - kBidi_Mask = 0x7 - }; +class TextLayout { +public: /* * Draws a unidirectional run of text. diff --git a/core/jni/android/graphics/TextLayoutCache.cpp b/core/jni/android/graphics/TextLayoutCache.cpp index 8db768c..088202e 100644 --- a/core/jni/android/graphics/TextLayoutCache.cpp +++ b/core/jni/android/graphics/TextLayoutCache.cpp @@ -15,6 +15,7 @@ */ #include "TextLayoutCache.h" +#include "TextLayout.h" namespace android { @@ -381,13 +382,127 @@ void TextLayoutCacheValue::shapeWithHarfbuzz(HB_ShaperItem* shaperItem, HB_FontR } } +struct GlyphRun { + inline GlyphRun() {} + inline GlyphRun(jchar* glyphs, size_t glyphsCount, bool isRTL) : + glyphs(glyphs), glyphsCount(glyphsCount), isRTL(isRTL) { } + jchar* glyphs; + size_t glyphsCount; + int isRTL; +}; + void TextLayoutCacheValue::computeValuesWithHarfbuzz(SkPaint* paint, const UChar* chars, size_t start, size_t count, size_t contextCount, int dirFlags, jfloat* outAdvances, jfloat* outTotalAdvance, jchar** outGlyphs, size_t* outGlyphsCount) { + + UBiDiLevel bidiReq = 0; + bool forceLTR = false; + bool forceRTL = false; + + switch (dirFlags) { + 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 + } + + if (forceLTR || forceRTL) { +#if DEBUG_GLYPHS + LOGD("computeValuesWithHarfbuzz -- forcing run with LTR=%d RTL=%d", + forceLTR, forceRTL); +#endif + computeRunValuesWithHarfbuzz(paint, chars, start, count, contextCount, dirFlags, + outAdvances, outTotalAdvance, outGlyphs, outGlyphsCount); + } else { + UBiDi* bidi = ubidi_open(); + if (bidi) { + UErrorCode status = U_ZERO_ERROR; + LOGD("computeValuesWithHarfbuzz -- bidiReq=%d", bidiReq); + 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 + size_t rc = ubidi_countRuns(bidi, &status); +#if DEBUG_GLYPHS + LOGD("computeValuesWithHarfbuzz -- dirFlags=%d run-count=%d paraDir=%d", dirFlags, rc, paraDir); +#endif + + if (rc == 1 || !U_SUCCESS(status)) { + LOGD("HERE !!!"); + computeRunValuesWithHarfbuzz(paint, chars, start, count, contextCount, + dirFlags, outAdvances, outTotalAdvance, outGlyphs, outGlyphsCount); + ubidi_close(bidi); + return; + } + + size_t runIndex = 0; + Vector<GlyphRun> glyphRuns; + for (size_t i = 0; i < rc; ++i) { + int32_t startRun; + int32_t lengthRun; + UBiDiDirection runDir = ubidi_getVisualRun(bidi, i, &startRun, &lengthRun); + + int newFlags = (runDir == UBIDI_RTL) ? kDirection_RTL : kDirection_LTR; + jfloat runTotalAdvance = 0; + jchar* runGlyphs; + size_t runGlyphsCount = 0; + +#if DEBUG_GLYPHS + LOGD("computeValuesWithHarfbuzz -- run-start=%d run-len=%d newFlags=%d", + startRun, lengthRun, newFlags); +#endif + computeRunValuesWithHarfbuzz(paint, chars, startRun, + lengthRun, contextCount, newFlags, + outAdvances + runIndex, &runTotalAdvance, + &runGlyphs, &runGlyphsCount); + + runIndex += lengthRun; + + *outTotalAdvance += runTotalAdvance; + *outGlyphsCount += runGlyphsCount; + +#if DEBUG_GLYPHS + LOGD("computeValuesWithHarfbuzz -- run=%d run-glyphs-count=%d", + i, runGlyphsCount); + for (size_t j = 0; j < runGlyphsCount; j++) { + LOGD(" -- glyphs[%d]=%d", j, runGlyphs[j]); + } +#endif + glyphRuns.push(GlyphRun(runGlyphs, runGlyphsCount, newFlags)); + } + +#if DEBUG_GLYPHS + LOGD("computeValuesWithHarfbuzz -- total-glyphs-count=%d", *outGlyphsCount); +#endif + *outGlyphs = new jchar[*outGlyphsCount]; + jchar* glyphs = *outGlyphs; + for (size_t i = 0; i < glyphRuns.size(); i++) { + const GlyphRun& glyphRun = glyphRuns.itemAt(i); + if (glyphRun.isRTL) { + for (size_t n = 0; n < glyphRun.glyphsCount; n++) { + glyphs[glyphRun.glyphsCount - n - 1] = glyphRun.glyphs[n]; + } + } else { + memcpy(glyphs, glyphRun.glyphs, glyphRun.glyphsCount * sizeof(jchar)); + } + glyphs += glyphRun.glyphsCount; + delete[] glyphRun.glyphs; + } + } + ubidi_close(bidi); + } + } +} + +void TextLayoutCacheValue::computeRunValuesWithHarfbuzz(SkPaint* paint, const UChar* chars, + size_t start, size_t count, size_t contextCount, int dirFlags, + jfloat* outAdvances, jfloat* outTotalAdvance, + jchar** outGlyphs, size_t* outGlyphsCount) { + bool isRTL = dirFlags & 0x1; - // TODO: need to run BiDi algo here to breakdown the text in several runs HB_ShaperItem shaperItem; HB_FontRec font; FontData fontData; @@ -397,7 +512,7 @@ void TextLayoutCacheValue::computeValuesWithHarfbuzz(SkPaint* paint, const UChar #if DEBUG_GLYPHS LOGD("HARFBUZZ -- num_glypth=%d - kerning_applied=%d", shaperItem.num_glyphs, shaperItem.kerning_applied); - LOGD(" -- string= '%s'", String8(chars, contextCount).string()); + LOGD(" -- string= '%s'", String8(chars + start, count).string()); LOGD(" -- isDevKernText=%d", paint->isDevKernText()); #endif diff --git a/core/jni/android/graphics/TextLayoutCache.h b/core/jni/android/graphics/TextLayoutCache.h index e6ce68d..62813df 100644 --- a/core/jni/android/graphics/TextLayoutCache.h +++ b/core/jni/android/graphics/TextLayoutCache.h @@ -178,6 +178,10 @@ private: static void createGlyphArrays(HB_ShaperItem* shaperItem, int size); static void resetGlyphArrays(HB_ShaperItem* shaperItem); + static void computeRunValuesWithHarfbuzz(SkPaint* paint, const UChar* chars, size_t start, + size_t count, size_t contextCount, int dirFlags, + jfloat* outAdvances, jfloat* outTotalAdvance, + jchar** outGlyphs, size_t* outGlyphsCount); }; // TextLayoutCacheValue /** diff --git a/tests/BiDiTests/AndroidManifest.xml b/tests/BiDiTests/AndroidManifest.xml index 346ace8..727f980 100644 --- a/tests/BiDiTests/AndroidManifest.xml +++ b/tests/BiDiTests/AndroidManifest.xml @@ -25,7 +25,8 @@ android:versionName="1.0"> <application android:label="BiDiTests"> - <activity android:name="BiDiTestActivity"> + <activity android:name="BiDiTestActivity" + android:windowSoftInputMode="stateAlwaysHidden"> <intent-filter> <action android:name="android.intent.action.MAIN" /> <category android:name="android.intent.category.LAUNCHER" /> diff --git a/tests/BiDiTests/res/values/strings.xml b/tests/BiDiTests/res/values/strings.xml index 632a02e..d20600e 100644 --- a/tests/BiDiTests/res/values/strings.xml +++ b/tests/BiDiTests/res/values/strings.xml @@ -20,9 +20,10 @@ <string name="normal_long_text">mmmmmmmmmmmmmmmmmmmmmmmm</string> <string name="normal_long_text_2">nnnnnnnnnnnnnnnnnnnnnnnn</string> <string name="normal_long_text_3">Notify me when an open network is available</string> - <string name="arabic_text">لا</string> + <string name="arabic_text">لا انا hello world</string> <string name="chinese_text">利比亚局势或影响美俄关系发展</string> <string name="italic_text">Italic String</string> <string name="bold_text">Bold String - other text</string> <string name="bold_italic_text">Bold Italic String</string> + <string name="mixed_text_1">he said in Arabic: لا. Wow this is cool</string> </resources>
\ No newline at end of file diff --git a/tests/BiDiTests/src/com/android/bidi/BiDiTestView.java b/tests/BiDiTests/src/com/android/bidi/BiDiTestView.java index f00bd06..2f9b026 100644 --- a/tests/BiDiTests/src/com/android/bidi/BiDiTestView.java +++ b/tests/BiDiTests/src/com/android/bidi/BiDiTestView.java @@ -49,6 +49,7 @@ public class BiDiTestView extends View { private String BOLD_ITALIC_TEXT; private String ARABIC_TEXT; private String CHINESE_TEXT; + private String MIXED_TEXT_1; private Typeface typeface; @@ -79,6 +80,7 @@ public class BiDiTestView extends View { 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); typeface = paint.getTypeface(); paint.setAntiAlias(true); @@ -124,6 +126,10 @@ public class BiDiTestView extends View { // Test Chinese deltaX = testString(canvas, CHINESE_TEXT, ORIGIN, ORIGIN + 10 * currentTextSize, paint, typeface, false, false, Paint.DIRECTION_LTR, currentTextSize); + + // Test Mixed (English and Arabic) + deltaX = testString(canvas, MIXED_TEXT_1, ORIGIN, ORIGIN + 12 * currentTextSize, + paint, typeface, false, false, Paint.DIRECTION_LTR, currentTextSize); } private int testString(Canvas canvas, String text, int x, int y, Paint paint, Typeface typeface, @@ -139,12 +145,15 @@ public class BiDiTestView extends View { paint.setTextSkewX(DEFAULT_ITALIC_SKEW_X); } - drawTextWithCanvasDrawText(text, canvas, x, y, textSize, Color.WHITE); + Log.v(TAG, "START -- drawTextWithCanvasDrawText"); + drawTextWithCanvasDrawText(text, canvas, x, y, textSize, Color.WHITE, dir); + Log.v(TAG, "END -- drawTextWithCanvasDrawText"); int length = text.length(); float[] advances = new float[length]; - float textWidthHB = paint.getTextRunAdvances(text, 0, length, 0, length, 0, advances, 0); - float textWidthICU = paint.getTextRunAdvancesICU(text, 0, length, 0, length, 0, advances, 0); + float textWidthHB = paint.getTextRunAdvances(text, 0, length, 0, length, dir, advances, 0); + setPaintDir(paint, dir); + float textWidthICU = paint.getTextRunAdvancesICU(text, 0, length, 0, length, dir, advances, 0); logAdvances(text, textWidthHB, textWidthICU, advances); drawMetricsAroundText(canvas, x, y, textWidthHB, textWidthICU, textSize, Color.RED, Color.GREEN); @@ -156,7 +165,9 @@ public class BiDiTestView extends View { // logGlypths(glyphs, count); // drawTextWithDrawGlyph(canvas, glyphs, count, x, y + currentTextSize); + Log.v(TAG, "START -- drawTextWithGlyphs"); drawTextWithGlyphs(canvas, text, x, y + currentTextSize, dir); + Log.v(TAG, "END -- drawTextWithGlyphs"); // Restore old paint properties paint.setFakeBoldText(oldFakeBold); @@ -165,12 +176,17 @@ public class BiDiTestView extends View { 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 drawTextWithDrawGlyph(Canvas canvas, char[] glyphs, int count, int x, int y) { canvas.drawGlyphs(glyphs, 0, count, x, y, paint); } private void drawTextWithGlyphs(Canvas canvas, String text, int x, int y, int dir) { - paint.setBidiFlags(dir); + setPaintDir(paint, dir); canvas.drawTextWithGlyphs(text, x, y, paint); } @@ -182,7 +198,6 @@ public class BiDiTestView extends View { } private int getGlyphs(String text, char[] glyphs, int dir) { -// int dir = 1; // Paint.DIRECTION_LTR; return paint.getTextGlypths(text, 0, text.length(), 0, text.length(), dir, glyphs); } @@ -195,7 +210,8 @@ public class BiDiTestView extends View { } private void drawTextWithCanvasDrawText(String text, Canvas canvas, - float x, float y, float textSize, int color) { + float x, float y, float textSize, int color, int dir) { + setPaintDir(paint, dir); paint.setColor(color); paint.setTextSize(textSize); canvas.drawText(text, x, y, paint); |