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 ++++++++++ css/css.c | 88 +++++++++-------- desktop/browser.c | 78 ++++++++------- desktop/browser.h | 3 +- makefile | 4 +- render/box.c | 12 ++- render/box.h | 4 +- render/html.c | 271 +++++++++++++++++++++++++++++---------------------- render/html.h | 4 +- render/layout.c | 9 +- riscos/gif.c | 3 +- riscos/gui.c | 15 +-- riscos/jpeg.c | 3 +- riscos/plugin.c | 4 +- riscos/png.c | 3 +- 24 files changed, 711 insertions(+), 488 deletions(-) create mode 100644 content/other.c create mode 100644 content/other.h create mode 100644 content/overview 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(). + diff --git a/css/css.c b/css/css.c index feea10888..0f5b61923 100644 --- a/css/css.c +++ b/css/css.c @@ -1,5 +1,5 @@ /** - * $Id: css.c,v 1.8 2003/04/25 08:03:15 bursa Exp $ + * $Id: css.c,v 1.9 2003/06/17 19:24:21 bursa Exp $ */ #include @@ -13,7 +13,9 @@ #include "netsurf/content/fetchcache.h" #include "netsurf/css/css.h" #include "netsurf/css/parser.h" +#ifdef riscos #include "netsurf/desktop/gui.h" +#endif #include "netsurf/utils/log.h" #include "netsurf/utils/utils.h" @@ -26,13 +28,8 @@ struct decl { struct rule * rule; }; -struct fetch_data { - struct content *c; - unsigned int i; -}; - -void css_atimport_callback(fetchcache_msg msg, struct content *css, - void *p, const char *error); +void css_atimport_callback(content_msg msg, struct content *css, + void *p1, void *p2, const char *error); void css_dump_style(const struct css_style * const style); @@ -136,6 +133,7 @@ int css_convert(struct content *c, unsigned int width, unsigned int height) gui_multitask(); } + c->status = CONTENT_STATUS_DONE; return 0; } @@ -143,15 +141,14 @@ int css_convert(struct content *c, unsigned int width, unsigned int height) void css_revive(struct content *c, unsigned int width, unsigned int height) { unsigned int i; - struct fetch_data *fetch_data; /* imported stylesheets */ for (i = 0; i != c->data.css.import_count; i++) { - fetch_data = xcalloc(1, sizeof(*fetch_data)); - fetch_data->c = c; - fetch_data->i = i; - c->active++; - fetchcache(c->data.css.import_url[i], c->url, css_atimport_callback, - fetch_data, c->width, c->height, 1 << CONTENT_CSS); + c->data.css.import_content[i] = fetchcache( + c->data.css.import_url[i], c->url, + css_atimport_callback, c, i, + c->width, c->height); + if (c->data.css.import_content[i]->status != CONTENT_STATUS_DONE) + c->active++; } while (c->active != 0) { fetch_poll(); @@ -181,7 +178,8 @@ void css_destroy(struct content *c) for (i = 0; i != c->data.css.import_count; i++) if (c->data.css.import_content[i] != 0) { free(c->data.css.import_url[i]); - cache_free(c->data.css.import_content[i]); + content_remove_user(c->data.css.import_content[i], + css_atimport_callback, c, i); } xfree(c->data.css.import_url); xfree(c->data.css.import_content); @@ -226,7 +224,7 @@ void css_atimport(struct content *c, struct node *node) { char *s, *url; int string = 0, screen = 1; - struct fetch_data *fetch_data; + unsigned int i; LOG(("@import rule")); @@ -293,43 +291,51 @@ void css_atimport(struct content *c, struct node *node) c->data.css.import_content = xrealloc(c->data.css.import_content, c->data.css.import_count * sizeof(*c->data.css.import_content)); - fetch_data = xcalloc(1, sizeof(*fetch_data)); - fetch_data->c = c; - fetch_data->i = c->data.css.import_count - 1; - c->data.css.import_url[fetch_data->i] = url_join(url, c->url); - c->active++; - fetchcache(c->data.css.import_url[fetch_data->i], c->url, css_atimport_callback, - fetch_data, c->width, c->height, 1 << CONTENT_CSS); + i = c->data.css.import_count - 1; + c->data.css.import_url[i] = url_join(url, c->url); + c->data.css.import_content[i] = fetchcache( + c->data.css.import_url[i], c->url, css_atimport_callback, + c, i, c->width, c->height); + if (c->data.css.import_content[i]->status != CONTENT_STATUS_DONE) + c->active++; free(url); } -void css_atimport_callback(fetchcache_msg msg, struct content *css, - void *p, const char *error) +void css_atimport_callback(content_msg msg, struct content *css, + void *p1, void *p2, const char *error) { - struct fetch_data *data = p; - struct content *c = data->c; - unsigned int i = data->i; + struct content *c = p1; + unsigned int i = (unsigned int) p2; switch (msg) { - case FETCHCACHE_OK: - free(data); + case CONTENT_MSG_LOADING: + if (css->type != CONTENT_CSS) { + content_remove_user(css, css_atimport_callback, c, i); + c->data.css.import_content[i] = 0; + c->active--; + c->error = 1; + } + break; + + case CONTENT_MSG_READY: + break; + + case CONTENT_MSG_DONE: LOG(("got imported stylesheet '%s'", css->url)); - c->data.css.import_content[i] = css; /*css_dump_stylesheet(css->data.css);*/ c->active--; break; - case FETCHCACHE_BADTYPE: - case FETCHCACHE_ERROR: - free(data); + + case CONTENT_MSG_ERROR: c->data.css.import_content[i] = 0; c->active--; c->error = 1; break; - case FETCHCACHE_STATUS: - /* TODO: need to add a way of sending status to the - * owning window */ + + case CONTENT_MSG_STATUS: break; + default: assert(0); } @@ -371,11 +377,13 @@ void css_get_style(struct content *c, struct css_selector * selector, for (m = n->left; m != 0; m = m->next) { if (m->type == NODE_ID) { /* TODO: check if case sensitive */ - if (strcmp(selector[i].id, m->data + 1) != 0) + if (selector[i].id == 0 || + strcmp(selector[i].id, m->data + 1) != 0) goto not_matched; } else if (m->type == NODE_CLASS) { /* TODO: check if case sensitive */ - if (strcmp(selector[i].class, m->data) != 0) + if (selector[i].class == 0 || + strcmp(selector[i].class, m->data) != 0) goto not_matched; } else { goto not_matched; diff --git a/desktop/browser.c b/desktop/browser.c index 21603de1e..13fdd7d36 100644 --- a/desktop/browser.c +++ b/desktop/browser.c @@ -1,5 +1,5 @@ /** - * $Id: browser.c,v 1.39 2003/06/05 13:17:55 philpem Exp $ + * $Id: browser.c,v 1.40 2003/06/17 19:24:21 bursa Exp $ */ #include "netsurf/content/cache.h" @@ -30,8 +30,8 @@ static int redraw_box_list(struct browser_window* bw, struct box* current, static void browser_window_redraw_boxes(struct browser_window* bw, struct box_position* start, struct box_position* end); static void browser_window_follow_link(struct browser_window* bw, unsigned long click_x, unsigned long click_y, int click_type); -static void browser_window_callback(fetchcache_msg msg, struct content *c, - void *p, const char *error); +static void browser_window_callback(content_msg msg, struct content *c, + void *p1, void *p2, const char *error); static void clear_radio_gadgets(struct browser_window* bw, struct box* box, struct gui_gadget* group); static void gui_redraw_gadget2(struct browser_window* bw, struct box* box, struct gui_gadget* g, unsigned long x, unsigned long y); @@ -157,6 +157,7 @@ struct browser_window* create_browser_window(int flags, int width, int height) bw->scale.div = 1; bw->current_content = NULL; + bw->loading_content = NULL; bw->history = NULL; bw->url = NULL; @@ -178,7 +179,7 @@ void browser_window_destroy(struct browser_window* bw) assert(bw != 0); if (bw->current_content != NULL) - cache_free(bw->current_content); + content_remove_user(bw->current_content, browser_window_callback, bw, 0); if (bw->history != NULL) { @@ -220,11 +221,12 @@ void browser_window_open_location_historical(struct browser_window* bw, const ch browser_window_set_status(bw, "Opening page..."); browser_window_start_throbber(bw); bw->time0 = clock(); - fetchcache(url, 0, browser_window_callback, bw, - gui_window_get_width(bw->window), 0, - (1 << CONTENT_HTML) | (1 << CONTENT_TEXTPLAIN) | - (1 << CONTENT_JPEG) | (1 << CONTENT_PNG) | - (1 << CONTENT_GIF)); + bw->loading_content = fetchcache(url, 0, browser_window_callback, bw, 0, + gui_window_get_width(bw->window), 0); + if (bw->loading_content->status == CONTENT_STATUS_READY) + browser_window_callback(CONTENT_MSG_READY, bw->loading_content, bw, 0, 0); + else if (bw->loading_content->status == CONTENT_STATUS_DONE) + browser_window_callback(CONTENT_MSG_DONE, bw->loading_content, bw, 0, 0); LOG(("end")); } @@ -247,17 +249,27 @@ void browser_window_open_location(struct browser_window* bw, const char* url0) LOG(("end")); } -void browser_window_callback(fetchcache_msg msg, struct content *c, - void *p, const char *error) +void browser_window_callback(content_msg msg, struct content *c, + void *p1, void *p2, const char *error) { - struct browser_window* bw = p; + struct browser_window* bw = p1; gui_safety previous_safety; char status[40]; switch (msg) { - case FETCHCACHE_OK: - { + case CONTENT_MSG_LOADING: + if (c->type == CONTENT_OTHER) { + /* TODO: implement downloads */ + /* we probably want to open a new window with a save icon and progress bar, + * and transfer content_loading to it */ + } + break; + + case CONTENT_MSG_READY: + case CONTENT_MSG_DONE: + previous_safety = gui_window_set_redraw_safety(bw->window, UNSAFE); + if (bw->loading_content == c) { struct gui_message gmsg; if (bw->url != 0) xfree(bw->url); @@ -267,7 +279,6 @@ void browser_window_callback(fetchcache_msg msg, struct content *c, gmsg.data.set_url.url = bw->url; gui_window_message(bw->window, &gmsg); - previous_safety = gui_window_set_redraw_safety(bw->window, UNSAFE); if (bw->current_content != NULL) { if (bw->current_content->type == CONTENT_HTML) @@ -278,34 +289,33 @@ void browser_window_callback(fetchcache_msg msg, struct content *c, gui_remove_gadget(bw->current_content->data.html.elements.gadgets[gc]); } } - cache_free(bw->current_content); + content_remove_user(bw->current_content, browser_window_callback, bw, 0); } bw->current_content = c; - browser_window_reformat(bw); - gui_window_set_redraw_safety(bw->window, previous_safety); - if (bw->current_content->status == CONTENT_DONE) { - sprintf(status, "Page complete (%gs)", ((float) (clock() - bw->time0)) / CLOCKS_PER_SEC); - browser_window_set_status(bw, status); - browser_window_stop_throbber(bw); - } else { - browser_window_set_status(bw, bw->current_content->status_message); - } + bw->loading_content = 0; + } + browser_window_reformat(bw); + gui_window_set_redraw_safety(bw->window, previous_safety); + if (bw->current_content->status == CONTENT_STATUS_DONE) { + sprintf(status, "Page complete (%gs)", ((float) (clock() - bw->time0)) / CLOCKS_PER_SEC); + browser_window_set_status(bw, status); + browser_window_stop_throbber(bw); + } else { + browser_window_set_status(bw, c->status_message); } break; - case FETCHCACHE_ERROR: + case CONTENT_MSG_ERROR: browser_window_set_status(bw, error); + if (c == bw->loading_content) + bw->loading_content = 0; + else if (c == bw->current_content) + bw->current_content = 0; browser_window_stop_throbber(bw); break; - case FETCHCACHE_BADTYPE: - sprintf(status, "Unknown type '%s'", error); - browser_window_set_status(bw, status); - browser_window_stop_throbber(bw); - break; - - case FETCHCACHE_STATUS: - browser_window_set_status(bw, error); + case CONTENT_MSG_STATUS: + browser_window_set_status(bw, c->status_message); break; default: diff --git a/desktop/browser.h b/desktop/browser.h index 11eba93c8..10613bcd4 100644 --- a/desktop/browser.h +++ b/desktop/browser.h @@ -1,5 +1,5 @@ /** - * $Id: browser.h,v 1.12 2003/04/15 17:53:00 bursa Exp $ + * $Id: browser.h,v 1.13 2003/06/17 19:24:21 bursa Exp $ */ #ifndef _NETSURF_DESKTOP_BROWSER_H_ @@ -48,6 +48,7 @@ struct browser_window struct { int mult; int div; } scale; struct content* current_content; + struct content* loading_content; struct history* history; clock_t time0; diff --git a/makefile b/makefile index 3a1ca7de7..ccbaa3aa2 100644 --- a/makefile +++ b/makefile @@ -1,7 +1,7 @@ -# $Id: makefile,v 1.33 2003/06/05 14:39:54 bursa Exp $ +# $Id: makefile,v 1.34 2003/06/17 19:24:20 bursa Exp $ CC = riscos-gcc -OBJECTS = cache.o content.o fetch.o fetchcache.o \ +OBJECTS = cache.o content.o fetch.o fetchcache.o other.o \ css.o css_enum.o parser.o ruleset.o scanner.o \ browser.o netsurf.o \ box.o html.o layout.o textplain.o \ diff --git a/render/box.c b/render/box.c index af1c88c9e..5d44a305c 100644 --- a/render/box.c +++ b/render/box.c @@ -1,5 +1,5 @@ /** - * $Id: box.c,v 1.50 2003/06/07 22:24:22 jmb Exp $ + * $Id: box.c,v 1.51 2003/06/17 19:24:21 bursa Exp $ */ #include @@ -10,13 +10,15 @@ #include "libxml/HTMLparser.h" #include "netsurf/content/fetchcache.h" #include "netsurf/css/css.h" -#include "netsurf/desktop/gui.h" #include "netsurf/render/box.h" +#ifdef riscos +#include "netsurf/desktop/gui.h" #include "netsurf/riscos/font.h" +#endif #include "netsurf/riscos/plugin.h" +#define NDEBUG #include "netsurf/utils/log.h" #include "netsurf/utils/utils.h" -//#define NDEBUG /** * internal functions @@ -1052,7 +1054,7 @@ struct box* box_image(xmlNode *n, struct content *content, xmlFree(s); /* start fetch */ - html_fetch_image(content, url, box); + html_fetch_object(content, url, box); return box; } @@ -1368,7 +1370,7 @@ struct form* box_form(xmlNode* n) struct form* form; char* s; - form = xcalloc(1, sizeof(struct form*)); + form = xcalloc(1, sizeof(*form)); if ((s = (char *) xmlGetProp(n, (const xmlChar *) "action"))) { form->action = s; diff --git a/render/box.h b/render/box.h index fb5e4c5bd..dbff18cf2 100644 --- a/render/box.h +++ b/render/box.h @@ -1,5 +1,5 @@ /** - * $Id: box.h,v 1.25 2003/05/22 13:21:45 bursa Exp $ + * $Id: box.h,v 1.26 2003/06/17 19:24:21 bursa Exp $ */ #ifndef _NETSURF_RENDER_BOX_H_ @@ -8,7 +8,9 @@ #include #include "libxml/HTMLparser.h" #include "netsurf/css/css.h" +#ifdef riscos #include "netsurf/riscos/font.h" +#endif /** * structures diff --git a/render/html.c b/render/html.c index 304de133c..ab6b55560 100644 --- a/render/html.c +++ b/render/html.c @@ -1,32 +1,29 @@ /** - * $Id: html.c,v 1.18 2003/06/05 13:17:55 philpem Exp $ + * $Id: html.c,v 1.19 2003/06/17 19:24:21 bursa Exp $ */ #include #include #include #include +#include "netsurf/content/content.h" #include "netsurf/content/fetch.h" #include "netsurf/content/fetchcache.h" +#ifdef riscos #include "netsurf/desktop/gui.h" +#endif #include "netsurf/render/html.h" #include "netsurf/render/layout.h" #include "netsurf/utils/utils.h" #include "netsurf/utils/log.h" -struct fetch_data { - struct content *c; - unsigned int i; -}; - - -static void html_convert_css_callback(fetchcache_msg msg, struct content *css, - void *p, const char *error); +static void html_convert_css_callback(content_msg msg, struct content *css, + void *p1, void *p2, const char *error); static void html_title(struct content *c, xmlNode *head); static void html_find_stylesheets(struct content *c, xmlNode *head); -static void html_image_callback(fetchcache_msg msg, struct content *image, - void *p, const char *error); +static void html_object_callback(content_msg msg, struct content *object, + void *p1, void *p2, const char *error); void html_create(struct content *c) @@ -43,6 +40,8 @@ void html_create(struct content *c) void html_process_data(struct content *c, char *data, unsigned long size) { unsigned long x; + LOG(("content %s, size %lu", c->url, size)); + cache_dump(); for (x = 0; x + CHUNK <= size; x += CHUNK) { htmlParseChunk(c->data.html.parser, data + x, CHUNK, 0); gui_multitask(); @@ -100,16 +99,19 @@ int html_convert(struct content *c, unsigned int width, unsigned int height) /* XML tree and stylesheets not required past this point */ xmlFreeDoc(document); - cache_free(c->data.html.stylesheet_content[0]); + content_remove_user(c->data.html.stylesheet_content[0], + html_convert_css_callback, c, 0); if (c->data.html.stylesheet_content[1] != 0) content_destroy(c->data.html.stylesheet_content[1]); for (i = 2; i != c->data.html.stylesheet_count; i++) if (c->data.html.stylesheet_content[i] != 0) - cache_free(c->data.html.stylesheet_content[i]); + content_remove_user(c->data.html.stylesheet_content[i], + html_convert_css_callback, c, i); xfree(c->data.html.stylesheet_content); /* layout the box tree */ - c->status_callback(c->status_p, "Formatting document"); + sprintf(c->status_message, "Formatting document"); + content_broadcast(c, CONTENT_MSG_STATUS, 0); LOG(("Layout document")); layout_document(c->data.html.layout->children, width); /*box_dump(c->data.html.layout->children, 0);*/ @@ -117,38 +119,53 @@ int html_convert(struct content *c, unsigned int width, unsigned int height) c->width = c->data.html.layout->children->width; c->height = c->data.html.layout->children->height; - if (c->active != 0) - c->status = CONTENT_PENDING; + if (c->active == 0) + c->status = CONTENT_STATUS_DONE; + else + c->status = CONTENT_STATUS_READY; return 0; } -void html_convert_css_callback(fetchcache_msg msg, struct content *css, - void *p, const char *error) +void html_convert_css_callback(content_msg msg, struct content *css, + void *p1, void *p2, const char *error) { - struct fetch_data *data = p; - struct content *c = data->c; - unsigned int i = data->i; + struct content *c = p1; + unsigned int i = (unsigned int) p2; switch (msg) { - case FETCHCACHE_OK: - free(data); + case CONTENT_MSG_LOADING: + /* check that the stylesheet is really CSS */ + if (css->type != CONTENT_CSS) { + c->data.html.stylesheet_content[i] = 0; + c->active--; + c->error = 1; + sprintf(c->status_message, "Warning: stylesheet is not CSS"); + content_broadcast(c, CONTENT_MSG_STATUS, 0); + content_remove_user(css, html_convert_css_callback, c, i); + } + break; + + case CONTENT_MSG_READY: + break; + + case CONTENT_MSG_DONE: LOG(("got stylesheet '%s'", css->url)); - c->data.html.stylesheet_content[i] = css; - /*css_dump_stylesheet(css->data.css);*/ c->active--; break; - case FETCHCACHE_BADTYPE: - case FETCHCACHE_ERROR: - free(data); + + case CONTENT_MSG_ERROR: c->data.html.stylesheet_content[i] = 0; c->active--; c->error = 1; break; - case FETCHCACHE_STATUS: - /* TODO: need to add a way of sending status to the - * owning window */ + + case CONTENT_MSG_STATUS: + sprintf(c->status_message, "Loading %u stylesheets: %s", + c->active, css->status_message); + content_broadcast(c, CONTENT_MSG_STATUS, 0); break; + default: assert(0); } @@ -177,9 +194,8 @@ void html_find_stylesheets(struct content *c, xmlNode *head) { xmlNode *node, *node2; char *rel, *type, *media, *href, *data, *url; - char status[80]; unsigned int i = 2; - struct fetch_data *fetch_data; + unsigned int last_active = 0; /* stylesheet 0 is the base style sheet, stylesheet 1 is any