android_graphics_Canvas.cpp revision f5d6c555c3430f6e423952ba3ab024380e550bba
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 "SkGraphics.h"
23#include "SkPorterDuff.h"
24#include "TypefaceImpl.h"
25
26#include <minikin/Layout.h>
27#include "MinikinSkia.h"
28#include "MinikinUtils.h"
29
30namespace android {
31
32namespace CanvasJNI {
33
34static Canvas* get_canvas(jlong canvasHandle) {
35    return reinterpret_cast<Canvas*>(canvasHandle);
36}
37
38static void finalizer(JNIEnv* env, jobject clazz, jlong canvasHandle) {
39    delete get_canvas(canvasHandle);
40}
41
42// Native wrapper constructor used by Canvas(Bitmap)
43static 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.
50static 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
56static jboolean isOpaque(JNIEnv*, jobject, jlong canvasHandle) {
57    return get_canvas(canvasHandle)->isOpaque() ? JNI_TRUE : JNI_FALSE;
58}
59
60static jint getWidth(JNIEnv*, jobject, jlong canvasHandle) {
61    return static_cast<jint>(get_canvas(canvasHandle)->width());
62}
63
64static jint getHeight(JNIEnv*, jobject, jlong canvasHandle) {
65    return static_cast<jint>(get_canvas(canvasHandle)->height());
66}
67
68static jint getSaveCount(JNIEnv*, jobject, jlong canvasHandle) {
69    return static_cast<jint>(get_canvas(canvasHandle)->getSaveCount());
70}
71
72static 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
77static jint saveLayer(JNIEnv* env, jobject, jlong canvasHandle, jfloat l, jfloat t,
78                      jfloat r, jfloat b, jlong paintHandle, jint flagsHandle) {
79    SkPaint* paint  = reinterpret_cast<SkPaint*>(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
84static 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
90static 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
99static 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
108static void getCTM(JNIEnv* env, jobject, jlong canvasHandle, jlong matrixHandle) {
109    SkMatrix* matrix = reinterpret_cast<SkMatrix*>(matrixHandle);
110    get_canvas(canvasHandle)->getMatrix(matrix);
111}
112
113static 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
118static 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
123static void rotate(JNIEnv*, jobject, jlong canvasHandle, jfloat degrees) {
124    get_canvas(canvasHandle)->rotate(degrees);
125}
126
127static void scale(JNIEnv*, jobject, jlong canvasHandle, jfloat sx, jfloat sy) {
128    get_canvas(canvasHandle)->scale(sx, sy);
129}
130
131static void skew(JNIEnv*, jobject, jlong canvasHandle, jfloat sx, jfloat sy) {
132    get_canvas(canvasHandle)->skew(sx, sy);
133}
134
135static void translate(JNIEnv*, jobject, jlong canvasHandle, jfloat dx, jfloat dy) {
136    get_canvas(canvasHandle)->translate(dx, dy);
137}
138
139static 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
153static 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
159static 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
165static 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
172static 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
180static 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
188static 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
193static void drawPaint(JNIEnv* env, jobject, jlong canvasHandle, jlong paintHandle) {
194    SkPaint* paint = reinterpret_cast<SkPaint*>(paintHandle);
195    get_canvas(canvasHandle)->drawPaint(*paint);
196}
197
198static void drawPoint(JNIEnv*, jobject, jlong canvasHandle, jfloat x, jfloat y,
199                      jlong paintHandle) {
200    const SkPaint* paint = reinterpret_cast<SkPaint*>(paintHandle);
201    get_canvas(canvasHandle)->drawPoint(x, y, *paint);
202}
203
204static 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 SkPaint* paint = reinterpret_cast<SkPaint*>(paintHandle);
217    get_canvas(canvasHandle)->drawPoints(floats + offset, count, *paint);
218}
219
220static void drawLine(JNIEnv* env, jobject, jlong canvasHandle, jfloat startX, jfloat startY,
221                     jfloat stopX, jfloat stopY, jlong paintHandle) {
222    SkPaint* paint = reinterpret_cast<SkPaint*>(paintHandle);
223    get_canvas(canvasHandle)->drawLine(startX, startY, stopX, stopY, *paint);
224}
225
226static 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 SkPaint* paint = reinterpret_cast<SkPaint*>(paintHandle);
239    get_canvas(canvasHandle)->drawLines(floats + offset, count, *paint);
240}
241
242static void drawRect(JNIEnv* env, jobject, jlong canvasHandle, jfloat left, jfloat top,
243                     jfloat right, jfloat bottom, jlong paintHandle) {
244    const SkPaint* paint = reinterpret_cast<SkPaint*>(paintHandle);
245    get_canvas(canvasHandle)->drawRect(left, top, right, bottom, *paint);
246}
247
248static void drawRoundRect(JNIEnv* env, jobject, jlong canvasHandle, jfloat left, jfloat top,
249                          jfloat right, jfloat bottom, jfloat rx, jfloat ry, jlong paintHandle) {
250    const SkPaint* paint = reinterpret_cast<SkPaint*>(paintHandle);
251    get_canvas(canvasHandle)->drawRoundRect(left, top, right, bottom, rx, ry, *paint);
252}
253
254static void drawCircle(JNIEnv* env, jobject, jlong canvasHandle, jfloat cx, jfloat cy,
255                       jfloat radius, jlong paintHandle) {
256    const SkPaint* paint = reinterpret_cast<SkPaint*>(paintHandle);
257    get_canvas(canvasHandle)->drawCircle(cx, cy, radius, *paint);
258}
259
260static void drawOval(JNIEnv* env, jobject, jlong canvasHandle, jfloat left, jfloat top,
261                     jfloat right, jfloat bottom, jlong paintHandle) {
262    const SkPaint* paint = reinterpret_cast<SkPaint*>(paintHandle);
263    get_canvas(canvasHandle)->drawOval(left, top, right, bottom, *paint);
264}
265
266static 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 SkPaint* paint = reinterpret_cast<SkPaint*>(paintHandle);
270    get_canvas(canvasHandle)->drawArc(left, top, right, bottom, startAngle, sweepAngle,
271                                       useCenter, *paint);
272}
273
274static void drawPath(JNIEnv* env, jobject, jlong canvasHandle, jlong pathHandle,
275                     jlong paintHandle) {
276    const SkPath* path = reinterpret_cast<SkPath*>(pathHandle);
277    const SkPaint* paint = reinterpret_cast<SkPaint*>(paintHandle);
278    get_canvas(canvasHandle)->drawPath(*path, *paint);
279}
280
281static 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 SkPaint* paint = reinterpret_cast<SkPaint*>(paintHandle);
307    get_canvas(canvasHandle)->drawVertices(mode, vertexCount, verts, texs, colors,
308                                           indices, indexCount, *paint);
309}
310
311static 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 SkPaint* paint = reinterpret_cast<SkPaint*>(paintHandle);
317
318    if (canvasDensity == bitmapDensity || canvasDensity == 0 || bitmapDensity == 0) {
319        if (screenDensity != 0 && screenDensity != bitmapDensity) {
320            SkPaint filteredPaint;
321            if (paint) {
322                filteredPaint = *paint;
323            }
324            filteredPaint.setFilterLevel(SkPaint::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        SkPaint filteredPaint;
336        if (paint) {
337            filteredPaint = *paint;
338        }
339        filteredPaint.setFilterLevel(SkPaint::kLow_FilterLevel);
340
341        canvas->drawBitmap(*bitmap, 0, 0, &filteredPaint);
342        canvas->restore();
343    }
344}
345
346static 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 SkPaint* paint = reinterpret_cast<SkPaint*>(paintHandle);
351    get_canvas(canvasHandle)->drawBitmap(*bitmap, *matrix, paint);
352}
353
354static 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 SkPaint* paint = reinterpret_cast<SkPaint*>(paintHandle);
361
362    if (screenDensity != 0 && screenDensity != bitmapDensity) {
363        SkPaint filteredPaint;
364        if (paint) {
365            filteredPaint = *paint;
366        }
367        filteredPaint.setFilterLevel(SkPaint::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
376static 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 SkPaint* paint = reinterpret_cast<SkPaint*>(paintHandle);
395    get_canvas(canvasHandle)->drawBitmap(bitmap, x, y, paint);
396}
397
398static 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 SkPaint* paint = reinterpret_cast<SkPaint*>(paintHandle);
407    get_canvas(canvasHandle)->drawBitmapMesh(*bitmap, meshWidth, meshHeight,
408                                             vertA.ptr(), colorA.ptr(), paint);
409}
410
411static void drawTextChars(JNIEnv* env, jobject, jlong canvasHandle, jcharArray text,
412                          jint index, jint count, jfloat x, jfloat y, jint bidiFlags,
413                          jlong paintHandle, jlong typefaceHandle) {
414    SkPaint* paint = reinterpret_cast<SkPaint*>(paintHandle);
415    TypefaceImpl* typeface = reinterpret_cast<TypefaceImpl*>(typefaceHandle);
416    jchar* jchars = env->GetCharArrayElements(text, NULL);
417    const char* textArray = reinterpret_cast<const char*>(jchars) + index;
418    get_canvas(canvasHandle)->drawText(textArray, 0, count, count, x, y, bidiFlags, *paint, typeface);
419    env->ReleaseCharArrayElements(text, jchars, JNI_ABORT);
420}
421
422static void drawTextString(JNIEnv* env, jobject, jlong canvasHandle, jstring text,
423                           jint start, jint end, jfloat x, jfloat y, jint bidiFlags,
424                           jlong paintHandle, jlong typefaceHandle) {
425    SkPaint* paint = reinterpret_cast<SkPaint*>(paintHandle);
426    TypefaceImpl* typeface = reinterpret_cast<TypefaceImpl*>(typefaceHandle);
427    const int count = end - start;
428    const jchar* jchars = env->GetStringChars(text, NULL);
429    const char* textArray = reinterpret_cast<const char*>(jchars) + start;
430    get_canvas(canvasHandle)->drawText(textArray, 0, count, count, x, y, bidiFlags, *paint, typeface);
431    env->ReleaseStringChars(text, jchars);
432}
433
434static void drawTextRunChars(JNIEnv* env, jobject, jlong canvasHandle, jcharArray text, jint index,
435                             jint count, jint contextIndex, jint contextCount, jfloat x, jfloat y,
436                             jboolean isRtl, jlong paintHandle, jlong typefaceHandle) {
437    SkPaint* paint = reinterpret_cast<SkPaint*>(paintHandle);
438    TypefaceImpl* typeface = reinterpret_cast<TypefaceImpl*>(typefaceHandle);
439
440    const int bidiFlags = isRtl ? kBidi_Force_RTL : kBidi_Force_LTR;
441    jchar* jchars = env->GetCharArrayElements(text, NULL);
442    const char* textArray = reinterpret_cast<const char*>(jchars) + contextIndex;
443    get_canvas(canvasHandle)->drawText(textArray, index - contextIndex, count, contextCount,
444                                       x, y, bidiFlags, *paint, typeface);
445    env->ReleaseCharArrayElements(text, jchars, JNI_ABORT);
446}
447
448static void drawTextRunString(JNIEnv* env, jobject obj, jlong canvasHandle, jstring text,
449                              jint start, jint end, jint contextStart, jint contextEnd,
450                              jfloat x, jfloat y, jboolean isRtl, jlong paintHandle,
451                              jlong typefaceHandle) {
452    SkPaint* paint = reinterpret_cast<SkPaint*>(paintHandle);
453    TypefaceImpl* typeface = reinterpret_cast<TypefaceImpl*>(typefaceHandle);
454
455    int bidiFlags = isRtl ? kBidi_Force_RTL : kBidi_Force_LTR;
456    jint count = end - start;
457    jint contextCount = contextEnd - contextStart;
458    const jchar* jchars = env->GetStringChars(text, NULL);
459    const char* textArray = reinterpret_cast<const char*>(jchars) + contextStart;
460    get_canvas(canvasHandle)->drawText(textArray, start - contextStart, count, contextCount,
461                                       x, y, bidiFlags, *paint, typeface);
462    env->ReleaseStringChars(text, jchars);
463}
464
465static void drawPosTextChars(JNIEnv* env, jobject, jlong canvasHandle, jcharArray text,
466                             jint index, jint count, jfloatArray pos, jlong paintHandle) {
467    SkPaint* paint = reinterpret_cast<SkPaint*>(paintHandle);
468    jchar* jchars = text ? env->GetCharArrayElements(text, NULL) : NULL;
469    float* posArray = pos ? env->GetFloatArrayElements(pos, NULL) : NULL;
470    int posCount = pos ? env->GetArrayLength(pos) >> 1: 0;
471
472    const char* textArray = reinterpret_cast<const char*>(jchars) + index;
473    get_canvas(canvasHandle)->drawPosText(textArray, posArray, count << 1, posCount, *paint);
474
475    if (text) {
476        env->ReleaseCharArrayElements(text, jchars, 0);
477    }
478    if (pos) {
479        env->ReleaseFloatArrayElements(pos, posArray, 0);
480    }
481}
482
483
484static void drawPosTextString(JNIEnv* env, jobject, jlong canvasHandle, jstring text,
485                              jfloatArray pos, jlong paintHandle) {
486    SkPaint* paint = reinterpret_cast<SkPaint*>(paintHandle);
487    const jchar* jchars = text ? env->GetStringChars(text, NULL) : NULL;
488    int byteLength = text ? env->GetStringLength(text) : 0;
489    float* posArray = pos ? env->GetFloatArrayElements(pos, NULL) : NULL;
490    int posCount = pos ? env->GetArrayLength(pos) >> 1: 0;
491
492    const char* textArray = reinterpret_cast<const char*>(jchars);
493    get_canvas(canvasHandle)->drawPosText(textArray , posArray, byteLength << 1, posCount, *paint);
494
495    if (text) {
496        env->ReleaseStringChars(text, jchars);
497    }
498    if (pos) {
499        env->ReleaseFloatArrayElements(pos, posArray, 0);
500    }
501}
502
503class DrawTextOnPathFunctor {
504public:
505    DrawTextOnPathFunctor(const Layout& layout, Canvas* canvas, float hOffset,
506                float vOffset, const SkPaint& paint, const SkPath& path)
507            : layout(layout), canvas(canvas), hOffset(hOffset), vOffset(vOffset),
508                paint(paint), path(path) {
509    }
510    void operator()(size_t start, size_t end) {
511        uint16_t glyphs[1];
512        for (size_t i = start; i < end; i++) {
513            glyphs[0] = layout.getGlyphId(i);
514            float x = hOffset + layout.getX(i);
515            float y = vOffset + layout.getY(i);
516            canvas->drawTextOnPath((const char*) glyphs, 1, path, x, y, paint);
517        }
518    }
519private:
520    const Layout& layout;
521    Canvas* canvas;
522    float hOffset;
523    float vOffset;
524    const SkPaint& paint;
525    const SkPath& path;
526};
527
528static void drawTextOnPath(Canvas* canvas, const char* text, int count, int bidiFlags,
529                           const SkPath& path, float hOffset, float vOffset,
530                           const SkPaint& paint, TypefaceImpl* typeface) {
531    SkPaint paintCopy(paint);
532    Layout layout;
533    std::string css = MinikinUtils::setLayoutProperties(&layout, &paintCopy, bidiFlags, typeface);
534    layout.doLayout((uint16_t*)text, 0, count, count, css);
535    hOffset += MinikinUtils::hOffsetForTextAlign(&paintCopy, layout, path);
536
537    // Set align to left for drawing, as we don't want individual
538    // glyphs centered or right-aligned; the offset above takes
539    // care of all alignment.
540    paintCopy.setTextAlign(SkPaint::kLeft_Align);
541
542    DrawTextOnPathFunctor f(layout, canvas, hOffset, vOffset, paintCopy, path);
543    MinikinUtils::forFontRun(layout, &paintCopy, f);
544}
545
546static void drawTextOnPathChars(JNIEnv* env, jobject, jlong canvasHandle, jcharArray text,
547                                jint index, jint count, jlong pathHandle, jfloat hOffset,
548                                jfloat vOffset, jint bidiFlags, jlong paintHandle,
549                                jlong typefaceHandle) {
550    SkPath* path = reinterpret_cast<SkPath*>(pathHandle);
551    SkPaint* paint = reinterpret_cast<SkPaint*>(paintHandle);
552    TypefaceImpl* typeface = reinterpret_cast<TypefaceImpl*>(typefaceHandle);
553
554    jchar* jchars = env->GetCharArrayElements(text, NULL);
555    const char* textArray = reinterpret_cast<const char*>(jchars);
556
557    drawTextOnPath(get_canvas(canvasHandle), textArray + index, count, bidiFlags, *path,
558                   hOffset, vOffset, *paint, typeface);
559
560    env->ReleaseCharArrayElements(text, jchars, 0);
561}
562
563static void drawTextOnPathString(JNIEnv* env, jobject, jlong canvasHandle, jstring text,
564                                 jlong pathHandle, jfloat hOffset, jfloat vOffset,
565                                 jint bidiFlags, jlong paintHandle, jlong typefaceHandle) {
566    SkPath* path = reinterpret_cast<SkPath*>(pathHandle);
567    SkPaint* paint = reinterpret_cast<SkPaint*>(paintHandle);
568    TypefaceImpl* typeface = reinterpret_cast<TypefaceImpl*>(typefaceHandle);
569
570    const jchar* jchars = env->GetStringChars(text, NULL);
571    const char* textArray = reinterpret_cast<const char*>(jchars);
572    int count = env->GetStringLength(text);
573
574    drawTextOnPath(get_canvas(canvasHandle), textArray, count, bidiFlags, *path,
575                   hOffset, vOffset, *paint, typeface);
576
577    env->ReleaseStringChars(text, jchars);
578}
579
580static void setDrawFilter(JNIEnv* env, jobject, jlong canvasHandle, jlong filterHandle) {
581    get_canvas(canvasHandle)->setDrawFilter(reinterpret_cast<SkDrawFilter*>(filterHandle));
582}
583
584static void freeCaches(JNIEnv* env, jobject) {
585    SkGraphics::PurgeFontCache();
586}
587
588static void freeTextLayoutCaches(JNIEnv* env, jobject) {
589    Layout::purgeCaches();
590}
591
592}; // namespace CanvasJNI
593
594static JNINativeMethod gMethods[] = {
595    {"finalizer", "(J)V", (void*) CanvasJNI::finalizer},
596    {"initRaster", "(J)J", (void*) CanvasJNI::initRaster},
597    {"native_setBitmap", "(JJZ)V", (void*) CanvasJNI::setBitmap},
598    {"native_isOpaque","(J)Z", (void*) CanvasJNI::isOpaque},
599    {"native_getWidth","(J)I", (void*) CanvasJNI::getWidth},
600    {"native_getHeight","(J)I", (void*) CanvasJNI::getHeight},
601    {"native_save","(JI)I", (void*) CanvasJNI::save},
602    {"native_saveLayer","(JFFFFJI)I", (void*) CanvasJNI::saveLayer},
603    {"native_saveLayerAlpha","(JFFFFII)I", (void*) CanvasJNI::saveLayerAlpha},
604    {"native_getSaveCount","(J)I", (void*) CanvasJNI::getSaveCount},
605    {"native_restore","(J)V", (void*) CanvasJNI::restore},
606    {"native_restoreToCount","(JI)V", (void*) CanvasJNI::restoreToCount},
607    {"native_getCTM", "(JJ)V", (void*)CanvasJNI::getCTM},
608    {"native_setMatrix","(JJ)V", (void*) CanvasJNI::setMatrix},
609    {"native_concat","(JJ)V", (void*) CanvasJNI::concat},
610    {"native_rotate","(JF)V", (void*) CanvasJNI::rotate},
611    {"native_scale","(JFF)V", (void*) CanvasJNI::scale},
612    {"native_skew","(JFF)V", (void*) CanvasJNI::skew},
613    {"native_translate","(JFF)V", (void*) CanvasJNI::translate},
614    {"native_getClipBounds","(JLandroid/graphics/Rect;)Z", (void*) CanvasJNI::getClipBounds},
615    {"native_quickReject","(JJ)Z", (void*) CanvasJNI::quickRejectPath},
616    {"native_quickReject","(JFFFF)Z", (void*)CanvasJNI::quickRejectRect},
617    {"native_clipRect","(JFFFFI)Z", (void*) CanvasJNI::clipRect},
618    {"native_clipPath","(JJI)Z", (void*) CanvasJNI::clipPath},
619    {"native_clipRegion","(JJI)Z", (void*) CanvasJNI::clipRegion},
620    {"native_drawColor","(JII)V", (void*) CanvasJNI::drawColor},
621    {"native_drawPaint","(JJ)V", (void*) CanvasJNI::drawPaint},
622    {"native_drawPoint", "(JFFJ)V", (void*) CanvasJNI::drawPoint},
623    {"native_drawPoints", "(J[FIIJ)V", (void*) CanvasJNI::drawPoints},
624    {"native_drawLine", "(JFFFFJ)V", (void*) CanvasJNI::drawLine},
625    {"native_drawLines", "(J[FIIJ)V", (void*) CanvasJNI::drawLines},
626    {"native_drawRect","(JFFFFJ)V", (void*) CanvasJNI::drawRect},
627    {"native_drawRoundRect","(JFFFFFFJ)V", (void*) CanvasJNI::drawRoundRect},
628    {"native_drawCircle","(JFFFJ)V", (void*) CanvasJNI::drawCircle},
629    {"native_drawOval","(JFFFFJ)V", (void*) CanvasJNI::drawOval},
630    {"native_drawArc","(JFFFFFFZJ)V", (void*) CanvasJNI::drawArc},
631    {"native_drawPath","(JJJ)V", (void*) CanvasJNI::drawPath},
632    {"nativeDrawVertices", "(JII[FI[FI[II[SIIJ)V", (void*)CanvasJNI::drawVertices},
633    {"native_drawBitmap","(JJFFJIII)V", (void*) CanvasJNI::drawBitmap},
634    {"nativeDrawBitmapMatrix", "(JJJJ)V", (void*)CanvasJNI::drawBitmapMatrix},
635    {"native_drawBitmap","(JJFFFFFFFFJII)V", (void*) CanvasJNI::drawBitmapRect},
636    {"native_drawBitmap", "(J[IIIFFIIZJ)V", (void*)CanvasJNI::drawBitmapArray},
637    {"nativeDrawBitmapMesh", "(JJII[FI[IIJ)V", (void*)CanvasJNI::drawBitmapMesh},
638    {"native_drawText","(J[CIIFFIJJ)V", (void*) CanvasJNI::drawTextChars},
639    {"native_drawText","(JLjava/lang/String;IIFFIJJ)V", (void*) CanvasJNI::drawTextString},
640    {"native_drawTextRun","(J[CIIIIFFZJJ)V", (void*) CanvasJNI::drawTextRunChars},
641    {"native_drawTextRun","(JLjava/lang/String;IIIIFFZJJ)V", (void*) CanvasJNI::drawTextRunString},
642    {"native_drawTextOnPath","(J[CIIJFFIJJ)V", (void*) CanvasJNI::drawTextOnPathChars},
643    {"native_drawTextOnPath","(JLjava/lang/String;JFFIJJ)V", (void*) CanvasJNI::drawTextOnPathString},
644    {"nativeSetDrawFilter", "(JJ)V", (void*) CanvasJNI::setDrawFilter},
645    {"freeCaches", "()V", (void*) CanvasJNI::freeCaches},
646    {"freeTextLayoutCaches", "()V", (void*) CanvasJNI::freeTextLayoutCaches}
647};
648
649int register_android_graphics_Canvas(JNIEnv* env) {
650    return AndroidRuntime::registerNativeMethods(env, "android/graphics/Canvas", gMethods, NELEM(gMethods));
651}
652
653}; // namespace android
654