Home | History | Annotate | Download | only in graphics
      1 #include "GraphicsJNI.h"
      2 #include "SkColorFilter.h"
      3 #include "SkGradientShader.h"
      4 #include "SkImagePriv.h"
      5 #include "SkShader.h"
      6 #include "SkBlendMode.h"
      7 #include "core_jni_helpers.h"
      8 
      9 #include <Caches.h>
     10 #include <jni.h>
     11 
     12 using namespace android::uirenderer;
     13 
     14 /**
     15  * By default Skia gradients will interpolate their colors in unpremul space
     16  * and then premultiply each of the results. We must set this flag to preserve
     17  * backwards compatiblity by premultiplying the colors of the gradient first,
     18  * and then interpolating between them.
     19  */
     20 static const uint32_t sGradientShaderFlags = SkGradientShader::kInterpolateColorsInPremul_Flag;
     21 
     22 static void ThrowIAE_IfNull(JNIEnv* env, void* ptr) {
     23     if (NULL == ptr) {
     24         doThrowIAE(env);
     25     }
     26 }
     27 
     28 static void Color_RGBToHSV(JNIEnv* env, jobject, jint red, jint green, jint blue, jfloatArray hsvArray)
     29 {
     30     SkScalar hsv[3];
     31     SkRGBToHSV(red, green, blue, hsv);
     32 
     33     AutoJavaFloatArray  autoHSV(env, hsvArray, 3);
     34     float* values = autoHSV.ptr();
     35     for (int i = 0; i < 3; i++) {
     36         values[i] = SkScalarToFloat(hsv[i]);
     37     }
     38 }
     39 
     40 static jint Color_HSVToColor(JNIEnv* env, jobject, jint alpha, jfloatArray hsvArray)
     41 {
     42     AutoJavaFloatArray  autoHSV(env, hsvArray, 3);
     43 #ifdef SK_SCALAR_IS_FLOAT
     44     SkScalar*   hsv = autoHSV.ptr();
     45 #else
     46     #error Need to convert float array to SkScalar array before calling the following function.
     47 #endif
     48 
     49     return static_cast<jint>(SkHSVToColor(alpha, hsv));
     50 }
     51 
     52 ///////////////////////////////////////////////////////////////////////////////////////////////
     53 
     54 static void Shader_safeUnref(SkShader* shader) {
     55     SkSafeUnref(shader);
     56 }
     57 
     58 static jlong Shader_getNativeFinalizer(JNIEnv*, jobject) {
     59     return static_cast<jlong>(reinterpret_cast<uintptr_t>(&Shader_safeUnref));
     60 }
     61 
     62 ///////////////////////////////////////////////////////////////////////////////////////////////
     63 
     64 static jlong BitmapShader_constructor(JNIEnv* env, jobject o, jlong matrixPtr, jobject jbitmap,
     65         jint tileModeX, jint tileModeY) {
     66     const SkMatrix* matrix = reinterpret_cast<const SkMatrix*>(matrixPtr);
     67     sk_sp<SkImage> image;
     68     sk_sp<SkColorFilter> colorFilter;
     69     if (jbitmap) {
     70         // Only pass a valid SkBitmap object to the constructor if the Bitmap exists. Otherwise,
     71         // we'll pass an empty SkBitmap to avoid crashing/excepting for compatibility.
     72         image = android::bitmap::toBitmap(env, jbitmap).makeImage(&colorFilter);
     73     }
     74 
     75     if (!image.get()) {
     76         SkBitmap bitmap;
     77         image = SkMakeImageFromRasterBitmap(bitmap, kNever_SkCopyPixelsMode);
     78     }
     79     sk_sp<SkShader> shader = image->makeShader(
     80             (SkShader::TileMode)tileModeX, (SkShader::TileMode)tileModeY);
     81 
     82     if (matrix) {
     83         shader = shader->makeWithLocalMatrix(*matrix);
     84     }
     85     if(colorFilter) {
     86         shader = shader->makeWithColorFilter(colorFilter);
     87     }
     88 
     89     ThrowIAE_IfNull(env, shader.get());
     90     return reinterpret_cast<jlong>(shader.release());
     91 }
     92 
     93 ///////////////////////////////////////////////////////////////////////////////////////////////
     94 
     95 static jlong LinearGradient_create1(JNIEnv* env, jobject o, jlong matrixPtr,
     96         jfloat x0, jfloat y0, jfloat x1, jfloat y1,
     97         jintArray colorArray, jfloatArray posArray, jint tileMode) {
     98     const SkMatrix* matrix = reinterpret_cast<const SkMatrix*>(matrixPtr);
     99     SkPoint pts[2];
    100     pts[0].set(x0, y0);
    101     pts[1].set(x1, y1);
    102 
    103     size_t count = env->GetArrayLength(colorArray);
    104     const jint* colorValues = env->GetIntArrayElements(colorArray, NULL);
    105 
    106     AutoJavaFloatArray autoPos(env, posArray, count);
    107 #ifdef SK_SCALAR_IS_FLOAT
    108     SkScalar* pos = autoPos.ptr();
    109 #else
    110     #error Need to convert float array to SkScalar array before calling the following function.
    111 #endif
    112 
    113     sk_sp<SkShader> baseShader(SkGradientShader::MakeLinear(pts,
    114             reinterpret_cast<const SkColor*>(colorValues), pos, count,
    115             static_cast<SkShader::TileMode>(tileMode), sGradientShaderFlags, NULL));
    116 
    117     SkShader* shader;
    118     if (matrix) {
    119         shader = baseShader->makeWithLocalMatrix(*matrix).release();
    120     } else {
    121         shader = baseShader.release();
    122     }
    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, jlong matrixPtr,
    130         jfloat x0, jfloat y0, jfloat x1, jfloat y1, jint color0, jint color1, jint tileMode) {
    131     const SkMatrix* matrix = reinterpret_cast<const SkMatrix*>(matrixPtr);
    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     sk_sp<SkShader> baseShader(SkGradientShader::MakeLinear(pts, colors, NULL, 2,
    142             static_cast<SkShader::TileMode>(tileMode), sGradientShaderFlags, NULL));
    143 
    144     SkShader* s;
    145     if (matrix) {
    146         s = baseShader->makeWithLocalMatrix(*matrix).release();
    147     } else {
    148         s = baseShader.release();
    149     }
    150 
    151     ThrowIAE_IfNull(env, s);
    152     return reinterpret_cast<jlong>(s);
    153 }
    154 
    155 ///////////////////////////////////////////////////////////////////////////////////////////////
    156 
    157 static jlong RadialGradient_create1(JNIEnv* env, jobject, jlong matrixPtr, jfloat x, jfloat y,
    158         jfloat radius, jintArray colorArray, jfloatArray posArray, jint tileMode) {
    159     const SkMatrix* matrix = reinterpret_cast<const SkMatrix*>(matrixPtr);
    160     SkPoint center;
    161     center.set(x, y);
    162 
    163     size_t      count = env->GetArrayLength(colorArray);
    164     const jint* colorValues = env->GetIntArrayElements(colorArray, NULL);
    165 
    166     AutoJavaFloatArray autoPos(env, posArray, count);
    167 #ifdef SK_SCALAR_IS_FLOAT
    168     SkScalar* pos = autoPos.ptr();
    169 #else
    170     #error Need to convert float array to SkScalar array before calling the following function.
    171 #endif
    172 
    173     sk_sp<SkShader> baseShader = SkGradientShader::MakeRadial(center, radius,
    174             reinterpret_cast<const SkColor*>(colorValues), pos, count,
    175             static_cast<SkShader::TileMode>(tileMode), sGradientShaderFlags, NULL);
    176 
    177     SkShader* shader;
    178     if (matrix) {
    179         shader = baseShader->makeWithLocalMatrix(*matrix).release();
    180     } else {
    181         shader = baseShader.release();
    182     }
    183 
    184     env->ReleaseIntArrayElements(colorArray, const_cast<jint*>(colorValues),
    185                                  JNI_ABORT);
    186 
    187     ThrowIAE_IfNull(env, shader);
    188     return reinterpret_cast<jlong>(shader);
    189 }
    190 
    191 static jlong RadialGradient_create2(JNIEnv* env, jobject, jlong matrixPtr, jfloat x, jfloat y, jfloat radius,
    192         jint color0, jint color1, jint tileMode) {
    193     const SkMatrix* matrix = reinterpret_cast<const SkMatrix*>(matrixPtr);
    194     SkPoint center;
    195     center.set(x, y);
    196 
    197     SkColor colors[2];
    198     colors[0] = color0;
    199     colors[1] = color1;
    200 
    201     sk_sp<SkShader> baseShader = SkGradientShader::MakeRadial(center, radius, colors, NULL, 2,
    202             static_cast<SkShader::TileMode>(tileMode), sGradientShaderFlags, NULL);
    203 
    204     SkShader* shader;
    205     if (matrix) {
    206         shader = baseShader->makeWithLocalMatrix(*matrix).release();
    207     } else {
    208         shader = baseShader.release();
    209     }
    210     ThrowIAE_IfNull(env, shader);
    211     return reinterpret_cast<jlong>(shader);
    212 }
    213 
    214 ///////////////////////////////////////////////////////////////////////////////
    215 
    216 static jlong SweepGradient_create1(JNIEnv* env, jobject, jlong matrixPtr, jfloat x, jfloat y,
    217         jintArray jcolors, jfloatArray jpositions) {
    218     const SkMatrix* matrix = reinterpret_cast<const SkMatrix*>(matrixPtr);
    219     size_t      count = env->GetArrayLength(jcolors);
    220     const jint* colors = env->GetIntArrayElements(jcolors, NULL);
    221 
    222     AutoJavaFloatArray autoPos(env, jpositions, count);
    223 #ifdef SK_SCALAR_IS_FLOAT
    224     SkScalar* pos = autoPos.ptr();
    225 #else
    226     #error Need to convert float array to SkScalar array before calling the following function.
    227 #endif
    228 
    229     sk_sp<SkShader> baseShader = SkGradientShader::MakeSweep(x, y,
    230             reinterpret_cast<const SkColor*>(colors), pos, count,
    231             sGradientShaderFlags, NULL);
    232 
    233     SkShader* shader;
    234     if (matrix) {
    235         shader = baseShader->makeWithLocalMatrix(*matrix).release();
    236     } else {
    237         shader = baseShader.release();
    238     }
    239 
    240     env->ReleaseIntArrayElements(jcolors, const_cast<jint*>(colors),
    241                                  JNI_ABORT);
    242     ThrowIAE_IfNull(env, shader);
    243     return reinterpret_cast<jlong>(shader);
    244 }
    245 
    246 static jlong SweepGradient_create2(JNIEnv* env, jobject, jlong matrixPtr, jfloat x, jfloat y,
    247         int color0, int color1) {
    248     const SkMatrix* matrix = reinterpret_cast<const SkMatrix*>(matrixPtr);
    249     SkColor colors[2];
    250     colors[0] = color0;
    251     colors[1] = color1;
    252 
    253     sk_sp<SkShader> baseShader = SkGradientShader::MakeSweep(x, y, colors,
    254             NULL, 2, sGradientShaderFlags, NULL);
    255 
    256     SkShader* shader;
    257     if (matrix) {
    258         shader = baseShader->makeWithLocalMatrix(*matrix).release();
    259     } else {
    260         shader = baseShader.release();
    261     }
    262     ThrowIAE_IfNull(env, shader);
    263     return reinterpret_cast<jlong>(shader);
    264 }
    265 
    266 ///////////////////////////////////////////////////////////////////////////////////////////////
    267 
    268 static jlong ComposeShader_create(JNIEnv* env, jobject o, jlong matrixPtr,
    269         jlong shaderAHandle, jlong shaderBHandle, jint xfermodeHandle) {
    270     const SkMatrix* matrix = reinterpret_cast<const SkMatrix*>(matrixPtr);
    271     SkShader* shaderA = reinterpret_cast<SkShader *>(shaderAHandle);
    272     SkShader* shaderB = reinterpret_cast<SkShader *>(shaderBHandle);
    273     SkBlendMode mode = static_cast<SkBlendMode>(xfermodeHandle);
    274     sk_sp<SkShader> baseShader(SkShader::MakeComposeShader(
    275             sk_ref_sp(shaderA), sk_ref_sp(shaderB), mode));
    276 
    277     SkShader* shader;
    278 
    279     if (matrix) {
    280         shader = baseShader->makeWithLocalMatrix(*matrix).release();
    281     } else {
    282         shader = baseShader.release();
    283     }
    284     return reinterpret_cast<jlong>(shader);
    285 }
    286 
    287 ///////////////////////////////////////////////////////////////////////////////////////////////
    288 
    289 static const JNINativeMethod gColorMethods[] = {
    290     { "nativeRGBToHSV",    "(III[F)V", (void*)Color_RGBToHSV   },
    291     { "nativeHSVToColor",  "(I[F)I",   (void*)Color_HSVToColor }
    292 };
    293 
    294 static const JNINativeMethod gShaderMethods[] = {
    295     { "nativeGetFinalizer",   "()J",    (void*)Shader_getNativeFinalizer },
    296 };
    297 
    298 static const JNINativeMethod gBitmapShaderMethods[] = {
    299     { "nativeCreate",      "(JLandroid/graphics/Bitmap;II)J",  (void*)BitmapShader_constructor },
    300 };
    301 
    302 static const JNINativeMethod gLinearGradientMethods[] = {
    303     { "nativeCreate1",     "(JFFFF[I[FI)J",  (void*)LinearGradient_create1     },
    304     { "nativeCreate2",     "(JFFFFIII)J",    (void*)LinearGradient_create2     },
    305 };
    306 
    307 static const JNINativeMethod gRadialGradientMethods[] = {
    308     { "nativeCreate1",     "(JFFF[I[FI)J",  (void*)RadialGradient_create1     },
    309     { "nativeCreate2",     "(JFFFIII)J",    (void*)RadialGradient_create2     },
    310 };
    311 
    312 static const JNINativeMethod gSweepGradientMethods[] = {
    313     { "nativeCreate1",     "(JFF[I[F)J",  (void*)SweepGradient_create1     },
    314     { "nativeCreate2",     "(JFFII)J",    (void*)SweepGradient_create2     },
    315 };
    316 
    317 static const JNINativeMethod gComposeShaderMethods[] = {
    318     { "nativeCreate",      "(JJJI)J",   (void*)ComposeShader_create     },
    319 };
    320 
    321 int register_android_graphics_Shader(JNIEnv* env)
    322 {
    323     android::RegisterMethodsOrDie(env, "android/graphics/Color", gColorMethods,
    324                                   NELEM(gColorMethods));
    325     android::RegisterMethodsOrDie(env, "android/graphics/Shader", gShaderMethods,
    326                                   NELEM(gShaderMethods));
    327     android::RegisterMethodsOrDie(env, "android/graphics/BitmapShader", gBitmapShaderMethods,
    328                                   NELEM(gBitmapShaderMethods));
    329     android::RegisterMethodsOrDie(env, "android/graphics/LinearGradient", gLinearGradientMethods,
    330                                   NELEM(gLinearGradientMethods));
    331     android::RegisterMethodsOrDie(env, "android/graphics/RadialGradient", gRadialGradientMethods,
    332                                   NELEM(gRadialGradientMethods));
    333     android::RegisterMethodsOrDie(env, "android/graphics/SweepGradient", gSweepGradientMethods,
    334                                   NELEM(gSweepGradientMethods));
    335     android::RegisterMethodsOrDie(env, "android/graphics/ComposeShader", gComposeShaderMethods,
    336                                   NELEM(gComposeShaderMethods));
    337 
    338     return 0;
    339 }
    340