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