blob: a77ed626d0e884c83502bcff435a9444504295df [file] [log] [blame]
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001#include "GraphicsJNI.h"
Ben Wagner60126ef2015-08-07 12:13:48 -04002#include "SkGradientShader.h"
Matt Sarett62feb3a2016-09-20 10:34:11 -04003#include "SkImagePriv.h"
Ben Wagner60126ef2015-08-07 12:13:48 -04004#include "SkShader.h"
Mike Reedc2f31df2016-10-28 17:21:45 -04005#include "SkBlendMode.h"
Ben Wagner60126ef2015-08-07 12:13:48 -04006#include "core_jni_helpers.h"
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007
Romain Guya2341a92010-09-08 18:04:33 -07008#include <Caches.h>
Ben Wagner60126ef2015-08-07 12:13:48 -04009#include <jni.h>
Andreas Gampeed6b9df2014-11-20 22:02:20 -080010
Romain Guy06f96e22010-07-30 19:18:16 -070011using namespace android::uirenderer;
12
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013static void ThrowIAE_IfNull(JNIEnv* env, void* ptr) {
14 if (NULL == ptr) {
15 doThrowIAE(env);
16 }
17}
18
Ashok Bhat36bef0b2014-01-20 20:08:01 +000019static void Color_RGBToHSV(JNIEnv* env, jobject, jint red, jint green, jint blue, jfloatArray hsvArray)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080020{
21 SkScalar hsv[3];
22 SkRGBToHSV(red, green, blue, hsv);
23
24 AutoJavaFloatArray autoHSV(env, hsvArray, 3);
25 float* values = autoHSV.ptr();
26 for (int i = 0; i < 3; i++) {
27 values[i] = SkScalarToFloat(hsv[i]);
28 }
29}
Elliott Hughes4cb17532011-04-12 16:10:26 -070030
Ashok Bhat36bef0b2014-01-20 20:08:01 +000031static jint Color_HSVToColor(JNIEnv* env, jobject, jint alpha, jfloatArray hsvArray)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080032{
33 AutoJavaFloatArray autoHSV(env, hsvArray, 3);
Leon Scroggins III2e0103e2014-04-04 17:05:24 -040034#ifdef SK_SCALAR_IS_FLOAT
35 SkScalar* hsv = autoHSV.ptr();
36#else
37 #error Need to convert float array to SkScalar array before calling the following function.
38#endif
Elliott Hughes4cb17532011-04-12 16:10:26 -070039
Ashok Bhat36bef0b2014-01-20 20:08:01 +000040 return static_cast<jint>(SkHSVToColor(alpha, hsv));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080041}
42
43///////////////////////////////////////////////////////////////////////////////////////////////
44
Chris Craikb581e672017-03-07 15:27:36 -080045static void Shader_safeUnref(JNIEnv* env, jobject o, jlong shaderHandle) {
Ashok Bhat36bef0b2014-01-20 20:08:01 +000046 SkShader* shader = reinterpret_cast<SkShader*>(shaderHandle);
Derek Sollenberger6062c592011-02-22 13:55:04 -050047 SkSafeUnref(shader);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080048}
49
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080050///////////////////////////////////////////////////////////////////////////////////////////////
51
Chris Craikb581e672017-03-07 15:27:36 -080052static jlong BitmapShader_constructor(JNIEnv* env, jobject o, jlong matrixPtr, jobject jbitmap,
53 jint tileModeX, jint tileModeY) {
54 const SkMatrix* matrix = reinterpret_cast<const SkMatrix*>(matrixPtr);
John Reck3731dc22015-04-13 15:20:29 -070055 SkBitmap bitmap;
Chris Craikb786bbd2015-06-10 16:58:42 -070056 if (jbitmap) {
57 // Only pass a valid SkBitmap object to the constructor if the Bitmap exists. Otherwise,
58 // we'll pass an empty SkBitmap to avoid crashing/excepting for compatibility.
sergeyv554ffeb2016-11-15 18:01:21 -080059 android::bitmap::toBitmap(env, jbitmap).getSkBitmapForShaders(&bitmap);
Chris Craikb786bbd2015-06-10 16:58:42 -070060 }
Romain Guy06f96e22010-07-30 19:18:16 -070061
Derek Sollenberger450756a2016-11-07 15:55:47 -050062 sk_sp<SkImage> image = SkMakeImageFromRasterBitmap(bitmap, kNever_SkCopyPixelsMode);
Chris Craikb581e672017-03-07 15:27:36 -080063 sk_sp<SkShader> shader = image->makeShader(
64 (SkShader::TileMode)tileModeX, (SkShader::TileMode)tileModeY, matrix);
Derek Sollenberger450756a2016-11-07 15:55:47 -050065
66 ThrowIAE_IfNull(env, shader.get());
67 return reinterpret_cast<jlong>(shader.release());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080068}
Romain Guy06f96e22010-07-30 19:18:16 -070069
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080070///////////////////////////////////////////////////////////////////////////////////////////////
71
Chris Craikb581e672017-03-07 15:27:36 -080072static jlong LinearGradient_create1(JNIEnv* env, jobject o, jlong matrixPtr,
73 jfloat x0, jfloat y0, jfloat x1, jfloat y1,
74 jintArray colorArray, jfloatArray posArray, jint tileMode) {
75 const SkMatrix* matrix = reinterpret_cast<const SkMatrix*>(matrixPtr);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080076 SkPoint pts[2];
Leon Scroggins III2e0103e2014-04-04 17:05:24 -040077 pts[0].set(x0, y0);
78 pts[1].set(x1, y1);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080079
Romain Guy06f96e22010-07-30 19:18:16 -070080 size_t count = env->GetArrayLength(colorArray);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080081 const jint* colorValues = env->GetIntArrayElements(colorArray, NULL);
82
Leon Scroggins III2e0103e2014-04-04 17:05:24 -040083 AutoJavaFloatArray autoPos(env, posArray, count);
84#ifdef SK_SCALAR_IS_FLOAT
85 SkScalar* pos = autoPos.ptr();
86#else
87 #error Need to convert float array to SkScalar array before calling the following function.
88#endif
Elliott Hughes4cb17532011-04-12 16:10:26 -070089
Mike Reed260ab722016-10-07 15:59:20 -040090 SkShader* shader = SkGradientShader::MakeLinear(pts,
Leon Scroggins III2e0103e2014-04-04 17:05:24 -040091 reinterpret_cast<const SkColor*>(colorValues), pos, count,
Chris Craikb581e672017-03-07 15:27:36 -080092 static_cast<SkShader::TileMode>(tileMode), /* flags */ 0, matrix).release();
Romain Guy06f96e22010-07-30 19:18:16 -070093
94 env->ReleaseIntArrayElements(colorArray, const_cast<jint*>(colorValues), JNI_ABORT);
95 ThrowIAE_IfNull(env, shader);
Ashok Bhat36bef0b2014-01-20 20:08:01 +000096 return reinterpret_cast<jlong>(shader);
Romain Guy06f96e22010-07-30 19:18:16 -070097}
98
Chris Craikb581e672017-03-07 15:27:36 -080099static jlong LinearGradient_create2(JNIEnv* env, jobject o, jlong matrixPtr,
100 jfloat x0, jfloat y0, jfloat x1, jfloat y1, jint color0, jint color1, jint tileMode) {
101 const SkMatrix* matrix = reinterpret_cast<const SkMatrix*>(matrixPtr);
102
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800103 SkPoint pts[2];
Leon Scroggins III2e0103e2014-04-04 17:05:24 -0400104 pts[0].set(x0, y0);
105 pts[1].set(x1, y1);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800106
107 SkColor colors[2];
108 colors[0] = color0;
109 colors[1] = color1;
Elliott Hughes4cb17532011-04-12 16:10:26 -0700110
Chris Craikb581e672017-03-07 15:27:36 -0800111 SkShader* s = SkGradientShader::MakeLinear(pts, colors, NULL, 2,
112 (SkShader::TileMode)tileMode, /* flags */ 0, matrix).release();
Romain Guy06f96e22010-07-30 19:18:16 -0700113
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800114 ThrowIAE_IfNull(env, s);
Ashok Bhat36bef0b2014-01-20 20:08:01 +0000115 return reinterpret_cast<jlong>(s);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800116}
117
118///////////////////////////////////////////////////////////////////////////////////////////////
119
Chris Craikb581e672017-03-07 15:27:36 -0800120static jlong RadialGradient_create1(JNIEnv* env, jobject, jlong matrixPtr, jfloat x, jfloat y,
121 jfloat radius, jintArray colorArray, jfloatArray posArray, jint tileMode) {
122 const SkMatrix* matrix = reinterpret_cast<const SkMatrix*>(matrixPtr);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800123 SkPoint center;
Leon Scroggins III2e0103e2014-04-04 17:05:24 -0400124 center.set(x, y);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800125
126 size_t count = env->GetArrayLength(colorArray);
127 const jint* colorValues = env->GetIntArrayElements(colorArray, NULL);
128
Leon Scroggins III2e0103e2014-04-04 17:05:24 -0400129 AutoJavaFloatArray autoPos(env, posArray, count);
130#ifdef SK_SCALAR_IS_FLOAT
131 SkScalar* pos = autoPos.ptr();
132#else
133 #error Need to convert float array to SkScalar array before calling the following function.
134#endif
Elliott Hughes4cb17532011-04-12 16:10:26 -0700135
Mike Reed260ab722016-10-07 15:59:20 -0400136 SkShader* shader = SkGradientShader::MakeRadial(center, radius,
Leon Scroggins III2e0103e2014-04-04 17:05:24 -0400137 reinterpret_cast<const SkColor*>(colorValues), pos, count,
Chris Craikb581e672017-03-07 15:27:36 -0800138 static_cast<SkShader::TileMode>(tileMode), /* flags */ 0, matrix).release();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800139 env->ReleaseIntArrayElements(colorArray, const_cast<jint*>(colorValues),
140 JNI_ABORT);
141
142 ThrowIAE_IfNull(env, shader);
Ashok Bhat36bef0b2014-01-20 20:08:01 +0000143 return reinterpret_cast<jlong>(shader);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800144}
145
Chris Craikb581e672017-03-07 15:27:36 -0800146static jlong RadialGradient_create2(JNIEnv* env, jobject, jlong matrixPtr, jfloat x, jfloat y, jfloat radius,
Ashok Bhat36bef0b2014-01-20 20:08:01 +0000147 jint color0, jint color1, jint tileMode) {
Chris Craikb581e672017-03-07 15:27:36 -0800148 const SkMatrix* matrix = reinterpret_cast<const SkMatrix*>(matrixPtr);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800149 SkPoint center;
Leon Scroggins III2e0103e2014-04-04 17:05:24 -0400150 center.set(x, y);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800151
152 SkColor colors[2];
153 colors[0] = color0;
154 colors[1] = color1;
155
Mike Reed260ab722016-10-07 15:59:20 -0400156 SkShader* s = SkGradientShader::MakeRadial(center, radius, colors, NULL, 2,
Chris Craikb581e672017-03-07 15:27:36 -0800157 (SkShader::TileMode)tileMode, /* flags */ 0, matrix).release();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800158 ThrowIAE_IfNull(env, s);
Ashok Bhat36bef0b2014-01-20 20:08:01 +0000159 return reinterpret_cast<jlong>(s);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800160}
161
162///////////////////////////////////////////////////////////////////////////////
163
Chris Craikb581e672017-03-07 15:27:36 -0800164static jlong SweepGradient_create1(JNIEnv* env, jobject, jlong matrixPtr, jfloat x, jfloat y,
Romain Guyddb80be2010-09-20 19:04:33 -0700165 jintArray jcolors, jfloatArray jpositions) {
Chris Craikb581e672017-03-07 15:27:36 -0800166 const SkMatrix* matrix = reinterpret_cast<const SkMatrix*>(matrixPtr);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800167 size_t count = env->GetArrayLength(jcolors);
168 const jint* colors = env->GetIntArrayElements(jcolors, NULL);
Elliott Hughes4cb17532011-04-12 16:10:26 -0700169
Leon Scroggins III2e0103e2014-04-04 17:05:24 -0400170 AutoJavaFloatArray autoPos(env, jpositions, count);
171#ifdef SK_SCALAR_IS_FLOAT
172 SkScalar* pos = autoPos.ptr();
173#else
174 #error Need to convert float array to SkScalar array before calling the following function.
175#endif
Elliott Hughes4cb17532011-04-12 16:10:26 -0700176
Mike Reed260ab722016-10-07 15:59:20 -0400177 SkShader* shader = SkGradientShader::MakeSweep(x, y,
Chris Craikb581e672017-03-07 15:27:36 -0800178 reinterpret_cast<const SkColor*>(colors), pos, count, /* flags */ 0, matrix).release();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800179 env->ReleaseIntArrayElements(jcolors, const_cast<jint*>(colors),
180 JNI_ABORT);
181 ThrowIAE_IfNull(env, shader);
Ashok Bhat36bef0b2014-01-20 20:08:01 +0000182 return reinterpret_cast<jlong>(shader);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800183}
184
Chris Craikb581e672017-03-07 15:27:36 -0800185static jlong SweepGradient_create2(JNIEnv* env, jobject, jlong matrixPtr, jfloat x, jfloat y,
Romain Guyddb80be2010-09-20 19:04:33 -0700186 int color0, int color1) {
Chris Craikb581e672017-03-07 15:27:36 -0800187 const SkMatrix* matrix = reinterpret_cast<const SkMatrix*>(matrixPtr);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800188 SkColor colors[2];
189 colors[0] = color0;
190 colors[1] = color1;
Chris Craikb581e672017-03-07 15:27:36 -0800191 SkShader* s = SkGradientShader::MakeSweep(x, y, colors, NULL, 2,
192 /* flags */ 0, matrix).release();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800193 ThrowIAE_IfNull(env, s);
Ashok Bhat36bef0b2014-01-20 20:08:01 +0000194 return reinterpret_cast<jlong>(s);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800195}
196
197///////////////////////////////////////////////////////////////////////////////////////////////
198
Chris Craikb581e672017-03-07 15:27:36 -0800199static jlong ComposeShader_create(JNIEnv* env, jobject o, jlong matrixPtr,
200 jlong shaderAHandle, jlong shaderBHandle, jint xfermodeHandle) {
201 const SkMatrix* matrix = reinterpret_cast<const SkMatrix*>(matrixPtr);
Ashok Bhat36bef0b2014-01-20 20:08:01 +0000202 SkShader* shaderA = reinterpret_cast<SkShader *>(shaderAHandle);
203 SkShader* shaderB = reinterpret_cast<SkShader *>(shaderBHandle);
Mike Reed260ab722016-10-07 15:59:20 -0400204 SkBlendMode mode = static_cast<SkBlendMode>(xfermodeHandle);
Chris Craikb581e672017-03-07 15:27:36 -0800205 sk_sp<SkShader> baseShader(SkShader::MakeComposeShader(
206 sk_ref_sp(shaderA), sk_ref_sp(shaderB), mode));
207
208 SkShader* shader;
209
210 if (matrix) {
211 shader = baseShader->makeWithLocalMatrix(*matrix).release();
212 } else {
213 shader = baseShader.release();
214 }
Ashok Bhat36bef0b2014-01-20 20:08:01 +0000215 return reinterpret_cast<jlong>(shader);
Romain Guy06f96e22010-07-30 19:18:16 -0700216}
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800217
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800218///////////////////////////////////////////////////////////////////////////////////////////////
219
Daniel Micay76f6a862015-09-19 17:31:01 -0400220static const JNINativeMethod gColorMethods[] = {
Chris Craikb581e672017-03-07 15:27:36 -0800221 { "nativeRGBToHSV", "(III[F)V", (void*)Color_RGBToHSV },
222 { "nativeHSVToColor", "(I[F)I", (void*)Color_HSVToColor }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800223};
224
Daniel Micay76f6a862015-09-19 17:31:01 -0400225static const JNINativeMethod gShaderMethods[] = {
Chris Craikb581e672017-03-07 15:27:36 -0800226 { "nativeSafeUnref", "(J)V", (void*)Shader_safeUnref },
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800227};
228
Daniel Micay76f6a862015-09-19 17:31:01 -0400229static const JNINativeMethod gBitmapShaderMethods[] = {
Chris Craikb581e672017-03-07 15:27:36 -0800230 { "nativeCreate", "(JLandroid/graphics/Bitmap;II)J", (void*)BitmapShader_constructor },
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800231};
232
Daniel Micay76f6a862015-09-19 17:31:01 -0400233static const JNINativeMethod gLinearGradientMethods[] = {
Chris Craikb581e672017-03-07 15:27:36 -0800234 { "nativeCreate1", "(JFFFF[I[FI)J", (void*)LinearGradient_create1 },
235 { "nativeCreate2", "(JFFFFIII)J", (void*)LinearGradient_create2 },
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800236};
237
Daniel Micay76f6a862015-09-19 17:31:01 -0400238static const JNINativeMethod gRadialGradientMethods[] = {
Chris Craikb581e672017-03-07 15:27:36 -0800239 { "nativeCreate1", "(JFFF[I[FI)J", (void*)RadialGradient_create1 },
240 { "nativeCreate2", "(JFFFIII)J", (void*)RadialGradient_create2 },
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800241};
242
Daniel Micay76f6a862015-09-19 17:31:01 -0400243static const JNINativeMethod gSweepGradientMethods[] = {
Chris Craikb581e672017-03-07 15:27:36 -0800244 { "nativeCreate1", "(JFF[I[F)J", (void*)SweepGradient_create1 },
245 { "nativeCreate2", "(JFFII)J", (void*)SweepGradient_create2 },
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800246};
247
Daniel Micay76f6a862015-09-19 17:31:01 -0400248static const JNINativeMethod gComposeShaderMethods[] = {
Chris Craikb581e672017-03-07 15:27:36 -0800249 { "nativeCreate", "(JJJI)J", (void*)ComposeShader_create },
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800250};
251
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800252int register_android_graphics_Shader(JNIEnv* env)
253{
Andreas Gampeed6b9df2014-11-20 22:02:20 -0800254 android::RegisterMethodsOrDie(env, "android/graphics/Color", gColorMethods,
255 NELEM(gColorMethods));
256 android::RegisterMethodsOrDie(env, "android/graphics/Shader", gShaderMethods,
257 NELEM(gShaderMethods));
258 android::RegisterMethodsOrDie(env, "android/graphics/BitmapShader", gBitmapShaderMethods,
259 NELEM(gBitmapShaderMethods));
260 android::RegisterMethodsOrDie(env, "android/graphics/LinearGradient", gLinearGradientMethods,
261 NELEM(gLinearGradientMethods));
262 android::RegisterMethodsOrDie(env, "android/graphics/RadialGradient", gRadialGradientMethods,
263 NELEM(gRadialGradientMethods));
264 android::RegisterMethodsOrDie(env, "android/graphics/SweepGradient", gSweepGradientMethods,
265 NELEM(gSweepGradientMethods));
266 android::RegisterMethodsOrDie(env, "android/graphics/ComposeShader", gComposeShaderMethods,
267 NELEM(gComposeShaderMethods));
Elliott Hughes4cb17532011-04-12 16:10:26 -0700268
Andreas Gampeed6b9df2014-11-20 22:02:20 -0800269 return 0;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800270}