mirror of
https://gitlab.gnome.org/GNOME/gtk.git
synced 2024-11-18 09:00:34 +00:00
e0fee22e78
2001-01-22 Havoc Pennington <hp@redhat.com> * Makefile.am: Add built marshaller files to support GdkPixbufLoader signals * gdk-pixbuf-io.c (gdk_pixbuf_load_module): have GDK_PIXBUF_MODULEDIR unconditionally replace the compiled-in module location, rather than acting as a fallback, because we are using GDK_PIXBUF_MODULEDIR to use gdk-pixbuf before installing it. * gdk-pixbuf.h: include gdk-pixbuf-loader.h * gdk-pixbuf-loader.h, gdk-pixbuf-loader.c: Move back over here from gtk, and add error to close(), because stop_load may do parsing of the image. * pixops/have_mmx.S (_pixops_have_mmx): add newline at end of file * io-*.c: make individual operations static, and add fill_vtable functions which are exported. Fix the collection of type warnings that surfaced, including a number of functions that didn't properly take a GError and some that weren't const-correct. Involved adding error handling for a few loaders. * gdk-pixbuf-io.h: Add error reporting to stop_load function * gdk-pixbuf-io.c (gdk_pixbuf_load_module): change to just look up a function that fills in the GdkPixbufModule vtable, instead of looking up all the image functions individually; this means we can get type safety within modules for the loader functions. Also it means you don't have to keep the statically compiled and GModule versions in sync. * test-gdk-pixbuf.c (main): remove gdk_pixbuf_init() * make-inline-pixbuf.c (main): remove call to gdk_pixbuf_init() * gdk-pixbuf.h: nuke gdk_pixbuf_init() * gdk-pixbuf-animation.c (gdk_pixbuf_frame_get_type): g_type_init () here * gdk-pixbuf.c (gdk_pixbuf_get_type): g_type_init () here * gdk-pixbuf-animation.c (gdk_pixbuf_animation_get_type): g_type_init() here 2001-01-22 Havoc Pennington <hp@redhat.com> * demos/testanimation.c: fix to reflect gdk-pixbuf changes * demos/testpixbuf.c: fix to reflect gdk-pixbuf changes * gtk/gdk-pixbuf-loader.c, gtk/gdk-pixbuf-loader.h: Remove, move back to gdk-pixbuf * gtk/gtktextiter.c, gtk/gtktextiter.h: add sentence equivalents to all the word functions * gtk/gtktextview.c (gtk_text_view_start_cursor_blink): return before doing anything on NULL layout or if we don't have the focus * gtk/testtext.c (fill_example_buffer): "justification" * gtk/gtktexttag.h, gtk/gtktexttag.c: change the tag attribute to be called "justification" not "justify" * demos/gtk-demo/textview.c (create_tags): "justification" * gtk/gtktextlayout.c (set_para_values): Handle char-wise wrapping
345 lines
9.0 KiB
C
345 lines
9.0 KiB
C
/* GdkPixbuf library - Wireless Bitmap image loader
|
||
*
|
||
* Copyright (C) 2000 Red Hat, Inc.
|
||
*
|
||
* Authors: Elliot Lee <sopwith@redhat.com
|
||
*
|
||
* Based on io-bmp.c
|
||
*
|
||
* 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.
|
||
*/
|
||
|
||
/*
|
||
|
||
Known bugs:
|
||
* Since this is based off the libgd implementation, no extended headers implemented (not required for a WAP client)
|
||
*/
|
||
|
||
#include <config.h>
|
||
#include <stdio.h>
|
||
#ifdef HAVE_UNISTD_H
|
||
#include <unistd.h>
|
||
#endif
|
||
#include <string.h>
|
||
#include "gdk-pixbuf-private.h"
|
||
#include "gdk-pixbuf-io.h"
|
||
|
||
|
||
|
||
/* Progressive loading */
|
||
|
||
struct wbmp_progressive_state {
|
||
ModulePreparedNotifyFunc prepared_func;
|
||
ModuleUpdatedNotifyFunc updated_func;
|
||
gpointer user_data;
|
||
|
||
gboolean need_type : 1;
|
||
gboolean need_header : 1;
|
||
gboolean need_width : 1;
|
||
gboolean need_height : 1;
|
||
gboolean needmore : 1;
|
||
gboolean call_progressive_updates : 1;
|
||
|
||
guchar last_buf[16]; /* Just needs to be big enough to hold the largest datum requestable via 'getin' */
|
||
guint last_len;
|
||
|
||
int type;
|
||
int width, height, curx, cury;
|
||
|
||
GdkPixbuf *pixbuf; /* Our "target" */
|
||
};
|
||
|
||
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,
|
||
GError **error);
|
||
|
||
static gboolean gdk_pixbuf__wbmp_image_stop_load(gpointer data, GError **error);
|
||
static gboolean gdk_pixbuf__wbmp_image_load_increment(gpointer data,
|
||
const guchar * buf,
|
||
guint size,
|
||
GError **error);
|
||
|
||
|
||
/* Shared library entry point --> This should be removed when
|
||
generic_image_load enters gdk-pixbuf-io. */
|
||
static GdkPixbuf *gdk_pixbuf__wbmp_image_load(FILE * f, GError **error)
|
||
{
|
||
size_t length;
|
||
char membuf[4096];
|
||
struct wbmp_progressive_state *State;
|
||
|
||
GdkPixbuf *pb;
|
||
|
||
State = gdk_pixbuf__wbmp_image_begin_load(NULL, NULL, NULL, NULL, NULL,
|
||
error);
|
||
|
||
if (State == NULL)
|
||
return NULL;
|
||
|
||
while (feof(f) == 0) {
|
||
length = fread(membuf, 1, 4096, f);
|
||
if (length > 0)
|
||
gdk_pixbuf__wbmp_image_load_increment(State,
|
||
membuf,
|
||
length,
|
||
error);
|
||
|
||
}
|
||
if (State->pixbuf != NULL)
|
||
gdk_pixbuf_ref(State->pixbuf);
|
||
|
||
pb = State->pixbuf;
|
||
|
||
gdk_pixbuf__wbmp_image_stop_load(State, NULL);
|
||
return pb;
|
||
}
|
||
|
||
/*
|
||
* func - called when we have pixmap created (but no image data)
|
||
* user_data - passed as arg 1 to func
|
||
* return context (opaque to user)
|
||
*/
|
||
|
||
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,
|
||
GError **error)
|
||
{
|
||
struct wbmp_progressive_state *context;
|
||
|
||
context = g_new0(struct wbmp_progressive_state, 1);
|
||
context->prepared_func = prepared_func;
|
||
context->updated_func = updated_func;
|
||
context->user_data = user_data;
|
||
|
||
context->needmore = context->need_type = context->need_header = context->need_width = context->need_height = TRUE;
|
||
context->call_progressive_updates = TRUE;
|
||
context->pixbuf = NULL;
|
||
|
||
return (gpointer) context;
|
||
}
|
||
|
||
/*
|
||
* context - returned from image_begin_load
|
||
*
|
||
* free context, unref gdk_pixbuf
|
||
*/
|
||
static gboolean gdk_pixbuf__wbmp_image_stop_load(gpointer data,
|
||
GError **error)
|
||
{
|
||
struct wbmp_progressive_state *context =
|
||
(struct wbmp_progressive_state *) data;
|
||
|
||
/* FIXME this thing needs to report errors if
|
||
* we have unused image data
|
||
*/
|
||
|
||
g_return_val_if_fail(context != NULL, TRUE);
|
||
if (context->pixbuf)
|
||
gdk_pixbuf_unref(context->pixbuf);
|
||
|
||
g_free(context);
|
||
|
||
return TRUE;
|
||
}
|
||
|
||
static gboolean
|
||
getin(struct wbmp_progressive_state *context, guchar **buf, guint *buf_size, guchar *ptr, int datum_size)
|
||
{
|
||
int last_num, buf_num;
|
||
|
||
if((context->last_len + *buf_size) < datum_size)
|
||
return FALSE;
|
||
|
||
/* We know we can pull it out of there */
|
||
last_num = MIN(datum_size, context->last_len);
|
||
buf_num = MIN(datum_size-last_num, *buf_size);
|
||
memcpy(ptr, context->last_buf, last_num);
|
||
memcpy(ptr+last_num, *buf, buf_num);
|
||
|
||
context->last_len -= last_num;
|
||
if(context->last_len)
|
||
memmove(context->last_buf, context->last_buf+last_num, context->last_len);
|
||
*buf_size -= buf_num;
|
||
*buf += buf_num;
|
||
|
||
return TRUE;
|
||
}
|
||
|
||
static gboolean
|
||
save_rest(struct wbmp_progressive_state *context, const guchar *buf, guint buf_size)
|
||
{
|
||
if(buf_size > (sizeof(context->last_buf) - context->last_len))
|
||
return FALSE;
|
||
|
||
memcpy(context->last_buf+context->last_len, buf, buf_size);
|
||
context->last_len += buf_size;
|
||
|
||
return TRUE;
|
||
}
|
||
|
||
static gboolean
|
||
get_mbi(struct wbmp_progressive_state *context, guchar **buf, guint *buf_size, int *val)
|
||
{
|
||
guchar intbuf[16];
|
||
int i, n;
|
||
gboolean rv;
|
||
|
||
*val = 0;
|
||
n = i = 0;
|
||
do {
|
||
rv = getin(context, buf, buf_size, intbuf+n, 1);
|
||
if(!rv)
|
||
goto out;
|
||
*val <<= 7;
|
||
*val |= intbuf[n] & 0x7F;
|
||
n++;
|
||
} while(n < sizeof(intbuf) && (intbuf[n-1] & 0x80));
|
||
|
||
out:
|
||
if(!rv || (intbuf[n-1] & 0x80))
|
||
{
|
||
rv = save_rest(context, intbuf, n);
|
||
|
||
if(!rv)
|
||
g_error("Couldn't save_rest of intbuf");
|
||
return FALSE;
|
||
}
|
||
|
||
return TRUE;
|
||
}
|
||
|
||
/*
|
||
* context - from image_begin_load
|
||
* buf - new image data
|
||
* size - length of new image data
|
||
*
|
||
* append image data onto inrecrementally built output image
|
||
*/
|
||
static gboolean gdk_pixbuf__wbmp_image_load_increment(gpointer data,
|
||
const guchar * buf,
|
||
guint size, GError **error)
|
||
{
|
||
struct wbmp_progressive_state *context =
|
||
(struct wbmp_progressive_state *) data;
|
||
gboolean bv = FALSE;
|
||
|
||
do
|
||
{
|
||
if(context->need_type)
|
||
{
|
||
guchar val;
|
||
|
||
bv = getin(context, &buf, &size, &val, 1);
|
||
if(bv)
|
||
{
|
||
context->type = val;
|
||
context->need_type = FALSE;
|
||
}
|
||
}
|
||
else if(context->need_header)
|
||
{
|
||
guchar val;
|
||
|
||
bv = getin(context, &buf, &size, &val, 1);
|
||
if(bv)
|
||
{
|
||
/* We skip over the extended header - val is unused */
|
||
if(!(val & 0x80))
|
||
context->need_header = FALSE;
|
||
}
|
||
}
|
||
else if(context->need_width)
|
||
{
|
||
bv = get_mbi(context, &buf, &size, &context->width);
|
||
if(bv)
|
||
context->need_width = FALSE;
|
||
}
|
||
else if(context->need_height)
|
||
{
|
||
bv = get_mbi(context, &buf, &size, &context->height);
|
||
if(bv)
|
||
{
|
||
context->need_height = FALSE;
|
||
context->pixbuf = gdk_pixbuf_new(GDK_COLORSPACE_RGB, FALSE, 8, context->width, context->height);
|
||
g_assert(context->pixbuf);
|
||
|
||
if(context->prepared_func)
|
||
context->prepared_func(context->pixbuf, context->user_data);
|
||
}
|
||
}
|
||
else if(context->needmore)
|
||
{
|
||
int first_row;
|
||
first_row = context->cury;
|
||
for( ; context->cury < context->height; context->cury++, context->curx = 0)
|
||
{
|
||
for( ; context->curx < context->width; context->curx += 8)
|
||
{
|
||
guchar byte;
|
||
guchar *ptr;
|
||
int xoff;
|
||
bv = getin(context, &buf, &size, &byte, 1);
|
||
if(!bv)
|
||
goto out;
|
||
|
||
ptr = context->pixbuf->pixels + context->pixbuf->rowstride * context->cury + context->curx * 3;
|
||
for(xoff = 7; xoff >= 0; xoff--, ptr += 3)
|
||
{
|
||
guchar pixval;
|
||
|
||
if(byte & (1<<xoff))
|
||
pixval = 0xFF;
|
||
else
|
||
pixval = 0x0;
|
||
|
||
ptr[0] = ptr[1] = ptr[2] = pixval;
|
||
}
|
||
}
|
||
}
|
||
context->needmore = FALSE;
|
||
|
||
out:
|
||
context->updated_func(context->pixbuf, 0, first_row, context->width, context->cury - first_row + 1,
|
||
context->user_data);
|
||
}
|
||
else
|
||
bv = FALSE; /* Nothing left to do, stop feeding me data! */
|
||
|
||
} while(bv);
|
||
|
||
if(size)
|
||
return save_rest(context, buf, size);
|
||
else
|
||
return context->needmore;
|
||
}
|
||
|
||
void
|
||
gdk_pixbuf__wbmp_fill_vtable (GdkPixbufModule *module)
|
||
{
|
||
module->load = gdk_pixbuf__wbmp_image_load;
|
||
module->begin_load = gdk_pixbuf__wbmp_image_begin_load;
|
||
module->stop_load = gdk_pixbuf__wbmp_image_stop_load;
|
||
module->load_increment = gdk_pixbuf__wbmp_image_load_increment;
|
||
}
|