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