diff options
author | Xin Li <delphij@google.com> | 2020-08-31 21:21:38 -0700 |
---|---|---|
committer | Xin Li <delphij@google.com> | 2020-08-31 21:21:38 -0700 |
commit | 628590d7ec80e10a3fc24b1c18a1afb55cca10a8 (patch) | |
tree | 4b1c3f52d86d7fb53afbe9e9438468588fa489f8 /libs/hwui/jni/Shader.cpp | |
parent | b11b8ec3aec8bb42f2c07e1c5ac7942da293baa8 (diff) | |
parent | d2d3a20624d968199353ccf6ddbae6f3ac39c9af (diff) |
Merge Android R (rvc-dev-plus-aosp-without-vendor@6692709)
Bug: 166295507
Merged-In: I3d92a6de21a938f6b352ec26dc23420c0fe02b27
Change-Id: Ifdb80563ef042738778ebb8a7581a97c4e3d96e2
Diffstat (limited to 'libs/hwui/jni/Shader.cpp')
-rw-r--r-- | libs/hwui/jni/Shader.cpp | 305 |
1 files changed, 305 insertions, 0 deletions
diff --git a/libs/hwui/jni/Shader.cpp b/libs/hwui/jni/Shader.cpp new file mode 100644 index 000000000000..0f6837640524 --- /dev/null +++ b/libs/hwui/jni/Shader.cpp @@ -0,0 +1,305 @@ +#include "GraphicsJNI.h" +#include "SkColorFilter.h" +#include "SkGradientShader.h" +#include "SkImagePriv.h" +#include "SkShader.h" +#include "SkBlendMode.h" +#include "include/effects/SkRuntimeEffect.h" + +#include <vector> + +using namespace android::uirenderer; + +/** + * By default Skia gradients will interpolate their colors in unpremul space + * and then premultiply each of the results. We must set this flag to preserve + * backwards compatiblity by premultiplying the colors of the gradient first, + * and then interpolating between them. + */ +static const uint32_t sGradientShaderFlags = SkGradientShader::kInterpolateColorsInPremul_Flag; + +#define ThrowIAE_IfNull(env, ptr) \ + if (nullptr == ptr) { \ + doThrowIAE(env); \ + return 0; \ + } + +static void Color_RGBToHSV(JNIEnv* env, jobject, jint red, jint green, jint blue, jfloatArray hsvArray) +{ + SkScalar hsv[3]; + SkRGBToHSV(red, green, blue, hsv); + + AutoJavaFloatArray autoHSV(env, hsvArray, 3); + float* values = autoHSV.ptr(); + for (int i = 0; i < 3; i++) { + values[i] = SkScalarToFloat(hsv[i]); + } +} + +static jint Color_HSVToColor(JNIEnv* env, jobject, jint alpha, jfloatArray hsvArray) +{ + AutoJavaFloatArray autoHSV(env, hsvArray, 3); +#ifdef SK_SCALAR_IS_FLOAT + SkScalar* hsv = autoHSV.ptr(); +#else + #error Need to convert float array to SkScalar array before calling the following function. +#endif + + return static_cast<jint>(SkHSVToColor(alpha, hsv)); +} + +/////////////////////////////////////////////////////////////////////////////////////////////// + +static void Shader_safeUnref(SkShader* shader) { + SkSafeUnref(shader); +} + +static jlong Shader_getNativeFinalizer(JNIEnv*, jobject) { + return static_cast<jlong>(reinterpret_cast<uintptr_t>(&Shader_safeUnref)); +} + +/////////////////////////////////////////////////////////////////////////////////////////////// + +static jlong BitmapShader_constructor(JNIEnv* env, jobject o, jlong matrixPtr, jlong bitmapHandle, + jint tileModeX, jint tileModeY) { + const SkMatrix* matrix = reinterpret_cast<const SkMatrix*>(matrixPtr); + sk_sp<SkImage> image; + if (bitmapHandle) { + // Only pass a valid SkBitmap object to the constructor if the Bitmap exists. Otherwise, + // we'll pass an empty SkBitmap to avoid crashing/excepting for compatibility. + image = android::bitmap::toBitmap(bitmapHandle).makeImage(); + } + + if (!image.get()) { + SkBitmap bitmap; + image = SkMakeImageFromRasterBitmap(bitmap, kNever_SkCopyPixelsMode); + } + sk_sp<SkShader> shader = image->makeShader( + (SkTileMode)tileModeX, (SkTileMode)tileModeY); + ThrowIAE_IfNull(env, shader.get()); + + if (matrix) { + shader = shader->makeWithLocalMatrix(*matrix); + } + + return reinterpret_cast<jlong>(shader.release()); +} + +/////////////////////////////////////////////////////////////////////////////////////////////// + +static std::vector<SkColor4f> convertColorLongs(JNIEnv* env, jlongArray colorArray) { + const size_t count = env->GetArrayLength(colorArray); + const jlong* colorValues = env->GetLongArrayElements(colorArray, nullptr); + + std::vector<SkColor4f> colors(count); + for (size_t i = 0; i < count; ++i) { + colors[i] = GraphicsJNI::convertColorLong(colorValues[i]); + } + + env->ReleaseLongArrayElements(colorArray, const_cast<jlong*>(colorValues), JNI_ABORT); + return colors; +} + +/////////////////////////////////////////////////////////////////////////////////////////////// + +static jlong LinearGradient_create(JNIEnv* env, jobject, jlong matrixPtr, + jfloat x0, jfloat y0, jfloat x1, jfloat y1, jlongArray colorArray, + jfloatArray posArray, jint tileMode, jlong colorSpaceHandle) { + SkPoint pts[2]; + pts[0].set(x0, y0); + pts[1].set(x1, y1); + + std::vector<SkColor4f> colors = convertColorLongs(env, colorArray); + + AutoJavaFloatArray autoPos(env, posArray, colors.size()); +#ifdef SK_SCALAR_IS_FLOAT + SkScalar* pos = autoPos.ptr(); +#else + #error Need to convert float array to SkScalar array before calling the following function. +#endif + + sk_sp<SkShader> shader(SkGradientShader::MakeLinear(pts, &colors[0], + GraphicsJNI::getNativeColorSpace(colorSpaceHandle), pos, colors.size(), + static_cast<SkTileMode>(tileMode), sGradientShaderFlags, nullptr)); + ThrowIAE_IfNull(env, shader); + + const SkMatrix* matrix = reinterpret_cast<const SkMatrix*>(matrixPtr); + if (matrix) { + shader = shader->makeWithLocalMatrix(*matrix); + } + + return reinterpret_cast<jlong>(shader.release()); +} + +/////////////////////////////////////////////////////////////////////////////////////////////// + +static jlong RadialGradient_create(JNIEnv* env, jobject, jlong matrixPtr, jfloat x, jfloat y, + jfloat radius, jlongArray colorArray, jfloatArray posArray, jint tileMode, + jlong colorSpaceHandle) { + SkPoint center; + center.set(x, y); + + std::vector<SkColor4f> colors = convertColorLongs(env, colorArray); + + AutoJavaFloatArray autoPos(env, posArray, colors.size()); +#ifdef SK_SCALAR_IS_FLOAT + SkScalar* pos = autoPos.ptr(); +#else + #error Need to convert float array to SkScalar array before calling the following function. +#endif + + sk_sp<SkShader> shader = SkGradientShader::MakeRadial(center, radius, &colors[0], + GraphicsJNI::getNativeColorSpace(colorSpaceHandle), pos, colors.size(), + static_cast<SkTileMode>(tileMode), sGradientShaderFlags, nullptr); + ThrowIAE_IfNull(env, shader); + + const SkMatrix* matrix = reinterpret_cast<const SkMatrix*>(matrixPtr); + if (matrix) { + shader = shader->makeWithLocalMatrix(*matrix); + } + + return reinterpret_cast<jlong>(shader.release()); +} + +/////////////////////////////////////////////////////////////////////////////// + +static jlong SweepGradient_create(JNIEnv* env, jobject, jlong matrixPtr, jfloat x, jfloat y, + jlongArray colorArray, jfloatArray jpositions, jlong colorSpaceHandle) { + std::vector<SkColor4f> colors = convertColorLongs(env, colorArray); + + AutoJavaFloatArray autoPos(env, jpositions, colors.size()); +#ifdef SK_SCALAR_IS_FLOAT + SkScalar* pos = autoPos.ptr(); +#else + #error Need to convert float array to SkScalar array before calling the following function. +#endif + + sk_sp<SkShader> shader = SkGradientShader::MakeSweep(x, y, &colors[0], + GraphicsJNI::getNativeColorSpace(colorSpaceHandle), pos, colors.size(), + sGradientShaderFlags, nullptr); + ThrowIAE_IfNull(env, shader); + + const SkMatrix* matrix = reinterpret_cast<const SkMatrix*>(matrixPtr); + if (matrix) { + shader = shader->makeWithLocalMatrix(*matrix); + } + + return reinterpret_cast<jlong>(shader.release()); +} + +/////////////////////////////////////////////////////////////////////////////////////////////// + +static jlong ComposeShader_create(JNIEnv* env, jobject o, jlong matrixPtr, + jlong shaderAHandle, jlong shaderBHandle, jint xfermodeHandle) { + const SkMatrix* matrix = reinterpret_cast<const SkMatrix*>(matrixPtr); + SkShader* shaderA = reinterpret_cast<SkShader *>(shaderAHandle); + SkShader* shaderB = reinterpret_cast<SkShader *>(shaderBHandle); + SkBlendMode mode = static_cast<SkBlendMode>(xfermodeHandle); + sk_sp<SkShader> baseShader(SkShaders::Blend(mode, + sk_ref_sp(shaderA), sk_ref_sp(shaderB))); + + SkShader* shader; + + if (matrix) { + shader = baseShader->makeWithLocalMatrix(*matrix).release(); + } else { + shader = baseShader.release(); + } + return reinterpret_cast<jlong>(shader); +} + +/////////////////////////////////////////////////////////////////////////////////////////////// + +static jlong RuntimeShader_create(JNIEnv* env, jobject, jlong shaderFactory, jlong matrixPtr, + jbyteArray inputs, jlong colorSpaceHandle, jboolean isOpaque) { + SkRuntimeEffect* effect = reinterpret_cast<SkRuntimeEffect*>(shaderFactory); + AutoJavaByteArray arInputs(env, inputs); + + sk_sp<SkData> fData; + fData = SkData::MakeWithCopy(arInputs.ptr(), arInputs.length()); + const SkMatrix* matrix = reinterpret_cast<const SkMatrix*>(matrixPtr); + sk_sp<SkShader> shader = effect->makeShader(fData, nullptr, 0, matrix, isOpaque == JNI_TRUE); + ThrowIAE_IfNull(env, shader); + + return reinterpret_cast<jlong>(shader.release()); +} + +/////////////////////////////////////////////////////////////////////////////////////////////// + +static jlong RuntimeShader_createShaderFactory(JNIEnv* env, jobject, jstring sksl) { + ScopedUtfChars strSksl(env, sksl); + sk_sp<SkRuntimeEffect> effect = std::get<0>(SkRuntimeEffect::Make(SkString(strSksl.c_str()))); + ThrowIAE_IfNull(env, effect); + + return reinterpret_cast<jlong>(effect.release()); +} + +/////////////////////////////////////////////////////////////////////////////////////////////// + +static void Effect_safeUnref(SkRuntimeEffect* effect) { + SkSafeUnref(effect); +} + +static jlong RuntimeShader_getNativeFinalizer(JNIEnv*, jobject) { + return static_cast<jlong>(reinterpret_cast<uintptr_t>(&Effect_safeUnref)); +} + +/////////////////////////////////////////////////////////////////////////////////////////////// + +static const JNINativeMethod gColorMethods[] = { + { "nativeRGBToHSV", "(III[F)V", (void*)Color_RGBToHSV }, + { "nativeHSVToColor", "(I[F)I", (void*)Color_HSVToColor } +}; + +static const JNINativeMethod gShaderMethods[] = { + { "nativeGetFinalizer", "()J", (void*)Shader_getNativeFinalizer }, +}; + +static const JNINativeMethod gBitmapShaderMethods[] = { + { "nativeCreate", "(JJII)J", (void*)BitmapShader_constructor }, +}; + +static const JNINativeMethod gLinearGradientMethods[] = { + { "nativeCreate", "(JFFFF[J[FIJ)J", (void*)LinearGradient_create }, +}; + +static const JNINativeMethod gRadialGradientMethods[] = { + { "nativeCreate", "(JFFF[J[FIJ)J", (void*)RadialGradient_create }, +}; + +static const JNINativeMethod gSweepGradientMethods[] = { + { "nativeCreate", "(JFF[J[FJ)J", (void*)SweepGradient_create }, +}; + +static const JNINativeMethod gComposeShaderMethods[] = { + { "nativeCreate", "(JJJI)J", (void*)ComposeShader_create }, +}; + +static const JNINativeMethod gRuntimeShaderMethods[] = { + { "nativeGetFinalizer", "()J", (void*)RuntimeShader_getNativeFinalizer }, + { "nativeCreate", "(JJ[BJZ)J", (void*)RuntimeShader_create }, + { "nativeCreateShaderFactory", "(Ljava/lang/String;)J", + (void*)RuntimeShader_createShaderFactory }, +}; + +int register_android_graphics_Shader(JNIEnv* env) +{ + android::RegisterMethodsOrDie(env, "android/graphics/Color", gColorMethods, + NELEM(gColorMethods)); + android::RegisterMethodsOrDie(env, "android/graphics/Shader", gShaderMethods, + NELEM(gShaderMethods)); + android::RegisterMethodsOrDie(env, "android/graphics/BitmapShader", gBitmapShaderMethods, + NELEM(gBitmapShaderMethods)); + android::RegisterMethodsOrDie(env, "android/graphics/LinearGradient", gLinearGradientMethods, + NELEM(gLinearGradientMethods)); + android::RegisterMethodsOrDie(env, "android/graphics/RadialGradient", gRadialGradientMethods, + NELEM(gRadialGradientMethods)); + android::RegisterMethodsOrDie(env, "android/graphics/SweepGradient", gSweepGradientMethods, + NELEM(gSweepGradientMethods)); + android::RegisterMethodsOrDie(env, "android/graphics/ComposeShader", gComposeShaderMethods, + NELEM(gComposeShaderMethods)); + android::RegisterMethodsOrDie(env, "android/graphics/RuntimeShader", gRuntimeShaderMethods, + NELEM(gRuntimeShaderMethods)); + + return 0; +} |