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