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