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 "SkComposeShader.h"
      7 #include "SkTemplates.h"
      8 #include "SkXfermode.h"
      9 
     10 #include <Caches.h>
     11 
     12 #include "core_jni_helpers.h"
     13 
     14 using namespace android::uirenderer;
     15 
     16 static void ThrowIAE_IfNull(JNIEnv* env, void* ptr) {
     17     if (NULL == ptr) {
     18         doThrowIAE(env);
     19     }
     20 }
     21 
     22 static void Color_RGBToHSV(JNIEnv* env, jobject, jint red, jint green, jint blue, jfloatArray hsvArray)
     23 {
     24     SkScalar hsv[3];
     25     SkRGBToHSV(red, green, blue, hsv);
     26 
     27     AutoJavaFloatArray  autoHSV(env, hsvArray, 3);
     28     float* values = autoHSV.ptr();
     29     for (int i = 0; i < 3; i++) {
     30         values[i] = SkScalarToFloat(hsv[i]);
     31     }
     32 }
     33 
     34 static jint Color_HSVToColor(JNIEnv* env, jobject, jint alpha, jfloatArray hsvArray)
     35 {
     36     AutoJavaFloatArray  autoHSV(env, hsvArray, 3);
     37 #ifdef SK_SCALAR_IS_FLOAT
     38     SkScalar*   hsv = autoHSV.ptr();
     39 #else
     40     #error Need to convert float array to SkScalar array before calling the following function.
     41 #endif
     42 
     43     return static_cast<jint>(SkHSVToColor(alpha, hsv));
     44 }
     45 
     46 ///////////////////////////////////////////////////////////////////////////////////////////////
     47 
     48 static void Shader_destructor(JNIEnv* env, jobject o, jlong shaderHandle, jlong shaderWithLMHandle)
     49 {
     50     SkShader* shader = reinterpret_cast<SkShader*>(shaderHandle);
     51     SkSafeUnref(shader);
     52 }
     53 
     54 static jlong Shader_setLocalMatrix(JNIEnv* env, jobject o, jlong shaderHandle, jlong matrixHandle)
     55 {
     56     // ensure we have a valid matrix to use
     57     const SkMatrix* matrix = reinterpret_cast<SkMatrix*>(matrixHandle);
     58     if (NULL == matrix) {
     59         matrix = &SkMatrix::I();
     60     }
     61 
     62     // The current shader will no longer need a direct reference owned by Shader.java
     63     // as all the data needed is contained within the newly created LocalMatrixShader.
     64     SkASSERT(shaderHandle);
     65     SkAutoTUnref<SkShader> currentShader(reinterpret_cast<SkShader*>(shaderHandle));
     66 
     67     SkMatrix currentMatrix;
     68     SkAutoTUnref<SkShader> baseShader(currentShader->refAsALocalMatrixShader(&currentMatrix));
     69     if (baseShader.get()) {
     70         // if the matrices are same then there is no need to allocate a new
     71         // shader that is identical to the existing one.
     72         if (currentMatrix == *matrix) {
     73             return reinterpret_cast<jlong>(currentShader.detach());
     74         }
     75         return reinterpret_cast<jlong>(SkShader::CreateLocalMatrixShader(baseShader, *matrix));
     76     }
     77 
     78     return reinterpret_cast<jlong>(SkShader::CreateLocalMatrixShader(currentShader, *matrix));
     79 }
     80 
     81 ///////////////////////////////////////////////////////////////////////////////////////////////
     82 
     83 static jlong BitmapShader_constructor(JNIEnv* env, jobject o, jobject jbitmap,
     84                                       jint tileModeX, jint tileModeY)
     85 {
     86     SkBitmap bitmap;
     87     if (jbitmap) {
     88         // Only pass a valid SkBitmap object to the constructor if the Bitmap exists. Otherwise,
     89         // we'll pass an empty SkBitmap to avoid crashing/excepting for compatibility.
     90         GraphicsJNI::getSkBitmap(env, jbitmap, &bitmap);
     91     }
     92     SkShader* s = SkShader::CreateBitmapShader(bitmap,
     93                                         (SkShader::TileMode)tileModeX,
     94                                         (SkShader::TileMode)tileModeY);
     95 
     96     ThrowIAE_IfNull(env, s);
     97     return reinterpret_cast<jlong>(s);
     98 }
     99 
    100 ///////////////////////////////////////////////////////////////////////////////////////////////
    101 
    102 static jlong LinearGradient_create1(JNIEnv* env, jobject o,
    103                                     jfloat x0, jfloat y0, jfloat x1, jfloat y1,
    104                                     jintArray colorArray, jfloatArray posArray, jint tileMode)
    105 {
    106     SkPoint pts[2];
    107     pts[0].set(x0, y0);
    108     pts[1].set(x1, y1);
    109 
    110     size_t count = env->GetArrayLength(colorArray);
    111     const jint* colorValues = env->GetIntArrayElements(colorArray, NULL);
    112 
    113     AutoJavaFloatArray autoPos(env, posArray, count);
    114 #ifdef SK_SCALAR_IS_FLOAT
    115     SkScalar* pos = autoPos.ptr();
    116 #else
    117     #error Need to convert float array to SkScalar array before calling the following function.
    118 #endif
    119 
    120     SkShader* shader = SkGradientShader::CreateLinear(pts,
    121             reinterpret_cast<const SkColor*>(colorValues), pos, count,
    122             static_cast<SkShader::TileMode>(tileMode));
    123 
    124     env->ReleaseIntArrayElements(colorArray, const_cast<jint*>(colorValues), JNI_ABORT);
    125     ThrowIAE_IfNull(env, shader);
    126     return reinterpret_cast<jlong>(shader);
    127 }
    128 
    129 static jlong LinearGradient_create2(JNIEnv* env, jobject o,
    130                                     jfloat x0, jfloat y0, jfloat x1, jfloat y1,
    131                                     jint color0, jint color1, jint tileMode)
    132 {
    133     SkPoint pts[2];
    134     pts[0].set(x0, y0);
    135     pts[1].set(x1, y1);
    136 
    137     SkColor colors[2];
    138     colors[0] = color0;
    139     colors[1] = color1;
    140 
    141     SkShader* s = SkGradientShader::CreateLinear(pts, colors, NULL, 2, (SkShader::TileMode)tileMode);
    142 
    143     ThrowIAE_IfNull(env, s);
    144     return reinterpret_cast<jlong>(s);
    145 }
    146 
    147 ///////////////////////////////////////////////////////////////////////////////////////////////
    148 
    149 static jlong RadialGradient_create1(JNIEnv* env, jobject, jfloat x, jfloat y, jfloat radius,
    150         jintArray colorArray, jfloatArray posArray, jint tileMode) {
    151     SkPoint center;
    152     center.set(x, y);
    153 
    154     size_t      count = env->GetArrayLength(colorArray);
    155     const jint* colorValues = env->GetIntArrayElements(colorArray, NULL);
    156 
    157     AutoJavaFloatArray autoPos(env, posArray, count);
    158 #ifdef SK_SCALAR_IS_FLOAT
    159     SkScalar* pos = autoPos.ptr();
    160 #else
    161     #error Need to convert float array to SkScalar array before calling the following function.
    162 #endif
    163 
    164     SkShader* shader = SkGradientShader::CreateRadial(center, radius,
    165             reinterpret_cast<const SkColor*>(colorValues), pos, count,
    166             static_cast<SkShader::TileMode>(tileMode));
    167     env->ReleaseIntArrayElements(colorArray, const_cast<jint*>(colorValues),
    168                                  JNI_ABORT);
    169 
    170     ThrowIAE_IfNull(env, shader);
    171     return reinterpret_cast<jlong>(shader);
    172 }
    173 
    174 static jlong RadialGradient_create2(JNIEnv* env, jobject, jfloat x, jfloat y, jfloat radius,
    175         jint color0, jint color1, jint tileMode) {
    176     SkPoint center;
    177     center.set(x, y);
    178 
    179     SkColor colors[2];
    180     colors[0] = color0;
    181     colors[1] = color1;
    182 
    183     SkShader* s = SkGradientShader::CreateRadial(center, radius, colors, NULL, 2,
    184             (SkShader::TileMode)tileMode);
    185     ThrowIAE_IfNull(env, s);
    186     return reinterpret_cast<jlong>(s);
    187 }
    188 
    189 ///////////////////////////////////////////////////////////////////////////////
    190 
    191 static jlong SweepGradient_create1(JNIEnv* env, jobject, jfloat x, jfloat y,
    192         jintArray jcolors, jfloatArray jpositions) {
    193     size_t      count = env->GetArrayLength(jcolors);
    194     const jint* colors = env->GetIntArrayElements(jcolors, NULL);
    195 
    196     AutoJavaFloatArray autoPos(env, jpositions, count);
    197 #ifdef SK_SCALAR_IS_FLOAT
    198     SkScalar* pos = autoPos.ptr();
    199 #else
    200     #error Need to convert float array to SkScalar array before calling the following function.
    201 #endif
    202 
    203     SkShader* shader = SkGradientShader::CreateSweep(x, y,
    204             reinterpret_cast<const SkColor*>(colors), pos, count);
    205     env->ReleaseIntArrayElements(jcolors, const_cast<jint*>(colors),
    206                                  JNI_ABORT);
    207     ThrowIAE_IfNull(env, shader);
    208     return reinterpret_cast<jlong>(shader);
    209 }
    210 
    211 static jlong SweepGradient_create2(JNIEnv* env, jobject, jfloat x, jfloat y,
    212         int color0, int color1) {
    213     SkColor colors[2];
    214     colors[0] = color0;
    215     colors[1] = color1;
    216     SkShader* s = SkGradientShader::CreateSweep(x, y, colors, NULL, 2);
    217     ThrowIAE_IfNull(env, s);
    218     return reinterpret_cast<jlong>(s);
    219 }
    220 
    221 ///////////////////////////////////////////////////////////////////////////////////////////////
    222 
    223 static jlong ComposeShader_create1(JNIEnv* env, jobject o,
    224         jlong shaderAHandle, jlong shaderBHandle, jlong modeHandle)
    225 {
    226     SkShader* shaderA = reinterpret_cast<SkShader *>(shaderAHandle);
    227     SkShader* shaderB = reinterpret_cast<SkShader *>(shaderBHandle);
    228     SkXfermode* mode = reinterpret_cast<SkXfermode *>(modeHandle);
    229     SkShader* shader = new SkComposeShader(shaderA, shaderB, mode);
    230     return reinterpret_cast<jlong>(shader);
    231 }
    232 
    233 static jlong ComposeShader_create2(JNIEnv* env, jobject o,
    234         jlong shaderAHandle, jlong shaderBHandle, jint xfermodeHandle)
    235 {
    236     SkShader* shaderA = reinterpret_cast<SkShader *>(shaderAHandle);
    237     SkShader* shaderB = reinterpret_cast<SkShader *>(shaderBHandle);
    238     SkXfermode::Mode mode = static_cast<SkXfermode::Mode>(xfermodeHandle);
    239     SkAutoTUnref<SkXfermode> xfermode(SkXfermode::Create(mode));
    240     SkShader* shader = new SkComposeShader(shaderA, shaderB, xfermode.get());
    241     return reinterpret_cast<jlong>(shader);
    242 }
    243 
    244 ///////////////////////////////////////////////////////////////////////////////////////////////
    245 
    246 static JNINativeMethod gColorMethods[] = {
    247     { "nativeRGBToHSV",     "(III[F)V", (void*)Color_RGBToHSV   },
    248     { "nativeHSVToColor",   "(I[F)I",   (void*)Color_HSVToColor }
    249 };
    250 
    251 static JNINativeMethod gShaderMethods[] = {
    252     { "nativeDestructor",        "(J)V",    (void*)Shader_destructor        },
    253     { "nativeSetLocalMatrix",    "(JJ)J",   (void*)Shader_setLocalMatrix    }
    254 };
    255 
    256 static JNINativeMethod gBitmapShaderMethods[] = {
    257     { "nativeCreate",     "(Landroid/graphics/Bitmap;II)J",  (void*)BitmapShader_constructor },
    258 };
    259 
    260 static JNINativeMethod gLinearGradientMethods[] = {
    261     { "nativeCreate1",     "(FFFF[I[FI)J",  (void*)LinearGradient_create1     },
    262     { "nativeCreate2",     "(FFFFIII)J",    (void*)LinearGradient_create2     },
    263 };
    264 
    265 static JNINativeMethod gRadialGradientMethods[] = {
    266     { "nativeCreate1",     "(FFF[I[FI)J",  (void*)RadialGradient_create1     },
    267     { "nativeCreate2",     "(FFFIII)J",    (void*)RadialGradient_create2     },
    268 };
    269 
    270 static JNINativeMethod gSweepGradientMethods[] = {
    271     { "nativeCreate1",     "(FF[I[F)J",  (void*)SweepGradient_create1     },
    272     { "nativeCreate2",     "(FFII)J",    (void*)SweepGradient_create2     },
    273 };
    274 
    275 static JNINativeMethod gComposeShaderMethods[] = {
    276     { "nativeCreate1",      "(JJJ)J",   (void*)ComposeShader_create1     },
    277     { "nativeCreate2",      "(JJI)J",   (void*)ComposeShader_create2     },
    278 };
    279 
    280 int register_android_graphics_Shader(JNIEnv* env)
    281 {
    282     android::RegisterMethodsOrDie(env, "android/graphics/Color", gColorMethods,
    283                                   NELEM(gColorMethods));
    284     android::RegisterMethodsOrDie(env, "android/graphics/Shader", gShaderMethods,
    285                                   NELEM(gShaderMethods));
    286     android::RegisterMethodsOrDie(env, "android/graphics/BitmapShader", gBitmapShaderMethods,
    287                                   NELEM(gBitmapShaderMethods));
    288     android::RegisterMethodsOrDie(env, "android/graphics/LinearGradient", gLinearGradientMethods,
    289                                   NELEM(gLinearGradientMethods));
    290     android::RegisterMethodsOrDie(env, "android/graphics/RadialGradient", gRadialGradientMethods,
    291                                   NELEM(gRadialGradientMethods));
    292     android::RegisterMethodsOrDie(env, "android/graphics/SweepGradient", gSweepGradientMethods,
    293                                   NELEM(gSweepGradientMethods));
    294     android::RegisterMethodsOrDie(env, "android/graphics/ComposeShader", gComposeShaderMethods,
    295                                   NELEM(gComposeShaderMethods));
    296 
    297     return 0;
    298 }
    299