From 79ce683b4e6d34fe327b00f1e427e476016cfab0 Mon Sep 17 00:00:00 2001 From: John Mark Bell Date: Sun, 4 Apr 2010 12:41:19 +0000 Subject: 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 --- content/content.c | 208 +++++++++++++++++++++++++++++++++++++++-------------- content/content.h | 10 +-- content/hlcache.c | 62 +++++++++++++++- content/hlcache.h | 8 +++ content/llcache.c | 179 ++++++++++++++++++++++++++++++++++++--------- content/llcache.h | 18 +++++ css/css.c | 27 +++++++ css/css.h | 2 + desktop/browser.c | 6 +- image/bmp.c | 17 +++++ image/bmp.h | 1 + image/gif.c | 16 +++++ image/gif.h | 1 + image/ico.c | 15 ++++ image/ico.h | 1 + image/jpeg.c | 13 ++++ image/jpeg.h | 1 + image/mng.c | 25 +++++++ image/mng.h | 1 + image/nssprite.c | 13 ++++ image/nssprite.h | 1 + image/png.c | 24 +++++++ image/png.h | 2 + image/rsvg.c | 24 +++++++ image/rsvg.h | 1 + image/svg.c | 16 +++++ image/svg.h | 1 + render/directory.c | 11 +++ render/directory.h | 1 + render/favicon.c | 7 +- render/html.c | 7 +- render/html.h | 1 + render/textplain.c | 55 +++++++++++--- render/textplain.h | 3 +- 34 files changed, 670 insertions(+), 108 deletions(-) diff --git a/content/content.c b/content/content.c index 9a33d964b..a247dda2b 100644 --- a/content/content.c +++ b/content/content.c @@ -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 diff --git a/content/content.h b/content/content.h index 1dd7f83cd..61fc6346f 100644 --- a/content/content.h +++ b/content/content.h @@ -29,6 +29,7 @@ #include #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); diff --git a/content/hlcache.c b/content/hlcache.c index 3a55dbeb4..05a416b0b 100644 --- a/content/hlcache.c +++ b/content/hlcache.c @@ -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)); } diff --git a/content/hlcache.h b/content/hlcache.h index 7c4f05290..5ef42a301 100644 --- a/content/hlcache.h +++ b/content/hlcache.h @@ -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 * diff --git a/content/llcache.c b/content/llcache.c index 49556b1fe..94df0f6e5 100644 --- a/content/llcache.c +++ b/content/llcache.c @@ -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; - } - } } /** diff --git a/content/llcache.h b/content/llcache.h index 7c3fad6de..434d0b641 100644 --- a/content/llcache.h +++ b/content/llcache.h @@ -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 * diff --git a/css/css.c b/css/css.c index b0a3cd472..ef38d76aa 100644 --- a/css/css.c +++ b/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 * diff --git a/css/css.h b/css/css.h index cd09beda6..c95f87053 100644 --- a/css/css.h +++ b/css/css.h @@ -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, diff --git a/desktop/browser.c b/desktop/browser.c index 57a4f59b2..70d6b8cf4 100644 --- a/desktop/browser.c +++ b/desktop/browser.c @@ -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); diff --git a/image/bmp.c b/image/bmp.c index 23ea740e9..ac7bc300e 100644 --- a/image/bmp.c +++ b/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() * diff --git a/image/bmp.h b/image/bmp.h index 0ef5ba602..e78d52f6f 100644 --- a/image/bmp.h +++ b/image/bmp.h @@ -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 */ diff --git a/image/gif.c b/image/gif.c index 01ea57420..7d5a2dc30 100644 --- a/image/gif.c +++ b/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 * diff --git a/image/gif.h b/image/gif.h index 9a39ecf55..9b2eb9fd6 100644 --- a/image/gif.h +++ b/image/gif.h @@ -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 */ diff --git a/image/ico.c b/image/ico.c index 3335a6a58..190da86d2 100644 --- a/image/ico.c +++ b/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 diff --git a/image/ico.h b/image/ico.h index 75f79a92e..6ed8b59d2 100644 --- a/image/ico.h +++ b/image/ico.h @@ -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); diff --git a/image/jpeg.c b/image/jpeg.c index af28fe6fa..6e5e446dd 100644 --- a/image/jpeg.c +++ b/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 */ diff --git a/image/jpeg.h b/image/jpeg.h index 1c01929b8..5f142546a 100644 --- a/image/jpeg.h +++ b/image/jpeg.h @@ -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 */ diff --git a/image/mng.c b/image/mng.c index 5498d0528..7d288a3d3 100644 --- a/image/mng.c +++ b/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 */ diff --git a/image/mng.h b/image/mng.h index 319d42059..9b45852a0 100644 --- a/image/mng.h +++ b/image/mng.h @@ -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 */ diff --git a/image/nssprite.c b/image/nssprite.c index 06e5696a0..6e2778960 100644 --- a/image/nssprite.c +++ b/image/nssprite.c @@ -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 diff --git a/image/nssprite.h b/image/nssprite.h index cc366efc7..7149b1fa0 100644 --- a/image/nssprite.h +++ b/image/nssprite.h @@ -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 */ diff --git a/image/png.c b/image/png.c index f68c07cda..5f01b2387 100644 --- a/image/png.c +++ b/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 diff --git a/image/png.h b/image/png.h index 253e685ad..9f673d9fe 100644 --- a/image/png.h +++ b/image/png.h @@ -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 diff --git a/image/rsvg.c b/image/rsvg.c index c47e9a078..02455733e 100644 --- a/image/rsvg.c +++ b/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 */ diff --git a/image/rsvg.h b/image/rsvg.h index 0eeb3c9eb..e85115dcf 100644 --- a/image/rsvg.h +++ b/image/rsvg.h @@ -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 */ diff --git a/image/svg.c b/image/svg.c index fce246588..44f893afe 100644 --- a/image/svg.c +++ b/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 */ diff --git a/image/svg.h b/image/svg.h index e6cffea39..9720a3772 100644 --- a/image/svg.h +++ b/image/svg.h @@ -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 diff --git a/render/directory.c b/render/directory.c index 969b0c5b9..193941ecf 100644 --- a/render/directory.c +++ b/render/directory.c @@ -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; +} + diff --git a/render/directory.h b/render/directory.h index 25e5f3281..f16ad541b 100644 --- a/render/directory.h +++ b/render/directory.h @@ -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 diff --git a/render/favicon.c b/render/favicon.c index 9f7ad7647..89b292528 100644 --- a/render/favicon.c +++ b/render/favicon.c @@ -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"); diff --git a/render/html.c b/render/html.c index e38a4ba99..2ead62fc3 100644 --- a/render/html.c +++ b/render/html.c @@ -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. diff --git a/render/html.h b/render/html.h index 42d4ec163..79a3b209a 100644 --- a/render/html.h +++ b/render/html.h @@ -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, diff --git a/render/textplain.c b/render/textplain.c index 8983fc2a9..f39a89a08 100644 --- a/render/textplain.c +++ b/render/textplain.c @@ -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). * diff --git a/render/textplain.h b/render/textplain.h index ec4882800..61a1c0c9a 100644 --- a/render/textplain.h +++ b/render/textplain.h @@ -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); -- cgit v1.2.3