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