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