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