Shader.cpp revision 163935113919a184122b8b3bd672ef08c8df65dc
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    memcpy(storedColors, colorValues, count);
153
154    if (posArray) {
155        AutoJavaFloatArray autoPos(env, posArray, count);
156        const float* posValues = autoPos.ptr();
157        for (size_t i = 0; i < count; i++) {
158            storedPositions[i] = posValues[i];
159        }
160    } else {
161        storedPositions[0] = 0.0f;
162        storedPositions[1] = 1.0f;
163    }
164
165    SkiaShader* skiaShader = new SkiaLinearGradientShader(storedBounds, storedColors,
166            storedPositions, count, shader, static_cast<SkShader::TileMode>(tileMode), NULL,
167            (shader->getFlags() & SkShader::kOpaqueAlpha_Flag) == 0);
168
169    env->ReleaseIntArrayElements(colorArray, const_cast<jint*>(colorValues), JNI_ABORT);
170    return skiaShader;
171#else
172    return NULL;
173#endif
174}
175
176static SkiaShader* LinearGradient_postCreate2(JNIEnv* env, jobject o, SkShader* shader,
177        float x0, float y0, float x1, float y1, int color0, int color1, int tileMode) {
178#ifdef USE_OPENGL_RENDERER
179    float* storedBounds = new float[4];
180    storedBounds[0] = x0; storedBounds[1] = y0;
181    storedBounds[2] = x1; storedBounds[3] = y1;
182
183    float* storedPositions = new float[2];
184    storedPositions[0] = 0.0f;
185    storedPositions[1] = 1.0f;
186
187    uint32_t* storedColors = new uint32_t[2];
188    storedColors[0] = color0;
189    storedColors[1] = color1;
190
191    SkiaShader* skiaShader = new SkiaLinearGradientShader(storedBounds, storedColors,
192            storedPositions, 2, shader, static_cast<SkShader::TileMode>(tileMode), NULL,
193            (shader->getFlags() & SkShader::kOpaqueAlpha_Flag) == 0);
194
195    return skiaShader;
196#else
197    return NULL;
198#endif
199}
200
201static SkShader* LinearGradient_create2(JNIEnv* env, jobject o,
202                                        float x0, float y0, float x1, float y1,
203                                        int color0, int color1, int tileMode)
204{
205    SkPoint pts[2];
206    pts[0].set(SkFloatToScalar(x0), SkFloatToScalar(y0));
207    pts[1].set(SkFloatToScalar(x1), SkFloatToScalar(y1));
208
209    SkColor colors[2];
210    colors[0] = color0;
211    colors[1] = color1;
212
213    SkShader* s = SkGradientShader::CreateLinear(pts, colors, NULL, 2, (SkShader::TileMode)tileMode);
214
215    ThrowIAE_IfNull(env, s);
216    return s;
217}
218
219///////////////////////////////////////////////////////////////////////////////////////////////
220
221static SkShader* RadialGradient_create1(JNIEnv* env, jobject,
222                                        float x, float y, float radius,
223                                        jintArray colorArray, jfloatArray posArray, int tileMode)
224{
225    SkPoint center;
226    center.set(SkFloatToScalar(x), SkFloatToScalar(y));
227
228    size_t      count = env->GetArrayLength(colorArray);
229    const jint* colorValues = env->GetIntArrayElements(colorArray, NULL);
230
231    SkAutoSTMalloc<8, SkScalar> storage(posArray ? count : 0);
232    SkScalar*                   pos = NULL;
233
234    if (posArray) {
235        AutoJavaFloatArray autoPos(env, posArray, count);
236        const float* posValues = autoPos.ptr();
237        pos = (SkScalar*)storage.get();
238        for (size_t i = 0; i < count; i++)
239            pos[i] = SkFloatToScalar(posValues[i]);
240    }
241
242    SkShader* shader = SkGradientShader::CreateRadial(center,
243                                SkFloatToScalar(radius),
244                                reinterpret_cast<const SkColor*>(colorValues),
245                                pos, count,
246                                static_cast<SkShader::TileMode>(tileMode));
247    env->ReleaseIntArrayElements(colorArray, const_cast<jint*>(colorValues),
248                                 JNI_ABORT);
249
250    ThrowIAE_IfNull(env, shader);
251    return shader;
252}
253
254static SkShader* RadialGradient_create2(JNIEnv* env, jobject,
255                                        float x, float y, float radius,
256                                        int color0, int color1, int tileMode)
257{
258    SkPoint center;
259    center.set(SkFloatToScalar(x), SkFloatToScalar(y));
260
261    SkColor colors[2];
262    colors[0] = color0;
263    colors[1] = color1;
264
265    SkShader* s = SkGradientShader::CreateRadial(center, SkFloatToScalar(radius), colors, NULL,
266                                          2, (SkShader::TileMode)tileMode);
267    ThrowIAE_IfNull(env, s);
268    return s;
269}
270
271///////////////////////////////////////////////////////////////////////////////
272
273static SkShader* SweepGradient_create1(JNIEnv* env, jobject, float x, float y,
274                                    jintArray jcolors, jfloatArray jpositions)
275{
276    size_t      count = env->GetArrayLength(jcolors);
277    const jint* colors = env->GetIntArrayElements(jcolors, NULL);
278
279    SkAutoSTMalloc<8, SkScalar> storage(jpositions ? count : 0);
280    SkScalar*                   pos = NULL;
281
282    if (NULL != jpositions) {
283        AutoJavaFloatArray autoPos(env, jpositions, count);
284        const float* posValues = autoPos.ptr();
285        pos = (SkScalar*)storage.get();
286        for (size_t i = 0; i < count; i++) {
287            pos[i] = SkFloatToScalar(posValues[i]);
288        }
289    }
290
291    SkShader* shader = SkGradientShader::CreateSweep(SkFloatToScalar(x),
292                                     SkFloatToScalar(y),
293                                     reinterpret_cast<const SkColor*>(colors),
294                                     pos, count);
295    env->ReleaseIntArrayElements(jcolors, const_cast<jint*>(colors),
296                                 JNI_ABORT);
297    ThrowIAE_IfNull(env, shader);
298    return shader;
299}
300
301static SkShader* SweepGradient_create2(JNIEnv* env, jobject, float x, float y,
302                                        int color0, int color1)
303{
304    SkColor colors[2];
305    colors[0] = color0;
306    colors[1] = color1;
307    SkShader* s = SkGradientShader::CreateSweep(SkFloatToScalar(x), SkFloatToScalar(y),
308                                         colors, NULL, 2);
309    ThrowIAE_IfNull(env, s);
310    return s;
311}
312
313///////////////////////////////////////////////////////////////////////////////////////////////
314
315static SkShader* ComposeShader_create1(JNIEnv* env, jobject o,
316        SkShader* shaderA, SkShader* shaderB, SkXfermode* mode)
317{
318    return new SkComposeShader(shaderA, shaderB, mode);
319}
320
321static SkShader* ComposeShader_create2(JNIEnv* env, jobject o,
322        SkShader* shaderA, SkShader* shaderB, SkPorterDuff::Mode porterDuffMode)
323{
324    SkAutoUnref au(SkPorterDuff::CreateXfermode(porterDuffMode));
325    SkXfermode* mode = (SkXfermode*) au.get();
326    return new SkComposeShader(shaderA, shaderB, mode);
327}
328
329static SkiaShader* ComposeShader_postCreate2(JNIEnv* env, jobject o, SkShader* shader,
330        SkiaShader* shaderA, SkiaShader* shaderB, SkPorterDuff::Mode porterDuffMode) {
331#ifdef USE_OPENGL_RENDERER
332    SkAutoUnref au(SkPorterDuff::CreateXfermode(porterDuffMode));
333    SkXfermode* mode = (SkXfermode*) au.get();
334    SkXfermode::Mode skiaMode;
335    if (!SkXfermode::IsMode(mode, &skiaMode)) {
336        skiaMode = SkXfermode::kSrcOver_Mode;
337    }
338    return new SkiaComposeShader(shaderA, shaderB, skiaMode, shader);
339#else
340    return NULL;
341#endif
342}
343
344static SkiaShader* ComposeShader_postCreate1(JNIEnv* env, jobject o, SkShader* shader,
345        SkiaShader* shaderA, SkiaShader* shaderB, SkXfermode* mode) {
346#ifdef USE_OPENGL_RENDERER
347    SkXfermode::Mode skiaMode;
348    if (!SkXfermode::IsMode(mode, &skiaMode)) {
349        skiaMode = SkXfermode::kSrcOver_Mode;
350    }
351    return new SkiaComposeShader(shaderA, shaderB, skiaMode, shader);
352#else
353    return NULL;
354#endif
355}
356
357///////////////////////////////////////////////////////////////////////////////////////////////
358
359static JNINativeMethod gColorMethods[] = {
360    { "nativeRGBToHSV",     "(III[F)V", (void*)Color_RGBToHSV   },
361    { "nativeHSVToColor",   "(I[F)I",   (void*)Color_HSVToColor }
362};
363
364static JNINativeMethod gShaderMethods[] = {
365    { "nativeDestructor",        "(II)V",    (void*)Shader_destructor        },
366    { "nativeGetLocalMatrix",    "(II)Z",    (void*)Shader_getLocalMatrix    },
367    { "nativeSetLocalMatrix",    "(III)V",   (void*)Shader_setLocalMatrix    }
368};
369
370static JNINativeMethod gBitmapShaderMethods[] = {
371    { "nativeCreate",     "(III)I",  (void*)BitmapShader_constructor },
372    { "nativePostCreate", "(IIII)I", (void*)BitmapShader_postConstructor }
373};
374
375static JNINativeMethod gLinearGradientMethods[] = {
376    { "nativeCreate1",     "(FFFF[I[FI)I",  (void*)LinearGradient_create1     },
377    { "nativeCreate2",     "(FFFFIII)I",    (void*)LinearGradient_create2     },
378    { "nativePostCreate1", "(IFFFF[I[FI)I", (void*)LinearGradient_postCreate1 },
379    { "nativePostCreate2", "(IFFFFIII)I",   (void*)LinearGradient_postCreate2 }
380};
381
382static JNINativeMethod gRadialGradientMethods[] = {
383    {"nativeCreate1",   "(FFF[I[FI)I",  (void*)RadialGradient_create1   },
384    {"nativeCreate2",   "(FFFIII)I",    (void*)RadialGradient_create2   }
385};
386
387static JNINativeMethod gSweepGradientMethods[] = {
388    {"nativeCreate1",   "(FF[I[F)I",  (void*)SweepGradient_create1   },
389    {"nativeCreate2",   "(FFII)I",    (void*)SweepGradient_create2   }
390};
391
392static JNINativeMethod gComposeShaderMethods[] = {
393    {"nativeCreate1",      "(III)I",   (void*)ComposeShader_create1     },
394    {"nativeCreate2",      "(III)I",   (void*)ComposeShader_create2     },
395    {"nativePostCreate1",  "(IIII)I",  (void*)ComposeShader_postCreate1 },
396    {"nativePostCreate2",  "(IIII)I",  (void*)ComposeShader_postCreate2 }
397};
398
399#include <android_runtime/AndroidRuntime.h>
400
401#define REG(env, name, array)                                                                       \
402    result = android::AndroidRuntime::registerNativeMethods(env, name, array, SK_ARRAY_COUNT(array));  \
403    if (result < 0) return result
404
405int register_android_graphics_Shader(JNIEnv* env);
406int register_android_graphics_Shader(JNIEnv* env)
407{
408    int result;
409
410    REG(env, "android/graphics/Color", gColorMethods);
411    REG(env, "android/graphics/Shader", gShaderMethods);
412    REG(env, "android/graphics/BitmapShader", gBitmapShaderMethods);
413    REG(env, "android/graphics/LinearGradient", gLinearGradientMethods);
414    REG(env, "android/graphics/RadialGradient", gRadialGradientMethods);
415    REG(env, "android/graphics/SweepGradient", gSweepGradientMethods);
416    REG(env, "android/graphics/ComposeShader", gComposeShaderMethods);
417
418    return result;
419}
420
421