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