blob: cff772002b14807cffffe4a9eefecf7ae70cac52 [file] [log] [blame]
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001#include "GraphicsJNI.h"
Derek Sollenbergerfb0c8fc2017-07-26 13:53:27 -04002#include "SkColorFilter.h"
Ben Wagner60126ef2015-08-07 12:13:48 -04003#include "SkGradientShader.h"
Matt Sarett62feb3a2016-09-20 10:34:11 -04004#include "SkImagePriv.h"
Ben Wagner60126ef2015-08-07 12:13:48 -04005#include "SkShader.h"
Mike Reedc2f31df2016-10-28 17:21:45 -04006#include "SkBlendMode.h"
Ben Wagner60126ef2015-08-07 12:13:48 -04007#include "core_jni_helpers.h"
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008
Romain Guya2341a92010-09-08 18:04:33 -07009#include <Caches.h>
Ben Wagner60126ef2015-08-07 12:13:48 -040010#include <jni.h>
Andreas Gampeed6b9df2014-11-20 22:02:20 -080011
Romain Guy06f96e22010-07-30 19:18:16 -070012using namespace android::uirenderer;
13
Derek Sollenberger669b15a2017-03-31 12:09:24 -040014/**
15 * By default Skia gradients will interpolate their colors in unpremul space
16 * and then premultiply each of the results. We must set this flag to preserve
17 * backwards compatiblity by premultiplying the colors of the gradient first,
18 * and then interpolating between them.
19 */
20static const uint32_t sGradientShaderFlags = SkGradientShader::kInterpolateColorsInPremul_Flag;
21
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080022static void ThrowIAE_IfNull(JNIEnv* env, void* ptr) {
23 if (NULL == ptr) {
24 doThrowIAE(env);
25 }
26}
27
Ashok Bhat36bef0b2014-01-20 20:08:01 +000028static void Color_RGBToHSV(JNIEnv* env, jobject, jint red, jint green, jint blue, jfloatArray hsvArray)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080029{
30 SkScalar hsv[3];
31 SkRGBToHSV(red, green, blue, hsv);
32
33 AutoJavaFloatArray autoHSV(env, hsvArray, 3);
34 float* values = autoHSV.ptr();
35 for (int i = 0; i < 3; i++) {
36 values[i] = SkScalarToFloat(hsv[i]);
37 }
38}
Elliott Hughes4cb17532011-04-12 16:10:26 -070039
Ashok Bhat36bef0b2014-01-20 20:08:01 +000040static jint Color_HSVToColor(JNIEnv* env, jobject, jint alpha, jfloatArray hsvArray)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080041{
42 AutoJavaFloatArray autoHSV(env, hsvArray, 3);
Leon Scroggins III2e0103e2014-04-04 17:05:24 -040043#ifdef SK_SCALAR_IS_FLOAT
44 SkScalar* hsv = autoHSV.ptr();
45#else
46 #error Need to convert float array to SkScalar array before calling the following function.
47#endif
Elliott Hughes4cb17532011-04-12 16:10:26 -070048
Ashok Bhat36bef0b2014-01-20 20:08:01 +000049 return static_cast<jint>(SkHSVToColor(alpha, hsv));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080050}
51
52///////////////////////////////////////////////////////////////////////////////////////////////
53
John Reck8bde0be2017-05-19 10:55:20 -070054static void Shader_safeUnref(SkShader* shader) {
Derek Sollenberger6062c592011-02-22 13:55:04 -050055 SkSafeUnref(shader);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080056}
57
John Reck8bde0be2017-05-19 10:55:20 -070058static jlong Shader_getNativeFinalizer(JNIEnv*, jobject) {
59 return static_cast<jlong>(reinterpret_cast<uintptr_t>(&Shader_safeUnref));
60}
61
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080062///////////////////////////////////////////////////////////////////////////////////////////////
63
Chris Craikb581e672017-03-07 15:27:36 -080064static jlong BitmapShader_constructor(JNIEnv* env, jobject o, jlong matrixPtr, jobject jbitmap,
65 jint tileModeX, jint tileModeY) {
66 const SkMatrix* matrix = reinterpret_cast<const SkMatrix*>(matrixPtr);
Stan Iliev7bc3bc62017-05-24 13:28:36 -040067 sk_sp<SkImage> image;
Derek Sollenbergerfb0c8fc2017-07-26 13:53:27 -040068 sk_sp<SkColorFilter> colorFilter;
Chris Craikb786bbd2015-06-10 16:58:42 -070069 if (jbitmap) {
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.
Derek Sollenbergerfb0c8fc2017-07-26 13:53:27 -040072 image = android::bitmap::toBitmap(env, jbitmap).makeImage(&colorFilter);
Chris Craikb786bbd2015-06-10 16:58:42 -070073 }
Romain Guy06f96e22010-07-30 19:18:16 -070074
Stan Iliev7bc3bc62017-05-24 13:28:36 -040075 if (!image.get()) {
76 SkBitmap bitmap;
77 image = SkMakeImageFromRasterBitmap(bitmap, kNever_SkCopyPixelsMode);
78 }
Derek Sollenbergerfb0c8fc2017-07-26 13:53:27 -040079 sk_sp<SkShader> shader = image->makeShader(
ztenghuib244fb52017-04-04 17:33:40 -070080 (SkShader::TileMode)tileModeX, (SkShader::TileMode)tileModeY);
Derek Sollenberger450756a2016-11-07 15:55:47 -050081
ztenghuib244fb52017-04-04 17:33:40 -070082 if (matrix) {
Derek Sollenbergerfb0c8fc2017-07-26 13:53:27 -040083 shader = shader->makeWithLocalMatrix(*matrix);
84 }
85 if(colorFilter) {
86 shader = shader->makeWithColorFilter(colorFilter);
ztenghuib244fb52017-04-04 17:33:40 -070087 }
88
Derek Sollenbergerfb0c8fc2017-07-26 13:53:27 -040089 ThrowIAE_IfNull(env, shader.get());
90 return reinterpret_cast<jlong>(shader.release());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080091}
Romain Guy06f96e22010-07-30 19:18:16 -070092
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080093///////////////////////////////////////////////////////////////////////////////////////////////
94
Chris Craikb581e672017-03-07 15:27:36 -080095static jlong LinearGradient_create1(JNIEnv* env, jobject o, jlong matrixPtr,
96 jfloat x0, jfloat y0, jfloat x1, jfloat y1,
97 jintArray colorArray, jfloatArray posArray, jint tileMode) {
98 const SkMatrix* matrix = reinterpret_cast<const SkMatrix*>(matrixPtr);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080099 SkPoint pts[2];
Leon Scroggins III2e0103e2014-04-04 17:05:24 -0400100 pts[0].set(x0, y0);
101 pts[1].set(x1, y1);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800102
Romain Guy06f96e22010-07-30 19:18:16 -0700103 size_t count = env->GetArrayLength(colorArray);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800104 const jint* colorValues = env->GetIntArrayElements(colorArray, NULL);
105
Leon Scroggins III2e0103e2014-04-04 17:05:24 -0400106 AutoJavaFloatArray autoPos(env, posArray, count);
107#ifdef SK_SCALAR_IS_FLOAT
108 SkScalar* pos = autoPos.ptr();
109#else
110 #error Need to convert float array to SkScalar array before calling the following function.
111#endif
Elliott Hughes4cb17532011-04-12 16:10:26 -0700112
ztenghuib244fb52017-04-04 17:33:40 -0700113 sk_sp<SkShader> baseShader(SkGradientShader::MakeLinear(pts,
Leon Scroggins III2e0103e2014-04-04 17:05:24 -0400114 reinterpret_cast<const SkColor*>(colorValues), pos, count,
ztenghuib244fb52017-04-04 17:33:40 -0700115 static_cast<SkShader::TileMode>(tileMode), sGradientShaderFlags, NULL));
116
117 SkShader* shader;
118 if (matrix) {
119 shader = baseShader->makeWithLocalMatrix(*matrix).release();
120 } else {
121 shader = baseShader.release();
122 }
Romain Guy06f96e22010-07-30 19:18:16 -0700123
124 env->ReleaseIntArrayElements(colorArray, const_cast<jint*>(colorValues), JNI_ABORT);
125 ThrowIAE_IfNull(env, shader);
Ashok Bhat36bef0b2014-01-20 20:08:01 +0000126 return reinterpret_cast<jlong>(shader);
Romain Guy06f96e22010-07-30 19:18:16 -0700127}
128
Chris Craikb581e672017-03-07 15:27:36 -0800129static jlong LinearGradient_create2(JNIEnv* env, jobject o, jlong matrixPtr,
130 jfloat x0, jfloat y0, jfloat x1, jfloat y1, jint color0, jint color1, jint tileMode) {
131 const SkMatrix* matrix = reinterpret_cast<const SkMatrix*>(matrixPtr);
132
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800133 SkPoint pts[2];
Leon Scroggins III2e0103e2014-04-04 17:05:24 -0400134 pts[0].set(x0, y0);
135 pts[1].set(x1, y1);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800136
137 SkColor colors[2];
138 colors[0] = color0;
139 colors[1] = color1;
Elliott Hughes4cb17532011-04-12 16:10:26 -0700140
ztenghuib244fb52017-04-04 17:33:40 -0700141 sk_sp<SkShader> baseShader(SkGradientShader::MakeLinear(pts, colors, NULL, 2,
142 static_cast<SkShader::TileMode>(tileMode), sGradientShaderFlags, NULL));
143
144 SkShader* s;
145 if (matrix) {
146 s = baseShader->makeWithLocalMatrix(*matrix).release();
147 } else {
148 s = baseShader.release();
149 }
Romain Guy06f96e22010-07-30 19:18:16 -0700150
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800151 ThrowIAE_IfNull(env, s);
Ashok Bhat36bef0b2014-01-20 20:08:01 +0000152 return reinterpret_cast<jlong>(s);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800153}
154
155///////////////////////////////////////////////////////////////////////////////////////////////
156
Chris Craikb581e672017-03-07 15:27:36 -0800157static jlong RadialGradient_create1(JNIEnv* env, jobject, jlong matrixPtr, jfloat x, jfloat y,
158 jfloat radius, jintArray colorArray, jfloatArray posArray, jint tileMode) {
159 const SkMatrix* matrix = reinterpret_cast<const SkMatrix*>(matrixPtr);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800160 SkPoint center;
Leon Scroggins III2e0103e2014-04-04 17:05:24 -0400161 center.set(x, y);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800162
163 size_t count = env->GetArrayLength(colorArray);
164 const jint* colorValues = env->GetIntArrayElements(colorArray, NULL);
165
Leon Scroggins III2e0103e2014-04-04 17:05:24 -0400166 AutoJavaFloatArray autoPos(env, posArray, count);
167#ifdef SK_SCALAR_IS_FLOAT
168 SkScalar* pos = autoPos.ptr();
169#else
170 #error Need to convert float array to SkScalar array before calling the following function.
171#endif
Elliott Hughes4cb17532011-04-12 16:10:26 -0700172
ztenghuib244fb52017-04-04 17:33:40 -0700173 sk_sp<SkShader> baseShader = SkGradientShader::MakeRadial(center, radius,
Leon Scroggins III2e0103e2014-04-04 17:05:24 -0400174 reinterpret_cast<const SkColor*>(colorValues), pos, count,
ztenghuib244fb52017-04-04 17:33:40 -0700175 static_cast<SkShader::TileMode>(tileMode), sGradientShaderFlags, NULL);
176
177 SkShader* shader;
178 if (matrix) {
179 shader = baseShader->makeWithLocalMatrix(*matrix).release();
180 } else {
181 shader = baseShader.release();
182 }
183
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800184 env->ReleaseIntArrayElements(colorArray, const_cast<jint*>(colorValues),
185 JNI_ABORT);
186
187 ThrowIAE_IfNull(env, shader);
Ashok Bhat36bef0b2014-01-20 20:08:01 +0000188 return reinterpret_cast<jlong>(shader);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800189}
190
Chris Craikb581e672017-03-07 15:27:36 -0800191static jlong RadialGradient_create2(JNIEnv* env, jobject, jlong matrixPtr, jfloat x, jfloat y, jfloat radius,
Ashok Bhat36bef0b2014-01-20 20:08:01 +0000192 jint color0, jint color1, jint tileMode) {
Chris Craikb581e672017-03-07 15:27:36 -0800193 const SkMatrix* matrix = reinterpret_cast<const SkMatrix*>(matrixPtr);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800194 SkPoint center;
Leon Scroggins III2e0103e2014-04-04 17:05:24 -0400195 center.set(x, y);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800196
197 SkColor colors[2];
198 colors[0] = color0;
199 colors[1] = color1;
200
ztenghuib244fb52017-04-04 17:33:40 -0700201 sk_sp<SkShader> baseShader = SkGradientShader::MakeRadial(center, radius, colors, NULL, 2,
202 static_cast<SkShader::TileMode>(tileMode), sGradientShaderFlags, NULL);
203
204 SkShader* shader;
205 if (matrix) {
206 shader = baseShader->makeWithLocalMatrix(*matrix).release();
207 } else {
208 shader = baseShader.release();
209 }
210 ThrowIAE_IfNull(env, shader);
211 return reinterpret_cast<jlong>(shader);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800212}
213
214///////////////////////////////////////////////////////////////////////////////
215
Chris Craikb581e672017-03-07 15:27:36 -0800216static jlong SweepGradient_create1(JNIEnv* env, jobject, jlong matrixPtr, jfloat x, jfloat y,
Romain Guyddb80be2010-09-20 19:04:33 -0700217 jintArray jcolors, jfloatArray jpositions) {
Chris Craikb581e672017-03-07 15:27:36 -0800218 const SkMatrix* matrix = reinterpret_cast<const SkMatrix*>(matrixPtr);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800219 size_t count = env->GetArrayLength(jcolors);
220 const jint* colors = env->GetIntArrayElements(jcolors, NULL);
Elliott Hughes4cb17532011-04-12 16:10:26 -0700221
Leon Scroggins III2e0103e2014-04-04 17:05:24 -0400222 AutoJavaFloatArray autoPos(env, jpositions, count);
223#ifdef SK_SCALAR_IS_FLOAT
224 SkScalar* pos = autoPos.ptr();
225#else
226 #error Need to convert float array to SkScalar array before calling the following function.
227#endif
Elliott Hughes4cb17532011-04-12 16:10:26 -0700228
ztenghuib244fb52017-04-04 17:33:40 -0700229 sk_sp<SkShader> baseShader = SkGradientShader::MakeSweep(x, y,
230 reinterpret_cast<const SkColor*>(colors), pos, count,
231 sGradientShaderFlags, NULL);
232
233 SkShader* shader;
234 if (matrix) {
235 shader = baseShader->makeWithLocalMatrix(*matrix).release();
236 } else {
237 shader = baseShader.release();
238 }
239
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800240 env->ReleaseIntArrayElements(jcolors, const_cast<jint*>(colors),
241 JNI_ABORT);
242 ThrowIAE_IfNull(env, shader);
Ashok Bhat36bef0b2014-01-20 20:08:01 +0000243 return reinterpret_cast<jlong>(shader);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800244}
245
Chris Craikb581e672017-03-07 15:27:36 -0800246static jlong SweepGradient_create2(JNIEnv* env, jobject, jlong matrixPtr, jfloat x, jfloat y,
Romain Guyddb80be2010-09-20 19:04:33 -0700247 int color0, int color1) {
Chris Craikb581e672017-03-07 15:27:36 -0800248 const SkMatrix* matrix = reinterpret_cast<const SkMatrix*>(matrixPtr);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800249 SkColor colors[2];
250 colors[0] = color0;
251 colors[1] = color1;
ztenghuib244fb52017-04-04 17:33:40 -0700252
253 sk_sp<SkShader> baseShader = SkGradientShader::MakeSweep(x, y, colors,
254 NULL, 2, sGradientShaderFlags, NULL);
255
256 SkShader* shader;
257 if (matrix) {
258 shader = baseShader->makeWithLocalMatrix(*matrix).release();
259 } else {
260 shader = baseShader.release();
261 }
262 ThrowIAE_IfNull(env, shader);
263 return reinterpret_cast<jlong>(shader);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800264}
265
266///////////////////////////////////////////////////////////////////////////////////////////////
267
Chris Craikb581e672017-03-07 15:27:36 -0800268static jlong ComposeShader_create(JNIEnv* env, jobject o, jlong matrixPtr,
269 jlong shaderAHandle, jlong shaderBHandle, jint xfermodeHandle) {
270 const SkMatrix* matrix = reinterpret_cast<const SkMatrix*>(matrixPtr);
Ashok Bhat36bef0b2014-01-20 20:08:01 +0000271 SkShader* shaderA = reinterpret_cast<SkShader *>(shaderAHandle);
272 SkShader* shaderB = reinterpret_cast<SkShader *>(shaderBHandle);
Mike Reed260ab722016-10-07 15:59:20 -0400273 SkBlendMode mode = static_cast<SkBlendMode>(xfermodeHandle);
Chris Craikb581e672017-03-07 15:27:36 -0800274 sk_sp<SkShader> baseShader(SkShader::MakeComposeShader(
275 sk_ref_sp(shaderA), sk_ref_sp(shaderB), mode));
276
277 SkShader* shader;
278
279 if (matrix) {
280 shader = baseShader->makeWithLocalMatrix(*matrix).release();
281 } else {
282 shader = baseShader.release();
283 }
Ashok Bhat36bef0b2014-01-20 20:08:01 +0000284 return reinterpret_cast<jlong>(shader);
Romain Guy06f96e22010-07-30 19:18:16 -0700285}
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800286
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800287///////////////////////////////////////////////////////////////////////////////////////////////
288
Daniel Micay76f6a862015-09-19 17:31:01 -0400289static const JNINativeMethod gColorMethods[] = {
Chris Craikb581e672017-03-07 15:27:36 -0800290 { "nativeRGBToHSV", "(III[F)V", (void*)Color_RGBToHSV },
291 { "nativeHSVToColor", "(I[F)I", (void*)Color_HSVToColor }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800292};
293
Daniel Micay76f6a862015-09-19 17:31:01 -0400294static const JNINativeMethod gShaderMethods[] = {
John Reck8bde0be2017-05-19 10:55:20 -0700295 { "nativeGetFinalizer", "()J", (void*)Shader_getNativeFinalizer },
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800296};
297
Daniel Micay76f6a862015-09-19 17:31:01 -0400298static const JNINativeMethod gBitmapShaderMethods[] = {
Chris Craikb581e672017-03-07 15:27:36 -0800299 { "nativeCreate", "(JLandroid/graphics/Bitmap;II)J", (void*)BitmapShader_constructor },
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800300};
301
Daniel Micay76f6a862015-09-19 17:31:01 -0400302static const JNINativeMethod gLinearGradientMethods[] = {
Chris Craikb581e672017-03-07 15:27:36 -0800303 { "nativeCreate1", "(JFFFF[I[FI)J", (void*)LinearGradient_create1 },
304 { "nativeCreate2", "(JFFFFIII)J", (void*)LinearGradient_create2 },
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800305};
306
Daniel Micay76f6a862015-09-19 17:31:01 -0400307static const JNINativeMethod gRadialGradientMethods[] = {
Chris Craikb581e672017-03-07 15:27:36 -0800308 { "nativeCreate1", "(JFFF[I[FI)J", (void*)RadialGradient_create1 },
309 { "nativeCreate2", "(JFFFIII)J", (void*)RadialGradient_create2 },
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800310};
311
Daniel Micay76f6a862015-09-19 17:31:01 -0400312static const JNINativeMethod gSweepGradientMethods[] = {
Chris Craikb581e672017-03-07 15:27:36 -0800313 { "nativeCreate1", "(JFF[I[F)J", (void*)SweepGradient_create1 },
314 { "nativeCreate2", "(JFFII)J", (void*)SweepGradient_create2 },
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800315};
316
Daniel Micay76f6a862015-09-19 17:31:01 -0400317static const JNINativeMethod gComposeShaderMethods[] = {
Chris Craikb581e672017-03-07 15:27:36 -0800318 { "nativeCreate", "(JJJI)J", (void*)ComposeShader_create },
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800319};
320
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800321int register_android_graphics_Shader(JNIEnv* env)
322{
Andreas Gampeed6b9df2014-11-20 22:02:20 -0800323 android::RegisterMethodsOrDie(env, "android/graphics/Color", gColorMethods,
324 NELEM(gColorMethods));
325 android::RegisterMethodsOrDie(env, "android/graphics/Shader", gShaderMethods,
326 NELEM(gShaderMethods));
327 android::RegisterMethodsOrDie(env, "android/graphics/BitmapShader", gBitmapShaderMethods,
328 NELEM(gBitmapShaderMethods));
329 android::RegisterMethodsOrDie(env, "android/graphics/LinearGradient", gLinearGradientMethods,
330 NELEM(gLinearGradientMethods));
331 android::RegisterMethodsOrDie(env, "android/graphics/RadialGradient", gRadialGradientMethods,
332 NELEM(gRadialGradientMethods));
333 android::RegisterMethodsOrDie(env, "android/graphics/SweepGradient", gSweepGradientMethods,
334 NELEM(gSweepGradientMethods));
335 android::RegisterMethodsOrDie(env, "android/graphics/ComposeShader", gComposeShaderMethods,
336 NELEM(gComposeShaderMethods));
Elliott Hughes4cb17532011-04-12 16:10:26 -0700337
Andreas Gampeed6b9df2014-11-20 22:02:20 -0800338 return 0;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800339}