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