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