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