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 14 using namespace android::uirenderer; 15 16 static struct { 17 jclass clazz; 18 jfieldID shader; 19 } gShaderClassInfo; 20 21 static void ThrowIAE_IfNull(JNIEnv* env, void* ptr) { 22 if (NULL == ptr) { 23 doThrowIAE(env); 24 } 25 } 26 27 static 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 39 static 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 54 static 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 67 static 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 85 static 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 96 static 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 110 static 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 143 static 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 185 static 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 210 static 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 230 static 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 261 static 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 276 static 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 314 static 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 337 static 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 364 static 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 375 static 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 412 static 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 434 static SkShader* ComposeShader_create1(JNIEnv* env, jobject o, 435 SkShader* shaderA, SkShader* shaderB, SkXfermode* mode) 436 { 437 return new SkComposeShader(shaderA, shaderB, mode); 438 } 439 440 static 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 448 static 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 458 static 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 474 static JNINativeMethod gColorMethods[] = { 475 { "nativeRGBToHSV", "(III[F)V", (void*)Color_RGBToHSV }, 476 { "nativeHSVToColor", "(I[F)I", (void*)Color_HSVToColor } 477 }; 478 479 static JNINativeMethod gShaderMethods[] = { 480 { "nativeDestructor", "(II)V", (void*)Shader_destructor }, 481 { "nativeSetLocalMatrix", "(III)V", (void*)Shader_setLocalMatrix } 482 }; 483 484 static JNINativeMethod gBitmapShaderMethods[] = { 485 { "nativeCreate", "(III)I", (void*)BitmapShader_constructor }, 486 { "nativePostCreate", "(IIII)I", (void*)BitmapShader_postConstructor } 487 }; 488 489 static 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 496 static 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 503 static 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 510 static 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 523 int 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