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