Shader.cpp revision 48daa54d31fc59ec969dcff65eb3cbb0ce879a8d
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 <SkiaShader.h>
12
13using namespace android::uirenderer;
14
15static struct {
16    jclass clazz;
17    jfieldID shader;
18} gShaderClassInfo;
19
20static void ThrowIAE_IfNull(JNIEnv* env, void* ptr) {
21    if (NULL == ptr) {
22        doThrowIAE(env);
23    }
24}
25
26static void Color_RGBToHSV(JNIEnv* env, jobject, int red, int green, int blue, jfloatArray hsvArray)
27{
28    SkScalar hsv[3];
29    SkRGBToHSV(red, green, blue, hsv);
30
31    AutoJavaFloatArray  autoHSV(env, hsvArray, 3);
32    float* values = autoHSV.ptr();
33    for (int i = 0; i < 3; i++) {
34        values[i] = SkScalarToFloat(hsv[i]);
35    }
36}
37
38static int Color_HSVToColor(JNIEnv* env, jobject, int alpha, jfloatArray hsvArray)
39{
40    AutoJavaFloatArray  autoHSV(env, hsvArray, 3);
41    float*      values = autoHSV.ptr();;
42    SkScalar    hsv[3];
43
44    for (int i = 0; i < 3; i++) {
45        hsv[i] = SkFloatToScalar(values[i]);
46    }
47
48    return SkHSVToColor(alpha, hsv);
49}
50
51///////////////////////////////////////////////////////////////////////////////////////////////
52
53static void Shader_destructor(JNIEnv* env, jobject o, SkShader* shader, SkiaShader* skiaShader)
54{
55    delete skiaShader;
56    shader->safeUnref();
57}
58
59static bool Shader_getLocalMatrix(JNIEnv* env, jobject, const SkShader* shader, SkMatrix* matrix)
60{
61    return shader ? shader->getLocalMatrix(matrix) : false;
62}
63
64static void Shader_setLocalMatrix(JNIEnv* env, jobject o, SkShader* shader, SkiaShader* skiaShader,
65        const SkMatrix* matrix)
66{
67    if (shader) {
68        if (NULL == matrix) {
69            shader->resetLocalMatrix();
70        }
71        else {
72            shader->setLocalMatrix(*matrix);
73        }
74#ifdef USE_OPENGL_RENDERER
75        skiaShader->setMatrix(const_cast<SkMatrix*>(matrix));
76#endif
77    }
78}
79
80///////////////////////////////////////////////////////////////////////////////////////////////
81
82static SkShader* BitmapShader_constructor(JNIEnv* env, jobject o, const SkBitmap* bitmap,
83                                          int tileModeX, int tileModeY)
84{
85    SkShader* s = SkShader::CreateBitmapShader(*bitmap,
86                                        (SkShader::TileMode)tileModeX,
87                                        (SkShader::TileMode)tileModeY);
88
89    ThrowIAE_IfNull(env, s);
90    return s;
91}
92
93static SkiaShader* BitmapShader_postConstructor(JNIEnv* env, jobject o, SkShader* shader,
94        SkBitmap* bitmap, int tileModeX, int tileModeY) {
95#ifdef USE_OPENGL_RENDERER
96    SkiaShader* skiaShader = new SkiaBitmapShader(bitmap, shader,
97            static_cast<SkShader::TileMode>(tileModeX), static_cast<SkShader::TileMode>(tileModeY),
98            NULL, (shader->getFlags() & SkShader::kOpaqueAlpha_Flag) == 0);
99    return skiaShader;
100#else
101    return NULL;
102#endif
103}
104
105///////////////////////////////////////////////////////////////////////////////////////////////
106
107static SkShader* LinearGradient_create1(JNIEnv* env, jobject o,
108                                        float x0, float y0, float x1, float y1,
109                                        jintArray colorArray, jfloatArray posArray, int tileMode)
110{
111    SkPoint pts[2];
112    pts[0].set(SkFloatToScalar(x0), SkFloatToScalar(y0));
113    pts[1].set(SkFloatToScalar(x1), SkFloatToScalar(y1));
114
115    size_t count = env->GetArrayLength(colorArray);
116    const jint* colorValues = env->GetIntArrayElements(colorArray, NULL);
117
118    SkAutoSTMalloc<8, SkScalar> storage(posArray ? count : 0);
119    SkScalar*                   pos = NULL;
120
121    if (posArray) {
122        AutoJavaFloatArray autoPos(env, posArray, count);
123        const float* posValues = autoPos.ptr();
124        pos = (SkScalar*)storage.get();
125        for (size_t i = 0; i < count; i++) {
126            pos[i] = SkFloatToScalar(posValues[i]);
127        }
128    }
129
130    SkShader* shader = SkGradientShader::CreateLinear(pts,
131                                reinterpret_cast<const SkColor*>(colorValues),
132                                pos, count,
133                                static_cast<SkShader::TileMode>(tileMode));
134
135    env->ReleaseIntArrayElements(colorArray, const_cast<jint*>(colorValues), JNI_ABORT);
136    ThrowIAE_IfNull(env, shader);
137    return shader;
138}
139
140static SkiaShader* LinearGradient_postCreate1(JNIEnv* env, jobject o, SkShader* shader,
141        float x0, float y0, float x1, float y1, jintArray colorArray,
142        jfloatArray posArray, int tileMode) {
143#ifdef USE_OPENGL_RENDERER
144    size_t count = env->GetArrayLength(colorArray);
145    const jint* colorValues = env->GetIntArrayElements(colorArray, NULL);
146
147    jfloat* storedBounds = new jfloat[4];
148    storedBounds[0] = x0; storedBounds[1] = y0;
149    storedBounds[2] = x1; storedBounds[3] = y1;
150    jfloat* storedPositions = new jfloat[count];
151    uint32_t* storedColors = new uint32_t[count];
152    for (size_t i = 0; i < count; i++) {
153        storedColors[i] = static_cast<uint32_t>(colorValues[i]);
154    }
155
156    if (posArray) {
157        AutoJavaFloatArray autoPos(env, posArray, count);
158        const float* posValues = autoPos.ptr();
159        for (size_t i = 0; i < count; i++) {
160            storedPositions[i] = posValues[i];
161        }
162    } else {
163        storedPositions[0] = 0.0f;
164        storedPositions[1] = 1.0f;
165    }
166
167    SkiaShader* skiaShader = new SkiaLinearGradientShader(storedBounds, storedColors,
168            storedPositions, count, shader, static_cast<SkShader::TileMode>(tileMode), NULL,
169            (shader->getFlags() & SkShader::kOpaqueAlpha_Flag) == 0);
170
171    env->ReleaseIntArrayElements(colorArray, const_cast<jint*>(colorValues), JNI_ABORT);
172    return skiaShader;
173#else
174    return NULL;
175#endif
176}
177
178static SkiaShader* LinearGradient_postCreate2(JNIEnv* env, jobject o, SkShader* shader,
179        float x0, float y0, float x1, float y1, int color0, int color1, int tileMode) {
180#ifdef USE_OPENGL_RENDERER
181    float* storedBounds = new float[4];
182    storedBounds[0] = x0; storedBounds[1] = y0;
183    storedBounds[2] = x1; storedBounds[3] = y1;
184
185    float* storedPositions = new float[2];
186    storedPositions[0] = 0.0f;
187    storedPositions[1] = 1.0f;
188
189    uint32_t* storedColors = new uint32_t[2];
190    storedColors[0] = static_cast<uint32_t>(color0);
191    storedColors[1] = static_cast<uint32_t>(color1);
192
193    SkiaShader* skiaShader = new SkiaLinearGradientShader(storedBounds, storedColors,
194            storedPositions, 2, shader, static_cast<SkShader::TileMode>(tileMode), NULL,
195            (shader->getFlags() & SkShader::kOpaqueAlpha_Flag) == 0);
196
197    return skiaShader;
198#else
199    return NULL;
200#endif
201}
202
203static SkShader* LinearGradient_create2(JNIEnv* env, jobject o,
204                                        float x0, float y0, float x1, float y1,
205                                        int color0, int color1, int tileMode)
206{
207    SkPoint pts[2];
208    pts[0].set(SkFloatToScalar(x0), SkFloatToScalar(y0));
209    pts[1].set(SkFloatToScalar(x1), SkFloatToScalar(y1));
210
211    SkColor colors[2];
212    colors[0] = color0;
213    colors[1] = color1;
214
215    SkShader* s = SkGradientShader::CreateLinear(pts, colors, NULL, 2, (SkShader::TileMode)tileMode);
216
217    ThrowIAE_IfNull(env, s);
218    return s;
219}
220
221///////////////////////////////////////////////////////////////////////////////////////////////
222
223static SkShader* RadialGradient_create1(JNIEnv* env, jobject,
224                                        float x, float y, float radius,
225                                        jintArray colorArray, jfloatArray posArray, int tileMode)
226{
227    SkPoint center;
228    center.set(SkFloatToScalar(x), SkFloatToScalar(y));
229
230    size_t      count = env->GetArrayLength(colorArray);
231    const jint* colorValues = env->GetIntArrayElements(colorArray, NULL);
232
233    SkAutoSTMalloc<8, SkScalar> storage(posArray ? count : 0);
234    SkScalar*                   pos = NULL;
235
236    if (posArray) {
237        AutoJavaFloatArray autoPos(env, posArray, count);
238        const float* posValues = autoPos.ptr();
239        pos = (SkScalar*)storage.get();
240        for (size_t i = 0; i < count; i++)
241            pos[i] = SkFloatToScalar(posValues[i]);
242    }
243
244    SkShader* shader = SkGradientShader::CreateRadial(center,
245                                SkFloatToScalar(radius),
246                                reinterpret_cast<const SkColor*>(colorValues),
247                                pos, count,
248                                static_cast<SkShader::TileMode>(tileMode));
249    env->ReleaseIntArrayElements(colorArray, const_cast<jint*>(colorValues),
250                                 JNI_ABORT);
251
252    ThrowIAE_IfNull(env, shader);
253    return shader;
254}
255
256static SkShader* RadialGradient_create2(JNIEnv* env, jobject,
257                                        float x, float y, float radius,
258                                        int color0, int color1, int tileMode)
259{
260    SkPoint center;
261    center.set(SkFloatToScalar(x), SkFloatToScalar(y));
262
263    SkColor colors[2];
264    colors[0] = color0;
265    colors[1] = color1;
266
267    SkShader* s = SkGradientShader::CreateRadial(center, SkFloatToScalar(radius), colors, NULL,
268                                          2, (SkShader::TileMode)tileMode);
269    ThrowIAE_IfNull(env, s);
270    return s;
271}
272
273///////////////////////////////////////////////////////////////////////////////
274
275static SkShader* SweepGradient_create1(JNIEnv* env, jobject, float x, float y,
276                                    jintArray jcolors, jfloatArray jpositions)
277{
278    size_t      count = env->GetArrayLength(jcolors);
279    const jint* colors = env->GetIntArrayElements(jcolors, NULL);
280
281    SkAutoSTMalloc<8, SkScalar> storage(jpositions ? count : 0);
282    SkScalar*                   pos = NULL;
283
284    if (NULL != jpositions) {
285        AutoJavaFloatArray autoPos(env, jpositions, count);
286        const float* posValues = autoPos.ptr();
287        pos = (SkScalar*)storage.get();
288        for (size_t i = 0; i < count; i++) {
289            pos[i] = SkFloatToScalar(posValues[i]);
290        }
291    }
292
293    SkShader* shader = SkGradientShader::CreateSweep(SkFloatToScalar(x),
294                                     SkFloatToScalar(y),
295                                     reinterpret_cast<const SkColor*>(colors),
296                                     pos, count);
297    env->ReleaseIntArrayElements(jcolors, const_cast<jint*>(colors),
298                                 JNI_ABORT);
299    ThrowIAE_IfNull(env, shader);
300    return shader;
301}
302
303static SkShader* SweepGradient_create2(JNIEnv* env, jobject, float x, float y,
304                                        int color0, int color1)
305{
306    SkColor colors[2];
307    colors[0] = color0;
308    colors[1] = color1;
309    SkShader* s = SkGradientShader::CreateSweep(SkFloatToScalar(x), SkFloatToScalar(y),
310                                         colors, NULL, 2);
311    ThrowIAE_IfNull(env, s);
312    return s;
313}
314
315///////////////////////////////////////////////////////////////////////////////////////////////
316
317static SkShader* ComposeShader_create1(JNIEnv* env, jobject o,
318        SkShader* shaderA, SkShader* shaderB, SkXfermode* mode)
319{
320    return new SkComposeShader(shaderA, shaderB, mode);
321}
322
323static SkShader* ComposeShader_create2(JNIEnv* env, jobject o,
324        SkShader* shaderA, SkShader* shaderB, SkPorterDuff::Mode porterDuffMode)
325{
326    SkAutoUnref au(SkPorterDuff::CreateXfermode(porterDuffMode));
327    SkXfermode* mode = (SkXfermode*) au.get();
328    return new SkComposeShader(shaderA, shaderB, mode);
329}
330
331static SkiaShader* ComposeShader_postCreate2(JNIEnv* env, jobject o, SkShader* shader,
332        SkiaShader* shaderA, SkiaShader* shaderB, SkPorterDuff::Mode porterDuffMode) {
333#ifdef USE_OPENGL_RENDERER
334    SkXfermode::Mode mode = SkPorterDuff::ToXfermodeMode(porterDuffMode);
335    return new SkiaComposeShader(shaderA, shaderB, mode, shader);
336#else
337    return NULL;
338#endif
339}
340
341static SkiaShader* ComposeShader_postCreate1(JNIEnv* env, jobject o, SkShader* shader,
342        SkiaShader* shaderA, SkiaShader* shaderB, SkXfermode* mode) {
343#ifdef USE_OPENGL_RENDERER
344    SkXfermode::Mode skiaMode;
345    if (!SkXfermode::IsMode(mode, &skiaMode)) {
346        // TODO: Support other modes
347        skiaMode = SkXfermode::kSrcOver_Mode;
348    }
349    return new SkiaComposeShader(shaderA, shaderB, skiaMode, shader);
350#else
351    return NULL;
352#endif
353}
354
355///////////////////////////////////////////////////////////////////////////////////////////////
356
357static JNINativeMethod gColorMethods[] = {
358    { "nativeRGBToHSV",     "(III[F)V", (void*)Color_RGBToHSV   },
359    { "nativeHSVToColor",   "(I[F)I",   (void*)Color_HSVToColor }
360};
361
362static JNINativeMethod gShaderMethods[] = {
363    { "nativeDestructor",        "(II)V",    (void*)Shader_destructor        },
364    { "nativeGetLocalMatrix",    "(II)Z",    (void*)Shader_getLocalMatrix    },
365    { "nativeSetLocalMatrix",    "(III)V",   (void*)Shader_setLocalMatrix    }
366};
367
368static JNINativeMethod gBitmapShaderMethods[] = {
369    { "nativeCreate",     "(III)I",  (void*)BitmapShader_constructor },
370    { "nativePostCreate", "(IIII)I", (void*)BitmapShader_postConstructor }
371};
372
373static JNINativeMethod gLinearGradientMethods[] = {
374    { "nativeCreate1",     "(FFFF[I[FI)I",  (void*)LinearGradient_create1     },
375    { "nativeCreate2",     "(FFFFIII)I",    (void*)LinearGradient_create2     },
376    { "nativePostCreate1", "(IFFFF[I[FI)I", (void*)LinearGradient_postCreate1 },
377    { "nativePostCreate2", "(IFFFFIII)I",   (void*)LinearGradient_postCreate2 }
378};
379
380static JNINativeMethod gRadialGradientMethods[] = {
381    {"nativeCreate1",   "(FFF[I[FI)I",  (void*)RadialGradient_create1   },
382    {"nativeCreate2",   "(FFFIII)I",    (void*)RadialGradient_create2   }
383};
384
385static JNINativeMethod gSweepGradientMethods[] = {
386    {"nativeCreate1",   "(FF[I[F)I",  (void*)SweepGradient_create1   },
387    {"nativeCreate2",   "(FFII)I",    (void*)SweepGradient_create2   }
388};
389
390static JNINativeMethod gComposeShaderMethods[] = {
391    {"nativeCreate1",      "(III)I",   (void*)ComposeShader_create1     },
392    {"nativeCreate2",      "(III)I",   (void*)ComposeShader_create2     },
393    {"nativePostCreate1",  "(IIII)I",  (void*)ComposeShader_postCreate1 },
394    {"nativePostCreate2",  "(IIII)I",  (void*)ComposeShader_postCreate2 }
395};
396
397#include <android_runtime/AndroidRuntime.h>
398
399#define REG(env, name, array)                                                                       \
400    result = android::AndroidRuntime::registerNativeMethods(env, name, array, SK_ARRAY_COUNT(array));  \
401    if (result < 0) return result
402
403int register_android_graphics_Shader(JNIEnv* env);
404int register_android_graphics_Shader(JNIEnv* env)
405{
406    int result;
407
408    REG(env, "android/graphics/Color", gColorMethods);
409    REG(env, "android/graphics/Shader", gShaderMethods);
410    REG(env, "android/graphics/BitmapShader", gBitmapShaderMethods);
411    REG(env, "android/graphics/LinearGradient", gLinearGradientMethods);
412    REG(env, "android/graphics/RadialGradient", gRadialGradientMethods);
413    REG(env, "android/graphics/SweepGradient", gSweepGradientMethods);
414    REG(env, "android/graphics/ComposeShader", gComposeShaderMethods);
415
416    return result;
417}
418
419