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