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 "SkGLCanvas.h"
24 #include "SkGraphics.h"
25 #include "SkImageRef_GlobalPool.h"
26 #include "SkPorterDuff.h"
28 #include "SkTemplates.h"
30 #include "SkBoundaryPatch.h"
31 #include "SkMeshUtils.h"
35 static uint32_t get_thread_msec() {
36 #if defined(HAVE_POSIX_CLOCKS)
39 clock_gettime(CLOCK_THREAD_CPUTIME_ID, &tm);
41 return tm.tv_sec * 1000LL + tm.tv_nsec / 1000000;
45 gettimeofday(&tv, NULL);
46 return tv.tv_sec * 1000LL + tv.tv_usec / 1000;
55 static void finalizer(JNIEnv* env, jobject clazz, SkCanvas* canvas) {
59 static SkCanvas* initRaster(JNIEnv* env, jobject, SkBitmap* bitmap) {
60 return bitmap ? new SkCanvas(*bitmap) : new SkCanvas;
63 static SkCanvas* initGL(JNIEnv* env, jobject) {
64 return new SkGLCanvas;
67 static void freeCaches(JNIEnv* env, jobject) {
68 // these are called in no particular order
69 SkGLCanvas::DeleteAllTextures();
70 SkImageRef_GlobalPool::SetRAMUsed(0);
71 SkGraphics::SetFontCacheUsed(0);
74 static jboolean isOpaque(JNIEnv* env, jobject jcanvas) {
75 NPE_CHECK_RETURN_ZERO(env, jcanvas);
76 SkCanvas* canvas = GraphicsJNI::getNativeCanvas(env, jcanvas);
79 Currently we cannot support transparency in GL-based canvas' at
80 the view level. Therefore we cannot base our answer on the device's
81 bitmap, but need to hard-code the answer. If we relax this
82 limitation in views, we can simplify the following code as well.
84 Use the getViewport() call to find out if we're gl-based...
86 if (canvas->getViewport(NULL)) {
90 // normal technique, rely on the device's bitmap for the answer
91 return canvas->getDevice()->accessBitmap(false).isOpaque();
94 static int getWidth(JNIEnv* env, jobject jcanvas) {
95 NPE_CHECK_RETURN_ZERO(env, jcanvas);
96 SkCanvas* canvas = GraphicsJNI::getNativeCanvas(env, jcanvas);
97 return canvas->getDevice()->accessBitmap(false).width();
100 static int getHeight(JNIEnv* env, jobject jcanvas) {
101 NPE_CHECK_RETURN_ZERO(env, jcanvas);
102 SkCanvas* canvas = GraphicsJNI::getNativeCanvas(env, jcanvas);
103 return canvas->getDevice()->accessBitmap(false).height();
106 static void setViewport(JNIEnv* env, jobject, SkCanvas* canvas,
107 int width, int height) {
108 canvas->setViewport(width, height);
111 static void setBitmap(JNIEnv* env, jobject, SkCanvas* canvas,
113 canvas->setBitmapDevice(*bitmap);
116 static int saveAll(JNIEnv* env, jobject jcanvas) {
117 NPE_CHECK_RETURN_ZERO(env, jcanvas);
118 return GraphicsJNI::getNativeCanvas(env, jcanvas)->save();
121 static int save(JNIEnv* env, jobject jcanvas, SkCanvas::SaveFlags flags) {
122 NPE_CHECK_RETURN_ZERO(env, jcanvas);
123 return GraphicsJNI::getNativeCanvas(env, jcanvas)->save(flags);
126 static int saveLayer(JNIEnv* env, jobject, SkCanvas* canvas, jobject bounds,
127 SkPaint* paint, int flags) {
128 SkRect* bounds_ = NULL;
130 if (bounds != NULL) {
131 GraphicsJNI::jrectf_to_rect(env, bounds, &storage);
134 return canvas->saveLayer(bounds_, paint, (SkCanvas::SaveFlags)flags);
137 static int saveLayer4F(JNIEnv* env, jobject, SkCanvas* canvas,
138 jfloat l, jfloat t, jfloat r, jfloat b,
139 SkPaint* paint, int flags) {
141 bounds.set(SkFloatToScalar(l), SkFloatToScalar(t), SkFloatToScalar(r),
143 return canvas->saveLayer(&bounds, paint, (SkCanvas::SaveFlags)flags);
146 static int saveLayerAlpha(JNIEnv* env, jobject, SkCanvas* canvas,
147 jobject bounds, int alpha, int flags) {
148 SkRect* bounds_ = NULL;
150 if (bounds != NULL) {
151 GraphicsJNI::jrectf_to_rect(env, bounds, &storage);
154 return canvas->saveLayerAlpha(bounds_, alpha,
155 (SkCanvas::SaveFlags)flags);
158 static int saveLayerAlpha4F(JNIEnv* env, jobject, SkCanvas* canvas,
159 jfloat l, jfloat t, jfloat r, jfloat b,
160 int alpha, int flags) {
162 bounds.set(SkFloatToScalar(l), SkFloatToScalar(t), SkFloatToScalar(r),
164 return canvas->saveLayerAlpha(&bounds, alpha,
165 (SkCanvas::SaveFlags)flags);
168 static void restore(JNIEnv* env, jobject jcanvas) {
169 NPE_CHECK_RETURN_VOID(env, jcanvas);
170 SkCanvas* canvas = GraphicsJNI::getNativeCanvas(env, jcanvas);
171 if (canvas->getSaveCount() <= 1) { // cannot restore anymore
172 doThrowISE(env, "Underflow in restore");
178 static int getSaveCount(JNIEnv* env, jobject jcanvas) {
179 NPE_CHECK_RETURN_ZERO(env, jcanvas);
180 return GraphicsJNI::getNativeCanvas(env, jcanvas)->getSaveCount();
183 static void restoreToCount(JNIEnv* env, jobject jcanvas, int restoreCount) {
184 NPE_CHECK_RETURN_VOID(env, jcanvas);
185 SkCanvas* canvas = GraphicsJNI::getNativeCanvas(env, jcanvas);
186 if (restoreCount < 1) {
187 doThrowIAE(env, "Underflow in restoreToCount");
190 canvas->restoreToCount(restoreCount);
193 static void translate(JNIEnv* env, jobject jcanvas, jfloat dx, jfloat dy) {
194 NPE_CHECK_RETURN_VOID(env, jcanvas);
195 SkScalar dx_ = SkFloatToScalar(dx);
196 SkScalar dy_ = SkFloatToScalar(dy);
197 (void)GraphicsJNI::getNativeCanvas(env, jcanvas)->translate(dx_, dy_);
200 static void scale__FF(JNIEnv* env, jobject jcanvas, jfloat sx, jfloat sy) {
201 NPE_CHECK_RETURN_VOID(env, jcanvas);
202 SkScalar sx_ = SkFloatToScalar(sx);
203 SkScalar sy_ = SkFloatToScalar(sy);
204 (void)GraphicsJNI::getNativeCanvas(env, jcanvas)->scale(sx_, sy_);
207 static void rotate__F(JNIEnv* env, jobject jcanvas, jfloat degrees) {
208 NPE_CHECK_RETURN_VOID(env, jcanvas);
209 SkScalar degrees_ = SkFloatToScalar(degrees);
210 (void)GraphicsJNI::getNativeCanvas(env, jcanvas)->rotate(degrees_);
213 static void skew__FF(JNIEnv* env, jobject jcanvas, jfloat sx, jfloat sy) {
214 NPE_CHECK_RETURN_VOID(env, jcanvas);
215 SkScalar sx_ = SkFloatToScalar(sx);
216 SkScalar sy_ = SkFloatToScalar(sy);
217 (void)GraphicsJNI::getNativeCanvas(env, jcanvas)->skew(sx_, sy_);
220 static void concat(JNIEnv* env, jobject, SkCanvas* canvas,
221 const SkMatrix* matrix) {
222 canvas->concat(*matrix);
225 static void setMatrix(JNIEnv* env, jobject, SkCanvas* canvas,
226 const SkMatrix* matrix) {
227 if (NULL == matrix) {
228 canvas->resetMatrix();
230 canvas->setMatrix(*matrix);
234 static jboolean clipRect_FFFF(JNIEnv* env, jobject jcanvas, jfloat left,
235 jfloat top, jfloat right, jfloat bottom) {
236 NPE_CHECK_RETURN_ZERO(env, jcanvas);
238 r.set(SkFloatToScalar(left), SkFloatToScalar(top),
239 SkFloatToScalar(right), SkFloatToScalar(bottom));
240 SkCanvas* c = GraphicsJNI::getNativeCanvas(env, jcanvas);
241 return c->clipRect(r);
244 static jboolean clipRect_IIII(JNIEnv* env, jobject jcanvas, jint left,
245 jint top, jint right, jint bottom) {
246 NPE_CHECK_RETURN_ZERO(env, jcanvas);
248 r.set(SkIntToScalar(left), SkIntToScalar(top),
249 SkIntToScalar(right), SkIntToScalar(bottom));
250 return GraphicsJNI::getNativeCanvas(env, jcanvas)->clipRect(r);
253 static jboolean clipRect_RectF(JNIEnv* env, jobject jcanvas, jobject rectf) {
254 NPE_CHECK_RETURN_ZERO(env, jcanvas);
255 NPE_CHECK_RETURN_ZERO(env, rectf);
256 SkCanvas* c = GraphicsJNI::getNativeCanvas(env, jcanvas);
258 return c->clipRect(*GraphicsJNI::jrectf_to_rect(env, rectf, &tmp));
261 static jboolean clipRect_Rect(JNIEnv* env, jobject jcanvas, jobject rect) {
262 NPE_CHECK_RETURN_ZERO(env, jcanvas);
263 NPE_CHECK_RETURN_ZERO(env, rect);
264 SkCanvas* c = GraphicsJNI::getNativeCanvas(env, jcanvas);
266 return c->clipRect(*GraphicsJNI::jrect_to_rect(env, rect, &tmp));
269 static jboolean clipRect(JNIEnv* env, jobject, SkCanvas* canvas,
270 float left, float top, float right, float bottom,
273 rect.set(SkFloatToScalar(left), SkFloatToScalar(top),
274 SkFloatToScalar(right), SkFloatToScalar(bottom));
275 return canvas->clipRect(rect, (SkRegion::Op)op);
278 static jboolean clipPath(JNIEnv* env, jobject, SkCanvas* canvas,
279 SkPath* path, int op) {
280 return canvas->clipPath(*path, (SkRegion::Op)op);
283 static jboolean clipRegion(JNIEnv* env, jobject, SkCanvas* canvas,
284 SkRegion* deviceRgn, int op) {
285 return canvas->clipRegion(*deviceRgn, (SkRegion::Op)op);
288 static void setDrawFilter(JNIEnv* env, jobject, SkCanvas* canvas,
289 SkDrawFilter* filter) {
290 canvas->setDrawFilter(filter);
293 static jboolean quickReject__RectFI(JNIEnv* env, jobject, SkCanvas* canvas,
294 jobject rect, int edgetype) {
296 GraphicsJNI::jrectf_to_rect(env, rect, &rect_);
297 return canvas->quickReject(rect_, (SkCanvas::EdgeType)edgetype);
300 static jboolean quickReject__PathI(JNIEnv* env, jobject, SkCanvas* canvas,
301 SkPath* path, int edgetype) {
302 return canvas->quickReject(*path, (SkCanvas::EdgeType)edgetype);
305 static jboolean quickReject__FFFFI(JNIEnv* env, jobject, SkCanvas* canvas,
306 jfloat left, jfloat top, jfloat right,
307 jfloat bottom, int edgetype) {
309 r.set(SkFloatToScalar(left), SkFloatToScalar(top),
310 SkFloatToScalar(right), SkFloatToScalar(bottom));
311 return canvas->quickReject(r, (SkCanvas::EdgeType)edgetype);
314 static void drawRGB(JNIEnv* env, jobject, SkCanvas* canvas,
315 jint r, jint g, jint b) {
316 canvas->drawARGB(0xFF, r, g, b);
319 static void drawARGB(JNIEnv* env, jobject, SkCanvas* canvas,
320 jint a, jint r, jint g, jint b) {
321 canvas->drawARGB(a, r, g, b);
324 static void drawColor__I(JNIEnv* env, jobject, SkCanvas* canvas,
326 canvas->drawColor(color);
329 static void drawColor__II(JNIEnv* env, jobject, SkCanvas* canvas,
330 jint color, SkPorterDuff::Mode mode) {
331 canvas->drawColor(color, SkPorterDuff::ToXfermodeMode(mode));
334 static void drawPaint(JNIEnv* env, jobject, SkCanvas* canvas,
336 canvas->drawPaint(*paint);
339 static void doPoints(JNIEnv* env, jobject jcanvas, jfloatArray jptsArray,
340 jint offset, jint count, jobject jpaint,
341 SkCanvas::PointMode mode) {
342 NPE_CHECK_RETURN_VOID(env, jcanvas);
343 NPE_CHECK_RETURN_VOID(env, jptsArray);
344 NPE_CHECK_RETURN_VOID(env, jpaint);
345 SkCanvas* canvas = GraphicsJNI::getNativeCanvas(env, jcanvas);
346 const SkPaint& paint = *GraphicsJNI::getNativePaint(env, jpaint);
348 AutoJavaFloatArray autoPts(env, jptsArray);
349 float* floats = autoPts.ptr();
350 const int length = autoPts.length();
352 if ((offset | count) < 0 || offset + count > length) {
357 // now convert the floats into SkPoints
358 count >>= 1; // now it is the number of points
359 SkAutoSTMalloc<32, SkPoint> storage(count);
360 SkPoint* pts = storage.get();
361 const float* src = floats + offset;
362 for (int i = 0; i < count; i++) {
363 pts[i].set(SkFloatToScalar(src[0]), SkFloatToScalar(src[1]));
366 canvas->drawPoints(mode, count, pts, paint);
369 static void drawPoints(JNIEnv* env, jobject jcanvas, jfloatArray jptsArray,
370 jint offset, jint count, jobject jpaint) {
371 doPoints(env, jcanvas, jptsArray, offset, count, jpaint,
372 SkCanvas::kPoints_PointMode);
375 static void drawLines(JNIEnv* env, jobject jcanvas, jfloatArray jptsArray,
376 jint offset, jint count, jobject jpaint) {
377 doPoints(env, jcanvas, jptsArray, offset, count, jpaint,
378 SkCanvas::kLines_PointMode);
381 static void drawPoint(JNIEnv* env, jobject jcanvas, float x, float y,
383 NPE_CHECK_RETURN_VOID(env, jcanvas);
384 NPE_CHECK_RETURN_VOID(env, jpaint);
385 SkCanvas* canvas = GraphicsJNI::getNativeCanvas(env, jcanvas);
386 const SkPaint& paint = *GraphicsJNI::getNativePaint(env, jpaint);
388 canvas->drawPoint(SkFloatToScalar(x), SkFloatToScalar(y), paint);
391 static void drawLine__FFFFPaint(JNIEnv* env, jobject, SkCanvas* canvas,
392 jfloat startX, jfloat startY, jfloat stopX,
393 jfloat stopY, SkPaint* paint) {
394 canvas->drawLine(SkFloatToScalar(startX), SkFloatToScalar(startY),
395 SkFloatToScalar(stopX), SkFloatToScalar(stopY),
399 static void drawRect__RectFPaint(JNIEnv* env, jobject, SkCanvas* canvas,
400 jobject rect, SkPaint* paint) {
402 GraphicsJNI::jrectf_to_rect(env, rect, &rect_);
403 canvas->drawRect(rect_, *paint);
406 static void drawRect__FFFFPaint(JNIEnv* env, jobject, SkCanvas* canvas,
407 jfloat left, jfloat top, jfloat right,
408 jfloat bottom, SkPaint* paint) {
409 SkScalar left_ = SkFloatToScalar(left);
410 SkScalar top_ = SkFloatToScalar(top);
411 SkScalar right_ = SkFloatToScalar(right);
412 SkScalar bottom_ = SkFloatToScalar(bottom);
413 canvas->drawRectCoords(left_, top_, right_, bottom_, *paint);
416 static void drawOval(JNIEnv* env, jobject, SkCanvas* canvas, jobject joval,
419 GraphicsJNI::jrectf_to_rect(env, joval, &oval);
420 canvas->drawOval(oval, *paint);
423 static void drawCircle(JNIEnv* env, jobject, SkCanvas* canvas, jfloat cx,
424 jfloat cy, jfloat radius, SkPaint* paint) {
425 canvas->drawCircle(SkFloatToScalar(cx), SkFloatToScalar(cy),
426 SkFloatToScalar(radius), *paint);
429 static void drawArc(JNIEnv* env, jobject, SkCanvas* canvas, jobject joval,
430 jfloat startAngle, jfloat sweepAngle,
431 jboolean useCenter, SkPaint* paint) {
433 GraphicsJNI::jrectf_to_rect(env, joval, &oval);
434 canvas->drawArc(oval, SkFloatToScalar(startAngle),
435 SkFloatToScalar(sweepAngle), useCenter, *paint);
438 static void drawRoundRect(JNIEnv* env, jobject, SkCanvas* canvas,
439 jobject jrect, jfloat rx, jfloat ry,
442 GraphicsJNI::jrectf_to_rect(env, jrect, &rect);
443 canvas->drawRoundRect(rect, SkFloatToScalar(rx), SkFloatToScalar(ry),
447 static void drawPath(JNIEnv* env, jobject, SkCanvas* canvas, SkPath* path,
449 canvas->drawPath(*path, *paint);
452 static void drawPicture(JNIEnv* env, jobject, SkCanvas* canvas,
453 SkPicture* picture) {
458 SkMSec now = get_thread_msec(); //SkTime::GetMSecs();
460 canvas->drawPicture(*picture);
462 LOGD("---- picture playback %d ms\n", get_thread_msec() - now);
466 static void drawBitmap__BitmapFFPaint(JNIEnv* env, jobject jcanvas,
467 SkCanvas* canvas, SkBitmap* bitmap,
468 jfloat left, jfloat top,
469 SkPaint* paint, jint canvasDensity,
470 jint screenDensity, jint bitmapDensity) {
471 SkScalar left_ = SkFloatToScalar(left);
472 SkScalar top_ = SkFloatToScalar(top);
474 if (canvasDensity == bitmapDensity || canvasDensity == 0
475 || bitmapDensity == 0) {
476 if (screenDensity != 0 && screenDensity != bitmapDensity) {
477 SkPaint filteredPaint;
479 filteredPaint = *paint;
481 filteredPaint.setFilterBitmap(true);
482 canvas->drawBitmap(*bitmap, left_, top_, &filteredPaint);
484 canvas->drawBitmap(*bitmap, left_, top_, paint);
488 SkScalar scale = SkFloatToScalar(canvasDensity / (float)bitmapDensity);
489 canvas->translate(left_, top_);
490 canvas->scale(scale, scale);
492 SkPaint filteredPaint;
494 filteredPaint = *paint;
496 filteredPaint.setFilterBitmap(true);
498 canvas->drawBitmap(*bitmap, 0, 0, &filteredPaint);
504 static void doDrawBitmap(JNIEnv* env, SkCanvas* canvas, SkBitmap* bitmap,
505 jobject srcIRect, const SkRect& dst, SkPaint* paint,
506 jint screenDensity, jint bitmapDensity) {
507 SkIRect src, *srcPtr = NULL;
509 if (NULL != srcIRect) {
510 GraphicsJNI::jrect_to_irect(env, srcIRect, &src);
514 if (screenDensity != 0 && screenDensity != bitmapDensity) {
515 SkPaint filteredPaint;
517 filteredPaint = *paint;
519 filteredPaint.setFilterBitmap(true);
520 canvas->drawBitmapRect(*bitmap, srcPtr, dst, &filteredPaint);
522 canvas->drawBitmapRect(*bitmap, srcPtr, dst, paint);
526 static void drawBitmapRF(JNIEnv* env, jobject, SkCanvas* canvas,
527 SkBitmap* bitmap, jobject srcIRect,
528 jobject dstRectF, SkPaint* paint,
529 jint screenDensity, jint bitmapDensity) {
531 GraphicsJNI::jrectf_to_rect(env, dstRectF, &dst);
532 doDrawBitmap(env, canvas, bitmap, srcIRect, dst, paint,
533 screenDensity, bitmapDensity);
536 static void drawBitmapRR(JNIEnv* env, jobject, SkCanvas* canvas,
537 SkBitmap* bitmap, jobject srcIRect,
538 jobject dstRect, SkPaint* paint,
539 jint screenDensity, jint bitmapDensity) {
541 GraphicsJNI::jrect_to_rect(env, dstRect, &dst);
542 doDrawBitmap(env, canvas, bitmap, srcIRect, dst, paint,
543 screenDensity, bitmapDensity);
546 static void drawBitmapArray(JNIEnv* env, jobject, SkCanvas* canvas,
547 jintArray jcolors, int offset, int stride,
548 jfloat x, jfloat y, int width, int height,
549 jboolean hasAlpha, SkPaint* paint)
553 bitmap.setConfig(hasAlpha ? SkBitmap::kARGB_8888_Config :
554 SkBitmap::kRGB_565_Config, width, height);
555 if (!bitmap.allocPixels()) {
559 if (!GraphicsJNI::SetPixels(env, jcolors, offset, stride,
560 0, 0, width, height, bitmap)) {
564 canvas->drawBitmap(bitmap, SkFloatToScalar(x), SkFloatToScalar(y),
568 static void drawBitmapMatrix(JNIEnv* env, jobject, SkCanvas* canvas,
569 const SkBitmap* bitmap, const SkMatrix* matrix,
570 const SkPaint* paint) {
571 canvas->drawBitmapMatrix(*bitmap, *matrix, paint);
574 static void drawBitmapMesh(JNIEnv* env, jobject, SkCanvas* canvas,
575 const SkBitmap* bitmap, int meshWidth, int meshHeight,
576 jfloatArray jverts, int vertIndex, jintArray jcolors,
577 int colorIndex, const SkPaint* paint) {
579 const int ptCount = (meshWidth + 1) * (meshHeight + 1);
580 const int indexCount = meshWidth * meshHeight * 6;
582 AutoJavaFloatArray vertA(env, jverts, vertIndex + (ptCount << 1));
583 AutoJavaIntArray colorA(env, jcolors, colorIndex + ptCount);
585 /* Our temp storage holds 2 or 3 arrays.
586 texture points [ptCount * sizeof(SkPoint)]
587 optionally vertex points [ptCount * sizeof(SkPoint)] if we need a
588 copy to convert from float to fixed
589 indices [ptCount * sizeof(uint16_t)]
591 ssize_t storageSize = ptCount * sizeof(SkPoint); // texs[]
592 #ifdef SK_SCALAR_IS_FIXED
593 storageSize += ptCount * sizeof(SkPoint); // storage for verts
595 storageSize += indexCount * sizeof(uint16_t); // indices[]
597 SkAutoMalloc storage(storageSize);
598 SkPoint* texs = (SkPoint*)storage.get();
601 #ifdef SK_SCALAR_IS_FLOAT
602 verts = (SkPoint*)(vertA.ptr() + vertIndex);
603 indices = (uint16_t*)(texs + ptCount);
605 verts = texs + ptCount;
606 indices = (uint16_t*)(verts + ptCount);
607 // convert floats to fixed
609 const float* src = vertA.ptr() + vertIndex;
610 for (int i = 0; i < ptCount; i++) {
611 verts[i].set(SkFloatToFixed(src[0]), SkFloatToFixed(src[1]));
617 // cons up texture coordinates and indices
619 const SkScalar w = SkIntToScalar(bitmap->width());
620 const SkScalar h = SkIntToScalar(bitmap->height());
621 const SkScalar dx = w / meshWidth;
622 const SkScalar dy = h / meshHeight;
624 SkPoint* texsPtr = texs;
626 for (int i = 0; i <= meshHeight; i++) {
627 if (i == meshHeight) {
628 y = h; // to ensure numerically we hit h exactly
631 for (int j = 0; j < meshWidth; j++) {
640 SkASSERT(texsPtr - texs == ptCount);
645 uint16_t* indexPtr = indices;
647 for (int i = 0; i < meshHeight; i++) {
648 for (int j = 0; j < meshWidth; j++) {
649 // lower-left triangle
651 *indexPtr++ = index + meshWidth + 1;
652 *indexPtr++ = index + meshWidth + 2;
653 // upper-right triangle
655 *indexPtr++ = index + meshWidth + 2;
656 *indexPtr++ = index + 1;
657 // bump to the next cell
660 // bump to the next row
663 SkASSERT(indexPtr - indices == indexCount);
664 SkASSERT((char*)indexPtr - (char*)storage.get() == storageSize);
667 // double-check that we have legal indices
670 for (int i = 0; i < indexCount; i++) {
671 SkASSERT((unsigned)indices[i] < (unsigned)ptCount);
676 // cons-up a shader for the bitmap
681 SkShader* shader = SkShader::CreateBitmapShader(*bitmap,
682 SkShader::kClamp_TileMode, SkShader::kClamp_TileMode);
683 tmpPaint.setShader(shader)->safeUnref();
685 canvas->drawVertices(SkCanvas::kTriangles_VertexMode, ptCount, verts,
686 texs, (const SkColor*)colorA.ptr(), NULL, indices,
687 indexCount, tmpPaint);
690 static void drawVertices(JNIEnv* env, jobject, SkCanvas* canvas,
691 SkCanvas::VertexMode mode, int vertexCount,
692 jfloatArray jverts, int vertIndex,
693 jfloatArray jtexs, int texIndex,
694 jintArray jcolors, int colorIndex,
695 jshortArray jindices, int indexIndex,
696 int indexCount, const SkPaint* paint) {
698 AutoJavaFloatArray vertA(env, jverts, vertIndex + vertexCount);
699 AutoJavaFloatArray texA(env, jtexs, texIndex + vertexCount);
700 AutoJavaIntArray colorA(env, jcolors, colorIndex + vertexCount);
701 AutoJavaShortArray indexA(env, jindices, indexIndex + indexCount);
703 const int ptCount = vertexCount >> 1;
706 SkPoint* texs = NULL;
707 #ifdef SK_SCALAR_IS_FLOAT
708 verts = (SkPoint*)(vertA.ptr() + vertIndex);
710 texs = (SkPoint*)(texA.ptr() + texIndex);
713 int count = ptCount; // for verts
715 count += ptCount; // += for texs
717 SkAutoMalloc storage(count * sizeof(SkPoint));
718 verts = (SkPoint*)storage.get();
719 const float* src = vertA.ptr() + vertIndex;
720 for (int i = 0; i < ptCount; i++) {
721 verts[i].set(SkFloatToFixed(src[0]), SkFloatToFixed(src[1]));
725 texs = verts + ptCount;
726 src = texA.ptr() + texIndex;
727 for (int i = 0; i < ptCount; i++) {
728 texs[i].set(SkFloatToFixed(src[0]), SkFloatToFixed(src[1]));
734 const SkColor* colors = NULL;
735 const uint16_t* indices = NULL;
736 if (jcolors != NULL) {
737 colors = (const SkColor*)(colorA.ptr() + colorIndex);
739 if (jindices != NULL) {
740 indices = (const uint16_t*)(indexA.ptr() + indexIndex);
743 canvas->drawVertices(mode, ptCount, verts, texs, colors, NULL,
744 indices, indexCount, *paint);
747 static void drawText___CIIFFPaint(JNIEnv* env, jobject, SkCanvas* canvas,
748 jcharArray text, int index, int count,
749 jfloat x, jfloat y, SkPaint* paint) {
750 jchar* textArray = env->GetCharArrayElements(text, NULL);
751 jsize textCount = env->GetArrayLength(text);
752 SkScalar x_ = SkFloatToScalar(x);
753 SkScalar y_ = SkFloatToScalar(y);
754 canvas->drawText(textArray + index, count << 1, x_, y_, *paint);
755 env->ReleaseCharArrayElements(text, textArray, 0);
758 static void drawText__StringIIFFPaint(JNIEnv* env, jobject,
759 SkCanvas* canvas, jstring text, int start, int end,
760 jfloat x, jfloat y, SkPaint* paint) {
761 const void* text_ = env->GetStringChars(text, NULL);
762 SkScalar x_ = SkFloatToScalar(x);
763 SkScalar y_ = SkFloatToScalar(y);
764 canvas->drawText((const uint16_t*)text_ + start, (end - start) << 1,
766 env->ReleaseStringChars(text, (const jchar*) text_);
769 static void drawString(JNIEnv* env, jobject canvas, jstring text,
770 jfloat x, jfloat y, jobject paint) {
771 NPE_CHECK_RETURN_VOID(env, canvas);
772 NPE_CHECK_RETURN_VOID(env, paint);
773 NPE_CHECK_RETURN_VOID(env, text);
774 size_t count = env->GetStringLength(text);
778 const jchar* text_ = env->GetStringChars(text, NULL);
779 SkCanvas* c = GraphicsJNI::getNativeCanvas(env, canvas);
780 c->drawText(text_, count << 1, SkFloatToScalar(x), SkFloatToScalar(y),
781 *GraphicsJNI::getNativePaint(env, paint));
782 env->ReleaseStringChars(text, text_);
785 static void drawPosText___CII_FPaint(JNIEnv* env, jobject, SkCanvas* canvas,
786 jcharArray text, int index, int count,
787 jfloatArray pos, SkPaint* paint) {
788 jchar* textArray = text ? env->GetCharArrayElements(text, NULL) : NULL;
789 jsize textCount = text ? env->GetArrayLength(text) : NULL;
790 float* posArray = pos ? env->GetFloatArrayElements(pos, NULL) : NULL;
791 int posCount = pos ? env->GetArrayLength(pos) >> 1: 0;
792 SkPoint* posPtr = posCount > 0 ? new SkPoint[posCount] : NULL;
794 for (indx = 0; indx < posCount; indx++) {
795 posPtr[indx].fX = SkFloatToScalar(posArray[indx << 1]);
796 posPtr[indx].fY = SkFloatToScalar(posArray[(indx << 1) + 1]);
798 canvas->drawPosText(textArray + index, count << 1, posPtr, *paint);
800 env->ReleaseCharArrayElements(text, textArray, 0);
803 env->ReleaseFloatArrayElements(pos, posArray, 0);
808 static void drawPosText__String_FPaint(JNIEnv* env, jobject,
809 SkCanvas* canvas, jstring text,
810 jfloatArray pos, SkPaint* paint) {
811 const void* text_ = text ? env->GetStringChars(text, NULL) : NULL;
812 int byteLength = text ? env->GetStringLength(text) : 0;
813 float* posArray = pos ? env->GetFloatArrayElements(pos, NULL) : NULL;
814 int posCount = pos ? env->GetArrayLength(pos) >> 1: 0;
815 SkPoint* posPtr = posCount > 0 ? new SkPoint[posCount] : NULL;
817 for (int indx = 0; indx < posCount; indx++) {
818 posPtr[indx].fX = SkFloatToScalar(posArray[indx << 1]);
819 posPtr[indx].fY = SkFloatToScalar(posArray[(indx << 1) + 1]);
821 canvas->drawPosText(text_, byteLength << 1, posPtr, *paint);
823 env->ReleaseStringChars(text, (const jchar*) text_);
826 env->ReleaseFloatArrayElements(pos, posArray, 0);
831 static void drawTextOnPath___CIIPathFFPaint(JNIEnv* env, jobject,
832 SkCanvas* canvas, jcharArray text, int index, int count,
833 SkPath* path, jfloat hOffset, jfloat vOffset, SkPaint* paint) {
835 jchar* textArray = env->GetCharArrayElements(text, NULL);
836 canvas->drawTextOnPathHV(textArray + index, count << 1, *path,
837 SkFloatToScalar(hOffset), SkFloatToScalar(vOffset), *paint);
838 env->ReleaseCharArrayElements(text, textArray, 0);
841 static void drawTextOnPath__StringPathFFPaint(JNIEnv* env, jobject,
842 SkCanvas* canvas, jstring text, SkPath* path,
843 jfloat hOffset, jfloat vOffset, SkPaint* paint) {
844 const jchar* text_ = env->GetStringChars(text, NULL);
845 int byteLength = env->GetStringLength(text) << 1;
846 canvas->drawTextOnPathHV(text_, byteLength, *path,
847 SkFloatToScalar(hOffset), SkFloatToScalar(vOffset), *paint);
848 env->ReleaseStringChars(text, text_);
851 static bool getClipBounds(JNIEnv* env, jobject, SkCanvas* canvas,
855 bool result = canvas->getClipBounds(&r, SkCanvas::kBW_EdgeType);
858 (void)GraphicsJNI::irect_to_jrect(ir, env, bounds);
862 static void getCTM(JNIEnv* env, jobject, SkCanvas* canvas,
864 *matrix = canvas->getTotalMatrix();
868 static JNINativeMethod gCanvasMethods[] = {
869 {"finalizer", "(I)V", (void*) SkCanvasGlue::finalizer},
870 {"initRaster","(I)I", (void*) SkCanvasGlue::initRaster},
871 {"initGL","()I", (void*) SkCanvasGlue::initGL},
872 {"isOpaque","()Z", (void*) SkCanvasGlue::isOpaque},
873 {"getWidth","()I", (void*) SkCanvasGlue::getWidth},
874 {"getHeight","()I", (void*) SkCanvasGlue::getHeight},
875 {"native_setBitmap","(II)V", (void*) SkCanvasGlue::setBitmap},
876 {"nativeSetViewport", "(III)V", (void*) SkCanvasGlue::setViewport},
877 {"save","()I", (void*) SkCanvasGlue::saveAll},
878 {"save","(I)I", (void*) SkCanvasGlue::save},
879 {"native_saveLayer","(ILandroid/graphics/RectF;II)I",
880 (void*) SkCanvasGlue::saveLayer},
881 {"native_saveLayer","(IFFFFII)I", (void*) SkCanvasGlue::saveLayer4F},
882 {"native_saveLayerAlpha","(ILandroid/graphics/RectF;II)I",
883 (void*) SkCanvasGlue::saveLayerAlpha},
884 {"native_saveLayerAlpha","(IFFFFII)I",
885 (void*) SkCanvasGlue::saveLayerAlpha4F},
886 {"restore","()V", (void*) SkCanvasGlue::restore},
887 {"getSaveCount","()I", (void*) SkCanvasGlue::getSaveCount},
888 {"restoreToCount","(I)V", (void*) SkCanvasGlue::restoreToCount},
889 {"translate","(FF)V", (void*) SkCanvasGlue::translate},
890 {"scale","(FF)V", (void*) SkCanvasGlue::scale__FF},
891 {"rotate","(F)V", (void*) SkCanvasGlue::rotate__F},
892 {"skew","(FF)V", (void*) SkCanvasGlue::skew__FF},
893 {"native_concat","(II)V", (void*) SkCanvasGlue::concat},
894 {"native_setMatrix","(II)V", (void*) SkCanvasGlue::setMatrix},
895 {"clipRect","(FFFF)Z", (void*) SkCanvasGlue::clipRect_FFFF},
896 {"clipRect","(IIII)Z", (void*) SkCanvasGlue::clipRect_IIII},
897 {"clipRect","(Landroid/graphics/RectF;)Z",
898 (void*) SkCanvasGlue::clipRect_RectF},
899 {"clipRect","(Landroid/graphics/Rect;)Z",
900 (void*) SkCanvasGlue::clipRect_Rect},
901 {"native_clipRect","(IFFFFI)Z", (void*) SkCanvasGlue::clipRect},
902 {"native_clipPath","(III)Z", (void*) SkCanvasGlue::clipPath},
903 {"native_clipRegion","(III)Z", (void*) SkCanvasGlue::clipRegion},
904 {"nativeSetDrawFilter", "(II)V", (void*) SkCanvasGlue::setDrawFilter},
905 {"native_getClipBounds","(ILandroid/graphics/Rect;)Z",
906 (void*) SkCanvasGlue::getClipBounds},
907 {"native_getCTM", "(II)V", (void*)SkCanvasGlue::getCTM},
908 {"native_quickReject","(ILandroid/graphics/RectF;I)Z",
909 (void*) SkCanvasGlue::quickReject__RectFI},
910 {"native_quickReject","(III)Z", (void*) SkCanvasGlue::quickReject__PathI},
911 {"native_quickReject","(IFFFFI)Z", (void*)SkCanvasGlue::quickReject__FFFFI},
912 {"native_drawRGB","(IIII)V", (void*) SkCanvasGlue::drawRGB},
913 {"native_drawARGB","(IIIII)V", (void*) SkCanvasGlue::drawARGB},
914 {"native_drawColor","(II)V", (void*) SkCanvasGlue::drawColor__I},
915 {"native_drawColor","(III)V", (void*) SkCanvasGlue::drawColor__II},
916 {"native_drawPaint","(II)V", (void*) SkCanvasGlue::drawPaint},
917 {"drawPoint", "(FFLandroid/graphics/Paint;)V",
918 (void*) SkCanvasGlue::drawPoint},
919 {"drawPoints", "([FIILandroid/graphics/Paint;)V",
920 (void*) SkCanvasGlue::drawPoints},
921 {"drawLines", "([FIILandroid/graphics/Paint;)V",
922 (void*) SkCanvasGlue::drawLines},
923 {"native_drawLine","(IFFFFI)V", (void*) SkCanvasGlue::drawLine__FFFFPaint},
924 {"native_drawRect","(ILandroid/graphics/RectF;I)V",
925 (void*) SkCanvasGlue::drawRect__RectFPaint},
926 {"native_drawRect","(IFFFFI)V", (void*) SkCanvasGlue::drawRect__FFFFPaint},
927 {"native_drawOval","(ILandroid/graphics/RectF;I)V",
928 (void*) SkCanvasGlue::drawOval},
929 {"native_drawCircle","(IFFFI)V", (void*) SkCanvasGlue::drawCircle},
930 {"native_drawArc","(ILandroid/graphics/RectF;FFZI)V",
931 (void*) SkCanvasGlue::drawArc},
932 {"native_drawRoundRect","(ILandroid/graphics/RectF;FFI)V",
933 (void*) SkCanvasGlue::drawRoundRect},
934 {"native_drawPath","(III)V", (void*) SkCanvasGlue::drawPath},
935 {"native_drawBitmap","(IIFFIIII)V",
936 (void*) SkCanvasGlue::drawBitmap__BitmapFFPaint},
937 {"native_drawBitmap","(IILandroid/graphics/Rect;Landroid/graphics/RectF;III)V",
938 (void*) SkCanvasGlue::drawBitmapRF},
939 {"native_drawBitmap","(IILandroid/graphics/Rect;Landroid/graphics/Rect;III)V",
940 (void*) SkCanvasGlue::drawBitmapRR},
941 {"native_drawBitmap", "(I[IIIFFIIZI)V",
942 (void*)SkCanvasGlue::drawBitmapArray},
944 {"nativeDrawBitmapMatrix", "(IIII)V",
945 (void*)SkCanvasGlue::drawBitmapMatrix},
946 {"nativeDrawBitmapMesh", "(IIII[FI[III)V",
947 (void*)SkCanvasGlue::drawBitmapMesh},
948 {"nativeDrawVertices", "(III[FI[FI[II[SIII)V",
949 (void*)SkCanvasGlue::drawVertices},
950 {"native_drawText","(I[CIIFFI)V",
951 (void*) SkCanvasGlue::drawText___CIIFFPaint},
952 {"native_drawText","(ILjava/lang/String;IIFFI)V",
953 (void*) SkCanvasGlue::drawText__StringIIFFPaint},
954 {"drawText","(Ljava/lang/String;FFLandroid/graphics/Paint;)V",
955 (void*) SkCanvasGlue::drawString},
956 {"native_drawPosText","(I[CII[FI)V",
957 (void*) SkCanvasGlue::drawPosText___CII_FPaint},
958 {"native_drawPosText","(ILjava/lang/String;[FI)V",
959 (void*) SkCanvasGlue::drawPosText__String_FPaint},
960 {"native_drawTextOnPath","(I[CIIIFFI)V",
961 (void*) SkCanvasGlue::drawTextOnPath___CIIPathFFPaint},
962 {"native_drawTextOnPath","(ILjava/lang/String;IFFI)V",
963 (void*) SkCanvasGlue::drawTextOnPath__StringPathFFPaint},
964 {"native_drawPicture", "(II)V", (void*) SkCanvasGlue::drawPicture},
966 {"freeCaches", "()V", (void*) SkCanvasGlue::freeCaches}
969 ///////////////////////////////////////////////////////////////////////////////
971 static void BoundaryPatch_computeCubic(JNIEnv* env, jobject, jfloatArray jpts,
972 int texW, int texH, int rows, int cols,
973 jfloatArray jverts, jshortArray jidx) {
974 AutoJavaFloatArray ptsArray(env, jpts, 24, kRO_JNIAccess);
976 int vertCount = rows * cols;
977 AutoJavaFloatArray vertsArray(env, jverts, vertCount * 4, kRW_JNIAccess);
978 SkPoint* verts = (SkPoint*)vertsArray.ptr();
979 SkPoint* texs = verts + vertCount;
981 int idxCount = (rows - 1) * (cols - 1) * 6;
982 AutoJavaShortArray idxArray(env, jidx, idxCount, kRW_JNIAccess);
983 uint16_t* idx = (uint16_t*)idxArray.ptr(); // cast from int16_t*
985 SkCubicBoundary cubic;
986 memcpy(cubic.fPts, ptsArray.ptr(), 12 * sizeof(SkPoint));
988 SkBoundaryPatch patch;
989 patch.setBoundary(&cubic);
990 // generate our verts
991 patch.evalPatch(verts, rows, cols);
994 // generate our texs and idx
995 mesh.init(texs, idx, texW, texH, rows, cols);
998 static JNINativeMethod gBoundaryPatchMethods[] = {
999 {"nativeComputeCubicPatch", "([FIIII[F[S)V",
1000 (void*)BoundaryPatch_computeCubic },
1003 ///////////////////////////////////////////////////////////////////////////////
1005 #include <android_runtime/AndroidRuntime.h>
1007 #define REG(env, name, array) \
1008 result = android::AndroidRuntime::registerNativeMethods(env, name, array, \
1009 SK_ARRAY_COUNT(array)); \
1010 if (result < 0) return result
1012 int register_android_graphics_Canvas(JNIEnv* env) {
1015 REG(env, "android/graphics/Canvas", gCanvasMethods);
1016 REG(env, "android/graphics/utils/BoundaryPatch", gBoundaryPatchMethods);