Most of a stop implementation.
Remaining work: 1) Clone content_html_data 2) Cloning content_css_data requires the charset of the old content 3) Calling hlcache_handle_abort() before a content has been created must clean up the retrieval context. svn path=/trunk/netsurf/; revision=10236
This commit is contained in:
parent
3daffe3d6b
commit
79ce683b4e
|
@ -267,6 +267,7 @@ struct handler_entry {
|
|||
struct box *box,
|
||||
struct object_params *params);
|
||||
void (*close)(struct content *c);
|
||||
bool (*clone)(const struct content *old, struct content *new_content);
|
||||
/** There must be one content per user for this type. */
|
||||
bool no_share;
|
||||
};
|
||||
|
@ -275,83 +276,87 @@ struct handler_entry {
|
|||
static const struct handler_entry handler_map[] = {
|
||||
{html_create, html_process_data, html_convert,
|
||||
html_reformat, html_destroy, html_stop, html_redraw, 0,
|
||||
html_open, html_close,
|
||||
html_open, html_close, html_clone,
|
||||
true},
|
||||
{textplain_create, textplain_process_data, textplain_convert,
|
||||
textplain_reformat, textplain_destroy, 0, textplain_redraw, 0,
|
||||
0, 0, true},
|
||||
0, 0, textplain_clone, true},
|
||||
{nscss_create, nscss_process_data, nscss_convert, 0, nscss_destroy,
|
||||
0, 0, 0, 0, 0, true},
|
||||
0, 0, 0, 0, 0, nscss_clone, true},
|
||||
#ifdef WITH_JPEG
|
||||
{0, 0, nsjpeg_convert, 0, nsjpeg_destroy, 0,
|
||||
nsjpeg_redraw, nsjpeg_redraw_tiled, 0, 0, false},
|
||||
nsjpeg_redraw, nsjpeg_redraw_tiled, 0, 0, nsjpeg_clone, false},
|
||||
#endif
|
||||
#ifdef WITH_GIF
|
||||
{nsgif_create, 0, nsgif_convert, 0, nsgif_destroy, 0,
|
||||
nsgif_redraw, nsgif_redraw_tiled, 0, 0, false},
|
||||
nsgif_redraw, nsgif_redraw_tiled, 0, 0, nsgif_clone, false},
|
||||
#endif
|
||||
#ifdef WITH_BMP
|
||||
{nsbmp_create, 0, nsbmp_convert, 0, nsbmp_destroy, 0,
|
||||
nsbmp_redraw, nsbmp_redraw_tiled, 0, 0, false},
|
||||
nsbmp_redraw, nsbmp_redraw_tiled, 0, 0, nsbmp_clone, false},
|
||||
{nsico_create, 0, nsico_convert, 0, nsico_destroy, 0,
|
||||
nsico_redraw, nsico_redraw_tiled, 0, 0, false},
|
||||
nsico_redraw, nsico_redraw_tiled, 0, 0, nsico_clone, false},
|
||||
#endif
|
||||
|
||||
#ifdef WITH_PNG
|
||||
{nspng_create, nspng_process_data, nspng_convert,
|
||||
0, nspng_destroy, 0, nspng_redraw, nspng_redraw_tiled,
|
||||
0, 0, false},
|
||||
0, 0, nspng_clone, false},
|
||||
#else
|
||||
#ifdef WITH_MNG
|
||||
{nsmng_create, nsmng_process_data, nsmng_convert,
|
||||
0, nsmng_destroy, 0, nsmng_redraw, nsmng_redraw_tiled,
|
||||
0, 0, false},
|
||||
0, 0, nsmng_clone, false},
|
||||
#endif
|
||||
#endif
|
||||
#ifdef WITH_MNG
|
||||
{nsmng_create, nsmng_process_data, nsmng_convert,
|
||||
0, nsmng_destroy, 0, nsmng_redraw, nsmng_redraw_tiled,
|
||||
0, 0, false},
|
||||
0, 0, nsmng_clone, false},
|
||||
{nsmng_create, nsmng_process_data, nsmng_convert,
|
||||
0, nsmng_destroy, 0, nsmng_redraw, nsmng_redraw_tiled,
|
||||
0, 0, false},
|
||||
0, 0, nsmng_clone, false},
|
||||
#endif
|
||||
#ifdef WITH_SPRITE
|
||||
{0, 0, sprite_convert,
|
||||
0, sprite_destroy, 0, sprite_redraw, 0, 0, 0, false},
|
||||
0, sprite_destroy, 0, sprite_redraw, 0,
|
||||
0, 0, sprite_clone, false},
|
||||
#endif
|
||||
#ifdef WITH_NSSPRITE
|
||||
{0, 0, nssprite_convert,
|
||||
0, nssprite_destroy, 0, nssprite_redraw, 0, 0, 0, false},
|
||||
0, nssprite_destroy, 0, nssprite_redraw, 0,
|
||||
0, 0, nssprite_clone, false},
|
||||
#endif
|
||||
#ifdef WITH_DRAW
|
||||
{0, 0, draw_convert,
|
||||
0, draw_destroy, 0, draw_redraw, 0, 0, 0, false},
|
||||
0, draw_destroy, 0, draw_redraw, 0, 0, 0, draw_clone, false},
|
||||
#endif
|
||||
#ifdef WITH_PLUGIN
|
||||
{plugin_create, 0, plugin_convert,
|
||||
plugin_reformat, plugin_destroy, 0, plugin_redraw, 0,
|
||||
plugin_open, plugin_close,
|
||||
plugin_open, plugin_close, plugin_clone,
|
||||
true},
|
||||
#endif
|
||||
{directory_create, 0, directory_convert,
|
||||
0, directory_destroy, 0, 0, 0, 0, 0, true},
|
||||
0, directory_destroy, 0, 0, 0, 0, 0, directory_clone, true},
|
||||
#ifdef WITH_THEME_INSTALL
|
||||
{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, false},
|
||||
{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, false},
|
||||
#endif
|
||||
#ifdef WITH_ARTWORKS
|
||||
{0, 0, artworks_convert,
|
||||
0, artworks_destroy, 0, artworks_redraw, 0, 0, 0, false},
|
||||
0, artworks_destroy, 0, artworks_redraw, 0,
|
||||
0, 0, artworks_clone, false},
|
||||
#endif
|
||||
#ifdef WITH_NS_SVG
|
||||
{svg_create, 0, svg_convert,
|
||||
svg_reformat, svg_destroy, 0, svg_redraw, 0, 0, 0, true},
|
||||
svg_reformat, svg_destroy, 0, svg_redraw, 0,
|
||||
0, 0, svg_clone, true},
|
||||
#endif
|
||||
#ifdef WITH_RSVG
|
||||
{rsvg_create, rsvg_process_data, rsvg_convert,
|
||||
0, rsvg_destroy, 0, rsvg_redraw, 0, 0, 0, false},
|
||||
0, rsvg_destroy, 0, rsvg_redraw, 0, 0, 0, rsvg_clone, false},
|
||||
#endif
|
||||
{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, false}
|
||||
{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, false}
|
||||
};
|
||||
#define HANDLER_MAP_COUNT (sizeof(handler_map) / sizeof(handler_map[0]))
|
||||
|
||||
|
@ -938,6 +943,22 @@ void content_remove_user(struct content *c,
|
|||
talloc_free(next);
|
||||
}
|
||||
|
||||
/**
|
||||
* Count users for the content.
|
||||
*/
|
||||
|
||||
uint32_t content_count_users(struct content *c)
|
||||
{
|
||||
struct content_user *user;
|
||||
uint32_t counter = 0;
|
||||
|
||||
assert(c != NULL);
|
||||
|
||||
for (user = c->user_list; user != NULL; user = user->next)
|
||||
counter += 1;
|
||||
|
||||
return counter - 1; /* Subtract 1 for the sentinel */
|
||||
}
|
||||
|
||||
/**
|
||||
* Send a message to all users.
|
||||
|
@ -957,39 +978,6 @@ void content_broadcast(struct content *c, content_msg msg,
|
|||
}
|
||||
|
||||
|
||||
/**
|
||||
* Stop a content loading.
|
||||
*
|
||||
* May only be called in CONTENT_STATUS_READY only. If all users have requested
|
||||
* stop, the loading is stopped and the content placed in CONTENT_STATUS_DONE.
|
||||
*/
|
||||
|
||||
void content_stop(hlcache_handle *h,
|
||||
void (*callback)(struct content *c, content_msg msg,
|
||||
union content_msg_data data, void *pw),
|
||||
void *pw)
|
||||
{
|
||||
//newcache
|
||||
#if 0
|
||||
struct content_user *user;
|
||||
|
||||
assert(c->status == CONTENT_STATUS_READY);
|
||||
|
||||
user = content_find_user(c, callback, p1, p2);
|
||||
if (!user) {
|
||||
LOG(("user not found in list"));
|
||||
assert(0);
|
||||
return;
|
||||
}
|
||||
|
||||
LOG(("%p %s: stop user %p 0x%" PRIxPTR " 0x%" PRIxPTR,
|
||||
c, llcache_handle_get_url(c->llcache),
|
||||
callback, p1, p2));
|
||||
user->stop = true;
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* A window containing the content has been opened.
|
||||
*
|
||||
|
@ -1308,6 +1296,118 @@ const llcache_handle *content_get_llcache_handle(struct content *c)
|
|||
return c->llcache;
|
||||
}
|
||||
|
||||
/**
|
||||
* Clone a content object in its current state.
|
||||
*
|
||||
* \param c Content to clone
|
||||
* \return Clone of \a c
|
||||
*/
|
||||
struct content *content_clone(struct content *c)
|
||||
{
|
||||
struct content *nc = talloc_zero(0, struct content);
|
||||
|
||||
if (nc == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (llcache_handle_clone(c->llcache, &(nc->llcache)) != NSERROR_OK) {
|
||||
content_destroy(nc);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
llcache_handle_change_callback(nc->llcache,
|
||||
content_llcache_callback, nc);
|
||||
|
||||
nc->type = c->type;
|
||||
|
||||
if (c->mime_type != NULL) {
|
||||
nc->mime_type = talloc_strdup(nc, c->mime_type);
|
||||
if (nc->mime_type == NULL) {
|
||||
content_destroy(nc);
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
nc->status = c->status;
|
||||
|
||||
nc->width = c->width;
|
||||
nc->height = c->height;
|
||||
nc->available_width = c->available_width;
|
||||
nc->quirks = c->quirks;
|
||||
|
||||
if (c->fallback_charset != NULL) {
|
||||
nc->fallback_charset = talloc_strdup(nc, c->fallback_charset);
|
||||
if (nc->fallback_charset == NULL) {
|
||||
content_destroy(nc);
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
if (c->refresh != NULL) {
|
||||
nc->refresh = talloc_strdup(nc, c->refresh);
|
||||
if (nc->refresh == NULL) {
|
||||
content_destroy(nc);
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
nc->fresh = c->fresh;
|
||||
nc->time = c->time;
|
||||
nc->reformat_time = c->reformat_time;
|
||||
nc->size = c->size;
|
||||
nc->talloc_size = c->talloc_size;
|
||||
|
||||
if (c->title != NULL) {
|
||||
nc->title = talloc_strdup(nc, c->title);
|
||||
if (nc->title == NULL) {
|
||||
content_destroy(nc);
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
nc->active = c->active;
|
||||
|
||||
memcpy(&(nc->status_message), &(c->status_message), 120);
|
||||
memcpy(&(nc->sub_status), &(c->sub_status), 80);
|
||||
|
||||
nc->locked = c->locked;
|
||||
nc->total_size = c->total_size;
|
||||
nc->http_code = c->http_code;
|
||||
|
||||
/* Duplicate the data member (and bitmap, if appropriate) */
|
||||
if (handler_map[nc->type].clone != NULL) {
|
||||
if (handler_map[nc->type].clone(c, nc) == false) {
|
||||
content_destroy(nc);
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
return nc;
|
||||
}
|
||||
|
||||
/**
|
||||
* Abort a content object
|
||||
*
|
||||
* \param c The content object to abort
|
||||
* \return NSERROR_OK on success, otherwise appropriate error
|
||||
*/
|
||||
nserror content_abort(struct content *c)
|
||||
{
|
||||
LOG(("Aborting %p", c));
|
||||
|
||||
if (c->status == CONTENT_STATUS_READY) {
|
||||
switch (c->type) {
|
||||
case CONTENT_HTML:
|
||||
html_stop(c);
|
||||
break;
|
||||
default:
|
||||
LOG(("Unable to abort sub-parts for type %d", c->type));
|
||||
}
|
||||
}
|
||||
|
||||
/* And for now, abort our llcache object */
|
||||
return llcache_handle_abort(c->llcache);
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert a content into a download
|
||||
|
|
|
@ -29,6 +29,7 @@
|
|||
#include <stdbool.h>
|
||||
|
||||
#include "utils/config.h"
|
||||
#include "utils/errors.h"
|
||||
#include "content/content_type.h"
|
||||
#include "desktop/plot_style.h"
|
||||
|
||||
|
@ -112,8 +113,13 @@ void content_remove_user(struct content *c,
|
|||
union content_msg_data data, void *pw),
|
||||
void *pw);
|
||||
|
||||
uint32_t content_count_users(struct content *c);
|
||||
|
||||
const struct llcache_handle *content_get_llcache_handle(struct content *c);
|
||||
|
||||
struct content *content_clone(struct content *c);
|
||||
|
||||
nserror content_abort(struct content *c);
|
||||
|
||||
/* Client functions */
|
||||
bool content_can_reformat(struct hlcache_handle *h);
|
||||
|
@ -129,10 +135,6 @@ bool content_redraw_tiled(struct hlcache_handle *h, int x, int y,
|
|||
int clip_x0, int clip_y0, int clip_x1, int clip_y1,
|
||||
float scale, colour background_colour,
|
||||
bool repeat_x, bool repeat_y);
|
||||
void content_stop(struct hlcache_handle *h,
|
||||
void (*callback)(struct content *c, content_msg msg,
|
||||
union content_msg_data data, void *pw),
|
||||
void *pw);
|
||||
void content_open(struct hlcache_handle *h, struct browser_window *bw,
|
||||
struct content *page, unsigned int index, struct box *box,
|
||||
struct object_params *params);
|
||||
|
|
|
@ -141,6 +141,61 @@ struct content *hlcache_handle_get_content(const hlcache_handle *handle)
|
|||
return NULL;
|
||||
}
|
||||
|
||||
/* See hlcache.h for documentation */
|
||||
nserror hlcache_handle_abort(hlcache_handle *handle)
|
||||
{
|
||||
struct hlcache_entry *entry = handle->entry;
|
||||
struct content *c;
|
||||
|
||||
if (entry == NULL) {
|
||||
/* This handle is not yet associated with a cache entry.
|
||||
* The implication is that the fetch for the handle has
|
||||
* not progressed to the point where the entry can be
|
||||
* created. */
|
||||
/** \todo Find retrieval context and abort llcache handle */
|
||||
|
||||
return NSERROR_OK;
|
||||
}
|
||||
|
||||
c = entry->content;
|
||||
|
||||
if (content_count_users(c) > 1) {
|
||||
/* We are not the only user of 'c' so clone it. */
|
||||
struct content *clone = content_clone(c);
|
||||
|
||||
if (clone == NULL)
|
||||
return NSERROR_NOMEM;
|
||||
|
||||
entry = calloc(sizeof(struct hlcache_entry), 1);
|
||||
|
||||
if (entry == NULL) {
|
||||
content_destroy(clone);
|
||||
return NSERROR_NOMEM;
|
||||
}
|
||||
|
||||
if (content_add_user(clone,
|
||||
hlcache_content_callback, handle) == false) {
|
||||
content_destroy(clone);
|
||||
free(entry);
|
||||
return NSERROR_NOMEM;
|
||||
}
|
||||
|
||||
content_remove_user(c, hlcache_content_callback, handle);
|
||||
|
||||
entry->content = clone;
|
||||
handle->entry = entry;
|
||||
entry->prev = NULL;
|
||||
entry->next = hlcache_content_list;
|
||||
if (hlcache_content_list != NULL)
|
||||
hlcache_content_list->prev = entry;
|
||||
hlcache_content_list = entry;
|
||||
|
||||
c = clone;
|
||||
}
|
||||
|
||||
return content_abort(c);
|
||||
}
|
||||
|
||||
/******************************************************************************
|
||||
* High-level cache internals *
|
||||
******************************************************************************/
|
||||
|
@ -309,13 +364,14 @@ void hlcache_content_callback(struct content *c, content_msg msg,
|
|||
{
|
||||
hlcache_handle *handle = pw;
|
||||
hlcache_event event;
|
||||
nserror error;
|
||||
nserror error = NSERROR_OK;
|
||||
|
||||
event.type = msg;
|
||||
event.data = data;
|
||||
|
||||
|
||||
error = handle->cb(handle, &event, handle->pw);
|
||||
if (handle->cb != NULL)
|
||||
error = handle->cb(handle, &event, handle->pw);
|
||||
|
||||
if (error != NSERROR_OK)
|
||||
LOG(("Error in callback: %d", error));
|
||||
}
|
||||
|
|
|
@ -87,6 +87,14 @@ nserror hlcache_handle_retrieve(const char *url, uint32_t flags,
|
|||
*/
|
||||
nserror hlcache_handle_release(hlcache_handle *handle);
|
||||
|
||||
/**
|
||||
* Abort a high-level cache fetch
|
||||
*
|
||||
* \param handle Handle to abort
|
||||
* \return NSERROR_OK on success, appropriate error otherwise
|
||||
*/
|
||||
nserror hlcache_handle_abort(hlcache_handle *handle);
|
||||
|
||||
/**
|
||||
* Retrieve a content object from a cache handle
|
||||
*
|
||||
|
|
|
@ -172,6 +172,9 @@ static nserror llcache_object_remove_from_list(llcache_object *object,
|
|||
|
||||
static nserror llcache_object_notify_users(llcache_object *object);
|
||||
|
||||
static nserror llcache_object_snapshot(llcache_object *object,
|
||||
llcache_object **snapshot);
|
||||
|
||||
static nserror llcache_clean(void);
|
||||
|
||||
static nserror llcache_post_data_clone(const llcache_post_data *orig,
|
||||
|
@ -301,6 +304,66 @@ nserror llcache_handle_release(llcache_handle *handle)
|
|||
return error;
|
||||
}
|
||||
|
||||
/* See llcache.h for documentation */
|
||||
nserror llcache_handle_clone(llcache_handle *handle, llcache_handle **result)
|
||||
{
|
||||
nserror error;
|
||||
llcache_object_user *newuser;
|
||||
|
||||
error = llcache_object_user_new(handle->cb, handle->pw, &newuser);
|
||||
if (error == NSERROR_OK) {
|
||||
llcache_object_add_user(handle->object, newuser);
|
||||
newuser->handle.state = handle->state;
|
||||
*result = &newuser->handle;
|
||||
}
|
||||
|
||||
return error;
|
||||
}
|
||||
|
||||
/* See llcache.h for documentation */
|
||||
nserror llcache_handle_abort(llcache_handle *handle)
|
||||
{
|
||||
llcache_object_user *user = (llcache_object_user *) handle;
|
||||
llcache_object *object = handle->object, *newobject;
|
||||
nserror error = NSERROR_OK;
|
||||
bool all_alone = true;
|
||||
|
||||
/* Determine if we are the only user */
|
||||
if (user->prev != NULL)
|
||||
all_alone = false;
|
||||
if (user->next != NULL)
|
||||
all_alone = false;
|
||||
|
||||
if (all_alone == false) {
|
||||
/* We must snapshot this object */
|
||||
error = llcache_object_snapshot(object, &newobject);
|
||||
if (error != NSERROR_OK)
|
||||
return error;
|
||||
/* Move across to the new object */
|
||||
llcache_object_remove_user(object, user);
|
||||
llcache_object_add_user(newobject, user);
|
||||
|
||||
/* Add new object to uncached list */
|
||||
llcache_object_add_to_list(object, &llcache_uncached_objects);
|
||||
|
||||
/* And use it from now on. */
|
||||
object = newobject;
|
||||
} else {
|
||||
/* We're the only user, so abort any fetch in progress */
|
||||
if (object->fetch.fetch != NULL) {
|
||||
fetch_abort(object->fetch.fetch);
|
||||
object->fetch.fetch = NULL;
|
||||
}
|
||||
|
||||
object->fetch.state = LLCACHE_FETCH_COMPLETE;
|
||||
|
||||
/* Invalidate cache control data */
|
||||
memset(&(object->cache), 0, sizeof(llcache_cache_control));
|
||||
}
|
||||
|
||||
return error;
|
||||
}
|
||||
|
||||
/* See llcache.h for documentation */
|
||||
const char *llcache_handle_get_url(const llcache_handle *handle)
|
||||
{
|
||||
|
@ -1033,8 +1096,7 @@ nserror llcache_object_notify_users(llcache_object *object)
|
|||
for (user = object->users; user != NULL; user = next_user) {
|
||||
/* Emit necessary events to bring the user up-to-date */
|
||||
llcache_handle *handle = &user->handle;
|
||||
llcache_fetch_state hstate = handle->state;
|
||||
llcache_fetch_state objstate = object->fetch.state;
|
||||
const llcache_fetch_state objstate = object->fetch.state;
|
||||
|
||||
/* Save identity of next user in case client destroys
|
||||
* the user underneath us */
|
||||
|
@ -1042,20 +1104,22 @@ nserror llcache_object_notify_users(llcache_object *object)
|
|||
next_user = user->next;
|
||||
|
||||
#ifdef LLCACHE_TRACE
|
||||
if (hstate != objstate)
|
||||
if (handle->state != objstate)
|
||||
LOG(("User %p state: %d Object state: %d",
|
||||
user, hstate, objstate));
|
||||
user, handle->state, objstate));
|
||||
#endif
|
||||
|
||||
/* User: INIT, Obj: HEADERS, DATA, COMPLETE => User->HEADERS */
|
||||
if (hstate == LLCACHE_FETCH_INIT &&
|
||||
if (handle->state == LLCACHE_FETCH_INIT &&
|
||||
objstate > LLCACHE_FETCH_INIT) {
|
||||
hstate = LLCACHE_FETCH_HEADERS;
|
||||
handle->state = LLCACHE_FETCH_HEADERS;
|
||||
}
|
||||
|
||||
/* User: HEADERS, Obj: DATA, COMPLETE => User->DATA */
|
||||
if (hstate == LLCACHE_FETCH_HEADERS &&
|
||||
if (handle->state == LLCACHE_FETCH_HEADERS &&
|
||||
objstate > LLCACHE_FETCH_HEADERS) {
|
||||
handle->state = LLCACHE_FETCH_DATA;
|
||||
|
||||
/* Emit HAD_HEADERS event */
|
||||
event.type = LLCACHE_EVENT_HAD_HEADERS;
|
||||
|
||||
|
@ -1069,20 +1133,21 @@ nserror llcache_object_notify_users(llcache_object *object)
|
|||
llcache_object_user_destroy(user);
|
||||
continue;
|
||||
}
|
||||
|
||||
hstate = LLCACHE_FETCH_DATA;
|
||||
}
|
||||
|
||||
/* User: DATA, Obj: DATA, COMPLETE, more source available */
|
||||
if (hstate == LLCACHE_FETCH_DATA &&
|
||||
if (handle->state == LLCACHE_FETCH_DATA &&
|
||||
objstate >= LLCACHE_FETCH_DATA &&
|
||||
object->source_len > handle->bytes) {
|
||||
size_t oldbytes = handle->bytes;
|
||||
|
||||
/* Update record of last byte emitted */
|
||||
handle->bytes = object->source_len;
|
||||
|
||||
/* Emit HAD_DATA event */
|
||||
event.type = LLCACHE_EVENT_HAD_DATA;
|
||||
event.data.data.buf =
|
||||
object->source_data + handle->bytes;
|
||||
event.data.data.len =
|
||||
object->source_len - handle->bytes;
|
||||
event.data.data.buf = object->source_data + oldbytes;
|
||||
event.data.data.len = object->source_len - oldbytes;
|
||||
|
||||
error = handle->cb(handle, &event, handle->pw);
|
||||
if (error != NSERROR_OK) {
|
||||
|
@ -1094,14 +1159,13 @@ nserror llcache_object_notify_users(llcache_object *object)
|
|||
llcache_object_user_destroy(user);
|
||||
continue;
|
||||
}
|
||||
|
||||
/* Update record of last byte emitted */
|
||||
handle->bytes = object->source_len;
|
||||
}
|
||||
|
||||
/* User: DATA, Obj: COMPLETE => User->COMPLETE */
|
||||
if (hstate == LLCACHE_FETCH_DATA &&
|
||||
if (handle->state == LLCACHE_FETCH_DATA &&
|
||||
objstate > LLCACHE_FETCH_DATA) {
|
||||
handle->state = LLCACHE_FETCH_COMPLETE;
|
||||
|
||||
/* Emit DONE event */
|
||||
event.type = LLCACHE_EVENT_DONE;
|
||||
|
||||
|
@ -1115,20 +1179,79 @@ nserror llcache_object_notify_users(llcache_object *object)
|
|||
llcache_object_user_destroy(user);
|
||||
continue;
|
||||
}
|
||||
|
||||
hstate = LLCACHE_FETCH_COMPLETE;
|
||||
}
|
||||
|
||||
/* No longer the target of an iterator */
|
||||
user->iterator_target = false;
|
||||
|
||||
/* Sync handle's state with reality */
|
||||
handle->state = hstate;
|
||||
}
|
||||
|
||||
return NSERROR_OK;
|
||||
}
|
||||
|
||||
/**
|
||||
* Make a snapshot of the current state of an llcache_object.
|
||||
*
|
||||
* This has the side-effect of the new object being non-cacheable,
|
||||
* also not-fetching and not a candidate for any other object.
|
||||
*
|
||||
* Also note that this new object has no users and at least one
|
||||
* should be assigned to it before llcache_clean is entered or it
|
||||
* will be immediately cleaned up.
|
||||
*
|
||||
* \param object The object to take a snapshot of
|
||||
* \param snapshot Pointer to receive snapshot of \a object
|
||||
* \return NSERROR_OK on success, appropriate error otherwise
|
||||
*/
|
||||
nserror llcache_object_snapshot(llcache_object *object,
|
||||
llcache_object **snapshot)
|
||||
{
|
||||
llcache_object *newobj;
|
||||
nserror error;
|
||||
|
||||
error = llcache_object_new(object->url, &newobj);
|
||||
|
||||
if (error != NSERROR_OK)
|
||||
return error;
|
||||
|
||||
newobj->has_query = object->has_query;
|
||||
|
||||
newobj->source_alloc = newobj->source_len = object->source_len;
|
||||
|
||||
if (object->source_len > 0) {
|
||||
newobj->source_data = malloc(newobj->source_alloc);
|
||||
if (newobj->source_data == NULL) {
|
||||
llcache_object_destroy(newobj);
|
||||
return NSERROR_NOMEM;
|
||||
}
|
||||
memcpy(newobj->source_data, object->source_data, newobj->source_len);
|
||||
}
|
||||
|
||||
if (object->num_headers > 0) {
|
||||
newobj->headers = calloc(sizeof(llcache_header), object->num_headers);
|
||||
if (newobj->headers == NULL) {
|
||||
llcache_object_destroy(newobj);
|
||||
return NSERROR_NOMEM;
|
||||
}
|
||||
while (newobj->num_headers < object->num_headers) {
|
||||
llcache_header *nh = &(newobj->headers[newobj->num_headers]);
|
||||
llcache_header *oh = &(object->headers[newobj->num_headers]);
|
||||
newobj->num_headers += 1;
|
||||
nh->name = strdup(oh->name);
|
||||
nh->value = strdup(oh->value);
|
||||
if (nh->name == NULL || nh->value == NULL) {
|
||||
llcache_object_destroy(newobj);
|
||||
return NSERROR_NOMEM;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
newobj->fetch.state = LLCACHE_FETCH_COMPLETE;
|
||||
|
||||
*snapshot = newobj;
|
||||
|
||||
return NSERROR_OK;
|
||||
}
|
||||
|
||||
/**
|
||||
* Attempt to clean the cache
|
||||
*
|
||||
|
@ -1376,16 +1499,6 @@ void llcache_fetch_callback(fetch_msg msg, void *p, const void *data,
|
|||
}
|
||||
return;
|
||||
}
|
||||
|
||||
/* Keep users in sync with reality */
|
||||
error = llcache_object_notify_users(object);
|
||||
if (error != NSERROR_OK) {
|
||||
/** \todo Error handling */
|
||||
if (object->fetch.fetch != NULL) {
|
||||
fetch_abort(object->fetch.fetch);
|
||||
object->fetch.fetch = NULL;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -200,6 +200,24 @@ nserror llcache_handle_change_callback(llcache_handle *handle,
|
|||
*/
|
||||
nserror llcache_handle_release(llcache_handle *handle);
|
||||
|
||||
/**
|
||||
* Clone a low-level cache handle, producing a new handle to
|
||||
* the same fetch/content.
|
||||
*
|
||||
* \param handle Handle to clone
|
||||
* \param result Pointer to location to receive cloned handle
|
||||
* \return NSERROR_OK on success, appropriate error otherwise
|
||||
*/
|
||||
nserror llcache_handle_clone(llcache_handle *handle, llcache_handle **result);
|
||||
|
||||
/**
|
||||
* Abort a low-level fetch, informing all users of this action.
|
||||
*
|
||||
* \param handle Handle to abort
|
||||
* \return NSERROR_OK on success, appropriate error otherwise
|
||||
*/
|
||||
nserror llcache_handle_abort(llcache_handle *handle);
|
||||
|
||||
/**
|
||||
* Retrieve the post-redirect URL of a low-level cache object
|
||||
*
|
||||
|
|
27
css/css.c
27
css/css.c
|
@ -326,6 +326,33 @@ void nscss_destroy_css_data(struct content_css_data *c)
|
|||
}
|
||||
}
|
||||
|
||||
bool nscss_clone(const struct content *old, struct content *new_content)
|
||||
{
|
||||
const char *data;
|
||||
unsigned long size;
|
||||
|
||||
/* Simply replay create/process/convert */
|
||||
/** \todo We need the charset of the old sheet */
|
||||
if (nscss_create_css_data(&new_content->data.css,
|
||||
content__get_url(new_content),
|
||||
NULL, new_content->quirks) != NSERROR_OK)
|
||||
return false;
|
||||
|
||||
data = content__get_source_data(new_content, &size);
|
||||
if (size > 0) {
|
||||
if (nscss_process_data(new_content, data, size) == false)
|
||||
return false;
|
||||
}
|
||||
|
||||
if (old->status == CONTENT_STATUS_READY ||
|
||||
old->status == CONTENT_STATUS_DONE) {
|
||||
if (nscss_convert(new_content) == false)
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve imported stylesheets
|
||||
*
|
||||
|
|
|
@ -57,6 +57,8 @@ bool nscss_convert(struct content *c);
|
|||
|
||||
void nscss_destroy(struct content *c);
|
||||
|
||||
bool nscss_clone(const struct content *old, struct content *new_content);
|
||||
|
||||
nserror nscss_create_css_data(struct content_css_data *c,
|
||||
const char *url, const char *charset, bool quirks);
|
||||
css_error nscss_process_css_data(struct content_css_data *c, const char *data,
|
||||
|
|
|
@ -811,16 +811,18 @@ void browser_window_stop(struct browser_window *bw)
|
|||
int children, index;
|
||||
|
||||
if (bw->loading_content != NULL) {
|
||||
hlcache_handle_abort(bw->loading_content);
|
||||
hlcache_handle_release(bw->loading_content);
|
||||
bw->loading_content = NULL;
|
||||
}
|
||||
|
||||
if (bw->current_content != NULL && content_get_status(
|
||||
bw->current_content) != CONTENT_STATUS_DONE) {
|
||||
nserror error;
|
||||
assert(content_get_status(bw->current_content) ==
|
||||
CONTENT_STATUS_READY);
|
||||
content_stop(bw->current_content,
|
||||
browser_window_callback, bw);
|
||||
error = hlcache_handle_abort(bw->current_content);
|
||||
assert(error == NSERROR_OK);
|
||||
}
|
||||
|
||||
schedule_remove(browser_window_refresh, bw);
|
||||
|
|
17
image/bmp.c
17
image/bmp.c
|
@ -162,6 +162,23 @@ void nsbmp_destroy(struct content *c)
|
|||
}
|
||||
|
||||
|
||||
|
||||
bool nsbmp_clone(const struct content *old, struct content *new_content)
|
||||
{
|
||||
/* We "clone" the old content by replaying creation and conversion */
|
||||
if (nsbmp_create(new_content, NULL) == false)
|
||||
return false;
|
||||
|
||||
if (old->status == CONTENT_STATUS_READY ||
|
||||
old->status == CONTENT_STATUS_DONE) {
|
||||
if (nsbmp_convert(new_content) == false)
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Callback for libnsbmp; forwards the call to bitmap_create()
|
||||
*
|
||||
|
|
|
@ -53,6 +53,7 @@ bool nsbmp_redraw_tiled(struct content *c, int x, int y,
|
|||
int clip_x0, int clip_y0, int clip_x1, int clip_y1,
|
||||
float scale, colour background_colour,
|
||||
bool repeat_x, bool repeat_y);
|
||||
bool nsbmp_clone(const struct content *old, struct content *new_content);
|
||||
void *nsbmp_bitmap_create(int width, int height, unsigned int bmp_state);
|
||||
|
||||
#endif /* WITH_BMP */
|
||||
|
|
16
image/gif.c
16
image/gif.c
|
@ -197,6 +197,22 @@ void nsgif_destroy(struct content *c)
|
|||
}
|
||||
|
||||
|
||||
bool nsgif_clone(const struct content *old, struct content *new_content)
|
||||
{
|
||||
/* Simply replay creation and conversion of content */
|
||||
if (nsgif_create(new_content, NULL) == false)
|
||||
return false;
|
||||
|
||||
if (old->status == CONTENT_STATUS_READY ||
|
||||
old->status == CONTENT_STATUS_DONE) {
|
||||
if (nsgif_convert(new_content) == false)
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Updates the GIF bitmap to display the current frame
|
||||
*
|
||||
|
|
|
@ -50,6 +50,7 @@ bool nsgif_redraw_tiled(struct content *c, int x, int y,
|
|||
int clip_x0, int clip_y0, int clip_x1, int clip_y1,
|
||||
float scale, colour background_colour,
|
||||
bool repeat_x, bool repeat_y);
|
||||
bool nsgif_clone(const struct content *old, struct content *new_content);
|
||||
void *nsgif_bitmap_create(int width, int height);
|
||||
|
||||
#endif /* WITH_GIF */
|
||||
|
|
15
image/ico.c
15
image/ico.c
|
@ -169,4 +169,19 @@ void nsico_destroy(struct content *c)
|
|||
free(c->data.ico.ico);
|
||||
}
|
||||
|
||||
bool nsico_clone(const struct content *old, struct content *new_content)
|
||||
{
|
||||
/* Simply replay creation and conversion */
|
||||
if (nsico_create(new_content, NULL) == false)
|
||||
return false;
|
||||
|
||||
if (old->status == CONTENT_STATUS_READY ||
|
||||
old->status == CONTENT_STATUS_DONE) {
|
||||
if (nsico_convert(new_content) == false)
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
|
@ -49,6 +49,7 @@ bool nsico_redraw_tiled(struct content *c, int x, int y,
|
|||
int clip_x0, int clip_y0, int clip_x1, int clip_y1,
|
||||
float scale, colour background_colour,
|
||||
bool repeat_x, bool repeat_y);
|
||||
bool nsico_clone(const struct content *old, struct content *new_content);
|
||||
bool nsico_set_bitmap_from_size(struct hlcache_handle *h,
|
||||
int width, int height);
|
||||
|
||||
|
|
13
image/jpeg.c
13
image/jpeg.c
|
@ -286,4 +286,17 @@ void nsjpeg_destroy(struct content *c)
|
|||
bitmap_destroy(c->bitmap);
|
||||
}
|
||||
|
||||
|
||||
bool nsjpeg_clone(const struct content *old, struct content *new_content)
|
||||
{
|
||||
/* Simply replay conversion */
|
||||
if (old->status == CONTENT_STATUS_READY ||
|
||||
old->status == CONTENT_STATUS_DONE) {
|
||||
if (nsjpeg_convert(new_content) == false)
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
#endif /* WITH_JPEG */
|
||||
|
|
|
@ -46,6 +46,7 @@ bool nsjpeg_redraw_tiled(struct content *c, int x, int y,
|
|||
int clip_x0, int clip_y0, int clip_x1, int clip_y1,
|
||||
float scale, colour background_colour,
|
||||
bool repeat_x, bool repeat_y);
|
||||
bool nsjpeg_clone(const struct content *old, struct content *new_content);
|
||||
|
||||
#endif /* WITH_JPEG */
|
||||
|
||||
|
|
25
image/mng.c
25
image/mng.c
|
@ -585,6 +585,31 @@ bool nsmng_redraw_tiled(struct content *c, int x, int y,
|
|||
return ret;
|
||||
}
|
||||
|
||||
|
||||
bool nsmng_clone(const struct content *old, struct content *new_content)
|
||||
{
|
||||
const char *data;
|
||||
unsigned long size;
|
||||
|
||||
/* Simply replay create/process/convert */
|
||||
if (nsmng_create(new_content, NULL) == false)
|
||||
return false;
|
||||
|
||||
data = content__get_source_data(new_content, &size);
|
||||
if (size > 0) {
|
||||
if (nsmng_process_data(new_content, data, size) == false)
|
||||
return false;
|
||||
}
|
||||
|
||||
if (old->status == CONTENT_STATUS_READY ||
|
||||
old->status == CONTENT_STATUS_DONE) {
|
||||
if (nsmng_convert(new_content) == false)
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Animates to the next frame
|
||||
*/
|
||||
|
|
|
@ -54,6 +54,7 @@ bool nsmng_redraw_tiled(struct content *c, int x, int y,
|
|||
int clip_x0, int clip_y0, int clip_x1, int clip_y1,
|
||||
float scale, colour background_colour,
|
||||
bool repeat_x, bool repeat_y);
|
||||
bool nsmng_clone(const struct content *old, struct content *new_content);
|
||||
|
||||
#endif /* WITH_MNG */
|
||||
|
||||
|
|
|
@ -144,4 +144,17 @@ bool nssprite_redraw(struct content *c, int x, int y,
|
|||
c->bitmap, background_colour, BITMAPF_NONE);
|
||||
}
|
||||
|
||||
|
||||
bool nssprite_clone(const struct content *old, struct content *new_content)
|
||||
{
|
||||
/* Simply replay convert */
|
||||
if (old->status == CONTENT_STATUS_READY ||
|
||||
old->status == CONTENT_STATUS_DONE) {
|
||||
if (nssprite_convert(new_content) == false)
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
|
@ -40,6 +40,7 @@ bool nssprite_redraw(struct content *c, int x, int y,
|
|||
int width, int height,
|
||||
int clip_x0, int clip_y0, int clip_x1, int clip_y1,
|
||||
float scale, colour background_colour);
|
||||
bool nssprite_clone(const struct content *old, struct content *new_content);
|
||||
|
||||
#endif /* WITH_NSSPRITE */
|
||||
|
||||
|
|
24
image/png.c
24
image/png.c
|
@ -326,4 +326,28 @@ bool nspng_redraw_tiled(struct content *c, int x, int y, int width, int height,
|
|||
background_colour, flags);
|
||||
}
|
||||
|
||||
bool nspng_clone(const struct content *old, struct content *new_content)
|
||||
{
|
||||
const char *data;
|
||||
unsigned long size;
|
||||
|
||||
/* Simply replay create/process/convert */
|
||||
if (nspng_create(new_content, NULL) == false)
|
||||
return false;
|
||||
|
||||
data = content__get_source_data(new_content, &size);
|
||||
if (size > 0) {
|
||||
if (nspng_process_data(new_content, data, size) == false)
|
||||
return false;
|
||||
}
|
||||
|
||||
if (old->status == CONTENT_STATUS_READY ||
|
||||
old->status == CONTENT_STATUS_DONE) {
|
||||
if (nspng_convert(new_content) == false)
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
|
@ -54,6 +54,8 @@ bool nspng_redraw_tiled(struct content *c, int x, int y, int width, int height,
|
|||
int clip_x0, int clip_y0, int clip_x1, int clip_y1,
|
||||
float scale, colour background_colour,
|
||||
bool repeat_x, bool repeat_y);
|
||||
bool nspng_clone(const struct content *old, struct content *new_content);
|
||||
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
|
24
image/rsvg.c
24
image/rsvg.c
|
@ -207,4 +207,28 @@ void rsvg_destroy(struct content *c)
|
|||
return;
|
||||
}
|
||||
|
||||
bool rsvg_clone(const struct content *old, struct content *new_content)
|
||||
{
|
||||
const char *data;
|
||||
unsigned long size;
|
||||
|
||||
/* Simply replay create/process/convert */
|
||||
if (rsvg_create(new_content, NULL) == false)
|
||||
return false;
|
||||
|
||||
data = content__get_source_data(new_content, &size);
|
||||
if (size > 0) {
|
||||
if (rsvg_process_data(new_content, data, size) == false)
|
||||
return false;
|
||||
}
|
||||
|
||||
if (old->status == CONTENT_STATUS_READY ||
|
||||
old->status == CONTENT_STATUS_DONE) {
|
||||
if (rsvg_convert(new_content) == false)
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
#endif /* WITH_RSVG */
|
||||
|
|
|
@ -55,6 +55,7 @@ bool rsvg_redraw_tiled(struct content *c, int x, int y,
|
|||
int clip_x0, int clip_y0, int clip_x1, int clip_y1,
|
||||
float scale, colour background_colour,
|
||||
bool repeat_x, bool repeat_y);
|
||||
bool rsvg_clone(const struct content *old, struct content *new_content);
|
||||
|
||||
#endif /* WITH_RSVG */
|
||||
|
||||
|
|
16
image/svg.c
16
image/svg.c
|
@ -177,4 +177,20 @@ void svg_destroy(struct content *c)
|
|||
}
|
||||
|
||||
|
||||
bool svg_clone(const struct content *old, struct content *new_content)
|
||||
{
|
||||
/* Simply replay create/convert */
|
||||
if (svg_create(new_content, NULL) == false)
|
||||
return false;
|
||||
|
||||
if (old->status == CONTENT_STATUS_READY ||
|
||||
old->status == CONTENT_STATUS_DONE) {
|
||||
if (svg_convert(new_content) == false)
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
#endif /* WITH_NS_SVG */
|
||||
|
|
|
@ -42,5 +42,6 @@ bool svg_redraw(struct content *c, int x, int y,
|
|||
int width, int height,
|
||||
int clip_x0, int clip_y0, int clip_x1, int clip_y1,
|
||||
float scale, colour background_colour);
|
||||
bool svg_clone(const struct content *old, struct content *new_content);
|
||||
|
||||
#endif
|
||||
|
|
|
@ -150,3 +150,14 @@ void directory_destroy(struct content *c)
|
|||
|
||||
return;
|
||||
}
|
||||
|
||||
bool directory_clone(const struct content *old, struct content *new_content)
|
||||
{
|
||||
/* This will only get called if the content is cloned before
|
||||
* content_convert() is called. Simply replay creation. */
|
||||
if (directory_create(new_content, NULL) == false)
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
|
@ -33,5 +33,6 @@ struct http_parameter;
|
|||
bool directory_create(struct content *c, const struct http_parameter *params);
|
||||
bool directory_convert(struct content *c);
|
||||
void directory_destroy(struct content *c);
|
||||
bool directory_clone(const struct content *old, struct content *new_content);
|
||||
|
||||
#endif
|
||||
|
|
|
@ -195,9 +195,12 @@ nserror favicon_callback(hlcache_handle *icon,
|
|||
if (*type == CONTENT_UNKNOWN) {
|
||||
union content_msg_data msg_data;
|
||||
|
||||
hlcache_handle_release(c->data.html.favicon);
|
||||
c->data.html.favicon = NULL;
|
||||
LOG(("%s is not a favicon", content_get_url(icon)));
|
||||
|
||||
hlcache_handle_abort(icon);
|
||||
hlcache_handle_release(icon);
|
||||
c->data.html.favicon = NULL;
|
||||
|
||||
content_add_error(c, "NotFavIco", 0);
|
||||
|
||||
msg_data.error = messages_get("NotFavIco");
|
||||
|
|
|
@ -1681,7 +1681,7 @@ void html_stop(struct content *c)
|
|||
if (content_get_status(object) == CONTENT_STATUS_DONE)
|
||||
; /* already loaded: do nothing */
|
||||
else if (content_get_status(object) == CONTENT_STATUS_READY)
|
||||
content_stop(object, html_object_callback, NULL);
|
||||
hlcache_handle_abort(object);
|
||||
else {
|
||||
hlcache_handle_release(object);
|
||||
c->data.html.object[i].content = NULL;
|
||||
|
@ -1847,6 +1847,11 @@ void html_destroy_iframe(struct content_html_iframe *iframe) {
|
|||
}
|
||||
}
|
||||
|
||||
bool html_clone(const struct content *old, struct content *new_content)
|
||||
{
|
||||
/** \todo Clone HTML specifics */
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the content status.
|
||||
|
|
|
@ -190,6 +190,7 @@ bool html_process_data(struct content *c, const char *data, unsigned int size);
|
|||
bool html_convert(struct content *c);
|
||||
void html_reformat(struct content *c, int width, int height);
|
||||
void html_destroy(struct content *c);
|
||||
bool html_clone(const struct content *old, struct content *new_content);
|
||||
bool html_fetch_object(struct content *c, const char *url, struct box *box,
|
||||
const content_type *permitted_types,
|
||||
int available_width, int available_height,
|
||||
|
|
|
@ -65,6 +65,7 @@ static plot_font_style_t textplain_style = {
|
|||
|
||||
static int textplain_tab_width = 256; /* try for a sensible default */
|
||||
|
||||
static bool textplain_create_internal(struct content *c, const char *encoding);
|
||||
static int textplain_coord_from_offset(const char *text, size_t offset,
|
||||
size_t length);
|
||||
static float textplain_line_height(void);
|
||||
|
@ -76,23 +77,29 @@ static float textplain_line_height(void);
|
|||
|
||||
bool textplain_create(struct content *c, const http_parameter *params)
|
||||
{
|
||||
char *utf8_data;
|
||||
const char *encoding;
|
||||
iconv_t iconv_cd;
|
||||
union content_msg_data msg_data;
|
||||
nserror error;
|
||||
|
||||
textplain_style.size = (option_font_size * FONT_SIZE_SCALE) / 10;
|
||||
|
||||
utf8_data = talloc_array(c, char, CHUNK);
|
||||
if (!utf8_data)
|
||||
goto no_memory;
|
||||
|
||||
error = http_parameter_list_find_item(params, "charset", &encoding);
|
||||
if (error != NSERROR_OK) {
|
||||
encoding = "Windows-1252";
|
||||
}
|
||||
|
||||
return textplain_create_internal(c, encoding);
|
||||
}
|
||||
|
||||
bool textplain_create_internal(struct content *c, const char *encoding)
|
||||
{
|
||||
char *utf8_data;
|
||||
iconv_t iconv_cd;
|
||||
union content_msg_data msg_data;
|
||||
|
||||
utf8_data = talloc_array(c, char, CHUNK);
|
||||
if (!utf8_data)
|
||||
goto no_memory;
|
||||
|
||||
iconv_cd = iconv_open("utf-8", encoding);
|
||||
if (iconv_cd == (iconv_t)(-1) && errno == EINVAL) {
|
||||
LOG(("unsupported encoding \"%s\"", encoding));
|
||||
|
@ -110,7 +117,10 @@ bool textplain_create(struct content *c, const http_parameter *params)
|
|||
return false;
|
||||
}
|
||||
|
||||
c->data.textplain.encoding = encoding;
|
||||
c->data.textplain.encoding = strdup(encoding);
|
||||
if (c->data.textplain.encoding == NULL)
|
||||
goto no_memory;
|
||||
|
||||
c->data.textplain.iconv_cd = iconv_cd;
|
||||
c->data.textplain.converted = 0;
|
||||
c->data.textplain.utf8_data = utf8_data;
|
||||
|
@ -310,11 +320,40 @@ no_memory:
|
|||
|
||||
void textplain_destroy(struct content *c)
|
||||
{
|
||||
if (c->data.textplain.encoding != NULL)
|
||||
free(c->data.textplain.encoding);
|
||||
|
||||
if (c->data.textplain.iconv_cd)
|
||||
iconv_close(c->data.textplain.iconv_cd);
|
||||
}
|
||||
|
||||
|
||||
bool textplain_clone(const struct content *old, struct content *new_content)
|
||||
{
|
||||
const char *data;
|
||||
unsigned long size;
|
||||
|
||||
/* Simply replay create/process/convert */
|
||||
if (textplain_create_internal(new_content,
|
||||
old->data.textplain.encoding) == false)
|
||||
return false;
|
||||
|
||||
data = content__get_source_data(new_content, &size);
|
||||
if (size > 0) {
|
||||
if (textplain_process_data(new_content, data, size) == false)
|
||||
return false;
|
||||
}
|
||||
|
||||
if (old->status == CONTENT_STATUS_READY ||
|
||||
old->status == CONTENT_STATUS_DONE) {
|
||||
if (textplain_convert(new_content) == false)
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Draw a CONTENT_TEXTPLAIN using the current set of plotters (plot).
|
||||
*
|
||||
|
|
|
@ -37,7 +37,7 @@ struct textplain_line {
|
|||
};
|
||||
|
||||
struct content_textplain_data {
|
||||
const char *encoding;
|
||||
char *encoding;
|
||||
iconv_t iconv_cd;
|
||||
size_t converted;
|
||||
char *utf8_data;
|
||||
|
@ -58,6 +58,7 @@ bool textplain_redraw(struct content *c, int x, int y,
|
|||
int width, int height,
|
||||
int clip_x0, int clip_y0, int clip_x1, int clip_y1,
|
||||
float scale, colour background_colour);
|
||||
bool textplain_clone(const struct content *old, struct content *new_content);
|
||||
|
||||
/* access to lines for text selection and searching */
|
||||
unsigned long textplain_line_count(struct hlcache_handle *h);
|
||||
|
|
Loading…
Reference in New Issue