summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorFabrice Di Meglio <fdimeglio@google.com>2011-03-30 12:01:52 -0700
committerAndroid (Google) Code Review <android-gerrit@google.com>2011-03-30 12:01:52 -0700
commit4111bec3b68a200932817f4b8924fea08f4d5905 (patch)
tree6d2a84f464791e15fe9da959bc4bc8860f0a1c04
parent525194034156707bcb1134f5dc54283fe0ff470d (diff)
parenteee49c699c035ffba188417489f40d34f587d65c (diff)
downloadframeworks_base-4111bec3b68a200932817f4b8924fea08f4d5905.zip
frameworks_base-4111bec3b68a200932817f4b8924fea08f4d5905.tar.gz
frameworks_base-4111bec3b68a200932817f4b8924fea08f4d5905.tar.bz2
Merge "Fix text redering issue where the text was sometimes truncated"
-rw-r--r--core/java/android/text/GraphicsOperations.java7
-rw-r--r--core/java/android/text/SpannableStringBuilder.java29
-rw-r--r--core/java/android/widget/TextView.java10
-rw-r--r--core/jni/android/graphics/HarfbuzzSkia.cpp55
-rw-r--r--core/jni/android/graphics/HarfbuzzSkia.h34
-rw-r--r--core/jni/android/graphics/Paint.cpp45
-rw-r--r--core/jni/android/graphics/RtlProperties.h5
-rw-r--r--core/jni/android/graphics/TextLayout.cpp15
-rw-r--r--core/jni/android/graphics/TextLayout.h8
-rw-r--r--core/jni/android/graphics/TextLayoutCache.h56
-rw-r--r--graphics/java/android/graphics/Paint.java122
-rw-r--r--tests/BiDiTests/res/layout/biditest_main.xml5
-rw-r--r--tests/BiDiTests/res/values/strings.xml4
-rw-r--r--tests/BiDiTests/src/com/android/bidi/BiDiTestActivity.java28
-rw-r--r--tests/BiDiTests/src/com/android/bidi/BiDiTestConstants.java22
-rw-r--r--tests/BiDiTests/src/com/android/bidi/BiDiTestView.java94
16 files changed, 442 insertions, 97 deletions
diff --git a/core/java/android/text/GraphicsOperations.java b/core/java/android/text/GraphicsOperations.java
index d426d12..6e2168b 100644
--- a/core/java/android/text/GraphicsOperations.java
+++ b/core/java/android/text/GraphicsOperations.java
@@ -58,6 +58,13 @@ extends CharSequence
int flags, float[] advances, int advancesIndex, Paint paint);
/**
+ * Just like {@link Paint#getTextRunAdvances}.
+ * @hide
+ */
+ float getTextRunAdvancesICU(int start, int end, int contextStart, int contextEnd,
+ int flags, float[] advances, int advancesIndex, Paint paint);
+
+ /**
* Just like {@link Paint#getTextRunCursor}.
* @hide
*/
diff --git a/core/java/android/text/SpannableStringBuilder.java b/core/java/android/text/SpannableStringBuilder.java
index ea5cdfe..ff6a4cd 100644
--- a/core/java/android/text/SpannableStringBuilder.java
+++ b/core/java/android/text/SpannableStringBuilder.java
@@ -1170,6 +1170,35 @@ implements CharSequence, GetChars, Spannable, Editable, Appendable,
}
/**
+ * Don't call this yourself -- exists for Paint to use internally.
+ * {@hide}
+ */
+ public float getTextRunAdvancesICU(int start, int end, int contextStart, int contextEnd, int flags,
+ float[] advances, int advancesPos, Paint p) {
+
+ float ret;
+
+ int contextLen = contextEnd - contextStart;
+ int len = end - start;
+
+ if (end <= mGapStart) {
+ ret = p.getTextRunAdvancesICU(mText, start, len, contextStart, contextLen,
+ flags, advances, advancesPos);
+ } else if (start >= mGapStart) {
+ ret = p.getTextRunAdvancesICU(mText, start + mGapLength, len,
+ contextStart + mGapLength, contextLen, flags, advances, advancesPos);
+ } else {
+ char[] buf = TextUtils.obtain(contextLen);
+ getChars(contextStart, contextEnd, buf, 0);
+ ret = p.getTextRunAdvancesICU(buf, start - contextStart, len,
+ 0, contextLen, flags, advances, advancesPos);
+ TextUtils.recycle(buf);
+ }
+
+ return ret;
+ }
+
+ /**
* Returns the next cursor position in the run. This avoids placing the cursor between
* surrogates, between characters that form conjuncts, between base characters and combining
* marks, or within a reordering cluster.
diff --git a/core/java/android/widget/TextView.java b/core/java/android/widget/TextView.java
index baf20a1..9e482b4 100644
--- a/core/java/android/widget/TextView.java
+++ b/core/java/android/widget/TextView.java
@@ -2951,6 +2951,16 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
advancesIndex);
}
+ public float getTextRunAdvancesICU(int start, int end, int contextStart,
+ int contextEnd, int flags, float[] advances, int advancesIndex,
+ Paint p) {
+ int count = end - start;
+ int contextCount = contextEnd - contextStart;
+ return p.getTextRunAdvancesICU(mChars, start + mStart, count,
+ contextStart + mStart, contextCount, flags, advances,
+ advancesIndex);
+ }
+
public int getTextRunCursor(int contextStart, int contextEnd, int flags,
int offset, int cursorOpt, Paint p) {
int contextCount = contextEnd - contextStart;
diff --git a/core/jni/android/graphics/HarfbuzzSkia.cpp b/core/jni/android/graphics/HarfbuzzSkia.cpp
index 58fb32b..92c743f 100644
--- a/core/jni/android/graphics/HarfbuzzSkia.cpp
+++ b/core/jni/android/graphics/HarfbuzzSkia.cpp
@@ -34,6 +34,8 @@
#include "SkRect.h"
#include "SkTypeface.h"
+#include <utils/Log.h>
+
extern "C" {
#include "harfbuzz-shaper.h"
}
@@ -43,20 +45,13 @@ extern "C" {
namespace android {
-static HB_Fixed SkiaScalarToHarfbuzzFixed(SkScalar value)
-{
- // HB_Fixed is a 26.6 fixed point format.
- return value * 64;
-}
-
static void setupPaintWithFontData(SkPaint* paint, FontData* data) {
- paint->setAntiAlias(true);
- paint->setSubpixelText(true);
- paint->setHinting(SkPaint::kSlight_Hinting);
- paint->setTextSize(SkFloatToScalar(data->textSize));
paint->setTypeface(data->typeFace);
- paint->setFakeBoldText(data->fakeBold);
- paint->setTextSkewX(data->fakeItalic ? -SK_Scalar1/4 : 0);
+ paint->setTextSize(data->textSize);
+ paint->setTextSkewX(data->textSkewX);
+ paint->setTextScaleX(data->textScaleX);
+ paint->setFlags(data->flags);
+ paint->setHinting(data->hinting);
}
static HB_Bool stringToGlyphs(HB_Font hbFont, const HB_UChar16* characters, hb_uint32 length,
@@ -67,16 +62,13 @@ static HB_Bool stringToGlyphs(HB_Font hbFont, const HB_UChar16* characters, hb_u
setupPaintWithFontData(&paint, data);
paint.setTextEncoding(SkPaint::kUTF16_TextEncoding);
- int numGlyphs = paint.textToGlyphs(characters, length * sizeof(uint16_t),
- reinterpret_cast<uint16_t*>(glyphs));
+ uint16_t* skiaGlyphs = reinterpret_cast<uint16_t*>(glyphs);
+ int numGlyphs = paint.textToGlyphs(characters, length * sizeof(uint16_t), skiaGlyphs);
// HB_Glyph is 32-bit, but Skia outputs only 16-bit numbers. So our
// |glyphs| array needs to be converted.
for (int i = numGlyphs - 1; i >= 0; --i) {
- uint16_t value;
- // We use a memcpy to avoid breaking strict aliasing rules.
- memcpy(&value, reinterpret_cast<char*>(glyphs) + sizeof(uint16_t) * i, sizeof(value));
- glyphs[i] = value;
+ glyphs[i] = skiaGlyphs[i];
}
*glyphsSize = numGlyphs;
@@ -97,16 +89,17 @@ static void glyphsToAdvances(HB_Font hbFont, const HB_Glyph* glyphs, hb_uint32 n
return;
for (unsigned i = 0; i < numGlyphs; ++i)
glyphs16[i] = glyphs[i];
- paint.getTextWidths(glyphs16, numGlyphs * sizeof(uint16_t), reinterpret_cast<SkScalar*>(advances));
+ SkScalar* scalarAdvances = reinterpret_cast<SkScalar*>(advances);
+ paint.getTextWidths(glyphs16, numGlyphs * sizeof(uint16_t), scalarAdvances);
// The |advances| values which Skia outputs are SkScalars, which are floats
// in Chromium. However, Harfbuzz wants them in 26.6 fixed point format.
// These two formats are both 32-bits long.
for (unsigned i = 0; i < numGlyphs; ++i) {
- float value;
- // We use a memcpy to avoid breaking strict aliasing rules.
- memcpy(&value, reinterpret_cast<char*>(advances) + sizeof(float) * i, sizeof(value));
- advances[i] = SkiaScalarToHarfbuzzFixed(value);
+ advances[i] = SkScalarToHBFixed(scalarAdvances[i]);
+#if DEBUG_ADVANCES
+ LOGD("glyphsToAdvances -- advances[%d]=%d", i, advances[i]);
+#endif
}
delete glyphs16;
}
@@ -156,8 +149,8 @@ static HB_Error getOutlinePoint(HB_Font hbFont, HB_Glyph glyph, int flags, hb_ui
return HB_Err_Invalid_SubTable;
// Skia does let us get a single point from the path.
path.getPoints(points, point + 1);
- *xPos = SkiaScalarToHarfbuzzFixed(points[point].fX);
- *yPos = SkiaScalarToHarfbuzzFixed(points[point].fY);
+ *xPos = SkScalarToHBFixed(points[point].fX);
+ *yPos = SkScalarToHBFixed(points[point].fY);
*resultingNumPoints = numPoints;
delete points;
@@ -176,12 +169,12 @@ static void getGlyphMetrics(HB_Font hbFont, HB_Glyph glyph, HB_GlyphMetrics* met
SkRect bounds;
paint.getTextWidths(&glyph16, sizeof(glyph16), &width, &bounds);
- metrics->x = SkiaScalarToHarfbuzzFixed(bounds.fLeft);
- metrics->y = SkiaScalarToHarfbuzzFixed(bounds.fTop);
- metrics->width = SkiaScalarToHarfbuzzFixed(bounds.width());
- metrics->height = SkiaScalarToHarfbuzzFixed(bounds.height());
+ metrics->x = SkScalarToHBFixed(bounds.fLeft);
+ metrics->y = SkScalarToHBFixed(bounds.fTop);
+ metrics->width = SkScalarToHBFixed(bounds.width());
+ metrics->height = SkScalarToHBFixed(bounds.height());
- metrics->xOffset = SkiaScalarToHarfbuzzFixed(width);
+ metrics->xOffset = SkScalarToHBFixed(width);
// We can't actually get the |y| correct because Skia doesn't export
// the vertical advance. However, nor we do ever render vertical text at
// the moment so it's unimportant.
@@ -199,7 +192,7 @@ static HB_Fixed getFontMetric(HB_Font hbFont, HB_FontMetric metric)
switch (metric) {
case HB_FontAscent:
- return SkiaScalarToHarfbuzzFixed(-skiaMetrics.fAscent);
+ return SkScalarToHBFixed(-skiaMetrics.fAscent);
// We don't support getting the rest of the metrics and Harfbuzz doesn't seem to need them.
default:
return 0;
diff --git a/core/jni/android/graphics/HarfbuzzSkia.h b/core/jni/android/graphics/HarfbuzzSkia.h
index d057d76..99b389a 100644
--- a/core/jni/android/graphics/HarfbuzzSkia.h
+++ b/core/jni/android/graphics/HarfbuzzSkia.h
@@ -27,22 +27,38 @@
#ifndef HarfbuzzSkia_h
#define HarfbuzzSkia_h
+#include "SkScalar.h"
#include "SkTypeface.h"
+#include "SkPaint.h"
extern "C" {
#include "harfbuzz-shaper.h"
}
namespace android {
- typedef struct {
- SkTypeface* typeFace;
- float textSize;
- bool fakeBold;
- bool fakeItalic;
- } FontData;
-
- HB_Error harfbuzzSkiaGetTable(void* voidface, const HB_Tag, HB_Byte* buffer, HB_UInt* len);
- extern const HB_FontClass harfbuzzSkiaClass;
+
+static inline float HBFixedToFloat(HB_Fixed v) {
+ // Harfbuzz uses 26.6 fixed point values for pixel offsets
+ return v * (1.0f / 64);
+}
+
+static inline HB_Fixed SkScalarToHBFixed(SkScalar value) {
+ // HB_Fixed is a 26.6 fixed point format.
+ return SkScalarToFloat(value) * 64.0f;
+}
+
+typedef struct {
+ SkTypeface* typeFace;
+ SkScalar textSize;
+ SkScalar textSkewX;
+ SkScalar textScaleX;
+ uint32_t flags;
+ SkPaint::Hinting hinting;
+} FontData;
+
+HB_Error harfbuzzSkiaGetTable(void* voidface, const HB_Tag, HB_Byte* buffer, HB_UInt* len);
+extern const HB_FontClass harfbuzzSkiaClass;
+
} // namespace android
#endif
diff --git a/core/jni/android/graphics/Paint.cpp b/core/jni/android/graphics/Paint.cpp
index 5c3497f..27be871 100644
--- a/core/jni/android/graphics/Paint.cpp
+++ b/core/jni/android/graphics/Paint.cpp
@@ -414,6 +414,7 @@ public:
for (int i = 0; i < glyphCount; i++) {
glyphsArray[i] = (jchar) shaperItem.glyphs[i];
}
+ env->ReleaseCharArrayElements(glyphs, glyphsArray, JNI_ABORT);
return glyphCount;
}
@@ -442,6 +443,21 @@ public:
return totalAdvance;
}
+ static jfloat doTextRunAdvancesICU(JNIEnv *env, SkPaint *paint, const jchar *text,
+ jint start, jint count, jint contextCount, jint flags,
+ jfloatArray advances, jint advancesIndex) {
+ jfloat advancesArray[count];
+ jfloat totalAdvance;
+
+ TextLayout::getTextRunAdvancesICU(paint, text, start, count, contextCount, flags,
+ advancesArray, totalAdvance);
+
+ if (advances != NULL) {
+ env->SetFloatArrayRegion(advances, advancesIndex, count, advancesArray);
+ }
+ return totalAdvance;
+ }
+
static float getTextRunAdvances___CIIIII_FI(JNIEnv* env, jobject clazz, SkPaint* paint,
jcharArray text, jint index, jint count, jint contextIndex, jint contextCount,
jint flags, jfloatArray advances, jint advancesIndex) {
@@ -463,6 +479,27 @@ public:
return result;
}
+ static float getTextRunAdvancesICU___CIIIII_FI(JNIEnv* env, jobject clazz, SkPaint* paint,
+ jcharArray text, jint index, jint count, jint contextIndex, jint contextCount,
+ jint flags, jfloatArray advances, jint advancesIndex) {
+ jchar* textArray = env->GetCharArrayElements(text, NULL);
+ jfloat result = doTextRunAdvancesICU(env, paint, textArray + contextIndex,
+ index - contextIndex, count, contextCount, flags, advances, advancesIndex);
+ env->ReleaseCharArrayElements(text, textArray, JNI_ABORT);
+ return result;
+ }
+
+ static float getTextRunAdvancesICU__StringIIIII_FI(JNIEnv* env, jobject clazz, SkPaint* paint,
+ jstring text, jint start, jint end, jint contextStart, jint contextEnd, jint flags,
+ jfloatArray advances, jint advancesIndex) {
+ const jchar* textArray = env->GetStringChars(text, NULL);
+ jfloat result = doTextRunAdvancesICU(env, paint, textArray + contextStart,
+ start - contextStart, end - start, contextEnd - contextStart, flags, advances,
+ advancesIndex);
+ env->ReleaseStringChars(text, textArray);
+ return result;
+ }
+
static jint doTextRunCursor(JNIEnv *env, SkPaint* paint, const jchar *text, jint start,
jint count, jint flags, jint offset, jint opt) {
SkScalar scalarArray[count];
@@ -748,10 +785,14 @@ static JNINativeMethod methods[] = {
{"native_breakText","(Ljava/lang/String;ZF[F)I", (void*) SkPaintGlue::breakTextS},
{"native_getTextWidths","(I[CII[F)I", (void*) SkPaintGlue::getTextWidths___CII_F},
{"native_getTextWidths","(ILjava/lang/String;II[F)I", (void*) SkPaintGlue::getTextWidths__StringII_F},
- {"native_getTextRunAdvances","(I[CIIIII[FI)F", (void*)
- SkPaintGlue::getTextRunAdvances___CIIIII_FI},
+ {"native_getTextRunAdvances","(I[CIIIII[FI)F",
+ (void*) SkPaintGlue::getTextRunAdvances___CIIIII_FI},
{"native_getTextRunAdvances","(ILjava/lang/String;IIIII[FI)F",
(void*) SkPaintGlue::getTextRunAdvances__StringIIIII_FI},
+ {"native_getTextRunAdvancesICU","(I[CIIIII[FI)F",
+ (void*) SkPaintGlue::getTextRunAdvancesICU___CIIIII_FI},
+ {"native_getTextRunAdvancesICU","(ILjava/lang/String;IIIII[FI)F",
+ (void*) SkPaintGlue::getTextRunAdvancesICU__StringIIIII_FI},
{"native_getTextGlyphs","(ILjava/lang/String;IIIII[C)I",
(void*) SkPaintGlue::getTextGlyphs__StringIIIII_C},
{"native_getTextRunCursor", "(I[CIIIII)I", (void*) SkPaintGlue::getTextRunCursor___C},
diff --git a/core/jni/android/graphics/RtlProperties.h b/core/jni/android/graphics/RtlProperties.h
index 2c68fa3..f41f4a1 100644
--- a/core/jni/android/graphics/RtlProperties.h
+++ b/core/jni/android/graphics/RtlProperties.h
@@ -45,7 +45,12 @@ static RtlDebugLevel readRtlDebugLevel() {
return kRtlDebugDisabled;
}
+// Define if we want to use Harfbuzz (1) or not (0)
#define RTL_USE_HARFBUZZ 1
+// Define if we want (1) to have Advances debug values or not (0)
+#define DEBUG_ADVANCES 0
+
+
} // namespace android
#endif // ANDROID_RTL_PROPERTIES_H
diff --git a/core/jni/android/graphics/TextLayout.cpp b/core/jni/android/graphics/TextLayout.cpp
index f1bb696..434f63b 100644
--- a/core/jni/android/graphics/TextLayout.cpp
+++ b/core/jni/android/graphics/TextLayout.cpp
@@ -269,6 +269,21 @@ void TextLayout::getTextRunAdvances(SkPaint* paint, const jchar* chars, jint sta
#endif
}
+void TextLayout::getTextRunAdvancesHB(SkPaint* paint, const jchar* chars, jint start,
+ jint count, jint contextCount, jint dirFlags,
+ jfloat* resultAdvances, jfloat& resultTotalAdvance) {
+ // Compute advances and return them
+ RunAdvanceDescription::computeAdvancesWithHarfbuzz(paint, chars, start, count, contextCount, dirFlags,
+ resultAdvances, &resultTotalAdvance);
+}
+
+void TextLayout::getTextRunAdvancesICU(SkPaint* paint, const jchar* chars, jint start,
+ jint count, jint contextCount, jint dirFlags,
+ jfloat* resultAdvances, jfloat& resultTotalAdvance) {
+ // Compute advances and return them
+ RunAdvanceDescription::computeAdvancesWithICU(paint, chars, start, count, contextCount, dirFlags,
+ resultAdvances, &resultTotalAdvance);
+}
// Draws a paragraph of text on a single line, running bidi and shaping
void TextLayout::drawText(SkPaint* paint, const jchar* text, jsize len,
diff --git a/core/jni/android/graphics/TextLayout.h b/core/jni/android/graphics/TextLayout.h
index a950d13..138983c 100644
--- a/core/jni/android/graphics/TextLayout.h
+++ b/core/jni/android/graphics/TextLayout.h
@@ -73,6 +73,14 @@ public:
jint count, jint contextCount, jint dirFlags,
jfloat* resultAdvances, jfloat& resultTotalAdvance);
+ static void getTextRunAdvancesICU(SkPaint* paint, const jchar* chars, jint start,
+ jint count, jint contextCount, jint dirFlags,
+ jfloat* resultAdvances, jfloat& resultTotalAdvance);
+
+ static void getTextRunAdvancesHB(SkPaint* paint, const jchar* chars, jint start,
+ jint count, jint contextCount, jint dirFlags,
+ jfloat* resultAdvances, jfloat& resultTotalAdvance);
+
static void drawText(SkPaint* paint, const jchar* text, jsize len,
jint bidiFlags, jfloat x, jfloat y, SkCanvas* canvas);
diff --git a/core/jni/android/graphics/TextLayoutCache.h b/core/jni/android/graphics/TextLayoutCache.h
index 925bb7c..31d802c 100644
--- a/core/jni/android/graphics/TextLayoutCache.h
+++ b/core/jni/android/graphics/TextLayoutCache.h
@@ -19,17 +19,20 @@
#include "RtlProperties.h"
-#include "stddef.h"
+#include <stddef.h>
#include <utils/threads.h>
#include <utils/String16.h>
-#include "utils/GenerationCache.h"
-#include "utils/Compare.h"
+#include <utils/GenerationCache.h>
+#include <utils/Compare.h>
-#include "SkPaint.h"
-#include "SkTemplates.h"
+#include <SkPaint.h>
+#include <SkTemplates.h>
+#include <SkUtils.h>
+#include <SkScalerContext.h>
+#include <SkAutoKern.h>
-#include "unicode/ubidi.h"
-#include "unicode/ushape.h"
+#include <unicode/ubidi.h>
+#include <unicode/ushape.h>
#include "HarfbuzzSkia.h"
#include "harfbuzz-shaper.h"
@@ -54,14 +57,8 @@
// Define the interval in number of cache hits between two statistics dump
#define DEFAULT_DUMP_STATS_CACHE_HIT_INTERVAL 100
-// Define if we want to have Advances debug values
-#define DEBUG_ADVANCES 0
-
namespace android {
-// Harfbuzz uses 26.6 fixed point values for pixel offsets
-#define HB_FIXED_TO_FLOAT(v) (((float) v) * (1.0 / 64))
-
/**
* TextLayoutCacheKey is the Cache key
*/
@@ -202,6 +199,8 @@ public:
shaperItem->font = font;
shaperItem->face = HB_NewFace(shaperItem->font, harfbuzzSkiaGetTable);
+ shaperItem->kerning_applied = false;
+
// We cannot know, ahead of time, how many glyphs a given script run
// will produce. We take a guess that script runs will not produce more
// than twice as many glyphs as there are code points plus a bit of
@@ -222,10 +221,12 @@ public:
shaperItem->string = chars;
shaperItem->stringLength = contextCount;
- fontData->textSize = paint->getTextSize();
- fontData->fakeBold = paint->isFakeBoldText();
- fontData->fakeItalic = (paint->getTextSkewX() > 0);
fontData->typeFace = paint->getTypeface();
+ fontData->textSize = paint->getTextSize();
+ fontData->textSkewX = paint->getTextSkewX();
+ fontData->textScaleX = paint->getTextScaleX();
+ fontData->flags = paint->getFlags();
+ fontData->hinting = paint->getHinting();
shaperItem->font->userData = fontData;
}
@@ -248,6 +249,21 @@ public:
}
}
+#define SkAutoKern_AdjustF(prev, next) (((next) - (prev) + 32) >> 6 << 16)
+
+ static int adjust(int prev, int next) {
+ int delta = next - prev;
+ if (delta >= 32) {
+ return -1;
+ }
+ else if (delta < -32) {
+ return +1;
+ }
+ else {
+ return 0;
+ }
+ }
+
static void computeAdvancesWithHarfbuzz(SkPaint* paint, const UChar* chars, size_t start,
size_t count, size_t contextCount, int dirFlags,
jfloat* outAdvances, jfloat* outTotalAdvance) {
@@ -261,13 +277,15 @@ public:
contextCount, dirFlags);
#if DEBUG_ADVANCES
- LOGD("HARFBUZZ -- num_glypth=%d", shaperItem.num_glyphs);
+ LOGD("HARFBUZZ -- num_glypth=%d - kerning_applied=%d", shaperItem.num_glyphs, shaperItem.kerning_applied);
+ LOGD(" -- string= '%s'", String8(chars, contextCount).string());
+ LOGD(" -- isDevKernText=%d", paint->isDevKernText());
#endif
jfloat totalAdvance = 0;
+
for (size_t i = 0; i < count; i++) {
- // Be careful: we need to use ceilf() for doing the same way as what Skia is doing
- totalAdvance += outAdvances[i] = ceilf(HB_FIXED_TO_FLOAT(shaperItem.advances[i]));
+ totalAdvance += outAdvances[i] = HBFixedToFloat(shaperItem.advances[i]);
#if DEBUG_ADVANCES
LOGD("hb-adv = %d - rebased = %f - total = %f", shaperItem.advances[i], outAdvances[i],
diff --git a/graphics/java/android/graphics/Paint.java b/graphics/java/android/graphics/Paint.java
index 96eb936..0949beb 100644
--- a/graphics/java/android/graphics/Paint.java
+++ b/graphics/java/android/graphics/Paint.java
@@ -1534,6 +1534,48 @@ public class Paint {
}
/**
+ * Convenience overload that takes a char array instead of a
+ * String.
+ *
+ * @see #getTextRunAdvances(String, int, int, int, int, int, float[], int)
+ * @hide
+ */
+ public float getTextRunAdvancesICU(char[] chars, int index, int count,
+ int contextIndex, int contextCount, int flags, float[] advances,
+ int advancesIndex) {
+
+ if ((index | count | contextIndex | contextCount | advancesIndex
+ | (index - contextIndex)
+ | ((contextIndex + contextCount) - (index + count))
+ | (chars.length - (contextIndex + contextCount))
+ | (advances == null ? 0 :
+ (advances.length - (advancesIndex + count)))) < 0) {
+ throw new IndexOutOfBoundsException();
+ }
+ if (flags != DIRECTION_LTR && flags != DIRECTION_RTL) {
+ throw new IllegalArgumentException("unknown flags value: " + flags);
+ }
+
+ if (!mHasCompatScaling) {
+ return native_getTextRunAdvancesICU(mNativePaint, chars, index, count,
+ contextIndex, contextCount, flags, advances, advancesIndex);
+ }
+
+ final float oldSize = getTextSize();
+ setTextSize(oldSize * mCompatScaling);
+ float res = native_getTextRunAdvancesICU(mNativePaint, chars, index, count,
+ contextIndex, contextCount, flags, advances, advancesIndex);
+ setTextSize(oldSize);
+
+ if (advances != null) {
+ for (int i = advancesIndex, e = i + count; i < e; i++) {
+ advances[i] *= mInvCompatScaling;
+ }
+ }
+ return res * mInvCompatScaling; // assume errors are not significant
+ }
+
+ /**
* Convenience overload that takes a CharSequence instead of a
* String.
*
@@ -1569,6 +1611,41 @@ public class Paint {
}
/**
+ * Convenience overload that takes a CharSequence instead of a
+ * String.
+ *
+ * @see #getTextRunAdvances(String, int, int, int, int, int, float[], int)
+ * @hide
+ */
+ public float getTextRunAdvancesICU(CharSequence text, int start, int end,
+ int contextStart, int contextEnd, int flags, float[] advances,
+ int advancesIndex) {
+
+ if (text instanceof String) {
+ return getTextRunAdvancesICU((String) text, start, end,
+ contextStart, contextEnd, flags, advances, advancesIndex);
+ }
+ if (text instanceof SpannedString ||
+ text instanceof SpannableString) {
+ return getTextRunAdvancesICU(text.toString(), start, end,
+ contextStart, contextEnd, flags, advances, advancesIndex);
+ }
+ if (text instanceof GraphicsOperations) {
+ return ((GraphicsOperations) text).getTextRunAdvancesICU(start, end,
+ contextStart, contextEnd, flags, advances, advancesIndex, this);
+ }
+
+ int contextLen = contextEnd - contextStart;
+ int len = end - start;
+ char[] buf = TemporaryBuffer.obtain(contextLen);
+ TextUtils.getChars(text, start, end, buf, 0);
+ float result = getTextRunAdvancesICU(buf, start - contextStart, len,
+ 0, contextLen, flags, advances, advancesIndex);
+ TemporaryBuffer.recycle(buf);
+ return result;
+ }
+
+ /**
* Returns the total advance width for the characters in the run
* between start and end, and if advances is not null, the advance
* assigned to each of these characters (java chars).
@@ -1644,6 +1721,44 @@ public class Paint {
}
/**
+ * Temporary - DO NOT USE
+ *
+ * @hide
+ */
+ public float getTextRunAdvancesICU(String text, int start, int end, int contextStart,
+ int contextEnd, int flags, float[] advances, int advancesIndex) {
+
+ if ((start | end | contextStart | contextEnd | advancesIndex | (end - start)
+ | (start - contextStart) | (contextEnd - end)
+ | (text.length() - contextEnd)
+ | (advances == null ? 0 :
+ (advances.length - advancesIndex - (end - start)))) < 0) {
+ throw new IndexOutOfBoundsException();
+ }
+ if (flags != DIRECTION_LTR && flags != DIRECTION_RTL) {
+ throw new IllegalArgumentException("unknown flags value: " + flags);
+ }
+
+ if (!mHasCompatScaling) {
+ return native_getTextRunAdvancesICU(mNativePaint, text, start, end,
+ contextStart, contextEnd, flags, advances, advancesIndex);
+ }
+
+ final float oldSize = getTextSize();
+ setTextSize(oldSize * mCompatScaling);
+ float totalAdvance = native_getTextRunAdvances(mNativePaint, text, start, end,
+ contextStart, contextEnd, flags, advances, advancesIndex);
+ setTextSize(oldSize);
+
+ if (advances != null) {
+ for (int i = advancesIndex, e = i + (end - start); i < e; i++) {
+ advances[i] *= mInvCompatScaling;
+ }
+ }
+ return totalAdvance * mInvCompatScaling; // assume errors are insignificant
+ }
+
+ /**
* Returns the next cursor position in the run. This avoids placing the
* cursor between surrogates, between characters that form conjuncts,
* between base characters and combining marks, or within a reordering
@@ -1907,6 +2022,13 @@ public class Paint {
String text, int start, int end, int contextStart, int contextEnd,
int flags, float[] advances, int advancesIndex);
+ private static native float native_getTextRunAdvancesICU(int native_object,
+ char[] text, int index, int count, int contextIndex, int contextCount,
+ int flags, float[] advances, int advancesIndex);
+ private static native float native_getTextRunAdvancesICU(int native_object,
+ String text, int start, int end, int contextStart, int contextEnd,
+ int flags, float[] advances, int advancesIndex);
+
private native int native_getTextRunCursor(int native_object, char[] text,
int contextStart, int contextLength, int flags, int offset, int cursorOpt);
private native int native_getTextRunCursor(int native_object, String text,
diff --git a/tests/BiDiTests/res/layout/biditest_main.xml b/tests/BiDiTests/res/layout/biditest_main.xml
index 9f77ad2..087c9a3 100644
--- a/tests/BiDiTests/res/layout/biditest_main.xml
+++ b/tests/BiDiTests/res/layout/biditest_main.xml
@@ -48,6 +48,11 @@
</LinearLayout>
+ <SeekBar android:id="@+id/seekbar"
+ android:layout_height="wrap_content"
+ android:layout_width="match_parent"
+ />
+
<view class="com.android.bidi.BiDiTestView"
android:id="@+id/main"
android:layout_width="match_parent"
diff --git a/tests/BiDiTests/res/values/strings.xml b/tests/BiDiTests/res/values/strings.xml
index ecff76e..632a02e 100644
--- a/tests/BiDiTests/res/values/strings.xml
+++ b/tests/BiDiTests/res/values/strings.xml
@@ -18,9 +18,11 @@
<string name="edittext_text">mmmmmmmmmmmmmmmmmmmmmmmm</string>
<string name="normal_text">Normal String</string>
<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">&#x0644;&#x0627;</string>
<string name="chinese_text">利比亚局势或影响美俄关系发展</string>
<string name="italic_text">Italic String</string>
- <string name="bold_text">Bold String</string>
+ <string name="bold_text">Bold String - other text</string>
<string name="bold_italic_text">Bold Italic String</string>
</resources> \ No newline at end of file
diff --git a/tests/BiDiTests/src/com/android/bidi/BiDiTestActivity.java b/tests/BiDiTests/src/com/android/bidi/BiDiTestActivity.java
index 3d7dd81..6c71574 100644
--- a/tests/BiDiTests/src/com/android/bidi/BiDiTestActivity.java
+++ b/tests/BiDiTests/src/com/android/bidi/BiDiTestActivity.java
@@ -20,16 +20,44 @@ import android.app.Activity;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
+import android.widget.SeekBar;
+
+import static com.android.bidi.BiDiTestConstants.FONT_MIN_SIZE;
+import static com.android.bidi.BiDiTestConstants.FONT_MAX_SIZE;
public class BiDiTestActivity extends Activity {
static final String TAG = "BiDiTestActivity";
+ static final int INIT_TEXT_SIZE = (FONT_MAX_SIZE - FONT_MIN_SIZE) / 2;
+
+ private BiDiTestView textView;
+ private SeekBar textSizeSeekBar;
+
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.biditest_main);
+
+ textView = (BiDiTestView) findViewById(R.id.main);
+ textView.setCurrentTextSize(INIT_TEXT_SIZE);
+
+ textSizeSeekBar = (SeekBar) findViewById(R.id.seekbar);
+ textSizeSeekBar.setProgress(INIT_TEXT_SIZE);
+ textSizeSeekBar.setMax(FONT_MAX_SIZE - FONT_MIN_SIZE);
+
+ textSizeSeekBar.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() {
+ public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {
+ textView.setCurrentTextSize(FONT_MIN_SIZE + progress);
+ }
+
+ public void onStartTrackingTouch(SeekBar seekBar) {
+ }
+
+ public void onStopTrackingTouch(SeekBar seekBar) {
+ }
+ });
}
@Override
diff --git a/tests/BiDiTests/src/com/android/bidi/BiDiTestConstants.java b/tests/BiDiTests/src/com/android/bidi/BiDiTestConstants.java
new file mode 100644
index 0000000..5c28e3d
--- /dev/null
+++ b/tests/BiDiTests/src/com/android/bidi/BiDiTestConstants.java
@@ -0,0 +1,22 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.bidi;
+
+public class BiDiTestConstants {
+ public static final int FONT_MIN_SIZE = 8;
+ public static final int FONT_MAX_SIZE = 72;
+}
diff --git a/tests/BiDiTests/src/com/android/bidi/BiDiTestView.java b/tests/BiDiTests/src/com/android/bidi/BiDiTestView.java
index e9b6fa6..cd415c2 100644
--- a/tests/BiDiTests/src/com/android/bidi/BiDiTestView.java
+++ b/tests/BiDiTests/src/com/android/bidi/BiDiTestView.java
@@ -32,9 +32,8 @@ public class BiDiTestView extends View {
private static final int BORDER_PADDING = 4;
private static final int TEXT_PADDING = 16;
- private static final int TEXT_SIZE = 32;
- private static final int ORIGIN = 48;
- private static final int DELTA_Y = TEXT_SIZE;
+ private static final int TEXT_SIZE = 16;
+ private static final int ORIGIN = 80;
private static final float DEFAULT_ITALIC_SKEW_X = -0.25f;
@@ -43,6 +42,8 @@ public class BiDiTestView extends View {
private String NORMAL_TEXT;
private String NORMAL_LONG_TEXT;
+ private String NORMAL_LONG_TEXT_2;
+ private String NORMAL_LONG_TEXT_3;
private String ITALIC_TEXT;
private String BOLD_TEXT;
private String BOLD_ITALIC_TEXT;
@@ -51,6 +52,8 @@ public class BiDiTestView extends View {
private Typeface typeface;
+ private int currentTextSize;
+
public BiDiTestView(Context context) {
super(context);
init(context);
@@ -69,6 +72,8 @@ public class BiDiTestView extends View {
private void init(Context context) {
NORMAL_TEXT = context.getString(R.string.normal_text);
NORMAL_LONG_TEXT = context.getString(R.string.normal_long_text);
+ NORMAL_LONG_TEXT_2 = context.getString(R.string.normal_long_text_2);
+ NORMAL_LONG_TEXT_3 = context.getString(R.string.normal_long_text_3);
ITALIC_TEXT = context.getString(R.string.italic_text);
BOLD_TEXT = context.getString(R.string.bold_text);
BOLD_ITALIC_TEXT = context.getString(R.string.bold_italic_text);
@@ -79,34 +84,50 @@ public class BiDiTestView extends View {
paint.setAntiAlias(true);
}
+ public void setCurrentTextSize(int size) {
+ currentTextSize = size;
+ invalidate();
+ }
+
@Override
public void onDraw(Canvas canvas) {
drawInsideRect(canvas, Color.BLACK);
- int deltaX = testString(canvas, NORMAL_TEXT, ORIGIN, ORIGIN, paint, typeface,
- false, false, Paint.DIRECTION_LTR);
- deltaX += testString(canvas, ITALIC_TEXT, ORIGIN + deltaX, ORIGIN, paint, typeface,
- true, false, Paint.DIRECTION_LTR);
- deltaX += testString(canvas, BOLD_TEXT, ORIGIN + deltaX, ORIGIN, paint, typeface,
- false, true, Paint.DIRECTION_LTR);
- deltaX += testString(canvas, BOLD_ITALIC_TEXT, ORIGIN + deltaX, ORIGIN, paint, typeface,
- true, true, Paint.DIRECTION_LTR);
+ int deltaX = testString(canvas, NORMAL_TEXT, ORIGIN, ORIGIN,
+ paint, typeface, false, false, Paint.DIRECTION_LTR, currentTextSize);
+
+ deltaX += testString(canvas, ITALIC_TEXT, ORIGIN + deltaX, ORIGIN,
+ paint, typeface, true, false, Paint.DIRECTION_LTR, currentTextSize);
+
+ deltaX += testString(canvas, BOLD_TEXT, ORIGIN + deltaX, ORIGIN,
+ paint, typeface, false, true, Paint.DIRECTION_LTR, currentTextSize);
+
+ deltaX += testString(canvas, BOLD_ITALIC_TEXT, ORIGIN + deltaX, ORIGIN,
+ paint, typeface, true, true, Paint.DIRECTION_LTR, currentTextSize);
// Test with a long string
- deltaX = testString(canvas, NORMAL_LONG_TEXT, ORIGIN, ORIGIN + 2 * DELTA_Y, paint, typeface,
- false, false, Paint.DIRECTION_LTR);
+ deltaX = testString(canvas, NORMAL_LONG_TEXT, ORIGIN, ORIGIN + 2 * currentTextSize,
+ paint, typeface, false, false, Paint.DIRECTION_LTR, currentTextSize);
+
+ // Test with a long string
+ deltaX = testString(canvas, NORMAL_LONG_TEXT_2, ORIGIN, ORIGIN + 4 * currentTextSize,
+ paint, typeface, false, false, Paint.DIRECTION_LTR, currentTextSize);
+
+ // Test with a long string
+ deltaX = testString(canvas, NORMAL_LONG_TEXT_3, ORIGIN, ORIGIN + 6 * currentTextSize,
+ paint, typeface, false, false, Paint.DIRECTION_LTR, currentTextSize);
// Test Arabic ligature
- deltaX = testString(canvas, ARABIC_TEXT, ORIGIN, ORIGIN + 4 * DELTA_Y, paint, typeface,
- false, false, Paint.DIRECTION_RTL);
+ deltaX = testString(canvas, ARABIC_TEXT, ORIGIN, ORIGIN + 8 * currentTextSize,
+ paint, typeface, false, false, Paint.DIRECTION_RTL, currentTextSize);
// Test Chinese
- deltaX = testString(canvas, CHINESE_TEXT, ORIGIN, ORIGIN + 6 * DELTA_Y, paint, typeface,
- false, false, Paint.DIRECTION_LTR);
+ deltaX = testString(canvas, CHINESE_TEXT, ORIGIN, ORIGIN + 10 * currentTextSize,
+ paint, typeface, false, false, Paint.DIRECTION_LTR, currentTextSize);
}
private int testString(Canvas canvas, String text, int x, int y, Paint paint, Typeface typeface,
- boolean isItalic, boolean isBold, int dir) {
+ boolean isItalic, boolean isBold, int dir, int textSize) {
paint.setTypeface(typeface);
// Set paint properties
@@ -118,27 +139,28 @@ public class BiDiTestView extends View {
paint.setTextSkewX(DEFAULT_ITALIC_SKEW_X);
}
- drawTextWithCanvasDrawText(text, canvas, x, y, TEXT_SIZE, Color.WHITE);
+ drawTextWithCanvasDrawText(text, canvas, x, y, textSize, Color.WHITE);
int length = text.length();
float[] advances = new float[length];
- float textWidth = paint.getTextRunAdvances(text, 0, length, 0, length, 0, advances, 0);
+ float textWidthHB = paint.getTextRunAdvances(text, 0, length, 0, length, 0, advances, 0);
+ float textWidthICU = paint.getTextRunAdvancesICU(text, 0, length, 0, length, 0, advances, 0);
- logAdvances(text, textWidth, advances);
- drawBoxAroundText(canvas, x, y, textWidth, TEXT_SIZE, Color.RED);
+ logAdvances(text, textWidthHB, textWidthICU, advances);
+ drawMetricsAroundText(canvas, x, y, textWidthHB, textWidthICU, textSize, Color.RED, Color.GREEN);
paint.setColor(Color.WHITE);
char[] glyphs = new char[2*length];
int count = getGlyphs(text, glyphs, dir);
- logGlypths(glyphs, count);
- drawTextWithDrawGlyph(canvas, glyphs, count, x, y + DELTA_Y);
+// logGlypths(glyphs, count);
+ drawTextWithDrawGlyph(canvas, glyphs, count, x, y + currentTextSize);
// Restore old paint properties
paint.setFakeBoldText(oldFakeBold);
paint.setTextSkewX(oldTextSkewX);
- return (int) Math.ceil(textWidth) + TEXT_PADDING;
+ return (int) Math.ceil(textWidthHB) + TEXT_PADDING;
}
private void drawTextWithDrawGlyph(Canvas canvas, char[] glyphs, int count, int x, int y) {
@@ -172,19 +194,21 @@ public class BiDiTestView extends View {
canvas.drawText(text, x, y, paint);
}
- private void drawBoxAroundText(Canvas canvas, int x, int y, float textWidth, int textSize,
- int color) {
+ private void drawMetricsAroundText(Canvas canvas, int x, int y, float textWidthHB,
+ float textWidthICU, int textSize, int color, int colorICU) {
paint.setColor(color);
canvas.drawLine(x, y - textSize, x, y + 8, paint);
- canvas.drawLine(x, y + 8, x + textWidth, y + 8, paint);
- canvas.drawLine(x + textWidth, y - textSize, x + textWidth, y + 8, paint);
+ canvas.drawLine(x, y + 8, x + textWidthHB, y + 8, paint);
+ canvas.drawLine(x + textWidthHB, y - textSize, x + textWidthHB, y + 8, paint);
+ paint.setColor(colorICU);
+ canvas.drawLine(x + textWidthICU, y - textSize, x + textWidthICU, y + 8, paint);
}
- private void logAdvances(String text, float textWidth, float[] advances) {
- Log.v(TAG, "Advances for text: " + text + " total=" + textWidth);
- int length = advances.length;
- for(int n=0; n<length; n++){
- Log.v(TAG, "adv[" + n + "]=" + advances[n]);
- }
+ private void logAdvances(String text, float textWidth, float textWidthICU, float[] advances) {
+ Log.v(TAG, "Advances for text: " + text + " total= " + textWidth + " - totalICU= " + textWidthICU);
+// int length = advances.length;
+// for(int n=0; n<length; n++){
+// Log.v(TAG, "adv[" + n + "]=" + advances[n]);
+// }
}
}