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