Canvas.cpp revision ad8b8f57a457ff615112b7fa4987f39e75fc5ff6
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        canvas->drawText(textArray + index, count << 1, x_, y_, *paint);
726        env->ReleaseCharArrayElements(text, textArray, 0);
727    }
728
729    static void drawText__StringIIFFPaint(JNIEnv* env, jobject,
730                            SkCanvas* canvas, jstring text, int start, int end,
731                                          jfloat x, jfloat y, SkPaint* paint) {
732        const void* text_ = env->GetStringChars(text, NULL);
733        SkScalar x_ = SkFloatToScalar(x);
734        SkScalar y_ = SkFloatToScalar(y);
735        canvas->drawText((const uint16_t*)text_ + start, (end - start) << 1,
736                         x_, y_, *paint);
737        env->ReleaseStringChars(text, (const jchar*) text_);
738    }
739
740    static void drawString(JNIEnv* env, jobject canvas, jstring text,
741                           jfloat x, jfloat y, jobject paint) {
742        NPE_CHECK_RETURN_VOID(env, canvas);
743        NPE_CHECK_RETURN_VOID(env, paint);
744        NPE_CHECK_RETURN_VOID(env, text);
745        size_t count = env->GetStringLength(text);
746        if (0 == count) {
747            return;
748        }
749        const jchar* text_ = env->GetStringChars(text, NULL);
750        SkCanvas* c = GraphicsJNI::getNativeCanvas(env, canvas);
751        c->drawText(text_, count << 1, SkFloatToScalar(x), SkFloatToScalar(y),
752                    *GraphicsJNI::getNativePaint(env, paint));
753        env->ReleaseStringChars(text, text_);
754    }
755
756    static void drawPosText___CII_FPaint(JNIEnv* env, jobject, SkCanvas* canvas,
757                                         jcharArray text, int index, int count,
758                                         jfloatArray pos, SkPaint* paint) {
759        jchar* textArray = text ? env->GetCharArrayElements(text, NULL) : NULL;
760        jsize textCount = text ? env->GetArrayLength(text) : NULL;
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        int indx;
765        for (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(textArray + index, count << 1, posPtr, *paint);
770        if (text) {
771            env->ReleaseCharArrayElements(text, textArray, 0);
772        }
773        if (pos) {
774            env->ReleaseFloatArrayElements(pos, posArray, 0);
775        }
776        delete[] posPtr;
777    }
778
779    static void drawPosText__String_FPaint(JNIEnv* env, jobject,
780                                           SkCanvas* canvas, jstring text,
781                                           jfloatArray pos, SkPaint* paint) {
782        const void* text_ = text ? env->GetStringChars(text, NULL) : NULL;
783        int byteLength = text ? env->GetStringLength(text) : 0;
784        float* posArray = pos ? env->GetFloatArrayElements(pos, NULL) : NULL;
785        int posCount = pos ? env->GetArrayLength(pos) >> 1: 0;
786        SkPoint* posPtr = posCount > 0 ? new SkPoint[posCount] : NULL;
787
788        for (int indx = 0; indx < posCount; indx++) {
789            posPtr[indx].fX = SkFloatToScalar(posArray[indx << 1]);
790            posPtr[indx].fY = SkFloatToScalar(posArray[(indx << 1) + 1]);
791        }
792        canvas->drawPosText(text_, byteLength << 1, posPtr, *paint);
793        if (text) {
794            env->ReleaseStringChars(text, (const jchar*) text_);
795        }
796        if (pos) {
797            env->ReleaseFloatArrayElements(pos, posArray, 0);
798        }
799        delete[] posPtr;
800    }
801
802    static void drawTextOnPath___CIIPathFFPaint(JNIEnv* env, jobject,
803                        SkCanvas* canvas, jcharArray text, int index, int count,
804                SkPath* path, jfloat hOffset, jfloat vOffset, SkPaint* paint) {
805
806        jchar* textArray = env->GetCharArrayElements(text, NULL);
807        canvas->drawTextOnPathHV(textArray + index, count << 1, *path,
808                    SkFloatToScalar(hOffset), SkFloatToScalar(vOffset), *paint);
809        env->ReleaseCharArrayElements(text, textArray, 0);
810    }
811
812    static void drawTextOnPath__StringPathFFPaint(JNIEnv* env, jobject,
813                            SkCanvas* canvas, jstring text, SkPath* path,
814                            jfloat hOffset, jfloat vOffset, SkPaint* paint) {
815        const jchar* text_ = env->GetStringChars(text, NULL);
816        int byteLength = env->GetStringLength(text) << 1;
817        canvas->drawTextOnPathHV(text_, byteLength, *path,
818                    SkFloatToScalar(hOffset), SkFloatToScalar(vOffset), *paint);
819        env->ReleaseStringChars(text, text_);
820    }
821
822    static bool getClipBounds(JNIEnv* env, jobject, SkCanvas* canvas,
823                              jobject bounds) {
824        SkRect   r;
825        SkIRect ir;
826        bool     result = canvas->getClipBounds(&r, SkCanvas::kBW_EdgeType);
827
828        r.round(&ir);
829        (void)GraphicsJNI::irect_to_jrect(ir, env, bounds);
830        return result;
831    }
832
833    static void getCTM(JNIEnv* env, jobject, SkCanvas* canvas,
834                       SkMatrix* matrix) {
835        *matrix = canvas->getTotalMatrix();
836    }
837};
838
839///////////////////////////////////////////////////////////////////////////////
840
841static JNINativeMethod gCanvasMethods[] = {
842    {"finalizer", "(I)V", (void*) SkCanvasGlue::finalizer},
843    {"initRaster","(I)I", (void*) SkCanvasGlue::initRaster},
844    {"initGL","()I", (void*) SkCanvasGlue::initGL},
845    {"isOpaque","()Z", (void*) SkCanvasGlue::isOpaque},
846    {"getWidth","()I", (void*) SkCanvasGlue::getWidth},
847    {"getHeight","()I", (void*) SkCanvasGlue::getHeight},
848    {"native_setBitmap","(II)V", (void*) SkCanvasGlue::setBitmap},
849    {"nativeSetViewport", "(III)V", (void*) SkCanvasGlue::setViewport},
850    {"save","()I", (void*) SkCanvasGlue::saveAll},
851    {"save","(I)I", (void*) SkCanvasGlue::save},
852    {"native_saveLayer","(ILandroid/graphics/RectF;II)I",
853        (void*) SkCanvasGlue::saveLayer},
854    {"native_saveLayer","(IFFFFII)I", (void*) SkCanvasGlue::saveLayer4F},
855    {"native_saveLayerAlpha","(ILandroid/graphics/RectF;II)I",
856        (void*) SkCanvasGlue::saveLayerAlpha},
857    {"native_saveLayerAlpha","(IFFFFII)I",
858        (void*) SkCanvasGlue::saveLayerAlpha4F},
859    {"restore","()V", (void*) SkCanvasGlue::restore},
860    {"getSaveCount","()I", (void*) SkCanvasGlue::getSaveCount},
861    {"restoreToCount","(I)V", (void*) SkCanvasGlue::restoreToCount},
862    {"translate","(FF)V", (void*) SkCanvasGlue::translate},
863    {"scale","(FF)V", (void*) SkCanvasGlue::scale__FF},
864    {"rotate","(F)V", (void*) SkCanvasGlue::rotate__F},
865    {"skew","(FF)V", (void*) SkCanvasGlue::skew__FF},
866    {"native_concat","(II)V", (void*) SkCanvasGlue::concat},
867    {"native_setMatrix","(II)V", (void*) SkCanvasGlue::setMatrix},
868    {"clipRect","(FFFF)Z", (void*) SkCanvasGlue::clipRect_FFFF},
869    {"clipRect","(IIII)Z", (void*) SkCanvasGlue::clipRect_IIII},
870    {"clipRect","(Landroid/graphics/RectF;)Z",
871        (void*) SkCanvasGlue::clipRect_RectF},
872    {"clipRect","(Landroid/graphics/Rect;)Z",
873        (void*) SkCanvasGlue::clipRect_Rect},
874    {"native_clipRect","(IFFFFI)Z", (void*) SkCanvasGlue::clipRect},
875    {"native_clipPath","(III)Z", (void*) SkCanvasGlue::clipPath},
876    {"native_clipRegion","(III)Z", (void*) SkCanvasGlue::clipRegion},
877    {"nativeSetDrawFilter", "(II)V", (void*) SkCanvasGlue::setDrawFilter},
878    {"native_getClipBounds","(ILandroid/graphics/Rect;)Z",
879        (void*) SkCanvasGlue::getClipBounds},
880    {"native_getCTM", "(II)V", (void*)SkCanvasGlue::getCTM},
881    {"native_quickReject","(ILandroid/graphics/RectF;I)Z",
882        (void*) SkCanvasGlue::quickReject__RectFI},
883    {"native_quickReject","(III)Z", (void*) SkCanvasGlue::quickReject__PathI},
884    {"native_quickReject","(IFFFFI)Z", (void*)SkCanvasGlue::quickReject__FFFFI},
885    {"native_drawRGB","(IIII)V", (void*) SkCanvasGlue::drawRGB},
886    {"native_drawARGB","(IIIII)V", (void*) SkCanvasGlue::drawARGB},
887    {"native_drawColor","(II)V", (void*) SkCanvasGlue::drawColor__I},
888    {"native_drawColor","(III)V", (void*) SkCanvasGlue::drawColor__II},
889    {"native_drawPaint","(II)V", (void*) SkCanvasGlue::drawPaint},
890    {"drawPoint", "(FFLandroid/graphics/Paint;)V",
891    (void*) SkCanvasGlue::drawPoint},
892    {"drawPoints", "([FIILandroid/graphics/Paint;)V",
893        (void*) SkCanvasGlue::drawPoints},
894    {"drawLines", "([FIILandroid/graphics/Paint;)V",
895        (void*) SkCanvasGlue::drawLines},
896    {"native_drawLine","(IFFFFI)V", (void*) SkCanvasGlue::drawLine__FFFFPaint},
897    {"native_drawRect","(ILandroid/graphics/RectF;I)V",
898        (void*) SkCanvasGlue::drawRect__RectFPaint},
899    {"native_drawRect","(IFFFFI)V", (void*) SkCanvasGlue::drawRect__FFFFPaint},
900    {"native_drawOval","(ILandroid/graphics/RectF;I)V",
901        (void*) SkCanvasGlue::drawOval},
902    {"native_drawCircle","(IFFFI)V", (void*) SkCanvasGlue::drawCircle},
903    {"native_drawArc","(ILandroid/graphics/RectF;FFZI)V",
904        (void*) SkCanvasGlue::drawArc},
905    {"native_drawRoundRect","(ILandroid/graphics/RectF;FFI)V",
906        (void*) SkCanvasGlue::drawRoundRect},
907    {"native_drawPath","(III)V", (void*) SkCanvasGlue::drawPath},
908    {"native_drawBitmap","(IIFFIZF)V",
909        (void*) SkCanvasGlue::drawBitmap__BitmapFFPaint},
910    {"native_drawBitmap","(IILandroid/graphics/Rect;Landroid/graphics/RectF;I)V",
911        (void*) SkCanvasGlue::drawBitmapRF},
912    {"native_drawBitmap","(IILandroid/graphics/Rect;Landroid/graphics/Rect;I)V",
913        (void*) SkCanvasGlue::drawBitmapRR},
914    {"native_drawBitmap", "(I[IIIFFIIZI)V",
915    (void*)SkCanvasGlue::drawBitmapArray},
916
917    {"nativeDrawBitmapMatrix", "(IIII)V",
918        (void*)SkCanvasGlue::drawBitmapMatrix},
919    {"nativeDrawBitmapMesh", "(IIII[FI[III)V",
920        (void*)SkCanvasGlue::drawBitmapMesh},
921    {"nativeDrawVertices", "(III[FI[FI[II[SIII)V",
922        (void*)SkCanvasGlue::drawVertices},
923    {"native_drawText","(I[CIIFFI)V",
924        (void*) SkCanvasGlue::drawText___CIIFFPaint},
925    {"native_drawText","(ILjava/lang/String;IIFFI)V",
926        (void*) SkCanvasGlue::drawText__StringIIFFPaint},
927    {"drawText","(Ljava/lang/String;FFLandroid/graphics/Paint;)V",
928        (void*) SkCanvasGlue::drawString},
929    {"native_drawPosText","(I[CII[FI)V",
930        (void*) SkCanvasGlue::drawPosText___CII_FPaint},
931    {"native_drawPosText","(ILjava/lang/String;[FI)V",
932        (void*) SkCanvasGlue::drawPosText__String_FPaint},
933    {"native_drawTextOnPath","(I[CIIIFFI)V",
934        (void*) SkCanvasGlue::drawTextOnPath___CIIPathFFPaint},
935    {"native_drawTextOnPath","(ILjava/lang/String;IFFI)V",
936        (void*) SkCanvasGlue::drawTextOnPath__StringPathFFPaint},
937    {"native_drawPicture", "(II)V", (void*) SkCanvasGlue::drawPicture},
938
939    {"freeCaches", "()V", (void*) SkCanvasGlue::freeCaches}
940};
941
942#include <android_runtime/AndroidRuntime.h>
943
944#define REG(env, name, array) \
945    result = android::AndroidRuntime::registerNativeMethods(env, name, array, \
946                                                    SK_ARRAY_COUNT(array));  \
947    if (result < 0) return result
948
949int register_android_graphics_Canvas(JNIEnv* env) {
950    int result;
951
952    REG(env, "android/graphics/Canvas", gCanvasMethods);
953
954    return result;
955}
956
957}
958