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