android_graphics_Canvas.cpp revision 1ff961dd6d51247e82e41de052f04fd0b577f09b
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 emptyClip = get_canvas(canvasHandle)->clipRect(l, t, r, b, op); 179 return emptyClip ? JNI_FALSE : JNI_TRUE; 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 emptyClip = get_canvas(canvasHandle)->clipPath(path, op); 187 return emptyClip ? JNI_FALSE : JNI_TRUE; 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 emptyClip = get_canvas(canvasHandle)->clipRegion(deviceRgn, op); 195 return emptyClip ? JNI_FALSE : JNI_TRUE; 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 drawRoundRect(JNIEnv* env, jobject, jlong canvasHandle, jfloat left, jfloat top, 259 jfloat right, jfloat bottom, jfloat rx, jfloat ry, jlong paintHandle) { 260 const Paint* paint = reinterpret_cast<Paint*>(paintHandle); 261 get_canvas(canvasHandle)->drawRoundRect(left, top, right, bottom, rx, ry, *paint); 262} 263 264static void drawCircle(JNIEnv* env, jobject, jlong canvasHandle, jfloat cx, jfloat cy, 265 jfloat radius, jlong paintHandle) { 266 const Paint* paint = reinterpret_cast<Paint*>(paintHandle); 267 get_canvas(canvasHandle)->drawCircle(cx, cy, radius, *paint); 268} 269 270static void drawOval(JNIEnv* env, jobject, jlong canvasHandle, jfloat left, jfloat top, 271 jfloat right, jfloat bottom, jlong paintHandle) { 272 const Paint* paint = reinterpret_cast<Paint*>(paintHandle); 273 get_canvas(canvasHandle)->drawOval(left, top, right, bottom, *paint); 274} 275 276static void drawArc(JNIEnv* env, jobject, jlong canvasHandle, jfloat left, jfloat top, 277 jfloat right, jfloat bottom, jfloat startAngle, jfloat sweepAngle, 278 jboolean useCenter, jlong paintHandle) { 279 const Paint* paint = reinterpret_cast<Paint*>(paintHandle); 280 get_canvas(canvasHandle)->drawArc(left, top, right, bottom, startAngle, sweepAngle, 281 useCenter, *paint); 282} 283 284static void drawPath(JNIEnv* env, jobject, jlong canvasHandle, jlong pathHandle, 285 jlong paintHandle) { 286 const SkPath* path = reinterpret_cast<SkPath*>(pathHandle); 287 const Paint* paint = reinterpret_cast<Paint*>(paintHandle); 288 get_canvas(canvasHandle)->drawPath(*path, *paint); 289} 290 291static void drawVertices(JNIEnv* env, jobject, jlong canvasHandle, 292 jint modeHandle, jint vertexCount, 293 jfloatArray jverts, jint vertIndex, 294 jfloatArray jtexs, jint texIndex, 295 jintArray jcolors, jint colorIndex, 296 jshortArray jindices, jint indexIndex, 297 jint indexCount, jlong paintHandle) { 298 AutoJavaFloatArray vertA(env, jverts, vertIndex + vertexCount); 299 AutoJavaFloatArray texA(env, jtexs, texIndex + vertexCount); 300 AutoJavaIntArray colorA(env, jcolors, colorIndex + vertexCount); 301 AutoJavaShortArray indexA(env, jindices, indexIndex + indexCount); 302 303 const float* verts = vertA.ptr() + vertIndex; 304 const float* texs = texA.ptr() + vertIndex; 305 const int* colors = NULL; 306 const uint16_t* indices = NULL; 307 308 if (jcolors != NULL) { 309 colors = colorA.ptr() + colorIndex; 310 } 311 if (jindices != NULL) { 312 indices = (const uint16_t*)(indexA.ptr() + indexIndex); 313 } 314 315 SkCanvas::VertexMode mode = static_cast<SkCanvas::VertexMode>(modeHandle); 316 const Paint* paint = reinterpret_cast<Paint*>(paintHandle); 317 get_canvas(canvasHandle)->drawVertices(mode, vertexCount, verts, texs, colors, 318 indices, indexCount, *paint); 319} 320 321static void drawBitmap(JNIEnv* env, jobject jcanvas, jlong canvasHandle, jlong bitmapHandle, 322 jfloat left, jfloat top, jlong paintHandle, jint canvasDensity, 323 jint screenDensity, jint bitmapDensity) { 324 Canvas* canvas = get_canvas(canvasHandle); 325 const SkBitmap* bitmap = reinterpret_cast<SkBitmap*>(bitmapHandle); 326 const Paint* paint = reinterpret_cast<Paint*>(paintHandle); 327 328 if (canvasDensity == bitmapDensity || canvasDensity == 0 || bitmapDensity == 0) { 329 if (screenDensity != 0 && screenDensity != bitmapDensity) { 330 Paint filteredPaint; 331 if (paint) { 332 filteredPaint = *paint; 333 } 334 filteredPaint.setFilterQuality(kLow_SkFilterQuality); 335 canvas->drawBitmap(*bitmap, left, top, &filteredPaint); 336 } else { 337 canvas->drawBitmap(*bitmap, left, top, paint); 338 } 339 } else { 340 canvas->save(SkCanvas::kMatrixClip_SaveFlag); 341 SkScalar scale = canvasDensity / (float)bitmapDensity; 342 canvas->translate(left, top); 343 canvas->scale(scale, scale); 344 345 Paint filteredPaint; 346 if (paint) { 347 filteredPaint = *paint; 348 } 349 filteredPaint.setFilterQuality(kLow_SkFilterQuality); 350 351 canvas->drawBitmap(*bitmap, 0, 0, &filteredPaint); 352 canvas->restore(); 353 } 354} 355 356static void drawBitmapMatrix(JNIEnv* env, jobject, jlong canvasHandle, jlong bitmapHandle, 357 jlong matrixHandle, jlong paintHandle) { 358 const SkBitmap* bitmap = reinterpret_cast<SkBitmap*>(bitmapHandle); 359 const SkMatrix* matrix = reinterpret_cast<SkMatrix*>(matrixHandle); 360 const Paint* paint = reinterpret_cast<Paint*>(paintHandle); 361 get_canvas(canvasHandle)->drawBitmap(*bitmap, *matrix, paint); 362} 363 364static void drawBitmapRect(JNIEnv* env, jobject, jlong canvasHandle, jlong bitmapHandle, 365 float srcLeft, float srcTop, float srcRight, float srcBottom, 366 float dstLeft, float dstTop, float dstRight, float dstBottom, 367 jlong paintHandle, jint screenDensity, jint bitmapDensity) { 368 Canvas* canvas = get_canvas(canvasHandle); 369 const SkBitmap* bitmap = reinterpret_cast<SkBitmap*>(bitmapHandle); 370 const Paint* paint = reinterpret_cast<Paint*>(paintHandle); 371 372 if (screenDensity != 0 && screenDensity != bitmapDensity) { 373 Paint filteredPaint; 374 if (paint) { 375 filteredPaint = *paint; 376 } 377 filteredPaint.setFilterQuality(kLow_SkFilterQuality); 378 canvas->drawBitmap(*bitmap, srcLeft, srcTop, srcRight, srcBottom, 379 dstLeft, dstTop, dstRight, dstBottom, &filteredPaint); 380 } else { 381 canvas->drawBitmap(*bitmap, srcLeft, srcTop, srcRight, srcBottom, 382 dstLeft, dstTop, dstRight, dstBottom, paint); 383 } 384} 385 386static void drawBitmapArray(JNIEnv* env, jobject, jlong canvasHandle, 387 jintArray jcolors, jint offset, jint stride, 388 jfloat x, jfloat y, jint width, jint height, 389 jboolean hasAlpha, jlong paintHandle) { 390 // Note: If hasAlpha is false, kRGB_565_SkColorType will be used, which will 391 // correct the alphaType to kOpaque_SkAlphaType. 392 SkImageInfo info = SkImageInfo::Make(width, height, 393 hasAlpha ? kN32_SkColorType : kRGB_565_SkColorType, 394 kPremul_SkAlphaType); 395 SkBitmap bitmap; 396 bitmap.setInfo(info); 397 if (!GraphicsJNI::allocatePixels(env, &bitmap, NULL)) { 398 return; 399 } 400 401 if (!GraphicsJNI::SetPixels(env, jcolors, offset, stride, 0, 0, width, height, bitmap)) { 402 return; 403 } 404 405 const Paint* paint = reinterpret_cast<Paint*>(paintHandle); 406 get_canvas(canvasHandle)->drawBitmap(bitmap, x, y, paint); 407} 408 409static void drawBitmapMesh(JNIEnv* env, jobject, jlong canvasHandle, jlong bitmapHandle, 410 jint meshWidth, jint meshHeight, jfloatArray jverts, 411 jint vertIndex, jintArray jcolors, jint colorIndex, jlong paintHandle) { 412 const int ptCount = (meshWidth + 1) * (meshHeight + 1); 413 AutoJavaFloatArray vertA(env, jverts, vertIndex + (ptCount << 1)); 414 AutoJavaIntArray colorA(env, jcolors, colorIndex + ptCount); 415 416 const SkBitmap* bitmap = reinterpret_cast<SkBitmap*>(bitmapHandle); 417 const Paint* paint = reinterpret_cast<Paint*>(paintHandle); 418 get_canvas(canvasHandle)->drawBitmapMesh(*bitmap, meshWidth, meshHeight, 419 vertA.ptr(), colorA.ptr(), paint); 420} 421 422class DrawTextFunctor { 423public: 424 DrawTextFunctor(const Layout& layout, Canvas* canvas, uint16_t* glyphs, float* pos, 425 const SkPaint& paint, float x, float y, MinikinRect& bounds, 426 float totalAdvance) 427 : layout(layout), canvas(canvas), glyphs(glyphs), pos(pos), paint(paint), 428 x(x), y(y), bounds(bounds), totalAdvance(totalAdvance) { } 429 430 void operator()(size_t start, size_t end) { 431 if (canvas->drawTextAbsolutePos()) { 432 for (size_t i = start; i < end; i++) { 433 glyphs[i] = layout.getGlyphId(i); 434 pos[2 * i] = x + layout.getX(i); 435 pos[2 * i + 1] = y + layout.getY(i); 436 } 437 } else { 438 for (size_t i = start; i < end; i++) { 439 glyphs[i] = layout.getGlyphId(i); 440 pos[2 * i] = layout.getX(i); 441 pos[2 * i + 1] = layout.getY(i); 442 } 443 } 444 445 size_t glyphCount = end - start; 446 canvas->drawText(glyphs + start, pos + (2 * start), glyphCount, paint, x, y, 447 bounds.mLeft, bounds.mTop, bounds.mRight, bounds.mBottom, 448 totalAdvance); 449 } 450private: 451 const Layout& layout; 452 Canvas* canvas; 453 uint16_t* glyphs; 454 float* pos; 455 const SkPaint& paint; 456 float x; 457 float y; 458 MinikinRect& bounds; 459 float totalAdvance; 460}; 461 462// Same values used by Skia 463#define kStdStrikeThru_Offset (-6.0f / 21.0f) 464#define kStdUnderline_Offset (1.0f / 9.0f) 465#define kStdUnderline_Thickness (1.0f / 18.0f) 466 467void drawTextDecorations(Canvas* canvas, float x, float y, float length, const SkPaint& paint) { 468 uint32_t flags; 469 SkDrawFilter* drawFilter = canvas->getDrawFilter(); 470 if (drawFilter) { 471 SkPaint paintCopy(paint); 472 drawFilter->filter(&paintCopy, SkDrawFilter::kText_Type); 473 flags = paintCopy.getFlags(); 474 } else { 475 flags = paint.getFlags(); 476 } 477 if (flags & (SkPaint::kUnderlineText_Flag | SkPaint::kStrikeThruText_Flag)) { 478 SkScalar left = x; 479 SkScalar right = x + length; 480 float textSize = paint.getTextSize(); 481 float strokeWidth = fmax(textSize * kStdUnderline_Thickness, 1.0f); 482 if (flags & SkPaint::kUnderlineText_Flag) { 483 SkScalar top = y + textSize * kStdUnderline_Offset - 0.5f * strokeWidth; 484 SkScalar bottom = y + textSize * kStdUnderline_Offset + 0.5f * strokeWidth; 485 canvas->drawRect(left, top, right, bottom, paint); 486 } 487 if (flags & SkPaint::kStrikeThruText_Flag) { 488 SkScalar top = y + textSize * kStdStrikeThru_Offset - 0.5f * strokeWidth; 489 SkScalar bottom = y + textSize * kStdStrikeThru_Offset + 0.5f * strokeWidth; 490 canvas->drawRect(left, top, right, bottom, paint); 491 } 492 } 493} 494 495void drawText(Canvas* canvas, const uint16_t* text, int start, int count, int contextCount, 496 float x, float y, int bidiFlags, const Paint& origPaint, TypefaceImpl* typeface) { 497 // minikin may modify the original paint 498 Paint paint(origPaint); 499 500 Layout layout; 501 MinikinUtils::doLayout(&layout, &paint, bidiFlags, typeface, text, start, count, contextCount); 502 503 size_t nGlyphs = layout.nGlyphs(); 504 uint16_t* glyphs = new uint16_t[nGlyphs]; 505 float* pos = new float[nGlyphs * 2]; 506 507 x += MinikinUtils::xOffsetForTextAlign(&paint, layout); 508 509 MinikinRect bounds; 510 layout.getBounds(&bounds); 511 if (!canvas->drawTextAbsolutePos()) { 512 bounds.offset(x, y); 513 } 514 515 DrawTextFunctor f(layout, canvas, glyphs, pos, paint, x, y, bounds, layout.getAdvance()); 516 MinikinUtils::forFontRun(layout, &paint, f); 517 518 drawTextDecorations(canvas, x, y, layout.getAdvance(), paint); 519 520 delete[] glyphs; 521 delete[] pos; 522} 523 524static void drawTextChars(JNIEnv* env, jobject, jlong canvasHandle, jcharArray text, 525 jint index, jint count, jfloat x, jfloat y, jint bidiFlags, 526 jlong paintHandle, jlong typefaceHandle) { 527 Paint* paint = reinterpret_cast<Paint*>(paintHandle); 528 TypefaceImpl* typeface = reinterpret_cast<TypefaceImpl*>(typefaceHandle); 529 jchar* jchars = env->GetCharArrayElements(text, NULL); 530 drawText(get_canvas(canvasHandle), jchars + index, 0, count, count, x, y, 531 bidiFlags, *paint, typeface); 532 env->ReleaseCharArrayElements(text, jchars, JNI_ABORT); 533} 534 535static void drawTextString(JNIEnv* env, jobject, jlong canvasHandle, jstring text, 536 jint start, jint end, 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 const int count = end - start; 541 const jchar* jchars = env->GetStringChars(text, NULL); 542 drawText(get_canvas(canvasHandle), jchars + start, 0, count, count, x, y, 543 bidiFlags, *paint, typeface); 544 env->ReleaseStringChars(text, jchars); 545} 546 547static void drawTextRunChars(JNIEnv* env, jobject, jlong canvasHandle, jcharArray text, jint index, 548 jint count, jint contextIndex, jint contextCount, jfloat x, jfloat y, 549 jboolean isRtl, jlong paintHandle, jlong typefaceHandle) { 550 Paint* paint = reinterpret_cast<Paint*>(paintHandle); 551 TypefaceImpl* typeface = reinterpret_cast<TypefaceImpl*>(typefaceHandle); 552 553 const int bidiFlags = isRtl ? kBidi_Force_RTL : kBidi_Force_LTR; 554 jchar* jchars = env->GetCharArrayElements(text, NULL); 555 drawText(get_canvas(canvasHandle), jchars + contextIndex, index - contextIndex, count, 556 contextCount, x, y, bidiFlags, *paint, typeface); 557 env->ReleaseCharArrayElements(text, jchars, JNI_ABORT); 558} 559 560static void drawTextRunString(JNIEnv* env, jobject obj, jlong canvasHandle, jstring text, 561 jint start, jint end, jint contextStart, jint contextEnd, 562 jfloat x, jfloat y, jboolean isRtl, jlong paintHandle, 563 jlong typefaceHandle) { 564 Paint* paint = reinterpret_cast<Paint*>(paintHandle); 565 TypefaceImpl* typeface = reinterpret_cast<TypefaceImpl*>(typefaceHandle); 566 567 int bidiFlags = isRtl ? kBidi_Force_RTL : kBidi_Force_LTR; 568 jint count = end - start; 569 jint contextCount = contextEnd - contextStart; 570 const jchar* jchars = env->GetStringChars(text, NULL); 571 drawText(get_canvas(canvasHandle), jchars + contextStart, start - contextStart, count, 572 contextCount, x, y, bidiFlags, *paint, typeface); 573 env->ReleaseStringChars(text, jchars); 574} 575 576class DrawTextOnPathFunctor { 577public: 578 DrawTextOnPathFunctor(const Layout& layout, Canvas* canvas, float hOffset, 579 float vOffset, const Paint& paint, const SkPath& path) 580 : layout(layout), canvas(canvas), hOffset(hOffset), vOffset(vOffset), 581 paint(paint), path(path) { 582 } 583 void operator()(size_t start, size_t end) { 584 uint16_t glyphs[1]; 585 for (size_t i = start; i < end; i++) { 586 glyphs[0] = layout.getGlyphId(i); 587 float x = hOffset + layout.getX(i); 588 float y = vOffset + layout.getY(i); 589 canvas->drawTextOnPath(glyphs, 1, path, x, y, paint); 590 } 591 } 592private: 593 const Layout& layout; 594 Canvas* canvas; 595 float hOffset; 596 float vOffset; 597 const Paint& paint; 598 const SkPath& path; 599}; 600 601static void drawTextOnPath(Canvas* canvas, const uint16_t* text, int count, int bidiFlags, 602 const SkPath& path, float hOffset, float vOffset, 603 const Paint& paint, TypefaceImpl* typeface) { 604 Paint paintCopy(paint); 605 Layout layout; 606 MinikinUtils::doLayout(&layout, &paintCopy, bidiFlags, typeface, text, 0, count, count); 607 hOffset += MinikinUtils::hOffsetForTextAlign(&paintCopy, layout, path); 608 609 // Set align to left for drawing, as we don't want individual 610 // glyphs centered or right-aligned; the offset above takes 611 // care of all alignment. 612 paintCopy.setTextAlign(Paint::kLeft_Align); 613 614 DrawTextOnPathFunctor f(layout, canvas, hOffset, vOffset, paintCopy, path); 615 MinikinUtils::forFontRun(layout, &paintCopy, f); 616} 617 618static void drawTextOnPathChars(JNIEnv* env, jobject, jlong canvasHandle, jcharArray text, 619 jint index, jint count, jlong pathHandle, jfloat hOffset, 620 jfloat vOffset, jint bidiFlags, jlong paintHandle, 621 jlong typefaceHandle) { 622 SkPath* path = reinterpret_cast<SkPath*>(pathHandle); 623 Paint* paint = reinterpret_cast<Paint*>(paintHandle); 624 TypefaceImpl* typeface = reinterpret_cast<TypefaceImpl*>(typefaceHandle); 625 626 jchar* jchars = env->GetCharArrayElements(text, NULL); 627 628 drawTextOnPath(get_canvas(canvasHandle), jchars + index, count, bidiFlags, *path, 629 hOffset, vOffset, *paint, typeface); 630 631 env->ReleaseCharArrayElements(text, jchars, 0); 632} 633 634static void drawTextOnPathString(JNIEnv* env, jobject, jlong canvasHandle, jstring text, 635 jlong pathHandle, jfloat hOffset, jfloat vOffset, 636 jint bidiFlags, jlong paintHandle, jlong typefaceHandle) { 637 SkPath* path = reinterpret_cast<SkPath*>(pathHandle); 638 Paint* paint = reinterpret_cast<Paint*>(paintHandle); 639 TypefaceImpl* typeface = reinterpret_cast<TypefaceImpl*>(typefaceHandle); 640 641 const jchar* jchars = env->GetStringChars(text, NULL); 642 int count = env->GetStringLength(text); 643 644 drawTextOnPath(get_canvas(canvasHandle), jchars, count, bidiFlags, *path, 645 hOffset, vOffset, *paint, typeface); 646 647 env->ReleaseStringChars(text, jchars); 648} 649 650static void setDrawFilter(JNIEnv* env, jobject, jlong canvasHandle, jlong filterHandle) { 651 get_canvas(canvasHandle)->setDrawFilter(reinterpret_cast<SkDrawFilter*>(filterHandle)); 652} 653 654static void freeCaches(JNIEnv* env, jobject) { 655 SkGraphics::PurgeFontCache(); 656} 657 658static void freeTextLayoutCaches(JNIEnv* env, jobject) { 659 Layout::purgeCaches(); 660} 661 662}; // namespace CanvasJNI 663 664static JNINativeMethod gMethods[] = { 665 {"finalizer", "(J)V", (void*) CanvasJNI::finalizer}, 666 {"initRaster", "(Landroid/graphics/Bitmap;)J", (void*) CanvasJNI::initRaster}, 667 {"native_setBitmap", "(JLandroid/graphics/Bitmap;)V", (void*) CanvasJNI::setBitmap}, 668 {"native_isOpaque","(J)Z", (void*) CanvasJNI::isOpaque}, 669 {"native_getWidth","(J)I", (void*) CanvasJNI::getWidth}, 670 {"native_getHeight","(J)I", (void*) CanvasJNI::getHeight}, 671 {"native_save","(JI)I", (void*) CanvasJNI::save}, 672 {"native_saveLayer","(JFFFFJI)I", (void*) CanvasJNI::saveLayer}, 673 {"native_saveLayerAlpha","(JFFFFII)I", (void*) CanvasJNI::saveLayerAlpha}, 674 {"native_getSaveCount","(J)I", (void*) CanvasJNI::getSaveCount}, 675 {"native_restore","(JZ)V", (void*) CanvasJNI::restore}, 676 {"native_restoreToCount","(JIZ)V", (void*) CanvasJNI::restoreToCount}, 677 {"native_getCTM", "(JJ)V", (void*)CanvasJNI::getCTM}, 678 {"native_setMatrix","(JJ)V", (void*) CanvasJNI::setMatrix}, 679 {"native_concat","(JJ)V", (void*) CanvasJNI::concat}, 680 {"native_rotate","(JF)V", (void*) CanvasJNI::rotate}, 681 {"native_scale","(JFF)V", (void*) CanvasJNI::scale}, 682 {"native_skew","(JFF)V", (void*) CanvasJNI::skew}, 683 {"native_translate","(JFF)V", (void*) CanvasJNI::translate}, 684 {"native_getClipBounds","(JLandroid/graphics/Rect;)Z", (void*) CanvasJNI::getClipBounds}, 685 {"native_quickReject","(JJ)Z", (void*) CanvasJNI::quickRejectPath}, 686 {"native_quickReject","(JFFFF)Z", (void*)CanvasJNI::quickRejectRect}, 687 {"native_clipRect","(JFFFFI)Z", (void*) CanvasJNI::clipRect}, 688 {"native_clipPath","(JJI)Z", (void*) CanvasJNI::clipPath}, 689 {"native_clipRegion","(JJI)Z", (void*) CanvasJNI::clipRegion}, 690 {"native_drawColor","(JII)V", (void*) CanvasJNI::drawColor}, 691 {"native_drawPaint","(JJ)V", (void*) CanvasJNI::drawPaint}, 692 {"native_drawPoint", "(JFFJ)V", (void*) CanvasJNI::drawPoint}, 693 {"native_drawPoints", "(J[FIIJ)V", (void*) CanvasJNI::drawPoints}, 694 {"native_drawLine", "(JFFFFJ)V", (void*) CanvasJNI::drawLine}, 695 {"native_drawLines", "(J[FIIJ)V", (void*) CanvasJNI::drawLines}, 696 {"native_drawRect","(JFFFFJ)V", (void*) CanvasJNI::drawRect}, 697 {"native_drawRoundRect","(JFFFFFFJ)V", (void*) CanvasJNI::drawRoundRect}, 698 {"native_drawCircle","(JFFFJ)V", (void*) CanvasJNI::drawCircle}, 699 {"native_drawOval","(JFFFFJ)V", (void*) CanvasJNI::drawOval}, 700 {"native_drawArc","(JFFFFFFZJ)V", (void*) CanvasJNI::drawArc}, 701 {"native_drawPath","(JJJ)V", (void*) CanvasJNI::drawPath}, 702 {"nativeDrawVertices", "(JII[FI[FI[II[SIIJ)V", (void*)CanvasJNI::drawVertices}, 703 {"native_drawBitmap","(JJFFJIII)V", (void*) CanvasJNI::drawBitmap}, 704 {"nativeDrawBitmapMatrix", "(JJJJ)V", (void*)CanvasJNI::drawBitmapMatrix}, 705 {"native_drawBitmap","(JJFFFFFFFFJII)V", (void*) CanvasJNI::drawBitmapRect}, 706 {"native_drawBitmap", "(J[IIIFFIIZJ)V", (void*)CanvasJNI::drawBitmapArray}, 707 {"nativeDrawBitmapMesh", "(JJII[FI[IIJ)V", (void*)CanvasJNI::drawBitmapMesh}, 708 {"native_drawText","(J[CIIFFIJJ)V", (void*) CanvasJNI::drawTextChars}, 709 {"native_drawText","(JLjava/lang/String;IIFFIJJ)V", (void*) CanvasJNI::drawTextString}, 710 {"native_drawTextRun","(J[CIIIIFFZJJ)V", (void*) CanvasJNI::drawTextRunChars}, 711 {"native_drawTextRun","(JLjava/lang/String;IIIIFFZJJ)V", (void*) CanvasJNI::drawTextRunString}, 712 {"native_drawTextOnPath","(J[CIIJFFIJJ)V", (void*) CanvasJNI::drawTextOnPathChars}, 713 {"native_drawTextOnPath","(JLjava/lang/String;JFFIJJ)V", (void*) CanvasJNI::drawTextOnPathString}, 714 {"nativeSetDrawFilter", "(JJ)V", (void*) CanvasJNI::setDrawFilter}, 715 {"freeCaches", "()V", (void*) CanvasJNI::freeCaches}, 716 {"freeTextLayoutCaches", "()V", (void*) CanvasJNI::freeTextLayoutCaches} 717}; 718 719int register_android_graphics_Canvas(JNIEnv* env) { 720 return RegisterMethodsOrDie(env, "android/graphics/Canvas", gMethods, NELEM(gMethods)); 721} 722 723}; // namespace android 724