Shader.cpp revision a2341a9f6addcd79723965ec5b1a1c5ae0f8bd65
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,
230                                        float x, float y, float radius,
231                                        jintArray colorArray, jfloatArray posArray, int tileMode)
232{
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,
263                                        float x, float y, float radius,
264                                        int color0, int color1, int tileMode)
265{
266    SkPoint center;
267    center.set(SkFloatToScalar(x), SkFloatToScalar(y));
268
269    SkColor colors[2];
270    colors[0] = color0;
271    colors[1] = color1;
272
273    SkShader* s = SkGradientShader::CreateRadial(center, SkFloatToScalar(radius), colors, NULL,
274                                          2, (SkShader::TileMode)tileMode);
275    ThrowIAE_IfNull(env, s);
276    return s;
277}
278
279///////////////////////////////////////////////////////////////////////////////
280
281static SkShader* SweepGradient_create1(JNIEnv* env, jobject, float x, float y,
282                                    jintArray jcolors, jfloatArray jpositions)
283{
284    size_t      count = env->GetArrayLength(jcolors);
285    const jint* colors = env->GetIntArrayElements(jcolors, NULL);
286
287    SkAutoSTMalloc<8, SkScalar> storage(jpositions ? count : 0);
288    SkScalar*                   pos = NULL;
289
290    if (NULL != jpositions) {
291        AutoJavaFloatArray autoPos(env, jpositions, count);
292        const float* posValues = autoPos.ptr();
293        pos = (SkScalar*)storage.get();
294        for (size_t i = 0; i < count; i++) {
295            pos[i] = SkFloatToScalar(posValues[i]);
296        }
297    }
298
299    SkShader* shader = SkGradientShader::CreateSweep(SkFloatToScalar(x),
300                                     SkFloatToScalar(y),
301                                     reinterpret_cast<const SkColor*>(colors),
302                                     pos, count);
303    env->ReleaseIntArrayElements(jcolors, const_cast<jint*>(colors),
304                                 JNI_ABORT);
305    ThrowIAE_IfNull(env, shader);
306    return shader;
307}
308
309static SkShader* SweepGradient_create2(JNIEnv* env, jobject, float x, float y,
310                                        int color0, int color1)
311{
312    SkColor colors[2];
313    colors[0] = color0;
314    colors[1] = color1;
315    SkShader* s = SkGradientShader::CreateSweep(SkFloatToScalar(x), SkFloatToScalar(y),
316                                         colors, NULL, 2);
317    ThrowIAE_IfNull(env, s);
318    return s;
319}
320
321///////////////////////////////////////////////////////////////////////////////////////////////
322
323static SkShader* ComposeShader_create1(JNIEnv* env, jobject o,
324        SkShader* shaderA, SkShader* shaderB, SkXfermode* mode)
325{
326    return new SkComposeShader(shaderA, shaderB, mode);
327}
328
329static SkShader* ComposeShader_create2(JNIEnv* env, jobject o,
330        SkShader* shaderA, SkShader* shaderB, SkPorterDuff::Mode porterDuffMode)
331{
332    SkAutoUnref au(SkPorterDuff::CreateXfermode(porterDuffMode));
333    SkXfermode* mode = (SkXfermode*) au.get();
334    return new SkComposeShader(shaderA, shaderB, mode);
335}
336
337static SkiaShader* ComposeShader_postCreate2(JNIEnv* env, jobject o, SkShader* shader,
338        SkiaShader* shaderA, SkiaShader* shaderB, SkPorterDuff::Mode porterDuffMode) {
339#ifdef USE_OPENGL_RENDERER
340    SkXfermode::Mode mode = SkPorterDuff::ToXfermodeMode(porterDuffMode);
341    return new SkiaComposeShader(shaderA, shaderB, mode, shader);
342#else
343    return NULL;
344#endif
345}
346
347static SkiaShader* ComposeShader_postCreate1(JNIEnv* env, jobject o, SkShader* shader,
348        SkiaShader* shaderA, SkiaShader* shaderB, SkXfermode* mode) {
349#ifdef USE_OPENGL_RENDERER
350    SkXfermode::Mode skiaMode;
351    if (!SkXfermode::IsMode(mode, &skiaMode)) {
352        // TODO: Support other modes
353        skiaMode = SkXfermode::kSrcOver_Mode;
354    }
355    return new SkiaComposeShader(shaderA, shaderB, skiaMode, shader);
356#else
357    return NULL;
358#endif
359}
360
361///////////////////////////////////////////////////////////////////////////////////////////////
362
363static JNINativeMethod gColorMethods[] = {
364    { "nativeRGBToHSV",     "(III[F)V", (void*)Color_RGBToHSV   },
365    { "nativeHSVToColor",   "(I[F)I",   (void*)Color_HSVToColor }
366};
367
368static JNINativeMethod gShaderMethods[] = {
369    { "nativeDestructor",        "(II)V",    (void*)Shader_destructor        },
370    { "nativeGetLocalMatrix",    "(II)Z",    (void*)Shader_getLocalMatrix    },
371    { "nativeSetLocalMatrix",    "(III)V",   (void*)Shader_setLocalMatrix    }
372};
373
374static JNINativeMethod gBitmapShaderMethods[] = {
375    { "nativeCreate",     "(III)I",  (void*)BitmapShader_constructor },
376    { "nativePostCreate", "(IIII)I", (void*)BitmapShader_postConstructor }
377};
378
379static JNINativeMethod gLinearGradientMethods[] = {
380    { "nativeCreate1",     "(FFFF[I[FI)I",  (void*)LinearGradient_create1     },
381    { "nativeCreate2",     "(FFFFIII)I",    (void*)LinearGradient_create2     },
382    { "nativePostCreate1", "(IFFFF[I[FI)I", (void*)LinearGradient_postCreate1 },
383    { "nativePostCreate2", "(IFFFFIII)I",   (void*)LinearGradient_postCreate2 }
384};
385
386static JNINativeMethod gRadialGradientMethods[] = {
387    {"nativeCreate1",   "(FFF[I[FI)I",  (void*)RadialGradient_create1   },
388    {"nativeCreate2",   "(FFFIII)I",    (void*)RadialGradient_create2   }
389};
390
391static JNINativeMethod gSweepGradientMethods[] = {
392    {"nativeCreate1",   "(FF[I[F)I",  (void*)SweepGradient_create1   },
393    {"nativeCreate2",   "(FFII)I",    (void*)SweepGradient_create2   }
394};
395
396static JNINativeMethod gComposeShaderMethods[] = {
397    {"nativeCreate1",      "(III)I",   (void*)ComposeShader_create1     },
398    {"nativeCreate2",      "(III)I",   (void*)ComposeShader_create2     },
399    {"nativePostCreate1",  "(IIII)I",  (void*)ComposeShader_postCreate1 },
400    {"nativePostCreate2",  "(IIII)I",  (void*)ComposeShader_postCreate2 }
401};
402
403#include <android_runtime/AndroidRuntime.h>
404
405#define REG(env, name, array)                                                                       \
406    result = android::AndroidRuntime::registerNativeMethods(env, name, array, SK_ARRAY_COUNT(array));  \
407    if (result < 0) return result
408
409int register_android_graphics_Shader(JNIEnv* env);
410int register_android_graphics_Shader(JNIEnv* env)
411{
412    int result;
413
414    REG(env, "android/graphics/Color", gColorMethods);
415    REG(env, "android/graphics/Shader", gShaderMethods);
416    REG(env, "android/graphics/BitmapShader", gBitmapShaderMethods);
417    REG(env, "android/graphics/LinearGradient", gLinearGradientMethods);
418    REG(env, "android/graphics/RadialGradient", gRadialGradientMethods);
419    REG(env, "android/graphics/SweepGradient", gSweepGradientMethods);
420    REG(env, "android/graphics/ComposeShader", gComposeShaderMethods);
421
422    return result;
423}
424
425