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