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