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