Shader.cpp revision ed5d5fb434eb2169f14d06649336f211117e2bee
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
13using namespace android::uirenderer;
14
15static void ThrowIAE_IfNull(JNIEnv* env, void* ptr) {
16    if (NULL == ptr) {
17        doThrowIAE(env);
18    }
19}
20
21static void Color_RGBToHSV(JNIEnv* env, jobject, jint red, jint green, jint blue, jfloatArray hsvArray)
22{
23    SkScalar hsv[3];
24    SkRGBToHSV(red, green, blue, hsv);
25
26    AutoJavaFloatArray  autoHSV(env, hsvArray, 3);
27    float* values = autoHSV.ptr();
28    for (int i = 0; i < 3; i++) {
29        values[i] = SkScalarToFloat(hsv[i]);
30    }
31}
32
33static jint Color_HSVToColor(JNIEnv* env, jobject, jint alpha, jfloatArray hsvArray)
34{
35    AutoJavaFloatArray  autoHSV(env, hsvArray, 3);
36#ifdef SK_SCALAR_IS_FLOAT
37    SkScalar*   hsv = autoHSV.ptr();
38#else
39    #error Need to convert float array to SkScalar array before calling the following function.
40#endif
41
42    return static_cast<jint>(SkHSVToColor(alpha, hsv));
43}
44
45///////////////////////////////////////////////////////////////////////////////////////////////
46
47static void Shader_destructor(JNIEnv* env, jobject o, jlong shaderHandle, jlong shaderWithLMHandle)
48{
49    SkShader* shader = reinterpret_cast<SkShader*>(shaderHandle);
50    SkSafeUnref(shader);
51}
52
53static jlong Shader_setLocalMatrix(JNIEnv* env, jobject o, jlong shaderHandle, jlong matrixHandle)
54{
55    // ensure we have a valid matrix to use
56    const SkMatrix* matrix = reinterpret_cast<SkMatrix*>(matrixHandle);
57    if (NULL == matrix) {
58        matrix = &SkMatrix::I();
59    }
60
61    // The current shader will no longer need a direct reference owned by Shader.java
62    // as all the data needed is contained within the newly created LocalMatrixShader.
63    SkASSERT(shaderHandle);
64    SkAutoTUnref<SkShader> currentShader(reinterpret_cast<SkShader*>(shaderHandle));
65
66    SkMatrix currentMatrix;
67    SkAutoTUnref<SkShader> baseShader(currentShader->refAsALocalMatrixShader(&currentMatrix));
68    if (baseShader.get()) {
69        // if the matrices are same then there is no need to allocate a new
70        // shader that is identical to the existing one.
71        if (currentMatrix == *matrix) {
72            return reinterpret_cast<jlong>(currentShader.detach());
73        }
74        return reinterpret_cast<jlong>(SkShader::CreateLocalMatrixShader(baseShader, *matrix));
75    }
76
77    return reinterpret_cast<jlong>(SkShader::CreateLocalMatrixShader(currentShader, *matrix));
78}
79
80///////////////////////////////////////////////////////////////////////////////////////////////
81
82static jlong BitmapShader_constructor(JNIEnv* env, jobject o, jlong bitmapHandle,
83                                      jint tileModeX, jint tileModeY)
84{
85    const SkBitmap* bitmap = reinterpret_cast<SkBitmap*>(bitmapHandle);
86    SkShader* s = SkShader::CreateBitmapShader(*bitmap,
87                                        (SkShader::TileMode)tileModeX,
88                                        (SkShader::TileMode)tileModeY);
89
90    ThrowIAE_IfNull(env, s);
91    return reinterpret_cast<jlong>(s);
92}
93
94///////////////////////////////////////////////////////////////////////////////////////////////
95
96static jlong LinearGradient_create1(JNIEnv* env, jobject o,
97                                    jfloat x0, jfloat y0, jfloat x1, jfloat y1,
98                                    jintArray colorArray, jfloatArray posArray, jint tileMode)
99{
100    SkPoint pts[2];
101    pts[0].set(x0, y0);
102    pts[1].set(x1, y1);
103
104    size_t count = env->GetArrayLength(colorArray);
105    const jint* colorValues = env->GetIntArrayElements(colorArray, NULL);
106
107    AutoJavaFloatArray autoPos(env, posArray, count);
108#ifdef SK_SCALAR_IS_FLOAT
109    SkScalar* pos = autoPos.ptr();
110#else
111    #error Need to convert float array to SkScalar array before calling the following function.
112#endif
113
114    SkShader* shader = SkGradientShader::CreateLinear(pts,
115            reinterpret_cast<const SkColor*>(colorValues), pos, count,
116            static_cast<SkShader::TileMode>(tileMode));
117
118    env->ReleaseIntArrayElements(colorArray, const_cast<jint*>(colorValues), JNI_ABORT);
119    ThrowIAE_IfNull(env, shader);
120    return reinterpret_cast<jlong>(shader);
121}
122
123static jlong LinearGradient_create2(JNIEnv* env, jobject o,
124                                    jfloat x0, jfloat y0, jfloat x1, jfloat y1,
125                                    jint color0, jint color1, jint tileMode)
126{
127    SkPoint pts[2];
128    pts[0].set(x0, y0);
129    pts[1].set(x1, y1);
130
131    SkColor colors[2];
132    colors[0] = color0;
133    colors[1] = color1;
134
135    SkShader* s = SkGradientShader::CreateLinear(pts, colors, NULL, 2, (SkShader::TileMode)tileMode);
136
137    ThrowIAE_IfNull(env, s);
138    return reinterpret_cast<jlong>(s);
139}
140
141///////////////////////////////////////////////////////////////////////////////////////////////
142
143static jlong RadialGradient_create1(JNIEnv* env, jobject, jfloat x, jfloat y, jfloat radius,
144        jintArray colorArray, jfloatArray posArray, jint tileMode) {
145    SkPoint center;
146    center.set(x, y);
147
148    size_t      count = env->GetArrayLength(colorArray);
149    const jint* colorValues = env->GetIntArrayElements(colorArray, NULL);
150
151    AutoJavaFloatArray autoPos(env, posArray, count);
152#ifdef SK_SCALAR_IS_FLOAT
153    SkScalar* pos = autoPos.ptr();
154#else
155    #error Need to convert float array to SkScalar array before calling the following function.
156#endif
157
158    SkShader* shader = SkGradientShader::CreateRadial(center, radius,
159            reinterpret_cast<const SkColor*>(colorValues), pos, count,
160            static_cast<SkShader::TileMode>(tileMode));
161    env->ReleaseIntArrayElements(colorArray, const_cast<jint*>(colorValues),
162                                 JNI_ABORT);
163
164    ThrowIAE_IfNull(env, shader);
165    return reinterpret_cast<jlong>(shader);
166}
167
168static jlong RadialGradient_create2(JNIEnv* env, jobject, jfloat x, jfloat y, jfloat radius,
169        jint color0, jint color1, jint tileMode) {
170    SkPoint center;
171    center.set(x, y);
172
173    SkColor colors[2];
174    colors[0] = color0;
175    colors[1] = color1;
176
177    SkShader* s = SkGradientShader::CreateRadial(center, radius, colors, NULL, 2,
178            (SkShader::TileMode)tileMode);
179    ThrowIAE_IfNull(env, s);
180    return reinterpret_cast<jlong>(s);
181}
182
183///////////////////////////////////////////////////////////////////////////////
184
185static jlong SweepGradient_create1(JNIEnv* env, jobject, jfloat x, jfloat y,
186        jintArray jcolors, jfloatArray jpositions) {
187    size_t      count = env->GetArrayLength(jcolors);
188    const jint* colors = env->GetIntArrayElements(jcolors, NULL);
189
190    AutoJavaFloatArray autoPos(env, jpositions, count);
191#ifdef SK_SCALAR_IS_FLOAT
192    SkScalar* pos = autoPos.ptr();
193#else
194    #error Need to convert float array to SkScalar array before calling the following function.
195#endif
196
197    SkShader* shader = SkGradientShader::CreateSweep(x, y,
198            reinterpret_cast<const SkColor*>(colors), pos, count);
199    env->ReleaseIntArrayElements(jcolors, const_cast<jint*>(colors),
200                                 JNI_ABORT);
201    ThrowIAE_IfNull(env, shader);
202    return reinterpret_cast<jlong>(shader);
203}
204
205static jlong SweepGradient_create2(JNIEnv* env, jobject, jfloat x, jfloat y,
206        int color0, int color1) {
207    SkColor colors[2];
208    colors[0] = color0;
209    colors[1] = color1;
210    SkShader* s = SkGradientShader::CreateSweep(x, y, colors, NULL, 2);
211    ThrowIAE_IfNull(env, s);
212    return reinterpret_cast<jlong>(s);
213}
214
215///////////////////////////////////////////////////////////////////////////////////////////////
216
217static jlong ComposeShader_create1(JNIEnv* env, jobject o,
218        jlong shaderAHandle, jlong shaderBHandle, jlong modeHandle)
219{
220    SkShader* shaderA = reinterpret_cast<SkShader *>(shaderAHandle);
221    SkShader* shaderB = reinterpret_cast<SkShader *>(shaderBHandle);
222    SkXfermode* mode = reinterpret_cast<SkXfermode *>(modeHandle);
223    SkShader* shader = new SkComposeShader(shaderA, shaderB, mode);
224    return reinterpret_cast<jlong>(shader);
225}
226
227static jlong ComposeShader_create2(JNIEnv* env, jobject o,
228        jlong shaderAHandle, jlong shaderBHandle, jint porterDuffModeHandle)
229{
230    SkShader* shaderA = reinterpret_cast<SkShader *>(shaderAHandle);
231    SkShader* shaderB = reinterpret_cast<SkShader *>(shaderBHandle);
232    SkPorterDuff::Mode porterDuffMode = static_cast<SkPorterDuff::Mode>(porterDuffModeHandle);
233    SkAutoUnref au(SkPorterDuff::CreateXfermode(porterDuffMode));
234    SkXfermode* mode = (SkXfermode*) au.get();
235    SkShader* shader = new SkComposeShader(shaderA, shaderB, mode);
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
275#include <android_runtime/AndroidRuntime.h>
276
277#define REG(env, name, array)                                                                       \
278    result = android::AndroidRuntime::registerNativeMethods(env, name, array, SK_ARRAY_COUNT(array));  \
279    if (result < 0) return result
280
281int register_android_graphics_Shader(JNIEnv* env)
282{
283    int result;
284
285    REG(env, "android/graphics/Color", gColorMethods);
286    REG(env, "android/graphics/Shader", gShaderMethods);
287    REG(env, "android/graphics/BitmapShader", gBitmapShaderMethods);
288    REG(env, "android/graphics/LinearGradient", gLinearGradientMethods);
289    REG(env, "android/graphics/RadialGradient", gRadialGradientMethods);
290    REG(env, "android/graphics/SweepGradient", gSweepGradientMethods);
291    REG(env, "android/graphics/ComposeShader", gComposeShaderMethods);
292
293    return result;
294}
295