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 
     31 namespace android {
     32 
     33 namespace CanvasJNI {
     34 
     35 static Canvas* get_canvas(jlong canvasHandle) {
     36     return reinterpret_cast<Canvas*>(canvasHandle);
     37 }
     38 
     39 static void delete_canvas(Canvas* canvas) {
     40     delete canvas;
     41 }
     42 
     43 static jlong getNativeFinalizer(JNIEnv* env, jobject clazz) {
     44     return static_cast<jlong>(reinterpret_cast<uintptr_t>(&delete_canvas));
     45 }
     46 
     47 // Native wrapper constructor used by Canvas(Bitmap)
     48 static jlong initRaster(JNIEnv* env, jobject, jobject jbitmap) {
     49     SkBitmap bitmap;
     50     if (jbitmap != NULL) {
     51         GraphicsJNI::getSkBitmap(env, jbitmap, &bitmap);
     52     }
     53     return reinterpret_cast<jlong>(Canvas::create_canvas(bitmap));
     54 }
     55 
     56 // Set the given bitmap as the new draw target (wrapped in a new SkCanvas),
     57 // optionally copying canvas matrix & clip state.
     58 static void setBitmap(JNIEnv* env, jobject, jlong canvasHandle, jobject jbitmap) {
     59     SkBitmap bitmap;
     60     if (jbitmap != NULL) {
     61         GraphicsJNI::getSkBitmap(env, jbitmap, &bitmap);
     62     }
     63     get_canvas(canvasHandle)->setBitmap(bitmap);
     64 }
     65 
     66 static jboolean isOpaque(JNIEnv*, jobject, jlong canvasHandle) {
     67     return get_canvas(canvasHandle)->isOpaque() ? JNI_TRUE : JNI_FALSE;
     68 }
     69 
     70 static jint getWidth(JNIEnv*, jobject, jlong canvasHandle) {
     71     return static_cast<jint>(get_canvas(canvasHandle)->width());
     72 }
     73 
     74 static jint getHeight(JNIEnv*, jobject, jlong canvasHandle) {
     75     return static_cast<jint>(get_canvas(canvasHandle)->height());
     76 }
     77 
     78 static void setHighContrastText(JNIEnv*, jobject, jlong canvasHandle, jboolean highContrastText) {
     79     Canvas* canvas = get_canvas(canvasHandle);
     80     canvas->setHighContrastText(highContrastText);
     81 }
     82 
     83 static jint getSaveCount(JNIEnv*, jobject, jlong canvasHandle) {
     84     return static_cast<jint>(get_canvas(canvasHandle)->getSaveCount());
     85 }
     86 
     87 static jint save(JNIEnv*, jobject, jlong canvasHandle, jint flagsHandle) {
     88     SaveFlags::Flags flags = static_cast<SaveFlags::Flags>(flagsHandle);
     89     return static_cast<jint>(get_canvas(canvasHandle)->save(flags));
     90 }
     91 
     92 static jint saveLayer(JNIEnv* env, jobject, jlong canvasHandle, jfloat l, jfloat t,
     93                       jfloat r, jfloat b, jlong paintHandle, jint flagsHandle) {
     94     Paint* paint  = reinterpret_cast<Paint*>(paintHandle);
     95     SaveFlags::Flags flags = static_cast<SaveFlags::Flags>(flagsHandle);
     96     return static_cast<jint>(get_canvas(canvasHandle)->saveLayer(l, t, r, b, paint, flags));
     97 }
     98 
     99 static jint saveLayerAlpha(JNIEnv* env, jobject, jlong canvasHandle, jfloat l, jfloat t,
    100                            jfloat r, jfloat b, jint alpha, jint flagsHandle) {
    101     SaveFlags::Flags flags = static_cast<SaveFlags::Flags>(flagsHandle);
    102     return static_cast<jint>(get_canvas(canvasHandle)->saveLayerAlpha(l, t, r, b, alpha, flags));
    103 }
    104 
    105 static void restore(JNIEnv* env, jobject, jlong canvasHandle, jboolean throwOnUnderflow) {
    106     Canvas* canvas = get_canvas(canvasHandle);
    107     if (canvas->getSaveCount() <= 1) {  // cannot restore anymore
    108         if (throwOnUnderflow) {
    109             doThrowISE(env, "Underflow in restore - more restores than saves");
    110         }
    111         return; // compat behavior - return without throwing
    112     }
    113     canvas->restore();
    114 }
    115 
    116 static void restoreToCount(JNIEnv* env, jobject, jlong canvasHandle, jint restoreCount,
    117         jboolean throwOnUnderflow) {
    118     Canvas* canvas = get_canvas(canvasHandle);
    119     if (restoreCount < 1 || restoreCount > canvas->getSaveCount()) {
    120         if (throwOnUnderflow) {
    121             doThrowIAE(env, "Underflow in restoreToCount - more restores than saves");
    122             return;
    123         }
    124         restoreCount = 1; // compat behavior - restore as far as possible
    125     }
    126     canvas->restoreToCount(restoreCount);
    127 }
    128 
    129 static void getCTM(JNIEnv* env, jobject, jlong canvasHandle, jlong matrixHandle) {
    130     SkMatrix* matrix = reinterpret_cast<SkMatrix*>(matrixHandle);
    131     get_canvas(canvasHandle)->getMatrix(matrix);
    132 }
    133 
    134 static void setMatrix(JNIEnv* env, jobject, jlong canvasHandle, jlong matrixHandle) {
    135     const SkMatrix* matrix = reinterpret_cast<SkMatrix*>(matrixHandle);
    136     get_canvas(canvasHandle)->setMatrix(matrix ? *matrix : SkMatrix::I());
    137 }
    138 
    139 static void concat(JNIEnv* env, jobject, jlong canvasHandle, jlong matrixHandle) {
    140     const SkMatrix* matrix = reinterpret_cast<SkMatrix*>(matrixHandle);
    141     get_canvas(canvasHandle)->concat(*matrix);
    142 }
    143 
    144 static void rotate(JNIEnv*, jobject, jlong canvasHandle, jfloat degrees) {
    145     get_canvas(canvasHandle)->rotate(degrees);
    146 }
    147 
    148 static void scale(JNIEnv*, jobject, jlong canvasHandle, jfloat sx, jfloat sy) {
    149     get_canvas(canvasHandle)->scale(sx, sy);
    150 }
    151 
    152 static void skew(JNIEnv*, jobject, jlong canvasHandle, jfloat sx, jfloat sy) {
    153     get_canvas(canvasHandle)->skew(sx, sy);
    154 }
    155 
    156 static void translate(JNIEnv*, jobject, jlong canvasHandle, jfloat dx, jfloat dy) {
    157     get_canvas(canvasHandle)->translate(dx, dy);
    158 }
    159 
    160 static jboolean getClipBounds(JNIEnv* env, jobject, jlong canvasHandle, jobject bounds) {
    161     SkRect   r;
    162     SkIRect ir;
    163     bool result = get_canvas(canvasHandle)->getClipBounds(&r);
    164 
    165     if (!result) {
    166         r.setEmpty();
    167     }
    168     r.round(&ir);
    169 
    170     (void)GraphicsJNI::irect_to_jrect(ir, env, bounds);
    171     return result ? JNI_TRUE : JNI_FALSE;
    172 }
    173 
    174 static jboolean quickRejectRect(JNIEnv* env, jobject, jlong canvasHandle,
    175                                 jfloat left, jfloat top, jfloat right, jfloat bottom) {
    176     bool result = get_canvas(canvasHandle)->quickRejectRect(left, top, right, bottom);
    177     return result ? JNI_TRUE : JNI_FALSE;
    178 }
    179 
    180 static jboolean quickRejectPath(JNIEnv* env, jobject, jlong canvasHandle, jlong pathHandle) {
    181     SkPath* path = reinterpret_cast<SkPath*>(pathHandle);
    182     bool result = get_canvas(canvasHandle)->quickRejectPath(*path);
    183     return result ? JNI_TRUE : JNI_FALSE;
    184 }
    185 
    186 static jboolean clipRect(JNIEnv*, jobject, jlong canvasHandle, jfloat l, jfloat t,
    187                          jfloat r, jfloat b, jint opHandle) {
    188     SkRegion::Op op = static_cast<SkRegion::Op>(opHandle);
    189     bool nonEmptyClip = get_canvas(canvasHandle)->clipRect(l, t, r, b, op);
    190     return nonEmptyClip ? JNI_TRUE : JNI_FALSE;
    191 }
    192 
    193 static jboolean clipPath(JNIEnv* env, jobject, jlong canvasHandle, jlong pathHandle,
    194                          jint opHandle) {
    195     SkPath* path = reinterpret_cast<SkPath*>(pathHandle);
    196     SkRegion::Op op = static_cast<SkRegion::Op>(opHandle);
    197     bool nonEmptyClip = get_canvas(canvasHandle)->clipPath(path, op);
    198     return nonEmptyClip ? JNI_TRUE : JNI_FALSE;
    199 }
    200 
    201 static jboolean clipRegion(JNIEnv* env, jobject, jlong canvasHandle, jlong deviceRgnHandle,
    202                            jint opHandle) {
    203     SkRegion* deviceRgn = reinterpret_cast<SkRegion*>(deviceRgnHandle);
    204     SkRegion::Op op = static_cast<SkRegion::Op>(opHandle);
    205     bool nonEmptyClip = get_canvas(canvasHandle)->clipRegion(deviceRgn, op);
    206     return nonEmptyClip ? JNI_TRUE : JNI_FALSE;
    207 }
    208 
    209 static void drawColor(JNIEnv* env, jobject, jlong canvasHandle, jint color, jint modeHandle) {
    210     SkXfermode::Mode mode = static_cast<SkXfermode::Mode>(modeHandle);
    211     get_canvas(canvasHandle)->drawColor(color, mode);
    212 }
    213 
    214 static void drawPaint(JNIEnv* env, jobject, jlong canvasHandle, jlong paintHandle) {
    215     Paint* paint = reinterpret_cast<Paint*>(paintHandle);
    216     get_canvas(canvasHandle)->drawPaint(*paint);
    217 }
    218 
    219 static void drawPoint(JNIEnv*, jobject, jlong canvasHandle, jfloat x, jfloat y,
    220                       jlong paintHandle) {
    221     const Paint* paint = reinterpret_cast<Paint*>(paintHandle);
    222     get_canvas(canvasHandle)->drawPoint(x, y, *paint);
    223 }
    224 
    225 static void drawPoints(JNIEnv* env, jobject, jlong canvasHandle, jfloatArray jptsArray,
    226                        jint offset, jint count, jlong paintHandle) {
    227     NPE_CHECK_RETURN_VOID(env, jptsArray);
    228     AutoJavaFloatArray autoPts(env, jptsArray);
    229     float* floats = autoPts.ptr();
    230     const int length = autoPts.length();
    231 
    232     if ((offset | count) < 0 || offset + count > length) {
    233         doThrowAIOOBE(env);
    234         return;
    235     }
    236 
    237     const Paint* paint = reinterpret_cast<Paint*>(paintHandle);
    238     get_canvas(canvasHandle)->drawPoints(floats + offset, count, *paint);
    239 }
    240 
    241 static void drawLine(JNIEnv* env, jobject, jlong canvasHandle, jfloat startX, jfloat startY,
    242                      jfloat stopX, jfloat stopY, jlong paintHandle) {
    243     Paint* paint = reinterpret_cast<Paint*>(paintHandle);
    244     get_canvas(canvasHandle)->drawLine(startX, startY, stopX, stopY, *paint);
    245 }
    246 
    247 static void drawLines(JNIEnv* env, jobject, jlong canvasHandle, jfloatArray jptsArray,
    248                       jint offset, jint count, jlong paintHandle) {
    249     NPE_CHECK_RETURN_VOID(env, jptsArray);
    250     AutoJavaFloatArray autoPts(env, jptsArray);
    251     float* floats = autoPts.ptr();
    252     const int length = autoPts.length();
    253 
    254     if ((offset | count) < 0 || offset + count > length) {
    255         doThrowAIOOBE(env);
    256         return;
    257     }
    258 
    259     const Paint* paint = reinterpret_cast<Paint*>(paintHandle);
    260     get_canvas(canvasHandle)->drawLines(floats + offset, count, *paint);
    261 }
    262 
    263 static void drawRect(JNIEnv* env, jobject, jlong canvasHandle, jfloat left, jfloat top,
    264                      jfloat right, jfloat bottom, jlong paintHandle) {
    265     const Paint* paint = reinterpret_cast<Paint*>(paintHandle);
    266     get_canvas(canvasHandle)->drawRect(left, top, right, bottom, *paint);
    267 }
    268 
    269 static void drawRegion(JNIEnv* env, jobject, jlong canvasHandle, jlong regionHandle,
    270                        jlong paintHandle) {
    271     const SkRegion* region = reinterpret_cast<SkRegion*>(regionHandle);
    272     const Paint* paint = reinterpret_cast<Paint*>(paintHandle);
    273     get_canvas(canvasHandle)->drawRegion(*region, *paint);
    274 }
    275 
    276 static void drawRoundRect(JNIEnv* env, jobject, jlong canvasHandle, jfloat left, jfloat top,
    277                           jfloat right, jfloat bottom, jfloat rx, jfloat ry, jlong paintHandle) {
    278     const Paint* paint = reinterpret_cast<Paint*>(paintHandle);
    279     get_canvas(canvasHandle)->drawRoundRect(left, top, right, bottom, rx, ry, *paint);
    280 }
    281 
    282 static void drawCircle(JNIEnv* env, jobject, jlong canvasHandle, jfloat cx, jfloat cy,
    283                        jfloat radius, jlong paintHandle) {
    284     const Paint* paint = reinterpret_cast<Paint*>(paintHandle);
    285     get_canvas(canvasHandle)->drawCircle(cx, cy, radius, *paint);
    286 }
    287 
    288 static void drawOval(JNIEnv* env, jobject, jlong canvasHandle, jfloat left, jfloat top,
    289                      jfloat right, jfloat bottom, jlong paintHandle) {
    290     const Paint* paint = reinterpret_cast<Paint*>(paintHandle);
    291     get_canvas(canvasHandle)->drawOval(left, top, right, bottom, *paint);
    292 }
    293 
    294 static void drawArc(JNIEnv* env, jobject, jlong canvasHandle, jfloat left, jfloat top,
    295                     jfloat right, jfloat bottom, jfloat startAngle, jfloat sweepAngle,
    296                     jboolean useCenter, jlong paintHandle) {
    297     const Paint* paint = reinterpret_cast<Paint*>(paintHandle);
    298     get_canvas(canvasHandle)->drawArc(left, top, right, bottom, startAngle, sweepAngle,
    299                                        useCenter, *paint);
    300 }
    301 
    302 static void drawPath(JNIEnv* env, jobject, jlong canvasHandle, jlong pathHandle,
    303                      jlong paintHandle) {
    304     const SkPath* path = reinterpret_cast<SkPath*>(pathHandle);
    305     const Paint* paint = reinterpret_cast<Paint*>(paintHandle);
    306     get_canvas(canvasHandle)->drawPath(*path, *paint);
    307 }
    308 
    309 static void drawVertices(JNIEnv* env, jobject, jlong canvasHandle,
    310                          jint modeHandle, jint vertexCount,
    311                          jfloatArray jverts, jint vertIndex,
    312                          jfloatArray jtexs, jint texIndex,
    313                          jintArray jcolors, jint colorIndex,
    314                          jshortArray jindices, jint indexIndex,
    315                          jint indexCount, jlong paintHandle) {
    316     AutoJavaFloatArray  vertA(env, jverts, vertIndex + vertexCount);
    317     AutoJavaFloatArray  texA(env, jtexs, texIndex + vertexCount);
    318     AutoJavaIntArray    colorA(env, jcolors, colorIndex + vertexCount);
    319     AutoJavaShortArray  indexA(env, jindices, indexIndex + indexCount);
    320 
    321     const float* verts = vertA.ptr() + vertIndex;
    322     const float* texs = texA.ptr() + vertIndex;
    323     const int* colors = NULL;
    324     const uint16_t* indices = NULL;
    325 
    326     if (jcolors != NULL) {
    327         colors = colorA.ptr() + colorIndex;
    328     }
    329     if (jindices != NULL) {
    330         indices = (const uint16_t*)(indexA.ptr() + indexIndex);
    331     }
    332 
    333     SkCanvas::VertexMode mode = static_cast<SkCanvas::VertexMode>(modeHandle);
    334     const Paint* paint = reinterpret_cast<Paint*>(paintHandle);
    335     get_canvas(canvasHandle)->drawVertices(mode, vertexCount, verts, texs, colors,
    336                                            indices, indexCount, *paint);
    337 }
    338 
    339 static void drawNinePatch(JNIEnv* env, jobject, jlong canvasHandle, jlong bitmapHandle,
    340         jlong chunkHandle, jfloat left, jfloat top, jfloat right, jfloat bottom,
    341         jlong paintHandle, jint dstDensity, jint srcDensity) {
    342 
    343     Canvas* canvas = get_canvas(canvasHandle);
    344     Bitmap* bitmap = reinterpret_cast<Bitmap*>(bitmapHandle);
    345     SkBitmap skiaBitmap;
    346     bitmap->getSkBitmap(&skiaBitmap);
    347     const android::Res_png_9patch* chunk = reinterpret_cast<android::Res_png_9patch*>(chunkHandle);
    348     const Paint* paint = reinterpret_cast<Paint*>(paintHandle);
    349 
    350     if (CC_LIKELY(dstDensity == srcDensity || dstDensity == 0 || srcDensity == 0)) {
    351         canvas->drawNinePatch(skiaBitmap, *chunk, left, top, right, bottom, paint);
    352     } else {
    353         canvas->save(SaveFlags::MatrixClip);
    354 
    355         SkScalar scale = dstDensity / (float)srcDensity;
    356         canvas->translate(left, top);
    357         canvas->scale(scale, scale);
    358 
    359         Paint filteredPaint;
    360         if (paint) {
    361             filteredPaint = *paint;
    362         }
    363         filteredPaint.setFilterQuality(kLow_SkFilterQuality);
    364 
    365         canvas->drawNinePatch(skiaBitmap, *chunk, 0, 0, (right-left)/scale, (bottom-top)/scale,
    366                 &filteredPaint);
    367 
    368         canvas->restore();
    369     }
    370 }
    371 
    372 static void drawBitmap(JNIEnv* env, jobject jcanvas, jlong canvasHandle, jobject jbitmap,
    373                        jfloat left, jfloat top, jlong paintHandle, jint canvasDensity,
    374                        jint screenDensity, jint bitmapDensity) {
    375     Canvas* canvas = get_canvas(canvasHandle);
    376     SkBitmap bitmap;
    377     GraphicsJNI::getSkBitmap(env, jbitmap, &bitmap);
    378     const Paint* paint = reinterpret_cast<Paint*>(paintHandle);
    379 
    380     if (canvasDensity == bitmapDensity || canvasDensity == 0 || bitmapDensity == 0) {
    381         if (screenDensity != 0 && screenDensity != bitmapDensity) {
    382             Paint filteredPaint;
    383             if (paint) {
    384                 filteredPaint = *paint;
    385             }
    386             filteredPaint.setFilterQuality(kLow_SkFilterQuality);
    387             canvas->drawBitmap(bitmap, left, top, &filteredPaint);
    388         } else {
    389             canvas->drawBitmap(bitmap, left, top, paint);
    390         }
    391     } else {
    392         canvas->save(SaveFlags::MatrixClip);
    393         SkScalar scale = canvasDensity / (float)bitmapDensity;
    394         canvas->translate(left, top);
    395         canvas->scale(scale, scale);
    396 
    397         Paint filteredPaint;
    398         if (paint) {
    399             filteredPaint = *paint;
    400         }
    401         filteredPaint.setFilterQuality(kLow_SkFilterQuality);
    402 
    403         canvas->drawBitmap(bitmap, 0, 0, &filteredPaint);
    404         canvas->restore();
    405     }
    406 }
    407 
    408 static void drawBitmapMatrix(JNIEnv* env, jobject, jlong canvasHandle, jobject jbitmap,
    409                              jlong matrixHandle, jlong paintHandle) {
    410     const SkMatrix* matrix = reinterpret_cast<SkMatrix*>(matrixHandle);
    411     const Paint* paint = reinterpret_cast<Paint*>(paintHandle);
    412     SkBitmap bitmap;
    413     GraphicsJNI::getSkBitmap(env, jbitmap, &bitmap);
    414     get_canvas(canvasHandle)->drawBitmap(bitmap, *matrix, paint);
    415 }
    416 
    417 static void drawBitmapRect(JNIEnv* env, jobject, jlong canvasHandle, jobject jbitmap,
    418                            float srcLeft, float srcTop, float srcRight, float srcBottom,
    419                            float dstLeft, float dstTop, float dstRight, float dstBottom,
    420                            jlong paintHandle, jint screenDensity, jint bitmapDensity) {
    421     Canvas* canvas = get_canvas(canvasHandle);
    422     const Paint* paint = reinterpret_cast<Paint*>(paintHandle);
    423 
    424     SkBitmap bitmap;
    425     GraphicsJNI::getSkBitmap(env, jbitmap, &bitmap);
    426     if (screenDensity != 0 && screenDensity != bitmapDensity) {
    427         Paint filteredPaint;
    428         if (paint) {
    429             filteredPaint = *paint;
    430         }
    431         filteredPaint.setFilterQuality(kLow_SkFilterQuality);
    432         canvas->drawBitmap(bitmap, srcLeft, srcTop, srcRight, srcBottom,
    433                            dstLeft, dstTop, dstRight, dstBottom, &filteredPaint);
    434     } else {
    435         canvas->drawBitmap(bitmap, srcLeft, srcTop, srcRight, srcBottom,
    436                            dstLeft, dstTop, dstRight, dstBottom, paint);
    437     }
    438 }
    439 
    440 static void drawBitmapArray(JNIEnv* env, jobject, jlong canvasHandle,
    441                             jintArray jcolors, jint offset, jint stride,
    442                             jfloat x, jfloat y, jint width, jint height,
    443                             jboolean hasAlpha, jlong paintHandle) {
    444     // Note: If hasAlpha is false, kRGB_565_SkColorType will be used, which will
    445     // correct the alphaType to kOpaque_SkAlphaType.
    446     SkImageInfo info = SkImageInfo::Make(width, height,
    447                            hasAlpha ? kN32_SkColorType : kRGB_565_SkColorType,
    448                            kPremul_SkAlphaType);
    449     SkBitmap bitmap;
    450     bitmap.setInfo(info);
    451     if (!GraphicsJNI::allocatePixels(env, &bitmap, NULL)) {
    452         return;
    453     }
    454 
    455     if (!GraphicsJNI::SetPixels(env, jcolors, offset, stride, 0, 0, width, height, bitmap)) {
    456         return;
    457     }
    458 
    459     const Paint* paint = reinterpret_cast<Paint*>(paintHandle);
    460     get_canvas(canvasHandle)->drawBitmap(bitmap, x, y, paint);
    461 }
    462 
    463 static void drawBitmapMesh(JNIEnv* env, jobject, jlong canvasHandle, jobject jbitmap,
    464                            jint meshWidth, jint meshHeight, jfloatArray jverts,
    465                            jint vertIndex, jintArray jcolors, jint colorIndex, jlong paintHandle) {
    466     const int ptCount = (meshWidth + 1) * (meshHeight + 1);
    467     AutoJavaFloatArray vertA(env, jverts, vertIndex + (ptCount << 1));
    468     AutoJavaIntArray colorA(env, jcolors, colorIndex + ptCount);
    469 
    470     const Paint* paint = reinterpret_cast<Paint*>(paintHandle);
    471     SkBitmap bitmap;
    472     GraphicsJNI::getSkBitmap(env, jbitmap, &bitmap);
    473     get_canvas(canvasHandle)->drawBitmapMesh(bitmap, meshWidth, meshHeight,
    474                                              vertA.ptr(), colorA.ptr(), paint);
    475 }
    476 
    477 static void drawTextChars(JNIEnv* env, jobject, jlong canvasHandle, jcharArray text,
    478                           jint index, jint count, jfloat x, jfloat y, jint bidiFlags,
    479                           jlong paintHandle, jlong typefaceHandle) {
    480     Paint* paint = reinterpret_cast<Paint*>(paintHandle);
    481     Typeface* typeface = reinterpret_cast<Typeface*>(typefaceHandle);
    482     jchar* jchars = env->GetCharArrayElements(text, NULL);
    483     get_canvas(canvasHandle)->drawText(jchars + index, 0, count, count, x, y,
    484                                        bidiFlags, *paint, typeface);
    485     env->ReleaseCharArrayElements(text, jchars, JNI_ABORT);
    486 }
    487 
    488 static void drawTextString(JNIEnv* env, jobject, jlong canvasHandle, jstring text,
    489                            jint start, jint end, jfloat x, jfloat y, jint bidiFlags,
    490                            jlong paintHandle, jlong typefaceHandle) {
    491     Paint* paint = reinterpret_cast<Paint*>(paintHandle);
    492     Typeface* typeface = reinterpret_cast<Typeface*>(typefaceHandle);
    493     const int count = end - start;
    494     const jchar* jchars = env->GetStringChars(text, NULL);
    495     get_canvas(canvasHandle)->drawText(jchars + start, 0, count, count, x, y,
    496                                        bidiFlags, *paint, typeface);
    497     env->ReleaseStringChars(text, jchars);
    498 }
    499 
    500 static void drawTextRunChars(JNIEnv* env, jobject, jlong canvasHandle, jcharArray text, jint index,
    501                              jint count, jint contextIndex, jint contextCount, jfloat x, jfloat y,
    502                              jboolean isRtl, jlong paintHandle, jlong typefaceHandle) {
    503     Paint* paint = reinterpret_cast<Paint*>(paintHandle);
    504     Typeface* typeface = reinterpret_cast<Typeface*>(typefaceHandle);
    505 
    506     const int bidiFlags = isRtl ? kBidi_Force_RTL : kBidi_Force_LTR;
    507     jchar* jchars = env->GetCharArrayElements(text, NULL);
    508     get_canvas(canvasHandle)->drawText(jchars + contextIndex, index - contextIndex, count,
    509                                        contextCount, x, y, bidiFlags, *paint, typeface);
    510     env->ReleaseCharArrayElements(text, jchars, JNI_ABORT);
    511 }
    512 
    513 static void drawTextRunString(JNIEnv* env, jobject obj, jlong canvasHandle, jstring text,
    514                               jint start, jint end, jint contextStart, jint contextEnd,
    515                               jfloat x, jfloat y, jboolean isRtl, jlong paintHandle,
    516                               jlong typefaceHandle) {
    517     Paint* paint = reinterpret_cast<Paint*>(paintHandle);
    518     Typeface* typeface = reinterpret_cast<Typeface*>(typefaceHandle);
    519 
    520     int bidiFlags = isRtl ? kBidi_Force_RTL : kBidi_Force_LTR;
    521     jint count = end - start;
    522     jint contextCount = contextEnd - contextStart;
    523     const jchar* jchars = env->GetStringChars(text, NULL);
    524     get_canvas(canvasHandle)->drawText(jchars + contextStart, start - contextStart, count,
    525                                        contextCount, x, y, bidiFlags, *paint, typeface);
    526     env->ReleaseStringChars(text, jchars);
    527 }
    528 
    529 static void drawTextOnPathChars(JNIEnv* env, jobject, jlong canvasHandle, jcharArray text,
    530                                 jint index, jint count, jlong pathHandle, jfloat hOffset,
    531                                 jfloat vOffset, jint bidiFlags, jlong paintHandle,
    532                                 jlong typefaceHandle) {
    533     SkPath* path = reinterpret_cast<SkPath*>(pathHandle);
    534     Paint* paint = reinterpret_cast<Paint*>(paintHandle);
    535     Typeface* typeface = reinterpret_cast<Typeface*>(typefaceHandle);
    536 
    537     jchar* jchars = env->GetCharArrayElements(text, NULL);
    538 
    539     get_canvas(canvasHandle)->drawTextOnPath(jchars + index, count, bidiFlags, *path,
    540                    hOffset, vOffset, *paint, typeface);
    541 
    542     env->ReleaseCharArrayElements(text, jchars, 0);
    543 }
    544 
    545 static void drawTextOnPathString(JNIEnv* env, jobject, jlong canvasHandle, jstring text,
    546                                  jlong pathHandle, jfloat hOffset, jfloat vOffset,
    547                                  jint bidiFlags, jlong paintHandle, jlong typefaceHandle) {
    548     SkPath* path = reinterpret_cast<SkPath*>(pathHandle);
    549     Paint* paint = reinterpret_cast<Paint*>(paintHandle);
    550     Typeface* typeface = reinterpret_cast<Typeface*>(typefaceHandle);
    551 
    552     const jchar* jchars = env->GetStringChars(text, NULL);
    553     int count = env->GetStringLength(text);
    554 
    555     get_canvas(canvasHandle)->drawTextOnPath(jchars, count, bidiFlags, *path,
    556                    hOffset, vOffset, *paint, typeface);
    557 
    558     env->ReleaseStringChars(text, jchars);
    559 }
    560 
    561 static void setDrawFilter(JNIEnv* env, jobject, jlong canvasHandle, jlong filterHandle) {
    562     get_canvas(canvasHandle)->setDrawFilter(reinterpret_cast<SkDrawFilter*>(filterHandle));
    563 }
    564 
    565 static void freeCaches(JNIEnv* env, jobject) {
    566     SkGraphics::PurgeFontCache();
    567 }
    568 
    569 static void freeTextLayoutCaches(JNIEnv* env, jobject) {
    570     Layout::purgeCaches();
    571 }
    572 
    573 }; // namespace CanvasJNI
    574 
    575 static const JNINativeMethod gMethods[] = {
    576     {"getNativeFinalizer", "()J", (void*) CanvasJNI::getNativeFinalizer},
    577     {"initRaster", "(Landroid/graphics/Bitmap;)J", (void*) CanvasJNI::initRaster},
    578     {"native_setBitmap", "!(JLandroid/graphics/Bitmap;)V", (void*) CanvasJNI::setBitmap},
    579     {"native_isOpaque","!(J)Z", (void*) CanvasJNI::isOpaque},
    580     {"native_getWidth","!(J)I", (void*) CanvasJNI::getWidth},
    581     {"native_getHeight","!(J)I", (void*) CanvasJNI::getHeight},
    582     {"native_setHighContrastText","!(JZ)V", (void*) CanvasJNI::setHighContrastText},
    583     {"native_save","!(JI)I", (void*) CanvasJNI::save},
    584     {"native_saveLayer","!(JFFFFJI)I", (void*) CanvasJNI::saveLayer},
    585     {"native_saveLayerAlpha","!(JFFFFII)I", (void*) CanvasJNI::saveLayerAlpha},
    586     {"native_getSaveCount","!(J)I", (void*) CanvasJNI::getSaveCount},
    587     {"native_restore","!(JZ)V", (void*) CanvasJNI::restore},
    588     {"native_restoreToCount","!(JIZ)V", (void*) CanvasJNI::restoreToCount},
    589     {"native_getCTM", "!(JJ)V", (void*)CanvasJNI::getCTM},
    590     {"native_setMatrix","!(JJ)V", (void*) CanvasJNI::setMatrix},
    591     {"native_concat","!(JJ)V", (void*) CanvasJNI::concat},
    592     {"native_rotate","!(JF)V", (void*) CanvasJNI::rotate},
    593     {"native_scale","!(JFF)V", (void*) CanvasJNI::scale},
    594     {"native_skew","!(JFF)V", (void*) CanvasJNI::skew},
    595     {"native_translate","!(JFF)V", (void*) CanvasJNI::translate},
    596     {"native_getClipBounds","!(JLandroid/graphics/Rect;)Z", (void*) CanvasJNI::getClipBounds},
    597     {"native_quickReject","!(JJ)Z", (void*) CanvasJNI::quickRejectPath},
    598     {"native_quickReject","!(JFFFF)Z", (void*)CanvasJNI::quickRejectRect},
    599     {"native_clipRect","!(JFFFFI)Z", (void*) CanvasJNI::clipRect},
    600     {"native_clipPath","!(JJI)Z", (void*) CanvasJNI::clipPath},
    601     {"native_clipRegion","!(JJI)Z", (void*) CanvasJNI::clipRegion},
    602     {"native_drawColor","!(JII)V", (void*) CanvasJNI::drawColor},
    603     {"native_drawPaint","!(JJ)V", (void*) CanvasJNI::drawPaint},
    604     {"native_drawPoint", "!(JFFJ)V", (void*) CanvasJNI::drawPoint},
    605     {"native_drawPoints", "!(J[FIIJ)V", (void*) CanvasJNI::drawPoints},
    606     {"native_drawLine", "!(JFFFFJ)V", (void*) CanvasJNI::drawLine},
    607     {"native_drawLines", "!(J[FIIJ)V", (void*) CanvasJNI::drawLines},
    608     {"native_drawRect","!(JFFFFJ)V", (void*) CanvasJNI::drawRect},
    609     {"native_drawRegion", "!(JJJ)V", (void*) CanvasJNI::drawRegion },
    610     {"native_drawRoundRect","!(JFFFFFFJ)V", (void*) CanvasJNI::drawRoundRect},
    611     {"native_drawCircle","!(JFFFJ)V", (void*) CanvasJNI::drawCircle},
    612     {"native_drawOval","!(JFFFFJ)V", (void*) CanvasJNI::drawOval},
    613     {"native_drawArc","!(JFFFFFFZJ)V", (void*) CanvasJNI::drawArc},
    614     {"native_drawPath","!(JJJ)V", (void*) CanvasJNI::drawPath},
    615     {"nativeDrawVertices", "!(JII[FI[FI[II[SIIJ)V", (void*)CanvasJNI::drawVertices},
    616     {"native_drawNinePatch", "!(JJJFFFFJII)V", (void*)CanvasJNI::drawNinePatch},
    617     {"native_drawBitmap","!(JLandroid/graphics/Bitmap;FFJIII)V", (void*) CanvasJNI::drawBitmap},
    618     {"nativeDrawBitmapMatrix", "!(JLandroid/graphics/Bitmap;JJ)V", (void*)CanvasJNI::drawBitmapMatrix},
    619     {"native_drawBitmap","!(JLandroid/graphics/Bitmap;FFFFFFFFJII)V", (void*) CanvasJNI::drawBitmapRect},
    620     {"native_drawBitmap", "!(J[IIIFFIIZJ)V", (void*)CanvasJNI::drawBitmapArray},
    621     {"nativeDrawBitmapMesh", "!(JLandroid/graphics/Bitmap;II[FI[IIJ)V", (void*)CanvasJNI::drawBitmapMesh},
    622     {"native_drawText","!(J[CIIFFIJJ)V", (void*) CanvasJNI::drawTextChars},
    623     {"native_drawText","!(JLjava/lang/String;IIFFIJJ)V", (void*) CanvasJNI::drawTextString},
    624     {"native_drawTextRun","!(J[CIIIIFFZJJ)V", (void*) CanvasJNI::drawTextRunChars},
    625     {"native_drawTextRun","!(JLjava/lang/String;IIIIFFZJJ)V", (void*) CanvasJNI::drawTextRunString},
    626     {"native_drawTextOnPath","!(J[CIIJFFIJJ)V", (void*) CanvasJNI::drawTextOnPathChars},
    627     {"native_drawTextOnPath","!(JLjava/lang/String;JFFIJJ)V", (void*) CanvasJNI::drawTextOnPathString},
    628     {"nativeSetDrawFilter", "!(JJ)V", (void*) CanvasJNI::setDrawFilter},
    629     {"freeCaches", "()V", (void*) CanvasJNI::freeCaches},
    630     {"freeTextLayoutCaches", "()V", (void*) CanvasJNI::freeTextLayoutCaches}
    631 };
    632 
    633 int register_android_graphics_Canvas(JNIEnv* env) {
    634     return RegisterMethodsOrDie(env, "android/graphics/Canvas", gMethods, NELEM(gMethods));
    635 }
    636 
    637 }; // namespace android
    638