• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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(&currentMatrix));
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