Merge "Fix bug #8437358 Clean any ICU related code from TextLayout / Paint and their dependencies" into jb-mr2-dev

This commit is contained in:
Fabrice Di Meglio
2013-03-20 22:26:57 +00:00
committed by Android (Google) Code Review
11 changed files with 22 additions and 588 deletions

View File

@@ -57,13 +57,6 @@ extends CharSequence
float getTextRunAdvances(int start, int end, int contextStart, int contextEnd,
int flags, float[] advances, int advancesIndex, Paint paint);
/**
* Just like {@link Paint#getTextRunAdvances}.
* @hide
*/
float getTextRunAdvances(int start, int end, int contextStart, int contextEnd,
int flags, float[] advances, int advancesIndex, Paint paint, int reserved);
/**
* Just like {@link Paint#getTextRunCursor}.
* @hide

View File

@@ -1225,35 +1225,6 @@ public class SpannableStringBuilder implements CharSequence, GetChars, Spannable
return ret;
}
/**
* Don't call this yourself -- exists for Paint to use internally.
* {@hide}
*/
public float getTextRunAdvances(int start, int end, int contextStart, int contextEnd, int flags,
float[] advances, int advancesPos, Paint p, int reserved) {
float ret;
int contextLen = contextEnd - contextStart;
int len = end - start;
if (end <= mGapStart) {
ret = p.getTextRunAdvances(mText, start, len, contextStart, contextLen,
flags, advances, advancesPos, reserved);
} else if (start >= mGapStart) {
ret = p.getTextRunAdvances(mText, start + mGapLength, len,
contextStart + mGapLength, contextLen, flags, advances, advancesPos, reserved);
} else {
char[] buf = TextUtils.obtain(contextLen);
getChars(contextStart, contextEnd, buf, 0);
ret = p.getTextRunAdvances(buf, start - contextStart, len,
0, contextLen, flags, advances, advancesPos, reserved);
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

View File

@@ -8881,16 +8881,6 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
advancesIndex);
}
public float getTextRunAdvances(int start, int end, int contextStart,
int contextEnd, int flags, float[] advances, int advancesIndex,
Paint p, int reserved) {
int count = end - start;
int contextCount = contextEnd - contextStart;
return p.getTextRunAdvances(mChars, start + mStart, count,
contextStart + mStart, contextCount, flags, advances,
advancesIndex, reserved);
}
public int getTextRunCursor(int contextStart, int contextEnd, int flags,
int offset, int cursorOpt, Paint p) {
int contextCount = contextEnd - contextStart;

View File

@@ -566,61 +566,23 @@ 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) {
NPE_CHECK_RETURN_ZERO(env, paint);
NPE_CHECK_RETURN_ZERO(env, text);
if ((start | count | contextCount | advancesIndex) < 0 || contextCount < count) {
doThrowAIOOBE(env);
return 0;
}
if (count == 0) {
return 0;
}
if (advances) {
size_t advancesLength = env->GetArrayLength(advances);
if ((size_t)count > advancesLength) {
doThrowAIOOBE(env);
return 0;
}
}
jfloat advancesArray[count];
jfloat totalAdvance = 0;
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_FII(JNIEnv* env, jobject clazz, SkPaint* paint,
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, jint reserved) {
jint flags, jfloatArray advances, jint advancesIndex) {
jchar* textArray = env->GetCharArrayElements(text, NULL);
jfloat result = (reserved == 0) ?
doTextRunAdvances(env, paint, textArray + contextIndex, index - contextIndex,
count, contextCount, flags, advances, advancesIndex) :
doTextRunAdvancesICU(env, paint, textArray + contextIndex, index - contextIndex,
count, contextCount, flags, advances, advancesIndex);
jfloat result = doTextRunAdvances(env, paint, textArray + contextIndex,
index - contextIndex, count, contextCount, flags, advances, advancesIndex);
env->ReleaseCharArrayElements(text, textArray, JNI_ABORT);
return result;
}
static float getTextRunAdvances__StringIIIII_FII(JNIEnv* env, jobject clazz, SkPaint* paint,
static float getTextRunAdvances__StringIIIII_FI(JNIEnv* env, jobject clazz, SkPaint* paint,
jstring text, jint start, jint end, jint contextStart, jint contextEnd, jint flags,
jfloatArray advances, jint advancesIndex, jint reserved) {
jfloatArray advances, jint advancesIndex) {
const jchar* textArray = env->GetStringChars(text, NULL);
jfloat result = (reserved == 0) ?
doTextRunAdvances(env, paint, textArray + contextStart, start - contextStart,
end - start, contextEnd - contextStart, flags, advances, advancesIndex) :
doTextRunAdvancesICU(env, paint, textArray + contextStart, start - contextStart,
end - start, contextEnd - contextStart, flags, advances, advancesIndex);
jfloat result = doTextRunAdvances(env, paint, textArray + contextStart,
start - contextStart, end - start, contextEnd - contextStart, flags,
advances, advancesIndex);
env->ReleaseStringChars(text, textArray);
return result;
}
@@ -886,10 +848,10 @@ 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[FII)F",
(void*) SkPaintGlue::getTextRunAdvances___CIIIII_FII},
{"native_getTextRunAdvances","(ILjava/lang/String;IIIII[FII)F",
(void*) SkPaintGlue::getTextRunAdvances__StringIIIII_FII},
{"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_getTextGlyphs","(ILjava/lang/String;IIIII[C)I",

View File

@@ -80,14 +80,6 @@ void TextLayout::getTextRunAdvances(SkPaint* paint, const jchar* chars, jint sta
}
}
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
computeAdvancesWithICU(paint, chars, start, count, contextCount, dirFlags,
resultAdvances, &resultTotalAdvance);
}
void TextLayout::getTextPath(SkPaint *paint, const jchar *text, jsize len,
jint bidiFlags, jfloat x, jfloat y, SkPath *path) {
handleText(paint, text, len, bidiFlags, x, y, path);
@@ -111,73 +103,4 @@ void TextLayout::drawTextOnPath(SkPaint* paint, const jchar* text, int count,
canvas->drawTextOnPathHV(value->getGlyphs(), value->getGlyphsCount() * 2, *path, h_, v_, *paint);
}
void TextLayout::computeAdvancesWithICU(SkPaint* paint, const UChar* chars,
size_t start, size_t count, size_t contextCount, int dirFlags,
jfloat* outAdvances, jfloat* outTotalAdvance) {
SkAutoSTMalloc<CHAR_BUFFER_SIZE, jchar> tempBuffer(contextCount);
jchar* buffer = tempBuffer.get();
SkScalar* scalarArray = (SkScalar*)outAdvances;
// this is where we'd call harfbuzz
// for now we just use ushape.c
size_t widths;
const jchar* text;
if (dirFlags & 0x1) { // rtl, call arabic shaping in case
UErrorCode status = U_ZERO_ERROR;
// Use fixed length since we need to keep start and count valid
u_shapeArabic(chars, 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);
// we shouldn't fail unless there's an out of memory condition,
// in which case we're hosed anyway
for (int i = start, e = i + count; i < e; ++i) {
if (buffer[i] == UNICODE_NOT_A_CHAR) {
buffer[i] = UNICODE_ZWSP; // zero-width-space for skia
}
}
text = buffer + start;
widths = paint->getTextWidths(text, count << 1, scalarArray);
} else {
text = chars + start;
widths = paint->getTextWidths(text, count << 1, scalarArray);
}
jfloat totalAdvance = 0;
if (widths < count) {
#if DEBUG_ADVANCES
ALOGD("ICU -- count=%d", widths);
#endif
// Skia operates on code points, not code units, so surrogate pairs return only
// one value. Expand the result so we have one value per UTF-16 code unit.
// Note, skia's getTextWidth gets confused if it encounters a surrogate pair,
// leaving the remaining widths zero. Not nice.
for (size_t i = 0, p = 0; i < widths; ++i) {
totalAdvance += outAdvances[p++] = SkScalarToFloat(scalarArray[i]);
if (p < count &&
text[p] >= UNICODE_FIRST_LOW_SURROGATE &&
text[p] < UNICODE_FIRST_PRIVATE_USE &&
text[p-1] >= UNICODE_FIRST_HIGH_SURROGATE &&
text[p-1] < UNICODE_FIRST_LOW_SURROGATE) {
outAdvances[p++] = 0;
}
#if DEBUG_ADVANCES
ALOGD("icu-adv = %f - total = %f", outAdvances[i], totalAdvance);
#endif
}
} else {
#if DEBUG_ADVANCES
ALOGD("ICU -- count=%d", count);
#endif
for (size_t i = 0; i < count; i++) {
totalAdvance += outAdvances[i] = SkScalarToFloat(scalarArray[i]);
#if DEBUG_ADVANCES
ALOGD("icu-adv = %f - total = %f", outAdvances[i], totalAdvance);
#endif
}
}
*outTotalAdvance = totalAdvance;
}
}

