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