android_graphics_Canvas.cpp revision 1526a458a30184609f19b05e7334da3cbde81dd1
1/*
2 * Copyright (C) 2014 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 *      http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17#include "jni.h"
18#include "GraphicsJNI.h"
19#include "core_jni_helpers.h"
20
21#include <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
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    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
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    SkXfermode::Mode mode = static_cast<SkXfermode::Mode>(modeHandle);
190    get_canvas(canvasHandle)->drawColor(color, mode);
191}
192
193static void drawPaint(JNIEnv* env, jobject, jlong canvasHandle, jlong paintHandle) {
194    Paint* paint = reinterpret_cast<Paint*>(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 Paint* paint = reinterpret_cast<Paint*>(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 Paint* paint = reinterpret_cast<Paint*>(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    Paint* paint = reinterpret_cast<Paint*>(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 Paint* paint = reinterpret_cast<Paint*>(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 Paint* paint = reinterpret_cast<Paint*>(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 Paint* paint = reinterpret_cast<Paint*>(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 Paint* paint = reinterpret_cast<Paint*>(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 Paint* paint = reinterpret_cast<Paint*>(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 Paint* paint = reinterpret_cast<Paint*>(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 Paint* paint = reinterpret_cast<Paint*>(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 Paint* paint = reinterpret_cast<Paint*>(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 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
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 Paint* paint = reinterpret_cast<Paint*>(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 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
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    bitmap.setInfo(info);
387    if (!GraphicsJNI::allocatePixels(env, &bitmap, NULL)) {
388        return;
389    }
390
391    if (!GraphicsJNI::SetPixels(env, jcolors, offset, stride, 0, 0, width, height, bitmap)) {
392        return;
393    }
394
395    const Paint* paint = reinterpret_cast<Paint*>(paintHandle);
396    get_canvas(canvasHandle)->drawBitmap(bitmap, x, y, paint);
397}
398
399static void drawBitmapMesh(JNIEnv* env, jobject, jlong canvasHandle, jlong bitmapHandle,
400                           jint meshWidth, jint meshHeight, jfloatArray jverts,
401                           jint vertIndex, jintArray jcolors, jint colorIndex, jlong paintHandle) {
402    const int ptCount = (meshWidth + 1) * (meshHeight + 1);
403    AutoJavaFloatArray vertA(env, jverts, vertIndex + (ptCount << 1));
404    AutoJavaIntArray colorA(env, jcolors, colorIndex + ptCount);
405
406    const SkBitmap* bitmap = reinterpret_cast<SkBitmap*>(bitmapHandle);
407    const Paint* paint = reinterpret_cast<Paint*>(paintHandle);
408    get_canvas(canvasHandle)->drawBitmapMesh(*bitmap, meshWidth, meshHeight,
409                                             vertA.ptr(), colorA.ptr(), paint);
410}
411
412class DrawTextFunctor {
413public:
414    DrawTextFunctor(const Layout& layout, Canvas* canvas, uint16_t* glyphs, float* pos,
415                    const SkPaint& paint, float x, float y, MinikinRect& bounds,
416                    float totalAdvance)
417            : layout(layout), canvas(canvas), glyphs(glyphs), pos(pos), paint(paint),
418              x(x), y(y), bounds(bounds), totalAdvance(totalAdvance) { }
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                         totalAdvance);
439    }
440private:
441    const Layout& layout;
442    Canvas* canvas;
443    uint16_t* glyphs;
444    float* pos;
445    const SkPaint& paint;
446    float x;
447    float y;
448    MinikinRect& bounds;
449    float totalAdvance;
450};
451
452// Same values used by Skia
453#define kStdStrikeThru_Offset   (-6.0f / 21.0f)
454#define kStdUnderline_Offset    (1.0f / 9.0f)
455#define kStdUnderline_Thickness (1.0f / 18.0f)
456
457void drawTextDecorations(Canvas* canvas, float x, float y, float length, const SkPaint& paint) {
458    uint32_t flags;
459    SkDrawFilter* drawFilter = canvas->getDrawFilter();
460    if (drawFilter) {
461        SkPaint paintCopy(paint);
462        drawFilter->filter(&paintCopy, SkDrawFilter::kText_Type);
463        flags = paintCopy.getFlags();
464    } else {
465        flags = paint.getFlags();
466    }
467    if (flags & (SkPaint::kUnderlineText_Flag | SkPaint::kStrikeThruText_Flag)) {
468        SkScalar left = x;
469        SkScalar right = x + length;
470        float textSize = paint.getTextSize();
471        float strokeWidth = fmax(textSize * kStdUnderline_Thickness, 1.0f);
472        if (flags & SkPaint::kUnderlineText_Flag) {
473            SkScalar top = y + textSize * kStdUnderline_Offset - 0.5f * strokeWidth;
474            SkScalar bottom = y + textSize * kStdUnderline_Offset + 0.5f * strokeWidth;
475            canvas->drawRect(left, top, right, bottom, paint);
476        }
477        if (flags & SkPaint::kStrikeThruText_Flag) {
478            SkScalar top = y + textSize * kStdStrikeThru_Offset - 0.5f * strokeWidth;
479            SkScalar bottom = y + textSize * kStdStrikeThru_Offset + 0.5f * strokeWidth;
480            canvas->drawRect(left, top, right, bottom, paint);
481        }
482    }
483}
484
485void drawText(Canvas* canvas, const uint16_t* text, int start, int count, int contextCount,
486             float x, float y, int bidiFlags, const Paint& origPaint, TypefaceImpl* typeface) {
487    // minikin may modify the original paint
488    Paint paint(origPaint);
489
490    Layout layout;
491    MinikinUtils::doLayout(&layout, &paint, bidiFlags, typeface, text, start, count, contextCount);
492
493    size_t nGlyphs = layout.nGlyphs();
494    uint16_t* glyphs = new uint16_t[nGlyphs];
495    float* pos = new float[nGlyphs * 2];
496
497    x += MinikinUtils::xOffsetForTextAlign(&paint, layout);
498
499    MinikinRect bounds;
500    layout.getBounds(&bounds);
501    if (!canvas->drawTextAbsolutePos()) {
502        bounds.offset(x, y);
503    }
504
505    DrawTextFunctor f(layout, canvas, glyphs, pos, paint, x, y, bounds, layout.getAdvance());
506    MinikinUtils::forFontRun(layout, &paint, f);
507
508    drawTextDecorations(canvas, x, y, layout.getAdvance(), paint);
509
510    delete[] glyphs;
511    delete[] pos;
512}
513
514static void drawTextChars(JNIEnv* env, jobject, jlong canvasHandle, jcharArray text,
515                          jint index, jint count, jfloat x, jfloat y, jint bidiFlags,
516                          jlong paintHandle, jlong typefaceHandle) {
517    Paint* paint = reinterpret_cast<Paint*>(paintHandle);
518    TypefaceImpl* typeface = reinterpret_cast<TypefaceImpl*>(typefaceHandle);
519    jchar* jchars = env->GetCharArrayElements(text, NULL);
520    drawText(get_canvas(canvasHandle), jchars + index, 0, count, count, x, y,
521                                       bidiFlags, *paint, typeface);
522    env->ReleaseCharArrayElements(text, jchars, JNI_ABORT);
523}
524
525static void drawTextString(JNIEnv* env, jobject, jlong canvasHandle, jstring text,
526                           jint start, jint end, jfloat x, jfloat y, jint bidiFlags,
527                           jlong paintHandle, jlong typefaceHandle) {
528    Paint* paint = reinterpret_cast<Paint*>(paintHandle);
529    TypefaceImpl* typeface = reinterpret_cast<TypefaceImpl*>(typefaceHandle);
530    const int count = end - start;
531    const jchar* jchars = env->GetStringChars(text, NULL);
532    drawText(get_canvas(canvasHandle), jchars + start, 0, count, count, x, y,
533                                       bidiFlags, *paint, typeface);
534    env->ReleaseStringChars(text, jchars);
535}
536
537static void drawTextRunChars(JNIEnv* env, jobject, jlong canvasHandle, jcharArray text, jint index,
538                             jint count, jint contextIndex, jint contextCount, jfloat x, jfloat y,
539                             jboolean isRtl, jlong paintHandle, jlong typefaceHandle) {
540    Paint* paint = reinterpret_cast<Paint*>(paintHandle);
541    TypefaceImpl* typeface = reinterpret_cast<TypefaceImpl*>(typefaceHandle);
542
543    const int bidiFlags = isRtl ? kBidi_Force_RTL : kBidi_Force_LTR;
544    jchar* jchars = env->GetCharArrayElements(text, NULL);
545    drawText(get_canvas(canvasHandle), jchars + contextIndex, index - contextIndex, count,
546                                       contextCount, x, y, bidiFlags, *paint, typeface);
547    env->ReleaseCharArrayElements(text, jchars, JNI_ABORT);
548}
549
550static void drawTextRunString(JNIEnv* env, jobject obj, jlong canvasHandle, jstring text,
551                              jint start, jint end, jint contextStart, jint contextEnd,
552                              jfloat x, jfloat y, jboolean isRtl, jlong paintHandle,
553                              jlong typefaceHandle) {
554    Paint* paint = reinterpret_cast<Paint*>(paintHandle);
555    TypefaceImpl* typeface = reinterpret_cast<TypefaceImpl*>(typefaceHandle);
556
557    int bidiFlags = isRtl ? kBidi_Force_RTL : kBidi_Force_LTR;
558    jint count = end - start;
559    jint contextCount = contextEnd - contextStart;
560    const jchar* jchars = env->GetStringChars(text, NULL);
561    drawText(get_canvas(canvasHandle), jchars + contextStart, start - contextStart, count,
562                                       contextCount, x, y, bidiFlags, *paint, typeface);
563    env->ReleaseStringChars(text, jchars);
564}
565
566class DrawTextOnPathFunctor {
567public:
568    DrawTextOnPathFunctor(const Layout& layout, Canvas* canvas, float hOffset,
569                float vOffset, const Paint& paint, const SkPath& path)
570            : layout(layout), canvas(canvas), hOffset(hOffset), vOffset(vOffset),
571                paint(paint), path(path) {
572    }
573    void operator()(size_t start, size_t end) {
574        uint16_t glyphs[1];
575        for (size_t i = start; i < end; i++) {
576            glyphs[0] = layout.getGlyphId(i);
577            float x = hOffset + layout.getX(i);
578            float y = vOffset + layout.getY(i);
579            canvas->drawTextOnPath(glyphs, 1, path, x, y, paint);
580        }
581    }
582private:
583    const Layout& layout;
584    Canvas* canvas;
585    float hOffset;
586    float vOffset;
587    const Paint& paint;
588    const SkPath& path;
589};
590
591static void drawTextOnPath(Canvas* canvas, const uint16_t* text, int count, int bidiFlags,
592                           const SkPath& path, float hOffset, float vOffset,
593                           const Paint& paint, TypefaceImpl* typeface) {
594    Paint paintCopy(paint);
595    Layout layout;
596    MinikinUtils::doLayout(&layout, &paintCopy, bidiFlags, typeface, text, 0, count, count);
597    hOffset += MinikinUtils::hOffsetForTextAlign(&paintCopy, layout, path);
598
599    // Set align to left for drawing, as we don't want individual
600    // glyphs centered or right-aligned; the offset above takes
601    // care of all alignment.
602    paintCopy.setTextAlign(Paint::kLeft_Align);
603
604    DrawTextOnPathFunctor f(layout, canvas, hOffset, vOffset, paintCopy, path);
605    MinikinUtils::forFontRun(layout, &paintCopy, f);
606}
607
608static void drawTextOnPathChars(JNIEnv* env, jobject, jlong canvasHandle, jcharArray text,
609                                jint index, jint count, jlong pathHandle, jfloat hOffset,
610                                jfloat vOffset, jint bidiFlags, jlong paintHandle,
611                                jlong typefaceHandle) {
612    SkPath* path = reinterpret_cast<SkPath*>(pathHandle);
613    Paint* paint = reinterpret_cast<Paint*>(paintHandle);
614    TypefaceImpl* typeface = reinterpret_cast<TypefaceImpl*>(typefaceHandle);
615
616    jchar* jchars = env->GetCharArrayElements(text, NULL);
617
618    drawTextOnPath(get_canvas(canvasHandle), jchars + index, count, bidiFlags, *path,
619                   hOffset, vOffset, *paint, typeface);
620
621    env->ReleaseCharArrayElements(text, jchars, 0);
622}
623
624static void drawTextOnPathString(JNIEnv* env, jobject, jlong canvasHandle, jstring text,
625                                 jlong pathHandle, jfloat hOffset, jfloat vOffset,
626                                 jint bidiFlags, jlong paintHandle, jlong typefaceHandle) {
627    SkPath* path = reinterpret_cast<SkPath*>(pathHandle);
628    Paint* paint = reinterpret_cast<Paint*>(paintHandle);
629    TypefaceImpl* typeface = reinterpret_cast<TypefaceImpl*>(typefaceHandle);
630
631    const jchar* jchars = env->GetStringChars(text, NULL);
632    int count = env->GetStringLength(text);
633
634    drawTextOnPath(get_canvas(canvasHandle), jchars, count, bidiFlags, *path,
635                   hOffset, vOffset, *paint, typeface);
636
637    env->ReleaseStringChars(text, jchars);
638}
639
640static void setDrawFilter(JNIEnv* env, jobject, jlong canvasHandle, jlong filterHandle) {
641    get_canvas(canvasHandle)->setDrawFilter(reinterpret_cast<SkDrawFilter*>(filterHandle));
642}
643
644static void freeCaches(JNIEnv* env, jobject) {
645    SkGraphics::PurgeFontCache();
646}
647
648static void freeTextLayoutCaches(JNIEnv* env, jobject) {
649    Layout::purgeCaches();
650}
651
652}; // namespace CanvasJNI
653
654static JNINativeMethod gMethods[] = {
655    {"finalizer", "(J)V", (void*) CanvasJNI::finalizer},
656    {"initRaster", "(J)J", (void*) CanvasJNI::initRaster},
657    {"native_setBitmap", "(JJZ)V", (void*) CanvasJNI::setBitmap},
658    {"native_isOpaque","(J)Z", (void*) CanvasJNI::isOpaque},
659    {"native_getWidth","(J)I", (void*) CanvasJNI::getWidth},
660    {"native_getHeight","(J)I", (void*) CanvasJNI::getHeight},
661    {"native_save","(JI)I", (void*) CanvasJNI::save},
662    {"native_saveLayer","(JFFFFJI)I", (void*) CanvasJNI::saveLayer},
663    {"native_saveLayerAlpha","(JFFFFII)I", (void*) CanvasJNI::saveLayerAlpha},
664    {"native_getSaveCount","(J)I", (void*) CanvasJNI::getSaveCount},
665    {"native_restore","(J)V", (void*) CanvasJNI::restore},
666    {"native_restoreToCount","(JI)V", (void*) CanvasJNI::restoreToCount},
667    {"native_getCTM", "(JJ)V", (void*)CanvasJNI::getCTM},
668    {"native_setMatrix","(JJ)V", (void*) CanvasJNI::setMatrix},
669    {"native_concat","(JJ)V", (void*) CanvasJNI::concat},
670    {"native_rotate","(JF)V", (void*) CanvasJNI::rotate},
671    {"native_scale","(JFF)V", (void*) CanvasJNI::scale},
672    {"native_skew","(JFF)V", (void*) CanvasJNI::skew},
673    {"native_translate","(JFF)V", (void*) CanvasJNI::translate},
674    {"native_getClipBounds","(JLandroid/graphics/Rect;)Z", (void*) CanvasJNI::getClipBounds},
675    {"native_quickReject","(JJ)Z", (void*) CanvasJNI::quickRejectPath},
676    {"native_quickReject","(JFFFF)Z", (void*)CanvasJNI::quickRejectRect},
677    {"native_clipRect","(JFFFFI)Z", (void*) CanvasJNI::clipRect},
678    {"native_clipPath","(JJI)Z", (void*) CanvasJNI::clipPath},
679    {"native_clipRegion","(JJI)Z", (void*) CanvasJNI::clipRegion},
680    {"native_drawColor","(JII)V", (void*) CanvasJNI::drawColor},
681    {"native_drawPaint","(JJ)V", (void*) CanvasJNI::drawPaint},
682    {"native_drawPoint", "(JFFJ)V", (void*) CanvasJNI::drawPoint},
683    {"native_drawPoints", "(J[FIIJ)V", (void*) CanvasJNI::drawPoints},
684    {"native_drawLine", "(JFFFFJ)V", (void*) CanvasJNI::drawLine},
685    {"native_drawLines", "(J[FIIJ)V", (void*) CanvasJNI::drawLines},
686    {"native_drawRect","(JFFFFJ)V", (void*) CanvasJNI::drawRect},
687    {"native_drawRoundRect","(JFFFFFFJ)V", (void*) CanvasJNI::drawRoundRect},
688    {"native_drawCircle","(JFFFJ)V", (void*) CanvasJNI::drawCircle},
689    {"native_drawOval","(JFFFFJ)V", (void*) CanvasJNI::drawOval},
690    {"native_drawArc","(JFFFFFFZJ)V", (void*) CanvasJNI::drawArc},
691    {"native_drawPath","(JJJ)V", (void*) CanvasJNI::drawPath},
692    {"nativeDrawVertices", "(JII[FI[FI[II[SIIJ)V", (void*)CanvasJNI::drawVertices},
693    {"native_drawBitmap","(JJFFJIII)V", (void*) CanvasJNI::drawBitmap},
694    {"nativeDrawBitmapMatrix", "(JJJJ)V", (void*)CanvasJNI::drawBitmapMatrix},
695    {"native_drawBitmap","(JJFFFFFFFFJII)V", (void*) CanvasJNI::drawBitmapRect},
696    {"native_drawBitmap", "(J[IIIFFIIZJ)V", (void*)CanvasJNI::drawBitmapArray},
697    {"nativeDrawBitmapMesh", "(JJII[FI[IIJ)V", (void*)CanvasJNI::drawBitmapMesh},
698    {"native_drawText","(J[CIIFFIJJ)V", (void*) CanvasJNI::drawTextChars},
699    {"native_drawText","(JLjava/lang/String;IIFFIJJ)V", (void*) CanvasJNI::drawTextString},
700    {"native_drawTextRun","(J[CIIIIFFZJJ)V", (void*) CanvasJNI::drawTextRunChars},
701    {"native_drawTextRun","(JLjava/lang/String;IIIIFFZJJ)V", (void*) CanvasJNI::drawTextRunString},
702    {"native_drawTextOnPath","(J[CIIJFFIJJ)V", (void*) CanvasJNI::drawTextOnPathChars},
703    {"native_drawTextOnPath","(JLjava/lang/String;JFFIJJ)V", (void*) CanvasJNI::drawTextOnPathString},
704    {"nativeSetDrawFilter", "(JJ)V", (void*) CanvasJNI::setDrawFilter},
705    {"freeCaches", "()V", (void*) CanvasJNI::freeCaches},
706    {"freeTextLayoutCaches", "()V", (void*) CanvasJNI::freeTextLayoutCaches}
707};
708
709int register_android_graphics_Canvas(JNIEnv* env) {
710    return RegisterMethodsOrDie(env, "android/graphics/Canvas", gMethods, NELEM(gMethods));
711}
712
713}; // namespace android
714