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