1 #include <jni.h>
2 #include "GraphicsJNI.h"
3
4 #include "SkShader.h"
5 #include "SkGradientShader.h"
6 #include "SkComposeShader.h"
7 #include "SkTemplates.h"
8 #include "SkXfermode.h"
9
10 #include <Caches.h>
11
12 #include "core_jni_helpers.h"
13
14 using namespace android::uirenderer;
15
ThrowIAE_IfNull(JNIEnv * env,void * ptr)16 static void ThrowIAE_IfNull(JNIEnv* env, void* ptr) {
17 if (NULL == ptr) {
18 doThrowIAE(env);
19 }
20 }
21
Color_RGBToHSV(JNIEnv * env,jobject,jint red,jint green,jint blue,jfloatArray hsvArray)22 static void Color_RGBToHSV(JNIEnv* env, jobject, jint red, jint green, jint blue, jfloatArray hsvArray)
23 {
24 SkScalar hsv[3];
25 SkRGBToHSV(red, green, blue, hsv);
26
27 AutoJavaFloatArray autoHSV(env, hsvArray, 3);
28 float* values = autoHSV.ptr();
29 for (int i = 0; i < 3; i++) {
30 values[i] = SkScalarToFloat(hsv[i]);
31 }
32 }
33
Color_HSVToColor(JNIEnv * env,jobject,jint alpha,jfloatArray hsvArray)34 static jint Color_HSVToColor(JNIEnv* env, jobject, jint alpha, jfloatArray hsvArray)
35 {
36 AutoJavaFloatArray autoHSV(env, hsvArray, 3);
37 #ifdef SK_SCALAR_IS_FLOAT
38 SkScalar* hsv = autoHSV.ptr();
39 #else
40 #error Need to convert float array to SkScalar array before calling the following function.
41 #endif
42
43 return static_cast<jint>(SkHSVToColor(alpha, hsv));
44 }
45
46 ///////////////////////////////////////////////////////////////////////////////////////////////
47
Shader_destructor(JNIEnv * env,jobject o,jlong shaderHandle,jlong shaderWithLMHandle)48 static void Shader_destructor(JNIEnv* env, jobject o, jlong shaderHandle, jlong shaderWithLMHandle)
49 {
50 SkShader* shader = reinterpret_cast<SkShader*>(shaderHandle);
51 SkSafeUnref(shader);
52 }
53
Shader_setLocalMatrix(JNIEnv * env,jobject o,jlong shaderHandle,jlong matrixHandle)54 static jlong Shader_setLocalMatrix(JNIEnv* env, jobject o, jlong shaderHandle, jlong matrixHandle)
55 {
56 // ensure we have a valid matrix to use
57 const SkMatrix* matrix = reinterpret_cast<SkMatrix*>(matrixHandle);
58 if (NULL == matrix) {
59 matrix = &SkMatrix::I();
60 }
61
62 // The current shader will no longer need a direct reference owned by Shader.java
63 // as all the data needed is contained within the newly created LocalMatrixShader.
64 SkASSERT(shaderHandle);
65 SkAutoTUnref<SkShader> currentShader(reinterpret_cast<SkShader*>(shaderHandle));
66
67 SkMatrix currentMatrix;
68 SkAutoTUnref<SkShader> baseShader(currentShader->refAsALocalMatrixShader(¤tMatrix));
69 if (baseShader.get()) {
70 // if the matrices are same then there is no need to allocate a new
71 // shader that is identical to the existing one.
72 if (currentMatrix == *matrix) {
73 return reinterpret_cast<jlong>(currentShader.detach());
74 }
75 return reinterpret_cast<jlong>(SkShader::CreateLocalMatrixShader(baseShader, *matrix));
76 }
77
78 return reinterpret_cast<jlong>(SkShader::CreateLocalMatrixShader(currentShader, *matrix));
79 }
80
81 ///////////////////////////////////////////////////////////////////////////////////////////////
82
BitmapShader_constructor(JNIEnv * env,jobject o,jobject jbitmap,jint tileModeX,jint tileModeY)83 static jlong BitmapShader_constructor(JNIEnv* env, jobject o, jobject jbitmap,
84 jint tileModeX, jint tileModeY)
85 {
86 SkBitmap bitmap;
87 if (jbitmap) {
88 // Only pass a valid SkBitmap object to the constructor if the Bitmap exists. Otherwise,
89 // we'll pass an empty SkBitmap to avoid crashing/excepting for compatibility.
90 GraphicsJNI::getSkBitmap(env, jbitmap, &bitmap);
91 }
92 SkShader* s = SkShader::CreateBitmapShader(bitmap,
93 (SkShader::TileMode)tileModeX,
94 (SkShader::TileMode)tileModeY);
95
96 ThrowIAE_IfNull(env, s);
97 return reinterpret_cast<jlong>(s);
98 }
99
100 ///////////////////////////////////////////////////////////////////////////////////////////////
101
LinearGradient_create1(JNIEnv * env,jobject o,jfloat x0,jfloat y0,jfloat x1,jfloat y1,jintArray colorArray,jfloatArray posArray,jint tileMode)102 static jlong LinearGradient_create1(JNIEnv* env, jobject o,
103 jfloat x0, jfloat y0, jfloat x1, jfloat y1,
104 jintArray colorArray, jfloatArray posArray, jint tileMode)
105 {
106 SkPoint pts[2];
107 pts[0].set(x0, y0);
108 pts[1].set(x1, y1);
109
110 size_t count = env->GetArrayLength(colorArray);
111 const jint* colorValues = env->GetIntArrayElements(colorArray, NULL);
112
113 AutoJavaFloatArray autoPos(env, posArray, count);
114 #ifdef SK_SCALAR_IS_FLOAT
115 SkScalar* pos = autoPos.ptr();
116 #else
117 #error Need to convert float array to SkScalar array before calling the following function.
118 #endif
119
120 SkShader* shader = SkGradientShader::CreateLinear(pts,
121 reinterpret_cast<const SkColor*>(colorValues), pos, count,
122 static_cast<SkShader::TileMode>(tileMode));
123
124 env->ReleaseIntArrayElements(colorArray, const_cast<jint*>(colorValues), JNI_ABORT);
125 ThrowIAE_IfNull(env, shader);
126 return reinterpret_cast<jlong>(shader);
127 }
128
LinearGradient_create2(JNIEnv * env,jobject o,jfloat x0,jfloat y0,jfloat x1,jfloat y1,jint color0,jint color1,jint tileMode)129 static jlong LinearGradient_create2(JNIEnv* env, jobject o,
130 jfloat x0, jfloat y0, jfloat x1, jfloat y1,
131 jint color0, jint color1, jint tileMode)
132 {
133 SkPoint pts[2];
134 pts[0].set(x0, y0);
135 pts[1].set(x1, y1);
136
137 SkColor colors[2];
138 colors[0] = color0;
139 colors[1] = color1;
140
141 SkShader* s = SkGradientShader::CreateLinear(pts, colors, NULL, 2, (SkShader::TileMode)tileMode);
142
143 ThrowIAE_IfNull(env, s);
144 return reinterpret_cast<jlong>(s);
145 }
146
147 ///////////////////////////////////////////////////////////////////////////////////////////////
148
RadialGradient_create1(JNIEnv * env,jobject,jfloat x,jfloat y,jfloat radius,jintArray colorArray,jfloatArray posArray,jint tileMode)149 static jlong RadialGradient_create1(JNIEnv* env, jobject, jfloat x, jfloat y, jfloat radius,
150 jintArray colorArray, jfloatArray posArray, jint tileMode) {
151 SkPoint center;
152 center.set(x, y);
153
154 size_t count = env->GetArrayLength(colorArray);
155 const jint* colorValues = env->GetIntArrayElements(colorArray, NULL);
156
157 AutoJavaFloatArray autoPos(env, posArray, count);
158 #ifdef SK_SCALAR_IS_FLOAT
159 SkScalar* pos = autoPos.ptr();
160 #else
161 #error Need to convert float array to SkScalar array before calling the following function.
162 #endif
163
164 SkShader* shader = SkGradientShader::CreateRadial(center, radius,
165 reinterpret_cast<const SkColor*>(colorValues), pos, count,
166 static_cast<SkShader::TileMode>(tileMode));
167 env->ReleaseIntArrayElements(colorArray, const_cast<jint*>(colorValues),
168 JNI_ABORT);
169
170 ThrowIAE_IfNull(env, shader);
171 return reinterpret_cast<jlong>(shader);
172 }
173
RadialGradient_create2(JNIEnv * env,jobject,jfloat x,jfloat y,jfloat radius,jint color0,jint color1,jint tileMode)174 static jlong RadialGradient_create2(JNIEnv* env, jobject, jfloat x, jfloat y, jfloat radius,
175 jint color0, jint color1, jint tileMode) {
176 SkPoint center;
177 center.set(x, y);
178
179 SkColor colors[2];
180 colors[0] = color0;
181 colors[1] = color1;
182
183 SkShader* s = SkGradientShader::CreateRadial(center, radius, colors, NULL, 2,
184 (SkShader::TileMode)tileMode);
185 ThrowIAE_IfNull(env, s);
186 return reinterpret_cast<jlong>(s);
187 }
188
189 ///////////////////////////////////////////////////////////////////////////////
190
SweepGradient_create1(JNIEnv * env,jobject,jfloat x,jfloat y,jintArray jcolors,jfloatArray jpositions)191 static jlong SweepGradient_create1(JNIEnv* env, jobject, jfloat x, jfloat y,
192 jintArray jcolors, jfloatArray jpositions) {
193 size_t count = env->GetArrayLength(jcolors);
194 const jint* colors = env->GetIntArrayElements(jcolors, NULL);
195
196 AutoJavaFloatArray autoPos(env, jpositions, count);
197 #ifdef SK_SCALAR_IS_FLOAT
198 SkScalar* pos = autoPos.ptr();
199 #else
200 #error Need to convert float array to SkScalar array before calling the following function.
201 #endif
202
203 SkShader* shader = SkGradientShader::CreateSweep(x, y,
204 reinterpret_cast<const SkColor*>(colors), pos, count);
205 env->ReleaseIntArrayElements(jcolors, const_cast<jint*>(colors),
206 JNI_ABORT);
207 ThrowIAE_IfNull(env, shader);
208 return reinterpret_cast<jlong>(shader);
209 }
210
SweepGradient_create2(JNIEnv * env,jobject,jfloat x,jfloat y,int color0,int color1)211 static jlong SweepGradient_create2(JNIEnv* env, jobject, jfloat x, jfloat y,
212 int color0, int color1) {
213 SkColor colors[2];
214 colors[0] = color0;
215 colors[1] = color1;
216 SkShader* s = SkGradientShader::CreateSweep(x, y, colors, NULL, 2);
217 ThrowIAE_IfNull(env, s);
218 return reinterpret_cast<jlong>(s);
219 }
220
221 ///////////////////////////////////////////////////////////////////////////////////////////////
222
ComposeShader_create1(JNIEnv * env,jobject o,jlong shaderAHandle,jlong shaderBHandle,jlong modeHandle)223 static jlong ComposeShader_create1(JNIEnv* env, jobject o,
224 jlong shaderAHandle, jlong shaderBHandle, jlong modeHandle)
225 {
226 SkShader* shaderA = reinterpret_cast<SkShader *>(shaderAHandle);
227 SkShader* shaderB = reinterpret_cast<SkShader *>(shaderBHandle);
228 SkXfermode* mode = reinterpret_cast<SkXfermode *>(modeHandle);
229 SkShader* shader = new SkComposeShader(shaderA, shaderB, mode);
230 return reinterpret_cast<jlong>(shader);
231 }
232
ComposeShader_create2(JNIEnv * env,jobject o,jlong shaderAHandle,jlong shaderBHandle,jint xfermodeHandle)233 static jlong ComposeShader_create2(JNIEnv* env, jobject o,
234 jlong shaderAHandle, jlong shaderBHandle, jint xfermodeHandle)
235 {
236 SkShader* shaderA = reinterpret_cast<SkShader *>(shaderAHandle);
237 SkShader* shaderB = reinterpret_cast<SkShader *>(shaderBHandle);
238 SkXfermode::Mode mode = static_cast<SkXfermode::Mode>(xfermodeHandle);
239 SkAutoTUnref<SkXfermode> xfermode(SkXfermode::Create(mode));
240 SkShader* shader = new SkComposeShader(shaderA, shaderB, xfermode.get());
241 return reinterpret_cast<jlong>(shader);
242 }
243
244 ///////////////////////////////////////////////////////////////////////////////////////////////
245
246 static JNINativeMethod gColorMethods[] = {
247 { "nativeRGBToHSV", "(III[F)V", (void*)Color_RGBToHSV },
248 { "nativeHSVToColor", "(I[F)I", (void*)Color_HSVToColor }
249 };
250
251 static JNINativeMethod gShaderMethods[] = {
252 { "nativeDestructor", "(J)V", (void*)Shader_destructor },
253 { "nativeSetLocalMatrix", "(JJ)J", (void*)Shader_setLocalMatrix }
254 };
255
256 static JNINativeMethod gBitmapShaderMethods[] = {
257 { "nativeCreate", "(Landroid/graphics/Bitmap;II)J", (void*)BitmapShader_constructor },
258 };
259
260 static JNINativeMethod gLinearGradientMethods[] = {
261 { "nativeCreate1", "(FFFF[I[FI)J", (void*)LinearGradient_create1 },
262 { "nativeCreate2", "(FFFFIII)J", (void*)LinearGradient_create2 },
263 };
264
265 static JNINativeMethod gRadialGradientMethods[] = {
266 { "nativeCreate1", "(FFF[I[FI)J", (void*)RadialGradient_create1 },
267 { "nativeCreate2", "(FFFIII)J", (void*)RadialGradient_create2 },
268 };
269
270 static JNINativeMethod gSweepGradientMethods[] = {
271 { "nativeCreate1", "(FF[I[F)J", (void*)SweepGradient_create1 },
272 { "nativeCreate2", "(FFII)J", (void*)SweepGradient_create2 },
273 };
274
275 static JNINativeMethod gComposeShaderMethods[] = {
276 { "nativeCreate1", "(JJJ)J", (void*)ComposeShader_create1 },
277 { "nativeCreate2", "(JJI)J", (void*)ComposeShader_create2 },
278 };
279
register_android_graphics_Shader(JNIEnv * env)280 int register_android_graphics_Shader(JNIEnv* env)
281 {
282 android::RegisterMethodsOrDie(env, "android/graphics/Color", gColorMethods,
283 NELEM(gColorMethods));
284 android::RegisterMethodsOrDie(env, "android/graphics/Shader", gShaderMethods,
285 NELEM(gShaderMethods));
286 android::RegisterMethodsOrDie(env, "android/graphics/BitmapShader", gBitmapShaderMethods,
287 NELEM(gBitmapShaderMethods));
288 android::RegisterMethodsOrDie(env, "android/graphics/LinearGradient", gLinearGradientMethods,
289 NELEM(gLinearGradientMethods));
290 android::RegisterMethodsOrDie(env, "android/graphics/RadialGradient", gRadialGradientMethods,
291 NELEM(gRadialGradientMethods));
292 android::RegisterMethodsOrDie(env, "android/graphics/SweepGradient", gSweepGradientMethods,
293 NELEM(gSweepGradientMethods));
294 android::RegisterMethodsOrDie(env, "android/graphics/ComposeShader", gComposeShaderMethods,
295 NELEM(gComposeShaderMethods));
296
297 return 0;
298 }
299