Shader.cpp revision 26b4f598c8b1e99b43261614a6861785638c8c00
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 <Caches.h>
12
13#include "core_jni_helpers.h"
14
15using namespace android::uirenderer;
16
17static void ThrowIAE_IfNull(JNIEnv* env, void* ptr) {
18    if (NULL == ptr) {
19        doThrowIAE(env);
20    }
21}
22
23static void Color_RGBToHSV(JNIEnv* env, jobject, jint red, jint green, jint blue, jfloatArray hsvArray)
24{
25    SkScalar hsv[3];
26    SkRGBToHSV(red, green, blue, hsv);
27
28    AutoJavaFloatArray  autoHSV(env, hsvArray, 3);
29    float* values = autoHSV.ptr();
30    for (int i = 0; i < 3; i++) {
31        values[i] = SkScalarToFloat(hsv[i]);
32    }
33}
34
35static jint Color_HSVToColor(JNIEnv* env, jobject, jint alpha, jfloatArray hsvArray)
36{
37    AutoJavaFloatArray  autoHSV(env, hsvArray, 3);
38#ifdef SK_SCALAR_IS_FLOAT
39    SkScalar*   hsv = autoHSV.ptr();
40#else
41    #error Need to convert float array to SkScalar array before calling the following function.
42#endif
43
44    return static_cast<jint>(SkHSVToColor(alpha, hsv));
45}
46
47///////////////////////////////////////////////////////////////////////////////////////////////
48
49static void Shader_destructor(JNIEnv* env, jobject o, jlong shaderHandle, jlong shaderWithLMHandle)
50{
51    SkShader* shader = reinterpret_cast<SkShader*>(shaderHandle);
52    SkSafeUnref(shader);
53}
54
55static jlong Shader_setLocalMatrix(JNIEnv* env, jobject o, jlong shaderHandle, jlong matrixHandle)
56{
57    // ensure we have a valid matrix to use
58    const SkMatrix* matrix = reinterpret_cast<SkMatrix*>(matrixHandle);
59    if (NULL == matrix) {
60        matrix = &SkMatrix::I();
61    }
62
63    // The current shader will no longer need a direct reference owned by Shader.java
64    // as all the data needed is contained within the newly created LocalMatrixShader.
65    SkASSERT(shaderHandle);
66    SkAutoTUnref<SkShader> currentShader(reinterpret_cast<SkShader*>(shaderHandle));
67
68    SkMatrix currentMatrix;
69    SkAutoTUnref<SkShader> baseShader(currentShader->refAsALocalMatrixShader(&currentMatrix));
70    if (baseShader.get()) {
71        // if the matrices are same then there is no need to allocate a new
72        // shader that is identical to the existing one.
73        if (currentMatrix == *matrix) {
74            return reinterpret_cast<jlong>(currentShader.detach());
75        }
76        return reinterpret_cast<jlong>(SkShader::CreateLocalMatrixShader(baseShader, *matrix));
77    }
78
79    return reinterpret_cast<jlong>(SkShader::CreateLocalMatrixShader(currentShader, *matrix));
80}
81
82///////////////////////////////////////////////////////////////////////////////////////////////
83
84static jlong BitmapShader_constructor(JNIEnv* env, jobject o, jlong bitmapHandle,
85                                      jint tileModeX, jint tileModeY)
86{
87    const SkBitmap* bitmap = reinterpret_cast<SkBitmap*>(bitmapHandle);
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 porterDuffModeHandle)
231{
232    SkShader* shaderA = reinterpret_cast<SkShader *>(shaderAHandle);
233    SkShader* shaderB = reinterpret_cast<SkShader *>(shaderBHandle);
234    SkPorterDuff::Mode porterDuffMode = static_cast<SkPorterDuff::Mode>(porterDuffModeHandle);
235    SkAutoUnref au(SkPorterDuff::CreateXfermode(porterDuffMode));
236    SkXfermode* mode = (SkXfermode*) au.get();
237    SkShader* shader = new SkComposeShader(shaderA, shaderB, mode);
238    return reinterpret_cast<jlong>(shader);
239}
240
241///////////////////////////////////////////////////////////////////////////////////////////////
242
243static JNINativeMethod gColorMethods[] = {
244    { "nativeRGBToHSV",     "(III[F)V", (void*)Color_RGBToHSV   },
245    { "nativeHSVToColor",   "(I[F)I",   (void*)Color_HSVToColor }
246};
247
248static JNINativeMethod gShaderMethods[] = {
249    { "nativeDestructor",        "(J)V",    (void*)Shader_destructor        },
250    { "nativeSetLocalMatrix",    "(JJ)J",   (void*)Shader_setLocalMatrix    }
251};
252
253static JNINativeMethod gBitmapShaderMethods[] = {
254    { "nativeCreate",     "(JII)J",  (void*)BitmapShader_constructor },
255};
256
257static JNINativeMethod gLinearGradientMethods[] = {
258    { "nativeCreate1",     "(FFFF[I[FI)J",  (void*)LinearGradient_create1     },
259    { "nativeCreate2",     "(FFFFIII)J",    (void*)LinearGradient_create2     },
260};
261
262static JNINativeMethod gRadialGradientMethods[] = {
263    { "nativeCreate1",     "(FFF[I[FI)J",  (void*)RadialGradient_create1     },
264    { "nativeCreate2",     "(FFFIII)J",    (void*)RadialGradient_create2     },
265};
266
267static JNINativeMethod gSweepGradientMethods[] = {
268    { "nativeCreate1",     "(FF[I[F)J",  (void*)SweepGradient_create1     },
269    { "nativeCreate2",     "(FFII)J",    (void*)SweepGradient_create2     },
270};
271
272static JNINativeMethod gComposeShaderMethods[] = {
273    { "nativeCreate1",      "(JJJ)J",   (void*)ComposeShader_create1     },
274    { "nativeCreate2",      "(JJI)J",   (void*)ComposeShader_create2     },
275};
276
277int register_android_graphics_Shader(JNIEnv* env)
278{
279    android::RegisterMethodsOrDie(env, "android/graphics/Color", gColorMethods,
280                                  NELEM(gColorMethods));
281    android::RegisterMethodsOrDie(env, "android/graphics/Shader", gShaderMethods,
282                                  NELEM(gShaderMethods));
283    android::RegisterMethodsOrDie(env, "android/graphics/BitmapShader", gBitmapShaderMethods,
284                                  NELEM(gBitmapShaderMethods));
285    android::RegisterMethodsOrDie(env, "android/graphics/LinearGradient", gLinearGradientMethods,
286                                  NELEM(gLinearGradientMethods));
287    android::RegisterMethodsOrDie(env, "android/graphics/RadialGradient", gRadialGradientMethods,
288                                  NELEM(gRadialGradientMethods));
289    android::RegisterMethodsOrDie(env, "android/graphics/SweepGradient", gSweepGradientMethods,
290                                  NELEM(gSweepGradientMethods));
291    android::RegisterMethodsOrDie(env, "android/graphics/ComposeShader", gComposeShaderMethods,
292                                  NELEM(gComposeShaderMethods));
293
294    return 0;
295}
296