am 261f82ca: Merge "Revert "Clean Paint.mBidiFlags as it is no longer used"" into jb-mr2-dev

* commit '261f82ca996a4b192b56350dd2eda6016f9d5203':
  Revert "Clean Paint.mBidiFlags as it is no longer used"
This commit is contained in:
Fabrice Di Meglio
2013-03-15 20:37:07 +00:00
committed by Android Git Automerger
20 changed files with 1160 additions and 297 deletions

View File

@ -38,7 +38,7 @@ extends CharSequence
* {@hide}
*/
void drawTextRun(Canvas c, int start, int end, int contextStart, int contextEnd,
float x, float y, Paint p);
float x, float y, int flags, Paint p);
/**
* Just like {@link Paint#measureText}.
@ -55,12 +55,19 @@ extends CharSequence
* @hide
*/
float getTextRunAdvances(int start, int end, int contextStart, int contextEnd,
float[] advances, int advancesIndex, Paint paint);
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
*/
int getTextRunCursor(int contextStart, int contextEnd, int offset,
int getTextRunCursor(int contextStart, int contextEnd, int flags, int offset,
int cursorOpt, Paint p);
}

View File

@ -159,15 +159,18 @@ class MeasuredText {
mPos = p + len;
if (mEasy) {
return paint.getTextRunAdvances(mChars, p, len, p, len, mWidths, p);
int flags = mDir == Layout.DIR_LEFT_TO_RIGHT
? Canvas.DIRECTION_LTR : Canvas.DIRECTION_RTL;
return paint.getTextRunAdvances(mChars, p, len, p, len, flags, mWidths, p);
}
float totalAdvance = 0;
int level = mLevels[p];
for (int q = p, i = p + 1, e = p + len;; ++i) {
if (i == e || mLevels[i] != level) {
int flags = (level & 0x1) == 0 ? Canvas.DIRECTION_LTR : Canvas.DIRECTION_RTL;
totalAdvance +=
paint.getTextRunAdvances(mChars, q, i - q, q, i - q, mWidths, q);
paint.getTextRunAdvances(mChars, q, i - q, q, i - q, flags, mWidths, q);
if (i == e) {
break;
}

View File

@ -1130,20 +1130,20 @@ public class SpannableStringBuilder implements CharSequence, GetChars, Spannable
* {@hide}
*/
public void drawTextRun(Canvas c, int start, int end, int contextStart, int contextEnd,
float x, float y, Paint p) {
float x, float y, int flags, Paint p) {
checkRange("drawTextRun", start, end);
int contextLen = contextEnd - contextStart;
int len = end - start;
if (contextEnd <= mGapStart) {
c.drawTextRun(mText, start, len, contextStart, contextLen, x, y, p);
c.drawTextRun(mText, start, len, contextStart, contextLen, x, y, flags, p);
} else if (contextStart >= mGapStart) {
c.drawTextRun(mText, start + mGapLength, len, contextStart + mGapLength,
contextLen, x, y, p);
contextLen, x, y, flags, p);
} else {
char[] buf = TextUtils.obtain(contextLen);
getChars(contextStart, contextEnd, buf, 0);
c.drawTextRun(buf, start - contextStart, len, 0, contextLen, x, y, p);
c.drawTextRun(buf, start - contextStart, len, 0, contextLen, x, y, flags, p);
TextUtils.recycle(buf);
}
}
@ -1200,7 +1200,7 @@ public class SpannableStringBuilder implements CharSequence, GetChars, Spannable
* Don't call this yourself -- exists for Paint to use internally.
* {@hide}
*/
public float getTextRunAdvances(int start, int end, int contextStart, int contextEnd,
public float getTextRunAdvances(int start, int end, int contextStart, int contextEnd, int flags,
float[] advances, int advancesPos, Paint p) {
float ret;
@ -1210,15 +1210,44 @@ public class SpannableStringBuilder implements CharSequence, GetChars, Spannable
if (end <= mGapStart) {
ret = p.getTextRunAdvances(mText, start, len, contextStart, contextLen,
advances, advancesPos);
flags, advances, advancesPos);
} else if (start >= mGapStart) {
ret = p.getTextRunAdvances(mText, start + mGapLength, len,
contextStart + mGapLength, contextLen, advances, advancesPos);
contextStart + mGapLength, contextLen, flags, advances, advancesPos);
} else {
char[] buf = TextUtils.obtain(contextLen);
getChars(contextStart, contextEnd, buf, 0);
ret = p.getTextRunAdvances(buf, start - contextStart, len,
0, contextLen, advances, advancesPos);
0, contextLen, flags, advances, advancesPos);
TextUtils.recycle(buf);
}
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);
}
@ -1241,7 +1270,7 @@ public class SpannableStringBuilder implements CharSequence, GetChars, Spannable
*
* @param contextStart the start index of the context
* @param contextEnd the (non-inclusive) end index of the context
* @param flags reserved
* @param flags either DIRECTION_RTL or DIRECTION_LTR
* @param offset the cursor position to move from
* @param cursorOpt how to move the cursor, one of CURSOR_AFTER,
* CURSOR_AT_OR_AFTER, CURSOR_BEFORE,
@ -1252,30 +1281,22 @@ public class SpannableStringBuilder implements CharSequence, GetChars, Spannable
*/
@Deprecated
public int getTextRunCursor(int contextStart, int contextEnd, int flags, int offset,
int cursorOpt, Paint p) {
return getTextRunCursor(contextStart, contextEnd, offset, cursorOpt, p);
}
/**
* @hide
*/
public int getTextRunCursor(int contextStart, int contextEnd, int offset,
int cursorOpt, Paint p) {
int cursorOpt, Paint p) {
int ret;
int contextLen = contextEnd - contextStart;
if (contextEnd <= mGapStart) {
ret = p.getTextRunCursor(mText, contextStart, contextLen,
offset, cursorOpt);
flags, offset, cursorOpt);
} else if (contextStart >= mGapStart) {
ret = p.getTextRunCursor(mText, contextStart + mGapLength, contextLen,
offset + mGapLength, cursorOpt) - mGapLength;
flags, offset + mGapLength, cursorOpt) - mGapLength;
} else {
char[] buf = TextUtils.obtain(contextLen);
getChars(contextStart, contextEnd, buf, 0);
ret = p.getTextRunCursor(buf, 0, contextLen,
offset - contextStart, cursorOpt) + contextStart;
flags, offset - contextStart, cursorOpt) + contextStart;
TextUtils.recycle(buf);
}

View File

@ -664,13 +664,14 @@ class TextLine {
}
}
int flags = runIsRtl ? Paint.DIRECTION_RTL : Paint.DIRECTION_LTR;
int cursorOpt = after ? Paint.CURSOR_AFTER : Paint.CURSOR_BEFORE;
if (mCharsValid) {
return wp.getTextRunCursor(mChars, spanStart, spanLimit - spanStart,
offset, cursorOpt);
flags, offset, cursorOpt);
} else {
return wp.getTextRunCursor(mText, mStart + spanStart,
mStart + spanLimit, mStart + offset, cursorOpt) - mStart;
mStart + spanLimit, flags, mStart + offset, cursorOpt) - mStart;
}
}
@ -737,13 +738,15 @@ class TextLine {
int contextLen = contextEnd - contextStart;
if (needWidth || (c != null && (wp.bgColor != 0 || wp.underlineColor != 0 || runIsRtl))) {
int flags = runIsRtl ? Paint.DIRECTION_RTL : Paint.DIRECTION_LTR;
if (mCharsValid) {
ret = wp.getTextRunAdvances(mChars, start, runLen,
contextStart, contextLen, null, 0);
contextStart, contextLen, flags, null, 0);
} else {
int delta = mStart;
ret = wp.getTextRunAdvances(mText, delta + start, delta + end,
delta + contextStart, delta + contextEnd, null, 0);
ret = wp.getTextRunAdvances(mText, delta + start,
delta + end, delta + contextStart, delta + contextEnd,
flags, null, 0);
}
}
@ -783,7 +786,8 @@ class TextLine {
wp.setAntiAlias(previousAntiAlias);
}
drawTextRun(c, wp, start, end, contextStart, contextEnd, x, y + wp.baselineShift);
drawTextRun(c, wp, start, end, contextStart, contextEnd, runIsRtl,
x, y + wp.baselineShift);
}
return runIsRtl ? -ret : ret;
@ -966,21 +970,23 @@ class TextLine {
* @param end the end of the run
* @param contextStart the start of context for the run
* @param contextEnd the end of the context for the run
* @param runIsRtl true if the run is right-to-left
* @param x the x position of the left edge of the run
* @param y the baseline of the run
*/
private void drawTextRun(Canvas c, TextPaint wp, int start, int end,
int contextStart, int contextEnd, float x, int y) {
int contextStart, int contextEnd, boolean runIsRtl, float x, int y) {
int flags = runIsRtl ? Canvas.DIRECTION_RTL : Canvas.DIRECTION_LTR;
if (mCharsValid) {
int count = end - start;
int contextCount = contextEnd - contextStart;
c.drawTextRun(mChars, start, count, contextStart, contextCount,
x, y, wp);
x, y, flags, wp);
} else {
int delta = mStart;
c.drawTextRun(mText, delta + start, delta + end,
delta + contextStart, delta + contextEnd, x, y, wp);
delta + contextStart, delta + contextEnd, x, y, flags, wp);
}
}

View File

