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
40static 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
55namespace android {
56
57class ClipCopier : public SkCanvas::ClipVisitor {
58public:
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
68private:
69    SkCanvas* m_dstCanvas;
70};
71
72class SkCanvasGlue {
73public:
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
813static 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
1011static 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
1122int 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