OSDN Git Service

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