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