summaryrefslogtreecommitdiff
path: root/content
diff options
context:
space:
mode:
Diffstat (limited to 'content')
-rw-r--r--content/cache.c78
-rw-r--r--content/cache.h38
-rw-r--r--content/content.c174
-rw-r--r--content/content.h70
-rw-r--r--content/fetch.c10
-rw-r--r--content/fetchcache.c198
-rw-r--r--content/fetchcache.h11
-rw-r--r--content/other.c50
-rw-r--r--content/other.h17
-rw-r--r--content/overview52
10 files changed, 433 insertions, 265 deletions
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 <assert.h>
@@ -11,7 +11,7 @@
#include "netsurf/utils/log.h"
#ifndef TEST
-#include "netsurf/desktop/browser.h"
+#include "netsurf/content/content.h"
#else
#include <unistd.h>
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 <assert.h>
#include <string.h>
#include <stdlib.h>
#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,34 +83,55 @@ 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
*/
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 <assert.h>
#include <string.h>
#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 <unistd.h>
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 <assert.h>
+#include <string.h>
+#include <stdlib.h>
+#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().
+