Layoutlib native delegate: primitive shapes and shaders

Change-Id: Id2b0c6231589e82d8e96c9f019042eba348a6583
diff --git a/bridge/src/android/graphics/BitmapShader.java b/bridge/src/android/graphics/BitmapShader.java
deleted file mode 100644
index ad3974c..0000000
--- a/bridge/src/android/graphics/BitmapShader.java
+++ /dev/null
@@ -1,48 +0,0 @@
-/*
- * Copyright (C) 2008 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.Paint;
-
-public class BitmapShader extends Shader {
-
-    // we hold on just for the GC, since our native counterpart is using it
-    private final Bitmap mBitmap;
-
-    /**
-     * Call this to create a new shader that will draw with a bitmap.
-     *
-     * @param bitmap            The bitmap to use inside the shader
-     * @param tileX             The tiling mode for x to draw the bitmap in.
-     * @param tileY             The tiling mode for y to draw the bitmap in.
-     */
-    public BitmapShader(Bitmap bitmap, TileMode tileX, TileMode tileY) {
-        mBitmap = bitmap;
-    }
-
-    //---------- Custom methods
-
-    public Bitmap getBitmap() {
-        return mBitmap;
-    }
-
-    @Override
-    Paint getJavaPaint() {
-        return null;
-    }
-}
-
diff --git a/bridge/src/android/graphics/Canvas_Delegate.java b/bridge/src/android/graphics/Canvas_Delegate.java
index e7996ed..bfe5c86 100644
--- a/bridge/src/android/graphics/Canvas_Delegate.java
+++ b/bridge/src/android/graphics/Canvas_Delegate.java
@@ -431,14 +431,14 @@
     /*package*/ static boolean native_quickReject(int nativeCanvas,
                                                      RectF rect,
                                                      int native_edgeType) {
-        // FIXME
+        // FIXME properly implement quickReject
         return false;
     }
 
     /*package*/ static boolean native_quickReject(int nativeCanvas,
                                                      int path,
                                                      int native_edgeType) {
-        // FIXME
+        // FIXME properly implement quickReject
         return false;
     }
 
@@ -446,18 +446,26 @@
                                                      float left, float top,
                                                      float right, float bottom,
                                                      int native_edgeType) {
-        // FIXME
+        // FIXME properly implement quickReject
         return false;
     }
 
