1022 lines
41 KiB
C++
1022 lines
41 KiB
C++
/*
|
|
* Copyright (C) 2006-2007 The Android Open Source Project
|
|
*
|
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
* you may not use this file except in compliance with the License.
|
|
* You may obtain a copy of the License at
|
|
*
|
|
* http://www.apache.org/licenses/LICENSE-2.0
|
|
*
|
|
* Unless required by applicable law or agreed to in writing, software
|
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
* See the License for the specific language governing permissions and
|
|
* limitations under the License.
|
|
*/
|
|
|
|
#include "jni.h"
|
|
#include "GraphicsJNI.h"
|
|
#include <android_runtime/AndroidRuntime.h>
|
|
|
|
#include "SkCanvas.h"
|
|
#include "SkDevice.h"
|
|
#include "SkGLCanvas.h"
|
|
#include "SkGraphics.h"
|
|
#include "SkImageRef_GlobalPool.h"
|
|
#include "SkPorterDuff.h"
|
|
#include "SkShader.h"
|
|
#include "SkTemplates.h"
|
|
|
|
#include "SkBoundaryPatch.h"
|
|
#include "SkMeshUtils.h"
|
|
|
|
#define TIME_DRAWx
|
|
|
|
static uint32_t get_thread_msec() {
|
|
#if defined(HAVE_POSIX_CLOCKS)
|
|
struct timespec tm;
|
|
|
|
clock_gettime(CLOCK_THREAD_CPUTIME_ID, &tm);
|
|
|
|
return tm.tv_sec * 1000LL + tm.tv_nsec / 1000000;
|
|
#else
|
|
struct timeval tv;
|
|
|
|
gettimeofday(&tv, NULL);
|
|
return tv.tv_sec * 1000LL + tv.tv_usec / 1000;
|
|
#endif
|
|
}
|
|
|
|
namespace android {
|
|
|
|
class SkCanvasGlue {
|
|
public:
|
|
|
|
static void finalizer(JNIEnv* env, jobject clazz, SkCanvas* canvas) {
|
|
canvas->unref();
|
|
}
|
|
|
|
static SkCanvas* initRaster(JNIEnv* env, jobject, SkBitmap* bitmap) {
|
|
return bitmap ? new SkCanvas(*bitmap) : new SkCanvas;
|
|
}
|
|
|
|
static SkCanvas* initGL(JNIEnv* env, jobject) {
|
|
return new SkGLCanvas;
|
|
}
|
|
|
|
static void freeCaches(JNIEnv* env, jobject) {
|
|
// these are called in no particular order
|
|
SkGLCanvas::DeleteAllTextures();
|
|
SkImageRef_GlobalPool::SetRAMUsed(0);
|
|
SkGraphics::SetFontCacheUsed(0);
|
|
}
|
|
|
|
static jboolean isOpaque(JNIEnv* env, jobject jcanvas) {
|
|
NPE_CHECK_RETURN_ZERO(env, jcanvas);
|
|
SkCanvas* canvas = GraphicsJNI::getNativeCanvas(env, jcanvas);
|
|
|
|
/*
|
|
Currently we cannot support transparency in GL-based canvas' at
|
|
the view level. Therefore we cannot base our answer on the device's
|
|
bitmap, but need to hard-code the answer. If we relax this
|
|
limitation in views, we can simplify the following code as well.
|
|
|
|
Use the getViewport() call to find out if we're gl-based...
|
|
*/
|
|
if (canvas->getViewport(NULL)) {
|
|
return true;
|
|
}
|
|
|
|
// normal technique, rely on the device's bitmap for the answer
|
|
return canvas->getDevice()->accessBitmap(false).isOpaque();
|
|
}
|
|
|
|
static int getWidth(JNIEnv* env, jobject jcanvas) {
|
|
NPE_CHECK_RETURN_ZERO(env, jcanvas);
|
|
SkCanvas* canvas = GraphicsJNI::getNativeCanvas(env, jcanvas);
|
|
return canvas->getDevice()->accessBitmap(false).width();
|
|
}
|
|
|
|
static int getHeight(JNIEnv* env, jobject jcanvas) {
|
|
NPE_CHECK_RETURN_ZERO(env, jcanvas);
|
|
SkCanvas* canvas = GraphicsJNI::getNativeCanvas(env, jcanvas);
|
|
return canvas->getDevice()->accessBitmap(false).height();
|
|
}
|
|
|
|
static void setViewport(JNIEnv* env, jobject, SkCanvas* canvas,
|
|
int width, int height) {
|
|
canvas->setViewport(width, height);
|
|
}
|
|
|
|
static void setBitmap(JNIEnv* env, jobject, SkCanvas* canvas,
|
|
SkBitmap* bitmap) {
|
|
canvas->setBitmapDevice(*bitmap);
|
|
}
|
|
|
|
static int saveAll(JNIEnv* env, jobject jcanvas) {
|
|
NPE_CHECK_RETURN_ZERO(env, jcanvas);
|
|
return GraphicsJNI::getNativeCanvas(env, jcanvas)->save();
|
|
}
|
|
|
|
static int save(JNIEnv* env, jobject jcanvas, SkCanvas::SaveFlags flags) {
|
|
NPE_CHECK_RETURN_ZERO(env, jcanvas);
|
|
return GraphicsJNI::getNativeCanvas(env, jcanvas)->save(flags);
|
|
}
|
|
|
|
static int saveLayer(JNIEnv* env, jobject, SkCanvas* canvas, jobject bounds,
|
|
SkPaint* paint, int flags) {
|
|
SkRect* bounds_ = NULL;
|
|
SkRect storage;
|
|
if (bounds != NULL) {
|
|
GraphicsJNI::jrectf_to_rect(env, bounds, &storage);
|
|
bounds_ = &storage;
|
|
}
|
|
return canvas->saveLayer(bounds_, paint, (SkCanvas::SaveFlags)flags);
|
|
}
|
|
|
|
static int saveLayer4F(JNIEnv* env, jobject, SkCanvas* canvas,
|
|
jfloat l, jfloat t, jfloat r, jfloat b,
|
|
SkPaint* paint, int flags) {
|
|
SkRect bounds;
|
|
bounds.set(SkFloatToScalar(l), SkFloatToScalar(t), SkFloatToScalar(r),
|
|
SkFloatToScalar(b));
|
|
return canvas->saveLayer(&bounds, paint, (SkCanvas::SaveFlags)flags);
|
|
}
|
|
|
|
static int saveLayerAlpha(JNIEnv* env, jobject, SkCanvas* canvas,
|
|
jobject bounds, int alpha, int flags) {
|
|
SkRect* bounds_ = NULL;
|
|
SkRect storage;
|
|
if (bounds != NULL) {
|
|
GraphicsJNI::jrectf_to_rect(env, bounds, &storage);
|
|
bounds_ = &storage;
|
|
}
|
|
return canvas->saveLayerAlpha(bounds_, alpha,
|
|
(SkCanvas::SaveFlags)flags);
|
|
}
|
|
|
|
static int saveLayerAlpha4F(JNIEnv* env, jobject, SkCanvas* canvas,
|
|
jfloat l, jfloat t, jfloat r, jfloat b,
|
|
int alpha, int flags) {
|
|
SkRect bounds;
|
|
bounds.set(SkFloatToScalar(l), SkFloatToScalar(t), SkFloatToScalar(r),
|
|
SkFloatToScalar(b));
|
|
return canvas->saveLayerAlpha(&bounds, alpha,
|
|
(SkCanvas::SaveFlags)flags);
|
|
}
|
|
|
|
static void restore(JNIEnv* env, jobject jcanvas) {
|
|
NPE_CHECK_RETURN_VOID(env, jcanvas);
|
|
SkCanvas* canvas = GraphicsJNI::getNativeCanvas(env, jcanvas);
|
|
if (canvas->getSaveCount() <= 1) { // cannot restore anymore
|
|
doThrowISE(env, "Underflow in restore");
|
|
return;
|
|
}
|
|
canvas->restore();
|
|
}
|
|
|
|
static int getSaveCount(JNIEnv* env, jobject jcanvas) {
|
|
NPE_CHECK_RETURN_ZERO(env, jcanvas);
|
|
return GraphicsJNI::getNativeCanvas(env, jcanvas)->getSaveCount();
|
|
}
|
|
|
|
static void restoreToCount(JNIEnv* env, jobject jcanvas, int restoreCount) {
|
|
NPE_CHECK_RETURN_VOID(env, jcanvas);
|
|
SkCanvas* canvas = GraphicsJNI::getNativeCanvas(env, jcanvas);
|
|
if (restoreCount < 1) {
|
|
doThrowIAE(env, "Underflow in restoreToCount");
|
|
return;
|
|
}
|
|
canvas->restoreToCount(restoreCount);
|
|
}
|
|
|
|
static void translate(JNIEnv* env, jobject jcanvas, jfloat dx, jfloat dy) {
|
|
NPE_CHECK_RETURN_VOID(env, jcanvas);
|
|
SkScalar dx_ = SkFloatToScalar(dx);
|
|
SkScalar dy_ = SkFloatToScalar(dy);
|
|
(void)GraphicsJNI::getNativeCanvas(env, jcanvas)->translate(dx_, dy_);
|
|
}
|
|
|
|
static void scale__FF(JNIEnv* env, jobject jcanvas, jfloat sx, jfloat sy) {
|
|
NPE_CHECK_RETURN_VOID(env, jcanvas);
|
|
SkScalar sx_ = SkFloatToScalar(sx);
|
|
SkScalar sy_ = SkFloatToScalar(sy);
|
|
(void)GraphicsJNI::getNativeCanvas(env, jcanvas)->scale(sx_, sy_);
|
|
}
|
|
|
|
static void rotate__F(JNIEnv* env, jobject jcanvas, jfloat degrees) {
|
|
NPE_CHECK_RETURN_VOID(env, jcanvas);
|
|
SkScalar degrees_ = SkFloatToScalar(degrees);
|
|
(void)GraphicsJNI::getNativeCanvas(env, jcanvas)->rotate(degrees_);
|
|
}
|
|
|
|
static void skew__FF(JNIEnv* env, jobject jcanvas, jfloat sx, jfloat sy) {
|
|
NPE_CHECK_RETURN_VOID(env, jcanvas);
|
|
SkScalar sx_ = SkFloatToScalar(sx);
|
|
SkScalar sy_ = SkFloatToScalar(sy);
|
|
(void)GraphicsJNI::getNativeCanvas(env, jcanvas)->skew(sx_, sy_);
|
|
}
|
|
|
|
static void concat(JNIEnv* env, jobject, SkCanvas* canvas,
|
|
const SkMatrix* matrix) {
|
|
canvas->concat(*matrix);
|
|
}
|
|
|
|
static void setMatrix(JNIEnv* env, jobject, SkCanvas* canvas,
|
|
const SkMatrix* matrix) {
|
|
if (NULL == matrix) {
|
|
canvas->resetMatrix();
|
|
} else {
|
|
canvas->setMatrix(*matrix);
|
|
}
|
|
}
|
|
|
|
static jboolean clipRect_FFFF(JNIEnv* env, jobject jcanvas, jfloat left,
|
|
jfloat top, jfloat right, jfloat bottom) {
|
|
NPE_CHECK_RETURN_ZERO(env, jcanvas);
|
|
SkRect r;
|
|
r.set(SkFloatToScalar(left), SkFloatToScalar(top),
|
|
SkFloatToScalar(right), SkFloatToScalar(bottom));
|
|
SkCanvas* c = GraphicsJNI::getNativeCanvas(env, jcanvas);
|
|
return c->clipRect(r);
|
|
}
|
|
|
|
static jboolean clipRect_IIII(JNIEnv* env, jobject jcanvas, jint left,
|
|
jint top, jint right, jint bottom) {
|
|
NPE_CHECK_RETURN_ZERO(env, jcanvas);
|
|
SkRect r;
|
|
r.set(SkIntToScalar(left), SkIntToScalar(top),
|
|
SkIntToScalar(right), SkIntToScalar(bottom));
|
|
return GraphicsJNI::getNativeCanvas(env, jcanvas)->clipRect(r);
|
|
}
|
|
|
|
static jboolean clipRect_RectF(JNIEnv* env, jobject jcanvas, jobject rectf) {
|
|
NPE_CHECK_RETURN_ZERO(env, jcanvas);
|
|
NPE_CHECK_RETURN_ZERO(env, rectf);
|
|
SkCanvas* c = GraphicsJNI::getNativeCanvas(env, jcanvas);
|
|
SkRect tmp;
|
|
return c->clipRect(*GraphicsJNI::jrectf_to_rect(env, rectf, &tmp));
|
|
}
|
|
|
|
static jboolean clipRect_Rect(JNIEnv* env, jobject jcanvas, jobject rect) {
|
|
NPE_CHECK_RETURN_ZERO(env, jcanvas);
|
|
NPE_CHECK_RETURN_ZERO(env, rect);
|
|
SkCanvas* c = GraphicsJNI::getNativeCanvas(env, jcanvas);
|
|
SkRect tmp;
|
|
return c->clipRect(*GraphicsJNI::jrect_to_rect(env, rect, &tmp));
|
|
}
|
|
|
|
static jboolean clipRect(JNIEnv* env, jobject, SkCanvas* canvas,
|
|
float left, float top, float right, float bottom,
|
|
int op) {
|
|
SkRect rect;
|
|
rect.set(SkFloatToScalar(left), SkFloatToScalar(top),
|
|
SkFloatToScalar(right), SkFloatToScalar(bottom));
|
|
return canvas->clipRect(rect, (SkRegion::Op)op);
|
|
}
|
|
|
|
static jboolean clipPath(JNIEnv* env, jobject, SkCanvas* canvas,
|
|
SkPath* path, int op) {
|
|
return canvas->clipPath(*path, (SkRegion::Op)op);
|
|
}
|
|
|
|
static jboolean clipRegion(JNIEnv* env, jobject, SkCanvas* canvas,
|
|
SkRegion* deviceRgn, int op) {
|
|
return canvas->clipRegion(*deviceRgn, (SkRegion::Op)op);
|
|
}
|
|
|
|
static void setDrawFilter(JNIEnv* env, jobject, SkCanvas* canvas,
|
|
SkDrawFilter* filter) {
|
|
canvas->setDrawFilter(filter);
|
|
}
|
|
|
|
static jboolean quickReject__RectFI(JNIEnv* env, jobject, SkCanvas* canvas,
|
|
jobject rect, int edgetype) {
|
|
SkRect rect_;
|
|
GraphicsJNI::jrectf_to_rect(env, rect, &rect_);
|
|
return canvas->quickReject(rect_, (SkCanvas::EdgeType)edgetype);
|
|
}
|
|
|
|
static jboolean quickReject__PathI(JNIEnv* env, jobject, SkCanvas* canvas,
|
|
SkPath* path, int edgetype) {
|
|
return canvas->quickReject(*path, (SkCanvas::EdgeType)edgetype);
|
|
}
|
|
|
|
static jboolean quickReject__FFFFI(JNIEnv* env, jobject, SkCanvas* canvas,
|
|
jfloat left, jfloat top, jfloat right,
|
|
jfloat bottom, int edgetype) {
|
|
SkRect r;
|
|
r.set(SkFloatToScalar(left), SkFloatToScalar(top),
|
|
SkFloatToScalar(right), SkFloatToScalar(bottom));
|
|
return canvas->quickReject(r, (SkCanvas::EdgeType)edgetype);
|
|
}
|
|
|
|
static void drawRGB(JNIEnv* env, jobject, SkCanvas* canvas,
|
|
jint r, jint g, jint b) {
|
|
canvas->drawARGB(0xFF, r, g, b);
|
|
}
|
|
|
|
static void drawARGB(JNIEnv* env, jobject, SkCanvas* canvas,
|
|
jint a, jint r, jint g, jint b) {
|
|
canvas->drawARGB(a, r, g, b);
|
|
}
|
|
|
|
static void drawColor__I(JNIEnv* env, jobject, SkCanvas* canvas,
|
|
jint color) {
|
|
canvas->drawColor(color);
|
|
}
|
|
|
|
static void drawColor__II(JNIEnv* env, jobject, SkCanvas* canvas,
|
|
jint color, SkPorterDuff::Mode mode) {
|
|
canvas->drawColor(color, SkPorterDuff::ToXfermodeMode(mode));
|
|
}
|
|
|
|
static void drawPaint(JNIEnv* env, jobject, SkCanvas* canvas,
|
|
SkPaint* paint) {
|
|
canvas->drawPaint(*paint);
|
|
}
|
|
|
|
static void doPoints(JNIEnv* env, jobject jcanvas, jfloatArray jptsArray,
|
|
jint offset, jint count, jobject jpaint,
|
|
SkCanvas::PointMode mode) {
|
|
NPE_CHECK_RETURN_VOID(env, jcanvas);
|
|
NPE_CHECK_RETURN_VOID(env, jptsArray);
|
|
NPE_CHECK_RETURN_VOID(env, jpaint);
|
|
SkCanvas* canvas = GraphicsJNI::getNativeCanvas(env, jcanvas);
|
|
const SkPaint& paint = *GraphicsJNI::getNativePaint(env, jpaint);
|
|
|
|
AutoJavaFloatArray autoPts(env, jptsArray);
|
|
float* floats = autoPts.ptr();
|
|
const int length = autoPts.length();
|
|
|
|
if ((offset | count) < 0 || offset + count > length) {
|
|
doThrowAIOOBE(env);
|
|
return;
|
|
}
|
|
|
|
// now convert the floats into SkPoints
|
|
count >>= 1; // now it is the number of points
|
|
SkAutoSTMalloc<32, SkPoint> storage(count);
|
|
SkPoint* pts = storage.get();
|
|
const float* src = floats + offset;
|
|
for (int i = 0; i < count; i++) {
|
|
pts[i].set(SkFloatToScalar(src[0]), SkFloatToScalar(src[1]));
|
|
src += 2;
|
|
}
|
|
canvas->drawPoints(mode, count, pts, paint);
|
|
}
|
|
|
|
static void drawPoints(JNIEnv* env, jobject jcanvas, jfloatArray jptsArray,
|
|
jint offset, jint count, jobject jpaint) {
|
|
doPoints(env, jcanvas, jptsArray, offset, count, jpaint,
|
|
SkCanvas::kPoints_PointMode);
|
|
}
|
|
|
|
static void drawLines(JNIEnv* env, jobject jcanvas, jfloatArray jptsArray,
|
|
jint offset, jint count, jobject jpaint) {
|
|
doPoints(env, jcanvas, jptsArray, offset, count, jpaint,
|
|
SkCanvas::kLines_PointMode);
|
|
}
|
|
|
|
static void drawPoint(JNIEnv* env, jobject jcanvas, float x, float y,
|
|
jobject jpaint) {
|
|
NPE_CHECK_RETURN_VOID(env, jcanvas);
|
|
NPE_CHECK_RETURN_VOID(env, jpaint);
|
|
SkCanvas* canvas = GraphicsJNI::getNativeCanvas(env, jcanvas);
|
|
const SkPaint& paint = *GraphicsJNI::getNativePaint(env, jpaint);
|
|
|
|
canvas->drawPoint(SkFloatToScalar(x), SkFloatToScalar(y), paint);
|
|
}
|
|
|
|
static void drawLine__FFFFPaint(JNIEnv* env, jobject, SkCanvas* canvas,
|
|
jfloat startX, jfloat startY, jfloat stopX,
|
|
jfloat stopY, SkPaint* paint) {
|
|
canvas->drawLine(SkFloatToScalar(startX), SkFloatToScalar(startY),
|
|
SkFloatToScalar(stopX), SkFloatToScalar(stopY),
|
|
*paint);
|
|
}
|
|
|
|
static void drawRect__RectFPaint(JNIEnv* env, jobject, SkCanvas* canvas,
|
|
jobject rect, SkPaint* paint) {
|
|
SkRect rect_;
|
|
GraphicsJNI::jrectf_to_rect(env, rect, &rect_);
|
|
canvas->drawRect(rect_, *paint);
|
|
}
|
|
|
|
static void drawRect__FFFFPaint(JNIEnv* env, jobject, SkCanvas* canvas,
|
|
jfloat left, jfloat top, jfloat right,
|
|
jfloat bottom, SkPaint* paint) {
|
|
SkScalar left_ = SkFloatToScalar(left);
|
|
SkScalar top_ = SkFloatToScalar(top);
|
|
SkScalar right_ = SkFloatToScalar(right);
|
|
SkScalar bottom_ = SkFloatToScalar(bottom);
|
|
canvas->drawRectCoords(left_, top_, right_, bottom_, *paint);
|
|
}
|
|
|
|
static void drawOval(JNIEnv* env, jobject, SkCanvas* canvas, jobject joval,
|
|
SkPaint* paint) {
|
|
SkRect oval;
|
|
GraphicsJNI::jrectf_to_rect(env, joval, &oval);
|
|
canvas->drawOval(oval, *paint);
|
|
}
|
|
|
|
static void drawCircle(JNIEnv* env, jobject, SkCanvas* canvas, jfloat cx,
|
|
jfloat cy, jfloat radius, SkPaint* paint) {
|
|
canvas->drawCircle(SkFloatToScalar(cx), SkFloatToScalar(cy),
|
|
SkFloatToScalar(radius), *paint);
|
|
}
|
|
|
|
static void drawArc(JNIEnv* env, jobject, SkCanvas* canvas, jobject joval,
|
|
jfloat startAngle, jfloat sweepAngle,
|
|
jboolean useCenter, SkPaint* paint) {
|
|
SkRect oval;
|
|
GraphicsJNI::jrectf_to_rect(env, joval, &oval);
|
|
canvas->drawArc(oval, SkFloatToScalar(startAngle),
|
|
SkFloatToScalar(sweepAngle), useCenter, *paint);
|
|
}
|
|
|
|
static void drawRoundRect(JNIEnv* env, jobject, SkCanvas* canvas,
|
|
jobject jrect, jfloat rx, jfloat ry,
|
|
SkPaint* paint) {
|
|
SkRect rect;
|
|
GraphicsJNI::jrectf_to_rect(env, jrect, &rect);
|
|
canvas->drawRoundRect(rect, SkFloatToScalar(rx), SkFloatToScalar(ry),
|
|
*paint);
|
|
}
|
|
|
|
static void drawPath(JNIEnv* env, jobject, SkCanvas* canvas, SkPath* path,
|
|
SkPaint* paint) {
|
|
canvas->drawPath(*path, *paint);
|
|
}
|
|
|
|
static void drawPicture(JNIEnv* env, jobject, SkCanvas* canvas,
|
|
SkPicture* picture) {
|
|
SkASSERT(canvas);
|
|
SkASSERT(picture);
|
|
|
|
#ifdef TIME_DRAW
|
|
SkMSec now = get_thread_msec(); //SkTime::GetMSecs();
|
|
#endif
|
|
canvas->drawPicture(*picture);
|
|
#ifdef TIME_DRAW
|
|
LOGD("---- picture playback %d ms\n", get_thread_msec() - now);
|
|
#endif
|
|
}
|
|
|
|
static void drawBitmap__BitmapFFPaint(JNIEnv* env, jobject jcanvas,
|
|
SkCanvas* canvas, SkBitmap* bitmap,
|
|
jfloat left, jfloat top,
|
|
SkPaint* paint, jint canvasDensity,
|
|
jint screenDensity, jint bitmapDensity) {
|
|
SkScalar left_ = SkFloatToScalar(left);
|
|
SkScalar top_ = SkFloatToScalar(top);
|
|
|
|
if (canvasDensity == bitmapDensity || canvasDensity == 0
|
|
|| bitmapDensity == 0) {
|
|
if (screenDensity != 0 && screenDensity != bitmapDensity) {
|
|
SkPaint filteredPaint;
|
|
if (paint) {
|
|
filteredPaint = *paint;
|
|
}
|
|
filteredPaint.setFilterBitmap(true);
|
|
canvas->drawBitmap(*bitmap, left_, top_, &filteredPaint);
|
|
} else {
|
|
canvas->drawBitmap(*bitmap, left_, top_, paint);
|
|
}
|
|
} else {
|
|
canvas->save();
|
|
SkScalar scale = SkFloatToScalar(canvasDensity / (float)bitmapDensity);
|
|
canvas->translate(left_, top_);
|
|
canvas->scale(scale, scale);
|
|
|
|
SkPaint filteredPaint;
|
|
if (paint) {
|
|
filteredPaint = *paint;
|
|
}
|
|
filteredPaint.setFilterBitmap(true);
|
|
|
|
canvas->drawBitmap(*bitmap, 0, 0, &filteredPaint);
|
|
|
|
canvas->restore();
|
|
}
|
|
}
|
|
|
|
static void doDrawBitmap(JNIEnv* env, SkCanvas* canvas, SkBitmap* bitmap,
|
|
jobject srcIRect, const SkRect& dst, SkPaint* paint,
|
|
jint screenDensity, jint bitmapDensity) {
|
|
SkIRect src, *srcPtr = NULL;
|
|
|
|
if (NULL != srcIRect) {
|
|
GraphicsJNI::jrect_to_irect(env, srcIRect, &src);
|
|
srcPtr = &src;
|
|
}
|
|
|
|
if (screenDensity != 0 && screenDensity != bitmapDensity) {
|
|
SkPaint filteredPaint;
|
|
if (paint) {
|
|
filteredPaint = *paint;
|
|
}
|
|
filteredPaint.setFilterBitmap(true);
|
|
canvas->drawBitmapRect(*bitmap, srcPtr, dst, &filteredPaint);
|
|
} else {
|
|
canvas->drawBitmapRect(*bitmap, srcPtr, dst, paint);
|
|
}
|
|
}
|
|
|
|
static void drawBitmapRF(JNIEnv* env, jobject, SkCanvas* canvas,
|
|
SkBitmap* bitmap, jobject srcIRect,
|
|
jobject dstRectF, SkPaint* paint,
|
|
jint screenDensity, jint bitmapDensity) {
|
|
SkRect dst;
|
|
GraphicsJNI::jrectf_to_rect(env, dstRectF, &dst);
|
|
doDrawBitmap(env, canvas, bitmap, srcIRect, dst, paint,
|
|
screenDensity, bitmapDensity);
|
|
}
|
|
|
|
static void drawBitmapRR(JNIEnv* env, jobject, SkCanvas* canvas,
|
|
SkBitmap* bitmap, jobject srcIRect,
|
|
jobject dstRect, SkPaint* paint,
|
|
jint screenDensity, jint bitmapDensity) {
|
|
SkRect dst;
|
|
GraphicsJNI::jrect_to_rect(env, dstRect, &dst);
|
|
doDrawBitmap(env, canvas, bitmap, srcIRect, dst, paint,
|
|
screenDensity, bitmapDensity);
|
|
}
|
|
|
|
static void drawBitmapArray(JNIEnv* env, jobject, SkCanvas* canvas,
|
|
jintArray jcolors, int offset, int stride,
|
|
jfloat x, jfloat y, int width, int height,
|
|
jboolean hasAlpha, SkPaint* paint)
|
|
{
|
|
SkBitmap bitmap;
|
|
|
|
bitmap.setConfig(hasAlpha ? SkBitmap::kARGB_8888_Config :
|
|
SkBitmap::kRGB_565_Config, width, height);
|
|
if (!bitmap.allocPixels()) {
|
|
return;
|
|
}
|
|
|
|
if (!GraphicsJNI::SetPixels(env, jcolors, offset, stride,
|
|
0, 0, width, height, bitmap)) {
|
|
return;
|
|
}
|
|
|
|
canvas->drawBitmap(bitmap, SkFloatToScalar(x), SkFloatToScalar(y),
|
|
paint);
|
|
}
|
|
|
|
static void drawBitmapMatrix(JNIEnv* env, jobject, SkCanvas* canvas,
|
|
const SkBitmap* bitmap, const SkMatrix* matrix,
|
|
const SkPaint* paint) {
|
|
canvas->drawBitmapMatrix(*bitmap, *matrix, paint);
|
|
}
|
|
|
|
static void drawBitmapMesh(JNIEnv* env, jobject, SkCanvas* canvas,
|
|
const SkBitmap* bitmap, int meshWidth, int meshHeight,
|
|
jfloatArray jverts, int vertIndex, jintArray jcolors,
|
|
int colorIndex, const SkPaint* paint) {
|
|
|
|
const int ptCount = (meshWidth + 1) * (meshHeight + 1);
|
|
const int indexCount = meshWidth * meshHeight * 6;
|
|
|
|
AutoJavaFloatArray vertA(env, jverts, vertIndex + (ptCount << 1));
|
|
AutoJavaIntArray colorA(env, jcolors, colorIndex + ptCount);
|
|
|
|
/* Our temp storage holds 2 or 3 arrays.
|
|
texture points [ptCount * sizeof(SkPoint)]
|
|
optionally vertex points [ptCount * sizeof(SkPoint)] if we need a
|
|
copy to convert from float to fixed
|
|
indices [ptCount * sizeof(uint16_t)]
|
|
*/
|
|
ssize_t storageSize = ptCount * sizeof(SkPoint); // texs[]
|
|
#ifdef SK_SCALAR_IS_FIXED
|
|
storageSize += ptCount * sizeof(SkPoint); // storage for verts
|
|
#endif
|
|
storageSize += indexCount * sizeof(uint16_t); // indices[]
|
|
|
|
SkAutoMalloc storage(storageSize);
|
|
SkPoint* texs = (SkPoint*)storage.get();
|
|
SkPoint* verts;
|
|
uint16_t* indices;
|
|
#ifdef SK_SCALAR_IS_FLOAT
|
|
verts = (SkPoint*)(vertA.ptr() + vertIndex);
|
|
indices = (uint16_t*)(texs + ptCount);
|
|
#else
|
|
verts = texs + ptCount;
|
|
indices = (uint16_t*)(verts + ptCount);
|
|
// convert floats to fixed
|
|
{
|
|
const float* src = vertA.ptr() + vertIndex;
|
|
for (int i = 0; i < ptCount; i++) {
|
|
verts[i].set(SkFloatToFixed(src[0]), SkFloatToFixed(src[1]));
|
|
src += 2;
|
|
}
|
|
}
|
|
#endif
|
|
|
|
// cons up texture coordinates and indices
|
|
{
|
|
const SkScalar w = SkIntToScalar(bitmap->width());
|
|
const SkScalar h = SkIntToScalar(bitmap->height());
|
|
const SkScalar dx = w / meshWidth;
|
|
const SkScalar dy = h / meshHeight;
|
|
|
|
SkPoint* texsPtr = texs;
|
|
SkScalar y = 0;
|
|
for (int i = 0; i <= meshHeight; i++) {
|
|
if (i == meshHeight) {
|
|
y = h; // to ensure numerically we hit h exactly
|
|
}
|
|
SkScalar x = 0;
|
|
for (int j = 0; j < meshWidth; j++) {
|
|
texsPtr->set(x, y);
|
|
texsPtr += 1;
|
|
x += dx;
|
|
}
|
|
texsPtr->set(w, y);
|
|
texsPtr += 1;
|
|
y += dy;
|
|
}
|
|
SkASSERT(texsPtr - texs == ptCount);
|
|
}
|
|
|
|
// cons up indices
|
|
{
|
|
uint16_t* indexPtr = indices;
|
|
int index = 0;
|
|
for (int i = 0; i < meshHeight; i++) {
|
|
for (int j = 0; j < meshWidth; j++) {
|
|
// lower-left triangle
|
|
*indexPtr++ = index;
|
|
*indexPtr++ = index + meshWidth + 1;
|
|
*indexPtr++ = index + meshWidth + 2;
|
|
// upper-right triangle
|
|
*indexPtr++ = index;
|
|
*indexPtr++ = index + meshWidth + 2;
|
|
*indexPtr++ = index + 1;
|
|
// bump to the next cell
|
|
index += 1;
|
|
}
|
|
// bump to the next row
|
|
index += 1;
|
|
}
|
|
SkASSERT(indexPtr - indices == indexCount);
|
|
SkASSERT((char*)indexPtr - (char*)storage.get() == storageSize);
|
|
}
|
|
|
|
// double-check that we have legal indices
|
|
#ifdef SK_DEBUG
|
|
{
|
|
for (int i = 0; i < indexCount; i++) {
|
|
SkASSERT((unsigned)indices[i] < (unsigned)ptCount);
|
|
}
|
|
}
|
|
#endif
|
|
|
|
// cons-up a shader for the bitmap
|
|
SkPaint tmpPaint;
|
|
if (paint) {
|
|
tmpPaint = *paint;
|
|
}
|
|
SkShader* shader = SkShader::CreateBitmapShader(*bitmap,
|
|
SkShader::kClamp_TileMode, SkShader::kClamp_TileMode);
|
|
tmpPaint.setShader(shader)->safeUnref();
|
|
|
|
canvas->drawVertices(SkCanvas::kTriangles_VertexMode, ptCount, verts,
|
|
texs, (const SkColor*)colorA.ptr(), NULL, indices,
|
|
indexCount, tmpPaint);
|
|
}
|
|
|
|
static void drawVertices(JNIEnv* env, jobject, SkCanvas* canvas,
|
|
SkCanvas::VertexMode mode, int vertexCount,
|
|
jfloatArray jverts, int vertIndex,
|
|
jfloatArray jtexs, int texIndex,
|
|
jintArray jcolors, int colorIndex,
|
|
jshortArray jindices, int indexIndex,
|
|
int indexCount, const SkPaint* paint) {
|
|
|
|
AutoJavaFloatArray vertA(env, jverts, vertIndex + vertexCount);
|
|
AutoJavaFloatArray texA(env, jtexs, texIndex + vertexCount);
|
|
AutoJavaIntArray colorA(env, jcolors, colorIndex + vertexCount);
|
|
AutoJavaShortArray indexA(env, jindices, indexIndex + indexCount);
|
|
|
|
const int ptCount = vertexCount >> 1;
|
|
|
|
SkPoint* verts;
|
|
SkPoint* texs = NULL;
|
|
#ifdef SK_SCALAR_IS_FLOAT
|
|
verts = (SkPoint*)(vertA.ptr() + vertIndex);
|
|
if (jtexs != NULL) {
|
|
texs = (SkPoint*)(texA.ptr() + texIndex);
|
|
}
|
|
#else
|
|
int count = ptCount; // for verts
|
|
if (jtexs != NULL) {
|
|
count += ptCount; // += for texs
|
|
}
|
|
SkAutoMalloc storage(count * sizeof(SkPoint));
|
|
verts = (SkPoint*)storage.get();
|
|
const float* src = vertA.ptr() + vertIndex;
|
|
for (int i = 0; i < ptCount; i++) {
|
|
verts[i].set(SkFloatToFixed(src[0]), SkFloatToFixed(src[1]));
|
|
src += 2;
|
|
}
|
|
if (jtexs != NULL) {
|
|
texs = verts + ptCount;
|
|
src = texA.ptr() + texIndex;
|
|
for (int i = 0; i < ptCount; i++) {
|
|
texs[i].set(SkFloatToFixed(src[0]), SkFloatToFixed(src[1]));
|
|
src += 2;
|
|
}
|
|
}
|
|
#endif
|
|
|
|
const SkColor* colors = NULL;
|
|
const uint16_t* indices = NULL;
|
|
if (jcolors != NULL) {
|
|
colors = (const SkColor*)(colorA.ptr() + colorIndex);
|
|
}
|
|
if (jindices != NULL) {
|
|
indices = (const uint16_t*)(indexA.ptr() + indexIndex);
|
|
}
|
|
|
|
canvas->drawVertices(mode, ptCount, verts, texs, colors, NULL,
|
|
indices, indexCount, *paint);
|
|
}
|
|
|
|
static void drawText___CIIFFPaint(JNIEnv* env, jobject, SkCanvas* canvas,
|
|
jcharArray text, int index, int count,
|
|
jfloat x, jfloat y, SkPaint* paint) {
|
|
jchar* textArray = env->GetCharArrayElements(text, NULL);
|
|
jsize textCount = env->GetArrayLength(text);
|
|
SkScalar x_ = SkFloatToScalar(x);
|
|
SkScalar y_ = SkFloatToScalar(y);
|
|
canvas->drawText(textArray + index, count << 1, x_, y_, *paint);
|
|
env->ReleaseCharArrayElements(text, textArray, 0);
|
|
}
|
|
|
|
static void drawText__StringIIFFPaint(JNIEnv* env, jobject,
|
|
SkCanvas* canvas, jstring text, int start, int end,
|
|
jfloat x, jfloat y, SkPaint* paint) {
|
|
const void* text_ = env->GetStringChars(text, NULL);
|
|
SkScalar x_ = SkFloatToScalar(x);
|
|
SkScalar y_ = SkFloatToScalar(y);
|
|
canvas->drawText((const uint16_t*)text_ + start, (end - start) << 1,
|
|
x_, y_, *paint);
|
|
env->ReleaseStringChars(text, (const jchar*) text_);
|
|
}
|
|
|
|
static void drawString(JNIEnv* env, jobject canvas, jstring text,
|
|
jfloat x, jfloat y, jobject paint) {
|
|
NPE_CHECK_RETURN_VOID(env, canvas);
|
|
NPE_CHECK_RETURN_VOID(env, paint);
|
|
NPE_CHECK_RETURN_VOID(env, text);
|
|
size_t count = env->GetStringLength(text);
|
|
if (0 == count) {
|
|
return;
|
|
}
|
|
const jchar* text_ = env->GetStringChars(text, NULL);
|
|
SkCanvas* c = GraphicsJNI::getNativeCanvas(env, canvas);
|
|
c->drawText(text_, count << 1, SkFloatToScalar(x), SkFloatToScalar(y),
|
|
*GraphicsJNI::getNativePaint(env, paint));
|
|
env->ReleaseStringChars(text, text_);
|
|
}
|
|
|
|
static void drawPosText___CII_FPaint(JNIEnv* env, jobject, SkCanvas* canvas,
|
|
jcharArray text, int index, int count,
|
|
jfloatArray pos, SkPaint* paint) {
|
|
jchar* textArray = text ? env->GetCharArrayElements(text, NULL) : NULL;
|
|
jsize textCount = text ? env->GetArrayLength(text) : NULL;
|
|
float* posArray = pos ? env->GetFloatArrayElements(pos, NULL) : NULL;
|
|
int posCount = pos ? env->GetArrayLength(pos) >> 1: 0;
|
|
SkPoint* posPtr = posCount > 0 ? new SkPoint[posCount] : NULL;
|
|
int indx;
|
|
for (indx = 0; indx < posCount; indx++) {
|
|
posPtr[indx].fX = SkFloatToScalar(posArray[indx << 1]);
|
|
posPtr[indx].fY = SkFloatToScalar(posArray[(indx << 1) + 1]);
|
|
}
|
|
canvas->drawPosText(textArray + index, count << 1, posPtr, *paint);
|
|
if (text) {
|
|
env->ReleaseCharArrayElements(text, textArray, 0);
|
|
}
|
|
if (pos) {
|
|
env->ReleaseFloatArrayElements(pos, posArray, 0);
|
|
}
|
|
delete[] posPtr;
|
|
}
|
|
|
|
static void drawPosText__String_FPaint(JNIEnv* env, jobject,
|
|
SkCanvas* canvas, jstring text,
|
|
jfloatArray pos, SkPaint* paint) {
|
|
const void* text_ = text ? env->GetStringChars(text, NULL) : NULL;
|
|
int byteLength = text ? env->GetStringLength(text) : 0;
|
|
float* posArray = pos ? env->GetFloatArrayElements(pos, NULL) : NULL;
|
|
int posCount = pos ? env->GetArrayLength(pos) >> 1: 0;
|
|
SkPoint* posPtr = posCount > 0 ? new SkPoint[posCount] : NULL;
|
|
|
|
for (int indx = 0; indx < posCount; indx++) {
|
|
posPtr[indx].fX = SkFloatToScalar(posArray[indx << 1]);
|
|
posPtr[indx].fY = SkFloatToScalar(posArray[(indx << 1) + 1]);
|
|
}
|
|
canvas->drawPosText(text_, byteLength << 1, posPtr, *paint);
|
|
if (text) {
|
|
env->ReleaseStringChars(text, (const jchar*) text_);
|
|
}
|
|
if (pos) {
|
|
env->ReleaseFloatArrayElements(pos, posArray, 0);
|
|
}
|
|
delete[] posPtr;
|
|
}
|
|
|
|
static void drawTextOnPath___CIIPathFFPaint(JNIEnv* env, jobject,
|
|
SkCanvas* canvas, jcharArray text, int index, int count,
|
|
SkPath* path, jfloat hOffset, jfloat vOffset, SkPaint* paint) {
|
|
|
|
jchar* textArray = env->GetCharArrayElements(text, NULL);
|
|
canvas->drawTextOnPathHV(textArray + index, count << 1, *path,
|
|
SkFloatToScalar(hOffset), SkFloatToScalar(vOffset), *paint);
|
|
env->ReleaseCharArrayElements(text, textArray, 0);
|
|
}
|
|
|
|
static void drawTextOnPath__StringPathFFPaint(JNIEnv* env, jobject,
|
|
SkCanvas* canvas, jstring text, SkPath* path,
|
|
jfloat hOffset, jfloat vOffset, SkPaint* paint) {
|
|
const jchar* text_ = env->GetStringChars(text, NULL);
|
|
int byteLength = env->GetStringLength(text) << 1;
|
|
canvas->drawTextOnPathHV(text_, byteLength, *path,
|
|
SkFloatToScalar(hOffset), SkFloatToScalar(vOffset), *paint);
|
|
env->ReleaseStringChars(text, text_);
|
|
}
|
|
|
|
static bool getClipBounds(JNIEnv* env, jobject, SkCanvas* canvas,
|
|
jobject bounds) {
|
|
SkRect r;
|
|
SkIRect ir;
|
|
bool result = canvas->getClipBounds(&r, SkCanvas::kBW_EdgeType);
|
|
|
|
r.round(&ir);
|
|
(void)GraphicsJNI::irect_to_jrect(ir, env, bounds);
|
|
return result;
|
|
}
|
|
|
|
static void getCTM(JNIEnv* env, jobject, SkCanvas* canvas,
|
|
SkMatrix* matrix) {
|
|
*matrix = canvas->getTotalMatrix();
|
|
}
|
|
};
|
|
|
|
static JNINativeMethod gCanvasMethods[] = {
|
|
{"finalizer", "(I)V", (void*) SkCanvasGlue::finalizer},
|
|
{"initRaster","(I)I", (void*) SkCanvasGlue::initRaster},
|
|
{"initGL","()I", (void*) SkCanvasGlue::initGL},
|
|
{"isOpaque","()Z", (void*) SkCanvasGlue::isOpaque},
|
|
{"getWidth","()I", (void*) SkCanvasGlue::getWidth},
|
|
{"getHeight","()I", (void*) SkCanvasGlue::getHeight},
|
|
{"native_setBitmap","(II)V", (void*) SkCanvasGlue::setBitmap},
|
|
{"nativeSetViewport", "(III)V", (void*) SkCanvasGlue::setViewport},
|
|
{"save","()I", (void*) SkCanvasGlue::saveAll},
|
|
{"save","(I)I", (void*) SkCanvasGlue::save},
|
|
{"native_saveLayer","(ILandroid/graphics/RectF;II)I",
|
|
(void*) SkCanvasGlue::saveLayer},
|
|
{"native_saveLayer","(IFFFFII)I", (void*) SkCanvasGlue::saveLayer4F},
|
|
{"native_saveLayerAlpha","(ILandroid/graphics/RectF;II)I",
|
|
(void*) SkCanvasGlue::saveLayerAlpha},
|
|
{"native_saveLayerAlpha","(IFFFFII)I",
|
|
(void*) SkCanvasGlue::saveLayerAlpha4F},
|
|
{"restore","()V", (void*) SkCanvasGlue::restore},
|
|
{"getSaveCount","()I", (void*) SkCanvasGlue::getSaveCount},
|
|
{"restoreToCount","(I)V", (void*) SkCanvasGlue::restoreToCount},
|
|
{"translate","(FF)V", (void*) SkCanvasGlue::translate},
|
|
{"scale","(FF)V", (void*) SkCanvasGlue::scale__FF},
|
|
{"rotate","(F)V", (void*) SkCanvasGlue::rotate__F},
|
|
{"skew","(FF)V", (void*) SkCanvasGlue::skew__FF},
|
|
{"native_concat","(II)V", (void*) SkCanvasGlue::concat},
|
|
{"native_setMatrix","(II)V", (void*) SkCanvasGlue::setMatrix},
|
|
{"clipRect","(FFFF)Z", (void*) SkCanvasGlue::clipRect_FFFF},
|
|
{"clipRect","(IIII)Z", (void*) SkCanvasGlue::clipRect_IIII},
|
|
{"clipRect","(Landroid/graphics/RectF;)Z",
|
|
(void*) SkCanvasGlue::clipRect_RectF},
|
|
{"clipRect","(Landroid/graphics/Rect;)Z",
|
|
(void*) SkCanvasGlue::clipRect_Rect},
|
|
{"native_clipRect","(IFFFFI)Z", (void*) SkCanvasGlue::clipRect},
|
|
{"native_clipPath","(III)Z", (void*) SkCanvasGlue::clipPath},
|
|
{"native_clipRegion","(III)Z", (void*) SkCanvasGlue::clipRegion},
|
|
{"nativeSetDrawFilter", "(II)V", (void*) SkCanvasGlue::setDrawFilter},
|
|
{"native_getClipBounds","(ILandroid/graphics/Rect;)Z",
|
|
(void*) SkCanvasGlue::getClipBounds},
|
|
{"native_getCTM", "(II)V", (void*)SkCanvasGlue::getCTM},
|
|
{"native_quickReject","(ILandroid/graphics/RectF;I)Z",
|
|
(void*) SkCanvasGlue::quickReject__RectFI},
|
|
{"native_quickReject","(III)Z", (void*) SkCanvasGlue::quickReject__PathI},
|
|
{"native_quickReject","(IFFFFI)Z", (void*)SkCanvasGlue::quickReject__FFFFI},
|
|
{"native_drawRGB","(IIII)V", (void*) SkCanvasGlue::drawRGB},
|
|
{"native_drawARGB","(IIIII)V", (void*) SkCanvasGlue::drawARGB},
|
|
{"native_drawColor","(II)V", (void*) SkCanvasGlue::drawColor__I},
|
|
{"native_drawColor","(III)V", (void*) SkCanvasGlue::drawColor__II},
|
|
{"native_drawPaint","(II)V", (void*) SkCanvasGlue::drawPaint},
|
|
{"drawPoint", "(FFLandroid/graphics/Paint;)V",
|
|
(void*) SkCanvasGlue::drawPoint},
|
|
{"drawPoints", "([FIILandroid/graphics/Paint;)V",
|
|
(void*) SkCanvasGlue::drawPoints},
|
|
{"drawLines", "([FIILandroid/graphics/Paint;)V",
|
|
(void*) SkCanvasGlue::drawLines},
|
|
{"native_drawLine","(IFFFFI)V", (void*) SkCanvasGlue::drawLine__FFFFPaint},
|
|
{"native_drawRect","(ILandroid/graphics/RectF;I)V",
|
|
(void*) SkCanvasGlue::drawRect__RectFPaint},
|
|
{"native_drawRect","(IFFFFI)V", (void*) SkCanvasGlue::drawRect__FFFFPaint},
|
|
{"native_drawOval","(ILandroid/graphics/RectF;I)V",
|
|
(void*) SkCanvasGlue::drawOval},
|
|
{"native_drawCircle","(IFFFI)V", (void*) SkCanvasGlue::drawCircle},
|
|
{"native_drawArc","(ILandroid/graphics/RectF;FFZI)V",
|
|
(void*) SkCanvasGlue::drawArc},
|
|
{"native_drawRoundRect","(ILandroid/graphics/RectF;FFI)V",
|
|
(void*) SkCanvasGlue::drawRoundRect},
|
|
{"native_drawPath","(III)V", (void*) SkCanvasGlue::drawPath},
|
|
{"native_drawBitmap","(IIFFIIII)V",
|
|
(void*) SkCanvasGlue::drawBitmap__BitmapFFPaint},
|
|
{"native_drawBitmap","(IILandroid/graphics/Rect;Landroid/graphics/RectF;III)V",
|
|
(void*) SkCanvasGlue::drawBitmapRF},
|
|
{"native_drawBitmap","(IILandroid/graphics/Rect;Landroid/graphics/Rect;III)V",
|
|
(void*) SkCanvasGlue::drawBitmapRR},
|
|
{"native_drawBitmap", "(I[IIIFFIIZI)V",
|
|
(void*)SkCanvasGlue::drawBitmapArray},
|
|
|
|
{"nativeDrawBitmapMatrix", "(IIII)V",
|
|
(void*)SkCanvasGlue::drawBitmapMatrix},
|
|
{"nativeDrawBitmapMesh", "(IIII[FI[III)V",
|
|
(void*)SkCanvasGlue::drawBitmapMesh},
|
|
{"nativeDrawVertices", "(III[FI[FI[II[SIII)V",
|
|
(void*)SkCanvasGlue::drawVertices},
|
|
{"native_drawText","(I[CIIFFI)V",
|
|
(void*) SkCanvasGlue::drawText___CIIFFPaint},
|
|
{"native_drawText","(ILjava/lang/String;IIFFI)V",
|
|
(void*) SkCanvasGlue::drawText__StringIIFFPaint},
|
|
{"drawText","(Ljava/lang/String;FFLandroid/graphics/Paint;)V",
|
|
(void*) SkCanvasGlue::drawString},
|
|
{"native_drawPosText","(I[CII[FI)V",
|
|
(void*) SkCanvasGlue::drawPosText___CII_FPaint},
|
|
{"native_drawPosText","(ILjava/lang/String;[FI)V",
|
|
(void*) SkCanvasGlue::drawPosText__String_FPaint},
|
|
{"native_drawTextOnPath","(I[CIIIFFI)V",
|
|
(void*) SkCanvasGlue::drawTextOnPath___CIIPathFFPaint},
|
|
{"native_drawTextOnPath","(ILjava/lang/String;IFFI)V",
|
|
(void*) SkCanvasGlue::drawTextOnPath__StringPathFFPaint},
|
|
{"native_drawPicture", "(II)V", (void*) SkCanvasGlue::drawPicture},
|
|
|
|
{"freeCaches", "()V", (void*) SkCanvasGlue::freeCaches}
|
|
};
|
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
|
|
static void BoundaryPatch_computeCubic(JNIEnv* env, jobject, jfloatArray jpts,
|
|
int texW, int texH, int rows, int cols,
|
|
jfloatArray jverts, jshortArray jidx) {
|
|
AutoJavaFloatArray ptsArray(env, jpts, 24, kRO_JNIAccess);
|
|
|
|
int vertCount = rows * cols;
|
|
AutoJavaFloatArray vertsArray(env, jverts, vertCount * 4, kRW_JNIAccess);
|
|
SkPoint* verts = (SkPoint*)vertsArray.ptr();
|
|
SkPoint* texs = verts + vertCount;
|
|
|
|
int idxCount = (rows - 1) * (cols - 1) * 6;
|
|
AutoJavaShortArray idxArray(env, jidx, idxCount, kRW_JNIAccess);
|
|
uint16_t* idx = (uint16_t*)idxArray.ptr(); // cast from int16_t*
|
|
|
|
SkCubicBoundary cubic;
|
|
memcpy(cubic.fPts, ptsArray.ptr(), 12 * sizeof(SkPoint));
|
|
|
|
SkBoundaryPatch patch;
|
|
patch.setBoundary(&cubic);
|
|
// generate our verts
|
|
patch.evalPatch(verts, rows, cols);
|
|
|
|
SkMeshIndices mesh;
|
|
// generate our texs and idx
|
|
mesh.init(texs, idx, texW, texH, rows, cols);
|
|
}
|
|
|
|
static JNINativeMethod gBoundaryPatchMethods[] = {
|
|
{"nativeComputeCubicPatch", "([FIIII[F[S)V",
|
|
(void*)BoundaryPatch_computeCubic },
|
|
};
|
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
|
|
#include <android_runtime/AndroidRuntime.h>
|
|
|
|
#define REG(env, name, array) \
|
|
result = android::AndroidRuntime::registerNativeMethods(env, name, array, \
|
|
SK_ARRAY_COUNT(array)); \
|
|
if (result < 0) return result
|
|
|
|
int register_android_graphics_Canvas(JNIEnv* env) {
|
|
int result;
|
|
|
|
REG(env, "android/graphics/Canvas", gCanvasMethods);
|
|
REG(env, "android/graphics/utils/BoundaryPatch", gBoundaryPatchMethods);
|
|
|
|
return result;
|
|
}
|
|
|
|
}
|