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