OSDN Git Service

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