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 callDrawGLFunction2(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.getLayerHandle(), 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, 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, patch.mNativeChunk,
    571                 dst.left, dst.top, dst.right, dst.bottom, nativePaint);
    572     }
    573 
    574     private static native void nDrawPatch(long renderer, long bitmap, 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, left, top, nativePaint);
    582     }
    583 
    584     private static native void nDrawBitmap(long renderer, long bitmap, float left,
    585             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, matrix.native_instance, nativePaint);
    592     }
    593 
    594     private static native void nDrawBitmap(long renderer, long bitmap,
    595             long matrix, long paint);
    596 
    597     @Override
    598     public void drawBitmap(Bitmap bitmap, Rect src, Rect dst, Paint paint) {
    599         throwIfCannotDraw(bitmap);
    600         final long nativePaint = paint == null ? 0 : paint.mNativePaint;
    601 
    602         int left, top, right, bottom;
    603         if (src == null) {
    604             left = top = 0;
    605             right = bitmap.getWidth();
    606             bottom = bitmap.getHeight();
    607         } else {
    608             left = src.left;
    609             right = src.right;
    610             top = src.top;
    611             bottom = src.bottom;
    612         }
    613 
    614         nDrawBitmap(mRenderer, bitmap.mNativeBitmap, left, top, right, bottom,
    615                 dst.left, dst.top, dst.right, dst.bottom, nativePaint);
    616     }
    617 
    618     @Override
    619     public void drawBitmap(Bitmap bitmap, Rect src, RectF dst, Paint paint) {
    620         throwIfCannotDraw(bitmap);
    621         final long nativePaint = paint == null ? 0 : paint.mNativePaint;
    622 
    623         float left, top, right, bottom;
    624         if (src == null) {
    625             left = top = 0;
    626             right = bitmap.getWidth();
    627             bottom = bitmap.getHeight();
    628         } else {
    629             left = src.left;
    630             right = src.right;
    631             top = src.top;
    632             bottom = src.bottom;
    633         }
    634 
    635         nDrawBitmap(mRenderer, bitmap.mNativeBitmap, left, top, right, bottom,
    636                 dst.left, dst.top, dst.right, dst.bottom, nativePaint);
    637     }
    638 
    639     private static native void nDrawBitmap(long renderer, long bitmap,
    640             float srcLeft, float srcTop, float srcRight, float srcBottom,
    641             float left, float top, float right, float bottom, long paint);
    642 
    643     @Override
    644     public void drawBitmap(int[] colors, int offset, int stride, float x, float y,
    645             int width, int height, boolean hasAlpha, Paint paint) {
    646         if (width < 0) {
    647             throw new IllegalArgumentException("width must be >= 0");
    648         }
    649 
    650         if (height < 0) {
    651             throw new IllegalArgumentException("height must be >= 0");
    652         }
    653 
    654         if (Math.abs(stride) < width) {
    655             throw new IllegalArgumentException("abs(stride) must be >= width");
    656         }
    657 
    658         int lastScanline = offset + (height - 1) * stride;
    659         int length = colors.length;
    660 
    661         if (offset < 0 || (offset + width > length) || lastScanline < 0 ||
    662                 (lastScanline + width > length)) {
    663             throw new ArrayIndexOutOfBoundsException();
    664         }
    665 
    666         final long nativePaint = paint == null ? 0 : paint.mNativePaint;
    667         nDrawBitmap(mRenderer, colors, offset, stride, x, y,
    668                 width, height, hasAlpha, nativePaint);
    669     }
    670 
    671     private static native void nDrawBitmap(long renderer, int[] colors, int offset, int stride,
    672             float x, float y, int width, int height, boolean hasAlpha, long nativePaint);
    673 
    674     @Override
    675     public void drawBitmap(int[] colors, int offset, int stride, int x, int y,
    676             int width, int height, boolean hasAlpha, Paint paint) {
    677         drawBitmap(colors, offset, stride, (float) x, (float) y, width, height, hasAlpha, paint);
    678     }
    679 
    680     @Override
    681     public void drawBitmapMesh(Bitmap bitmap, int meshWidth, int meshHeight, float[] verts,
    682             int vertOffset, int[] colors, int colorOffset, Paint paint) {
    683         throwIfCannotDraw(bitmap);
    684         if (meshWidth < 0 || meshHeight < 0 || vertOffset < 0 || colorOffset < 0) {
    685             throw new ArrayIndexOutOfBoundsException();
    686         }
    687 
    688         if (meshWidth == 0 || meshHeight == 0) {
    689             return;
    690         }
    691 
    692         final int count = (meshWidth + 1) * (meshHeight + 1);
    693         checkRange(verts.length, vertOffset, count * 2);
    694 
    695         if (colors != null) {
    696             checkRange(colors.length, colorOffset, count);
    697         }
    698 
    699         final long nativePaint = paint == null ? 0 : paint.mNativePaint;
    700         nDrawBitmapMesh(mRenderer, bitmap.mNativeBitmap, meshWidth, meshHeight,
    701                 verts, vertOffset, colors, colorOffset, nativePaint);
    702     }
    703 
    704     private static native void nDrawBitmapMesh(long renderer, long bitmap,
    705             int meshWidth, int meshHeight, float[] verts, int vertOffset,
    706             int[] colors, int colorOffset, long paint);
    707 
    708     @Override
    709     public void drawCircle(float cx, float cy, float radius, Paint paint) {
    710         nDrawCircle(mRenderer, cx, cy, radius, paint.mNativePaint);
    711     }
    712 
    713     private static native void nDrawCircle(long renderer, float cx, float cy,
    714             float radius, long paint);
    715 
    716     @Override
    717     public void drawCircle(CanvasProperty<Float> cx, CanvasProperty<Float> cy,
    718             CanvasProperty<Float> radius, CanvasProperty<Paint> paint) {
    719         nDrawCircle(mRenderer, cx.getNativeContainer(), cy.getNativeContainer(),
    720                 radius.getNativeContainer(), paint.getNativeContainer());
    721     }
    722 
    723     private static native void nDrawCircle(long renderer, long propCx,
    724             long propCy, long propRadius, long propPaint);
    725 
    726     @Override
    727     public void drawRoundRect(CanvasProperty<Float> left, CanvasProperty<Float> top,
    728             CanvasProperty<Float> right, CanvasProperty<Float> bottom, CanvasProperty<Float> rx,
    729             CanvasProperty<Float> ry, CanvasProperty<Paint> paint) {
    730         nDrawRoundRect(mRenderer, left.getNativeContainer(), top.getNativeContainer(),
    731                 right.getNativeContainer(), bottom.getNativeContainer(),
    732                 rx.getNativeContainer(), ry.getNativeContainer(),
    733                 paint.getNativeContainer());
    734     }
    735 
    736     private static native void nDrawRoundRect(long renderer, long propLeft, long propTop,
    737             long propRight, long propBottom, long propRx, long propRy, long propPaint);
    738 
    739     @Override
    740     public void drawColor(int color) {
    741         drawColor(color, PorterDuff.Mode.SRC_OVER);
    742     }
    743 
    744     @Override
    745     public void drawColor(int color, PorterDuff.Mode mode) {
    746         nDrawColor(mRenderer, color, mode.nativeInt);
    747     }
    748 
    749     private static native void nDrawColor(long renderer, int color, int mode);
    750 
    751     @Override
    752     public void drawLine(float startX, float startY, float stopX, float stopY, Paint paint) {
    753         float[] line = getLineStorage();
    754         line[0] = startX;
    755         line[1] = startY;
    756         line[2] = stopX;
    757         line[3] = stopY;
    758         drawLines(line, 0, 4, paint);
    759     }
    760 
    761     @Override
    762     public void drawLines(float[] pts, int offset, int count, Paint paint) {
    763         if (count < 4) return;
    764 
    765         if ((offset | count) < 0 || offset + count > pts.length) {
    766             throw new IllegalArgumentException("The lines array must contain 4 elements per line.");
    767         }
    768         nDrawLines(mRenderer, pts, offset, count, paint.mNativePaint);
    769     }
    770 
    771     private static native void nDrawLines(long renderer, float[] points,
    772             int offset, int count, long paint);
    773 
    774     @Override
    775     public void drawLines(float[] pts, Paint paint) {
    776         drawLines(pts, 0, pts.length, paint);
    777     }
    778 
    779     @Override
    780     public void drawOval(float left, float top, float right, float bottom, Paint paint) {
    781         nDrawOval(mRenderer, left, top, right, bottom, paint.mNativePaint);
    782     }
    783 
    784     private static native void nDrawOval(long renderer, float left, float top,
    785             float right, float bottom, long paint);
    786 
    787     @Override
    788     public void drawPaint(Paint paint) {
    789         final Rect r = getInternalClipBounds();
    790         nGetClipBounds(mRenderer, r);
    791         drawRect(r.left, r.top, r.right, r.bottom, paint);
    792     }
    793 
    794     @Override
    795     public void drawPath(Path path, Paint paint) {
    796         if (path.isSimplePath) {
    797             if (path.rects != null) {
    798                 nDrawRects(mRenderer, path.rects.mNativeRegion, paint.mNativePaint);
    799             }
    800         } else {
    801             nDrawPath(mRenderer, path.mNativePath, paint.mNativePaint);
    802         }
    803     }
    804 
    805     private static native void nDrawPath(long renderer, long path, long paint);
    806     private static native void nDrawRects(long renderer, long region, long paint);
    807 
    808     @Override
    809     public void drawPicture(Picture picture) {
    810         picture.endRecording();
    811         // TODO: Implement rendering
    812     }
    813 
    814     @Override
    815     public void drawPoint(float x, float y, Paint paint) {
    816         float[] point = getPointStorage();
    817         point[0] = x;
    818         point[1] = y;
    819         drawPoints(point, 0, 2, paint);
    820     }
    821 
    822     @Override
    823     public void drawPoints(float[] pts, Paint paint) {
    824         drawPoints(pts, 0, pts.length, paint);
    825     }
    826 
    827     @Override
    828     public void drawPoints(float[] pts, int offset, int count, Paint paint) {
    829         if (count < 2) return;
    830 
    831         nDrawPoints(mRenderer, pts, offset, count, paint.mNativePaint);
    832     }
    833 
    834     private static native void nDrawPoints(long renderer, float[] points,
    835             int offset, int count, long paint);
    836 
    837     // Note: drawPosText just uses implementation in Canvas
    838 
    839     @Override
    840     public void drawRect(float left, float top, float right, float bottom, Paint paint) {
    841         if (left == right || top == bottom) return;
    842         nDrawRect(mRenderer, left, top, right, bottom, paint.mNativePaint);
    843     }
    844 
    845     private static native void nDrawRect(long renderer, float left, float top,
    846             float right, float bottom, long paint);
    847 
    848     @Override
    849     public void drawRect(Rect r, Paint paint) {
    850         drawRect(r.left, r.top, r.right, r.bottom, paint);
    851     }
    852 
    853     @Override
    854     public void drawRect(RectF r, Paint paint) {
    855         drawRect(r.left, r.top, r.right, r.bottom, paint);
    856     }
    857 
    858     @Override
    859     public void drawRGB(int r, int g, int b) {
    860         drawColor(0xFF000000 | (r & 0xFF) << 16 | (g & 0xFF) << 8 | (b & 0xFF));
    861     }
    862 
    863     @Override
    864     public void drawRoundRect(float left, float top, float right, float bottom, float rx, float ry,
    865             Paint paint) {
    866         nDrawRoundRect(mRenderer, left, top, right, bottom, rx, ry, paint.mNativePaint);
    867     }
    868 
    869     private static native void nDrawRoundRect(long renderer, float left, float top,
    870             float right, float bottom, float rx, float y, long paint);
    871 
    872     @Override
    873     public void drawText(char[] text, int index, int count, float x, float y, Paint paint) {
    874         if ((index | count | (index + count) | (text.length - index - count)) < 0) {
    875             throw new IndexOutOfBoundsException();
    876         }
    877 
    878         nDrawText(mRenderer, text, index, count, x, y,
    879                 paint.mBidiFlags, paint.mNativePaint, paint.mNativeTypeface);
    880     }
    881 
    882     private static native void nDrawText(long renderer, char[] text, int index, int count,
    883             float x, float y, int bidiFlags, long paint, long typeface);
    884 
    885     @Override
    886     public void drawText(CharSequence text, int start, int end, float x, float y, Paint paint) {
    887         if ((start | end | (end - start) | (text.length() - end)) < 0) {
    888             throw new IndexOutOfBoundsException();
    889         }
    890         if (text instanceof String || text instanceof SpannedString ||
    891                 text instanceof SpannableString) {
    892             nDrawText(mRenderer, text.toString(), start, end, x, y, paint.mBidiFlags,
    893                     paint.mNativePaint, paint.mNativeTypeface);
    894         } else if (text instanceof GraphicsOperations) {
    895             ((GraphicsOperations) text).drawText(this, start, end, x, y, paint);
    896         } else {
    897             char[] buf = TemporaryBuffer.obtain(end - start);
    898             TextUtils.getChars(text, start, end, buf, 0);
    899             nDrawText(mRenderer, buf, 0, end - start, x, y,
    900                     paint.mBidiFlags, paint.mNativePaint, paint.mNativeTypeface);
    901             TemporaryBuffer.recycle(buf);
    902         }
    903     }
    904 
    905     @Override
    906     public void drawText(String text, int start, int end, float x, float y, Paint paint) {
    907         if ((start | end | (end - start) | (text.length() - end)) < 0) {
    908             throw new IndexOutOfBoundsException();
    909         }
    910 
    911         nDrawText(mRenderer, text, start, end, x, y,
    912                 paint.mBidiFlags, paint.mNativePaint, paint.mNativeTypeface);
    913     }
    914 
    915     private static native void nDrawText(long renderer, String text, int start, int end,
    916             float x, float y, int bidiFlags, long paint, long typeface);
    917 
    918     @Override
    919     public void drawText(String text, float x, float y, Paint paint) {
    920         nDrawText(mRenderer, text, 0, text.length(), x, y,
    921                 paint.mBidiFlags, paint.mNativePaint, paint.mNativeTypeface);
    922     }
    923 
    924     @Override
    925     public void drawTextOnPath(char[] text, int index, int count, Path path, float hOffset,
    926             float vOffset, Paint paint) {
    927         if (index < 0 || index + count > text.length) {
    928             throw new ArrayIndexOutOfBoundsException();
    929         }
    930 
    931         nDrawTextOnPath(mRenderer, text, index, count, path.mNativePath, hOffset, vOffset,
    932                 paint.mBidiFlags, paint.mNativePaint, paint.mNativeTypeface);
    933     }
    934 
    935     private static native void nDrawTextOnPath(long renderer, char[] text, int index, int count,
    936             long path, float hOffset, float vOffset, int bidiFlags, long nativePaint,
    937             long typeface);
    938 
    939     @Override
    940     public void drawTextOnPath(String text, Path path, float hOffset, float vOffset, Paint paint) {
    941         if (text.length() == 0) return;
    942 
    943         nDrawTextOnPath(mRenderer, text, 0, text.length(), path.mNativePath, hOffset, vOffset,
    944                 paint.mBidiFlags, paint.mNativePaint, paint.mNativeTypeface);
    945     }
    946 
    947     private static native void nDrawTextOnPath(long renderer, String text, int start, int end,
    948             long path, float hOffset, float vOffset, int bidiFlags, long nativePaint,
    949             long typeface);
    950 
    951     @Override
    952     public void drawTextRun(char[] text, int index, int count, int contextIndex, int contextCount,
    953             float x, float y, boolean isRtl, Paint paint) {
    954         if ((index | count | text.length - index - count) < 0) {
    955             throw new IndexOutOfBoundsException();
    956         }
    957 
    958         nDrawTextRun(mRenderer, text, index, count, contextIndex, contextCount, x, y, isRtl,
    959                 paint.mNativePaint, paint.mNativeTypeface);
    960     }
    961 
    962     private static native void nDrawTextRun(long renderer, char[] text, int index, int count,
    963             int contextIndex, int contextCount, float x, float y, boolean isRtl, long nativePaint, long nativeTypeface);
    964 
    965     @Override
    966     public void drawTextRun(CharSequence text, int start, int end, int contextStart, int contextEnd,
    967             float x, float y, boolean isRtl, Paint paint) {
    968         if ((start | end | end - start | text.length() - end) < 0) {
    969             throw new IndexOutOfBoundsException();
    970         }
    971 
    972         if (text instanceof String || text instanceof SpannedString ||
    973                 text instanceof SpannableString) {
    974             nDrawTextRun(mRenderer, text.toString(), start, end, contextStart,
    975                     contextEnd, x, y, isRtl, paint.mNativePaint, paint.mNativeTypeface);
    976         } else if (text instanceof GraphicsOperations) {
    977             ((GraphicsOperations) text).drawTextRun(this, start, end,
    978                     contextStart, contextEnd, x, y, isRtl, paint);
    979         } else {
    980             int contextLen = contextEnd - contextStart;
    981             int len = end - start;
    982             char[] buf = TemporaryBuffer.obtain(contextLen);
    983             TextUtils.getChars(text, contextStart, contextEnd, buf, 0);
    984             nDrawTextRun(mRenderer, buf, start - contextStart, len, 0, contextLen,
    985                     x, y, isRtl, paint.mNativePaint, paint.mNativeTypeface);
    986             TemporaryBuffer.recycle(buf);
    987         }
    988     }
    989 
    990     private static native void nDrawTextRun(long renderer, String text, int start, int end,
    991             int contextStart, int contextEnd, float x, float y, boolean isRtl, long nativePaint, long nativeTypeface);
    992 
    993     @Override
    994     public void drawVertices(VertexMode mode, int vertexCount, float[] verts, int vertOffset,
    995             float[] texs, int texOffset, int[] colors, int colorOffset, short[] indices,
    996             int indexOffset, int indexCount, Paint paint) {
    997         // TODO: Implement
    998     }
    999 }
   1000