]> gcc.gnu.org Git - gcc.git/blob - libjava/classpath/native/jni/gtk-peer/gnu_java_awt_peer_gtk_GdkPixbufDecoder.c
Imported GNU Classpath 0.90
[gcc.git] / libjava / classpath / native / jni / gtk-peer / gnu_java_awt_peer_gtk_GdkPixbufDecoder.c
1 /* gdkpixbufdecoder.c
2 Copyright (C) 1999, 2003, 2004, 2005, 2006 Free Software Foundation, Inc.
3
4 This file is part of GNU Classpath.
5
6 GNU Classpath is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 2, or (at your option)
9 any later version.
10
11 GNU Classpath is distributed in the hope that it will be useful, but
12 WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 General Public License for more details.
15
16 You should have received a copy of the GNU General Public License
17 along with GNU Classpath; see the file COPYING. If not, write to the
18 Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
19 02110-1301 USA.
20
21 Linking this library statically or dynamically with other modules is
22 making a combined work based on this library. Thus, the terms and
23 conditions of the GNU General Public License cover the whole
24 combination.
25
26 As a special exception, the copyright holders of this library give you
27 permission to link this library with independent modules to produce an
28 executable, regardless of the license terms of these independent
29 modules, and to copy and distribute the resulting executable under
30 terms of your choice, provided that you also meet, for each linked
31 independent module, the terms and conditions of the license of that
32 module. An independent module is a module which is not derived from
33 or based on this library. If you modify this library, you may extend
34 this exception to your version of the library, but you are not
35 obligated to do so. If you do not wish to do so, delete this
36 exception statement from your version. */
37
38 #include <gtkpeer.h>
39 #include <gdk/gdk.h>
40 #include <gdk-pixbuf/gdk-pixbuf.h>
41 #include <gdk-pixbuf/gdk-pixbuf-loader.h>
42
43 #include <jni.h>
44 #include <jcl.h>
45 #include "native_state.h"
46 #include "gnu_java_awt_peer_gtk_GdkPixbufDecoder.h"
47
48 #include <string.h>
49 #include <stdlib.h>
50
51 static struct state_table *native_pixbufdecoder_state_table;
52
53 #define NSA_PB_INIT(env, clazz) \
54 native_pixbufdecoder_state_table = cp_gtk_init_state_table (env, clazz)
55
56 #define NSA_GET_PB_PTR(env, obj) \
57 cp_gtk_get_state (env, obj, native_pixbufdecoder_state_table)
58
59 #define NSA_SET_PB_PTR(env, obj, ptr) \
60 cp_gtk_set_state (env, obj, native_pixbufdecoder_state_table, (void *)ptr)
61
62 #define NSA_DEL_PB_PTR(env, obj) \
63 cp_gtk_remove_state_slot (env, obj, native_pixbufdecoder_state_table)
64
65 /* Union used for type punning. */
66 union env_union
67 {
68 void **void_env;
69 JNIEnv **jni_env;
70 };
71
72 static JavaVM *vm;
73
74 static jmethodID areaPreparedID;
75 static jmethodID areaUpdatedID;
76 static jmethodID dataOutputWriteID;
77 static jmethodID registerFormatID;
78
79 static void
80 area_prepared_cb (GdkPixbufLoader *loader,
81 jobject *decoder)
82 {
83 JNIEnv *env = NULL;
84 union env_union e;
85 jint width = 0;
86 jint height = 0;
87 GdkPixbuf *pixbuf = NULL;
88
89 pixbuf = gdk_pixbuf_loader_get_pixbuf (loader);
90 g_assert (pixbuf != NULL);
91
92 width = gdk_pixbuf_get_width (pixbuf);
93 height = gdk_pixbuf_get_height (pixbuf);
94
95 g_assert (decoder != NULL);
96
97 e.jni_env = &env;
98 (*vm)->GetEnv (vm, e.void_env, JNI_VERSION_1_1);
99
100 (*env)->CallVoidMethod (env,
101 *decoder,
102 areaPreparedID,
103 width, height);
104 }
105
106 static void
107 area_updated_cb (GdkPixbufLoader *loader,
108 gint x, gint y,
109 gint width, gint height,
110 jobject *decoder)
111 {
112 JNIEnv *env;
113 union env_union e;
114 jint stride_bytes, stride_pixels, n_channels, n_pixels;
115 jintArray jpixels;
116 jint *java_pixels;
117 guchar *gdk_pixels;
118
119 GdkPixbuf *pixbuf_no_alpha = NULL;
120 GdkPixbuf *pixbuf = NULL;
121
122 #ifndef WORDS_BIGENDIAN
123 int i;
124 #endif
125
126 pixbuf_no_alpha = gdk_pixbuf_loader_get_pixbuf (loader);
127 if (pixbuf_no_alpha == NULL)
128 return;
129
130 pixbuf = gdk_pixbuf_add_alpha(pixbuf_no_alpha, FALSE, 0, 0, 0);
131 g_assert (gdk_pixbuf_get_has_alpha (pixbuf));
132
133 stride_bytes = gdk_pixbuf_get_rowstride (pixbuf);
134 n_channels = gdk_pixbuf_get_n_channels (pixbuf);
135 stride_pixels = stride_bytes / n_channels;
136 n_pixels = height * stride_pixels;
137 gdk_pixels = gdk_pixbuf_get_pixels (pixbuf);
138
139 e.jni_env = &env;
140 (*vm)->GetEnv (vm, e.void_env, JNI_VERSION_1_1);
141
142 jpixels = (*env)->NewIntArray (env, n_pixels);
143
144 java_pixels = (*env)->GetIntArrayElements (env, jpixels, NULL);
145
146 memcpy (java_pixels,
147 gdk_pixels + (y * stride_bytes),
148 (height * stride_bytes));
149
150 #ifndef WORDS_BIGENDIAN
151 /* convert pixels from 0xBBGGRRAA to 0xAARRGGBB */
152 for (i = 0; i < n_pixels; ++i)
153 {
154 java_pixels[i] = SWAPU32 ((unsigned)java_pixels[i]);
155 }
156 #endif
157
158 g_object_unref (pixbuf);
159
160 (*env)->ReleaseIntArrayElements (env, jpixels, java_pixels, 0);
161
162 (*env)->CallVoidMethod (env,
163 *decoder,
164 areaUpdatedID,
165 (jint) x, (jint) y,
166 (jint) width, (jint) height,
167 jpixels,
168 stride_pixels);
169
170 (*env)->DeleteLocalRef(env, jpixels);
171 }
172
173 static void
174 closed_cb (GdkPixbufLoader *loader __attribute__((unused)), jobject *decoder)
175 {
176 JNIEnv *env;
177 union env_union e;
178 e.jni_env = &env;
179 (*vm)->GetEnv (vm, e.void_env, JNI_VERSION_1_1);
180
181 (*env)->DeleteGlobalRef (env, *decoder);
182 g_free (decoder);
183 }
184
185
186
187 JNIEXPORT void JNICALL
188 Java_gnu_java_awt_peer_gtk_GdkPixbufDecoder_initState
189 (JNIEnv *env, jobject obj)
190 {
191 GdkPixbufLoader *loader = NULL;
192 jobject *decoder = NULL;
193
194 decoder = (jobject *) g_malloc (sizeof (jobject));
195 g_assert (decoder != NULL);
196 *decoder = (*env)->NewGlobalRef (env, obj);
197
198 loader = gdk_pixbuf_loader_new ();
199 g_assert (loader != NULL);
200 g_signal_connect (loader, "area-prepared", G_CALLBACK (area_prepared_cb), decoder);
201 g_signal_connect (loader, "area-updated", G_CALLBACK (area_updated_cb), decoder);
202 g_signal_connect (loader, "closed", G_CALLBACK (closed_cb), decoder);
203
204 NSA_SET_PB_PTR (env, obj, loader);
205 }
206
207 static void
208 query_formats (JNIEnv *env, jclass clazz)
209 {
210 jobject jformat;
211 GSList *formats, *f;
212 GdkPixbufFormat *format;
213 char **ch, *name;
214
215 jclass formatClass;
216 jmethodID addExtensionID;
217 jmethodID addMimeTypeID;
218 jobject string;
219
220 formatClass = (*env)->FindClass
221 (env, "gnu/java/awt/peer/gtk/GdkPixbufDecoder$ImageFormatSpec");
222
223 g_assert(formatClass != NULL);
224
225 addExtensionID = (*env)->GetMethodID (env, formatClass,
226 "addExtension",
227 "(Ljava/lang/String;)V");
228
229 addMimeTypeID = (*env)->GetMethodID (env, formatClass,
230 "addMimeType",
231 "(Ljava/lang/String;)V");
232
233 formats = gdk_pixbuf_get_formats ();
234
235 for (f = formats; f; f = f->next)
236 {
237 format = (GdkPixbufFormat *) f->data;
238 name = gdk_pixbuf_format_get_name(format);
239
240 string = (*env)->NewStringUTF(env, name);
241 g_assert(string != NULL);
242
243 jformat = (*env)->CallStaticObjectMethod
244 (env, clazz, registerFormatID, string,
245 (jboolean) gdk_pixbuf_format_is_writable(format));
246 (*env)->DeleteLocalRef(env, string);
247
248 g_assert(jformat != NULL);
249
250 ch = gdk_pixbuf_format_get_extensions(format);
251 while (*ch)
252 {
253 string = (*env)->NewStringUTF(env, *ch);
254 g_assert(string != NULL);
255 (*env)->CallVoidMethod (env, jformat, addExtensionID, string);
256 (*env)->DeleteLocalRef(env, string);
257 ++ch;
258 }
259
260 ch = gdk_pixbuf_format_get_mime_types(format);
261 while (*ch)
262 {
263 string = (*env)->NewStringUTF(env, *ch);
264 g_assert(string != NULL);
265 (*env)->CallVoidMethod (env, jformat, addMimeTypeID, string);
266 (*env)->DeleteLocalRef(env, string);
267 ++ch;
268 }
269
270 (*env)->DeleteLocalRef(env, jformat);
271 }
272
273 g_slist_free(formats);
274 }
275
276
277 JNIEXPORT void JNICALL
278 Java_gnu_java_awt_peer_gtk_GdkPixbufDecoder_initStaticState
279 (JNIEnv *env, jclass clazz)
280 {
281 jclass dataOutputClass;
282
283 (*env)->GetJavaVM(env, &vm);
284
285 areaPreparedID = (*env)->GetMethodID (env, clazz,
286 "areaPrepared",
287 "(II)V");
288
289 areaUpdatedID = (*env)->GetMethodID (env, clazz,
290 "areaUpdated",
291 "(IIII[II)V");
292
293 registerFormatID = (*env)->GetStaticMethodID
294 (env, clazz,
295 "registerFormat",
296 "(Ljava/lang/String;Z)"
297 "Lgnu/java/awt/peer/gtk/GdkPixbufDecoder$ImageFormatSpec;");
298
299
300 dataOutputClass = (*env)->FindClass(env, "java/io/DataOutput");
301 dataOutputWriteID = (*env)->GetMethodID (env, dataOutputClass,
302 "write", "([B)V");
303
304 query_formats (env, clazz);
305
306 NSA_PB_INIT (env, clazz);
307 }
308
309
310 JNIEXPORT void JNICALL
311 Java_gnu_java_awt_peer_gtk_GdkPixbufDecoder_finish
312 (JNIEnv *env, jobject obj, jboolean needs_close)
313 {
314 GdkPixbufLoader *loader = NULL;
315
316 loader = (GdkPixbufLoader *)NSA_DEL_PB_PTR (env, obj);
317 if (loader == NULL)
318 return;
319
320 if (needs_close)
321 gdk_pixbuf_loader_close (loader, NULL);
322 g_object_unref (loader);
323 }
324
325 JNIEXPORT void JNICALL
326 Java_gnu_java_awt_peer_gtk_GdkPixbufDecoder_pumpDone
327 (JNIEnv *env, jobject obj)
328 {
329 GError *err = NULL;
330 GdkPixbufLoader *loader = NULL;
331
332 loader = (GdkPixbufLoader *)NSA_GET_PB_PTR (env, obj);
333 g_assert (loader != NULL);
334
335 gdk_pixbuf_loader_close (loader, &err);
336
337 if (err != NULL)
338 {
339 JCL_ThrowException (env, "java/io/IOException", err->message);
340 g_error_free (err);
341 }
342 }
343
344 struct stream_save_request
345 {
346 JNIEnv *env;
347 jobject *stream;
348 };
349
350 static gboolean
351 save_to_stream(const gchar *buf,
352 gsize count,
353 GError **error __attribute__((unused)),
354 gpointer data)
355 {
356 struct stream_save_request *ssr = (struct stream_save_request *)data;
357
358 jbyteArray jbuf;
359 jbyte *cbuf;
360
361 /* FIXME. Don't call user code directly on this thread.
362 Store bytes and signal a "pump" thread to deliver to user code.
363 Then we don't have to drop/acquire any locks. */
364 gdk_threads_leave ();
365
366 jbuf = (*(ssr->env))->NewByteArray ((ssr->env), count);
367 cbuf = (*(ssr->env))->GetByteArrayElements ((ssr->env), jbuf, NULL);
368 memcpy (cbuf, buf, count);
369 (*(ssr->env))->ReleaseByteArrayElements ((ssr->env), jbuf, cbuf, 0);
370 (*(ssr->env))->CallVoidMethod ((ssr->env), *(ssr->stream),
371 dataOutputWriteID, jbuf);
372 (*(ssr->env))->DeleteLocalRef((ssr->env), jbuf);
373
374 gdk_threads_enter ();
375
376 return TRUE;
377 }
378
379
380 JNIEXPORT void JNICALL
381 Java_gnu_java_awt_peer_gtk_GdkPixbufDecoder_streamImage
382 (JNIEnv *env, jclass clazz __attribute__((unused)),
383 jintArray jarr, jstring jenctype, jint width, jint height,
384 jboolean hasAlpha, jobject stream)
385 {
386 GdkPixbuf* pixbuf;
387 jint *ints;
388 guchar a, r, g, b, *pix, *p;
389 GError *err = NULL;
390 const char *enctype;
391 int i;
392 struct stream_save_request ssr;
393
394 ssr.stream = &stream;
395 ssr.env = env;
396
397 ints = (*env)->GetIntArrayElements (env, jarr, NULL);
398 pix = g_malloc(width * height * (hasAlpha ? 4 : 3));
399
400 enctype = (*env)->GetStringUTFChars (env, jenctype, NULL);
401 g_assert(enctype != NULL);
402
403 g_assert (pix != NULL);
404 g_assert (ints != NULL);
405
406 p = pix;
407 for (i = 0; i < width*height; ++i)
408 {
409 /*
410 * Java encodes pixels as integers in a predictable arithmetic order:
411 * 0xAARRGGBB. Since these are jints, JNI has already byte-swapped
412 * them for us if necessary, so they're in "our" endianness, whatever
413 * that is. It uses 4 bytes per pixel whether or not there's an alpha
414 * channel.
415 */
416
417 a = 0xff & (ints[i] >> 24);
418 r = 0xff & (ints[i] >> 16);
419 g = 0xff & (ints[i] >> 8);
420 b = 0xff & ints[i];
421
422 /*
423 * GDK-pixbuf has a very different storage model:
424 *
425 * - A different alpha order (alpha after colors).
426 * - A different packing model (no alpha -> 3-bytes-per-pixel).
427 * - A different "RGB" order (host memory order, not endian-neutral).
428 */
429
430 *p++ = r;
431 *p++ = g;
432 *p++ = b;
433 if (hasAlpha)
434 *p++ = a;
435 }
436
437 pixbuf = gdk_pixbuf_new_from_data (pix,
438 GDK_COLORSPACE_RGB,
439 (gboolean) hasAlpha,
440 8, width, height,
441 width * (hasAlpha ? 4 : 3), /* rowstride */
442 NULL, NULL);
443 g_assert (pixbuf != NULL);
444
445 g_assert(gdk_pixbuf_save_to_callback (pixbuf,
446 &save_to_stream,
447 &ssr,
448 enctype,
449 &err, NULL));
450
451 g_object_unref (pixbuf);
452
453 g_free(pix);
454
455 (*env)->ReleaseStringUTFChars (env, jenctype, enctype);
456 (*env)->ReleaseIntArrayElements (env, jarr, ints, 0);
457 }
458
459
460 JNIEXPORT void JNICALL
461 Java_gnu_java_awt_peer_gtk_GdkPixbufDecoder_pumpBytes
462 (JNIEnv *env, jobject obj, jbyteArray jarr, jint len)
463 {
464 GdkPixbufLoader *loader = NULL;
465 jbyte *bytes = NULL;
466 GError *err = NULL;
467
468 g_assert (len >= 1);
469 g_assert (jarr != NULL);
470
471 bytes = (*env)->GetByteArrayElements (env, jarr, NULL);
472 g_assert (bytes != NULL);
473 loader = (GdkPixbufLoader *)NSA_GET_PB_PTR (env, obj);
474 g_assert (loader != NULL);
475
476 gdk_pixbuf_loader_write (loader, (const guchar *) bytes, len, &err);
477
478 (*env)->ReleaseByteArrayElements (env, jarr, bytes, 0);
479
480 if (err != NULL)
481 {
482 JCL_ThrowException (env, "java/io/IOException", err->message);
483 g_error_free (err);
484 }
485 }
This page took 0.057521 seconds and 5 git commands to generate.