2 * Copyright (C) 2006-2007 The Android Open Source Project
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
8 * http://www.apache.org/licenses/LICENSE-2.0
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.
18 #include "GraphicsJNI.h"
19 #include <android_runtime/AndroidRuntime.h>
23 #include "SkDrawFilter.h"
24 #include "SkGraphics.h"
25 #include "SkImageRef_GlobalPool.h"
26 #include "SkPorterDuff.h"
28 #include "SkTemplates.h"
30 #include "TextLayout.h"
31 #include "TextLayoutCache.h"
33 #include "unicode/ubidi.h"
34 #include "unicode/ushape.h"
36 #include <utils/Log.h>
40 static uint32_t get_thread_msec() {
41 #if defined(HAVE_POSIX_CLOCKS)
44 clock_gettime(CLOCK_THREAD_CPUTIME_ID, &tm);
46 return tm.tv_sec * 1000LL + tm.tv_nsec / 1000000;
50 gettimeofday(&tv, NULL);
51 return tv.tv_sec * 1000LL + tv.tv_usec / 1000;
60 static void finalizer(JNIEnv* env, jobject clazz, SkCanvas* canvas) {
64 static SkCanvas* initRaster(JNIEnv* env, jobject, SkBitmap* bitmap) {
65 return bitmap ? new SkCanvas(*bitmap) : new SkCanvas;
68 static void freeCaches(JNIEnv* env, jobject) {
69 // these are called in no particular order
70 SkImageRef_GlobalPool::SetRAMUsed(0);
71 SkGraphics::PurgeFontCache();
74 static void freeTextLayoutCaches(JNIEnv* env, jobject) {
75 TextLayoutEngine::getInstance().purgeCaches();
78 static jboolean isOpaque(JNIEnv* env, jobject jcanvas) {
79 NPE_CHECK_RETURN_ZERO(env, jcanvas);
80 SkCanvas* canvas = GraphicsJNI::getNativeCanvas(env, jcanvas);
81 return canvas->getDevice()->accessBitmap(false).isOpaque();
84 static int getWidth(JNIEnv* env, jobject jcanvas) {
85 NPE_CHECK_RETURN_ZERO(env, jcanvas);
86 SkCanvas* canvas = GraphicsJNI::getNativeCanvas(env, jcanvas);
87 return canvas->getDevice()->accessBitmap(false).width();
90 static int getHeight(JNIEnv* env, jobject jcanvas) {
91 NPE_CHECK_RETURN_ZERO(env, jcanvas);
92 SkCanvas* canvas = GraphicsJNI::getNativeCanvas(env, jcanvas);
93 return canvas->getDevice()->accessBitmap(false).height();
96 static int saveAll(JNIEnv* env, jobject jcanvas) {
97 NPE_CHECK_RETURN_ZERO(env, jcanvas);
98 return GraphicsJNI::getNativeCanvas(env, jcanvas)->save();
101 static int save(JNIEnv* env, jobject jcanvas, SkCanvas::SaveFlags flags) {
102 NPE_CHECK_RETURN_ZERO(env, jcanvas);
103 return GraphicsJNI::getNativeCanvas(env, jcanvas)->save(flags);
106 static int saveLayer(JNIEnv* env, jobject, SkCanvas* canvas, jobject bounds,
107 SkPaint* paint, int flags) {
108 SkRect* bounds_ = NULL;
110 if (bounds != NULL) {
111 GraphicsJNI::jrectf_to_rect(env, bounds, &storage);
114 return canvas->saveLayer(bounds_, paint, (SkCanvas::SaveFlags)flags);
117 static int saveLayer4F(JNIEnv* env, jobject, SkCanvas* canvas,
118 jfloat l, jfloat t, jfloat r, jfloat b,
119 SkPaint* paint, int flags) {
121 bounds.set(SkFloatToScalar(l), SkFloatToScalar(t), SkFloatToScalar(r),
123 return canvas->saveLayer(&bounds, paint, (SkCanvas::SaveFlags)flags);
126 static int saveLayerAlpha(JNIEnv* env, jobject, SkCanvas* canvas,
127 jobject bounds, int alpha, int flags) {
128 SkRect* bounds_ = NULL;
130 if (bounds != NULL) {
131 GraphicsJNI::jrectf_to_rect(env, bounds, &storage);
134 return canvas->saveLayerAlpha(bounds_, alpha,
135 (SkCanvas::SaveFlags)flags);
138 static int saveLayerAlpha4F(JNIEnv* env, jobject, SkCanvas* canvas,
139 jfloat l, jfloat t, jfloat r, jfloat b,
140 int alpha, int flags) {
142 bounds.set(SkFloatToScalar(l), SkFloatToScalar(t), SkFloatToScalar(r),
144 return canvas->saveLayerAlpha(&bounds, alpha,
145 (SkCanvas::SaveFlags)flags);
148 static void restore(JNIEnv* env, jobject jcanvas) {
149 NPE_CHECK_RETURN_VOID(env, jcanvas);
150 SkCanvas* canvas = GraphicsJNI::getNativeCanvas(env, jcanvas);
151 if (canvas->getSaveCount() <= 1) { // cannot restore anymore
152 doThrowISE(env, "Underflow in restore");
158 static int getSaveCount(JNIEnv* env, jobject jcanvas) {
159 NPE_CHECK_RETURN_ZERO(env, jcanvas);
160 return GraphicsJNI::getNativeCanvas(env, jcanvas)->getSaveCount();
163 static void restoreToCount(JNIEnv* env, jobject jcanvas, int restoreCount) {
164 NPE_CHECK_RETURN_VOID(env, jcanvas);
165 SkCanvas* canvas = GraphicsJNI::getNativeCanvas(env, jcanvas);
166 if (restoreCount < 1) {
167 doThrowIAE(env, "Underflow in restoreToCount");
170 canvas->restoreToCount(restoreCount);
173 static void translate(JNIEnv* env, jobject jcanvas, jfloat dx, jfloat dy) {
174 NPE_CHECK_RETURN_VOID(env, jcanvas);
175 SkScalar dx_ = SkFloatToScalar(dx);
176 SkScalar dy_ = SkFloatToScalar(dy);
177 (void)GraphicsJNI::getNativeCanvas(env, jcanvas)->translate(dx_, dy_);
180 static void scale__FF(JNIEnv* env, jobject jcanvas, jfloat sx, jfloat sy) {
181 NPE_CHECK_RETURN_VOID(env, jcanvas);
182 SkScalar sx_ = SkFloatToScalar(sx);
183 SkScalar sy_ = SkFloatToScalar(sy);
184 (void)GraphicsJNI::getNativeCanvas(env, jcanvas)->scale(sx_, sy_);
187 static void rotate__F(JNIEnv* env, jobject jcanvas, jfloat degrees) {
188 NPE_CHECK_RETURN_VOID(env, jcanvas);
189 SkScalar degrees_ = SkFloatToScalar(degrees);
190 (void)GraphicsJNI::getNativeCanvas(env, jcanvas)->rotate(degrees_);
193 static void skew__FF(JNIEnv* env, jobject jcanvas, jfloat sx, jfloat sy) {
194 NPE_CHECK_RETURN_VOID(env, jcanvas);
195 SkScalar sx_ = SkFloatToScalar(sx);
196 SkScalar sy_ = SkFloatToScalar(sy);
197 (void)GraphicsJNI::getNativeCanvas(env, jcanvas)->skew(sx_, sy_);
200 static void concat(JNIEnv* env, jobject, SkCanvas* canvas,
201 const SkMatrix* matrix) {
202 canvas->concat(*matrix);
205 static void setMatrix(JNIEnv* env, jobject, SkCanvas* canvas,
206 const SkMatrix* matrix) {
207 if (NULL == matrix) {
208 canvas->resetMatrix();
210 canvas->setMatrix(*matrix);
214 static jboolean clipRect_FFFF(JNIEnv* env, jobject jcanvas, jfloat left,
215 jfloat top, jfloat right, jfloat bottom) {
216 NPE_CHECK_RETURN_ZERO(env, jcanvas);
218 r.set(SkFloatToScalar(left), SkFloatToScalar(top),
219 SkFloatToScalar(right), SkFloatToScalar(bottom));
220 SkCanvas* c = GraphicsJNI::getNativeCanvas(env, jcanvas);
221 return c->clipRect(r);
224 static jboolean clipRect_IIII(JNIEnv* env, jobject jcanvas, jint left,
225 jint top, jint right, jint bottom) {
226 NPE_CHECK_RETURN_ZERO(env, jcanvas);
228 r.set(SkIntToScalar(left), SkIntToScalar(top),
229 SkIntToScalar(right), SkIntToScalar(bottom));
230 return GraphicsJNI::getNativeCanvas(env, jcanvas)->clipRect(r);
233 static jboolean clipRect_RectF(JNIEnv* env, jobject jcanvas, jobject rectf) {
234 NPE_CHECK_RETURN_ZERO(env, jcanvas);
235 NPE_CHECK_RETURN_ZERO(env, rectf);
236 SkCanvas* c = GraphicsJNI::getNativeCanvas(env, jcanvas);
238 return c->clipRect(*GraphicsJNI::jrectf_to_rect(env, rectf, &tmp));
241 static jboolean clipRect_Rect(JNIEnv* env, jobject jcanvas, jobject rect) {
242 NPE_CHECK_RETURN_ZERO(env, jcanvas);
243 NPE_CHECK_RETURN_ZERO(env, rect);
244 SkCanvas* c = GraphicsJNI::getNativeCanvas(env, jcanvas);
246 return c->clipRect(*GraphicsJNI::jrect_to_rect(env, rect, &tmp));
249 static jboolean clipRect(JNIEnv* env, jobject, SkCanvas* canvas,
250 float left, float top, float right, float bottom,
253 rect.set(SkFloatToScalar(left), SkFloatToScalar(top),
254 SkFloatToScalar(right), SkFloatToScalar(bottom));
255 return canvas->clipRect(rect, (SkRegion::Op)op);
258 static jboolean clipPath(JNIEnv* env, jobject, SkCanvas* canvas,
259 SkPath* path, int op) {
260 return canvas->clipPath(*path, (SkRegion::Op)op);
263 static jboolean clipRegion(JNIEnv* env, jobject, SkCanvas* canvas,
264 SkRegion* deviceRgn, int op) {
265 return canvas->clipRegion(*deviceRgn, (SkRegion::Op)op);
268 static void setDrawFilter(JNIEnv* env, jobject, SkCanvas* canvas,
269 SkDrawFilter* filter) {
270 canvas->setDrawFilter(filter);
273 static jboolean quickReject__RectF(JNIEnv* env, jobject, SkCanvas* canvas,
276 GraphicsJNI::jrectf_to_rect(env, rect, &rect_);
277 return canvas->quickReject(rect_);
280 static jboolean quickReject__Path(JNIEnv* env, jobject, SkCanvas* canvas,
282 return canvas->quickReject(*path);
285 static jboolean quickReject__FFFF(JNIEnv* env, jobject, SkCanvas* canvas,
286 jfloat left, jfloat top, jfloat right,
289 r.set(SkFloatToScalar(left), SkFloatToScalar(top),
290 SkFloatToScalar(right), SkFloatToScalar(bottom));
291 return canvas->quickReject(r);
294 static void drawRGB(JNIEnv* env, jobject, SkCanvas* canvas,
295 jint r, jint g, jint b) {
296 canvas->drawARGB(0xFF, r, g, b);
299 static void drawARGB(JNIEnv* env, jobject, SkCanvas* canvas,
300 jint a, jint r, jint g, jint b) {
301 canvas->drawARGB(a, r, g, b);
304 static void drawColor__I(JNIEnv* env, jobject, SkCanvas* canvas,
306 canvas->drawColor(color);
309 static void drawColor__II(JNIEnv* env, jobject, SkCanvas* canvas,
310 jint color, SkPorterDuff::Mode mode) {
311 canvas->drawColor(color, SkPorterDuff::ToXfermodeMode(mode));
314 static void drawPaint(JNIEnv* env, jobject, SkCanvas* canvas,
316 canvas->drawPaint(*paint);
319 static void doPoints(JNIEnv* env, jobject jcanvas, jfloatArray jptsArray,
320 jint offset, jint count, jobject jpaint,
321 SkCanvas::PointMode mode) {
322 NPE_CHECK_RETURN_VOID(env, jcanvas);
323 NPE_CHECK_RETURN_VOID(env, jptsArray);
324 NPE_CHECK_RETURN_VOID(env, jpaint);
325 SkCanvas* canvas = GraphicsJNI::getNativeCanvas(env, jcanvas);
326 const SkPaint& paint = *GraphicsJNI::getNativePaint(env, jpaint);
328 AutoJavaFloatArray autoPts(env, jptsArray);
329 float* floats = autoPts.ptr();
330 const int length = autoPts.length();
332 if ((offset | count) < 0 || offset + count > length) {
337 // now convert the floats into SkPoints
338 count >>= 1; // now it is the number of points
339 SkAutoSTMalloc<32, SkPoint> storage(count);
340 SkPoint* pts = storage.get();
341 const float* src = floats + offset;
342 for (int i = 0; i < count; i++) {
343 pts[i].set(SkFloatToScalar(src[0]), SkFloatToScalar(src[1]));
346 canvas->drawPoints(mode, count, pts, paint);
349 static void drawPoints(JNIEnv* env, jobject jcanvas, jfloatArray jptsArray,
350 jint offset, jint count, jobject jpaint) {
351 doPoints(env, jcanvas, jptsArray, offset, count, jpaint,
352 SkCanvas::kPoints_PointMode);
355 static void drawLines(JNIEnv* env, jobject jcanvas, jfloatArray jptsArray,
356 jint offset, jint count, jobject jpaint) {
357 doPoints(env, jcanvas, jptsArray, offset, count, jpaint,
358 SkCanvas::kLines_PointMode);
361 static void drawPoint(JNIEnv* env, jobject jcanvas, float x, float y,
363 NPE_CHECK_RETURN_VOID(env, jcanvas);
364 NPE_CHECK_RETURN_VOID(env, jpaint);
365 SkCanvas* canvas = GraphicsJNI::getNativeCanvas(env, jcanvas);
366 const SkPaint& paint = *GraphicsJNI::getNativePaint(env, jpaint);
368 canvas->drawPoint(SkFloatToScalar(x), SkFloatToScalar(y), paint);
371 static void drawLine__FFFFPaint(JNIEnv* env, jobject, SkCanvas* canvas,
372 jfloat startX, jfloat startY, jfloat stopX,
373 jfloat stopY, SkPaint* paint) {
374 canvas->drawLine(SkFloatToScalar(startX), SkFloatToScalar(startY),
375 SkFloatToScalar(stopX), SkFloatToScalar(stopY),
379 static void drawRect__RectFPaint(JNIEnv* env, jobject, SkCanvas* canvas,
380 jobject rect, SkPaint* paint) {
382 GraphicsJNI::jrectf_to_rect(env, rect, &rect_);
383 canvas->drawRect(rect_, *paint);
386 static void drawRect__FFFFPaint(JNIEnv* env, jobject, SkCanvas* canvas,
387 jfloat left, jfloat top, jfloat right,
388 jfloat bottom, SkPaint* paint) {
389 SkScalar left_ = SkFloatToScalar(left);
390 SkScalar top_ = SkFloatToScalar(top);
391 SkScalar right_ = SkFloatToScalar(right);
392 SkScalar bottom_ = SkFloatToScalar(bottom);
393 canvas->drawRectCoords(left_, top_, right_, bottom_, *paint);
396 static void drawOval(JNIEnv* env, jobject, SkCanvas* canvas, jobject joval,
399 GraphicsJNI::jrectf_to_rect(env, joval, &oval);
400 canvas->drawOval(oval, *paint);
403 static void drawCircle(JNIEnv* env, jobject, SkCanvas* canvas, jfloat cx,
404 jfloat cy, jfloat radius, SkPaint* paint) {
405 canvas->drawCircle(SkFloatToScalar(cx), SkFloatToScalar(cy),
406 SkFloatToScalar(radius), *paint);
409 static void drawArc(JNIEnv* env, jobject, SkCanvas* canvas, jobject joval,
410 jfloat startAngle, jfloat sweepAngle,
411 jboolean useCenter, SkPaint* paint) {
413 GraphicsJNI::jrectf_to_rect(env, joval, &oval);
414 canvas->drawArc(oval, SkFloatToScalar(startAngle),
415 SkFloatToScalar(sweepAngle), useCenter, *paint);
418 static void drawRoundRect(JNIEnv* env, jobject, SkCanvas* canvas,
419 jobject jrect, jfloat rx, jfloat ry,
422 GraphicsJNI::jrectf_to_rect(env, jrect, &rect);
423 canvas->drawRoundRect(rect, SkFloatToScalar(rx), SkFloatToScalar(ry),
427 static void drawPath(JNIEnv* env, jobject, SkCanvas* canvas, SkPath* path,
429 canvas->drawPath(*path, *paint);
432 static void drawPicture(JNIEnv* env, jobject, SkCanvas* canvas,
433 SkPicture* picture) {
438 SkMSec now = get_thread_msec(); //SkTime::GetMSecs();
440 canvas->drawPicture(*picture);
442 ALOGD("---- picture playback %d ms\n", get_thread_msec() - now);
446 static void drawBitmap__BitmapFFPaint(JNIEnv* env, jobject jcanvas,
447 SkCanvas* canvas, SkBitmap* bitmap,
448 jfloat left, jfloat top,
449 SkPaint* paint, jint canvasDensity,
450 jint screenDensity, jint bitmapDensity) {
451 SkScalar left_ = SkFloatToScalar(left);
452 SkScalar top_ = SkFloatToScalar(top);
454 if (canvasDensity == bitmapDensity || canvasDensity == 0
455 || bitmapDensity == 0) {
456 if (screenDensity != 0 && screenDensity != bitmapDensity) {
457 SkPaint filteredPaint;
459 filteredPaint = *paint;
461 filteredPaint.setFilterBitmap(true);
462 canvas->drawBitmap(*bitmap, left_, top_, &filteredPaint);
464 canvas->drawBitmap(*bitmap, left_, top_, paint);
468 SkScalar scale = SkFloatToScalar(canvasDensity / (float)bitmapDensity);
469 canvas->translate(left_, top_);
470 canvas->scale(scale, scale);
472 SkPaint filteredPaint;
474 filteredPaint = *paint;
476 filteredPaint.setFilterBitmap(true);
478 canvas->drawBitmap(*bitmap, 0, 0, &filteredPaint);
484 static void doDrawBitmap(JNIEnv* env, SkCanvas* canvas, SkBitmap* bitmap,
485 jobject srcIRect, const SkRect& dst, SkPaint* paint,
486 jint screenDensity, jint bitmapDensity) {
487 SkIRect src, *srcPtr = NULL;
489 if (NULL != srcIRect) {
490 GraphicsJNI::jrect_to_irect(env, srcIRect, &src);
494 if (screenDensity != 0 && screenDensity != bitmapDensity) {
495 SkPaint filteredPaint;
497 filteredPaint = *paint;
499 filteredPaint.setFilterBitmap(true);
500 canvas->drawBitmapRect(*bitmap, srcPtr, dst, &filteredPaint);
502 canvas->drawBitmapRect(*bitmap, srcPtr, dst, paint);
506 static void drawBitmapRF(JNIEnv* env, jobject, SkCanvas* canvas,
507 SkBitmap* bitmap, jobject srcIRect,
508 jobject dstRectF, SkPaint* paint,
509 jint screenDensity, jint bitmapDensity) {
511 GraphicsJNI::jrectf_to_rect(env, dstRectF, &dst);
512 doDrawBitmap(env, canvas, bitmap, srcIRect, dst, paint,
513 screenDensity, bitmapDensity);
516 static void drawBitmapRR(JNIEnv* env, jobject, SkCanvas* canvas,
517 SkBitmap* bitmap, jobject srcIRect,
518 jobject dstRect, SkPaint* paint,
519 jint screenDensity, jint bitmapDensity) {
521 GraphicsJNI::jrect_to_rect(env, dstRect, &dst);
522 doDrawBitmap(env, canvas, bitmap, srcIRect, dst, paint,
523 screenDensity, bitmapDensity);
526 static void drawBitmapArray(JNIEnv* env, jobject, SkCanvas* canvas,
527 jintArray jcolors, int offset, int stride,
528 jfloat x, jfloat y, int width, int height,
529 jboolean hasAlpha, SkPaint* paint)
533 bitmap.setConfig(hasAlpha ? SkBitmap::kARGB_8888_Config :
534 SkBitmap::kRGB_565_Config, width, height);
535 if (!bitmap.allocPixels()) {
539 if (!GraphicsJNI::SetPixels(env, jcolors, offset, stride,
540 0, 0, width, height, bitmap)) {
544 canvas->drawBitmap(bitmap, SkFloatToScalar(x), SkFloatToScalar(y),
548 static void drawBitmapMatrix(JNIEnv* env, jobject, SkCanvas* canvas,
549 const SkBitmap* bitmap, const SkMatrix* matrix,
550 const SkPaint* paint) {
551 canvas->drawBitmapMatrix(*bitmap, *matrix, paint);
554 static void drawBitmapMesh(JNIEnv* env, jobject, SkCanvas* canvas,
555 const SkBitmap* bitmap, int meshWidth, int meshHeight,
556 jfloatArray jverts, int vertIndex, jintArray jcolors,
557 int colorIndex, const SkPaint* paint) {
559 const int ptCount = (meshWidth + 1) * (meshHeight + 1);
560 const int indexCount = meshWidth * meshHeight * 6;
562 AutoJavaFloatArray vertA(env, jverts, vertIndex + (ptCount << 1));
563 AutoJavaIntArray colorA(env, jcolors, colorIndex + ptCount);
565 /* Our temp storage holds 2 or 3 arrays.
566 texture points [ptCount * sizeof(SkPoint)]
567 optionally vertex points [ptCount * sizeof(SkPoint)] if we need a
568 copy to convert from float to fixed
569 indices [ptCount * sizeof(uint16_t)]
571 ssize_t storageSize = ptCount * sizeof(SkPoint); // texs[]
572 #ifdef SK_SCALAR_IS_FIXED
573 storageSize += ptCount * sizeof(SkPoint); // storage for verts
575 storageSize += indexCount * sizeof(uint16_t); // indices[]
577 SkAutoMalloc storage(storageSize);
578 SkPoint* texs = (SkPoint*)storage.get();
581 #ifdef SK_SCALAR_IS_FLOAT
582 verts = (SkPoint*)(vertA.ptr() + vertIndex);
583 indices = (uint16_t*)(texs + ptCount);
585 verts = texs + ptCount;
586 indices = (uint16_t*)(verts + ptCount);
587 // convert floats to fixed
589 const float* src = vertA.ptr() + vertIndex;
590 for (int i = 0; i < ptCount; i++) {
591 verts[i].set(SkFloatToFixed(src[0]), SkFloatToFixed(src[1]));
597 // cons up texture coordinates and indices
599 const SkScalar w = SkIntToScalar(bitmap->width());
600 const SkScalar h = SkIntToScalar(bitmap->height());
601 const SkScalar dx = w / meshWidth;
602 const SkScalar dy = h / meshHeight;
604 SkPoint* texsPtr = texs;
606 for (int i = 0; i <= meshHeight; i++) {
607 if (i == meshHeight) {
608 y = h; // to ensure numerically we hit h exactly
611 for (int j = 0; j < meshWidth; j++) {
620 SkASSERT(texsPtr - texs == ptCount);
625 uint16_t* indexPtr = indices;
627 for (int i = 0; i < meshHeight; i++) {
628 for (int j = 0; j < meshWidth; j++) {
629 // lower-left triangle
631 *indexPtr++ = index + meshWidth + 1;
632 *indexPtr++ = index + meshWidth + 2;
633 // upper-right triangle
635 *indexPtr++ = index + meshWidth + 2;
636 *indexPtr++ = index + 1;
637 // bump to the next cell
640 // bump to the next row
643 SkASSERT(indexPtr - indices == indexCount);
644 SkASSERT((char*)indexPtr - (char*)storage.get() == storageSize);
647 // double-check that we have legal indices
650 for (int i = 0; i < indexCount; i++) {
651 SkASSERT((unsigned)indices[i] < (unsigned)ptCount);
656 // cons-up a shader for the bitmap
661 SkShader* shader = SkShader::CreateBitmapShader(*bitmap,
662 SkShader::kClamp_TileMode, SkShader::kClamp_TileMode);
663 SkSafeUnref(tmpPaint.setShader(shader));
665 canvas->drawVertices(SkCanvas::kTriangles_VertexMode, ptCount, verts,
666 texs, (const SkColor*)colorA.ptr(), NULL, indices,
667 indexCount, tmpPaint);
670 static void drawVertices(JNIEnv* env, jobject, SkCanvas* canvas,
671 SkCanvas::VertexMode mode, int vertexCount,
672 jfloatArray jverts, int vertIndex,
673 jfloatArray jtexs, int texIndex,
674 jintArray jcolors, int colorIndex,
675 jshortArray jindices, int indexIndex,
676 int indexCount, const SkPaint* paint) {
678 AutoJavaFloatArray vertA(env, jverts, vertIndex + vertexCount);
679 AutoJavaFloatArray texA(env, jtexs, texIndex + vertexCount);
680 AutoJavaIntArray colorA(env, jcolors, colorIndex + vertexCount);
681 AutoJavaShortArray indexA(env, jindices, indexIndex + indexCount);
683 const int ptCount = vertexCount >> 1;
686 SkPoint* texs = NULL;
687 #ifdef SK_SCALAR_IS_FLOAT
688 verts = (SkPoint*)(vertA.ptr() + vertIndex);
690 texs = (SkPoint*)(texA.ptr() + texIndex);
693 int count = ptCount; // for verts
695 count += ptCount; // += for texs
697 SkAutoMalloc storage(count * sizeof(SkPoint));
698 verts = (SkPoint*)storage.get();
699 const float* src = vertA.ptr() + vertIndex;
700 for (int i = 0; i < ptCount; i++) {
701 verts[i].set(SkFloatToFixed(src[0]), SkFloatToFixed(src[1]));
705 texs = verts + ptCount;
706 src = texA.ptr() + texIndex;
707 for (int i = 0; i < ptCount; i++) {
708 texs[i].set(SkFloatToFixed(src[0]), SkFloatToFixed(src[1]));
714 const SkColor* colors = NULL;
715 const uint16_t* indices = NULL;
716 if (jcolors != NULL) {
717 colors = (const SkColor*)(colorA.ptr() + colorIndex);
719 if (jindices != NULL) {
720 indices = (const uint16_t*)(indexA.ptr() + indexIndex);
723 canvas->drawVertices(mode, ptCount, verts, texs, colors, NULL,
724 indices, indexCount, *paint);
728 static void drawText___CIIFFPaint(JNIEnv* env, jobject, SkCanvas* canvas,
729 jcharArray text, int index, int count,
730 jfloat x, jfloat y, SkPaint* paint) {
731 jchar* textArray = env->GetCharArrayElements(text, NULL);
732 drawTextWithGlyphs(canvas, textArray + index, 0, count, x, y, paint);
733 env->ReleaseCharArrayElements(text, textArray, JNI_ABORT);
736 static void drawText__StringIIFFPaint(JNIEnv* env, jobject,
737 SkCanvas* canvas, jstring text,
739 jfloat x, jfloat y, SkPaint* paint) {
740 const jchar* textArray = env->GetStringChars(text, NULL);
741 drawTextWithGlyphs(canvas, textArray, start, end, x, y, paint);
742 env->ReleaseStringChars(text, textArray);
745 static void drawTextWithGlyphs(SkCanvas* canvas, const jchar* textArray,
747 jfloat x, jfloat y, SkPaint* paint) {
749 jint count = end - start;
750 drawTextWithGlyphs(canvas, textArray + start, 0, count, count, x, y, paint);
753 static void drawTextWithGlyphs(SkCanvas* canvas, const jchar* textArray,
754 int start, int count, int contextCount,
755 jfloat x, jfloat y, SkPaint* paint) {
757 sp<TextLayoutValue> value = TextLayoutEngine::getInstance().getValue(paint,
758 textArray, start, count, contextCount);
762 SkPaint::Align align = paint->getTextAlign();
763 if (align == SkPaint::kCenter_Align) {
764 x -= 0.5 * value->getTotalAdvance();
765 } else if (align == SkPaint::kRight_Align) {
766 x -= value->getTotalAdvance();
768 paint->setTextAlign(SkPaint::kLeft_Align);
769 doDrawGlyphsPos(canvas, value->getGlyphs(), value->getPos(), 0, value->getGlyphsCount(), x, y, paint);
770 doDrawTextDecorations(canvas, x, y, value->getTotalAdvance(), paint);
771 paint->setTextAlign(align);
774 // Same values used by Skia
775 #define kStdStrikeThru_Offset (-6.0f / 21.0f)
776 #define kStdUnderline_Offset (1.0f / 9.0f)
777 #define kStdUnderline_Thickness (1.0f / 18.0f)
779 static void doDrawTextDecorations(SkCanvas* canvas, jfloat x, jfloat y, jfloat length, SkPaint* paint) {
781 SkDrawFilter* drawFilter = canvas->getDrawFilter();
783 SkPaint paintCopy(*paint);
784 drawFilter->filter(&paintCopy, SkDrawFilter::kText_Type);
785 flags = paintCopy.getFlags();
787 flags = paint->getFlags();
789 if (flags & (SkPaint::kUnderlineText_Flag | SkPaint::kStrikeThruText_Flag)) {
790 SkScalar left = SkFloatToScalar(x);
791 SkScalar right = SkFloatToScalar(x + length);
792 float textSize = paint->getTextSize();
793 float strokeWidth = fmax(textSize * kStdUnderline_Thickness, 1.0f);
794 if (flags & SkPaint::kUnderlineText_Flag) {
795 SkScalar top = SkFloatToScalar(y + textSize * kStdUnderline_Offset
796 - 0.5f * strokeWidth);
797 SkScalar bottom = SkFloatToScalar(y + textSize * kStdUnderline_Offset
798 + 0.5f * strokeWidth);
799 canvas->drawRectCoords(left, top, right, bottom, *paint);
801 if (flags & SkPaint::kStrikeThruText_Flag) {
802 SkScalar top = SkFloatToScalar(y + textSize * kStdStrikeThru_Offset
803 - 0.5f * strokeWidth);
804 SkScalar bottom = SkFloatToScalar(y + textSize * kStdStrikeThru_Offset
805 + 0.5f * strokeWidth);
806 canvas->drawRectCoords(left, top, right, bottom, *paint);
811 static void doDrawGlyphsPos(SkCanvas* canvas, const jchar* glyphArray, const jfloat* posArray,
812 int index, int count, jfloat x, jfloat y, SkPaint* paint) {
813 SkPoint* posPtr = new SkPoint[count];
814 for (int indx = 0; indx < count; indx++) {
815 posPtr[indx].fX = SkFloatToScalar(x + posArray[indx * 2]);
816 posPtr[indx].fY = SkFloatToScalar(y + posArray[indx * 2 + 1]);
818 canvas->drawPosText(glyphArray, count << 1, posPtr, *paint);
822 static void drawTextRun___CIIIIFFPaint(
823 JNIEnv* env, jobject, SkCanvas* canvas, jcharArray text, int index,
824 int count, int contextIndex, int contextCount,
825 jfloat x, jfloat y, SkPaint* paint) {
827 jchar* chars = env->GetCharArrayElements(text, NULL);
828 drawTextWithGlyphs(canvas, chars + contextIndex, index - contextIndex,
829 count, contextCount, x, y, paint);
830 env->ReleaseCharArrayElements(text, chars, JNI_ABORT);
833 static void drawTextRun__StringIIIIFFPaint(
834 JNIEnv* env, jobject obj, SkCanvas* canvas, jstring text, jint start,
835 jint end, jint contextStart, jint contextEnd,
836 jfloat x, jfloat y, SkPaint* paint) {
838 jint count = end - start;
839 jint contextCount = contextEnd - contextStart;
840 const jchar* chars = env->GetStringChars(text, NULL);
841 drawTextWithGlyphs(canvas, chars + contextStart, start - contextStart,
842 count, contextCount, x, y, paint);
843 env->ReleaseStringChars(text, chars);
846 static void drawPosText___CII_FPaint(JNIEnv* env, jobject, SkCanvas* canvas,
847 jcharArray text, int index, int count,
848 jfloatArray pos, SkPaint* paint) {
849 jchar* textArray = text ? env->GetCharArrayElements(text, NULL) : NULL;
850 jsize textCount = text ? env->GetArrayLength(text) : NULL;
851 float* posArray = pos ? env->GetFloatArrayElements(pos, NULL) : NULL;
852 int posCount = pos ? env->GetArrayLength(pos) >> 1: 0;
853 SkPoint* posPtr = posCount > 0 ? new SkPoint[posCount] : NULL;
855 for (indx = 0; indx < posCount; indx++) {
856 posPtr[indx].fX = SkFloatToScalar(posArray[indx << 1]);
857 posPtr[indx].fY = SkFloatToScalar(posArray[(indx << 1) + 1]);
860 SkPaint::TextEncoding encoding = paint->getTextEncoding();
861 paint->setTextEncoding(SkPaint::kUTF16_TextEncoding);
862 canvas->drawPosText(textArray + index, count << 1, posPtr, *paint);
863 paint->setTextEncoding(encoding);
866 env->ReleaseCharArrayElements(text, textArray, 0);
869 env->ReleaseFloatArrayElements(pos, posArray, 0);
874 static void drawPosText__String_FPaint(JNIEnv* env, jobject,
875 SkCanvas* canvas, jstring text,
878 const void* text_ = text ? env->GetStringChars(text, NULL) : NULL;
879 int byteLength = text ? env->GetStringLength(text) : 0;
880 float* posArray = pos ? env->GetFloatArrayElements(pos, NULL) : NULL;
881 int posCount = pos ? env->GetArrayLength(pos) >> 1: 0;
882 SkPoint* posPtr = posCount > 0 ? new SkPoint[posCount] : NULL;
884 for (int indx = 0; indx < posCount; indx++) {
885 posPtr[indx].fX = SkFloatToScalar(posArray[indx << 1]);
886 posPtr[indx].fY = SkFloatToScalar(posArray[(indx << 1) + 1]);
889 SkPaint::TextEncoding encoding = paint->getTextEncoding();
890 paint->setTextEncoding(SkPaint::kUTF16_TextEncoding);
891 canvas->drawPosText(text_, byteLength << 1, posPtr, *paint);
892 paint->setTextEncoding(encoding);
895 env->ReleaseStringChars(text, (const jchar*) text_);
898 env->ReleaseFloatArrayElements(pos, posArray, 0);
903 static void drawTextOnPath___CIIPathFFPaint(JNIEnv* env, jobject,
904 SkCanvas* canvas, jcharArray text, int index, int count,
905 SkPath* path, jfloat hOffset, jfloat vOffset, SkPaint* paint) {
907 jchar* textArray = env->GetCharArrayElements(text, NULL);
908 TextLayout::drawTextOnPath(paint, textArray + index, count, hOffset, vOffset, path, canvas);
909 env->ReleaseCharArrayElements(text, textArray, 0);
912 static void drawTextOnPath__StringPathFFPaint(JNIEnv* env, jobject,
913 SkCanvas* canvas, jstring text, SkPath* path,
914 jfloat hOffset, jfloat vOffset, SkPaint* paint) {
915 const jchar* text_ = env->GetStringChars(text, NULL);
916 int count = env->GetStringLength(text);
917 TextLayout::drawTextOnPath(paint, text_, count, hOffset, vOffset, path, canvas);
918 env->ReleaseStringChars(text, text_);
921 static bool getClipBounds(JNIEnv* env, jobject, SkCanvas* canvas,
925 bool result = canvas->getClipBounds(&r);
930 // ensure the clip is not larger than the canvas
932 SkISize deviceSize = canvas->getDeviceSize();
933 canvasRect.iset(0, 0, deviceSize.fWidth, deviceSize.fHeight);
934 r.intersect(canvasRect);
938 (void)GraphicsJNI::irect_to_jrect(ir, env, bounds);
942 static void getCTM(JNIEnv* env, jobject, SkCanvas* canvas,
944 *matrix = canvas->getTotalMatrix();
948 static JNINativeMethod gCanvasMethods[] = {
949 {"finalizer", "(I)V", (void*) SkCanvasGlue::finalizer},
950 {"initRaster","(I)I", (void*) SkCanvasGlue::initRaster},
951 {"isOpaque","()Z", (void*) SkCanvasGlue::isOpaque},
952 {"getWidth","()I", (void*) SkCanvasGlue::getWidth},
953 {"getHeight","()I", (void*) SkCanvasGlue::getHeight},
954 {"save","()I", (void*) SkCanvasGlue::saveAll},
955 {"save","(I)I", (void*) SkCanvasGlue::save},
956 {"native_saveLayer","(ILandroid/graphics/RectF;II)I",
957 (void*) SkCanvasGlue::saveLayer},
958 {"native_saveLayer","(IFFFFII)I", (void*) SkCanvasGlue::saveLayer4F},
959 {"native_saveLayerAlpha","(ILandroid/graphics/RectF;II)I",
960 (void*) SkCanvasGlue::saveLayerAlpha},
961 {"native_saveLayerAlpha","(IFFFFII)I",
962 (void*) SkCanvasGlue::saveLayerAlpha4F},
963 {"restore","()V", (void*) SkCanvasGlue::restore},
964 {"getSaveCount","()I", (void*) SkCanvasGlue::getSaveCount},
965 {"restoreToCount","(I)V", (void*) SkCanvasGlue::restoreToCount},
966 {"translate","(FF)V", (void*) SkCanvasGlue::translate},
967 {"scale","(FF)V", (void*) SkCanvasGlue::scale__FF},
968 {"rotate","(F)V", (void*) SkCanvasGlue::rotate__F},
969 {"skew","(FF)V", (void*) SkCanvasGlue::skew__FF},
970 {"native_concat","(II)V", (void*) SkCanvasGlue::concat},
971 {"native_setMatrix","(II)V", (void*) SkCanvasGlue::setMatrix},
972 {"clipRect","(FFFF)Z", (void*) SkCanvasGlue::clipRect_FFFF},
973 {"clipRect","(IIII)Z", (void*) SkCanvasGlue::clipRect_IIII},
974 {"clipRect","(Landroid/graphics/RectF;)Z",
975 (void*) SkCanvasGlue::clipRect_RectF},
976 {"clipRect","(Landroid/graphics/Rect;)Z",
977 (void*) SkCanvasGlue::clipRect_Rect},
978 {"native_clipRect","(IFFFFI)Z", (void*) SkCanvasGlue::clipRect},
979 {"native_clipPath","(III)Z", (void*) SkCanvasGlue::clipPath},
980 {"native_clipRegion","(III)Z", (void*) SkCanvasGlue::clipRegion},
981 {"nativeSetDrawFilter", "(II)V", (void*) SkCanvasGlue::setDrawFilter},
982 {"native_getClipBounds","(ILandroid/graphics/Rect;)Z",
983 (void*) SkCanvasGlue::getClipBounds},
984 {"native_getCTM", "(II)V", (void*)SkCanvasGlue::getCTM},
985 {"native_quickReject","(ILandroid/graphics/RectF;)Z",
986 (void*) SkCanvasGlue::quickReject__RectF},
987 {"native_quickReject","(II)Z", (void*) SkCanvasGlue::quickReject__Path},
988 {"native_quickReject","(IFFFF)Z", (void*)SkCanvasGlue::quickReject__FFFF},
989 {"native_drawRGB","(IIII)V", (void*) SkCanvasGlue::drawRGB},
990 {"native_drawARGB","(IIIII)V", (void*) SkCanvasGlue::drawARGB},
991 {"native_drawColor","(II)V", (void*) SkCanvasGlue::drawColor__I},
992 {"native_drawColor","(III)V", (void*) SkCanvasGlue::drawColor__II},
993 {"native_drawPaint","(II)V", (void*) SkCanvasGlue::drawPaint},
994 {"drawPoint", "(FFLandroid/graphics/Paint;)V",
995 (void*) SkCanvasGlue::drawPoint},
996 {"drawPoints", "([FIILandroid/graphics/Paint;)V",
997 (void*) SkCanvasGlue::drawPoints},
998 {"drawLines", "([FIILandroid/graphics/Paint;)V",
999 (void*) SkCanvasGlue::drawLines},
1000 {"native_drawLine","(IFFFFI)V", (void*) SkCanvasGlue::drawLine__FFFFPaint},
1001 {"native_drawRect","(ILandroid/graphics/RectF;I)V",
1002 (void*) SkCanvasGlue::drawRect__RectFPaint},
1003 {"native_drawRect","(IFFFFI)V", (void*) SkCanvasGlue::drawRect__FFFFPaint},
1004 {"native_drawOval","(ILandroid/graphics/RectF;I)V",
1005 (void*) SkCanvasGlue::drawOval},
1006 {"native_drawCircle","(IFFFI)V", (void*) SkCanvasGlue::drawCircle},
1007 {"native_drawArc","(ILandroid/graphics/RectF;FFZI)V",
1008 (void*) SkCanvasGlue::drawArc},
1009 {"native_drawRoundRect","(ILandroid/graphics/RectF;FFI)V",
1010 (void*) SkCanvasGlue::drawRoundRect},
1011 {"native_drawPath","(III)V", (void*) SkCanvasGlue::drawPath},
1012 {"native_drawBitmap","(IIFFIIII)V",
1013 (void*) SkCanvasGlue::drawBitmap__BitmapFFPaint},
1014 {"native_drawBitmap","(IILandroid/graphics/Rect;Landroid/graphics/RectF;III)V",
1015 (void*) SkCanvasGlue::drawBitmapRF},
1016 {"native_drawBitmap","(IILandroid/graphics/Rect;Landroid/graphics/Rect;III)V",
1017 (void*) SkCanvasGlue::drawBitmapRR},
1018 {"native_drawBitmap", "(I[IIIFFIIZI)V",
1019 (void*)SkCanvasGlue::drawBitmapArray},
1020 {"nativeDrawBitmapMatrix", "(IIII)V",
1021 (void*)SkCanvasGlue::drawBitmapMatrix},
1022 {"nativeDrawBitmapMesh", "(IIII[FI[III)V",
1023 (void*)SkCanvasGlue::drawBitmapMesh},
1024 {"nativeDrawVertices", "(III[FI[FI[II[SIII)V",
1025 (void*)SkCanvasGlue::drawVertices},
1026 {"native_drawText","(I[CIIFFI)V",
1027 (void*) SkCanvasGlue::drawText___CIIFFPaint},
1028 {"native_drawText","(ILjava/lang/String;IIFFI)V",
1029 (void*) SkCanvasGlue::drawText__StringIIFFPaint},
1030 {"native_drawTextRun","(I[CIIIIFFI)V",
1031 (void*) SkCanvasGlue::drawTextRun___CIIIIFFPaint},
1032 {"native_drawTextRun","(ILjava/lang/String;IIIIFFI)V",
1033 (void*) SkCanvasGlue::drawTextRun__StringIIIIFFPaint},
1034 {"native_drawPosText","(I[CII[FI)V",
1035 (void*) SkCanvasGlue::drawPosText___CII_FPaint},
1036 {"native_drawPosText","(ILjava/lang/String;[FI)V",
1037 (void*) SkCanvasGlue::drawPosText__String_FPaint},
1038 {"native_drawTextOnPath","(I[CIIIFFI)V",
1039 (void*) SkCanvasGlue::drawTextOnPath___CIIPathFFPaint},
1040 {"native_drawTextOnPath","(ILjava/lang/String;IFFI)V",
1041 (void*) SkCanvasGlue::drawTextOnPath__StringPathFFPaint},
1042 {"native_drawPicture", "(II)V", (void*) SkCanvasGlue::drawPicture},
1044 {"freeCaches", "()V", (void*) SkCanvasGlue::freeCaches},
1046 {"freeTextLayoutCaches", "()V", (void*) SkCanvasGlue::freeTextLayoutCaches}
1049 ///////////////////////////////////////////////////////////////////////////////
1051 #include <android_runtime/AndroidRuntime.h>
1053 #define REG(env, name, array) \
1054 result = android::AndroidRuntime::registerNativeMethods(env, name, array, \
1055 SK_ARRAY_COUNT(array)); \
1056 if (result < 0) return result
1058 int register_android_graphics_Canvas(JNIEnv* env) {
1061 REG(env, "android/graphics/Canvas", gCanvasMethods);