FileDocCategorySizeDatePackage
Canvas_Delegate.javaAPI DocAndroid 5.1 API45339Thu Mar 12 22:22:44 GMT 2015android.graphics

Canvas_Delegate

public final class Canvas_Delegate extends Object
Delegate implementing the native methods of android.graphics.Canvas Through the layoutlib_create tool, the original native methods of Canvas 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 Canvas class.
see
DelegateManager

Fields Summary
private static final com.android.layoutlib.bridge.impl.DelegateManager
sManager
private static final boolean[]
sBoolOut
private Bitmap_Delegate
mBitmap
private com.android.layoutlib.bridge.impl.GcSnapshot
mSnapshot
private DrawFilter_Delegate
mDrawFilter
Constructors Summary
private Canvas_Delegate(Bitmap_Delegate bitmap)

        mSnapshot = GcSnapshot.createDefaultSnapshot(mBitmap = bitmap);
    
private Canvas_Delegate()

        mSnapshot = GcSnapshot.createDefaultSnapshot(null /*image*/);
    
Methods Summary
private booleanclipRect(float left, float top, float right, float bottom, int regionOp)

        return mSnapshot.clipRect(left, top, right, bottom, regionOp);
    
private voiddispose()
Disposes of the {@link Graphics2D} stack.

        mSnapshot.dispose();
    
private static voiddraw(long nCanvas, long nPaint, boolean compositeOnly, boolean forceSrcMode, GcSnapshot.Drawable drawable)
Executes a {@link GcSnapshot.Drawable} with a given canvas and paint.

