Home | History | Annotate | Download | only in jni
      1 /*
      2  * Copyright (C) 2014 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 #include "jni.h"
     18 #include "GraphicsJNI.h"
     19 #include "core_jni_helpers.h"
     20 
     21 #include <android/api-level.h>
     22 #include <androidfw/ResourceTypes.h>
     23 #include <hwui/Canvas.h>
     24 #include <hwui/Paint.h>
     25 #include <hwui/Typeface.h>
     26 #include <minikin/Layout.h>
     27 
     28 #include "Bitmap.h"
     29 #include "SkDrawFilter.h"
     30 #include "SkGraphics.h"
     31 #include "SkRegion.h"
     32 #include "SkVertices.h"
     33 
     34 namespace minikin {
     35 class MeasuredText;
     36 }  // namespace minikin
     37 
     38 namespace android {
     39 
     40 namespace CanvasJNI {
     41 
     42 static Canvas* get_canvas(jlong canvasHandle) {
     43     return reinterpret_cast<Canvas*>(canvasHandle);
     44 }
     45 
     46 static void delete_canvas(Canvas* canvas) {
     47     delete canvas;
     48 }
     49 
     50 static jlong getNativeFinalizer(JNIEnv* env, jobject clazz) {
     51     return static_cast<jlong>(reinterpret_cast<uintptr_t>(&delete_canvas));
     52 }
     53 
     54 // Native wrapper constructor used by Canvas(Bitmap)
     55 static jlong initRaster(JNIEnv* env, jobject, jobject jbitmap) {
     56     SkBitmap bitmap;
     57     if (jbitmap != NULL) {
     58         GraphicsJNI::getSkBitmap(env, jbitmap, &bitmap);
     59     }
     60     return reinterpret_cast<jlong>(Canvas::create_canvas(bitmap));
     61 }
     62 
     63 // Set the given bitmap as the new draw target (wrapped in a new SkCanvas),
     64 // optionally copying canvas matrix & clip state.
     65 static void setBitmap(JNIEnv* env, jobject, jlong canvasHandle, jobject jbitmap) {
     66     SkBitmap bitmap;
     67     if (jbitmap != NULL) {
     68         GraphicsJNI::getSkBitmap(env, jbitmap, &bitmap);
     69     }
     70     get_canvas(canvasHandle)->setBitmap(bitmap);
     71 }
     72 
     73 static jboolean isOpaque(jlong canvasHandle) {
     74     return get_canvas(canvasHandle)->isOpaque() ? JNI_TRUE : JNI_FALSE;
     75 }
     76 
     77 static jint getWidth(jlong canvasHandle) {
     78     return static_cast<jint>(get_canvas(canvasHandle)->width());
     79 }
     80 
     81 static jint getHeight(jlong canvasHandle) {
     82     return static_cast<jint>(get_canvas(canvasHandle)->height());
     83 }
     84 
     85 static jint save(jlong canvasHandle, jint flagsHandle) {
     86     SaveFlags::Flags flags = static_cast<SaveFlags::Flags>(flagsHandle);
     87     return static_cast<jint>(get_canvas(canvasHandle)->save(flags));
     88 }
     89 
     90 static jint saveLayer(jlong canvasHandle, jfloat l, jfloat t,
     91                       jfloat r, jfloat b, jlong paintHandle, jint flagsHandle) {
     92     Paint* paint  = reinterpret_cast<Paint*>(paintHandle);
     93     SaveFlags::Flags flags = static_cast<SaveFlags::Flags>(flagsHandle);
     94     return static_cast<jint>(get_canvas(canvasHandle)->saveLayer(l, t, r, b, paint, flags));
     95 }
     96 
     97 static jint saveLayerAlpha(jlong canvasHandle, jfloat l, jfloat t,
     98                            jfloat r, jfloat b, jint alpha, jint flagsHandle) {
     99     SaveFlags::Flags flags = static_cast<SaveFlags::Flags>(flagsHandle);
    100     return static_cast<jint>(get_canvas(canvasHandle)->saveLayerAlpha(l, t, r, b, alpha, flags));
    101 }
    102 
    103 static bool restore(jlong canvasHandle) {
    104     Canvas* canvas = get_canvas(canvasHandle);
    105     if (canvas->getSaveCount() <= 1) {
    106         return false; // cannot restore anymore
    107     }
    108     canvas->restore();
    109     return true; // success
    110 }
    111 
    112 static void restoreToCount(jlong canvasHandle, jint saveCount) {
    113     Canvas* canvas = get_canvas(canvasHandle);
    114     canvas->restoreToCount(saveCount);
    115 }
    116 
    117 static jint getSaveCount(jlong canvasHandle) {
    118     return static_cast<jint>(get_canvas(canvasHandle)->getSaveCount());
    119 }
    120 
    121 static void getMatrix(jlong canvasHandle, jlong matrixHandle) {
    122     SkMatrix* matrix = reinterpret_cast<SkMatrix*>(matrixHandle);
    123     get_canvas(canvasHandle)->getMatrix(matrix);
    124 }
    125 
    126 static void setMatrix(jlong canvasHandle, jlong matrixHandle) {
    127     const SkMatrix* matrix = reinterpret_cast<SkMatrix*>(matrixHandle);
    128     get_canvas(canvasHandle)->setMatrix(matrix ? *matrix : SkMatrix::I());
    129 }
    130 
    131 static void concat(jlong canvasHandle, jlong matrixHandle) {
    132     const SkMatrix* matrix = reinterpret_cast<SkMatrix*>(matrixHandle);
    133     get_canvas(canvasHandle)->concat(*matrix);
    134 }
    135 
    136 static void rotate(jlong canvasHandle, jfloat degrees) {
    137     get_canvas(canvasHandle)->rotate(degrees);
    138 }
    139 
    140 static void scale(jlong canvasHandle, jfloat sx, jfloat sy) {
    141     get_canvas(canvasHandle)->scale(sx, sy);
    142 }
    143 
    144 static void skew(jlong canvasHandle, jfloat sx, jfloat sy) {
    145     get_canvas(canvasHandle)->skew(sx, sy);
    146 }
    147 
    148 static void translate(jlong canvasHandle, jfloat dx, jfloat dy) {
    149     get_canvas(canvasHandle)->translate(dx, dy);
    150 }
    151 
    152 static jboolean getClipBounds(JNIEnv* env, jobject, jlong canvasHandle, jobject bounds) {
    153     SkRect   r;
    154     SkIRect ir;
    155     bool result = get_canvas(canvasHandle)->getClipBounds(&r);
    156 
    157     if (!result) {
    158         r.setEmpty();
    159     }
    160     r.round(&ir);
    161 
    162     (void)GraphicsJNI::irect_to_jrect(ir, env, bounds);
    163     return result ? JNI_TRUE : JNI_FALSE;
    164 }
    165 
    166 static jboolean quickRejectRect(jlong canvasHandle,
    167                                 jfloat left, jfloat top, jfloat right, jfloat bottom) {
    168     bool result = get_canvas(canvasHandle)->quickRejectRect(left, top, right, bottom);
    169     return result ? JNI_TRUE : JNI_FALSE;
    170 }
    171 
    172 static jboolean quickRejectPath(jlong canvasHandle, jlong pathHandle) {
    173     SkPath* path = reinterpret_cast<SkPath*>(pathHandle);
    174     bool result = get_canvas(canvasHandle)->quickRejectPath(*path);
    175     return result ? JNI_TRUE : JNI_FALSE;
    176 }
    177 
    178 // SkRegion::Op and SkClipOp are numerically identical, so we can freely cast
    179 // from one to the other (though SkClipOp is destined to become a strict subset)
    180 static_assert(SkRegion::kDifference_Op == static_cast<SkRegion::Op>(SkClipOp::kDifference), "");
    181 static_assert(SkRegion::kIntersect_Op == static_cast<SkRegion::Op>(SkClipOp::kIntersect), "");
    182 static_assert(SkRegion::kUnion_Op == static_cast<SkRegion::Op>(SkClipOp::kUnion_deprecated), "");
    183 static_assert(SkRegion::kXOR_Op == static_cast<SkRegion::Op>(SkClipOp::kXOR_deprecated), "");
    184 static_assert(SkRegion::kReverseDifference_Op == static_cast<SkRegion::Op>(SkClipOp::kReverseDifference_deprecated), "");
    185 static_assert(SkRegion::kReplace_Op == static_cast<SkRegion::Op>(SkClipOp::kReplace_deprecated), "");
    186 
    187 static SkClipOp opHandleToClipOp(jint opHandle) {
    188     // The opHandle is defined in Canvas.java to be Region::Op
    189     SkRegion::Op rgnOp = static_cast<SkRegion::Op>(opHandle);
    190 
    191     // In the future, when we no longer support the wide range of ops (e.g. Union, Xor)
    192     // this function can perform a range check and throw an unsupported-exception.
    193     // e.g. if (rgnOp != kIntersect && rgnOp != kDifference) throw...
    194 
    195     // Skia now takes a different type, SkClipOp, as the parameter to clipping calls
    196     // This type is binary compatible with SkRegion::Op, so a static_cast<> is safe.
    197     return static_cast<SkClipOp>(rgnOp);
    198 }
    199 
    200 static jboolean clipRect(jlong canvasHandle, jfloat l, jfloat t,
    201                          jfloat r, jfloat b, jint opHandle) {
    202     bool nonEmptyClip = get_canvas(canvasHandle)->clipRect(l, t, r, b,
    203             opHandleToClipOp(opHandle));
    204     return nonEmptyClip ? JNI_TRUE : JNI_FALSE;
    205 }
    206 
    207 static jboolean clipPath(jlong canvasHandle, jlong pathHandle,
    208                          jint opHandle) {
    209     SkPath* path = reinterpret_cast<SkPath*>(pathHandle);
    210     bool nonEmptyClip = get_canvas(canvasHandle)->clipPath(path, opHandleToClipOp(opHandle));
    211     return nonEmptyClip ? JNI_TRUE : JNI_FALSE;
    212 }
    213 
    214 static void drawColor(JNIEnv* env, jobject, jlong canvasHandle, jint color, jint modeHandle) {
    215     SkBlendMode mode = static_cast<SkBlendMode>(modeHandle);
    216     get_canvas(canvasHandle)->drawColor(color, mode);
    217 }
    218 
    219 static void drawPaint(JNIEnv* env, jobject, jlong canvasHandle, jlong paintHandle) {
    220     Paint* paint = reinterpret_cast<Paint*>(paintHandle);
    221     get_canvas(canvasHandle)->drawPaint(*paint);
    222 }
    223 
    224 static void drawPoint(JNIEnv*, jobject, jlong canvasHandle, jfloat x, jfloat y,
    225                       jlong paintHandle) {
    226     const Paint* paint = reinterpret_cast<Paint*>(paintHandle);
    227     get_canvas(canvasHandle)->drawPoint(x, y, *paint);
    228 }
    229 
    230 static void drawPoints(JNIEnv* env, jobject, jlong canvasHandle, jfloatArray jptsArray,
    231                        jint offset, jint count, jlong paintHandle) {
    232     NPE_CHECK_RETURN_VOID(env, jptsArray);
    233     AutoJavaFloatArray autoPts(env, jptsArray);
    234     float* floats = autoPts.ptr();
    235     const int length = autoPts.length();
    236 
    237     if ((offset | count) < 0 || offset + count > length) {
    238         doThrowAIOOBE(env);
    239         return;
    240     }
    241 
    242     const Paint* paint = reinterpret_cast<Paint*>(paintHandle);
    243     get_canvas(canvasHandle)->drawPoints(floats + offset, count, *paint);
    244 }
    245 
    246 static void drawLine(JNIEnv* env, jobject, jlong canvasHandle, jfloat startX, jfloat startY,
    247                      jfloat stopX, jfloat stopY, jlong paintHandle) {
    248     Paint* paint = reinterpret_cast<Paint*>(paintHandle);
    249     get_canvas(canvasHandle)->drawLine(startX, startY, stopX, stopY, *paint);
    250 }
    251 
    252 static void drawLines(JNIEnv* env, jobject, jlong canvasHandle, jfloatArray jptsArray,
    253                       jint offset, jint count, jlong paintHandle) {
    254     NPE_CHECK_RETURN_VOID(env, jptsArray);
    255     AutoJavaFloatArray autoPts(env, jptsArray);
    256     float* floats = autoPts.ptr();
    257     const int length = autoPts.length();
    258 
    259     if ((offset | count) < 0 || offset + count > length) {
    260         doThrowAIOOBE(env);
    261         return;
    262     }
    263 
    264     const Paint* paint = reinterpret_cast<Paint*>(paintHandle);
    265     get_canvas(canvasHandle)->drawLines(floats + offset, count, *paint);
    266 }
    267 
    268 static void drawRect(JNIEnv* env, jobject, jlong canvasHandle, jfloat left, jfloat top,
    269                      jfloat right, jfloat bottom, jlong paintHandle) {
    270     const Paint* paint = reinterpret_cast<Paint*>(paintHandle);
    271     get_canvas(canvasHandle)->drawRect(left, top, right, bottom, *paint);
    272 }
    273 
    274 static void drawRegion(JNIEnv* env, jobject, jlong canvasHandle, jlong regionHandle,
    275                        jlong paintHandle) {
    276     const SkRegion* region = reinterpret_cast<SkRegion*>(regionHandle);
    277     const Paint* paint = reinterpret_cast<Paint*>(paintHandle);
    278     get_canvas(canvasHandle)->drawRegion(*region, *paint);
    279 }
    280 
    281 static void drawRoundRect(JNIEnv* env, jobject, jlong canvasHandle, jfloat left, jfloat top,
    282                           jfloat right, jfloat bottom, jfloat rx, jfloat ry, jlong paintHandle) {
    283     const Paint* paint = reinterpret_cast<Paint*>(paintHandle);
    284     get_canvas(canvasHandle)->drawRoundRect(left, top, right, bottom, rx, ry, *paint);
    285 }
    286 
    287 static void drawCircle(JNIEnv* env, jobject, jlong canvasHandle, jfloat cx, jfloat cy,
    288                        jfloat radius, jlong paintHandle) {
    289     const Paint* paint = reinterpret_cast<Paint*>(paintHandle);
    290     get_canvas(canvasHandle)->drawCircle(cx, cy, radius, *paint);
    291 }
    292 
    293 static void drawOval(JNIEnv* env, jobject, jlong canvasHandle, jfloat left, jfloat top,
    294                      jfloat right, jfloat bottom, jlong paintHandle) {
    295     const Paint* paint = reinterpret_cast<Paint*>(paintHandle);
    296     get_canvas(canvasHandle)->drawOval(left, top, right, bottom, *paint);
    297 }
    298 
    299 static void drawArc(JNIEnv* env, jobject, jlong canvasHandle, jfloat left, jfloat top,
    300                     jfloat right, jfloat bottom, jfloat startAngle, jfloat sweepAngle,
    301                     jboolean useCenter, jlong paintHandle) {
    302     const Paint* paint = reinterpret_cast<Paint*>(paintHandle);
    303     get_canvas(canvasHandle)->drawArc(left, top, right, bottom, startAngle, sweepAngle,
    304                                        useCenter, *paint);
    305 }
    306 
    307 static void drawPath(JNIEnv* env, jobject, jlong canvasHandle, jlong pathHandle,
    308                      jlong paintHandle) {
    309     const SkPath* path = reinterpret_cast<SkPath*>(pathHandle);
    310     const Paint* paint = reinterpret_cast<Paint*>(paintHandle);
    311     get_canvas(canvasHandle)->drawPath(*path, *paint);
    312 }
    313 
    314 static void drawVertices(JNIEnv* env, jobject, jlong canvasHandle,
    315                          jint modeHandle, jint floatCount,
    316                          jfloatArray jverts, jint vertIndex,
    317                          jfloatArray jtexs, jint texIndex,
    318                          jintArray jcolors, jint colorIndex,
    319                          jshortArray jindices, jint indexIndex,
    320                          jint indexCount, jlong paintHandle) {
    321     AutoJavaFloatArray  vertA(env, jverts, vertIndex + floatCount);
    322     AutoJavaFloatArray  texA(env, jtexs, texIndex + floatCount);
    323     AutoJavaIntArray    colorA(env, jcolors, colorIndex + floatCount);
    324     AutoJavaShortArray  indexA(env, jindices, indexIndex + indexCount);
    325 
    326     const float* verts = vertA.ptr() + vertIndex;
    327     const float* texs = texA.ptr() + vertIndex;
    328     const int* colors = NULL;
    329     const uint16_t* indices = NULL;
    330 
    331     if (jcolors != NULL) {
    332         colors = colorA.ptr() + colorIndex;
    333     }
    334     if (jindices != NULL) {
    335         indices = (const uint16_t*)(indexA.ptr() + indexIndex);
    336     }
    337 
    338     int vertexCount = floatCount >> 1;  // 2 floats per SkPoint
    339     SkVertices::VertexMode mode = static_cast<SkVertices::VertexMode>(modeHandle);
    340     const Paint* paint = reinterpret_cast<Paint*>(paintHandle);
    341     get_canvas(canvasHandle)->drawVertices(SkVertices::MakeCopy(mode, vertexCount,
    342                                            reinterpret_cast<const SkPoint*>(verts),
    343                                            reinterpret_cast<const SkPoint*>(texs),
    344                                            reinterpret_cast<const SkColor*>(colors),
    345                                            indexCount, indices).get(),
    346                                            SkBlendMode::kModulate, *paint);
    347 }
    348 
    349 static void drawNinePatch(JNIEnv* env, jobject, jlong canvasHandle, jlong bitmapHandle,
    350         jlong chunkHandle, jfloat left, jfloat top, jfloat right, jfloat bottom,
    351         jlong paintHandle, jint dstDensity, jint srcDensity) {
    352 
    353     Canvas* canvas = get_canvas(canvasHandle);
    354     Bitmap& bitmap = android::bitmap::toBitmap(env, bitmapHandle);
    355     const android::Res_png_9patch* chunk = reinterpret_cast<android::Res_png_9patch*>(chunkHandle);
    356     const Paint* paint = reinterpret_cast<Paint*>(paintHandle);
    357 
    358     if (CC_LIKELY(dstDensity == srcDensity || dstDensity == 0 || srcDensity == 0)) {
    359         canvas->drawNinePatch(bitmap, *chunk, left, top, right, bottom, paint);
    360     } else {
    361         canvas->save(SaveFlags::MatrixClip);
    362 
    363         SkScalar scale = dstDensity / (float)srcDensity;
    364         canvas->translate(left, top);
    365         canvas->scale(scale, scale);
    366 
    367         Paint filteredPaint;
    368         if (paint) {
    369             filteredPaint = *paint;
    370         }
    371         filteredPaint.setFilterQuality(kLow_SkFilterQuality);
    372 
    373         canvas->drawNinePatch(bitmap, *chunk, 0, 0, (right-left)/scale, (bottom-top)/scale,
    374                 &filteredPaint);
    375 
    376         canvas->restore();
    377     }
    378 }
    379 
    380 static void drawBitmap(JNIEnv* env, jobject, jlong canvasHandle, jobject jbitmap,
    381                        jfloat left, jfloat top, jlong paintHandle, jint canvasDensity,
    382                        jint screenDensity, jint bitmapDensity) {
    383     Canvas* canvas = get_canvas(canvasHandle);
    384     Bitmap& bitmap = android::bitmap::toBitmap(env, jbitmap);
    385     const Paint* paint = reinterpret_cast<Paint*>(paintHandle);
    386 
    387     if (canvasDensity == bitmapDensity || canvasDensity == 0 || bitmapDensity == 0) {
    388         if (screenDensity != 0 && screenDensity != bitmapDensity) {
    389             Paint filteredPaint;
    390             if (paint) {
    391                 filteredPaint = *paint;
    392             }
    393             filteredPaint.setFilterQuality(kLow_SkFilterQuality);
    394             canvas->drawBitmap(bitmap, left, top, &filteredPaint);
    395         } else {
    396             canvas->drawBitmap(bitmap, left, top, paint);
    397         }
    398     } else {
    399         canvas->save(SaveFlags::MatrixClip);
    400         SkScalar scale = canvasDensity / (float)bitmapDensity;
    401         canvas->translate(left, top);
    402         canvas->scale(scale, scale);
    403 
    404         Paint filteredPaint;
    405         if (paint) {
    406             filteredPaint = *paint;
    407         }
    408         filteredPaint.setFilterQuality(kLow_SkFilterQuality);
    409 
    410         canvas->drawBitmap(bitmap, 0, 0, &filteredPaint);
    411         canvas->restore();
    412     }
    413 }
    414 
    415 static void drawBitmapMatrix(JNIEnv* env, jobject, jlong canvasHandle, jobject jbitmap,
    416                              jlong matrixHandle, jlong paintHandle) {
    417     const SkMatrix* matrix = reinterpret_cast<SkMatrix*>(matrixHandle);
    418     const Paint* paint = reinterpret_cast<Paint*>(paintHandle);
    419     Bitmap& bitmap = android::bitmap::toBitmap(env, jbitmap);
    420     get_canvas(canvasHandle)->drawBitmap(bitmap, *matrix, paint);
    421 }
    422 
    423 static void drawBitmapRect(JNIEnv* env, jobject, jlong canvasHandle, jobject jbitmap,
    424                            float srcLeft, float srcTop, float srcRight, float srcBottom,
    425                            float dstLeft, float dstTop, float dstRight, float dstBottom,
    426                            jlong paintHandle, jint screenDensity, jint bitmapDensity) {
    427     Canvas* canvas = get_canvas(canvasHandle);
    428     const Paint* paint = reinterpret_cast<Paint*>(paintHandle);
    429 
    430     Bitmap& bitmap = android::bitmap::toBitmap(env, jbitmap);
    431     if (screenDensity != 0 && screenDensity != bitmapDensity) {
    432         Paint filteredPaint;
    433         if (paint) {
    434             filteredPaint = *paint;
    435         }
    436         filteredPaint.setFilterQuality(kLow_SkFilterQuality);
    437         canvas->drawBitmap(bitmap, srcLeft, srcTop, srcRight, srcBottom,
    438                            dstLeft, dstTop, dstRight, dstBottom, &filteredPaint);
    439     } else {
    440         canvas->drawBitmap(bitmap, srcLeft, srcTop, srcRight, srcBottom,
    441                            dstLeft, dstTop, dstRight, dstBottom, paint);
    442     }
    443 }
    444 
    445 static void drawBitmapArray(JNIEnv* env, jobject, jlong canvasHandle,
    446                             jintArray jcolors, jint offset, jint stride,
    447                             jfloat x, jfloat y, jint width, jint height,
    448                             jboolean hasAlpha, jlong paintHandle) {
    449     // Note: If hasAlpha is false, kRGB_565_SkColorType will be used, which will
    450     // correct the alphaType to kOpaque_SkAlphaType.
    451     SkImageInfo info = SkImageInfo::Make(width, height,
    452                            hasAlpha ? kN32_SkColorType : kRGB_565_SkColorType,
    453                            kPremul_SkAlphaType);
    454     SkBitmap bitmap;
    455     bitmap.setInfo(info);
    456     sk_sp<Bitmap> androidBitmap = Bitmap::allocateHeapBitmap(&bitmap);
    457     if (!androidBitmap) {
    458         return;
    459     }
    460 
    461     if (!GraphicsJNI::SetPixels(env, jcolors, offset, stride, 0, 0, width, height, bitmap)) {
    462         return;
    463     }
    464 
    465     const Paint* paint = reinterpret_cast<Paint*>(paintHandle);
    466     get_canvas(canvasHandle)->drawBitmap(*androidBitmap, x, y, paint);
    467 }
    468 
    469 static void drawBitmapMesh(JNIEnv* env, jobject, jlong canvasHandle, jobject jbitmap,
    470                            jint meshWidth, jint meshHeight, jfloatArray jverts,
    471                            jint vertIndex, jintArray jcolors, jint colorIndex, jlong paintHandle) {
    472     if (Canvas::GetApiLevel() < __ANDROID_API_P__) {
    473         // Before P we forgot to respect these. Now that we do respect them, explicitly
    474         // zero them for backward compatibility.
    475         vertIndex = 0;
    476         colorIndex = 0;
    477     }
    478 
    479     const int ptCount = (meshWidth + 1) * (meshHeight + 1);
    480     AutoJavaFloatArray vertA(env, jverts, vertIndex + (ptCount << 1));
    481     AutoJavaIntArray colorA(env, jcolors, colorIndex + ptCount);
    482 
    483     const Paint* paint = reinterpret_cast<Paint*>(paintHandle);
    484     Bitmap& bitmap = android::bitmap::toBitmap(env, jbitmap);
    485     get_canvas(canvasHandle)->drawBitmapMesh(bitmap, meshWidth, meshHeight,
    486                                              vertA.ptr() + vertIndex*2,
    487                                              colorA.ptr() + colorIndex, paint);
    488 }
    489 
    490 static void drawTextChars(JNIEnv* env, jobject, jlong canvasHandle, jcharArray text,
    491                           jint index, jint count, jfloat x, jfloat y, jint bidiFlags,
    492                           jlong paintHandle) {
    493     Paint* paint = reinterpret_cast<Paint*>(paintHandle);
    494     const Typeface* typeface = paint->getAndroidTypeface();
    495     jchar* jchars = env->GetCharArrayElements(text, NULL);
    496     get_canvas(canvasHandle)->drawText(jchars + index, 0, count, count, x, y,
    497             static_cast<minikin::Bidi>(bidiFlags), *paint, typeface, nullptr);
    498     env->ReleaseCharArrayElements(text, jchars, JNI_ABORT);
    499 }
    500 
    501 static void drawTextString(JNIEnv* env, jobject, jlong canvasHandle, jstring text,
    502                            jint start, jint end, jfloat x, jfloat y, jint bidiFlags,
    503                            jlong paintHandle) {
    504     Paint* paint = reinterpret_cast<Paint*>(paintHandle);
    505     const Typeface* typeface = paint->getAndroidTypeface();
    506     const int count = end - start;
    507     const jchar* jchars = env->GetStringChars(text, NULL);
    508     get_canvas(canvasHandle)->drawText(jchars + start, 0, count, count, x, y,
    509             static_cast<minikin::Bidi>(bidiFlags), *paint, typeface, nullptr);
    510     env->ReleaseStringChars(text, jchars);
    511 }
    512 
    513 static void drawTextRunChars(JNIEnv* env, jobject, jlong canvasHandle, jcharArray text, jint index,
    514                              jint count, jint contextIndex, jint contextCount, jfloat x, jfloat y,
    515                              jboolean isRtl, jlong paintHandle, jlong mtHandle) {
    516     Paint* paint = reinterpret_cast<Paint*>(paintHandle);
    517     minikin::MeasuredText* mt = reinterpret_cast<minikin::MeasuredText*>(mtHandle);
    518     const Typeface* typeface = paint->getAndroidTypeface();
    519 
    520     const minikin::Bidi bidiFlags = isRtl ? minikin::Bidi::FORCE_RTL : minikin::Bidi::FORCE_LTR;
    521     jchar* jchars = env->GetCharArrayElements(text, NULL);
    522     get_canvas(canvasHandle)->drawText(jchars + contextIndex, index - contextIndex, count,
    523                                        contextCount, x, y, bidiFlags, *paint, typeface, mt);
    524     env->ReleaseCharArrayElements(text, jchars, JNI_ABORT);
    525 }
    526 
    527 static void drawTextRunString(JNIEnv* env, jobject obj, jlong canvasHandle, jstring text,
    528                               jint start, jint end, jint contextStart, jint contextEnd,
    529                               jfloat x, jfloat y, jboolean isRtl, jlong paintHandle) {
    530     Paint* paint = reinterpret_cast<Paint*>(paintHandle);
    531     const Typeface* typeface = paint->getAndroidTypeface();
    532 
    533     const minikin::Bidi bidiFlags = isRtl ? minikin::Bidi::FORCE_RTL : minikin::Bidi::FORCE_LTR;
    534     jint count = end - start;
    535     jint contextCount = contextEnd - contextStart;
    536     const jchar* jchars = env->GetStringChars(text, NULL);
    537     get_canvas(canvasHandle)->drawText(jchars + contextStart, start - contextStart, count,
    538                                        contextCount, x, y, bidiFlags, *paint, typeface, nullptr);
    539     env->ReleaseStringChars(text, jchars);
    540 }
    541 
    542 static void drawTextOnPathChars(JNIEnv* env, jobject, jlong canvasHandle, jcharArray text,
    543                                 jint index, jint count, jlong pathHandle, jfloat hOffset,
    544                                 jfloat vOffset, jint bidiFlags, jlong paintHandle) {
    545     SkPath* path = reinterpret_cast<SkPath*>(pathHandle);
    546     Paint* paint = reinterpret_cast<Paint*>(paintHandle);
    547     const Typeface* typeface = paint->getAndroidTypeface();
    548 
    549     jchar* jchars = env->GetCharArrayElements(text, NULL);
    550 
    551     get_canvas(canvasHandle)->drawTextOnPath(jchars + index, count,
    552             static_cast<minikin::Bidi>(bidiFlags), *path, hOffset, vOffset, *paint, typeface);
    553 
    554     env->ReleaseCharArrayElements(text, jchars, 0);
    555 }
    556 
    557 static void drawTextOnPathString(JNIEnv* env, jobject, jlong canvasHandle, jstring text,
    558                                  jlong pathHandle, jfloat hOffset, jfloat vOffset,
    559                                  jint bidiFlags, jlong paintHandle) {
    560     SkPath* path = reinterpret_cast<SkPath*>(pathHandle);
    561     Paint* paint = reinterpret_cast<Paint*>(paintHandle);
    562     const Typeface* typeface = paint->getAndroidTypeface();
    563 
    564     const jchar* jchars = env->GetStringChars(text, NULL);
    565     int count = env->GetStringLength(text);
    566 
    567     get_canvas(canvasHandle)->drawTextOnPath(jchars, count, static_cast<minikin::Bidi>(bidiFlags),
    568             *path, hOffset, vOffset, *paint, typeface);
    569 
    570     env->ReleaseStringChars(text, jchars);
    571 }
    572 
    573 static void setDrawFilter(jlong canvasHandle, jlong filterHandle) {
    574     get_canvas(canvasHandle)->setDrawFilter(reinterpret_cast<SkDrawFilter*>(filterHandle));
    575 }
    576 
    577 static void freeCaches(JNIEnv* env, jobject) {
    578     SkGraphics::PurgeFontCache();
    579 }
    580 
    581 static void freeTextLayoutCaches(JNIEnv* env, jobject) {
    582     minikin::Layout::purgeCaches();
    583 }
    584 
    585 static void setCompatibilityVersion(JNIEnv* env, jobject, jint apiLevel) {
    586     Canvas::setCompatibilityVersion(apiLevel);
    587 }
    588 
    589 
    590 }; // namespace CanvasJNI
    591 
    592 static const JNINativeMethod gMethods[] = {
    593     {"nGetNativeFinalizer", "()J", (void*) CanvasJNI::getNativeFinalizer},
    594     {"nInitRaster", "(Landroid/graphics/Bitmap;)J", (void*) CanvasJNI::initRaster},
    595     {"nFreeCaches", "()V", (void*) CanvasJNI::freeCaches},
    596     {"nFreeTextLayoutCaches", "()V", (void*) CanvasJNI::freeTextLayoutCaches},
    597     {"nSetCompatibilityVersion", "(I)V", (void*) CanvasJNI::setCompatibilityVersion},
    598 
    599     // ------------ @FastNative ----------------
    600     {"nSetBitmap", "(JLandroid/graphics/Bitmap;)V", (void*) CanvasJNI::setBitmap},
    601     {"nGetClipBounds","(JLandroid/graphics/Rect;)Z", (void*) CanvasJNI::getClipBounds},
    602 
    603     // ------------ @CriticalNative ----------------
    604     {"nIsOpaque","(J)Z", (void*) CanvasJNI::isOpaque},
    605     {"nGetWidth","(J)I", (void*) CanvasJNI::getWidth},
    606     {"nGetHeight","(J)I", (void*) CanvasJNI::getHeight},
    607     {"nSave","(JI)I", (void*) CanvasJNI::save},
    608     {"nSaveLayer","(JFFFFJI)I", (void*) CanvasJNI::saveLayer},
    609     {"nSaveLayerAlpha","(JFFFFII)I", (void*) CanvasJNI::saveLayerAlpha},
    610     {"nGetSaveCount","(J)I", (void*) CanvasJNI::getSaveCount},
    611     {"nRestore","(J)Z", (void*) CanvasJNI::restore},
    612     {"nRestoreToCount","(JI)V", (void*) CanvasJNI::restoreToCount},
    613     {"nGetMatrix", "(JJ)V", (void*)CanvasJNI::getMatrix},
    614     {"nSetMatrix","(JJ)V", (void*) CanvasJNI::setMatrix},
    615     {"nConcat","(JJ)V", (void*) CanvasJNI::concat},
    616     {"nRotate","(JF)V", (void*) CanvasJNI::rotate},
    617     {"nScale","(JFF)V", (void*) CanvasJNI::scale},
    618     {"nSkew","(JFF)V", (void*) CanvasJNI::skew},
    619     {"nTranslate","(JFF)V", (void*) CanvasJNI::translate},
    620     {"nQuickReject","(JJ)Z", (void*) CanvasJNI::quickRejectPath},
    621     {"nQuickReject","(JFFFF)Z", (void*)CanvasJNI::quickRejectRect},
    622     {"nClipRect","(JFFFFI)Z", (void*) CanvasJNI::clipRect},
    623     {"nClipPath","(JJI)Z", (void*) CanvasJNI::clipPath},
    624     {"nSetDrawFilter", "(JJ)V", (void*) CanvasJNI::setDrawFilter},
    625 };
    626 
    627 // If called from Canvas these are regular JNI
    628 // If called from DisplayListCanvas they are @FastNative
    629 static const JNINativeMethod gDrawMethods[] = {
    630     {"nDrawColor","(JII)V", (void*) CanvasJNI::drawColor},
    631     {"nDrawPaint","(JJ)V", (void*) CanvasJNI::drawPaint},
    632     {"nDrawPoint", "(JFFJ)V", (void*) CanvasJNI::drawPoint},
    633     {"nDrawPoints", "(J[FIIJ)V", (void*) CanvasJNI::drawPoints},
    634     {"nDrawLine", "(JFFFFJ)V", (void*) CanvasJNI::drawLine},
    635     {"nDrawLines", "(J[FIIJ)V", (void*) CanvasJNI::drawLines},
    636     {"nDrawRect","(JFFFFJ)V", (void*) CanvasJNI::drawRect},
    637     {"nDrawRegion", "(JJJ)V", (void*) CanvasJNI::drawRegion },
    638     {"nDrawRoundRect","(JFFFFFFJ)V", (void*) CanvasJNI::drawRoundRect},
    639     {"nDrawCircle","(JFFFJ)V", (void*) CanvasJNI::drawCircle},
    640     {"nDrawOval","(JFFFFJ)V", (void*) CanvasJNI::drawOval},
    641     {"nDrawArc","(JFFFFFFZJ)V", (void*) CanvasJNI::drawArc},
    642     {"nDrawPath","(JJJ)V", (void*) CanvasJNI::drawPath},
    643     {"nDrawVertices", "(JII[FI[FI[II[SIIJ)V", (void*)CanvasJNI::drawVertices},
    644     {"nDrawNinePatch", "(JJJFFFFJII)V", (void*)CanvasJNI::drawNinePatch},
    645     {"nDrawBitmapMatrix", "(JLandroid/graphics/Bitmap;JJ)V", (void*)CanvasJNI::drawBitmapMatrix},
    646     {"nDrawBitmapMesh", "(JLandroid/graphics/Bitmap;II[FI[IIJ)V", (void*)CanvasJNI::drawBitmapMesh},
    647     {"nDrawBitmap","(JLandroid/graphics/Bitmap;FFJIII)V", (void*) CanvasJNI::drawBitmap},
    648     {"nDrawBitmap","(JLandroid/graphics/Bitmap;FFFFFFFFJII)V", (void*) CanvasJNI::drawBitmapRect},
    649     {"nDrawBitmap", "(J[IIIFFIIZJ)V", (void*)CanvasJNI::drawBitmapArray},
    650     {"nDrawText","(J[CIIFFIJ)V", (void*) CanvasJNI::drawTextChars},
    651     {"nDrawText","(JLjava/lang/String;IIFFIJ)V", (void*) CanvasJNI::drawTextString},
    652     {"nDrawTextRun","(J[CIIIIFFZJJ)V", (void*) CanvasJNI::drawTextRunChars},
    653     {"nDrawTextRun","(JLjava/lang/String;IIIIFFZJ)V", (void*) CanvasJNI::drawTextRunString},
    654     {"nDrawTextOnPath","(J[CIIJFFIJ)V", (void*) CanvasJNI::drawTextOnPathChars},
    655     {"nDrawTextOnPath","(JLjava/lang/String;JFFIJ)V", (void*) CanvasJNI::drawTextOnPathString},
    656 };
    657 
    658 int register_android_graphics_Canvas(JNIEnv* env) {
    659     int ret = 0;
    660     ret |= RegisterMethodsOrDie(env, "android/graphics/Canvas", gMethods, NELEM(gMethods));
    661     ret |= RegisterMethodsOrDie(env, "android/graphics/BaseCanvas", gDrawMethods, NELEM(gDrawMethods));
    662     ret |= RegisterMethodsOrDie(env, "android/view/RecordingCanvas", gDrawMethods, NELEM(gDrawMethods));
    663     return ret;
    664 
    665 }
    666 
    667 }; // namespace android
    668