blob: d0f75917106a5612a3b93c94fae175ef98bfaf87 [file] [log] [blame]
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001#include <jni.h>
2#include "GraphicsJNI.h"
3
4#include "SkShader.h"
5#include "SkGradientShader.h"
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006#include "SkComposeShader.h"
7#include "SkTemplates.h"
8#include "SkXfermode.h"
9
Romain Guya2341a92010-09-08 18:04:33 -070010#include <Caches.h>
Romain Guy06f96e22010-07-30 19:18:16 -070011
Andreas Gampeed6b9df2014-11-20 22:02:20 -080012#include "core_jni_helpers.h"
13
Romain Guy06f96e22010-07-30 19:18:16 -070014using namespace android::uirenderer;
15
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080016static void ThrowIAE_IfNull(JNIEnv* env, void* ptr) {
17 if (NULL == ptr) {
18 doThrowIAE(env);
19 }
20}
21
Ashok Bhat36bef0b2014-01-20 20:08:01 +000022static void Color_RGBToHSV(JNIEnv* env, jobject, jint red, jint green, jint blue, jfloatArray hsvArray)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080023{
24 SkScalar hsv[3];
25 SkRGBToHSV(red, green, blue, hsv);
26
27 AutoJavaFloatArray autoHSV(env, hsvArray, 3);
28 float* values = autoHSV.ptr();
29 for (int i = 0; i < 3; i++) {
30 values[i] = SkScalarToFloat(hsv[i]);
31 }
32}
Elliott Hughes4cb17532011-04-12 16:10:26 -070033
Ashok Bhat36bef0b2014-01-20 20:08:01 +000034static jint Color_HSVToColor(JNIEnv* env, jobject, jint alpha, jfloatArray hsvArray)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080035{
36 AutoJavaFloatArray autoHSV(env, hsvArray, 3);
Leon Scroggins III2e0103e2014-04-04 17:05:24 -040037#ifdef SK_SCALAR_IS_FLOAT
38 SkScalar* hsv = autoHSV.ptr();
39#else
40 #error Need to convert float array to SkScalar array before calling the following function.
41#endif
Elliott Hughes4cb17532011-04-12 16:10:26 -070042
Ashok Bhat36bef0b2014-01-20 20:08:01 +000043 return static_cast<jint>(SkHSVToColor(alpha, hsv));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080044}
45
46///////////////////////////////////////////////////////////////////////////////////////////////
47
Leon Scroggins III866cf652014-07-22 17:25:22 -040048static void Shader_destructor(JNIEnv* env, jobject o, jlong shaderHandle, jlong shaderWithLMHandle)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080049{
Ashok Bhat36bef0b2014-01-20 20:08:01 +000050 SkShader* shader = reinterpret_cast<SkShader*>(shaderHandle);
Derek Sollenberger6062c592011-02-22 13:55:04 -050051 SkSafeUnref(shader);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080052}
53
Derek Sollenbergerdfba4d32014-09-02 15:42:54 -040054static jlong Shader_setLocalMatrix(JNIEnv* env, jobject o, jlong shaderHandle, jlong matrixHandle)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080055{
Derek Sollenbergerdfba4d32014-09-02 15:42:54 -040056 // ensure we have a valid matrix to use
Ashok Bhat36bef0b2014-01-20 20:08:01 +000057 const SkMatrix* matrix = reinterpret_cast<SkMatrix*>(matrixHandle);
Derek Sollenbergerdfba4d32014-09-02 15:42:54 -040058 if (NULL == matrix) {
59 matrix = &SkMatrix::I();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080060 }
Derek Sollenbergerdfba4d32014-09-02 15:42:54 -040061
62 // The current shader will no longer need a direct reference owned by Shader.java
63 // as all the data needed is contained within the newly created LocalMatrixShader.
64 SkASSERT(shaderHandle);
65 SkAutoTUnref<SkShader> currentShader(reinterpret_cast<SkShader*>(shaderHandle));
66
67 SkMatrix currentMatrix;
68 SkAutoTUnref<SkShader> baseShader(currentShader->refAsALocalMatrixShader(&currentMatrix));
69 if (baseShader.get()) {
70 // if the matrices are same then there is no need to allocate a new
71 // shader that is identical to the existing one.
72 if (currentMatrix == *matrix) {
73 return reinterpret_cast<jlong>(currentShader.detach());
74 }
75 return reinterpret_cast<jlong>(SkShader::CreateLocalMatrixShader(baseShader, *matrix));
76 }
77
78 return reinterpret_cast<jlong>(SkShader::CreateLocalMatrixShader(currentShader, *matrix));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080079}
80
81///////////////////////////////////////////////////////////////////////////////////////////////
82
John Reckc294d122015-04-13 15:20:29 -070083static jlong BitmapShader_constructor(JNIEnv* env, jobject o, jobject jbitmap,
Ashok Bhat36bef0b2014-01-20 20:08:01 +000084 jint tileModeX, jint tileModeY)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080085{
John Reckc294d122015-04-13 15:20:29 -070086 SkBitmap bitmap;
87 GraphicsJNI::getSkBitmap(env, jbitmap, &bitmap);
88 SkShader* s = SkShader::CreateBitmapShader(bitmap,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080089 (SkShader::TileMode)tileModeX,
90 (SkShader::TileMode)tileModeY);
Romain Guy06f96e22010-07-30 19:18:16 -070091
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080092 ThrowIAE_IfNull(env, s);
Ashok Bhat36bef0b2014-01-20 20:08:01 +000093 return reinterpret_cast<jlong>(s);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080094}
Romain Guy06f96e22010-07-30 19:18:16 -070095
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080096///////////////////////////////////////////////////////////////////////////////////////////////
97
Ashok Bhat36bef0b2014-01-20 20:08:01 +000098static jlong LinearGradient_create1(JNIEnv* env, jobject o,
99 jfloat x0, jfloat y0, jfloat x1, jfloat y1,
100 jintArray colorArray, jfloatArray posArray, jint tileMode)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800101{
102 SkPoint pts[2];
Leon Scroggins III2e0103e2014-04-04 17:05:24 -0400103 pts[0].set(x0, y0);
104 pts[1].set(x1, y1);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800105
Romain Guy06f96e22010-07-30 19:18:16 -0700106 size_t count = env->GetArrayLength(colorArray);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800107 const jint* colorValues = env->GetIntArrayElements(colorArray, NULL);
108
Leon Scroggins III2e0103e2014-04-04 17:05:24 -0400109 AutoJavaFloatArray autoPos(env, posArray, count);
110#ifdef SK_SCALAR_IS_FLOAT
111 SkScalar* pos = autoPos.ptr();
112#else
113 #error Need to convert float array to SkScalar array before calling the following function.
114#endif
Elliott Hughes4cb17532011-04-12 16:10:26 -0700115
Romain Guy06f96e22010-07-30 19:18:16 -0700116 SkShader* shader = SkGradientShader::CreateLinear(pts,
Leon Scroggins III2e0103e2014-04-04 17:05:24 -0400117 reinterpret_cast<const SkColor*>(colorValues), pos, count,
118 static_cast<SkShader::TileMode>(tileMode));
Romain Guy06f96e22010-07-30 19:18:16 -0700119
120 env->ReleaseIntArrayElements(colorArray, const_cast<jint*>(colorValues), JNI_ABORT);
121 ThrowIAE_IfNull(env, shader);
Ashok Bhat36bef0b2014-01-20 20:08:01 +0000122 return reinterpret_cast<jlong>(shader);
Romain Guy06f96e22010-07-30 19:18:16 -0700123}
124
Ashok Bhat36bef0b2014-01-20 20:08:01 +0000125static jlong LinearGradient_create2(JNIEnv* env, jobject o,
126 jfloat x0, jfloat y0, jfloat x1, jfloat y1,
127 jint color0, jint color1, jint tileMode)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800128{
129 SkPoint pts[2];
Leon Scroggins III2e0103e2014-04-04 17:05:24 -0400130 pts[0].set(x0, y0);
131 pts[1].set(x1, y1);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800132
133 SkColor colors[2];
134 colors[0] = color0;
135 colors[1] = color1;
Elliott Hughes4cb17532011-04-12 16:10:26 -0700136
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800137 SkShader* s = SkGradientShader::CreateLinear(pts, colors, NULL, 2, (SkShader::TileMode)tileMode);
Romain Guy06f96e22010-07-30 19:18:16 -0700138
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800139 ThrowIAE_IfNull(env, s);
Ashok Bhat36bef0b2014-01-20 20:08:01 +0000140 return reinterpret_cast<jlong>(s);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800141}
142
143///////////////////////////////////////////////////////////////////////////////////////////////
144
Ashok Bhat36bef0b2014-01-20 20:08:01 +0000145static jlong RadialGradient_create1(JNIEnv* env, jobject, jfloat x, jfloat y, jfloat radius,
146 jintArray colorArray, jfloatArray posArray, jint tileMode) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800147 SkPoint center;
Leon Scroggins III2e0103e2014-04-04 17:05:24 -0400148 center.set(x, y);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800149
150 size_t count = env->GetArrayLength(colorArray);
151 const jint* colorValues = env->GetIntArrayElements(colorArray, NULL);
152
Leon Scroggins III2e0103e2014-04-04 17:05:24 -0400153 AutoJavaFloatArray autoPos(env, posArray, count);
154#ifdef SK_SCALAR_IS_FLOAT
155 SkScalar* pos = autoPos.ptr();
156#else
157 #error Need to convert float array to SkScalar array before calling the following function.
158#endif
Elliott Hughes4cb17532011-04-12 16:10:26 -0700159
Leon Scroggins III2e0103e2014-04-04 17:05:24 -0400160 SkShader* shader = SkGradientShader::CreateRadial(center, radius,
161 reinterpret_cast<const SkColor*>(colorValues), pos, count,
162 static_cast<SkShader::TileMode>(tileMode));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800163 env->ReleaseIntArrayElements(colorArray, const_cast<jint*>(colorValues),
164 JNI_ABORT);
165
166 ThrowIAE_IfNull(env, shader);
Ashok Bhat36bef0b2014-01-20 20:08:01 +0000167 return reinterpret_cast<jlong>(shader);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800168}
169
Ashok Bhat36bef0b2014-01-20 20:08:01 +0000170static jlong RadialGradient_create2(JNIEnv* env, jobject, jfloat x, jfloat y, jfloat radius,
171 jint color0, jint color1, jint tileMode) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800172 SkPoint center;
Leon Scroggins III2e0103e2014-04-04 17:05:24 -0400173 center.set(x, y);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800174
175 SkColor colors[2];
176 colors[0] = color0;
177 colors[1] = color1;
178
Leon Scroggins III2e0103e2014-04-04 17:05:24 -0400179 SkShader* s = SkGradientShader::CreateRadial(center, radius, colors, NULL, 2,
180 (SkShader::TileMode)tileMode);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800181 ThrowIAE_IfNull(env, s);
Ashok Bhat36bef0b2014-01-20 20:08:01 +0000182 return reinterpret_cast<jlong>(s);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800183}
184
185///////////////////////////////////////////////////////////////////////////////
186
Ashok Bhat36bef0b2014-01-20 20:08:01 +0000187static jlong SweepGradient_create1(JNIEnv* env, jobject, jfloat x, jfloat y,
Romain Guyddb80be2010-09-20 19:04:33 -0700188 jintArray jcolors, jfloatArray jpositions) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800189 size_t count = env->GetArrayLength(jcolors);
190 const jint* colors = env->GetIntArrayElements(jcolors, NULL);
Elliott Hughes4cb17532011-04-12 16:10:26 -0700191
Leon Scroggins III2e0103e2014-04-04 17:05:24 -0400192 AutoJavaFloatArray autoPos(env, jpositions, count);
193#ifdef SK_SCALAR_IS_FLOAT
194 SkScalar* pos = autoPos.ptr();
195#else
196 #error Need to convert float array to SkScalar array before calling the following function.
197#endif
Elliott Hughes4cb17532011-04-12 16:10:26 -0700198
Leon Scroggins III2e0103e2014-04-04 17:05:24 -0400199 SkShader* shader = SkGradientShader::CreateSweep(x, y,
200 reinterpret_cast<const SkColor*>(colors), pos, count);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800201 env->ReleaseIntArrayElements(jcolors, const_cast<jint*>(colors),
202 JNI_ABORT);
203 ThrowIAE_IfNull(env, shader);
Ashok Bhat36bef0b2014-01-20 20:08:01 +0000204 return reinterpret_cast<jlong>(shader);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800205}
206
Ashok Bhat36bef0b2014-01-20 20:08:01 +0000207static jlong SweepGradient_create2(JNIEnv* env, jobject, jfloat x, jfloat y,
Romain Guyddb80be2010-09-20 19:04:33 -0700208 int color0, int color1) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800209 SkColor colors[2];
210 colors[0] = color0;
211 colors[1] = color1;
Leon Scroggins III2e0103e2014-04-04 17:05:24 -0400212 SkShader* s = SkGradientShader::CreateSweep(x, y, colors, NULL, 2);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800213 ThrowIAE_IfNull(env, s);
Ashok Bhat36bef0b2014-01-20 20:08:01 +0000214 return reinterpret_cast<jlong>(s);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800215}
216
217///////////////////////////////////////////////////////////////////////////////////////////////
218
Ashok Bhat36bef0b2014-01-20 20:08:01 +0000219static jlong ComposeShader_create1(JNIEnv* env, jobject o,
220 jlong shaderAHandle, jlong shaderBHandle, jlong modeHandle)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800221{
Ashok Bhat36bef0b2014-01-20 20:08:01 +0000222 SkShader* shaderA = reinterpret_cast<SkShader *>(shaderAHandle);
223 SkShader* shaderB = reinterpret_cast<SkShader *>(shaderBHandle);
224 SkXfermode* mode = reinterpret_cast<SkXfermode *>(modeHandle);
225 SkShader* shader = new SkComposeShader(shaderA, shaderB, mode);
226 return reinterpret_cast<jlong>(shader);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800227}
228
Ashok Bhat36bef0b2014-01-20 20:08:01 +0000229static jlong ComposeShader_create2(JNIEnv* env, jobject o,
Chris Craik1526a452015-03-06 18:42:15 +0000230 jlong shaderAHandle, jlong shaderBHandle, jint xfermodeHandle)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800231{
Ashok Bhat36bef0b2014-01-20 20:08:01 +0000232 SkShader* shaderA = reinterpret_cast<SkShader *>(shaderAHandle);
233 SkShader* shaderB = reinterpret_cast<SkShader *>(shaderBHandle);
Chris Craik1526a452015-03-06 18:42:15 +0000234 SkXfermode::Mode mode = static_cast<SkXfermode::Mode>(xfermodeHandle);
235 SkAutoTUnref<SkXfermode> xfermode(SkXfermode::Create(mode));
236 SkShader* shader = new SkComposeShader(shaderA, shaderB, xfermode.get());
Ashok Bhat36bef0b2014-01-20 20:08:01 +0000237 return reinterpret_cast<jlong>(shader);
Romain Guy06f96e22010-07-30 19:18:16 -0700238}
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800239
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800240///////////////////////////////////////////////////////////////////////////////////////////////
241
242static JNINativeMethod gColorMethods[] = {
243 { "nativeRGBToHSV", "(III[F)V", (void*)Color_RGBToHSV },
244 { "nativeHSVToColor", "(I[F)I", (void*)Color_HSVToColor }
245};
246
247static JNINativeMethod gShaderMethods[] = {
John Reck01edef12014-08-22 11:15:37 -0700248 { "nativeDestructor", "(J)V", (void*)Shader_destructor },
Derek Sollenbergerdfba4d32014-09-02 15:42:54 -0400249 { "nativeSetLocalMatrix", "(JJ)J", (void*)Shader_setLocalMatrix }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800250};
251
252static JNINativeMethod gBitmapShaderMethods[] = {
John Reckc294d122015-04-13 15:20:29 -0700253 { "nativeCreate", "(Landroid/graphics/Bitmap;II)J", (void*)BitmapShader_constructor },
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800254};
255
256static JNINativeMethod gLinearGradientMethods[] = {
Ashok Bhat36bef0b2014-01-20 20:08:01 +0000257 { "nativeCreate1", "(FFFF[I[FI)J", (void*)LinearGradient_create1 },
258 { "nativeCreate2", "(FFFFIII)J", (void*)LinearGradient_create2 },
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800259};
260
261static JNINativeMethod gRadialGradientMethods[] = {
Ashok Bhat36bef0b2014-01-20 20:08:01 +0000262 { "nativeCreate1", "(FFF[I[FI)J", (void*)RadialGradient_create1 },
263 { "nativeCreate2", "(FFFIII)J", (void*)RadialGradient_create2 },
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800264};
265
266static JNINativeMethod gSweepGradientMethods[] = {
Ashok Bhat36bef0b2014-01-20 20:08:01 +0000267 { "nativeCreate1", "(FF[I[F)J", (void*)SweepGradient_create1 },
268 { "nativeCreate2", "(FFII)J", (void*)SweepGradient_create2 },
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800269};
270
271static JNINativeMethod gComposeShaderMethods[] = {
Ashok Bhat36bef0b2014-01-20 20:08:01 +0000272 { "nativeCreate1", "(JJJ)J", (void*)ComposeShader_create1 },
273 { "nativeCreate2", "(JJI)J", (void*)ComposeShader_create2 },
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800274};
275
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800276int register_android_graphics_Shader(JNIEnv* env)
277{
Andreas Gampeed6b9df2014-11-20 22:02:20 -0800278 android::RegisterMethodsOrDie(env, "android/graphics/Color", gColorMethods,
279 NELEM(gColorMethods));
280 android::RegisterMethodsOrDie(env, "android/graphics/Shader", gShaderMethods,
281 NELEM(gShaderMethods));
282 android::RegisterMethodsOrDie(env, "android/graphics/BitmapShader", gBitmapShaderMethods,
283 NELEM(gBitmapShaderMethods));
284 android::RegisterMethodsOrDie(env, "android/graphics/LinearGradient", gLinearGradientMethods,
285 NELEM(gLinearGradientMethods));
286 android::RegisterMethodsOrDie(env, "android/graphics/RadialGradient", gRadialGradientMethods,
287 NELEM(gRadialGradientMethods));
288 android::RegisterMethodsOrDie(env, "android/graphics/SweepGradient", gSweepGradientMethods,
289 NELEM(gSweepGradientMethods));
290 android::RegisterMethodsOrDie(env, "android/graphics/ComposeShader", gComposeShaderMethods,
291 NELEM(gComposeShaderMethods));
Elliott Hughes4cb17532011-04-12 16:10:26 -0700292
Andreas Gampeed6b9df2014-11-20 22:02:20 -0800293 return 0;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800294}