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