1/*
2 * Copyright (C) 2008 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 *      http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17package android.graphics;
18
19import com.android.layoutlib.api.ILayoutLog;
20
21import android.graphics.DrawFilter;
22import android.graphics.Picture;
23import android.graphics.PorterDuff;
24import android.graphics.Rect;
25import android.graphics.RectF;
26import android.graphics.Region;
27import android.graphics.Xfermode;
28import android.graphics.Paint.Align;
29import android.graphics.Paint.Style;
30import android.graphics.Region.Op;
31
32import java.awt.AlphaComposite;
33import java.awt.Color;
34import java.awt.Composite;
35import java.awt.Graphics2D;
36import java.awt.Rectangle;
37import java.awt.RenderingHints;
38import java.awt.geom.AffineTransform;
39import java.awt.image.BufferedImage;
40import java.util.Stack;
41
42import javax.microedition.khronos.opengles.GL;
43
44/**
45 * Re-implementation of the Canvas, 100% in java on top of a BufferedImage.
46 */
47public class Canvas extends _Original_Canvas {
48
49    private BufferedImage mBufferedImage;
50    private final Stack<Graphics2D> mGraphicsStack = new Stack<Graphics2D>();
51    private final ILayoutLog mLogger;
52
53    public Canvas() {
54        mLogger = null;
55        // the mBufferedImage will be taken from a bitmap in #setBitmap()
56    }
57
58    public Canvas(Bitmap bitmap) {
59        mLogger = null;
60        mBufferedImage = bitmap.getImage();
61        mGraphicsStack.push(mBufferedImage.createGraphics());
62    }
63
64    public Canvas(int nativeCanvas) {
65        mLogger = null;
66        throw new UnsupportedOperationException("Can't create Canvas(int)");
67    }
68
69    public Canvas(javax.microedition.khronos.opengles.GL gl) {
70        mLogger = null;
71        throw new UnsupportedOperationException("Can't create Canvas(javax.microedition.khronos.opengles.GL)");
72    }
73
74    // custom constructors for our use.
75    public Canvas(int width, int height, ILayoutLog logger) {
76        mLogger = logger;
77        mBufferedImage = new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB);
78        mGraphicsStack.push(mBufferedImage.createGraphics());
79    }
80
81    public Canvas(int width, int height) {
82        this(width, height, null /* logger*/);
83    }
84
85    // custom mehtods
86    public BufferedImage getImage() {
87        return mBufferedImage;
88    }
89
90    public Graphics2D getGraphics2d() {
91        return mGraphicsStack.peek();
92    }
93
94    public void dispose() {
95        while (mGraphicsStack.size() > 0) {
96            mGraphicsStack.pop().dispose();
97        }
98    }
99
100    /**
101     * Creates a new {@link Graphics2D} based on the {@link Paint} parameters.
102     * <p/>The object must be disposed ({@link Graphics2D#dispose()}) after being used.
103     */
104    private Graphics2D getNewGraphics(Paint paint, Graphics2D g) {
105        // make new one
106        g = (Graphics2D)g.create();
107        g.setColor(new Color(paint.getColor()));
108        int alpha = paint.getAlpha();
109        float falpha = alpha / 255.f;
110
111        Xfermode xfermode = paint.getXfermode();
112        if (xfermode instanceof PorterDuffXfermode) {
113            PorterDuff.Mode mode = ((PorterDuffXfermode)xfermode).getMode();
114
115            setModeInGraphics(mode, g, falpha);
116        } else {
117            if (mLogger != null && xfermode != null) {
118                mLogger.warning(String.format(
119                        "Xfermode '%1$s' is not supported in the Layout Editor.",
120                        xfermode.getClass().getCanonicalName()));
121            }
122            g.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER, falpha));
123        }
124
125        Shader shader = paint.getShader();
126        if (shader instanceof LinearGradient) {
127            g.setPaint(((LinearGradient)shader).getPaint());
128        } else {
129            if (mLogger != null && shader != null) {
130                mLogger.warning(String.format(
131                        "Shader '%1$s' is not supported in the Layout Editor.",
132                        shader.getClass().getCanonicalName()));
133            }
134        }
135
136        return g;
137    }
138
139    private void setModeInGraphics(PorterDuff.Mode mode, Graphics2D g, float falpha) {
140        switch (mode) {
141            case CLEAR:
142                g.setComposite(AlphaComposite.getInstance(AlphaComposite.CLEAR, falpha));
143                break;
144            case DARKEN:
145                break;
146            case DST:
147                g.setComposite(AlphaComposite.getInstance(AlphaComposite.DST, falpha));
148                break;
149            case DST_ATOP:
150                g.setComposite(AlphaComposite.getInstance(AlphaComposite.DST_ATOP, falpha));
151                break;
152            case DST_IN:
153                g.setComposite(AlphaComposite.getInstance(AlphaComposite.DST_IN, falpha));
154                break;
155            case DST_OUT:
156                g.setComposite(AlphaComposite.getInstance(AlphaComposite.DST_OUT, falpha));
157                break;
158            case DST_OVER:
159                g.setComposite(AlphaComposite.getInstance(AlphaComposite.DST_OVER, falpha));
160                break;
161            case LIGHTEN:
162                break;
163            case MULTIPLY:
164                break;
165            case SCREEN:
166                break;
167            case SRC:
168                g.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC, falpha));
169                break;
170            case SRC_ATOP:
171                g.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_ATOP, falpha));
172                break;
173            case SRC_IN:
174                g.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_IN, falpha));
175                break;
176            case SRC_OUT:
177                g.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OUT, falpha));
178                break;
179            case SRC_OVER:
180                g.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER, falpha));
181                break;
182            case XOR:
183                g.setComposite(AlphaComposite.getInstance(AlphaComposite.XOR, falpha));
184                break;
185        }
186    }
187
188
189    // --------------------
190    // OVERRIDEN ENUMS
191    // This is needed since we rename Canvas into _Original_Canvas
192    // --------------------
193
194    public enum EdgeType {
195        BW(0),  //!< treat edges by just rounding to nearest pixel boundary
196        AA(1);  //!< treat edges by rounding-out, since they may be antialiased
197
198        EdgeType(int nativeInt) {
199            this.nativeInt = nativeInt;
200        }
201        final int nativeInt;
202    }
203
204
205    // --------------------
206    // OVERRIDEN METHODS
207    // --------------------
208
209    @Override
210    public void finalize() throws Throwable {
211        // pass
212    }
213
214    /* (non-Javadoc)
215     * @see android.graphics.Canvas#setBitmap(android.graphics.Bitmap)
216     */
217    @Override
218    public void setBitmap(Bitmap bitmap) {
219        mBufferedImage = bitmap.getImage();
220        mGraphicsStack.push(mBufferedImage.createGraphics());
221    }
222
223
224    /* (non-Javadoc)
225     * @see android.graphics.Canvas#translate(float, float)
226     */
227    @Override
228    public void translate(float dx, float dy) {
229        getGraphics2d().translate(dx, dy);
230    }
231
232    /* (non-Javadoc)
233     * @see android.graphics.Canvas#save()
234     */
235    @Override
236    public int save() {
237        Graphics2D g = (Graphics2D)getGraphics2d().create();
238        mGraphicsStack.push(g);
239
240        return mGraphicsStack.size() - 1;
241    }
242
243    /* (non-Javadoc)
244     * @see android.graphics.Canvas#save(int)
245     */
246    @Override
247    public int save(int saveFlags) {
248        // For now we ignore saveFlags
249        return save();
250    }
251
252    /* (non-Javadoc)
253     * @see android.graphics.Canvas#restore()
254     */
255    @Override
256    public void restore() {
257        mGraphicsStack.pop();
258    }
259
260    /* (non-Javadoc)
261     * @see android.graphics.Canvas#restoreToCount(int)
262     */
263    @Override
264    public void restoreToCount(int saveCount) {
265        while (mGraphicsStack.size() > saveCount) {
266            mGraphicsStack.pop();
267        }
268    }
269
270    /* (non-Javadoc)
271     * @see android.graphics.Canvas#getSaveCount()
272     */
273    @Override
274    public int getSaveCount() {
275        return mGraphicsStack.size() - 1;
276    }
277
278
279    /* (non-Javadoc)
280     * @see android.graphics.Canvas#clipRect(float, float, float, float, android.graphics.Region.Op)
281     */
282    @Override
283    public boolean clipRect(float left, float top, float right, float bottom, Op op) {
284        return clipRect(left, top, right, bottom);
285    }
286
287    /* (non-Javadoc)
288     * @see android.graphics.Canvas#clipRect(float, float, float, float)
289     */
290    @Override
291    public boolean clipRect(float left, float top, float right, float bottom) {
292        getGraphics2d().clipRect((int)left, (int)top, (int)(right-left), (int)(bottom-top));
293        return true;
294    }
295
296    /* (non-Javadoc)
297     * @see android.graphics.Canvas#clipRect(int, int, int, int)
298     */
299    @Override
300    public boolean clipRect(int left, int top, int right, int bottom) {
301        getGraphics2d().clipRect(left, top, right-left, bottom-top);
302        return true;
303    }
304
305    /* (non-Javadoc)
306     * @see android.graphics.Canvas#clipRect(android.graphics.Rect, android.graphics.Region.Op)
307     */
308    @Override
309    public boolean clipRect(Rect rect, Op op) {
310        return clipRect(rect.left, rect.top, rect.right, rect.bottom);
311    }
312
313    /* (non-Javadoc)
314     * @see android.graphics.Canvas#clipRect(android.graphics.Rect)
315     */
316    @Override
317    public boolean clipRect(Rect rect) {
318        return clipRect(rect.left, rect.top, rect.right, rect.bottom);
319    }
320
321    /* (non-Javadoc)
322     * @see android.graphics.Canvas#clipRect(android.graphics.RectF, android.graphics.Region.Op)
323     */
324    @Override
325    public boolean clipRect(RectF rect, Op op) {
326        return clipRect(rect.left, rect.top, rect.right, rect.bottom);
327    }
328
329    /* (non-Javadoc)
330     * @see android.graphics.Canvas#clipRect(android.graphics.RectF)
331     */
332    @Override
333    public boolean clipRect(RectF rect) {
334        return clipRect(rect.left, rect.top, rect.right, rect.bottom);
335    }
336
337    public boolean quickReject(RectF rect, EdgeType type) {
338        return false;
339    }
340
341    @Override
342    public boolean quickReject(RectF rect, _Original_Canvas.EdgeType type) {
343        throw new UnsupportedOperationException("CALL TO PARENT FORBIDDEN");
344    }
345
346    public boolean quickReject(Path path, EdgeType type) {
347        return false;
348    }
349
350    @Override
351    public boolean quickReject(Path path, _Original_Canvas.EdgeType type) {
352        throw new UnsupportedOperationException("CALL TO PARENT FORBIDDEN");
353    }
354
355    public boolean quickReject(float left, float top, float right, float bottom,
356                               EdgeType type) {
357        return false;
358    }
359
360    @Override
361    public boolean quickReject(float left, float top, float right, float bottom,
362                               _Original_Canvas.EdgeType type) {
363        throw new UnsupportedOperationException("CALL TO PARENT FORBIDDEN");
364    }
365
366    /**
367     * Retrieve the clip bounds, returning true if they are non-empty.
368     *
369     * @param bounds Return the clip bounds here. If it is null, ignore it but
370     *               still return true if the current clip is non-empty.
371     * @return true if the current clip is non-empty.
372     */
373    @Override
374    public boolean getClipBounds(Rect bounds) {
375        Rectangle rect = getGraphics2d().getClipBounds();
376        if (rect != null) {
377            bounds.left = rect.x;
378            bounds.top = rect.y;
379            bounds.right = rect.x + rect.width;
380            bounds.bottom = rect.y + rect.height;
381            return true;
382        }
383        return false;
384    }
385
386    /* (non-Javadoc)
387     * @see android.graphics.Canvas#drawColor(int, android.graphics.PorterDuff.Mode)
388     */
389    @Override
390    public void drawColor(int color, PorterDuff.Mode mode) {
391        Graphics2D g = getGraphics2d();
392
393        // save old color
394        Color c = g.getColor();
395
396        Composite composite = g.getComposite();
397
398        // get the alpha from the color
399        int alpha = color >>> 24;
400        float falpha = alpha / 255.f;
401
402        setModeInGraphics(mode, g, falpha);
403
404        g.setColor(new Color(color));
405
406        getGraphics2d().fillRect(0, 0, getWidth(), getHeight());
407
408        g.setComposite(composite);
409
410        // restore color
411        g.setColor(c);
412    }
413
414    /* (non-Javadoc)
415     * @see android.graphics.Canvas#drawColor(int)
416     */
417    @Override
418    public void drawColor(int color) {
419        drawColor(color, PorterDuff.Mode.SRC_OVER);
420    }
421
422    /* (non-Javadoc)
423     * @see android.graphics.Canvas#drawARGB(int, int, int, int)
424     */
425    @Override
426    public void drawARGB(int a, int r, int g, int b) {
427        drawColor(a << 24 | r << 16 | g << 8 | b, PorterDuff.Mode.SRC_OVER);
428    }
429
430    /* (non-Javadoc)
431     * @see android.graphics.Canvas#drawRGB(int, int, int)
432     */
433    @Override
434    public void drawRGB(int r, int g, int b) {
435        drawColor(0xFF << 24 | r << 16 | g << 8 | b, PorterDuff.Mode.SRC_OVER);
436    }
437
438
439    /* (non-Javadoc)
440     * @see android.graphics.Canvas#getWidth()
441     */
442    @Override
443    public int getWidth() {
444        return mBufferedImage.getWidth();
445    }
446
447    /* (non-Javadoc)
448     * @see android.graphics.Canvas#getHeight()
449     */
450    @Override
451    public int getHeight() {
452        return mBufferedImage.getHeight();
453    }
454
455    /* (non-Javadoc)
456     * @see android.graphics.Canvas#drawPaint(android.graphics.Paint)
457     */
458    @Override
459    public void drawPaint(Paint paint) {
460        drawColor(paint.getColor());
461    }
462
463    /* (non-Javadoc)
464     * @see android.graphics.Canvas#drawBitmap(android.graphics.Bitmap, float, float, android.graphics.Paint)
465     */
466    @Override
467    public void drawBitmap(Bitmap bitmap, float left, float top, Paint paint) {
468        drawBitmap(bitmap, 0, 0, bitmap.getWidth(), bitmap.getHeight(),
469                (int)left, (int)top,
470                (int)left+bitmap.getWidth(), (int)top+bitmap.getHeight(), paint);
471    }
472
473    /* (non-Javadoc)
474     * @see android.graphics.Canvas#drawBitmap(android.graphics.Bitmap, android.graphics.Matrix, android.graphics.Paint)
475     */
476    @Override
477    public void drawBitmap(Bitmap bitmap, Matrix matrix, Paint paint) {
478        boolean needsRestore = false;
479        if (matrix.isIdentity() == false) {
480            // create a new graphics and apply the matrix to it
481            save(); // this creates a new Graphics2D, and stores it for children call to use
482            needsRestore = true;
483            Graphics2D g = getGraphics2d(); // get the newly create Graphics2D
484
485            // get the Graphics2D current matrix
486            AffineTransform currentTx = g.getTransform();
487            // get the AffineTransform from the matrix
488            AffineTransform matrixTx = matrix.getTransform();
489
490            // combine them so that the matrix is applied after.
491            currentTx.preConcatenate(matrixTx);
492
493            // give it to the graphics as a new matrix replacing all previous transform
494            g.setTransform(currentTx);
495        }
496
497        // draw the bitmap
498        drawBitmap(bitmap, 0, 0, paint);
499
500        if (needsRestore) {
501            // remove the new graphics
502            restore();
503        }
504    }
505
506    /* (non-Javadoc)
507     * @see android.graphics.Canvas#drawBitmap(android.graphics.Bitmap, android.graphics.Rect, android.graphics.Rect, android.graphics.Paint)
508     */
509    @Override
510    public void drawBitmap(Bitmap bitmap, Rect src, Rect dst, Paint paint) {
511        if (src == null) {
512            drawBitmap(bitmap, 0, 0, bitmap.getWidth(), bitmap.getHeight(),
513                    dst.left, dst.top, dst.right, dst.bottom, paint);
514        } else {
515            drawBitmap(bitmap, src.left, src.top, src.width(), src.height(),
516                    dst.left, dst.top, dst.right, dst.bottom, paint);
517        }
518    }
519
520    /* (non-Javadoc)
521     * @see android.graphics.Canvas#drawBitmap(android.graphics.Bitmap, android.graphics.Rect, android.graphics.RectF, android.graphics.Paint)
522     */
523    @Override
524    public void drawBitmap(Bitmap bitmap, Rect src, RectF dst, Paint paint) {
525        if (src == null) {
526            drawBitmap(bitmap, 0, 0, bitmap.getWidth(), bitmap.getHeight(),
527                    (int)dst.left, (int)dst.top, (int)dst.right, (int)dst.bottom, paint);
528        } else {
529            drawBitmap(bitmap, src.left, src.top, src.width(), src.height(),
530                    (int)dst.left, (int)dst.top, (int)dst.right, (int)dst.bottom, paint);
531        }
532    }
533
534    /* (non-Javadoc)
535     * @see android.graphics.Canvas#drawBitmap(int[], int, int, int, int, int, int, boolean, android.graphics.Paint)
536     */
537    @Override
538    public void drawBitmap(int[] colors, int offset, int stride, int x, int y, int width,
539            int height, boolean hasAlpha, Paint paint) {
540        throw new UnsupportedOperationException();
541    }
542
543    private void drawBitmap(Bitmap bitmap, int sleft, int stop, int sright, int sbottom, int dleft,
544            int dtop, int dright, int dbottom, Paint paint) {
545        BufferedImage image = bitmap.getImage();
546
547        Graphics2D g = getGraphics2d();
548
549        Composite c = null;
550
551        if (paint != null) {
552            if (paint.isFilterBitmap()) {
553                g = (Graphics2D)g.create();
554                g.setRenderingHint(RenderingHints.KEY_INTERPOLATION,
555                        RenderingHints.VALUE_INTERPOLATION_BILINEAR);
556            }
557
558            if (paint.getAlpha() != 0xFF) {
559                c = g.getComposite();
560                g.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER,
561                        paint.getAlpha()/255.f));
562            }
563        }
564
565        g.drawImage(image, dleft, dtop, dright, dbottom,
566                sleft, stop, sright, sbottom, null);
567
568        if (paint != null) {
569            if (paint.isFilterBitmap()) {
570                g.dispose();
571            }
572            if (c != null) {
573                g.setComposite(c);
574            }
575        }
576    }
577
578    /* (non-Javadoc)
579     * @see android.graphics.Canvas#rotate(float, float, float)
580     */
581    @Override
582    public void rotate(float degrees, float px, float py) {
583        if (degrees != 0) {
584            Graphics2D g = getGraphics2d();
585            g.translate(px, py);
586            g.rotate(Math.toRadians(degrees));
587            g.translate(-px, -py);
588        }
589    }
590
591    /* (non-Javadoc)
592     * @see android.graphics.Canvas#rotate(float)
593     */
594    @Override
595    public void rotate(float degrees) {
596        getGraphics2d().rotate(Math.toRadians(degrees));
597    }
598
599    /* (non-Javadoc)
600     * @see android.graphics.Canvas#scale(float, float, float, float)
601     */
602    @Override
603    public void scale(float sx, float sy, float px, float py) {
604        Graphics2D g = getGraphics2d();
605        g.translate(px, py);
606        g.scale(sx, sy);
607        g.translate(-px, -py);
608    }
609
610    /* (non-Javadoc)
611     * @see android.graphics.Canvas#scale(float, float)
612     */
613    @Override
614    public void scale(float sx, float sy) {
615        getGraphics2d().scale(sx, sy);
616    }
617
618    /* (non-Javadoc)
619     * @see android.graphics.Canvas#drawText(char[], int, int, float, float, android.graphics.Paint)
620     */
621    @Override
622    public void drawText(char[] text, int index, int count, float x, float y, Paint paint) {
623        Graphics2D g = getGraphics2d();
624
625        g = (Graphics2D)g.create();
626        g.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
627
628        g.setFont(paint.getFont());
629
630        // set the color. because this only handles RGB we have to handle the alpha separately
631        g.setColor(new Color(paint.getColor()));
632        int alpha = paint.getAlpha();
633        float falpha = alpha / 255.f;
634        g.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER, falpha));
635
636        // Paint.TextAlign indicates how the text is positioned relative to X.
637        // LEFT is the default and there's nothing to do.
638        if (paint.getTextAlign() != Align.LEFT) {
639            float m = paint.measureText(text, index, count);
640            if (paint.getTextAlign() == Align.CENTER) {
641                x -= m / 2;
642            } else if (paint.getTextAlign() == Align.RIGHT) {
643                x -= m;
644            }
645        }
646
647        g.drawChars(text, index, count, (int)x, (int)y);
648
649        g.dispose();
650    }
651
652    /* (non-Javadoc)
653     * @see android.graphics.Canvas#drawText(java.lang.CharSequence, int, int, float, float, android.graphics.Paint)
654     */
655    @Override
656    public void drawText(CharSequence text, int start, int end, float x, float y, Paint paint) {
657        drawText(text.toString().toCharArray(), start, end - start, x, y, paint);
658    }
659
660    /* (non-Javadoc)
661     * @see android.graphics.Canvas#drawText(java.lang.String, float, float, android.graphics.Paint)
662     */
663    @Override
664    public void drawText(String text, float x, float y, Paint paint) {
665        drawText(text.toCharArray(), 0, text.length(), x, y, paint);
666    }
667
668    /* (non-Javadoc)
669     * @see android.graphics.Canvas#drawText(java.lang.String, int, int, float, float, android.graphics.Paint)
670     */
671    @Override
672    public void drawText(String text, int start, int end, float x, float y, Paint paint) {
673        drawText(text.toCharArray(), start, end - start, x, y, paint);
674    }
675
676    /* (non-Javadoc)
677     * @see android.graphics.Canvas#drawRect(android.graphics.RectF, android.graphics.Paint)
678     */
679    @Override
680    public void drawRect(RectF rect, Paint paint) {
681        doDrawRect((int)rect.left, (int)rect.top, (int)rect.width(), (int)rect.height(), paint);
682    }
683
684    /* (non-Javadoc)
685     * @see android.graphics.Canvas#drawRect(float, float, float, float, android.graphics.Paint)
686     */
687    @Override
688    public void drawRect(float left, float top, float right, float bottom, Paint paint) {
689        doDrawRect((int)left, (int)top, (int)(right-left), (int)(bottom-top), paint);
690    }
691
692    /* (non-Javadoc)
693     * @see android.graphics.Canvas#drawRect(android.graphics.Rect, android.graphics.Paint)
694     */
695    @Override
696    public void drawRect(Rect r, Paint paint) {
697        doDrawRect(r.left, r.top, r.width(), r.height(), paint);
698    }
699
700    private final void doDrawRect(int left, int top, int width, int height, Paint paint) {
701        // get current graphisc
702        Graphics2D g = getGraphics2d();
703
704        g = getNewGraphics(paint, g);
705
706        Style style = paint.getStyle();
707
708        // draw
709        if (style == Style.FILL || style == Style.FILL_AND_STROKE) {
710            g.fillRect(left, top, width, height);
711        }
712
713        if (style == Style.STROKE || style == Style.FILL_AND_STROKE) {
714            g.drawRect(left, top, width, height);
715        }
716
717        // dispose Graphics2D object
718        g.dispose();
719    }
720
721    /* (non-Javadoc)
722     * @see android.graphics.Canvas#drawRoundRect(android.graphics.RectF, float, float, android.graphics.Paint)
723     */
724    @Override
725    public void drawRoundRect(RectF rect, float rx, float ry, Paint paint) {
726        // get current graphisc
727        Graphics2D g = getGraphics2d();
728
729        g = getNewGraphics(paint, g);
730
731        Style style = paint.getStyle();
732
733        // draw
734
735        int arcWidth = (int)(rx * 2);
736        int arcHeight = (int)(ry * 2);
737
738        if (style == Style.FILL || style == Style.FILL_AND_STROKE) {
739            g.fillRoundRect((int)rect.left, (int)rect.top, (int)rect.width(), (int)rect.height(),
740                    arcWidth, arcHeight);
741        }
742
743        if (style == Style.STROKE || style == Style.FILL_AND_STROKE) {
744            g.drawRoundRect((int)rect.left, (int)rect.top, (int)rect.width(), (int)rect.height(),
745                    arcWidth, arcHeight);
746        }
747
748        // dispose Graphics2D object
749        g.dispose();
750    }
751
752
753    /* (non-Javadoc)
754     * @see android.graphics.Canvas#drawLine(float, float, float, float, android.graphics.Paint)
755     */
756    @Override
757    public void drawLine(float startX, float startY, float stopX, float stopY, Paint paint) {
758        // get current graphisc
759        Graphics2D g = getGraphics2d();
760
761        g = getNewGraphics(paint, g);
762
763        g.drawLine((int)startX, (int)startY, (int)stopX, (int)stopY);
764
765        // dispose Graphics2D object
766        g.dispose();
767    }
768
769    /* (non-Javadoc)
770     * @see android.graphics.Canvas#drawLines(float[], int, int, android.graphics.Paint)
771     */
772    @Override
773    public void drawLines(float[] pts, int offset, int count, Paint paint) {
774        // get current graphisc
775        Graphics2D g = getGraphics2d();
776
777        g = getNewGraphics(paint, g);
778
779        for (int i = 0 ; i < count ; i += 4) {
780            g.drawLine((int)pts[i + offset], (int)pts[i + offset + 1],
781                    (int)pts[i + offset + 2], (int)pts[i + offset + 3]);
782        }
783
784        // dispose Graphics2D object
785        g.dispose();
786    }
787
788    /* (non-Javadoc)
789     * @see android.graphics.Canvas#drawLines(float[], android.graphics.Paint)
790     */
791    @Override
792    public void drawLines(float[] pts, Paint paint) {
793        drawLines(pts, 0, pts.length, paint);
794    }
795
796    /* (non-Javadoc)
797     * @see android.graphics.Canvas#drawCircle(float, float, float, android.graphics.Paint)
798     */
799    @Override
800    public void drawCircle(float cx, float cy, float radius, Paint paint) {
801        // get current graphisc
802        Graphics2D g = getGraphics2d();
803
804        g = getNewGraphics(paint, g);
805
806        Style style = paint.getStyle();
807
808        int size = (int)(radius * 2);
809
810        // draw
811        if (style == Style.FILL || style == Style.FILL_AND_STROKE) {
812            g.fillOval((int)(cx - radius), (int)(cy - radius), size, size);
813        }
814
815        if (style == Style.STROKE || style == Style.FILL_AND_STROKE) {
816            g.drawOval((int)(cx - radius), (int)(cy - radius), size, size);
817        }
818
819        // dispose Graphics2D object
820        g.dispose();
821    }
822
823    /* (non-Javadoc)
824     * @see android.graphics.Canvas#drawOval(android.graphics.RectF, android.graphics.Paint)
825     */
826    @Override
827    public void drawOval(RectF oval, Paint paint) {
828        // get current graphics
829        Graphics2D g = getGraphics2d();
830
831        g = getNewGraphics(paint, g);
832
833        Style style = paint.getStyle();
834
835        // draw
836        if (style == Style.FILL || style == Style.FILL_AND_STROKE) {
837            g.fillOval((int)oval.left, (int)oval.top, (int)oval.width(), (int)oval.height());
838        }
839
840        if (style == Style.STROKE || style == Style.FILL_AND_STROKE) {
841            g.drawOval((int)oval.left, (int)oval.top, (int)oval.width(), (int)oval.height());
842        }
843
844        // dispose Graphics2D object
845        g.dispose();
846    }
847
848    /* (non-Javadoc)
849     * @see android.graphics.Canvas#drawPath(android.graphics.Path, android.graphics.Paint)
850     */
851    @Override
852    public void drawPath(Path path, Paint paint) {
853        // get current graphics
854        Graphics2D g = getGraphics2d();
855
856        g = getNewGraphics(paint, g);
857
858        Style style = paint.getStyle();
859
860        // draw
861        if (style == Style.FILL || style == Style.FILL_AND_STROKE) {
862            g.fill(path.getAwtShape());
863        }
864
865        if (style == Style.STROKE || style == Style.FILL_AND_STROKE) {
866            g.draw(path.getAwtShape());
867        }
868
869        // dispose Graphics2D object
870        g.dispose();
871    }
872
873    /* (non-Javadoc)
874     * @see android.graphics.Canvas#setMatrix(android.graphics.Matrix)
875     */
876    @Override
877    public void setMatrix(Matrix matrix) {
878        // since SetMatrix *replaces* all the other transformation, we have to restore/save
879        restore();
880        save();
881
882        // get the new current graphics
883        Graphics2D g = getGraphics2d();
884
885        // and apply the matrix
886        g.setTransform(matrix.getTransform());
887
888        if (mLogger != null && matrix.hasPerspective()) {
889            mLogger.warning("android.graphics.Canvas#setMatrix(android.graphics.Matrix) only supports affine transformations in the Layout Editor.");
890        }
891    }
892
893    // --------------------
894
895    /* (non-Javadoc)
896     * @see android.graphics.Canvas#clipPath(android.graphics.Path, android.graphics.Region.Op)
897     */
898    @Override
899    public boolean clipPath(Path path, Op op) {
900        // TODO Auto-generated method stub
901        return super.clipPath(path, op);
902    }
903
904    /* (non-Javadoc)
905     * @see android.graphics.Canvas#clipPath(android.graphics.Path)
906     */
907    @Override
908    public boolean clipPath(Path path) {
909        // TODO Auto-generated method stub
910        return super.clipPath(path);
911    }
912
913
914    /* (non-Javadoc)
915     * @see android.graphics.Canvas#clipRegion(android.graphics.Region, android.graphics.Region.Op)
916     */
917    @Override
918    public boolean clipRegion(Region region, Op op) {
919        // TODO Auto-generated method stub
920        return super.clipRegion(region, op);
921    }
922
923    /* (non-Javadoc)
924     * @see android.graphics.Canvas#clipRegion(android.graphics.Region)
925     */
926    @Override
927    public boolean clipRegion(Region region) {
928        // TODO Auto-generated method stub
929        return super.clipRegion(region);
930    }
931
932    /* (non-Javadoc)
933     * @see android.graphics.Canvas#concat(android.graphics.Matrix)
934     */
935    @Override
936    public void concat(Matrix matrix) {
937        // TODO Auto-generated method stub
938        super.concat(matrix);
939    }
940
941    /* (non-Javadoc)
942     * @see android.graphics.Canvas#drawArc(android.graphics.RectF, float, float, boolean, android.graphics.Paint)
943     */
944    @Override
945    public void drawArc(RectF oval, float startAngle, float sweepAngle, boolean useCenter,
946            Paint paint) {
947        // TODO Auto-generated method stub
948        super.drawArc(oval, startAngle, sweepAngle, useCenter, paint);
949    }
950
951    /* (non-Javadoc)
952     * @see android.graphics.Canvas#drawBitmapMesh(android.graphics.Bitmap, int, int, float[], int, int[], int, android.graphics.Paint)
953     */
954    @Override
955    public void drawBitmapMesh(Bitmap bitmap, int meshWidth, int meshHeight, float[] verts,
956            int vertOffset, int[] colors, int colorOffset, Paint paint) {
957        // TODO Auto-generated method stub
958        super.drawBitmapMesh(bitmap, meshWidth, meshHeight, verts, vertOffset, colors, colorOffset, paint);
959    }
960
961    /* (non-Javadoc)
962     * @see android.graphics.Canvas#drawPicture(android.graphics.Picture, android.graphics.Rect)
963     */
964    @Override
965    public void drawPicture(Picture picture, Rect dst) {
966        // TODO Auto-generated method stub
967        super.drawPicture(picture, dst);
968    }
969
970    /* (non-Javadoc)
971     * @see android.graphics.Canvas#drawPicture(android.graphics.Picture, android.graphics.RectF)
972     */
973    @Override
974    public void drawPicture(Picture picture, RectF dst) {
975        // TODO Auto-generated method stub
976        super.drawPicture(picture, dst);
977    }
978
979    /* (non-Javadoc)
980     * @see android.graphics.Canvas#drawPicture(android.graphics.Picture)
981     */
982    @Override
983    public void drawPicture(Picture picture) {
984        // TODO Auto-generated method stub
985        super.drawPicture(picture);
986    }
987
988    /* (non-Javadoc)
989     * @see android.graphics.Canvas#drawPoint(float, float, android.graphics.Paint)
990     */
991    @Override
992    public void drawPoint(float x, float y, Paint paint) {
993        // TODO Auto-generated method stub
994        super.drawPoint(x, y, paint);
995    }
996
997    /* (non-Javadoc)
998     * @see android.graphics.Canvas#drawPoints(float[], int, int, android.graphics.Paint)
999     */
1000    @Override
1001    public void drawPoints(float[] pts, int offset, int count, Paint paint) {
1002        // TODO Auto-generated method stub
1003        super.drawPoints(pts, offset, count, paint);
1004    }
1005
1006    /* (non-Javadoc)
1007     * @see android.graphics.Canvas#drawPoints(float[], android.graphics.Paint)
1008     */
1009    @Override
1010    public void drawPoints(float[] pts, Paint paint) {
1011        // TODO Auto-generated method stub
1012        super.drawPoints(pts, paint);
1013    }
1014
1015    /* (non-Javadoc)
1016     * @see android.graphics.Canvas#drawPosText(char[], int, int, float[], android.graphics.Paint)
1017     */
1018    @Override
1019    public void drawPosText(char[] text, int index, int count, float[] pos, Paint paint) {
1020        // TODO Auto-generated method stub
1021        super.drawPosText(text, index, count, pos, paint);
1022    }
1023
1024    /* (non-Javadoc)
1025     * @see android.graphics.Canvas#drawPosText(java.lang.String, float[], android.graphics.Paint)
1026     */
1027    @Override
1028    public void drawPosText(String text, float[] pos, Paint paint) {
1029        // TODO Auto-generated method stub
1030        super.drawPosText(text, pos, paint);
1031    }
1032
1033    /* (non-Javadoc)
1034     * @see android.graphics.Canvas#drawTextOnPath(char[], int, int, android.graphics.Path, float, float, android.graphics.Paint)
1035     */
1036    @Override
1037    public void drawTextOnPath(char[] text, int index, int count, Path path, float offset,
1038            float offset2, Paint paint) {
1039        // TODO Auto-generated method stub
1040        super.drawTextOnPath(text, index, count, path, offset, offset2, paint);
1041    }
1042
1043    /* (non-Javadoc)
1044     * @see android.graphics.Canvas#drawTextOnPath(java.lang.String, android.graphics.Path, float, float, android.graphics.Paint)
1045     */
1046    @Override
1047    public void drawTextOnPath(String text, Path path, float offset, float offset2, Paint paint) {
1048        // TODO Auto-generated method stub
1049        super.drawTextOnPath(text, path, offset, offset2, paint);
1050    }
1051
1052    /* (non-Javadoc)
1053     * @see android.graphics.Canvas#drawVertices(android.graphics.Canvas.VertexMode, int, float[], int, float[], int, int[], int, short[], int, int, android.graphics.Paint)
1054     */
1055    @Override
1056    public void drawVertices(VertexMode mode, int vertexCount, float[] verts, int vertOffset,
1057            float[] texs, int texOffset, int[] colors, int colorOffset, short[] indices,
1058            int indexOffset, int indexCount, Paint paint) {
1059        // TODO Auto-generated method stub
1060        super.drawVertices(mode, vertexCount, verts, vertOffset, texs, texOffset, colors, colorOffset,
1061                indices, indexOffset, indexCount, paint);
1062    }
1063
1064    /* (non-Javadoc)
1065     * @see android.graphics.Canvas#getDrawFilter()
1066     */
1067    @Override
1068    public DrawFilter getDrawFilter() {
1069        // TODO Auto-generated method stub
1070        return super.getDrawFilter();
1071    }
1072
1073    /* (non-Javadoc)
1074     * @see android.graphics.Canvas#getGL()
1075     */
1076    @Override
1077    public GL getGL() {
1078        // TODO Auto-generated method stub
1079        return super.getGL();
1080    }
1081
1082    /* (non-Javadoc)
1083     * @see android.graphics.Canvas#getMatrix()
1084     */
1085    @Override
1086    public Matrix getMatrix() {
1087        // TODO Auto-generated method stub
1088        return super.getMatrix();
1089    }
1090
1091    /* (non-Javadoc)
1092     * @see android.graphics.Canvas#getMatrix(android.graphics.Matrix)
1093     */
1094    @Override
1095    public void getMatrix(Matrix ctm) {
1096        // TODO Auto-generated method stub
1097        super.getMatrix(ctm);
1098    }
1099
1100    /* (non-Javadoc)
1101     * @see android.graphics.Canvas#isOpaque()
1102     */
1103    @Override
1104    public boolean isOpaque() {
1105        // TODO Auto-generated method stub
1106        return super.isOpaque();
1107    }
1108
1109    /* (non-Javadoc)
1110     * @see android.graphics.Canvas#saveLayer(float, float, float, float, android.graphics.Paint, int)
1111     */
1112    @Override
1113    public int saveLayer(float left, float top, float right, float bottom, Paint paint,
1114            int saveFlags) {
1115        // TODO Auto-generated method stub
1116        return super.saveLayer(left, top, right, bottom, paint, saveFlags);
1117    }
1118
1119    /* (non-Javadoc)
1120     * @see android.graphics.Canvas#saveLayer(android.graphics.RectF, android.graphics.Paint, int)
1121     */
1122    @Override
1123    public int saveLayer(RectF bounds, Paint paint, int saveFlags) {
1124        // TODO Auto-generated method stub
1125        return super.saveLayer(bounds, paint, saveFlags);
1126    }
1127
1128    /* (non-Javadoc)
1129     * @see android.graphics.Canvas#saveLayerAlpha(float, float, float, float, int, int)
1130     */
1131    @Override
1132    public int saveLayerAlpha(float left, float top, float right, float bottom, int alpha,
1133            int saveFlags) {
1134        // TODO Auto-generated method stub
1135        return super.saveLayerAlpha(left, top, right, bottom, alpha, saveFlags);
1136    }
1137
1138    /* (non-Javadoc)
1139     * @see android.graphics.Canvas#saveLayerAlpha(android.graphics.RectF, int, int)
1140     */
1141    @Override
1142    public int saveLayerAlpha(RectF bounds, int alpha, int saveFlags) {
1143        // TODO Auto-generated method stub
1144        return super.saveLayerAlpha(bounds, alpha, saveFlags);
1145    }
1146
1147    /* (non-Javadoc)
1148     * @see android.graphics.Canvas#setDrawFilter(android.graphics.DrawFilter)
1149     */
1150    @Override
1151    public void setDrawFilter(DrawFilter filter) {
1152        // TODO Auto-generated method stub
1153        super.setDrawFilter(filter);
1154    }
1155
1156    /* (non-Javadoc)
1157     * @see android.graphics.Canvas#setViewport(int, int)
1158     */
1159    @Override
1160    public void setViewport(int width, int height) {
1161        // TODO Auto-generated method stub
1162        super.setViewport(width, height);
1163    }
1164
1165    /* (non-Javadoc)
1166     * @see android.graphics.Canvas#skew(float, float)
1167     */
1168    @Override
1169    public void skew(float sx, float sy) {
1170        // TODO Auto-generated method stub
1171        super.skew(sx, sy);
1172    }
1173
1174
1175
1176}
1177