• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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