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