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