Canvas.cpp revision 54b6cfa9a9e5b861a9930af873580d6dc20f773c
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, 458 SkCanvas* canvas, SkBitmap* bitmap, 459 jfloat left, jfloat top, 460 SkPaint* paint) { 461 SkScalar left_ = SkFloatToScalar(left); 462 SkScalar top_ = SkFloatToScalar(top); 463 canvas->drawBitmap(*bitmap, left_, top_, paint); 464 } 465 466 static void doDrawBitmap(JNIEnv* env, SkCanvas* canvas, SkBitmap* bitmap, 467 jobject srcIRect, const SkRect& dst, SkPaint* paint) { 468 SkIRect src, *srcPtr = NULL; 469 470 if (NULL != srcIRect) { 471 GraphicsJNI::jrect_to_irect(env, srcIRect, &src); 472 srcPtr = &src; 473 } 474 canvas->drawBitmapRect(*bitmap, srcPtr, dst, paint); 475 } 476 477 static void drawBitmapRF(JNIEnv* env, jobject, SkCanvas* canvas, 478 SkBitmap* bitmap, jobject srcIRect, 479 jobject dstRectF, SkPaint* paint) { 480 SkRect dst; 481 GraphicsJNI::jrectf_to_rect(env, dstRectF, &dst); 482 doDrawBitmap(env, canvas, bitmap, srcIRect, dst, paint); 483 } 484 485 static void drawBitmapRR(JNIEnv* env, jobject, SkCanvas* canvas, 486 SkBitmap* bitmap, jobject srcIRect, 487 jobject dstRect, SkPaint* paint) { 488 SkRect dst; 489 GraphicsJNI::jrect_to_rect(env, dstRect, &dst); 490 doDrawBitmap(env, canvas, bitmap, srcIRect, dst, paint); 491 } 492 493 static void drawBitmapArray(JNIEnv* env, jobject, SkCanvas* canvas, 494 jintArray jcolors, int offset, int stride, 495 int x, int y, int width, int height, 496 jboolean hasAlpha, SkPaint* paint) 497 { 498 SkBitmap bitmap; 499 500 bitmap.setConfig(hasAlpha ? SkBitmap::kARGB_8888_Config : 501 SkBitmap::kRGB_565_Config, width, height); 502 if (!bitmap.allocPixels()) { 503 return; 504 } 505 506 if (!GraphicsJNI::SetPixels(env, jcolors, offset, stride, 507 0, 0, width, height, bitmap)) { 508 return; 509 } 510 511 canvas->drawBitmap(bitmap, SkIntToScalar(x), SkIntToScalar(y), paint); 512 } 513 514 static void drawBitmapMatrix(JNIEnv* env, jobject, SkCanvas* canvas, 515 const SkBitmap* bitmap, const SkMatrix* matrix, 516 const SkPaint* paint) { 517 canvas->drawBitmapMatrix(*bitmap, *matrix, paint); 518 } 519 520 static void drawBitmapMesh(JNIEnv* env, jobject, SkCanvas* canvas, 521 const SkBitmap* bitmap, int meshWidth, int meshHeight, 522 jfloatArray jverts, int vertIndex, jintArray jcolors, 523 int colorIndex, const SkPaint* paint) { 524 525 const int ptCount = (meshWidth + 1) * (meshHeight + 1); 526 const int indexCount = meshWidth * meshHeight * 6; 527 528 AutoJavaFloatArray vertA(env, jverts, vertIndex + (ptCount << 1)); 529 AutoJavaIntArray colorA(env, jcolors, colorIndex + ptCount); 530 531 /* Our temp storage holds 2 or 3 arrays. 532 texture points [ptCount * sizeof(SkPoint)] 533 optionally vertex points [ptCount * sizeof(SkPoint)] if we need a 534 copy to convert from float to fixed 535 indices [ptCount * sizeof(uint16_t)] 536 */ 537 ssize_t storageSize = ptCount * sizeof(SkPoint); // texs[] 538#ifdef SK_SCALAR_IS_FIXED 539 storageSize += ptCount * sizeof(SkPoint); // storage for verts 540#endif 541 storageSize += indexCount * sizeof(uint16_t); // indices[] 542 543 SkAutoMalloc storage(storageSize); 544 SkPoint* texs = (SkPoint*)storage.get(); 545 SkPoint* verts; 546 uint16_t* indices; 547#ifdef SK_SCALAR_IS_FLOAT 548 verts = (SkPoint*)(vertA.ptr() + vertIndex); 549 indices = (uint16_t*)(texs + ptCount); 550#else 551 verts = texs + ptCount; 552 indices = (uint16_t*)(verts + ptCount); 553 // convert floats to fixed 554 { 555 const float* src = vertA.ptr() + vertIndex; 556 for (int i = 0; i < ptCount; i++) { 557 verts[i].set(SkFloatToFixed(src[0]), SkFloatToFixed(src[1])); 558 src += 2; 559 } 560 } 561#endif 562 563 // cons up texture coordinates and indices 564 { 565 const SkScalar w = SkIntToScalar(bitmap->width()); 566 const SkScalar h = SkIntToScalar(bitmap->height()); 567 const SkScalar dx = w / meshWidth; 568 const SkScalar dy = h / meshHeight; 569 570 SkPoint* texsPtr = texs; 571 SkScalar y = 0; 572 for (int i = 0; i <= meshHeight; i++) { 573 if (i == meshHeight) { 574 y = h; // to ensure numerically we hit h exactly 575 } 576 SkScalar x = 0; 577 for (int j = 0; j < meshWidth; j++) { 578 texsPtr->set(x, y); 579 texsPtr += 1; 580 x += dx; 581 } 582 texsPtr->set(w, y); 583 texsPtr += 1; 584 y += dy; 585 } 586 SkASSERT(texsPtr - texs == ptCount); 587 } 588 589 // cons up indices 590 { 591 uint16_t* indexPtr = indices; 592 int index = 0; 593 for (int i = 0; i < meshHeight; i++) { 594 for (int j = 0; j < meshWidth; j++) { 595 // lower-left triangle 596 *indexPtr++ = index; 597 *indexPtr++ = index + meshWidth + 1; 598 *indexPtr++ = index + meshWidth + 2; 599 // upper-right triangle 600 *indexPtr++ = index; 601 *indexPtr++ = index + meshWidth + 2; 602 *indexPtr++ = index + 1; 603 // bump to the next cell 604 index += 1; 605 } 606 // bump to the next row 607 index += 1; 608 } 609 SkASSERT(indexPtr - indices == indexCount); 610 SkASSERT((char*)indexPtr - (char*)storage.get() == storageSize); 611 } 612 613 // double-check that we have legal indices 614#ifdef SK_DEBUG 615 { 616 for (int i = 0; i < indexCount; i++) { 617 SkASSERT((unsigned)indices[i] < (unsigned)ptCount); 618 } 619 } 620#endif 621 622 // cons-up a shader for the bitmap 623 SkPaint tmpPaint; 624 if (paint) { 625 tmpPaint = *paint; 626 } 627 SkShader* shader = SkShader::CreateBitmapShader(*bitmap, 628 SkShader::kClamp_TileMode, SkShader::kClamp_TileMode); 629 tmpPaint.setShader(shader)->safeUnref(); 630 631 canvas->drawVertices(SkCanvas::kTriangles_VertexMode, ptCount, verts, 632 texs, (const SkColor*)colorA.ptr(), NULL, indices, 633 indexCount, tmpPaint); 634 } 635 636 static void drawVertices(JNIEnv* env, jobject, SkCanvas* canvas, 637 SkCanvas::VertexMode mode, int vertexCount, 638 jfloatArray jverts, int vertIndex, 639 jfloatArray jtexs, int texIndex, 640 jintArray jcolors, int colorIndex, 641 jshortArray jindices, int indexIndex, 642 int indexCount, const SkPaint* paint) { 643 644 AutoJavaFloatArray vertA(env, jverts, vertIndex + vertexCount); 645 AutoJavaFloatArray texA(env, jtexs, texIndex + vertexCount); 646 AutoJavaIntArray colorA(env, jcolors, colorIndex + vertexCount); 647 AutoJavaShortArray indexA(env, jindices, indexIndex + indexCount); 648 649 const int ptCount = vertexCount >> 1; 650 651 SkPoint* verts; 652 SkPoint* texs = NULL; 653#ifdef SK_SCALAR_IS_FLOAT 654 verts = (SkPoint*)(vertA.ptr() + vertIndex); 655 if (jtexs != NULL) { 656 texs = (SkPoint*)(texA.ptr() + texIndex); 657 } 658#else 659 int count = ptCount; // for verts 660 if (jtexs != NULL) { 661 count += ptCount; // += for texs 662 } 663 SkAutoMalloc storage(count * sizeof(SkPoint)); 664 verts = (SkPoint*)storage.get(); 665 const float* src = vertA.ptr() + vertIndex; 666 for (int i = 0; i < ptCount; i++) { 667 verts[i].set(SkFloatToFixed(src[0]), SkFloatToFixed(src[1])); 668 src += 2; 669 } 670 if (jtexs != NULL) { 671 texs = verts + ptCount; 672 src = texA.ptr() + texIndex; 673 for (int i = 0; i < ptCount; i++) { 674 texs[i].set(SkFloatToFixed(src[0]), SkFloatToFixed(src[1])); 675 src += 2; 676 } 677 } 678#endif 679 680 const SkColor* colors = NULL; 681 const uint16_t* indices = NULL; 682 if (jcolors != NULL) { 683 colors = (const SkColor*)(colorA.ptr() + colorIndex); 684 } 685 if (jindices != NULL) { 686 indices = (const uint16_t*)(indexA.ptr() + indexIndex); 687 } 688 689 canvas->drawVertices(mode, ptCount, verts, texs, colors, NULL, 690 indices, indexCount, *paint); 691 } 692 693 static void drawText___CIIFFPaint(JNIEnv* env, jobject, SkCanvas* canvas, 694 jcharArray text, int index, int count, 695 jfloat x, jfloat y, SkPaint* paint) { 696 jchar* textArray = env->GetCharArrayElements(text, NULL); 697 jsize textCount = env->GetArrayLength(text); 698 SkScalar x_ = SkFloatToScalar(x); 699 SkScalar y_ = SkFloatToScalar(y); 700 textArray += index; 701 canvas->drawText(textArray, count << 1, x_, y_, *paint); 702 env->ReleaseCharArrayElements(text, textArray, 0); 703 } 704 705 static void drawText__StringIIFFPaint(JNIEnv* env, jobject, 706 SkCanvas* canvas, jstring text, int start, int end, 707 jfloat x, jfloat y, SkPaint* paint) { 708 const void* text_ = env->GetStringChars(text, NULL); 709 SkScalar x_ = SkFloatToScalar(x); 710 SkScalar y_ = SkFloatToScalar(y); 711 canvas->drawText((const uint16_t*)text_ + start, (end - start) << 1, 712 x_, y_, *paint); 713 env->ReleaseStringChars(text, (const jchar*) text_); 714 } 715 716 static void drawString(JNIEnv* env, jobject canvas, jstring text, 717 jfloat x, jfloat y, jobject paint) { 718 NPE_CHECK_RETURN_VOID(env, canvas); 719 NPE_CHECK_RETURN_VOID(env, paint); 720 NPE_CHECK_RETURN_VOID(env, text); 721 size_t count = env->GetStringLength(text); 722 if (0 == count) { 723 return; 724 } 725 const jchar* text_ = env->GetStringChars(text, NULL); 726 SkCanvas* c = GraphicsJNI::getNativeCanvas(env, canvas); 727 c->drawText(text_, count << 1, SkFloatToScalar(x), SkFloatToScalar(y), 728 *GraphicsJNI::getNativePaint(env, paint)); 729 env->ReleaseStringChars(text, text_); 730 } 731 732 static void drawPosText___CII_FPaint(JNIEnv* env, jobject, SkCanvas* canvas, 733 jcharArray text, int index, int count, 734 jfloatArray pos, SkPaint* paint) { 735 jchar* textArray = text ? env->GetCharArrayElements(text, NULL) : NULL; 736 jsize textCount = text ? env->GetArrayLength(text) : NULL; 737 float* posArray = pos ? env->GetFloatArrayElements(pos, NULL) : NULL; 738 int posCount = pos ? env->GetArrayLength(pos) >> 1: 0; 739 SkPoint* posPtr = posCount > 0 ? new SkPoint[posCount] : NULL; 740 int indx; 741 for (indx = 0; indx < posCount; indx++) { 742 posPtr[indx].fX = SkFloatToScalar(posArray[indx << 1]); 743 posPtr[indx].fY = SkFloatToScalar(posArray[(indx << 1) + 1]); 744 } 745 textArray += index; 746 canvas->drawPosText(textArray, count << 1, posPtr, *paint); 747 if (text) { 748 env->ReleaseCharArrayElements(text, textArray, 0); 749 } 750 if (pos) { 751 env->ReleaseFloatArrayElements(pos, posArray, 0); 752 } 753 delete[] posPtr; 754 } 755 756 static void drawPosText__String_FPaint(JNIEnv* env, jobject, 757 SkCanvas* canvas, jstring text, 758 jfloatArray pos, SkPaint* paint) { 759 const void* text_ = text ? env->GetStringChars(text, NULL) : NULL; 760 int byteLength = text ? env->GetStringLength(text) : 0; 761 float* posArray = pos ? env->GetFloatArrayElements(pos, NULL) : NULL; 762 int posCount = pos ? env->GetArrayLength(pos) >> 1: 0; 763 SkPoint* posPtr = posCount > 0 ? new SkPoint[posCount] : NULL; 764 765 for (int indx = 0; indx < posCount; indx++) { 766 posPtr[indx].fX = SkFloatToScalar(posArray[indx << 1]); 767 posPtr[indx].fY = SkFloatToScalar(posArray[(indx << 1) + 1]); 768 } 769 canvas->drawPosText(text_, byteLength << 1, posPtr, *paint); 770 if (text) { 771 env->ReleaseStringChars(text, (const jchar*) text_); 772 } 773 if (pos) { 774 env->ReleaseFloatArrayElements(pos, posArray, 0); 775 } 776 delete[] posPtr; 777 } 778 779 static void drawTextOnPath___CIIPathFFPaint(JNIEnv* env, jobject, 780 SkCanvas* canvas, jcharArray text, int index, int count, 781 SkPath* path, jfloat hOffset, jfloat vOffset, SkPaint* paint) { 782 783 jchar* textArray = env->GetCharArrayElements(text, NULL); 784 canvas->drawTextOnPathHV(textArray + index, count << 1, *path, 785 SkFloatToScalar(hOffset), SkFloatToScalar(vOffset), *paint); 786 env->ReleaseCharArrayElements(text, textArray, 0); 787 } 788 789 static void drawTextOnPath__StringPathFFPaint(JNIEnv* env, jobject, 790 SkCanvas* canvas, jstring text, SkPath* path, 791 jfloat hOffset, jfloat vOffset, SkPaint* paint) { 792 const jchar* text_ = env->GetStringChars(text, NULL); 793 int byteLength = env->GetStringLength(text) << 1; 794 canvas->drawTextOnPathHV(text_, byteLength, *path, 795 SkFloatToScalar(hOffset), SkFloatToScalar(vOffset), *paint); 796 env->ReleaseStringChars(text, text_); 797 } 798 799 static bool getClipBounds(JNIEnv* env, jobject, SkCanvas* canvas, 800 jobject bounds) { 801 SkRect r; 802 SkIRect ir; 803 bool result = canvas->getClipBounds(&r); 804 805 r.round(&ir); 806 (void)GraphicsJNI::irect_to_jrect(ir, env, bounds); 807 return result; 808 } 809 810 static void getCTM(JNIEnv* env, jobject, SkCanvas* canvas, 811 SkMatrix* matrix) { 812 *matrix = canvas->getTotalMatrix(); 813 } 814}; 815 816/////////////////////////////////////////////////////////////////////////////// 817 818static JNINativeMethod gCanvasMethods[] = { 819 {"finalizer", "(I)V", (void*) SkCanvasGlue::finalizer}, 820 {"initRaster","(I)I", (void*) SkCanvasGlue::initRaster}, 821 {"initGL","()I", (void*) SkCanvasGlue::initGL}, 822 {"isOpaque","()Z", (void*) SkCanvasGlue::isOpaque}, 823 {"getWidth","()I", (void*) SkCanvasGlue::getWidth}, 824 {"getHeight","()I", (void*) SkCanvasGlue::getHeight}, 825 {"native_setBitmap","(II)V", (void*) SkCanvasGlue::setBitmap}, 826 {"nativeSetViewport", "(III)V", (void*) SkCanvasGlue::setViewport}, 827 {"save","()I", (void*) SkCanvasGlue::saveAll}, 828 {"save","(I)I", (void*) SkCanvasGlue::save}, 829 {"native_saveLayer","(ILandroid/graphics/RectF;II)I", 830 (void*) SkCanvasGlue::saveLayer}, 831 {"native_saveLayer","(IFFFFII)I", (void*) SkCanvasGlue::saveLayer4F}, 832 {"native_saveLayerAlpha","(ILandroid/graphics/RectF;II)I", 833 (void*) SkCanvasGlue::saveLayerAlpha}, 834 {"native_saveLayerAlpha","(IFFFFII)I", 835 (void*) SkCanvasGlue::saveLayerAlpha4F}, 836 {"restore","()V", (void*) SkCanvasGlue::restore}, 837 {"getSaveCount","()I", (void*) SkCanvasGlue::getSaveCount}, 838 {"restoreToCount","(I)V", (void*) SkCanvasGlue::restoreToCount}, 839 {"translate","(FF)V", (void*) SkCanvasGlue::translate}, 840 {"scale","(FF)V", (void*) SkCanvasGlue::scale__FF}, 841 {"rotate","(F)V", (void*) SkCanvasGlue::rotate__F}, 842 {"skew","(FF)V", (void*) SkCanvasGlue::skew__FF}, 843 {"native_concat","(II)V", (void*) SkCanvasGlue::concat}, 844 {"native_setMatrix","(II)V", (void*) SkCanvasGlue::setMatrix}, 845 {"clipRect","(FFFF)Z", (void*) SkCanvasGlue::clipRect_FFFF}, 846 {"clipRect","(IIII)Z", (void*) SkCanvasGlue::clipRect_IIII}, 847 {"clipRect","(Landroid/graphics/RectF;)Z", 848 (void*) SkCanvasGlue::clipRect_RectF}, 849 {"clipRect","(Landroid/graphics/Rect;)Z", 850 (void*) SkCanvasGlue::clipRect_Rect}, 851 {"native_clipRect","(IFFFFI)Z", (void*) SkCanvasGlue::clipRect}, 852 {"native_clipPath","(III)Z", (void*) SkCanvasGlue::clipPath}, 853 {"native_clipRegion","(III)Z", (void*) SkCanvasGlue::clipRegion}, 854 {"nativeSetDrawFilter", "(II)V", (void*) SkCanvasGlue::setDrawFilter}, 855 {"native_getClipBounds","(ILandroid/graphics/Rect;)Z", 856 (void*) SkCanvasGlue::getClipBounds}, 857 {"native_getCTM", "(II)V", (void*)SkCanvasGlue::getCTM}, 858 {"native_quickReject","(ILandroid/graphics/RectF;I)Z", 859 (void*) SkCanvasGlue::quickReject__RectFI}, 860 {"native_quickReject","(III)Z", (void*) SkCanvasGlue::quickReject__PathI}, 861 {"native_quickReject","(IFFFFI)Z", (void*)SkCanvasGlue::quickReject__FFFFI}, 862 {"native_drawRGB","(IIII)V", (void*) SkCanvasGlue::drawRGB}, 863 {"native_drawARGB","(IIIII)V", (void*) SkCanvasGlue::drawARGB}, 864 {"native_drawColor","(II)V", (void*) SkCanvasGlue::drawColor__I}, 865 {"native_drawColor","(III)V", (void*) SkCanvasGlue::drawColor__II}, 866 {"native_drawPaint","(II)V", (void*) SkCanvasGlue::drawPaint}, 867 {"drawPoint", "(FFLandroid/graphics/Paint;)V", 868 (void*) SkCanvasGlue::drawPoint}, 869 {"drawPoints", "([FIILandroid/graphics/Paint;)V", 870 (void*) SkCanvasGlue::drawPoints}, 871 {"drawLines", "([FIILandroid/graphics/Paint;)V", 872 (void*) SkCanvasGlue::drawLines}, 873 {"native_drawLine","(IFFFFI)V", (void*) SkCanvasGlue::drawLine__FFFFPaint}, 874 {"native_drawRect","(ILandroid/graphics/RectF;I)V", 875 (void*) SkCanvasGlue::drawRect__RectFPaint}, 876 {"native_drawRect","(IFFFFI)V", (void*) SkCanvasGlue::drawRect__FFFFPaint}, 877 {"native_drawOval","(ILandroid/graphics/RectF;I)V", 878 (void*) SkCanvasGlue::drawOval}, 879 {"native_drawCircle","(IFFFI)V", (void*) SkCanvasGlue::drawCircle}, 880 {"native_drawArc","(ILandroid/graphics/RectF;FFZI)V", 881 (void*) SkCanvasGlue::drawArc}, 882 {"native_drawRoundRect","(ILandroid/graphics/RectF;FFI)V", 883 (void*) SkCanvasGlue::drawRoundRect}, 884 {"native_drawPath","(III)V", (void*) SkCanvasGlue::drawPath}, 885 {"native_drawBitmap","(IIFFI)V", 886 (void*) SkCanvasGlue::drawBitmap__BitmapFFPaint}, 887 {"native_drawBitmap","(IILandroid/graphics/Rect;Landroid/graphics/RectF;I)V", 888 (void*) SkCanvasGlue::drawBitmapRF}, 889 {"native_drawBitmap","(IILandroid/graphics/Rect;Landroid/graphics/Rect;I)V", 890 (void*) SkCanvasGlue::drawBitmapRR}, 891 {"native_drawBitmap", "(I[IIIIIIIZI)V", 892 (void*)SkCanvasGlue::drawBitmapArray}, 893 894 {"nativeDrawBitmapMatrix", "(IIII)V", 895 (void*)SkCanvasGlue::drawBitmapMatrix}, 896 {"nativeDrawBitmapMesh", "(IIII[FI[III)V", 897 (void*)SkCanvasGlue::drawBitmapMesh}, 898 {"nativeDrawVertices", "(III[FI[FI[II[SIII)V", 899 (void*)SkCanvasGlue::drawVertices}, 900 {"native_drawText","(I[CIIFFI)V", 901 (void*) SkCanvasGlue::drawText___CIIFFPaint}, 902 {"native_drawText","(ILjava/lang/String;IIFFI)V", 903 (void*) SkCanvasGlue::drawText__StringIIFFPaint}, 904 {"drawText","(Ljava/lang/String;FFLandroid/graphics/Paint;)V", 905 (void*) SkCanvasGlue::drawString}, 906 {"native_drawPosText","(I[CII[FI)V", 907 (void*) SkCanvasGlue::drawPosText___CII_FPaint}, 908 {"native_drawPosText","(ILjava/lang/String;[FI)V", 909 (void*) SkCanvasGlue::drawPosText__String_FPaint}, 910 {"native_drawTextOnPath","(I[CIIIFFI)V", 911 (void*) SkCanvasGlue::drawTextOnPath___CIIPathFFPaint}, 912 {"native_drawTextOnPath","(ILjava/lang/String;IFFI)V", 913 (void*) SkCanvasGlue::drawTextOnPath__StringPathFFPaint}, 914 {"native_drawPicture", "(II)V", (void*) SkCanvasGlue::drawPicture}, 915 916 {"freeGlCaches", "()V", (void*) SkCanvasGlue::freeGlCaches} 917}; 918 919#include <android_runtime/AndroidRuntime.h> 920 921#define REG(env, name, array) \ 922 result = android::AndroidRuntime::registerNativeMethods(env, name, array, \ 923 SK_ARRAY_COUNT(array)); \ 924 if (result < 0) return result 925 926int register_android_graphics_Canvas(JNIEnv* env) { 927 int result; 928 929 REG(env, "android/graphics/Canvas", gCanvasMethods); 930 931 return result; 932} 933 934} 935