Canvas.cpp revision e2dba02441b42afbae725109ac779877a4b72aa0
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 "SkPorterDuff.h" 27#include "SkShader.h" 28#include "SkTemplates.h" 29 30#define TIME_DRAWx 31 32static uint32_t get_thread_msec() { 33#if defined(HAVE_POSIX_CLOCKS) 34 struct timespec tm; 35 36 clock_gettime(CLOCK_THREAD_CPUTIME_ID, &tm); 37 38 return tm.tv_sec * 1000LL + tm.tv_nsec / 1000000; 39#else 40 struct timeval tv; 41 42 gettimeofday(&tv, NULL); 43 return tv.tv_sec * 1000LL + tv.tv_usec / 1000; 44#endif 45} 46 47namespace android { 48 49class SkCanvasGlue { 50public: 51 52 static void finalizer(JNIEnv* env, jobject clazz, SkCanvas* canvas) { 53 canvas->unref(); 54 } 55 56 static SkCanvas* initRaster(JNIEnv* env, jobject, SkBitmap* bitmap) { 57 return bitmap ? new SkCanvas(*bitmap) : new SkCanvas; 58 } 59 60 static SkCanvas* initGL(JNIEnv* env, jobject) { 61 return new SkGLCanvas; 62 } 63 64 static void freeCaches(JNIEnv* env, jobject) { 65 // these are called in no particular order 66 SkGLCanvas::DeleteAllTextures(); 67 SkImageRef_GlobalPool::SetRAMUsed(0); 68 SkGraphics::SetFontCacheUsed(0); 69 } 70 71 static jboolean isOpaque(JNIEnv* env, jobject jcanvas) { 72 NPE_CHECK_RETURN_ZERO(env, jcanvas); 73 SkCanvas* canvas = GraphicsJNI::getNativeCanvas(env, jcanvas); 74 75 /* 76 Currently we cannot support transparency in GL-based canvas' at 77 the view level. Therefore we cannot base our answer on the device's 78 bitmap, but need to hard-code the answer. If we relax this 79 limitation in views, we can simplify the following code as well. 80 81 Use the getViewport() call to find out if we're gl-based... 82 */ 83 if (canvas->getViewport(NULL)) { 84 return true; 85 } 86 87 // normal technique, rely on the device's bitmap for the answer 88 return canvas->getDevice()->accessBitmap(false).isOpaque(); 89 } 90 91 static int getWidth(JNIEnv* env, jobject jcanvas) { 92 NPE_CHECK_RETURN_ZERO(env, jcanvas); 93 SkCanvas* canvas = GraphicsJNI::getNativeCanvas(env, jcanvas); 94 return canvas->getDevice()->accessBitmap(false).width(); 95 } 96 97 static int getHeight(JNIEnv* env, jobject jcanvas) { 98 NPE_CHECK_RETURN_ZERO(env, jcanvas); 99 SkCanvas* canvas = GraphicsJNI::getNativeCanvas(env, jcanvas); 100 return canvas->getDevice()->accessBitmap(false).height(); 101 } 102 103 static void setViewport(JNIEnv* env, jobject, SkCanvas* canvas, 104 int width, int height) { 105 canvas->setViewport(width, height); 106 } 107 108 static void setBitmap(JNIEnv* env, jobject, SkCanvas* canvas, 109 SkBitmap* bitmap) { 110 canvas->setBitmapDevice(*bitmap); 111 } 112 113 static int saveAll(JNIEnv* env, jobject jcanvas) { 114 NPE_CHECK_RETURN_ZERO(env, jcanvas); 115 return GraphicsJNI::getNativeCanvas(env, jcanvas)->save(); 116 } 117 118 static int save(JNIEnv* env, jobject jcanvas, SkCanvas::SaveFlags flags) { 119 NPE_CHECK_RETURN_ZERO(env, jcanvas); 120 return GraphicsJNI::getNativeCanvas(env, jcanvas)->save(flags); 121 } 122 123 static int saveLayer(JNIEnv* env, jobject, SkCanvas* canvas, jobject bounds, 124 SkPaint* paint, int flags) { 125 SkRect* bounds_ = NULL; 126 SkRect storage; 127 if (bounds != NULL) { 128 GraphicsJNI::jrectf_to_rect(env, bounds, &storage); 129 bounds_ = &storage; 130 } 131 return canvas->saveLayer(bounds_, paint, (SkCanvas::SaveFlags)flags); 132 } 133 134 static int saveLayer4F(JNIEnv* env, jobject, SkCanvas* canvas, 135 jfloat l, jfloat t, jfloat r, jfloat b, 136 SkPaint* paint, int flags) { 137 SkRect bounds; 138 bounds.set(SkFloatToScalar(l), SkFloatToScalar(t), SkFloatToScalar(r), 139 SkFloatToScalar(b)); 140 return canvas->saveLayer(&bounds, paint, (SkCanvas::SaveFlags)flags); 141 } 142 143 static int saveLayerAlpha(JNIEnv* env, jobject, SkCanvas* canvas, 144 jobject bounds, int alpha, int flags) { 145 SkRect* bounds_ = NULL; 146 SkRect storage; 147 if (bounds != NULL) { 148 GraphicsJNI::jrectf_to_rect(env, bounds, &storage); 149 bounds_ = &storage; 150 } 151 return canvas->saveLayerAlpha(bounds_, alpha, 152 (SkCanvas::SaveFlags)flags); 153 } 154 155 static int saveLayerAlpha4F(JNIEnv* env, jobject, SkCanvas* canvas, 156 jfloat l, jfloat t, jfloat r, jfloat b, 157 int alpha, int flags) { 158 SkRect bounds; 159 bounds.set(SkFloatToScalar(l), SkFloatToScalar(t), SkFloatToScalar(r), 160 SkFloatToScalar(b)); 161 return canvas->saveLayerAlpha(&bounds, alpha, 162 (SkCanvas::SaveFlags)flags); 163 } 164 165 static void restore(JNIEnv* env, jobject jcanvas) { 166 NPE_CHECK_RETURN_VOID(env, jcanvas); 167 SkCanvas* canvas = GraphicsJNI::getNativeCanvas(env, jcanvas); 168 if (canvas->getSaveCount() <= 1) { // cannot restore anymore 169 doThrowISE(env, "Underflow in restore"); 170 return; 171 } 172 canvas->restore(); 173 } 174 175 static int getSaveCount(JNIEnv* env, jobject jcanvas) { 176 NPE_CHECK_RETURN_ZERO(env, jcanvas); 177 return GraphicsJNI::getNativeCanvas(env, jcanvas)->getSaveCount(); 178 } 179 180 static void restoreToCount(JNIEnv* env, jobject jcanvas, int restoreCount) { 181 NPE_CHECK_RETURN_VOID(env, jcanvas); 182 SkCanvas* canvas = GraphicsJNI::getNativeCanvas(env, jcanvas); 183 if (restoreCount < 1) { 184 doThrowIAE(env, "Underflow in restoreToCount"); 185 return; 186 } 187 canvas->restoreToCount(restoreCount); 188 } 189 190 static void translate(JNIEnv* env, jobject jcanvas, jfloat dx, jfloat dy) { 191 NPE_CHECK_RETURN_VOID(env, jcanvas); 192 SkScalar dx_ = SkFloatToScalar(dx); 193 SkScalar dy_ = SkFloatToScalar(dy); 194 (void)GraphicsJNI::getNativeCanvas(env, jcanvas)->translate(dx_, dy_); 195 } 196 197 static void scale__FF(JNIEnv* env, jobject jcanvas, jfloat sx, jfloat sy) { 198 NPE_CHECK_RETURN_VOID(env, jcanvas); 199 SkScalar sx_ = SkFloatToScalar(sx); 200 SkScalar sy_ = SkFloatToScalar(sy); 201 (void)GraphicsJNI::getNativeCanvas(env, jcanvas)->scale(sx_, sy_); 202 } 203 204 static void rotate__F(JNIEnv* env, jobject jcanvas, jfloat degrees) { 205 NPE_CHECK_RETURN_VOID(env, jcanvas); 206 SkScalar degrees_ = SkFloatToScalar(degrees); 207 (void)GraphicsJNI::getNativeCanvas(env, jcanvas)->rotate(degrees_); 208 } 209 210 static void skew__FF(JNIEnv* env, jobject jcanvas, jfloat sx, jfloat sy) { 211 NPE_CHECK_RETURN_VOID(env, jcanvas); 212 SkScalar sx_ = SkFloatToScalar(sx); 213 SkScalar sy_ = SkFloatToScalar(sy); 214 (void)GraphicsJNI::getNativeCanvas(env, jcanvas)->skew(sx_, sy_); 215 } 216 217 static void concat(JNIEnv* env, jobject, SkCanvas* canvas, 218 const SkMatrix* matrix) { 219 canvas->concat(*matrix); 220 } 221 222 static void setMatrix(JNIEnv* env, jobject, SkCanvas* canvas, 223 const SkMatrix* matrix) { 224 if (NULL == matrix) { 225 canvas->resetMatrix(); 226 } else { 227 canvas->setMatrix(*matrix); 228 } 229 } 230 231 static jboolean clipRect_FFFF(JNIEnv* env, jobject jcanvas, jfloat left, 232 jfloat top, jfloat right, jfloat bottom) { 233 NPE_CHECK_RETURN_ZERO(env, jcanvas); 234 SkRect r; 235 r.set(SkFloatToScalar(left), SkFloatToScalar(top), 236 SkFloatToScalar(right), SkFloatToScalar(bottom)); 237 SkCanvas* c = GraphicsJNI::getNativeCanvas(env, jcanvas); 238 return c->clipRect(r); 239 } 240 241 static jboolean clipRect_IIII(JNIEnv* env, jobject jcanvas, jint left, 242 jint top, jint right, jint bottom) { 243 NPE_CHECK_RETURN_ZERO(env, jcanvas); 244 SkRect r; 245 r.set(SkIntToScalar(left), SkIntToScalar(top), 246 SkIntToScalar(right), SkIntToScalar(bottom)); 247 return GraphicsJNI::getNativeCanvas(env, jcanvas)->clipRect(r); 248 } 249 250 static jboolean clipRect_RectF(JNIEnv* env, jobject jcanvas, jobject rectf) { 251 NPE_CHECK_RETURN_ZERO(env, jcanvas); 252 NPE_CHECK_RETURN_ZERO(env, rectf); 253 SkCanvas* c = GraphicsJNI::getNativeCanvas(env, jcanvas); 254 SkRect tmp; 255 return c->clipRect(*GraphicsJNI::jrectf_to_rect(env, rectf, &tmp)); 256 } 257 258 static jboolean clipRect_Rect(JNIEnv* env, jobject jcanvas, jobject rect) { 259 NPE_CHECK_RETURN_ZERO(env, jcanvas); 260 NPE_CHECK_RETURN_ZERO(env, rect); 261 SkCanvas* c = GraphicsJNI::getNativeCanvas(env, jcanvas); 262 SkRect tmp; 263 return c->clipRect(*GraphicsJNI::jrect_to_rect(env, rect, &tmp)); 264 } 265 266 static jboolean clipRect(JNIEnv* env, jobject, SkCanvas* canvas, 267 float left, float top, float right, float bottom, 268 int op) { 269 SkRect rect; 270 rect.set(SkFloatToScalar(left), SkFloatToScalar(top), 271 SkFloatToScalar(right), SkFloatToScalar(bottom)); 272 return canvas->clipRect(rect, (SkRegion::Op)op); 273 } 274 275 static jboolean clipPath(JNIEnv* env, jobject, SkCanvas* canvas, 276 SkPath* path, int op) { 277 return canvas->clipPath(*path, (SkRegion::Op)op); 278 } 279 280 static jboolean clipRegion(JNIEnv* env, jobject, SkCanvas* canvas, 281 SkRegion* deviceRgn, int op) { 282 return canvas->clipRegion(*deviceRgn, (SkRegion::Op)op); 283 } 284 285 static void setDrawFilter(JNIEnv* env, jobject, SkCanvas* canvas, 286 SkDrawFilter* filter) { 287 canvas->setDrawFilter(filter); 288 } 289 290 static jboolean quickReject__RectFI(JNIEnv* env, jobject, SkCanvas* canvas, 291 jobject rect, int edgetype) { 292 SkRect rect_; 293 GraphicsJNI::jrectf_to_rect(env, rect, &rect_); 294 return canvas->quickReject(rect_, (SkCanvas::EdgeType)edgetype); 295 } 296 297 static jboolean quickReject__PathI(JNIEnv* env, jobject, SkCanvas* canvas, 298 SkPath* path, int edgetype) { 299 return canvas->quickReject(*path, (SkCanvas::EdgeType)edgetype); 300 } 301 302 static jboolean quickReject__FFFFI(JNIEnv* env, jobject, SkCanvas* canvas, 303 jfloat left, jfloat top, jfloat right, 304 jfloat bottom, int edgetype) { 305 SkRect r; 306 r.set(SkFloatToScalar(left), SkFloatToScalar(top), 307 SkFloatToScalar(right), SkFloatToScalar(bottom)); 308 return canvas->quickReject(r, (SkCanvas::EdgeType)edgetype); 309 } 310 311 static void drawRGB(JNIEnv* env, jobject, SkCanvas* canvas, 312 jint r, jint g, jint b) { 313 canvas->drawARGB(0xFF, r, g, b); 314 } 315 316 static void drawARGB(JNIEnv* env, jobject, SkCanvas* canvas, 317 jint a, jint r, jint g, jint b) { 318 canvas->drawARGB(a, r, g, b); 319 } 320 321 static void drawColor__I(JNIEnv* env, jobject, SkCanvas* canvas, 322 jint color) { 323 canvas->drawColor(color); 324 } 325 326 static void drawColor__II(JNIEnv* env, jobject, SkCanvas* canvas, 327 jint color, SkPorterDuff::Mode mode) { 328 canvas->drawColor(color, SkPorterDuff::ToXfermodeMode(mode)); 329 } 330 331 static void drawPaint(JNIEnv* env, jobject, SkCanvas* canvas, 332 SkPaint* paint) { 333 canvas->drawPaint(*paint); 334 } 335 336 static void doPoints(JNIEnv* env, jobject jcanvas, jfloatArray jptsArray, 337 jint offset, jint count, jobject jpaint, 338 SkCanvas::PointMode mode) { 339 NPE_CHECK_RETURN_VOID(env, jcanvas); 340 NPE_CHECK_RETURN_VOID(env, jptsArray); 341 NPE_CHECK_RETURN_VOID(env, jpaint); 342 SkCanvas* canvas = GraphicsJNI::getNativeCanvas(env, jcanvas); 343 const SkPaint& paint = *GraphicsJNI::getNativePaint(env, jpaint); 344 345 AutoJavaFloatArray autoPts(env, jptsArray); 346 float* floats = autoPts.ptr(); 347 const int length = autoPts.length(); 348 349 if ((offset | count) < 0 || offset + count > length) { 350 doThrowAIOOBE(env); 351 return; 352 } 353 354 // now convert the floats into SkPoints 355 count >>= 1; // now it is the number of points 356 SkAutoSTMalloc<32, SkPoint> storage(count); 357 SkPoint* pts = storage.get(); 358 const float* src = floats + offset; 359 for (int i = 0; i < count; i++) { 360 pts[i].set(SkFloatToScalar(src[0]), SkFloatToScalar(src[1])); 361 src += 2; 362 } 363 canvas->drawPoints(mode, count, pts, paint); 364 } 365 366 static void drawPoints(JNIEnv* env, jobject jcanvas, jfloatArray jptsArray, 367 jint offset, jint count, jobject jpaint) { 368 doPoints(env, jcanvas, jptsArray, offset, count, jpaint, 369 SkCanvas::kPoints_PointMode); 370 } 371 372 static void drawLines(JNIEnv* env, jobject jcanvas, jfloatArray jptsArray, 373 jint offset, jint count, jobject jpaint) { 374 doPoints(env, jcanvas, jptsArray, offset, count, jpaint, 375 SkCanvas::kLines_PointMode); 376 } 377 378 static void drawPoint(JNIEnv* env, jobject jcanvas, float x, float y, 379 jobject jpaint) { 380 NPE_CHECK_RETURN_VOID(env, jcanvas); 381 NPE_CHECK_RETURN_VOID(env, jpaint); 382 SkCanvas* canvas = GraphicsJNI::getNativeCanvas(env, jcanvas); 383 const SkPaint& paint = *GraphicsJNI::getNativePaint(env, jpaint); 384 385 canvas->drawPoint(SkFloatToScalar(x), SkFloatToScalar(y), paint); 386 } 387 388 static void drawLine__FFFFPaint(JNIEnv* env, jobject, SkCanvas* canvas, 389 jfloat startX, jfloat startY, jfloat stopX, 390 jfloat stopY, SkPaint* paint) { 391 canvas->drawLine(SkFloatToScalar(startX), SkFloatToScalar(startY), 392 SkFloatToScalar(stopX), SkFloatToScalar(stopY), 393 *paint); 394 } 395 396 static void drawRect__RectFPaint(JNIEnv* env, jobject, SkCanvas* canvas, 397 jobject rect, SkPaint* paint) { 398 SkRect rect_; 399 GraphicsJNI::jrectf_to_rect(env, rect, &rect_); 400 canvas->drawRect(rect_, *paint); 401 } 402 403 static void drawRect__FFFFPaint(JNIEnv* env, jobject, SkCanvas* canvas, 404 jfloat left, jfloat top, jfloat right, 405 jfloat bottom, SkPaint* paint) { 406 SkScalar left_ = SkFloatToScalar(left); 407 SkScalar top_ = SkFloatToScalar(top); 408 SkScalar right_ = SkFloatToScalar(right); 409 SkScalar bottom_ = SkFloatToScalar(bottom); 410 canvas->drawRectCoords(left_, top_, right_, bottom_, *paint); 411 } 412 413 static void drawOval(JNIEnv* env, jobject, SkCanvas* canvas, jobject joval, 414 SkPaint* paint) { 415 SkRect oval; 416 GraphicsJNI::jrectf_to_rect(env, joval, &oval); 417 canvas->drawOval(oval, *paint); 418 } 419 420 static void drawCircle(JNIEnv* env, jobject, SkCanvas* canvas, jfloat cx, 421 jfloat cy, jfloat radius, SkPaint* paint) { 422 canvas->drawCircle(SkFloatToScalar(cx), SkFloatToScalar(cy), 423 SkFloatToScalar(radius), *paint); 424 } 425 426 static void drawArc(JNIEnv* env, jobject, SkCanvas* canvas, jobject joval, 427 jfloat startAngle, jfloat sweepAngle, 428 jboolean useCenter, SkPaint* paint) { 429 SkRect oval; 430 GraphicsJNI::jrectf_to_rect(env, joval, &oval); 431 canvas->drawArc(oval, SkFloatToScalar(startAngle), 432 SkFloatToScalar(sweepAngle), useCenter, *paint); 433 } 434 435 static void drawRoundRect(JNIEnv* env, jobject, SkCanvas* canvas, 436 jobject jrect, jfloat rx, jfloat ry, 437 SkPaint* paint) { 438 SkRect rect; 439 GraphicsJNI::jrectf_to_rect(env, jrect, &rect); 440 canvas->drawRoundRect(rect, SkFloatToScalar(rx), SkFloatToScalar(ry), 441 *paint); 442 } 443 444 static void drawPath(JNIEnv* env, jobject, SkCanvas* canvas, SkPath* path, 445 SkPaint* paint) { 446 canvas->drawPath(*path, *paint); 447 } 448 449 static void drawPicture(JNIEnv* env, jobject, SkCanvas* canvas, 450 SkPicture* picture) { 451 SkASSERT(canvas); 452 SkASSERT(picture); 453 454#ifdef TIME_DRAW 455 SkMSec now = get_thread_msec(); //SkTime::GetMSecs(); 456#endif 457 canvas->drawPicture(*picture); 458#ifdef TIME_DRAW 459 LOGD("---- picture playback %d ms\n", get_thread_msec() - now); 460#endif 461 } 462 463 static void drawBitmap__BitmapFFPaint(JNIEnv* env, jobject jcanvas, 464 SkCanvas* canvas, SkBitmap* bitmap, 465 jfloat left, jfloat top, 466 SkPaint* paint, jint canvasDensity, 467 jint bitmapDensity) { 468 SkScalar left_ = SkFloatToScalar(left); 469 SkScalar top_ = SkFloatToScalar(top); 470 471 if (canvasDensity == bitmapDensity || canvasDensity == 0 472 || bitmapDensity == 0) { 473 canvas->drawBitmap(*bitmap, left_, top_, paint); 474 } else { 475 canvas->save(); 476 SkScalar scale = SkFloatToScalar(canvasDensity / (float)bitmapDensity); 477 canvas->translate(left_, top_); 478 canvas->scale(scale, scale); 479 480 SkPaint filteredPaint; 481 if (paint) { 482 filteredPaint = *paint; 483 } 484 filteredPaint.setFilterBitmap(true); 485 486 canvas->drawBitmap(*bitmap, 0, 0, &filteredPaint); 487 488 canvas->restore(); 489 } 490 } 491 492 static void doDrawBitmap(JNIEnv* env, SkCanvas* canvas, SkBitmap* bitmap, 493 jobject srcIRect, const SkRect& dst, SkPaint* paint) { 494 SkIRect src, *srcPtr = NULL; 495 496 if (NULL != srcIRect) { 497 GraphicsJNI::jrect_to_irect(env, srcIRect, &src); 498 srcPtr = &src; 499 } 500 canvas->drawBitmapRect(*bitmap, srcPtr, dst, paint); 501 } 502 503 static void drawBitmapRF(JNIEnv* env, jobject, SkCanvas* canvas, 504 SkBitmap* bitmap, jobject srcIRect, 505 jobject dstRectF, SkPaint* paint) { 506 SkRect dst; 507 GraphicsJNI::jrectf_to_rect(env, dstRectF, &dst); 508 doDrawBitmap(env, canvas, bitmap, srcIRect, dst, paint); 509 } 510 511 static void drawBitmapRR(JNIEnv* env, jobject, SkCanvas* canvas, 512 SkBitmap* bitmap, jobject srcIRect, 513 jobject dstRect, SkPaint* paint) { 514 SkRect dst; 515 GraphicsJNI::jrect_to_rect(env, dstRect, &dst); 516 doDrawBitmap(env, canvas, bitmap, srcIRect, dst, paint); 517 } 518 519 static void drawBitmapArray(JNIEnv* env, jobject, SkCanvas* canvas, 520 jintArray jcolors, int offset, int stride, 521 jfloat x, jfloat y, int width, int height, 522 jboolean hasAlpha, SkPaint* paint) 523 { 524 SkBitmap bitmap; 525 526 bitmap.setConfig(hasAlpha ? SkBitmap::kARGB_8888_Config : 527 SkBitmap::kRGB_565_Config, width, height); 528 if (!bitmap.allocPixels()) { 529 return; 530 } 531 532 if (!GraphicsJNI::SetPixels(env, jcolors, offset, stride, 533 0, 0, width, height, bitmap)) { 534 return; 535 } 536 537 canvas->drawBitmap(bitmap, SkFloatToScalar(x), SkFloatToScalar(y), 538 paint); 539 } 540 541 static void drawBitmapMatrix(JNIEnv* env, jobject, SkCanvas* canvas, 542 const SkBitmap* bitmap, const SkMatrix* matrix, 543 const SkPaint* paint) { 544 canvas->drawBitmapMatrix(*bitmap, *matrix, paint); 545 } 546 547 static void drawBitmapMesh(JNIEnv* env, jobject, SkCanvas* canvas, 548 const SkBitmap* bitmap, int meshWidth, int meshHeight, 549 jfloatArray jverts, int vertIndex, jintArray jcolors, 550 int colorIndex, const SkPaint* paint) { 551 552 const int ptCount = (meshWidth + 1) * (meshHeight + 1); 553 const int indexCount = meshWidth * meshHeight * 6; 554 555 AutoJavaFloatArray vertA(env, jverts, vertIndex + (ptCount << 1)); 556 AutoJavaIntArray colorA(env, jcolors, colorIndex + ptCount); 557 558 /* Our temp storage holds 2 or 3 arrays. 559 texture points [ptCount * sizeof(SkPoint)] 560 optionally vertex points [ptCount * sizeof(SkPoint)] if we need a 561 copy to convert from float to fixed 562 indices [ptCount * sizeof(uint16_t)] 563 */ 564 ssize_t storageSize = ptCount * sizeof(SkPoint); // texs[] 565#ifdef SK_SCALAR_IS_FIXED 566 storageSize += ptCount * sizeof(SkPoint); // storage for verts 567#endif 568 storageSize += indexCount * sizeof(uint16_t); // indices[] 569 570 SkAutoMalloc storage(storageSize); 571 SkPoint* texs = (SkPoint*)storage.get(); 572 SkPoint* verts; 573 uint16_t* indices; 574#ifdef SK_SCALAR_IS_FLOAT 575 verts = (SkPoint*)(vertA.ptr() + vertIndex); 576 indices = (uint16_t*)(texs + ptCount); 577#else 578 verts = texs + ptCount; 579 indices = (uint16_t*)(verts + ptCount); 580 // convert floats to fixed 581 { 582 const float* src = vertA.ptr() + vertIndex; 583 for (int i = 0; i < ptCount; i++) { 584 verts[i].set(SkFloatToFixed(src[0]), SkFloatToFixed(src[1])); 585 src += 2; 586 } 587 } 588#endif 589 590 // cons up texture coordinates and indices 591 { 592 const SkScalar w = SkIntToScalar(bitmap->width()); 593 const SkScalar h = SkIntToScalar(bitmap->height()); 594 const SkScalar dx = w / meshWidth; 595 const SkScalar dy = h / meshHeight; 596 597 SkPoint* texsPtr = texs; 598 SkScalar y = 0; 599 for (int i = 0; i <= meshHeight; i++) { 600 if (i == meshHeight) { 601 y = h; // to ensure numerically we hit h exactly 602 } 603 SkScalar x = 0; 604 for (int j = 0; j < meshWidth; j++) { 605 texsPtr->set(x, y); 606 texsPtr += 1; 607 x += dx; 608 } 609 texsPtr->set(w, y); 610 texsPtr += 1; 611 y += dy; 612 } 613 SkASSERT(texsPtr - texs == ptCount); 614 } 615 616 // cons up indices 617 { 618 uint16_t* indexPtr = indices; 619 int index = 0; 620 for (int i = 0; i < meshHeight; i++) { 621 for (int j = 0; j < meshWidth; j++) { 622 // lower-left triangle 623 *indexPtr++ = index; 624 *indexPtr++ = index + meshWidth + 1; 625 *indexPtr++ = index + meshWidth + 2; 626 // upper-right triangle 627 *indexPtr++ = index; 628 *indexPtr++ = index + meshWidth + 2; 629 *indexPtr++ = index + 1; 630 // bump to the next cell 631 index += 1; 632 } 633 // bump to the next row 634 index += 1; 635 } 636 SkASSERT(indexPtr - indices == indexCount); 637 SkASSERT((char*)indexPtr - (char*)storage.get() == storageSize); 638 } 639 640 // double-check that we have legal indices 641#ifdef SK_DEBUG 642 { 643 for (int i = 0; i < indexCount; i++) { 644 SkASSERT((unsigned)indices[i] < (unsigned)ptCount); 645 } 646 } 647#endif 648 649 // cons-up a shader for the bitmap 650 SkPaint tmpPaint; 651 if (paint) { 652 tmpPaint = *paint; 653 } 654 SkShader* shader = SkShader::CreateBitmapShader(*bitmap, 655 SkShader::kClamp_TileMode, SkShader::kClamp_TileMode); 656 tmpPaint.setShader(shader)->safeUnref(); 657 658 canvas->drawVertices(SkCanvas::kTriangles_VertexMode, ptCount, verts, 659 texs, (const SkColor*)colorA.ptr(), NULL, indices, 660 indexCount, tmpPaint); 661 } 662 663 static void drawVertices(JNIEnv* env, jobject, SkCanvas* canvas, 664 SkCanvas::VertexMode mode, int vertexCount, 665 jfloatArray jverts, int vertIndex, 666 jfloatArray jtexs, int texIndex, 667 jintArray jcolors, int colorIndex, 668 jshortArray jindices, int indexIndex, 669 int indexCount, const SkPaint* paint) { 670 671 AutoJavaFloatArray vertA(env, jverts, vertIndex + vertexCount); 672 AutoJavaFloatArray texA(env, jtexs, texIndex + vertexCount); 673 AutoJavaIntArray colorA(env, jcolors, colorIndex + vertexCount); 674 AutoJavaShortArray indexA(env, jindices, indexIndex + indexCount); 675 676 const int ptCount = vertexCount >> 1; 677 678 SkPoint* verts; 679 SkPoint* texs = NULL; 680#ifdef SK_SCALAR_IS_FLOAT 681 verts = (SkPoint*)(vertA.ptr() + vertIndex); 682 if (jtexs != NULL) { 683 texs = (SkPoint*)(texA.ptr() + texIndex); 684 } 685#else 686 int count = ptCount; // for verts 687 if (jtexs != NULL) { 688 count += ptCount; // += for texs 689 } 690 SkAutoMalloc storage(count * sizeof(SkPoint)); 691 verts = (SkPoint*)storage.get(); 692 const float* src = vertA.ptr() + vertIndex; 693 for (int i = 0; i < ptCount; i++) { 694 verts[i].set(SkFloatToFixed(src[0]), SkFloatToFixed(src[1])); 695 src += 2; 696 } 697 if (jtexs != NULL) { 698 texs = verts + ptCount; 699 src = texA.ptr() + texIndex; 700 for (int i = 0; i < ptCount; i++) { 701 texs[i].set(SkFloatToFixed(src[0]), SkFloatToFixed(src[1])); 702 src += 2; 703 } 704 } 705#endif 706 707 const SkColor* colors = NULL; 708 const uint16_t* indices = NULL; 709 if (jcolors != NULL) { 710 colors = (const SkColor*)(colorA.ptr() + colorIndex); 711 } 712 if (jindices != NULL) { 713 indices = (const uint16_t*)(indexA.ptr() + indexIndex); 714 } 715 716 canvas->drawVertices(mode, ptCount, verts, texs, colors, NULL, 717 indices, indexCount, *paint); 718 } 719 720 static void drawText___CIIFFPaint(JNIEnv* env, jobject, SkCanvas* canvas, 721 jcharArray text, int index, int count, 722 jfloat x, jfloat y, SkPaint* paint) { 723 jchar* textArray = env->GetCharArrayElements(text, NULL); 724 jsize textCount = env->GetArrayLength(text); 725 SkScalar x_ = SkFloatToScalar(x); 726 SkScalar y_ = SkFloatToScalar(y); 727 canvas->drawText(textArray + index, count << 1, x_, y_, *paint); 728 env->ReleaseCharArrayElements(text, textArray, 0); 729 } 730 731 static void drawText__StringIIFFPaint(JNIEnv* env, jobject, 732 SkCanvas* canvas, jstring text, int start, int end, 733 jfloat x, jfloat y, SkPaint* paint) { 734 const void* text_ = env->GetStringChars(text, NULL); 735 SkScalar x_ = SkFloatToScalar(x); 736 SkScalar y_ = SkFloatToScalar(y); 737 canvas->drawText((const uint16_t*)text_ + start, (end - start) << 1, 738 x_, y_, *paint); 739 env->ReleaseStringChars(text, (const jchar*) text_); 740 } 741 742 static void drawString(JNIEnv* env, jobject canvas, jstring text, 743 jfloat x, jfloat y, jobject paint) { 744 NPE_CHECK_RETURN_VOID(env, canvas); 745 NPE_CHECK_RETURN_VOID(env, paint); 746 NPE_CHECK_RETURN_VOID(env, text); 747 size_t count = env->GetStringLength(text); 748 if (0 == count) { 749 return; 750 } 751 const jchar* text_ = env->GetStringChars(text, NULL); 752 SkCanvas* c = GraphicsJNI::getNativeCanvas(env, canvas); 753 c->drawText(text_, count << 1, SkFloatToScalar(x), SkFloatToScalar(y), 754 *GraphicsJNI::getNativePaint(env, paint)); 755 env->ReleaseStringChars(text, text_); 756 } 757 758 static void drawPosText___CII_FPaint(JNIEnv* env, jobject, SkCanvas* canvas, 759 jcharArray text, int index, int count, 760 jfloatArray pos, SkPaint* paint) { 761 jchar* textArray = text ? env->GetCharArrayElements(text, NULL) : NULL; 762 jsize textCount = text ? env->GetArrayLength(text) : NULL; 763 float* posArray = pos ? env->GetFloatArrayElements(pos, NULL) : NULL; 764 int posCount = pos ? env->GetArrayLength(pos) >> 1: 0; 765 SkPoint* posPtr = posCount > 0 ? new SkPoint[posCount] : NULL; 766 int indx; 767 for (indx = 0; indx < posCount; indx++) { 768 posPtr[indx].fX = SkFloatToScalar(posArray[indx << 1]); 769 posPtr[indx].fY = SkFloatToScalar(posArray[(indx << 1) + 1]); 770 } 771 canvas->drawPosText(textArray + index, 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","(IIFFIII)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