Shader.cpp revision a2341a9f6addcd79723965ec5b1a1c5ae0f8bd65
1#include <jni.h> 2#include "GraphicsJNI.h" 3 4#include "SkShader.h" 5#include "SkGradientShader.h" 6#include "SkPorterDuff.h" 7#include "SkComposeShader.h" 8#include "SkTemplates.h" 9#include "SkXfermode.h" 10 11#include <SkiaShader.h> 12#include <Caches.h> 13 14using namespace android::uirenderer; 15 16static struct { 17 jclass clazz; 18 jfieldID shader; 19} gShaderClassInfo; 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, int red, int green, int 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 int Color_HSVToColor(JNIEnv* env, jobject, int alpha, jfloatArray hsvArray) 40{ 41 AutoJavaFloatArray autoHSV(env, hsvArray, 3); 42 float* values = autoHSV.ptr();; 43 SkScalar hsv[3]; 44 45 for (int i = 0; i < 3; i++) { 46 hsv[i] = SkFloatToScalar(values[i]); 47 } 48 49 return SkHSVToColor(alpha, hsv); 50} 51 52/////////////////////////////////////////////////////////////////////////////////////////////// 53 54static void Shader_destructor(JNIEnv* env, jobject o, SkShader* shader, SkiaShader* skiaShader) 55{ 56#ifdef USE_OPENGL_RENDERER 57 if (android::uirenderer::Caches::hasInstance()) { 58 android::uirenderer::Caches::getInstance().gradientCache.remove(shader); 59 } 60#endif 61 delete skiaShader; 62 shader->safeUnref(); 63} 64 65static bool Shader_getLocalMatrix(JNIEnv* env, jobject, const SkShader* shader, SkMatrix* matrix) 66{ 67 return shader ? shader->getLocalMatrix(matrix) : false; 68} 69 70static void Shader_setLocalMatrix(JNIEnv* env, jobject o, SkShader* shader, SkiaShader* skiaShader, 71 const SkMatrix* matrix) 72{ 73 if (shader) { 74 if (NULL == matrix) { 75 shader->resetLocalMatrix(); 76 } 77 else { 78 shader->setLocalMatrix(*matrix); 79 } 80#ifdef USE_OPENGL_RENDERER 81 skiaShader->setMatrix(const_cast<SkMatrix*>(matrix)); 82#endif 83 } 84} 85 86/////////////////////////////////////////////////////////////////////////////////////////////// 87 88static SkShader* BitmapShader_constructor(JNIEnv* env, jobject o, const SkBitmap* bitmap, 89 int tileModeX, int tileModeY) 90{ 91 SkShader* s = SkShader::CreateBitmapShader(*bitmap, 92 (SkShader::TileMode)tileModeX, 93 (SkShader::TileMode)tileModeY); 94 95 ThrowIAE_IfNull(env, s); 96 return s; 97} 98 99static SkiaShader* BitmapShader_postConstructor(JNIEnv* env, jobject o, SkShader* shader, 100 SkBitmap* bitmap, int tileModeX, int tileModeY) { 101#ifdef USE_OPENGL_RENDERER 102 SkiaShader* skiaShader = new SkiaBitmapShader(bitmap, shader, 103 static_cast<SkShader::TileMode>(tileModeX), static_cast<SkShader::TileMode>(tileModeY), 104 NULL, (shader->getFlags() & SkShader::kOpaqueAlpha_Flag) == 0); 105 return skiaShader; 106#else 107 return NULL; 108#endif 109} 110 111/////////////////////////////////////////////////////////////////////////////////////////////// 112 113static SkShader* LinearGradient_create1(JNIEnv* env, jobject o, 114 float x0, float y0, float x1, float y1, 115 jintArray colorArray, jfloatArray posArray, int tileMode) 116{ 117 SkPoint pts[2]; 118 pts[0].set(SkFloatToScalar(x0), SkFloatToScalar(y0)); 119 pts[1].set(SkFloatToScalar(x1), SkFloatToScalar(y1)); 120 121 size_t count = env->GetArrayLength(colorArray); 122 const jint* colorValues = env->GetIntArrayElements(colorArray, NULL); 123 124 SkAutoSTMalloc<8, SkScalar> storage(posArray ? count : 0); 125 SkScalar* pos = NULL; 126 127 if (posArray) { 128 AutoJavaFloatArray autoPos(env, posArray, count); 129 const float* posValues = autoPos.ptr(); 130 pos = (SkScalar*)storage.get(); 131 for (size_t i = 0; i < count; i++) { 132 pos[i] = SkFloatToScalar(posValues[i]); 133 } 134 } 135 136 SkShader* shader = SkGradientShader::CreateLinear(pts, 137 reinterpret_cast<const SkColor*>(colorValues), 138 pos, count, 139 static_cast<SkShader::TileMode>(tileMode)); 140 141 env->ReleaseIntArrayElements(colorArray, const_cast<jint*>(colorValues), JNI_ABORT); 142 ThrowIAE_IfNull(env, shader); 143 return shader; 144} 145 146static SkiaShader* LinearGradient_postCreate1(JNIEnv* env, jobject o, SkShader* shader, 147 float x0, float y0, float x1, float y1, jintArray colorArray, 148 jfloatArray posArray, int tileMode) { 149#ifdef USE_OPENGL_RENDERER 150 size_t count = env->GetArrayLength(colorArray); 151 const jint* colorValues = env->GetIntArrayElements(colorArray, NULL); 152 153 jfloat* storedBounds = new jfloat[4]; 154 storedBounds[0] = x0; storedBounds[1] = y0; 155 storedBounds[2] = x1; storedBounds[3] = y1; 156 jfloat* storedPositions = new jfloat[count]; 157 uint32_t* storedColors = new uint32_t[count]; 158 for (size_t i = 0; i < count; i++) { 159 storedColors[i] = static_cast<uint32_t>(colorValues[i]); 160 } 161 162 if (posArray) { 163 AutoJavaFloatArray autoPos(env, posArray, count); 164 const float* posValues = autoPos.ptr(); 165 for (size_t i = 0; i < count; i++) { 166 storedPositions[i] = posValues[i]; 167 } 168 } else { 169 storedPositions[0] = 0.0f; 170 storedPositions[1] = 1.0f; 171 } 172 173 SkiaShader* skiaShader = new SkiaLinearGradientShader(storedBounds, storedColors, 174 storedPositions, count, shader, static_cast<SkShader::TileMode>(tileMode), NULL, 175 (shader->getFlags() & SkShader::kOpaqueAlpha_Flag) == 0); 176 177 env->ReleaseIntArrayElements(colorArray, const_cast<jint*>(colorValues), JNI_ABORT); 178 return skiaShader; 179#else 180 return NULL; 181#endif 182} 183 184static SkiaShader* LinearGradient_postCreate2(JNIEnv* env, jobject o, SkShader* shader, 185 float x0, float y0, float x1, float y1, int color0, int color1, int tileMode) { 186#ifdef USE_OPENGL_RENDERER 187 float* storedBounds = new float[4]; 188 storedBounds[0] = x0; storedBounds[1] = y0; 189 storedBounds[2] = x1; storedBounds[3] = y1; 190 191 float* storedPositions = new float[2]; 192 storedPositions[0] = 0.0f; 193 storedPositions[1] = 1.0f; 194 195 uint32_t* storedColors = new uint32_t[2]; 196 storedColors[0] = static_cast<uint32_t>(color0); 197 storedColors[1] = static_cast<uint32_t>(color1); 198 199 SkiaShader* skiaShader = new SkiaLinearGradientShader(storedBounds, storedColors, 200 storedPositions, 2, shader, static_cast<SkShader::TileMode>(tileMode), NULL, 201 (shader->getFlags() & SkShader::kOpaqueAlpha_Flag) == 0); 202 203 return skiaShader; 204#else 205 return NULL; 206#endif 207} 208 209static SkShader* LinearGradient_create2(JNIEnv* env, jobject o, 210 float x0, float y0, float x1, float y1, 211 int color0, int color1, int tileMode) 212{ 213 SkPoint pts[2]; 214 pts[0].set(SkFloatToScalar(x0), SkFloatToScalar(y0)); 215 pts[1].set(SkFloatToScalar(x1), SkFloatToScalar(y1)); 216 217 SkColor colors[2]; 218 colors[0] = color0; 219 colors[1] = color1; 220 221 SkShader* s = SkGradientShader::CreateLinear(pts, colors, NULL, 2, (SkShader::TileMode)tileMode); 222 223 ThrowIAE_IfNull(env, s); 224 return s; 225} 226 227/////////////////////////////////////////////////////////////////////////////////////////////// 228 229static SkShader* RadialGradient_create1(JNIEnv* env, jobject, 230 float x, float y, float radius, 231 jintArray colorArray, jfloatArray posArray, int tileMode) 232{ 233 SkPoint center; 234 center.set(SkFloatToScalar(x), SkFloatToScalar(y)); 235 236 size_t count = env->GetArrayLength(colorArray); 237 const jint* colorValues = env->GetIntArrayElements(colorArray, NULL); 238 239 SkAutoSTMalloc<8, SkScalar> storage(posArray ? count : 0); 240 SkScalar* pos = NULL; 241 242 if (posArray) { 243 AutoJavaFloatArray autoPos(env, posArray, count); 244 const float* posValues = autoPos.ptr(); 245 pos = (SkScalar*)storage.get(); 246 for (size_t i = 0; i < count; i++) 247 pos[i] = SkFloatToScalar(posValues[i]); 248 } 249 250 SkShader* shader = SkGradientShader::CreateRadial(center, 251 SkFloatToScalar(radius), 252 reinterpret_cast<const SkColor*>(colorValues), 253 pos, count, 254 static_cast<SkShader::TileMode>(tileMode)); 255 env->ReleaseIntArrayElements(colorArray, const_cast<jint*>(colorValues), 256 JNI_ABORT); 257 258 ThrowIAE_IfNull(env, shader); 259 return shader; 260} 261 262static SkShader* RadialGradient_create2(JNIEnv* env, jobject, 263 float x, float y, float radius, 264 int color0, int color1, int tileMode) 265{ 266 SkPoint center; 267 center.set(SkFloatToScalar(x), SkFloatToScalar(y)); 268 269 SkColor colors[2]; 270 colors[0] = color0; 271 colors[1] = color1; 272 273 SkShader* s = SkGradientShader::CreateRadial(center, SkFloatToScalar(radius), colors, NULL, 274 2, (SkShader::TileMode)tileMode); 275 ThrowIAE_IfNull(env, s); 276 return s; 277} 278 279/////////////////////////////////////////////////////////////////////////////// 280 281static SkShader* SweepGradient_create1(JNIEnv* env, jobject, float x, float y, 282 jintArray jcolors, jfloatArray jpositions) 283{ 284 size_t count = env->GetArrayLength(jcolors); 285 const jint* colors = env->GetIntArrayElements(jcolors, NULL); 286 287 SkAutoSTMalloc<8, SkScalar> storage(jpositions ? count : 0); 288 SkScalar* pos = NULL; 289 290 if (NULL != jpositions) { 291 AutoJavaFloatArray autoPos(env, jpositions, count); 292 const float* posValues = autoPos.ptr(); 293 pos = (SkScalar*)storage.get(); 294 for (size_t i = 0; i < count; i++) { 295 pos[i] = SkFloatToScalar(posValues[i]); 296 } 297 } 298 299 SkShader* shader = SkGradientShader::CreateSweep(SkFloatToScalar(x), 300 SkFloatToScalar(y), 301 reinterpret_cast<const SkColor*>(colors), 302 pos, count); 303 env->ReleaseIntArrayElements(jcolors, const_cast<jint*>(colors), 304 JNI_ABORT); 305 ThrowIAE_IfNull(env, shader); 306 return shader; 307} 308 309static SkShader* SweepGradient_create2(JNIEnv* env, jobject, float x, float y, 310 int color0, int color1) 311{ 312 SkColor colors[2]; 313 colors[0] = color0; 314 colors[1] = color1; 315 SkShader* s = SkGradientShader::CreateSweep(SkFloatToScalar(x), SkFloatToScalar(y), 316 colors, NULL, 2); 317 ThrowIAE_IfNull(env, s); 318 return s; 319} 320 321/////////////////////////////////////////////////////////////////////////////////////////////// 322 323static SkShader* ComposeShader_create1(JNIEnv* env, jobject o, 324 SkShader* shaderA, SkShader* shaderB, SkXfermode* mode) 325{ 326 return new SkComposeShader(shaderA, shaderB, mode); 327} 328 329static SkShader* ComposeShader_create2(JNIEnv* env, jobject o, 330 SkShader* shaderA, SkShader* shaderB, SkPorterDuff::Mode porterDuffMode) 331{ 332 SkAutoUnref au(SkPorterDuff::CreateXfermode(porterDuffMode)); 333 SkXfermode* mode = (SkXfermode*) au.get(); 334 return new SkComposeShader(shaderA, shaderB, mode); 335} 336 337static SkiaShader* ComposeShader_postCreate2(JNIEnv* env, jobject o, SkShader* shader, 338 SkiaShader* shaderA, SkiaShader* shaderB, SkPorterDuff::Mode porterDuffMode) { 339#ifdef USE_OPENGL_RENDERER 340 SkXfermode::Mode mode = SkPorterDuff::ToXfermodeMode(porterDuffMode); 341 return new SkiaComposeShader(shaderA, shaderB, mode, shader); 342#else 343 return NULL; 344#endif 345} 346 347static SkiaShader* ComposeShader_postCreate1(JNIEnv* env, jobject o, SkShader* shader, 348 SkiaShader* shaderA, SkiaShader* shaderB, SkXfermode* mode) { 349#ifdef USE_OPENGL_RENDERER 350 SkXfermode::Mode skiaMode; 351 if (!SkXfermode::IsMode(mode, &skiaMode)) { 352 // TODO: Support other modes 353 skiaMode = SkXfermode::kSrcOver_Mode; 354 } 355 return new SkiaComposeShader(shaderA, shaderB, skiaMode, shader); 356#else 357 return NULL; 358#endif 359} 360 361/////////////////////////////////////////////////////////////////////////////////////////////// 362 363static JNINativeMethod gColorMethods[] = { 364 { "nativeRGBToHSV", "(III[F)V", (void*)Color_RGBToHSV }, 365 { "nativeHSVToColor", "(I[F)I", (void*)Color_HSVToColor } 366}; 367 368static JNINativeMethod gShaderMethods[] = { 369 { "nativeDestructor", "(II)V", (void*)Shader_destructor }, 370 { "nativeGetLocalMatrix", "(II)Z", (void*)Shader_getLocalMatrix }, 371 { "nativeSetLocalMatrix", "(III)V", (void*)Shader_setLocalMatrix } 372}; 373 374static JNINativeMethod gBitmapShaderMethods[] = { 375 { "nativeCreate", "(III)I", (void*)BitmapShader_constructor }, 376 { "nativePostCreate", "(IIII)I", (void*)BitmapShader_postConstructor } 377}; 378 379static JNINativeMethod gLinearGradientMethods[] = { 380 { "nativeCreate1", "(FFFF[I[FI)I", (void*)LinearGradient_create1 }, 381 { "nativeCreate2", "(FFFFIII)I", (void*)LinearGradient_create2 }, 382 { "nativePostCreate1", "(IFFFF[I[FI)I", (void*)LinearGradient_postCreate1 }, 383 { "nativePostCreate2", "(IFFFFIII)I", (void*)LinearGradient_postCreate2 } 384}; 385 386static JNINativeMethod gRadialGradientMethods[] = { 387 {"nativeCreate1", "(FFF[I[FI)I", (void*)RadialGradient_create1 }, 388 {"nativeCreate2", "(FFFIII)I", (void*)RadialGradient_create2 } 389}; 390 391static JNINativeMethod gSweepGradientMethods[] = { 392 {"nativeCreate1", "(FF[I[F)I", (void*)SweepGradient_create1 }, 393 {"nativeCreate2", "(FFII)I", (void*)SweepGradient_create2 } 394}; 395 396static JNINativeMethod gComposeShaderMethods[] = { 397 {"nativeCreate1", "(III)I", (void*)ComposeShader_create1 }, 398 {"nativeCreate2", "(III)I", (void*)ComposeShader_create2 }, 399 {"nativePostCreate1", "(IIII)I", (void*)ComposeShader_postCreate1 }, 400 {"nativePostCreate2", "(IIII)I", (void*)ComposeShader_postCreate2 } 401}; 402 403#include <android_runtime/AndroidRuntime.h> 404 405#define REG(env, name, array) \ 406 result = android::AndroidRuntime::registerNativeMethods(env, name, array, SK_ARRAY_COUNT(array)); \ 407 if (result < 0) return result 408 409int register_android_graphics_Shader(JNIEnv* env); 410int register_android_graphics_Shader(JNIEnv* env) 411{ 412 int result; 413 414 REG(env, "android/graphics/Color", gColorMethods); 415 REG(env, "android/graphics/Shader", gShaderMethods); 416 REG(env, "android/graphics/BitmapShader", gBitmapShaderMethods); 417 REG(env, "android/graphics/LinearGradient", gLinearGradientMethods); 418 REG(env, "android/graphics/RadialGradient", gRadialGradientMethods); 419 REG(env, "android/graphics/SweepGradient", gSweepGradientMethods); 420 REG(env, "android/graphics/ComposeShader", gComposeShaderMethods); 421 422 return result; 423} 424 425