1#include "GraphicsJNI.h" 2#include "SkGradientShader.h" 3#include "SkShader.h" 4#include "SkXfermode.h" 5#include "core_jni_helpers.h" 6 7#include <Caches.h> 8#include <jni.h> 9 10using namespace android::uirenderer; 11 12static void ThrowIAE_IfNull(JNIEnv* env, void* ptr) { 13 if (NULL == ptr) { 14 doThrowIAE(env); 15 } 16} 17 18static void Color_RGBToHSV(JNIEnv* env, jobject, jint red, jint green, jint blue, jfloatArray hsvArray) 19{ 20 SkScalar hsv[3]; 21 SkRGBToHSV(red, green, blue, hsv); 22 23 AutoJavaFloatArray autoHSV(env, hsvArray, 3); 24 float* values = autoHSV.ptr(); 25 for (int i = 0; i < 3; i++) { 26 values[i] = SkScalarToFloat(hsv[i]); 27 } 28} 29 30static jint Color_HSVToColor(JNIEnv* env, jobject, jint alpha, jfloatArray hsvArray) 31{ 32 AutoJavaFloatArray autoHSV(env, hsvArray, 3); 33#ifdef SK_SCALAR_IS_FLOAT 34 SkScalar* hsv = autoHSV.ptr(); 35#else 36 #error Need to convert float array to SkScalar array before calling the following function. 37#endif 38 39 return static_cast<jint>(SkHSVToColor(alpha, hsv)); 40} 41 42/////////////////////////////////////////////////////////////////////////////////////////////// 43 44static void Shader_destructor(JNIEnv* env, jobject o, jlong shaderHandle, jlong shaderWithLMHandle) 45{ 46 SkShader* shader = reinterpret_cast<SkShader*>(shaderHandle); 47 SkSafeUnref(shader); 48} 49 50static jlong Shader_setLocalMatrix(JNIEnv* env, jobject o, jlong shaderHandle, jlong matrixHandle) 51{ 52 // ensure we have a valid matrix to use 53 const SkMatrix* matrix = reinterpret_cast<SkMatrix*>(matrixHandle); 54 if (NULL == matrix) { 55 matrix = &SkMatrix::I(); 56 } 57 58 // The current shader will no longer need a direct reference owned by Shader.java 59 // as all the data needed is contained within the newly created LocalMatrixShader. 60 SkASSERT(shaderHandle); 61 SkAutoTUnref<SkShader> currentShader(reinterpret_cast<SkShader*>(shaderHandle)); 62 63 // Attempt to peel off an existing proxy shader and get the proxy's matrix. If 64 // the proxy existed and it's matrix equals the desired matrix then just return 65 // the proxy, otherwise replace it with a new proxy containing the desired matrix. 66 // 67 // refAsALocalMatrixShader(): if the shader contains a proxy then it unwraps the proxy 68 // returning both the underlying shader and the proxy's matrix. 69 // newWithLocalMatrix(): will return a proxy shader that wraps the provided shader and 70 // concats the provided local matrix with the shader's matrix. 71 // 72 // WARNING: This proxy replacement only behaves like a setter because the Java 73 // API enforces that all local matrices are set using this call and 74 // not passed to the constructor of the Shader. 75 SkMatrix proxyMatrix; 76 SkAutoTUnref<SkShader> baseShader(currentShader->refAsALocalMatrixShader(&proxyMatrix)); 77 if (baseShader.get()) { 78 if (proxyMatrix == *matrix) { 79 return reinterpret_cast<jlong>(currentShader.detach()); 80 } 81 return reinterpret_cast<jlong>(baseShader->newWithLocalMatrix(*matrix)); 82 } 83 return reinterpret_cast<jlong>(currentShader->newWithLocalMatrix(*matrix)); 84} 85 86/////////////////////////////////////////////////////////////////////////////////////////////// 87 88static jlong BitmapShader_constructor(JNIEnv* env, jobject o, jobject jbitmap, 89 jint tileModeX, jint tileModeY) 90{ 91 SkBitmap bitmap; 92 if (jbitmap) { 93 // Only pass a valid SkBitmap object to the constructor if the Bitmap exists. Otherwise, 94 // we'll pass an empty SkBitmap to avoid crashing/excepting for compatibility. 95 GraphicsJNI::getSkBitmap(env, jbitmap, &bitmap); 96 } 97 SkShader* s = SkShader::CreateBitmapShader(bitmap, 98 (SkShader::TileMode)tileModeX, 99 (SkShader::TileMode)tileModeY); 100 101 ThrowIAE_IfNull(env, s); 102 return reinterpret_cast<jlong>(s); 103} 104 105/////////////////////////////////////////////////////////////////////////////////////////////// 106 107static jlong LinearGradient_create1(JNIEnv* env, jobject o, 108 jfloat x0, jfloat y0, jfloat x1, jfloat y1, 109 jintArray colorArray, jfloatArray posArray, jint tileMode) 110{ 111 SkPoint pts[2]; 112 pts[0].set(x0, y0); 113 pts[1].set(x1, y1); 114 115 size_t count = env->GetArrayLength(colorArray); 116 const jint* colorValues = env->GetIntArrayElements(colorArray, NULL); 117 118 AutoJavaFloatArray autoPos(env, posArray, count); 119#ifdef SK_SCALAR_IS_FLOAT 120 SkScalar* pos = autoPos.ptr(); 121#else 122 #error Need to convert float array to SkScalar array before calling the following function. 123#endif 124 125 SkShader* shader = SkGradientShader::CreateLinear(pts, 126 reinterpret_cast<const SkColor*>(colorValues), pos, count, 127 static_cast<SkShader::TileMode>(tileMode)); 128 129 env->ReleaseIntArrayElements(colorArray, const_cast<jint*>(colorValues), JNI_ABORT); 130 ThrowIAE_IfNull(env, shader); 131 return reinterpret_cast<jlong>(shader); 132} 133 134static jlong LinearGradient_create2(JNIEnv* env, jobject o, 135 jfloat x0, jfloat y0, jfloat x1, jfloat y1, 136 jint color0, jint color1, jint tileMode) 137{ 138 SkPoint pts[2]; 139 pts[0].set(x0, y0); 140 pts[1].set(x1, y1); 141 142 SkColor colors[2]; 143 colors[0] = color0; 144 colors[1] = color1; 145 146 SkShader* s = SkGradientShader::CreateLinear(pts, colors, NULL, 2, (SkShader::TileMode)tileMode); 147 148 ThrowIAE_IfNull(env, s); 149 return reinterpret_cast<jlong>(s); 150} 151 152/////////////////////////////////////////////////////////////////////////////////////////////// 153 154static jlong RadialGradient_create1(JNIEnv* env, jobject, jfloat x, jfloat y, jfloat radius, 155 jintArray colorArray, jfloatArray posArray, jint tileMode) { 156 SkPoint center; 157 center.set(x, y); 158 159 size_t count = env->GetArrayLength(colorArray); 160 const jint* colorValues = env->GetIntArrayElements(colorArray, NULL); 161 162 AutoJavaFloatArray autoPos(env, posArray, count); 163#ifdef SK_SCALAR_IS_FLOAT 164 SkScalar* pos = autoPos.ptr(); 165#else 166 #error Need to convert float array to SkScalar array before calling the following function. 167#endif 168 169 SkShader* shader = SkGradientShader::CreateRadial(center, radius, 170 reinterpret_cast<const SkColor*>(colorValues), pos, count, 171 static_cast<SkShader::TileMode>(tileMode)); 172 env->ReleaseIntArrayElements(colorArray, const_cast<jint*>(colorValues), 173 JNI_ABORT); 174 175 ThrowIAE_IfNull(env, shader); 176 return reinterpret_cast<jlong>(shader); 177} 178 179static jlong RadialGradient_create2(JNIEnv* env, jobject, jfloat x, jfloat y, jfloat radius, 180 jint color0, jint color1, jint tileMode) { 181 SkPoint center; 182 center.set(x, y); 183 184 SkColor colors[2]; 185 colors[0] = color0; 186 colors[1] = color1; 187 188 SkShader* s = SkGradientShader::CreateRadial(center, radius, colors, NULL, 2, 189 (SkShader::TileMode)tileMode); 190 ThrowIAE_IfNull(env, s); 191 return reinterpret_cast<jlong>(s); 192} 193 194/////////////////////////////////////////////////////////////////////////////// 195 196static jlong SweepGradient_create1(JNIEnv* env, jobject, jfloat x, jfloat y, 197 jintArray jcolors, jfloatArray jpositions) { 198 size_t count = env->GetArrayLength(jcolors); 199 const jint* colors = env->GetIntArrayElements(jcolors, NULL); 200 201 AutoJavaFloatArray autoPos(env, jpositions, count); 202#ifdef SK_SCALAR_IS_FLOAT 203 SkScalar* pos = autoPos.ptr(); 204#else 205 #error Need to convert float array to SkScalar array before calling the following function. 206#endif 207 208 SkShader* shader = SkGradientShader::CreateSweep(x, y, 209 reinterpret_cast<const SkColor*>(colors), pos, count); 210 env->ReleaseIntArrayElements(jcolors, const_cast<jint*>(colors), 211 JNI_ABORT); 212 ThrowIAE_IfNull(env, shader); 213 return reinterpret_cast<jlong>(shader); 214} 215 216static jlong SweepGradient_create2(JNIEnv* env, jobject, jfloat x, jfloat y, 217 int color0, int color1) { 218 SkColor colors[2]; 219 colors[0] = color0; 220 colors[1] = color1; 221 SkShader* s = SkGradientShader::CreateSweep(x, y, colors, NULL, 2); 222 ThrowIAE_IfNull(env, s); 223 return reinterpret_cast<jlong>(s); 224} 225 226/////////////////////////////////////////////////////////////////////////////////////////////// 227 228static jlong ComposeShader_create1(JNIEnv* env, jobject o, 229 jlong shaderAHandle, jlong shaderBHandle, jlong modeHandle) 230{ 231 SkShader* shaderA = reinterpret_cast<SkShader *>(shaderAHandle); 232 SkShader* shaderB = reinterpret_cast<SkShader *>(shaderBHandle); 233 SkXfermode* mode = reinterpret_cast<SkXfermode *>(modeHandle); 234 SkShader* shader = SkShader::CreateComposeShader(shaderA, shaderB, mode); 235 return reinterpret_cast<jlong>(shader); 236} 237 238static jlong ComposeShader_create2(JNIEnv* env, jobject o, 239 jlong shaderAHandle, jlong shaderBHandle, jint xfermodeHandle) 240{ 241 SkShader* shaderA = reinterpret_cast<SkShader *>(shaderAHandle); 242 SkShader* shaderB = reinterpret_cast<SkShader *>(shaderBHandle); 243 SkXfermode::Mode mode = static_cast<SkXfermode::Mode>(xfermodeHandle); 244 SkAutoTUnref<SkXfermode> xfermode(SkXfermode::Create(mode)); 245 SkShader* shader = SkShader::CreateComposeShader(shaderA, shaderB, xfermode.get()); 246 return reinterpret_cast<jlong>(shader); 247} 248 249/////////////////////////////////////////////////////////////////////////////////////////////// 250 251static const JNINativeMethod gColorMethods[] = { 252 { "nativeRGBToHSV", "(III[F)V", (void*)Color_RGBToHSV }, 253 { "nativeHSVToColor", "(I[F)I", (void*)Color_HSVToColor } 254}; 255 256static const JNINativeMethod gShaderMethods[] = { 257 { "nativeDestructor", "(J)V", (void*)Shader_destructor }, 258 { "nativeSetLocalMatrix", "(JJ)J", (void*)Shader_setLocalMatrix } 259}; 260 261static const JNINativeMethod gBitmapShaderMethods[] = { 262 { "nativeCreate", "(Landroid/graphics/Bitmap;II)J", (void*)BitmapShader_constructor }, 263}; 264 265static const JNINativeMethod gLinearGradientMethods[] = { 266 { "nativeCreate1", "(FFFF[I[FI)J", (void*)LinearGradient_create1 }, 267 { "nativeCreate2", "(FFFFIII)J", (void*)LinearGradient_create2 }, 268}; 269 270static const JNINativeMethod gRadialGradientMethods[] = { 271 { "nativeCreate1", "(FFF[I[FI)J", (void*)RadialGradient_create1 }, 272 { "nativeCreate2", "(FFFIII)J", (void*)RadialGradient_create2 }, 273}; 274 275static const JNINativeMethod gSweepGradientMethods[] = { 276 { "nativeCreate1", "(FF[I[F)J", (void*)SweepGradient_create1 }, 277 { "nativeCreate2", "(FFII)J", (void*)SweepGradient_create2 }, 278}; 279 280static const JNINativeMethod gComposeShaderMethods[] = { 281 { "nativeCreate1", "(JJJ)J", (void*)ComposeShader_create1 }, 282 { "nativeCreate2", "(JJI)J", (void*)ComposeShader_create2 }, 283}; 284 285int register_android_graphics_Shader(JNIEnv* env) 286{ 287 android::RegisterMethodsOrDie(env, "android/graphics/Color", gColorMethods, 288 NELEM(gColorMethods)); 289 android::RegisterMethodsOrDie(env, "android/graphics/Shader", gShaderMethods, 290 NELEM(gShaderMethods)); 291 android::RegisterMethodsOrDie(env, "android/graphics/BitmapShader", gBitmapShaderMethods, 292 NELEM(gBitmapShaderMethods)); 293 android::RegisterMethodsOrDie(env, "android/graphics/LinearGradient", gLinearGradientMethods, 294 NELEM(gLinearGradientMethods)); 295 android::RegisterMethodsOrDie(env, "android/graphics/RadialGradient", gRadialGradientMethods, 296 NELEM(gRadialGradientMethods)); 297 android::RegisterMethodsOrDie(env, "android/graphics/SweepGradient", gSweepGradientMethods, 298 NELEM(gSweepGradientMethods)); 299 android::RegisterMethodsOrDie(env, "android/graphics/ComposeShader", gComposeShaderMethods, 300 NELEM(gComposeShaderMethods)); 301 302 return 0; 303} 304