Home | History | Annotate | Download | only in view
      1 /*
      2  * Copyright (C) 2010 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.view;
     18 
     19 import android.graphics.Bitmap;
     20 import android.graphics.Canvas;
     21 import android.graphics.CanvasProperty;
     22 import android.graphics.DrawFilter;
     23 import android.graphics.Matrix;
     24 import android.graphics.NinePatch;
     25 import android.graphics.Paint;
     26 import android.graphics.PaintFlagsDrawFilter;
     27 import android.graphics.Path;
     28 import android.graphics.Picture;
     29 import android.graphics.PorterDuff;
     30 import android.graphics.Rect;
     31 import android.graphics.RectF;
     32 import android.graphics.Region;
     33 import android.graphics.Shader;
     34 import android.graphics.TemporaryBuffer;
     35 import android.text.GraphicsOperations;
     36 import android.text.SpannableString;
     37 import android.text.SpannedString;
     38 import android.text.TextUtils;
     39 
     40 /**
     41  * An implementation of Canvas on top of OpenGL ES 2.0.
     42  */
     43 class GLES20Canvas extends HardwareCanvas {
     44     private final boolean mOpaque;
     45     protected long mRenderer;
     46 
     47     // The native renderer will be destroyed when this object dies.
     48     // DO NOT overwrite this reference once it is set.
     49     @SuppressWarnings({"unused", "FieldCanBeLocal"})
     50     private CanvasFinalizer mFinalizer;
     51 
     52     private int mWidth;
     53     private int mHeight;
     54 
     55     private float[] mPoint;
     56     private float[] mLine;
     57 
     58     private Rect mClipBounds;
     59     private RectF mPathBounds;
     60 
     61     private DrawFilter mFilter;
     62 
     63     ///////////////////////////////////////////////////////////////////////////
     64     // JNI
     65     ///////////////////////////////////////////////////////////////////////////
     66 
     67     private static native boolean nIsAvailable();
     68     private static boolean sIsAvailable = nIsAvailable();
     69 
     70     static boolean isAvailable() {
     71         return sIsAvailable;
     72     }
     73 
     74     ///////////////////////////////////////////////////////////////////////////
     75     // Constructors
     76     ///////////////////////////////////////////////////////////////////////////
     77 
     78     // TODO: Merge with GLES20RecordingCanvas
     79     protected GLES20Canvas() {
     80         mOpaque = false;
     81         mRenderer = nCreateDisplayListRenderer();
     82         setupFinalizer();
     83     }
     84 
     85     private void setupFinalizer() {
     86         if (mRenderer == 0) {
     87             throw new IllegalStateException("Could not create GLES20Canvas renderer");
     88         } else {
     89             mFinalizer = new CanvasFinalizer(mRenderer);
     90         }
     91     }
     92 
     93     private static native long nCreateDisplayListRenderer();
     94     private static native void nResetDisplayListRenderer(long renderer);
     95     private static native void nDestroyRenderer(long renderer);
     96 
     97     private static final class CanvasFinalizer {
     98         private final long mRenderer;
     99 
    100         public CanvasFinalizer(long renderer) {
    101             mRenderer = renderer;
    102         }
    103 
    104         @Override
    105         protected void finalize() throws Throwable {
    106             try {
    107                 nDestroyRenderer(mRenderer);
    108             } finally {
    109                 super.finalize();
    110             }
    111         }
    112     }
    113 
    114     public static void setProperty(String name, String value) {
    115         nSetProperty(name, value);
    116     }
    117 
    118     private static native void nSetProperty(String name, String value);
    119 
    120     ///////////////////////////////////////////////////////////////////////////
    121     // Canvas management
    122     ///////////////////////////////////////////////////////////////////////////
    123 
    124     @Override
    125     public boolean isOpaque() {
    126         return mOpaque;
    127     }
    128 
    129     @Override
    130     public int getWidth() {
    131         return mWidth;
    132     }
    133 
    134     @Override
    135     public int getHeight() {
    136         return mHeight;
    137     }
    138 
    139     @Override
    140     public int getMaximumBitmapWidth() {
    141         return nGetMaximumTextureWidth();
    142     }
    143 
    144     @Override
    145     public int getMaximumBitmapHeight() {
    146         return nGetMaximumTextureHeight();
    147     }
    148 
    149     private static native int nGetMaximumTextureWidth();
    150     private static native int nGetMaximumTextureHeight();
    151 
    152     /**
    153      * Returns the native OpenGLRenderer object.
    154      */
    155     long getRenderer() {
    156         return mRenderer;
    157     }
    158 
    159     ///////////////////////////////////////////////////////////////////////////
    160     // Setup
    161     ///////////////////////////////////////////////////////////////////////////
    162 
    163     @Override
    164     public void setViewport(int width, int height) {
    165         mWidth = width;
    166         mHeight = height;
    167 
    168         nSetViewport(mRenderer, width, height);
    169     }
    170 
    171     private static native void nSetViewport(long renderer,
    172             int width, int height);
    173 
    174     @Override
    175     public void setHighContrastText(boolean highContrastText) {
    176         nSetHighContrastText(mRenderer, highContrastText);
    177     }
    178 
    179     private static native void nSetHighContrastText(long renderer, boolean highContrastText);
    180 
    181     @Override
    182     public void insertReorderBarrier() {
    183         nInsertReorderBarrier(mRenderer, true);
    184     }
    185 
    186     @Override
    187     public void insertInorderBarrier() {
    188         nInsertReorderBarrier(mRenderer, false);
    189     }
    190 
    191     private static native void nInsertReorderBarrier(long renderer, boolean enableReorder);
    192 
    193     @Override
    194     public int onPreDraw(Rect dirty) {
    195         if (dirty != null) {
    196             return nPrepareDirty(mRenderer, dirty.left, dirty.top, dirty.right, dirty.bottom,
    197                     mOpaque);
    198         } else {
    199             return nPrepare(mRenderer, mOpaque);
    200         }
    201     }
    202 
    203     private static native int nPrepare(long renderer, boolean opaque);
    204     private static native int nPrepareDirty(long renderer, int left, int top, int right, int bottom,
    205             boolean opaque);
    206 
    207     @Override
    208     public void onPostDraw() {
    209         nFinish(mRenderer);
    210     }
    211 
    212     private static native void nFinish(long renderer);
    213 
    214     ///////////////////////////////////////////////////////////////////////////
    215     // Functor
    216     ///////////////////////////////////////////////////////////////////////////
    217 
    218     @Override
    219     public int callDrawGLFunction(long drawGLFunction) {
    220         return nCallDrawGLFunction(mRenderer, drawGLFunction);
    221     }
    222 
    223     private static native int nCallDrawGLFunction(long renderer, long drawGLFunction);
    224 
    225     ///////////////////////////////////////////////////////////////////////////
    226     // Display list
    227     ///////////////////////////////////////////////////////////////////////////
    228 
    229     protected static native long nFinishRecording(long renderer);
    230 
    231     @Override
    232     public int drawRenderNode(RenderNode renderNode, Rect dirty, int flags) {
    233         return nDrawRenderNode(mRenderer, renderNode.getNativeDisplayList(), dirty, flags);
    234     }
    235 
    236     private static native int nDrawRenderNode(long renderer, long renderNode,
    237             Rect dirty, int flags);
    238 
    239     ///////////////////////////////////////////////////////////////////////////
    240     // Hardware layer
    241     ///////////////////////////////////////////////////////////////////////////
    242 
    243     void drawHardwareLayer(HardwareLayer layer, float x, float y, Paint paint) {
    244         layer.setLayerPaint(paint);
    245         nDrawLayer(mRenderer, layer.getLayer(), x, y);
    246     }
    247 
    248     private static native void nDrawLayer(long renderer, long layer, float x, float y);
    249 
    250     ///////////////////////////////////////////////////////////////////////////
    251     // Support
    252     ///////////////////////////////////////////////////////////////////////////
    253 
    254     private Rect getInternalClipBounds() {
    255         if (mClipBounds == null) mClipBounds = new Rect();
    256         return mClipBounds;
    257     }
    258 
    259 
    260     private RectF getPathBounds() {
    261         if (mPathBounds == null) mPathBounds = new RectF();
    262         return mPathBounds;
    263     }
    264 
    265     private float[] getPointStorage() {
    266         if (mPoint == null) mPoint = new float[2];
    267         return mPoint;
    268     }
    269 
    270     private float[] getLineStorage() {
    271         if (mLine == null) mLine = new float[4];
    272         return mLine;
    273     }
    274 
    275     ///////////////////////////////////////////////////////////////////////////
    276     // Clipping
    277     ///////////////////////////////////////////////////////////////////////////
    278 
    279     @Override
    280     public boolean clipPath(Path path) {
    281         return nClipPath(mRenderer, path.mNativePath, Region.Op.INTERSECT.nativeInt);
    282     }
    283 
    284     @Override
    285     public boolean clipPath(Path path, Region.Op op) {
    286         return nClipPath(mRenderer, path.mNativePath, op.nativeInt);
    287     }
    288 
    289     private static native boolean nClipPath(long renderer, long path, int op);
    290 
    291     @Override
    292     public boolean clipRect(float left, float top, float right, float bottom) {
    293         return nClipRect(mRenderer, left, top, right, bottom, Region.Op.INTERSECT.nativeInt);
    294     }
    295 
    296     private static native boolean nClipRect(long renderer, float left, float top,
    297             float right, float bottom, int op);
    298 
    299     @Override
    300     public boolean clipRect(float left, float top, float right, float bottom, Region.Op op) {
    301         return nClipRect(mRenderer, left, top, right, bottom, op.nativeInt);
    302     }
    303 
    304     @Override
    305     public boolean clipRect(int left, int top, int right, int bottom) {
    306         return nClipRect(mRenderer, left, top, right, bottom, Region.Op.INTERSECT.nativeInt);
    307     }
    308 
    309     private static native boolean nClipRect(long renderer, int left, int top,
    310             int right, int bottom, int op);
    311 
    312     @Override
    313     public boolean clipRect(Rect rect) {
    314         return nClipRect(mRenderer, rect.left, rect.top, rect.right, rect.bottom,
    315                 Region.Op.INTERSECT.nativeInt);
    316     }
    317 
    318     @Override
    319     public boolean clipRect(Rect rect, Region.Op op) {
    320         return nClipRect(mRenderer, rect.left, rect.top, rect.right, rect.bottom, op.nativeInt);
    321     }
    322 
    323     @Override
    324     public boolean clipRect(RectF rect) {
    325         return nClipRect(mRenderer, rect.left, rect.top, rect.right, rect.bottom,
    326                 Region.Op.INTERSECT.nativeInt);
    327     }
    328 
    329     @Override
    330     public boolean clipRect(RectF rect, Region.Op op) {
    331         return nClipRect(mRenderer, rect.left, rect.top, rect.right, rect.bottom, op.nativeInt);
    332     }
    333 
    334     @Override
    335     public boolean clipRegion(Region region) {
    336         return nClipRegion(mRenderer, region.mNativeRegion, Region.Op.INTERSECT.nativeInt);
    337     }
    338 
    339     @Override
    340     public boolean clipRegion(Region region, Region.Op op) {
    341         return nClipRegion(mRenderer, region.mNativeRegion, op.nativeInt);
    342     }
    343 
    344     private static native boolean nClipRegion(long renderer, long region, int op);
    345 
    346     @Override
    347     public boolean getClipBounds(Rect bounds) {
    348         return nGetClipBounds(mRenderer, bounds);
    349     }
    350 
    351     private static native boolean nGetClipBounds(long renderer, Rect bounds);
    352 
    353     @Override
    354     public boolean quickReject(float left, float top, float right, float bottom, EdgeType type) {
    355         return nQuickReject(mRenderer, left, top, right, bottom);
    356     }
    357 
    358     private static native boolean nQuickReject(long renderer, float left, float top,
    359             float right, float bottom);
    360 
    361     @Override
    362     public boolean quickReject(Path path, EdgeType type) {
    363         RectF pathBounds = getPathBounds();
    364         path.computeBounds(pathBounds, true);
    365         return nQuickReject(mRenderer, pathBounds.left, pathBounds.top,
    366                 pathBounds.right, pathBounds.bottom);
    367     }
    368 
    369     @Override
    370     public boolean quickReject(RectF rect, EdgeType type) {
    371         return nQuickReject(mRenderer, rect.left, rect.top, rect.right, rect.bottom);
    372     }
    373 
    374     ///////////////////////////////////////////////////////////////////////////
    375     // Transformations
    376     ///////////////////////////////////////////////////////////////////////////
    377 
    378     @Override
    379     public void translate(float dx, float dy) {
    380         if (dx != 0.0f || dy != 0.0f) nTranslate(mRenderer, dx, dy);
    381     }
    382 
    383     private static native void nTranslate(long renderer, float dx, float dy);
    384 
    385     @Override
    386     public void skew(float sx, float sy) {
    387         nSkew(mRenderer, sx, sy);
    388     }
    389 
    390     private static native void nSkew(long renderer, float sx, float sy);
    391 
    392     @Override
    393     public void rotate(float degrees) {
    394         nRotate(mRenderer, degrees);
    395     }
    396 
    397     private static native void nRotate(long renderer, float degrees);
    398 
    399     @Override
    400     public void scale(float sx, float sy) {
    401         nScale(mRenderer, sx, sy);
    402     }
    403 
    404     private static native void nScale(long renderer, float sx, float sy);
    405 
    406     @Override
    407     public void setMatrix(Matrix matrix) {
    408         nSetMatrix(mRenderer, matrix == null ? 0 : matrix.native_instance);
    409     }
    410 
    411     private static native void nSetMatrix(long renderer, long matrix);
    412 
    413     @SuppressWarnings("deprecation")
    414     @Override
    415     public void getMatrix(Matrix matrix) {
    416         nGetMatrix(mRenderer, matrix.native_instance);
    417     }
    418 
    419     private static native void nGetMatrix(long renderer, long matrix);
    420 
    421     @Override
    422     public void concat(Matrix matrix) {
    423         if (matrix != null) nConcatMatrix(mRenderer, matrix.native_instance);
    424     }
    425 
    426     private static native void nConcatMatrix(long renderer, long matrix);
    427 
    428     ///////////////////////////////////////////////////////////////////////////
    429     // State management
    430     ///////////////////////////////////////////////////////////////////////////
    431 
    432     @Override
    433     public int save() {
    434         return nSave(mRenderer, Canvas.CLIP_SAVE_FLAG | Canvas.MATRIX_SAVE_FLAG);
    435     }
    436 
    437     @Override
    438     public int save(int saveFlags) {
    439         return nSave(mRenderer, saveFlags);
    440     }
    441 
    442     private static native int nSave(long renderer, int flags);
    443 
    444     @Override
    445     public int saveLayer(RectF bounds, Paint paint, int saveFlags) {
    446         if (bounds != null) {
    447             return saveLayer(bounds.left, bounds.top, bounds.right, bounds.bottom, paint, saveFlags);
    448         }
    449 
    450         final long nativePaint = paint == null ? 0 : paint.mNativePaint;
    451         return nSaveLayer(mRenderer, nativePaint, saveFlags);
    452     }
    453 
    454     private static native int nSaveLayer(long renderer, long paint, int saveFlags);
    455 
    456     @Override
    457     public int saveLayer(float left, float top, float right, float bottom, Paint paint,
    458             int saveFlags) {
    459         if (left < right && top < bottom) {
    460             final long nativePaint = paint == null ? 0 : paint.mNativePaint;
    461             return nSaveLayer(mRenderer, left, top, right, bottom, nativePaint, saveFlags);
    462         }
    463         return save(saveFlags);
    464     }
    465 
    466     private static native int nSaveLayer(long renderer, float left, float top,
    467             float right, float bottom, long paint, int saveFlags);
    468 
    469     @Override
    470     public int saveLayerAlpha(RectF bounds, int alpha, int saveFlags) {
    471         if (bounds != null) {
    472             return saveLayerAlpha(bounds.left, bounds.top, bounds.right, bounds.bottom,
    473                     alpha, saveFlags);
    474         }
    475         return nSaveLayerAlpha(mRenderer, alpha, saveFlags);
    476     }
    477 
    478     private static native int nSaveLayerAlpha(long renderer, int alpha, int saveFlags);
    479 
    480     @Override
    481     public int saveLayerAlpha(float left, float top, float right, float bottom, int alpha,
    482             int saveFlags) {
    483         if (left < right && top < bottom) {
    484             return nSaveLayerAlpha(mRenderer, left, top, right, bottom, alpha, saveFlags);
    485         }
    486         return save(saveFlags);
    487     }
    488 
    489     private static native int nSaveLayerAlpha(long renderer, float left, float top, float right,
    490             float bottom, int alpha, int saveFlags);
    491 
    492     @Override
    493     public void restore() {
    494         nRestore(mRenderer);
    495     }
    496 
    497     private static native void nRestore(long renderer);
    498 
    499     @Override
    500     public void restoreToCount(int saveCount) {
    501         nRestoreToCount(mRenderer, saveCount);
    502     }
    503 
    504     private static native void nRestoreToCount(long renderer, int saveCount);
    505 
    506     @Override
    507     public int getSaveCount() {
    508         return nGetSaveCount(mRenderer);
    509     }
    510 
    511     private static native int nGetSaveCount(long renderer);
    512 
    513     ///////////////////////////////////////////////////////////////////////////
    514     // Filtering
    515     ///////////////////////////////////////////////////////////////////////////
    516 
    517     @Override
    518     public void setDrawFilter(DrawFilter filter) {
    519         mFilter = filter;
    520         if (filter == null) {
    521             nResetPaintFilter(mRenderer);
    522         } else if (filter instanceof PaintFlagsDrawFilter) {
    523             PaintFlagsDrawFilter flagsFilter = (PaintFlagsDrawFilter) filter;
    524             nSetupPaintFilter(mRenderer, flagsFilter.clearBits, flagsFilter.setBits);
    525         }
    526     }
    527 
    528     private static native void nResetPaintFilter(long renderer);
    529     private static native void nSetupPaintFilter(long renderer, int clearBits, int setBits);
    530 
    531     @Override
    532     public DrawFilter getDrawFilter() {
    533         return mFilter;
    534     }
    535 
    536     ///////////////////////////////////////////////////////////////////////////
    537     // Drawing
    538     ///////////////////////////////////////////////////////////////////////////
    539 
    540     @Override
    541     public void drawArc(float left, float top, float right, float bottom,
    542             float startAngle, float sweepAngle, boolean useCenter, Paint paint) {
    543         nDrawArc(mRenderer, left, top, right, bottom,
    544                 startAngle, sweepAngle, useCenter, paint.mNativePaint);
    545     }
    546 
    547     private static native void nDrawArc(long renderer, float left, float top,
    548             float right, float bottom, float startAngle, float sweepAngle,
    549             boolean useCenter, long paint);
    550 
    551     @Override
    552     public void drawARGB(int a, int r, int g, int b) {
    553         drawColor((a & 0xFF) << 24 | (r & 0xFF) << 16 | (g & 0xFF) << 8 | (b & 0xFF));
    554     }
    555 
    556     @Override
    557     public void drawPatch(NinePatch patch, Rect dst, Paint paint) {
    558         Bitmap bitmap = patch.getBitmap();
    559         throwIfCannotDraw(bitmap);
    560         final long nativePaint = paint == null ? 0 : paint.mNativePaint;
    561         nDrawPatch(mRenderer, bitmap.mNativeBitmap, bitmap.mBuffer, patch.mNativeChunk,
    562                 dst.left, dst.top, dst.right, dst.bottom, nativePaint);
    563     }
    564 
    565     @Override
    566     public void drawPatch(NinePatch patch, RectF dst, Paint paint) {
    567         Bitmap bitmap = patch.getBitmap();
    568         throwIfCannotDraw(bitmap);
    569         final long nativePaint = paint == null ? 0 : paint.mNativePaint;
    570         nDrawPatch(mRenderer, bitmap.mNativeBitmap, bitmap.mBuffer, patch.mNativeChunk,
    571                 dst.left, dst.top, dst.right, dst.bottom, nativePaint);
    572     }
    573 
    574     private static native void nDrawPatch(long renderer, long bitmap, byte[] buffer, long chunk,
    575             float left, float top, float right, float bottom, long paint);
    576 
    577     @Override
    578     public void drawBitmap(Bitmap bitmap, float left, float top, Paint paint) {
    579         throwIfCannotDraw(bitmap);
    580         final long nativePaint = paint == null ? 0 : paint.mNativePaint;
    581         nDrawBitmap(mRenderer, bitmap.mNativeBitmap, bitmap.mBuffer, left, top, nativePaint);
    582     }
    583 
    584     private static native void nDrawBitmap(long renderer, long bitmap, byte[] buffer,
    585             float left, float top, long paint);
    586 
    587     @Override
    588     public void drawBitmap(Bitmap bitmap, Matrix matrix, Paint paint) {
    589         throwIfCannotDraw(bitmap);
    590         final long nativePaint = paint == null ? 0 : paint.mNativePaint;
    591         nDrawBitmap(mRenderer, bitmap.mNativeBitmap, bitmap.mBuffer,
    592                 matrix.native_instance, nativePaint);
    593     }
    594 
    595     private static native void nDrawBitmap(long renderer, long bitmap, byte[] buffer,
    596             long matrix, long paint);
    597 
    598     @Override
    599     public void drawBitmap(Bitmap bitmap, Rect src, Rect dst, Paint paint) {
    600         throwIfCannotDraw(bitmap);
    601         final long nativePaint = paint == null ? 0 : paint.mNativePaint;
    602 
    603         int left, top, right, bottom;
    604         if (src == null) {
    605             left = top = 0;
    606             right = bitmap.getWidth();
    607             bottom = bitmap.getHeight();
    608         } else {
    609             left = src.left;
    610             right = src.right;
    611             top = src.top;
    612             bottom = src.bottom;
    613         }
    614 
    615         nDrawBitmap(mRenderer, bitmap.mNativeBitmap, bitmap.mBuffer, left, top, right, bottom,
    616                 dst.left, dst.top, dst.right, dst.bottom, nativePaint);
    617     }
    618 
    619     @Override
    620     public void drawBitmap(Bitmap bitmap, Rect src, RectF dst, Paint paint) {
    621         throwIfCannotDraw(bitmap);
    622         final long nativePaint = paint == null ? 0 : paint.mNativePaint;
    623 
    624         float left, top, right, bottom;
    625         if (src == null) {
    626             left = top = 0;
    627             right = bitmap.getWidth();
    628             bottom = bitmap.getHeight();
    629         } else {
    630             left = src.left;
    631             right = src.right;
    632             top = src.top;
    633             bottom = src.bottom;
    634         }
    635 
    636         nDrawBitmap(mRenderer, bitmap.mNativeBitmap, bitmap.mBuffer, left, top, right, bottom,
    637                 dst.left, dst.top, dst.right, dst.bottom, nativePaint);
    638     }
    639 
    640     private static native void nDrawBitmap(long renderer, long bitmap, byte[] buffer,
    641             float srcLeft, float srcTop, float srcRight, float srcBottom,
    642             float left, float top, float right, float bottom, long paint);
    643 
    644     @Override
    645     public void drawBitmap(int[] colors, int offset, int stride, float x, float y,
    646             int width, int height, boolean hasAlpha, Paint paint) {
    647         if (width < 0) {
    648             throw new IllegalArgumentException("width must be >= 0");
    649         }
    650 
    651         if (height < 0) {
    652             throw new IllegalArgumentException("height must be >= 0");
    653         }
    654 
    655         if (Math.abs(stride) < width) {
    656             throw new IllegalArgumentException("abs(stride) must be >= width");
    657         }
    658 
    659         int lastScanline = offset + (height - 1) * stride;
    660         int length = colors.length;
    661 
    662         if (offset < 0 || (offset + width > length) || lastScanline < 0 ||
    663                 (lastScanline + width > length)) {
    664             throw new ArrayIndexOutOfBoundsException();
    665         }
    666 
    667         final long nativePaint = paint == null ? 0 : paint.mNativePaint;
    668         nDrawBitmap(mRenderer, colors, offset, stride, x, y,
    669                 width, height, hasAlpha, nativePaint);
    670     }
    671 
    672     private static native void nDrawBitmap(long renderer, int[] colors, int offset, int stride,
    673             float x, float y, int width, int height, boolean hasAlpha, long nativePaint);
    674 
    675     @Override
    676     public void drawBitmap(int[] colors, int offset, int stride, int x, int y,
    677             int width, int height, boolean hasAlpha, Paint paint) {
    678         drawBitmap(colors, offset, stride, (float) x, (float) y, width, height, hasAlpha, paint);
    679     }
    680 
    681     @Override
    682     public void drawBitmapMesh(Bitmap bitmap, int meshWidth, int meshHeight, float[] verts,
    683             int vertOffset, int[] colors, int colorOffset, Paint paint) {
    684         throwIfCannotDraw(bitmap);
    685         if (meshWidth < 0 || meshHeight < 0 || vertOffset < 0 || colorOffset < 0) {
    686             throw new ArrayIndexOutOfBoundsException();
    687         }
    688 
    689         if (meshWidth == 0 || meshHeight == 0) {
    690             return;
    691         }
    692 
    693         final int count = (meshWidth + 1) * (meshHeight + 1);
    694         checkRange(verts.length, vertOffset, count * 2);
    695 
    696         if (colors != null) {
    697             checkRange(colors.length, colorOffset, count);
    698         }
    699 
    700         final long nativePaint = paint == null ? 0 : paint.mNativePaint;
    701         nDrawBitmapMesh(mRenderer, bitmap.mNativeBitmap, bitmap.mBuffer, meshWidth, meshHeight,
    702                 verts, vertOffset, colors, colorOffset, nativePaint);
    703     }
    704 
    705     private static native void nDrawBitmapMesh(long renderer, long bitmap, byte[] buffer,
    706             int meshWidth, int meshHeight, float[] verts, int vertOffset,
    707             int[] colors, int colorOffset, long paint);
    708 
    709     @Override
    710     public void drawCircle(float cx, float cy, float radius, Paint paint) {
    711         nDrawCircle(mRenderer, cx, cy, radius, paint.mNativePaint);
    712     }
    713 
    714     private static native void nDrawCircle(long renderer, float cx, float cy,
    715             float radius, long paint);
    716 
    717     @Override
    718     public void drawCircle(CanvasProperty<Float> cx, CanvasProperty<Float> cy,
    719             CanvasProperty<Float> radius, CanvasProperty<Paint> paint) {
    720         nDrawCircle(mRenderer, cx.getNativeContainer(), cy.getNativeContainer(),
    721                 radius.getNativeContainer(), paint.getNativeContainer());
    722     }
    723 
    724     private static native void nDrawCircle(long renderer, long propCx,
    725             long propCy, long propRadius, long propPaint);
    726 
    727     @Override
    728     public void drawRoundRect(CanvasProperty<Float> left, CanvasProperty<Float> top,
    729             CanvasProperty<Float> right, CanvasProperty<Float> bottom, CanvasProperty<Float> rx,
    730             CanvasProperty<Float> ry, CanvasProperty<Paint> paint) {
    731         nDrawRoundRect(mRenderer, left.getNativeContainer(), top.getNativeContainer(),
    732                 right.getNativeContainer(), bottom.getNativeContainer(),
    733                 rx.getNativeContainer(), ry.getNativeContainer(),
    734                 paint.getNativeContainer());
    735     }
    736 
    737     private static native void nDrawRoundRect(long renderer, long propLeft, long propTop,
    738             long propRight, long propBottom, long propRx, long propRy, long propPaint);
    739 
    740     @Override
    741     public void drawColor(int color) {
    742         drawColor(color, PorterDuff.Mode.SRC_OVER);
    743     }
    744 
    745     @Override
    746     public void drawColor(int color, PorterDuff.Mode mode) {
    747         nDrawColor(mRenderer, color, mode.nativeInt);
    748     }
    749 
    750     private static native void nDrawColor(long renderer, int color, int mode);
    751 
    752     @Override
    753     public void drawLine(float startX, float startY, float stopX, float stopY, Paint paint) {
    754         float[] line = getLineStorage();
    755         line[0] = startX;
    756         line[1] = startY;
    757         line[2] = stopX;
    758         line[3] = stopY;
    759         drawLines(line, 0, 4, paint);
    760     }
    761 
    762     @Override
    763     public void drawLines(float[] pts, int offset, int count, Paint paint) {
    764         if (count < 4) return;
    765 
    766         if ((offset | count) < 0 || offset + count > pts.length) {
    767             throw new IllegalArgumentException("The lines array must contain 4 elements per line.");
    768         }
    769         nDrawLines(mRenderer, pts, offset, count, paint.mNativePaint);
    770     }
    771 
    772     private static native void nDrawLines(long renderer, float[] points,
    773             int offset, int count, long paint);
    774 
    775     @Override
    776     public void drawLines(float[] pts, Paint paint) {
    777         drawLines(pts, 0, pts.length, paint);
    778     }
    779 
    780     @Override
    781     public void drawOval(float left, float top, float right, float bottom, Paint paint) {
    782         nDrawOval(mRenderer, left, top, right, bottom, paint.mNativePaint);
    783     }
    784 
    785     private static native void nDrawOval(long renderer, float left, float top,
    786             float right, float bottom, long paint);
    787 
    788     @Override
    789     public void drawPaint(Paint paint) {
    790         final Rect r = getInternalClipBounds();
    791         nGetClipBounds(mRenderer, r);
    792         drawRect(r.left, r.top, r.right, r.bottom, paint);
    793     }
    794 
    795     @Override
    796     public void drawPath(Path path, Paint paint) {
    797         if (path.isSimplePath) {
    798             if (path.rects != null) {
    799                 nDrawRects(mRenderer, path.rects.mNativeRegion, paint.mNativePaint);
    800             }
    801         } else {
    802             nDrawPath(mRenderer, path.mNativePath, paint.mNativePaint);
    803         }
    804     }
    805 
    806     private static native void nDrawPath(long renderer, long path, long paint);
    807     private static native void nDrawRects(long renderer, long region, long paint);
    808 
    809     @Override
    810     public void drawPicture(Picture picture) {
    811         picture.endRecording();
    812         // TODO: Implement rendering
    813     }
    814 
    815     @Override
    816     public void drawPoint(float x, float y, Paint paint) {
    817         float[] point = getPointStorage();
    818         point[0] = x;
    819         point[1] = y;
    820         drawPoints(point, 0, 2, paint);
    821     }
    822 
    823     @Override
    824     public void drawPoints(float[] pts, Paint paint) {
    825         drawPoints(pts, 0, pts.length, paint);
    826     }
    827 
    828     @Override
    829     public void drawPoints(float[] pts, int offset, int count, Paint paint) {
    830         if (count < 2) return;
    831 
    832         nDrawPoints(mRenderer, pts, offset, count, paint.mNativePaint);
    833     }
    834 
    835     private static native void nDrawPoints(long renderer, float[] points,
    836             int offset, int count, long paint);
    837 
    838     // Note: drawPosText just uses implementation in Canvas
    839 
    840     @Override
    841     public void drawRect(float left, float top, float right, float bottom, Paint paint) {
    842         if (left == right || top == bottom) return;
    843         nDrawRect(mRenderer, left, top, right, bottom, paint.mNativePaint);
    844     }
    845 
    846     private static native void nDrawRect(long renderer, float left, float top,
    847             float right, float bottom, long paint);
    848 
    849     @Override
    850     public void drawRect(Rect r, Paint paint) {
    851         drawRect(r.left, r.top, r.right, r.bottom, paint);
    852     }
    853 
    854     @Override
    855     public void drawRect(RectF r, Paint paint) {
    856         drawRect(r.left, r.top, r.right, r.bottom, paint);
    857     }
    858 
    859     @Override
    860     public void drawRGB(int r, int g, int b) {
    861         drawColor(0xFF000000 | (r & 0xFF) << 16 | (g & 0xFF) << 8 | (b & 0xFF));
    862     }
    863 
    864     @Override
    865     public void drawRoundRect(float left, float top, float right, float bottom, float rx, float ry,
    866             Paint paint) {
    867         nDrawRoundRect(mRenderer, left, top, right, bottom, rx, ry, paint.mNativePaint);
    868     }
    869 
    870     private static native void nDrawRoundRect(long renderer, float left, float top,
    871             float right, float bottom, float rx, float y, long paint);
    872 
    873     @Override
    874     public void drawText(char[] text, int index, int count, float x, float y, Paint paint) {
    875         if ((index | count | (index + count) | (text.length - index - count)) < 0) {
    876             throw new IndexOutOfBoundsException();
    877         }
    878 
    879         nDrawText(mRenderer, text, index, count, x, y,
    880                 paint.mBidiFlags, paint.mNativePaint, paint.mNativeTypeface);
    881     }
    882 
    883     private static native void nDrawText(long renderer, char[] text, int index, int count,
    884             float x, float y, int bidiFlags, long paint, long typeface);
    885 
    886     @Override
    887     public void drawText(CharSequence text, int start, int end, float x, float y, Paint paint) {
    888         if (text instanceof String || text instanceof SpannedString ||
    889                 text instanceof SpannableString) {
    890             nDrawText(mRenderer, text.toString(), start, end, x, y, paint.mBidiFlags,
    891                     paint.mNativePaint, paint.mNativeTypeface);
    892         } else if (text instanceof GraphicsOperations) {
    893             ((GraphicsOperations) text).drawText(this, start, end, x, y, paint);
    894         } else {
    895             char[] buf = TemporaryBuffer.obtain(end - start);
    896             TextUtils.getChars(text, start, end, buf, 0);
    897             nDrawText(mRenderer, buf, 0, end - start, x, y,
    898                     paint.mBidiFlags, paint.mNativePaint, paint.mNativeTypeface);
    899             TemporaryBuffer.recycle(buf);
    900         }
    901     }
    902 
    903     @Override
    904     public void drawText(String text, int start, int end, float x, float y, Paint paint) {
    905         if ((start | end | (end - start) | (text.length() - end)) < 0) {
    906             throw new IndexOutOfBoundsException();
    907         }
    908 
    909         nDrawText(mRenderer, text, start, end, x, y,
    910                 paint.mBidiFlags, paint.mNativePaint, paint.mNativeTypeface);
    911     }
    912 
    913     private static native void nDrawText(long renderer, String text, int start, int end,
    914             float x, float y, int bidiFlags, long paint, long typeface);
    915 
    916     @Override
    917     public void drawText(String text, float x, float y, Paint paint) {
    918         nDrawText(mRenderer, text, 0, text.length(), x, y,
    919                 paint.mBidiFlags, paint.mNativePaint, paint.mNativeTypeface);
    920     }
    921 
    922     @Override
    923     public void drawTextOnPath(char[] text, int index, int count, Path path, float hOffset,
    924             float vOffset, Paint paint) {
    925         if (index < 0 || index + count > text.length) {
    926             throw new ArrayIndexOutOfBoundsException();
    927         }
    928 
    929         nDrawTextOnPath(mRenderer, text, index, count, path.mNativePath, hOffset, vOffset,
    930                 paint.mBidiFlags, paint.mNativePaint, paint.mNativeTypeface);
    931     }
    932 
    933     private static native void nDrawTextOnPath(long renderer, char[] text, int index, int count,
    934             long path, float hOffset, float vOffset, int bidiFlags, long nativePaint,
    935             long typeface);
    936 
    937     @Override
    938     public void drawTextOnPath(String text, Path path, float hOffset, float vOffset, Paint paint) {
    939         if (text.length() == 0) return;
    940 
    941         nDrawTextOnPath(mRenderer, text, 0, text.length(), path.mNativePath, hOffset, vOffset,
    942                 paint.mBidiFlags, paint.mNativePaint, paint.mNativeTypeface);
    943     }
    944 
    945     private static native void nDrawTextOnPath(long renderer, String text, int start, int end,
    946             long path, float hOffset, float vOffset, int bidiFlags, long nativePaint,
    947             long typeface);
    948 
    949     @Override
    950     public void drawTextRun(char[] text, int index, int count, int contextIndex, int contextCount,
    951             float x, float y, boolean isRtl, Paint paint) {
    952         if ((index | count | text.length - index - count) < 0) {
    953             throw new IndexOutOfBoundsException();
    954         }
    955 
    956         nDrawTextRun(mRenderer, text, index, count, contextIndex, contextCount, x, y, isRtl,
    957                 paint.mNativePaint, paint.mNativeTypeface);
    958     }
    959 
    960     private static native void nDrawTextRun(long renderer, char[] text, int index, int count,
    961             int contextIndex, int contextCount, float x, float y, boolean isRtl, long nativePaint, long nativeTypeface);
    962 
    963     @Override
    964     public void drawTextRun(CharSequence text, int start, int end, int contextStart, int contextEnd,
    965             float x, float y, boolean isRtl, Paint paint) {
    966         if ((start | end | end - start | text.length() - end) < 0) {
    967             throw new IndexOutOfBoundsException();
    968         }
    969 
    970         if (text instanceof String || text instanceof SpannedString ||
    971                 text instanceof SpannableString) {
    972             nDrawTextRun(mRenderer, text.toString(), start, end, contextStart,
    973                     contextEnd, x, y, isRtl, paint.mNativePaint, paint.mNativeTypeface);
    974         } else if (text instanceof GraphicsOperations) {
    975             ((GraphicsOperations) text).drawTextRun(this, start, end,
    976                     contextStart, contextEnd, x, y, isRtl, paint);
    977         } else {
    978             int contextLen = contextEnd - contextStart;
    979             int len = end - start;
    980             char[] buf = TemporaryBuffer.obtain(contextLen);
    981             TextUtils.getChars(text, contextStart, contextEnd, buf, 0);
    982             nDrawTextRun(mRenderer, buf, start - contextStart, len, 0, contextLen,
    983                     x, y, isRtl, paint.mNativePaint, paint.mNativeTypeface);
    984             TemporaryBuffer.recycle(buf);
    985         }
    986     }
    987 
    988     private static native void nDrawTextRun(long renderer, String text, int start, int end,
    989             int contextStart, int contextEnd, float x, float y, boolean isRtl, long nativePaint, long nativeTypeface);
    990 
    991     @Override
    992     public void drawVertices(VertexMode mode, int vertexCount, float[] verts, int vertOffset,
    993             float[] texs, int texOffset, int[] colors, int colorOffset, short[] indices,
    994             int indexOffset, int indexCount, Paint paint) {
    995         // TODO: Implement
    996     }
    997 }
    998