1 #include "GraphicsJNI.h"
2 #include "SkGradientShader.h"
3 #include "SkImagePriv.h"
4 #include "SkShader.h"
5 #include "SkBlendMode.h"
6 #include "core_jni_helpers.h"
7
8 #include <Caches.h>
9 #include <jni.h>
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
ThrowIAE_IfNull(JNIEnv * env,void * ptr)21 static void ThrowIAE_IfNull(JNIEnv* env, void* ptr) {
22 if (NULL == ptr) {
23 doThrowIAE(env);
24 }
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,jobject jbitmap,jint tileModeX,jint tileModeY)63 static 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);
66 SkBitmap bitmap;
67 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.
70 android::bitmap::toBitmap(env, jbitmap).getSkBitmapForShaders(&bitmap);
71 }
72
73 sk_sp<SkImage> image = SkMakeImageFromRasterBitmap(bitmap, kNever_SkCopyPixelsMode);
74 sk_sp<SkShader> baseShader = image->makeShader(
75 (SkShader::TileMode)tileModeX, (SkShader::TileMode)tileModeY);
76
77 SkShader* shader;
78 if (matrix) {
79 shader = baseShader->makeWithLocalMatrix(*matrix).release();
80 } else {
81 shader = baseShader.release();
82 }
83
84 ThrowIAE_IfNull(env, shader);
85 return reinterpret_cast<jlong>(shader);
86 }
87
88 ///////////////////////////////////////////////////////////////////////////////////////////////
89
LinearGradient_create1(JNIEnv * env,jobject o,jlong matrixPtr,jfloat x0,jfloat y0,jfloat x1,jfloat y1,jintArray colorArray,jfloatArray posArray,jint tileMode)90 static jlong LinearGradient_create1(JNIEnv* env, jobject o, jlong matrixPtr,
91 jfloat x0, jfloat y0, jfloat x1, jfloat y1,
92 jintArray colorArray, jfloatArray posArray, jint tileMode) {
93 const SkMatrix* matrix = reinterpret_cast<const SkMatrix*>(matrixPtr);
94 SkPoint pts[2];
95 pts[0].set(x0, y0);
96 pts[1].set(x1, y1);
97
98 size_t count = env->GetArrayLength(colorArray);
99 const jint* colorValues = env->GetIntArrayElements(colorArray, NULL);
100
101 AutoJavaFloatArray autoPos(env, posArray, count);
102 #ifdef SK_SCALAR_IS_FLOAT
103 SkScalar* pos = autoPos.ptr();
104 #else
105 #error Need to convert float array to SkScalar array before calling the following function.
106 #endif
107
108 sk_sp<SkShader> baseShader(SkGradientShader::MakeLinear(pts,
109 reinterpret_cast<const SkColor*>(colorValues), pos, count,
110 static_cast<SkShader::TileMode>(tileMode), sGradientShaderFlags, NULL));
111
112 SkShader* shader;
113 if (matrix) {
114 shader = baseShader->makeWithLocalMatrix(*matrix).release();
115 } else {
116 shader = baseShader.release();
117 }
118
119 env->ReleaseIntArrayElements(colorArray, const_cast<jint*>(colorValues), JNI_ABORT);
120 ThrowIAE_IfNull(env, shader);
121 return reinterpret_cast<jlong>(shader);
122 }
123
LinearGradient_create2(JNIEnv * env,jobject o,jlong matrixPtr,jfloat x0,jfloat y0,jfloat x1,jfloat y1,jint color0,jint color1,jint tileMode)124 static jlong LinearGradient_create2(JNIEnv* env, jobject o, jlong matrixPtr,
125 jfloat x0, jfloat y0, jfloat x1, jfloat y1, jint color0, jint color1, jint tileMode) {
126 const SkMatrix* matrix = reinterpret_cast<const SkMatrix*>(matrixPtr);
127
128 SkPoint pts[2];
129 pts[0].set(x0, y0);
130 pts[1].set(x1, y1);
131
132 SkColor colors[2];
133 colors[0] = color0;
134 colors[1] = color1;
135
136 sk_sp<SkShader> baseShader(SkGradientShader::MakeLinear(pts, colors, NULL, 2,
137 static_cast<SkShader::TileMode>(tileMode), sGradientShaderFlags, NULL));
138
139 SkShader* s;
140 if (matrix) {
141 s = baseShader->makeWithLocalMatrix(*matrix).release();
142 } else {
143 s = baseShader.release();
144 }
145
146 ThrowIAE_IfNull(env, s);
147 return reinterpret_cast<jlong>(s);
148 }
149
150 ///////////////////////////////////////////////////////////////////////////////////////////////
151
RadialGradient_create1(JNIEnv * env,jobject,jlong matrixPtr,jfloat x,jfloat y,jfloat radius,jintArray colorArray,jfloatArray posArray,jint tileMode)152 static jlong RadialGradient_create1(JNIEnv* env, jobject, jlong matrixPtr, jfloat x, jfloat y,
153 jfloat radius, jintArray colorArray, jfloatArray posArray, jint tileMode) {
154 const SkMatrix* matrix = reinterpret_cast<const SkMatrix*>(matrixPtr);
155 SkPoint center;
156 center.set(x, y);
157
158 size_t count = env->GetArrayLength(colorArray);
159 const jint* colorValues = env->GetIntArrayElements(colorArray, NULL);
160
161 AutoJavaFloatArray autoPos(env, posArray, count);
162 #ifdef SK_SCALAR_IS_FLOAT
163 SkScalar* pos = autoPos.ptr();
164 #else
165 #error Need to convert float array to SkScalar array before calling the following function.
166 #endif
167
168 sk_sp<SkShader> baseShader = SkGradientShader::MakeRadial(center, radius,
169 reinterpret_cast<const SkColor*>(colorValues), pos, count,
170 static_cast<SkShader::TileMode>(tileMode), sGradientShaderFlags, NULL);
171
172 SkShader* shader;
173 if (matrix) {
174 shader = baseShader->makeWithLocalMatrix(*matrix).release();
175 } else {
176 shader = baseShader.release();
177 }
178
179 env->ReleaseIntArrayElements(colorArray, const_cast<jint*>(colorValues),
180 JNI_ABORT);
181
182 ThrowIAE_IfNull(env, shader);
183 return reinterpret_cast<jlong>(shader);
184 }
185
RadialGradient_create2(JNIEnv * env,jobject,jlong matrixPtr,jfloat x,jfloat y,jfloat radius,jint color0,jint color1,jint tileMode)186 static jlong RadialGradient_create2(JNIEnv* env, jobject, jlong matrixPtr, jfloat x, jfloat y, jfloat radius,
187 jint color0, jint color1, jint tileMode) {
188 const SkMatrix* matrix = reinterpret_cast<const SkMatrix*>(matrixPtr);
189 SkPoint center;
190 center.set(x, y);
191
192 SkColor colors[2];
193 colors[0] = color0;
194 colors[1] = color1;
195
196 sk_sp<SkShader> baseShader = SkGradientShader::MakeRadial(center, radius, colors, NULL, 2,
197 static_cast<SkShader::TileMode>(tileMode), sGradientShaderFlags, NULL);
198
199 SkShader* shader;
200 if (matrix) {
201 shader = baseShader->makeWithLocalMatrix(*matrix).release();
202 } else {
203 shader = baseShader.release();
204 }
205 ThrowIAE_IfNull(env, shader);
206 return reinterpret_cast<jlong>(shader);
207 }
208
209 ///////////////////////////////////////////////////////////////////////////////
210
SweepGradient_create1(JNIEnv * env,jobject,jlong matrixPtr,jfloat x,jfloat y,jintArray jcolors,jfloatArray jpositions)211 static jlong SweepGradient_create1(JNIEnv* env, jobject, jlong matrixPtr, jfloat x, jfloat y,
212 jintArray jcolors, jfloatArray jpositions) {
213 const SkMatrix* matrix = reinterpret_cast<const SkMatrix*>(matrixPtr);
214 size_t count = env->GetArrayLength(jcolors);
215 const jint* colors = env->GetIntArrayElements(jcolors, NULL);
216
217 AutoJavaFloatArray autoPos(env, jpositions, count);
218 #ifdef SK_SCALAR_IS_FLOAT
219 SkScalar* pos = autoPos.ptr();
220 #else
221 #error Need to convert float array to SkScalar array before calling the following function.
222 #endif
223
224 sk_sp<SkShader> baseShader = SkGradientShader::MakeSweep(x, y,
225 reinterpret_cast<const SkColor*>(colors), pos, count,
226 sGradientShaderFlags, NULL);
227
228 SkShader* shader;
229 if (matrix) {
230 shader = baseShader->makeWithLocalMatrix(*matrix).release();
231 } else {
232 shader = baseShader.release();
233 }
234
235 env->ReleaseIntArrayElements(jcolors, const_cast<jint*>(colors),
236 JNI_ABORT);
237 ThrowIAE_IfNull(env, shader);
238 return reinterpret_cast<jlong>(shader);
239 }
240
SweepGradient_create2(JNIEnv * env,jobject,jlong matrixPtr,jfloat x,jfloat y,int color0,int color1)241 static jlong SweepGradient_create2(JNIEnv* env, jobject, jlong matrixPtr, jfloat x, jfloat y,
242 int color0, int color1) {
243 const SkMatrix* matrix = reinterpret_cast<const SkMatrix*>(matrixPtr);
244 SkColor colors[2];
245 colors[0] = color0;
246 colors[1] = color1;
247
248 sk_sp<SkShader> baseShader = SkGradientShader::MakeSweep(x, y, colors,
249 NULL, 2, sGradientShaderFlags, NULL);
250
251 SkShader* shader;
252 if (matrix) {
253 shader = baseShader->makeWithLocalMatrix(*matrix).release();
254 } else {
255 shader = baseShader.release();
256 }
257 ThrowIAE_IfNull(env, shader);
258 return reinterpret_cast<jlong>(shader);
259 }
260
261 ///////////////////////////////////////////////////////////////////////////////////////////////
262
ComposeShader_create(JNIEnv * env,jobject o,jlong matrixPtr,jlong shaderAHandle,jlong shaderBHandle,jint xfermodeHandle)263 static jlong ComposeShader_create(JNIEnv* env, jobject o, jlong matrixPtr,
264 jlong shaderAHandle, jlong shaderBHandle, jint xfermodeHandle) {
265 const SkMatrix* matrix = reinterpret_cast<const SkMatrix*>(matrixPtr);
266 SkShader* shaderA = reinterpret_cast<SkShader *>(shaderAHandle);
267 SkShader* shaderB = reinterpret_cast<SkShader *>(shaderBHandle);
268 SkBlendMode mode = static_cast<SkBlendMode>(xfermodeHandle);
269 sk_sp<SkShader> baseShader(SkShader::MakeComposeShader(
270 sk_ref_sp(shaderA), sk_ref_sp(shaderB), mode));
271
272 SkShader* shader;
273
274 if (matrix) {
275 shader = baseShader->makeWithLocalMatrix(*matrix).release();
276 } else {
277 shader = baseShader.release();
278 }
279 return reinterpret_cast<jlong>(shader);
280 }
281
282 ///////////////////////////////////////////////////////////////////////////////////////////////
283
284 static const JNINativeMethod gColorMethods[] = {
285 { "nativeRGBToHSV", "(III[F)V", (void*)Color_RGBToHSV },
286 { "nativeHSVToColor", "(I[F)I", (void*)Color_HSVToColor }
287 };
288
289 static const JNINativeMethod gShaderMethods[] = {
290 { "nativeGetFinalizer", "()J", (void*)Shader_getNativeFinalizer },
291 };
292
293 static const JNINativeMethod gBitmapShaderMethods[] = {
294 { "nativeCreate", "(JLandroid/graphics/Bitmap;II)J", (void*)BitmapShader_constructor },
295 };
296
297 static const JNINativeMethod gLinearGradientMethods[] = {
298 { "nativeCreate1", "(JFFFF[I[FI)J", (void*)LinearGradient_create1 },
299 { "nativeCreate2", "(JFFFFIII)J", (void*)LinearGradient_create2 },
300 };
301
302 static const JNINativeMethod gRadialGradientMethods[] = {
303 { "nativeCreate1", "(JFFF[I[FI)J", (void*)RadialGradient_create1 },
304 { "nativeCreate2", "(JFFFIII)J", (void*)RadialGradient_create2 },
305 };
306
307 static const JNINativeMethod gSweepGradientMethods[] = {
308 { "nativeCreate1", "(JFF[I[F)J", (void*)SweepGradient_create1 },
309 { "nativeCreate2", "(JFFII)J", (void*)SweepGradient_create2 },
310 };
311
312 static const JNINativeMethod gComposeShaderMethods[] = {
313 { "nativeCreate", "(JJJI)J", (void*)ComposeShader_create },
314 };
315
register_android_graphics_Shader(JNIEnv * env)316 int register_android_graphics_Shader(JNIEnv* env)
317 {
318 android::RegisterMethodsOrDie(env, "android/graphics/Color", gColorMethods,
319 NELEM(gColorMethods));
320 android::RegisterMethodsOrDie(env, "android/graphics/Shader", gShaderMethods,
321 NELEM(gShaderMethods));
322 android::RegisterMethodsOrDie(env, "android/graphics/BitmapShader", gBitmapShaderMethods,
323 NELEM(gBitmapShaderMethods));
324 android::RegisterMethodsOrDie(env, "android/graphics/LinearGradient", gLinearGradientMethods,
325 NELEM(gLinearGradientMethods));
326 android::RegisterMethodsOrDie(env, "android/graphics/RadialGradient", gRadialGradientMethods,
327 NELEM(gRadialGradientMethods));
328 android::RegisterMethodsOrDie(env, "android/graphics/SweepGradient", gSweepGradientMethods,
329 NELEM(gSweepGradientMethods));
330 android::RegisterMethodsOrDie(env, "android/graphics/ComposeShader", gComposeShaderMethods,
331 NELEM(gComposeShaderMethods));
332
333 return 0;
334 }
335