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