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
Color_RGBToHSV(JNIEnv * env,jobject,jint red,jint green,jint blue,jfloatArray hsvArray)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
Color_HSVToColor(JNIEnv * env,jobject,jint alpha,jfloatArray hsvArray)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
Shader_safeUnref(SkShader * shader)55 static void Shader_safeUnref(SkShader* shader) {
56 SkSafeUnref(shader);
57 }
58
Shader_getNativeFinalizer(JNIEnv *,jobject)59 static jlong Shader_getNativeFinalizer(JNIEnv*, jobject) {
60 return static_cast<jlong>(reinterpret_cast<uintptr_t>(&Shader_safeUnref));
61 }
62
63 ///////////////////////////////////////////////////////////////////////////////////////////////
64
BitmapShader_constructor(JNIEnv * env,jobject o,jlong matrixPtr,jlong bitmapHandle,jint tileModeX,jint tileModeY)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
convertColorLongs(JNIEnv * env,jlongArray colorArray)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
LinearGradient_create(JNIEnv * env,jobject,jlong matrixPtr,jfloat x0,jfloat y0,jfloat x1,jfloat y1,jlongArray colorArray,jfloatArray posArray,jint tileMode,jlong colorSpaceHandle)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
RadialGradient_create(JNIEnv * env,jobject,jlong matrixPtr,jfloat x,jfloat y,jfloat radius,jlongArray colorArray,jfloatArray posArray,jint tileMode,jlong colorSpaceHandle)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
SweepGradient_create(JNIEnv * env,jobject,jlong matrixPtr,jfloat x,jfloat y,jlongArray colorArray,jfloatArray jpositions,jlong colorSpaceHandle)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
ComposeShader_create(JNIEnv * env,jobject o,jlong matrixPtr,jlong shaderAHandle,jlong shaderBHandle,jint xfermodeHandle)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
register_android_graphics_Shader(JNIEnv * env)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