LayoutLib: support for Path and BitmapShader using delegates.
Also created delegates for all missing shader, xfermode
and patheffect classes. Moved the logic of the xfermode,
and patheffects that was in Canvas_Delegate into the
xfermode/patheffect classes, and added support (in all
3 clases) for knowing if the shader/xfermode/patheffect
is actually supported or not. Make use of fidelityWarning
in LayoutLog if they are not.
diff --git a/bridge/src/android/graphics/AvoidXfermode_Delegate.java b/bridge/src/android/graphics/AvoidXfermode_Delegate.java
new file mode 100644
index 0000000..9c49bb8
--- /dev/null
+++ b/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/bridge/src/android/graphics/BitmapShader_Delegate.java b/bridge/src/android/graphics/BitmapShader_Delegate.java
new file mode 100644
index 0000000..b660ae6
--- /dev/null
+++ b/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/bridge/src/android/graphics/Bitmap_Delegate.java b/bridge/src/android/graphics/Bitmap_Delegate.java
index d69abc9..9d60a43 100644
--- a/bridge/src/android/graphics/Bitmap_Delegate.java
+++ b/bridge/src/android/graphics/Bitmap_Delegate.java
@@ -45,7 +45,7 @@
* @see DelegateManager
*
*/
-public class Bitmap_Delegate {
+public final class Bitmap_Delegate {
// ---- delegate manager ----
private static final DelegateManager<Bitmap_Delegate> sManager =
diff --git a/bridge/src/android/graphics/Canvas_Delegate.java b/bridge/src/android/graphics/Canvas_Delegate.java
index c75e1b6..ba4bed6 100644
--- a/bridge/src/android/graphics/Canvas_Delegate.java
+++ b/bridge/src/android/graphics/Canvas_Delegate.java
@@ -23,12 +23,14 @@
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 @@
* @see DelegateManager
*
*/
-public class Canvas_Delegate {
+public final class Canvas_Delegate {
// ---- delegate manager ----
private static final DelegateManager<Canvas_Delegate> sManager =
@@ -55,6 +57,10 @@
// ---- 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 @@
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 @@
// 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 @@
/*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 @@
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 @@
// ---- 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 @@
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 @@
if (style == Paint.Style.STROKE.nativeInt ||
style == Paint.Style.FILL_AND_STROKE.nativeInt) {
- PathEffect_Delegate effectDelegate = PathEffect_Delegate.getDelegate(
- paint.getPathEffect());
+ boolean customStroke = false;
- 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 {
+ 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 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 @@
}
}
- 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 @@
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/bridge/src/android/graphics/ComposePathEffect_Delegate.java b/bridge/src/android/graphics/ComposePathEffect_Delegate.java
new file mode 100644
index 0000000..954c658
--- /dev/null
+++ b/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/bridge/src/android/graphics/ComposeShader_Delegate.java b/bridge/src/android/graphics/ComposeShader_Delegate.java
new file mode 100644
index 0000000..2853222
--- /dev/null
+++ b/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/bridge/src/android/graphics/CornerPathEffect_Delegate.java b/bridge/src/android/graphics/CornerPathEffect_Delegate.java
new file mode 100644
index 0000000..cd08549
--- /dev/null
+++ b/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/bridge/src/android/graphics/DashPathEffect_Delegate.java b/bridge/src/android/graphics/DashPathEffect_Delegate.java
index 7ee72d8..1b539ce 100644
--- a/bridge/src/android/graphics/DashPathEffect_Delegate.java
+++ b/bridge/src/android/graphics/DashPathEffect_Delegate.java
@@ -18,6 +18,9 @@
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 @@
* {@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 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);
}
- public float getPhase() {
- return mPhase;
+ @Override
+ public boolean isSupported() {
+ return true;
+ }
+
+ @Override
+ public String getSupportMessage() {
+ // no message since isSupported returns true;
+ return null;
}
// ---- native methods ----
diff --git a/bridge/src/android/graphics/DiscretePathEffect_Delegate.java b/bridge/src/android/graphics/DiscretePathEffect_Delegate.java
new file mode 100644
index 0000000..f99ab2b
--- /dev/null
+++ b/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/bridge/src/android/graphics/Gradient_Delegate.java b/bridge/src/android/graphics/Gradient_Delegate.java
index bc4ccd2..7a0c2f7 100644
--- a/bridge/src/android/graphics/Gradient_Delegate.java
+++ b/bridge/src/android/graphics/Gradient_Delegate.java
@@ -26,6 +26,18 @@
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/bridge/src/android/graphics/LinearGradient_Delegate.java b/bridge/src/android/graphics/LinearGradient_Delegate.java
index 862b4544..baa0a6a 100644
--- a/bridge/src/android/graphics/LinearGradient_Delegate.java
+++ b/bridge/src/android/graphics/LinearGradient_Delegate.java
@@ -21,10 +21,6 @@
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 @@
* @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 Helper methods ----
@Override
- public Paint getJavaPaint() {
+ public java.awt.Paint getJavaPaint() {
return mJavaPaint;
}
@@ -58,17 +54,8 @@
/*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 @@
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 @@
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/bridge/src/android/graphics/Matrix_Delegate.java b/bridge/src/android/graphics/Matrix_Delegate.java
index b464f66..f6cee5e 100644
--- a/bridge/src/android/graphics/Matrix_Delegate.java
+++ b/bridge/src/android/graphics/Matrix_Delegate.java
@@ -1052,6 +1052,4 @@
return tmp;
}
-
-
}
diff --git a/bridge/src/android/graphics/NinePatch_Delegate.java b/bridge/src/android/graphics/NinePatch_Delegate.java
index fe9bef9..b8f76a6 100644
--- a/bridge/src/android/graphics/NinePatch_Delegate.java
+++ b/bridge/src/android/graphics/NinePatch_Delegate.java
@@ -43,7 +43,7 @@
* 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/bridge/src/android/graphics/Path.java b/bridge/src/android/graphics/Path.java
deleted file mode 100644
index c0bc005..0000000
--- a/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/bridge/src/android/graphics/PathDashPathEffect_Delegate.java b/bridge/src/android/graphics/PathDashPathEffect_Delegate.java
new file mode 100644
index 0000000..3777ac9
--- /dev/null
+++ b/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/bridge/src/android/graphics/PathEffect_Delegate.java b/bridge/src/android/graphics/PathEffect_Delegate.java
index ce7eef0..c588423 100644
--- a/bridge/src/android/graphics/PathEffect_Delegate.java
+++ b/bridge/src/android/graphics/PathEffect_Delegate.java
@@ -18,6 +18,8 @@
import com.android.layoutlib.bridge.impl.DelegateManager;
+import java.awt.Stroke;
+
/**
* Delegate implementing the native methods of android.graphics.PathEffect
*
@@ -33,7 +35,7 @@
* @see DelegateManager
*
*/
-public class PathEffect_Delegate {
+public abstract class PathEffect_Delegate {
// ---- delegate manager ----
protected static final DelegateManager<PathEffect_Delegate> sManager =
@@ -49,6 +51,11 @@
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/bridge/src/android/graphics/Path_Delegate.java b/bridge/src/android/graphics/Path_Delegate.java
new file mode 100644
index 0000000..811f0f6
--- /dev/null
+++ b/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/bridge/src/android/graphics/PixelXorXfermode_Delegate.java b/bridge/src/android/graphics/PixelXorXfermode_Delegate.java
new file mode 100644
index 0000000..e8f29ad
--- /dev/null
+++ b/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/bridge/src/android/graphics/PorterDuffXfermode_Delegate.java b/bridge/src/android/graphics/PorterDuffXfermode_Delegate.java
index a5885ea..3e9a346 100644
--- a/bridge/src/android/graphics/PorterDuffXfermode_Delegate.java
+++ b/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 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 @@
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/bridge/src/android/graphics/RadialGradient_Delegate.java b/bridge/src/android/graphics/RadialGradient_Delegate.java
index eebf378..1f6f4b4 100644
--- a/bridge/src/android/graphics/RadialGradient_Delegate.java
+++ b/bridge/src/android/graphics/RadialGradient_Delegate.java
@@ -21,10 +21,6 @@
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 Helper methods ----
@Override
- public Paint getJavaPaint() {
+ public java.awt.Paint getJavaPaint() {
return mJavaPaint;
}
@@ -57,17 +53,8 @@
/*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 @@
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 @@
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/bridge/src/android/graphics/Shader_Delegate.java b/bridge/src/android/graphics/Shader_Delegate.java
index 7bf1443..3759b26 100644
--- a/bridge/src/android/graphics/Shader_Delegate.java
+++ b/bridge/src/android/graphics/Shader_Delegate.java
@@ -18,7 +18,7 @@
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 @@
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 @@
// ---- 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/bridge/src/android/graphics/SumPathEffect_Delegate.java b/bridge/src/android/graphics/SumPathEffect_Delegate.java
new file mode 100644
index 0000000..b02f9c5
--- /dev/null
+++ b/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/bridge/src/android/graphics/SweepGradient_Delegate.java b/bridge/src/android/graphics/SweepGradient_Delegate.java
index 97c3cfd..970e781 100644
--- a/bridge/src/android/graphics/SweepGradient_Delegate.java
+++ b/bridge/src/android/graphics/SweepGradient_Delegate.java
@@ -19,10 +19,6 @@
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 Helper methods ----
@Override
- public Paint getJavaPaint() {
+ public java.awt.Paint getJavaPaint() {
return mJavaPaint;
}
@@ -116,20 +112,20 @@
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 @@
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/bridge/src/android/graphics/Xfermode_Delegate.java b/bridge/src/android/graphics/Xfermode_Delegate.java
index 0c1170d..e783fd1 100644
--- a/bridge/src/android/graphics/Xfermode_Delegate.java
+++ b/bridge/src/android/graphics/Xfermode_Delegate.java
@@ -18,6 +18,8 @@
import com.android.layoutlib.bridge.impl.DelegateManager;
+import java.awt.Composite;
+
/**
* Delegate implementing the native methods of android.graphics.Xfermode
*
@@ -33,7 +35,7 @@
* @see DelegateManager
*
*/
-public class Xfermode_Delegate {
+public abstract class Xfermode_Delegate {
// ---- delegate manager ----
protected static final DelegateManager<Xfermode_Delegate> sManager =
@@ -49,6 +51,11 @@
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) {