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 <android_runtime/AndroidRuntime.h>
20 
21 #include "Canvas.h"
22 #include "SkDrawFilter.h"
23 #include "SkGraphics.h"
24 #include "SkPorterDuff.h"
25 #include "Paint.h"
26 #include "TypefaceImpl.h"
27 
28 #include "MinikinUtils.h"
29 
30 namespace android {
31 
32 namespace CanvasJNI {
33 
get_canvas(jlong canvasHandle)34 static Canvas* get_canvas(jlong canvasHandle) {
35     return reinterpret_cast<Canvas*>(canvasHandle);
36 }
37 
finalizer(JNIEnv * env,jobject clazz,jlong canvasHandle)38 static void finalizer(JNIEnv* env, jobject clazz, jlong canvasHandle) {
39     delete get_canvas(canvasHandle);
40 }
41 
42 // Native wrapper constructor used by Canvas(Bitmap)
initRaster(JNIEnv * env,jobject,jlong bitmapHandle)43 static jlong initRaster(JNIEnv* env, jobject, jlong bitmapHandle) {
44     SkBitmap* bitmap = reinterpret_cast<SkBitmap*>(bitmapHandle);
45     return reinterpret_cast<jlong>(Canvas::create_canvas(bitmap));
46 }
47 
48 // Set the given bitmap as the new draw target (wrapped in a new SkCanvas),
49 // optionally copying canvas matrix & clip state.
setBitmap(JNIEnv * env,jobject,jlong canvasHandle,jlong bitmapHandle,jboolean copyState)50 static void setBitmap(JNIEnv* env, jobject, jlong canvasHandle, jlong bitmapHandle,
51                       jboolean copyState) {
52     SkBitmap* bitmap = reinterpret_cast<SkBitmap*>(bitmapHandle);
53     get_canvas(canvasHandle)->setBitmap(bitmap, copyState);
54 }
55 
isOpaque(JNIEnv *,jobject,jlong canvasHandle)56 static jboolean isOpaque(JNIEnv*, jobject, jlong canvasHandle) {
57     return get_canvas(canvasHandle)->isOpaque() ? JNI_TRUE : JNI_FALSE;
58 }
59 
getWidth(JNIEnv *,jobject,jlong canvasHandle)60 static jint getWidth(JNIEnv*, jobject, jlong canvasHandle) {
61     return static_cast<jint>(get_canvas(canvasHandle)->width());
62 }
63 
getHeight(JNIEnv *,jobject,jlong canvasHandle)64 static jint getHeight(JNIEnv*, jobject, jlong canvasHandle) {
65     return static_cast<jint>(get_canvas(canvasHandle)->height());
66 }
67 
getSaveCount(JNIEnv *,jobject,jlong canvasHandle)68 static jint getSaveCount(JNIEnv*, jobject, jlong canvasHandle) {
69     return static_cast<jint>(get_canvas(canvasHandle)->getSaveCount());
70 }
71 
save(JNIEnv *,jobject,jlong canvasHandle,jint flagsHandle)72 static jint save(JNIEnv*, jobject, jlong canvasHandle, jint flagsHandle) {
73     SkCanvas::SaveFlags flags = static_cast<SkCanvas::SaveFlags>(flagsHandle);
74     return static_cast<jint>(get_canvas(canvasHandle)->save(flags));
75 }
76 
saveLayer(JNIEnv * env,jobject,jlong canvasHandle,jfloat l,jfloat t,jfloat r,jfloat b,jlong paintHandle,jint flagsHandle)77 static jint saveLayer(JNIEnv* env, jobject, jlong canvasHandle, jfloat l, jfloat t,
78                       jfloat r, jfloat b, jlong paintHandle, jint flagsHandle) {
79     Paint* paint  = reinterpret_cast<Paint*>(paintHandle);
80     SkCanvas::SaveFlags flags = static_cast<SkCanvas::SaveFlags>(flagsHandle);
81     return static_cast<jint>(get_canvas(canvasHandle)->saveLayer(l, t, r, b, paint, flags));
82 }
83 
saveLayerAlpha(JNIEnv * env,jobject,jlong canvasHandle,jfloat l,jfloat t,jfloat r,jfloat b,jint alpha,jint flagsHandle)84 static jint saveLayerAlpha(JNIEnv* env, jobject, jlong canvasHandle, jfloat l, jfloat t,
85                            jfloat r, jfloat b, jint alpha, jint flagsHandle) {
86     SkCanvas::SaveFlags flags = static_cast<SkCanvas::SaveFlags>(flagsHandle);
87     return static_cast<jint>(get_canvas(canvasHandle)->saveLayerAlpha(l, t, r, b, alpha, flags));
88 }
89 
restore(JNIEnv * env,jobject,jlong canvasHandle)90 static void restore(JNIEnv* env, jobject, jlong canvasHandle) {
91     Canvas* canvas = get_canvas(canvasHandle);
92     if (canvas->getSaveCount() <= 1) {  // cannot restore anymore
93         doThrowISE(env, "Underflow in restore");
94         return;
95     }
96     canvas->restore();
97 }
98 
restoreToCount(JNIEnv * env,jobject,jlong canvasHandle,jint restoreCount)99 static void restoreToCount(JNIEnv* env, jobject, jlong canvasHandle, jint restoreCount) {
100     Canvas* canvas = get_canvas(canvasHandle);
101     if (restoreCount < 1 || restoreCount > canvas->getSaveCount()) {
102         doThrowIAE(env, "Underflow in restoreToCount");
103         return;
104     }
105     canvas->restoreToCount(restoreCount);
106 }
107 
getCTM(JNIEnv * env,jobject,jlong canvasHandle,jlong matrixHandle)108 static void getCTM(JNIEnv* env, jobject, jlong canvasHandle, jlong matrixHandle) {
109     SkMatrix* matrix = reinterpret_cast<SkMatrix*>(matrixHandle);
110     get_canvas(canvasHandle)->getMatrix(matrix);
111 }
112 
setMatrix(JNIEnv * env,jobject,jlong canvasHandle,jlong matrixHandle)113 static void setMatrix(JNIEnv* env, jobject, jlong canvasHandle, jlong matrixHandle) {
114     const SkMatrix* matrix = reinterpret_cast<SkMatrix*>(matrixHandle);
115     get_canvas(canvasHandle)->setMatrix(matrix ? *matrix : SkMatrix::I());
116 }
117 
concat(JNIEnv * env,jobject,jlong canvasHandle,jlong matrixHandle)118 static void concat(JNIEnv* env, jobject, jlong canvasHandle, jlong matrixHandle) {
119     const SkMatrix* matrix = reinterpret_cast<SkMatrix*>(matrixHandle);
120     get_canvas(canvasHandle)->concat(*matrix);
121 }
122 
rotate(JNIEnv *,jobject,jlong canvasHandle,jfloat degrees)123 static void rotate(JNIEnv*, jobject, jlong canvasHandle, jfloat degrees) {
124     get_canvas(canvasHandle)->rotate(degrees);
125 }
126 
scale(JNIEnv *,jobject,jlong canvasHandle,jfloat sx,jfloat sy)127 static void scale(JNIEnv*, jobject, jlong canvasHandle, jfloat sx, jfloat sy) {
128     get_canvas(canvasHandle)->scale(sx, sy);
129 }
130 
skew(JNIEnv *,jobject,jlong canvasHandle,jfloat sx,jfloat sy)131 static void skew(JNIEnv*, jobject, jlong canvasHandle, jfloat sx, jfloat sy) {
132     get_canvas(canvasHandle)->skew(sx, sy);
133 }
134 
translate(JNIEnv *,jobject,jlong canvasHandle,jfloat dx,jfloat dy)135 static void translate(JNIEnv*, jobject, jlong canvasHandle, jfloat dx, jfloat dy) {
136     get_canvas(canvasHandle)->translate(dx, dy);
137 }
138 
getClipBounds(JNIEnv * env,jobject,jlong canvasHandle,jobject bounds)139 static jboolean getClipBounds(JNIEnv* env, jobject, jlong canvasHandle, jobject bounds) {
140     SkRect   r;
141     SkIRect ir;
142     bool result = get_canvas(canvasHandle)->getClipBounds(&r);
143 
144     if (!result) {
145         r.setEmpty();
146     }
147     r.round(&ir);
148 
149     (void)GraphicsJNI::irect_to_jrect(ir, env, bounds);
150     return result ? JNI_TRUE : JNI_FALSE;
151 }
152 
quickRejectRect(JNIEnv * env,jobject,jlong canvasHandle,jfloat left,jfloat top,jfloat right,jfloat bottom)153 static jboolean quickRejectRect(JNIEnv* env, jobject, jlong canvasHandle,
154                                 jfloat left, jfloat top, jfloat right, jfloat bottom) {
155     bool result = get_canvas(canvasHandle)->quickRejectRect(left, top, right, bottom);
156     return result ? JNI_TRUE : JNI_FALSE;
157 }
158 
quickRejectPath(JNIEnv * env,jobject,jlong canvasHandle,jlong pathHandle)159 static jboolean quickRejectPath(JNIEnv* env, jobject, jlong canvasHandle, jlong pathHandle) {
160     SkPath* path = reinterpret_cast<SkPath*>(pathHandle);
161     bool result = get_canvas(canvasHandle)->quickRejectPath(*path);
162     return result ? JNI_TRUE : JNI_FALSE;
163 }
164 
clipRect(JNIEnv *,jobject,jlong canvasHandle,jfloat l,jfloat t,jfloat r,jfloat b,jint opHandle)165 static jboolean clipRect(JNIEnv*, jobject, jlong canvasHandle, jfloat l, jfloat t,
166                          jfloat r, jfloat b, jint opHandle) {
167     SkRegion::Op op = static_cast<SkRegion::Op>(opHandle);
168     bool emptyClip = get_canvas(canvasHandle)->clipRect(l, t, r, b, op);
169     return emptyClip ? JNI_FALSE : JNI_TRUE;
170 }
171 
clipPath(JNIEnv * env,jobject,jlong canvasHandle,jlong pathHandle,jint opHandle)172 static jboolean clipPath(JNIEnv* env, jobject, jlong canvasHandle, jlong pathHandle,
173                          jint opHandle) {
174     SkPath* path = reinterpret_cast<SkPath*>(pathHandle);
175     SkRegion::Op op = static_cast<SkRegion::Op>(opHandle);
176     bool emptyClip = get_canvas(canvasHandle)->clipPath(path, op);
177     return emptyClip ? JNI_FALSE : JNI_TRUE;
178 }
179 
clipRegion(JNIEnv * env,jobject,jlong canvasHandle,jlong deviceRgnHandle,jint opHandle)180 static jboolean clipRegion(JNIEnv* env, jobject, jlong canvasHandle, jlong deviceRgnHandle,
181                            jint opHandle) {
182     SkRegion* deviceRgn = reinterpret_cast<SkRegion*>(deviceRgnHandle);
183     SkRegion::Op op = static_cast<SkRegion::Op>(opHandle);
184     bool emptyClip = get_canvas(canvasHandle)->clipRegion(deviceRgn, op);
185     return emptyClip ? JNI_FALSE : JNI_TRUE;
186 }
187 
drawColor(JNIEnv * env,jobject,jlong canvasHandle,jint color,jint modeHandle)188 static void drawColor(JNIEnv* env, jobject, jlong canvasHandle, jint color, jint modeHandle) {
189      SkPorterDuff::Mode mode = static_cast<SkPorterDuff::Mode>(modeHandle);
190      get_canvas(canvasHandle)->drawColor(color, SkPorterDuff::ToXfermodeMode(mode));
191 }
192 
drawPaint(JNIEnv * env,jobject,jlong canvasHandle,jlong paintHandle)193 static void drawPaint(JNIEnv* env, jobject, jlong canvasHandle, jlong paintHandle) {
194     Paint* paint = reinterpret_cast<Paint*>(paintHandle);
195     get_canvas(canvasHandle)->drawPaint(*paint);
196 }
197 
drawPoint(JNIEnv *,jobject,jlong canvasHandle,jfloat x,jfloat y,jlong paintHandle)198 static void drawPoint(JNIEnv*, jobject, jlong canvasHandle, jfloat x, jfloat y,
199                       jlong paintHandle) {
200     const Paint* paint = reinterpret_cast<Paint*>(paintHandle);
201     get_canvas(canvasHandle)->drawPoint(x, y, *paint);
202 }
203 
drawPoints(JNIEnv * env,jobject,jlong canvasHandle,jfloatArray jptsArray,jint offset,jint count,jlong paintHandle)204 static void drawPoints(JNIEnv* env, jobject, jlong canvasHandle, jfloatArray jptsArray,
205                        jint offset, jint count, jlong paintHandle) {
206     NPE_CHECK_RETURN_VOID(env, jptsArray);
207     AutoJavaFloatArray autoPts(env, jptsArray);
208     float* floats = autoPts.ptr();
209     const int length = autoPts.length();
210 
211     if ((offset | count) < 0 || offset + count > length) {
212         doThrowAIOOBE(env);
213         return;
214     }
215 
216     const Paint* paint = reinterpret_cast<Paint*>(paintHandle);
217     get_canvas(canvasHandle)->drawPoints(floats + offset, count, *paint);
218 }
219 
drawLine(JNIEnv * env,jobject,jlong canvasHandle,jfloat startX,jfloat startY,jfloat stopX,jfloat stopY,jlong paintHandle)220 static void drawLine(JNIEnv* env, jobject, jlong canvasHandle, jfloat startX, jfloat startY,
221                      jfloat stopX, jfloat stopY, jlong paintHandle) {
222     Paint* paint = reinterpret_cast<Paint*>(paintHandle);
223     get_canvas(canvasHandle)->drawLine(startX, startY, stopX, stopY, *paint);
224 }
225 
drawLines(JNIEnv * env,jobject,jlong canvasHandle,jfloatArray jptsArray,jint offset,jint count,jlong paintHandle)226 static void drawLines(JNIEnv* env, jobject, jlong canvasHandle, jfloatArray jptsArray,
227                       jint offset, jint count, jlong paintHandle) {
228     NPE_CHECK_RETURN_VOID(env, jptsArray);
229     AutoJavaFloatArray autoPts(env, jptsArray);
230     float* floats = autoPts.ptr();
231     const int length = autoPts.length();
232 
233     if ((offset | count) < 0 || offset + count > length) {
234         doThrowAIOOBE(env);
235         return;
236     }
237 
238     const Paint* paint = reinterpret_cast<Paint*>(paintHandle);
239     get_canvas(canvasHandle)->drawLines(floats + offset, count, *paint);
240 }
241 
drawRect(JNIEnv * env,jobject,jlong canvasHandle,jfloat left,jfloat top,jfloat right,jfloat bottom,jlong paintHandle)242 static void drawRect(JNIEnv* env, jobject, jlong canvasHandle, jfloat left, jfloat top,
243                      jfloat right, jfloat bottom, jlong paintHandle) {
244     const Paint* paint = reinterpret_cast<Paint*>(paintHandle);
245     get_canvas(canvasHandle)->drawRect(left, top, right, bottom, *paint);
246 }
247 
drawRoundRect(JNIEnv * env,jobject,jlong canvasHandle,jfloat left,jfloat top,jfloat right,jfloat bottom,jfloat rx,jfloat ry,jlong paintHandle)248 static void drawRoundRect(JNIEnv* env, jobject, jlong canvasHandle, jfloat left, jfloat top,
249                           jfloat right, jfloat bottom, jfloat rx, jfloat ry, jlong paintHandle) {
250     const Paint* paint = reinterpret_cast<Paint*>(paintHandle);
251     get_canvas(canvasHandle)->drawRoundRect(left, top, right, bottom, rx, ry, *paint);
252 }
253 
drawCircle(JNIEnv * env,jobject,jlong canvasHandle,jfloat cx,jfloat cy,jfloat radius,jlong paintHandle)254 static void drawCircle(JNIEnv* env, jobject, jlong canvasHandle, jfloat cx, jfloat cy,
255                        jfloat radius, jlong paintHandle) {
256     const Paint* paint = reinterpret_cast<Paint*>(paintHandle);
257     get_canvas(canvasHandle)->drawCircle(cx, cy, radius, *paint);
258 }
259 
drawOval(JNIEnv * env,jobject,jlong canvasHandle,jfloat left,jfloat top,jfloat right,jfloat bottom,jlong paintHandle)260 static void drawOval(JNIEnv* env, jobject, jlong canvasHandle, jfloat left, jfloat top,
261                      jfloat right, jfloat bottom, jlong paintHandle) {
262     const Paint* paint = reinterpret_cast<Paint*>(paintHandle);
263     get_canvas(canvasHandle)->drawOval(left, top, right, bottom, *paint);
264 }
265 
drawArc(JNIEnv * env,jobject,jlong canvasHandle,jfloat left,jfloat top,jfloat right,jfloat bottom,jfloat startAngle,jfloat sweepAngle,jboolean useCenter,jlong paintHandle)266 static void drawArc(JNIEnv* env, jobject, jlong canvasHandle, jfloat left, jfloat top,
267                     jfloat right, jfloat bottom, jfloat startAngle, jfloat sweepAngle,
268                     jboolean useCenter, jlong paintHandle) {
269     const Paint* paint = reinterpret_cast<Paint*>(paintHandle);
270     get_canvas(canvasHandle)->drawArc(left, top, right, bottom, startAngle, sweepAngle,
271                                        useCenter, *paint);
272 }
273 
drawPath(JNIEnv * env,jobject,jlong canvasHandle,jlong pathHandle,jlong paintHandle)274 static void drawPath(JNIEnv* env, jobject, jlong canvasHandle, jlong pathHandle,
275                      jlong paintHandle) {
276     const SkPath* path = reinterpret_cast<SkPath*>(pathHandle);
277     const Paint* paint = reinterpret_cast<Paint*>(paintHandle);
278     get_canvas(canvasHandle)->drawPath(*path, *paint);
279 }
280 
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)281 static void drawVertices(JNIEnv* env, jobject, jlong canvasHandle,
282                          jint modeHandle, jint vertexCount,
283                          jfloatArray jverts, jint vertIndex,
284                          jfloatArray jtexs, jint texIndex,
285                          jintArray jcolors, jint colorIndex,
286                          jshortArray jindices, jint indexIndex,
287                          jint indexCount, jlong paintHandle) {
288     AutoJavaFloatArray  vertA(env, jverts, vertIndex + vertexCount);
289     AutoJavaFloatArray  texA(env, jtexs, texIndex + vertexCount);
290     AutoJavaIntArray    colorA(env, jcolors, colorIndex + vertexCount);
291     AutoJavaShortArray  indexA(env, jindices, indexIndex + indexCount);
292 
293     const float* verts = vertA.ptr() + vertIndex;
294     const float* texs = texA.ptr() + vertIndex;
295     const int* colors = NULL;
296     const uint16_t* indices = NULL;
297 
298     if (jcolors != NULL) {
299         colors = colorA.ptr() + colorIndex;
300     }
301     if (jindices != NULL) {
302         indices = (const uint16_t*)(indexA.ptr() + indexIndex);
303     }
304 
305     SkCanvas::VertexMode mode = static_cast<SkCanvas::VertexMode>(modeHandle);
306     const Paint* paint = reinterpret_cast<Paint*>(paintHandle);
307     get_canvas(canvasHandle)->drawVertices(mode, vertexCount, verts, texs, colors,
308                                            indices, indexCount, *paint);
309 }
310 
drawBitmap(JNIEnv * env,jobject jcanvas,jlong canvasHandle,jlong bitmapHandle,jfloat left,jfloat top,jlong paintHandle,jint canvasDensity,jint screenDensity,jint bitmapDensity)311 static void drawBitmap(JNIEnv* env, jobject jcanvas, jlong canvasHandle, jlong bitmapHandle,
312                        jfloat left, jfloat top, jlong paintHandle, jint canvasDensity,
313                        jint screenDensity, jint bitmapDensity) {
314     Canvas* canvas = get_canvas(canvasHandle);
315     const SkBitmap* bitmap = reinterpret_cast<SkBitmap*>(bitmapHandle);
316     const Paint* paint = reinterpret_cast<Paint*>(paintHandle);
317 
318     if (canvasDensity == bitmapDensity || canvasDensity == 0 || bitmapDensity == 0) {
319         if (screenDensity != 0 && screenDensity != bitmapDensity) {
320             Paint filteredPaint;
321             if (paint) {
322                 filteredPaint = *paint;
323             }
324             filteredPaint.setFilterLevel(Paint::kLow_FilterLevel);
325             canvas->drawBitmap(*bitmap, left, top, &filteredPaint);
326         } else {
327             canvas->drawBitmap(*bitmap, left, top, paint);
328         }
329     } else {
330         canvas->save(SkCanvas::kMatrixClip_SaveFlag);
331         SkScalar scale = canvasDensity / (float)bitmapDensity;
332         canvas->translate(left, top);
333         canvas->scale(scale, scale);
334 
335         Paint filteredPaint;
336         if (paint) {
337             filteredPaint = *paint;
338         }
339         filteredPaint.setFilterLevel(Paint::kLow_FilterLevel);
340 
341         canvas->drawBitmap(*bitmap, 0, 0, &filteredPaint);
342         canvas->restore();
343     }
344 }
345 
drawBitmapMatrix(JNIEnv * env,jobject,jlong canvasHandle,jlong bitmapHandle,jlong matrixHandle,jlong paintHandle)346 static void drawBitmapMatrix(JNIEnv* env, jobject, jlong canvasHandle, jlong bitmapHandle,
347                              jlong matrixHandle, jlong paintHandle) {
348     const SkBitmap* bitmap = reinterpret_cast<SkBitmap*>(bitmapHandle);
349     const SkMatrix* matrix = reinterpret_cast<SkMatrix*>(matrixHandle);
350     const Paint* paint = reinterpret_cast<Paint*>(paintHandle);
351     get_canvas(canvasHandle)->drawBitmap(*bitmap, *matrix, paint);
352 }
353 
drawBitmapRect(JNIEnv * env,jobject,jlong canvasHandle,jlong bitmapHandle,float srcLeft,float srcTop,float srcRight,float srcBottom,float dstLeft,float dstTop,float dstRight,float dstBottom,jlong paintHandle,jint screenDensity,jint bitmapDensity)354 static void drawBitmapRect(JNIEnv* env, jobject, jlong canvasHandle, jlong bitmapHandle,
355                            float srcLeft, float srcTop, float srcRight, float srcBottom,
356                            float dstLeft, float dstTop, float dstRight, float dstBottom,
357                            jlong paintHandle, jint screenDensity, jint bitmapDensity) {
358     Canvas* canvas = get_canvas(canvasHandle);
359     const SkBitmap* bitmap = reinterpret_cast<SkBitmap*>(bitmapHandle);
360     const Paint* paint = reinterpret_cast<Paint*>(paintHandle);
361 
362     if (screenDensity != 0 && screenDensity != bitmapDensity) {
363         Paint filteredPaint;
364         if (paint) {
365             filteredPaint = *paint;
366         }
367         filteredPaint.setFilterLevel(Paint::kLow_FilterLevel);
368         canvas->drawBitmap(*bitmap, srcLeft, srcTop, srcRight, srcBottom,
369                            dstLeft, dstTop, dstRight, dstBottom, &filteredPaint);
370     } else {
371         canvas->drawBitmap(*bitmap, srcLeft, srcTop, srcRight, srcBottom,
372                            dstLeft, dstTop, dstRight, dstBottom, paint);
373     }
374 }
375 
drawBitmapArray(JNIEnv * env,jobject,jlong canvasHandle,jintArray jcolors,jint offset,jint stride,jfloat x,jfloat y,jint width,jint height,jboolean hasAlpha,jlong paintHandle)376 static void drawBitmapArray(JNIEnv* env, jobject, jlong canvasHandle,
377                             jintArray jcolors, jint offset, jint stride,
378                             jfloat x, jfloat y, jint width, jint height,
379                             jboolean hasAlpha, jlong paintHandle) {
380     // Note: If hasAlpha is false, kRGB_565_SkColorType will be used, which will
381     // correct the alphaType to kOpaque_SkAlphaType.
382     SkImageInfo info = SkImageInfo::Make(width, height,
383                            hasAlpha ? kN32_SkColorType : kRGB_565_SkColorType,
384                            kPremul_SkAlphaType);
385     SkBitmap bitmap;
386     if (!bitmap.allocPixels(info)) {
387         return;
388     }
389 
390     if (!GraphicsJNI::SetPixels(env, jcolors, offset, stride, 0, 0, width, height, bitmap)) {
391         return;
392     }
393 
394     const Paint* paint = reinterpret_cast<Paint*>(paintHandle);
395     get_canvas(canvasHandle)->drawBitmap(bitmap, x, y, paint);
396 }
397 
drawBitmapMesh(JNIEnv * env,jobject,jlong canvasHandle,jlong bitmapHandle,jint meshWidth,jint meshHeight,jfloatArray jverts,jint vertIndex,jintArray jcolors,jint colorIndex,jlong paintHandle)398 static void drawBitmapMesh(JNIEnv* env, jobject, jlong canvasHandle, jlong bitmapHandle,
399                            jint meshWidth, jint meshHeight, jfloatArray jverts,
400                            jint vertIndex, jintArray jcolors, jint colorIndex, jlong paintHandle) {
401     const int ptCount = (meshWidth + 1) * (meshHeight + 1);
402     AutoJavaFloatArray vertA(env, jverts, vertIndex + (ptCount << 1));
403     AutoJavaIntArray colorA(env, jcolors, colorIndex + ptCount);
404 
405     const SkBitmap* bitmap = reinterpret_cast<SkBitmap*>(bitmapHandle);
406     const Paint* paint = reinterpret_cast<Paint*>(paintHandle);
407     get_canvas(canvasHandle)->drawBitmapMesh(*bitmap, meshWidth, meshHeight,
408                                              vertA.ptr(), colorA.ptr(), paint);
409 }
410 
411 class DrawTextFunctor {
412 public:
DrawTextFunctor(const Layout & layout,Canvas * canvas,uint16_t * glyphs,float * pos,const SkPaint & paint,float x,float y,MinikinRect & bounds)413     DrawTextFunctor(const Layout& layout, Canvas* canvas, uint16_t* glyphs, float* pos,
414                     const SkPaint& paint, float x, float y, MinikinRect& bounds)
415             : layout(layout), canvas(canvas), glyphs(glyphs), pos(pos), paint(paint),
416               x(x), y(y), bounds(bounds) { }
417 
operator ()(size_t start,size_t end)418     void operator()(size_t start, size_t end) {
419         if (canvas->drawTextAbsolutePos()) {
420             for (size_t i = start; i < end; i++) {
421                 glyphs[i] = layout.getGlyphId(i);
422                 pos[2 * i] = x + layout.getX(i);
423                 pos[2 * i + 1] = y + layout.getY(i);
424             }
425         } else {
426             for (size_t i = start; i < end; i++) {
427                 glyphs[i] = layout.getGlyphId(i);
428                 pos[2 * i] = layout.getX(i);
429                 pos[2 * i + 1] = layout.getY(i);
430             }
431         }
432 
433         size_t glyphCount = end - start;
434         canvas->drawText(glyphs + start, pos + (2 * start), glyphCount, paint, x, y,
435                          bounds.mLeft , bounds.mTop , bounds.mRight , bounds.mBottom);
436     }
437 private:
438     const Layout& layout;
439     Canvas* canvas;
440     uint16_t* glyphs;
441     float* pos;
442     const SkPaint& paint;
443     float x;
444     float y;
445     MinikinRect& bounds;
446 };
447 
448 // Same values used by Skia
449 #define kStdStrikeThru_Offset   (-6.0f / 21.0f)
450 #define kStdUnderline_Offset    (1.0f / 9.0f)
451 #define kStdUnderline_Thickness (1.0f / 18.0f)
452 
drawTextDecorations(Canvas * canvas,float x,float y,float length,const SkPaint & paint)453 void drawTextDecorations(Canvas* canvas, float x, float y, float length, const SkPaint& paint) {
454     uint32_t flags;
455     SkDrawFilter* drawFilter = canvas->getDrawFilter();
456     if (drawFilter) {
457         SkPaint paintCopy(paint);
458         drawFilter->filter(&paintCopy, SkDrawFilter::kText_Type);
459         flags = paintCopy.getFlags();
460     } else {
461         flags = paint.getFlags();
462     }
463     if (flags & (SkPaint::kUnderlineText_Flag | SkPaint::kStrikeThruText_Flag)) {
464         SkScalar left = x;
465         SkScalar right = x + length;
466         float textSize = paint.getTextSize();
467         float strokeWidth = fmax(textSize * kStdUnderline_Thickness, 1.0f);
468         if (flags & SkPaint::kUnderlineText_Flag) {
469             SkScalar top = y + textSize * kStdUnderline_Offset - 0.5f * strokeWidth;
470             SkScalar bottom = y + textSize * kStdUnderline_Offset + 0.5f * strokeWidth;
471             canvas->drawRect(left, top, right, bottom, paint);
472         }
473         if (flags & SkPaint::kStrikeThruText_Flag) {
474             SkScalar top = y + textSize * kStdStrikeThru_Offset - 0.5f * strokeWidth;
475             SkScalar bottom = y + textSize * kStdStrikeThru_Offset + 0.5f * strokeWidth;
476             canvas->drawRect(left, top, right, bottom, paint);
477         }
478     }
479 }
480 
drawText(Canvas * canvas,const uint16_t * text,int start,int count,int contextCount,float x,float y,int bidiFlags,const Paint & origPaint,TypefaceImpl * typeface)481 void drawText(Canvas* canvas, const uint16_t* text, int start, int count, int contextCount,
482              float x, float y, int bidiFlags, const Paint& origPaint, TypefaceImpl* typeface) {
483     // minikin may modify the original paint
484     Paint paint(origPaint);
485 
486     Layout layout;
487     MinikinUtils::doLayout(&layout, &paint, bidiFlags, typeface, text, start, count, contextCount);
488 
489     size_t nGlyphs = layout.nGlyphs();
490     uint16_t* glyphs = new uint16_t[nGlyphs];
491     float* pos = new float[nGlyphs * 2];
492 
493     x += MinikinUtils::xOffsetForTextAlign(&paint, layout);
494 
495     MinikinRect bounds;
496     layout.getBounds(&bounds);
497 
498     DrawTextFunctor f(layout, canvas, glyphs, pos, paint, x, y, bounds);
499     MinikinUtils::forFontRun(layout, &paint, f);
500 
501     drawTextDecorations(canvas, x, y, layout.getAdvance(), paint);
502 
503     delete[] glyphs;
504     delete[] pos;
505 }
506 
drawTextChars(JNIEnv * env,jobject,jlong canvasHandle,jcharArray text,jint index,jint count,jfloat x,jfloat y,jint bidiFlags,jlong paintHandle,jlong typefaceHandle)507 static void drawTextChars(JNIEnv* env, jobject, jlong canvasHandle, jcharArray text,
508                           jint index, jint count, jfloat x, jfloat y, jint bidiFlags,
509                           jlong paintHandle, jlong typefaceHandle) {
510     Paint* paint = reinterpret_cast<Paint*>(paintHandle);
511     TypefaceImpl* typeface = reinterpret_cast<TypefaceImpl*>(typefaceHandle);
512     jchar* jchars = env->GetCharArrayElements(text, NULL);
513     drawText(get_canvas(canvasHandle), jchars + index, 0, count, count, x, y,
514                                        bidiFlags, *paint, typeface);
515     env->ReleaseCharArrayElements(text, jchars, JNI_ABORT);
516 }
517 
drawTextString(JNIEnv * env,jobject,jlong canvasHandle,jstring text,jint start,jint end,jfloat x,jfloat y,jint bidiFlags,jlong paintHandle,jlong typefaceHandle)518 static void drawTextString(JNIEnv* env, jobject, jlong canvasHandle, jstring text,
519                            jint start, jint end, jfloat x, jfloat y, jint bidiFlags,
520                            jlong paintHandle, jlong typefaceHandle) {
521     Paint* paint = reinterpret_cast<Paint*>(paintHandle);
522     TypefaceImpl* typeface = reinterpret_cast<TypefaceImpl*>(typefaceHandle);
523     const int count = end - start;
524     const jchar* jchars = env->GetStringChars(text, NULL);
525     drawText(get_canvas(canvasHandle), jchars + start, 0, count, count, x, y,
526                                        bidiFlags, *paint, typeface);
527     env->ReleaseStringChars(text, jchars);
528 }
529 
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)530 static void drawTextRunChars(JNIEnv* env, jobject, jlong canvasHandle, jcharArray text, jint index,
531                              jint count, jint contextIndex, jint contextCount, jfloat x, jfloat y,
532                              jboolean isRtl, jlong paintHandle, jlong typefaceHandle) {
533     Paint* paint = reinterpret_cast<Paint*>(paintHandle);
534     TypefaceImpl* typeface = reinterpret_cast<TypefaceImpl*>(typefaceHandle);
535 
536     const int bidiFlags = isRtl ? kBidi_Force_RTL : kBidi_Force_LTR;
537     jchar* jchars = env->GetCharArrayElements(text, NULL);
538     drawText(get_canvas(canvasHandle), jchars + contextIndex, index - contextIndex, count,
539                                        contextCount, x, y, bidiFlags, *paint, typeface);
540     env->ReleaseCharArrayElements(text, jchars, JNI_ABORT);
541 }
542 
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)543 static void drawTextRunString(JNIEnv* env, jobject obj, jlong canvasHandle, jstring text,
544                               jint start, jint end, jint contextStart, jint contextEnd,
545                               jfloat x, jfloat y, jboolean isRtl, jlong paintHandle,
546                               jlong typefaceHandle) {
547     Paint* paint = reinterpret_cast<Paint*>(paintHandle);
548     TypefaceImpl* typeface = reinterpret_cast<TypefaceImpl*>(typefaceHandle);
549 
550     int bidiFlags = isRtl ? kBidi_Force_RTL : kBidi_Force_LTR;
551     jint count = end - start;
552     jint contextCount = contextEnd - contextStart;
553     const jchar* jchars = env->GetStringChars(text, NULL);
554     drawText(get_canvas(canvasHandle), jchars + contextStart, start - contextStart, count,
555                                        contextCount, x, y, bidiFlags, *paint, typeface);
556     env->ReleaseStringChars(text, jchars);
557 }
558 
drawPosTextChars(JNIEnv * env,jobject,jlong canvasHandle,jcharArray text,jint index,jint count,jfloatArray pos,jlong paintHandle)559 static void drawPosTextChars(JNIEnv* env, jobject, jlong canvasHandle, jcharArray text,
560                              jint index, jint count, jfloatArray pos, jlong paintHandle) {
561     Paint* paint = reinterpret_cast<Paint*>(paintHandle);
562     jchar* jchars = text ? env->GetCharArrayElements(text, NULL) : NULL;
563     float* posArray = pos ? env->GetFloatArrayElements(pos, NULL) : NULL;
564     int posCount = pos ? env->GetArrayLength(pos) >> 1: 0;
565 
566     get_canvas(canvasHandle)->drawPosText(jchars + index, posArray, count << 1, posCount, *paint);
567 
568     if (text) {
569         env->ReleaseCharArrayElements(text, jchars, 0);
570     }
571     if (pos) {
572         env->ReleaseFloatArrayElements(pos, posArray, 0);
573     }
574 }
575 
576 
drawPosTextString(JNIEnv * env,jobject,jlong canvasHandle,jstring text,jfloatArray pos,jlong paintHandle)577 static void drawPosTextString(JNIEnv* env, jobject, jlong canvasHandle, jstring text,
578                               jfloatArray pos, jlong paintHandle) {
579     Paint* paint = reinterpret_cast<Paint*>(paintHandle);
580     const jchar* jchars = text ? env->GetStringChars(text, NULL) : NULL;
581     int byteLength = text ? env->GetStringLength(text) : 0;
582     float* posArray = pos ? env->GetFloatArrayElements(pos, NULL) : NULL;
583     int posCount = pos ? env->GetArrayLength(pos) >> 1: 0;
584 
585     get_canvas(canvasHandle)->drawPosText(jchars , posArray, byteLength << 1, posCount, *paint);
586 
587     if (text) {
588         env->ReleaseStringChars(text, jchars);
589     }
590     if (pos) {
591         env->ReleaseFloatArrayElements(pos, posArray, 0);
592     }
593 }
594 
595 class DrawTextOnPathFunctor {
596 public:
DrawTextOnPathFunctor(const Layout & layout,Canvas * canvas,float hOffset,float vOffset,const Paint & paint,const SkPath & path)597     DrawTextOnPathFunctor(const Layout& layout, Canvas* canvas, float hOffset,
598                 float vOffset, const Paint& paint, const SkPath& path)
599             : layout(layout), canvas(canvas), hOffset(hOffset), vOffset(vOffset),
600                 paint(paint), path(path) {
601     }
operator ()(size_t start,size_t end)602     void operator()(size_t start, size_t end) {
603         uint16_t glyphs[1];
604         for (size_t i = start; i < end; i++) {
605             glyphs[0] = layout.getGlyphId(i);
606             float x = hOffset + layout.getX(i);
607             float y = vOffset + layout.getY(i);
608             canvas->drawTextOnPath(glyphs, 1, path, x, y, paint);
609         }
610     }
611 private:
612     const Layout& layout;
613     Canvas* canvas;
614     float hOffset;
615     float vOffset;
616     const Paint& paint;
617     const SkPath& path;
618 };
619 
drawTextOnPath(Canvas * canvas,const uint16_t * text,int count,int bidiFlags,const SkPath & path,float hOffset,float vOffset,const Paint & paint,TypefaceImpl * typeface)620 static void drawTextOnPath(Canvas* canvas, const uint16_t* text, int count, int bidiFlags,
621                            const SkPath& path, float hOffset, float vOffset,
622                            const Paint& paint, TypefaceImpl* typeface) {
623     Paint paintCopy(paint);
624     Layout layout;
625     MinikinUtils::doLayout(&layout, &paintCopy, bidiFlags, typeface, text, 0, count, count);
626     hOffset += MinikinUtils::hOffsetForTextAlign(&paintCopy, layout, path);
627 
628     // Set align to left for drawing, as we don't want individual
629     // glyphs centered or right-aligned; the offset above takes
630     // care of all alignment.
631     paintCopy.setTextAlign(Paint::kLeft_Align);
632 
633     DrawTextOnPathFunctor f(layout, canvas, hOffset, vOffset, paintCopy, path);
634     MinikinUtils::forFontRun(layout, &paintCopy, f);
635 }
636 
drawTextOnPathChars(JNIEnv * env,jobject,jlong canvasHandle,jcharArray text,jint index,jint count,jlong pathHandle,jfloat hOffset,jfloat vOffset,jint bidiFlags,jlong paintHandle,jlong typefaceHandle)637 static void drawTextOnPathChars(JNIEnv* env, jobject, jlong canvasHandle, jcharArray text,
638                                 jint index, jint count, jlong pathHandle, jfloat hOffset,
639                                 jfloat vOffset, jint bidiFlags, jlong paintHandle,
640                                 jlong typefaceHandle) {
641     SkPath* path = reinterpret_cast<SkPath*>(pathHandle);
642     Paint* paint = reinterpret_cast<Paint*>(paintHandle);
643     TypefaceImpl* typeface = reinterpret_cast<TypefaceImpl*>(typefaceHandle);
644 
645     jchar* jchars = env->GetCharArrayElements(text, NULL);
646 
647     drawTextOnPath(get_canvas(canvasHandle), jchars + index, count, bidiFlags, *path,
648                    hOffset, vOffset, *paint, typeface);
649 
650     env->ReleaseCharArrayElements(text, jchars, 0);
651 }
652 
drawTextOnPathString(JNIEnv * env,jobject,jlong canvasHandle,jstring text,jlong pathHandle,jfloat hOffset,jfloat vOffset,jint bidiFlags,jlong paintHandle,jlong typefaceHandle)653 static void drawTextOnPathString(JNIEnv* env, jobject, jlong canvasHandle, jstring text,
654                                  jlong pathHandle, jfloat hOffset, jfloat vOffset,
655                                  jint bidiFlags, jlong paintHandle, jlong typefaceHandle) {
656     SkPath* path = reinterpret_cast<SkPath*>(pathHandle);
657     Paint* paint = reinterpret_cast<Paint*>(paintHandle);
658     TypefaceImpl* typeface = reinterpret_cast<TypefaceImpl*>(typefaceHandle);
659 
660     const jchar* jchars = env->GetStringChars(text, NULL);
661     int count = env->GetStringLength(text);
662 
663     drawTextOnPath(get_canvas(canvasHandle), jchars, count, bidiFlags, *path,
664                    hOffset, vOffset, *paint, typeface);
665 
666     env->ReleaseStringChars(text, jchars);
667 }
668 
setDrawFilter(JNIEnv * env,jobject,jlong canvasHandle,jlong filterHandle)669 static void setDrawFilter(JNIEnv* env, jobject, jlong canvasHandle, jlong filterHandle) {
670     get_canvas(canvasHandle)->setDrawFilter(reinterpret_cast<SkDrawFilter*>(filterHandle));
671 }
672 
freeCaches(JNIEnv * env,jobject)673 static void freeCaches(JNIEnv* env, jobject) {
674     SkGraphics::PurgeFontCache();
675 }
676 
freeTextLayoutCaches(JNIEnv * env,jobject)677 static void freeTextLayoutCaches(JNIEnv* env, jobject) {
678     Layout::purgeCaches();
679 }
680 
681 }; // namespace CanvasJNI
682 
683 static JNINativeMethod gMethods[] = {
684     {"finalizer", "(J)V", (void*) CanvasJNI::finalizer},
685     {"initRaster", "(J)J", (void*) CanvasJNI::initRaster},
686     {"native_setBitmap", "(JJZ)V", (void*) CanvasJNI::setBitmap},
687     {"native_isOpaque","(J)Z", (void*) CanvasJNI::isOpaque},
688     {"native_getWidth","(J)I", (void*) CanvasJNI::getWidth},
689     {"native_getHeight","(J)I", (void*) CanvasJNI::getHeight},
690     {"native_save","(JI)I", (void*) CanvasJNI::save},
691     {"native_saveLayer","(JFFFFJI)I", (void*) CanvasJNI::saveLayer},
692     {"native_saveLayerAlpha","(JFFFFII)I", (void*) CanvasJNI::saveLayerAlpha},
693     {"native_getSaveCount","(J)I", (void*) CanvasJNI::getSaveCount},
694     {"native_restore","(J)V", (void*) CanvasJNI::restore},
695     {"native_restoreToCount","(JI)V", (void*) CanvasJNI::restoreToCount},
696     {"native_getCTM", "(JJ)V", (void*)CanvasJNI::getCTM},
697     {"native_setMatrix","(JJ)V", (void*) CanvasJNI::setMatrix},
698     {"native_concat","(JJ)V", (void*) CanvasJNI::concat},
699     {"native_rotate","(JF)V", (void*) CanvasJNI::rotate},
700     {"native_scale","(JFF)V", (void*) CanvasJNI::scale},
701     {"native_skew","(JFF)V", (void*) CanvasJNI::skew},
702     {"native_translate","(JFF)V", (void*) CanvasJNI::translate},
703     {"native_getClipBounds","(JLandroid/graphics/Rect;)Z", (void*) CanvasJNI::getClipBounds},
704     {"native_quickReject","(JJ)Z", (void*) CanvasJNI::quickRejectPath},
705     {"native_quickReject","(JFFFF)Z", (void*)CanvasJNI::quickRejectRect},
706     {"native_clipRect","(JFFFFI)Z", (void*) CanvasJNI::clipRect},
707     {"native_clipPath","(JJI)Z", (void*) CanvasJNI::clipPath},
708     {"native_clipRegion","(JJI)Z", (void*) CanvasJNI::clipRegion},
709     {"native_drawColor","(JII)V", (void*) CanvasJNI::drawColor},
710     {"native_drawPaint","(JJ)V", (void*) CanvasJNI::drawPaint},
711     {"native_drawPoint", "(JFFJ)V", (void*) CanvasJNI::drawPoint},
712     {"native_drawPoints", "(J[FIIJ)V", (void*) CanvasJNI::drawPoints},
713     {"native_drawLine", "(JFFFFJ)V", (void*) CanvasJNI::drawLine},
714     {"native_drawLines", "(J[FIIJ)V", (void*) CanvasJNI::drawLines},
715     {"native_drawRect","(JFFFFJ)V", (void*) CanvasJNI::drawRect},
716     {"native_drawRoundRect","(JFFFFFFJ)V", (void*) CanvasJNI::drawRoundRect},
717     {"native_drawCircle","(JFFFJ)V", (void*) CanvasJNI::drawCircle},
718     {"native_drawOval","(JFFFFJ)V", (void*) CanvasJNI::drawOval},
719     {"native_drawArc","(JFFFFFFZJ)V", (void*) CanvasJNI::drawArc},
720     {"native_drawPath","(JJJ)V", (void*) CanvasJNI::drawPath},
721     {"nativeDrawVertices", "(JII[FI[FI[II[SIIJ)V", (void*)CanvasJNI::drawVertices},
722     {"native_drawBitmap","(JJFFJIII)V", (void*) CanvasJNI::drawBitmap},
723     {"nativeDrawBitmapMatrix", "(JJJJ)V", (void*)CanvasJNI::drawBitmapMatrix},
724     {"native_drawBitmap","(JJFFFFFFFFJII)V", (void*) CanvasJNI::drawBitmapRect},
725     {"native_drawBitmap", "(J[IIIFFIIZJ)V", (void*)CanvasJNI::drawBitmapArray},
726     {"nativeDrawBitmapMesh", "(JJII[FI[IIJ)V", (void*)CanvasJNI::drawBitmapMesh},
727     {"native_drawText","(J[CIIFFIJJ)V", (void*) CanvasJNI::drawTextChars},
728     {"native_drawText","(JLjava/lang/String;IIFFIJJ)V", (void*) CanvasJNI::drawTextString},
729     {"native_drawTextRun","(J[CIIIIFFZJJ)V", (void*) CanvasJNI::drawTextRunChars},
730     {"native_drawTextRun","(JLjava/lang/String;IIIIFFZJJ)V", (void*) CanvasJNI::drawTextRunString},
731     {"native_drawTextOnPath","(J[CIIJFFIJJ)V", (void*) CanvasJNI::drawTextOnPathChars},
732     {"native_drawTextOnPath","(JLjava/lang/String;JFFIJJ)V", (void*) CanvasJNI::drawTextOnPathString},
733     {"nativeSetDrawFilter", "(JJ)V", (void*) CanvasJNI::setDrawFilter},
734     {"freeCaches", "()V", (void*) CanvasJNI::freeCaches},
735     {"freeTextLayoutCaches", "()V", (void*) CanvasJNI::freeTextLayoutCaches}
736 };
737 
register_android_graphics_Canvas(JNIEnv * env)738 int register_android_graphics_Canvas(JNIEnv* env) {
739     return AndroidRuntime::registerNativeMethods(env, "android/graphics/Canvas", gMethods, NELEM(gMethods));
740 }
741 
742 }; // namespace android
743