Home | History | Annotate | Download | only in graphics
      1 /*
      2  * Copyright (C) 2016 The Android Open Source Project
      3  *
      4  * Licensed under the Apache License, Version 2.0 (the "License");
      5  * you may not use this file except in compliance with the License.
      6  * You may obtain a copy of the License at
      7  *
      8  *      http://www.apache.org/licenses/LICENSE-2.0
      9  *
     10  * Unless required by applicable law or agreed to in writing, software
     11  * distributed under the License is distributed on an "AS IS" BASIS,
     12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13  * See the License for the specific language governing permissions and
     14  * limitations under the License.
     15  */
     16 
     17 package android.graphics;
     18 
     19 import android.annotation.ColorInt;
     20 import android.annotation.NonNull;
     21 import android.annotation.Nullable;
     22 import android.annotation.Size;
     23 import android.graphics.Canvas.VertexMode;
     24 import android.text.GraphicsOperations;
     25 import android.text.PrecomputedText;
     26 import android.text.SpannableString;
     27 import android.text.SpannedString;
     28 import android.text.TextUtils;
     29 import android.view.RecordingCanvas;
     30 
     31 /**
     32  * This class is a base class for Canvas's drawing operations. Any modifications here
     33  * should be accompanied by a similar modification to {@link RecordingCanvas}.
     34  *
     35  * The purpose of this class is to minimize the cost of deciding between regular JNI
     36  * and @FastNative JNI to just the virtual call that Canvas already has.
     37  *
     38  * @hide
     39  */
     40 public abstract class BaseCanvas {
     41     /**
     42      * Should only be assigned in constructors (or setBitmap if software canvas),
     43      * freed by NativeAllocation.
     44      * @hide
     45      */
     46     protected long mNativeCanvasWrapper;
     47 
     48     /**
     49      * Used to determine when compatibility scaling is in effect.
     50      * @hide
     51      */
     52     protected int mScreenDensity = Bitmap.DENSITY_NONE;
     53 
     54     /**
     55      * @hide
     56      */
     57     protected int mDensity = Bitmap.DENSITY_NONE;
     58     private boolean mAllowHwBitmapsInSwMode = false;
     59 
     60     protected void throwIfCannotDraw(Bitmap bitmap) {
     61         if (bitmap.isRecycled()) {
     62             throw new RuntimeException("Canvas: trying to use a recycled bitmap " + bitmap);
     63         }
     64         if (!bitmap.isPremultiplied() && bitmap.getConfig() == Bitmap.Config.ARGB_8888 &&
     65                 bitmap.hasAlpha()) {
     66             throw new RuntimeException("Canvas: trying to use a non-premultiplied bitmap "
     67                     + bitmap);
     68         }
     69         throwIfHwBitmapInSwMode(bitmap);
     70     }
     71 
     72     protected final static void checkRange(int length, int offset, int count) {
     73         if ((offset | count) < 0 || offset + count > length) {
     74             throw new ArrayIndexOutOfBoundsException();
     75         }
     76     }
     77 
     78     public boolean isHardwareAccelerated() {
     79         return false;
     80     }
     81 
     82     // ---------------------------------------------------------------------------
     83     // Drawing methods
     84     // These are also implemented in DisplayListCanvas so that we can
     85     // selectively apply on them
     86     // Everything below here is copy/pasted from Canvas.java
     87     // The JNI registration is handled by android_view_Canvas.cpp
     88     // ---------------------------------------------------------------------------
     89 
     90     public void drawArc(float left, float top, float right, float bottom, float startAngle,
     91             float sweepAngle, boolean useCenter, @NonNull Paint paint) {
     92         throwIfHasHwBitmapInSwMode(paint);
     93         nDrawArc(mNativeCanvasWrapper, left, top, right, bottom, startAngle, sweepAngle,
     94                 useCenter, paint.getNativeInstance());
     95     }
     96 
     97     public void drawArc(@NonNull RectF oval, float startAngle, float sweepAngle, boolean useCenter,
     98             @NonNull Paint paint) {
     99         throwIfHasHwBitmapInSwMode(paint);
    100         drawArc(oval.left, oval.top, oval.right, oval.bottom, startAngle, sweepAngle, useCenter,
    101                 paint);
    102     }
    103 
    104     public void drawARGB(int a, int r, int g, int b) {
    105         drawColor(Color.argb(a, r, g, b));
    106     }
    107 
    108     public void drawBitmap(@NonNull Bitmap bitmap, float left, float top, @Nullable Paint paint) {
    109         throwIfCannotDraw(bitmap);
    110         throwIfHasHwBitmapInSwMode(paint);
    111         nDrawBitmap(mNativeCanvasWrapper, bitmap, left, top,
    112                 paint != null ? paint.getNativeInstance() : 0, mDensity, mScreenDensity,
    113                 bitmap.mDensity);
    114     }
    115 
    116     public void drawBitmap(@NonNull Bitmap bitmap, @NonNull Matrix matrix, @Nullable Paint paint) {
    117         throwIfHasHwBitmapInSwMode(paint);
    118         nDrawBitmapMatrix(mNativeCanvasWrapper, bitmap, matrix.ni(),
    119                 paint != null ? paint.getNativeInstance() : 0);
    120     }
    121 
    122     public void drawBitmap(@NonNull Bitmap bitmap, @Nullable Rect src, @NonNull Rect dst,
    123             @Nullable Paint paint) {
    124         if (dst == null) {
    125             throw new NullPointerException();
    126         }
    127         throwIfCannotDraw(bitmap);
    128         throwIfHasHwBitmapInSwMode(paint);
    129         final long nativePaint = paint == null ? 0 : paint.getNativeInstance();
    130 
    131         int left, top, right, bottom;
    132         if (src == null) {
    133             left = top = 0;
    134             right = bitmap.getWidth();
    135             bottom = bitmap.getHeight();
    136         } else {
    137             left = src.left;
    138             right = src.right;
    139             top = src.top;
    140             bottom = src.bottom;
    141         }
    142 
    143         nDrawBitmap(mNativeCanvasWrapper, bitmap, left, top, right, bottom,
    144                 dst.left, dst.top, dst.right, dst.bottom, nativePaint, mScreenDensity,
    145                 bitmap.mDensity);
    146     }
    147 
    148     public void drawBitmap(@NonNull Bitmap bitmap, @Nullable Rect src, @NonNull RectF dst,
    149             @Nullable Paint paint) {
    150         if (dst == null) {
    151             throw new NullPointerException();
    152         }
    153         throwIfCannotDraw(bitmap);
    154         throwIfHasHwBitmapInSwMode(paint);
    155         final long nativePaint = paint == null ? 0 : paint.getNativeInstance();
    156 
    157         float left, top, right, bottom;
    158         if (src == null) {
    159             left = top = 0;
    160             right = bitmap.getWidth();
    161             bottom = bitmap.getHeight();
    162         } else {
    163             left = src.left;
    164             right = src.right;
    165             top = src.top;
    166             bottom = src.bottom;
    167         }
    168 
    169         nDrawBitmap(mNativeCanvasWrapper, bitmap, left, top, right, bottom,
    170                 dst.left, dst.top, dst.right, dst.bottom, nativePaint, mScreenDensity,
    171                 bitmap.mDensity);
    172     }
    173 
    174     @Deprecated
    175     public void drawBitmap(@NonNull int[] colors, int offset, int stride, float x, float y,
    176             int width, int height, boolean hasAlpha, @Nullable Paint paint) {
    177         // check for valid input
    178         if (width < 0) {
    179             throw new IllegalArgumentException("width must be >= 0");
    180         }
    181         if (height < 0) {
    182             throw new IllegalArgumentException("height must be >= 0");
    183         }
    184         if (Math.abs(stride) < width) {
    185             throw new IllegalArgumentException("abs(stride) must be >= width");
    186         }
    187         int lastScanline = offset + (height - 1) * stride;
    188         int length = colors.length;
    189         if (offset < 0 || (offset + width > length) || lastScanline < 0
    190                 || (lastScanline + width > length)) {
    191             throw new ArrayIndexOutOfBoundsException();
    192         }
    193         throwIfHasHwBitmapInSwMode(paint);
    194         // quick escape if there's nothing to draw
    195         if (width == 0 || height == 0) {
    196             return;
    197         }
    198         // punch down to native for the actual draw
    199         nDrawBitmap(mNativeCanvasWrapper, colors, offset, stride, x, y, width, height, hasAlpha,
    200                 paint != null ? paint.getNativeInstance() : 0);
    201     }
    202 
    203     @Deprecated
    204     public void drawBitmap(@NonNull int[] colors, int offset, int stride, int x, int y,
    205             int width, int height, boolean hasAlpha, @Nullable Paint paint) {
    206         // call through to the common float version
    207         drawBitmap(colors, offset, stride, (float) x, (float) y, width, height,
    208                 hasAlpha, paint);
    209     }
    210 
    211     public void drawBitmapMesh(@NonNull Bitmap bitmap, int meshWidth, int meshHeight,
    212             @NonNull float[] verts, int vertOffset, @Nullable int[] colors, int colorOffset,
    213             @Nullable Paint paint) {
    214         if ((meshWidth | meshHeight | vertOffset | colorOffset) < 0) {
    215             throw new ArrayIndexOutOfBoundsException();
    216         }
    217         throwIfHasHwBitmapInSwMode(paint);
    218         if (meshWidth == 0 || meshHeight == 0) {
    219             return;
    220         }
    221         int count = (meshWidth + 1) * (meshHeight + 1);
    222         // we mul by 2 since we need two floats per vertex
    223         checkRange(verts.length, vertOffset, count * 2);
    224         if (colors != null) {
    225             // no mul by 2, since we need only 1 color per vertex
    226             checkRange(colors.length, colorOffset, count);
    227         }
    228         nDrawBitmapMesh(mNativeCanvasWrapper, bitmap, meshWidth, meshHeight,
    229                 verts, vertOffset, colors, colorOffset,
    230                 paint != null ? paint.getNativeInstance() : 0);
    231     }
    232 
    233     public void drawCircle(float cx, float cy, float radius, @NonNull Paint paint) {
    234         throwIfHasHwBitmapInSwMode(paint);
    235         nDrawCircle(mNativeCanvasWrapper, cx, cy, radius, paint.getNativeInstance());
    236     }
    237 
    238     public void drawColor(@ColorInt int color) {
    239         nDrawColor(mNativeCanvasWrapper, color, PorterDuff.Mode.SRC_OVER.nativeInt);
    240     }
    241 
    242     public void drawColor(@ColorInt int color, @NonNull PorterDuff.Mode mode) {
    243         nDrawColor(mNativeCanvasWrapper, color, mode.nativeInt);
    244     }
    245 
    246     public void drawLine(float startX, float startY, float stopX, float stopY,
    247             @NonNull Paint paint) {
    248         throwIfHasHwBitmapInSwMode(paint);
    249         nDrawLine(mNativeCanvasWrapper, startX, startY, stopX, stopY, paint.getNativeInstance());
    250     }
    251 
    252     public void drawLines(@Size(multiple = 4) @NonNull float[] pts, int offset, int count,
    253             @NonNull Paint paint) {
    254         throwIfHasHwBitmapInSwMode(paint);
    255         nDrawLines(mNativeCanvasWrapper, pts, offset, count, paint.getNativeInstance());
    256     }
    257 
    258     public void drawLines(@Size(multiple = 4) @NonNull float[] pts, @NonNull Paint paint) {
    259         throwIfHasHwBitmapInSwMode(paint);
    260         drawLines(pts, 0, pts.length, paint);
    261     }
    262 
    263     public void drawOval(float left, float top, float right, float bottom, @NonNull Paint paint) {
    264         throwIfHasHwBitmapInSwMode(paint);
    265         nDrawOval(mNativeCanvasWrapper, left, top, right, bottom, paint.getNativeInstance());
    266     }
    267 
    268     public void drawOval(@NonNull RectF oval, @NonNull Paint paint) {
    269         if (oval == null) {
    270             throw new NullPointerException();
    271         }
    272         throwIfHasHwBitmapInSwMode(paint);
    273         drawOval(oval.left, oval.top, oval.right, oval.bottom, paint);
    274     }
    275 
    276     public void drawPaint(@NonNull Paint paint) {
    277         nDrawPaint(mNativeCanvasWrapper, paint.getNativeInstance());
    278     }
    279 
    280     public void drawPatch(@NonNull NinePatch patch, @NonNull Rect dst, @Nullable Paint paint) {
    281         Bitmap bitmap = patch.getBitmap();
    282         throwIfCannotDraw(bitmap);
    283         throwIfHasHwBitmapInSwMode(paint);
    284         final long nativePaint = paint == null ? 0 : paint.getNativeInstance();
    285         nDrawNinePatch(mNativeCanvasWrapper, bitmap.getNativeInstance(), patch.mNativeChunk,
    286                 dst.left, dst.top, dst.right, dst.bottom, nativePaint,
    287                 mDensity, patch.getDensity());
    288     }
    289 
    290     public void drawPatch(@NonNull NinePatch patch, @NonNull RectF dst, @Nullable Paint paint) {
    291         Bitmap bitmap = patch.getBitmap();
    292         throwIfCannotDraw(bitmap);
    293         throwIfHasHwBitmapInSwMode(paint);
    294         final long nativePaint = paint == null ? 0 : paint.getNativeInstance();
    295         nDrawNinePatch(mNativeCanvasWrapper, bitmap.getNativeInstance(), patch.mNativeChunk,
    296                 dst.left, dst.top, dst.right, dst.bottom, nativePaint,
    297                 mDensity, patch.getDensity());
    298     }
    299 
    300     public void drawPath(@NonNull Path path, @NonNull Paint paint) {
    301         throwIfHasHwBitmapInSwMode(paint);
    302         if (path.isSimplePath && path.rects != null) {
    303             nDrawRegion(mNativeCanvasWrapper, path.rects.mNativeRegion, paint.getNativeInstance());
    304         } else {
    305             nDrawPath(mNativeCanvasWrapper, path.readOnlyNI(), paint.getNativeInstance());
    306         }
    307     }
    308 
    309     public void drawPoint(float x, float y, @NonNull Paint paint) {
    310         throwIfHasHwBitmapInSwMode(paint);
    311         nDrawPoint(mNativeCanvasWrapper, x, y, paint.getNativeInstance());
    312     }
    313 
    314     public void drawPoints(@Size(multiple = 2) float[] pts, int offset, int count,
    315             @NonNull Paint paint) {
    316         throwIfHasHwBitmapInSwMode(paint);
    317         nDrawPoints(mNativeCanvasWrapper, pts, offset, count, paint.getNativeInstance());
    318     }
    319 
    320     public void drawPoints(@Size(multiple = 2) @NonNull float[] pts, @NonNull Paint paint) {
    321         throwIfHasHwBitmapInSwMode(paint);
    322         drawPoints(pts, 0, pts.length, paint);
    323     }
    324 
    325     @Deprecated
    326     public void drawPosText(@NonNull char[] text, int index, int count,
    327             @NonNull @Size(multiple = 2) float[] pos,
    328             @NonNull Paint paint) {
    329         if (index < 0 || index + count > text.length || count * 2 > pos.length) {
    330             throw new IndexOutOfBoundsException();
    331         }
    332         throwIfHasHwBitmapInSwMode(paint);
    333         for (int i = 0; i < count; i++) {
    334             drawText(text, index + i, 1, pos[i * 2], pos[i * 2 + 1], paint);
    335         }
    336     }
    337 
    338     @Deprecated
    339     public void drawPosText(@NonNull String text, @NonNull @Size(multiple = 2) float[] pos,
    340             @NonNull Paint paint) {
    341         throwIfHasHwBitmapInSwMode(paint);
    342         drawPosText(text.toCharArray(), 0, text.length(), pos, paint);
    343     }
    344 
    345     public void drawRect(float left, float top, float right, float bottom, @NonNull Paint paint) {
    346         throwIfHasHwBitmapInSwMode(paint);
    347         nDrawRect(mNativeCanvasWrapper, left, top, right, bottom, paint.getNativeInstance());
    348     }
    349 
    350     public void drawRect(@NonNull Rect r, @NonNull Paint paint) {
    351         throwIfHasHwBitmapInSwMode(paint);
    352         drawRect(r.left, r.top, r.right, r.bottom, paint);
    353     }
    354 
    355     public void drawRect(@NonNull RectF rect, @NonNull Paint paint) {
    356         throwIfHasHwBitmapInSwMode(paint);
    357         nDrawRect(mNativeCanvasWrapper,
    358                 rect.left, rect.top, rect.right, rect.bottom, paint.getNativeInstance());
    359     }
    360 
    361     public void drawRGB(int r, int g, int b) {
    362         drawColor(Color.rgb(r, g, b));
    363     }
    364 
    365     public void drawRoundRect(float left, float top, float right, float bottom, float rx, float ry,
    366             @NonNull Paint paint) {
    367         throwIfHasHwBitmapInSwMode(paint);
    368         nDrawRoundRect(mNativeCanvasWrapper, left, top, right, bottom, rx, ry,
    369                 paint.getNativeInstance());
    370     }
    371 
    372     public void drawRoundRect(@NonNull RectF rect, float rx, float ry, @NonNull Paint paint) {
    373         throwIfHasHwBitmapInSwMode(paint);
    374         drawRoundRect(rect.left, rect.top, rect.right, rect.bottom, rx, ry, paint);
    375     }
    376 
    377     public void drawText(@NonNull char[] text, int index, int count, float x, float y,
    378             @NonNull Paint paint) {
    379         if ((index | count | (index + count) |
    380                 (text.length - index - count)) < 0) {
    381             throw new IndexOutOfBoundsException();
    382         }
    383         throwIfHasHwBitmapInSwMode(paint);
    384         nDrawText(mNativeCanvasWrapper, text, index, count, x, y, paint.mBidiFlags,
    385                 paint.getNativeInstance());
    386     }
    387 
    388     public void drawText(@NonNull CharSequence text, int start, int end, float x, float y,
    389             @NonNull Paint paint) {
    390         if ((start | end | (end - start) | (text.length() - end)) < 0) {
    391             throw new IndexOutOfBoundsException();
    392         }
    393         throwIfHasHwBitmapInSwMode(paint);
    394         if (text instanceof String || text instanceof SpannedString ||
    395                 text instanceof SpannableString) {
    396             nDrawText(mNativeCanvasWrapper, text.toString(), start, end, x, y,
    397                     paint.mBidiFlags, paint.getNativeInstance());
    398         } else if (text instanceof GraphicsOperations) {
    399             ((GraphicsOperations) text).drawText(this, start, end, x, y,
    400                     paint);
    401         } else {
    402             char[] buf = TemporaryBuffer.obtain(end - start);
    403             TextUtils.getChars(text, start, end, buf, 0);
    404             nDrawText(mNativeCanvasWrapper, buf, 0, end - start, x, y,
    405                     paint.mBidiFlags, paint.getNativeInstance());
    406             TemporaryBuffer.recycle(buf);
    407         }
    408     }
    409 
    410     public void drawText(@NonNull String text, float x, float y, @NonNull Paint paint) {
    411         throwIfHasHwBitmapInSwMode(paint);
    412         nDrawText(mNativeCanvasWrapper, text, 0, text.length(), x, y, paint.mBidiFlags,
    413                 paint.getNativeInstance());
    414     }
    415 
    416     public void drawText(@NonNull String text, int start, int end, float x, float y,
    417             @NonNull Paint paint) {
    418         if ((start | end | (end - start) | (text.length() - end)) < 0) {
    419             throw new IndexOutOfBoundsException();
    420         }
    421         throwIfHasHwBitmapInSwMode(paint);
    422         nDrawText(mNativeCanvasWrapper, text, start, end, x, y, paint.mBidiFlags,
    423                 paint.getNativeInstance());
    424     }
    425 
    426     public void drawTextOnPath(@NonNull char[] text, int index, int count, @NonNull Path path,
    427             float hOffset, float vOffset, @NonNull Paint paint) {
    428         if (index < 0 || index + count > text.length) {
    429             throw new ArrayIndexOutOfBoundsException();
    430         }
    431         throwIfHasHwBitmapInSwMode(paint);
    432         nDrawTextOnPath(mNativeCanvasWrapper, text, index, count,
    433                 path.readOnlyNI(), hOffset, vOffset,
    434                 paint.mBidiFlags, paint.getNativeInstance());
    435     }
    436 
    437     public void drawTextOnPath(@NonNull String text, @NonNull Path path, float hOffset,
    438             float vOffset, @NonNull Paint paint) {
    439         if (text.length() > 0) {
    440             throwIfHasHwBitmapInSwMode(paint);
    441             nDrawTextOnPath(mNativeCanvasWrapper, text, path.readOnlyNI(), hOffset, vOffset,
    442                     paint.mBidiFlags, paint.getNativeInstance());
    443         }
    444     }
    445 
    446     public void drawTextRun(@NonNull char[] text, int index, int count, int contextIndex,
    447             int contextCount, float x, float y, boolean isRtl, @NonNull Paint paint) {
    448 
    449         if (text == null) {
    450             throw new NullPointerException("text is null");
    451         }
    452         if (paint == null) {
    453             throw new NullPointerException("paint is null");
    454         }
    455         if ((index | count | contextIndex | contextCount | index - contextIndex
    456                 | (contextIndex + contextCount) - (index + count)
    457                 | text.length - (contextIndex + contextCount)) < 0) {
    458             throw new IndexOutOfBoundsException();
    459         }
    460 
    461         throwIfHasHwBitmapInSwMode(paint);
    462         nDrawTextRun(mNativeCanvasWrapper, text, index, count, contextIndex, contextCount,
    463                 x, y, isRtl, paint.getNativeInstance(), 0 /* measured text */);
    464     }
    465 
    466     public void drawTextRun(@NonNull CharSequence text, int start, int end, int contextStart,
    467             int contextEnd, float x, float y, boolean isRtl, @NonNull Paint paint) {
    468 
    469         if (text == null) {
    470             throw new NullPointerException("text is null");
    471         }
    472         if (paint == null) {
    473             throw new NullPointerException("paint is null");
    474         }
    475         if ((start | end | contextStart | contextEnd | start - contextStart | end - start
    476                 | contextEnd - end | text.length() - contextEnd) < 0) {
    477             throw new IndexOutOfBoundsException();
    478         }
    479 
    480         throwIfHasHwBitmapInSwMode(paint);
    481         if (text instanceof String || text instanceof SpannedString ||
    482                 text instanceof SpannableString) {
    483             nDrawTextRun(mNativeCanvasWrapper, text.toString(), start, end, contextStart,
    484                     contextEnd, x, y, isRtl, paint.getNativeInstance());
    485         } else if (text instanceof GraphicsOperations) {
    486             ((GraphicsOperations) text).drawTextRun(this, start, end,
    487                     contextStart, contextEnd, x, y, isRtl, paint);
    488         } else {
    489             int contextLen = contextEnd - contextStart;
    490             int len = end - start;
    491             char[] buf = TemporaryBuffer.obtain(contextLen);
    492             TextUtils.getChars(text, contextStart, contextEnd, buf, 0);
    493             long measuredTextPtr = 0;
    494             if (text instanceof PrecomputedText) {
    495                 PrecomputedText mt = (PrecomputedText) text;
    496                 int paraIndex = mt.findParaIndex(start);
    497                 if (end <= mt.getParagraphEnd(paraIndex)) {
    498                     // Only suppor the text in the same paragraph.
    499                     measuredTextPtr = mt.getMeasuredParagraph(paraIndex).getNativePtr();
    500                 }
    501             }
    502             nDrawTextRun(mNativeCanvasWrapper, buf, start - contextStart, len,
    503                     0, contextLen, x, y, isRtl, paint.getNativeInstance(), measuredTextPtr);
    504             TemporaryBuffer.recycle(buf);
    505         }
    506     }
    507 
    508     public void drawVertices(@NonNull VertexMode mode, int vertexCount, @NonNull float[] verts,
    509             int vertOffset, @Nullable float[] texs, int texOffset, @Nullable int[] colors,
    510             int colorOffset, @Nullable short[] indices, int indexOffset, int indexCount,
    511             @NonNull Paint paint) {
    512         checkRange(verts.length, vertOffset, vertexCount);
    513         if (isHardwareAccelerated()) {
    514             return;
    515         }
    516         if (texs != null) {
    517             checkRange(texs.length, texOffset, vertexCount);
    518         }
    519         if (colors != null) {
    520             checkRange(colors.length, colorOffset, vertexCount / 2);
    521         }
    522         if (indices != null) {
    523             checkRange(indices.length, indexOffset, indexCount);
    524         }
    525         throwIfHasHwBitmapInSwMode(paint);
    526         nDrawVertices(mNativeCanvasWrapper, mode.nativeInt, vertexCount, verts,
    527                 vertOffset, texs, texOffset, colors, colorOffset,
    528                 indices, indexOffset, indexCount, paint.getNativeInstance());
    529     }
    530 
    531     /**
    532      * @hide
    533      */
    534     public void setHwBitmapsInSwModeEnabled(boolean enabled) {
    535         mAllowHwBitmapsInSwMode = enabled;
    536     }
    537 
    538     /**
    539      * @hide
    540      */
    541     public boolean isHwBitmapsInSwModeEnabled() {
    542         return mAllowHwBitmapsInSwMode;
    543     }
    544 
    545     /**
    546      * @hide
    547      */
    548     protected void onHwBitmapInSwMode() {
    549         if (!mAllowHwBitmapsInSwMode) {
    550             throw new IllegalArgumentException(
    551                     "Software rendering doesn't support hardware bitmaps");
    552         }
    553     }
    554 
    555     private void throwIfHwBitmapInSwMode(Bitmap bitmap) {
    556         if (!isHardwareAccelerated() && bitmap.getConfig() == Bitmap.Config.HARDWARE) {
    557             onHwBitmapInSwMode();
    558         }
    559     }
    560 
    561     private void throwIfHasHwBitmapInSwMode(Paint p) {
    562         if (isHardwareAccelerated() || p == null) {
    563             return;
    564         }
    565         throwIfHasHwBitmapInSwMode(p.getShader());
    566     }
    567 
    568     private void throwIfHasHwBitmapInSwMode(Shader shader) {
    569         if (shader == null) {
    570             return;
    571         }
    572         if (shader instanceof BitmapShader) {
    573             throwIfHwBitmapInSwMode(((BitmapShader) shader).mBitmap);
    574         }
    575         if (shader instanceof ComposeShader) {
    576             throwIfHasHwBitmapInSwMode(((ComposeShader) shader).mShaderA);
    577             throwIfHasHwBitmapInSwMode(((ComposeShader) shader).mShaderB);
    578         }
    579     }
    580 
    581     private static native void nDrawBitmap(long nativeCanvas, Bitmap bitmap, float left, float top,
    582             long nativePaintOrZero, int canvasDensity, int screenDensity, int bitmapDensity);
    583 
    584     private static native void nDrawBitmap(long nativeCanvas, Bitmap bitmap, float srcLeft,
    585             float srcTop,
    586             float srcRight, float srcBottom, float dstLeft, float dstTop, float dstRight,
    587             float dstBottom, long nativePaintOrZero, int screenDensity, int bitmapDensity);
    588 
    589     private static native void nDrawBitmap(long nativeCanvas, int[] colors, int offset, int stride,
    590             float x, float y, int width, int height, boolean hasAlpha, long nativePaintOrZero);
    591 
    592     private static native void nDrawColor(long nativeCanvas, int color, int mode);
    593 
    594     private static native void nDrawPaint(long nativeCanvas, long nativePaint);
    595 
    596     private static native void nDrawPoint(long canvasHandle, float x, float y, long paintHandle);
    597 
    598     private static native void nDrawPoints(long canvasHandle, float[] pts, int offset, int count,
    599             long paintHandle);
    600 
    601     private static native void nDrawLine(long nativeCanvas, float startX, float startY, float stopX,
    602             float stopY, long nativePaint);
    603 
    604     private static native void nDrawLines(long canvasHandle, float[] pts, int offset, int count,
    605             long paintHandle);
    606 
    607     private static native void nDrawRect(long nativeCanvas, float left, float top, float right,
    608             float bottom, long nativePaint);
    609 
    610     private static native void nDrawOval(long nativeCanvas, float left, float top, float right,
    611             float bottom, long nativePaint);
    612 
    613     private static native void nDrawCircle(long nativeCanvas, float cx, float cy, float radius,
    614             long nativePaint);
    615 
    616     private static native void nDrawArc(long nativeCanvas, float left, float top, float right,
    617             float bottom, float startAngle, float sweep, boolean useCenter, long nativePaint);
    618 
    619     private static native void nDrawRoundRect(long nativeCanvas, float left, float top, float right,
    620             float bottom, float rx, float ry, long nativePaint);
    621 
    622     private static native void nDrawPath(long nativeCanvas, long nativePath, long nativePaint);
    623 
    624     private static native void nDrawRegion(long nativeCanvas, long nativeRegion, long nativePaint);
    625 
    626     private static native void nDrawNinePatch(long nativeCanvas, long nativeBitmap, long ninePatch,
    627             float dstLeft, float dstTop, float dstRight, float dstBottom, long nativePaintOrZero,
    628             int screenDensity, int bitmapDensity);
    629 
    630     private static native void nDrawBitmapMatrix(long nativeCanvas, Bitmap bitmap,
    631             long nativeMatrix, long nativePaint);
    632 
    633     private static native void nDrawBitmapMesh(long nativeCanvas, Bitmap bitmap, int meshWidth,
    634             int meshHeight, float[] verts, int vertOffset, int[] colors, int colorOffset,
    635             long nativePaint);
    636 
    637     private static native void nDrawVertices(long nativeCanvas, int mode, int n, float[] verts,
    638             int vertOffset, float[] texs, int texOffset, int[] colors, int colorOffset,
    639             short[] indices, int indexOffset, int indexCount, long nativePaint);
    640 
    641     private static native void nDrawText(long nativeCanvas, char[] text, int index, int count,
    642             float x, float y, int flags, long nativePaint);
    643 
    644     private static native void nDrawText(long nativeCanvas, String text, int start, int end,
    645             float x, float y, int flags, long nativePaint);
    646 
    647     private static native void nDrawTextRun(long nativeCanvas, String text, int start, int end,
    648             int contextStart, int contextEnd, float x, float y, boolean isRtl, long nativePaint);
    649 
    650     private static native void nDrawTextRun(long nativeCanvas, char[] text, int start, int count,
    651             int contextStart, int contextCount, float x, float y, boolean isRtl, long nativePaint,
    652             long nativePrecomputedText);
    653 
    654     private static native void nDrawTextOnPath(long nativeCanvas, char[] text, int index, int count,
    655             long nativePath, float hOffset, float vOffset, int bidiFlags, long nativePaint);
    656 
    657     private static native void nDrawTextOnPath(long nativeCanvas, String text, long nativePath,
    658             float hOffset, float vOffset, int flags, long nativePaint);
    659 }
    660