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, 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 
     39 static jint Color_HSVToColor(JNIEnv* env, jobject, jint alpha, jfloatArray hsvArray)
     40 {
     41     AutoJavaFloatArray  autoHSV(env, hsvArray, 3);
     42 #ifdef SK_SCALAR_IS_FLOAT
     43     SkScalar*   hsv = autoHSV.ptr();
     44 #else
     45     #error Need to convert float array to SkScalar array before calling the following function.
     46 #endif
     47 
     48     return static_cast<jint>(SkHSVToColor(alpha, hsv));
     49 }
     50 
     51 ///////////////////////////////////////////////////////////////////////////////////////////////
     52 
     53 static void Shader_destructor(JNIEnv* env, jobject o, jlong shaderHandle, jlong shaderWithLMHandle)
     54 {
     55     SkShader* shader = reinterpret_cast<SkShader*>(shaderHandle);
     56     SkSafeUnref(shader);
     57 }
     58 
     59 static void Shader_setLocalMatrix(JNIEnv* env, jobject o, jlong shaderHandle, jlong matrixHandle)
     60 {
     61     SkShader* shader       = reinterpret_cast<SkShader*>(shaderHandle);
     62     const SkMatrix* matrix = reinterpret_cast<SkMatrix*>(matrixHandle);
     63     if (shader) {
     64         if (matrix) {
     65             shader->setLocalMatrix(*matrix);
     66         } else {
     67             shader->resetLocalMatrix();
     68         }
     69         shader->setGenerationID(shader->getGenerationID() + 1);
     70     }
     71 }
     72 
     73 ///////////////////////////////////////////////////////////////////////////////////////////////
     74 
     75 static jlong BitmapShader_constructor(JNIEnv* env, jobject o, jlong bitmapHandle,
     76                                       jint tileModeX, jint tileModeY)
     77 {
     78     const SkBitmap* bitmap = reinterpret_cast<SkBitmap*>(bitmapHandle);
     79     SkShader* s = SkShader::CreateBitmapShader(*bitmap,
     80                                         (SkShader::TileMode)tileModeX,
     81                                         (SkShader::TileMode)tileModeY);
     82 
     83     ThrowIAE_IfNull(env, s);
     84     return reinterpret_cast<jlong>(s);
     85 }
     86 
     87 ///////////////////////////////////////////////////////////////////////////////////////////////
     88 
     89 static jlong LinearGradient_create1(JNIEnv* env, jobject o,
     90                                     jfloat x0, jfloat y0, jfloat x1, jfloat y1,
     91                                     jintArray colorArray, jfloatArray posArray, jint tileMode)
     92 {
     93     SkPoint pts[2];
     94     pts[0].set(x0, y0);
     95     pts[1].set(x1, y1);
     96 
     97     size_t count = env->GetArrayLength(colorArray);
     98     const jint* colorValues = env->GetIntArrayElements(colorArray, NULL);
     99 
    100     AutoJavaFloatArray autoPos(env, posArray, count);
    101 #ifdef SK_SCALAR_IS_FLOAT
    102     SkScalar* pos = autoPos.ptr();
    103 #else
    104     #error Need to convert float array to SkScalar array before calling the following function.
    105 #endif
    106 
    107     SkShader* shader = SkGradientShader::CreateLinear(pts,
    108             reinterpret_cast<const SkColor*>(colorValues), pos, count,
    109             static_cast<SkShader::TileMode>(tileMode));
    110 
    111     env->ReleaseIntArrayElements(colorArray, const_cast<jint*>(colorValues), JNI_ABORT);
    112     ThrowIAE_IfNull(env, shader);
    113     return reinterpret_cast<jlong>(shader);
    114 }
    115 
    116 static jlong LinearGradient_create2(JNIEnv* env, jobject o,
    117                                     jfloat x0, jfloat y0, jfloat x1, jfloat y1,
    118                                     jint color0, jint color1, jint tileMode)
    119 {
    120     SkPoint pts[2];
    121     pts[0].set(x0, y0);
    122     pts[1].set(x1, y1);
    123 
    124     SkColor colors[2];
    125     colors[0] = color0;
    126     colors[1] = color1;
    127 
    128     SkShader* s = SkGradientShader::CreateLinear(pts, colors, NULL, 2, (SkShader::TileMode)tileMode);
    129 
    130     ThrowIAE_IfNull(env, s);
    131     return reinterpret_cast<jlong>(s);
    132 }
    133 
    134 ///////////////////////////////////////////////////////////////////////////////////////////////
    135 
    136 static jlong RadialGradient_create1(JNIEnv* env, jobject, jfloat x, jfloat y, jfloat radius,
    137         jintArray colorArray, jfloatArray posArray, jint tileMode) {
    138     SkPoint center;
    139     center.set(x, y);
    140 
    141     size_t      count = env->GetArrayLength(colorArray);
    142     const jint* colorValues = env->GetIntArrayElements(colorArray, NULL);
    143 
    144     AutoJavaFloatArray autoPos(env, posArray, count);
    145 #ifdef SK_SCALAR_IS_FLOAT
    146     SkScalar* pos = autoPos.ptr();
    147 #else
    148     #error Need to convert float array to SkScalar array before calling the following function.
    149 #endif
    150 
    151     SkShader* shader = SkGradientShader::CreateRadial(center, radius,
    152             reinterpret_cast<const SkColor*>(colorValues), pos, count,
    153             static_cast<SkShader::TileMode>(tileMode));
    154     env->ReleaseIntArrayElements(colorArray, const_cast<jint*>(colorValues),
    155                                  JNI_ABORT);
    156 
    157     ThrowIAE_IfNull(env, shader);
    158     return reinterpret_cast<jlong>(shader);
    159 }
    160 
    161 static jlong RadialGradient_create2(JNIEnv* env, jobject, jfloat x, jfloat y, jfloat radius,
    162         jint color0, jint color1, jint tileMode) {
    163     SkPoint center;
    164     center.set(x, y);
    165 
    166     SkColor colors[2];
    167     colors[0] = color0;
    168     colors[1] = color1;
    169 
    170     SkShader* s = SkGradientShader::CreateRadial(center, radius, colors, NULL, 2,
    171             (SkShader::TileMode)tileMode);
    172     ThrowIAE_IfNull(env, s);
    173     return reinterpret_cast<jlong>(s);
    174 }
    175 
    176 ///////////////////////////////////////////////////////////////////////////////
    177 
    178 static jlong SweepGradient_create1(JNIEnv* env, jobject, jfloat x, jfloat y,
    179         jintArray jcolors, jfloatArray jpositions) {
    180     size_t      count = env->GetArrayLength(jcolors);
    181     const jint* colors = env->GetIntArrayElements(jcolors, NULL);
    182 
    183     AutoJavaFloatArray autoPos(env, jpositions, count);
    184 #ifdef SK_SCALAR_IS_FLOAT
    185     SkScalar* pos = autoPos.ptr();
    186 #else
    187     #error Need to convert float array to SkScalar array before calling the following function.
    188 #endif
    189 
    190     SkShader* shader = SkGradientShader::CreateSweep(x, y,
    191             reinterpret_cast<const SkColor*>(colors), pos, count);
    192     env->ReleaseIntArrayElements(jcolors, const_cast<jint*>(colors),
    193                                  JNI_ABORT);
    194     ThrowIAE_IfNull(env, shader);
    195     return reinterpret_cast<jlong>(shader);
    196 }
    197 
    198 static jlong SweepGradient_create2(JNIEnv* env, jobject, jfloat x, jfloat y,
    199         int color0, int color1) {
    200     SkColor colors[2];
    201     colors[0] = color0;
    202     colors[1] = color1;
    203     SkShader* s = SkGradientShader::CreateSweep(x, y, colors, NULL, 2);
    204     ThrowIAE_IfNull(env, s);
    205     return reinterpret_cast<jlong>(s);
    206 }
    207 
    208 ///////////////////////////////////////////////////////////////////////////////////////////////
    209 
    210 static jlong ComposeShader_create1(JNIEnv* env, jobject o,
    211         jlong shaderAHandle, jlong shaderBHandle, jlong modeHandle)
    212 {
    213     SkShader* shaderA = reinterpret_cast<SkShader *>(shaderAHandle);
    214     SkShader* shaderB = reinterpret_cast<SkShader *>(shaderBHandle);
    215     SkXfermode* mode = reinterpret_cast<SkXfermode *>(modeHandle);
    216     SkShader* shader = new SkComposeShader(shaderA, shaderB, mode);
    217     return reinterpret_cast<jlong>(shader);
    218 }
    219 
    220 static jlong ComposeShader_create2(JNIEnv* env, jobject o,
    221         jlong shaderAHandle, jlong shaderBHandle, jint porterDuffModeHandle)
    222 {
    223     SkShader* shaderA = reinterpret_cast<SkShader *>(shaderAHandle);
    224     SkShader* shaderB = reinterpret_cast<SkShader *>(shaderBHandle);
    225     SkPorterDuff::Mode porterDuffMode = static_cast<SkPorterDuff::Mode>(porterDuffModeHandle);
    226     SkAutoUnref au(SkPorterDuff::CreateXfermode(porterDuffMode));
    227     SkXfermode* mode = (SkXfermode*) au.get();
    228     SkShader* shader = new SkComposeShader(shaderA, shaderB, mode);
    229     return reinterpret_cast<jlong>(shader);
    230 }
    231 
    232 ///////////////////////////////////////////////////////////////////////////////////////////////
    233 
    234 static JNINativeMethod gColorMethods[] = {
    235     { "nativeRGBToHSV",     "(III[F)V", (void*)Color_RGBToHSV   },
    236     { "nativeHSVToColor",   "(I[F)I",   (void*)Color_HSVToColor }
    237 };
    238 
    239 static JNINativeMethod gShaderMethods[] = {
    240     { "nativeDestructor",        "(J)V",    (void*)Shader_destructor        },
    241     { "nativeSetLocalMatrix",    "(JJ)V",   (void*)Shader_setLocalMatrix    }
    242 };
    243 
    244 static JNINativeMethod gBitmapShaderMethods[] = {
    245     { "nativeCreate",     "(JII)J",  (void*)BitmapShader_constructor },
    246 };
    247 
    248 static JNINativeMethod gLinearGradientMethods[] = {
    249     { "nativeCreate1",     "(FFFF[I[FI)J",  (void*)LinearGradient_create1     },
    250     { "nativeCreate2",     "(FFFFIII)J",    (void*)LinearGradient_create2     },
    251 };
    252 
    253 static JNINativeMethod gRadialGradientMethods[] = {
    254     { "nativeCreate1",     "(FFF[I[FI)J",  (void*)RadialGradient_create1     },
    255     { "nativeCreate2",     "(FFFIII)J",    (void*)RadialGradient_create2     },
    256 };
    257 
    258 static JNINativeMethod gSweepGradientMethods[] = {
    259     { "nativeCreate1",     "(FF[I[F)J",  (void*)SweepGradient_create1     },
    260     { "nativeCreate2",     "(FFII)J",    (void*)SweepGradient_create2     },
    261 };
    262 
    263 static JNINativeMethod gComposeShaderMethods[] = {
    264     { "nativeCreate1",      "(JJJ)J",   (void*)ComposeShader_create1     },
    265     { "nativeCreate2",      "(JJI)J",   (void*)ComposeShader_create2     },
    266 };
    267 
    268 #include <android_runtime/AndroidRuntime.h>
    269 
    270 #define REG(env, name, array)                                                                       \
    271     result = android::AndroidRuntime::registerNativeMethods(env, name, array, SK_ARRAY_COUNT(array));  \
    272     if (result < 0) return result
    273 
    274 int register_android_graphics_Shader(JNIEnv* env)
    275 {
    276     int result;
    277 
    278     REG(env, "android/graphics/Color", gColorMethods);
    279     REG(env, "android/graphics/Shader", gShaderMethods);
    280     REG(env, "android/graphics/BitmapShader", gBitmapShaderMethods);
    281     REG(env, "android/graphics/LinearGradient", gLinearGradientMethods);
    282     REG(env, "android/graphics/RadialGradient", gRadialGradientMethods);
    283     REG(env, "android/graphics/SweepGradient", gSweepGradientMethods);
    284     REG(env, "android/graphics/ComposeShader", gComposeShaderMethods);
    285 
    286     return result;
    287 }
    288