Home | History | Annotate | Download | only in graphics
      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 
     21 static void ThrowIAE_IfNull(JNIEnv* env, void* ptr) {
     22     if (NULL == ptr) {
     23         doThrowIAE(env);
     24     }
     25 }
     26 
     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 
     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 
     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 
     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 
     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 
     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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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