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