diff options
author | Xavier Ducrohet <xav@android.com> | 2010-11-01 16:17:18 -0700 |
---|---|---|
committer | Xavier Ducrohet <xav@android.com> | 2010-11-01 17:52:42 -0700 |
commit | 5802deabf06a0754c36e990ce2af7b5c8727e543 (patch) | |
tree | 1d824bd2fda259b9eaed46aab4742bc9e82359ba | |
parent | 1d8479fa95d61d5e49a8b054f5a8aad62432af1e (diff) | |
download | frameworks_base-5802deabf06a0754c36e990ce2af7b5c8727e543.zip frameworks_base-5802deabf06a0754c36e990ce2af7b5c8727e543.tar.gz frameworks_base-5802deabf06a0754c36e990ce2af7b5c8727e543.tar.bz2 |
More implementation of the layoutlib Paint/Canvas delegates.
Change-Id: I0c0029b9a679af4ae0178488f70b2a90292ea42d
3 files changed, 720 insertions, 127 deletions
diff --git a/tools/layoutlib/bridge/src/android/graphics/Canvas_Delegate.java b/tools/layoutlib/bridge/src/android/graphics/Canvas_Delegate.java index 6627d37..2b54711 100644 --- a/tools/layoutlib/bridge/src/android/graphics/Canvas_Delegate.java +++ b/tools/layoutlib/bridge/src/android/graphics/Canvas_Delegate.java @@ -19,10 +19,22 @@ package android.graphics; import com.android.layoutlib.api.ILayoutLog; import com.android.layoutlib.bridge.DelegateManager; +import android.graphics.Paint_Delegate.FontInfo; +import android.text.TextUtils; + +import java.awt.AlphaComposite; +import java.awt.BasicStroke; +import java.awt.Color; +import java.awt.Composite; import java.awt.Graphics2D; +import java.awt.Rectangle; +import java.awt.RenderingHints; +import java.awt.geom.AffineTransform; import java.awt.image.BufferedImage; +import java.util.List; import java.util.Stack; + /** * Delegate implementing the native methods of android.graphics.Canvas * @@ -95,80 +107,177 @@ public class Canvas_Delegate { } /*package*/ static int getWidth(Canvas thisCanvas) { - // FIXME - throw new UnsupportedOperationException(); + // get the delegate from the native int. + Canvas_Delegate canvasDelegate = sManager.getDelegate(thisCanvas.mNativeCanvas); + if (canvasDelegate == null) { + assert false; + return 0; + } + + return canvasDelegate.mBufferedImage.getWidth(); } /*package*/ static int getHeight(Canvas thisCanvas) { - // FIXME - throw new UnsupportedOperationException(); + // get the delegate from the native int. + Canvas_Delegate canvasDelegate = sManager.getDelegate(thisCanvas.mNativeCanvas); + if (canvasDelegate == null) { + assert false; + return 0; + } + + return canvasDelegate.mBufferedImage.getHeight(); } /*package*/ static void translate(Canvas thisCanvas, float dx, float dy) { - // FIXME - throw new UnsupportedOperationException(); + // get the delegate from the native int. + Canvas_Delegate canvasDelegate = sManager.getDelegate(thisCanvas.mNativeCanvas); + if (canvasDelegate == null) { + assert false; + return; + } + + canvasDelegate.getGraphics2d().translate(dx, dy); } /*package*/ static void rotate(Canvas thisCanvas, float degrees) { - // FIXME - throw new UnsupportedOperationException(); + // get the delegate from the native int. + Canvas_Delegate canvasDelegate = sManager.getDelegate(thisCanvas.mNativeCanvas); + if (canvasDelegate == null) { + assert false; + return; + } + + canvasDelegate.getGraphics2d().rotate(Math.toRadians(degrees)); } /*package*/ static void scale(Canvas thisCanvas, float sx, float sy) { - // FIXME - throw new UnsupportedOperationException(); + // get the delegate from the native int. + Canvas_Delegate canvasDelegate = sManager.getDelegate(thisCanvas.mNativeCanvas); + if (canvasDelegate == null) { + assert false; + return; + } + + canvasDelegate.getGraphics2d().scale(sx, sy); } - /*package*/ static void skew(Canvas thisCanvas, float sx, float sy) { - // FIXME - throw new UnsupportedOperationException(); + /*package*/ static void skew(Canvas thisCanvas, float kx, float ky) { + // get the delegate from the native int. + Canvas_Delegate canvasDelegate = sManager.getDelegate(thisCanvas.mNativeCanvas); + if (canvasDelegate == null) { + assert false; + return; + } + + // get the current top graphics2D object. + Graphics2D g = canvasDelegate.getGraphics2d(); + + // get its current matrix + AffineTransform currentTx = g.getTransform(); + // get the AffineTransform for the given skew. + float[] mtx = Matrix_Delegate.getSkew(kx, ky); + AffineTransform matrixTx = Matrix_Delegate.getAffineTransform(mtx); + + // combine them so that the given matrix is applied after. + currentTx.preConcatenate(matrixTx); + + // give it to the graphics2D as a new matrix replacing all previous transform + g.setTransform(currentTx); } /*package*/ static boolean clipRect(Canvas thisCanvas, RectF rect) { - // FIXME - throw new UnsupportedOperationException(); + return clipRect(thisCanvas, rect.left, rect.top, rect.right, rect.bottom); } /*package*/ static boolean clipRect(Canvas thisCanvas, Rect rect) { - // FIXME - throw new UnsupportedOperationException(); + return clipRect(thisCanvas, rect.left, rect.top, rect.right, rect.bottom); } /*package*/ static boolean clipRect(Canvas thisCanvas, float left, float top, float right, float bottom) { - // FIXME - throw new UnsupportedOperationException(); + // get the delegate from the native int. + Canvas_Delegate canvasDelegate = sManager.getDelegate(thisCanvas.mNativeCanvas); + if (canvasDelegate == null) { + assert false; + return false; + } + + canvasDelegate.getGraphics2d().clipRect((int)left, (int)top, (int)(right-left), + (int)(bottom-top)); + return true; } /*package*/ static boolean clipRect(Canvas thisCanvas, int left, int top, int right, int bottom) { - // FIXME - throw new UnsupportedOperationException(); + // get the delegate from the native int. + Canvas_Delegate canvasDelegate = sManager.getDelegate(thisCanvas.mNativeCanvas); + if (canvasDelegate == null) { + assert false; + return false; + } + + canvasDelegate.getGraphics2d().clipRect(left, top, right - left, bottom - top); + return true; } /*package*/ static int save(Canvas thisCanvas) { - // FIXME - throw new UnsupportedOperationException(); + // get the delegate from the native int. + Canvas_Delegate canvasDelegate = sManager.getDelegate(thisCanvas.mNativeCanvas); + if (canvasDelegate == null) { + assert false; + return 0; + } + + // get the current save count + int count = canvasDelegate.mGraphicsStack.size(); + + // create a new graphics and add it to the stack + Graphics2D g = (Graphics2D)canvasDelegate.getGraphics2d().create(); + canvasDelegate.mGraphicsStack.push(g); + + // return the old save count + return count; + } /*package*/ static int save(Canvas thisCanvas, int saveFlags) { - // FIXME - throw new UnsupportedOperationException(); + // FIXME implement save(flags) + return save(thisCanvas); } /*package*/ static void restore(Canvas thisCanvas) { - // FIXME - throw new UnsupportedOperationException(); + // get the delegate from the native int. + Canvas_Delegate canvasDelegate = sManager.getDelegate(thisCanvas.mNativeCanvas); + if (canvasDelegate == null) { + assert false; + return; + } + + canvasDelegate.mGraphicsStack.pop(); } /*package*/ static int getSaveCount(Canvas thisCanvas) { - // FIXME - throw new UnsupportedOperationException(); + // get the delegate from the native int. + Canvas_Delegate canvasDelegate = sManager.getDelegate(thisCanvas.mNativeCanvas); + if (canvasDelegate == null) { + assert false; + return 0; + } + + return canvasDelegate.mGraphicsStack.size(); } /*package*/ static void restoreToCount(Canvas thisCanvas, int saveCount) { - // FIXME - throw new UnsupportedOperationException(); + // get the delegate from the native int. + Canvas_Delegate canvasDelegate = sManager.getDelegate(thisCanvas.mNativeCanvas); + if (canvasDelegate == null) { + assert false; + return; + } + + while (canvasDelegate.mGraphicsStack.size() > saveCount) { + canvasDelegate.mGraphicsStack.pop(); + } } /*package*/ static void drawPoints(Canvas thisCanvas, float[] pts, int offset, int count, @@ -296,8 +405,22 @@ public class Canvas_Delegate { /*package*/ static boolean native_getClipBounds(int nativeCanvas, Rect bounds) { - // FIXME - throw new UnsupportedOperationException(); + // get the delegate from the native int. + Canvas_Delegate canvasDelegate = sManager.getDelegate(nativeCanvas); + if (canvasDelegate == null) { + assert false; + return false; + } + + Rectangle rect = canvasDelegate.getGraphics2d().getClipBounds(); + if (rect != null) { + bounds.left = rect.x; + bounds.top = rect.y; + bounds.right = rect.x + rect.width; + bounds.bottom = rect.y + rect.height; + return true; + } + return false; } /*package*/ static void native_getCTM(int canvas, int matrix) { @@ -309,14 +432,14 @@ public class Canvas_Delegate { RectF rect, int native_edgeType) { // FIXME - throw new UnsupportedOperationException(); + return false; } /*package*/ static boolean native_quickReject(int nativeCanvas, int path, int native_edgeType) { // FIXME - throw new UnsupportedOperationException(); + return false; } /*package*/ static boolean native_quickReject(int nativeCanvas, @@ -324,7 +447,7 @@ public class Canvas_Delegate { float right, float bottom, int native_edgeType) { // FIXME - throw new UnsupportedOperationException(); + return false; } /*package*/ static void native_drawRGB(int nativeCanvas, int r, int g, @@ -371,8 +494,41 @@ public class Canvas_Delegate { /*package*/ static void native_drawRect(int nativeCanvas, float left, float top, float right, float bottom, int paint) { - // FIXME - throw new UnsupportedOperationException(); + // get the delegate from the native int. + Canvas_Delegate canvasDelegate = sManager.getDelegate(nativeCanvas); + if (canvasDelegate == null) { + assert false; + return; + } + + // get the delegate from the native int. + Paint_Delegate paintDelegate = Paint_Delegate.getDelegate(paint); + if (paintDelegate == null) { + assert false; + return; + } + + if (right > left && bottom > top) { + // get a Graphics2D object configured with the drawing parameters. + Graphics2D g = canvasDelegate.getCustomGraphics(paintDelegate); + + int style = paintDelegate.getStyle(); + + // draw + if (style == Paint.Style.FILL.nativeInt || + style == Paint.Style.FILL_AND_STROKE.nativeInt) { + g.fillRect((int)left, (int)top, (int)(right-left), (int)(bottom-top)); + } + + if (style == Paint.Style.STROKE.nativeInt || + style == Paint.Style.FILL_AND_STROKE.nativeInt) { + g.drawRect((int)left, (int)top, (int)(right-left), (int)(bottom-top)); + } + + // dispose Graphics2D object + g.dispose(); + } + } /*package*/ static void native_drawOval(int nativeCanvas, RectF oval, @@ -423,8 +579,24 @@ public class Canvas_Delegate { int nativePaintOrZero, int screenDensity, int bitmapDensity) { - // FIXME - throw new UnsupportedOperationException(); + // get the delegate from the native int. + Bitmap_Delegate bitmapDelegate = Bitmap_Delegate.getDelegate(bitmap); + if (bitmapDelegate == null) { + assert false; + return; + } + + BufferedImage image = bitmapDelegate.getImage(); + + if (src == null) { + drawBitmap(nativeCanvas, image, nativePaintOrZero, + 0, 0, image.getWidth(), image.getHeight(), + (int)dst.left, (int)dst.top, (int)dst.right, (int)dst.bottom); + } else { + drawBitmap(nativeCanvas, image, nativePaintOrZero, + src.left, src.top, src.width(), src.height(), + (int)dst.left, (int)dst.top, (int)dst.right, (int)dst.bottom); + } } /*package*/ static void native_drawBitmap(int nativeCanvas, int bitmap, @@ -432,8 +604,24 @@ public class Canvas_Delegate { int nativePaintOrZero, int screenDensity, int bitmapDensity) { - // FIXME - throw new UnsupportedOperationException(); + // get the delegate from the native int. + Bitmap_Delegate bitmapDelegate = Bitmap_Delegate.getDelegate(bitmap); + if (bitmapDelegate == null) { + assert false; + return; + } + + BufferedImage image = bitmapDelegate.getImage(); + + if (src == null) { + drawBitmap(nativeCanvas, image, nativePaintOrZero, + 0, 0, image.getWidth(), image.getHeight(), + dst.left, dst.top, dst.right, dst.bottom); + } else { + drawBitmap(nativeCanvas, image, nativePaintOrZero, + src.left, src.top, src.width(), src.height(), + dst.left, dst.top, dst.right, dst.bottom); + } } /*package*/ static void native_drawBitmap(int nativeCanvas, int[] colors, @@ -471,15 +659,134 @@ public class Canvas_Delegate { /*package*/ static void native_drawText(int nativeCanvas, char[] text, int index, int count, float x, float y, int flags, int paint) { - // FIXME - throw new UnsupportedOperationException(); + // WARNING: the logic in this method is similar to Paint.measureText. + // Any change to this method should be reflected in Paint.measureText + + // get the delegate from the native int. + Canvas_Delegate canvasDelegate = sManager.getDelegate(nativeCanvas); + if (canvasDelegate == null) { + assert false; + return; + } + + // get the delegate from the native int. + Paint_Delegate paintDelegate = Paint_Delegate.getDelegate(paint); + if (paintDelegate == null) { + assert false; + return; + } + + Graphics2D g = canvasDelegate.getGraphics2d(); + + g = (Graphics2D)g.create(); + g.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON); + + // set the color. because this only handles RGB, the alpha channel is handled + // as a composite. + g.setColor(new Color(paintDelegate.getColor())); + int alpha = paintDelegate.getAlpha(); + float falpha = alpha / 255.f; + g.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER, falpha)); + + + // Paint.TextAlign indicates how the text is positioned relative to X. + // LEFT is the default and there's nothing to do. + if (paintDelegate.getTextAlign() != Paint.Align.LEFT.nativeInt) { + float m = paintDelegate.measureText(text, index, count); + if (paintDelegate.getTextAlign() == Paint.Align.CENTER.nativeInt) { + x -= m / 2; + } else if (paintDelegate.getTextAlign() == Paint.Align.RIGHT.nativeInt) { + x -= m; + } + } + + List<FontInfo> fonts = paintDelegate.getFonts(); + try { + if (fonts.size() > 0) { + FontInfo mainFont = fonts.get(0); + int i = index; + int lastIndex = index + count; + while (i < lastIndex) { + // always start with the main font. + int upTo = mainFont.mFont.canDisplayUpTo(text, i, lastIndex); + if (upTo == -1) { + // draw all the rest and exit. + g.setFont(mainFont.mFont); + g.drawChars(text, i, lastIndex - i, (int)x, (int)y); + return; + } else if (upTo > 0) { + // draw what's possible + g.setFont(mainFont.mFont); + g.drawChars(text, i, upTo - i, (int)x, (int)y); + + // compute the width that was drawn to increase x + x += mainFont.mMetrics.charsWidth(text, i, upTo - i); + + // move index to the first non displayed char. + i = upTo; + + // don't call continue at this point. Since it is certain the main font + // cannot display the font a index upTo (now ==i), we move on to the + // fallback fonts directly. + } + + // no char supported, attempt to read the next char(s) with the + // fallback font. In this case we only test the first character + // and then go back to test with the main font. + // Special test for 2-char characters. + boolean foundFont = false; + for (int f = 1 ; f < fonts.size() ; f++) { + FontInfo fontInfo = fonts.get(f); + + // need to check that the font can display the character. We test + // differently if the char is a high surrogate. + int charCount = Character.isHighSurrogate(text[i]) ? 2 : 1; + upTo = fontInfo.mFont.canDisplayUpTo(text, i, i + charCount); + if (upTo == -1) { + // draw that char + g.setFont(fontInfo.mFont); + g.drawChars(text, i, charCount, (int)x, (int)y); + + // update x + x += fontInfo.mMetrics.charsWidth(text, i, charCount); + + // update the index in the text, and move on + i += charCount; + foundFont = true; + break; + + } + } + + // in case no font can display the char, display it with the main font. + // (it'll put a square probably) + if (foundFont == false) { + int charCount = Character.isHighSurrogate(text[i]) ? 2 : 1; + + g.setFont(mainFont.mFont); + g.drawChars(text, i, charCount, (int)x, (int)y); + + // measure it to advance x + x += mainFont.mMetrics.charsWidth(text, i, charCount); + + // and move to the next chars. + i += charCount; + } + } + } + } finally { + g.dispose(); + } } /*package*/ static void native_drawText(int nativeCanvas, String text, int start, int end, float x, float y, int flags, int paint) { - // FIXME - throw new UnsupportedOperationException(); + 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); } @@ -556,4 +863,141 @@ public class Canvas_Delegate { mBufferedImage = image; mGraphicsStack.push(mBufferedImage.createGraphics()); } + + /** + * Creates a new {@link Graphics2D} based on the {@link Paint} parameters. + * <p/>The object must be disposed ({@link Graphics2D#dispose()}) after being used. + */ + private Graphics2D getCustomGraphics(Paint_Delegate paint) { + // make new one + Graphics2D g = getGraphics2d(); + g = (Graphics2D)g.create(); + + // configure it + g.setColor(new Color(paint.getColor())); + int alpha = paint.getAlpha(); + float falpha = alpha / 255.f; + + int style = paint.getStyle(); + if (style == Paint.Style.STROKE.nativeInt || + style == Paint.Style.FILL_AND_STROKE.nativeInt) { + /* FIXME + PathEffect e = paint.getPathEffect(); + if (e instanceof DashPathEffect) { + DashPathEffect dpe = (DashPathEffect)e; + g.setStroke(new BasicStroke( + paint.getStrokeWidth(), + paint.getStrokeCap().getJavaCap(), + paint.getStrokeJoin().getJavaJoin(), + paint.getStrokeMiter(), + dpe.getIntervals(), + dpe.getPhase())); + } else {*/ + g.setStroke(new BasicStroke( + paint.getStrokeWidth(), + paint.getJavaCap(), + paint.getJavaJoin(), + paint.getStrokeMiter())); + /* }*/ + } +/* + Xfermode xfermode = paint.getXfermode(); + if (xfermode instanceof PorterDuffXfermode) { + PorterDuff.Mode mode = ((PorterDuffXfermode)xfermode).getMode(); + + setModeInGraphics(mode, g, falpha); + } else { + if (mLogger != null && xfermode != null) { + mLogger.warning(String.format( + "Xfermode '%1$s' is not supported in the Layout Editor.", + xfermode.getClass().getCanonicalName())); + } + g.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER, falpha)); + } + + Shader shader = paint.getShader(); + if (shader != null) { + java.awt.Paint shaderPaint = shader.getJavaPaint(); + if (shaderPaint != null) { + g.setPaint(shaderPaint); + } else { + if (mLogger != null) { + mLogger.warning(String.format( + "Shader '%1$s' is not supported in the Layout Editor.", + shader.getClass().getCanonicalName())); + } + } + } +*/ + return g; + } + + + private static void drawBitmap( + int nativeCanvas, + BufferedImage image, + int nativePaintOrZero, + int sleft, int stop, int sright, int sbottom, + int dleft, int dtop, int dright, int dbottom) { + // get the delegate from the native int. + Canvas_Delegate canvasDelegate = sManager.getDelegate(nativeCanvas); + if (canvasDelegate == null) { + assert false; + return; + } + + // get the delegate from the native int. + Paint_Delegate paintDelegate = null; + if (nativePaintOrZero > 0) { + paintDelegate = Paint_Delegate.getDelegate(nativePaintOrZero); + if (paintDelegate == null) { + assert false; + return; + } + } + + drawBitmap(canvasDelegate, image, paintDelegate, + sleft, stop, sright, sbottom, + dleft, dtop, dright, dbottom); + } + + private static void drawBitmap( + Canvas_Delegate canvasDelegate, + BufferedImage image, + Paint_Delegate paintDelegate, + int sleft, int stop, int sright, int sbottom, + int dleft, int dtop, int dright, int dbottom) { + + Graphics2D g = canvasDelegate.getGraphics2d(); + + Composite c = null; + + if (paintDelegate != null) { + if (paintDelegate.isFilterBitmap()) { + g = (Graphics2D)g.create(); + g.setRenderingHint(RenderingHints.KEY_INTERPOLATION, + RenderingHints.VALUE_INTERPOLATION_BILINEAR); + } + + if (paintDelegate.getAlpha() != 0xFF) { + c = g.getComposite(); + g.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER, + paintDelegate.getAlpha()/255.f)); + } + } + + g.drawImage(image, dleft, dtop, dright, dbottom, + sleft, stop, sright, sbottom, null); + + if (paintDelegate != null) { + if (paintDelegate.isFilterBitmap()) { + g.dispose(); + } + if (c != null) { + g.setComposite(c); + } + } + } + } + diff --git a/tools/layoutlib/bridge/src/android/graphics/Matrix_Delegate.java b/tools/layoutlib/bridge/src/android/graphics/Matrix_Delegate.java index cc4a80c..713f784 100644 --- a/tools/layoutlib/bridge/src/android/graphics/Matrix_Delegate.java +++ b/tools/layoutlib/bridge/src/android/graphics/Matrix_Delegate.java @@ -689,13 +689,17 @@ public final class Matrix_Delegate { // ---- Private helper methods ---- private static AffineTransform getAffineTransform(Matrix_Delegate d) { + return getAffineTransform(d.mValues); + } + + /*package*/ static AffineTransform getAffineTransform(float[] matrix) { // the AffineTransform constructor takes the value in a different order // for a matrix [ 0 1 2 ] // [ 3 4 5 ] // the order is 0, 3, 1, 4, 2, 5... return new AffineTransform( - d.mValues[0], d.mValues[3], d.mValues[1], - d.mValues[4], d.mValues[2], d.mValues[5]); + matrix[0], matrix[3], matrix[1], + matrix[4], matrix[2], matrix[5]); } @@ -862,7 +866,7 @@ public final class Matrix_Delegate { * <p/>This in effect does dest = a*b * dest cannot be the same as a or b. */ - private static void multiply(float dest[], float[] a, float[] b) { + /*package*/ static void multiply(float dest[], float[] a, float[] b) { // first row dest[0] = b[0] * a[0] + b[1] * a[3] + b[2] * a[6]; dest[1] = b[0] * a[1] + b[1] * a[4] + b[2] * a[7]; @@ -885,11 +889,11 @@ public final class Matrix_Delegate { * @param dy * @return */ - private static float[] getTranslate(float dx, float dy) { + /*package*/ static float[] getTranslate(float dx, float dy) { return setTranslate(new float[9], dx, dy); } - private static float[] setTranslate(float[] dest, float dx, float dy) { + /*package*/ static float[] setTranslate(float[] dest, float dx, float dy) { dest[0] = 1; dest[1] = 0; dest[2] = dx; @@ -902,7 +906,7 @@ public final class Matrix_Delegate { return dest; } - private static float[] getScale(float sx, float sy) { + /*package*/ static float[] getScale(float sx, float sy) { return new float[] { sx, 0, 0, 0, sy, 0, 0, 0, 1 }; } @@ -913,7 +917,7 @@ public final class Matrix_Delegate { * @param px * @param py */ - private static float[] getScale(float sx, float sy, float px, float py) { + /*package*/ static float[] getScale(float sx, float sy, float px, float py) { float[] tmp = new float[9]; float[] tmp2 = new float[9]; @@ -932,7 +936,7 @@ public final class Matrix_Delegate { } - private static float[] getRotate(float degrees) { + /*package*/ static float[] getRotate(float degrees) { double rad = Math.toRadians(degrees); float sin = (float)Math.sin(rad); float cos = (float)Math.cos(rad); @@ -940,11 +944,11 @@ public final class Matrix_Delegate { return getRotate(sin, cos); } - private static float[] getRotate(float sin, float cos) { + /*package*/ static float[] getRotate(float sin, float cos) { return setRotate(new float[9], sin, cos); } - private static float[] setRotate(float[] dest, float degrees) { + /*package*/ static float[] setRotate(float[] dest, float degrees) { double rad = Math.toRadians(degrees); float sin = (float)Math.sin(rad); float cos = (float)Math.cos(rad); @@ -952,7 +956,7 @@ public final class Matrix_Delegate { return setRotate(dest, sin, cos); } - private static float[] setRotate(float[] dest, float sin, float cos) { + /*package*/ static float[] setRotate(float[] dest, float sin, float cos) { dest[0] = cos; dest[1] = -sin; dest[2] = 0; @@ -965,7 +969,7 @@ public final class Matrix_Delegate { return dest; } - private static float[] getRotate(float degrees, float px, float py) { + /*package*/ static float[] getRotate(float degrees, float px, float py) { float[] tmp = new float[9]; float[] tmp2 = new float[9]; @@ -986,11 +990,11 @@ public final class Matrix_Delegate { return tmp; } - private static float[] getSkew(float kx, float ky) { + /*package*/ static float[] getSkew(float kx, float ky) { return new float[] { 1, kx, 0, ky, 1, 0, 0, 0, 1 }; } - private static float[] getSkew(float kx, float ky, float px, float py) { + /*package*/ static float[] getSkew(float kx, float ky, float px, float py) { float[] tmp = new float[9]; float[] tmp2 = new float[9]; diff --git a/tools/layoutlib/bridge/src/android/graphics/Paint_Delegate.java b/tools/layoutlib/bridge/src/android/graphics/Paint_Delegate.java index e8079ed..f2602b5 100644 --- a/tools/layoutlib/bridge/src/android/graphics/Paint_Delegate.java +++ b/tools/layoutlib/bridge/src/android/graphics/Paint_Delegate.java @@ -20,7 +20,9 @@ import com.android.layoutlib.bridge.DelegateManager; import android.graphics.Paint.FontMetrics; import android.graphics.Paint.FontMetricsInt; +import android.text.TextUtils; +import java.awt.BasicStroke; import java.awt.Font; import java.awt.Toolkit; import java.awt.font.FontRenderContext; @@ -47,7 +49,7 @@ public class Paint_Delegate { /** * Class associating a {@link Font} and it's {@link java.awt.FontMetrics}. */ - public static final class FontInfo { + /*package*/ static final class FontInfo { Font mFont; java.awt.FontMetrics mMetrics; } @@ -67,7 +69,7 @@ public class Paint_Delegate { private int mStyle; private int mCap; private int mJoin; - private int mAlign; + private int mTextAlign; private int mTypeface; private float mStrokeWidth; private float mStrokeMiter; @@ -78,6 +80,10 @@ public class Paint_Delegate { // ---- Public Helper methods ---- + public static Paint_Delegate getDelegate(int native_paint) { + return sManager.getDelegate(native_paint); + } + /** * Returns the list of {@link Font} objects. The first item is the main font, the rest * are fall backs for characters not present in the main font. @@ -86,6 +92,57 @@ public class Paint_Delegate { return mFonts; } + public boolean isFilterBitmap() { + return (mFlags & Paint.FILTER_BITMAP_FLAG) != 0; + } + + public int getStyle() { + return mStyle; + } + + public int getColor() { + return mColor; + } + + public int getAlpha() { + return mColor >>> 24; + } + + public int getTextAlign() { + return mTextAlign; + } + + public float getStrokeWidth() { + return mStrokeWidth; + } + + public float getStrokeMiter() { + return mStrokeMiter; + } + + public int getJavaCap() { + switch (Paint.sCapArray[mCap]) { + case BUTT: + return BasicStroke.CAP_BUTT; + case ROUND: + return BasicStroke.CAP_ROUND; + default: + case SQUARE: + return BasicStroke.CAP_SQUARE; + } + } + + public int getJavaJoin() { + switch (Paint.sJoinArray[mJoin]) { + default: + case MITER: + return BasicStroke.JOIN_MITER; + case ROUND: + return BasicStroke.JOIN_ROUND; + case BEVEL: + return BasicStroke.JOIN_BEVEL; + } + } // ---- native methods ---- @@ -112,8 +169,7 @@ public class Paint_Delegate { } /*package*/ static void setFilterBitmap(Paint thisPaint, boolean filter) { - // FIXME - throw new UnsupportedOperationException(); + setFlag(thisPaint, Paint.FILTER_BITMAP_FLAG, filter); } /*package*/ static void setAntiAlias(Paint thisPaint, boolean aa) { @@ -174,7 +230,7 @@ public class Paint_Delegate { return 0; } - return delegate.mColor >>> 24; + return delegate.getAlpha(); } /*package*/ static void setAlpha(Paint thisPaint, int a) { @@ -315,20 +371,31 @@ public class Paint_Delegate { } /*package*/ static float getFontMetrics(Paint thisPaint, FontMetrics metrics) { - // FIXME - throw new UnsupportedOperationException(); - } + // get the delegate + Paint_Delegate delegate = sManager.getDelegate(thisPaint.mNativePaint); + if (delegate == null) { + assert false; + return 0; + } - /*package*/ static int getFontMetricsInt(Paint thisPaint, FontMetricsInt fmi) { - // FIXME - throw new UnsupportedOperationException(); - } + if (delegate.mFonts.size() > 0) { + java.awt.FontMetrics javaMetrics = delegate.mFonts.get(0).mMetrics; + if (metrics != null) { + // Android expects negative ascent so we invert the value from Java. + metrics.top = - javaMetrics.getMaxAscent(); + metrics.ascent = - javaMetrics.getAscent(); + metrics.descent = javaMetrics.getDescent(); + metrics.bottom = javaMetrics.getMaxDescent(); + metrics.leading = javaMetrics.getLeading(); + } - /*package*/ static float native_measureText(Paint thisPaint, char[] text, int index, - int count) { - // WARNING: the logic in this method is similar to Canvas.drawText. - // Any change to this method should be reflected in Canvas.drawText + return javaMetrics.getHeight(); + } + return 0; + } + + /*package*/ static int getFontMetricsInt(Paint thisPaint, FontMetricsInt fmi) { // get the delegate Paint_Delegate delegate = sManager.getDelegate(thisPaint.mNativePaint); if (delegate == null) { @@ -337,55 +404,35 @@ public class Paint_Delegate { } if (delegate.mFonts.size() > 0) { - FontInfo mainFont = delegate.mFonts.get(0); - int i = index; - int lastIndex = index + count; - float total = 0f; - while (i < lastIndex) { - // always start with the main font. - int upTo = mainFont.mFont.canDisplayUpTo(text, i, lastIndex); - if (upTo == -1) { - // shortcut to exit - return total + mainFont.mMetrics.charsWidth(text, i, lastIndex - i); - } else if (upTo > 0) { - total += mainFont.mMetrics.charsWidth(text, i, upTo - i); - i = upTo; - // don't call continue at this point. Since it is certain the main font - // cannot display the font a index upTo (now ==i), we move on to the - // fallback fonts directly. - } + java.awt.FontMetrics javaMetrics = delegate.mFonts.get(0).mMetrics; + if (fmi != null) { + // Android expects negative ascent so we invert the value from Java. + fmi.top = - javaMetrics.getMaxAscent(); + fmi.ascent = - javaMetrics.getAscent(); + fmi.descent = javaMetrics.getDescent(); + fmi.bottom = javaMetrics.getMaxDescent(); + fmi.leading = javaMetrics.getLeading(); + } - // no char supported, attempt to read the next char(s) with the - // fallback font. In this case we only test the first character - // and then go back to test with the main font. - // Special test for 2-char characters. - boolean foundFont = false; - for (int f = 1 ; f < delegate.mFonts.size() ; f++) { - FontInfo fontInfo = delegate.mFonts.get(f); + return javaMetrics.getHeight(); + } - // need to check that the font can display the character. We test - // differently if the char is a high surrogate. - int charCount = Character.isHighSurrogate(text[i]) ? 2 : 1; - upTo = fontInfo.mFont.canDisplayUpTo(text, i, i + charCount); - if (upTo == -1) { - total += fontInfo.mMetrics.charsWidth(text, i, charCount); - i += charCount; - foundFont = true; - break; + return 0; + } - } - } + /*package*/ static float native_measureText(Paint thisPaint, char[] text, int index, + int count) { + // WARNING: the logic in this method is similar to Canvas.drawText. + // Any change to this method should be reflected in Canvas.drawText - // in case no font can display the char, measure it with the main font. - if (foundFont == false) { - int size = Character.isHighSurrogate(text[i]) ? 2 : 1; - total += mainFont.mMetrics.charsWidth(text, i, size); - i += size; - } - } + // get the delegate + Paint_Delegate delegate = sManager.getDelegate(thisPaint.mNativePaint); + if (delegate == null) { + assert false; + return 0; } - return 0; + return delegate.measureText(text, index, count); } /*package*/ static float native_measureText(Paint thisPaint, String text, int start, int end) { @@ -576,7 +623,7 @@ public class Paint_Delegate { return 0; } - return delegate.mAlign; + return delegate.mTextAlign; } /*package*/ static void native_setTextAlign(int native_object, int align) { @@ -587,7 +634,7 @@ public class Paint_Delegate { return; } - delegate.mAlign = align; + delegate.mTextAlign = align; } /*package*/ static float native_getFontMetrics(int native_paint, FontMetrics metrics) { @@ -610,15 +657,58 @@ public class Paint_Delegate { /*package*/ static float native_getTextRunAdvances(int native_object, char[] text, int index, int count, int contextIndex, int contextCount, int flags, float[] advances, int advancesIndex) { - // FIXME - throw new UnsupportedOperationException(); + // get the delegate from the native int. + Paint_Delegate delegate = sManager.getDelegate(native_object); + if (delegate == null) { + assert false; + return 0.f; + } + + if (delegate.mFonts.size() > 0) { + // FIXME: handle multi-char characters. + // see measureText. + float totalAdvance = 0; + for (int i = 0; i < count; i++) { + char c = text[i + index]; + boolean found = false; + for (FontInfo info : delegate.mFonts) { + if (info.mFont.canDisplay(c)) { + float adv = info.mMetrics.charWidth(c); + totalAdvance += adv; + if (advances != null) { + advances[i] = adv; + } + + found = true; + break; + } + } + + if (found == false) { + // no advance for this char. + if (advances != null) { + advances[i] = 0.f; + } + } + } + + return totalAdvance; + } + + return 0; + } /*package*/ static float native_getTextRunAdvances(int native_object, String text, int start, int end, int contextStart, int contextEnd, int flags, float[] advances, int advancesIndex) { - // FIXME - throw new UnsupportedOperationException(); + // FIXME: support contextStart, contextEnd and direction flag + int count = end - start; + char[] buffer = TemporaryBuffer.obtain(count); + TextUtils.getChars(text, start, end, buffer, 0); + + return native_getTextRunAdvances(native_object, buffer, 0, count, contextStart, + contextEnd - contextStart, flags, advances, advancesIndex); } /*package*/ static int native_getTextRunCursor(Paint thisPaint, int native_object, char[] text, @@ -681,7 +771,7 @@ public class Paint_Delegate { mStyle = paint.mStyle; mCap = paint.mCap; mJoin = paint.mJoin; - mAlign = paint.mAlign; + mTextAlign = paint.mTextAlign; mTypeface = paint.mTypeface; mStrokeWidth = paint.mStrokeWidth; mStrokeMiter = paint.mStrokeMiter; @@ -696,7 +786,7 @@ public class Paint_Delegate { mStyle = 0; mCap = 0; mJoin = 0; - mAlign = 0; + mTextAlign = 0; mTypeface = 0; mStrokeWidth = 1.f; mStrokeMiter = 2.f; @@ -733,6 +823,61 @@ public class Paint_Delegate { } } + /*package*/ float measureText(char[] text, int index, int count) { + if (mFonts.size() > 0) { + FontInfo mainFont = mFonts.get(0); + int i = index; + int lastIndex = index + count; + float total = 0f; + while (i < lastIndex) { + // always start with the main font. + int upTo = mainFont.mFont.canDisplayUpTo(text, i, lastIndex); + if (upTo == -1) { + // shortcut to exit + return total + mainFont.mMetrics.charsWidth(text, i, lastIndex - i); + } else if (upTo > 0) { + total += mainFont.mMetrics.charsWidth(text, i, upTo - i); + i = upTo; + // don't call continue at this point. Since it is certain the main font + // cannot display the font a index upTo (now ==i), we move on to the + // fallback fonts directly. + } + + // no char supported, attempt to read the next char(s) with the + // fallback font. In this case we only test the first character + // and then go back to test with the main font. + // Special test for 2-char characters. + boolean foundFont = false; + for (int f = 1 ; f < mFonts.size() ; f++) { + FontInfo fontInfo = mFonts.get(f); + + // need to check that the font can display the character. We test + // differently if the char is a high surrogate. + int charCount = Character.isHighSurrogate(text[i]) ? 2 : 1; + upTo = fontInfo.mFont.canDisplayUpTo(text, i, i + charCount); + if (upTo == -1) { + total += fontInfo.mMetrics.charsWidth(text, i, charCount); + i += charCount; + foundFont = true; + break; + + } + } + + // in case no font can display the char, measure it with the main font. + if (foundFont == false) { + int size = Character.isHighSurrogate(text[i]) ? 2 : 1; + total += mainFont.mMetrics.charsWidth(text, i, size); + i += size; + } + } + } + + return 0; + + } + + private static void setFlag(Paint thisPaint, int flagMask, boolean flagValue) { // get the delegate from the native int. Paint_Delegate delegate = sManager.getDelegate(thisPaint.mNativePaint); |