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