-    /*package*/ static void native_drawRGB(int nativeCanvas, int r, int g,
-                                              int b) {
-        // FIXME
-        throw new UnsupportedOperationException();
+    /*package*/ static void native_drawRGB(int nativeCanvas, int r, int g, int b) {
+        native_drawColor(nativeCanvas, 0xFF000000 | r << 16 | (g&0xFF) << 8 | (b&0xFF),
+                PorterDuff.Mode.SRC_OVER.nativeInt);
+
     }
 
-    /*package*/ static void native_drawARGB(int nativeCanvas, int a, int r,
-                                               int g, int b) {
+    /*package*/ static void native_drawARGB(int nativeCanvas, int a, int r, int g, int b) {
+        native_drawColor(nativeCanvas, a << 24 | (r&0xFF) << 16 | (g&0xFF) << 8 | (b&0xFF),
+                PorterDuff.Mode.SRC_OVER.nativeInt);
+    }
+
+    /*package*/ static void native_drawColor(int nativeCanvas, int color) {
+        native_drawColor(nativeCanvas, color, PorterDuff.Mode.SRC_OVER.nativeInt);
+    }
+
+    /*package*/ static void native_drawColor(int nativeCanvas, int color, int mode) {
         // get the delegate from the native int.
         Canvas_Delegate canvasDelegate = sManager.getDelegate(nativeCanvas);
         if (canvasDelegate == null) {
@@ -472,7 +480,13 @@
             graphics.setTransform(new AffineTransform());
 
             // set the color
-            graphics.setColor(new Color(r, g, b, a));
+            graphics.setColor(new Color(color));
+
+            // set the mode and alpha.
+            int alpha = color >>> 24;
+            float falpha = alpha / 255.f;
+
+            setModeInGraphics(graphics, mode, falpha);
 
             graphics.fillRect(0, 0, canvasDelegate.mBufferedImage.getWidth(),
                     canvasDelegate.mBufferedImage.getHeight());
@@ -482,17 +496,6 @@
         }
     }
 
-    /*package*/ static void native_drawColor(int nativeCanvas, int color) {
-        // FIXME
-        throw new UnsupportedOperationException();
-    }
-
-    /*package*/ static void native_drawColor(int nativeCanvas, int color,
-                                                int mode) {
-        // FIXME
-        throw new UnsupportedOperationException();
-    }
-
     /*package*/ static void native_drawPaint(int nativeCanvas, int paint) {
         // FIXME
         throw new UnsupportedOperationException();
@@ -501,14 +504,32 @@
     /*package*/ static void native_drawLine(int nativeCanvas, float startX,
                                                float startY, float stopX,
                                                float stopY, int paint) {
-        // FIXME
-        throw new UnsupportedOperationException();
+        // get the delegate from the native int.
+        Canvas_Delegate canvasDelegate = sManager.getDelegate(nativeCanvas);
+        if (canvasDelegate == null) {
+            assert false;
+            return;
+        }
+
+        // get the delegate from the native int.
+        Paint_Delegate paintDelegate = Paint_Delegate.getDelegate(paint);
+        if (paintDelegate == null) {
+            assert false;
+            return;
+        }
+
+        // get a Graphics2D object configured with the drawing parameters.
+        Graphics2D g = canvasDelegate.getCustomGraphics(paintDelegate);
+
+        g.drawLine((int)startX, (int)startY, (int)stopX, (int)stopY);
+
+        // dispose Graphics2D object
+        g.dispose();
     }
 
     /*package*/ static void native_drawRect(int nativeCanvas, RectF rect,
                                                int paint) {
-        // FIXME
-        throw new UnsupportedOperationException();
+        native_drawRect(nativeCanvas, rect.left, rect.top, rect.right, rect.bottom, paint);
     }
 
     /*package*/ static void native_drawRect(int nativeCanvas, float left,
@@ -548,20 +569,52 @@
             // dispose Graphics2D object
             g.dispose();
         }
-
     }
 
     /*package*/ static void native_drawOval(int nativeCanvas, RectF oval,
                                                int paint) {
-        // FIXME
-        throw new UnsupportedOperationException();
+        // get the delegate from the native int.
+        Canvas_Delegate canvasDelegate = sManager.getDelegate(nativeCanvas);
+        if (canvasDelegate == null) {
+            assert false;
+            return;
+        }
+
+        // get the delegate from the native int.
+        Paint_Delegate paintDelegate = Paint_Delegate.getDelegate(paint);
+        if (paintDelegate == null) {
+            assert false;
+            return;
+        }
+
+        if (oval.right > oval.left && oval.bottom > oval.top) {
+            // get a Graphics2D object configured with the drawing parameters.
+            Graphics2D g = canvasDelegate.getCustomGraphics(paintDelegate);
+
+            int style = paintDelegate.getStyle();
+
+            // draw
+            if (style == Paint.Style.FILL.nativeInt ||
+                    style == Paint.Style.FILL_AND_STROKE.nativeInt) {
+                g.fillOval((int)oval.left, (int)oval.top, (int)oval.width(), (int)oval.height());
+            }
+
+            if (style == Paint.Style.STROKE.nativeInt ||
+                    style == Paint.Style.FILL_AND_STROKE.nativeInt) {
+                g.drawOval((int)oval.left, (int)oval.top, (int)oval.width(), (int)oval.height());
+            }
+
+            // dispose Graphics2D object
+            g.dispose();
+        }
     }
 
     /*package*/ static void native_drawCircle(int nativeCanvas, float cx,
                                                  float cy, float radius,
                                                  int paint) {
-        // FIXME
-        throw new UnsupportedOperationException();
+        native_drawOval(nativeCanvas,
+                new RectF(cx - radius, cy - radius, radius*2, radius*2),
+                paint);
     }
 
     /*package*/ static void native_drawArc(int nativeCanvas, RectF oval,
@@ -574,8 +627,44 @@
     /*package*/ static void native_drawRoundRect(int nativeCanvas,
                                                     RectF rect, float rx,
                                                     float ry, int paint) {
-        // FIXME
-        throw new UnsupportedOperationException();
+        // get the delegate from the native int.
+        Canvas_Delegate canvasDelegate = sManager.getDelegate(nativeCanvas);
+        if (canvasDelegate == null) {
+            assert false;
+            return;
+        }
+
+        // get the delegate from the native int.
+        Paint_Delegate paintDelegate = Paint_Delegate.getDelegate(paint);
+        if (paintDelegate == null) {
+            assert false;
+            return;
+        }
+
+        if (rect.right > rect.left && rect.bottom > rect.top) {
+            // get a Graphics2D object configured with the drawing parameters.
+            Graphics2D g = canvasDelegate.getCustomGraphics(paintDelegate);
+
+            int style = paintDelegate.getStyle();
+
+            // draw
+            if (style == Paint.Style.FILL.nativeInt ||
+                    style == Paint.Style.FILL_AND_STROKE.nativeInt) {
+                g.fillRoundRect(
+                        (int)rect.left, (int)rect.top, (int)rect.width(), (int)rect.height(),
+                        (int)rx, (int)ry);
+            }
+
+            if (style == Paint.Style.STROKE.nativeInt ||
+                    style == Paint.Style.FILL_AND_STROKE.nativeInt) {
+                g.drawRoundRect(
+                        (int)rect.left, (int)rect.top, (int)rect.width(), (int)rect.height(),
+                        (int)rx, (int)ry);
+            }
+
+            // dispose Graphics2D object
+            g.dispose();
+        }
     }
 
     /*package*/ static void native_drawPath(int nativeCanvas, int path,
@@ -675,7 +764,6 @@
         throw new UnsupportedOperationException();
     }
 
-
     /*package*/ static void native_drawText(int nativeCanvas, char[] text,
                                                int index, int count, float x,
                                                float y, int flags, int paint) {
@@ -696,21 +784,8 @@
             return;
         }
 
-        Graphics2D g = (Graphics2D) canvasDelegate.getGraphics2d().create();
+        Graphics2D g = (Graphics2D) canvasDelegate.getCustomGraphics(paintDelegate);
         try {
-            if (paintDelegate.isAntiAliased()) {
-                g.setRenderingHint(
-                        RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
-            }
-
-            // set the color. because this only handles RGB, the alpha channel is handled
-            // as a composite.
-            g.setColor(new Color(paintDelegate.getColor()));
-            int alpha = paintDelegate.getAlpha();
-            float falpha = alpha / 255.f;
-
-            setModeInGraphics(g, PorterDuff.Mode.SRC_OVER, falpha);
-
             // Paint.TextAlign indicates how the text is positioned relative to X.
             // LEFT is the default and there's nothing to do.
             if (paintDelegate.getTextAlign() != Paint.Align.LEFT.nativeInt) {
@@ -898,6 +973,8 @@
         if (paint.isAntiAliased()) {
             g.setRenderingHint(
                     RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
+            g.setRenderingHint(
+                    RenderingHints.KEY_TEXT_ANTIALIASING, RenderingHints.VALUE_TEXT_ANTIALIAS_ON);
         }
 
         // configure it
@@ -941,24 +1018,34 @@
             }
             g.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER, falpha));
         }
-
-        Shader shader = paint.getShader();
-        if (shader != null) {
-            java.awt.Paint shaderPaint = shader.getJavaPaint();
+*/
+        int nativeShader = paint.getShader();
+        Shader_Delegate shaderDelegate = Shader_Delegate.getDelegate(nativeShader);
+        if (shaderDelegate != null) {
+            java.awt.Paint shaderPaint = shaderDelegate.getJavaPaint();
             if (shaderPaint != null) {
                 g.setPaint(shaderPaint);
             } else {
                 if (mLogger != null) {
                     mLogger.warning(String.format(
                             "Shader '%1$s' is not supported in the Layout Editor.",
-                            shader.getClass().getCanonicalName()));
+                            shaderDelegate.getClass().getCanonicalName()));
                 }
             }
         }
-*/
+
         return g;
     }
 
+    private static void setModeInGraphics(Graphics2D g, int mode, float falpha) {
+        for (PorterDuff.Mode m : PorterDuff.Mode.values()) {
+            if (m.nativeInt == mode) {
+                setModeInGraphics(g, m, falpha);
+                return;
+            }
+        }
+    }
+
     private static void setModeInGraphics(Graphics2D g, PorterDuff.Mode mode, float falpha) {
         switch (mode) {
             case CLEAR:
diff --git a/bridge/src/android/graphics/ComposeShader.java b/bridge/src/android/graphics/ComposeShader.java
deleted file mode 100644
index 863d64a..0000000
--- a/bridge/src/android/graphics/ComposeShader.java
+++ /dev/null
@@ -1,53 +0,0 @@
-/*
- * Copyright (C) 2008 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.Paint;
-
-/** A subclass of shader that returns the composition of two other shaders, combined by
-    an {@link android.graphics.Xfermode} subclass.
-*/
-public class ComposeShader extends Shader {
-    /** Create a new compose shader, given shaders A, B, and a combining mode.
-        When the mode is applied, it will be given the result from shader A as its
-        "dst", and the result of from shader B as its "src".
-        @param shaderA  The colors from this shader are seen as the "dst" by the mode
-        @param shaderB  The colors from this shader are seen as the "src" by the mode
-        @param mode     The mode that combines the colors from the two shaders. If mode
-                        is null, then SRC_OVER is assumed.
-    */
-    public ComposeShader(Shader shaderA, Shader shaderB, Xfermode mode) {
-        // FIXME Implement shader
-    }
-
-    /** Create a new compose shader, given shaders A, B, and a combining PorterDuff mode.
-        When the mode is applied, it will be given the result from shader A as its
-        "dst", and the result of from shader B as its "src".
-        @param shaderA  The colors from this shader are seen as the "dst" by the mode
-        @param shaderB  The colors from this shader are seen as the "src" by the mode
-        @param mode     The PorterDuff mode that combines the colors from the two shaders.
-    */
-    public ComposeShader(Shader shaderA, Shader shaderB, PorterDuff.Mode mode) {
-        // FIXME Implement shader
-    }
-
-    @Override
-    Paint getJavaPaint() {
-        return null;
-    }
-}
-
diff --git a/bridge/src/android/graphics/GradientShader.java b/bridge/src/android/graphics/Gradient_Delegate.java
similarity index 93%
rename from bridge/src/android/graphics/GradientShader.java
rename to bridge/src/android/graphics/Gradient_Delegate.java
index 8c5a2a4..042d557 100644
--- a/bridge/src/android/graphics/GradientShader.java
+++ b/bridge/src/android/graphics/Gradient_Delegate.java
@@ -16,19 +16,12 @@
 
 package android.graphics;
 
+import android.graphics.Shader.TileMode;
 
 /**
- * Base class for Gradient shader. This is not a standard android class and is just used
- * as a base class for the re-implemented gradient classes.
- *
- * It also provides a base class to handle common code between the different shaders'
- * implementations of {@link java.awt.Paint}.
- *
- * @see LinearGradient
- * @see RadialGradient
- * @see SweepGradient
+ * Base class for true Gradient shader delegate.
  */
-public abstract class GradientShader extends Shader {
+public abstract class Gradient_Delegate extends Shader_Delegate {
 
     protected final int[] mColors;
     protected final float[] mPositions;
@@ -41,7 +34,7 @@
      *            corresponding color in the colors array. If this is null, the
      *            the colors are distributed evenly along the gradient line.
      */
-    protected GradientShader(int colors[], float positions[]) {
+    protected Gradient_Delegate(int colors[], float positions[]) {
         if (colors.length < 2) {
             throw new IllegalArgumentException("needs >= 2 number of colors");
         }
@@ -199,7 +192,5 @@
         private int computeChannel(int c1, int c2, float percent) {
             return c1 + (int)((percent * (c2-c1)) + .5);
         }
-
-
     }
 }
diff --git a/bridge/src/android/graphics/LinearGradient.java b/bridge/src/android/graphics/LinearGradient_Delegate.java
similarity index 66%
rename from bridge/src/android/graphics/LinearGradient.java
rename to bridge/src/android/graphics/LinearGradient_Delegate.java
index 10c4a5e..405e537 100644
--- a/bridge/src/android/graphics/LinearGradient.java
+++ b/bridge/src/android/graphics/LinearGradient_Delegate.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2008 The Android Open Source Project
+ * 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.
@@ -16,10 +16,80 @@
 
 package android.graphics;
 
-public class LinearGradient extends GradientShader {
+import com.android.layoutlib.bridge.DelegateManager;
 
+import android.graphics.Shader.TileMode;
+
+import java.awt.Paint;
+
+/**
+ * Delegate implementing the native methods of android.graphics.LinearGradient
+ *
+ * Through the layoutlib_create tool, the original native methods of LinearGradient 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 LinearGradient 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 LinearGradient_Delegate extends Gradient_Delegate {
+
+    // ---- delegate data ----
     private java.awt.Paint mJavaPaint;
 
+    // ---- Public Helper methods ----
+
+    @Override
+    public Paint getJavaPaint() {
+        return mJavaPaint;
+    }
+
+    // ---- native methods ----
+
+    /*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);
+        return sManager.addDelegate(newDelegate);
+    }
+    /*package*/ static int nativeCreate2(LinearGradient thisGradient,
+            float x0, float y0, float x1, float y1,
+            int color0, int color1, int tileMode) {
+        return nativeCreate1(thisGradient,
+                x0, y0, x1, y1, new int[] { color0, color1}, null /*positions*/,
+                tileMode);
+    }
+    /*package*/ static int nativePostCreate1(LinearGradient thisGradient,
+            int native_shader, float x0, float y0, float x1, float y1,
+            int colors[], float positions[], int tileMode) {
+        // nothing to be done here.
+        return 0;
+    }
+    /*package*/ static int nativePostCreate2(LinearGradient thisGradient,
+            int native_shader, float x0, float y0, float x1, float y1,
+            int color0, int color1, int tileMode) {
+        // nothing to be done here.
+        return 0;
+    }
+
+    // ---- Private delegate/helper methods ----
+
     /**
      * Create a shader that draws a linear gradient along a line.
      *
@@ -33,35 +103,13 @@
      *            the colors are distributed evenly along the gradient line.
      * @param tile The Shader tiling mode
      */
-    public LinearGradient(float x0, float y0, float x1, float y1, int colors[], float positions[],
-            TileMode tile) {
+    private LinearGradient_Delegate(float x0, float y0, float x1, float y1,
+            int colors[], float positions[], TileMode tile) {
         super(colors, positions);
         mJavaPaint = new LinearGradientPaint(x0, y0, x1, y1, mColors, mPositions, tile);
     }
 
-    /**
-     * Create a shader that draws a linear gradient along a line.
-     *
-     * @param x0 The x-coordinate for the start of the gradient line
-     * @param y0 The y-coordinate for the start of the gradient line
-     * @param x1 The x-coordinate for the end of the gradient line
-     * @param y1 The y-coordinate for the end of the gradient line
-     * @param color0 The color at the start of the gradient line.
-     * @param color1 The color at the end of the gradient line.
-     * @param tile The Shader tiling mode
-     */
-    public LinearGradient(float x0, float y0, float x1, float y1, int color0, int color1,
-            TileMode tile) {
-        this(x0, y0, x1, y1, new int[] { color0, color1}, null /*positions*/, tile);
-    }
-
-    // ---------- Custom Methods
-
-    @Override
-    java.awt.Paint getJavaPaint() {
-        return mJavaPaint;
-    }
-
+    // ---- Custom Java Paint ----
     /**
      * Linear Gradient (Java) Paint able to handle more than 2 points, as
      * {@link java.awt.GradientPaint} only supports 2 points and does not support Android's tile
@@ -101,7 +149,7 @@
 
             public LinearGradientPaintContext(java.awt.image.ColorModel colorModel) {
                 mColorModel = colorModel;
-                // FIXME: so far all this is always the same rect gotten in getRaster with an indentity matrix?
+                // FIXME: so far all this is always the same rect gotten in getRaster with an identity matrix?
             }
 
             public void dispose() {
diff --git a/bridge/src/android/graphics/Matrix_Delegate.java b/bridge/src/android/graphics/Matrix_Delegate.java
index 713f784..0966f39 100644
--- a/bridge/src/android/graphics/Matrix_Delegate.java
+++ b/bridge/src/android/graphics/Matrix_Delegate.java
@@ -50,6 +50,10 @@
 
     // ---- Public Helper methods ----
 
+    public static Matrix_Delegate getDelegate(int native_instance) {
+        return sManager.getDelegate(native_instance);
+    }
+
     /**
      * Returns an {@link AffineTransform} matching the given Matrix.
      */
@@ -73,6 +77,35 @@
         return (delegate.mValues[6] != 0 || delegate.mValues[7] != 0 || delegate.mValues[8] != 1);
     }
 
+    /**
+     * Sets the content of the matrix with the content of another matrix.
+     */
+    public void set(Matrix_Delegate matrix) {
+        System.arraycopy(matrix.mValues, 0, mValues, 0, MATRIX_SIZE);
+    }
+
+    /**
+     * Resets the matrix to be the identity matrix.
+     */
+    public void reset() {
+        reset(mValues);
+    }
+
+    /**
+     * Returns whether or not the matrix is identity.
+     */
+    public boolean isIdentity() {
+        for (int i = 0, k = 0; i < 3; i++) {
+            for (int j = 0; j < 3; j++, k++) {
+                if (mValues[k] != ((i==j) ? 1 : 0)) {
+                    return false;
+                }
+            }
+        }
+
+        return true;
+    }
+
 
     // ---- native methods ----
 
@@ -101,15 +134,7 @@
             return false;
         }
 
-        for (int i = 0, k = 0; i < 3; i++) {
-            for (int j = 0; j < 3; j++, k++) {
-                if (d.mValues[k] != ((i==j) ? 1 : 0)) {
-                    return false;
-                }
-            }
-        }
-
-        return true;
+        return d.isIdentity();
     }
 
     /*package*/ static boolean native_rectStaysRect(int native_object) {
diff --git a/bridge/src/android/graphics/Paint_Delegate.java b/bridge/src/android/graphics/Paint_Delegate.java
index 6074bd3..6e90bdd 100644
--- a/bridge/src/android/graphics/Paint_Delegate.java
+++ b/bridge/src/android/graphics/Paint_Delegate.java
@@ -154,6 +154,26 @@
         }
     }
 
+    public int getXfermode() {
+        return mXfermode;
+    }
+
+    public int getColorFilter() {
+        return mColorFilter;
+    }
+
+    public int getShader() {
+        return mShader;
+    }
+
+    public int getPathEffect() {
+        return mPathEffect;
+    }
+
+    public int getMaskFilter() {
+        return mMaskFilter;
+    }
+
     // ---- native methods ----
 
     /*package*/ static int getFlags(Paint thisPaint) {
@@ -705,8 +725,7 @@
         }
 
         if (delegate.mFonts.size() > 0) {
-            // FIXME: handle multi-char characters.
-            // see measureText.
+            // FIXME: handle multi-char characters (see measureText)
             float totalAdvance = 0;
             for (int i = 0; i < count; i++) {
                 char c = text[i + index];
diff --git a/bridge/src/android/graphics/RadialGradient.java b/bridge/src/android/graphics/RadialGradient.java
deleted file mode 100644
index 4409a80..0000000
--- a/bridge/src/android/graphics/RadialGradient.java
+++ /dev/null
@@ -1,132 +0,0 @@
-/*
- * Copyright (C) 2008 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;
-
-public class RadialGradient extends GradientShader {
-
-    private RadialGradientPaint mPaint;
-
-    /**
-     * Create a shader that draws a radial gradient given the center and radius.
-     *
-     * @param x The x-coordinate of the center of the radius
-     * @param y The y-coordinate of the center of the radius
-     * @param radius Must be positive. The radius of the circle for this
-     *            gradient
-     * @param colors The colors to be distributed between the center and edge of
-     *            the circle
-     * @param positions May be NULL. The relative position of each corresponding
-     *            color in the colors array. If this is NULL, the the colors are
-     *            distributed evenly between the center and edge of the circle.
-     * @param tile The Shader tiling mode
-     */
-    public RadialGradient(float x, float y, float radius, int colors[], float positions[],
-            TileMode tile) {
-        super(colors, positions);
-        if (radius <= 0) {
-            throw new IllegalArgumentException("radius must be > 0");
-        }
-
-        mPaint = new RadialGradientPaint(x, y, radius, mColors, mPositions, tile);
-    }
-
-    /**
-     * Create a shader that draws a radial gradient given the center and radius.
-     *
-     * @param x The x-coordinate of the center of the radius
-     * @param y The y-coordinate of the center of the radius
-     * @param radius Must be positive. The radius of the circle for this
-     *            gradient
-     * @param color0 The color at the center of the circle.
-     * @param color1 The color at the edge of the circle.
-     * @param tile The Shader tiling mode
-     */
-    public RadialGradient(float x, float y, float radius, int color0, int color1, TileMode tile) {
-        this(x, y, radius, new int[] { color0, color1 }, null /* positions */, tile);
-    }
-
-    @Override
-    java.awt.Paint getJavaPaint() {
-        return mPaint;
-    }
-
-    private static class RadialGradientPaint extends GradientPaint {
-
-        private final float mX;
-        private final float mY;
-        private final float mRadius;
-
-        public RadialGradientPaint(float x, float y, float radius, int[] colors, float[] positions, TileMode mode) {
-            super(colors, positions, mode);
-            mX = x;
-            mY = y;
-            mRadius = radius;
-        }
-
-        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) {
-            precomputeGradientColors();
-            return new RadialGradientPaintContext(colorModel);
-        }
-
-        private class RadialGradientPaintContext implements java.awt.PaintContext {
-
-            private final java.awt.image.ColorModel mColorModel;
-
-            public RadialGradientPaintContext(java.awt.image.ColorModel colorModel) {
-                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];
-
-                // compute distance from each point to the center, and figure out the distance from
-                // it.
-                int index = 0;
-                for (int iy = 0 ; iy < h ; iy++) {
-                    for (int ix = 0 ; ix < w ; ix++) {
-                        float _x = x + ix - mX;
-                        float _y = y + iy - mY;
-                        float distance = (float) Math.sqrt(_x * _x + _y * _y);
-
-                        data[index++] = getGradientColor(distance / mRadius);
-                    }
-                }
-
-                image.setRGB(0 /*startX*/, 0 /*startY*/, w, h, data, 0 /*offset*/, w /*scansize*/);
-
-                return image.getRaster();
-            }
-
-        }
-    }
-
-}
diff --git a/bridge/src/android/graphics/RadialGradient_Delegate.java b/bridge/src/android/graphics/RadialGradient_Delegate.java
new file mode 100644
index 0000000..c4e764c
--- /dev/null
+++ b/bridge/src/android/graphics/RadialGradient_Delegate.java
@@ -0,0 +1,178 @@
+/*
+ * 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.DelegateManager;
+
+import android.graphics.Shader.TileMode;
+
+import java.awt.Paint;
+
+/**
+ * Delegate implementing the native methods of android.graphics.RadialGradient
+ *
+ * Through the layoutlib_create tool, the original native methods of RadialGradient 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 RadialGradient 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 RadialGradient_Delegate extends Gradient_Delegate {
+
+    // ---- delegate data ----
+    private java.awt.Paint mJavaPaint;
+
+    // ---- Public Helper methods ----
+
+    @Override
+    public Paint getJavaPaint() {
+        return mJavaPaint;
+    }
+
+    // ---- native methods ----
+
+    /*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);
+        return sManager.addDelegate(newDelegate);
+    }
+
+    /*package*/ static int nativeCreate2(float x, float y, float radius,
+            int color0, int color1, int tileMode) {
+        return nativeCreate1(x, y, radius, new int[] { color0, color1 }, null /*positions*/,
+                tileMode);
+    }
+
+    /*package*/ static int nativePostCreate1(int native_shader, float x, float y, float radius,
+            int colors[], float positions[], int tileMode) {
+        // nothing to be done here.
+        return 0;
+    }
+
+    /*package*/ static int nativePostCreate2(int native_shader, float x, float y, float radius,
+            int color0, int color1, int tileMode) {
+        // nothing to be done here.
+        return 0;
+    }
+
+    // ---- Private delegate/helper methods ----
+
+    /**
+     * Create a shader that draws a radial gradient given the center and radius.
+     *
+     * @param x The x-coordinate of the center of the radius
+     * @param y The y-coordinate of the center of the radius
+     * @param radius Must be positive. The radius of the circle for this
+     *            gradient
+     * @param colors The colors to be distributed between the center and edge of
+     *            the circle
+     * @param positions May be NULL. The relative position of each corresponding
+     *            color in the colors array. If this is NULL, the the colors are
+     *            distributed evenly between the center and edge of the circle.
+     * @param tile The Shader tiling mode
+     */
+    private RadialGradient_Delegate(float x, float y, float radius, int colors[], float positions[],
+            TileMode tile) {
+        super(colors, positions);
+
+        mJavaPaint = new RadialGradientPaint(x, y, radius, mColors, mPositions, tile);
+    }
+
+    private static class RadialGradientPaint extends GradientPaint {
+
+        private final float mX;
+        private final float mY;
+        private final float mRadius;
+
+        public RadialGradientPaint(float x, float y, float radius, int[] colors, float[] positions,
+                TileMode mode) {
+            super(colors, positions, mode);
+            mX = x;
+            mY = y;
+            mRadius = radius;
+        }
+
+        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) {
+            precomputeGradientColors();
+            return new RadialGradientPaintContext(colorModel);
+        }
+
+        private class RadialGradientPaintContext implements java.awt.PaintContext {
+
+            private final java.awt.image.ColorModel mColorModel;
+
+            public RadialGradientPaintContext(java.awt.image.ColorModel colorModel) {
+                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];
+
+                // compute distance from each point to the center, and figure out the distance from
+                // it.
+                int index = 0;
+                for (int iy = 0 ; iy < h ; iy++) {
+                    for (int ix = 0 ; ix < w ; ix++) {
+                        float _x = x + ix - mX;
+                        float _y = y + iy - mY;
+                        float distance = (float) Math.sqrt(_x * _x + _y * _y);
+
+                        data[index++] = getGradientColor(distance / mRadius);
+                    }
+                }
+
+                image.setRGB(0 /*startX*/, 0 /*startY*/, w, h, data, 0 /*offset*/, w /*scansize*/);
+
+                return image.getRaster();
+            }
+
+        }
+    }
+
+}
diff --git a/bridge/src/android/graphics/Shader.java b/bridge/src/android/graphics/Shader.java
deleted file mode 100644
index 0cc5940..0000000
--- a/bridge/src/android/graphics/Shader.java
+++ /dev/null
@@ -1,83 +0,0 @@
-/*
- * Copyright (C) 2008 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;
-
-
-
-/**
- * Shader is the based class for objects that return horizontal spans of colors
- * during drawing. A subclass of Shader is installed in a Paint calling
- * paint.setShader(shader). After that any object (other than a bitmap) that is
- * drawn with that paint will get its color(s) from the shader.
- */
-public abstract class Shader {
-
-    private final Matrix mMatrix = new Matrix();
-
-    public enum TileMode {
-        /**
-         * replicate the edge color if the shader draws outside of its
-         * original bounds
-         */
-        CLAMP   (0),
-        /**
-         * repeat the shader's image horizontally and vertically
-         */
-        REPEAT  (1),
-        /**
-         * repeat the shader's image horizontally and vertically, alternating
-         * mirror images so that adjacent images always seam
-         */
-        MIRROR  (2);
-
-        TileMode(int nativeInt) {
-            this.nativeInt = nativeInt;
-        }
-        final int nativeInt;
-    }
-
-    /**
-     * Return true if the shader has a non-identity local matrix.
-     * @param localM If not null, it is set to the shader's local matrix.
-     * @return true if the shader has a non-identity local matrix
-     */
-    public boolean getLocalMatrix(Matrix localM) {
-        if (localM != null) {
-            localM.set(mMatrix);
-        }
-
-        return !mMatrix.isIdentity();
-    }
-
-    /**
-     * Set the shader's local matrix. Passing null will reset the shader's
-     * matrix to identity
-     * @param localM The shader's new local matrix, or null to specify identity
-     */
-    public void setLocalMatrix(Matrix localM) {
-        if (localM != null) {
-            mMatrix.set(localM);
-        } else {
-            mMatrix.reset();
-        }
-    }
-
-    /**
-     * Returns a java.awt.Paint object matching this shader.
-     */
-    abstract java.awt.Paint getJavaPaint();
-}
diff --git a/bridge/src/android/graphics/Shader_Delegate.java b/bridge/src/android/graphics/Shader_Delegate.java
new file mode 100644
index 0000000..4dcf144
--- /dev/null
+++ b/bridge/src/android/graphics/Shader_Delegate.java
@@ -0,0 +1,112 @@
+/*
+ * 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.DelegateManager;
+
+/**
+ * Delegate implementing the native methods of android.graphics.Shader
+ *
+ * Through the layoutlib_create tool, the original native methods of Shader 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 Shader class.
+ *
+ * This also serve as a base class for all Shader delegate classes.
+ *
+ * @see DelegateManager
+ *
+ */
+public abstract class Shader_Delegate {
+
+    // ---- delegate manager ----
+    protected static final DelegateManager<Shader_Delegate> sManager =
+            new DelegateManager<Shader_Delegate>();
+
+    // ---- delegate helper data ----
+
+    // ---- delegate data ----
+    private int mLocalMatrix = 0;
+
+    // ---- Public Helper methods ----
+
+    public static Shader_Delegate getDelegate(int nativeShader) {
+        return sManager.getDelegate(nativeShader);
+    }
+
+    public abstract java.awt.Paint getJavaPaint();
+
+    // ---- native methods ----
+
+    /*package*/ static void nativeDestructor(int native_shader, int native_skiaShader) {
+        sManager.removeDelegate(native_shader);
+    }
+
+    /*package*/ static boolean nativeGetLocalMatrix(int native_shader, int matrix_instance) {
+        // get the delegate from the native int.
+        Shader_Delegate shaderDelegate = sManager.getDelegate(native_shader);
+        if (shaderDelegate == null) {
+            assert false;
+            return false;
+        }
+
+        Matrix_Delegate localMatrixDelegate = null;
+        if (shaderDelegate.mLocalMatrix > 0) {
+            localMatrixDelegate = Matrix_Delegate.getDelegate(shaderDelegate.mLocalMatrix);
+            if (localMatrixDelegate == null) {
+                assert false;
+                return false;
+            }
+        }
+
+        Matrix_Delegate destMatrixDelegate = null;
+        if (matrix_instance > 0) {
+            destMatrixDelegate = Matrix_Delegate.getDelegate(shaderDelegate.mLocalMatrix);
+            if (destMatrixDelegate == null) {
+                assert false;
+                return false;
+            }
+
+            if (localMatrixDelegate != null) {
+                destMatrixDelegate.set(localMatrixDelegate);
+            } else {
+                // since there's no local matrix, it's considered to be the identity, reset
+                // the destination matrix
+                destMatrixDelegate.reset();
+            }
+        }
+
+        return localMatrixDelegate == null || localMatrixDelegate.isIdentity();
+    }
+
+    /*package*/ static void nativeSetLocalMatrix(int native_shader, int native_skiaShader,
+            int matrix_instance) {
+        // get the delegate from the native int.
+        Shader_Delegate shaderDelegate = sManager.getDelegate(native_shader);
+        if (shaderDelegate == null) {
+            assert false;
+            return;
+        }
+
+        shaderDelegate.mLocalMatrix = matrix_instance;
+    }
+
+    // ---- Private delegate/helper methods ----
+
+}
diff --git a/bridge/src/android/graphics/SweepGradient.java b/bridge/src/android/graphics/SweepGradient_Delegate.java
similarity index 67%
rename from bridge/src/android/graphics/SweepGradient.java
rename to bridge/src/android/graphics/SweepGradient_Delegate.java
index 87036ed..0492e4f 100644
--- a/bridge/src/android/graphics/SweepGradient.java
+++ b/bridge/src/android/graphics/SweepGradient_Delegate.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2008 The Android Open Source Project
+ * 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.
@@ -16,9 +16,62 @@
 
 package android.graphics;
 
