From 0c0ff3c59631d0968c888279195ea40d4a7fd824 Mon Sep 17 00:00:00 2001 From: James Bursa Date: Tue, 17 Jun 2003 19:24:21 +0000 Subject: [project @ 2003-06-17 19:24:20 by bursa] Change fetchcache system to store loading contents in cache. svn path=/import/netsurf/; revision=180 --- content/cache.c | 78 ++++++++++---------- content/cache.h | 38 +++++----- content/content.c | 174 +++++++++++++++++++++++++++++++++++++------- content/content.h | 70 ++++++++++++++---- content/fetch.c | 10 +-- content/fetchcache.c | 198 +++++++++------------------------------------------ content/fetchcache.h | 11 ++- content/other.c | 50 +++++++++++++ content/other.h | 17 +++++ content/overview | 52 ++++++++++++++ 10 files changed, 433 insertions(+), 265 deletions(-) create mode 100644 content/other.c create mode 100644 content/other.h create mode 100644 content/overview (limited to 'content') diff --git a/content/cache.c b/content/cache.c index bf0f46511..aa4727eb3 100644 --- a/content/cache.c +++ b/content/cache.c @@ -1,5 +1,5 @@ /** - * $Id: cache.c,v 1.3 2003/04/15 17:53:00 bursa Exp $ + * $Id: cache.c,v 1.4 2003/06/17 19:24:20 bursa Exp $ */ #include @@ -11,7 +11,7 @@ #include "netsurf/utils/log.h" #ifndef TEST -#include "netsurf/desktop/browser.h" +#include "netsurf/content/content.h" #else #include struct content { @@ -29,15 +29,14 @@ void content_destroy(struct content *c); struct cache_entry { struct content *content; - unsigned int use_count; time_t t; struct cache_entry *next, *prev; }; /* doubly-linked lists using a sentinel */ /* TODO: replace with a structure which can be searched faster */ -static struct cache_entry inuse_list_sentinel = {0, 0, 0, &inuse_list_sentinel, &inuse_list_sentinel}; -static struct cache_entry unused_list_sentinel = {0, 0, 0, &unused_list_sentinel, &unused_list_sentinel}; +static struct cache_entry inuse_list_sentinel = {0, 0, &inuse_list_sentinel, &inuse_list_sentinel}; +static struct cache_entry unused_list_sentinel = {0, 0, &unused_list_sentinel, &unused_list_sentinel}; static struct cache_entry *inuse_list = &inuse_list_sentinel; static struct cache_entry *unused_list = &unused_list_sentinel; @@ -70,23 +69,24 @@ void cache_quit(void) struct content * cache_get(const char * const url) { struct cache_entry *e; + LOG(("url %s", url)); /* search inuse_list first */ for (e = inuse_list->next; e != inuse_list && strcmp(e->content->url, url) != 0; e = e->next) ; if (e != inuse_list) { - LOG(("'%s' in inuse_list, content %p, use_count %u", url, e->content, e->use_count)); - e->use_count++; + LOG(("'%s' in inuse_list, content %p", url, e->content)); return e->content; } + LOG(("not in inuse_list")); + /* search unused_list if not found */ for (e = unused_list->next; e != unused_list && strcmp(e->content->url, url) != 0; e = e->next) ; if (e != unused_list) { LOG(("'%s' in unused_list, content %p", url, e->content)); /* move to inuse_list */ - e->use_count = 1; e->prev->next = e->next; e->next->prev = e->prev; e->prev = inuse_list->prev; @@ -110,6 +110,7 @@ void cache_put(struct content * content) struct cache_entry * e; LOG(("content %p, url '%s', size %lu", content, content->url, content->size)); + /* TODO: contents will grow in size as they load */ current_size += content->size; /* clear old data from the usused_list until the size drops below max_size */ while (max_size < current_size && unused_list->next != unused_list) { @@ -126,7 +127,6 @@ void cache_put(struct content * content) /* add the new content to the inuse_list */ e = xcalloc(1, sizeof(struct cache_entry)); e->content = content; - e->use_count = 1; e->prev = inuse_list->prev; e->next = inuse_list; inuse_list->prev->next = e; @@ -136,41 +136,45 @@ void cache_put(struct content * content) /** - * cache_free -- free a cache object if it is no longer used + * cache_freeable -- inform cache that the content has no users */ -void cache_free(struct content * content) +void cache_freeable(struct content * content) { struct cache_entry * e = content->cache; assert(e != 0); - LOG(("content %p, url '%s', use_count %u", content, content->url, e->use_count)); - - assert(e->use_count != 0); - e->use_count--; - if (e->use_count == 0) { - /* move to unused_list or destroy if insufficient space */ - e->use_count = 0; - e->t = time(0); - e->prev->next = e->next; - e->next->prev = e->prev; - if (max_size < current_size) { - LOG(("size %lu, removing", current_size)); - /* TODO: move to disc cache */ - current_size -= e->content->size; - content_destroy(e->content); - xfree(e); - } else { - LOG(("size %lu, moving to unused_list", current_size)); - e->prev = unused_list->prev; - e->next = unused_list; - unused_list->prev->next = e; - unused_list->prev = e; - } + LOG(("content %p, url '%s'", content, content->url)); + + /* move to unused_list or destroy if insufficient space */ + e->t = time(0); + e->prev->next = e->next; + e->next->prev = e->prev; + if (max_size < current_size) { + LOG(("size %lu, removing", current_size)); + /* TODO: move to disc cache */ + current_size -= e->content->size; + content_destroy(e->content); + xfree(e); + } else { + LOG(("size %lu, moving to unused_list", current_size)); + e->prev = unused_list->prev; + e->next = unused_list; + unused_list->prev->next = e; + unused_list->prev = e; } } +void cache_destroy(struct content * content) +{ + struct cache_entry * e = content->cache; + e->prev->next = e->next; + e->next->prev = e->prev; + current_size -= content->size; +} + + /** * cache_dump -- dump contents of cache */ @@ -180,10 +184,12 @@ void cache_dump(void) { LOG(("size %lu", current_size)); LOG(("inuse_list:")); for (e = inuse_list->next; e != inuse_list; e = e->next) - LOG((" content %p, url '%s', use_count %u", e->content, e->content->url, e->use_count)); + LOG((" content %p, size %lu, url '%s'", e->content, + e->content->size, e->content->url)); LOG(("unused_list (time now %lu):", time(0))); for (e = unused_list->next; e != unused_list; e = e->next) - LOG((" content %p, url '%s', t %lu", e->content, e->content->url, e->t)); + LOG((" content %p, size %lu, url '%s', t %lu", e->content, + e->content->size, e->content->url, e->t)); LOG(("end")); } diff --git a/content/cache.h b/content/cache.h index a1c681507..ae1ab503f 100644 --- a/content/cache.h +++ b/content/cache.h @@ -1,25 +1,28 @@ /** - * $Id: cache.h,v 1.2 2003/03/04 11:59:35 bursa Exp $ + * $Id: cache.h,v 1.3 2003/06/17 19:24:20 bursa Exp $ */ /** - * Using the cache: + * The cache contains a content structure for each url. If a structure is not + * in state CONTENT_STATUS_DONE, then loading and converting must be actively + * in progress, so that when a not done content is retrieved no action needs + * to be taken to load it. * - * cache_init(); - * ... - * c = cache_get(url); - * if (c == 0) { - * ... (create c) ... - * cache_put(c); - * } - * ... - * cache_free(c); - * ... - * cache_quit(); + * Each content in the cache is either freeable or not freeable. If an entry + * is freeable, the cache may destroy it through content_destroy at any time. * - * cache_free informs the cache that the content is no longer being used, so - * it can be deleted from the cache if necessary. There must be a call to - * cache_free for each cache_get or cache_put. + * cache_get attempts to retrieve an url from the cache, returning the + * content and setting it to not freeable on success, and returning 0 on + * failure. + * + * cache_put adds a content to the cache, setting it to not freeable. + * + * cache_freeable sets the content to freeable. + * + * cache_destroy informs the cache that a content is about to be destroyed, + * and must be removed from the cache. This should be called when an error + * occurs when loading an url and the content is destroyed. The content must + * be non freeable. */ #ifndef _NETSURF_DESKTOP_CACHE_H_ @@ -32,7 +35,8 @@ void cache_init(void); void cache_quit(void); struct content * cache_get(const char * const url); void cache_put(struct content * content); -void cache_free(struct content * content); +void cache_freeable(struct content * content); +void cache_destroy(struct content * content); void cache_dump(void); #endif diff --git a/content/content.c b/content/content.c index 0538d52c3..65e730ee5 100644 --- a/content/content.c +++ b/content/content.c @@ -1,17 +1,19 @@ /** - * $Id: content.c,v 1.10 2003/06/05 13:17:55 philpem Exp $ + * $Id: content.c,v 1.11 2003/06/17 19:24:20 bursa Exp $ */ #include #include #include #include "netsurf/content/content.h" +#include "netsurf/content/other.h" #include "netsurf/css/css.h" #include "netsurf/render/html.h" #include "netsurf/render/textplain.h" #include "netsurf/riscos/jpeg.h" #include "netsurf/riscos/png.h" #include "netsurf/riscos/gif.h" +#include "netsurf/utils/log.h" #include "netsurf/utils/utils.h" @@ -21,9 +23,11 @@ struct mime_entry { content_type type; }; static const struct mime_entry mime_map[] = { +#ifdef riscos {"image/gif", CONTENT_GIF}, {"image/jpeg", CONTENT_JPEG}, {"image/png", CONTENT_PNG}, +#endif {"text/css", CONTENT_CSS}, {"text/html", CONTENT_HTML}, {"text/plain", CONTENT_TEXTPLAIN}, @@ -46,14 +50,21 @@ static const struct handler_entry handler_map[] = { html_reformat, html_destroy, 0}, {textplain_create, textplain_process_data, textplain_convert, textplain_revive, textplain_reformat, textplain_destroy, 0}, +#ifdef riscos {jpeg_create, jpeg_process_data, jpeg_convert, jpeg_revive, jpeg_reformat, jpeg_destroy, jpeg_redraw}, +#endif {css_create, css_process_data, css_convert, css_revive, css_reformat, css_destroy, 0}, +#ifdef riscos {nspng_create, nspng_process_data, nspng_convert, nspng_revive, nspng_reformat, nspng_destroy, nspng_redraw}, {nsgif_create, nsgif_process_data, nsgif_convert, nsgif_revive, - nsgif_reformat, nsgif_destroy, nsgif_redraw} + nsgif_reformat, nsgif_destroy, nsgif_redraw}, +#endif + {other_create, other_process_data, other_convert, other_revive, + other_reformat, other_destroy, 0} }; +#define HANDLER_MAP_COUNT (sizeof(handler_map) / sizeof(handler_map[0])) /** @@ -72,25 +83,46 @@ content_type content_lookup(const char *mime_type) /** - * content_create -- create a content structure of the specified mime type + * content_create -- create a content structure */ -struct content * content_create(content_type type, char *url) +struct content * content_create(char *url) { struct content *c; - assert(type < CONTENT_OTHER); + struct content_user *user_sentinel; + LOG(("url %s", url)); c = xcalloc(1, sizeof(struct content)); c->url = xstrdup(url); - c->type = type; - c->status = CONTENT_LOADING; + c->type = CONTENT_UNKNOWN; + c->status = CONTENT_STATUS_TYPE_UNKNOWN; c->size = sizeof(struct content); - c->status_callback = 0; + c->fetch = 0; strcpy(c->status_message, "Loading"); - handler_map[type].create(c); + user_sentinel = xcalloc(1, sizeof(*user_sentinel)); + user_sentinel->callback = 0; + user_sentinel->p1 = user_sentinel->p2 = 0; + user_sentinel->next = 0; + c->user_list = user_sentinel; return c; } +/** + * content_set_type -- initialise the content for the specified mime type + */ + +void content_set_type(struct content *c, content_type type) +{ + assert(c->status == CONTENT_STATUS_TYPE_UNKNOWN); + assert(type < CONTENT_UNKNOWN); + LOG(("content %s, type %i", c->url, type)); + c->type = type; + c->status = CONTENT_STATUS_LOADING; + content_broadcast(c, CONTENT_MSG_LOADING, 0); + handler_map[type].create(c); +} + + /** * content_process_data -- process a block source data */ @@ -98,8 +130,8 @@ struct content * content_create(content_type type, char *url) void content_process_data(struct content *c, char *data, unsigned long size) { assert(c != 0); - assert(c->type < CONTENT_OTHER); - assert(c->status == CONTENT_LOADING); + assert(c->status == CONTENT_STATUS_LOADING); + LOG(("content %s, size %lu", c->url, size)); handler_map[c->type].process_data(c, data, size); } @@ -108,17 +140,25 @@ void content_process_data(struct content *c, char *data, unsigned long size) * content_convert -- all data has arrived, complete the conversion */ -int content_convert(struct content *c, unsigned long width, unsigned long height) +void content_convert(struct content *c, unsigned long width, unsigned long height) { assert(c != 0); - assert(c->type < CONTENT_OTHER); - assert(c->status == CONTENT_LOADING); + assert(c->type < HANDLER_MAP_COUNT); + assert(c->status == CONTENT_STATUS_LOADING); + LOG(("content %s", c->url)); c->available_width = width; - if (handler_map[c->type].convert(c, width, height)) - return 1; - if (c->status == CONTENT_LOADING) - c->status = CONTENT_DONE; - return 0; + if (handler_map[c->type].convert(c, width, height)) { + /* convert failed, destroy content */ + content_broadcast(c, CONTENT_MSG_ERROR, "Conversion failed"); + content_destroy(c); + return; + } + assert(c->status == CONTENT_STATUS_READY || + c->status == CONTENT_STATUS_DONE); + if (c->status == CONTENT_STATUS_READY) + content_broadcast(c, CONTENT_MSG_READY, 0); + else + content_broadcast(c, CONTENT_MSG_DONE, 0); } @@ -130,8 +170,7 @@ int content_convert(struct content *c, unsigned long width, unsigned long height void content_revive(struct content *c, unsigned long width, unsigned long height) { assert(c != 0); - assert(c->type < CONTENT_OTHER); - if (c->status != CONTENT_DONE) + if (c->status != CONTENT_STATUS_DONE) return; c->available_width = width; handler_map[c->type].revive(c, width, height); @@ -145,8 +184,8 @@ void content_revive(struct content *c, unsigned long width, unsigned long height void content_reformat(struct content *c, unsigned long width, unsigned long height) { assert(c != 0); - assert(c->type < CONTENT_OTHER); - assert(c->status != CONTENT_LOADING); + assert(c->status == CONTENT_STATUS_READY || + c->status == CONTENT_STATUS_DONE); c->available_width = width; handler_map[c->type].reformat(c, width, height); } @@ -158,9 +197,15 @@ void content_reformat(struct content *c, unsigned long width, unsigned long heig void content_destroy(struct content *c) { + struct content_user *user, *next; assert(c != 0); - assert(c->type < CONTENT_OTHER); - handler_map[c->type].destroy(c); + LOG(("content %p %s", c, c->url)); + if (c->type < HANDLER_MAP_COUNT) + handler_map[c->type].destroy(c); + for (user = c->user_list; user != 0; user = next) { + next = user->next; + xfree(user); + } xfree(c); } @@ -173,8 +218,85 @@ void content_redraw(struct content *c, long x, long y, unsigned long width, unsigned long height) { assert(c != 0); - assert(c->type < CONTENT_OTHER); if (handler_map[c->type].redraw != 0) handler_map[c->type].redraw(c, x, y, width, height); } + +/** + * content_add_user -- register a user for callbacks + */ + +void content_add_user(struct content *c, + void (*callback)(content_msg msg, struct content *c, void *p1, + void *p2, const char *error), + void *p1, void *p2) +{ + struct content_user *user; + LOG(("content %s, user %p %p %p", c->url, callback, p1, p2)); + user = xcalloc(1, sizeof(*user)); + user->callback = callback; + user->p1 = p1; + user->p2 = p2; + user->next = c->user_list->next; + c->user_list->next = user; +} + + +/** + * content_remove_user -- remove a callback user + */ + +void content_remove_user(struct content *c, + void (*callback)(content_msg msg, struct content *c, void *p1, + void *p2, const char *error), + void *p1, void *p2) +{ + struct content_user *user, *next; + LOG(("content %s, user %p %p %p", c->url, callback, p1, p2)); + + /* user_list starts with a sentinel */ + for (user = c->user_list; user->next != 0 && + !(user->next->callback == callback && + user->next->p1 == p1 && + user->next->p2 == p2); user = user->next) + ; + if (user->next == 0) { + LOG(("user not found in list")); + assert(0); + return; + } + next = user->next; + user->next = next->next; + xfree(next); + + /* if there are now no users, stop any loading in progress + * and destroy content structure if not in state READY or DONE */ + if (c->user_list->next == 0) { + LOG(("no users for %p %s", c, c->url)); + if (c->fetch != 0) + fetch_abort(c->fetch); + if (c->status < CONTENT_STATUS_READY) { + cache_destroy(c); + content_destroy(c); + } else + cache_freeable(c); + } +} + + +/** + * content_broadcast -- send a message to all users + */ + +void content_broadcast(struct content *c, content_msg msg, char *error) +{ + struct content_user *user, *next; + LOG(("content %s, message %i", c->url, msg)); + for (user = c->user_list->next; user != 0; user = next) { + next = user->next; /* user may be destroyed during callback */ + if (user->callback != 0) + user->callback(msg, c, user->p1, user->p2, error); + } +} + diff --git a/content/content.h b/content/content.h index c9fa9870b..077b3cc89 100644 --- a/content/content.h +++ b/content/content.h @@ -1,18 +1,23 @@ /** - * $Id: content.h,v 1.11 2003/06/05 13:17:55 philpem Exp $ + * $Id: content.h,v 1.12 2003/06/17 19:24:20 bursa Exp $ */ #ifndef _NETSURF_DESKTOP_CONTENT_H_ #define _NETSURF_DESKTOP_CONTENT_H_ #include "libxml/HTMLparser.h" +#ifdef riscos #include "libpng/png.h" #include "libungif/gif_lib.h" #include "oslib/osspriteop.h" +#endif #include "netsurf/content/cache.h" +#include "netsurf/content/fetch.h" #include "netsurf/css/css.h" #include "netsurf/render/box.h" +#ifdef riscos #include "netsurf/riscos/font.h" +#endif /** @@ -32,11 +37,16 @@ typedef enum { CONTENT_HTML, CONTENT_TEXTPLAIN, +#ifdef riscos CONTENT_JPEG, +#endif CONTENT_CSS, +#ifdef riscos CONTENT_PNG, CONTENT_GIF, - CONTENT_OTHER +#endif + CONTENT_OTHER, + CONTENT_UNKNOWN /* content-type not received yet */ } content_type; struct box_position @@ -49,16 +59,34 @@ struct box_position int char_offset; }; +typedef enum { + CONTENT_MSG_LOADING, /* fetching or converting */ + CONTENT_MSG_READY, /* may be displayed */ + CONTENT_MSG_DONE, /* finished */ + CONTENT_MSG_ERROR, /* error occurred */ + CONTENT_MSG_STATUS /* new status string */ +} content_msg; + +struct content_user +{ + void (*callback)(content_msg msg, struct content *c, void *p1, + void *p2, const char *error); + void *p1; + void *p2; + struct content_user *next; +}; + struct content { char *url; content_type type; enum { - CONTENT_LOADING, /* content is being fetched or converted - and is not safe to display */ - CONTENT_PENDING, /* some parts of content still being - loaded, but can be displayed */ - CONTENT_DONE /* all finished */ + CONTENT_STATUS_TYPE_UNKNOWN, /* type not yet known */ + CONTENT_STATUS_LOADING, /* content is being fetched or converted + and is not safe to display */ + CONTENT_STATUS_READY, /* some parts of content still being + loaded, but can be displayed */ + CONTENT_STATUS_DONE /* all finished */ } status; unsigned long width, height; unsigned long available_width; @@ -95,7 +123,7 @@ struct content char **import_url; struct content **import_content; } css; - +#ifdef riscos struct { char * data; @@ -122,6 +150,13 @@ struct content osspriteop_area *sprite_area; // Sprite area char *sprite_image; // Sprite image } gif; +#endif + /* downloads */ + struct + { + char *data; + unsigned long length; + } other; } data; @@ -130,20 +165,31 @@ struct content char *title; unsigned int active; int error; - void (*status_callback)(void *p, const char *status); - void *status_p; + struct content_user *user_list; char status_message[80]; + struct fetch *fetch; + unsigned long fetch_size; }; content_type content_lookup(const char *mime_type); -struct content * content_create(content_type type, char *url); +struct content * content_create(char *url); +void content_set_type(struct content *c, content_type type); void content_process_data(struct content *c, char *data, unsigned long size); -int content_convert(struct content *c, unsigned long width, unsigned long height); +void content_convert(struct content *c, unsigned long width, unsigned long height); void content_revive(struct content *c, unsigned long width, unsigned long height); void content_reformat(struct content *c, unsigned long width, unsigned long height); void content_destroy(struct content *c); void content_redraw(struct content *c, long x, long y, unsigned long width, unsigned long height); +void content_add_user(struct content *c, + void (*callback)(content_msg msg, struct content *c, void *p1, + void *p2, const char *error), + void *p1, void *p2); +void content_remove_user(struct content *c, + void (*callback)(content_msg msg, struct content *c, void *p1, + void *p2, const char *error), + void *p1, void *p2); +void content_broadcast(struct content *c, content_msg msg, char *error); #endif diff --git a/content/fetch.c b/content/fetch.c index 3d1bdc817..65a0de988 100644 --- a/content/fetch.c +++ b/content/fetch.c @@ -1,5 +1,5 @@ /** - * $Id: fetch.c,v 1.9 2003/06/02 01:09:50 jmb Exp $ + * $Id: fetch.c,v 1.10 2003/06/17 19:24:20 bursa Exp $ * * This module handles fetching of data from any url. * @@ -285,6 +285,7 @@ void fetch_poll(void) CURLMsg * curl_msg; struct fetch *f; void *p; + void (*callback)(fetch_msg msg, void *p, char *data, unsigned long size); /* do any possible work on the current fetches */ do { @@ -305,20 +306,21 @@ void fetch_poll(void) /* inform the caller that the fetch is done */ finished = 0; + callback = f->callback; p = f->p; if (curl_msg->data.result == CURLE_OK && f->had_headers) finished = 1; else if (curl_msg->data.result == CURLE_OK) - f->callback(FETCH_ERROR, f->p, "No data received", 0); + callback(FETCH_ERROR, f->p, "No data received", 0); else if (curl_msg->data.result != CURLE_WRITE_ERROR) - f->callback(FETCH_ERROR, f->p, f->error_buffer, 0); + callback(FETCH_ERROR, f->p, f->error_buffer, 0); /* clean up fetch */ fetch_abort(f); /* postponed until after abort so that queue fetches are started */ if (finished) - f->callback(FETCH_FINISHED, p, 0, 0); + callback(FETCH_FINISHED, p, 0, 0); break; diff --git a/content/fetchcache.c b/content/fetchcache.c index 600fd13fd..0755b37c5 100644 --- a/content/fetchcache.c +++ b/content/fetchcache.c @@ -1,117 +1,52 @@ /** - * $Id: fetchcache.c,v 1.9 2003/04/25 08:03:15 bursa Exp $ + * $Id: fetchcache.c,v 1.10 2003/06/17 19:24:20 bursa Exp $ */ #include #include #include "netsurf/content/cache.h" +#include "netsurf/content/content.h" #include "netsurf/content/fetchcache.h" #include "netsurf/content/fetch.h" #include "netsurf/utils/log.h" #include "netsurf/utils/utils.h" -struct fetchcache { - char *url; - void (*callback)(fetchcache_msg msg, struct content *c, void *p, const char *error); - void *p; - struct fetch *f; - struct content *c; - unsigned long width, height; - unsigned long size; - content_type allowed; - struct fetchcache *next; - struct fetchcache *prev; - struct fetchcache *next_request; - int active; -}; - -static struct fetchcache *fetchcache_list = 0; - -static void fetchcache_free(struct fetchcache *fc); -static void fetchcache_callback(fetchcache_msg msg, void *p, char *data, unsigned long size); -static void status_callback(void *p, const char *status); +static void fetchcache_callback(fetch_msg msg, void *p, char *data, unsigned long size); -void fetchcache(const char *url, char *referer, - void (*callback)(fetchcache_msg msg, struct content *c, void *p, const char *error), - void *p, unsigned long width, unsigned long height, content_type allowed) +struct content * fetchcache(const char *url, char *referer, + void (*callback)(content_msg msg, struct content *c, void *p1, + void *p2, const char *error), + void *p1, void *p2, unsigned long width, unsigned long height) { struct content *c; - struct fetchcache *fc, *fc_url; + + LOG(("url %s", url)); c = cache_get(url); if (c != 0) { - /* check type is allowed */ - if ((1 << c->type) & allowed) { - callback(FETCHCACHE_STATUS, c, p, "Found in cache"); - content_revive(c, width, height); - callback(FETCHCACHE_OK, c, p, 0); - } else { - callback(FETCHCACHE_BADTYPE, 0, p, ""); - cache_free(c); - } - return; - } - - callback(FETCHCACHE_STATUS, c, p, "Starting fetch"); - fc = xcalloc(1, sizeof(struct fetchcache)); - fc->url = xstrdup(url); - fc->callback = callback; - fc->p = p; - fc->c = 0; - fc->width = width; - fc->height = height; - fc->size = 0; - fc->allowed = allowed; - fc->next = 0; - fc->prev = 0; - fc->next_request = 0; - fc->active = 1; - - /* check if we're already fetching this url */ - for (fc_url = fetchcache_list; - fc_url != 0 && strcmp(fc_url->url, url) != 0; - fc_url = fc_url->next) - ; - if (fc_url != 0) { - /* already fetching: add ourselves to list of requestors */ - LOG(("already fetching")); - fc->next_request = fc_url->next_request; - fc_url->next_request = fc; - - } else { - /* not fetching yet */ - if (fetchcache_list != 0) - fetchcache_list->prev = fc; - fc->next = fetchcache_list; - fetchcache_list = fc; - fc->f = fetch_start(fc->url, referer, fetchcache_callback, fc); + content_add_user(c, callback, p1, p2); + return c; } -} - -void fetchcache_free(struct fetchcache *fc) -{ - free(fc->url); - free(fc); - if (fc->prev == 0) - fetchcache_list = fc->next; - else - fc->prev->next = fc->next; - if (fc->next != 0) - fc->next->prev = fc->prev; + c = content_create(url); + content_add_user(c, callback, p1, p2); + cache_put(c); + c->fetch_size = 0; + c->width = width; + c->height = height; + c->fetch = fetch_start(url, referer, fetchcache_callback, c); + return c; } void fetchcache_callback(fetch_msg msg, void *p, char *data, unsigned long size) { - struct fetchcache *fc = p, *fc_url; + struct content *c = p; content_type type; char *mime_type; char *semic; - char status[40]; - int active = 0; switch (msg) { case FETCH_TYPE: @@ -119,89 +54,33 @@ void fetchcache_callback(fetch_msg msg, void *p, char *data, unsigned long size) if ((semic = strchr(mime_type, ';')) != 0) *semic = 0; /* remove "; charset=..." */ type = content_lookup(mime_type); - LOG(("FETCH_TYPE, type %u", type)); - - /* check if each request allows this type */ - for (fc_url = fc; fc_url != 0; fc_url = fc_url->next_request) { - if (!fc_url->active) - continue; - if ((1 << type) & fc_url->allowed) { - active++; - } else { - fc_url->active = 0; - fc_url->callback(FETCHCACHE_BADTYPE, 0, - fc_url->p, mime_type); - } - } - if (active != 0) { - /* someone is still interested */ - fc->c = content_create(type, fc->url); - fc->c->status_callback = status_callback; - fc->c->status_p = fc; - } else { - /* no request allows the type */ - fetch_abort(fc->f); - for (; fc != 0; fc = fc_url) { - fc_url = fc->next_request; - fetchcache_free(fc); - } - } - free(mime_type); + LOG(("FETCH_TYPE, type %u", type)); + content_set_type(c, type); break; case FETCH_DATA: LOG(("FETCH_DATA")); - assert(fc->c != 0); - fc->size += size; - sprintf(status, "Received %lu bytes", fc->size); - for (fc_url = fc; fc_url != 0; fc_url = fc_url->next_request) - if (fc_url->active) - fc_url->callback(FETCHCACHE_STATUS, fc->c, - fc_url->p, status); - content_process_data(fc->c, data, size); + c->fetch_size += size; + sprintf(c->status_message, "Received %lu bytes", c->fetch_size); + content_broadcast(c, CONTENT_MSG_STATUS, 0); + content_process_data(c, data, size); break; case FETCH_FINISHED: LOG(("FETCH_FINISHED")); - assert(fc->c != 0); - sprintf(status, "Converting %lu bytes", fc->size); - for (fc_url = fc; fc_url != 0; fc_url = fc_url->next_request) - if (fc_url->active) - fc_url->callback(FETCHCACHE_STATUS, fc->c, - fc_url->p, status); - - if (content_convert(fc->c, fc->width, fc->height) == 0) { - cache_put(fc->c); - for (fc_url = fc; fc_url != 0; fc_url = fc_url->next_request) - if (fc_url->active) - fc_url->callback(FETCHCACHE_OK, cache_get(fc->url), - fc_url->p, 0); - cache_free(fc->c); - } else { - content_destroy(fc->c); - for (fc_url = fc; fc_url != 0; fc_url = fc_url->next_request) - if (fc_url->active) - fc_url->callback(FETCHCACHE_ERROR, 0, - fc_url->p, "Conversion failed"); - } - for (; fc != 0; fc = fc_url) { - fc_url = fc->next_request; - fetchcache_free(fc); - } + sprintf(c->status_message, "Converting %lu bytes", c->fetch_size); + c->fetch = 0; + content_broadcast(c, CONTENT_MSG_STATUS, 0); + content_convert(c, c->width, c->height); break; case FETCH_ERROR: LOG(("FETCH_ERROR, '%s'", data)); - if (fc->c != 0) - content_destroy(fc->c); - for (fc_url = fc; fc_url != 0; fc_url = fc_url->next_request) - if (fc_url->active) - fc->callback(FETCHCACHE_ERROR, 0, fc_url->p, data); - for (; fc != 0; fc = fc_url) { - fc_url = fc->next_request; - fetchcache_free(fc); - } + c->fetch = 0; + content_broadcast(c, CONTENT_MSG_ERROR, data); + cache_destroy(c); + content_destroy(c); break; default: @@ -210,15 +89,6 @@ void fetchcache_callback(fetch_msg msg, void *p, char *data, unsigned long size) } -void status_callback(void *p, const char *status) -{ - struct fetchcache *fc = p, *fc_url; - for (fc_url = fc; fc_url != 0; fc_url = fc_url->next_request) - if (fc_url->active) - fc_url->callback(FETCHCACHE_STATUS, fc->c, fc_url->p, status); -} - - #ifdef TEST #include diff --git a/content/fetchcache.h b/content/fetchcache.h index 9241ddf0f..c9b3d182c 100644 --- a/content/fetchcache.h +++ b/content/fetchcache.h @@ -1,5 +1,5 @@ /** - * $Id: fetchcache.h,v 1.4 2003/04/09 21:57:09 bursa Exp $ + * $Id: fetchcache.h,v 1.5 2003/06/17 19:24:20 bursa Exp $ */ #ifndef _NETSURF_DESKTOP_FETCHCACHE_H_ @@ -7,10 +7,9 @@ #include "netsurf/content/content.h" -typedef enum {FETCHCACHE_OK, FETCHCACHE_BADTYPE, FETCHCACHE_ERROR, FETCHCACHE_STATUS} fetchcache_msg; - -void fetchcache(const char *url, char *referer, - void (*callback)(fetchcache_msg msg, struct content *c, void *p, const char *error), - void *p, unsigned long width, unsigned long height, content_type allowed); +struct content * fetchcache(const char *url, char *referer, + void (*callback)(content_msg msg, struct content *c, void *p1, + void *p2, const char *error), + void *p1, void *p2, unsigned long width, unsigned long height); #endif diff --git a/content/other.c b/content/other.c new file mode 100644 index 000000000..2374aa679 --- /dev/null +++ b/content/other.c @@ -0,0 +1,50 @@ +/** + * $Id: other.c,v 1.1 2003/06/17 19:24:20 bursa Exp $ + */ + +#include +#include +#include +#include "netsurf/content/other.h" +#include "netsurf/utils/utils.h" + + +void other_create(struct content *c) +{ + c->data.other.data = xcalloc(0, 1); + c->data.other.length = 0; +} + + +void other_process_data(struct content *c, char *data, unsigned long size) +{ + c->data.other.data = xrealloc(c->data.other.data, c->data.other.length + size); + memcpy(c->data.other.data + c->data.other.length, data, size); + c->data.other.length += size; + c->size += size; +} + + +int other_convert(struct content *c, unsigned int width, unsigned int height) +{ + c->status = CONTENT_STATUS_DONE; + return 0; +} + + +void other_revive(struct content *c, unsigned int width, unsigned int height) +{ + assert(0); +} + + +void other_reformat(struct content *c, unsigned int width, unsigned int height) +{ + assert(0); +} + + +void other_destroy(struct content *c) +{ + assert(0); +} diff --git a/content/other.h b/content/other.h new file mode 100644 index 000000000..66d69a7ae --- /dev/null +++ b/content/other.h @@ -0,0 +1,17 @@ +/** + * $Id: other.h,v 1.1 2003/06/17 19:24:20 bursa Exp $ + */ + +#ifndef _NETSURF_RISCOS_OTHER_H_ +#define _NETSURF_RISCOS_OTHER_H_ + +#include "netsurf/content/content.h" + +void other_create(struct content *c); +void other_process_data(struct content *c, char *data, unsigned long size); +int other_convert(struct content *c, unsigned int width, unsigned int height); +void other_revive(struct content *c, unsigned int width, unsigned int height); +void other_reformat(struct content *c, unsigned int width, unsigned int height); +void other_destroy(struct content *c); + +#endif diff --git a/content/overview b/content/overview new file mode 100644 index 000000000..0a911dc44 --- /dev/null +++ b/content/overview @@ -0,0 +1,52 @@ +NetSurf fetch, cache, and content system +======================================== + +There is a one-to-one mapping between URLs and content structures. + +The resource at a URL may be required for two reasons: + +1. The user requests a URL in the GUI by entering it or following a link. +2. A page contains an object (such as an image). + +When a URL is required, call fetchcache() as follows: + + c = fetchcache(url, referer, callback, p1, p2, width, height); + +p1 and p2 are the callers private pointers used to identify the resource, and +they are passed to the callback. The triple (callback, p1, p2) must be unique. +The call returns immediately with a struct content. The structure may be in the +following states (c->status): + + CONTENT_STATUS_TYPE_UNKNOWN -- the MIME type of the resource has not been + determined yet. + + CONTENT_STATUS_LOADING -- the resource is being fetched or converted, and can + not be displayed. + + CONTENT_STATUS_READY -- the resource is still loading, but may be displayed. + + CONTENT_STATUS_DONE -- the resource has loaded completely. + +States may only follow in the above order (but some may be skipped). The +callback function is called when the state changes or at other times as follows: + + CONTENT_MSG_LOADING -- state has changed from CONTENT_STATUS_TYPE_UNKNOWN to + CONTENT_STATUS_LOADING. If the type is not acceptable content_remove_user() + should be called (see below). + + CONTENT_MSG_READY -- state has changed to CONTENT_STATUS_READY. + + CONTENT_MSG_DONE -- state has changed to CONTENT_STATUS_DONE. + + CONTENT_MSG_ERROR -- a fatal error with the resource has occurred. The error + message is in the callback parameter. The content structure will be + destroyed after this message and must not be used. + + CONTENT_MSG_STATUS -- the content structure's status message has changed. + +If at any time the resource is no longer required, call content_remove_user(): + + content_remove_user(c, callback, p1, p2); + +with the same callback, p1, p2 as passed to fetchcache(). + -- cgit v1.2.3