diff options
Diffstat (limited to 'tools/layoutlib')
4 files changed, 154 insertions, 89 deletions
diff --git a/tools/layoutlib/bridge/src/android/graphics/BidiRenderer.java b/tools/layoutlib/bridge/src/android/graphics/BidiRenderer.java index 33813d1..88ebd1f 100644 --- a/tools/layoutlib/bridge/src/android/graphics/BidiRenderer.java +++ b/tools/layoutlib/bridge/src/android/graphics/BidiRenderer.java @@ -28,6 +28,8 @@ import java.util.List; import com.ibm.icu.lang.UScript; import com.ibm.icu.lang.UScriptRun; +import com.ibm.icu.text.Bidi; +import com.ibm.icu.text.BidiRun; import android.graphics.Paint_Delegate.FontInfo; @@ -38,7 +40,7 @@ import android.graphics.Paint_Delegate.FontInfo; @SuppressWarnings("deprecation") public class BidiRenderer { - /*package*/ static class ScriptRun { + private static class ScriptRun { int start; int limit; boolean isRtl; @@ -66,7 +68,7 @@ public class BidiRenderer { * @param paint The Paint to use to get the fonts. Should not be null. * @param text Unidirectional text. Should not be null. */ - /*package*/ BidiRenderer(Graphics2D graphics, Paint_Delegate paint, char[] text) { + public BidiRenderer(Graphics2D graphics, Paint_Delegate paint, char[] text) { assert (paint != null); mGraphics = graphics; mPaint = paint; @@ -75,13 +77,45 @@ public class BidiRenderer { for (FontInfo fontInfo : paint.getFonts()) { mFonts.add(fontInfo.mFont); } + mBounds = new RectF(); } /** - * Render unidirectional text. * - * This method can also be used to measure the width of the text without actually drawing it. + * @param x The x-coordinate of the left edge of where the text should be drawn on the given + * graphics. + * @param y The y-coordinate at which to draw the text on the given mGraphics. * + */ + public BidiRenderer setRenderLocation(float x, float y) { + mBounds = new RectF(x, y, x, y); + mBaseline = y; + return this; + } + + /** + * Perform Bidi Analysis on the text and then render it. + * <p/> + * To skip the analysis and render unidirectional text, see {@link + * #renderText(int, int, boolean, float[], int, boolean)} + */ + public RectF renderText(int start, int limit, int bidiFlags, float[] advances, + int advancesIndex, boolean draw) { + Bidi bidi = new Bidi(mText, start, null, 0, limit - start, getIcuFlags(bidiFlags)); + for (int i = 0; i < bidi.countRuns(); i++) { + BidiRun visualRun = bidi.getVisualRun(i); + boolean isRtl = visualRun.getDirection() == Bidi.RTL; + renderText(visualRun.getStart(), visualRun.getLimit(), isRtl, advances, + advancesIndex, draw); + } + return mBounds; + } + + /** + * Render unidirectional text. + * <p/> + * This method can also be used to measure the width of the text without actually drawing it. + * <p/> * @param start index of the first character * @param limit index of the first character that should not be rendered. * @param isRtl is the text right-to-left @@ -90,17 +124,12 @@ public class BidiRenderer { * @param advancesIndex index into advances from where the advances need to be filled. * @param draw If true and {@code graphics} is not null, draw the rendered text on the graphics * at the given co-ordinates - * @param x The x-coordinate of the left edge of where the text should be drawn on the given - * graphics. - * @param y The y-coordinate at which to draw the text on the given mGraphics. * @return A rectangle specifying the bounds of the text drawn. */ - /* package */ RectF renderText(int start, int limit, boolean isRtl, float[] advances, - int advancesIndex, boolean draw, float x, float y) { + public RectF renderText(int start, int limit, boolean isRtl, float[] advances, + int advancesIndex, boolean draw) { // We break the text into scripts and then select font based on it and then render each of // the script runs. - mBounds = new RectF(x, y, x, y); - mBaseline = y; for (ScriptRun run : getScriptRuns(mText, start, limit, isRtl, mFonts)) { int flag = Font.LAYOUT_NO_LIMIT_CONTEXT | Font.LAYOUT_NO_START_CONTEXT; flag |= isRtl ? Font.LAYOUT_RIGHT_TO_LEFT : Font.LAYOUT_LEFT_TO_RIGHT; @@ -244,4 +273,22 @@ public class BidiRenderer { } run.font = fonts.get(0); } + + private static int getIcuFlags(int bidiFlag) { + switch (bidiFlag) { + case Paint.BIDI_LTR: + case Paint.BIDI_FORCE_LTR: + return Bidi.DIRECTION_LEFT_TO_RIGHT; + case Paint.BIDI_RTL: + case Paint.BIDI_FORCE_RTL: + return Bidi.DIRECTION_RIGHT_TO_LEFT; + case Paint.BIDI_DEFAULT_LTR: + return Bidi.DIRECTION_DEFAULT_LEFT_TO_RIGHT; + case Paint.BIDI_DEFAULT_RTL: + return Bidi.DIRECTION_DEFAULT_RIGHT_TO_LEFT; + default: + assert false; + return Bidi.DIRECTION_DEFAULT_LEFT_TO_RIGHT; + } + } } diff --git a/tools/layoutlib/bridge/src/android/graphics/Canvas_Delegate.java b/tools/layoutlib/bridge/src/android/graphics/Canvas_Delegate.java index 12e4a85..7c8ef70 100644 --- a/tools/layoutlib/bridge/src/android/graphics/Canvas_Delegate.java +++ b/tools/layoutlib/bridge/src/android/graphics/Canvas_Delegate.java @@ -906,41 +906,10 @@ public final class Canvas_Delegate { } @LayoutlibDelegate - /*package*/ static void native_drawText(long nativeCanvas, - final char[] text, final int index, final int count, - final float startX, final float startY, final int flags, long paint, - final long typeface) { - - draw(nativeCanvas, paint, false /*compositeOnly*/, false /*forceSrcMode*/, - new GcSnapshot.Drawable() { - @Override - public void draw(Graphics2D graphics, Paint_Delegate paintDelegate) { - // WARNING: the logic in this method is similar to Paint_Delegate.measureText. - // Any change to this method should be reflected in Paint.measureText - - // assert that the typeface passed is actually the one stored in paint. - assert (typeface == paintDelegate.mNativeTypeface); - - - // Paint.TextAlign indicates how the text is positioned relative to X. - // LEFT is the default and there's nothing to do. - float x = startX; - int limit = index + count; - boolean isRtl = flags == Canvas.DIRECTION_RTL; - if (paintDelegate.getTextAlign() != Paint.Align.LEFT.nativeInt) { - RectF bounds = paintDelegate.measureText(text, index, count, isRtl); - float m = bounds.right - bounds.left; - if (paintDelegate.getTextAlign() == Paint.Align.CENTER.nativeInt) { - x -= m / 2; - } else if (paintDelegate.getTextAlign() == Paint.Align.RIGHT.nativeInt) { - x -= m; - } - } - - new BidiRenderer(graphics, paintDelegate, text).renderText( - index, limit, isRtl, null, 0, true, x, startY); - } - }); + /*package*/ static void native_drawText(long nativeCanvas, char[] text, int index, int count, + float startX, float startY, int flags, long paint, long typeface) { + drawText(nativeCanvas, text, index, count, startX, startY, flags == Canvas.DIRECTION_RTL, + paint, typeface); } @LayoutlibDelegate @@ -957,19 +926,19 @@ public final class Canvas_Delegate { @LayoutlibDelegate /*package*/ static void native_drawTextRun(long nativeCanvas, String text, int start, int end, int contextStart, int contextEnd, - float x, float y, int flags, long paint, long typeface) { + float x, float y, boolean isRtl, long paint, long typeface) { int count = end - start; char[] buffer = TemporaryBuffer.obtain(count); TextUtils.getChars(text, start, end, buffer, 0); - native_drawText(nativeCanvas, buffer, 0, count, x, y, flags, paint, typeface); + drawText(nativeCanvas, buffer, 0, count, x, y, isRtl, paint, typeface); } @LayoutlibDelegate /*package*/ static void native_drawTextRun(long nativeCanvas, char[] text, int start, int count, int contextStart, int contextCount, - float x, float y, int flags, long paint, long typeface) { - native_drawText(nativeCanvas, text, start, count, x, y, flags, paint, typeface); + float x, float y, boolean isRtl, long paint, long typeface) { + drawText(nativeCanvas, text, start, count, x, y, isRtl, paint, typeface); } @LayoutlibDelegate @@ -978,7 +947,7 @@ public final class Canvas_Delegate { int count, long path, float hOffset, float vOffset, int bidiFlags, - long paint) { + long paint, long typeface) { // FIXME Bridge.getLog().fidelityWarning(LayoutLog.TAG_UNSUPPORTED, "Canvas.drawTextOnPath is not supported.", null, null /*data*/); @@ -989,7 +958,8 @@ public final class Canvas_Delegate { String text, long path, float hOffset, float vOffset, - int bidiFlags, long paint, long typeface) { + int bidiFlags, long paint, + long typeface) { // FIXME Bridge.getLog().fidelityWarning(LayoutLog.TAG_UNSUPPORTED, "Canvas.drawTextOnPath is not supported.", null, null /*data*/); @@ -1047,6 +1017,41 @@ public final class Canvas_Delegate { canvasDelegate.mSnapshot.draw(drawable); } + private static void drawText(long nativeCanvas, final char[] text, final int index, + final int count, final float startX, final float startY, final boolean isRtl, + long paint, final long typeface) { + + draw(nativeCanvas, paint, false /*compositeOnly*/, false /*forceSrcMode*/, + new GcSnapshot.Drawable() { + @Override + public void draw(Graphics2D graphics, Paint_Delegate paintDelegate) { + // WARNING: the logic in this method is similar to Paint_Delegate.measureText. + // Any change to this method should be reflected in Paint.measureText + + // assert that the typeface passed is actually the one stored in paint. + assert (typeface == paintDelegate.mNativeTypeface); + + // Paint.TextAlign indicates how the text is positioned relative to X. + // LEFT is the default and there's nothing to do. + float x = startX; + int limit = index + count; + if (paintDelegate.getTextAlign() != Paint.Align.LEFT.nativeInt) { + RectF bounds = paintDelegate.measureText(text, index, count, null, 0, + isRtl); + float m = bounds.right - bounds.left; + if (paintDelegate.getTextAlign() == Paint.Align.CENTER.nativeInt) { + x -= m / 2; + } else if (paintDelegate.getTextAlign() == Paint.Align.RIGHT.nativeInt) { + x -= m; + } + } + + new BidiRenderer(graphics, paintDelegate, text).setRenderLocation(x, startY) + .renderText(index, limit, isRtl, null, 0, true); + } + }); + } + private Canvas_Delegate(Bitmap_Delegate bitmap) { mSnapshot = GcSnapshot.createDefaultSnapshot(mBitmap = bitmap); } diff --git a/tools/layoutlib/bridge/src/android/graphics/Paint_Delegate.java b/tools/layoutlib/bridge/src/android/graphics/Paint_Delegate.java index 5adf4ca..24ef189 100644 --- a/tools/layoutlib/bridge/src/android/graphics/Paint_Delegate.java +++ b/tools/layoutlib/bridge/src/android/graphics/Paint_Delegate.java @@ -602,7 +602,7 @@ public class Paint_Delegate { return 0; } - RectF bounds = delegate.measureText(text, index, count, isRtl(bidiFlags)); + RectF bounds = delegate.measureText(text, index, count, null, 0, bidiFlags); return bounds.right - bounds.left; } @@ -618,11 +618,11 @@ public class Paint_Delegate { } @LayoutlibDelegate - /*package*/ static int native_breakText(Paint thisPaint, char[] text, int index, int count, - float maxWidth, int bidiFlags, float[] measuredWidth) { + /*package*/ static int native_breakText(long nativePaint, long nativeTypeface, char[] text, + int index, int count, float maxWidth, int bidiFlags, float[] measuredWidth) { // get the delegate - Paint_Delegate delegate = sManager.getDelegate(thisPaint.mNativePaint); + Paint_Delegate delegate = sManager.getDelegate(nativePaint); if (delegate == null) { return 0; } @@ -641,7 +641,7 @@ public class Paint_Delegate { } // measure from start to end - RectF bounds = delegate.measureText(text, start, end - start + 1, isRtl(bidiFlags)); + RectF bounds = delegate.measureText(text, start, end - start + 1, null, 0, bidiFlags); float res = bounds.right - bounds.left; if (measuredWidth != null) { @@ -660,10 +660,11 @@ public class Paint_Delegate { } @LayoutlibDelegate - /*package*/ static int native_breakText(Paint thisPaint, String text, boolean measureForwards, + /*package*/ static int native_breakText(long nativePaint, long nativeTypeface, String text, + boolean measureForwards, float maxWidth, int bidiFlags, float[] measuredWidth) { - return native_breakText(thisPaint, text.toCharArray(), 0, text.length(), maxWidth, - bidiFlags, measuredWidth); + return native_breakText(nativePaint, nativeTypeface, text.toCharArray(), 0, text.length(), + maxWidth, bidiFlags, measuredWidth); } @LayoutlibDelegate @@ -950,8 +951,25 @@ public class Paint_Delegate { @LayoutlibDelegate /*package*/ static int native_getTextWidths(long native_object, long native_typeface, char[] text, int index, int count, int bidiFlags, float[] widths) { - return (int) native_getTextRunAdvances(native_object, native_typeface, text, index, count, - index, count, bidiFlags, widths, 0); + + if (widths != null) { + for (int i = 0; i< count; i++) { + widths[i]=0; + } + } + // get the delegate from the native int. + Paint_Delegate delegate = sManager.getDelegate(native_object); + if (delegate == null) { + return 0; + } + + // native_typeface is passed here since Framework's old implementation did not have the + // typeface object associated with the Paint. Since, we follow the new framework way, + // we store the typeface with the paint and use it directly. + assert (native_typeface == delegate.mNativeTypeface); + + RectF bounds = delegate.measureText(text, index, count, widths, 0, bidiFlags); + return ((int) (bounds.right - bounds.left)); } @LayoutlibDelegate @@ -971,7 +989,7 @@ public class Paint_Delegate { @LayoutlibDelegate /*package*/ static float native_getTextRunAdvances(long native_object, long native_typeface, char[] text, int index, int count, int contextIndex, int contextCount, - int flags, float[] advances, int advancesIndex) { + boolean isRtl, float[] advances, int advancesIndex) { if (advances != null) for (int i = advancesIndex; i< advancesIndex+count; i++) @@ -987,25 +1005,21 @@ public class Paint_Delegate { // we store the typeface with the paint and use it directly. assert (native_typeface == delegate.mNativeTypeface); - boolean isRtl = isRtl(flags); - - int limit = index + count; - RectF bounds = new BidiRenderer(null, delegate, text).renderText( - index, limit, isRtl, advances, advancesIndex, false, 0, 0); + RectF bounds = delegate.measureText(text, index, count, advances, advancesIndex, isRtl); return bounds.right - bounds.left; } @LayoutlibDelegate /*package*/ static float native_getTextRunAdvances(long native_object, long native_typeface, String text, int start, int end, int contextStart, int contextEnd, - int flags, float[] advances, int advancesIndex) { + boolean isRtl, float[] advances, int advancesIndex) { // FIXME: support contextStart and contextEnd int count = end - start; char[] buffer = TemporaryBuffer.obtain(count); TextUtils.getChars(text, start, end, buffer, 0); return native_getTextRunAdvances(native_object, native_typeface, buffer, 0, count, - contextStart, contextEnd - contextStart, flags, advances, advancesIndex); + contextStart, contextEnd - contextStart, isRtl, advances, advancesIndex); } @LayoutlibDelegate @@ -1062,7 +1076,7 @@ public class Paint_Delegate { // assert that the typeface passed is actually the one that we had stored. assert (native_typeface == delegate.mNativeTypeface); - delegate.measureText(text, index, count, isRtl(bidiFlags)).roundOut(bounds); + delegate.measureText(text, index, count, null, 0, bidiFlags).roundOut(bounds); } @LayoutlibDelegate @@ -1158,9 +1172,16 @@ public class Paint_Delegate { } } - /*package*/ RectF measureText(char[] text, int index, int count, boolean isRtl) { - return new BidiRenderer(null, this, text).renderText( - index, index + count, isRtl, null, 0, false, 0, 0); + /*package*/ RectF measureText(char[] text, int index, int count, float[] advances, + int advancesIndex, int bidiFlags) { + return new BidiRenderer(null, this, text) + .renderText(index, index + count, bidiFlags, advances, advancesIndex, false); + } + + /*package*/ RectF measureText(char[] text, int index, int count, float[] advances, + int advancesIndex, boolean isRtl) { + return new BidiRenderer(null, this, text) + .renderText(index, index + count, isRtl, advances, advancesIndex, false); } private float getFontMetrics(FontMetrics metrics) { @@ -1198,15 +1219,4 @@ public class Paint_Delegate { delegate.mFlags &= ~flagMask; } } - - private static boolean isRtl(int flag) { - switch(flag) { - case Paint.BIDI_RTL: - case Paint.BIDI_FORCE_RTL: - case Paint.BIDI_DEFAULT_RTL: - return true; - default: - return false; - } - } } diff --git a/tools/layoutlib/bridge/src/android/text/AndroidBidi_Delegate.java b/tools/layoutlib/bridge/src/android/text/AndroidBidi_Delegate.java index 973fa0e..6247dae 100644 --- a/tools/layoutlib/bridge/src/android/text/AndroidBidi_Delegate.java +++ b/tools/layoutlib/bridge/src/android/text/AndroidBidi_Delegate.java @@ -37,14 +37,17 @@ public class AndroidBidi_Delegate { switch (dir) { case 0: // Layout.DIR_REQUEST_LTR + dir = Bidi.LTR; + break; case 1: // Layout.DIR_REQUEST_RTL - break; // No change. - case -1: - dir = Bidi.LEVEL_DEFAULT_LTR; + dir = Bidi.RTL; break; - case -2: + case -1: // Layout.DIR_REQUEST_DEFAULT_RTL dir = Bidi.LEVEL_DEFAULT_RTL; break; + case -2: // Layout.DIR_REQUEST_DEFAULT_LTR + dir = Bidi.LEVEL_DEFAULT_LTR; + break; default: // Invalid code. Log error, assume LEVEL_DEFAULT_LTR and continue. Bridge.getLog().error(LayoutLog.TAG_BROKEN, "Invalid direction flag", null); |