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