Merge from mainline (gomp-merge-2005-02-26).
[official-gcc.git] / libjava / jni / gtk-peer / gnu_java_awt_peer_gtk_GdkPixbufDecoder.c
blob0727999df196af8845a3e158c5b5cc9d4ee98491
1 /* gdkpixbufdecoder.c
2 Copyright (C) 1999, 2003, 2004 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., 59 Temple Place, Suite 330, Boston, MA
19 02111-1307 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 "native_state.h"
45 #include "gnu_java_awt_peer_gtk_GdkPixbufDecoder.h"
47 #include <string.h>
48 #include <stdlib.h>
50 struct state_table *native_pixbufdecoder_state_table;
52 /* Union used for type punning. */
53 union env_union
55 void **void_env;
56 JNIEnv **jni_env;
59 static JavaVM *vm;
61 static jmethodID areaPreparedID;
62 static jmethodID areaUpdatedID;
63 static jmethodID dataOutputWriteID;
64 static jmethodID registerFormatID;
66 static void
67 area_prepared (GdkPixbufLoader *loader,
68 jobject *decoder)
70 JNIEnv *env;
71 union env_union e;
72 jint width, height;
74 GdkPixbuf *pixbuf = gdk_pixbuf_loader_get_pixbuf (loader);
75 if (pixbuf == NULL)
76 return;
78 width = gdk_pixbuf_get_width (pixbuf);
79 height = gdk_pixbuf_get_height (pixbuf);
81 gdk_threads_leave ();
83 g_assert (decoder != NULL);
85 e.jni_env = &env;
86 (*vm)->GetEnv (vm, e.void_env, JNI_VERSION_1_1);
87 (*env)->CallVoidMethod (env,
88 *decoder,
89 areaPreparedID,
90 width, height);
92 gdk_threads_enter ();
95 static void
96 area_updated (GdkPixbufLoader *loader,
97 gint x, gint y,
98 gint width, gint height,
99 jobject *decoder)
101 JNIEnv *env;
102 union env_union e;
103 jint stride_bytes, stride_pixels, n_channels, n_pixels;
104 jintArray jpixels;
105 jint *java_pixels;
106 guchar *gdk_pixels;
108 GdkPixbuf *pixbuf_no_alpha = NULL;
109 GdkPixbuf *pixbuf = NULL;
111 #ifndef WORDS_BIGENDIAN
112 int i;
113 #endif
115 pixbuf_no_alpha = gdk_pixbuf_loader_get_pixbuf (loader);
116 if (pixbuf_no_alpha == NULL)
117 return;
119 pixbuf = gdk_pixbuf_add_alpha(pixbuf_no_alpha, FALSE, 0, 0, 0);
120 g_assert (gdk_pixbuf_get_has_alpha (pixbuf));
122 stride_bytes = gdk_pixbuf_get_rowstride (pixbuf);
123 n_channels = gdk_pixbuf_get_n_channels (pixbuf);
124 stride_pixels = stride_bytes / n_channels;
125 n_pixels = height * stride_pixels;
126 gdk_pixels = gdk_pixbuf_get_pixels (pixbuf);
128 e.jni_env = &env;
129 (*vm)->GetEnv (vm, e.void_env, JNI_VERSION_1_1);
130 jpixels = (*env)->NewIntArray (env, n_pixels);
131 java_pixels = (*env)->GetIntArrayElements (env, jpixels, NULL);
133 memcpy (java_pixels,
134 gdk_pixels + (y * stride_bytes),
135 (height * stride_bytes));
137 #ifndef WORDS_BIGENDIAN
138 /* convert pixels from 0xBBGGRRAA to 0xAARRGGBB */
139 for (i = 0; i < n_pixels; ++i)
141 java_pixels[i] = SWAPU32 ((unsigned)java_pixels[i]);
143 #endif
145 g_object_unref (pixbuf);
147 gdk_threads_leave ();
149 (*env)->ReleaseIntArrayElements (env, jpixels, java_pixels, 0);
150 (*env)->CallVoidMethod (env,
151 *decoder,
152 areaUpdatedID,
153 (jint) x, (jint) y,
154 (jint) width, (jint) height,
155 jpixels,
156 stride_pixels);
157 gdk_threads_enter ();
160 static void
161 closed (GdkPixbufLoader *loader __attribute__((unused)), jobject *decoder)
163 JNIEnv *env;
164 union env_union e;
165 e.jni_env = &env;
166 (*vm)->GetEnv (vm, e.void_env, JNI_VERSION_1_1);
168 gdk_threads_leave ();
169 (*env)->DeleteGlobalRef (env, *decoder);
170 free (decoder);
171 gdk_threads_enter ();
176 JNIEXPORT void JNICALL
177 Java_gnu_java_awt_peer_gtk_GdkPixbufDecoder_initState
178 (JNIEnv *env, jobject obj)
180 GdkPixbufLoader *loader = NULL;
181 jobject *decoder = NULL;
183 decoder = (jobject *) malloc (sizeof (jobject));
184 g_assert (decoder != NULL);
185 *decoder = (*env)->NewGlobalRef (env, obj);
187 gdk_threads_enter ();
188 loader = gdk_pixbuf_loader_new ();
189 g_assert (loader != NULL);
190 g_signal_connect (loader, "area-prepared", G_CALLBACK (area_prepared), decoder);
191 g_signal_connect (loader, "area-updated", G_CALLBACK (area_updated), decoder);
192 g_signal_connect (loader, "closed", G_CALLBACK (closed), decoder);
193 gdk_threads_leave ();
195 NSA_SET_PB_PTR (env, obj, loader);
198 static void
199 query_formats (JNIEnv *env, jclass clazz)
201 jobject jformat;
202 GSList *formats, *f;
203 GdkPixbufFormat *format;
204 char **ch, *name;
206 jclass formatClass;
207 jmethodID addExtensionID;
208 jmethodID addMimeTypeID;
210 formatClass = (*env)->FindClass
211 (env, "gnu/java/awt/peer/gtk/GdkPixbufDecoder$ImageFormatSpec");
213 g_assert(formatClass != NULL);
215 addExtensionID = (*env)->GetMethodID (env, formatClass,
216 "addExtension",
217 "(Ljava/lang/String;)V");
219 addMimeTypeID = (*env)->GetMethodID (env, formatClass,
220 "addMimeType",
221 "(Ljava/lang/String;)V");
223 formats = gdk_pixbuf_get_formats ();
225 for (f = formats; f; f = f->next)
227 format = (GdkPixbufFormat *) f->data;
228 name = gdk_pixbuf_format_get_name(format);
230 jformat = (*env)->CallStaticObjectMethod
231 (env, clazz, registerFormatID,
232 (*env)->NewStringUTF(env, name),
233 (jboolean) gdk_pixbuf_format_is_writable(format));
235 g_assert(jformat != NULL);
237 ch = gdk_pixbuf_format_get_extensions(format);
238 while (*ch)
240 (*env)->CallVoidMethod (env, jformat, addExtensionID,
241 (*env)->NewStringUTF(env, *ch));
242 ++ch;
245 ch = gdk_pixbuf_format_get_mime_types(format);
246 while (*ch)
248 (*env)->CallVoidMethod (env, jformat, addMimeTypeID,
249 (*env)->NewStringUTF(env, *ch));
250 ++ch;
254 g_slist_free(formats);
258 JNIEXPORT void JNICALL
259 Java_gnu_java_awt_peer_gtk_GdkPixbufDecoder_initStaticState
260 (JNIEnv *env, jclass clazz)
262 jclass dataOutputClass;
264 (*env)->GetJavaVM(env, &vm);
266 areaPreparedID = (*env)->GetMethodID (env, clazz,
267 "areaPrepared",
268 "(II)V");
270 areaUpdatedID = (*env)->GetMethodID (env, clazz,
271 "areaUpdated",
272 "(IIII[II)V");
274 registerFormatID = (*env)->GetStaticMethodID
275 (env, clazz,
276 "registerFormat",
277 "(Ljava/lang/String;Z)"
278 "Lgnu/java/awt/peer/gtk/GdkPixbufDecoder$ImageFormatSpec;");
281 dataOutputClass = (*env)->FindClass(env, "java/io/DataOutput");
282 dataOutputWriteID = (*env)->GetMethodID (env, dataOutputClass,
283 "write", "([B)V");
285 query_formats (env, clazz);
287 NSA_PB_INIT (env, clazz);
291 JNIEXPORT void JNICALL
292 Java_gnu_java_awt_peer_gtk_GdkPixbufDecoder_finish
293 (JNIEnv *env, jobject obj)
295 GdkPixbufLoader *loader = NULL;
297 loader = (GdkPixbufLoader *)NSA_DEL_PB_PTR (env, obj);
298 if (loader == NULL)
299 return;
301 gdk_threads_enter ();
302 gdk_pixbuf_loader_close (loader, NULL);
303 g_object_unref (loader);
304 gdk_threads_leave ();
307 struct stream_save_request
309 JNIEnv *env;
310 jobject *stream;
313 static gboolean
314 save_to_stream(const gchar *buf,
315 gsize count,
316 GError **error __attribute__((unused)),
317 gpointer data)
319 struct stream_save_request *ssr = (struct stream_save_request *)data;
321 jbyteArray jbuf;
322 jbyte *cbuf;
324 gdk_threads_leave ();
325 jbuf = (*(ssr->env))->NewByteArray ((ssr->env), count);
326 cbuf = (*(ssr->env))->GetByteArrayElements ((ssr->env), jbuf, NULL);
327 memcpy (cbuf, buf, count);
328 (*(ssr->env))->ReleaseByteArrayElements ((ssr->env), jbuf, cbuf, 0);
329 (*(ssr->env))->CallVoidMethod ((ssr->env), *(ssr->stream),
330 dataOutputWriteID, jbuf);
331 gdk_threads_enter ();
332 return TRUE;
336 JNIEXPORT void JNICALL
337 Java_gnu_java_awt_peer_gtk_GdkPixbufDecoder_streamImage
338 (JNIEnv *env, jclass clazz __attribute__((unused)),
339 jintArray jarr, jstring jenctype, jint width, jint height,
340 jboolean hasAlpha, jobject stream)
342 GdkPixbuf* pixbuf;
343 jint *ints;
344 guchar a, r, g, b, *pix, *p;
345 GError *err = NULL;
346 const char *enctype;
347 int i;
349 struct stream_save_request ssr;
350 ssr.stream = &stream;
351 ssr.env = env;
353 ints = (*env)->GetIntArrayElements (env, jarr, NULL);
354 pix = g_malloc(width * height * (hasAlpha ? 4 : 3));
356 enctype = (*env)->GetStringUTFChars (env, jenctype, NULL);
357 g_assert(enctype != NULL);
359 g_assert (pix != NULL);
360 g_assert (ints != NULL);
362 p = pix;
363 for (i = 0; i < width*height; ++i)
366 * Java encodes pixels as integers in a predictable arithmetic order:
367 * 0xAARRGGBB. Since these are jints, JNI has already byte-swapped
368 * them for us if necessary, so they're in "our" endianness, whatever
369 * that is. It uses 4 bytes per pixel whether or not there's an alpha
370 * channel.
373 a = 0xff & (ints[i] >> 24);
374 r = 0xff & (ints[i] >> 16);
375 g = 0xff & (ints[i] >> 8);
376 b = 0xff & ints[i];
379 * GDK-pixbuf has a very different storage model:
381 * - A different alpha order (alpha after colors).
382 * - A different packing model (no alpha -> 3-bytes-per-pixel).
383 * - A different "RGB" order (host memory order, not endian-neutral).
386 *p++ = r;
387 *p++ = g;
388 *p++ = b;
389 if (hasAlpha)
390 *p++ = a;
393 gdk_threads_enter ();
394 pixbuf = gdk_pixbuf_new_from_data (pix,
395 GDK_COLORSPACE_RGB,
396 (gboolean) hasAlpha,
397 8, width, height,
398 width * (hasAlpha ? 4 : 3), /* rowstride */
399 NULL, NULL);
400 g_assert (pixbuf != NULL);
402 g_assert(gdk_pixbuf_save_to_callback (pixbuf,
403 &save_to_stream,
404 &ssr,
405 enctype,
406 &err, NULL));
408 g_object_unref (pixbuf);
410 gdk_threads_leave ();
411 g_free(pix);
413 (*env)->ReleaseStringUTFChars (env, jenctype, enctype);
414 (*env)->ReleaseIntArrayElements (env, jarr, ints, 0);
417 JNIEXPORT void JNICALL
418 Java_gnu_java_awt_peer_gtk_GdkPixbufDecoder_pumpBytes
419 (JNIEnv *env, jobject obj, jbyteArray jarr, jint len)
421 GdkPixbufLoader *loader = NULL;
422 jbyte *bytes = NULL;
424 if (len < 1)
425 return;
427 bytes = (*env)->GetByteArrayElements (env, jarr, NULL);
428 g_assert (bytes != NULL);
429 loader = (GdkPixbufLoader *)NSA_GET_PB_PTR (env, obj);
430 g_assert (loader != NULL);
432 gdk_threads_enter ();
433 gdk_pixbuf_loader_write (loader, (const guchar *) bytes, len, NULL);
434 gdk_threads_leave ();
436 (*env)->ReleaseByteArrayElements (env, jarr, bytes, 0);