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