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) {