OSDN Git Service

DO NOT MERGE. Grant MMS Uri permissions as the calling UID.
[android-x86/frameworks-base.git] / core / jni / android_graphics_Canvas.cpp
1 /*
2  * Copyright (C) 2014 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 "core_jni_helpers.h"
20
21 #include <androidfw/ResourceTypes.h>
22 #include <hwui/Canvas.h>
23 #include <hwui/Paint.h>
24 #include <hwui/Typeface.h>
25 #include <minikin/Layout.h>
26
27 #include "Bitmap.h"
28 #include "SkDrawFilter.h"
29 #include "SkGraphics.h"
30
31 namespace android {
32
33 namespace CanvasJNI {
34
35 static Canvas* get_canvas(jlong canvasHandle) {
36     return reinterpret_cast<Canvas*>(canvasHandle);
37 }
38
39 static void delete_canvas(Canvas* canvas) {
40     delete canvas;
41 }
42
43 static jlong getNativeFinalizer(JNIEnv* env, jobject clazz) {
44     return static_cast<jlong>(reinterpret_cast<uintptr_t>(&delete_canvas));
45 }
46
47 // Native wrapper constructor used by Canvas(Bitmap)
48 static jlong initRaster(JNIEnv* env, jobject, jobject jbitmap) {
49     SkBitmap bitmap;
50     if (jbitmap != NULL) {
51         GraphicsJNI::getSkBitmap(env, jbitmap, &bitmap);
52     }
53     return reinterpret_cast<jlong>(Canvas::create_canvas(bitmap));
54 }
55
56 // Set the given bitmap as the new draw target (wrapped in a new SkCanvas),
57 // optionally copying canvas matrix & clip state.
58 static void setBitmap(JNIEnv* env, jobject, jlong canvasHandle, jobject jbitmap) {
59     SkBitmap bitmap;
60     if (jbitmap != NULL) {
61         GraphicsJNI::getSkBitmap(env, jbitmap, &bitmap);
62     }
63     get_canvas(canvasHandle)->setBitmap(bitmap);
64 }
65
66 static jboolean isOpaque(JNIEnv*, jobject, jlong canvasHandle) {
67     return get_canvas(canvasHandle)->isOpaque() ? JNI_TRUE : JNI_FALSE;
68 }
69
70 static jint getWidth(JNIEnv*, jobject, jlong canvasHandle) {
71     return static_cast<jint>(get_canvas(canvasHandle)->width());
72 }
73
74 static jint getHeight(JNIEnv*, jobject, jlong canvasHandle) {
75     return static_cast<jint>(get_canvas(canvasHandle)->height());
76 }
77
78 static void setHighContrastText(JNIEnv*, jobject, jlong canvasHandle, jboolean highContrastText) {
79     Canvas* canvas = get_canvas(canvasHandle);
80     canvas->setHighContrastText(highContrastText);
81 }
82
83 static jint getSaveCount(JNIEnv*, jobject, jlong canvasHandle) {
84     return static_cast<jint>(get_canvas(canvasHandle)->getSaveCount());
85 }
86
87 static jint save(JNIEnv*, jobject, jlong canvasHandle, jint flagsHandle) {
88     SaveFlags::Flags flags = static_cast<SaveFlags::Flags>(flagsHandle);
89     return static_cast<jint>(get_canvas(canvasHandle)->save(flags));
90 }
91
92 static jint saveLayer(JNIEnv* env, jobject, jlong canvasHandle, jfloat l, jfloat t,
93                       jfloat r, jfloat b, jlong paintHandle, jint flagsHandle) {
94     Paint* paint  = reinterpret_cast<Paint*>(paintHandle);
95     SaveFlags::Flags flags = static_cast<SaveFlags::Flags>(flagsHandle);
96     return static_cast<jint>(get_canvas(canvasHandle)->saveLayer(l, t, r, b, paint, flags));
97 }
98
99 static jint saveLayerAlpha(JNIEnv* env, jobject, jlong canvasHandle, jfloat l, jfloat t,
100                            jfloat r, jfloat b, jint alpha, jint flagsHandle) {
101     SaveFlags::Flags flags = static_cast<SaveFlags::Flags>(flagsHandle);
102     return static_cast<jint>(get_canvas(canvasHandle)->saveLayerAlpha(l, t, r, b, alpha, flags));
103 }
104
105 static void restore(JNIEnv* env, jobject, jlong canvasHandle, jboolean throwOnUnderflow) {
106     Canvas* canvas = get_canvas(canvasHandle);
107     if (canvas->getSaveCount() <= 1) {  // cannot restore anymore
108         if (throwOnUnderflow) {
109             doThrowISE(env, "Underflow in restore - more restores than saves");
110         }
111         return; // compat behavior - return without throwing
112     }
113     canvas->restore();
114 }
115
116 static void restoreToCount(JNIEnv* env, jobject, jlong canvasHandle, jint restoreCount,
117         jboolean throwOnUnderflow) {
118     Canvas* canvas = get_canvas(canvasHandle);
119     if (restoreCount < 1 || restoreCount > canvas->getSaveCount()) {
120         if (throwOnUnderflow) {
121             doThrowIAE(env, "Underflow in restoreToCount - more restores than saves");
122             return;
123         }
124         restoreCount = 1; // compat behavior - restore as far as possible
125     }
126     canvas->restoreToCount(restoreCount);
127 }
128
129 static void getCTM(JNIEnv* env, jobject, jlong canvasHandle, jlong matrixHandle) {
130     SkMatrix* matrix = reinterpret_cast<SkMatrix*>(matrixHandle);
131     get_canvas(canvasHandle)->getMatrix(matrix);
132 }
133
134 static void setMatrix(JNIEnv* env, jobject, jlong canvasHandle, jlong matrixHandle) {
135     const SkMatrix* matrix = reinterpret_cast<SkMatrix*>(matrixHandle);
136     get_canvas(canvasHandle)->setMatrix(matrix ? *matrix : SkMatrix::I());
137 }
138
139 static void concat(JNIEnv* env, jobject, jlong canvasHandle, jlong matrixHandle) {
140     const SkMatrix* matrix = reinterpret_cast<SkMatrix*>(matrixHandle);
141     get_canvas(canvasHandle)->concat(*matrix);
142 }
143
144 static void rotate(JNIEnv*, jobject, jlong canvasHandle, jfloat degrees) {
145     get_canvas(canvasHandle)->rotate(degrees);
146 }
147
148 static void scale(JNIEnv*, jobject, jlong canvasHandle, jfloat sx, jfloat sy) {
149     get_canvas(canvasHandle)->scale(sx, sy);
150 }
151
152 static void skew(JNIEnv*, jobject, jlong canvasHandle, jfloat sx, jfloat sy) {
153     get_canvas(canvasHandle)->skew(sx, sy);
154 }
155
156 static void translate(JNIEnv*, jobject, jlong canvasHandle, jfloat dx, jfloat dy) {
157     get_canvas(canvasHandle)->translate(dx, dy);
158 }
159
160 static jboolean getClipBounds(JNIEnv* env, jobject, jlong canvasHandle, jobject bounds) {
161     SkRect   r;
162     SkIRect ir;
163     bool result = get_canvas(canvasHandle)->getClipBounds(&r);
164
165     if (!result) {
166         r.setEmpty();
167     }
168     r.round(&ir);
169
170     (void)GraphicsJNI::irect_to_jrect(ir, env, bounds);
171     return result ? JNI_TRUE : JNI_FALSE;
172 }
173
174 static jboolean quickRejectRect(JNIEnv* env, jobject, jlong canvasHandle,
175                                 jfloat left, jfloat top, jfloat right, jfloat bottom) {
176     bool result = get_canvas(canvasHandle)->quickRejectRect(left, top, right, bottom);
177     return result ? JNI_TRUE : JNI_FALSE;
178 }
179
180 static jboolean quickRejectPath(JNIEnv* env, jobject, jlong canvasHandle, jlong pathHandle) {
181     SkPath* path = reinterpret_cast<SkPath*>(pathHandle);
182     bool result = get_canvas(canvasHandle)->quickRejectPath(*path);
183     return result ? JNI_TRUE : JNI_FALSE;
184 }
185
186 static jboolean clipRect(JNIEnv*, jobject, jlong canvasHandle, jfloat l, jfloat t,
187                          jfloat r, jfloat b, jint opHandle) {
188     SkRegion::Op op = static_cast<SkRegion::Op>(opHandle);
189     bool nonEmptyClip = get_canvas(canvasHandle)->clipRect(l, t, r, b, op);
190     return nonEmptyClip ? JNI_TRUE : JNI_FALSE;
191 }
192
193 static jboolean clipPath(JNIEnv* env, jobject, jlong canvasHandle, jlong pathHandle,
194                          jint opHandle) {
195     SkPath* path = reinterpret_cast<SkPath*>(pathHandle);
196     SkRegion::Op op = static_cast<SkRegion::Op>(opHandle);
197     bool nonEmptyClip = get_canvas(canvasHandle)->clipPath(path, op);
198     return nonEmptyClip ? JNI_TRUE : JNI_FALSE;
199 }
200
201 static jboolean clipRegion(JNIEnv* env, jobject, jlong canvasHandle, jlong deviceRgnHandle,
202                            jint opHandle) {
203     SkRegion* deviceRgn = reinterpret_cast<SkRegion*>(deviceRgnHandle);
204     SkRegion::Op op = static_cast<SkRegion::Op>(opHandle);
205     bool nonEmptyClip = get_canvas(canvasHandle)->clipRegion(deviceRgn, op);
206     return nonEmptyClip ? JNI_TRUE : JNI_FALSE;
207 }
208
209 static void drawColor(JNIEnv* env, jobject, jlong canvasHandle, jint color, jint modeHandle) {
210     SkXfermode::Mode mode = static_cast<SkXfermode::Mode>(modeHandle);
211     get_canvas(canvasHandle)->drawColor(color, mode);
212 }
213
214 static void drawPaint(JNIEnv* env, jobject, jlong canvasHandle, jlong paintHandle) {
215     Paint* paint = reinterpret_cast<Paint*>(paintHandle);
216     get_canvas(canvasHandle)->drawPaint(*paint);
217 }
218
219 static void drawPoint(JNIEnv*, jobject, jlong canvasHandle, jfloat x, jfloat y,
220                       jlong paintHandle) {
221     const Paint* paint = reinterpret_cast<Paint*>(paintHandle);
222     get_canvas(canvasHandle)->drawPoint(x, y, *paint);
223 }
224
225 static void drawPoints(JNIEnv* env, jobject, jlong canvasHandle, jfloatArray jptsArray,
226                        jint offset, jint count, jlong paintHandle) {
227     NPE_CHECK_RETURN_VOID(env, jptsArray);
228     AutoJavaFloatArray autoPts(env, jptsArray);
229     float* floats = autoPts.ptr();
230     const int length = autoPts.length();
231
232     if ((offset | count) < 0 || offset + count > length) {
233         doThrowAIOOBE(env);
234         return;
235     }
236
237     const Paint* paint = reinterpret_cast<Paint*>(paintHandle);
238     get_canvas(canvasHandle)->drawPoints(floats + offset, count, *paint);
239 }
240
241 static void drawLine(JNIEnv* env, jobject, jlong canvasHandle, jfloat startX, jfloat startY,
242                      jfloat stopX, jfloat stopY, jlong paintHandle) {
243     Paint* paint = reinterpret_cast<Paint*>(paintHandle);
244     get_canvas(canvasHandle)->drawLine(startX, startY, stopX, stopY, *paint);
245 }
246
247 static void drawLines(JNIEnv* env, jobject, jlong canvasHandle, jfloatArray jptsArray,
248                       jint offset, jint count, jlong paintHandle) {
249     NPE_CHECK_RETURN_VOID(env, jptsArray);
250     AutoJavaFloatArray autoPts(env, jptsArray);
251     float* floats = autoPts.ptr();
252     const int length = autoPts.length();
253
254     if ((offset | count) < 0 || offset + count > length) {
255         doThrowAIOOBE(env);
256         return;
257     }
258
259     const Paint* paint = reinterpret_cast<Paint*>(paintHandle);
260     get_canvas(canvasHandle)->drawLines(floats + offset, count, *paint);
261 }
262
263 static void drawRect(JNIEnv* env, jobject, jlong canvasHandle, jfloat left, jfloat top,
264                      jfloat right, jfloat bottom, jlong paintHandle) {
265     const Paint* paint = reinterpret_cast<Paint*>(paintHandle);
266     get_canvas(canvasHandle)->drawRect(left, top, right, bottom, *paint);
267 }
268
269 static void drawRegion(JNIEnv* env, jobject, jlong canvasHandle, jlong regionHandle,
270                        jlong paintHandle) {
271     const SkRegion* region = reinterpret_cast<SkRegion*>(regionHandle);
272     const Paint* paint = reinterpret_cast<Paint*>(paintHandle);
273     get_canvas(canvasHandle)->drawRegion(*region, *paint);
274 }
275
276 static void drawRoundRect(JNIEnv* env, jobject, jlong canvasHandle, jfloat left, jfloat top,
277                           jfloat right, jfloat bottom, jfloat rx, jfloat ry, jlong paintHandle) {
278     const Paint* paint = reinterpret_cast<Paint*>(paintHandle);
279     get_canvas(canvasHandle)->drawRoundRect(left, top, right, bottom, rx, ry, *paint);
280 }
281
282 static void drawCircle(JNIEnv* env, jobject, jlong canvasHandle, jfloat cx, jfloat cy,
283                        jfloat radius, jlong paintHandle) {
284     const Paint* paint = reinterpret_cast<Paint*>(paintHandle);
285     get_canvas(canvasHandle)->drawCircle(cx, cy, radius, *paint);
286 }
287
288 static void drawOval(JNIEnv* env, jobject, jlong canvasHandle, jfloat left, jfloat top,
289                      jfloat right, jfloat bottom, jlong paintHandle) {
290     const Paint* paint = reinterpret_cast<Paint*>(paintHandle);
291     get_canvas(canvasHandle)->drawOval(left, top, right, bottom, *paint);
292 }
293
294 static void drawArc(JNIEnv* env, jobject, jlong canvasHandle, jfloat left, jfloat top,
295                     jfloat right, jfloat bottom, jfloat startAngle, jfloat sweepAngle,
296                     jboolean useCenter, jlong paintHandle) {
297     const Paint* paint = reinterpret_cast<Paint*>(paintHandle);
298     get_canvas(canvasHandle)->drawArc(left, top, right, bottom, startAngle, sweepAngle,
299                                        useCenter, *paint);
300 }
301
302 static void drawPath(JNIEnv* env, jobject, jlong canvasHandle, jlong pathHandle,
303                      jlong paintHandle) {
304     const SkPath* path = reinterpret_cast<SkPath*>(pathHandle);
305     const Paint* paint = reinterpret_cast<Paint*>(paintHandle);
306     get_canvas(canvasHandle)->drawPath(*path, *paint);
307 }
308
309 static void drawVertices(JNIEnv* env, jobject, jlong canvasHandle,
310                          jint modeHandle, jint vertexCount,
311                          jfloatArray jverts, jint vertIndex,
312                          jfloatArray jtexs, jint texIndex,
313                          jintArray jcolors, jint colorIndex,
314                          jshortArray jindices, jint indexIndex,
315                          jint indexCount, jlong paintHandle) {
316     AutoJavaFloatArray  vertA(env, jverts, vertIndex + vertexCount);
317     AutoJavaFloatArray  texA(env, jtexs, texIndex + vertexCount);
318     AutoJavaIntArray    colorA(env, jcolors, colorIndex + vertexCount);
319     AutoJavaShortArray  indexA(env, jindices, indexIndex + indexCount);
320
321     const float* verts = vertA.ptr() + vertIndex;
322     const float* texs = texA.ptr() + vertIndex;
323     const int* colors = NULL;
324     const uint16_t* indices = NULL;
325
326     if (jcolors != NULL) {
327         colors = colorA.ptr() + colorIndex;
328     }
329     if (jindices != NULL) {
330         indices = (const uint16_t*)(indexA.ptr() + indexIndex);
331     }
332
333     SkCanvas::VertexMode mode = static_cast<SkCanvas::VertexMode>(modeHandle);
334     const Paint* paint = reinterpret_cast<Paint*>(paintHandle);
335     get_canvas(canvasHandle)->drawVertices(mode, vertexCount, verts, texs, colors,
336                                            indices, indexCount, *paint);
337 }
338
339 static void drawNinePatch(JNIEnv* env, jobject, jlong canvasHandle, jlong bitmapHandle,
340         jlong chunkHandle, jfloat left, jfloat top, jfloat right, jfloat bottom,
341         jlong paintHandle, jint dstDensity, jint srcDensity) {
342
343     Canvas* canvas = get_canvas(canvasHandle);
344     Bitmap* bitmap = reinterpret_cast<Bitmap*>(bitmapHandle);
345     SkBitmap skiaBitmap;
346     bitmap->getSkBitmap(&skiaBitmap);
347     const android::Res_png_9patch* chunk = reinterpret_cast<android::Res_png_9patch*>(chunkHandle);
348     const Paint* paint = reinterpret_cast<Paint*>(paintHandle);
349
350     if (CC_LIKELY(dstDensity == srcDensity || dstDensity == 0 || srcDensity == 0)) {
351         canvas->drawNinePatch(skiaBitmap, *chunk, left, top, right, bottom, paint);
352     } else {
353         canvas->save(SaveFlags::MatrixClip);
354
355         SkScalar scale = dstDensity / (float)srcDensity;
356         canvas->translate(left, top);
357         canvas->scale(scale, scale);
358
359         Paint filteredPaint;
360         if (paint) {
361             filteredPaint = *paint;
362         }
363         filteredPaint.setFilterQuality(kLow_SkFilterQuality);
364
365         canvas->drawNinePatch(skiaBitmap, *chunk, 0, 0, (right-left)/scale, (bottom-top)/scale,
366                 &filteredPaint);
367
368         canvas->restore();
369     }
370 }
371
372 static void drawBitmap(JNIEnv* env, jobject jcanvas, jlong canvasHandle, jobject jbitmap,
373                        jfloat left, jfloat top, jlong paintHandle, jint canvasDensity,
374                        jint screenDensity, jint bitmapDensity) {
375     Canvas* canvas = get_canvas(canvasHandle);
376     SkBitmap bitmap;
377     GraphicsJNI::getSkBitmap(env, jbitmap, &bitmap);
378     const Paint* paint = reinterpret_cast<Paint*>(paintHandle);
379
380     if (canvasDensity == bitmapDensity || canvasDensity == 0 || bitmapDensity == 0) {
381         if (screenDensity != 0 && screenDensity != bitmapDensity) {
382             Paint filteredPaint;
383             if (paint) {
384                 filteredPaint = *paint;
385             }
386             filteredPaint.setFilterQuality(kLow_SkFilterQuality);
387             canvas->drawBitmap(bitmap, left, top, &filteredPaint);
388         } else {
389             canvas->drawBitmap(bitmap, left, top, paint);
390         }
391     } else {
392         canvas->save(SaveFlags::MatrixClip);
393         SkScalar scale = canvasDensity / (float)bitmapDensity;
394         canvas->translate(left, top);
395         canvas->scale(scale, scale);
396
397         Paint filteredPaint;
398         if (paint) {
399             filteredPaint = *paint;
400         }
401         filteredPaint.setFilterQuality(kLow_SkFilterQuality);
402
403         canvas->drawBitmap(bitmap, 0, 0, &filteredPaint);
404         canvas->restore();
405     }
406 }
407
408 static void drawBitmapMatrix(JNIEnv* env, jobject, jlong canvasHandle, jobject jbitmap,
409                              jlong matrixHandle, jlong paintHandle) {
410     const SkMatrix* matrix = reinterpret_cast<SkMatrix*>(matrixHandle);
411     const Paint* paint = reinterpret_cast<Paint*>(paintHandle);
412     SkBitmap bitmap;
413     GraphicsJNI::getSkBitmap(env, jbitmap, &bitmap);
414     get_canvas(canvasHandle)->drawBitmap(bitmap, *matrix, paint);
415 }
416
417 static void drawBitmapRect(JNIEnv* env, jobject, jlong canvasHandle, jobject jbitmap,
418                            float srcLeft, float srcTop, float srcRight, float srcBottom,
419                            float dstLeft, float dstTop, float dstRight, float dstBottom,
420                            jlong paintHandle, jint screenDensity, jint bitmapDensity) {
421     Canvas* canvas = get_canvas(canvasHandle);
422     const Paint* paint = reinterpret_cast<Paint*>(paintHandle);
423
424     SkBitmap bitmap;
425     GraphicsJNI::getSkBitmap(env, jbitmap, &bitmap);
426     if (screenDensity != 0 && screenDensity != bitmapDensity) {
427         Paint filteredPaint;
428         if (paint) {
429             filteredPaint = *paint;
430         }
431         filteredPaint.setFilterQuality(kLow_SkFilterQuality);
432         canvas->drawBitmap(bitmap, srcLeft, srcTop, srcRight, srcBottom,
433                            dstLeft, dstTop, dstRight, dstBottom, &filteredPaint);
434     } else {
435         canvas->drawBitmap(bitmap, srcLeft, srcTop, srcRight, srcBottom,
436                            dstLeft, dstTop, dstRight, dstBottom, paint);
437     }
438 }
439
440 static void drawBitmapArray(JNIEnv* env, jobject, jlong canvasHandle,
441                             jintArray jcolors, jint offset, jint stride,
442                             jfloat x, jfloat y, jint width, jint height,
443                             jboolean hasAlpha, jlong paintHandle) {
444     // Note: If hasAlpha is false, kRGB_565_SkColorType will be used, which will
445     // correct the alphaType to kOpaque_SkAlphaType.
446     SkImageInfo info = SkImageInfo::Make(width, height,
447                            hasAlpha ? kN32_SkColorType : kRGB_565_SkColorType,
448                            kPremul_SkAlphaType);
449     SkBitmap bitmap;
450     bitmap.setInfo(info);
451     if (!GraphicsJNI::allocatePixels(env, &bitmap, NULL)) {
452         return;
453     }
454
455     if (!GraphicsJNI::SetPixels(env, jcolors, offset, stride, 0, 0, width, height, bitmap)) {
456         return;
457     }
458
459     const Paint* paint = reinterpret_cast<Paint*>(paintHandle);
460     get_canvas(canvasHandle)->drawBitmap(bitmap, x, y, paint);
461 }
462
463 static void drawBitmapMesh(JNIEnv* env, jobject, jlong canvasHandle, jobject jbitmap,
464                            jint meshWidth, jint meshHeight, jfloatArray jverts,
465                            jint vertIndex, jintArray jcolors, jint colorIndex, jlong paintHandle) {
466     const int ptCount = (meshWidth + 1) * (meshHeight + 1);
467     AutoJavaFloatArray vertA(env, jverts, vertIndex + (ptCount << 1));
468     AutoJavaIntArray colorA(env, jcolors, colorIndex + ptCount);
469
470     const Paint* paint = reinterpret_cast<Paint*>(paintHandle);
471     SkBitmap bitmap;
472     GraphicsJNI::getSkBitmap(env, jbitmap, &bitmap);
473     get_canvas(canvasHandle)->drawBitmapMesh(bitmap, meshWidth, meshHeight,
474                                              vertA.ptr(), colorA.ptr(), paint);
475 }
476
477 static void drawTextChars(JNIEnv* env, jobject, jlong canvasHandle, jcharArray text,
478                           jint index, jint count, jfloat x, jfloat y, jint bidiFlags,
479                           jlong paintHandle, jlong typefaceHandle) {
480     Paint* paint = reinterpret_cast<Paint*>(paintHandle);
481     Typeface* typeface = reinterpret_cast<Typeface*>(typefaceHandle);
482     jchar* jchars = env->GetCharArrayElements(text, NULL);
483     get_canvas(canvasHandle)->drawText(jchars + index, 0, count, count, x, y,
484                                        bidiFlags, *paint, typeface);
485     env->ReleaseCharArrayElements(text, jchars, JNI_ABORT);
486 }
487
488 static void drawTextString(JNIEnv* env, jobject, jlong canvasHandle, jstring text,
489                            jint start, jint end, jfloat x, jfloat y, jint bidiFlags,
490                            jlong paintHandle, jlong typefaceHandle) {
491     Paint* paint = reinterpret_cast<Paint*>(paintHandle);
492     Typeface* typeface = reinterpret_cast<Typeface*>(typefaceHandle);
493     const int count = end - start;
494     const jchar* jchars = env->GetStringChars(text, NULL);
495     get_canvas(canvasHandle)->drawText(jchars + start, 0, count, count, x, y,
496                                        bidiFlags, *paint, typeface);
497     env->ReleaseStringChars(text, jchars);
498 }
499
500 static void drawTextRunChars(JNIEnv* env, jobject, jlong canvasHandle, jcharArray text, jint index,
501                              jint count, jint contextIndex, jint contextCount, jfloat x, jfloat y,
502                              jboolean isRtl, jlong paintHandle, jlong typefaceHandle) {
503     Paint* paint = reinterpret_cast<Paint*>(paintHandle);
504     Typeface* typeface = reinterpret_cast<Typeface*>(typefaceHandle);
505
506     const int bidiFlags = isRtl ? kBidi_Force_RTL : kBidi_Force_LTR;
507     jchar* jchars = env->GetCharArrayElements(text, NULL);
508     get_canvas(canvasHandle)->drawText(jchars + contextIndex, index - contextIndex, count,
509                                        contextCount, x, y, bidiFlags, *paint, typeface);
510     env->ReleaseCharArrayElements(text, jchars, JNI_ABORT);
511 }
512
513 static void drawTextRunString(JNIEnv* env, jobject obj, jlong canvasHandle, jstring text,
514                               jint start, jint end, jint contextStart, jint contextEnd,
515                               jfloat x, jfloat y, jboolean isRtl, jlong paintHandle,
516                               jlong typefaceHandle) {
517     Paint* paint = reinterpret_cast<Paint*>(paintHandle);
518     Typeface* typeface = reinterpret_cast<Typeface*>(typefaceHandle);
519
520     int bidiFlags = isRtl ? kBidi_Force_RTL : kBidi_Force_LTR;
521     jint count = end - start;
522     jint contextCount = contextEnd - contextStart;
523     const jchar* jchars = env->GetStringChars(text, NULL);
524     get_canvas(canvasHandle)->drawText(jchars + contextStart, start - contextStart, count,
525                                        contextCount, x, y, bidiFlags, *paint, typeface);
526     env->ReleaseStringChars(text, jchars);
527 }
528
529 static void drawTextOnPathChars(JNIEnv* env, jobject, jlong canvasHandle, jcharArray text,
530                                 jint index, jint count, jlong pathHandle, jfloat hOffset,
531                                 jfloat vOffset, jint bidiFlags, jlong paintHandle,
532                                 jlong typefaceHandle) {
533     SkPath* path = reinterpret_cast<SkPath*>(pathHandle);
534     Paint* paint = reinterpret_cast<Paint*>(paintHandle);
535     Typeface* typeface = reinterpret_cast<Typeface*>(typefaceHandle);
536
537     jchar* jchars = env->GetCharArrayElements(text, NULL);
538
539     get_canvas(canvasHandle)->drawTextOnPath(jchars + index, count, bidiFlags, *path,
540                    hOffset, vOffset, *paint, typeface);
541
542     env->ReleaseCharArrayElements(text, jchars, 0);
543 }
544
545 static void drawTextOnPathString(JNIEnv* env, jobject, jlong canvasHandle, jstring text,
546                                  jlong pathHandle, jfloat hOffset, jfloat vOffset,
547                                  jint bidiFlags, jlong paintHandle, jlong typefaceHandle) {
548     SkPath* path = reinterpret_cast<SkPath*>(pathHandle);
549     Paint* paint = reinterpret_cast<Paint*>(paintHandle);
550     Typeface* typeface = reinterpret_cast<Typeface*>(typefaceHandle);
551
552     const jchar* jchars = env->GetStringChars(text, NULL);
553     int count = env->GetStringLength(text);
554
555     get_canvas(canvasHandle)->drawTextOnPath(jchars, count, bidiFlags, *path,
556                    hOffset, vOffset, *paint, typeface);
557
558     env->ReleaseStringChars(text, jchars);
559 }
560
561 static void setDrawFilter(JNIEnv* env, jobject, jlong canvasHandle, jlong filterHandle) {
562     get_canvas(canvasHandle)->setDrawFilter(reinterpret_cast<SkDrawFilter*>(filterHandle));
563 }
564
565 static void freeCaches(JNIEnv* env, jobject) {
566     SkGraphics::PurgeFontCache();
567 }
568
569 static void freeTextLayoutCaches(JNIEnv* env, jobject) {
570     Layout::purgeCaches();
571 }
572
573 }; // namespace CanvasJNI
574
575 static const JNINativeMethod gMethods[] = {
576     {"getNativeFinalizer", "()J", (void*) CanvasJNI::getNativeFinalizer},
577     {"initRaster", "(Landroid/graphics/Bitmap;)J", (void*) CanvasJNI::initRaster},
578     {"native_setBitmap", "!(JLandroid/graphics/Bitmap;)V", (void*) CanvasJNI::setBitmap},
579     {"native_isOpaque","!(J)Z", (void*) CanvasJNI::isOpaque},
580     {"native_getWidth","!(J)I", (void*) CanvasJNI::getWidth},
581     {"native_getHeight","!(J)I", (void*) CanvasJNI::getHeight},
582     {"native_setHighContrastText","!(JZ)V", (void*) CanvasJNI::setHighContrastText},
583     {"native_save","!(JI)I", (void*) CanvasJNI::save},
584     {"native_saveLayer","!(JFFFFJI)I", (void*) CanvasJNI::saveLayer},
585     {"native_saveLayerAlpha","!(JFFFFII)I", (void*) CanvasJNI::saveLayerAlpha},
586     {"native_getSaveCount","!(J)I", (void*) CanvasJNI::getSaveCount},
587     {"native_restore","!(JZ)V", (void*) CanvasJNI::restore},
588     {"native_restoreToCount","!(JIZ)V", (void*) CanvasJNI::restoreToCount},
589     {"native_getCTM", "!(JJ)V", (void*)CanvasJNI::getCTM},
590     {"native_setMatrix","!(JJ)V", (void*) CanvasJNI::setMatrix},
591     {"native_concat","!(JJ)V", (void*) CanvasJNI::concat},
592     {"native_rotate","!(JF)V", (void*) CanvasJNI::rotate},
593     {"native_scale","!(JFF)V", (void*) CanvasJNI::scale},
594     {"native_skew","!(JFF)V", (void*) CanvasJNI::skew},
595     {"native_translate","!(JFF)V", (void*) CanvasJNI::translate},
596     {"native_getClipBounds","!(JLandroid/graphics/Rect;)Z", (void*) CanvasJNI::getClipBounds},
597     {"native_quickReject","!(JJ)Z", (void*) CanvasJNI::quickRejectPath},
598     {"native_quickReject","!(JFFFF)Z", (void*)CanvasJNI::quickRejectRect},
599     {"native_clipRect","!(JFFFFI)Z", (void*) CanvasJNI::clipRect},
600     {"native_clipPath","!(JJI)Z", (void*) CanvasJNI::clipPath},
601     {"native_clipRegion","!(JJI)Z", (void*) CanvasJNI::clipRegion},
602     {"native_drawColor","!(JII)V", (void*) CanvasJNI::drawColor},
603     {"native_drawPaint","!(JJ)V", (void*) CanvasJNI::drawPaint},
604     {"native_drawPoint", "!(JFFJ)V", (void*) CanvasJNI::drawPoint},
605     {"native_drawPoints", "!(J[FIIJ)V", (void*) CanvasJNI::drawPoints},
606     {"native_drawLine", "!(JFFFFJ)V", (void*) CanvasJNI::drawLine},
607     {"native_drawLines", "!(J[FIIJ)V", (void*) CanvasJNI::drawLines},
608     {"native_drawRect","!(JFFFFJ)V", (void*) CanvasJNI::drawRect},
609     {"native_drawRegion", "!(JJJ)V", (void*) CanvasJNI::drawRegion },
610     {"native_drawRoundRect","!(JFFFFFFJ)V", (void*) CanvasJNI::drawRoundRect},
611     {"native_drawCircle","!(JFFFJ)V", (void*) CanvasJNI::drawCircle},
612     {"native_drawOval","!(JFFFFJ)V", (void*) CanvasJNI::drawOval},
613     {"native_drawArc","!(JFFFFFFZJ)V", (void*) CanvasJNI::drawArc},
614     {"native_drawPath","!(JJJ)V", (void*) CanvasJNI::drawPath},
615     {"nativeDrawVertices", "!(JII[FI[FI[II[SIIJ)V", (void*)CanvasJNI::drawVertices},
616     {"native_drawNinePatch", "!(JJJFFFFJII)V", (void*)CanvasJNI::drawNinePatch},
617     {"native_drawBitmap","!(JLandroid/graphics/Bitmap;FFJIII)V", (void*) CanvasJNI::drawBitmap},
618     {"nativeDrawBitmapMatrix", "!(JLandroid/graphics/Bitmap;JJ)V", (void*)CanvasJNI::drawBitmapMatrix},
619     {"native_drawBitmap","!(JLandroid/graphics/Bitmap;FFFFFFFFJII)V", (void*) CanvasJNI::drawBitmapRect},
620     {"native_drawBitmap", "!(J[IIIFFIIZJ)V", (void*)CanvasJNI::drawBitmapArray},
621     {"nativeDrawBitmapMesh", "!(JLandroid/graphics/Bitmap;II[FI[IIJ)V", (void*)CanvasJNI::drawBitmapMesh},
622     {"native_drawText","!(J[CIIFFIJJ)V", (void*) CanvasJNI::drawTextChars},
623     {"native_drawText","!(JLjava/lang/String;IIFFIJJ)V", (void*) CanvasJNI::drawTextString},
624     {"native_drawTextRun","!(J[CIIIIFFZJJ)V", (void*) CanvasJNI::drawTextRunChars},
625     {"native_drawTextRun","!(JLjava/lang/String;IIIIFFZJJ)V", (void*) CanvasJNI::drawTextRunString},
626     {"native_drawTextOnPath","!(J[CIIJFFIJJ)V", (void*) CanvasJNI::drawTextOnPathChars},
627     {"native_drawTextOnPath","!(JLjava/lang/String;JFFIJJ)V", (void*) CanvasJNI::drawTextOnPathString},
628     {"nativeSetDrawFilter", "!(JJ)V", (void*) CanvasJNI::setDrawFilter},
629     {"freeCaches", "()V", (void*) CanvasJNI::freeCaches},
630     {"freeTextLayoutCaches", "()V", (void*) CanvasJNI::freeTextLayoutCaches}
631 };
632
633 int register_android_graphics_Canvas(JNIEnv* env) {
634     return RegisterMethodsOrDie(env, "android/graphics/Canvas", gMethods, NELEM(gMethods));
635 }
636
637 }; // namespace android