Note that the drawable may actually be executed several times if there are layers involved (see {@link #saveLayer(RectF, Paint_Delegate, int)}.

        // get the delegate from the native int.
        Canvas_Delegate canvasDelegate = sManager.getDelegate(nCanvas);
        if (canvasDelegate == null) {
            return;
        }

        // get the paint which can be null if nPaint is 0;
        Paint_Delegate paintDelegate = Paint_Delegate.getDelegate(nPaint);

        canvasDelegate.getSnapshot().draw(drawable, paintDelegate, compositeOnly, forceSrcMode);
    
private static voiddraw(long nCanvas, GcSnapshot.Drawable drawable)
Executes a {@link GcSnapshot.Drawable} with a given canvas. No paint object will be provided to {@link GcSnapshot.Drawable#draw(Graphics2D, Paint_Delegate)}.

Note that the drawable may actually be executed several times if there are layers involved (see {@link #saveLayer(RectF, Paint_Delegate, int)}.

        // get the delegate from the native int.
        Canvas_Delegate canvasDelegate = sManager.getDelegate(nCanvas);
        if (canvasDelegate == null) {
            return;
        }

        canvasDelegate.mSnapshot.draw(drawable);
    
private static voiddrawBitmap(long nativeCanvas, Bitmap_Delegate bitmap, long nativePaintOrZero, int sleft, int stop, int sright, int sbottom, int dleft, int dtop, int dright, int dbottom)

        // get the delegate from the native int.
        Canvas_Delegate canvasDelegate = sManager.getDelegate(nativeCanvas);
        if (canvasDelegate == null) {
            return;
        }

        // get the paint, which could be null if the int is 0
        Paint_Delegate paintDelegate = Paint_Delegate.getDelegate(nativePaintOrZero);

        final BufferedImage image = getImageToDraw(bitmap, paintDelegate, sBoolOut);

        draw(nativeCanvas, nativePaintOrZero, true /*compositeOnly*/, sBoolOut[0],
                new GcSnapshot.Drawable() {
                    @Override
                    public void draw(Graphics2D graphics, Paint_Delegate paint) {
                        if (paint != null && paint.isFilterBitmap()) {
                            graphics.setRenderingHint(RenderingHints.KEY_INTERPOLATION,
                                    RenderingHints.VALUE_INTERPOLATION_BILINEAR);
                        }

                        //FIXME add support for canvas, screen and bitmap densities.
                        graphics.drawImage(image, dleft, dtop, dright, dbottom,
                                sleft, stop, sright, sbottom, null);
                    }
        });
    
private static voiddrawText(long nativeCanvas, char[] text, int index, int count, float startX, float startY, boolean isRtl, long paint, long typeface)


        draw(nativeCanvas, paint, false /*compositeOnly*/, false /*forceSrcMode*/,
                new GcSnapshot.Drawable() {
            @Override
            public void draw(Graphics2D graphics, Paint_Delegate paintDelegate) {
                // WARNING: the logic in this method is similar to Paint_Delegate.measureText.
                // Any change to this method should be reflected in Paint.measureText

                // assert that the typeface passed is actually the one stored in paint.
                assert (typeface == paintDelegate.mNativeTypeface);

                // Paint.TextAlign indicates how the text is positioned relative to X.
                // LEFT is the default and there's nothing to do.
                float x = startX;
                int limit = index + count;
                if (paintDelegate.getTextAlign() != Paint.Align.LEFT.nativeInt) {
                    RectF bounds = paintDelegate.measureText(text, index, count, null, 0,
                            isRtl);
                    float m = bounds.right - bounds.left;
                    if (paintDelegate.getTextAlign() == Paint.Align.CENTER.nativeInt) {
                        x -= m / 2;
                    } else if (paintDelegate.getTextAlign() == Paint.Align.RIGHT.nativeInt) {
                        x -= m;
                    }
                }

                new BidiRenderer(graphics, paintDelegate, text).setRenderLocation(x, startY)
                        .renderText(index, limit, isRtl, null, 0, true);
            }
        });
    
static voidfinalizer(long nativeCanvas)

        // get the delegate from the native int so that it can be disposed.
        Canvas_Delegate canvasDelegate = sManager.getDelegate(nativeCanvas);
        if (canvasDelegate == null) {
            return;
        }

        canvasDelegate.dispose();

        // remove it from the manager.
        sManager.removeJavaReferenceFor(nativeCanvas);
    
private static voidfixAlpha8Bitmap(java.awt.image.BufferedImage image)

        int w = image.getWidth();
        int h = image.getHeight();
        int[] argb = new int[w * h];
        image.getRGB(0, 0, image.getWidth(), image.getHeight(), argb, 0, image.getWidth());

        final int length = argb.length;
        for (int i = 0 ; i < length; i++) {
            argb[i] &= 0xFF000000;
        }
        image.setRGB(0, 0, w, h, argb, 0, w);
    
static voidfreeCaches()

        // nothing to be done here.
    
static voidfreeTextLayoutCaches()

        // nothing to be done here yet.
    
public static android.graphics.Canvas_DelegategetDelegate(Canvas canvas)
Returns the native delegate associated to a given {@link Canvas} object.



    // ---- Public Helper methods ----

                    
         
        return sManager.getDelegate(canvas.getNativeCanvasWrapper());
    
public static android.graphics.Canvas_DelegategetDelegate(long native_canvas)
Returns the native delegate associated to a given an int referencing a {@link Canvas} object.

        return sManager.getDelegate(native_canvas);
    
public DrawFilter_DelegategetDrawFilter()
Returns the {@link DrawFilter} delegate or null if none have been set.

return
the delegate or null.

        return mDrawFilter;
    
private static java.awt.image.BufferedImagegetImageToDraw(Bitmap_Delegate bitmap, Paint_Delegate paint, boolean[] forceSrcMode)
Returns a BufferedImage ready for drawing, based on the bitmap and paint delegate. The image returns, through a 1-size boolean array, whether the drawing code should use a SRC composite no matter what the paint says.

param
bitmap the bitmap
param
paint the paint that will be used to draw
param
forceSrcMode whether the composite will have to be SRC
return
the image to draw

        BufferedImage image = bitmap.getImage();
        forceSrcMode[0] = false;

        // if the bitmap config is alpha_8, then we erase all color value from it
        // before drawing it.
        if (bitmap.getConfig() == Bitmap.Config.ALPHA_8) {
            fixAlpha8Bitmap(image);
        } else if (bitmap.hasAlpha() == false) {
            // hasAlpha is merely a rendering hint. There can in fact be alpha values
            // in the bitmap but it should be ignored at drawing time.
            // There is two ways to do this:
            // - override the composite to be SRC. This can only be used if the composite
            //   was going to be SRC or SRC_OVER in the first place
            // - Create a different bitmap to draw in which all the alpha channel values is set
            //   to 0xFF.
            if (paint != null) {
                Xfermode_Delegate xfermodeDelegate = paint.getXfermode();
                if (xfermodeDelegate instanceof PorterDuffXfermode_Delegate) {
                    PorterDuff.Mode mode =
                        ((PorterDuffXfermode_Delegate)xfermodeDelegate).getMode();

                    forceSrcMode[0] = mode == PorterDuff.Mode.SRC_OVER ||
                            mode == PorterDuff.Mode.SRC;
                }
            }

            // if we can't force SRC mode, then create a temp bitmap of TYPE_RGB
            if (forceSrcMode[0] == false) {
                image = Bitmap_Delegate.createCopy(image, BufferedImage.TYPE_INT_RGB, 0xFF);
            }
        }

        return image;
    
public com.android.layoutlib.bridge.impl.GcSnapshotgetSnapshot()
Returns the current {@link Graphics2D} used to draw.

        return mSnapshot;
    
static longinitRaster(long nativeBitmapOrZero)

        if (nativeBitmapOrZero > 0) {
            // get the Bitmap from the int
            Bitmap_Delegate bitmapDelegate = Bitmap_Delegate.getDelegate(nativeBitmapOrZero);

            // create a new Canvas_Delegate with the given bitmap and return its new native int.
            Canvas_Delegate newDelegate = new Canvas_Delegate(bitmapDelegate);

            return sManager.addNewDelegate(newDelegate);
        }

        // create a new Canvas_Delegate and return its new native int.
        Canvas_Delegate newDelegate = new Canvas_Delegate();

        return sManager.addNewDelegate(newDelegate);
    
static voidnativeDrawBitmapMatrix(long nCanvas, long nBitmap, long nMatrix, long nPaint)

        // get the delegate from the native int.
        Canvas_Delegate canvasDelegate = sManager.getDelegate(nCanvas);
        if (canvasDelegate == null) {
            return;
        }

        // get the delegate from the native int, which can be null
        Paint_Delegate paintDelegate = Paint_Delegate.getDelegate(nPaint);

        // get the delegate from the native int.
        Bitmap_Delegate bitmapDelegate = Bitmap_Delegate.getDelegate(nBitmap);
        if (bitmapDelegate == null) {
            return;
        }

        final BufferedImage image = getImageToDraw(bitmapDelegate, paintDelegate, sBoolOut);

        Matrix_Delegate matrixDelegate = Matrix_Delegate.getDelegate(nMatrix);
        if (matrixDelegate == null) {
            return;
        }

        final AffineTransform mtx = matrixDelegate.getAffineTransform();

        canvasDelegate.getSnapshot().draw(new GcSnapshot.Drawable() {
                @Override
                public void draw(Graphics2D graphics, Paint_Delegate paint) {
                    if (paint != null && paint.isFilterBitmap()) {
                        graphics.setRenderingHint(RenderingHints.KEY_INTERPOLATION,
                                RenderingHints.VALUE_INTERPOLATION_BILINEAR);
                    }

                    //FIXME add support for canvas, screen and bitmap densities.
                    graphics.drawImage(image, mtx, null);
                }
        }, paintDelegate, true /*compositeOnly*/, false /*forceSrcMode*/);
    
static voidnativeDrawBitmapMesh(long nCanvas, long nBitmap, int meshWidth, int meshHeight, float[] verts, int vertOffset, int[] colors, int colorOffset, long nPaint)

        // FIXME
        Bridge.getLog().fidelityWarning(LayoutLog.TAG_UNSUPPORTED,
                "Canvas.drawBitmapMesh is not supported.", null, null /*data*/);
    
static voidnativeDrawVertices(long nCanvas, int mode, int n, float[] verts, int vertOffset, float[] texs, int texOffset, int[] colors, int colorOffset, short[] indices, int indexOffset, int indexCount, long nPaint)

        // FIXME
        Bridge.getLog().fidelityWarning(LayoutLog.TAG_UNSUPPORTED,
                "Canvas.drawVertices is not supported.", null, null /*data*/);
    
static voidnativeSetDrawFilter(long nativeCanvas, long nativeFilter)

        Canvas_Delegate canvasDelegate = sManager.getDelegate(nativeCanvas);
        if (canvasDelegate == null) {
            return;
        }

        canvasDelegate.mDrawFilter = DrawFilter_Delegate.getDelegate(nativeFilter);

        if (canvasDelegate.mDrawFilter != null &&
                canvasDelegate.mDrawFilter.isSupported() == false) {
            Bridge.getLog().fidelityWarning(LayoutLog.TAG_DRAWFILTER,
                    canvasDelegate.mDrawFilter.getSupportMessage(), null, null /*data*/);
        }
    
static booleannative_clipPath(long nativeCanvas, long nativePath, int regionOp)

        Canvas_Delegate canvasDelegate = sManager.getDelegate(nativeCanvas);
        if (canvasDelegate == null) {
            return true;
        }

        Path_Delegate pathDelegate = Path_Delegate.getDelegate(nativePath);
        if (pathDelegate == null) {
            return true;
        }

        return canvasDelegate.mSnapshot.clip(pathDelegate.getJavaShape(), regionOp);
    
static booleannative_clipRect(long nCanvas, float left, float top, float right, float bottom, int regionOp)

        // get the delegate from the native int.
        Canvas_Delegate canvasDelegate = sManager.getDelegate(nCanvas);
        if (canvasDelegate == null) {
            return false;
        }

        return canvasDelegate.clipRect(left, top, right, bottom, regionOp);
    
static booleannative_clipRegion(long nativeCanvas, long nativeRegion, int regionOp)

        Canvas_Delegate canvasDelegate = sManager.getDelegate(nativeCanvas);
        if (canvasDelegate == null) {
            return true;
        }

        Region_Delegate region = Region_Delegate.getDelegate(nativeRegion);
        if (region == null) {
            return true;
        }

        return canvasDelegate.mSnapshot.clip(region.getJavaArea(), regionOp);
    
static voidnative_concat(long nCanvas, long nMatrix)

        // get the delegate from the native int.
        Canvas_Delegate canvasDelegate = sManager.getDelegate(nCanvas);
        if (canvasDelegate == null) {
            return;
        }

        Matrix_Delegate matrixDelegate = Matrix_Delegate.getDelegate(nMatrix);
        if (matrixDelegate == null) {
            return;
        }

        // get the current top graphics2D object.
        GcSnapshot snapshot = canvasDelegate.getSnapshot();

        // get its current matrix
        AffineTransform currentTx = snapshot.getTransform();
        // get the AffineTransform of the given matrix
        AffineTransform matrixTx = matrixDelegate.getAffineTransform();

        // combine them so that the given matrix is applied after.
        currentTx.concatenate(matrixTx);

        // give it to the graphics2D as a new matrix replacing all previous transform
        snapshot.setTransform(currentTx);
    
static voidnative_drawArc(long nativeCanvas, float left, float top, float right, float bottom, float startAngle, float sweep, boolean useCenter, long paint)

        if (right > left && bottom > top) {
            draw(nativeCanvas, paint, false /*compositeOnly*/, false /*forceSrcMode*/,
                    new GcSnapshot.Drawable() {
                        @Override
                        public void draw(Graphics2D graphics, Paint_Delegate paintDelegate) {
                            int style = paintDelegate.getStyle();

                            Arc2D.Float arc = new Arc2D.Float(
                                    left, top, right - left, bottom - top,
                                    -startAngle, -sweep,
                                    useCenter ? Arc2D.PIE : Arc2D.OPEN);

                            // draw
                            if (style == Paint.Style.FILL.nativeInt ||
                                    style == Paint.Style.FILL_AND_STROKE.nativeInt) {
                                graphics.fill(arc);
                            }

                            if (style == Paint.Style.STROKE.nativeInt ||
                                    style == Paint.Style.FILL_AND_STROKE.nativeInt) {
                                graphics.draw(arc);
                            }
                        }
            });
        }
    
static voidnative_drawBitmap(Canvas thisCanvas, long nativeCanvas, long bitmap, float left, float top, long nativePaintOrZero, int canvasDensity, int screenDensity, int bitmapDensity)

        // get the delegate from the native int.
        Bitmap_Delegate bitmapDelegate = Bitmap_Delegate.getDelegate(bitmap);
        if (bitmapDelegate == null) {
            return;
        }

        BufferedImage image = bitmapDelegate.getImage();
        float right = left + image.getWidth();
        float bottom = top + image.getHeight();

        drawBitmap(nativeCanvas, bitmapDelegate, nativePaintOrZero,
                0, 0, image.getWidth(), image.getHeight(),
                (int)left, (int)top, (int)right, (int)bottom);
    
static voidnative_drawBitmap(Canvas thisCanvas, long nativeCanvas, long bitmap, float srcLeft, float srcTop, float srcRight, float srcBottom, float dstLeft, float dstTop, float dstRight, float dstBottom, long nativePaintOrZero, int screenDensity, int bitmapDensity)

        // get the delegate from the native int.
        Bitmap_Delegate bitmapDelegate = Bitmap_Delegate.getDelegate(bitmap);
        if (bitmapDelegate == null) {
            return;
        }

        drawBitmap(nativeCanvas, bitmapDelegate, nativePaintOrZero,
                (int)srcLeft, (int)srcTop, (int)srcRight, (int)srcBottom,
                (int)dstLeft, (int)dstTop, (int)dstRight, (int)dstBottom);
    
static voidnative_drawBitmap(long nativeCanvas, int[] colors, int offset, int stride, float x, float y, int width, int height, boolean hasAlpha, long nativePaintOrZero)

        // create a temp BufferedImage containing the content.
        final BufferedImage image = new BufferedImage(width, height,
                hasAlpha ? BufferedImage.TYPE_INT_ARGB : BufferedImage.TYPE_INT_RGB);
        image.setRGB(0, 0, width, height, colors, offset, stride);

        draw(nativeCanvas, nativePaintOrZero, true /*compositeOnly*/, false /*forceSrcMode*/,
                new GcSnapshot.Drawable() {
                    @Override
                    public void draw(Graphics2D graphics, Paint_Delegate paint) {
                        if (paint != null && paint.isFilterBitmap()) {
                            graphics.setRenderingHint(RenderingHints.KEY_INTERPOLATION,
                                    RenderingHints.VALUE_INTERPOLATION_BILINEAR);
                        }

                        graphics.drawImage(image, (int) x, (int) y, null);
                    }
        });
    
static voidnative_drawCircle(long nativeCanvas, float cx, float cy, float radius, long paint)

        native_drawOval(nativeCanvas,
                cx - radius, cy - radius, cx + radius, cy + radius,
                paint);
    
static voidnative_drawColor(long nativeCanvas, int color, int mode)

        // get the delegate from the native int.
        Canvas_Delegate canvasDelegate = sManager.getDelegate(nativeCanvas);
        if (canvasDelegate == null) {
            return;
        }

        final int w = canvasDelegate.mBitmap.getImage().getWidth();
        final int h = canvasDelegate.mBitmap.getImage().getHeight();
        draw(nativeCanvas, new GcSnapshot.Drawable() {

            @Override
            public void draw(Graphics2D graphics, Paint_Delegate paint) {
                // reset its transform just in case
                graphics.setTransform(new AffineTransform());

                // set the color
                graphics.setColor(new Color(color, true /*alpha*/));

                Composite composite = PorterDuffUtility.getComposite(
                        PorterDuffUtility.getPorterDuffMode(mode), 0xFF);
                if (composite != null) {
                    graphics.setComposite(composite);
                }

                graphics.fillRect(0, 0, w, h);
            }
        });
    
static voidnative_drawLine(long nativeCanvas, float startX, float startY, float stopX, float stopY, long paint)

        draw(nativeCanvas, paint, false /*compositeOnly*/, false /*forceSrcMode*/,
                new GcSnapshot.Drawable() {
                    @Override
                    public void draw(Graphics2D graphics, Paint_Delegate paintDelegate) {
                        graphics.drawLine((int)startX, (int)startY, (int)stopX, (int)stopY);
                    }
        });
    
static voidnative_drawLines(long nativeCanvas, float[] pts, int offset, int count, long nativePaint)

        draw(nativeCanvas, nativePaint, false /*compositeOnly*/,
                false /*forceSrcMode*/, new GcSnapshot.Drawable() {
                    @Override
                    public void draw(Graphics2D graphics, Paint_Delegate paintDelegate) {
                        for (int i = 0; i < count; i += 4) {
                            graphics.drawLine((int) pts[i + offset], (int) pts[i + offset + 1],
                                    (int) pts[i + offset + 2], (int) pts[i + offset + 3]);
                        }
                    }
                });
    
static voidnative_drawOval(long nativeCanvas, float left, float top, float right, float bottom, long paint)

        if (right > left && bottom > top) {
            draw(nativeCanvas, paint, false /*compositeOnly*/, false /*forceSrcMode*/,
                    new GcSnapshot.Drawable() {
                        @Override
                        public void draw(Graphics2D graphics, Paint_Delegate paintDelegate) {
                            int style = paintDelegate.getStyle();

                            // draw
                            if (style == Paint.Style.FILL.nativeInt ||
                                    style == Paint.Style.FILL_AND_STROKE.nativeInt) {
                                graphics.fillOval((int)left, (int)top,
                                        (int)(right - left), (int)(bottom - top));
                            }

                            if (style == Paint.Style.STROKE.nativeInt ||
                                    style == Paint.Style.FILL_AND_STROKE.nativeInt) {
                                graphics.drawOval((int)left, (int)top,
                                        (int)(right - left), (int)(bottom - top));
                            }
                        }
            });
        }
    
static voidnative_drawPaint(long nativeCanvas, long paint)

        // FIXME
        Bridge.getLog().fidelityWarning(LayoutLog.TAG_UNSUPPORTED,
                "Canvas.drawPaint is not supported.", null, null /*data*/);
    
static voidnative_drawPath(long nativeCanvas, long path, long paint)

        final Path_Delegate pathDelegate = Path_Delegate.getDelegate(path);
        if (pathDelegate == null) {
            return;
        }

        draw(nativeCanvas, paint, false /*compositeOnly*/, false /*forceSrcMode*/,
                new GcSnapshot.Drawable() {
                    @Override
                    public void draw(Graphics2D graphics, Paint_Delegate paintDelegate) {
                        Shape shape = pathDelegate.getJavaShape();
                        int style = paintDelegate.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);
                        }
                    }
        });
    
static voidnative_drawPoint(long nativeCanvas, float x, float y, long nativePaint)

        // FIXME
        Bridge.getLog().fidelityWarning(LayoutLog.TAG_UNSUPPORTED,
                "Canvas.drawPoint is not supported.", null, null /*data*/);
    
static voidnative_drawPoints(long nativeCanvas, float[] pts, int offset, int count, long nativePaint)

        // FIXME
        Bridge.getLog().fidelityWarning(LayoutLog.TAG_UNSUPPORTED,
                "Canvas.drawPoint is not supported.", null, null /*data*/);
    
static voidnative_drawRect(long nativeCanvas, float left, float top, float right, float bottom, long paint)


        draw(nativeCanvas, paint, false /*compositeOnly*/, false /*forceSrcMode*/,
                new GcSnapshot.Drawable() {
                    @Override
                    public void draw(Graphics2D graphics, Paint_Delegate paintDelegate) {
                        int style = paintDelegate.getStyle();

                        // draw
                        if (style == Paint.Style.FILL.nativeInt ||
                                style == Paint.Style.FILL_AND_STROKE.nativeInt) {
                            graphics.fillRect((int)left, (int)top,
                                    (int)(right-left), (int)(bottom-top));
                        }

                        if (style == Paint.Style.STROKE.nativeInt ||
                                style == Paint.Style.FILL_AND_STROKE.nativeInt) {
                            graphics.drawRect((int)left, (int)top,
                                    (int)(right-left), (int)(bottom-top));
                        }
                    }
        });
    
static voidnative_drawRoundRect(long nativeCanvas, float left, float top, float right, float bottom, float rx, float ry, long paint)

        draw(nativeCanvas, paint, false /*compositeOnly*/, false /*forceSrcMode*/,
                new GcSnapshot.Drawable() {
                    @Override
                    public void draw(Graphics2D graphics, Paint_Delegate paintDelegate) {
                        int style = paintDelegate.getStyle();

                        // draw
                        if (style == Paint.Style.FILL.nativeInt ||
                                style == Paint.Style.FILL_AND_STROKE.nativeInt) {
                            graphics.fillRoundRect(
                                    (int)left, (int)top,
                                    (int)(right - left), (int)(bottom - top),
                                    (int)rx, (int)ry);
                        }

                        if (style == Paint.Style.STROKE.nativeInt ||
                                style == Paint.Style.FILL_AND_STROKE.nativeInt) {
                            graphics.drawRoundRect(
                                    (int)left, (int)top,
                                    (int)(right - left), (int)(bottom - top),
                                    (int)rx, (int)ry);
                        }
                    }
        });
    
static voidnative_drawText(long nativeCanvas, char[] text, int index, int count, float startX, float startY, int flags, long paint, long typeface)

        drawText(nativeCanvas, text, index, count, startX, startY, flags == Canvas.DIRECTION_RTL,
                paint, typeface);
    
static voidnative_drawText(long nativeCanvas, java.lang.String text, int start, int end, float x, float y, int flags, long paint, long typeface)

        int count = end - start;
        char[] buffer = TemporaryBuffer.obtain(count);
        TextUtils.getChars(text, start, end, buffer, 0);

        native_drawText(nativeCanvas, buffer, 0, count, x, y, flags, paint, typeface);
    
static voidnative_drawTextOnPath(long nativeCanvas, char[] text, int index, int count, long path, float hOffset, float vOffset, int bidiFlags, long paint, long typeface)

        // FIXME
        Bridge.getLog().fidelityWarning(LayoutLog.TAG_UNSUPPORTED,
                "Canvas.drawTextOnPath is not supported.", null, null /*data*/);
    
static voidnative_drawTextOnPath(long nativeCanvas, java.lang.String text, long path, float hOffset, float vOffset, int bidiFlags, long paint, long typeface)

        // FIXME
        Bridge.getLog().fidelityWarning(LayoutLog.TAG_UNSUPPORTED,
                "Canvas.drawTextOnPath is not supported.", null, null /*data*/);
    
static voidnative_drawTextRun(long nativeCanvas, java.lang.String text, int start, int end, int contextStart, int contextEnd, float x, float y, boolean isRtl, long paint, long typeface)

        int count = end - start;
        char[] buffer = TemporaryBuffer.obtain(count);
        TextUtils.getChars(text, start, end, buffer, 0);

        drawText(nativeCanvas, buffer, 0, count, x, y, isRtl, paint, typeface);
    
static voidnative_drawTextRun(long nativeCanvas, char[] text, int start, int count, int contextStart, int contextCount, float x, float y, boolean isRtl, long paint, long typeface)

        drawText(nativeCanvas, text, start, count, x, y, isRtl, paint, typeface);
    
static voidnative_getCTM(long canvas, long matrix)

        // get the delegate from the native int.
        Canvas_Delegate canvasDelegate = sManager.getDelegate(canvas);
        if (canvasDelegate == null) {
            return;
        }

        Matrix_Delegate matrixDelegate = Matrix_Delegate.getDelegate(matrix);
        if (matrixDelegate == null) {
            return;
        }

        AffineTransform transform = canvasDelegate.getSnapshot().getTransform();
        matrixDelegate.set(Matrix_Delegate.makeValues(transform));
    
static booleannative_getClipBounds(long nativeCanvas, Rect bounds)

        // get the delegate from the native int.
        Canvas_Delegate canvasDelegate = sManager.getDelegate(nativeCanvas);
        if (canvasDelegate == null) {
            return false;
        }

        Rectangle rect = canvasDelegate.getSnapshot().getClip().getBounds();
        if (rect != null && rect.isEmpty() == false) {
            bounds.left = rect.x;
            bounds.top = rect.y;
            bounds.right = rect.x + rect.width;
            bounds.bottom = rect.y + rect.height;
            return true;
        }

        return false;
    
static intnative_getHeight(long nativeCanvas)

        // get the delegate from the native int.
        Canvas_Delegate canvasDelegate = sManager.getDelegate(nativeCanvas);
        if (canvasDelegate == null) {
            return 0;
        }

        return canvasDelegate.mBitmap.getImage().getHeight();
    
static intnative_getSaveCount(long nativeCanvas)

        // get the delegate from the native int.
        Canvas_Delegate canvasDelegate = sManager.getDelegate(nativeCanvas);
        if (canvasDelegate == null) {
            return 0;
        }

        return canvasDelegate.getSnapshot().size();
    
static intnative_getWidth(long nativeCanvas)

        // get the delegate from the native int.
        Canvas_Delegate canvasDelegate = sManager.getDelegate(nativeCanvas);
        if (canvasDelegate == null) {
            return 0;
        }

        return canvasDelegate.mBitmap.getImage().getWidth();
    
static booleannative_isOpaque(long nativeCanvas)

        // get the delegate from the native int.
        Canvas_Delegate canvasDelegate = sManager.getDelegate(nativeCanvas);
        if (canvasDelegate == null) {
            return false;
        }

        return canvasDelegate.mBitmap.getConfig() == Config.RGB_565;
    
static booleannative_quickReject(long nativeCanvas, long path)

        // FIXME properly implement quickReject
        return false;
    
static booleannative_quickReject(long nativeCanvas, float left, float top, float right, float bottom)

        // FIXME properly implement quickReject
        return false;
    
static voidnative_restore(long nativeCanvas)

        // get the delegate from the native int.
        Canvas_Delegate canvasDelegate = sManager.getDelegate(nativeCanvas);
        if (canvasDelegate == null) {
            return;
        }

        canvasDelegate.restore();
    
static voidnative_restoreToCount(long nativeCanvas, int saveCount)

        // get the delegate from the native int.
        Canvas_Delegate canvasDelegate = sManager.getDelegate(nativeCanvas);
        if (canvasDelegate == null) {
            return;
        }

        canvasDelegate.restoreTo(saveCount);
    
static voidnative_rotate(long nativeCanvas, float degrees)

        // get the delegate from the native int.
        Canvas_Delegate canvasDelegate = sManager.getDelegate(nativeCanvas);
        if (canvasDelegate == null) {
            return;
        }

        canvasDelegate.getSnapshot().rotate(Math.toRadians(degrees));
    
static intnative_save(long nativeCanvas, int saveFlags)

        // get the delegate from the native int.
        Canvas_Delegate canvasDelegate = sManager.getDelegate(nativeCanvas);
        if (canvasDelegate == null) {
            return 0;
        }

        return canvasDelegate.save(saveFlags);
    
static intnative_saveLayer(long nativeCanvas, float l, float t, float r, float b, long paint, int layerFlags)

        // get the delegate from the native int.
        Canvas_Delegate canvasDelegate = sManager.getDelegate(nativeCanvas);
        if (canvasDelegate == null) {
            return 0;
        }

        Paint_Delegate paintDelegate = Paint_Delegate.getDelegate(paint);
        if (paintDelegate == null) {
            return 0;
        }

        return canvasDelegate.saveLayer(new RectF(l, t, r, b),
                paintDelegate, layerFlags);
    
static intnative_saveLayerAlpha(long nativeCanvas, float l, float t, float r, float b, int alpha, int layerFlags)

        // get the delegate from the native int.
        Canvas_Delegate canvasDelegate = sManager.getDelegate(nativeCanvas);
        if (canvasDelegate == null) {
            return 0;
        }

        return canvasDelegate.saveLayerAlpha(new RectF(l, t, r, b), alpha, layerFlags);
    
static voidnative_scale(long nativeCanvas, float sx, float sy)

            // get the delegate from the native int.
            Canvas_Delegate canvasDelegate = sManager.getDelegate(nativeCanvas);
            if (canvasDelegate == null) {
                return;
            }

            canvasDelegate.getSnapshot().scale(sx, sy);
        
static voidnative_setBitmap(long canvas, long bitmap, boolean copyState)

        Canvas_Delegate canvasDelegate = sManager.getDelegate(canvas);
        Bitmap_Delegate bitmapDelegate = Bitmap_Delegate.getDelegate(bitmap);
        if (canvasDelegate == null || bitmapDelegate==null) {
            return;
        }
        canvasDelegate.mBitmap = bitmapDelegate;
        canvasDelegate.mSnapshot = GcSnapshot.createDefaultSnapshot(bitmapDelegate);
    
static voidnative_setMatrix(long nCanvas, long nMatrix)

        // get the delegate from the native int.
        Canvas_Delegate canvasDelegate = sManager.getDelegate(nCanvas);
        if (canvasDelegate == null) {
            return;
        }

        Matrix_Delegate matrixDelegate = Matrix_Delegate.getDelegate(nMatrix);
        if (matrixDelegate == null) {
            return;
        }

        // get the current top graphics2D object.
        GcSnapshot snapshot = canvasDelegate.getSnapshot();

        // get the AffineTransform of the given matrix
        AffineTransform matrixTx = matrixDelegate.getAffineTransform();

        // give it to the graphics2D as a new matrix replacing all previous transform
        snapshot.setTransform(matrixTx);

        if (matrixDelegate.hasPerspective()) {
            assert false;
            Bridge.getLog().fidelityWarning(LayoutLog.TAG_MATRIX_AFFINE,
                    "android.graphics.Canvas#setMatrix(android.graphics.Matrix) only " +
                    "supports affine transformations.", null, null /*data*/);
        }
    
static voidnative_skew(long nativeCanvas, float kx, float ky)

        // get the delegate from the native int.
        Canvas_Delegate canvasDelegate = sManager.getDelegate(nativeCanvas);
        if (canvasDelegate == null) {
            return;
        }

        // get the current top graphics2D object.
        GcSnapshot g = canvasDelegate.getSnapshot();

        // get its current matrix
        AffineTransform currentTx = g.getTransform();
        // get the AffineTransform for the given skew.
        float[] mtx = Matrix_Delegate.getSkew(kx, ky);
        AffineTransform matrixTx = Matrix_Delegate.getAffineTransform(mtx);

        // combine them so that the given matrix is applied after.
        currentTx.preConcatenate(matrixTx);

        // give it to the graphics2D as a new matrix replacing all previous transform
        g.setTransform(currentTx);
    
static voidnative_translate(long nativeCanvas, float dx, float dy)

        // get the delegate from the native int.
        Canvas_Delegate canvasDelegate = sManager.getDelegate(nativeCanvas);
        if (canvasDelegate == null) {
            return;
        }

        canvasDelegate.getSnapshot().translate(dx, dy);
    
private voidrestore()
Restores the {@link GcSnapshot} to saveCount

param
saveCount the saveCount

        mSnapshot = mSnapshot.restore();
    
private voidrestoreTo(int saveCount)
Restores the {@link GcSnapshot} to saveCount

param
saveCount the saveCount

        mSnapshot = mSnapshot.restoreTo(saveCount);
    
private intsave(int saveFlags)

        // get the current save count
        int count = mSnapshot.size();

        mSnapshot = mSnapshot.save(saveFlags);

        // return the old save count
        return count;
    
private intsaveLayer(RectF rect, Paint_Delegate paint, int saveFlags)

        // get the current save count
        int count = mSnapshot.size();

        mSnapshot = mSnapshot.saveLayer(rect, paint, saveFlags);

        // return the old save count
        return count;
    
private intsaveLayerAlpha(RectF rect, int alpha, int saveFlags)

        Paint_Delegate paint = new Paint_Delegate();
        paint.setAlpha(alpha);
        return saveLayer(rect, paint, saveFlags);