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