• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
14 using namespace android::uirenderer;
15 
16 static struct {
17     jclass clazz;
18     jfieldID shader;
19 } gShaderClassInfo;
20 
ThrowIAE_IfNull(JNIEnv * env,void * ptr)21 static void ThrowIAE_IfNull(JNIEnv* env, void* ptr) {
22     if (NULL == ptr) {
23         doThrowIAE(env);
24     }
25 }
26 
Color_RGBToHSV(JNIEnv * env,jobject,int red,int green,int blue,jfloatArray hsvArray)27 static 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 
Color_HSVToColor(JNIEnv * env,jobject,int alpha,jfloatArray hsvArray)39 static 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 
Shader_destructor(JNIEnv * env,jobject o,SkShader * shader,SkiaShader * skiaShader)54 static 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 
Shader_setLocalMatrix(JNIEnv * env,jobject o,SkShader * shader,SkiaShader * skiaShader,const SkMatrix * matrix)67 static 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 
BitmapShader_constructor(JNIEnv * env,jobject o,const SkBitmap * bitmap,int tileModeX,int tileModeY)85 static 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 
BitmapShader_postConstructor(JNIEnv * env,jobject o,SkShader * shader,SkBitmap * bitmap,int tileModeX,int tileModeY)96 static 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 
LinearGradient_create1(JNIEnv * env,jobject o,float x0,float y0,float x1,float y1,jintArray colorArray,jfloatArray posArray,int tileMode)110 static 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 
LinearGradient_postCreate1(JNIEnv * env,jobject o,SkShader * shader,float x0,float y0,float x1,float y1,jintArray colorArray,jfloatArray posArray,int tileMode)143 static 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 
LinearGradient_postCreate2(JNIEnv * env,jobject o,SkShader * shader,float x0,float y0,float x1,float y1,int color0,int color1,int tileMode)185 static 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 
LinearGradient_create2(JNIEnv * env,jobject o,float x0,float y0,float x1,float y1,int color0,int color1,int tileMode)210 static 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 
RadialGradient_create1(JNIEnv * env,jobject,float x,float y,float radius,jintArray colorArray,jfloatArray posArray,int tileMode)230 static 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 
RadialGradient_create2(JNIEnv * env,jobject,float x,float y,float radius,int color0,int color1,int tileMode)261 static 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 
RadialGradient_postCreate1(JNIEnv * env,jobject o,SkShader * shader,float x,float y,float radius,jintArray colorArray,jfloatArray posArray,int tileMode)276 static 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 
RadialGradient_postCreate2(JNIEnv * env,jobject o,SkShader * shader,float x,float y,float radius,int color0,int color1,int tileMode)314 static 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 
SweepGradient_create1(JNIEnv * env,jobject,float x,float y,jintArray jcolors,jfloatArray jpositions)337 static 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 
SweepGradient_create2(JNIEnv * env,jobject,float x,float y,int color0,int color1)364 static 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 
SweepGradient_postCreate1(JNIEnv * env,jobject o,SkShader * shader,float x,float y,jintArray colorArray,jfloatArray posArray)375 static 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 
SweepGradient_postCreate2(JNIEnv * env,jobject o,SkShader * shader,float x,float y,int color0,int color1)412 static 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 
ComposeShader_create1(JNIEnv * env,jobject o,SkShader * shaderA,SkShader * shaderB,SkXfermode * mode)434 static SkShader* ComposeShader_create1(JNIEnv* env, jobject o,
435         SkShader* shaderA, SkShader* shaderB, SkXfermode* mode)
436 {
437     return new SkComposeShader(shaderA, shaderB, mode);
438 }
439 
ComposeShader_create2(JNIEnv * env,jobject o,SkShader * shaderA,SkShader * shaderB,SkPorterDuff::Mode porterDuffMode)440 static 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 
ComposeShader_postCreate2(JNIEnv * env,jobject o,SkShader * shader,SkiaShader * shaderA,SkiaShader * shaderB,SkPorterDuff::Mode porterDuffMode)448 static 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 
ComposeShader_postCreate1(JNIEnv * env,jobject o,SkShader * shader,SkiaShader * shaderA,SkiaShader * shaderB,SkXfermode * mode)458 static 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 
474 static JNINativeMethod gColorMethods[] = {
475     { "nativeRGBToHSV",     "(III[F)V", (void*)Color_RGBToHSV   },
476     { "nativeHSVToColor",   "(I[F)I",   (void*)Color_HSVToColor }
477 };
478 
479 static JNINativeMethod gShaderMethods[] = {
480     { "nativeDestructor",        "(II)V",    (void*)Shader_destructor        },
481     { "nativeSetLocalMatrix",    "(III)V",   (void*)Shader_setLocalMatrix    }
482 };
483 
484 static JNINativeMethod gBitmapShaderMethods[] = {
485     { "nativeCreate",     "(III)I",  (void*)BitmapShader_constructor },
486     { "nativePostCreate", "(IIII)I", (void*)BitmapShader_postConstructor }
487 };
488 
489 static 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 
496 static 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 
503 static 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 
510 static 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 
register_android_graphics_Shader(JNIEnv * env)523 int register_android_graphics_Shader(JNIEnv* env)
524 {
525     int result;
526 
527     REG(env, "android/graphics/Color", gColorMethods);
528     REG(env, "android/graphics/Shader", gShaderMethods);
529     REG(env, "android/graphics/BitmapShader", gBitmapShaderMethods);
530     REG(env, "android/graphics/LinearGradient", gLinearGradientMethods);
531     REG(env, "android/graphics/RadialGradient", gRadialGradientMethods);
532     REG(env, "android/graphics/SweepGradient", gSweepGradientMethods);
533     REG(env, "android/graphics/ComposeShader", gComposeShaderMethods);
534 
535     return result;
536 }
537