Home | History | Annotate | Download | only in graphics
      1 /*
      2  * Copyright (C) 2006 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 
     17 package android.graphics;
     18 
     19 import android.text.GraphicsOperations;
     20 import android.text.SpannableString;
     21 import android.text.SpannedString;
     22 import android.text.TextUtils;
     23 
     24 import javax.microedition.khronos.opengles.GL;
     25 
     26 /**
     27  * The Canvas class holds the "draw" calls. To draw something, you need
     28  * 4 basic components: A Bitmap to hold the pixels, a Canvas to host
     29  * the draw calls (writing into the bitmap), a drawing primitive (e.g. Rect,
     30  * Path, text, Bitmap), and a paint (to describe the colors and styles for the
     31  * drawing).
     32  *
     33  * <div class="special reference">
     34  * <h3>Developer Guides</h3>
     35  * <p>For more information about how to use Canvas, read the
     36  * <a href="{@docRoot}guide/topics/graphics/2d-graphics.html">
     37  * Canvas and Drawables</a> developer guide.</p></div>
     38  */
     39 public class Canvas {
     40     // assigned in constructors, freed in finalizer
     41     final int mNativeCanvas;
     42 
     43     // may be null
     44     private Bitmap mBitmap;
     45 
     46     // optional field set by the caller
     47     private DrawFilter mDrawFilter;
     48 
     49     /**
     50      * @hide
     51      */
     52     protected int mDensity = Bitmap.DENSITY_NONE;
     53 
     54     /**
     55      * Used to determine when compatibility scaling is in effect.
     56      *
     57      * @hide
     58      */
     59     protected int mScreenDensity = Bitmap.DENSITY_NONE;
     60 
     61     // Used by native code
     62     @SuppressWarnings({"UnusedDeclaration"})
     63     private int mSurfaceFormat;
     64 
     65     /**
     66      * Flag for drawTextRun indicating left-to-right run direction.
     67      * @hide
     68      */
     69     public static final int DIRECTION_LTR = 0;
     70 
     71     /**
     72      * Flag for drawTextRun indicating right-to-left run direction.
     73      * @hide
     74      */
     75     public static final int DIRECTION_RTL = 1;
     76 
     77     // Maximum bitmap size as defined in Skia's native code
     78     // (see SkCanvas.cpp, SkDraw.cpp)
     79     private static final int MAXMIMUM_BITMAP_SIZE = 32766;
     80 
     81     // This field is used to finalize the native Canvas properly
     82     @SuppressWarnings({"UnusedDeclaration"})
     83     private final CanvasFinalizer mFinalizer;
     84 
     85     private static class CanvasFinalizer {
     86         private final int mNativeCanvas;
     87 
     88         public CanvasFinalizer(int nativeCanvas) {
     89             mNativeCanvas = nativeCanvas;
     90         }
     91 
     92         @Override
     93         protected void finalize() throws Throwable {
     94             try {
     95                 if (mNativeCanvas != 0) {
     96                     finalizer(mNativeCanvas);
     97                 }
     98             } finally {
     99                 super.finalize();
    100             }
    101         }
    102     }
    103 
    104     /**
    105      * Construct an empty raster canvas. Use setBitmap() to specify a bitmap to
    106      * draw into.  The initial target density is {@link Bitmap#DENSITY_NONE};
    107      * this will typically be replaced when a target bitmap is set for the
    108      * canvas.
    109      */
    110     public Canvas() {
    111         // 0 means no native bitmap
    112         mNativeCanvas = initRaster(0);
    113         mFinalizer = new CanvasFinalizer(mNativeCanvas);
    114     }
    115 
    116     /**
    117      * Construct a canvas with the specified bitmap to draw into. The bitmap
    118      * must be mutable.
    119      *
    120      * <p>The initial target density of the canvas is the same as the given
    121      * bitmap's density.
    122      *
    123      * @param bitmap Specifies a mutable bitmap for the canvas to draw into.
    124      */
    125     public Canvas(Bitmap bitmap) {
    126         if (!bitmap.isMutable()) {
    127             throw new IllegalStateException("Immutable bitmap passed to Canvas constructor");
    128         }
    129         throwIfRecycled(bitmap);
    130         mNativeCanvas = initRaster(bitmap.ni());
    131         mFinalizer = new CanvasFinalizer(mNativeCanvas);
    132         mBitmap = bitmap;
    133         mDensity = bitmap.mDensity;
    134     }
    135 
    136     Canvas(int nativeCanvas) {
    137         if (nativeCanvas == 0) {
    138             throw new IllegalStateException();
    139         }
    140         mNativeCanvas = nativeCanvas;
    141         mFinalizer = new CanvasFinalizer(nativeCanvas);
    142         mDensity = Bitmap.getDefaultDensity();
    143     }
    144 
    145     /**
    146      * Returns null.
    147      *
    148      * @deprecated This method is not supported and should not be invoked.
    149      *
    150      * @hide
    151      */
    152     @Deprecated
    153     protected GL getGL() {
    154         return null;
    155     }
    156 
    157     /**
    158      * Indicates whether this Canvas uses hardware acceleration.
    159      *
    160      * Note that this method does not define what type of hardware acceleration
    161      * may or may not be used.
    162      *
    163      * @return True if drawing operations are hardware accelerated,
    164      *         false otherwise.
    165      */
    166     public boolean isHardwareAccelerated() {
    167         return false;
    168     }
    169 
    170     /**
    171      * Specify a bitmap for the canvas to draw into.  As a side-effect, also
    172      * updates the canvas's target density to match that of the bitmap.
    173      *
    174      * @param bitmap Specifies a mutable bitmap for the canvas to draw into.
    175      *
    176      * @see #setDensity(int)
    177      * @see #getDensity()
    178      */
    179     public void setBitmap(Bitmap bitmap) {
    180         if (isHardwareAccelerated()) {
    181             throw new RuntimeException("Can't set a bitmap device on a GL canvas");
    182         }
    183 
    184         int pointer = 0;
    185         if (bitmap != null) {
    186             if (!bitmap.isMutable()) {
    187                 throw new IllegalStateException();
    188             }
    189             throwIfRecycled(bitmap);
    190             mDensity = bitmap.mDensity;
    191             pointer = bitmap.ni();
    192         }
    193 
    194         native_setBitmap(mNativeCanvas, pointer);
    195         mBitmap = bitmap;
    196     }
    197 
    198     /**
    199      * Set the viewport dimensions if this canvas is GL based. If it is not,
    200      * this method is ignored and no exception is thrown.
    201      *
    202      * @param width The width of the viewport
    203      * @param height The height of the viewport
    204      *
    205      * @hide
    206      */
    207     public void setViewport(int width, int height) {
    208     }
    209 
    210     /**
    211      * Return true if the device that the current layer draws into is opaque
    212      * (i.e. does not support per-pixel alpha).
    213      *
    214      * @return true if the device that the current layer draws into is opaque
    215      */
    216     public native boolean isOpaque();
    217 
    218     /**
    219      * Returns the width of the current drawing layer
    220      *
    221      * @return the width of the current drawing layer
    222      */
    223     public native int getWidth();
    224 
    225     /**
    226      * Returns the height of the current drawing layer
    227      *
    228      * @return the height of the current drawing layer
    229      */
    230     public native int getHeight();
    231 
    232     /**
    233      * <p>Returns the target density of the canvas.  The default density is
    234      * derived from the density of its backing bitmap, or
    235      * {@link Bitmap#DENSITY_NONE} if there is not one.</p>
    236      *
    237      * @return Returns the current target density of the canvas, which is used
    238      * to determine the scaling factor when drawing a bitmap into it.
    239      *
    240      * @see #setDensity(int)
    241      * @see Bitmap#getDensity()
    242      */
    243     public int getDensity() {
    244         return mDensity;
    245     }
    246 
    247     /**
    248      * <p>Specifies the density for this Canvas' backing bitmap.  This modifies
    249      * the target density of the canvas itself, as well as the density of its
    250      * backing bitmap via {@link Bitmap#setDensity(int) Bitmap.setDensity(int)}.
    251      *
    252      * @param density The new target density of the canvas, which is used
    253      * to determine the scaling factor when drawing a bitmap into it.  Use
    254      * {@link Bitmap#DENSITY_NONE} to disable bitmap scaling.
    255      *
    256      * @see #getDensity()
    257      * @see Bitmap#setDensity(int)
    258      */
    259     public void setDensity(int density) {
    260         if (mBitmap != null) {
    261             mBitmap.setDensity(density);
    262         }
    263         mDensity = density;
    264     }
    265 
    266     /** @hide */
    267     public void setScreenDensity(int density) {
    268         mScreenDensity = density;
    269     }
    270 
    271     /**
    272      * Returns the maximum allowed width for bitmaps drawn with this canvas.
    273      * Attempting to draw with a bitmap wider than this value will result
    274      * in an error.
    275      *
    276      * @see #getMaximumBitmapHeight()
    277      */
    278     public int getMaximumBitmapWidth() {
    279         return MAXMIMUM_BITMAP_SIZE;
    280     }
    281 
    282     /**
    283      * Returns the maximum allowed height for bitmaps drawn with this canvas.
    284      * Attempting to draw with a bitmap taller than this value will result
    285      * in an error.
    286      *
    287      * @see #getMaximumBitmapWidth()
    288      */
    289     public int getMaximumBitmapHeight() {
    290         return MAXMIMUM_BITMAP_SIZE;
    291     }
    292 
    293     // the SAVE_FLAG constants must match their native equivalents
    294 
    295     /** restore the current matrix when restore() is called */
    296     public static final int MATRIX_SAVE_FLAG = 0x01;
    297     /** restore the current clip when restore() is called */
    298     public static final int CLIP_SAVE_FLAG = 0x02;
    299     /** the layer needs to per-pixel alpha */
    300     public static final int HAS_ALPHA_LAYER_SAVE_FLAG = 0x04;
    301     /** the layer needs to 8-bits per color component */
    302     public static final int FULL_COLOR_LAYER_SAVE_FLAG = 0x08;
    303     /** clip against the layer's bounds */
    304     public static final int CLIP_TO_LAYER_SAVE_FLAG = 0x10;
    305     /** restore everything when restore() is called */
    306     public static final int ALL_SAVE_FLAG = 0x1F;
    307 
    308     /**
    309      * Saves the current matrix and clip onto a private stack. Subsequent
    310      * calls to translate,scale,rotate,skew,concat or clipRect,clipPath
    311      * will all operate as usual, but when the balancing call to restore()
    312      * is made, those calls will be forgotten, and the settings that existed
    313      * before the save() will be reinstated.
    314      *
    315      * @return The value to pass to restoreToCount() to balance this save()
    316      */
    317     public native int save();
    318 
    319     /**
    320      * Based on saveFlags, can save the current matrix and clip onto a private
    321      * stack. Subsequent calls to translate,scale,rotate,skew,concat or
    322      * clipRect,clipPath will all operate as usual, but when the balancing
    323      * call to restore() is made, those calls will be forgotten, and the
    324      * settings that existed before the save() will be reinstated.
    325      *
    326      * @param saveFlags flag bits that specify which parts of the Canvas state
    327      *                  to save/restore
    328      * @return The value to pass to restoreToCount() to balance this save()
    329      */
    330     public native int save(int saveFlags);
    331 
    332     /**
    333      * This behaves the same as save(), but in addition it allocates an
    334      * offscreen bitmap. All drawing calls are directed there, and only when
    335      * the balancing call to restore() is made is that offscreen transfered to
    336      * the canvas (or the previous layer). Subsequent calls to translate,
    337      * scale, rotate, skew, concat or clipRect, clipPath all operate on this
    338      * copy. When the balancing call to restore() is made, this copy is
    339      * deleted and the previous matrix/clip state is restored.
    340      *
    341      * @param bounds May be null. The maximum size the offscreen bitmap
    342      *               needs to be (in local coordinates)
    343      * @param paint  This is copied, and is applied to the offscreen when
    344      *               restore() is called.
    345      * @param saveFlags  see _SAVE_FLAG constants
    346      * @return       value to pass to restoreToCount() to balance this save()
    347      */
    348     public int saveLayer(RectF bounds, Paint paint, int saveFlags) {
    349         return native_saveLayer(mNativeCanvas, bounds,
    350                                 paint != null ? paint.mNativePaint : 0,
    351                                 saveFlags);
    352     }
    353 
    354     /**
    355      * Helper version of saveLayer() that takes 4 values rather than a RectF.
    356      */
    357     public int saveLayer(float left, float top, float right, float bottom, Paint paint,
    358             int saveFlags) {
    359         return native_saveLayer(mNativeCanvas, left, top, right, bottom,
    360                                 paint != null ? paint.mNativePaint : 0,
    361                                 saveFlags);
    362     }
    363 
    364     /**
    365      * This behaves the same as save(), but in addition it allocates an
    366      * offscreen bitmap. All drawing calls are directed there, and only when
    367      * the balancing call to restore() is made is that offscreen transfered to
    368      * the canvas (or the previous layer). Subsequent calls to translate,
    369      * scale, rotate, skew, concat or clipRect, clipPath all operate on this
    370      * copy. When the balancing call to restore() is made, this copy is
    371      * deleted and the previous matrix/clip state is restored.
    372      *
    373      * @param bounds    The maximum size the offscreen bitmap needs to be
    374      *                  (in local coordinates)
    375      * @param alpha     The alpha to apply to the offscreen when when it is
    376                         drawn during restore()
    377      * @param saveFlags see _SAVE_FLAG constants
    378      * @return          value to pass to restoreToCount() to balance this call
    379      */
    380     public int saveLayerAlpha(RectF bounds, int alpha, int saveFlags) {
    381         alpha = Math.min(255, Math.max(0, alpha));
    382         return native_saveLayerAlpha(mNativeCanvas, bounds, alpha, saveFlags);
    383     }
    384 
    385     /**
    386      * Helper for saveLayerAlpha() that takes 4 values instead of a RectF.
    387      */
    388     public int saveLayerAlpha(float left, float top, float right, float bottom, int alpha,
    389             int saveFlags) {
    390         return native_saveLayerAlpha(mNativeCanvas, left, top, right, bottom,
    391                                      alpha, saveFlags);
    392     }
    393 
    394     /**
    395      * This call balances a previous call to save(), and is used to remove all
    396      * modifications to the matrix/clip state since the last save call. It is
    397      * an error to call restore() more times than save() was called.
    398      */
    399     public native void restore();
    400 
    401     /**
    402      * Returns the number of matrix/clip states on the Canvas' private stack.
    403      * This will equal # save() calls - # restore() calls.
    404      */
    405     public native int getSaveCount();
    406 
    407     /**
    408      * Efficient way to pop any calls to save() that happened after the save
    409      * count reached saveCount. It is an error for saveCount to be less than 1.
    410      *
    411      * Example:
    412      *    int count = canvas.save();
    413      *    ... // more calls potentially to save()
    414      *    canvas.restoreToCount(count);
    415      *    // now the canvas is back in the same state it was before the initial
    416      *    // call to save().
    417      *
    418      * @param saveCount The save level to restore to.
    419      */
    420     public native void restoreToCount(int saveCount);
    421 
    422     /**
    423      * Preconcat the current matrix with the specified translation
    424      *
    425      * @param dx The distance to translate in X
    426      * @param dy The distance to translate in Y
    427     */
    428     public native void translate(float dx, float dy);
    429 
    430     /**
    431      * Preconcat the current matrix with the specified scale.
    432      *
    433      * @param sx The amount to scale in X
    434      * @param sy The amount to scale in Y
    435      */
    436     public native void scale(float sx, float sy);
    437 
    438     /**
    439      * Preconcat the current matrix with the specified scale.
    440      *
    441      * @param sx The amount to scale in X
    442      * @param sy The amount to scale in Y
    443      * @param px The x-coord for the pivot point (unchanged by the scale)
    444      * @param py The y-coord for the pivot point (unchanged by the scale)
    445      */
    446     public final void scale(float sx, float sy, float px, float py) {
    447         translate(px, py);
    448         scale(sx, sy);
    449         translate(-px, -py);
    450     }
    451 
    452     /**
    453      * Preconcat the current matrix with the specified rotation.
    454      *
    455      * @param degrees The amount to rotate, in degrees
    456      */
    457     public native void rotate(float degrees);
    458 
    459     /**
    460      * Preconcat the current matrix with the specified rotation.
    461      *
    462      * @param degrees The amount to rotate, in degrees
    463      * @param px The x-coord for the pivot point (unchanged by the rotation)
    464      * @param py The y-coord for the pivot point (unchanged by the rotation)
    465      */
    466     public final void rotate(float degrees, float px, float py) {
    467         translate(px, py);
    468         rotate(degrees);
    469         translate(-px, -py);
    470     }
    471 
    472     /**
    473      * Preconcat the current matrix with the specified skew.
    474      *
    475      * @param sx The amount to skew in X
    476      * @param sy The amount to skew in Y
    477      */
    478     public native void skew(float sx, float sy);
    479 
    480     /**
    481      * Preconcat the current matrix with the specified matrix.
    482      *
    483      * @param matrix The matrix to preconcatenate with the current matrix
    484      */
    485     public void concat(Matrix matrix) {
    486         native_concat(mNativeCanvas, matrix.native_instance);
    487     }
    488 
    489     /**
    490      * Completely replace the current matrix with the specified matrix. If the
    491      * matrix parameter is null, then the current matrix is reset to identity.
    492      *
    493      * <strong>Note:</strong> it is recommended to use {@link #concat(Matrix)},
    494      * {@link #scale(float, float)}, {@link #translate(float, float)} and
    495      * {@link #rotate(float)} instead of this method.
    496      *
    497      * @param matrix The matrix to replace the current matrix with. If it is
    498      *               null, set the current matrix to identity.
    499      *
    500      * @see #concat(Matrix)
    501      */
    502     public void setMatrix(Matrix matrix) {
    503         native_setMatrix(mNativeCanvas,
    504                          matrix == null ? 0 : matrix.native_instance);
    505     }
    506 
    507     /**
    508      * Return, in ctm, the current transformation matrix. This does not alter
    509      * the matrix in the canvas, but just returns a copy of it.
    510      */
    511     @Deprecated
    512     public void getMatrix(Matrix ctm) {
    513         native_getCTM(mNativeCanvas, ctm.native_instance);
    514     }
    515 
    516     /**
    517      * Return a new matrix with a copy of the canvas' current transformation
    518      * matrix.
    519      */
    520     @Deprecated
    521     public final Matrix getMatrix() {
    522         Matrix m = new Matrix();
    523         //noinspection deprecation
    524         getMatrix(m);
    525         return m;
    526     }
    527 
    528     /**
    529      * Modify the current clip with the specified rectangle.
    530      *
    531      * @param rect The rect to intersect with the current clip
    532      * @param op How the clip is modified
    533      * @return true if the resulting clip is non-empty
    534      */
    535     public boolean clipRect(RectF rect, Region.Op op) {
    536         return native_clipRect(mNativeCanvas, rect.left, rect.top, rect.right, rect.bottom,
    537                 op.nativeInt);
    538     }
    539 
    540     /**
    541      * Modify the current clip with the specified rectangle, which is
    542      * expressed in local coordinates.
    543      *
    544      * @param rect The rectangle to intersect with the current clip.
    545      * @param op How the clip is modified
    546      * @return true if the resulting clip is non-empty
    547      */
    548     public boolean clipRect(Rect rect, Region.Op op) {
    549         return native_clipRect(mNativeCanvas, rect.left, rect.top, rect.right, rect.bottom,
    550                 op.nativeInt);
    551     }
    552 
    553     /**
    554      * Intersect the current clip with the specified rectangle, which is
    555      * expressed in local coordinates.
    556      *
    557      * @param rect The rectangle to intersect with the current clip.
    558      * @return true if the resulting clip is non-empty
    559      */
    560     public native boolean clipRect(RectF rect);
    561 
    562     /**
    563      * Intersect the current clip with the specified rectangle, which is
    564      * expressed in local coordinates.
    565      *
    566      * @param rect The rectangle to intersect with the current clip.
    567      * @return true if the resulting clip is non-empty
    568      */
    569     public native boolean clipRect(Rect rect);
    570 
    571     /**
    572      * Modify the current clip with the specified rectangle, which is
    573      * expressed in local coordinates.
    574      *
    575      * @param left   The left side of the rectangle to intersect with the
    576      *               current clip
    577      * @param top    The top of the rectangle to intersect with the current
    578      *               clip
    579      * @param right  The right side of the rectangle to intersect with the
    580      *               current clip
    581      * @param bottom The bottom of the rectangle to intersect with the current
    582      *               clip
    583      * @param op     How the clip is modified
    584      * @return       true if the resulting clip is non-empty
    585      */
    586     public boolean clipRect(float left, float top, float right, float bottom, Region.Op op) {
    587         return native_clipRect(mNativeCanvas, left, top, right, bottom, op.nativeInt);
    588     }
    589 
    590     /**
    591      * Intersect the current clip with the specified rectangle, which is
    592      * expressed in local coordinates.
    593      *
    594      * @param left   The left side of the rectangle to intersect with the
    595      *               current clip
    596      * @param top    The top of the rectangle to intersect with the current clip
    597      * @param right  The right side of the rectangle to intersect with the
    598      *               current clip
    599      * @param bottom The bottom of the rectangle to intersect with the current
    600      *               clip
    601      * @return       true if the resulting clip is non-empty
    602      */
    603     public native boolean clipRect(float left, float top, float right, float bottom);
    604 
    605     /**
    606      * Intersect the current clip with the specified rectangle, which is
    607      * expressed in local coordinates.
    608      *
    609      * @param left   The left side of the rectangle to intersect with the
    610      *               current clip
    611      * @param top    The top of the rectangle to intersect with the current clip
    612      * @param right  The right side of the rectangle to intersect with the
    613      *               current clip
    614      * @param bottom The bottom of the rectangle to intersect with the current
    615      *               clip
    616      * @return       true if the resulting clip is non-empty
    617      */
    618     public native boolean clipRect(int left, int top, int right, int bottom);
    619 
    620     /**
    621         * Modify the current clip with the specified path.
    622      *
    623      * @param path The path to operate on the current clip
    624      * @param op   How the clip is modified
    625      * @return     true if the resulting is non-empty
    626      */
    627     public boolean clipPath(Path path, Region.Op op) {
    628         return native_clipPath(mNativeCanvas, path.ni(), op.nativeInt);
    629     }
    630 
    631     /**
    632      * Intersect the current clip with the specified path.
    633      *
    634      * @param path The path to intersect with the current clip
    635      * @return     true if the resulting is non-empty
    636      */
    637     public boolean clipPath(Path path) {
    638         return clipPath(path, Region.Op.INTERSECT);
    639     }
    640 
    641     /**
    642      * Modify the current clip with the specified region. Note that unlike
    643      * clipRect() and clipPath() which transform their arguments by the
    644      * current matrix, clipRegion() assumes its argument is already in the
    645      * coordinate system of the current layer's bitmap, and so not
    646      * transformation is performed.
    647      *
    648      * @param region The region to operate on the current clip, based on op
    649      * @param op How the clip is modified
    650      * @return true if the resulting is non-empty
    651      */
    652     public boolean clipRegion(Region region, Region.Op op) {
    653         return native_clipRegion(mNativeCanvas, region.ni(), op.nativeInt);
    654     }
    655 
    656     /**
    657      * Intersect the current clip with the specified region. Note that unlike
    658      * clipRect() and clipPath() which transform their arguments by the
    659      * current matrix, clipRegion() assumes its argument is already in the
    660      * coordinate system of the current layer's bitmap, and so not
    661      * transformation is performed.
    662      *
    663      * @param region The region to operate on the current clip, based on op
    664      * @return true if the resulting is non-empty
    665      */
    666     public boolean clipRegion(Region region) {
    667         return clipRegion(region, Region.Op.INTERSECT);
    668     }
    669 
    670     public DrawFilter getDrawFilter() {
    671         return mDrawFilter;
    672     }
    673 
    674     public void setDrawFilter(DrawFilter filter) {
    675         int nativeFilter = 0;
    676         if (filter != null) {
    677             nativeFilter = filter.mNativeInt;
    678         }
    679         mDrawFilter = filter;
    680         nativeSetDrawFilter(mNativeCanvas, nativeFilter);
    681     }
    682 
    683     public enum EdgeType {
    684         BW(0),  //!< treat edges by just rounding to nearest pixel boundary
    685         AA(1);  //!< treat edges by rounding-out, since they may be antialiased
    686 
    687         EdgeType(int nativeInt) {
    688             this.nativeInt = nativeInt;
    689         }
    690 
    691         /**
    692          * @hide
    693          */
    694         public final int nativeInt;
    695     }
    696 
    697     /**
    698      * Return true if the specified rectangle, after being transformed by the
    699      * current matrix, would lie completely outside of the current clip. Call
    700      * this to check if an area you intend to draw into is clipped out (and
    701      * therefore you can skip making the draw calls).
    702      *
    703      * @param rect  the rect to compare with the current clip
    704      * @param type  specifies how to treat the edges (BW or antialiased)
    705      * @return      true if the rect (transformed by the canvas' matrix)
    706      *              does not intersect with the canvas' clip
    707      */
    708     public boolean quickReject(RectF rect, EdgeType type) {
    709         return native_quickReject(mNativeCanvas, rect, type.nativeInt);
    710     }
    711 
    712     /**
    713      * Return true if the specified path, after being transformed by the
    714      * current matrix, would lie completely outside of the current clip. Call
    715      * this to check if an area you intend to draw into is clipped out (and
    716      * therefore you can skip making the draw calls). Note: for speed it may
    717      * return false even if the path itself might not intersect the clip
    718      * (i.e. the bounds of the path intersects, but the path does not).
    719      *
    720      * @param path        The path to compare with the current clip
    721      * @param type        true if the path should be considered antialiased,
    722      *                    since that means it may
    723      *                    affect a larger area (more pixels) than
    724      *                    non-antialiased.
    725      * @return            true if the path (transformed by the canvas' matrix)
    726      *                    does not intersect with the canvas' clip
    727      */
    728     public boolean quickReject(Path path, EdgeType type) {
    729         return native_quickReject(mNativeCanvas, path.ni(), type.nativeInt);
    730     }
    731 
    732     /**
    733      * Return true if the specified rectangle, after being transformed by the
    734      * current matrix, would lie completely outside of the current clip. Call
    735      * this to check if an area you intend to draw into is clipped out (and
    736      * therefore you can skip making the draw calls).
    737      *
    738      * @param left        The left side of the rectangle to compare with the
    739      *                    current clip
    740      * @param top         The top of the rectangle to compare with the current
    741      *                    clip
    742      * @param right       The right side of the rectangle to compare with the
    743      *                    current clip
    744      * @param bottom      The bottom of the rectangle to compare with the
    745      *                    current clip
    746      * @param type        true if the rect should be considered antialiased,
    747      *                    since that means it may affect a larger area (more
    748      *                    pixels) than non-antialiased.
    749      * @return            true if the rect (transformed by the canvas' matrix)
    750      *                    does not intersect with the canvas' clip
    751      */
    752     public boolean quickReject(float left, float top, float right, float bottom, EdgeType type) {
    753         return native_quickReject(mNativeCanvas, left, top, right, bottom,
    754                                   type.nativeInt);
    755     }
    756 
    757     /**
    758      * Retrieve the clip bounds, returning true if they are non-empty.
    759      *
    760      * @param bounds Return the clip bounds here. If it is null, ignore it but
    761      *               still return true if the current clip is non-empty.
    762      * @return true if the current clip is non-empty.
    763      */
    764     public boolean getClipBounds(Rect bounds) {
    765         return native_getClipBounds(mNativeCanvas, bounds);
    766     }
    767 
    768     /**
    769      * Retrieve the clip bounds.
    770      *
    771      * @return the clip bounds, or [0, 0, 0, 0] if the clip is empty.
    772      */
    773     public final Rect getClipBounds() {
    774         Rect r = new Rect();
    775         getClipBounds(r);
    776         return r;
    777     }
    778 
    779     /**
    780      * Fill the entire canvas' bitmap (restricted to the current clip) with the
    781      * specified RGB color, using srcover porterduff mode.
    782      *
    783      * @param r red component (0..255) of the color to draw onto the canvas
    784      * @param g green component (0..255) of the color to draw onto the canvas
    785      * @param b blue component (0..255) of the color to draw onto the canvas
    786      */
    787     public void drawRGB(int r, int g, int b) {
    788         native_drawRGB(mNativeCanvas, r, g, b);
    789     }
    790 
    791     /**
    792      * Fill the entire canvas' bitmap (restricted to the current clip) with the
    793      * specified ARGB color, using srcover porterduff mode.
    794      *
    795      * @param a alpha component (0..255) of the color to draw onto the canvas
    796      * @param r red component (0..255) of the color to draw onto the canvas
    797      * @param g green component (0..255) of the color to draw onto the canvas
    798      * @param b blue component (0..255) of the color to draw onto the canvas
    799      */
    800     public void drawARGB(int a, int r, int g, int b) {
    801         native_drawARGB(mNativeCanvas, a, r, g, b);
    802     }
    803 
    804     /**
    805      * Fill the entire canvas' bitmap (restricted to the current clip) with the
    806      * specified color, using srcover porterduff mode.
    807      *
    808      * @param color the color to draw onto the canvas
    809      */
    810     public void drawColor(int color) {
    811         native_drawColor(mNativeCanvas, color);
    812     }
    813 
    814     /**
    815      * Fill the entire canvas' bitmap (restricted to the current clip) with the
    816      * specified color and porter-duff xfermode.
    817      *
    818      * @param color the color to draw with
    819      * @param mode  the porter-duff mode to apply to the color
    820      */
    821     public void drawColor(int color, PorterDuff.Mode mode) {
    822         native_drawColor(mNativeCanvas, color, mode.nativeInt);
    823     }
    824 
    825     /**
    826      * Fill the entire canvas' bitmap (restricted to the current clip) with
    827      * the specified paint. This is equivalent (but faster) to drawing an
    828      * infinitely large rectangle with the specified paint.
    829      *
    830      * @param paint The paint used to draw onto the canvas
    831      */
    832     public void drawPaint(Paint paint) {
    833         native_drawPaint(mNativeCanvas, paint.mNativePaint);
    834     }
    835 
    836     /**
    837      * Draw a series of points. Each point is centered at the coordinate
    838      * specified by pts[], and its diameter is specified by the paint's stroke
    839      * width (as transformed by the canvas' CTM), with special treatment for
    840      * a stroke width of 0, which always draws exactly 1 pixel (or at most 4
    841      * if antialiasing is enabled). The shape of the point is controlled by
    842      * the paint's Cap type. The shape is a square, unless the cap type is
    843      * Round, in which case the shape is a circle.
    844      *
    845      * @param pts      Array of points to draw [x0 y0 x1 y1 x2 y2 ...]
    846      * @param offset   Number of values to skip before starting to draw.
    847      * @param count    The number of values to process, after skipping offset
    848      *                 of them. Since one point uses two values, the number of
    849      *                 "points" that are drawn is really (count >> 1).
    850      * @param paint    The paint used to draw the points
    851      */
    852     public native void drawPoints(float[] pts, int offset, int count, Paint paint);
    853 
    854     /**
    855      * Helper for drawPoints() that assumes you want to draw the entire array
    856      */
    857     public void drawPoints(float[] pts, Paint paint) {
    858         drawPoints(pts, 0, pts.length, paint);
    859     }
    860 
    861     /**
    862      * Helper for drawPoints() for drawing a single point.
    863      */
    864     public native void drawPoint(float x, float y, Paint paint);
    865 
    866     /**
    867      * Draw a line segment with the specified start and stop x,y coordinates,
    868      * using the specified paint. NOTE: since a line is always "framed", the
    869      * Style is ignored in the paint.
    870      *
    871      * @param startX The x-coordinate of the start point of the line
    872      * @param startY The y-coordinate of the start point of the line
    873      * @param paint  The paint used to draw the line
    874      */
    875     public void drawLine(float startX, float startY, float stopX, float stopY, Paint paint) {
    876         native_drawLine(mNativeCanvas, startX, startY, stopX, stopY, paint.mNativePaint);
    877     }
    878 
    879     /**
    880      * Draw a series of lines. Each line is taken from 4 consecutive values
    881      * in the pts array. Thus to draw 1 line, the array must contain at least 4
    882      * values. This is logically the same as drawing the array as follows:
    883      * drawLine(pts[0], pts[1], pts[2], pts[3]) followed by
    884      * drawLine(pts[4], pts[5], pts[6], pts[7]) and so on.
    885      *
    886      * @param pts      Array of points to draw [x0 y0 x1 y1 x2 y2 ...]
    887      * @param offset   Number of values in the array to skip before drawing.
    888      * @param count    The number of values in the array to process, after
    889      *                 skipping "offset" of them. Since each line uses 4 values,
    890      *                 the number of "lines" that are drawn is really
    891      *                 (count >> 2).
    892      * @param paint    The paint used to draw the points
    893      */
    894     public native void drawLines(float[] pts, int offset, int count, Paint paint);
    895 
    896     public void drawLines(float[] pts, Paint paint) {
    897         drawLines(pts, 0, pts.length, paint);
    898     }
    899 
    900     /**
    901      * Draw the specified Rect using the specified paint. The rectangle will
    902      * be filled or framed based on the Style in the paint.
    903      *
    904      * @param rect  The rect to be drawn
    905      * @param paint The paint used to draw the rect
    906      */
    907     public void drawRect(RectF rect, Paint paint) {
    908         native_drawRect(mNativeCanvas, rect, paint.mNativePaint);
    909     }
    910 
    911     /**
    912      * Draw the specified Rect using the specified Paint. The rectangle
    913      * will be filled or framed based on the Style in the paint.
    914      *
    915      * @param r        The rectangle to be drawn.
    916      * @param paint    The paint used to draw the rectangle
    917      */
    918     public void drawRect(Rect r, Paint paint) {
    919         drawRect(r.left, r.top, r.right, r.bottom, paint);
    920     }
    921 
    922 
    923     /**
    924      * Draw the specified Rect using the specified paint. The rectangle will
    925      * be filled or framed based on the Style in the paint.
    926      *
    927      * @param left   The left side of the rectangle to be drawn
    928      * @param top    The top side of the rectangle to be drawn
    929      * @param right  The right side of the rectangle to be drawn
    930      * @param bottom The bottom side of the rectangle to be drawn
    931      * @param paint  The paint used to draw the rect
    932      */
    933     public void drawRect(float left, float top, float right, float bottom, Paint paint) {
    934         native_drawRect(mNativeCanvas, left, top, right, bottom, paint.mNativePaint);
    935     }
    936 
    937     /**
    938      * Draw the specified oval using the specified paint. The oval will be
    939      * filled or framed based on the Style in the paint.
    940      *
    941      * @param oval The rectangle bounds of the oval to be drawn
    942      */
    943     public void drawOval(RectF oval, Paint paint) {
    944         if (oval == null) {
    945             throw new NullPointerException();
    946         }
    947         native_drawOval(mNativeCanvas, oval, paint.mNativePaint);
    948     }
    949 
    950     /**
    951      * Draw the specified circle using the specified paint. If radius is <= 0,
    952      * then nothing will be drawn. The circle will be filled or framed based
    953      * on the Style in the paint.
    954      *
    955      * @param cx     The x-coordinate of the center of the cirle to be drawn
    956      * @param cy     The y-coordinate of the center of the cirle to be drawn
    957      * @param radius The radius of the cirle to be drawn
    958      * @param paint  The paint used to draw the circle
    959      */
    960     public void drawCircle(float cx, float cy, float radius, Paint paint) {
    961         native_drawCircle(mNativeCanvas, cx, cy, radius, paint.mNativePaint);
    962     }
    963 
    964     /**
    965      * <p>Draw the specified arc, which will be scaled to fit inside the
    966      * specified oval.</p>
    967      *
    968      * <p>If the start angle is negative or >= 360, the start angle is treated
    969      * as start angle modulo 360.</p>
    970      *
    971      * <p>If the sweep angle is >= 360, then the oval is drawn
    972      * completely. Note that this differs slightly from SkPath::arcTo, which
    973      * treats the sweep angle modulo 360. If the sweep angle is negative,
    974      * the sweep angle is treated as sweep angle modulo 360</p>
    975      *
    976      * <p>The arc is drawn clockwise. An angle of 0 degrees correspond to the
    977      * geometric angle of 0 degrees (3 o'clock on a watch.)</p>
    978      *
    979      * @param oval       The bounds of oval used to define the shape and size
    980      *                   of the arc
    981      * @param startAngle Starting angle (in degrees) where the arc begins
    982      * @param sweepAngle Sweep angle (in degrees) measured clockwise
    983      * @param useCenter If true, include the center of the oval in the arc, and
    984                         close it if it is being stroked. This will draw a wedge
    985      * @param paint      The paint used to draw the arc
    986      */
    987     public void drawArc(RectF oval, float startAngle, float sweepAngle, boolean useCenter,
    988             Paint paint) {
    989         if (oval == null) {
    990             throw new NullPointerException();
    991         }
    992         native_drawArc(mNativeCanvas, oval, startAngle, sweepAngle,
    993                        useCenter, paint.mNativePaint);
    994     }
    995 
    996     /**
    997      * Draw the specified round-rect using the specified paint. The roundrect
    998      * will be filled or framed based on the Style in the paint.
    999      *
   1000      * @param rect  The rectangular bounds of the roundRect to be drawn
   1001      * @param rx    The x-radius of the oval used to round the corners
   1002      * @param ry    The y-radius of the oval used to round the corners
   1003      * @param paint The paint used to draw the roundRect
   1004      */
   1005     public void drawRoundRect(RectF rect, float rx, float ry, Paint paint) {
   1006         if (rect == null) {
   1007             throw new NullPointerException();
   1008         }
   1009         native_drawRoundRect(mNativeCanvas, rect, rx, ry,
   1010                              paint.mNativePaint);
   1011     }
   1012 
   1013     /**
   1014      * Draw the specified path using the specified paint. The path will be
   1015      * filled or framed based on the Style in the paint.
   1016      *
   1017      * @param path  The path to be drawn
   1018      * @param paint The paint used to draw the path
   1019      */
   1020     public void drawPath(Path path, Paint paint) {
   1021         native_drawPath(mNativeCanvas, path.ni(), paint.mNativePaint);
   1022     }
   1023 
   1024     private static void throwIfRecycled(Bitmap bitmap) {
   1025         if (bitmap.isRecycled()) {
   1026             throw new RuntimeException("Canvas: trying to use a recycled bitmap " + bitmap);
   1027         }
   1028     }
   1029 
   1030     /**
   1031      * Draws the specified bitmap as an N-patch (most often, a 9-patches.)
   1032      *
   1033      * Note: Only supported by hardware accelerated canvas at the moment.
   1034      *
   1035      * @param bitmap The bitmap to draw as an N-patch
   1036      * @param chunks The patches information (matches the native struct Res_png_9patch)
   1037      * @param dst The destination rectangle.
   1038      * @param paint The paint to draw the bitmap with. may be null
   1039      *
   1040      * @hide
   1041      */
   1042     public void drawPatch(Bitmap bitmap, byte[] chunks, RectF dst, Paint paint) {
   1043     }
   1044 
   1045     /**
   1046      * Draw the specified bitmap, with its top/left corner at (x,y), using
   1047      * the specified paint, transformed by the current matrix.
   1048      *
   1049      * <p>Note: if the paint contains a maskfilter that generates a mask which
   1050      * extends beyond the bitmap's original width/height (e.g. BlurMaskFilter),
   1051      * then the bitmap will be drawn as if it were in a Shader with CLAMP mode.
   1052      * Thus the color outside of the original width/height will be the edge
   1053      * color replicated.
   1054      *
   1055      * <p>If the bitmap and canvas have different densities, this function
   1056      * will take care of automatically scaling the bitmap to draw at the
   1057      * same density as the canvas.
   1058      *
   1059      * @param bitmap The bitmap to be drawn
   1060      * @param left   The position of the left side of the bitmap being drawn
   1061      * @param top    The position of the top side of the bitmap being drawn
   1062      * @param paint  The paint used to draw the bitmap (may be null)
   1063      */
   1064     public void drawBitmap(Bitmap bitmap, float left, float top, Paint paint) {
   1065         throwIfRecycled(bitmap);
   1066         native_drawBitmap(mNativeCanvas, bitmap.ni(), left, top,
   1067                 paint != null ? paint.mNativePaint : 0, mDensity, mScreenDensity, bitmap.mDensity);
   1068     }
   1069 
   1070     /**
   1071      * Draw the specified bitmap, scaling/translating automatically to fill
   1072      * the destination rectangle. If the source rectangle is not null, it
   1073      * specifies the subset of the bitmap to draw.
   1074      *
   1075      * <p>Note: if the paint contains a maskfilter that generates a mask which
   1076      * extends beyond the bitmap's original width/height (e.g. BlurMaskFilter),
   1077      * then the bitmap will be drawn as if it were in a Shader with CLAMP mode.
   1078      * Thus the color outside of the original width/height will be the edge
   1079      * color replicated.
   1080      *
   1081      * <p>This function <em>ignores the density associated with the bitmap</em>.
   1082      * This is because the source and destination rectangle coordinate
   1083      * spaces are in their respective densities, so must already have the
   1084      * appropriate scaling factor applied.
   1085      *
   1086      * @param bitmap The bitmap to be drawn
   1087      * @param src    May be null. The subset of the bitmap to be drawn
   1088      * @param dst    The rectangle that the bitmap will be scaled/translated
   1089      *               to fit into
   1090      * @param paint  May be null. The paint used to draw the bitmap
   1091      */
   1092     public void drawBitmap(Bitmap bitmap, Rect src, RectF dst, Paint paint) {
   1093         if (dst == null) {
   1094             throw new NullPointerException();
   1095         }
   1096         throwIfRecycled(bitmap);
   1097         native_drawBitmap(mNativeCanvas, bitmap.ni(), src, dst,
   1098                           paint != null ? paint.mNativePaint : 0, mScreenDensity, bitmap.mDensity);
   1099     }
   1100 
   1101     /**
   1102      * Draw the specified bitmap, scaling/translating automatically to fill
   1103      * the destination rectangle. If the source rectangle is not null, it
   1104      * specifies the subset of the bitmap to draw.
   1105      *
   1106      * <p>Note: if the paint contains a maskfilter that generates a mask which
   1107      * extends beyond the bitmap's original width/height (e.g. BlurMaskFilter),
   1108      * then the bitmap will be drawn as if it were in a Shader with CLAMP mode.
   1109      * Thus the color outside of the original width/height will be the edge
   1110      * color replicated.
   1111      *
   1112      * <p>This function <em>ignores the density associated with the bitmap</em>.
   1113      * This is because the source and destination rectangle coordinate
   1114      * spaces are in their respective densities, so must already have the
   1115      * appropriate scaling factor applied.
   1116      *
   1117      * @param bitmap The bitmap to be drawn
   1118      * @param src    May be null. The subset of the bitmap to be drawn
   1119      * @param dst    The rectangle that the bitmap will be scaled/translated
   1120      *               to fit into
   1121      * @param paint  May be null. The paint used to draw the bitmap
   1122      */
   1123     public void drawBitmap(Bitmap bitmap, Rect src, Rect dst, Paint paint) {
   1124         if (dst == null) {
   1125             throw new NullPointerException();
   1126         }
   1127         throwIfRecycled(bitmap);
   1128         native_drawBitmap(mNativeCanvas, bitmap.ni(), src, dst,
   1129                           paint != null ? paint.mNativePaint : 0, mScreenDensity, bitmap.mDensity);
   1130     }
   1131 
   1132     /**
   1133      * Treat the specified array of colors as a bitmap, and draw it. This gives
   1134      * the same result as first creating a bitmap from the array, and then
   1135      * drawing it, but this method avoids explicitly creating a bitmap object
   1136      * which can be more efficient if the colors are changing often.
   1137      *
   1138      * @param colors Array of colors representing the pixels of the bitmap
   1139      * @param offset Offset into the array of colors for the first pixel
   1140      * @param stride The number of colors in the array between rows (must be
   1141      *               >= width or <= -width).
   1142      * @param x The X coordinate for where to draw the bitmap
   1143      * @param y The Y coordinate for where to draw the bitmap
   1144      * @param width The width of the bitmap
   1145      * @param height The height of the bitmap
   1146      * @param hasAlpha True if the alpha channel of the colors contains valid
   1147      *                 values. If false, the alpha byte is ignored (assumed to
   1148      *                 be 0xFF for every pixel).
   1149      * @param paint  May be null. The paint used to draw the bitmap
   1150      */
   1151     public void drawBitmap(int[] colors, int offset, int stride, float x, float y,
   1152             int width, int height, boolean hasAlpha, Paint paint) {
   1153         // check for valid input
   1154         if (width < 0) {
   1155             throw new IllegalArgumentException("width must be >= 0");
   1156         }
   1157         if (height < 0) {
   1158             throw new IllegalArgumentException("height must be >= 0");
   1159         }
   1160         if (Math.abs(stride) < width) {
   1161             throw new IllegalArgumentException("abs(stride) must be >= width");
   1162         }
   1163         int lastScanline = offset + (height - 1) * stride;
   1164         int length = colors.length;
   1165         if (offset < 0 || (offset + width > length) || lastScanline < 0
   1166                 || (lastScanline + width > length)) {
   1167             throw new ArrayIndexOutOfBoundsException();
   1168         }
   1169         // quick escape if there's nothing to draw
   1170         if (width == 0 || height == 0) {
   1171             return;
   1172         }
   1173         // punch down to native for the actual draw
   1174         native_drawBitmap(mNativeCanvas, colors, offset, stride, x, y, width, height, hasAlpha,
   1175                 paint != null ? paint.mNativePaint : 0);
   1176     }
   1177 
   1178     /** Legacy version of drawBitmap(int[] colors, ...) that took ints for x,y
   1179      */
   1180     public void drawBitmap(int[] colors, int offset, int stride, int x, int y,
   1181             int width, int height, boolean hasAlpha, Paint paint) {
   1182         // call through to the common float version
   1183         drawBitmap(colors, offset, stride, (float)x, (float)y, width, height,
   1184                    hasAlpha, paint);
   1185     }
   1186 
   1187     /**
   1188      * Draw the bitmap using the specified matrix.
   1189      *
   1190      * @param bitmap The bitmap to draw
   1191      * @param matrix The matrix used to transform the bitmap when it is drawn
   1192      * @param paint  May be null. The paint used to draw the bitmap
   1193      */
   1194     public void drawBitmap(Bitmap bitmap, Matrix matrix, Paint paint) {
   1195         nativeDrawBitmapMatrix(mNativeCanvas, bitmap.ni(), matrix.ni(),
   1196                 paint != null ? paint.mNativePaint : 0);
   1197     }
   1198 
   1199     /**
   1200      * @hide
   1201      */
   1202     protected static void checkRange(int length, int offset, int count) {
   1203         if ((offset | count) < 0 || offset + count > length) {
   1204             throw new ArrayIndexOutOfBoundsException();
   1205         }
   1206     }
   1207 
   1208     /**
   1209      * Draw the bitmap through the mesh, where mesh vertices are evenly
   1210      * distributed across the bitmap. There are meshWidth+1 vertices across, and
   1211      * meshHeight+1 vertices down. The verts array is accessed in row-major
   1212      * order, so that the first meshWidth+1 vertices are distributed across the
   1213      * top of the bitmap from left to right. A more general version of this
   1214      * methid is drawVertices().
   1215      *
   1216      * @param bitmap The bitmap to draw using the mesh
   1217      * @param meshWidth The number of columns in the mesh. Nothing is drawn if
   1218      *                  this is 0
   1219      * @param meshHeight The number of rows in the mesh. Nothing is drawn if
   1220      *                   this is 0
   1221      * @param verts Array of x,y pairs, specifying where the mesh should be
   1222      *              drawn. There must be at least
   1223      *              (meshWidth+1) * (meshHeight+1) * 2 + meshOffset values
   1224      *              in the array
   1225      * @param vertOffset Number of verts elements to skip before drawing
   1226      * @param colors May be null. Specifies a color at each vertex, which is
   1227      *               interpolated across the cell, and whose values are
   1228      *               multiplied by the corresponding bitmap colors. If not null,
   1229      *               there must be at least (meshWidth+1) * (meshHeight+1) +
   1230      *               colorOffset values in the array.
   1231      * @param colorOffset Number of color elements to skip before drawing
   1232      * @param paint  May be null. The paint used to draw the bitmap
   1233      */
   1234     public void drawBitmapMesh(Bitmap bitmap, int meshWidth, int meshHeight,
   1235             float[] verts, int vertOffset, int[] colors, int colorOffset, Paint paint) {
   1236         if ((meshWidth | meshHeight | vertOffset | colorOffset) < 0) {
   1237             throw new ArrayIndexOutOfBoundsException();
   1238         }
   1239         if (meshWidth == 0 || meshHeight == 0) {
   1240             return;
   1241         }
   1242         int count = (meshWidth + 1) * (meshHeight + 1);
   1243         // we mul by 2 since we need two floats per vertex
   1244         checkRange(verts.length, vertOffset, count * 2);
   1245         if (colors != null) {
   1246             // no mul by 2, since we need only 1 color per vertex
   1247             checkRange(colors.length, colorOffset, count);
   1248         }
   1249         nativeDrawBitmapMesh(mNativeCanvas, bitmap.ni(), meshWidth, meshHeight,
   1250                              verts, vertOffset, colors, colorOffset,
   1251                              paint != null ? paint.mNativePaint : 0);
   1252     }
   1253 
   1254     public enum VertexMode {
   1255         TRIANGLES(0),
   1256         TRIANGLE_STRIP(1),
   1257         TRIANGLE_FAN(2);
   1258 
   1259         VertexMode(int nativeInt) {
   1260             this.nativeInt = nativeInt;
   1261         }
   1262 
   1263         /**
   1264          * @hide
   1265          */
   1266         public final int nativeInt;
   1267     }
   1268 
   1269     /**
   1270      * Draw the array of vertices, interpreted as triangles (based on mode). The
   1271      * verts array is required, and specifies the x,y pairs for each vertex. If
   1272      * texs is non-null, then it is used to specify the coordinate in shader
   1273      * coordinates to use at each vertex (the paint must have a shader in this
   1274      * case). If there is no texs array, but there is a color array, then each
   1275      * color is interpolated across its corresponding triangle in a gradient. If
   1276      * both texs and colors arrays are present, then they behave as before, but
   1277      * the resulting color at each pixels is the result of multiplying the
   1278      * colors from the shader and the color-gradient together. The indices array
   1279      * is optional, but if it is present, then it is used to specify the index
   1280      * of each triangle, rather than just walking through the arrays in order.
   1281      *
   1282      * @param mode How to interpret the array of vertices
   1283      * @param vertexCount The number of values in the vertices array (and
   1284      *      corresponding texs and colors arrays if non-null). Each logical
   1285      *      vertex is two values (x, y), vertexCount must be a multiple of 2.
   1286      * @param verts Array of vertices for the mesh
   1287      * @param vertOffset Number of values in the verts to skip before drawing.
   1288      * @param texs May be null. If not null, specifies the coordinates to sample
   1289      *      into the current shader (e.g. bitmap tile or gradient)
   1290      * @param texOffset Number of values in texs to skip before drawing.
   1291      * @param colors May be null. If not null, specifies a color for each
   1292      *      vertex, to be interpolated across the triangle.
   1293      * @param colorOffset Number of values in colors to skip before drawing.
   1294      * @param indices If not null, array of indices to reference into the
   1295      *      vertex (texs, colors) array.
   1296      * @param indexCount number of entries in the indices array (if not null).
   1297      * @param paint Specifies the shader to use if the texs array is non-null.
   1298      */
   1299     public void drawVertices(VertexMode mode, int vertexCount, float[] verts, int vertOffset,
   1300             float[] texs, int texOffset, int[] colors, int colorOffset,
   1301             short[] indices, int indexOffset, int indexCount, Paint paint) {
   1302         checkRange(verts.length, vertOffset, vertexCount);
   1303         if (texs != null) {
   1304             checkRange(texs.length, texOffset, vertexCount);
   1305         }
   1306         if (colors != null) {
   1307             checkRange(colors.length, colorOffset, vertexCount / 2);
   1308         }
   1309         if (indices != null) {
   1310             checkRange(indices.length, indexOffset, indexCount);
   1311         }
   1312         nativeDrawVertices(mNativeCanvas, mode.nativeInt, vertexCount, verts,
   1313                            vertOffset, texs, texOffset, colors, colorOffset,
   1314                           indices, indexOffset, indexCount, paint.mNativePaint);
   1315     }
   1316 
   1317     /**
   1318      * Draw the text, with origin at (x,y), using the specified paint. The
   1319      * origin is interpreted based on the Align setting in the paint.
   1320      *
   1321      * @param text  The text to be drawn
   1322      * @param x     The x-coordinate of the origin of the text being drawn
   1323      * @param y     The y-coordinate of the origin of the text being drawn
   1324      * @param paint The paint used for the text (e.g. color, size, style)
   1325      */
   1326     public void drawText(char[] text, int index, int count, float x, float y, Paint paint) {
   1327         if ((index | count | (index + count) |
   1328             (text.length - index - count)) < 0) {
   1329             throw new IndexOutOfBoundsException();
   1330         }
   1331         native_drawText(mNativeCanvas, text, index, count, x, y, paint.mBidiFlags,
   1332                 paint.mNativePaint);
   1333     }
   1334 
   1335     /**
   1336      * Draw the text, with origin at (x,y), using the specified paint. The
   1337      * origin is interpreted based on the Align setting in the paint.
   1338      *
   1339      * @param text  The text to be drawn
   1340      * @param x     The x-coordinate of the origin of the text being drawn
   1341      * @param y     The y-coordinate of the origin of the text being drawn
   1342      * @param paint The paint used for the text (e.g. color, size, style)
   1343      */
   1344     public void drawText(String text, float x, float y, Paint paint) {
   1345         native_drawText(mNativeCanvas, text, 0, text.length(), x, y, paint.mBidiFlags,
   1346                 paint.mNativePaint);
   1347     }
   1348 
   1349     /**
   1350      * Draw the text, with origin at (x,y), using the specified paint.
   1351      * The origin is interpreted based on the Align setting in the paint.
   1352      *
   1353      * @param text  The text to be drawn
   1354      * @param start The index of the first character in text to draw
   1355      * @param end   (end - 1) is the index of the last character in text to draw
   1356      * @param x     The x-coordinate of the origin of the text being drawn
   1357      * @param y     The y-coordinate of the origin of the text being drawn
   1358      * @param paint The paint used for the text (e.g. color, size, style)
   1359      */
   1360     public void drawText(String text, int start, int end, float x, float y, Paint paint) {
   1361         if ((start | end | (end - start) | (text.length() - end)) < 0) {
   1362             throw new IndexOutOfBoundsException();
   1363         }
   1364         native_drawText(mNativeCanvas, text, start, end, x, y, paint.mBidiFlags,
   1365                 paint.mNativePaint);
   1366     }
   1367 
   1368     /**
   1369      * Draw the specified range of text, specified by start/end, with its
   1370      * origin at (x,y), in the specified Paint. The origin is interpreted
   1371      * based on the Align setting in the Paint.
   1372      *
   1373      * @param text     The text to be drawn
   1374      * @param start    The index of the first character in text to draw
   1375      * @param end      (end - 1) is the index of the last character in text
   1376      *                 to draw
   1377      * @param x        The x-coordinate of origin for where to draw the text
   1378      * @param y        The y-coordinate of origin for where to draw the text
   1379      * @param paint The paint used for the text (e.g. color, size, style)
   1380      */
   1381     public void drawText(CharSequence text, int start, int end, float x, float y, Paint paint) {
   1382         if (text instanceof String || text instanceof SpannedString ||
   1383             text instanceof SpannableString) {
   1384             native_drawText(mNativeCanvas, text.toString(), start, end, x, y,
   1385                             paint.mBidiFlags, paint.mNativePaint);
   1386         } else if (text instanceof GraphicsOperations) {
   1387             ((GraphicsOperations) text).drawText(this, start, end, x, y,
   1388                                                      paint);
   1389         } else {
   1390             char[] buf = TemporaryBuffer.obtain(end - start);
   1391             TextUtils.getChars(text, start, end, buf, 0);
   1392             native_drawText(mNativeCanvas, buf, 0, end - start, x, y,
   1393                     paint.mBidiFlags, paint.mNativePaint);
   1394             TemporaryBuffer.recycle(buf);
   1395         }
   1396     }
   1397 
   1398     /**
   1399      * Render a run of all LTR or all RTL text, with shaping. This does not run
   1400      * bidi on the provided text, but renders it as a uniform right-to-left or
   1401      * left-to-right run, as indicated by dir. Alignment of the text is as
   1402      * determined by the Paint's TextAlign value.
   1403      *
   1404      * @param text the text to render
   1405      * @param index the start of the text to render
   1406      * @param count the count of chars to render
   1407      * @param contextIndex the start of the context for shaping.  Must be
   1408      *         no greater than index.
   1409      * @param contextCount the number of characters in the context for shaping.
   1410      *         ContexIndex + contextCount must be no less than index
   1411      *         + count.
   1412      * @param x the x position at which to draw the text
   1413      * @param y the y position at which to draw the text
   1414      * @param dir the run direction, either {@link #DIRECTION_LTR} or
   1415      *         {@link #DIRECTION_RTL}.
   1416      * @param paint the paint
   1417      * @hide
   1418      */
   1419     public void drawTextRun(char[] text, int index, int count, int contextIndex, int contextCount,
   1420             float x, float y, int dir, Paint paint) {
   1421 
   1422         if (text == null) {
   1423             throw new NullPointerException("text is null");
   1424         }
   1425         if (paint == null) {
   1426             throw new NullPointerException("paint is null");
   1427         }
   1428         if ((index | count | text.length - index - count) < 0) {
   1429             throw new IndexOutOfBoundsException();
   1430         }
   1431         if (dir != DIRECTION_LTR && dir != DIRECTION_RTL) {
   1432             throw new IllegalArgumentException("unknown dir: " + dir);
   1433         }
   1434 
   1435         native_drawTextRun(mNativeCanvas, text, index, count,
   1436                 contextIndex, contextCount, x, y, dir, paint.mNativePaint);
   1437     }
   1438 
   1439     /**
   1440      * Render a run of all LTR or all RTL text, with shaping. This does not run
   1441      * bidi on the provided text, but renders it as a uniform right-to-left or
   1442      * left-to-right run, as indicated by dir. Alignment of the text is as
   1443      * determined by the Paint's TextAlign value.
   1444      *
   1445      * @param text the text to render
   1446      * @param start the start of the text to render. Data before this position
   1447      *            can be used for shaping context.
   1448      * @param end the end of the text to render. Data at or after this
   1449      *            position can be used for shaping context.
   1450      * @param x the x position at which to draw the text
   1451      * @param y the y position at which to draw the text
   1452      * @param dir the run direction, either 0 for LTR or 1 for RTL.
   1453      * @param paint the paint
   1454      * @hide
   1455      */
   1456     public void drawTextRun(CharSequence text, int start, int end, int contextStart, int contextEnd,
   1457             float x, float y, int dir, Paint paint) {
   1458 
   1459         if (text == null) {
   1460             throw new NullPointerException("text is null");
   1461         }
   1462         if (paint == null) {
   1463             throw new NullPointerException("paint is null");
   1464         }
   1465         if ((start | end | end - start | text.length() - end) < 0) {
   1466             throw new IndexOutOfBoundsException();
   1467         }
   1468 
   1469         int flags = dir == 0 ? 0 : 1;
   1470 
   1471         if (text instanceof String || text instanceof SpannedString ||
   1472                 text instanceof SpannableString) {
   1473             native_drawTextRun(mNativeCanvas, text.toString(), start, end,
   1474                     contextStart, contextEnd, x, y, flags, paint.mNativePaint);
   1475         } else if (text instanceof GraphicsOperations) {
   1476             ((GraphicsOperations) text).drawTextRun(this, start, end,
   1477                     contextStart, contextEnd, x, y, flags, paint);
   1478         } else {
   1479             int contextLen = contextEnd - contextStart;
   1480             int len = end - start;
   1481             char[] buf = TemporaryBuffer.obtain(contextLen);
   1482             TextUtils.getChars(text, contextStart, contextEnd, buf, 0);
   1483             native_drawTextRun(mNativeCanvas, buf, start - contextStart, len,
   1484                     0, contextLen, x, y, flags, paint.mNativePaint);
   1485             TemporaryBuffer.recycle(buf);
   1486         }
   1487     }
   1488 
   1489     /**
   1490      * Draw the text in the array, with each character's origin specified by
   1491      * the pos array.
   1492      *
   1493      * This method does not support glyph composition and decomposition and
   1494      * should therefore not be used to render complex scripts.
   1495      *
   1496      * @param text     The text to be drawn
   1497      * @param index    The index of the first character to draw
   1498      * @param count    The number of characters to draw, starting from index.
   1499      * @param pos      Array of [x,y] positions, used to position each
   1500      *                 character
   1501      * @param paint    The paint used for the text (e.g. color, size, style)
   1502      */
   1503     @Deprecated
   1504     public void drawPosText(char[] text, int index, int count, float[] pos, Paint paint) {
   1505         if (index < 0 || index + count > text.length || count*2 > pos.length) {
   1506             throw new IndexOutOfBoundsException();
   1507         }
   1508         native_drawPosText(mNativeCanvas, text, index, count, pos,
   1509                            paint.mNativePaint);
   1510     }
   1511 
   1512     /**
   1513      * Draw the text in the array, with each character's origin specified by
   1514      * the pos array.
   1515      *
   1516      * This method does not support glyph composition and decomposition and
   1517      * should therefore not be used to render complex scripts.
   1518      *
   1519      * @param text  The text to be drawn
   1520      * @param pos   Array of [x,y] positions, used to position each character
   1521      * @param paint The paint used for the text (e.g. color, size, style)
   1522      */
   1523     @Deprecated
   1524     public void drawPosText(String text, float[] pos, Paint paint) {
   1525         if (text.length()*2 > pos.length) {
   1526             throw new ArrayIndexOutOfBoundsException();
   1527         }
   1528         native_drawPosText(mNativeCanvas, text, pos, paint.mNativePaint);
   1529     }
   1530 
   1531     /**
   1532      * Draw the text, with origin at (x,y), using the specified paint, along
   1533      * the specified path. The paint's Align setting determins where along the
   1534      * path to start the text.
   1535      *
   1536      * @param text     The text to be drawn
   1537      * @param path     The path the text should follow for its baseline
   1538      * @param hOffset  The distance along the path to add to the text's
   1539      *                 starting position
   1540      * @param vOffset  The distance above(-) or below(+) the path to position
   1541      *                 the text
   1542      * @param paint    The paint used for the text (e.g. color, size, style)
   1543      */
   1544     public void drawTextOnPath(char[] text, int index, int count, Path path,
   1545             float hOffset, float vOffset, Paint paint) {
   1546         if (index < 0 || index + count > text.length) {
   1547             throw new ArrayIndexOutOfBoundsException();
   1548         }
   1549         native_drawTextOnPath(mNativeCanvas, text, index, count,
   1550                               path.ni(), hOffset, vOffset,
   1551                               paint.mBidiFlags, paint.mNativePaint);
   1552     }
   1553 
   1554     /**
   1555      * Draw the text, with origin at (x,y), using the specified paint, along
   1556      * the specified path. The paint's Align setting determins where along the
   1557      * path to start the text.
   1558      *
   1559      * @param text     The text to be drawn
   1560      * @param path     The path the text should follow for its baseline
   1561      * @param hOffset  The distance along the path to add to the text's
   1562      *                 starting position
   1563      * @param vOffset  The distance above(-) or below(+) the path to position
   1564      *                 the text
   1565      * @param paint    The paint used for the text (e.g. color, size, style)
   1566      */
   1567     public void drawTextOnPath(String text, Path path, float hOffset, float vOffset, Paint paint) {
   1568         if (text.length() > 0) {
   1569             native_drawTextOnPath(mNativeCanvas, text, path.ni(), hOffset, vOffset,
   1570                     paint.mBidiFlags, paint.mNativePaint);
   1571         }
   1572     }
   1573 
   1574     /**
   1575      * Save the canvas state, draw the picture, and restore the canvas state.
   1576      * This differs from picture.draw(canvas), which does not perform any
   1577      * save/restore.
   1578      *
   1579      * @param picture  The picture to be drawn
   1580      */
   1581     public void drawPicture(Picture picture) {
   1582         picture.endRecording();
   1583         native_drawPicture(mNativeCanvas, picture.ni());
   1584     }
   1585 
   1586     /**
   1587      * Draw the picture, stretched to fit into the dst rectangle.
   1588      */
   1589     public void drawPicture(Picture picture, RectF dst) {
   1590         save();
   1591         translate(dst.left, dst.top);
   1592         if (picture.getWidth() > 0 && picture.getHeight() > 0) {
   1593             scale(dst.width() / picture.getWidth(), dst.height() / picture.getHeight());
   1594         }
   1595         drawPicture(picture);
   1596         restore();
   1597     }
   1598 
   1599     /**
   1600      * Draw the picture, stretched to fit into the dst rectangle.
   1601      */
   1602     public void drawPicture(Picture picture, Rect dst) {
   1603         save();
   1604         translate(dst.left, dst.top);
   1605         if (picture.getWidth() > 0 && picture.getHeight() > 0) {
   1606             scale((float) dst.width() / picture.getWidth(),
   1607                     (float) dst.height() / picture.getHeight());
   1608         }
   1609         drawPicture(picture);
   1610         restore();
   1611     }
   1612 
   1613     /**
   1614      * Free up as much memory as possible from private caches (e.g. fonts, images)
   1615      *
   1616      * @hide
   1617      */
   1618     public static native void freeCaches();
   1619 
   1620     /**
   1621      * Free up text layout caches
   1622      *
   1623      * @hide
   1624      */
   1625     public static native void freeTextLayoutCaches();
   1626 
   1627     private static native int initRaster(int nativeBitmapOrZero);
   1628     private static native void native_setBitmap(int nativeCanvas, int bitmap);
   1629     private static native int native_saveLayer(int nativeCanvas, RectF bounds,
   1630                                                int paint, int layerFlags);
   1631     private static native int native_saveLayer(int nativeCanvas, float l,
   1632                                                float t, float r, float b,
   1633                                                int paint, int layerFlags);
   1634     private static native int native_saveLayerAlpha(int nativeCanvas,
   1635                                                     RectF bounds, int alpha,
   1636                                                     int layerFlags);
   1637     private static native int native_saveLayerAlpha(int nativeCanvas, float l,
   1638                                                     float t, float r, float b,
   1639                                                     int alpha, int layerFlags);
   1640 
   1641     private static native void native_concat(int nCanvas, int nMatrix);
   1642     private static native void native_setMatrix(int nCanvas, int nMatrix);
   1643     private static native boolean native_clipRect(int nCanvas,
   1644                                                   float left, float top,
   1645                                                   float right, float bottom,
   1646                                                   int regionOp);
   1647     private static native boolean native_clipPath(int nativeCanvas,
   1648                                                   int nativePath,
   1649                                                   int regionOp);
   1650     private static native boolean native_clipRegion(int nativeCanvas,
   1651                                                     int nativeRegion,
   1652                                                     int regionOp);
   1653     private static native void nativeSetDrawFilter(int nativeCanvas,
   1654                                                    int nativeFilter);
   1655     private static native boolean native_getClipBounds(int nativeCanvas,
   1656                                                        Rect bounds);
   1657     private static native void native_getCTM(int canvas, int matrix);
   1658     private static native boolean native_quickReject(int nativeCanvas,
   1659                                                      RectF rect,
   1660                                                      int native_edgeType);
   1661     private static native boolean native_quickReject(int nativeCanvas,
   1662                                                      int path,
   1663                                                      int native_edgeType);
   1664     private static native boolean native_quickReject(int nativeCanvas,
   1665                                                      float left, float top,
   1666                                                      float right, float bottom,
   1667                                                      int native_edgeType);
   1668     private static native void native_drawRGB(int nativeCanvas, int r, int g,
   1669                                               int b);
   1670     private static native void native_drawARGB(int nativeCanvas, int a, int r,
   1671                                                int g, int b);
   1672     private static native void native_drawColor(int nativeCanvas, int color);
   1673     private static native void native_drawColor(int nativeCanvas, int color,
   1674                                                 int mode);
   1675     private static native void native_drawPaint(int nativeCanvas, int paint);
   1676     private static native void native_drawLine(int nativeCanvas, float startX,
   1677                                                float startY, float stopX,
   1678                                                float stopY, int paint);
   1679     private static native void native_drawRect(int nativeCanvas, RectF rect,
   1680                                                int paint);
   1681     private static native void native_drawRect(int nativeCanvas, float left,
   1682                                                float top, float right,
   1683                                                float bottom, int paint);
   1684     private static native void native_drawOval(int nativeCanvas, RectF oval,
   1685                                                int paint);
   1686     private static native void native_drawCircle(int nativeCanvas, float cx,
   1687                                                  float cy, float radius,
   1688                                                  int paint);
   1689     private static native void native_drawArc(int nativeCanvas, RectF oval,
   1690                                               float startAngle, float sweep,
   1691                                               boolean useCenter, int paint);
   1692     private static native void native_drawRoundRect(int nativeCanvas,
   1693                                                     RectF rect, float rx,
   1694                                                     float ry, int paint);
   1695     private static native void native_drawPath(int nativeCanvas, int path,
   1696                                                int paint);
   1697     private native void native_drawBitmap(int nativeCanvas, int bitmap,
   1698                                                  float left, float top,
   1699                                                  int nativePaintOrZero,
   1700                                                  int canvasDensity,
   1701                                                  int screenDensity,
   1702                                                  int bitmapDensity);
   1703     private native void native_drawBitmap(int nativeCanvas, int bitmap,
   1704                                                  Rect src, RectF dst,
   1705                                                  int nativePaintOrZero,
   1706                                                  int screenDensity,
   1707                                                  int bitmapDensity);
   1708     private static native void native_drawBitmap(int nativeCanvas, int bitmap,
   1709                                                  Rect src, Rect dst,
   1710                                                  int nativePaintOrZero,
   1711                                                  int screenDensity,
   1712                                                  int bitmapDensity);
   1713     private static native void native_drawBitmap(int nativeCanvas, int[] colors,
   1714                                                 int offset, int stride, float x,
   1715                                                  float y, int width, int height,
   1716                                                  boolean hasAlpha,
   1717                                                  int nativePaintOrZero);
   1718     private static native void nativeDrawBitmapMatrix(int nCanvas, int nBitmap,
   1719                                                       int nMatrix, int nPaint);
   1720     private static native void nativeDrawBitmapMesh(int nCanvas, int nBitmap,
   1721                                                     int meshWidth, int meshHeight,
   1722                                                     float[] verts, int vertOffset,
   1723                                                     int[] colors, int colorOffset, int nPaint);
   1724     private static native void nativeDrawVertices(int nCanvas, int mode, int n,
   1725                    float[] verts, int vertOffset, float[] texs, int texOffset,
   1726                    int[] colors, int colorOffset, short[] indices,
   1727                    int indexOffset, int indexCount, int nPaint);
   1728 
   1729     private static native void native_drawText(int nativeCanvas, char[] text,
   1730                                                int index, int count, float x,
   1731                                                float y, int flags, int paint);
   1732     private static native void native_drawText(int nativeCanvas, String text,
   1733                                                int start, int end, float x,
   1734                                                float y, int flags, int paint);
   1735 
   1736     private static native void native_drawTextRun(int nativeCanvas, String text,
   1737             int start, int end, int contextStart, int contextEnd,
   1738             float x, float y, int flags, int paint);
   1739 
   1740     private static native void native_drawTextRun(int nativeCanvas, char[] text,
   1741             int start, int count, int contextStart, int contextCount,
   1742             float x, float y, int flags, int paint);
   1743 
   1744     private static native void native_drawPosText(int nativeCanvas,
   1745                                                   char[] text, int index,
   1746                                                   int count, float[] pos,
   1747                                                   int paint);
   1748     private static native void native_drawPosText(int nativeCanvas,
   1749                                                   String text, float[] pos,
   1750                                                   int paint);
   1751     private static native void native_drawTextOnPath(int nativeCanvas,
   1752                                                      char[] text, int index,
   1753                                                      int count, int path,
   1754                                                      float hOffset,
   1755                                                      float vOffset, int bidiFlags,
   1756                                                      int paint);
   1757     private static native void native_drawTextOnPath(int nativeCanvas,
   1758                                                      String text, int path,
   1759                                                      float hOffset,
   1760                                                      float vOffset,
   1761                                                      int flags, int paint);
   1762     private static native void native_drawPicture(int nativeCanvas,
   1763                                                   int nativePicture);
   1764     private static native void finalizer(int nativeCanvas);
   1765 }
   1766