-public class SweepGradient extends GradientShader {
+import com.android.layoutlib.bridge.DelegateManager;
 
-    private SweepGradientPaint mPaint;
+import java.awt.Paint;
+
+/**
+ * Delegate implementing the native methods of android.graphics.SweepGradient
+ *
+ * Through the layoutlib_create tool, the original native methods of SweepGradient 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 SweepGradient 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 SweepGradient_Delegate extends Gradient_Delegate {
+
+    // ---- delegate data ----
+    private java.awt.Paint mJavaPaint;
+
+    // ---- Public Helper methods ----
+
+    @Override
+    public Paint getJavaPaint() {
+        return mJavaPaint;
+    }
+
+    // ---- native methods ----
+
+    /*package*/ static int nativeCreate1(float x, float y, int colors[], float positions[]) {
+        SweepGradient_Delegate newDelegate = new SweepGradient_Delegate(x, y, colors, positions);
+        return sManager.addDelegate(newDelegate);
+    }
+
+    /*package*/ static int nativeCreate2(float x, float y, int color0, int color1) {
+        return nativeCreate1(x, y, new int[] { color0, color1 }, null /*positions*/);
+    }
+
+    /*package*/ static int nativePostCreate1(int native_shader, float cx, float cy,
+            int[] colors, float[] positions) {
+        // nothing to be done here.
+        return 0;
+    }
+
+    /*package*/ static int nativePostCreate2(int native_shader, float cx, float cy,
+            int color0, int color1) {
+        // nothing to be done here.
+        return 0;
+    }
+
+    // ---- Private delegate/helper methods ----
 
     /**
      * A subclass of Shader that draws a sweep gradient around a center point.
@@ -34,28 +87,11 @@
      *                 If positions is NULL, then the colors are automatically
      *                 spaced evenly.
      */
-    public SweepGradient(float cx, float cy,
+    private SweepGradient_Delegate(float cx, float cy,
                          int colors[], float positions[]) {
         super(colors, positions);
 
-        mPaint = new SweepGradientPaint(cx, cy, mColors, mPositions);
-    }
-
-    /**
-     * A subclass of Shader that draws a sweep gradient around a center point.
-     *
-     * @param cx       The x-coordinate of the center
-     * @param cy       The y-coordinate of the center
-     * @param color0   The color to use at the start of the sweep
-     * @param color1   The color to use at the end of the sweep
-     */
-    public SweepGradient(float cx, float cy, int color0, int color1) {
-        this(cx, cy, new int[] { color0, color1}, null /*positions*/);
-    }
-
-    @Override
-    java.awt.Paint getJavaPaint() {
-        return mPaint;
+        mJavaPaint = new SweepGradientPaint(cx, cy, mColors, mPositions);
     }
 
     private static class SweepGradientPaint extends GradientPaint {
@@ -135,6 +171,4 @@
 
         }
     }
-
 }
