Imported GNU Classpath 0.90
[official-gcc.git] / libjava / classpath / native / jni / gtk-peer / gnu_java_awt_peer_gtk_GdkPixbufDecoder.c
blobeba00fb68275417a6cd5ac8704d8152fa74e28a0
1 /* gdkpixbufdecoder.c
2 Copyright (C) 1999, 2003, 2004, 2005, 2006 Free Software Foundation, Inc.
4 This file is part of GNU Classpath.
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.
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.
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.
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.
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. */
38 #include <gtkpeer.h>
39 #include <gdk/gdk.h>
40 #include <gdk-pixbuf/gdk-pixbuf.h>
41 #include <gdk-pixbuf/gdk-pixbuf-loader.h>
43 #include <jni.h>
44 #include <jcl.h>
45 #include "native_state.h"
46 #include "gnu_java_awt_peer_gtk_GdkPixbufDecoder.h"
48 #include <string.h>
49 #include <stdlib.h>
51 static struct state_table *native_pixbufdecoder_state_table;
53 #define NSA_PB_INIT(env, clazz) \
54 native_pixbufdecoder_state_table = cp_gtk_init_state_table (env, clazz)
56 #define NSA_GET_PB_PTR(env, obj) \
57 cp_gtk_get_state (env, obj, native_pixbufdecoder_state_table)
59 #define NSA_SET_PB_PTR(env, obj, ptr) \
60 cp_gtk_set_state (env, obj, native_pixbufdecoder_state_table, (void *)ptr)
62 #define NSA_DEL_PB_PTR(env, obj) \
63 cp_gtk_remove_state_slot (env, obj, native_pixbufdecoder_state_table)
65 /* Union used for type punning. */
66 union env_union
68 void **void_env;
69 JNIEnv **jni_env;
72 static JavaVM *vm;
74 static jmethodID areaPreparedID;
75 static jmethodID areaUpdatedID;
76 static jmethodID dataOutputWriteID;
77 static jmethodID registerFormatID;
79 static void
80 area_prepared_cb (GdkPixbufLoader *loader,
81 jobject *decoder)
83 JNIEnv *env = NULL;
84 union env_union e;
85 jint width = 0;
86 jint height = 0;
87 GdkPixbuf *pixbuf = NULL;
89 pixbuf = gdk_pixbuf_loader_get_pixbuf (loader);
90 g_assert (pixbuf != NULL);
92 width = gdk_pixbuf_get_width (pixbuf);
93 height = gdk_pixbuf_get_height (pixbuf);
95 g_assert (decoder != NULL);
97 e.jni_env = &env;
98 (*vm)->GetEnv (vm, e.void_env, JNI_VERSION_1_1);
100 (*env)->CallVoidMethod (env,
101 *decoder,
102 areaPreparedID,
103 width, height);
106 static void
107 area_updated_cb (GdkPixbufLoader *loader,
108 gint x, gint y,
109 gint width, gint height,
110 jobject *decoder)
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;
119 GdkPixbuf *pixbuf_no_alpha = NULL;
120 GdkPixbuf *pixbuf = NULL;
122 #ifndef WORDS_BIGENDIAN
123 int i;
124 #endif
126 pixbuf_no_alpha = gdk_pixbuf_loader_get_pixbuf (loader);
127 if (pixbuf_no_alpha == NULL)
128 return;
130 pixbuf = gdk_pixbuf_add_alpha(pixbuf_no_alpha, FALSE, 0, 0, 0);
131 g_assert (gdk_pixbuf_get_has_alpha (pixbuf));
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);
139 e.jni_env = &env;
140 (*vm)->GetEnv (vm, e.void_env, JNI_VERSION_1_1);
142 jpixels = (*env)->NewIntArray (env, n_pixels);
144 java_pixels = (*env)->GetIntArrayElements (env, jpixels, NULL);
146 memcpy (java_pixels,
147 gdk_pixels + (y * stride_bytes),
148 (height * stride_bytes));
150 #ifndef WORDS_BIGENDIAN
151 /* convert pixels from 0xBBGGRRAA to 0xAARRGGBB */
152 for (i = 0; i < n_pixels; ++i)
154 java_pixels[i] = SWAPU32 ((unsigned)java_pixels[i]);
156 #endif
158 g_object_unref (pixbuf);
160 (*env)->ReleaseIntArrayElements (env, jpixels, java_pixels, 0);
162 (*env)->CallVoidMethod (env,
163 *decoder,
164 areaUpdatedID,
165 (jint) x, (jint) y,
166 (jint) width, (jint) height,
167 jpixels,
168 stride_pixels);
170 (*env)->DeleteLocalRef(env, jpixels);
173 static void
174 closed_cb (GdkPixbufLoader *loader __attribute__((unused)), jobject *decoder)
176 JNIEnv *env;
177 union env_union e;
178 e.jni_env = &env;
179 (*vm)->GetEnv (vm, e.void_env, JNI_VERSION_1_1);
181 (*env)->DeleteGlobalRef (env, *decoder);
182 g_free (decoder);
187 JNIEXPORT void JNICALL
188 Java_gnu_java_awt_peer_gtk_GdkPixbufDecoder_initState
189 (JNIEnv *env, jobject obj)
191 GdkPixbufLoader *loader = NULL;
192 jobject *decoder = NULL;
194 decoder = (jobject *) g_malloc (sizeof (jobject));
195 g_assert (decoder != NULL);
196 *decoder = (*env)->NewGlobalRef (env, obj);
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);
204 NSA_SET_PB_PTR (env, obj, loader);
207 static void
208 query_formats (JNIEnv *env, jclass clazz)
210 jobject jformat;
211 GSList *formats, *f;
212 GdkPixbufFormat *format;
213 char **ch, *name;
215 jclass formatClass;
216 jmethodID addExtensionID;
217 jmethodID addMimeTypeID;
218 jobject string;
220 formatClass = (*env)->FindClass
221 (env, "gnu/java/awt/peer/gtk/GdkPixbufDecoder$ImageFormatSpec");
223 g_assert(formatClass != NULL);
225 addExtensionID = (*env)->GetMethodID (env, formatClass,
226 "addExtension",
227 "(Ljava/lang/String;)V");
229 addMimeTypeID = (*env)->GetMethodID (env, formatClass,
230 "addMimeType",
231 "(Ljava/lang/String;)V");
233 formats = gdk_pixbuf_get_formats ();
235 for (f = formats; f; f = f->next)
237 format = (GdkPixbufFormat *) f->data;
238 name = gdk_pixbuf_format_get_name(format);
240 string = (*env)->NewStringUTF(env, name);
241 g_assert(string != NULL);
243 jformat = (*env)->CallStaticObjectMethod
244 (env, clazz, registerFormatID, string,
245 (jboolean) gdk_pixbuf_format_is_writable(format));
246 (*env)->DeleteLocalRef(env, string);
248 g_assert(jformat != NULL);
250 ch = gdk_pixbuf_format_get_extensions(format);
251 while (*ch)
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;
260 ch = gdk_pixbuf_format_get_mime_types(format);
261 while (*ch)
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;
270 (*env)->DeleteLocalRef(env, jformat);
273 g_slist_free(formats);
277 JNIEXPORT void JNICALL
278 Java_gnu_java_awt_peer_gtk_GdkPixbufDecoder_initStaticState
279 (JNIEnv *env, jclass clazz)
281 jclass dataOutputClass;
283 (*env)->GetJavaVM(env, &vm);
285 areaPreparedID = (*env)->GetMethodID (env, clazz,
286 "areaPrepared",
287 "(II)V");
289 areaUpdatedID = (*env)->GetMethodID (env, clazz,
290 "areaUpdated",
291 "(IIII[II)V");
293 registerFormatID = (*env)->GetStaticMethodID
294 (env, clazz,
295 "registerFormat",
296 "(Ljava/lang/String;Z)"
297 "Lgnu/java/awt/peer/gtk/GdkPixbufDecoder$ImageFormatSpec;");
300 dataOutputClass = (*env)->FindClass(env, "java/io/DataOutput");
301 dataOutputWriteID = (*env)->GetMethodID (env, dataOutputClass,
302 "write", "([B)V");
304 query_formats (env, clazz);
306 NSA_PB_INIT (env, clazz);
310 JNIEXPORT void JNICALL
311 Java_gnu_java_awt_peer_gtk_GdkPixbufDecoder_finish
312 (JNIEnv *env, jobject obj, jboolean needs_close)
314 GdkPixbufLoader *loader = NULL;
316 loader = (GdkPixbufLoader *)NSA_DEL_PB_PTR (env, obj);
317 if (loader == NULL)
318 return;
320 if (needs_close)
321 gdk_pixbuf_loader_close (loader, NULL);
322 g_object_unref (loader);
325 JNIEXPORT void JNICALL
326 Java_gnu_java_awt_peer_gtk_GdkPixbufDecoder_pumpDone
327 (JNIEnv *env, jobject obj)
329 GError *err = NULL;
330 GdkPixbufLoader *loader = NULL;
332 loader = (GdkPixbufLoader *)NSA_GET_PB_PTR (env, obj);
333 g_assert (loader != NULL);
335 gdk_pixbuf_loader_close (loader, &err);
337 if (err != NULL)
339 JCL_ThrowException (env, "java/io/IOException", err->message);
340 g_error_free (err);
344 struct stream_save_request
346 JNIEnv *env;
347 jobject *stream;
350 static gboolean
351 save_to_stream(const gchar *buf,
352 gsize count,
353 GError **error __attribute__((unused)),
354 gpointer data)
356 struct stream_save_request *ssr = (struct stream_save_request *)data;
358 jbyteArray jbuf;
359 jbyte *cbuf;
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 ();
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);
374 gdk_threads_enter ();
376 return TRUE;
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)
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;
394 ssr.stream = &stream;
395 ssr.env = env;
397 ints = (*env)->GetIntArrayElements (env, jarr, NULL);
398 pix = g_malloc(width * height * (hasAlpha ? 4 : 3));
400 enctype = (*env)->GetStringUTFChars (env, jenctype, NULL);
401 g_assert(enctype != NULL);
403 g_assert (pix != NULL);
404 g_assert (ints != NULL);
406 p = pix;
407 for (i = 0; i < width*height; ++i)
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.
417 a = 0xff & (ints[i] >> 24);
418 r = 0xff & (ints[i] >> 16);
419 g = 0xff & (ints[i] >> 8);
420 b = 0xff & ints[i];
423 * GDK-pixbuf has a very different storage model:
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).
430 *p++ = r;
431 *p++ = g;
432 *p++ = b;
433 if (hasAlpha)
434 *p++ = a;
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);
445 g_assert(gdk_pixbuf_save_to_callback (pixbuf,
446 &save_to_stream,
447 &ssr,
448 enctype,
449 &err, NULL));
451 g_object_unref (pixbuf);
453 g_free(pix);
455 (*env)->ReleaseStringUTFChars (env, jenctype, enctype);
456 (*env)->ReleaseIntArrayElements (env, jarr, ints, 0);
460 JNIEXPORT void JNICALL
461 Java_gnu_java_awt_peer_gtk_GdkPixbufDecoder_pumpBytes
462 (JNIEnv *env, jobject obj, jbyteArray jarr, jint len)
464 GdkPixbufLoader *loader = NULL;
465 jbyte *bytes = NULL;
466 GError *err = NULL;
468 g_assert (len >= 1);
469 g_assert (jarr != NULL);
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);
476 gdk_pixbuf_loader_write (loader, (const guchar *) bytes, len, &err);
478 (*env)->ReleaseByteArrayElements (env, jarr, bytes, 0);
480 if (err != NULL)
482 JCL_ThrowException (env, "java/io/IOException", err->message);
483 g_error_free (err);