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