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