@ -1162,14 +1162,14 @@ class GLES20Canvas extends HardwareCanvas {
int modifiers = setupModifiers(paint);
try {
nDrawText(mRenderer, text, index, count, x, y, paint.mNativePaint);
nDrawText(mRenderer, text, index, count, x, y, paint.mBidiFlags, paint.mNativePaint);
} finally {
if (modifiers != MODIFIER_NONE) nResetModifiers(mRenderer, modifiers);
}
}
private static native void nDrawText(int renderer, char[] text, int index, int count,
float x, float y, int paint);
float x, float y, int bidiFlags, int paint);
@Override
public void drawText(CharSequence text, int start, int end, float x, float y, Paint paint) {
@ -1177,14 +1177,16 @@ class GLES20Canvas extends HardwareCanvas {
try {
if (text instanceof String || text instanceof SpannedString ||
text instanceof SpannableString) {
nDrawText(mRenderer, text.toString(), start, end, x, y, paint.mNativePaint);
nDrawText(mRenderer, text.toString(), start, end, x, y, paint.mBidiFlags,
paint.mNativePaint);
} else if (text instanceof GraphicsOperations) {
((GraphicsOperations) text).drawText(this, start, end, x, y,
paint);
} else {
char[] buf = TemporaryBuffer.obtain(end - start);
TextUtils.getChars(text, start, end, buf, 0);
nDrawText(mRenderer, buf, 0, end - start, x, y, paint.mNativePaint);
nDrawText(mRenderer, buf, 0, end - start, x, y,
paint.mBidiFlags, paint.mNativePaint);
TemporaryBuffer.recycle(buf);
}
} finally {
@ -1200,20 +1202,21 @@ class GLES20Canvas extends HardwareCanvas {
int modifiers = setupModifiers(paint);
try {
nDrawText(mRenderer, text, start, end, x, y, paint.mNativePaint);
nDrawText(mRenderer, text, start, end, x, y, paint.mBidiFlags, paint.mNativePaint);
} finally {
if (modifiers != MODIFIER_NONE) nResetModifiers(mRenderer, modifiers);
}
}
private static native void nDrawText(int renderer, String text, int start, int end,
float x, float y, int paint);
float x, float y, int bidiFlags, int paint);
@Override
public void drawText(String text, float x, float y, Paint paint) {
int modifiers = setupModifiers(paint);
try {
nDrawText(mRenderer, text, 0, text.length(), x, y, paint.mNativePaint);
nDrawText(mRenderer, text, 0, text.length(), x, y, paint.mBidiFlags,
paint.mNativePaint);
} finally {
if (modifiers != MODIFIER_NONE) nResetModifiers(mRenderer, modifiers);
}
@ -1229,14 +1232,14 @@ class GLES20Canvas extends HardwareCanvas {
int modifiers = setupModifiers(paint);
try {
nDrawTextOnPath(mRenderer, text, index, count, path.mNativePath, hOffset, vOffset,
paint.mNativePaint);
paint.mBidiFlags, paint.mNativePaint);
} finally {
if (modifiers != MODIFIER_NONE) nResetModifiers(mRenderer, modifiers);
}
}
private static native void nDrawTextOnPath(int renderer, char[] text, int index, int count,
int path, float hOffset, float vOffset, int nativePaint);
int path, float hOffset, float vOffset, int bidiFlags, int nativePaint);
@Override
public void drawTextOnPath(String text, Path path, float hOffset, float vOffset, Paint paint) {
@ -1245,25 +1248,28 @@ class GLES20Canvas extends HardwareCanvas {
int modifiers = setupModifiers(paint);
try {
nDrawTextOnPath(mRenderer, text, 0, text.length(), path.mNativePath, hOffset, vOffset,
paint.mNativePaint);
paint.mBidiFlags, paint.mNativePaint);
} finally {
if (modifiers != MODIFIER_NONE) nResetModifiers(mRenderer, modifiers);
}
}
private static native void nDrawTextOnPath(int renderer, String text, int start, int end,
int path, float hOffset, float vOffset, int nativePaint);
int path, float hOffset, float vOffset, int bidiFlags, int nativePaint);
@Override
public void drawTextRun(char[] text, int index, int count, int contextIndex, int contextCount,
float x, float y, Paint paint) {
float x, float y, int dir, Paint paint) {
if ((index | count | text.length - index - count) < 0) {
throw new IndexOutOfBoundsException();
}
if (dir != DIRECTION_LTR && dir != DIRECTION_RTL) {
throw new IllegalArgumentException("Unknown direction: " + dir);
}
int modifiers = setupModifiers(paint);
try {
nDrawTextRun(mRenderer, text, index, count, contextIndex, contextCount, x, y,
nDrawTextRun(mRenderer, text, index, count, contextIndex, contextCount, x, y, dir,
paint.mNativePaint);
} finally {
if (modifiers != MODIFIER_NONE) nResetModifiers(mRenderer, modifiers);
@ -1271,31 +1277,32 @@ class GLES20Canvas extends HardwareCanvas {
}
private static native void nDrawTextRun(int renderer, char[] text, int index, int count,
int contextIndex, int contextCount, float x, float y, int nativePaint);
int contextIndex, int contextCount, float x, float y, int dir, int nativePaint);
@Override
public void drawTextRun(CharSequence text, int start, int end, int contextStart, int contextEnd,
float x, float y, Paint paint) {
float x, float y, int dir, Paint paint) {
if ((start | end | end - start | text.length() - end) < 0) {
throw new IndexOutOfBoundsException();
}
int modifiers = setupModifiers(paint);
try {
int flags = dir == 0 ? 0 : 1;
if (text instanceof String || text instanceof SpannedString ||
text instanceof SpannableString) {
nDrawTextRun(mRenderer, text.toString(), start, end, contextStart,
contextEnd, x, y, paint.mNativePaint);
contextEnd, x, y, flags, paint.mNativePaint);
} else if (text instanceof GraphicsOperations) {
((GraphicsOperations) text).drawTextRun(this, start, end,
contextStart, contextEnd, x, y, paint);
contextStart, contextEnd, x, y, flags, paint);
} else {
int contextLen = contextEnd - contextStart;
int len = end - start;
char[] buf = TemporaryBuffer.obtain(contextLen);
TextUtils.getChars(text, contextStart, contextEnd, buf, 0);
nDrawTextRun(mRenderer, buf, start - contextStart, len, 0, contextLen,
x, y, paint.mNativePaint);
x, y, flags, paint.mNativePaint);
TemporaryBuffer.recycle(buf);
}
} finally {
@ -1304,7 +1311,7 @@ class GLES20Canvas extends HardwareCanvas {
}
private static native void nDrawTextRun(int renderer, String text, int start, int end,
int contextStart, int contextEnd, float x, float y, int nativePaint);
int contextStart, int contextEnd, float x, float y, int flags, int nativePaint);
@Override
public void drawVertices(VertexMode mode, int vertexCount, float[] verts, int vertOffset,

View File

@ -267,15 +267,15 @@ class GLES20RecordingCanvas extends GLES20Canvas {
@Override
public void drawTextRun(char[] text, int index, int count, int contextIndex, int contextCount,
float x, float y, Paint paint) {
super.drawTextRun(text, index, count, contextIndex, contextCount, x, y, paint);
float x, float y, int dir, Paint paint) {
super.drawTextRun(text, index, count, contextIndex, contextCount, x, y, dir, paint);
recordShaderBitmap(paint);
}
@Override
public void drawTextRun(CharSequence text, int start, int end, int contextStart,
int contextEnd, float x, float y, Paint paint) {
super.drawTextRun(text, start, end, contextStart, contextEnd, x, y, paint);
int contextEnd, float x, float y, int dir, Paint paint) {
super.drawTextRun(text, start, end, contextStart, contextEnd, x, y, dir, paint);
recordShaderBitmap(paint);
}

View File

@ -8813,11 +8813,11 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
}
public void drawTextRun(Canvas c, int start, int end,
int contextStart, int contextEnd, float x, float y, Paint p) {
int contextStart, int contextEnd, float x, float y, int flags, Paint p) {
int count = end - start;
int contextCount = contextEnd - contextStart;
c.drawTextRun(mChars, start + mStart, count, contextStart + mStart,
contextCount, x, y, p);
contextCount, x, y, flags, p);
}
public float measureText(int start, int end, Paint p) {
@ -8829,20 +8829,30 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
}
public float getTextRunAdvances(int start, int end, int contextStart,
int contextEnd, float[] advances, int advancesIndex,
int contextEnd, int flags, float[] advances, int advancesIndex,
Paint p) {
int count = end - start;
int contextCount = contextEnd - contextStart;
return p.getTextRunAdvances(mChars, start + mStart, count,
contextStart + mStart, contextCount, advances,
contextStart + mStart, contextCount, flags, advances,
advancesIndex);
}
public int getTextRunCursor(int contextStart, int contextEnd,
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;
return p.getTextRunCursor(mChars, contextStart + mStart,
contextCount, offset + mStart, cursorOpt);
contextCount, flags, offset + mStart, cursorOpt);
}
}

View File

