diff options
31 files changed, 1926 insertions, 816 deletions
diff --git a/tests/HwAccelerationTest/res/layout/advanced_blend.xml b/tests/HwAccelerationTest/res/layout/_advanced_blend.xml index 6efdd7345b69..6efdd7345b69 100644 --- a/tests/HwAccelerationTest/res/layout/advanced_blend.xml +++ b/tests/HwAccelerationTest/res/layout/_advanced_blend.xml diff --git a/tests/HwAccelerationTest/res/layout/advanced_gradient.xml b/tests/HwAccelerationTest/res/layout/_advanced_gradient.xml index dd937f9b5676..dd937f9b5676 100644 --- a/tests/HwAccelerationTest/res/layout/advanced_gradient.xml +++ b/tests/HwAccelerationTest/res/layout/_advanced_gradient.xml diff --git a/tests/HwAccelerationTest/res/layout/_paths.xml b/tests/HwAccelerationTest/res/layout/_paths.xml new file mode 100644 index 000000000000..b0534826d565 --- /dev/null +++ b/tests/HwAccelerationTest/res/layout/_paths.xml @@ -0,0 +1,6 @@ +<?xml version="1.0" encoding="utf-8"?> +<com.android.test.hwui.PathsActivity.PathsView + xmlns:android="http://schemas.android.com/apk/res/android" + android:layout_width="fill_parent" + android:layout_height="fill_parent"> +</com.android.test.hwui.PathsActivity.PathsView> diff --git a/tests/HwAccelerationTest/res/layout/_shaders.xml b/tests/HwAccelerationTest/res/layout/_shaders.xml new file mode 100644 index 000000000000..dcb42fba929a --- /dev/null +++ b/tests/HwAccelerationTest/res/layout/_shaders.xml @@ -0,0 +1,6 @@ +<?xml version="1.0" encoding="utf-8"?> +<com.android.test.hwui.ShadersActivity.ShadersView + xmlns:android="http://schemas.android.com/apk/res/android" + android:layout_width="fill_parent" + android:layout_height="fill_parent"> +</com.android.test.hwui.ShadersActivity.ShadersView> diff --git a/tests/HwAccelerationTest/src/com/android/test/hwui/PathsActivity.java b/tests/HwAccelerationTest/src/com/android/test/hwui/PathsActivity.java index 8d9bf3796248..aa1eb5955585 100644 --- a/tests/HwAccelerationTest/src/com/android/test/hwui/PathsActivity.java +++ b/tests/HwAccelerationTest/src/com/android/test/hwui/PathsActivity.java @@ -37,7 +37,7 @@ public class PathsActivity extends Activity { setContentView(view); } - static class PathsView extends View { + public static class PathsView extends View { private final Bitmap mBitmap1; private final Paint mSmallPaint; private final Paint mMediumPaint; @@ -50,7 +50,7 @@ public class PathsActivity extends Activity { private final float mOffset; private final Paint mLinePaint; - PathsView(Context c) { + public PathsView(Context c) { super(c); mBitmap1 = BitmapFactory.decodeResource(c.getResources(), R.drawable.sunset1); @@ -60,7 +60,7 @@ public class PathsActivity extends Activity { mSmallPaint.setColor(0xffff0000); mSmallPaint.setStrokeWidth(1.0f); mSmallPaint.setStyle(Paint.Style.STROKE); - + mLinePaint = new Paint(); mLinePaint.setAntiAlias(true); mLinePaint.setColor(0xffff00ff); @@ -112,7 +112,7 @@ public class PathsActivity extends Activity { canvas.save(); canvas.translate(200.0f, 60.0f); canvas.drawPath(mPath, mSmallPaint); - + canvas.translate(350.0f, 0.0f); canvas.drawPath(mPath, mMediumPaint); @@ -121,12 +121,12 @@ public class PathsActivity extends Activity { canvas.drawPath(mPath, mLargePaint); mLargePaint.setShader(null); canvas.restore(); - + canvas.save(); canvas.translate(200.0f, 360.0f); canvas.drawPath(mPath, mSmallPaint); canvas.drawRect(mPathBounds, mBoundsPaint); - + canvas.translate(350.0f, 0.0f); canvas.drawBitmap(mBitmap, mPathBounds.left - mOffset * 1.5f, mPathBounds.top - mOffset * 1.5f, null); diff --git a/tests/HwAccelerationTest/src/com/android/test/hwui/ShadersActivity.java b/tests/HwAccelerationTest/src/com/android/test/hwui/ShadersActivity.java index 02eaa7cf698c..f89e1841cf86 100644 --- a/tests/HwAccelerationTest/src/com/android/test/hwui/ShadersActivity.java +++ b/tests/HwAccelerationTest/src/com/android/test/hwui/ShadersActivity.java @@ -39,7 +39,7 @@ public class ShadersActivity extends Activity { setContentView(new ShadersView(this)); } - static class ShadersView extends View { + public static class ShadersView extends View { private BitmapShader mRepeatShader; private BitmapShader mTranslatedShader; private BitmapShader mScaledShader; @@ -53,7 +53,7 @@ public class ShadersActivity extends Activity { private LinearGradient mVertGradient; private Bitmap mTexture; - ShadersView(Context c) { + public ShadersView(Context c) { super(c); mTexture = BitmapFactory.decodeResource(c.getResources(), R.drawable.sunset1); @@ -71,7 +71,7 @@ public class ShadersActivity extends Activity { m1.setTranslate(mTexWidth / 2.0f, mTexHeight / 2.0f); m1.postRotate(45, 0, 0); mTranslatedShader.setLocalMatrix(m1); - + mScaledShader = new BitmapShader(mTexture, Shader.TileMode.MIRROR, Shader.TileMode.MIRROR); Matrix m2 = new Matrix(); @@ -85,10 +85,10 @@ public class ShadersActivity extends Activity { m3.postRotate(-90.0f); m3.postTranslate(0.0f, mDrawHeight); mHorGradient.setLocalMatrix(m3); - + mDiagGradient = new LinearGradient(0.0f, 0.0f, mDrawWidth / 1.5f, mDrawHeight, Color.BLUE, Color.MAGENTA, Shader.TileMode.CLAMP); - + mVertGradient = new LinearGradient(0.0f, 0.0f, 0.0f, mDrawHeight / 2.0f, Color.YELLOW, Color.MAGENTA, Shader.TileMode.MIRROR); @@ -107,7 +107,7 @@ public class ShadersActivity extends Activity { mPaint.setShader(mRepeatShader); canvas.drawRect(0.0f, 0.0f, mDrawWidth, mDrawHeight, mPaint); - + canvas.translate(0.0f, 40.0f + mDrawHeight); mPaint.setShader(mTranslatedShader); canvas.drawRect(0.0f, 0.0f, mDrawWidth, mDrawHeight, mPaint); @@ -124,7 +124,7 @@ public class ShadersActivity extends Activity { mPaint.setShader(mHorGradient); canvas.drawRect(0.0f, 0.0f, mDrawWidth, mDrawHeight, mPaint); - + canvas.translate(0.0f, 40.0f + mDrawHeight); mPaint.setShader(mDiagGradient); canvas.drawRect(0.0f, 0.0f, mDrawWidth, mDrawHeight, mPaint); @@ -132,7 +132,7 @@ public class ShadersActivity extends Activity { canvas.translate(0.0f, 40.0f + mDrawHeight); mPaint.setShader(mVertGradient); canvas.drawRect(0.0f, 0.0f, mDrawWidth, mDrawHeight, mPaint); - + canvas.restore(); } } diff --git a/tools/layoutlib/bridge/src/android/graphics/AvoidXfermode_Delegate.java b/tools/layoutlib/bridge/src/android/graphics/AvoidXfermode_Delegate.java new file mode 100644 index 000000000000..9c49bb883dc9 --- /dev/null +++ b/tools/layoutlib/bridge/src/android/graphics/AvoidXfermode_Delegate.java @@ -0,0 +1,68 @@ +/* + * Copyright (C) 2010 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 android.graphics; + +import com.android.layoutlib.bridge.impl.DelegateManager; + +import java.awt.Composite; + +/** + * Delegate implementing the native methods of android.graphics.AvoidXfermode + * + * Through the layoutlib_create tool, the original native methods of AvoidXfermode have been + * replaced by calls to methods of the same name in this delegate class. + * + * This class behaves like the original native implementation, but in Java, keeping previously + * native data into its own objects and mapping them to int that are sent back and forth between + * it and the original AvoidXfermode class. + * + * Because this extends {@link Xfermode_Delegate}, there's no need to use a + * {@link DelegateManager}, as all the PathEffect classes will be added to the manager owned by + * {@link Xfermode_Delegate}. + * + */ +public class AvoidXfermode_Delegate extends Xfermode_Delegate { + + // ---- delegate data ---- + + // ---- Public Helper methods ---- + + @Override + public Composite getComposite() { + // FIXME + return null; + } + + @Override + public boolean isSupported() { + return false; + } + + @Override + public String getSupportMessage() { + return "Avoid Xfermodes are not supported in Layout Preview mode."; + } + + // ---- native methods ---- + + /*package*/ static int nativeCreate(int opColor, int tolerance, int nativeMode) { + AvoidXfermode_Delegate newDelegate = new AvoidXfermode_Delegate(); + return sManager.addDelegate(newDelegate); + } + + // ---- Private delegate/helper methods ---- +} diff --git a/tools/layoutlib/bridge/src/android/graphics/BitmapShader_Delegate.java b/tools/layoutlib/bridge/src/android/graphics/BitmapShader_Delegate.java new file mode 100644 index 000000000000..b660ae6eb145 --- /dev/null +++ b/tools/layoutlib/bridge/src/android/graphics/BitmapShader_Delegate.java @@ -0,0 +1,242 @@ +/* + * Copyright (C) 2010 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 android.graphics; + +import com.android.layoutlib.bridge.Bridge; +import com.android.layoutlib.bridge.impl.DelegateManager; + +import android.graphics.Shader.TileMode; + +/** + * Delegate implementing the native methods of android.graphics.BitmapShader + * + * Through the layoutlib_create tool, the original native methods of BitmapShader have been + * replaced by calls to methods of the same name in this delegate class. + * + * This class behaves like the original native implementation, but in Java, keeping previously + * native data into its own objects and mapping them to int that are sent back and forth between + * it and the original BitmapShader class. + * + * Because this extends {@link Shader_Delegate}, there's no need to use a {@link DelegateManager}, + * as all the Shader classes will be added to the manager owned by {@link Shader_Delegate}. + * + * @see Shader_Delegate + * + */ +public class BitmapShader_Delegate extends Shader_Delegate { + + // ---- delegate data ---- + private java.awt.Paint mJavaPaint; + + // ---- Public Helper methods ---- + + @Override + public java.awt.Paint getJavaPaint() { + return mJavaPaint; + } + + @Override + public boolean isSupported() { + return true; + } + + @Override + public String getSupportMessage() { + // no message since isSupported returns true; + return null; + } + + // ---- native methods ---- + + /*package*/ static int nativeCreate(int native_bitmap, int shaderTileModeX, + int shaderTileModeY) { + Bitmap_Delegate bitmap = Bitmap_Delegate.getDelegate(native_bitmap); + assert bitmap != null; + if (bitmap == null) { + return 0; + } + + BitmapShader_Delegate newDelegate = new BitmapShader_Delegate( + bitmap.getImage(), + Shader_Delegate.getTileMode(shaderTileModeX), + Shader_Delegate.getTileMode(shaderTileModeY)); + return sManager.addDelegate(newDelegate); + } + + /*package*/ static int nativePostCreate(int native_shader, int native_bitmap, + int shaderTileModeX, int shaderTileModeY) { + // pass, not needed. + return 0; + } + + // ---- Private delegate/helper methods ---- + + private BitmapShader_Delegate(java.awt.image.BufferedImage image, + TileMode tileModeX, TileMode tileModeY) { + mJavaPaint = new BitmapShaderPaint(image, tileModeX, tileModeY); + } + + private class BitmapShaderPaint implements java.awt.Paint { + private final java.awt.image.BufferedImage mImage; + private final TileMode mTileModeX; + private final TileMode mTileModeY; + + BitmapShaderPaint(java.awt.image.BufferedImage image, + TileMode tileModeX, TileMode tileModeY) { + mImage = image; + mTileModeX = tileModeX; + mTileModeY = tileModeY; + } + + public java.awt.PaintContext createContext( + java.awt.image.ColorModel colorModel, + java.awt.Rectangle deviceBounds, + java.awt.geom.Rectangle2D userBounds, + java.awt.geom.AffineTransform xform, + java.awt.RenderingHints hints) { + + java.awt.geom.AffineTransform canvasMatrix; + try { + canvasMatrix = xform.createInverse(); + } catch (java.awt.geom.NoninvertibleTransformException e) { + Bridge.getLog().error(null, "Unable to inverse matrix in BitmapShader", e); + canvasMatrix = new java.awt.geom.AffineTransform(); + } + + java.awt.geom.AffineTransform localMatrix = getLocalMatrix(); + try { + localMatrix = localMatrix.createInverse(); + } catch (java.awt.geom.NoninvertibleTransformException e) { + Bridge.getLog().error(null, "Unable to inverse matrix in BitmapShader", e); + localMatrix = new java.awt.geom.AffineTransform(); + } + + return new BitmapShaderContext(canvasMatrix, localMatrix, colorModel); + } + + private class BitmapShaderContext implements java.awt.PaintContext { + + private final java.awt.geom.AffineTransform mCanvasMatrix; + private final java.awt.geom.AffineTransform mLocalMatrix; + private final java.awt.image.ColorModel mColorModel; + + public BitmapShaderContext( + java.awt.geom.AffineTransform canvasMatrix, + java.awt.geom.AffineTransform localMatrix, + java.awt.image.ColorModel colorModel) { + mCanvasMatrix = canvasMatrix; + mLocalMatrix = localMatrix; + mColorModel = colorModel; + } + + public void dispose() { + } + + public java.awt.image.ColorModel getColorModel() { + return mColorModel; + } + + public java.awt.image.Raster getRaster(int x, int y, int w, int h) { + java.awt.image.BufferedImage image = new java.awt.image.BufferedImage(w, h, + java.awt.image.BufferedImage.TYPE_INT_ARGB); + + int[] data = new int[w*h]; + + int index = 0; + float[] pt1 = new float[2]; + float[] pt2 = new float[2]; + for (int iy = 0 ; iy < h ; iy++) { + for (int ix = 0 ; ix < w ; ix++) { + // handle the canvas transform + pt1[0] = x + ix; + pt1[1] = y + iy; + mCanvasMatrix.transform(pt1, 0, pt2, 0, 1); + + // handle the local matrix. + pt1[0] = pt2[0]; + pt1[1] = pt2[1]; + mLocalMatrix.transform(pt1, 0, pt2, 0, 1); + + data[index++] = getColor(pt2[0], pt2[1]); + } + } + + image.setRGB(0 /*startX*/, 0 /*startY*/, w, h, data, 0 /*offset*/, w /*scansize*/); + + return image.getRaster(); + } + } + + /** + * Returns a color for an arbitrary point. + */ + private int getColor(float fx, float fy) { + int x = getCoordinate(Math.round(fx), mImage.getWidth(), mTileModeX); + int y = getCoordinate(Math.round(fy), mImage.getHeight(), mTileModeY); + + return mImage.getRGB(x, y); + } + + private int getCoordinate(int i, int size, TileMode mode) { + if (i < 0) { + switch (mode) { + case CLAMP: + i = 0; + break; + case REPEAT: + i = size - 1 - (-i % size); + break; + case MIRROR: + // this is the same as the positive side, just make the value positive + // first. + i = -i; + int count = i / size; + i = i % size; + + if ((count % 2) == 1) { + i = size - 1 - i; + } + break; + } + } else if (i >= size) { + switch (mode) { + case CLAMP: + i = size - 1; + break; + case REPEAT: + i = i % size; + break; + case MIRROR: + int count = i / size; + i = i % size; + + if ((count % 2) == 1) { + i = size - 1 - i; + } + break; + } + } + + return i; + } + + + public int getTransparency() { + return java.awt.Paint.TRANSLUCENT; + } + } +} diff --git a/tools/layoutlib/bridge/src/android/graphics/Bitmap_Delegate.java b/tools/layoutlib/bridge/src/android/graphics/Bitmap_Delegate.java index d69abc9cd193..9d60a4369ac3 100644 --- a/tools/layoutlib/bridge/src/android/graphics/Bitmap_Delegate.java +++ b/tools/layoutlib/bridge/src/android/graphics/Bitmap_Delegate.java @@ -45,7 +45,7 @@ import javax.imageio.ImageIO; * @see DelegateManager * */ -public class Bitmap_Delegate { +public final class Bitmap_Delegate { // ---- delegate manager ---- private static final DelegateManager<Bitmap_Delegate> sManager = diff --git a/tools/layoutlib/bridge/src/android/graphics/Canvas_Delegate.java b/tools/layoutlib/bridge/src/android/graphics/Canvas_Delegate.java index c75e1b6a23d7..ba4bed66b942 100644 --- a/tools/layoutlib/bridge/src/android/graphics/Canvas_Delegate.java +++ b/tools/layoutlib/bridge/src/android/graphics/Canvas_Delegate.java @@ -23,12 +23,14 @@ import com.android.layoutlib.bridge.impl.GcSnapshot; 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.Shape; +import java.awt.Stroke; import java.awt.geom.AffineTransform; import java.awt.image.BufferedImage; import java.util.List; @@ -47,7 +49,7 @@ import java.util.List; * @see DelegateManager * */ -public class Canvas_Delegate { +public final class Canvas_Delegate { // ---- delegate manager ---- private static final DelegateManager<Canvas_Delegate> sManager = @@ -55,6 +57,10 @@ public class Canvas_Delegate { // ---- delegate helper data ---- + private interface Drawable { + void draw(Graphics2D graphics, Paint_Delegate paint); + } + // ---- delegate data ---- private BufferedImage mBufferedImage; private GcSnapshot mSnapshot = new GcSnapshot(); @@ -403,9 +409,9 @@ public class Canvas_Delegate { if (matrixDelegate.hasPerspective()) { assert false; - Bridge.getLog().warning(null, + Bridge.getLog().fidelityWarning(null, "android.graphics.Canvas#setMatrix(android.graphics.Matrix) only " + - "supports affine transformations in the Layout Preview."); + "supports affine transformations in the Layout Preview.", null); } } @@ -522,7 +528,10 @@ public class Canvas_Delegate { // set the color graphics.setColor(new Color(color, true /*alpha*/)); - setModeInGraphics(graphics, mode); + Composite composite = PorterDuffXfermode_Delegate.getComposite(mode); + if (composite != null) { + graphics.setComposite(composite); + } graphics.fillRect(0, 0, canvasDelegate.mBufferedImage.getWidth(), canvasDelegate.mBufferedImage.getHeight()); @@ -709,8 +718,28 @@ public class Canvas_Delegate { /*package*/ static void native_drawPath(int nativeCanvas, int path, int paint) { - // FIXME - throw new UnsupportedOperationException(); + final Path_Delegate pathDelegate = Path_Delegate.getDelegate(path); + if (pathDelegate == null) { + assert false; + return; + } + + draw(nativeCanvas, paint, new Drawable() { + public void draw(Graphics2D graphics, Paint_Delegate paint) { + Shape shape = pathDelegate.getJavaShape(); + int style = paint.getStyle(); + + if (style == Paint.Style.FILL.nativeInt || + style == Paint.Style.FILL_AND_STROKE.nativeInt) { + graphics.fill(shape); + } + + if (style == Paint.Style.STROKE.nativeInt || + style == Paint.Style.FILL_AND_STROKE.nativeInt) { + graphics.draw(shape); + } + } + }); } /*package*/ static void native_drawBitmap(Canvas thisCanvas, int nativeCanvas, int bitmap, @@ -719,8 +748,20 @@ public class Canvas_Delegate { int canvasDensity, 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(); + float right = left + image.getWidth(); + float bottom = top + image.getHeight(); + + drawBitmap(nativeCanvas, image, nativePaintOrZero, + 0, 0, image.getWidth(), image.getHeight(), + (int)left, (int)top, (int)right, (int)bottom); } /*package*/ static void native_drawBitmap(Canvas thisCanvas, int nativeCanvas, int bitmap, @@ -998,6 +1039,34 @@ public class Canvas_Delegate { // ---- Private delegate/helper methods ---- + /** + * Executes a {@link Drawable} with a given canvas and paint. + */ + private static void draw(int nCanvas, int nPaint, Drawable runnable) { + // get the delegate from the native int. + Canvas_Delegate canvasDelegate = sManager.getDelegate(nCanvas); + if (canvasDelegate == null) { + assert false; + return; + } + + Paint_Delegate paintDelegate = Paint_Delegate.getDelegate(nPaint); + if (paintDelegate == null) { + assert false; + return; + } + + // get a Graphics2D object configured with the drawing parameters. + Graphics2D g = canvasDelegate.createCustomGraphics(paintDelegate); + + try { + runnable.draw(g, paintDelegate); + } finally { + // dispose Graphics2D object + g.dispose(); + } + } + private Canvas_Delegate(BufferedImage image) { setBitmap(image); } @@ -1069,18 +1138,23 @@ public class Canvas_Delegate { boolean useColorPaint = true; // get the shader first, as it'll replace the color if it can be used it. - Shader_Delegate shaderDelegate = Shader_Delegate.getDelegate(paint.getShader()); - if (shaderDelegate != null) { - java.awt.Paint shaderPaint = shaderDelegate.getJavaPaint(); - assert shaderPaint != null; - if (shaderPaint != null) { - g.setPaint(shaderPaint); - useColorPaint = false; - } else { - Bridge.getLog().warning(null, - String.format( - "Shader '%1$s' is not supported in the Layout Preview.", - shaderDelegate.getClass().getCanonicalName())); + int nativeShader = paint.getShader(); + if (nativeShader > 0) { + Shader_Delegate shaderDelegate = Shader_Delegate.getDelegate(nativeShader); + assert shaderDelegate != null; + if (shaderDelegate != null) { + if (shaderDelegate.isSupported()) { + java.awt.Paint shaderPaint = shaderDelegate.getJavaPaint(); + assert shaderPaint != null; + if (shaderPaint != null) { + g.setPaint(shaderPaint); + useColorPaint = false; + } + } else { + Bridge.getLog().fidelityWarning(null, + shaderDelegate.getSupportMessage(), + null); + } } } @@ -1092,19 +1166,30 @@ public class Canvas_Delegate { if (style == Paint.Style.STROKE.nativeInt || style == Paint.Style.FILL_AND_STROKE.nativeInt) { - PathEffect_Delegate effectDelegate = PathEffect_Delegate.getDelegate( - paint.getPathEffect()); + boolean customStroke = false; + + int pathEffect = paint.getPathEffect(); + if (pathEffect > 0) { + PathEffect_Delegate effectDelegate = PathEffect_Delegate.getDelegate(pathEffect); + assert effectDelegate != null; + if (effectDelegate != null) { + if (effectDelegate.isSupported()) { + Stroke stroke = effectDelegate.getStroke(paint); + assert stroke != null; + if (stroke != null) { + g.setStroke(stroke); + customStroke = true; + } + } else { + Bridge.getLog().fidelityWarning(null, + effectDelegate.getSupportMessage(), + null); + } + } + } - if (effectDelegate instanceof DashPathEffect_Delegate) { - DashPathEffect_Delegate dpe = (DashPathEffect_Delegate)effectDelegate; - g.setStroke(new BasicStroke( - paint.getStrokeWidth(), - paint.getJavaCap(), - paint.getJavaJoin(), - paint.getStrokeMiter(), - dpe.getIntervals(), - dpe.getPhase())); - } else { + // if no custom stroke as been set, set the default one. + if (customStroke == false) { g.setStroke(new BasicStroke( paint.getStrokeWidth(), paint.getJavaCap(), @@ -1113,87 +1198,28 @@ public class Canvas_Delegate { } } - Xfermode_Delegate xfermodeDelegate = Xfermode_Delegate.getDelegate(paint.getXfermode()); - if (xfermodeDelegate instanceof PorterDuffXfermode_Delegate) { - int mode = ((PorterDuffXfermode_Delegate)xfermodeDelegate).getMode(); - - setModeInGraphics(g, mode); - } else { - // default mode is src_over - g.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER)); - - // if xfermode wasn't null, then it's something we don't support. log it. + int xfermode = paint.getXfermode(); + if (xfermode > 0) { + Xfermode_Delegate xfermodeDelegate = Xfermode_Delegate.getDelegate(paint.getXfermode()); + assert xfermodeDelegate != null; if (xfermodeDelegate != null) { - assert false; - Bridge.getLog().warning(null, - String.format( - "Xfermode '%1$s' is not supported in the Layout Preview.", - xfermodeDelegate.getClass().getCanonicalName())); + if (xfermodeDelegate.isSupported()) { + Composite composite = xfermodeDelegate.getComposite(); + assert composite != null; + if (composite != null) { + g.setComposite(composite); + } + } else { + Bridge.getLog().fidelityWarning(null, + xfermodeDelegate.getSupportMessage(), + null); + } } } return g; } - private static void setModeInGraphics(Graphics2D g, int mode) { - for (PorterDuff.Mode m : PorterDuff.Mode.values()) { - if (m.nativeInt == mode) { - setModeInGraphics(g, m); - return; - } - } - } - - private static void setModeInGraphics(Graphics2D g, PorterDuff.Mode mode) { - switch (mode) { - case CLEAR: - g.setComposite(AlphaComposite.getInstance(AlphaComposite.CLEAR, 1.0f /*alpha*/)); - break; - case DARKEN: - break; - case DST: - g.setComposite(AlphaComposite.getInstance(AlphaComposite.DST, 1.0f /*alpha*/)); - break; - case DST_ATOP: - g.setComposite(AlphaComposite.getInstance(AlphaComposite.DST_ATOP, 1.0f /*alpha*/)); - break; - case DST_IN: - g.setComposite(AlphaComposite.getInstance(AlphaComposite.DST_IN, 1.0f /*alpha*/)); - break; - case DST_OUT: - g.setComposite(AlphaComposite.getInstance(AlphaComposite.DST_OUT, 1.0f /*alpha*/)); - break; - case DST_OVER: - g.setComposite(AlphaComposite.getInstance(AlphaComposite.DST_OVER, 1.0f /*alpha*/)); - break; - case LIGHTEN: - break; - case MULTIPLY: - break; - case SCREEN: - break; - case SRC: - g.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC, 1.0f /*alpha*/)); - break; - case SRC_ATOP: - g.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_ATOP, 1.0f /*alpha*/)); - break; - case SRC_IN: - g.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_IN, 1.0f /*alpha*/)); - break; - case SRC_OUT: - g.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OUT, 1.0f /*alpha*/)); - break; - case SRC_OVER: - g.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER, 1.0f /*alpha*/)); - break; - case XOR: - g.setComposite(AlphaComposite.getInstance(AlphaComposite.XOR, 1.0f /*alpha*/)); - break; - } - } - - private static void drawBitmap( int nativeCanvas, BufferedImage image, @@ -1228,6 +1254,7 @@ public class Canvas_Delegate { Paint_Delegate paintDelegate, int sleft, int stop, int sright, int sbottom, int dleft, int dtop, int dright, int dbottom) { + //FIXME add support for canvas, screen and bitmap densities. Graphics2D g = canvasDelegate.getGcSnapshot().create(); try { diff --git a/tools/layoutlib/bridge/src/android/graphics/ComposePathEffect_Delegate.java b/tools/layoutlib/bridge/src/android/graphics/ComposePathEffect_Delegate.java new file mode 100644 index 000000000000..954c658cb92a --- /dev/null +++ b/tools/layoutlib/bridge/src/android/graphics/ComposePathEffect_Delegate.java @@ -0,0 +1,69 @@ +/* + * Copyright (C) 2010 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 android.graphics; + +import com.android.layoutlib.bridge.impl.DelegateManager; + +import java.awt.Stroke; + +/** + * Delegate implementing the native methods of android.graphics.ComposePathEffect + * + * Through the layoutlib_create tool, the original native methods of ComposePathEffect have been + * replaced by calls to methods of the same name in this delegate class. + * + * This class behaves like the original native implementation, but in Java, keeping previously + * native data into its own objects and mapping them to int that are sent back and forth between + * it and the original ComposePathEffect class. + * + * Because this extends {@link Shader_Delegate}, there's no need to use a {@link DelegateManager}, + * as all the Shader classes will be added to the manager owned by {@link Shader_Delegate}. + * + * @see Shader_Delegate + * + */ +public class ComposePathEffect_Delegate extends PathEffect_Delegate { + + // ---- delegate data ---- + + // ---- Public Helper methods ---- + + @Override + public Stroke getStroke(Paint_Delegate paint) { + // FIXME + return null; + } + + @Override + public boolean isSupported() { + return false; + } + + @Override + public String getSupportMessage() { + return "Composte Path Effects are not supported in Layout Preview mode."; + } + + // ---- native methods ---- + + /*package*/ static int nativeCreate(int outerpe, int innerpe) { + ComposePathEffect_Delegate newDelegate = new ComposePathEffect_Delegate(); + return sManager.addDelegate(newDelegate); + } + + // ---- Private delegate/helper methods ---- +} diff --git a/tools/layoutlib/bridge/src/android/graphics/ComposeShader_Delegate.java b/tools/layoutlib/bridge/src/android/graphics/ComposeShader_Delegate.java new file mode 100644 index 000000000000..285322224c39 --- /dev/null +++ b/tools/layoutlib/bridge/src/android/graphics/ComposeShader_Delegate.java @@ -0,0 +1,93 @@ +/* + * Copyright (C) 2010 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 android.graphics; + +import com.android.layoutlib.bridge.impl.DelegateManager; + +import java.awt.Paint; + +/** + * Delegate implementing the native methods of android.graphics.ComposeShader + * + * Through the layoutlib_create tool, the original native methods of ComposeShader have been + * replaced by calls to methods of the same name in this delegate class. + * + * This class behaves like the original native implementation, but in Java, keeping previously + * native data into its own objects and mapping them to int that are sent back and forth between + * it and the original ComposeShader class. + * + * Because this extends {@link Shader_Delegate}, there's no need to use a {@link DelegateManager}, + * as all the Shader classes will be added to the manager owned by {@link Shader_Delegate}. + * + * @see Shader_Delegate + * + */ +public class ComposeShader_Delegate extends Shader_Delegate { + + // ---- delegate data ---- + + // ---- Public Helper methods ---- + + @Override + public Paint getJavaPaint() { + // FIXME + return null; + } + + @Override + public boolean isSupported() { + return false; + } + + @Override + public String getSupportMessage() { + return "Compose Shader are not supported in Layout Preview mode."; + } + + + // ---- native methods ---- + + /*package*/ static int nativeCreate1(int native_shaderA, int native_shaderB, + int native_mode) { + // FIXME not supported yet. + ComposeShader_Delegate newDelegate = new ComposeShader_Delegate(); + return sManager.addDelegate(newDelegate); + } + + /*package*/ static int nativeCreate2(int native_shaderA, int native_shaderB, + int porterDuffMode) { + // FIXME not supported yet. + ComposeShader_Delegate newDelegate = new ComposeShader_Delegate(); + return sManager.addDelegate(newDelegate); + } + + /*package*/ static int nativePostCreate1(int native_shader, int native_skiaShaderA, + int native_skiaShaderB, int native_mode) { + // pass, not needed. + return 0; + } + + /*package*/ static int nativePostCreate2(int native_shader, int native_skiaShaderA, + int native_skiaShaderB, int porterDuffMode) { + // pass, not needed. + return 0; + } + + + // ---- Private delegate/helper methods ---- + +} diff --git a/tools/layoutlib/bridge/src/android/graphics/CornerPathEffect_Delegate.java b/tools/layoutlib/bridge/src/android/graphics/CornerPathEffect_Delegate.java new file mode 100644 index 000000000000..cd0854943901 --- /dev/null +++ b/tools/layoutlib/bridge/src/android/graphics/CornerPathEffect_Delegate.java @@ -0,0 +1,69 @@ +/* + * Copyright (C) 2010 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 android.graphics; + +import com.android.layoutlib.bridge.impl.DelegateManager; + +import java.awt.Stroke; + +/** + * Delegate implementing the native methods of android.graphics.CornerPathEffect + * + * Through the layoutlib_create tool, the original native methods of CornerPathEffect have been + * replaced by calls to methods of the same name in this delegate class. + * + * This class behaves like the original native implementation, but in Java, keeping previously + * native data into its own objects and mapping them to int that are sent back and forth between + * it and the original CornerPathEffect class. + * + * Because this extends {@link Shader_Delegate}, there's no need to use a {@link DelegateManager}, + * as all the Shader classes will be added to the manager owned by {@link Shader_Delegate}. + * + * @see Shader_Delegate + * + */ +public class CornerPathEffect_Delegate extends PathEffect_Delegate { + + // ---- delegate data ---- + + // ---- Public Helper methods ---- + + @Override + public Stroke getStroke(Paint_Delegate paint) { + // FIXME + return null; + } + + @Override + public boolean isSupported() { + return false; + } + + @Override + public String getSupportMessage() { + return "Corner Path Effects are not supported in Layout Preview mode."; + } + + // ---- native methods ---- + + /*package*/ static int nativeCreate(float radius) { + CornerPathEffect_Delegate newDelegate = new CornerPathEffect_Delegate(); + return sManager.addDelegate(newDelegate); + } + + // ---- Private delegate/helper methods ---- +} diff --git a/tools/layoutlib/bridge/src/android/graphics/DashPathEffect_Delegate.java b/tools/layoutlib/bridge/src/android/graphics/DashPathEffect_Delegate.java index 7ee72d8582a2..1b539ce5d426 100644 --- a/tools/layoutlib/bridge/src/android/graphics/DashPathEffect_Delegate.java +++ b/tools/layoutlib/bridge/src/android/graphics/DashPathEffect_Delegate.java @@ -18,6 +18,9 @@ package android.graphics; import com.android.layoutlib.bridge.impl.DelegateManager; +import java.awt.BasicStroke; +import java.awt.Stroke; + /** * Delegate implementing the native methods of android.graphics.DashPathEffect * @@ -32,8 +35,10 @@ import com.android.layoutlib.bridge.impl.DelegateManager; * {@link DelegateManager}, as all the PathEffect classes will be added to the manager owned by * {@link PathEffect_Delegate}. * + * @see PathEffect_Delegate + * */ -public class DashPathEffect_Delegate extends PathEffect_Delegate { +public final class DashPathEffect_Delegate extends PathEffect_Delegate { // ---- delegate data ---- @@ -42,12 +47,26 @@ public class DashPathEffect_Delegate extends PathEffect_Delegate { // ---- Public Helper methods ---- - public float[] getIntervals() { - return mIntervals; + @Override + public Stroke getStroke(Paint_Delegate paint) { + return new BasicStroke( + paint.getStrokeWidth(), + paint.getJavaCap(), + paint.getJavaJoin(), + paint.getStrokeMiter(), + mIntervals, + mPhase); + } + + @Override + public boolean isSupported() { + return true; } - public float getPhase() { - return mPhase; + @Override + public String getSupportMessage() { + // no message since isSupported returns true; + return null; } // ---- native methods ---- diff --git a/tools/layoutlib/bridge/src/android/graphics/DiscretePathEffect_Delegate.java b/tools/layoutlib/bridge/src/android/graphics/DiscretePathEffect_Delegate.java new file mode 100644 index 000000000000..f99ab2bd4221 --- /dev/null +++ b/tools/layoutlib/bridge/src/android/graphics/DiscretePathEffect_Delegate.java @@ -0,0 +1,69 @@ +/* + * Copyright (C) 2010 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 android.graphics; + +import com.android.layoutlib.bridge.impl.DelegateManager; + +import java.awt.Stroke; + +/** + * Delegate implementing the native methods of android.graphics.DiscretePathEffect + * + * Through the layoutlib_create tool, the original native methods of DiscretePathEffect have been + * replaced by calls to methods of the same name in this delegate class. + * + * This class behaves like the original native implementation, but in Java, keeping previously + * native data into its own objects and mapping them to int that are sent back and forth between + * it and the original DiscretePathEffect class. + * + * Because this extends {@link Shader_Delegate}, there's no need to use a {@link DelegateManager}, + * as all the Shader classes will be added to the manager owned by {@link Shader_Delegate}. + * + * @see Shader_Delegate + * + */ +public class DiscretePathEffect_Delegate extends PathEffect_Delegate { + + // ---- delegate data ---- + + // ---- Public Helper methods ---- + + @Override + public Stroke getStroke(Paint_Delegate paint) { + // FIXME + return null; + } + + @Override + public boolean isSupported() { + return false; + } + + @Override + public String getSupportMessage() { + return "Discrete Path Effects are not supported in Layout Preview mode."; + } + + // ---- native methods ---- + + /*package*/ static int nativeCreate(float length, float deviation) { + DiscretePathEffect_Delegate newDelegate = new DiscretePathEffect_Delegate(); + return sManager.addDelegate(newDelegate); + } + + // ---- Private delegate/helper methods ---- +} diff --git a/tools/layoutlib/bridge/src/android/graphics/Gradient_Delegate.java b/tools/layoutlib/bridge/src/android/graphics/Gradient_Delegate.java index bc4ccd2e3db4..7a0c2f776775 100644 --- a/tools/layoutlib/bridge/src/android/graphics/Gradient_Delegate.java +++ b/tools/layoutlib/bridge/src/android/graphics/Gradient_Delegate.java @@ -26,6 +26,18 @@ public abstract class Gradient_Delegate extends Shader_Delegate { protected final int[] mColors; protected final float[] mPositions; + @Override + public boolean isSupported() { + // all gradient shaders are supported. + return true; + } + + @Override + public String getSupportMessage() { + // all gradient shaders are supported, no need for a gradient support + return null; + } + /** * Creates the base shader and do some basic test on the parameters. * diff --git a/tools/layoutlib/bridge/src/android/graphics/LinearGradient_Delegate.java b/tools/layoutlib/bridge/src/android/graphics/LinearGradient_Delegate.java index 862b4544a060..baa0a6afc0d0 100644 --- a/tools/layoutlib/bridge/src/android/graphics/LinearGradient_Delegate.java +++ b/tools/layoutlib/bridge/src/android/graphics/LinearGradient_Delegate.java @@ -21,10 +21,6 @@ import com.android.layoutlib.bridge.impl.DelegateManager; import android.graphics.Shader.TileMode; -import java.awt.Paint; -import java.awt.geom.AffineTransform; -import java.awt.geom.NoninvertibleTransformException; - /** * Delegate implementing the native methods of android.graphics.LinearGradient * @@ -41,7 +37,7 @@ import java.awt.geom.NoninvertibleTransformException; * @see Shader_Delegate * */ -public class LinearGradient_Delegate extends Gradient_Delegate { +public final class LinearGradient_Delegate extends Gradient_Delegate { // ---- delegate data ---- private java.awt.Paint mJavaPaint; @@ -49,7 +45,7 @@ public class LinearGradient_Delegate extends Gradient_Delegate { // ---- Public Helper methods ---- @Override - public Paint getJavaPaint() { + public java.awt.Paint getJavaPaint() { return mJavaPaint; } @@ -58,17 +54,8 @@ public class LinearGradient_Delegate extends Gradient_Delegate { /*package*/ static int nativeCreate1(LinearGradient thisGradient, float x0, float y0, float x1, float y1, int colors[], float positions[], int tileMode) { - // figure out the tile - TileMode tile = null; - for (TileMode tm : TileMode.values()) { - if (tm.nativeInt == tileMode) { - tile = tm; - break; - } - } - LinearGradient_Delegate newDelegate = new LinearGradient_Delegate(x0, y0, x1, y1, - colors, positions, tile); + colors, positions, Shader_Delegate.getTileMode(tileMode)); return sManager.addDelegate(newDelegate); } /*package*/ static int nativeCreate2(LinearGradient thisGradient, @@ -144,20 +131,20 @@ public class LinearGradient_Delegate extends Gradient_Delegate { java.awt.RenderingHints hints) { precomputeGradientColors(); - AffineTransform canvasMatrix; + java.awt.geom.AffineTransform canvasMatrix; try { canvasMatrix = xform.createInverse(); - } catch (NoninvertibleTransformException e) { + } catch (java.awt.geom.NoninvertibleTransformException e) { Bridge.getLog().error(null, "Unable to inverse matrix in LinearGradient", e); - canvasMatrix = new AffineTransform(); + canvasMatrix = new java.awt.geom.AffineTransform(); } - AffineTransform localMatrix = getLocalMatrix(); + java.awt.geom.AffineTransform localMatrix = getLocalMatrix(); try { localMatrix = localMatrix.createInverse(); - } catch (NoninvertibleTransformException e) { + } catch (java.awt.geom.NoninvertibleTransformException e) { Bridge.getLog().error(null, "Unable to inverse matrix in LinearGradient", e); - localMatrix = new AffineTransform(); + localMatrix = new java.awt.geom.AffineTransform(); } return new LinearGradientPaintContext(canvasMatrix, localMatrix, colorModel); @@ -165,12 +152,14 @@ public class LinearGradient_Delegate extends Gradient_Delegate { private class LinearGradientPaintContext implements java.awt.PaintContext { - private final AffineTransform mCanvasMatrix; - private final AffineTransform mLocalMatrix; + private final java.awt.geom.AffineTransform mCanvasMatrix; + private final java.awt.geom.AffineTransform mLocalMatrix; private final java.awt.image.ColorModel mColorModel; - public LinearGradientPaintContext(AffineTransform canvasMatrix, - AffineTransform localMatrix, java.awt.image.ColorModel colorModel) { + private LinearGradientPaintContext( + java.awt.geom.AffineTransform canvasMatrix, + java.awt.geom.AffineTransform localMatrix, + java.awt.image.ColorModel colorModel) { mCanvasMatrix = canvasMatrix; mLocalMatrix = localMatrix; mColorModel = colorModel; diff --git a/tools/layoutlib/bridge/src/android/graphics/Matrix_Delegate.java b/tools/layoutlib/bridge/src/android/graphics/Matrix_Delegate.java index b464f66b4311..f6cee5ec6e90 100644 --- a/tools/layoutlib/bridge/src/android/graphics/Matrix_Delegate.java +++ b/tools/layoutlib/bridge/src/android/graphics/Matrix_Delegate.java @@ -1052,6 +1052,4 @@ public final class Matrix_Delegate { return tmp; } - - } diff --git a/tools/layoutlib/bridge/src/android/graphics/NinePatch_Delegate.java b/tools/layoutlib/bridge/src/android/graphics/NinePatch_Delegate.java index fe9bef934bd1..b8f76a60d4fa 100644 --- a/tools/layoutlib/bridge/src/android/graphics/NinePatch_Delegate.java +++ b/tools/layoutlib/bridge/src/android/graphics/NinePatch_Delegate.java @@ -43,7 +43,7 @@ import java.util.Map; * around to map int to instance of the delegate. * */ -public class NinePatch_Delegate { +public final class NinePatch_Delegate { /** * Cache map for {@link NinePatchChunk}. diff --git a/tools/layoutlib/bridge/src/android/graphics/Path.java b/tools/layoutlib/bridge/src/android/graphics/Path.java deleted file mode 100644 index c0bc005bf5f2..000000000000 --- a/tools/layoutlib/bridge/src/android/graphics/Path.java +++ /dev/null @@ -1,611 +0,0 @@ -/* - * Copyright (C) 2006 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 android.graphics; - -import java.awt.Shape; -import java.awt.geom.AffineTransform; -import java.awt.geom.Ellipse2D; -import java.awt.geom.GeneralPath; -import java.awt.geom.PathIterator; -import java.awt.geom.Rectangle2D; - -/** - * The Path class encapsulates compound (multiple contour) geometric paths - * consisting of straight line segments, quadratic curves, and cubic curves. - * It can be drawn with canvas.drawPath(path, paint), either filled or stroked - * (based on the paint's Style), or it can be used for clipping or to draw - * text on a path. - */ -public class Path { - - private FillType mFillType = FillType.WINDING; - private GeneralPath mPath = new GeneralPath(); - - private float mLastX = 0; - private float mLastY = 0; - - //---------- Custom methods ---------- - - public Shape getAwtShape() { - return mPath; - } - - //---------- - - /** - * Create an empty path - */ - public Path() { - } - - /** - * Create a new path, copying the contents from the src path. - * - * @param src The path to copy from when initializing the new path - */ - public Path(Path src) { - mPath.append(src.mPath, false /* connect */); - } - - /** - * Clear any lines and curves from the path, making it empty. - * This does NOT change the fill-type setting. - */ - public void reset() { - mPath = new GeneralPath(); - } - - /** - * Rewinds the path: clears any lines and curves from the path but - * keeps the internal data structure for faster reuse. - */ - public void rewind() { - // FIXME - throw new UnsupportedOperationException(); - } - - /** Replace the contents of this with the contents of src. - */ - public void set(Path src) { - mPath.append(src.mPath, false /* connect */); - } - - /** Enum for the ways a path may be filled - */ - public enum FillType { - // these must match the values in SkPath.h - WINDING (GeneralPath.WIND_NON_ZERO, false), - EVEN_ODD (GeneralPath.WIND_EVEN_ODD, false), - INVERSE_WINDING (GeneralPath.WIND_NON_ZERO, true), - INVERSE_EVEN_ODD(GeneralPath.WIND_EVEN_ODD, true); - - FillType(int rule, boolean inverse) { - this.rule = rule; - this.inverse = inverse; - } - - final int rule; - final boolean inverse; - } - - /** - * Return the path's fill type. This defines how "inside" is - * computed. The default value is WINDING. - * - * @return the path's fill type - */ - public FillType getFillType() { - return mFillType; - } - - /** - * Set the path's fill type. This defines how "inside" is computed. - * - * @param ft The new fill type for this path - */ - public void setFillType(FillType ft) { - mFillType = ft; - mPath.setWindingRule(ft.rule); - } - - /** - * Returns true if the filltype is one of the INVERSE variants - * - * @return true if the filltype is one of the INVERSE variants - */ - public boolean isInverseFillType() { - return mFillType.inverse; - } - - /** - * Toggles the INVERSE state of the filltype - */ - public void toggleInverseFillType() { - switch (mFillType) { - case WINDING: - mFillType = FillType.INVERSE_WINDING; - break; - case EVEN_ODD: - mFillType = FillType.INVERSE_EVEN_ODD; - break; - case INVERSE_WINDING: - mFillType = FillType.WINDING; - break; - case INVERSE_EVEN_ODD: - mFillType = FillType.EVEN_ODD; - break; - } - } - - /** - * Returns true if the path is empty (contains no lines or curves) - * - * @return true if the path is empty (contains no lines or curves) - */ - public boolean isEmpty() { - return mPath.getCurrentPoint() == null; - } - - /** - * Returns true if the path specifies a rectangle. If so, and if rect is - * not null, set rect to the bounds of the path. If the path does not - * specify a rectangle, return false and ignore rect. - * - * @param rect If not null, returns the bounds of the path if it specifies - * a rectangle - * @return true if the path specifies a rectangle - */ - public boolean isRect(RectF rect) { - // FIXME - throw new UnsupportedOperationException(); - } - - /** - * Compute the bounds of the path, and write the answer into bounds. If the - * path contains 0 or 1 points, the bounds is set to (0,0,0,0) - * - * @param bounds Returns the computed bounds of the path - * @param exact If true, return the exact (but slower) bounds, else return - * just the bounds of all control points - */ - public void computeBounds(RectF bounds, boolean exact) { - Rectangle2D rect = mPath.getBounds2D(); - bounds.left = (float)rect.getMinX(); - bounds.right = (float)rect.getMaxX(); - bounds.top = (float)rect.getMinY(); - bounds.bottom = (float)rect.getMaxY(); - } - - /** - * Hint to the path to prepare for adding more points. This can allow the - * path to more efficiently allocate its storage. - * - * @param extraPtCount The number of extra points that may be added to this - * path - */ - public void incReserve(int extraPtCount) { - // pass - } - - /** - * Set the beginning of the next contour to the point (x,y). - * - * @param x The x-coordinate of the start of a new contour - * @param y The y-coordinate of the start of a new contour - */ - public void moveTo(float x, float y) { - mPath.moveTo(mLastX = x, mLastY = y); - } - - /** - * Set the beginning of the next contour relative to the last point on the - * previous contour. If there is no previous contour, this is treated the - * same as moveTo(). - * - * @param dx The amount to add to the x-coordinate of the end of the - * previous contour, to specify the start of a new contour - * @param dy The amount to add to the y-coordinate of the end of the - * previous contour, to specify the start of a new contour - */ - public void rMoveTo(float dx, float dy) { - dx += mLastX; - dy += mLastY; - mPath.moveTo(mLastX = dx, mLastY = dy); - } - - /** - * Add a line from the last point to the specified point (x,y). - * If no moveTo() call has been made for this contour, the first point is - * automatically set to (0,0). - * - * @param x The x-coordinate of the end of a line - * @param y The y-coordinate of the end of a line - */ - public void lineTo(float x, float y) { - mPath.lineTo(mLastX = x, mLastY = y); - } - - /** - * Same as lineTo, but the coordinates are considered relative to the last - * point on this contour. If there is no previous point, then a moveTo(0,0) - * is inserted automatically. - * - * @param dx The amount to add to the x-coordinate of the previous point on - * this contour, to specify a line - * @param dy The amount to add to the y-coordinate of the previous point on - * this contour, to specify a line - */ - public void rLineTo(float dx, float dy) { - if (isEmpty()) { - mPath.moveTo(mLastX = 0, mLastY = 0); - } - dx += mLastX; - dy += mLastY; - mPath.lineTo(mLastX = dx, mLastY = dy); - } - - /** - * Add a quadratic bezier from the last point, approaching control point - * (x1,y1), and ending at (x2,y2). If no moveTo() call has been made for - * this contour, the first point is automatically set to (0,0). - * - * @param x1 The x-coordinate of the control point on a quadratic curve - * @param y1 The y-coordinate of the control point on a quadratic curve - * @param x2 The x-coordinate of the end point on a quadratic curve - * @param y2 The y-coordinate of the end point on a quadratic curve - */ - public void quadTo(float x1, float y1, float x2, float y2) { - mPath.quadTo(x1, y1, mLastX = x2, mLastY = y2); - } - - /** - * Same as quadTo, but the coordinates are considered relative to the last - * point on this contour. If there is no previous point, then a moveTo(0,0) - * is inserted automatically. - * - * @param dx1 The amount to add to the x-coordinate of the last point on - * this contour, for the control point of a quadratic curve - * @param dy1 The amount to add to the y-coordinate of the last point on - * this contour, for the control point of a quadratic curve - * @param dx2 The amount to add to the x-coordinate of the last point on - * this contour, for the end point of a quadratic curve - * @param dy2 The amount to add to the y-coordinate of the last point on - * this contour, for the end point of a quadratic curve - */ - public void rQuadTo(float dx1, float dy1, float dx2, float dy2) { - if (isEmpty()) { - mPath.moveTo(mLastX = 0, mLastY = 0); - } - dx1 += mLastX; - dy1 += mLastY; - dx2 += mLastX; - dy2 += mLastY; - mPath.quadTo(dx1, dy1, mLastX = dx2, mLastY = dy2); - } - - /** - * Add a cubic bezier from the last point, approaching control points - * (x1,y1) and (x2,y2), and ending at (x3,y3). If no moveTo() call has been - * made for this contour, the first point is automatically set to (0,0). - * - * @param x1 The x-coordinate of the 1st control point on a cubic curve - * @param y1 The y-coordinate of the 1st control point on a cubic curve - * @param x2 The x-coordinate of the 2nd control point on a cubic curve - * @param y2 The y-coordinate of the 2nd control point on a cubic curve - * @param x3 The x-coordinate of the end point on a cubic curve - * @param y3 The y-coordinate of the end point on a cubic curve - */ - public void cubicTo(float x1, float y1, float x2, float y2, - float x3, float y3) { - mPath.curveTo(x1, y1, x2, y2, mLastX = x3, mLastY = y3); - } - - /** - * Same as cubicTo, but the coordinates are considered relative to the - * current point on this contour. If there is no previous point, then a - * moveTo(0,0) is inserted automatically. - */ - public void rCubicTo(float dx1, float dy1, float dx2, float dy2, - float dx3, float dy3) { - if (isEmpty()) { - mPath.moveTo(mLastX = 0, mLastY = 0); - } - dx1 += mLastX; - dy1 += mLastY; - dx2 += mLastX; - dy2 += mLastY; - dx3 += mLastX; - dy3 += mLastY; - mPath.curveTo(dx1, dy1, dx2, dy2, mLastX = dx3, mLastY = dy3); - } - - /** - * Append the specified arc to the path as a new contour. If the start of - * the path is different from the path's current last point, then an - * automatic lineTo() is added to connect the current contour to the - * start of the arc. However, if the path is empty, then we call moveTo() - * with the first point of the arc. The sweep angle is tread mod 360. - * - * @param oval The bounds of oval defining shape and size of the arc - * @param startAngle Starting angle (in degrees) where the arc begins - * @param sweepAngle Sweep angle (in degrees) measured clockwise, treated - * mod 360. - * @param forceMoveTo If true, always begin a new contour with the arc - */ - public void arcTo(RectF oval, float startAngle, float sweepAngle, - boolean forceMoveTo) { - throw new UnsupportedOperationException(); - } - - /** - * Append the specified arc to the path as a new contour. If the start of - * the path is different from the path's current last point, then an - * automatic lineTo() is added to connect the current contour to the - * start of the arc. However, if the path is empty, then we call moveTo() - * with the first point of the arc. - * - * @param oval The bounds of oval defining shape and size of the arc - * @param startAngle Starting angle (in degrees) where the arc begins - * @param sweepAngle Sweep angle (in degrees) measured clockwise - */ - public void arcTo(RectF oval, float startAngle, float sweepAngle) { - throw new UnsupportedOperationException(); - } - - /** - * Close the current contour. If the current point is not equal to the - * first point of the contour, a line segment is automatically added. - */ - public void close() { - mPath.closePath(); - } - - /** - * Specifies how closed shapes (e.g. rects, ovals) are oriented when they - * are added to a path. - */ - public enum Direction { - /** clockwise */ - CW (0), // must match enum in SkPath.h - /** counter-clockwise */ - CCW (1); // must match enum in SkPath.h - - Direction(int ni) { - nativeInt = ni; - } - final int nativeInt; - } - - /** - * Add a closed rectangle contour to the path - * - * @param rect The rectangle to add as a closed contour to the path - * @param dir The direction to wind the rectangle's contour - */ - public void addRect(RectF rect, Direction dir) { - if (rect == null) { - throw new NullPointerException("need rect parameter"); - } - - addRect(rect.left, rect.top, rect.right, rect.bottom, dir); - } - - /** - * Add a closed rectangle contour to the path - * - * @param left The left side of a rectangle to add to the path - * @param top The top of a rectangle to add to the path - * @param right The right side of a rectangle to add to the path - * @param bottom The bottom of a rectangle to add to the path - * @param dir The direction to wind the rectangle's contour - */ - public void addRect(float left, float top, float right, float bottom, - Direction dir) { - moveTo(left, top); - - switch (dir) { - case CW: - lineTo(right, top); - lineTo(right, bottom); - lineTo(left, bottom); - break; - case CCW: - lineTo(left, bottom); - lineTo(right, bottom); - lineTo(right, top); - break; - } - - close(); - } - - /** - * Add a closed oval contour to the path - * - * @param oval The bounds of the oval to add as a closed contour to the path - * @param dir The direction to wind the oval's contour - */ - public void addOval(RectF oval, Direction dir) { - if (oval == null) { - throw new NullPointerException("need oval parameter"); - } - - // FIXME Need to support direction - Ellipse2D ovalShape = new Ellipse2D.Float(oval.left, oval.top, oval.width(), oval.height()); - - mPath.append(ovalShape, false /* connect */); - } - - /** - * Add a closed circle contour to the path - * - * @param x The x-coordinate of the center of a circle to add to the path - * @param y The y-coordinate of the center of a circle to add to the path - * @param radius The radius of a circle to add to the path - * @param dir The direction to wind the circle's contour - */ - public void addCircle(float x, float y, float radius, Direction dir) { - // FIXME - throw new UnsupportedOperationException(); - } - - /** - * Add the specified arc to the path as a new contour. - * - * @param oval The bounds of oval defining the shape and size of the arc - * @param startAngle Starting angle (in degrees) where the arc begins - * @param sweepAngle Sweep angle (in degrees) measured clockwise - */ - public void addArc(RectF oval, float startAngle, float sweepAngle) { - if (oval == null) { - throw new NullPointerException("need oval parameter"); - } - // FIXME - throw new UnsupportedOperationException(); - } - - /** - * Add a closed round-rectangle contour to the path - * - * @param rect The bounds of a round-rectangle to add to the path - * @param rx The x-radius of the rounded corners on the round-rectangle - * @param ry The y-radius of the rounded corners on the round-rectangle - * @param dir The direction to wind the round-rectangle's contour - */ - public void addRoundRect(RectF rect, float rx, float ry, Direction dir) { - if (rect == null) { - throw new NullPointerException("need rect parameter"); - } - // FIXME - throw new UnsupportedOperationException(); - } - - /** - * Add a closed round-rectangle contour to the path. Each corner receives - * two radius values [X, Y]. The corners are ordered top-left, top-right, - * bottom-right, bottom-left - * - * @param rect The bounds of a round-rectangle to add to the path - * @param radii Array of 8 values, 4 pairs of [X,Y] radii - * @param dir The direction to wind the round-rectangle's contour - */ - public void addRoundRect(RectF rect, float[] radii, Direction dir) { - if (rect == null) { - throw new NullPointerException("need rect parameter"); - } - if (radii.length < 8) { - throw new ArrayIndexOutOfBoundsException("radii[] needs 8 values"); - } - // FIXME - throw new UnsupportedOperationException(); - } - - /** - * Add a copy of src to the path, offset by (dx,dy) - * - * @param src The path to add as a new contour - * @param dx The amount to translate the path in X as it is added - */ - public void addPath(Path src, float dx, float dy) { - PathIterator iterator = src.mPath.getPathIterator(new AffineTransform(0, 0, dx, 0, 0, dy)); - mPath.append(iterator, false /* connect */); - } - - /** - * Add a copy of src to the path - * - * @param src The path that is appended to the current path - */ - public void addPath(Path src) { - addPath(src, 0, 0); - } - - /** - * Add a copy of src to the path, transformed by matrix - * - * @param src The path to add as a new contour - */ - public void addPath(Path src, Matrix matrix) { - // FIXME - throw new UnsupportedOperationException(); - } - - /** - * Offset the path by (dx,dy), returning true on success - * - * @param dx The amount in the X direction to offset the entire path - * @param dy The amount in the Y direction to offset the entire path - * @param dst The translated path is written here. If this is null, then - * the original path is modified. - */ - public void offset(float dx, float dy, Path dst) { - GeneralPath newPath = new GeneralPath(); - - PathIterator iterator = mPath.getPathIterator(new AffineTransform(0, 0, dx, 0, 0, dy)); - - newPath.append(iterator, false /* connect */); - - if (dst != null) { - dst.mPath = newPath; - } else { - mPath = newPath; - } - } - - /** - * Offset the path by (dx,dy), returning true on success - * - * @param dx The amount in the X direction to offset the entire path - * @param dy The amount in the Y direction to offset the entire path - */ - public void offset(float dx, float dy) { - offset(dx, dy, null /* dst */); - } - - /** - * Sets the last point of the path. - * - * @param dx The new X coordinate for the last point - * @param dy The new Y coordinate for the last point - */ - public void setLastPoint(float dx, float dy) { - mLastX = dx; - mLastY = dy; - } - - /** - * Transform the points in this path by matrix, and write the answer - * into dst. If dst is null, then the the original path is modified. - * - * @param matrix The matrix to apply to the path - * @param dst The transformed path is written here. If dst is null, - * then the the original path is modified - */ - public void transform(Matrix matrix, Path dst) { - // FIXME - throw new UnsupportedOperationException(); - } - - /** - * Transform the points in this path by matrix. - * - * @param matrix The matrix to apply to the path - */ - public void transform(Matrix matrix) { - transform(matrix, null /* dst */); - } -} diff --git a/tools/layoutlib/bridge/src/android/graphics/PathDashPathEffect_Delegate.java b/tools/layoutlib/bridge/src/android/graphics/PathDashPathEffect_Delegate.java new file mode 100644 index 000000000000..3777ac9b9c69 --- /dev/null +++ b/tools/layoutlib/bridge/src/android/graphics/PathDashPathEffect_Delegate.java @@ -0,0 +1,70 @@ +/* + * Copyright (C) 2010 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 android.graphics; + +import com.android.layoutlib.bridge.impl.DelegateManager; + +import java.awt.Stroke; + +/** + * Delegate implementing the native methods of android.graphics.PathDashPathEffect + * + * Through the layoutlib_create tool, the original native methods of PathDashPathEffect have been + * replaced by calls to methods of the same name in this delegate class. + * + * This class behaves like the original native implementation, but in Java, keeping previously + * native data into its own objects and mapping them to int that are sent back and forth between + * it and the original PathDashPathEffect class. + * + * Because this extends {@link Shader_Delegate}, there's no need to use a {@link DelegateManager}, + * as all the Shader classes will be added to the manager owned by {@link Shader_Delegate}. + * + * @see Shader_Delegate + * + */ +public class PathDashPathEffect_Delegate extends PathEffect_Delegate { + + // ---- delegate data ---- + + // ---- Public Helper methods ---- + + @Override + public Stroke getStroke(Paint_Delegate paint) { + // FIXME + return null; + } + + @Override + public boolean isSupported() { + return false; + } + + @Override + public String getSupportMessage() { + return "Path Dash Path Effects are not supported in Layout Preview mode."; + } + + // ---- native methods ---- + + /*package*/ static int nativeCreate(int native_path, float advance, float phase, + int native_style) { + PathDashPathEffect_Delegate newDelegate = new PathDashPathEffect_Delegate(); + return sManager.addDelegate(newDelegate); + } + + // ---- Private delegate/helper methods ---- +} diff --git a/tools/layoutlib/bridge/src/android/graphics/PathEffect_Delegate.java b/tools/layoutlib/bridge/src/android/graphics/PathEffect_Delegate.java index ce7eef07a6eb..c5884236d67e 100644 --- a/tools/layoutlib/bridge/src/android/graphics/PathEffect_Delegate.java +++ b/tools/layoutlib/bridge/src/android/graphics/PathEffect_Delegate.java @@ -18,6 +18,8 @@ package android.graphics; import com.android.layoutlib.bridge.impl.DelegateManager; +import java.awt.Stroke; + /** * Delegate implementing the native methods of android.graphics.PathEffect * @@ -33,7 +35,7 @@ import com.android.layoutlib.bridge.impl.DelegateManager; * @see DelegateManager * */ -public class PathEffect_Delegate { +public abstract class PathEffect_Delegate { // ---- delegate manager ---- protected static final DelegateManager<PathEffect_Delegate> sManager = @@ -49,6 +51,11 @@ public class PathEffect_Delegate { return sManager.getDelegate(nativeShader); } + public abstract Stroke getStroke(Paint_Delegate paint); + public abstract boolean isSupported(); + public abstract String getSupportMessage(); + + // ---- native methods ---- /*package*/ static void nativeDestructor(int native_patheffect) { diff --git a/tools/layoutlib/bridge/src/android/graphics/Path_Delegate.java b/tools/layoutlib/bridge/src/android/graphics/Path_Delegate.java new file mode 100644 index 000000000000..811f0f6f41c9 --- /dev/null +++ b/tools/layoutlib/bridge/src/android/graphics/Path_Delegate.java @@ -0,0 +1,748 @@ +/* + * Copyright (C) 2010 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 android.graphics; + +import com.android.layoutlib.bridge.Bridge; +import com.android.layoutlib.bridge.impl.DelegateManager; + +import android.graphics.Path.Direction; +import android.graphics.Path.FillType; + +import java.awt.Shape; +import java.awt.geom.AffineTransform; +import java.awt.geom.Arc2D; +import java.awt.geom.Area; +import java.awt.geom.GeneralPath; +import java.awt.geom.PathIterator; +import java.awt.geom.Point2D; +import java.awt.geom.Rectangle2D; + +/** + * Delegate implementing the native methods of android.graphics.Path + * + * Through the layoutlib_create tool, the original native methods of Path have been replaced + * by calls to methods of the same name in this delegate class. + * + * This class behaves like the original native implementation, but in Java, keeping previously + * native data into its own objects and mapping them to int that are sent back and forth between + * it and the original Path class. + * + * @see DelegateManager + * + */ +public final class Path_Delegate { + + // ---- delegate manager ---- + private static final DelegateManager<Path_Delegate> sManager = + new DelegateManager<Path_Delegate>(); + + // ---- delegate data ---- + private FillType mFillType = FillType.WINDING; + private GeneralPath mPath = new GeneralPath(); + + private float mLastX = 0; + private float mLastY = 0; + + // ---- Public Helper methods ---- + + public static Path_Delegate getDelegate(int nPath) { + return sManager.getDelegate(nPath); + } + + public Shape getJavaShape() { + return mPath; + } + + // ---- native methods ---- + + /*package*/ static int init1() { + // create the delegate + Path_Delegate newDelegate = new Path_Delegate(); + + return sManager.addDelegate(newDelegate); + } + + /*package*/ static int init2(int nPath) { + // create the delegate + Path_Delegate newDelegate = new Path_Delegate(); + + // get the delegate to copy + if (nPath > 0) { + Path_Delegate pathDelegate = sManager.getDelegate(nPath); + if (pathDelegate == null) { + assert false; + return 0; + } + + newDelegate.set(pathDelegate); + } + + return sManager.addDelegate(newDelegate); + } + + /*package*/ static void native_reset(int nPath) { + Path_Delegate pathDelegate = sManager.getDelegate(nPath); + if (pathDelegate == null) { + assert false; + return; + } + + pathDelegate.mPath.reset(); + } + + /*package*/ static void native_rewind(int nPath) { + // call out to reset since there's nothing to optimize in + // terms of data structs. + native_reset(nPath); + } + + /*package*/ static void native_set(int native_dst, int native_src) { + Path_Delegate pathDstDelegate = sManager.getDelegate(native_dst); + if (pathDstDelegate == null) { + assert false; + return; + } + + Path_Delegate pathSrcDelegate = sManager.getDelegate(native_src); + if (pathSrcDelegate == null) { + assert false; + return; + } + + pathDstDelegate.set(pathSrcDelegate); + } + + /*package*/ static int native_getFillType(int nPath) { + Path_Delegate pathDelegate = sManager.getDelegate(nPath); + if (pathDelegate == null) { + assert false; + return 0; + } + + return pathDelegate.mFillType.nativeInt; + } + + /*package*/ static void native_setFillType(int nPath, int ft) { + Path_Delegate pathDelegate = sManager.getDelegate(nPath); + if (pathDelegate == null) { + assert false; + return; + } + + pathDelegate.mFillType = Path.sFillTypeArray[ft]; + } + + /*package*/ static boolean native_isEmpty(int nPath) { + Path_Delegate pathDelegate = sManager.getDelegate(nPath); + if (pathDelegate == null) { + assert false; + return true; + } + + return pathDelegate.isEmpty(); + } + + /*package*/ static boolean native_isRect(int nPath, RectF rect) { + Path_Delegate pathDelegate = sManager.getDelegate(nPath); + if (pathDelegate == null) { + assert false; + return false; + } + + // create an Area that can test if the path is a rect + Area area = new Area(pathDelegate.mPath); + if (area.isRectangular()) { + if (rect != null) { + pathDelegate.fillBounds(rect); + } + + return true; + } + + return false; + } + + /*package*/ static void native_computeBounds(int nPath, RectF bounds) { + Path_Delegate pathDelegate = sManager.getDelegate(nPath); + if (pathDelegate == null) { + assert false; + return; + } + + pathDelegate.fillBounds(bounds); + } + + /*package*/ static void native_incReserve(int nPath, int extraPtCount) { + // since we use a java2D path, there's no way to pre-allocate new points, + // so we do nothing. + } + + /*package*/ static void native_moveTo(int nPath, float x, float y) { + Path_Delegate pathDelegate = sManager.getDelegate(nPath); + if (pathDelegate == null) { + assert false; + return; + } + + pathDelegate.moveTo(x, y); + } + + /*package*/ static void native_rMoveTo(int nPath, float dx, float dy) { + Path_Delegate pathDelegate = sManager.getDelegate(nPath); + if (pathDelegate == null) { + assert false; + return; + } + + pathDelegate.rMoveTo(dx, dy); + } + + /*package*/ static void native_lineTo(int nPath, float x, float y) { + Path_Delegate pathDelegate = sManager.getDelegate(nPath); + if (pathDelegate == null) { + assert false; + return; + } + + pathDelegate.lineTo(x, y); + } + + /*package*/ static void native_rLineTo(int nPath, float dx, float dy) { + Path_Delegate pathDelegate = sManager.getDelegate(nPath); + if (pathDelegate == null) { + assert false; + return; + } + + pathDelegate.rLineTo(dx, dy); + } + + /*package*/ static void native_quadTo(int nPath, float x1, float y1, float x2, float y2) { + Path_Delegate pathDelegate = sManager.getDelegate(nPath); + if (pathDelegate == null) { + assert false; + return; + } + + pathDelegate.quadTo(x1, y1, x2, y2); + } + + /*package*/ static void native_rQuadTo(int nPath, float dx1, float dy1, + float dx2, float dy2) { + Path_Delegate pathDelegate = sManager.getDelegate(nPath); + if (pathDelegate == null) { + assert false; + return; + } + + pathDelegate.rQuadTo(dx1, dy1, dx2, dy2); + } + + /*package*/ static void native_cubicTo(int nPath, float x1, float y1, + float x2, float y2, float x3, float y3) { + Path_Delegate pathDelegate = sManager.getDelegate(nPath); + if (pathDelegate == null) { + assert false; + return; + } + + pathDelegate.cubicTo(x1, y1, x2, y2, x3, y3); + } + + /*package*/ static void native_rCubicTo(int nPath, float x1, float y1, + float x2, float y2, float x3, float y3) { + Path_Delegate pathDelegate = sManager.getDelegate(nPath); + if (pathDelegate == null) { + assert false; + return; + } + + pathDelegate.rCubicTo(x1, y1, x2, y2, x3, y3); + } + + /*package*/ static void native_arcTo(int nPath, RectF oval, + float startAngle, float sweepAngle, boolean forceMoveTo) { + Path_Delegate pathDelegate = sManager.getDelegate(nPath); + if (pathDelegate == null) { + assert false; + return; + } + + pathDelegate.arcTo(oval, startAngle, sweepAngle, forceMoveTo); + } + + /*package*/ static void native_close(int nPath) { + Path_Delegate pathDelegate = sManager.getDelegate(nPath); + if (pathDelegate == null) { + assert false; + return; + } + + pathDelegate.close(); + } + + /*package*/ static void native_addRect(int nPath, RectF rect, int dir) { + Path_Delegate pathDelegate = sManager.getDelegate(nPath); + if (pathDelegate == null) { + assert false; + return; + } + + pathDelegate.addRect(rect.left, rect.top, rect.right, rect.bottom, dir); + } + + /*package*/ static void native_addRect(int nPath, float left, float top, + float right, float bottom, int dir) { + Path_Delegate pathDelegate = sManager.getDelegate(nPath); + if (pathDelegate == null) { + assert false; + return; + } + + pathDelegate.addRect(left, top, right, bottom, dir); + } + + /*package*/ static void native_addOval(int nPath, RectF oval, int dir) { + // FIXME + throw new UnsupportedOperationException(); + } + + /*package*/ static void native_addCircle(int nPath, float x, float y, + float radius, int dir) { + // FIXME + throw new UnsupportedOperationException(); + } + + /*package*/ static void native_addArc(int nPath, RectF oval, + float startAngle, float sweepAngle) { + // FIXME + throw new UnsupportedOperationException(); + } + + /*package*/ static void native_addRoundRect(int nPath, RectF rect, + float rx, float ry, int dir) { + // FIXME + throw new UnsupportedOperationException(); + } + + /*package*/ static void native_addRoundRect(int nPath, RectF r, + float[] radii, int dir) { + // FIXME + throw new UnsupportedOperationException(); + } + + /*package*/ static void native_addPath(int nPath, int src, float dx, + float dy) { + // FIXME + throw new UnsupportedOperationException(); + } + + /*package*/ static void native_addPath(int nPath, int src) { + // FIXME + throw new UnsupportedOperationException(); + } + + /*package*/ static void native_addPath(int nPath, int src, int matrix) { + // FIXME + throw new UnsupportedOperationException(); + } + + /*package*/ static void native_offset(int nPath, float dx, float dy, + int dst_path) { + Path_Delegate pathDelegate = sManager.getDelegate(nPath); + if (pathDelegate == null) { + assert false; + return; + } + + Path_Delegate dstDelegate = null; + if (dst_path > 0) { + dstDelegate = sManager.getDelegate(dst_path); + if (dstDelegate == null) { + assert false; + return; + } + } + + pathDelegate.offset(dx, dy, dstDelegate); + } + + /*package*/ static void native_offset(int nPath, float dx, float dy) { + native_offset(nPath, dx, dy, 0); + } + + /*package*/ static void native_setLastPoint(int nPath, float dx, float dy) { + Path_Delegate pathDelegate = sManager.getDelegate(nPath); + if (pathDelegate == null) { + assert false; + return; + } + + pathDelegate.mLastX = dx; + pathDelegate.mLastY = dy; + } + + /*package*/ static void native_transform(int nPath, int matrix, + int dst_path) { + Path_Delegate pathDelegate = sManager.getDelegate(nPath); + if (pathDelegate == null) { + assert false; + return; + } + + Matrix_Delegate matrixDelegate = Matrix_Delegate.getDelegate(matrix); + if (matrixDelegate == null) { + assert false; + return; + } + + Path_Delegate dstDelegate = null; + if (dst_path > 0) { + dstDelegate = sManager.getDelegate(dst_path); + if (dstDelegate == null) { + assert false; + return; + } + } + + pathDelegate.transform(matrixDelegate, dstDelegate); + } + + /*package*/ static void native_transform(int nPath, int matrix) { + native_transform(nPath, matrix, 0); + } + + /*package*/ static void finalizer(int nPath) { + sManager.removeDelegate(nPath); + } + + + // ---- Private helper methods ---- + + private void set(Path_Delegate delegate) { + mPath.reset(); + setFillType(delegate.mFillType); + mPath.append(delegate.mPath, false /*connect*/); + } + + private void setFillType(FillType fillType) { + mFillType = fillType; + mPath.setWindingRule(getWindingRule(fillType)); + } + + /** + * Returns the Java2D winding rules matching a given Android {@link FillType}. + * @param type the android fill type + * @return the matching java2d winding rule. + */ + private static int getWindingRule(FillType type) { + switch (type) { + case WINDING: + case INVERSE_WINDING: + return GeneralPath.WIND_NON_ZERO; + case EVEN_ODD: + case INVERSE_EVEN_ODD: + return GeneralPath.WIND_EVEN_ODD; + } + + assert false; + throw new IllegalArgumentException(); + } + + private static Direction getDirection(int direction) { + for (Direction d : Direction.values()) { + if (direction == d.nativeInt) { + return d; + } + } + + assert false; + return null; + } + + /** + * Returns whether the path is empty. + * @return true if the path is empty. + */ + private boolean isEmpty() { + return mPath.getCurrentPoint() == null; + } + + /** + * Fills the given {@link RectF} with the path bounds. + * @param bounds the RectF to be filled. + */ + private void fillBounds(RectF bounds) { + Rectangle2D rect = mPath.getBounds2D(); + bounds.left = (float)rect.getMinX(); + bounds.right = (float)rect.getMaxX(); + bounds.top = (float)rect.getMinY(); + bounds.bottom = (float)rect.getMaxY(); + } + + /** + * Set the beginning of the next contour to the point (x,y). + * + * @param x The x-coordinate of the start of a new contour + * @param y The y-coordinate of the start of a new contour + */ + private void moveTo(float x, float y) { + mPath.moveTo(mLastX = x, mLastY = y); + } + + /** + * Set the beginning of the next contour relative to the last point on the + * previous contour. If there is no previous contour, this is treated the + * same as moveTo(). + * + * @param dx The amount to add to the x-coordinate of the end of the + * previous contour, to specify the start of a new contour + * @param dy The amount to add to the y-coordinate of the end of the + * previous contour, to specify the start of a new contour + */ + private void rMoveTo(float dx, float dy) { + dx += mLastX; + dy += mLastY; + mPath.moveTo(mLastX = dx, mLastY = dy); + } + + /** + * Add a line from the last point to the specified point (x,y). + * If no moveTo() call has been made for this contour, the first point is + * automatically set to (0,0). + * + * @param x The x-coordinate of the end of a line + * @param y The y-coordinate of the end of a line + */ + private void lineTo(float x, float y) { + mPath.lineTo(mLastX = x, mLastY = y); + } + + /** + * Same as lineTo, but the coordinates are considered relative to the last + * point on this contour. If there is no previous point, then a moveTo(0,0) + * is inserted automatically. + * + * @param dx The amount to add to the x-coordinate of the previous point on + * this contour, to specify a line + * @param dy The amount to add to the y-coordinate of the previous point on + * this contour, to specify a line + */ + private void rLineTo(float dx, float dy) { + if (isEmpty()) { + mPath.moveTo(mLastX = 0, mLastY = 0); + } + dx += mLastX; + dy += mLastY; + mPath.lineTo(mLastX = dx, mLastY = dy); + } + + /** + * Add a quadratic bezier from the last point, approaching control point + * (x1,y1), and ending at (x2,y2). If no moveTo() call has been made for + * this contour, the first point is automatically set to (0,0). + * + * @param x1 The x-coordinate of the control point on a quadratic curve + * @param y1 The y-coordinate of the control point on a quadratic curve + * @param x2 The x-coordinate of the end point on a quadratic curve + * @param y2 The y-coordinate of the end point on a quadratic curve + */ + private void quadTo(float x1, float y1, float x2, float y2) { + mPath.quadTo(x1, y1, mLastX = x2, mLastY = y2); + } + + /** + * Same as quadTo, but the coordinates are considered relative to the last + * point on this contour. If there is no previous point, then a moveTo(0,0) + * is inserted automatically. + * + * @param dx1 The amount to add to the x-coordinate of the last point on + * this contour, for the control point of a quadratic curve + * @param dy1 The amount to add to the y-coordinate of the last point on + * this contour, for the control point of a quadratic curve + * @param dx2 The amount to add to the x-coordinate of the last point on + * this contour, for the end point of a quadratic curve + * @param dy2 The amount to add to the y-coordinate of the last point on + * this contour, for the end point of a quadratic curve + */ + private void rQuadTo(float dx1, float dy1, float dx2, float dy2) { + if (isEmpty()) { + mPath.moveTo(mLastX = 0, mLastY = 0); + } + dx1 += mLastX; + dy1 += mLastY; + dx2 += mLastX; + dy2 += mLastY; + mPath.quadTo(dx1, dy1, mLastX = dx2, mLastY = dy2); + } + + /** + * Add a cubic bezier from the last point, approaching control points + * (x1,y1) and (x2,y2), and ending at (x3,y3). If no moveTo() call has been + * made for this contour, the first point is automatically set to (0,0). + * + * @param x1 The x-coordinate of the 1st control point on a cubic curve + * @param y1 The y-coordinate of the 1st control point on a cubic curve + * @param x2 The x-coordinate of the 2nd control point on a cubic curve + * @param y2 The y-coordinate of the 2nd control point on a cubic curve + * @param x3 The x-coordinate of the end point on a cubic curve + * @param y3 The y-coordinate of the end point on a cubic curve + */ + private void cubicTo(float x1, float y1, float x2, float y2, + float x3, float y3) { + mPath.curveTo(x1, y1, x2, y2, mLastX = x3, mLastY = y3); + } + + /** + * Same as cubicTo, but the coordinates are considered relative to the + * current point on this contour. If there is no previous point, then a + * moveTo(0,0) is inserted automatically. + */ + private void rCubicTo(float dx1, float dy1, float dx2, float dy2, + float dx3, float dy3) { + if (isEmpty()) { + mPath.moveTo(mLastX = 0, mLastY = 0); + } + dx1 += mLastX; + dy1 += mLastY; + dx2 += mLastX; + dy2 += mLastY; + dx3 += mLastX; + dy3 += mLastY; + mPath.curveTo(dx1, dy1, dx2, dy2, mLastX = dx3, mLastY = dy3); + } + + /** + * Append the specified arc to the path as a new contour. If the start of + * the path is different from the path's current last point, then an + * automatic lineTo() is added to connect the current contour to the + * start of the arc. However, if the path is empty, then we call moveTo() + * with the first point of the arc. The sweep angle is tread mod 360. + * + * @param oval The bounds of oval defining shape and size of the arc + * @param startAngle Starting angle (in degrees) where the arc begins + * @param sweepAngle Sweep angle (in degrees) measured clockwise, treated + * mod 360. + * @param forceMoveTo If true, always begin a new contour with the arc + */ + private void arcTo(RectF oval, float startAngle, float sweepAngle, + boolean forceMoveTo) { + Arc2D arc = new Arc2D.Float(oval.left, oval.top, oval.width(), oval.height(), startAngle, + sweepAngle, Arc2D.OPEN); + mPath.append(arc, true /*connect*/); + + resetLastPointFromPath(); + } + + /** + * Close the current contour. If the current point is not equal to the + * first point of the contour, a line segment is automatically added. + */ + private void close() { + mPath.closePath(); + } + + private void resetLastPointFromPath() { + Point2D last = mPath.getCurrentPoint(); + mLastX = (float) last.getX(); + mLastY = (float) last.getY(); + } + + /** + * Add a closed rectangle contour to the path + * + * @param left The left side of a rectangle to add to the path + * @param top The top of a rectangle to add to the path + * @param right The right side of a rectangle to add to the path + * @param bottom The bottom of a rectangle to add to the path + * @param dir The direction to wind the rectangle's contour + */ + private void addRect(float left, float top, float right, float bottom, + int dir) { + moveTo(left, top); + + Direction direction = getDirection(dir); + + switch (direction) { + case CW: + lineTo(right, top); + lineTo(right, bottom); + lineTo(left, bottom); + break; + case CCW: + lineTo(left, bottom); + lineTo(right, bottom); + lineTo(right, top); + break; + } + + close(); + + resetLastPointFromPath(); + } + + /** + * Offset the path by (dx,dy), returning true on success + * + * @param dx The amount in the X direction to offset the entire path + * @param dy The amount in the Y direction to offset the entire path + * @param dst The translated path is written here. If this is null, then + * the original path is modified. + */ + public void offset(float dx, float dy, Path_Delegate dst) { + GeneralPath newPath = new GeneralPath(); + + PathIterator iterator = mPath.getPathIterator(new AffineTransform(0, 0, dx, 0, 0, dy)); + + newPath.append(iterator, false /*connect*/); + + if (dst != null) { + dst.mPath = newPath; + } else { + mPath = newPath; + } + } + + /** + * Transform the points in this path by matrix, and write the answer + * into dst. If dst is null, then the the original path is modified. + * + * @param matrix The matrix to apply to the path + * @param dst The transformed path is written here. If dst is null, + * then the the original path is modified + */ + public void transform(Matrix_Delegate matrix, Path_Delegate dst) { + if (matrix.hasPerspective()) { + assert false; + Bridge.getLog().fidelityWarning(null, + "android.graphics.Path#transform() only " + + "supports affine transformations in the Layout Preview.", null); + } + + GeneralPath newPath = new GeneralPath(); + + PathIterator iterator = mPath.getPathIterator(matrix.getAffineTransform()); + + newPath.append(iterator, false /*connect*/); + + if (dst != null) { + dst.mPath = newPath; + } else { + mPath = newPath; + } + } +} diff --git a/tools/layoutlib/bridge/src/android/graphics/PixelXorXfermode_Delegate.java b/tools/layoutlib/bridge/src/android/graphics/PixelXorXfermode_Delegate.java new file mode 100644 index 000000000000..e8f29ad581fd --- /dev/null +++ b/tools/layoutlib/bridge/src/android/graphics/PixelXorXfermode_Delegate.java @@ -0,0 +1,68 @@ +/* + * Copyright (C) 2010 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 android.graphics; + +import com.android.layoutlib.bridge.impl.DelegateManager; + +import java.awt.Composite; + +/** + * Delegate implementing the native methods of android.graphics.PixelXorXfermode + * + * Through the layoutlib_create tool, the original native methods of PixelXorXfermode have been + * replaced by calls to methods of the same name in this delegate class. + * + * This class behaves like the original native implementation, but in Java, keeping previously + * native data into its own objects and mapping them to int that are sent back and forth between + * it and the original PixelXorXfermode class. + * + * Because this extends {@link Xfermode_Delegate}, there's no need to use a + * {@link DelegateManager}, as all the PathEffect classes will be added to the manager owned by + * {@link Xfermode_Delegate}. + * + * @see Xfermode_Delegate + */ +public class PixelXorXfermode_Delegate extends Xfermode_Delegate { + // ---- delegate data ---- + + // ---- Public Helper methods ---- + + @Override + public Composite getComposite() { + // FIXME + return null; + } + + @Override + public boolean isSupported() { + return false; + } + + @Override + public String getSupportMessage() { + return "Pixel XOR Xfermodes are not supported in Layout Preview mode."; + } + + // ---- native methods ---- + + /*package*/ static int nativeCreate(int opColor) { + PixelXorXfermode_Delegate newDelegate = new PixelXorXfermode_Delegate(); + return sManager.addDelegate(newDelegate); + } + + // ---- Private delegate/helper methods ---- +} diff --git a/tools/layoutlib/bridge/src/android/graphics/PorterDuffXfermode_Delegate.java b/tools/layoutlib/bridge/src/android/graphics/PorterDuffXfermode_Delegate.java index a5885ea3e1cd..3e9a346bcba1 100644 --- a/tools/layoutlib/bridge/src/android/graphics/PorterDuffXfermode_Delegate.java +++ b/tools/layoutlib/bridge/src/android/graphics/PorterDuffXfermode_Delegate.java @@ -16,8 +16,12 @@ package android.graphics; +import com.android.layoutlib.bridge.Bridge; import com.android.layoutlib.bridge.impl.DelegateManager; +import java.awt.AlphaComposite; +import java.awt.Composite; + /** * Delegate implementing the native methods of android.graphics.PorterDuffXfermode * @@ -41,8 +45,64 @@ public class PorterDuffXfermode_Delegate extends Xfermode_Delegate { // ---- Public Helper methods ---- - public int getMode() { - return mMode; + @Override + public Composite getComposite() { + return getComposite(mMode); + } + + @Override + public boolean isSupported() { + return true; + } + + @Override + public String getSupportMessage() { + // no message since isSupported returns true; + return null; + } + + public static Composite getComposite(int mode) { + PorterDuff.Mode m = getMode(mode); + switch (m) { + case CLEAR: + return AlphaComposite.getInstance(AlphaComposite.CLEAR, 1.0f /*alpha*/); + case DARKEN: + break; + case DST: + return AlphaComposite.getInstance(AlphaComposite.DST, 1.0f /*alpha*/); + case DST_ATOP: + return AlphaComposite.getInstance(AlphaComposite.DST_ATOP, 1.0f /*alpha*/); + case DST_IN: + return AlphaComposite.getInstance(AlphaComposite.DST_IN, 1.0f /*alpha*/); + case DST_OUT: + return AlphaComposite.getInstance(AlphaComposite.DST_OUT, 1.0f /*alpha*/); + case DST_OVER: + return AlphaComposite.getInstance(AlphaComposite.DST_OVER, 1.0f /*alpha*/); + case LIGHTEN: + break; + case MULTIPLY: + break; + case SCREEN: + break; + case SRC: + return AlphaComposite.getInstance(AlphaComposite.SRC, 1.0f /*alpha*/); + case SRC_ATOP: + return AlphaComposite.getInstance(AlphaComposite.SRC_ATOP, 1.0f /*alpha*/); + case SRC_IN: + return AlphaComposite.getInstance(AlphaComposite.SRC_IN, 1.0f /*alpha*/); + case SRC_OUT: + return AlphaComposite.getInstance(AlphaComposite.SRC_OUT, 1.0f /*alpha*/); + case SRC_OVER: + return AlphaComposite.getInstance(AlphaComposite.SRC_OVER, 1.0f /*alpha*/); + case XOR: + return AlphaComposite.getInstance(AlphaComposite.XOR, 1.0f /*alpha*/); + } + + Bridge.getLog().fidelityWarning(null, + String.format("Unsupported PorterDuff Mode: %s", m.name()), + null); + + return AlphaComposite.getInstance(AlphaComposite.SRC_OVER); } // ---- native methods ---- @@ -58,4 +118,15 @@ public class PorterDuffXfermode_Delegate extends Xfermode_Delegate { mMode = mode; } + private static PorterDuff.Mode getMode(int mode) { + for (PorterDuff.Mode m : PorterDuff.Mode.values()) { + if (m.nativeInt == mode) { + return m; + } + } + + Bridge.getLog().error(null, String.format("Unknown PorterDuff.Mode: %d", mode)); + assert false; + return PorterDuff.Mode.SRC_OVER; + } } diff --git a/tools/layoutlib/bridge/src/android/graphics/RadialGradient_Delegate.java b/tools/layoutlib/bridge/src/android/graphics/RadialGradient_Delegate.java index eebf378060b6..1f6f4b43bf3c 100644 --- a/tools/layoutlib/bridge/src/android/graphics/RadialGradient_Delegate.java +++ b/tools/layoutlib/bridge/src/android/graphics/RadialGradient_Delegate.java @@ -21,10 +21,6 @@ import com.android.layoutlib.bridge.impl.DelegateManager; import android.graphics.Shader.TileMode; -import java.awt.Paint; -import java.awt.geom.AffineTransform; -import java.awt.geom.NoninvertibleTransformException; - /** * Delegate implementing the native methods of android.graphics.RadialGradient * @@ -49,7 +45,7 @@ public class RadialGradient_Delegate extends Gradient_Delegate { // ---- Public Helper methods ---- @Override - public Paint getJavaPaint() { + public java.awt.Paint getJavaPaint() { return mJavaPaint; } @@ -57,17 +53,8 @@ public class RadialGradient_Delegate extends Gradient_Delegate { /*package*/ static int nativeCreate1(float x, float y, float radius, int colors[], float positions[], int tileMode) { - // figure out the tile - TileMode tile = null; - for (TileMode tm : TileMode.values()) { - if (tm.nativeInt == tileMode) { - tile = tm; - break; - } - } - RadialGradient_Delegate newDelegate = new RadialGradient_Delegate(x, y, radius, - colors, positions, tile); + colors, positions, Shader_Delegate.getTileMode(tileMode)); return sManager.addDelegate(newDelegate); } @@ -133,20 +120,20 @@ public class RadialGradient_Delegate extends Gradient_Delegate { java.awt.RenderingHints hints) { precomputeGradientColors(); - AffineTransform canvasMatrix; + java.awt.geom.AffineTransform canvasMatrix; try { canvasMatrix = xform.createInverse(); - } catch (NoninvertibleTransformException e) { + } catch (java.awt.geom.NoninvertibleTransformException e) { Bridge.getLog().error(null, "Unable to inverse matrix in RadialGradient", e); - canvasMatrix = new AffineTransform(); + canvasMatrix = new java.awt.geom.AffineTransform(); } - AffineTransform localMatrix = getLocalMatrix(); + java.awt.geom.AffineTransform localMatrix = getLocalMatrix(); try { localMatrix = localMatrix.createInverse(); - } catch (NoninvertibleTransformException e) { + } catch (java.awt.geom.NoninvertibleTransformException e) { Bridge.getLog().error(null, "Unable to inverse matrix in RadialGradient", e); - localMatrix = new AffineTransform(); + localMatrix = new java.awt.geom.AffineTransform(); } return new RadialGradientPaintContext(canvasMatrix, localMatrix, colorModel); @@ -154,12 +141,14 @@ public class RadialGradient_Delegate extends Gradient_Delegate { private class RadialGradientPaintContext implements java.awt.PaintContext { - private final AffineTransform mCanvasMatrix; - private final AffineTransform mLocalMatrix; + private final java.awt.geom.AffineTransform mCanvasMatrix; + private final java.awt.geom.AffineTransform mLocalMatrix; private final java.awt.image.ColorModel mColorModel; - public RadialGradientPaintContext(AffineTransform canvasMatrix, - AffineTransform localMatrix, java.awt.image.ColorModel colorModel) { + public RadialGradientPaintContext( + java.awt.geom.AffineTransform canvasMatrix, + java.awt.geom.AffineTransform localMatrix, + java.awt.image.ColorModel colorModel) { mCanvasMatrix = canvasMatrix; mLocalMatrix = localMatrix; mColorModel = colorModel; diff --git a/tools/layoutlib/bridge/src/android/graphics/Shader_Delegate.java b/tools/layoutlib/bridge/src/android/graphics/Shader_Delegate.java index 7bf144314e10..3759b265aeb6 100644 --- a/tools/layoutlib/bridge/src/android/graphics/Shader_Delegate.java +++ b/tools/layoutlib/bridge/src/android/graphics/Shader_Delegate.java @@ -18,7 +18,7 @@ package android.graphics; import com.android.layoutlib.bridge.impl.DelegateManager; -import java.awt.geom.AffineTransform; +import android.graphics.Shader.TileMode; /** * Delegate implementing the native methods of android.graphics.Shader @@ -52,7 +52,25 @@ public abstract class Shader_Delegate { return sManager.getDelegate(nativeShader); } + /** + * Returns the {@link TileMode} matching the given int. + * @param tileMode the tile mode int value + * @return the TileMode enum. + */ + public static TileMode getTileMode(int tileMode) { + for (TileMode tm : TileMode.values()) { + if (tm.nativeInt == tileMode) { + return tm; + } + } + + assert false; + return TileMode.CLAMP; + } + public abstract java.awt.Paint getJavaPaint(); + public abstract boolean isSupported(); + public abstract String getSupportMessage(); // ---- native methods ---- @@ -111,19 +129,19 @@ public abstract class Shader_Delegate { // ---- Private delegate/helper methods ---- - protected AffineTransform getLocalMatrix() { + protected java.awt.geom.AffineTransform getLocalMatrix() { Matrix_Delegate localMatrixDelegate = null; if (mLocalMatrix > 0) { localMatrixDelegate = Matrix_Delegate.getDelegate(mLocalMatrix); if (localMatrixDelegate == null) { assert false; - return new AffineTransform(); + return new java.awt.geom.AffineTransform(); } return localMatrixDelegate.getAffineTransform(); } - return new AffineTransform(); + return new java.awt.geom.AffineTransform(); } } diff --git a/tools/layoutlib/bridge/src/android/graphics/SumPathEffect_Delegate.java b/tools/layoutlib/bridge/src/android/graphics/SumPathEffect_Delegate.java new file mode 100644 index 000000000000..b02f9c586274 --- /dev/null +++ b/tools/layoutlib/bridge/src/android/graphics/SumPathEffect_Delegate.java @@ -0,0 +1,69 @@ +/* + * Copyright (C) 2010 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 android.graphics; + +import com.android.layoutlib.bridge.impl.DelegateManager; + +import java.awt.Stroke; + +/** + * Delegate implementing the native methods of android.graphics.SumPathEffect + * + * Through the layoutlib_create tool, the original native methods of SumPathEffect have been + * replaced by calls to methods of the same name in this delegate class. + * + * This class behaves like the original native implementation, but in Java, keeping previously + * native data into its own objects and mapping them to int that are sent back and forth between + * it and the original SumPathEffect class. + * + * Because this extends {@link Shader_Delegate}, there's no need to use a {@link DelegateManager}, + * as all the Shader classes will be added to the manager owned by {@link Shader_Delegate}. + * + * @see Shader_Delegate + * + */ +public class SumPathEffect_Delegate extends PathEffect_Delegate { + + // ---- delegate data ---- + + // ---- Public Helper methods ---- + + @Override + public Stroke getStroke(Paint_Delegate paint) { + // FIXME + return null; + } + + @Override + public boolean isSupported() { + return false; + } + + @Override + public String getSupportMessage() { + return "Sum Path Effects are not supported in Layout Preview mode."; + } + + // ---- native methods ---- + + /*package*/ static int nativeCreate(int first, int second) { + SumPathEffect_Delegate newDelegate = new SumPathEffect_Delegate(); + return sManager.addDelegate(newDelegate); + } + + // ---- Private delegate/helper methods ---- +} diff --git a/tools/layoutlib/bridge/src/android/graphics/SweepGradient_Delegate.java b/tools/layoutlib/bridge/src/android/graphics/SweepGradient_Delegate.java index 97c3cfd24855..970e78153cd2 100644 --- a/tools/layoutlib/bridge/src/android/graphics/SweepGradient_Delegate.java +++ b/tools/layoutlib/bridge/src/android/graphics/SweepGradient_Delegate.java @@ -19,10 +19,6 @@ package android.graphics; import com.android.layoutlib.bridge.Bridge; import com.android.layoutlib.bridge.impl.DelegateManager; -import java.awt.Paint; -import java.awt.geom.AffineTransform; -import java.awt.geom.NoninvertibleTransformException; - /** * Delegate implementing the native methods of android.graphics.SweepGradient * @@ -47,7 +43,7 @@ public class SweepGradient_Delegate extends Gradient_Delegate { // ---- Public Helper methods ---- @Override - public Paint getJavaPaint() { + public java.awt.Paint getJavaPaint() { return mJavaPaint; } @@ -116,20 +112,20 @@ public class SweepGradient_Delegate extends Gradient_Delegate { java.awt.RenderingHints hints) { precomputeGradientColors(); - AffineTransform canvasMatrix; + java.awt.geom.AffineTransform canvasMatrix; try { canvasMatrix = xform.createInverse(); - } catch (NoninvertibleTransformException e) { + } catch (java.awt.geom.NoninvertibleTransformException e) { Bridge.getLog().error(null, "Unable to inverse matrix in SweepGradient", e); - canvasMatrix = new AffineTransform(); + canvasMatrix = new java.awt.geom.AffineTransform(); } - AffineTransform localMatrix = getLocalMatrix(); + java.awt.geom.AffineTransform localMatrix = getLocalMatrix(); try { localMatrix = localMatrix.createInverse(); - } catch (NoninvertibleTransformException e) { + } catch (java.awt.geom.NoninvertibleTransformException e) { Bridge.getLog().error(null, "Unable to inverse matrix in SweepGradient", e); - localMatrix = new AffineTransform(); + localMatrix = new java.awt.geom.AffineTransform(); } return new SweepGradientPaintContext(canvasMatrix, localMatrix, colorModel); @@ -137,12 +133,14 @@ public class SweepGradient_Delegate extends Gradient_Delegate { private class SweepGradientPaintContext implements java.awt.PaintContext { - private final AffineTransform mCanvasMatrix; - private final AffineTransform mLocalMatrix; + private final java.awt.geom.AffineTransform mCanvasMatrix; + private final java.awt.geom.AffineTransform mLocalMatrix; private final java.awt.image.ColorModel mColorModel; - public SweepGradientPaintContext(AffineTransform canvasMatrix, - AffineTransform localMatrix, java.awt.image.ColorModel colorModel) { + public SweepGradientPaintContext( + java.awt.geom.AffineTransform canvasMatrix, + java.awt.geom.AffineTransform localMatrix, + java.awt.image.ColorModel colorModel) { mCanvasMatrix = canvasMatrix; mLocalMatrix = localMatrix; mColorModel = colorModel; diff --git a/tools/layoutlib/bridge/src/android/graphics/Xfermode_Delegate.java b/tools/layoutlib/bridge/src/android/graphics/Xfermode_Delegate.java index 0c1170dc2118..e783fd112e59 100644 --- a/tools/layoutlib/bridge/src/android/graphics/Xfermode_Delegate.java +++ b/tools/layoutlib/bridge/src/android/graphics/Xfermode_Delegate.java @@ -18,6 +18,8 @@ package android.graphics; import com.android.layoutlib.bridge.impl.DelegateManager; +import java.awt.Composite; + /** * Delegate implementing the native methods of android.graphics.Xfermode * @@ -33,7 +35,7 @@ import com.android.layoutlib.bridge.impl.DelegateManager; * @see DelegateManager * */ -public class Xfermode_Delegate { +public abstract class Xfermode_Delegate { // ---- delegate manager ---- protected static final DelegateManager<Xfermode_Delegate> sManager = @@ -49,6 +51,11 @@ public class Xfermode_Delegate { return sManager.getDelegate(native_instance); } + public abstract Composite getComposite(); + public abstract boolean isSupported(); + public abstract String getSupportMessage(); + + // ---- native methods ---- /*package*/ static void finalizer(int native_instance) { diff --git a/tools/layoutlib/create/src/com/android/tools/layoutlib/create/CreateInfo.java b/tools/layoutlib/create/src/com/android/tools/layoutlib/create/CreateInfo.java index 1d40d3307d68..baa4f0608592 100644 --- a/tools/layoutlib/create/src/com/android/tools/layoutlib/create/CreateInfo.java +++ b/tools/layoutlib/create/src/com/android/tools/layoutlib/create/CreateInfo.java @@ -106,17 +106,27 @@ public final class CreateInfo implements ICreateInfo { */ private final static String[] DELEGATE_CLASS_NATIVES = new String[] { "android.animation.PropertyValuesHolder", + "android.graphics.AvoidXfermode", "android.graphics.Bitmap", + "android.graphics.BitmapShader", "android.graphics.Canvas", + "android.graphics.ComposePathEffect", + "android.graphics.ComposeShader", + "android.graphics.CornerPathEffect", "android.graphics.DashPathEffect", + "android.graphics.DiscretePathEffect", "android.graphics.LinearGradient", "android.graphics.Matrix", "android.graphics.NinePatch", "android.graphics.Paint", + "android.graphics.Path", + "android.graphics.PathDashPathEffect", "android.graphics.PathEffect", + "android.graphics.PixelXorXfermode", "android.graphics.PorterDuffXfermode", "android.graphics.RadialGradient", "android.graphics.Shader", + "android.graphics.SumPathEffect", "android.graphics.SweepGradient", "android.graphics.Typeface", "android.graphics.Xfermode", @@ -140,7 +150,6 @@ public final class CreateInfo implements ICreateInfo { private final static String[] RENAMED_CLASSES = new String[] { "android.graphics.BitmapFactory", "android.graphics._Original_BitmapFactory", - "android.graphics.Path", "android.graphics._Original_Path", "android.os.ServiceManager", "android.os._Original_ServiceManager", "android.view.SurfaceView", "android.view._Original_SurfaceView", "android.view.accessibility.AccessibilityManager", "android.view.accessibility._Original_AccessibilityManager", |