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