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