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