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