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