diff options
| -rw-r--r-- | core/java/android/text/GraphicsOperations.java | 6 | ||||
| -rw-r--r-- | core/java/android/text/SpannableStringBuilder.java | 38 | ||||
| -rw-r--r-- | core/java/android/text/TextLine.java | 43 | ||||
| -rw-r--r-- | core/java/android/widget/TextView.java | 5 | ||||
| -rw-r--r-- | core/jni/android/graphics/Canvas.cpp | 255 | ||||
| -rw-r--r-- | graphics/java/android/graphics/Canvas.java | 137 | ||||
| -rw-r--r-- | graphics/java/android/graphics/Paint.java | 95 |
7 files changed, 479 insertions, 100 deletions
diff --git a/core/java/android/text/GraphicsOperations.java b/core/java/android/text/GraphicsOperations.java index c3bd0ae..d51bf7c 100644 --- a/core/java/android/text/GraphicsOperations.java +++ b/core/java/android/text/GraphicsOperations.java @@ -34,6 +34,12 @@ extends CharSequence float x, float y, Paint p); /** + * Just like {@link Canvas#drawTextRun}. + */ + void drawTextRun(Canvas c, int start, int end, + float x, float y, int flags, Paint p); + + /** * Just like {@link Paint#measureText}. */ float measureText(int start, int end, Paint p); diff --git a/core/java/android/text/SpannableStringBuilder.java b/core/java/android/text/SpannableStringBuilder.java index caaafa1..7563179 100644 --- a/core/java/android/text/SpannableStringBuilder.java +++ b/core/java/android/text/SpannableStringBuilder.java @@ -17,8 +17,9 @@ package android.text; import com.android.internal.util.ArrayUtils; -import android.graphics.Paint; + import android.graphics.Canvas; +import android.graphics.Paint; import java.lang.reflect.Array; @@ -780,7 +781,7 @@ implements CharSequence, GetChars, Spannable, Editable, Appendable, } if (count == 0) { - return (T[]) ArrayUtils.emptyArray(kind); + return ArrayUtils.emptyArray(kind); } if (count == 1) { ret = (Object[]) Array.newInstance(kind, 1); @@ -1055,6 +1056,39 @@ implements CharSequence, GetChars, Spannable, Editable, Appendable, } /** + * Don't call this yourself -- exists for Canvas to use internally. + * {@hide} + */ + public void drawTextRun(Canvas c, int start, int end, + float x, float y, int flags, Paint p) { + checkRange("drawTextRun", start, end); + + // Assume context requires no more than 8 chars on either side. + // This is ample, only decomposed U+FDFA falls into this + // category, and no one should put a style break within it + // anyway. + int cstart = start - 8; + if (cstart < 0) { + cstart = 0; + } + int cend = end + 8; + int max = length(); + if (cend > max) { + cend = max; + } + if (cend <= mGapStart) { + c.drawTextRun(mText, start, end - start, x, y, flags, p); + } else if (cstart >= mGapStart) { + c.drawTextRun(mText, start + mGapLength, end - start, x, y, flags, p); + } else { + char[] buf = TextUtils.obtain(cend - cstart); + getChars(cstart, cend, buf, 0); + c.drawTextRun(buf, start - cstart, end - start, x, y, flags, p); + TextUtils.recycle(buf); + } + } + + /** * Don't call this yourself -- exists for Paint to use internally. * {@hide} */ diff --git a/core/java/android/text/TextLine.java b/core/java/android/text/TextLine.java index 4aeabf3..fae3fc3 100644 --- a/core/java/android/text/TextLine.java +++ b/core/java/android/text/TextLine.java @@ -951,48 +951,11 @@ class TextLine { private void drawTextRun(Canvas c, TextPaint wp, int start, int limit, boolean runIsRtl, float x, int y) { - // Since currently skia only renders text left-to-right, we need to - // put the shaped characters into visual order before rendering. - // Since we might want to re-render the line again, we swap them - // back when we're done. If we left them swapped, measurement - // would be broken since it expects the characters in logical order. - if (runIsRtl) { - swapRun(start, limit); - } + int flags = runIsRtl ? Canvas.DIRECTION_RTL : Canvas.DIRECTION_LTR; if (mCharsValid) { - c.drawText(mChars, start, limit - start, x, y, wp); + c.drawTextRun(mChars, start, limit - start, x, y, flags, wp); } else { - c.drawText(mText, mStart + start, mStart + limit, x, y, wp); - } - if (runIsRtl) { - swapRun(start, limit); - } - } - - /** - * Reverses the order of characters in the chars array between start and - * limit, used by drawTextRun. - * @param start the start of the run to reverse - * @param limit the limit of the run to reverse - */ - private void swapRun(int start, int limit) { - // First we swap all the characters one for one, then we - // do another pass looking for surrogate pairs and swapping them - // back into their logical order. - char[] chars = mChars; - for (int s = start, e = limit - 1; s < e; ++s, --e) { - char ch = chars[s]; chars[s] = chars[e]; chars[e] = ch; - } - - for (int s = start, e = limit - 1; s < e; ++s) { - char c1 = chars[s]; - if (c1 >= 0xdc00 && c1 < 0xe000) { - char c2 = chars[s+1]; - if (c2 >= 0xd800 && c2 < 0xdc00) { - chars[s++] = c2; - chars[s] = c1; - } - } + c.drawTextRun(mText, mStart + start, mStart + limit, x, y, flags, wp); } } diff --git a/core/java/android/widget/TextView.java b/core/java/android/widget/TextView.java index 64c9c99..968636b 100644 --- a/core/java/android/widget/TextView.java +++ b/core/java/android/widget/TextView.java @@ -2781,6 +2781,11 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener c.drawText(mChars, start + mStart, end - start, x, y, p); } + public void drawTextRun(Canvas c, int start, int end, + float x, float y, int flags, Paint p) { + c.drawTextRun(mChars, start + mStart, end - start, x, y, flags, p); + } + public float measureText(int start, int end, Paint p) { return p.measureText(mChars, start + mStart, end - start); } diff --git a/core/jni/android/graphics/Canvas.cpp b/core/jni/android/graphics/Canvas.cpp index e1e9536..4c7e762 100644 --- a/core/jni/android/graphics/Canvas.cpp +++ b/core/jni/android/graphics/Canvas.cpp @@ -30,6 +30,8 @@ #include "SkBoundaryPatch.h" #include "SkMeshUtils.h" +#include "unicode/ubidi.h" + #define TIME_DRAWx static uint32_t get_thread_msec() { @@ -52,6 +54,24 @@ namespace android { class SkCanvasGlue { public: + enum { + kDirection_LTR = 0, + kDirection_RTL = 1 + }; + + enum { + kDirection_Mask = 0x1 + }; + + enum { + kBidi_LTR = 0, + kBidi_RTL = 1, + kBidi_Default_LTR = 2, + kBidi_Default_RTL = 3, + kBidi_Force_LTR = 4, + kBidi_Force_RTL = 5 + }; + static void finalizer(JNIEnv* env, jobject clazz, SkCanvas* canvas) { canvas->unref(); } @@ -743,45 +763,206 @@ public: canvas->drawVertices(mode, ptCount, verts, texs, colors, NULL, indices, indexCount, *paint); } + + static void shapeRtlText__(const jchar* text, jsize len, jsize start, jsize count, jchar* shaped) { + // fake shaping, just reverse the text + for (int i = 0; i < count; ++i) { + shaped[i] = text[start + count - 1 - i]; + } + // fix surrogate pairs, if any + for (int i = 1; i < count; ++i) { + if (shaped[i] >= 0xd800 && shaped[i] < 0xdc00 && + shaped[i-1] >= 0xdc00 && shaped[i-1] < 0xe000) { + jchar c = shaped[i]; shaped[i] = shaped[i-1]; shaped[i-1] = c; + i += 1; + } + } + } + + static void drawText__(JNIEnv* env, SkCanvas* canvas, const jchar* text, jsize len, + jfloat x, jfloat y, int flags, SkPaint* paint) { + SkScalar x_ = SkFloatToScalar(x); + SkScalar y_ = SkFloatToScalar(y); + + SkPaint::Align horiz = paint->getTextAlign(); + + bool needBidi = (flags == kBidi_RTL) || (flags == kBidi_Default_RTL); + if (!needBidi && flags < kBidi_Force_LTR) { + for (int i = 0; i < len; ++i) { + if (text[i] >= 0x0590) { + needBidi = TRUE; + break; + } + } + } + + int dir = (flags == kBidi_Force_RTL) ? kDirection_RTL : kDirection_LTR; // will be reset if we run bidi + UErrorCode status = U_ZERO_ERROR; + jchar *shaped = NULL; + int32_t slen = 0; + if (needBidi || (flags == kBidi_Force_RTL)) { + shaped = (jchar *)malloc(len * sizeof(jchar)); + if (!shaped) { + status = U_MEMORY_ALLOCATION_ERROR; + } else { + if (needBidi) { + static int RTL_OPTS = UBIDI_DO_MIRRORING | UBIDI_KEEP_BASE_COMBINING | + UBIDI_REMOVE_BIDI_CONTROLS | UBIDI_OUTPUT_REVERSE; + jint lineDir = 0; + switch (flags) { + case kBidi_LTR: lineDir = 0; break; // no ICU constant, canonical LTR level + case kBidi_RTL: lineDir = 1; break; // no ICU constant, canonical RTL level + case kBidi_Default_LTR: lineDir = UBIDI_DEFAULT_LTR; break; + case kBidi_Default_RTL: lineDir = UBIDI_DEFAULT_RTL; break; + } + + UBiDi* bidi = ubidi_open(); + ubidi_setPara(bidi, text, len, lineDir, NULL, &status); + if (U_SUCCESS(status)) { + dir = ubidi_getParaLevel(bidi) & 0x1; + + int rc = ubidi_countRuns(bidi, &status); + if (U_SUCCESS(status)) { + int32_t start; + int32_t length; + UBiDiDirection dir; + jchar *buffer = NULL; + for (int i = 0; i < rc; ++i) { + dir = ubidi_getVisualRun(bidi, i, &start, &length); + // fake shaping, except it doesn't shape, just mirrors and reverses + // use harfbuzz when available + if (dir == UBIDI_RTL) { + slen += ubidi_writeReverse(text + start, length, shaped + slen, + length, RTL_OPTS, &status); + } else { + for (int i = 0; i < length; ++i) { + shaped[slen + i] = text[start + i]; + } + slen += length; + } + } + } + ubidi_close(bidi); + } + } else { + shapeRtlText__(text, len, 0, len, shaped); + } + } + } + + if (!U_SUCCESS(status)) { + char buffer[35]; + sprintf(buffer, "DrawText bidi error %d", status); + doThrowIAE(env, buffer); + } else { + bool trimLeft = false; + bool trimRight = false; + + switch (horiz) { + case SkPaint::kLeft_Align: trimLeft = dir & kDirection_Mask; break; + case SkPaint::kCenter_Align: trimLeft = trimRight = true; break; + case SkPaint::kRight_Align: trimRight = !(dir & kDirection_Mask); + default: break; + } + const jchar* workText = shaped ? shaped : text; + const jchar* workLimit = workText + len; + + if (trimLeft) { + while (workText < workLimit && *workText == ' ') { + ++workText; + } + } + if (trimRight) { + while (workLimit > workText && *(workLimit - 1) == ' ') { + --workLimit; + } + } + int32_t workBytes = (workLimit - workText) << 1; + + canvas->drawText(workText, workBytes, x_, y_, *paint); + } + + if (shaped) { + free(shaped); + } + } - static void drawText___CIIFFPaint(JNIEnv* env, jobject, SkCanvas* canvas, + 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); - jsize textCount = env->GetArrayLength(text); - SkScalar x_ = SkFloatToScalar(x); - SkScalar y_ = SkFloatToScalar(y); - canvas->drawText(textArray + index, count << 1, x_, y_, *paint); - env->ReleaseCharArrayElements(text, textArray, 0); + drawText__(env, canvas, textArray + index, count, x, y, flags, paint); + env->ReleaseCharArrayElements(text, textArray, JNI_ABORT); } - static void drawText__StringIIFFPaint(JNIEnv* env, jobject, - SkCanvas* canvas, jstring text, int start, int end, - jfloat x, jfloat y, SkPaint* paint) { - const void* text_ = env->GetStringChars(text, NULL); - SkScalar x_ = SkFloatToScalar(x); - SkScalar y_ = SkFloatToScalar(y); - canvas->drawText((const uint16_t*)text_ + start, (end - start) << 1, - x_, y_, *paint); - env->ReleaseStringChars(text, (const jchar*) text_); + static void drawText__StringIIFFIPaint(JNIEnv* env, jobject, + SkCanvas* canvas, jstring text, + int start, int end, + jfloat x, jfloat y, int flags, SkPaint* paint) { + const jchar* textArray = env->GetStringChars(text, NULL); + drawText__(env, canvas, textArray + start, end - start, x, y, flags, paint); + env->ReleaseStringChars(text, textArray); } - static void drawString(JNIEnv* env, jobject canvas, jstring text, - jfloat x, jfloat y, jobject paint) { - NPE_CHECK_RETURN_VOID(env, canvas); - NPE_CHECK_RETURN_VOID(env, paint); - NPE_CHECK_RETURN_VOID(env, text); - size_t count = env->GetStringLength(text); - if (0 == count) { - return; + // Draws a unidirectional run of text. Does not run bidi, but does reorder the + // text and run shaping (or will, when we have harfbuzz support). + static void drawTextRun__(JNIEnv* env, SkCanvas* canvas, const jchar* chars, int len, + int start, int count, + jfloat x, jfloat y, int flags, SkPaint* paint) { + + SkScalar x_ = SkFloatToScalar(x); + SkScalar y_ = SkFloatToScalar(y); + + uint8_t rtl = flags & 0x1; + + UErrorCode status = U_ZERO_ERROR; + jchar *shaped = NULL; + if (rtl) { + shaped = (jchar *)malloc(count * sizeof(jchar)); + if (!shaped) { + status = U_MEMORY_ALLOCATION_ERROR; + } else { + shapeRtlText__(chars, len, start, count, shaped); + } + } + + if (!U_SUCCESS(status)) { + char buffer[30]; + sprintf(buffer, "DrawTextRun error %d", status); + doThrowIAE(env, buffer); + } else { + if (shaped) { + canvas->drawText(shaped, count << 1, x_, y_, *paint); + } else { + canvas->drawText(chars + start, count << 1, x_, y_, *paint); + } + } + + if (shaped) { + free(shaped); } - const jchar* text_ = env->GetStringChars(text, NULL); - SkCanvas* c = GraphicsJNI::getNativeCanvas(env, canvas); - c->drawText(text_, count << 1, SkFloatToScalar(x), SkFloatToScalar(y), - *GraphicsJNI::getNativePaint(env, paint)); - env->ReleaseStringChars(text, text_); } - + + static void drawTextRun___CIIFFIPaint( + JNIEnv* env, jobject, SkCanvas* canvas, jcharArray text, int index, + int count, jfloat x, jfloat y, int flags, SkPaint* paint) { + + jint len = env->GetArrayLength(text); + jchar* chars = env->GetCharArrayElements(text, NULL); + drawTextRun__(env, canvas, chars, len, index, count, x, y, flags, paint); + env->ReleaseCharArrayElements(text, chars, JNI_ABORT); + } + + static void drawTextRun__StringIIFFIPaint( + JNIEnv* env, jobject obj, SkCanvas* canvas, jstring text, int start, + int end, jfloat x, jfloat y, int flags, SkPaint* paint) { + + jint len = env->GetStringLength(text); + const jchar* chars = env->GetStringChars(text, NULL); + drawTextRun__(env, canvas, chars, len, start, end - start, x, y, flags, paint); + env->ReleaseStringChars(text, chars); + } + static void drawPosText___CII_FPaint(JNIEnv* env, jobject, SkCanvas* canvas, jcharArray text, int index, int count, jfloatArray pos, SkPaint* paint) { @@ -947,12 +1128,14 @@ static JNINativeMethod gCanvasMethods[] = { (void*)SkCanvasGlue::drawBitmapMesh}, {"nativeDrawVertices", "(III[FI[FI[II[SIII)V", (void*)SkCanvasGlue::drawVertices}, - {"native_drawText","(I[CIIFFI)V", - (void*) SkCanvasGlue::drawText___CIIFFPaint}, - {"native_drawText","(ILjava/lang/String;IIFFI)V", - (void*) SkCanvasGlue::drawText__StringIIFFPaint}, - {"drawText","(Ljava/lang/String;FFLandroid/graphics/Paint;)V", - (void*) SkCanvasGlue::drawString}, + {"native_drawText","(I[CIIFFII)V", + (void*) SkCanvasGlue::drawText___CIIFFIPaint}, + {"native_drawText","(ILjava/lang/String;IIFFII)V", + (void*) SkCanvasGlue::drawText__StringIIFFIPaint}, + {"native_drawTextRun","(I[CIIFFII)V", + (void*) SkCanvasGlue::drawTextRun___CIIFFIPaint}, + {"native_drawTextRun","(ILjava/lang/String;IIFFII)V", + (void*) SkCanvasGlue::drawTextRun__StringIIFFIPaint}, {"native_drawPosText","(I[CII[FI)V", (void*) SkCanvasGlue::drawPosText___CII_FPaint}, {"native_drawPosText","(ILjava/lang/String;[FI)V", diff --git a/graphics/java/android/graphics/Canvas.java b/graphics/java/android/graphics/Canvas.java index 345f810..064fab6 100644 --- a/graphics/java/android/graphics/Canvas.java +++ b/graphics/java/android/graphics/Canvas.java @@ -16,11 +16,10 @@ package android.graphics; -import android.text.TextUtils; -import android.text.SpannedString; -import android.text.SpannableString; import android.text.GraphicsOperations; -import android.util.DisplayMetrics; +import android.text.SpannableString; +import android.text.SpannedString; +import android.text.TextUtils; import javax.microedition.khronos.opengles.GL; @@ -59,6 +58,18 @@ public class Canvas { 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; + + /** * Construct an empty raster canvas. Use setBitmap() to specify a bitmap to * draw into. The initial target density is {@link Bitmap#DENSITY_NONE}; * this will typically be replaced when a target bitmap is set for the @@ -1246,8 +1257,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); } /** @@ -1259,7 +1270,10 @@ public class Canvas { * @param y The y-coordinate of the origin of the text being drawn * @param paint The paint used for the text (e.g. color, size, style) */ - public native void drawText(String text, float x, float y, Paint paint); + public void drawText(String text, float x, float y, Paint paint) { + native_drawText(mNativeCanvas, text, 0, text.length(), x, y, paint.mBidiFlags, + paint.mNativePaint); + } /** * Draw the text, with origin at (x,y), using the specified paint. @@ -1277,8 +1291,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); } /** @@ -1299,16 +1313,100 @@ public class Canvas { if (text instanceof String || text instanceof SpannedString || text instanceof SpannableString) { native_drawText(mNativeCanvas, text.toString(), start, end, x, y, - paint.mNativePaint); - } - else if (text instanceof GraphicsOperations) { + 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.mBidiFlags, paint.mNativePaint); + TemporaryBuffer.recycle(buf); } - else { + } + + /** + * Render a run of all LTR or all RTL text, with shaping. This does not run + * bidi on the provided text, but renders it as a uniform right-to-left or + * left-to-right run, as indicated by dir. Alignment of the text is as + * determined by the Paint's TextAlign value. + * + * @param text the text to render + * @param index the start of the text to render. Data before this position + * can be used for shaping context. + * @param length the length of the text to render. Data at or after this + * position (start + length) 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 {@link DIRECTION_LTR} or + * {@link DIRECTION_RTL}. + * @param paint the paint + * @hide + */ + public void drawTextRun(char[] text, int index, int length, float x, float y, int dir, + Paint paint) { + + if (text == null) { + throw new NullPointerException("text is null"); + } + if (paint == null) { + throw new NullPointerException("paint is null"); + } + if ((index | length | text.length - index - length) < 0) { + throw new IndexOutOfBoundsException(); + } + if (dir != DIRECTION_LTR && dir != DIRECTION_RTL) { + throw new IllegalArgumentException("unknown dir: " + dir); + } + + native_drawTextRun(mNativeCanvas, text, index, length, x, y, dir, paint.mNativePaint); + } + + /** + * Render a run of all LTR or all RTL text, with shaping. This does not run + * bidi on the provided text, but renders it as a uniform right-to-left or + * left-to-right run, as indicated by dir. Alignment of the text is as + * determined by the Paint's TextAlign value. + * + * @param text the text to render + * @param start the start of the text to render. Data before this position + * can be used for shaping context. + * @param end the end of the text to render. Data at or after this + * 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, float x, + float y, int dir, Paint paint) { + + if (text == null) { + throw new NullPointerException("text is null"); + } + if (paint == null) { + throw new NullPointerException("paint is null"); + } + if ((start | end | end - start | text.length() - end) < 0) { + 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, x, y, + flags, paint.mNativePaint); + } else if (text instanceof GraphicsOperations) { + ((GraphicsOperations) text).drawTextRun(this, start, end, x, y, flags, + paint); + } else { char[] buf = TemporaryBuffer.obtain(end - start); TextUtils.getChars(text, start, end, buf, 0); - drawText(buf, 0, end - start, x, y, paint); + native_drawTextRun(mNativeCanvas, buf, 0, end - start, x, y, + flags, paint.mNativePaint); TemporaryBuffer.recycle(buf); } } @@ -1555,10 +1653,17 @@ 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, float x, float y, int flags, int paint); + + private static native void native_drawTextRun(int nativeCanvas, char[] + text, int start, int len, float x, float y, int flags, int paint); + private static native void native_drawPosText(int nativeCanvas, char[] text, int index, int count, float[] pos, diff --git a/graphics/java/android/graphics/Paint.java b/graphics/java/android/graphics/Paint.java index 183c896..b564929 100644 --- a/graphics/java/android/graphics/Paint.java +++ b/graphics/java/android/graphics/Paint.java @@ -16,10 +16,10 @@ package android.graphics; -import android.text.TextUtils; +import android.text.GraphicsOperations; import android.text.SpannableString; import android.text.SpannedString; -import android.text.GraphicsOperations; +import android.text.TextUtils; /** * The Paint class holds the style and color information about how to draw @@ -39,6 +39,7 @@ public class Paint { private boolean mHasCompatScaling; private float mCompatScaling; private float mInvCompatScaling; + /* package */ int mBidiFlags = BIDI_DEFAULT_LTR; private static final Style[] sStyleArray = { Style.FILL, Style.STROKE, Style.FILL_AND_STROKE @@ -76,8 +77,64 @@ public class Paint { private static final int DEFAULT_PAINT_FLAGS = DEV_KERN_TEXT_FLAG; /** - * The Style specifies if the primitive being drawn is filled, - * stroked, or both (in the same color). The default is FILL. + * 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; + + /** + * The Style specifies if the primitive being drawn is filled, stroked, or + * both (in the same color). The default is FILL. */ public enum Style { /** @@ -210,6 +267,7 @@ public class Paint { mHasCompatScaling = paint.mHasCompatScaling; mCompatScaling = paint.mCompatScaling; mInvCompatScaling = paint.mInvCompatScaling; + mBidiFlags = paint.mBidiFlags; } /** Restores the paint to its default settings. */ @@ -218,6 +276,7 @@ public class Paint { setFlags(DEFAULT_PAINT_FLAGS); mHasCompatScaling = false; mCompatScaling = mInvCompatScaling = 1; + mBidiFlags = BIDI_DEFAULT_LTR; } /** @@ -240,6 +299,7 @@ public class Paint { mHasCompatScaling = src.mHasCompatScaling; mCompatScaling = src.mCompatScaling; mInvCompatScaling = src.mInvCompatScaling; + mBidiFlags = src.mBidiFlags; } } @@ -254,10 +314,33 @@ public class Paint { mInvCompatScaling = 1.0f/factor; } } - + + /** + * 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. - * + * * @return the paint's flags (see enums ending in _Flag for bit masks) */ public native int getFlags(); |
