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 #include "SkRegion.h"
31 
32 namespace android {
33 
34 namespace CanvasJNI {
35 
get_canvas(jlong canvasHandle)36 static Canvas* get_canvas(jlong canvasHandle) {
37     return reinterpret_cast<Canvas*>(canvasHandle);
38 }
39 
delete_canvas(Canvas * canvas)40 static void delete_canvas(Canvas* canvas) {
41     delete canvas;
42 }
43 
getNativeFinalizer(JNIEnv * env,jobject clazz)44 static jlong getNativeFinalizer(JNIEnv* env, jobject clazz) {
45     return static_cast<jlong>(reinterpret_cast<uintptr_t>(&delete_canvas));
46 }
47 
48 // Native wrapper constructor used by Canvas(Bitmap)
initRaster(JNIEnv * env,jobject,jobject jbitmap)49 static jlong initRaster(JNIEnv* env, jobject, jobject jbitmap) {
50     SkBitmap bitmap;
51     if (jbitmap != NULL) {
52         GraphicsJNI::getSkBitmap(env, jbitmap, &bitmap);
53     }
54     return reinterpret_cast<jlong>(Canvas::create_canvas(bitmap));
55 }
56 
57 // Set the given bitmap as the new draw target (wrapped in a new SkCanvas),
58 // optionally copying canvas matrix & clip state.
setBitmap(JNIEnv * env,jobject,jlong canvasHandle,jobject jbitmap)59 static void setBitmap(JNIEnv* env, jobject, jlong canvasHandle, jobject jbitmap) {
60     SkBitmap bitmap;
61     if (jbitmap != NULL) {
62         GraphicsJNI::getSkBitmap(env, jbitmap, &bitmap);
63     }
64     get_canvas(canvasHandle)->setBitmap(bitmap);
65 }
66 
isOpaque(jlong canvasHandle)67 static jboolean isOpaque(jlong canvasHandle) {
68     return get_canvas(canvasHandle)->isOpaque() ? JNI_TRUE : JNI_FALSE;
69 }
70 
getWidth(jlong canvasHandle)71 static jint getWidth(jlong canvasHandle) {
72     return static_cast<jint>(get_canvas(canvasHandle)->width());
73 }
74 
getHeight(jlong canvasHandle)75 static jint getHeight(jlong canvasHandle) {
76     return static_cast<jint>(get_canvas(canvasHandle)->height());
77 }
78 
setHighContrastText(jlong canvasHandle,jboolean highContrastText)79 static void setHighContrastText(jlong canvasHandle, jboolean highContrastText) {
80     Canvas* canvas = get_canvas(canvasHandle);
81     canvas->setHighContrastText(highContrastText);
82 }
83 
save(jlong canvasHandle,jint flagsHandle)84 static jint save(jlong canvasHandle, jint flagsHandle) {
85     SaveFlags::Flags flags = static_cast<SaveFlags::Flags>(flagsHandle);
86     return static_cast<jint>(get_canvas(canvasHandle)->save(flags));
87 }
88 
saveLayer(jlong canvasHandle,jfloat l,jfloat t,jfloat r,jfloat b,jlong paintHandle,jint flagsHandle)89 static jint saveLayer(jlong canvasHandle, jfloat l, jfloat t,
90                       jfloat r, jfloat b, jlong paintHandle, jint flagsHandle) {
91     Paint* paint  = reinterpret_cast<Paint*>(paintHandle);
92     SaveFlags::Flags flags = static_cast<SaveFlags::Flags>(flagsHandle);
93     return static_cast<jint>(get_canvas(canvasHandle)->saveLayer(l, t, r, b, paint, flags));
94 }
95 
saveLayerAlpha(jlong canvasHandle,jfloat l,jfloat t,jfloat r,jfloat b,jint alpha,jint flagsHandle)96 static jint saveLayerAlpha(jlong canvasHandle, jfloat l, jfloat t,
97                            jfloat r, jfloat b, jint alpha, jint flagsHandle) {
98     SaveFlags::Flags flags = static_cast<SaveFlags::Flags>(flagsHandle);
99     return static_cast<jint>(get_canvas(canvasHandle)->saveLayerAlpha(l, t, r, b, alpha, flags));
100 }
101 
restore(jlong canvasHandle)102 static bool restore(jlong canvasHandle) {
103     Canvas* canvas = get_canvas(canvasHandle);
104     if (canvas->getSaveCount() <= 1) {
105         return false; // cannot restore anymore
106     }
107     canvas->restore();
108     return true; // success
109 }
110 
restoreToCount(jlong canvasHandle,jint saveCount)111 static void restoreToCount(jlong canvasHandle, jint saveCount) {
112     Canvas* canvas = get_canvas(canvasHandle);
113     canvas->restoreToCount(saveCount);
114 }
115 
getSaveCount(jlong canvasHandle)116 static jint getSaveCount(jlong canvasHandle) {
117     return static_cast<jint>(get_canvas(canvasHandle)->getSaveCount());
118 }
119 
getMatrix(jlong canvasHandle,jlong matrixHandle)120 static void getMatrix(jlong canvasHandle, jlong matrixHandle) {
121     SkMatrix* matrix = reinterpret_cast<SkMatrix*>(matrixHandle);
122     get_canvas(canvasHandle)->getMatrix(matrix);
123 }
124 
setMatrix(jlong canvasHandle,jlong matrixHandle)125 static void setMatrix(jlong canvasHandle, jlong matrixHandle) {
126     const SkMatrix* matrix = reinterpret_cast<SkMatrix*>(matrixHandle);
127     get_canvas(canvasHandle)->setMatrix(matrix ? *matrix : SkMatrix::I());
128 }
129 
concat(jlong canvasHandle,jlong matrixHandle)130 static void concat(jlong canvasHandle, jlong matrixHandle) {
131     const SkMatrix* matrix = reinterpret_cast<SkMatrix*>(matrixHandle);
132     get_canvas(canvasHandle)->concat(*matrix);
133 }
134 
rotate(jlong canvasHandle,jfloat degrees)135 static void rotate(jlong canvasHandle, jfloat degrees) {
136     get_canvas(canvasHandle)->rotate(degrees);
137 }
138 
scale(jlong canvasHandle,jfloat sx,jfloat sy)139 static void scale(jlong canvasHandle, jfloat sx, jfloat sy) {
140     get_canvas(canvasHandle)->scale(sx, sy);
141 }
142 
skew(jlong canvasHandle,jfloat sx,jfloat sy)143 static void skew(jlong canvasHandle, jfloat sx, jfloat sy) {
144     get_canvas(canvasHandle)->skew(sx, sy);
145 }
146 
translate(jlong canvasHandle,jfloat dx,jfloat dy)147 static void translate(jlong canvasHandle, jfloat dx, jfloat dy) {
148     get_canvas(canvasHandle)->translate(dx, dy);
149 }
150 
getClipBounds(JNIEnv * env,jobject,jlong canvasHandle,jobject bounds)151 static jboolean getClipBounds(JNIEnv* env, jobject, jlong canvasHandle, jobject bounds) {
152     SkRect   r;
153     SkIRect ir;
154     bool result = get_canvas(canvasHandle)->getClipBounds(&r);
155 
156     if (!result) {
157         r.setEmpty();
158     }
159     r.round(&ir);
160 
161     (void)GraphicsJNI::irect_to_jrect(ir, env, bounds);
162     return result ? JNI_TRUE : JNI_FALSE;
163 }
164 
quickRejectRect(jlong canvasHandle,jfloat left,jfloat top,jfloat right,jfloat bottom)165 static jboolean quickRejectRect(jlong canvasHandle,
166                                 jfloat left, jfloat top, jfloat right, jfloat bottom) {
167     bool result = get_canvas(canvasHandle)->quickRejectRect(left, top, right, bottom);
168     return result ? JNI_TRUE : JNI_FALSE;
169 }
170 
quickRejectPath(jlong canvasHandle,jlong pathHandle)171 static jboolean quickRejectPath(jlong canvasHandle, jlong pathHandle) {
172     SkPath* path = reinterpret_cast<SkPath*>(pathHandle);
173     bool result = get_canvas(canvasHandle)->quickRejectPath(*path);
174     return result ? JNI_TRUE : JNI_FALSE;
175 }
176 
177 // SkRegion::Op and SkClipOp are numerically identical, so we can freely cast
178 // from one to the other (though SkClipOp is destined to become a strict subset)
179 static_assert(SkRegion::kDifference_Op == static_cast<SkRegion::Op>(SkClipOp::kDifference), "");
180 static_assert(SkRegion::kIntersect_Op == static_cast<SkRegion::Op>(SkClipOp::kIntersect), "");
181 static_assert(SkRegion::kUnion_Op == static_cast<SkRegion::Op>(SkClipOp::kUnion_deprecated), "");
182 static_assert(SkRegion::kXOR_Op == static_cast<SkRegion::Op>(SkClipOp::kXOR_deprecated), "");
183 static_assert(SkRegion::kReverseDifference_Op == static_cast<SkRegion::Op>(SkClipOp::kReverseDifference_deprecated), "");
184 static_assert(SkRegion::kReplace_Op == static_cast<SkRegion::Op>(SkClipOp::kReplace_deprecated), "");
185 
opHandleToClipOp(jint opHandle)186 static SkClipOp opHandleToClipOp(jint opHandle) {
187     // The opHandle is defined in Canvas.java to be Region::Op
188     SkRegion::Op rgnOp = static_cast<SkRegion::Op>(opHandle);
189 
190     // In the future, when we no longer support the wide range of ops (e.g. Union, Xor)
191     // this function can perform a range check and throw an unsupported-exception.
192     // e.g. if (rgnOp != kIntersect && rgnOp != kDifference) throw...
193 
194     // Skia now takes a different type, SkClipOp, as the parameter to clipping calls
195     // This type is binary compatible with SkRegion::Op, so a static_cast<> is safe.
196     return static_cast<SkClipOp>(rgnOp);
197 }
198 
clipRect(jlong canvasHandle,jfloat l,jfloat t,jfloat r,jfloat b,jint opHandle)199 static jboolean clipRect(jlong canvasHandle, jfloat l, jfloat t,
200                          jfloat r, jfloat b, jint opHandle) {
201     bool nonEmptyClip = get_canvas(canvasHandle)->clipRect(l, t, r, b,
202             opHandleToClipOp(opHandle));
203     return nonEmptyClip ? JNI_TRUE : JNI_FALSE;
204 }
205 
clipPath(jlong canvasHandle,jlong pathHandle,jint opHandle)206 static jboolean clipPath(jlong canvasHandle, jlong pathHandle,
207                          jint opHandle) {
208     SkPath* path = reinterpret_cast<SkPath*>(pathHandle);
209     bool nonEmptyClip = get_canvas(canvasHandle)->clipPath(path, opHandleToClipOp(opHandle));
210     return nonEmptyClip ? JNI_TRUE : JNI_FALSE;
211 }
212 
drawColor(JNIEnv * env,jobject,jlong canvasHandle,jint color,jint modeHandle)213 static void drawColor(JNIEnv* env, jobject, jlong canvasHandle, jint color, jint modeHandle) {
214     SkBlendMode mode = static_cast<SkBlendMode>(modeHandle);
215     get_canvas(canvasHandle)->drawColor(color, mode);
216 }
217 
drawPaint(JNIEnv * env,jobject,jlong canvasHandle,jlong paintHandle)218 static void drawPaint(JNIEnv* env, jobject, jlong canvasHandle, jlong paintHandle) {
219     Paint* paint = reinterpret_cast<Paint*>(paintHandle);
220     get_canvas(canvasHandle)->drawPaint(*paint);
221 }
222 
drawPoint(JNIEnv *,jobject,jlong canvasHandle,jfloat x,jfloat y,jlong paintHandle)223 static void drawPoint(JNIEnv*, jobject, jlong canvasHandle, jfloat x, jfloat y,
224                       jlong paintHandle) {
225     const Paint* paint = reinterpret_cast<Paint*>(paintHandle);
226     get_canvas(canvasHandle)->drawPoint(x, y, *paint);
227 }
228 
drawPoints(JNIEnv * env,jobject,jlong canvasHandle,jfloatArray jptsArray,jint offset,jint count,jlong paintHandle)229 static void drawPoints(JNIEnv* env, jobject, jlong canvasHandle, jfloatArray jptsArray,
230                        jint offset, jint count, jlong paintHandle) {
231     NPE_CHECK_RETURN_VOID(env, jptsArray);
232     AutoJavaFloatArray autoPts(env, jptsArray);
233     float* floats = autoPts.ptr();
234     const int length = autoPts.length();
235 
236     if ((offset | count) < 0 || offset + count > length) {
237         doThrowAIOOBE(env);
238         return;
239     }
240 
241     const Paint* paint = reinterpret_cast<Paint*>(paintHandle);
242     get_canvas(canvasHandle)->drawPoints(floats + offset, count, *paint);
243 }
244 
drawLine(JNIEnv * env,jobject,jlong canvasHandle,jfloat startX,jfloat startY,jfloat stopX,jfloat stopY,jlong paintHandle)245 static void drawLine(JNIEnv* env, jobject, jlong canvasHandle, jfloat startX, jfloat startY,
246                      jfloat stopX, jfloat stopY, jlong paintHandle) {
247     Paint* paint = reinterpret_cast<Paint*>(paintHandle);
248     get_canvas(canvasHandle)->drawLine(startX, startY, stopX, stopY, *paint);
249 }
250 
drawLines(JNIEnv * env,jobject,jlong canvasHandle,jfloatArray jptsArray,jint offset,jint count,jlong paintHandle)251 static void drawLines(JNIEnv* env, jobject, jlong canvasHandle, jfloatArray jptsArray,
252                       jint offset, jint count, jlong paintHandle) {
253     NPE_CHECK_RETURN_VOID(env, jptsArray);
254     AutoJavaFloatArray autoPts(env, jptsArray);
255     float* floats = autoPts.ptr();
256     const int length = autoPts.length();
257 
258     if ((offset | count) < 0 || offset + count > length) {
259         doThrowAIOOBE(env);
260         return;
261     }
262 
263     const Paint* paint = reinterpret_cast<Paint*>(paintHandle);
264     get_canvas(canvasHandle)->drawLines(floats + offset, count, *paint);
265 }
266 
drawRect(JNIEnv * env,jobject,jlong canvasHandle,jfloat left,jfloat top,jfloat right,jfloat bottom,jlong paintHandle)267 static void drawRect(JNIEnv* env, jobject, jlong canvasHandle, jfloat left, jfloat top,
268                      jfloat right, jfloat bottom, jlong paintHandle) {
269     const Paint* paint = reinterpret_cast<Paint*>(paintHandle);
270     get_canvas(canvasHandle)->drawRect(left, top, right, bottom, *paint);
271 }
272 
drawRegion(JNIEnv * env,jobject,jlong canvasHandle,jlong regionHandle,jlong paintHandle)273 static void drawRegion(JNIEnv* env, jobject, jlong canvasHandle, jlong regionHandle,
274                        jlong paintHandle) {
275     const SkRegion* region = reinterpret_cast<SkRegion*>(regionHandle);
276     const Paint* paint = reinterpret_cast<Paint*>(paintHandle);
277     get_canvas(canvasHandle)->drawRegion(*region, *paint);
278 }
279 
drawRoundRect(JNIEnv * env,jobject,jlong canvasHandle,jfloat left,jfloat top,jfloat right,jfloat bottom,jfloat rx,jfloat ry,jlong paintHandle)280 static void drawRoundRect(JNIEnv* env, jobject, jlong canvasHandle, jfloat left, jfloat top,
281                           jfloat right, jfloat bottom, jfloat rx, jfloat ry, jlong paintHandle) {
282     const Paint* paint = reinterpret_cast<Paint*>(paintHandle);
283     get_canvas(canvasHandle)->drawRoundRect(left, top, right, bottom, rx, ry, *paint);
284 }
285 
drawCircle(JNIEnv * env,jobject,jlong canvasHandle,jfloat cx,jfloat cy,jfloat radius,jlong paintHandle)286 static void drawCircle(JNIEnv* env, jobject, jlong canvasHandle, jfloat cx, jfloat cy,
287                        jfloat radius, jlong paintHandle) {
288     const Paint* paint = reinterpret_cast<Paint*>(paintHandle);
289     get_canvas(canvasHandle)->drawCircle(cx, cy, radius, *paint);
290 }
291 
drawOval(JNIEnv * env,jobject,jlong canvasHandle,jfloat left,jfloat top,jfloat right,jfloat bottom,jlong paintHandle)292 static void drawOval(JNIEnv* env, jobject, jlong canvasHandle, jfloat left, jfloat top,
293                      jfloat right, jfloat bottom, jlong paintHandle) {
294     const Paint* paint = reinterpret_cast<Paint*>(paintHandle);
295     get_canvas(canvasHandle)->drawOval(left, top, right, bottom, *paint);
296 }
297 
drawArc(JNIEnv * env,jobject,jlong canvasHandle,jfloat left,jfloat top,jfloat right,jfloat bottom,jfloat startAngle,jfloat sweepAngle,jboolean useCenter,jlong paintHandle)298 static void drawArc(JNIEnv* env, jobject, jlong canvasHandle, jfloat left, jfloat top,
299                     jfloat right, jfloat bottom, jfloat startAngle, jfloat sweepAngle,
300                     jboolean useCenter, jlong paintHandle) {
301     const Paint* paint = reinterpret_cast<Paint*>(paintHandle);
302     get_canvas(canvasHandle)->drawArc(left, top, right, bottom, startAngle, sweepAngle,
303                                        useCenter, *paint);
304 }
305 
drawPath(JNIEnv * env,jobject,jlong canvasHandle,jlong pathHandle,jlong paintHandle)306 static void drawPath(JNIEnv* env, jobject, jlong canvasHandle, jlong pathHandle,
307                      jlong paintHandle) {
308     const SkPath* path = reinterpret_cast<SkPath*>(pathHandle);
309     const Paint* paint = reinterpret_cast<Paint*>(paintHandle);
310     get_canvas(canvasHandle)->drawPath(*path, *paint);
311 }
312 
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)313 static void drawVertices(JNIEnv* env, jobject, jlong canvasHandle,
314                          jint modeHandle, jint vertexCount,
315                          jfloatArray jverts, jint vertIndex,
316                          jfloatArray jtexs, jint texIndex,
317                          jintArray jcolors, jint colorIndex,
318                          jshortArray jindices, jint indexIndex,
319                          jint indexCount, jlong paintHandle) {
320     AutoJavaFloatArray  vertA(env, jverts, vertIndex + vertexCount);
321     AutoJavaFloatArray  texA(env, jtexs, texIndex + vertexCount);
322     AutoJavaIntArray    colorA(env, jcolors, colorIndex + vertexCount);
323     AutoJavaShortArray  indexA(env, jindices, indexIndex + indexCount);
324 
325     const float* verts = vertA.ptr() + vertIndex;
326     const float* texs = texA.ptr() + vertIndex;
327     const int* colors = NULL;
328     const uint16_t* indices = NULL;
329 
330     if (jcolors != NULL) {
331         colors = colorA.ptr() + colorIndex;
332     }
333     if (jindices != NULL) {
334         indices = (const uint16_t*)(indexA.ptr() + indexIndex);
335     }
336 
337     SkCanvas::VertexMode mode = static_cast<SkCanvas::VertexMode>(modeHandle);
338     const Paint* paint = reinterpret_cast<Paint*>(paintHandle);
339     get_canvas(canvasHandle)->drawVertices(mode, vertexCount, verts, texs, colors,
340                                            indices, indexCount, *paint);
341 }
342 
drawNinePatch(JNIEnv * env,jobject,jlong canvasHandle,jlong bitmapHandle,jlong chunkHandle,jfloat left,jfloat top,jfloat right,jfloat bottom,jlong paintHandle,jint dstDensity,jint srcDensity)343 static void drawNinePatch(JNIEnv* env, jobject, jlong canvasHandle, jlong bitmapHandle,
344         jlong chunkHandle, jfloat left, jfloat top, jfloat right, jfloat bottom,
345         jlong paintHandle, jint dstDensity, jint srcDensity) {
346 
347     Canvas* canvas = get_canvas(canvasHandle);
348     Bitmap& bitmap = android::bitmap::toBitmap(env, bitmapHandle);
349     const android::Res_png_9patch* chunk = reinterpret_cast<android::Res_png_9patch*>(chunkHandle);
350     const Paint* paint = reinterpret_cast<Paint*>(paintHandle);
351 
352     if (CC_LIKELY(dstDensity == srcDensity || dstDensity == 0 || srcDensity == 0)) {
353         canvas->drawNinePatch(bitmap, *chunk, left, top, right, bottom, paint);
354     } else {
355         canvas->save(SaveFlags::MatrixClip);
356 
357         SkScalar scale = dstDensity / (float)srcDensity;
358         canvas->translate(left, top);
359         canvas->scale(scale, scale);
360 
361         Paint filteredPaint;
362         if (paint) {
363             filteredPaint = *paint;
364         }
365         filteredPaint.setFilterQuality(kLow_SkFilterQuality);
366 
367         canvas->drawNinePatch(bitmap, *chunk, 0, 0, (right-left)/scale, (bottom-top)/scale,
368                 &filteredPaint);
369 
370         canvas->restore();
371     }
372 }
373 
drawBitmap(JNIEnv * env,jobject,jlong canvasHandle,jobject jbitmap,jfloat left,jfloat top,jlong paintHandle,jint canvasDensity,jint screenDensity,jint bitmapDensity)374 static void drawBitmap(JNIEnv* env, jobject, jlong canvasHandle, jobject jbitmap,
375                        jfloat left, jfloat top, jlong paintHandle, jint canvasDensity,
376                        jint screenDensity, jint bitmapDensity) {
377     Canvas* canvas = get_canvas(canvasHandle);
378     Bitmap& bitmap = android::bitmap::toBitmap(env, jbitmap);
379     const Paint* paint = reinterpret_cast<Paint*>(paintHandle);
380 
381     if (canvasDensity == bitmapDensity || canvasDensity == 0 || bitmapDensity == 0) {
382         if (screenDensity != 0 && screenDensity != bitmapDensity) {
383             Paint filteredPaint;
384             if (paint) {
385                 filteredPaint = *paint;
386             }
387             filteredPaint.setFilterQuality(kLow_SkFilterQuality);
388             canvas->drawBitmap(bitmap, left, top, &filteredPaint);
389         } else {
390             canvas->drawBitmap(bitmap, left, top, paint);
391         }
392     } else {
393         canvas->save(SaveFlags::MatrixClip);
394         SkScalar scale = canvasDensity / (float)bitmapDensity;
395         canvas->translate(left, top);
396         canvas->scale(scale, scale);
397 
398         Paint filteredPaint;
399         if (paint) {
400             filteredPaint = *paint;
401         }
402         filteredPaint.setFilterQuality(kLow_SkFilterQuality);
403 
404         canvas->drawBitmap(bitmap, 0, 0, &filteredPaint);
405         canvas->restore();
406     }
407 }
408 
drawBitmapMatrix(JNIEnv * env,jobject,jlong canvasHandle,jobject jbitmap,jlong matrixHandle,jlong paintHandle)409 static void drawBitmapMatrix(JNIEnv* env, jobject, jlong canvasHandle, jobject jbitmap,
410                              jlong matrixHandle, jlong paintHandle) {
411     const SkMatrix* matrix = reinterpret_cast<SkMatrix*>(matrixHandle);
412     const Paint* paint = reinterpret_cast<Paint*>(paintHandle);
413     Bitmap& bitmap = android::bitmap::toBitmap(env, jbitmap);
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     Bitmap& bitmap = android::bitmap::toBitmap(env, jbitmap);
425     if (screenDensity != 0 && screenDensity != bitmapDensity) {
426         Paint filteredPaint;
427         if (paint) {
428             filteredPaint = *paint;
429         }
430         filteredPaint.setFilterQuality(kLow_SkFilterQuality);
431         canvas->drawBitmap(bitmap, srcLeft, srcTop, srcRight, srcBottom,
432                            dstLeft, dstTop, dstRight, dstBottom, &filteredPaint);
433     } else {
434         canvas->drawBitmap(bitmap, srcLeft, srcTop, srcRight, srcBottom,
435                            dstLeft, dstTop, dstRight, dstBottom, paint);
436     }
437 }
438 
drawBitmapArray(JNIEnv * env,jobject,jlong canvasHandle,jintArray jcolors,jint offset,jint stride,jfloat x,jfloat y,jint width,jint height,jboolean hasAlpha,jlong paintHandle)439 static void drawBitmapArray(JNIEnv* env, jobject, jlong canvasHandle,
440                             jintArray jcolors, jint offset, jint stride,
441                             jfloat x, jfloat y, jint width, jint height,
442                             jboolean hasAlpha, jlong paintHandle) {
443     // Note: If hasAlpha is false, kRGB_565_SkColorType will be used, which will
444     // correct the alphaType to kOpaque_SkAlphaType.
445     SkImageInfo info = SkImageInfo::MakeN32(width, height, kPremul_SkAlphaType,
446             GraphicsJNI::defaultColorSpace());
447     SkBitmap bitmap;
448     bitmap.setInfo(info);
449     sk_sp<Bitmap> androidBitmap = Bitmap::allocateHeapBitmap(&bitmap, NULL);
450     if (!androidBitmap) {
451         return;
452     }
453 
454     if (!GraphicsJNI::SetPixels(env, jcolors, offset, stride, 0, 0, width, height, bitmap)) {
455         return;
456     }
457 
458     const Paint* paint = reinterpret_cast<Paint*>(paintHandle);
459     get_canvas(canvasHandle)->drawBitmap(*androidBitmap, x, y, paint);
460 }
461 
drawBitmapMesh(JNIEnv * env,jobject,jlong canvasHandle,jobject jbitmap,jint meshWidth,jint meshHeight,jfloatArray jverts,jint vertIndex,jintArray jcolors,jint colorIndex,jlong paintHandle)462 static void drawBitmapMesh(JNIEnv* env, jobject, jlong canvasHandle, jobject jbitmap,
463                            jint meshWidth, jint meshHeight, jfloatArray jverts,
464                            jint vertIndex, jintArray jcolors, jint colorIndex, jlong paintHandle) {
465     const int ptCount = (meshWidth + 1) * (meshHeight + 1);
466     AutoJavaFloatArray vertA(env, jverts, vertIndex + (ptCount << 1));
467     AutoJavaIntArray colorA(env, jcolors, colorIndex + ptCount);
468 
469     const Paint* paint = reinterpret_cast<Paint*>(paintHandle);
470     Bitmap& bitmap = android::bitmap::toBitmap(env, jbitmap);
471     get_canvas(canvasHandle)->drawBitmapMesh(bitmap, meshWidth, meshHeight,
472                                              vertA.ptr(), colorA.ptr(), paint);
473 }
474 
drawTextChars(JNIEnv * env,jobject,jlong canvasHandle,jcharArray text,jint index,jint count,jfloat x,jfloat y,jint bidiFlags,jlong paintHandle,jlong typefaceHandle)475 static void drawTextChars(JNIEnv* env, jobject, jlong canvasHandle, jcharArray text,
476                           jint index, jint count, jfloat x, jfloat y, jint bidiFlags,
477                           jlong paintHandle, jlong typefaceHandle) {
478     Paint* paint = reinterpret_cast<Paint*>(paintHandle);
479     Typeface* typeface = reinterpret_cast<Typeface*>(typefaceHandle);
480     jchar* jchars = env->GetCharArrayElements(text, NULL);
481     get_canvas(canvasHandle)->drawText(jchars + index, 0, count, count, x, y,
482                                        bidiFlags, *paint, typeface);
483     env->ReleaseCharArrayElements(text, jchars, JNI_ABORT);
484 }
485 
drawTextString(JNIEnv * env,jobject,jlong canvasHandle,jstring text,jint start,jint end,jfloat x,jfloat y,jint bidiFlags,jlong paintHandle,jlong typefaceHandle)486 static void drawTextString(JNIEnv* env, jobject, jlong canvasHandle, jstring text,
487                            jint start, jint end, jfloat x, jfloat y, jint bidiFlags,
488                            jlong paintHandle, jlong typefaceHandle) {
489     Paint* paint = reinterpret_cast<Paint*>(paintHandle);
490     Typeface* typeface = reinterpret_cast<Typeface*>(typefaceHandle);
491     const int count = end - start;
492     const jchar* jchars = env->GetStringChars(text, NULL);
493     get_canvas(canvasHandle)->drawText(jchars + start, 0, count, count, x, y,
494                                        bidiFlags, *paint, typeface);
495     env->ReleaseStringChars(text, jchars);
496 }
497 
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)498 static void drawTextRunChars(JNIEnv* env, jobject, jlong canvasHandle, jcharArray text, jint index,
499                              jint count, jint contextIndex, jint contextCount, jfloat x, jfloat y,
500                              jboolean isRtl, jlong paintHandle, jlong typefaceHandle) {
501     Paint* paint = reinterpret_cast<Paint*>(paintHandle);
502     Typeface* typeface = reinterpret_cast<Typeface*>(typefaceHandle);
503 
504     const int bidiFlags = isRtl ? minikin::kBidi_Force_RTL : minikin::kBidi_Force_LTR;
505     jchar* jchars = env->GetCharArrayElements(text, NULL);
506     get_canvas(canvasHandle)->drawText(jchars + contextIndex, index - contextIndex, count,
507                                        contextCount, x, y, bidiFlags, *paint, typeface);
508     env->ReleaseCharArrayElements(text, jchars, JNI_ABORT);
509 }
510 
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)511 static void drawTextRunString(JNIEnv* env, jobject obj, jlong canvasHandle, jstring text,
512                               jint start, jint end, jint contextStart, jint contextEnd,
513                               jfloat x, jfloat y, jboolean isRtl, jlong paintHandle,
514                               jlong typefaceHandle) {
515     Paint* paint = reinterpret_cast<Paint*>(paintHandle);
516     Typeface* typeface = reinterpret_cast<Typeface*>(typefaceHandle);
517 
518     int bidiFlags = isRtl ? minikin::kBidi_Force_RTL : minikin::kBidi_Force_LTR;
519     jint count = end - start;
520     jint contextCount = contextEnd - contextStart;
521     const jchar* jchars = env->GetStringChars(text, NULL);
522     get_canvas(canvasHandle)->drawText(jchars + contextStart, start - contextStart, count,
523                                        contextCount, x, y, bidiFlags, *paint, typeface);
524     env->ReleaseStringChars(text, jchars);
525 }
526 
drawTextOnPathChars(JNIEnv * env,jobject,jlong canvasHandle,jcharArray text,jint index,jint count,jlong pathHandle,jfloat hOffset,jfloat vOffset,jint bidiFlags,jlong paintHandle,jlong typefaceHandle)527 static void drawTextOnPathChars(JNIEnv* env, jobject, jlong canvasHandle, jcharArray text,
528                                 jint index, jint count, jlong pathHandle, jfloat hOffset,
529                                 jfloat vOffset, jint bidiFlags, jlong paintHandle,
530                                 jlong typefaceHandle) {
531     SkPath* path = reinterpret_cast<SkPath*>(pathHandle);
532     Paint* paint = reinterpret_cast<Paint*>(paintHandle);
533     Typeface* typeface = reinterpret_cast<Typeface*>(typefaceHandle);
534 
535     jchar* jchars = env->GetCharArrayElements(text, NULL);
536 
537     get_canvas(canvasHandle)->drawTextOnPath(jchars + index, count, bidiFlags, *path,
538                    hOffset, vOffset, *paint, typeface);
539 
540     env->ReleaseCharArrayElements(text, jchars, 0);
541 }
542 
drawTextOnPathString(JNIEnv * env,jobject,jlong canvasHandle,jstring text,jlong pathHandle,jfloat hOffset,jfloat vOffset,jint bidiFlags,jlong paintHandle,jlong typefaceHandle)543 static void drawTextOnPathString(JNIEnv* env, jobject, jlong canvasHandle, jstring text,
544                                  jlong pathHandle, jfloat hOffset, jfloat vOffset,
545                                  jint bidiFlags, jlong paintHandle, jlong typefaceHandle) {
546     SkPath* path = reinterpret_cast<SkPath*>(pathHandle);
547     Paint* paint = reinterpret_cast<Paint*>(paintHandle);
548     Typeface* typeface = reinterpret_cast<Typeface*>(typefaceHandle);
549 
550     const jchar* jchars = env->GetStringChars(text, NULL);
551     int count = env->GetStringLength(text);
552 
553     get_canvas(canvasHandle)->drawTextOnPath(jchars, count, bidiFlags, *path,
554                    hOffset, vOffset, *paint, typeface);
555 
556     env->ReleaseStringChars(text, jchars);
557 }
558 
setDrawFilter(jlong canvasHandle,jlong filterHandle)559 static void setDrawFilter(jlong canvasHandle, jlong filterHandle) {
560     get_canvas(canvasHandle)->setDrawFilter(reinterpret_cast<SkDrawFilter*>(filterHandle));
561 }
562 
freeCaches(JNIEnv * env,jobject)563 static void freeCaches(JNIEnv* env, jobject) {
564     SkGraphics::PurgeFontCache();
565 }
566 
freeTextLayoutCaches(JNIEnv * env,jobject)567 static void freeTextLayoutCaches(JNIEnv* env, jobject) {
568     minikin::Layout::purgeCaches();
569 }
570 
571 }; // namespace CanvasJNI
572 
573 static const JNINativeMethod gMethods[] = {
574     {"nGetNativeFinalizer", "()J", (void*) CanvasJNI::getNativeFinalizer},
575     {"nInitRaster", "(Landroid/graphics/Bitmap;)J", (void*) CanvasJNI::initRaster},
576     {"nFreeCaches", "()V", (void*) CanvasJNI::freeCaches},
577     {"nFreeTextLayoutCaches", "()V", (void*) CanvasJNI::freeTextLayoutCaches},
578 
579     // ------------ @FastNative ----------------
580     {"nSetBitmap", "(JLandroid/graphics/Bitmap;)V", (void*) CanvasJNI::setBitmap},
581     {"nGetClipBounds","(JLandroid/graphics/Rect;)Z", (void*) CanvasJNI::getClipBounds},
582 
583     // ------------ @CriticalNative ----------------
584     {"nIsOpaque","(J)Z", (void*) CanvasJNI::isOpaque},
585     {"nGetWidth","(J)I", (void*) CanvasJNI::getWidth},
586     {"nGetHeight","(J)I", (void*) CanvasJNI::getHeight},
587     {"nSetHighContrastText","(JZ)V", (void*) CanvasJNI::setHighContrastText},
588     {"nSave","(JI)I", (void*) CanvasJNI::save},
589     {"nSaveLayer","(JFFFFJI)I", (void*) CanvasJNI::saveLayer},
590     {"nSaveLayerAlpha","(JFFFFII)I", (void*) CanvasJNI::saveLayerAlpha},
591     {"nGetSaveCount","(J)I", (void*) CanvasJNI::getSaveCount},
592     {"nRestore","(J)Z", (void*) CanvasJNI::restore},
593     {"nRestoreToCount","(JI)V", (void*) CanvasJNI::restoreToCount},
594     {"nGetMatrix", "(JJ)V", (void*)CanvasJNI::getMatrix},
595     {"nSetMatrix","(JJ)V", (void*) CanvasJNI::setMatrix},
596     {"nConcat","(JJ)V", (void*) CanvasJNI::concat},
597     {"nRotate","(JF)V", (void*) CanvasJNI::rotate},
598     {"nScale","(JFF)V", (void*) CanvasJNI::scale},
599     {"nSkew","(JFF)V", (void*) CanvasJNI::skew},
600     {"nTranslate","(JFF)V", (void*) CanvasJNI::translate},
601     {"nQuickReject","(JJ)Z", (void*) CanvasJNI::quickRejectPath},
602     {"nQuickReject","(JFFFF)Z", (void*)CanvasJNI::quickRejectRect},
603     {"nClipRect","(JFFFFI)Z", (void*) CanvasJNI::clipRect},
604     {"nClipPath","(JJI)Z", (void*) CanvasJNI::clipPath},
605     {"nSetDrawFilter", "(JJ)V", (void*) CanvasJNI::setDrawFilter},
606 };
607 
608 // If called from Canvas these are regular JNI
609 // If called from DisplayListCanvas they are @FastNative
610 static const JNINativeMethod gDrawMethods[] = {
611     {"nDrawColor","(JII)V", (void*) CanvasJNI::drawColor},
612     {"nDrawPaint","(JJ)V", (void*) CanvasJNI::drawPaint},
613     {"nDrawPoint", "(JFFJ)V", (void*) CanvasJNI::drawPoint},
614     {"nDrawPoints", "(J[FIIJ)V", (void*) CanvasJNI::drawPoints},
615     {"nDrawLine", "(JFFFFJ)V", (void*) CanvasJNI::drawLine},
616     {"nDrawLines", "(J[FIIJ)V", (void*) CanvasJNI::drawLines},
617     {"nDrawRect","(JFFFFJ)V", (void*) CanvasJNI::drawRect},
618     {"nDrawRegion", "(JJJ)V", (void*) CanvasJNI::drawRegion },
619     {"nDrawRoundRect","(JFFFFFFJ)V", (void*) CanvasJNI::drawRoundRect},
620     {"nDrawCircle","(JFFFJ)V", (void*) CanvasJNI::drawCircle},
621     {"nDrawOval","(JFFFFJ)V", (void*) CanvasJNI::drawOval},
622     {"nDrawArc","(JFFFFFFZJ)V", (void*) CanvasJNI::drawArc},
623     {"nDrawPath","(JJJ)V", (void*) CanvasJNI::drawPath},
624     {"nDrawVertices", "(JII[FI[FI[II[SIIJ)V", (void*)CanvasJNI::drawVertices},
625     {"nDrawNinePatch", "(JJJFFFFJII)V", (void*)CanvasJNI::drawNinePatch},
626     {"nDrawBitmapMatrix", "(JLandroid/graphics/Bitmap;JJ)V", (void*)CanvasJNI::drawBitmapMatrix},
627     {"nDrawBitmapMesh", "(JLandroid/graphics/Bitmap;II[FI[IIJ)V", (void*)CanvasJNI::drawBitmapMesh},
628     {"nDrawBitmap","(JLandroid/graphics/Bitmap;FFJIII)V", (void*) CanvasJNI::drawBitmap},
629     {"nDrawBitmap","(JLandroid/graphics/Bitmap;FFFFFFFFJII)V", (void*) CanvasJNI::drawBitmapRect},
630     {"nDrawBitmap", "(J[IIIFFIIZJ)V", (void*)CanvasJNI::drawBitmapArray},
631     {"nDrawText","(J[CIIFFIJJ)V", (void*) CanvasJNI::drawTextChars},
632     {"nDrawText","(JLjava/lang/String;IIFFIJJ)V", (void*) CanvasJNI::drawTextString},
633     {"nDrawTextRun","(J[CIIIIFFZJJ)V", (void*) CanvasJNI::drawTextRunChars},
634     {"nDrawTextRun","(JLjava/lang/String;IIIIFFZJJ)V", (void*) CanvasJNI::drawTextRunString},
635     {"nDrawTextOnPath","(J[CIIJFFIJJ)V", (void*) CanvasJNI::drawTextOnPathChars},
636     {"nDrawTextOnPath","(JLjava/lang/String;JFFIJJ)V", (void*) CanvasJNI::drawTextOnPathString},
637 };
638 
register_android_graphics_Canvas(JNIEnv * env)639 int register_android_graphics_Canvas(JNIEnv* env) {
640     int ret = 0;
641     ret |= RegisterMethodsOrDie(env, "android/graphics/Canvas", gMethods, NELEM(gMethods));
642     ret |= RegisterMethodsOrDie(env, "android/graphics/BaseCanvas", gDrawMethods, NELEM(gDrawMethods));
643     ret |= RegisterMethodsOrDie(env, "android/view/RecordingCanvas", gDrawMethods, NELEM(gDrawMethods));
644     return ret;
645 
646 }
647 
648 }; // namespace android
649