blob: 0de46e6b4d046737e04f22aa680b083fd5e6289e [file] [log] [blame]
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001#include "GraphicsJNI.h"
Ben Wagner60126ef2015-08-07 12:13:48 -04002#include "SkGradientShader.h"
Matt Sarett62feb3a2016-09-20 10:34:11 -04003#include "SkImagePriv.h"
Ben Wagner60126ef2015-08-07 12:13:48 -04004#include "SkShader.h"
Mike Reedc2f31df2016-10-28 17:21:45 -04005#include "SkBlendMode.h"
Ben Wagner60126ef2015-08-07 12:13:48 -04006#include "core_jni_helpers.h"
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007
Romain Guya2341a92010-09-08 18:04:33 -07008#include <Caches.h>
Ben Wagner60126ef2015-08-07 12:13:48 -04009#include <jni.h>
Andreas Gampeed6b9df2014-11-20 22:02:20 -080010
Romain Guy06f96e22010-07-30 19:18:16 -070011using namespace android::uirenderer;
12
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013static void ThrowIAE_IfNull(JNIEnv* env, void* ptr) {
14 if (NULL == ptr) {
15 doThrowIAE(env);
16 }
17}
18
Ashok Bhat36bef0b2014-01-20 20:08:01 +000019static void Color_RGBToHSV(JNIEnv* env, jobject, jint red, jint green, jint blue, jfloatArray hsvArray)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080020{
21 SkScalar hsv[3];
22 SkRGBToHSV(red, green, blue, hsv);
23
24 AutoJavaFloatArray autoHSV(env, hsvArray, 3);
25 float* values = autoHSV.ptr();
26 for (int i = 0; i < 3; i++) {
27 values[i] = SkScalarToFloat(hsv[i]);
28 }
29}
Elliott Hughes4cb17532011-04-12 16:10:26 -070030
Ashok Bhat36bef0b2014-01-20 20:08:01 +000031static jint Color_HSVToColor(JNIEnv* env, jobject, jint alpha, jfloatArray hsvArray)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080032{
33 AutoJavaFloatArray autoHSV(env, hsvArray, 3);
Leon Scroggins III2e0103e2014-04-04 17:05:24 -040034#ifdef SK_SCALAR_IS_FLOAT
35 SkScalar* hsv = autoHSV.ptr();
36#else
37 #error Need to convert float array to SkScalar array before calling the following function.
38#endif
Elliott Hughes4cb17532011-04-12 16:10:26 -070039
Ashok Bhat36bef0b2014-01-20 20:08:01 +000040 return static_cast<jint>(SkHSVToColor(alpha, hsv));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080041}
42
43///////////////////////////////////////////////////////////////////////////////////////////////
44
Leon Scroggins III866cf652014-07-22 17:25:22 -040045static void Shader_destructor(JNIEnv* env, jobject o, jlong shaderHandle, jlong shaderWithLMHandle)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080046{
Ashok Bhat36bef0b2014-01-20 20:08:01 +000047 SkShader* shader = reinterpret_cast<SkShader*>(shaderHandle);
Derek Sollenberger6062c592011-02-22 13:55:04 -050048 SkSafeUnref(shader);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080049}
50
Derek Sollenbergerdfba4d32014-09-02 15:42:54 -040051static jlong Shader_setLocalMatrix(JNIEnv* env, jobject o, jlong shaderHandle, jlong matrixHandle)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080052{
Derek Sollenbergerdfba4d32014-09-02 15:42:54 -040053 // ensure we have a valid matrix to use
Ashok Bhat36bef0b2014-01-20 20:08:01 +000054 const SkMatrix* matrix = reinterpret_cast<SkMatrix*>(matrixHandle);
Derek Sollenbergerdfba4d32014-09-02 15:42:54 -040055 if (NULL == matrix) {
56 matrix = &SkMatrix::I();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080057 }
Derek Sollenbergerdfba4d32014-09-02 15:42:54 -040058
59 // The current shader will no longer need a direct reference owned by Shader.java
60 // as all the data needed is contained within the newly created LocalMatrixShader.
61 SkASSERT(shaderHandle);
Ben Wagner18bd8852016-10-24 14:50:10 -040062 sk_sp<SkShader> currentShader(reinterpret_cast<SkShader*>(shaderHandle));
Leon Scroggins IIIc95d2d12016-01-14 17:18:54 -050063
64 // Attempt to peel off an existing proxy shader and get the proxy's matrix. If
65 // the proxy existed and it's matrix equals the desired matrix then just return
66 // the proxy, otherwise replace it with a new proxy containing the desired matrix.
67 //
68 // refAsALocalMatrixShader(): if the shader contains a proxy then it unwraps the proxy
69 // returning both the underlying shader and the proxy's matrix.
70 // newWithLocalMatrix(): will return a proxy shader that wraps the provided shader and
71 // concats the provided local matrix with the shader's matrix.
72 //
73 // WARNING: This proxy replacement only behaves like a setter because the Java
74 // API enforces that all local matrices are set using this call and
75 // not passed to the constructor of the Shader.
76 SkMatrix proxyMatrix;
Ben Wagner18bd8852016-10-24 14:50:10 -040077 sk_sp<SkShader> baseShader = currentShader->makeAsALocalMatrixShader(&proxyMatrix);
Leon Scroggins IIIc95d2d12016-01-14 17:18:54 -050078 if (baseShader.get()) {
79 if (proxyMatrix == *matrix) {
Ben Wagner18bd8852016-10-24 14:50:10 -040080 return reinterpret_cast<jlong>(currentShader.release());
Leon Scroggins IIIc95d2d12016-01-14 17:18:54 -050081 }
Mike Reed260ab722016-10-07 15:59:20 -040082 return reinterpret_cast<jlong>(baseShader->makeWithLocalMatrix(*matrix).release());
Leon Scroggins IIIc95d2d12016-01-14 17:18:54 -050083 }
Mike Reed260ab722016-10-07 15:59:20 -040084 return reinterpret_cast<jlong>(currentShader->makeWithLocalMatrix(*matrix).release());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080085}
86
87///////////////////////////////////////////////////////////////////////////////////////////////
88
John Reck3731dc22015-04-13 15:20:29 -070089static jlong BitmapShader_constructor(JNIEnv* env, jobject o, jobject jbitmap,
Ashok Bhat36bef0b2014-01-20 20:08:01 +000090 jint tileModeX, jint tileModeY)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080091{
John Reck3731dc22015-04-13 15:20:29 -070092 SkBitmap bitmap;
Chris Craikb786bbd2015-06-10 16:58:42 -070093 if (jbitmap) {
94 // Only pass a valid SkBitmap object to the constructor if the Bitmap exists. Otherwise,
95 // we'll pass an empty SkBitmap to avoid crashing/excepting for compatibility.
96 GraphicsJNI::getSkBitmap(env, jbitmap, &bitmap);
97 }
Romain Guy06f96e22010-07-30 19:18:16 -070098
Derek Sollenberger450756a2016-11-07 15:55:47 -050099 sk_sp<SkImage> image = SkMakeImageFromRasterBitmap(bitmap, kNever_SkCopyPixelsMode);
100 sk_sp<SkShader> shader = image->makeShader((SkShader::TileMode)tileModeX,
101 (SkShader::TileMode)tileModeY);
102
103 ThrowIAE_IfNull(env, shader.get());
104 return reinterpret_cast<jlong>(shader.release());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800105}
Romain Guy06f96e22010-07-30 19:18:16 -0700106
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800107///////////////////////////////////////////////////////////////////////////////////////////////
108
Ashok Bhat36bef0b2014-01-20 20:08:01 +0000109static jlong LinearGradient_create1(JNIEnv* env, jobject o,
110 jfloat x0, jfloat y0, jfloat x1, jfloat y1,
111 jintArray colorArray, jfloatArray posArray, jint tileMode)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800112{
113 SkPoint pts[2];
Leon Scroggins III2e0103e2014-04-04 17:05:24 -0400114 pts[0].set(x0, y0);
115 pts[1].set(x1, y1);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800116
Romain Guy06f96e22010-07-30 19:18:16 -0700117 size_t count = env->GetArrayLength(colorArray);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800118 const jint* colorValues = env->GetIntArrayElements(colorArray, NULL);
119
Leon Scroggins III2e0103e2014-04-04 17:05:24 -0400120 AutoJavaFloatArray autoPos(env, posArray, count);
121#ifdef SK_SCALAR_IS_FLOAT
122 SkScalar* pos = autoPos.ptr();
123#else
124 #error Need to convert float array to SkScalar array before calling the following function.
125#endif
Elliott Hughes4cb17532011-04-12 16:10:26 -0700126
Mike Reed260ab722016-10-07 15:59:20 -0400127 SkShader* shader = SkGradientShader::MakeLinear(pts,
Leon Scroggins III2e0103e2014-04-04 17:05:24 -0400128 reinterpret_cast<const SkColor*>(colorValues), pos, count,
Mike Reed260ab722016-10-07 15:59:20 -0400129 static_cast<SkShader::TileMode>(tileMode)).release();
Romain Guy06f96e22010-07-30 19:18:16 -0700130
131 env->ReleaseIntArrayElements(colorArray, const_cast<jint*>(colorValues), JNI_ABORT);
132 ThrowIAE_IfNull(env, shader);
Ashok Bhat36bef0b2014-01-20 20:08:01 +0000133 return reinterpret_cast<jlong>(shader);
Romain Guy06f96e22010-07-30 19:18:16 -0700134}
135
Ashok Bhat36bef0b2014-01-20 20:08:01 +0000136static jlong LinearGradient_create2(JNIEnv* env, jobject o,
137 jfloat x0, jfloat y0, jfloat x1, jfloat y1,
138 jint color0, jint color1, jint tileMode)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800139{
140 SkPoint pts[2];
Leon Scroggins III2e0103e2014-04-04 17:05:24 -0400141 pts[0].set(x0, y0);
142 pts[1].set(x1, y1);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800143
144 SkColor colors[2];
145 colors[0] = color0;
146 colors[1] = color1;
Elliott Hughes4cb17532011-04-12 16:10:26 -0700147
Mike Reed260ab722016-10-07 15:59:20 -0400148 SkShader* s = SkGradientShader::MakeLinear(pts, colors, NULL, 2, (SkShader::TileMode)tileMode).release();
Romain Guy06f96e22010-07-30 19:18:16 -0700149
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800150 ThrowIAE_IfNull(env, s);
Ashok Bhat36bef0b2014-01-20 20:08:01 +0000151 return reinterpret_cast<jlong>(s);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800152}
153
154///////////////////////////////////////////////////////////////////////////////////////////////
155
Ashok Bhat36bef0b2014-01-20 20:08:01 +0000156static jlong RadialGradient_create1(JNIEnv* env, jobject, jfloat x, jfloat y, jfloat radius,
157 jintArray colorArray, jfloatArray posArray, jint tileMode) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800158 SkPoint center;
Leon Scroggins III2e0103e2014-04-04 17:05:24 -0400159 center.set(x, y);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800160
161 size_t count = env->GetArrayLength(colorArray);
162 const jint* colorValues = env->GetIntArrayElements(colorArray, NULL);
163
Leon Scroggins III2e0103e2014-04-04 17:05:24 -0400164 AutoJavaFloatArray autoPos(env, posArray, count);
165#ifdef SK_SCALAR_IS_FLOAT
166 SkScalar* pos = autoPos.ptr();
167#else
168 #error Need to convert float array to SkScalar array before calling the following function.
169#endif
Elliott Hughes4cb17532011-04-12 16:10:26 -0700170
Mike Reed260ab722016-10-07 15:59:20 -0400171 SkShader* shader = SkGradientShader::MakeRadial(center, radius,
Leon Scroggins III2e0103e2014-04-04 17:05:24 -0400172 reinterpret_cast<const SkColor*>(colorValues), pos, count,
Mike Reed260ab722016-10-07 15:59:20 -0400173 static_cast<SkShader::TileMode>(tileMode)).release();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800174 env->ReleaseIntArrayElements(colorArray, const_cast<jint*>(colorValues),
175 JNI_ABORT);
176
177 ThrowIAE_IfNull(env, shader);
Ashok Bhat36bef0b2014-01-20 20:08:01 +0000178 return reinterpret_cast<jlong>(shader);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800179}
180
Ashok Bhat36bef0b2014-01-20 20:08:01 +0000181static jlong RadialGradient_create2(JNIEnv* env, jobject, jfloat x, jfloat y, jfloat radius,
182 jint color0, jint color1, jint tileMode) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800183 SkPoint center;
Leon Scroggins III2e0103e2014-04-04 17:05:24 -0400184 center.set(x, y);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800185
186 SkColor colors[2];
187 colors[0] = color0;
188 colors[1] = color1;
189
Mike Reed260ab722016-10-07 15:59:20 -0400190 SkShader* s = SkGradientShader::MakeRadial(center, radius, colors, NULL, 2,
191 (SkShader::TileMode)tileMode).release();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800192 ThrowIAE_IfNull(env, s);
Ashok Bhat36bef0b2014-01-20 20:08:01 +0000193 return reinterpret_cast<jlong>(s);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800194}
195
196///////////////////////////////////////////////////////////////////////////////
197
Ashok Bhat36bef0b2014-01-20 20:08:01 +0000198static jlong SweepGradient_create1(JNIEnv* env, jobject, jfloat x, jfloat y,
Romain Guyddb80be2010-09-20 19:04:33 -0700199 jintArray jcolors, jfloatArray jpositions) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800200 size_t count = env->GetArrayLength(jcolors);
201 const jint* colors = env->GetIntArrayElements(jcolors, NULL);
Elliott Hughes4cb17532011-04-12 16:10:26 -0700202
Leon Scroggins III2e0103e2014-04-04 17:05:24 -0400203 AutoJavaFloatArray autoPos(env, jpositions, count);
204#ifdef SK_SCALAR_IS_FLOAT
205 SkScalar* pos = autoPos.ptr();
206#else
207 #error Need to convert float array to SkScalar array before calling the following function.
208#endif
Elliott Hughes4cb17532011-04-12 16:10:26 -0700209
Mike Reed260ab722016-10-07 15:59:20 -0400210 SkShader* shader = SkGradientShader::MakeSweep(x, y,
211 reinterpret_cast<const SkColor*>(colors), pos, count).release();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800212 env->ReleaseIntArrayElements(jcolors, const_cast<jint*>(colors),
213 JNI_ABORT);
214 ThrowIAE_IfNull(env, shader);
Ashok Bhat36bef0b2014-01-20 20:08:01 +0000215 return reinterpret_cast<jlong>(shader);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800216}
217
Ashok Bhat36bef0b2014-01-20 20:08:01 +0000218static jlong SweepGradient_create2(JNIEnv* env, jobject, jfloat x, jfloat y,
Romain Guyddb80be2010-09-20 19:04:33 -0700219 int color0, int color1) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800220 SkColor colors[2];
221 colors[0] = color0;
222 colors[1] = color1;
Mike Reed260ab722016-10-07 15:59:20 -0400223 SkShader* s = SkGradientShader::MakeSweep(x, y, colors, NULL, 2).release();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800224 ThrowIAE_IfNull(env, s);
Ashok Bhat36bef0b2014-01-20 20:08:01 +0000225 return reinterpret_cast<jlong>(s);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800226}
227
228///////////////////////////////////////////////////////////////////////////////////////////////
229
John Reck5d31a292016-09-15 10:13:10 -0700230static jlong ComposeShader_create(JNIEnv* env, jobject o,
Chris Craik1526a452015-03-06 18:42:15 +0000231 jlong shaderAHandle, jlong shaderBHandle, jint xfermodeHandle)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800232{
Ashok Bhat36bef0b2014-01-20 20:08:01 +0000233 SkShader* shaderA = reinterpret_cast<SkShader *>(shaderAHandle);
234 SkShader* shaderB = reinterpret_cast<SkShader *>(shaderBHandle);
Mike Reed260ab722016-10-07 15:59:20 -0400235 SkBlendMode mode = static_cast<SkBlendMode>(xfermodeHandle);
236 SkShader* shader = SkShader::MakeComposeShader(sk_ref_sp(shaderA),
237 sk_ref_sp(shaderB),
Mike Reedc2f31df2016-10-28 17:21:45 -0400238 mode).release();
Ashok Bhat36bef0b2014-01-20 20:08:01 +0000239 return reinterpret_cast<jlong>(shader);
Romain Guy06f96e22010-07-30 19:18:16 -0700240}
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800241
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800242///////////////////////////////////////////////////////////////////////////////////////////////
243
Daniel Micay76f6a862015-09-19 17:31:01 -0400244static const JNINativeMethod gColorMethods[] = {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800245 { "nativeRGBToHSV", "(III[F)V", (void*)Color_RGBToHSV },
246 { "nativeHSVToColor", "(I[F)I", (void*)Color_HSVToColor }
247};
248
Daniel Micay76f6a862015-09-19 17:31:01 -0400249static const JNINativeMethod gShaderMethods[] = {
John Reck01edef12014-08-22 11:15:37 -0700250 { "nativeDestructor", "(J)V", (void*)Shader_destructor },
Derek Sollenbergerdfba4d32014-09-02 15:42:54 -0400251 { "nativeSetLocalMatrix", "(JJ)J", (void*)Shader_setLocalMatrix }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800252};
253
Daniel Micay76f6a862015-09-19 17:31:01 -0400254static const JNINativeMethod gBitmapShaderMethods[] = {
John Reck3731dc22015-04-13 15:20:29 -0700255 { "nativeCreate", "(Landroid/graphics/Bitmap;II)J", (void*)BitmapShader_constructor },
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800256};
257
Daniel Micay76f6a862015-09-19 17:31:01 -0400258static const JNINativeMethod gLinearGradientMethods[] = {
Ashok Bhat36bef0b2014-01-20 20:08:01 +0000259 { "nativeCreate1", "(FFFF[I[FI)J", (void*)LinearGradient_create1 },
260 { "nativeCreate2", "(FFFFIII)J", (void*)LinearGradient_create2 },
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800261};
262
Daniel Micay76f6a862015-09-19 17:31:01 -0400263static const JNINativeMethod gRadialGradientMethods[] = {
Ashok Bhat36bef0b2014-01-20 20:08:01 +0000264 { "nativeCreate1", "(FFF[I[FI)J", (void*)RadialGradient_create1 },
265 { "nativeCreate2", "(FFFIII)J", (void*)RadialGradient_create2 },
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800266};
267
Daniel Micay76f6a862015-09-19 17:31:01 -0400268static const JNINativeMethod gSweepGradientMethods[] = {
Ashok Bhat36bef0b2014-01-20 20:08:01 +0000269 { "nativeCreate1", "(FF[I[F)J", (void*)SweepGradient_create1 },
270 { "nativeCreate2", "(FFII)J", (void*)SweepGradient_create2 },
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800271};
272
Daniel Micay76f6a862015-09-19 17:31:01 -0400273static const JNINativeMethod gComposeShaderMethods[] = {
John Reck5d31a292016-09-15 10:13:10 -0700274 { "nativeCreate", "(JJI)J", (void*)ComposeShader_create },
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800275};
276
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800277int register_android_graphics_Shader(JNIEnv* env)
278{
Andreas Gampeed6b9df2014-11-20 22:02:20 -0800279 android::RegisterMethodsOrDie(env, "android/graphics/Color", gColorMethods,
280 NELEM(gColorMethods));
281 android::RegisterMethodsOrDie(env, "android/graphics/Shader", gShaderMethods,
282 NELEM(gShaderMethods));
283 android::RegisterMethodsOrDie(env, "android/graphics/BitmapShader", gBitmapShaderMethods,
284 NELEM(gBitmapShaderMethods));
285 android::RegisterMethodsOrDie(env, "android/graphics/LinearGradient", gLinearGradientMethods,
286 NELEM(gLinearGradientMethods));
287 android::RegisterMethodsOrDie(env, "android/graphics/RadialGradient", gRadialGradientMethods,
288 NELEM(gRadialGradientMethods));
289 android::RegisterMethodsOrDie(env, "android/graphics/SweepGradient", gSweepGradientMethods,
290 NELEM(gSweepGradientMethods));
291 android::RegisterMethodsOrDie(env, "android/graphics/ComposeShader", gComposeShaderMethods,
292 NELEM(gComposeShaderMethods));
Elliott Hughes4cb17532011-04-12 16:10:26 -0700293
Andreas Gampeed6b9df2014-11-20 22:02:20 -0800294 return 0;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800295}