blob: bd28fe027a0b5fd04d9ff86735587a452ca0c0ba [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"
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008
Ben Wagner60126ef2015-08-07 12:13:48 -04009#include <jni.h>
Andreas Gampeed6b9df2014-11-20 22:02:20 -080010
Leon Scroggins IIIb0aecc22019-01-18 11:09:59 -050011#include <vector>
12
Romain Guy06f96e22010-07-30 19:18:16 -070013using namespace android::uirenderer;
14
Derek Sollenberger669b15a2017-03-31 12:09:24 -040015/**
16 * By default Skia gradients will interpolate their colors in unpremul space
17 * and then premultiply each of the results. We must set this flag to preserve
18 * backwards compatiblity by premultiplying the colors of the gradient first,
19 * and then interpolating between them.
20 */
21static const uint32_t sGradientShaderFlags = SkGradientShader::kInterpolateColorsInPremul_Flag;
22
Leon Scroggins IIIb0aecc22019-01-18 11:09:59 -050023#define ThrowIAE_IfNull(env, ptr) \
24 if (nullptr == ptr) { \
25 doThrowIAE(env); \
26 return 0; \
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080027 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080028
Ashok Bhat36bef0b2014-01-20 20:08:01 +000029static void Color_RGBToHSV(JNIEnv* env, jobject, jint red, jint green, jint blue, jfloatArray hsvArray)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080030{
31 SkScalar hsv[3];
32 SkRGBToHSV(red, green, blue, hsv);
33
34 AutoJavaFloatArray autoHSV(env, hsvArray, 3);
35 float* values = autoHSV.ptr();
36 for (int i = 0; i < 3; i++) {
37 values[i] = SkScalarToFloat(hsv[i]);
38 }
39}
Elliott Hughes4cb17532011-04-12 16:10:26 -070040
Ashok Bhat36bef0b2014-01-20 20:08:01 +000041static jint Color_HSVToColor(JNIEnv* env, jobject, jint alpha, jfloatArray hsvArray)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080042{
43 AutoJavaFloatArray autoHSV(env, hsvArray, 3);
Leon Scroggins III2e0103e2014-04-04 17:05:24 -040044#ifdef SK_SCALAR_IS_FLOAT
45 SkScalar* hsv = autoHSV.ptr();
46#else
47 #error Need to convert float array to SkScalar array before calling the following function.
48#endif
Elliott Hughes4cb17532011-04-12 16:10:26 -070049
Ashok Bhat36bef0b2014-01-20 20:08:01 +000050 return static_cast<jint>(SkHSVToColor(alpha, hsv));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080051}
52
53///////////////////////////////////////////////////////////////////////////////////////////////
54
John Reck8bde0be2017-05-19 10:55:20 -070055static void Shader_safeUnref(SkShader* shader) {
Derek Sollenberger6062c592011-02-22 13:55:04 -050056 SkSafeUnref(shader);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080057}
58
John Reck8bde0be2017-05-19 10:55:20 -070059static jlong Shader_getNativeFinalizer(JNIEnv*, jobject) {
60 return static_cast<jlong>(reinterpret_cast<uintptr_t>(&Shader_safeUnref));
61}
62
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080063///////////////////////////////////////////////////////////////////////////////////////////////
64
Leon Scroggins III71fae622019-03-26 16:28:41 -040065static jlong BitmapShader_constructor(JNIEnv* env, jobject o, jlong matrixPtr, jlong bitmapHandle,
Chris Craikb581e672017-03-07 15:27:36 -080066 jint tileModeX, jint tileModeY) {
67 const SkMatrix* matrix = reinterpret_cast<const SkMatrix*>(matrixPtr);
Stan Iliev7bc3bc62017-05-24 13:28:36 -040068 sk_sp<SkImage> image;
Leon Scroggins III71fae622019-03-26 16:28:41 -040069 if (bitmapHandle) {
Chris Craikb786bbd2015-06-10 16:58:42 -070070 // Only pass a valid SkBitmap object to the constructor if the Bitmap exists. Otherwise,
71 // we'll pass an empty SkBitmap to avoid crashing/excepting for compatibility.
Leon Scroggins III71fae622019-03-26 16:28:41 -040072 image = android::bitmap::toBitmap(bitmapHandle).makeImage();
Chris Craikb786bbd2015-06-10 16:58:42 -070073 }
Romain Guy06f96e22010-07-30 19:18:16 -070074
Stan Iliev7bc3bc62017-05-24 13:28:36 -040075 if (!image.get()) {
76 SkBitmap bitmap;
77 image = SkMakeImageFromRasterBitmap(bitmap, kNever_SkCopyPixelsMode);
78 }
Derek Sollenbergerfb0c8fc2017-07-26 13:53:27 -040079 sk_sp<SkShader> shader = image->makeShader(
Mike Reed1c2f5fc2019-04-10 16:57:52 -040080 (SkTileMode)tileModeX, (SkTileMode)tileModeY);
Leon Scroggins IIIb0aecc22019-01-18 11:09:59 -050081 ThrowIAE_IfNull(env, shader.get());
Derek Sollenberger450756a2016-11-07 15:55:47 -050082
ztenghuib244fb52017-04-04 17:33:40 -070083 if (matrix) {
Derek Sollenbergerfb0c8fc2017-07-26 13:53:27 -040084 shader = shader->makeWithLocalMatrix(*matrix);
85 }
ztenghuib244fb52017-04-04 17:33:40 -070086
Derek Sollenbergerfb0c8fc2017-07-26 13:53:27 -040087 return reinterpret_cast<jlong>(shader.release());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080088}
Romain Guy06f96e22010-07-30 19:18:16 -070089
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080090///////////////////////////////////////////////////////////////////////////////////////////////
91
Leon Scroggins IIIb0aecc22019-01-18 11:09:59 -050092static std::vector<SkColor4f> convertColorLongs(JNIEnv* env, jlongArray colorArray) {
93 const size_t count = env->GetArrayLength(colorArray);
94 const jlong* colorValues = env->GetLongArrayElements(colorArray, nullptr);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080095
Leon Scroggins IIIb0aecc22019-01-18 11:09:59 -050096 std::vector<SkColor4f> colors(count);
97 for (size_t i = 0; i < count; ++i) {
98 colors[i] = GraphicsJNI::convertColorLong(colorValues[i]);
ztenghuib244fb52017-04-04 17:33:40 -070099 }
Romain Guy06f96e22010-07-30 19:18:16 -0700100
Leon Scroggins IIIb0aecc22019-01-18 11:09:59 -0500101 env->ReleaseLongArrayElements(colorArray, const_cast<jlong*>(colorValues), JNI_ABORT);
102 return colors;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800103}
104
105///////////////////////////////////////////////////////////////////////////////////////////////
106
Leon Scroggins IIIb0aecc22019-01-18 11:09:59 -0500107static jlong LinearGradient_create(JNIEnv* env, jobject, jlong matrixPtr,
108 jfloat x0, jfloat y0, jfloat x1, jfloat y1, jlongArray colorArray,
Leon Scroggins III2befe1d2019-01-31 13:19:26 -0500109 jfloatArray posArray, jint tileMode, jlong colorSpaceHandle) {
Leon Scroggins IIIb0aecc22019-01-18 11:09:59 -0500110 SkPoint pts[2];
111 pts[0].set(x0, y0);
112 pts[1].set(x1, y1);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800113
Leon Scroggins IIIb0aecc22019-01-18 11:09:59 -0500114 std::vector<SkColor4f> colors = convertColorLongs(env, colorArray);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800115
Leon Scroggins IIIb0aecc22019-01-18 11:09:59 -0500116 AutoJavaFloatArray autoPos(env, posArray, colors.size());
Leon Scroggins III2e0103e2014-04-04 17:05:24 -0400117#ifdef SK_SCALAR_IS_FLOAT
118 SkScalar* pos = autoPos.ptr();
119#else
120 #error Need to convert float array to SkScalar array before calling the following function.
121#endif
Elliott Hughes4cb17532011-04-12 16:10:26 -0700122
Leon Scroggins IIIb0aecc22019-01-18 11:09:59 -0500123 sk_sp<SkShader> shader(SkGradientShader::MakeLinear(pts, &colors[0],
124 GraphicsJNI::getNativeColorSpace(colorSpaceHandle), pos, colors.size(),
Mike Reed1c2f5fc2019-04-10 16:57:52 -0400125 static_cast<SkTileMode>(tileMode), sGradientShaderFlags, nullptr));
Leon Scroggins IIIb0aecc22019-01-18 11:09:59 -0500126 ThrowIAE_IfNull(env, shader);
ztenghuib244fb52017-04-04 17:33:40 -0700127
Leon Scroggins IIIb0aecc22019-01-18 11:09:59 -0500128 const SkMatrix* matrix = reinterpret_cast<const SkMatrix*>(matrixPtr);
ztenghuib244fb52017-04-04 17:33:40 -0700129 if (matrix) {
Leon Scroggins IIIb0aecc22019-01-18 11:09:59 -0500130 shader = shader->makeWithLocalMatrix(*matrix);
ztenghuib244fb52017-04-04 17:33:40 -0700131 }
132
Leon Scroggins IIIb0aecc22019-01-18 11:09:59 -0500133 return reinterpret_cast<jlong>(shader.release());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800134}
135
Leon Scroggins IIIb0aecc22019-01-18 11:09:59 -0500136///////////////////////////////////////////////////////////////////////////////////////////////
137
138static jlong RadialGradient_create(JNIEnv* env, jobject, jlong matrixPtr, jfloat x, jfloat y,
139 jfloat radius, jlongArray colorArray, jfloatArray posArray, jint tileMode,
140 jlong colorSpaceHandle) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800141 SkPoint center;
Leon Scroggins III2e0103e2014-04-04 17:05:24 -0400142 center.set(x, y);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800143
Leon Scroggins IIIb0aecc22019-01-18 11:09:59 -0500144 std::vector<SkColor4f> colors = convertColorLongs(env, colorArray);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800145
Leon Scroggins IIIb0aecc22019-01-18 11:09:59 -0500146 AutoJavaFloatArray autoPos(env, posArray, colors.size());
147#ifdef SK_SCALAR_IS_FLOAT
148 SkScalar* pos = autoPos.ptr();
149#else
150 #error Need to convert float array to SkScalar array before calling the following function.
151#endif
ztenghuib244fb52017-04-04 17:33:40 -0700152
Leon Scroggins IIIb0aecc22019-01-18 11:09:59 -0500153 sk_sp<SkShader> shader = SkGradientShader::MakeRadial(center, radius, &colors[0],
154 GraphicsJNI::getNativeColorSpace(colorSpaceHandle), pos, colors.size(),
Mike Reed1c2f5fc2019-04-10 16:57:52 -0400155 static_cast<SkTileMode>(tileMode), sGradientShaderFlags, nullptr);
ztenghuib244fb52017-04-04 17:33:40 -0700156 ThrowIAE_IfNull(env, shader);
Leon Scroggins IIIb0aecc22019-01-18 11:09:59 -0500157
158 const SkMatrix* matrix = reinterpret_cast<const SkMatrix*>(matrixPtr);
159 if (matrix) {
160 shader = shader->makeWithLocalMatrix(*matrix);
161 }
162
163 return reinterpret_cast<jlong>(shader.release());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800164}
165
166///////////////////////////////////////////////////////////////////////////////
167
Leon Scroggins IIIb0aecc22019-01-18 11:09:59 -0500168static jlong SweepGradient_create(JNIEnv* env, jobject, jlong matrixPtr, jfloat x, jfloat y,
169 jlongArray colorArray, jfloatArray jpositions, jlong colorSpaceHandle) {
170 std::vector<SkColor4f> colors = convertColorLongs(env, colorArray);
Elliott Hughes4cb17532011-04-12 16:10:26 -0700171
Leon Scroggins IIIb0aecc22019-01-18 11:09:59 -0500172 AutoJavaFloatArray autoPos(env, jpositions, colors.size());
Leon Scroggins III2e0103e2014-04-04 17:05:24 -0400173#ifdef SK_SCALAR_IS_FLOAT
174 SkScalar* pos = autoPos.ptr();
175#else
176 #error Need to convert float array to SkScalar array before calling the following function.
177#endif
Elliott Hughes4cb17532011-04-12 16:10:26 -0700178
Leon Scroggins IIIb0aecc22019-01-18 11:09:59 -0500179 sk_sp<SkShader> shader = SkGradientShader::MakeSweep(x, y, &colors[0],
180 GraphicsJNI::getNativeColorSpace(colorSpaceHandle), pos, colors.size(),
181 sGradientShaderFlags, nullptr);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800182 ThrowIAE_IfNull(env, shader);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800183
Chris Craikb581e672017-03-07 15:27:36 -0800184 const SkMatrix* matrix = reinterpret_cast<const SkMatrix*>(matrixPtr);
ztenghuib244fb52017-04-04 17:33:40 -0700185 if (matrix) {
Leon Scroggins IIIb0aecc22019-01-18 11:09:59 -0500186 shader = shader->makeWithLocalMatrix(*matrix);
ztenghuib244fb52017-04-04 17:33:40 -0700187 }
Leon Scroggins IIIb0aecc22019-01-18 11:09:59 -0500188
189 return reinterpret_cast<jlong>(shader.release());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800190}
191
192///////////////////////////////////////////////////////////////////////////////////////////////
193
Chris Craikb581e672017-03-07 15:27:36 -0800194static jlong ComposeShader_create(JNIEnv* env, jobject o, jlong matrixPtr,
195 jlong shaderAHandle, jlong shaderBHandle, jint xfermodeHandle) {
196 const SkMatrix* matrix = reinterpret_cast<const SkMatrix*>(matrixPtr);
Ashok Bhat36bef0b2014-01-20 20:08:01 +0000197 SkShader* shaderA = reinterpret_cast<SkShader *>(shaderAHandle);
198 SkShader* shaderB = reinterpret_cast<SkShader *>(shaderBHandle);
Mike Reed260ab722016-10-07 15:59:20 -0400199 SkBlendMode mode = static_cast<SkBlendMode>(xfermodeHandle);
Mike Reed1c2f5fc2019-04-10 16:57:52 -0400200 sk_sp<SkShader> baseShader(SkShaders::Blend(mode,
201 sk_ref_sp(shaderA), sk_ref_sp(shaderB)));
Chris Craikb581e672017-03-07 15:27:36 -0800202
203 SkShader* shader;
204
205 if (matrix) {
206 shader = baseShader->makeWithLocalMatrix(*matrix).release();
207 } else {
208 shader = baseShader.release();
209 }
Ashok Bhat36bef0b2014-01-20 20:08:01 +0000210 return reinterpret_cast<jlong>(shader);
Romain Guy06f96e22010-07-30 19:18:16 -0700211}
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800212
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800213///////////////////////////////////////////////////////////////////////////////////////////////
214
Daniel Micay76f6a862015-09-19 17:31:01 -0400215static const JNINativeMethod gColorMethods[] = {
Chris Craikb581e672017-03-07 15:27:36 -0800216 { "nativeRGBToHSV", "(III[F)V", (void*)Color_RGBToHSV },
217 { "nativeHSVToColor", "(I[F)I", (void*)Color_HSVToColor }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800218};
219
Daniel Micay76f6a862015-09-19 17:31:01 -0400220static const JNINativeMethod gShaderMethods[] = {
John Reck8bde0be2017-05-19 10:55:20 -0700221 { "nativeGetFinalizer", "()J", (void*)Shader_getNativeFinalizer },
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800222};
223
Daniel Micay76f6a862015-09-19 17:31:01 -0400224static const JNINativeMethod gBitmapShaderMethods[] = {
Leon Scroggins III71fae622019-03-26 16:28:41 -0400225 { "nativeCreate", "(JJII)J", (void*)BitmapShader_constructor },
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800226};
227
Daniel Micay76f6a862015-09-19 17:31:01 -0400228static const JNINativeMethod gLinearGradientMethods[] = {
Leon Scroggins IIIb0aecc22019-01-18 11:09:59 -0500229 { "nativeCreate", "(JFFFF[J[FIJ)J", (void*)LinearGradient_create },
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800230};
231
Daniel Micay76f6a862015-09-19 17:31:01 -0400232static const JNINativeMethod gRadialGradientMethods[] = {
Leon Scroggins IIIb0aecc22019-01-18 11:09:59 -0500233 { "nativeCreate", "(JFFF[J[FIJ)J", (void*)RadialGradient_create },
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800234};
235
Daniel Micay76f6a862015-09-19 17:31:01 -0400236static const JNINativeMethod gSweepGradientMethods[] = {
Leon Scroggins IIIb0aecc22019-01-18 11:09:59 -0500237 { "nativeCreate", "(JFF[J[FJ)J", (void*)SweepGradient_create },
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800238};
239
Daniel Micay76f6a862015-09-19 17:31:01 -0400240static const JNINativeMethod gComposeShaderMethods[] = {
Chris Craikb581e672017-03-07 15:27:36 -0800241 { "nativeCreate", "(JJJI)J", (void*)ComposeShader_create },
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800242};
243
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800244int register_android_graphics_Shader(JNIEnv* env)
245{
Andreas Gampeed6b9df2014-11-20 22:02:20 -0800246 android::RegisterMethodsOrDie(env, "android/graphics/Color", gColorMethods,
247 NELEM(gColorMethods));
248 android::RegisterMethodsOrDie(env, "android/graphics/Shader", gShaderMethods,
249 NELEM(gShaderMethods));
250 android::RegisterMethodsOrDie(env, "android/graphics/BitmapShader", gBitmapShaderMethods,
251 NELEM(gBitmapShaderMethods));
252 android::RegisterMethodsOrDie(env, "android/graphics/LinearGradient", gLinearGradientMethods,
253 NELEM(gLinearGradientMethods));
254 android::RegisterMethodsOrDie(env, "android/graphics/RadialGradient", gRadialGradientMethods,
255 NELEM(gRadialGradientMethods));
256 android::RegisterMethodsOrDie(env, "android/graphics/SweepGradient", gSweepGradientMethods,
257 NELEM(gSweepGradientMethods));
258 android::RegisterMethodsOrDie(env, "android/graphics/ComposeShader", gComposeShaderMethods,
259 NELEM(gComposeShaderMethods));
Elliott Hughes4cb17532011-04-12 16:10:26 -0700260
Andreas Gampeed6b9df2014-11-20 22:02:20 -0800261 return 0;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800262}