-
diff --git a/create/src/com/android/tools/layoutlib/create/CreateInfo.java b/create/src/com/android/tools/layoutlib/create/CreateInfo.java
index c845cc4..2a6ef4d 100644
--- a/create/src/com/android/tools/layoutlib/create/CreateInfo.java
+++ b/create/src/com/android/tools/layoutlib/create/CreateInfo.java
@@ -105,8 +105,12 @@
     private final static String[] DELEGATE_CLASS_NATIVES = new String[] {
         "android.graphics.Bitmap",
         "android.graphics.Canvas",
+        "android.graphics.LinearGradient",
         "android.graphics.Matrix",
         "android.graphics.Paint",
+        "android.graphics.RadialGradient",
+        "android.graphics.Shader",
+        "android.graphics.SweepGradient",
         "android.graphics.Typeface",
     };
 
@@ -127,15 +131,9 @@
     private final static String[] RENAMED_CLASSES =
         new String[] {
             "android.graphics.BitmapFactory",       "android.graphics._Original_BitmapFactory",
-            "android.graphics.BitmapShader",        "android.graphics._Original_BitmapShader",
-            "android.graphics.ComposeShader",       "android.graphics._Original_ComposeShader",
             "android.graphics.DashPathEffect",       "android.graphics._Original_DashPathEffect",
-            "android.graphics.LinearGradient",      "android.graphics._Original_LinearGradient",
             "android.graphics.Path",                "android.graphics._Original_Path",
             "android.graphics.PorterDuffXfermode",  "android.graphics._Original_PorterDuffXfermode",
-            "android.graphics.RadialGradient",      "android.graphics._Original_RadialGradient",
-            "android.graphics.Shader",              "android.graphics._Original_Shader",
-            "android.graphics.SweepGradient",       "android.graphics._Original_SweepGradient",
             "android.os.ServiceManager",            "android.os._Original_ServiceManager",
             "android.util.FloatMath",               "android.util._Original_FloatMath",
             "android.view.SurfaceView",             "android.view._Original_SurfaceView",