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