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