Canvas.cpp revision af033caf26ef4eca99c4024e59def7e42c3fa4cd
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        return canvas->getDevice()->accessBitmap(false).isOpaque();
77    }
78
79    static int getWidth(JNIEnv* env, jobject jcanvas) {
80        NPE_CHECK_RETURN_ZERO(env, jcanvas);
81        SkCanvas* canvas = GraphicsJNI::getNativeCanvas(env, jcanvas);
82        return canvas->getDevice()->accessBitmap(false).width();
83    }
84
85    static int getHeight(JNIEnv* env, jobject jcanvas) {
86        NPE_CHECK_RETURN_ZERO(env, jcanvas);
87        SkCanvas* canvas = GraphicsJNI::getNativeCanvas(env, jcanvas);
88        return canvas->getDevice()->accessBitmap(false).height();
89    }
90
91    static void setBitmap(JNIEnv* env, jobject, SkCanvas* canvas,
92                          SkBitmap* bitmap) {
93        canvas->setBitmapDevice(*bitmap);
94    }
95
96    static int saveAll(JNIEnv* env, jobject jcanvas) {
97        NPE_CHECK_RETURN_ZERO(env, jcanvas);
98        return GraphicsJNI::getNativeCanvas(env, jcanvas)->save();
99    }
100
101    static int save(JNIEnv* env, jobject jcanvas, SkCanvas::SaveFlags flags) {
102        NPE_CHECK_RETURN_ZERO(env, jcanvas);
103        return GraphicsJNI::getNativeCanvas(env, jcanvas)->save(flags);
104    }
105
106    static int saveLayer(JNIEnv* env, jobject, SkCanvas* canvas, jobject bounds,
107                         SkPaint* paint, int flags) {
108        SkRect* bounds_ = NULL;
109        SkRect  storage;
110        if (bounds != NULL) {
111            GraphicsJNI::jrectf_to_rect(env, bounds, &storage);
112            bounds_ = &storage;
113        }
114        return canvas->saveLayer(bounds_, paint, (SkCanvas::SaveFlags)flags);
115    }
116
117    static int saveLayer4F(JNIEnv* env, jobject, SkCanvas* canvas,
118                           jfloat l, jfloat t, jfloat r, jfloat b,
119                           SkPaint* paint, int flags) {
120        SkRect bounds;
121        bounds.set(SkFloatToScalar(l), SkFloatToScalar(t), SkFloatToScalar(r),
122                   SkFloatToScalar(b));
123        return canvas->saveLayer(&bounds, paint, (SkCanvas::SaveFlags)flags);
124    }
125
126    static int saveLayerAlpha(JNIEnv* env, jobject, SkCanvas* canvas,
127                              jobject bounds, int alpha, int flags) {
128        SkRect* bounds_ = NULL;
129        SkRect  storage;
130        if (bounds != NULL) {
131            GraphicsJNI::jrectf_to_rect(env, bounds, &storage);
132            bounds_ = &storage;
133        }
134        return canvas->saveLayerAlpha(bounds_, alpha,
135                                      (SkCanvas::SaveFlags)flags);
136    }
137
138    static int saveLayerAlpha4F(JNIEnv* env, jobject, SkCanvas* canvas,
139                                jfloat l, jfloat t, jfloat r, jfloat b,
140                                int alpha, int flags) {
141        SkRect  bounds;
142        bounds.set(SkFloatToScalar(l), SkFloatToScalar(t), SkFloatToScalar(r),
143                   SkFloatToScalar(b));
144        return canvas->saveLayerAlpha(&bounds, alpha,
145                                      (SkCanvas::SaveFlags)flags);
146    }
147
148    static void restore(JNIEnv* env, jobject jcanvas) {
149        NPE_CHECK_RETURN_VOID(env, jcanvas);
150        SkCanvas* canvas = GraphicsJNI::getNativeCanvas(env, jcanvas);
151        if (canvas->getSaveCount() <= 1) {  // cannot restore anymore
152            doThrowISE(env, "Underflow in restore");
153            return;
154        }
155        canvas->restore();
156    }
157
158    static int getSaveCount(JNIEnv* env, jobject jcanvas) {
159        NPE_CHECK_RETURN_ZERO(env, jcanvas);
160        return GraphicsJNI::getNativeCanvas(env, jcanvas)->getSaveCount();
161    }
162
163    static void restoreToCount(JNIEnv* env, jobject jcanvas, int restoreCount) {
164        NPE_CHECK_RETURN_VOID(env, jcanvas);
165        SkCanvas* canvas = GraphicsJNI::getNativeCanvas(env, jcanvas);
166        if (restoreCount < 1) {
167            doThrowIAE(env, "Underflow in restoreToCount");
168            return;
169        }
170        canvas->restoreToCount(restoreCount);
171    }
172
173    static void translate(JNIEnv* env, jobject jcanvas, jfloat dx, jfloat dy) {
174        NPE_CHECK_RETURN_VOID(env, jcanvas);
175        SkScalar dx_ = SkFloatToScalar(dx);
176        SkScalar dy_ = SkFloatToScalar(dy);
177        (void)GraphicsJNI::getNativeCanvas(env, jcanvas)->translate(dx_, dy_);
178    }
179
180    static void scale__FF(JNIEnv* env, jobject jcanvas, jfloat sx, jfloat sy) {
181        NPE_CHECK_RETURN_VOID(env, jcanvas);
182        SkScalar sx_ = SkFloatToScalar(sx);
183        SkScalar sy_ = SkFloatToScalar(sy);
184        (void)GraphicsJNI::getNativeCanvas(env, jcanvas)->scale(sx_, sy_);
185    }
186
187    static void rotate__F(JNIEnv* env, jobject jcanvas, jfloat degrees) {
188        NPE_CHECK_RETURN_VOID(env, jcanvas);
189        SkScalar degrees_ = SkFloatToScalar(degrees);
190        (void)GraphicsJNI::getNativeCanvas(env, jcanvas)->rotate(degrees_);
191    }
192
193    static void skew__FF(JNIEnv* env, jobject jcanvas, jfloat sx, jfloat sy) {
194        NPE_CHECK_RETURN_VOID(env, jcanvas);
195        SkScalar sx_ = SkFloatToScalar(sx);
196        SkScalar sy_ = SkFloatToScalar(sy);
197        (void)GraphicsJNI::getNativeCanvas(env, jcanvas)->skew(sx_, sy_);
198    }
199
200    static void concat(JNIEnv* env, jobject, SkCanvas* canvas,
201                       const SkMatrix* matrix) {
202        canvas->concat(*matrix);
203    }
204
205    static void setMatrix(JNIEnv* env, jobject, SkCanvas* canvas,
206                          const SkMatrix* matrix) {
207        if (NULL == matrix) {
208            canvas->resetMatrix();
209        } else {
210            canvas->setMatrix(*matrix);
211        }
212    }
213
214    static jboolean clipRect_FFFF(JNIEnv* env, jobject jcanvas, jfloat left,
215                                  jfloat top, jfloat right, jfloat bottom) {
216        NPE_CHECK_RETURN_ZERO(env, jcanvas);
217        SkRect  r;
218        r.set(SkFloatToScalar(left), SkFloatToScalar(top),
219              SkFloatToScalar(right), SkFloatToScalar(bottom));
220        SkCanvas* c = GraphicsJNI::getNativeCanvas(env, jcanvas);
221        return c->clipRect(r);
222    }
223
224    static jboolean clipRect_IIII(JNIEnv* env, jobject jcanvas, jint left,
225                                  jint top, jint right, jint bottom) {
226        NPE_CHECK_RETURN_ZERO(env, jcanvas);
227        SkRect  r;
228        r.set(SkIntToScalar(left), SkIntToScalar(top),
229              SkIntToScalar(right), SkIntToScalar(bottom));
230        return GraphicsJNI::getNativeCanvas(env, jcanvas)->clipRect(r);
231    }
232
233    static jboolean clipRect_RectF(JNIEnv* env, jobject jcanvas, jobject rectf) {
234        NPE_CHECK_RETURN_ZERO(env, jcanvas);
235        NPE_CHECK_RETURN_ZERO(env, rectf);
236        SkCanvas* c = GraphicsJNI::getNativeCanvas(env, jcanvas);
237        SkRect tmp;
238        return c->clipRect(*GraphicsJNI::jrectf_to_rect(env, rectf, &tmp));
239    }
240
241    static jboolean clipRect_Rect(JNIEnv* env, jobject jcanvas, jobject rect) {
242        NPE_CHECK_RETURN_ZERO(env, jcanvas);
243        NPE_CHECK_RETURN_ZERO(env, rect);
244        SkCanvas* c = GraphicsJNI::getNativeCanvas(env, jcanvas);
245        SkRect tmp;
246        return c->clipRect(*GraphicsJNI::jrect_to_rect(env, rect, &tmp));
247    }
248
249    static jboolean clipRect(JNIEnv* env, jobject, SkCanvas* canvas,
250                             float left, float top, float right, float bottom,
251                             int op) {
252        SkRect rect;
253        rect.set(SkFloatToScalar(left), SkFloatToScalar(top),
254                 SkFloatToScalar(right), SkFloatToScalar(bottom));
255        return canvas->clipRect(rect, (SkRegion::Op)op);
256    }
257
258    static jboolean clipPath(JNIEnv* env, jobject, SkCanvas* canvas,
259                             SkPath* path, int op) {
260        return canvas->clipPath(*path, (SkRegion::Op)op);
261    }
262
263    static jboolean clipRegion(JNIEnv* env, jobject, SkCanvas* canvas,
264                               SkRegion* deviceRgn, int op) {
265        return canvas->clipRegion(*deviceRgn, (SkRegion::Op)op);
266    }
267
268    static void setDrawFilter(JNIEnv* env, jobject, SkCanvas* canvas,
269                              SkDrawFilter* filter) {
270        canvas->setDrawFilter(filter);
271    }
272
273    static jboolean quickReject__RectFI(JNIEnv* env, jobject, SkCanvas* canvas,
274                                        jobject rect, int edgetype) {
275        SkRect rect_;
276        GraphicsJNI::jrectf_to_rect(env, rect, &rect_);
277        return canvas->quickReject(rect_, (SkCanvas::EdgeType)edgetype);
278    }
279
280    static jboolean quickReject__PathI(JNIEnv* env, jobject, SkCanvas* canvas,
281                                       SkPath* path, int edgetype) {
282        return canvas->quickReject(*path, (SkCanvas::EdgeType)edgetype);
283    }
284
285    static jboolean quickReject__FFFFI(JNIEnv* env, jobject, SkCanvas* canvas,
286                                       jfloat left, jfloat top, jfloat right,
287                                       jfloat bottom, int edgetype) {
288        SkRect r;
289        r.set(SkFloatToScalar(left), SkFloatToScalar(top),
290              SkFloatToScalar(right), SkFloatToScalar(bottom));
291        return canvas->quickReject(r, (SkCanvas::EdgeType)edgetype);
292    }
293
294    static void drawRGB(JNIEnv* env, jobject, SkCanvas* canvas,
295                        jint r, jint g, jint b) {
296        canvas->drawARGB(0xFF, r, g, b);
297    }
298
299    static void drawARGB(JNIEnv* env, jobject, SkCanvas* canvas,
300                         jint a, jint r, jint g, jint b) {
301        canvas->drawARGB(a, r, g, b);
302    }
303
304    static void drawColor__I(JNIEnv* env, jobject, SkCanvas* canvas,
305                             jint color) {
306        canvas->drawColor(color);
307    }
308
309    static void drawColor__II(JNIEnv* env, jobject, SkCanvas* canvas,
310                              jint color, SkPorterDuff::Mode mode) {
311        canvas->drawColor(color, SkPorterDuff::ToXfermodeMode(mode));
312    }
313
314    static void drawPaint(JNIEnv* env, jobject, SkCanvas* canvas,
315                          SkPaint* paint) {
316        canvas->drawPaint(*paint);
317    }
318
319    static void doPoints(JNIEnv* env, jobject jcanvas, jfloatArray jptsArray,
320                         jint offset, jint count, jobject jpaint,
321                         SkCanvas::PointMode mode) {
322        NPE_CHECK_RETURN_VOID(env, jcanvas);
323        NPE_CHECK_RETURN_VOID(env, jptsArray);
324        NPE_CHECK_RETURN_VOID(env, jpaint);
325        SkCanvas* canvas = GraphicsJNI::getNativeCanvas(env, jcanvas);
326        const SkPaint& paint = *GraphicsJNI::getNativePaint(env, jpaint);
327
328        AutoJavaFloatArray autoPts(env, jptsArray);
329        float* floats = autoPts.ptr();
330        const int length = autoPts.length();
331
332        if ((offset | count) < 0 || offset + count > length) {
333            doThrowAIOOBE(env);
334            return;
335        }
336
337        // now convert the floats into SkPoints
338        count >>= 1;    // now it is the number of points
339        SkAutoSTMalloc<32, SkPoint> storage(count);
340        SkPoint* pts = storage.get();
341        const float* src = floats + offset;
342        for (int i = 0; i < count; i++) {
343            pts[i].set(SkFloatToScalar(src[0]), SkFloatToScalar(src[1]));
344            src += 2;
345        }
346        canvas->drawPoints(mode, count, pts, paint);
347    }
348
349    static void drawPoints(JNIEnv* env, jobject jcanvas, jfloatArray jptsArray,
350                           jint offset, jint count, jobject jpaint) {
351        doPoints(env, jcanvas, jptsArray, offset, count, jpaint,
352                 SkCanvas::kPoints_PointMode);
353    }
354
355    static void drawLines(JNIEnv* env, jobject jcanvas, jfloatArray jptsArray,
356                           jint offset, jint count, jobject jpaint) {
357        doPoints(env, jcanvas, jptsArray, offset, count, jpaint,
358                 SkCanvas::kLines_PointMode);
359    }
360
361    static void drawPoint(JNIEnv* env, jobject jcanvas, float x, float y,
362                          jobject jpaint) {
363        NPE_CHECK_RETURN_VOID(env, jcanvas);
364        NPE_CHECK_RETURN_VOID(env, jpaint);
365        SkCanvas* canvas = GraphicsJNI::getNativeCanvas(env, jcanvas);
366        const SkPaint& paint = *GraphicsJNI::getNativePaint(env, jpaint);
367
368        canvas->drawPoint(SkFloatToScalar(x), SkFloatToScalar(y), paint);
369    }
370
371    static void drawLine__FFFFPaint(JNIEnv* env, jobject, SkCanvas* canvas,
372                                    jfloat startX, jfloat startY, jfloat stopX,
373                                    jfloat stopY, SkPaint* paint) {
374        canvas->drawLine(SkFloatToScalar(startX), SkFloatToScalar(startY),
375                         SkFloatToScalar(stopX), SkFloatToScalar(stopY),
376                         *paint);
377    }
378
379    static void drawRect__RectFPaint(JNIEnv* env, jobject, SkCanvas* canvas,
380                                     jobject rect, SkPaint* paint) {
381        SkRect rect_;
382        GraphicsJNI::jrectf_to_rect(env, rect, &rect_);
383        canvas->drawRect(rect_, *paint);
384    }
385
386    static void drawRect__FFFFPaint(JNIEnv* env, jobject, SkCanvas* canvas,
387                                    jfloat left, jfloat top, jfloat right,
388                                    jfloat bottom, SkPaint* paint) {
389        SkScalar left_ = SkFloatToScalar(left);
390        SkScalar top_ = SkFloatToScalar(top);
391        SkScalar right_ = SkFloatToScalar(right);
392        SkScalar bottom_ = SkFloatToScalar(bottom);
393        canvas->drawRectCoords(left_, top_, right_, bottom_, *paint);
394    }
395
396    static void drawOval(JNIEnv* env, jobject, SkCanvas* canvas, jobject joval,
397                         SkPaint* paint) {
398        SkRect oval;
399        GraphicsJNI::jrectf_to_rect(env, joval, &oval);
400        canvas->drawOval(oval, *paint);
401    }
402
403    static void drawCircle(JNIEnv* env, jobject, SkCanvas* canvas, jfloat cx,
404                           jfloat cy, jfloat radius, SkPaint* paint) {
405        canvas->drawCircle(SkFloatToScalar(cx), SkFloatToScalar(cy),
406                           SkFloatToScalar(radius), *paint);
407    }
408
409    static void drawArc(JNIEnv* env, jobject, SkCanvas* canvas, jobject joval,
410                        jfloat startAngle, jfloat sweepAngle,
411                        jboolean useCenter, SkPaint* paint) {
412        SkRect oval;
413        GraphicsJNI::jrectf_to_rect(env, joval, &oval);
414        canvas->drawArc(oval, SkFloatToScalar(startAngle),
415                        SkFloatToScalar(sweepAngle), useCenter, *paint);
416    }
417
418    static void drawRoundRect(JNIEnv* env, jobject, SkCanvas* canvas,
419                              jobject jrect, jfloat rx, jfloat ry,
420                              SkPaint* paint) {
421        SkRect rect;
422        GraphicsJNI::jrectf_to_rect(env, jrect, &rect);
423        canvas->drawRoundRect(rect, SkFloatToScalar(rx), SkFloatToScalar(ry),
424                              *paint);
425    }
426
427    static void drawPath(JNIEnv* env, jobject, SkCanvas* canvas, SkPath* path,
428                         SkPaint* paint) {
429        canvas->drawPath(*path, *paint);
430    }
431
432    static void drawPicture(JNIEnv* env, jobject, SkCanvas* canvas,
433                            SkPicture* picture) {
434        SkASSERT(canvas);
435        SkASSERT(picture);
436
437#ifdef TIME_DRAW
438        SkMSec now = get_thread_msec(); //SkTime::GetMSecs();
439#endif
440        canvas->drawPicture(*picture);
441#ifdef TIME_DRAW
442        LOGD("---- picture playback %d ms\n", get_thread_msec() - now);
443#endif
444    }
445
446    static void drawBitmap__BitmapFFPaint(JNIEnv* env, jobject jcanvas,
447                                          SkCanvas* canvas, SkBitmap* bitmap,
448                                          jfloat left, jfloat top,
449                                          SkPaint* paint, jint canvasDensity,
450                                          jint screenDensity, jint bitmapDensity) {
451        SkScalar left_ = SkFloatToScalar(left);
452        SkScalar top_ = SkFloatToScalar(top);
453
454        if (canvasDensity == bitmapDensity || canvasDensity == 0
455                || bitmapDensity == 0) {
456            if (screenDensity != 0 && screenDensity != bitmapDensity) {
457                SkPaint filteredPaint;
458                if (paint) {
459                    filteredPaint = *paint;
460                }
461                filteredPaint.setFilterBitmap(true);
462                canvas->drawBitmap(*bitmap, left_, top_, &filteredPaint);
463            } else {
464                canvas->drawBitmap(*bitmap, left_, top_, paint);
465            }
466        } else {
467            canvas->save();
468            SkScalar scale = SkFloatToScalar(canvasDensity / (float)bitmapDensity);
469            canvas->translate(left_, top_);
470            canvas->scale(scale, scale);
471
472            SkPaint filteredPaint;
473            if (paint) {
474                filteredPaint = *paint;
475            }
476            filteredPaint.setFilterBitmap(true);
477
478            canvas->drawBitmap(*bitmap, 0, 0, &filteredPaint);
479
480            canvas->restore();
481        }
482    }
483
484    static void doDrawBitmap(JNIEnv* env, SkCanvas* canvas, SkBitmap* bitmap,
485                        jobject srcIRect, const SkRect& dst, SkPaint* paint,
486                        jint screenDensity, jint bitmapDensity) {
487        SkIRect    src, *srcPtr = NULL;
488
489        if (NULL != srcIRect) {
490            GraphicsJNI::jrect_to_irect(env, srcIRect, &src);
491            srcPtr = &src;
492        }
493
494        if (screenDensity != 0 && screenDensity != bitmapDensity) {
495            SkPaint filteredPaint;
496            if (paint) {
497                filteredPaint = *paint;
498            }
499            filteredPaint.setFilterBitmap(true);
500            canvas->drawBitmapRect(*bitmap, srcPtr, dst, &filteredPaint);
501        } else {
502            canvas->drawBitmapRect(*bitmap, srcPtr, dst, paint);
503        }
504    }
505
506    static void drawBitmapRF(JNIEnv* env, jobject, SkCanvas* canvas,
507                             SkBitmap* bitmap, jobject srcIRect,
508                             jobject dstRectF, SkPaint* paint,
509                             jint screenDensity, jint bitmapDensity) {
510        SkRect      dst;
511        GraphicsJNI::jrectf_to_rect(env, dstRectF, &dst);
512        doDrawBitmap(env, canvas, bitmap, srcIRect, dst, paint,
513                screenDensity, bitmapDensity);
514    }
515
516    static void drawBitmapRR(JNIEnv* env, jobject, SkCanvas* canvas,
517                             SkBitmap* bitmap, jobject srcIRect,
518                             jobject dstRect, SkPaint* paint,
519                             jint screenDensity, jint bitmapDensity) {
520        SkRect      dst;
521        GraphicsJNI::jrect_to_rect(env, dstRect, &dst);
522        doDrawBitmap(env, canvas, bitmap, srcIRect, dst, paint,
523                screenDensity, bitmapDensity);
524    }
525
526    static void drawBitmapArray(JNIEnv* env, jobject, SkCanvas* canvas,
527                                jintArray jcolors, int offset, int stride,
528                                jfloat x, jfloat y, int width, int height,
529                                jboolean hasAlpha, SkPaint* paint)
530    {
531        SkBitmap    bitmap;
532
533        bitmap.setConfig(hasAlpha ? SkBitmap::kARGB_8888_Config :
534                         SkBitmap::kRGB_565_Config, width, height);
535        if (!bitmap.allocPixels()) {
536            return;
537        }
538
539        if (!GraphicsJNI::SetPixels(env, jcolors, offset, stride,
540                                    0, 0, width, height, bitmap)) {
541            return;
542        }
543
544        canvas->drawBitmap(bitmap, SkFloatToScalar(x), SkFloatToScalar(y),
545                           paint);
546    }
547
548    static void drawBitmapMatrix(JNIEnv* env, jobject, SkCanvas* canvas,
549                                 const SkBitmap* bitmap, const SkMatrix* matrix,
550                                 const SkPaint* paint) {
551        canvas->drawBitmapMatrix(*bitmap, *matrix, paint);
552    }
553
554    static void drawBitmapMesh(JNIEnv* env, jobject, SkCanvas* canvas,
555                          const SkBitmap* bitmap, int meshWidth, int meshHeight,
556                          jfloatArray jverts, int vertIndex, jintArray jcolors,
557                          int colorIndex, const SkPaint* paint) {
558
559        const int ptCount = (meshWidth + 1) * (meshHeight + 1);
560        const int indexCount = meshWidth * meshHeight * 6;
561
562        AutoJavaFloatArray  vertA(env, jverts, vertIndex + (ptCount << 1));
563        AutoJavaIntArray    colorA(env, jcolors, colorIndex + ptCount);
564
565        /*  Our temp storage holds 2 or 3 arrays.
566            texture points [ptCount * sizeof(SkPoint)]
567            optionally vertex points [ptCount * sizeof(SkPoint)] if we need a
568                copy to convert from float to fixed
569            indices [ptCount * sizeof(uint16_t)]
570        */
571        ssize_t storageSize = ptCount * sizeof(SkPoint); // texs[]
572#ifdef SK_SCALAR_IS_FIXED
573        storageSize += ptCount * sizeof(SkPoint);  // storage for verts
574#endif
575        storageSize += indexCount * sizeof(uint16_t);  // indices[]
576
577        SkAutoMalloc storage(storageSize);
578        SkPoint* texs = (SkPoint*)storage.get();
579        SkPoint* verts;
580        uint16_t* indices;
581#ifdef SK_SCALAR_IS_FLOAT
582        verts = (SkPoint*)(vertA.ptr() + vertIndex);
583        indices = (uint16_t*)(texs + ptCount);
584#else
585        verts = texs + ptCount;
586        indices = (uint16_t*)(verts + ptCount);
587        // convert floats to fixed
588        {
589            const float* src = vertA.ptr() + vertIndex;
590            for (int i = 0; i < ptCount; i++) {
591                verts[i].set(SkFloatToFixed(src[0]), SkFloatToFixed(src[1]));
592                src += 2;
593            }
594        }
595#endif
596
597        // cons up texture coordinates and indices
598        {
599            const SkScalar w = SkIntToScalar(bitmap->width());
600            const SkScalar h = SkIntToScalar(bitmap->height());
601            const SkScalar dx = w / meshWidth;
602            const SkScalar dy = h / meshHeight;
603
604            SkPoint* texsPtr = texs;
605            SkScalar y = 0;
606            for (int i = 0; i <= meshHeight; i++) {
607                if (i == meshHeight) {
608                    y = h;  // to ensure numerically we hit h exactly
609                }
610                SkScalar x = 0;
611                for (int j = 0; j < meshWidth; j++) {
612                    texsPtr->set(x, y);
613                    texsPtr += 1;
614                    x += dx;
615                }
616                texsPtr->set(w, y);
617                texsPtr += 1;
618                y += dy;
619            }
620            SkASSERT(texsPtr - texs == ptCount);
621        }
622
623        // cons up indices
624        {
625            uint16_t* indexPtr = indices;
626            int index = 0;
627            for (int i = 0; i < meshHeight; i++) {
628                for (int j = 0; j < meshWidth; j++) {
629                    // lower-left triangle
630                    *indexPtr++ = index;
631                    *indexPtr++ = index + meshWidth + 1;
632                    *indexPtr++ = index + meshWidth + 2;
633                    // upper-right triangle
634                    *indexPtr++ = index;
635                    *indexPtr++ = index + meshWidth + 2;
636                    *indexPtr++ = index + 1;
637                    // bump to the next cell
638                    index += 1;
639                }
640                // bump to the next row
641                index += 1;
642            }
643            SkASSERT(indexPtr - indices == indexCount);
644            SkASSERT((char*)indexPtr - (char*)storage.get() == storageSize);
645        }
646
647        // double-check that we have legal indices
648#ifdef SK_DEBUG
649        {
650            for (int i = 0; i < indexCount; i++) {
651                SkASSERT((unsigned)indices[i] < (unsigned)ptCount);
652            }
653        }
654#endif
655
656        // cons-up a shader for the bitmap
657        SkPaint tmpPaint;
658        if (paint) {
659            tmpPaint = *paint;
660        }
661        SkShader* shader = SkShader::CreateBitmapShader(*bitmap,
662                        SkShader::kClamp_TileMode, SkShader::kClamp_TileMode);
663        SkSafeUnref(tmpPaint.setShader(shader));
664
665        canvas->drawVertices(SkCanvas::kTriangles_VertexMode, ptCount, verts,
666                             texs, (const SkColor*)colorA.ptr(), NULL, indices,
667                             indexCount, tmpPaint);
668    }
669
670    static void drawVertices(JNIEnv* env, jobject, SkCanvas* canvas,
671                             SkCanvas::VertexMode mode, int vertexCount,
672                             jfloatArray jverts, int vertIndex,
673                             jfloatArray jtexs, int texIndex,
674                             jintArray jcolors, int colorIndex,
675                             jshortArray jindices, int indexIndex,
676                             int indexCount, const SkPaint* paint) {
677
678        AutoJavaFloatArray  vertA(env, jverts, vertIndex + vertexCount);
679        AutoJavaFloatArray  texA(env, jtexs, texIndex + vertexCount);
680        AutoJavaIntArray    colorA(env, jcolors, colorIndex + vertexCount);
681        AutoJavaShortArray  indexA(env, jindices, indexIndex + indexCount);
682
683        const int ptCount = vertexCount >> 1;
684
685        SkPoint* verts;
686        SkPoint* texs = NULL;
687#ifdef SK_SCALAR_IS_FLOAT
688        verts = (SkPoint*)(vertA.ptr() + vertIndex);
689        if (jtexs != NULL) {
690            texs = (SkPoint*)(texA.ptr() + texIndex);
691        }
692#else
693        int count = ptCount;    // for verts
694        if (jtexs != NULL) {
695            count += ptCount;   // += for texs
696        }
697        SkAutoMalloc storage(count * sizeof(SkPoint));
698        verts = (SkPoint*)storage.get();
699        const float* src = vertA.ptr() + vertIndex;
700        for (int i = 0; i < ptCount; i++) {
701            verts[i].set(SkFloatToFixed(src[0]), SkFloatToFixed(src[1]));
702            src += 2;
703        }
704        if (jtexs != NULL) {
705            texs = verts + ptCount;
706            src = texA.ptr() + texIndex;
707            for (int i = 0; i < ptCount; i++) {
708                texs[i].set(SkFloatToFixed(src[0]), SkFloatToFixed(src[1]));
709                src += 2;
710            }
711        }
712#endif
713
714        const SkColor* colors = NULL;
715        const uint16_t* indices = NULL;
716        if (jcolors != NULL) {
717            colors = (const SkColor*)(colorA.ptr() + colorIndex);
718        }
719        if (jindices != NULL) {
720            indices = (const uint16_t*)(indexA.ptr() + indexIndex);
721        }
722
723        canvas->drawVertices(mode, ptCount, verts, texs, colors, NULL,
724                             indices, indexCount, *paint);
725    }
726
727
728    static void drawText___CIIFFIPaint(JNIEnv* env, jobject, SkCanvas* canvas,
729                                      jcharArray text, int index, int count,
730                                      jfloat x, jfloat y, int flags, SkPaint* paint) {
731        jchar* textArray = env->GetCharArrayElements(text, NULL);
732#if RTL_USE_HARFBUZZ
733        drawTextWithGlyphs(canvas, textArray + index, 0, count, x, y, flags, paint);
734#else
735        TextLayout::drawText(paint, textArray + index, count, flags, x, y, canvas);
736#endif
737        env->ReleaseCharArrayElements(text, textArray, JNI_ABORT);
738    }
739
740    static void drawText__StringIIFFIPaint(JNIEnv* env, jobject,
741                                          SkCanvas* canvas, jstring text,
742                                          int start, int end,
743                                          jfloat x, jfloat y, int flags, SkPaint* paint) {
744        const jchar* textArray = env->GetStringChars(text, NULL);
745#if RTL_USE_HARFBUZZ
746        drawTextWithGlyphs(canvas, textArray, start, end, x, y, flags, paint);
747#else
748        TextLayout::drawText(paint, textArray + start, end - start, flags, x, y, canvas);
749#endif
750        env->ReleaseStringChars(text, textArray);
751    }
752
753    static void drawTextWithGlyphs(SkCanvas* canvas, const jchar* textArray,
754            int start, int end,
755            jfloat x, jfloat y, int flags, SkPaint* paint) {
756
757        jint count = end - start;
758        sp<TextLayoutCacheValue> value;
759#if USE_TEXT_LAYOUT_CACHE
760        value = gTextLayoutCache.getValue(paint, textArray, start, count, end, flags);
761        if (value == NULL) {
762            LOGE("Cannot get TextLayoutCache value");
763            return ;
764        }
765#else
766        value = new TextLayoutCacheValue();
767        value->computeValues(paint, textArray, start, count, end, flags);
768#endif
769
770#if DEBUG_GLYPHS
771        logGlyphs(value);
772#endif
773
774    doDrawGlyphs(canvas, value->getGlyphs(), 0, value->getGlyphsCount(),
775            x, y, flags, paint);
776    }
777
778    static void drawTextWithGlyphs(SkCanvas* canvas, const jchar* textArray,
779            int start, int count, int contextCount,
780            jfloat x, jfloat y, int flags, SkPaint* paint) {
781
782        sp<TextLayoutCacheValue> value;
783#if USE_TEXT_LAYOUT_CACHE
784        value = gTextLayoutCache.getValue(paint, textArray, start, count, contextCount, flags);
785        if (value == NULL) {
786            LOGE("Cannot get TextLayoutCache value");
787            return ;
788        }
789#else
790        value = new TextLayoutCacheValue();
791        value->computeValues(paint, textArray, start, count, contextCount, flags);
792#endif
793
794#if DEBUG_GLYPHS
795        logGlyphs(value);
796#endif
797
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