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 <jni.h>
     10 
     11 #include <vector>
     12 
     13 using namespace android::uirenderer;
     14 
     15 /**
     16  * By default Skia gradients will interpolate their colors in unpremul space
     17  * and then premultiply each of the results. We must set this flag to preserve
     18  * backwards compatiblity by premultiplying the colors of the gradient first,
     19  * and then interpolating between them.
     20  */
     21 static const uint32_t sGradientShaderFlags = SkGradientShader::kInterpolateColorsInPremul_Flag;
     22 
     23 #define ThrowIAE_IfNull(env, ptr)   \
     24     if (nullptr == ptr) {           \
     25         doThrowIAE(env);            \
     26         return 0;                   \
     27     }
     28 
     29 static void Color_RGBToHSV(JNIEnv* env, jobject, jint red, jint green, jint blue, jfloatArray hsvArray)
     30 {
     31     SkScalar hsv[3];
     32     SkRGBToHSV(red, green, blue, hsv);
     33 
     34     AutoJavaFloatArray  autoHSV(env, hsvArray, 3);
     35     float* values = autoHSV.ptr();
     36     for (int i = 0; i < 3; i++) {
     37         values[i] = SkScalarToFloat(hsv[i]);
     38     }
     39 }
     40 
     41 static jint Color_HSVToColor(JNIEnv* env, jobject, jint alpha, jfloatArray hsvArray)
     42 {
     43     AutoJavaFloatArray  autoHSV(env, hsvArray, 3);
     44 #ifdef SK_SCALAR_IS_FLOAT
     45     SkScalar*   hsv = autoHSV.ptr();
     46 #else
     47     #error Need to convert float array to SkScalar array before calling the following function.
     48 #endif
     49 
     50     return static_cast<jint>(SkHSVToColor(alpha, hsv));
     51 }
     52 
     53 ///////////////////////////////////////////////////////////////////////////////////////////////
     54 
     55 static void Shader_safeUnref(SkShader* shader) {
     56     SkSafeUnref(shader);
     57 }
     58 
     59 static jlong Shader_getNativeFinalizer(JNIEnv*, jobject) {
     60     return static_cast<jlong>(reinterpret_cast<uintptr_t>(&Shader_safeUnref));
     61 }
     62 
     63 ///////////////////////////////////////////////////////////////////////////////////////////////
     64 
     65 static jlong BitmapShader_constructor(JNIEnv* env, jobject o, jlong matrixPtr, jlong bitmapHandle,
     66         jint tileModeX, jint tileModeY) {
     67     const SkMatrix* matrix = reinterpret_cast<const SkMatrix*>(matrixPtr);
     68     sk_sp<SkImage> image;
     69     if (bitmapHandle) {
     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(bitmapHandle).makeImage();
     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     ThrowIAE_IfNull(env, shader.get());
     82 
     83     if (matrix) {
     84         shader = shader->makeWithLocalMatrix(*matrix);
     85     }
     86 
     87     return reinterpret_cast<jlong>(shader.release());
     88 }
     89 
     90 ///////////////////////////////////////////////////////////////////////////////////////////////
     91 
     92 static std::vector<SkColor4f> convertColorLongs(JNIEnv* env, jlongArray colorArray) {
     93     const size_t count = env->GetArrayLength(colorArray);
     94     const jlong* colorValues = env->GetLongArrayElements(colorArray, nullptr);
     95 
     96     std::vector<SkColor4f> colors(count);
     97     for (size_t i = 0; i < count; ++i) {
     98         colors[i] = GraphicsJNI::convertColorLong(colorValues[i]);
     99     }
    100 
    101     env->ReleaseLongArrayElements(colorArray, const_cast<jlong*>(colorValues), JNI_ABORT);
    102     return colors;
    103 }
    104 
    105 ///////////////////////////////////////////////////////////////////////////////////////////////
    106 
    107 static jlong LinearGradient_create(JNIEnv* env, jobject, jlong matrixPtr,
    108         jfloat x0, jfloat y0, jfloat x1, jfloat y1, jlongArray colorArray,
    109         jfloatArray posArray, jint tileMode, jlong colorSpaceHandle) {
    110     SkPoint pts[2];
    111     pts[0].set(x0, y0);
    112     pts[1].set(x1, y1);
    113 
    114     std::vector<SkColor4f> colors = convertColorLongs(env, colorArray);
    115 
    116     AutoJavaFloatArray autoPos(env, posArray, colors.size());
    117 #ifdef SK_SCALAR_IS_FLOAT
    118     SkScalar* pos = autoPos.ptr();
    119 #else
    120     #error Need to convert float array to SkScalar array before calling the following function.
    121 #endif
    122 
    123     sk_sp<SkShader> shader(SkGradientShader::MakeLinear(pts, &colors[0],
    124                 GraphicsJNI::getNativeColorSpace(colorSpaceHandle), pos, colors.size(),
    125                 static_cast<SkShader::TileMode>(tileMode), sGradientShaderFlags, nullptr));
    126     ThrowIAE_IfNull(env, shader);
    127 
    128     const SkMatrix* matrix = reinterpret_cast<const SkMatrix*>(matrixPtr);
    129     if (matrix) {
    130         shader = shader->makeWithLocalMatrix(*matrix);
    131     }
    132 
    133     return reinterpret_cast<jlong>(shader.release());
    134 }
    135 
    136 ///////////////////////////////////////////////////////////////////////////////////////////////
    137 
    138 static jlong RadialGradient_create(JNIEnv* env, jobject, jlong matrixPtr, jfloat x, jfloat y,
    139         jfloat radius, jlongArray colorArray, jfloatArray posArray, jint tileMode,
    140         jlong colorSpaceHandle) {
    141     SkPoint center;
    142     center.set(x, y);
    143 
    144     std::vector<SkColor4f> colors = convertColorLongs(env, colorArray);
    145 
    146     AutoJavaFloatArray autoPos(env, posArray, colors.size());
    147 #ifdef SK_SCALAR_IS_FLOAT
    148     SkScalar* pos = autoPos.ptr();
    149 #else
    150     #error Need to convert float array to SkScalar array before calling the following function.
    151 #endif
    152 
    153     sk_sp<SkShader> shader = SkGradientShader::MakeRadial(center, radius, &colors[0],
    154             GraphicsJNI::getNativeColorSpace(colorSpaceHandle), pos, colors.size(),
    155             static_cast<SkShader::TileMode>(tileMode), sGradientShaderFlags, nullptr);
    156     ThrowIAE_IfNull(env, shader);
    157 
    158     const SkMatrix* matrix = reinterpret_cast<const SkMatrix*>(matrixPtr);
    159     if (matrix) {
    160         shader = shader->makeWithLocalMatrix(*matrix);
    161     }
    162 
    163     return reinterpret_cast<jlong>(shader.release());
    164 }
    165 
    166 ///////////////////////////////////////////////////////////////////////////////
    167 
    168 static jlong SweepGradient_create(JNIEnv* env, jobject, jlong matrixPtr, jfloat x, jfloat y,
    169         jlongArray colorArray, jfloatArray jpositions, jlong colorSpaceHandle) {
    170     std::vector<SkColor4f> colors = convertColorLongs(env, colorArray);
    171 
    172     AutoJavaFloatArray autoPos(env, jpositions, colors.size());
    173 #ifdef SK_SCALAR_IS_FLOAT
    174     SkScalar* pos = autoPos.ptr();
    175 #else
    176     #error Need to convert float array to SkScalar array before calling the following function.
    177 #endif
    178 
    179     sk_sp<SkShader> shader = SkGradientShader::MakeSweep(x, y, &colors[0],
    180             GraphicsJNI::getNativeColorSpace(colorSpaceHandle), pos, colors.size(),
    181             sGradientShaderFlags, nullptr);
    182     ThrowIAE_IfNull(env, shader);
    183 
    184     const SkMatrix* matrix = reinterpret_cast<const SkMatrix*>(matrixPtr);
    185     if (matrix) {
    186         shader = shader->makeWithLocalMatrix(*matrix);
    187     }
    188 
    189     return reinterpret_cast<jlong>(shader.release());
    190 }
    191 
    192 ///////////////////////////////////////////////////////////////////////////////////////////////
    193 
    194 static jlong ComposeShader_create(JNIEnv* env, jobject o, jlong matrixPtr,
    195         jlong shaderAHandle, jlong shaderBHandle, jint xfermodeHandle) {
    196     const SkMatrix* matrix = reinterpret_cast<const SkMatrix*>(matrixPtr);
    197     SkShader* shaderA = reinterpret_cast<SkShader *>(shaderAHandle);
    198     SkShader* shaderB = reinterpret_cast<SkShader *>(shaderBHandle);
    199     SkBlendMode mode = static_cast<SkBlendMode>(xfermodeHandle);
    200     sk_sp<SkShader> baseShader(SkShader::MakeComposeShader(
    201             sk_ref_sp(shaderA), sk_ref_sp(shaderB), mode));
    202 
    203     SkShader* shader;
    204 
    205     if (matrix) {
    206         shader = baseShader->makeWithLocalMatrix(*matrix).release();
    207     } else {
    208         shader = baseShader.release();
    209     }
    210     return reinterpret_cast<jlong>(shader);
    211 }
    212 
    213 ///////////////////////////////////////////////////////////////////////////////////////////////
    214 
    215 static const JNINativeMethod gColorMethods[] = {
    216     { "nativeRGBToHSV",    "(III[F)V", (void*)Color_RGBToHSV   },
    217     { "nativeHSVToColor",  "(I[F)I",   (void*)Color_HSVToColor }
    218 };
    219 
    220 static const JNINativeMethod gShaderMethods[] = {
    221     { "nativeGetFinalizer",   "()J",    (void*)Shader_getNativeFinalizer },
    222 };
    223 
    224 static const JNINativeMethod gBitmapShaderMethods[] = {
    225     { "nativeCreate",      "(JJII)J",  (void*)BitmapShader_constructor },
    226 };
    227 
    228 static const JNINativeMethod gLinearGradientMethods[] = {
    229     { "nativeCreate",     "(JFFFF[J[FIJ)J",  (void*)LinearGradient_create     },
    230 };
    231 
    232 static const JNINativeMethod gRadialGradientMethods[] = {
    233     { "nativeCreate",     "(JFFF[J[FIJ)J",  (void*)RadialGradient_create     },
    234 };
    235 
    236 static const JNINativeMethod gSweepGradientMethods[] = {
    237     { "nativeCreate",     "(JFF[J[FJ)J",  (void*)SweepGradient_create     },
    238 };
    239 
    240 static const JNINativeMethod gComposeShaderMethods[] = {
    241     { "nativeCreate",      "(JJJI)J",   (void*)ComposeShader_create     },
    242 };
    243 
    244 int register_android_graphics_Shader(JNIEnv* env)
    245 {
    246     android::RegisterMethodsOrDie(env, "android/graphics/Color", gColorMethods,
    247                                   NELEM(gColorMethods));
    248     android::RegisterMethodsOrDie(env, "android/graphics/Shader", gShaderMethods,
    249                                   NELEM(gShaderMethods));
    250     android::RegisterMethodsOrDie(env, "android/graphics/BitmapShader", gBitmapShaderMethods,
    251                                   NELEM(gBitmapShaderMethods));
    252     android::RegisterMethodsOrDie(env, "android/graphics/LinearGradient", gLinearGradientMethods,
    253                                   NELEM(gLinearGradientMethods));
    254     android::RegisterMethodsOrDie(env, "android/graphics/RadialGradient", gRadialGradientMethods,
    255                                   NELEM(gRadialGradientMethods));
    256     android::RegisterMethodsOrDie(env, "android/graphics/SweepGradient", gSweepGradientMethods,
    257                                   NELEM(gSweepGradientMethods));
    258     android::RegisterMethodsOrDie(env, "android/graphics/ComposeShader", gComposeShaderMethods,
    259                                   NELEM(gComposeShaderMethods));
    260 
    261     return 0;
    262 }
    263