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