View File

@@ -66,10 +66,6 @@ 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 getTextPath(SkPaint* paint, const jchar* text, jsize len,
jint bidiFlags, jfloat x, jfloat y, SkPath* path);
@@ -82,9 +78,5 @@ private:
static void handleText(SkPaint* paint, const jchar* text, jsize len,
int bidiFlags, jfloat x, jfloat y, SkPath* path);
static void computeAdvancesWithICU(SkPaint* paint, const UChar* chars,
size_t start, size_t count, size_t contextCount, int dirFlags,
jfloat* outAdvances, jfloat* outTotalAdvance);
};
} // namespace android

View File

@@ -1717,20 +1717,6 @@ public class Paint {
public float getTextRunAdvances(char[] chars, int index, int count,
int contextIndex, int contextCount, int flags, float[] advances,
int advancesIndex) {
return getTextRunAdvances(chars, index, count, contextIndex, contextCount, flags,
advances, advancesIndex, 0 /* use Harfbuzz*/);
}
/**
* Convenience overload that takes a char array instead of a
* String.
*
* @see #getTextRunAdvances(String, int, int, int, int, int, float[], int, int)
* @hide
*/
public float getTextRunAdvances(char[] chars, int index, int count,
int contextIndex, int contextCount, int flags, float[] advances,
int advancesIndex, int reserved) {
if (chars == null) {
throw new IllegalArgumentException("text cannot be null");
@@ -1752,13 +1738,13 @@ public class Paint {
}
if (!mHasCompatScaling) {
return native_getTextRunAdvances(mNativePaint, chars, index, count,
contextIndex, contextCount, flags, advances, advancesIndex, reserved);
contextIndex, contextCount, flags, advances, advancesIndex);
}
final float oldSize = getTextSize();
setTextSize(oldSize * mCompatScaling);
float res = native_getTextRunAdvances(mNativePaint, chars, index, count,
contextIndex, contextCount, flags, advances, advancesIndex, reserved);
contextIndex, contextCount, flags, advances, advancesIndex);
setTextSize(oldSize);
if (advances != null) {
@@ -1779,20 +1765,6 @@ public class Paint {
public float getTextRunAdvances(CharSequence text, int start, int end,
int contextStart, int contextEnd, int flags, float[] advances,
int advancesIndex) {
return getTextRunAdvances(text, start, end, contextStart, contextEnd, flags,
advances, advancesIndex, 0 /* use Harfbuzz */);
}
/**
* Convenience overload that takes a CharSequence instead of a
* String.
*
* @see #getTextRunAdvances(String, int, int, int, int, int, float[], int)
* @hide
*/
public float getTextRunAdvances(CharSequence text, int start, int end,
int contextStart, int contextEnd, int flags, float[] advances,
int advancesIndex, int reserved) {
if (text == null) {
throw new IllegalArgumentException("text cannot be null");
@@ -1807,12 +1779,12 @@ public class Paint {
if (text instanceof String) {
return getTextRunAdvances((String) text, start, end,
contextStart, contextEnd, flags, advances, advancesIndex, reserved);
contextStart, contextEnd, flags, advances, advancesIndex);
}
if (text instanceof SpannedString ||
text instanceof SpannableString) {
return getTextRunAdvances(text.toString(), start, end,
contextStart, contextEnd, flags, advances, advancesIndex, reserved);
contextStart, contextEnd, flags, advances, advancesIndex);
}
if (text instanceof GraphicsOperations) {
return ((GraphicsOperations) text).getTextRunAdvances(start, end,
@@ -1827,7 +1799,7 @@ public class Paint {
char[] buf = TemporaryBuffer.obtain(contextLen);
TextUtils.getChars(text, contextStart, contextEnd, buf, 0);
float result = getTextRunAdvances(buf, start - contextStart, len,
0, contextLen, flags, advances, advancesIndex, reserved);
0, contextLen, flags, advances, advancesIndex);
TemporaryBuffer.recycle(buf);
return result;
}
@@ -1876,55 +1848,6 @@ public class Paint {
*/
public float getTextRunAdvances(String text, int start, int end, int contextStart,
int contextEnd, int flags, float[] advances, int advancesIndex) {
return getTextRunAdvances(text, start, end, contextStart, contextEnd, flags,
advances, advancesIndex, 0 /* use Harfbuzz*/);
}
/**
* 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).
*
* <p>The trailing surrogate in a valid surrogate pair is assigned
* an advance of 0. Thus the number of returned advances is
* always equal to count, not to the number of unicode codepoints
* represented by the run.
*
* <p>In the case of conjuncts or combining marks, the total
* advance is assigned to the first logical character, and the
* following characters are assigned an advance of 0.
*
* <p>This generates the sum of the advances of glyphs for
* characters in a reordered cluster as the width of the first
* logical character in the cluster, and 0 for the widths of all
* other characters in the cluster. In effect, such clusters are
* treated like conjuncts.
*
* <p>The shaping bounds limit the amount of context available
* outside start and end that can be used for shaping analysis.
* These bounds typically reflect changes in bidi level or font
* metrics across which shaping does not occur.
*
* @param text the text to measure. Cannot be null.
* @param start the index of the first character to measure
* @param end the index past the last character to measure
* @param contextStart the index of the first character to use for shaping context,
* must be <= start
* @param contextEnd the index past the last character to use for shaping context,
* must be >= end
* @param flags the flags to control the advances, either {@link #DIRECTION_LTR}
* or {@link #DIRECTION_RTL}
* @param advances array to receive the advances, must have room for all advances,
* can be null if only total advance is needed
* @param advancesIndex the position in advances at which to put the
* advance corresponding to the character at start
* @param reserved int reserved value
* @return the total advance
*
* @hide
*/
public float getTextRunAdvances(String text, int start, int end, int contextStart,
int contextEnd, int flags, float[] advances, int advancesIndex, int reserved) {
if (text == null) {
throw new IllegalArgumentException("text cannot be null");
@@ -1946,13 +1869,13 @@ public class Paint {
if (!mHasCompatScaling) {
return native_getTextRunAdvances(mNativePaint, text, start, end,
contextStart, contextEnd, flags, advances, advancesIndex, reserved);
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, reserved);
contextStart, contextEnd, flags, advances, advancesIndex);
setTextSize(oldSize);
if (advances != null) {
@@ -2227,10 +2150,10 @@ public class Paint {
private static native float native_getTextRunAdvances(int native_object,
char[] text, int index, int count, int contextIndex, int contextCount,
int flags, float[] advances, int advancesIndex, int reserved);
int flags, float[] advances, int advancesIndex);
private static native float native_getTextRunAdvances(int native_object,
String text, int start, int end, int contextStart, int contextEnd,
int flags, float[] advances, int advancesIndex, int reserved);
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);

View File

@@ -1,40 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- 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.
-->
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/canvas"
android:layout_width="fill_parent"
android:layout_height="fill_parent">
<LinearLayout android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent">
<SeekBar android:id="@+id/seekbar"
android:layout_height="wrap_content"
android:layout_width="match_parent"
/>
<view class="com.android.bidi.BiDiTestView"
android:id="@+id/testview"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="#FF0000"
/>
</LinearLayout>
</FrameLayout>

View File

@@ -101,7 +101,6 @@ public class BiDiTestActivity extends Activity {
addItem(result, "Basic", BiDiTestBasic.class, R.id.basic);
addItem(result, "Canvas", BiDiTestCanvas.class, R.id.canvas);
addItem(result, "Canvas2", BiDiTestCanvas2.class, R.id.canvas2);
addItem(result, "TextView LTR", BiDiTestTextViewLtr.class, R.id.textview_ltr);

View File

@@ -1,67 +0,0 @@
/*
* 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;
import android.app.Fragment;
import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.SeekBar;
import static com.android.bidi.BiDiTestConstants.FONT_MAX_SIZE;
import static com.android.bidi.BiDiTestConstants.FONT_MIN_SIZE;
public class BiDiTestCanvas extends Fragment {
static final int INIT_TEXT_SIZE = (FONT_MAX_SIZE - FONT_MIN_SIZE) / 2;
private BiDiTestView testView;
private SeekBar textSizeSeekBar;
private View currentView;
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
currentView = inflater.inflate(R.layout.canvas, container, false);
return currentView;
}
@Override
public void onViewCreated(View view, Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
testView = (BiDiTestView) currentView.findViewById(R.id.testview);
testView.setCurrentTextSize(INIT_TEXT_SIZE);
textSizeSeekBar = (SeekBar) currentView.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) {
testView.setCurrentTextSize(FONT_MIN_SIZE + progress);
}
public void onStartTrackingTouch(SeekBar seekBar) {
}
public void onStopTrackingTouch(SeekBar seekBar) {
}
});
}
}

View File

@@ -1,212 +0,0 @@
/*
* 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;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Rect;
import android.text.TextPaint;
import android.util.AttributeSet;
import android.util.Log;
import android.view.View;
public class BiDiTestView extends View {
private static final String TAG = "BiDiTestView";
private static final int BORDER_PADDING = 4;
private static final int TEXT_PADDING = 16;
private static final int TEXT_SIZE = 16;
private static final int ORIGIN = 80;
private static final float DEFAULT_ITALIC_SKEW_X = -0.25f;
private Rect rect = new Rect();
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;
private String ARABIC_TEXT;
private String CHINESE_TEXT;
private String MIXED_TEXT_1;
private String HEBREW_TEXT;
private String RTL_TEXT;
private String THAI_TEXT;
private int currentTextSize;
public BiDiTestView(Context context) {
super(context);
init(context);
}
public BiDiTestView(Context context, AttributeSet attrs) {
super(context, attrs);
init(context);
}
public BiDiTestView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
init(context);
}
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);
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);
HEBREW_TEXT = context.getString(R.string.hebrew_text);
RTL_TEXT = context.getString(R.string.rtl);
THAI_TEXT = context.getString(R.string.pointer_location);
}
public void setCurrentTextSize(int size) {
currentTextSize = size;
invalidate();
}
@Override
public void onDraw(Canvas canvas) {
drawInsideRect(canvas, new Paint(), Color.BLACK);
int deltaX = 0;
deltaX = testString(canvas, NORMAL_TEXT, ORIGIN, ORIGIN,
false, false, Paint.DIRECTION_LTR, currentTextSize);
deltaX += testString(canvas, ITALIC_TEXT, ORIGIN + deltaX, ORIGIN,
true, false, Paint.DIRECTION_LTR, currentTextSize);
deltaX += testString(canvas, BOLD_TEXT, ORIGIN + deltaX, ORIGIN,
false, true, Paint.DIRECTION_LTR, currentTextSize);
deltaX += testString(canvas, BOLD_ITALIC_TEXT, ORIGIN + deltaX, ORIGIN,
true, true, Paint.DIRECTION_LTR, currentTextSize);
// Test with a long string
deltaX = testString(canvas, NORMAL_LONG_TEXT, ORIGIN, ORIGIN + 2 * currentTextSize,
false, false, Paint.DIRECTION_LTR, currentTextSize);
// Test with a long string
deltaX = testString(canvas, NORMAL_LONG_TEXT_2, ORIGIN, ORIGIN + 4 * currentTextSize,
false, false, Paint.DIRECTION_LTR, currentTextSize);
// Test with a long string
deltaX = testString(canvas, NORMAL_LONG_TEXT_3, ORIGIN, ORIGIN + 6 * currentTextSize,
false, false, Paint.DIRECTION_LTR, currentTextSize);
// Test Arabic ligature
deltaX = testString(canvas, ARABIC_TEXT, ORIGIN, ORIGIN + 8 * currentTextSize,
false, false, Paint.DIRECTION_RTL, currentTextSize);
// Test Chinese
deltaX = testString(canvas, CHINESE_TEXT, ORIGIN, ORIGIN + 10 * currentTextSize,
false, false, Paint.DIRECTION_LTR, currentTextSize);
// Test Mixed (English and Arabic)
deltaX = testString(canvas, MIXED_TEXT_1, ORIGIN, ORIGIN + 12 * currentTextSize,
false, false, Paint.DIRECTION_LTR, currentTextSize);
// Test Hebrew
deltaX = testString(canvas, RTL_TEXT, ORIGIN, ORIGIN + 14 * currentTextSize,
false, false, Paint.DIRECTION_RTL, currentTextSize);
// Test Thai
deltaX = testString(canvas, THAI_TEXT, ORIGIN, ORIGIN + 16 * currentTextSize,
false, false, Paint.DIRECTION_LTR, currentTextSize);
}
private int testString(Canvas canvas, String text, int x, int y,
boolean isItalic, boolean isBold, int dir, int textSize) {
TextPaint paint = new TextPaint();
paint.setAntiAlias(true);
// Set paint properties
boolean oldFakeBold = paint.isFakeBoldText();
paint.setFakeBoldText(isBold);
float oldTextSkewX = paint.getTextSkewX();
if (isItalic) {
paint.setTextSkewX(DEFAULT_ITALIC_SKEW_X);
}
paint.setTextSize(textSize);
paint.setColor(Color.WHITE);
canvas.drawText(text, x, y, paint);
int length = text.length();
float[] advances = new float[length];
float textWidthHB = paint.getTextRunAdvances(text, 0, length, 0, length, dir, advances, 0);
setPaintDir(paint, dir);
float textWidthICU = paint.getTextRunAdvances(text, 0, length, 0, length, dir, advances, 0,
1 /* use ICU */);
logAdvances(text, textWidthHB, textWidthICU, advances);
drawMetricsAroundText(canvas, x, y, textWidthHB, textWidthICU, textSize, Color.RED, Color.GREEN);
// Restore old paint properties
paint.setFakeBoldText(oldFakeBold);
paint.setTextSkewX(oldTextSkewX);
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 drawInsideRect(Canvas canvas, Paint paint, int color) {
paint.setColor(color);
int width = getWidth();
int height = getHeight();
rect.set(BORDER_PADDING, BORDER_PADDING, width - BORDER_PADDING, height - BORDER_PADDING);
canvas.drawRect(rect, paint);
}
private void drawMetricsAroundText(Canvas canvas, int x, int y, float textWidthHB,
float textWidthICU, int textSize, int color, int colorICU) {
Paint paint = new Paint();
paint.setColor(color);
canvas.drawLine(x, y - textSize, x, 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 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]);
// }
}
}