1 #include "GraphicsJNI.h" 2 #include "SkColorFilter.h" 3 #include "SkGradientShader.h" 4 #include "SkImagePriv.h" 5 #include "SkShader.h" 6 #include "SkBlendMode.h" 7 #include "core_jni_helpers.h" 8 9 #include <jni.h> 10 11 #include <vector> 12 13 using namespace android::uirenderer; 14 15 /** 16 * By default Skia gradients will interpolate their colors in unpremul space 17 * and then premultiply each of the results. We must set this flag to preserve 18 * backwards compatiblity by premultiplying the colors of the gradient first, 19 * and then interpolating between them. 20 */ 21 static const uint32_t sGradientShaderFlags = SkGradientShader::kInterpolateColorsInPremul_Flag; 22 23 #define ThrowIAE_IfNull(env, ptr) \ 24 if (nullptr == ptr) { \ 25 doThrowIAE(env); \ 26 return 0; \ 27 } 28 29 static void Color_RGBToHSV(JNIEnv* env, jobject, jint red, jint green, jint blue, jfloatArray hsvArray) 30 { 31 SkScalar hsv[3]; 32 SkRGBToHSV(red, green, blue, hsv); 33 34 AutoJavaFloatArray autoHSV(env, hsvArray, 3); 35 float* values = autoHSV.ptr(); 36 for (int i = 0; i < 3; i++) { 37 values[i] = SkScalarToFloat(hsv[i]); 38 } 39 } 40 41 static jint Color_HSVToColor(JNIEnv* env, jobject, jint alpha, jfloatArray hsvArray) 42 { 43 AutoJavaFloatArray autoHSV(env, hsvArray, 3); 44 #ifdef SK_SCALAR_IS_FLOAT 45 SkScalar* hsv = autoHSV.ptr(); 46 #else 47 #error Need to convert float array to SkScalar array before calling the following function. 48 #endif 49 50 return static_cast<jint>(SkHSVToColor(alpha, hsv)); 51 } 52 53 /////////////////////////////////////////////////////////////////////////////////////////////// 54 55 static void Shader_safeUnref(SkShader* shader) { 56 SkSafeUnref(shader); 57 } 58 59 static jlong Shader_getNativeFinalizer(JNIEnv*, jobject) { 60 return static_cast<jlong>(reinterpret_cast<uintptr_t>(&Shader_safeUnref)); 61 } 62 63 /////////////////////////////////////////////////////////////////////////////////////////////// 64 65 static jlong BitmapShader_constructor(JNIEnv* env, jobject o, jlong matrixPtr, jlong bitmapHandle, 66 jint tileModeX, jint tileModeY) { 67 const SkMatrix* matrix = reinterpret_cast<const SkMatrix*>(matrixPtr); 68 sk_sp<SkImage> image; 69 if (bitmapHandle) { 70 // Only pass a valid SkBitmap object to the constructor if the Bitmap exists. Otherwise, 71 // we'll pass an empty SkBitmap to avoid crashing/excepting for compatibility. 72 image = android::bitmap::toBitmap(bitmapHandle).makeImage(); 73 } 74 75 if (!image.get()) { 76 SkBitmap bitmap; 77 image = SkMakeImageFromRasterBitmap(bitmap, kNever_SkCopyPixelsMode); 78 } 79 sk_sp<SkShader> shader = image->makeShader( 80 (SkShader::TileMode)tileModeX, (SkShader::TileMode)tileModeY); 81 ThrowIAE_IfNull(env, shader.get()); 82 83 if (matrix) { 84 shader = shader->makeWithLocalMatrix(*matrix); 85 } 86 87 return reinterpret_cast<jlong>(shader.release()); 88 } 89 90 /////////////////////////////////////////////////////////////////////////////////////////////// 91 92 static std::vector<SkColor4f> convertColorLongs(JNIEnv* env, jlongArray colorArray) { 93 const size_t count = env->GetArrayLength(colorArray); 94 const jlong* colorValues = env->GetLongArrayElements(colorArray, nullptr); 95 96 std::vector<SkColor4f> colors(count); 97 for (size_t i = 0; i < count; ++i) { 98 colors[i] = GraphicsJNI::convertColorLong(colorValues[i]); 99 } 100 101 env->ReleaseLongArrayElements(colorArray, const_cast<jlong*>(colorValues), JNI_ABORT); 102 return colors; 103 } 104 105 /////////////////////////////////////////////////////////////////////////////////////////////// 106 107 static jlong LinearGradient_create(JNIEnv* env, jobject, jlong matrixPtr, 108 jfloat x0, jfloat y0, jfloat x1, jfloat y1, jlongArray colorArray, 109 jfloatArray posArray, jint tileMode, jlong colorSpaceHandle) { 110 SkPoint pts[2]; 111 pts[0].set(x0, y0); 112 pts[1].set(x1, y1); 113 114 std::vector<SkColor4f> colors = convertColorLongs(env, colorArray); 115 116 AutoJavaFloatArray autoPos(env, posArray, colors.size()); 117 #ifdef SK_SCALAR_IS_FLOAT 118 SkScalar* pos = autoPos.ptr(); 119 #else 120 #error Need to convert float array to SkScalar array before calling the following function. 121 #endif 122 123 sk_sp<SkShader> shader(SkGradientShader::MakeLinear(pts, &colors[0], 124 GraphicsJNI::getNativeColorSpace(colorSpaceHandle), pos, colors.size(), 125 static_cast<SkShader::TileMode>(tileMode), sGradientShaderFlags, nullptr)); 126 ThrowIAE_IfNull(env, shader); 127 128 const SkMatrix* matrix = reinterpret_cast<const SkMatrix*>(matrixPtr); 129 if (matrix) { 130 shader = shader->makeWithLocalMatrix(*matrix); 131 } 132 133 return reinterpret_cast<jlong>(shader.release()); 134 } 135 136 /////////////////////////////////////////////////////////////////////////////////////////////// 137 138 static jlong RadialGradient_create(JNIEnv* env, jobject, jlong matrixPtr, jfloat x, jfloat y, 139 jfloat radius, jlongArray colorArray, jfloatArray posArray, jint tileMode, 140 jlong colorSpaceHandle) { 141 SkPoint center; 142 center.set(x, y); 143 144 std::vector<SkColor4f> colors = convertColorLongs(env, colorArray); 145 146 AutoJavaFloatArray autoPos(env, posArray, colors.size()); 147 #ifdef SK_SCALAR_IS_FLOAT 148 SkScalar* pos = autoPos.ptr(); 149 #else 150 #error Need to convert float array to SkScalar array before calling the following function. 151 #endif 152 153 sk_sp<SkShader> shader = SkGradientShader::MakeRadial(center, radius, &colors[0], 154 GraphicsJNI::getNativeColorSpace(colorSpaceHandle), pos, colors.size(), 155 static_cast<SkShader::TileMode>(tileMode), sGradientShaderFlags, nullptr); 156 ThrowIAE_IfNull(env, shader); 157 158 const SkMatrix* matrix = reinterpret_cast<const SkMatrix*>(matrixPtr); 159 if (matrix) { 160 shader = shader->makeWithLocalMatrix(*matrix); 161 } 162 163 return reinterpret_cast<jlong>(shader.release()); 164 } 165 166 /////////////////////////////////////////////////////////////////////////////// 167 168 static jlong SweepGradient_create(JNIEnv* env, jobject, jlong matrixPtr, jfloat x, jfloat y, 169 jlongArray colorArray, jfloatArray jpositions, jlong colorSpaceHandle) { 170 std::vector<SkColor4f> colors = convertColorLongs(env, colorArray); 171 172 AutoJavaFloatArray autoPos(env, jpositions, colors.size()); 173 #ifdef SK_SCALAR_IS_FLOAT 174 SkScalar* pos = autoPos.ptr(); 175 #else 176 #error Need to convert float array to SkScalar array before calling the following function. 177 #endif 178 179 sk_sp<SkShader> shader = SkGradientShader::MakeSweep(x, y, &colors[0], 180 GraphicsJNI::getNativeColorSpace(colorSpaceHandle), pos, colors.size(), 181 sGradientShaderFlags, nullptr); 182 ThrowIAE_IfNull(env, shader); 183 184 const SkMatrix* matrix = reinterpret_cast<const SkMatrix*>(matrixPtr); 185 if (matrix) { 186 shader = shader->makeWithLocalMatrix(*matrix); 187 } 188 189 return reinterpret_cast<jlong>(shader.release()); 190 } 191 192 /////////////////////////////////////////////////////////////////////////////////////////////// 193 194 static jlong ComposeShader_create(JNIEnv* env, jobject o, jlong matrixPtr, 195 jlong shaderAHandle, jlong shaderBHandle, jint xfermodeHandle) { 196 const SkMatrix* matrix = reinterpret_cast<const SkMatrix*>(matrixPtr); 197 SkShader* shaderA = reinterpret_cast<SkShader *>(shaderAHandle); 198 SkShader* shaderB = reinterpret_cast<SkShader *>(shaderBHandle); 199 SkBlendMode mode = static_cast<SkBlendMode>(xfermodeHandle); 200 sk_sp<SkShader> baseShader(SkShader::MakeComposeShader( 201 sk_ref_sp(shaderA), sk_ref_sp(shaderB), mode)); 202 203 SkShader* shader; 204 205 if (matrix) { 206 shader = baseShader->makeWithLocalMatrix(*matrix).release(); 207 } else { 208 shader = baseShader.release(); 209 } 210 return reinterpret_cast<jlong>(shader); 211 } 212 213 /////////////////////////////////////////////////////////////////////////////////////////////// 214 215 static const JNINativeMethod gColorMethods[] = { 216 { "nativeRGBToHSV", "(III[F)V", (void*)Color_RGBToHSV }, 217 { "nativeHSVToColor", "(I[F)I", (void*)Color_HSVToColor } 218 }; 219 220 static const JNINativeMethod gShaderMethods[] = { 221 { "nativeGetFinalizer", "()J", (void*)Shader_getNativeFinalizer }, 222 }; 223 224 static const JNINativeMethod gBitmapShaderMethods[] = { 225 { "nativeCreate", "(JJII)J", (void*)BitmapShader_constructor }, 226 }; 227 228 static const JNINativeMethod gLinearGradientMethods[] = { 229 { "nativeCreate", "(JFFFF[J[FIJ)J", (void*)LinearGradient_create }, 230 }; 231 232 static const JNINativeMethod gRadialGradientMethods[] = { 233 { "nativeCreate", "(JFFF[J[FIJ)J", (void*)RadialGradient_create }, 234 }; 235 236 static const JNINativeMethod gSweepGradientMethods[] = { 237 { "nativeCreate", "(JFF[J[FJ)J", (void*)SweepGradient_create }, 238 }; 239 240 static const JNINativeMethod gComposeShaderMethods[] = { 241 { "nativeCreate", "(JJJI)J", (void*)ComposeShader_create }, 242 }; 243 244 int register_android_graphics_Shader(JNIEnv* env) 245 { 246 android::RegisterMethodsOrDie(env, "android/graphics/Color", gColorMethods, 247 NELEM(gColorMethods)); 248 android::RegisterMethodsOrDie(env, "android/graphics/Shader", gShaderMethods, 249 NELEM(gShaderMethods)); 250 android::RegisterMethodsOrDie(env, "android/graphics/BitmapShader", gBitmapShaderMethods, 251 NELEM(gBitmapShaderMethods)); 252 android::RegisterMethodsOrDie(env, "android/graphics/LinearGradient", gLinearGradientMethods, 253 NELEM(gLinearGradientMethods)); 254 android::RegisterMethodsOrDie(env, "android/graphics/RadialGradient", gRadialGradientMethods, 255 NELEM(gRadialGradientMethods)); 256 android::RegisterMethodsOrDie(env, "android/graphics/SweepGradient", gSweepGradientMethods, 257 NELEM(gSweepGradientMethods)); 258 android::RegisterMethodsOrDie(env, "android/graphics/ComposeShader", gComposeShaderMethods, 259 NELEM(gComposeShaderMethods)); 260 261 return 0; 262 } 263