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