Canvas.cpp revision 0965a3244b4c3009d08db2e084cdcb681ef66d26
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 39static 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 54namespace android { 55 56class SkCanvasGlue { 57public: 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 sp<TextLayoutCacheValue> value; 762#if USE_TEXT_LAYOUT_CACHE 763 value = gTextLayoutCache.getValue(paint, textArray, start, count, end, flags); 764 if (value == NULL) { 765 LOGE("Cannot get TextLayoutCache value"); 766 return ; 767 } 768#else 769 value = new TextLayoutCacheValue(); 770 value->computeValues(paint, textArray, start, count, end, flags); 771#endif 772 773#if DEBUG_GLYPHS 774 logGlyphs(value); 775#endif 776 777 doDrawGlyphs(canvas, value->getGlyphs(), 0, value->getGlyphsCount(), 778 x, y, flags, paint); 779 } 780 781 static void drawTextWithGlyphs(SkCanvas* canvas, const jchar* textArray, 782 int start, int count, int contextCount, 783 jfloat x, jfloat y, int flags, SkPaint* paint) { 784 785 sp<TextLayoutCacheValue> value; 786#if USE_TEXT_LAYOUT_CACHE 787 value = gTextLayoutCache.getValue(paint, textArray, start, count, contextCount, flags); 788 if (value == NULL) { 789 LOGE("Cannot get TextLayoutCache value"); 790 return ; 791 } 792#else 793 value = new TextLayoutCacheValue(); 794 value->computeValues(paint, textArray, start, count, contextCount, flags); 795#endif 796 797#if DEBUG_GLYPHS 798 logGlyphs(value); 799#endif 800 801 doDrawGlyphs(canvas, value->getGlyphs(), 0, value->getGlyphsCount(), 802 x, y, flags, paint); 803 } 804 805 static void doDrawGlyphs(SkCanvas* canvas, const jchar* glyphArray, int index, int count, 806 jfloat x, jfloat y, int flags, SkPaint* paint) { 807 // TODO: need to suppress this code after the GL renderer is modified for not 808 // copying the paint 809 810 // Save old text encoding 811 SkPaint::TextEncoding oldEncoding = paint->getTextEncoding(); 812 // Define Glyph encoding 813 paint->setTextEncoding(SkPaint::kGlyphID_TextEncoding); 814 815 canvas->drawText(glyphArray + index * 2, count * 2, x, y, *paint); 816 817 // Get back old encoding 818 paint->setTextEncoding(oldEncoding); 819 } 820 821 static void drawTextRun___CIIIIFFIPaint( 822 JNIEnv* env, jobject, SkCanvas* canvas, jcharArray text, int index, 823 int count, int contextIndex, int contextCount, 824 jfloat x, jfloat y, int dirFlags, SkPaint* paint) { 825 826 jchar* chars = env->GetCharArrayElements(text, NULL); 827#if RTL_USE_HARFBUZZ 828 drawTextWithGlyphs(canvas, chars + contextIndex, index - contextIndex, 829 count, contextCount, x, y, dirFlags, paint); 830#else 831 TextLayout::drawTextRun(paint, chars + contextIndex, index - contextIndex, 832 count, contextCount, dirFlags, x, y, canvas); 833#endif 834 env->ReleaseCharArrayElements(text, chars, JNI_ABORT); 835 } 836 837 static void drawTextRun__StringIIIIFFIPaint( 838 JNIEnv* env, jobject obj, SkCanvas* canvas, jstring text, jint start, 839 jint end, jint contextStart, jint contextEnd, 840 jfloat x, jfloat y, jint dirFlags, SkPaint* paint) { 841 842 jint count = end - start; 843 jint contextCount = contextEnd - contextStart; 844 const jchar* chars = env->GetStringChars(text, NULL); 845#if RTL_USE_HARFBUZZ 846 drawTextWithGlyphs(canvas, chars + contextStart, start - contextStart, 847 count, contextCount, x, y, dirFlags, paint); 848#else 849 TextLayout::drawTextRun(paint, chars + contextStart, start - contextStart, 850 count, contextCount, dirFlags, x, y, canvas); 851#endif 852 env->ReleaseStringChars(text, chars); 853 } 854 855 static void drawPosText___CII_FPaint(JNIEnv* env, jobject, SkCanvas* canvas, 856 jcharArray text, int index, int count, 857 jfloatArray pos, SkPaint* paint) { 858 jchar* textArray = text ? env->GetCharArrayElements(text, NULL) : NULL; 859 jsize textCount = text ? env->GetArrayLength(text) : NULL; 860 float* posArray = pos ? env->GetFloatArrayElements(pos, NULL) : NULL; 861 int posCount = pos ? env->GetArrayLength(pos) >> 1: 0; 862 SkPoint* posPtr = posCount > 0 ? new SkPoint[posCount] : NULL; 863 int indx; 864 for (indx = 0; indx < posCount; indx++) { 865 posPtr[indx].fX = SkFloatToScalar(posArray[indx << 1]); 866 posPtr[indx].fY = SkFloatToScalar(posArray[(indx << 1) + 1]); 867 } 868 canvas->drawPosText(textArray + index, count << 1, posPtr, *paint); 869 if (text) { 870 env->ReleaseCharArrayElements(text, textArray, 0); 871 } 872 if (pos) { 873 env->ReleaseFloatArrayElements(pos, posArray, 0); 874 } 875 delete[] posPtr; 876 } 877 878 static void drawPosText__String_FPaint(JNIEnv* env, jobject, 879 SkCanvas* canvas, jstring text, 880 jfloatArray pos, 881 SkPaint* paint) { 882 const void* text_ = text ? env->GetStringChars(text, NULL) : NULL; 883 int byteLength = text ? env->GetStringLength(text) : 0; 884 float* posArray = pos ? env->GetFloatArrayElements(pos, NULL) : NULL; 885 int posCount = pos ? env->GetArrayLength(pos) >> 1: 0; 886 SkPoint* posPtr = posCount > 0 ? new SkPoint[posCount] : NULL; 887 888 for (int indx = 0; indx < posCount; indx++) { 889 posPtr[indx].fX = SkFloatToScalar(posArray[indx << 1]); 890 posPtr[indx].fY = SkFloatToScalar(posArray[(indx << 1) + 1]); 891 } 892 canvas->drawPosText(text_, byteLength << 1, posPtr, *paint); 893 if (text) { 894 env->ReleaseStringChars(text, (const jchar*) text_); 895 } 896 if (pos) { 897 env->ReleaseFloatArrayElements(pos, posArray, 0); 898 } 899 delete[] posPtr; 900 } 901 902 static void drawTextOnPath___CIIPathFFPaint(JNIEnv* env, jobject, 903 SkCanvas* canvas, jcharArray text, int index, int count, 904 SkPath* path, jfloat hOffset, jfloat vOffset, jint bidiFlags, SkPaint* paint) { 905 906 jchar* textArray = env->GetCharArrayElements(text, NULL); 907 TextLayout::drawTextOnPath(paint, textArray + index, count, bidiFlags, hOffset, vOffset, 908 path, canvas); 909 env->ReleaseCharArrayElements(text, textArray, 0); 910 } 911 912 static void drawTextOnPath__StringPathFFPaint(JNIEnv* env, jobject, 913 SkCanvas* canvas, jstring text, SkPath* path, 914 jfloat hOffset, jfloat vOffset, jint bidiFlags, SkPaint* paint) { 915 const jchar* text_ = env->GetStringChars(text, NULL); 916 int count = env->GetStringLength(text); 917 TextLayout::drawTextOnPath(paint, text_, count, bidiFlags, hOffset, vOffset, 918 path, canvas); 919 env->ReleaseStringChars(text, text_); 920 } 921 922 static bool getClipBounds(JNIEnv* env, jobject, SkCanvas* canvas, 923 jobject bounds) { 924 SkRect r; 925 SkIRect ir; 926 bool result = canvas->getClipBounds(&r, SkCanvas::kBW_EdgeType); 927 928 r.round(&ir); 929 (void)GraphicsJNI::irect_to_jrect(ir, env, bounds); 930 return result; 931 } 932 933 static void getCTM(JNIEnv* env, jobject, SkCanvas* canvas, 934 SkMatrix* matrix) { 935 *matrix = canvas->getTotalMatrix(); 936 } 937}; 938 939static JNINativeMethod gCanvasMethods[] = { 940 {"finalizer", "(I)V", (void*) SkCanvasGlue::finalizer}, 941 {"initRaster","(I)I", (void*) SkCanvasGlue::initRaster}, 942 {"isOpaque","()Z", (void*) SkCanvasGlue::isOpaque}, 943 {"getWidth","()I", (void*) SkCanvasGlue::getWidth}, 944 {"getHeight","()I", (void*) SkCanvasGlue::getHeight}, 945 {"native_setBitmap","(II)V", (void*) SkCanvasGlue::setBitmap}, 946 {"save","()I", (void*) SkCanvasGlue::saveAll}, 947 {"save","(I)I", (void*) SkCanvasGlue::save}, 948 {"native_saveLayer","(ILandroid/graphics/RectF;II)I", 949 (void*) SkCanvasGlue::saveLayer}, 950 {"native_saveLayer","(IFFFFII)I", (void*) SkCanvasGlue::saveLayer4F}, 951 {"native_saveLayerAlpha","(ILandroid/graphics/RectF;II)I", 952 (void*) SkCanvasGlue::saveLayerAlpha}, 953 {"native_saveLayerAlpha","(IFFFFII)I", 954 (void*) SkCanvasGlue::saveLayerAlpha4F}, 955 {"restore","()V", (void*) SkCanvasGlue::restore}, 956 {"getSaveCount","()I", (void*) SkCanvasGlue::getSaveCount}, 957 {"restoreToCount","(I)V", (void*) SkCanvasGlue::restoreToCount}, 958 {"translate","(FF)V", (void*) SkCanvasGlue::translate}, 959 {"scale","(FF)V", (void*) SkCanvasGlue::scale__FF}, 960 {"rotate","(F)V", (void*) SkCanvasGlue::rotate__F}, 961 {"skew","(FF)V", (void*) SkCanvasGlue::skew__FF}, 962 {"native_concat","(II)V", (void*) SkCanvasGlue::concat}, 963 {"native_setMatrix","(II)V", (void*) SkCanvasGlue::setMatrix}, 964 {"clipRect","(FFFF)Z", (void*) SkCanvasGlue::clipRect_FFFF}, 965 {"clipRect","(IIII)Z", (void*) SkCanvasGlue::clipRect_IIII}, 966 {"clipRect","(Landroid/graphics/RectF;)Z", 967 (void*) SkCanvasGlue::clipRect_RectF}, 968 {"clipRect","(Landroid/graphics/Rect;)Z", 969 (void*) SkCanvasGlue::clipRect_Rect}, 970 {"native_clipRect","(IFFFFI)Z", (void*) SkCanvasGlue::clipRect}, 971 {"native_clipPath","(III)Z", (void*) SkCanvasGlue::clipPath}, 972 {"native_clipRegion","(III)Z", (void*) SkCanvasGlue::clipRegion}, 973 {"nativeSetDrawFilter", "(II)V", (void*) SkCanvasGlue::setDrawFilter}, 974 {"native_getClipBounds","(ILandroid/graphics/Rect;)Z", 975 (void*) SkCanvasGlue::getClipBounds}, 976 {"native_getCTM", "(II)V", (void*)SkCanvasGlue::getCTM}, 977 {"native_quickReject","(ILandroid/graphics/RectF;I)Z", 978 (void*) SkCanvasGlue::quickReject__RectFI}, 979 {"native_quickReject","(III)Z", (void*) SkCanvasGlue::quickReject__PathI}, 980 {"native_quickReject","(IFFFFI)Z", (void*)SkCanvasGlue::quickReject__FFFFI}, 981 {"native_drawRGB","(IIII)V", (void*) SkCanvasGlue::drawRGB}, 982 {"native_drawARGB","(IIIII)V", (void*) SkCanvasGlue::drawARGB}, 983 {"native_drawColor","(II)V", (void*) SkCanvasGlue::drawColor__I}, 984 {"native_drawColor","(III)V", (void*) SkCanvasGlue::drawColor__II}, 985 {"native_drawPaint","(II)V", (void*) SkCanvasGlue::drawPaint}, 986 {"drawPoint", "(FFLandroid/graphics/Paint;)V", 987 (void*) SkCanvasGlue::drawPoint}, 988 {"drawPoints", "([FIILandroid/graphics/Paint;)V", 989 (void*) SkCanvasGlue::drawPoints}, 990 {"drawLines", "([FIILandroid/graphics/Paint;)V", 991 (void*) SkCanvasGlue::drawLines}, 992 {"native_drawLine","(IFFFFI)V", (void*) SkCanvasGlue::drawLine__FFFFPaint}, 993 {"native_drawRect","(ILandroid/graphics/RectF;I)V", 994 (void*) SkCanvasGlue::drawRect__RectFPaint}, 995 {"native_drawRect","(IFFFFI)V", (void*) SkCanvasGlue::drawRect__FFFFPaint}, 996 {"native_drawOval","(ILandroid/graphics/RectF;I)V", 997 (void*) SkCanvasGlue::drawOval}, 998 {"native_drawCircle","(IFFFI)V", (void*) SkCanvasGlue::drawCircle}, 999 {"native_drawArc","(ILandroid/graphics/RectF;FFZI)V", 1000 (void*) SkCanvasGlue::drawArc}, 1001 {"native_drawRoundRect","(ILandroid/graphics/RectF;FFI)V", 1002 (void*) SkCanvasGlue::drawRoundRect}, 1003 {"native_drawPath","(III)V", (void*) SkCanvasGlue::drawPath}, 1004 {"native_drawBitmap","(IIFFIIII)V", 1005 (void*) SkCanvasGlue::drawBitmap__BitmapFFPaint}, 1006 {"native_drawBitmap","(IILandroid/graphics/Rect;Landroid/graphics/RectF;III)V", 1007 (void*) SkCanvasGlue::drawBitmapRF}, 1008 {"native_drawBitmap","(IILandroid/graphics/Rect;Landroid/graphics/Rect;III)V", 1009 (void*) SkCanvasGlue::drawBitmapRR}, 1010 {"native_drawBitmap", "(I[IIIFFIIZI)V", 1011 (void*)SkCanvasGlue::drawBitmapArray}, 1012 {"nativeDrawBitmapMatrix", "(IIII)V", 1013 (void*)SkCanvasGlue::drawBitmapMatrix}, 1014 {"nativeDrawBitmapMesh", "(IIII[FI[III)V", 1015 (void*)SkCanvasGlue::drawBitmapMesh}, 1016 {"nativeDrawVertices", "(III[FI[FI[II[SIII)V", 1017 (void*)SkCanvasGlue::drawVertices}, 1018 {"native_drawText","(I[CIIFFII)V", 1019 (void*) SkCanvasGlue::drawText___CIIFFIPaint}, 1020 {"native_drawText","(ILjava/lang/String;IIFFII)V", 1021 (void*) SkCanvasGlue::drawText__StringIIFFIPaint}, 1022 {"native_drawTextRun","(I[CIIIIFFII)V", 1023 (void*) SkCanvasGlue::drawTextRun___CIIIIFFIPaint}, 1024 {"native_drawTextRun","(ILjava/lang/String;IIIIFFII)V", 1025 (void*) SkCanvasGlue::drawTextRun__StringIIIIFFIPaint}, 1026 {"native_drawPosText","(I[CII[FI)V", 1027 (void*) SkCanvasGlue::drawPosText___CII_FPaint}, 1028 {"native_drawPosText","(ILjava/lang/String;[FI)V", 1029 (void*) SkCanvasGlue::drawPosText__String_FPaint}, 1030 {"native_drawTextOnPath","(I[CIIIFFII)V", 1031 (void*) SkCanvasGlue::drawTextOnPath___CIIPathFFPaint}, 1032 {"native_drawTextOnPath","(ILjava/lang/String;IFFII)V", 1033 (void*) SkCanvasGlue::drawTextOnPath__StringPathFFPaint}, 1034 {"native_drawPicture", "(II)V", (void*) SkCanvasGlue::drawPicture}, 1035 1036 {"freeCaches", "()V", (void*) SkCanvasGlue::freeCaches} 1037}; 1038 1039/////////////////////////////////////////////////////////////////////////////// 1040 1041#include <android_runtime/AndroidRuntime.h> 1042 1043#define REG(env, name, array) \ 1044 result = android::AndroidRuntime::registerNativeMethods(env, name, array, \ 1045 SK_ARRAY_COUNT(array)); \ 1046 if (result < 0) return result 1047 1048int register_android_graphics_Canvas(JNIEnv* env) { 1049 int result; 1050 1051 REG(env, "android/graphics/Canvas", gCanvasMethods); 1052 1053 return result; 1054} 1055 1056} 1057