blob: f04abecade20f9e682c2411d5b0c5688ef5f763d [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
Derek Sollenberger669b15a2017-03-31 12:09:24 -040013/**
14 * By default Skia gradients will interpolate their colors in unpremul space
15 * and then premultiply each of the results. We must set this flag to preserve
16 * backwards compatiblity by premultiplying the colors of the gradient first,
17 * and then interpolating between them.
18 */
19static const uint32_t sGradientShaderFlags = SkGradientShader::kInterpolateColorsInPremul_Flag;
20
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080021static void ThrowIAE_IfNull(JNIEnv* env, void* ptr) {
22 if (NULL == ptr) {
23 doThrowIAE(env);
24 }
25}
26
Ashok Bhat36bef0b2014-01-20 20:08:01 +000027static void Color_RGBToHSV(JNIEnv* env, jobject, jint red, jint green, jint blue, jfloatArray hsvArray)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080028{
29 SkScalar hsv[3];
30 SkRGBToHSV(red, green, blue, hsv);
31
32 AutoJavaFloatArray autoHSV(env, hsvArray, 3);
33 float* values = autoHSV.ptr();
34 for (int i = 0; i < 3; i++) {
35 values[i] = SkScalarToFloat(hsv[i]);
36 }
37}
Elliott Hughes4cb17532011-04-12 16:10:26 -070038
Ashok Bhat36bef0b2014-01-20 20:08:01 +000039static jint Color_HSVToColor(JNIEnv* env, jobject, jint alpha, jfloatArray hsvArray)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080040{
41 AutoJavaFloatArray autoHSV(env, hsvArray, 3);
Leon Scroggins III2e0103e2014-04-04 17:05:24 -040042#ifdef SK_SCALAR_IS_FLOAT
43 SkScalar* hsv = autoHSV.ptr();
44#else
45 #error Need to convert float array to SkScalar array before calling the following function.
46#endif
Elliott Hughes4cb17532011-04-12 16:10:26 -070047
Ashok Bhat36bef0b2014-01-20 20:08:01 +000048 return static_cast<jint>(SkHSVToColor(alpha, hsv));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080049}
50
51///////////////////////////////////////////////////////////////////////////////////////////////
52
John Reck8bde0be2017-05-19 10:55:20 -070053static void Shader_safeUnref(SkShader* shader) {
Derek Sollenberger6062c592011-02-22 13:55:04 -050054 SkSafeUnref(shader);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080055}
56
John Reck8bde0be2017-05-19 10:55:20 -070057static jlong Shader_getNativeFinalizer(JNIEnv*, jobject) {
58 return static_cast<jlong>(reinterpret_cast<uintptr_t>(&Shader_safeUnref));
59}
60
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080061///////////////////////////////////////////////////////////////////////////////////////////////
62
Chris Craikb581e672017-03-07 15:27:36 -080063static jlong BitmapShader_constructor(JNIEnv* env, jobject o, jlong matrixPtr, jobject jbitmap,
64 jint tileModeX, jint tileModeY) {
65 const SkMatrix* matrix = reinterpret_cast<const SkMatrix*>(matrixPtr);
Stan Iliev7bc3bc62017-05-24 13:28:36 -040066 sk_sp<SkImage> image;
Chris Craikb786bbd2015-06-10 16:58:42 -070067 if (jbitmap) {
68 // Only pass a valid SkBitmap object to the constructor if the Bitmap exists. Otherwise,
69 // we'll pass an empty SkBitmap to avoid crashing/excepting for compatibility.
Stan Iliev7bc3bc62017-05-24 13:28:36 -040070 image = android::bitmap::toBitmap(env, jbitmap).makeImage();
Chris Craikb786bbd2015-06-10 16:58:42 -070071 }
Romain Guy06f96e22010-07-30 19:18:16 -070072
Stan Iliev7bc3bc62017-05-24 13:28:36 -040073 if (!image.get()) {
74 SkBitmap bitmap;
75 image = SkMakeImageFromRasterBitmap(bitmap, kNever_SkCopyPixelsMode);
76 }
ztenghuib244fb52017-04-04 17:33:40 -070077 sk_sp<SkShader> baseShader = image->makeShader(
78 (SkShader::TileMode)tileModeX, (SkShader::TileMode)tileModeY);
Derek Sollenberger450756a2016-11-07 15:55:47 -050079
ztenghuib244fb52017-04-04 17:33:40 -070080 SkShader* shader;
81 if (matrix) {
82 shader = baseShader->makeWithLocalMatrix(*matrix).release();
83 } else {
84 shader = baseShader.release();
85 }
86
87 ThrowIAE_IfNull(env, shader);
88 return reinterpret_cast<jlong>(shader);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080089}
Romain Guy06f96e22010-07-30 19:18:16 -070090
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080091///////////////////////////////////////////////////////////////////////////////////////////////
92
Chris Craikb581e672017-03-07 15:27:36 -080093static jlong LinearGradient_create1(JNIEnv* env, jobject o, jlong matrixPtr,
94 jfloat x0, jfloat y0, jfloat x1, jfloat y1,
95 jintArray colorArray, jfloatArray posArray, jint tileMode) {
96 const SkMatrix* matrix = reinterpret_cast<const SkMatrix*>(matrixPtr);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080097 SkPoint pts[2];
Leon Scroggins III2e0103e2014-04-04 17:05:24 -040098 pts[0].set(x0, y0);
99 pts[1].set(x1, y1);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800100
Romain Guy06f96e22010-07-30 19:18:16 -0700101 size_t count = env->GetArrayLength(colorArray);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800102 const jint* colorValues = env->GetIntArrayElements(colorArray, NULL);
103
Leon Scroggins III2e0103e2014-04-04 17:05:24 -0400104 AutoJavaFloatArray autoPos(env, posArray, count);
105#ifdef SK_SCALAR_IS_FLOAT
106 SkScalar* pos = autoPos.ptr();
107#else
108 #error Need to convert float array to SkScalar array before calling the following function.
109#endif
Elliott Hughes4cb17532011-04-12 16:10:26 -0700110
ztenghuib244fb52017-04-04 17:33:40 -0700111 sk_sp<SkShader> baseShader(SkGradientShader::MakeLinear(pts,
Leon Scroggins III2e0103e2014-04-04 17:05:24 -0400112 reinterpret_cast<const SkColor*>(colorValues), pos, count,
ztenghuib244fb52017-04-04 17:33:40 -0700113 static_cast<SkShader::TileMode>(tileMode), sGradientShaderFlags, NULL));
114
115 SkShader* shader;
116 if (matrix) {
117 shader = baseShader->makeWithLocalMatrix(*matrix).release();
118 } else {
119 shader = baseShader.release();
120 }
Romain Guy06f96e22010-07-30 19:18:16 -0700121
122 env->ReleaseIntArrayElements(colorArray, const_cast<jint*>(colorValues), JNI_ABORT);
123 ThrowIAE_IfNull(env, shader);
Ashok Bhat36bef0b2014-01-20 20:08:01 +0000124 return reinterpret_cast<jlong>(shader);
Romain Guy06f96e22010-07-30 19:18:16 -0700125}
126
Chris Craikb581e672017-03-07 15:27:36 -0800127static jlong LinearGradient_create2(JNIEnv* env, jobject o, jlong matrixPtr,
128 jfloat x0, jfloat y0, jfloat x1, jfloat y1, jint color0, jint color1, jint tileMode) {
129 const SkMatrix* matrix = reinterpret_cast<const SkMatrix*>(matrixPtr);
130
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800131 SkPoint pts[2];
Leon Scroggins III2e0103e2014-04-04 17:05:24 -0400132 pts[0].set(x0, y0);
133 pts[1].set(x1, y1);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800134
135 SkColor colors[2];
136 colors[0] = color0;
137 colors[1] = color1;
Elliott Hughes4cb17532011-04-12 16:10:26 -0700138
ztenghuib244fb52017-04-04 17:33:40 -0700139 sk_sp<SkShader> baseShader(SkGradientShader::MakeLinear(pts, colors, NULL, 2,
140 static_cast<SkShader::TileMode>(tileMode), sGradientShaderFlags, NULL));
141
142 SkShader* s;
143 if (matrix) {
144 s = baseShader->makeWithLocalMatrix(*matrix).release();
145 } else {
146 s = baseShader.release();
147 }
Romain Guy06f96e22010-07-30 19:18:16 -0700148
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800149 ThrowIAE_IfNull(env, s);
Ashok Bhat36bef0b2014-01-20 20:08:01 +0000150 return reinterpret_cast<jlong>(s);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800151}
152
153///////////////////////////////////////////////////////////////////////////////////////////////
154
Chris Craikb581e672017-03-07 15:27:36 -0800155static jlong RadialGradient_create1(JNIEnv* env, jobject, jlong matrixPtr, jfloat x, jfloat y,
156 jfloat radius, jintArray colorArray, jfloatArray posArray, jint tileMode) {
157 const SkMatrix* matrix = reinterpret_cast<const SkMatrix*>(matrixPtr);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800158 SkPoint center;
Leon Scroggins III2e0103e2014-04-04 17:05:24 -0400159 center.set(x, y);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800160
161 size_t count = env->GetArrayLength(colorArray);
162 const jint* colorValues = env->GetIntArrayElements(colorArray, NULL);
163
Leon Scroggins III2e0103e2014-04-04 17:05:24 -0400164 AutoJavaFloatArray autoPos(env, posArray, count);
165#ifdef SK_SCALAR_IS_FLOAT
166 SkScalar* pos = autoPos.ptr();
167#else
168 #error Need to convert float array to SkScalar array before calling the following function.
169#endif
Elliott Hughes4cb17532011-04-12 16:10:26 -0700170
ztenghuib244fb52017-04-04 17:33:40 -0700171 sk_sp<SkShader> baseShader = SkGradientShader::MakeRadial(center, radius,
Leon Scroggins III2e0103e2014-04-04 17:05:24 -0400172 reinterpret_cast<const SkColor*>(colorValues), pos, count,
ztenghuib244fb52017-04-04 17:33:40 -0700173 static_cast<SkShader::TileMode>(tileMode), sGradientShaderFlags, NULL);
174
175 SkShader* shader;
176 if (matrix) {
177 shader = baseShader->makeWithLocalMatrix(*matrix).release();
178 } else {
179 shader = baseShader.release();
180 }
181
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800182 env->ReleaseIntArrayElements(colorArray, const_cast<jint*>(colorValues),
183 JNI_ABORT);
184
185 ThrowIAE_IfNull(env, shader);
Ashok Bhat36bef0b2014-01-20 20:08:01 +0000186 return reinterpret_cast<jlong>(shader);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800187}
188
Chris Craikb581e672017-03-07 15:27:36 -0800189static jlong RadialGradient_create2(JNIEnv* env, jobject, jlong matrixPtr, jfloat x, jfloat y, jfloat radius,
Ashok Bhat36bef0b2014-01-20 20:08:01 +0000190 jint color0, jint color1, jint tileMode) {
Chris Craikb581e672017-03-07 15:27:36 -0800191 const SkMatrix* matrix = reinterpret_cast<const SkMatrix*>(matrixPtr);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800192 SkPoint center;
Leon Scroggins III2e0103e2014-04-04 17:05:24 -0400193 center.set(x, y);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800194
195 SkColor colors[2];
196 colors[0] = color0;
197 colors[1] = color1;
198
ztenghuib244fb52017-04-04 17:33:40 -0700199 sk_sp<SkShader> baseShader = SkGradientShader::MakeRadial(center, radius, colors, NULL, 2,
200 static_cast<SkShader::TileMode>(tileMode), sGradientShaderFlags, NULL);
201
202 SkShader* shader;
203 if (matrix) {
204 shader = baseShader->makeWithLocalMatrix(*matrix).release();
205 } else {
206 shader = baseShader.release();
207 }
208 ThrowIAE_IfNull(env, shader);
209 return reinterpret_cast<jlong>(shader);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800210}
211
212///////////////////////////////////////////////////////////////////////////////
213
Chris Craikb581e672017-03-07 15:27:36 -0800214static jlong SweepGradient_create1(JNIEnv* env, jobject, jlong matrixPtr, jfloat x, jfloat y,
Romain Guyddb80be2010-09-20 19:04:33 -0700215 jintArray jcolors, jfloatArray jpositions) {
Chris Craikb581e672017-03-07 15:27:36 -0800216 const SkMatrix* matrix = reinterpret_cast<const SkMatrix*>(matrixPtr);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800217 size_t count = env->GetArrayLength(jcolors);
218 const jint* colors = env->GetIntArrayElements(jcolors, NULL);
Elliott Hughes4cb17532011-04-12 16:10:26 -0700219
Leon Scroggins III2e0103e2014-04-04 17:05:24 -0400220 AutoJavaFloatArray autoPos(env, jpositions, count);
221#ifdef SK_SCALAR_IS_FLOAT
222 SkScalar* pos = autoPos.ptr();
223#else
224 #error Need to convert float array to SkScalar array before calling the following function.
225#endif
Elliott Hughes4cb17532011-04-12 16:10:26 -0700226
ztenghuib244fb52017-04-04 17:33:40 -0700227 sk_sp<SkShader> baseShader = SkGradientShader::MakeSweep(x, y,
228 reinterpret_cast<const SkColor*>(colors), pos, count,
229 sGradientShaderFlags, NULL);
230
231 SkShader* shader;
232 if (matrix) {
233 shader = baseShader->makeWithLocalMatrix(*matrix).release();
234 } else {
235 shader = baseShader.release();
236 }
237
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800238 env->ReleaseIntArrayElements(jcolors, const_cast<jint*>(colors),
239 JNI_ABORT);
240 ThrowIAE_IfNull(env, shader);
Ashok Bhat36bef0b2014-01-20 20:08:01 +0000241 return reinterpret_cast<jlong>(shader);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800242}
243
Chris Craikb581e672017-03-07 15:27:36 -0800244static jlong SweepGradient_create2(JNIEnv* env, jobject, jlong matrixPtr, jfloat x, jfloat y,
Romain Guyddb80be2010-09-20 19:04:33 -0700245 int color0, int color1) {
Chris Craikb581e672017-03-07 15:27:36 -0800246 const SkMatrix* matrix = reinterpret_cast<const SkMatrix*>(matrixPtr);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800247 SkColor colors[2];
248 colors[0] = color0;
249 colors[1] = color1;
ztenghuib244fb52017-04-04 17:33:40 -0700250
251 sk_sp<SkShader> baseShader = SkGradientShader::MakeSweep(x, y, colors,
252 NULL, 2, sGradientShaderFlags, NULL);
253
254 SkShader* shader;
255 if (matrix) {
256 shader = baseShader->makeWithLocalMatrix(*matrix).release();
257 } else {
258 shader = baseShader.release();
259 }
260 ThrowIAE_IfNull(env, shader);
261 return reinterpret_cast<jlong>(shader);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800262}
263
264///////////////////////////////////////////////////////////////////////////////////////////////
265
Chris Craikb581e672017-03-07 15:27:36 -0800266static jlong ComposeShader_create(JNIEnv* env, jobject o, jlong matrixPtr,
267 jlong shaderAHandle, jlong shaderBHandle, jint xfermodeHandle) {
268 const SkMatrix* matrix = reinterpret_cast<const SkMatrix*>(matrixPtr);
Ashok Bhat36bef0b2014-01-20 20:08:01 +0000269 SkShader* shaderA = reinterpret_cast<SkShader *>(shaderAHandle);
270 SkShader* shaderB = reinterpret_cast<SkShader *>(shaderBHandle);
Mike Reed260ab722016-10-07 15:59:20 -0400271 SkBlendMode mode = static_cast<SkBlendMode>(xfermodeHandle);
Chris Craikb581e672017-03-07 15:27:36 -0800272 sk_sp<SkShader> baseShader(SkShader::MakeComposeShader(
273 sk_ref_sp(shaderA), sk_ref_sp(shaderB), mode));
274
275 SkShader* shader;
276
277 if (matrix) {
278 shader = baseShader->makeWithLocalMatrix(*matrix).release();
279 } else {
280 shader = baseShader.release();
281 }
Ashok Bhat36bef0b2014-01-20 20:08:01 +0000282 return reinterpret_cast<jlong>(shader);
Romain Guy06f96e22010-07-30 19:18:16 -0700283}
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800284
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800285///////////////////////////////////////////////////////////////////////////////////////////////
286
Daniel Micay76f6a862015-09-19 17:31:01 -0400287static const JNINativeMethod gColorMethods[] = {
Chris Craikb581e672017-03-07 15:27:36 -0800288 { "nativeRGBToHSV", "(III[F)V", (void*)Color_RGBToHSV },
289 { "nativeHSVToColor", "(I[F)I", (void*)Color_HSVToColor }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800290};
291
Daniel Micay76f6a862015-09-19 17:31:01 -0400292static const JNINativeMethod gShaderMethods[] = {
John Reck8bde0be2017-05-19 10:55:20 -0700293 { "nativeGetFinalizer", "()J", (void*)Shader_getNativeFinalizer },
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800294};
295
Daniel Micay76f6a862015-09-19 17:31:01 -0400296static const JNINativeMethod gBitmapShaderMethods[] = {
Chris Craikb581e672017-03-07 15:27:36 -0800297 { "nativeCreate", "(JLandroid/graphics/Bitmap;II)J", (void*)BitmapShader_constructor },
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800298};
299
Daniel Micay76f6a862015-09-19 17:31:01 -0400300static const JNINativeMethod gLinearGradientMethods[] = {
Chris Craikb581e672017-03-07 15:27:36 -0800301 { "nativeCreate1", "(JFFFF[I[FI)J", (void*)LinearGradient_create1 },
302 { "nativeCreate2", "(JFFFFIII)J", (void*)LinearGradient_create2 },
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800303};
304
Daniel Micay76f6a862015-09-19 17:31:01 -0400305static const JNINativeMethod gRadialGradientMethods[] = {
Chris Craikb581e672017-03-07 15:27:36 -0800306 { "nativeCreate1", "(JFFF[I[FI)J", (void*)RadialGradient_create1 },
307 { "nativeCreate2", "(JFFFIII)J", (void*)RadialGradient_create2 },
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800308};
309
Daniel Micay76f6a862015-09-19 17:31:01 -0400310static const JNINativeMethod gSweepGradientMethods[] = {
Chris Craikb581e672017-03-07 15:27:36 -0800311 { "nativeCreate1", "(JFF[I[F)J", (void*)SweepGradient_create1 },
312 { "nativeCreate2", "(JFFII)J", (void*)SweepGradient_create2 },
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800313};
314
Daniel Micay76f6a862015-09-19 17:31:01 -0400315static const JNINativeMethod gComposeShaderMethods[] = {
Chris Craikb581e672017-03-07 15:27:36 -0800316 { "nativeCreate", "(JJJI)J", (void*)ComposeShader_create },
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800317};
318
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800319int register_android_graphics_Shader(JNIEnv* env)
320{
Andreas Gampeed6b9df2014-11-20 22:02:20 -0800321 android::RegisterMethodsOrDie(env, "android/graphics/Color", gColorMethods,
322 NELEM(gColorMethods));
323 android::RegisterMethodsOrDie(env, "android/graphics/Shader", gShaderMethods,
324 NELEM(gShaderMethods));
325 android::RegisterMethodsOrDie(env, "android/graphics/BitmapShader", gBitmapShaderMethods,
326 NELEM(gBitmapShaderMethods));
327 android::RegisterMethodsOrDie(env, "android/graphics/LinearGradient", gLinearGradientMethods,
328 NELEM(gLinearGradientMethods));
329 android::RegisterMethodsOrDie(env, "android/graphics/RadialGradient", gRadialGradientMethods,
330 NELEM(gRadialGradientMethods));
331 android::RegisterMethodsOrDie(env, "android/graphics/SweepGradient", gSweepGradientMethods,
332 NELEM(gSweepGradientMethods));
333 android::RegisterMethodsOrDie(env, "android/graphics/ComposeShader", gComposeShaderMethods,
334 NELEM(gComposeShaderMethods));
Elliott Hughes4cb17532011-04-12 16:10:26 -0700335
Andreas Gampeed6b9df2014-11-20 22:02:20 -0800336 return 0;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800337}