Shader.cpp revision 60126efd7d905ca24822765c6dafac17fef278ab
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 SkMatrix currentMatrix; 65 SkAutoTUnref<SkShader> baseShader(currentShader->refAsALocalMatrixShader(¤tMatrix)); 66 if (baseShader.get()) { 67 // if the matrices are same then there is no need to allocate a new 68 // shader that is identical to the existing one. 69 if (currentMatrix == *matrix) { 70 return reinterpret_cast<jlong>(currentShader.detach()); 71 } 72 return reinterpret_cast<jlong>(SkShader::CreateLocalMatrixShader(baseShader, *matrix)); 73 } 74 75 return reinterpret_cast<jlong>(SkShader::CreateLocalMatrixShader(currentShader, *matrix)); 76} 77 78/////////////////////////////////////////////////////////////////////////////////////////////// 79 80static jlong BitmapShader_constructor(JNIEnv* env, jobject o, jobject jbitmap, 81 jint tileModeX, jint tileModeY) 82{ 83 SkBitmap bitmap; 84 if (jbitmap) { 85 // Only pass a valid SkBitmap object to the constructor if the Bitmap exists. Otherwise, 86 // we'll pass an empty SkBitmap to avoid crashing/excepting for compatibility. 87 GraphicsJNI::getSkBitmap(env, jbitmap, &bitmap); 88 } 89 SkShader* s = SkShader::CreateBitmapShader(bitmap, 90 (SkShader::TileMode)tileModeX, 91 (SkShader::TileMode)tileModeY); 92 93 ThrowIAE_IfNull(env, s); 94 return reinterpret_cast<jlong>(s); 95} 96 97/////////////////////////////////////////////////////////////////////////////////////////////// 98 99static jlong LinearGradient_create1(JNIEnv* env, jobject o, 100 jfloat x0, jfloat y0, jfloat x1, jfloat y1, 101 jintArray colorArray, jfloatArray posArray, jint tileMode) 102{ 103 SkPoint pts[2]; 104 pts[0].set(x0, y0); 105 pts[1].set(x1, y1); 106 107 size_t count = env->GetArrayLength(colorArray); 108 const jint* colorValues = env->GetIntArrayElements(colorArray, NULL); 109 110 AutoJavaFloatArray autoPos(env, posArray, count); 111#ifdef SK_SCALAR_IS_FLOAT 112 SkScalar* pos = autoPos.ptr(); 113#else 114 #error Need to convert float array to SkScalar array before calling the following function. 115#endif 116 117 SkShader* shader = SkGradientShader::CreateLinear(pts, 118 reinterpret_cast<const SkColor*>(colorValues), pos, count, 119 static_cast<SkShader::TileMode>(tileMode)); 120 121 env->ReleaseIntArrayElements(colorArray, const_cast<jint*>(colorValues), JNI_ABORT); 122 ThrowIAE_IfNull(env, shader); 123 return reinterpret_cast<jlong>(shader); 124} 125 126static jlong LinearGradient_create2(JNIEnv* env, jobject o, 127 jfloat x0, jfloat y0, jfloat x1, jfloat y1, 128 jint color0, jint color1, jint tileMode) 129{ 130 SkPoint pts[2]; 131 pts[0].set(x0, y0); 132 pts[1].set(x1, y1); 133 134 SkColor colors[2]; 135 colors[0] = color0; 136 colors[1] = color1; 137 138 SkShader* s = SkGradientShader::CreateLinear(pts, colors, NULL, 2, (SkShader::TileMode)tileMode); 139 140 ThrowIAE_IfNull(env, s); 141 return reinterpret_cast<jlong>(s); 142} 143 144/////////////////////////////////////////////////////////////////////////////////////////////// 145 146static jlong RadialGradient_create1(JNIEnv* env, jobject, jfloat x, jfloat y, jfloat radius, 147 jintArray colorArray, jfloatArray posArray, jint tileMode) { 148 SkPoint center; 149 center.set(x, y); 150 151 size_t count = env->GetArrayLength(colorArray); 152 const jint* colorValues = env->GetIntArrayElements(colorArray, NULL); 153 154 AutoJavaFloatArray autoPos(env, posArray, count); 155#ifdef SK_SCALAR_IS_FLOAT 156 SkScalar* pos = autoPos.ptr(); 157#else 158 #error Need to convert float array to SkScalar array before calling the following function. 159#endif 160 161 SkShader* shader = SkGradientShader::CreateRadial(center, radius, 162 reinterpret_cast<const SkColor*>(colorValues), pos, count, 163 static_cast<SkShader::TileMode>(tileMode)); 164 env->ReleaseIntArrayElements(colorArray, const_cast<jint*>(colorValues), 165 JNI_ABORT); 166 167 ThrowIAE_IfNull(env, shader); 168 return reinterpret_cast<jlong>(shader); 169} 170 171static jlong RadialGradient_create2(JNIEnv* env, jobject, jfloat x, jfloat y, jfloat radius, 172 jint color0, jint color1, jint tileMode) { 173 SkPoint center; 174 center.set(x, y); 175 176 SkColor colors[2]; 177 colors[0] = color0; 178 colors[1] = color1; 179 180 SkShader* s = SkGradientShader::CreateRadial(center, radius, colors, NULL, 2, 181 (SkShader::TileMode)tileMode); 182 ThrowIAE_IfNull(env, s); 183 return reinterpret_cast<jlong>(s); 184} 185 186/////////////////////////////////////////////////////////////////////////////// 187 188static jlong SweepGradient_create1(JNIEnv* env, jobject, jfloat x, jfloat y, 189 jintArray jcolors, jfloatArray jpositions) { 190 size_t count = env->GetArrayLength(jcolors); 191 const jint* colors = env->GetIntArrayElements(jcolors, NULL); 192 193 AutoJavaFloatArray autoPos(env, jpositions, count); 194#ifdef SK_SCALAR_IS_FLOAT 195 SkScalar* pos = autoPos.ptr(); 196#else 197 #error Need to convert float array to SkScalar array before calling the following function. 198#endif 199 200 SkShader* shader = SkGradientShader::CreateSweep(x, y, 201 reinterpret_cast<const SkColor*>(colors), pos, count); 202 env->ReleaseIntArrayElements(jcolors, const_cast<jint*>(colors), 203 JNI_ABORT); 204 ThrowIAE_IfNull(env, shader); 205 return reinterpret_cast<jlong>(shader); 206} 207 208static jlong SweepGradient_create2(JNIEnv* env, jobject, jfloat x, jfloat y, 209 int color0, int color1) { 210 SkColor colors[2]; 211 colors[0] = color0; 212 colors[1] = color1; 213 SkShader* s = SkGradientShader::CreateSweep(x, y, colors, NULL, 2); 214 ThrowIAE_IfNull(env, s); 215 return reinterpret_cast<jlong>(s); 216} 217 218/////////////////////////////////////////////////////////////////////////////////////////////// 219 220static jlong ComposeShader_create1(JNIEnv* env, jobject o, 221 jlong shaderAHandle, jlong shaderBHandle, jlong modeHandle) 222{ 223 SkShader* shaderA = reinterpret_cast<SkShader *>(shaderAHandle); 224 SkShader* shaderB = reinterpret_cast<SkShader *>(shaderBHandle); 225 SkXfermode* mode = reinterpret_cast<SkXfermode *>(modeHandle); 226 SkShader* shader = new SkComposeShader(shaderA, shaderB, mode); 227 return reinterpret_cast<jlong>(shader); 228} 229 230static jlong ComposeShader_create2(JNIEnv* env, jobject o, 231 jlong shaderAHandle, jlong shaderBHandle, jint xfermodeHandle) 232{ 233 SkShader* shaderA = reinterpret_cast<SkShader *>(shaderAHandle); 234 SkShader* shaderB = reinterpret_cast<SkShader *>(shaderBHandle); 235 SkXfermode::Mode mode = static_cast<SkXfermode::Mode>(xfermodeHandle); 236 SkAutoTUnref<SkXfermode> xfermode(SkXfermode::Create(mode)); 237 SkShader* shader = new SkComposeShader(shaderA, shaderB, xfermode.get()); 238 return reinterpret_cast<jlong>(shader); 239} 240 241/////////////////////////////////////////////////////////////////////////////////////////////// 242 243static JNINativeMethod gColorMethods[] = { 244 { "nativeRGBToHSV", "(III[F)V", (void*)Color_RGBToHSV }, 245 { "nativeHSVToColor", "(I[F)I", (void*)Color_HSVToColor } 246}; 247 248static JNINativeMethod gShaderMethods[] = { 249 { "nativeDestructor", "(J)V", (void*)Shader_destructor }, 250 { "nativeSetLocalMatrix", "(JJ)J", (void*)Shader_setLocalMatrix } 251}; 252 253static JNINativeMethod gBitmapShaderMethods[] = { 254 { "nativeCreate", "(Landroid/graphics/Bitmap;II)J", (void*)BitmapShader_constructor }, 255}; 256 257static JNINativeMethod gLinearGradientMethods[] = { 258 { "nativeCreate1", "(FFFF[I[FI)J", (void*)LinearGradient_create1 }, 259 { "nativeCreate2", "(FFFFIII)J", (void*)LinearGradient_create2 }, 260}; 261 262static JNINativeMethod gRadialGradientMethods[] = { 263 { "nativeCreate1", "(FFF[I[FI)J", (void*)RadialGradient_create1 }, 264 { "nativeCreate2", "(FFFIII)J", (void*)RadialGradient_create2 }, 265}; 266 267static JNINativeMethod gSweepGradientMethods[] = { 268 { "nativeCreate1", "(FF[I[F)J", (void*)SweepGradient_create1 }, 269 { "nativeCreate2", "(FFII)J", (void*)SweepGradient_create2 }, 270}; 271 272static JNINativeMethod gComposeShaderMethods[] = { 273 { "nativeCreate1", "(JJJ)J", (void*)ComposeShader_create1 }, 274 { "nativeCreate2", "(JJI)J", (void*)ComposeShader_create2 }, 275}; 276 277int register_android_graphics_Shader(JNIEnv* env) 278{ 279 android::RegisterMethodsOrDie(env, "android/graphics/Color", gColorMethods, 280 NELEM(gColorMethods)); 281 android::RegisterMethodsOrDie(env, "android/graphics/Shader", gShaderMethods, 282 NELEM(gShaderMethods)); 283 android::RegisterMethodsOrDie(env, "android/graphics/BitmapShader", gBitmapShaderMethods, 284 NELEM(gBitmapShaderMethods)); 285 android::RegisterMethodsOrDie(env, "android/graphics/LinearGradient", gLinearGradientMethods, 286 NELEM(gLinearGradientMethods)); 287 android::RegisterMethodsOrDie(env, "android/graphics/RadialGradient", gRadialGradientMethods, 288 NELEM(gRadialGradientMethods)); 289 android::RegisterMethodsOrDie(env, "android/graphics/SweepGradient", gSweepGradientMethods, 290 NELEM(gSweepGradientMethods)); 291 android::RegisterMethodsOrDie(env, "android/graphics/ComposeShader", gComposeShaderMethods, 292 NELEM(gComposeShaderMethods)); 293 294 return 0; 295} 296