blob: 2b98e8975771bdb9766d37e95f7656aafaa0ba61 [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];
152 memcpy(storedColors, colorValues, count);
153
154 if (posArray) {
155 AutoJavaFloatArray autoPos(env, posArray, count);
156 const float* posValues = autoPos.ptr();
157 for (size_t i = 0; i < count; i++) {
Romain Guy7fac2e12010-07-16 17:10:13 -0700158 storedPositions[i] = posValues[i];
159 }
160 } else {
161 storedPositions[0] = 0.0f;
162 storedPositions[1] = 1.0f;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800163 }
Romain Guy06f96e22010-07-30 19:18:16 -0700164
165 SkiaShader* skiaShader = new SkiaLinearGradientShader(storedBounds, storedColors,
166 storedPositions, count, shader, static_cast<SkShader::TileMode>(tileMode), NULL,
167 (shader->getFlags() & SkShader::kOpaqueAlpha_Flag) == 0);
168
169 env->ReleaseIntArrayElements(colorArray, const_cast<jint*>(colorValues), JNI_ABORT);
170 return skiaShader;
Romain Guy16393512010-08-08 00:14:31 -0700171#else
172 return NULL;
173#endif
Romain Guy06f96e22010-07-30 19:18:16 -0700174}
175
176static SkiaShader* LinearGradient_postCreate2(JNIEnv* env, jobject o, SkShader* shader,
177 float x0, float y0, float x1, float y1, int color0, int color1, int tileMode) {
Romain Guy16393512010-08-08 00:14:31 -0700178#ifdef USE_OPENGL_RENDERER
Romain Guy06f96e22010-07-30 19:18:16 -0700179 float* storedBounds = new float[4];
180 storedBounds[0] = x0; storedBounds[1] = y0;
181 storedBounds[2] = x1; storedBounds[3] = y1;
182
183 float* storedPositions = new float[2];
184 storedPositions[0] = 0.0f;
185 storedPositions[1] = 1.0f;
186
187 uint32_t* storedColors = new uint32_t[2];
188 storedColors[0] = color0;
189 storedColors[1] = color1;
190
191 SkiaShader* skiaShader = new SkiaLinearGradientShader(storedBounds, storedColors,
192 storedPositions, 2, shader, static_cast<SkShader::TileMode>(tileMode), NULL,
193 (shader->getFlags() & SkShader::kOpaqueAlpha_Flag) == 0);
194
195 return skiaShader;
Romain Guy16393512010-08-08 00:14:31 -0700196#else
197 return NULL;
198#endif
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800199}
200
Romain Guy7fac2e12010-07-16 17:10:13 -0700201static SkShader* LinearGradient_create2(JNIEnv* env, jobject o,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800202 float x0, float y0, float x1, float y1,
203 int color0, int color1, int tileMode)
204{
205 SkPoint pts[2];
206 pts[0].set(SkFloatToScalar(x0), SkFloatToScalar(y0));
207 pts[1].set(SkFloatToScalar(x1), SkFloatToScalar(y1));
208
209 SkColor colors[2];
210 colors[0] = color0;
211 colors[1] = color1;
Romain Guy7fac2e12010-07-16 17:10:13 -0700212
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800213 SkShader* s = SkGradientShader::CreateLinear(pts, colors, NULL, 2, (SkShader::TileMode)tileMode);
Romain Guy06f96e22010-07-30 19:18:16 -0700214
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800215 ThrowIAE_IfNull(env, s);
216 return s;
217}
218
219///////////////////////////////////////////////////////////////////////////////////////////////
220
221static SkShader* RadialGradient_create1(JNIEnv* env, jobject,
222 float x, float y, float radius,
223 jintArray colorArray, jfloatArray posArray, int tileMode)
224{
225 SkPoint center;
226 center.set(SkFloatToScalar(x), SkFloatToScalar(y));
227
228 size_t count = env->GetArrayLength(colorArray);
229 const jint* colorValues = env->GetIntArrayElements(colorArray, NULL);
230
231 SkAutoSTMalloc<8, SkScalar> storage(posArray ? count : 0);
232 SkScalar* pos = NULL;
233
234 if (posArray) {
235 AutoJavaFloatArray autoPos(env, posArray, count);
236 const float* posValues = autoPos.ptr();
237 pos = (SkScalar*)storage.get();
238 for (size_t i = 0; i < count; i++)
239 pos[i] = SkFloatToScalar(posValues[i]);
240 }
241
242 SkShader* shader = SkGradientShader::CreateRadial(center,
243 SkFloatToScalar(radius),
244 reinterpret_cast<const SkColor*>(colorValues),
245 pos, count,
246 static_cast<SkShader::TileMode>(tileMode));
247 env->ReleaseIntArrayElements(colorArray, const_cast<jint*>(colorValues),
248 JNI_ABORT);
249
250 ThrowIAE_IfNull(env, shader);
251 return shader;
252}
253
254static SkShader* RadialGradient_create2(JNIEnv* env, jobject,
255 float x, float y, float radius,
256 int color0, int color1, int tileMode)
257{
258 SkPoint center;
259 center.set(SkFloatToScalar(x), SkFloatToScalar(y));
260
261 SkColor colors[2];
262 colors[0] = color0;
263 colors[1] = color1;
264
265 SkShader* s = SkGradientShader::CreateRadial(center, SkFloatToScalar(radius), colors, NULL,
266 2, (SkShader::TileMode)tileMode);
267 ThrowIAE_IfNull(env, s);
268 return s;
269}
270
271///////////////////////////////////////////////////////////////////////////////
272
273static SkShader* SweepGradient_create1(JNIEnv* env, jobject, float x, float y,
274 jintArray jcolors, jfloatArray jpositions)
275{
276 size_t count = env->GetArrayLength(jcolors);
277 const jint* colors = env->GetIntArrayElements(jcolors, NULL);
278
279 SkAutoSTMalloc<8, SkScalar> storage(jpositions ? count : 0);
280 SkScalar* pos = NULL;
281
282 if (NULL != jpositions) {
283 AutoJavaFloatArray autoPos(env, jpositions, count);
284 const float* posValues = autoPos.ptr();
285 pos = (SkScalar*)storage.get();
286 for (size_t i = 0; i < count; i++) {
287 pos[i] = SkFloatToScalar(posValues[i]);
288 }
289 }
290
291 SkShader* shader = SkGradientShader::CreateSweep(SkFloatToScalar(x),
292 SkFloatToScalar(y),
293 reinterpret_cast<const SkColor*>(colors),
294 pos, count);
295 env->ReleaseIntArrayElements(jcolors, const_cast<jint*>(colors),
296 JNI_ABORT);
297 ThrowIAE_IfNull(env, shader);
298 return shader;
299}
300
301static SkShader* SweepGradient_create2(JNIEnv* env, jobject, float x, float y,
302 int color0, int color1)
303{
304 SkColor colors[2];
305 colors[0] = color0;
306 colors[1] = color1;
307 SkShader* s = SkGradientShader::CreateSweep(SkFloatToScalar(x), SkFloatToScalar(y),
308 colors, NULL, 2);
309 ThrowIAE_IfNull(env, s);
310 return s;
311}
312
313///////////////////////////////////////////////////////////////////////////////////////////////
314
Romain Guy06f96e22010-07-30 19:18:16 -0700315static SkShader* ComposeShader_create1(JNIEnv* env, jobject o,
316 SkShader* shaderA, SkShader* shaderB, SkXfermode* mode)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800317{
318 return new SkComposeShader(shaderA, shaderB, mode);
319}
320
Romain Guy06f96e22010-07-30 19:18:16 -0700321static SkShader* ComposeShader_create2(JNIEnv* env, jobject o,
322 SkShader* shaderA, SkShader* shaderB, SkPorterDuff::Mode porterDuffMode)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800323{
Romain Guy06f96e22010-07-30 19:18:16 -0700324 SkAutoUnref au(SkPorterDuff::CreateXfermode(porterDuffMode));
325 SkXfermode* mode = (SkXfermode*) au.get();
326 return new SkComposeShader(shaderA, shaderB, mode);
327}
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800328
Romain Guy06f96e22010-07-30 19:18:16 -0700329static SkiaShader* ComposeShader_postCreate2(JNIEnv* env, jobject o, SkShader* shader,
330 SkiaShader* shaderA, SkiaShader* shaderB, SkPorterDuff::Mode porterDuffMode) {
Romain Guy16393512010-08-08 00:14:31 -0700331#ifdef USE_OPENGL_RENDERER
Romain Guy06f96e22010-07-30 19:18:16 -0700332 SkAutoUnref au(SkPorterDuff::CreateXfermode(porterDuffMode));
333 SkXfermode* mode = (SkXfermode*) au.get();
334 SkXfermode::Mode skiaMode;
335 if (!SkXfermode::IsMode(mode, &skiaMode)) {
336 skiaMode = SkXfermode::kSrcOver_Mode;
337 }
338 return new SkiaComposeShader(shaderA, shaderB, skiaMode, shader);
Romain Guy16393512010-08-08 00:14:31 -0700339#else
340 return NULL;
341#endif
Romain Guy06f96e22010-07-30 19:18:16 -0700342}
343
344static SkiaShader* ComposeShader_postCreate1(JNIEnv* env, jobject o, SkShader* shader,
345 SkiaShader* shaderA, SkiaShader* shaderB, SkXfermode* mode) {
Romain Guy16393512010-08-08 00:14:31 -0700346#ifdef USE_OPENGL_RENDERER
Romain Guy06f96e22010-07-30 19:18:16 -0700347 SkXfermode::Mode skiaMode;
348 if (!SkXfermode::IsMode(mode, &skiaMode)) {
349 skiaMode = SkXfermode::kSrcOver_Mode;
350 }
351 return new SkiaComposeShader(shaderA, shaderB, skiaMode, shader);
Romain Guy16393512010-08-08 00:14:31 -0700352#else
353 return NULL;
354#endif
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800355}
356
357///////////////////////////////////////////////////////////////////////////////////////////////
358
359static JNINativeMethod gColorMethods[] = {
360 { "nativeRGBToHSV", "(III[F)V", (void*)Color_RGBToHSV },
361 { "nativeHSVToColor", "(I[F)I", (void*)Color_HSVToColor }
362};
363
364static JNINativeMethod gShaderMethods[] = {
Romain Guy06f96e22010-07-30 19:18:16 -0700365 { "nativeDestructor", "(II)V", (void*)Shader_destructor },
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800366 { "nativeGetLocalMatrix", "(II)Z", (void*)Shader_getLocalMatrix },
Romain Guy06f96e22010-07-30 19:18:16 -0700367 { "nativeSetLocalMatrix", "(III)V", (void*)Shader_setLocalMatrix }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800368};
369
370static JNINativeMethod gBitmapShaderMethods[] = {
Romain Guy06f96e22010-07-30 19:18:16 -0700371 { "nativeCreate", "(III)I", (void*)BitmapShader_constructor },
372 { "nativePostCreate", "(IIII)I", (void*)BitmapShader_postConstructor }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800373};
374
375static JNINativeMethod gLinearGradientMethods[] = {
Romain Guy06f96e22010-07-30 19:18:16 -0700376 { "nativeCreate1", "(FFFF[I[FI)I", (void*)LinearGradient_create1 },
377 { "nativeCreate2", "(FFFFIII)I", (void*)LinearGradient_create2 },
378 { "nativePostCreate1", "(IFFFF[I[FI)I", (void*)LinearGradient_postCreate1 },
379 { "nativePostCreate2", "(IFFFFIII)I", (void*)LinearGradient_postCreate2 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800380};
381
382static JNINativeMethod gRadialGradientMethods[] = {
383 {"nativeCreate1", "(FFF[I[FI)I", (void*)RadialGradient_create1 },
384 {"nativeCreate2", "(FFFIII)I", (void*)RadialGradient_create2 }
385};
386
387static JNINativeMethod gSweepGradientMethods[] = {
388 {"nativeCreate1", "(FF[I[F)I", (void*)SweepGradient_create1 },
389 {"nativeCreate2", "(FFII)I", (void*)SweepGradient_create2 }
390};
391
392static JNINativeMethod gComposeShaderMethods[] = {
Romain Guy06f96e22010-07-30 19:18:16 -0700393 {"nativeCreate1", "(III)I", (void*)ComposeShader_create1 },
394 {"nativeCreate2", "(III)I", (void*)ComposeShader_create2 },
395 {"nativePostCreate1", "(IIII)I", (void*)ComposeShader_postCreate1 },
396 {"nativePostCreate2", "(IIII)I", (void*)ComposeShader_postCreate2 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800397};
398
399#include <android_runtime/AndroidRuntime.h>
400
401#define REG(env, name, array) \
402 result = android::AndroidRuntime::registerNativeMethods(env, name, array, SK_ARRAY_COUNT(array)); \
403 if (result < 0) return result
404
405int register_android_graphics_Shader(JNIEnv* env);
406int register_android_graphics_Shader(JNIEnv* env)
407{
408 int result;
409
410 REG(env, "android/graphics/Color", gColorMethods);
411 REG(env, "android/graphics/Shader", gShaderMethods);
412 REG(env, "android/graphics/BitmapShader", gBitmapShaderMethods);
413 REG(env, "android/graphics/LinearGradient", gLinearGradientMethods);
414 REG(env, "android/graphics/RadialGradient", gRadialGradientMethods);
415 REG(env, "android/graphics/SweepGradient", gSweepGradientMethods);
416 REG(env, "android/graphics/ComposeShader", gComposeShaderMethods);
417
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800418 return result;
419}
420