android_graphics_Canvas.cpp revision 6c67f1d04591f44bccb476d715a005ad5bbdf840
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 <androidfw/ResourceTypes.h> 22#include <hwui/Canvas.h> 23#include <hwui/Paint.h> 24#include <hwui/Typeface.h> 25#include <minikin/Layout.h> 26 27#include "Bitmap.h" 28#include "SkDrawFilter.h" 29#include "SkGraphics.h" 30 31namespace android { 32 33namespace CanvasJNI { 34 35static Canvas* get_canvas(jlong canvasHandle) { 36 return reinterpret_cast<Canvas*>(canvasHandle); 37} 38 39static void delete_canvas(Canvas* canvas) { 40 delete canvas; 41} 42 43static jlong getNativeFinalizer(JNIEnv* env, jobject clazz) { 44 return static_cast<jlong>(reinterpret_cast<uintptr_t>(&delete_canvas)); 45} 46 47// Native wrapper constructor used by Canvas(Bitmap) 48static jlong initRaster(JNIEnv* env, jobject, jobject jbitmap) { 49 SkBitmap bitmap; 50 if (jbitmap != NULL) { 51 GraphicsJNI::getSkBitmap(env, jbitmap, &bitmap); 52 } 53 return reinterpret_cast<jlong>(Canvas::create_canvas(bitmap)); 54} 55 56// Set the given bitmap as the new draw target (wrapped in a new SkCanvas), 57// optionally copying canvas matrix & clip state. 58static void setBitmap(JNIEnv* env, jobject, jlong canvasHandle, jobject jbitmap) { 59 SkBitmap bitmap; 60 if (jbitmap != NULL) { 61 GraphicsJNI::getSkBitmap(env, jbitmap, &bitmap); 62 } 63 get_canvas(canvasHandle)->setBitmap(bitmap); 64} 65 66static jboolean isOpaque(JNIEnv*, jobject, jlong canvasHandle) { 67 return get_canvas(canvasHandle)->isOpaque() ? JNI_TRUE : JNI_FALSE; 68} 69 70static jint getWidth(JNIEnv*, jobject, jlong canvasHandle) { 71 return static_cast<jint>(get_canvas(canvasHandle)->width()); 72} 73 74static jint getHeight(JNIEnv*, jobject, jlong canvasHandle) { 75 return static_cast<jint>(get_canvas(canvasHandle)->height()); 76} 77 78static void setHighContrastText(JNIEnv*, jobject, jlong canvasHandle, jboolean highContrastText) { 79 Canvas* canvas = get_canvas(canvasHandle); 80 canvas->setHighContrastText(highContrastText); 81} 82 83static jint getSaveCount(JNIEnv*, jobject, jlong canvasHandle) { 84 return static_cast<jint>(get_canvas(canvasHandle)->getSaveCount()); 85} 86 87static jint save(JNIEnv*, jobject, jlong canvasHandle, jint flagsHandle) { 88 SaveFlags::Flags flags = static_cast<SaveFlags::Flags>(flagsHandle); 89 return static_cast<jint>(get_canvas(canvasHandle)->save(flags)); 90} 91 92static jint saveLayer(JNIEnv* env, jobject, jlong canvasHandle, jfloat l, jfloat t, 93 jfloat r, jfloat b, jlong paintHandle, jint flagsHandle) { 94 Paint* paint = reinterpret_cast<Paint*>(paintHandle); 95 SaveFlags::Flags flags = static_cast<SaveFlags::Flags>(flagsHandle); 96 return static_cast<jint>(get_canvas(canvasHandle)->saveLayer(l, t, r, b, paint, flags)); 97} 98 99static jint saveLayerAlpha(JNIEnv* env, jobject, jlong canvasHandle, jfloat l, jfloat t, 100 jfloat r, jfloat b, jint alpha, jint flagsHandle) { 101 SaveFlags::Flags flags = static_cast<SaveFlags::Flags>(flagsHandle); 102 return static_cast<jint>(get_canvas(canvasHandle)->saveLayerAlpha(l, t, r, b, alpha, flags)); 103} 104 105static void restore(JNIEnv* env, jobject, jlong canvasHandle, jboolean throwOnUnderflow) { 106 Canvas* canvas = get_canvas(canvasHandle); 107 if (canvas->getSaveCount() <= 1) { // cannot restore anymore 108 if (throwOnUnderflow) { 109 doThrowISE(env, "Underflow in restore - more restores than saves"); 110 } 111 return; // compat behavior - return without throwing 112 } 113 canvas->restore(); 114} 115 116static void restoreToCount(JNIEnv* env, jobject, jlong canvasHandle, jint restoreCount, 117 jboolean throwOnUnderflow) { 118 Canvas* canvas = get_canvas(canvasHandle); 119 if (restoreCount < 1 || restoreCount > canvas->getSaveCount()) { 120 if (throwOnUnderflow) { 121 doThrowIAE(env, "Underflow in restoreToCount - more restores than saves"); 122 return; 123 } 124 restoreCount = 1; // compat behavior - restore as far as possible 125 } 126 canvas->restoreToCount(restoreCount); 127} 128 129static void getCTM(JNIEnv* env, jobject, jlong canvasHandle, jlong matrixHandle) { 130 SkMatrix* matrix = reinterpret_cast<SkMatrix*>(matrixHandle); 131 get_canvas(canvasHandle)->getMatrix(matrix); 132} 133 134static void setMatrix(JNIEnv* env, jobject, jlong canvasHandle, jlong matrixHandle) { 135 const SkMatrix* matrix = reinterpret_cast<SkMatrix*>(matrixHandle); 136 get_canvas(canvasHandle)->setMatrix(matrix ? *matrix : SkMatrix::I()); 137} 138 139static void concat(JNIEnv* env, jobject, jlong canvasHandle, jlong matrixHandle) { 140 const SkMatrix* matrix = reinterpret_cast<SkMatrix*>(matrixHandle); 141 get_canvas(canvasHandle)->concat(*matrix); 142} 143 144static void rotate(JNIEnv*, jobject, jlong canvasHandle, jfloat degrees) { 145 get_canvas(canvasHandle)->rotate(degrees); 146} 147 148static void scale(JNIEnv*, jobject, jlong canvasHandle, jfloat sx, jfloat sy) { 149 get_canvas(canvasHandle)->scale(sx, sy); 150} 151 152static void skew(JNIEnv*, jobject, jlong canvasHandle, jfloat sx, jfloat sy) { 153 get_canvas(canvasHandle)->skew(sx, sy); 154} 155 156static void translate(JNIEnv*, jobject, jlong canvasHandle, jfloat dx, jfloat dy) { 157 get_canvas(canvasHandle)->translate(dx, dy); 158} 159 160static jboolean getClipBounds(JNIEnv* env, jobject, jlong canvasHandle, jobject bounds) { 161 SkRect r; 162 SkIRect ir; 163 bool result = get_canvas(canvasHandle)->getClipBounds(&r); 164 165 if (!result) { 166 r.setEmpty(); 167 } 168 r.round(&ir); 169 170 (void)GraphicsJNI::irect_to_jrect(ir, env, bounds); 171 return result ? JNI_TRUE : JNI_FALSE; 172} 173 174static jboolean quickRejectRect(JNIEnv* env, jobject, jlong canvasHandle, 175 jfloat left, jfloat top, jfloat right, jfloat bottom) { 176 bool result = get_canvas(canvasHandle)->quickRejectRect(left, top, right, bottom); 177 return result ? JNI_TRUE : JNI_FALSE; 178} 179 180static jboolean quickRejectPath(JNIEnv* env, jobject, jlong canvasHandle, jlong pathHandle) { 181 SkPath* path = reinterpret_cast<SkPath*>(pathHandle); 182 bool result = get_canvas(canvasHandle)->quickRejectPath(*path); 183 return result ? JNI_TRUE : JNI_FALSE; 184} 185 186// SkRegion::Op and SkClipOp are numerically identical, so we can freely cast 187// from one to the other (though SkClipOp is destined to become a strict subset) 188static_assert(SkRegion::kDifference_Op == static_cast<SkRegion::Op>(SkClipOp::kDifference), ""); 189static_assert(SkRegion::kIntersect_Op == static_cast<SkRegion::Op>(SkClipOp::kIntersect), ""); 190static_assert(SkRegion::kUnion_Op == static_cast<SkRegion::Op>(SkClipOp::kUnion), ""); 191static_assert(SkRegion::kXOR_Op == static_cast<SkRegion::Op>(SkClipOp::kXOR), ""); 192static_assert(SkRegion::kReverseDifference_Op == static_cast<SkRegion::Op>(SkClipOp::kReverseDifference), ""); 193static_assert(SkRegion::kReplace_Op == static_cast<SkRegion::Op>(SkClipOp::kReplace), ""); 194 195static SkClipOp opHandleToClipOp(jint opHandle) { 196 // The opHandle is defined in Canvas.java to be Region::Op 197 SkRegion::Op rgnOp = static_cast<SkRegion::Op>(opHandle); 198 199 // In the future, when we no longer support the wide range of ops (e.g. Union, Xor) 200 // this function can perform a range check and throw an unsupported-exception. 201 // e.g. if (rgnOp != kIntersect && rgnOp != kDifference) throw... 202 203 // Skia now takes a different type, SkClipOp, as the parameter to clipping calls 204 // This type is binary compatible with SkRegion::Op, so a static_cast<> is safe. 205 return static_cast<SkClipOp>(rgnOp); 206} 207 208static jboolean clipRect(JNIEnv*, jobject, jlong canvasHandle, jfloat l, jfloat t, 209 jfloat r, jfloat b, jint opHandle) { 210 bool nonEmptyClip = get_canvas(canvasHandle)->clipRect(l, t, r, b, 211 opHandleToClipOp(opHandle)); 212 return nonEmptyClip ? JNI_TRUE : JNI_FALSE; 213} 214 215static jboolean clipPath(JNIEnv* env, jobject, jlong canvasHandle, jlong pathHandle, 216 jint opHandle) { 217 SkPath* path = reinterpret_cast<SkPath*>(pathHandle); 218 bool nonEmptyClip = get_canvas(canvasHandle)->clipPath(path, opHandleToClipOp(opHandle)); 219 return nonEmptyClip ? JNI_TRUE : JNI_FALSE; 220} 221 222static jboolean clipRegion(JNIEnv* env, jobject, jlong canvasHandle, jlong deviceRgnHandle, 223 jint opHandle) { 224 SkRegion* deviceRgn = reinterpret_cast<SkRegion*>(deviceRgnHandle); 225 bool nonEmptyClip = get_canvas(canvasHandle)->clipRegion(deviceRgn, opHandleToClipOp(opHandle)); 226 return nonEmptyClip ? JNI_TRUE : JNI_FALSE; 227} 228 229static void drawColor(JNIEnv* env, jobject, jlong canvasHandle, jint color, jint modeHandle) { 230 SkBlendMode mode = static_cast<SkBlendMode>(modeHandle); 231 get_canvas(canvasHandle)->drawColor(color, mode); 232} 233 234static void drawPaint(JNIEnv* env, jobject, jlong canvasHandle, jlong paintHandle) { 235 Paint* paint = reinterpret_cast<Paint*>(paintHandle); 236 get_canvas(canvasHandle)->drawPaint(*paint); 237} 238 239static void drawPoint(JNIEnv*, jobject, jlong canvasHandle, jfloat x, jfloat y, 240 jlong paintHandle) { 241 const Paint* paint = reinterpret_cast<Paint*>(paintHandle); 242 get_canvas(canvasHandle)->drawPoint(x, y, *paint); 243} 244 245static void drawPoints(JNIEnv* env, jobject, jlong canvasHandle, jfloatArray jptsArray, 246 jint offset, jint count, jlong paintHandle) { 247 NPE_CHECK_RETURN_VOID(env, jptsArray); 248 AutoJavaFloatArray autoPts(env, jptsArray); 249 float* floats = autoPts.ptr(); 250 const int length = autoPts.length(); 251 252 if ((offset | count) < 0 || offset + count > length) { 253 doThrowAIOOBE(env); 254 return; 255 } 256 257 const Paint* paint = reinterpret_cast<Paint*>(paintHandle); 258 get_canvas(canvasHandle)->drawPoints(floats + offset, count, *paint); 259} 260 261static void drawLine(JNIEnv* env, jobject, jlong canvasHandle, jfloat startX, jfloat startY, 262 jfloat stopX, jfloat stopY, jlong paintHandle) { 263 Paint* paint = reinterpret_cast<Paint*>(paintHandle); 264 get_canvas(canvasHandle)->drawLine(startX, startY, stopX, stopY, *paint); 265} 266 267static void drawLines(JNIEnv* env, jobject, jlong canvasHandle, jfloatArray jptsArray, 268 jint offset, jint count, jlong paintHandle) { 269 NPE_CHECK_RETURN_VOID(env, jptsArray); 270 AutoJavaFloatArray autoPts(env, jptsArray); 271 float* floats = autoPts.ptr(); 272 const int length = autoPts.length(); 273 274 if ((offset | count) < 0 || offset + count > length) { 275 doThrowAIOOBE(env); 276 return; 277 } 278 279 const Paint* paint = reinterpret_cast<Paint*>(paintHandle); 280 get_canvas(canvasHandle)->drawLines(floats + offset, count, *paint); 281} 282 283static void drawRect(JNIEnv* env, jobject, jlong canvasHandle, jfloat left, jfloat top, 284 jfloat right, jfloat bottom, jlong paintHandle) { 285 const Paint* paint = reinterpret_cast<Paint*>(paintHandle); 286 get_canvas(canvasHandle)->drawRect(left, top, right, bottom, *paint); 287} 288 289static void drawRegion(JNIEnv* env, jobject, jlong canvasHandle, jlong regionHandle, 290 jlong paintHandle) { 291 const SkRegion* region = reinterpret_cast<SkRegion*>(regionHandle); 292 const Paint* paint = reinterpret_cast<Paint*>(paintHandle); 293 get_canvas(canvasHandle)->drawRegion(*region, *paint); 294} 295 296static void drawRoundRect(JNIEnv* env, jobject, jlong canvasHandle, jfloat left, jfloat top, 297 jfloat right, jfloat bottom, jfloat rx, jfloat ry, jlong paintHandle) { 298 const Paint* paint = reinterpret_cast<Paint*>(paintHandle); 299 get_canvas(canvasHandle)->drawRoundRect(left, top, right, bottom, rx, ry, *paint); 300} 301 302static void drawCircle(JNIEnv* env, jobject, jlong canvasHandle, jfloat cx, jfloat cy, 303 jfloat radius, jlong paintHandle) { 304 const Paint* paint = reinterpret_cast<Paint*>(paintHandle); 305 get_canvas(canvasHandle)->drawCircle(cx, cy, radius, *paint); 306} 307 308static void drawOval(JNIEnv* env, jobject, jlong canvasHandle, jfloat left, jfloat top, 309 jfloat right, jfloat bottom, jlong paintHandle) { 310 const Paint* paint = reinterpret_cast<Paint*>(paintHandle); 311 get_canvas(canvasHandle)->drawOval(left, top, right, bottom, *paint); 312} 313 314static void drawArc(JNIEnv* env, jobject, jlong canvasHandle, jfloat left, jfloat top, 315 jfloat right, jfloat bottom, jfloat startAngle, jfloat sweepAngle, 316 jboolean useCenter, jlong paintHandle) { 317 const Paint* paint = reinterpret_cast<Paint*>(paintHandle); 318 get_canvas(canvasHandle)->drawArc(left, top, right, bottom, startAngle, sweepAngle, 319 useCenter, *paint); 320} 321 322static void drawPath(JNIEnv* env, jobject, jlong canvasHandle, jlong pathHandle, 323 jlong paintHandle) { 324 const SkPath* path = reinterpret_cast<SkPath*>(pathHandle); 325 const Paint* paint = reinterpret_cast<Paint*>(paintHandle); 326 get_canvas(canvasHandle)->drawPath(*path, *paint); 327} 328 329static void drawVertices(JNIEnv* env, jobject, jlong canvasHandle, 330 jint modeHandle, jint vertexCount, 331 jfloatArray jverts, jint vertIndex, 332 jfloatArray jtexs, jint texIndex, 333 jintArray jcolors, jint colorIndex, 334 jshortArray jindices, jint indexIndex, 335 jint indexCount, jlong paintHandle) { 336 AutoJavaFloatArray vertA(env, jverts, vertIndex + vertexCount); 337 AutoJavaFloatArray texA(env, jtexs, texIndex + vertexCount); 338 AutoJavaIntArray colorA(env, jcolors, colorIndex + vertexCount); 339 AutoJavaShortArray indexA(env, jindices, indexIndex + indexCount); 340 341 const float* verts = vertA.ptr() + vertIndex; 342 const float* texs = texA.ptr() + vertIndex; 343 const int* colors = NULL; 344 const uint16_t* indices = NULL; 345 346 if (jcolors != NULL) { 347 colors = colorA.ptr() + colorIndex; 348 } 349 if (jindices != NULL) { 350 indices = (const uint16_t*)(indexA.ptr() + indexIndex); 351 } 352 353 SkCanvas::VertexMode mode = static_cast<SkCanvas::VertexMode>(modeHandle); 354 const Paint* paint = reinterpret_cast<Paint*>(paintHandle); 355 get_canvas(canvasHandle)->drawVertices(mode, vertexCount, verts, texs, colors, 356 indices, indexCount, *paint); 357} 358 359static void drawNinePatch(JNIEnv* env, jobject, jlong canvasHandle, jlong bitmapHandle, 360 jlong chunkHandle, jfloat left, jfloat top, jfloat right, jfloat bottom, 361 jlong paintHandle, jint dstDensity, jint srcDensity) { 362 363 Canvas* canvas = get_canvas(canvasHandle); 364 Bitmap& bitmap = android::bitmap::toBitmap(env, bitmapHandle); 365 const android::Res_png_9patch* chunk = reinterpret_cast<android::Res_png_9patch*>(chunkHandle); 366 const Paint* paint = reinterpret_cast<Paint*>(paintHandle); 367 368 if (CC_LIKELY(dstDensity == srcDensity || dstDensity == 0 || srcDensity == 0)) { 369 canvas->drawNinePatch(bitmap, *chunk, left, top, right, bottom, paint); 370 } else { 371 canvas->save(SaveFlags::MatrixClip); 372 373 SkScalar scale = dstDensity / (float)srcDensity; 374 canvas->translate(left, top); 375 canvas->scale(scale, scale); 376 377 Paint filteredPaint; 378 if (paint) { 379 filteredPaint = *paint; 380 } 381 filteredPaint.setFilterQuality(kLow_SkFilterQuality); 382 383 canvas->drawNinePatch(bitmap, *chunk, 0, 0, (right-left)/scale, (bottom-top)/scale, 384 &filteredPaint); 385 386 canvas->restore(); 387 } 388} 389 390static void drawBitmap(JNIEnv* env, jobject, jlong canvasHandle, jobject jbitmap, 391 jfloat left, jfloat top, jlong paintHandle, jint canvasDensity, 392 jint screenDensity, jint bitmapDensity) { 393 Canvas* canvas = get_canvas(canvasHandle); 394 Bitmap& bitmap = android::bitmap::toBitmap(env, jbitmap); 395 const Paint* paint = reinterpret_cast<Paint*>(paintHandle); 396 397 if (canvasDensity == bitmapDensity || canvasDensity == 0 || bitmapDensity == 0) { 398 if (screenDensity != 0 && screenDensity != bitmapDensity) { 399 Paint filteredPaint; 400 if (paint) { 401 filteredPaint = *paint; 402 } 403 filteredPaint.setFilterQuality(kLow_SkFilterQuality); 404 canvas->drawBitmap(bitmap, left, top, &filteredPaint); 405 } else { 406 canvas->drawBitmap(bitmap, left, top, paint); 407 } 408 } else { 409 canvas->save(SaveFlags::MatrixClip); 410 SkScalar scale = canvasDensity / (float)bitmapDensity; 411 canvas->translate(left, top); 412 canvas->scale(scale, scale); 413 414 Paint filteredPaint; 415 if (paint) { 416 filteredPaint = *paint; 417 } 418 filteredPaint.setFilterQuality(kLow_SkFilterQuality); 419 420 canvas->drawBitmap(bitmap, 0, 0, &filteredPaint); 421 canvas->restore(); 422 } 423} 424 425static void drawBitmapMatrix(JNIEnv* env, jobject, jlong canvasHandle, jobject jbitmap, 426 jlong matrixHandle, jlong paintHandle) { 427 const SkMatrix* matrix = reinterpret_cast<SkMatrix*>(matrixHandle); 428 const Paint* paint = reinterpret_cast<Paint*>(paintHandle); 429 Bitmap& bitmap = android::bitmap::toBitmap(env, jbitmap); 430 get_canvas(canvasHandle)->drawBitmap(bitmap, *matrix, paint); 431} 432 433static void drawBitmapRect(JNIEnv* env, jobject, jlong canvasHandle, jobject jbitmap, 434 float srcLeft, float srcTop, float srcRight, float srcBottom, 435 float dstLeft, float dstTop, float dstRight, float dstBottom, 436 jlong paintHandle, jint screenDensity, jint bitmapDensity) { 437 Canvas* canvas = get_canvas(canvasHandle); 438 const Paint* paint = reinterpret_cast<Paint*>(paintHandle); 439 440 Bitmap& bitmap = android::bitmap::toBitmap(env, jbitmap); 441 if (screenDensity != 0 && screenDensity != bitmapDensity) { 442 Paint filteredPaint; 443 if (paint) { 444 filteredPaint = *paint; 445 } 446 filteredPaint.setFilterQuality(kLow_SkFilterQuality); 447 canvas->drawBitmap(bitmap, srcLeft, srcTop, srcRight, srcBottom, 448 dstLeft, dstTop, dstRight, dstBottom, &filteredPaint); 449 } else { 450 canvas->drawBitmap(bitmap, srcLeft, srcTop, srcRight, srcBottom, 451 dstLeft, dstTop, dstRight, dstBottom, paint); 452 } 453} 454 455static void drawBitmapArray(JNIEnv* env, jobject, jlong canvasHandle, 456 jintArray jcolors, jint offset, jint stride, 457 jfloat x, jfloat y, jint width, jint height, 458 jboolean hasAlpha, jlong paintHandle) { 459 // Note: If hasAlpha is false, kRGB_565_SkColorType will be used, which will 460 // correct the alphaType to kOpaque_SkAlphaType. 461 SkImageInfo info = SkImageInfo::MakeN32(width, height, kPremul_SkAlphaType, 462 GraphicsJNI::defaultColorSpace()); 463 SkBitmap bitmap; 464 bitmap.setInfo(info); 465 sk_sp<Bitmap> androidBitmap = Bitmap::allocateHeapBitmap(&bitmap, NULL); 466 if (!androidBitmap) { 467 return; 468 } 469 470 if (!GraphicsJNI::SetPixels(env, jcolors, offset, stride, 0, 0, width, height, bitmap)) { 471 return; 472 } 473 474 const Paint* paint = reinterpret_cast<Paint*>(paintHandle); 475 get_canvas(canvasHandle)->drawBitmap(*androidBitmap, x, y, paint); 476} 477 478static void drawBitmapMesh(JNIEnv* env, jobject, jlong canvasHandle, jobject jbitmap, 479 jint meshWidth, jint meshHeight, jfloatArray jverts, 480 jint vertIndex, jintArray jcolors, jint colorIndex, jlong paintHandle) { 481 const int ptCount = (meshWidth + 1) * (meshHeight + 1); 482 AutoJavaFloatArray vertA(env, jverts, vertIndex + (ptCount << 1)); 483 AutoJavaIntArray colorA(env, jcolors, colorIndex + ptCount); 484 485 const Paint* paint = reinterpret_cast<Paint*>(paintHandle); 486 Bitmap& bitmap = android::bitmap::toBitmap(env, jbitmap); 487 get_canvas(canvasHandle)->drawBitmapMesh(bitmap, meshWidth, meshHeight, 488 vertA.ptr(), colorA.ptr(), paint); 489} 490 491static void drawTextChars(JNIEnv* env, jobject, jlong canvasHandle, jcharArray text, 492 jint index, jint count, jfloat x, jfloat y, jint bidiFlags, 493 jlong paintHandle, jlong typefaceHandle) { 494 Paint* paint = reinterpret_cast<Paint*>(paintHandle); 495 Typeface* typeface = reinterpret_cast<Typeface*>(typefaceHandle); 496 jchar* jchars = env->GetCharArrayElements(text, NULL); 497 get_canvas(canvasHandle)->drawText(jchars + index, 0, count, count, x, y, 498 bidiFlags, *paint, typeface); 499 env->ReleaseCharArrayElements(text, jchars, JNI_ABORT); 500} 501 502static void drawTextString(JNIEnv* env, jobject, jlong canvasHandle, jstring text, 503 jint start, jint end, jfloat x, jfloat y, jint bidiFlags, 504 jlong paintHandle, jlong typefaceHandle) { 505 Paint* paint = reinterpret_cast<Paint*>(paintHandle); 506 Typeface* typeface = reinterpret_cast<Typeface*>(typefaceHandle); 507 const int count = end - start; 508 const jchar* jchars = env->GetStringChars(text, NULL); 509 get_canvas(canvasHandle)->drawText(jchars + start, 0, count, count, x, y, 510 bidiFlags, *paint, typeface); 511 env->ReleaseStringChars(text, jchars); 512} 513 514static void drawTextRunChars(JNIEnv* env, jobject, jlong canvasHandle, jcharArray text, jint index, 515 jint count, jint contextIndex, jint contextCount, jfloat x, jfloat y, 516 jboolean isRtl, jlong paintHandle, jlong typefaceHandle) { 517 Paint* paint = reinterpret_cast<Paint*>(paintHandle); 518 Typeface* typeface = reinterpret_cast<Typeface*>(typefaceHandle); 519 520 const int bidiFlags = isRtl ? minikin::kBidi_Force_RTL : minikin::kBidi_Force_LTR; 521 jchar* jchars = env->GetCharArrayElements(text, NULL); 522 get_canvas(canvasHandle)->drawText(jchars + contextIndex, index - contextIndex, count, 523 contextCount, x, y, bidiFlags, *paint, typeface); 524 env->ReleaseCharArrayElements(text, jchars, JNI_ABORT); 525} 526 527static void drawTextRunString(JNIEnv* env, jobject obj, jlong canvasHandle, jstring text, 528 jint start, jint end, jint contextStart, jint contextEnd, 529 jfloat x, jfloat y, jboolean isRtl, jlong paintHandle, 530 jlong typefaceHandle) { 531 Paint* paint = reinterpret_cast<Paint*>(paintHandle); 532 Typeface* typeface = reinterpret_cast<Typeface*>(typefaceHandle); 533 534 int bidiFlags = isRtl ? minikin::kBidi_Force_RTL : minikin::kBidi_Force_LTR; 535 jint count = end - start; 536 jint contextCount = contextEnd - contextStart; 537 const jchar* jchars = env->GetStringChars(text, NULL); 538 get_canvas(canvasHandle)->drawText(jchars + contextStart, start - contextStart, count, 539 contextCount, x, y, bidiFlags, *paint, typeface); 540 env->ReleaseStringChars(text, jchars); 541} 542 543static void drawTextOnPathChars(JNIEnv* env, jobject, jlong canvasHandle, jcharArray text, 544 jint index, jint count, jlong pathHandle, jfloat hOffset, 545 jfloat vOffset, jint bidiFlags, jlong paintHandle, 546 jlong typefaceHandle) { 547 SkPath* path = reinterpret_cast<SkPath*>(pathHandle); 548 Paint* paint = reinterpret_cast<Paint*>(paintHandle); 549 Typeface* typeface = reinterpret_cast<Typeface*>(typefaceHandle); 550 551 jchar* jchars = env->GetCharArrayElements(text, NULL); 552 553 get_canvas(canvasHandle)->drawTextOnPath(jchars + index, count, bidiFlags, *path, 554 hOffset, vOffset, *paint, typeface); 555 556 env->ReleaseCharArrayElements(text, jchars, 0); 557} 558 559static void drawTextOnPathString(JNIEnv* env, jobject, jlong canvasHandle, jstring text, 560 jlong pathHandle, jfloat hOffset, jfloat vOffset, 561 jint bidiFlags, jlong paintHandle, jlong typefaceHandle) { 562 SkPath* path = reinterpret_cast<SkPath*>(pathHandle); 563 Paint* paint = reinterpret_cast<Paint*>(paintHandle); 564 Typeface* typeface = reinterpret_cast<Typeface*>(typefaceHandle); 565 566 const jchar* jchars = env->GetStringChars(text, NULL); 567 int count = env->GetStringLength(text); 568 569 get_canvas(canvasHandle)->drawTextOnPath(jchars, count, bidiFlags, *path, 570 hOffset, vOffset, *paint, typeface); 571 572 env->ReleaseStringChars(text, jchars); 573} 574 575static void setDrawFilter(JNIEnv* env, jobject, jlong canvasHandle, jlong filterHandle) { 576 get_canvas(canvasHandle)->setDrawFilter(reinterpret_cast<SkDrawFilter*>(filterHandle)); 577} 578 579static void freeCaches(JNIEnv* env, jobject) { 580 SkGraphics::PurgeFontCache(); 581} 582 583static void freeTextLayoutCaches(JNIEnv* env, jobject) { 584 minikin::Layout::purgeCaches(); 585} 586 587}; // namespace CanvasJNI 588 589static const JNINativeMethod gMethods[] = { 590 {"nGetNativeFinalizer", "()J", (void*) CanvasJNI::getNativeFinalizer}, 591 {"nInitRaster", "(Landroid/graphics/Bitmap;)J", (void*) CanvasJNI::initRaster}, 592 {"nFreeCaches", "()V", (void*) CanvasJNI::freeCaches}, 593 {"nFreeTextLayoutCaches", "()V", (void*) CanvasJNI::freeTextLayoutCaches}, 594 595 // ------------ @FastNative ---------------- 596 {"nSetBitmap", "(JLandroid/graphics/Bitmap;)V", (void*) CanvasJNI::setBitmap}, 597 {"nIsOpaque","(J)Z", (void*) CanvasJNI::isOpaque}, 598 {"nGetWidth","(J)I", (void*) CanvasJNI::getWidth}, 599 {"nGetHeight","(J)I", (void*) CanvasJNI::getHeight}, 600 {"nSetHighContrastText","(JZ)V", (void*) CanvasJNI::setHighContrastText}, 601 {"nSave","(JI)I", (void*) CanvasJNI::save}, 602 {"nSaveLayer","(JFFFFJI)I", (void*) CanvasJNI::saveLayer}, 603 {"nSaveLayerAlpha","(JFFFFII)I", (void*) CanvasJNI::saveLayerAlpha}, 604 {"nGetSaveCount","(J)I", (void*) CanvasJNI::getSaveCount}, 605 {"nRestore","(JZ)V", (void*) CanvasJNI::restore}, 606 {"nRestoreToCount","(JIZ)V", (void*) CanvasJNI::restoreToCount}, 607 {"nGetCTM", "(JJ)V", (void*)CanvasJNI::getCTM}, 608 {"nSetMatrix","(JJ)V", (void*) CanvasJNI::setMatrix}, 609 {"nConcat","(JJ)V", (void*) CanvasJNI::concat}, 610 {"nRotate","(JF)V", (void*) CanvasJNI::rotate}, 611 {"nScale","(JFF)V", (void*) CanvasJNI::scale}, 612 {"nSkew","(JFF)V", (void*) CanvasJNI::skew}, 613 {"nTranslate","(JFF)V", (void*) CanvasJNI::translate}, 614 {"nGetClipBounds","(JLandroid/graphics/Rect;)Z", (void*) CanvasJNI::getClipBounds}, 615 {"nQuickReject","(JJ)Z", (void*) CanvasJNI::quickRejectPath}, 616 {"nQuickReject","(JFFFF)Z", (void*)CanvasJNI::quickRejectRect}, 617 {"nClipRect","(JFFFFI)Z", (void*) CanvasJNI::clipRect}, 618 {"nClipPath","(JJI)Z", (void*) CanvasJNI::clipPath}, 619 {"nClipRegion","(JJI)Z", (void*) CanvasJNI::clipRegion}, 620 {"nSetDrawFilter", "(JJ)V", (void*) CanvasJNI::setDrawFilter}, 621}; 622 623// If called from Canvas these are regular JNI 624// If called from DisplayListCanvas they are @FastNative 625static const JNINativeMethod gDrawMethods[] = { 626 {"nDrawColor","(JII)V", (void*) CanvasJNI::drawColor}, 627 {"nDrawPaint","(JJ)V", (void*) CanvasJNI::drawPaint}, 628 {"nDrawPoint", "(JFFJ)V", (void*) CanvasJNI::drawPoint}, 629 {"nDrawPoints", "(J[FIIJ)V", (void*) CanvasJNI::drawPoints}, 630 {"nDrawLine", "(JFFFFJ)V", (void*) CanvasJNI::drawLine}, 631 {"nDrawLines", "(J[FIIJ)V", (void*) CanvasJNI::drawLines}, 632 {"nDrawRect","(JFFFFJ)V", (void*) CanvasJNI::drawRect}, 633 {"nDrawRegion", "(JJJ)V", (void*) CanvasJNI::drawRegion }, 634 {"nDrawRoundRect","(JFFFFFFJ)V", (void*) CanvasJNI::drawRoundRect}, 635 {"nDrawCircle","(JFFFJ)V", (void*) CanvasJNI::drawCircle}, 636 {"nDrawOval","(JFFFFJ)V", (void*) CanvasJNI::drawOval}, 637 {"nDrawArc","(JFFFFFFZJ)V", (void*) CanvasJNI::drawArc}, 638 {"nDrawPath","(JJJ)V", (void*) CanvasJNI::drawPath}, 639 {"nDrawVertices", "(JII[FI[FI[II[SIIJ)V", (void*)CanvasJNI::drawVertices}, 640 {"nDrawNinePatch", "(JJJFFFFJII)V", (void*)CanvasJNI::drawNinePatch}, 641 {"nDrawBitmapMatrix", "(JLandroid/graphics/Bitmap;JJ)V", (void*)CanvasJNI::drawBitmapMatrix}, 642 {"nDrawBitmapMesh", "(JLandroid/graphics/Bitmap;II[FI[IIJ)V", (void*)CanvasJNI::drawBitmapMesh}, 643 {"nDrawBitmap","(JLandroid/graphics/Bitmap;FFJIII)V", (void*) CanvasJNI::drawBitmap}, 644 {"nDrawBitmap","(JLandroid/graphics/Bitmap;FFFFFFFFJII)V", (void*) CanvasJNI::drawBitmapRect}, 645 {"nDrawBitmap", "(J[IIIFFIIZJ)V", (void*)CanvasJNI::drawBitmapArray}, 646 {"nDrawText","(J[CIIFFIJJ)V", (void*) CanvasJNI::drawTextChars}, 647 {"nDrawText","(JLjava/lang/String;IIFFIJJ)V", (void*) CanvasJNI::drawTextString}, 648 {"nDrawTextRun","(J[CIIIIFFZJJ)V", (void*) CanvasJNI::drawTextRunChars}, 649 {"nDrawTextRun","(JLjava/lang/String;IIIIFFZJJ)V", (void*) CanvasJNI::drawTextRunString}, 650 {"nDrawTextOnPath","(J[CIIJFFIJJ)V", (void*) CanvasJNI::drawTextOnPathChars}, 651 {"nDrawTextOnPath","(JLjava/lang/String;JFFIJJ)V", (void*) CanvasJNI::drawTextOnPathString}, 652}; 653 654int register_android_graphics_Canvas(JNIEnv* env) { 655 int ret = 0; 656 ret |= RegisterMethodsOrDie(env, "android/graphics/Canvas", gMethods, NELEM(gMethods)); 657 ret |= RegisterMethodsOrDie(env, "android/graphics/BaseCanvas", gDrawMethods, NELEM(gDrawMethods)); 658 ret |= RegisterMethodsOrDie(env, "android/view/RecordingCanvas", gDrawMethods, NELEM(gDrawMethods)); 659 return ret; 660 661} 662 663}; // namespace android 664