[project @ 2003-06-17 19:24:20 by bursa]

Change fetchcache system to store loading contents in cache.

svn path=/import/netsurf/; revision=180
This commit is contained in:
James Bursa 2003-06-17 19:24:21 +00:00
parent ce6dbbb5db
commit 0c0ff3c596
24 changed files with 710 additions and 487 deletions

View File

@ -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));
LOG(("content %p, url '%s'", content, content->url));
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;
}
/* 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"));
}

View File

@ -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

View File

@ -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,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);
}
}

View File

@ -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

View File

@ -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;

View File

@ -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;
content_add_user(c, callback, p1, p2);
return c;
}
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);
}
}
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>

View File

@ -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

50
content/other.c Normal file
View File

@ -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);
}

17
content/other.h Normal file
View File

@ -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

52
content/overview Normal file
View File

@ -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().

View File

@ -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 <assert.h>
@ -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;

View File

@ -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:

View File

@ -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;

View File

@ -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 \

View File

@ -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 <assert.h>
@ -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;

View File

@ -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 <limits.h>
#include "libxml/HTMLparser.h"
#include "netsurf/css/css.h"
#ifdef riscos
#include "netsurf/riscos/font.h"
#endif
/**
* structures

View File

@ -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 <assert.h>
#include <string.h>
#include <strings.h>
#include <stdlib.h>
#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 <style> elements */
c->data.html.stylesheet_content = xcalloc(2, sizeof(*c->data.html.stylesheet_content));
@ -189,13 +205,17 @@ void html_find_stylesheets(struct content *c, xmlNode *head)
c->error = 0;
c->active = 0;
fetch_data = xcalloc(1, sizeof(*fetch_data));
fetch_data->c = c;
fetch_data->i = 0;
c->active++;
fetchcache("file:///%3CNetSurf$Dir%3E/Resources/CSS", c->url,
c->data.html.stylesheet_content[0] = fetchcache(
#ifdef riscos
"file:///%3CNetSurf$Dir%3E/Resources/CSS",
#else
"file:///home/james/Projects/netsurf/CSS",
#endif
c->url,
html_convert_css_callback,
fetch_data, c->width, c->height, 1 << CONTENT_CSS);
c, 0, c->width, c->height);
if (c->data.html.stylesheet_content[0]->status != CONTENT_STATUS_DONE)
c->active++;
for (node = head == 0 ? 0 : head->children; node != 0; node = node->next) {
if (strcmp(node->name, "link") == 0) {
@ -238,24 +258,23 @@ void html_find_stylesheets(struct content *c, xmlNode *head)
/* start fetch */
c->data.html.stylesheet_content = xrealloc(c->data.html.stylesheet_content,
(i + 1) * sizeof(*c->data.html.stylesheet_content));
fetch_data = xcalloc(1, sizeof(*fetch_data));
fetch_data->c = c;
fetch_data->i = i;
c->active++;
fetchcache(url, c->url, html_convert_css_callback,
fetch_data, c->width, c->height, 1 << CONTENT_CSS);
c->data.html.stylesheet_content[i] = fetchcache(url, c->url,
html_convert_css_callback, c, i,
c->width, c->height);
if (c->data.html.stylesheet_content[i]->status != CONTENT_STATUS_DONE)
c->active++;
free(url);
i++;
} else if (strcmp(node->name, "style") == 0) {
/* type='text/css' */
if (!(type = (char *) xmlGetProp(node, (const xmlChar *) "type")))
continue;
if (strcmp(type, "text/css") != 0) {
/* type='text/css', or not present (invalid but common) */
if ((type = (char *) xmlGetProp(node, (const xmlChar *) "type"))) {
if (strcmp(type, "text/css") != 0) {
xmlFree(type);
continue;
}
xmlFree(type);
continue;
}
xmlFree(type);
/* media contains 'screen' or 'all' or not present */
if ((media = (char *) xmlGetProp(node, (const xmlChar *) "media"))) {
@ -269,8 +288,10 @@ void html_find_stylesheets(struct content *c, xmlNode *head)
/* create stylesheet */
LOG(("style element"));
if (c->data.html.stylesheet_content[1] == 0)
c->data.html.stylesheet_content[1] = content_create(CONTENT_CSS, c->url);
if (c->data.html.stylesheet_content[1] == 0) {
c->data.html.stylesheet_content[1] = content_create(c->url);
content_set_type(c->data.html.stylesheet_content[1], CONTENT_CSS);
}
/* can't just use xmlNodeGetContent(node), because that won't give
* the content of comments which may be used to 'hide' the content */
@ -290,71 +311,80 @@ void html_find_stylesheets(struct content *c, xmlNode *head)
/* complete the fetches */
while (c->active != 0) {
if (c->status_callback != 0) {
sprintf(status, "Loading %u stylesheets", c->active);
c->status_callback(c->status_p, status);
if (c->active != last_active) {
sprintf(c->status_message, "Loading %u stylesheets", c->active);
content_broadcast(c, CONTENT_MSG_STATUS, 0);
last_active = c->active;
}
fetch_poll();
gui_multitask();
}
if (c->error) {
c->status_callback(c->status_p, "Warning: some stylesheets failed to load");
sprintf(c->status_message, "Warning: some stylesheets failed to load");
content_broadcast(c, CONTENT_MSG_STATUS, 0);
}
}
void html_fetch_image(struct content *c, char *url, struct box *box)
void html_fetch_object(struct content *c, char *url, struct box *box)
{
struct fetch_data *fetch_data;
unsigned int i = c->data.html.object_count;
/* add to object list */
c->data.html.object = xrealloc(c->data.html.object,
(c->data.html.object_count + 1) *
sizeof(*c->data.html.object));
c->data.html.object[c->data.html.object_count].url = url;
c->data.html.object[c->data.html.object_count].content = 0;
c->data.html.object[c->data.html.object_count].box = box;
(i + 1) * sizeof(*c->data.html.object));
c->data.html.object[i].url = url;
c->data.html.object[i].box = box;
/* start fetch */
fetch_data = xcalloc(1, sizeof(*fetch_data));
fetch_data->c = c;
fetch_data->i = c->data.html.object_count;
c->data.html.object[i].content = fetchcache(url, c->url,
html_object_callback,
c, i, 0, 0);
if (c->data.html.object[i].content->status != CONTENT_STATUS_DONE)
c->active++;
c->data.html.object_count++;
c->active++;
fetchcache(url, c->url,
html_image_callback,
fetch_data, 0, 0,
(1 << CONTENT_JPEG) | (1 << CONTENT_PNG) |
(1 << CONTENT_GIF));
}
void html_image_callback(fetchcache_msg msg, struct content *image,
void *p, const char *error)
void html_object_callback(content_msg msg, struct content *object,
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;
struct box *box = c->data.html.object[i].box;
switch (msg) {
case FETCHCACHE_OK:
LOG(("got image '%s'", image->url));
box->object = image;
c->data.html.object[i].content = image;
case CONTENT_MSG_LOADING:
if (CONTENT_OTHER <= c->type) {
c->data.html.object[i].content = 0;
c->active--;
c->error = 1;
sprintf(c->status_message, "Warning: bad object type");
content_broadcast(c, CONTENT_MSG_STATUS, 0);
content_remove_user(object, html_object_callback, c, i);
}
break;
case CONTENT_MSG_READY:
break;
case CONTENT_MSG_DONE:
LOG(("got object '%s'", object->url));
box->object = object;
/* set dimensions to object dimensions if auto */
if (box->style->width.width == CSS_WIDTH_AUTO) {
box->style->width.width = CSS_WIDTH_LENGTH;
box->style->width.value.length.unit = CSS_UNIT_PX;
box->style->width.value.length.value = image->width;
box->min_width = box->max_width = box->width = image->width;
box->style->width.value.length.value = object->width;
box->min_width = box->max_width = box->width = object->width;
/* invalidate parent min, max widths */
if (box->parent->max_width != UNKNOWN_MAX_WIDTH) {
struct box *b = box->parent;
if (b->min_width < image->width)
b->min_width = image->width;
if (b->max_width < image->width)
b->max_width = image->width;
if (b->min_width < object->width)
b->min_width = object->width;
if (b->max_width < object->width)
b->max_width = object->width;
for (b = b->parent;
b != 0 && b->max_width != UNKNOWN_MAX_WIDTH;
b = b->parent)
@ -364,7 +394,7 @@ void html_image_callback(fetchcache_msg msg, struct content *image,
if (box->style->height.height == CSS_HEIGHT_AUTO) {
box->style->height.height = CSS_HEIGHT_LENGTH;
box->style->height.length.unit = CSS_UNIT_PX;
box->style->height.length.value = image->height;
box->style->height.length.value = object->height;
}
/* remove alt text */
if (box->text != 0) {
@ -377,49 +407,53 @@ void html_image_callback(fetchcache_msg msg, struct content *image,
box->children = 0;
}*/
/* TODO: recalculate min, max width */
/* drop through */
case FETCHCACHE_BADTYPE:
case FETCHCACHE_ERROR:
if (c->active == 1 && c->status == CONTENT_PENDING) {
/* all images have arrived */
content_reformat(c, c->available_width, 0);
/*box_dump(c->data.html.layout->children, 0);*/
}
c->active--;
if (c->active == 0)
sprintf(c->status_message, "Document done");
else
sprintf(c->status_message, "Loading %i images", c->active);
free(data);
break;
case FETCHCACHE_STATUS:
/* TODO: need to add a way of sending status to the
* owning window */
case CONTENT_MSG_ERROR:
c->data.html.object[i].content = 0;
c->active--;
c->error = 1;
sprintf(c->status_message, "Image error: %s", error);
content_broadcast(c, CONTENT_MSG_STATUS, 0);
break;
case CONTENT_MSG_STATUS:
sprintf(c->status_message, "Loading %i objects: %s",
c->active, object->status_message);
break;
default:
assert(0);
}
LOG(("%i active", c->active));
if (c->active == 0) {
/* all objects have arrived */
content_reformat(c, c->available_width, 0);
c->status = CONTENT_STATUS_DONE;
content_broadcast(c, CONTENT_MSG_DONE, 0);
}
if (c->active == 0)
sprintf(c->status_message, "Document done");
else
sprintf(c->status_message, "Loading %i objects", c->active);
}
void html_revive(struct content *c, unsigned int width, unsigned int height)
{
unsigned int i;
struct fetch_data *fetch_data;
/* reload images and fix pointers */
/* reload objects and fix pointers */
for (i = 0; i != c->data.html.object_count; i++) {
if (c->data.html.object[i].content != 0) {
fetch_data = xcalloc(1, sizeof(*fetch_data));
fetch_data->c = c;
fetch_data->i = i;
c->active++;
fetchcache(c->data.html.object[i].url, c->url,
html_image_callback,
fetch_data, 0, 0,
(1 << CONTENT_JPEG) |
(1 << CONTENT_PNG) |
(1 << CONTENT_GIF));
c->data.html.object[i].content = fetchcache(
c->data.html.object[i].url, c->url,
html_object_callback,
c, i, 0, 0);
if (c->data.html.object[i].content->status != CONTENT_STATUS_DONE)
c->active++;
}
}
@ -428,7 +462,7 @@ void html_revive(struct content *c, unsigned int width, unsigned int height)
c->height = c->data.html.layout->children->height;
if (c->active != 0)
c->status = CONTENT_PENDING;
c->status = CONTENT_STATUS_READY;
}
@ -458,7 +492,8 @@ void html_destroy(struct content *c)
for (i = 0; i != c->data.html.object_count; i++) {
LOG(("object %i %p", i, c->data.html.object[i].content));
if (c->data.html.object[i].content != 0)
cache_free(c->data.html.object[i].content);
content_remove_user(c->data.html.object[i].content,
html_object_callback, c, i);
free(c->data.html.object[i].url);
}
free(c->data.html.object);

View File

@ -1,5 +1,5 @@
/**
* $Id: html.h,v 1.2 2003/04/15 17:53:00 bursa Exp $
* $Id: html.h,v 1.3 2003/06/17 19:24:21 bursa Exp $
*/
#ifndef _NETSURF_RENDER_HTML_H_
@ -13,6 +13,6 @@ int html_convert(struct content *c, unsigned int width, unsigned int height);
void html_revive(struct content *c, unsigned int width, unsigned int height);
void html_reformat(struct content *c, unsigned int width, unsigned int height);
void html_destroy(struct content *c);
void html_fetch_image(struct content *c, char *url, struct box *box);
void html_fetch_object(struct content *c, char *url, struct box *box);
#endif

View File

@ -1,5 +1,5 @@
/**
* $Id: layout.c,v 1.40 2003/04/15 17:53:00 bursa Exp $
* $Id: layout.c,v 1.41 2003/06/17 19:24:21 bursa Exp $
*/
#include <assert.h>
@ -8,11 +8,18 @@
#include <stdlib.h>
#include <string.h>
#include "libxml/HTMLparser.h"
#ifdef riscos
#include "netsurf/desktop/gui.h"
#endif
#include "netsurf/content/content.h"
#include "netsurf/render/box.h"
#include "netsurf/css/css.h"
#include "netsurf/render/layout.h"
#ifdef riscos
#include "netsurf/riscos/font.h"
#else
#include "netsurf/debug/font.h"
#endif
#include "netsurf/utils/utils.h"
#define NDEBUG
#include "netsurf/utils/log.h"

View File

@ -10,7 +10,7 @@
* Add better error handling
* - especially where bad GIFs are concerned.
*
* $Id: gif.c,v 1.6 2003/06/07 13:07:48 philpem Exp $
* $Id: gif.c,v 1.7 2003/06/17 19:24:21 bursa Exp $
*/
#include <assert.h>
@ -274,6 +274,7 @@ int nsgif_convert(struct content *c, unsigned int iwidth, unsigned int iheight)
c->title = xcalloc(100, 1);
sprintf(c->title, "GIF image (%lux%lu)", c->width, c->height);
c->status = CONTENT_STATUS_DONE;
// Enable this if you want to debug the GIF loader
// xosspriteop_save_sprite_file(osspriteop_USER_AREA, c->data.gif.sprite_area,

View File

@ -1,5 +1,5 @@
/**
* $Id: gui.c,v 1.32 2003/06/14 11:34:02 bursa Exp $
* $Id: gui.c,v 1.33 2003/06/17 19:24:21 bursa Exp $
*/
#include "netsurf/desktop/options.h"
@ -1170,19 +1170,6 @@ void ro_gui_throb(void)
{
if (g->type == GUI_BROWSER_WINDOW)
{
if (g->data.browser.bw->current_content->status == CONTENT_PENDING) {
/* images still loading */
gui_window_set_status(g, g->data.browser.bw->current_content->status_message);
if (g->data.browser.bw->current_content->active == 0) {
/* any image fetches have finished */
browser_window_reformat(g->data.browser.bw);
browser_window_stop_throbber(g->data.browser.bw);
/* TODO: move this elsewhere: can't just move it to the image loader,
* because then this if would be triggered when an old content is
* present */
g->data.browser.bw->current_content->status = CONTENT_DONE;
}
}
if ((g->data.browser.bw->flags & browser_TOOLBAR) != 0)
{
if (g->data.browser.bw->throbbing != 0)

View File

@ -1,5 +1,5 @@
/**
* $Id: jpeg.c,v 1.5 2003/06/14 11:34:02 bursa Exp $
* $Id: jpeg.c,v 1.6 2003/06/17 19:24:21 bursa Exp $
*
* This is just a temporary implementation using the JPEG renderer
* available in some versions of RISC OS.
@ -42,6 +42,7 @@ int jpeg_convert(struct content *c, unsigned int width, unsigned int height)
c->height = h;
c->title = xcalloc(100, 1);
sprintf(c->title, "JPEG image (%ux%u, %lu bytes)", w, h, c->data.jpeg.length);
c->status = CONTENT_STATUS_DONE;
return 0;
}

View File

@ -1,5 +1,5 @@
/**
* $Id: plugin.c,v 1.9 2003/06/07 22:24:22 jmb Exp $
* $Id: plugin.c,v 1.10 2003/06/17 19:24:21 bursa Exp $
*/
#include <assert.h>
@ -156,7 +156,7 @@ void plugin_decode(struct content* content, char* url, struct box* box,
*/
xfree(po);
LOG(("sending data to image handler"));
html_fetch_image(content, url, box);
html_fetch_object(content, url, box);
return;
}
else { /* not an image; is sys var set? */

View File

@ -1,5 +1,5 @@
/**
* $Id: png.c,v 1.3 2003/06/14 11:34:02 bursa Exp $
* $Id: png.c,v 1.4 2003/06/17 19:24:21 bursa Exp $
*/
#include <assert.h>
@ -259,6 +259,7 @@ int nspng_convert(struct content *c, unsigned int width, unsigned int height)
png_destroy_read_struct(&c->data.png.png, &c->data.png.info, 0);
c->title = xcalloc(100, 1);
sprintf(c->title, "png image (%ux%u)", c->width, c->height);
c->status = CONTENT_STATUS_DONE;
return 0;
}