Home | History | Annotate | Download | only in graphics
      1 /*
      2  * Copyright (C) 2006-2007 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 <android_runtime/AndroidRuntime.h>
     20 
     21 #include "SkCanvas.h"
     22 #include "SkDevice.h"
     23 #include "SkGraphics.h"
     24 #include "SkImageRef_GlobalPool.h"
     25 #include "SkPorterDuff.h"
     26 #include "SkShader.h"
     27 #include "SkTemplates.h"
     28 
     29 #include "TextLayout.h"
     30 #include "TextLayoutCache.h"
     31 
     32 #include "unicode/ubidi.h"
     33 #include "unicode/ushape.h"
     34 
     35 #include <utils/Log.h>
     36 
     37 #define TIME_DRAWx
     38 
     39 static uint32_t get_thread_msec() {
     40 #if defined(HAVE_POSIX_CLOCKS)
     41     struct timespec tm;
     42 
     43     clock_gettime(CLOCK_THREAD_CPUTIME_ID, &tm);
     44 
     45     return tm.tv_sec * 1000LL + tm.tv_nsec / 1000000;
     46 #else
     47     struct timeval tv;
     48 
     49     gettimeofday(&tv, NULL);
     50     return tv.tv_sec * 1000LL + tv.tv_usec / 1000;
     51 #endif
     52 }
     53 
     54 namespace android {
     55 
     56 class SkCanvasGlue {
     57 public:
     58 
     59     static void finalizer(JNIEnv* env, jobject clazz, SkCanvas* canvas) {
     60         canvas->unref();
     61     }
     62 
     63     static SkCanvas* initRaster(JNIEnv* env, jobject, SkBitmap* bitmap) {
     64         return bitmap ? new SkCanvas(*bitmap) : new SkCanvas;
     65     }
     66 
     67     static void freeCaches(JNIEnv* env, jobject) {
     68         // these are called in no particular order
     69         SkImageRef_GlobalPool::SetRAMUsed(0);
     70         SkGraphics::SetFontCacheUsed(0);
     71     }
     72 
     73     static jboolean isOpaque(JNIEnv* env, jobject jcanvas) {
     74         NPE_CHECK_RETURN_ZERO(env, jcanvas);
     75         SkCanvas* canvas = GraphicsJNI::getNativeCanvas(env, jcanvas);
     76         return canvas->getDevice()->accessBitmap(false).isOpaque();
     77     }
     78 
     79     static int getWidth(JNIEnv* env, jobject jcanvas) {
     80         NPE_CHECK_RETURN_ZERO(env, jcanvas);
     81         SkCanvas* canvas = GraphicsJNI::getNativeCanvas(env, jcanvas);
     82         return canvas->getDevice()->accessBitmap(false).width();
     83     }
     84 
     85     static int getHeight(JNIEnv* env, jobject jcanvas) {
     86         NPE_CHECK_RETURN_ZERO(env, jcanvas);
     87         SkCanvas* canvas = GraphicsJNI::getNativeCanvas(env, jcanvas);
     88         return canvas->getDevice()->accessBitmap(false).height();
     89     }
     90 
     91     static void setBitmap(JNIEnv* env, jobject, SkCanvas* canvas, SkBitmap* bitmap) {
     92         if (bitmap) {
     93             canvas->setBitmapDevice(*bitmap);
     94         } else {
     95             canvas->setDevice(NULL);
     96         }
     97     }
     98 
     99     static int saveAll(JNIEnv* env, jobject jcanvas) {
    100         NPE_CHECK_RETURN_ZERO(env, jcanvas);
    101         return GraphicsJNI::getNativeCanvas(env, jcanvas)->save();
    102     }
    103 
    104     static int save(JNIEnv* env, jobject jcanvas, SkCanvas::SaveFlags flags) {
    105         NPE_CHECK_RETURN_ZERO(env, jcanvas);
    106         return GraphicsJNI::getNativeCanvas(env, jcanvas)->save(flags);
    107     }
    108 
    109     static int saveLayer(JNIEnv* env, jobject, SkCanvas* canvas, jobject bounds,
    110                          SkPaint* paint, int flags) {
    111         SkRect* bounds_ = NULL;
    112         SkRect  storage;
    113         if (bounds != NULL) {
    114             GraphicsJNI::jrectf_to_rect(env, bounds, &storage);
    115             bounds_ = &storage;
    116         }
    117         return canvas->saveLayer(bounds_, paint, (SkCanvas::SaveFlags)flags);
    118     }
    119 
    120     static int saveLayer4F(JNIEnv* env, jobject, SkCanvas* canvas,
    121                            jfloat l, jfloat t, jfloat r, jfloat b,
    122                            SkPaint* paint, int flags) {
    123         SkRect bounds;
    124         bounds.set(SkFloatToScalar(l), SkFloatToScalar(t), SkFloatToScalar(r),
    125                    SkFloatToScalar(b));
    126         return canvas->saveLayer(&bounds, paint, (SkCanvas::SaveFlags)flags);
    127     }
    128 
    129     static int saveLayerAlpha(JNIEnv* env, jobject, SkCanvas* canvas,
    130                               jobject bounds, int alpha, int flags) {
    131         SkRect* bounds_ = NULL;
    132         SkRect  storage;
    133         if (bounds != NULL) {
    134             GraphicsJNI::jrectf_to_rect(env, bounds, &storage);
    135             bounds_ = &storage;
    136         }
    137         return canvas->saveLayerAlpha(bounds_, alpha,
    138                                       (SkCanvas::SaveFlags)flags);
    139     }
    140 
    141     static int saveLayerAlpha4F(JNIEnv* env, jobject, SkCanvas* canvas,
    142                                 jfloat l, jfloat t, jfloat r, jfloat b,
    143                                 int alpha, int flags) {
    144         SkRect  bounds;
    145         bounds.set(SkFloatToScalar(l), SkFloatToScalar(t), SkFloatToScalar(r),
    146                    SkFloatToScalar(b));
    147         return canvas->saveLayerAlpha(&bounds, alpha,
    148                                       (SkCanvas::SaveFlags)flags);
    149     }
    150 
    151     static void restore(JNIEnv* env, jobject jcanvas) {
    152         NPE_CHECK_RETURN_VOID(env, jcanvas);
    153         SkCanvas* canvas = GraphicsJNI::getNativeCanvas(env, jcanvas);
    154         if (canvas->getSaveCount() <= 1) {  // cannot restore anymore
    155             doThrowISE(env, "Underflow in restore");
    156             return;
    157         }
    158         canvas->restore();
    159     }
    160 
    161     static int getSaveCount(JNIEnv* env, jobject jcanvas) {
    162         NPE_CHECK_RETURN_ZERO(env, jcanvas);
    163         return GraphicsJNI::getNativeCanvas(env, jcanvas)->getSaveCount();
    164     }
    165 
    166     static void restoreToCount(JNIEnv* env, jobject jcanvas, int restoreCount) {
    167         NPE_CHECK_RETURN_VOID(env, jcanvas);
    168         SkCanvas* canvas = GraphicsJNI::getNativeCanvas(env, jcanvas);
    169         if (restoreCount < 1) {
    170             doThrowIAE(env, "Underflow in restoreToCount");
    171             return;
    172         }
    173         canvas->restoreToCount(restoreCount);
    174     }
    175 
    176     static void translate(JNIEnv* env, jobject jcanvas, jfloat dx, jfloat dy) {
    177         NPE_CHECK_RETURN_VOID(env, jcanvas);
    178         SkScalar dx_ = SkFloatToScalar(dx);
    179         SkScalar dy_ = SkFloatToScalar(dy);
    180         (void)GraphicsJNI::getNativeCanvas(env, jcanvas)->translate(dx_, dy_);
    181     }
    182 
    183     static void scale__FF(JNIEnv* env, jobject jcanvas, jfloat sx, jfloat sy) {
    184         NPE_CHECK_RETURN_VOID(env, jcanvas);
    185         SkScalar sx_ = SkFloatToScalar(sx);
    186         SkScalar sy_ = SkFloatToScalar(sy);
    187         (void)GraphicsJNI::getNativeCanvas(env, jcanvas)->scale(sx_, sy_);
    188     }
    189 
    190     static void rotate__F(JNIEnv* env, jobject jcanvas, jfloat degrees) {
    191         NPE_CHECK_RETURN_VOID(env, jcanvas);
    192         SkScalar degrees_ = SkFloatToScalar(degrees);
    193         (void)GraphicsJNI::getNativeCanvas(env, jcanvas)->rotate(degrees_);
    194     }
    195 
    196     static void skew__FF(JNIEnv* env, jobject jcanvas, jfloat sx, jfloat sy) {
    197         NPE_CHECK_RETURN_VOID(env, jcanvas);
    198         SkScalar sx_ = SkFloatToScalar(sx);
    199         SkScalar sy_ = SkFloatToScalar(sy);
    200         (void)GraphicsJNI::getNativeCanvas(env, jcanvas)->skew(sx_, sy_);
    201     }
    202 
    203     static void concat(JNIEnv* env, jobject, SkCanvas* canvas,
    204                        const SkMatrix* matrix) {
    205         canvas->concat(*matrix);
    206     }
    207 
    208     static void setMatrix(JNIEnv* env, jobject, SkCanvas* canvas,
    209                           const SkMatrix* matrix) {
    210         if (NULL == matrix) {
    211             canvas->resetMatrix();
    212         } else {
    213             canvas->setMatrix(*matrix);
    214         }
    215     }
    216 
    217     static jboolean clipRect_FFFF(JNIEnv* env, jobject jcanvas, jfloat left,
    218                                   jfloat top, jfloat right, jfloat bottom) {
    219         NPE_CHECK_RETURN_ZERO(env, jcanvas);
    220         SkRect  r;
    221         r.set(SkFloatToScalar(left), SkFloatToScalar(top),
    222               SkFloatToScalar(right), SkFloatToScalar(bottom));
    223         SkCanvas* c = GraphicsJNI::getNativeCanvas(env, jcanvas);
    224         return c->clipRect(r);
    225     }
    226 
    227     static jboolean clipRect_IIII(JNIEnv* env, jobject jcanvas, jint left,
    228                                   jint top, jint right, jint bottom) {
    229         NPE_CHECK_RETURN_ZERO(env, jcanvas);
    230         SkRect  r;
    231         r.set(SkIntToScalar(left), SkIntToScalar(top),
    232               SkIntToScalar(right), SkIntToScalar(bottom));
    233         return GraphicsJNI::getNativeCanvas(env, jcanvas)->clipRect(r);
    234     }
    235 
    236     static jboolean clipRect_RectF(JNIEnv* env, jobject jcanvas, jobject rectf) {
    237         NPE_CHECK_RETURN_ZERO(env, jcanvas);
    238         NPE_CHECK_RETURN_ZERO(env, rectf);
    239         SkCanvas* c = GraphicsJNI::getNativeCanvas(env, jcanvas);
    240         SkRect tmp;
    241         return c->clipRect(*GraphicsJNI::jrectf_to_rect(env, rectf, &tmp));
    242     }
    243 
    244     static jboolean clipRect_Rect(JNIEnv* env, jobject jcanvas, jobject rect) {
    245         NPE_CHECK_RETURN_ZERO(env, jcanvas);
    246         NPE_CHECK_RETURN_ZERO(env, rect);
    247         SkCanvas* c = GraphicsJNI::getNativeCanvas(env, jcanvas);
    248         SkRect tmp;
    249         return c->clipRect(*GraphicsJNI::jrect_to_rect(env, rect, &tmp));
    250     }
    251 
    252     static jboolean clipRect(JNIEnv* env, jobject, SkCanvas* canvas,
    253                              float left, float top, float right, float bottom,
    254                              int op) {
    255         SkRect rect;
    256         rect.set(SkFloatToScalar(left), SkFloatToScalar(top),
    257                  SkFloatToScalar(right), SkFloatToScalar(bottom));
    258         return canvas->clipRect(rect, (SkRegion::Op)op);
    259     }
    260 
    261     static jboolean clipPath(JNIEnv* env, jobject, SkCanvas* canvas,
    262                              SkPath* path, int op) {
    263         return canvas->clipPath(*path, (SkRegion::Op)op);
    264     }
    265 
    266     static jboolean clipRegion(JNIEnv* env, jobject, SkCanvas* canvas,
    267                                SkRegion* deviceRgn, int op) {
    268         return canvas->clipRegion(*deviceRgn, (SkRegion::Op)op);
    269     }
    270 
    271     static void setDrawFilter(JNIEnv* env, jobject, SkCanvas* canvas,
    272                               SkDrawFilter* filter) {
    273         canvas->setDrawFilter(filter);
    274     }
    275 
    276     static jboolean quickReject__RectFI(JNIEnv* env, jobject, SkCanvas* canvas,
    277                                         jobject rect, int edgetype) {
    278         SkRect rect_;
    279         GraphicsJNI::jrectf_to_rect(env, rect, &rect_);
    280         return canvas->quickReject(rect_, (SkCanvas::EdgeType)edgetype);
    281     }
    282 
    283     static jboolean quickReject__PathI(JNIEnv* env, jobject, SkCanvas* canvas,
    284                                        SkPath* path, int edgetype) {
    285         return canvas->quickReject(*path, (SkCanvas::EdgeType)edgetype);
    286     }
    287 
    288     static jboolean quickReject__FFFFI(JNIEnv* env, jobject, SkCanvas* canvas,
    289                                        jfloat left, jfloat top, jfloat right,
    290                                        jfloat bottom, int edgetype) {
    291         SkRect r;
    292         r.set(SkFloatToScalar(left), SkFloatToScalar(top),
    293               SkFloatToScalar(right), SkFloatToScalar(bottom));
    294         return canvas->quickReject(r, (SkCanvas::EdgeType)edgetype);
    295     }
    296 
    297     static void drawRGB(JNIEnv* env, jobject, SkCanvas* canvas,
    298                         jint r, jint g, jint b) {
    299         canvas->drawARGB(0xFF, r, g, b);
    300     }
    301 
    302     static void drawARGB(JNIEnv* env, jobject, SkCanvas* canvas,
    303                          jint a, jint r, jint g, jint b) {
    304         canvas->drawARGB(a, r, g, b);
    305     }
    306 
    307     static void drawColor__I(JNIEnv* env, jobject, SkCanvas* canvas,
    308                              jint color) {
    309         canvas->drawColor(color);
    310     }
    311 
    312     static void drawColor__II(JNIEnv* env, jobject, SkCanvas* canvas,
    313                               jint color, SkPorterDuff::Mode mode) {
    314         canvas->drawColor(color, SkPorterDuff::ToXfermodeMode(mode));
    315     }
    316 
    317     static void drawPaint(JNIEnv* env, jobject, SkCanvas* canvas,
    318                           SkPaint* paint) {
    319         canvas->drawPaint(*paint);
    320     }
    321 
    322     static void doPoints(JNIEnv* env, jobject jcanvas, jfloatArray jptsArray,
    323                          jint offset, jint count, jobject jpaint,
    324                          SkCanvas::PointMode mode) {
    325         NPE_CHECK_RETURN_VOID(env, jcanvas);
    326         NPE_CHECK_RETURN_VOID(env, jptsArray);
    327         NPE_CHECK_RETURN_VOID(env, jpaint);
    328         SkCanvas* canvas = GraphicsJNI::getNativeCanvas(env, jcanvas);
    329         const SkPaint& paint = *GraphicsJNI::getNativePaint(env, jpaint);
    330 
    331         AutoJavaFloatArray autoPts(env, jptsArray);
    332         float* floats = autoPts.ptr();
    333         const int length = autoPts.length();
    334 
    335         if ((offset | count) < 0 || offset + count > length) {
    336             doThrowAIOOBE(env);
    337             return;
    338         }
    339 
    340         // now convert the floats into SkPoints
    341         count >>= 1;    // now it is the number of points
    342         SkAutoSTMalloc<32, SkPoint> storage(count);
    343         SkPoint* pts = storage.get();
    344         const float* src = floats + offset;
    345         for (int i = 0; i < count; i++) {
    346             pts[i].set(SkFloatToScalar(src[0]), SkFloatToScalar(src[1]));
    347             src += 2;
    348         }
    349         canvas->drawPoints(mode, count, pts, paint);
    350     }
    351 
    352     static void drawPoints(JNIEnv* env, jobject jcanvas, jfloatArray jptsArray,
    353                            jint offset, jint count, jobject jpaint) {
    354         doPoints(env, jcanvas, jptsArray, offset, count, jpaint,
    355                  SkCanvas::kPoints_PointMode);
    356     }
    357 
    358     static void drawLines(JNIEnv* env, jobject jcanvas, jfloatArray jptsArray,
    359                            jint offset, jint count, jobject jpaint) {
    360         doPoints(env, jcanvas, jptsArray, offset, count, jpaint,
    361                  SkCanvas::kLines_PointMode);
    362     }
    363 
    364     static void drawPoint(JNIEnv* env, jobject jcanvas, float x, float y,
    365                           jobject jpaint) {
    366         NPE_CHECK_RETURN_VOID(env, jcanvas);
    367         NPE_CHECK_RETURN_VOID(env, jpaint);
    368         SkCanvas* canvas = GraphicsJNI::getNativeCanvas(env, jcanvas);
    369         const SkPaint& paint = *GraphicsJNI::getNativePaint(env, jpaint);
    370 
    371         canvas->drawPoint(SkFloatToScalar(x), SkFloatToScalar(y), paint);
    372     }
    373 
    374     static void drawLine__FFFFPaint(JNIEnv* env, jobject, SkCanvas* canvas,
    375                                     jfloat startX, jfloat startY, jfloat stopX,
    376                                     jfloat stopY, SkPaint* paint) {
    377         canvas->drawLine(SkFloatToScalar(startX), SkFloatToScalar(startY),
    378                          SkFloatToScalar(stopX), SkFloatToScalar(stopY),
    379                          *paint);
    380     }
    381 
    382     static void drawRect__RectFPaint(JNIEnv* env, jobject, SkCanvas* canvas,
    383                                      jobject rect, SkPaint* paint) {
    384         SkRect rect_;
    385         GraphicsJNI::jrectf_to_rect(env, rect, &rect_);
    386         canvas->drawRect(rect_, *paint);
    387     }
    388 
    389     static void drawRect__FFFFPaint(JNIEnv* env, jobject, SkCanvas* canvas,
    390                                     jfloat left, jfloat top, jfloat right,
    391                                     jfloat bottom, SkPaint* paint) {
    392         SkScalar left_ = SkFloatToScalar(left);
    393         SkScalar top_ = SkFloatToScalar(top);
    394         SkScalar right_ = SkFloatToScalar(right);
    395         SkScalar bottom_ = SkFloatToScalar(bottom);
    396         canvas->drawRectCoords(left_, top_, right_, bottom_, *paint);
    397     }
    398 
    399     static void drawOval(JNIEnv* env, jobject, SkCanvas* canvas, jobject joval,
    400                          SkPaint* paint) {
    401         SkRect oval;
    402         GraphicsJNI::jrectf_to_rect(env, joval, &oval);
    403         canvas->drawOval(oval, *paint);
    404     }
    405 
    406     static void drawCircle(JNIEnv* env, jobject, SkCanvas* canvas, jfloat cx,
    407                            jfloat cy, jfloat radius, SkPaint* paint) {
    408         canvas->drawCircle(SkFloatToScalar(cx), SkFloatToScalar(cy),
    409                            SkFloatToScalar(radius), *paint);
    410     }
    411 
    412     static void drawArc(JNIEnv* env, jobject, SkCanvas* canvas, jobject joval,
    413                         jfloat startAngle, jfloat sweepAngle,
    414                         jboolean useCenter, SkPaint* paint) {
    415         SkRect oval;
    416         GraphicsJNI::jrectf_to_rect(env, joval, &oval);
    417         canvas->drawArc(oval, SkFloatToScalar(startAngle),
    418                         SkFloatToScalar(sweepAngle), useCenter, *paint);
    419     }
    420 
    421     static void drawRoundRect(JNIEnv* env, jobject, SkCanvas* canvas,
    422                               jobject jrect, jfloat rx, jfloat ry,
    423                               SkPaint* paint) {
    424         SkRect rect;
    425         GraphicsJNI::jrectf_to_rect(env, jrect, &rect);
    426         canvas->drawRoundRect(rect, SkFloatToScalar(rx), SkFloatToScalar(ry),
    427                               *paint);
    428     }
    429 
    430     static void drawPath(JNIEnv* env, jobject, SkCanvas* canvas, SkPath* path,
    431                          SkPaint* paint) {
    432         canvas->drawPath(*path, *paint);
    433     }
    434 
    435     static void drawPicture(JNIEnv* env, jobject, SkCanvas* canvas,
    436                             SkPicture* picture) {
    437         SkASSERT(canvas);
    438         SkASSERT(picture);
    439 
    440 #ifdef TIME_DRAW
    441         SkMSec now = get_thread_msec(); //SkTime::GetMSecs();
    442 #endif
    443         canvas->drawPicture(*picture);
    444 #ifdef TIME_DRAW
    445         LOGD("---- picture playback %d ms\n", get_thread_msec() - now);
    446 #endif
    447     }
    448 
    449     static void drawBitmap__BitmapFFPaint(JNIEnv* env, jobject jcanvas,
    450                                           SkCanvas* canvas, SkBitmap* bitmap,
    451                                           jfloat left, jfloat top,
    452                                           SkPaint* paint, jint canvasDensity,
    453                                           jint screenDensity, jint bitmapDensity) {
    454         SkScalar left_ = SkFloatToScalar(left);
    455         SkScalar top_ = SkFloatToScalar(top);
    456 
    457         if (canvasDensity == bitmapDensity || canvasDensity == 0
    458                 || bitmapDensity == 0) {
    459             if (screenDensity != 0 && screenDensity != bitmapDensity) {
    460                 SkPaint filteredPaint;
    461                 if (paint) {
    462                     filteredPaint = *paint;
    463                 }
    464                 filteredPaint.setFilterBitmap(true);
    465                 canvas->drawBitmap(*bitmap, left_, top_, &filteredPaint);
    466             } else {
    467                 canvas->drawBitmap(*bitmap, left_, top_, paint);
    468             }
    469         } else {
    470             canvas->save();
    471             SkScalar scale = SkFloatToScalar(canvasDensity / (float)bitmapDensity);
    472             canvas->translate(left_, top_);
    473             canvas->scale(scale, scale);
    474 
    475             SkPaint filteredPaint;
    476             if (paint) {
    477                 filteredPaint = *paint;
    478             }
    479             filteredPaint.setFilterBitmap(true);
    480 
    481             canvas->drawBitmap(*bitmap, 0, 0, &filteredPaint);
    482 
    483             canvas->restore();
    484         }
    485     }
    486 
    487     static void doDrawBitmap(JNIEnv* env, SkCanvas* canvas, SkBitmap* bitmap,
    488                         jobject srcIRect, const SkRect& dst, SkPaint* paint,
    489                         jint screenDensity, jint bitmapDensity) {
    490         SkIRect    src, *srcPtr = NULL;
    491 
    492         if (NULL != srcIRect) {
    493             GraphicsJNI::jrect_to_irect(env, srcIRect, &src);
    494             srcPtr = &src;
    495         }
    496 
    497         if (screenDensity != 0 && screenDensity != bitmapDensity) {
    498             SkPaint filteredPaint;
    499             if (paint) {
    500                 filteredPaint = *paint;
    501             }
    502             filteredPaint.setFilterBitmap(true);
    503             canvas->drawBitmapRect(*bitmap, srcPtr, dst, &filteredPaint);
    504         } else {
    505             canvas->drawBitmapRect(*bitmap, srcPtr, dst, paint);
    506         }
    507     }
    508 
    509     static void drawBitmapRF(JNIEnv* env, jobject, SkCanvas* canvas,
    510                              SkBitmap* bitmap, jobject srcIRect,
    511                              jobject dstRectF, SkPaint* paint,
    512                              jint screenDensity, jint bitmapDensity) {
    513         SkRect      dst;
    514         GraphicsJNI::jrectf_to_rect(env, dstRectF, &dst);
    515         doDrawBitmap(env, canvas, bitmap, srcIRect, dst, paint,
    516                 screenDensity, bitmapDensity);
    517     }
    518 
    519     static void drawBitmapRR(JNIEnv* env, jobject, SkCanvas* canvas,
    520                              SkBitmap* bitmap, jobject srcIRect,
    521                              jobject dstRect, SkPaint* paint,
    522                              jint screenDensity, jint bitmapDensity) {
    523         SkRect      dst;
    524         GraphicsJNI::jrect_to_rect(env, dstRect, &dst);
    525         doDrawBitmap(env, canvas, bitmap, srcIRect, dst, paint,
    526                 screenDensity, bitmapDensity);
    527     }
    528 
    529     static void drawBitmapArray(JNIEnv* env, jobject, SkCanvas* canvas,
    530                                 jintArray jcolors, int offset, int stride,
    531                                 jfloat x, jfloat y, int width, int height,
    532                                 jboolean hasAlpha, SkPaint* paint)
    533     {
    534         SkBitmap    bitmap;
    535 
    536         bitmap.setConfig(hasAlpha ? SkBitmap::kARGB_8888_Config :
    537                          SkBitmap::kRGB_565_Config, width, height);
    538         if (!bitmap.allocPixels()) {
    539             return;
    540         }
    541 
    542         if (!GraphicsJNI::SetPixels(env, jcolors, offset, stride,
    543                                     0, 0, width, height, bitmap)) {
    544             return;
    545         }
    546 
    547         canvas->drawBitmap(bitmap, SkFloatToScalar(x), SkFloatToScalar(y),
    548                            paint);
    549     }
    550 
    551     static void drawBitmapMatrix(JNIEnv* env, jobject, SkCanvas* canvas,
    552                                  const SkBitmap* bitmap, const SkMatrix* matrix,
    553                                  const SkPaint* paint) {
    554         canvas->drawBitmapMatrix(*bitmap, *matrix, paint);
    555     }
    556 
    557     static void drawBitmapMesh(JNIEnv* env, jobject, SkCanvas* canvas,
    558                           const SkBitmap* bitmap, int meshWidth, int meshHeight,
    559                           jfloatArray jverts, int vertIndex, jintArray jcolors,
    560                           int colorIndex, const SkPaint* paint) {
    561 
    562         const int ptCount = (meshWidth + 1) * (meshHeight + 1);
    563         const int indexCount = meshWidth * meshHeight * 6;
    564 
    565         AutoJavaFloatArray  vertA(env, jverts, vertIndex + (ptCount << 1));
    566         AutoJavaIntArray    colorA(env, jcolors, colorIndex + ptCount);
    567 
    568         /*  Our temp storage holds 2 or 3 arrays.
    569             texture points [ptCount * sizeof(SkPoint)]
    570             optionally vertex points [ptCount * sizeof(SkPoint)] if we need a
    571                 copy to convert from float to fixed
    572             indices [ptCount * sizeof(uint16_t)]
    573         */
    574         ssize_t storageSize = ptCount * sizeof(SkPoint); // texs[]
    575 #ifdef SK_SCALAR_IS_FIXED
    576         storageSize += ptCount * sizeof(SkPoint);  // storage for verts
    577 #endif
    578         storageSize += indexCount * sizeof(uint16_t);  // indices[]
    579 
    580         SkAutoMalloc storage(storageSize);
    581         SkPoint* texs = (SkPoint*)storage.get();
    582         SkPoint* verts;
    583         uint16_t* indices;
    584 #ifdef SK_SCALAR_IS_FLOAT
    585         verts = (SkPoint*)(vertA.ptr() + vertIndex);
    586         indices = (uint16_t*)(texs + ptCount);
    587 #else
    588         verts = texs + ptCount;
    589         indices = (uint16_t*)(verts + ptCount);
    590         // convert floats to fixed
    591         {
    592             const float* src = vertA.ptr() + vertIndex;
    593             for (int i = 0; i < ptCount; i++) {
    594                 verts[i].set(SkFloatToFixed(src[0]), SkFloatToFixed(src[1]));
    595                 src += 2;
    596             }
    597         }
    598 #endif
    599 
    600         // cons up texture coordinates and indices
    601         {
    602             const SkScalar w = SkIntToScalar(bitmap->width());
    603             const SkScalar h = SkIntToScalar(bitmap->height());
    604             const SkScalar dx = w / meshWidth;
    605             const SkScalar dy = h / meshHeight;
    606 
    607             SkPoint* texsPtr = texs;
    608             SkScalar y = 0;
    609             for (int i = 0; i <= meshHeight; i++) {
    610                 if (i == meshHeight) {
    611                     y = h;  // to ensure numerically we hit h exactly
    612                 }
    613                 SkScalar x = 0;
    614                 for (int j = 0; j < meshWidth; j++) {
    615                     texsPtr->set(x, y);
    616                     texsPtr += 1;
    617                     x += dx;
    618                 }
    619                 texsPtr->set(w, y);
    620                 texsPtr += 1;
    621                 y += dy;
    622             }
    623             SkASSERT(texsPtr - texs == ptCount);
    624         }
    625 
    626         // cons up indices
    627         {
    628             uint16_t* indexPtr = indices;
    629             int index = 0;
    630             for (int i = 0; i < meshHeight; i++) {
    631                 for (int j = 0; j < meshWidth; j++) {
    632                     // lower-left triangle
    633                     *indexPtr++ = index;
    634                     *indexPtr++ = index + meshWidth + 1;
    635                     *indexPtr++ = index + meshWidth + 2;
    636                     // upper-right triangle
    637                     *indexPtr++ = index;
    638                     *indexPtr++ = index + meshWidth + 2;
    639                     *indexPtr++ = index + 1;
    640                     // bump to the next cell
    641                     index += 1;
    642                 }
    643                 // bump to the next row
    644                 index += 1;
    645             }
    646             SkASSERT(indexPtr - indices == indexCount);
    647             SkASSERT((char*)indexPtr - (char*)storage.get() == storageSize);
    648         }
    649 
    650         // double-check that we have legal indices
    651 #ifdef SK_DEBUG
    652         {
    653             for (int i = 0; i < indexCount; i++) {
    654                 SkASSERT((unsigned)indices[i] < (unsigned)ptCount);
    655             }
    656         }
    657 #endif
    658 
    659         // cons-up a shader for the bitmap
    660         SkPaint tmpPaint;
    661         if (paint) {
    662             tmpPaint = *paint;
    663         }
    664         SkShader* shader = SkShader::CreateBitmapShader(*bitmap,
    665                         SkShader::kClamp_TileMode, SkShader::kClamp_TileMode);
    666         SkSafeUnref(tmpPaint.setShader(shader));
    667 
    668         canvas->drawVertices(SkCanvas::kTriangles_VertexMode, ptCount, verts,
    669                              texs, (const SkColor*)colorA.ptr(), NULL, indices,
    670                              indexCount, tmpPaint);
    671     }
    672 
    673     static void drawVertices(JNIEnv* env, jobject, SkCanvas* canvas,
    674                              SkCanvas::VertexMode mode, int vertexCount,
    675                              jfloatArray jverts, int vertIndex,
    676                              jfloatArray jtexs, int texIndex,
    677                              jintArray jcolors, int colorIndex,
    678                              jshortArray jindices, int indexIndex,
    679                              int indexCount, const SkPaint* paint) {
    680 
    681         AutoJavaFloatArray  vertA(env, jverts, vertIndex + vertexCount);
    682         AutoJavaFloatArray  texA(env, jtexs, texIndex + vertexCount);
    683         AutoJavaIntArray    colorA(env, jcolors, colorIndex + vertexCount);
    684         AutoJavaShortArray  indexA(env, jindices, indexIndex + indexCount);
    685 
    686         const int ptCount = vertexCount >> 1;
    687 
    688         SkPoint* verts;
    689         SkPoint* texs = NULL;
    690 #ifdef SK_SCALAR_IS_FLOAT
    691         verts = (SkPoint*)(vertA.ptr() + vertIndex);
    692         if (jtexs != NULL) {
    693             texs = (SkPoint*)(texA.ptr() + texIndex);
    694         }
    695 #else
    696         int count = ptCount;    // for verts
    697         if (jtexs != NULL) {
    698             count += ptCount;   // += for texs
    699         }
    700         SkAutoMalloc storage(count * sizeof(SkPoint));
    701         verts = (SkPoint*)storage.get();
    702         const float* src = vertA.ptr() + vertIndex;
    703         for (int i = 0; i < ptCount; i++) {
    704             verts[i].set(SkFloatToFixed(src[0]), SkFloatToFixed(src[1]));
    705             src += 2;
    706         }
    707         if (jtexs != NULL) {
    708             texs = verts + ptCount;
    709             src = texA.ptr() + texIndex;
    710             for (int i = 0; i < ptCount; i++) {
    711                 texs[i].set(SkFloatToFixed(src[0]), SkFloatToFixed(src[1]));
    712                 src += 2;
    713             }
    714         }
    715 #endif
    716 
    717         const SkColor* colors = NULL;
    718         const uint16_t* indices = NULL;
    719         if (jcolors != NULL) {
    720             colors = (const SkColor*)(colorA.ptr() + colorIndex);
    721         }
    722         if (jindices != NULL) {
    723             indices = (const uint16_t*)(indexA.ptr() + indexIndex);
    724         }
    725 
    726         canvas->drawVertices(mode, ptCount, verts, texs, colors, NULL,
    727                              indices, indexCount, *paint);
    728     }
    729 
    730 
    731     static void drawText___CIIFFIPaint(JNIEnv* env, jobject, SkCanvas* canvas,
    732                                       jcharArray text, int index, int count,
    733                                       jfloat x, jfloat y, int flags, SkPaint* paint) {
    734         jchar* textArray = env->GetCharArrayElements(text, NULL);
    735 #if RTL_USE_HARFBUZZ
    736         drawTextWithGlyphs(canvas, textArray + index, 0, count, x, y, flags, paint);
    737 #else
    738         TextLayout::drawText(paint, textArray + index, count, flags, x, y, canvas);
    739 #endif
    740         env->ReleaseCharArrayElements(text, textArray, JNI_ABORT);
    741     }
    742 
    743     static void drawText__StringIIFFIPaint(JNIEnv* env, jobject,
    744                                           SkCanvas* canvas, jstring text,
    745                                           int start, int end,
    746                                           jfloat x, jfloat y, int flags, SkPaint* paint) {
    747         const jchar* textArray = env->GetStringChars(text, NULL);
    748 #if RTL_USE_HARFBUZZ
    749         drawTextWithGlyphs(canvas, textArray, start, end, x, y, flags, paint);
    750 #else
    751         TextLayout::drawText(paint, textArray + start, end - start, flags, x, y, canvas);
    752 #endif
    753         env->ReleaseStringChars(text, textArray);
    754     }
    755 
    756     static void drawTextWithGlyphs(SkCanvas* canvas, const jchar* textArray,
    757             int start, int end,
    758             jfloat x, jfloat y, int flags, SkPaint* paint) {
    759 
    760         jint count = end - start;
    761         drawTextWithGlyphs(canvas, textArray + start, 0, count, count, x, y, flags, paint);
    762     }
    763 
    764     static void drawTextWithGlyphs(SkCanvas* canvas, const jchar* textArray,
    765             int start, int count, int contextCount,
    766             jfloat x, jfloat y, int flags, SkPaint* paint) {
    767 
    768         sp<TextLayoutCacheValue> value;
    769 #if USE_TEXT_LAYOUT_CACHE
    770         value = TextLayoutCache::getInstance().getValue(paint, textArray, start, count,
    771                 contextCount, flags);
    772         if (value == NULL) {
    773             LOGE("Cannot get TextLayoutCache value");
    774             return ;
    775         }
    776 #else
    777         value = new TextLayoutCacheValue();
    778         value->computeValues(paint, textArray, start, count, contextCount, flags);
    779 #endif
    780         doDrawGlyphs(canvas, value->getGlyphs(), 0, value->getGlyphsCount(), x, y, flags, paint);
    781     }
    782 
    783     static void doDrawGlyphs(SkCanvas* canvas, const jchar* glyphArray, int index, int count,
    784             jfloat x, jfloat y, int flags, SkPaint* paint) {
    785         // TODO: need to suppress this code after the GL renderer is modified for not
    786         // copying the paint
    787 
    788         // Save old text encoding
    789         SkPaint::TextEncoding oldEncoding = paint->getTextEncoding();
    790         // Define Glyph encoding
    791         paint->setTextEncoding(SkPaint::kGlyphID_TextEncoding);
    792 
    793         canvas->drawText(glyphArray + index * 2, count * 2, x, y, *paint);
    794 
    795         // Get back old encoding
    796         paint->setTextEncoding(oldEncoding);
    797     }
    798 
    799     static void drawTextRun___CIIIIFFIPaint(
    800         JNIEnv* env, jobject, SkCanvas* canvas, jcharArray text, int index,
    801         int count, int contextIndex, int contextCount,
    802         jfloat x, jfloat y, int dirFlags, SkPaint* paint) {
    803 
    804         jchar* chars = env->GetCharArrayElements(text, NULL);
    805 #if RTL_USE_HARFBUZZ
    806         drawTextWithGlyphs(canvas, chars + contextIndex, index - contextIndex,
    807                 count, contextCount, x, y, dirFlags, paint);
    808 #else
    809         TextLayout::drawTextRun(paint, chars + contextIndex, index - contextIndex,
    810                 count, contextCount, dirFlags, x, y, canvas);
    811 #endif
    812         env->ReleaseCharArrayElements(text, chars, JNI_ABORT);
    813     }
    814 
    815     static void drawTextRun__StringIIIIFFIPaint(
    816         JNIEnv* env, jobject obj, SkCanvas* canvas, jstring text, jint start,
    817         jint end, jint contextStart, jint contextEnd,
    818         jfloat x, jfloat y, jint dirFlags, SkPaint* paint) {
    819 
    820         jint count = end - start;
    821         jint contextCount = contextEnd - contextStart;
    822         const jchar* chars = env->GetStringChars(text, NULL);
    823 #if RTL_USE_HARFBUZZ
    824         drawTextWithGlyphs(canvas, chars + contextStart, start - contextStart,
    825                 count, contextCount, x, y, dirFlags, paint);
    826 #else
    827         TextLayout::drawTextRun(paint, chars + contextStart, start - contextStart,
    828                 count, contextCount, dirFlags, x, y, canvas);
    829 #endif
    830         env->ReleaseStringChars(text, chars);
    831     }
    832 
    833     static void drawPosText___CII_FPaint(JNIEnv* env, jobject, SkCanvas* canvas,
    834                                          jcharArray text, int index, int count,
    835                                          jfloatArray pos, SkPaint* paint) {
    836         jchar* textArray = text ? env->GetCharArrayElements(text, NULL) : NULL;
    837         jsize textCount = text ? env->GetArrayLength(text) : NULL;
    838         float* posArray = pos ? env->GetFloatArrayElements(pos, NULL) : NULL;
    839         int posCount = pos ? env->GetArrayLength(pos) >> 1: 0;
    840         SkPoint* posPtr = posCount > 0 ? new SkPoint[posCount] : NULL;
    841         int indx;
    842         for (indx = 0; indx < posCount; indx++) {
    843             posPtr[indx].fX = SkFloatToScalar(posArray[indx << 1]);
    844             posPtr[indx].fY = SkFloatToScalar(posArray[(indx << 1) + 1]);
    845         }
    846         canvas->drawPosText(textArray + index, count << 1, posPtr, *paint);
    847         if (text) {
    848             env->ReleaseCharArrayElements(text, textArray, 0);
    849         }
    850         if (pos) {
    851             env->ReleaseFloatArrayElements(pos, posArray, 0);
    852         }
    853         delete[] posPtr;
    854     }
    855 
    856     static void drawPosText__String_FPaint(JNIEnv* env, jobject,
    857                                            SkCanvas* canvas, jstring text,
    858                                            jfloatArray pos,
    859                                            SkPaint* paint) {
    860         const void* text_ = text ? env->GetStringChars(text, NULL) : NULL;
    861         int byteLength = text ? env->GetStringLength(text) : 0;
    862         float* posArray = pos ? env->GetFloatArrayElements(pos, NULL) : NULL;
    863         int posCount = pos ? env->GetArrayLength(pos) >> 1: 0;
    864         SkPoint* posPtr = posCount > 0 ? new SkPoint[posCount] : NULL;
    865 
    866         for (int indx = 0; indx < posCount; indx++) {
    867             posPtr[indx].fX = SkFloatToScalar(posArray[indx << 1]);
    868             posPtr[indx].fY = SkFloatToScalar(posArray[(indx << 1) + 1]);
    869         }
    870         canvas->drawPosText(text_, byteLength << 1, posPtr, *paint);
    871         if (text) {
    872             env->ReleaseStringChars(text, (const jchar*) text_);
    873         }
    874         if (pos) {
    875             env->ReleaseFloatArrayElements(pos, posArray, 0);
    876         }
    877         delete[] posPtr;
    878     }
    879 
    880     static void drawTextOnPath___CIIPathFFPaint(JNIEnv* env, jobject,
    881             SkCanvas* canvas, jcharArray text, int index, int count,
    882             SkPath* path, jfloat hOffset, jfloat vOffset, jint bidiFlags, SkPaint* paint) {
    883 
    884         jchar* textArray = env->GetCharArrayElements(text, NULL);
    885         TextLayout::drawTextOnPath(paint, textArray + index, count, bidiFlags, hOffset, vOffset,
    886                                    path, canvas);
    887         env->ReleaseCharArrayElements(text, textArray, 0);
    888     }
    889 
    890     static void drawTextOnPath__StringPathFFPaint(JNIEnv* env, jobject,
    891             SkCanvas* canvas, jstring text, SkPath* path,
    892             jfloat hOffset, jfloat vOffset, jint bidiFlags, SkPaint* paint) {
    893         const jchar* text_ = env->GetStringChars(text, NULL);
    894         int count = env->GetStringLength(text);
    895         TextLayout::drawTextOnPath(paint, text_, count, bidiFlags, hOffset, vOffset,
    896                                    path, canvas);
    897         env->ReleaseStringChars(text, text_);
    898     }
    899 
    900     static bool getClipBounds(JNIEnv* env, jobject, SkCanvas* canvas,
    901                               jobject bounds) {
    902         SkRect   r;
    903         SkIRect ir;
    904         bool     result = canvas->getClipBounds(&r, SkCanvas::kBW_EdgeType);
    905 
    906         r.round(&ir);
    907         (void)GraphicsJNI::irect_to_jrect(ir, env, bounds);
    908         return result;
    909     }
    910 
    911     static void getCTM(JNIEnv* env, jobject, SkCanvas* canvas,
    912                        SkMatrix* matrix) {
    913         *matrix = canvas->getTotalMatrix();
    914     }
    915 };
    916 
    917 static JNINativeMethod gCanvasMethods[] = {
    918     {"finalizer", "(I)V", (void*) SkCanvasGlue::finalizer},
    919     {"initRaster","(I)I", (void*) SkCanvasGlue::initRaster},
    920     {"isOpaque","()Z", (void*) SkCanvasGlue::isOpaque},
    921     {"getWidth","()I", (void*) SkCanvasGlue::getWidth},
    922     {"getHeight","()I", (void*) SkCanvasGlue::getHeight},
    923     {"native_setBitmap","(II)V", (void*) SkCanvasGlue::setBitmap},
    924     {"save","()I", (void*) SkCanvasGlue::saveAll},
    925     {"save","(I)I", (void*) SkCanvasGlue::save},
    926     {"native_saveLayer","(ILandroid/graphics/RectF;II)I",
    927         (void*) SkCanvasGlue::saveLayer},
    928     {"native_saveLayer","(IFFFFII)I", (void*) SkCanvasGlue::saveLayer4F},
    929     {"native_saveLayerAlpha","(ILandroid/graphics/RectF;II)I",
    930         (void*) SkCanvasGlue::saveLayerAlpha},
    931     {"native_saveLayerAlpha","(IFFFFII)I",
    932         (void*) SkCanvasGlue::saveLayerAlpha4F},
    933     {"restore","()V", (void*) SkCanvasGlue::restore},
    934     {"getSaveCount","()I", (void*) SkCanvasGlue::getSaveCount},
    935     {"restoreToCount","(I)V", (void*) SkCanvasGlue::restoreToCount},
    936     {"translate","(FF)V", (void*) SkCanvasGlue::translate},
    937     {"scale","(FF)V", (void*) SkCanvasGlue::scale__FF},
    938     {"rotate","(F)V", (void*) SkCanvasGlue::rotate__F},
    939     {"skew","(FF)V", (void*) SkCanvasGlue::skew__FF},
    940     {"native_concat","(II)V", (void*) SkCanvasGlue::concat},
    941     {"native_setMatrix","(II)V", (void*) SkCanvasGlue::setMatrix},
    942     {"clipRect","(FFFF)Z", (void*) SkCanvasGlue::clipRect_FFFF},
    943     {"clipRect","(IIII)Z", (void*) SkCanvasGlue::clipRect_IIII},
    944     {"clipRect","(Landroid/graphics/RectF;)Z",
    945         (void*) SkCanvasGlue::clipRect_RectF},
    946     {"clipRect","(Landroid/graphics/Rect;)Z",
    947         (void*) SkCanvasGlue::clipRect_Rect},
    948     {"native_clipRect","(IFFFFI)Z", (void*) SkCanvasGlue::clipRect},
    949     {"native_clipPath","(III)Z", (void*) SkCanvasGlue::clipPath},
    950     {"native_clipRegion","(III)Z", (void*) SkCanvasGlue::clipRegion},
    951     {"nativeSetDrawFilter", "(II)V", (void*) SkCanvasGlue::setDrawFilter},
    952     {"native_getClipBounds","(ILandroid/graphics/Rect;)Z",
    953         (void*) SkCanvasGlue::getClipBounds},
    954     {"native_getCTM", "(II)V", (void*)SkCanvasGlue::getCTM},
    955     {"native_quickReject","(ILandroid/graphics/RectF;I)Z",
    956         (void*) SkCanvasGlue::quickReject__RectFI},
    957     {"native_quickReject","(III)Z", (void*) SkCanvasGlue::quickReject__PathI},
    958     {"native_quickReject","(IFFFFI)Z", (void*)SkCanvasGlue::quickReject__FFFFI},
    959     {"native_drawRGB","(IIII)V", (void*) SkCanvasGlue::drawRGB},
    960     {"native_drawARGB","(IIIII)V", (void*) SkCanvasGlue::drawARGB},
    961     {"native_drawColor","(II)V", (void*) SkCanvasGlue::drawColor__I},
    962     {"native_drawColor","(III)V", (void*) SkCanvasGlue::drawColor__II},
    963     {"native_drawPaint","(II)V", (void*) SkCanvasGlue::drawPaint},
    964     {"drawPoint", "(FFLandroid/graphics/Paint;)V",
    965     (void*) SkCanvasGlue::drawPoint},
    966     {"drawPoints", "([FIILandroid/graphics/Paint;)V",
    967         (void*) SkCanvasGlue::drawPoints},
    968     {"drawLines", "([FIILandroid/graphics/Paint;)V",
    969         (void*) SkCanvasGlue::drawLines},
    970     {"native_drawLine","(IFFFFI)V", (void*) SkCanvasGlue::drawLine__FFFFPaint},
    971     {"native_drawRect","(ILandroid/graphics/RectF;I)V",
    972         (void*) SkCanvasGlue::drawRect__RectFPaint},
    973     {"native_drawRect","(IFFFFI)V", (void*) SkCanvasGlue::drawRect__FFFFPaint},
    974     {"native_drawOval","(ILandroid/graphics/RectF;I)V",
    975         (void*) SkCanvasGlue::drawOval},
    976     {"native_drawCircle","(IFFFI)V", (void*) SkCanvasGlue::drawCircle},
    977     {"native_drawArc","(ILandroid/graphics/RectF;FFZI)V",
    978         (void*) SkCanvasGlue::drawArc},
    979     {"native_drawRoundRect","(ILandroid/graphics/RectF;FFI)V",
    980         (void*) SkCanvasGlue::drawRoundRect},
    981     {"native_drawPath","(III)V", (void*) SkCanvasGlue::drawPath},
    982     {"native_drawBitmap","(IIFFIIII)V",
    983         (void*) SkCanvasGlue::drawBitmap__BitmapFFPaint},
    984     {"native_drawBitmap","(IILandroid/graphics/Rect;Landroid/graphics/RectF;III)V",
    985         (void*) SkCanvasGlue::drawBitmapRF},
    986     {"native_drawBitmap","(IILandroid/graphics/Rect;Landroid/graphics/Rect;III)V",
    987         (void*) SkCanvasGlue::drawBitmapRR},
    988     {"native_drawBitmap", "(I[IIIFFIIZI)V",
    989     (void*)SkCanvasGlue::drawBitmapArray},
    990     {"nativeDrawBitmapMatrix", "(IIII)V",
    991         (void*)SkCanvasGlue::drawBitmapMatrix},
    992     {"nativeDrawBitmapMesh", "(IIII[FI[III)V",
    993         (void*)SkCanvasGlue::drawBitmapMesh},
    994     {"nativeDrawVertices", "(III[FI[FI[II[SIII)V",
    995         (void*)SkCanvasGlue::drawVertices},
    996     {"native_drawText","(I[CIIFFII)V",
    997         (void*) SkCanvasGlue::drawText___CIIFFIPaint},
    998     {"native_drawText","(ILjava/lang/String;IIFFII)V",
    999         (void*) SkCanvasGlue::drawText__StringIIFFIPaint},
   1000     {"native_drawTextRun","(I[CIIIIFFII)V",
   1001         (void*) SkCanvasGlue::drawTextRun___CIIIIFFIPaint},
   1002     {"native_drawTextRun","(ILjava/lang/String;IIIIFFII)V",
   1003         (void*) SkCanvasGlue::drawTextRun__StringIIIIFFIPaint},
   1004     {"native_drawPosText","(I[CII[FI)V",
   1005         (void*) SkCanvasGlue::drawPosText___CII_FPaint},
   1006     {"native_drawPosText","(ILjava/lang/String;[FI)V",
   1007         (void*) SkCanvasGlue::drawPosText__String_FPaint},
   1008     {"native_drawTextOnPath","(I[CIIIFFII)V",
   1009         (void*) SkCanvasGlue::drawTextOnPath___CIIPathFFPaint},
   1010     {"native_drawTextOnPath","(ILjava/lang/String;IFFII)V",
   1011         (void*) SkCanvasGlue::drawTextOnPath__StringPathFFPaint},
   1012     {"native_drawPicture", "(II)V", (void*) SkCanvasGlue::drawPicture},
   1013 
   1014     {"freeCaches", "()V", (void*) SkCanvasGlue::freeCaches}
   1015 };
   1016 
   1017 ///////////////////////////////////////////////////////////////////////////////
   1018 
   1019 #include <android_runtime/AndroidRuntime.h>
   1020 
   1021 #define REG(env, name, array) \
   1022     result = android::AndroidRuntime::registerNativeMethods(env, name, array, \
   1023                                                     SK_ARRAY_COUNT(array));  \
   1024     if (result < 0) return result
   1025 
   1026 int register_android_graphics_Canvas(JNIEnv* env) {
   1027     int result;
   1028 
   1029     REG(env, "android/graphics/Canvas", gCanvasMethods);
   1030 
   1031     return result;
   1032 }
   1033 
   1034 }
   1035