1 #include "GraphicsJNI.h"
2 #include "SkColorFilter.h"
3 #include "SkGradientShader.h"
4 #include "SkImagePriv.h"
5 #include "SkShader.h"
6 #include "SkBlendMode.h"
7 #include "include/effects/SkRuntimeEffect.h"
8
9 #include <vector>
10
11 using namespace android::uirenderer;
12
13 /**
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 */
19 static const uint32_t sGradientShaderFlags = SkGradientShader::kInterpolateColorsInPremul_Flag;
20
21 #define ThrowIAE_IfNull(env, ptr) \
22 if (nullptr == ptr) { \
23 doThrowIAE(env); \
24 return 0; \
25 }
26
Color_RGBToHSV(JNIEnv * env,jobject,jint red,jint green,jint blue,jfloatArray hsvArray)27 static void Color_RGBToHSV(JNIEnv* env, jobject, jint red, jint green, jint blue, jfloatArray hsvArray)
28 {
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 }
38
Color_HSVToColor(JNIEnv * env,jobject,jint alpha,jfloatArray hsvArray)39 static jint Color_HSVToColor(JNIEnv* env, jobject, jint alpha, jfloatArray hsvArray)
40 {
41 AutoJavaFloatArray autoHSV(env, hsvArray, 3);
42 #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
47
48 return static_cast<jint>(SkHSVToColor(alpha, hsv));
49 }
50
51 ///////////////////////////////////////////////////////////////////////////////////////////////
52
Shader_safeUnref(SkShader * shader)53 static void Shader_safeUnref(SkShader* shader) {
54 SkSafeUnref(shader);
55 }
56
Shader_getNativeFinalizer(JNIEnv *,jobject)57 static jlong Shader_getNativeFinalizer(JNIEnv*, jobject) {
58 return static_cast<jlong>(reinterpret_cast<uintptr_t>(&Shader_safeUnref));
59 }
60
61 ///////////////////////////////////////////////////////////////////////////////////////////////
62
BitmapShader_constructor(JNIEnv * env,jobject o,jlong matrixPtr,jlong bitmapHandle,jint tileModeX,jint tileModeY)63 static jlong BitmapShader_constructor(JNIEnv* env, jobject o, jlong matrixPtr, jlong bitmapHandle,
64 jint tileModeX, jint tileModeY) {
65 const SkMatrix* matrix = reinterpret_cast<const SkMatrix*>(matrixPtr);
66 sk_sp<SkImage> image;
67 if (bitmapHandle) {
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.
70 image = android::bitmap::toBitmap(bitmapHandle).makeImage();
71 }
72
73 if (!image.get()) {
74 SkBitmap bitmap;
75 image = SkMakeImageFromRasterBitmap(bitmap, kNever_SkCopyPixelsMode);
76 }
77 sk_sp<SkShader> shader = image->makeShader(
78 (SkTileMode)tileModeX, (SkTileMode)tileModeY);
79 ThrowIAE_IfNull(env, shader.get());
80
81 if (matrix) {
82 shader = shader->makeWithLocalMatrix(*matrix);
83 }
84
85 return reinterpret_cast<jlong>(shader.release());
86 }
87
88 ///////////////////////////////////////////////////////////////////////////////////////////////
89
convertColorLongs(JNIEnv * env,jlongArray colorArray)90 static std::vector<SkColor4f> convertColorLongs(JNIEnv* env, jlongArray colorArray) {
91 const size_t count = env->GetArrayLength(colorArray);
92 const jlong* colorValues = env->GetLongArrayElements(colorArray, nullptr);
93
94 std::vector<SkColor4f> colors(count);
95 for (size_t i = 0; i < count; ++i) {
96 colors[i] = GraphicsJNI::convertColorLong(colorValues[i]);
97 }
98
99 env->ReleaseLongArrayElements(colorArray, const_cast<jlong*>(colorValues), JNI_ABORT);
100 return colors;
101 }
102
103 ///////////////////////////////////////////////////////////////////////////////////////////////
104
LinearGradient_create(JNIEnv * env,jobject,jlong matrixPtr,jfloat x0,jfloat y0,jfloat x1,jfloat y1,jlongArray colorArray,jfloatArray posArray,jint tileMode,jlong colorSpaceHandle)105 static jlong LinearGradient_create(JNIEnv* env, jobject, jlong matrixPtr,
106 jfloat x0, jfloat y0, jfloat x1, jfloat y1, jlongArray colorArray,
107 jfloatArray posArray, jint tileMode, jlong colorSpaceHandle) {
108 SkPoint pts[2];
109 pts[0].set(x0, y0);
110 pts[1].set(x1, y1);
111
112 std::vector<SkColor4f> colors = convertColorLongs(env, colorArray);
113
114 AutoJavaFloatArray autoPos(env, posArray, colors.size());
115 #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
120
121 sk_sp<SkShader> shader(SkGradientShader::MakeLinear(pts, &colors[0],
122 GraphicsJNI::getNativeColorSpace(colorSpaceHandle), pos, colors.size(),
123 static_cast<SkTileMode>(tileMode), sGradientShaderFlags, nullptr));
124 ThrowIAE_IfNull(env, shader);
125
126 const SkMatrix* matrix = reinterpret_cast<const SkMatrix*>(matrixPtr);
127 if (matrix) {
128 shader = shader->makeWithLocalMatrix(*matrix);
129 }
130
131 return reinterpret_cast<jlong>(shader.release());
132 }
133
134 ///////////////////////////////////////////////////////////////////////////////////////////////
135
RadialGradient_create(JNIEnv * env,jobject,jlong matrixPtr,jfloat x,jfloat y,jfloat radius,jlongArray colorArray,jfloatArray posArray,jint tileMode,jlong colorSpaceHandle)136 static jlong RadialGradient_create(JNIEnv* env, jobject, jlong matrixPtr, jfloat x, jfloat y,
137 jfloat radius, jlongArray colorArray, jfloatArray posArray, jint tileMode,
138 jlong colorSpaceHandle) {
139 SkPoint center;
140 center.set(x, y);
141
142 std::vector<SkColor4f> colors = convertColorLongs(env, colorArray);
143
144 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
150
151 sk_sp<SkShader> shader = SkGradientShader::MakeRadial(center, radius, &colors[0],
152 GraphicsJNI::getNativeColorSpace(colorSpaceHandle), pos, colors.size(),
153 static_cast<SkTileMode>(tileMode), sGradientShaderFlags, nullptr);
154 ThrowIAE_IfNull(env, shader);
155
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());
162 }
163
164 ///////////////////////////////////////////////////////////////////////////////
165
SweepGradient_create(JNIEnv * env,jobject,jlong matrixPtr,jfloat x,jfloat y,jlongArray colorArray,jfloatArray jpositions,jlong colorSpaceHandle)166 static 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);
169
170 AutoJavaFloatArray autoPos(env, jpositions, colors.size());
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
176
177 sk_sp<SkShader> shader = SkGradientShader::MakeSweep(x, y, &colors[0],
178 GraphicsJNI::getNativeColorSpace(colorSpaceHandle), pos, colors.size(),
179 sGradientShaderFlags, nullptr);
180 ThrowIAE_IfNull(env, shader);
181
182 const SkMatrix* matrix = reinterpret_cast<const SkMatrix*>(matrixPtr);
183 if (matrix) {
184 shader = shader->makeWithLocalMatrix(*matrix);
185 }
186
187 return reinterpret_cast<jlong>(shader.release());
188 }
189
190 ///////////////////////////////////////////////////////////////////////////////////////////////
191
ComposeShader_create(JNIEnv * env,jobject o,jlong matrixPtr,jlong shaderAHandle,jlong shaderBHandle,jint xfermodeHandle)192 static 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);
195 SkShader* shaderA = reinterpret_cast<SkShader *>(shaderAHandle);
196 SkShader* shaderB = reinterpret_cast<SkShader *>(shaderBHandle);
197 SkBlendMode mode = static_cast<SkBlendMode>(xfermodeHandle);
198 sk_sp<SkShader> baseShader(SkShaders::Blend(mode,
199 sk_ref_sp(shaderA), sk_ref_sp(shaderB)));
200
201 SkShader* shader;
202
203 if (matrix) {
204 shader = baseShader->makeWithLocalMatrix(*matrix).release();
205 } else {
206 shader = baseShader.release();
207 }
208 return reinterpret_cast<jlong>(shader);
209 }
210
211 ///////////////////////////////////////////////////////////////////////////////////////////////
212
RuntimeShader_create(JNIEnv * env,jobject,jlong shaderFactory,jlong matrixPtr,jbyteArray inputs,jlong colorSpaceHandle,jboolean isOpaque)213 static jlong RuntimeShader_create(JNIEnv* env, jobject, jlong shaderFactory, jlong matrixPtr,
214 jbyteArray inputs, jlong colorSpaceHandle, jboolean isOpaque) {
215 SkRuntimeEffect* effect = reinterpret_cast<SkRuntimeEffect*>(shaderFactory);
216 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);
221 sk_sp<SkShader> shader = effect->makeShader(fData, nullptr, 0, matrix, isOpaque == JNI_TRUE);
222 ThrowIAE_IfNull(env, shader);
223
224 return reinterpret_cast<jlong>(shader.release());
225 }
226
227 ///////////////////////////////////////////////////////////////////////////////////////////////
228
RuntimeShader_createShaderFactory(JNIEnv * env,jobject,jstring sksl)229 static jlong RuntimeShader_createShaderFactory(JNIEnv* env, jobject, jstring sksl) {
230 ScopedUtfChars strSksl(env, sksl);
231 sk_sp<SkRuntimeEffect> effect = std::get<0>(SkRuntimeEffect::Make(SkString(strSksl.c_str())));
232 ThrowIAE_IfNull(env, effect);
233
234 return reinterpret_cast<jlong>(effect.release());
235 }
236
237 ///////////////////////////////////////////////////////////////////////////////////////////////
238
Effect_safeUnref(SkRuntimeEffect * effect)239 static void Effect_safeUnref(SkRuntimeEffect* effect) {
240 SkSafeUnref(effect);
241 }
242
RuntimeShader_getNativeFinalizer(JNIEnv *,jobject)243 static jlong RuntimeShader_getNativeFinalizer(JNIEnv*, jobject) {
244 return static_cast<jlong>(reinterpret_cast<uintptr_t>(&Effect_safeUnref));
245 }
246
247 ///////////////////////////////////////////////////////////////////////////////////////////////
248
249 static const JNINativeMethod gColorMethods[] = {
250 { "nativeRGBToHSV", "(III[F)V", (void*)Color_RGBToHSV },
251 { "nativeHSVToColor", "(I[F)I", (void*)Color_HSVToColor }
252 };
253
254 static const JNINativeMethod gShaderMethods[] = {
255 { "nativeGetFinalizer", "()J", (void*)Shader_getNativeFinalizer },
256 };
257
258 static const JNINativeMethod gBitmapShaderMethods[] = {
259 { "nativeCreate", "(JJII)J", (void*)BitmapShader_constructor },
260 };
261
262 static const JNINativeMethod gLinearGradientMethods[] = {
263 { "nativeCreate", "(JFFFF[J[FIJ)J", (void*)LinearGradient_create },
264 };
265
266 static const JNINativeMethod gRadialGradientMethods[] = {
267 { "nativeCreate", "(JFFF[J[FIJ)J", (void*)RadialGradient_create },
268 };
269
270 static const JNINativeMethod gSweepGradientMethods[] = {
271 { "nativeCreate", "(JFF[J[FJ)J", (void*)SweepGradient_create },
272 };
273
274 static const JNINativeMethod gComposeShaderMethods[] = {
275 { "nativeCreate", "(JJJI)J", (void*)ComposeShader_create },
276 };
277
278 static const JNINativeMethod gRuntimeShaderMethods[] = {
279 { "nativeGetFinalizer", "()J", (void*)RuntimeShader_getNativeFinalizer },
280 { "nativeCreate", "(JJ[BJZ)J", (void*)RuntimeShader_create },
281 { "nativeCreateShaderFactory", "(Ljava/lang/String;)J",
282 (void*)RuntimeShader_createShaderFactory },
283 };
284
register_android_graphics_Shader(JNIEnv * env)285 int register_android_graphics_Shader(JNIEnv* env)
286 {
287 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));
301 android::RegisterMethodsOrDie(env, "android/graphics/RuntimeShader", gRuntimeShaderMethods,
302 NELEM(gRuntimeShaderMethods));
303
304 return 0;
305 }
306