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