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