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.ColorFilter;
     22 import android.graphics.DrawFilter;
     23 import android.graphics.Matrix;
     24 import android.graphics.Paint;
     25 import android.graphics.Path;
     26 import android.graphics.Picture;
     27 import android.graphics.PorterDuff;
     28 import android.graphics.Rect;
     29 import android.graphics.RectF;
     30 import android.graphics.Region;
     31 import android.graphics.Shader;
     32 import android.graphics.SurfaceTexture;
     33 import android.graphics.TemporaryBuffer;
     34 import android.text.GraphicsOperations;
     35 import android.text.SpannableString;
     36 import android.text.SpannedString;
     37 import android.text.TextUtils;
     38 
     39 /**
     40  * An implementation of Canvas on top of OpenGL ES 2.0.
     41  */
     42 class GLES20Canvas extends HardwareCanvas {
     43     // Must match modifiers used in the JNI layer
     44     private static final int MODIFIER_NONE = 0;
     45     private static final int MODIFIER_SHADOW = 1;
     46     private static final int MODIFIER_SHADER = 2;
     47     private static final int MODIFIER_COLOR_FILTER = 4;
     48 
     49     private final boolean mOpaque;
     50     private int mRenderer;
     51 
     52     // The native renderer will be destroyed when this object dies.
     53     // DO NOT overwrite this reference once it is set.
     54     @SuppressWarnings({"unused", "FieldCanBeLocal"})
     55     private CanvasFinalizer mFinalizer;
     56 
     57     private int mWidth;
     58     private int mHeight;
     59 
     60     private final float[] mPoint = new float[2];
     61     private final float[] mLine = new float[4];
     62 
     63     private final Rect mClipBounds = new Rect();
     64 
     65     private DrawFilter mFilter;
     66 
     67     ///////////////////////////////////////////////////////////////////////////
     68     // JNI
     69     ///////////////////////////////////////////////////////////////////////////
     70 
     71     private static native boolean nIsAvailable();
     72     private static boolean sIsAvailable = nIsAvailable();
     73 
     74     static boolean isAvailable() {
     75         return sIsAvailable;
     76     }
     77 
     78     ///////////////////////////////////////////////////////////////////////////
     79     // Constructors
     80     ///////////////////////////////////////////////////////////////////////////
     81 
     82     /**
     83      * Creates a canvas to render directly on screen.
     84      */
     85     GLES20Canvas(boolean translucent) {
     86         this(false, translucent);
     87     }
     88 
     89     /**
     90      * Creates a canvas to render into an FBO.
     91      */
     92     GLES20Canvas(int layer, boolean translucent) {
     93         mOpaque = !translucent;
     94         mRenderer = nCreateLayerRenderer(layer);
     95         setupFinalizer();
     96     }
     97 
     98     protected GLES20Canvas(boolean record, boolean translucent) {
     99         mOpaque = !translucent;
    100 
    101         if (record) {
    102             mRenderer = nCreateDisplayListRenderer();
    103         } else {
    104             mRenderer = nCreateRenderer();
    105         }
    106 
    107         setupFinalizer();
    108     }
    109 
    110     private void setupFinalizer() {
    111         if (mRenderer == 0) {
    112             throw new IllegalStateException("Could not create GLES20Canvas renderer");
    113         } else {
    114             mFinalizer = new CanvasFinalizer(mRenderer);
    115         }
    116     }
    117 
    118     protected void resetDisplayListRenderer() {
    119         nResetDisplayListRenderer(mRenderer);
    120     }
    121 
    122     private static native int nCreateRenderer();
    123     private static native int nCreateLayerRenderer(int layer);
    124     private static native int nCreateDisplayListRenderer();
    125     private static native void nResetDisplayListRenderer(int renderer);
    126     private static native void nDestroyRenderer(int renderer);
    127 
    128     private static final class CanvasFinalizer {
    129         private final int mRenderer;
    130 
    131         public CanvasFinalizer(int renderer) {
    132             mRenderer = renderer;
    133         }
    134 
    135         @Override
    136         protected void finalize() throws Throwable {
    137             try {
    138                 nDestroyRenderer(mRenderer);
    139             } finally {
    140                 super.finalize();
    141             }
    142         }
    143     }
    144 
    145     ///////////////////////////////////////////////////////////////////////////
    146     // Hardware layers
    147     ///////////////////////////////////////////////////////////////////////////
    148 
    149     static native int nCreateTextureLayer(boolean opaque, int[] layerInfo);
    150     static native int nCreateLayer(int width, int height, boolean isOpaque, int[] layerInfo);
    151     static native void nResizeLayer(int layerId, int width, int height, int[] layerInfo);
    152     static native void nUpdateTextureLayer(int layerId, int width, int height, boolean opaque,
    153             SurfaceTexture surface);
    154     static native void nSetTextureLayerTransform(int layerId, int matrix);
    155     static native void nDestroyLayer(int layerId);
    156     static native void nDestroyLayerDeferred(int layerId);
    157     static native boolean nCopyLayer(int layerId, int bitmap);
    158 
    159     ///////////////////////////////////////////////////////////////////////////
    160     // Canvas management
    161     ///////////////////////////////////////////////////////////////////////////
    162 
    163     @Override
    164     public boolean isOpaque() {
    165         return mOpaque;
    166     }
    167 
    168     @Override
    169     public int getWidth() {
    170         return mWidth;
    171     }
    172 
    173     @Override
    174     public int getHeight() {
    175         return mHeight;
    176     }
    177 
    178     @Override
    179     public int getMaximumBitmapWidth() {
    180         return nGetMaximumTextureWidth();
    181     }
    182 
    183     @Override
    184     public int getMaximumBitmapHeight() {
    185         return nGetMaximumTextureHeight();
    186     }
    187 
    188     private static native int nGetMaximumTextureWidth();
    189     private static native int nGetMaximumTextureHeight();
    190 
    191     ///////////////////////////////////////////////////////////////////////////
    192     // Setup
    193     ///////////////////////////////////////////////////////////////////////////
    194 
    195     @Override
    196     public void setViewport(int width, int height) {
    197         mWidth = width;
    198         mHeight = height;
    199 
    200         nSetViewport(mRenderer, width, height);
    201     }
    202 
    203     private static native void nSetViewport(int renderer, int width, int height);
    204 
    205     /**
    206      * Preserves the back buffer of the current surface after a buffer swap.
    207      * Calling this method sets the EGL_SWAP_BEHAVIOR attribute of the current
    208      * surface to EGL_BUFFER_PRESERVED. Calling this method requires an EGL
    209      * config that supports EGL_SWAP_BEHAVIOR_PRESERVED_BIT.
    210      *
    211      * @return True if the swap behavior was successfully changed,
    212      *         false otherwise.
    213      *
    214      * @hide
    215      */
    216     public static boolean preserveBackBuffer() {
    217         return nPreserveBackBuffer();
    218     }
    219 
    220     private static native boolean nPreserveBackBuffer();
    221 
    222     /**
    223      * Indicates whether the current surface preserves its back buffer
    224      * after a buffer swap.
    225      *
    226      * @return True, if the surface's EGL_SWAP_BEHAVIOR is EGL_BUFFER_PRESERVED,
    227      *         false otherwise
    228      *
    229      * @hide
    230      */
    231     public static boolean isBackBufferPreserved() {
    232         return nIsBackBufferPreserved();
    233     }
    234 
    235     private static native boolean nIsBackBufferPreserved();
    236 
    237     /**
    238      * Disables v-sync. For performance testing only.
    239      *
    240      * @hide
    241      */
    242     public static void disableVsync() {
    243         nDisableVsync();
    244     }
    245 
    246     private static native void nDisableVsync();
    247 
    248     @Override
    249     void onPreDraw(Rect dirty) {
    250         if (dirty != null) {
    251             nPrepareDirty(mRenderer, dirty.left, dirty.top, dirty.right, dirty.bottom, mOpaque);
    252         } else {
    253             nPrepare(mRenderer, mOpaque);
    254         }
    255     }
    256 
    257     private static native void nPrepare(int renderer, boolean opaque);
    258     private static native void nPrepareDirty(int renderer, int left, int top, int right, int bottom,
    259             boolean opaque);
    260 
    261     @Override
    262     void onPostDraw() {
    263         nFinish(mRenderer);
    264     }
    265 
    266     private static native void nFinish(int renderer);
    267 
    268     @Override
    269     public boolean callDrawGLFunction(int drawGLFunction) {
    270         return nCallDrawGLFunction(mRenderer, drawGLFunction);
    271     }
    272 
    273     private static native boolean nCallDrawGLFunction(int renderer, int drawGLFunction);
    274 
    275 
    276     ///////////////////////////////////////////////////////////////////////////
    277     // Memory
    278     ///////////////////////////////////////////////////////////////////////////
    279 
    280     /**
    281      * Must match Caches::FlushMode values
    282      *
    283      * @see #flushCaches(int)
    284      */
    285     public static final int FLUSH_CACHES_LAYERS = 0;
    286 
    287     /**
    288      * Must match Caches::FlushMode values
    289      *
    290      * @see #flushCaches(int)
    291      */
    292     public static final int FLUSH_CACHES_MODERATE = 1;
    293 
    294     /**
    295      * Must match Caches::FlushMode values
    296      *
    297      * @see #flushCaches(int)
    298      */
    299     public static final int FLUSH_CACHES_FULL = 2;
    300 
    301     /**
    302      * Flush caches to reclaim as much memory as possible. The amount of memory
    303      * to reclaim is indicate by the level parameter.
    304      *
    305      * The level can be one of {@link #FLUSH_CACHES_MODERATE} or
    306      * {@link #FLUSH_CACHES_FULL}.
    307      *
    308      * @param level Hint about the amount of memory to reclaim
    309      *
    310      * @hide
    311      */
    312     public static void flushCaches(int level) {
    313         nFlushCaches(level);
    314     }
    315 
    316     private static native void nFlushCaches(int level);
    317 
    318     /**
    319      * Release all resources associated with the underlying caches. This should
    320      * only be called after a full flushCaches().
    321      *
    322      * @hide
    323      */
    324     public static void terminateCaches() {
    325         nTerminateCaches();
    326     }
    327 
    328     private static native void nTerminateCaches();
    329 
    330     /**
    331      * @hide
    332      */
    333     public static void initCaches() {
    334         nInitCaches();
    335     }
    336 
    337     private static native void nInitCaches();
    338 
    339     ///////////////////////////////////////////////////////////////////////////
    340     // Display list
    341     ///////////////////////////////////////////////////////////////////////////
    342 
    343     int getDisplayList(int displayList) {
    344         return nGetDisplayList(mRenderer, displayList);
    345     }
    346 
    347     private static native int nGetDisplayList(int renderer, int displayList);
    348 
    349     static void destroyDisplayList(int displayList) {
    350         nDestroyDisplayList(displayList);
    351     }
    352 
    353     private static native void nDestroyDisplayList(int displayList);
    354 
    355     static int getDisplayListSize(int displayList) {
    356         return nGetDisplayListSize(displayList);
    357     }
    358 
    359     private static native int nGetDisplayListSize(int displayList);
    360 
    361     @Override
    362     public boolean drawDisplayList(DisplayList displayList, int width, int height, Rect dirty) {
    363         return nDrawDisplayList(mRenderer,
    364                 ((GLES20DisplayList) displayList).getNativeDisplayList(), width, height, dirty);
    365     }
    366 
    367     private static native boolean nDrawDisplayList(int renderer, int displayList,
    368             int width, int height, Rect dirty);
    369 
    370     @Override
    371     void outputDisplayList(DisplayList displayList) {
    372         nOutputDisplayList(mRenderer, ((GLES20DisplayList) displayList).getNativeDisplayList());
    373     }
    374 
    375     private static native void nOutputDisplayList(int renderer, int displayList);
    376 
    377     ///////////////////////////////////////////////////////////////////////////
    378     // Hardware layer
    379     ///////////////////////////////////////////////////////////////////////////
    380 
    381     void drawHardwareLayer(HardwareLayer layer, float x, float y, Paint paint) {
    382         final GLES20Layer glLayer = (GLES20Layer) layer;
    383         int modifier = paint != null ? setupColorFilter(paint) : MODIFIER_NONE;
    384         final int nativePaint = paint == null ? 0 : paint.mNativePaint;
    385         nDrawLayer(mRenderer, glLayer.getLayer(), x, y, nativePaint);
    386         if (modifier != MODIFIER_NONE) nResetModifiers(mRenderer, modifier);
    387     }
    388 
    389     private static native void nDrawLayer(int renderer, int layer, float x, float y, int paint);
    390 
    391     void interrupt() {
    392         nInterrupt(mRenderer);
    393     }
    394 
    395     void resume() {
    396         nResume(mRenderer);
    397     }
    398 
    399     private static native void nInterrupt(int renderer);
    400     private static native void nResume(int renderer);
    401 
    402     ///////////////////////////////////////////////////////////////////////////
    403     // Clipping
    404     ///////////////////////////////////////////////////////////////////////////
    405 
    406     @Override
    407     public boolean clipPath(Path path) {
    408         throw new UnsupportedOperationException();
    409     }
    410 
    411     @Override
    412     public boolean clipPath(Path path, Region.Op op) {
    413         throw new UnsupportedOperationException();
    414     }
    415 
    416     @Override
    417     public boolean clipRect(float left, float top, float right, float bottom) {
    418         return nClipRect(mRenderer, left, top, right, bottom, Region.Op.INTERSECT.nativeInt);
    419     }
    420 
    421     private static native boolean nClipRect(int renderer, float left, float top,
    422             float right, float bottom, int op);
    423 
    424     @Override
    425     public boolean clipRect(float left, float top, float right, float bottom, Region.Op op) {
    426         return nClipRect(mRenderer, left, top, right, bottom, op.nativeInt);
    427     }
    428 
    429     @Override
    430     public boolean clipRect(int left, int top, int right, int bottom) {
    431         return nClipRect(mRenderer, left, top, right, bottom, Region.Op.INTERSECT.nativeInt);
    432     }
    433 
    434     private static native boolean nClipRect(int renderer, int left, int top, int right, int bottom,
    435             int op);
    436 
    437     @Override
    438     public boolean clipRect(Rect rect) {
    439         return nClipRect(mRenderer, rect.left, rect.top, rect.right, rect.bottom,
    440                 Region.Op.INTERSECT.nativeInt);
    441     }
    442 
    443     @Override
    444     public boolean clipRect(Rect rect, Region.Op op) {
    445         return nClipRect(mRenderer, rect.left, rect.top, rect.right, rect.bottom, op.nativeInt);
    446     }
    447 
    448     @Override
    449     public boolean clipRect(RectF rect) {
    450         return nClipRect(mRenderer, rect.left, rect.top, rect.right, rect.bottom,
    451                 Region.Op.INTERSECT.nativeInt);
    452     }
    453 
    454     @Override
    455     public boolean clipRect(RectF rect, Region.Op op) {
    456         return nClipRect(mRenderer, rect.left, rect.top, rect.right, rect.bottom, op.nativeInt);
    457     }
    458 
    459     @Override
    460     public boolean clipRegion(Region region) {
    461         throw new UnsupportedOperationException();
    462     }
    463 
    464     @Override
    465     public boolean clipRegion(Region region, Region.Op op) {
    466         throw new UnsupportedOperationException();
    467     }
    468 
    469     @Override
    470     public boolean getClipBounds(Rect bounds) {
    471         return nGetClipBounds(mRenderer, bounds);
    472     }
    473 
    474     private static native boolean nGetClipBounds(int renderer, Rect bounds);
    475 
    476     @Override
    477     public boolean quickReject(float left, float top, float right, float bottom, EdgeType type) {
    478         return nQuickReject(mRenderer, left, top, right, bottom, type.nativeInt);
    479     }
    480 
    481     private static native boolean nQuickReject(int renderer, float left, float top,
    482             float right, float bottom, int edge);
    483 
    484     @Override
    485     public boolean quickReject(Path path, EdgeType type) {
    486         throw new UnsupportedOperationException();
    487     }
    488 
    489     @Override
    490     public boolean quickReject(RectF rect, EdgeType type) {
    491         return quickReject(rect.left, rect.top, rect.right, rect.bottom, type);
    492     }
    493 
    494     ///////////////////////////////////////////////////////////////////////////
    495     // Transformations
    496     ///////////////////////////////////////////////////////////////////////////
    497 
    498     @Override
    499     public void translate(float dx, float dy) {
    500         if (dx != 0.0f || dy != 0.0f) nTranslate(mRenderer, dx, dy);
    501     }
    502 
    503     private static native void nTranslate(int renderer, float dx, float dy);
    504 
    505     @Override
    506     public void skew(float sx, float sy) {
    507         nSkew(mRenderer, sx, sy);
    508     }
    509 
    510     private static native void nSkew(int renderer, float sx, float sy);
    511 
    512     @Override
    513     public void rotate(float degrees) {
    514         nRotate(mRenderer, degrees);
    515     }
    516 
    517     private static native void nRotate(int renderer, float degrees);
    518 
    519     @Override
    520     public void scale(float sx, float sy) {
    521         nScale(mRenderer, sx, sy);
    522     }
    523 
    524     private static native void nScale(int renderer, float sx, float sy);
    525 
    526     @Override
    527     public void setMatrix(Matrix matrix) {
    528         nSetMatrix(mRenderer, matrix.native_instance);
    529     }
    530 
    531     private static native void nSetMatrix(int renderer, int matrix);
    532 
    533     @Override
    534     public void getMatrix(Matrix matrix) {
    535         nGetMatrix(mRenderer, matrix.native_instance);
    536     }
    537 
    538     private static native void nGetMatrix(int renderer, int matrix);
    539 
    540     @Override
    541     public void concat(Matrix matrix) {
    542         nConcatMatrix(mRenderer, matrix.native_instance);
    543     }
    544 
    545     private static native void nConcatMatrix(int renderer, int matrix);
    546 
    547     ///////////////////////////////////////////////////////////////////////////
    548     // State management
    549     ///////////////////////////////////////////////////////////////////////////
    550 
    551     @Override
    552     public int save() {
    553         return nSave(mRenderer, Canvas.CLIP_SAVE_FLAG | Canvas.MATRIX_SAVE_FLAG);
    554     }
    555 
    556     @Override
    557     public int save(int saveFlags) {
    558         return nSave(mRenderer, saveFlags);
    559     }
    560 
    561     private static native int nSave(int renderer, int flags);
    562 
    563     @Override
    564     public int saveLayer(RectF bounds, Paint paint, int saveFlags) {
    565         if (bounds != null) {
    566             return saveLayer(bounds.left, bounds.top, bounds.right, bounds.bottom, paint, saveFlags);
    567         }
    568 
    569         int modifier = paint != null ? setupColorFilter(paint) : MODIFIER_NONE;
    570         final int nativePaint = paint == null ? 0 : paint.mNativePaint;
    571         int count = nSaveLayer(mRenderer, nativePaint, saveFlags);
    572         if (modifier != MODIFIER_NONE) nResetModifiers(mRenderer, modifier);
    573         return count;
    574     }
    575 
    576     private static native int nSaveLayer(int renderer, int paint, int saveFlags);
    577 
    578     @Override
    579     public int saveLayer(float left, float top, float right, float bottom, Paint paint,
    580             int saveFlags) {
    581         if (left < right && top < bottom) {
    582             int modifier = paint != null ? setupColorFilter(paint) : MODIFIER_NONE;
    583             final int nativePaint = paint == null ? 0 : paint.mNativePaint;
    584             int count = nSaveLayer(mRenderer, left, top, right, bottom, nativePaint, saveFlags);
    585             if (modifier != MODIFIER_NONE) nResetModifiers(mRenderer, modifier);
    586             return count;
    587         }
    588         return save(saveFlags);
    589     }
    590 
    591     private static native int nSaveLayer(int renderer, float left, float top,
    592             float right, float bottom, int paint, int saveFlags);
    593 
    594     @Override
    595     public int saveLayerAlpha(RectF bounds, int alpha, int saveFlags) {
    596         if (bounds != null) {
    597             return saveLayerAlpha(bounds.left, bounds.top, bounds.right, bounds.bottom,
    598                     alpha, saveFlags);
    599         }
    600         return nSaveLayerAlpha(mRenderer, alpha, saveFlags);
    601     }
    602 
    603     private static native int nSaveLayerAlpha(int renderer, int alpha, int saveFlags);
    604 
    605     @Override
    606     public int saveLayerAlpha(float left, float top, float right, float bottom, int alpha,
    607             int saveFlags) {
    608         if (left < right && top < bottom) {
    609             return nSaveLayerAlpha(mRenderer, left, top, right, bottom, alpha, saveFlags);
    610         }
    611         return save(saveFlags);
    612     }
    613 
    614     private static native int nSaveLayerAlpha(int renderer, float left, float top, float right,
    615             float bottom, int alpha, int saveFlags);
    616 
    617     @Override
    618     public void restore() {
    619         nRestore(mRenderer);
    620     }
    621 
    622     private static native void nRestore(int renderer);
    623 
    624     @Override
    625     public void restoreToCount(int saveCount) {
    626         nRestoreToCount(mRenderer, saveCount);
    627     }
    628 
    629     private static native void nRestoreToCount(int renderer, int saveCount);
    630 
    631     @Override
    632     public int getSaveCount() {
    633         return nGetSaveCount(mRenderer);
    634     }
    635 
    636     private static native int nGetSaveCount(int renderer);
    637 
    638     ///////////////////////////////////////////////////////////////////////////
    639     // Filtering
    640     ///////////////////////////////////////////////////////////////////////////
    641 
    642     @Override
    643     public void setDrawFilter(DrawFilter filter) {
    644         mFilter = filter;
    645     }
    646 
    647     @Override
    648     public DrawFilter getDrawFilter() {
    649         return mFilter;
    650     }
    651 
    652     ///////////////////////////////////////////////////////////////////////////
    653     // Drawing
    654     ///////////////////////////////////////////////////////////////////////////
    655 
    656     @Override
    657     public void drawArc(RectF oval, float startAngle, float sweepAngle, boolean useCenter,
    658             Paint paint) {
    659         int modifiers = setupModifiers(paint);
    660         nDrawArc(mRenderer, oval.left, oval.top, oval.right, oval.bottom, startAngle, sweepAngle,
    661                 useCenter, paint.mNativePaint);
    662         if (modifiers != MODIFIER_NONE) nResetModifiers(mRenderer, modifiers);
    663     }
    664 
    665     private static native void nDrawArc(int renderer, float left, float top,
    666             float right, float bottom, float startAngle, float sweepAngle,
    667             boolean useCenter, int paint);
    668 
    669     @Override
    670     public void drawARGB(int a, int r, int g, int b) {
    671         drawColor((a & 0xFF) << 24 | (r & 0xFF) << 16 | (g & 0xFF) << 8 | (b & 0xFF));
    672     }
    673 
    674     @Override
    675     public void drawPatch(Bitmap bitmap, byte[] chunks, RectF dst, Paint paint) {
    676         // Shaders are ignored when drawing patches
    677         int modifier = paint != null ? setupColorFilter(paint) : MODIFIER_NONE;
    678         final int nativePaint = paint == null ? 0 : paint.mNativePaint;
    679         nDrawPatch(mRenderer, bitmap.mNativeBitmap, bitmap.mBuffer, chunks,
    680                 dst.left, dst.top, dst.right, dst.bottom, nativePaint);
    681         if (modifier != MODIFIER_NONE) nResetModifiers(mRenderer, modifier);
    682     }
    683 
    684     private static native void nDrawPatch(int renderer, int bitmap, byte[] buffer, byte[] chunks,
    685             float left, float top, float right, float bottom, int paint);
    686 
    687     @Override
    688     public void drawBitmap(Bitmap bitmap, float left, float top, Paint paint) {
    689         // Shaders are ignored when drawing bitmaps
    690         int modifiers = paint != null ? setupModifiers(bitmap, paint) : MODIFIER_NONE;
    691         final int nativePaint = paint == null ? 0 : paint.mNativePaint;
    692         nDrawBitmap(mRenderer, bitmap.mNativeBitmap, bitmap.mBuffer, left, top, nativePaint);
    693         if (modifiers != MODIFIER_NONE) nResetModifiers(mRenderer, modifiers);
    694     }
    695 
    696     private static native void nDrawBitmap(
    697             int renderer, int bitmap, byte[] buffer, float left, float top, int paint);
    698 
    699     @Override
    700     public void drawBitmap(Bitmap bitmap, Matrix matrix, Paint paint) {
    701         // Shaders are ignored when drawing bitmaps
    702         int modifiers = paint != null ? setupModifiers(bitmap, paint) : MODIFIER_NONE;
    703         final int nativePaint = paint == null ? 0 : paint.mNativePaint;
    704         nDrawBitmap(mRenderer, bitmap.mNativeBitmap, bitmap.mBuffer,
    705                 matrix.native_instance, nativePaint);
    706         if (modifiers != MODIFIER_NONE) nResetModifiers(mRenderer, modifiers);
    707     }
    708 
    709     private static native void nDrawBitmap(int renderer, int bitmap, byte[] buff,
    710             int matrix, int paint);
    711 
    712     @Override
    713     public void drawBitmap(Bitmap bitmap, Rect src, Rect dst, Paint paint) {
    714         // Shaders are ignored when drawing bitmaps
    715         int modifiers = paint != null ? setupModifiers(bitmap, paint) : MODIFIER_NONE;
    716         final int nativePaint = paint == null ? 0 : paint.mNativePaint;
    717 
    718         int left, top, right, bottom;
    719         if (src == null) {
    720             left = top = 0;
    721             right = bitmap.getWidth();
    722             bottom = bitmap.getHeight();
    723         } else {
    724             left = src.left;
    725             right = src.right;
    726             top = src.top;
    727             bottom = src.bottom;
    728         }
    729 
    730         nDrawBitmap(mRenderer, bitmap.mNativeBitmap, bitmap.mBuffer, left, top, right, bottom,
    731                 dst.left, dst.top, dst.right, dst.bottom, nativePaint);
    732         if (modifiers != MODIFIER_NONE) nResetModifiers(mRenderer, modifiers);
    733     }
    734 
    735     @Override
    736     public void drawBitmap(Bitmap bitmap, Rect src, RectF dst, Paint paint) {
    737         // Shaders are ignored when drawing bitmaps
    738         int modifiers = paint != null ? setupModifiers(bitmap, paint) : MODIFIER_NONE;
    739         final int nativePaint = paint == null ? 0 : paint.mNativePaint;
    740 
    741         float left, top, right, bottom;
    742         if (src == null) {
    743             left = top = 0;
    744             right = bitmap.getWidth();
    745             bottom = bitmap.getHeight();
    746         } else {
    747             left = src.left;
    748             right = src.right;
    749             top = src.top;
    750             bottom = src.bottom;
    751         }
    752 
    753         nDrawBitmap(mRenderer, bitmap.mNativeBitmap, bitmap.mBuffer, left, top, right, bottom,
    754                 dst.left, dst.top, dst.right, dst.bottom, nativePaint);
    755         if (modifiers != MODIFIER_NONE) nResetModifiers(mRenderer, modifiers);
    756     }
    757 
    758     private static native void nDrawBitmap(int renderer, int bitmap, byte[] buffer,
    759             float srcLeft, float srcTop, float srcRight, float srcBottom,
    760             float left, float top, float right, float bottom, int paint);
    761 
    762     @Override
    763     public void drawBitmap(int[] colors, int offset, int stride, float x, float y,
    764             int width, int height, boolean hasAlpha, Paint paint) {
    765         // Shaders are ignored when drawing bitmaps
    766         int modifier = paint != null ? setupColorFilter(paint) : MODIFIER_NONE;
    767         final Bitmap.Config config = hasAlpha ? Bitmap.Config.ARGB_8888 : Bitmap.Config.RGB_565;
    768         final Bitmap b = Bitmap.createBitmap(colors, offset, stride, width, height, config);
    769         final int nativePaint = paint == null ? 0 : paint.mNativePaint;
    770         nDrawBitmap(mRenderer, b.mNativeBitmap, b.mBuffer, x, y, nativePaint);
    771         b.recycle();
    772         if (modifier != MODIFIER_NONE) nResetModifiers(mRenderer, modifier);
    773     }
    774 
    775     @Override
    776     public void drawBitmap(int[] colors, int offset, int stride, int x, int y,
    777             int width, int height, boolean hasAlpha, Paint paint) {
    778         // Shaders are ignored when drawing bitmaps
    779         drawBitmap(colors, offset, stride, (float) x, (float) y, width, height, hasAlpha, paint);
    780     }
    781 
    782     @Override
    783     public void drawBitmapMesh(Bitmap bitmap, int meshWidth, int meshHeight, float[] verts,
    784             int vertOffset, int[] colors, int colorOffset, Paint paint) {
    785         if (meshWidth < 0 || meshHeight < 0 || vertOffset < 0 || colorOffset < 0) {
    786             throw new ArrayIndexOutOfBoundsException();
    787         }
    788 
    789         if (meshWidth == 0 || meshHeight == 0) {
    790             return;
    791         }
    792 
    793         final int count = (meshWidth + 1) * (meshHeight + 1);
    794         checkRange(verts.length, vertOffset, count * 2);
    795 
    796         // TODO: Colors are ignored for now
    797         colors = null;
    798         colorOffset = 0;
    799 
    800         int modifiers = paint != null ? setupModifiers(bitmap, paint) : MODIFIER_NONE;
    801         final int nativePaint = paint == null ? 0 : paint.mNativePaint;
    802         nDrawBitmapMesh(mRenderer, bitmap.mNativeBitmap, bitmap.mBuffer, meshWidth, meshHeight,
    803                 verts, vertOffset, colors, colorOffset, nativePaint);
    804         if (modifiers != MODIFIER_NONE) nResetModifiers(mRenderer, modifiers);
    805     }
    806 
    807     private static native void nDrawBitmapMesh(int renderer, int bitmap, byte[] buffer,
    808             int meshWidth, int meshHeight, float[] verts, int vertOffset,
    809             int[] colors, int colorOffset, int paint);
    810 
    811     @Override
    812     public void drawCircle(float cx, float cy, float radius, Paint paint) {
    813         int modifiers = setupModifiers(paint);
    814         nDrawCircle(mRenderer, cx, cy, radius, paint.mNativePaint);
    815         if (modifiers != MODIFIER_NONE) nResetModifiers(mRenderer, modifiers);
    816     }
    817 
    818     private static native void nDrawCircle(int renderer, float cx, float cy,
    819             float radius, int paint);
    820 
    821     @Override
    822     public void drawColor(int color) {
    823         drawColor(color, PorterDuff.Mode.SRC_OVER);
    824     }
    825 
    826     @Override
    827     public void drawColor(int color, PorterDuff.Mode mode) {
    828         nDrawColor(mRenderer, color, mode.nativeInt);
    829     }
    830 
    831     private static native void nDrawColor(int renderer, int color, int mode);
    832 
    833     @Override
    834     public void drawLine(float startX, float startY, float stopX, float stopY, Paint paint) {
    835         mLine[0] = startX;
    836         mLine[1] = startY;
    837         mLine[2] = stopX;
    838         mLine[3] = stopY;
    839         drawLines(mLine, 0, 4, paint);
    840     }
    841 
    842     @Override
    843     public void drawLines(float[] pts, int offset, int count, Paint paint) {
    844         if ((offset | count) < 0 || offset + count > pts.length) {
    845             throw new IllegalArgumentException("The lines array must contain 4 elements per line.");
    846         }
    847         int modifiers = setupModifiers(paint);
    848         nDrawLines(mRenderer, pts, offset, count, paint.mNativePaint);
    849         if (modifiers != MODIFIER_NONE) nResetModifiers(mRenderer, modifiers);
    850     }
    851 
    852     private static native void nDrawLines(int renderer, float[] points,
    853             int offset, int count, int paint);
    854 
    855     @Override
    856     public void drawLines(float[] pts, Paint paint) {
    857         drawLines(pts, 0, pts.length, paint);
    858     }
    859 
    860     @Override
    861     public void drawOval(RectF oval, Paint paint) {
    862         int modifiers = setupModifiers(paint);
    863         nDrawOval(mRenderer, oval.left, oval.top, oval.right, oval.bottom, paint.mNativePaint);
    864         if (modifiers != MODIFIER_NONE) nResetModifiers(mRenderer, modifiers);
    865     }
    866 
    867     private static native void nDrawOval(int renderer, float left, float top,
    868             float right, float bottom, int paint);
    869 
    870     @Override
    871     public void drawPaint(Paint paint) {
    872         final Rect r = mClipBounds;
    873         nGetClipBounds(mRenderer, r);
    874         drawRect(r.left, r.top, r.right, r.bottom, paint);
    875     }
    876 
    877     @Override
    878     public void drawPath(Path path, Paint paint) {
    879         int modifiers = setupModifiers(paint);
    880         if (path.isSimplePath) {
    881             if (path.rects != null) {
    882                 nDrawRects(mRenderer, path.rects.mNativeRegion, paint.mNativePaint);
    883             }
    884         } else {
    885             nDrawPath(mRenderer, path.mNativePath, paint.mNativePaint);
    886         }
    887         if (modifiers != MODIFIER_NONE) nResetModifiers(mRenderer, modifiers);
    888     }
    889 
    890     private static native void nDrawPath(int renderer, int path, int paint);
    891     private static native void nDrawRects(int renderer, int region, int paint);
    892 
    893     @Override
    894     public void drawPicture(Picture picture) {
    895         throw new UnsupportedOperationException();
    896     }
    897 
    898     @Override
    899     public void drawPicture(Picture picture, Rect dst) {
    900         throw new UnsupportedOperationException();
    901     }
    902 
    903     @Override
    904     public void drawPicture(Picture picture, RectF dst) {
    905         throw new UnsupportedOperationException();
    906     }
    907 
    908     @Override
    909     public void drawPoint(float x, float y, Paint paint) {
    910         mPoint[0] = x;
    911         mPoint[1] = y;
    912         drawPoints(mPoint, 0, 2, paint);
    913     }
    914 
    915     @Override
    916     public void drawPoints(float[] pts, Paint paint) {
    917         drawPoints(pts, 0, pts.length, paint);
    918     }
    919 
    920     @Override
    921     public void drawPoints(float[] pts, int offset, int count, Paint paint) {
    922         int modifiers = setupModifiers(paint);
    923         nDrawPoints(mRenderer, pts, offset, count, paint.mNativePaint);
    924         if (modifiers != MODIFIER_NONE) nResetModifiers(mRenderer, modifiers);
    925     }
    926 
    927     private static native void nDrawPoints(int renderer, float[] points,
    928             int offset, int count, int paint);
    929 
    930     @Override
    931     public void drawPosText(char[] text, int index, int count, float[] pos, Paint paint) {
    932         // TODO: Implement
    933     }
    934 
    935     @Override
    936     public void drawPosText(String text, float[] pos, Paint paint) {
    937         // TODO: Implement
    938     }
    939 
    940     @Override
    941     public void drawRect(float left, float top, float right, float bottom, Paint paint) {
    942         int modifiers = setupModifiers(paint);
    943         nDrawRect(mRenderer, left, top, right, bottom, paint.mNativePaint);
    944         if (modifiers != MODIFIER_NONE) nResetModifiers(mRenderer, modifiers);
    945     }
    946 
    947     private static native void nDrawRect(int renderer, float left, float top,
    948             float right, float bottom, int paint);
    949 
    950     @Override
    951     public void drawRect(Rect r, Paint paint) {
    952         drawRect(r.left, r.top, r.right, r.bottom, paint);
    953     }
    954 
    955     @Override
    956     public void drawRect(RectF r, Paint paint) {
    957         drawRect(r.left, r.top, r.right, r.bottom, paint);
    958     }
    959 
    960     @Override
    961     public void drawRGB(int r, int g, int b) {
    962         drawColor(0xFF000000 | (r & 0xFF) << 16 | (g & 0xFF) << 8 | (b & 0xFF));
    963     }
    964 
    965     @Override
    966     public void drawRoundRect(RectF rect, float rx, float ry, Paint paint) {
    967         int modifiers = setupModifiers(paint);
    968         nDrawRoundRect(mRenderer, rect.left, rect.top, rect.right, rect.bottom,
    969                 rx, ry, paint.mNativePaint);
    970         if (modifiers != MODIFIER_NONE) nResetModifiers(mRenderer, modifiers);
    971     }
    972 
    973     private static native void nDrawRoundRect(int renderer, float left, float top,
    974             float right, float bottom, float rx, float y, int paint);
    975 
    976     @Override
    977     public void drawText(char[] text, int index, int count, float x, float y, Paint paint) {
    978         if ((index | count | (index + count) | (text.length - index - count)) < 0) {
    979             throw new IndexOutOfBoundsException();
    980         }
    981 
    982         int modifiers = setupModifiers(paint);
    983         try {
    984             nDrawText(mRenderer, text, index, count, x, y, paint.mBidiFlags, paint.mNativePaint);
    985         } finally {
    986             if (modifiers != MODIFIER_NONE) nResetModifiers(mRenderer, modifiers);
    987         }
    988     }
    989 
    990     private static native void nDrawText(int renderer, char[] text, int index, int count,
    991             float x, float y, int bidiFlags, int paint);
    992 
    993     @Override
    994     public void drawText(CharSequence text, int start, int end, float x, float y, Paint paint) {
    995         int modifiers = setupModifiers(paint);
    996         try {
    997             if (text instanceof String || text instanceof SpannedString ||
    998                     text instanceof SpannableString) {
    999                 nDrawText(mRenderer, text.toString(), start, end, x, y, paint.mBidiFlags,
   1000                         paint.mNativePaint);
   1001             } else if (text instanceof GraphicsOperations) {
   1002                 ((GraphicsOperations) text).drawText(this, start, end, x, y,
   1003                                                          paint);
   1004             } else {
   1005                 char[] buf = TemporaryBuffer.obtain(end - start);
   1006                 TextUtils.getChars(text, start, end, buf, 0);
   1007                 nDrawText(mRenderer, buf, 0, end - start, x, y,
   1008                         paint.mBidiFlags, paint.mNativePaint);
   1009                 TemporaryBuffer.recycle(buf);
   1010             }
   1011         } finally {
   1012             if (modifiers != MODIFIER_NONE) nResetModifiers(mRenderer, modifiers);
   1013         }
   1014     }
   1015 
   1016     @Override
   1017     public void drawText(String text, int start, int end, float x, float y, Paint paint) {
   1018         if ((start | end | (end - start) | (text.length() - end)) < 0) {
   1019             throw new IndexOutOfBoundsException();
   1020         }
   1021 
   1022         int modifiers = setupModifiers(paint);
   1023         try {
   1024             nDrawText(mRenderer, text, start, end, x, y, paint.mBidiFlags, paint.mNativePaint);
   1025         } finally {
   1026             if (modifiers != MODIFIER_NONE) nResetModifiers(mRenderer, modifiers);
   1027         }
   1028     }
   1029 
   1030     private static native void nDrawText(int renderer, String text, int start, int end,
   1031             float x, float y, int bidiFlags, int paint);
   1032 
   1033     @Override
   1034     public void drawText(String text, float x, float y, Paint paint) {
   1035         int modifiers = setupModifiers(paint);
   1036         try {
   1037             nDrawText(mRenderer, text, 0, text.length(), x, y, paint.mBidiFlags,
   1038                     paint.mNativePaint);
   1039         } finally {
   1040             if (modifiers != MODIFIER_NONE) nResetModifiers(mRenderer, modifiers);
   1041         }
   1042     }
   1043 
   1044     @Override
   1045     public void drawTextOnPath(char[] text, int index, int count, Path path, float hOffset,
   1046             float vOffset, Paint paint) {
   1047         // TODO: Implement
   1048     }
   1049 
   1050     @Override
   1051     public void drawTextOnPath(String text, Path path, float hOffset, float vOffset, Paint paint) {
   1052         // TODO: Implement
   1053     }
   1054 
   1055     @Override
   1056     public void drawTextRun(char[] text, int index, int count, int contextIndex, int contextCount,
   1057             float x, float y, int dir, Paint paint) {
   1058         if ((index | count | text.length - index - count) < 0) {
   1059             throw new IndexOutOfBoundsException();
   1060         }
   1061         if (dir != DIRECTION_LTR && dir != DIRECTION_RTL) {
   1062             throw new IllegalArgumentException("Unknown direction: " + dir);
   1063         }
   1064 
   1065         int modifiers = setupModifiers(paint);
   1066         try {
   1067             nDrawTextRun(mRenderer, text, index, count, contextIndex, contextCount, x, y, dir,
   1068                     paint.mNativePaint);
   1069         } finally {
   1070             if (modifiers != MODIFIER_NONE) nResetModifiers(mRenderer, modifiers);
   1071         }
   1072     }
   1073 
   1074     private static native void nDrawTextRun(int renderer, char[] text, int index, int count,
   1075             int contextIndex, int contextCount, float x, float y, int dir, int nativePaint);
   1076 
   1077     @Override
   1078     public void drawTextRun(CharSequence text, int start, int end, int contextStart, int contextEnd,
   1079             float x, float y, int dir, Paint paint) {
   1080         if ((start | end | end - start | text.length() - end) < 0) {
   1081             throw new IndexOutOfBoundsException();
   1082         }
   1083 
   1084         int modifiers = setupModifiers(paint);
   1085         try {
   1086             int flags = dir == 0 ? 0 : 1;
   1087             if (text instanceof String || text instanceof SpannedString ||
   1088                     text instanceof SpannableString) {
   1089                 nDrawTextRun(mRenderer, text.toString(), start, end, contextStart,
   1090                         contextEnd, x, y, flags, paint.mNativePaint);
   1091             } else if (text instanceof GraphicsOperations) {
   1092                 ((GraphicsOperations) text).drawTextRun(this, start, end,
   1093                         contextStart, contextEnd, x, y, flags, paint);
   1094             } else {
   1095                 int contextLen = contextEnd - contextStart;
   1096                 int len = end - start;
   1097                 char[] buf = TemporaryBuffer.obtain(contextLen);
   1098                 TextUtils.getChars(text, contextStart, contextEnd, buf, 0);
   1099                 nDrawTextRun(mRenderer, buf, start - contextStart, len, 0, contextLen,
   1100                         x, y, flags, paint.mNativePaint);
   1101                 TemporaryBuffer.recycle(buf);
   1102             }
   1103         } finally {
   1104             if (modifiers != MODIFIER_NONE) nResetModifiers(mRenderer, modifiers);
   1105         }
   1106     }
   1107 
   1108     private static native void nDrawTextRun(int renderer, String text, int start, int end,
   1109             int contextStart, int contextEnd, float x, float y, int flags, int nativePaint);
   1110 
   1111     @Override
   1112     public void drawVertices(VertexMode mode, int vertexCount, float[] verts, int vertOffset,
   1113             float[] texs, int texOffset, int[] colors, int colorOffset, short[] indices,
   1114             int indexOffset, int indexCount, Paint paint) {
   1115         // TODO: Implement
   1116     }
   1117 
   1118     private int setupModifiers(Bitmap b, Paint paint) {
   1119         if (b.getConfig() == Bitmap.Config.ALPHA_8) {
   1120             return setupModifiers(paint);
   1121         }
   1122 
   1123         final ColorFilter filter = paint.getColorFilter();
   1124         if (filter != null) {
   1125             nSetupColorFilter(mRenderer, filter.nativeColorFilter);
   1126             return MODIFIER_COLOR_FILTER;
   1127         }
   1128 
   1129         return MODIFIER_NONE;
   1130     }
   1131 
   1132     private int setupModifiers(Paint paint) {
   1133         int modifiers = MODIFIER_NONE;
   1134 
   1135         if (paint.hasShadow) {
   1136             nSetupShadow(mRenderer, paint.shadowRadius, paint.shadowDx, paint.shadowDy,
   1137                     paint.shadowColor);
   1138             modifiers |= MODIFIER_SHADOW;
   1139         }
   1140 
   1141         final Shader shader = paint.getShader();
   1142         if (shader != null) {
   1143             nSetupShader(mRenderer, shader.native_shader);
   1144             modifiers |= MODIFIER_SHADER;
   1145         }
   1146 
   1147         final ColorFilter filter = paint.getColorFilter();
   1148         if (filter != null) {
   1149             nSetupColorFilter(mRenderer, filter.nativeColorFilter);
   1150             modifiers |= MODIFIER_COLOR_FILTER;
   1151         }
   1152 
   1153         return modifiers;
   1154     }
   1155 
   1156     private int setupColorFilter(Paint paint) {
   1157         final ColorFilter filter = paint.getColorFilter();
   1158         if (filter != null) {
   1159             nSetupColorFilter(mRenderer, filter.nativeColorFilter);
   1160             return MODIFIER_COLOR_FILTER;
   1161         }
   1162         return MODIFIER_NONE;
   1163     }
   1164 
   1165     private static native void nSetupShader(int renderer, int shader);
   1166     private static native void nSetupColorFilter(int renderer, int colorFilter);
   1167     private static native void nSetupShadow(int renderer, float radius,
   1168             float dx, float dy, int color);
   1169 
   1170     private static native void nResetModifiers(int renderer, int modifiers);
   1171 }
   1172