Shader.cpp revision e1721099b5bbb6a1dbd50c1d6cd0cacb10159a59
1#include "GraphicsJNI.h"
2#include "SkComposeShader.h"
3#include "SkGradientShader.h"
4#include "SkShader.h"
5#include "SkXfermode.h"
6#include "core_jni_helpers.h"
7
8#include <Caches.h>
9#include <jni.h>
10
11using namespace android::uirenderer;
12
13static void ThrowIAE_IfNull(JNIEnv* env, void* ptr) {
14    if (NULL == ptr) {
15        doThrowIAE(env);
16    }
17}
18
19static void Color_RGBToHSV(JNIEnv* env, jobject, jint red, jint green, jint blue, jfloatArray hsvArray)
20{
21    SkScalar hsv[3];
22    SkRGBToHSV(red, green, blue, hsv);
23
24    AutoJavaFloatArray  autoHSV(env, hsvArray, 3);
25    float* values = autoHSV.ptr();
26    for (int i = 0; i < 3; i++) {
27        values[i] = SkScalarToFloat(hsv[i]);
28    }
29}
30
31static jint Color_HSVToColor(JNIEnv* env, jobject, jint alpha, jfloatArray hsvArray)
32{
33    AutoJavaFloatArray  autoHSV(env, hsvArray, 3);
34#ifdef SK_SCALAR_IS_FLOAT
35    SkScalar*   hsv = autoHSV.ptr();
36#else
37    #error Need to convert float array to SkScalar array before calling the following function.
38#endif
39
40    return static_cast<jint>(SkHSVToColor(alpha, hsv));
41}
42
43///////////////////////////////////////////////////////////////////////////////////////////////
44
45static void Shader_destructor(JNIEnv* env, jobject o, jlong shaderHandle, jlong shaderWithLMHandle)
46{
47    SkShader* shader = reinterpret_cast<SkShader*>(shaderHandle);
48    SkSafeUnref(shader);
49}
50
51static jlong Shader_setLocalMatrix(JNIEnv* env, jobject o, jlong shaderHandle, jlong matrixHandle)
52{
53    // ensure we have a valid matrix to use
54    const SkMatrix* matrix = reinterpret_cast<SkMatrix*>(matrixHandle);
55    if (NULL == matrix) {
56        matrix = &SkMatrix::I();
57    }
58
59    // The current shader will no longer need a direct reference owned by Shader.java
60    // as all the data needed is contained within the newly created LocalMatrixShader.
61    SkASSERT(shaderHandle);
62    SkAutoTUnref<SkShader> currentShader(reinterpret_cast<SkShader*>(shaderHandle));
63    return reinterpret_cast<jlong>(currentShader->newWithLocalMatrix(*matrix));
64}
65
66///////////////////////////////////////////////////////////////////////////////////////////////
67
68static jlong BitmapShader_constructor(JNIEnv* env, jobject o, jobject jbitmap,
69                                      jint tileModeX, jint tileModeY)
70{
71    SkBitmap bitmap;
72    if (jbitmap) {
73        // Only pass a valid SkBitmap object to the constructor if the Bitmap exists. Otherwise,
74        // we'll pass an empty SkBitmap to avoid crashing/excepting for compatibility.
75        GraphicsJNI::getSkBitmap(env, jbitmap, &bitmap);
76    }
77    SkShader* s = SkShader::CreateBitmapShader(bitmap,
78                                        (SkShader::TileMode)tileModeX,
79                                        (SkShader::TileMode)tileModeY);
80
81    ThrowIAE_IfNull(env, s);
82    return reinterpret_cast<jlong>(s);
83}
84
85///////////////////////////////////////////////////////////////////////////////////////////////
86
87static jlong LinearGradient_create1(JNIEnv* env, jobject o,
88                                    jfloat x0, jfloat y0, jfloat x1, jfloat y1,
89                                    jintArray colorArray, jfloatArray posArray, jint tileMode)
90{
91    SkPoint pts[2];
92    pts[0].set(x0, y0);
93    pts[1].set(x1, y1);
94
95    size_t count = env->GetArrayLength(colorArray);
96    const jint* colorValues = env->GetIntArrayElements(colorArray, NULL);
97
98    AutoJavaFloatArray autoPos(env, posArray, count);
99#ifdef SK_SCALAR_IS_FLOAT
100    SkScalar* pos = autoPos.ptr();
101#else
102    #error Need to convert float array to SkScalar array before calling the following function.
103#endif
104
105    SkShader* shader = SkGradientShader::CreateLinear(pts,
106            reinterpret_cast<const SkColor*>(colorValues), pos, count,
107            static_cast<SkShader::TileMode>(tileMode));
108
109    env->ReleaseIntArrayElements(colorArray, const_cast<jint*>(colorValues), JNI_ABORT);
110    ThrowIAE_IfNull(env, shader);
111    return reinterpret_cast<jlong>(shader);
112}
113
114static jlong LinearGradient_create2(JNIEnv* env, jobject o,
115                                    jfloat x0, jfloat y0, jfloat x1, jfloat y1,
116                                    jint color0, jint color1, jint tileMode)
117{
118    SkPoint pts[2];
119    pts[0].set(x0, y0);
120    pts[1].set(x1, y1);
121
122    SkColor colors[2];
123    colors[0] = color0;
124    colors[1] = color1;
125
126    SkShader* s = SkGradientShader::CreateLinear(pts, colors, NULL, 2, (SkShader::TileMode)tileMode);
127
128    ThrowIAE_IfNull(env, s);
129    return reinterpret_cast<jlong>(s);
130}
131
132///////////////////////////////////////////////////////////////////////////////////////////////
133
134static jlong RadialGradient_create1(JNIEnv* env, jobject, jfloat x, jfloat y, jfloat radius,
135        jintArray colorArray, jfloatArray posArray, jint tileMode) {
136    SkPoint center;
137    center.set(x, y);
138
139    size_t      count = env->GetArrayLength(colorArray);
140    const jint* colorValues = env->GetIntArrayElements(colorArray, NULL);
141
142    AutoJavaFloatArray autoPos(env, posArray, count);
143#ifdef SK_SCALAR_IS_FLOAT
144    SkScalar* pos = autoPos.ptr();
145#else
146    #error Need to convert float array to SkScalar array before calling the following function.
147#endif
148
149    SkShader* shader = SkGradientShader::CreateRadial(center, radius,
150            reinterpret_cast<const SkColor*>(colorValues), pos, count,
151            static_cast<SkShader::TileMode>(tileMode));
152    env->ReleaseIntArrayElements(colorArray, const_cast<jint*>(colorValues),
153                                 JNI_ABORT);
154
155    ThrowIAE_IfNull(env, shader);
156    return reinterpret_cast<jlong>(shader);
157}
158
159static jlong RadialGradient_create2(JNIEnv* env, jobject, jfloat x, jfloat y, jfloat radius,
160        jint color0, jint color1, jint tileMode) {
161    SkPoint center;
162    center.set(x, y);
163
164    SkColor colors[2];
165    colors[0] = color0;
166    colors[1] = color1;
167
168    SkShader* s = SkGradientShader::CreateRadial(center, radius, colors, NULL, 2,
169            (SkShader::TileMode)tileMode);
170    ThrowIAE_IfNull(env, s);
171    return reinterpret_cast<jlong>(s);
172}
173
174///////////////////////////////////////////////////////////////////////////////
175
176static jlong SweepGradient_create1(JNIEnv* env, jobject, jfloat x, jfloat y,
177        jintArray jcolors, jfloatArray jpositions) {
178    size_t      count = env->GetArrayLength(jcolors);
179    const jint* colors = env->GetIntArrayElements(jcolors, NULL);
180
181    AutoJavaFloatArray autoPos(env, jpositions, count);
182#ifdef SK_SCALAR_IS_FLOAT
183    SkScalar* pos = autoPos.ptr();
184#else
185    #error Need to convert float array to SkScalar array before calling the following function.
186#endif
187
188    SkShader* shader = SkGradientShader::CreateSweep(x, y,
189            reinterpret_cast<const SkColor*>(colors), pos, count);
190    env->ReleaseIntArrayElements(jcolors, const_cast<jint*>(colors),
191                                 JNI_ABORT);
192    ThrowIAE_IfNull(env, shader);
193    return reinterpret_cast<jlong>(shader);
194}
195
196static jlong SweepGradient_create2(JNIEnv* env, jobject, jfloat x, jfloat y,
197        int color0, int color1) {
198    SkColor colors[2];
199    colors[0] = color0;
200    colors[1] = color1;
201    SkShader* s = SkGradientShader::CreateSweep(x, y, colors, NULL, 2);
202    ThrowIAE_IfNull(env, s);
203    return reinterpret_cast<jlong>(s);
204}
205
206///////////////////////////////////////////////////////////////////////////////////////////////
207
208static jlong ComposeShader_create1(JNIEnv* env, jobject o,
209        jlong shaderAHandle, jlong shaderBHandle, jlong modeHandle)
210{
211    SkShader* shaderA = reinterpret_cast<SkShader *>(shaderAHandle);
212    SkShader* shaderB = reinterpret_cast<SkShader *>(shaderBHandle);
213    SkXfermode* mode = reinterpret_cast<SkXfermode *>(modeHandle);
214    SkShader* shader = new SkComposeShader(shaderA, shaderB, mode);
215    return reinterpret_cast<jlong>(shader);
216}
217
218static jlong ComposeShader_create2(JNIEnv* env, jobject o,
219        jlong shaderAHandle, jlong shaderBHandle, jint xfermodeHandle)
220{
221    SkShader* shaderA = reinterpret_cast<SkShader *>(shaderAHandle);
222    SkShader* shaderB = reinterpret_cast<SkShader *>(shaderBHandle);
223    SkXfermode::Mode mode = static_cast<SkXfermode::Mode>(xfermodeHandle);
224    SkAutoTUnref<SkXfermode> xfermode(SkXfermode::Create(mode));
225    SkShader* shader = new SkComposeShader(shaderA, shaderB, xfermode.get());
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)J",   (void*)Shader_setLocalMatrix    }
239};
240
241static const JNINativeMethod gBitmapShaderMethods[] = {
242    { "nativeCreate",     "(Landroid/graphics/Bitmap;II)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