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