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