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