Shader.cpp revision ad93c2bb63dfc813b2eefa1043aa63afbddce655
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 shader->safeUnref(); 57 // skiaShader == NULL when not !USE_OPENGL_RENDERER, so no need to delete it outside the ifdef 58#ifdef USE_OPENGL_RENDERER 59 if (android::uirenderer::Caches::hasInstance()) { 60 android::uirenderer::Caches::getInstance().resourceCache.destructor(skiaShader); 61 } else { 62 delete skiaShader; 63 } 64#endif 65} 66 67static bool Shader_getLocalMatrix(JNIEnv* env, jobject, const SkShader* shader, SkMatrix* matrix) 68{ 69 return shader ? shader->getLocalMatrix(matrix) : false; 70} 71 72static void Shader_setLocalMatrix(JNIEnv* env, jobject o, SkShader* shader, SkiaShader* skiaShader, 73 const SkMatrix* matrix) 74{ 75 if (shader) { 76 if (NULL == matrix) { 77 shader->resetLocalMatrix(); 78 } 79 else { 80 shader->setLocalMatrix(*matrix); 81 } 82#ifdef USE_OPENGL_RENDERER 83 skiaShader->setMatrix(const_cast<SkMatrix*>(matrix)); 84#endif 85 } 86} 87 88/////////////////////////////////////////////////////////////////////////////////////////////// 89 90static SkShader* BitmapShader_constructor(JNIEnv* env, jobject o, const SkBitmap* bitmap, 91 int tileModeX, int tileModeY) 92{ 93 SkShader* s = SkShader::CreateBitmapShader(*bitmap, 94 (SkShader::TileMode)tileModeX, 95 (SkShader::TileMode)tileModeY); 96 97 ThrowIAE_IfNull(env, s); 98 return s; 99} 100 101static SkiaShader* BitmapShader_postConstructor(JNIEnv* env, jobject o, SkShader* shader, 102 SkBitmap* bitmap, int tileModeX, int tileModeY) { 103#ifdef USE_OPENGL_RENDERER 104 SkiaShader* skiaShader = new SkiaBitmapShader(bitmap, shader, 105 static_cast<SkShader::TileMode>(tileModeX), static_cast<SkShader::TileMode>(tileModeY), 106 NULL, (shader->getFlags() & SkShader::kOpaqueAlpha_Flag) == 0); 107 return skiaShader; 108#else 109 return NULL; 110#endif 111} 112 113/////////////////////////////////////////////////////////////////////////////////////////////// 114 115static SkShader* LinearGradient_create1(JNIEnv* env, jobject o, 116 float x0, float y0, float x1, float y1, 117 jintArray colorArray, jfloatArray posArray, int tileMode) 118{ 119 SkPoint pts[2]; 120 pts[0].set(SkFloatToScalar(x0), SkFloatToScalar(y0)); 121 pts[1].set(SkFloatToScalar(x1), SkFloatToScalar(y1)); 122 123 size_t count = env->GetArrayLength(colorArray); 124 const jint* colorValues = env->GetIntArrayElements(colorArray, NULL); 125 126 SkAutoSTMalloc<8, SkScalar> storage(posArray ? count : 0); 127 SkScalar* pos = NULL; 128 129 if (posArray) { 130 AutoJavaFloatArray autoPos(env, posArray, count); 131 const float* posValues = autoPos.ptr(); 132 pos = (SkScalar*)storage.get(); 133 for (size_t i = 0; i < count; i++) { 134 pos[i] = SkFloatToScalar(posValues[i]); 135 } 136 } 137 138 SkShader* shader = SkGradientShader::CreateLinear(pts, 139 reinterpret_cast<const SkColor*>(colorValues), 140 pos, count, 141 static_cast<SkShader::TileMode>(tileMode)); 142 143 env->ReleaseIntArrayElements(colorArray, const_cast<jint*>(colorValues), JNI_ABORT); 144 ThrowIAE_IfNull(env, shader); 145 return shader; 146} 147 148static SkiaShader* LinearGradient_postCreate1(JNIEnv* env, jobject o, SkShader* shader, 149 float x0, float y0, float x1, float y1, jintArray colorArray, 150 jfloatArray posArray, int tileMode) { 151#ifdef USE_OPENGL_RENDERER 152 size_t count = env->GetArrayLength(colorArray); 153 const jint* colorValues = env->GetIntArrayElements(colorArray, NULL); 154 155 jfloat* storedBounds = new jfloat[4]; 156 storedBounds[0] = x0; storedBounds[1] = y0; 157 storedBounds[2] = x1; storedBounds[3] = y1; 158 jfloat* storedPositions = new jfloat[count]; 159 uint32_t* storedColors = new uint32_t[count]; 160 for (size_t i = 0; i < count; i++) { 161 storedColors[i] = static_cast<uint32_t>(colorValues[i]); 162 } 163 164 if (posArray) { 165 AutoJavaFloatArray autoPos(env, posArray, count); 166 const float* posValues = autoPos.ptr(); 167 for (size_t i = 0; i < count; i++) { 168 storedPositions[i] = posValues[i]; 169 } 170 } else { 171 storedPositions[0] = 0.0f; 172 storedPositions[1] = 1.0f; 173 } 174 175 SkiaShader* skiaShader = new SkiaLinearGradientShader(storedBounds, storedColors, 176 storedPositions, count, shader, static_cast<SkShader::TileMode>(tileMode), NULL, 177 (shader->getFlags() & SkShader::kOpaqueAlpha_Flag) == 0); 178 179 env->ReleaseIntArrayElements(colorArray, const_cast<jint*>(colorValues), JNI_ABORT); 180 return skiaShader; 181#else 182 return NULL; 183#endif 184} 185 186static SkiaShader* LinearGradient_postCreate2(JNIEnv* env, jobject o, SkShader* shader, 187 float x0, float y0, float x1, float y1, int color0, int color1, int tileMode) { 188#ifdef USE_OPENGL_RENDERER 189 float* storedBounds = new float[4]; 190 storedBounds[0] = x0; storedBounds[1] = y0; 191 storedBounds[2] = x1; storedBounds[3] = y1; 192 193 float* storedPositions = new float[2]; 194 storedPositions[0] = 0.0f; 195 storedPositions[1] = 1.0f; 196 197 uint32_t* storedColors = new uint32_t[2]; 198 storedColors[0] = static_cast<uint32_t>(color0); 199 storedColors[1] = static_cast<uint32_t>(color1); 200 201 SkiaShader* skiaShader = new SkiaLinearGradientShader(storedBounds, storedColors, 202 storedPositions, 2, shader, static_cast<SkShader::TileMode>(tileMode), NULL, 203 (shader->getFlags() & SkShader::kOpaqueAlpha_Flag) == 0); 204 205 return skiaShader; 206#else 207 return NULL; 208#endif 209} 210 211static SkShader* LinearGradient_create2(JNIEnv* env, jobject o, 212 float x0, float y0, float x1, float y1, 213 int color0, int color1, int tileMode) 214{ 215 SkPoint pts[2]; 216 pts[0].set(SkFloatToScalar(x0), SkFloatToScalar(y0)); 217 pts[1].set(SkFloatToScalar(x1), SkFloatToScalar(y1)); 218 219 SkColor colors[2]; 220 colors[0] = color0; 221 colors[1] = color1; 222 223 SkShader* s = SkGradientShader::CreateLinear(pts, colors, NULL, 2, (SkShader::TileMode)tileMode); 224 225 ThrowIAE_IfNull(env, s); 226 return s; 227} 228 229/////////////////////////////////////////////////////////////////////////////////////////////// 230 231static SkShader* RadialGradient_create1(JNIEnv* env, jobject, float x, float y, float radius, 232 jintArray colorArray, jfloatArray posArray, int tileMode) { 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, float x, float y, float radius, 263 int color0, int color1, int tileMode) { 264 SkPoint center; 265 center.set(SkFloatToScalar(x), SkFloatToScalar(y)); 266 267 SkColor colors[2]; 268 colors[0] = color0; 269 colors[1] = color1; 270 271 SkShader* s = SkGradientShader::CreateRadial(center, SkFloatToScalar(radius), colors, NULL, 272 2, (SkShader::TileMode)tileMode); 273 ThrowIAE_IfNull(env, s); 274 return s; 275} 276 277static SkiaShader* RadialGradient_postCreate1(JNIEnv* env, jobject o, SkShader* shader, 278 float x, float y, float radius, jintArray colorArray, jfloatArray posArray, int tileMode) { 279#ifdef USE_OPENGL_RENDERER 280 size_t count = env->GetArrayLength(colorArray); 281 const jint* colorValues = env->GetIntArrayElements(colorArray, NULL); 282 283 jfloat* storedPositions = new jfloat[count]; 284 uint32_t* storedColors = new uint32_t[count]; 285 for (size_t i = 0; i < count; i++) { 286 storedColors[i] = static_cast<uint32_t>(colorValues[i]); 287 } 288 289 if (posArray) { 290 AutoJavaFloatArray autoPos(env, posArray, count); 291 const float* posValues = autoPos.ptr(); 292 for (size_t i = 0; i < count; i++) { 293 storedPositions[i] = posValues[i]; 294 } 295 } else { 296 storedPositions[0] = 0.0f; 297 storedPositions[1] = 1.0f; 298 } 299 300 SkiaShader* skiaShader = new SkiaCircularGradientShader(x, y, radius, storedColors, 301 storedPositions, count, shader, (SkShader::TileMode) tileMode, NULL, 302 (shader->getFlags() & SkShader::kOpaqueAlpha_Flag) == 0); 303 304 env->ReleaseIntArrayElements(colorArray, const_cast<jint*>(colorValues), JNI_ABORT); 305 return skiaShader; 306#else 307 return NULL; 308#endif 309} 310 311static SkiaShader* RadialGradient_postCreate2(JNIEnv* env, jobject o, SkShader* shader, 312 float x, float y, float radius, int color0, int color1, int tileMode) { 313#ifdef USE_OPENGL_RENDERER 314 float* storedPositions = new float[2]; 315 storedPositions[0] = 0.0f; 316 storedPositions[1] = 1.0f; 317 318 uint32_t* storedColors = new uint32_t[2]; 319 storedColors[0] = static_cast<uint32_t>(color0); 320 storedColors[1] = static_cast<uint32_t>(color1); 321 322 SkiaShader* skiaShader = new SkiaCircularGradientShader(x, y, radius, storedColors, 323 storedPositions, 2, shader, (SkShader::TileMode) tileMode, NULL, 324 (shader->getFlags() & SkShader::kOpaqueAlpha_Flag) == 0); 325 326 return skiaShader; 327#else 328 return NULL; 329#endif 330} 331 332/////////////////////////////////////////////////////////////////////////////// 333 334static SkShader* SweepGradient_create1(JNIEnv* env, jobject, float x, float y, 335 jintArray jcolors, jfloatArray jpositions) { 336 size_t count = env->GetArrayLength(jcolors); 337 const jint* colors = env->GetIntArrayElements(jcolors, NULL); 338 339 SkAutoSTMalloc<8, SkScalar> storage(jpositions ? count : 0); 340 SkScalar* pos = NULL; 341 342 if (NULL != jpositions) { 343 AutoJavaFloatArray autoPos(env, jpositions, count); 344 const float* posValues = autoPos.ptr(); 345 pos = (SkScalar*)storage.get(); 346 for (size_t i = 0; i < count; i++) { 347 pos[i] = SkFloatToScalar(posValues[i]); 348 } 349 } 350 351 SkShader* shader = SkGradientShader::CreateSweep(SkFloatToScalar(x), 352 SkFloatToScalar(y), 353 reinterpret_cast<const SkColor*>(colors), 354 pos, count); 355 env->ReleaseIntArrayElements(jcolors, const_cast<jint*>(colors), 356 JNI_ABORT); 357 ThrowIAE_IfNull(env, shader); 358 return shader; 359} 360 361static SkShader* SweepGradient_create2(JNIEnv* env, jobject, float x, float y, 362 int color0, int color1) { 363 SkColor colors[2]; 364 colors[0] = color0; 365 colors[1] = color1; 366 SkShader* s = SkGradientShader::CreateSweep(SkFloatToScalar(x), SkFloatToScalar(y), 367 colors, NULL, 2); 368 ThrowIAE_IfNull(env, s); 369 return s; 370} 371 372static SkiaShader* SweepGradient_postCreate1(JNIEnv* env, jobject o, SkShader* shader, 373 float x, float y, jintArray colorArray, jfloatArray posArray) { 374#ifdef USE_OPENGL_RENDERER 375 size_t count = env->GetArrayLength(colorArray); 376 const jint* colorValues = env->GetIntArrayElements(colorArray, NULL); 377 378 jfloat* storedPositions = new jfloat[count]; 379 uint32_t* storedColors = new uint32_t[count]; 380 for (size_t i = 0; i < count; i++) { 381 storedColors[i] = static_cast<uint32_t>(colorValues[i]); 382 } 383 384 if (posArray) { 385 AutoJavaFloatArray autoPos(env, posArray, count); 386 const float* posValues = autoPos.ptr(); 387 for (size_t i = 0; i < count; i++) { 388 storedPositions[i] = posValues[i]; 389 } 390 } else { 391 storedPositions[0] = 0.0f; 392 storedPositions[1] = 1.0f; 393 } 394 395 SkiaShader* skiaShader = new SkiaSweepGradientShader(x, y, storedColors, storedPositions, count, 396 shader, NULL, (shader->getFlags() & SkShader::kOpaqueAlpha_Flag) == 0); 397 398 env->ReleaseIntArrayElements(colorArray, const_cast<jint*>(colorValues), JNI_ABORT); 399 return skiaShader; 400#else 401 return NULL; 402#endif 403} 404 405static SkiaShader* SweepGradient_postCreate2(JNIEnv* env, jobject o, SkShader* shader, 406 float x, float y, int color0, int color1) { 407#ifdef USE_OPENGL_RENDERER 408 float* storedPositions = new float[2]; 409 storedPositions[0] = 0.0f; 410 storedPositions[1] = 1.0f; 411 412 uint32_t* storedColors = new uint32_t[2]; 413 storedColors[0] = static_cast<uint32_t>(color0); 414 storedColors[1] = static_cast<uint32_t>(color1); 415 416 SkiaShader* skiaShader = new SkiaSweepGradientShader(x, y, storedColors, storedPositions, 2, 417 shader, NULL, (shader->getFlags() & SkShader::kOpaqueAlpha_Flag) == 0); 418 419 return skiaShader; 420#else 421 return NULL; 422#endif 423} 424 425/////////////////////////////////////////////////////////////////////////////////////////////// 426 427static SkShader* ComposeShader_create1(JNIEnv* env, jobject o, 428 SkShader* shaderA, SkShader* shaderB, SkXfermode* mode) 429{ 430 return new SkComposeShader(shaderA, shaderB, mode); 431} 432 433static SkShader* ComposeShader_create2(JNIEnv* env, jobject o, 434 SkShader* shaderA, SkShader* shaderB, SkPorterDuff::Mode porterDuffMode) 435{ 436 SkAutoUnref au(SkPorterDuff::CreateXfermode(porterDuffMode)); 437 SkXfermode* mode = (SkXfermode*) au.get(); 438 return new SkComposeShader(shaderA, shaderB, mode); 439} 440 441static SkiaShader* ComposeShader_postCreate2(JNIEnv* env, jobject o, SkShader* shader, 442 SkiaShader* shaderA, SkiaShader* shaderB, SkPorterDuff::Mode porterDuffMode) { 443#ifdef USE_OPENGL_RENDERER 444 SkXfermode::Mode mode = SkPorterDuff::ToXfermodeMode(porterDuffMode); 445 return new SkiaComposeShader(shaderA, shaderB, mode, shader); 446#else 447 return NULL; 448#endif 449} 450 451static SkiaShader* ComposeShader_postCreate1(JNIEnv* env, jobject o, SkShader* shader, 452 SkiaShader* shaderA, SkiaShader* shaderB, SkXfermode* mode) { 453#ifdef USE_OPENGL_RENDERER 454 SkXfermode::Mode skiaMode; 455 if (!SkXfermode::IsMode(mode, &skiaMode)) { 456 // TODO: Support other modes 457 skiaMode = SkXfermode::kSrcOver_Mode; 458 } 459 return new SkiaComposeShader(shaderA, shaderB, skiaMode, shader); 460#else 461 return NULL; 462#endif 463} 464 465/////////////////////////////////////////////////////////////////////////////////////////////// 466 467static JNINativeMethod gColorMethods[] = { 468 { "nativeRGBToHSV", "(III[F)V", (void*)Color_RGBToHSV }, 469 { "nativeHSVToColor", "(I[F)I", (void*)Color_HSVToColor } 470}; 471 472static JNINativeMethod gShaderMethods[] = { 473 { "nativeDestructor", "(II)V", (void*)Shader_destructor }, 474 { "nativeGetLocalMatrix", "(II)Z", (void*)Shader_getLocalMatrix }, 475 { "nativeSetLocalMatrix", "(III)V", (void*)Shader_setLocalMatrix } 476}; 477 478static JNINativeMethod gBitmapShaderMethods[] = { 479 { "nativeCreate", "(III)I", (void*)BitmapShader_constructor }, 480 { "nativePostCreate", "(IIII)I", (void*)BitmapShader_postConstructor } 481}; 482 483static JNINativeMethod gLinearGradientMethods[] = { 484 { "nativeCreate1", "(FFFF[I[FI)I", (void*)LinearGradient_create1 }, 485 { "nativeCreate2", "(FFFFIII)I", (void*)LinearGradient_create2 }, 486 { "nativePostCreate1", "(IFFFF[I[FI)I", (void*)LinearGradient_postCreate1 }, 487 { "nativePostCreate2", "(IFFFFIII)I", (void*)LinearGradient_postCreate2 } 488}; 489 490static JNINativeMethod gRadialGradientMethods[] = { 491 { "nativeCreate1", "(FFF[I[FI)I", (void*)RadialGradient_create1 }, 492 { "nativeCreate2", "(FFFIII)I", (void*)RadialGradient_create2 }, 493 { "nativePostCreate1", "(IFFF[I[FI)I", (void*)RadialGradient_postCreate1 }, 494 { "nativePostCreate2", "(IFFFIII)I", (void*)RadialGradient_postCreate2 } 495}; 496 497static JNINativeMethod gSweepGradientMethods[] = { 498 { "nativeCreate1", "(FF[I[F)I", (void*)SweepGradient_create1 }, 499 { "nativeCreate2", "(FFII)I", (void*)SweepGradient_create2 }, 500 { "nativePostCreate1", "(IFF[I[F)I", (void*)SweepGradient_postCreate1 }, 501 { "nativePostCreate2", "(IFFII)I", (void*)SweepGradient_postCreate2 } 502}; 503 504static JNINativeMethod gComposeShaderMethods[] = { 505 { "nativeCreate1", "(III)I", (void*)ComposeShader_create1 }, 506 { "nativeCreate2", "(III)I", (void*)ComposeShader_create2 }, 507 { "nativePostCreate1", "(IIII)I", (void*)ComposeShader_postCreate1 }, 508 { "nativePostCreate2", "(IIII)I", (void*)ComposeShader_postCreate2 } 509}; 510 511#include <android_runtime/AndroidRuntime.h> 512 513#define REG(env, name, array) \ 514 result = android::AndroidRuntime::registerNativeMethods(env, name, array, SK_ARRAY_COUNT(array)); \ 515 if (result < 0) return result 516 517int register_android_graphics_Shader(JNIEnv* env); 518int register_android_graphics_Shader(JNIEnv* env) 519{ 520 int result; 521 522 REG(env, "android/graphics/Color", gColorMethods); 523 REG(env, "android/graphics/Shader", gShaderMethods); 524 REG(env, "android/graphics/BitmapShader", gBitmapShaderMethods); 525 REG(env, "android/graphics/LinearGradient", gLinearGradientMethods); 526 REG(env, "android/graphics/RadialGradient", gRadialGradientMethods); 527 REG(env, "android/graphics/SweepGradient", gSweepGradientMethods); 528 REG(env, "android/graphics/ComposeShader", gComposeShaderMethods); 529 530 return result; 531} 532 533