Canvas.cpp revision 0c702b88c5d0d4380930b920f5be6e66dd95a0d8
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#include "SkBoundaryPatch.h" 31#include "SkMeshUtils.h" 32 33#include "unicode/ubidi.h" 34#include "unicode/ushape.h" 35 36// temporary for debugging 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 enum { 62 kDirection_LTR = 0, 63 kDirection_RTL = 1 64 }; 65 66 enum { 67 kDirection_Mask = 0x1 68 }; 69 70 enum { 71 kBidi_LTR = 0, 72 kBidi_RTL = 1, 73 kBidi_Default_LTR = 2, 74 kBidi_Default_RTL = 3, 75 kBidi_Force_LTR = 4, 76 kBidi_Force_RTL = 5 77 }; 78 79 static void finalizer(JNIEnv* env, jobject clazz, SkCanvas* canvas) { 80 canvas->unref(); 81 } 82 83 static SkCanvas* initRaster(JNIEnv* env, jobject, SkBitmap* bitmap) { 84 return bitmap ? new SkCanvas(*bitmap) : new SkCanvas; 85 } 86 87 static SkCanvas* initGL(JNIEnv* env, jobject) { 88 return new SkGLCanvas; 89 } 90 91 static void freeCaches(JNIEnv* env, jobject) { 92 // these are called in no particular order 93 SkGLCanvas::DeleteAllTextures(); 94 SkImageRef_GlobalPool::SetRAMUsed(0); 95 SkGraphics::SetFontCacheUsed(0); 96 } 97 98 static jboolean isOpaque(JNIEnv* env, jobject jcanvas) { 99 NPE_CHECK_RETURN_ZERO(env, jcanvas); 100 SkCanvas* canvas = GraphicsJNI::getNativeCanvas(env, jcanvas); 101 102 /* 103 Currently we cannot support transparency in GL-based canvas' at 104 the view level. Therefore we cannot base our answer on the device's 105 bitmap, but need to hard-code the answer. If we relax this 106 limitation in views, we can simplify the following code as well. 107 108 Use the getViewport() call to find out if we're gl-based... 109 */ 110 if (canvas->getViewport(NULL)) { 111 return true; 112 } 113 114 // normal technique, rely on the device's bitmap for the answer 115 return canvas->getDevice()->accessBitmap(false).isOpaque(); 116 } 117 118 static int getWidth(JNIEnv* env, jobject jcanvas) { 119 NPE_CHECK_RETURN_ZERO(env, jcanvas); 120 SkCanvas* canvas = GraphicsJNI::getNativeCanvas(env, jcanvas); 121 return canvas->getDevice()->accessBitmap(false).width(); 122 } 123 124 static int getHeight(JNIEnv* env, jobject jcanvas) { 125 NPE_CHECK_RETURN_ZERO(env, jcanvas); 126 SkCanvas* canvas = GraphicsJNI::getNativeCanvas(env, jcanvas); 127 return canvas->getDevice()->accessBitmap(false).height(); 128 } 129 130 static void setViewport(JNIEnv* env, jobject, SkCanvas* canvas, 131 int width, int height) { 132 canvas->setViewport(width, height); 133 } 134 135 static void setBitmap(JNIEnv* env, jobject, SkCanvas* canvas, 136 SkBitmap* bitmap) { 137 canvas->setBitmapDevice(*bitmap); 138 } 139 140 static int saveAll(JNIEnv* env, jobject jcanvas) { 141 NPE_CHECK_RETURN_ZERO(env, jcanvas); 142 return GraphicsJNI::getNativeCanvas(env, jcanvas)->save(); 143 } 144 145 static int save(JNIEnv* env, jobject jcanvas, SkCanvas::SaveFlags flags) { 146 NPE_CHECK_RETURN_ZERO(env, jcanvas); 147 return GraphicsJNI::getNativeCanvas(env, jcanvas)->save(flags); 148 } 149 150 static int saveLayer(JNIEnv* env, jobject, SkCanvas* canvas, jobject bounds, 151 SkPaint* paint, int flags) { 152 SkRect* bounds_ = NULL; 153 SkRect storage; 154 if (bounds != NULL) { 155 GraphicsJNI::jrectf_to_rect(env, bounds, &storage); 156 bounds_ = &storage; 157 } 158 return canvas->saveLayer(bounds_, paint, (SkCanvas::SaveFlags)flags); 159 } 160 161 static int saveLayer4F(JNIEnv* env, jobject, SkCanvas* canvas, 162 jfloat l, jfloat t, jfloat r, jfloat b, 163 SkPaint* paint, int flags) { 164 SkRect bounds; 165 bounds.set(SkFloatToScalar(l), SkFloatToScalar(t), SkFloatToScalar(r), 166 SkFloatToScalar(b)); 167 return canvas->saveLayer(&bounds, paint, (SkCanvas::SaveFlags)flags); 168 } 169 170 static int saveLayerAlpha(JNIEnv* env, jobject, SkCanvas* canvas, 171 jobject bounds, int alpha, int flags) { 172 SkRect* bounds_ = NULL; 173 SkRect storage; 174 if (bounds != NULL) { 175 GraphicsJNI::jrectf_to_rect(env, bounds, &storage); 176 bounds_ = &storage; 177 } 178 return canvas->saveLayerAlpha(bounds_, alpha, 179 (SkCanvas::SaveFlags)flags); 180 } 181 182 static int saveLayerAlpha4F(JNIEnv* env, jobject, SkCanvas* canvas, 183 jfloat l, jfloat t, jfloat r, jfloat b, 184 int alpha, int flags) { 185 SkRect bounds; 186 bounds.set(SkFloatToScalar(l), SkFloatToScalar(t), SkFloatToScalar(r), 187 SkFloatToScalar(b)); 188 return canvas->saveLayerAlpha(&bounds, alpha, 189 (SkCanvas::SaveFlags)flags); 190 } 191 192 static void restore(JNIEnv* env, jobject jcanvas) { 193 NPE_CHECK_RETURN_VOID(env, jcanvas); 194 SkCanvas* canvas = GraphicsJNI::getNativeCanvas(env, jcanvas); 195 if (canvas->getSaveCount() <= 1) { // cannot restore anymore 196 doThrowISE(env, "Underflow in restore"); 197 return; 198 } 199 canvas->restore(); 200 } 201 202 static int getSaveCount(JNIEnv* env, jobject jcanvas) { 203 NPE_CHECK_RETURN_ZERO(env, jcanvas); 204 return GraphicsJNI::getNativeCanvas(env, jcanvas)->getSaveCount(); 205 } 206 207 static void restoreToCount(JNIEnv* env, jobject jcanvas, int restoreCount) { 208 NPE_CHECK_RETURN_VOID(env, jcanvas); 209 SkCanvas* canvas = GraphicsJNI::getNativeCanvas(env, jcanvas); 210 if (restoreCount < 1) { 211 doThrowIAE(env, "Underflow in restoreToCount"); 212 return; 213 } 214 canvas->restoreToCount(restoreCount); 215 } 216 217 static void translate(JNIEnv* env, jobject jcanvas, jfloat dx, jfloat dy) { 218 NPE_CHECK_RETURN_VOID(env, jcanvas); 219 SkScalar dx_ = SkFloatToScalar(dx); 220 SkScalar dy_ = SkFloatToScalar(dy); 221 (void)GraphicsJNI::getNativeCanvas(env, jcanvas)->translate(dx_, dy_); 222 } 223 224 static void scale__FF(JNIEnv* env, jobject jcanvas, jfloat sx, jfloat sy) { 225 NPE_CHECK_RETURN_VOID(env, jcanvas); 226 SkScalar sx_ = SkFloatToScalar(sx); 227 SkScalar sy_ = SkFloatToScalar(sy); 228 (void)GraphicsJNI::getNativeCanvas(env, jcanvas)->scale(sx_, sy_); 229 } 230 231 static void rotate__F(JNIEnv* env, jobject jcanvas, jfloat degrees) { 232 NPE_CHECK_RETURN_VOID(env, jcanvas); 233 SkScalar degrees_ = SkFloatToScalar(degrees); 234 (void)GraphicsJNI::getNativeCanvas(env, jcanvas)->rotate(degrees_); 235 } 236 237 static void skew__FF(JNIEnv* env, jobject jcanvas, jfloat sx, jfloat sy) { 238 NPE_CHECK_RETURN_VOID(env, jcanvas); 239 SkScalar sx_ = SkFloatToScalar(sx); 240 SkScalar sy_ = SkFloatToScalar(sy); 241 (void)GraphicsJNI::getNativeCanvas(env, jcanvas)->skew(sx_, sy_); 242 } 243 244 static void concat(JNIEnv* env, jobject, SkCanvas* canvas, 245 const SkMatrix* matrix) { 246 canvas->concat(*matrix); 247 } 248 249 static void setMatrix(JNIEnv* env, jobject, SkCanvas* canvas, 250 const SkMatrix* matrix) { 251 if (NULL == matrix) { 252 canvas->resetMatrix(); 253 } else { 254 canvas->setMatrix(*matrix); 255 } 256 } 257 258 static jboolean clipRect_FFFF(JNIEnv* env, jobject jcanvas, jfloat left, 259 jfloat top, jfloat right, jfloat bottom) { 260 NPE_CHECK_RETURN_ZERO(env, jcanvas); 261 SkRect r; 262 r.set(SkFloatToScalar(left), SkFloatToScalar(top), 263 SkFloatToScalar(right), SkFloatToScalar(bottom)); 264 SkCanvas* c = GraphicsJNI::getNativeCanvas(env, jcanvas); 265 return c->clipRect(r); 266 } 267 268 static jboolean clipRect_IIII(JNIEnv* env, jobject jcanvas, jint left, 269 jint top, jint right, jint bottom) { 270 NPE_CHECK_RETURN_ZERO(env, jcanvas); 271 SkRect r; 272 r.set(SkIntToScalar(left), SkIntToScalar(top), 273 SkIntToScalar(right), SkIntToScalar(bottom)); 274 return GraphicsJNI::getNativeCanvas(env, jcanvas)->clipRect(r); 275 } 276 277 static jboolean clipRect_RectF(JNIEnv* env, jobject jcanvas, jobject rectf) { 278 NPE_CHECK_RETURN_ZERO(env, jcanvas); 279 NPE_CHECK_RETURN_ZERO(env, rectf); 280 SkCanvas* c = GraphicsJNI::getNativeCanvas(env, jcanvas); 281 SkRect tmp; 282 return c->clipRect(*GraphicsJNI::jrectf_to_rect(env, rectf, &tmp)); 283 } 284 285 static jboolean clipRect_Rect(JNIEnv* env, jobject jcanvas, jobject rect) { 286 NPE_CHECK_RETURN_ZERO(env, jcanvas); 287 NPE_CHECK_RETURN_ZERO(env, rect); 288 SkCanvas* c = GraphicsJNI::getNativeCanvas(env, jcanvas); 289 SkRect tmp; 290 return c->clipRect(*GraphicsJNI::jrect_to_rect(env, rect, &tmp)); 291 } 292 293 static jboolean clipRect(JNIEnv* env, jobject, SkCanvas* canvas, 294 float left, float top, float right, float bottom, 295 int op) { 296 SkRect rect; 297 rect.set(SkFloatToScalar(left), SkFloatToScalar(top), 298 SkFloatToScalar(right), SkFloatToScalar(bottom)); 299 return canvas->clipRect(rect, (SkRegion::Op)op); 300 } 301 302 static jboolean clipPath(JNIEnv* env, jobject, SkCanvas* canvas, 303 SkPath* path, int op) { 304 return canvas->clipPath(*path, (SkRegion::Op)op); 305 } 306 307 static jboolean clipRegion(JNIEnv* env, jobject, SkCanvas* canvas, 308 SkRegion* deviceRgn, int op) { 309 return canvas->clipRegion(*deviceRgn, (SkRegion::Op)op); 310 } 311 312 static void setDrawFilter(JNIEnv* env, jobject, SkCanvas* canvas, 313 SkDrawFilter* filter) { 314 canvas->setDrawFilter(filter); 315 } 316 317 static jboolean quickReject__RectFI(JNIEnv* env, jobject, SkCanvas* canvas, 318 jobject rect, int edgetype) { 319 SkRect rect_; 320 GraphicsJNI::jrectf_to_rect(env, rect, &rect_); 321 return canvas->quickReject(rect_, (SkCanvas::EdgeType)edgetype); 322 } 323 324 static jboolean quickReject__PathI(JNIEnv* env, jobject, SkCanvas* canvas, 325 SkPath* path, int edgetype) { 326 return canvas->quickReject(*path, (SkCanvas::EdgeType)edgetype); 327 } 328 329 static jboolean quickReject__FFFFI(JNIEnv* env, jobject, SkCanvas* canvas, 330 jfloat left, jfloat top, jfloat right, 331 jfloat bottom, int edgetype) { 332 SkRect r; 333 r.set(SkFloatToScalar(left), SkFloatToScalar(top), 334 SkFloatToScalar(right), SkFloatToScalar(bottom)); 335 return canvas->quickReject(r, (SkCanvas::EdgeType)edgetype); 336 } 337 338 static void drawRGB(JNIEnv* env, jobject, SkCanvas* canvas, 339 jint r, jint g, jint b) { 340 canvas->drawARGB(0xFF, r, g, b); 341 } 342 343 static void drawARGB(JNIEnv* env, jobject, SkCanvas* canvas, 344 jint a, jint r, jint g, jint b) { 345 canvas->drawARGB(a, r, g, b); 346 } 347 348 static void drawColor__I(JNIEnv* env, jobject, SkCanvas* canvas, 349 jint color) { 350 canvas->drawColor(color); 351 } 352 353 static void drawColor__II(JNIEnv* env, jobject, SkCanvas* canvas, 354 jint color, SkPorterDuff::Mode mode) { 355 canvas->drawColor(color, SkPorterDuff::ToXfermodeMode(mode)); 356 } 357 358 static void drawPaint(JNIEnv* env, jobject, SkCanvas* canvas, 359 SkPaint* paint) { 360 canvas->drawPaint(*paint); 361 } 362 363 static void doPoints(JNIEnv* env, jobject jcanvas, jfloatArray jptsArray, 364 jint offset, jint count, jobject jpaint, 365 SkCanvas::PointMode mode) { 366 NPE_CHECK_RETURN_VOID(env, jcanvas); 367 NPE_CHECK_RETURN_VOID(env, jptsArray); 368 NPE_CHECK_RETURN_VOID(env, jpaint); 369 SkCanvas* canvas = GraphicsJNI::getNativeCanvas(env, jcanvas); 370 const SkPaint& paint = *GraphicsJNI::getNativePaint(env, jpaint); 371 372 AutoJavaFloatArray autoPts(env, jptsArray); 373 float* floats = autoPts.ptr(); 374 const int length = autoPts.length(); 375 376 if ((offset | count) < 0 || offset + count > length) { 377 doThrowAIOOBE(env); 378 return; 379 } 380 381 // now convert the floats into SkPoints 382 count >>= 1; // now it is the number of points 383 SkAutoSTMalloc<32, SkPoint> storage(count); 384 SkPoint* pts = storage.get(); 385 const float* src = floats + offset; 386 for (int i = 0; i < count; i++) { 387 pts[i].set(SkFloatToScalar(src[0]), SkFloatToScalar(src[1])); 388 src += 2; 389 } 390 canvas->drawPoints(mode, count, pts, paint); 391 } 392 393 static void drawPoints(JNIEnv* env, jobject jcanvas, jfloatArray jptsArray, 394 jint offset, jint count, jobject jpaint) { 395 doPoints(env, jcanvas, jptsArray, offset, count, jpaint, 396 SkCanvas::kPoints_PointMode); 397 } 398 399 static void drawLines(JNIEnv* env, jobject jcanvas, jfloatArray jptsArray, 400 jint offset, jint count, jobject jpaint) { 401 doPoints(env, jcanvas, jptsArray, offset, count, jpaint, 402 SkCanvas::kLines_PointMode); 403 } 404 405 static void drawPoint(JNIEnv* env, jobject jcanvas, float x, float y, 406 jobject jpaint) { 407 NPE_CHECK_RETURN_VOID(env, jcanvas); 408 NPE_CHECK_RETURN_VOID(env, jpaint); 409 SkCanvas* canvas = GraphicsJNI::getNativeCanvas(env, jcanvas); 410 const SkPaint& paint = *GraphicsJNI::getNativePaint(env, jpaint); 411 412 canvas->drawPoint(SkFloatToScalar(x), SkFloatToScalar(y), paint); 413 } 414 415 static void drawLine__FFFFPaint(JNIEnv* env, jobject, SkCanvas* canvas, 416 jfloat startX, jfloat startY, jfloat stopX, 417 jfloat stopY, SkPaint* paint) { 418 canvas->drawLine(SkFloatToScalar(startX), SkFloatToScalar(startY), 419 SkFloatToScalar(stopX), SkFloatToScalar(stopY), 420 *paint); 421 } 422 423 static void drawRect__RectFPaint(JNIEnv* env, jobject, SkCanvas* canvas, 424 jobject rect, SkPaint* paint) { 425 SkRect rect_; 426 GraphicsJNI::jrectf_to_rect(env, rect, &rect_); 427 canvas->drawRect(rect_, *paint); 428 } 429 430 static void drawRect__FFFFPaint(JNIEnv* env, jobject, SkCanvas* canvas, 431 jfloat left, jfloat top, jfloat right, 432 jfloat bottom, SkPaint* paint) { 433 SkScalar left_ = SkFloatToScalar(left); 434 SkScalar top_ = SkFloatToScalar(top); 435 SkScalar right_ = SkFloatToScalar(right); 436 SkScalar bottom_ = SkFloatToScalar(bottom); 437 canvas->drawRectCoords(left_, top_, right_, bottom_, *paint); 438 } 439 440 static void drawOval(JNIEnv* env, jobject, SkCanvas* canvas, jobject joval, 441 SkPaint* paint) { 442 SkRect oval; 443 GraphicsJNI::jrectf_to_rect(env, joval, &oval); 444 canvas->drawOval(oval, *paint); 445 } 446 447 static void drawCircle(JNIEnv* env, jobject, SkCanvas* canvas, jfloat cx, 448 jfloat cy, jfloat radius, SkPaint* paint) { 449 canvas->drawCircle(SkFloatToScalar(cx), SkFloatToScalar(cy), 450 SkFloatToScalar(radius), *paint); 451 } 452 453 static void drawArc(JNIEnv* env, jobject, SkCanvas* canvas, jobject joval, 454 jfloat startAngle, jfloat sweepAngle, 455 jboolean useCenter, SkPaint* paint) { 456 SkRect oval; 457 GraphicsJNI::jrectf_to_rect(env, joval, &oval); 458 canvas->drawArc(oval, SkFloatToScalar(startAngle), 459 SkFloatToScalar(sweepAngle), useCenter, *paint); 460 } 461 462 static void drawRoundRect(JNIEnv* env, jobject, SkCanvas* canvas, 463 jobject jrect, jfloat rx, jfloat ry, 464 SkPaint* paint) { 465 SkRect rect; 466 GraphicsJNI::jrectf_to_rect(env, jrect, &rect); 467 canvas->drawRoundRect(rect, SkFloatToScalar(rx), SkFloatToScalar(ry), 468 *paint); 469 } 470 471 static void drawPath(JNIEnv* env, jobject, SkCanvas* canvas, SkPath* path, 472 SkPaint* paint) { 473 canvas->drawPath(*path, *paint); 474 } 475 476 static void drawPicture(JNIEnv* env, jobject, SkCanvas* canvas, 477 SkPicture* picture) { 478 SkASSERT(canvas); 479 SkASSERT(picture); 480 481#ifdef TIME_DRAW 482 SkMSec now = get_thread_msec(); //SkTime::GetMSecs(); 483#endif 484 canvas->drawPicture(*picture); 485#ifdef TIME_DRAW 486 LOGD("---- picture playback %d ms\n", get_thread_msec() - now); 487#endif 488 } 489 490 static void drawBitmap__BitmapFFPaint(JNIEnv* env, jobject jcanvas, 491 SkCanvas* canvas, SkBitmap* bitmap, 492 jfloat left, jfloat top, 493 SkPaint* paint, jint canvasDensity, 494 jint screenDensity, jint bitmapDensity) { 495 SkScalar left_ = SkFloatToScalar(left); 496 SkScalar top_ = SkFloatToScalar(top); 497 498 if (canvasDensity == bitmapDensity || canvasDensity == 0 499 || bitmapDensity == 0) { 500 if (screenDensity != 0 && screenDensity != bitmapDensity) { 501 SkPaint filteredPaint; 502 if (paint) { 503 filteredPaint = *paint; 504 } 505 filteredPaint.setFilterBitmap(true); 506 canvas->drawBitmap(*bitmap, left_, top_, &filteredPaint); 507 } else { 508 canvas->drawBitmap(*bitmap, left_, top_, paint); 509 } 510 } else { 511 canvas->save(); 512 SkScalar scale = SkFloatToScalar(canvasDensity / (float)bitmapDensity); 513 canvas->translate(left_, top_); 514 canvas->scale(scale, scale); 515 516 SkPaint filteredPaint; 517 if (paint) { 518 filteredPaint = *paint; 519 } 520 filteredPaint.setFilterBitmap(true); 521 522 canvas->drawBitmap(*bitmap, 0, 0, &filteredPaint); 523 524 canvas->restore(); 525 } 526 } 527 528 static void doDrawBitmap(JNIEnv* env, SkCanvas* canvas, SkBitmap* bitmap, 529 jobject srcIRect, const SkRect& dst, SkPaint* paint, 530 jint screenDensity, jint bitmapDensity) { 531 SkIRect src, *srcPtr = NULL; 532 533 if (NULL != srcIRect) { 534 GraphicsJNI::jrect_to_irect(env, srcIRect, &src); 535 srcPtr = &src; 536 } 537 538 if (screenDensity != 0 && screenDensity != bitmapDensity) { 539 SkPaint filteredPaint; 540 if (paint) { 541 filteredPaint = *paint; 542 } 543 filteredPaint.setFilterBitmap(true); 544 canvas->drawBitmapRect(*bitmap, srcPtr, dst, &filteredPaint); 545 } else { 546 canvas->drawBitmapRect(*bitmap, srcPtr, dst, paint); 547 } 548 } 549 550 static void drawBitmapRF(JNIEnv* env, jobject, SkCanvas* canvas, 551 SkBitmap* bitmap, jobject srcIRect, 552 jobject dstRectF, SkPaint* paint, 553 jint screenDensity, jint bitmapDensity) { 554 SkRect dst; 555 GraphicsJNI::jrectf_to_rect(env, dstRectF, &dst); 556 doDrawBitmap(env, canvas, bitmap, srcIRect, dst, paint, 557 screenDensity, bitmapDensity); 558 } 559 560 static void drawBitmapRR(JNIEnv* env, jobject, SkCanvas* canvas, 561 SkBitmap* bitmap, jobject srcIRect, 562 jobject dstRect, SkPaint* paint, 563 jint screenDensity, jint bitmapDensity) { 564 SkRect dst; 565 GraphicsJNI::jrect_to_rect(env, dstRect, &dst); 566 doDrawBitmap(env, canvas, bitmap, srcIRect, dst, paint, 567 screenDensity, bitmapDensity); 568 } 569 570 static void drawBitmapArray(JNIEnv* env, jobject, SkCanvas* canvas, 571 jintArray jcolors, int offset, int stride, 572 jfloat x, jfloat y, int width, int height, 573 jboolean hasAlpha, SkPaint* paint) 574 { 575 SkBitmap bitmap; 576 577 bitmap.setConfig(hasAlpha ? SkBitmap::kARGB_8888_Config : 578 SkBitmap::kRGB_565_Config, width, height); 579 if (!bitmap.allocPixels()) { 580 return; 581 } 582 583 if (!GraphicsJNI::SetPixels(env, jcolors, offset, stride, 584 0, 0, width, height, bitmap)) { 585 return; 586 } 587 588 canvas->drawBitmap(bitmap, SkFloatToScalar(x), SkFloatToScalar(y), 589 paint); 590 } 591 592 static void drawBitmapMatrix(JNIEnv* env, jobject, SkCanvas* canvas, 593 const SkBitmap* bitmap, const SkMatrix* matrix, 594 const SkPaint* paint) { 595 canvas->drawBitmapMatrix(*bitmap, *matrix, paint); 596 } 597 598 static void drawBitmapMesh(JNIEnv* env, jobject, SkCanvas* canvas, 599 const SkBitmap* bitmap, int meshWidth, int meshHeight, 600 jfloatArray jverts, int vertIndex, jintArray jcolors, 601 int colorIndex, const SkPaint* paint) { 602 603 const int ptCount = (meshWidth + 1) * (meshHeight + 1); 604 const int indexCount = meshWidth * meshHeight * 6; 605 606 AutoJavaFloatArray vertA(env, jverts, vertIndex + (ptCount << 1)); 607 AutoJavaIntArray colorA(env, jcolors, colorIndex + ptCount); 608 609 /* Our temp storage holds 2 or 3 arrays. 610 texture points [ptCount * sizeof(SkPoint)] 611 optionally vertex points [ptCount * sizeof(SkPoint)] if we need a 612 copy to convert from float to fixed 613 indices [ptCount * sizeof(uint16_t)] 614 */ 615 ssize_t storageSize = ptCount * sizeof(SkPoint); // texs[] 616#ifdef SK_SCALAR_IS_FIXED 617 storageSize += ptCount * sizeof(SkPoint); // storage for verts 618#endif 619 storageSize += indexCount * sizeof(uint16_t); // indices[] 620 621 SkAutoMalloc storage(storageSize); 622 SkPoint* texs = (SkPoint*)storage.get(); 623 SkPoint* verts; 624 uint16_t* indices; 625#ifdef SK_SCALAR_IS_FLOAT 626 verts = (SkPoint*)(vertA.ptr() + vertIndex); 627 indices = (uint16_t*)(texs + ptCount); 628#else 629 verts = texs + ptCount; 630 indices = (uint16_t*)(verts + ptCount); 631 // convert floats to fixed 632 { 633 const float* src = vertA.ptr() + vertIndex; 634 for (int i = 0; i < ptCount; i++) { 635 verts[i].set(SkFloatToFixed(src[0]), SkFloatToFixed(src[1])); 636 src += 2; 637 } 638 } 639#endif 640 641 // cons up texture coordinates and indices 642 { 643 const SkScalar w = SkIntToScalar(bitmap->width()); 644 const SkScalar h = SkIntToScalar(bitmap->height()); 645 const SkScalar dx = w / meshWidth; 646 const SkScalar dy = h / meshHeight; 647 648 SkPoint* texsPtr = texs; 649 SkScalar y = 0; 650 for (int i = 0; i <= meshHeight; i++) { 651 if (i == meshHeight) { 652 y = h; // to ensure numerically we hit h exactly 653 } 654 SkScalar x = 0; 655 for (int j = 0; j < meshWidth; j++) { 656 texsPtr->set(x, y); 657 texsPtr += 1; 658 x += dx; 659 } 660 texsPtr->set(w, y); 661 texsPtr += 1; 662 y += dy; 663 } 664 SkASSERT(texsPtr - texs == ptCount); 665 } 666 667 // cons up indices 668 { 669 uint16_t* indexPtr = indices; 670 int index = 0; 671 for (int i = 0; i < meshHeight; i++) { 672 for (int j = 0; j < meshWidth; j++) { 673 // lower-left triangle 674 *indexPtr++ = index; 675 *indexPtr++ = index + meshWidth + 1; 676 *indexPtr++ = index + meshWidth + 2; 677 // upper-right triangle 678 *indexPtr++ = index; 679 *indexPtr++ = index + meshWidth + 2; 680 *indexPtr++ = index + 1; 681 // bump to the next cell 682 index += 1; 683 } 684 // bump to the next row 685 index += 1; 686 } 687 SkASSERT(indexPtr - indices == indexCount); 688 SkASSERT((char*)indexPtr - (char*)storage.get() == storageSize); 689 } 690 691 // double-check that we have legal indices 692#ifdef SK_DEBUG 693 { 694 for (int i = 0; i < indexCount; i++) { 695 SkASSERT((unsigned)indices[i] < (unsigned)ptCount); 696 } 697 } 698#endif 699 700 // cons-up a shader for the bitmap 701 SkPaint tmpPaint; 702 if (paint) { 703 tmpPaint = *paint; 704 } 705 SkShader* shader = SkShader::CreateBitmapShader(*bitmap, 706 SkShader::kClamp_TileMode, SkShader::kClamp_TileMode); 707 tmpPaint.setShader(shader)->safeUnref(); 708 709 canvas->drawVertices(SkCanvas::kTriangles_VertexMode, ptCount, verts, 710 texs, (const SkColor*)colorA.ptr(), NULL, indices, 711 indexCount, tmpPaint); 712 } 713 714 static void drawVertices(JNIEnv* env, jobject, SkCanvas* canvas, 715 SkCanvas::VertexMode mode, int vertexCount, 716 jfloatArray jverts, int vertIndex, 717 jfloatArray jtexs, int texIndex, 718 jintArray jcolors, int colorIndex, 719 jshortArray jindices, int indexIndex, 720 int indexCount, const SkPaint* paint) { 721 722 AutoJavaFloatArray vertA(env, jverts, vertIndex + vertexCount); 723 AutoJavaFloatArray texA(env, jtexs, texIndex + vertexCount); 724 AutoJavaIntArray colorA(env, jcolors, colorIndex + vertexCount); 725 AutoJavaShortArray indexA(env, jindices, indexIndex + indexCount); 726 727 const int ptCount = vertexCount >> 1; 728 729 SkPoint* verts; 730 SkPoint* texs = NULL; 731#ifdef SK_SCALAR_IS_FLOAT 732 verts = (SkPoint*)(vertA.ptr() + vertIndex); 733 if (jtexs != NULL) { 734 texs = (SkPoint*)(texA.ptr() + texIndex); 735 } 736#else 737 int count = ptCount; // for verts 738 if (jtexs != NULL) { 739 count += ptCount; // += for texs 740 } 741 SkAutoMalloc storage(count * sizeof(SkPoint)); 742 verts = (SkPoint*)storage.get(); 743 const float* src = vertA.ptr() + vertIndex; 744 for (int i = 0; i < ptCount; i++) { 745 verts[i].set(SkFloatToFixed(src[0]), SkFloatToFixed(src[1])); 746 src += 2; 747 } 748 if (jtexs != NULL) { 749 texs = verts + ptCount; 750 src = texA.ptr() + texIndex; 751 for (int i = 0; i < ptCount; i++) { 752 texs[i].set(SkFloatToFixed(src[0]), SkFloatToFixed(src[1])); 753 src += 2; 754 } 755 } 756#endif 757 758 const SkColor* colors = NULL; 759 const uint16_t* indices = NULL; 760 if (jcolors != NULL) { 761 colors = (const SkColor*)(colorA.ptr() + colorIndex); 762 } 763 if (jindices != NULL) { 764 indices = (const uint16_t*)(indexA.ptr() + indexIndex); 765 } 766 767 canvas->drawVertices(mode, ptCount, verts, texs, colors, NULL, 768 indices, indexCount, *paint); 769 } 770 771 /** 772 * @context the text context 773 * @start the start of the text to render 774 * @count the length of the text to render, start + count must be <= len 775 * @contextCount the length of the context 776 * @shaped where to put the shaped text, must have capacity for count uchars 777 * @return the length of the shaped text, or -1 if error 778 */ 779 static int shapeRtlText__(const jchar* context, jsize start, jsize count, jsize contextCount, 780 jchar* shaped, UErrorCode &status) { 781 jchar buffer[contextCount]; 782 783 // We'd rather use harfbuzz here. Use character based shaping for now. 784 785 // Use fixed length since we need to keep start and count valid 786 u_shapeArabic(context, contextCount, buffer, contextCount, 787 U_SHAPE_LENGTH_FIXED_SPACES_NEAR | 788 U_SHAPE_TEXT_DIRECTION_LOGICAL | U_SHAPE_LETTERS_SHAPE | 789 U_SHAPE_X_LAMALEF_SUB_ALTERNATE, &status); 790 791 if (!U_SUCCESS(status)) { 792 return 0; 793 } 794 795 // trim out 0xffff following ligatures, if any 796 int end = 0; 797 for (int i = start, e = start + count; i < e; ++i) { 798 if (buffer[i] == 0xffff) { 799 continue; 800 } 801 buffer[end++] = buffer[i]; 802 } 803 count = end; 804 // LOG(LOG_INFO, "CSRTL", "start %d count %d ccount %d\n", start, count, contextCount); 805 ubidi_writeReverse(buffer, count, shaped, count, UBIDI_DO_MIRRORING | UBIDI_OUTPUT_REVERSE 806 | UBIDI_KEEP_BASE_COMBINING, &status); 807 return count; 808 } 809 810 static void drawText__(JNIEnv* env, SkCanvas* canvas, const jchar* text, jsize len, 811 jfloat x, jfloat y, int flags, SkPaint* paint) { 812 SkScalar x_ = SkFloatToScalar(x); 813 SkScalar y_ = SkFloatToScalar(y); 814 815 SkPaint::Align horiz = paint->getTextAlign(); 816 817 bool needBidi = (flags == kBidi_RTL) || (flags == kBidi_Default_RTL); 818 if (!needBidi && flags < kBidi_Force_LTR) { 819 for (int i = 0; i < len; ++i) { 820 if (text[i] >= 0x0590) { 821 needBidi = TRUE; 822 break; 823 } 824 } 825 } 826 827 int dir = (flags == kBidi_Force_RTL) ? kDirection_RTL : kDirection_LTR; // will be reset if we run bidi 828 UErrorCode status = U_ZERO_ERROR; 829 jchar *shaped = NULL; 830 int32_t slen = 0; 831 if (needBidi || (flags == kBidi_Force_RTL)) { 832 shaped = (jchar *)malloc(len * sizeof(jchar)); 833 if (!shaped) { 834 status = U_MEMORY_ALLOCATION_ERROR; 835 } else { 836 if (needBidi) { 837 static int RTL_OPTS = UBIDI_DO_MIRRORING | UBIDI_KEEP_BASE_COMBINING | 838 UBIDI_REMOVE_BIDI_CONTROLS | UBIDI_OUTPUT_REVERSE; 839 jint lineDir = 0; 840 switch (flags) { 841 case kBidi_LTR: lineDir = 0; break; // no ICU constant, canonical LTR level 842 case kBidi_RTL: lineDir = 1; break; // no ICU constant, canonical RTL level 843 case kBidi_Default_LTR: lineDir = UBIDI_DEFAULT_LTR; break; 844 case kBidi_Default_RTL: lineDir = UBIDI_DEFAULT_RTL; break; 845 } 846 847 UBiDi* bidi = ubidi_open(); 848 ubidi_setPara(bidi, text, len, lineDir, NULL, &status); 849 if (U_SUCCESS(status)) { 850 dir = ubidi_getParaLevel(bidi) & 0x1; 851 852 int rc = ubidi_countRuns(bidi, &status); 853 if (U_SUCCESS(status)) { 854 int32_t start; 855 int32_t length; 856 UBiDiDirection dir; 857 jchar *buffer = NULL; 858 for (int i = 0; i < rc; ++i) { 859 dir = ubidi_getVisualRun(bidi, i, &start, &length); 860 // fake shaping, except it doesn't shape, just mirrors and reverses 861 // use harfbuzz when available 862 if (dir == UBIDI_RTL) { 863 slen += ubidi_writeReverse(text + start, length, shaped + slen, 864 length, RTL_OPTS, &status); 865 } else { 866 for (int i = 0; i < length; ++i) { 867 shaped[slen + i] = text[start + i]; 868 } 869 slen += length; 870 } 871 } 872 } 873 ubidi_close(bidi); 874 } 875 } else { 876 len = shapeRtlText__(text, 0, len, len, shaped, status); 877 } 878 } 879 } 880 881 if (!U_SUCCESS(status)) { 882 char buffer[35]; 883 sprintf(buffer, "DrawText bidi error %d", status); 884 doThrowIAE(env, buffer); 885 } else { 886 bool trimLeft = false; 887 bool trimRight = false; 888 889 switch (horiz) { 890 case SkPaint::kLeft_Align: trimLeft = dir & kDirection_Mask; break; 891 case SkPaint::kCenter_Align: trimLeft = trimRight = true; break; 892 case SkPaint::kRight_Align: trimRight = !(dir & kDirection_Mask); 893 default: break; 894 } 895 const jchar* workText = shaped ? shaped : text; 896 const jchar* workLimit = workText + len; 897 898 if (trimLeft) { 899 while (workText < workLimit && *workText == ' ') { 900 ++workText; 901 } 902 } 903 if (trimRight) { 904 while (workLimit > workText && *(workLimit - 1) == ' ') { 905 --workLimit; 906 } 907 } 908 int32_t workBytes = (workLimit - workText) << 1; 909 910 canvas->drawText(workText, workBytes, x_, y_, *paint); 911 } 912 913 if (shaped) { 914 free(shaped); 915 } 916 } 917 918 static void drawText___CIIFFIPaint(JNIEnv* env, jobject, SkCanvas* canvas, 919 jcharArray text, int index, int count, 920 jfloat x, jfloat y, int flags, SkPaint* paint) { 921 jchar* textArray = env->GetCharArrayElements(text, NULL); 922 drawText__(env, canvas, textArray + index, count, x, y, flags, paint); 923 env->ReleaseCharArrayElements(text, textArray, JNI_ABORT); 924 } 925 926 static void drawText__StringIIFFIPaint(JNIEnv* env, jobject, 927 SkCanvas* canvas, jstring text, 928 int start, int end, 929 jfloat x, jfloat y, int flags, SkPaint* paint) { 930 const jchar* textArray = env->GetStringChars(text, NULL); 931 drawText__(env, canvas, textArray + start, end - start, x, y, flags, paint); 932 env->ReleaseStringChars(text, textArray); 933 } 934 935 // Draws a unidirectional run of text. 936 static void drawTextRun__(JNIEnv* env, SkCanvas* canvas, const jchar* chars, 937 jint start, jint count, jint contextCount, 938 jfloat x, jfloat y, int flags, SkPaint* paint) { 939 940 SkScalar x_ = SkFloatToScalar(x); 941 SkScalar y_ = SkFloatToScalar(y); 942 943 uint8_t rtl = flags & 0x1; 944 if (rtl) { 945 jchar context[contextCount]; 946 UErrorCode status = U_ZERO_ERROR; 947 count = shapeRtlText__(chars, start, count, contextCount, context, status); 948 if (U_SUCCESS(status)) { 949 canvas->drawText(context, count << 1, x_, y_, *paint); 950 } else { 951 doThrowIAE(env, "shaping error"); 952 } 953 } else { 954 canvas->drawText(chars + start, count << 1, x_, y_, *paint); 955 } 956 } 957 958 static void drawTextRun___CIIIIFFIPaint( 959 JNIEnv* env, jobject, SkCanvas* canvas, jcharArray text, int index, 960 int count, int contextIndex, int contextCount, 961 jfloat x, jfloat y, int flags, SkPaint* paint) { 962 963 jchar* chars = env->GetCharArrayElements(text, NULL); 964 drawTextRun__(env, canvas, chars + contextIndex, index - contextIndex, 965 count, contextCount, x, y, flags, paint); 966 env->ReleaseCharArrayElements(text, chars, JNI_ABORT); 967 } 968 969 static void drawTextRun__StringIIIIFFIPaint( 970 JNIEnv* env, jobject obj, SkCanvas* canvas, jstring text, jint start, 971 jint end, jint contextStart, jint contextEnd, 972 jfloat x, jfloat y, jint flags, SkPaint* paint) { 973 974 jint count = end - start; 975 jint contextCount = contextEnd - contextStart; 976 const jchar* chars = env->GetStringChars(text, NULL); 977 drawTextRun__(env, canvas, chars + contextStart, start - contextStart, 978 count, contextCount, x, y, flags, paint); 979 env->ReleaseStringChars(text, chars); 980 } 981 982 static void drawPosText___CII_FPaint(JNIEnv* env, jobject, SkCanvas* canvas, 983 jcharArray text, int index, int count, 984 jfloatArray pos, SkPaint* paint) { 985 jchar* textArray = text ? env->GetCharArrayElements(text, NULL) : NULL; 986 jsize textCount = text ? env->GetArrayLength(text) : NULL; 987 float* posArray = pos ? env->GetFloatArrayElements(pos, NULL) : NULL; 988 int posCount = pos ? env->GetArrayLength(pos) >> 1: 0; 989 SkPoint* posPtr = posCount > 0 ? new SkPoint[posCount] : NULL; 990 int indx; 991 for (indx = 0; indx < posCount; indx++) { 992 posPtr[indx].fX = SkFloatToScalar(posArray[indx << 1]); 993 posPtr[indx].fY = SkFloatToScalar(posArray[(indx << 1) + 1]); 994 } 995 canvas->drawPosText(textArray + index, count << 1, posPtr, *paint); 996 if (text) { 997 env->ReleaseCharArrayElements(text, textArray, 0); 998 } 999 if (pos) { 1000 env->ReleaseFloatArrayElements(pos, posArray, 0); 1001 } 1002 delete[] posPtr; 1003 } 1004 1005 static void drawPosText__String_FPaint(JNIEnv* env, jobject, 1006 SkCanvas* canvas, jstring text, 1007 jfloatArray pos, SkPaint* paint) { 1008 const void* text_ = text ? env->GetStringChars(text, NULL) : NULL; 1009 int byteLength = text ? env->GetStringLength(text) : 0; 1010 float* posArray = pos ? env->GetFloatArrayElements(pos, NULL) : NULL; 1011 int posCount = pos ? env->GetArrayLength(pos) >> 1: 0; 1012 SkPoint* posPtr = posCount > 0 ? new SkPoint[posCount] : NULL; 1013 1014 for (int indx = 0; indx < posCount; indx++) { 1015 posPtr[indx].fX = SkFloatToScalar(posArray[indx << 1]); 1016 posPtr[indx].fY = SkFloatToScalar(posArray[(indx << 1) + 1]); 1017 } 1018 canvas->drawPosText(text_, byteLength << 1, posPtr, *paint); 1019 if (text) { 1020 env->ReleaseStringChars(text, (const jchar*) text_); 1021 } 1022 if (pos) { 1023 env->ReleaseFloatArrayElements(pos, posArray, 0); 1024 } 1025 delete[] posPtr; 1026 } 1027 1028 static void drawTextOnPath___CIIPathFFPaint(JNIEnv* env, jobject, 1029 SkCanvas* canvas, jcharArray text, int index, int count, 1030 SkPath* path, jfloat hOffset, jfloat vOffset, SkPaint* paint) { 1031 1032 jchar* textArray = env->GetCharArrayElements(text, NULL); 1033 canvas->drawTextOnPathHV(textArray + index, count << 1, *path, 1034 SkFloatToScalar(hOffset), SkFloatToScalar(vOffset), *paint); 1035 env->ReleaseCharArrayElements(text, textArray, 0); 1036 } 1037 1038 static void drawTextOnPath__StringPathFFPaint(JNIEnv* env, jobject, 1039 SkCanvas* canvas, jstring text, SkPath* path, 1040 jfloat hOffset, jfloat vOffset, SkPaint* paint) { 1041 const jchar* text_ = env->GetStringChars(text, NULL); 1042 int byteLength = env->GetStringLength(text) << 1; 1043 canvas->drawTextOnPathHV(text_, byteLength, *path, 1044 SkFloatToScalar(hOffset), SkFloatToScalar(vOffset), *paint); 1045 env->ReleaseStringChars(text, text_); 1046 } 1047 1048 static bool getClipBounds(JNIEnv* env, jobject, SkCanvas* canvas, 1049 jobject bounds) { 1050 SkRect r; 1051 SkIRect ir; 1052 bool result = canvas->getClipBounds(&r, SkCanvas::kBW_EdgeType); 1053 1054 r.round(&ir); 1055 (void)GraphicsJNI::irect_to_jrect(ir, env, bounds); 1056 return result; 1057 } 1058 1059 static void getCTM(JNIEnv* env, jobject, SkCanvas* canvas, 1060 SkMatrix* matrix) { 1061 *matrix = canvas->getTotalMatrix(); 1062 } 1063}; 1064 1065static JNINativeMethod gCanvasMethods[] = { 1066 {"finalizer", "(I)V", (void*) SkCanvasGlue::finalizer}, 1067 {"initRaster","(I)I", (void*) SkCanvasGlue::initRaster}, 1068 {"initGL","()I", (void*) SkCanvasGlue::initGL}, 1069 {"isOpaque","()Z", (void*) SkCanvasGlue::isOpaque}, 1070 {"getWidth","()I", (void*) SkCanvasGlue::getWidth}, 1071 {"getHeight","()I", (void*) SkCanvasGlue::getHeight}, 1072 {"native_setBitmap","(II)V", (void*) SkCanvasGlue::setBitmap}, 1073 {"nativeSetViewport", "(III)V", (void*) SkCanvasGlue::setViewport}, 1074 {"save","()I", (void*) SkCanvasGlue::saveAll}, 1075 {"save","(I)I", (void*) SkCanvasGlue::save}, 1076 {"native_saveLayer","(ILandroid/graphics/RectF;II)I", 1077 (void*) SkCanvasGlue::saveLayer}, 1078 {"native_saveLayer","(IFFFFII)I", (void*) SkCanvasGlue::saveLayer4F}, 1079 {"native_saveLayerAlpha","(ILandroid/graphics/RectF;II)I", 1080 (void*) SkCanvasGlue::saveLayerAlpha}, 1081 {"native_saveLayerAlpha","(IFFFFII)I", 1082 (void*) SkCanvasGlue::saveLayerAlpha4F}, 1083 {"restore","()V", (void*) SkCanvasGlue::restore}, 1084 {"getSaveCount","()I", (void*) SkCanvasGlue::getSaveCount}, 1085 {"restoreToCount","(I)V", (void*) SkCanvasGlue::restoreToCount}, 1086 {"translate","(FF)V", (void*) SkCanvasGlue::translate}, 1087 {"scale","(FF)V", (void*) SkCanvasGlue::scale__FF}, 1088 {"rotate","(F)V", (void*) SkCanvasGlue::rotate__F}, 1089 {"skew","(FF)V", (void*) SkCanvasGlue::skew__FF}, 1090 {"native_concat","(II)V", (void*) SkCanvasGlue::concat}, 1091 {"native_setMatrix","(II)V", (void*) SkCanvasGlue::setMatrix}, 1092 {"clipRect","(FFFF)Z", (void*) SkCanvasGlue::clipRect_FFFF}, 1093 {"clipRect","(IIII)Z", (void*) SkCanvasGlue::clipRect_IIII}, 1094 {"clipRect","(Landroid/graphics/RectF;)Z", 1095 (void*) SkCanvasGlue::clipRect_RectF}, 1096 {"clipRect","(Landroid/graphics/Rect;)Z", 1097 (void*) SkCanvasGlue::clipRect_Rect}, 1098 {"native_clipRect","(IFFFFI)Z", (void*) SkCanvasGlue::clipRect}, 1099 {"native_clipPath","(III)Z", (void*) SkCanvasGlue::clipPath}, 1100 {"native_clipRegion","(III)Z", (void*) SkCanvasGlue::clipRegion}, 1101 {"nativeSetDrawFilter", "(II)V", (void*) SkCanvasGlue::setDrawFilter}, 1102 {"native_getClipBounds","(ILandroid/graphics/Rect;)Z", 1103 (void*) SkCanvasGlue::getClipBounds}, 1104 {"native_getCTM", "(II)V", (void*)SkCanvasGlue::getCTM}, 1105 {"native_quickReject","(ILandroid/graphics/RectF;I)Z", 1106 (void*) SkCanvasGlue::quickReject__RectFI}, 1107 {"native_quickReject","(III)Z", (void*) SkCanvasGlue::quickReject__PathI}, 1108 {"native_quickReject","(IFFFFI)Z", (void*)SkCanvasGlue::quickReject__FFFFI}, 1109 {"native_drawRGB","(IIII)V", (void*) SkCanvasGlue::drawRGB}, 1110 {"native_drawARGB","(IIIII)V", (void*) SkCanvasGlue::drawARGB}, 1111 {"native_drawColor","(II)V", (void*) SkCanvasGlue::drawColor__I}, 1112 {"native_drawColor","(III)V", (void*) SkCanvasGlue::drawColor__II}, 1113 {"native_drawPaint","(II)V", (void*) SkCanvasGlue::drawPaint}, 1114 {"drawPoint", "(FFLandroid/graphics/Paint;)V", 1115 (void*) SkCanvasGlue::drawPoint}, 1116 {"drawPoints", "([FIILandroid/graphics/Paint;)V", 1117 (void*) SkCanvasGlue::drawPoints}, 1118 {"drawLines", "([FIILandroid/graphics/Paint;)V", 1119 (void*) SkCanvasGlue::drawLines}, 1120 {"native_drawLine","(IFFFFI)V", (void*) SkCanvasGlue::drawLine__FFFFPaint}, 1121 {"native_drawRect","(ILandroid/graphics/RectF;I)V", 1122 (void*) SkCanvasGlue::drawRect__RectFPaint}, 1123 {"native_drawRect","(IFFFFI)V", (void*) SkCanvasGlue::drawRect__FFFFPaint}, 1124 {"native_drawOval","(ILandroid/graphics/RectF;I)V", 1125 (void*) SkCanvasGlue::drawOval}, 1126 {"native_drawCircle","(IFFFI)V", (void*) SkCanvasGlue::drawCircle}, 1127 {"native_drawArc","(ILandroid/graphics/RectF;FFZI)V", 1128 (void*) SkCanvasGlue::drawArc}, 1129 {"native_drawRoundRect","(ILandroid/graphics/RectF;FFI)V", 1130 (void*) SkCanvasGlue::drawRoundRect}, 1131 {"native_drawPath","(III)V", (void*) SkCanvasGlue::drawPath}, 1132 {"native_drawBitmap","(IIFFIIII)V", 1133 (void*) SkCanvasGlue::drawBitmap__BitmapFFPaint}, 1134 {"native_drawBitmap","(IILandroid/graphics/Rect;Landroid/graphics/RectF;III)V", 1135 (void*) SkCanvasGlue::drawBitmapRF}, 1136 {"native_drawBitmap","(IILandroid/graphics/Rect;Landroid/graphics/Rect;III)V", 1137 (void*) SkCanvasGlue::drawBitmapRR}, 1138 {"native_drawBitmap", "(I[IIIFFIIZI)V", 1139 (void*)SkCanvasGlue::drawBitmapArray}, 1140 {"nativeDrawBitmapMatrix", "(IIII)V", 1141 (void*)SkCanvasGlue::drawBitmapMatrix}, 1142 {"nativeDrawBitmapMesh", "(IIII[FI[III)V", 1143 (void*)SkCanvasGlue::drawBitmapMesh}, 1144 {"nativeDrawVertices", "(III[FI[FI[II[SIII)V", 1145 (void*)SkCanvasGlue::drawVertices}, 1146 {"native_drawText","(I[CIIFFII)V", 1147 (void*) SkCanvasGlue::drawText___CIIFFIPaint}, 1148 {"native_drawText","(ILjava/lang/String;IIFFII)V", 1149 (void*) SkCanvasGlue::drawText__StringIIFFIPaint}, 1150 {"native_drawTextRun","(I[CIIIIFFII)V", 1151 (void*) SkCanvasGlue::drawTextRun___CIIIIFFIPaint}, 1152 {"native_drawTextRun","(ILjava/lang/String;IIIIFFII)V", 1153 (void*) SkCanvasGlue::drawTextRun__StringIIIIFFIPaint}, 1154 {"native_drawPosText","(I[CII[FI)V", 1155 (void*) SkCanvasGlue::drawPosText___CII_FPaint}, 1156 {"native_drawPosText","(ILjava/lang/String;[FI)V", 1157 (void*) SkCanvasGlue::drawPosText__String_FPaint}, 1158 {"native_drawTextOnPath","(I[CIIIFFI)V", 1159 (void*) SkCanvasGlue::drawTextOnPath___CIIPathFFPaint}, 1160 {"native_drawTextOnPath","(ILjava/lang/String;IFFI)V", 1161 (void*) SkCanvasGlue::drawTextOnPath__StringPathFFPaint}, 1162 {"native_drawPicture", "(II)V", (void*) SkCanvasGlue::drawPicture}, 1163 1164 {"freeCaches", "()V", (void*) SkCanvasGlue::freeCaches} 1165}; 1166 1167/////////////////////////////////////////////////////////////////////////////// 1168 1169static void BoundaryPatch_computeCubic(JNIEnv* env, jobject, jfloatArray jpts, 1170 int texW, int texH, int rows, int cols, 1171 jfloatArray jverts, jshortArray jidx) { 1172 AutoJavaFloatArray ptsArray(env, jpts, 24, kRO_JNIAccess); 1173 1174 int vertCount = rows * cols; 1175 AutoJavaFloatArray vertsArray(env, jverts, vertCount * 4, kRW_JNIAccess); 1176 SkPoint* verts = (SkPoint*)vertsArray.ptr(); 1177 SkPoint* texs = verts + vertCount; 1178 1179 int idxCount = (rows - 1) * (cols - 1) * 6; 1180 AutoJavaShortArray idxArray(env, jidx, idxCount, kRW_JNIAccess); 1181 uint16_t* idx = (uint16_t*)idxArray.ptr(); // cast from int16_t* 1182 1183 SkCubicBoundary cubic; 1184 memcpy(cubic.fPts, ptsArray.ptr(), 12 * sizeof(SkPoint)); 1185 1186 SkBoundaryPatch patch; 1187 patch.setBoundary(&cubic); 1188 // generate our verts 1189 patch.evalPatch(verts, rows, cols); 1190 1191 SkMeshIndices mesh; 1192 // generate our texs and idx 1193 mesh.init(texs, idx, texW, texH, rows, cols); 1194} 1195 1196static JNINativeMethod gBoundaryPatchMethods[] = { 1197 {"nativeComputeCubicPatch", "([FIIII[F[S)V", 1198 (void*)BoundaryPatch_computeCubic }, 1199}; 1200 1201/////////////////////////////////////////////////////////////////////////////// 1202 1203#include <android_runtime/AndroidRuntime.h> 1204 1205#define REG(env, name, array) \ 1206 result = android::AndroidRuntime::registerNativeMethods(env, name, array, \ 1207 SK_ARRAY_COUNT(array)); \ 1208 if (result < 0) return result 1209 1210int register_android_graphics_Canvas(JNIEnv* env) { 1211 int result; 1212 1213 REG(env, "android/graphics/Canvas", gCanvasMethods); 1214 REG(env, "android/graphics/utils/BoundaryPatch", gBoundaryPatchMethods); 1215 1216 return result; 1217} 1218 1219} 1220