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