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