blob: 0f6837640524af9a62ffeffb48fa02c37847b95b [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"
Brian Osmanbc44fa02020-01-03 15:28:06 -05007#include "include/effects/SkRuntimeEffect.h"
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008
Leon Scroggins IIIb0aecc22019-01-18 11:09:59 -05009#include <vector>
10
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
Leon Scroggins IIIb0aecc22019-01-18 11:09:59 -050021#define ThrowIAE_IfNull(env, ptr) \
22 if (nullptr == ptr) { \
23 doThrowIAE(env); \
24 return 0; \
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080025 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080026
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
Leon Scroggins III71fae622019-03-26 16:28:41 -040063static jlong BitmapShader_constructor(JNIEnv* env, jobject o, jlong matrixPtr, jlong bitmapHandle,
Chris Craikb581e672017-03-07 15:27:36 -080064 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;
Leon Scroggins III71fae622019-03-26 16:28:41 -040067 if (bitmapHandle) {
Chris Craikb786bbd2015-06-10 16:58:42 -070068 // 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.
Leon Scroggins III71fae622019-03-26 16:28:41 -040070 image = android::bitmap::toBitmap(bitmapHandle).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 }
Derek Sollenbergerfb0c8fc2017-07-26 13:53:27 -040077 sk_sp<SkShader> shader = image->makeShader(
Mike Reed1c2f5fc2019-04-10 16:57:52 -040078 (SkTileMode)tileModeX, (SkTileMode)tileModeY);
Leon Scroggins IIIb0aecc22019-01-18 11:09:59 -050079 ThrowIAE_IfNull(env, shader.get());
Derek Sollenberger450756a2016-11-07 15:55:47 -050080
ztenghuib244fb52017-04-04 17:33:40 -070081 if (matrix) {
Derek Sollenbergerfb0c8fc2017-07-26 13:53:27 -040082 shader = shader->makeWithLocalMatrix(*matrix);
83 }
ztenghuib244fb52017-04-04 17:33:40 -070084
Derek Sollenbergerfb0c8fc2017-07-26 13:53:27 -040085 return reinterpret_cast<jlong>(shader.release());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080086}
Romain Guy06f96e22010-07-30 19:18:16 -070087
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080088///////////////////////////////////////////////////////////////////////////////////////////////
89
Leon Scroggins IIIb0aecc22019-01-18 11:09:59 -050090static std::vector<SkColor4f> convertColorLongs(JNIEnv* env, jlongArray colorArray) {
91 const size_t count = env->GetArrayLength(colorArray);
92 const jlong* colorValues = env->GetLongArrayElements(colorArray, nullptr);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080093
Leon Scroggins IIIb0aecc22019-01-18 11:09:59 -050094 std::vector<SkColor4f> colors(count);
95 for (size_t i = 0; i < count; ++i) {
96 colors[i] = GraphicsJNI::convertColorLong(colorValues[i]);
ztenghuib244fb52017-04-04 17:33:40 -070097 }
Romain Guy06f96e22010-07-30 19:18:16 -070098
Leon Scroggins IIIb0aecc22019-01-18 11:09:59 -050099 env->ReleaseLongArrayElements(colorArray, const_cast<jlong*>(colorValues), JNI_ABORT);
100 return colors;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800101}
102
103///////////////////////////////////////////////////////////////////////////////////////////////
104
Leon Scroggins IIIb0aecc22019-01-18 11:09:59 -0500105static jlong LinearGradient_create(JNIEnv* env, jobject, jlong matrixPtr,
106 jfloat x0, jfloat y0, jfloat x1, jfloat y1, jlongArray colorArray,
Leon Scroggins III2befe1d2019-01-31 13:19:26 -0500107 jfloatArray posArray, jint tileMode, jlong colorSpaceHandle) {
Leon Scroggins IIIb0aecc22019-01-18 11:09:59 -0500108 SkPoint pts[2];
109 pts[0].set(x0, y0);
110 pts[1].set(x1, y1);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800111
Leon Scroggins IIIb0aecc22019-01-18 11:09:59 -0500112 std::vector<SkColor4f> colors = convertColorLongs(env, colorArray);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800113
Leon Scroggins IIIb0aecc22019-01-18 11:09:59 -0500114 AutoJavaFloatArray autoPos(env, posArray, colors.size());
Leon Scroggins III2e0103e2014-04-04 17:05:24 -0400115#ifdef SK_SCALAR_IS_FLOAT
116 SkScalar* pos = autoPos.ptr();
117#else
118 #error Need to convert float array to SkScalar array before calling the following function.
119#endif
Elliott Hughes4cb17532011-04-12 16:10:26 -0700120
Leon Scroggins IIIb0aecc22019-01-18 11:09:59 -0500121 sk_sp<SkShader> shader(SkGradientShader::MakeLinear(pts, &colors[0],
122 GraphicsJNI::getNativeColorSpace(colorSpaceHandle), pos, colors.size(),
Mike Reed1c2f5fc2019-04-10 16:57:52 -0400123 static_cast<SkTileMode>(tileMode), sGradientShaderFlags, nullptr));
Leon Scroggins IIIb0aecc22019-01-18 11:09:59 -0500124 ThrowIAE_IfNull(env, shader);
ztenghuib244fb52017-04-04 17:33:40 -0700125
Leon Scroggins IIIb0aecc22019-01-18 11:09:59 -0500126 const SkMatrix* matrix = reinterpret_cast<const SkMatrix*>(matrixPtr);
ztenghuib244fb52017-04-04 17:33:40 -0700127 if (matrix) {
Leon Scroggins IIIb0aecc22019-01-18 11:09:59 -0500128 shader = shader->makeWithLocalMatrix(*matrix);
ztenghuib244fb52017-04-04 17:33:40 -0700129 }
130
Leon Scroggins IIIb0aecc22019-01-18 11:09:59 -0500131 return reinterpret_cast<jlong>(shader.release());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800132}
133
Leon Scroggins IIIb0aecc22019-01-18 11:09:59 -0500134///////////////////////////////////////////////////////////////////////////////////////////////
135
136static jlong RadialGradient_create(JNIEnv* env, jobject, jlong matrixPtr, jfloat x, jfloat y,
137 jfloat radius, jlongArray colorArray, jfloatArray posArray, jint tileMode,
138 jlong colorSpaceHandle) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800139 SkPoint center;
Leon Scroggins III2e0103e2014-04-04 17:05:24 -0400140 center.set(x, y);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800141
Leon Scroggins IIIb0aecc22019-01-18 11:09:59 -0500142 std::vector<SkColor4f> colors = convertColorLongs(env, colorArray);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800143
Leon Scroggins IIIb0aecc22019-01-18 11:09:59 -0500144 AutoJavaFloatArray autoPos(env, posArray, colors.size());
145#ifdef SK_SCALAR_IS_FLOAT
146 SkScalar* pos = autoPos.ptr();
147#else
148 #error Need to convert float array to SkScalar array before calling the following function.
149#endif
ztenghuib244fb52017-04-04 17:33:40 -0700150
Leon Scroggins IIIb0aecc22019-01-18 11:09:59 -0500151 sk_sp<SkShader> shader = SkGradientShader::MakeRadial(center, radius, &colors[0],
152 GraphicsJNI::getNativeColorSpace(colorSpaceHandle), pos, colors.size(),
Mike Reed1c2f5fc2019-04-10 16:57:52 -0400153 static_cast<SkTileMode>(tileMode), sGradientShaderFlags, nullptr);
ztenghuib244fb52017-04-04 17:33:40 -0700154 ThrowIAE_IfNull(env, shader);
Leon Scroggins IIIb0aecc22019-01-18 11:09:59 -0500155
156 const SkMatrix* matrix = reinterpret_cast<const SkMatrix*>(matrixPtr);
157 if (matrix) {
158 shader = shader->makeWithLocalMatrix(*matrix);
159 }
160
161 return reinterpret_cast<jlong>(shader.release());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800162}
163
164///////////////////////////////////////////////////////////////////////////////
165
Leon Scroggins IIIb0aecc22019-01-18 11:09:59 -0500166static jlong SweepGradient_create(JNIEnv* env, jobject, jlong matrixPtr, jfloat x, jfloat y,
167 jlongArray colorArray, jfloatArray jpositions, jlong colorSpaceHandle) {
168 std::vector<SkColor4f> colors = convertColorLongs(env, colorArray);
Elliott Hughes4cb17532011-04-12 16:10:26 -0700169
Leon Scroggins IIIb0aecc22019-01-18 11:09:59 -0500170 AutoJavaFloatArray autoPos(env, jpositions, colors.size());
Leon Scroggins III2e0103e2014-04-04 17:05:24 -0400171#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
Leon Scroggins IIIb0aecc22019-01-18 11:09:59 -0500177 sk_sp<SkShader> shader = SkGradientShader::MakeSweep(x, y, &colors[0],
178 GraphicsJNI::getNativeColorSpace(colorSpaceHandle), pos, colors.size(),
179 sGradientShaderFlags, nullptr);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800180 ThrowIAE_IfNull(env, shader);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800181
Chris Craikb581e672017-03-07 15:27:36 -0800182 const SkMatrix* matrix = reinterpret_cast<const SkMatrix*>(matrixPtr);
ztenghuib244fb52017-04-04 17:33:40 -0700183 if (matrix) {
Leon Scroggins IIIb0aecc22019-01-18 11:09:59 -0500184 shader = shader->makeWithLocalMatrix(*matrix);
ztenghuib244fb52017-04-04 17:33:40 -0700185 }
Leon Scroggins IIIb0aecc22019-01-18 11:09:59 -0500186
187 return reinterpret_cast<jlong>(shader.release());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800188}
189
190///////////////////////////////////////////////////////////////////////////////////////////////
191
Chris Craikb581e672017-03-07 15:27:36 -0800192static jlong ComposeShader_create(JNIEnv* env, jobject o, jlong matrixPtr,
193 jlong shaderAHandle, jlong shaderBHandle, jint xfermodeHandle) {
194 const SkMatrix* matrix = reinterpret_cast<const SkMatrix*>(matrixPtr);
Ashok Bhat36bef0b2014-01-20 20:08:01 +0000195 SkShader* shaderA = reinterpret_cast<SkShader *>(shaderAHandle);
196 SkShader* shaderB = reinterpret_cast<SkShader *>(shaderBHandle);
Mike Reed260ab722016-10-07 15:59:20 -0400197 SkBlendMode mode = static_cast<SkBlendMode>(xfermodeHandle);
Mike Reed1c2f5fc2019-04-10 16:57:52 -0400198 sk_sp<SkShader> baseShader(SkShaders::Blend(mode,
199 sk_ref_sp(shaderA), sk_ref_sp(shaderB)));
Chris Craikb581e672017-03-07 15:27:36 -0800200
201 SkShader* shader;
202
203 if (matrix) {
204 shader = baseShader->makeWithLocalMatrix(*matrix).release();
205 } else {
206 shader = baseShader.release();
207 }
Ashok Bhat36bef0b2014-01-20 20:08:01 +0000208 return reinterpret_cast<jlong>(shader);
Romain Guy06f96e22010-07-30 19:18:16 -0700209}
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800210
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800211///////////////////////////////////////////////////////////////////////////////////////////////
212
Stan Iliev6867fc82019-11-22 18:00:01 -0500213static jlong RuntimeShader_create(JNIEnv* env, jobject, jlong shaderFactory, jlong matrixPtr,
Brian Osmanbc44fa02020-01-03 15:28:06 -0500214 jbyteArray inputs, jlong colorSpaceHandle, jboolean isOpaque) {
215 SkRuntimeEffect* effect = reinterpret_cast<SkRuntimeEffect*>(shaderFactory);
Stan Iliev6867fc82019-11-22 18:00:01 -0500216 AutoJavaByteArray arInputs(env, inputs);
217
218 sk_sp<SkData> fData;
219 fData = SkData::MakeWithCopy(arInputs.ptr(), arInputs.length());
220 const SkMatrix* matrix = reinterpret_cast<const SkMatrix*>(matrixPtr);
Brian Osmanbc44fa02020-01-03 15:28:06 -0500221 sk_sp<SkShader> shader = effect->makeShader(fData, nullptr, 0, matrix, isOpaque == JNI_TRUE);
Stan Iliev6867fc82019-11-22 18:00:01 -0500222 ThrowIAE_IfNull(env, shader);
223
224 return reinterpret_cast<jlong>(shader.release());
225}
226
227///////////////////////////////////////////////////////////////////////////////////////////////
228
Brian Osmanbc44fa02020-01-03 15:28:06 -0500229static jlong RuntimeShader_createShaderFactory(JNIEnv* env, jobject, jstring sksl) {
Stan Iliev6867fc82019-11-22 18:00:01 -0500230 ScopedUtfChars strSksl(env, sksl);
Brian Osmanbc44fa02020-01-03 15:28:06 -0500231 sk_sp<SkRuntimeEffect> effect = std::get<0>(SkRuntimeEffect::Make(SkString(strSksl.c_str())));
232 ThrowIAE_IfNull(env, effect);
Stan Iliev6867fc82019-11-22 18:00:01 -0500233
Brian Osmanbc44fa02020-01-03 15:28:06 -0500234 return reinterpret_cast<jlong>(effect.release());
Stan Iliev6867fc82019-11-22 18:00:01 -0500235}
236
237///////////////////////////////////////////////////////////////////////////////////////////////
238
Brian Osmanbc44fa02020-01-03 15:28:06 -0500239static void Effect_safeUnref(SkRuntimeEffect* effect) {
240 SkSafeUnref(effect);
Stan Iliev6867fc82019-11-22 18:00:01 -0500241}
242
243static jlong RuntimeShader_getNativeFinalizer(JNIEnv*, jobject) {
Brian Osmanbc44fa02020-01-03 15:28:06 -0500244 return static_cast<jlong>(reinterpret_cast<uintptr_t>(&Effect_safeUnref));
Stan Iliev6867fc82019-11-22 18:00:01 -0500245}
246
247///////////////////////////////////////////////////////////////////////////////////////////////
248
Daniel Micay76f6a862015-09-19 17:31:01 -0400249static const JNINativeMethod gColorMethods[] = {
Chris Craikb581e672017-03-07 15:27:36 -0800250 { "nativeRGBToHSV", "(III[F)V", (void*)Color_RGBToHSV },
251 { "nativeHSVToColor", "(I[F)I", (void*)Color_HSVToColor }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800252};
253
Daniel Micay76f6a862015-09-19 17:31:01 -0400254static const JNINativeMethod gShaderMethods[] = {
John Reck8bde0be2017-05-19 10:55:20 -0700255 { "nativeGetFinalizer", "()J", (void*)Shader_getNativeFinalizer },
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800256};
257
Daniel Micay76f6a862015-09-19 17:31:01 -0400258static const JNINativeMethod gBitmapShaderMethods[] = {
Leon Scroggins III71fae622019-03-26 16:28:41 -0400259 { "nativeCreate", "(JJII)J", (void*)BitmapShader_constructor },
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800260};
261
Daniel Micay76f6a862015-09-19 17:31:01 -0400262static const JNINativeMethod gLinearGradientMethods[] = {
Leon Scroggins IIIb0aecc22019-01-18 11:09:59 -0500263 { "nativeCreate", "(JFFFF[J[FIJ)J", (void*)LinearGradient_create },
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800264};
265
Daniel Micay76f6a862015-09-19 17:31:01 -0400266static const JNINativeMethod gRadialGradientMethods[] = {
Leon Scroggins IIIb0aecc22019-01-18 11:09:59 -0500267 { "nativeCreate", "(JFFF[J[FIJ)J", (void*)RadialGradient_create },
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800268};
269
Daniel Micay76f6a862015-09-19 17:31:01 -0400270static const JNINativeMethod gSweepGradientMethods[] = {
Leon Scroggins IIIb0aecc22019-01-18 11:09:59 -0500271 { "nativeCreate", "(JFF[J[FJ)J", (void*)SweepGradient_create },
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800272};
273
Daniel Micay76f6a862015-09-19 17:31:01 -0400274static const JNINativeMethod gComposeShaderMethods[] = {
Chris Craikb581e672017-03-07 15:27:36 -0800275 { "nativeCreate", "(JJJI)J", (void*)ComposeShader_create },
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800276};
277
Stan Iliev6867fc82019-11-22 18:00:01 -0500278static const JNINativeMethod gRuntimeShaderMethods[] = {
279 { "nativeGetFinalizer", "()J", (void*)RuntimeShader_getNativeFinalizer },
Brian Osmanbc44fa02020-01-03 15:28:06 -0500280 { "nativeCreate", "(JJ[BJZ)J", (void*)RuntimeShader_create },
281 { "nativeCreateShaderFactory", "(Ljava/lang/String;)J",
Stan Iliev6867fc82019-11-22 18:00:01 -0500282 (void*)RuntimeShader_createShaderFactory },
283};
284
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800285int register_android_graphics_Shader(JNIEnv* env)
286{
Andreas Gampeed6b9df2014-11-20 22:02:20 -0800287 android::RegisterMethodsOrDie(env, "android/graphics/Color", gColorMethods,
288 NELEM(gColorMethods));
289 android::RegisterMethodsOrDie(env, "android/graphics/Shader", gShaderMethods,
290 NELEM(gShaderMethods));
291 android::RegisterMethodsOrDie(env, "android/graphics/BitmapShader", gBitmapShaderMethods,
292 NELEM(gBitmapShaderMethods));
293 android::RegisterMethodsOrDie(env, "android/graphics/LinearGradient", gLinearGradientMethods,
294 NELEM(gLinearGradientMethods));
295 android::RegisterMethodsOrDie(env, "android/graphics/RadialGradient", gRadialGradientMethods,
296 NELEM(gRadialGradientMethods));
297 android::RegisterMethodsOrDie(env, "android/graphics/SweepGradient", gSweepGradientMethods,
298 NELEM(gSweepGradientMethods));
299 android::RegisterMethodsOrDie(env, "android/graphics/ComposeShader", gComposeShaderMethods,
300 NELEM(gComposeShaderMethods));
Stan Iliev6867fc82019-11-22 18:00:01 -0500301 android::RegisterMethodsOrDie(env, "android/graphics/RuntimeShader", gRuntimeShaderMethods,
302 NELEM(gRuntimeShaderMethods));
Elliott Hughes4cb17532011-04-12 16:10:26 -0700303
Andreas Gampeed6b9df2014-11-20 22:02:20 -0800304 return 0;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800305}