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