Merged with mainline at revision 128810.
[official-gcc.git] / libjava / classpath / native / jni / gtk-peer / gnu_java_awt_peer_gtk_GdkPixbufDecoder.c
blob5ed39521aca25b7270310ba3269f864d52d7e15f
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 "gnu_java_awt_peer_gtk_GdkPixbufDecoder.h"
47 #include <string.h>
48 #include <stdlib.h>
50 /* Union used for type punning. */
51 union env_union
53 void **void_env;
54 JNIEnv **jni_env;
57 static JavaVM *vm;
59 static jmethodID areaPreparedID;
60 static jmethodID areaUpdatedID;
61 static jmethodID dataOutputWriteID;
62 static jmethodID registerFormatID;
64 static void
65 area_prepared_cb (GdkPixbufLoader *loader,
66 jobject *decoder)
68 JNIEnv *env = NULL;
69 union env_union e;
70 jint width = 0;
71 jint height = 0;
72 GdkPixbuf *pixbuf = NULL;
74 pixbuf = gdk_pixbuf_loader_get_pixbuf (loader);
75 g_assert (pixbuf != NULL);
77 width = gdk_pixbuf_get_width (pixbuf);
78 height = gdk_pixbuf_get_height (pixbuf);
80 g_assert (decoder != NULL);
82 e.jni_env = &env;
83 (*vm)->GetEnv (vm, e.void_env, JNI_VERSION_1_1);
85 (*env)->CallVoidMethod (env,
86 *decoder,
87 areaPreparedID,
88 width, height);
91 static void
92 area_updated_cb (GdkPixbufLoader *loader,
93 gint x, gint y,
94 gint width, gint height,
95 jobject *decoder)
97 JNIEnv *env;
98 union env_union e;
99 jint stride_bytes, stride_pixels, n_channels, n_pixels;
100 jintArray jpixels;
101 jint *java_pixels;
102 guchar *gdk_pixels;
104 GdkPixbuf *pixbuf_no_alpha = NULL;
105 GdkPixbuf *pixbuf = NULL;
107 #ifndef WORDS_BIGENDIAN
108 int i;
109 #endif
111 pixbuf_no_alpha = gdk_pixbuf_loader_get_pixbuf (loader);
112 if (pixbuf_no_alpha == NULL)
113 return;
115 pixbuf = gdk_pixbuf_add_alpha(pixbuf_no_alpha, FALSE, 0, 0, 0);
116 g_assert (gdk_pixbuf_get_has_alpha (pixbuf));
118 stride_bytes = gdk_pixbuf_get_rowstride (pixbuf);
119 n_channels = gdk_pixbuf_get_n_channels (pixbuf);
120 stride_pixels = stride_bytes / n_channels;
121 n_pixels = height * stride_pixels;
122 gdk_pixels = gdk_pixbuf_get_pixels (pixbuf);
124 e.jni_env = &env;
125 (*vm)->GetEnv (vm, e.void_env, JNI_VERSION_1_1);
127 jpixels = (*env)->NewIntArray (env, n_pixels);
129 java_pixels = (*env)->GetIntArrayElements (env, jpixels, NULL);
131 memcpy (java_pixels,
132 gdk_pixels + (y * stride_bytes),
133 (height * stride_bytes));
135 #ifndef WORDS_BIGENDIAN
136 /* convert pixels from 0xBBGGRRAA to 0xAARRGGBB */
137 for (i = 0; i < n_pixels; ++i)
139 java_pixels[i] = SWAPU32 ((unsigned)java_pixels[i]);
141 #endif
143 g_object_unref (pixbuf);
145 (*env)->ReleaseIntArrayElements (env, jpixels, java_pixels, 0);
147 (*env)->CallVoidMethod (env,
148 *decoder,
149 areaUpdatedID,
150 (jint) x, (jint) y,
151 (jint) width, (jint) height,
152 jpixels,
153 stride_pixels);
155 (*env)->DeleteLocalRef(env, jpixels);
158 static void
159 closed_cb (GdkPixbufLoader *loader __attribute__((unused)), jobject *decoder)
161 JNIEnv *env;
162 union env_union e;
163 e.jni_env = &env;
164 (*vm)->GetEnv (vm, e.void_env, JNI_VERSION_1_1);
166 (*env)->DeleteGlobalRef (env, *decoder);
167 g_free (decoder);
172 JNIEXPORT void JNICALL
173 Java_gnu_java_awt_peer_gtk_GdkPixbufDecoder_initState
174 (JNIEnv *env, jobject obj)
176 GdkPixbufLoader *loader = NULL;
177 jobject *decoder = NULL;
179 decoder = (jobject *) g_malloc (sizeof (jobject));
180 g_assert (decoder != NULL);
181 *decoder = (*env)->NewGlobalRef (env, obj);
183 loader = gdk_pixbuf_loader_new ();
184 g_assert (loader != NULL);
185 g_signal_connect (loader, "area-prepared", G_CALLBACK (area_prepared_cb), decoder);
186 g_signal_connect (loader, "area-updated", G_CALLBACK (area_updated_cb), decoder);
187 g_signal_connect (loader, "closed", G_CALLBACK (closed_cb), decoder);
189 gtkpeer_set_pixbuf_loader (env, obj, loader);
192 static void
193 query_formats (JNIEnv *env, jclass clazz)
195 jobject jformat;
196 GSList *formats, *f;
197 GdkPixbufFormat *format;
198 gchar **ch, *name;
199 gint count;
201 jclass formatClass;
202 jmethodID addExtensionID;
203 jmethodID addMimeTypeID;
204 jobject string;
206 formatClass = (*env)->FindClass
207 (env, "gnu/java/awt/peer/gtk/GdkPixbufDecoder$ImageFormatSpec");
209 g_assert(formatClass != NULL);
211 addExtensionID = (*env)->GetMethodID (env, formatClass,
212 "addExtension",
213 "(Ljava/lang/String;)V");
215 addMimeTypeID = (*env)->GetMethodID (env, formatClass,
216 "addMimeType",
217 "(Ljava/lang/String;)V");
219 formats = gdk_pixbuf_get_formats ();
221 for (f = formats; f; f = f->next)
223 format = (GdkPixbufFormat *) f->data;
224 name = gdk_pixbuf_format_get_name(format);
226 string = (*env)->NewStringUTF(env, name);
227 g_assert(string != NULL);
229 jformat = (*env)->CallStaticObjectMethod
230 (env, clazz, registerFormatID, string,
231 (jboolean) gdk_pixbuf_format_is_writable(format));
232 (*env)->DeleteLocalRef(env, string);
233 g_free(name);
235 g_assert(jformat != NULL);
237 ch = gdk_pixbuf_format_get_extensions(format);
238 count = 0;
239 while (*ch)
241 string = (*env)->NewStringUTF(env, *ch);
242 g_assert(string != NULL);
243 (*env)->CallVoidMethod (env, jformat, addExtensionID, string);
244 (*env)->DeleteLocalRef(env, string);
245 ++ch;
246 ++count;
248 g_strfreev(ch - count);
250 ch = gdk_pixbuf_format_get_mime_types(format);
251 count = 0;
252 while (*ch)
254 string = (*env)->NewStringUTF(env, *ch);
255 g_assert(string != NULL);
256 (*env)->CallVoidMethod (env, jformat, addMimeTypeID, string);
257 (*env)->DeleteLocalRef(env, string);
258 ++ch;
259 ++count;
261 g_strfreev(ch - count);
262 (*env)->DeleteLocalRef(env, jformat);
265 g_slist_free(formats);
269 JNIEXPORT void JNICALL
270 Java_gnu_java_awt_peer_gtk_GdkPixbufDecoder_initStaticState
271 (JNIEnv *env, jclass clazz)
273 jclass writerClass;
275 (*env)->GetJavaVM(env, &vm);
277 areaPreparedID = (*env)->GetMethodID (env, clazz,
278 "areaPrepared",
279 "(II)V");
281 areaUpdatedID = (*env)->GetMethodID (env, clazz,
282 "areaUpdated",
283 "(IIII[II)V");
285 registerFormatID = (*env)->GetStaticMethodID
286 (env, clazz,
287 "registerFormat",
288 "(Ljava/lang/String;Z)"
289 "Lgnu/java/awt/peer/gtk/GdkPixbufDecoder$ImageFormatSpec;");
291 writerClass = (*env)->FindClass
292 (env, "gnu/java/awt/peer/gtk/GdkPixbufDecoder$GdkPixbufWriter");
293 dataOutputWriteID = (*env)->GetMethodID (env, writerClass,
294 "write", "([B)V");
296 query_formats (env, clazz);
298 gtkpeer_init_pixbuf_IDs (env);
302 JNIEXPORT void JNICALL
303 Java_gnu_java_awt_peer_gtk_GdkPixbufDecoder_finish
304 (JNIEnv *env, jobject obj, jboolean needs_close)
306 GdkPixbufLoader *loader = NULL;
308 loader = (GdkPixbufLoader *) gtkpeer_get_pixbuf_loader(env, obj);
309 if (loader == NULL)
310 return;
312 if (needs_close)
313 gdk_pixbuf_loader_close (loader, NULL);
314 g_object_unref (loader);
317 JNIEXPORT void JNICALL
318 Java_gnu_java_awt_peer_gtk_GdkPixbufDecoder_pumpDone
319 (JNIEnv *env, jobject obj)
321 GError *err = NULL;
322 GdkPixbufLoader *loader = NULL;
324 loader = (GdkPixbufLoader *) gtkpeer_get_pixbuf_loader (env, obj);
325 g_assert (loader != NULL);
327 gdk_pixbuf_loader_close (loader, &err);
329 if (err != NULL)
331 JCL_ThrowException (env, "java/io/IOException", err->message);
332 g_error_free (err);
336 struct stream_save_request
338 JNIEnv *env;
339 jobject *writer;
342 static gboolean
343 save_to_stream(const gchar *buf,
344 gsize count,
345 GError **error __attribute__((unused)),
346 gpointer data)
348 struct stream_save_request *ssr = (struct stream_save_request *)data;
350 jbyteArray jbuf;
351 jbyte *cbuf;
353 jbuf = (*(ssr->env))->NewByteArray ((ssr->env), count);
354 cbuf = (*(ssr->env))->GetByteArrayElements ((ssr->env), jbuf, NULL);
355 memcpy (cbuf, buf, count);
356 (*(ssr->env))->ReleaseByteArrayElements ((ssr->env), jbuf, cbuf, 0);
357 (*(ssr->env))->CallVoidMethod ((ssr->env), *(ssr->writer),
358 dataOutputWriteID, jbuf);
359 (*(ssr->env))->DeleteLocalRef((ssr->env), jbuf);
361 return TRUE;
365 JNIEXPORT void JNICALL
366 Java_gnu_java_awt_peer_gtk_GdkPixbufDecoder_streamImage
367 (JNIEnv *env, jclass clazz __attribute__((unused)),
368 jintArray jarr, jstring jenctype, jint width, jint height,
369 jboolean hasAlpha, jobject writer)
371 GdkPixbuf* pixbuf;
372 jint *ints;
373 guchar a, r, g, b, *pix, *p;
374 GError *err = NULL;
375 const char *enctype;
376 int i;
377 struct stream_save_request ssr;
379 ssr.writer = &writer;
380 ssr.env = env;
382 ints = (*env)->GetIntArrayElements (env, jarr, NULL);
383 pix = g_malloc(width * height * (hasAlpha ? 4 : 3));
385 enctype = (*env)->GetStringUTFChars (env, jenctype, NULL);
386 g_assert(enctype != NULL);
388 g_assert (pix != NULL);
389 g_assert (ints != NULL);
391 p = pix;
392 for (i = 0; i < width*height; ++i)
395 * Java encodes pixels as integers in a predictable arithmetic order:
396 * 0xAARRGGBB. Since these are jints, JNI has already byte-swapped
397 * them for us if necessary, so they're in "our" endianness, whatever
398 * that is. It uses 4 bytes per pixel whether or not there's an alpha
399 * channel.
402 a = 0xff & (ints[i] >> 24);
403 r = 0xff & (ints[i] >> 16);
404 g = 0xff & (ints[i] >> 8);
405 b = 0xff & ints[i];
408 * GDK-pixbuf has a very different storage model:
410 * - A different alpha order (alpha after colors).
411 * - A different packing model (no alpha -> 3-bytes-per-pixel).
412 * - A different "RGB" order (host memory order, not endian-neutral).
415 *p++ = r;
416 *p++ = g;
417 *p++ = b;
418 if (hasAlpha)
419 *p++ = a;
422 pixbuf = gdk_pixbuf_new_from_data (pix,
423 GDK_COLORSPACE_RGB,
424 (gboolean) hasAlpha,
425 8, width, height,
426 width * (hasAlpha ? 4 : 3), /* rowstride */
427 NULL, NULL);
428 g_assert (pixbuf != NULL);
430 g_assert(gdk_pixbuf_save_to_callback (pixbuf,
431 &save_to_stream,
432 &ssr,
433 enctype,
434 &err, NULL));
436 g_object_unref (pixbuf);
438 g_free(pix);
440 (*env)->ReleaseStringUTFChars (env, jenctype, enctype);
441 (*env)->ReleaseIntArrayElements (env, jarr, ints, 0);
445 JNIEXPORT void JNICALL
446 Java_gnu_java_awt_peer_gtk_GdkPixbufDecoder_pumpBytes
447 (JNIEnv *env, jobject obj, jbyteArray jarr, jint len)
449 GdkPixbufLoader *loader = NULL;
450 jbyte *bytes = NULL;
451 GError *err = NULL;
453 g_assert (len >= 1);
454 g_assert (jarr != NULL);
456 bytes = (*env)->GetByteArrayElements (env, jarr, NULL);
457 g_assert (bytes != NULL);
458 loader = (GdkPixbufLoader *) gtkpeer_get_pixbuf_loader (env, obj);
459 g_assert (loader != NULL);
461 gdk_pixbuf_loader_write (loader, (const guchar *) bytes, len, &err);
463 (*env)->ReleaseByteArrayElements (env, jarr, bytes, 0);
465 if (err != NULL)
467 JCL_ThrowException (env, "java/io/IOException", err->message);
468 g_error_free (err);