Shader.cpp revision 669b15a93548b82135c73196665bcb7f03d87795
1#include "GraphicsJNI.h" 2#include "SkGradientShader.h" 3#include "SkImagePriv.h" 4#include "SkShader.h" 5#include "SkBlendMode.h" 6#include "core_jni_helpers.h" 7 8#include <Caches.h> 9#include <jni.h> 10 11using namespace android::uirenderer; 12 13/** 14 * By default Skia gradients will interpolate their colors in unpremul space 15 * and then premultiply each of the results. We must set this flag to preserve 16 * backwards compatiblity by premultiplying the colors of the gradient first, 17 * and then interpolating between them. 18 */ 19static const uint32_t sGradientShaderFlags = SkGradientShader::kInterpolateColorsInPremul_Flag; 20 21static void ThrowIAE_IfNull(JNIEnv* env, void* ptr) { 22 if (NULL == ptr) { 23 doThrowIAE(env); 24 } 25} 26 27static 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 39static 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 53static void Shader_safeUnref(JNIEnv* env, jobject o, jlong shaderHandle) { 54 SkShader* shader = reinterpret_cast<SkShader*>(shaderHandle); 55 SkSafeUnref(shader); 56} 57 58/////////////////////////////////////////////////////////////////////////////////////////////// 59 60static jlong BitmapShader_constructor(JNIEnv* env, jobject o, jlong matrixPtr, jobject jbitmap, 61 jint tileModeX, jint tileModeY) { 62 const SkMatrix* matrix = reinterpret_cast<const SkMatrix*>(matrixPtr); 63 SkBitmap bitmap; 64 if (jbitmap) { 65 // Only pass a valid SkBitmap object to the constructor if the Bitmap exists. Otherwise, 66 // we'll pass an empty SkBitmap to avoid crashing/excepting for compatibility. 67 android::bitmap::toBitmap(env, jbitmap).getSkBitmapForShaders(&bitmap); 68 } 69 70 sk_sp<SkImage> image = SkMakeImageFromRasterBitmap(bitmap, kNever_SkCopyPixelsMode); 71 sk_sp<SkShader> shader = image->makeShader( 72 (SkShader::TileMode)tileModeX, (SkShader::TileMode)tileModeY, matrix); 73 74 ThrowIAE_IfNull(env, shader.get()); 75 return reinterpret_cast<jlong>(shader.release()); 76} 77 78/////////////////////////////////////////////////////////////////////////////////////////////// 79 80static jlong LinearGradient_create1(JNIEnv* env, jobject o, jlong matrixPtr, 81 jfloat x0, jfloat y0, jfloat x1, jfloat y1, 82 jintArray colorArray, jfloatArray posArray, jint tileMode) { 83 const SkMatrix* matrix = reinterpret_cast<const SkMatrix*>(matrixPtr); 84 SkPoint pts[2]; 85 pts[0].set(x0, y0); 86 pts[1].set(x1, y1); 87 88 size_t count = env->GetArrayLength(colorArray); 89 const jint* colorValues = env->GetIntArrayElements(colorArray, NULL); 90 91 AutoJavaFloatArray autoPos(env, posArray, count); 92#ifdef SK_SCALAR_IS_FLOAT 93 SkScalar* pos = autoPos.ptr(); 94#else 95 #error Need to convert float array to SkScalar array before calling the following function. 96#endif 97 98 SkShader* shader = SkGradientShader::MakeLinear(pts, 99 reinterpret_cast<const SkColor*>(colorValues), pos, count, 100 static_cast<SkShader::TileMode>(tileMode), sGradientShaderFlags, matrix).release(); 101 102 env->ReleaseIntArrayElements(colorArray, const_cast<jint*>(colorValues), JNI_ABORT); 103 ThrowIAE_IfNull(env, shader); 104 return reinterpret_cast<jlong>(shader); 105} 106 107static jlong LinearGradient_create2(JNIEnv* env, jobject o, jlong matrixPtr, 108 jfloat x0, jfloat y0, jfloat x1, jfloat y1, jint color0, jint color1, jint tileMode) { 109 const SkMatrix* matrix = reinterpret_cast<const SkMatrix*>(matrixPtr); 110 111 SkPoint pts[2]; 112 pts[0].set(x0, y0); 113 pts[1].set(x1, y1); 114 115 SkColor colors[2]; 116 colors[0] = color0; 117 colors[1] = color1; 118 119 SkShader* s = SkGradientShader::MakeLinear(pts, colors, NULL, 2, 120 static_cast<SkShader::TileMode>(tileMode), sGradientShaderFlags, matrix).release(); 121 122 ThrowIAE_IfNull(env, s); 123 return reinterpret_cast<jlong>(s); 124} 125 126/////////////////////////////////////////////////////////////////////////////////////////////// 127 128static jlong RadialGradient_create1(JNIEnv* env, jobject, jlong matrixPtr, jfloat x, jfloat y, 129 jfloat radius, jintArray colorArray, jfloatArray posArray, jint tileMode) { 130 const SkMatrix* matrix = reinterpret_cast<const SkMatrix*>(matrixPtr); 131 SkPoint center; 132 center.set(x, y); 133 134 size_t count = env->GetArrayLength(colorArray); 135 const jint* colorValues = env->GetIntArrayElements(colorArray, NULL); 136 137 AutoJavaFloatArray autoPos(env, posArray, count); 138#ifdef SK_SCALAR_IS_FLOAT 139 SkScalar* pos = autoPos.ptr(); 140#else 141 #error Need to convert float array to SkScalar array before calling the following function. 142#endif 143 144 SkShader* shader = SkGradientShader::MakeRadial(center, radius, 145 reinterpret_cast<const SkColor*>(colorValues), pos, count, 146 static_cast<SkShader::TileMode>(tileMode), sGradientShaderFlags, matrix).release(); 147 env->ReleaseIntArrayElements(colorArray, const_cast<jint*>(colorValues), 148 JNI_ABORT); 149 150 ThrowIAE_IfNull(env, shader); 151 return reinterpret_cast<jlong>(shader); 152} 153 154static jlong RadialGradient_create2(JNIEnv* env, jobject, jlong matrixPtr, jfloat x, jfloat y, jfloat radius, 155 jint color0, jint color1, jint tileMode) { 156 const SkMatrix* matrix = reinterpret_cast<const SkMatrix*>(matrixPtr); 157 SkPoint center; 158 center.set(x, y); 159 160 SkColor colors[2]; 161 colors[0] = color0; 162 colors[1] = color1; 163 164 SkShader* s = SkGradientShader::MakeRadial(center, radius, colors, NULL, 2, 165 static_cast<SkShader::TileMode>(tileMode), sGradientShaderFlags, matrix).release(); 166 ThrowIAE_IfNull(env, s); 167 return reinterpret_cast<jlong>(s); 168} 169 170/////////////////////////////////////////////////////////////////////////////// 171 172static jlong SweepGradient_create1(JNIEnv* env, jobject, jlong matrixPtr, jfloat x, jfloat y, 173 jintArray jcolors, jfloatArray jpositions) { 174 const SkMatrix* matrix = reinterpret_cast<const SkMatrix*>(matrixPtr); 175 size_t count = env->GetArrayLength(jcolors); 176 const jint* colors = env->GetIntArrayElements(jcolors, NULL); 177 178 AutoJavaFloatArray autoPos(env, jpositions, count); 179#ifdef SK_SCALAR_IS_FLOAT 180 SkScalar* pos = autoPos.ptr(); 181#else 182 #error Need to convert float array to SkScalar array before calling the following function. 183#endif 184 185 SkShader* shader = SkGradientShader::MakeSweep(x, y, reinterpret_cast<const SkColor*>(colors), 186 pos, count, sGradientShaderFlags, matrix).release(); 187 env->ReleaseIntArrayElements(jcolors, const_cast<jint*>(colors), 188 JNI_ABORT); 189 ThrowIAE_IfNull(env, shader); 190 return reinterpret_cast<jlong>(shader); 191} 192 193static jlong SweepGradient_create2(JNIEnv* env, jobject, jlong matrixPtr, jfloat x, jfloat y, 194 int color0, int color1) { 195 const SkMatrix* matrix = reinterpret_cast<const SkMatrix*>(matrixPtr); 196 SkColor colors[2]; 197 colors[0] = color0; 198 colors[1] = color1; 199 SkShader* s = SkGradientShader::MakeSweep(x, y, colors, NULL, 2, 200 sGradientShaderFlags, matrix).release(); 201 ThrowIAE_IfNull(env, s); 202 return reinterpret_cast<jlong>(s); 203} 204 205/////////////////////////////////////////////////////////////////////////////////////////////// 206 207static jlong ComposeShader_create(JNIEnv* env, jobject o, jlong matrixPtr, 208 jlong shaderAHandle, jlong shaderBHandle, jint xfermodeHandle) { 209 const SkMatrix* matrix = reinterpret_cast<const SkMatrix*>(matrixPtr); 210 SkShader* shaderA = reinterpret_cast<SkShader *>(shaderAHandle); 211 SkShader* shaderB = reinterpret_cast<SkShader *>(shaderBHandle); 212 SkBlendMode mode = static_cast<SkBlendMode>(xfermodeHandle); 213 sk_sp<SkShader> baseShader(SkShader::MakeComposeShader( 214 sk_ref_sp(shaderA), sk_ref_sp(shaderB), mode)); 215 216 SkShader* shader; 217 218 if (matrix) { 219 shader = baseShader->makeWithLocalMatrix(*matrix).release(); 220 } else { 221 shader = baseShader.release(); 222 } 223 return reinterpret_cast<jlong>(shader); 224} 225 226/////////////////////////////////////////////////////////////////////////////////////////////// 227 228static const JNINativeMethod gColorMethods[] = { 229 { "nativeRGBToHSV", "(III[F)V", (void*)Color_RGBToHSV }, 230 { "nativeHSVToColor", "(I[F)I", (void*)Color_HSVToColor } 231}; 232 233static const JNINativeMethod gShaderMethods[] = { 234 { "nativeSafeUnref", "(J)V", (void*)Shader_safeUnref }, 235}; 236 237static const JNINativeMethod gBitmapShaderMethods[] = { 238 { "nativeCreate", "(JLandroid/graphics/Bitmap;II)J", (void*)BitmapShader_constructor }, 239}; 240 241static const JNINativeMethod gLinearGradientMethods[] = { 242 { "nativeCreate1", "(JFFFF[I[FI)J", (void*)LinearGradient_create1 }, 243 { "nativeCreate2", "(JFFFFIII)J", (void*)LinearGradient_create2 }, 244}; 245 246static const JNINativeMethod gRadialGradientMethods[] = { 247 { "nativeCreate1", "(JFFF[I[FI)J", (void*)RadialGradient_create1 }, 248 { "nativeCreate2", "(JFFFIII)J", (void*)RadialGradient_create2 }, 249}; 250 251static const JNINativeMethod gSweepGradientMethods[] = { 252 { "nativeCreate1", "(JFF[I[F)J", (void*)SweepGradient_create1 }, 253 { "nativeCreate2", "(JFFII)J", (void*)SweepGradient_create2 }, 254}; 255 256static const JNINativeMethod gComposeShaderMethods[] = { 257 { "nativeCreate", "(JJJI)J", (void*)ComposeShader_create }, 258}; 259 260int register_android_graphics_Shader(JNIEnv* env) 261{ 262 android::RegisterMethodsOrDie(env, "android/graphics/Color", gColorMethods, 263 NELEM(gColorMethods)); 264 android::RegisterMethodsOrDie(env, "android/graphics/Shader", gShaderMethods, 265 NELEM(gShaderMethods)); 266 android::RegisterMethodsOrDie(env, "android/graphics/BitmapShader", gBitmapShaderMethods, 267 NELEM(gBitmapShaderMethods)); 268 android::RegisterMethodsOrDie(env, "android/graphics/LinearGradient", gLinearGradientMethods, 269 NELEM(gLinearGradientMethods)); 270 android::RegisterMethodsOrDie(env, "android/graphics/RadialGradient", gRadialGradientMethods, 271 NELEM(gRadialGradientMethods)); 272 android::RegisterMethodsOrDie(env, "android/graphics/SweepGradient", gSweepGradientMethods, 273 NELEM(gSweepGradientMethods)); 274 android::RegisterMethodsOrDie(env, "android/graphics/ComposeShader", gComposeShaderMethods, 275 NELEM(gComposeShaderMethods)); 276 277 return 0; 278} 279