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