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