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