@ -754,35 +754,35 @@ public:
static void drawText___CIIFFIPaint(JNIEnv* env, jobject, SkCanvas* canvas,
jcharArray text, int index, int count,
jfloat x, jfloat y, SkPaint* paint) {
jfloat x, jfloat y, int flags, SkPaint* paint) {
jchar* textArray = env->GetCharArrayElements(text, NULL);
drawTextWithGlyphs(canvas, textArray + index, 0, count, x, y, paint);
drawTextWithGlyphs(canvas, textArray + index, 0, count, x, y, flags, paint);
env->ReleaseCharArrayElements(text, textArray, JNI_ABORT);
}
static void drawText__StringIIFFIPaint(JNIEnv* env, jobject,
SkCanvas* canvas, jstring text,
int start, int end,
jfloat x, jfloat y, SkPaint* paint) {
jfloat x, jfloat y, int flags, SkPaint* paint) {
const jchar* textArray = env->GetStringChars(text, NULL);
drawTextWithGlyphs(canvas, textArray, start, end, x, y, paint);
drawTextWithGlyphs(canvas, textArray, start, end, x, y, flags, paint);
env->ReleaseStringChars(text, textArray);
}
static void drawTextWithGlyphs(SkCanvas* canvas, const jchar* textArray,
int start, int end,
jfloat x, jfloat y, SkPaint* paint) {
jfloat x, jfloat y, int flags, SkPaint* paint) {
jint count = end - start;
drawTextWithGlyphs(canvas, textArray + start, 0, count, count, x, y, paint);
drawTextWithGlyphs(canvas, textArray + start, 0, count, count, x, y, flags, paint);
}
static void drawTextWithGlyphs(SkCanvas* canvas, const jchar* textArray,
int start, int count, int contextCount,
jfloat x, jfloat y, SkPaint* paint) {
jfloat x, jfloat y, int flags, SkPaint* paint) {
sp<TextLayoutValue> value = TextLayoutEngine::getInstance().getValue(paint,
textArray, start, count, contextCount);
textArray, start, count, contextCount, flags);
if (value == NULL) {
return;
}
@ -793,7 +793,7 @@ public:
x -= value->getTotalAdvance();
}
paint->setTextAlign(SkPaint::kLeft_Align);
doDrawGlyphsPos(canvas, value->getGlyphs(), value->getPos(), 0, value->getGlyphsCount(), x, y, paint);
doDrawGlyphsPos(canvas, value->getGlyphs(), value->getPos(), 0, value->getGlyphsCount(), x, y, flags, paint);
doDrawTextDecorations(canvas, x, y, value->getTotalAdvance(), paint);
paint->setTextAlign(align);
}
@ -835,8 +835,14 @@ static void doDrawTextDecorations(SkCanvas* canvas, jfloat x, jfloat y, jfloat l
}
}
static void doDrawGlyphs(SkCanvas* canvas, const jchar* glyphArray, int index, int count,
jfloat x, jfloat y, int flags, SkPaint* paint) {
// Beware: this needs Glyph encoding (already done on the Paint constructor)
canvas->drawText(glyphArray + index * 2, count * 2, x, y, *paint);
}
static void doDrawGlyphsPos(SkCanvas* canvas, const jchar* glyphArray, const jfloat* posArray,
int index, int count, jfloat x, jfloat y, SkPaint* paint) {
int index, int count, jfloat x, jfloat y, int flags, SkPaint* paint) {
SkPoint* posPtr = new SkPoint[count];
for (int indx = 0; indx < count; indx++) {
posPtr[indx].fX = SkFloatToScalar(x + posArray[indx * 2]);
@ -853,7 +859,7 @@ static void doDrawTextDecorations(SkCanvas* canvas, jfloat x, jfloat y, jfloat l
jchar* chars = env->GetCharArrayElements(text, NULL);
drawTextWithGlyphs(canvas, chars + contextIndex, index - contextIndex,
count, contextCount, x, y, paint);
count, contextCount, x, y, dirFlags, paint);
env->ReleaseCharArrayElements(text, chars, JNI_ABORT);
}
@ -866,7 +872,7 @@ static void doDrawTextDecorations(SkCanvas* canvas, jfloat x, jfloat y, jfloat l
jint contextCount = contextEnd - contextStart;
const jchar* chars = env->GetStringChars(text, NULL);
drawTextWithGlyphs(canvas, chars + contextStart, start - contextStart,
count, contextCount, x, y, paint);
count, contextCount, x, y, dirFlags, paint);
env->ReleaseStringChars(text, chars);
}
@ -929,19 +935,21 @@ static void doDrawTextDecorations(SkCanvas* canvas, jfloat x, jfloat y, jfloat l
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);
TextLayout::drawTextOnPath(paint, textArray + index, count, hOffset, vOffset, path, canvas);
TextLayout::drawTextOnPath(paint, textArray + index, count, bidiFlags, hOffset, vOffset,
path, canvas);
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 count = env->GetStringLength(text);
TextLayout::drawTextOnPath(paint, text_, count, hOffset, vOffset, path, canvas);
TextLayout::drawTextOnPath(paint, text_, count, bidiFlags, hOffset, vOffset,
path, canvas);
env->ReleaseStringChars(text, text_);
}
@ -1051,21 +1059,21 @@ static JNINativeMethod gCanvasMethods[] = {
(void*)SkCanvasGlue::drawBitmapMesh},
{"nativeDrawVertices", "(III[FI[FI[II[SIII)V",
(void*)SkCanvasGlue::drawVertices},
{"native_drawText","(I[CIIFFI)V",
{"native_drawText","(I[CIIFFII)V",
(void*) SkCanvasGlue::drawText___CIIFFIPaint},
{"native_drawText","(ILjava/lang/String;IIFFI)V",
{"native_drawText","(ILjava/lang/String;IIFFII)V",
(void*) SkCanvasGlue::drawText__StringIIFFIPaint},
{"native_drawTextRun","(I[CIIIIFFI)V",
{"native_drawTextRun","(I[CIIIIFFII)V",
(void*) SkCanvasGlue::drawTextRun___CIIIIFFIPaint},
{"native_drawTextRun","(ILjava/lang/String;IIIIFFI)V",
{"native_drawTextRun","(ILjava/lang/String;IIIIFFII)V",
(void*) SkCanvasGlue::drawTextRun__StringIIIIFFIPaint},
{"native_drawPosText","(I[CII[FI)V",
(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},

View File

@ -401,7 +401,7 @@ public:
jfloat result = 0;
TextLayout::getTextRunAdvances(paint, textArray, index, count, textLength,
NULL /* dont need all advances */, &result);
paint->getFlags(), NULL /* dont need all advances */, &result);
env->ReleaseCharArrayElements(text, const_cast<jchar*>(textArray), JNI_ABORT);
return result;
@ -426,7 +426,7 @@ public:
jfloat width = 0;
TextLayout::getTextRunAdvances(paint, textArray, start, count, textLength,
NULL /* dont need all advances */, &width);
paint->getFlags(), NULL /* dont need all advances */, &width);
env->ReleaseStringChars(text, textArray);
return width;
@ -446,7 +446,7 @@ public:
jfloat width = 0;
TextLayout::getTextRunAdvances(paint, textArray, 0, textLength, textLength,
NULL /* dont need all advances */, &width);
paint->getFlags(), NULL /* dont need all advances */, &width);
env->ReleaseStringChars(text, textArray);
return width;
@ -473,7 +473,7 @@ public:
jfloat* widthsArray = autoWidths.ptr();
TextLayout::getTextRunAdvances(paint, text, 0, count, count,
widthsArray, NULL /* dont need totalAdvance */);
paint->getFlags(), widthsArray, NULL /* dont need totalAdvance */);
return count;
}
@ -494,8 +494,48 @@ public:
return count;
}
static int doTextGlyphs(JNIEnv* env, SkPaint* paint, const jchar* text, jint start, jint count,
jint contextCount, jint flags, jcharArray glyphs) {
NPE_CHECK_RETURN_ZERO(env, paint);
NPE_CHECK_RETURN_ZERO(env, text);
if ((start | count | contextCount) < 0 || contextCount < count || !glyphs) {
doThrowAIOOBE(env);
return 0;
}
if (count == 0) {
return 0;
}
size_t glypthsLength = env->GetArrayLength(glyphs);
if ((size_t)count > glypthsLength) {
doThrowAIOOBE(env);
return 0;
}
jchar* glyphsArray = env->GetCharArrayElements(glyphs, NULL);
sp<TextLayoutValue> value = TextLayoutEngine::getInstance().getValue(paint,
text, start, count, contextCount, flags);
const jchar* shapedGlyphs = value->getGlyphs();
size_t glyphsCount = value->getGlyphsCount();
memcpy(glyphsArray, shapedGlyphs, sizeof(jchar) * glyphsCount);
env->ReleaseCharArrayElements(glyphs, glyphsArray, JNI_ABORT);
return glyphsCount;
}
static int getTextGlyphs__StringIIIII_C(JNIEnv* env, jobject clazz, SkPaint* paint,
jstring text, jint start, jint end, jint contextStart, jint contextEnd, jint flags,
jcharArray glyphs) {
const jchar* textArray = env->GetStringChars(text, NULL);
int count = doTextGlyphs(env, paint, textArray + contextStart, start - contextStart,
end - start, contextEnd - contextStart, flags, glyphs);
env->ReleaseStringChars(text, textArray);
return count;
}
static jfloat doTextRunAdvances(JNIEnv *env, SkPaint *paint, const jchar *text,
jint start, jint count, jint contextCount,
jint start, jint count, jint contextCount, jint flags,
jfloatArray advances, jint advancesIndex) {
NPE_CHECK_RETURN_ZERO(env, paint);
NPE_CHECK_RETURN_ZERO(env, text);
@ -517,7 +557,7 @@ public:
jfloat advancesArray[count];
jfloat totalAdvance = 0;
TextLayout::getTextRunAdvances(paint, text, start, count, contextCount,
TextLayout::getTextRunAdvances(paint, text, start, count, contextCount, flags,
advancesArray, &totalAdvance);
if (advances != NULL) {
@ -526,23 +566,61 @@ public:
return totalAdvance;
}
static float getTextRunAdvances___CIIII_FI(JNIEnv* env, jobject clazz, SkPaint* paint,
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,
jcharArray text, jint index, jint count, jint contextIndex, jint contextCount,
jfloatArray advances, jint advancesIndex) {
jint flags, jfloatArray advances, jint advancesIndex, jint reserved) {
jchar* textArray = env->GetCharArrayElements(text, NULL);
jfloat result = doTextRunAdvances(env, paint, textArray + contextIndex,
index - contextIndex, count, contextCount, advances, advancesIndex);
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);
env->ReleaseCharArrayElements(text, textArray, JNI_ABORT);
return result;
}
static float getTextRunAdvances__StringIIII_FI(JNIEnv* env, jobject clazz, SkPaint* paint,
jstring text, jint start, jint end, jint contextStart, jint contextEnd,
jfloatArray advances, jint advancesIndex) {
static float getTextRunAdvances__StringIIIII_FII(JNIEnv* env, jobject clazz, SkPaint* paint,
jstring text, jint start, jint end, jint contextStart, jint contextEnd, jint flags,
jfloatArray advances, jint advancesIndex, jint reserved) {
const jchar* textArray = env->GetStringChars(text, NULL);
jfloat result = doTextRunAdvances(env, paint, textArray + contextStart,
start - contextStart, end - start, contextEnd - contextStart,
advances, advancesIndex);
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);
env->ReleaseStringChars(text, textArray);
return result;
}
@ -551,7 +629,7 @@ public:
jint count, jint flags, jint offset, jint opt) {
jfloat scalarArray[count];
TextLayout::getTextRunAdvances(paint, text, start, count, start + count,
TextLayout::getTextRunAdvances(paint, text, start, count, start + count, flags,
scalarArray, NULL /* dont need totalAdvance */);
jint pos = offset - start;
@ -610,21 +688,21 @@ public:
}
static void getTextPath(JNIEnv* env, SkPaint* paint, const jchar* text, jint count,
jfloat x, jfloat y, SkPath *path) {
TextLayout::getTextPath(paint, text, count, x, y, path);
jint bidiFlags, jfloat x, jfloat y, SkPath *path) {
TextLayout::getTextPath(paint, text, count, bidiFlags, x, y, path);
}
static void getTextPath___C(JNIEnv* env, jobject clazz, SkPaint* paint,
static void getTextPath___C(JNIEnv* env, jobject clazz, SkPaint* paint, jint bidiFlags,
jcharArray text, int index, int count, jfloat x, jfloat y, SkPath* path) {
const jchar* textArray = env->GetCharArrayElements(text, NULL);
getTextPath(env, paint, textArray + index, count, x, y, path);
getTextPath(env, paint, textArray + index, count, bidiFlags, x, y, path);
env->ReleaseCharArrayElements(text, const_cast<jchar*>(textArray), JNI_ABORT);
}
static void getTextPath__String(JNIEnv* env, jobject clazz, SkPaint* paint,
static void getTextPath__String(JNIEnv* env, jobject clazz, SkPaint* paint, jint bidiFlags,
jstring text, int start, int end, jfloat x, jfloat y, SkPath* path) {
const jchar* textArray = env->GetStringChars(text, NULL);
getTextPath(env, paint, textArray + start, end - start, x, y, path);
getTextPath(env, paint, textArray + start, end - start, bidiFlags, x, y, path);
env->ReleaseStringChars(text, textArray);
}
@ -648,7 +726,7 @@ public:
int count, float maxWidth, jfloatArray jmeasured,
SkPaint::TextBufferDirection tbd) {
sp<TextLayoutValue> value = TextLayoutEngine::getInstance().getValue(&paint,
text, 0, count, count);
text, 0, count, count, paint.getFlags());
if (value == NULL) {
return 0;
}
@ -720,7 +798,7 @@ public:
SkIRect ir;
sp<TextLayoutValue> value = TextLayoutEngine::getInstance().getValue(&paint,
text, 0, count, count);
text, 0, count, count, paint.getFlags());
if (value == NULL) {
return;
}
@ -808,15 +886,19 @@ 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[CIIII[FI)F",
(void*) SkPaintGlue::getTextRunAdvances___CIIII_FI},
{"native_getTextRunAdvances","(ILjava/lang/String;IIII[FI)F",
(void*) SkPaintGlue::getTextRunAdvances__StringIIII_FI},
{"native_getTextRunCursor", "(I[CIIII)I", (void*) SkPaintGlue::getTextRunCursor___C},
{"native_getTextRunCursor", "(ILjava/lang/String;IIII)I",
{"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_getTextGlyphs","(ILjava/lang/String;IIIII[C)I",
(void*) SkPaintGlue::getTextGlyphs__StringIIIII_C},
{"native_getTextRunCursor", "(I[CIIIII)I", (void*) SkPaintGlue::getTextRunCursor___C},
{"native_getTextRunCursor", "(ILjava/lang/String;IIIII)I",
(void*) SkPaintGlue::getTextRunCursor__String},
{"native_getTextPath","(I[CIIFFI)V", (void*) SkPaintGlue::getTextPath___C},
{"native_getTextPath","(ILjava/lang/String;IIFFI)V", (void*) SkPaintGlue::getTextPath__String},
{"native_getTextPath","(II[CIIFFI)V", (void*) SkPaintGlue::getTextPath___C},
{"native_getTextPath","(IILjava/lang/String;IIFFI)V", (void*) SkPaintGlue::getTextPath__String},
{"nativeGetStringBounds", "(ILjava/lang/String;IILandroid/graphics/Rect;)V",
(void*) SkPaintGlue::getStringBounds },
{"nativeGetCharArrayBounds", "(I[CIILandroid/graphics/Rect;)V",

View File

@ -28,13 +28,33 @@
namespace android {
// 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.
bool TextLayout::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] >= UNICODE_FIRST_RTL_CHAR) {
return true;
}
}
return false;
}
// Draws or gets the path of a paragraph of text on a single line, running bidi and shaping.
// This will draw if canvas is not null, otherwise path must be non-null and it will create
// a path representing the text that would have been drawn.
void TextLayout::handleText(SkPaint *paint, const jchar* text, jsize len,
jfloat x, jfloat y, SkPath *path) {
jint bidiFlags, jfloat x, jfloat y, SkPath *path) {
sp<TextLayoutValue> value = TextLayoutEngine::getInstance().getValue(paint,
text, 0, len, len);
text, 0, len, len, bidiFlags);
if (value == NULL) {
return ;
}
@ -45,10 +65,10 @@ void TextLayout::handleText(SkPaint *paint, const jchar* text, jsize len,
}
void TextLayout::getTextRunAdvances(SkPaint* paint, const jchar* chars, jint start,
jint count, jint contextCount,
jint count, jint contextCount, jint dirFlags,
jfloat* resultAdvances, jfloat* resultTotalAdvance) {
sp<TextLayoutValue> value = TextLayoutEngine::getInstance().getValue(paint,
chars, start, count, contextCount);
chars, start, count, contextCount, dirFlags);
if (value == NULL) {
return ;
}
@ -60,20 +80,29 @@ void TextLayout::getTextRunAdvances(SkPaint* paint, const jchar* chars, jint sta
}
}
void TextLayout::getTextPath(SkPaint *paint, const jchar *text, jsize len,
jfloat x, jfloat y, SkPath *path) {
handleText(paint, text, len, x, y, path);
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);
}
void TextLayout::drawTextOnPath(SkPaint* paint, const jchar* text, int count,
jfloat hOffset, jfloat vOffset,
int bidiFlags, jfloat hOffset, jfloat vOffset,
SkPath* path, SkCanvas* canvas) {
SkScalar h_ = SkFloatToScalar(hOffset);
SkScalar v_ = SkFloatToScalar(vOffset);
sp<TextLayoutValue> value = TextLayoutEngine::getInstance().getValue(paint,
text, 0, count, count);
text, 0, count, count, bidiFlags);
if (value == NULL) {
return;
}
@ -82,4 +111,73 @@ 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

