summaryrefslogtreecommitdiffstats
path: root/core
diff options
context:
space:
mode:
authorFabrice Di Meglio <fdimeglio@google.com>2011-04-13 16:07:37 -0700
committerFabrice Di Meglio <fdimeglio@google.com>2011-04-15 19:39:47 -0700
commit689e515ed2b8064c15e54d8ab69d87de54c5e0d6 (patch)
tree92c6b436a8c4e7d6b76286f076aa2b0f6bd50648 /core
parent0343a7eb6d7cd2bd44dabe5119e2366e84427c93 (diff)
downloadframeworks_base-689e515ed2b8064c15e54d8ab69d87de54c5e0d6.zip
frameworks_base-689e515ed2b8064c15e54d8ab69d87de54c5e0d6.tar.gz
frameworks_base-689e515ed2b8064c15e54d8ab69d87de54c5e0d6.tar.bz2
Add Unicode BiDi Algo before drawing text in Canvas
- only for temporary API - update BiDiTest Change-Id: Ifd445799dc0fda4da896246e41978cd8d71aa035
Diffstat (limited to 'core')
-rw-r--r--core/jni/android/graphics/Canvas.cpp60
-rw-r--r--core/jni/android/graphics/RtlProperties.h2
-rw-r--r--core/jni/android/graphics/TextLayout.h34
-rw-r--r--core/jni/android/graphics/TextLayoutCache.cpp119
-rw-r--r--core/jni/android/graphics/TextLayoutCache.h4
5 files changed, 166 insertions, 53 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
/**