• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
get_canvas(jlong canvasHandle)35 static Canvas* get_canvas(jlong canvasHandle) {
36     return reinterpret_cast<Canvas*>(canvasHandle);
37 }
38 
delete_canvas(Canvas * canvas)39 static void delete_canvas(Canvas* canvas) {
40     delete canvas;
41 }
42 
getNativeFinalizer(JNIEnv * env,jobject clazz)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)
initRaster(JNIEnv * env,jobject,jobject jbitmap)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.
setBitmap(JNIEnv * env,jobject,jlong canvasHandle,jobject jbitmap)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 
isOpaque(JNIEnv *,jobject,jlong canvasHandle)66 static jboolean isOpaque(JNIEnv*, jobject, jlong canvasHandle) {
67     return get_canvas(canvasHandle)->isOpaque() ? JNI_TRUE : JNI_FALSE;
68 }
69 
getWidth(JNIEnv *,jobject,jlong canvasHandle)70 static jint getWidth(JNIEnv*, jobject, jlong canvasHandle) {
71     return static_cast<jint>(get_canvas(canvasHandle)->width());
72 }
73 
getHeight(JNIEnv *,jobject,jlong canvasHandle)74 static jint getHeight(JNIEnv*, jobject, jlong canvasHandle) {
75     return static_cast<jint>(get_canvas(canvasHandle)->height());
76 }
77 
setHighContrastText(JNIEnv *,jobject,jlong canvasHandle,jboolean highContrastText)78 static void setHighContrastText(JNIEnv*, jobject, jlong canvasHandle, jboolean highContrastText) {
79     Canvas* canvas = get_canvas(canvasHandle);
80     canvas->setHighContrastText(highContrastText);
81 }
82 
getSaveCount(JNIEnv *,jobject,jlong canvasHandle)83 static jint getSaveCount(JNIEnv*, jobject, jlong canvasHandle) {
84     return static_cast<jint>(get_canvas(canvasHandle)->getSaveCount());
85 }
86 
save(JNIEnv *,jobject,jlong canvasHandle,jint flagsHandle)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 
saveLayer(JNIEnv * env,jobject,jlong canvasHandle,jfloat l,jfloat t,jfloat r,jfloat b,jlong paintHandle,jint flagsHandle)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 
saveLayerAlpha(JNIEnv * env,jobject,jlong canvasHandle,jfloat l,jfloat t,jfloat r,jfloat b,jint alpha,jint flagsHandle)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 
restore(JNIEnv * env,jobject,jlong canvasHandle,jboolean throwOnUnderflow)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 
restoreToCount(JNIEnv * env,jobject,jlong canvasHandle,jint restoreCount,jboolean throwOnUnderflow)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 
getCTM(JNIEnv * env,jobject,jlong canvasHandle,jlong matrixHandle)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 
setMatrix(JNIEnv * env,jobject,jlong canvasHandle,jlong matrixHandle)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 
concat(JNIEnv * env,jobject,jlong canvasHandle,jlong matrixHandle)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 
rotate(JNIEnv *,jobject,jlong canvasHandle,jfloat degrees)144 static void rotate(JNIEnv*, jobject, jlong canvasHandle, jfloat degrees) {
145     get_canvas(canvasHandle)->rotate(degrees);
146 }
147 
scale(JNIEnv *,jobject,jlong canvasHandle,jfloat sx,jfloat sy)148 static void scale(JNIEnv*, jobject, jlong canvasHandle, jfloat sx, jfloat sy) {
149     get_canvas(canvasHandle)->scale(sx, sy);
150 }
151 
skew(JNIEnv *,jobject,jlong canvasHandle,jfloat sx,jfloat sy)152 static void skew(JNIEnv*, jobject, jlong canvasHandle, jfloat sx, jfloat sy) {
153     get_canvas(canvasHandle)->skew(sx, sy);
154 }
155 
translate(JNIEnv *,jobject,jlong canvasHandle,jfloat dx,jfloat dy)156 static void translate(JNIEnv*, jobject, jlong canvasHandle, jfloat dx, jfloat dy) {
157     get_canvas(canvasHandle)->translate(dx, dy);
158 }
159 
getClipBounds(JNIEnv * env,jobject,jlong canvasHandle,jobject bounds)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 
quickRejectRect(JNIEnv * env,jobject,jlong canvasHandle,jfloat left,jfloat top,jfloat right,jfloat bottom)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 
quickRejectPath(JNIEnv * env,jobject,jlong canvasHandle,jlong pathHandle)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 
clipRect(JNIEnv *,jobject,jlong canvasHandle,jfloat l,jfloat t,jfloat r,jfloat b,jint opHandle)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 
clipPath(JNIEnv * env,jobject,jlong canvasHandle,jlong pathHandle,jint opHandle)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 
clipRegion(JNIEnv * env,jobject,jlong canvasHandle,jlong deviceRgnHandle,jint opHandle)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 
drawColor(JNIEnv * env,jobject,jlong canvasHandle,jint color,jint modeHandle)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 
drawPaint(JNIEnv * env,jobject,jlong canvasHandle,jlong paintHandle)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 
drawPoint(JNIEnv *,jobject,jlong canvasHandle,jfloat x,jfloat y,jlong paintHandle)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 
drawPoints(JNIEnv * env,jobject,jlong canvasHandle,jfloatArray jptsArray,jint offset,jint count,jlong paintHandle)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 
drawLine(JNIEnv * env,jobject,jlong canvasHandle,jfloat startX,jfloat startY,jfloat stopX,jfloat stopY,jlong paintHandle)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 
drawLines(JNIEnv * env,jobject,jlong canvasHandle,jfloatArray jptsArray,jint offset,jint count,jlong paintHandle)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 
drawRect(JNIEnv * env,jobject,jlong canvasHandle,jfloat left,jfloat top,jfloat right,jfloat bottom,jlong paintHandle)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 
drawRegion(JNIEnv * env,jobject,jlong canvasHandle,jlong regionHandle,jlong paintHandle)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 
drawRoundRect(JNIEnv * env,jobject,jlong canvasHandle,jfloat left,jfloat top,jfloat right,jfloat bottom,jfloat rx,jfloat ry,jlong paintHandle)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 
drawCircle(JNIEnv * env,jobject,jlong canvasHandle,jfloat cx,jfloat cy,jfloat radius,jlong paintHandle)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 
drawOval(JNIEnv * env,jobject,jlong canvasHandle,jfloat left,jfloat top,jfloat right,jfloat bottom,jlong paintHandle)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 
drawArc(JNIEnv * env,jobject,jlong canvasHandle,jfloat left,jfloat top,jfloat right,jfloat bottom,jfloat startAngle,jfloat sweepAngle,jboolean useCenter,jlong paintHandle)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 
drawPath(JNIEnv * env,jobject,jlong canvasHandle,jlong pathHandle,jlong paintHandle)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 
drawVertices(JNIEnv * env,jobject,jlong canvasHandle,jint modeHandle,jint vertexCount,jfloatArray jverts,jint vertIndex,jfloatArray jtexs,jint texIndex,jintArray jcolors,jint colorIndex,jshortArray jindices,jint indexIndex,jint indexCount,jlong paintHandle)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 
drawNinePatch(JNIEnv * env,jobject,jlong canvasHandle,jlong bitmapHandle,jlong chunkHandle,jfloat left,jfloat top,jfloat right,jfloat bottom,jlong paintHandle,jint dstDensity,jint srcDensity)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 
drawBitmap(JNIEnv * env,jobject jcanvas,jlong canvasHandle,jobject jbitmap,jfloat left,jfloat top,jlong paintHandle,jint canvasDensity,jint screenDensity,jint bitmapDensity)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 
drawBitmapMatrix(JNIEnv * env,jobject,jlong canvasHandle,jobject jbitmap,jlong matrixHandle,jlong paintHandle)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 
drawBitmapRect(JNIEnv * env,jobject,jlong canvasHandle,jobject jbitmap,float srcLeft,float srcTop,float srcRight,float srcBottom,float dstLeft,float dstTop,float dstRight,float dstBottom,jlong paintHandle,jint screenDensity,jint bitmapDensity)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 
drawBitmapArray(JNIEnv * env,jobject,jlong canvasHandle,jintArray jcolors,jint offset,jint stride,jfloat x,jfloat y,jint width,jint height,jboolean hasAlpha,jlong paintHandle)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 
drawBitmapMesh(JNIEnv * env,jobject,jlong canvasHandle,jobject jbitmap,jint meshWidth,jint meshHeight,jfloatArray jverts,jint vertIndex,jintArray jcolors,jint colorIndex,jlong paintHandle)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 
drawTextChars(JNIEnv * env,jobject,jlong canvasHandle,jcharArray text,jint index,jint count,jfloat x,jfloat y,jint bidiFlags,jlong paintHandle,jlong typefaceHandle)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 
drawTextString(JNIEnv * env,jobject,jlong canvasHandle,jstring text,jint start,jint end,jfloat x,jfloat y,jint bidiFlags,jlong paintHandle,jlong typefaceHandle)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 
drawTextRunChars(JNIEnv * env,jobject,jlong canvasHandle,jcharArray text,jint index,jint count,jint contextIndex,jint contextCount,jfloat x,jfloat y,jboolean isRtl,jlong paintHandle,jlong typefaceHandle)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 
drawTextRunString(JNIEnv * env,jobject obj,jlong canvasHandle,jstring text,jint start,jint end,jint contextStart,jint contextEnd,jfloat x,jfloat y,jboolean isRtl,jlong paintHandle,jlong typefaceHandle)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 
drawTextOnPathChars(JNIEnv * env,jobject,jlong canvasHandle,jcharArray text,jint index,jint count,jlong pathHandle,jfloat hOffset,jfloat vOffset,jint bidiFlags,jlong paintHandle,jlong typefaceHandle)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 
drawTextOnPathString(JNIEnv * env,jobject,jlong canvasHandle,jstring text,jlong pathHandle,jfloat hOffset,jfloat vOffset,jint bidiFlags,jlong paintHandle,jlong typefaceHandle)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 
setDrawFilter(JNIEnv * env,jobject,jlong canvasHandle,jlong filterHandle)561 static void setDrawFilter(JNIEnv* env, jobject, jlong canvasHandle, jlong filterHandle) {
562     get_canvas(canvasHandle)->setDrawFilter(reinterpret_cast<SkDrawFilter*>(filterHandle));
563 }
564 
freeCaches(JNIEnv * env,jobject)565 static void freeCaches(JNIEnv* env, jobject) {
566     SkGraphics::PurgeFontCache();
567 }
568 
freeTextLayoutCaches(JNIEnv * env,jobject)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 
register_android_graphics_Canvas(JNIEnv * env)633 int register_android_graphics_Canvas(JNIEnv* env) {
634     return RegisterMethodsOrDie(env, "android/graphics/Canvas", gMethods, NELEM(gMethods));
635 }
636 
637 }; // namespace android
638