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