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