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