1 /* 2 * Copyright (C) 2006-2007 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 "SkCanvas.h" 22 #include "SkDevice.h" 23 #include "SkDrawFilter.h" 24 #include "SkGraphics.h" 25 #include "SkImageRef_GlobalPool.h" 26 #include "SkPorterDuff.h" 27 #include "SkShader.h" 28 #include "SkTemplates.h" 29 30 #include "TextLayout.h" 31 #include "TextLayoutCache.h" 32 33 #include "unicode/ubidi.h" 34 #include "unicode/ushape.h" 35 36 #include <utils/Log.h> 37 38 #define TIME_DRAWx 39 40 static uint32_t get_thread_msec() { 41 #if defined(HAVE_POSIX_CLOCKS) 42 struct timespec tm; 43 44 clock_gettime(CLOCK_THREAD_CPUTIME_ID, &tm); 45 46 return tm.tv_sec * 1000LL + tm.tv_nsec / 1000000; 47 #else 48 struct timeval tv; 49 50 gettimeofday(&tv, NULL); 51 return tv.tv_sec * 1000LL + tv.tv_usec / 1000; 52 #endif 53 } 54 55 namespace android { 56 57 class ClipCopier : public SkCanvas::ClipVisitor { 58 public: 59 ClipCopier(SkCanvas* dstCanvas) : m_dstCanvas(dstCanvas) {} 60 61 virtual void clipRect(const SkRect& rect, SkRegion::Op op, bool antialias) { 62 m_dstCanvas->clipRect(rect, op, antialias); 63 } 64 virtual void clipPath(const SkPath& path, SkRegion::Op op, bool antialias) { 65 m_dstCanvas->clipPath(path, op, antialias); 66 } 67 68 private: 69 SkCanvas* m_dstCanvas; 70 }; 71 72 class SkCanvasGlue { 73 public: 74 75 static void finalizer(JNIEnv* env, jobject clazz, SkCanvas* canvas) { 76 canvas->unref(); 77 } 78 79 static SkCanvas* initRaster(JNIEnv* env, jobject, SkBitmap* bitmap) { 80 if (bitmap) { 81 return new SkCanvas(*bitmap); 82 } else { 83 // Create an empty bitmap device to prevent callers from crashing 84 // if they attempt to draw into this canvas. 85 SkBitmap emptyBitmap; 86 return new SkCanvas(emptyBitmap); 87 } 88 } 89 90 static void copyCanvasState(JNIEnv* env, jobject clazz, 91 SkCanvas* srcCanvas, SkCanvas* dstCanvas) { 92 if (srcCanvas && dstCanvas) { 93 dstCanvas->setMatrix(srcCanvas->getTotalMatrix()); 94 if (NULL != srcCanvas->getDevice() && NULL != dstCanvas->getDevice()) { 95 ClipCopier copier(dstCanvas); 96 srcCanvas->replayClips(&copier); 97 } 98 } 99 } 100 101 102 static void freeCaches(JNIEnv* env, jobject) { 103 // these are called in no particular order 104 SkImageRef_GlobalPool::SetRAMUsed(0); 105 SkGraphics::PurgeFontCache(); 106 } 107 108 static void freeTextLayoutCaches(JNIEnv* env, jobject) { 109 TextLayoutEngine::getInstance().purgeCaches(); 110 } 111 112 static jboolean isOpaque(JNIEnv* env, jobject jcanvas) { 113 NPE_CHECK_RETURN_ZERO(env, jcanvas); 114 SkCanvas* canvas = GraphicsJNI::getNativeCanvas(env, jcanvas); 115 return canvas->getDevice()->accessBitmap(false).isOpaque(); 116 } 117 118 static int getWidth(JNIEnv* env, jobject jcanvas) { 119 NPE_CHECK_RETURN_ZERO(env, jcanvas); 120 SkCanvas* canvas = GraphicsJNI::getNativeCanvas(env, jcanvas); 121 return canvas->getDevice()->accessBitmap(false).width(); 122 } 123 124 static int getHeight(JNIEnv* env, jobject jcanvas) { 125 NPE_CHECK_RETURN_ZERO(env, jcanvas); 126 SkCanvas* canvas = GraphicsJNI::getNativeCanvas(env, jcanvas); 127 return canvas->getDevice()->accessBitmap(false).height(); 128 } 129 130 static int saveAll(JNIEnv* env, jobject jcanvas) { 131 NPE_CHECK_RETURN_ZERO(env, jcanvas); 132 return GraphicsJNI::getNativeCanvas(env, jcanvas)->save(); 133 } 134 135 static int save(JNIEnv* env, jobject jcanvas, SkCanvas::SaveFlags flags) { 136 NPE_CHECK_RETURN_ZERO(env, jcanvas); 137 return GraphicsJNI::getNativeCanvas(env, jcanvas)->save(flags); 138 } 139 140 static int saveLayer(JNIEnv* env, jobject, SkCanvas* canvas, jobject bounds, 141 SkPaint* paint, int flags) { 142 SkRect* bounds_ = NULL; 143 SkRect storage; 144 if (bounds != NULL) { 145 GraphicsJNI::jrectf_to_rect(env, bounds, &storage); 146 bounds_ = &storage; 147 } 148 return canvas->saveLayer(bounds_, paint, (SkCanvas::SaveFlags)flags); 149 } 150 151 static int saveLayer4F(JNIEnv* env, jobject, SkCanvas* canvas, 152 jfloat l, jfloat t, jfloat r, jfloat b, 153 SkPaint* paint, int flags) { 154 SkRect bounds; 155 bounds.set(SkFloatToScalar(l), SkFloatToScalar(t), SkFloatToScalar(r), 156 SkFloatToScalar(b)); 157 return canvas->saveLayer(&bounds, paint, (SkCanvas::SaveFlags)flags); 158 } 159 160 static int saveLayerAlpha(JNIEnv* env, jobject, SkCanvas* canvas, 161 jobject bounds, int alpha, int flags) { 162 SkRect* bounds_ = NULL; 163 SkRect storage; 164 if (bounds != NULL) { 165 GraphicsJNI::jrectf_to_rect(env, bounds, &storage); 166 bounds_ = &storage; 167 } 168 return canvas->saveLayerAlpha(bounds_, alpha, 169 (SkCanvas::SaveFlags)flags); 170 } 171 172 static int saveLayerAlpha4F(JNIEnv* env, jobject, SkCanvas* canvas, 173 jfloat l, jfloat t, jfloat r, jfloat b, 174 int alpha, int flags) { 175 SkRect bounds; 176 bounds.set(SkFloatToScalar(l), SkFloatToScalar(t), SkFloatToScalar(r), 177 SkFloatToScalar(b)); 178 return canvas->saveLayerAlpha(&bounds, alpha, 179 (SkCanvas::SaveFlags)flags); 180 } 181 182 static void restore(JNIEnv* env, jobject jcanvas) { 183 NPE_CHECK_RETURN_VOID(env, jcanvas); 184 SkCanvas* canvas = GraphicsJNI::getNativeCanvas(env, jcanvas); 185 if (canvas->getSaveCount() <= 1) { // cannot restore anymore 186 doThrowISE(env, "Underflow in restore"); 187 return; 188 } 189 canvas->restore(); 190 } 191 192 static int getSaveCount(JNIEnv* env, jobject jcanvas) { 193 NPE_CHECK_RETURN_ZERO(env, jcanvas); 194 return GraphicsJNI::getNativeCanvas(env, jcanvas)->getSaveCount(); 195 } 196 197 static void restoreToCount(JNIEnv* env, jobject jcanvas, int restoreCount) { 198 NPE_CHECK_RETURN_VOID(env, jcanvas); 199 SkCanvas* canvas = GraphicsJNI::getNativeCanvas(env, jcanvas); 200 if (restoreCount < 1) { 201 doThrowIAE(env, "Underflow in restoreToCount"); 202 return; 203 } 204 canvas->restoreToCount(restoreCount); 205 } 206 207 static void translate(JNIEnv* env, jobject jcanvas, jfloat dx, jfloat dy) { 208 NPE_CHECK_RETURN_VOID(env, jcanvas); 209 SkScalar dx_ = SkFloatToScalar(dx); 210 SkScalar dy_ = SkFloatToScalar(dy); 211 (void)GraphicsJNI::getNativeCanvas(env, jcanvas)->translate(dx_, dy_); 212 } 213 214 static void scale__FF(JNIEnv* env, jobject jcanvas, jfloat sx, jfloat sy) { 215 NPE_CHECK_RETURN_VOID(env, jcanvas); 216 SkScalar sx_ = SkFloatToScalar(sx); 217 SkScalar sy_ = SkFloatToScalar(sy); 218 (void)GraphicsJNI::getNativeCanvas(env, jcanvas)->scale(sx_, sy_); 219 } 220 221 static void rotate__F(JNIEnv* env, jobject jcanvas, jfloat degrees) { 222 NPE_CHECK_RETURN_VOID(env, jcanvas); 223 SkScalar degrees_ = SkFloatToScalar(degrees); 224 (void)GraphicsJNI::getNativeCanvas(env, jcanvas)->rotate(degrees_); 225 } 226 227 static void skew__FF(JNIEnv* env, jobject jcanvas, jfloat sx, jfloat sy) { 228 NPE_CHECK_RETURN_VOID(env, jcanvas); 229 SkScalar sx_ = SkFloatToScalar(sx); 230 SkScalar sy_ = SkFloatToScalar(sy); 231 (void)GraphicsJNI::getNativeCanvas(env, jcanvas)->skew(sx_, sy_); 232 } 233 234 static void concat(JNIEnv* env, jobject, SkCanvas* canvas, 235 const SkMatrix* matrix) { 236 canvas->concat(*matrix); 237 } 238 239 static void setMatrix(JNIEnv* env, jobject, SkCanvas* canvas, 240 const SkMatrix* matrix) { 241 if (NULL == matrix) { 242 canvas->resetMatrix(); 243 } else { 244 canvas->setMatrix(*matrix); 245 } 246 } 247 248 static jboolean clipRect_FFFF(JNIEnv* env, jobject jcanvas, jfloat left, 249 jfloat top, jfloat right, jfloat bottom) { 250 NPE_CHECK_RETURN_ZERO(env, jcanvas); 251 SkRect r; 252 r.set(SkFloatToScalar(left), SkFloatToScalar(top), 253 SkFloatToScalar(right), SkFloatToScalar(bottom)); 254 SkCanvas* c = GraphicsJNI::getNativeCanvas(env, jcanvas); 255 return c->clipRect(r); 256 } 257 258 static jboolean clipRect_IIII(JNIEnv* env, jobject jcanvas, jint left, 259 jint top, jint right, jint bottom) { 260 NPE_CHECK_RETURN_ZERO(env, jcanvas); 261 SkRect r; 262 r.set(SkIntToScalar(left), SkIntToScalar(top), 263 SkIntToScalar(right), SkIntToScalar(bottom)); 264 return GraphicsJNI::getNativeCanvas(env, jcanvas)->clipRect(r); 265 } 266 267 static jboolean clipRect_RectF(JNIEnv* env, jobject jcanvas, jobject rectf) { 268 NPE_CHECK_RETURN_ZERO(env, jcanvas); 269 NPE_CHECK_RETURN_ZERO(env, rectf); 270 SkCanvas* c = GraphicsJNI::getNativeCanvas(env, jcanvas); 271 SkRect tmp; 272 return c->clipRect(*GraphicsJNI::jrectf_to_rect(env, rectf, &tmp)); 273 } 274 275 static jboolean clipRect_Rect(JNIEnv* env, jobject jcanvas, jobject rect) { 276 NPE_CHECK_RETURN_ZERO(env, jcanvas); 277 NPE_CHECK_RETURN_ZERO(env, rect); 278 SkCanvas* c = GraphicsJNI::getNativeCanvas(env, jcanvas); 279 SkRect tmp; 280 return c->clipRect(*GraphicsJNI::jrect_to_rect(env, rect, &tmp)); 281 } 282 283 static jboolean clipRect(JNIEnv* env, jobject, SkCanvas* canvas, 284 float left, float top, float right, float bottom, 285 int op) { 286 SkRect rect; 287 rect.set(SkFloatToScalar(left), SkFloatToScalar(top), 288 SkFloatToScalar(right), SkFloatToScalar(bottom)); 289 return canvas->clipRect(rect, (SkRegion::Op)op); 290 } 291 292 static jboolean clipPath(JNIEnv* env, jobject, SkCanvas* canvas, 293 SkPath* path, int op) { 294 return canvas->clipPath(*path, (SkRegion::Op)op); 295 } 296 297 static jboolean clipRegion(JNIEnv* env, jobject, SkCanvas* canvas, 298 SkRegion* deviceRgn, int op) { 299 return canvas->clipRegion(*deviceRgn, (SkRegion::Op)op); 300 } 301 302 static void setDrawFilter(JNIEnv* env, jobject, SkCanvas* canvas, 303 SkDrawFilter* filter) { 304 canvas->setDrawFilter(filter); 305 } 306 307 static jboolean quickReject__RectF(JNIEnv* env, jobject, SkCanvas* canvas, 308 jobject rect) { 309 SkRect rect_; 310 GraphicsJNI::jrectf_to_rect(env, rect, &rect_); 311 return canvas->quickReject(rect_); 312 } 313 314 static jboolean quickReject__Path(JNIEnv* env, jobject, SkCanvas* canvas, 315 SkPath* path) { 316 return canvas->quickReject(*path); 317 } 318 319 static jboolean quickReject__FFFF(JNIEnv* env, jobject, SkCanvas* canvas, 320 jfloat left, jfloat top, jfloat right, 321 jfloat bottom) { 322 SkRect r; 323 r.set(SkFloatToScalar(left), SkFloatToScalar(top), 324 SkFloatToScalar(right), SkFloatToScalar(bottom)); 325 return canvas->quickReject(r); 326 } 327 328 static void drawRGB(JNIEnv* env, jobject, SkCanvas* canvas, 329 jint r, jint g, jint b) { 330 canvas->drawARGB(0xFF, r, g, b); 331 } 332 333 static void drawARGB(JNIEnv* env, jobject, SkCanvas* canvas, 334 jint a, jint r, jint g, jint b) { 335 canvas->drawARGB(a, r, g, b); 336 } 337 338 static void drawColor__I(JNIEnv* env, jobject, SkCanvas* canvas, 339 jint color) { 340 canvas->drawColor(color); 341 } 342 343 static void drawColor__II(JNIEnv* env, jobject, SkCanvas* canvas, 344 jint color, SkPorterDuff::Mode mode) { 345 canvas->drawColor(color, SkPorterDuff::ToXfermodeMode(mode)); 346 } 347 348 static void drawPaint(JNIEnv* env, jobject, SkCanvas* canvas, 349 SkPaint* paint) { 350 canvas->drawPaint(*paint); 351 } 352 353 static void doPoints(JNIEnv* env, jobject jcanvas, jfloatArray jptsArray, 354 jint offset, jint count, jobject jpaint, 355 SkCanvas::PointMode mode) { 356 NPE_CHECK_RETURN_VOID(env, jcanvas); 357 NPE_CHECK_RETURN_VOID(env, jptsArray); 358 NPE_CHECK_RETURN_VOID(env, jpaint); 359 SkCanvas* canvas = GraphicsJNI::getNativeCanvas(env, jcanvas); 360 const SkPaint& paint = *GraphicsJNI::getNativePaint(env, jpaint); 361 362 AutoJavaFloatArray autoPts(env, jptsArray); 363 float* floats = autoPts.ptr(); 364 const int length = autoPts.length(); 365 366 if ((offset | count) < 0 || offset + count > length) { 367 doThrowAIOOBE(env); 368 return; 369 } 370 371 // now convert the floats into SkPoints 372 count >>= 1; // now it is the number of points 373 SkAutoSTMalloc<32, SkPoint> storage(count); 374 SkPoint* pts = storage.get(); 375 const float* src = floats + offset; 376 for (int i = 0; i < count; i++) { 377 pts[i].set(SkFloatToScalar(src[0]), SkFloatToScalar(src[1])); 378 src += 2; 379 } 380 canvas->drawPoints(mode, count, pts, paint); 381 } 382 383 static void drawPoints(JNIEnv* env, jobject jcanvas, jfloatArray jptsArray, 384 jint offset, jint count, jobject jpaint) { 385 doPoints(env, jcanvas, jptsArray, offset, count, jpaint, 386 SkCanvas::kPoints_PointMode); 387 } 388 389 static void drawLines(JNIEnv* env, jobject jcanvas, jfloatArray jptsArray, 390 jint offset, jint count, jobject jpaint) { 391 doPoints(env, jcanvas, jptsArray, offset, count, jpaint, 392 SkCanvas::kLines_PointMode); 393 } 394 395 static void drawPoint(JNIEnv* env, jobject jcanvas, float x, float y, 396 jobject jpaint) { 397 NPE_CHECK_RETURN_VOID(env, jcanvas); 398 NPE_CHECK_RETURN_VOID(env, jpaint); 399 SkCanvas* canvas = GraphicsJNI::getNativeCanvas(env, jcanvas); 400 const SkPaint& paint = *GraphicsJNI::getNativePaint(env, jpaint); 401 402 canvas->drawPoint(SkFloatToScalar(x), SkFloatToScalar(y), paint); 403 } 404 405 static void drawLine__FFFFPaint(JNIEnv* env, jobject, SkCanvas* canvas, 406 jfloat startX, jfloat startY, jfloat stopX, 407 jfloat stopY, SkPaint* paint) { 408 canvas->drawLine(SkFloatToScalar(startX), SkFloatToScalar(startY), 409 SkFloatToScalar(stopX), SkFloatToScalar(stopY), 410 *paint); 411 } 412 413 static void drawRect__RectFPaint(JNIEnv* env, jobject, SkCanvas* canvas, 414 jobject rect, SkPaint* paint) { 415 SkRect rect_; 416 GraphicsJNI::jrectf_to_rect(env, rect, &rect_); 417 canvas->drawRect(rect_, *paint); 418 } 419 420 static void drawRect__FFFFPaint(JNIEnv* env, jobject, SkCanvas* canvas, 421 jfloat left, jfloat top, jfloat right, 422 jfloat bottom, SkPaint* paint) { 423 SkScalar left_ = SkFloatToScalar(left); 424 SkScalar top_ = SkFloatToScalar(top); 425 SkScalar right_ = SkFloatToScalar(right); 426 SkScalar bottom_ = SkFloatToScalar(bottom); 427 canvas->drawRectCoords(left_, top_, right_, bottom_, *paint); 428 } 429 430 static void drawOval(JNIEnv* env, jobject, SkCanvas* canvas, jobject joval, 431 SkPaint* paint) { 432 SkRect oval; 433 GraphicsJNI::jrectf_to_rect(env, joval, &oval); 434 canvas->drawOval(oval, *paint); 435 } 436 437 static void drawCircle(JNIEnv* env, jobject, SkCanvas* canvas, jfloat cx, 438 jfloat cy, jfloat radius, SkPaint* paint) { 439 canvas->drawCircle(SkFloatToScalar(cx), SkFloatToScalar(cy), 440 SkFloatToScalar(radius), *paint); 441 } 442 443 static void drawArc(JNIEnv* env, jobject, SkCanvas* canvas, jobject joval, 444 jfloat startAngle, jfloat sweepAngle, 445 jboolean useCenter, SkPaint* paint) { 446 SkRect oval; 447 GraphicsJNI::jrectf_to_rect(env, joval, &oval); 448 canvas->drawArc(oval, SkFloatToScalar(startAngle), 449 SkFloatToScalar(sweepAngle), useCenter, *paint); 450 } 451 452 static void drawRoundRect(JNIEnv* env, jobject, SkCanvas* canvas, 453 jobject jrect, jfloat rx, jfloat ry, 454 SkPaint* paint) { 455 SkRect rect; 456 GraphicsJNI::jrectf_to_rect(env, jrect, &rect); 457 canvas->drawRoundRect(rect, SkFloatToScalar(rx), SkFloatToScalar(ry), 458 *paint); 459 } 460 461 static void drawPath(JNIEnv* env, jobject, SkCanvas* canvas, SkPath* path, 462 SkPaint* paint) { 463 canvas->drawPath(*path, *paint); 464 } 465 466 static void drawPicture(JNIEnv* env, jobject, SkCanvas* canvas, 467 SkPicture* picture) { 468 SkASSERT(canvas); 469 SkASSERT(picture); 470 471 #ifdef TIME_DRAW 472 SkMSec now = get_thread_msec(); //SkTime::GetMSecs(); 473 #endif 474 canvas->drawPicture(*picture); 475 #ifdef TIME_DRAW 476 ALOGD("---- picture playback %d ms\n", get_thread_msec() - now); 477 #endif 478 } 479 480 static void drawBitmap__BitmapFFPaint(JNIEnv* env, jobject jcanvas, 481 SkCanvas* canvas, SkBitmap* bitmap, 482 jfloat left, jfloat top, 483 SkPaint* paint, jint canvasDensity, 484 jint screenDensity, jint bitmapDensity) { 485 SkScalar left_ = SkFloatToScalar(left); 486 SkScalar top_ = SkFloatToScalar(top); 487 488 if (canvasDensity == bitmapDensity || canvasDensity == 0 489 || bitmapDensity == 0) { 490 if (screenDensity != 0 && screenDensity != bitmapDensity) { 491 SkPaint filteredPaint; 492 if (paint) { 493 filteredPaint = *paint; 494 } 495 filteredPaint.setFilterBitmap(true); 496 canvas->drawBitmap(*bitmap, left_, top_, &filteredPaint); 497 } else { 498 canvas->drawBitmap(*bitmap, left_, top_, paint); 499 } 500 } else { 501 canvas->save(); 502 SkScalar scale = SkFloatToScalar(canvasDensity / (float)bitmapDensity); 503 canvas->translate(left_, top_); 504 canvas->scale(scale, scale); 505 506 SkPaint filteredPaint; 507 if (paint) { 508 filteredPaint = *paint; 509 } 510 filteredPaint.setFilterBitmap(true); 511 512 canvas->drawBitmap(*bitmap, 0, 0, &filteredPaint); 513 514 canvas->restore(); 515 } 516 } 517 518 static void doDrawBitmap(JNIEnv* env, SkCanvas* canvas, SkBitmap* bitmap, 519 jobject srcIRect, const SkRect& dst, SkPaint* paint, 520 jint screenDensity, jint bitmapDensity) { 521 SkIRect src, *srcPtr = NULL; 522 523 if (NULL != srcIRect) { 524 GraphicsJNI::jrect_to_irect(env, srcIRect, &src); 525 srcPtr = &src; 526 } 527 528 if (screenDensity != 0 && screenDensity != bitmapDensity) { 529 SkPaint filteredPaint; 530 if (paint) { 531 filteredPaint = *paint; 532 } 533 filteredPaint.setFilterBitmap(true); 534 canvas->drawBitmapRect(*bitmap, srcPtr, dst, &filteredPaint); 535 } else { 536 canvas->drawBitmapRect(*bitmap, srcPtr, dst, paint); 537 } 538 } 539 540 static void drawBitmapRF(JNIEnv* env, jobject, SkCanvas* canvas, 541 SkBitmap* bitmap, jobject srcIRect, 542 jobject dstRectF, SkPaint* paint, 543 jint screenDensity, jint bitmapDensity) { 544 SkRect dst; 545 GraphicsJNI::jrectf_to_rect(env, dstRectF, &dst); 546 doDrawBitmap(env, canvas, bitmap, srcIRect, dst, paint, 547 screenDensity, bitmapDensity); 548 } 549 550 static void drawBitmapRR(JNIEnv* env, jobject, SkCanvas* canvas, 551 SkBitmap* bitmap, jobject srcIRect, 552 jobject dstRect, SkPaint* paint, 553 jint screenDensity, jint bitmapDensity) { 554 SkRect dst; 555 GraphicsJNI::jrect_to_rect(env, dstRect, &dst); 556 doDrawBitmap(env, canvas, bitmap, srcIRect, dst, paint, 557 screenDensity, bitmapDensity); 558 } 559 560 static void drawBitmapArray(JNIEnv* env, jobject, SkCanvas* canvas, 561 jintArray jcolors, int offset, int stride, 562 jfloat x, jfloat y, int width, int height, 563 jboolean hasAlpha, SkPaint* paint) 564 { 565 SkBitmap bitmap; 566 567 bitmap.setConfig(hasAlpha ? SkBitmap::kARGB_8888_Config : 568 SkBitmap::kRGB_565_Config, width, height); 569 if (!bitmap.allocPixels()) { 570 return; 571 } 572 573 if (!GraphicsJNI::SetPixels(env, jcolors, offset, stride, 574 0, 0, width, height, bitmap)) { 575 return; 576 } 577 578 canvas->drawBitmap(bitmap, SkFloatToScalar(x), SkFloatToScalar(y), 579 paint); 580 } 581 582 static void drawBitmapMatrix(JNIEnv* env, jobject, SkCanvas* canvas, 583 const SkBitmap* bitmap, const SkMatrix* matrix, 584 const SkPaint* paint) { 585 canvas->drawBitmapMatrix(*bitmap, *matrix, paint); 586 } 587 588 static void drawBitmapMesh(JNIEnv* env, jobject, SkCanvas* canvas, 589 const SkBitmap* bitmap, int meshWidth, int meshHeight, 590 jfloatArray jverts, int vertIndex, jintArray jcolors, 591 int colorIndex, const SkPaint* paint) { 592 593 const int ptCount = (meshWidth + 1) * (meshHeight + 1); 594 const int indexCount = meshWidth * meshHeight * 6; 595 596 AutoJavaFloatArray vertA(env, jverts, vertIndex + (ptCount << 1)); 597 AutoJavaIntArray colorA(env, jcolors, colorIndex + ptCount); 598 599 /* Our temp storage holds 2 or 3 arrays. 600 texture points [ptCount * sizeof(SkPoint)] 601 optionally vertex points [ptCount * sizeof(SkPoint)] if we need a 602 copy to convert from float to fixed 603 indices [ptCount * sizeof(uint16_t)] 604 */ 605 ssize_t storageSize = ptCount * sizeof(SkPoint); // texs[] 606 #ifdef SK_SCALAR_IS_FIXED 607 storageSize += ptCount * sizeof(SkPoint); // storage for verts 608 #endif 609 storageSize += indexCount * sizeof(uint16_t); // indices[] 610 611 SkAutoMalloc storage(storageSize); 612 SkPoint* texs = (SkPoint*)storage.get(); 613 SkPoint* verts; 614 uint16_t* indices; 615 #ifdef SK_SCALAR_IS_FLOAT 616 verts = (SkPoint*)(vertA.ptr() + vertIndex); 617 indices = (uint16_t*)(texs + ptCount); 618 #else 619 verts = texs + ptCount; 620 indices = (uint16_t*)(verts + ptCount); 621 // convert floats to fixed 622 { 623 const float* src = vertA.ptr() + vertIndex; 624 for (int i = 0; i < ptCount; i++) { 625 verts[i].set(SkFloatToFixed(src[0]), SkFloatToFixed(src[1])); 626 src += 2; 627 } 628 } 629 #endif 630 631 // cons up texture coordinates and indices 632 { 633 const SkScalar w = SkIntToScalar(bitmap->width()); 634 const SkScalar h = SkIntToScalar(bitmap->height()); 635 const SkScalar dx = w / meshWidth; 636 const SkScalar dy = h / meshHeight; 637 638 SkPoint* texsPtr = texs; 639 SkScalar y = 0; 640 for (int i = 0; i <= meshHeight; i++) { 641 if (i == meshHeight) { 642 y = h; // to ensure numerically we hit h exactly 643 } 644 SkScalar x = 0; 645 for (int j = 0; j < meshWidth; j++) { 646 texsPtr->set(x, y); 647 texsPtr += 1; 648 x += dx; 649 } 650 texsPtr->set(w, y); 651 texsPtr += 1; 652 y += dy; 653 } 654 SkASSERT(texsPtr - texs == ptCount); 655 } 656 657 // cons up indices 658 { 659 uint16_t* indexPtr = indices; 660 int index = 0; 661 for (int i = 0; i < meshHeight; i++) { 662 for (int j = 0; j < meshWidth; j++) { 663 // lower-left triangle 664 *indexPtr++ = index; 665 *indexPtr++ = index + meshWidth + 1; 666 *indexPtr++ = index + meshWidth + 2; 667 // upper-right triangle 668 *indexPtr++ = index; 669 *indexPtr++ = index + meshWidth + 2; 670 *indexPtr++ = index + 1; 671 // bump to the next cell 672 index += 1; 673 } 674 // bump to the next row 675 index += 1; 676 } 677 SkASSERT(indexPtr - indices == indexCount); 678 SkASSERT((char*)indexPtr - (char*)storage.get() == storageSize); 679 } 680 681 // double-check that we have legal indices 682 #ifdef SK_DEBUG 683 { 684 for (int i = 0; i < indexCount; i++) { 685 SkASSERT((unsigned)indices[i] < (unsigned)ptCount); 686 } 687 } 688 #endif 689 690 // cons-up a shader for the bitmap 691 SkPaint tmpPaint; 692 if (paint) { 693 tmpPaint = *paint; 694 } 695 SkShader* shader = SkShader::CreateBitmapShader(*bitmap, 696 SkShader::kClamp_TileMode, SkShader::kClamp_TileMode); 697 SkSafeUnref(tmpPaint.setShader(shader)); 698 699 canvas->drawVertices(SkCanvas::kTriangles_VertexMode, ptCount, verts, 700 texs, (const SkColor*)colorA.ptr(), NULL, indices, 701 indexCount, tmpPaint); 702 } 703 704 static void drawVertices(JNIEnv* env, jobject, SkCanvas* canvas, 705 SkCanvas::VertexMode mode, int vertexCount, 706 jfloatArray jverts, int vertIndex, 707 jfloatArray jtexs, int texIndex, 708 jintArray jcolors, int colorIndex, 709 jshortArray jindices, int indexIndex, 710 int indexCount, const SkPaint* paint) { 711 712 AutoJavaFloatArray vertA(env, jverts, vertIndex + vertexCount); 713 AutoJavaFloatArray texA(env, jtexs, texIndex + vertexCount); 714 AutoJavaIntArray colorA(env, jcolors, colorIndex + vertexCount); 715 AutoJavaShortArray indexA(env, jindices, indexIndex + indexCount); 716 717 const int ptCount = vertexCount >> 1; 718 719 SkPoint* verts; 720 SkPoint* texs = NULL; 721 #ifdef SK_SCALAR_IS_FLOAT 722 verts = (SkPoint*)(vertA.ptr() + vertIndex); 723 if (jtexs != NULL) { 724 texs = (SkPoint*)(texA.ptr() + texIndex); 725 } 726 #else 727 int count = ptCount; // for verts 728 if (jtexs != NULL) { 729 count += ptCount; // += for texs 730 } 731 SkAutoMalloc storage(count * sizeof(SkPoint)); 732 verts = (SkPoint*)storage.get(); 733 const float* src = vertA.ptr() + vertIndex; 734 for (int i = 0; i < ptCount; i++) { 735 verts[i].set(SkFloatToFixed(src[0]), SkFloatToFixed(src[1])); 736 src += 2; 737 } 738 if (jtexs != NULL) { 739 texs = verts + ptCount; 740 src = texA.ptr() + texIndex; 741 for (int i = 0; i < ptCount; i++) { 742 texs[i].set(SkFloatToFixed(src[0]), SkFloatToFixed(src[1])); 743 src += 2; 744 } 745 } 746 #endif 747 748 const SkColor* colors = NULL; 749 const uint16_t* indices = NULL; 750 if (jcolors != NULL) { 751 colors = (const SkColor*)(colorA.ptr() + colorIndex); 752 } 753 if (jindices != NULL) { 754 indices = (const uint16_t*)(indexA.ptr() + indexIndex); 755 } 756 757 canvas->drawVertices(mode, ptCount, verts, texs, colors, NULL, 758 indices, indexCount, *paint); 759 } 760 761 762 static void drawText___CIIFFIPaint(JNIEnv* env, jobject, SkCanvas* canvas, 763 jcharArray text, int index, int count, 764 jfloat x, jfloat y, int flags, SkPaint* paint) { 765 jchar* textArray = env->GetCharArrayElements(text, NULL); 766 drawTextWithGlyphs(canvas, textArray + index, 0, count, x, y, flags, paint); 767 env->ReleaseCharArrayElements(text, textArray, JNI_ABORT); 768 } 769 770 static void drawText__StringIIFFIPaint(JNIEnv* env, jobject, 771 SkCanvas* canvas, jstring text, 772 int start, int end, 773 jfloat x, jfloat y, int flags, SkPaint* paint) { 774 const jchar* textArray = env->GetStringChars(text, NULL); 775 drawTextWithGlyphs(canvas, textArray, start, end, x, y, flags, paint); 776 env->ReleaseStringChars(text, textArray); 777 } 778 779 static void drawTextWithGlyphs(SkCanvas* canvas, const jchar* textArray, 780 int start, int end, 781 jfloat x, jfloat y, int flags, SkPaint* paint) { 782 783 jint count = end - start; 784 drawTextWithGlyphs(canvas, textArray + start, 0, count, count, x, y, flags, paint); 785 } 786 787 static void drawTextWithGlyphs(SkCanvas* canvas, const jchar* textArray, 788 int start, int count, int contextCount, 789 jfloat x, jfloat y, int flags, SkPaint* paint) { 790 791 sp<TextLayoutValue> value = TextLayoutEngine::getInstance().getValue(paint, 792 textArray, start, count, contextCount, flags); 793 if (value == NULL) { 794 return; 795 } 796 SkPaint::Align align = paint->getTextAlign(); 797 if (align == SkPaint::kCenter_Align) { 798 x -= 0.5 * value->getTotalAdvance(); 799 } else if (align == SkPaint::kRight_Align) { 800 x -= value->getTotalAdvance(); 801 } 802 paint->setTextAlign(SkPaint::kLeft_Align); 803 doDrawGlyphsPos(canvas, value->getGlyphs(), value->getPos(), 0, value->getGlyphsCount(), x, y, flags, paint); 804 doDrawTextDecorations(canvas, x, y, value->getTotalAdvance(), paint); 805 paint->setTextAlign(align); 806 } 807 808 // Same values used by Skia 809 #define kStdStrikeThru_Offset (-6.0f / 21.0f) 810 #define kStdUnderline_Offset (1.0f / 9.0f) 811 #define kStdUnderline_Thickness (1.0f / 18.0f) 812 813 static void doDrawTextDecorations(SkCanvas* canvas, jfloat x, jfloat y, jfloat length, SkPaint* paint) { 814 uint32_t flags; 815 SkDrawFilter* drawFilter = canvas->getDrawFilter(); 816 if (drawFilter) { 817 SkPaint paintCopy(*paint); 818 drawFilter->filter(&paintCopy, SkDrawFilter::kText_Type); 819 flags = paintCopy.getFlags(); 820 } else { 821 flags = paint->getFlags(); 822 } 823 if (flags & (SkPaint::kUnderlineText_Flag | SkPaint::kStrikeThruText_Flag)) { 824 SkScalar left = SkFloatToScalar(x); 825 SkScalar right = SkFloatToScalar(x + length); 826 float textSize = paint->getTextSize(); 827 float strokeWidth = fmax(textSize * kStdUnderline_Thickness, 1.0f); 828 if (flags & SkPaint::kUnderlineText_Flag) { 829 SkScalar top = SkFloatToScalar(y + textSize * kStdUnderline_Offset 830 - 0.5f * strokeWidth); 831 SkScalar bottom = SkFloatToScalar(y + textSize * kStdUnderline_Offset 832 + 0.5f * strokeWidth); 833 canvas->drawRectCoords(left, top, right, bottom, *paint); 834 } 835 if (flags & SkPaint::kStrikeThruText_Flag) { 836 SkScalar top = SkFloatToScalar(y + textSize * kStdStrikeThru_Offset 837 - 0.5f * strokeWidth); 838 SkScalar bottom = SkFloatToScalar(y + textSize * kStdStrikeThru_Offset 839 + 0.5f * strokeWidth); 840 canvas->drawRectCoords(left, top, right, bottom, *paint); 841 } 842 } 843 } 844 845 static void doDrawGlyphs(SkCanvas* canvas, const jchar* glyphArray, int index, int count, 846 jfloat x, jfloat y, int flags, SkPaint* paint) { 847 // Beware: this needs Glyph encoding (already done on the Paint constructor) 848 canvas->drawText(glyphArray + index * 2, count * 2, x, y, *paint); 849 } 850 851 static void doDrawGlyphsPos(SkCanvas* canvas, const jchar* glyphArray, const jfloat* posArray, 852 int index, int count, jfloat x, jfloat y, int flags, SkPaint* paint) { 853 SkPoint* posPtr = new SkPoint[count]; 854 for (int indx = 0; indx < count; indx++) { 855 posPtr[indx].fX = SkFloatToScalar(x + posArray[indx * 2]); 856 posPtr[indx].fY = SkFloatToScalar(y + posArray[indx * 2 + 1]); 857 } 858 canvas->drawPosText(glyphArray, count << 1, posPtr, *paint); 859 delete[] posPtr; 860 } 861 862 static void drawTextRun___CIIIIFFIPaint( 863 JNIEnv* env, jobject, SkCanvas* canvas, jcharArray text, int index, 864 int count, int contextIndex, int contextCount, 865 jfloat x, jfloat y, int dirFlags, SkPaint* paint) { 866 867 jchar* chars = env->GetCharArrayElements(text, NULL); 868 drawTextWithGlyphs(canvas, chars + contextIndex, index - contextIndex, 869 count, contextCount, x, y, dirFlags, paint); 870 env->ReleaseCharArrayElements(text, chars, JNI_ABORT); 871 } 872 873 static void drawTextRun__StringIIIIFFIPaint( 874 JNIEnv* env, jobject obj, SkCanvas* canvas, jstring text, jint start, 875 jint end, jint contextStart, jint contextEnd, 876 jfloat x, jfloat y, jint dirFlags, SkPaint* paint) { 877 878 jint count = end - start; 879 jint contextCount = contextEnd - contextStart; 880 const jchar* chars = env->GetStringChars(text, NULL); 881 drawTextWithGlyphs(canvas, chars + contextStart, start - contextStart, 882 count, contextCount, x, y, dirFlags, paint); 883 env->ReleaseStringChars(text, chars); 884 } 885 886 static void drawPosText___CII_FPaint(JNIEnv* env, jobject, SkCanvas* canvas, 887 jcharArray text, int index, int count, 888 jfloatArray pos, SkPaint* paint) { 889 jchar* textArray = text ? env->GetCharArrayElements(text, NULL) : NULL; 890 jsize textCount = text ? env->GetArrayLength(text) : NULL; 891 float* posArray = pos ? env->GetFloatArrayElements(pos, NULL) : NULL; 892 int posCount = pos ? env->GetArrayLength(pos) >> 1: 0; 893 SkPoint* posPtr = posCount > 0 ? new SkPoint[posCount] : NULL; 894 int indx; 895 for (indx = 0; indx < posCount; indx++) { 896 posPtr[indx].fX = SkFloatToScalar(posArray[indx << 1]); 897 posPtr[indx].fY = SkFloatToScalar(posArray[(indx << 1) + 1]); 898 } 899 900 SkPaint::TextEncoding encoding = paint->getTextEncoding(); 901 paint->setTextEncoding(SkPaint::kUTF16_TextEncoding); 902 canvas->drawPosText(textArray + index, count << 1, posPtr, *paint); 903 paint->setTextEncoding(encoding); 904 905 if (text) { 906 env->ReleaseCharArrayElements(text, textArray, 0); 907 } 908 if (pos) { 909 env->ReleaseFloatArrayElements(pos, posArray, 0); 910 } 911 delete[] posPtr; 912 } 913 914 static void drawPosText__String_FPaint(JNIEnv* env, jobject, 915 SkCanvas* canvas, jstring text, 916 jfloatArray pos, 917 SkPaint* paint) { 918 const void* text_ = text ? env->GetStringChars(text, NULL) : NULL; 919 int byteLength = text ? env->GetStringLength(text) : 0; 920 float* posArray = pos ? env->GetFloatArrayElements(pos, NULL) : NULL; 921 int posCount = pos ? env->GetArrayLength(pos) >> 1: 0; 922 SkPoint* posPtr = posCount > 0 ? new SkPoint[posCount] : NULL; 923 924 for (int indx = 0; indx < posCount; indx++) { 925 posPtr[indx].fX = SkFloatToScalar(posArray[indx << 1]); 926 posPtr[indx].fY = SkFloatToScalar(posArray[(indx << 1) + 1]); 927 } 928 929 SkPaint::TextEncoding encoding = paint->getTextEncoding(); 930 paint->setTextEncoding(SkPaint::kUTF16_TextEncoding); 931 canvas->drawPosText(text_, byteLength << 1, posPtr, *paint); 932 paint->setTextEncoding(encoding); 933 934 if (text) { 935 env->ReleaseStringChars(text, (const jchar*) text_); 936 } 937 if (pos) { 938 env->ReleaseFloatArrayElements(pos, posArray, 0); 939 } 940 delete[] posPtr; 941 } 942 943 static void drawTextOnPath___CIIPathFFPaint(JNIEnv* env, jobject, 944 SkCanvas* canvas, jcharArray text, int index, int count, 945 SkPath* path, jfloat hOffset, jfloat vOffset, jint bidiFlags, SkPaint* paint) { 946 947 jchar* textArray = env->GetCharArrayElements(text, NULL); 948 TextLayout::drawTextOnPath(paint, textArray + index, count, bidiFlags, hOffset, vOffset, 949 path, canvas); 950 env->ReleaseCharArrayElements(text, textArray, 0); 951 } 952 953 static void drawTextOnPath__StringPathFFPaint(JNIEnv* env, jobject, 954 SkCanvas* canvas, jstring text, SkPath* path, 955 jfloat hOffset, jfloat vOffset, jint bidiFlags, SkPaint* paint) { 956 const jchar* text_ = env->GetStringChars(text, NULL); 957 int count = env->GetStringLength(text); 958 TextLayout::drawTextOnPath(paint, text_, count, bidiFlags, hOffset, vOffset, 959 path, canvas); 960 env->ReleaseStringChars(text, text_); 961 } 962 963 964 // This function is a mirror of SkCanvas::getClipBounds except that it does 965 // not outset the edge of the clip to account for anti-aliasing. There is 966 // a skia bug to investigate pushing this logic into back into skia. 967 // (see https://code.google.com/p/skia/issues/detail?id=1303) 968 static bool getHardClipBounds(SkCanvas* canvas, SkRect* bounds) { 969 SkIRect ibounds; 970 if (!canvas->getClipDeviceBounds(&ibounds)) { 971 return false; 972 } 973 974 SkMatrix inverse; 975 // if we can't invert the CTM, we can't return local clip bounds 976 if (!canvas->getTotalMatrix().invert(&inverse)) { 977 if (bounds) { 978 bounds->setEmpty(); 979 } 980 return false; 981 } 982 983 if (NULL != bounds) { 984 SkRect r = SkRect::Make(ibounds); 985 inverse.mapRect(bounds, r); 986 } 987 return true; 988 } 989 990 static bool getClipBounds(JNIEnv* env, jobject, SkCanvas* canvas, 991 jobject bounds) { 992 SkRect r; 993 SkIRect ir; 994 bool result = getHardClipBounds(canvas, &r); 995 996 if (!result) { 997 r.setEmpty(); 998 } 999 r.round(&ir); 1000 1001 (void)GraphicsJNI::irect_to_jrect(ir, env, bounds); 1002 return result; 1003 } 1004 1005 static void getCTM(JNIEnv* env, jobject, SkCanvas* canvas, 1006 SkMatrix* matrix) { 1007 *matrix = canvas->getTotalMatrix(); 1008 } 1009 }; 1010 1011 static JNINativeMethod gCanvasMethods[] = { 1012 {"finalizer", "(I)V", (void*) SkCanvasGlue::finalizer}, 1013 {"initRaster","(I)I", (void*) SkCanvasGlue::initRaster}, 1014 {"copyNativeCanvasState","(II)V", (void*) SkCanvasGlue::copyCanvasState}, 1015 {"isOpaque","()Z", (void*) SkCanvasGlue::isOpaque}, 1016 {"getWidth","()I", (void*) SkCanvasGlue::getWidth}, 1017 {"getHeight","()I", (void*) SkCanvasGlue::getHeight}, 1018 {"save","()I", (void*) SkCanvasGlue::saveAll}, 1019 {"save","(I)I", (void*) SkCanvasGlue::save}, 1020 {"native_saveLayer","(ILandroid/graphics/RectF;II)I", 1021 (void*) SkCanvasGlue::saveLayer}, 1022 {"native_saveLayer","(IFFFFII)I", (void*) SkCanvasGlue::saveLayer4F}, 1023 {"native_saveLayerAlpha","(ILandroid/graphics/RectF;II)I", 1024 (void*) SkCanvasGlue::saveLayerAlpha}, 1025 {"native_saveLayerAlpha","(IFFFFII)I", 1026 (void*) SkCanvasGlue::saveLayerAlpha4F}, 1027 {"restore","()V", (void*) SkCanvasGlue::restore}, 1028 {"getSaveCount","()I", (void*) SkCanvasGlue::getSaveCount}, 1029 {"restoreToCount","(I)V", (void*) SkCanvasGlue::restoreToCount}, 1030 {"translate","(FF)V", (void*) SkCanvasGlue::translate}, 1031 {"scale","(FF)V", (void*) SkCanvasGlue::scale__FF}, 1032 {"rotate","(F)V", (void*) SkCanvasGlue::rotate__F}, 1033 {"skew","(FF)V", (void*) SkCanvasGlue::skew__FF}, 1034 {"native_concat","(II)V", (void*) SkCanvasGlue::concat}, 1035 {"native_setMatrix","(II)V", (void*) SkCanvasGlue::setMatrix}, 1036 {"clipRect","(FFFF)Z", (void*) SkCanvasGlue::clipRect_FFFF}, 1037 {"clipRect","(IIII)Z", (void*) SkCanvasGlue::clipRect_IIII}, 1038 {"clipRect","(Landroid/graphics/RectF;)Z", 1039 (void*) SkCanvasGlue::clipRect_RectF}, 1040 {"clipRect","(Landroid/graphics/Rect;)Z", 1041 (void*) SkCanvasGlue::clipRect_Rect}, 1042 {"native_clipRect","(IFFFFI)Z", (void*) SkCanvasGlue::clipRect}, 1043 {"native_clipPath","(III)Z", (void*) SkCanvasGlue::clipPath}, 1044 {"native_clipRegion","(III)Z", (void*) SkCanvasGlue::clipRegion}, 1045 {"nativeSetDrawFilter", "(II)V", (void*) SkCanvasGlue::setDrawFilter}, 1046 {"native_getClipBounds","(ILandroid/graphics/Rect;)Z", 1047 (void*) SkCanvasGlue::getClipBounds}, 1048 {"native_getCTM", "(II)V", (void*)SkCanvasGlue::getCTM}, 1049 {"native_quickReject","(ILandroid/graphics/RectF;)Z", 1050 (void*) SkCanvasGlue::quickReject__RectF}, 1051 {"native_quickReject","(II)Z", (void*) SkCanvasGlue::quickReject__Path}, 1052 {"native_quickReject","(IFFFF)Z", (void*)SkCanvasGlue::quickReject__FFFF}, 1053 {"native_drawRGB","(IIII)V", (void*) SkCanvasGlue::drawRGB}, 1054 {"native_drawARGB","(IIIII)V", (void*) SkCanvasGlue::drawARGB}, 1055 {"native_drawColor","(II)V", (void*) SkCanvasGlue::drawColor__I}, 1056 {"native_drawColor","(III)V", (void*) SkCanvasGlue::drawColor__II}, 1057 {"native_drawPaint","(II)V", (void*) SkCanvasGlue::drawPaint}, 1058 {"drawPoint", "(FFLandroid/graphics/Paint;)V", 1059 (void*) SkCanvasGlue::drawPoint}, 1060 {"drawPoints", "([FIILandroid/graphics/Paint;)V", 1061 (void*) SkCanvasGlue::drawPoints}, 1062 {"drawLines", "([FIILandroid/graphics/Paint;)V", 1063 (void*) SkCanvasGlue::drawLines}, 1064 {"native_drawLine","(IFFFFI)V", (void*) SkCanvasGlue::drawLine__FFFFPaint}, 1065 {"native_drawRect","(ILandroid/graphics/RectF;I)V", 1066 (void*) SkCanvasGlue::drawRect__RectFPaint}, 1067 {"native_drawRect","(IFFFFI)V", (void*) SkCanvasGlue::drawRect__FFFFPaint}, 1068 {"native_drawOval","(ILandroid/graphics/RectF;I)V", 1069 (void*) SkCanvasGlue::drawOval}, 1070 {"native_drawCircle","(IFFFI)V", (void*) SkCanvasGlue::drawCircle}, 1071 {"native_drawArc","(ILandroid/graphics/RectF;FFZI)V", 1072 (void*) SkCanvasGlue::drawArc}, 1073 {"native_drawRoundRect","(ILandroid/graphics/RectF;FFI)V", 1074 (void*) SkCanvasGlue::drawRoundRect}, 1075 {"native_drawPath","(III)V", (void*) SkCanvasGlue::drawPath}, 1076 {"native_drawBitmap","(IIFFIIII)V", 1077 (void*) SkCanvasGlue::drawBitmap__BitmapFFPaint}, 1078 {"native_drawBitmap","(IILandroid/graphics/Rect;Landroid/graphics/RectF;III)V", 1079 (void*) SkCanvasGlue::drawBitmapRF}, 1080 {"native_drawBitmap","(IILandroid/graphics/Rect;Landroid/graphics/Rect;III)V", 1081 (void*) SkCanvasGlue::drawBitmapRR}, 1082 {"native_drawBitmap", "(I[IIIFFIIZI)V", 1083 (void*)SkCanvasGlue::drawBitmapArray}, 1084 {"nativeDrawBitmapMatrix", "(IIII)V", 1085 (void*)SkCanvasGlue::drawBitmapMatrix}, 1086 {"nativeDrawBitmapMesh", "(IIII[FI[III)V", 1087 (void*)SkCanvasGlue::drawBitmapMesh}, 1088 {"nativeDrawVertices", "(III[FI[FI[II[SIII)V", 1089 (void*)SkCanvasGlue::drawVertices}, 1090 {"native_drawText","(I[CIIFFII)V", 1091 (void*) SkCanvasGlue::drawText___CIIFFIPaint}, 1092 {"native_drawText","(ILjava/lang/String;IIFFII)V", 1093 (void*) SkCanvasGlue::drawText__StringIIFFIPaint}, 1094 {"native_drawTextRun","(I[CIIIIFFII)V", 1095 (void*) SkCanvasGlue::drawTextRun___CIIIIFFIPaint}, 1096 {"native_drawTextRun","(ILjava/lang/String;IIIIFFII)V", 1097 (void*) SkCanvasGlue::drawTextRun__StringIIIIFFIPaint}, 1098 {"native_drawPosText","(I[CII[FI)V", 1099 (void*) SkCanvasGlue::drawPosText___CII_FPaint}, 1100 {"native_drawPosText","(ILjava/lang/String;[FI)V", 1101 (void*) SkCanvasGlue::drawPosText__String_FPaint}, 1102 {"native_drawTextOnPath","(I[CIIIFFII)V", 1103 (void*) SkCanvasGlue::drawTextOnPath___CIIPathFFPaint}, 1104 {"native_drawTextOnPath","(ILjava/lang/String;IFFII)V", 1105 (void*) SkCanvasGlue::drawTextOnPath__StringPathFFPaint}, 1106 {"native_drawPicture", "(II)V", (void*) SkCanvasGlue::drawPicture}, 1107 1108 {"freeCaches", "()V", (void*) SkCanvasGlue::freeCaches}, 1109 1110 {"freeTextLayoutCaches", "()V", (void*) SkCanvasGlue::freeTextLayoutCaches} 1111 }; 1112 1113 /////////////////////////////////////////////////////////////////////////////// 1114 1115 #include <android_runtime/AndroidRuntime.h> 1116 1117 #define REG(env, name, array) \ 1118 result = android::AndroidRuntime::registerNativeMethods(env, name, array, \ 1119 SK_ARRAY_COUNT(array)); \ 1120 if (result < 0) return result 1121 1122 int register_android_graphics_Canvas(JNIEnv* env) { 1123 int result; 1124 1125 REG(env, "android/graphics/Canvas", gCanvasMethods); 1126 1127 return result; 1128 } 1129 1130 } 1131