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