android_graphics_Canvas.cpp revision 63c5c78a72a21d57913e8601cc2a1ab72a424a02
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 MinikinUtils::doLayout(&layout, &paint, bidiFlags, typeface, text, start, count, contextCount); 490 491 size_t nGlyphs = layout.nGlyphs(); 492 uint16_t* glyphs = new uint16_t[nGlyphs]; 493 float* pos = new float[nGlyphs * 2]; 494 495 x += MinikinUtils::xOffsetForTextAlign(&paint, layout); 496 497 MinikinRect bounds; 498 layout.getBounds(&bounds); 499 500 DrawTextFunctor f(layout, canvas, glyphs, pos, paint, x, y, bounds); 501 MinikinUtils::forFontRun(layout, &paint, f); 502 503 drawTextDecorations(canvas, x, y, layout.getAdvance(), paint); 504 505 delete[] glyphs; 506 delete[] pos; 507} 508 509static void drawTextChars(JNIEnv* env, jobject, jlong canvasHandle, jcharArray text, 510 jint index, jint count, jfloat x, jfloat y, jint bidiFlags, 511 jlong paintHandle, jlong typefaceHandle) { 512 Paint* paint = reinterpret_cast<Paint*>(paintHandle); 513 TypefaceImpl* typeface = reinterpret_cast<TypefaceImpl*>(typefaceHandle); 514 jchar* jchars = env->GetCharArrayElements(text, NULL); 515 drawText(get_canvas(canvasHandle), jchars + index, 0, count, count, x, y, 516 bidiFlags, *paint, typeface); 517 env->ReleaseCharArrayElements(text, jchars, JNI_ABORT); 518} 519 520static void drawTextString(JNIEnv* env, jobject, jlong canvasHandle, jstring text, 521 jint start, jint end, jfloat x, jfloat y, jint bidiFlags, 522 jlong paintHandle, jlong typefaceHandle) { 523 Paint* paint = reinterpret_cast<Paint*>(paintHandle); 524 TypefaceImpl* typeface = reinterpret_cast<TypefaceImpl*>(typefaceHandle); 525 const int count = end - start; 526 const jchar* jchars = env->GetStringChars(text, NULL); 527 drawText(get_canvas(canvasHandle), jchars + start, 0, count, count, x, y, 528 bidiFlags, *paint, typeface); 529 env->ReleaseStringChars(text, jchars); 530} 531 532static void drawTextRunChars(JNIEnv* env, jobject, jlong canvasHandle, jcharArray text, jint index, 533 jint count, jint contextIndex, jint contextCount, jfloat x, jfloat y, 534 jboolean isRtl, jlong paintHandle, jlong typefaceHandle) { 535 Paint* paint = reinterpret_cast<Paint*>(paintHandle); 536 TypefaceImpl* typeface = reinterpret_cast<TypefaceImpl*>(typefaceHandle); 537 538 const int bidiFlags = isRtl ? kBidi_Force_RTL : kBidi_Force_LTR; 539 jchar* jchars = env->GetCharArrayElements(text, NULL); 540 drawText(get_canvas(canvasHandle), jchars + contextIndex, index - contextIndex, count, 541 contextCount, x, y, bidiFlags, *paint, typeface); 542 env->ReleaseCharArrayElements(text, jchars, JNI_ABORT); 543} 544 545static void drawTextRunString(JNIEnv* env, jobject obj, jlong canvasHandle, jstring text, 546 jint start, jint end, jint contextStart, jint contextEnd, 547 jfloat x, jfloat y, jboolean isRtl, jlong paintHandle, 548 jlong typefaceHandle) { 549 Paint* paint = reinterpret_cast<Paint*>(paintHandle); 550 TypefaceImpl* typeface = reinterpret_cast<TypefaceImpl*>(typefaceHandle); 551 552 int bidiFlags = isRtl ? kBidi_Force_RTL : kBidi_Force_LTR; 553 jint count = end - start; 554 jint contextCount = contextEnd - contextStart; 555 const jchar* jchars = env->GetStringChars(text, NULL); 556 drawText(get_canvas(canvasHandle), jchars + contextStart, start - contextStart, count, 557 contextCount, x, y, bidiFlags, *paint, typeface); 558 env->ReleaseStringChars(text, jchars); 559} 560 561static void drawPosTextChars(JNIEnv* env, jobject, jlong canvasHandle, jcharArray text, 562 jint index, jint count, jfloatArray pos, jlong paintHandle) { 563 Paint* paint = reinterpret_cast<Paint*>(paintHandle); 564 jchar* jchars = text ? env->GetCharArrayElements(text, NULL) : NULL; 565 float* posArray = pos ? env->GetFloatArrayElements(pos, NULL) : NULL; 566 int posCount = pos ? env->GetArrayLength(pos) >> 1: 0; 567 568 get_canvas(canvasHandle)->drawPosText(jchars + index, posArray, count << 1, posCount, *paint); 569 570 if (text) { 571 env->ReleaseCharArrayElements(text, jchars, 0); 572 } 573 if (pos) { 574 env->ReleaseFloatArrayElements(pos, posArray, 0); 575 } 576} 577 578 579static void drawPosTextString(JNIEnv* env, jobject, jlong canvasHandle, jstring text, 580 jfloatArray pos, jlong paintHandle) { 581 Paint* paint = reinterpret_cast<Paint*>(paintHandle); 582 const jchar* jchars = text ? env->GetStringChars(text, NULL) : NULL; 583 int byteLength = text ? env->GetStringLength(text) : 0; 584 float* posArray = pos ? env->GetFloatArrayElements(pos, NULL) : NULL; 585 int posCount = pos ? env->GetArrayLength(pos) >> 1: 0; 586 587 get_canvas(canvasHandle)->drawPosText(jchars , posArray, byteLength << 1, posCount, *paint); 588 589 if (text) { 590 env->ReleaseStringChars(text, jchars); 591 } 592 if (pos) { 593 env->ReleaseFloatArrayElements(pos, posArray, 0); 594 } 595} 596 597class DrawTextOnPathFunctor { 598public: 599 DrawTextOnPathFunctor(const Layout& layout, Canvas* canvas, float hOffset, 600 float vOffset, const Paint& paint, const SkPath& path) 601 : layout(layout), canvas(canvas), hOffset(hOffset), vOffset(vOffset), 602 paint(paint), path(path) { 603 } 604 void operator()(size_t start, size_t end) { 605 uint16_t glyphs[1]; 606 for (size_t i = start; i < end; i++) { 607 glyphs[0] = layout.getGlyphId(i); 608 float x = hOffset + layout.getX(i); 609 float y = vOffset + layout.getY(i); 610 canvas->drawTextOnPath(glyphs, 1, path, x, y, paint); 611 } 612 } 613private: 614 const Layout& layout; 615 Canvas* canvas; 616 float hOffset; 617 float vOffset; 618 const Paint& paint; 619 const SkPath& path; 620}; 621 622static void drawTextOnPath(Canvas* canvas, const uint16_t* text, int count, int bidiFlags, 623 const SkPath& path, float hOffset, float vOffset, 624 const Paint& paint, TypefaceImpl* typeface) { 625 Paint paintCopy(paint); 626 Layout layout; 627 MinikinUtils::doLayout(&layout, &paintCopy, bidiFlags, typeface, text, 0, count, count); 628 hOffset += MinikinUtils::hOffsetForTextAlign(&paintCopy, layout, path); 629 630 // Set align to left for drawing, as we don't want individual 631 // glyphs centered or right-aligned; the offset above takes 632 // care of all alignment. 633 paintCopy.setTextAlign(Paint::kLeft_Align); 634 635 DrawTextOnPathFunctor f(layout, canvas, hOffset, vOffset, paintCopy, path); 636 MinikinUtils::forFontRun(layout, &paintCopy, f); 637} 638 639static void drawTextOnPathChars(JNIEnv* env, jobject, jlong canvasHandle, jcharArray text, 640 jint index, jint count, jlong pathHandle, jfloat hOffset, 641 jfloat vOffset, jint bidiFlags, jlong paintHandle, 642 jlong typefaceHandle) { 643 SkPath* path = reinterpret_cast<SkPath*>(pathHandle); 644 Paint* paint = reinterpret_cast<Paint*>(paintHandle); 645 TypefaceImpl* typeface = reinterpret_cast<TypefaceImpl*>(typefaceHandle); 646 647 jchar* jchars = env->GetCharArrayElements(text, NULL); 648 649 drawTextOnPath(get_canvas(canvasHandle), jchars + index, count, bidiFlags, *path, 650 hOffset, vOffset, *paint, typeface); 651 652 env->ReleaseCharArrayElements(text, jchars, 0); 653} 654 655static void drawTextOnPathString(JNIEnv* env, jobject, jlong canvasHandle, jstring text, 656 jlong pathHandle, jfloat hOffset, jfloat vOffset, 657 jint bidiFlags, jlong paintHandle, jlong typefaceHandle) { 658 SkPath* path = reinterpret_cast<SkPath*>(pathHandle); 659 Paint* paint = reinterpret_cast<Paint*>(paintHandle); 660 TypefaceImpl* typeface = reinterpret_cast<TypefaceImpl*>(typefaceHandle); 661 662 const jchar* jchars = env->GetStringChars(text, NULL); 663 int count = env->GetStringLength(text); 664 665 drawTextOnPath(get_canvas(canvasHandle), jchars, count, bidiFlags, *path, 666 hOffset, vOffset, *paint, typeface); 667 668 env->ReleaseStringChars(text, jchars); 669} 670 671static void setDrawFilter(JNIEnv* env, jobject, jlong canvasHandle, jlong filterHandle) { 672 get_canvas(canvasHandle)->setDrawFilter(reinterpret_cast<SkDrawFilter*>(filterHandle)); 673} 674 675static void freeCaches(JNIEnv* env, jobject) { 676 SkGraphics::PurgeFontCache(); 677} 678 679static void freeTextLayoutCaches(JNIEnv* env, jobject) { 680 Layout::purgeCaches(); 681} 682 683}; // namespace CanvasJNI 684 685static JNINativeMethod gMethods[] = { 686 {"finalizer", "(J)V", (void*) CanvasJNI::finalizer}, 687 {"initRaster", "(J)J", (void*) CanvasJNI::initRaster}, 688 {"native_setBitmap", "(JJZ)V", (void*) CanvasJNI::setBitmap}, 689 {"native_isOpaque","(J)Z", (void*) CanvasJNI::isOpaque}, 690 {"native_getWidth","(J)I", (void*) CanvasJNI::getWidth}, 691 {"native_getHeight","(J)I", (void*) CanvasJNI::getHeight}, 692 {"native_save","(JI)I", (void*) CanvasJNI::save}, 693 {"native_saveLayer","(JFFFFJI)I", (void*) CanvasJNI::saveLayer}, 694 {"native_saveLayerAlpha","(JFFFFII)I", (void*) CanvasJNI::saveLayerAlpha}, 695 {"native_getSaveCount","(J)I", (void*) CanvasJNI::getSaveCount}, 696 {"native_restore","(J)V", (void*) CanvasJNI::restore}, 697 {"native_restoreToCount","(JI)V", (void*) CanvasJNI::restoreToCount}, 698 {"native_getCTM", "(JJ)V", (void*)CanvasJNI::getCTM}, 699 {"native_setMatrix","(JJ)V", (void*) CanvasJNI::setMatrix}, 700 {"native_concat","(JJ)V", (void*) CanvasJNI::concat}, 701 {"native_rotate","(JF)V", (void*) CanvasJNI::rotate}, 702 {"native_scale","(JFF)V", (void*) CanvasJNI::scale}, 703 {"native_skew","(JFF)V", (void*) CanvasJNI::skew}, 704 {"native_translate","(JFF)V", (void*) CanvasJNI::translate}, 705 {"native_getClipBounds","(JLandroid/graphics/Rect;)Z", (void*) CanvasJNI::getClipBounds}, 706 {"native_quickReject","(JJ)Z", (void*) CanvasJNI::quickRejectPath}, 707 {"native_quickReject","(JFFFF)Z", (void*)CanvasJNI::quickRejectRect}, 708 {"native_clipRect","(JFFFFI)Z", (void*) CanvasJNI::clipRect}, 709 {"native_clipPath","(JJI)Z", (void*) CanvasJNI::clipPath}, 710 {"native_clipRegion","(JJI)Z", (void*) CanvasJNI::clipRegion}, 711 {"native_drawColor","(JII)V", (void*) CanvasJNI::drawColor}, 712 {"native_drawPaint","(JJ)V", (void*) CanvasJNI::drawPaint}, 713 {"native_drawPoint", "(JFFJ)V", (void*) CanvasJNI::drawPoint}, 714 {"native_drawPoints", "(J[FIIJ)V", (void*) CanvasJNI::drawPoints}, 715 {"native_drawLine", "(JFFFFJ)V", (void*) CanvasJNI::drawLine}, 716 {"native_drawLines", "(J[FIIJ)V", (void*) CanvasJNI::drawLines}, 717 {"native_drawRect","(JFFFFJ)V", (void*) CanvasJNI::drawRect}, 718 {"native_drawRoundRect","(JFFFFFFJ)V", (void*) CanvasJNI::drawRoundRect}, 719 {"native_drawCircle","(JFFFJ)V", (void*) CanvasJNI::drawCircle}, 720 {"native_drawOval","(JFFFFJ)V", (void*) CanvasJNI::drawOval}, 721 {"native_drawArc","(JFFFFFFZJ)V", (void*) CanvasJNI::drawArc}, 722 {"native_drawPath","(JJJ)V", (void*) CanvasJNI::drawPath}, 723 {"nativeDrawVertices", "(JII[FI[FI[II[SIIJ)V", (void*)CanvasJNI::drawVertices}, 724 {"native_drawBitmap","(JJFFJIII)V", (void*) CanvasJNI::drawBitmap}, 725 {"nativeDrawBitmapMatrix", "(JJJJ)V", (void*)CanvasJNI::drawBitmapMatrix}, 726 {"native_drawBitmap","(JJFFFFFFFFJII)V", (void*) CanvasJNI::drawBitmapRect}, 727 {"native_drawBitmap", "(J[IIIFFIIZJ)V", (void*)CanvasJNI::drawBitmapArray}, 728 {"nativeDrawBitmapMesh", "(JJII[FI[IIJ)V", (void*)CanvasJNI::drawBitmapMesh}, 729 {"native_drawText","(J[CIIFFIJJ)V", (void*) CanvasJNI::drawTextChars}, 730 {"native_drawText","(JLjava/lang/String;IIFFIJJ)V", (void*) CanvasJNI::drawTextString}, 731 {"native_drawTextRun","(J[CIIIIFFZJJ)V", (void*) CanvasJNI::drawTextRunChars}, 732 {"native_drawTextRun","(JLjava/lang/String;IIIIFFZJJ)V", (void*) CanvasJNI::drawTextRunString}, 733 {"native_drawTextOnPath","(J[CIIJFFIJJ)V", (void*) CanvasJNI::drawTextOnPathChars}, 734 {"native_drawTextOnPath","(JLjava/lang/String;JFFIJJ)V", (void*) CanvasJNI::drawTextOnPathString}, 735 {"nativeSetDrawFilter", "(JJ)V", (void*) CanvasJNI::setDrawFilter}, 736 {"freeCaches", "()V", (void*) CanvasJNI::freeCaches}, 737 {"freeTextLayoutCaches", "()V", (void*) CanvasJNI::freeTextLayoutCaches} 738}; 739 740int register_android_graphics_Canvas(JNIEnv* env) { 741 return AndroidRuntime::registerNativeMethods(env, "android/graphics/Canvas", gMethods, NELEM(gMethods)); 742} 743 744}; // namespace android 745