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