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:
@ -38,7 +38,7 @@ extends CharSequence
|
|||||||
* {@hide}
|
* {@hide}
|
||||||
*/
|
*/
|
||||||
void drawTextRun(Canvas c, int start, int end, int contextStart, int contextEnd,
|
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}.
|
* Just like {@link Paint#measureText}.
|
||||||
@ -55,12 +55,19 @@ extends CharSequence
|
|||||||
* @hide
|
* @hide
|
||||||
*/
|
*/
|
||||||
float getTextRunAdvances(int start, int end, int contextStart, int contextEnd,
|
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}.
|
* Just like {@link Paint#getTextRunCursor}.
|
||||||
* @hide
|
* @hide
|
||||||
*/
|
*/
|
||||||
int getTextRunCursor(int contextStart, int contextEnd, int offset,
|
int getTextRunCursor(int contextStart, int contextEnd, int flags, int offset,
|
||||||
int cursorOpt, Paint p);
|
int cursorOpt, Paint p);
|
||||||
}
|
}
|
||||||
|
@ -159,15 +159,18 @@ class MeasuredText {
|
|||||||
mPos = p + len;
|
mPos = p + len;
|
||||||
|
|
||||||
if (mEasy) {
|
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;
|
float totalAdvance = 0;
|
||||||
int level = mLevels[p];
|
int level = mLevels[p];
|
||||||
for (int q = p, i = p + 1, e = p + len;; ++i) {
|
for (int q = p, i = p + 1, e = p + len;; ++i) {
|
||||||
if (i == e || mLevels[i] != level) {
|
if (i == e || mLevels[i] != level) {
|
||||||
|
int flags = (level & 0x1) == 0 ? Canvas.DIRECTION_LTR : Canvas.DIRECTION_RTL;
|
||||||
totalAdvance +=
|
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) {
|
if (i == e) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -1130,20 +1130,20 @@ public class SpannableStringBuilder implements CharSequence, GetChars, Spannable
|
|||||||
* {@hide}
|
* {@hide}
|
||||||
*/
|
*/
|
||||||
public void drawTextRun(Canvas c, int start, int end, int contextStart, int contextEnd,
|
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);
|
checkRange("drawTextRun", start, end);
|
||||||
|
|
||||||
int contextLen = contextEnd - contextStart;
|
int contextLen = contextEnd - contextStart;
|
||||||
int len = end - start;
|
int len = end - start;
|
||||||
if (contextEnd <= mGapStart) {
|
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) {
|
} else if (contextStart >= mGapStart) {
|
||||||
c.drawTextRun(mText, start + mGapLength, len, contextStart + mGapLength,
|
c.drawTextRun(mText, start + mGapLength, len, contextStart + mGapLength,
|
||||||
contextLen, x, y, p);
|
contextLen, x, y, flags, p);
|
||||||
} else {
|
} else {
|
||||||
char[] buf = TextUtils.obtain(contextLen);
|
char[] buf = TextUtils.obtain(contextLen);
|
||||||
getChars(contextStart, contextEnd, buf, 0);
|
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);
|
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.
|
* Don't call this yourself -- exists for Paint to use internally.
|
||||||
* {@hide}
|
* {@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[] advances, int advancesPos, Paint p) {
|
||||||
|
|
||||||
float ret;
|
float ret;
|
||||||
@ -1210,15 +1210,44 @@ public class SpannableStringBuilder implements CharSequence, GetChars, Spannable
|
|||||||
|
|
||||||
if (end <= mGapStart) {
|
if (end <= mGapStart) {
|
||||||
ret = p.getTextRunAdvances(mText, start, len, contextStart, contextLen,
|
ret = p.getTextRunAdvances(mText, start, len, contextStart, contextLen,
|
||||||
advances, advancesPos);
|
flags, advances, advancesPos);
|
||||||
} else if (start >= mGapStart) {
|
} else if (start >= mGapStart) {
|
||||||
ret = p.getTextRunAdvances(mText, start + mGapLength, len,
|
ret = p.getTextRunAdvances(mText, start + mGapLength, len,
|
||||||
contextStart + mGapLength, contextLen, advances, advancesPos);
|
contextStart + mGapLength, contextLen, flags, advances, advancesPos);
|
||||||
} else {
|
} else {
|
||||||
char[] buf = TextUtils.obtain(contextLen);
|
char[] buf = TextUtils.obtain(contextLen);
|
||||||
getChars(contextStart, contextEnd, buf, 0);
|
getChars(contextStart, contextEnd, buf, 0);
|
||||||
ret = p.getTextRunAdvances(buf, start - contextStart, len,
|
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);
|
TextUtils.recycle(buf);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1241,7 +1270,7 @@ public class SpannableStringBuilder implements CharSequence, GetChars, Spannable
|
|||||||
*
|
*
|
||||||
* @param contextStart the start index of the context
|
* @param contextStart the start index of the context
|
||||||
* @param contextEnd the (non-inclusive) end 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 offset the cursor position to move from
|
||||||
* @param cursorOpt how to move the cursor, one of CURSOR_AFTER,
|
* @param cursorOpt how to move the cursor, one of CURSOR_AFTER,
|
||||||
* CURSOR_AT_OR_AFTER, CURSOR_BEFORE,
|
* CURSOR_AT_OR_AFTER, CURSOR_BEFORE,
|
||||||
@ -1253,29 +1282,21 @@ public class SpannableStringBuilder implements CharSequence, GetChars, Spannable
|
|||||||
@Deprecated
|
@Deprecated
|
||||||
public int getTextRunCursor(int contextStart, int contextEnd, int flags, int offset,
|
public int getTextRunCursor(int contextStart, int contextEnd, int flags, int offset,
|
||||||
int cursorOpt, Paint p) {
|
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 ret;
|
int ret;
|
||||||
|
|
||||||
int contextLen = contextEnd - contextStart;
|
int contextLen = contextEnd - contextStart;
|
||||||
if (contextEnd <= mGapStart) {
|
if (contextEnd <= mGapStart) {
|
||||||
ret = p.getTextRunCursor(mText, contextStart, contextLen,
|
ret = p.getTextRunCursor(mText, contextStart, contextLen,
|
||||||
offset, cursorOpt);
|
flags, offset, cursorOpt);
|
||||||
} else if (contextStart >= mGapStart) {
|
} else if (contextStart >= mGapStart) {
|
||||||
ret = p.getTextRunCursor(mText, contextStart + mGapLength, contextLen,
|
ret = p.getTextRunCursor(mText, contextStart + mGapLength, contextLen,
|
||||||
offset + mGapLength, cursorOpt) - mGapLength;
|
flags, offset + mGapLength, cursorOpt) - mGapLength;
|
||||||
} else {
|
} else {
|
||||||
char[] buf = TextUtils.obtain(contextLen);
|
char[] buf = TextUtils.obtain(contextLen);
|
||||||
getChars(contextStart, contextEnd, buf, 0);
|
getChars(contextStart, contextEnd, buf, 0);
|
||||||
ret = p.getTextRunCursor(buf, 0, contextLen,
|
ret = p.getTextRunCursor(buf, 0, contextLen,
|
||||||
offset - contextStart, cursorOpt) + contextStart;
|
flags, offset - contextStart, cursorOpt) + contextStart;
|
||||||
TextUtils.recycle(buf);
|
TextUtils.recycle(buf);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -664,13 +664,14 @@ class TextLine {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int flags = runIsRtl ? Paint.DIRECTION_RTL : Paint.DIRECTION_LTR;
|
||||||
int cursorOpt = after ? Paint.CURSOR_AFTER : Paint.CURSOR_BEFORE;
|
int cursorOpt = after ? Paint.CURSOR_AFTER : Paint.CURSOR_BEFORE;
|
||||||
if (mCharsValid) {
|
if (mCharsValid) {
|
||||||
return wp.getTextRunCursor(mChars, spanStart, spanLimit - spanStart,
|
return wp.getTextRunCursor(mChars, spanStart, spanLimit - spanStart,
|
||||||
offset, cursorOpt);
|
flags, offset, cursorOpt);
|
||||||
} else {
|
} else {
|
||||||
return wp.getTextRunCursor(mText, mStart + spanStart,
|
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;
|
int contextLen = contextEnd - contextStart;
|
||||||
if (needWidth || (c != null && (wp.bgColor != 0 || wp.underlineColor != 0 || runIsRtl))) {
|
if (needWidth || (c != null && (wp.bgColor != 0 || wp.underlineColor != 0 || runIsRtl))) {
|
||||||
|
int flags = runIsRtl ? Paint.DIRECTION_RTL : Paint.DIRECTION_LTR;
|
||||||
if (mCharsValid) {
|
if (mCharsValid) {
|
||||||
ret = wp.getTextRunAdvances(mChars, start, runLen,
|
ret = wp.getTextRunAdvances(mChars, start, runLen,
|
||||||
contextStart, contextLen, null, 0);
|
contextStart, contextLen, flags, null, 0);
|
||||||
} else {
|
} else {
|
||||||
int delta = mStart;
|
int delta = mStart;
|
||||||
ret = wp.getTextRunAdvances(mText, delta + start, delta + end,
|
ret = wp.getTextRunAdvances(mText, delta + start,
|
||||||
delta + contextStart, delta + contextEnd, null, 0);
|
delta + end, delta + contextStart, delta + contextEnd,
|
||||||
|
flags, null, 0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -783,7 +786,8 @@ class TextLine {
|
|||||||
wp.setAntiAlias(previousAntiAlias);
|
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;
|
return runIsRtl ? -ret : ret;
|
||||||
@ -966,21 +970,23 @@ class TextLine {
|
|||||||
* @param end the end of the run
|
* @param end the end of the run
|
||||||
* @param contextStart the start of context for the run
|
* @param contextStart the start of context for the run
|
||||||
* @param contextEnd the end of the 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 x the x position of the left edge of the run
|
||||||
* @param y the baseline of the run
|
* @param y the baseline of the run
|
||||||
*/
|
*/
|
||||||
private void drawTextRun(Canvas c, TextPaint wp, int start, int end,
|
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) {
|
if (mCharsValid) {
|
||||||
int count = end - start;
|
int count = end - start;
|
||||||
int contextCount = contextEnd - contextStart;
|
int contextCount = contextEnd - contextStart;
|
||||||
c.drawTextRun(mChars, start, count, contextStart, contextCount,
|
c.drawTextRun(mChars, start, count, contextStart, contextCount,
|
||||||
x, y, wp);
|
x, y, flags, wp);
|
||||||
} else {
|
} else {
|
||||||
int delta = mStart;
|
int delta = mStart;
|
||||||
c.drawTextRun(mText, delta + start, delta + end,
|
c.drawTextRun(mText, delta + start, delta + end,
|
||||||
delta + contextStart, delta + contextEnd, x, y, wp);
|
delta + contextStart, delta + contextEnd, x, y, flags, wp);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1162,14 +1162,14 @@ class GLES20Canvas extends HardwareCanvas {
|
|||||||
|
|
||||||
int modifiers = setupModifiers(paint);
|
int modifiers = setupModifiers(paint);
|
||||||
try {
|
try {
|
||||||
nDrawText(mRenderer, text, index, count, x, y, paint.mNativePaint);
|
nDrawText(mRenderer, text, index, count, x, y, paint.mBidiFlags, paint.mNativePaint);
|
||||||
} finally {
|
} finally {
|
||||||
if (modifiers != MODIFIER_NONE) nResetModifiers(mRenderer, modifiers);
|
if (modifiers != MODIFIER_NONE) nResetModifiers(mRenderer, modifiers);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static native void nDrawText(int renderer, char[] text, int index, int count,
|
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
|
@Override
|
||||||
public void drawText(CharSequence text, int start, int end, float x, float y, Paint paint) {
|
public void drawText(CharSequence text, int start, int end, float x, float y, Paint paint) {
|
||||||
@ -1177,14 +1177,16 @@ class GLES20Canvas extends HardwareCanvas {
|
|||||||
try {
|
try {
|
||||||
if (text instanceof String || text instanceof SpannedString ||
|
if (text instanceof String || text instanceof SpannedString ||
|
||||||
text instanceof SpannableString) {
|
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) {
|
} else if (text instanceof GraphicsOperations) {
|
||||||
((GraphicsOperations) text).drawText(this, start, end, x, y,
|
((GraphicsOperations) text).drawText(this, start, end, x, y,
|
||||||
paint);
|
paint);
|
||||||
} else {
|
} else {
|
||||||
char[] buf = TemporaryBuffer.obtain(end - start);
|
char[] buf = TemporaryBuffer.obtain(end - start);
|
||||||
TextUtils.getChars(text, start, end, buf, 0);
|
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);
|
TemporaryBuffer.recycle(buf);
|
||||||
}
|
}
|
||||||
} finally {
|
} finally {
|
||||||
@ -1200,20 +1202,21 @@ class GLES20Canvas extends HardwareCanvas {
|
|||||||
|
|
||||||
int modifiers = setupModifiers(paint);
|
int modifiers = setupModifiers(paint);
|
||||||
try {
|
try {
|
||||||
nDrawText(mRenderer, text, start, end, x, y, paint.mNativePaint);
|
nDrawText(mRenderer, text, start, end, x, y, paint.mBidiFlags, paint.mNativePaint);
|
||||||
} finally {
|
} finally {
|
||||||
if (modifiers != MODIFIER_NONE) nResetModifiers(mRenderer, modifiers);
|
if (modifiers != MODIFIER_NONE) nResetModifiers(mRenderer, modifiers);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static native void nDrawText(int renderer, String text, int start, int end,
|
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
|
@Override
|
||||||
public void drawText(String text, float x, float y, Paint paint) {
|
public void drawText(String text, float x, float y, Paint paint) {
|
||||||
int modifiers = setupModifiers(paint);
|
int modifiers = setupModifiers(paint);
|
||||||
try {
|
try {
|
||||||
nDrawText(mRenderer, text, 0, text.length(), x, y, paint.mNativePaint);
|
nDrawText(mRenderer, text, 0, text.length(), x, y, paint.mBidiFlags,
|
||||||
|
paint.mNativePaint);
|
||||||
} finally {
|
} finally {
|
||||||
if (modifiers != MODIFIER_NONE) nResetModifiers(mRenderer, modifiers);
|
if (modifiers != MODIFIER_NONE) nResetModifiers(mRenderer, modifiers);
|
||||||
}
|
}
|
||||||
@ -1229,14 +1232,14 @@ class GLES20Canvas extends HardwareCanvas {
|
|||||||
int modifiers = setupModifiers(paint);
|
int modifiers = setupModifiers(paint);
|
||||||
try {
|
try {
|
||||||
nDrawTextOnPath(mRenderer, text, index, count, path.mNativePath, hOffset, vOffset,
|
nDrawTextOnPath(mRenderer, text, index, count, path.mNativePath, hOffset, vOffset,
|
||||||
paint.mNativePaint);
|
paint.mBidiFlags, paint.mNativePaint);
|
||||||
} finally {
|
} finally {
|
||||||
if (modifiers != MODIFIER_NONE) nResetModifiers(mRenderer, modifiers);
|
if (modifiers != MODIFIER_NONE) nResetModifiers(mRenderer, modifiers);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static native void nDrawTextOnPath(int renderer, char[] text, int index, int count,
|
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
|
@Override
|
||||||
public void drawTextOnPath(String text, Path path, float hOffset, float vOffset, Paint paint) {
|
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);
|
int modifiers = setupModifiers(paint);
|
||||||
try {
|
try {
|
||||||
nDrawTextOnPath(mRenderer, text, 0, text.length(), path.mNativePath, hOffset, vOffset,
|
nDrawTextOnPath(mRenderer, text, 0, text.length(), path.mNativePath, hOffset, vOffset,
|
||||||
paint.mNativePaint);
|
paint.mBidiFlags, paint.mNativePaint);
|
||||||
} finally {
|
} finally {
|
||||||
if (modifiers != MODIFIER_NONE) nResetModifiers(mRenderer, modifiers);
|
if (modifiers != MODIFIER_NONE) nResetModifiers(mRenderer, modifiers);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static native void nDrawTextOnPath(int renderer, String text, int start, int end,
|
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
|
@Override
|
||||||
public void drawTextRun(char[] text, int index, int count, int contextIndex, int contextCount,
|
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) {
|
if ((index | count | text.length - index - count) < 0) {
|
||||||
throw new IndexOutOfBoundsException();
|
throw new IndexOutOfBoundsException();
|
||||||
}
|
}
|
||||||
|
if (dir != DIRECTION_LTR && dir != DIRECTION_RTL) {
|
||||||
|
throw new IllegalArgumentException("Unknown direction: " + dir);
|
||||||
|
}
|
||||||
|
|
||||||
int modifiers = setupModifiers(paint);
|
int modifiers = setupModifiers(paint);
|
||||||
try {
|
try {
|
||||||
nDrawTextRun(mRenderer, text, index, count, contextIndex, contextCount, x, y,
|
nDrawTextRun(mRenderer, text, index, count, contextIndex, contextCount, x, y, dir,
|
||||||
paint.mNativePaint);
|
paint.mNativePaint);
|
||||||
} finally {
|
} finally {
|
||||||
if (modifiers != MODIFIER_NONE) nResetModifiers(mRenderer, modifiers);
|
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,
|
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
|
@Override
|
||||||
public void drawTextRun(CharSequence text, int start, int end, int contextStart, int contextEnd,
|
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) {
|
if ((start | end | end - start | text.length() - end) < 0) {
|
||||||
throw new IndexOutOfBoundsException();
|
throw new IndexOutOfBoundsException();
|
||||||
}
|
}
|
||||||
|
|
||||||
int modifiers = setupModifiers(paint);
|
int modifiers = setupModifiers(paint);
|
||||||
try {
|
try {
|
||||||
|
int flags = dir == 0 ? 0 : 1;
|
||||||
if (text instanceof String || text instanceof SpannedString ||
|
if (text instanceof String || text instanceof SpannedString ||
|
||||||
text instanceof SpannableString) {
|
text instanceof SpannableString) {
|
||||||
nDrawTextRun(mRenderer, text.toString(), start, end, contextStart,
|
nDrawTextRun(mRenderer, text.toString(), start, end, contextStart,
|
||||||
contextEnd, x, y, paint.mNativePaint);
|
contextEnd, x, y, flags, paint.mNativePaint);
|
||||||
} else if (text instanceof GraphicsOperations) {
|
} else if (text instanceof GraphicsOperations) {
|
||||||
((GraphicsOperations) text).drawTextRun(this, start, end,
|
((GraphicsOperations) text).drawTextRun(this, start, end,
|
||||||
contextStart, contextEnd, x, y, paint);
|
contextStart, contextEnd, x, y, flags, paint);
|
||||||
} else {
|
} else {
|
||||||
int contextLen = contextEnd - contextStart;
|
int contextLen = contextEnd - contextStart;
|
||||||
int len = end - start;
|
int len = end - start;
|
||||||
char[] buf = TemporaryBuffer.obtain(contextLen);
|
char[] buf = TemporaryBuffer.obtain(contextLen);
|
||||||
TextUtils.getChars(text, contextStart, contextEnd, buf, 0);
|
TextUtils.getChars(text, contextStart, contextEnd, buf, 0);
|
||||||
nDrawTextRun(mRenderer, buf, start - contextStart, len, 0, contextLen,
|
nDrawTextRun(mRenderer, buf, start - contextStart, len, 0, contextLen,
|
||||||
x, y, paint.mNativePaint);
|
x, y, flags, paint.mNativePaint);
|
||||||
TemporaryBuffer.recycle(buf);
|
TemporaryBuffer.recycle(buf);
|
||||||
}
|
}
|
||||||
} finally {
|
} finally {
|
||||||
@ -1304,7 +1311,7 @@ class GLES20Canvas extends HardwareCanvas {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private static native void nDrawTextRun(int renderer, String text, int start, int end,
|
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
|
@Override
|
||||||
public void drawVertices(VertexMode mode, int vertexCount, float[] verts, int vertOffset,
|
public void drawVertices(VertexMode mode, int vertexCount, float[] verts, int vertOffset,
|
||||||
|
@ -267,15 +267,15 @@ class GLES20RecordingCanvas extends GLES20Canvas {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void drawTextRun(char[] text, int index, int count, int contextIndex, int contextCount,
|
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) {
|
||||||
super.drawTextRun(text, index, count, contextIndex, contextCount, x, y, paint);
|
super.drawTextRun(text, index, count, contextIndex, contextCount, x, y, dir, paint);
|
||||||
recordShaderBitmap(paint);
|
recordShaderBitmap(paint);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void drawTextRun(CharSequence text, int start, int end, int contextStart,
|
public void drawTextRun(CharSequence text, int start, int end, int contextStart,
|
||||||
int contextEnd, float x, float y, Paint paint) {
|
int contextEnd, float x, float y, int dir, Paint paint) {
|
||||||
super.drawTextRun(text, start, end, contextStart, contextEnd, x, y, paint);
|
super.drawTextRun(text, start, end, contextStart, contextEnd, x, y, dir, paint);
|
||||||
recordShaderBitmap(paint);
|
recordShaderBitmap(paint);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -8813,11 +8813,11 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
|
|||||||
}
|
}
|
||||||
|
|
||||||
public void drawTextRun(Canvas c, int start, int end,
|
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 count = end - start;
|
||||||
int contextCount = contextEnd - contextStart;
|
int contextCount = contextEnd - contextStart;
|
||||||
c.drawTextRun(mChars, start + mStart, count, contextStart + mStart,
|
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) {
|
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,
|
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) {
|
Paint p) {
|
||||||
int count = end - start;
|
int count = end - start;
|
||||||
int contextCount = contextEnd - contextStart;
|
int contextCount = contextEnd - contextStart;
|
||||||
return p.getTextRunAdvances(mChars, start + mStart, count,
|
return p.getTextRunAdvances(mChars, start + mStart, count,
|
||||||
contextStart + mStart, contextCount, advances,
|
contextStart + mStart, contextCount, flags, advances,
|
||||||
advancesIndex);
|
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 offset, int cursorOpt, Paint p) {
|
||||||
int contextCount = contextEnd - contextStart;
|
int contextCount = contextEnd - contextStart;
|
||||||
return p.getTextRunCursor(mChars, contextStart + mStart,
|
return p.getTextRunCursor(mChars, contextStart + mStart,
|
||||||
contextCount, offset + mStart, cursorOpt);
|
contextCount, flags, offset + mStart, cursorOpt);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -754,35 +754,35 @@ public:
|
|||||||
|
|
||||||
static void drawText___CIIFFIPaint(JNIEnv* env, jobject, SkCanvas* canvas,
|
static void drawText___CIIFFIPaint(JNIEnv* env, jobject, SkCanvas* canvas,
|
||||||
jcharArray text, int index, int count,
|
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);
|
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);
|
env->ReleaseCharArrayElements(text, textArray, JNI_ABORT);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void drawText__StringIIFFIPaint(JNIEnv* env, jobject,
|
static void drawText__StringIIFFIPaint(JNIEnv* env, jobject,
|
||||||
SkCanvas* canvas, jstring text,
|
SkCanvas* canvas, jstring text,
|
||||||
int start, int end,
|
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);
|
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);
|
env->ReleaseStringChars(text, textArray);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void drawTextWithGlyphs(SkCanvas* canvas, const jchar* textArray,
|
static void drawTextWithGlyphs(SkCanvas* canvas, const jchar* textArray,
|
||||||
int start, int end,
|
int start, int end,
|
||||||
jfloat x, jfloat y, SkPaint* paint) {
|
jfloat x, jfloat y, int flags, SkPaint* paint) {
|
||||||
|
|
||||||
jint count = end - start;
|
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,
|
static void drawTextWithGlyphs(SkCanvas* canvas, const jchar* textArray,
|
||||||
int start, int count, int contextCount,
|
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,
|
sp<TextLayoutValue> value = TextLayoutEngine::getInstance().getValue(paint,
|
||||||
textArray, start, count, contextCount);
|
textArray, start, count, contextCount, flags);
|
||||||
if (value == NULL) {
|
if (value == NULL) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -793,7 +793,7 @@ public:
|
|||||||
x -= value->getTotalAdvance();
|
x -= value->getTotalAdvance();
|
||||||
}
|
}
|
||||||
paint->setTextAlign(SkPaint::kLeft_Align);
|
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);
|
doDrawTextDecorations(canvas, x, y, value->getTotalAdvance(), paint);
|
||||||
paint->setTextAlign(align);
|
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,
|
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];
|
SkPoint* posPtr = new SkPoint[count];
|
||||||
for (int indx = 0; indx < count; indx++) {
|
for (int indx = 0; indx < count; indx++) {
|
||||||
posPtr[indx].fX = SkFloatToScalar(x + posArray[indx * 2]);
|
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);
|
jchar* chars = env->GetCharArrayElements(text, NULL);
|
||||||
drawTextWithGlyphs(canvas, chars + contextIndex, index - contextIndex,
|
drawTextWithGlyphs(canvas, chars + contextIndex, index - contextIndex,
|
||||||
count, contextCount, x, y, paint);
|
count, contextCount, x, y, dirFlags, paint);
|
||||||
env->ReleaseCharArrayElements(text, chars, JNI_ABORT);
|
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;
|
jint contextCount = contextEnd - contextStart;
|
||||||
const jchar* chars = env->GetStringChars(text, NULL);
|
const jchar* chars = env->GetStringChars(text, NULL);
|
||||||
drawTextWithGlyphs(canvas, chars + contextStart, start - contextStart,
|
drawTextWithGlyphs(canvas, chars + contextStart, start - contextStart,
|
||||||
count, contextCount, x, y, paint);
|
count, contextCount, x, y, dirFlags, paint);
|
||||||
env->ReleaseStringChars(text, chars);
|
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,
|
static void drawTextOnPath___CIIPathFFPaint(JNIEnv* env, jobject,
|
||||||
SkCanvas* canvas, jcharArray text, int index, int count,
|
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);
|
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);
|
env->ReleaseCharArrayElements(text, textArray, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void drawTextOnPath__StringPathFFPaint(JNIEnv* env, jobject,
|
static void drawTextOnPath__StringPathFFPaint(JNIEnv* env, jobject,
|
||||||
SkCanvas* canvas, jstring text, SkPath* path,
|
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);
|
const jchar* text_ = env->GetStringChars(text, NULL);
|
||||||
int count = env->GetStringLength(text);
|
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_);
|
env->ReleaseStringChars(text, text_);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1051,21 +1059,21 @@ static JNINativeMethod gCanvasMethods[] = {
|
|||||||
(void*)SkCanvasGlue::drawBitmapMesh},
|
(void*)SkCanvasGlue::drawBitmapMesh},
|
||||||
{"nativeDrawVertices", "(III[FI[FI[II[SIII)V",
|
{"nativeDrawVertices", "(III[FI[FI[II[SIII)V",
|
||||||
(void*)SkCanvasGlue::drawVertices},
|
(void*)SkCanvasGlue::drawVertices},
|
||||||
{"native_drawText","(I[CIIFFI)V",
|
{"native_drawText","(I[CIIFFII)V",
|
||||||
(void*) SkCanvasGlue::drawText___CIIFFIPaint},
|
(void*) SkCanvasGlue::drawText___CIIFFIPaint},
|
||||||
{"native_drawText","(ILjava/lang/String;IIFFI)V",
|
{"native_drawText","(ILjava/lang/String;IIFFII)V",
|
||||||
(void*) SkCanvasGlue::drawText__StringIIFFIPaint},
|
(void*) SkCanvasGlue::drawText__StringIIFFIPaint},
|
||||||
{"native_drawTextRun","(I[CIIIIFFI)V",
|
{"native_drawTextRun","(I[CIIIIFFII)V",
|
||||||
(void*) SkCanvasGlue::drawTextRun___CIIIIFFIPaint},
|
(void*) SkCanvasGlue::drawTextRun___CIIIIFFIPaint},
|
||||||
{"native_drawTextRun","(ILjava/lang/String;IIIIFFI)V",
|
{"native_drawTextRun","(ILjava/lang/String;IIIIFFII)V",
|
||||||
(void*) SkCanvasGlue::drawTextRun__StringIIIIFFIPaint},
|
(void*) SkCanvasGlue::drawTextRun__StringIIIIFFIPaint},
|
||||||
{"native_drawPosText","(I[CII[FI)V",
|
{"native_drawPosText","(I[CII[FI)V",
|
||||||
(void*) SkCanvasGlue::drawPosText___CII_FPaint},
|
(void*) SkCanvasGlue::drawPosText___CII_FPaint},
|
||||||
{"native_drawPosText","(ILjava/lang/String;[FI)V",
|
{"native_drawPosText","(ILjava/lang/String;[FI)V",
|
||||||
(void*) SkCanvasGlue::drawPosText__String_FPaint},
|
(void*) SkCanvasGlue::drawPosText__String_FPaint},
|
||||||
{"native_drawTextOnPath","(I[CIIIFFI)V",
|
{"native_drawTextOnPath","(I[CIIIFFII)V",
|
||||||
(void*) SkCanvasGlue::drawTextOnPath___CIIPathFFPaint},
|
(void*) SkCanvasGlue::drawTextOnPath___CIIPathFFPaint},
|
||||||
{"native_drawTextOnPath","(ILjava/lang/String;IFFI)V",
|
{"native_drawTextOnPath","(ILjava/lang/String;IFFII)V",
|
||||||
(void*) SkCanvasGlue::drawTextOnPath__StringPathFFPaint},
|
(void*) SkCanvasGlue::drawTextOnPath__StringPathFFPaint},
|
||||||
{"native_drawPicture", "(II)V", (void*) SkCanvasGlue::drawPicture},
|
{"native_drawPicture", "(II)V", (void*) SkCanvasGlue::drawPicture},
|
||||||
|
|
||||||
|
@ -401,7 +401,7 @@ public:
|
|||||||
jfloat result = 0;
|
jfloat result = 0;
|
||||||
|
|
||||||
TextLayout::getTextRunAdvances(paint, textArray, index, count, textLength,
|
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);
|
env->ReleaseCharArrayElements(text, const_cast<jchar*>(textArray), JNI_ABORT);
|
||||||
return result;
|
return result;
|
||||||
@ -426,7 +426,7 @@ public:
|
|||||||
jfloat width = 0;
|
jfloat width = 0;
|
||||||
|
|
||||||
TextLayout::getTextRunAdvances(paint, textArray, start, count, textLength,
|
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);
|
env->ReleaseStringChars(text, textArray);
|
||||||
return width;
|
return width;
|
||||||
@ -446,7 +446,7 @@ public:
|
|||||||
jfloat width = 0;
|
jfloat width = 0;
|
||||||
|
|
||||||
TextLayout::getTextRunAdvances(paint, textArray, 0, textLength, textLength,
|
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);
|
env->ReleaseStringChars(text, textArray);
|
||||||
return width;
|
return width;
|
||||||
@ -473,7 +473,7 @@ public:
|
|||||||
jfloat* widthsArray = autoWidths.ptr();
|
jfloat* widthsArray = autoWidths.ptr();
|
||||||
|
|
||||||
TextLayout::getTextRunAdvances(paint, text, 0, count, count,
|
TextLayout::getTextRunAdvances(paint, text, 0, count, count,
|
||||||
widthsArray, NULL /* dont need totalAdvance */);
|
paint->getFlags(), widthsArray, NULL /* dont need totalAdvance */);
|
||||||
|
|
||||||
return count;
|
return count;
|
||||||
}
|
}
|
||||||
@ -494,8 +494,48 @@ public:
|
|||||||
return count;
|
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,
|
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) {
|
jfloatArray advances, jint advancesIndex) {
|
||||||
NPE_CHECK_RETURN_ZERO(env, paint);
|
NPE_CHECK_RETURN_ZERO(env, paint);
|
||||||
NPE_CHECK_RETURN_ZERO(env, text);
|
NPE_CHECK_RETURN_ZERO(env, text);
|
||||||
@ -517,7 +557,7 @@ public:
|
|||||||
jfloat advancesArray[count];
|
jfloat advancesArray[count];
|
||||||
jfloat totalAdvance = 0;
|
jfloat totalAdvance = 0;
|
||||||
|
|
||||||
TextLayout::getTextRunAdvances(paint, text, start, count, contextCount,
|
TextLayout::getTextRunAdvances(paint, text, start, count, contextCount, flags,
|
||||||
advancesArray, &totalAdvance);
|
advancesArray, &totalAdvance);
|
||||||
|
|
||||||
if (advances != NULL) {
|
if (advances != NULL) {
|
||||||
@ -526,23 +566,61 @@ public:
|
|||||||
return totalAdvance;
|
return totalAdvance;
|
||||||
}
|
}
|
||||||
|
|
||||||
static float getTextRunAdvances___CIIII_FI(JNIEnv* env, jobject clazz, SkPaint* paint,
|
static jfloat doTextRunAdvancesICU(JNIEnv *env, SkPaint *paint, const jchar *text,
|
||||||
jcharArray text, jint index, jint count, jint contextIndex, jint contextCount,
|
jint start, jint count, jint contextCount, jint flags,
|
||||||
jfloatArray advances, jint advancesIndex) {
|
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,
|
||||||
|
jint flags, jfloatArray advances, jint advancesIndex, jint reserved) {
|
||||||
jchar* textArray = env->GetCharArrayElements(text, NULL);
|
jchar* textArray = env->GetCharArrayElements(text, NULL);
|
||||||
jfloat result = doTextRunAdvances(env, paint, textArray + contextIndex,
|
jfloat result = (reserved == 0) ?
|
||||||
index - contextIndex, count, contextCount, advances, advancesIndex);
|
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);
|
env->ReleaseCharArrayElements(text, textArray, JNI_ABORT);
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
static float getTextRunAdvances__StringIIII_FI(JNIEnv* env, jobject clazz, SkPaint* paint,
|
static float getTextRunAdvances__StringIIIII_FII(JNIEnv* env, jobject clazz, SkPaint* paint,
|
||||||
jstring text, jint start, jint end, jint contextStart, jint contextEnd,
|
jstring text, jint start, jint end, jint contextStart, jint contextEnd, jint flags,
|
||||||
jfloatArray advances, jint advancesIndex) {
|
jfloatArray advances, jint advancesIndex, jint reserved) {
|
||||||
const jchar* textArray = env->GetStringChars(text, NULL);
|
const jchar* textArray = env->GetStringChars(text, NULL);
|
||||||
jfloat result = doTextRunAdvances(env, paint, textArray + contextStart,
|
jfloat result = (reserved == 0) ?
|
||||||
start - contextStart, end - start, contextEnd - contextStart,
|
doTextRunAdvances(env, paint, textArray + contextStart, start - contextStart,
|
||||||
advances, advancesIndex);
|
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);
|
env->ReleaseStringChars(text, textArray);
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
@ -551,7 +629,7 @@ public:
|
|||||||
jint count, jint flags, jint offset, jint opt) {
|
jint count, jint flags, jint offset, jint opt) {
|
||||||
jfloat scalarArray[count];
|
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 */);
|
scalarArray, NULL /* dont need totalAdvance */);
|
||||||
|
|
||||||
jint pos = offset - start;
|
jint pos = offset - start;
|
||||||
@ -610,21 +688,21 @@ public:
|
|||||||
}
|
}
|
||||||
|
|
||||||
static void getTextPath(JNIEnv* env, SkPaint* paint, const jchar* text, jint count,
|
static void getTextPath(JNIEnv* env, SkPaint* paint, const jchar* text, jint count,
|
||||||
jfloat x, jfloat y, SkPath *path) {
|
jint bidiFlags, jfloat x, jfloat y, SkPath *path) {
|
||||||
TextLayout::getTextPath(paint, text, count, x, y, 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) {
|
jcharArray text, int index, int count, jfloat x, jfloat y, SkPath* path) {
|
||||||
const jchar* textArray = env->GetCharArrayElements(text, NULL);
|
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);
|
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) {
|
jstring text, int start, int end, jfloat x, jfloat y, SkPath* path) {
|
||||||
const jchar* textArray = env->GetStringChars(text, NULL);
|
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);
|
env->ReleaseStringChars(text, textArray);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -648,7 +726,7 @@ public:
|
|||||||
int count, float maxWidth, jfloatArray jmeasured,
|
int count, float maxWidth, jfloatArray jmeasured,
|
||||||
SkPaint::TextBufferDirection tbd) {
|
SkPaint::TextBufferDirection tbd) {
|
||||||
sp<TextLayoutValue> value = TextLayoutEngine::getInstance().getValue(&paint,
|
sp<TextLayoutValue> value = TextLayoutEngine::getInstance().getValue(&paint,
|
||||||
text, 0, count, count);
|
text, 0, count, count, paint.getFlags());
|
||||||
if (value == NULL) {
|
if (value == NULL) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@ -720,7 +798,7 @@ public:
|
|||||||
SkIRect ir;
|
SkIRect ir;
|
||||||
|
|
||||||
sp<TextLayoutValue> value = TextLayoutEngine::getInstance().getValue(&paint,
|
sp<TextLayoutValue> value = TextLayoutEngine::getInstance().getValue(&paint,
|
||||||
text, 0, count, count);
|
text, 0, count, count, paint.getFlags());
|
||||||
if (value == NULL) {
|
if (value == NULL) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -808,15 +886,19 @@ static JNINativeMethod methods[] = {
|
|||||||
{"native_breakText","(Ljava/lang/String;ZF[F)I", (void*) SkPaintGlue::breakTextS},
|
{"native_breakText","(Ljava/lang/String;ZF[F)I", (void*) SkPaintGlue::breakTextS},
|
||||||
{"native_getTextWidths","(I[CII[F)I", (void*) SkPaintGlue::getTextWidths___CII_F},
|
{"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_getTextWidths","(ILjava/lang/String;II[F)I", (void*) SkPaintGlue::getTextWidths__StringII_F},
|
||||||
{"native_getTextRunAdvances","(I[CIIII[FI)F",
|
{"native_getTextRunAdvances","(I[CIIIII[FII)F",
|
||||||
(void*) SkPaintGlue::getTextRunAdvances___CIIII_FI},
|
(void*) SkPaintGlue::getTextRunAdvances___CIIIII_FII},
|
||||||
{"native_getTextRunAdvances","(ILjava/lang/String;IIII[FI)F",
|
{"native_getTextRunAdvances","(ILjava/lang/String;IIIII[FII)F",
|
||||||
(void*) SkPaintGlue::getTextRunAdvances__StringIIII_FI},
|
(void*) SkPaintGlue::getTextRunAdvances__StringIIIII_FII},
|
||||||
{"native_getTextRunCursor", "(I[CIIII)I", (void*) SkPaintGlue::getTextRunCursor___C},
|
|
||||||
{"native_getTextRunCursor", "(ILjava/lang/String;IIII)I",
|
|
||||||
|
{"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},
|
(void*) SkPaintGlue::getTextRunCursor__String},
|
||||||
{"native_getTextPath","(I[CIIFFI)V", (void*) SkPaintGlue::getTextPath___C},
|
{"native_getTextPath","(II[CIIFFI)V", (void*) SkPaintGlue::getTextPath___C},
|
||||||
{"native_getTextPath","(ILjava/lang/String;IIFFI)V", (void*) SkPaintGlue::getTextPath__String},
|
{"native_getTextPath","(IILjava/lang/String;IIFFI)V", (void*) SkPaintGlue::getTextPath__String},
|
||||||
{"nativeGetStringBounds", "(ILjava/lang/String;IILandroid/graphics/Rect;)V",
|
{"nativeGetStringBounds", "(ILjava/lang/String;IILandroid/graphics/Rect;)V",
|
||||||
(void*) SkPaintGlue::getStringBounds },
|
(void*) SkPaintGlue::getStringBounds },
|
||||||
{"nativeGetCharArrayBounds", "(I[CIILandroid/graphics/Rect;)V",
|
{"nativeGetCharArrayBounds", "(I[CIILandroid/graphics/Rect;)V",
|
||||||
|
@ -28,13 +28,33 @@
|
|||||||
|
|
||||||
namespace android {
|
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.
|
// 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
|
// 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.
|
// a path representing the text that would have been drawn.
|
||||||
void TextLayout::handleText(SkPaint *paint, const jchar* text, jsize len,
|
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,
|
sp<TextLayoutValue> value = TextLayoutEngine::getInstance().getValue(paint,
|
||||||
text, 0, len, len);
|
text, 0, len, len, bidiFlags);
|
||||||
if (value == NULL) {
|
if (value == NULL) {
|
||||||
return ;
|
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,
|
void TextLayout::getTextRunAdvances(SkPaint* paint, const jchar* chars, jint start,
|
||||||
jint count, jint contextCount,
|
jint count, jint contextCount, jint dirFlags,
|
||||||
jfloat* resultAdvances, jfloat* resultTotalAdvance) {
|
jfloat* resultAdvances, jfloat* resultTotalAdvance) {
|
||||||
sp<TextLayoutValue> value = TextLayoutEngine::getInstance().getValue(paint,
|
sp<TextLayoutValue> value = TextLayoutEngine::getInstance().getValue(paint,
|
||||||
chars, start, count, contextCount);
|
chars, start, count, contextCount, dirFlags);
|
||||||
if (value == NULL) {
|
if (value == NULL) {
|
||||||
return ;
|
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,
|
void TextLayout::getTextRunAdvancesICU(SkPaint* paint, const jchar* chars, jint start,
|
||||||
jfloat x, jfloat y, SkPath *path) {
|
jint count, jint contextCount, jint dirFlags,
|
||||||
handleText(paint, text, len, x, y, path);
|
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,
|
void TextLayout::drawTextOnPath(SkPaint* paint, const jchar* text, int count,
|
||||||
jfloat hOffset, jfloat vOffset,
|
int bidiFlags, jfloat hOffset, jfloat vOffset,
|
||||||
SkPath* path, SkCanvas* canvas) {
|
SkPath* path, SkCanvas* canvas) {
|
||||||
|
|
||||||
SkScalar h_ = SkFloatToScalar(hOffset);
|
SkScalar h_ = SkFloatToScalar(hOffset);
|
||||||
SkScalar v_ = SkFloatToScalar(vOffset);
|
SkScalar v_ = SkFloatToScalar(vOffset);
|
||||||
|
|
||||||
sp<TextLayoutValue> value = TextLayoutEngine::getInstance().getValue(paint,
|
sp<TextLayoutValue> value = TextLayoutEngine::getInstance().getValue(paint,
|
||||||
text, 0, count, count);
|
text, 0, count, count, bidiFlags);
|
||||||
if (value == NULL) {
|
if (value == NULL) {
|
||||||
return;
|
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);
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -41,6 +41,17 @@ namespace android {
|
|||||||
*/
|
*/
|
||||||
#define USE_TEXT_LAYOUT_CACHE 1
|
#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 {
|
enum {
|
||||||
kDirection_LTR = 0,
|
kDirection_LTR = 0,
|
||||||
kDirection_RTL = 1,
|
kDirection_RTL = 1,
|
||||||
@ -52,18 +63,28 @@ class TextLayout {
|
|||||||
public:
|
public:
|
||||||
|
|
||||||
static void getTextRunAdvances(SkPaint* paint, const jchar* chars, jint start,
|
static void getTextRunAdvances(SkPaint* paint, const jchar* chars, jint start,
|
||||||
jint count, jint contextCount,
|
jint count, jint contextCount, jint dirFlags,
|
||||||
jfloat* resultAdvances, jfloat* resultTotalAdvance);
|
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,
|
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,
|
static void drawTextOnPath(SkPaint* paint, const jchar* text, jsize len,
|
||||||
jfloat hOffset, jfloat vOffset,
|
int bidiFlags, jfloat hOffset, jfloat vOffset,
|
||||||
SkPath* path, SkCanvas* canvas);
|
SkPath* path, SkCanvas* canvas);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
static bool needsLayout(const jchar* text, jint len, jint bidiFlags);
|
||||||
|
|
||||||
static void handleText(SkPaint* paint, const jchar* text, jsize len,
|
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
|
} // namespace android
|
||||||
|
@ -87,7 +87,7 @@ void TextLayoutCache::purgeCaches() {
|
|||||||
* Caching
|
* Caching
|
||||||
*/
|
*/
|
||||||
sp<TextLayoutValue> TextLayoutCache::getValue(const SkPaint* paint,
|
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);
|
AutoMutex _l(mLock);
|
||||||
nsecs_t startTime = 0;
|
nsecs_t startTime = 0;
|
||||||
if (mDebugEnabled) {
|
if (mDebugEnabled) {
|
||||||
@ -95,7 +95,7 @@ sp<TextLayoutValue> TextLayoutCache::getValue(const SkPaint* paint,
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Create the key
|
// Create the key
|
||||||
TextLayoutCacheKey key(paint, text, start, count, contextCount);
|
TextLayoutCacheKey key(paint, text, start, count, contextCount, dirFlags);
|
||||||
|
|
||||||
// Get value from cache if possible
|
// Get value from cache if possible
|
||||||
sp<TextLayoutValue> value = mCache.get(key);
|
sp<TextLayoutValue> value = mCache.get(key);
|
||||||
@ -111,7 +111,7 @@ sp<TextLayoutValue> TextLayoutCache::getValue(const SkPaint* paint,
|
|||||||
// Compute advances and store them
|
// Compute advances and store them
|
||||||
mShaper->computeValues(value.get(), paint,
|
mShaper->computeValues(value.get(), paint,
|
||||||
reinterpret_cast<const UChar*>(key.getText()), start, count,
|
reinterpret_cast<const UChar*>(key.getText()), start, count,
|
||||||
size_t(contextCount));
|
size_t(contextCount), int(dirFlags));
|
||||||
|
|
||||||
if (mDebugEnabled) {
|
if (mDebugEnabled) {
|
||||||
value->setElapsedTime(systemTime(SYSTEM_TIME_MONOTONIC) - startTime);
|
value->setElapsedTime(systemTime(SYSTEM_TIME_MONOTONIC) - startTime);
|
||||||
@ -218,13 +218,14 @@ void TextLayoutCache::dumpCacheStats() {
|
|||||||
* TextLayoutCacheKey
|
* TextLayoutCacheKey
|
||||||
*/
|
*/
|
||||||
TextLayoutCacheKey::TextLayoutCacheKey(): start(0), count(0), contextCount(0),
|
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() {
|
hinting(SkPaint::kNo_Hinting), variant(SkPaint::kDefault_Variant), language() {
|
||||||
}
|
}
|
||||||
|
|
||||||
TextLayoutCacheKey::TextLayoutCacheKey(const SkPaint* paint, const UChar* text,
|
TextLayoutCacheKey::TextLayoutCacheKey(const SkPaint* paint, const UChar* text,
|
||||||
size_t start, size_t count, size_t contextCount) :
|
size_t start, size_t count, size_t contextCount, int dirFlags) :
|
||||||
start(start), count(count), contextCount(contextCount) {
|
start(start), count(count), contextCount(contextCount),
|
||||||
|
dirFlags(dirFlags) {
|
||||||
textCopy.setTo(text, contextCount);
|
textCopy.setTo(text, contextCount);
|
||||||
typeface = paint->getTypeface();
|
typeface = paint->getTypeface();
|
||||||
textSize = paint->getTextSize();
|
textSize = paint->getTextSize();
|
||||||
@ -241,6 +242,7 @@ TextLayoutCacheKey::TextLayoutCacheKey(const TextLayoutCacheKey& other) :
|
|||||||
start(other.start),
|
start(other.start),
|
||||||
count(other.count),
|
count(other.count),
|
||||||
contextCount(other.contextCount),
|
contextCount(other.contextCount),
|
||||||
|
dirFlags(other.dirFlags),
|
||||||
typeface(other.typeface),
|
typeface(other.typeface),
|
||||||
textSize(other.textSize),
|
textSize(other.textSize),
|
||||||
textSkewX(other.textSkewX),
|
textSkewX(other.textSkewX),
|
||||||
@ -279,6 +281,9 @@ int TextLayoutCacheKey::compare(const TextLayoutCacheKey& lhs, const TextLayoutC
|
|||||||
deltaInt = lhs.hinting - rhs.hinting;
|
deltaInt = lhs.hinting - rhs.hinting;
|
||||||
if (deltaInt != 0) return (deltaInt);
|
if (deltaInt != 0) return (deltaInt);
|
||||||
|
|
||||||
|
deltaInt = lhs.dirFlags - rhs.dirFlags;
|
||||||
|
if (deltaInt) return (deltaInt);
|
||||||
|
|
||||||
deltaInt = lhs.variant - rhs.variant;
|
deltaInt = lhs.variant - rhs.variant;
|
||||||
if (deltaInt) return (deltaInt);
|
if (deltaInt) return (deltaInt);
|
||||||
|
|
||||||
@ -354,9 +359,9 @@ TextLayoutShaper::~TextLayoutShaper() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void TextLayoutShaper::computeValues(TextLayoutValue* value, const SkPaint* paint, const UChar* chars,
|
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);
|
&value->mAdvances, &value->mTotalAdvance, &value->mGlyphs, &value->mPos);
|
||||||
#if DEBUG_ADVANCES
|
#if DEBUG_ADVANCES
|
||||||
ALOGD("Advances - start = %d, count = %d, contextCount = %d, totalAdvance = %f", start, count,
|
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,
|
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<jfloat>* const outAdvances, jfloat* outTotalAdvance,
|
||||||
Vector<jchar>* const outGlyphs, Vector<jfloat>* const outPos) {
|
Vector<jchar>* const outGlyphs, Vector<jfloat>* const outPos) {
|
||||||
*outTotalAdvance = 0;
|
*outTotalAdvance = 0;
|
||||||
@ -373,10 +378,24 @@ void TextLayoutShaper::computeValues(const SkPaint* paint, const UChar* chars,
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
UBiDiLevel bidiReq = UBIDI_DEFAULT_LTR;
|
UBiDiLevel bidiReq = 0;
|
||||||
bool useSingleRun = false;
|
bool forceLTR = false;
|
||||||
bool isRTL = 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 = forceRTL;
|
||||||
|
if (forceLTR || forceRTL) {
|
||||||
|
useSingleRun = true;
|
||||||
|
} else {
|
||||||
UBiDi* bidi = ubidi_open();
|
UBiDi* bidi = ubidi_open();
|
||||||
if (bidi) {
|
if (bidi) {
|
||||||
UErrorCode status = U_ZERO_ERROR;
|
UErrorCode status = U_ZERO_ERROR;
|
||||||
@ -393,6 +412,7 @@ void TextLayoutShaper::computeValues(const SkPaint* paint, const UChar* chars,
|
|||||||
int paraDir = ubidi_getParaLevel(bidi) & kDirection_Mask; // 0 if ltr, 1 if rtl
|
int paraDir = ubidi_getParaLevel(bidi) & kDirection_Mask; // 0 if ltr, 1 if rtl
|
||||||
ssize_t rc = ubidi_countRuns(bidi, &status);
|
ssize_t rc = ubidi_countRuns(bidi, &status);
|
||||||
#if DEBUG_GLYPHS
|
#if DEBUG_GLYPHS
|
||||||
|
ALOGD(" -- dirFlags = %d", dirFlags);
|
||||||
ALOGD(" -- paraDir = %d", paraDir);
|
ALOGD(" -- paraDir = %d", paraDir);
|
||||||
ALOGD(" -- run-count = %d", int(rc));
|
ALOGD(" -- run-count = %d", int(rc));
|
||||||
#endif
|
#endif
|
||||||
@ -462,6 +482,7 @@ void TextLayoutShaper::computeValues(const SkPaint* paint, const UChar* chars,
|
|||||||
useSingleRun = true;
|
useSingleRun = true;
|
||||||
isRTL = (bidiReq = 1) || (bidiReq = UBIDI_DEFAULT_RTL);
|
isRTL = (bidiReq = 1) || (bidiReq = UBIDI_DEFAULT_RTL);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Default single run case
|
// Default single run case
|
||||||
if (useSingleRun){
|
if (useSingleRun){
|
||||||
@ -897,11 +918,11 @@ TextLayoutEngine::~TextLayoutEngine() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
sp<TextLayoutValue> TextLayoutEngine::getValue(const SkPaint* paint, const jchar* text,
|
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;
|
sp<TextLayoutValue> value;
|
||||||
#if USE_TEXT_LAYOUT_CACHE
|
#if USE_TEXT_LAYOUT_CACHE
|
||||||
value = mTextLayoutCache->getValue(paint, text, start, count,
|
value = mTextLayoutCache->getValue(paint, text, start, count,
|
||||||
contextCount);
|
contextCount, dirFlags);
|
||||||
if (value == NULL) {
|
if (value == NULL) {
|
||||||
ALOGE("Cannot get TextLayoutCache value for text = '%s'",
|
ALOGE("Cannot get TextLayoutCache value for text = '%s'",
|
||||||
String8(text + start, count).string());
|
String8(text + start, count).string());
|
||||||
@ -909,7 +930,7 @@ sp<TextLayoutValue> TextLayoutEngine::getValue(const SkPaint* paint, const jchar
|
|||||||
#else
|
#else
|
||||||
value = new TextLayoutValue(count);
|
value = new TextLayoutValue(count);
|
||||||
mShaper->computeValues(value.get(), paint,
|
mShaper->computeValues(value.get(), paint,
|
||||||
reinterpret_cast<const UChar*>(text), start, count, contextCount);
|
reinterpret_cast<const UChar*>(text), start, count, contextCount, dirFlags);
|
||||||
#endif
|
#endif
|
||||||
return value;
|
return value;
|
||||||
}
|
}
|
||||||
|
@ -70,7 +70,7 @@ public:
|
|||||||
TextLayoutCacheKey();
|
TextLayoutCacheKey();
|
||||||
|
|
||||||
TextLayoutCacheKey(const SkPaint* paint, const UChar* text, size_t start, size_t count,
|
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);
|
TextLayoutCacheKey(const TextLayoutCacheKey& other);
|
||||||
|
|
||||||
@ -97,6 +97,7 @@ private:
|
|||||||
size_t start;
|
size_t start;
|
||||||
size_t count;
|
size_t count;
|
||||||
size_t contextCount;
|
size_t contextCount;
|
||||||
|
int dirFlags;
|
||||||
SkTypeface* typeface;
|
SkTypeface* typeface;
|
||||||
SkScalar textSize;
|
SkScalar textSize;
|
||||||
SkScalar textSkewX;
|
SkScalar textSkewX;
|
||||||
@ -180,7 +181,7 @@ public:
|
|||||||
virtual ~TextLayoutShaper();
|
virtual ~TextLayoutShaper();
|
||||||
|
|
||||||
void computeValues(TextLayoutValue* value, const SkPaint* paint, const UChar* chars,
|
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();
|
void purgeCaches();
|
||||||
|
|
||||||
@ -214,7 +215,7 @@ private:
|
|||||||
size_t shapeFontRun(const SkPaint* paint);
|
size_t shapeFontRun(const SkPaint* paint);
|
||||||
|
|
||||||
void computeValues(const SkPaint* paint, const UChar* chars,
|
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<jfloat>* const outAdvances, jfloat* outTotalAdvance,
|
||||||
Vector<jchar>* const outGlyphs, Vector<jfloat>* const outPos);
|
Vector<jchar>* const outGlyphs, Vector<jfloat>* const outPos);
|
||||||
|
|
||||||
@ -251,7 +252,7 @@ public:
|
|||||||
void operator()(TextLayoutCacheKey& text, sp<TextLayoutValue>& desc);
|
void operator()(TextLayoutCacheKey& text, sp<TextLayoutValue>& desc);
|
||||||
|
|
||||||
sp<TextLayoutValue> getValue(const SkPaint* paint, const jchar* text, jint start,
|
sp<TextLayoutValue> getValue(const SkPaint* paint, const jchar* text, jint start,
|
||||||
jint count, jint contextCount);
|
jint count, jint contextCount, jint dirFlags);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Clear the cache
|
* Clear the cache
|
||||||
@ -303,7 +304,7 @@ public:
|
|||||||
* the call. Be careful of this when doing optimization.
|
* the call. Be careful of this when doing optimization.
|
||||||
**/
|
**/
|
||||||
sp<TextLayoutValue> getValue(const SkPaint* paint, const jchar* text, jint start,
|
sp<TextLayoutValue> getValue(const SkPaint* paint, const jchar* text, jint start,
|
||||||
jint count, jint contextCount);
|
jint count, jint contextCount, jint dirFlags);
|
||||||
|
|
||||||
void purgeCaches();
|
void purgeCaches();
|
||||||
|
|
||||||
|
@ -568,9 +568,9 @@ static void android_view_GLES20Canvas_resetPaintFilter(JNIEnv* env, jobject claz
|
|||||||
// ----------------------------------------------------------------------------
|
// ----------------------------------------------------------------------------
|
||||||
|
|
||||||
static void renderText(OpenGLRenderer* renderer, const jchar* text, int count,
|
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,
|
sp<TextLayoutValue> value = TextLayoutEngine::getInstance().getValue(paint,
|
||||||
text, 0, count, count);
|
text, 0, count, count, flags);
|
||||||
if (value == NULL) {
|
if (value == NULL) {
|
||||||
return;
|
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,
|
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,
|
sp<TextLayoutValue> value = TextLayoutEngine::getInstance().getValue(paint,
|
||||||
text, 0, count, count);
|
text, 0, count, count, flags);
|
||||||
if (value == NULL) {
|
if (value == NULL) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -599,9 +599,9 @@ static void renderTextOnPath(OpenGLRenderer* renderer, const jchar* text, int co
|
|||||||
|
|
||||||
static void renderTextRun(OpenGLRenderer* renderer, const jchar* text,
|
static void renderTextRun(OpenGLRenderer* renderer, const jchar* text,
|
||||||
jint start, jint count, jint contextCount, jfloat x, jfloat y,
|
jint start, jint count, jint contextCount, jfloat x, jfloat y,
|
||||||
SkPaint* paint) {
|
int flags, SkPaint* paint) {
|
||||||
sp<TextLayoutValue> value = TextLayoutEngine::getInstance().getValue(paint,
|
sp<TextLayoutValue> value = TextLayoutEngine::getInstance().getValue(paint,
|
||||||
text, start, count, contextCount);
|
text, start, count, contextCount, flags);
|
||||||
if (value == NULL) {
|
if (value == NULL) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -616,62 +616,64 @@ static void renderTextRun(OpenGLRenderer* renderer, const jchar* text,
|
|||||||
|
|
||||||
static void android_view_GLES20Canvas_drawTextArray(JNIEnv* env, jobject clazz,
|
static void android_view_GLES20Canvas_drawTextArray(JNIEnv* env, jobject clazz,
|
||||||
OpenGLRenderer* renderer, jcharArray text, jint index, jint count,
|
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);
|
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);
|
env->ReleaseCharArrayElements(text, textArray, JNI_ABORT);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void android_view_GLES20Canvas_drawText(JNIEnv* env, jobject clazz,
|
static void android_view_GLES20Canvas_drawText(JNIEnv* env, jobject clazz,
|
||||||
OpenGLRenderer* renderer, jstring text, jint start, jint end,
|
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);
|
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);
|
env->ReleaseStringChars(text, textArray);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void android_view_GLES20Canvas_drawTextArrayOnPath(JNIEnv* env, jobject clazz,
|
static void android_view_GLES20Canvas_drawTextArrayOnPath(JNIEnv* env, jobject clazz,
|
||||||
OpenGLRenderer* renderer, jcharArray text, jint index, jint count,
|
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);
|
jchar* textArray = env->GetCharArrayElements(text, NULL);
|
||||||
renderTextOnPath(renderer, textArray + index, count, path,
|
renderTextOnPath(renderer, textArray + index, count, path,
|
||||||
hOffset, vOffset, paint);
|
hOffset, vOffset, flags, paint);
|
||||||
env->ReleaseCharArrayElements(text, textArray, JNI_ABORT);
|
env->ReleaseCharArrayElements(text, textArray, JNI_ABORT);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void android_view_GLES20Canvas_drawTextOnPath(JNIEnv* env, jobject clazz,
|
static void android_view_GLES20Canvas_drawTextOnPath(JNIEnv* env, jobject clazz,
|
||||||
OpenGLRenderer* renderer, jstring text, jint start, jint end,
|
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);
|
const jchar* textArray = env->GetStringChars(text, NULL);
|
||||||
renderTextOnPath(renderer, textArray + start, end - start, path,
|
renderTextOnPath(renderer, textArray + start, end - start, path,
|
||||||
hOffset, vOffset, paint);
|
hOffset, vOffset, flags, paint);
|
||||||
env->ReleaseStringChars(text, textArray);
|
env->ReleaseStringChars(text, textArray);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void android_view_GLES20Canvas_drawTextRunArray(JNIEnv* env, jobject clazz,
|
static void android_view_GLES20Canvas_drawTextRunArray(JNIEnv* env, jobject clazz,
|
||||||
OpenGLRenderer* renderer, jcharArray text, jint index, jint count,
|
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);
|
jchar* textArray = env->GetCharArrayElements(text, NULL);
|
||||||
renderTextRun(renderer, textArray + contextIndex, index - contextIndex,
|
renderTextRun(renderer, textArray + contextIndex, index - contextIndex,
|
||||||
count, contextCount, x, y, paint);
|
count, contextCount, x, y, dirFlags, paint);
|
||||||
env->ReleaseCharArrayElements(text, textArray, JNI_ABORT);
|
env->ReleaseCharArrayElements(text, textArray, JNI_ABORT);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void android_view_GLES20Canvas_drawTextRun(JNIEnv* env, jobject clazz,
|
static void android_view_GLES20Canvas_drawTextRun(JNIEnv* env, jobject clazz,
|
||||||
OpenGLRenderer* renderer, jstring text, jint start, jint end,
|
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);
|
const jchar* textArray = env->GetStringChars(text, NULL);
|
||||||
jint count = end - start;
|
jint count = end - start;
|
||||||
jint contextCount = contextEnd - contextStart;
|
jint contextCount = contextEnd - contextStart;
|
||||||
renderTextRun(renderer, textArray + contextStart, start - contextStart,
|
renderTextRun(renderer, textArray + contextStart, start - contextStart,
|
||||||
count, contextCount, x, y, paint);
|
count, contextCount, x, y, dirFlags, paint);
|
||||||
env->ReleaseStringChars(text, textArray);
|
env->ReleaseStringChars(text, textArray);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void renderPosText(OpenGLRenderer* renderer, const jchar* text, int count,
|
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,
|
sp<TextLayoutValue> value = TextLayoutEngine::getInstance().getValue(paint,
|
||||||
text, 0, count, count);
|
text, 0, count, count, dirFlags);
|
||||||
if (value == NULL) {
|
if (value == NULL) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -689,7 +691,7 @@ static void android_view_GLES20Canvas_drawPosTextArray(JNIEnv* env, jobject claz
|
|||||||
jchar* textArray = env->GetCharArrayElements(text, NULL);
|
jchar* textArray = env->GetCharArrayElements(text, NULL);
|
||||||
jfloat* positions = env->GetFloatArrayElements(pos, 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->ReleaseFloatArrayElements(pos, positions, JNI_ABORT);
|
||||||
env->ReleaseCharArrayElements(text, textArray, 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);
|
const jchar* textArray = env->GetStringChars(text, NULL);
|
||||||
jfloat* positions = env->GetFloatArrayElements(pos, 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->ReleaseFloatArrayElements(pos, positions, JNI_ABORT);
|
||||||
env->ReleaseStringChars(text, textArray);
|
env->ReleaseStringChars(text, textArray);
|
||||||
@ -1005,16 +1007,16 @@ static JNINativeMethod gMethods[] = {
|
|||||||
{ "nSetupPaintFilter", "(III)V", (void*) android_view_GLES20Canvas_setupPaintFilter },
|
{ "nSetupPaintFilter", "(III)V", (void*) android_view_GLES20Canvas_setupPaintFilter },
|
||||||
{ "nResetPaintFilter", "(I)V", (void*) android_view_GLES20Canvas_resetPaintFilter },
|
{ "nResetPaintFilter", "(I)V", (void*) android_view_GLES20Canvas_resetPaintFilter },
|
||||||
|
|
||||||
{ "nDrawText", "(I[CIIFFI)V", (void*) android_view_GLES20Canvas_drawTextArray },
|
{ "nDrawText", "(I[CIIFFII)V", (void*) android_view_GLES20Canvas_drawTextArray },
|
||||||
{ "nDrawText", "(ILjava/lang/String;IIFFI)V",
|
{ "nDrawText", "(ILjava/lang/String;IIFFII)V",
|
||||||
(void*) android_view_GLES20Canvas_drawText },
|
(void*) android_view_GLES20Canvas_drawText },
|
||||||
|
|
||||||
{ "nDrawTextOnPath", "(I[CIIIFFI)V", (void*) android_view_GLES20Canvas_drawTextArrayOnPath },
|
{ "nDrawTextOnPath", "(I[CIIIFFII)V", (void*) android_view_GLES20Canvas_drawTextArrayOnPath },
|
||||||
{ "nDrawTextOnPath", "(ILjava/lang/String;IIIFFI)V",
|
{ "nDrawTextOnPath", "(ILjava/lang/String;IIIFFII)V",
|
||||||
(void*) android_view_GLES20Canvas_drawTextOnPath },
|
(void*) android_view_GLES20Canvas_drawTextOnPath },
|
||||||
|
|
||||||
{ "nDrawTextRun", "(I[CIIIIFFI)V", (void*) android_view_GLES20Canvas_drawTextRunArray },
|
{ "nDrawTextRun", "(I[CIIIIFFII)V", (void*) android_view_GLES20Canvas_drawTextRunArray },
|
||||||
{ "nDrawTextRun", "(ILjava/lang/String;IIIIFFI)V",
|
{ "nDrawTextRun", "(ILjava/lang/String;IIIIFFII)V",
|
||||||
(void*) android_view_GLES20Canvas_drawTextRun },
|
(void*) android_view_GLES20Canvas_drawTextRun },
|
||||||
|
|
||||||
{ "nDrawPosText", "(I[CII[FI)V", (void*) android_view_GLES20Canvas_drawPosTextArray },
|
{ "nDrawPosText", "(I[CII[FI)V", (void*) android_view_GLES20Canvas_drawPosTextArray },
|
||||||
|
@ -62,6 +62,18 @@ public class Canvas {
|
|||||||
@SuppressWarnings({"UnusedDeclaration"})
|
@SuppressWarnings({"UnusedDeclaration"})
|
||||||
private int mSurfaceFormat;
|
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
|
// Maximum bitmap size as defined in Skia's native code
|
||||||
// (see SkCanvas.cpp, SkDraw.cpp)
|
// (see SkCanvas.cpp, SkDraw.cpp)
|
||||||
private static final int MAXMIMUM_BITMAP_SIZE = 32766;
|
private static final int MAXMIMUM_BITMAP_SIZE = 32766;
|
||||||
@ -1333,7 +1345,8 @@ public class Canvas {
|
|||||||
(text.length - index - count)) < 0) {
|
(text.length - index - count)) < 0) {
|
||||||
throw new IndexOutOfBoundsException();
|
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)
|
* @param paint The paint used for the text (e.g. color, size, style)
|
||||||
*/
|
*/
|
||||||
public 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.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) {
|
if ((start | end | (end - start) | (text.length() - end)) < 0) {
|
||||||
throw new IndexOutOfBoundsException();
|
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) {
|
public void drawText(CharSequence text, int start, int end, float x, float y, Paint paint) {
|
||||||
if (text instanceof String || text instanceof SpannedString ||
|
if (text instanceof String || text instanceof SpannedString ||
|
||||||
text instanceof SpannableString) {
|
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) {
|
} else if (text instanceof GraphicsOperations) {
|
||||||
((GraphicsOperations) text).drawText(this, start, end, x, y,
|
((GraphicsOperations) text).drawText(this, start, end, x, y,
|
||||||
paint);
|
paint);
|
||||||
} else {
|
} else {
|
||||||
char[] buf = TemporaryBuffer.obtain(end - start);
|
char[] buf = TemporaryBuffer.obtain(end - start);
|
||||||
TextUtils.getChars(text, start, end, buf, 0);
|
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);
|
TemporaryBuffer.recycle(buf);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1411,11 +1428,13 @@ public class Canvas {
|
|||||||
* + count.
|
* + count.
|
||||||
* @param x the x position at which to draw the text
|
* @param x the x position at which to draw the text
|
||||||
* @param y the y 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
|
* @param paint the paint
|
||||||
* @hide
|
* @hide
|
||||||
*/
|
*/
|
||||||
public void drawTextRun(char[] text, int index, int count, int contextIndex, int contextCount,
|
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) {
|
if (text == null) {
|
||||||
throw new NullPointerException("text is null");
|
throw new NullPointerException("text is null");
|
||||||
@ -1426,9 +1445,12 @@ public class Canvas {
|
|||||||
if ((index | count | text.length - index - count) < 0) {
|
if ((index | count | text.length - index - count) < 0) {
|
||||||
throw new IndexOutOfBoundsException();
|
throw new IndexOutOfBoundsException();
|
||||||
}
|
}
|
||||||
|
if (dir != DIRECTION_LTR && dir != DIRECTION_RTL) {
|
||||||
|
throw new IllegalArgumentException("unknown dir: " + dir);
|
||||||
|
}
|
||||||
|
|
||||||
native_drawTextRun(mNativeCanvas, text, index, count,
|
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.
|
* position can be used for shaping context.
|
||||||
* @param x the x position at which to draw the text
|
* @param x the x position at which to draw the text
|
||||||
* @param y the y 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
|
* @param paint the paint
|
||||||
* @hide
|
* @hide
|
||||||
*/
|
*/
|
||||||
public void drawTextRun(CharSequence text, int start, int end, int contextStart, int contextEnd,
|
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) {
|
if (text == null) {
|
||||||
throw new NullPointerException("text is null");
|
throw new NullPointerException("text is null");
|
||||||
@ -1460,20 +1483,22 @@ public class Canvas {
|
|||||||
throw new IndexOutOfBoundsException();
|
throw new IndexOutOfBoundsException();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int flags = dir == 0 ? 0 : 1;
|
||||||
|
|
||||||
if (text instanceof String || text instanceof SpannedString ||
|
if (text instanceof String || text instanceof SpannedString ||
|
||||||
text instanceof SpannableString) {
|
text instanceof SpannableString) {
|
||||||
native_drawTextRun(mNativeCanvas, text.toString(), start, end,
|
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) {
|
} else if (text instanceof GraphicsOperations) {
|
||||||
((GraphicsOperations) text).drawTextRun(this, start, end,
|
((GraphicsOperations) text).drawTextRun(this, start, end,
|
||||||
contextStart, contextEnd, x, y, paint);
|
contextStart, contextEnd, x, y, flags, paint);
|
||||||
} else {
|
} else {
|
||||||
int contextLen = contextEnd - contextStart;
|
int contextLen = contextEnd - contextStart;
|
||||||
int len = end - start;
|
int len = end - start;
|
||||||
char[] buf = TemporaryBuffer.obtain(contextLen);
|
char[] buf = TemporaryBuffer.obtain(contextLen);
|
||||||
TextUtils.getChars(text, contextStart, contextEnd, buf, 0);
|
TextUtils.getChars(text, contextStart, contextEnd, buf, 0);
|
||||||
native_drawTextRun(mNativeCanvas, buf, start - contextStart, len,
|
native_drawTextRun(mNativeCanvas, buf, start - contextStart, len,
|
||||||
0, contextLen, x, y, paint.mNativePaint);
|
0, contextLen, x, y, flags, paint.mNativePaint);
|
||||||
TemporaryBuffer.recycle(buf);
|
TemporaryBuffer.recycle(buf);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1539,7 +1564,8 @@ public class Canvas {
|
|||||||
throw new ArrayIndexOutOfBoundsException();
|
throw new ArrayIndexOutOfBoundsException();
|
||||||
}
|
}
|
||||||
native_drawTextOnPath(mNativeCanvas, text, index, count,
|
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) {
|
public void drawTextOnPath(String text, Path path, float hOffset, float vOffset, Paint paint) {
|
||||||
if (text.length() > 0) {
|
if (text.length() > 0) {
|
||||||
native_drawTextOnPath(mNativeCanvas, text, path.ni(), hOffset, vOffset,
|
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,
|
private static native void native_drawText(int nativeCanvas, char[] text,
|
||||||
int index, int count, float x,
|
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,
|
private static native void native_drawText(int nativeCanvas, String text,
|
||||||
int start, int end, float x,
|
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,
|
private static native void native_drawTextRun(int nativeCanvas, String text,
|
||||||
int start, int end, int contextStart, int contextEnd,
|
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,
|
private static native void native_drawTextRun(int nativeCanvas, char[] text,
|
||||||
int start, int count, int contextStart, int contextCount,
|
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,
|
private static native void native_drawPosText(int nativeCanvas,
|
||||||
char[] text, int index,
|
char[] text, int index,
|
||||||
@ -1744,13 +1770,13 @@ public class Canvas {
|
|||||||
char[] text, int index,
|
char[] text, int index,
|
||||||
int count, int path,
|
int count, int path,
|
||||||
float hOffset,
|
float hOffset,
|
||||||
float vOffset,
|
float vOffset, int bidiFlags,
|
||||||
int paint);
|
int paint);
|
||||||
private static native void native_drawTextOnPath(int nativeCanvas,
|
private static native void native_drawTextOnPath(int nativeCanvas,
|
||||||
String text, int path,
|
String text, int path,
|
||||||
float hOffset,
|
float hOffset,
|
||||||
float vOffset,
|
float vOffset,
|
||||||
int paint);
|
int flags, int paint);
|
||||||
private static native void native_drawPicture(int nativeCanvas,
|
private static native void native_drawPicture(int nativeCanvas,
|
||||||
int nativePicture);
|
int nativePicture);
|
||||||
private static native void finalizer(int nativeCanvas);
|
private static native void finalizer(int nativeCanvas);
|
||||||
|
@ -69,6 +69,11 @@ public class Paint {
|
|||||||
*/
|
*/
|
||||||
public int shadowColor;
|
public int shadowColor;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @hide
|
||||||
|
*/
|
||||||
|
public int mBidiFlags = BIDI_DEFAULT_LTR;
|
||||||
|
|
||||||
static final Style[] sStyleArray = {
|
static final Style[] sStyleArray = {
|
||||||
Style.FILL, Style.STROKE, Style.FILL_AND_STROKE
|
Style.FILL, Style.STROKE, Style.FILL_AND_STROKE
|
||||||
};
|
};
|
||||||
@ -114,6 +119,74 @@ public class Paint {
|
|||||||
*/
|
*/
|
||||||
public static final int HINTING_ON = 0x1;
|
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
|
* Option for getTextRunCursor to compute the valid cursor after
|
||||||
* offset or the limit of the context, whichever is less.
|
* offset or the limit of the context, whichever is less.
|
||||||
@ -322,6 +395,7 @@ public class Paint {
|
|||||||
shadowRadius = 0;
|
shadowRadius = 0;
|
||||||
shadowColor = 0;
|
shadowColor = 0;
|
||||||
|
|
||||||
|
mBidiFlags = BIDI_DEFAULT_LTR;
|
||||||
setTextLocale(Locale.getDefault());
|
setTextLocale(Locale.getDefault());
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -361,6 +435,7 @@ public class Paint {
|
|||||||
shadowRadius = paint.shadowRadius;
|
shadowRadius = paint.shadowRadius;
|
||||||
shadowColor = paint.shadowColor;
|
shadowColor = paint.shadowColor;
|
||||||
|
|
||||||
|
mBidiFlags = paint.mBidiFlags;
|
||||||
mLocale = paint.mLocale;
|
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.
|
* 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 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
|
* Convenience overload that takes a char array instead of a
|
||||||
* String.
|
* String.
|
||||||
*
|
*
|
||||||
* @see #getTextRunAdvances(String, int, int, int, int, float[], int)
|
* @see #getTextRunAdvances(String, int, int, int, int, int, float[], int)
|
||||||
* @hide
|
* @hide
|
||||||
*/
|
*/
|
||||||
public float getTextRunAdvances(char[] chars, int index, int count,
|
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) {
|
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) {
|
if (chars == null) {
|
||||||
throw new IllegalArgumentException("text cannot be 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
|
if ((index | count | contextIndex | contextCount | advancesIndex
|
||||||
| (index - contextIndex) | (contextCount - count)
|
| (index - contextIndex) | (contextCount - count)
|
||||||
| ((contextIndex + contextCount) - (index + count))
|
| ((contextIndex + contextCount) - (index + count))
|
||||||
@ -1597,13 +1752,13 @@ public class Paint {
|
|||||||
}
|
}
|
||||||
if (!mHasCompatScaling) {
|
if (!mHasCompatScaling) {
|
||||||
return native_getTextRunAdvances(mNativePaint, chars, index, count,
|
return native_getTextRunAdvances(mNativePaint, chars, index, count,
|
||||||
contextIndex, contextCount, advances, advancesIndex);
|
contextIndex, contextCount, flags, advances, advancesIndex, reserved);
|
||||||
}
|
}
|
||||||
|
|
||||||
final float oldSize = getTextSize();
|
final float oldSize = getTextSize();
|
||||||
setTextSize(oldSize * mCompatScaling);
|
setTextSize(oldSize * mCompatScaling);
|
||||||
float res = native_getTextRunAdvances(mNativePaint, chars, index, count,
|
float res = native_getTextRunAdvances(mNativePaint, chars, index, count,
|
||||||
contextIndex, contextCount, advances, advancesIndex);
|
contextIndex, contextCount, flags, advances, advancesIndex, reserved);
|
||||||
setTextSize(oldSize);
|
setTextSize(oldSize);
|
||||||
|
|
||||||
if (advances != null) {
|
if (advances != null) {
|
||||||
@ -1618,12 +1773,26 @@ public class Paint {
|
|||||||
* Convenience overload that takes a CharSequence instead of a
|
* Convenience overload that takes a CharSequence instead of a
|
||||||
* String.
|
* String.
|
||||||
*
|
*
|
||||||
* @see #getTextRunAdvances(String, int, int, int, int, float[], int)
|
* @see #getTextRunAdvances(String, int, int, int, int, int, float[], int)
|
||||||
* @hide
|
* @hide
|
||||||
*/
|
*/
|
||||||
public float getTextRunAdvances(CharSequence text, int start, int end,
|
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) {
|
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) {
|
if (text == null) {
|
||||||
throw new IllegalArgumentException("text cannot be null");
|
throw new IllegalArgumentException("text cannot be null");
|
||||||
@ -1638,16 +1807,16 @@ public class Paint {
|
|||||||
|
|
||||||
if (text instanceof String) {
|
if (text instanceof String) {
|
||||||
return getTextRunAdvances((String) text, start, end,
|
return getTextRunAdvances((String) text, start, end,
|
||||||
contextStart, contextEnd, advances, advancesIndex);
|
contextStart, contextEnd, flags, advances, advancesIndex, reserved);
|
||||||
}
|
}
|
||||||
if (text instanceof SpannedString ||
|
if (text instanceof SpannedString ||
|
||||||
text instanceof SpannableString) {
|
text instanceof SpannableString) {
|
||||||
return getTextRunAdvances(text.toString(), start, end,
|
return getTextRunAdvances(text.toString(), start, end,
|
||||||
contextStart, contextEnd, advances, advancesIndex);
|
contextStart, contextEnd, flags, advances, advancesIndex, reserved);
|
||||||
}
|
}
|
||||||
if (text instanceof GraphicsOperations) {
|
if (text instanceof GraphicsOperations) {
|
||||||
return ((GraphicsOperations) text).getTextRunAdvances(start, end,
|
return ((GraphicsOperations) text).getTextRunAdvances(start, end,
|
||||||
contextStart, contextEnd, advances, advancesIndex, this);
|
contextStart, contextEnd, flags, advances, advancesIndex, this);
|
||||||
}
|
}
|
||||||
if (text.length() == 0 || end == start) {
|
if (text.length() == 0 || end == start) {
|
||||||
return 0f;
|
return 0f;
|
||||||
@ -1658,7 +1827,7 @@ public class Paint {
|
|||||||
char[] buf = TemporaryBuffer.obtain(contextLen);
|
char[] buf = TemporaryBuffer.obtain(contextLen);
|
||||||
TextUtils.getChars(text, contextStart, contextEnd, buf, 0);
|
TextUtils.getChars(text, contextStart, contextEnd, buf, 0);
|
||||||
float result = getTextRunAdvances(buf, start - contextStart, len,
|
float result = getTextRunAdvances(buf, start - contextStart, len,
|
||||||
0, contextLen, advances, advancesIndex);
|
0, contextLen, flags, advances, advancesIndex, reserved);
|
||||||
TemporaryBuffer.recycle(buf);
|
TemporaryBuffer.recycle(buf);
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
@ -1695,6 +1864,8 @@ public class Paint {
|
|||||||
* must be <= start
|
* must be <= start
|
||||||
* @param contextEnd the index past the last character to use for shaping context,
|
* @param contextEnd the index past the last character to use for shaping context,
|
||||||
* must be >= end
|
* 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,
|
* @param advances array to receive the advances, must have room for all advances,
|
||||||
* can be null if only total advance is needed
|
* can be null if only total advance is needed
|
||||||
* @param advancesIndex the position in advances at which to put the
|
* @param advancesIndex the position in advances at which to put the
|
||||||
@ -1704,11 +1875,63 @@ public class Paint {
|
|||||||
* @hide
|
* @hide
|
||||||
*/
|
*/
|
||||||
public float getTextRunAdvances(String text, int start, int end, int contextStart,
|
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) {
|
if (text == null) {
|
||||||
throw new IllegalArgumentException("text cannot be 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)
|
if ((start | end | contextStart | contextEnd | advancesIndex | (end - start)
|
||||||
| (start - contextStart) | (contextEnd - end)
|
| (start - contextStart) | (contextEnd - end)
|
||||||
| (text.length() - contextEnd)
|
| (text.length() - contextEnd)
|
||||||
@ -1723,13 +1946,13 @@ public class Paint {
|
|||||||
|
|
||||||
if (!mHasCompatScaling) {
|
if (!mHasCompatScaling) {
|
||||||
return native_getTextRunAdvances(mNativePaint, text, start, end,
|
return native_getTextRunAdvances(mNativePaint, text, start, end,
|
||||||
contextStart, contextEnd, advances, advancesIndex);
|
contextStart, contextEnd, flags, advances, advancesIndex, reserved);
|
||||||
}
|
}
|
||||||
|
|
||||||
final float oldSize = getTextSize();
|
final float oldSize = getTextSize();
|
||||||
setTextSize(oldSize * mCompatScaling);
|
setTextSize(oldSize * mCompatScaling);
|
||||||
float totalAdvance = native_getTextRunAdvances(mNativePaint, text, start, end,
|
float totalAdvance = native_getTextRunAdvances(mNativePaint, text, start, end,
|
||||||
contextStart, contextEnd, advances, advancesIndex);
|
contextStart, contextEnd, flags, advances, advancesIndex, reserved);
|
||||||
setTextSize(oldSize);
|
setTextSize(oldSize);
|
||||||
|
|
||||||
if (advances != null) {
|
if (advances != null) {
|
||||||
@ -1758,6 +1981,7 @@ public class Paint {
|
|||||||
* @param text the text
|
* @param text the text
|
||||||
* @param contextStart the start of the context
|
* @param contextStart the start of the context
|
||||||
* @param contextLength the length 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 offset the cursor position to move from
|
||||||
* @param cursorOpt how to move the cursor, one of {@link #CURSOR_AFTER},
|
* @param cursorOpt how to move the cursor, one of {@link #CURSOR_AFTER},
|
||||||
* {@link #CURSOR_AT_OR_AFTER}, {@link #CURSOR_BEFORE},
|
* {@link #CURSOR_AT_OR_AFTER}, {@link #CURSOR_BEFORE},
|
||||||
@ -1766,7 +1990,7 @@ public class Paint {
|
|||||||
* @hide
|
* @hide
|
||||||
*/
|
*/
|
||||||
public int getTextRunCursor(char[] text, int contextStart, int contextLength,
|
public int getTextRunCursor(char[] text, int contextStart, int contextLength,
|
||||||
int offset, int cursorOpt) {
|
int flags, int offset, int cursorOpt) {
|
||||||
int contextEnd = contextStart + contextLength;
|
int contextEnd = contextStart + contextLength;
|
||||||
if (((contextStart | contextEnd | offset | (contextEnd - contextStart)
|
if (((contextStart | contextEnd | offset | (contextEnd - contextStart)
|
||||||
| (offset - contextStart) | (contextEnd - offset)
|
| (offset - contextStart) | (contextEnd - offset)
|
||||||
@ -1776,7 +2000,7 @@ public class Paint {
|
|||||||
}
|
}
|
||||||
|
|
||||||
return native_getTextRunCursor(mNativePaint, text,
|
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 text the text
|
||||||
* @param contextStart the start of the context
|
* @param contextStart the start of the context
|
||||||
* @param contextEnd the end 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 offset the cursor position to move from
|
||||||
* @param cursorOpt how to move the cursor, one of {@link #CURSOR_AFTER},
|
* @param cursorOpt how to move the cursor, one of {@link #CURSOR_AFTER},
|
||||||
* {@link #CURSOR_AT_OR_AFTER}, {@link #CURSOR_BEFORE},
|
* {@link #CURSOR_AT_OR_AFTER}, {@link #CURSOR_BEFORE},
|
||||||
@ -1805,22 +2030,22 @@ public class Paint {
|
|||||||
* @hide
|
* @hide
|
||||||
*/
|
*/
|
||||||
public int getTextRunCursor(CharSequence text, int contextStart,
|
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 ||
|
if (text instanceof String || text instanceof SpannedString ||
|
||||||
text instanceof SpannableString) {
|
text instanceof SpannableString) {
|
||||||
return getTextRunCursor(text.toString(), contextStart, contextEnd,
|
return getTextRunCursor(text.toString(), contextStart, contextEnd,
|
||||||
offset, cursorOpt);
|
flags, offset, cursorOpt);
|
||||||
}
|
}
|
||||||
if (text instanceof GraphicsOperations) {
|
if (text instanceof GraphicsOperations) {
|
||||||
return ((GraphicsOperations) text).getTextRunCursor(
|
return ((GraphicsOperations) text).getTextRunCursor(
|
||||||
contextStart, contextEnd, offset, cursorOpt, this);
|
contextStart, contextEnd, flags, offset, cursorOpt, this);
|
||||||
}
|
}
|
||||||
|
|
||||||
int contextLen = contextEnd - contextStart;
|
int contextLen = contextEnd - contextStart;
|
||||||
char[] buf = TemporaryBuffer.obtain(contextLen);
|
char[] buf = TemporaryBuffer.obtain(contextLen);
|
||||||
TextUtils.getChars(text, contextStart, contextEnd, buf, 0);
|
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);
|
TemporaryBuffer.recycle(buf);
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
@ -1843,6 +2068,7 @@ public class Paint {
|
|||||||
* @param text the text
|
* @param text the text
|
||||||
* @param contextStart the start of the context
|
* @param contextStart the start of the context
|
||||||
* @param contextEnd the end 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 offset the cursor position to move from
|
||||||
* @param cursorOpt how to move the cursor, one of {@link #CURSOR_AFTER},
|
* @param cursorOpt how to move the cursor, one of {@link #CURSOR_AFTER},
|
||||||
* {@link #CURSOR_AT_OR_AFTER}, {@link #CURSOR_BEFORE},
|
* {@link #CURSOR_AT_OR_AFTER}, {@link #CURSOR_BEFORE},
|
||||||
@ -1860,7 +2086,7 @@ public class Paint {
|
|||||||
}
|
}
|
||||||
|
|
||||||
return native_getTextRunCursor(mNativePaint, text,
|
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) {
|
if ((index | count) < 0 || index + count > text.length) {
|
||||||
throw new ArrayIndexOutOfBoundsException();
|
throw new ArrayIndexOutOfBoundsException();
|
||||||
}
|
}
|
||||||
native_getTextPath(mNativePaint, text, index, count, x, y,
|
native_getTextPath(mNativePaint, mBidiFlags, text, index, count, x, y,
|
||||||
path.ni());
|
path.ni());
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1903,7 +2129,7 @@ public class Paint {
|
|||||||
if ((start | end | (end - start) | (text.length() - end)) < 0) {
|
if ((start | end | (end - start) | (text.length() - end)) < 0) {
|
||||||
throw new IndexOutOfBoundsException();
|
throw new IndexOutOfBoundsException();
|
||||||
}
|
}
|
||||||
native_getTextPath(mNativePaint, text, start, end, x, y,
|
native_getTextPath(mNativePaint, mBidiFlags, text, start, end, x, y,
|
||||||
path.ni());
|
path.ni());
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1995,22 +2221,26 @@ public class Paint {
|
|||||||
private static native int native_getTextWidths(int native_object,
|
private static native int native_getTextWidths(int native_object,
|
||||||
String text, int start, int end, float[] widths);
|
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,
|
private static native float native_getTextRunAdvances(int native_object,
|
||||||
char[] text, int index, int count, int contextIndex, int contextCount,
|
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,
|
private static native float native_getTextRunAdvances(int native_object,
|
||||||
String text, int start, int end, int contextStart, int contextEnd,
|
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,
|
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,
|
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,
|
private static native void native_getTextPath(int native_object, int bidiFlags,
|
||||||
int index, int count, float x, float y, int path);
|
char[] text, int index, int count, float x, float y, int path);
|
||||||
private static native void native_getTextPath(int native_object, String text,
|
private static native void native_getTextPath(int native_object, int bidiFlags,
|
||||||
int start, int end, float x, float y, int path);
|
String text, int start, int end, float x, float y, int path);
|
||||||
private static native void nativeGetStringBounds(int nativePaint,
|
private static native void nativeGetStringBounds(int nativePaint,
|
||||||
String text, int start, int end, Rect bounds);
|
String text, int start, int end, Rect bounds);
|
||||||
private static native void nativeGetCharArrayBounds(int nativePaint,
|
private static native void nativeGetCharArrayBounds(int nativePaint,
|
||||||
|
40
tests/BiDiTests/res/layout/canvas.xml
Normal file
40
tests/BiDiTests/res/layout/canvas.xml
Normal 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>
|
@ -101,6 +101,7 @@ public class BiDiTestActivity extends Activity {
|
|||||||
|
|
||||||
addItem(result, "Basic", BiDiTestBasic.class, R.id.basic);
|
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, "Canvas2", BiDiTestCanvas2.class, R.id.canvas2);
|
||||||
|
|
||||||
addItem(result, "TextView LTR", BiDiTestTextViewLtr.class, R.id.textview_ltr);
|
addItem(result, "TextView LTR", BiDiTestTextViewLtr.class, R.id.textview_ltr);
|
||||||
|
67
tests/BiDiTests/src/com/android/bidi/BiDiTestCanvas.java
Normal file
67
tests/BiDiTests/src/com/android/bidi/BiDiTestCanvas.java
Normal 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) {
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
212
tests/BiDiTests/src/com/android/bidi/BiDiTestView.java
Normal file
212
tests/BiDiTests/src/com/android/bidi/BiDiTestView.java
Normal 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]);
|
||||||
|
// }
|
||||||
|
}
|
||||||
|
}
|
Reference in New Issue
Block a user