Shader.cpp revision 7fac2e18339f765320d759e8d4c090f92431959e
1#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
11static struct {
12    jclass clazz;
13    jfieldID bounds;
14    jfieldID colors;
15    jfieldID positions;
16} gLinearGradientClassInfo;
17
18static void ThrowIAE_IfNull(JNIEnv* env, void* ptr) {
19    if (NULL == ptr) {
20        doThrowIAE(env);
21    }
22}
23
24static void Color_RGBToHSV(JNIEnv* env, jobject, int red, int green, int blue, jfloatArray hsvArray)
25{
26    SkScalar hsv[3];
27    SkRGBToHSV(red, green, blue, hsv);
28
29    AutoJavaFloatArray  autoHSV(env, hsvArray, 3);
30    float* values = autoHSV.ptr();
31    for (int i = 0; i < 3; i++) {
32        values[i] = SkScalarToFloat(hsv[i]);
33    }
34}
35
36static int Color_HSVToColor(JNIEnv* env, jobject, int alpha, jfloatArray hsvArray)
37{
38    AutoJavaFloatArray  autoHSV(env, hsvArray, 3);
39    float*      values = autoHSV.ptr();;
40    SkScalar    hsv[3];
41
42    for (int i = 0; i < 3; i++) {
43        hsv[i] = SkFloatToScalar(values[i]);
44    }
45
46    return SkHSVToColor(alpha, hsv);
47}
48
49///////////////////////////////////////////////////////////////////////////////////////////////
50
51static void Shader_destructor(JNIEnv* env, jobject, SkShader* shader)
52{
53    shader->safeUnref();
54}
55
56static bool Shader_getLocalMatrix(JNIEnv* env, jobject, const SkShader* shader, SkMatrix* matrix)
57{
58    return shader ? shader->getLocalMatrix(matrix) : false;
59}
60
61static void Shader_setLocalMatrix(JNIEnv* env, jobject, SkShader* shader, const SkMatrix* matrix)
62{
63    if (shader) {
64        if (NULL == matrix) {
65            shader->resetLocalMatrix();
66        }
67        else {
68            shader->setLocalMatrix(*matrix);
69        }
70    }
71}
72
73///////////////////////////////////////////////////////////////////////////////////////////////
74
75static SkShader* BitmapShader_constructor(JNIEnv* env, jobject, const SkBitmap* bitmap,
76                                          int tileModeX, int tileModeY)
77{
78    SkShader* s = SkShader::CreateBitmapShader(*bitmap,
79                                        (SkShader::TileMode)tileModeX,
80                                        (SkShader::TileMode)tileModeY);
81    ThrowIAE_IfNull(env, s);
82    return s;
83}
84
85///////////////////////////////////////////////////////////////////////////////////////////////
86
87static void LinearGradient_destructor(JNIEnv* env, jobject o, SkShader* shader)
88{
89    delete reinterpret_cast<jfloat*>(env->GetIntField(o, gLinearGradientClassInfo.bounds));
90    delete reinterpret_cast<jint*>(env->GetIntField(o, gLinearGradientClassInfo.colors));
91    delete reinterpret_cast<jfloat*>(env->GetIntField(o, gLinearGradientClassInfo.positions));
92}
93
94static SkShader* LinearGradient_create1(JNIEnv* env, jobject o,
95                                        float x0, float y0, float x1, float y1,
96                                        jintArray colorArray, jfloatArray posArray, int tileMode)
97{
98    SkPoint pts[2];
99    pts[0].set(SkFloatToScalar(x0), SkFloatToScalar(y0));
100    pts[1].set(SkFloatToScalar(x1), SkFloatToScalar(y1));
101
102    size_t      count = env->GetArrayLength(colorArray);
103    const jint* colorValues = env->GetIntArrayElements(colorArray, NULL);
104
105    SkAutoSTMalloc<8, SkScalar> storage(posArray ? count : 0);
106    SkScalar*                   pos = NULL;
107
108    jfloat* storedBounds = new jfloat[4];
109    storedBounds[0] = x0; storedBounds[1] = y0;
110    storedBounds[2] = x1; storedBounds[3] = y1;
111    jfloat* storedPositions = new jfloat[count];
112    jint* storedColors = new jint[count];
113    memcpy(storedColors, colorValues, count);
114
115    if (posArray) {
116        AutoJavaFloatArray autoPos(env, posArray, count);
117        const float* posValues = autoPos.ptr();
118        pos = (SkScalar*)storage.get();
119        for (size_t i = 0; i < count; i++) {
120            pos[i] = SkFloatToScalar(posValues[i]);
121            storedPositions[i] = posValues[i];
122        }
123    } else {
124        storedPositions[0] = 0.0f;
125        storedPositions[1] = 1.0f;
126    }
127
128    env->SetIntField(o, gLinearGradientClassInfo.bounds, reinterpret_cast<jint>(storedBounds));
129    env->SetIntField(o, gLinearGradientClassInfo.colors, reinterpret_cast<jint>(storedColors));
130    env->SetIntField(o, gLinearGradientClassInfo.positions, reinterpret_cast<jint>(storedPositions));
131
132    SkShader* shader = SkGradientShader::CreateLinear(pts,
133                                reinterpret_cast<const SkColor*>(colorValues),
134                                pos, count,
135                                static_cast<SkShader::TileMode>(tileMode));
136    env->ReleaseIntArrayElements(colorArray, const_cast<jint*>(colorValues),
137                                 JNI_ABORT);
138    ThrowIAE_IfNull(env, shader);
139    return shader;
140}
141
142static SkShader* LinearGradient_create2(JNIEnv* env, jobject o,
143                                        float x0, float y0, float x1, float y1,
144                                        int color0, int color1, int tileMode)
145{
146    SkPoint pts[2];
147    pts[0].set(SkFloatToScalar(x0), SkFloatToScalar(y0));
148    pts[1].set(SkFloatToScalar(x1), SkFloatToScalar(y1));
149
150    SkColor colors[2];
151    colors[0] = color0;
152    colors[1] = color1;
153
154    float* storedBounds = new float[4];
155    storedBounds[0] = x0; storedBounds[1] = y0;
156    storedBounds[2] = x1; storedBounds[3] = y1;
157
158    float* storedPositions = new float[2];
159    storedPositions[0] = 0.0f;
160    storedPositions[1] = 1.0f;
161
162    uint32_t* storedColors = new uint32_t[2];
163    storedColors[0] = color0;
164    storedColors[1] = color1;
165
166    env->SetIntField(o, gLinearGradientClassInfo.bounds, reinterpret_cast<jint>(storedBounds));
167    env->SetIntField(o, gLinearGradientClassInfo.colors, reinterpret_cast<jint>(storedColors));
168    env->SetIntField(o, gLinearGradientClassInfo.positions, reinterpret_cast<jint>(storedPositions));
169
170    SkShader* s = SkGradientShader::CreateLinear(pts, colors, NULL, 2, (SkShader::TileMode)tileMode);
171    ThrowIAE_IfNull(env, s);
172    return s;
173}
174
175///////////////////////////////////////////////////////////////////////////////////////////////
176
177static SkShader* RadialGradient_create1(JNIEnv* env, jobject,
178                                        float x, float y, float radius,
179                                        jintArray colorArray, jfloatArray posArray, int tileMode)
180{
181    SkPoint center;
182    center.set(SkFloatToScalar(x), SkFloatToScalar(y));
183
184    size_t      count = env->GetArrayLength(colorArray);
185    const jint* colorValues = env->GetIntArrayElements(colorArray, NULL);
186
187    SkAutoSTMalloc<8, SkScalar> storage(posArray ? count : 0);
188    SkScalar*                   pos = NULL;
189
190    if (posArray) {
191        AutoJavaFloatArray autoPos(env, posArray, count);
192        const float* posValues = autoPos.ptr();
193        pos = (SkScalar*)storage.get();
194        for (size_t i = 0; i < count; i++)
195            pos[i] = SkFloatToScalar(posValues[i]);
196    }
197
198    SkShader* shader = SkGradientShader::CreateRadial(center,
199                                SkFloatToScalar(radius),
200                                reinterpret_cast<const SkColor*>(colorValues),
201                                pos, count,
202                                static_cast<SkShader::TileMode>(tileMode));
203    env->ReleaseIntArrayElements(colorArray, const_cast<jint*>(colorValues),
204                                 JNI_ABORT);
205
206    ThrowIAE_IfNull(env, shader);
207    return shader;
208}
209
210static SkShader* RadialGradient_create2(JNIEnv* env, jobject,
211                                        float x, float y, float radius,
212                                        int color0, int color1, int tileMode)
213{
214    SkPoint center;
215    center.set(SkFloatToScalar(x), SkFloatToScalar(y));
216
217    SkColor colors[2];
218    colors[0] = color0;
219    colors[1] = color1;
220
221    SkShader* s = SkGradientShader::CreateRadial(center, SkFloatToScalar(radius), colors, NULL,
222                                          2, (SkShader::TileMode)tileMode);
223    ThrowIAE_IfNull(env, s);
224    return s;
225}
226
227///////////////////////////////////////////////////////////////////////////////
228
229static SkShader* SweepGradient_create1(JNIEnv* env, jobject, float x, float y,
230                                    jintArray jcolors, jfloatArray jpositions)
231{
232    size_t      count = env->GetArrayLength(jcolors);
233    const jint* colors = env->GetIntArrayElements(jcolors, NULL);
234
235    SkAutoSTMalloc<8, SkScalar> storage(jpositions ? count : 0);
236    SkScalar*                   pos = NULL;
237
238    if (NULL != jpositions) {
239        AutoJavaFloatArray autoPos(env, jpositions, count);
240        const float* posValues = autoPos.ptr();
241        pos = (SkScalar*)storage.get();
242        for (size_t i = 0; i < count; i++) {
243            pos[i] = SkFloatToScalar(posValues[i]);
244        }
245    }
246
247    SkShader* shader = SkGradientShader::CreateSweep(SkFloatToScalar(x),
248                                     SkFloatToScalar(y),
249                                     reinterpret_cast<const SkColor*>(colors),
250                                     pos, count);
251    env->ReleaseIntArrayElements(jcolors, const_cast<jint*>(colors),
252                                 JNI_ABORT);
253    ThrowIAE_IfNull(env, shader);
254    return shader;
255}
256
257static SkShader* SweepGradient_create2(JNIEnv* env, jobject, float x, float y,
258                                        int color0, int color1)
259{
260    SkColor colors[2];
261    colors[0] = color0;
262    colors[1] = color1;
263    SkShader* s = SkGradientShader::CreateSweep(SkFloatToScalar(x), SkFloatToScalar(y),
264                                         colors, NULL, 2);
265    ThrowIAE_IfNull(env, s);
266    return s;
267}
268
269///////////////////////////////////////////////////////////////////////////////////////////////
270
271static SkShader* ComposeShader_create1(JNIEnv* env, jobject,
272                                       SkShader* shaderA, SkShader* shaderB, SkXfermode* mode)
273{
274    return new SkComposeShader(shaderA, shaderB, mode);
275}
276
277static SkShader* ComposeShader_create2(JNIEnv* env, jobject,
278                                       SkShader* shaderA, SkShader* shaderB, SkPorterDuff::Mode mode)
279{
280    SkAutoUnref au(SkPorterDuff::CreateXfermode(mode));
281
282    return new SkComposeShader(shaderA, shaderB, (SkXfermode*)au.get());
283}
284
285///////////////////////////////////////////////////////////////////////////////////////////////
286
287static JNINativeMethod gColorMethods[] = {
288    { "nativeRGBToHSV",     "(III[F)V", (void*)Color_RGBToHSV   },
289    { "nativeHSVToColor",   "(I[F)I",   (void*)Color_HSVToColor }
290};
291
292static JNINativeMethod gShaderMethods[] = {
293    { "nativeDestructor",        "(I)V",     (void*)Shader_destructor        },
294    { "nativeGetLocalMatrix",    "(II)Z",    (void*)Shader_getLocalMatrix    },
295    { "nativeSetLocalMatrix",    "(II)V",    (void*)Shader_setLocalMatrix    }
296};
297
298static JNINativeMethod gBitmapShaderMethods[] = {
299    { "nativeCreate",   "(III)I",  (void*)BitmapShader_constructor }
300};
301
302static JNINativeMethod gLinearGradientMethods[] = {
303    { "nativeDestructor", "(I)V",         (void*)LinearGradient_destructor },
304    { "nativeCreate1",    "(FFFF[I[FI)I", (void*)LinearGradient_create1    },
305    { "nativeCreate2",    "(FFFFIII)I",   (void*)LinearGradient_create2    }
306};
307
308static JNINativeMethod gRadialGradientMethods[] = {
309    {"nativeCreate1",   "(FFF[I[FI)I",  (void*)RadialGradient_create1   },
310    {"nativeCreate2",   "(FFFIII)I",    (void*)RadialGradient_create2   }
311};
312
313static JNINativeMethod gSweepGradientMethods[] = {
314    {"nativeCreate1",   "(FF[I[F)I",  (void*)SweepGradient_create1   },
315    {"nativeCreate2",   "(FFII)I",    (void*)SweepGradient_create2   }
316};
317
318static JNINativeMethod gComposeShaderMethods[] = {
319    {"nativeCreate1",  "(III)I",    (void*)ComposeShader_create1 },
320    {"nativeCreate2",  "(III)I",    (void*)ComposeShader_create2 }
321};
322
323#include <android_runtime/AndroidRuntime.h>
324
325#define REG(env, name, array)                                                                       \
326    result = android::AndroidRuntime::registerNativeMethods(env, name, array, SK_ARRAY_COUNT(array));  \
327    if (result < 0) return result
328
329#define FIND_CLASS(var, className) \
330        var = env->FindClass(className); \
331        LOG_FATAL_IF(! var, "Unable to find class " className); \
332        var = jclass(env->NewGlobalRef(var));
333
334#define GET_FIELD_ID(var, clazz, fieldName, fieldType) \
335        var = env->GetFieldID(clazz, fieldName, fieldType); \
336        LOG_FATAL_IF(! var, "Unable to find field " fieldName);
337
338int register_android_graphics_Shader(JNIEnv* env);
339int register_android_graphics_Shader(JNIEnv* env)
340{
341    int result;
342
343    REG(env, "android/graphics/Color", gColorMethods);
344    REG(env, "android/graphics/Shader", gShaderMethods);
345    REG(env, "android/graphics/BitmapShader", gBitmapShaderMethods);
346    REG(env, "android/graphics/LinearGradient", gLinearGradientMethods);
347    REG(env, "android/graphics/RadialGradient", gRadialGradientMethods);
348    REG(env, "android/graphics/SweepGradient", gSweepGradientMethods);
349    REG(env, "android/graphics/ComposeShader", gComposeShaderMethods);
350
351    FIND_CLASS(gLinearGradientClassInfo.clazz, "android/graphics/LinearGradient");
352    GET_FIELD_ID(gLinearGradientClassInfo.bounds, gLinearGradientClassInfo.clazz, "bounds", "I");
353    GET_FIELD_ID(gLinearGradientClassInfo.colors, gLinearGradientClassInfo.clazz, "colors", "I");
354    GET_FIELD_ID(gLinearGradientClassInfo.positions, gLinearGradientClassInfo.clazz, "positions", "I");
355
356    return result;
357}
358
359