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