Shader.cpp revision b33013fb3c570e0a3ced8729dced9f0d294761a6
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 sk_sp<SkImage> image; 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 image = android::bitmap::toBitmap(env, jbitmap).makeImage(nullptr); 68 } 69 70 if (!image.get()) { 71 SkBitmap bitmap; 72 image = SkMakeImageFromRasterBitmap(bitmap, kNever_SkCopyPixelsMode); 73 } 74 sk_sp<SkShader> baseShader = image->makeShader( 75 (SkShader::TileMode)tileModeX, (SkShader::TileMode)tileModeY); 76 77 SkShader* shader; 78 if (matrix) { 79 shader = baseShader->makeWithLocalMatrix(*matrix).release(); 80 } else { 81 shader = baseShader.release(); 82 } 83 84 ThrowIAE_IfNull(env, shader); 85 return reinterpret_cast<jlong>(shader); 86} 87 88/////////////////////////////////////////////////////////////////////////////////////////////// 89 90static jlong LinearGradient_create1(JNIEnv* env, jobject o, jlong matrixPtr, 91 jfloat x0, jfloat y0, jfloat x1, jfloat y1, 92 jintArray colorArray, jfloatArray posArray, jint tileMode) { 93 const SkMatrix* matrix = reinterpret_cast<const SkMatrix*>(matrixPtr); 94 SkPoint pts[2]; 95 pts[0].set(x0, y0); 96 pts[1].set(x1, y1); 97 98 size_t count = env->GetArrayLength(colorArray); 99 const jint* colorValues = env->GetIntArrayElements(colorArray, NULL); 100 101 AutoJavaFloatArray autoPos(env, posArray, count); 102#ifdef SK_SCALAR_IS_FLOAT 103 SkScalar* pos = autoPos.ptr(); 104#else 105 #error Need to convert float array to SkScalar array before calling the following function. 106#endif 107 108 sk_sp<SkShader> baseShader(SkGradientShader::MakeLinear(pts, 109 reinterpret_cast<const SkColor*>(colorValues), pos, count, 110 static_cast<SkShader::TileMode>(tileMode), sGradientShaderFlags, NULL)); 111 112 SkShader* shader; 113 if (matrix) { 114 shader = baseShader->makeWithLocalMatrix(*matrix).release(); 115 } else { 116 shader = baseShader.release(); 117 } 118 119 env->ReleaseIntArrayElements(colorArray, const_cast<jint*>(colorValues), JNI_ABORT); 120 ThrowIAE_IfNull(env, shader); 121 return reinterpret_cast<jlong>(shader); 122} 123 124static jlong LinearGradient_create2(JNIEnv* env, jobject o, jlong matrixPtr, 125 jfloat x0, jfloat y0, jfloat x1, jfloat y1, jint color0, jint color1, jint tileMode) { 126 const SkMatrix* matrix = reinterpret_cast<const SkMatrix*>(matrixPtr); 127 128 SkPoint pts[2]; 129 pts[0].set(x0, y0); 130 pts[1].set(x1, y1); 131 132 SkColor colors[2]; 133 colors[0] = color0; 134 colors[1] = color1; 135 136 sk_sp<SkShader> baseShader(SkGradientShader::MakeLinear(pts, colors, NULL, 2, 137 static_cast<SkShader::TileMode>(tileMode), sGradientShaderFlags, NULL)); 138 139 SkShader* s; 140 if (matrix) { 141 s = baseShader->makeWithLocalMatrix(*matrix).release(); 142 } else { 143 s = baseShader.release(); 144 } 145 146 ThrowIAE_IfNull(env, s); 147 return reinterpret_cast<jlong>(s); 148} 149 150/////////////////////////////////////////////////////////////////////////////////////////////// 151 152static jlong RadialGradient_create1(JNIEnv* env, jobject, jlong matrixPtr, jfloat x, jfloat y, 153 jfloat radius, jintArray colorArray, jfloatArray posArray, jint tileMode) { 154 const SkMatrix* matrix = reinterpret_cast<const SkMatrix*>(matrixPtr); 155 SkPoint center; 156 center.set(x, y); 157 158 size_t count = env->GetArrayLength(colorArray); 159 const jint* colorValues = env->GetIntArrayElements(colorArray, NULL); 160 161 AutoJavaFloatArray autoPos(env, posArray, count); 162#ifdef SK_SCALAR_IS_FLOAT 163 SkScalar* pos = autoPos.ptr(); 164#else 165 #error Need to convert float array to SkScalar array before calling the following function. 166#endif 167 168 sk_sp<SkShader> baseShader = SkGradientShader::MakeRadial(center, radius, 169 reinterpret_cast<const SkColor*>(colorValues), pos, count, 170 static_cast<SkShader::TileMode>(tileMode), sGradientShaderFlags, NULL); 171 172 SkShader* shader; 173 if (matrix) { 174 shader = baseShader->makeWithLocalMatrix(*matrix).release(); 175 } else { 176 shader = baseShader.release(); 177 } 178 179 env->ReleaseIntArrayElements(colorArray, const_cast<jint*>(colorValues), 180 JNI_ABORT); 181 182 ThrowIAE_IfNull(env, shader); 183 return reinterpret_cast<jlong>(shader); 184} 185 186static jlong RadialGradient_create2(JNIEnv* env, jobject, jlong matrixPtr, jfloat x, jfloat y, jfloat radius, 187 jint color0, jint color1, jint tileMode) { 188 const SkMatrix* matrix = reinterpret_cast<const SkMatrix*>(matrixPtr); 189 SkPoint center; 190 center.set(x, y); 191 192 SkColor colors[2]; 193 colors[0] = color0; 194 colors[1] = color1; 195 196 sk_sp<SkShader> baseShader = SkGradientShader::MakeRadial(center, radius, colors, NULL, 2, 197 static_cast<SkShader::TileMode>(tileMode), sGradientShaderFlags, NULL); 198 199 SkShader* shader; 200 if (matrix) { 201 shader = baseShader->makeWithLocalMatrix(*matrix).release(); 202 } else { 203 shader = baseShader.release(); 204 } 205 ThrowIAE_IfNull(env, shader); 206 return reinterpret_cast<jlong>(shader); 207} 208 209/////////////////////////////////////////////////////////////////////////////// 210 211static jlong SweepGradient_create1(JNIEnv* env, jobject, jlong matrixPtr, jfloat x, jfloat y, 212 jintArray jcolors, jfloatArray jpositions) { 213 const SkMatrix* matrix = reinterpret_cast<const SkMatrix*>(matrixPtr); 214 size_t count = env->GetArrayLength(jcolors); 215 const jint* colors = env->GetIntArrayElements(jcolors, NULL); 216 217 AutoJavaFloatArray autoPos(env, jpositions, count); 218#ifdef SK_SCALAR_IS_FLOAT 219 SkScalar* pos = autoPos.ptr(); 220#else 221 #error Need to convert float array to SkScalar array before calling the following function. 222#endif 223 224 sk_sp<SkShader> baseShader = SkGradientShader::MakeSweep(x, y, 225 reinterpret_cast<const SkColor*>(colors), pos, count, 226 sGradientShaderFlags, NULL); 227 228 SkShader* shader; 229 if (matrix) { 230 shader = baseShader->makeWithLocalMatrix(*matrix).release(); 231 } else { 232 shader = baseShader.release(); 233 } 234 235 env->ReleaseIntArrayElements(jcolors, const_cast<jint*>(colors), 236 JNI_ABORT); 237 ThrowIAE_IfNull(env, shader); 238 return reinterpret_cast<jlong>(shader); 239} 240 241static jlong SweepGradient_create2(JNIEnv* env, jobject, jlong matrixPtr, jfloat x, jfloat y, 242 int color0, int color1) { 243 const SkMatrix* matrix = reinterpret_cast<const SkMatrix*>(matrixPtr); 244 SkColor colors[2]; 245 colors[0] = color0; 246 colors[1] = color1; 247 248 sk_sp<SkShader> baseShader = SkGradientShader::MakeSweep(x, y, colors, 249 NULL, 2, sGradientShaderFlags, NULL); 250 251 SkShader* shader; 252 if (matrix) { 253 shader = baseShader->makeWithLocalMatrix(*matrix).release(); 254 } else { 255 shader = baseShader.release(); 256 } 257 ThrowIAE_IfNull(env, shader); 258 return reinterpret_cast<jlong>(shader); 259} 260 261/////////////////////////////////////////////////////////////////////////////////////////////// 262 263static jlong ComposeShader_create(JNIEnv* env, jobject o, jlong matrixPtr, 264 jlong shaderAHandle, jlong shaderBHandle, jint xfermodeHandle) { 265 const SkMatrix* matrix = reinterpret_cast<const SkMatrix*>(matrixPtr); 266 SkShader* shaderA = reinterpret_cast<SkShader *>(shaderAHandle); 267 SkShader* shaderB = reinterpret_cast<SkShader *>(shaderBHandle); 268 SkBlendMode mode = static_cast<SkBlendMode>(xfermodeHandle); 269 sk_sp<SkShader> baseShader(SkShader::MakeComposeShader( 270 sk_ref_sp(shaderA), sk_ref_sp(shaderB), mode)); 271 272 SkShader* shader; 273 274 if (matrix) { 275 shader = baseShader->makeWithLocalMatrix(*matrix).release(); 276 } else { 277 shader = baseShader.release(); 278 } 279 return reinterpret_cast<jlong>(shader); 280} 281 282/////////////////////////////////////////////////////////////////////////////////////////////// 283 284static const JNINativeMethod gColorMethods[] = { 285 { "nativeRGBToHSV", "(III[F)V", (void*)Color_RGBToHSV }, 286 { "nativeHSVToColor", "(I[F)I", (void*)Color_HSVToColor } 287}; 288 289static const JNINativeMethod gShaderMethods[] = { 290 { "nativeSafeUnref", "(J)V", (void*)Shader_safeUnref }, 291}; 292 293static const JNINativeMethod gBitmapShaderMethods[] = { 294 { "nativeCreate", "(JLandroid/graphics/Bitmap;II)J", (void*)BitmapShader_constructor }, 295}; 296 297static const JNINativeMethod gLinearGradientMethods[] = { 298 { "nativeCreate1", "(JFFFF[I[FI)J", (void*)LinearGradient_create1 }, 299 { "nativeCreate2", "(JFFFFIII)J", (void*)LinearGradient_create2 }, 300}; 301 302static const JNINativeMethod gRadialGradientMethods[] = { 303 { "nativeCreate1", "(JFFF[I[FI)J", (void*)RadialGradient_create1 }, 304 { "nativeCreate2", "(JFFFIII)J", (void*)RadialGradient_create2 }, 305}; 306 307static const JNINativeMethod gSweepGradientMethods[] = { 308 { "nativeCreate1", "(JFF[I[F)J", (void*)SweepGradient_create1 }, 309 { "nativeCreate2", "(JFFII)J", (void*)SweepGradient_create2 }, 310}; 311 312static const JNINativeMethod gComposeShaderMethods[] = { 313 { "nativeCreate", "(JJJI)J", (void*)ComposeShader_create }, 314}; 315 316int register_android_graphics_Shader(JNIEnv* env) 317{ 318 android::RegisterMethodsOrDie(env, "android/graphics/Color", gColorMethods, 319 NELEM(gColorMethods)); 320 android::RegisterMethodsOrDie(env, "android/graphics/Shader", gShaderMethods, 321 NELEM(gShaderMethods)); 322 android::RegisterMethodsOrDie(env, "android/graphics/BitmapShader", gBitmapShaderMethods, 323 NELEM(gBitmapShaderMethods)); 324 android::RegisterMethodsOrDie(env, "android/graphics/LinearGradient", gLinearGradientMethods, 325 NELEM(gLinearGradientMethods)); 326 android::RegisterMethodsOrDie(env, "android/graphics/RadialGradient", gRadialGradientMethods, 327 NELEM(gRadialGradientMethods)); 328 android::RegisterMethodsOrDie(env, "android/graphics/SweepGradient", gSweepGradientMethods, 329 NELEM(gSweepGradientMethods)); 330 android::RegisterMethodsOrDie(env, "android/graphics/ComposeShader", gComposeShaderMethods, 331 NELEM(gComposeShaderMethods)); 332 333 return 0; 334} 335