• 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 
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 
LinearGradient_postCreate2(JNIEnv * env,jobject o,SkShader * shader,float x0,float y0,float x1,float y1,int color0,int color1,int tileMode)215 static 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 
LinearGradient_create2(JNIEnv * env,jobject o,float x0,float y0,float x1,float y1,int color0,int color1,int tileMode)240 static 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 
RadialGradient_create1(JNIEnv * env,jobject,float x,float y,float radius,jintArray colorArray,jfloatArray posArray,int tileMode)260 static 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 
RadialGradient_create2(JNIEnv * env,jobject,float x,float y,float radius,int color0,int color1,int tileMode)291 static 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 
RadialGradient_postCreate1(JNIEnv * env,jobject o,SkShader * shader,float x,float y,float radius,jintArray colorArray,jfloatArray posArray,int tileMode)306 static 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 
RadialGradient_postCreate2(JNIEnv * env,jobject o,SkShader * shader,float x,float y,float radius,int color0,int color1,int tileMode)344 static 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 
SweepGradient_create1(JNIEnv * env,jobject,float x,float y,jintArray jcolors,jfloatArray jpositions)367 static 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 
SweepGradient_create2(JNIEnv * env,jobject,float x,float y,int color0,int color1)394 static 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 
SweepGradient_postCreate1(JNIEnv * env,jobject o,SkShader * shader,float x,float y,jintArray colorArray,jfloatArray posArray)405 static 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 
SweepGradient_postCreate2(JNIEnv * env,jobject o,SkShader * shader,float x,float y,int color0,int color1)442 static 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 
ComposeShader_create1(JNIEnv * env,jobject o,SkShader * shaderA,SkShader * shaderB,SkXfermode * mode)464 static SkShader* ComposeShader_create1(JNIEnv* env, jobject o,
465         SkShader* shaderA, SkShader* shaderB, SkXfermode* mode)
466 {
467     return new SkComposeShader(shaderA, shaderB, mode);
468 }
469 
ComposeShader_create2(JNIEnv * env,jobject o,SkShader * shaderA,SkShader * shaderB,SkPorterDuff::Mode porterDuffMode)470 static 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 
ComposeShader_postCreate2(JNIEnv * env,jobject o,SkShader * shader,SkiaShader * shaderA,SkiaShader * shaderB,SkPorterDuff::Mode porterDuffMode)478 static 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 
ComposeShader_postCreate1(JNIEnv * env,jobject o,SkShader * shader,SkiaShader * shaderA,SkiaShader * shaderB,SkXfermode * mode)488 static 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 
504 static JNINativeMethod gColorMethods[] = {
505     { "nativeRGBToHSV",     "(III[F)V", (void*)Color_RGBToHSV   },
506     { "nativeHSVToColor",   "(I[F)I",   (void*)Color_HSVToColor }
507 };
508 
509 static JNINativeMethod gShaderMethods[] = {
510     { "nativeDestructor",        "(II)V",    (void*)Shader_destructor        },
511     { "nativeSetLocalMatrix",    "(III)V",   (void*)Shader_setLocalMatrix    }
512 };
513 
514 static JNINativeMethod gBitmapShaderMethods[] = {
515     { "nativeCreate",     "(III)I",  (void*)BitmapShader_constructor },
516     { "nativePostCreate", "(IIII)I", (void*)BitmapShader_postConstructor }
517 };
518 
519 static 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 
526 static 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 
533 static 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 
540 static 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 
register_android_graphics_Shader(JNIEnv * env)553 int 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