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