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