summaryrefslogtreecommitdiff
path: root/gdk-pixbuf
diff options
context:
space:
mode:
authorHavoc Pennington <hp@redhat.com>2001-05-07 15:58:47 +0000
committerHavoc Pennington <hp@src.gnome.org>2001-05-07 15:58:47 +0000
commit4607c8e9f339e5d21ad875f3753133f370c2457c (patch)
tree5d50f9009e1b772e7ee455287cfa20bede9f4b44 /gdk-pixbuf
parente585458a3b02c4486af813409ecfc61b666e2c47 (diff)
downloadgdk-pixbuf-4607c8e9f339e5d21ad875f3753133f370c2457c.tar.gz
fix some shell typos
2001-05-04 Havoc Pennington <hp@redhat.com> * configure.in: fix some shell typos * gtk/gtkcolorsel.c (gtk_color_selection_destroy): warning fix * gtk/gtkimage.c: handle animations * gtk/gtkcheckbutton.c (gtk_check_button_size_request): request border_width * 2, not just border_width * gtk/gtkscale.c: add "format_value" signal to allow people to override the way values are drawn. (gtk_scale_get_value_size): fix width/height mistake, and compute size from actual displayed text, not from made-up text. * gtk/gtktexttag.c (gtk_text_tag_class_init): fix return type in signal registration * tests/testtext.c: Add "Remove all tags" menu item for testing * gtk/gtktextbuffer.c (gtk_text_buffer_remove_all_tags): implement * demos/gtk-demo/main.c (main): add hack so we can find modules without installing gtk * demos/gtk-demo/textview.c (insert_text): demo font scaling * gtk/gtkcellrenderertext.c: Add "scale" property (font scaling factor) (gtk_cell_renderer_text_set_property): remove some bogus g_object_notify * gtk/gtktexttag.c: add "scale" property which is a font scaling factor * gtk/gtktextlayout.c (add_text_attrs): add font scale attribute to layout * gtk/gtktextiter.c (gtk_text_iter_is_start): rename from gtk_text_iter_is_first 2001-05-04 Havoc Pennington <hp@redhat.com> * pixops/pixops.c (pixops_process): merge fix from stable: Patch from hoshem@mel.comcen.com.au to fix nonzero X offsets. Fixes bug #50371. * gdk-pixbuf/pixops/pixops.c (pixops_composite_nearest): merge from stable: Patch from OKADA Mitsuru <m-okada@fjb.co.jp> to fix confusion of using "src" instead of "p". (pixops_composite_color_nearest): Use a more accurate (and correct, to begin with) compositing method. This cures checks showing through on images with no alpha. * gdk-pixbuf.c (gdk_pixbuf_fill): fix bug that left some trailing bytes unfilled. * gdk-pixbuf-io.h: fix UpdatedNotifyFunc to use signed ints * gdk-pixbuf-loader.h (struct _GdkPixbufLoaderClass): Change area_updated signal to use signed ints. Removed animation-related signals. * io-gif.c, io-gif-animation.h, io-gif-animation.c: Massive rewrite action * gdk-pixbuf-animation.c: Add GdkPixbufAnimationIter to abstract all the pesky details. Remove old frame-based API. Make GdkPixbufAnimation an abstract base class, derived by the loaders.
Diffstat (limited to 'gdk-pixbuf')
-rw-r--r--gdk-pixbuf/Makefile.am4
-rw-r--r--gdk-pixbuf/gdk-pixbuf-animation.c655
-rw-r--r--gdk-pixbuf/gdk-pixbuf-io.h21
-rw-r--r--gdk-pixbuf/gdk-pixbuf-loader.c157
-rw-r--r--gdk-pixbuf/gdk-pixbuf-loader.h24
-rw-r--r--gdk-pixbuf/gdk-pixbuf-private.h63
-rw-r--r--gdk-pixbuf/gdk-pixbuf-util.c2
-rw-r--r--gdk-pixbuf/gdk-pixbuf.c4
-rw-r--r--gdk-pixbuf/gdk-pixbuf.h34
-rw-r--r--gdk-pixbuf/io-bmp.c12
-rw-r--r--gdk-pixbuf/io-gif-animation.c557
-rw-r--r--gdk-pixbuf/io-gif-animation.h169
-rw-r--r--gdk-pixbuf/io-gif.c514
-rw-r--r--gdk-pixbuf/io-ico.c9
-rw-r--r--gdk-pixbuf/io-jpeg.c5
-rw-r--r--gdk-pixbuf/io-png.c4
-rw-r--r--gdk-pixbuf/io-pnm.c5
-rw-r--r--gdk-pixbuf/io-ras.c8
-rw-r--r--gdk-pixbuf/io-tiff.c4
-rw-r--r--gdk-pixbuf/io-wbmp.c12
-rw-r--r--gdk-pixbuf/io-xbm.c4
-rw-r--r--gdk-pixbuf/io-xpm.c6
-rw-r--r--gdk-pixbuf/pixops/pixops.c45
23 files changed, 1720 insertions, 598 deletions
diff --git a/gdk-pixbuf/Makefile.am b/gdk-pixbuf/Makefile.am
index c8ba6e088..b006435cc 100644
--- a/gdk-pixbuf/Makefile.am
+++ b/gdk-pixbuf/Makefile.am
@@ -32,8 +32,8 @@ libpixbufloader_xpm_la_LIBADD =
#
# The GIF loader
#
-libpixbufloader_static_gif_la_SOURCES = io-gif.c
-libpixbufloader_gif_la_SOURCES = io-gif.c
+libpixbufloader_static_gif_la_SOURCES = io-gif.c io-gif-animation.c io-gif-animation.h
+libpixbufloader_gif_la_SOURCES = io-gif.c io-gif-animation.c io-gif-animation.h
libpixbufloader_gif_la_LDFLAGS = -avoid-version -module
libpixbufloader_gif_la_LIBADD =
diff --git a/gdk-pixbuf/gdk-pixbuf-animation.c b/gdk-pixbuf/gdk-pixbuf-animation.c
index cc3255904..274813c50 100644
--- a/gdk-pixbuf/gdk-pixbuf-animation.c
+++ b/gdk-pixbuf/gdk-pixbuf-animation.c
@@ -1,3 +1,4 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*- */
/* GdkPixbuf library - Simple animation support
*
* Copyright (C) 1999 The Free Software Foundation
@@ -26,12 +27,59 @@
#include "gdk-pixbuf-io.h"
#include "gdk-pixbuf-private.h"
-static void gdk_pixbuf_animation_class_init (GdkPixbufAnimationClass *klass);
-static void gdk_pixbuf_animation_finalize (GObject *object);
+typedef struct _GdkPixbufNonAnim GdkPixbufNonAnim;
+typedef struct _GdkPixbufNonAnimClass GdkPixbufNonAnimClass;
+
+#define GDK_TYPE_PIXBUF_NON_ANIM (gdk_pixbuf_non_anim_get_type ())
+#define GDK_PIXBUF_NON_ANIM(object) (G_TYPE_CHECK_INSTANCE_CAST ((object), GDK_TYPE_PIXBUF_NON_ANIM, GdkPixbufNonAnim))
+#define GDK_IS_PIXBUF_NON_ANIM(object) (G_TYPE_CHECK_INSTANCE_TYPE ((object), GDK_TYPE_PIXBUF_NON_ANIM))
+
+#define GDK_PIXBUF_NON_ANIM_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GDK_TYPE_PIXBUF_NON_ANIM, GdkPixbufNonAnimClass))
+#define GDK_IS_PIXBUF_NON_ANIM_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GDK_TYPE_PIXBUF_NON_ANIM))
+#define GDK_PIXBUF_NON_ANIM_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GDK_TYPE_PIXBUF_NON_ANIM, GdkPixbufNonAnimClass))
+
+/* Private part of the GdkPixbufNonAnim structure */
+struct _GdkPixbufNonAnim {
+ GdkPixbufAnimation parent_instance;
+
+ GdkPixbuf *pixbuf;
+};
+
+struct _GdkPixbufNonAnimClass {
+ GdkPixbufAnimationClass parent_class;
+
+};
+
+static GType gdk_pixbuf_non_anim_get_type (void) G_GNUC_CONST;
-static gpointer parent_class;
+typedef struct _GdkPixbufNonAnimIter GdkPixbufNonAnimIter;
+typedef struct _GdkPixbufNonAnimIterClass GdkPixbufNonAnimIterClass;
+
+
+#define GDK_TYPE_PIXBUF_NON_ANIM_ITER (gdk_pixbuf_non_anim_iter_get_type ())
+#define GDK_PIXBUF_NON_ANIM_ITER(object) (G_TYPE_CHECK_INSTANCE_CAST ((object), GDK_TYPE_PIXBUF_NON_ANIM_ITER, GdkPixbufNonAnimIter))
+#define GDK_IS_PIXBUF_NON_ANIM_ITER(object) (G_TYPE_CHECK_INSTANCE_TYPE ((object), GDK_TYPE_PIXBUF_NON_ANIM_ITER))
+
+#define GDK_PIXBUF_NON_ANIM_ITER_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GDK_TYPE_PIXBUF_NON_ANIM_ITER, GdkPixbufNonAnimIterClass))
+#define GDK_IS_PIXBUF_NON_ANIM_ITER_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GDK_TYPE_PIXBUF_NON_ANIM_ITER))
+#define GDK_PIXBUF_NON_ANIM_ITER_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GDK_TYPE_PIXBUF_NON_ANIM_ITER, GdkPixbufNonAnimIterClass))
+
+struct _GdkPixbufNonAnimIter {
+ GdkPixbufAnimationIter parent_instance;
+
+ GdkPixbufNonAnim *non_anim;
+};
+
+struct _GdkPixbufNonAnimIterClass {
+ GdkPixbufAnimationIterClass parent_class;
+
+};
+
+static GType gdk_pixbuf_non_anim_iter_get_type (void) G_GNUC_CONST;
+
+
GType
gdk_pixbuf_animation_get_type (void)
@@ -43,7 +91,7 @@ gdk_pixbuf_animation_get_type (void)
sizeof (GdkPixbufAnimationClass),
(GBaseInitFunc) NULL,
(GBaseFinalizeFunc) NULL,
- (GClassInitFunc) gdk_pixbuf_animation_class_init,
+ (GClassInitFunc) NULL,
NULL, /* class_finalize */
NULL, /* class_data */
sizeof (GdkPixbufAnimation),
@@ -59,35 +107,6 @@ gdk_pixbuf_animation_get_type (void)
return object_type;
}
-static void
-gdk_pixbuf_animation_class_init (GdkPixbufAnimationClass *klass)
-{
- GObjectClass *object_class = G_OBJECT_CLASS (klass);
-
- parent_class = g_type_class_peek_parent (klass);
-
- object_class->finalize = gdk_pixbuf_animation_finalize;
-}
-
-static void
-gdk_pixbuf_animation_finalize (GObject *object)
-{
- GdkPixbufAnimation *animation = GDK_PIXBUF_ANIMATION (object);
-
- GList *l;
- GdkPixbufFrame *frame;
-
- for (l = animation->frames; l; l = l->next) {
- frame = l->data;
- gdk_pixbuf_unref (frame->pixbuf);
- g_free (frame);
- }
-
- g_list_free (animation->frames);
-
- G_OBJECT_CLASS (parent_class)->finalize (object);
-}
-
/**
@@ -154,7 +173,6 @@ gdk_pixbuf_animation_new_from_file (const char *filename,
if (image_module->load_animation == NULL) {
GdkPixbuf *pixbuf;
- GdkPixbufFrame *frame;
/* Keep this logic in sync with gdk_pixbuf_new_from_file() */
@@ -191,20 +209,9 @@ gdk_pixbuf_animation_new_from_file (const char *filename,
if (pixbuf == NULL)
return NULL;
- frame = g_new (GdkPixbufFrame, 1);
- frame->pixbuf = pixbuf;
- g_object_ref (G_OBJECT (frame->pixbuf));
- frame->x_offset = 0;
- frame->y_offset = 0;
- frame->delay_time = -1;
- frame->action = GDK_PIXBUF_FRAME_RETAIN;
+ animation = gdk_pixbuf_non_anim_new (pixbuf);
- animation = g_object_new (GDK_TYPE_PIXBUF_ANIMATION, NULL);
-
- animation->n_frames = 1;
- animation->frames = g_list_prepend (NULL, frame);
- animation->width = gdk_pixbuf_get_width (pixbuf);
- animation->height = gdk_pixbuf_get_height (pixbuf);
+ g_object_unref (G_OBJECT (pixbuf));
} else {
fseek (f, 0, SEEK_SET);
animation = (* image_module->load_animation) (f, error);
@@ -262,6 +269,46 @@ gdk_pixbuf_animation_unref (GdkPixbufAnimation *animation)
}
/**
+ * gdk_pixbuf_animation_is_static_image:
+ * @animation: a #GdkPixbufAnimation
+ *
+ * If you load a file with gdk_pixbuf_animation_new_from_file() and it turns
+ * out to be a plain, unanimated image, then this function will return
+ * %TRUE. Use gdk_pixbuf_animation_get_static_image() to retrieve
+ * the image.
+ *
+ * Return value: %TRUE if the "animation" was really just an image
+ **/
+gboolean
+gdk_pixbuf_animation_is_static_image (GdkPixbufAnimation *animation)
+{
+ g_return_val_if_fail (GDK_IS_PIXBUF_ANIMATION (animation), FALSE);
+
+ return GDK_PIXBUF_ANIMATION_GET_CLASS (animation)->is_static_image (animation);
+}
+
+/**
+ * gdk_pixbuf_animation_get_static_image:
+ * @animation: a #GdkPixbufAnimation
+ *
+ * If an animation is really just a plain image (has only one frame),
+ * this function returns that image. If the animation is an animation,
+ * this function returns a reasonable thing to display as a static
+ * unanimated image, which might be the first frame, or something more
+ * sophisticated. If an animation hasn't loaded any frames yet, this
+ * function will return %NULL.
+ *
+ * Return value: unanimated image representing the animation
+ **/
+GdkPixbuf*
+gdk_pixbuf_animation_get_static_image (GdkPixbufAnimation *animation)
+{
+ g_return_val_if_fail (GDK_IS_PIXBUF_ANIMATION (animation), NULL);
+
+ return GDK_PIXBUF_ANIMATION_GET_CLASS (animation)->get_static_image (animation);
+}
+
+/**
* gdk_pixbuf_animation_get_width:
* @animation: An animation.
*
@@ -272,9 +319,16 @@ gdk_pixbuf_animation_unref (GdkPixbufAnimation *animation)
int
gdk_pixbuf_animation_get_width (GdkPixbufAnimation *animation)
{
- g_return_val_if_fail (animation != NULL, -1);
+ int width;
+
+ g_return_val_if_fail (GDK_IS_PIXBUF_ANIMATION (animation), 0);
+
+ width = 0;
+ GDK_PIXBUF_ANIMATION_GET_CLASS (animation)->get_size (animation,
+ &width, NULL);
+
- return animation->width;
+ return width;
}
/**
@@ -288,179 +342,444 @@ gdk_pixbuf_animation_get_width (GdkPixbufAnimation *animation)
int
gdk_pixbuf_animation_get_height (GdkPixbufAnimation *animation)
{
- g_return_val_if_fail (animation != NULL, -1);
-
- return animation->height;
-}
+ int height;
+
+ g_return_val_if_fail (GDK_IS_PIXBUF_ANIMATION (animation), 0);
-/**
- * gdk_pixbuf_animation_get_num_frames:
- * @animation: An animation.
- *
- * Queries the number of frames in a pixbuf animation.
- *
- * Return value: Number of frames in the animation.
- **/
-int
-gdk_pixbuf_animation_get_num_frames (GdkPixbufAnimation *animation)
-{
- g_return_val_if_fail (animation != NULL, -1);
+ height = 0;
+ GDK_PIXBUF_ANIMATION_GET_CLASS (animation)->get_size (animation,
+ NULL, &height);
+
- return animation->n_frames;
+ return height;
}
+
/**
- * gdk_pixbuf_animation_get_frames:
- * @animation: An animation.
+ * gdk_pixbuf_animation_get_iter:
+ * @animation: a #GdkPixbufAnimation
+ * @start_time: time when the animation starts playing
+ *
+ * Get an iterator for displaying an animation. The iterator provides
+ * the frames that should be displayed at a given time.
+ * It should be freed after use with g_object_unref().
+ *
+ * @start_time would normally come from g_get_current_time(), and
+ * marks the beginning of animation playback. After creating an
+ * iterator, you should immediately display the pixbuf returned by
+ * gdk_pixbuf_animation_iter_get_pixbuf(). Then, you should install a
+ * timeout (with g_timeout_add()) or by some other mechanism ensure
+ * that you'll update the image after
+ * gdk_pixbuf_animation_iter_get_delay_time() milliseconds. Each time
+ * the image is updated, you should reinstall the timeout with the new,
+ * possibly-changed delay time.
+ *
+ * As a shortcut, if @start_time is %NULL, the result of
+ * g_get_current_time() will be used automatically.
*
- * Queries the list of frames of an animation.
+ * To update the image (i.e. possibly change the result of
+ * gdk_pixbuf_animation_iter_get_pixbuf() to a new frame of the animation),
+ * call gdk_pixbuf_animation_iter_advance().
+ *
+ * If you're using #GdkPixbufLoader, in addition to updating the image
+ * after the delay time, you should also update it whenever you
+ * receive the area_updated signal and
+ * gdk_pixbuf_animation_iter_on_currently_loading_frame() returns
+ * %TRUE. In this case, the frame currently being fed into the loader
+ * has received new data, so needs to be refreshed. The delay time for
+ * a frame may also be modified after an area_updated signal, for
+ * example if the delay time for a frame is encoded in the data after
+ * the frame itself. So your timeout should be reinstalled after any
+ * area_updated signal.
+ *
+ * A delay time of -1 is possible, indicating "infinite."
*
- * Return value: List of frames in the animation; this is a #GList of
- * #GdkPixbufFrame structures.
+ * Return value: an iterator to move over the animation
**/
-GList *
-gdk_pixbuf_animation_get_frames (GdkPixbufAnimation *animation)
+GdkPixbufAnimationIter*
+gdk_pixbuf_animation_get_iter (GdkPixbufAnimation *animation,
+ const GTimeVal *start_time)
{
- g_return_val_if_fail (animation != NULL, NULL);
+ GTimeVal val;
+
+ g_return_val_if_fail (GDK_IS_PIXBUF_ANIMATION (animation), NULL);
+
- return animation->frames;
+ if (start_time)
+ val = *start_time;
+ else
+ g_get_current_time (&val);
+
+ return GDK_PIXBUF_ANIMATION_GET_CLASS (animation)->get_iter (animation, &val);
}
-/**
- * gdk_pixbuf_frame_get_pixbuf:
- * @frame: A pixbuf animation frame.
- *
- * Queries the pixbuf of an animation frame.
- *
- * Return value: A pixbuf.
- **/
-GdkPixbuf *
-gdk_pixbuf_frame_get_pixbuf (GdkPixbufFrame *frame)
+GType
+gdk_pixbuf_animation_iter_get_type (void)
{
- g_return_val_if_fail (frame != NULL, NULL);
+ static GType object_type = 0;
- return frame->pixbuf;
+ if (!object_type) {
+ static const GTypeInfo object_info = {
+ sizeof (GdkPixbufAnimationIterClass),
+ (GBaseInitFunc) NULL,
+ (GBaseFinalizeFunc) NULL,
+ (GClassInitFunc) NULL,
+ NULL, /* class_finalize */
+ NULL, /* class_data */
+ sizeof (GdkPixbufAnimationIter),
+ 0, /* n_preallocs */
+ (GInstanceInitFunc) NULL,
+ };
+
+ object_type = g_type_register_static (G_TYPE_OBJECT,
+ "GdkPixbufAnimationIter",
+ &object_info, 0);
+ }
+
+ return object_type;
}
/**
- * gdk_pixbuf_frame_get_x_offset:
- * @frame: A pixbuf animation frame.
+ * gdk_pixbuf_animation_iter_get_delay_time:
+ * @iter: an animation iterator
*
- * Queries the X offset of an animation frame.
- *
- * Return value: X offset from the top left corner of the animation.
+ * Gets the number of milliseconds the current pixbuf should be displayed,
+ * or -1 if the current pixbuf should be displayed forever. g_timeout_add()
+ * conveniently takes a timeout in milliseconds, so you can use a timeout
+ * to schedule the next update.
+ *
+ * Return value: delay time in milliseconds (thousandths of a second)
**/
int
-gdk_pixbuf_frame_get_x_offset (GdkPixbufFrame *frame)
+gdk_pixbuf_animation_iter_get_delay_time (GdkPixbufAnimationIter *iter)
{
- g_return_val_if_fail (frame != NULL, -1);
-
- return frame->x_offset;
+ g_return_val_if_fail (GDK_IS_PIXBUF_ANIMATION_ITER (iter), -1);
+
+ return GDK_PIXBUF_ANIMATION_ITER_GET_CLASS (iter)->get_delay_time (iter);
}
/**
- * gdk_pixbuf_frame_get_y_offset:
- * @frame: A pixbuf animation frame.
+ * gdk_pixbuf_animation_iter_get_pixbuf:
+ * @iter: an animation iterator
*
- * Queries the Y offset of an animation frame.
- *
- * Return value: Y offset from the top left corner of the animation.
+ * Gets the current pixbuf which should be displayed; the pixbuf will
+ * be the same size as the animation itself
+ * (gdk_pixbuf_animation_get_width(),
+ * gdk_pixbuf_animation_get_height()). This pixbuf should be displayed
+ * for gdk_pixbuf_animation_get_delay_time() milliseconds. The caller
+ * of this function does not own a reference to the returned pixbuf;
+ * the returned pixbuf will become invalid when the iterator advances
+ * to the next frame, which may happen anytime you call
+ * gdk_pixbuf_animation_iter_advance(). Copy the pixbuf to keep it
+ * (don't just add a reference), as it may get recycled as you advance
+ * the iterator.
+ *
+ * Return value: the pixbuf to be displayed
**/
-int
-gdk_pixbuf_frame_get_y_offset (GdkPixbufFrame *frame)
+GdkPixbuf*
+gdk_pixbuf_animation_iter_get_pixbuf (GdkPixbufAnimationIter *iter)
{
- g_return_val_if_fail (frame != NULL, -1);
-
- return frame->y_offset;
+ g_return_val_if_fail (GDK_IS_PIXBUF_ANIMATION_ITER (iter), NULL);
+
+ return GDK_PIXBUF_ANIMATION_ITER_GET_CLASS (iter)->get_pixbuf (iter);
}
/**
- * gdk_pixbuf_frame_get_delay_time:
- * @frame: A pixbuf animation frame.
- *
- * Queries the delay time in milliseconds of an animation frame.
+ * gdk_pixbuf_animation_iter_on_currently_loading_frame:
+ * @iter: a #GdkPixbufAnimationIter
+ *
+ * Used to determine how to respond to the area_updated signal on
+ * #GdkPixbufLoader when loading an animation. area_updated is emitted
+ * for an area of the frame currently streaming in to the loader. So if
+ * you're on the currently loading frame, you need to redraw the screen for
+ * the updated area.
*
- * Return value: Delay time in milliseconds.
+ * Return value: %TRUE if the frame we're on is partially loaded, or the last frame
**/
-int
-gdk_pixbuf_frame_get_delay_time (GdkPixbufFrame *frame)
+gboolean
+gdk_pixbuf_animation_iter_on_currently_loading_frame (GdkPixbufAnimationIter *iter)
{
- g_return_val_if_fail (frame != NULL, -1);
-
- return frame->delay_time;
+ g_return_val_if_fail (GDK_IS_PIXBUF_ANIMATION_ITER (iter), FALSE);
+
+ return GDK_PIXBUF_ANIMATION_ITER_GET_CLASS (iter)->on_currently_loading_frame (iter);
}
/**
- * gdk_pixbuf_frame_get_action:
- * @frame: A pixbuf animation frame.
+ * gdk_pixbuf_animation_iter_advance:
+ * @iter: a #GdkPixbufAnimationIter
+ * @current_time: current time
+ *
+ * Possibly advances an animation to a new frame. Chooses the frame based
+ * on the start time passed to gdk_pixbuf_animation_get_iter().
*
- * Queries the overlay action of an animation frame.
+ * @current_time would normally come from g_get_current_time(), and
+ * must be greater than or equal to the time passed to
+ * gdk_pixbuf_animation_get_iter(), and must increase or remain
+ * unchanged each time gdk_pixbuf_animation_iter_get_pixbuf() is
+ * called. That is, you can't go backward in time; animations only
+ * play forward.
+ *
+ * As a shortcut, pass %NULL for the current time and g_get_current_time()
+ * will be invoked on your behalf. So you only need to explicitly pass
+ * @current_time if you're doing something odd like playing the animation
+ * at double speed.
+ *
+ * If this function returns %FALSE, there's no need to update the animation
+ * display, assuming the display had been rendered prior to advancing;
+ * if %TRUE, you need to call gdk_animation_iter_get_pixbuf() and update the
+ * display with the new pixbuf.
+ *
+ * Returns: %TRUE if the image may need updating
*
- * Return value: Overlay action for this frame.
**/
-GdkPixbufFrameAction
-gdk_pixbuf_frame_get_action (GdkPixbufFrame *frame)
+gboolean
+gdk_pixbuf_animation_iter_advance (GdkPixbufAnimationIter *iter,
+ const GTimeVal *current_time)
{
- g_return_val_if_fail (frame != NULL, GDK_PIXBUF_FRAME_RETAIN);
+ GTimeVal val;
+
+ g_return_val_if_fail (GDK_IS_PIXBUF_ANIMATION_ITER (iter), FALSE);
- return frame->action;
+ if (current_time)
+ val = *current_time;
+ else
+ g_get_current_time (&val);
+
+ return GDK_PIXBUF_ANIMATION_ITER_GET_CLASS (iter)->advance (iter, &val);
}
-/**
- * gdk_pixbuf_frame_copy:
- * @src: a #GdkPixbufFrame to copy
- *
- * Copies a #GdkPixbufFrame. Free the result
- * with gdk_pixbuf_frame_free().
- *
- * Return value: a new #GdkPixbufFrame
- **/
-GdkPixbufFrame*
-gdk_pixbuf_frame_copy (GdkPixbufFrame *src)
+
+
+static void gdk_pixbuf_non_anim_class_init (GdkPixbufNonAnimClass *klass);
+static void gdk_pixbuf_non_anim_finalize (GObject *object);
+
+static gboolean gdk_pixbuf_non_anim_is_static_image (GdkPixbufAnimation *animation);
+static GdkPixbuf* gdk_pixbuf_non_anim_get_static_image (GdkPixbufAnimation *animation);
+static void gdk_pixbuf_non_anim_get_size (GdkPixbufAnimation *anim,
+ int *width,
+ int *height);
+static GdkPixbufAnimationIter* gdk_pixbuf_non_anim_get_iter (GdkPixbufAnimation *anim,
+ const GTimeVal *start_time);
+
+
+
+
+
+static gpointer non_parent_class;
+
+GType
+gdk_pixbuf_non_anim_get_type (void)
{
- GdkPixbufFrame *frame;
-
- frame = g_new (GdkPixbufFrame, 1);
- frame->pixbuf = src->pixbuf;
- g_object_ref (G_OBJECT (frame->pixbuf));
- frame->x_offset = src->x_offset;
- frame->y_offset = src->y_offset;
- frame->delay_time = src->delay_time;
- frame->action = src->action;
-
- return frame;
+ static GType object_type = 0;
+
+ if (!object_type) {
+ static const GTypeInfo object_info = {
+ sizeof (GdkPixbufNonAnimClass),
+ (GBaseInitFunc) NULL,
+ (GBaseFinalizeFunc) NULL,
+ (GClassInitFunc) gdk_pixbuf_non_anim_class_init,
+ NULL, /* class_finalize */
+ NULL, /* class_data */
+ sizeof (GdkPixbufNonAnim),
+ 0, /* n_preallocs */
+ (GInstanceInitFunc) NULL,
+ };
+
+ object_type = g_type_register_static (GDK_TYPE_PIXBUF_ANIMATION,
+ "GdkPixbufNonAnim",
+ &object_info, 0);
+ }
+
+ return object_type;
}
-/**
- * gdk_pixbuf_frame_free:
- * @frame: a #GdkPixbufFrame
- *
- * Frees a #GdkPixbufFrame. Don't do this with frames you got from
- * #GdkPixbufAnimation, usually the animation owns those (it doesn't
- * make a copy before returning the frame).
- **/
-void
-gdk_pixbuf_frame_free (GdkPixbufFrame *frame)
+static void
+gdk_pixbuf_non_anim_class_init (GdkPixbufNonAnimClass *klass)
{
- g_return_if_fail (frame != NULL);
+ GObjectClass *object_class = G_OBJECT_CLASS (klass);
+ GdkPixbufAnimationClass *anim_class = GDK_PIXBUF_ANIMATION_CLASS (klass);
+
+ non_parent_class = g_type_class_peek_parent (klass);
+
+ object_class->finalize = gdk_pixbuf_non_anim_finalize;
+
+ anim_class->is_static_image = gdk_pixbuf_non_anim_is_static_image;
+ anim_class->get_static_image = gdk_pixbuf_non_anim_get_static_image;
+ anim_class->get_size = gdk_pixbuf_non_anim_get_size;
+ anim_class->get_iter = gdk_pixbuf_non_anim_get_iter;
+}
+
+static void
+gdk_pixbuf_non_anim_finalize (GObject *object)
+{
+ GdkPixbufNonAnim *non_anim = GDK_PIXBUF_NON_ANIM (object);
+
+ if (non_anim->pixbuf)
+ g_object_unref (G_OBJECT (non_anim->pixbuf));
+
+ G_OBJECT_CLASS (non_parent_class)->finalize (object);
+}
+
+GdkPixbufAnimation*
+gdk_pixbuf_non_anim_new (GdkPixbuf *pixbuf)
+{
+ GdkPixbufNonAnim *non_anim;
+
+ non_anim = g_object_new (GDK_TYPE_PIXBUF_NON_ANIM, NULL);
+
+ non_anim->pixbuf = pixbuf;
+
+ if (pixbuf)
+ g_object_ref (G_OBJECT (pixbuf));
- g_object_unref (G_OBJECT (frame->pixbuf));
- g_free (frame);
+ return GDK_PIXBUF_ANIMATION (non_anim);
}
+static gboolean
+gdk_pixbuf_non_anim_is_static_image (GdkPixbufAnimation *animation)
+{
+
+ return TRUE;
+}
+
+static GdkPixbuf*
+gdk_pixbuf_non_anim_get_static_image (GdkPixbufAnimation *animation)
+{
+ GdkPixbufNonAnim *non_anim;
+
+ non_anim = GDK_PIXBUF_NON_ANIM (animation);
+
+ return non_anim->pixbuf;
+}
+
+static void
+gdk_pixbuf_non_anim_get_size (GdkPixbufAnimation *anim,
+ int *width,
+ int *height)
+{
+ GdkPixbufNonAnim *non_anim;
+
+ non_anim = GDK_PIXBUF_NON_ANIM (anim);
+
+ if (width)
+ *width = gdk_pixbuf_get_width (non_anim->pixbuf);
+
+ if (height)
+ *height = gdk_pixbuf_get_height (non_anim->pixbuf);
+}
+
+
+static GdkPixbufAnimationIter*
+gdk_pixbuf_non_anim_get_iter (GdkPixbufAnimation *anim,
+ const GTimeVal *start_time)
+{
+ GdkPixbufNonAnimIter *iter;
+
+ iter = g_object_new (GDK_TYPE_PIXBUF_NON_ANIM_ITER, NULL);
+
+ iter->non_anim = GDK_PIXBUF_NON_ANIM (anim);
+
+ g_object_ref (G_OBJECT (iter->non_anim));
+
+ return GDK_PIXBUF_ANIMATION_ITER (iter);
+}
+
+
+
+static void gdk_pixbuf_non_anim_iter_class_init (GdkPixbufNonAnimIterClass *klass);
+static void gdk_pixbuf_non_anim_iter_finalize (GObject *object);
+static int gdk_pixbuf_non_anim_iter_get_delay_time (GdkPixbufAnimationIter *iter);
+static GdkPixbuf* gdk_pixbuf_non_anim_iter_get_pixbuf (GdkPixbufAnimationIter *iter);
+static gboolean gdk_pixbuf_non_anim_iter_on_currently_loading_frame (GdkPixbufAnimationIter *iter);
+static gboolean gdk_pixbuf_non_anim_iter_advance (GdkPixbufAnimationIter *iter,
+ const GTimeVal *current_time);
+
+
+
+
+
+static gpointer non_iter_parent_class;
+
GType
-gdk_pixbuf_frame_get_type (void)
+gdk_pixbuf_non_anim_iter_get_type (void)
+{
+ static GType object_type = 0;
+
+ if (!object_type) {
+ static const GTypeInfo object_info = {
+ sizeof (GdkPixbufNonAnimIterClass),
+ (GBaseInitFunc) NULL,
+ (GBaseFinalizeFunc) NULL,
+ (GClassInitFunc) gdk_pixbuf_non_anim_iter_class_init,
+ NULL, /* class_finalize */
+ NULL, /* class_data */
+ sizeof (GdkPixbufNonAnimIter),
+ 0, /* n_preallocs */
+ (GInstanceInitFunc) NULL,
+ };
+
+ object_type = g_type_register_static (GDK_TYPE_PIXBUF_ANIMATION_ITER,
+ "GdkPixbufNonAnimIter",
+ &object_info, 0);
+ }
+
+ return object_type;
+}
+
+static void
+gdk_pixbuf_non_anim_iter_class_init (GdkPixbufNonAnimIterClass *klass)
+{
+ GObjectClass *object_class = G_OBJECT_CLASS (klass);
+ GdkPixbufAnimationIterClass *anim_iter_class =
+ GDK_PIXBUF_ANIMATION_ITER_CLASS (klass);
+
+ non_iter_parent_class = g_type_class_peek_parent (klass);
+
+ object_class->finalize = gdk_pixbuf_non_anim_iter_finalize;
+
+ anim_iter_class->get_delay_time = gdk_pixbuf_non_anim_iter_get_delay_time;
+ anim_iter_class->get_pixbuf = gdk_pixbuf_non_anim_iter_get_pixbuf;
+ anim_iter_class->on_currently_loading_frame = gdk_pixbuf_non_anim_iter_on_currently_loading_frame;
+ anim_iter_class->advance = gdk_pixbuf_non_anim_iter_advance;
+}
+
+static void
+gdk_pixbuf_non_anim_iter_finalize (GObject *object)
{
- static GType our_type = 0;
+ GdkPixbufNonAnimIter *iter = GDK_PIXBUF_NON_ANIM_ITER (object);
- if (our_type == 0)
- our_type = g_boxed_type_register_static ("GdkPixbufFrame",
- NULL,
- gdk_pixbuf_frame_copy,
- gdk_pixbuf_frame_free,
- FALSE);
+ g_object_unref (G_OBJECT (iter->non_anim));
+
+ G_OBJECT_CLASS (non_iter_parent_class)->finalize (object);
+}
+
+static int
+gdk_pixbuf_non_anim_iter_get_delay_time (GdkPixbufAnimationIter *iter)
+{
+ return -1; /* show only frame forever */
+}
- return our_type;
+static GdkPixbuf*
+gdk_pixbuf_non_anim_iter_get_pixbuf (GdkPixbufAnimationIter *iter)
+{
+ return GDK_PIXBUF_NON_ANIM_ITER (iter)->non_anim->pixbuf;
}
+
+
+static gboolean
+gdk_pixbuf_non_anim_iter_on_currently_loading_frame (GdkPixbufAnimationIter *iter)
+{
+ return TRUE;
+}
+
+static gboolean
+gdk_pixbuf_non_anim_iter_advance (GdkPixbufAnimationIter *iter,
+ const GTimeVal *current_time)
+{
+
+ /* Advancing never requires a refresh */
+ return FALSE;
+}
+
diff --git a/gdk-pixbuf/gdk-pixbuf-io.h b/gdk-pixbuf/gdk-pixbuf-io.h
index d4cf389fd..b66bcaf08 100644
--- a/gdk-pixbuf/gdk-pixbuf-io.h
+++ b/gdk-pixbuf/gdk-pixbuf-io.h
@@ -39,16 +39,15 @@ extern "C" {
-typedef void (* ModulePreparedNotifyFunc) (GdkPixbuf *pixbuf, gpointer user_data);
-typedef void (* ModuleUpdatedNotifyFunc) (GdkPixbuf *pixbuf,
- guint x, guint y,
- guint width, guint height,
- gpointer user_data);
-/* Needed only for animated images. */
-typedef void (* ModuleFrameDoneNotifyFunc) (GdkPixbufFrame *frame,
- gpointer user_data);
-typedef void (* ModuleAnimationDoneNotifyFunc) (GdkPixbuf *pixbuf,
- gpointer user_data);
+typedef void (* ModulePreparedNotifyFunc) (GdkPixbuf *pixbuf,
+ GdkPixbufAnimation *anim,
+ gpointer user_data);
+typedef void (* ModuleUpdatedNotifyFunc) (GdkPixbuf *pixbuf,
+ int x,
+ int y,
+ int width,
+ int height,
+ gpointer user_data);
typedef struct _GdkPixbufModule GdkPixbufModule;
struct _GdkPixbufModule {
@@ -63,8 +62,6 @@ struct _GdkPixbufModule {
gpointer (* begin_load) (ModulePreparedNotifyFunc prepare_func,
ModuleUpdatedNotifyFunc update_func,
- ModuleFrameDoneNotifyFunc frame_done_func,
- ModuleAnimationDoneNotifyFunc anim_done_func,
gpointer user_data,
GError **error);
gboolean (* stop_load) (gpointer context,
diff --git a/gdk-pixbuf/gdk-pixbuf-loader.c b/gdk-pixbuf/gdk-pixbuf-loader.c
index 2a8d2658e..a9148d7fd 100644
--- a/gdk-pixbuf/gdk-pixbuf-loader.c
+++ b/gdk-pixbuf/gdk-pixbuf-loader.c
@@ -35,8 +35,6 @@
enum {
AREA_UPDATED,
AREA_PREPARED,
- FRAME_DONE,
- ANIMATION_DONE,
CLOSED,
LAST_SIGNAL
};
@@ -56,7 +54,6 @@ static guint pixbuf_loader_signals[LAST_SIGNAL] = { 0 };
typedef struct
{
- GdkPixbuf *pixbuf;
GdkPixbufAnimation *animation;
gboolean closed;
guchar header_buf[LOADER_HEADER_SIZE];
@@ -136,25 +133,6 @@ gdk_pixbuf_loader_class_init (GdkPixbufLoaderClass *class)
G_TYPE_INT,
G_TYPE_INT);
- pixbuf_loader_signals[FRAME_DONE] =
- g_signal_newc ("frame_done",
- G_TYPE_FROM_CLASS (object_class),
- G_SIGNAL_RUN_LAST,
- G_STRUCT_OFFSET (GdkPixbufLoaderClass, frame_done),
- NULL, NULL,
- gdk_pixbuf_marshal_VOID__POINTER,
- G_TYPE_NONE, 1,
- GDK_TYPE_PIXBUF_FRAME);
-
- pixbuf_loader_signals[ANIMATION_DONE] =
- g_signal_newc ("animation_done",
- G_TYPE_FROM_CLASS (object_class),
- G_SIGNAL_RUN_LAST,
- G_STRUCT_OFFSET (GdkPixbufLoaderClass, animation_done),
- NULL, NULL,
- gdk_pixbuf_marshal_VOID__VOID,
- G_TYPE_NONE, 0);
-
pixbuf_loader_signals[CLOSED] =
g_signal_newc ("closed",
G_TYPE_FROM_CLASS (object_class),
@@ -188,9 +166,6 @@ gdk_pixbuf_loader_finalize (GObject *object)
if (priv->animation)
gdk_pixbuf_animation_unref (priv->animation);
-
- if (priv->pixbuf)
- gdk_pixbuf_unref (priv->pixbuf);
g_free (priv);
@@ -198,26 +173,30 @@ gdk_pixbuf_loader_finalize (GObject *object)
}
static void
-gdk_pixbuf_loader_prepare (GdkPixbuf *pixbuf,
- gpointer loader)
+gdk_pixbuf_loader_prepare (GdkPixbuf *pixbuf,
+ GdkPixbufAnimation *anim,
+ gpointer loader)
{
GdkPixbufLoaderPrivate *priv = NULL;
priv = GDK_PIXBUF_LOADER (loader)->priv;
- gdk_pixbuf_ref (pixbuf);
- g_assert (priv->pixbuf == NULL);
+ if (anim)
+ g_object_ref (G_OBJECT (anim));
+ else
+ anim = gdk_pixbuf_non_anim_new (pixbuf);
+
+ priv->animation = anim;
- priv->pixbuf = pixbuf;
g_signal_emit (G_OBJECT (loader), pixbuf_loader_signals[AREA_PREPARED], 0);
}
static void
gdk_pixbuf_loader_update (GdkPixbuf *pixbuf,
- guint x,
- guint y,
- guint width,
- guint height,
+ gint x,
+ gint y,
+ gint width,
+ gint height,
gpointer loader)
{
GdkPixbufLoaderPrivate *priv = NULL;
@@ -229,82 +208,8 @@ gdk_pixbuf_loader_update (GdkPixbuf *pixbuf,
0,
x, y,
/* sanity check in here. Defend against an errant loader */
- MIN (width, gdk_pixbuf_get_width (priv->pixbuf)),
- MIN (height, gdk_pixbuf_get_height (priv->pixbuf)));
-}
-
-static void
-gdk_pixbuf_loader_frame_done (GdkPixbufFrame *frame,
- gpointer loader)
-{
- GdkPixbufLoaderPrivate *priv = NULL;
-
- priv = GDK_PIXBUF_LOADER (loader)->priv;
-
- priv->pixbuf = NULL;
-
- if (priv->animation == NULL)
- {
- priv->animation = g_object_new (GDK_TYPE_PIXBUF_ANIMATION, NULL);
-
- priv->animation->n_frames = 0;
- priv->animation->width = gdk_pixbuf_get_width (frame->pixbuf) + frame->x_offset;
- priv->animation->height = gdk_pixbuf_get_height (frame->pixbuf) + frame->y_offset;
- }
- else
- {
- int w, h;
-
- /* update bbox size */
- w = gdk_pixbuf_get_width (frame->pixbuf) + frame->x_offset;
- h = gdk_pixbuf_get_height (frame->pixbuf) + frame->y_offset;
-
- if (w > priv->animation->width) {
- priv->animation->width = w;
- }
- if (h > priv->animation->height) {
- priv->animation->height = h;
- }
- }
-
- priv->animation->frames = g_list_append (priv->animation->frames, frame);
- priv->animation->n_frames++;
- g_signal_emit (G_OBJECT (loader),
- pixbuf_loader_signals[FRAME_DONE],
- 0,
- frame);
-}
-
-static void
-gdk_pixbuf_loader_animation_done (GdkPixbuf *pixbuf,
- gpointer loader)
-{
- GdkPixbufLoaderPrivate *priv = NULL;
- GdkPixbufFrame *frame;
- GList *current = NULL;
- gint h, w;
-
- priv = GDK_PIXBUF_LOADER (loader)->priv;
- priv->pixbuf = NULL;
-
- current = gdk_pixbuf_animation_get_frames (priv->animation);
-
- while (current)
- {
- frame = (GdkPixbufFrame *) current->data;
-
- /* update bbox size */
- w = gdk_pixbuf_get_width (frame->pixbuf) + frame->x_offset;
- h = gdk_pixbuf_get_height (frame->pixbuf) + frame->y_offset;
-
- if (w > priv->animation->width)
- priv->animation->width = w;
- if (h > priv->animation->height)
- priv->animation->height = h;
- current = current->next;
- }
-
- g_signal_emit (G_OBJECT (loader), pixbuf_loader_signals[ANIMATION_DONE], 0);
+ MIN (width, gdk_pixbuf_animation_get_width (priv->animation)),
+ MIN (height, gdk_pixbuf_animation_get_height (priv->animation)));
}
static gint
@@ -353,8 +258,6 @@ gdk_pixbuf_loader_load_module (GdkPixbufLoader *loader,
priv->context = priv->image_module->begin_load (gdk_pixbuf_loader_prepare,
gdk_pixbuf_loader_update,
- gdk_pixbuf_loader_frame_done,
- gdk_pixbuf_loader_animation_done,
loader,
error);
@@ -450,7 +353,7 @@ gdk_pixbuf_loader_write (GdkPixbufLoader *loader,
{
gint eaten;
- eaten = gdk_pixbuf_loader_eat_header_write(loader, buf, count, error);
+ eaten = gdk_pixbuf_loader_eat_header_write (loader, buf, count, error);
if (eaten <= 0)
return FALSE;
@@ -540,13 +443,14 @@ gdk_pixbuf_loader_new_with_type (const char *image_type,
* "area_prepared" signal has been emitted by the loader; this means
* that enough data has been read to know the size of the image that
* will be allocated. If the loader has not received enough data via
- * gdk_pixbuf_loader_write(), then this function returns NULL. The
+ * gdk_pixbuf_loader_write(), then this function returns %NULL. The
* returned pixbuf will be the same in all future calls to the loader,
* so simply calling gdk_pixbuf_ref() should be sufficient to continue
* using it. Additionally, if the loader is an animation, it will
- * return the first frame of the animation.
+ * return the "static image" of the animation
+ * (see gdk_pixbuf_animation_get_static_image()).
*
- * Return value: The GdkPixbuf that the loader is creating, or NULL if not
+ * Return value: The #GdkPixbuf that the loader is creating, or %NULL if not
* enough data has been read to determine how to create the image buffer.
**/
GdkPixbuf *
@@ -560,19 +464,9 @@ gdk_pixbuf_loader_get_pixbuf (GdkPixbufLoader *loader)
priv = loader->priv;
if (priv->animation)
- {
- GList *list;
-
- list = gdk_pixbuf_animation_get_frames (priv->animation);
- if (list != NULL)
- {
- GdkPixbufFrame *frame = list->data;
-
- return gdk_pixbuf_frame_get_pixbuf (frame);
- }
- }
-
- return priv->pixbuf;
+ return gdk_pixbuf_animation_get_static_image (priv->animation);
+ else
+ return NULL;
}
/**
@@ -581,8 +475,9 @@ gdk_pixbuf_loader_get_pixbuf (GdkPixbufLoader *loader)
*
* Queries the GdkPixbufAnimation that a pixbuf loader is currently creating.
* In general it only makes sense to call this function afer the "area_prepared"
- * signal has been emitted by the loader. If the image is not an animation,
- * then it will return NULL.
+ * signal has been emitted by the loader. If the loader doesn't have enough
+ * bytes yet (hasn't emitted the area_prepared signal) this function will return
+ * %NULL.
*
* Return value: The GdkPixbufAnimation that the loader is loading, or NULL if
not enough data has been read to determine the information.
diff --git a/gdk-pixbuf/gdk-pixbuf-loader.h b/gdk-pixbuf/gdk-pixbuf-loader.h
index 9c47478a2..eea72f30d 100644
--- a/gdk-pixbuf/gdk-pixbuf-loader.h
+++ b/gdk-pixbuf/gdk-pixbuf-loader.h
@@ -51,21 +51,21 @@ typedef struct _GdkPixbufLoaderClass GdkPixbufLoaderClass;
struct _GdkPixbufLoaderClass
{
GObjectClass parent_class;
-
- void (*area_prepared) (GdkPixbufLoader *loader);
- void (*area_updated) (GdkPixbufLoader *loader,
- guint x,
- guint y,
- guint width,
- guint height);
- void (*frame_done) (GdkPixbufLoader *loader,
- GdkPixbufFrame *frame);
- void (*animation_done) (GdkPixbufLoader *loader);
- void (*closed) (GdkPixbufLoader *loader);
+
+ void (*area_prepared) (GdkPixbufLoader *loader);
+
+ /* Last known frame needs a redraw for x, y, width, height */
+ void (*area_updated) (GdkPixbufLoader *loader,
+ int x,
+ int y,
+ int width,
+ int height);
+
+ void (*closed) (GdkPixbufLoader *loader);
};
-GType gdk_pixbuf_loader_get_type (void) G_GNUC_CONST;
+GType gdk_pixbuf_loader_get_type (void) G_GNUC_CONST;
GdkPixbufLoader * gdk_pixbuf_loader_new (void);
GdkPixbufLoader * gdk_pixbuf_loader_new_with_type (const char *image_type,
GError **error);
diff --git a/gdk-pixbuf/gdk-pixbuf-private.h b/gdk-pixbuf/gdk-pixbuf-private.h
index e8eb7248a..0bdae8715 100644
--- a/gdk-pixbuf/gdk-pixbuf-private.h
+++ b/gdk-pixbuf/gdk-pixbuf-private.h
@@ -1,3 +1,4 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*- */
/* GdkPixbuf library - Private declarations
*
* Copyright (C) 1999 The Free Software Foundation
@@ -73,22 +74,6 @@ struct _GdkPixbufClass {
};
-/* Private part of the GdkPixbufFrame structure */
-struct _GdkPixbufFrame {
- /* The pixbuf with this frame's image data */
- GdkPixbuf *pixbuf;
-
- /* Offsets for overlaying onto the animation's area */
- int x_offset;
- int y_offset;
-
- /* Frame duration in ms */
- int delay_time;
-
- /* Overlay mode */
- GdkPixbufFrameAction action;
-};
-
typedef struct _GdkPixbufAnimationClass GdkPixbufAnimationClass;
#define GDK_PIXBUF_ANIMATION_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GDK_TYPE_PIXBUF_ANIMATION, GdkPixbufAnimationClass))
@@ -99,22 +84,50 @@ typedef struct _GdkPixbufAnimationClass GdkPixbufAnimationClass;
struct _GdkPixbufAnimation {
GObject parent_instance;
- /* Number of frames */
- int n_frames;
-
- /* List of GdkPixbufFrame structures */
- GList *frames;
-
- /* bounding box size */
- int width, height;
};
struct _GdkPixbufAnimationClass {
GObjectClass parent_class;
+ gboolean (*is_static_image) (GdkPixbufAnimation *anim);
+
+ GdkPixbuf* (*get_static_image) (GdkPixbufAnimation *anim);
+
+ void (*get_size) (GdkPixbufAnimation *anim,
+ int *width,
+ int *height);
+
+ GdkPixbufAnimationIter* (*get_iter) (GdkPixbufAnimation *anim,
+ const GTimeVal *start_time);
+
+};
+
+
+
+typedef struct _GdkPixbufAnimationIterClass GdkPixbufAnimationIterClass;
+
+#define GDK_PIXBUF_ANIMATION_ITER_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GDK_TYPE_PIXBUF_ANIMATION_ITER, GdkPixbufAnimationIterClass))
+#define GDK_IS_PIXBUF_ANIMATION_ITER_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GDK_TYPE_PIXBUF_ANIMATION_ITER))
+#define GDK_PIXBUF_ANIMATION_ITER_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GDK_TYPE_PIXBUF_ANIMATION_ITER, GdkPixbufAnimationIterClass))
+
+struct _GdkPixbufAnimationIter {
+ GObject parent_instance;
};
+struct _GdkPixbufAnimationIterClass {
+ GObjectClass parent_class;
+
+ int (*get_delay_time) (GdkPixbufAnimationIter *iter);
+
+ GdkPixbuf* (*get_pixbuf) (GdkPixbufAnimationIter *iter);
+
+ gboolean (*on_currently_loading_frame) (GdkPixbufAnimationIter *iter);
+
+ gboolean (*advance) (GdkPixbufAnimationIter *iter,
+ const GTimeVal *current_time);
+};
+
#define GDK_PIXBUF_INLINE_MAGIC_NUMBER 0x47646B50 /* 'GdkP' */
@@ -125,6 +138,8 @@ typedef enum
GDK_PIXBUF_INLINE_RLE = 1
} GdkPixbufInlineFormat;
+
+GdkPixbufAnimation* gdk_pixbuf_non_anim_new (GdkPixbuf *pixbuf);
#endif
diff --git a/gdk-pixbuf/gdk-pixbuf-util.c b/gdk-pixbuf/gdk-pixbuf-util.c
index bee4fb5bb..0f869b947 100644
--- a/gdk-pixbuf/gdk-pixbuf-util.c
+++ b/gdk-pixbuf/gdk-pixbuf-util.c
@@ -121,6 +121,8 @@ gdk_pixbuf_copy_area (const GdkPixbuf *src_pixbuf,
g_return_if_fail (dest_x >= 0 && dest_x + width <= dest_pixbuf->width);
g_return_if_fail (dest_y >= 0 && dest_y + height <= dest_pixbuf->height);
+ g_return_if_fail (!(gdk_pixbuf_get_has_alpha (src_pixbuf) && !gdk_pixbuf_get_has_alpha (dest_pixbuf)));
+
/* This will perform format conversions automatically */
gdk_pixbuf_scale (src_pixbuf,
diff --git a/gdk-pixbuf/gdk-pixbuf.c b/gdk-pixbuf/gdk-pixbuf.c
index 12b8e6144..cfc0bb323 100644
--- a/gdk-pixbuf/gdk-pixbuf.c
+++ b/gdk-pixbuf/gdk-pixbuf.c
@@ -412,7 +412,7 @@ gdk_pixbuf_error_quark (void)
/**
* gdk_pixbuf_fill:
* @pixbuf: a #GdkPixbuf
- * @pixel: RGBA pixel to clear to (0xffffff00 is opaque white, 0x000000ff transparent black)
+ * @pixel: RGBA pixel to clear to (0xffffffff is opaque white, 0x00000000 transparent black)
*
* Clears a pixbuf to the given RGBA value, converting the RGBA value into
* the pixbuf's pixel format. The alpha will be ignored if the pixbuf
@@ -454,7 +454,7 @@ gdk_pixbuf_fill (GdkPixbuf *pixbuf,
p = pixels;
end = pixels + pixbuf->rowstride * pixbuf->height;
- end -= (pixbuf->rowstride - pixbuf->width);
+ end -= (pixbuf->rowstride - pixbuf->width * pixbuf->n_channels);
while (p < end) {
*p++ = r;
diff --git a/gdk-pixbuf/gdk-pixbuf.h b/gdk-pixbuf/gdk-pixbuf.h
index b8b5a03af..46ff3533c 100644
--- a/gdk-pixbuf/gdk-pixbuf.h
+++ b/gdk-pixbuf/gdk-pixbuf.h
@@ -54,6 +54,7 @@ typedef enum {
/* All of these are opaque structures */
typedef struct _GdkPixbuf GdkPixbuf;
typedef struct _GdkPixbufAnimation GdkPixbufAnimation;
+typedef struct _GdkPixbufAnimationIter GdkPixbufAnimationIter;
typedef struct _GdkPixbufFrame GdkPixbufFrame;
#define GDK_TYPE_PIXBUF (gdk_pixbuf_get_type ())
@@ -64,6 +65,9 @@ typedef struct _GdkPixbufFrame GdkPixbufFrame;
#define GDK_PIXBUF_ANIMATION(object) (G_TYPE_CHECK_INSTANCE_CAST ((object), GDK_TYPE_PIXBUF_ANIMATION, GdkPixbufAnimation))
#define GDK_IS_PIXBUF_ANIMATION(object) (G_TYPE_CHECK_INSTANCE_TYPE ((object), GDK_TYPE_PIXBUF_ANIMATION))
+#define GDK_TYPE_PIXBUF_ANIMATION_ITER (gdk_pixbuf_animation_iter_get_type ())
+#define GDK_PIXBUF_ANIMATION_ITER(object) (G_TYPE_CHECK_INSTANCE_CAST ((object), GDK_TYPE_PIXBUF_ANIMATION_ITER, GdkPixbufAnimationIter))
+#define GDK_IS_PIXBUF_ANIMATION_ITER(object) (G_TYPE_CHECK_INSTANCE_TYPE ((object), GDK_TYPE_PIXBUF_ANIMATION_ITER))
/* Handler that must free the pixel array */
typedef void (* GdkPixbufDestroyNotify) (guchar *pixels, gpointer data);
@@ -255,13 +259,6 @@ GdkPixbuf *gdk_pixbuf_composite_color_simple (const GdkPixbuf *src,
/* Animation support */
-/* GIF-like animation overlay modes for frames */
-typedef enum {
- GDK_PIXBUF_FRAME_RETAIN,
- GDK_PIXBUF_FRAME_DISPOSE,
- GDK_PIXBUF_FRAME_REVERT
-} GdkPixbufFrameAction;
-
GType gdk_pixbuf_animation_get_type (void) G_GNUC_CONST;
GdkPixbufAnimation *gdk_pixbuf_animation_new_from_file (const char *filename,
@@ -272,21 +269,20 @@ void gdk_pixbuf_animation_unref (GdkPixbufAnimation *an
int gdk_pixbuf_animation_get_width (GdkPixbufAnimation *animation);
int gdk_pixbuf_animation_get_height (GdkPixbufAnimation *animation);
-GList *gdk_pixbuf_animation_get_frames (GdkPixbufAnimation *animation);
-int gdk_pixbuf_animation_get_num_frames (GdkPixbufAnimation *animation);
+gboolean gdk_pixbuf_animation_is_static_image (GdkPixbufAnimation *animation);
+GdkPixbuf *gdk_pixbuf_animation_get_static_image (GdkPixbufAnimation *animation);
-/* Frame accessors */
+GdkPixbufAnimationIter *gdk_pixbuf_animation_get_iter (GdkPixbufAnimation *animation,
+ const GTimeVal *start_time);
+GType gdk_pixbuf_animation_iter_get_type (void) G_GNUC_CONST;
+int gdk_pixbuf_animation_iter_get_delay_time (GdkPixbufAnimationIter *iter);
+GdkPixbuf *gdk_pixbuf_animation_iter_get_pixbuf (GdkPixbufAnimationIter *iter);
+gboolean gdk_pixbuf_animation_iter_on_currently_loading_frame (GdkPixbufAnimationIter *iter);
+gboolean gdk_pixbuf_animation_iter_advance (GdkPixbufAnimationIter *iter,
+ const GTimeVal *current_time);
-GdkPixbuf *gdk_pixbuf_frame_get_pixbuf (GdkPixbufFrame *frame);
-int gdk_pixbuf_frame_get_x_offset (GdkPixbufFrame *frame);
-int gdk_pixbuf_frame_get_y_offset (GdkPixbufFrame *frame);
-int gdk_pixbuf_frame_get_delay_time (GdkPixbufFrame *frame);
-GdkPixbufFrameAction gdk_pixbuf_frame_get_action (GdkPixbufFrame *frame);
-GdkPixbufFrame *gdk_pixbuf_frame_copy (GdkPixbufFrame *src);
-void gdk_pixbuf_frame_free (GdkPixbufFrame *frame);
-GType gdk_pixbuf_frame_get_type (void) G_GNUC_CONST;
-#define GDK_TYPE_PIXBUF_FRAME gdk_pixbuf_frame_get_type ()
+
#include <gdk-pixbuf/gdk-pixbuf-loader.h>
diff --git a/gdk-pixbuf/io-bmp.c b/gdk-pixbuf/io-bmp.c
index c5108bcc1..ce112f85a 100644
--- a/gdk-pixbuf/io-bmp.c
+++ b/gdk-pixbuf/io-bmp.c
@@ -174,9 +174,7 @@ struct bmp_progressive_state {
static gpointer
gdk_pixbuf__bmp_image_begin_load(ModulePreparedNotifyFunc prepared_func,
ModuleUpdatedNotifyFunc updated_func,
- ModuleFrameDoneNotifyFunc frame_done_func,
- ModuleAnimationDoneNotifyFunc
- anim_done_func, gpointer user_data,
+ gpointer user_data,
GError **error);
static gboolean gdk_pixbuf__bmp_image_stop_load(gpointer data, GError **error);
@@ -198,7 +196,7 @@ static GdkPixbuf *gdk_pixbuf__bmp_image_load(FILE * f, GError **error)
GdkPixbuf *pb;
State =
- gdk_pixbuf__bmp_image_begin_load(NULL, NULL, NULL, NULL, NULL,
+ gdk_pixbuf__bmp_image_begin_load(NULL, NULL, NULL,
error);
if (State == NULL)
@@ -312,7 +310,7 @@ static gboolean DecodeHeader(unsigned char *BFH, unsigned char *BIH,
if (State->prepared_func != NULL)
/* Notify the client that we are ready to go */
- (*State->prepared_func) (State->pixbuf, State->user_data);
+ (*State->prepared_func) (State->pixbuf, NULL, State->user_data);
}
@@ -328,9 +326,7 @@ static gboolean DecodeHeader(unsigned char *BFH, unsigned char *BIH,
static gpointer
gdk_pixbuf__bmp_image_begin_load(ModulePreparedNotifyFunc prepared_func,
ModuleUpdatedNotifyFunc updated_func,
- ModuleFrameDoneNotifyFunc frame_done_func,
- ModuleAnimationDoneNotifyFunc
- anim_done_func, gpointer user_data,
+ gpointer user_data,
GError **error)
{
struct bmp_progressive_state *context;
diff --git a/gdk-pixbuf/io-gif-animation.c b/gdk-pixbuf/io-gif-animation.c
new file mode 100644
index 000000000..fe164a095
--- /dev/null
+++ b/gdk-pixbuf/io-gif-animation.c
@@ -0,0 +1,557 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*- */
+/* GdkPixbuf library - animated gif support
+ *
+ * Copyright (C) 1999 The Free Software Foundation
+ *
+ * Authors: Jonathan Blandford <jrb@redhat.com>
+ * Havoc Pennington <hp@redhat.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#include <config.h>
+#include <errno.h>
+#include "gdk-pixbuf-io.h"
+#include "gdk-pixbuf-private.h"
+#include "io-gif-animation.h"
+
+static void gdk_pixbuf_gif_anim_class_init (GdkPixbufGifAnimClass *klass);
+static void gdk_pixbuf_gif_anim_finalize (GObject *object);
+
+static gboolean gdk_pixbuf_gif_anim_is_static_image (GdkPixbufAnimation *animation);
+static GdkPixbuf* gdk_pixbuf_gif_anim_get_static_image (GdkPixbufAnimation *animation);
+
+static void gdk_pixbuf_gif_anim_get_size (GdkPixbufAnimation *anim,
+ int *width,
+ int *height);
+static GdkPixbufAnimationIter* gdk_pixbuf_gif_anim_get_iter (GdkPixbufAnimation *anim,
+ const GTimeVal *start_time);
+
+
+
+
+static gpointer parent_class;
+
+GType
+gdk_pixbuf_gif_anim_get_type (void)
+{
+ static GType object_type = 0;
+
+ if (!object_type) {
+ static const GTypeInfo object_info = {
+ sizeof (GdkPixbufGifAnimClass),
+ (GBaseInitFunc) NULL,
+ (GBaseFinalizeFunc) NULL,
+ (GClassInitFunc) gdk_pixbuf_gif_anim_class_init,
+ NULL, /* class_finalize */
+ NULL, /* class_data */
+ sizeof (GdkPixbufGifAnim),
+ 0, /* n_preallocs */
+ (GInstanceInitFunc) NULL,
+ };
+
+ object_type = g_type_register_static (GDK_TYPE_PIXBUF_ANIMATION,
+ "GdkPixbufGifAnim",
+ &object_info, 0);
+ }
+
+ return object_type;
+}
+
+static void
+gdk_pixbuf_gif_anim_class_init (GdkPixbufGifAnimClass *klass)
+{
+ GObjectClass *object_class = G_OBJECT_CLASS (klass);
+ GdkPixbufAnimationClass *anim_class = GDK_PIXBUF_ANIMATION_CLASS (klass);
+
+ parent_class = g_type_class_peek_parent (klass);
+
+ object_class->finalize = gdk_pixbuf_gif_anim_finalize;
+
+ anim_class->is_static_image = gdk_pixbuf_gif_anim_is_static_image;
+ anim_class->get_static_image = gdk_pixbuf_gif_anim_get_static_image;
+ anim_class->get_size = gdk_pixbuf_gif_anim_get_size;
+ anim_class->get_iter = gdk_pixbuf_gif_anim_get_iter;
+}
+
+static void
+gdk_pixbuf_gif_anim_finalize (GObject *object)
+{
+ GdkPixbufGifAnim *gif_anim = GDK_PIXBUF_GIF_ANIM (object);
+
+ GList *l;
+ GdkPixbufFrame *frame;
+
+ for (l = gif_anim->frames; l; l = l->next) {
+ frame = l->data;
+ gdk_pixbuf_unref (frame->pixbuf);
+ if (frame->composited)
+ gdk_pixbuf_unref (frame->composited);
+ if (frame->revert)
+ gdk_pixbuf_unref (frame->revert);
+ g_free (frame);
+ }
+
+ g_list_free (gif_anim->frames);
+
+ G_OBJECT_CLASS (parent_class)->finalize (object);
+}
+
+static gboolean
+gdk_pixbuf_gif_anim_is_static_image (GdkPixbufAnimation *animation)
+{
+ GdkPixbufGifAnim *gif_anim;
+
+ gif_anim = GDK_PIXBUF_GIF_ANIM (animation);
+
+ return (gif_anim->frames != NULL &&
+ gif_anim->frames->next == NULL);
+}
+
+static GdkPixbuf*
+gdk_pixbuf_gif_anim_get_static_image (GdkPixbufAnimation *animation)
+{
+ GdkPixbufGifAnim *gif_anim;
+
+ gif_anim = GDK_PIXBUF_GIF_ANIM (animation);
+
+ if (gif_anim->frames == NULL)
+ return NULL;
+ else
+ return GDK_PIXBUF (((GdkPixbufFrame*)gif_anim->frames->data)->pixbuf);
+}
+
+static void
+gdk_pixbuf_gif_anim_get_size (GdkPixbufAnimation *anim,
+ int *width,
+ int *height)
+{
+ GdkPixbufGifAnim *gif_anim;
+
+ gif_anim = GDK_PIXBUF_GIF_ANIM (anim);
+
+ if (width)
+ *width = gif_anim->width;
+
+ if (height)
+ *height = gif_anim->height;
+}
+
+
+static void
+iter_clear (GdkPixbufGifAnimIter *iter)
+{
+ iter->current_frame = NULL;
+}
+
+static void
+iter_restart (GdkPixbufGifAnimIter *iter)
+{
+ iter_clear (iter);
+
+ iter->current_frame = iter->gif_anim->frames;
+}
+
+static GdkPixbufAnimationIter*
+gdk_pixbuf_gif_anim_get_iter (GdkPixbufAnimation *anim,
+ const GTimeVal *start_time)
+{
+ GdkPixbufGifAnimIter *iter;
+
+ iter = g_object_new (GDK_TYPE_PIXBUF_GIF_ANIM_ITER, NULL);
+
+ iter->gif_anim = GDK_PIXBUF_GIF_ANIM (anim);
+
+ g_object_ref (G_OBJECT (iter->gif_anim));
+
+ iter_restart (iter);
+
+ iter->start_time = *start_time;
+ iter->current_time = *start_time;
+
+ return GDK_PIXBUF_ANIMATION_ITER (iter);
+}
+
+
+
+static void gdk_pixbuf_gif_anim_iter_class_init (GdkPixbufGifAnimIterClass *klass);
+static void gdk_pixbuf_gif_anim_iter_finalize (GObject *object);
+
+static int gdk_pixbuf_gif_anim_iter_get_delay_time (GdkPixbufAnimationIter *iter);
+static GdkPixbuf* gdk_pixbuf_gif_anim_iter_get_pixbuf (GdkPixbufAnimationIter *iter);
+static gboolean gdk_pixbuf_gif_anim_iter_on_currently_loading_frame (GdkPixbufAnimationIter *iter);
+static gboolean gdk_pixbuf_gif_anim_iter_advance (GdkPixbufAnimationIter *iter,
+ const GTimeVal *current_time);
+
+
+
+static gpointer iter_parent_class;
+
+GType
+gdk_pixbuf_gif_anim_iter_get_type (void)
+{
+ static GType object_type = 0;
+
+ if (!object_type) {
+ static const GTypeInfo object_info = {
+ sizeof (GdkPixbufGifAnimIterClass),
+ (GBaseInitFunc) NULL,
+ (GBaseFinalizeFunc) NULL,
+ (GClassInitFunc) gdk_pixbuf_gif_anim_iter_class_init,
+ NULL, /* class_finalize */
+ NULL, /* class_data */
+ sizeof (GdkPixbufGifAnimIter),
+ 0, /* n_preallocs */
+ (GInstanceInitFunc) NULL,
+ };
+
+ object_type = g_type_register_static (GDK_TYPE_PIXBUF_ANIMATION_ITER,
+ "GdkPixbufGifAnimIter",
+ &object_info, 0);
+ }
+
+ return object_type;
+}
+
+static void
+gdk_pixbuf_gif_anim_iter_class_init (GdkPixbufGifAnimIterClass *klass)
+{
+ GObjectClass *object_class = G_OBJECT_CLASS (klass);
+ GdkPixbufAnimationIterClass *anim_iter_class =
+ GDK_PIXBUF_ANIMATION_ITER_CLASS (klass);
+
+ iter_parent_class = g_type_class_peek_parent (klass);
+
+ object_class->finalize = gdk_pixbuf_gif_anim_iter_finalize;
+
+ anim_iter_class->get_delay_time = gdk_pixbuf_gif_anim_iter_get_delay_time;
+ anim_iter_class->get_pixbuf = gdk_pixbuf_gif_anim_iter_get_pixbuf;
+ anim_iter_class->on_currently_loading_frame = gdk_pixbuf_gif_anim_iter_on_currently_loading_frame;
+ anim_iter_class->advance = gdk_pixbuf_gif_anim_iter_advance;
+}
+
+static void
+gdk_pixbuf_gif_anim_iter_finalize (GObject *object)
+{
+ GdkPixbufGifAnimIter *iter = GDK_PIXBUF_GIF_ANIM_ITER (object);
+
+ iter_clear (iter);
+
+ g_object_unref (G_OBJECT (iter->gif_anim));
+
+ G_OBJECT_CLASS (iter_parent_class)->finalize (object);
+}
+
+static gboolean
+gdk_pixbuf_gif_anim_iter_advance (GdkPixbufAnimationIter *anim_iter,
+ const GTimeVal *current_time)
+{
+ GdkPixbufGifAnimIter *iter;
+ gint elapsed;
+ GList *tmp;
+ GList *old;
+
+ iter = GDK_PIXBUF_GIF_ANIM_ITER (anim_iter);
+
+ iter->current_time = *current_time;
+
+ /* We use milliseconds for all times */
+ elapsed =
+ (((iter->current_time.tv_sec - iter->start_time.tv_sec) * G_USEC_PER_SEC +
+ iter->current_time.tv_usec - iter->start_time.tv_usec)) / 1000;
+
+ if (elapsed < 0) {
+ /* Try to compensate; probably the system clock
+ * was set backwards
+ */
+ iter->start_time = iter->current_time;
+ elapsed = 0;
+ }
+
+ /* See how many times we've already played the full animation,
+ * and subtract time for that.
+ */
+ elapsed = elapsed % iter->gif_anim->total_time;
+
+ g_assert (elapsed < iter->gif_anim->total_time);
+
+ iter->position = elapsed;
+
+ /* Now move to the proper frame */
+ tmp = iter->gif_anim->frames;
+ while (tmp != NULL) {
+ GdkPixbufFrame *frame = tmp->data;
+
+ if (iter->position >= frame->elapsed &&
+ iter->position < (frame->elapsed + frame->delay_time))
+ break;
+
+ tmp = tmp->next;
+ }
+
+ old = iter->current_frame;
+
+ iter->current_frame = tmp;
+
+ return iter->current_frame != old;
+}
+
+int
+gdk_pixbuf_gif_anim_iter_get_delay_time (GdkPixbufAnimationIter *anim_iter)
+{
+ GdkPixbufFrame *frame;
+ GdkPixbufGifAnimIter *iter;
+
+ iter = GDK_PIXBUF_GIF_ANIM_ITER (anim_iter);
+
+ if (iter->current_frame) {
+ frame = iter->current_frame->data;
+
+#if 0
+ g_print ("frame start: %d pos: %d frame len: %d frame remaining: %d\n",
+ frame->elapsed,
+ iter->position,
+ frame->delay_time,
+ frame->delay_time - (iter->position - frame->elapsed));
+#endif
+
+ return frame->delay_time - (iter->position - frame->elapsed);
+ } else {
+ return -1; /* show last frame forever */
+ }
+}
+
+void
+gdk_pixbuf_gif_anim_frame_composite (GdkPixbufGifAnim *gif_anim,
+ GdkPixbufFrame *frame)
+{
+ GList *link;
+ GList *tmp;
+
+ link = g_list_find (gif_anim->frames, frame);
+
+ if (frame->need_recomposite || frame->composited == NULL) {
+ /* For now, to composite we start with the last
+ * composited frame and composite everything up to
+ * here.
+ */
+
+ /* Rewind to last composited frame. */
+ tmp = link;
+ while (tmp != NULL) {
+ GdkPixbufFrame *f = tmp->data;
+
+ if (f->need_recomposite) {
+ if (f->composited) {
+ g_object_unref (G_OBJECT (f->composited));
+ f->composited = NULL;
+ }
+ }
+
+ if (f->composited != NULL)
+ break;
+
+ tmp = tmp->prev;
+ }
+
+ /* Go forward, compositing all frames up to the current frame */
+ if (tmp == NULL)
+ tmp = gif_anim->frames;
+
+ while (tmp != NULL) {
+ GdkPixbufFrame *f = tmp->data;
+
+ if (f->need_recomposite) {
+ if (f->composited) {
+ g_object_unref (G_OBJECT (f->composited));
+ f->composited = NULL;
+ }
+ }
+
+ if (f->composited != NULL)
+ goto next;
+
+ if (tmp->prev == NULL) {
+ /* First frame may be smaller than the whole image;
+ * if so, we make the area outside it full alpha if the
+ * image has alpha, and background color otherwise.
+ * GIF spec doesn't actually say what to do about this.
+ */
+ f->composited = gdk_pixbuf_new (GDK_COLORSPACE_RGB,
+ TRUE,
+ 8, gif_anim->width, gif_anim->height);
+
+ /* alpha gets dumped if f->composited has no alpha */
+
+ gdk_pixbuf_fill (f->composited,
+ (gif_anim->bg_red << 24) |
+ (gif_anim->bg_green << 16) |
+ (gif_anim->bg_blue << 8) |
+ (f->bg_transparent ? 0 : 255));
+
+ gdk_pixbuf_composite (f->pixbuf,
+ f->composited,
+ f->x_offset,
+ f->y_offset,
+ gdk_pixbuf_get_width (f->pixbuf),
+ gdk_pixbuf_get_height (f->pixbuf),
+ f->x_offset, f->y_offset,
+ 1.0, 1.0,
+ GDK_INTERP_BILINEAR,
+ 255);
+#if 0
+ gdk_pixbuf_copy_area (f->pixbuf,
+ 0, 0,
+ gdk_pixbuf_get_width (f->pixbuf),
+ gdk_pixbuf_get_height (f->pixbuf),
+ f->composited,
+ f->x_offset,
+ f->y_offset);
+
+#endif
+
+ if (f->action == GDK_PIXBUF_FRAME_REVERT)
+ g_warning ("First frame of GIF has bad dispose mode, GIF loader should not have loaded this image");
+
+ f->need_recomposite = FALSE;
+ } else {
+ GdkPixbufFrame *prev_frame;
+
+ prev_frame = tmp->prev->data;
+
+ /* Init f->composited with what we should have after the previous
+ * frame
+ */
+
+ if (prev_frame->action == GDK_PIXBUF_FRAME_RETAIN) {
+ f->composited = gdk_pixbuf_copy (prev_frame->composited);
+
+ } else if (prev_frame->action == GDK_PIXBUF_FRAME_DISPOSE) {
+ GdkPixbuf *area;
+
+ f->composited = gdk_pixbuf_copy (prev_frame->composited);
+
+ /* Clear area of previous frame to background */
+ area = gdk_pixbuf_new_subpixbuf (f->composited,
+ prev_frame->x_offset,
+ prev_frame->y_offset,
+ gdk_pixbuf_get_width (prev_frame->pixbuf),
+ gdk_pixbuf_get_height (prev_frame->pixbuf));
+
+ gdk_pixbuf_fill (area,
+ (gif_anim->bg_red << 24) |
+ (gif_anim->bg_green << 16) |
+ (gif_anim->bg_blue << 8) |
+ prev_frame->bg_transparent ? 0 : 255);
+
+ g_object_unref (G_OBJECT (area));
+
+ } else if (prev_frame->action == GDK_PIXBUF_FRAME_REVERT) {
+ f->composited = gdk_pixbuf_copy (prev_frame->composited);
+
+ /* Copy in the revert frame */
+ gdk_pixbuf_copy_area (prev_frame->revert,
+ 0, 0,
+ gdk_pixbuf_get_width (prev_frame->revert),
+ gdk_pixbuf_get_height (prev_frame->revert),
+ f->composited,
+ prev_frame->x_offset,
+ prev_frame->y_offset);
+ } else {
+ g_warning ("Unknown revert action for GIF frame");
+ }
+
+ if (f->revert == NULL &&
+ f->action == GDK_PIXBUF_FRAME_REVERT) {
+ /* We need to save the contents before compositing */
+ GdkPixbuf *area;
+
+ area = gdk_pixbuf_new_subpixbuf (f->composited,
+ f->x_offset,
+ f->y_offset,
+ gdk_pixbuf_get_width (f->pixbuf),
+ gdk_pixbuf_get_height (f->pixbuf));
+
+ f->revert = gdk_pixbuf_copy (area);
+
+ g_object_unref (G_OBJECT (area));
+ }
+
+ /* Put current frame onto f->composited */
+ gdk_pixbuf_composite (f->pixbuf,
+ f->composited,
+ f->x_offset,
+ f->y_offset,
+ gdk_pixbuf_get_width (f->pixbuf),
+ gdk_pixbuf_get_height (f->pixbuf),
+ f->x_offset, f->y_offset,
+ 1.0, 1.0,
+ GDK_INTERP_NEAREST,
+ 255);
+
+ f->need_recomposite = FALSE;
+ }
+
+ next:
+ if (tmp == link)
+ break;
+
+ tmp = tmp->next;
+ }
+ }
+
+ g_assert (frame->composited != NULL);
+ g_assert (gdk_pixbuf_get_width (frame->composited) == gif_anim->width);
+ g_assert (gdk_pixbuf_get_height (frame->composited) == gif_anim->height);
+}
+
+GdkPixbuf*
+gdk_pixbuf_gif_anim_iter_get_pixbuf (GdkPixbufAnimationIter *anim_iter)
+{
+ GdkPixbufGifAnimIter *iter;
+ GdkPixbufFrame *frame;
+
+ iter = GDK_PIXBUF_GIF_ANIM_ITER (anim_iter);
+
+ frame = iter->current_frame ? iter->current_frame->data : NULL;
+
+#if 0
+ if (FALSE && frame)
+ g_print ("current frame %d dispose mode %d %d x %d\n",
+ g_list_index (iter->gif_anim->frames,
+ frame),
+ frame->action,
+ gdk_pixbuf_get_width (frame->pixbuf),
+ gdk_pixbuf_get_height (frame->pixbuf));
+#endif
+
+ if (frame == NULL)
+ return NULL;
+
+ gdk_pixbuf_gif_anim_frame_composite (iter->gif_anim, frame);
+
+ return frame->composited;
+}
+
+static gboolean
+gdk_pixbuf_gif_anim_iter_on_currently_loading_frame (GdkPixbufAnimationIter *anim_iter)
+{
+ GdkPixbufGifAnimIter *iter;
+
+ iter = GDK_PIXBUF_GIF_ANIM_ITER (anim_iter);
+
+ return iter->current_frame == NULL || iter->current_frame->next == NULL;
+}
diff --git a/gdk-pixbuf/io-gif-animation.h b/gdk-pixbuf/io-gif-animation.h
new file mode 100644
index 000000000..ce1ebaa6f
--- /dev/null
+++ b/gdk-pixbuf/io-gif-animation.h
@@ -0,0 +1,169 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*- */
+/* GdkPixbuf library - GIF loader declarations
+ *
+ * Copyright (C) 1999 The Free Software Foundation
+ *
+ * Authors: Mark Crichton <crichton@gimp.org>
+ * Miguel de Icaza <miguel@gnu.org>
+ * Federico Mena-Quintero <federico@gimp.org>
+ * Havoc Pennington <hp@redhat.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#ifndef GDK_PIXBUF_GIF_H
+#define GDK_PIXBUF_GIF_H
+
+#include "gdk-pixbuf-private.h"
+
+typedef enum {
+ /* Keep this frame and composite next frame over it */
+ /* (GIF disposal method 1) */
+ GDK_PIXBUF_FRAME_RETAIN,
+ /* Revert to background color before compositing next frame */
+ /* (GIF disposal method 2) */
+ GDK_PIXBUF_FRAME_DISPOSE,
+ /* Revert to previously-displayed composite image after
+ * displaying this frame
+ */
+ /* (GIF disposal method 3) */
+ GDK_PIXBUF_FRAME_REVERT
+} GdkPixbufFrameAction;
+
+
+
+typedef struct _GdkPixbufGifAnim GdkPixbufGifAnim;
+typedef struct _GdkPixbufGifAnimClass GdkPixbufGifAnimClass;
+
+#define GDK_TYPE_PIXBUF_GIF_ANIM (gdk_pixbuf_gif_anim_get_type ())
+#define GDK_PIXBUF_GIF_ANIM(object) (G_TYPE_CHECK_INSTANCE_CAST ((object), GDK_TYPE_PIXBUF_GIF_ANIM, GdkPixbufGifAnim))
+#define GDK_IS_PIXBUF_GIF_ANIM(object) (G_TYPE_CHECK_INSTANCE_TYPE ((object), GDK_TYPE_PIXBUF_GIF_ANIM))
+
+#define GDK_PIXBUF_GIF_ANIM_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GDK_TYPE_PIXBUF_GIF_ANIM, GdkPixbufGifAnimClass))
+#define GDK_IS_PIXBUF_GIF_ANIM_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GDK_TYPE_PIXBUF_GIF_ANIM))
+#define GDK_PIXBUF_GIF_ANIM_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GDK_TYPE_PIXBUF_GIF_ANIM, GdkPixbufGifAnimClass))
+
+/* Private part of the GdkPixbufGifAnim structure */
+struct _GdkPixbufGifAnim {
+ GdkPixbufAnimation parent_instance;
+
+ /* Number of frames */
+ int n_frames;
+
+ /* Total length of animation */
+ int total_time;
+
+ /* List of GdkPixbufFrame structures */
+ GList *frames;
+
+ /* bounding box size */
+ int width, height;
+
+ guchar bg_red;
+ guchar bg_green;
+ guchar bg_blue;
+};
+
+struct _GdkPixbufGifAnimClass {
+ GdkPixbufAnimationClass parent_class;
+
+};
+
+GType gdk_pixbuf_gif_anim_get_type (void) G_GNUC_CONST;
+
+
+
+typedef struct _GdkPixbufGifAnimIter GdkPixbufGifAnimIter;
+typedef struct _GdkPixbufGifAnimIterClass GdkPixbufGifAnimIterClass;
+
+
+#define GDK_TYPE_PIXBUF_GIF_ANIM_ITER (gdk_pixbuf_gif_anim_iter_get_type ())
+#define GDK_PIXBUF_GIF_ANIM_ITER(object) (G_TYPE_CHECK_INSTANCE_CAST ((object), GDK_TYPE_PIXBUF_GIF_ANIM_ITER, GdkPixbufGifAnimIter))
+#define GDK_IS_PIXBUF_GIF_ANIM_ITER(object) (G_TYPE_CHECK_INSTANCE_TYPE ((object), GDK_TYPE_PIXBUF_GIF_ANIM_ITER))
+
+#define GDK_PIXBUF_GIF_ANIM_ITER_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GDK_TYPE_PIXBUF_GIF_ANIM_ITER, GdkPixbufGifAnimIterClass))
+#define GDK_IS_PIXBUF_GIF_ANIM_ITER_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GDK_TYPE_PIXBUF_GIF_ANIM_ITER))
+#define GDK_PIXBUF_GIF_ANIM_ITER_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GDK_TYPE_PIXBUF_GIF_ANIM_ITER, GdkPixbufGifAnimIterClass))
+
+struct _GdkPixbufGifAnimIter {
+ GdkPixbufAnimationIter parent_instance;
+
+ GdkPixbufGifAnim *gif_anim;
+
+ GTimeVal start_time;
+ GTimeVal current_time;
+
+ /* Time in milliseconds into this run of the animation */
+ gint position;
+
+ GList *current_frame;
+};
+
+struct _GdkPixbufGifAnimIterClass {
+ GdkPixbufAnimationIterClass parent_class;
+
+};
+
+GType gdk_pixbuf_gif_anim_iter_get_type (void) G_GNUC_CONST;
+
+
+
+struct _GdkPixbufFrame {
+ /* The pixbuf with this frame's image data */
+ GdkPixbuf *pixbuf;
+
+ /* Offsets for overlaying onto the GIF graphic area */
+ int x_offset;
+ int y_offset;
+
+ /* Frame duration in ms */
+ int delay_time;
+
+ /* Sum of preceding delay times */
+ int elapsed;
+
+ /* Overlay mode */
+ GdkPixbufFrameAction action;
+
+ /* TRUE if the pixbuf has been modified since
+ * the last frame composite operation
+ */
+ gboolean need_recomposite;
+
+ /* TRUE if the background for this frame is transparent */
+ gboolean bg_transparent;
+
+ /* The below reflects the "use hell of a lot of RAM"
+ * philosophy of coding
+ */
+
+ /* Cached composite image (the image you actually display
+ * for this frame)
+ */
+ GdkPixbuf *composited;
+
+ /* Cached revert image (the contents of the area
+ * covered by the frame prior to compositing;
+ * same size as pixbuf, not as the composite image; only
+ * used for FRAME_REVERT frames)
+ */
+ GdkPixbuf *revert;
+};
+
+void gdk_pixbuf_gif_anim_frame_composite (GdkPixbufGifAnim *gif_anim,
+ GdkPixbufFrame *frame);
+
+#endif
diff --git a/gdk-pixbuf/io-gif.c b/gdk-pixbuf/io-gif.c
index 5be68023f..c3c1b8728 100644
--- a/gdk-pixbuf/io-gif.c
+++ b/gdk-pixbuf/io-gif.c
@@ -1,3 +1,4 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*- */
/* GdkPixbuf library - GIF image loader
*
* Copyright (C) 1999 Mark Crichton
@@ -30,10 +31,6 @@
* in it got a bit messy. Basicly, every function is written to expect a failed
* read_gif, and lets you call it again assuming that the bytes are there.
*
- * A note on Animations:
- * Currently, it doesn't correctly read the different colormap per frame. This
- * needs implementing sometime.
- *
* Return vals.
* Unless otherwise specified, these are the return vals for most functions:
*
@@ -59,11 +56,15 @@
#include <config.h>
#include <stdio.h>
#include <string.h>
+#include <errno.h>
#include "gdk-pixbuf-private.h"
#include "gdk-pixbuf-io.h"
+#include "io-gif-animation.h"
+#undef DUMP_IMAGE_DETAILS
+
#define MAXCOLORMAPSIZE 256
#define MAX_LZW_BITS 12
@@ -88,7 +89,7 @@ enum {
GIF_LZW_FILL_BUFFER,
GIF_LZW_CLEAR_CODE,
GIF_GET_LZW,
- GIF_DONE,
+ GIF_DONE
};
@@ -107,19 +108,27 @@ struct _GifContext
int state; /* really only relevant for progressive loading */
unsigned int width;
unsigned int height;
- CMap color_map;
- CMap frame_color_map;
- unsigned int bit_pixel;
- unsigned int color_resolution;
- unsigned int background;
+
+ gboolean has_global_cmap;
+
+ CMap global_color_map;
+ gint global_colormap_size;
+ unsigned int global_bit_pixel;
+ unsigned int global_color_resolution;
+ unsigned int background_index;
+
+ gboolean frame_cmap_active;
+ CMap frame_color_map;
+ gint frame_colormap_size;
+ unsigned int frame_bit_pixel;
+
unsigned int aspect_ratio;
GdkPixbuf *pixbuf;
- GdkPixbufAnimation *animation;
+ GdkPixbufGifAnim *animation;
GdkPixbufFrame *frame;
Gif89 gif89;
- /* stuff per frame. As we only support the first one, not so
- * relevant. But still needed */
+ /* stuff per frame. */
int frame_len;
int frame_height;
int frame_interlace;
@@ -132,18 +141,12 @@ struct _GifContext
/* progressive read, only. */
ModulePreparedNotifyFunc prepare_func;
ModuleUpdatedNotifyFunc update_func;
- ModuleFrameDoneNotifyFunc frame_done_func;
- ModuleAnimationDoneNotifyFunc anim_done_func;
gpointer user_data;
guchar *buf;
guint ptr;
guint size;
guint amount_needed;
- /* colormap context */
- gint colormap_index;
- gint colormap_flag;
-
/* extension context */
guchar extension_label;
guchar extension_flag;
@@ -207,7 +210,14 @@ gif_read (GifContext *context, guchar *buffer, size_t len)
count += len;
g_print ("Fsize :%d\tcount :%d\t", len, count);
#endif
- retval = (fread(buffer, len, 1, context->file) != 0);
+ retval = (fread(buffer, len, 1, context->file) != 0);
+
+ if (!retval && ferror (context->file))
+ g_set_error (context->error,
+ G_FILE_ERROR,
+ g_file_error_from_errno (errno),
+ _("Failure reading GIF: %s"), strerror (errno));
+
#ifdef IO_GIFDEBUG
if (len < 100) {
for (i = 0; i < len; i++)
@@ -247,16 +257,14 @@ gif_read (GifContext *context, guchar *buffer, size_t len)
static void
gif_set_get_colormap (GifContext *context)
{
- context->colormap_flag = TRUE;
- context->colormap_index = 0;
+ context->global_colormap_size = 0;
context->state = GIF_GET_COLORMAP;
}
static void
gif_set_get_colormap2 (GifContext *context)
{
- context->colormap_flag = TRUE;
- context->colormap_index = 0;
+ context->frame_colormap_size = 0;
context->state = GIF_GET_COLORMAP2;
}
@@ -265,18 +273,43 @@ gif_get_colormap (GifContext *context)
{
unsigned char rgb[3];
- while (context->colormap_index < context->bit_pixel) {
+ while (context->global_colormap_size < context->global_bit_pixel) {
+ if (!gif_read (context, rgb, sizeof (rgb))) {
+ return -1;
+ }
+
+ context->global_color_map[0][context->global_colormap_size] = rgb[0];
+ context->global_color_map[1][context->global_colormap_size] = rgb[1];
+ context->global_color_map[2][context->global_colormap_size] = rgb[2];
+
+ if (context->global_colormap_size == context->background_index) {
+ context->animation->bg_red = rgb[0];
+ context->animation->bg_green = rgb[1];
+ context->animation->bg_blue = rgb[2];
+ }
+
+ context->global_colormap_size ++;
+ }
+
+ return 0;
+}
+
+
+static gint
+gif_get_colormap2 (GifContext *context)
+{
+ unsigned char rgb[3];
+
+ while (context->frame_colormap_size < context->frame_bit_pixel) {
if (!gif_read (context, rgb, sizeof (rgb))) {
- /*g_message (_("GIF: bad colormap\n"));*/
return -1;
}
- context->color_map[0][context->colormap_index] = rgb[0];
- context->color_map[1][context->colormap_index] = rgb[1];
- context->color_map[2][context->colormap_index] = rgb[2];
+ context->frame_color_map[0][context->frame_colormap_size] = rgb[0];
+ context->frame_color_map[1][context->frame_colormap_size] = rgb[1];
+ context->frame_color_map[2][context->frame_colormap_size] = rgb[2];
- context->colormap_flag &= (rgb[0] == rgb[1] && rgb[1] == rgb[2]);
- context->colormap_index ++;
+ context->frame_colormap_size ++;
}
return 0;
@@ -348,9 +381,11 @@ gif_get_extension (GifContext *context)
retval = get_data_block (context, (unsigned char *) context->block_buf, NULL);
if (retval != 0)
return retval;
- if (context->pixbuf == NULL) {
+
+ if (context->frame == NULL) {
/* I only want to set the transparency if I haven't
- * created the pixbuf yet. */
+ * created the frame yet.
+ */
context->gif89.disposal = (context->block_buf[0] >> 2) & 0x7;
context->gif89.input_flag = (context->block_buf[0] >> 1) & 0x1;
context->gif89.delay_time = LM_to_uint (context->block_buf[1], context->block_buf[2]);
@@ -623,18 +658,24 @@ static void
gif_fill_in_pixels (GifContext *context, guchar *dest, gint offset, guchar v)
{
guchar *pixel = NULL;
+ guchar (*cmap)[MAXCOLORMAPSIZE];
+ if (context->frame_cmap_active)
+ cmap = context->frame_color_map;
+ else
+ cmap = context->global_color_map;
+
if (context->gif89.transparent != -1) {
- pixel = dest + (context->draw_ypos + offset) * gdk_pixbuf_get_rowstride (context->pixbuf) + context->draw_xpos * 4;
- *pixel = context->color_map [0][(guchar) v];
- *(pixel+1) = context->color_map [1][(guchar) v];
- *(pixel+2) = context->color_map [2][(guchar) v];
- *(pixel+3) = (guchar) ((v == context->gif89.transparent) ? 0 : 65535);
+ pixel = dest + (context->draw_ypos + offset) * gdk_pixbuf_get_rowstride (context->frame->pixbuf) + context->draw_xpos * 4;
+ *pixel = cmap [0][(guchar) v];
+ *(pixel+1) = cmap [1][(guchar) v];
+ *(pixel+2) = cmap [2][(guchar) v];
+ *(pixel+3) = (guchar) ((v == context->gif89.transparent) ? 0 : 255);
} else {
- pixel = dest + (context->draw_ypos + offset) * gdk_pixbuf_get_rowstride (context->pixbuf) + context->draw_xpos * 3;
- *pixel = context->color_map [0][(guchar) v];
- *(pixel+1) = context->color_map [1][(guchar) v];
- *(pixel+2) = context->color_map [2][(guchar) v];
+ pixel = dest + (context->draw_ypos + offset) * gdk_pixbuf_get_rowstride (context->frame->pixbuf) + context->draw_xpos * 3;
+ *pixel = cmap [0][(guchar) v];
+ *(pixel+1) = cmap [1][(guchar) v];
+ *(pixel+2) = cmap [2][(guchar) v];
}
}
@@ -682,80 +723,123 @@ gif_get_lzw (GifContext *context)
gint first_pass; /* bounds for emitting the area_updated signal */
gint v;
- if (context->pixbuf == NULL) {
- context->pixbuf = gdk_pixbuf_new (GDK_COLORSPACE_RGB,
- context->gif89.transparent != -1,
- 8,
- context->frame_len,
- context->frame_height);
-
- if (context->prepare_func)
- (* context->prepare_func) (context->pixbuf, context->user_data);
- if (context->animation || context->frame_done_func || context->anim_done_func) {
- context->frame = g_new (GdkPixbufFrame, 1);
- context->frame->x_offset = context->x_offset;
- context->frame->y_offset = context->y_offset;;
- context->frame->delay_time = context->gif89.delay_time;
- switch (context->gif89.disposal) {
- case 0:
- case 1:
- context->frame->action = GDK_PIXBUF_FRAME_RETAIN;
- break;
- case 2:
- context->frame->action = GDK_PIXBUF_FRAME_DISPOSE;
- break;
- case 3:
- context->frame->action = GDK_PIXBUF_FRAME_REVERT;
- break;
- default:
- context->frame->action = GDK_PIXBUF_FRAME_RETAIN;
- break;
- }
- context->frame->pixbuf = context->pixbuf;
- if (context->animation) {
- int w,h;
- context->animation->n_frames ++;
- context->animation->frames = g_list_append (context->animation->frames, context->frame);
- w = gdk_pixbuf_get_width (context->pixbuf);
- h = gdk_pixbuf_get_height (context->pixbuf);
- if (w > context->animation->width)
- context->animation->width = w;
- if (h > context->animation->height)
- context->animation->height = h;
- }
- }
- }
- dest = gdk_pixbuf_get_pixels (context->pixbuf);
+ if (context->frame == NULL) {
+ context->frame = g_new (GdkPixbufFrame, 1);
+
+ context->frame->composited = NULL;
+ context->frame->revert = NULL;
+
+ context->frame->pixbuf =
+ gdk_pixbuf_new (GDK_COLORSPACE_RGB,
+ TRUE,
+ 8,
+ context->frame_len,
+ context->frame_height);
+
+ context->frame->x_offset = context->x_offset;
+ context->frame->y_offset = context->y_offset;
+ context->frame->need_recomposite = TRUE;
+
+ /* GIF delay is in hundredths, we want thousandths */
+ context->frame->delay_time = context->gif89.delay_time * 10;
+ context->frame->elapsed = context->animation->total_time;
+ context->animation->total_time += context->frame->delay_time;
+
+ switch (context->gif89.disposal) {
+ case 0:
+ case 1:
+ context->frame->action = GDK_PIXBUF_FRAME_RETAIN;
+ break;
+ case 2:
+ context->frame->action = GDK_PIXBUF_FRAME_DISPOSE;
+ break;
+ case 3:
+ context->frame->action = GDK_PIXBUF_FRAME_REVERT;
+ break;
+ default:
+ context->frame->action = GDK_PIXBUF_FRAME_RETAIN;
+ break;
+ }
+
+ context->frame->bg_transparent = (context->gif89.transparent == context->background_index);
+
+ {
+ /* Update animation size */
+ int w, h;
+
+ context->animation->n_frames ++;
+ context->animation->frames = g_list_append (context->animation->frames, context->frame);
+
+ w = context->frame->x_offset +
+ gdk_pixbuf_get_width (context->frame->pixbuf);
+ h = context->frame->y_offset +
+ gdk_pixbuf_get_height (context->frame->pixbuf);
+ if (w > context->animation->width)
+ context->animation->width = w;
+ if (h > context->animation->height)
+ context->animation->height = h;
+ }
+
+ /* Only call prepare_func for the first frame */
+ if (context->animation->frames->next == NULL) {
+ if (context->prepare_func)
+ (* context->prepare_func) (context->frame->pixbuf,
+ GDK_PIXBUF_ANIMATION (context->animation),
+ context->user_data);
+ } else {
+ /* Otherwise init frame with last frame */
+ GList *link;
+ GdkPixbufFrame *prev_frame;
+
+ link = g_list_find (context->animation->frames, context->frame);
+
+ prev_frame = link->prev->data;
+
+ gdk_pixbuf_gif_anim_frame_composite (context->animation, prev_frame);
+
+ gdk_pixbuf_copy_area (prev_frame->composited,
+ context->frame->x_offset,
+ context->frame->y_offset,
+ gdk_pixbuf_get_width (context->frame->pixbuf),
+ gdk_pixbuf_get_height (context->frame->pixbuf),
+ context->frame->pixbuf,
+ 0, 0);
+ }
+ }
+
+ dest = gdk_pixbuf_get_pixels (context->frame->pixbuf);
bound_flag = FALSE;
lower_bound = upper_bound = context->draw_ypos;
first_pass = context->draw_pass;
while (TRUE) {
+ guchar (*cmap)[MAXCOLORMAPSIZE];
+
+ if (context->frame_cmap_active)
+ cmap = context->frame_color_map;
+ else
+ cmap = context->global_color_map;
+
v = lzw_read_byte (context);
if (v < 0) {
goto finished_data;
}
bound_flag = TRUE;
- if (context->gif89.transparent != -1) {
- temp = dest + context->draw_ypos * gdk_pixbuf_get_rowstride (context->pixbuf) + context->draw_xpos * 4;
- *temp = context->color_map [0][(guchar) v];
- *(temp+1) = context->color_map [1][(guchar) v];
- *(temp+2) = context->color_map [2][(guchar) v];
- *(temp+3) = (guchar) ((v == context->gif89.transparent) ? 0 : -1);
- } else {
- temp = dest + context->draw_ypos * gdk_pixbuf_get_rowstride (context->pixbuf) + context->draw_xpos * 3;
- *temp = context->color_map [0][(guchar) v];
- *(temp+1) = context->color_map [1][(guchar) v];
- *(temp+2) = context->color_map [2][(guchar) v];
- }
+ g_assert (gdk_pixbuf_get_has_alpha (context->frame->pixbuf));
+
+ temp = dest + context->draw_ypos * gdk_pixbuf_get_rowstride (context->frame->pixbuf) + context->draw_xpos * 4;
+ *temp = cmap [0][(guchar) v];
+ *(temp+1) = cmap [1][(guchar) v];
+ *(temp+2) = cmap [2][(guchar) v];
+ *(temp+3) = (guchar) ((v == context->gif89.transparent) ? 0 : 255);
if (context->prepare_func && context->frame_interlace)
gif_fill_in_lines (context, dest, v);
context->draw_xpos++;
-
+
if (context->draw_xpos == context->frame_len) {
context->draw_xpos = 0;
if (context->frame_interlace) {
@@ -796,7 +880,7 @@ gif_get_lzw (GifContext *context)
lower_bound = 0;
upper_bound = context->frame_height;
} else {
-
+
}
} else
upper_bound = context->draw_ypos;
@@ -804,56 +888,60 @@ gif_get_lzw (GifContext *context)
if (context->draw_ypos >= context->frame_height)
break;
}
+
done:
- /* we got enough data. there may be more (ie, newer layers) but we can quit now */
- if (context->animation || context->frame_done_func || context->anim_done_func) {
- context->state = GIF_GET_NEXT_STEP;
- } else
- context->state = GIF_DONE;
- v = 0;
+
+ context->state = GIF_GET_NEXT_STEP;
+
+ v = 0;
+
finished_data:
+
+ if (bound_flag)
+ context->frame->need_recomposite = TRUE;
+
if (bound_flag && context->update_func) {
if (lower_bound <= upper_bound && first_pass == context->draw_pass) {
(* context->update_func)
- (context->pixbuf,
+ (context->frame->pixbuf,
0, lower_bound,
- gdk_pixbuf_get_width (context->pixbuf),
+ gdk_pixbuf_get_width (context->frame->pixbuf),
upper_bound - lower_bound,
context->user_data);
} else {
if (lower_bound <= upper_bound) {
(* context->update_func)
- (context->pixbuf,
- 0, 0,
- gdk_pixbuf_get_width (context->pixbuf),
- gdk_pixbuf_get_height (context->pixbuf),
+ (context->frame->pixbuf,
+ context->frame->x_offset,
+ context->frame->y_offset,
+ gdk_pixbuf_get_width (context->frame->pixbuf),
+ gdk_pixbuf_get_height (context->frame->pixbuf),
context->user_data);
} else {
(* context->update_func)
- (context->pixbuf,
- 0, 0,
- gdk_pixbuf_get_width (context->pixbuf),
+ (context->frame->pixbuf,
+ context->frame->x_offset,
+ context->frame->y_offset,
+ gdk_pixbuf_get_width (context->frame->pixbuf),
upper_bound,
context->user_data);
(* context->update_func)
- (context->pixbuf,
- 0, lower_bound,
- gdk_pixbuf_get_width (context->pixbuf),
- gdk_pixbuf_get_height (context->pixbuf),
+ (context->frame->pixbuf,
+ context->frame->x_offset,
+ lower_bound + context->frame->y_offset,
+ gdk_pixbuf_get_width (context->frame->pixbuf),
+ gdk_pixbuf_get_height (context->frame->pixbuf),
context->user_data);
}
}
}
- if ((context->animation || context->frame_done_func || context->anim_done_func)
- && context->state == GIF_GET_NEXT_STEP) {
- if (context->frame_done_func)
- (* context->frame_done_func) (context->frame,
- context->user_data);
- if (context->frame_done_func)
- gdk_pixbuf_unref (context->pixbuf);
- context->pixbuf = NULL;
+ if (context->state == GIF_GET_NEXT_STEP) {
+ /* Will be freed with context->animation, we are just
+ * marking that we're done with it (no current frame)
+ */
context->frame = NULL;
+ context->frame_cmap_active = FALSE;
}
return v;
@@ -943,16 +1031,36 @@ gif_init (GifContext *context)
context->width = LM_to_uint (buf[0], buf[1]);
context->height = LM_to_uint (buf[2], buf[3]);
- context->bit_pixel = 2 << (buf[4] & 0x07);
- context->color_resolution = (((buf[4] & 0x70) >> 3) + 1);
- context->background = buf[5];
+ /* The 4th byte is
+ * high bit: whether to use the background index
+ * next 3: color resolution
+ * next: whether colormap is sorted by priority of allocation
+ * last 3: size of colormap
+ */
+ context->global_bit_pixel = 2 << (buf[4] & 0x07);
+ context->global_color_resolution = (((buf[4] & 0x70) >> 3) + 1);
+ context->has_global_cmap = (buf[4] & 0x80) != 0;
+ context->background_index = buf[5];
context->aspect_ratio = buf[6];
- if (BitSet (buf[4], LOCALCOLORMAP)) {
+ /* Use background of transparent black as default, though if
+ * one isn't set explicitly no one should ever use it.
+ */
+ context->animation->bg_red = 0;
+ context->animation->bg_green = 0;
+ context->animation->bg_blue = 0;
+
+ if (context->has_global_cmap) {
gif_set_get_colormap (context);
} else {
context->state = GIF_GET_NEXT_STEP;
}
+
+#ifdef DUMP_IMAGE_DETAILS
+ g_print (">Image width: %d height: %d global_cmap: %d background: %d\n",
+ context->width, context->height, context->has_global_cmap, context->background_index);
+#endif
+
return 0;
}
@@ -966,38 +1074,81 @@ static gint
gif_get_frame_info (GifContext *context)
{
unsigned char buf[9];
+
if (!gif_read (context, buf, 9)) {
return -1;
}
+
/* Okay, we got all the info we need. Lets record it */
context->frame_len = LM_to_uint (buf[4], buf[5]);
context->frame_height = LM_to_uint (buf[6], buf[7]);
context->x_offset = LM_to_uint (buf[0], buf[1]);
context->y_offset = LM_to_uint (buf[2], buf[3]);
- if (context->frame_height > context->height) {
- /* we don't want to resize things. So we exit */
+ if (((context->frame_height + context->y_offset) > context->height) ||
+ ((context->frame_len + context->x_offset) > context->width)) {
+ /* All frames must fit in the image bounds */
+ context->state = GIF_DONE;
+
+ g_set_error (context->error,
+ GDK_PIXBUF_ERROR,
+ GDK_PIXBUF_ERROR_CORRUPT_IMAGE,
+ _("GIF image contained a frame appearing outside the image bounds."));
+
+ return -2;
+ }
+
+ if (context->animation->frames == NULL &&
+ context->gif89.disposal == 3) {
+ /* First frame can't have "revert to previous" as its
+ * dispose mode.
+ */
+
context->state = GIF_DONE;
g_set_error (context->error,
GDK_PIXBUF_ERROR,
GDK_PIXBUF_ERROR_CORRUPT_IMAGE,
- _("GIF animation contained a frame with an incorrect size"));
+ _("First frame of GIF image had 'revert to previous' as its disposal mode."));
return -2;
}
+#ifdef DUMP_IMAGE_DETAILS
+ g_print (">width: %d height: %d xoffset: %d yoffset: %d disposal: %d delay: %d transparent: %d\n",
+ context->frame_len, context->frame_height, context->x_offset, context->y_offset,
+ context->gif89.disposal, context->gif89.delay_time, context->gif89.transparent);
+#endif
+
context->frame_interlace = BitSet (buf[8], INTERLACE);
if (BitSet (buf[8], LOCALCOLORMAP)) {
+
+#ifdef DUMP_IMAGE_DETAILS
+ g_print (">has local colormap\n");
+#endif
+
/* Does this frame have it's own colormap. */
/* really only relevant when looking at the first frame
* of an animated gif. */
/* if it does, we need to re-read in the colormap,
* the gray_scale, and the bit_pixel */
- context->bit_pixel = 1 << ((buf[8] & 0x07) + 1);
+ context->frame_cmap_active = TRUE;
+ context->frame_bit_pixel = 1 << ((buf[8] & 0x07) + 1);
gif_set_get_colormap2 (context);
return 0;
}
+
+ if (!context->has_global_cmap) {
+ context->state = GIF_DONE;
+
+ g_set_error (context->error,
+ GDK_PIXBUF_ERROR,
+ GDK_PIXBUF_ERROR_CORRUPT_IMAGE,
+ _("GIF image has no global colormap, and a frame inside it has no local colormap."));
+
+ return -2;
+ }
+
gif_set_prepare_lzw (context);
return 0;
@@ -1037,6 +1188,8 @@ gif_get_next_step (GifContext *context)
}
+#define LOG(x)
+
static gint
gif_main_loop (GifContext *context)
{
@@ -1045,52 +1198,63 @@ gif_main_loop (GifContext *context)
do {
switch (context->state) {
case GIF_START:
+ LOG("start\n");
retval = gif_init (context);
break;
case GIF_GET_COLORMAP:
+ LOG("get_colormap\n");
retval = gif_get_colormap (context);
if (retval == 0)
context->state = GIF_GET_NEXT_STEP;
break;
case GIF_GET_NEXT_STEP:
+ LOG("next_step\n");
retval = gif_get_next_step (context);
break;
case GIF_GET_FRAME_INFO:
+ LOG("frame_info\n");
retval = gif_get_frame_info (context);
break;
case GIF_GET_EXTENTION:
+ LOG("get_extension\n");
retval = gif_get_extension (context);
if (retval == 0)
context->state = GIF_GET_NEXT_STEP;
break;
case GIF_GET_COLORMAP2:
- retval = gif_get_colormap (context);
+ LOG("get_colormap2\n");
+ retval = gif_get_colormap2 (context);
if (retval == 0)
gif_set_prepare_lzw (context);
break;
case GIF_PREPARE_LZW:
+ LOG("prepare_lzw\n");
retval = gif_prepare_lzw (context);
break;
case GIF_LZW_FILL_BUFFER:
+ LOG("fill_buffer\n");
retval = gif_lzw_fill_buffer (context);
break;
case GIF_LZW_CLEAR_CODE:
+ LOG("clear_code\n");
retval = gif_lzw_clear_code (context);
break;
case GIF_GET_LZW:
+ LOG("get_lzw\n");
retval = gif_get_lzw (context);
break;
case GIF_DONE:
+ LOG("done\n");
default:
retval = 0;
goto done;
@@ -1107,13 +1271,12 @@ new_context (void)
context = g_new0 (GifContext, 1);
- context->pixbuf = NULL;
+ context->animation = g_object_new (GDK_TYPE_PIXBUF_GIF_ANIM, NULL);
+ context->frame = NULL;
context->file = NULL;
context->state = GIF_START;
context->prepare_func = NULL;
context->update_func = NULL;
- context->frame_done_func = NULL;
- context->anim_done_func = NULL;
context->user_data = NULL;
context->buf = NULL;
context->amount_needed = 0;
@@ -1137,9 +1300,22 @@ gdk_pixbuf__gif_image_load (FILE *file, GError **error)
context->file = file;
context->error = error;
- gif_main_loop (context);
+ if (gif_main_loop (context) == -1 || context->animation->frames == NULL) {
+ if (context->error && *(context->error) == NULL)
+ g_set_error (context->error,
+ GDK_PIXBUF_ERROR,
+ GDK_PIXBUF_ERROR_CORRUPT_IMAGE,
+ _("GIF file was missing some data (perhaps it was truncated somehow?)"));
+ }
+
+ pixbuf = gdk_pixbuf_animation_get_static_image (GDK_PIXBUF_ANIMATION (context->animation));
- pixbuf = context->pixbuf;
+ if (pixbuf)
+ g_object_ref (G_OBJECT (pixbuf));
+
+ g_object_unref (G_OBJECT (context->animation));
+
+ g_free (context->buf);
g_free (context);
return pixbuf;
@@ -1148,8 +1324,6 @@ gdk_pixbuf__gif_image_load (FILE *file, GError **error)
static gpointer
gdk_pixbuf__gif_image_begin_load (ModulePreparedNotifyFunc prepare_func,
ModuleUpdatedNotifyFunc update_func,
- ModuleFrameDoneNotifyFunc frame_done_func,
- ModuleAnimationDoneNotifyFunc anim_done_func,
gpointer user_data,
GError **error)
{
@@ -1162,8 +1336,6 @@ gdk_pixbuf__gif_image_begin_load (ModulePreparedNotifyFunc prepare_func,
context->error = error;
context->prepare_func = prepare_func;
context->update_func = update_func;
- context->frame_done_func = frame_done_func;
- context->anim_done_func = anim_done_func;
context->user_data = user_data;
return (gpointer) context;
@@ -1173,21 +1345,23 @@ static gboolean
gdk_pixbuf__gif_image_stop_load (gpointer data, GError **error)
{
GifContext *context = (GifContext *) data;
-
- /* FIXME: free the animation data */
+ gboolean retval = TRUE;
- /* FIXME this thing needs to report errors if
- * we have unused image data
- */
+ if (context->state != GIF_DONE) {
+ g_set_error (error,
+ GDK_PIXBUF_ERROR,
+ GDK_PIXBUF_ERROR_CORRUPT_IMAGE,
+ _("GIF image was truncated or incomplete."));
+
+ retval = FALSE;
+ }
- if (context->pixbuf)
- gdk_pixbuf_unref (context->pixbuf);
- if (context->animation)
- gdk_pixbuf_animation_unref (context->animation);
-/* g_free (context->buf);*/
+ g_object_unref (G_OBJECT (context->animation));
+
+ g_free (context->buf);
g_free (context);
- return TRUE;
+ return retval;
}
static gboolean
@@ -1264,18 +1438,28 @@ gdk_pixbuf__gif_image_load_animation (FILE *file,
context = new_context ();
context->error = error;
-
- context->animation = g_object_new (GDK_TYPE_PIXBUF_ANIMATION, NULL);
-
- context->animation->n_frames = 0;
- context->animation->frames = NULL;
- context->animation->width = 0;
- context->animation->height = 0;
context->file = file;
- gif_main_loop (context);
+ if (gif_main_loop (context) == -1 || context->animation->frames == NULL) {
+ if (context->error && *(context->error) == NULL)
+ g_set_error (context->error,
+ GDK_PIXBUF_ERROR,
+ GDK_PIXBUF_ERROR_CORRUPT_IMAGE,
+ _("GIF file was missing some data (perhaps it was truncated somehow?)"));
- animation = context->animation;
+ g_object_unref (G_OBJECT (context->animation));
+ context->animation = NULL;
+ }
+
+ if (context->animation)
+ animation = GDK_PIXBUF_ANIMATION (context->animation);
+ else
+ animation = NULL;
+
+ if (context->error && *(context->error))
+ g_print ("%s\n", (*(context->error))->message);
+
+ g_free (context->buf);
g_free (context);
return animation;
}
diff --git a/gdk-pixbuf/io-ico.c b/gdk-pixbuf/io-ico.c
index dc6dadb2f..6a2ca4884 100644
--- a/gdk-pixbuf/io-ico.c
+++ b/gdk-pixbuf/io-ico.c
@@ -156,8 +156,6 @@ struct ico_progressive_state {
static gpointer
gdk_pixbuf__ico_image_begin_load(ModulePreparedNotifyFunc prepared_func,
ModuleUpdatedNotifyFunc updated_func,
- ModuleFrameDoneNotifyFunc frame_done_func,
- ModuleAnimationDoneNotifyFunc anim_done_func,
gpointer user_data,
GError **error);
static gboolean gdk_pixbuf__ico_image_stop_load(gpointer data, GError **error);
@@ -178,8 +176,8 @@ gdk_pixbuf__ico_image_load(FILE * f, GError **error)
GdkPixbuf *pb;
- State = gdk_pixbuf__ico_image_begin_load(NULL, NULL, NULL,
- NULL, NULL, error);
+ State = gdk_pixbuf__ico_image_begin_load(NULL, NULL, NULL, error);
+
if (State == NULL)
return NULL;
@@ -363,6 +361,7 @@ static void DecodeHeader(guchar *Data, gint Bytes,
if (State->prepared_func != NULL)
/* Notify the client that we are ready to go */
(*State->prepared_func) (State->pixbuf,
+ NULL,
State->user_data);
}
@@ -378,8 +377,6 @@ static void DecodeHeader(guchar *Data, gint Bytes,
static gpointer
gdk_pixbuf__ico_image_begin_load(ModulePreparedNotifyFunc prepared_func,
ModuleUpdatedNotifyFunc updated_func,
- ModuleFrameDoneNotifyFunc frame_done_func,
- ModuleAnimationDoneNotifyFunc anim_done_func,
gpointer user_data,
GError **error)
{
diff --git a/gdk-pixbuf/io-jpeg.c b/gdk-pixbuf/io-jpeg.c
index 2c295131d..c707d347a 100644
--- a/gdk-pixbuf/io-jpeg.c
+++ b/gdk-pixbuf/io-jpeg.c
@@ -96,8 +96,6 @@ typedef struct {
static GdkPixbuf *gdk_pixbuf__jpeg_image_load (FILE *f, GError **error);
static gpointer gdk_pixbuf__jpeg_image_begin_load (ModulePreparedNotifyFunc func,
ModuleUpdatedNotifyFunc func2,
- ModuleFrameDoneNotifyFunc func3,
- ModuleAnimationDoneNotifyFunc func4,
gpointer user_data,
GError **error);
static gboolean gdk_pixbuf__jpeg_image_stop_load (gpointer context, GError **error);
@@ -321,8 +319,6 @@ skip_input_data (j_decompress_ptr cinfo, long num_bytes)
gpointer
gdk_pixbuf__jpeg_image_begin_load (ModulePreparedNotifyFunc prepared_func,
ModuleUpdatedNotifyFunc updated_func,
- ModuleFrameDoneNotifyFunc frame_func,
- ModuleAnimationDoneNotifyFunc anim_done_func,
gpointer user_data,
GError **error)
{
@@ -539,6 +535,7 @@ gdk_pixbuf__jpeg_image_load_increment (gpointer data,
/* Notify the client that we are ready to go */
(* context->prepared_func) (context->pixbuf,
+ NULL,
context->user_data);
} else if (!context->did_prescan) {
diff --git a/gdk-pixbuf/io-png.c b/gdk-pixbuf/io-png.c
index 9ece35d40..21b1d4b29 100644
--- a/gdk-pixbuf/io-png.c
+++ b/gdk-pixbuf/io-png.c
@@ -324,8 +324,6 @@ struct _LoadContext {
static gpointer
gdk_pixbuf__png_image_begin_load (ModulePreparedNotifyFunc prepare_func,
ModuleUpdatedNotifyFunc update_func,
- ModuleFrameDoneNotifyFunc frame_done_func,
- ModuleAnimationDoneNotifyFunc anim_done_func,
gpointer user_data,
GError **error)
{
@@ -540,7 +538,7 @@ png_info_callback (png_structp png_read_ptr,
/* Notify the client that we are ready to go */
if (lc->prepare_func)
- (* lc->prepare_func) (lc->pixbuf, lc->notify_user_data);
+ (* lc->prepare_func) (lc->pixbuf, NULL, lc->notify_user_data);
return;
}
diff --git a/gdk-pixbuf/io-pnm.c b/gdk-pixbuf/io-pnm.c
index 87c392db5..cd7dd9d9b 100644
--- a/gdk-pixbuf/io-pnm.c
+++ b/gdk-pixbuf/io-pnm.c
@@ -84,8 +84,6 @@ typedef struct {
static GdkPixbuf *gdk_pixbuf__pnm_image_load (FILE *f, GError **error);
static gpointer gdk_pixbuf__pnm_image_begin_load (ModulePreparedNotifyFunc func,
ModuleUpdatedNotifyFunc func2,
- ModuleFrameDoneNotifyFunc frame_done_func,
- ModuleAnimationDoneNotifyFunc anim_done_func,
gpointer user_data,
GError **error);
static gboolean gdk_pixbuf__pnm_image_stop_load (gpointer context, GError **error);
@@ -763,8 +761,6 @@ gdk_pixbuf__pnm_image_load (FILE *f, GError **error)
static gpointer
gdk_pixbuf__pnm_image_begin_load (ModulePreparedNotifyFunc prepared_func,
ModuleUpdatedNotifyFunc updated_func,
- ModuleFrameDoneNotifyFunc frame_done_func,
- ModuleAnimationDoneNotifyFunc anim_done_func,
gpointer user_data,
GError **error)
{
@@ -923,6 +919,7 @@ gdk_pixbuf__pnm_image_load_increment (gpointer data,
/* Notify the client that we are ready to go */
(* context->prepared_func) (context->pixbuf,
+ NULL,
context->user_data);
}
diff --git a/gdk-pixbuf/io-ras.c b/gdk-pixbuf/io-ras.c
index 25a3c0b7a..84b7c27f9 100644
--- a/gdk-pixbuf/io-ras.c
+++ b/gdk-pixbuf/io-ras.c
@@ -96,8 +96,6 @@ struct ras_progressive_state {
static gpointer
gdk_pixbuf__ras_image_begin_load(ModulePreparedNotifyFunc prepared_func,
ModuleUpdatedNotifyFunc updated_func,
- ModuleFrameDoneNotifyFunc frame_done_func,
- ModuleAnimationDoneNotifyFunc anim_done_func,
gpointer user_data,
GError **error);
static gboolean gdk_pixbuf__ras_image_stop_load(gpointer data, GError **error);
@@ -116,8 +114,7 @@ static GdkPixbuf *gdk_pixbuf__ras_image_load(FILE * f, GError **error)
GdkPixbuf *pb;
- State = gdk_pixbuf__ras_image_begin_load(NULL, NULL, NULL,
- NULL, NULL, error);
+ State = gdk_pixbuf__ras_image_begin_load(NULL, NULL, NULL, error);
membuf = g_malloc(4096);
@@ -195,6 +192,7 @@ static void RAS2State(struct rasterfile *RAS,
if (State->prepared_func != NULL)
/* Notify the client that we are ready to go */
(*State->prepared_func) (State->pixbuf,
+ NULL,
State->user_data);
}
@@ -219,8 +217,6 @@ static void RAS2State(struct rasterfile *RAS,
static gpointer
gdk_pixbuf__ras_image_begin_load(ModulePreparedNotifyFunc prepared_func,
ModuleUpdatedNotifyFunc updated_func,
- ModuleFrameDoneNotifyFunc frame_done_func,
- ModuleAnimationDoneNotifyFunc anim_done_func,
gpointer user_data,
GError **error)
{
diff --git a/gdk-pixbuf/io-tiff.c b/gdk-pixbuf/io-tiff.c
index 9b23f5d71..51040dcda 100644
--- a/gdk-pixbuf/io-tiff.c
+++ b/gdk-pixbuf/io-tiff.c
@@ -92,7 +92,7 @@ gdk_pixbuf__tiff_image_load_real (FILE *f, TiffData *context, GError **error)
}
if (context)
- (* context->prepare_func) (pixbuf, context->user_data);
+ (* context->prepare_func) (pixbuf, NULL, context->user_data);
/* Yes, it needs to be _TIFFMalloc... */
rast = (uint32 *) _TIFFmalloc (num_pixs * sizeof (uint32));
@@ -163,8 +163,6 @@ gdk_pixbuf__tiff_image_load (FILE *f, GError **error)
static gpointer
gdk_pixbuf__tiff_image_begin_load (ModulePreparedNotifyFunc prepare_func,
ModuleUpdatedNotifyFunc update_func,
- ModuleFrameDoneNotifyFunc frame_done_func,
- ModuleAnimationDoneNotifyFunc anim_done_func,
gpointer user_data,
GError **error)
{
diff --git a/gdk-pixbuf/io-wbmp.c b/gdk-pixbuf/io-wbmp.c
index 1b7784b13..1537d83d6 100644
--- a/gdk-pixbuf/io-wbmp.c
+++ b/gdk-pixbuf/io-wbmp.c
@@ -65,9 +65,7 @@ struct wbmp_progressive_state {
static gpointer
gdk_pixbuf__wbmp_image_begin_load(ModulePreparedNotifyFunc prepared_func,
ModuleUpdatedNotifyFunc updated_func,
- ModuleFrameDoneNotifyFunc frame_done_func,
- ModuleAnimationDoneNotifyFunc
- anim_done_func, gpointer user_data,
+ gpointer user_data,
GError **error);
static gboolean gdk_pixbuf__wbmp_image_stop_load(gpointer data, GError **error);
@@ -87,7 +85,7 @@ static GdkPixbuf *gdk_pixbuf__wbmp_image_load(FILE * f, GError **error)
GdkPixbuf *pb;
- State = gdk_pixbuf__wbmp_image_begin_load(NULL, NULL, NULL, NULL, NULL,
+ State = gdk_pixbuf__wbmp_image_begin_load(NULL, NULL, NULL,
error);
if (State == NULL)
@@ -120,9 +118,7 @@ static GdkPixbuf *gdk_pixbuf__wbmp_image_load(FILE * f, GError **error)
static gpointer
gdk_pixbuf__wbmp_image_begin_load(ModulePreparedNotifyFunc prepared_func,
ModuleUpdatedNotifyFunc updated_func,
- ModuleFrameDoneNotifyFunc frame_done_func,
- ModuleAnimationDoneNotifyFunc
- anim_done_func, gpointer user_data,
+ gpointer user_data,
GError **error)
{
struct wbmp_progressive_state *context;
@@ -285,7 +281,7 @@ static gboolean gdk_pixbuf__wbmp_image_load_increment(gpointer data,
g_assert(context->pixbuf);
if(context->prepared_func)
- context->prepared_func(context->pixbuf, context->user_data);
+ context->prepared_func(context->pixbuf, NULL, context->user_data);
}
}
else if(context->needmore)
diff --git a/gdk-pixbuf/io-xbm.c b/gdk-pixbuf/io-xbm.c
index 05d8f994a..0041488eb 100644
--- a/gdk-pixbuf/io-xbm.c
+++ b/gdk-pixbuf/io-xbm.c
@@ -300,7 +300,7 @@ gdk_pixbuf__xbm_image_load_real (FILE *f, XBMData *context, GError **error)
row_stride = gdk_pixbuf_get_rowstride (pixbuf);
if (context)
- (* context->prepare_func) (pixbuf, context->user_data);
+ (* context->prepare_func) (pixbuf, NULL, context->user_data);
/* Initialize PIXBUF */
@@ -355,8 +355,6 @@ gdk_pixbuf__xbm_image_load (FILE *f, GError **error)
static gpointer
gdk_pixbuf__xbm_image_begin_load (ModulePreparedNotifyFunc prepare_func,
ModuleUpdatedNotifyFunc update_func,
- ModuleFrameDoneNotifyFunc frame_done_func,
- ModuleAnimationDoneNotifyFunc anim_done_func,
gpointer user_data,
GError **error)
{
diff --git a/gdk-pixbuf/io-xpm.c b/gdk-pixbuf/io-xpm.c
index 0ddc3c234..1f99088c3 100644
--- a/gdk-pixbuf/io-xpm.c
+++ b/gdk-pixbuf/io-xpm.c
@@ -1424,8 +1424,6 @@ struct _XPMContext
static gpointer
gdk_pixbuf__xpm_image_begin_load (ModulePreparedNotifyFunc prepare_func,
ModuleUpdatedNotifyFunc update_func,
- ModuleFrameDoneNotifyFunc frame_done_func,
- ModuleAnimationDoneNotifyFunc anim_done_func,
gpointer user_data,
GError **error)
{
@@ -1471,7 +1469,9 @@ gdk_pixbuf__xpm_image_stop_load (gpointer data,
pixbuf = gdk_pixbuf__xpm_image_load (context->file, error);
if (pixbuf != NULL) {
- (* context->prepare_func) (pixbuf, context->user_data);
+ (* context->prepare_func) (pixbuf,
+ NULL,
+ context->user_data);
(* context->update_func) (pixbuf, 0, 0, pixbuf->width, pixbuf->height, context->user_data);
gdk_pixbuf_unref (pixbuf);
diff --git a/gdk-pixbuf/pixops/pixops.c b/gdk-pixbuf/pixops/pixops.c
index ea1960715..7a13e043b 100644
--- a/gdk-pixbuf/pixops/pixops.c
+++ b/gdk-pixbuf/pixops/pixops.c
@@ -1,4 +1,5 @@
#include <math.h>
+#include <glib.h>
#include "config.h"
#include "pixops.h"
@@ -93,6 +94,7 @@ pixops_scale_nearest (guchar *dest_buf,
for (i = 0; i < (render_y1 - render_y0); i++)
{
const guchar *src = src_buf + (((i + render_y0) * y_step + y_step / 2) >> SCALE_SHIFT) * src_rowstride;
+ /* FIXME Owen needs to look at this */
guchar *dest = dest_buf + i * dest_rowstride;
x = render_x0 * x_step + x_step / 2;
@@ -160,7 +162,6 @@ pixops_composite_nearest (guchar *dest_buf,
for (i = 0; i < (render_y1 - render_y0); i++)
{
const guchar *src = src_buf + (((i + render_y0) * y_step + y_step / 2) >> SCALE_SHIFT) * src_rowstride;
- /* FIXME Owen needs to look at this */
guchar *dest = dest_buf + i * dest_rowstride;
x = render_x0 * x_step + x_step / 2;
@@ -183,9 +184,9 @@ pixops_composite_nearest (guchar *dest_buf,
if (w != 0)
{
- dest[0] = (w0 * src[0] + w1 * dest[0]) / w;
- dest[1] = (w0 * src[1] + w1 * dest[1]) / w;
- dest[2] = (w0 * src[2] + w1 * dest[2]) / w;
+ dest[0] = (w0 * p[0] + w1 * dest[0]) / w;
+ dest[1] = (w0 * p[1] + w1 * dest[1]) / w;
+ dest[2] = (w0 * p[2] + w1 * dest[2]) / w;
dest[3] = w / 0xff;
}
else
@@ -274,25 +275,39 @@ pixops_composite_color_nearest (guchar *dest_buf,
for (j=0 ; j < (render_x1 - render_x0); j++)
{
const guchar *p = src + (x >> SCALE_SHIFT) * src_channels;
- unsigned int a0;
+ int a0;
+ int tmp;
if (src_has_alpha)
a0 = (p[3] * overall_alpha + 0xff) >> 8;
else
a0 = overall_alpha;
- if (((j + check_x) >> check_shift) & 1)
+ if (a0 == 255)
{
- dest[0] = r2 + ((a0 * ((int)p[0] - r2) + 0xff) >> 8);
- dest[1] = g2 + ((a0 * ((int)p[1] - g2) + 0xff) >> 8);
- dest[2] = b2 + ((a0 * ((int)p[2] - b2) + 0xff) >> 8);
+ dest[0] = p[0];
+ dest[1] = p[1];
+ dest[2] = p[2];
}
else
- {
- dest[0] = r1 + ((a0 * ((int)p[0] - r1) + 0xff) >> 8);
- dest[1] = g1 + ((a0 * ((int)p[1] - g1) + 0xff) >> 8);
- dest[2] = b1 + ((a0 * ((int)p[2] - b1) + 0xff) >> 8);
- }
+ if (((j + check_x) >> check_shift) & 1)
+ {
+ tmp = ((int) p[0] - r2) * a0;
+ dest[0] = r2 + ((tmp + (tmp >> 8) + 0x80) >> 8);
+ tmp = ((int) p[1] - g2) * a0;
+ dest[1] = g2 + ((tmp + (tmp >> 8) + 0x80) >> 8);
+ tmp = ((int) p[2] - b2) * a0;
+ dest[2] = b2 + ((tmp + (tmp >> 8) + 0x80) >> 8);
+ }
+ else
+ {
+ tmp = ((int) p[0] - r1) * a0;
+ dest[0] = r1 + ((tmp + (tmp >> 8) + 0x80) >> 8);
+ tmp = ((int) p[1] - g1) * a0;
+ dest[1] = g1 + ((tmp + (tmp >> 8) + 0x80) >> 8);
+ tmp = ((int) p[2] - b1) * a0;
+ dest[2] = b1 + ((tmp + (tmp >> 8) + 0x80) >> 8);
+ }
if (dest_channels == 4)
dest[3] = 0xff;
@@ -1003,7 +1018,7 @@ pixops_process (guchar *dest_buf,
dest_x += (new_outbuf - outbuf) / dest_channels;
- x = dest_x * x_step + scaled_x_offset;
+ x = (dest_x - check_x + render_x0) * x_step + scaled_x_offset;
outbuf = new_outbuf;
while (outbuf < outbuf_end)