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