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