Shader.cpp revision b786bbdd1164cf3ca7fcfb8448c7c619a82118a0
1#include <jni.h>
2#include "GraphicsJNI.h"
3
4#include "SkShader.h"
5#include "SkGradientShader.h"
6#include "SkComposeShader.h"
7#include "SkTemplates.h"
8#include "SkXfermode.h"
9
10#include <Caches.h>
11
12#include "core_jni_helpers.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 jlong Shader_setLocalMatrix(JNIEnv* env, jobject o, jlong shaderHandle, jlong matrixHandle)
55{
56    // ensure we have a valid matrix to use
57    const SkMatrix* matrix = reinterpret_cast<SkMatrix*>(matrixHandle);
58    if (NULL == matrix) {
59        matrix = &SkMatrix::I();
60    }
61
62    // The current shader will no longer need a direct reference owned by Shader.java
63    // as all the data needed is contained within the newly created LocalMatrixShader.
64    SkASSERT(shaderHandle);
65    SkAutoTUnref<SkShader> currentShader(reinterpret_cast<SkShader*>(shaderHandle));
66
67    SkMatrix currentMatrix;
68    SkAutoTUnref<SkShader> baseShader(currentShader->refAsALocalMatrixShader(&currentMatrix));
69    if (baseShader.get()) {
70        // if the matrices are same then there is no need to allocate a new
71        // shader that is identical to the existing one.
72        if (currentMatrix == *matrix) {
73            return reinterpret_cast<jlong>(currentShader.detach());
74        }
75        return reinterpret_cast<jlong>(SkShader::CreateLocalMatrixShader(baseShader, *matrix));
76    }
77
78    return reinterpret_cast<jlong>(SkShader::CreateLocalMatrixShader(currentShader, *matrix));
79}
80
81///////////////////////////////////////////////////////////////////////////////////////////////
82
83static jlong BitmapShader_constructor(JNIEnv* env, jobject o, jobject jbitmap,
84                                      jint tileModeX, jint tileModeY)
85{
86    SkBitmap bitmap;
87    if (jbitmap) {
88        // Only pass a valid SkBitmap object to the constructor if the Bitmap exists. Otherwise,
89        // we'll pass an empty SkBitmap to avoid crashing/excepting for compatibility.
90        GraphicsJNI::getSkBitmap(env, jbitmap, &bitmap);
91    }
92    SkShader* s = SkShader::CreateBitmapShader(bitmap,
93                                        (SkShader::TileMode)tileModeX,
94                                        (SkShader::TileMode)tileModeY);
95
96    ThrowIAE_IfNull(env, s);
97    return reinterpret_cast<jlong>(s);
98}
99
100///////////////////////////////////////////////////////////////////////////////////////////////
101
102static jlong LinearGradient_create1(JNIEnv* env, jobject o,
103                                    jfloat x0, jfloat y0, jfloat x1, jfloat y1,
104                                    jintArray colorArray, jfloatArray posArray, jint tileMode)
105{
106    SkPoint pts[2];
107    pts[0].set(x0, y0);
108    pts[1].set(x1, y1);
109
110    size_t count = env->GetArrayLength(colorArray);
111    const jint* colorValues = env->GetIntArrayElements(colorArray, NULL);
112
113    AutoJavaFloatArray autoPos(env, posArray, count);
114#ifdef SK_SCALAR_IS_FLOAT
115    SkScalar* pos = autoPos.ptr();
116#else
117    #error Need to convert float array to SkScalar array before calling the following function.
118#endif
119
120    SkShader* shader = SkGradientShader::CreateLinear(pts,
121            reinterpret_cast<const SkColor*>(colorValues), pos, count,
122            static_cast<SkShader::TileMode>(tileMode));
123
124    env->ReleaseIntArrayElements(colorArray, const_cast<jint*>(colorValues), JNI_ABORT);
125    ThrowIAE_IfNull(env, shader);
126    return reinterpret_cast<jlong>(shader);
127}
128
129static jlong LinearGradient_create2(JNIEnv* env, jobject o,
130                                    jfloat x0, jfloat y0, jfloat x1, jfloat y1,
131                                    jint color0, jint color1, jint tileMode)
132{
133    SkPoint pts[2];
134    pts[0].set(x0, y0);
135    pts[1].set(x1, y1);
136
137    SkColor colors[2];
138    colors[0] = color0;
139    colors[1] = color1;
140
141    SkShader* s = SkGradientShader::CreateLinear(pts, colors, NULL, 2, (SkShader::TileMode)tileMode);
142
143    ThrowIAE_IfNull(env, s);
144    return reinterpret_cast<jlong>(s);
145}
146
147///////////////////////////////////////////////////////////////////////////////////////////////
148
149static jlong RadialGradient_create1(JNIEnv* env, jobject, jfloat x, jfloat y, jfloat radius,
150        jintArray colorArray, jfloatArray posArray, jint tileMode) {
151    SkPoint center;
152    center.set(x, y);
153
154    size_t      count = env->GetArrayLength(colorArray);
155    const jint* colorValues = env->GetIntArrayElements(colorArray, NULL);
156
157    AutoJavaFloatArray autoPos(env, posArray, count);
158#ifdef SK_SCALAR_IS_FLOAT
159    SkScalar* pos = autoPos.ptr();
160#else
161    #error Need to convert float array to SkScalar array before calling the following function.
162#endif
163
164    SkShader* shader = SkGradientShader::CreateRadial(center, radius,
165            reinterpret_cast<const SkColor*>(colorValues), pos, count,
166            static_cast<SkShader::TileMode>(tileMode));
167    env->ReleaseIntArrayElements(colorArray, const_cast<jint*>(colorValues),
168                                 JNI_ABORT);
169
170    ThrowIAE_IfNull(env, shader);
171    return reinterpret_cast<jlong>(shader);
172}
173
174static jlong RadialGradient_create2(JNIEnv* env, jobject, jfloat x, jfloat y, jfloat radius,
175        jint color0, jint color1, jint tileMode) {
176    SkPoint center;
177    center.set(x, y);
178
179    SkColor colors[2];
180    colors[0] = color0;
181    colors[1] = color1;
182
183    SkShader* s = SkGradientShader::CreateRadial(center, radius, colors, NULL, 2,
184            (SkShader::TileMode)tileMode);
185    ThrowIAE_IfNull(env, s);
186    return reinterpret_cast<jlong>(s);
187}
188
189///////////////////////////////////////////////////////////////////////////////
190
191static jlong SweepGradient_create1(JNIEnv* env, jobject, jfloat x, jfloat y,
192        jintArray jcolors, jfloatArray jpositions) {
193    size_t      count = env->GetArrayLength(jcolors);
194    const jint* colors = env->GetIntArrayElements(jcolors, NULL);
195
196    AutoJavaFloatArray autoPos(env, jpositions, count);
197#ifdef SK_SCALAR_IS_FLOAT
198    SkScalar* pos = autoPos.ptr();
199#else
200    #error Need to convert float array to SkScalar array before calling the following function.
201#endif
202
203    SkShader* shader = SkGradientShader::CreateSweep(x, y,
204            reinterpret_cast<const SkColor*>(colors), pos, count);
205    env->ReleaseIntArrayElements(jcolors, const_cast<jint*>(colors),
206                                 JNI_ABORT);
207    ThrowIAE_IfNull(env, shader);
208    return reinterpret_cast<jlong>(shader);
209}
210
211static jlong SweepGradient_create2(JNIEnv* env, jobject, jfloat x, jfloat y,
212        int color0, int color1) {
213    SkColor colors[2];
214    colors[0] = color0;
215    colors[1] = color1;
216    SkShader* s = SkGradientShader::CreateSweep(x, y, colors, NULL, 2);
217    ThrowIAE_IfNull(env, s);
218    return reinterpret_cast<jlong>(s);
219}
220
221///////////////////////////////////////////////////////////////////////////////////////////////
222
223static jlong ComposeShader_create1(JNIEnv* env, jobject o,
224        jlong shaderAHandle, jlong shaderBHandle, jlong modeHandle)
225{
226    SkShader* shaderA = reinterpret_cast<SkShader *>(shaderAHandle);
227    SkShader* shaderB = reinterpret_cast<SkShader *>(shaderBHandle);
228    SkXfermode* mode = reinterpret_cast<SkXfermode *>(modeHandle);
229    SkShader* shader = new SkComposeShader(shaderA, shaderB, mode);
230    return reinterpret_cast<jlong>(shader);
231}
232
233static jlong ComposeShader_create2(JNIEnv* env, jobject o,
234        jlong shaderAHandle, jlong shaderBHandle, jint xfermodeHandle)
235{
236    SkShader* shaderA = reinterpret_cast<SkShader *>(shaderAHandle);
237    SkShader* shaderB = reinterpret_cast<SkShader *>(shaderBHandle);
238    SkXfermode::Mode mode = static_cast<SkXfermode::Mode>(xfermodeHandle);
239    SkAutoTUnref<SkXfermode> xfermode(SkXfermode::Create(mode));
240    SkShader* shader = new SkComposeShader(shaderA, shaderB, xfermode.get());
241    return reinterpret_cast<jlong>(shader);
242}
243
244///////////////////////////////////////////////////////////////////////////////////////////////
245
246static JNINativeMethod gColorMethods[] = {
247    { "nativeRGBToHSV",     "(III[F)V", (void*)Color_RGBToHSV   },
248    { "nativeHSVToColor",   "(I[F)I",   (void*)Color_HSVToColor }
249};
250
251static JNINativeMethod gShaderMethods[] = {
252    { "nativeDestructor",        "(J)V",    (void*)Shader_destructor        },
253    { "nativeSetLocalMatrix",    "(JJ)J",   (void*)Shader_setLocalMatrix    }
254};
255
256static JNINativeMethod gBitmapShaderMethods[] = {
257    { "nativeCreate",     "(Landroid/graphics/Bitmap;II)J",  (void*)BitmapShader_constructor },
258};
259
260static JNINativeMethod gLinearGradientMethods[] = {
261    { "nativeCreate1",     "(FFFF[I[FI)J",  (void*)LinearGradient_create1     },
262    { "nativeCreate2",     "(FFFFIII)J",    (void*)LinearGradient_create2     },
263};
264
265static JNINativeMethod gRadialGradientMethods[] = {
266    { "nativeCreate1",     "(FFF[I[FI)J",  (void*)RadialGradient_create1     },
267    { "nativeCreate2",     "(FFFIII)J",    (void*)RadialGradient_create2     },
268};
269
270static JNINativeMethod gSweepGradientMethods[] = {
271    { "nativeCreate1",     "(FF[I[F)J",  (void*)SweepGradient_create1     },
272    { "nativeCreate2",     "(FFII)J",    (void*)SweepGradient_create2     },
273};
274
275static JNINativeMethod gComposeShaderMethods[] = {
276    { "nativeCreate1",      "(JJJ)J",   (void*)ComposeShader_create1     },
277    { "nativeCreate2",      "(JJI)J",   (void*)ComposeShader_create2     },
278};
279
280int register_android_graphics_Shader(JNIEnv* env)
281{
282    android::RegisterMethodsOrDie(env, "android/graphics/Color", gColorMethods,
283                                  NELEM(gColorMethods));
284    android::RegisterMethodsOrDie(env, "android/graphics/Shader", gShaderMethods,
285                                  NELEM(gShaderMethods));
286    android::RegisterMethodsOrDie(env, "android/graphics/BitmapShader", gBitmapShaderMethods,
287                                  NELEM(gBitmapShaderMethods));
288    android::RegisterMethodsOrDie(env, "android/graphics/LinearGradient", gLinearGradientMethods,
289                                  NELEM(gLinearGradientMethods));
290    android::RegisterMethodsOrDie(env, "android/graphics/RadialGradient", gRadialGradientMethods,
291                                  NELEM(gRadialGradientMethods));
292    android::RegisterMethodsOrDie(env, "android/graphics/SweepGradient", gSweepGradientMethods,
293                                  NELEM(gSweepGradientMethods));
294    android::RegisterMethodsOrDie(env, "android/graphics/ComposeShader", gComposeShaderMethods,
295                                  NELEM(gComposeShaderMethods));
296
297    return 0;
298}
299