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