@ -41,6 +41,17 @@ namespace android {
*/
#define USE_TEXT_LAYOUT_CACHE 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
};
enum {
kDirection_LTR = 0,
kDirection_RTL = 1,
@ -52,18 +63,28 @@ class TextLayout {
public:
static void getTextRunAdvances(SkPaint* paint, const jchar* chars, jint start,
jint count, jint contextCount,
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,
jfloat x, jfloat y, SkPath* path);
jint bidiFlags, jfloat x, jfloat y, SkPath* path);
static void drawTextOnPath(SkPaint* paint, const jchar* text, jsize len,
jfloat hOffset, jfloat vOffset,
int bidiFlags, jfloat hOffset, jfloat vOffset,
SkPath* path, SkCanvas* canvas);
private:
static bool needsLayout(const jchar* text, jint len, jint bidiFlags);
static void handleText(SkPaint* paint, const jchar* text, jsize len,
jfloat x, jfloat y, SkPath* path);
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

@ -87,7 +87,7 @@ void TextLayoutCache::purgeCaches() {
* Caching
*/
sp<TextLayoutValue> TextLayoutCache::getValue(const SkPaint* paint,
const jchar* text, jint start, jint count, jint contextCount) {
const jchar* text, jint start, jint count, jint contextCount, jint dirFlags) {
AutoMutex _l(mLock);
nsecs_t startTime = 0;
if (mDebugEnabled) {
@ -95,7 +95,7 @@ sp<TextLayoutValue> TextLayoutCache::getValue(const SkPaint* paint,
}
// Create the key
TextLayoutCacheKey key(paint, text, start, count, contextCount);
TextLayoutCacheKey key(paint, text, start, count, contextCount, dirFlags);
// Get value from cache if possible
sp<TextLayoutValue> value = mCache.get(key);
@ -111,7 +111,7 @@ sp<TextLayoutValue> TextLayoutCache::getValue(const SkPaint* paint,
// Compute advances and store them
mShaper->computeValues(value.get(), paint,
reinterpret_cast<const UChar*>(key.getText()), start, count,
size_t(contextCount));
size_t(contextCount), int(dirFlags));
if (mDebugEnabled) {
value->setElapsedTime(systemTime(SYSTEM_TIME_MONOTONIC) - startTime);
@ -218,13 +218,14 @@ void TextLayoutCache::dumpCacheStats() {
* TextLayoutCacheKey
*/
TextLayoutCacheKey::TextLayoutCacheKey(): start(0), count(0), contextCount(0),
typeface(NULL), textSize(0), textSkewX(0), textScaleX(0), flags(0),
dirFlags(0), typeface(NULL), textSize(0), textSkewX(0), textScaleX(0), flags(0),
hinting(SkPaint::kNo_Hinting), variant(SkPaint::kDefault_Variant), language() {
}
TextLayoutCacheKey::TextLayoutCacheKey(const SkPaint* paint, const UChar* text,
size_t start, size_t count, size_t contextCount) :
start(start), count(count), contextCount(contextCount) {
size_t start, size_t count, size_t contextCount, int dirFlags) :
start(start), count(count), contextCount(contextCount),
dirFlags(dirFlags) {
textCopy.setTo(text, contextCount);
typeface = paint->getTypeface();
textSize = paint->getTextSize();
@ -241,6 +242,7 @@ TextLayoutCacheKey::TextLayoutCacheKey(const TextLayoutCacheKey& other) :
start(other.start),
count(other.count),
contextCount(other.contextCount),
dirFlags(other.dirFlags),
typeface(other.typeface),
textSize(other.textSize),
textSkewX(other.textSkewX),
@ -279,6 +281,9 @@ int TextLayoutCacheKey::compare(const TextLayoutCacheKey& lhs, const TextLayoutC
deltaInt = lhs.hinting - rhs.hinting;
if (deltaInt != 0) return (deltaInt);
deltaInt = lhs.dirFlags - rhs.dirFlags;
if (deltaInt) return (deltaInt);
deltaInt = lhs.variant - rhs.variant;
if (deltaInt) return (deltaInt);
@ -354,9 +359,9 @@ TextLayoutShaper::~TextLayoutShaper() {
}
void TextLayoutShaper::computeValues(TextLayoutValue* value, const SkPaint* paint, const UChar* chars,
size_t start, size_t count, size_t contextCount) {
size_t start, size_t count, size_t contextCount, int dirFlags) {
computeValues(paint, chars, start, count, contextCount,
computeValues(paint, chars, start, count, contextCount, dirFlags,
&value->mAdvances, &value->mTotalAdvance, &value->mGlyphs, &value->mPos);
#if DEBUG_ADVANCES
ALOGD("Advances - start = %d, count = %d, contextCount = %d, totalAdvance = %f", start, count,
@ -365,7 +370,7 @@ void TextLayoutShaper::computeValues(TextLayoutValue* value, const SkPaint* pain
}
void TextLayoutShaper::computeValues(const SkPaint* paint, const UChar* chars,
size_t start, size_t count, size_t contextCount,
size_t start, size_t count, size_t contextCount, int dirFlags,
Vector<jfloat>* const outAdvances, jfloat* outTotalAdvance,
Vector<jchar>* const outGlyphs, Vector<jfloat>* const outPos) {
*outTotalAdvance = 0;
@ -373,94 +378,110 @@ void TextLayoutShaper::computeValues(const SkPaint* paint, const UChar* chars,
return;
}
UBiDiLevel bidiReq = UBIDI_DEFAULT_LTR;
UBiDiLevel bidiReq = 0;
bool forceLTR = false;
bool forceRTL = false;
switch (dirFlags & kBidi_Mask) {
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
}
bool useSingleRun = false;
bool isRTL = false;
UBiDi* bidi = ubidi_open();
if (bidi) {
UErrorCode status = U_ZERO_ERROR;
bool isRTL = forceRTL;
if (forceLTR || forceRTL) {
useSingleRun = true;
} else {
UBiDi* bidi = ubidi_open();
if (bidi) {
UErrorCode status = U_ZERO_ERROR;
#if DEBUG_GLYPHS
ALOGD("******** ComputeValues -- start");
ALOGD(" -- string = '%s'", String8(chars + start, count).string());
ALOGD(" -- start = %d", start);
ALOGD(" -- count = %d", count);
ALOGD(" -- contextCount = %d", contextCount);
ALOGD(" -- bidiReq = %d", bidiReq);
ALOGD("******** ComputeValues -- start");
ALOGD(" -- string = '%s'", String8(chars + start, count).string());
ALOGD(" -- start = %d", start);
ALOGD(" -- count = %d", count);
ALOGD(" -- contextCount = %d", contextCount);
ALOGD(" -- bidiReq = %d", bidiReq);
#endif
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
ssize_t rc = ubidi_countRuns(bidi, &status);
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
ssize_t rc = ubidi_countRuns(bidi, &status);
#if DEBUG_GLYPHS
ALOGD(" -- paraDir = %d", paraDir);
ALOGD(" -- run-count = %d", int(rc));
ALOGD(" -- dirFlags = %d", dirFlags);
ALOGD(" -- paraDir = %d", paraDir);
ALOGD(" -- run-count = %d", int(rc));
#endif
if (U_SUCCESS(status) && rc == 1) {
// Normal case: one run, status is ok
isRTL = (paraDir == 1);
useSingleRun = true;
} else if (!U_SUCCESS(status) || rc < 1) {
ALOGW("Need to force to single run -- string = '%s',"
" status = %d, rc = %d",
String8(chars + start, count).string(), status, int(rc));
isRTL = (paraDir == 1);
useSingleRun = true;
} else {
int32_t end = start + count;
for (size_t i = 0; i < size_t(rc); ++i) {
int32_t startRun = -1;
int32_t lengthRun = -1;
UBiDiDirection runDir = ubidi_getVisualRun(bidi, i, &startRun, &lengthRun);
if (U_SUCCESS(status) && rc == 1) {
// Normal case: one run, status is ok
isRTL = (paraDir == 1);
useSingleRun = true;
} else if (!U_SUCCESS(status) || rc < 1) {
ALOGW("Need to force to single run -- string = '%s',"
" status = %d, rc = %d",
String8(chars + start, count).string(), status, int(rc));
isRTL = (paraDir == 1);
useSingleRun = true;
} else {
int32_t end = start + count;
for (size_t i = 0; i < size_t(rc); ++i) {
int32_t startRun = -1;
int32_t lengthRun = -1;
UBiDiDirection runDir = ubidi_getVisualRun(bidi, i, &startRun, &lengthRun);
if (startRun == -1 || lengthRun == -1) {
// Something went wrong when getting the visual run, need to clear
// already computed data before doing a single run pass
ALOGW("Visual run is not valid");
outGlyphs->clear();
outAdvances->clear();
outPos->clear();
*outTotalAdvance = 0;
isRTL = (paraDir == 1);
useSingleRun = true;
break;
}
if (startRun == -1 || lengthRun == -1) {
// Something went wrong when getting the visual run, need to clear
// already computed data before doing a single run pass
ALOGW("Visual run is not valid");
outGlyphs->clear();
outAdvances->clear();
outPos->clear();
*outTotalAdvance = 0;
isRTL = (paraDir == 1);
useSingleRun = true;
break;
}
if (startRun >= end) {
continue;
}
int32_t endRun = startRun + lengthRun;
if (endRun <= int32_t(start)) {
continue;
}
if (startRun < int32_t(start)) {
startRun = int32_t(start);
}
if (endRun > end) {
endRun = end;
}
if (startRun >= end) {
continue;
}
int32_t endRun = startRun + lengthRun;
if (endRun <= int32_t(start)) {
continue;
}
if (startRun < int32_t(start)) {
startRun = int32_t(start);
}
if (endRun > end) {
endRun = end;
}
lengthRun = endRun - startRun;
isRTL = (runDir == UBIDI_RTL);
lengthRun = endRun - startRun;
isRTL = (runDir == UBIDI_RTL);
#if DEBUG_GLYPHS
ALOGD("Processing Bidi Run = %d -- run-start = %d, run-len = %d, isRTL = %d",
i, startRun, lengthRun, isRTL);
ALOGD("Processing Bidi Run = %d -- run-start = %d, run-len = %d, isRTL = %d",
i, startRun, lengthRun, isRTL);
#endif
computeRunValues(paint, chars, startRun, lengthRun, contextCount, isRTL,
outAdvances, outTotalAdvance, outGlyphs, outPos);
computeRunValues(paint, chars, startRun, lengthRun, contextCount, isRTL,
outAdvances, outTotalAdvance, outGlyphs, outPos);
}
}
} else {
ALOGW("Cannot set Para");
useSingleRun = true;
isRTL = (bidiReq = 1) || (bidiReq = UBIDI_DEFAULT_RTL);
}
ubidi_close(bidi);
} else {
ALOGW("Cannot set Para");
ALOGW("Cannot ubidi_open()");
useSingleRun = true;
isRTL = (bidiReq = 1) || (bidiReq = UBIDI_DEFAULT_RTL);
}
ubidi_close(bidi);
} else {
ALOGW("Cannot ubidi_open()");
useSingleRun = true;
isRTL = (bidiReq = 1) || (bidiReq = UBIDI_DEFAULT_RTL);
}
// Default single run case
@ -897,11 +918,11 @@ TextLayoutEngine::~TextLayoutEngine() {
}
sp<TextLayoutValue> TextLayoutEngine::getValue(const SkPaint* paint, const jchar* text,
jint start, jint count, jint contextCount) {
jint start, jint count, jint contextCount, jint dirFlags) {
sp<TextLayoutValue> value;
#if USE_TEXT_LAYOUT_CACHE
value = mTextLayoutCache->getValue(paint, text, start, count,
contextCount);
contextCount, dirFlags);
if (value == NULL) {
ALOGE("Cannot get TextLayoutCache value for text = '%s'",
String8(text + start, count).string());
@ -909,7 +930,7 @@ sp<TextLayoutValue> TextLayoutEngine::getValue(const SkPaint* paint, const jchar
#else
value = new TextLayoutValue(count);
mShaper->computeValues(value.get(), paint,
reinterpret_cast<const UChar*>(text), start, count, contextCount);
reinterpret_cast<const UChar*>(text), start, count, contextCount, dirFlags);
#endif
return value;
}

View File

@ -70,7 +70,7 @@ public:
TextLayoutCacheKey();
TextLayoutCacheKey(const SkPaint* paint, const UChar* text, size_t start, size_t count,
size_t contextCount);
size_t contextCount, int dirFlags);
TextLayoutCacheKey(const TextLayoutCacheKey& other);
@ -97,6 +97,7 @@ private:
size_t start;
size_t count;
size_t contextCount;
int dirFlags;
SkTypeface* typeface;
SkScalar textSize;
SkScalar textSkewX;
@ -180,7 +181,7 @@ public:
virtual ~TextLayoutShaper();
void computeValues(TextLayoutValue* value, const SkPaint* paint, const UChar* chars,
size_t start, size_t count, size_t contextCount);
size_t start, size_t count, size_t contextCount, int dirFlags);
void purgeCaches();
@ -214,7 +215,7 @@ private:
size_t shapeFontRun(const SkPaint* paint);
void computeValues(const SkPaint* paint, const UChar* chars,
size_t start, size_t count, size_t contextCount,
size_t start, size_t count, size_t contextCount, int dirFlags,
Vector<jfloat>* const outAdvances, jfloat* outTotalAdvance,
Vector<jchar>* const outGlyphs, Vector<jfloat>* const outPos);
@ -251,7 +252,7 @@ public:
void operator()(TextLayoutCacheKey& text, sp<TextLayoutValue>& desc);
sp<TextLayoutValue> getValue(const SkPaint* paint, const jchar* text, jint start,
jint count, jint contextCount);
jint count, jint contextCount, jint dirFlags);
/**
* Clear the cache
@ -303,7 +304,7 @@ public:
* the call. Be careful of this when doing optimization.
**/
sp<TextLayoutValue> getValue(const SkPaint* paint, const jchar* text, jint start,
jint count, jint contextCount);
jint count, jint contextCount, jint dirFlags);
void purgeCaches();

View File

@ -568,9 +568,9 @@ static void android_view_GLES20Canvas_resetPaintFilter(JNIEnv* env, jobject claz
// ----------------------------------------------------------------------------
static void renderText(OpenGLRenderer* renderer, const jchar* text, int count,
jfloat x, jfloat y, SkPaint* paint) {
jfloat x, jfloat y, int flags, SkPaint* paint) {
sp<TextLayoutValue> value = TextLayoutEngine::getInstance().getValue(paint,
text, 0, count, count);
text, 0, count, count, flags);
if (value == NULL) {
return;
}
@ -584,9 +584,9 @@ static void renderText(OpenGLRenderer* renderer, const jchar* text, int count,
}
static void renderTextOnPath(OpenGLRenderer* renderer, const jchar* text, int count,
SkPath* path, jfloat hOffset, jfloat vOffset, SkPaint* paint) {
SkPath* path, jfloat hOffset, jfloat vOffset, int flags, SkPaint* paint) {
sp<TextLayoutValue> value = TextLayoutEngine::getInstance().getValue(paint,
text, 0, count, count);
text, 0, count, count, flags);
if (value == NULL) {
return;
}
@ -599,9 +599,9 @@ static void renderTextOnPath(OpenGLRenderer* renderer, const jchar* text, int co
static void renderTextRun(OpenGLRenderer* renderer, const jchar* text,
jint start, jint count, jint contextCount, jfloat x, jfloat y,
SkPaint* paint) {
int flags, SkPaint* paint) {
sp<TextLayoutValue> value = TextLayoutEngine::getInstance().getValue(paint,
text, start, count, contextCount);
text, start, count, contextCount, flags);
if (value == NULL) {
return;
}
@ -616,62 +616,64 @@ static void renderTextRun(OpenGLRenderer* renderer, const jchar* text,
static void android_view_GLES20Canvas_drawTextArray(JNIEnv* env, jobject clazz,
OpenGLRenderer* renderer, jcharArray text, jint index, jint count,
jfloat x, jfloat y, SkPaint* paint) {
jfloat x, jfloat y, jint flags, SkPaint* paint) {
jchar* textArray = env->GetCharArrayElements(text, NULL);
renderText(renderer, textArray + index, count, x, y, paint);
renderText(renderer, textArray + index, count, x, y, flags, paint);
env->ReleaseCharArrayElements(text, textArray, JNI_ABORT);
}
static void android_view_GLES20Canvas_drawText(JNIEnv* env, jobject clazz,
OpenGLRenderer* renderer, jstring text, jint start, jint end,
jfloat x, jfloat y, SkPaint* paint) {
jfloat x, jfloat y, jint flags, SkPaint* paint) {
const jchar* textArray = env->GetStringChars(text, NULL);
renderText(renderer, textArray + start, end - start, x, y, paint);
renderText(renderer, textArray + start, end - start, x, y, flags, paint);
env->ReleaseStringChars(text, textArray);
}
static void android_view_GLES20Canvas_drawTextArrayOnPath(JNIEnv* env, jobject clazz,
OpenGLRenderer* renderer, jcharArray text, jint index, jint count,
SkPath* path, jfloat hOffset, jfloat vOffset, SkPaint* paint) {
SkPath* path, jfloat hOffset, jfloat vOffset, jint flags, SkPaint* paint) {
jchar* textArray = env->GetCharArrayElements(text, NULL);
renderTextOnPath(renderer, textArray + index, count, path,
hOffset, vOffset, paint);
hOffset, vOffset, flags, paint);
env->ReleaseCharArrayElements(text, textArray, JNI_ABORT);
}
static void android_view_GLES20Canvas_drawTextOnPath(JNIEnv* env, jobject clazz,
OpenGLRenderer* renderer, jstring text, jint start, jint end,
SkPath* path, jfloat hOffset, jfloat vOffset, SkPaint* paint) {
SkPath* path, jfloat hOffset, jfloat vOffset, jint flags, SkPaint* paint) {
const jchar* textArray = env->GetStringChars(text, NULL);
renderTextOnPath(renderer, textArray + start, end - start, path,
hOffset, vOffset, paint);
hOffset, vOffset, flags, paint);
env->ReleaseStringChars(text, textArray);
}
static void android_view_GLES20Canvas_drawTextRunArray(JNIEnv* env, jobject clazz,
OpenGLRenderer* renderer, jcharArray text, jint index, jint count,
jint contextIndex, jint contextCount, jfloat x, jfloat y, SkPaint* paint) {
jint contextIndex, jint contextCount, jfloat x, jfloat y, jint dirFlags,
SkPaint* paint) {
jchar* textArray = env->GetCharArrayElements(text, NULL);
renderTextRun(renderer, textArray + contextIndex, index - contextIndex,
count, contextCount, x, y, paint);
count, contextCount, x, y, dirFlags, paint);
env->ReleaseCharArrayElements(text, textArray, JNI_ABORT);
}
static void android_view_GLES20Canvas_drawTextRun(JNIEnv* env, jobject clazz,
OpenGLRenderer* renderer, jstring text, jint start, jint end,
jint contextStart, int contextEnd, jfloat x, jfloat y, SkPaint* paint) {
jint contextStart, int contextEnd, jfloat x, jfloat y, jint dirFlags,
SkPaint* paint) {
const jchar* textArray = env->GetStringChars(text, NULL);
jint count = end - start;
jint contextCount = contextEnd - contextStart;
renderTextRun(renderer, textArray + contextStart, start - contextStart,
count, contextCount, x, y, paint);
count, contextCount, x, y, dirFlags, paint);
env->ReleaseStringChars(text, textArray);
}
static void renderPosText(OpenGLRenderer* renderer, const jchar* text, int count,
const jfloat* positions, SkPaint* paint) {
const jfloat* positions, jint dirFlags, SkPaint* paint) {
sp<TextLayoutValue> value = TextLayoutEngine::getInstance().getValue(paint,
text, 0, count, count);
text, 0, count, count, dirFlags);
if (value == NULL) {
return;
}
@ -689,7 +691,7 @@ static void android_view_GLES20Canvas_drawPosTextArray(JNIEnv* env, jobject claz
jchar* textArray = env->GetCharArrayElements(text, NULL);
jfloat* positions = env->GetFloatArrayElements(pos, NULL);
renderPosText(renderer, textArray + index, count, positions, paint);
renderPosText(renderer, textArray + index, count, positions, kBidi_LTR, paint);
env->ReleaseFloatArrayElements(pos, positions, JNI_ABORT);
env->ReleaseCharArrayElements(text, textArray, JNI_ABORT);
@ -701,7 +703,7 @@ static void android_view_GLES20Canvas_drawPosText(JNIEnv* env, jobject clazz,
const jchar* textArray = env->GetStringChars(text, NULL);
jfloat* positions = env->GetFloatArrayElements(pos, NULL);
renderPosText(renderer, textArray + start, end - start, positions, paint);
renderPosText(renderer, textArray + start, end - start, positions, kBidi_LTR, paint);
env->ReleaseFloatArrayElements(pos, positions, JNI_ABORT);
env->ReleaseStringChars(text, textArray);
@ -1005,16 +1007,16 @@ static JNINativeMethod gMethods[] = {
{ "nSetupPaintFilter", "(III)V", (void*) android_view_GLES20Canvas_setupPaintFilter },
{ "nResetPaintFilter", "(I)V", (void*) android_view_GLES20Canvas_resetPaintFilter },
{ "nDrawText", "(I[CIIFFI)V", (void*) android_view_GLES20Canvas_drawTextArray },
{ "nDrawText", "(ILjava/lang/String;IIFFI)V",
{ "nDrawText", "(I[CIIFFII)V", (void*) android_view_GLES20Canvas_drawTextArray },
{ "nDrawText", "(ILjava/lang/String;IIFFII)V",
(void*) android_view_GLES20Canvas_drawText },
{ "nDrawTextOnPath", "(I[CIIIFFI)V", (void*) android_view_GLES20Canvas_drawTextArrayOnPath },
{ "nDrawTextOnPath", "(ILjava/lang/String;IIIFFI)V",
{ "nDrawTextOnPath", "(I[CIIIFFII)V", (void*) android_view_GLES20Canvas_drawTextArrayOnPath },
{ "nDrawTextOnPath", "(ILjava/lang/String;IIIFFII)V",
(void*) android_view_GLES20Canvas_drawTextOnPath },
{ "nDrawTextRun", "(I[CIIIIFFI)V", (void*) android_view_GLES20Canvas_drawTextRunArray },
{ "nDrawTextRun", "(ILjava/lang/String;IIIIFFI)V",
{ "nDrawTextRun", "(I[CIIIIFFII)V", (void*) android_view_GLES20Canvas_drawTextRunArray },
{ "nDrawTextRun", "(ILjava/lang/String;IIIIFFII)V",
(void*) android_view_GLES20Canvas_drawTextRun },
{ "nDrawPosText", "(I[CII[FI)V", (void*) android_view_GLES20Canvas_drawPosTextArray },

View File

@ -62,6 +62,18 @@ public class Canvas {
@SuppressWarnings({"UnusedDeclaration"})
private int mSurfaceFormat;
/**
* Flag for drawTextRun indicating left-to-right run direction.
* @hide
*/
public static final int DIRECTION_LTR = 0;
/**
* Flag for drawTextRun indicating right-to-left run direction.
* @hide
*/
public static final int DIRECTION_RTL = 1;
// Maximum bitmap size as defined in Skia's native code
// (see SkCanvas.cpp, SkDraw.cpp)
private static final int MAXMIMUM_BITMAP_SIZE = 32766;
@ -1333,7 +1345,8 @@ public class Canvas {
(text.length - index - count)) < 0) {
throw new IndexOutOfBoundsException();
}
native_drawText(mNativeCanvas, text, index, count, x, y, paint.mNativePaint);
native_drawText(mNativeCanvas, text, index, count, x, y, paint.mBidiFlags,
paint.mNativePaint);
}
/**
@ -1346,7 +1359,8 @@ public class Canvas {
* @param paint The paint used for the text (e.g. color, size, style)
*/
public void drawText(String text, float x, float y, Paint paint) {
native_drawText(mNativeCanvas, text, 0, text.length(), x, y, paint.mNativePaint);
native_drawText(mNativeCanvas, text, 0, text.length(), x, y, paint.mBidiFlags,
paint.mNativePaint);
}
/**
@ -1364,7 +1378,8 @@ public class Canvas {
if ((start | end | (end - start) | (text.length() - end)) < 0) {
throw new IndexOutOfBoundsException();
}
native_drawText(mNativeCanvas, text, start, end, x, y, paint.mNativePaint);
native_drawText(mNativeCanvas, text, start, end, x, y, paint.mBidiFlags,
paint.mNativePaint);
}
/**
@ -1383,14 +1398,16 @@ public class Canvas {
public void drawText(CharSequence text, int start, int end, float x, float y, Paint paint) {
if (text instanceof String || text instanceof SpannedString ||
text instanceof SpannableString) {
native_drawText(mNativeCanvas, text.toString(), start, end, x, y, paint.mNativePaint);
native_drawText(mNativeCanvas, text.toString(), start, end, x, y,
paint.mBidiFlags, paint.mNativePaint);
} else if (text instanceof GraphicsOperations) {
((GraphicsOperations) text).drawText(this, start, end, x, y,
paint);
} else {
char[] buf = TemporaryBuffer.obtain(end - start);
TextUtils.getChars(text, start, end, buf, 0);
native_drawText(mNativeCanvas, buf, 0, end - start, x, y, paint.mNativePaint);
native_drawText(mNativeCanvas, buf, 0, end - start, x, y,
paint.mBidiFlags, paint.mNativePaint);
TemporaryBuffer.recycle(buf);
}
}
@ -1411,11 +1428,13 @@ public class Canvas {
* + count.
* @param x the x position at which to draw the text
* @param y the y position at which to draw the text
* @param dir the run direction, either {@link #DIRECTION_LTR} or
* {@link #DIRECTION_RTL}.
* @param paint the paint
* @hide
*/
public void drawTextRun(char[] text, int index, int count, int contextIndex, int contextCount,
float x, float y, Paint paint) {
float x, float y, int dir, Paint paint) {
if (text == null) {
throw new NullPointerException("text is null");
@ -1426,9 +1445,12 @@ public class Canvas {
if ((index | count | text.length - index - count) < 0) {
throw new IndexOutOfBoundsException();
}
if (dir != DIRECTION_LTR && dir != DIRECTION_RTL) {
throw new IllegalArgumentException("unknown dir: " + dir);
}
native_drawTextRun(mNativeCanvas, text, index, count,
contextIndex, contextCount, x, y, paint.mNativePaint);
contextIndex, contextCount, x, y, dir, paint.mNativePaint);
}
/**
@ -1444,11 +1466,12 @@ public class Canvas {
* position can be used for shaping context.
* @param x the x position at which to draw the text
* @param y the y position at which to draw the text
* @param dir the run direction, either 0 for LTR or 1 for RTL.
* @param paint the paint
* @hide
*/
public void drawTextRun(CharSequence text, int start, int end, int contextStart, int contextEnd,
float x, float y, Paint paint) {
float x, float y, int dir, Paint paint) {
if (text == null) {
throw new NullPointerException("text is null");
@ -1460,20 +1483,22 @@ public class Canvas {
throw new IndexOutOfBoundsException();
}
int flags = dir == 0 ? 0 : 1;
if (text instanceof String || text instanceof SpannedString ||
text instanceof SpannableString) {
native_drawTextRun(mNativeCanvas, text.toString(), start, end,
contextStart, contextEnd, x, y, paint.mNativePaint);
contextStart, contextEnd, x, y, flags, paint.mNativePaint);
} else if (text instanceof GraphicsOperations) {
((GraphicsOperations) text).drawTextRun(this, start, end,
contextStart, contextEnd, x, y, paint);
contextStart, contextEnd, x, y, flags, paint);
} else {
int contextLen = contextEnd - contextStart;
int len = end - start;
char[] buf = TemporaryBuffer.obtain(contextLen);
TextUtils.getChars(text, contextStart, contextEnd, buf, 0);
native_drawTextRun(mNativeCanvas, buf, start - contextStart, len,
0, contextLen, x, y, paint.mNativePaint);
0, contextLen, x, y, flags, paint.mNativePaint);
TemporaryBuffer.recycle(buf);
}
}
@ -1539,7 +1564,8 @@ public class Canvas {
throw new ArrayIndexOutOfBoundsException();
}
native_drawTextOnPath(mNativeCanvas, text, index, count,
path.ni(), hOffset, vOffset, paint.mNativePaint);
path.ni(), hOffset, vOffset,
paint.mBidiFlags, paint.mNativePaint);
}
/**
@ -1558,7 +1584,7 @@ public class Canvas {
public void drawTextOnPath(String text, Path path, float hOffset, float vOffset, Paint paint) {
if (text.length() > 0) {
native_drawTextOnPath(mNativeCanvas, text, path.ni(), hOffset, vOffset,
paint.mNativePaint);
paint.mBidiFlags, paint.mNativePaint);
}
}
@ -1720,18 +1746,18 @@ public class Canvas {
private static native void native_drawText(int nativeCanvas, char[] text,
int index, int count, float x,
float y, int paint);
float y, int flags, int paint);
private static native void native_drawText(int nativeCanvas, String text,
int start, int end, float x,
float y, int paint);
float y, int flags, int paint);
private static native void native_drawTextRun(int nativeCanvas, String text,
int start, int end, int contextStart, int contextEnd,
float x, float y, int paint);
float x, float y, int flags, int paint);
private static native void native_drawTextRun(int nativeCanvas, char[] text,
int start, int count, int contextStart, int contextCount,
float x, float y, int paint);
float x, float y, int flags, int paint);
private static native void native_drawPosText(int nativeCanvas,
char[] text, int index,
@ -1744,13 +1770,13 @@ public class Canvas {
char[] text, int index,
int count, int path,
float hOffset,
float vOffset,
float vOffset, int bidiFlags,
int paint);
private static native void native_drawTextOnPath(int nativeCanvas,
String text, int path,
float hOffset,
float vOffset,
int paint);
int flags, int paint);
private static native void native_drawPicture(int nativeCanvas,
int nativePicture);
private static native void finalizer(int nativeCanvas);

View File

@ -69,6 +69,11 @@ public class Paint {
*/
public int shadowColor;
/**
* @hide
*/
public int mBidiFlags = BIDI_DEFAULT_LTR;
static final Style[] sStyleArray = {
Style.FILL, Style.STROKE, Style.FILL_AND_STROKE
};
@ -114,6 +119,74 @@ public class Paint {
*/
public static final int HINTING_ON = 0x1;
/**
* Bidi flag to set LTR paragraph direction.
*
* @hide
*/
public static final int BIDI_LTR = 0x0;
/**
* Bidi flag to set RTL paragraph direction.
*
* @hide
*/
public static final int BIDI_RTL = 0x1;
/**
* Bidi flag to detect paragraph direction via heuristics, defaulting to
* LTR.
*
* @hide
*/
public static final int BIDI_DEFAULT_LTR = 0x2;
/**
* Bidi flag to detect paragraph direction via heuristics, defaulting to
* RTL.
*
* @hide
*/
public static final int BIDI_DEFAULT_RTL = 0x3;
/**
* Bidi flag to override direction to all LTR (ignore bidi).
*
* @hide
*/
public static final int BIDI_FORCE_LTR = 0x4;
/**
* Bidi flag to override direction to all RTL (ignore bidi).
*
* @hide
*/
public static final int BIDI_FORCE_RTL = 0x5;
/**
* Maximum Bidi flag value.
* @hide
*/
private static final int BIDI_MAX_FLAG_VALUE = BIDI_FORCE_RTL;
/**
* Mask for bidi flags.
* @hide
*/
private static final int BIDI_FLAG_MASK = 0x7;
/**
* Flag for getTextRunAdvances indicating left-to-right run direction.
* @hide
*/
public static final int DIRECTION_LTR = 0;
/**
* Flag for getTextRunAdvances indicating right-to-left run direction.
* @hide
*/
public static final int DIRECTION_RTL = 1;
/**
* Option for getTextRunCursor to compute the valid cursor after
* offset or the limit of the context, whichever is less.
@ -322,6 +395,7 @@ public class Paint {
shadowRadius = 0;
shadowColor = 0;
mBidiFlags = BIDI_DEFAULT_LTR;
setTextLocale(Locale.getDefault());
}
@ -361,6 +435,7 @@ public class Paint {
shadowRadius = paint.shadowRadius;
shadowColor = paint.shadowColor;
mBidiFlags = paint.mBidiFlags;
mLocale = paint.mLocale;
}
@ -376,6 +451,29 @@ public class Paint {
}
}
/**
* Return the bidi flags on the paint.
*
* @return the bidi flags on the paint
* @hide
*/
public int getBidiFlags() {
return mBidiFlags;
}
/**
* Set the bidi flags on the paint.
* @hide
*/
public void setBidiFlags(int flags) {
// only flag value is the 3-bit BIDI control setting
flags &= BIDI_FLAG_MASK;
if (flags > BIDI_MAX_FLAG_VALUE) {
throw new IllegalArgumentException("unknown bidi flag: " + flags);
}
mBidiFlags = flags;
}
/**
* Return the paint's flags. Use the Flag enum to test flag values.
*
@ -1569,20 +1667,77 @@ public class Paint {
return getTextWidths(text, 0, text.length(), widths);
}
/**
* Return the glyph Ids for the characters in the string.
*
* @param text The text to measure
* @param start The index of the first char to to measure
* @param end The end of the text slice 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 glyphs array to receive the glyph Ids of the characters.
* Must be at least a large as the text.
* @return the number of glyphs in the returned array
*
* @hide
*
* Used only for BiDi / RTL Tests
*/
public int getTextGlyphs(String text, int start, int end, int contextStart, int contextEnd,
int flags, char[] glyphs) {
if (text == null) {
throw new IllegalArgumentException("text cannot be null");
}
if (flags != DIRECTION_LTR && flags != DIRECTION_RTL) {
throw new IllegalArgumentException("unknown flags value: " + flags);
}
if ((start | end | contextStart | contextEnd | (end - start)
| (start - contextStart) | (contextEnd - end) | (text.length() - end)
| (text.length() - contextEnd)) < 0) {
throw new IndexOutOfBoundsException();
}
if (end - start > glyphs.length) {
throw new ArrayIndexOutOfBoundsException();
}
return native_getTextGlyphs(mNativePaint, text, start, end, contextStart, contextEnd,
flags, glyphs);
}
/**
* Convenience overload that takes a char array instead of a
* String.
*
* @see #getTextRunAdvances(String, int, int, int, int, float[], int)
* @see #getTextRunAdvances(String, int, int, int, int, int, float[], int)
* @hide
*/
public float getTextRunAdvances(char[] chars, int index, int count,
int contextIndex, int contextCount, float[] advances,
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");
}
if (flags != DIRECTION_LTR && flags != DIRECTION_RTL) {
throw new IllegalArgumentException("unknown flags value: " + flags);
}
if ((index | count | contextIndex | contextCount | advancesIndex
| (index - contextIndex) | (contextCount - count)
| ((contextIndex + contextCount) - (index + count))
@ -1597,13 +1752,13 @@ public class Paint {
}
if (!mHasCompatScaling) {
return native_getTextRunAdvances(mNativePaint, chars, index, count,
contextIndex, contextCount, advances, advancesIndex);
contextIndex, contextCount, flags, advances, advancesIndex, reserved);
}
final float oldSize = getTextSize();
setTextSize(oldSize * mCompatScaling);
float res = native_getTextRunAdvances(mNativePaint, chars, index, count,
contextIndex, contextCount, advances, advancesIndex);
contextIndex, contextCount, flags, advances, advancesIndex, reserved);
setTextSize(oldSize);
if (advances != null) {
@ -1618,12 +1773,26 @@ public class Paint {
* Convenience overload that takes a CharSequence instead of a
* String.
*
* @see #getTextRunAdvances(String, int, int, int, int, float[], int)
* @see #getTextRunAdvances(String, int, int, int, int, int, float[], int)
* @hide
*/
public float getTextRunAdvances(CharSequence text, int start, int end,
int contextStart, int contextEnd, float[] advances,
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");
@ -1638,16 +1807,16 @@ public class Paint {
if (text instanceof String) {
return getTextRunAdvances((String) text, start, end,
contextStart, contextEnd, advances, advancesIndex);
contextStart, contextEnd, flags, advances, advancesIndex, reserved);
}
if (text instanceof SpannedString ||
text instanceof SpannableString) {
return getTextRunAdvances(text.toString(), start, end,
contextStart, contextEnd, advances, advancesIndex);
contextStart, contextEnd, flags, advances, advancesIndex, reserved);
}
if (text instanceof GraphicsOperations) {
return ((GraphicsOperations) text).getTextRunAdvances(start, end,
contextStart, contextEnd, advances, advancesIndex, this);
contextStart, contextEnd, flags, advances, advancesIndex, this);
}
if (text.length() == 0 || end == start) {
return 0f;
@ -1658,7 +1827,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, advances, advancesIndex);
0, contextLen, flags, advances, advancesIndex, reserved);
TemporaryBuffer.recycle(buf);
return result;
}
@ -1695,6 +1864,8 @@ public class Paint {
* 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
@ -1704,11 +1875,63 @@ public class Paint {
* @hide
*/
public float getTextRunAdvances(String text, int start, int end, int contextStart,
int contextEnd, float[] advances, int advancesIndex) {
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");
}
if (flags != DIRECTION_LTR && flags != DIRECTION_RTL) {
throw new IllegalArgumentException("unknown flags value: " + flags);
}
if ((start | end | contextStart | contextEnd | advancesIndex | (end - start)
| (start - contextStart) | (contextEnd - end)
| (text.length() - contextEnd)
@ -1723,13 +1946,13 @@ public class Paint {
if (!mHasCompatScaling) {
return native_getTextRunAdvances(mNativePaint, text, start, end,
contextStart, contextEnd, advances, advancesIndex);
contextStart, contextEnd, flags, advances, advancesIndex, reserved);
}
final float oldSize = getTextSize();
setTextSize(oldSize * mCompatScaling);
float totalAdvance = native_getTextRunAdvances(mNativePaint, text, start, end,
contextStart, contextEnd, advances, advancesIndex);
contextStart, contextEnd, flags, advances, advancesIndex, reserved);
setTextSize(oldSize);
if (advances != null) {
@ -1758,6 +1981,7 @@ public class Paint {
* @param text the text
* @param contextStart the start of the context
* @param contextLength the length of the context
* @param flags either {@link #DIRECTION_RTL} or {@link #DIRECTION_LTR}
* @param offset the cursor position to move from
* @param cursorOpt how to move the cursor, one of {@link #CURSOR_AFTER},
* {@link #CURSOR_AT_OR_AFTER}, {@link #CURSOR_BEFORE},
@ -1766,7 +1990,7 @@ public class Paint {
* @hide
*/
public int getTextRunCursor(char[] text, int contextStart, int contextLength,
int offset, int cursorOpt) {
int flags, int offset, int cursorOpt) {
int contextEnd = contextStart + contextLength;
if (((contextStart | contextEnd | offset | (contextEnd - contextStart)
| (offset - contextStart) | (contextEnd - offset)
@ -1776,7 +2000,7 @@ public class Paint {
}
return native_getTextRunCursor(mNativePaint, text,
contextStart, contextLength, offset, cursorOpt);
contextStart, contextLength, flags, offset, cursorOpt);
}
/**
@ -1797,6 +2021,7 @@ public class Paint {
* @param text the text
* @param contextStart the start of the context
* @param contextEnd the end of the context
* @param flags either {@link #DIRECTION_RTL} or {@link #DIRECTION_LTR}
* @param offset the cursor position to move from
* @param cursorOpt how to move the cursor, one of {@link #CURSOR_AFTER},
* {@link #CURSOR_AT_OR_AFTER}, {@link #CURSOR_BEFORE},
@ -1805,22 +2030,22 @@ public class Paint {
* @hide
*/
public int getTextRunCursor(CharSequence text, int contextStart,
int contextEnd, int offset, int cursorOpt) {
int contextEnd, int flags, int offset, int cursorOpt) {
if (text instanceof String || text instanceof SpannedString ||
text instanceof SpannableString) {
return getTextRunCursor(text.toString(), contextStart, contextEnd,
offset, cursorOpt);
flags, offset, cursorOpt);
}
if (text instanceof GraphicsOperations) {
return ((GraphicsOperations) text).getTextRunCursor(
contextStart, contextEnd, offset, cursorOpt, this);
contextStart, contextEnd, flags, offset, cursorOpt, this);
}
int contextLen = contextEnd - contextStart;
char[] buf = TemporaryBuffer.obtain(contextLen);
TextUtils.getChars(text, contextStart, contextEnd, buf, 0);
int result = getTextRunCursor(buf, 0, contextLen, offset - contextStart, cursorOpt);
int result = getTextRunCursor(buf, 0, contextLen, flags, offset - contextStart, cursorOpt);
TemporaryBuffer.recycle(buf);
return result;
}
@ -1843,6 +2068,7 @@ public class Paint {
* @param text the text
* @param contextStart the start of the context
* @param contextEnd the end of the context
* @param flags either {@link #DIRECTION_RTL} or {@link #DIRECTION_LTR}
* @param offset the cursor position to move from
* @param cursorOpt how to move the cursor, one of {@link #CURSOR_AFTER},
* {@link #CURSOR_AT_OR_AFTER}, {@link #CURSOR_BEFORE},
@ -1860,7 +2086,7 @@ public class Paint {
}
return native_getTextRunCursor(mNativePaint, text,
contextStart, contextEnd, offset, cursorOpt);
contextStart, contextEnd, flags, offset, cursorOpt);
}
/**
@ -1881,7 +2107,7 @@ public class Paint {
if ((index | count) < 0 || index + count > text.length) {
throw new ArrayIndexOutOfBoundsException();
}
native_getTextPath(mNativePaint, text, index, count, x, y,
native_getTextPath(mNativePaint, mBidiFlags, text, index, count, x, y,
path.ni());
}
@ -1903,7 +2129,7 @@ public class Paint {
if ((start | end | (end - start) | (text.length() - end)) < 0) {
throw new IndexOutOfBoundsException();
}
native_getTextPath(mNativePaint, text, start, end, x, y,
native_getTextPath(mNativePaint, mBidiFlags, text, start, end, x, y,
path.ni());
}
@ -1995,22 +2221,26 @@ public class Paint {
private static native int native_getTextWidths(int native_object,
String text, int start, int end, float[] widths);
private static native int native_getTextGlyphs(int native_object,
String text, int start, int end, int contextStart, int contextEnd,
int flags, char[] glyphs);
private static native float native_getTextRunAdvances(int native_object,
char[] text, int index, int count, int contextIndex, int contextCount,
float[] advances, int advancesIndex);
int flags, float[] advances, int advancesIndex, int reserved);
private static native float native_getTextRunAdvances(int native_object,
String text, int start, int end, int contextStart, int contextEnd,
float[] advances, int advancesIndex);
int flags, float[] advances, int advancesIndex, int reserved);
private native int native_getTextRunCursor(int native_object, char[] text,
int contextStart, int contextLength, int offset, int cursorOpt);
int contextStart, int contextLength, int flags, int offset, int cursorOpt);
private native int native_getTextRunCursor(int native_object, String text,
int contextStart, int contextEnd, int offset, int cursorOpt);
int contextStart, int contextEnd, int flags, int offset, int cursorOpt);
private static native void native_getTextPath(int native_object, char[] text,
int index, int count, float x, float y, int path);
private static native void native_getTextPath(int native_object, String text,
int start, int end, float x, float y, int path);
private static native void native_getTextPath(int native_object, int bidiFlags,
char[] text, int index, int count, float x, float y, int path);
private static native void native_getTextPath(int native_object, int bidiFlags,
String text, int start, int end, float x, float y, int path);
private static native void nativeGetStringBounds(int nativePaint,
String text, int start, int end, Rect bounds);
private static native void nativeGetCharArrayBounds(int nativePaint,

View File

@ -0,0 +1,40 @@
<?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,6 +101,7 @@ 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

@ -0,0 +1,67 @@
/*
* 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

@ -0,0 +1,212 @@
/*
* 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]);
// }
}
}