blob: 36413d7fba2e24b2288e6df92fe7130b46acaef3 [file] [log] [blame]
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001#include <jni.h>
2#include "GraphicsJNI.h"
3
4#include "SkShader.h"
5#include "SkGradientShader.h"
6#include "SkPorterDuff.h"
7#include "SkComposeShader.h"
8#include "SkTemplates.h"
9#include "SkXfermode.h"
10
Romain Guy06f96e22010-07-30 19:18:16 -070011#include <SkiaShader.h>
12
13using namespace android::uirenderer;
14
Romain Guy7fac2e12010-07-16 17:10:13 -070015static struct {
16 jclass clazz;
Romain Guy06f96e22010-07-30 19:18:16 -070017 jfieldID shader;
18} gShaderClassInfo;
Romain Guy7fac2e12010-07-16 17:10:13 -070019
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080020static void ThrowIAE_IfNull(JNIEnv* env, void* ptr) {
21 if (NULL == ptr) {
22 doThrowIAE(env);
23 }
24}
25
26static void Color_RGBToHSV(JNIEnv* env, jobject, int red, int green, int blue, jfloatArray hsvArray)
27{
28 SkScalar hsv[3];
29 SkRGBToHSV(red, green, blue, hsv);
30
31 AutoJavaFloatArray autoHSV(env, hsvArray, 3);
32 float* values = autoHSV.ptr();
33 for (int i = 0; i < 3; i++) {
34 values[i] = SkScalarToFloat(hsv[i]);
35 }
36}
37
38static int Color_HSVToColor(JNIEnv* env, jobject, int alpha, jfloatArray hsvArray)
39{
40 AutoJavaFloatArray autoHSV(env, hsvArray, 3);
41 float* values = autoHSV.ptr();;
42 SkScalar hsv[3];
43
44 for (int i = 0; i < 3; i++) {
45 hsv[i] = SkFloatToScalar(values[i]);
46 }
47
48 return SkHSVToColor(alpha, hsv);
49}
50
51///////////////////////////////////////////////////////////////////////////////////////////////
52
Romain Guy06f96e22010-07-30 19:18:16 -070053static void Shader_destructor(JNIEnv* env, jobject o, SkShader* shader, SkiaShader* skiaShader)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080054{
Romain Guy06f96e22010-07-30 19:18:16 -070055 delete skiaShader;
Mike Reed6af25522009-07-30 11:46:47 -040056 shader->safeUnref();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080057}
58
59static bool Shader_getLocalMatrix(JNIEnv* env, jobject, const SkShader* shader, SkMatrix* matrix)
60{
Mike Reeda04e5552009-07-30 11:05:57 -040061 return shader ? shader->getLocalMatrix(matrix) : false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080062}
63
Romain Guy06f96e22010-07-30 19:18:16 -070064static void Shader_setLocalMatrix(JNIEnv* env, jobject o, SkShader* shader, SkiaShader* skiaShader,
65 const SkMatrix* matrix)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080066{
Mike Reeda04e5552009-07-30 11:05:57 -040067 if (shader) {
68 if (NULL == matrix) {
69 shader->resetLocalMatrix();
70 }
71 else {
72 shader->setLocalMatrix(*matrix);
73 }
Romain Guy16393512010-08-08 00:14:31 -070074#ifdef USE_OPENGL_RENDERER
Romain Guy06f96e22010-07-30 19:18:16 -070075 skiaShader->setMatrix(const_cast<SkMatrix*>(matrix));
Romain Guy16393512010-08-08 00:14:31 -070076#endif
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080077 }
78}
79
80///////////////////////////////////////////////////////////////////////////////////////////////
81
Romain Guy06f96e22010-07-30 19:18:16 -070082static SkShader* BitmapShader_constructor(JNIEnv* env, jobject o, const SkBitmap* bitmap,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080083 int tileModeX, int tileModeY)
84{
85 SkShader* s = SkShader::CreateBitmapShader(*bitmap,
86 (SkShader::TileMode)tileModeX,
87 (SkShader::TileMode)tileModeY);
Romain Guy06f96e22010-07-30 19:18:16 -070088
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080089 ThrowIAE_IfNull(env, s);
90 return s;
91}
Romain Guy06f96e22010-07-30 19:18:16 -070092
93static SkiaShader* BitmapShader_postConstructor(JNIEnv* env, jobject o, SkShader* shader,
94 SkBitmap* bitmap, int tileModeX, int tileModeY) {
Romain Guy16393512010-08-08 00:14:31 -070095#ifdef USE_OPENGL_RENDERER
Romain Guy06f96e22010-07-30 19:18:16 -070096 SkiaShader* skiaShader = new SkiaBitmapShader(bitmap, shader,
97 static_cast<SkShader::TileMode>(tileModeX), static_cast<SkShader::TileMode>(tileModeY),
98 NULL, (shader->getFlags() & SkShader::kOpaqueAlpha_Flag) == 0);
99 return skiaShader;
Romain Guy16393512010-08-08 00:14:31 -0700100#else
101 return NULL;
102#endif
Romain Guy06f96e22010-07-30 19:18:16 -0700103}
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800104
105///////////////////////////////////////////////////////////////////////////////////////////////
106
Romain Guy7fac2e12010-07-16 17:10:13 -0700107static SkShader* LinearGradient_create1(JNIEnv* env, jobject o,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800108 float x0, float y0, float x1, float y1,
109 jintArray colorArray, jfloatArray posArray, int tileMode)
110{
111 SkPoint pts[2];
112 pts[0].set(SkFloatToScalar(x0), SkFloatToScalar(y0));
113 pts[1].set(SkFloatToScalar(x1), SkFloatToScalar(y1));
114
Romain Guy06f96e22010-07-30 19:18:16 -0700115 size_t count = env->GetArrayLength(colorArray);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800116 const jint* colorValues = env->GetIntArrayElements(colorArray, NULL);
117
118 SkAutoSTMalloc<8, SkScalar> storage(posArray ? count : 0);
119 SkScalar* pos = NULL;
Romain Guy7fac2e12010-07-16 17:10:13 -0700120
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800121 if (posArray) {
122 AutoJavaFloatArray autoPos(env, posArray, count);
123 const float* posValues = autoPos.ptr();
124 pos = (SkScalar*)storage.get();
Romain Guy7fac2e12010-07-16 17:10:13 -0700125 for (size_t i = 0; i < count; i++) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800126 pos[i] = SkFloatToScalar(posValues[i]);
Romain Guy06f96e22010-07-30 19:18:16 -0700127 }
128 }
129
130 SkShader* shader = SkGradientShader::CreateLinear(pts,
131 reinterpret_cast<const SkColor*>(colorValues),
132 pos, count,
133 static_cast<SkShader::TileMode>(tileMode));
134
135 env->ReleaseIntArrayElements(colorArray, const_cast<jint*>(colorValues), JNI_ABORT);
136 ThrowIAE_IfNull(env, shader);
137 return shader;
138}
139
140static SkiaShader* LinearGradient_postCreate1(JNIEnv* env, jobject o, SkShader* shader,
141 float x0, float y0, float x1, float y1, jintArray colorArray,
142 jfloatArray posArray, int tileMode) {
Romain Guy16393512010-08-08 00:14:31 -0700143#ifdef USE_OPENGL_RENDERER
Romain Guy06f96e22010-07-30 19:18:16 -0700144 size_t count = env->GetArrayLength(colorArray);
145 const jint* colorValues = env->GetIntArrayElements(colorArray, NULL);
146
147 jfloat* storedBounds = new jfloat[4];
148 storedBounds[0] = x0; storedBounds[1] = y0;
149 storedBounds[2] = x1; storedBounds[3] = y1;
150 jfloat* storedPositions = new jfloat[count];
151 uint32_t* storedColors = new uint32_t[count];
Romain Guy61c8c9c2010-08-09 20:48:09 -0700152 for (size_t i = 0; i < count; i++) {
153 storedColors[i] = static_cast<uint32_t>(colorValues[i]);
154 }
Romain Guy06f96e22010-07-30 19:18:16 -0700155
156 if (posArray) {
157 AutoJavaFloatArray autoPos(env, posArray, count);
158 const float* posValues = autoPos.ptr();
159 for (size_t i = 0; i < count; i++) {
Romain Guy7fac2e12010-07-16 17:10:13 -0700160 storedPositions[i] = posValues[i];
161 }
162 } else {
163 storedPositions[0] = 0.0f;
164 storedPositions[1] = 1.0f;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800165 }
Romain Guy06f96e22010-07-30 19:18:16 -0700166
167 SkiaShader* skiaShader = new SkiaLinearGradientShader(storedBounds, storedColors,
168 storedPositions, count, shader, static_cast<SkShader::TileMode>(tileMode), NULL,
169 (shader->getFlags() & SkShader::kOpaqueAlpha_Flag) == 0);
170
171 env->ReleaseIntArrayElements(colorArray, const_cast<jint*>(colorValues), JNI_ABORT);
172 return skiaShader;
Romain Guy16393512010-08-08 00:14:31 -0700173#else
174 return NULL;
175#endif
Romain Guy06f96e22010-07-30 19:18:16 -0700176}
177
178static SkiaShader* LinearGradient_postCreate2(JNIEnv* env, jobject o, SkShader* shader,
179 float x0, float y0, float x1, float y1, int color0, int color1, int tileMode) {
Romain Guy16393512010-08-08 00:14:31 -0700180#ifdef USE_OPENGL_RENDERER
Romain Guy06f96e22010-07-30 19:18:16 -0700181 float* storedBounds = new float[4];
182 storedBounds[0] = x0; storedBounds[1] = y0;
183 storedBounds[2] = x1; storedBounds[3] = y1;
184
185 float* storedPositions = new float[2];
186 storedPositions[0] = 0.0f;
187 storedPositions[1] = 1.0f;
188
189 uint32_t* storedColors = new uint32_t[2];
Romain Guy61c8c9c2010-08-09 20:48:09 -0700190 storedColors[0] = static_cast<uint32_t>(color0);
191 storedColors[1] = static_cast<uint32_t>(color1);
Romain Guy06f96e22010-07-30 19:18:16 -0700192
193 SkiaShader* skiaShader = new SkiaLinearGradientShader(storedBounds, storedColors,
194 storedPositions, 2, shader, static_cast<SkShader::TileMode>(tileMode), NULL,
195 (shader->getFlags() & SkShader::kOpaqueAlpha_Flag) == 0);
196
197 return skiaShader;
Romain Guy16393512010-08-08 00:14:31 -0700198#else
199 return NULL;
200#endif
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800201}
202
Romain Guy7fac2e12010-07-16 17:10:13 -0700203static SkShader* LinearGradient_create2(JNIEnv* env, jobject o,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800204 float x0, float y0, float x1, float y1,
205 int color0, int color1, int tileMode)
206{
207 SkPoint pts[2];
208 pts[0].set(SkFloatToScalar(x0), SkFloatToScalar(y0));
209 pts[1].set(SkFloatToScalar(x1), SkFloatToScalar(y1));
210
211 SkColor colors[2];
212 colors[0] = color0;
213 colors[1] = color1;
Romain Guy7fac2e12010-07-16 17:10:13 -0700214
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800215 SkShader* s = SkGradientShader::CreateLinear(pts, colors, NULL, 2, (SkShader::TileMode)tileMode);
Romain Guy06f96e22010-07-30 19:18:16 -0700216
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800217 ThrowIAE_IfNull(env, s);
218 return s;
219}
220
221///////////////////////////////////////////////////////////////////////////////////////////////
222
223static SkShader* RadialGradient_create1(JNIEnv* env, jobject,
224 float x, float y, float radius,
225 jintArray colorArray, jfloatArray posArray, int tileMode)
226{
227 SkPoint center;
228 center.set(SkFloatToScalar(x), SkFloatToScalar(y));
229
230 size_t count = env->GetArrayLength(colorArray);
231 const jint* colorValues = env->GetIntArrayElements(colorArray, NULL);
232
233 SkAutoSTMalloc<8, SkScalar> storage(posArray ? count : 0);
234 SkScalar* pos = NULL;
235
236 if (posArray) {
237 AutoJavaFloatArray autoPos(env, posArray, count);
238 const float* posValues = autoPos.ptr();
239 pos = (SkScalar*)storage.get();
240 for (size_t i = 0; i < count; i++)
241 pos[i] = SkFloatToScalar(posValues[i]);
242 }
243
244 SkShader* shader = SkGradientShader::CreateRadial(center,
245 SkFloatToScalar(radius),
246 reinterpret_cast<const SkColor*>(colorValues),
247 pos, count,
248 static_cast<SkShader::TileMode>(tileMode));
249 env->ReleaseIntArrayElements(colorArray, const_cast<jint*>(colorValues),
250 JNI_ABORT);
251
252 ThrowIAE_IfNull(env, shader);
253 return shader;
254}
255
256static SkShader* RadialGradient_create2(JNIEnv* env, jobject,
257 float x, float y, float radius,
258 int color0, int color1, int tileMode)
259{
260 SkPoint center;
261 center.set(SkFloatToScalar(x), SkFloatToScalar(y));
262
263 SkColor colors[2];
264 colors[0] = color0;
265 colors[1] = color1;
266
267 SkShader* s = SkGradientShader::CreateRadial(center, SkFloatToScalar(radius), colors, NULL,
268 2, (SkShader::TileMode)tileMode);
269 ThrowIAE_IfNull(env, s);
270 return s;
271}
272
273///////////////////////////////////////////////////////////////////////////////
274
275static SkShader* SweepGradient_create1(JNIEnv* env, jobject, float x, float y,
276 jintArray jcolors, jfloatArray jpositions)
277{
278 size_t count = env->GetArrayLength(jcolors);
279 const jint* colors = env->GetIntArrayElements(jcolors, NULL);
280
281 SkAutoSTMalloc<8, SkScalar> storage(jpositions ? count : 0);
282 SkScalar* pos = NULL;
283
284 if (NULL != jpositions) {
285 AutoJavaFloatArray autoPos(env, jpositions, count);
286 const float* posValues = autoPos.ptr();
287 pos = (SkScalar*)storage.get();
288 for (size_t i = 0; i < count; i++) {
289 pos[i] = SkFloatToScalar(posValues[i]);
290 }
291 }
292
293 SkShader* shader = SkGradientShader::CreateSweep(SkFloatToScalar(x),
294 SkFloatToScalar(y),
295 reinterpret_cast<const SkColor*>(colors),
296 pos, count);
297 env->ReleaseIntArrayElements(jcolors, const_cast<jint*>(colors),
298 JNI_ABORT);
299 ThrowIAE_IfNull(env, shader);
300 return shader;
301}
302
303static SkShader* SweepGradient_create2(JNIEnv* env, jobject, float x, float y,
304 int color0, int color1)
305{
306 SkColor colors[2];
307 colors[0] = color0;
308 colors[1] = color1;
309 SkShader* s = SkGradientShader::CreateSweep(SkFloatToScalar(x), SkFloatToScalar(y),
310 colors, NULL, 2);
311 ThrowIAE_IfNull(env, s);
312 return s;
313}
314
315///////////////////////////////////////////////////////////////////////////////////////////////
316
Romain Guy06f96e22010-07-30 19:18:16 -0700317static SkShader* ComposeShader_create1(JNIEnv* env, jobject o,
318 SkShader* shaderA, SkShader* shaderB, SkXfermode* mode)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800319{
320 return new SkComposeShader(shaderA, shaderB, mode);
321}
322
Romain Guy06f96e22010-07-30 19:18:16 -0700323static SkShader* ComposeShader_create2(JNIEnv* env, jobject o,
324 SkShader* shaderA, SkShader* shaderB, SkPorterDuff::Mode porterDuffMode)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800325{
Romain Guy06f96e22010-07-30 19:18:16 -0700326 SkAutoUnref au(SkPorterDuff::CreateXfermode(porterDuffMode));
327 SkXfermode* mode = (SkXfermode*) au.get();
328 return new SkComposeShader(shaderA, shaderB, mode);
329}
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800330
Romain Guy06f96e22010-07-30 19:18:16 -0700331static SkiaShader* ComposeShader_postCreate2(JNIEnv* env, jobject o, SkShader* shader,
332 SkiaShader* shaderA, SkiaShader* shaderB, SkPorterDuff::Mode porterDuffMode) {
Romain Guy16393512010-08-08 00:14:31 -0700333#ifdef USE_OPENGL_RENDERER
Romain Guy06f96e22010-07-30 19:18:16 -0700334 SkAutoUnref au(SkPorterDuff::CreateXfermode(porterDuffMode));
335 SkXfermode* mode = (SkXfermode*) au.get();
336 SkXfermode::Mode skiaMode;
337 if (!SkXfermode::IsMode(mode, &skiaMode)) {
338 skiaMode = SkXfermode::kSrcOver_Mode;
339 }
340 return new SkiaComposeShader(shaderA, shaderB, skiaMode, shader);
Romain Guy16393512010-08-08 00:14:31 -0700341#else
342 return NULL;
343#endif
Romain Guy06f96e22010-07-30 19:18:16 -0700344}
345
346static SkiaShader* ComposeShader_postCreate1(JNIEnv* env, jobject o, SkShader* shader,
347 SkiaShader* shaderA, SkiaShader* shaderB, SkXfermode* mode) {
Romain Guy16393512010-08-08 00:14:31 -0700348#ifdef USE_OPENGL_RENDERER
Romain Guy06f96e22010-07-30 19:18:16 -0700349 SkXfermode::Mode skiaMode;
350 if (!SkXfermode::IsMode(mode, &skiaMode)) {
351 skiaMode = SkXfermode::kSrcOver_Mode;
352 }
353 return new SkiaComposeShader(shaderA, shaderB, skiaMode, shader);
Romain Guy16393512010-08-08 00:14:31 -0700354#else
355 return NULL;
356#endif
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800357}
358
359///////////////////////////////////////////////////////////////////////////////////////////////
360
361static JNINativeMethod gColorMethods[] = {
362 { "nativeRGBToHSV", "(III[F)V", (void*)Color_RGBToHSV },
363 { "nativeHSVToColor", "(I[F)I", (void*)Color_HSVToColor }
364};
365
366static JNINativeMethod gShaderMethods[] = {
Romain Guy06f96e22010-07-30 19:18:16 -0700367 { "nativeDestructor", "(II)V", (void*)Shader_destructor },
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800368 { "nativeGetLocalMatrix", "(II)Z", (void*)Shader_getLocalMatrix },
Romain Guy06f96e22010-07-30 19:18:16 -0700369 { "nativeSetLocalMatrix", "(III)V", (void*)Shader_setLocalMatrix }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800370};
371
372static JNINativeMethod gBitmapShaderMethods[] = {
Romain Guy06f96e22010-07-30 19:18:16 -0700373 { "nativeCreate", "(III)I", (void*)BitmapShader_constructor },
374 { "nativePostCreate", "(IIII)I", (void*)BitmapShader_postConstructor }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800375};
376
377static JNINativeMethod gLinearGradientMethods[] = {
Romain Guy06f96e22010-07-30 19:18:16 -0700378 { "nativeCreate1", "(FFFF[I[FI)I", (void*)LinearGradient_create1 },
379 { "nativeCreate2", "(FFFFIII)I", (void*)LinearGradient_create2 },
380 { "nativePostCreate1", "(IFFFF[I[FI)I", (void*)LinearGradient_postCreate1 },
381 { "nativePostCreate2", "(IFFFFIII)I", (void*)LinearGradient_postCreate2 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800382};
383
384static JNINativeMethod gRadialGradientMethods[] = {
385 {"nativeCreate1", "(FFF[I[FI)I", (void*)RadialGradient_create1 },
386 {"nativeCreate2", "(FFFIII)I", (void*)RadialGradient_create2 }
387};
388
389static JNINativeMethod gSweepGradientMethods[] = {
390 {"nativeCreate1", "(FF[I[F)I", (void*)SweepGradient_create1 },
391 {"nativeCreate2", "(FFII)I", (void*)SweepGradient_create2 }
392};
393
394static JNINativeMethod gComposeShaderMethods[] = {
Romain Guy06f96e22010-07-30 19:18:16 -0700395 {"nativeCreate1", "(III)I", (void*)ComposeShader_create1 },
396 {"nativeCreate2", "(III)I", (void*)ComposeShader_create2 },
397 {"nativePostCreate1", "(IIII)I", (void*)ComposeShader_postCreate1 },
398 {"nativePostCreate2", "(IIII)I", (void*)ComposeShader_postCreate2 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800399};
400
401#include <android_runtime/AndroidRuntime.h>
402
403#define REG(env, name, array) \
404 result = android::AndroidRuntime::registerNativeMethods(env, name, array, SK_ARRAY_COUNT(array)); \
405 if (result < 0) return result
406
407int register_android_graphics_Shader(JNIEnv* env);
408int register_android_graphics_Shader(JNIEnv* env)
409{
410 int result;
411
412 REG(env, "android/graphics/Color", gColorMethods);
413 REG(env, "android/graphics/Shader", gShaderMethods);
414 REG(env, "android/graphics/BitmapShader", gBitmapShaderMethods);
415 REG(env, "android/graphics/LinearGradient", gLinearGradientMethods);
416 REG(env, "android/graphics/RadialGradient", gRadialGradientMethods);
417 REG(env, "android/graphics/SweepGradient", gSweepGradientMethods);
418 REG(env, "android/graphics/ComposeShader", gComposeShaderMethods);
419
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800420 return result;
421}
422