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