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