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