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 <androidfw/ResourceTypes.h>
     22 #include <hwui/Canvas.h>
     23 #include <hwui/Paint.h>
     24 #include <hwui/Typeface.h>
     25 #include <minikin/Layout.h>
     26 
     27 #include "Bitmap.h"
     28 #include "SkDrawFilter.h"
     29 #include "SkGraphics.h"
     30 #include "SkRegion.h"
     31 #include "SkVertices.h"
     32 
     33 namespace android {
     34 
     35 namespace CanvasJNI {
     36 
     37 static Canvas* get_canvas(jlong canvasHandle) {
     38     return reinterpret_cast<Canvas*>(canvasHandle);
     39 }
     40 
     41 static void delete_canvas(Canvas* canvas) {
     42     delete canvas;
     43 }
     44 
     45 static jlong getNativeFinalizer(JNIEnv* env, jobject clazz) {
     46     return static_cast<jlong>(reinterpret_cast<uintptr_t>(&delete_canvas));
     47 }
     48 
     49 // Native wrapper constructor used by Canvas(Bitmap)
     50 static jlong initRaster(JNIEnv* env, jobject, jobject jbitmap) {
     51     SkBitmap bitmap;
     52     if (jbitmap != NULL) {
     53         GraphicsJNI::getSkBitmap(env, jbitmap, &bitmap);
     54     }
     55     return reinterpret_cast<jlong>(Canvas::create_canvas(bitmap));
     56 }
     57 
     58 // Set the given bitmap as the new draw target (wrapped in a new SkCanvas),
     59 // optionally copying canvas matrix & clip state.
     60 static void setBitmap(JNIEnv* env, jobject, jlong canvasHandle, jobject jbitmap) {
     61     SkBitmap bitmap;
     62     if (jbitmap != NULL) {
     63         GraphicsJNI::getSkBitmap(env, jbitmap, &bitmap);
     64     }
     65     get_canvas(canvasHandle)->setBitmap(bitmap);
     66 }
     67 
     68 static jboolean isOpaque(jlong canvasHandle) {
     69     return get_canvas(canvasHandle)->isOpaque() ? JNI_TRUE : JNI_FALSE;
     70 }
     71 
     72 static jint getWidth(jlong canvasHandle) {
     73     return static_cast<jint>(get_canvas(canvasHandle)->width());
     74 }
     75 
     76 static jint getHeight(jlong canvasHandle) {
     77     return static_cast<jint>(get_canvas(canvasHandle)->height());
     78 }
     79 
     80 static void setHighContrastText(jlong canvasHandle, jboolean highContrastText) {
     81     Canvas* canvas = get_canvas(canvasHandle);
     82     canvas->setHighContrastText(highContrastText);
     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::MakeN32(width, height, kPremul_SkAlphaType,
    452             GraphicsJNI::defaultColorSpace());
    453     SkBitmap bitmap;
    454     bitmap.setInfo(info);
    455     sk_sp<Bitmap> androidBitmap = Bitmap::allocateHeapBitmap(&bitmap);
    456     if (!androidBitmap) {
    457         return;
    458     }
    459 
    460     if (!GraphicsJNI::SetPixels(env, jcolors, offset, stride, 0, 0, width, height, bitmap)) {
    461         return;
    462     }
    463 
    464     const Paint* paint = reinterpret_cast<Paint*>(paintHandle);
    465     get_canvas(canvasHandle)->drawBitmap(*androidBitmap, x, y, paint);
    466 }
    467 
    468 static void drawBitmapMesh(JNIEnv* env, jobject, jlong canvasHandle, jobject jbitmap,
    469                            jint meshWidth, jint meshHeight, jfloatArray jverts,
    470                            jint vertIndex, jintArray jcolors, jint colorIndex, jlong paintHandle) {
    471     const int ptCount = (meshWidth + 1) * (meshHeight + 1);
    472     AutoJavaFloatArray vertA(env, jverts, vertIndex + (ptCount << 1));
    473     AutoJavaIntArray colorA(env, jcolors, colorIndex + ptCount);
    474 
    475     const Paint* paint = reinterpret_cast<Paint*>(paintHandle);
    476     Bitmap& bitmap = android::bitmap::toBitmap(env, jbitmap);
    477     get_canvas(canvasHandle)->drawBitmapMesh(bitmap, meshWidth, meshHeight,
    478                                              vertA.ptr(), colorA.ptr(), paint);
    479 }
    480 
    481 static void drawTextChars(JNIEnv* env, jobject, jlong canvasHandle, jcharArray text,
    482                           jint index, jint count, jfloat x, jfloat y, jint bidiFlags,
    483                           jlong paintHandle, jlong typefaceHandle) {
    484     Paint* paint = reinterpret_cast<Paint*>(paintHandle);
    485     Typeface* typeface = reinterpret_cast<Typeface*>(typefaceHandle);
    486     jchar* jchars = env->GetCharArrayElements(text, NULL);
    487     get_canvas(canvasHandle)->drawText(jchars + index, 0, count, count, x, y,
    488                                        bidiFlags, *paint, typeface);
    489     env->ReleaseCharArrayElements(text, jchars, JNI_ABORT);
    490 }
    491 
    492 static void drawTextString(JNIEnv* env, jobject, jlong canvasHandle, jstring text,
    493                            jint start, jint end, jfloat x, jfloat y, jint bidiFlags,
    494                            jlong paintHandle, jlong typefaceHandle) {
    495     Paint* paint = reinterpret_cast<Paint*>(paintHandle);
    496     Typeface* typeface = reinterpret_cast<Typeface*>(typefaceHandle);
    497     const int count = end - start;
    498     const jchar* jchars = env->GetStringChars(text, NULL);
    499     get_canvas(canvasHandle)->drawText(jchars + start, 0, count, count, x, y,
    500                                        bidiFlags, *paint, typeface);
    501     env->ReleaseStringChars(text, jchars);
    502 }
    503 
    504 static void drawTextRunChars(JNIEnv* env, jobject, jlong canvasHandle, jcharArray text, jint index,
    505                              jint count, jint contextIndex, jint contextCount, jfloat x, jfloat y,
    506                              jboolean isRtl, jlong paintHandle, jlong typefaceHandle) {
    507     Paint* paint = reinterpret_cast<Paint*>(paintHandle);
    508     Typeface* typeface = reinterpret_cast<Typeface*>(typefaceHandle);
    509 
    510     const int bidiFlags = isRtl ? minikin::kBidi_Force_RTL : minikin::kBidi_Force_LTR;
    511     jchar* jchars = env->GetCharArrayElements(text, NULL);
    512     get_canvas(canvasHandle)->drawText(jchars + contextIndex, index - contextIndex, count,
    513                                        contextCount, x, y, bidiFlags, *paint, typeface);
    514     env->ReleaseCharArrayElements(text, jchars, JNI_ABORT);
    515 }
    516 
    517 static void drawTextRunString(JNIEnv* env, jobject obj, jlong canvasHandle, jstring text,
    518                               jint start, jint end, jint contextStart, jint contextEnd,
    519                               jfloat x, jfloat y, jboolean isRtl, jlong paintHandle,
    520                               jlong typefaceHandle) {
    521     Paint* paint = reinterpret_cast<Paint*>(paintHandle);
    522     Typeface* typeface = reinterpret_cast<Typeface*>(typefaceHandle);
    523 
    524     int bidiFlags = isRtl ? minikin::kBidi_Force_RTL : minikin::kBidi_Force_LTR;
    525     jint count = end - start;
    526     jint contextCount = contextEnd - contextStart;
    527     const jchar* jchars = env->GetStringChars(text, NULL);
    528     get_canvas(canvasHandle)->drawText(jchars + contextStart, start - contextStart, count,
    529                                        contextCount, x, y, bidiFlags, *paint, typeface);
    530     env->ReleaseStringChars(text, jchars);
    531 }
    532 
    533 static void drawTextOnPathChars(JNIEnv* env, jobject, jlong canvasHandle, jcharArray text,
    534                                 jint index, jint count, jlong pathHandle, jfloat hOffset,
    535                                 jfloat vOffset, jint bidiFlags, jlong paintHandle,
    536                                 jlong typefaceHandle) {
    537     SkPath* path = reinterpret_cast<SkPath*>(pathHandle);
    538     Paint* paint = reinterpret_cast<Paint*>(paintHandle);
    539     Typeface* typeface = reinterpret_cast<Typeface*>(typefaceHandle);
    540 
    541     jchar* jchars = env->GetCharArrayElements(text, NULL);
    542 
    543     get_canvas(canvasHandle)->drawTextOnPath(jchars + index, count, bidiFlags, *path,
    544                    hOffset, vOffset, *paint, typeface);
    545 
    546     env->ReleaseCharArrayElements(text, jchars, 0);
    547 }
    548 
    549 static void drawTextOnPathString(JNIEnv* env, jobject, jlong canvasHandle, jstring text,
    550                                  jlong pathHandle, jfloat hOffset, jfloat vOffset,
    551                                  jint bidiFlags, jlong paintHandle, jlong typefaceHandle) {
    552     SkPath* path = reinterpret_cast<SkPath*>(pathHandle);
    553     Paint* paint = reinterpret_cast<Paint*>(paintHandle);
    554     Typeface* typeface = reinterpret_cast<Typeface*>(typefaceHandle);
    555 
    556     const jchar* jchars = env->GetStringChars(text, NULL);
    557     int count = env->GetStringLength(text);
    558 
    559     get_canvas(canvasHandle)->drawTextOnPath(jchars, count, bidiFlags, *path,
    560                    hOffset, vOffset, *paint, typeface);
    561 
    562     env->ReleaseStringChars(text, jchars);
    563 }
    564 
    565 static void setDrawFilter(jlong canvasHandle, jlong filterHandle) {
    566     get_canvas(canvasHandle)->setDrawFilter(reinterpret_cast<SkDrawFilter*>(filterHandle));
    567 }
    568 
    569 static void freeCaches(JNIEnv* env, jobject) {
    570     SkGraphics::PurgeFontCache();
    571 }
    572 
    573 static void freeTextLayoutCaches(JNIEnv* env, jobject) {
    574     minikin::Layout::purgeCaches();
    575 }
    576 
    577 }; // namespace CanvasJNI
    578 
    579 static const JNINativeMethod gMethods[] = {
    580     {"nGetNativeFinalizer", "()J", (void*) CanvasJNI::getNativeFinalizer},
    581     {"nInitRaster", "(Landroid/graphics/Bitmap;)J", (void*) CanvasJNI::initRaster},
    582     {"nFreeCaches", "()V", (void*) CanvasJNI::freeCaches},
    583     {"nFreeTextLayoutCaches", "()V", (void*) CanvasJNI::freeTextLayoutCaches},
    584 
    585     // ------------ @FastNative ----------------
    586     {"nSetBitmap", "(JLandroid/graphics/Bitmap;)V", (void*) CanvasJNI::setBitmap},
    587     {"nGetClipBounds","(JLandroid/graphics/Rect;)Z", (void*) CanvasJNI::getClipBounds},
    588 
    589     // ------------ @CriticalNative ----------------
    590     {"nIsOpaque","(J)Z", (void*) CanvasJNI::isOpaque},
    591     {"nGetWidth","(J)I", (void*) CanvasJNI::getWidth},
    592     {"nGetHeight","(J)I", (void*) CanvasJNI::getHeight},
    593     {"nSetHighContrastText","(JZ)V", (void*) CanvasJNI::setHighContrastText},
    594     {"nSave","(JI)I", (void*) CanvasJNI::save},
    595     {"nSaveLayer","(JFFFFJI)I", (void*) CanvasJNI::saveLayer},
    596     {"nSaveLayerAlpha","(JFFFFII)I", (void*) CanvasJNI::saveLayerAlpha},
    597     {"nGetSaveCount","(J)I", (void*) CanvasJNI::getSaveCount},
    598     {"nRestore","(J)Z", (void*) CanvasJNI::restore},
    599     {"nRestoreToCount","(JI)V", (void*) CanvasJNI::restoreToCount},
    600     {"nGetMatrix", "(JJ)V", (void*)CanvasJNI::getMatrix},
    601     {"nSetMatrix","(JJ)V", (void*) CanvasJNI::setMatrix},
    602     {"nConcat","(JJ)V", (void*) CanvasJNI::concat},
    603     {"nRotate","(JF)V", (void*) CanvasJNI::rotate},
    604     {"nScale","(JFF)V", (void*) CanvasJNI::scale},
    605     {"nSkew","(JFF)V", (void*) CanvasJNI::skew},
    606     {"nTranslate","(JFF)V", (void*) CanvasJNI::translate},
    607     {"nQuickReject","(JJ)Z", (void*) CanvasJNI::quickRejectPath},
    608     {"nQuickReject","(JFFFF)Z", (void*)CanvasJNI::quickRejectRect},
    609     {"nClipRect","(JFFFFI)Z", (void*) CanvasJNI::clipRect},
    610     {"nClipPath","(JJI)Z", (void*) CanvasJNI::clipPath},
    611     {"nSetDrawFilter", "(JJ)V", (void*) CanvasJNI::setDrawFilter},
    612 };
    613 
    614 // If called from Canvas these are regular JNI
    615 // If called from DisplayListCanvas they are @FastNative
    616 static const JNINativeMethod gDrawMethods[] = {
    617     {"nDrawColor","(JII)V", (void*) CanvasJNI::drawColor},
    618     {"nDrawPaint","(JJ)V", (void*) CanvasJNI::drawPaint},
    619     {"nDrawPoint", "(JFFJ)V", (void*) CanvasJNI::drawPoint},
    620     {"nDrawPoints", "(J[FIIJ)V", (void*) CanvasJNI::drawPoints},
    621     {"nDrawLine", "(JFFFFJ)V", (void*) CanvasJNI::drawLine},
    622     {"nDrawLines", "(J[FIIJ)V", (void*) CanvasJNI::drawLines},
    623     {"nDrawRect","(JFFFFJ)V", (void*) CanvasJNI::drawRect},
    624     {"nDrawRegion", "(JJJ)V", (void*) CanvasJNI::drawRegion },
    625     {"nDrawRoundRect","(JFFFFFFJ)V", (void*) CanvasJNI::drawRoundRect},
    626     {"nDrawCircle","(JFFFJ)V", (void*) CanvasJNI::drawCircle},
    627     {"nDrawOval","(JFFFFJ)V", (void*) CanvasJNI::drawOval},
    628     {"nDrawArc","(JFFFFFFZJ)V", (void*) CanvasJNI::drawArc},
    629     {"nDrawPath","(JJJ)V", (void*) CanvasJNI::drawPath},
    630     {"nDrawVertices", "(JII[FI[FI[II[SIIJ)V", (void*)CanvasJNI::drawVertices},
    631     {"nDrawNinePatch", "(JJJFFFFJII)V", (void*)CanvasJNI::drawNinePatch},
    632     {"nDrawBitmapMatrix", "(JLandroid/graphics/Bitmap;JJ)V", (void*)CanvasJNI::drawBitmapMatrix},
    633     {"nDrawBitmapMesh", "(JLandroid/graphics/Bitmap;II[FI[IIJ)V", (void*)CanvasJNI::drawBitmapMesh},
    634     {"nDrawBitmap","(JLandroid/graphics/Bitmap;FFJIII)V", (void*) CanvasJNI::drawBitmap},
    635     {"nDrawBitmap","(JLandroid/graphics/Bitmap;FFFFFFFFJII)V", (void*) CanvasJNI::drawBitmapRect},
    636     {"nDrawBitmap", "(J[IIIFFIIZJ)V", (void*)CanvasJNI::drawBitmapArray},
    637     {"nDrawText","(J[CIIFFIJJ)V", (void*) CanvasJNI::drawTextChars},
    638     {"nDrawText","(JLjava/lang/String;IIFFIJJ)V", (void*) CanvasJNI::drawTextString},
    639     {"nDrawTextRun","(J[CIIIIFFZJJ)V", (void*) CanvasJNI::drawTextRunChars},
    640     {"nDrawTextRun","(JLjava/lang/String;IIIIFFZJJ)V", (void*) CanvasJNI::drawTextRunString},
    641     {"nDrawTextOnPath","(J[CIIJFFIJJ)V", (void*) CanvasJNI::drawTextOnPathChars},
    642     {"nDrawTextOnPath","(JLjava/lang/String;JFFIJJ)V", (void*) CanvasJNI::drawTextOnPathString},
    643 };
    644 
    645 int register_android_graphics_Canvas(JNIEnv* env) {
    646     int ret = 0;
    647     ret |= RegisterMethodsOrDie(env, "android/graphics/Canvas", gMethods, NELEM(gMethods));
    648     ret |= RegisterMethodsOrDie(env, "android/graphics/BaseCanvas", gDrawMethods, NELEM(gDrawMethods));
    649     ret |= RegisterMethodsOrDie(env, "android/view/RecordingCanvas", gDrawMethods, NELEM(gDrawMethods));
    650     return ret;
    651 
    652 }
    653 
    654 }; // namespace android
    655