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