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