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