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