summaryrefslogtreecommitdiff
path: root/riscos/gif.c
diff options
context:
space:
mode:
Diffstat (limited to 'riscos/gif.c')
-rw-r--r--riscos/gif.c549
1 files changed, 46 insertions, 503 deletions
diff --git a/riscos/gif.c b/riscos/gif.c
index b559268f8..94fdc6a42 100644
--- a/riscos/gif.c
+++ b/riscos/gif.c
@@ -14,381 +14,90 @@
#include <stdbool.h>
#include <stdlib.h>
#include <swis.h>
-#include "animlib/animlib.h"
-#include "oslib/colourtrans.h"
-#include "oslib/os.h"
#include "oslib/osfile.h"
#include "oslib/osspriteop.h"
#include "netsurf/utils/config.h"
#include "netsurf/content/content.h"
#include "netsurf/riscos/gif.h"
+#include "netsurf/riscos/gifread.h"
#include "netsurf/riscos/gui.h"
#include "netsurf/riscos/options.h"
#include "netsurf/riscos/tinct.h"
#include "netsurf/utils/log.h"
-#include "netsurf/utils/messages.h"
#include "netsurf/utils/utils.h"
-/* REVISED GIF FUNCTIONALITY
- =========================
+/* GIF FUNCTIONALITY
+ =================
- To improve the display quality of the GIFs, Tinct is used when plotting the
- images. This provides a speed gain as the necessary translation tables are
- cached, but comes at the expense that the current frame must be held as a
- 32bpp sprite.
-
- To overcome the problem of memory wastage, each frame of the GIF is held as
- a Nbpp paletted sprite and is converted into a 32bpp sprite suitable for
- plotting following a frame transition. This conversion is performed by using
- Tinct_ConvertSprite.
-
- By using this technique rather than dynamically decompressing the current
- GIF frame we can skip over frames that we can't display and always keep
- pace with the animation simply. If we were dynamically decompressing the
- GIF then it would be necessary to also decompress any intermediate frames as
- the GIF format dictates that each successive frame is plotted on top of any
- previous one.
-
- [rjw] - Thu 18th March 2004
+ All GIFs are dynamically decompressed using the routines that gifread.c
+ provides. Whilst this allows support for progressive decoding, it is
+ not implemented here as NetSurf currently does not provide such support.
+
+ [rjw] - Sun 4th April 2004
*/
#ifdef WITH_GIF
-static bool nsgif_decompress_frame(struct content *c, anim *p_gif_animation,
- unsigned int cur_frame);
static void nsgif_animate(void *p);
-static osspriteop_header *nsgif_get_sprite_address(struct content *c,
- unsigned int frame);
-static void CompressSpriteLine( pixel *dest, const pixel *src, int n, int bpp );
-static void CompressMaskLine( pixel *dest, const pixel *src, int n, int bpp );
void nsgif_init(void) {
}
void nsgif_create(struct content *c, const char *params[]) {
- c->data.gif.sprite_area = 0;
- c->data.gif.buffer_pos = 0;
- c->data.gif.total_frames = 0; // Paranoid
+ /* Initialise our data structure
+ */
+ c->data.gif.gif = (gif_animation *)xcalloc(sizeof(gif_animation), 1);
+ c->data.gif.current_frame = 0;
}
int nsgif_convert(struct content *c, unsigned int iwidth, unsigned int iheight) {
- struct osspriteop_area *sprite_area;
-
- unsigned int sprite_area_size;
- unsigned int frame_count;
- unsigned int cur_frame;
- unsigned int frame_colours;
- unsigned int frame_bpp;
- unsigned int frame_size;
- unsigned int *frame_delays;
-
- anim gif_animation;
- frame gif_frame;
-
-
- /* Get an anim object from our data
- */
- gif_animation = Anim_FromData(c->source_data, c->source_size, NULL, false, false, false);
- if (!gif_animation) {
- LOG(("Error creating anim object"));
- return 1;
- }
-
- /* Check we have some frames
+ struct gif_animation *gif;
+
+ /* Create our animation
*/
- if (gif_animation->nFrames < 1) {
- LOG(("No frames found"));
- Anim_Destroy(&gif_animation);
- return 1;
- }
-
- /* Store the animation details
+ gif = c->data.gif.gif;
+ gif->gif_data = c->source_data;
+ gif->buffer_size = c->source_size;
+ gif->buffer_position = 0; // Paranoid
+
+ /* Initialise the GIF
*/
- c->width = gif_animation->nWidth;
- c->height = gif_animation->nHeight;
- c->data.gif.current_frame = 0;
- c->data.gif.expanded_frame = 0xffffffff; // ie invalid value
- c->data.gif.remainder_time = 0;
- c->data.gif.total_frames = frame_count = gif_animation->nFrames;
- c->data.gif.animate_gif = (frame_count > 1);
- c->data.gif.loop_gif = true;
-
- /* Claim a buffer for the cached 32bpp version of the current frame. By
- doing this now we can use the same memory area as the temporary buffer
- for decoding all the subsequent frames later.
+ gif_initialise(gif);
+
+ /* Store our content width
*/
- struct osspriteop_header *temp_buf = xcalloc(gif_animation->nWidth *
- gif_animation->nHeight + 11, 4);
- c->data.gif.buffer_header = (osspriteop_header*)(temp_buf);
+ c->width = gif->width;
+ c->height = gif->height;
- /* We can store our frame transitions now too
+ /* Schedule the animation if we have one
*/
- if (frame_count > 1) {
- frame_delays = xcalloc(frame_count, sizeof(int));
- c->data.gif.frame_transitions = frame_delays;
+ if (gif->frame_count > 1) {
+ schedule(gif->frame_delays[0], nsgif_animate, c);
}
- /* Now we need to work out the total size of the sprite area. If we are
- doing dynamic decompression then this can simply be an 8bpp paletted
- sprite of the required dimensions as all frames will fit.
- For dynamic decompression, the frame delay buffer must still be filled
- in a similar manner.
- */
- sprite_area_size = sizeof(osspriteop_area);
- for (cur_frame = 0; cur_frame < frame_count; cur_frame++) {
-
- /* Increment by the header size
- */
- sprite_area_size += sizeof(osspriteop_header);
-
- /* Get the frame details
- */
- gif_frame = gif_animation->pFrames + cur_frame;
- frame_colours = gif_frame->pal->nColours;
-
- /* Store our transition time
- */
- if (frame_count > 1) {
- frame_delays[cur_frame] = gif_frame->csDelay;
- }
-
- /* Get the minimum number of bpp for this frame
- */
- frame_bpp = 8;
- if (frame_colours <=16) frame_bpp = 4;
- if (frame_colours <=4) frame_bpp = 2;
- if (frame_colours <=2) frame_bpp = 1;
-
- /* Increase our area by our palette size. Due to legacy flashing
- colour support, RISC OS lumbers all sprites with two words of
- palette data per colour.
- */
- sprite_area_size += (8 << frame_bpp);
-
- /* Now we need to calculate how big each sprite is given the
- current number of bits per pixel.
- */
- frame_size = (((((gif_animation->nWidth * frame_bpp) + 31) & ~31) >> 3) *
- gif_animation->nHeight);
-
- /* Finally we add in our frame size, and add it again if we have
- some mask data.
- */
- if (gif_frame->pMaskData) frame_size *= 2;
- sprite_area_size += frame_size;
- }
-
- /* So, we now have the size needed so we can create our sprite area and
- fill in some data for it.
- */
- sprite_area = xcalloc(sprite_area_size, 1);
- sprite_area->size = sprite_area_size;
- sprite_area->sprite_count = frame_count;
- sprite_area->first = sizeof(osspriteop_area);
- sprite_area->used = sprite_area_size;
- c->data.gif.sprite_area = sprite_area;
-
- /* Now we need to decompress all our frames. This is handled by a
- sub-routine so we can easily modify this object to do dynamic
- decompression if desired.
- */
- for (cur_frame = 0; cur_frame < frame_count; cur_frame++) {
-
- /* Decompress the frame. We don't worry if we failed as
- we'll have an empty sprite that'll just make the animation
- look wrong rather than having no animation at all.
- If we wanted we could stop at this frame and set the maximum
- number of frames as our current frame.
- */
- nsgif_decompress_frame(c, &gif_animation, cur_frame);
-
- }
-
- /* Destroy our animation data. If things are being done dynamically
- then this needs to be done in nsgif_destroy or things will go
- horribly wrong.
- */
- Anim_Destroy(&gif_animation);
-
- /* Finish things off
- */
- c->title = xcalloc(100, sizeof(char));
- sprintf(c->title, messages_get("GIFTitle"), c->width, c->height);
- c->status = CONTENT_STATUS_DONE;
-
- /* Debugging helpers
- */
-/* xosspriteop_save_sprite_file(osspriteop_USER_AREA,
- c->data.gif.sprite_area, "gif");
- if (frame_count > 1) {
- xosfile_save_stamped("gif_frames", 0xffd,
- frame_delays, (unsigned int*)(frame_delays + frame_count));
- }
-*/
-
- if (c->data.gif.animate_gif)
- schedule(frame_delays[0], nsgif_animate, c);
-
/* Exit as a success
*/
+ c->status = CONTENT_STATUS_DONE;
return 0;
}
-/** Decompresses a GIF frame.
- NB: This call uses the current decompressed image as a temporary buffer.
-
- @param c The content store the data back to
- @param p_gif_animation A pointer to the GIF animation to read from
- @param cur_frame The desired frame [0...(max-1)]
- @return <code>true</code> on success, <code>false</code> otherwise
-*/
-bool nsgif_decompress_frame(struct content *c, anim *p_gif_animation, unsigned int cur_frame) {
-
- struct osspriteop_header *sprite_header;
- anim gif_animation = *p_gif_animation;
- frame gif_frame;
- palette frame_palette;
- const unsigned int *palette_entries;
- unsigned int frame_colours;
- unsigned int frame_bpp;
- unsigned int scanline_size;
- unsigned int frame_size;
- unsigned int *sprite_palette;
- unsigned int loop;
- pixel *src;
- pixel *dest;
-
- /* Get the frame details
- */
- gif_frame = gif_animation->pFrames + cur_frame;
- frame_palette = gif_frame->pal;
- palette_entries = frame_palette->pColours;
- frame_colours = frame_palette->nColours;
-
- /* Get the minimum number of bpp for this frame
- */
- frame_bpp = 8;
- if (frame_colours <=16) frame_bpp = 4;
- if (frame_colours <=4) frame_bpp = 2;
- if (frame_colours <=2) frame_bpp = 1;
-
- /* Now we need to calculate how big each sprite is given the
- current number of bits per pixel.
- */
- scanline_size = ((((gif_animation->nWidth * frame_bpp) + 31) & ~31) >> 3);
- frame_size = scanline_size * gif_animation->nHeight;
-
- /* Get our current sprite. For dynamic decompression we should always use 0.
- */
- sprite_header = nsgif_get_sprite_address(c, cur_frame);
-
- /* Set up the sprite header details
- */
- sprite_header->size = frame_size + (8 << frame_bpp) + sizeof(osspriteop_header);
- sprite_header->width = (scanline_size >> 2) - 1;
- sprite_header->height = gif_animation->nHeight - 1;
- sprite_header->left_bit = 0;
- sprite_header->right_bit = (gif_animation->nWidth * frame_bpp - 1 ) & 31;
- sprite_header->image = (8 << frame_bpp) + sizeof(osspriteop_header);
- strcpy(sprite_header->name, "gif");
-
- /* Do the mask stuff if we have one
- */
- if (gif_frame->pMaskData) {
- sprite_header->size += frame_size;
- sprite_header->mask = sprite_header->image + frame_size;
- } else {
- sprite_header->mask = sprite_header->image;
- }
-
- /* Set the mode using old skool values
- */
- switch (frame_bpp) {
- case 1: sprite_header->mode = 18; break;
- case 2: sprite_header->mode = 19; break;
- case 4: sprite_header->mode = 20; break;
- case 8: sprite_header->mode = 21; break;
- }
-
- /* Set up the palette - 2 words per entry.
- */
- sprite_palette = (unsigned int*)(sprite_header + 1);
- memset(sprite_palette, 0, frame_colours);
- for (loop = 0; loop < frame_colours; loop++) {
- *sprite_palette++ = palette_entries[loop];
- *sprite_palette++ = palette_entries[loop];
- }
-
- /* Get the intermediate result place (src) and where it ends up after
- we've changed it to the correct bpp (dest).
- We use our 32bpp sprite buffer as temporary workspace.
- */
- dest = ((pixel*)sprite_header) + sprite_header->image;
- src = (pixel*)c->data.gif.buffer_header;
-
- if (!Anim_Decompress(gif_frame->pImageData, gif_frame->nImageSize,
- gif_animation->nWidth * gif_animation->nHeight, src)) {
- return false;
- }
-
- /* Now we compress each line to the minimum bpp
- */
- for (loop=0; loop < gif_animation->nHeight; loop++) {
- CompressSpriteLine(dest, src, gif_animation->nWidth, frame_bpp );
- dest += scanline_size;
- src += gif_animation->nWidth;
- }
-
- /* As before, but for the mask this time
- */
- if (gif_frame->pMaskData) {
- dest = ((pixel*)sprite_header) + sprite_header->mask;
- src = (pixel*)c->data.gif.buffer_header;
-
- if (!Anim_Decompress(gif_frame->pMaskData, gif_frame->nMaskSize,
- gif_animation->nWidth * gif_animation->nHeight, src)) {
- return false;
- }
-
- /* Now we compress each line to the minimum bpp
- */
- for (loop=0; loop < gif_animation->nHeight; loop++) {
- CompressMaskLine(dest, src, gif_animation->nWidth, frame_bpp);
- dest += scanline_size;
- src += gif_animation->nWidth;
- }
- }
-
- /* Return success
- */
- return true;
-}
-
void nsgif_redraw(struct content *c, long x, long y,
unsigned long width, unsigned long height,
long clip_x0, long clip_y0, long clip_x1, long clip_y1,
float scale) {
-
- /* Hack - animate as if 4cs have passed every redraw
+
+ int previous_frame;
+ unsigned int frame;
+
+ /* Decode from the last frame to the current frame
*/
-/* nsgif_animate(c, 4); */
-
- /* Check if we need to expand the current frame to 32bpp
- */
- if (c->data.gif.current_frame != c->data.gif.expanded_frame) {
-
- /* Convert the sprite
- */
- _swix(Tinct_ConvertSprite, _IN(2) | _IN(3),
- ((char *) nsgif_get_sprite_address(c, c->data.gif.current_frame)),
- ((char *) c->data.gif.buffer_header));
-
- /* Remember we are expanded for future calls
- */
- c->data.gif.expanded_frame = c->data.gif.current_frame;
+ previous_frame = c->data.gif.gif->decoded_frame;
+ if (previous_frame > c->data.gif.current_frame) previous_frame = -1;
+ for (frame = previous_frame + 1; frame <= c->data.gif.current_frame; frame++) {
+ gif_decode_frame(c->data.gif.gif, frame);
}
/* Tinct currently only handles 32bpp sprites that have an embedded alpha mask. Any
@@ -396,7 +105,7 @@ void nsgif_redraw(struct content *c, long x, long y,
documentation for further information.
*/
_swix(Tinct_PlotScaledAlpha, _IN(2) | _IN(3) | _IN(4) | _IN(5) | _IN(6) | _IN(7),
- ((char *) c->data.gif.buffer_header),
+ (char *)c->data.gif.gif->frame_image,
x, (int)(y - height),
width, height,
(option_filter_sprites?(1<<1):0) | (option_dither_sprites?(1<<2):0));
@@ -410,10 +119,8 @@ void nsgif_destroy(struct content *c)
/* Free all the associated memory buffers
*/
schedule_remove(nsgif_animate, c);
- xfree(c->title);
- xfree(c->data.gif.sprite_area);
- xfree(c->data.gif.buffer_header);
- xfree(c->data.gif.frame_transitions);
+ gif_finalise(c->data.gif.gif);
+ xfree(c->data.gif.gif);
}
@@ -428,183 +135,19 @@ void nsgif_animate(void *p)
/* at the moment just advance by one frame */
c->data.gif.current_frame++;
- if (c->data.gif.current_frame == c->data.gif.total_frames) {
- if (!c->data.gif.loop_gif) {
+ if (c->data.gif.current_frame == c->data.gif.gif->frame_count) {
+/* if (!c->data.gif.loop_gif) {
c->data.gif.current_frame--;
c->data.gif.animate_gif = false;
return;
} else
- c->data.gif.current_frame = 0;
+*/ c->data.gif.current_frame = 0;
}
- schedule(c->data.gif.frame_transitions[c->data.gif.current_frame],
+ schedule(c->data.gif.gif->frame_delays[c->data.gif.current_frame],
nsgif_animate, c);
content_broadcast(c, CONTENT_MSG_REDRAW, 0);
}
-
-#if 0
- unsigned int max_frame;
- unsigned int cur_frame;
- unsigned int old_frame;
- unsigned int *delay_values;
-
- /* Abort if we are not animated or cannot animate
- */
- max_frame = c->data.gif.total_frames;
- if ((max_frame < 2) || (!c->data.gif.animate_gif)) return 0;
-
- /* Add in the number of cs we had left over from the last animation
- */
- advance_time += c->data.gif.remainder_time;
-
- /* Get our frame information locally
- */
- cur_frame = c->data.gif.current_frame;
- old_frame = cur_frame;
- delay_values = c->data.gif.frame_transitions;
-
- /* Move through the frames
- */
- while (advance_time >= delay_values[cur_frame]) {
-
- /* Advance a frame
- */
- advance_time -= delay_values[cur_frame++];
-
- /* Handle looping
- */
- if (cur_frame >= max_frame) {
- if (!c->data.gif.loop_gif) {
- c->data.gif.current_frame = max_frame - 1;
- c->data.gif.animate_gif = false;
-
- /* We can't return 0 as it indicates no animation
- has occured, so we return a small value so we
- can be called back and then say that we're done.
- */
- return -1;
- } else {
- cur_frame -= max_frame;
- }
- }
- }
-
- /* Store the leftover time
- */
- c->data.gif.remainder_time = advance_time;
-
- /* Return whether we've changed and when the next update should be
- */
- if (cur_frame == old_frame) {
- return (delay_values[cur_frame] - advance_time);
- } else {
- c->data.gif.current_frame = cur_frame;
- return (advance_time - delay_values[cur_frame]);
- }
-}
-#endif
-
-
-
-/** Provides the address of a frame within the sprite area.
-
- @param c The content to find the frame from
- @param frame The desired frame [0...(max-1)]
- @return The address of the sprite header
-*/
-osspriteop_header *nsgif_get_sprite_address(struct content *c, unsigned int frame) {
-
- struct osspriteop_header *header;
-
- /* Get the header for the first sprite
- */
- header = (osspriteop_header*)((char *)c->data.gif.sprite_area +
- c->data.gif.sprite_area->first);
-
- /* Keep advancing until we get our sprite
- */
- while (frame-- > 0) {
- header = (osspriteop_header*)(((char *)header) + header->size);
- }
-
- /* Return our value
- */
- return header;
-}
-
-
-
-
-/* Shamelessly stolen from AnimLib.savesprite.c
-*/
-static void CompressSpriteLine( pixel *dest, const pixel *src, int n, int bpp )
-{
- int i;
- pixel j;
-
- switch ( bpp )
- {
- case 8:
- if ( src != dest )
- memmove( dest, src, n );
- break;
-
- case 4:
- for ( i=0; i< (n+1)/2; i++ )
- dest[i] = (src[i<<1] & 0xF) + ( src[(i<<1)+1] << 4 ) ;
- break;
-
- case 2:
- for ( i=0; i < (n+3)/4; i++ )
- dest[i] = ( ( src[i<<2 ] ) & 3 )
- | ( ( src[(i<<2)+1] << 2 ) & 0xC )
- | ( ( src[(i<<2)+2] << 4 ) & 0x30 )
- | ( src[(i<<2)+3] << 6 );
- break;
-
- case 1:
- j = 0;
- for ( i=0; i < (n|7)+1; i++ )
- {
- j += (src[i] & 1) << (i&7);
- if ( (i&7) == 7 )
- {
- dest[i>>3] = j;
- j = 0;
- }
- }
- break;
- }
-}
-
-static void CompressMaskLine( pixel *dest, const pixel *src, int n, int bpp )
-{
- int i;
-
- switch ( bpp )
- {
- case 8:
- for ( i=0; i<n; i++ )
- dest[i] = ( src[i] ) ? 0xFF : 0;
- break;
- case 4:
- for ( i=0; i< (n+1)/2; i++ )
- dest[i] = ( src[i<<1] ? 0xF : 0 )
- + ( ( src[(i<<1)+1] ? 0xF : 0 ) << 4 );
- break;
- case 2:
- for ( i=0; i < (n+3)/4; i++ )
- dest[i] = ( src[i<<2 ] ? 0x3 : 0 )
- + ( src[(i<<2)+1] ? 0xC : 0 )
- + ( src[(i<<2)+2] ? 0x30 : 0 )
- + ( src[(i<<2)+3] ? 0xC0 : 0 );
- break;
- case 1:
- CompressSpriteLine( dest, src, n, 1 ); /* It's the same! */
- break;
- }
-}
-
#endif