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