blob: 6095ffa6b3dcbc8bbbd317bfa9ede49f6aaa923e [file] [log] [blame]
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001#include "GraphicsJNI.h"
Derek Sollenbergerfb0c8fc2017-07-26 13:53:27 -04002#include "SkColorFilter.h"
Ben Wagner60126ef2015-08-07 12:13:48 -04003#include "SkGradientShader.h"
Matt Sarett62feb3a2016-09-20 10:34:11 -04004#include "SkImagePriv.h"
Ben Wagner60126ef2015-08-07 12:13:48 -04005#include "SkShader.h"
Mike Reedc2f31df2016-10-28 17:21:45 -04006#include "SkBlendMode.h"
Ben Wagner60126ef2015-08-07 12:13:48 -04007#include "core_jni_helpers.h"
Stan Iliev6867fc82019-11-22 18:00:01 -05008#include "src/shaders/SkRTShader.h"
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009
Ben Wagner60126ef2015-08-07 12:13:48 -040010#include <jni.h>
Andreas Gampeed6b9df2014-11-20 22:02:20 -080011
Leon Scroggins IIIb0aecc22019-01-18 11:09:59 -050012#include <vector>
13
Romain Guy06f96e22010-07-30 19:18:16 -070014using namespace android::uirenderer;
15
Derek Sollenberger669b15a2017-03-31 12:09:24 -040016/**
17 * By default Skia gradients will interpolate their colors in unpremul space
18 * and then premultiply each of the results. We must set this flag to preserve
19 * backwards compatiblity by premultiplying the colors of the gradient first,
20 * and then interpolating between them.
21 */
22static const uint32_t sGradientShaderFlags = SkGradientShader::kInterpolateColorsInPremul_Flag;
23
Leon Scroggins IIIb0aecc22019-01-18 11:09:59 -050024#define ThrowIAE_IfNull(env, ptr) \
25 if (nullptr == ptr) { \
26 doThrowIAE(env); \
27 return 0; \
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080028 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080029
Ashok Bhat36bef0b2014-01-20 20:08:01 +000030static void Color_RGBToHSV(JNIEnv* env, jobject, jint red, jint green, jint blue, jfloatArray hsvArray)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080031{
32 SkScalar hsv[3];
33 SkRGBToHSV(red, green, blue, hsv);
34
35 AutoJavaFloatArray autoHSV(env, hsvArray, 3);
36 float* values = autoHSV.ptr();
37 for (int i = 0; i < 3; i++) {
38 values[i] = SkScalarToFloat(hsv[i]);
39 }
40}
Elliott Hughes4cb17532011-04-12 16:10:26 -070041
Ashok Bhat36bef0b2014-01-20 20:08:01 +000042static jint Color_HSVToColor(JNIEnv* env, jobject, jint alpha, jfloatArray hsvArray)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080043{
44 AutoJavaFloatArray autoHSV(env, hsvArray, 3);
Leon Scroggins III2e0103e2014-04-04 17:05:24 -040045#ifdef SK_SCALAR_IS_FLOAT
46 SkScalar* hsv = autoHSV.ptr();
47#else
48 #error Need to convert float array to SkScalar array before calling the following function.
49#endif
Elliott Hughes4cb17532011-04-12 16:10:26 -070050
Ashok Bhat36bef0b2014-01-20 20:08:01 +000051 return static_cast<jint>(SkHSVToColor(alpha, hsv));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080052}
53
54///////////////////////////////////////////////////////////////////////////////////////////////
55
John Reck8bde0be2017-05-19 10:55:20 -070056static void Shader_safeUnref(SkShader* shader) {
Derek Sollenberger6062c592011-02-22 13:55:04 -050057 SkSafeUnref(shader);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080058}
59
John Reck8bde0be2017-05-19 10:55:20 -070060static jlong Shader_getNativeFinalizer(JNIEnv*, jobject) {
61 return static_cast<jlong>(reinterpret_cast<uintptr_t>(&Shader_safeUnref));
62}
63
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080064///////////////////////////////////////////////////////////////////////////////////////////////
65
Leon Scroggins III71fae622019-03-26 16:28:41 -040066static jlong BitmapShader_constructor(JNIEnv* env, jobject o, jlong matrixPtr, jlong bitmapHandle,
Chris Craikb581e672017-03-07 15:27:36 -080067 jint tileModeX, jint tileModeY) {
68 const SkMatrix* matrix = reinterpret_cast<const SkMatrix*>(matrixPtr);
Stan Iliev7bc3bc62017-05-24 13:28:36 -040069 sk_sp<SkImage> image;
Leon Scroggins III71fae622019-03-26 16:28:41 -040070 if (bitmapHandle) {
Chris Craikb786bbd2015-06-10 16:58:42 -070071 // Only pass a valid SkBitmap object to the constructor if the Bitmap exists. Otherwise,
72 // we'll pass an empty SkBitmap to avoid crashing/excepting for compatibility.
Leon Scroggins III71fae622019-03-26 16:28:41 -040073 image = android::bitmap::toBitmap(bitmapHandle).makeImage();
Chris Craikb786bbd2015-06-10 16:58:42 -070074 }
Romain Guy06f96e22010-07-30 19:18:16 -070075
Stan Iliev7bc3bc62017-05-24 13:28:36 -040076 if (!image.get()) {
77 SkBitmap bitmap;
78 image = SkMakeImageFromRasterBitmap(bitmap, kNever_SkCopyPixelsMode);
79 }
Derek Sollenbergerfb0c8fc2017-07-26 13:53:27 -040080 sk_sp<SkShader> shader = image->makeShader(
Mike Reed1c2f5fc2019-04-10 16:57:52 -040081 (SkTileMode)tileModeX, (SkTileMode)tileModeY);
Leon Scroggins IIIb0aecc22019-01-18 11:09:59 -050082 ThrowIAE_IfNull(env, shader.get());
Derek Sollenberger450756a2016-11-07 15:55:47 -050083
ztenghuib244fb52017-04-04 17:33:40 -070084 if (matrix) {
Derek Sollenbergerfb0c8fc2017-07-26 13:53:27 -040085 shader = shader->makeWithLocalMatrix(*matrix);
86 }
ztenghuib244fb52017-04-04 17:33:40 -070087
Derek Sollenbergerfb0c8fc2017-07-26 13:53:27 -040088 return reinterpret_cast<jlong>(shader.release());
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
Leon Scroggins IIIb0aecc22019-01-18 11:09:59 -050093static std::vector<SkColor4f> convertColorLongs(JNIEnv* env, jlongArray colorArray) {
94 const size_t count = env->GetArrayLength(colorArray);
95 const jlong* colorValues = env->GetLongArrayElements(colorArray, nullptr);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080096
Leon Scroggins IIIb0aecc22019-01-18 11:09:59 -050097 std::vector<SkColor4f> colors(count);
98 for (size_t i = 0; i < count; ++i) {
99 colors[i] = GraphicsJNI::convertColorLong(colorValues[i]);
ztenghuib244fb52017-04-04 17:33:40 -0700100 }
Romain Guy06f96e22010-07-30 19:18:16 -0700101
Leon Scroggins IIIb0aecc22019-01-18 11:09:59 -0500102 env->ReleaseLongArrayElements(colorArray, const_cast<jlong*>(colorValues), JNI_ABORT);
103 return colors;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800104}
105
106///////////////////////////////////////////////////////////////////////////////////////////////
107
Leon Scroggins IIIb0aecc22019-01-18 11:09:59 -0500108static jlong LinearGradient_create(JNIEnv* env, jobject, jlong matrixPtr,
109 jfloat x0, jfloat y0, jfloat x1, jfloat y1, jlongArray colorArray,
Leon Scroggins III2befe1d2019-01-31 13:19:26 -0500110 jfloatArray posArray, jint tileMode, jlong colorSpaceHandle) {
Leon Scroggins IIIb0aecc22019-01-18 11:09:59 -0500111 SkPoint pts[2];
112 pts[0].set(x0, y0);
113 pts[1].set(x1, y1);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800114
Leon Scroggins IIIb0aecc22019-01-18 11:09:59 -0500115 std::vector<SkColor4f> colors = convertColorLongs(env, colorArray);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800116
Leon Scroggins IIIb0aecc22019-01-18 11:09:59 -0500117 AutoJavaFloatArray autoPos(env, posArray, colors.size());
Leon Scroggins III2e0103e2014-04-04 17:05:24 -0400118#ifdef SK_SCALAR_IS_FLOAT
119 SkScalar* pos = autoPos.ptr();
120#else
121 #error Need to convert float array to SkScalar array before calling the following function.
122#endif
Elliott Hughes4cb17532011-04-12 16:10:26 -0700123
Leon Scroggins IIIb0aecc22019-01-18 11:09:59 -0500124 sk_sp<SkShader> shader(SkGradientShader::MakeLinear(pts, &colors[0],
125 GraphicsJNI::getNativeColorSpace(colorSpaceHandle), pos, colors.size(),
Mike Reed1c2f5fc2019-04-10 16:57:52 -0400126 static_cast<SkTileMode>(tileMode), sGradientShaderFlags, nullptr));
Leon Scroggins IIIb0aecc22019-01-18 11:09:59 -0500127 ThrowIAE_IfNull(env, shader);
ztenghuib244fb52017-04-04 17:33:40 -0700128
Leon Scroggins IIIb0aecc22019-01-18 11:09:59 -0500129 const SkMatrix* matrix = reinterpret_cast<const SkMatrix*>(matrixPtr);
ztenghuib244fb52017-04-04 17:33:40 -0700130 if (matrix) {
Leon Scroggins IIIb0aecc22019-01-18 11:09:59 -0500131 shader = shader->makeWithLocalMatrix(*matrix);
ztenghuib244fb52017-04-04 17:33:40 -0700132 }
133
Leon Scroggins IIIb0aecc22019-01-18 11:09:59 -0500134 return reinterpret_cast<jlong>(shader.release());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800135}
136
Leon Scroggins IIIb0aecc22019-01-18 11:09:59 -0500137///////////////////////////////////////////////////////////////////////////////////////////////
138
139static jlong RadialGradient_create(JNIEnv* env, jobject, jlong matrixPtr, jfloat x, jfloat y,
140 jfloat radius, jlongArray colorArray, jfloatArray posArray, jint tileMode,
141 jlong colorSpaceHandle) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800142 SkPoint center;
Leon Scroggins III2e0103e2014-04-04 17:05:24 -0400143 center.set(x, y);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800144
Leon Scroggins IIIb0aecc22019-01-18 11:09:59 -0500145 std::vector<SkColor4f> colors = convertColorLongs(env, colorArray);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800146
Leon Scroggins IIIb0aecc22019-01-18 11:09:59 -0500147 AutoJavaFloatArray autoPos(env, posArray, colors.size());
148#ifdef SK_SCALAR_IS_FLOAT
149 SkScalar* pos = autoPos.ptr();
150#else
151 #error Need to convert float array to SkScalar array before calling the following function.
152#endif
ztenghuib244fb52017-04-04 17:33:40 -0700153
Leon Scroggins IIIb0aecc22019-01-18 11:09:59 -0500154 sk_sp<SkShader> shader = SkGradientShader::MakeRadial(center, radius, &colors[0],
155 GraphicsJNI::getNativeColorSpace(colorSpaceHandle), pos, colors.size(),
Mike Reed1c2f5fc2019-04-10 16:57:52 -0400156 static_cast<SkTileMode>(tileMode), sGradientShaderFlags, nullptr);
ztenghuib244fb52017-04-04 17:33:40 -0700157 ThrowIAE_IfNull(env, shader);
Leon Scroggins IIIb0aecc22019-01-18 11:09:59 -0500158
159 const SkMatrix* matrix = reinterpret_cast<const SkMatrix*>(matrixPtr);
160 if (matrix) {
161 shader = shader->makeWithLocalMatrix(*matrix);
162 }
163
164 return reinterpret_cast<jlong>(shader.release());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800165}
166
167///////////////////////////////////////////////////////////////////////////////
168
Leon Scroggins IIIb0aecc22019-01-18 11:09:59 -0500169static jlong SweepGradient_create(JNIEnv* env, jobject, jlong matrixPtr, jfloat x, jfloat y,
170 jlongArray colorArray, jfloatArray jpositions, jlong colorSpaceHandle) {
171 std::vector<SkColor4f> colors = convertColorLongs(env, colorArray);
Elliott Hughes4cb17532011-04-12 16:10:26 -0700172
Leon Scroggins IIIb0aecc22019-01-18 11:09:59 -0500173 AutoJavaFloatArray autoPos(env, jpositions, colors.size());
Leon Scroggins III2e0103e2014-04-04 17:05:24 -0400174#ifdef SK_SCALAR_IS_FLOAT
175 SkScalar* pos = autoPos.ptr();
176#else
177 #error Need to convert float array to SkScalar array before calling the following function.
178#endif
Elliott Hughes4cb17532011-04-12 16:10:26 -0700179
Leon Scroggins IIIb0aecc22019-01-18 11:09:59 -0500180 sk_sp<SkShader> shader = SkGradientShader::MakeSweep(x, y, &colors[0],
181 GraphicsJNI::getNativeColorSpace(colorSpaceHandle), pos, colors.size(),
182 sGradientShaderFlags, nullptr);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800183 ThrowIAE_IfNull(env, shader);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800184
Chris Craikb581e672017-03-07 15:27:36 -0800185 const SkMatrix* matrix = reinterpret_cast<const SkMatrix*>(matrixPtr);
ztenghuib244fb52017-04-04 17:33:40 -0700186 if (matrix) {
Leon Scroggins IIIb0aecc22019-01-18 11:09:59 -0500187 shader = shader->makeWithLocalMatrix(*matrix);
ztenghuib244fb52017-04-04 17:33:40 -0700188 }
Leon Scroggins IIIb0aecc22019-01-18 11:09:59 -0500189
190 return reinterpret_cast<jlong>(shader.release());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800191}
192
193///////////////////////////////////////////////////////////////////////////////////////////////
194
Chris Craikb581e672017-03-07 15:27:36 -0800195static jlong ComposeShader_create(JNIEnv* env, jobject o, jlong matrixPtr,
196 jlong shaderAHandle, jlong shaderBHandle, jint xfermodeHandle) {
197 const SkMatrix* matrix = reinterpret_cast<const SkMatrix*>(matrixPtr);
Ashok Bhat36bef0b2014-01-20 20:08:01 +0000198 SkShader* shaderA = reinterpret_cast<SkShader *>(shaderAHandle);
199 SkShader* shaderB = reinterpret_cast<SkShader *>(shaderBHandle);
Mike Reed260ab722016-10-07 15:59:20 -0400200 SkBlendMode mode = static_cast<SkBlendMode>(xfermodeHandle);
Mike Reed1c2f5fc2019-04-10 16:57:52 -0400201 sk_sp<SkShader> baseShader(SkShaders::Blend(mode,
202 sk_ref_sp(shaderA), sk_ref_sp(shaderB)));
Chris Craikb581e672017-03-07 15:27:36 -0800203
204 SkShader* shader;
205
206 if (matrix) {
207 shader = baseShader->makeWithLocalMatrix(*matrix).release();
208 } else {
209 shader = baseShader.release();
210 }
Ashok Bhat36bef0b2014-01-20 20:08:01 +0000211 return reinterpret_cast<jlong>(shader);
Romain Guy06f96e22010-07-30 19:18:16 -0700212}
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800213
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800214///////////////////////////////////////////////////////////////////////////////////////////////
215
Stan Iliev6867fc82019-11-22 18:00:01 -0500216static jlong RuntimeShader_create(JNIEnv* env, jobject, jlong shaderFactory, jlong matrixPtr,
217 jbyteArray inputs, jlong colorSpaceHandle) {
218 SkRuntimeShaderFactory* factory = reinterpret_cast<SkRuntimeShaderFactory*>(shaderFactory);
219 AutoJavaByteArray arInputs(env, inputs);
220
221 sk_sp<SkData> fData;
222 fData = SkData::MakeWithCopy(arInputs.ptr(), arInputs.length());
223 const SkMatrix* matrix = reinterpret_cast<const SkMatrix*>(matrixPtr);
224 sk_sp<SkShader> shader = factory->make(fData, matrix);
225 ThrowIAE_IfNull(env, shader);
226
227 return reinterpret_cast<jlong>(shader.release());
228}
229
230///////////////////////////////////////////////////////////////////////////////////////////////
231
232static jlong RuntimeShader_createShaderFactory(JNIEnv* env, jobject, jstring sksl,
233 jboolean isOpaque) {
234 ScopedUtfChars strSksl(env, sksl);
235 SkRuntimeShaderFactory* shaderFactory = new SkRuntimeShaderFactory(SkString(strSksl.c_str()),
236 isOpaque == JNI_TRUE);
237 ThrowIAE_IfNull(env, shaderFactory);
238
239 return reinterpret_cast<jlong>(shaderFactory);
240}
241
242///////////////////////////////////////////////////////////////////////////////////////////////
243
244static void RuntimeShader_delete(SkRuntimeShaderFactory* shaderFactory) {
245 delete shaderFactory;
246}
247
248static jlong RuntimeShader_getNativeFinalizer(JNIEnv*, jobject) {
249 return static_cast<jlong>(reinterpret_cast<uintptr_t>(&RuntimeShader_delete));
250}
251
252///////////////////////////////////////////////////////////////////////////////////////////////
253
Daniel Micay76f6a862015-09-19 17:31:01 -0400254static const JNINativeMethod gColorMethods[] = {
Chris Craikb581e672017-03-07 15:27:36 -0800255 { "nativeRGBToHSV", "(III[F)V", (void*)Color_RGBToHSV },
256 { "nativeHSVToColor", "(I[F)I", (void*)Color_HSVToColor }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800257};
258
Daniel Micay76f6a862015-09-19 17:31:01 -0400259static const JNINativeMethod gShaderMethods[] = {
John Reck8bde0be2017-05-19 10:55:20 -0700260 { "nativeGetFinalizer", "()J", (void*)Shader_getNativeFinalizer },
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800261};
262
Daniel Micay76f6a862015-09-19 17:31:01 -0400263static const JNINativeMethod gBitmapShaderMethods[] = {
Leon Scroggins III71fae622019-03-26 16:28:41 -0400264 { "nativeCreate", "(JJII)J", (void*)BitmapShader_constructor },
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800265};
266
Daniel Micay76f6a862015-09-19 17:31:01 -0400267static const JNINativeMethod gLinearGradientMethods[] = {
Leon Scroggins IIIb0aecc22019-01-18 11:09:59 -0500268 { "nativeCreate", "(JFFFF[J[FIJ)J", (void*)LinearGradient_create },
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800269};
270
Daniel Micay76f6a862015-09-19 17:31:01 -0400271static const JNINativeMethod gRadialGradientMethods[] = {
Leon Scroggins IIIb0aecc22019-01-18 11:09:59 -0500272 { "nativeCreate", "(JFFF[J[FIJ)J", (void*)RadialGradient_create },
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800273};
274
Daniel Micay76f6a862015-09-19 17:31:01 -0400275static const JNINativeMethod gSweepGradientMethods[] = {
Leon Scroggins IIIb0aecc22019-01-18 11:09:59 -0500276 { "nativeCreate", "(JFF[J[FJ)J", (void*)SweepGradient_create },
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800277};
278
Daniel Micay76f6a862015-09-19 17:31:01 -0400279static const JNINativeMethod gComposeShaderMethods[] = {
Chris Craikb581e672017-03-07 15:27:36 -0800280 { "nativeCreate", "(JJJI)J", (void*)ComposeShader_create },
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800281};
282
Stan Iliev6867fc82019-11-22 18:00:01 -0500283static const JNINativeMethod gRuntimeShaderMethods[] = {
284 { "nativeGetFinalizer", "()J", (void*)RuntimeShader_getNativeFinalizer },
285 { "nativeCreate", "(JJ[BJ)J", (void*)RuntimeShader_create },
286 { "nativeCreateShaderFactory", "(Ljava/lang/String;Z)J",
287 (void*)RuntimeShader_createShaderFactory },
288};
289
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800290int register_android_graphics_Shader(JNIEnv* env)
291{
Andreas Gampeed6b9df2014-11-20 22:02:20 -0800292 android::RegisterMethodsOrDie(env, "android/graphics/Color", gColorMethods,
293 NELEM(gColorMethods));
294 android::RegisterMethodsOrDie(env, "android/graphics/Shader", gShaderMethods,
295 NELEM(gShaderMethods));
296 android::RegisterMethodsOrDie(env, "android/graphics/BitmapShader", gBitmapShaderMethods,
297 NELEM(gBitmapShaderMethods));
298 android::RegisterMethodsOrDie(env, "android/graphics/LinearGradient", gLinearGradientMethods,
299 NELEM(gLinearGradientMethods));
300 android::RegisterMethodsOrDie(env, "android/graphics/RadialGradient", gRadialGradientMethods,
301 NELEM(gRadialGradientMethods));
302 android::RegisterMethodsOrDie(env, "android/graphics/SweepGradient", gSweepGradientMethods,
303 NELEM(gSweepGradientMethods));
304 android::RegisterMethodsOrDie(env, "android/graphics/ComposeShader", gComposeShaderMethods,
305 NELEM(gComposeShaderMethods));
Stan Iliev6867fc82019-11-22 18:00:01 -0500306 android::RegisterMethodsOrDie(env, "android/graphics/RuntimeShader", gRuntimeShaderMethods,
307 NELEM(gRuntimeShaderMethods));
Elliott Hughes4cb17532011-04-12 16:10:26 -0700308
Andreas Gampeed6b9df2014-11-20 22:02:20 -0800309 return 0;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800310}