/contrib/network/netsurf/netsurf/image/bitmap.h |
---|
0,0 → 1,87 |
/* |
* Copyright 2004 James Bursa <bursa@users.sourceforge.net> |
* |
* This file is part of NetSurf, http://www.netsurf-browser.org/ |
* |
* NetSurf is free software; you can redistribute it and/or modify |
* it under the terms of the GNU General Public License as published by |
* the Free Software Foundation; version 2 of the License. |
* |
* NetSurf 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 General Public License for more details. |
* |
* You should have received a copy of the GNU General Public License |
* along with this program. If not, see <http://www.gnu.org/licenses/>. |
*/ |
/** \file |
* Generic bitmap handling (interface). |
* |
* This interface wraps the native platform-specific image format, so that |
* portable image convertors can be written. |
* |
* Bitmaps are required to be 32bpp with components in the order RR GG BB AA. |
* |
* For example, an opaque 1x1 pixel image would yield the following bitmap |
* data: |
* |
* Red : 0xff 0x00 0x00 0x00 |
* Green: 0x00 0xff 0x00 0x00 |
* Blue : 0x00 0x00 0xff 0x00 |
* |
* Any attempt to read pixels by casting bitmap data to uint32_t or similar |
* will need to cater for the order of bytes in a word being different on |
* big and little endian systems. To avoid confusion, it is recommended |
* that pixel data is loaded as follows: |
* |
* uint32_t read_pixel(const uint8_t *bmp) |
* { |
* // red green blue alpha |
* return bmp[0] | (bmp[1] << 8) | (bmp[2] << 16) | (bmp[3] << 24); |
* } |
* |
* and *not* as follows: |
* |
* uint32_t read_pixel(const uint8_t *bmp) |
* { |
* return *((uint32_t *) bmp); |
* } |
*/ |
#ifndef _NETSURF_IMAGE_BITMAP_H_ |
#define _NETSURF_IMAGE_BITMAP_H_ |
#include <stdbool.h> |
#include <stdlib.h> |
#define BITMAP_NEW 0 |
#define BITMAP_OPAQUE (1 << 0) /** image is opaque */ |
#define BITMAP_MODIFIED (1 << 1) /** buffer has been modified */ |
#define BITMAP_PERSISTENT (1 << 2) /** retain between sessions */ |
#define BITMAP_CLEAR_MEMORY (1 << 3) /** memory should be wiped */ |
#define BITMAP_READY (1 << 4) /** fully initialised */ |
#define BITMAP_SAVE_FULL_ALPHA (1 << 0) /** save with full alpha channel (if not opaque) */ |
struct content; |
/** An opaque image. */ |
struct bitmap; |
void *bitmap_create(int width, int height, unsigned int state); |
void bitmap_set_opaque(void *bitmap, bool opaque); |
bool bitmap_test_opaque(void *bitmap); |
bool bitmap_get_opaque(void *bitmap); |
unsigned char *bitmap_get_buffer(void *bitmap); |
size_t bitmap_get_rowstride(void *bitmap); |
size_t bitmap_get_bpp(void *bitmap); |
void bitmap_destroy(void *bitmap); |
bool bitmap_save(void *bitmap, const char *path, unsigned flags); |
void bitmap_modified(void *bitmap); |
int bitmap_get_width(void *bitmap); |
int bitmap_get_height(void *bitmap); |
#endif |
/contrib/network/netsurf/netsurf/image/bmp.c |
---|
0,0 → 1,289 |
/* |
* Copyright 2006 Richard Wilson <info@tinct.net> |
* Copyright 2008 Sean Fox <dyntryx@gmail.com> |
* |
* This file is part of NetSurf, http://www.netsurf-browser.org/ |
* |
* NetSurf is free software; you can redistribute it and/or modify |
* it under the terms of the GNU General Public License as published by |
* the Free Software Foundation; version 2 of the License. |
* |
* NetSurf 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 General Public License for more details. |
* |
* You should have received a copy of the GNU General Public License |
* along with this program. If not, see <http://www.gnu.org/licenses/>. |
*/ |
/** \file |
* Content for image/bmp (implementation) |
*/ |
#include <assert.h> |
#include <string.h> |
#include <stdbool.h> |
#include <stdlib.h> |
#include <libnsbmp.h> |
#include "utils/config.h" |
#include "content/content_protected.h" |
#include "content/hlcache.h" |
#include "desktop/plotters.h" |
#include "utils/log.h" |
#include "utils/messages.h" |
#include "utils/utils.h" |
#include "image/bitmap.h" |
#include "image/bmp.h" |
typedef struct nsbmp_content { |
struct content base; |
bmp_image *bmp; /** BMP image data */ |
struct bitmap *bitmap; /**< Created NetSurf bitmap */ |
} nsbmp_content; |
static nserror nsbmp_create_bmp_data(nsbmp_content *bmp) |
{ |
union content_msg_data msg_data; |
bmp->bmp = calloc(sizeof(struct bmp_image), 1); |
if (bmp->bmp == NULL) { |
msg_data.error = messages_get("NoMemory"); |
content_broadcast(&bmp->base, CONTENT_MSG_ERROR, msg_data); |
return NSERROR_NOMEM; |
} |
bmp_create(bmp->bmp, &bmp_bitmap_callbacks); |
return NSERROR_OK; |
} |
static nserror nsbmp_create(const content_handler *handler, |
lwc_string *imime_type, const struct http_parameter *params, |
llcache_handle *llcache, const char *fallback_charset, |
bool quirks, struct content **c) |
{ |
nsbmp_content *bmp; |
nserror error; |
bmp = calloc(1, sizeof(nsbmp_content)); |
if (bmp == NULL) |
return NSERROR_NOMEM; |
error = content__init(&bmp->base, handler, imime_type, params, |
llcache, fallback_charset, quirks); |
if (error != NSERROR_OK) { |
free(bmp); |
return error; |
} |
error = nsbmp_create_bmp_data(bmp); |
if (error != NSERROR_OK) { |
free(bmp); |
return error; |
} |
*c = (struct content *) bmp; |
return NSERROR_OK; |
} |
/** |
* Callback for libnsbmp; forwards the call to bitmap_create() |
* |
* \param width width of image in pixels |
* \param height width of image in pixels |
* \param state a flag word indicating the initial state |
* \return an opaque struct bitmap, or NULL on memory exhaustion |
*/ |
static void *nsbmp_bitmap_create(int width, int height, unsigned int bmp_state) |
{ |
unsigned int bitmap_state = BITMAP_NEW; |
/* set bitmap state based on bmp state */ |
bitmap_state |= (bmp_state & BMP_OPAQUE) ? BITMAP_OPAQUE : 0; |
bitmap_state |= (bmp_state & BMP_CLEAR_MEMORY) ? |
BITMAP_CLEAR_MEMORY : 0; |
/* return the created bitmap */ |
return bitmap_create(width, height, bitmap_state); |
} |
/* The Bitmap callbacks function table; |
* necessary for interaction with nsbmplib. |
*/ |
bmp_bitmap_callback_vt bmp_bitmap_callbacks = { |
.bitmap_create = nsbmp_bitmap_create, |
.bitmap_destroy = bitmap_destroy, |
.bitmap_get_buffer = bitmap_get_buffer, |
.bitmap_get_bpp = bitmap_get_bpp |
}; |
static bool nsbmp_convert(struct content *c) |
{ |
nsbmp_content *bmp = (nsbmp_content *) c; |
bmp_result res; |
union content_msg_data msg_data; |
uint32_t swidth; |
const char *data; |
unsigned long size; |
char *title; |
/* set the bmp data */ |
data = content__get_source_data(c, &size); |
/* analyse the BMP */ |
res = bmp_analyse(bmp->bmp, size, (unsigned char *) data); |
switch (res) { |
case BMP_OK: |
break; |
case BMP_INSUFFICIENT_MEMORY: |
msg_data.error = messages_get("NoMemory"); |
content_broadcast(c, CONTENT_MSG_ERROR, msg_data); |
return false; |
case BMP_INSUFFICIENT_DATA: |
case BMP_DATA_ERROR: |
msg_data.error = messages_get("BadBMP"); |
content_broadcast(c, CONTENT_MSG_ERROR, msg_data); |
return false; |
} |
/* Store our content width and description */ |
c->width = bmp->bmp->width; |
c->height = bmp->bmp->height; |
swidth = bmp->bmp->bitmap_callbacks.bitmap_get_bpp(bmp->bmp->bitmap) * |
bmp->bmp->width; |
c->size += (swidth * bmp->bmp->height) + 16 + 44; |
/* set title text */ |
title = messages_get_buff("BMPTitle", |
nsurl_access_leaf(llcache_handle_get_url(c->llcache)), |
c->width, c->height); |
if (title != NULL) { |
content__set_title(c, title); |
free(title); |
} |
/* exit as a success */ |
bmp->bitmap = bmp->bmp->bitmap; |
bitmap_modified(bmp->bitmap); |
content_set_ready(c); |
content_set_done(c); |
/* Done: update status bar */ |
content_set_status(c, ""); |
return true; |
} |
static bool nsbmp_redraw(struct content *c, struct content_redraw_data *data, |
const struct rect *clip, const struct redraw_context *ctx) |
{ |
nsbmp_content *bmp = (nsbmp_content *) c; |
bitmap_flags_t flags = BITMAPF_NONE; |
if (bmp->bmp->decoded == false) |
if (bmp_decode(bmp->bmp) != BMP_OK) |
return false; |
bmp->bitmap = bmp->bmp->bitmap; |
if (data->repeat_x) |
flags |= BITMAPF_REPEAT_X; |
if (data->repeat_y) |
flags |= BITMAPF_REPEAT_Y; |
return ctx->plot->bitmap(data->x, data->y, data->width, data->height, |
bmp->bitmap, data->background_colour, flags); |
} |
static void nsbmp_destroy(struct content *c) |
{ |
nsbmp_content *bmp = (nsbmp_content *) c; |
bmp_finalise(bmp->bmp); |
free(bmp->bmp); |
} |
static nserror nsbmp_clone(const struct content *old, struct content **newc) |
{ |
nsbmp_content *new_bmp; |
nserror error; |
new_bmp = calloc(1, sizeof(nsbmp_content)); |
if (new_bmp == NULL) |
return NSERROR_NOMEM; |
error = content__clone(old, &new_bmp->base); |
if (error != NSERROR_OK) { |
content_destroy(&new_bmp->base); |
return error; |
} |
/* We "clone" the old content by replaying creation and conversion */ |
error = nsbmp_create_bmp_data(new_bmp); |
if (error != NSERROR_OK) { |
content_destroy(&new_bmp->base); |
return error; |
} |
if (old->status == CONTENT_STATUS_READY || |
old->status == CONTENT_STATUS_DONE) { |
if (nsbmp_convert(&new_bmp->base) == false) { |
content_destroy(&new_bmp->base); |
return NSERROR_CLONE_FAILED; |
} |
} |
*newc = (struct content *) new_bmp; |
return NSERROR_OK; |
} |
static void *nsbmp_get_internal(const struct content *c, void *context) |
{ |
nsbmp_content *bmp = (nsbmp_content *)c; |
return bmp->bitmap; |
} |
static content_type nsbmp_content_type(void) |
{ |
return CONTENT_IMAGE; |
} |
static const content_handler nsbmp_content_handler = { |
.create = nsbmp_create, |
.data_complete = nsbmp_convert, |
.destroy = nsbmp_destroy, |
.redraw = nsbmp_redraw, |
.clone = nsbmp_clone, |
.get_internal = nsbmp_get_internal, |
.type = nsbmp_content_type, |
.no_share = false, |
}; |
static const char *nsbmp_types[] = { |
"application/bmp", |
"application/preview", |
"application/x-bmp", |
"application/x-win-bitmap", |
"image/bmp", |
"image/ms-bmp", |
"image/x-bitmap", |
"image/x-bmp", |
"image/x-ms-bmp", |
"image/x-win-bitmap", |
"image/x-windows-bmp", |
"image/x-xbitmap" |
}; |
CONTENT_FACTORY_REGISTER_TYPES(nsbmp, nsbmp_types, nsbmp_content_handler); |
/contrib/network/netsurf/netsurf/image/bmp.h |
---|
0,0 → 1,35 |
/* |
* Copyright 2006 Richard Wilson <info@tinct.net> |
* Copyright 2008 Sean Fox <dyntryx@gmail.com> |
* |
* This file is part of NetSurf, http://www.netsurf-browser.org/ |
* |
* NetSurf is free software; you can redistribute it and/or modify |
* it under the terms of the GNU General Public License as published by |
* the Free Software Foundation; version 2 of the License. |
* |
* NetSurf 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 General Public License for more details. |
* |
* You should have received a copy of the GNU General Public License |
* along with this program. If not, see <http://www.gnu.org/licenses/>. |
*/ |
/** \file |
* Content for image/bmp (interface). |
*/ |
#ifndef _NETSURF_IMAGE_BMP_H_ |
#define _NETSURF_IMAGE_BMP_H_ |
#include <libnsbmp.h> |
#include "image/bitmap.h" |
extern bmp_bitmap_callback_vt bmp_bitmap_callbacks; /** Only to be used by ICO code. */ |
nserror nsbmp_init(void); |
#endif |
/contrib/network/netsurf/netsurf/image/gif.c |
---|
0,0 → 1,427 |
/* |
* Copyright 2003 John M Bell <jmb202@ecs.soton.ac.uk> |
* Copyright 2004 Richard Wilson <not_ginger_matt@users.sourceforge.net> |
* Copyright 2008 Sean Fox <dyntryx@gmail.com> |
* |
* This file is part of NetSurf, http://www.netsurf-browser.org/ |
* |
* NetSurf is free software; you can redistribute it and/or modify |
* it under the terms of the GNU General Public License as published by |
* the Free Software Foundation; version 2 of the License. |
* |
* NetSurf 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 General Public License for more details. |
* |
* You should have received a copy of the GNU General Public License |
* along with this program. If not, see <http://www.gnu.org/licenses/>. |
*/ |
/** \file |
* Content for image/gif (implementation) |
* |
* 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 |
*/ |
#include <assert.h> |
#include <string.h> |
#include <stdbool.h> |
#include <stdlib.h> |
#include <libnsgif.h> |
#include "utils/config.h" |
#include "content/content_protected.h" |
#include "content/hlcache.h" |
#include "desktop/options.h" |
#include "desktop/plotters.h" |
#include "image/image.h" |
#include "image/bitmap.h" |
#include "image/gif.h" |
#include "utils/log.h" |
#include "utils/messages.h" |
#include "utils/schedule.h" |
#include "utils/utils.h" |
typedef struct nsgif_content { |
struct content base; |
struct gif_animation *gif; /**< GIF animation data */ |
int current_frame; /**< current frame to display [0...(max-1)] */ |
} nsgif_content; |
/** |
* Callback for libnsgif; forwards the call to bitmap_create() |
* |
* \param width width of image in pixels |
* \param height width of image in pixels |
* \return an opaque struct bitmap, or NULL on memory exhaustion |
*/ |
static void *nsgif_bitmap_create(int width, int height) |
{ |
return bitmap_create(width, height, BITMAP_NEW); |
} |
/* The Bitmap callbacks function table; |
* necessary for interaction with nsgiflib. |
*/ |
static gif_bitmap_callback_vt gif_bitmap_callbacks = { |
.bitmap_create = nsgif_bitmap_create, |
.bitmap_destroy = bitmap_destroy, |
.bitmap_get_buffer = bitmap_get_buffer, |
.bitmap_set_opaque = bitmap_set_opaque, |
.bitmap_test_opaque = bitmap_test_opaque, |
.bitmap_modified = bitmap_modified |
}; |
static nserror nsgif_create_gif_data(nsgif_content *c) |
{ |
union content_msg_data msg_data; |
/* Initialise our data structure */ |
c->gif = calloc(sizeof(gif_animation), 1); |
if (c->gif == NULL) { |
msg_data.error = messages_get("NoMemory"); |
content_broadcast(&c->base, CONTENT_MSG_ERROR, msg_data); |
return NSERROR_NOMEM; |
} |
gif_create(c->gif, &gif_bitmap_callbacks); |
return NSERROR_OK; |
} |
static nserror nsgif_create(const content_handler *handler, |
lwc_string *imime_type, const struct http_parameter *params, |
llcache_handle *llcache, const char *fallback_charset, |
bool quirks, struct content **c) |
{ |
nsgif_content *result; |
nserror error; |
result = calloc(1, sizeof(nsgif_content)); |
if (result == NULL) |
return NSERROR_NOMEM; |
error = content__init(&result->base, handler, imime_type, params, |
llcache, fallback_charset, quirks); |
if (error != NSERROR_OK) { |
free(result); |
return error; |
} |
error = nsgif_create_gif_data(result); |
if (error != NSERROR_OK) { |
free(result); |
return error; |
} |
*c = (struct content *) result; |
return NSERROR_OK; |
} |
/** |
* Performs any necessary animation. |
* |
* \param p The content to animate |
*/ |
static void nsgif_animate(void *p) |
{ |
nsgif_content *gif = p; |
union content_msg_data data; |
int delay; |
int f; |
/* Advance by a frame, updating the loop count accordingly */ |
gif->current_frame++; |
if (gif->current_frame == (int)gif->gif->frame_count_partial) { |
gif->current_frame = 0; |
/* A loop count of 0 has a special meaning of infinite */ |
if (gif->gif->loop_count != 0) { |
gif->gif->loop_count--; |
if (gif->gif->loop_count == 0) { |
gif->current_frame = |
gif->gif->frame_count_partial - 1; |
gif->gif->loop_count = -1; |
} |
} |
} |
/* Continue animating if we should */ |
if (gif->gif->loop_count >= 0) { |
delay = gif->gif->frames[gif->current_frame].frame_delay; |
if (delay < nsoption_int(minimum_gif_delay)) |
delay = nsoption_int(minimum_gif_delay); |
schedule(delay, nsgif_animate, gif); |
} |
if ((!nsoption_bool(animate_images)) || |
(!gif->gif->frames[gif->current_frame].display)) { |
return; |
} |
/* area within gif to redraw */ |
f = gif->current_frame; |
data.redraw.x = gif->gif->frames[f].redraw_x; |
data.redraw.y = gif->gif->frames[f].redraw_y; |
data.redraw.width = gif->gif->frames[f].redraw_width; |
data.redraw.height = gif->gif->frames[f].redraw_height; |
/* redraw background (true) or plot on top (false) */ |
if (gif->current_frame > 0) { |
data.redraw.full_redraw = |
gif->gif->frames[f - 1].redraw_required; |
/* previous frame needed clearing: expand the redraw area to |
* cover it */ |
if (data.redraw.full_redraw) { |
if (data.redraw.x > |
(int)(gif->gif->frames[f - 1].redraw_x)) { |
data.redraw.width += data.redraw.x - |
gif->gif->frames[f - 1].redraw_x; |
data.redraw.x = |
gif->gif->frames[f - 1].redraw_x; |
} |
if (data.redraw.y > |
(int)(gif->gif->frames[f - 1].redraw_y)) { |
data.redraw.height += (data.redraw.y - |
gif->gif->frames[f - 1].redraw_y); |
data.redraw.y = |
gif->gif->frames[f - 1].redraw_y; |
} |
if ((int)(gif->gif->frames[f - 1].redraw_x + |
gif->gif->frames[f - 1].redraw_width) > |
(data.redraw.x + data.redraw.width)) |
data.redraw.width = |
gif->gif->frames[f - 1].redraw_x - |
data.redraw.x + |
gif->gif->frames[f - 1].redraw_width; |
if ((int)(gif->gif->frames[f - 1].redraw_y + |
gif->gif->frames[f - 1].redraw_height) > |
(data.redraw.y + data.redraw.height)) |
data.redraw.height = |
gif->gif->frames[f - 1].redraw_y - |
data.redraw.y + |
gif->gif->frames[f - 1].redraw_height; |
} |
} else { |
/* do advanced check */ |
if ((data.redraw.x == 0) && (data.redraw.y == 0) && |
(data.redraw.width == (int)(gif->gif->width)) && |
(data.redraw.height == (int)(gif->gif->height))) { |
data.redraw.full_redraw = !gif->gif->frames[f].opaque; |
} else { |
data.redraw.full_redraw = true; |
data.redraw.x = 0; |
data.redraw.y = 0; |
data.redraw.width = gif->gif->width; |
data.redraw.height = gif->gif->height; |
} |
} |
/* other data */ |
data.redraw.object = (struct content *) gif; |
data.redraw.object_x = 0; |
data.redraw.object_y = 0; |
data.redraw.object_width = gif->base.width; |
data.redraw.object_height = gif->base.height; |
content_broadcast(&gif->base, CONTENT_MSG_REDRAW, data); |
} |
static bool nsgif_convert(struct content *c) |
{ |
nsgif_content *gif = (nsgif_content *) c; |
int res; |
union content_msg_data msg_data; |
const char *data; |
unsigned long size; |
char *title; |
/* Get the animation */ |
data = content__get_source_data(c, &size); |
/* Initialise the GIF */ |
do { |
res = gif_initialise(gif->gif, size, (unsigned char *) data); |
if (res != GIF_OK && res != GIF_WORKING && |
res != GIF_INSUFFICIENT_FRAME_DATA) { |
switch (res) { |
case GIF_FRAME_DATA_ERROR: |
case GIF_INSUFFICIENT_DATA: |
case GIF_DATA_ERROR: |
msg_data.error = messages_get("BadGIF"); |
break; |
case GIF_INSUFFICIENT_MEMORY: |
msg_data.error = messages_get("NoMemory"); |
break; |
} |
content_broadcast(c, CONTENT_MSG_ERROR, msg_data); |
return false; |
} |
} while (res != GIF_OK && res != GIF_INSUFFICIENT_FRAME_DATA); |
/* Abort on bad GIFs */ |
if ((gif->gif->frame_count_partial == 0) || (gif->gif->width == 0) || |
(gif->gif->height == 0)) { |
msg_data.error = messages_get("BadGIF"); |
content_broadcast(c, CONTENT_MSG_ERROR, msg_data); |
return false; |
} |
/* Store our content width, height and calculate size */ |
c->width = gif->gif->width; |
c->height = gif->gif->height; |
c->size += (gif->gif->width * gif->gif->height * 4) + 16 + 44; |
/* set title text */ |
title = messages_get_buff("GIFTitle", |
nsurl_access_leaf(llcache_handle_get_url(c->llcache)), |
c->width, c->height); |
if (title != NULL) { |
content__set_title(c, title); |
free(title); |
} |
/* Schedule the animation if we have one */ |
gif->current_frame = 0; |
if (gif->gif->frame_count_partial > 1) |
schedule(gif->gif->frames[0].frame_delay, nsgif_animate, c); |
/* Exit as a success */ |
content_set_ready(c); |
content_set_done(c); |
/* Done: update status bar */ |
content_set_status(c, ""); |
return true; |
} |
/** |
* Updates the GIF bitmap to display the current frame |
* |
* \param c the content to update |
*/ |
static gif_result nsgif_get_frame(nsgif_content *gif) |
{ |
int previous_frame, current_frame, frame; |
gif_result res = GIF_OK; |
current_frame = gif->current_frame; |
if (!nsoption_bool(animate_images)) { |
current_frame = 0; |
} |
if (current_frame < gif->gif->decoded_frame) |
previous_frame = 0; |
else |
previous_frame = gif->gif->decoded_frame + 1; |
for (frame = previous_frame; frame <= current_frame; frame++) { |
res = gif_decode_frame(gif->gif, frame); |
} |
return res; |
} |
static bool nsgif_redraw(struct content *c, struct content_redraw_data *data, |
const struct rect *clip, const struct redraw_context *ctx) |
{ |
nsgif_content *gif = (nsgif_content *) c; |
if (gif->current_frame != gif->gif->decoded_frame) { |
if (nsgif_get_frame(gif) != GIF_OK) { |
return false; |
} |
} |
return image_bitmap_plot(gif->gif->frame_image, data, clip, ctx); |
} |
static void nsgif_destroy(struct content *c) |
{ |
nsgif_content *gif = (nsgif_content *) c; |
/* Free all the associated memory buffers */ |
schedule_remove(nsgif_animate, c); |
gif_finalise(gif->gif); |
free(gif->gif); |
} |
static nserror nsgif_clone(const struct content *old, struct content **newc) |
{ |
nsgif_content *gif; |
nserror error; |
gif = calloc(1, sizeof(nsgif_content)); |
if (gif == NULL) |
return NSERROR_NOMEM; |
error = content__clone(old, &gif->base); |
if (error != NSERROR_OK) { |
content_destroy(&gif->base); |
return error; |
} |
/* Simply replay creation and conversion of content */ |
error = nsgif_create_gif_data(gif); |
if (error != NSERROR_OK) { |
content_destroy(&gif->base); |
return error; |
} |
if (old->status == CONTENT_STATUS_READY || |
old->status == CONTENT_STATUS_DONE) { |
if (nsgif_convert(&gif->base) == false) { |
content_destroy(&gif->base); |
return NSERROR_CLONE_FAILED; |
} |
} |
*newc = (struct content *) gif; |
return NSERROR_OK; |
} |
static void *nsgif_get_internal(const struct content *c, void *context) |
{ |
nsgif_content *gif = (nsgif_content *) c; |
if (gif->current_frame != gif->gif->decoded_frame) { |
if (nsgif_get_frame(gif) != GIF_OK) |
return NULL; |
} |
return gif->gif->frame_image; |
} |
static content_type nsgif_content_type(void) |
{ |
return CONTENT_IMAGE; |
} |
static const content_handler nsgif_content_handler = { |
.create = nsgif_create, |
.data_complete = nsgif_convert, |
.destroy = nsgif_destroy, |
.redraw = nsgif_redraw, |
.clone = nsgif_clone, |
.get_internal = nsgif_get_internal, |
.type = nsgif_content_type, |
.no_share = false, |
}; |
static const char *nsgif_types[] = { |
"image/gif" |
}; |
CONTENT_FACTORY_REGISTER_TYPES(nsgif, nsgif_types, nsgif_content_handler); |
/contrib/network/netsurf/netsurf/image/gif.h |
---|
0,0 → 1,29 |
/* |
* Copyright 2004 Richard Wilson <not_ginger_matt@users.sourceforge.net> |
* Copyright 2008 Sean Fox <dyntryx@gmail.com> |
* |
* This file is part of NetSurf, http://www.netsurf-browser.org/ |
* |
* NetSurf is free software; you can redistribute it and/or modify |
* it under the terms of the GNU General Public License as published by |
* the Free Software Foundation; version 2 of the License. |
* |
* NetSurf 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 General Public License for more details. |
* |
* You should have received a copy of the GNU General Public License |
* along with this program. If not, see <http://www.gnu.org/licenses/>. |
*/ |
/** \file |
* Content for image/gif (interface). |
*/ |
#ifndef _NETSURF_IMAGE_GIF_H_ |
#define _NETSURF_IMAGE_GIF_H_ |
nserror nsgif_init(void); |
#endif |
/contrib/network/netsurf/netsurf/image/ico.c |
---|
0,0 → 1,277 |
/* |
* Copyright 2006 Richard Wilson <info@tinct.net> |
* |
* This file is part of NetSurf, http://www.netsurf-browser.org/ |
* |
* NetSurf is free software; you can redistribute it and/or modify |
* it under the terms of the GNU General Public License as published by |
* the Free Software Foundation; version 2 of the License. |
* |
* NetSurf 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 General Public License for more details. |
* |
* You should have received a copy of the GNU General Public License |
* along with this program. If not, see <http://www.gnu.org/licenses/>. |
*/ |
/** \file |
* Content for image/ico (implementation) |
*/ |
#include <assert.h> |
#include <string.h> |
#include <stdbool.h> |
#include <stdlib.h> |
#include <libnsbmp.h> |
#include "utils/config.h" |
#include "content/content_protected.h" |
#include "content/hlcache.h" |
#include "desktop/plotters.h" |
#include "image/bitmap.h" |
#include "image/bmp.h" |
#include "image/ico.h" |
#include "image/image.h" |
#include "utils/log.h" |
#include "utils/messages.h" |
#include "utils/utils.h" |
typedef struct nsico_content { |
struct content base; |
struct ico_collection *ico; /** ICO collection data */ |
} nsico_content; |
static nserror nsico_create_ico_data(nsico_content *c) |
{ |
union content_msg_data msg_data; |
c->ico = calloc(sizeof(ico_collection), 1); |
if (c->ico == NULL) { |
msg_data.error = messages_get("NoMemory"); |
content_broadcast(&c->base, CONTENT_MSG_ERROR, msg_data); |
return NSERROR_NOMEM; |
} |
ico_collection_create(c->ico, &bmp_bitmap_callbacks); |
return NSERROR_OK; |
} |
static nserror nsico_create(const content_handler *handler, |
lwc_string *imime_type, const struct http_parameter *params, |
llcache_handle *llcache, const char *fallback_charset, |
bool quirks, struct content **c) |
{ |
nsico_content *result; |
nserror error; |
result = calloc(1, sizeof(nsico_content)); |
if (result == NULL) |
return NSERROR_NOMEM; |
error = content__init(&result->base, handler, imime_type, params, |
llcache, fallback_charset, quirks); |
if (error != NSERROR_OK) { |
free(result); |
return error; |
} |
error = nsico_create_ico_data(result); |
if (error != NSERROR_OK) { |
free(result); |
return error; |
} |
*c = (struct content *) result; |
return NSERROR_OK; |
} |
static bool nsico_convert(struct content *c) |
{ |
nsico_content *ico = (nsico_content *) c; |
struct bmp_image *bmp; |
bmp_result res; |
union content_msg_data msg_data; |
const char *data; |
unsigned long size; |
char *title; |
/* set the ico data */ |
data = content__get_source_data(c, &size); |
/* analyse the ico */ |
res = ico_analyse(ico->ico, size, (unsigned char *) data); |
switch (res) { |
case BMP_OK: |
break; |
case BMP_INSUFFICIENT_MEMORY: |
msg_data.error = messages_get("NoMemory"); |
content_broadcast(c, CONTENT_MSG_ERROR, msg_data); |
return false; |
case BMP_INSUFFICIENT_DATA: |
case BMP_DATA_ERROR: |
msg_data.error = messages_get("BadICO"); |
content_broadcast(c, CONTENT_MSG_ERROR, msg_data); |
return false; |
} |
/* Store our content width, height and calculate size */ |
c->width = ico->ico->width; |
c->height = ico->ico->height; |
c->size += (ico->ico->width * ico->ico->height * 4) + 16 + 44; |
/* set title text */ |
title = messages_get_buff("ICOTitle", |
nsurl_access_leaf(llcache_handle_get_url(c->llcache)), |
c->width, c->height); |
if (title != NULL) { |
content__set_title(c, title); |
free(title); |
} |
/* select largest icon to ensure one can be selected */ |
bmp = ico_find(ico->ico, 255, 255); |
if (bmp == NULL) { |
/* return error */ |
LOG(("Failed to select icon")); |
return false; |
} |
content_set_ready(c); |
content_set_done(c); |
/* Done: update status bar */ |
content_set_status(c, ""); |
return true; |
} |
static bool nsico_redraw(struct content *c, struct content_redraw_data *data, |
const struct rect *clip, const struct redraw_context *ctx) |
{ |
nsico_content *ico = (nsico_content *)c; |
struct bmp_image *bmp; |
/* select most appropriate sized icon for size */ |
bmp = ico_find(ico->ico, data->width, data->height); |
if (bmp == NULL) { |
/* return error */ |
LOG(("Failed to select icon")); |
return false; |
} |
/* ensure its decided */ |
if (bmp->decoded == false) { |
if (bmp_decode(bmp) != BMP_OK) { |
return false; |
} else { |
LOG(("Decoding bitmap")); |
bitmap_modified(bmp->bitmap); |
} |
} |
return image_bitmap_plot(bmp->bitmap, data, clip, ctx); |
} |
static void nsico_destroy(struct content *c) |
{ |
nsico_content *ico = (nsico_content *) c; |
ico_finalise(ico->ico); |
free(ico->ico); |
} |
static nserror nsico_clone(const struct content *old, struct content **newc) |
{ |
nsico_content *ico; |
nserror error; |
ico = calloc(1, sizeof(nsico_content)); |
if (ico == NULL) |
return NSERROR_NOMEM; |
error = content__clone(old, &ico->base); |
if (error != NSERROR_OK) { |
content_destroy(&ico->base); |
return error; |
} |
/* Simply replay creation and conversion */ |
error = nsico_create_ico_data(ico); |
if (error != NSERROR_OK) { |
content_destroy(&ico->base); |
return error; |
} |
if (old->status == CONTENT_STATUS_READY || |
old->status == CONTENT_STATUS_DONE) { |
if (nsico_convert(&ico->base) == false) { |
content_destroy(&ico->base); |
return NSERROR_CLONE_FAILED; |
} |
} |
*newc = (struct content *) ico; |
return NSERROR_OK; |
} |
static void *nsico_get_internal(const struct content *c, void *context) |
{ |
nsico_content *ico = (nsico_content *) c; |
/* TODO: Pick best size for purpose. |
* Currently assumes it's for a URL bar. */ |
struct bmp_image *bmp; |
bmp = ico_find(ico->ico, 16, 16); |
if (bmp == NULL) { |
/* return error */ |
LOG(("Failed to select icon")); |
return NULL; |
} |
if (bmp->decoded == false) { |
if (bmp_decode(bmp) != BMP_OK) { |
return NULL; |
} else { |
bitmap_modified(bmp->bitmap); |
} |
} |
return bmp->bitmap; |
} |
static content_type nsico_content_type(void) |
{ |
return CONTENT_IMAGE; |
} |
static const content_handler nsico_content_handler = { |
.create = nsico_create, |
.data_complete = nsico_convert, |
.destroy = nsico_destroy, |
.redraw = nsico_redraw, |
.clone = nsico_clone, |
.get_internal = nsico_get_internal, |
.type = nsico_content_type, |
.no_share = false, |
}; |
static const char *nsico_types[] = { |
"application/ico", |
"application/x-ico", |
"image/ico", |
"image/vnd.microsoft.icon", |
"image/x-icon" |
}; |
CONTENT_FACTORY_REGISTER_TYPES(nsico, nsico_types, nsico_content_handler); |
/contrib/network/netsurf/netsurf/image/ico.h |
---|
0,0 → 1,28 |
/* |
* Copyright 2006 Richard Wilson <info@tinct.net> |
* |
* This file is part of NetSurf, http://www.netsurf-browser.org/ |
* |
* NetSurf is free software; you can redistribute it and/or modify |
* it under the terms of the GNU General Public License as published by |
* the Free Software Foundation; version 2 of the License. |
* |
* NetSurf 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 General Public License for more details. |
* |
* You should have received a copy of the GNU General Public License |
* along with this program. If not, see <http://www.gnu.org/licenses/>. |
*/ |
/** \file |
* Content for image/ico (interface). |
*/ |
#ifndef _NETSURF_IMAGE_ICO_H_ |
#define _NETSURF_IMAGE_ICO_H_ |
nserror nsico_init(void); |
#endif |
/contrib/network/netsurf/netsurf/image/image.c |
---|
0,0 → 1,181 |
/* |
* Copyright 2011 John-Mark Bell <jmb@netsurf-browser.org> |
* |
* This file is part of NetSurf, http://www.netsurf-browser.org/ |
* |
* NetSurf is free software; you can redistribute it and/or modify |
* it under the terms of the GNU General Public License as published by |
* the Free Software Foundation; version 2 of the License. |
* |
* NetSurf 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 General Public License for more details. |
* |
* You should have received a copy of the GNU General Public License |
* along with this program. If not, see <http://www.gnu.org/licenses/>. |
*/ |
#include <assert.h> |
#include <stdint.h> |
#include <stdbool.h> |
#include <string.h> |
#include "utils/errors.h" |
#include "utils/config.h" |
#include "utils/log.h" |
#include "desktop/plotters.h" |
#include "image/bitmap.h" |
#include "image/bmp.h" |
#include "image/gif.h" |
#include "image/ico.h" |
#include "image/jpeg.h" |
#include "image/mng.h" |
#include "image/nssprite.h" |
#include "image/png.h" |
#include "image/rsvg.h" |
#include "image/svg.h" |
#include "image/webp.h" |
#include "image/image.h" |
/** |
* Initialise image content handlers |
* |
* \return NSERROR_OK on success, appropriate error otherwise. |
*/ |
nserror image_init(void) |
{ |
nserror error; |
#ifdef WITH_BMP |
error = nsbmp_init(); |
if (error != NSERROR_OK) |
return error; |
#endif |
#ifdef WITH_GIF |
error = nsgif_init(); |
if (error != NSERROR_OK) |
return error; |
#endif |
#ifdef WITH_BMP |
error = nsico_init(); |
if (error != NSERROR_OK) |
return error; |
#endif |
#ifdef WITH_JPEG |
error = nsjpeg_init(); |
if (error != NSERROR_OK) |
return error; |
#endif |
#ifdef WITH_MNG |
error = nsmng_init(); |
if (error != NSERROR_OK) |
return error; |
error = nsjpng_init(); |
if (error != NSERROR_OK) |
return error; |
#endif |
#ifdef WITH_PNG |
/* Prefer libpng over libmng for pngs by registering later */ |
error = nspng_init(); |
if (error != NSERROR_OK) |
return error; |
#endif |
#ifdef WITH_NSSPRITE |
error = nssprite_init(); |
if (error != NSERROR_OK) |
return error; |
#endif |
/* Prefer rsvg over libsvgtiny for svgs */ |
#ifdef WITH_NS_SVG |
error = svg_init(); |
if (error != NSERROR_OK) |
return error; |
#endif |
#ifdef WITH_RSVG |
error = nsrsvg_init(); |
if (error != NSERROR_OK) |
return error; |
#endif |
#ifdef WITH_WEBP |
error = webp_init(); |
if (error != NSERROR_OK) |
return error; |
#endif /* WITH_WEBP */ |
return NSERROR_OK; |
} |
bool image_bitmap_plot(struct bitmap *bitmap, |
struct content_redraw_data *data, |
const struct rect *clip, |
const struct redraw_context *ctx) |
{ |
bitmap_flags_t flags = BITMAPF_NONE; |
int width; |
int height; |
unsigned char *pixel; |
plot_style_t fill_style; |
struct rect area; |
width = bitmap_get_width(bitmap); |
if (width == 1) { |
height = bitmap_get_height(bitmap); |
if (height == 1) { |
/* optimise 1x1 bitmap plot */ |
pixel = bitmap_get_buffer(bitmap); |
fill_style.fill_colour = pixel_to_colour(pixel); |
if (bitmap_get_opaque(bitmap) || |
((fill_style.fill_colour & 0xff000000) == 0xff000000)) { |
area = *clip; |
if (data->repeat_x != true) { |
area.x0 = data->x; |
area.x1 = data->x + data->width; |
} |
if (data->repeat_y != true) { |
area.y0 = data->y; |
area.y1 = data->y + data->height; |
} |
fill_style.stroke_type = PLOT_OP_TYPE_NONE; |
fill_style.fill_type = PLOT_OP_TYPE_SOLID; |
return ctx->plot->rectangle(area.x0, area.y0, |
area.x1, area.y1, |
&fill_style); |
} else if ((fill_style.fill_colour & 0xff000000) == 0) { |
/* transparent pixel used as spacer, skip it */ |
return true; |
} |
} |
} |
/* do the plot */ |
if (data->repeat_x) |
flags |= BITMAPF_REPEAT_X; |
if (data->repeat_y) |
flags |= BITMAPF_REPEAT_Y; |
return ctx->plot->bitmap(data->x, data->y, data->width, data->height, |
bitmap, data->background_colour, flags); |
} |
/contrib/network/netsurf/netsurf/image/image.h |
---|
0,0 → 1,43 |
/* |
* Copyright 2011 John-Mark Bell <jmb@netsurf-browser.org> |
* |
* This file is part of NetSurf, http://www.netsurf-browser.org/ |
* |
* NetSurf is free software; you can redistribute it and/or modify |
* it under the terms of the GNU General Public License as published by |
* the Free Software Foundation; version 2 of the License. |
* |
* NetSurf 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 General Public License for more details. |
* |
* You should have received a copy of the GNU General Public License |
* along with this program. If not, see <http://www.gnu.org/licenses/>. |
*/ |
/** \file |
* Initialisation/finalisation of image handlers. |
*/ |
#ifndef NETSURF_IMAGE_IMAGE_H_ |
#define NETSURF_IMAGE_IMAGE_H_ |
#include "utils/errors.h" |
/** Initialise the content handlers for image types. |
*/ |
nserror image_init(void); |
/** Common image content handler bitmap plot call. |
* |
* This plots the specified bitmap controlled by the redraw context |
* and specific content redraw data. It is a helper specifically |
* provided for image content handlers redraw callback. |
*/ |
bool image_bitmap_plot(struct bitmap *bitmap, |
struct content_redraw_data *data, |
const struct rect *clip, |
const struct redraw_context *ctx); |
#endif |
/contrib/network/netsurf/netsurf/image/image_cache.c |
---|
0,0 → 1,800 |
/* |
* Copyright 2011 Vincent Sanders <vince@netsurf-browser.org> |
* |
* This file is part of NetSurf, http://www.netsurf-browser.org/ |
* |
* NetSurf is free software; you can redistribute it and/or modify |
* it under the terms of the GNU General Public License as published by |
* the Free Software Foundation; version 2 of the License. |
* |
* NetSurf 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 General Public License for more details. |
* |
* You should have received a copy of the GNU General Public License |
* along with this program. If not, see <http://www.gnu.org/licenses/>. |
*/ |
#include <assert.h> |
#include <inttypes.h> |
#include <stdint.h> |
#include <stdbool.h> |
#include <string.h> |
#include "utils/schedule.h" |
#include "utils/log.h" |
#include "content/content_protected.h" |
#include "image/image_cache.h" |
#include "image/image.h" |
/** Age of an entry within the cache |
* |
* type deffed away so it can be readily changed later perhaps to a |
* wallclock time structure. |
*/ |
typedef unsigned int cache_age; |
/** Image cache entry |
*/ |
struct image_cache_entry_s { |
struct image_cache_entry_s *next; /* next cache entry in list */ |
struct image_cache_entry_s *prev; /* previous cache entry in list */ |
struct content *content; /** content is used as a key */ |
struct bitmap *bitmap; /** associated bitmap entry */ |
/** Conversion routine */ |
image_cache_convert_fn *convert; |
/* Statistics for replacement algorithm */ |
unsigned int redraw_count; /**< number of times object has been drawn */ |
cache_age redraw_age; /**< Age of last redraw */ |
size_t bitmap_size; /**< size if storage occupied by bitmap */ |
cache_age bitmap_age; /**< Age of last conversion to a bitmap by cache*/ |
int conversion_count; /**< Number of times image has been converted */ |
}; |
/** Current state of the cache. |
* |
* Global state of the cache. entries "age" is determined based on a |
* monotonically incrementing operation count. This avoids issues with |
* using wall clock time while allowing the LRU algorithm to work |
* sensibly. |
*/ |
struct image_cache_s { |
/** Cache parameters */ |
struct image_cache_parameters params; |
/** The "age" of the current operation */ |
cache_age current_age; |
/* The objects the cache holds */ |
struct image_cache_entry_s *entries; |
/* Statistics for management algorithm */ |
/** total size of bitmaps currently allocated */ |
size_t total_bitmap_size; |
/** Total count of bitmaps currently allocated */ |
int bitmap_count; |
/** Maximum size of bitmaps allocated at any one time */ |
size_t max_bitmap_size; |
/** The number of objects when maximum bitmap usage occoured */ |
int max_bitmap_size_count; |
/** Maximum count of bitmaps allocated at any one time */ |
int max_bitmap_count; |
/** The size of the bitmaps when the max count occoured */ |
size_t max_bitmap_count_size; |
/** Bitmap was not available at plot time required conversion */ |
int miss_count; |
uint64_t miss_size; |
/** Bitmap was available at plot time required no conversion */ |
int hit_count; |
uint64_t hit_size; |
/** Bitmap was not available at plot time and required |
* conversion which failed. |
*/ |
int fail_count; |
uint64_t fail_size; |
/* Cache entry freed without ever being redrawn */ |
int total_unrendered; |
/** Bitmap was available but never required - wasted conversions */ |
int specultive_miss_count; |
/** Total number of additional (after the first) conversions */ |
int total_extra_conversions; |
/** counts total number of images with more than one conversion */ |
int total_extra_conversions_count; |
/** Bitmap with most conversions was converted this many times */ |
int peak_conversions; |
/** Size of bitmap with most conversions */ |
unsigned int peak_conversions_size; |
}; |
/** image cache state */ |
static struct image_cache_s *image_cache = NULL; |
/** Find the nth cache entry |
*/ |
static struct image_cache_entry_s *image_cache__findn(int entryn) |
{ |
struct image_cache_entry_s *found; |
found = image_cache->entries; |
while ((found != NULL) && (entryn > 0)) { |
entryn--; |
found = found->next; |
} |
return found; |
} |
/** Find the cache entry for a content |
*/ |
static struct image_cache_entry_s *image_cache__find(const struct content *c) |
{ |
struct image_cache_entry_s *found; |
found = image_cache->entries; |
while ((found != NULL) && (found->content != c)) { |
found = found->next; |
} |
return found; |
} |
static void image_cache_stats_bitmap_add(struct image_cache_entry_s *centry) |
{ |
centry->bitmap_age = image_cache->current_age; |
centry->conversion_count++; |
image_cache->total_bitmap_size += centry->bitmap_size; |
image_cache->bitmap_count++; |
if (image_cache->total_bitmap_size > image_cache->max_bitmap_size) { |
image_cache->max_bitmap_size = image_cache->total_bitmap_size; |
image_cache->max_bitmap_size_count = image_cache->bitmap_count; |
} |
if (image_cache->bitmap_count > image_cache->max_bitmap_count) { |
image_cache->max_bitmap_count = image_cache->bitmap_count; |
image_cache->max_bitmap_count_size = image_cache->total_bitmap_size; |
} |
if (centry->conversion_count == 2) { |
image_cache->total_extra_conversions_count++; |
} |
if (centry->conversion_count > 1) { |
image_cache->total_extra_conversions++; |
} |
if ((centry->conversion_count > image_cache->peak_conversions) || |
(centry->conversion_count == image_cache->peak_conversions && |
centry->bitmap_size > image_cache->peak_conversions_size)) { |
image_cache->peak_conversions = centry->conversion_count; |
image_cache->peak_conversions_size = centry->bitmap_size; |
} |
} |
static void image_cache__link(struct image_cache_entry_s *centry) |
{ |
centry->next = image_cache->entries; |
centry->prev = NULL; |
if (centry->next != NULL) { |
centry->next->prev = centry; |
} |
image_cache->entries = centry; |
} |
static void image_cache__unlink(struct image_cache_entry_s *centry) |
{ |
/* unlink entry */ |
if (centry->prev == NULL) { |
/* first in list */ |
if (centry->next != NULL) { |
centry->next->prev = centry->prev; |
image_cache->entries = centry->next; |
} else { |
/* empty list */ |
image_cache->entries = NULL; |
} |
} else { |
centry->prev->next = centry->next; |
if (centry->next != NULL) { |
centry->next->prev = centry->prev; |
} |
} |
} |
static void image_cache__free_bitmap(struct image_cache_entry_s *centry) |
{ |
if (centry->bitmap != NULL) { |
#ifdef IMAGE_CACHE_VERBOSE |
LOG(("Freeing bitmap %p size %d age %d redraw count %d", |
centry->bitmap, |
centry->bitmap_size, |
image_cache->current_age - centry->bitmap_age, |
centry->redraw_count)); |
#endif |
bitmap_destroy(centry->bitmap); |
centry->bitmap = NULL; |
image_cache->total_bitmap_size -= centry->bitmap_size; |
image_cache->bitmap_count--; |
if (centry->redraw_count == 0) { |
image_cache->specultive_miss_count++; |
} |
} |
} |
/* free cache entry */ |
static void image_cache__free_entry(struct image_cache_entry_s *centry) |
{ |
#ifdef IMAGE_CACHE_VERBOSE |
LOG(("freeing %p ", centry)); |
#endif |
if (centry->redraw_count == 0) { |
image_cache->total_unrendered++; |
} |
image_cache__free_bitmap(centry); |
image_cache__unlink(centry); |
free(centry); |
} |
/** Cache cleaner */ |
static void image_cache__clean(struct image_cache_s *icache) |
{ |
struct image_cache_entry_s *centry = icache->entries; |
while (centry != NULL) { |
if ((icache->current_age - centry->redraw_age) > |
icache->params.bg_clean_time) { |
/* only consider older entries, avoids active entries */ |
if ((icache->total_bitmap_size > |
(icache->params.limit - icache->params.hysteresis)) && |
(rand() > (RAND_MAX / 2))) { |
image_cache__free_bitmap(centry); |
} |
} |
centry=centry->next; |
} |
} |
/** Cache background scheduled callback. */ |
static void image_cache__background_update(void *p) |
{ |
struct image_cache_s *icache = p; |
/* increment current cache age */ |
icache->current_age += icache->params.bg_clean_time; |
#ifdef IMAGE_CACHE_VERBOSE |
LOG(("Cache age %ds", icache->current_age / 1000)); |
#endif |
image_cache__clean(icache); |
schedule((icache->params.bg_clean_time / 10), |
image_cache__background_update, |
icache); |
} |
/* exported interface documented in image_cache.h */ |
struct bitmap *image_cache_get_bitmap(const struct content *c) |
{ |
struct image_cache_entry_s *centry; |
centry = image_cache__find(c); |
if (centry == NULL) { |
return NULL; |
} |
if (centry->bitmap == NULL) { |
if (centry->convert != NULL) { |
centry->bitmap = centry->convert(centry->content); |
} |
if (centry->bitmap != NULL) { |
image_cache_stats_bitmap_add(centry); |
image_cache->miss_count++; |
image_cache->miss_size += centry->bitmap_size; |
} else { |
image_cache->fail_count++; |
image_cache->fail_size += centry->bitmap_size; |
} |
} else { |
image_cache->hit_count++; |
image_cache->hit_size += centry->bitmap_size; |
} |
return centry->bitmap; |
} |
/* exported interface documented in image_cache.h */ |
bool image_cache_speculate(struct content *c) |
{ |
bool decision = false; |
/* If the cache is below its target usage and the bitmap is |
* small enough speculate. |
*/ |
if ((image_cache->total_bitmap_size < image_cache->params.limit) && |
(c->size <= image_cache->params.speculative_small)) { |
#ifdef IMAGE_CACHE_VERBOSE |
LOG(("content size (%d) is smaller than minimum (%d)", c->size, SPECULATE_SMALL)); |
#endif |
decision = true; |
} |
#ifdef IMAGE_CACHE_VERBOSE |
LOG(("returning %d", decision)); |
#endif |
return decision; |
} |
/* exported interface documented in image_cache.h */ |
struct bitmap *image_cache_find_bitmap(struct content *c) |
{ |
struct image_cache_entry_s *centry; |
centry = image_cache__find(c); |
if (centry == NULL) { |
return NULL; |
} |
return centry->bitmap; |
} |
/* exported interface documented in image_cache.h */ |
nserror |
image_cache_init(const struct image_cache_parameters *image_cache_parameters) |
{ |
image_cache = calloc(1, sizeof(struct image_cache_s)); |
if (image_cache == NULL) { |
return NSERROR_NOMEM; |
} |
image_cache->params = *image_cache_parameters; |
schedule((image_cache->params.bg_clean_time / 10), |
image_cache__background_update, |
image_cache); |
LOG(("Image cache initilised with a limit of %d hysteresis of %d", |
image_cache->params.limit, image_cache->params.hysteresis)); |
return NSERROR_OK; |
} |
/* exported interface documented in image_cache.h */ |
nserror image_cache_fini(void) |
{ |
unsigned int op_count; |
schedule_remove(image_cache__background_update, image_cache); |
LOG(("Size at finish %d (in %d)", |
image_cache->total_bitmap_size, |
image_cache->bitmap_count)); |
while (image_cache->entries != NULL) { |
image_cache__free_entry(image_cache->entries); |
} |
op_count = image_cache->hit_count + |
image_cache->miss_count + |
image_cache->fail_count; |
LOG(("Age %ds", image_cache->current_age / 1000)); |
LOG(("Peak size %d (in %d)", |
image_cache->max_bitmap_size, |
image_cache->max_bitmap_size_count )); |
LOG(("Peak image count %d (size %d)", |
image_cache->max_bitmap_count, |
image_cache->max_bitmap_count_size)); |
if (op_count > 0) { |
uint64_t op_size; |
op_size = image_cache->hit_size + |
image_cache->miss_size + |
image_cache->fail_size; |
LOG(("Cache total/hit/miss/fail (counts) %d/%d/%d/%d (100%%/%d%%/%d%%/%d%%)", |
op_count, |
image_cache->hit_count, |
image_cache->miss_count, |
image_cache->fail_count, |
(image_cache->hit_count * 100) / op_count, |
(image_cache->miss_count * 100) / op_count, |
(image_cache->fail_count * 100) / op_count)); |
LOG(("Cache total/hit/miss/fail (size) %d/%d/%d/%d (100%%/%d%%/%d%%/%d%%)", |
op_size, |
image_cache->hit_size, |
image_cache->miss_size, |
image_cache->fail_size, |
(image_cache->hit_size * 100) / op_size, |
(image_cache->miss_size * 100) / op_size, |
(image_cache->fail_size * 100) / op_size)); |
} |
LOG(("Total images never rendered: %d (includes %d that were converted)", |
image_cache->total_unrendered, |
image_cache->specultive_miss_count)); |
LOG(("Total number of excessive conversions: %d (from %d images converted more than once)", |
image_cache->total_extra_conversions, |
image_cache->total_extra_conversions_count)); |
LOG(("Bitmap of size %d had most (%d) conversions", |
image_cache->peak_conversions_size, |
image_cache->peak_conversions)); |
free(image_cache); |
return NSERROR_OK; |
} |
/* exported interface documented in image_cache.h */ |
nserror image_cache_add(struct content *content, |
struct bitmap *bitmap, |
image_cache_convert_fn *convert) |
{ |
struct image_cache_entry_s *centry; |
/* bump the cache age by a ms to ensure multiple items are not |
* added at exactly the same time |
*/ |
image_cache->current_age++; |
centry = image_cache__find(content); |
if (centry == NULL) { |
/* new cache entry, content not previously added */ |
centry = calloc(1, sizeof(struct image_cache_entry_s)); |
if (centry == NULL) { |
return NSERROR_NOMEM; |
} |
image_cache__link(centry); |
centry->content = content; |
centry->bitmap_size = content->width * content->height * 4; |
} |
LOG(("centry %p, content %p, bitmap %p", centry, content, bitmap)); |
centry->convert = convert; |
/* set bitmap entry if one is passed, free extant one if present */ |
if (bitmap != NULL) { |
if (centry->bitmap != NULL) { |
bitmap_destroy(centry->bitmap); |
} else { |
image_cache_stats_bitmap_add(centry); |
} |
centry->bitmap = bitmap; |
} else { |
/* no bitmap, check to see if we should speculatively convert */ |
if ((centry->convert != NULL) && |
(image_cache_speculate(content) == true)) { |
centry->bitmap = centry->convert(centry->content); |
if (centry->bitmap != NULL) { |
image_cache_stats_bitmap_add(centry); |
} else { |
image_cache->fail_count++; |
} |
} |
} |
return NSERROR_OK; |
} |
/* exported interface documented in image_cache.h */ |
nserror image_cache_remove(struct content *content) |
{ |
struct image_cache_entry_s *centry; |
/* get the cache entry */ |
centry = image_cache__find(content); |
if (centry == NULL) { |
LOG(("Could not find cache entry for content (%p)", content)); |
return NSERROR_NOT_FOUND; |
} |
image_cache__free_entry(centry); |
return NSERROR_OK; |
} |
/* exported interface documented in image_cache.h */ |
int image_cache_snsummaryf(char *string, size_t size, const char *fmt) |
{ |
size_t slen = 0; /* current output string length */ |
int fmtc = 0; /* current index into format string */ |
bool pct; |
unsigned int op_count; |
uint64_t op_size; |
op_count = image_cache->hit_count + |
image_cache->miss_count + |
image_cache->fail_count; |
op_size = image_cache->hit_size + |
image_cache->miss_size + |
image_cache->fail_size; |
while((slen < size) && (fmt[fmtc] != 0)) { |
if (fmt[fmtc] == '%') { |
fmtc++; |
/* check for percentage modifier */ |
if (fmt[fmtc] == 'p') { |
fmtc++; |
pct = true; |
} else { |
pct = false; |
} |
#define FMTCHR(chr,fmt,var) case chr : \ |
slen += snprintf(string + slen, size - slen, "%"fmt, image_cache->var); break |
#define FMTPCHR(chr,fmt,var,div) \ |
case chr : \ |
if (pct) { \ |
if (div > 0) { \ |
slen += snprintf(string + slen, size - slen, "%"PRId64, (uint64_t)((image_cache->var * 100) / div)); \ |
} else { \ |
slen += snprintf(string + slen, size - slen, "100"); \ |
} \ |
} else { \ |
slen += snprintf(string + slen, size - slen, "%"fmt, image_cache->var); \ |
} break |
switch (fmt[fmtc]) { |
case '%': |
string[slen] = '%'; |
slen++; |
break; |
FMTCHR('a', SSIZET_FMT, params.limit); |
FMTCHR('b', SSIZET_FMT, params.hysteresis); |
FMTCHR('c', SSIZET_FMT, total_bitmap_size); |
FMTCHR('d', "d", bitmap_count); |
FMTCHR('e', "d", current_age / 1000); |
FMTCHR('f', SSIZET_FMT, max_bitmap_size); |
FMTCHR('g', "d", max_bitmap_size_count); |
FMTCHR('h', "d", max_bitmap_count); |
FMTCHR('i', SSIZET_FMT, max_bitmap_count_size); |
case 'j': |
slen += snprintf(string + slen, size - slen, |
"%d", pct?100:op_count); |
break; |
FMTPCHR('k', "d", hit_count, op_count); |
FMTPCHR('l', "d", miss_count, op_count); |
FMTPCHR('m', "d", fail_count, op_count); |
case 'n': |
slen += snprintf(string + slen, size - slen, |
"%"PRId64, pct?100:op_size); |
break; |
FMTPCHR('o', PRId64, hit_size, op_size); |
FMTPCHR('q', PRId64, miss_size, op_size); |
FMTPCHR('r', PRId64, fail_size, op_size); |
FMTCHR('s', "d", total_unrendered); |
FMTCHR('t', "d", specultive_miss_count); |
FMTCHR('u', "d", total_extra_conversions); |
FMTCHR('v', "d", total_extra_conversions_count); |
FMTCHR('w', "d", peak_conversions_size); |
FMTCHR('x', "d", peak_conversions); |
} |
#undef FMTCHR |
#undef FMTPCHR |
fmtc++; |
} else { |
string[slen] = fmt[fmtc]; |
slen++; |
fmtc++; |
} |
} |
/* Ensure that we NUL-terminate the output */ |
string[min(slen, size - 1)] = '\0'; |
return slen; |
} |
/* exported interface documented in image_cache.h */ |
int image_cache_snentryf(char *string, size_t size, unsigned int entryn, |
const char *fmt) |
{ |
struct image_cache_entry_s *centry; |
size_t slen = 0; /* current output string length */ |
int fmtc = 0; /* current index into format string */ |
lwc_string *origin; /* current entry's origin */ |
centry = image_cache__findn(entryn); |
if (centry == NULL) |
return -1; |
while((slen < size) && (fmt[fmtc] != 0)) { |
if (fmt[fmtc] == '%') { |
fmtc++; |
switch (fmt[fmtc]) { |
case 'e': |
slen += snprintf(string + slen, size - slen, |
"%d", entryn); |
break; |
case 'r': |
slen += snprintf(string + slen, size - slen, |
"%u", centry->redraw_count); |
break; |
case 'a': |
slen += snprintf(string + slen, size - slen, |
"%.2f", (float)((image_cache->current_age - centry->redraw_age)) / 1000); |
break; |
case 'c': |
slen += snprintf(string + slen, size - slen, |
"%d", centry->conversion_count); |
break; |
case 'g': |
slen += snprintf(string + slen, size - slen, |
"%.2f", (float)((image_cache->current_age - centry->bitmap_age)) / 1000); |
break; |
case 'k': |
slen += snprintf(string + slen, size - slen, |
"%p", centry->content); |
break; |
case 'U': |
slen += snprintf(string + slen, size - slen, |
"%s", nsurl_access(llcache_handle_get_url(centry->content->llcache))); |
break; |
case 'o': |
if (nsurl_has_component(llcache_handle_get_url( |
centry->content->llcache), |
NSURL_HOST)) { |
origin = nsurl_get_component( |
llcache_handle_get_url( |
centry->content-> |
llcache), |
NSURL_HOST); |
slen += snprintf(string + slen, |
size - slen, "%s", |
lwc_string_data( |
origin)); |
lwc_string_unref(origin); |
} else { |
slen += snprintf(string + slen, |
size - slen, "%s", |
"localhost"); |
} |
break; |
case 's': |
if (centry->bitmap != NULL) { |
slen += snprintf(string + slen, |
size - slen, |
"%"SSIZET_FMT, |
centry->bitmap_size); |
} else { |
slen += snprintf(string + slen, |
size - slen, |
"0"); |
} |
break; |
} |
fmtc++; |
} else { |
string[slen] = fmt[fmtc]; |
slen++; |
fmtc++; |
} |
} |
/* Ensure that we NUL-terminate the output */ |
string[min(slen, size - 1)] = '\0'; |
return slen; |
} |
/* exported interface documented in image_cache.h */ |
bool image_cache_redraw(struct content *c, |
struct content_redraw_data *data, |
const struct rect *clip, |
const struct redraw_context *ctx) |
{ |
struct image_cache_entry_s *centry; |
/* get the cache entry */ |
centry = image_cache__find(c); |
if (centry == NULL) { |
LOG(("Could not find cache entry for content (%p)", c)); |
return false; |
} |
if (centry->bitmap == NULL) { |
if (centry->convert != NULL) { |
centry->bitmap = centry->convert(centry->content); |
} |
if (centry->bitmap != NULL) { |
image_cache_stats_bitmap_add(centry); |
image_cache->miss_count++; |
image_cache->miss_size += centry->bitmap_size; |
} else { |
image_cache->fail_count++; |
image_cache->fail_size += centry->bitmap_size; |
return false; |
} |
} else { |
image_cache->hit_count++; |
image_cache->hit_size += centry->bitmap_size; |
} |
/* update statistics */ |
centry->redraw_count++; |
centry->redraw_age = image_cache->current_age; |
return image_bitmap_plot(centry->bitmap, data, clip, ctx); |
} |
void image_cache_destroy(struct content *content) |
{ |
struct image_cache_entry_s *centry; |
/* get the cache entry */ |
centry = image_cache__find(content); |
if (centry == NULL) { |
LOG(("Could not find cache entry for content (%p)", content)); |
} else { |
image_cache__free_entry(centry); |
} |
} |
void *image_cache_get_internal(const struct content *c, void *context) |
{ |
return image_cache_get_bitmap(c); |
} |
content_type image_cache_content_type(void) |
{ |
return CONTENT_IMAGE; |
} |
/contrib/network/netsurf/netsurf/image/image_cache.h |
---|
0,0 → 1,188 |
/* |
* Copyright 2011 John-Mark Bell <jmb@netsurf-browser.org> |
* |
* This file is part of NetSurf, http://www.netsurf-browser.org/ |
* |
* NetSurf is free software; you can redistribute it and/or modify |
* it under the terms of the GNU General Public License as published by |
* the Free Software Foundation; version 2 of the License. |
* |
* NetSurf 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 General Public License for more details. |
* |
* You should have received a copy of the GNU General Public License |
* along with this program. If not, see <http://www.gnu.org/licenses/>. |
*/ |
/** \file |
* The image content handler intermediate image cache. |
* |
* This cache allows netsurf to use a generic intermediate bitmap |
* format without keeping the |
* intermediate representation in memory. |
* |
* The bitmap structure is opaque to the rest of netsurf and is |
* controlled by the platform-specific code (see image/bitmap.h for |
* detials). All image content handlers convert into this format and |
* pass it to the plot functions for display, |
* |
* This cache maintains a link between the underlying original content |
* and the intermediate representation. It is intended to be flexable |
* and either manage the bitmap plotting completely or give the image |
* content handler complete control. |
*/ |
#ifndef NETSURF_IMAGE_IMAGE_CACHE_H_ |
#define NETSURF_IMAGE_IMAGE_CACHE_H_ |
#include "utils/errors.h" |
#include "desktop/plotters.h" |
#include "image/bitmap.h" |
typedef struct bitmap * (image_cache_convert_fn) (struct content *content); |
struct image_cache_parameters { |
/** How frequently the background cache clean process is run (ms) */ |
unsigned int bg_clean_time; |
/** The target upper bound for the image cache size */ |
size_t limit; |
/** The hysteresis allowed round the target size */ |
size_t hysteresis; |
/** The speculative conversion "small" size */ |
size_t speculative_small; |
}; |
/** Initialise the image cache |
* |
* @param image_cache_parameters The control parameters for the image cache |
*/ |
nserror image_cache_init(const struct image_cache_parameters *image_cache_parameters); |
nserror image_cache_fini(void); |
/** adds an image content to be cached. |
* |
* @param content The content handle used as a key |
* @param bitmap A bitmap representing the already converted content or NULL. |
* @param convert A function pointer to convert the content into a bitmap or NULL. |
* @return A netsurf error code. |
*/ |
nserror image_cache_add(struct content *content, |
struct bitmap *bitmap, |
image_cache_convert_fn *convert); |
nserror image_cache_remove(struct content *content); |
/** Obtain a bitmap from a content converting from source if neccessary. */ |
struct bitmap *image_cache_get_bitmap(const struct content *c); |
/** Obtain a bitmap from a content with no conversion */ |
struct bitmap *image_cache_find_bitmap(struct content *c); |
/** Decide if a content should be speculatively converted. |
* |
* This allows for image content handlers to ask the cache if a bitmap |
* should be generated before it is added to the cache. This is the |
* same decision logic used to decide to perform an immediate |
* conversion when a content is initially added to the cache. |
* |
* @param c The content to be considered. |
* @return true if a speculative conversion is desired false otehrwise. |
*/ |
bool image_cache_speculate(struct content *c); |
/** |
* Fill a buffer with information about a cache entry using a format. |
* |
* The format string is copied into the output buffer with the |
* following replaced: |
* %e - The entry number |
* %k - The content key |
* %r - The number of redraws of this bitmap |
* %c - The number of times this bitmap has been converted |
* %s - The size of the current bitmap allocation |
* |
* \param string The buffer in which to place the results. |
* \param size The size of the string buffer. |
* \param entryn The opaque entry number. |
* \param fmt The format string. |
* \return The number of bytes written to \a string or -1 on error |
*/ |
int image_cache_snentryf(char *string, size_t size, unsigned int entryn, |
const char *fmt); |
/** |
* Fill a buffer with information about the image cache using a format. |
* |
* The format string is copied into the output buffer with the |
* following replaced: |
* |
* a Configured cache limit size |
* b Configured cache hysteresis size |
* c Current caches total consumed size |
* d Number of images currently in the cache |
* e The age of the cache |
* f The largest amount of space the cache has occupied since initialisation |
* g The number of objetcs when the cache was at its largest |
* h The largest number of images in the cache since initialisation |
* i The size of the cache when the largest number of objects occoured |
* j The total number of read operations performed on the cache |
* k The total number of read operations satisfied from the cache without |
* conversion. |
* l The total number of read operations satisfied from the cache which |
* required a conversion. |
* m The total number of read operations which could not be sucessfully |
* returned. ie. not available in cache and conversion failed. |
* n The total size of read operations performed on the cache |
* o The total size of read operations satisfied from the cache without |
* conversion. |
* q The total size of read operations satisfied from the cache which |
* required a conversion. |
* r The total size of read operations which could not be sucessfully |
* returned. ie. not available in cache and conversion failed. |
* s The number of images which were placed in the cache but never read. |
* t The number of images that were converted on insertion into teh cache which were subsequently never used. |
* u The number of times an image was converted after the first |
* v The number of images that had extra conversions performed. |
* w Size of the image that was converted (read missed cache) highest number |
* of times. |
* x The number of times the image that was converted (read missed cache) |
* highest number of times. |
* |
* format modifiers: |
* A p before the value modifies the replacement to be a percentage. |
* |
* |
* \param string The buffer in which to place the results. |
* \param size The size of the string buffer. |
* \param fmt The format string. |
* \return The number of bytes written to \a string or -1 on error |
*/ |
int image_cache_snsummaryf(char *string, size_t size, const char *fmt); |
/********* Image content handler generic cache callbacks ************/ |
/** Generic content redraw callback |
* |
* May be used by image content handlers as their redraw |
* callback. Performs all neccissary cache lookups and conversions and |
* calls the bitmap plot function in the redraw context. |
*/ |
bool image_cache_redraw(struct content *c, |
struct content_redraw_data *data, |
const struct rect *clip, |
const struct redraw_context *ctx); |
void image_cache_destroy(struct content *c); |
void *image_cache_get_internal(const struct content *c, void *context); |
content_type image_cache_content_type(void); |
#endif |
/contrib/network/netsurf/netsurf/image/jpeg.c |
---|
0,0 → 1,395 |
/* |
* Copyright 2004 James Bursa <bursa@users.sourceforge.net> |
* Copyright 2004 John M Bell <jmb202@ecs.soton.ac.uk> |
* |
* This file is part of NetSurf, http://www.netsurf-browser.org/ |
* |
* NetSurf is free software; you can redistribute it and/or modify |
* it under the terms of the GNU General Public License as published by |
* the Free Software Foundation; version 2 of the License. |
* |
* NetSurf 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 General Public License for more details. |
* |
* You should have received a copy of the GNU General Public License |
* along with this program. If not, see <http://www.gnu.org/licenses/>. |
*/ |
/** \file |
* Content for image/jpeg (implementation). |
* |
* This implementation uses the IJG JPEG library. |
*/ |
#include <assert.h> |
#include <setjmp.h> |
#include <string.h> |
#include <stdio.h> |
#include <stdlib.h> |
#include "content/content_protected.h" |
#include "desktop/plotters.h" |
#include "image/image_cache.h" |
#include "utils/log.h" |
#include "utils/messages.h" |
#include "utils/types.h" |
#include "utils/utils.h" |
#define JPEG_INTERNAL_OPTIONS |
#include "jpeglib.h" |
#include "image/jpeg.h" |
/** absolute minimum size of a jpeg below which it is not even worth |
* trying to read header data |
*/ |
#define MIN_JPEG_SIZE 20 |
#ifdef riscos |
/* We prefer the library to be configured with these options to save |
* copying data during decoding. */ |
#if RGB_RED != 0 || RGB_GREEN != 1 || RGB_BLUE != 2 || RGB_PIXELSIZE != 4 |
#warning JPEG library not optimally configured. Decoding will be slower. |
#endif |
/* but we don't care if we're not on RISC OS */ |
#endif |
static char nsjpeg_error_buffer[JMSG_LENGTH_MAX]; |
static unsigned char nsjpeg_eoi[] = { 0xff, JPEG_EOI }; |
/** |
* Content create entry point. |
*/ |
static nserror nsjpeg_create(const content_handler *handler, |
lwc_string *imime_type, const http_parameter *params, |
llcache_handle *llcache, const char *fallback_charset, |
bool quirks, struct content **c) |
{ |
struct content *jpeg; |
nserror error; |
jpeg = calloc(1, sizeof(struct content)); |
if (jpeg == NULL) |
return NSERROR_NOMEM; |
error = content__init(jpeg, handler, imime_type, params, |
llcache, fallback_charset, quirks); |
if (error != NSERROR_OK) { |
free(jpeg); |
return error; |
} |
*c = jpeg; |
return NSERROR_OK; |
} |
/** |
* JPEG data source manager: initialize source. |
*/ |
static void nsjpeg_init_source(j_decompress_ptr cinfo) |
{ |
} |
/** |
* JPEG data source manager: fill the input buffer. |
* |
* This can only occur if the JPEG data was truncated or corrupted. Insert a |
* fake EOI marker to allow the decompressor to output as much as possible. |
*/ |
static boolean nsjpeg_fill_input_buffer(j_decompress_ptr cinfo) |
{ |
cinfo->src->next_input_byte = nsjpeg_eoi; |
cinfo->src->bytes_in_buffer = 2; |
return TRUE; |
} |
/** |
* JPEG data source manager: skip num_bytes worth of data. |
*/ |
static void nsjpeg_skip_input_data(j_decompress_ptr cinfo, long num_bytes) |
{ |
if ((long) cinfo->src->bytes_in_buffer < num_bytes) { |
cinfo->src->next_input_byte = 0; |
cinfo->src->bytes_in_buffer = 0; |
} else { |
cinfo->src->next_input_byte += num_bytes; |
cinfo->src->bytes_in_buffer -= num_bytes; |
} |
} |
/** |
* JPEG data source manager: terminate source. |
*/ |
static void nsjpeg_term_source(j_decompress_ptr cinfo) |
{ |
} |
/** |
* Error output handler for JPEG library. |
* |
* This logs to NetSurf log instead of stderr. |
* Warnings only - fatal errors are trapped by nsjpeg_error_exit |
* and do not call the output handler. |
*/ |
static void nsjpeg_error_log(j_common_ptr cinfo) |
{ |
cinfo->err->format_message(cinfo, nsjpeg_error_buffer); |
LOG(("%s", nsjpeg_error_buffer)); |
} |
/** |
* Fatal error handler for JPEG library. |
* |
* This prevents jpeglib calling exit() on a fatal error. |
*/ |
static void nsjpeg_error_exit(j_common_ptr cinfo) |
{ |
jmp_buf *setjmp_buffer = (jmp_buf *) cinfo->client_data; |
cinfo->err->format_message(cinfo, nsjpeg_error_buffer); |
LOG(("%s", nsjpeg_error_buffer)); |
longjmp(*setjmp_buffer, 1); |
} |
static struct bitmap * |
jpeg_cache_convert(struct content *c) |
{ |
uint8_t *source_data; /* Jpeg source data */ |
unsigned long source_size; /* length of Jpeg source data */ |
struct jpeg_decompress_struct cinfo; |
struct jpeg_error_mgr jerr; |
jmp_buf setjmp_buffer; |
unsigned int height; |
unsigned int width; |
struct bitmap * volatile bitmap = NULL; |
uint8_t * volatile pixels = NULL; |
size_t rowstride; |
struct jpeg_source_mgr source_mgr = { |
0, |
0, |
nsjpeg_init_source, |
nsjpeg_fill_input_buffer, |
nsjpeg_skip_input_data, |
jpeg_resync_to_restart, |
nsjpeg_term_source }; |
/* obtain jpeg source data and perfom minimal sanity checks */ |
source_data = (uint8_t *)content__get_source_data(c, &source_size); |
if ((source_data == NULL) || |
(source_size < MIN_JPEG_SIZE)) { |
return NULL; |
} |
/* setup a JPEG library error handler */ |
cinfo.err = jpeg_std_error(&jerr); |
jerr.error_exit = nsjpeg_error_exit; |
jerr.output_message = nsjpeg_error_log; |
/* handler for fatal errors during decompression */ |
if (setjmp(setjmp_buffer)) { |
jpeg_destroy_decompress(&cinfo); |
return bitmap; |
} |
jpeg_create_decompress(&cinfo); |
cinfo.client_data = &setjmp_buffer; |
/* setup data source */ |
source_mgr.next_input_byte = source_data; |
source_mgr.bytes_in_buffer = source_size; |
cinfo.src = &source_mgr; |
/* read JPEG header information */ |
jpeg_read_header(&cinfo, TRUE); |
/* set output processing parameters */ |
cinfo.out_color_space = JCS_RGB; |
cinfo.dct_method = JDCT_ISLOW; |
/* commence the decompression, output parameters now valid */ |
jpeg_start_decompress(&cinfo); |
width = cinfo.output_width; |
height = cinfo.output_height; |
/* create opaque bitmap (jpegs cannot be transparent) */ |
bitmap = bitmap_create(width, height, BITMAP_NEW | BITMAP_OPAQUE); |
if (bitmap == NULL) { |
/* empty bitmap could not be created */ |
jpeg_destroy_decompress(&cinfo); |
return NULL; |
} |
pixels = bitmap_get_buffer(bitmap); |
if (pixels == NULL) { |
/* bitmap with no buffer available */ |
bitmap_destroy(bitmap); |
jpeg_destroy_decompress(&cinfo); |
return NULL; |
} |
/* Convert scanlines from jpeg into bitmap */ |
rowstride = bitmap_get_rowstride(bitmap); |
do { |
JSAMPROW scanlines[1]; |
scanlines[0] = (JSAMPROW) (pixels + |
rowstride * cinfo.output_scanline); |
jpeg_read_scanlines(&cinfo, scanlines, 1); |
#if RGB_RED != 0 || RGB_GREEN != 1 || RGB_BLUE != 2 || RGB_PIXELSIZE != 4 |
{ |
/* Missmatch between configured libjpeg pixel format and |
* NetSurf pixel format. Convert to RGBA */ |
int i; |
for (i = width - 1; 0 <= i; i--) { |
int r = scanlines[0][i * RGB_PIXELSIZE + RGB_RED]; |
int g = scanlines[0][i * RGB_PIXELSIZE + RGB_GREEN]; |
int b = scanlines[0][i * RGB_PIXELSIZE + RGB_BLUE]; |
scanlines[0][i * 4 + 0] = r; |
scanlines[0][i * 4 + 1] = g; |
scanlines[0][i * 4 + 2] = b; |
scanlines[0][i * 4 + 3] = 0xff; |
} |
} |
#endif |
} while (cinfo.output_scanline != cinfo.output_height); |
bitmap_modified(bitmap); |
jpeg_finish_decompress(&cinfo); |
jpeg_destroy_decompress(&cinfo); |
return bitmap; |
} |
/** |
* Convert a CONTENT_JPEG for display. |
*/ |
static bool nsjpeg_convert(struct content *c) |
{ |
struct jpeg_decompress_struct cinfo; |
struct jpeg_error_mgr jerr; |
jmp_buf setjmp_buffer; |
struct jpeg_source_mgr source_mgr = { 0, 0, |
nsjpeg_init_source, nsjpeg_fill_input_buffer, |
nsjpeg_skip_input_data, jpeg_resync_to_restart, |
nsjpeg_term_source }; |
union content_msg_data msg_data; |
const char *data; |
unsigned long size; |
char *title; |
/* check image header is valid and get width/height */ |
data = content__get_source_data(c, &size); |
cinfo.err = jpeg_std_error(&jerr); |
jerr.error_exit = nsjpeg_error_exit; |
jerr.output_message = nsjpeg_error_log; |
if (setjmp(setjmp_buffer)) { |
jpeg_destroy_decompress(&cinfo); |
msg_data.error = nsjpeg_error_buffer; |
content_broadcast(c, CONTENT_MSG_ERROR, msg_data); |
return false; |
} |
jpeg_create_decompress(&cinfo); |
cinfo.client_data = &setjmp_buffer; |
source_mgr.next_input_byte = (unsigned char *) data; |
source_mgr.bytes_in_buffer = size; |
cinfo.src = &source_mgr; |
jpeg_read_header(&cinfo, TRUE); |
cinfo.out_color_space = JCS_RGB; |
cinfo.dct_method = JDCT_ISLOW; |
jpeg_calc_output_dimensions(&cinfo); |
c->width = cinfo.output_width; |
c->height = cinfo.output_height; |
c->size = c->width * c->height * 4; |
jpeg_destroy_decompress(&cinfo); |
image_cache_add(c, NULL, jpeg_cache_convert); |
/* set title text */ |
title = messages_get_buff("JPEGTitle", |
nsurl_access_leaf(llcache_handle_get_url(c->llcache)), |
c->width, c->height); |
if (title != NULL) { |
content__set_title(c, title); |
free(title); |
} |
content_set_ready(c); |
content_set_done(c); |
content_set_status(c, ""); /* Done: update status bar */ |
return true; |
} |
/** |
* Clone content. |
*/ |
static nserror nsjpeg_clone(const struct content *old, struct content **newc) |
{ |
struct content *jpeg_c; |
nserror error; |
jpeg_c = calloc(1, sizeof(struct content)); |
if (jpeg_c == NULL) |
return NSERROR_NOMEM; |
error = content__clone(old, jpeg_c); |
if (error != NSERROR_OK) { |
content_destroy(jpeg_c); |
return error; |
} |
/* re-convert if the content is ready */ |
if ((old->status == CONTENT_STATUS_READY) || |
(old->status == CONTENT_STATUS_DONE)) { |
if (nsjpeg_convert(jpeg_c) == false) { |
content_destroy(jpeg_c); |
return NSERROR_CLONE_FAILED; |
} |
} |
*newc = jpeg_c; |
return NSERROR_OK; |
} |
static const content_handler nsjpeg_content_handler = { |
.create = nsjpeg_create, |
.data_complete = nsjpeg_convert, |
.destroy = image_cache_destroy, |
.redraw = image_cache_redraw, |
.clone = nsjpeg_clone, |
.get_internal = image_cache_get_internal, |
.type = image_cache_content_type, |
.no_share = false, |
}; |
static const char *nsjpeg_types[] = { |
"image/jpeg", |
"image/jpg", |
"image/pjpeg" |
}; |
CONTENT_FACTORY_REGISTER_TYPES(nsjpeg, nsjpeg_types, nsjpeg_content_handler); |
/contrib/network/netsurf/netsurf/image/jpeg.h |
---|
0,0 → 1,28 |
/* |
* Copyright 2004 James Bursa <bursa@users.sourceforge.net> |
* |
* This file is part of NetSurf, http://www.netsurf-browser.org/ |
* |
* NetSurf is free software; you can redistribute it and/or modify |
* it under the terms of the GNU General Public License as published by |
* the Free Software Foundation; version 2 of the License. |
* |
* NetSurf 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 General Public License for more details. |
* |
* You should have received a copy of the GNU General Public License |
* along with this program. If not, see <http://www.gnu.org/licenses/>. |
*/ |
/** \file |
* Content for image/jpeg (interface). |
*/ |
#ifndef _NETSURF_IMAGE_JPEG_H_ |
#define _NETSURF_IMAGE_JPEG_H_ |
nserror nsjpeg_init(void); |
#endif |
/contrib/network/netsurf/netsurf/image/make.image |
---|
0,0 → 1,21 |
CFLAGS += -O2 -DWITH_PNG -DWITH_BMP -DWITH_JPEG -DWITH_GIF |
NETSURF_FB_FRONTEND := sdl |
NETSURF_FB_FONTLIB := internal |
NETSURF_FRAMEBUFFER_BIN := $(PREFIX)/bin/ |
# Default resource install path |
NETSURF_FRAMEBUFFER_RESOURCES := $(PREFIX)/share/netsurf/ |
# Default framebuffer search path |
NETSURF_FB_RESPATH := $${HOME}/.netsurf/:$${NETSURFRES}:$(NETSURF_FRAMEBUFFER_RESOURCES):./framebuffer/res |
# freetype compiled in font serch path |
NETSURF_FB_FONTPATH := /usr/share/fonts/truetype/ttf-dejavu:/usr/share/fonts/truetype/msttcorefonts |
OBJS := image.o image_cache.o bmp.o ico.o gif.o jpeg.o png.o |
OUTFILE = TEST.o |
CFLAGS += -I ../include/ -I ../ -I../../ -I./ -I/home/sourcerer/kos_src/newenginek/kolibri/include |
include $(MENUETDEV)/makefiles/Makefile_for_o_lib |
/contrib/network/netsurf/netsurf/image/mng.c |
---|
0,0 → 1,832 |
/* |
* Copyright 2005 Richard Wilson <info@tinct.net> |
* |
* This file is part of NetSurf, http://www.netsurf-browser.org/ |
* |
* NetSurf is free software; you can redistribute it and/or modify |
* it under the terms of the GNU General Public License as published by |
* the Free Software Foundation; version 2 of the License. |
* |
* NetSurf 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 General Public License for more details. |
* |
* You should have received a copy of the GNU General Public License |
* along with this program. If not, see <http://www.gnu.org/licenses/>. |
*/ |
/** \file |
* Content for image/mng, image/png, and image/jng (implementation). |
*/ |
#include <assert.h> |
#include <stdbool.h> |
#include <string.h> |
#include <stdlib.h> |
#include <sys/time.h> |
#include <time.h> |
#include <libmng.h> |
#include "content/content_protected.h" |
#include "desktop/options.h" |
#include "desktop/plotters.h" |
#include "image/bitmap.h" |
#include "image/mng.h" |
#include "utils/log.h" |
#include "utils/messages.h" |
#include "utils/schedule.h" |
#include "utils/utils.h" |
/* This implementation does not currently support dynamic MNGs or any |
* form of colour/gamma correction, |
*/ |
typedef struct nsmng_content |
{ |
struct content base; |
bool opaque_test_pending; |
bool read_start; |
bool read_resume; |
int read_size; |
bool waiting; |
bool displayed; |
void *handle; |
struct bitmap *bitmap; /**< Created NetSurf bitmap */ |
} nsmng_content; |
#ifndef MNG_INTERNAL_MEMMNGMT |
/** |
* Memory allocation callback for libmng. |
*/ |
static mng_ptr nsmng_alloc(mng_size_t n) |
{ |
return calloc(1, n); |
} |
/** |
* Memory free callback for libmng. |
*/ |
static void nsmng_free(mng_ptr p, mng_size_t n) |
{ |
free(p); |
} |
#endif |
/** |
* Broadcasts an error message and returns false |
* |
* \param c the content to broadcast for |
* \return Appropriate error |
*/ |
static nserror nsmng_broadcast_error(nsmng_content *c, mng_retcode code) |
{ |
union content_msg_data msg_data; |
char error[100]; |
assert(c != NULL); |
if (code == MNG_OUTOFMEMORY) { |
msg_data.error = messages_get("NoMemory"); |
content_broadcast(&c->base, CONTENT_MSG_ERROR, msg_data); |
return NSERROR_NOMEM; |
} |
snprintf(error, sizeof error, messages_get("MNGError"), code); |
msg_data.error = error; |
content_broadcast(&c->base, CONTENT_MSG_ERROR, msg_data); |
return NSERROR_MNG_ERROR; |
} |
/* CALLBACKS REQUIRED FOR libmng READING */ |
static mng_bool nsmng_openstream(mng_handle mng) |
{ |
assert(mng != NULL); |
return MNG_TRUE; |
} |
static mng_bool nsmng_readdata(mng_handle mng, mng_ptr buffer, mng_uint32 size, |
mng_uint32 *bytesread) |
{ |
nsmng_content *c; |
const char *data; |
unsigned long data_size; |
assert(mng != NULL); |
assert(buffer != NULL); |
assert(bytesread != NULL); |
/* Get our content back |
*/ |
c = (nsmng_content *) mng_get_userdata(mng); |
assert(c != NULL); |
/* Copy any data we have (maximum of 'size') |
*/ |
data = content__get_source_data(&c->base, &data_size); |
*bytesread = ((data_size - c->read_size) < size) ? |
(data_size - c->read_size) : size; |
if ((*bytesread) > 0) { |
memcpy(buffer, data + c->read_size, *bytesread); |
c->read_size += *bytesread; |
} |
/* Return success |
*/ |
return MNG_TRUE; |
} |
static mng_bool nsmng_closestream(mng_handle mng) |
{ |
assert(mng != NULL); |
return MNG_TRUE; |
} |
static mng_bool nsmng_processheader(mng_handle mng, mng_uint32 width, |
mng_uint32 height) |
{ |
nsmng_content *c; |
union content_msg_data msg_data; |
uint8_t *buffer; |
assert(mng != NULL); |
/* This function is called when the header has been read and we |
know the dimensions of the canvas. |
*/ |
c = (nsmng_content *) mng_get_userdata(mng); |
assert(c != NULL); |
c->bitmap = bitmap_create(width, height, BITMAP_NEW); |
if (c->bitmap == NULL) { |
msg_data.error = messages_get("NoMemory"); |
content_broadcast(&c->base, CONTENT_MSG_ERROR, msg_data); |
LOG(("Insufficient memory to create canvas.")); |
return MNG_FALSE; |
} |
/* Get the buffer to ensure that it is allocated and the calls in |
* nsmng_getcanvasline() succeed. */ |
buffer = bitmap_get_buffer(c->bitmap); |
if (buffer == NULL) { |
msg_data.error = messages_get("NoMemory"); |
content_broadcast(&c->base, CONTENT_MSG_ERROR, msg_data); |
LOG(("Insufficient memory to create canvas.")); |
return MNG_FALSE; |
} |
/* Initialise the content size |
*/ |
c->base.width = width; |
c->base.height = height; |
/* Set the canvas style |
*/ |
if (mng_set_canvasstyle(mng, MNG_CANVAS_RGBA8) != MNG_NOERROR) { |
LOG(("Error setting canvas style.")); |
} |
/* Return success |
*/ |
return MNG_TRUE; |
} |
/* END OF CALLBACKS REQUIRED FOR READING |
*/ |
static bool nsmng_process_data(struct content *c, const char *data, unsigned int size) |
{ |
nsmng_content *mng = (nsmng_content *) c; |
mng_retcode status; |
assert(c != NULL); |
assert(data != NULL); |
/* We only need to do any processing if we're starting/resuming reading. |
*/ |
if ((!mng->read_resume) && (!mng->read_start)) |
return true; |
/* Try to start processing, or process some more data |
*/ |
if (mng->read_start) { |
status = mng_read(mng->handle); |
mng->read_start = false; |
} else { |
status = mng_read_resume(mng->handle); |
} |
mng->read_resume = (status == MNG_NEEDMOREDATA); |
if ((status != MNG_NOERROR) && (status != MNG_NEEDMOREDATA)) { |
LOG(("Failed to start/continue reading (%i).", status)); |
return nsmng_broadcast_error(mng, status) == NSERROR_OK; |
} |
/* Continue onwards |
*/ |
return true; |
} |
/* START OF CALLBACKS REQUIRED FOR DISPLAYING |
*/ |
static mng_ptr nsmng_getcanvasline(mng_handle mng, mng_uint32 line) |
{ |
nsmng_content *c; |
assert(mng != NULL); |
/* Get our content back |
*/ |
c = (nsmng_content *) mng_get_userdata(mng); |
assert(c != NULL); |
/* Calculate the address |
*/ |
return bitmap_get_buffer(c->bitmap) + |
bitmap_get_rowstride(c->bitmap) * line; |
} |
static mng_bool nsmng_refresh(mng_handle mng, mng_uint32 x, mng_uint32 y, |
mng_uint32 w, mng_uint32 h) |
{ |
union content_msg_data data; |
nsmng_content *c; |
assert(mng != NULL); |
/* Get our content back |
*/ |
c = (nsmng_content *) mng_get_userdata(mng); |
assert(c != NULL); |
/* Set the minimum redraw area |
*/ |
data.redraw.x = x; |
data.redraw.y = y; |
data.redraw.width = w; |
data.redraw.height = h; |
/* Set the redraw area to the whole canvas to ensure that if |
we can redraw something to trigger animation later then we do |
*/ |
/* data.redraw.x = 0; |
data.redraw.y = 0; |
data.redraw.width = c->width; |
data.redraw.height = c->height; |
*/ |
/* Always redraw everything |
*/ |
data.redraw.full_redraw = true; |
/* Set the object characteristics |
*/ |
data.redraw.object = &c->base; |
data.redraw.object_x = 0; |
data.redraw.object_y = 0; |
data.redraw.object_width = c->base.width; |
data.redraw.object_height = c->base.height; |
/* Only attempt to force the redraw if we've been requested to |
* display the image in the first place (i.e. nsmng_redraw has |
* been called). This avoids the situation of forcibly redrawing |
* an image that shouldn't be shown (e.g. if the image is a fallback |
* for an object that can't be rendered) |
*/ |
if (c->displayed) |
content_broadcast(&c->base, CONTENT_MSG_REDRAW, data); |
return MNG_TRUE; |
} |
/** |
* Animates to the next frame |
*/ |
static void nsmng_animate(void *p) |
{ |
nsmng_content *c; |
assert(p != NULL); |
c = (nsmng_content *) p; |
/* If we used the last animation we advance, if not we try again later |
*/ |
if (c->base.user_list->next == NULL) { |
c->waiting = true; |
} else { |
c->waiting = false; |
mng_display_resume(c->handle); |
c->opaque_test_pending = true; |
if (c->bitmap) |
bitmap_modified(c->bitmap); |
} |
} |
static mng_bool nsmng_settimer(mng_handle mng, mng_uint32 msecs) |
{ |
nsmng_content *c; |
assert(mng != NULL); |
/* Get our content back |
*/ |
c = (nsmng_content *) mng_get_userdata(mng); |
assert(c != NULL); |
/* Perform the scheduling |
*/ |
schedule(msecs / 10, nsmng_animate, c); |
return MNG_TRUE; |
} |
/** |
* Get the wall-clock time in milliseconds since some fixed time. |
*/ |
static mng_uint32 nsmng_gettickcount(mng_handle mng) |
{ |
static bool start = true; |
static time_t t0; |
struct timeval tv; |
#if defined(__SVR4) && defined(__sun) || defined(__NetBSD__) || \ |
defined(__APPLE__) |
/* Solaris, NetBSD, and OS X don't have this structure, and ignore the |
* second parameter to gettimeofday() |
*/ |
int tz; |
#else |
struct timezone tz; |
#endif |
assert(mng != NULL); |
gettimeofday(&tv, &tz); |
if (start) { |
t0 = tv.tv_sec; |
start = false; |
} |
return (tv.tv_sec - t0) * 1000 + tv.tv_usec / 1000; |
} |
/* END OF CALLBACKS REQUIRED FOR DISPLAYING |
*/ |
static mng_bool nsmng_errorproc(mng_handle mng, mng_int32 code, |
mng_int8 severity, mng_chunkid chunktype, mng_uint32 chunkseq, |
mng_int32 extra1, mng_int32 extra2, mng_pchar text) |
{ |
nsmng_content *c; |
char chunk[5]; |
assert(mng != NULL); |
c = (nsmng_content *) mng_get_userdata(mng); |
assert(c != NULL); |
chunk[0] = (char)((chunktype >> 24) & 0xFF); |
chunk[1] = (char)((chunktype >> 16) & 0xFF); |
chunk[2] = (char)((chunktype >> 8) & 0xFF); |
chunk[3] = (char)((chunktype ) & 0xFF); |
chunk[4] = '\0'; |
LOG(("error playing '%s' chunk %s (%d):", |
content_get_url(&c->base), chunk, chunkseq)); |
LOG(("code %d severity %d extra1 %d extra2 %d text:'%s'", code, |
severity, extra1, extra2, text)); |
return (0); |
} |
static nserror nsmng_create_mng_data(nsmng_content *c) |
{ |
mng_retcode code; |
union content_msg_data msg_data; |
assert(c != NULL); |
/* Initialise the library |
*/ |
#ifdef MNG_INTERNAL_MEMMNGMT |
c->handle = mng_initialize(c, MNG_NULL, MNG_NULL, MNG_NULL); |
#else |
c->handle = mng_initialize(c, nsmng_alloc, nsmng_free, MNG_NULL); |
#endif |
if (c->handle == MNG_NULL) { |
LOG(("Unable to initialise MNG library.")); |
msg_data.error = messages_get("NoMemory"); |
content_broadcast(&c->base, CONTENT_MSG_ERROR, msg_data); |
return NSERROR_NOMEM; |
} |
/* We need to decode in suspension mode |
*/ |
code = mng_set_suspensionmode(c->handle, MNG_TRUE); |
if (code) { |
LOG(("Unable to set suspension mode.")); |
return nsmng_broadcast_error(c, code); |
} |
/* We need to register our callbacks |
*/ |
code = mng_setcb_openstream(c->handle, nsmng_openstream); |
if (code) { |
LOG(("Unable to set openstream callback.")); |
return nsmng_broadcast_error(c, code); |
} |
code = mng_setcb_readdata(c->handle, nsmng_readdata); |
if (code) { |
LOG(("Unable to set readdata callback.")); |
return nsmng_broadcast_error(c, code); |
} |
code = mng_setcb_closestream(c->handle, nsmng_closestream); |
if (code) { |
LOG(("Unable to set closestream callback.")); |
return nsmng_broadcast_error(c, code); |
} |
code = mng_setcb_processheader(c->handle, nsmng_processheader); |
if (code) { |
LOG(("Unable to set processheader callback.")); |
return nsmng_broadcast_error(c, code); |
} |
/* Register our callbacks for displaying |
*/ |
code = mng_setcb_getcanvasline(c->handle, nsmng_getcanvasline); |
if (code) { |
LOG(("Unable to set getcanvasline callback.")); |
return nsmng_broadcast_error(c, code); |
} |
code = mng_setcb_refresh(c->handle, nsmng_refresh); |
if (code) { |
LOG(("Unable to set refresh callback.")); |
return nsmng_broadcast_error(c, code); |
} |
code = mng_setcb_gettickcount(c->handle, nsmng_gettickcount); |
if (code) { |
LOG(("Unable to set gettickcount callback.")); |
return nsmng_broadcast_error(c, code); |
} |
code = mng_setcb_settimer(c->handle, nsmng_settimer); |
if (code) { |
LOG(("Unable to set settimer callback.")); |
return nsmng_broadcast_error(c, code); |
} |
/* register error handling function */ |
code = mng_setcb_errorproc(c->handle, nsmng_errorproc); |
if (code) { |
LOG(("Unable to set errorproc")); |
return nsmng_broadcast_error(c, code); |
} |
/* Initialise the reading |
*/ |
c->read_start = true; |
c->read_resume = false; |
c->read_size = 0; |
c->waiting = false; |
c->displayed = false; |
return NSERROR_OK; |
} |
static nserror nsmng_create(const content_handler *handler, |
lwc_string *imime_type, const struct http_parameter *params, |
llcache_handle *llcache, const char *fallback_charset, |
bool quirks, struct content **c) |
{ |
nsmng_content *mng; |
nserror error; |
mng = calloc(1, sizeof(nsmng_content)); |
if (mng == NULL) |
return NSERROR_NOMEM; |
error = content__init(&mng->base, handler, imime_type, params, |
llcache, fallback_charset, quirks); |
if (error != NSERROR_OK) { |
free(mng); |
return error; |
} |
error = nsmng_create_mng_data(mng); |
if (error != NSERROR_OK) { |
free(mng); |
return error; |
} |
*c = (struct content *) mng; |
return NSERROR_OK; |
} |
static bool nsmng_convert(struct content *c) |
{ |
nsmng_content *mng = (nsmng_content *) c; |
mng_retcode status; |
unsigned long size; |
char *title; |
assert(c != NULL); |
content__get_source_data(c, &size); |
/* by this point, the png should have been parsed |
* and the bitmap created, so ensure that's the case |
*/ |
if (mng->bitmap == NULL) { |
return nsmng_broadcast_error(mng, -1) == NSERROR_OK; |
} |
/* set title text */ |
title = messages_get_buff("MNGTitle", |
nsurl_access_leaf(llcache_handle_get_url(c->llcache)), |
c->width, c->height); |
if (title != NULL) { |
content__set_title(c, title); |
free(title); |
} |
c->size += c->width * c->height * 4; |
content_set_ready(c); |
content_set_done(c); |
/* Done: update status bar */ |
content_set_status(c, ""); |
/* jmb: I'm really not sure that this should be here. |
* The *_convert functions are for converting a content into a |
* displayable format. They should not, however, do anything which |
* could cause the content to be displayed; the content may have |
* hidden visibility or be a fallback for an object; this |
* information is not available here (nor is there any need for it |
* to be). |
* The specific issue here is that mng_display calls the display |
* callbacks, which include nsmng_refresh. nsmng_refresh forces |
* a content to be redrawn regardless of whether it should be |
* displayed or not. |
*/ |
/* Start displaying |
*/ |
status = mng_display(mng->handle); |
if ((status != MNG_NOERROR) && (status != MNG_NEEDTIMERWAIT)) { |
LOG(("Unable to start display (%i)", status)); |
return nsmng_broadcast_error(mng, status) == NSERROR_OK; |
} |
bitmap_modified(mng->bitmap); |
/* Optimise the plotting of MNG */ |
mng->opaque_test_pending = false; |
return true; |
} |
static bool nsjpng_convert(struct content *c) |
{ |
nsmng_content *mng = (nsmng_content *) c; |
mng_retcode status; |
unsigned long size; |
char *title; |
mng_handle handle; |
assert(c != NULL); |
content__get_source_data(c, &size); |
/* by this point, the png should have been parsed |
* and the bitmap created, so ensure that's the case |
*/ |
if (mng->bitmap == NULL) { |
return nsmng_broadcast_error(mng, -1) == NSERROR_OK; |
} |
/* set title text */ |
title = messages_get_buff("PNGTitle", |
nsurl_access_leaf(llcache_handle_get_url(c->llcache)), |
c->width, c->height); |
if (title != NULL) { |
content__set_title(c, title); |
free(title); |
} |
c->size += c->width * c->height * 4; |
content_set_ready(c); |
content_set_done(c); |
/* Done: update status bar */ |
content_set_status(c, ""); |
/* jmb: I'm really not sure that this should be here. |
* The *_convert functions are for converting a content into a |
* displayable format. They should not, however, do anything which |
* could cause the content to be displayed; the content may have |
* hidden visibility or be a fallback for an object; this |
* information is not available here (nor is there any need for it |
* to be). |
* The specific issue here is that mng_display calls the display |
* callbacks, which include nsmng_refresh. nsmng_refresh forces |
* a content to be redrawn regardless of whether it should be |
* displayed or not. |
*/ |
/* Start displaying |
*/ |
status = mng_display(mng->handle); |
if ((status != MNG_NOERROR) && (status != MNG_NEEDTIMERWAIT)) { |
LOG(("Unable to start display (%i)", status)); |
return nsmng_broadcast_error(mng, status) == NSERROR_OK; |
} |
bitmap_modified(mng->bitmap); |
/* Optimise the plotting of JNG/PNGs |
*/ |
mng->opaque_test_pending = true; |
bitmap_set_opaque(mng->bitmap, false); |
/* free associated memory */ |
handle = mng->handle; |
mng_cleanup(&handle); |
mng->handle = NULL; |
return true; |
} |
static void nsmng_destroy(struct content *c) |
{ |
nsmng_content *mng = (nsmng_content *) c; |
assert (c != NULL); |
/* Cleanup the MNG structure and release the canvas memory |
*/ |
schedule_remove(nsmng_animate, c); |
if (mng->handle != NULL) { |
mng_handle handle = mng->handle; |
mng_cleanup(&handle); |
mng->handle = NULL; |
} |
if (mng->bitmap) { |
bitmap_destroy(mng->bitmap); |
} |
} |
static bool nsmng_redraw(struct content *c, struct content_redraw_data *data, |
const struct rect *clip, const struct redraw_context *ctx) |
{ |
nsmng_content *mng = (nsmng_content *) c; |
bool ret; |
bitmap_flags_t flags = BITMAPF_NONE; |
/* mark image as having been requested to display */ |
mng->displayed = true; |
if ((mng->bitmap) && |
(mng->opaque_test_pending)) { |
bitmap_set_opaque(mng->bitmap, bitmap_test_opaque(mng->bitmap)); |
mng->opaque_test_pending = false; |
} |
if (data->repeat_x) |
flags |= BITMAPF_REPEAT_X; |
if (data->repeat_y) |
flags |= BITMAPF_REPEAT_Y; |
ret = ctx->plot->bitmap(data->x, data->y, data->width, data->height, |
mng->bitmap, data->background_colour, flags); |
/* Check if we need to restart the animation */ |
if ((mng->waiting) && |
(nsoption_bool(animate_images))) { |
nsmng_animate(c); |
} |
return ret; |
} |
static nserror nsmng_clone(const struct content *old, struct content **newc) |
{ |
nsmng_content *mng; |
nserror error; |
const char *data; |
unsigned long size; |
mng = calloc(1, sizeof(nsmng_content)); |
if (mng == NULL) |
return NSERROR_NOMEM; |
error = content__clone(old, &mng->base); |
if (error != NSERROR_OK) { |
content_destroy(&mng->base); |
return error; |
} |
/* Simply replay create/process/convert */ |
error = nsmng_create_mng_data(mng); |
if (error != NSERROR_OK) { |
content_destroy(&mng->base); |
return error; |
} |
data = content__get_source_data(&mng->base, &size); |
if (size > 0) { |
if (nsmng_process_data(&mng->base, data, size) == false) { |
content_destroy(&mng->base); |
return NSERROR_CLONE_FAILED; |
} |
} |
if (old->status == CONTENT_STATUS_READY || |
old->status == CONTENT_STATUS_DONE) { |
if (nsmng_convert(&mng->base) == false) { |
content_destroy(&mng->base); |
return NSERROR_CLONE_FAILED; |
} |
} |
*newc = (struct content *) mng; |
return NSERROR_OK; |
} |
static void *nsmng_get_internal(const struct content *c, void *context) |
{ |
nsmng_content *mng = (nsmng_content *)c; |
return mng->bitmap; |
} |
static content_type nsmng_content_type(void) |
{ |
return CONTENT_IMAGE; |
} |
/* register handler for mng types */ |
static const content_handler nsmng_content_handler = { |
.create = nsmng_create, |
.process_data = nsmng_process_data, |
.data_complete = nsmng_convert, |
.destroy = nsmng_destroy, |
.redraw = nsmng_redraw, |
.clone = nsmng_clone, |
.get_internal = nsmng_get_internal, |
.type = nsmng_content_type, |
.no_share = false, |
}; |
static const char *nsmng_types[] = { |
/* MNG types*/ |
"image/mng", |
"image/x-mng", |
"video/mng", |
"video/x-mng", |
}; |
CONTENT_FACTORY_REGISTER_TYPES(nsmng, nsmng_types, nsmng_content_handler); |
/* register handler for jng and png types */ |
static const content_handler nsjpng_content_handler = { |
.create = nsmng_create, |
.process_data = nsmng_process_data, |
.data_complete = nsjpng_convert, |
.destroy = nsmng_destroy, |
.redraw = nsmng_redraw, |
.clone = nsmng_clone, |
.get_internal = nsmng_get_internal, |
.type = nsmng_content_type, |
.no_share = false, |
}; |
static const char *nsjpng_types[] = { |
/* JNG types*/ |
"image/jng", |
"image/x-jng", |
/* PNG types*/ |
"image/png", |
"image/x-png" |
}; |
CONTENT_FACTORY_REGISTER_TYPES(nsjpng, nsjpng_types, nsjpng_content_handler); |
/contrib/network/netsurf/netsurf/image/mng.h |
---|
0,0 → 1,29 |
/* |
* Copyright 2004 Richard Wilson <not_ginger_matt@users.sourceforge.net> |
* |
* This file is part of NetSurf, http://www.netsurf-browser.org/ |
* |
* NetSurf is free software; you can redistribute it and/or modify |
* it under the terms of the GNU General Public License as published by |
* the Free Software Foundation; version 2 of the License. |
* |
* NetSurf 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 General Public License for more details. |
* |
* You should have received a copy of the GNU General Public License |
* along with this program. If not, see <http://www.gnu.org/licenses/>. |
*/ |
/** \file |
* Content for image/mng, image/png, and image/jng (interface). |
*/ |
#ifndef _NETSURF_IMAGE_MNG_H_ |
#define _NETSURF_IMAGE_MNG_H_ |
nserror nsmng_init(void); |
nserror nsjpng_init(void); |
#endif |
/contrib/network/netsurf/netsurf/image/nssprite.c |
---|
0,0 → 1,258 |
/* |
* Copyright 2008 James Shaw <js102@zepler.net> |
* |
* This file is part of NetSurf, http://www.netsurf-browser.org/ |
* |
* NetSurf is free software; you can redistribute it and/or modify |
* it under the terms of the GNU General Public License as published by |
* the Free Software Foundation; version 2 of the License. |
* |
* NetSurf 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 General Public License for more details. |
* |
* You should have received a copy of the GNU General Public License |
* along with this program. If not, see <http://www.gnu.org/licenses/>. |
*/ |
/** \file |
* Content for image/x-riscos-sprite (librosprite implementation). |
* |
*/ |
#include <assert.h> |
#include <string.h> |
#include <stdlib.h> |
#include <librosprite.h> |
#include "utils/config.h" |
#include "content/content_protected.h" |
#include "desktop/plotters.h" |
#include "image/bitmap.h" |
#include "image/nssprite.h" |
#include "utils/log.h" |
#include "utils/messages.h" |
#include "utils/utils.h" |
typedef struct nssprite_content { |
struct content base; |
struct bitmap *bitmap; /**< Created NetSurf bitmap */ |
struct rosprite_area* sprite_area; |
} nssprite_content; |
#define ERRCHK(x) do { \ |
rosprite_error err = x; \ |
if (err == ROSPRITE_EOF) { \ |
LOG(("Got ROSPRITE_EOF when loading sprite file")); \ |
return false; \ |
} else if (err == ROSPRITE_BADMODE) { \ |
LOG(("Got ROSPRITE_BADMODE when loading sprite file")); \ |
return false; \ |
} else if (err == ROSPRITE_OK) { \ |
} else { \ |
return false; \ |
} \ |
} while(0) |
static nserror nssprite_create(const content_handler *handler, |
lwc_string *imime_type, const http_parameter *params, |
llcache_handle *llcache, const char *fallback_charset, |
bool quirks, struct content **c) |
{ |
nssprite_content *sprite; |
nserror error; |
sprite = calloc(1, sizeof(nssprite_content)); |
if (sprite == NULL) |
return NSERROR_NOMEM; |
error = content__init(&sprite->base, handler, imime_type, params, |
llcache, fallback_charset, quirks); |
if (error != NSERROR_OK) { |
free(sprite); |
return error; |
} |
*c = (struct content *) sprite; |
return NSERROR_OK; |
} |
/** |
* Convert a CONTENT_SPRITE for display. |
* |
* No conversion is necessary. We merely read the sprite dimensions. |
*/ |
static bool nssprite_convert(struct content *c) |
{ |
nssprite_content *nssprite = (nssprite_content *) c; |
union content_msg_data msg_data; |
struct rosprite_mem_context* ctx; |
const char *data; |
unsigned long size; |
char *title; |
data = content__get_source_data(c, &size); |
ERRCHK(rosprite_create_mem_context((uint8_t *) data, size, &ctx)); |
struct rosprite_area* sprite_area; |
ERRCHK(rosprite_load(rosprite_mem_reader, ctx, &sprite_area)); |
rosprite_destroy_mem_context(ctx); |
nssprite->sprite_area = sprite_area; |
assert(sprite_area->sprite_count > 0); |
struct rosprite* sprite = sprite_area->sprites[0]; |
nssprite->bitmap = bitmap_create(sprite->width, sprite->height, BITMAP_NEW); |
if (!nssprite->bitmap) { |
msg_data.error = messages_get("NoMemory"); |
content_broadcast(c, CONTENT_MSG_ERROR, msg_data); |
return false; |
} |
uint32_t* imagebuf = (uint32_t *)bitmap_get_buffer(nssprite->bitmap); |
if (!imagebuf) { |
msg_data.error = messages_get("NoMemory"); |
content_broadcast(c, CONTENT_MSG_ERROR, msg_data); |
return false; |
} |
unsigned char *spritebuf = (unsigned char *)sprite->image; |
/* reverse byte order of each word */ |
for (uint32_t y = 0; y < sprite->height; y++) { |
for (uint32_t x = 0; x < sprite->width; x++) { |
int offset = 4 * (y * sprite->width + x); |
*imagebuf = (spritebuf[offset] << 24) | |
(spritebuf[offset + 1] << 16) | |
(spritebuf[offset + 2] << 8) | |
(spritebuf[offset + 3]); |
imagebuf++; |
} |
} |
c->width = sprite->width; |
c->height = sprite->height; |
/* set title text */ |
title = messages_get_buff("SpriteTitle", |
nsurl_access_leaf(llcache_handle_get_url(c->llcache)), |
c->width, c->height); |
if (title != NULL) { |
content__set_title(c, title); |
free(title); |
} |
bitmap_modified(nssprite->bitmap); |
content_set_ready(c); |
content_set_done(c); |
content_set_status(c, ""); /* Done: update status bar */ |
return true; |
} |
/** |
* Destroy a CONTENT_SPRITE and free all resources it owns. |
*/ |
static void nssprite_destroy(struct content *c) |
{ |
nssprite_content *nssprite = (nssprite_content *) c; |
if (nssprite->sprite_area != NULL) |
rosprite_destroy_sprite_area(nssprite->sprite_area); |
if (nssprite->bitmap != NULL) |
bitmap_destroy(nssprite->bitmap); |
} |
/** |
* Redraw a CONTENT_SPRITE. |
*/ |
static bool nssprite_redraw(struct content *c, struct content_redraw_data *data, |
const struct rect *clip, const struct redraw_context *ctx) |
{ |
nssprite_content *nssprite = (nssprite_content *) c; |
bitmap_flags_t flags = BITMAPF_NONE; |
if (data->repeat_x) |
flags |= BITMAPF_REPEAT_X; |
if (data->repeat_y) |
flags |= BITMAPF_REPEAT_Y; |
return ctx->plot->bitmap(data->x, data->y, data->width, data->height, |
nssprite->bitmap, data->background_colour, flags); |
} |
static nserror nssprite_clone(const struct content *old, struct content **newc) |
{ |
nssprite_content *sprite; |
nserror error; |
sprite = calloc(1, sizeof(nssprite_content)); |
if (sprite == NULL) |
return NSERROR_NOMEM; |
error = content__clone(old, &sprite->base); |
if (error != NSERROR_OK) { |
content_destroy(&sprite->base); |
return error; |
} |
/* Simply replay convert */ |
if (old->status == CONTENT_STATUS_READY || |
old->status == CONTENT_STATUS_DONE) { |
if (nssprite_convert(&sprite->base) == false) { |
content_destroy(&sprite->base); |
return NSERROR_CLONE_FAILED; |
} |
} |
*newc = (struct content *) sprite; |
return NSERROR_OK; |
} |
static void *nssprite_get_internal(const struct content *c, void *context) |
{ |
nssprite_content *nssprite = (nssprite_content *) c; |
return nssprite->bitmap; |
} |
static content_type nssprite_content_type(void) |
{ |
return CONTENT_IMAGE; |
} |
static const content_handler nssprite_content_handler = { |
.create = nssprite_create, |
.data_complete = nssprite_convert, |
.destroy = nssprite_destroy, |
.redraw = nssprite_redraw, |
.clone = nssprite_clone, |
.get_internal = nssprite_get_internal, |
.type = nssprite_content_type, |
.no_share = false, |
}; |
static const char *nssprite_types[] = { |
"image/x-riscos-sprite" |
}; |
CONTENT_FACTORY_REGISTER_TYPES(nssprite, nssprite_types, nssprite_content_handler); |
/contrib/network/netsurf/netsurf/image/nssprite.h |
---|
0,0 → 1,28 |
/* |
* Copyright 2008 James Shaw <js102@zepler.net> |
* |
* This file is part of NetSurf, http://www.netsurf-browser.org/ |
* |
* NetSurf is free software; you can redistribute it and/or modify |
* it under the terms of the GNU General Public License as published by |
* the Free Software Foundation; version 2 of the License. |
* |
* NetSurf 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 General Public License for more details. |
* |
* You should have received a copy of the GNU General Public License |
* along with this program. If not, see <http://www.gnu.org/licenses/>. |
*/ |
/** \file |
* Content for image/x-riscos-sprite (librosprite interface). |
*/ |
#ifndef _NETSURF_NS_SPRITE_H_ |
#define _NETSURF_NS_SPRITE_H_ |
nserror nssprite_init(void); |
#endif |
/contrib/network/netsurf/netsurf/image/png.c |
---|
0,0 → 1,608 |
/* |
* Copyright 2004 James Bursa <bursa@users.sourceforge.net> |
* Copyright 2004 Richard Wilson <not_ginger_matt@hotmail.com> |
* Copyright 2008 Daniel Silverstone <dsilvers@netsurf-browser.org> |
* |
* This file is part of NetSurf, http://www.netsurf-browser.org/ |
* |
* NetSurf is free software; you can redistribute it and/or modify |
* it under the terms of the GNU General Public License as published by |
* the Free Software Foundation; version 2 of the License. |
* |
* NetSurf 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 General Public License for more details. |
* |
* You should have received a copy of the GNU General Public License |
* along with this program. If not, see <http://www.gnu.org/licenses/>. |
*/ |
#include <assert.h> |
#include <stdbool.h> |
#include <string.h> |
#include <stdlib.h> |
#include <png.h> |
#include "desktop/plotters.h" |
#include "content/content_protected.h" |
#include "image/bitmap.h" |
#include "image/image_cache.h" |
#include "image/png.h" |
#include "utils/log.h" |
#include "utils/messages.h" |
#include "utils/utils.h" |
/* accommodate for old versions of libpng (beware security holes!) */ |
#ifndef png_jmpbuf |
#warning you have an antique libpng |
#define png_jmpbuf(png_ptr) ((png_ptr)->jmpbuf) |
#endif |
#if PNG_LIBPNG_VER < 10209 |
#define png_set_expand_gray_1_2_4_to_8(png) png_set_gray_1_2_4_to_8(png) |
#endif |
typedef struct nspng_content { |
struct content base; /**< base content type */ |
bool no_process_data; /**< Do not continue to process data as it arrives */ |
png_structp png; |
png_infop info; |
int interlace; |
struct bitmap *bitmap; /**< Created NetSurf bitmap */ |
size_t rowstride, bpp; /**< Bitmap rowstride and bpp */ |
size_t rowbytes; /**< Number of bytes per row */ |
} nspng_content; |
static unsigned int interlace_start[8] = {0, 16, 0, 8, 0, 4, 0}; |
static unsigned int interlace_step[8] = {28, 28, 12, 12, 4, 4, 0}; |
static unsigned int interlace_row_start[8] = {0, 0, 4, 0, 2, 0, 1}; |
static unsigned int interlace_row_step[8] = {8, 8, 8, 4, 4, 2, 2}; |
/** Callbak error numbers*/ |
enum nspng_cberr { |
CBERR_NONE = 0, /* no error */ |
CBERR_LIBPNG, /* error from png library */ |
CBERR_NOPRE, /* no pre-conversion performed */ |
}; |
/** |
* nspng_warning -- callback for libpng warnings |
*/ |
static void nspng_warning(png_structp png_ptr, png_const_charp warning_message) |
{ |
LOG(("%s", warning_message)); |
} |
/** |
* nspng_error -- callback for libpng errors |
*/ |
static void nspng_error(png_structp png_ptr, png_const_charp error_message) |
{ |
LOG(("%s", error_message)); |
longjmp(png_jmpbuf(png_ptr), CBERR_LIBPNG); |
} |
static void nspng_setup_transforms(png_structp png_ptr, png_infop info_ptr) |
{ |
int bit_depth, color_type, intent; |
double gamma; |
bit_depth = png_get_bit_depth(png_ptr, info_ptr); |
color_type = png_get_color_type(png_ptr, info_ptr); |
/* Set up our transformations */ |
if (color_type == PNG_COLOR_TYPE_PALETTE) { |
png_set_palette_to_rgb(png_ptr); |
} |
if ((color_type == PNG_COLOR_TYPE_GRAY) && (bit_depth < 8)) { |
png_set_expand_gray_1_2_4_to_8(png_ptr); |
} |
if (png_get_valid(png_ptr, info_ptr, PNG_INFO_tRNS)) { |
png_set_tRNS_to_alpha(png_ptr); |
} |
if (bit_depth == 16) { |
png_set_strip_16(png_ptr); |
} |
if (color_type == PNG_COLOR_TYPE_GRAY || |
color_type == PNG_COLOR_TYPE_GRAY_ALPHA) { |
png_set_gray_to_rgb(png_ptr); |
} |
if (!(color_type & PNG_COLOR_MASK_ALPHA)) { |
png_set_filler(png_ptr, 0xff, PNG_FILLER_AFTER); |
} |
/* gamma correction - we use 2.2 as our screen gamma |
* this appears to be correct (at least in respect to !Browse) |
* see http://www.w3.org/Graphics/PNG/all_seven.html for a test case |
*/ |
if (png_get_sRGB(png_ptr, info_ptr, &intent)) { |
png_set_gamma(png_ptr, 2.2, 0.45455); |
} else { |
if (png_get_gAMA(png_ptr, info_ptr, &gamma)) { |
png_set_gamma(png_ptr, 2.2, gamma); |
} else { |
png_set_gamma(png_ptr, 2.2, 0.45455); |
} |
} |
png_read_update_info(png_ptr, info_ptr); |
} |
/** |
* info_callback -- PNG header has been completely received, prepare to process |
* image data |
*/ |
static void info_callback(png_structp png_s, png_infop info) |
{ |
int interlace; |
png_uint_32 width, height; |
nspng_content *png_c = png_get_progressive_ptr(png_s); |
width = png_get_image_width(png_s, info); |
height = png_get_image_height(png_s, info); |
interlace = png_get_interlace_type(png_s, info); |
png_c->base.width = width; |
png_c->base.height = height; |
png_c->base.size += width * height * 4; |
/* see if progressive-conversion should continue */ |
if (image_cache_speculate((struct content *)png_c) == false) { |
longjmp(png_jmpbuf(png_s), CBERR_NOPRE); |
} |
/* Claim the required memory for the converted PNG */ |
png_c->bitmap = bitmap_create(width, height, BITMAP_NEW); |
if (png_c->bitmap == NULL) { |
/* Failed to create bitmap skip pre-conversion */ |
longjmp(png_jmpbuf(png_s), CBERR_NOPRE); |
} |
png_c->rowstride = bitmap_get_rowstride(png_c->bitmap); |
png_c->bpp = bitmap_get_bpp(png_c->bitmap); |
nspng_setup_transforms(png_s, info); |
png_c->rowbytes = png_get_rowbytes(png_s, info); |
png_c->interlace = (interlace == PNG_INTERLACE_ADAM7); |
LOG(("size %li * %li, rowbytes %zu", (unsigned long)width, |
(unsigned long)height, png_c->rowbytes)); |
} |
static void row_callback(png_structp png_s, png_bytep new_row, |
png_uint_32 row_num, int pass) |
{ |
nspng_content *png_c = png_get_progressive_ptr(png_s); |
unsigned long rowbytes = png_c->rowbytes; |
unsigned char *buffer, *row; |
/* Give up if there's no bitmap */ |
if (png_c->bitmap == NULL) |
return; |
/* Abort if we've not got any data */ |
if (new_row == NULL) |
return; |
/* Get bitmap buffer */ |
buffer = bitmap_get_buffer(png_c->bitmap); |
if (buffer == NULL) { |
/* No buffer, bail out */ |
longjmp(png_jmpbuf(png_s), 1); |
} |
/* Calculate address of row start */ |
row = buffer + (png_c->rowstride * row_num); |
/* Handle interlaced sprites using the Adam7 algorithm */ |
if (png_c->interlace) { |
unsigned long dst_off; |
unsigned long src_off = 0; |
unsigned int start, step; |
start = interlace_start[pass]; |
step = interlace_step[pass]; |
row_num = interlace_row_start[pass] + |
interlace_row_step[pass] * row_num; |
/* Copy the data to our current row taking interlacing |
* into consideration */ |
row = buffer + (png_c->rowstride * row_num); |
for (dst_off = start; dst_off < rowbytes; dst_off += step) { |
row[dst_off++] = new_row[src_off++]; |
row[dst_off++] = new_row[src_off++]; |
row[dst_off++] = new_row[src_off++]; |
row[dst_off++] = new_row[src_off++]; |
} |
} else { |
/* Do a fast memcpy of the row data */ |
memcpy(row, new_row, rowbytes); |
} |
} |
static void end_callback(png_structp png_s, png_infop info) |
{ |
} |
static nserror nspng_create_png_data(nspng_content *png_c) |
{ |
union content_msg_data msg_data; |
png_c->bitmap = NULL; |
png_c->png = png_create_read_struct(PNG_LIBPNG_VER_STRING, 0, 0, 0); |
if (png_c->png == NULL) { |
msg_data.error = messages_get("NoMemory"); |
content_broadcast(&png_c->base, CONTENT_MSG_ERROR, msg_data); |
warn_user("NoMemory", 0); |
return NSERROR_NOMEM; |
} |
png_set_error_fn(png_c->png, NULL, nspng_error, nspng_warning); |
png_c->info = png_create_info_struct(png_c->png); |
if (png_c->info == NULL) { |
png_destroy_read_struct(&png_c->png, &png_c->info, 0); |
msg_data.error = messages_get("NoMemory"); |
content_broadcast(&png_c->base, CONTENT_MSG_ERROR, msg_data); |
warn_user("NoMemory", 0); |
return NSERROR_NOMEM; |
} |
if (setjmp(png_jmpbuf(png_c->png))) { |
png_destroy_read_struct(&png_c->png, &png_c->info, 0); |
LOG(("Failed to set callbacks")); |
png_c->png = NULL; |
png_c->info = NULL; |
msg_data.error = messages_get("PNGError"); |
content_broadcast(&png_c->base, CONTENT_MSG_ERROR, msg_data); |
return NSERROR_NOMEM; |
} |
png_set_progressive_read_fn(png_c->png, png_c, |
info_callback, row_callback, end_callback); |
return NSERROR_OK; |
} |
static nserror nspng_create(const content_handler *handler, |
lwc_string *imime_type, const http_parameter *params, |
llcache_handle *llcache, const char *fallback_charset, |
bool quirks, struct content **c) |
{ |
nspng_content *png_c; |
nserror error; |
png_c = calloc(1, sizeof(nspng_content)); |
if (png_c == NULL) |
return NSERROR_NOMEM; |
error = content__init(&png_c->base, |
handler, |
imime_type, |
params, |
llcache, |
fallback_charset, |
quirks); |
if (error != NSERROR_OK) { |
free(png_c); |
return error; |
} |
error = nspng_create_png_data(png_c); |
if (error != NSERROR_OK) { |
free(png_c); |
return error; |
} |
*c = (struct content *)png_c; |
return NSERROR_OK; |
} |
static bool nspng_process_data(struct content *c, const char *data, |
unsigned int size) |
{ |
nspng_content *png_c = (nspng_content *)c; |
union content_msg_data msg_data; |
volatile bool ret = true; |
if (png_c->no_process_data) { |
return ret; |
} |
switch (setjmp(png_jmpbuf(png_c->png))) { |
case CBERR_NONE: /* direct return */ |
png_process_data(png_c->png, png_c->info, (uint8_t *)data, size); |
break; |
case CBERR_NOPRE: /* not going to progressive convert */ |
png_c->no_process_data = true; |
break; |
default: /* fatal error from library processing png */ |
if (png_c->bitmap != NULL) { |
/* A bitmap managed to get created so |
* operation is past header and possibly some |
* conversion happened before faliure. |
* |
* In this case keep the partial |
* conversion. This is usually seen if a png |
* has been truncated (often jsut lost its |
* last byte and hence end of image marker) |
*/ |
png_c->no_process_data = true; |
} else { |
/* not managed to progress past header, clean |
* up png conversion and signal the content |
* error |
*/ |
LOG(("Fatal PNG error during header, error content")); |
png_destroy_read_struct(&png_c->png, &png_c->info, 0); |
png_c->png = NULL; |
png_c->info = NULL; |
msg_data.error = messages_get("PNGError"); |
content_broadcast(c, CONTENT_MSG_ERROR, msg_data); |
ret = false; |
} |
break; |
} |
return ret; |
} |
struct png_cache_read_data_s { |
const char *data; |
unsigned long size; |
}; |
/** PNG library read fucntion to read data from a memory array |
*/ |
static void |
png_cache_read_fn(png_structp png_ptr, png_bytep data, png_size_t length) |
{ |
struct png_cache_read_data_s *png_cache_read_data; |
png_cache_read_data = png_get_io_ptr(png_ptr); |
if (length > png_cache_read_data->size) { |
length = png_cache_read_data->size; |
} |
if (length == 0) { |
png_error(png_ptr, "Read Error"); |
} |
memcpy(data, png_cache_read_data->data, length); |
png_cache_read_data->data += length; |
png_cache_read_data->size -= length; |
} |
/** calculate an array of row pointers into a bitmap data area |
*/ |
static png_bytep *calc_row_pointers(struct bitmap *bitmap) |
{ |
int height = bitmap_get_height(bitmap); |
unsigned char *buffer= bitmap_get_buffer(bitmap); |
size_t rowstride = bitmap_get_rowstride(bitmap); |
png_bytep *row_ptrs; |
int hloop; |
row_ptrs = malloc(sizeof(png_bytep) * height); |
if (row_ptrs != NULL) { |
for (hloop = 0; hloop < height; hloop++) { |
row_ptrs[hloop] = buffer + (rowstride * hloop); |
} |
} |
return row_ptrs; |
} |
/** PNG content to bitmap conversion. |
* |
* This routine generates a bitmap object from a PNG image content |
*/ |
static struct bitmap * |
png_cache_convert(struct content *c) |
{ |
png_structp png_ptr; |
png_infop info_ptr; |
png_infop end_info; |
volatile struct bitmap *bitmap = NULL; |
struct png_cache_read_data_s png_cache_read_data; |
png_uint_32 width, height; |
volatile png_bytep *row_pointers = NULL; |
png_cache_read_data.data = |
content__get_source_data(c, &png_cache_read_data.size); |
if ((png_cache_read_data.data == NULL) || |
(png_cache_read_data.size <= 8)) { |
return NULL; |
} |
png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, |
NULL, |
nspng_error, |
nspng_warning); |
if (png_ptr == NULL) { |
return NULL; |
} |
info_ptr = png_create_info_struct(png_ptr); |
if (png_ptr == NULL) { |
png_destroy_read_struct(&png_ptr, NULL, NULL); |
return NULL; |
} |
end_info = png_create_info_struct(png_ptr); |
if (png_ptr == NULL) { |
png_destroy_read_struct(&png_ptr, &info_ptr, NULL); |
return NULL; |
} |
/* setup error exit path */ |
if (setjmp(png_jmpbuf(png_ptr))) { |
/* cleanup and bail */ |
goto png_cache_convert_error; |
} |
/* read from a buffer instead of stdio */ |
png_set_read_fn(png_ptr, &png_cache_read_data, png_cache_read_fn); |
/* ensure the png info structure is populated */ |
png_read_info(png_ptr, info_ptr); |
/* setup output transforms */ |
nspng_setup_transforms(png_ptr, info_ptr); |
width = png_get_image_width(png_ptr, info_ptr); |
height = png_get_image_height(png_ptr,info_ptr); |
/* Claim the required memory for the converted PNG */ |
bitmap = bitmap_create(width, height, BITMAP_NEW); |
if (bitmap == NULL) { |
/* cleanup and bail */ |
goto png_cache_convert_error; |
} |
row_pointers = calc_row_pointers((struct bitmap *) bitmap); |
if (row_pointers != NULL) { |
png_read_image(png_ptr, (png_bytep *) row_pointers); |
} |
png_cache_convert_error: |
/* cleanup png read */ |
png_destroy_read_struct(&png_ptr, &info_ptr, &end_info); |
free((png_bytep *) row_pointers); |
if (bitmap != NULL) |
bitmap_modified((struct bitmap *)bitmap); |
return (struct bitmap *)bitmap; |
} |
static bool nspng_convert(struct content *c) |
{ |
nspng_content *png_c = (nspng_content *) c; |
char *title; |
assert(png_c->png != NULL); |
assert(png_c->info != NULL); |
/* clean up png structures */ |
png_destroy_read_struct(&png_c->png, &png_c->info, 0); |
/* set title text */ |
title = messages_get_buff("PNGTitle", |
nsurl_access_leaf(llcache_handle_get_url(c->llcache)), |
c->width, c->height); |
if (title != NULL) { |
content__set_title(c, title); |
free(title); |
} |
if (png_c->bitmap != NULL) { |
bitmap_set_opaque(png_c->bitmap, bitmap_test_opaque(png_c->bitmap)); |
bitmap_modified(png_c->bitmap); |
} |
image_cache_add(c, png_c->bitmap, png_cache_convert); |
content_set_ready(c); |
content_set_done(c); |
content_set_status(c, ""); |
return true; |
} |
static nserror nspng_clone(const struct content *old_c, struct content **new_c) |
{ |
nspng_content *clone_png_c; |
nserror error; |
const char *data; |
unsigned long size; |
clone_png_c = calloc(1, sizeof(nspng_content)); |
if (clone_png_c == NULL) |
return NSERROR_NOMEM; |
error = content__clone(old_c, &clone_png_c->base); |
if (error != NSERROR_OK) { |
content_destroy(&clone_png_c->base); |
return error; |
} |
/* Simply replay create/process/convert */ |
error = nspng_create_png_data(clone_png_c); |
if (error != NSERROR_OK) { |
content_destroy(&clone_png_c->base); |
return error; |
} |
data = content__get_source_data(&clone_png_c->base, &size); |
if (size > 0) { |
if (nspng_process_data(&clone_png_c->base, data, size) == false) { |
content_destroy(&clone_png_c->base); |
return NSERROR_NOMEM; |
} |
} |
if ((old_c->status == CONTENT_STATUS_READY) || |
(old_c->status == CONTENT_STATUS_DONE)) { |
if (nspng_convert(&clone_png_c->base) == false) { |
content_destroy(&clone_png_c->base); |
return NSERROR_CLONE_FAILED; |
} |
} |
*new_c = (struct content *)clone_png_c; |
return NSERROR_OK; |
} |
static const content_handler nspng_content_handler = { |
.create = nspng_create, |
.process_data = nspng_process_data, |
.data_complete = nspng_convert, |
.clone = nspng_clone, |
.destroy = image_cache_destroy, |
.redraw = image_cache_redraw, |
.get_internal = image_cache_get_internal, |
.type = image_cache_content_type, |
.no_share = false, |
}; |
static const char *nspng_types[] = { |
"image/png", |
"image/x-png" |
}; |
CONTENT_FACTORY_REGISTER_TYPES(nspng, nspng_types, nspng_content_handler); |
/contrib/network/netsurf/netsurf/image/png.h |
---|
0,0 → 1,25 |
/* |
* Copyright 2003 James Bursa <bursa@users.sourceforge.net> |
* Copyright 2008 Daniel Silverstone <dsilvers@netsurf-browser.org> |
* |
* This file is part of NetSurf, http://www.netsurf-browser.org/ |
* |
* NetSurf is free software; you can redistribute it and/or modify |
* it under the terms of the GNU General Public License as published by |
* the Free Software Foundation; version 2 of the License. |
* |
* NetSurf 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 General Public License for more details. |
* |
* You should have received a copy of the GNU General Public License |
* along with this program. If not, see <http://www.gnu.org/licenses/>. |
*/ |
#ifndef _NETSURF_RISCOS_PNG_H_ |
#define _NETSURF_RISCOS_PNG_H_ |
nserror nspng_init(void); |
#endif |
/contrib/network/netsurf/netsurf/image/rsvg.c |
---|
0,0 → 1,322 |
/* |
* Copyright 2007 Rob Kendrick <rjek@netsurf-browser.org> |
* |
* This file is part of NetSurf, http://www.netsurf-browser.org/ |
* |
* NetSurf is free software; you can redistribute it and/or modify |
* it under the terms of the GNU General Public License as published by |
* the Free Software Foundation; version 2 of the License. |
* |
* NetSurf 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 General Public License for more details. |
* |
* You should have received a copy of the GNU General Public License |
* along with this program. If not, see <http://www.gnu.org/licenses/>. |
*/ |
/** \file |
* Content handler for image/svg using librsvg (implementation). |
* |
* SVG files are rendered to a NetSurf bitmap by creating a Cairo rendering |
* surface (content_rsvg_data.cs) over the bitmap's data, creating a Cairo |
* drawing context using that surface, and then passing that drawing context |
* to librsvg which then uses Cairo calls to plot the graphic to the bitmap. |
* We store this in content->bitmap, and then use the usual bitmap plotter |
* function to render it for redraw requests. |
*/ |
#include <stdbool.h> |
#include <assert.h> |
#include <string.h> |
#include <sys/types.h> |
#include <librsvg/rsvg.h> |
#include <librsvg/rsvg-cairo.h> |
#include "content/content_protected.h" |
#include "desktop/plotters.h" |
#include "image/bitmap.h" |
#include "utils/log.h" |
#include "utils/utils.h" |
#include "utils/messages.h" |
#include "image/rsvg.h" |
typedef struct rsvg_content { |
struct content base; |
RsvgHandle *rsvgh; /**< Context handle for RSVG renderer */ |
cairo_surface_t *cs; /**< The surface built inside a nsbitmap */ |
cairo_t *ct; /**< Cairo drawing context */ |
struct bitmap *bitmap; /**< Created NetSurf bitmap */ |
} rsvg_content; |
static nserror rsvg_create_svg_data(rsvg_content *c) |
{ |
union content_msg_data msg_data; |
c->rsvgh = NULL; |
c->cs = NULL; |
c->ct = NULL; |
c->bitmap = NULL; |
if ((c->rsvgh = rsvg_handle_new()) == NULL) { |
LOG(("rsvg_handle_new() returned NULL.")); |
msg_data.error = messages_get("NoMemory"); |
content_broadcast(&c->base, CONTENT_MSG_ERROR, msg_data); |
return NSERROR_NOMEM; |
} |
return NSERROR_OK; |
} |
static nserror rsvg_create(const content_handler *handler, |
lwc_string *imime_type, const http_parameter *params, |
llcache_handle *llcache, const char *fallback_charset, |
bool quirks, struct content **c) |
{ |
rsvg_content *svg; |
nserror error; |
svg = calloc(1, sizeof(rsvg_content)); |
if (svg == NULL) |
return NSERROR_NOMEM; |
error = content__init(&svg->base, handler, imime_type, params, |
llcache, fallback_charset, quirks); |
if (error != NSERROR_OK) { |
free(svg); |
return error; |
} |
error = rsvg_create_svg_data(svg); |
if (error != NSERROR_OK) { |
free(svg); |
return error; |
} |
*c = (struct content *) svg; |
return NSERROR_OK; |
} |
static bool rsvg_process_data(struct content *c, const char *data, |
unsigned int size) |
{ |
rsvg_content *d = (rsvg_content *) c; |
union content_msg_data msg_data; |
GError *err = NULL; |
if (rsvg_handle_write(d->rsvgh, (const guchar *)data, (gsize)size, |
&err) == FALSE) { |
LOG(("rsvg_handle_write returned an error: %s", err->message)); |
msg_data.error = err->message; |
content_broadcast(c, CONTENT_MSG_ERROR, msg_data); |
return false; |
} |
return true; |
} |
/** Convert Cairo's ARGB output to NetSurf's favoured ABGR format. It converts |
* the data in-place. |
* |
* \param pixels Pixel data, in the form of ARGB. This will |
* be overwritten with new data in the form of ABGR. |
* \param width Width of the bitmap |
* \param height Height of the bitmap |
* \param rowstride Number of bytes to skip after each row (this |
* implementation requires this to be a multiple of 4.) |
*/ |
static inline void rsvg_argb_to_abgr(uint8_t *pixels, |
int width, int height, size_t rowstride) |
{ |
uint8_t *p = pixels; |
for (int y = 0; y < height; y++) { |
for (int x = 0; x < width; x++) { |
/* Swap R and B */ |
const uint8_t r = p[x+3]; |
p[x+3] = p[x]; |
p[x] = r; |
} |
p += rowstride; |
} |
} |
static bool rsvg_convert(struct content *c) |
{ |
rsvg_content *d = (rsvg_content *) c; |
union content_msg_data msg_data; |
RsvgDimensionData rsvgsize; |
GError *err = NULL; |
if (rsvg_handle_close(d->rsvgh, &err) == FALSE) { |
LOG(("rsvg_handle_close returned an error: %s", err->message)); |
msg_data.error = err->message; |
content_broadcast(c, CONTENT_MSG_ERROR, msg_data); |
return false; |
} |
assert(err == NULL); |
/* we should now be able to query librsvg for the natural size of the |
* graphic, so we can create our bitmap. |
*/ |
rsvg_handle_get_dimensions(d->rsvgh, &rsvgsize); |
c->width = rsvgsize.width; |
c->height = rsvgsize.height; |
if ((d->bitmap = bitmap_create(c->width, c->height, |
BITMAP_NEW)) == NULL) { |
LOG(("Failed to create bitmap for rsvg render.")); |
msg_data.error = messages_get("NoMemory"); |
content_broadcast(c, CONTENT_MSG_ERROR, msg_data); |
return false; |
} |
if ((d->cs = cairo_image_surface_create_for_data( |
(unsigned char *)bitmap_get_buffer(d->bitmap), |
CAIRO_FORMAT_ARGB32, |
c->width, c->height, |
bitmap_get_rowstride(d->bitmap))) == NULL) { |
LOG(("Failed to create Cairo image surface for rsvg render.")); |
msg_data.error = messages_get("NoMemory"); |
content_broadcast(c, CONTENT_MSG_ERROR, msg_data); |
return false; |
} |
if ((d->ct = cairo_create(d->cs)) == NULL) { |
LOG(("Failed to create Cairo drawing context for rsvg render.")); |
msg_data.error = messages_get("NoMemory"); |
content_broadcast(c, CONTENT_MSG_ERROR, msg_data); |
return false; |
} |
rsvg_handle_render_cairo(d->rsvgh, d->ct); |
rsvg_argb_to_abgr(bitmap_get_buffer(d->bitmap), |
c->width, c->height, |
bitmap_get_rowstride(d->bitmap)); |
bitmap_modified(d->bitmap); |
content_set_ready(c); |
content_set_done(c); |
/* Done: update status bar */ |
content_set_status(c, ""); |
return true; |
} |
static bool rsvg_redraw(struct content *c, struct content_redraw_data *data, |
const struct rect *clip, const struct redraw_context *ctx) |
{ |
rsvg_content *rsvgcontent = (rsvg_content *) c; |
bitmap_flags_t flags = BITMAPF_NONE; |
assert(rsvgcontent->bitmap != NULL); |
if (data->repeat_x) |
flags |= BITMAPF_REPEAT_X; |
if (data->repeat_y) |
flags |= BITMAPF_REPEAT_Y; |
return ctx->plot->bitmap(data->x, data->y, data->width, data->height, |
rsvgcontent->bitmap, data->background_colour, flags); |
} |
static void rsvg_destroy(struct content *c) |
{ |
rsvg_content *d = (rsvg_content *) c; |
if (d->bitmap != NULL) bitmap_destroy(d->bitmap); |
if (d->rsvgh != NULL) g_object_unref(d->rsvgh); |
if (d->ct != NULL) cairo_destroy(d->ct); |
if (d->cs != NULL) cairo_surface_destroy(d->cs); |
return; |
} |
static nserror rsvg_clone(const struct content *old, struct content **newc) |
{ |
rsvg_content *svg; |
nserror error; |
const char *data; |
unsigned long size; |
svg = calloc(1, sizeof(rsvg_content)); |
if (svg == NULL) |
return NSERROR_NOMEM; |
error = content__clone(old, &svg->base); |
if (error != NSERROR_OK) { |
content_destroy(&svg->base); |
return error; |
} |
/* Simply replay create/process/convert */ |
error = rsvg_create_svg_data(svg); |
if (error != NSERROR_OK) { |
content_destroy(&svg->base); |
return error; |
} |
data = content__get_source_data(&svg->base, &size); |
if (size > 0) { |
if (rsvg_process_data(&svg->base, data, size) == false) { |
content_destroy(&svg->base); |
return NSERROR_NOMEM; |
} |
} |
if (old->status == CONTENT_STATUS_READY || |
old->status == CONTENT_STATUS_DONE) { |
if (rsvg_convert(&svg->base) == false) { |
content_destroy(&svg->base); |
return NSERROR_CLONE_FAILED; |
} |
} |
*newc = (struct content *) svg; |
return NSERROR_OK; |
} |
static void *rsvg_get_internal(const struct content *c, void *context) |
{ |
rsvg_content *d = (rsvg_content *) c; |
return d->bitmap; |
} |
static content_type rsvg_content_type(void) |
{ |
return CONTENT_IMAGE; |
} |
static const content_handler rsvg_content_handler = { |
.create = rsvg_create, |
.process_data = rsvg_process_data, |
.data_complete = rsvg_convert, |
.destroy = rsvg_destroy, |
.redraw = rsvg_redraw, |
.clone = rsvg_clone, |
.get_internal = rsvg_get_internal, |
.type = rsvg_content_type, |
.no_share = false, |
}; |
static const char *rsvg_types[] = { |
"image/svg", |
"image/svg+xml" |
}; |
CONTENT_FACTORY_REGISTER_TYPES(nsrsvg, rsvg_types, rsvg_content_handler); |
/contrib/network/netsurf/netsurf/image/rsvg.h |
---|
0,0 → 1,28 |
/* |
* Copyright 2007 Rob Kendrick <rjek@netsurf-browser.org> |
* |
* This file is part of NetSurf, http://www.netsurf-browser.org/ |
* |
* NetSurf is free software; you can redistribute it and/or modify |
* it under the terms of the GNU General Public License as published by |
* the Free Software Foundation; version 2 of the License. |
* |
* NetSurf 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 General Public License for more details. |
* |
* You should have received a copy of the GNU General Public License |
* along with this program. If not, see <http://www.gnu.org/licenses/>. |
*/ |
/** \file |
* Content handler for image/svg using librsvg (interface). |
*/ |
#ifndef _NETSURF_IMAGE_RSVG_H_ |
#define _NETSURF_IMAGE_RSVG_H_ |
nserror nsrsvg_init(void); |
#endif |
/contrib/network/netsurf/netsurf/image/svg.c |
---|
0,0 → 1,352 |
/* |
* Copyright 2007-2008 James Bursa <bursa@users.sourceforge.net> |
* |
* This file is part of NetSurf, http://www.netsurf-browser.org/ |
* |
* NetSurf is free software; you can redistribute it and/or modify |
* it under the terms of the GNU General Public License as published by |
* the Free Software Foundation; version 2 of the License. |
* |
* NetSurf 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 General Public License for more details. |
* |
* You should have received a copy of the GNU General Public License |
* along with this program. If not, see <http://www.gnu.org/licenses/>. |
*/ |
/** \file |
* Content for image/svg (implementation). |
*/ |
#include <assert.h> |
#include <limits.h> |
#include <string.h> |
#include <svgtiny.h> |
#include "content/content_protected.h" |
#include "css/css.h" |
#include "desktop/plotters.h" |
#include "image/svg.h" |
#include "utils/messages.h" |
#include "utils/utils.h" |
typedef struct svg_content { |
struct content base; |
struct svgtiny_diagram *diagram; |
int current_width; |
int current_height; |
} svg_content; |
static nserror svg_create_svg_data(svg_content *c) |
{ |
union content_msg_data msg_data; |
c->diagram = svgtiny_create(); |
if (c->diagram == NULL) |
goto no_memory; |
c->current_width = INT_MAX; |
c->current_height = INT_MAX; |
return NSERROR_OK; |
no_memory: |
msg_data.error = messages_get("NoMemory"); |
content_broadcast(&c->base, CONTENT_MSG_ERROR, msg_data); |
return NSERROR_NOMEM; |
} |
/** |
* Create a CONTENT_SVG. |
*/ |
static nserror svg_create(const content_handler *handler, |
lwc_string *imime_type, const http_parameter *params, |
llcache_handle *llcache, const char *fallback_charset, |
bool quirks, struct content **c) |
{ |
svg_content *svg; |
nserror error; |
svg = calloc(1, sizeof(svg_content)); |
if (svg == NULL) |
return NSERROR_NOMEM; |
error = content__init(&svg->base, handler, imime_type, params, |
llcache, fallback_charset, quirks); |
if (error != NSERROR_OK) { |
free(svg); |
return error; |
} |
error = svg_create_svg_data(svg); |
if (error != NSERROR_OK) { |
free(svg); |
return error; |
} |
*c = (struct content *) svg; |
return NSERROR_OK; |
} |
/** |
* Convert a CONTENT_SVG for display. |
*/ |
static bool svg_convert(struct content *c) |
{ |
/*c->title = malloc(100); |
if (c->title) |
snprintf(c->title, 100, messages_get("svgTitle"), |
width, height, c->source_size);*/ |
//c->size += ?; |
content_set_ready(c); |
content_set_done(c); |
/* Done: update status bar */ |
content_set_status(c, ""); |
return true; |
} |
/** |
* Reformat a CONTENT_SVG. |
*/ |
static void svg_reformat(struct content *c, int width, int height) |
{ |
svg_content *svg = (svg_content *) c; |
const char *source_data; |
unsigned long source_size; |
assert(svg->diagram); |
/* Avoid reformats to same width/height as we already reformatted to */ |
if (width != svg->current_width || height != svg->current_height) { |
source_data = content__get_source_data(c, &source_size); |
svgtiny_parse(svg->diagram, source_data, source_size, |
nsurl_access(content_get_url(c)), |
width, height); |
svg->current_width = width; |
svg->current_height = height; |
} |
c->width = svg->diagram->width; |
c->height = svg->diagram->height; |
} |
/** |
* Redraw a CONTENT_SVG. |
*/ |
static bool svg_redraw_internal(struct content *c, int x, int y, |
int width, int height, const struct rect *clip, |
const struct redraw_context *ctx, float scale, |
colour background_colour) |
{ |
svg_content *svg = (svg_content *) c; |
float transform[6]; |
struct svgtiny_diagram *diagram = svg->diagram; |
bool ok; |
int px, py; |
unsigned int i; |
plot_font_style_t fstyle = *plot_style_font; |
assert(diagram); |
transform[0] = (float) width / (float) c->width; |
transform[1] = 0; |
transform[2] = 0; |
transform[3] = (float) height / (float) c->height; |
transform[4] = x; |
transform[5] = y; |
#define BGR(c) ((c) == svgtiny_TRANSPARENT ? NS_TRANSPARENT : \ |
((svgtiny_RED((c))) | \ |
(svgtiny_GREEN((c)) << 8) | \ |
(svgtiny_BLUE((c)) << 16))) |
for (i = 0; i != diagram->shape_count; i++) { |
if (diagram->shape[i].path) { |
ok = ctx->plot->path(diagram->shape[i].path, |
diagram->shape[i].path_length, |
BGR(diagram->shape[i].fill), |
diagram->shape[i].stroke_width, |
BGR(diagram->shape[i].stroke), |
transform); |
if (!ok) |
return false; |
} else if (diagram->shape[i].text) { |
px = transform[0] * diagram->shape[i].text_x + |
transform[2] * diagram->shape[i].text_y + |
transform[4]; |
py = transform[1] * diagram->shape[i].text_x + |
transform[3] * diagram->shape[i].text_y + |
transform[5]; |
fstyle.background = 0xffffff; |
fstyle.foreground = 0x000000; |
fstyle.size = (8 * FONT_SIZE_SCALE) * scale; |
ok = ctx->plot->text(px, py, |
diagram->shape[i].text, |
strlen(diagram->shape[i].text), |
&fstyle); |
if (!ok) |
return false; |
} |
} |
#undef BGR |
return true; |
} |
/** |
* Redraw a CONTENT_SVG. |
*/ |
static bool svg_redraw(struct content *c, struct content_redraw_data *data, |
const struct rect *clip, const struct redraw_context *ctx) |
{ |
int x = data->x; |
int y = data->y; |
if ((data->width <= 0) && (data->height <= 0)) { |
/* No point trying to plot SVG if it does not occupy a valid |
* area */ |
return true; |
} |
if ((data->repeat_x == false) && (data->repeat_y == false)) { |
/* Simple case: SVG is not tiled */ |
return svg_redraw_internal(c, x, y, |
data->width, data->height, |
clip, ctx, data->scale, |
data->background_colour); |
} else { |
/* Tiled redraw required. SVG repeats to extents of clip |
* rectangle, in x, y or both directions */ |
int x0, y0, x1, y1; |
/* Find the redraw boundaries to loop within */ |
x0 = x; |
if (data->repeat_x) { |
for (; x0 > clip->x0; x0 -= data->width); |
x1 = clip->x1; |
} else { |
x1 = x + 1; |
} |
y0 = y; |
if (data->repeat_y) { |
for (; y0 > clip->y0; y0 -= data->height); |
y1 = clip->y1; |
} else { |
y1 = y + 1; |
} |
/* Repeatedly plot the SVG across the area */ |
for (y = y0; y < y1; y += data->height) { |
for (x = x0; x < x1; x += data->width) { |
if (!svg_redraw_internal(c, x, y, |
data->width, data->height, |
clip, ctx, data->scale, |
data->background_colour)) { |
return false; |
} |
} |
} |
} |
return true; |
} |
/** |
* Destroy a CONTENT_SVG and free all resources it owns. |
*/ |
static void svg_destroy(struct content *c) |
{ |
svg_content *svg = (svg_content *) c; |
if (svg->diagram != NULL) |
svgtiny_free(svg->diagram); |
} |
static nserror svg_clone(const struct content *old, struct content **newc) |
{ |
svg_content *svg; |
nserror error; |
svg = calloc(1, sizeof(svg_content)); |
if (svg == NULL) |
return NSERROR_NOMEM; |
error = content__clone(old, &svg->base); |
if (error != NSERROR_OK) { |
content_destroy(&svg->base); |
return error; |
} |
/* Simply replay create/convert */ |
error = svg_create_svg_data(svg); |
if (error != NSERROR_OK) { |
content_destroy(&svg->base); |
return error; |
} |
if (old->status == CONTENT_STATUS_READY || |
old->status == CONTENT_STATUS_DONE) { |
if (svg_convert(&svg->base) == false) { |
content_destroy(&svg->base); |
return NSERROR_CLONE_FAILED; |
} |
} |
*newc = (struct content *) svg; |
return NSERROR_OK; |
} |
static content_type svg_content_type(void) |
{ |
return CONTENT_IMAGE; |
} |
static const content_handler svg_content_handler = { |
.create = svg_create, |
.data_complete = svg_convert, |
.reformat = svg_reformat, |
.destroy = svg_destroy, |
.redraw = svg_redraw, |
.clone = svg_clone, |
.type = svg_content_type, |
.no_share = true |
}; |
static const char *svg_types[] = { |
"image/svg", |
"image/svg+xml" |
}; |
CONTENT_FACTORY_REGISTER_TYPES(svg, svg_types, svg_content_handler); |
/contrib/network/netsurf/netsurf/image/svg.h |
---|
0,0 → 1,28 |
/* |
* Copyright 2007-2008 James Bursa <bursa@users.sourceforge.net> |
* |
* This file is part of NetSurf, http://www.netsurf-browser.org/ |
* |
* NetSurf is free software; you can redistribute it and/or modify |
* it under the terms of the GNU General Public License as published by |
* the Free Software Foundation; version 2 of the License. |
* |
* NetSurf 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 General Public License for more details. |
* |
* You should have received a copy of the GNU General Public License |
* along with this program. If not, see <http://www.gnu.org/licenses/>. |
*/ |
/** \file |
* Content for image/svg (interface). |
*/ |
#ifndef _NETSURF_IMAGE_SVG_H_ |
#define _NETSURF_IMAGE_SVG_H_ |
nserror svg_init(void); |
#endif |
/contrib/network/netsurf/netsurf/image/video.c |
---|
0,0 → 1,201 |
/* |
* Copyright 2011 John-Mark Bell <jmb@netsurf-browser.org> |
* |
* This file is part of NetSurf, http://www.netsurf-browser.org/ |
* |
* NetSurf is free software; you can redistribute it and/or modify |
* it under the terms of the GNU General Public License as published by |
* the Free Software Foundation; version 2 of the License. |
* |
* NetSurf 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 General Public License for more details. |
* |
* You should have received a copy of the GNU General Public License |
* along with this program. If not, see <http://www.gnu.org/licenses/>. |
*/ |
#include <gst/gst.h> |
#include "content/content_factory.h" |
#include "content/content_protected.h" |
#include "image/video.h" |
typedef struct nsvideo_content { |
struct content base; |
GstElement *playbin; |
GstElement *appsrc; |
} nsvideo_content; |
static gboolean nsvideo_bus_call(GstBus *bus, GstMessage *msg, |
nsvideo_content *video) |
{ |
switch (GST_MESSAGE_TYPE(msg)) { |
case GST_MESSAGE_ERROR: |
break; |
case GST_MESSAGE_EOS: |
break; |
default: |
break; |
} |
return TRUE; |
} |
static void nsvideo_need_data_event(GstElement *playbin, guint size, |
nsvideo_content *video) |
{ |
} |
static void nsvideo_enough_data_event(GstElement *playbin, |
nsvideo_content *video) |
{ |
} |
static void nsvideo_source_event(GObject *object, GObject *orig, |
GParamSpec *pspec, nsvideo_content *video) |
{ |
g_object_get(orig, pspec->name, &video->appsrc, NULL); |
g_signal_connect(video->appsrc, "need-data", |
G_CALLBACK(nsvideo_need_data_event), video); |
g_signal_connect(video->appsrc, "enough-data", |
G_CALLBACK(nsvideo_enough_data_event), video); |
} |
static nserror nsvideo_create(const content_handler *handler, |
lwc_string *imime_type, const http_parameter *params, |
llcache_handle *llcache, |
const char *fallback_charset, bool quirks, |
struct content **c) |
{ |
nsvideo_content *video; |
nserror error; |
GstBus *bus; |
video = calloc(1, sizeof(nsvideo_content)); |
if (video == NULL) |
return NSERROR_NOMEM; |
error = content__init(&video->base, handler, imime_type, params, |
llcache, fallback_charset, quirks); |
if (error != NSERROR_OK) { |
free(video); |
return error; |
} |
error = llcache_handle_force_stream(llcache); |
if (error != NSERROR_OK) { |
free(video); |
return error; |
} |
video->playbin = gst_element_factory_make("playbin2", NULL); |
if (video->playbin == NULL) { |
free(video); |
return NSERROR_NOMEM; |
} |
bus = gst_pipeline_get_bus(GST_PIPELINE(video->playbin)); |
gst_bus_add_watch(bus, (GstBusFunc) nsvideo_bus_call, video); |
gst_object_unref(bus); |
g_object_set(video->playbin, "uri", "appsrc://", NULL); |
g_signal_connect(video->playbin, "deep-notify::source", |
G_CALLBACK(nsvideo_source_event), video); |
/** \todo Create appsink & register with playbin */ |
gst_element_set_state(video->playbin, GST_STATE_PLAYING); |
*c = (struct content *) video; |
return NSERROR_OK; |
} |
static bool nsvideo_process_data(struct content *c, const char *data, |
unsigned int size) |
{ |
nsvideo_content *video = (nsvideo_content *) c; |
GstBuffer *buffer; |
GstFlowReturn ret; |
buffer = gst_buffer_new(); |
GST_BUFFER_DATA(buffer) = (guint8 *) data; |
GST_BUFFER_SIZE(buffer) = (gsize) size; |
/* Send data to appsrc */ |
g_signal_emit_by_name(video->appsrc, "push-buffer", buffer, &ret); |
return ret == GST_FLOW_OK; |
} |
static bool nsvideo_convert(struct content *c) |
{ |
nsvideo_content *video = (nsvideo_content *) c; |
GstFlowReturn ret; |
/* Tell appsrc we're done */ |
g_signal_emit_by_name(video->appsrc, "end-of-stream", &ret); |
/* Appsink will flag DONE on receipt of first frame */ |
return ret == GST_FLOW_OK; |
} |
static void nsvideo_destroy(struct content *c) |
{ |
nsvideo_content *video = (nsvideo_content *) c; |
gst_element_set_state(video->playbin, GST_STATE_NULL); |
gst_object_unref(video->playbin); |
} |
static bool nsvideo_redraw(struct content *c, struct content_redraw_data *data, |
const struct rect *clip, const struct redraw_context *ctx) |
{ |
/** \todo Implement */ |
return true; |
} |
static nserror nsvideo_clone(const struct content *old, struct content **newc) |
{ |
/** \todo Implement */ |
return NSERROR_CLONE_FAILED; |
} |
static content_type nsvideo_type(void) |
{ |
/** \todo Lies */ |
return CONTENT_IMAGE; |
} |
static void *nsvideo_get_internal(const struct content *c, void *context) |
{ |
/** \todo Return pointer to bitmap containing current frame, if any? */ |
return NULL; |
} |
static const content_handler nsvideo_content_handler = { |
.create = nsvideo_create, |
.process_data = nsvideo_process_data, |
.data_complete = nsvideo_convert, |
.destroy = nsvideo_destroy, |
.redraw = nsvideo_redraw, |
.clone = nsvideo_clone, |
.type = nsvideo_type, |
.get_internal = nsvideo_get_internal, |
/* Can't share videos because we stream them */ |
.no_share = true |
}; |
static const char *nsvideo_types[] = { |
"video/mp4", |
"video/webm" |
}; |
CONTENT_FACTORY_REGISTER_TYPES(nsvideo, nsvideo_types, |
nsvideo_content_handler); |
/contrib/network/netsurf/netsurf/image/video.h |
---|
0,0 → 1,26 |
/* |
* Copyright 2011 John-Mark Bell <jmb@netsurf-browser.org> |
* |
* This file is part of NetSurf, http://www.netsurf-browser.org/ |
* |
* NetSurf is free software; you can redistribute it and/or modify |
* it under the terms of the GNU General Public License as published by |
* the Free Software Foundation; version 2 of the License. |
* |
* NetSurf 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 General Public License for more details. |
* |
* You should have received a copy of the GNU General Public License |
* along with this program. If not, see <http://www.gnu.org/licenses/>. |
*/ |
#ifndef NETSURF_IMAGE_VIDEO_H_ |
#define NETSURF_IMAGE_VIDEO_H_ |
#include "utils/errors.h" |
nserror nsvideo_init(void); |
#endif |
/contrib/network/netsurf/netsurf/image/webp.c |
---|
0,0 → 1,229 |
/* |
* Copyright 2010 Chris Young <chris@unsatisfactorysoftware.co.uk> |
* |
* This file is part of NetSurf, http://www.netsurf-browser.org/ |
* |
* NetSurf is free software; you can redistribute it and/or modify |
* it under the terms of the GNU General Public License as published by |
* the Free Software Foundation; version 2 of the License. |
* |
* NetSurf 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 General Public License for more details. |
* |
* You should have received a copy of the GNU General Public License |
* along with this program. If not, see <http://www.gnu.org/licenses/>. |
*/ |
/** \file |
* Content for image/webp (libwebp implementation). |
* |
*/ |
#include <assert.h> |
#include <string.h> |
#include <stdlib.h> |
#include <webp/decode.h> |
#include "desktop/plotters.h" |
#include "image/bitmap.h" |
#include "content/content_protected.h" |
#include "utils/log.h" |
#include "utils/messages.h" |
#include "utils/utils.h" |
typedef struct webp_content |
{ |
struct content base; |
struct bitmap *bitmap; /**< Created NetSurf bitmap */ |
} webp_content; |
static nserror webp_create(const content_handler *handler, |
lwc_string *imime_type, const http_parameter *params, |
llcache_handle *llcache, const char *fallback_charset, |
bool quirks, struct content **c) |
{ |
webp_content *webp; |
nserror error; |
webp = calloc(1, sizeof(webp_content)); |
if (webp == NULL) |
return NSERROR_NOMEM; |
error = content__init(&webp->base, handler, imime_type, params, |
llcache, fallback_charset, quirks); |
if (error != NSERROR_OK) { |
free(webp); |
return error; |
} |
*c = (struct content *) webp; |
return NSERROR_OK; |
} |
/** |
* Convert a CONTENT_WEBP for display. |
* |
* No conversion is necessary. We merely read the WebP dimensions. |
*/ |
static bool webp_convert(struct content *c) |
{ |
webp_content *webp = (webp_content *)c; |
union content_msg_data msg_data; |
const uint8_t *data; |
unsigned char *imagebuf = NULL; |
unsigned long size; |
int width = 0, height = 0; |
char *title; |
int res = 0; |
uint8_t *res_p = NULL; |
data = (uint8_t *)content__get_source_data(c, &size); |
res = WebPGetInfo(data, size, &width, &height); |
if (res == 0) { |
msg_data.error = messages_get("NoMemory"); |
content_broadcast(c, CONTENT_MSG_ERROR, msg_data); |
return false; |
} |
webp->bitmap = bitmap_create(width, height, BITMAP_NEW | BITMAP_OPAQUE); |
if (!webp->bitmap) { |
msg_data.error = messages_get("NoMemory"); |
content_broadcast(c, CONTENT_MSG_ERROR, msg_data); |
return false; |
} |
imagebuf = bitmap_get_buffer(webp->bitmap); |
if (!imagebuf) { |
msg_data.error = messages_get("NoMemory"); |
content_broadcast(c, CONTENT_MSG_ERROR, msg_data); |
return false; |
} |
unsigned int row_width = bitmap_get_rowstride(webp->bitmap); |
res_p = WebPDecodeRGBAInto(data, size, imagebuf, |
row_width * height, row_width); |
if (res_p == NULL) { |
msg_data.error = messages_get("NoMemory"); |
content_broadcast(c, CONTENT_MSG_ERROR, msg_data); |
return false; |
} |
c->width = width; |
c->height = height; |
/* set title */ |
title = messages_get_buff("WebPTitle", |
nsurl_access_leaf(llcache_handle_get_url(c->llcache)), |
c->width, c->height); |
if (title != NULL) { |
content__set_title(c, title); |
free(title); |
} |
bitmap_modified(webp->bitmap); |
content_set_ready(c); |
content_set_done(c); |
content_set_status(c, ""); |
return true; |
} |
/** |
* Destroy a CONTENT_WEBP and free all resources it owns. |
*/ |
static void webp_destroy(struct content *c) |
{ |
webp_content *webp = (webp_content *)c; |
if (webp->bitmap != NULL) |
bitmap_destroy(webp->bitmap); |
} |
/** |
* Redraw a CONTENT_WEBP. |
*/ |
static bool webp_redraw(struct content *c, struct content_redraw_data *data, |
const struct rect *clip, const struct redraw_context *ctx) |
{ |
webp_content *webp = (webp_content *)c; |
bitmap_flags_t flags = BITMAPF_NONE; |
if (data->repeat_x) |
flags |= BITMAPF_REPEAT_X; |
if (data->repeat_y) |
flags |= BITMAPF_REPEAT_Y; |
return ctx->plot->bitmap(data->x, data->y, data->width, data->height, |
webp->bitmap, data->background_colour, flags); |
} |
static nserror webp_clone(const struct content *old, struct content **newc) |
{ |
webp_content *webp; |
nserror error; |
webp = calloc(1, sizeof(webp_content)); |
if (webp == NULL) |
return NSERROR_NOMEM; |
error = content__clone(old, &webp->base); |
if (error != NSERROR_OK) { |
content_destroy(&webp->base); |
return error; |
} |
/* Simply replay convert */ |
if (old->status == CONTENT_STATUS_READY || |
old->status == CONTENT_STATUS_DONE) { |
if (webp_convert(&webp->base) == false) { |
content_destroy(&webp->base); |
return NSERROR_CLONE_FAILED; |
} |
} |
*newc = (struct content *) webp; |
return NSERROR_OK; |
} |
static void *webp_get_internal(const struct content *c, void *context) |
{ |
webp_content *webp = (webp_content *)c; |
return webp->bitmap; |
} |
static content_type webp_content_type(void) |
{ |
return CONTENT_IMAGE; |
} |
static const content_handler webp_content_handler = { |
.create = webp_create, |
.data_complete = webp_convert, |
.destroy = webp_destroy, |
.redraw = webp_redraw, |
.clone = webp_clone, |
.get_internal = webp_get_internal, |
.type = webp_content_type, |
.no_share = false, |
}; |
static const char *webp_types[] = { |
"image/webp" |
}; |
CONTENT_FACTORY_REGISTER_TYPES(webp, webp_types, webp_content_handler); |
/contrib/network/netsurf/netsurf/image/webp.h |
---|
0,0 → 1,28 |
/* |
* Copyright 2010 Chris Young <chris@unsatisfactorysoftware.co.uk> |
* |
* This file is part of NetSurf, http://www.netsurf-browser.org/ |
* |
* NetSurf is free software; you can redistribute it and/or modify |
* it under the terms of the GNU General Public License as published by |
* the Free Software Foundation; version 2 of the License. |
* |
* NetSurf 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 General Public License for more details. |
* |
* You should have received a copy of the GNU General Public License |
* along with this program. If not, see <http://www.gnu.org/licenses/>. |
*/ |
/** \file |
* Content for image/webp (libwebp interface). |
*/ |
#ifndef _NETSURF_WEBP_H_ |
#define _NETSURF_WEBP_H_ |
nserror webp_init(void); |
#endif |