Canvas.cpp revision afcf686cb070313ae5ce6c54ac381a3a86a60ed2
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 screenDensity, jint bitmapDensity) {
468        SkScalar left_ = SkFloatToScalar(left);
469        SkScalar top_ = SkFloatToScalar(top);
470
471        if (canvasDensity == bitmapDensity || canvasDensity == 0
472                || bitmapDensity == 0) {
473            if (screenDensity != 0 && screenDensity != bitmapDensity) {
474                SkPaint filteredPaint;
475                if (paint) {
476                    filteredPaint = *paint;
477                }
478                filteredPaint.setFilterBitmap(true);
479                canvas->drawBitmap(*bitmap, left_, top_, &filteredPaint);
480            } else {
481                canvas->drawBitmap(*bitmap, left_, top_, paint);
482            }
483        } else {
484            canvas->save();
485            SkScalar scale = SkFloatToScalar(canvasDensity / (float)bitmapDensity);
486            canvas->translate(left_, top_);
487            canvas->scale(scale, scale);
488
489            SkPaint filteredPaint;
490            if (paint) {
491                filteredPaint = *paint;
492            }
493            filteredPaint.setFilterBitmap(true);
494
495            canvas->drawBitmap(*bitmap, 0, 0, &filteredPaint);
496
497            canvas->restore();
498        }
499    }
500
501    static void doDrawBitmap(JNIEnv* env, SkCanvas* canvas, SkBitmap* bitmap,
502                        jobject srcIRect, const SkRect& dst, SkPaint* paint,
503                        jint screenDensity, jint bitmapDensity) {
504        SkIRect    src, *srcPtr = NULL;
505
506        if (NULL != srcIRect) {
507            GraphicsJNI::jrect_to_irect(env, srcIRect, &src);
508            srcPtr = &src;
509        }
510
511        if (screenDensity != 0 && screenDensity != bitmapDensity) {
512            SkPaint filteredPaint;
513            if (paint) {
514                filteredPaint = *paint;
515            }
516            filteredPaint.setFilterBitmap(true);
517            canvas->drawBitmapRect(*bitmap, srcPtr, dst, &filteredPaint);
518        } else {
519            canvas->drawBitmapRect(*bitmap, srcPtr, dst, paint);
520        }
521    }
522
523    static void drawBitmapRF(JNIEnv* env, jobject, SkCanvas* canvas,
524                             SkBitmap* bitmap, jobject srcIRect,
525                             jobject dstRectF, SkPaint* paint,
526                             jint screenDensity, jint bitmapDensity) {
527        SkRect      dst;
528        GraphicsJNI::jrectf_to_rect(env, dstRectF, &dst);
529        doDrawBitmap(env, canvas, bitmap, srcIRect, dst, paint,
530                screenDensity, bitmapDensity);
531    }
532
533    static void drawBitmapRR(JNIEnv* env, jobject, SkCanvas* canvas,
534                             SkBitmap* bitmap, jobject srcIRect,
535                             jobject dstRect, SkPaint* paint,
536                             jint screenDensity, jint bitmapDensity) {
537        SkRect      dst;
538        GraphicsJNI::jrect_to_rect(env, dstRect, &dst);
539        doDrawBitmap(env, canvas, bitmap, srcIRect, dst, paint,
540                screenDensity, bitmapDensity);
541    }
542
543    static void drawBitmapArray(JNIEnv* env, jobject, SkCanvas* canvas,
544                                jintArray jcolors, int offset, int stride,
545                                jfloat x, jfloat y, int width, int height,
546                                jboolean hasAlpha, SkPaint* paint)
547    {
548        SkBitmap    bitmap;
549
550        bitmap.setConfig(hasAlpha ? SkBitmap::kARGB_8888_Config :
551                         SkBitmap::kRGB_565_Config, width, height);
552        if (!bitmap.allocPixels()) {
553            return;
554        }
555
556        if (!GraphicsJNI::SetPixels(env, jcolors, offset, stride,
557                                    0, 0, width, height, bitmap)) {
558            return;
559        }
560
561        canvas->drawBitmap(bitmap, SkFloatToScalar(x), SkFloatToScalar(y),
562                           paint);
563    }
564
565    static void drawBitmapMatrix(JNIEnv* env, jobject, SkCanvas* canvas,
566                                 const SkBitmap* bitmap, const SkMatrix* matrix,
567                                 const SkPaint* paint) {
568        canvas->drawBitmapMatrix(*bitmap, *matrix, paint);
569    }
570
571    static void drawBitmapMesh(JNIEnv* env, jobject, SkCanvas* canvas,
572                          const SkBitmap* bitmap, int meshWidth, int meshHeight,
573                          jfloatArray jverts, int vertIndex, jintArray jcolors,
574                          int colorIndex, const SkPaint* paint) {
575
576        const int ptCount = (meshWidth + 1) * (meshHeight + 1);
577        const int indexCount = meshWidth * meshHeight * 6;
578
579        AutoJavaFloatArray  vertA(env, jverts, vertIndex + (ptCount << 1));
580        AutoJavaIntArray    colorA(env, jcolors, colorIndex + ptCount);
581
582        /*  Our temp storage holds 2 or 3 arrays.
583            texture points [ptCount * sizeof(SkPoint)]
584            optionally vertex points [ptCount * sizeof(SkPoint)] if we need a
585                copy to convert from float to fixed
586            indices [ptCount * sizeof(uint16_t)]
587        */
588        ssize_t storageSize = ptCount * sizeof(SkPoint); // texs[]
589#ifdef SK_SCALAR_IS_FIXED
590        storageSize += ptCount * sizeof(SkPoint);  // storage for verts
591#endif
592        storageSize += indexCount * sizeof(uint16_t);  // indices[]
593
594        SkAutoMalloc storage(storageSize);
595        SkPoint* texs = (SkPoint*)storage.get();
596        SkPoint* verts;
597        uint16_t* indices;
598#ifdef SK_SCALAR_IS_FLOAT
599        verts = (SkPoint*)(vertA.ptr() + vertIndex);
600        indices = (uint16_t*)(texs + ptCount);
601#else
602        verts = texs + ptCount;
603        indices = (uint16_t*)(verts + ptCount);
604        // convert floats to fixed
605        {
606            const float* src = vertA.ptr() + vertIndex;
607            for (int i = 0; i < ptCount; i++) {
608                verts[i].set(SkFloatToFixed(src[0]), SkFloatToFixed(src[1]));
609                src += 2;
610            }
611        }
612#endif
613
614        // cons up texture coordinates and indices
615        {
616            const SkScalar w = SkIntToScalar(bitmap->width());
617            const SkScalar h = SkIntToScalar(bitmap->height());
618            const SkScalar dx = w / meshWidth;
619            const SkScalar dy = h / meshHeight;
620
621            SkPoint* texsPtr = texs;
622            SkScalar y = 0;
623            for (int i = 0; i <= meshHeight; i++) {
624                if (i == meshHeight) {
625                    y = h;  // to ensure numerically we hit h exactly
626                }
627                SkScalar x = 0;
628                for (int j = 0; j < meshWidth; j++) {
629                    texsPtr->set(x, y);
630                    texsPtr += 1;
631                    x += dx;
632                }
633                texsPtr->set(w, y);
634                texsPtr += 1;
635                y += dy;
636            }
637            SkASSERT(texsPtr - texs == ptCount);
638        }
639
640        // cons up indices
641        {
642            uint16_t* indexPtr = indices;
643            int index = 0;
644            for (int i = 0; i < meshHeight; i++) {
645                for (int j = 0; j < meshWidth; j++) {
646                    // lower-left triangle
647                    *indexPtr++ = index;
648                    *indexPtr++ = index + meshWidth + 1;
649                    *indexPtr++ = index + meshWidth + 2;
650                    // upper-right triangle
651                    *indexPtr++ = index;
652                    *indexPtr++ = index + meshWidth + 2;
653                    *indexPtr++ = index + 1;
654                    // bump to the next cell
655                    index += 1;
656                }
657                // bump to the next row
658                index += 1;
659            }
660            SkASSERT(indexPtr - indices == indexCount);
661            SkASSERT((char*)indexPtr - (char*)storage.get() == storageSize);
662        }
663
664        // double-check that we have legal indices
665#ifdef SK_DEBUG
666        {
667            for (int i = 0; i < indexCount; i++) {
668                SkASSERT((unsigned)indices[i] < (unsigned)ptCount);
669            }
670        }
671#endif
672
673        // cons-up a shader for the bitmap
674        SkPaint tmpPaint;
675        if (paint) {
676            tmpPaint = *paint;
677        }
678        SkShader* shader = SkShader::CreateBitmapShader(*bitmap,
679                        SkShader::kClamp_TileMode, SkShader::kClamp_TileMode);
680        tmpPaint.setShader(shader)->safeUnref();
681
682        canvas->drawVertices(SkCanvas::kTriangles_VertexMode, ptCount, verts,
683                             texs, (const SkColor*)colorA.ptr(), NULL, indices,
684                             indexCount, tmpPaint);
685    }
686
687    static void drawVertices(JNIEnv* env, jobject, SkCanvas* canvas,
688                             SkCanvas::VertexMode mode, int vertexCount,
689                             jfloatArray jverts, int vertIndex,
690                             jfloatArray jtexs, int texIndex,
691                             jintArray jcolors, int colorIndex,
692                             jshortArray jindices, int indexIndex,
693                             int indexCount, const SkPaint* paint) {
694
695        AutoJavaFloatArray  vertA(env, jverts, vertIndex + vertexCount);
696        AutoJavaFloatArray  texA(env, jtexs, texIndex + vertexCount);
697        AutoJavaIntArray    colorA(env, jcolors, colorIndex + vertexCount);
698        AutoJavaShortArray  indexA(env, jindices, indexIndex + indexCount);
699
700        const int ptCount = vertexCount >> 1;
701
702        SkPoint* verts;
703        SkPoint* texs = NULL;
704#ifdef SK_SCALAR_IS_FLOAT
705        verts = (SkPoint*)(vertA.ptr() + vertIndex);
706        if (jtexs != NULL) {
707            texs = (SkPoint*)(texA.ptr() + texIndex);
708        }
709#else
710        int count = ptCount;    // for verts
711        if (jtexs != NULL) {
712            count += ptCount;   // += for texs
713        }
714        SkAutoMalloc storage(count * sizeof(SkPoint));
715        verts = (SkPoint*)storage.get();
716        const float* src = vertA.ptr() + vertIndex;
717        for (int i = 0; i < ptCount; i++) {
718            verts[i].set(SkFloatToFixed(src[0]), SkFloatToFixed(src[1]));
719            src += 2;
720        }
721        if (jtexs != NULL) {
722            texs = verts + ptCount;
723            src = texA.ptr() + texIndex;
724            for (int i = 0; i < ptCount; i++) {
725                texs[i].set(SkFloatToFixed(src[0]), SkFloatToFixed(src[1]));
726                src += 2;
727            }
728        }
729#endif
730
731        const SkColor* colors = NULL;
732        const uint16_t* indices = NULL;
733        if (jcolors != NULL) {
734            colors = (const SkColor*)(colorA.ptr() + colorIndex);
735        }
736        if (jindices != NULL) {
737            indices = (const uint16_t*)(indexA.ptr() + indexIndex);
738        }
739
740        canvas->drawVertices(mode, ptCount, verts, texs, colors, NULL,
741                             indices, indexCount, *paint);
742    }
743
744    static void drawText___CIIFFPaint(JNIEnv* env, jobject, SkCanvas* canvas,
745                                      jcharArray text, int index, int count,
746                                      jfloat x, jfloat y, SkPaint* paint) {
747        jchar* textArray = env->GetCharArrayElements(text, NULL);
748        jsize textCount = env->GetArrayLength(text);
749        SkScalar x_ = SkFloatToScalar(x);
750        SkScalar y_ = SkFloatToScalar(y);
751        canvas->drawText(textArray + index, count << 1, x_, y_, *paint);
752        env->ReleaseCharArrayElements(text, textArray, 0);
753    }
754
755    static void drawText__StringIIFFPaint(JNIEnv* env, jobject,
756                            SkCanvas* canvas, jstring text, int start, int end,
757                                          jfloat x, jfloat y, SkPaint* paint) {
758        const void* text_ = env->GetStringChars(text, NULL);
759        SkScalar x_ = SkFloatToScalar(x);
760        SkScalar y_ = SkFloatToScalar(y);
761        canvas->drawText((const uint16_t*)text_ + start, (end - start) << 1,
762                         x_, y_, *paint);
763        env->ReleaseStringChars(text, (const jchar*) text_);
764    }
765
766    static void drawString(JNIEnv* env, jobject canvas, jstring text,
767                           jfloat x, jfloat y, jobject paint) {
768        NPE_CHECK_RETURN_VOID(env, canvas);
769        NPE_CHECK_RETURN_VOID(env, paint);
770        NPE_CHECK_RETURN_VOID(env, text);
771        size_t count = env->GetStringLength(text);
772        if (0 == count) {
773            return;
774        }
775        const jchar* text_ = env->GetStringChars(text, NULL);
776        SkCanvas* c = GraphicsJNI::getNativeCanvas(env, canvas);
777        c->drawText(text_, count << 1, SkFloatToScalar(x), SkFloatToScalar(y),
778                    *GraphicsJNI::getNativePaint(env, paint));
779        env->ReleaseStringChars(text, text_);
780    }
781
782    static void drawPosText___CII_FPaint(JNIEnv* env, jobject, SkCanvas* canvas,
783                                         jcharArray text, int index, int count,
784                                         jfloatArray pos, SkPaint* paint) {
785        jchar* textArray = text ? env->GetCharArrayElements(text, NULL) : NULL;
786        jsize textCount = text ? env->GetArrayLength(text) : NULL;
787        float* posArray = pos ? env->GetFloatArrayElements(pos, NULL) : NULL;
788        int posCount = pos ? env->GetArrayLength(pos) >> 1: 0;
789        SkPoint* posPtr = posCount > 0 ? new SkPoint[posCount] : NULL;
790        int indx;
791        for (indx = 0; indx < posCount; indx++) {
792            posPtr[indx].fX = SkFloatToScalar(posArray[indx << 1]);
793            posPtr[indx].fY = SkFloatToScalar(posArray[(indx << 1) + 1]);
794        }
795        canvas->drawPosText(textArray + index, count << 1, posPtr, *paint);
796        if (text) {
797            env->ReleaseCharArrayElements(text, textArray, 0);
798        }
799        if (pos) {
800            env->ReleaseFloatArrayElements(pos, posArray, 0);
801        }
802        delete[] posPtr;
803    }
804
805    static void drawPosText__String_FPaint(JNIEnv* env, jobject,
806                                           SkCanvas* canvas, jstring text,
807                                           jfloatArray pos, SkPaint* paint) {
808        const void* text_ = text ? env->GetStringChars(text, NULL) : NULL;
809        int byteLength = text ? env->GetStringLength(text) : 0;
810        float* posArray = pos ? env->GetFloatArrayElements(pos, NULL) : NULL;
811        int posCount = pos ? env->GetArrayLength(pos) >> 1: 0;
812        SkPoint* posPtr = posCount > 0 ? new SkPoint[posCount] : NULL;
813
814        for (int indx = 0; indx < posCount; indx++) {
815            posPtr[indx].fX = SkFloatToScalar(posArray[indx << 1]);
816            posPtr[indx].fY = SkFloatToScalar(posArray[(indx << 1) + 1]);
817        }
818        canvas->drawPosText(text_, byteLength << 1, posPtr, *paint);
819        if (text) {
820            env->ReleaseStringChars(text, (const jchar*) text_);
821        }
822        if (pos) {
823            env->ReleaseFloatArrayElements(pos, posArray, 0);
824        }
825        delete[] posPtr;
826    }
827
828    static void drawTextOnPath___CIIPathFFPaint(JNIEnv* env, jobject,
829                        SkCanvas* canvas, jcharArray text, int index, int count,
830                SkPath* path, jfloat hOffset, jfloat vOffset, SkPaint* paint) {
831
832        jchar* textArray = env->GetCharArrayElements(text, NULL);
833        canvas->drawTextOnPathHV(textArray + index, count << 1, *path,
834                    SkFloatToScalar(hOffset), SkFloatToScalar(vOffset), *paint);
835        env->ReleaseCharArrayElements(text, textArray, 0);
836    }
837
838    static void drawTextOnPath__StringPathFFPaint(JNIEnv* env, jobject,
839                            SkCanvas* canvas, jstring text, SkPath* path,
840                            jfloat hOffset, jfloat vOffset, SkPaint* paint) {
841        const jchar* text_ = env->GetStringChars(text, NULL);
842        int byteLength = env->GetStringLength(text) << 1;
843        canvas->drawTextOnPathHV(text_, byteLength, *path,
844                    SkFloatToScalar(hOffset), SkFloatToScalar(vOffset), *paint);
845        env->ReleaseStringChars(text, text_);
846    }
847
848    static bool getClipBounds(JNIEnv* env, jobject, SkCanvas* canvas,
849                              jobject bounds) {
850        SkRect   r;
851        SkIRect ir;
852        bool     result = canvas->getClipBounds(&r, SkCanvas::kBW_EdgeType);
853
854        r.round(&ir);
855        (void)GraphicsJNI::irect_to_jrect(ir, env, bounds);
856        return result;
857    }
858
859    static void getCTM(JNIEnv* env, jobject, SkCanvas* canvas,
860                       SkMatrix* matrix) {
861        *matrix = canvas->getTotalMatrix();
862    }
863};
864
865///////////////////////////////////////////////////////////////////////////////
866
867static JNINativeMethod gCanvasMethods[] = {
868    {"finalizer", "(I)V", (void*) SkCanvasGlue::finalizer},
869    {"initRaster","(I)I", (void*) SkCanvasGlue::initRaster},
870    {"initGL","()I", (void*) SkCanvasGlue::initGL},
871    {"isOpaque","()Z", (void*) SkCanvasGlue::isOpaque},
872    {"getWidth","()I", (void*) SkCanvasGlue::getWidth},
873    {"getHeight","()I", (void*) SkCanvasGlue::getHeight},
874    {"native_setBitmap","(II)V", (void*) SkCanvasGlue::setBitmap},
875    {"nativeSetViewport", "(III)V", (void*) SkCanvasGlue::setViewport},
876    {"save","()I", (void*) SkCanvasGlue::saveAll},
877    {"save","(I)I", (void*) SkCanvasGlue::save},
878    {"native_saveLayer","(ILandroid/graphics/RectF;II)I",
879        (void*) SkCanvasGlue::saveLayer},
880    {"native_saveLayer","(IFFFFII)I", (void*) SkCanvasGlue::saveLayer4F},
881    {"native_saveLayerAlpha","(ILandroid/graphics/RectF;II)I",
882        (void*) SkCanvasGlue::saveLayerAlpha},
883    {"native_saveLayerAlpha","(IFFFFII)I",
884        (void*) SkCanvasGlue::saveLayerAlpha4F},
885    {"restore","()V", (void*) SkCanvasGlue::restore},
886    {"getSaveCount","()I", (void*) SkCanvasGlue::getSaveCount},
887    {"restoreToCount","(I)V", (void*) SkCanvasGlue::restoreToCount},
888    {"translate","(FF)V", (void*) SkCanvasGlue::translate},
889    {"scale","(FF)V", (void*) SkCanvasGlue::scale__FF},
890    {"rotate","(F)V", (void*) SkCanvasGlue::rotate__F},
891    {"skew","(FF)V", (void*) SkCanvasGlue::skew__FF},
892    {"native_concat","(II)V", (void*) SkCanvasGlue::concat},
893    {"native_setMatrix","(II)V", (void*) SkCanvasGlue::setMatrix},
894    {"clipRect","(FFFF)Z", (void*) SkCanvasGlue::clipRect_FFFF},
895    {"clipRect","(IIII)Z", (void*) SkCanvasGlue::clipRect_IIII},
896    {"clipRect","(Landroid/graphics/RectF;)Z",
897        (void*) SkCanvasGlue::clipRect_RectF},
898    {"clipRect","(Landroid/graphics/Rect;)Z",
899        (void*) SkCanvasGlue::clipRect_Rect},
900    {"native_clipRect","(IFFFFI)Z", (void*) SkCanvasGlue::clipRect},
901    {"native_clipPath","(III)Z", (void*) SkCanvasGlue::clipPath},
902    {"native_clipRegion","(III)Z", (void*) SkCanvasGlue::clipRegion},
903    {"nativeSetDrawFilter", "(II)V", (void*) SkCanvasGlue::setDrawFilter},
904    {"native_getClipBounds","(ILandroid/graphics/Rect;)Z",
905        (void*) SkCanvasGlue::getClipBounds},
906    {"native_getCTM", "(II)V", (void*)SkCanvasGlue::getCTM},
907    {"native_quickReject","(ILandroid/graphics/RectF;I)Z",
908        (void*) SkCanvasGlue::quickReject__RectFI},
909    {"native_quickReject","(III)Z", (void*) SkCanvasGlue::quickReject__PathI},
910    {"native_quickReject","(IFFFFI)Z", (void*)SkCanvasGlue::quickReject__FFFFI},
911    {"native_drawRGB","(IIII)V", (void*) SkCanvasGlue::drawRGB},
912    {"native_drawARGB","(IIIII)V", (void*) SkCanvasGlue::drawARGB},
913    {"native_drawColor","(II)V", (void*) SkCanvasGlue::drawColor__I},
914    {"native_drawColor","(III)V", (void*) SkCanvasGlue::drawColor__II},
915    {"native_drawPaint","(II)V", (void*) SkCanvasGlue::drawPaint},
916    {"drawPoint", "(FFLandroid/graphics/Paint;)V",
917    (void*) SkCanvasGlue::drawPoint},
918    {"drawPoints", "([FIILandroid/graphics/Paint;)V",
919        (void*) SkCanvasGlue::drawPoints},
920    {"drawLines", "([FIILandroid/graphics/Paint;)V",
921        (void*) SkCanvasGlue::drawLines},
922    {"native_drawLine","(IFFFFI)V", (void*) SkCanvasGlue::drawLine__FFFFPaint},
923    {"native_drawRect","(ILandroid/graphics/RectF;I)V",
924        (void*) SkCanvasGlue::drawRect__RectFPaint},
925    {"native_drawRect","(IFFFFI)V", (void*) SkCanvasGlue::drawRect__FFFFPaint},
926    {"native_drawOval","(ILandroid/graphics/RectF;I)V",
927        (void*) SkCanvasGlue::drawOval},
928    {"native_drawCircle","(IFFFI)V", (void*) SkCanvasGlue::drawCircle},
929    {"native_drawArc","(ILandroid/graphics/RectF;FFZI)V",
930        (void*) SkCanvasGlue::drawArc},
931    {"native_drawRoundRect","(ILandroid/graphics/RectF;FFI)V",
932        (void*) SkCanvasGlue::drawRoundRect},
933    {"native_drawPath","(III)V", (void*) SkCanvasGlue::drawPath},
934    {"native_drawBitmap","(IIFFIIII)V",
935        (void*) SkCanvasGlue::drawBitmap__BitmapFFPaint},
936    {"native_drawBitmap","(IILandroid/graphics/Rect;Landroid/graphics/RectF;III)V",
937        (void*) SkCanvasGlue::drawBitmapRF},
938    {"native_drawBitmap","(IILandroid/graphics/Rect;Landroid/graphics/Rect;III)V",
939        (void*) SkCanvasGlue::drawBitmapRR},
940    {"native_drawBitmap", "(I[IIIFFIIZI)V",
941    (void*)SkCanvasGlue::drawBitmapArray},
942
943    {"nativeDrawBitmapMatrix", "(IIII)V",
944        (void*)SkCanvasGlue::drawBitmapMatrix},
945    {"nativeDrawBitmapMesh", "(IIII[FI[III)V",
946        (void*)SkCanvasGlue::drawBitmapMesh},
947    {"nativeDrawVertices", "(III[FI[FI[II[SIII)V",
948        (void*)SkCanvasGlue::drawVertices},
949    {"native_drawText","(I[CIIFFI)V",
950        (void*) SkCanvasGlue::drawText___CIIFFPaint},
951    {"native_drawText","(ILjava/lang/String;IIFFI)V",
952        (void*) SkCanvasGlue::drawText__StringIIFFPaint},
953    {"drawText","(Ljava/lang/String;FFLandroid/graphics/Paint;)V",
954        (void*) SkCanvasGlue::drawString},
955    {"native_drawPosText","(I[CII[FI)V",
956        (void*) SkCanvasGlue::drawPosText___CII_FPaint},
957    {"native_drawPosText","(ILjava/lang/String;[FI)V",
958        (void*) SkCanvasGlue::drawPosText__String_FPaint},
959    {"native_drawTextOnPath","(I[CIIIFFI)V",
960        (void*) SkCanvasGlue::drawTextOnPath___CIIPathFFPaint},
961    {"native_drawTextOnPath","(ILjava/lang/String;IFFI)V",
962        (void*) SkCanvasGlue::drawTextOnPath__StringPathFFPaint},
963    {"native_drawPicture", "(II)V", (void*) SkCanvasGlue::drawPicture},
964
965    {"freeCaches", "()V", (void*) SkCanvasGlue::freeCaches}
966};
967
968#include <android_runtime/AndroidRuntime.h>
969
970#define REG(env, name, array) \
971    result = android::AndroidRuntime::registerNativeMethods(env, name, array, \
972                                                    SK_ARRAY_COUNT(array));  \
973    if (result < 0) return result
974
975int register_android_graphics_Canvas(JNIEnv* env) {
976    int result;
977
978    REG(env, "android/graphics/Canvas", gCanvasMethods);
979
980    return result;
981}
982
983}
984