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