summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDaniel Silverstone <dsilvers@netsurf-browser.org>2010-03-28 12:56:39 +0000
committerDaniel Silverstone <dsilvers@netsurf-browser.org>2010-03-28 12:56:39 +0000
commit270ef59a98d34fef418fb6cd27e46f3edc912948 (patch)
tree9d363b42d441640e1d2dbff3ba548a2cdf8d67a9
parent21da4f5bdf74c6654730c32dfcc1c6b3d24da4b4 (diff)
downloadnetsurf-270ef59a98d34fef418fb6cd27e46f3edc912948.tar.gz
netsurf-270ef59a98d34fef418fb6cd27e46f3edc912948.tar.bz2
Merge jmb/new-cache; r=dsilvers,rs=vince
svn path=/trunk/netsurf/; revision=10180
-rw-r--r--Makefile.sources4
-rw-r--r--amiga/download.c9
-rwxr-xr-xamiga/fetch_file.c20
-rw-r--r--beos/beos_fetch_rsrc.cpp17
-rw-r--r--beos/beos_gui.cpp13
-rw-r--r--content/content.c999
-rw-r--r--content/content.h295
-rw-r--r--content/content_protected.h221
-rw-r--r--content/fetch.c79
-rw-r--r--content/fetch.h18
-rw-r--r--content/fetchcache.c4
-rw-r--r--content/fetchcache.h6
-rw-r--r--content/fetchers/fetch_curl.c110
-rw-r--r--content/fetchers/fetch_data.c32
-rw-r--r--content/hlcache.c362
-rw-r--r--content/hlcache.h110
-rw-r--r--content/llcache.c1815
-rw-r--r--content/llcache.h238
-rw-r--r--css/css.c434
-rw-r--r--css/css.h20
-rw-r--r--css/internal.c7
-rw-r--r--css/internal.h4
-rw-r--r--css/select.c43
-rw-r--r--css/select.h2
-rw-r--r--desktop/401login.h6
-rw-r--r--desktop/browser.c726
-rw-r--r--desktop/browser.h63
-rw-r--r--desktop/frames.c15
-rw-r--r--desktop/gui.h13
-rw-r--r--desktop/history_core.c28
-rw-r--r--desktop/history_core.h6
-rw-r--r--desktop/netsurf.c81
-rw-r--r--desktop/netsurf.h1
-rw-r--r--desktop/print.c42
-rw-r--r--desktop/print.h8
-rw-r--r--desktop/save_complete.c150
-rw-r--r--desktop/save_complete.h4
-rw-r--r--desktop/save_pdf/pdf_plotters.c42
-rw-r--r--desktop/save_text.c7
-rw-r--r--desktop/save_text.h4
-rw-r--r--desktop/search.c32
-rw-r--r--desktop/searchweb.c58
-rw-r--r--desktop/searchweb.h11
-rw-r--r--desktop/selection.c14
-rw-r--r--desktop/textinput.c7
-rw-r--r--framebuffer/gui.c90
-rw-r--r--framebuffer/hotlist.c2
-rw-r--r--framebuffer/login.c2
-rw-r--r--framebuffer/thumbnail.c2
-rw-r--r--gtk/dialogs/gtk_options.c2
-rw-r--r--gtk/dialogs/gtk_source.c44
-rw-r--r--gtk/gtk_gui.c20
-rw-r--r--gtk/gtk_login.c7
-rw-r--r--gtk/gtk_print.c3
-rw-r--r--gtk/gtk_print.h4
-rw-r--r--gtk/gtk_scaffolding.c171
-rw-r--r--gtk/gtk_search.c6
-rw-r--r--gtk/gtk_theme.c29
-rw-r--r--gtk/gtk_thumbnail.c19
-rw-r--r--gtk/gtk_toolbar.c7
-rw-r--r--gtk/gtk_window.c15
-rw-r--r--image/bmp.c13
-rw-r--r--image/bmp.h4
-rw-r--r--image/gif.c37
-rw-r--r--image/gif.h4
-rw-r--r--image/ico.c49
-rw-r--r--image/ico.h8
-rw-r--r--image/jpeg.c12
-rw-r--r--image/mng.c31
-rw-r--r--image/mng.h4
-rw-r--r--image/nssprite.c11
-rw-r--r--image/png.c12
-rw-r--r--image/png.h4
-rw-r--r--image/rsvg.c5
-rw-r--r--image/rsvg.h4
-rw-r--r--image/svg.c2
-rw-r--r--image/svg.h4
-rw-r--r--render/box.c76
-rw-r--r--render/box.h10
-rw-r--r--render/box_construct.c6
-rw-r--r--render/directory.c16
-rw-r--r--render/directory.h4
-rw-r--r--render/favicon.c163
-rw-r--r--render/favicon.h3
-rw-r--r--render/form.c31
-rw-r--r--render/form.h13
-rw-r--r--render/html.c925
-rw-r--r--render/html.h43
-rw-r--r--render/html_redraw.c157
-rw-r--r--render/imagemap.c20
-rw-r--r--render/imagemap.h4
-rw-r--r--render/layout.c118
-rw-r--r--render/textplain.c112
-rw-r--r--render/textplain.h20
-rw-r--r--riscos/gui.c10
-rw-r--r--riscos/window.c8
-rw-r--r--test/Makefile19
-rw-r--r--test/llcache.c282
-rw-r--r--utils/errors.h40
-rw-r--r--utils/http.c390
-rw-r--r--utils/http.h73
-rw-r--r--windows/bitmap.c10
-rw-r--r--windows/gui.c62
-rw-r--r--windows/hotlist.c3
-rw-r--r--windows/login.c3
-rw-r--r--windows/thumbnail.c33
106 files changed, 6574 insertions, 2887 deletions
diff --git a/Makefile.sources b/Makefile.sources
index ec7edc7a5..2e09a3d1a 100644
--- a/Makefile.sources
+++ b/Makefile.sources
@@ -5,13 +5,13 @@
# for each build.
#
-S_CONTENT := content.c fetch.c fetchcache.c urldb.c \
+S_CONTENT := content.c fetch.c hlcache.c llcache.c urldb.c \
fetchers/fetch_curl.c fetchers/fetch_data.c
S_CSS := css.c dump.c internal.c select.c utils.c
S_RENDER := box.c box_construct.c box_normalise.c directory.c favicon.c \
font.c form.c html.c html_redraw.c hubbub_binding.c imagemap.c \
layout.c list.c table.c textplain.c
-S_UTILS := base64.c filename.c hashtable.c locale.c \
+S_UTILS := base64.c filename.c hashtable.c http.c locale.c \
messages.c talloc.c url.c utf8.c utils.c useragent.c
S_DESKTOP := knockout.c options.c plot_style.c print.c search.c \
searchweb.c scroll.c textarea.c tree.c version.c
diff --git a/amiga/download.c b/amiga/download.c
index 2172fb8cc..064923eff 100644
--- a/amiga/download.c
+++ b/amiga/download.c
@@ -252,14 +252,15 @@ void ami_free_download_list(struct List *dllist)
}while(node=nnode);
}
-void gui_window_save_as_link(struct gui_window *g, struct content *c)
+void
+gui_window_save_link(struct gui_window *g, const char *url, const char *title)
{
BPTR fh = 0;
char fname[1024];
STRPTR openurlstring,linkname;
struct DiskObject *dobj = NULL;
- linkname = ASPrintf("Link_to_%s",FilePart(c->url));
+ linkname = ASPrintf("Link_to_%s",FilePart(url));
if(AslRequestTags(savereq,
ASLFR_TitleText,messages_get("NetSurf"),
@@ -272,11 +273,11 @@ void gui_window_save_as_link(struct gui_window *g, struct content *c)
ami_update_pointer(g->shared->win,GUI_POINTER_WAIT);
if(fh = FOpen(fname,MODE_NEWFILE,0))
{
- openurlstring = ASPrintf("openurl \"%s\"\n",c->url);
+ openurlstring = ASPrintf("openurl \"%s\"\n",url);
FWrite(fh,openurlstring,1,strlen(openurlstring));
FClose(fh);
FreeVec(openurlstring);
- SetComment(fname,c->url);
+ SetComment(fname,url);
dobj = GetIconTags(NULL,ICONGETA_GetDefaultName,"url",
ICONGETA_GetDefaultType,WBPROJECT,
diff --git a/amiga/fetch_file.c b/amiga/fetch_file.c
index 953478423..bc03962ab 100755
--- a/amiga/fetch_file.c
+++ b/amiga/fetch_file.c
@@ -56,7 +56,7 @@ static bool ami_fetch_file_initialise(const char *scheme);
static void ami_fetch_file_finalise(const char *scheme);
static void * ami_fetch_file_setup(struct fetch *parent_fetch, const char *url,
bool only_2xx, const char *post_urlenc,
- struct form_successful_control *post_multipart,
+ struct fetch_multipart_data *post_multipart,
const char **headers);
static bool ami_fetch_file_start(void *vfetch);
static void ami_fetch_file_abort(void *vf);
@@ -135,7 +135,7 @@ void ami_fetch_file_finalise(const char *scheme)
void * ami_fetch_file_setup(struct fetch *parent_fetch, const char *url,
bool only_2xx, const char *post_urlenc,
- struct form_successful_control *post_multipart,
+ struct fetch_multipart_data *post_multipart,
const char **headers)
{
struct ami_file_fetch_info *fetch;
@@ -280,6 +280,7 @@ void ami_fetch_file_poll(const char *scheme_ignored)
if(fetch->fh)
{
+ char header[64];
struct ExamineData *fib;
if(fib = ExamineObjectTags(EX_FileHandleInput,fetch->fh,TAG_DONE))
{
@@ -291,9 +292,18 @@ void ami_fetch_file_poll(const char *scheme_ignored)
fetch->mimetype = fetch_mimetype(fetch->path);
LOG(("mimetype %s len %ld",fetch->mimetype,fetch->len));
- ami_fetch_file_send_callback(FETCH_TYPE,
- fetch, fetch->mimetype, (ULONG)fetch->len,
- errorcode);
+ snprintf(header, sizeof header,
+ "Content-Type: %s",
+ fetch->mimetype);
+ ami_fetch_file_send_callback(FETCH_HEADER,
+ fetch, header, strlen(header), errorcode);
+
+ snprintf(header, sizeof header,
+ "Content-Length: %ld",
+ fetch->len);
+ ami_fetch_file_send_callback(FETCH_HEADER,
+ fetch, header, strlen(header), errorcode);
+
}
else
{
diff --git a/beos/beos_fetch_rsrc.cpp b/beos/beos_fetch_rsrc.cpp
index 89916cb08..8b2fa5e60 100644
--- a/beos/beos_fetch_rsrc.cpp
+++ b/beos/beos_fetch_rsrc.cpp
@@ -38,7 +38,6 @@ extern "C" {
#include "content/urldb.h"
#include "desktop/netsurf.h"
#include "desktop/options.h"
-#include "render/form.h"
#include "utils/log.h"
#include "utils/messages.h"
#include "utils/url.h"
@@ -83,7 +82,7 @@ static void fetch_rsrc_finalise(const char *scheme)
static void *fetch_rsrc_setup(struct fetch *parent_fetch, const char *url,
bool only_2xx, const char *post_urlenc,
- struct form_successful_control *post_multipart,
+ struct fetch_multipart_data *post_multipart,
const char **headers)
{
struct fetch_rsrc_context *ctx;
@@ -277,6 +276,8 @@ static void fetch_rsrc_poll(const char *scheme)
/* Only process non-aborted fetches */
if (!c->aborted && fetch_rsrc_process(c) == true) {
+ char header[64];
+
fetch_set_http_code(c->parent_fetch, 200);
LOG(("setting rsrc: MIME type to %s, length to %zd",
c->mimetype, c->datalen));
@@ -284,8 +285,16 @@ static void fetch_rsrc_poll(const char *scheme)
* Therefore, we _must_ check for this after _every_
* call to fetch_rsrc_send_callback().
*/
- fetch_rsrc_send_callback(FETCH_TYPE,
- c, c->mimetype, c->datalen, FETCH_ERROR_NO_ERROR);
+ snprintf(header, sizeof header, "Content-Type: %s",
+ c->mimetype);
+ fetch_rsrc_send_callback(FETCH_HEADER, c, header,
+ strlen(header), FETCH_ERROR_NO_ERROR);
+
+ snprintf(header, sizeof header, "Content-Length: %zd",
+ c->datalen);
+ fetch_rsrc_send_callback(FETCH_HEADER, c, header,
+ strlen(header), FETCH_ERROR_NO_ERROR);
+
if (!c->aborted) {
fetch_rsrc_send_callback(FETCH_DATA,
c, c->data, c->datalen, FETCH_ERROR_NO_ERROR);
diff --git a/beos/beos_gui.cpp b/beos/beos_gui.cpp
index 6c05bc401..90db0ff94 100644
--- a/beos/beos_gui.cpp
+++ b/beos/beos_gui.cpp
@@ -424,7 +424,15 @@ static int32 bapp_thread(void *arg)
int main(int argc, char** argv)
{
setbuf(stderr, NULL);
- return netsurf_main(argc, argv);
+
+ /* initialise netsurf */
+ netsurf_init(argc, argv);
+
+ netsurf_main_loop();
+
+ netsurf_exit();
+
+ return 0;
}
void gui_init(int argc, char** argv)
@@ -843,7 +851,8 @@ void gui_create_form_select_menu(struct browser_window *bw,
#endif
}
-void gui_window_save_as_link(struct gui_window *g, struct content *c)
+void
+gui_window_save_link(struct gui_window *g, const char *url, const char *title)
{
}
diff --git a/content/content.c b/content/content.c
index 8b6cfd47d..1d7345207 100644
--- a/content/content.c
+++ b/content/content.c
@@ -32,9 +32,9 @@
#include <strings.h>
#include <time.h>
#include "utils/config.h"
-#include "content/content.h"
-#include "content/fetch.h"
+#include "content/content_protected.h"
#include "content/fetchcache.h"
+#include "content/hlcache.h"
#include "css/css.h"
#include "image/bitmap.h"
#include "desktop/options.h"
@@ -78,16 +78,13 @@
#ifdef WITH_PNG
#include "image/png.h"
#endif
+#include "utils/http.h"
#include "utils/log.h"
#include "utils/messages.h"
#include "utils/talloc.h"
#include "utils/utils.h"
-/** Linked list of all content structures. May include more than one content
- * per URL. Doubly-linked. */
-struct content *content_list = 0;
-
/** An entry in mime_map. */
struct mime_entry {
char mime_type[40];
@@ -250,8 +247,7 @@ const char * const content_status_name[] = {
/** An entry in handler_map. */
struct handler_entry {
- bool (*create)(struct content *c, struct content *parent,
- const char *params[]);
+ bool (*create)(struct content *c, const http_parameter *params);
bool (*process_data)(struct content *c, char *data, unsigned int size);
bool (*convert)(struct content *c, int width, int height);
void (*reformat)(struct content *c, int width, int height);
@@ -359,16 +355,16 @@ static const struct handler_entry handler_map[] = {
};
#define HANDLER_MAP_COUNT (sizeof(handler_map) / sizeof(handler_map[0]))
-
+static nserror content_llcache_callback(llcache_handle *llcache,
+ const llcache_event *event, void *pw);
+static void content_convert(struct content *c, int width, int height);
static void content_update_status(struct content *c);
-static void content_destroy(struct content *c);
-static void content_stop_check(struct content *c);
/**
* Convert a MIME type to a content_type.
*
- * The returned ::content_type will always be suitable for content_set_type().
+ * The returned ::content_type will always be suitable for content_create().
*/
content_type content_lookup(const char *mime_type)
@@ -397,289 +393,188 @@ content_type content_lookup(const char *mime_type)
* CONTENT_STATUS_TYPE_UNKNOWN.
*/
-struct content * content_create(const char *url)
+struct content * content_create(llcache_handle *llcache,
+ const char *fallback_charset, bool quirks)
{
struct content *c;
struct content_user *user_sentinel;
+ const char *content_type_header;
+ content_type type;
+ char *mime_type;
+ http_parameter *params;
+ nserror error;
+
+ content_type_header =
+ llcache_handle_get_header(llcache, "Content-Type");
+ if (content_type_header == NULL)
+ content_type_header = "text/plain";
+
+ error = http_parse_content_type(content_type_header, &mime_type,
+ &params);
+ if (error != NSERROR_OK)
+ return NULL;
+
+ type = content_lookup(mime_type);
+ if (type == CONTENT_OTHER) {
+ http_parameter_list_destroy(params);
+ free(mime_type);
+ return NULL;
+ }
c = talloc_zero(0, struct content);
- if (!c)
- return 0;
+ if (c == NULL) {
+ http_parameter_list_destroy(params);
+ free(mime_type);
+ return NULL;
+ }
- LOG(("url %s -> %p", url, c));
+ LOG(("url %s -> %p", llcache_handle_get_url(llcache), c));
user_sentinel = talloc(c, struct content_user);
- if (!user_sentinel) {
+ if (user_sentinel == NULL) {
talloc_free(c);
- return 0;
+ http_parameter_list_destroy(params);
+ free(mime_type);
+ return NULL;
}
- c->url = talloc_strdup(c, url);
- if (!c->url) {
+
+ c->fallback_charset = talloc_strdup(c, fallback_charset);
+ if (fallback_charset != NULL && c->fallback_charset == NULL) {
talloc_free(c);
- return 0;
+ http_parameter_list_destroy(params);
+ free(mime_type);
+ return NULL;
}
- talloc_set_name_const(c, c->url);
- c->type = CONTENT_UNKNOWN;
- c->mime_type = 0;
- c->status = CONTENT_STATUS_TYPE_UNKNOWN;
+
+ c->mime_type = talloc_strdup(c, mime_type);
+ if (c->mime_type == NULL) {
+ talloc_free(c);
+ http_parameter_list_destroy(params);
+ free(mime_type);
+ return NULL;
+ }
+
+ /* No longer require mime_type */
+ free(mime_type);
+
+ c->llcache = llcache;
+ c->type = type;
+ c->status = CONTENT_STATUS_LOADING;
c->width = 0;
c->height = 0;
c->available_width = 0;
+ c->quirks = quirks;
c->refresh = 0;
- c->bitmap = 0;
+ c->bitmap = NULL;
c->fresh = false;
c->time = wallclock();
c->size = 0;
- c->title = 0;
+ c->title = NULL;
c->active = 0;
- user_sentinel->callback = 0;
- user_sentinel->p1 = user_sentinel->p2 = 0;
- user_sentinel->next = 0;
+ user_sentinel->callback = NULL;
+ user_sentinel->pw = NULL;
+ user_sentinel->next = NULL;
c->user_list = user_sentinel;
c->sub_status[0] = 0;
c->locked = false;
- c->fetch = 0;
- c->source_data = 0;
- c->source_size = 0;
- c->source_allocated = 0;
c->total_size = 0;
c->http_code = 0;
- c->no_error_pages = false;
- c->download = false;
- c->tried_with_auth = false;
- c->redirect_count = 0;
c->error_count = 0;
- c->cache_data.req_time = 0;
- c->cache_data.res_time = 0;
- c->cache_data.date = 0;
- c->cache_data.expires = 0;
- c->cache_data.age = INVALID_AGE;
- c->cache_data.max_age = INVALID_AGE;
- c->cache_data.no_cache = false;
- c->cache_data.etag = 0;
- c->cache_data.last_modified = 0;
content_set_status(c, messages_get("Loading"));
- c->prev = 0;
- c->next = content_list;
- if (content_list)
- content_list->prev = c;
- content_list = c;
-
- return c;
-}
-
-
-/**
- * Get a content from the memory cache.
- *
- * \param url URL of content
- * \return content if found, or 0
- *
- * Searches the list of contents for one corresponding to the given url, and
- * which is fresh and shareable.
- */
+ if (handler_map[type].create) {
+ if (handler_map[type].create(c, params) == false) {
+ talloc_free(c);
+ http_parameter_list_destroy(params);
+ return NULL;
+ }
+ }
-struct content * content_get(const char *url)
-{
- struct content *c;
+ http_parameter_list_destroy(params);
- for (c = content_list; c; c = c->next) {
- if (!c->fresh)
- /* not fresh */
- continue;
- if (c->status == CONTENT_STATUS_ERROR)
- /* error state */
- continue;
- /** \todo We need to reconsider the entire caching strategy in
- * the light of data being shared between specific contents.
- *
- * For example, string dictionaries are owned by the document,
- * and all stylesheets used by the document share the same
- * dictionary.
- *
- * The CSS content handler retrieves the dictionary from its
- * parent content. This relies upon there being a 1:1 mapping
- * between documents and stylesheets.
- *
- * The type of a content is only known once we've received the
- * headers from the fetch layer (and potentially some of the
- * content data, too, if we ever sniff for the type). There
- * is thus a problem with returning contents of unknown type
- * here -- when we subsequently discover that they must only
- * have one user, we clone them. By that point, however, we've
- * no idea what the parent content is, which means that they
- * end up with the wrong parent (and thus wrong dictionary).
- *
- * Of course, the problem with ignoring unknown content types
- * here is that, for all the content types which may be shared,
- * we end up duplicating them and wasting memory. Hence the
- * need to reconsider everything.
- */
- if (c->type == CONTENT_UNKNOWN)
- continue;
- if (c->type != CONTENT_UNKNOWN &&
- handler_map[c->type].no_share &&
- c->user_list->next)
- /* not shareable, and has a user already */
- continue;
- if (strcmp(c->url, url))
- continue;
- return c;
+ /* Finally, claim low-level cache events */
+ if (llcache_handle_change_callback(llcache,
+ content_llcache_callback, c) != NSERROR_OK) {
+ talloc_free(c);
+ return NULL;
}
- return 0;
+ return c;
}
-
/**
- * Get a READY or DONE content from the memory cache.
- *
- * \param url URL of content
- * \return content if found, or 0
+ * Handler for low-level cache events
*
- * Searches the list of contents for one corresponding to the given url, and
- * which is fresh, shareable and either READY or DONE.
+ * \param llcache Low-level cache handle
+ * \param event Event details
+ * \param pw Pointer to our context
+ * \return NSERROR_OK on success, appropriate error otherwise
*/
-
-struct content * content_get_ready(const char *url)
+nserror content_llcache_callback(llcache_handle *llcache,
+ const llcache_event *event, void *pw)
{
- struct content *c;
+ struct content *c = pw;
+ union content_msg_data msg_data;
+ nserror error = NSERROR_OK;
+
+ switch (event->type) {
+ case LLCACHE_EVENT_HAD_HEADERS:
+ /* Will never happen: handled in hlcache */
+ break;
+ case LLCACHE_EVENT_HAD_DATA:
+ if (handler_map[c->type].process_data) {
+ if (handler_map[c->type].process_data(c,
+ (char *) event->data.data.buf,
+ event->data.data.len) == false) {
+ c->status = CONTENT_STATUS_ERROR;
+ /** \todo It's not clear what error this is */
+ error = NSERROR_NOMEM;
+ }
+ }
+ break;
+ case LLCACHE_EVENT_DONE:
+ {
+ const uint8_t *source;
+ size_t source_size;
+
+ source = llcache_handle_get_source_data(llcache, &source_size);
- for (c = content_list; c; c = c->next) {
- if (!c->fresh)
- /* not fresh */
- continue;
- if (c->status != CONTENT_STATUS_READY &&
- c->status != CONTENT_STATUS_DONE)
- /* not ready or done */
- continue;
- if (c->type != CONTENT_UNKNOWN &&
- handler_map[c->type].no_share &&
- c->user_list->next)
- /* not shareable, and has a user already */
- continue;
- if (strcmp(c->url, url))
- continue;
- return c;
+ content_set_status(c, messages_get("Converting"), source_size);
+ content_broadcast(c, CONTENT_MSG_STATUS, msg_data);
+
+ content_convert(c, c->width, c->height);
+ }
+ break;
+ case LLCACHE_EVENT_ERROR:
+ /** \todo Error page? */
+ c->status = CONTENT_STATUS_ERROR;
+ msg_data.error = event->data.msg;
+ content_broadcast(c, CONTENT_MSG_ERROR, msg_data);
+ break;
+ case LLCACHE_EVENT_PROGRESS:
+ content_set_status(c, "%s", event->data.msg);
+ content_broadcast(c, CONTENT_MSG_STATUS, msg_data);
+ break;
}
- return 0;
+ return error;
}
-
/**
* Get whether a content can reformat
*
- * \param c content to check
+ * \param h content to check
* \return whether the content can reformat
*/
-bool content_can_reformat(struct content *c)
+bool content_can_reformat(hlcache_handle *h)
{
- return (handler_map[c->type].reformat != NULL);
-}
-
+ struct content *c = hlcache_handle_get_content(h);
-/**
- * Initialise the content for the specified type.
- *
- * \param c content structure
- * \param type content_type to initialise to
- * \param mime_type MIME-type string for this content
- * \param params array of strings, ordered attribute, value, attribute, ..., 0
- * \return true on success, false on error and error broadcast to users and
- * possibly reported
- *
- * The type is updated to the given type, and a copy of mime_type is taken. The
- * status is changed to CONTENT_STATUS_LOADING. CONTENT_MSG_LOADING is sent to
- * all users. The create function for the type is called to initialise the type
- * specific parts of the content structure.
- */
-
-bool content_set_type(struct content *c, content_type type,
- const char *mime_type, const char *params[],
- struct content *parent)
-{
- union content_msg_data msg_data;
- struct content *clone;
- void (*callback)(content_msg msg, struct content *c, intptr_t p1,
- intptr_t p2, union content_msg_data data);
- intptr_t p1, p2;
-
- assert(c != 0);
- assert(c->status == CONTENT_STATUS_TYPE_UNKNOWN);
- assert(type < CONTENT_UNKNOWN);
-
- LOG(("content %s (%p), type %i", c->url, c, type));
-
- c->mime_type = talloc_strdup(c, mime_type);
- if (!c->mime_type) {
- c->status = CONTENT_STATUS_ERROR;
- msg_data.error = messages_get("NoMemory");
- content_broadcast(c, CONTENT_MSG_ERROR, msg_data);
+ if (c == NULL)
return false;
- }
-
- c->type = type;
- c->status = CONTENT_STATUS_LOADING;
- if (handler_map[type].no_share && c->user_list->next &&
- c->user_list->next->next) {
- /* type not shareable, and more than one user: split into
- * a content per user */
- const char *referer =
- c->fetch ? fetch_get_referer(c->fetch) : NULL;
- struct content *parent =
- c->fetch ? fetch_get_parent(c->fetch) : NULL;
-
- while (c->user_list->next->next) {
- clone = content_create(c->url);
- if (!clone) {
- c->type = CONTENT_UNKNOWN;
- c->status = CONTENT_STATUS_ERROR;
- msg_data.error = messages_get("NoMemory");
- content_broadcast(c, CONTENT_MSG_ERROR,
- msg_data);
- return false;
- }
-
- clone->width = c->width;
- clone->height = c->height;
- clone->fresh = c->fresh;
-
- callback = c->user_list->next->next->callback;
- p1 = c->user_list->next->next->p1;
- p2 = c->user_list->next->next->p2;
- if (!content_add_user(clone, callback, p1, p2)) {
- c->type = CONTENT_UNKNOWN;
- c->status = CONTENT_STATUS_ERROR;
- content_destroy(clone);
- msg_data.error = messages_get("NoMemory");
- content_broadcast(c, CONTENT_MSG_ERROR,
- msg_data);
- return false;
- }
- content_remove_user(c, callback, p1, p2);
- msg_data.new_url = NULL;
- content_broadcast(clone, CONTENT_MSG_NEWPTR, msg_data);
- fetchcache_go(clone, referer,
- callback, p1, p2,
- clone->width, clone->height,
- 0, 0, false, parent);
- }
- }
-
- if (handler_map[type].create) {
- if (!handler_map[type].create(c, parent, params)) {
- c->type = CONTENT_UNKNOWN;
- c->status = CONTENT_STATUS_ERROR;
- return false;
- }
- }
-
- content_broadcast(c, CONTENT_MSG_LOADING, msg_data);
- return true;
+ return (handler_map[c->type].reformat != NULL);
}
@@ -733,58 +628,6 @@ void content_update_status(struct content *c)
/**
- * Process a block of source data.
- *
- * Calls the process_data function for the content.
- *
- * \param c content structure
- * \param data new data to process
- * \param size size of data
- * \return true on success, false on error and error broadcast to users and
- * possibly reported
- */
-
-bool content_process_data(struct content *c, const char *data,
- unsigned int size)
-{
- char *source_data;
- union content_msg_data msg_data;
- unsigned int extra_space;
-
- assert(c);
- assert(c->type < HANDLER_MAP_COUNT);
- assert(c->status == CONTENT_STATUS_LOADING);
-
- if ((c->source_size + size) > c->source_allocated) {
- extra_space = (c->source_size + size) / 4;
- if (extra_space < 65536)
- extra_space = 65536;
- source_data = talloc_realloc(c, c->source_data, char,
- c->source_size + size + extra_space);
- if (!source_data) {
- c->status = CONTENT_STATUS_ERROR;
- msg_data.error = messages_get("NoMemory");
- content_broadcast(c, CONTENT_MSG_ERROR, msg_data);
- return false;
- }
- c->source_data = source_data;
- c->source_allocated = c->source_size + size + extra_space;
- }
- memcpy(c->source_data + c->source_size, data, size);
- c->source_size += size;
-
- if (handler_map[c->type].process_data) {
- if (!handler_map[c->type].process_data(c,
- c->source_data + c->source_size - size, size)) {
- c->status = CONTENT_STATUS_ERROR;
- return false;
- }
- }
- return true;
-}
-
-
-/**
* All data has arrived, convert for display.
*
* Calls the convert function for the content.
@@ -801,22 +644,12 @@ bool content_process_data(struct content *c, const char *data,
void content_convert(struct content *c, int width, int height)
{
union content_msg_data msg_data;
- char *source_data;
assert(c);
assert(c->type < HANDLER_MAP_COUNT);
assert(c->status == CONTENT_STATUS_LOADING);
assert(!c->locked);
- LOG(("content %s (%p)", c->url, c));
-
- if (c->source_allocated != c->source_size) {
- source_data = talloc_realloc(c, c->source_data, char,
- c->source_size);
- if (source_data) {
- c->source_data = source_data;
- c->source_allocated = c->source_size;
- }
- }
+ LOG(("content %s (%p)", llcache_handle_get_url(c->llcache), c));
c->locked = true;
c->available_width = width;
@@ -860,14 +693,19 @@ void content_set_done(struct content *c)
* Calls the reformat function for the content.
*/
-void content_reformat(struct content *c, int width, int height)
+void content_reformat(hlcache_handle *h, int width, int height)
+{
+ content__reformat(hlcache_handle_get_content(h), width, height);
+}
+
+void content__reformat(struct content *c, int width, int height)
{
union content_msg_data data;
assert(c != 0);
assert(c->status == CONTENT_STATUS_READY ||
c->status == CONTENT_STATUS_DONE);
assert(!c->locked);
- LOG(("%p %s", c, c->url));
+ LOG(("%p %s", c, llcache_handle_get_url(c->llcache)));
c->locked = true;
c->available_width = width;
if (handler_map[c->type].reformat) {
@@ -879,65 +717,6 @@ void content_reformat(struct content *c, int width, int height)
/**
- * Clean unused contents from the content_list.
- *
- * Destroys any contents in the content_list with no users or in
- * CONTENT_STATUS_ERROR. Fresh contents in CONTENT_STATUS_DONE may be kept even
- * with no users.
- *
- * Each content is also checked for stop requests.
- */
-
-void content_clean(void)
-{
- unsigned int size;
- struct content *c, *next, *prev;
-
- /* destroy unused stale contents and contents with errors */
- for (c = content_list; c; c = next) {
- next = c->next;
-
- /* this function must not be called from a content function */
- assert(!c->locked);
-
- if (c->user_list->next && c->status != CONTENT_STATUS_ERROR)
- /* content has users */
- continue;
-
- if (c->fresh && c->status == CONTENT_STATUS_DONE)
- /* content is fresh */
- continue;
-
- /* content can be destroyed */
- content_destroy(c);
- }
-
- /* check for pending stops */
- for (c = content_list; c; c = c->next) {
- if (c->status == CONTENT_STATUS_READY)
- content_stop_check(c);
- }
-
- /* attempt to shrink the memory cache (unused fresh contents) */
- size = 0;
- next = 0;
- for (c = content_list; c; c = c->next) {
- next = c;
- c->talloc_size = talloc_total_size(c);
- size += c->size + c->talloc_size;
- }
- for (c = next; c && (unsigned int) option_memory_cache_size < size;
- c = prev) {
- prev = c->prev;
- if (c->user_list->next)
- continue;
- size -= c->size + c->talloc_size;
- content_destroy(c);
- }
-}
-
-
-/**
* Destroy and free a content.
*
* Calls the destroy function for the content, and frees the structure.
@@ -946,92 +725,54 @@ void content_clean(void)
void content_destroy(struct content *c)
{
assert(c);
- LOG(("content %p %s", c, c->url));
+ LOG(("content %p %s", c, llcache_handle_get_url(c->llcache)));
assert(!c->locked);
- if (c->fetch)
- fetch_abort(c->fetch);
-
- if (c->next)
- c->next->prev = c->prev;
- if (c->prev)
- c->prev->next = c->next;
- else
- content_list = c->next;
-
if (c->type < HANDLER_MAP_COUNT && handler_map[c->type].destroy)
handler_map[c->type].destroy(c);
talloc_free(c);
}
-
/**
- * Reset a content.
+ * Request a redraw of an area of a content
*
- * Calls the destroy function for the content, but does not free
- * the structure.
+ * \param h Content handle
+ * \param x x co-ord of left edge
+ * \param y y co-ord of top edge
+ * \param width Width of rectangle
+ * \param height Height of rectangle
*/
-
-void content_reset(struct content *c)
+void content_request_redraw(struct hlcache_handle *h,
+ int x, int y, int width, int height)
{
- assert(c != 0);
- LOG(("content %p %s", c, c->url));
- assert(!c->locked);
- if (c->type < HANDLER_MAP_COUNT && handler_map[c->type].destroy)
- handler_map[c->type].destroy(c);
- c->type = CONTENT_UNKNOWN;
- c->status = CONTENT_STATUS_TYPE_UNKNOWN;
- c->size = 0;
- talloc_free(c->mime_type);
- c->mime_type = 0;
- talloc_free(c->refresh);
- c->refresh = 0;
- talloc_free(c->title);
- c->title = 0;
- talloc_free(c->source_data);
- c->source_data = 0;
- c->source_size = c->source_allocated = 0;
-}
+ struct content *c = hlcache_handle_get_content(h);
+ union content_msg_data data;
+ if (c == NULL)
+ return;
-/**
- * Free all contents in the content_list.
- */
+ data.redraw.x = x;
+ data.redraw.y = y;
+ data.redraw.width = width;
+ data.redraw.height = height;
-void content_quit(void)
-{
- bool progress = true;
- struct content *c, *next;
-
- while (content_list && progress) {
- progress = false;
- for (c = content_list; c; c = next) {
- assert(c->next != c);
- next = c->next;
-
- if (c->user_list->next &&
- c->status != CONTENT_STATUS_ERROR)
- /* content has users */
- continue;
-
- /* content can be destroyed */
- content_destroy(c);
- progress = true;
- }
- }
+ data.redraw.full_redraw = true;
- if (content_list) {
- LOG(("bug: some contents could not be destroyed"));
- }
-}
+ data.redraw.object = c;
+ data.redraw.object_x = 0;
+ data.redraw.object_y = 0;
+ data.redraw.object_width = c->width;
+ data.redraw.object_height = c->height;
+ content_broadcast(c, CONTENT_MSG_REDRAW, data);
+}
/**
* Display content on screen.
*
* Calls the redraw function for the content, if it exists.
*
- * \param c content
+ * \param h content
* \param x coordinate for top-left of redraw
* \param y coordinate for top-left of redraw
* \param width available width (not used for HTML redraw)
@@ -1051,11 +792,12 @@ void content_quit(void)
* Units for x, y and clip_* are pixels.
*/
-bool content_redraw(struct content *c, int x, int y,
+bool content_redraw(hlcache_handle *h, int x, int y,
int width, int height,
int clip_x0, int clip_y0, int clip_x1, int clip_y1,
float scale, colour background_colour)
{
+ struct content *c = hlcache_handle_get_content(h);
assert(c != 0);
// LOG(("%p %s", c, c->url));
if (c->locked)
@@ -1076,12 +818,13 @@ bool content_redraw(struct content *c, int x, int y,
* redraw function if it doesn't exist.
*/
-bool content_redraw_tiled(struct content *c, int x, int y,
+bool content_redraw_tiled(hlcache_handle *h, int x, int y,
int width, int height,
int clip_x0, int clip_y0, int clip_x1, int clip_y1,
float scale, colour background_colour,
bool repeat_x, bool repeat_y)
{
+ struct content *c = hlcache_handle_get_content(h);
int x0, y0, x1, y1;
assert(c != 0);
@@ -1139,29 +882,27 @@ bool content_redraw_tiled(struct content *c, int x, int y,
*
* \param c the content to register
* \param callback the callback function
- * \param p1, p2 callback private data
+ * \param pw callback private data
* \return true on success, false otherwise on memory exhaustion
*
- * The callback will be called with p1 and p2 when content_broadcast() is
+ * The callback will be called when content_broadcast() is
* called with the content.
*/
bool content_add_user(struct content *c,
- void (*callback)(content_msg msg, struct content *c,
- intptr_t p1, intptr_t p2, union content_msg_data data),
- intptr_t p1, intptr_t p2)
+ void (*callback)(struct content *c, content_msg msg,
+ union content_msg_data data, void *pw),
+ void *pw)
{
struct content_user *user;
- LOG(("content %s (%p), user %p 0x%" PRIxPTR " 0x%" PRIxPTR,
- c->url, c, callback, p1, p2));
+ LOG(("content %s (%p), user %p %p",
+ llcache_handle_get_url(c->llcache), c, callback, pw));
user = talloc(c, struct content_user);
if (!user)
return false;
user->callback = callback;
- user->p1 = p1;
- user->p2 = p2;
- user->stop = false;
+ user->pw = pw;
user->next = c->user_list->next;
c->user_list->next = user;
@@ -1170,49 +911,25 @@ bool content_add_user(struct content *c,
/**
- * Search the users of a content for the specified user.
- *
- * \return a content_user struct for the user, or 0 if not found
- */
-
-struct content_user * content_find_user(struct content *c,
- void (*callback)(content_msg msg, struct content *c,
- intptr_t p1, intptr_t p2, union content_msg_data data),
- intptr_t p1, intptr_t p2)
-{
- struct content_user *user;
-
- /* user_list starts with a sentinel */
- for (user = c->user_list; user->next &&
- !(user->next->callback == callback &&
- user->next->p1 == p1 &&
- user->next->p2 == p2); user = user->next)
- ;
- return user->next;
-}
-
-
-/**
* Remove a callback user.
*
- * The callback function, p1, and p2 must be identical to those passed to
+ * The callback function and pw must be identical to those passed to
* content_add_user().
*/
void content_remove_user(struct content *c,
- void (*callback)(content_msg msg, struct content *c,
- intptr_t p1, intptr_t p2, union content_msg_data data),
- intptr_t p1, intptr_t p2)
+ void (*callback)(struct content *c, content_msg msg,
+ union content_msg_data data, void *pw),
+ void *pw)
{
struct content_user *user, *next;
- LOG(("content %s (%p), user %p 0x%" PRIxPTR " 0x%" PRIxPTR,
- c->url, c, callback, p1, p2));
+ LOG(("content %s (%p), user %p %p",
+ llcache_handle_get_url(c->llcache), c, callback, pw));
/* 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)
+ user->next->pw == pw); user = user->next)
;
if (user->next == 0) {
LOG(("user not found in list"));
@@ -1238,7 +955,7 @@ void content_broadcast(struct content *c, content_msg 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, data);
+ user->callback(c, msg, data, user->pw);
}
}
@@ -1250,11 +967,13 @@ void content_broadcast(struct content *c, content_msg msg,
* stop, the loading is stopped and the content placed in CONTENT_STATUS_DONE.
*/
-void content_stop(struct content *c,
- void (*callback)(content_msg msg, struct content *c,
- intptr_t p1, intptr_t p2, union content_msg_data data),
- intptr_t p1, intptr_t p2)
+void content_stop(hlcache_handle *h,
+ void (*callback)(struct content *c, content_msg msg,
+ union content_msg_data data, void *pw),
+ void *pw)
{
+//newcache
+#if 0
struct content_user *user;
assert(c->status == CONTENT_STATUS_READY);
@@ -1267,36 +986,10 @@ void content_stop(struct content *c,
}
LOG(("%p %s: stop user %p 0x%" PRIxPTR " 0x%" PRIxPTR,
- c, c->url, callback, p1, p2));
+ c, llcache_handle_get_url(c->llcache),
+ callback, p1, p2));
user->stop = true;
-}
-
-
-/**
- * Check if all users have requested a stop, and do it if so.
- */
-
-void content_stop_check(struct content *c)
-{
- struct content_user *user;
- union content_msg_data data;
-
- assert(c->status == CONTENT_STATUS_READY);
-
- /* user_list starts with a sentinel */
- for (user = c->user_list->next; user; user = user->next)
- if (!user->stop)
- return;
-
- LOG(("%p %s", c, c->url));
-
- /* all users have requested stop */
- assert(handler_map[c->type].stop);
- handler_map[c->type].stop(c);
- assert(c->status == CONTENT_STATUS_DONE);
-
- content_set_status(c, messages_get("Stopped"));
- content_broadcast(c, CONTENT_MSG_DONE, data);
+#endif
}
@@ -1314,13 +1007,14 @@ void content_stop_check(struct content *c)
* Calls the open function for the content.
*/
-void content_open(struct content *c, struct browser_window *bw,
+void content_open(hlcache_handle *h, struct browser_window *bw,
struct content *page, unsigned int index, struct box *box,
struct object_params *params)
{
+ struct content *c = hlcache_handle_get_content(h);
assert(c != 0);
assert(c->type < CONTENT_UNKNOWN);
- LOG(("content %p %s", c, c->url));
+ LOG(("content %p %s", c, llcache_handle_get_url(c->llcache)));
if (handler_map[c->type].open)
handler_map[c->type].open(c, bw, page, index, box, params);
}
@@ -1332,11 +1026,12 @@ void content_open(struct content *c, struct browser_window *bw,
* Calls the close function for the content.
*/
-void content_close(struct content *c)
+void content_close(hlcache_handle *h)
{
+ struct content *c = hlcache_handle_get_content(h);
assert(c != 0);
assert(c->type < CONTENT_UNKNOWN);
- LOG(("content %p %s", c, c->url));
+ LOG(("content %p %s", c, llcache_handle_get_url(c->llcache)));
if (handler_map[c->type].close)
handler_map[c->type].close(c);
}
@@ -1346,3 +1041,285 @@ void content_add_error(struct content *c, const char *token,
unsigned int line)
{
}
+
+/**
+ * Retrieve type of content
+ *
+ * \param c Content to retrieve type of
+ * \return Content type
+ */
+content_type content_get_type(hlcache_handle *h)
+{
+ return content__get_type(hlcache_handle_get_content(h));
+}
+
+content_type content__get_type(struct content *c)
+{
+ if (c == NULL)
+ return CONTENT_UNKNOWN;
+
+ return c->type;
+}
+
+/**
+ * Retrieve URL associated with content
+ *
+ * \param c Content to retrieve URL from
+ * \return Pointer to URL, or NULL if not found.
+ */
+const char *content_get_url(hlcache_handle *h)
+{
+ return content__get_url(hlcache_handle_get_content(h));
+}
+
+const char *content__get_url(struct content *c)
+{
+ if (c == NULL)
+ return NULL;
+
+ return llcache_handle_get_url(c->llcache);
+}
+
+/**
+ * Retrieve title associated with content
+ *
+ * \param c Content to retrieve title from
+ * \return Pointer to title, or NULL if not found.
+ */
+const char *content_get_title(hlcache_handle *h)
+{
+ return content__get_title(hlcache_handle_get_content(h));
+}
+
+const char *content__get_title(struct content *c)
+{
+ if (c == NULL)
+ return NULL;
+
+ return c->title != NULL ? c->title : llcache_handle_get_url(c->llcache);
+}
+
+/**
+ * Retrieve status of content
+ *
+ * \param c Content to retrieve status of
+ * \return Content status
+ */
+content_status content_get_status(hlcache_handle *h)
+{
+ return content__get_status(hlcache_handle_get_content(h));
+}
+
+content_status content__get_status(struct content *c)
+{
+ if (c == NULL)
+ return CONTENT_STATUS_TYPE_UNKNOWN;
+
+ return c->status;
+}
+
+/**
+ * Retrieve status message associated with content
+ *
+ * \param c Content to retrieve status message from
+ * \return Pointer to status message, or NULL if not found.
+ */
+const char *content_get_status_message(hlcache_handle *h)
+{
+ return content__get_status_message(hlcache_handle_get_content(h));
+}
+
+const char *content__get_status_message(struct content *c)
+{
+ if (c == NULL)
+ return NULL;
+
+ return c->status_message;
+}
+
+/**
+ * Retrieve width of content
+ *
+ * \param c Content to retrieve width of
+ * \return Content width
+ */
+int content_get_width(hlcache_handle *h)
+{
+ return content__get_width(hlcache_handle_get_content(h));
+}
+
+int content__get_width(struct content *c)
+{
+ if (c == NULL)
+ return 0;
+
+ return c->width;
+}
+
+/**
+ * Retrieve height of content
+ *
+ * \param c Content to retrieve height of
+ * \return Content height
+ */
+int content_get_height(hlcache_handle *h)
+{
+ return content__get_height(hlcache_handle_get_content(h));
+}
+
+int content__get_height(struct content *c)
+{
+ if (c == NULL)
+ return 0;
+
+ return c->height;
+}
+
+/**
+ * Retrieve available width of content
+ *
+ * \param c Content to retrieve available width of
+ * \return Available width of content
+ */
+int content_get_available_width(hlcache_handle *h)
+{
+ return content__get_available_width(hlcache_handle_get_content(h));
+}
+
+int content__get_available_width(struct content *c)
+{
+ if (c == NULL)
+ return 0;
+
+ return c->available_width;
+}
+
+
+/**
+ * Retrieve source of content
+ *
+ * \param c Content to retrieve source of
+ * \param size Pointer to location to receive byte size of source
+ * \return Pointer to source data
+ */
+const char *content_get_source_data(hlcache_handle *h, unsigned long *size)
+{
+ return content__get_source_data(hlcache_handle_get_content(h), size);
+}
+
+const char *content__get_source_data(struct content *c, unsigned long *size)
+{
+ const uint8_t *data;
+ size_t len;
+
+ assert(size != NULL);
+
+ if (c == NULL)
+ return NULL;
+
+ data = llcache_handle_get_source_data(c->llcache, &len);
+
+ *size = (unsigned long) len;
+
+ return (const char *) data;
+}
+
+/**
+ * Invalidate content reuse data: causes subsequent requests for content URL
+ * to query server to determine if content can be reused. This is required
+ * behaviour for forced reloads etc.
+ *
+ * \param c Content to invalidate
+ */
+void content_invalidate_reuse_data(hlcache_handle *h)
+{
+ content__invalidate_reuse_data(hlcache_handle_get_content(h));
+}
+
+void content__invalidate_reuse_data(struct content *c)
+{
+ if (c == NULL)
+ return;
+
+ /* For now, just cause the content to be completely ignored */
+ c->fresh = false;
+}
+
+/**
+ * Retrieve the refresh URL for a content
+ *
+ * \param c Content to retrieve refresh URL from
+ * \return Pointer to URL, or NULL if none
+ */
+const char *content_get_refresh_url(hlcache_handle *h)
+{
+ return content__get_refresh_url(hlcache_handle_get_content(h));
+}
+
+const char *content__get_refresh_url(struct content *c)
+{
+ if (c == NULL)
+ return NULL;
+
+ return c->refresh;
+}
+
+/**
+ * Retrieve the bitmap contained in an image content
+ *
+ * \param c Content to retrieve bitmap from
+ * \return Pointer to bitmap, or NULL if none.
+ */
+struct bitmap *content_get_bitmap(hlcache_handle *h)
+{
+ return content__get_bitmap(hlcache_handle_get_content(h));
+}
+
+struct bitmap *content__get_bitmap(struct content *c)
+{
+ if (c == NULL)
+ return NULL;
+
+ return c->bitmap;
+}
+
+/**
+ * Retrieve the low-level cache handle for a content
+ *
+ * \param h Content to retrieve from
+ * \return Low-level cache handle
+ */
+const llcache_handle *content_get_llcache_handle(struct content *c)
+{
+ if (c == NULL)
+ return NULL;
+
+ return c->llcache;
+}
+
+
+/**
+ * Convert a content into a download
+ *
+ * \param h Content to convert
+ * \return Pointer to low-level cache handle
+ */
+llcache_handle *content_convert_to_download(hlcache_handle *h)
+{
+ struct content *c = hlcache_handle_get_content(h);
+ llcache_handle *stream = c->llcache;
+
+ assert(c != NULL);
+ assert(c->status == CONTENT_STATUS_LOADING);
+
+ /** \todo Is this safe? */
+ c->llcache = NULL;
+
+ /** \todo Tell the llcache to stream the data without caching it */
+
+ /** \todo Invalidate the content object so it's flushed from the
+ * cache at the earliest opportunity */
+
+ return stream;
+}
+
diff --git a/content/content.h b/content/content.h
index db35b39a2..1dd7f83cd 100644
--- a/content/content.h
+++ b/content/content.h
@@ -26,64 +26,31 @@
#ifndef _NETSURF_CONTENT_CONTENT_H_
#define _NETSURF_CONTENT_CONTENT_H_
-/* Irritatingly this must come first, or odd include errors
- * will occur to do with setjmp.h.
- */
-#ifdef WITH_PNG
-#include "image/png.h"
-#endif
+#include <stdbool.h>
-#include <stdint.h>
-#include <time.h>
#include "utils/config.h"
#include "content/content_type.h"
-#include "css/css.h"
-#include "render/html.h"
-#include "render/textplain.h"
-#ifdef WITH_JPEG
-#include "image/jpeg.h"
-#endif
-#ifdef WITH_GIF
-#include "image/gif.h"
-#endif
-#ifdef WITH_BMP
-#include "image/bmp.h"
-#include "image/ico.h"
-#endif
-#ifdef WITH_PLUGIN
-#include "riscos/plugin.h"
-#endif
-#ifdef WITH_MNG
-#include "image/mng.h"
-#endif
-#ifdef WITH_SPRITE
-#include "riscos/sprite.h"
-#endif
-#ifdef WITH_NSSPRITE
-#include "image/nssprite.h"
-#endif
-#ifdef WITH_DRAW
-#include "riscos/draw.h"
-#endif
-#ifdef WITH_ARTWORKS
-#include "riscos/artworks.h"
-#endif
-#ifdef WITH_NS_SVG
-#include "image/svg.h"
-#endif
-#ifdef WITH_RSVG
-#include "image/rsvg.h"
-#endif
+#include "desktop/plot_style.h"
+struct llcache_handle;
-struct bitmap;
struct box;
struct browser_window;
struct content;
-struct fetch;
+struct hlcache_handle;
struct object_params;
-struct ssl_cert_info;
+/** Status of a content */
+typedef enum {
+ 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. */
+ CONTENT_STATUS_ERROR /**< Error occurred, content will be
+ destroyed imminently. */
+} content_status;
/** Used in callbacks to indicate what has occurred. */
typedef enum {
@@ -129,204 +96,64 @@ union content_msg_data {
} ssl;
};
-struct cache_data {
- time_t req_time; /**< Time of request */
- time_t res_time; /**< Time of response */
- time_t date; /**< Date: response header */
- time_t expires; /**< Expires: response header */
-#define INVALID_AGE -1
- int age; /**< Age: response header */
- int max_age; /**< Max-age Cache-control parameter */
- bool no_cache; /**< no-cache Cache-control parameter */
- char *etag; /**< Etag: response header */
- time_t last_modified; /**< Last-Modified: response header */
-};
-
-/** Linked list of users of a content. */
-struct content_user
-{
- void (*callback)(content_msg msg, struct content *c, intptr_t p1,
- intptr_t p2, union content_msg_data data);
- intptr_t p1;
- intptr_t p2;
- bool stop;
- struct content_user *next;
-};
-
-/** Corresponds to a single URL. */
-struct content {
- char *url; /**< URL, in standard form as from url_join. */
- content_type type; /**< Type of content. */
- char *mime_type; /**< Original MIME type of data, or 0. */
- enum {
- 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. */
- CONTENT_STATUS_ERROR /**< Error occurred, content will be
- destroyed imminently. */
- } status; /**< Current status. */
-
- int width, height; /**< Dimensions, if applicable. */
- int available_width; /**< Available width (eg window width). */
-
- /** Data dependent on type. */
- union {
- struct content_html_data html;
- struct content_textplain_data textplain;
- struct content_css_data css;
-#ifdef WITH_JPEG
- struct content_jpeg_data jpeg;
-#endif
-#ifdef WITH_GIF
- struct content_gif_data gif;
-#endif
-#ifdef WITH_BMP
- struct content_bmp_data bmp;
- struct content_ico_data ico;
-#endif
-#ifdef WITH_MNG
- struct content_mng_data mng;
-#endif
-#ifdef WITH_SPRITE
- struct content_sprite_data sprite;
-#endif
-#ifdef WITH_NSSPRITE
- struct content_nssprite_data nssprite;
-#endif
-#ifdef WITH_DRAW
- struct content_draw_data draw;
-#endif
-#ifdef WITH_PLUGIN
- struct content_plugin_data plugin;
-#endif
-#ifdef WITH_ARTWORKS
- struct content_artworks_data artworks;
-#endif
-#ifdef WITH_NS_SVG
- struct content_svg_data svg;
-#endif
-#ifdef WITH_RSVG
- struct content_rsvg_data rsvg;
-#endif
-#ifdef WITH_PNG
- struct content_png_data png;
-#endif
- } data;
-
- /**< URL for refresh request, in standard form as from url_join. */
- char *refresh;
-
- /** Bitmap, for various image contents. */
- struct bitmap *bitmap;
-
- /** This content may be given to new users. Indicates that the content
- * was fetched using a simple GET, has not expired, and may be
- * shared between users. */
- bool fresh;
- struct cache_data cache_data; /**< Cache control data */
- unsigned int time; /**< Creation time, if TYPE_UNKNOWN,
- LOADING or READY,
- otherwise total time. */
-
- unsigned int reformat_time; /**< Earliest time to attempt a
- period reflow while fetching a
- page's objects. */
-
- unsigned int size; /**< Estimated size of all data
- associated with this content, except
- alloced as talloc children of this. */
- off_t talloc_size; /**< Used by content_clean() */
- char *title; /**< Title for browser window. */
- unsigned int active; /**< Number of child fetches or
- conversions currently in progress. */
- struct content_user *user_list; /**< List of users. */
- char status_message[120]; /**< Full text for status bar. */
- char sub_status[80]; /**< Status of content. */
- /** Content is being processed: data structures may be inconsistent
- * and content must not be redrawn or modified. */
- bool locked;
-
- struct fetch *fetch; /**< Associated fetch, or 0. */
- char *source_data; /**< Source data, as received. */
- unsigned long source_size; /**< Amount of data fetched so far. */
- unsigned long source_allocated; /**< Amount of space allocated so far. */
- unsigned long total_size; /**< Total data size, 0 if unknown. */
- long http_code; /**< HTTP status code, 0 if not HTTP. */
-
- bool no_error_pages; /**< Used by fetchcache(). */
- bool download; /**< Used by fetchcache(). */
- bool tried_with_auth; /**< Used by fetchcache(). */
- unsigned int redirect_count; /**< Used by fetchcache(). */
-
- /** Array of first n rendering errors or warnings. */
- struct {
- const char *token;
- unsigned int line; /**< Line no, 0 if not applicable. */
- } error_list[40];
- unsigned int error_count; /**< Number of valid error entries. */
-
- struct content *prev; /**< Previous in global content list. */
- struct content *next; /**< Next in global content list. */
-};
+/* The following are for hlcache */
+content_type content_lookup(const char *mime_type);
+struct content *content_create(struct llcache_handle *llcache,
+ const char *fallback_charset, bool quirks);
+void content_destroy(struct content *c);
+
+bool content_add_user(struct content *h,
+ void (*callback)(struct content *c, content_msg msg,
+ union content_msg_data data, void *pw),
+ void *pw);
+void content_remove_user(struct content *c,
+ void (*callback)(struct content *c, content_msg msg,
+ union content_msg_data data, void *pw),
+ void *pw);
-extern struct content *content_list;
-extern const char * const content_type_name[];
-extern const char * const content_status_name[];
+const struct llcache_handle *content_get_llcache_handle(struct content *c);
-content_type content_lookup(const char *mime_type);
-struct content * content_create(const char *url);
-struct content * content_get(const char *url);
-struct content * content_get_ready(const char *url);
-bool content_can_reformat(struct content *c);
-bool content_set_type(struct content *c, content_type type,
- const char *mime_type, const char *params[],
- struct content *parent);
-void content_set_status(struct content *c, const char *status_message, ...);
-bool content_process_data(struct content *c, const char *data,
- unsigned int size);
-void content_convert(struct content *c, int width, int height);
-void content_set_done(struct content *c);
-void content_reformat(struct content *c, int width, int height);
-void content_clean(void);
-void content_reset(struct content *c);
-void content_quit(void);
-bool content_redraw(struct content *c, int x, int y,
+/* Client functions */
+bool content_can_reformat(struct hlcache_handle *h);
+void content_reformat(struct hlcache_handle *h, int width, int height);
+void content_request_redraw(struct hlcache_handle *h,
+ int x, int y, int width, int height);
+bool content_redraw(struct hlcache_handle *h, int x, int y,
int width, int height,
int clip_x0, int clip_y0, int clip_x1, int clip_y1,
float scale, colour background_colour);
-bool content_redraw_tiled(struct content *c, int x, int y,
+bool content_redraw_tiled(struct hlcache_handle *h, int x, int y,
int width, int height,
int clip_x0, int clip_y0, int clip_x1, int clip_y1,
float scale, colour background_colour,
bool repeat_x, bool repeat_y);
-bool content_add_user(struct content *c,
- void (*callback)(content_msg msg, struct content *c,
- intptr_t p1, intptr_t p2, union content_msg_data data),
- intptr_t p1, intptr_t p2);
-struct content_user * content_find_user(struct content *c,
- void (*callback)(content_msg msg, struct content *c,
- intptr_t p1, intptr_t p2, union content_msg_data data),
- intptr_t p1, intptr_t p2);
-void content_remove_user(struct content *c,
- void (*callback)(content_msg msg, struct content *c,
- intptr_t p1, intptr_t p2, union content_msg_data data),
- intptr_t p1, intptr_t p2);
-void content_broadcast(struct content *c, content_msg msg,
- union content_msg_data data);
-void content_stop(struct content *c,
- void (*callback)(content_msg msg, struct content *c,
- intptr_t p1, intptr_t p2, union content_msg_data data),
- intptr_t p1, intptr_t p2);
-void content_open(struct content *c, struct browser_window *bw,
+void content_stop(struct hlcache_handle *h,
+ void (*callback)(struct content *c, content_msg msg,
+ union content_msg_data data, void *pw),
+ void *pw);
+void content_open(struct hlcache_handle *h, struct browser_window *bw,
struct content *page, unsigned int index, struct box *box,
struct object_params *params);
-void content_close(struct content *c);
-void content_add_error(struct content *c, const char *token,
- unsigned int line);
+void content_close(struct hlcache_handle *h);
+
+/* Member accessors */
+content_type content_get_type(struct hlcache_handle *c);
+const char *content_get_url(struct hlcache_handle *c);
+const char *content_get_title(struct hlcache_handle *c);
+content_status content_get_status(struct hlcache_handle *c);
+const char *content_get_status_message(struct hlcache_handle *c);
+int content_get_width(struct hlcache_handle *c);
+int content_get_height(struct hlcache_handle *c);
+int content_get_available_width(struct hlcache_handle *c);
+const char *content_get_source_data(struct hlcache_handle *c,
+ unsigned long *size);
+void content_invalidate_reuse_data(struct hlcache_handle *c);
+const char *content_get_refresh_url(struct hlcache_handle *c);
+struct bitmap *content_get_bitmap(struct hlcache_handle *c);
+
+/* Download support */
+struct llcache_handle *content_convert_to_download(struct hlcache_handle *c);
#endif
diff --git a/content/content_protected.h b/content/content_protected.h
new file mode 100644
index 000000000..261ee7bcb
--- /dev/null
+++ b/content/content_protected.h
@@ -0,0 +1,221 @@
+/*
+ * Copyright 2005-2007 James Bursa <bursa@users.sourceforge.net>
+ * Copyright 2003 Philip Pemberton <philpem@users.sourceforge.net>
+ *
+ * This file is part of NetSurf, http://www.netsurf-browser.org/
+ *
+ * NetSurf is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * NetSurf is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+/** \file
+ * Content handling (interface).
+ *
+ * The content functions manipulate struct contents, which correspond to URLs.
+ */
+
+#ifndef _NETSURF_CONTENT_CONTENT_PROTECTED_H_
+#define _NETSURF_CONTENT_CONTENT_PROTECTED_H_
+
+/* Irritatingly this must come first, or odd include errors
+ * will occur to do with setjmp.h.
+ */
+#ifdef WITH_PNG
+#include "image/png.h"
+#endif
+
+#include <stdint.h>
+#include <time.h>
+#include "utils/config.h"
+#include "content/content.h"
+#include "content/llcache.h"
+#include "css/css.h"
+#include "render/html.h"
+#include "render/textplain.h"
+#ifdef WITH_JPEG
+#include "image/jpeg.h"
+#endif
+#ifdef WITH_GIF
+#include "image/gif.h"
+#endif
+#ifdef WITH_BMP
+#include "image/bmp.h"
+#include "image/ico.h"
+#endif
+#ifdef WITH_PLUGIN
+#include "riscos/plugin.h"
+#endif
+#ifdef WITH_MNG
+#include "image/mng.h"
+#endif
+#ifdef WITH_SPRITE
+#include "riscos/sprite.h"
+#endif
+#ifdef WITH_NSSPRITE
+#include "image/nssprite.h"
+#endif
+#ifdef WITH_DRAW
+#include "riscos/draw.h"
+#endif
+#ifdef WITH_ARTWORKS
+#include "riscos/artworks.h"
+#endif
+#ifdef WITH_NS_SVG
+#include "image/svg.h"
+#endif
+#ifdef WITH_RSVG
+#include "image/rsvg.h"
+#endif
+
+
+struct bitmap;
+struct content;
+
+/** Linked list of users of a content. */
+struct content_user
+{
+ void (*callback)(struct content *c, content_msg msg,
+ union content_msg_data data, void *pw);
+ void *pw;
+
+ struct content_user *next;
+};
+
+/** Corresponds to a single URL. */
+struct content {
+ llcache_handle *llcache; /**< Low-level cache object */
+
+ content_type type; /**< Type of content. */
+ char *mime_type; /**< Original MIME type of data, or 0. */
+
+ content_status status; /**< Current status. */
+
+ int width, height; /**< Dimensions, if applicable. */
+ int available_width; /**< Available width (eg window width). */
+
+ bool quirks; /**< Content is in quirks mode */
+ char *fallback_charset; /**< Fallback charset, or NULL */
+
+ /** Data dependent on type. */
+ union {
+ struct content_html_data html;
+ struct content_textplain_data textplain;
+ struct content_css_data css;
+#ifdef WITH_JPEG
+ struct content_jpeg_data jpeg;
+#endif
+#ifdef WITH_GIF
+ struct content_gif_data gif;
+#endif
+#ifdef WITH_BMP
+ struct content_bmp_data bmp;
+ struct content_ico_data ico;
+#endif
+#ifdef WITH_MNG
+ struct content_mng_data mng;
+#endif
+#ifdef WITH_SPRITE
+ struct content_sprite_data sprite;
+#endif
+#ifdef WITH_NSSPRITE
+ struct content_nssprite_data nssprite;
+#endif
+#ifdef WITH_DRAW
+ struct content_draw_data draw;
+#endif
+#ifdef WITH_PLUGIN
+ struct content_plugin_data plugin;
+#endif
+#ifdef WITH_ARTWORKS
+ struct content_artworks_data artworks;
+#endif
+#ifdef WITH_NS_SVG
+ struct content_svg_data svg;
+#endif
+#ifdef WITH_RSVG
+ struct content_rsvg_data rsvg;
+#endif
+#ifdef WITH_PNG
+ struct content_png_data png;
+#endif
+ } data;
+
+ /**< URL for refresh request, in standard form as from url_join. */
+ char *refresh;
+
+ /** Bitmap, for various image contents. */
+ struct bitmap *bitmap;
+
+ /** This content may be given to new users. Indicates that the content
+ * was fetched using a simple GET, has not expired, and may be
+ * shared between users. */
+ bool fresh;
+ unsigned int time; /**< Creation time, if TYPE_UNKNOWN,
+ LOADING or READY,
+ otherwise total time. */
+
+ unsigned int reformat_time; /**< Earliest time to attempt a
+ period reflow while fetching a
+ page's objects. */
+
+ unsigned int size; /**< Estimated size of all data
+ associated with this content, except
+ alloced as talloc children of this. */
+ off_t talloc_size; /**< Used by content_clean() */
+ char *title; /**< Title for browser window. */
+ unsigned int active; /**< Number of child fetches or
+ conversions currently in progress. */
+ struct content_user *user_list; /**< List of users. */
+ char status_message[120]; /**< Full text for status bar. */
+ char sub_status[80]; /**< Status of content. */
+ /** Content is being processed: data structures may be inconsistent
+ * and content must not be redrawn or modified. */
+ bool locked;
+
+ unsigned long total_size; /**< Total data size, 0 if unknown. */
+ long http_code; /**< HTTP status code, 0 if not HTTP. */
+
+ /** Array of first n rendering errors or warnings. */
+ struct {
+ const char *token;
+ unsigned int line; /**< Line no, 0 if not applicable. */
+ } error_list[40];
+ unsigned int error_count; /**< Number of valid error entries. */
+};
+
+extern const char * const content_type_name[];
+extern const char * const content_status_name[];
+
+void content_set_done(struct content *c);
+void content_set_status(struct content *c, const char *status_message, ...);
+void content_broadcast(struct content *c, content_msg msg,
+ union content_msg_data data);
+void content_add_error(struct content *c, const char *token,
+ unsigned int line);
+
+void content__reformat(struct content *c, int width, int height);
+
+
+content_type content__get_type(struct content *c);
+const char *content__get_url(struct content *c);
+const char *content__get_title(struct content *c);
+content_status content__get_status(struct content *c);
+const char *content__get_status_message(struct content *c);
+int content__get_width(struct content *c);
+int content__get_height(struct content *c);
+int content__get_available_width(struct content *c);
+const char *content__get_source_data(struct content *c, unsigned long *size);
+void content__invalidate_reuse_data(struct content *c);
+const char *content__get_refresh_url(struct content *c);
+struct bitmap *content__get_bitmap(struct content *c);
+
+#endif
diff --git a/content/fetch.c b/content/fetch.c
index f835ac121..627d7caf0 100644
--- a/content/fetch.c
+++ b/content/fetch.c
@@ -41,7 +41,6 @@
#include "content/urldb.h"
#include "desktop/netsurf.h"
#include "desktop/options.h"
-#include "render/form.h"
#include "utils/log.h"
#include "utils/messages.h"
#include "utils/url.h"
@@ -213,7 +212,7 @@ void fetch_unref_fetcher(scheme_fetcher *fetcher)
struct fetch * fetch_start(const char *url, const char *referer,
fetch_callback callback,
void *p, bool only_2xx, const char *post_urlenc,
- struct form_successful_control *post_multipart,
+ struct fetch_multipart_data *post_multipart,
bool verifiable, struct content *parent,
char *headers[])
{
@@ -598,6 +597,78 @@ bool fetch_get_verifiable(struct fetch *fetch)
return fetch->verifiable;
}
+/**
+ * Clone a linked list of fetch_multipart_data.
+ *
+ * \param list List to clone
+ * \return Pointer to head of cloned list, or NULL on failure
+ */
+struct fetch_multipart_data *fetch_multipart_data_clone(
+ const struct fetch_multipart_data *list)
+{
+ struct fetch_multipart_data *clone, *last = NULL;
+ struct fetch_multipart_data *result = NULL;
+
+ for (; list != NULL; list = list->next) {
+ clone = malloc(sizeof(struct fetch_multipart_data));
+ if (clone == NULL) {
+ if (result != NULL)
+ fetch_multipart_data_destroy(result);
+
+ return NULL;
+ }
+
+ clone->file = list->file;
+
+ clone->name = strdup(list->name);
+ if (clone->name == NULL) {
+ free(clone);
+ if (result != NULL)
+ fetch_multipart_data_destroy(result);
+
+ return NULL;
+ }
+
+ clone->value = strdup(list->value);
+ if (clone->value == NULL) {
+ free(clone->name);
+ free(clone);
+ if (result != NULL)
+ fetch_multipart_data_destroy(result);
+
+ return NULL;
+ }
+
+ clone->next = NULL;
+
+ if (result == NULL)
+ result = clone;
+ else
+ last->next = clone;
+
+ last = clone;
+ }
+
+ return result;
+}
+
+/**
+ * Free a linked list of fetch_multipart_data.
+ *
+ * \param list Pointer to head of list to free
+ */
+void fetch_multipart_data_destroy(struct fetch_multipart_data *list)
+{
+ struct fetch_multipart_data *next;
+
+ for (; list != NULL; list = next) {
+ next = list->next;
+ free(list->name);
+ free(list->value);
+ free(list);
+ }
+}
+
void
fetch_send_callback(fetch_msg msg, struct fetch *fetch, const void *data,
unsigned long size, fetch_error_code errorcode)
@@ -665,8 +736,8 @@ fetch_set_cookie(struct fetch *fetch, const char *data)
* that the request uri and the parent domain match,
* so don't pass in the parent in this case. */
urldb_set_cookie(data, fetch->url,
- fetch->verifiable ? NULL
- : fetch->parent->url);
+ fetch->verifiable ? NULL
+ : content_get_url(fetch->parent));
}
}
diff --git a/content/fetch.h b/content/fetch.h
index 168c9b252..16dae63d0 100644
--- a/content/fetch.h
+++ b/content/fetch.h
@@ -54,7 +54,15 @@ typedef enum {
struct content;
struct fetch;
-struct form_successful_control;
+
+/** Fetch POST multipart data */
+struct fetch_multipart_data {
+ bool file; /**< Item is a file */
+ char *name; /**< Name of item */
+ char *value; /**< Item value */
+
+ struct fetch_multipart_data *next; /**< Next in linked list */
+};
struct ssl_cert_info {
long version; /**< Certificate version */
@@ -77,7 +85,7 @@ void fetch_init(void);
struct fetch * fetch_start(const char *url, const char *referer,
fetch_callback callback,
void *p, bool only_2xx, const char *post_urlenc,
- struct form_successful_control *post_multipart,
+ struct fetch_multipart_data *post_multipart,
bool verifiable, struct content *parent,
char *headers[]);
void fetch_abort(struct fetch *f);
@@ -94,12 +102,16 @@ const char *fetch_get_referer(struct fetch *fetch);
struct content *fetch_get_parent(struct fetch *fetch);
bool fetch_get_verifiable(struct fetch *fetch);
+void fetch_multipart_data_destroy(struct fetch_multipart_data *list);
+struct fetch_multipart_data *fetch_multipart_data_clone(
+ const struct fetch_multipart_data *list);
+
/* API for fetchers themselves */
typedef bool (*fetcher_initialise)(const char *);
typedef void* (*fetcher_setup_fetch)(struct fetch *, const char *,
bool, const char *,
- struct form_successful_control *,
+ struct fetch_multipart_data *,
const char **);
typedef bool (*fetcher_start_fetch)(void *);
typedef void (*fetcher_abort_fetch)(void *);
diff --git a/content/fetchcache.c b/content/fetchcache.c
index 243d5c04b..3a0b667f9 100644
--- a/content/fetchcache.c
+++ b/content/fetchcache.c
@@ -102,7 +102,7 @@ struct content * fetchcache(const char *url,
int width, int height,
bool no_error_pages,
char *post_urlenc,
- struct form_successful_control *post_multipart,
+ struct fetch_multipart_data *post_multipart,
bool verifiable,
bool download)
{
@@ -250,7 +250,7 @@ void fetchcache_go(struct content *content, const char *referer,
intptr_t p1, intptr_t p2,
int width, int height,
char *post_urlenc,
- struct form_successful_control *post_multipart,
+ struct fetch_multipart_data *post_multipart,
bool verifiable, struct content *parent)
{
char error_message[500];
diff --git a/content/fetchcache.h b/content/fetchcache.h
index 24ed564ad..46e9b3d94 100644
--- a/content/fetchcache.h
+++ b/content/fetchcache.h
@@ -30,7 +30,7 @@
#include <stdint.h>
#include "content/content.h"
-struct form_successful_control;
+struct fetch_multipart_data;
void fetchcache_init(void);
struct content * fetchcache(const char *url,
@@ -40,7 +40,7 @@ struct content * fetchcache(const char *url,
int width, int height,
bool no_error_pages,
char *post_urlenc,
- struct form_successful_control *post_multipart,
+ struct fetch_multipart_data *post_multipart,
bool verifiable,
bool download);
void fetchcache_go(struct content *content, const char *referer,
@@ -49,7 +49,7 @@ void fetchcache_go(struct content *content, const char *referer,
intptr_t p1, intptr_t p2,
int width, int height,
char *post_urlenc,
- struct form_successful_control *post_multipart,
+ struct fetch_multipart_data *post_multipart,
bool verifiable, struct content *parent);
#endif
diff --git a/content/fetchers/fetch_curl.c b/content/fetchers/fetch_curl.c
index ca2d86845..9ac3ad7b3 100644
--- a/content/fetchers/fetch_curl.c
+++ b/content/fetchers/fetch_curl.c
@@ -30,6 +30,7 @@
#include <assert.h>
#include <errno.h>
+#include <inttypes.h>
#include <stdbool.h>
#include <string.h>
#include <strings.h>
@@ -43,7 +44,6 @@
#include "content/urldb.h"
#include "desktop/netsurf.h"
#include "desktop/options.h"
-#include "render/form.h"
#include "utils/log.h"
#include "utils/messages.h"
#include "utils/url.h"
@@ -104,7 +104,7 @@ static bool fetch_curl_initialise(const char *scheme);
static void fetch_curl_finalise(const char *scheme);
static void * fetch_curl_setup(struct fetch *parent_fetch, const char *url,
bool only_2xx, const char *post_urlenc,
- struct form_successful_control *post_multipart,
+ struct fetch_multipart_data *post_multipart,
const char **headers);
static bool fetch_curl_start(void *vfetch);
static bool fetch_curl_initiate_fetch(struct curl_fetch_info *fetch,
@@ -132,7 +132,7 @@ static size_t fetch_curl_header(char *data, size_t size, size_t nmemb,
void *_f);
static bool fetch_curl_process_headers(struct curl_fetch_info *f);
static struct curl_httppost *fetch_curl_post_convert(
- struct form_successful_control *control);
+ struct fetch_multipart_data *control);
static int fetch_curl_verify_callback(int preverify_ok,
X509_STORE_CTX *x509_ctx);
static int fetch_curl_cert_verify_callback(X509_STORE_CTX *x509_ctx,
@@ -294,7 +294,7 @@ void fetch_curl_finalise(const char *scheme)
void * fetch_curl_setup(struct fetch *parent_fetch, const char *url,
bool only_2xx, const char *post_urlenc,
- struct form_successful_control *post_multipart,
+ struct fetch_multipart_data *post_multipart,
const char **headers)
{
char *host;
@@ -1108,10 +1108,7 @@ size_t fetch_curl_header(char *data, size_t size, size_t nmemb,
bool fetch_curl_process_headers(struct curl_fetch_info *f)
{
long http_code;
- const char *type;
CURLcode code;
- struct stat s;
- char *url_path = 0;
f->had_headers = true;
@@ -1142,7 +1139,7 @@ bool fetch_curl_process_headers(struct curl_fetch_info *f)
/* handle HTTP 401 (Authentication errors) */
if (http_code == 401) {
- fetch_send_callback(FETCH_AUTH, f->fetch_handle, f->realm,0,
+ fetch_send_callback(FETCH_AUTH, f->fetch_handle, f->realm, 0,
FETCH_ERROR_AUTHENTICATION);
return true;
}
@@ -1156,49 +1153,64 @@ bool fetch_curl_process_headers(struct curl_fetch_info *f)
return true;
}
- /* find MIME type from headers or filetype for local files */
- code = curl_easy_getinfo(f->curl_handle, CURLINFO_CONTENT_TYPE, &type);
- assert(code == CURLE_OK);
-
- if (strncmp(f->url, "file:///", 8) == 0)
- url_path = curl_unescape(f->url + 7,
- (int) strlen(f->url) - 7);
-
- if (url_path && stat(url_path, &s) == 0) {
- /* file: URL and file exists */
- /* create etag */
- char etag_buf[20];
- snprintf(etag_buf, sizeof etag_buf,
- "ETag: \"%10d\"", (int) s.st_mtime);
- /* And send it to the header handler */
- fetch_send_callback(FETCH_HEADER, f->fetch_handle, etag_buf,
- strlen(etag_buf), FETCH_ERROR_NO_ERROR);
-
- /* don't set last modified time so as to ensure that local
- * files are revalidated at all times. */
-
- /* If performed a conditional request and unmodified ... */
- if (f->last_modified && f->file_etag &&
- f->last_modified > s.st_mtime &&
- f->file_etag == s.st_mtime) {
- fetch_send_callback(FETCH_NOTMODIFIED, f->fetch_handle,
- 0, 0, FETCH_ERROR_NO_ERROR);
- curl_free(url_path);
- return true;
- }
- }
-
- if (type == 0) {
- type = "text/plain";
- if (url_path) {
+ /* find MIME type from filetype for local files */
+ if (strncmp(f->url, "file:///", 8) == 0) {
+ struct stat s;
+ char *url_path = curl_unescape(f->url + 7,
+ (int) strlen(f->url + 7));
+
+ if (url_path != NULL && stat(url_path, &s) == 0) {
+ /* file: URL and file exists */
+ char header[64];
+ const char *type;
+
+ /* create etag */
+ snprintf(header, sizeof header,
+ "ETag: \"%10" PRId64 "\"",
+ (int64_t) s.st_mtime);
+ /* And send it to the header handler */
+ fetch_send_callback(FETCH_HEADER, f->fetch_handle,
+ header, strlen(header),
+ FETCH_ERROR_NO_ERROR);
+
+ /* create Content-Type */
type = fetch_filetype(url_path);
+ snprintf(header, sizeof header,
+ "Content-Type: %s", type);
+ /* Send it to the header handler */
+ fetch_send_callback(FETCH_HEADER, f->fetch_handle,
+ header, strlen(header),
+ FETCH_ERROR_NO_ERROR);
+
+ /* create Content-Length */
+ type = fetch_filetype(url_path);
+ snprintf(header, sizeof header,
+ "Content-Length: %" PRId64,
+ (int64_t) s.st_size);
+ /* Send it to the header handler */
+ fetch_send_callback(FETCH_HEADER, f->fetch_handle,
+ header, strlen(header),
+ FETCH_ERROR_NO_ERROR);
+
+ /* don't set last modified time so as to ensure that
+ * local files are revalidated at all times. */
+
+ /* Report not modified, if appropriate */
+ if (f->last_modified && f->file_etag &&
+ f->last_modified > s.st_mtime &&
+ f->file_etag == s.st_mtime) {
+ fetch_send_callback(FETCH_NOTMODIFIED,
+ f->fetch_handle, 0, 0,
+ FETCH_ERROR_NO_ERROR);
+ curl_free(url_path);
+ return true;
+ }
}
- }
- curl_free(url_path);
+ if (url_path != NULL)
+ curl_free(url_path);
+ }
- LOG(("FETCH_TYPE, '%s'", type));
- fetch_send_callback(FETCH_TYPE, f->fetch_handle, type, f->content_length, FETCH_ERROR_NO_ERROR);
if (f->abort)
return true;
@@ -1207,11 +1219,11 @@ bool fetch_curl_process_headers(struct curl_fetch_info *f)
/**
- * Convert a list of struct ::form_successful_control to a list of
+ * Convert a list of struct ::fetch_multipart_data to a list of
* struct curl_httppost for libcurl.
*/
struct curl_httppost *
-fetch_curl_post_convert(struct form_successful_control *control)
+fetch_curl_post_convert(struct fetch_multipart_data *control)
{
struct curl_httppost *post = 0, *last = 0;
CURLFORMcode code;
diff --git a/content/fetchers/fetch_data.c b/content/fetchers/fetch_data.c
index f2a90c50d..1790de56f 100644
--- a/content/fetchers/fetch_data.c
+++ b/content/fetchers/fetch_data.c
@@ -35,7 +35,6 @@
#include "content/urldb.h"
#include "desktop/netsurf.h"
#include "desktop/options.h"
-#include "render/form.h"
#include "utils/log.h"
#include "utils/messages.h"
#include "utils/url.h"
@@ -78,7 +77,7 @@ static void fetch_data_finalise(const char *scheme)
static void *fetch_data_setup(struct fetch *parent_fetch, const char *url,
bool only_2xx, const char *post_urlenc,
- struct form_successful_control *post_multipart,
+ struct fetch_multipart_data *post_multipart,
const char **headers)
{
struct fetch_data_context *ctx = calloc(1, sizeof(*ctx));
@@ -232,20 +231,9 @@ static bool fetch_data_process(struct fetch_data_context *c)
static void fetch_data_poll(const char *scheme)
{
struct fetch_data_context *c, *next;
- struct cache_data cachedata;
if (ring == NULL) return;
- cachedata.req_time = time(NULL);
- cachedata.res_time = time(NULL);
- cachedata.date = 0;
- cachedata.expires = 0;
- cachedata.age = INVALID_AGE;
- cachedata.max_age = 0;
- cachedata.no_cache = true;
- cachedata.etag = NULL;
- cachedata.last_modified = 0;
-
/* Iterate over ring, processing each pending fetch */
c = ring;
do {
@@ -265,6 +253,8 @@ static void fetch_data_poll(const char *scheme)
/* Only process non-aborted fetches */
if (!c->aborted && fetch_data_process(c) == true) {
+ char header[64];
+
fetch_set_http_code(c->parent_fetch, 200);
LOG(("setting data: MIME type to %s, length to %zd",
c->mimetype, c->datalen));
@@ -272,9 +262,16 @@ static void fetch_data_poll(const char *scheme)
* Therefore, we _must_ check for this after _every_
* call to fetch_data_send_callback().
*/
- fetch_data_send_callback(FETCH_TYPE,
- c, c->mimetype, c->datalen,
- FETCH_ERROR_NO_ERROR);
+ snprintf(header, sizeof header, "Content-Type: %s",
+ c->mimetype);
+ fetch_data_send_callback(FETCH_HEADER, c, header,
+ strlen(header), FETCH_ERROR_NO_ERROR);
+
+ snprintf(header, sizeof header, "Content-Length: %zd",
+ c->datalen);
+ fetch_data_send_callback(FETCH_HEADER, c, header,
+ strlen(header), FETCH_ERROR_NO_ERROR);
+
if (!c->aborted) {
fetch_data_send_callback(FETCH_DATA,
c, c->data, c->datalen,
@@ -282,8 +279,7 @@ static void fetch_data_poll(const char *scheme)
}
if (!c->aborted) {
fetch_data_send_callback(FETCH_FINISHED,
- c, &cachedata, 0,
- FETCH_ERROR_NO_ERROR);
+ c, 0, 0, FETCH_ERROR_NO_ERROR);
}
} else {
LOG(("Processing of %s failed!", c->url));
diff --git a/content/hlcache.c b/content/hlcache.c
new file mode 100644
index 000000000..94d5f0036
--- /dev/null
+++ b/content/hlcache.c
@@ -0,0 +1,362 @@
+/*
+ * Copyright 2009 John-Mark Bell <jmb@netsurf-browser.org>
+ *
+ * This file is part of NetSurf, http://www.netsurf-browser.org/
+ *
+ * NetSurf is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * NetSurf is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+/** \file
+ * High-level resource cache (implementation)
+ */
+
+#include <assert.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "content/content.h"
+#include "content/hlcache.h"
+#include "utils/log.h"
+#include "utils/url.h"
+
+typedef struct hlcache_entry hlcache_entry;
+typedef struct hlcache_retrieval_ctx hlcache_retrieval_ctx;
+
+/** High-level cache retrieval context */
+struct hlcache_retrieval_ctx {
+ llcache_handle *llcache; /**< Low-level cache handle */
+
+ hlcache_handle *handle; /**< High-level handle for object */
+
+ /* The following are only used if a child content is requested */
+ const char *charset; /**< Fallback charset, or NULL */
+ bool quirks; /**< Whether object should be quirky */
+};
+
+/** High-level cache handle */
+struct hlcache_handle {
+ hlcache_entry *entry; /**< Pointer to cache entry */
+
+ hlcache_handle_callback cb; /**< Client callback */
+ void *pw; /**< Client data */
+};
+
+/** Entry in high-level cache */
+struct hlcache_entry {
+ struct content *content; /**< Pointer to associated content */
+
+ hlcache_entry *next; /**< Next sibling */
+ hlcache_entry *prev; /**< Previous sibling */
+};
+
+/** List of cached content objects */
+static hlcache_entry *hlcache_content_list;
+
+static nserror hlcache_llcache_callback(llcache_handle *handle,
+ const llcache_event *event, void *pw);
+static nserror hlcache_find_content(hlcache_retrieval_ctx *ctx);
+static void hlcache_content_callback(struct content *c,
+ content_msg msg, union content_msg_data data, void *pw);
+
+/******************************************************************************
+ * Public API *
+ ******************************************************************************/
+
+/**
+ * Retrieve a high-level cache handle for an object
+ *
+ * \param url URL of the object to retrieve handle for
+ * \param flags Object retrieval flags
+ * \param referer Referring URL, or NULL if none
+ * \param post POST data, or NULL for a GET request
+ * \param width Available width for content
+ * \param height Available height for content
+ * \param cb Callback to handle object events
+ * \param pw Pointer to client-specific data for callback
+ * \param child Child retrieval context, or NULL for top-level content
+ * \param result Pointer to location to recieve cache handle
+ * \return NSERROR_OK on success, appropriate error otherwise
+ *
+ * \todo Is there any way to sensibly reduce the number of parameters here?
+ */
+nserror hlcache_handle_retrieve(const char *url, uint32_t flags,
+ const char *referer, llcache_post_data *post,
+ uint32_t width, uint32_t height,
+ hlcache_handle_callback cb, void *pw,
+ hlcache_child_context *child, hlcache_handle **result)
+{
+ hlcache_retrieval_ctx *ctx;
+ nserror error;
+
+ assert(cb != NULL);
+
+ ctx = calloc(1, sizeof(hlcache_retrieval_ctx));
+ if (ctx == NULL)
+ return NSERROR_NOMEM;
+
+ ctx->handle = calloc(1, sizeof(hlcache_handle));
+ if (ctx->handle == NULL) {
+ free(ctx);
+ return NSERROR_NOMEM;
+ }
+
+ if (child != NULL) {
+ /** \todo Is the charset guaranteed to exist during fetch? */
+ ctx->charset = child->charset;
+ ctx->quirks = child->quirks;
+ }
+
+ /** \todo What happens with width/height? */
+
+ ctx->handle->cb = cb;
+ ctx->handle->pw = pw;
+
+ error = llcache_handle_retrieve(url, flags, referer, post,
+ hlcache_llcache_callback, ctx,
+ &ctx->llcache);
+ if (error != NSERROR_OK) {
+ free(ctx->handle);
+ free(ctx);
+ return error;
+ }
+
+ *result = ctx->handle;
+
+ return NSERROR_OK;
+}
+
+/**
+ * Release a high-level cache handle
+ *
+ * \param handle Handle to release
+ * \return NSERROR_OK on success, appropriate error otherwise
+ */
+nserror hlcache_handle_release(hlcache_handle *handle)
+{
+ /** \todo What if this is called during fetch? */
+
+ if (handle->entry != NULL) {
+ content_remove_user(handle->entry->content,
+ hlcache_content_callback, handle);
+ }
+
+ handle->cb = NULL;
+ handle->pw = NULL;
+
+ /** \todo Provide hlcache_poll() to perform cache maintenance */
+
+ return NSERROR_OK;
+}
+
+/**
+ * Retrieve a content object from a cache handle
+ *
+ * \param handle Cache handle to dereference
+ * \return Pointer to content object, or NULL if there is none
+ *
+ * \todo This may not be correct. Ideally, the client should never need to
+ * directly access a content object. It may, therefore, be better to provide a
+ * bunch of veneers here that take a hlcache_handle and invoke the
+ * corresponding content_ API. If there's no content object associated with the
+ * hlcache_handle (e.g. because the source data is still being fetched, so it
+ * doesn't exist yet), then these veneers would behave as a NOP. The important
+ * thing being that the client need not care about this possibility and can
+ * just call the functions with impugnity.
+ */
+struct content *hlcache_handle_get_content(const hlcache_handle *handle)
+{
+ assert(handle != NULL);
+
+ if (handle->entry != NULL)
+ return handle->entry->content;
+
+ return NULL;
+}
+
+/******************************************************************************
+ * High-level cache internals *
+ ******************************************************************************/
+
+/**
+ * Handler for low-level cache events
+ *
+ * \param handle Handle for which event is issued
+ * \param event Event data
+ * \param pw Pointer to client-specific data
+ * \return NSERROR_OK on success, appropriate error otherwise
+ */
+nserror hlcache_llcache_callback(llcache_handle *handle,
+ const llcache_event *event, void *pw)
+{
+ hlcache_retrieval_ctx *ctx = pw;
+ nserror error;
+
+ assert(ctx->llcache == handle);
+
+ switch (event->type) {
+ case LLCACHE_EVENT_HAD_HEADERS:
+ error = hlcache_find_content(ctx);
+ if (error != NSERROR_OK)
+ return error;
+ /* No longer require retrieval context */
+ free(ctx);
+ break;
+ case LLCACHE_EVENT_HAD_DATA:
+ /* fall through */
+ case LLCACHE_EVENT_DONE:
+ /* should never happen: the handler must be changed */
+ break;
+ case LLCACHE_EVENT_ERROR:
+ /** \todo handle errors */
+ break;
+ case LLCACHE_EVENT_PROGRESS:
+ break;
+ }
+
+ return NSERROR_OK;
+}
+
+/**
+ * Find a content for the high-level cache handle
+ *
+ * \param ctx High-level cache retrieval context
+ * \return NSERROR_OK on success, appropriate error otherwise
+ *
+ * \pre handle::state == HLCACHE_HANDLE_NEW
+ * \pre Headers must have been received for associated low-level handle
+ * \post Low-level handle is either released, or associated with new content
+ * \post High-level handle is registered with content
+ */
+nserror hlcache_find_content(hlcache_retrieval_ctx *ctx)
+{
+ hlcache_entry *entry;
+ hlcache_event event;
+
+ /* Search list of cached contents for a suitable one */
+ for (entry = hlcache_content_list; entry != NULL; entry = entry->next) {
+ const llcache_handle *entry_llcache;
+
+ /** \todo Need to ensure that quirks mode matches */
+ /** \todo Need to ensure that content is shareable */
+ /** \todo Need to ensure that content can be reused */
+ if (entry->content == NULL)
+ continue;
+
+ /* Ensure that content uses same low-level object as
+ * low-level handle */
+ entry_llcache = content_get_llcache_handle(entry->content);
+
+ if (llcache_handle_references_same_object(entry_llcache,
+ ctx->llcache))
+ break;
+ }
+
+ if (entry == NULL) {
+ /* No existing entry, so need to create one */
+ entry = malloc(sizeof(hlcache_entry));
+ if (entry == NULL)
+ return NSERROR_NOMEM;
+
+ /* Create content using llhandle */
+ entry->content = content_create(ctx->llcache,
+ ctx->charset, ctx->quirks);
+ if (entry->content == NULL) {
+ free(entry);
+ return NSERROR_NOMEM;
+ }
+
+ /* Insert into cache */
+ entry->prev = NULL;
+ entry->next = hlcache_content_list;
+ if (hlcache_content_list != NULL)
+ hlcache_content_list->prev = entry;
+ hlcache_content_list = entry;
+ } else {
+ /* Found a suitable content: no longer need low-level handle */
+ llcache_handle_release(ctx->llcache);
+ }
+
+ /* Associate handle with content */
+ if (content_add_user(entry->content,
+ hlcache_content_callback, ctx->handle) == false)
+ return NSERROR_NOMEM;
+
+ /* Associate cache entry with handle */
+ ctx->handle->entry = entry;
+
+ /* Catch handle up with state of content */
+ if (ctx->handle->cb != NULL) {
+ content_status status = content_get_status(ctx->handle);
+
+ if (status == CONTENT_STATUS_LOADING) {
+ event.type = CONTENT_MSG_LOADING;
+ ctx->handle->cb(ctx->handle, &event, ctx->handle->pw);
+ } else if (status == CONTENT_STATUS_READY) {
+ event.type = CONTENT_MSG_LOADING;
+ ctx->handle->cb(ctx->handle, &event, ctx->handle->pw);
+
+ if (ctx->handle->cb != NULL) {
+ event.type = CONTENT_MSG_READY;
+ ctx->handle->cb(ctx->handle, &event,
+ ctx->handle->pw);
+ }
+ } else if (status == CONTENT_STATUS_DONE) {
+ event.type = CONTENT_MSG_LOADING;
+ ctx->handle->cb(ctx->handle, &event, ctx->handle->pw);
+
+ /** \todo Reflow content to new width
+ if (content_get_available_width(ctx->handle) != width)
+ content_reformat(ctx->handle, width, height);
+ */
+
+ if (ctx->handle->cb != NULL) {
+ event.type = CONTENT_MSG_READY;
+ ctx->handle->cb(ctx->handle, &event,
+ ctx->handle->pw);
+ }
+
+ if (ctx->handle->cb != NULL) {
+ event.type = CONTENT_MSG_DONE;
+ ctx->handle->cb(ctx->handle, &event,
+ ctx->handle->pw);
+ }
+ }
+ }
+
+ return NSERROR_OK;
+}
+
+/**
+ * Veneer between content callback API and hlcache callback API
+ *
+ * \param c Content to emit message for
+ * \param msg Message to emit
+ * \param data Data for message
+ * \param pw Pointer to private data (hlcache_handle)
+ */
+void hlcache_content_callback(struct content *c, content_msg msg,
+ union content_msg_data data, void *pw)
+{
+ hlcache_handle *handle = pw;
+ hlcache_event event;
+ nserror error;
+
+ event.type = msg;
+ event.data = data;
+
+
+ error = handle->cb(handle, &event, handle->pw);
+ if (error != NSERROR_OK)
+ LOG(("Error in callback: %d", error));
+}
+
diff --git a/content/hlcache.h b/content/hlcache.h
new file mode 100644
index 000000000..fb6ba219c
--- /dev/null
+++ b/content/hlcache.h
@@ -0,0 +1,110 @@
+/*
+ * Copyright 2009 John-Mark Bell <jmb@netsurf-browser.org>
+ *
+ * This file is part of NetSurf, http://www.netsurf-browser.org/
+ *
+ * NetSurf is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * NetSurf is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+/** \file
+ * High-level resource cache (interface)
+ */
+
+#ifndef NETSURF_CONTENT_HLCACHE_H_
+#define NETSURF_CONTENT_HLCACHE_H_
+
+#include "content/content.h"
+#include "content/llcache.h"
+#include "utils/errors.h"
+
+/** High-level cache handle */
+typedef struct hlcache_handle hlcache_handle;
+
+/** Context for retrieving a child object */
+typedef struct hlcache_child_context {
+ const char *charset; /**< Charset of parent */
+ bool quirks; /**< Whether parent is quirky */
+} hlcache_child_context;
+
+/** High-level cache event */
+typedef struct {
+ content_msg type; /**< Event type */
+ union content_msg_data data; /**< Event data */
+} hlcache_event;
+
+/**
+ * Client callback for high-level cache events
+ *
+ * \param handle Handle to object generating event
+ * \param event Event data
+ * \param pw Pointer to client-specific data
+ * \return NSERROR_OK on success, appropriate error otherwise.
+ */
+typedef nserror (*hlcache_handle_callback)(hlcache_handle *handle,
+ const hlcache_event *event, void *pw);
+
+/**
+ * Retrieve a high-level cache handle for an object
+ *
+ * \param url URL of the object to retrieve handle for
+ * \param flags Object retrieval flags
+ * \param referer Referring URL, or NULL if none
+ * \param post POST data, or NULL for a GET request
+ * \param width Available width for content
+ * \param height Available height for content
+ * \param cb Callback to handle object events
+ * \param pw Pointer to client-specific data for callback
+ * \param child Child retrieval context, or NULL for top-level content
+ * \param result Pointer to location to recieve cache handle
+ * \return NSERROR_OK on success, appropriate error otherwise
+ *
+ * Child contents are keyed on the tuple < URL, quirks >.
+ * The quirks field is ignored for child contents whose behaviour is not
+ * affected by quirks mode.
+ *
+ * \todo The above rules should be encoded in the handler_map.
+ *
+ * \todo Is there any way to sensibly reduce the number of parameters here?
+ */
+nserror hlcache_handle_retrieve(const char *url, uint32_t flags,
+ const char *referer, llcache_post_data *post,
+ uint32_t width, uint32_t height,
+ hlcache_handle_callback cb, void *pw,
+ hlcache_child_context *child, hlcache_handle **result);
+
+/**
+ * Release a high-level cache handle
+ *
+ * \param handle Handle to release
+ * \return NSERROR_OK on success, appropriate error otherwise
+ */
+nserror hlcache_handle_release(hlcache_handle *handle);
+
+/**
+ * Retrieve a content object from a cache handle
+ *
+ * \param handle Cache handle to dereference
+ * \return Pointer to content object, or NULL if there is none
+ *
+ * \todo This may not be correct. Ideally, the client should never need to
+ * directly access a content object. It may, therefore, be better to provide a
+ * bunch of veneers here that take a hlcache_handle and invoke the
+ * corresponding content_ API. If there's no content object associated with the
+ * hlcache_handle (e.g. because the source data is still being fetched, so it
+ * doesn't exist yet), then these veneers would behave as a NOP. The important
+ * thing being that the client need not care about this possibility and can
+ * just call the functions with impugnity.
+ */
+struct content *hlcache_handle_get_content(const hlcache_handle *handle);
+
+#endif
diff --git a/content/llcache.c b/content/llcache.c
new file mode 100644
index 000000000..4d2a7f0b5
--- /dev/null
+++ b/content/llcache.c
@@ -0,0 +1,1815 @@
+/*
+ * Copyright 2009 John-Mark Bell <jmb@netsurf-browser.org>
+ *
+ * This file is part of NetSurf, http://www.netsurf-browser.org/
+ *
+ * NetSurf is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * NetSurf is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+/** \file
+ * Low-level resource cache (implementation)
+ */
+
+#define _GNU_SOURCE /* For strndup. Ugh. */
+#include <stdlib.h>
+#include <string.h>
+#include <time.h>
+
+#include <curl/curl.h>
+
+#include "content/fetch.h"
+#include "content/llcache.h"
+#include "utils/messages.h"
+#include "utils/url.h"
+#include "utils/utils.h"
+
+/** State of a low-level cache object fetch */
+typedef enum {
+ LLCACHE_FETCH_INIT, /**< Initial state, before fetch */
+ LLCACHE_FETCH_HEADERS, /**< Fetching headers */
+ LLCACHE_FETCH_DATA, /**< Fetching object data */
+ LLCACHE_FETCH_COMPLETE /**< Fetch completed */
+} llcache_fetch_state;
+
+/** Type of low-level cache object */
+typedef struct llcache_object llcache_object;
+
+/** Handle to low-level cache object */
+struct llcache_handle {
+ llcache_object *object; /**< Pointer to associated object */
+
+ llcache_handle_callback cb; /**< Client callback */
+ void *pw; /**< Client data */
+
+ llcache_fetch_state state; /**< Last known state of object fetch */
+ size_t bytes; /**< Last reported byte count */
+};
+
+/** Low-level cache object user record */
+typedef struct llcache_object_user {
+ /* Must be first in struct */
+ llcache_handle handle; /**< Handle data for client */
+
+ bool iterator_target; /**< This is the an iterator target */
+ bool queued_for_delete; /**< This user is queued for deletion */
+
+ struct llcache_object_user *prev; /**< Previous in list */
+ struct llcache_object_user *next; /**< Next in list */
+} llcache_object_user;
+
+/** Low-level cache object fetch context */
+typedef struct {
+ uint32_t flags; /**< Fetch flags */
+ char *referer; /**< Referring URL, or NULL if none */
+ llcache_post_data *post; /**< POST data, or NULL for GET */
+
+ struct fetch *fetch; /**< Fetch handle for this object */
+
+ llcache_fetch_state state; /**< Current state of object fetch */
+} llcache_fetch_ctx;
+
+/** Cache control data */
+typedef struct {
+ time_t req_time; /**< Time of request */
+ time_t res_time; /**< Time of response */
+ time_t date; /**< Date: response header */
+ time_t expires; /**< Expires: response header */
+#define INVALID_AGE -1
+ int age; /**< Age: response header */
+ int max_age; /**< Max-Age Cache-control parameter */
+ bool no_cache; /**< No-Cache Cache-control parameter */
+ char *etag; /**< Etag: response header */
+ time_t last_modified; /**< Last-Modified: response header */
+} llcache_cache_control;
+
+/** Representation of a fetch header */
+typedef struct {
+ char *name; /**< Header name */
+ char *value; /**< Header value */
+} llcache_header;
+
+/** Low-level cache object */
+/** \todo Consider whether a list is a sane container */
+struct llcache_object {
+ llcache_object *prev; /**< Previous in list */
+ llcache_object *next; /**< Next in list */
+
+ char *url; /**< Post-redirect URL for object */
+
+ /** \todo We need a generic dynamic buffer object */
+ uint8_t *source_data; /**< Source data for object */
+ size_t source_len; /**< Byte length of source data */
+ size_t source_alloc; /**< Allocated size of source buffer */
+
+ llcache_object_user *users; /**< List of users */
+
+ llcache_fetch_ctx fetch; /**< Fetch context for object */
+
+ llcache_cache_control cache; /**< Cache control data for object */
+ llcache_object *candidate; /**< Object to use, if fetch determines
+ * that it is still fresh */
+ uint32_t candidate_count; /**< Count of objects this is a
+ * candidate for */
+
+ llcache_header *headers; /**< Fetch headers */
+ size_t num_headers; /**< Number of fetch headers */
+};
+
+/** Handler for fetch-related queries */
+static llcache_query_callback query_cb;
+/** Data for fetch-related query handler */
+static void *query_cb_pw;
+
+/** Head of the low-level cached object list */
+static llcache_object *llcache_cached_objects;
+/** Head of the low-level uncached object list */
+static llcache_object *llcache_uncached_objects;
+
+static nserror llcache_object_user_new(llcache_handle_callback cb, void *pw,
+ llcache_object_user **user);
+static nserror llcache_object_user_destroy(llcache_object_user *user);
+
+static nserror llcache_object_retrieve(const char *url, uint32_t flags,
+ const char *referer, const llcache_post_data *post,
+ llcache_object **result);
+static nserror llcache_object_retrieve_from_cache(const char *url,
+ uint32_t flags, const char *referer,
+ const llcache_post_data *post, llcache_object **result);
+static bool llcache_object_is_fresh(const llcache_object *object);
+static nserror llcache_object_cache_update(llcache_object *object);
+static nserror llcache_object_clone_cache_data(const llcache_object *source,
+ llcache_object *destination, bool deep);
+static nserror llcache_object_fetch(llcache_object *object, uint32_t flags,
+ const char *referer, const llcache_post_data *post);
+static nserror llcache_object_refetch(llcache_object *object);
+
+static nserror llcache_object_new(const char *url, llcache_object **result);
+static nserror llcache_object_destroy(llcache_object *object);
+static nserror llcache_object_add_user(llcache_object *object,
+ llcache_object_user *user);
+static nserror llcache_object_remove_user(llcache_object *object,
+ llcache_object_user *user);
+
+static nserror llcache_object_add_to_list(llcache_object *object,
+ llcache_object **list);
+static nserror llcache_object_remove_from_list(llcache_object *object,
+ llcache_object **list);
+
+static nserror llcache_object_notify_users(llcache_object *object);
+
+static nserror llcache_clean(void);
+
+static nserror llcache_post_data_clone(const llcache_post_data *orig,
+ llcache_post_data **clone);
+
+static nserror llcache_query_handle_response(bool proceed, void *cbpw);
+
+static void llcache_fetch_callback(fetch_msg msg, void *p, const void *data,
+ unsigned long size, fetch_error_code errorcode);
+static nserror llcache_fetch_redirect(llcache_object *object,
+ const char *target, llcache_object **replacement);
+static nserror llcache_fetch_notmodified(llcache_object *object,
+ llcache_object **replacement);
+static nserror llcache_fetch_split_header(const char *data, size_t len,
+ char **name, char **value);
+static nserror llcache_fetch_parse_header(llcache_object *object,
+ const char *data, size_t len, char **name, char **value);
+static nserror llcache_fetch_process_header(llcache_object *object,
+ const char *data, size_t len);
+static nserror llcache_fetch_process_data(llcache_object *object,
+ const uint8_t *data, size_t len);
+static nserror llcache_fetch_auth(llcache_object *object,
+ const char *realm);
+static nserror llcache_fetch_cert_error(llcache_object *object,
+ const struct ssl_cert_info *certs, size_t num);
+
+
+/******************************************************************************
+ * Public API *
+ ******************************************************************************/
+
+/**
+ * Initialise the low-level cache
+ *
+ * \param cb Query handler
+ * \param pw Pointer to query handler data
+ * \return NSERROR_OK on success, appropriate error otherwise.
+ */
+nserror llcache_initialise(llcache_query_callback cb, void *pw)
+{
+ query_cb = cb;
+ query_cb_pw = pw;
+
+ return NSERROR_OK;
+}
+
+/**
+ * Poll the low-level cache
+ *
+ * \return NSERROR_OK on success, appropriate error otherwise.
+ */
+nserror llcache_poll(void)
+{
+ llcache_object *object;
+
+ /* Catch new users up with state of objects */
+ for (object = llcache_cached_objects; object != NULL;
+ object = object->next) {
+ llcache_object_notify_users(object);
+ }
+
+ for (object = llcache_uncached_objects; object != NULL;
+ object = object->next) {
+ llcache_object_notify_users(object);
+ }
+
+ /* Attempt to clean the cache */
+ llcache_clean();
+
+ return NSERROR_OK;
+}
+
+/**
+ * Retrieve a handle for a low-level cache object
+ *
+ * \param url URL of the object to fetch
+ * \param flags Object retrieval flags
+ * \param referer Referring URL, or NULL if none
+ * \param post POST data, or NULL for a GET request
+ * \param cb Client callback for events
+ * \param pw Pointer to client-specific data
+ * \param result Pointer to location to recieve cache handle
+ * \return NSERROR_OK on success, appropriate error otherwise
+ */
+nserror llcache_handle_retrieve(const char *url, uint32_t flags,
+ const char *referer, const llcache_post_data *post,
+ llcache_handle_callback cb, void *pw,
+ llcache_handle **result)
+{
+ nserror error;
+ llcache_object_user *user;
+ llcache_object *object;
+
+ /* Can we fetch this URL at all? */
+ if (fetch_can_fetch(url) == false)
+ return NSERROR_NO_FETCH_HANDLER;
+
+ /* Create a new object user */
+ error = llcache_object_user_new(cb, pw, &user);
+ if (error != NSERROR_OK)
+ return error;
+
+ /* Retrieve a suitable object from the cache,
+ * creating a new one if needed. */
+ error = llcache_object_retrieve(url, flags, referer, post, &object);
+ if (error != NSERROR_OK) {
+ llcache_object_user_destroy(user);
+ return error;
+ }
+
+ /* Add user to object */
+ llcache_object_add_user(object, user);
+
+ *result = &user->handle;
+
+ return NSERROR_OK;
+}
+
+/**
+ * Change the callback associated with a low-level cache handle
+ *
+ * \param handle Handle to change callback of
+ * \param cb New callback
+ * \param pw Client data for new callback
+ * \return NSERROR_OK on success, appropriate error otherwise
+ */
+nserror llcache_handle_change_callback(llcache_handle *handle,
+ llcache_handle_callback cb, void *pw)
+{
+ handle->cb = cb;
+ handle->pw = pw;
+
+ return NSERROR_OK;
+}
+
+/**
+ * Release a low-level cache handle
+ *
+ * \param handle Handle to release
+ * \return NSERROR_OK on success, appropriate error otherwise
+ */
+nserror llcache_handle_release(llcache_handle *handle)
+{
+ nserror error = NSERROR_OK;
+ llcache_object *object = handle->object;
+ llcache_object_user *user = (llcache_object_user *) handle;
+
+ /* Remove the user from the object and destroy it */
+ error = llcache_object_remove_user(object, user);
+ if (error == NSERROR_OK) {
+ /* Can't delete user object if it's the target of an iterator */
+ if (user->iterator_target)
+ user->queued_for_delete = true;
+ else
+ error = llcache_object_user_destroy(user);
+ }
+
+ return error;
+}
+
+/**
+ * Retrieve the post-redirect URL of a low-level cache object
+ *
+ * \param handle Handle to retrieve URL from
+ * \return Post-redirect URL of cache object
+ */
+const char *llcache_handle_get_url(const llcache_handle *handle)
+{
+ return handle->object != NULL ? handle->object->url : NULL;
+}
+
+/**
+ * Retrieve source data of a low-level cache object
+ *
+ * \param handle Handle to retrieve source data from
+ * \param size Pointer to location to receive byte length of data
+ * \return Pointer to source data
+ */
+const uint8_t *llcache_handle_get_source_data(const llcache_handle *handle,
+ size_t *size)
+{
+ *size = handle->object != NULL ? handle->object->source_len : 0;
+
+ return handle->object != NULL ? handle->object->source_data : NULL;
+}
+
+/**
+ * Retrieve a header value associated with a low-level cache object
+ *
+ * \param handle Handle to retrieve header from
+ * \param key Header name
+ * \return Header value, or NULL if header does not exist
+ *
+ * \todo Make the key an enumeration, to avoid needless string comparisons
+ * \todo Forcing the client to parse the header value seems wrong.
+ * Better would be to return the actual value part and an array of
+ * key-value pairs for any additional parameters.
+ */
+const char *llcache_handle_get_header(const llcache_handle *handle,
+ const char *key)
+{
+ const llcache_object *object = handle->object;
+ size_t i;
+
+ if (object == NULL)
+ return NULL;
+
+ /* About as trivial as possible */
+ for (i = 0; i < object->num_headers; i++) {
+ if (strcasecmp(key, object->headers[i].name) == 0)
+ return object->headers[i].value;
+ }
+
+ return NULL;
+}
+
+/**
+ * Determine if the same underlying object is referenced by the given handles
+ *
+ * \param a First handle
+ * \param b Second handle
+ * \return True if handles reference the same object, false otherwise
+ */
+bool llcache_handle_references_same_object(const llcache_handle *a,
+ const llcache_handle *b)
+{
+ return a->object == b->object;
+}
+
+/******************************************************************************
+ * Low-level cache internals *
+ ******************************************************************************/
+
+/**
+ * Create a new object user
+ *
+ * \param cb Callback routine
+ * \param pw Private data for callback
+ * \param user Pointer to location to receive result
+ * \return NSERROR_OK on success, appropriate error otherwise
+ */
+nserror llcache_object_user_new(llcache_handle_callback cb, void *pw,
+ llcache_object_user **user)
+{
+ llcache_object_user *u = calloc(1, sizeof(llcache_object_user));
+ if (u == NULL)
+ return NSERROR_NOMEM;
+
+ u->handle.cb = cb;
+ u->handle.pw = pw;
+
+ *user = u;
+
+ return NSERROR_OK;
+}
+
+/**
+ * Destroy an object user
+ *
+ * \param user User to destroy
+ * \return NSERROR_OK on success, appropriate error otherwise
+ *
+ * \pre User is not attached to an object
+ */
+nserror llcache_object_user_destroy(llcache_object_user *user)
+{
+ free(user);
+
+ return NSERROR_OK;
+}
+
+/**
+ * Retrieve an object from the cache, fetching it if necessary.
+ *
+ * \param url URL of object to retrieve
+ * \param flags Fetch flags
+ * \param referer Referring URL, or NULL if none
+ * \param post POST data, or NULL for a GET request
+ * \param result Pointer to location to recieve retrieved object
+ * \return NSERROR_OK on success, appropriate error otherwise
+ */
+nserror llcache_object_retrieve(const char *url, uint32_t flags,
+ const char *referer, const llcache_post_data *post,
+ llcache_object **result)
+{
+ nserror error;
+ llcache_object *obj;
+ bool has_query;
+ url_func_result res;
+ struct url_components components;
+
+ /**
+ * Caching Rules:
+ *
+ * 1) Forced fetches are never cached
+ * 2) GET requests with query segments are never cached
+ * 3) POST requests are never cached
+ *
+ * \todo Find out if restriction (2) can be removed
+ */
+
+ /* Look for a query segment */
+ res = url_get_components(url, &components);
+ if (res == URL_FUNC_NOMEM)
+ return NSERROR_NOMEM;
+
+ has_query = (components.query != NULL);
+
+ url_destroy_components(&components);
+
+ if (flags & LLCACHE_RETRIEVE_FORCE_FETCH || has_query || post != NULL) {
+ /* Create new object */
+ error = llcache_object_new(url, &obj);
+ if (error != NSERROR_OK)
+ return error;
+
+ /* Attempt to kick-off fetch */
+ error = llcache_object_fetch(obj, flags, referer, post);
+ if (error != NSERROR_OK) {
+ llcache_object_destroy(obj);
+ return error;
+ }
+
+ /* Add new object to uncached list */
+ llcache_object_add_to_list(obj, &llcache_uncached_objects);
+ } else {
+ error = llcache_object_retrieve_from_cache(url, flags, referer,
+ post, &obj);
+ if (error != NSERROR_OK)
+ return error;
+
+ /* Returned object is already in the cached list */
+ }
+
+ *result = obj;
+
+ return NSERROR_OK;
+}
+
+/**
+ * Retrieve a potentially cached object
+ *
+ * \param url URL of object to retrieve
+ * \param flags Fetch flags
+ * \param referer Referring URL, or NULL if none
+ * \param post POST data, or NULL for a GET request
+ * \param result Pointer to location to recieve retrieved object
+ * \return NSERROR_OK on success, appropriate error otherwise
+ */
+nserror llcache_object_retrieve_from_cache(const char *url, uint32_t flags,
+ const char *referer, const llcache_post_data *post,
+ llcache_object **result)
+{
+ nserror error;
+ llcache_object *obj, *newest = NULL;
+
+ /* Search for the most recently fetched matching object */
+ for (obj = llcache_cached_objects; obj != NULL; obj = obj->next) {
+ if (strcasecmp(obj->url, url) == 0 && (newest == NULL ||
+ obj->cache.req_time > newest->cache.req_time))
+ newest = obj;
+ }
+
+ if (newest != NULL && llcache_object_is_fresh(newest)) {
+ /* Found a suitable object, and it's still fresh, so use it */
+ obj = newest;
+
+ /* The client needs to catch up with the object's state.
+ * This will occur the next time that llcache_poll is called.
+ */
+ } else if (newest != NULL) {
+ /* Found a candidate object but it needs freshness validation */
+ /* Create a new object */
+ error = llcache_object_new(url, &obj);
+ if (error != NSERROR_OK)
+ return error;
+
+ /* Clone candidate's cache data */
+ error = llcache_object_clone_cache_data(newest, obj, true);
+ if (error != NSERROR_OK) {
+ llcache_object_destroy(obj);
+ return error;
+ }
+
+ /* Record candidate, so we can fall back if it is still fresh */
+ newest->candidate_count++;
+ obj->candidate = newest;
+
+ /* Attempt to kick-off fetch */
+ error = llcache_object_fetch(obj, flags, referer, post);
+ if (error != NSERROR_OK) {
+ newest->candidate_count--;
+ llcache_object_destroy(obj);
+ return error;
+ }
+
+ /* Add new object to cache */
+ llcache_object_add_to_list(obj, &llcache_cached_objects);
+ } else {
+ /* No object found; create a new one */
+ /* Create new object */
+ error = llcache_object_new(url, &obj);
+ if (error != NSERROR_OK)
+ return error;
+
+ /* Attempt to kick-off fetch */
+ error = llcache_object_fetch(obj, flags, referer, post);
+ if (error != NSERROR_OK) {
+ llcache_object_destroy(obj);
+ return error;
+ }
+
+ /* Add new object to cache */
+ llcache_object_add_to_list(obj, &llcache_cached_objects);
+ }
+
+ *result = obj;
+
+ return NSERROR_OK;
+}
+
+/**
+ * Determine if an object is still fresh
+ *
+ * \param object Object to consider
+ * \return True if object is still fresh, false otherwise
+ */
+bool llcache_object_is_fresh(const llcache_object *object)
+{
+ const llcache_cache_control *cd = &object->cache;
+ int current_age, freshness_lifetime;
+ time_t now = time(NULL);
+
+ /* Calculate staleness of cached object as per RFC 2616 13.2.3/13.2.4 */
+ current_age = max(0, (cd->res_time - cd->date));
+ current_age = max(current_age, (cd->age == INVALID_AGE) ? 0 : cd->age);
+ current_age += cd->res_time - cd->req_time + now - cd->res_time;
+
+ /* Determine freshness lifetime of this object */
+ if (cd->max_age != INVALID_AGE)
+ freshness_lifetime = cd->max_age;
+ else if (cd->expires != 0)
+ freshness_lifetime = cd->expires - cd->date;
+ else if (cd->last_modified != 0)
+ freshness_lifetime = (now - cd->last_modified) / 10;
+ else
+ freshness_lifetime = 0;
+
+ /* The object is fresh if its current age is within the freshness
+ * lifetime or if we're still fetching the object */
+ return (freshness_lifetime > current_age ||
+ object->fetch.state != LLCACHE_FETCH_COMPLETE);
+}
+
+/**
+ * Update an object's cache state
+ *
+ * \param object Object to update cache for
+ * \return NSERROR_OK.
+ */
+nserror llcache_object_cache_update(llcache_object *object)
+{
+ if (object->cache.date == 0)
+ object->cache.date = time(NULL);
+
+ /** \todo Any magic we need to do for no_cache? */
+
+ return NSERROR_OK;
+}
+
+/**
+ * Clone an object's cache data
+ *
+ * \param source Source object containing cache data to clone
+ * \param destination Destination object to clone cache data into
+ * \param deep Whether to deep-copy the data or not
+ * \return NSERROR_OK on success, appropriate error otherwise
+ */
+nserror llcache_object_clone_cache_data(const llcache_object *source,
+ llcache_object *destination, bool deep)
+{
+ /* ETag must be first, as it can fail when deep cloning */
+ if (source->cache.etag != NULL) {
+ char *etag = source->cache.etag;
+
+ if (deep) {
+ /* Copy the etag */
+ etag = strdup(source->cache.etag);
+ if (etag == NULL)
+ return NSERROR_NOMEM;
+ }
+
+ if (destination->cache.etag != NULL)
+ free(destination->cache.etag);
+
+ destination->cache.etag = etag;
+ }
+
+ destination->cache.req_time = source->cache.req_time;
+ destination->cache.res_time = source->cache.res_time;
+
+ if (source->cache.date != 0)
+ destination->cache.date = source->cache.date;
+
+ if (source->cache.expires != 0)
+ destination->cache.expires = source->cache.expires;
+
+ if (source->cache.age != INVALID_AGE)
+ destination->cache.age = source->cache.age;
+
+ if (source->cache.max_age != INVALID_AGE)
+ destination->cache.max_age = source->cache.max_age;
+
+ if (source->cache.no_cache)
+ destination->cache.no_cache = source->cache.no_cache;
+
+ if (source->cache.last_modified != 0)
+ destination->cache.last_modified = source->cache.last_modified;
+
+ return NSERROR_OK;
+}
+
+/**
+ * Kick-off a fetch for an object
+ *
+ * \param object Object to fetch
+ * \param flags Fetch flags
+ * \param referer Referring URL, or NULL for none
+ * \param post POST data, or NULL for GET
+ * \return NSERROR_OK on success, appropriate error otherwise
+ *
+ * \pre object::url must contain the URL to fetch
+ * \pre If there is a freshness validation candidate,
+ * object::candidate and object::cache must be filled in
+ * \pre There must not be a fetch in progress for \a object
+ */
+nserror llcache_object_fetch(llcache_object *object, uint32_t flags,
+ const char *referer, const llcache_post_data *post)
+{
+ nserror error;
+ char *referer_clone = NULL;
+ llcache_post_data *post_clone = NULL;
+
+ if (referer != NULL) {
+ referer_clone = strdup(referer);
+ if (referer_clone == NULL)
+ return NSERROR_NOMEM;
+ }
+
+ if (post != NULL) {
+ error = llcache_post_data_clone(post, &post_clone);
+ if (error != NSERROR_OK) {
+ free(referer_clone);
+ return error;
+ }
+ }
+
+ object->fetch.flags = flags;
+ object->fetch.referer = referer_clone;
+ object->fetch.post = post_clone;
+
+ return llcache_object_refetch(object);
+}
+
+/**
+ * (Re)fetch an object
+ *
+ * \param object Object to refetch
+ * \return NSERROR_OK on success, appropriate error otherwise
+ *
+ * \pre The fetch parameters in object->fetch must be populated
+ */
+nserror llcache_object_refetch(llcache_object *object)
+{
+ const char *urlenc = NULL;
+ /** \todo Why is fetch_start's post_multipart parameter not const? */
+ struct fetch_multipart_data *multipart = NULL;
+ /** \todo Why is the headers parameter of fetch_start not const? */
+ char **headers = NULL;
+ int header_idx = 0;
+
+ if (object->fetch.post != NULL) {
+ if (object->fetch.post->type == LLCACHE_POST_URL_ENCODED)
+ urlenc = object->fetch.post->data.urlenc;
+ else
+ multipart = object->fetch.post->data.multipart;
+ }
+
+ /* Generate cache-control headers */
+ headers = malloc(3 * sizeof(char *));
+ if (headers == NULL)
+ return NSERROR_NOMEM;
+
+ if (object->cache.etag != NULL) {
+ const size_t len = SLEN("If-None-Match: ") +
+ strlen(object->cache.etag) + 1;
+
+ headers[header_idx] = malloc(len);
+ if (headers[header_idx] == NULL) {
+ free(headers);
+ return NSERROR_NOMEM;
+ }
+
+ snprintf(headers[header_idx], len, "If-None-Match: %s",
+ object->cache.etag);
+
+ header_idx++;
+ }
+ if (object->cache.date != 0) {
+ /* Maximum length of an RFC 1123 date is 29 bytes */
+ const size_t len = SLEN("If-Modified-Since: ") + 29 + 1;
+
+ headers[header_idx] = malloc(len);
+ if (headers[header_idx] == NULL) {
+ while (--header_idx >= 0)
+ free(headers[header_idx]);
+ free(headers);
+ return NSERROR_NOMEM;
+ }
+
+ snprintf(headers[header_idx], len, "If-Modified-Since: %s",
+ rfc1123_date(object->cache.date));
+
+ header_idx++;
+ }
+ headers[header_idx] = NULL;
+
+ /* Reset cache control data */
+ object->cache.req_time = time(NULL);
+ object->cache.res_time = 0;
+ object->cache.date = 0;
+ object->cache.expires = 0;
+ object->cache.age = INVALID_AGE;
+ object->cache.max_age = INVALID_AGE;
+ object->cache.no_cache = false;
+ free(object->cache.etag);
+ object->cache.etag = NULL;
+ object->cache.last_modified = 0;
+
+ /* Kick off fetch */
+ object->fetch.fetch = fetch_start(object->url, object->fetch.referer,
+ llcache_fetch_callback, object,
+ object->fetch.flags & LLCACHE_RETRIEVE_NO_ERROR_PAGES,
+ urlenc, multipart,
+ object->fetch.flags & LLCACHE_RETRIEVE_VERIFIABLE,
+ NULL, /** \todo Remove parent from this API */
+ headers);
+
+ /* Clean up cache-control headers */
+ while (--header_idx >= 0)
+ free(headers[header_idx]);
+ free(headers);
+
+ /* Did we succeed in creating a fetch? */
+ if (object->fetch.fetch == NULL)
+ return NSERROR_NOMEM;
+
+ return NSERROR_OK;
+}
+
+/**
+ * Create a new low-level cache object
+ *
+ * \param url URL of object to create
+ * \param result Pointer to location to receive result
+ * \return NSERROR_OK on success, appropriate error otherwise
+ */
+nserror llcache_object_new(const char *url, llcache_object **result)
+{
+ llcache_object *obj = calloc(1, sizeof(llcache_object));
+ if (obj == NULL)
+ return NSERROR_NOMEM;
+
+ obj->url = strdup(url);
+ if (obj->url == NULL) {
+ free(obj);
+ return NSERROR_NOMEM;
+ }
+
+ *result = obj;
+
+ return NSERROR_OK;
+}
+
+/**
+ * Destroy a low-level cache object
+ *
+ * \param object Object to destroy
+ * \return NSERROR_OK on success, appropriate error otherwise
+ *
+ * \pre Object is detached from cache list
+ * \pre Object has no users
+ * \pre Object is not a candidate (i.e. object::candidate_count == 0)
+ */
+nserror llcache_object_destroy(llcache_object *object)
+{
+ size_t i;
+
+ free(object->url);
+ free(object->source_data);
+
+ if (object->fetch.fetch != NULL) {
+ fetch_abort(object->fetch.fetch);
+ object->fetch.fetch = NULL;
+ }
+
+ free(object->fetch.referer);
+
+ if (object->fetch.post != NULL) {
+ if (object->fetch.post->type == LLCACHE_POST_URL_ENCODED) {
+ free(object->fetch.post->data.urlenc);
+ } else {
+ fetch_multipart_data_destroy(
+ object->fetch.post->data.multipart);
+ }
+
+ free(object->fetch.post);
+ }
+
+ free(object->cache.etag);
+
+ for (i = 0; i < object->num_headers; i++) {
+ free(object->headers[i].name);
+ free(object->headers[i].value);
+ }
+ free(object->headers);
+
+ free(object);
+
+ return NSERROR_OK;
+}
+
+/**
+ * Add a user to a low-level cache object
+ *
+ * \param object Object to add user to
+ * \param user User to add
+ * \return NSERROR_OK.
+ */
+nserror llcache_object_add_user(llcache_object *object,
+ llcache_object_user *user)
+{
+ user->handle.object = object;
+
+ user->prev = NULL;
+ user->next = object->users;
+
+ if (object->users != NULL)
+ object->users->prev = user;
+ object->users = user;
+
+ return NSERROR_OK;
+}
+
+/**
+ * Remove a user from a low-level cache object
+ *
+ * \param object Object to remove user from
+ * \param user User to remove
+ * \return NSERROR_OK.
+ */
+nserror llcache_object_remove_user(llcache_object *object,
+ llcache_object_user *user)
+{
+ if (user == object->users)
+ object->users = user->next;
+ else
+ user->prev->next = user->next;
+
+ if (user->next != NULL)
+ user->next->prev = user->prev;
+
+ return NSERROR_OK;
+}
+
+/**
+ * Add a low-level cache object to a cache list
+ *
+ * \param object Object to add
+ * \param list List to add to
+ * \return NSERROR_OK
+ */
+nserror llcache_object_add_to_list(llcache_object *object,
+ llcache_object **list)
+{
+ object->prev = NULL;
+ object->next = *list;
+
+ if (*list != NULL)
+ (*list)->prev = object;
+ *list = object;
+
+ return NSERROR_OK;
+}
+
+/**
+ * Remove a low-level cache object from a cache list
+ *
+ * \param object Object to remove
+ * \param list List to remove from
+ * \return NSERROR_OK
+ */
+nserror llcache_object_remove_from_list(llcache_object *object,
+ llcache_object **list)
+{
+ if (object == *list)
+ *list = object->next;
+ else
+ object->prev->next = object->next;
+
+ if (object->next != NULL)
+ object->next->prev = object->next;
+
+ return NSERROR_OK;
+}
+
+/**
+ * Notify users of an object's current state
+ *
+ * \param object Object to notify users about
+ * \return NSERROR_OK on success, appropriate error otherwise
+ */
+nserror llcache_object_notify_users(llcache_object *object)
+{
+ nserror error;
+ llcache_object_user *user, *next_user;
+ llcache_event event;
+
+ /**
+ * State transitions and event emission for users.
+ * Rows: user state. Cols: object state.
+ *
+ * User\Obj INIT HEADERS DATA COMPLETE
+ * INIT - T T* T*
+ * HEADERS - - T T*
+ * DATA - - M T
+ * COMPLETE - - - -
+ *
+ * T => transition user to object state
+ * M => no transition required, but may need to emit event
+ *
+ * The transitions marked with an asterisk can be removed by moving
+ * the user context into the subsequent state and then reevaluating.
+ *
+ * Events are issued as follows:
+ *
+ * HAD_HEADERS: on transition from HEADERS -> DATA state
+ * HAD_DATA : in DATA state, whenever there's new source data
+ * DONE : on transition from DATA -> COMPLETE state
+ */
+
+ for (user = object->users; user != NULL; user = next_user) {
+ /* Emit necessary events to bring the user up-to-date */
+ llcache_handle *handle = &user->handle;
+ llcache_fetch_state hstate = handle->state;
+ llcache_fetch_state objstate = object->fetch.state;
+
+ /* Save identity of next user in case client destroys
+ * the user underneath us */
+ user->iterator_target = true;
+ next_user = user->next;
+
+ /* User: INIT, Obj: HEADERS, DATA, COMPLETE => User->HEADERS */
+ if (hstate == LLCACHE_FETCH_INIT &&
+ objstate > LLCACHE_FETCH_INIT) {
+ hstate = LLCACHE_FETCH_HEADERS;
+ }
+
+ /* User: HEADERS, Obj: DATA, COMPLETE => User->DATA */
+ if (hstate == LLCACHE_FETCH_HEADERS &&
+ objstate > LLCACHE_FETCH_HEADERS) {
+ /* Emit HAD_HEADERS event */
+ event.type = LLCACHE_EVENT_HAD_HEADERS;
+
+ error = handle->cb(handle, &event, handle->pw);
+ if (error != NSERROR_OK) {
+ user->iterator_target = false;
+ return error;
+ }
+
+ if (user->queued_for_delete) {
+ llcache_object_user_destroy(user);
+ continue;
+ }
+
+ hstate = LLCACHE_FETCH_DATA;
+ }
+
+ /* User: DATA, Obj: DATA, COMPLETE, more source available */
+ if (hstate == LLCACHE_FETCH_DATA &&
+ objstate >= LLCACHE_FETCH_DATA &&
+ object->source_len > handle->bytes) {
+ /* Emit HAD_DATA event */
+ event.type = LLCACHE_EVENT_HAD_DATA;
+ event.data.data.buf =
+ object->source_data + handle->bytes;
+ event.data.data.len =
+ object->source_len - handle->bytes;
+
+ error = handle->cb(handle, &event, handle->pw);
+ if (error != NSERROR_OK) {
+ user->iterator_target = false;
+ return error;
+ }
+
+ if (user->queued_for_delete) {
+ llcache_object_user_destroy(user);
+ continue;
+ }
+
+ /* Update record of last byte emitted */
+ handle->bytes = object->source_len;
+ }
+
+ /* User: DATA, Obj: COMPLETE => User->COMPLETE */
+ if (hstate == LLCACHE_FETCH_DATA &&
+ objstate > LLCACHE_FETCH_DATA) {
+ /* Emit DONE event */
+ event.type = LLCACHE_EVENT_DONE;
+
+ error = handle->cb(handle, &event, handle->pw);
+ if (error != NSERROR_OK) {
+ user->iterator_target = false;
+ return error;
+ }
+
+ if (user->queued_for_delete) {
+ llcache_object_user_destroy(user);
+ continue;
+ }
+
+ hstate = LLCACHE_FETCH_COMPLETE;
+ }
+
+ /* No longer the target of an iterator */
+ user->iterator_target = false;
+
+ /* Sync handle's state with reality */
+ handle->state = hstate;
+ }
+
+ return NSERROR_OK;
+}
+
+/**
+ * Attempt to clean the cache
+ *
+ * \return NSERROR_OK.
+ */
+nserror llcache_clean(void)
+{
+ llcache_object *object, *next;
+
+ /* Candidates for cleaning are (in order of priority):
+ *
+ * 1) Uncacheable objects with no users
+ * 2) Stale cacheable objects with no users or pending fetches
+ * 3) Fresh cacheable objects with no users or pending fetches
+ */
+
+ /* 1) Uncacheable objects with no users */
+ for (object = llcache_uncached_objects; object != NULL; object = next) {
+ next = object->next;
+
+ /* The candidate count of uncacheable objects is always 0 */
+ if (object->users == NULL && object->candidate_count == 0) {
+ llcache_object_remove_from_list(object,
+ &llcache_uncached_objects);
+ llcache_object_destroy(object);
+ }
+ }
+
+ /* 2) Stale cacheable objects with no users or pending fetches */
+ for (object = llcache_cached_objects; object != NULL; object = next) {
+ next = object->next;
+
+ if (object->users == NULL && object->candidate_count == 0 &&
+ llcache_object_is_fresh(object) == false) {
+ llcache_object_remove_from_list(object,
+ &llcache_cached_objects);
+ llcache_object_destroy(object);
+ }
+ }
+
+ /* 3) Fresh cacheable objects with no users or pending fetches */
+ /** \todo This one only happens if the cache is too large */
+
+ return NSERROR_OK;
+}
+
+/**
+ * Clone a POST data object
+ *
+ * \param orig Object to clone
+ * \param clone Pointer to location to receive clone
+ * \return NSERROR_OK on success, appropriate error otherwise
+ */
+nserror llcache_post_data_clone(const llcache_post_data *orig,
+ llcache_post_data **clone)
+{
+ llcache_post_data *post_clone;
+
+ post_clone = calloc(1, sizeof(llcache_post_data));
+ if (post_clone == NULL)
+ return NSERROR_NOMEM;
+
+ post_clone->type = orig->type;
+
+ /* Deep-copy the type-specific data */
+ if (orig->type == LLCACHE_POST_URL_ENCODED) {
+ post_clone->data.urlenc = strdup(orig->data.urlenc);
+ if (post_clone->data.urlenc == NULL) {
+ free(post_clone);
+
+ return NSERROR_NOMEM;
+ }
+ } else {
+ post_clone->data.multipart = fetch_multipart_data_clone(
+ orig->data.multipart);
+ if (post_clone->data.multipart == NULL) {
+ free(post_clone);
+
+ return NSERROR_NOMEM;
+ }
+ }
+
+ *clone = post_clone;
+
+ return NSERROR_OK;
+}
+
+/**
+ * Handle a query response
+ *
+ * \param proceed Whether to proceed with fetch
+ * \param cbpw Our context for query
+ * \return NSERROR_OK on success, appropriate error otherwise
+ */
+nserror llcache_query_handle_response(bool proceed, void *cbpw)
+{
+ nserror error;
+ llcache_event event;
+ llcache_object_user *user;
+ llcache_object *object = cbpw;
+
+ /* Refetch, using existing fetch parameters, if client allows us to */
+ if (proceed)
+ return llcache_object_refetch(object);
+
+ /* Inform client(s) that object fetch failed */
+ event.type = LLCACHE_EVENT_ERROR;
+ /** \todo More appropriate error message */
+ event.data.msg = messages_get("FetchFailed");
+
+ for (user = object->users; user != NULL; user = user->next) {
+ error = user->handle.cb(&user->handle, &event, user->handle.pw);
+ if (error != NSERROR_OK)
+ return error;
+ }
+
+ return NSERROR_OK;
+}
+
+/**
+ * Handler for fetch events
+ *
+ * \param msg Type of fetch event
+ * \param p Our private data
+ * \param data Event data
+ * \param size Length of data in bytes
+ * \param errorcode Reason for fetch error
+ */
+void llcache_fetch_callback(fetch_msg msg, void *p, const void *data,
+ unsigned long size, fetch_error_code errorcode)
+{
+ nserror error = NSERROR_OK;
+ llcache_object *object = p;
+ llcache_object_user *user;
+ llcache_event event;
+
+ switch (msg) {
+ /* 3xx responses */
+ case FETCH_REDIRECT:
+ /* Request resulted in a redirect */
+ error = llcache_fetch_redirect(object, data, &object);
+ break;
+ case FETCH_NOTMODIFIED:
+ /* Conditional request determined that cached object is fresh */
+ error = llcache_fetch_notmodified(object, &object);
+ break;
+
+ /* Normal 2xx state machine */
+ case FETCH_HEADER:
+ /* Received a fetch header */
+ object->fetch.state = LLCACHE_FETCH_HEADERS;
+
+ error = llcache_fetch_process_header(object, data, size);
+ case FETCH_TYPE:
+ /** \todo Purge FETCH_TYPE completely */
+ break;
+ case FETCH_DATA:
+ /* Received some data */
+ object->fetch.state = LLCACHE_FETCH_DATA;
+
+ error = llcache_fetch_process_data(object, data, size);
+ break;
+ case FETCH_FINISHED:
+ /* Finished fetching */
+ object->fetch.state = LLCACHE_FETCH_COMPLETE;
+ object->fetch.fetch = NULL;
+
+ llcache_object_cache_update(object);
+ break;
+
+ /* Out-of-band information */
+ case FETCH_ERROR:
+ /* An error occurred while fetching */
+ fetch_abort(object->fetch.fetch);
+ object->fetch.fetch = NULL;
+ /** \todo Ensure this object becomes stale */
+
+ /** \todo Consider using errorcode for something */
+
+ event.type = LLCACHE_EVENT_ERROR;
+ event.data.msg = data;
+
+ for (user = object->users; user != NULL; user = user->next) {
+ error = user->handle.cb(&user->handle, &event,
+ user->handle.pw);
+ if (error != NSERROR_OK)
+ break;
+ }
+ break;
+ case FETCH_PROGRESS:
+ /* Progress update */
+ event.type = LLCACHE_EVENT_PROGRESS;
+ event.data.msg = data;
+
+ for (user = object->users; user != NULL; user = user->next) {
+ error = user->handle.cb(&user->handle, &event,
+ user->handle.pw);
+ if (error != NSERROR_OK)
+ break;
+ }
+ break;
+
+ /* Events requiring action */
+ case FETCH_AUTH:
+ /* Need Authentication */
+ error = llcache_fetch_auth(object, data);
+ break;
+ case FETCH_CERT_ERR:
+ /* Something went wrong when validating TLS certificates */
+ error = llcache_fetch_cert_error(object, data, size);
+ break;
+ }
+
+ /* Deal with any errors reported by event handlers */
+ if (error != NSERROR_OK) {
+ /** \todo Error handling */
+ if (object->fetch.fetch != NULL) {
+ fetch_abort(object->fetch.fetch);
+ object->fetch.fetch = NULL;
+ }
+ return;
+ }
+
+ /* Keep users in sync with reality */
+ error = llcache_object_notify_users(object);
+ if (error != NSERROR_OK) {
+ /** \todo Error handling */
+ if (object->fetch.fetch != NULL) {
+ fetch_abort(object->fetch.fetch);
+ object->fetch.fetch = NULL;
+ }
+ }
+}
+
+/**
+ * Handle FETCH_REDIRECT event
+ *
+ * \param object Object being redirected
+ * \param target Target of redirect (may be relative)
+ * \param replacement Pointer to location to receive replacement object
+ * \return NSERROR_OK on success, appropriate error otherwise
+ */
+nserror llcache_fetch_redirect(llcache_object *object, const char *target,
+ llcache_object **replacement)
+{
+ nserror error;
+ llcache_object *dest;
+ llcache_object_user *user, *next;
+ const llcache_post_data *post = object->fetch.post;
+ char *url, *absurl;
+ url_func_result result;
+ /* Extract HTTP response code from the fetch object */
+ long http_code = fetch_http_code(object->fetch.fetch);
+
+ /* Abort fetch for this object */
+ fetch_abort(object->fetch.fetch);
+ object->fetch.fetch = NULL;
+
+ /** \todo Limit redirect depth, or detect cycles */
+
+ /* Make target absolute */
+ result = url_join(target, object->url, &absurl);
+ if (result != URL_FUNC_OK) {
+ return NSERROR_NOMEM;
+ }
+
+ /* Ensure target is normalised */
+ result = url_normalize(absurl, &url);
+
+ /* No longer require absolute url */
+ free(absurl);
+
+ if (result != URL_FUNC_OK) {
+ return NSERROR_NOMEM;
+ }
+
+ /** \todo Ensure that redirects to file:/// don't happen? */
+
+ /** \todo What happens if we've no way of handling this URL? */
+
+ /** \todo All the magical processing for the various redirect types */
+ if (http_code == 301 || http_code == 302 || http_code == 303) {
+ /* 301, 302, 303 redirects are all unconditional GET requests */
+ post = NULL;
+ } else {
+ /** \todo 300, 305, 307 */
+ free(url);
+ return NSERROR_OK;
+ }
+
+ /* Attempt to fetch target URL */
+ error = llcache_object_retrieve(url, object->fetch.flags,
+ object->fetch.referer, object->fetch.post,
+ &dest);
+
+ /* No longer require url */
+ free(url);
+
+ if (error != NSERROR_OK)
+ return error;
+
+ /* Move user(s) to replacement object */
+ for (user = object->users; user != NULL; user = next) {
+ next = user->next;
+
+ llcache_object_remove_user(object, user);
+ llcache_object_add_user(dest, user);
+ }
+
+ /* Dest is now our object */
+ *replacement = dest;
+
+ return NSERROR_OK;
+}
+
+/**
+ * Handle FETCH_NOTMODIFIED event
+ *
+ * \param object Object to process
+ * \param replacement Pointer to location to receive replacement object
+ * \return NSERROR_OK.
+ */
+nserror llcache_fetch_notmodified(llcache_object *object,
+ llcache_object **replacement)
+{
+ llcache_object_user *user, *next;
+
+ /* Move user(s) to candidate content */
+ for (user = object->users; user != NULL; user = next) {
+ next = user->next;
+
+ llcache_object_remove_user(object, user);
+ llcache_object_add_user(object->candidate, user);
+ }
+
+ /* Candidate is no longer a candidate for us */
+ object->candidate->candidate_count--;
+
+ /* Clone our cache control data into the candidate */
+ llcache_object_clone_cache_data(object, object->candidate, false);
+ /* Bring candidate's cache data up to date */
+ llcache_object_cache_update(object->candidate);
+
+ /* Invalidate our cache-control data */
+ memset(&object->cache, 0, sizeof(llcache_cache_control));
+
+ /* Ensure fetch has stopped */
+ /** \todo Are there any other fields that need invalidating? */
+ fetch_abort(object->fetch.fetch);
+ object->fetch.fetch = NULL;
+
+ /* Candidate is now our object */
+ *replacement = object->candidate;
+
+ /** \todo Ensure that old object gets flushed from the cache */
+
+ return NSERROR_OK;
+}
+
+/**
+ * Split a fetch header into name and value
+ *
+ * \param data Header string
+ * \param len Byte length of header
+ * \param name Pointer to location to receive header name
+ * \param value Pointer to location to receive header value
+ * \return NSERROR_OK on success, appropriate error otherwise
+ */
+nserror llcache_fetch_split_header(const char *data, size_t len, char **name,
+ char **value)
+{
+ char *n, *v;
+ const char *colon;
+
+ /* Find colon */
+ colon = strchr(data, ':');
+ if (colon == NULL) {
+ /* Failed, assume a key with no value */
+ n = strdup(data);
+ if (n == NULL)
+ return NSERROR_NOMEM;
+
+ v = strdup("");
+ if (v == NULL) {
+ free(n);
+ return NSERROR_NOMEM;
+ }
+ } else {
+ /* Split header into name & value */
+
+ /* Strip leading whitespace from name */
+ while (data[0] == ' ' || data[0] == '\t' ||
+ data[0] == '\r' || data[0] == '\n') {
+ data++;
+ }
+
+ /* Strip trailing whitespace from name */
+ while (colon > data && (colon[-1] == ' ' ||
+ colon[-1] == '\t' || colon[-1] == '\r' ||
+ colon[-1] == '\n'))
+ colon--;
+
+ n = strndup(data, colon - data);
+ if (n == NULL)
+ return NSERROR_NOMEM;
+
+ /* Find colon again */
+ while (*colon != ':') {
+ colon++;
+ }
+
+ /* Skip over colon and any subsequent whitespace */
+ do {
+ colon++;
+ } while (*colon == ' ' || *colon == '\t' ||
+ *colon == '\r' || *colon == '\n');
+
+ /* Strip trailing whitespace from value */
+ while (len > 0 && (data[len - 1] == ' ' ||
+ data[len - 1] == '\t' ||
+ data[len - 1] == '\r' ||
+ data[len - 1] == '\n')) {
+ len--;
+ }
+
+ v = strndup(colon, len - (colon - data));
+ if (v == NULL) {
+ free(n);
+ return NSERROR_NOMEM;
+ }
+ }
+
+ *name = n;
+ *value = v;
+
+ return NSERROR_OK;
+}
+
+/**
+ * Parse a fetch header
+ *
+ * \param object Object to parse header for
+ * \param data Header string
+ * \param len Byte length of header
+ * \param name Pointer to location to receive header name
+ * \param value Pointer to location to receive header value
+ * \return NSERROR_OK on success, appropriate error otherwise
+ */
+nserror llcache_fetch_parse_header(llcache_object *object, const char *data,
+ size_t len, char **name, char **value)
+{
+ nserror error;
+
+ /* Set fetch response time if not already set */
+ if (object->cache.res_time == 0)
+ object->cache.res_time = time(NULL);
+
+ /* Decompose header into name-value pair */
+ error = llcache_fetch_split_header(data, len, name, value);
+ if (error != NSERROR_OK)
+ return error;
+
+ /* Parse cache headers to populate cache control data */
+#define SKIP_ST(p) while (*p != '\0' && (*p == ' ' || *p == '\t')) p++
+
+ if (5 < len && strcasecmp(*name, "Date") == 0) {
+ /* extract Date header */
+ object->cache.date = curl_getdate(*value, NULL);
+ } else if (4 < len && strcasecmp(*name, "Age") == 0) {
+ /* extract Age header */
+ if ('0' <= **value && **value <= '9')
+ object->cache.age = atoi(*value);
+ } else if (8 < len && strcasecmp(*name, "Expires") == 0) {
+ /* extract Expires header */
+ object->cache.expires = curl_getdate(*value, NULL);
+ } else if (14 < len && strcasecmp(*name, "Cache-Control") == 0) {
+ /* extract and parse Cache-Control header */
+ const char *start = *value;
+ const char *comma = *value;
+
+ while (*comma != '\0') {
+ while (*comma != '\0' && *comma != ',')
+ comma++;
+
+ if (8 < comma - start && (strncasecmp(start,
+ "no-cache", 8) == 0 ||
+ strncasecmp(start, "no-store", 8) == 0))
+ /* When we get a disk cache we should
+ * distinguish between these two */
+ object->cache.no_cache = true;
+ else if (7 < comma - start &&
+ strncasecmp(start, "max-age", 7) == 0) {
+ /* Find '=' */
+ while (start < comma && *start != '=')
+ start++;
+
+ /* Skip over it */
+ start++;
+
+ /* Skip whitespace */
+ SKIP_ST(start);
+
+ if (start < comma)
+ object->cache.max_age = atoi(start);
+ }
+
+ if (*comma != '\0') {
+ /* Skip past comma */
+ comma++;
+ /* Skip whitespace */
+ SKIP_ST(comma);
+ }
+
+ /* Set start for next token */
+ start = comma;
+ }
+ } else if (5 < len && strcasecmp(*name, "ETag") == 0) {
+ /* extract ETag header */
+ free(object->cache.etag);
+ object->cache.etag = strdup(*value);
+ if (object->cache.etag == NULL)
+ return NSERROR_NOMEM;
+ } else if (14 < len && strcasecmp(*name, "Last-Modified") == 0) {
+ /* extract Last-Modified header */
+ object->cache.last_modified = curl_getdate(*value, NULL);
+ }
+
+#undef SKIP_ST
+
+ return NSERROR_OK;
+}
+
+/**
+ * Process a fetch header
+ *
+ * \param object Object being fetched
+ * \param data Header string
+ * \param len Byte length of header
+ * \return NSERROR_OK on success, appropriate error otherwise
+ */
+nserror llcache_fetch_process_header(llcache_object *object, const char *data,
+ size_t len)
+{
+ nserror error;
+ char *name, *value;
+ llcache_header *temp;
+
+ error = llcache_fetch_parse_header(object, data, len, &name, &value);
+ if (error != NSERROR_OK)
+ return error;
+
+ /* Append header data to the object's headers array */
+ temp = realloc(object->headers, (object->num_headers + 1) *
+ sizeof(llcache_header));
+ if (temp == NULL) {
+ free(name);
+ free(value);
+ return NSERROR_NOMEM;
+ }
+
+ object->headers = temp;
+
+ object->headers[object->num_headers].name = name;
+ object->headers[object->num_headers].value = value;
+
+ object->num_headers++;
+
+ return NSERROR_OK;
+}
+
+/**
+ * Process a chunk of fetched data
+ *
+ * \param object Object being fetched
+ * \param data Data to process
+ * \param len Byte length of data
+ * \return NSERROR_OK on success, appropriate error otherwise.
+ */
+nserror llcache_fetch_process_data(llcache_object *object, const uint8_t *data,
+ size_t len)
+{
+ /* Resize source buffer if it's too small */
+ if (object->source_len + len >= object->source_alloc) {
+ const size_t new_len = object->source_len + len + 64 * 1024;
+ uint8_t *temp = realloc(object->source_data, new_len);
+ if (temp == NULL)
+ return NSERROR_NOMEM;
+
+ object->source_data = temp;
+ object->source_alloc = new_len;
+ }
+
+ /* Append this data chunk to source buffer */
+ memcpy(object->source_data + object->source_len, data, len);
+ object->source_len += len;
+
+ return NSERROR_OK;
+}
+
+/**
+ * Handle an authentication request
+ *
+ * \param object Object being fetched
+ * \param realm Authentication realm
+ * \return NSERROR_OK on success, appropriate error otherwise.
+ */
+nserror llcache_fetch_auth(llcache_object *object, const char *realm)
+{
+ nserror error = NSERROR_OK;
+
+ /* Abort fetch for this object */
+ fetch_abort(object->fetch.fetch);
+ object->fetch.fetch = NULL;
+
+ if (query_cb != NULL) {
+ llcache_query query;
+
+ /* Destroy headers */
+ while (object->num_headers > 0) {
+ object->num_headers--;
+
+ free(object->headers[object->num_headers].name);
+ free(object->headers[object->num_headers].value);
+ }
+ free(object->headers);
+ object->headers = NULL;
+
+ /* Emit query for authentication details */
+ query.type = LLCACHE_QUERY_AUTH;
+ query.url = object->url;
+ query.data.auth.realm = realm;
+
+ error = query_cb(&query, query_cb_pw,
+ llcache_query_handle_response, object);
+ } else {
+ llcache_object_user *user;
+ llcache_event event;
+
+ /* Inform client(s) that object fetch failed */
+ event.type = LLCACHE_EVENT_ERROR;
+ /** \todo More appropriate error message */
+ event.data.msg = messages_get("FetchFailed");
+
+ for (user = object->users; user != NULL; user = user->next) {
+ error = user->handle.cb(&user->handle, &event,
+ user->handle.pw);
+ if (error != NSERROR_OK)
+ break;
+ }
+ }
+
+ return error;
+}
+
+/**
+ * Handle a TLS certificate verification failure
+ *
+ * \param object Object being fetched
+ * \param certs Certificate chain
+ * \param num Number of certificates in chain
+ * \return NSERROR_OK on success, appropriate error otherwise
+ */
+nserror llcache_fetch_cert_error(llcache_object *object,
+ const struct ssl_cert_info *certs, size_t num)
+{
+ nserror error = NSERROR_OK;
+
+ /* Abort fetch for this object */
+ fetch_abort(object->fetch.fetch);
+ object->fetch.fetch = NULL;
+
+ if (query_cb != NULL) {
+ llcache_query query;
+
+ /* Emit query for TLS */
+ query.type = LLCACHE_QUERY_SSL;
+ query.url = object->url;
+ query.data.ssl.certs = certs;
+ query.data.ssl.num = num;
+
+ error = query_cb(&query, query_cb_pw,
+ llcache_query_handle_response, object);
+ } else {
+ llcache_object_user *user;
+ llcache_event event;
+
+ /* Inform client(s) that object fetch failed */
+ event.type = LLCACHE_EVENT_ERROR;
+ /** \todo More appropriate error message */
+ event.data.msg = messages_get("FetchFailed");
+
+ for (user = object->users; user != NULL; user = user->next) {
+ error = user->handle.cb(&user->handle, &event,
+ user->handle.pw);
+ if (error != NSERROR_OK)
+ break;
+ }
+ }
+
+ return error;
+}
+
diff --git a/content/llcache.h b/content/llcache.h
new file mode 100644
index 000000000..b2c856f3b
--- /dev/null
+++ b/content/llcache.h
@@ -0,0 +1,238 @@
+/*
+ * Copyright 2009 John-Mark Bell <jmb@netsurf-browser.org>
+ *
+ * This file is part of NetSurf, http://www.netsurf-browser.org/
+ *
+ * NetSurf is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * NetSurf is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+/** \file
+ * Low-level resource cache (interface)
+ */
+
+#ifndef NETSURF_CONTENT_LLCACHE_H_
+#define NETSURF_CONTENT_LLCACHE_H_
+
+#include <stdbool.h>
+#include <stddef.h>
+#include <stdint.h>
+
+#include "utils/errors.h"
+
+struct ssl_cert_info;
+struct fetch_multipart_data;
+
+/** Handle for low-level cache object */
+typedef struct llcache_handle llcache_handle;
+
+/** POST data object for low-level cache requests */
+typedef struct {
+ enum {
+ LLCACHE_POST_URL_ENCODED,
+ LLCACHE_POST_MULTIPART
+ } type; /**< Type of POST data */
+ union {
+ char *urlenc; /**< URL encoded data */
+ struct fetch_multipart_data *multipart; /**< Multipart data */
+ } data; /**< POST data content */
+} llcache_post_data;
+
+/** Low-level cache event types */
+typedef enum {
+ LLCACHE_EVENT_HAD_HEADERS, /**< Received all headers */
+ LLCACHE_EVENT_HAD_DATA, /**< Received some data */
+ LLCACHE_EVENT_DONE, /**< Finished fetching data */
+
+ LLCACHE_EVENT_ERROR, /**< An error occurred during fetch */
+ LLCACHE_EVENT_PROGRESS, /**< Fetch progress update */
+} llcache_event_type;
+
+/** Low-level cache events */
+typedef struct {
+ llcache_event_type type; /**< Type of event */
+ union {
+ struct {
+ const uint8_t *buf; /**< Buffer of data */
+ size_t len; /**< Length of buffer, in bytes */
+ } data; /**< Received data */
+ const char *msg; /**< Error or progress message */
+ } data; /**< Event data */
+} llcache_event;
+
+/**
+ * Client callback for low-level cache events
+ *
+ * \param handle Handle for which event is issued
+ * \param event Event data
+ * \param pw Pointer to client-specific data
+ * \return NSERROR_OK on success, appropriate error otherwise.
+ */
+typedef nserror (*llcache_handle_callback)(llcache_handle *handle,
+ const llcache_event *event, void *pw);
+
+/** Flags for low-level cache object retrieval */
+#define LLCACHE_RETRIEVE_FORCE_FETCH (1 << 0) /* Force a new fetch */
+#define LLCACHE_RETRIEVE_VERIFIABLE (1 << 1) /* Requested URL was verified */
+#define LLCACHE_RETRIEVE_SNIFF_TYPE (1 << 2) /* Permit content-type sniffing */
+#define LLCACHE_RETRIEVE_NO_ERROR_PAGES (1 << 3) /* No error pages */
+
+/** Low-level cache query types */
+typedef enum {
+ LLCACHE_QUERY_AUTH, /**< Need authentication details */
+ LLCACHE_QUERY_REDIRECT, /**< Need permission to redirect */
+ LLCACHE_QUERY_SSL /**< SSL chain needs inspection */
+} llcache_query_type;
+
+/** Low-level cache query */
+typedef struct {
+ llcache_query_type type; /**< Type of query */
+
+ const char *url; /**< URL being fetched */
+
+ union {
+ struct {
+ const char *realm; /**< Authentication realm */
+ } auth;
+
+ struct {
+ const char *target; /**< Redirect target */
+ } redirect;
+
+ struct {
+ const struct ssl_cert_info *certs;
+ size_t num; /**< Number of certs in chain */
+ } ssl;
+ } data;
+} llcache_query;
+
+/**
+ * Response handler for fetch-related queries
+ *
+ * \param proceed Whether to proceed with the fetch or not
+ * \param cbpw Opaque value provided to llcache_query_callback
+ * \return NSERROR_OK on success, appropriate error otherwise
+ */
+typedef nserror (*llcache_query_response)(bool proceed, void *cbpw);
+
+/**
+ * Callback to handle fetch-related queries
+ *
+ * \param query Object containing details of query
+ * \param pw Pointer to callback-specific data
+ * \param cb Callback that client should call once query is satisfied
+ * \param cbpw Opaque value to pass into \a cb
+ * \return NSERROR_OK on success, appropriate error otherwise
+ *
+ * \note This callback should return immediately. Once a suitable answer to
+ * the query has been obtained, the provided response callback should be
+ * called. This is intended to be an entirely asynchronous process.
+ */
+typedef nserror (*llcache_query_callback)(const llcache_query *query, void *pw,
+ llcache_query_response cb, void *cbpw);
+
+/**
+ * Initialise the low-level cache
+ *
+ * \param cb Query handler
+ * \param pw Pointer to query handler data
+ * \return NSERROR_OK on success, appropriate error otherwise.
+ */
+nserror llcache_initialise(llcache_query_callback cb, void *pw);
+
+/**
+ * Poll the low-level cache
+ *
+ * \return NSERROR_OK on success, appropriate error otherwise.
+ */
+nserror llcache_poll(void);
+
+/**
+ * Retrieve a handle for a low-level cache object
+ *
+ * \param url URL of the object to fetch
+ * \param flags Object retrieval flags
+ * \param referer Referring URL, or NULL if none
+ * \param post POST data, or NULL for a GET request
+ * \param cb Client callback for events
+ * \param pw Pointer to client-specific data
+ * \param result Pointer to location to recieve cache handle
+ * \return NSERROR_OK on success, appropriate error otherwise
+ */
+nserror llcache_handle_retrieve(const char *url, uint32_t flags,
+ const char *referer, const llcache_post_data *post,
+ llcache_handle_callback cb, void *pw,
+ llcache_handle **result);
+
+/**
+ * Change the callback associated with a low-level cache handle
+ *
+ * \param handle Handle to change callback of
+ * \param cb New callback
+ * \param pw Client data for new callback
+ * \return NSERROR_OK on success, appropriate error otherwise
+ */
+nserror llcache_handle_change_callback(llcache_handle *handle,
+ llcache_handle_callback cb, void *pw);
+
+/**
+ * Release a low-level cache handle
+ *
+ * \param handle Handle to release
+ * \return NSERROR_OK on success, appropriate error otherwise
+ */
+nserror llcache_handle_release(llcache_handle *handle);
+
+/**
+ * Retrieve the post-redirect URL of a low-level cache object
+ *
+ * \param handle Handle to retrieve URL from
+ * \return Post-redirect URL of cache object
+ */
+const char *llcache_handle_get_url(const llcache_handle *handle);
+
+/**
+ * Retrieve source data of a low-level cache object
+ *
+ * \param handle Handle to retrieve source data from
+ * \param size Pointer to location to receive byte length of data
+ * \return Pointer to source data
+ */
+const uint8_t *llcache_handle_get_source_data(const llcache_handle *handle,
+ size_t *size);
+
+/**
+ * Retrieve a header value associated with a low-level cache object
+ *
+ * \param handle Handle to retrieve header from
+ * \param key Header name
+ * \return Header value, or NULL if header does not exist
+ *
+ * \todo Make the key an enumeration, to avoid needless string comparisons
+ * \todo Forcing the client to parse the header value seems wrong.
+ * Better would be to return the actual value part and an array of
+ * key-value pairs for any additional parameters.
+ */
+const char *llcache_handle_get_header(const llcache_handle *handle,
+ const char *key);
+
+/**
+ * Determine if the same underlying object is referenced by the given handles
+ *
+ * \param a First handle
+ * \param b Second handle
+ * \return True if handles reference the same object, false otherwise
+ */
+bool llcache_handle_references_same_object(const llcache_handle *a,
+ const llcache_handle *b);
+
+#endif
diff --git a/css/css.c b/css/css.c
index cf8902037..473ea488a 100644
--- a/css/css.c
+++ b/css/css.c
@@ -20,17 +20,18 @@
#include <libwapcaplet/libwapcaplet.h>
-#include "content/content.h"
+#include "content/content_protected.h"
#include "content/fetch.h"
-#include "content/fetchcache.h"
+#include "content/hlcache.h"
#include "css/css.h"
#include "css/internal.h"
#include "desktop/gui.h"
#include "render/html.h"
+#include "utils/http.h"
#include "utils/messages.h"
-static void nscss_import(content_msg msg, struct content *c,
- intptr_t p1, intptr_t p2, union content_msg_data data);
+static nserror nscss_import(hlcache_handle *handle,
+ const hlcache_event *event, void *pw);
/**
* Allocation callback for libcss
@@ -49,125 +50,63 @@ static void *myrealloc(void *ptr, size_t size, void *pw)
* Initialise a CSS content
*
* \param c Content to initialise
- * \param parent Parent content, or NULL if top-level
* \param params Content-Type parameters
* \return true on success, false on failure
*/
-bool nscss_create(struct content *c, struct content *parent,
- const char *params[])
+bool nscss_create(struct content *c, const http_parameter *params)
{
const char *charset = NULL;
- css_origin origin = CSS_ORIGIN_AUTHOR;
- uint64_t media = CSS_MEDIA_ALL;
- lwc_context *dict = NULL;
- bool quirks = true;
- uint32_t i;
union content_msg_data msg_data;
- css_error error;
+ nserror error;
/** \todo what happens about the allocator? */
/** \todo proper error reporting */
/* Find charset specified on HTTP layer, if any */
- /** \todo What happens if there isn't one and parent content exists? */
- for (i = 0; params[i] != NULL; i += 2) {
- if (strcasecmp(params[i], "charset") == 0) {
- charset = params[i + 1];
- break;
- }
+ error = http_parameter_list_find_item(params, "charset", &charset);
+ if (error != NSERROR_OK) {
+ /* No charset specified, use fallback, if any */
+ /** \todo libcss will take this as gospel, which is wrong */
+ charset = c->fallback_charset;
}
- if (parent != NULL) {
- assert(parent->type == CONTENT_HTML ||
- parent->type == CONTENT_CSS);
-
- if (parent->type == CONTENT_HTML) {
- assert(parent->data.html.dict != NULL);
-
- if (c == parent->data.html.
- stylesheets[STYLESHEET_BASE].c ||
- c == parent->data.html.
- stylesheets[STYLESHEET_QUIRKS].c ||
- c == parent->data.html.
- stylesheets[STYLESHEET_ADBLOCK].c)
- origin = CSS_ORIGIN_UA;
-
- quirks = (parent->data.html.quirks !=
- BINDING_QUIRKS_MODE_NONE);
-
- for (i = 0; i < parent->data.html.stylesheet_count;
- i++) {
- if (parent->data.html.stylesheets[i].c == c) {
- media = parent->data.html.
- stylesheets[i].media;
- break;
- }
- }
-
- dict = parent->data.html.dict;
- } else {
- assert(parent->data.css.sheet != NULL);
- assert(parent->data.css.dict != NULL);
-
- error = css_stylesheet_get_origin(
- parent->data.css.sheet, &origin);
- if (error != CSS_OK) {
- msg_data.error = "?";
- content_broadcast(c, CONTENT_MSG_ERROR,
- msg_data);
- return false;
- }
-
- error = css_stylesheet_quirks_allowed(
- parent->data.css.sheet, &quirks);
- if (error != CSS_OK) {
- msg_data.error = "?";
- content_broadcast(c, CONTENT_MSG_ERROR,
- msg_data);
- return false;
- }
-
- for (i = 0; i < parent->data.css.import_count; i++) {
- if (parent->data.css.imports[i].c == c) {
- media = parent->data.css.
- imports[i].media;
- break;
- }
- }
-
- dict = parent->data.css.dict;
- }
+ if (nscss_create_css_data(&c->data.css, content__get_url(c),
+ charset, c->quirks) != NSERROR_OK) {
+ msg_data.error = messages_get("NoMemory");
+ content_broadcast(c, CONTENT_MSG_ERROR, msg_data);
+ return false;
}
- if (dict == NULL) {
- lwc_error lerror = lwc_create_context(myrealloc, NULL, &dict);
+ return true;
+}
- if (lerror != lwc_error_ok) {
- msg_data.error = messages_get("NoMemory");
- content_broadcast(c, CONTENT_MSG_ERROR, msg_data);
- return false;
- }
- }
+/**
+ * Create a struct content_css_data, creating a stylesheet object
+ *
+ * \param c Struct to populate
+ * \param url URL of stylesheet
+ * \param charset Stylesheet charset
+ * \param quirks Stylesheet quirks mode
+ * \return NSERROR_OK on success, NSERROR_NOMEM on memory exhaustion
+ */
+nserror nscss_create_css_data(struct content_css_data *c,
+ const char *url, const char *charset, bool quirks)
+{
+ css_error error;
- c->data.css.dict = lwc_context_ref(dict);
- c->data.css.import_count = 0;
- c->data.css.imports = NULL;
+ c->import_count = 0;
+ c->imports = NULL;
error = css_stylesheet_create(CSS_LEVEL_21, charset,
- c->url, NULL, origin, media, quirks, false,
- c->data.css.dict,
+ url, NULL, quirks, false,
myrealloc, NULL,
nscss_resolve_url, NULL,
- &c->data.css.sheet);
+ &c->sheet);
if (error != CSS_OK) {
- lwc_context_unref(c->data.css.dict);
- c->data.css.dict = NULL;
- msg_data.error = messages_get("NoMemory");
- content_broadcast(c, CONTENT_MSG_ERROR, msg_data);
- return false;
+ return NSERROR_NOMEM;
}
- return true;
+ return NSERROR_OK;
}
/**
@@ -183,9 +122,7 @@ bool nscss_process_data(struct content *c, char *data, unsigned int size)
union content_msg_data msg_data;
css_error error;
- error = css_stylesheet_append_data(c->data.css.sheet,
- (const uint8_t *) data, size);
-
+ error = nscss_process_css_data(&c->data.css, data, size);
if (error != CSS_OK && error != CSS_NEEDDATA) {
msg_data.error = "?";
content_broadcast(c, CONTENT_MSG_ERROR, msg_data);
@@ -195,6 +132,21 @@ bool nscss_process_data(struct content *c, char *data, unsigned int size)
}
/**
+ * Process CSS data
+ *
+ * \param c CSS content object
+ * \param data Data to process
+ * \param size Number of bytes to process
+ * \return CSS_OK on success, appropriate error otherwise
+ */
+css_error nscss_process_css_data(struct content_css_data *c, char *data,
+ unsigned int size)
+{
+ return css_stylesheet_append_data(c->sheet,
+ (const uint8_t *) data, size);
+}
+
+/**
* Convert a CSS content ready for use
*
* \param c Content to convert
@@ -209,22 +161,73 @@ bool nscss_convert(struct content *c, int w, int h)
size_t size;
css_error error;
- error = css_stylesheet_data_done(c->data.css.sheet);
+ error = nscss_convert_css_data(&c->data.css, w, h);
+ if (error != CSS_OK) {
+ msg_data.error = "?";
+ content_broadcast(c, CONTENT_MSG_ERROR, msg_data);
+ c->status = CONTENT_STATUS_ERROR;
+ return false;
+ }
+
+ /* Retrieve the size of this sheet */
+ error = css_stylesheet_size(c->data.css.sheet, &size);
+ if (error != CSS_OK) {
+ msg_data.error = "?";
+ content_broadcast(c, CONTENT_MSG_ERROR, msg_data);
+ c->status = CONTENT_STATUS_ERROR;
+ return false;
+ }
+ c->size += size;
+
+ /* Add on the size of the imported sheets */
+ for (i = 0; i < c->data.css.import_count; i++) {
+ struct content *import = hlcache_handle_get_content(
+ c->data.css.imports[i].c);
+
+ if (import != NULL) {
+ c->size += import->size;
+ }
+ }
+
+ c->status = CONTENT_STATUS_DONE;
+
+ return error == CSS_OK;
+}
+
+/**
+ * Convert CSS data ready for use
+ *
+ * \param c CSS data to convert
+ * \param w Width of area content will be displayed in
+ * \param h Height of area content will be displayed in
+ * \return CSS error
+ */
+css_error nscss_convert_css_data(struct content_css_data *c, int w, int h)
+{
+ const char *referer;
+ uint32_t i = 0;
+ css_error error;
+ nserror nerror;
+
+ error = css_stylesheet_get_url(c->sheet, &referer);
+ if (error != CSS_OK) {
+ return error;
+ }
+
+ error = css_stylesheet_data_done(c->sheet);
/* Process pending imports */
while (error == CSS_IMPORTS_PENDING) {
+ hlcache_child_context child;
struct nscss_import *imports;
lwc_string *uri;
uint64_t media;
css_stylesheet *sheet;
- error = css_stylesheet_next_pending_import(c->data.css.sheet,
+ error = css_stylesheet_next_pending_import(c->sheet,
&uri, &media);
if (error != CSS_OK && error != CSS_INVALID) {
- msg_data.error = "?";
- content_broadcast(c, CONTENT_MSG_ERROR, msg_data);
- c->status = CONTENT_STATUS_ERROR;
- return false;
+ return error;
}
/* Give up if there are no more imports */
@@ -234,111 +237,63 @@ bool nscss_convert(struct content *c, int w, int h)
}
/* Increase space in table */
- imports = realloc(c->data.css.imports,
- (c->data.css.import_count + 1) *
+ imports = realloc(c->imports, (c->import_count + 1) *
sizeof(struct nscss_import));
if (imports == NULL) {
- msg_data.error = "?";
- content_broadcast(c, CONTENT_MSG_ERROR, msg_data);
- c->status = CONTENT_STATUS_ERROR;
- return false;
+ return CSS_NOMEM;
}
- c->data.css.imports = imports;
+ c->imports = imports;
- /* Create content */
- i = c->data.css.import_count;
- c->data.css.imports[c->data.css.import_count].media = media;
- c->data.css.imports[c->data.css.import_count++].c =
- fetchcache(lwc_string_data(uri),
- nscss_import, (intptr_t) c, i,
- c->width, c->height, true, NULL, NULL,
- false, false);
- if (c->data.css.imports[i].c == NULL) {
- msg_data.error = "?";
- content_broadcast(c, CONTENT_MSG_ERROR, msg_data);
- c->status = CONTENT_STATUS_ERROR;
- return false;
+ /** \todo fallback charset */
+ child.charset = NULL;
+ error = css_stylesheet_quirks_allowed(c->sheet, &child.quirks);
+ if (error != CSS_OK) {
+ return error;
}
- /* Fetch content */
- c->active++;
- fetchcache_go(c->data.css.imports[i].c, c->url,
- nscss_import, (intptr_t) c, i,
- c->width, c->height, NULL, NULL, false, c);
+ /* Create content */
+ i = c->import_count;
+ c->imports[c->import_count].media = media;
+ nerror = hlcache_handle_retrieve(lwc_string_data(uri),
+ 0, referer, NULL, w, h, nscss_import, c,
+ &child, &c->imports[c->import_count++].c);
+ if (error != NSERROR_OK) {
+ return CSS_NOMEM;
+ }
/* Wait for import to fetch + convert */
- while (c->active > 0) {
+ /** \todo This blocking approach needs to die */
+ while (c->imports[i].c != NULL &&
+ content_get_status(c->imports[i].c) !=
+ CONTENT_STATUS_DONE) {
fetch_poll();
gui_multitask();
}
- if (c->data.css.imports[i].c != NULL) {
- sheet = c->data.css.imports[i].c->data.css.sheet;
- c->data.css.imports[i].c->data.css.sheet = NULL;
+ if (c->imports[i].c != NULL) {
+ struct content *s = hlcache_handle_get_content(
+ c->imports[i].c);
+ sheet = s->data.css.sheet;
} else {
error = css_stylesheet_create(CSS_LEVEL_DEFAULT,
- NULL, "", NULL, CSS_ORIGIN_AUTHOR,
- media, false, false, c->data.css.dict,
+ NULL, "", NULL, false, false,
myrealloc, NULL,
nscss_resolve_url, NULL,
&sheet);
if (error != CSS_OK) {
- msg_data.error = messages_get("NoMemory");
- content_broadcast(c, CONTENT_MSG_ERROR,
- msg_data);
- c->status = CONTENT_STATUS_ERROR;
- return false;
+ return error;
}
}
- error = css_stylesheet_register_import(
- c->data.css.sheet, sheet);
+ error = css_stylesheet_register_import(c->sheet, sheet);
if (error != CSS_OK) {
- msg_data.error = "?";
- content_broadcast(c, CONTENT_MSG_ERROR, msg_data);
- c->status = CONTENT_STATUS_ERROR;
- return false;
+ return error;
}
error = CSS_IMPORTS_PENDING;
}
- /* Retrieve the size of this sheet */
- error = css_stylesheet_size(c->data.css.sheet, &size);
- if (error != CSS_OK) {
- msg_data.error = "?";
- content_broadcast(c, CONTENT_MSG_ERROR, msg_data);
- c->status = CONTENT_STATUS_ERROR;
- return false;
- }
- c->size += size;
-
- /* Add on the size of the imported sheets, removing ourselves from
- * their user list as we go (they're of no use to us now, as we've
- * inserted the sheet into ourselves) */
- for (i = 0; i < c->data.css.import_count; i++) {
- if (c->data.css.imports[i].c != NULL) {
- c->size += c->data.css.imports[i].c->size;
-
- content_remove_user(c->data.css.imports[i].c,
- nscss_import, (uintptr_t) c, i);
- }
-
- c->data.css.imports[i].c = NULL;
- }
-
- /* Remove the imports */
- c->data.css.import_count = 0;
- free(c->data.css.imports);
- c->data.css.imports = NULL;
-
- c->status = CONTENT_STATUS_DONE;
-
- /* Filthy hack to stop this content being reused
- * when whatever is using it has finished with it. */
- c->fresh = false;
-
- return error == CSS_OK;
+ return error;
}
/**
@@ -348,80 +303,99 @@ bool nscss_convert(struct content *c, int w, int h)
*/
void nscss_destroy(struct content *c)
{
+ nscss_destroy_css_data(&c->data.css);
+}
+
+/**
+ * Clean up CSS data
+ *
+ * \param c CSS data to clean up
+ */
+void nscss_destroy_css_data(struct content_css_data *c)
+{
uint32_t i;
- for (i = 0; i < c->data.css.import_count; i++) {
- if (c->data.css.imports[i].c != NULL) {
- content_remove_user(c->data.css.imports[i].c,
- nscss_import, (uintptr_t) c, i);
+ for (i = 0; i < c->import_count; i++) {
+ if (c->imports[i].c != NULL) {
+ hlcache_handle_release(c->imports[i].c);
}
- c->data.css.imports[i].c = NULL;
+ c->imports[i].c = NULL;
}
- free(c->data.css.imports);
+ free(c->imports);
- if (c->data.css.sheet != NULL) {
- css_stylesheet_destroy(c->data.css.sheet);
- c->data.css.sheet = NULL;
+ if (c->sheet != NULL) {
+ css_stylesheet_destroy(c->sheet);
+ c->sheet = NULL;
}
+}
- if (c->data.css.dict != NULL) {
- lwc_context_unref(c->data.css.dict);
- c->data.css.dict = NULL;
- }
+/**
+ * Retrieve imported stylesheets
+ *
+ * \param h Stylesheet containing imports
+ * \param n Pointer to location to receive number of imports
+ * \return Pointer to array of imported stylesheets
+ */
+struct nscss_import *nscss_get_imports(hlcache_handle *h, uint32_t *n)
+{
+ struct content *c = hlcache_handle_get_content(h);
+
+ assert(c != NULL);
+ assert(c->type == CONTENT_CSS);
+ assert(n != NULL);
+
+ *n = c->data.css.import_count;
+
+ return c->data.css.imports;
}
/**
- * Fetchcache handler for imported stylesheets
+ * Handler for imported stylesheet events
*
- * \param msg Message type
- * \param c Content being fetched
- * \param p1 Parent content
- * \param p2 Index into parent's imported stylesheet array
- * \param data Message data
+ * \param handle Handle for stylesheet
+ * \param event Event object
+ * \param pw Callback context
+ * \return NSERROR_OK on success, appropriate error otherwise
*/
-void nscss_import(content_msg msg, struct content *c,
- intptr_t p1, intptr_t p2, union content_msg_data data)
+nserror nscss_import(hlcache_handle *handle,
+ const hlcache_event *event, void *pw)
{
- struct content *parent = (struct content *) p1;
- uint32_t i = (uint32_t) p2;
+ struct content_css_data *parent = pw;
+ uint32_t i = 0;
- switch (msg) {
+ switch (event->type) {
case CONTENT_MSG_LOADING:
- if (c->type != CONTENT_CSS) {
- content_remove_user(c, nscss_import, p1, p2);
- if (c->user_list->next == NULL) {
- fetch_abort(c->fetch);
- c->fetch = NULL;
- c->status = CONTENT_STATUS_ERROR;
- }
+ if (content_get_type(handle) != CONTENT_CSS) {
+ hlcache_handle_release(handle);
- parent->data.css.imports[i].c = NULL;
- parent->active--;
- content_add_error(parent, "NotCSS", 0);
+ for (i = 0; i < parent->import_count; i++) {
+ if (parent->imports[i].c == handle) {
+ parent->imports[i].c = NULL;
+ break;
+ }
+ }
}
break;
case CONTENT_MSG_READY:
break;
case CONTENT_MSG_DONE:
- parent->active--;
break;
- case CONTENT_MSG_AUTH:
- case CONTENT_MSG_SSL:
- case CONTENT_MSG_LAUNCH:
case CONTENT_MSG_ERROR:
- if (parent->data.css.imports[i].c == c) {
- parent->data.css.imports[i].c = NULL;
- parent->active--;
+ hlcache_handle_release(handle);
+ for (i = 0; i < parent->import_count; i++) {
+ if (parent->imports[i].c == handle) {
+ parent->imports[i].c = NULL;
+ break;
+ }
}
break;
case CONTENT_MSG_STATUS:
break;
- case CONTENT_MSG_NEWPTR:
- parent->data.css.imports[i].c = c;
- break;
default:
assert(0);
}
+
+ return NSERROR_OK;
}
diff --git a/css/css.h b/css/css.h
index d65de15cf..925b4ae40 100644
--- a/css/css.h
+++ b/css/css.h
@@ -23,7 +23,11 @@
#include <libcss/libcss.h>
+#include "utils/errors.h"
+
struct content;
+struct hlcache_handle;
+struct http_parameter;
struct nscss_import;
/**
@@ -31,8 +35,6 @@ struct nscss_import;
*/
struct content_css_data
{
- lwc_context *dict; /**< Dictionary to intern strings in */
-
css_stylesheet *sheet; /**< Stylesheet object */
uint32_t import_count; /**< Number of sheets imported */
@@ -43,12 +45,11 @@ struct content_css_data
* Imported stylesheet record
*/
struct nscss_import {
- struct content *c; /**< Content containing sheet */
+ struct hlcache_handle *c; /**< Content containing sheet */
uint64_t media; /**< Media types that sheet applies to */
};
-bool nscss_create(struct content *c, struct content *parent,
- const char *params[]);
+bool nscss_create(struct content *c, const struct http_parameter *params);
bool nscss_process_data(struct content *c, char *data, unsigned int size);
@@ -56,5 +57,14 @@ bool nscss_convert(struct content *c, int w, int h);
void nscss_destroy(struct content *c);
+nserror nscss_create_css_data(struct content_css_data *c,
+ const char *url, const char *charset, bool quirks);
+css_error nscss_process_css_data(struct content_css_data *c, char *data,
+ unsigned int size);
+css_error nscss_convert_css_data(struct content_css_data *c, int w, int h);
+void nscss_destroy_css_data(struct content_css_data *c);
+
+struct nscss_import *nscss_get_imports(struct hlcache_handle *h, uint32_t *n);
+
#endif
diff --git a/css/internal.c b/css/internal.c
index b9aa83f0d..4c80e639e 100644
--- a/css/internal.c
+++ b/css/internal.c
@@ -26,7 +26,6 @@
* URL resolution callback for libcss
*
* \param pw Resolution context
- * \param ctx Dictionary to intern result in
* \param base Base URI
* \param rel Relative URL
* \param abs Pointer to location to receive resolved URL
@@ -34,8 +33,8 @@
* CSS_NOMEM on memory exhaustion,
* CSS_INVALID if resolution failed.
*/
-css_error nscss_resolve_url(void *pw, lwc_context *ctx,
- const char *base, lwc_string *rel, lwc_string **abs)
+css_error nscss_resolve_url(void *pw, const char *base,
+ lwc_string *rel, lwc_string **abs)
{
lwc_error lerror;
char *abs_url, *norm_url;
@@ -57,7 +56,7 @@ css_error nscss_resolve_url(void *pw, lwc_context *ctx,
free(abs_url);
/* Intern it */
- lerror = lwc_context_intern(ctx, norm_url, strlen(norm_url), abs);
+ lerror = lwc_intern_string(norm_url, strlen(norm_url), abs);
if (lerror != lwc_error_ok) {
*abs = NULL;
free(norm_url);
diff --git a/css/internal.h b/css/internal.h
index e675a4876..0344d6b32 100644
--- a/css/internal.h
+++ b/css/internal.h
@@ -21,7 +21,7 @@
#include "css/css.h"
-css_error nscss_resolve_url(void *pw, lwc_context *ctx,
- const char *base, lwc_string *rel, lwc_string **abs);
+css_error nscss_resolve_url(void *pw, const char *base,
+ lwc_string *rel, lwc_string **abs);
#endif
diff --git a/css/select.c b/css/select.c
index aeb7d3c58..be95a29c0 100644
--- a/css/select.c
+++ b/css/select.c
@@ -21,7 +21,7 @@
#include <string.h>
#include <strings.h>
-#include "content/content.h"
+#include "content/content_protected.h"
#include "content/urldb.h"
#include "css/internal.h"
#include "css/select.h"
@@ -31,12 +31,10 @@
#include "utils/url.h"
#include "utils/utils.h"
-static css_error node_name(void *pw, void *node,
- lwc_context *dict, lwc_string **name);
+static css_error node_name(void *pw, void *node, lwc_string **name);
static css_error node_classes(void *pw, void *node,
- lwc_context *dict, lwc_string ***classes, uint32_t *n_classes);
-static css_error node_id(void *pw, void *node,
- lwc_context *dict, lwc_string **id);
+ lwc_string ***classes, uint32_t *n_classes);
+static css_error node_id(void *pw, void *node, lwc_string **id);
static css_error named_ancestor_node(void *pw, void *node,
lwc_string *name, void **ancestor);
static css_error named_parent_node(void *pw, void *node,
@@ -125,21 +123,20 @@ static css_select_handler selection_handler = {
* \param charset Charset of data, or NULL if unknown
* \param url URL of document containing data
* \param allow_quirks True to permit CSS parsing quirks
- * \param dict String internment context
* \param alloc Memory allocation function
* \param pw Private word for allocator
* \return Pointer to stylesheet, or NULL on failure.
*/
css_stylesheet *nscss_create_inline_style(const uint8_t *data, size_t len,
const char *charset, const char *url, bool allow_quirks,
- lwc_context *dict, css_allocator_fn alloc, void *pw)
+ css_allocator_fn alloc, void *pw)
{
css_stylesheet *sheet;
css_error error;
error = css_stylesheet_create(CSS_LEVEL_DEFAULT, charset, url, NULL,
- CSS_ORIGIN_AUTHOR, CSS_MEDIA_ALL, allow_quirks, true,
- dict, alloc, pw, nscss_resolve_url, NULL, &sheet);
+ allow_quirks, true, alloc, pw, nscss_resolve_url,
+ NULL, &sheet);
if (error != CSS_OK) {
LOG(("Failed creating sheet: %d", error));
return NULL;
@@ -413,18 +410,16 @@ bool nscss_parse_colour(const char *data, css_color *result)
*
* \param pw HTML document
* \param node DOM node
- * \param dict Dictionary to intern result in
* \param name Pointer to location to receive node name
* \return CSS_OK on success,
* CSS_NOMEM on memory exhaustion.
*/
-css_error node_name(void *pw, void *node,
- lwc_context *dict, lwc_string **name)
+css_error node_name(void *pw, void *node, lwc_string **name)
{
xmlNode *n = node;
lwc_error lerror;
- lerror = lwc_context_intern(dict, (const char *) n->name,
+ lerror = lwc_intern_string((const char *) n->name,
strlen((const char *) n->name), name);
switch (lerror) {
case lwc_error_oom:
@@ -444,7 +439,6 @@ css_error node_name(void *pw, void *node,
*
* \param pw HTML document
* \param node DOM node
- * \param dict Dictionary to intern result in
* \param classes Pointer to location to receive class name array
* \param n_classes Pointer to location to receive length of class name array
* \return CSS_OK on success,
@@ -454,8 +448,8 @@ css_error node_name(void *pw, void *node,
* be allocated using the same allocator as used by libcss during style
* selection.
*/
-css_error node_classes(void *pw, void *node,
- lwc_context *dict, lwc_string ***classes, uint32_t *n_classes)
+css_error node_classes(void *pw, void *node,
+ lwc_string ***classes, uint32_t *n_classes)
{
xmlNode *n = node;
xmlAttr *class;
@@ -503,8 +497,7 @@ css_error node_classes(void *pw, void *node,
}
result = temp;
- lerror = lwc_context_intern(dict, start, p - start,
- &result[items]);
+ lerror = lwc_intern_string(start, p - start, &result[items]);
switch (lerror) {
case lwc_error_oom:
error = CSS_NOMEM;
@@ -536,7 +529,7 @@ cleanup:
uint32_t i;
for (i = 0; i < items; i++)
- lwc_context_string_unref(dict, result[i]);
+ lwc_string_unref(result[i]);
free(result);
}
@@ -553,13 +546,11 @@ cleanup:
*
* \param pw HTML document
* \param node DOM node
- * \param dict Dictionary to intern result in
* \param id Pointer to location to receive id value
* \return CSS_OK on success,
* CSS_NOMEM on memory exhaustion.
*/
-css_error node_id(void *pw, void *node,
- lwc_context *dict, lwc_string **id)
+css_error node_id(void *pw, void *node, lwc_string **id)
{
xmlNode *n = node;
xmlAttr *attr;
@@ -590,7 +581,7 @@ css_error node_id(void *pw, void *node,
}
/* Intern value */
- lerror = lwc_context_intern(dict, start, strlen(start), id);
+ lerror = lwc_intern_string(start, strlen(start), id);
switch (lerror) {
case lwc_error_oom:
error = CSS_NOMEM;
@@ -1285,9 +1276,7 @@ css_error node_presentational_hint(void *pw, void *node,
lwc_string *iurl;
lwc_error lerror;
- lerror = lwc_context_intern(
- html->data.html.dict, url,
- strlen(url), &iurl);
+ lerror = lwc_intern_string(url, strlen(url), &iurl);
free(url);
diff --git a/css/select.h b/css/select.h
index 7b87b2783..06868d5b2 100644
--- a/css/select.h
+++ b/css/select.h
@@ -29,7 +29,7 @@ struct content;
css_stylesheet *nscss_create_inline_style(const uint8_t *data, size_t len,
const char *charset, const char *url, bool allow_quirks,
- lwc_context *dict, css_allocator_fn alloc, void *pw);
+ css_allocator_fn alloc, void *pw);
css_computed_style *nscss_get_style(struct content *html, xmlNode *n,
uint32_t pseudo_element, uint64_t media,
diff --git a/desktop/401login.h b/desktop/401login.h
index 8a45477fd..8b5a0a778 100644
--- a/desktop/401login.h
+++ b/desktop/401login.h
@@ -21,10 +21,10 @@
#include "utils/config.h"
-#include "content/content.h"
-#include "desktop/browser.h"
+struct hlcache_handle;
+struct browser_window;
-void gui_401login_open(struct browser_window *bw, struct content *c,
+void gui_401login_open(struct browser_window *bw, struct hlcache_handle *c,
const char *realm);
#endif
diff --git a/desktop/browser.c b/desktop/browser.c
index a4c1e2156..115c16c5c 100644
--- a/desktop/browser.c
+++ b/desktop/browser.c
@@ -38,7 +38,7 @@
#include "curl/curl.h"
#include "utils/config.h"
#include "content/fetch.h"
-#include "content/fetchcache.h"
+#include "content/hlcache.h"
#include "content/urldb.h"
#include "css/css.h"
#include "desktop/401login.h"
@@ -66,9 +66,6 @@
/** browser window which is being redrawn. Valid only during redraw. */
struct browser_window *current_redraw_browser;
-/** fake content for <a> being saved as a link */
-struct content browser_window_href_content;
-
/** one or more windows require a reformat */
bool browser_reformat_pending;
@@ -77,11 +74,11 @@ bool browser_reformat_pending;
static void browser_window_go_post(struct browser_window *bw,
const char *url, char *post_urlenc,
- struct form_successful_control *post_multipart,
+ struct fetch_multipart_data *post_multipart,
bool add_to_history, const char *referer, bool download,
- bool verifiable, struct content *parent);
-static void browser_window_callback(content_msg msg, struct content *c,
- intptr_t p1, intptr_t p2, union content_msg_data data);
+ bool verifiable, hlcache_handle *parent);
+static nserror browser_window_callback(hlcache_handle *c,
+ const hlcache_event *event, void *pw);
static void browser_window_refresh(void *p);
static bool browser_window_check_throbber(struct browser_window *bw);
static void browser_window_convert_to_download(struct browser_window *bw);
@@ -92,8 +89,8 @@ static void browser_window_set_status(struct browser_window *bw,
const char *text);
static void browser_window_set_pointer(struct gui_window *g,
gui_pointer_shape shape);
-static void download_window_callback(fetch_msg msg, void *p, const void *data,
- unsigned long size, fetch_error_code errorcode);
+static nserror download_window_callback(llcache_handle *handle,
+ const llcache_event *event, void *pw);
static void browser_window_destroy_children(struct browser_window *bw);
static void browser_window_destroy_internal(struct browser_window *bw);
static void browser_window_set_scale_internal(struct browser_window *bw,
@@ -112,7 +109,7 @@ static void browser_window_mouse_track_html(struct browser_window *bw,
browser_mouse_state mouse, int x, int y);
static void browser_window_mouse_track_text(struct browser_window *bw,
browser_mouse_state mouse, int x, int y);
-static void browser_radio_set(struct content *content,
+static void browser_radio_set(hlcache_handle *content,
struct form_control *radio);
static gui_pointer_shape get_pointer_shape(struct browser_window *bw,
struct box *box, bool imagemap);
@@ -253,7 +250,7 @@ void browser_window_download(struct browser_window *bw, const char *url,
void browser_window_go_unverifiable(struct browser_window *bw,
const char *url, const char *referer, bool history_add,
- struct content *parent)
+ hlcache_handle *parent)
{
/* All fetches passing through here are unverifiable
* (i.e are not the result of user action) */
@@ -284,17 +281,22 @@ void browser_window_go_unverifiable(struct browser_window *bw,
void browser_window_go_post(struct browser_window *bw, const char *url,
char *post_urlenc,
- struct form_successful_control *post_multipart,
+ struct fetch_multipart_data *post_multipart,
bool add_to_history, const char *referer, bool download,
- bool verifiable, struct content *parent)
+ bool verifiable, hlcache_handle *parent)
{
- struct content *c;
+ hlcache_handle *c;
char *url2;
char *fragment;
url_func_result res;
int depth = 0;
struct browser_window *cur;
int width, height;
+ uint32_t fetch_flags = 0;
+ bool fetch_is_post = (post_urlenc != NULL || post_multipart != NULL);
+ llcache_post_data post;
+ hlcache_child_context child;
+ nserror error;
LOG(("bw %p, url %s", bw, url));
assert(bw);
@@ -308,16 +310,44 @@ void browser_window_go_post(struct browser_window *bw, const char *url,
return;
}
+ /* Set up retrieval parameters */
+ if (verifiable)
+ fetch_flags |= LLCACHE_RETRIEVE_VERIFIABLE;
+
+ if (post_multipart != NULL) {
+ post.type = LLCACHE_POST_MULTIPART;
+ post.data.multipart = post_multipart;
+ } else if (post_urlenc != NULL) {
+ post.type = LLCACHE_POST_URL_ENCODED;
+ post.data.urlenc = post_urlenc;
+ }
+
+ if (parent != NULL) {
+//newcache extract charset and quirks from parent content
+ child.charset = NULL;
+ child.quirks = false;
+ }
+
+ /* Normalize the request URL */
res = url_normalize(url, &url2);
if (res != URL_FUNC_OK) {
LOG(("failed to normalize url %s", url));
return;
}
- /* check we can actually handle this URL */
- if (!fetch_can_fetch(url2)) {
- gui_launch_url(url2);
+ /* Get download out of the way */
+ if (download) {
+ llcache_handle *l;
+
+ error = llcache_handle_retrieve(url2,
+ fetch_flags | LLCACHE_RETRIEVE_FORCE_FETCH,
+ referer, fetch_is_post ? &post : NULL,
+ download_window_callback, NULL, &l);
+ if (error != NSERROR_OK)
+ LOG(("Failed to fetch download: %d", error));
+
free(url2);
+
return;
}
@@ -336,9 +366,10 @@ void browser_window_go_post(struct browser_window *bw, const char *url,
bw->frag_id = fragment;
/* Compare new URL with existing one (ignoring fragments) */
- if (bw->current_content && bw->current_content->url) {
- res = url_compare(bw->current_content->url, url2,
- true, &same_url);
+ if (bw->current_content != NULL &&
+ content_get_url(bw->current_content) != NULL) {
+ res = url_compare(content_get_url(bw->current_content),
+ url2, true, &same_url);
if (res == URL_FUNC_NOMEM) {
free(url2);
warn_user("NoMemory", 0);
@@ -351,17 +382,17 @@ void browser_window_go_post(struct browser_window *bw, const char *url,
/* if we're simply moving to another ID on the same page,
* don't bother to fetch, just update the window.
*/
- if (same_url && !post_urlenc && !post_multipart &&
- !strchr(url2, '?')) {
+ if (same_url && fetch_is_post == false &&
+ strchr(url2, '?') == 0) {
free(url2);
if (add_to_history)
history_add(bw->history, bw->current_content,
bw->frag_id);
browser_window_update(bw, false);
- if (bw->current_content) {
+ if (bw->current_content != NULL) {
browser_window_refresh_url_bar(bw,
- bw->current_content->url,
- bw->frag_id);
+ content_get_url(bw->current_content),
+ bw->frag_id);
}
return;
}
@@ -376,28 +407,26 @@ void browser_window_go_post(struct browser_window *bw, const char *url,
browser_window_set_status(bw, messages_get("Loading"));
bw->history_add = add_to_history;
- c = fetchcache(url2, browser_window_callback, (intptr_t) bw, 0,
- width, height, false,
- post_urlenc, post_multipart, verifiable, download);
- free(url2);
- if (!c) {
+
+ error = hlcache_handle_retrieve(url2, 0, referer,
+ fetch_is_post ? &post : NULL, width, height,
+ browser_window_callback, bw,
+ parent != NULL ? &child : NULL, &c);
+ if (error == NSERROR_NO_FETCH_HANDLER) {
+ gui_launch_url(url2);
+ free(url2);
+ return;
+ } else if (error != NSERROR_OK) {
+ free(url2);
browser_window_set_status(bw, messages_get("NoMemory"));
warn_user("NoMemory", 0);
return;
}
+ free(url2);
+
bw->loading_content = c;
browser_window_start_throbber(bw);
-
- if (referer && referer != bw->referer) {
- free(bw->referer);
- bw->referer = strdup(referer);
- }
-
- bw->download = download;
- fetchcache_go(c, referer, browser_window_callback,
- (intptr_t) bw, 0, width, height,
- post_urlenc, post_multipart, verifiable, parent);
}
@@ -405,89 +434,95 @@ void browser_window_go_post(struct browser_window *bw, const char *url,
* Callback for fetchcache() for browser window fetches.
*/
-void browser_window_callback(content_msg msg, struct content *c,
- intptr_t p1, intptr_t p2, union content_msg_data data)
+nserror browser_window_callback(hlcache_handle *c,
+ const hlcache_event *event, void *pw)
{
- struct browser_window *bw = (struct browser_window *) p1;
+ struct browser_window *bw = pw;
- switch (msg) {
+ switch (event->type) {
case CONTENT_MSG_LOADING:
assert(bw->loading_content == c);
- if (c->type == CONTENT_OTHER)
+ if (content_get_type(c) == CONTENT_OTHER)
browser_window_convert_to_download(bw);
#ifdef WITH_THEME_INSTALL
- else if (c->type == CONTENT_THEME) {
+ else if (content_get_type(c) == CONTENT_THEME) {
theme_install_start(c);
- bw->loading_content = 0;
- content_remove_user(c, browser_window_callback,
- (intptr_t) bw, 0);
+ bw->loading_content = NULL;
+//newcache do we not just pass ownership to the theme installation stuff?
+ hlcache_handle_release(c);
browser_window_stop_throbber(bw);
}
#endif
else {
bw->refresh_interval = -1;
- browser_window_set_status(bw, c->status_message);
+ browser_window_set_status(bw,
+ content_get_status_message(c));
}
break;
case CONTENT_MSG_READY:
assert(bw->loading_content == c);
- if (bw->current_content) {
- if (bw->current_content->status ==
- CONTENT_STATUS_READY ||
- bw->current_content->status ==
- CONTENT_STATUS_DONE)
+ if (bw->current_content != NULL) {
+ content_status status =
+ content_get_status(bw->current_content);
+
+ if (status == CONTENT_STATUS_READY ||
+ status == CONTENT_STATUS_DONE)
content_close(bw->current_content);
- content_remove_user(bw->current_content,
- browser_window_callback,
- (intptr_t) bw, 0);
+
+ hlcache_handle_release(bw->current_content);
}
+
bw->current_content = c;
bw->loading_content = NULL;
+
browser_window_remove_caret(bw);
+
bw->scroll = NULL;
+
gui_window_new_content(bw->window);
- if (bw->current_content) {
- browser_window_refresh_url_bar(bw,
- bw->current_content->url,
- bw->frag_id);
- }
+
+ browser_window_refresh_url_bar(bw,
+ content_get_url(bw->current_content),
+ bw->frag_id);
+
/* new content; set scroll_to_top */
browser_window_update(bw, true);
content_open(c, bw, 0, 0, 0, 0);
- browser_window_set_status(bw, c->status_message);
+ browser_window_set_status(bw, content_get_status_message(c));
/* history */
if (bw->history_add && bw->history) {
+ const char *url = content_get_url(c);
+
history_add(bw->history, c, bw->frag_id);
- if (urldb_add_url(c->url)) {
- urldb_set_url_title(c->url,
- c->title ? c->title : c->url);
- urldb_update_url_visit_data(c->url);
- urldb_set_url_content_type(c->url,
- c->type);
- /* This is safe as we've just
- * added the URL */
- global_history_add(
- urldb_get_url(c->url));
+ if (urldb_add_url(url)) {
+ urldb_set_url_title(url, content_get_title(c));
+ urldb_update_url_visit_data(url);
+ urldb_set_url_content_type(url,
+ content_get_type(c));
+ /* This is safe as we've just added the URL */
+ global_history_add(urldb_get_url(url));
}
}
/* text selection */
- if (c->type == CONTENT_HTML)
+ if (content_get_type(c) == CONTENT_HTML)
selection_init(bw->sel,
- bw->current_content->data.html.layout);
- if (c->type == CONTENT_TEXTPLAIN)
+ html_get_box_tree(bw->current_content));
+ if (content_get_type(c) == CONTENT_TEXTPLAIN)
selection_init(bw->sel, NULL);
/* frames */
- if (c->type == CONTENT_HTML && c->data.html.frameset)
- browser_window_create_frameset(bw,
- c->data.html.frameset);
- if (c->type == CONTENT_HTML && c->data.html.iframe)
- browser_window_create_iframes(bw, c->data.html.iframe);
+ if (content_get_type(c) == CONTENT_HTML &&
+ html_get_frameset(c) != NULL)
+ browser_window_create_frameset(bw,
+ html_get_frameset(c));
+ if (content_get_type(c) == CONTENT_HTML &&
+ html_get_iframe(c) != NULL)
+ browser_window_create_iframes(bw, html_get_iframe(c));
break;
@@ -495,137 +530,75 @@ void browser_window_callback(content_msg msg, struct content *c,
assert(bw->current_content == c);
browser_window_update(bw, false);
- browser_window_set_status(bw, c->status_message);
+ browser_window_set_status(bw, content_get_status_message(c));
browser_window_stop_throbber(bw);
browser_window_set_icon(bw);
+
history_update(bw->history, c);
hotlist_visited(c);
- free(bw->referer);
- bw->referer = 0;
+
if (bw->refresh_interval != -1)
schedule(bw->refresh_interval,
browser_window_refresh, bw);
break;
case CONTENT_MSG_ERROR:
- browser_window_set_status(bw, data.error);
+ browser_window_set_status(bw, event->data.error);
/* Only warn the user about errors in top-level windows */
if (bw->browser_window_type == BROWSER_WINDOW_NORMAL)
- warn_user(data.error, 0);
+ warn_user(event->data.error, 0);
if (c == bw->loading_content)
- bw->loading_content = 0;
+ bw->loading_content = NULL;
else if (c == bw->current_content) {
- bw->current_content = 0;
+ bw->current_content = NULL;
browser_window_remove_caret(bw);
bw->scroll = NULL;
selection_init(bw->sel, NULL);
}
+
+ hlcache_handle_release(c);
+
browser_window_stop_throbber(bw);
- free(bw->referer);
- bw->referer = 0;
break;
case CONTENT_MSG_STATUS:
- browser_window_set_status(bw, c->status_message);
+ browser_window_set_status(bw, content_get_status_message(c));
break;
case CONTENT_MSG_REFORMAT:
if (c == bw->current_content &&
- c->type == CONTENT_HTML) {
+ content_get_type(c) == CONTENT_HTML) {
/* reposition frames */
- if (c->data.html.frameset)
+ if (html_get_frameset(c) != NULL)
browser_window_recalculate_frameset(bw);
/* reflow iframe positions */
- if (c->data.html.iframe)
+ if (html_get_iframe(c) != NULL)
browser_window_recalculate_iframes(bw);
/* box tree may have changed, need to relabel */
- selection_reinit(bw->sel, c->data.html.layout);
+ selection_reinit(bw->sel, html_get_box_tree(c));
}
+
if (bw->move_callback)
bw->move_callback(bw, bw->caret_p);
+
browser_window_update(bw, false);
break;
case CONTENT_MSG_REDRAW:
- gui_window_update_box(bw->window, &data);
- break;
-
- case CONTENT_MSG_NEWPTR:
- bw->loading_content = c;
- if (data.new_url) {
- /* Replacement URL too, so check for new fragment */
- char *fragment;
- url_func_result res;
-
- /* Remove any existing fragment */
- free(bw->frag_id);
- bw->frag_id = NULL;
-
- /* Extract new one, if any */
- res = url_fragment(data.new_url, &fragment);
- if (res == URL_FUNC_OK) {
- /* Save for later use */
- bw->frag_id = fragment;
- }
- /* Ignore memory exhaustion here -- it'll simply result
- * in the window being scrolled to the top rather than
- * to the fragment. That's acceptable, given that it's
- * likely that more important things will complain
- * about memory shortage. */
- }
- break;
-
- case CONTENT_MSG_LAUNCH:
- assert(data.launch_url != NULL);
-
- bw->loading_content = NULL;
-
- gui_launch_url(data.launch_url);
-
- browser_window_stop_throbber(bw);
- free(bw->referer);
- bw->referer = 0;
- break;
-
- case CONTENT_MSG_AUTH:
- gui_401login_open(bw, c, data.auth_realm);
- if (c == bw->loading_content)
- bw->loading_content = 0;
- else if (c == bw->current_content) {
- bw->current_content = 0;
- browser_window_remove_caret(bw);
- bw->scroll = NULL;
- selection_init(bw->sel, NULL);
- }
- browser_window_stop_throbber(bw);
- free(bw->referer);
- bw->referer = 0;
- break;
-
- case CONTENT_MSG_SSL:
- gui_cert_verify(bw, c, data.ssl.certs, data.ssl.num);
- if (c == bw->loading_content)
- bw->loading_content = 0;
- else if (c == bw->current_content) {
- bw->current_content = 0;
- browser_window_remove_caret(bw);
- bw->scroll = NULL;
- selection_init(bw->sel, NULL);
- }
- browser_window_stop_throbber(bw);
- free(bw->referer);
- bw->referer = 0;
+ gui_window_update_box(bw->window, &event->data);
break;
case CONTENT_MSG_REFRESH:
- bw->refresh_interval = data.delay * 100;
+ bw->refresh_interval = event->data.delay * 100;
break;
default:
assert(0);
}
+
+ return NSERROR_OK;
}
@@ -636,34 +609,26 @@ void browser_window_callback(content_msg msg, struct content *c,
void browser_window_convert_to_download(struct browser_window *bw)
{
struct gui_download_window *download_window;
- struct content *c = bw->loading_content;
- struct fetch *fetch;
+ hlcache_handle *c = bw->loading_content;
+ llcache_handle *stream;
assert(c);
- fetch = c->fetch;
+ stream = content_convert_to_download(c);
- if (fetch) {
- /* create download window */
- download_window = gui_download_window_create(c->url,
- c->mime_type, fetch, c->total_size,
- bw->window);
+ /** \todo Sort parameters out here */
+ download_window = gui_download_window_create(
+ llcache_handle_get_url(stream),
+ llcache_handle_get_header(stream, "Content-Type"),
+ NULL, 0, NULL);
- if (download_window) {
- /* extract fetch from content */
- c->fetch = 0;
- c->fresh = false;
- fetch_change_callback(fetch, download_window_callback,
- download_window);
- }
- } else {
- /* must already be a download window for this fetch */
- /** \todo open it at top of stack */
- }
+ llcache_handle_change_callback(stream,
+ download_window_callback, download_window);
/* remove content from browser window */
- bw->loading_content = 0;
- content_remove_user(c, browser_window_callback, (intptr_t) bw, 0);
+ hlcache_handle_release(bw->loading_content);
+ bw->loading_content = NULL;
+
browser_window_stop_throbber(bw);
}
@@ -678,23 +643,26 @@ void browser_window_refresh(void *p)
{
struct browser_window *bw = p;
bool history_add = true;
+ const char *url;
+ const char *refresh;
- assert(bw->current_content &&
- (bw->current_content->status == CONTENT_STATUS_READY ||
- bw->current_content->status == CONTENT_STATUS_DONE));
+ assert(bw->current_content != NULL &&
+ (content_get_status(bw->current_content) ==
+ CONTENT_STATUS_READY ||
+ content_get_status(bw->current_content) ==
+ CONTENT_STATUS_DONE));
/* Ignore if the refresh URL has gone
* (may happen if a fetch error occurred) */
- if (!bw->current_content->refresh)
+ refresh = content_get_refresh_url(bw->current_content);
+ if (refresh == NULL)
return;
/* mark this content as invalid so it gets flushed from the cache */
- bw->current_content->fresh = false;
+ content_invalidate_reuse_data(bw->current_content);
- if ((bw->current_content->url) &&
- (bw->current_content->refresh) &&
- (!strcmp(bw->current_content->url,
- bw->current_content->refresh)))
+ url = content_get_url(bw->current_content);
+ if (url != NULL && strcmp(url, refresh) == 0)
history_add = false;
/* Treat an (almost) immediate refresh in a top-level browser window as
@@ -705,11 +673,9 @@ void browser_window_refresh(void *p)
* all.
*/
if (bw->refresh_interval <= 100 && bw->parent == NULL) {
- browser_window_go(bw, bw->current_content->refresh,
- bw->current_content->url, history_add);
+ browser_window_go(bw, refresh, url, history_add);
} else {
- browser_window_go_unverifiable(bw, bw->current_content->refresh,
- bw->current_content->url, history_add,
+ browser_window_go_unverifiable(bw, refresh, url, history_add,
bw->current_content);
}
}
@@ -727,6 +693,7 @@ void browser_window_start_throbber(struct browser_window *bw)
while (bw->parent)
bw = bw->parent;
+
gui_window_start_throbber(bw->window);
}
@@ -780,9 +747,11 @@ void browser_window_set_icon(struct browser_window *bw)
{
while (bw->parent)
bw = bw->parent;
- if ((bw->current_content != NULL) && (bw->current_content->type == CONTENT_HTML))
+
+ if (bw->current_content != NULL &&
+ content_get_type(bw->current_content) == CONTENT_HTML)
gui_window_set_icon(bw->window,
- bw->current_content->data.html.favicon);
+ html_get_favicon(bw->current_content));
else
gui_window_set_icon(bw->window, NULL);
}
@@ -794,19 +763,16 @@ void browser_window_set_icon(struct browser_window *bw)
* \param scroll_to_top move view to top of page
*/
-void browser_window_update(struct browser_window *bw,
- bool scroll_to_top)
+void browser_window_update(struct browser_window *bw, bool scroll_to_top)
{
struct box *pos;
int x, y;
- if (!bw->current_content)
+ if (bw->current_content == NULL)
return;
- if (bw->current_content->title != NULL) {
- gui_window_set_title(bw->window, bw->current_content->title);
- } else
- gui_window_set_title(bw->window, bw->current_content->url);
+ gui_window_set_title(bw->window,
+ content_get_title(bw->current_content));
gui_window_update_extent(bw->window);
@@ -815,9 +781,11 @@ void browser_window_update(struct browser_window *bw,
/** \todo don't do this if the user has scrolled */
/* if frag_id exists, then try to scroll to it */
- if (bw->frag_id && bw->current_content->type == CONTENT_HTML) {
- if ((pos = box_find_by_id(bw->current_content->data.html.layout,
- bw->frag_id)) != 0) {
+ if (bw->frag_id &&
+ content_get_type(bw->current_content) == CONTENT_HTML) {
+ struct box *layout = html_get_box_tree(bw->current_content);
+
+ if ((pos = box_find_by_id(layout, bw->frag_id)) != 0) {
box_coords(pos, &x, &y);
gui_window_set_scroll(bw->window, x, y);
}
@@ -837,17 +805,17 @@ void browser_window_stop(struct browser_window *bw)
{
int children, index;
- if (bw->loading_content) {
- content_remove_user(bw->loading_content,
- browser_window_callback, (intptr_t) bw, 0);
- bw->loading_content = 0;
+ if (bw->loading_content != NULL) {
+ hlcache_handle_release(bw->loading_content);
+ bw->loading_content = NULL;
}
- if (bw->current_content &&
- bw->current_content->status != CONTENT_STATUS_DONE) {
- assert(bw->current_content->status == CONTENT_STATUS_READY);
+ if (bw->current_content != NULL && content_get_status(
+ bw->current_content) != CONTENT_STATUS_DONE) {
+ assert(content_get_status(bw->current_content) ==
+ CONTENT_STATUS_READY);
content_stop(bw->current_content,
- browser_window_callback, (intptr_t) bw, 0);
+ browser_window_callback, bw);
}
schedule_remove(browser_window_refresh, bw);
@@ -876,29 +844,43 @@ void browser_window_stop(struct browser_window *bw)
void browser_window_reload(struct browser_window *bw, bool all)
{
- struct content *c;
+ hlcache_handle *c;
unsigned int i;
- if (!bw->current_content || bw->loading_content)
+ if (bw->current_content == NULL || bw->loading_content != NULL)
return;
- if (all && bw->current_content->type == CONTENT_HTML) {
+ if (all && content_get_type(bw->current_content) == CONTENT_HTML) {
+ struct html_stylesheet *sheets;
+ struct content_html_object *objects;
+ unsigned int count;
+
c = bw->current_content;
+
/* invalidate objects */
- for (i = 0; i != c->data.html.object_count; i++) {
- if (c->data.html.object[i].content)
- c->data.html.object[i].content->fresh = false;
+ objects = html_get_objects(c, &count);
+
+ for (i = 0; i != count; i++) {
+ if (objects[i].content != NULL)
+ content_invalidate_reuse_data(
+ objects[i].content);
}
+
/* invalidate stylesheets */
- for (i = STYLESHEET_START; i != c->data.html.stylesheet_count;
- i++) {
- if (c->data.html.stylesheets[i].c)
- c->data.html.stylesheets[i].c->fresh =
- false;
+ sheets = html_get_stylesheets(c, &count);
+
+ for (i = STYLESHEET_START; i != count; i++) {
+ if (sheets[i].type == HTML_STYLESHEET_EXTERNAL &&
+ sheets[i].data.external != NULL) {
+ content_invalidate_reuse_data(
+ sheets[i].data.external);
+ }
}
}
- bw->current_content->fresh = false;
- browser_window_go_post(bw, bw->current_content->url, 0, 0,
+
+ content_invalidate_reuse_data(bw->current_content);
+
+ browser_window_go_post(bw, content_get_url(bw->current_content), 0, 0,
false, 0, false, true, 0);
}
@@ -1012,21 +994,22 @@ void browser_window_destroy_internal(struct browser_window *bw)
LOG(("Destroying window"));
- if ((bw->children) || (bw->iframes))
+ if (bw->children != NULL || bw->iframes != NULL)
browser_window_destroy_children(bw);
- if (bw->loading_content) {
- content_remove_user(bw->loading_content,
- browser_window_callback, (intptr_t) bw, 0);
- bw->loading_content = 0;
+
+ if (bw->loading_content != NULL) {
+ hlcache_handle_release(bw->loading_content);
+ bw->loading_content = NULL;
}
- if (bw->current_content) {
- if (bw->current_content->status == CONTENT_STATUS_READY ||
- bw->current_content->status ==
- CONTENT_STATUS_DONE)
+
+ if (bw->current_content != NULL) {
+ content_status status = content_get_status(bw->current_content);
+ if (status == CONTENT_STATUS_READY ||
+ status == CONTENT_STATUS_DONE)
content_close(bw->current_content);
- content_remove_user(bw->current_content,
- browser_window_callback, (intptr_t) bw, 0);
- bw->current_content = 0;
+
+ hlcache_handle_release(bw->current_content);
+ bw->current_content = NULL;
}
schedule_remove(browser_window_refresh, bw);
@@ -1058,15 +1041,15 @@ struct browser_window *browser_window_owner(struct browser_window *bw)
return bw->parent;
/* the parent of a frameset is either a NORMAL window or an IFRAME */
- while (bw->parent) {
+ while (bw->parent != NULL) {
switch (bw->browser_window_type) {
- case BROWSER_WINDOW_NORMAL:
- case BROWSER_WINDOW_IFRAME:
- return bw;
- case BROWSER_WINDOW_FRAME:
- case BROWSER_WINDOW_FRAMESET:
- bw = bw->parent;
- break;
+ case BROWSER_WINDOW_NORMAL:
+ case BROWSER_WINDOW_IFRAME:
+ return bw;
+ case BROWSER_WINDOW_FRAME:
+ case BROWSER_WINDOW_FRAMESET:
+ bw = bw->parent;
+ break;
}
}
return bw;
@@ -1083,9 +1066,9 @@ struct browser_window *browser_window_owner(struct browser_window *bw)
void browser_window_reformat(struct browser_window *bw, int width, int height)
{
- struct content *c = bw->current_content;
+ hlcache_handle *c = bw->current_content;
- if (!c)
+ if (c == NULL)
return;
content_reformat(c, width / bw->scale, height / bw->scale);
@@ -1104,23 +1087,28 @@ void browser_window_set_scale(struct browser_window *bw, float scale, bool all)
{
while (bw->parent && all)
bw = bw->parent;
+
browser_window_set_scale_internal(bw, scale);
+
if (bw->parent)
bw = bw->parent;
+
browser_window_recalculate_frameset(bw);
}
void browser_window_set_scale_internal(struct browser_window *bw, float scale)
{
int i;
- struct content *c;
+ hlcache_handle *c;
if (fabs(bw->scale-scale) < 0.0001)
return;
+
bw->scale = scale;
c = bw->current_content;
- if (c) {
- if (!content_can_reformat(c)) {
+
+ if (c != NULL) {
+ if (content_can_reformat(c) == false) {
browser_window_update(bw, false);
} else {
bw->reformat_pending = true;
@@ -1189,14 +1177,14 @@ struct browser_window *browser_window_find_target(struct browser_window *bw,
{
struct browser_window *bw_target;
struct browser_window *top;
- struct content *c;
+ hlcache_handle *c;
int rdepth;
/* use the base target if we don't have one */
c = bw->current_content;
- if (!target && c && c->data.html.base_target)
- target = c->data.html.base_target;
- if (!target)
+ if (target == NULL && c != NULL && content_get_type(c) == CONTENT_HTML)
+ target = html_get_base_target(c);
+ if (target == NULL)
target = TARGET_SELF;
/* allow the simple case of target="_blank" to be ignored if requested
@@ -1348,35 +1336,57 @@ void browser_window_find_target_internal(struct browser_window *bw,
* Callback for fetch for download window fetches.
*/
-void download_window_callback(fetch_msg msg, void *p, const void *data,
- unsigned long size, fetch_error_code errorcode)
+nserror download_window_callback(llcache_handle *handle,
+ const llcache_event *event, void *pw)
{
- struct gui_download_window *download_window = p;
+ struct gui_download_window *download_window = pw;
+
+ switch (event->type) {
+ case LLCACHE_EVENT_HAD_HEADERS:
+ assert(download_window == NULL);
+
+ /** \todo Ensure parameters are correct here */
+ download_window = gui_download_window_create(
+ llcache_handle_get_url(handle),
+ llcache_handle_get_header(handle,
+ "Content-Type"),
+ NULL, 0, NULL);
+ if (download_window == NULL)
+ return NSERROR_NOMEM;
+
+ llcache_handle_change_callback(handle,
+ download_window_callback, download_window);
+ break;
- switch (msg) {
- case FETCH_PROGRESS:
- break;
- case FETCH_DATA:
- gui_download_window_data(download_window, data, size);
- break;
+ case LLCACHE_EVENT_HAD_DATA:
+ assert(download_window != NULL);
- case FETCH_FINISHED:
- gui_download_window_done(download_window);
- break;
+ /** \todo Lose ugly cast */
+ gui_download_window_data(download_window,
+ (char *) event->data.data.buf,
+ event->data.data.len);
- case FETCH_ERROR:
- gui_download_window_error(download_window, data);
- break;
+ break;
- case FETCH_TYPE:
- case FETCH_NOTMODIFIED:
- case FETCH_AUTH:
- case FETCH_CERT_ERR:
- default:
- /* not possible */
- assert(0);
- break;
+ case LLCACHE_EVENT_DONE:
+ assert(download_window != NULL);
+
+ gui_download_window_done(download_window);
+
+ break;
+
+ case LLCACHE_EVENT_ERROR:
+ if (download_window != NULL)
+ gui_download_window_error(download_window,
+ event->data.msg);
+
+ break;
+
+ case LLCACHE_EVENT_PROGRESS:
+ break;
}
+
+ return NSERROR_OK;
}
@@ -1392,12 +1402,12 @@ void download_window_callback(fetch_msg msg, void *p, const void *data,
void browser_window_mouse_click(struct browser_window *bw,
browser_mouse_state mouse, int x, int y)
{
- struct content *c = bw->current_content;
+ hlcache_handle *c = bw->current_content;
if (!c)
return;
- switch (c->type) {
+ switch (content_get_type(c)) {
case CONTENT_HTML:
browser_window_mouse_action_html(bw, mouse, x, y);
break;
@@ -1457,12 +1467,12 @@ void browser_window_mouse_action_html(struct browser_window *bw,
struct box *url_box = 0;
struct box *gadget_box = 0;
struct box *text_box = 0;
- struct content *c = bw->current_content;
+ hlcache_handle *c = bw->current_content;
struct box *box;
- struct content *content = c;
- struct content *gadget_content = c;
+ hlcache_handle *content = c;
+ hlcache_handle *gadget_content = c;
struct form_control *gadget = 0;
- struct content *object = NULL;
+ hlcache_handle *object = NULL;
struct box *next_box;
struct box *drag_candidate = NULL;
struct scroll *scroll = NULL;
@@ -1522,7 +1532,7 @@ void browser_window_mouse_action_html(struct browser_window *bw,
/* search the box tree for a link, imagemap, form control, or
* box with scrollbars */
- box = c->data.html.layout;
+ box = html_get_box_tree(c);
/* Consider the margins of the html page now */
box_x = box->margin[LEFT];
@@ -1715,7 +1725,7 @@ void browser_window_mouse_action_html(struct browser_window *bw,
bw->drag_type = DRAGGING_SELECTION;
status = messages_get("Selecting");
} else
- status = c->status_message;
+ status = content_get_status_message(c);
}
else if (mouse & BROWSER_MOUSE_PRESS_1)
selection_clear(bw->sel, true);
@@ -1787,7 +1797,7 @@ void browser_window_mouse_action_html(struct browser_window *bw,
bw->window);
/* \todo should have a drag-saving object msg */
- status = c->status_message;
+ status = content_get_status_message(c);
} else if (url) {
if (title) {
@@ -1803,17 +1813,10 @@ void browser_window_mouse_action_html(struct browser_window *bw,
mouse & BROWSER_MOUSE_MOD_1) {
/* force download of link */
browser_window_go_post(bw, url, 0, 0, false,
- c->url, true, true, 0);
+ content_get_url(c), true, true, 0);
} else if (mouse & BROWSER_MOUSE_CLICK_2 &&
mouse & BROWSER_MOUSE_MOD_1) {
- free(browser_window_href_content.url);
- browser_window_href_content.url = strdup(url);
- if (!browser_window_href_content.url)
- warn_user("NoMemory", 0);
- else
- gui_window_save_as_link(bw->window,
- &browser_window_href_content);
-
+ gui_window_save_link(bw->window, url, title);
} else if (mouse & (BROWSER_MOUSE_CLICK_1 |
BROWSER_MOUSE_CLICK_2))
action = ACTION_GO;
@@ -1834,11 +1837,13 @@ void browser_window_mouse_action_html(struct browser_window *bw,
/* if clicking in the main page, remove the selection from any
* text areas */
if (!done) {
+ struct box *layout = html_get_box_tree(c);
+
if (text_box &&
(mouse & (BROWSER_MOUSE_CLICK_1 |
BROWSER_MOUSE_CLICK_2)) &&
- selection_root(bw->sel) != c->data.html.layout)
- selection_init(bw->sel, c->data.html.layout);
+ selection_root(bw->sel) != layout)
+ selection_init(bw->sel, layout);
if (text_box) {
int pixel_offset;
@@ -1866,7 +1871,7 @@ void browser_window_mouse_action_html(struct browser_window *bw,
status =
messages_get("Selecting");
} else
- status = c->status_message;
+ status = content_get_status_message(c);
done = true;
}
@@ -1879,9 +1884,10 @@ void browser_window_mouse_action_html(struct browser_window *bw,
if (title)
status = title;
else if (bw->loading_content)
- status = bw->loading_content->status_message;
+ status = content_get_status_message(
+ bw->loading_content);
else
- status = c->status_message;
+ status = content_get_status_message(c);
if (mouse & BROWSER_MOUSE_DRAG_1) {
if (mouse & BROWSER_MOUSE_MOD_2) {
@@ -1944,7 +1950,7 @@ void browser_window_mouse_action_html(struct browser_window *bw,
break;
case ACTION_GO:
browser_window_go(browser_window_find_target(bw, target, mouse),
- url, c->url, true);
+ url, content_get_url(c), true);
break;
case ACTION_NONE:
break;
@@ -1970,7 +1976,7 @@ void browser_window_mouse_action_html(struct browser_window *bw,
void browser_window_mouse_action_text(struct browser_window *bw,
browser_mouse_state mouse, int x, int y)
{
- struct content *c = bw->current_content;
+ hlcache_handle *c = bw->current_content;
gui_pointer_shape pointer = GUI_POINTER_DEFAULT;
const char *status = 0;
size_t idx;
@@ -1988,13 +1994,14 @@ void browser_window_mouse_action_text(struct browser_window *bw,
status = messages_get("Selecting");
}
else
- status = c->status_message;
+ status = content_get_status_message(c);
}
else {
if (bw->loading_content)
- status = bw->loading_content->status_message;
+ status = content_get_status_message(
+ bw->loading_content);
else
- status = c->status_message;
+ status = content_get_status_message(c);
if (mouse & (BROWSER_MOUSE_DRAG_1 | BROWSER_MOUSE_DRAG_2)) {
browser_window_page_drag_start(bw, x, y);
@@ -2021,7 +2028,7 @@ void browser_window_mouse_action_text(struct browser_window *bw,
void browser_window_mouse_track(struct browser_window *bw,
browser_mouse_state mouse, int x, int y)
{
- struct content *c = bw->current_content;
+ hlcache_handle *c = bw->current_content;
if (c == NULL && bw->drag_type != DRAGGING_FRAME)
return;
@@ -2051,7 +2058,7 @@ void browser_window_mouse_track(struct browser_window *bw,
} else {
assert(c != NULL);
- switch (c->type) {
+ switch (content_get_type(c)) {
case CONTENT_HTML:
browser_window_mouse_track_html(bw, mouse, x, y);
break;
@@ -2129,7 +2136,7 @@ void browser_window_mouse_track_text(struct browser_window *bw,
switch (bw->drag_type) {
case DRAGGING_SELECTION: {
- struct content *c = bw->current_content;
+ hlcache_handle *c = bw->current_content;
int dir = -1;
size_t idx;
@@ -2198,7 +2205,7 @@ void browser_window_mouse_drag_end(struct browser_window *bw,
switch (bw->drag_type) {
case DRAGGING_SELECTION: {
- struct content *c = bw->current_content;
+ hlcache_handle *c = bw->current_content;
if (c) {
bool found = true;
int dir = -1;
@@ -2206,7 +2213,7 @@ void browser_window_mouse_drag_end(struct browser_window *bw,
if (selection_dragging_start(bw->sel)) dir = 1;
- if (c->type == CONTENT_HTML) {
+ if (content_get_type(c) == CONTENT_HTML) {
int pixel_offset;
struct box *box;
int dx, dy;
@@ -2236,7 +2243,8 @@ void browser_window_mouse_drag_end(struct browser_window *bw,
found = false;
}
else {
- assert(c->type == CONTENT_TEXTPLAIN);
+ assert(content_get_type(c) ==
+ CONTENT_TEXTPLAIN);
idx = textplain_offset_from_coords(c, x,
y, dir);
}
@@ -2263,7 +2271,7 @@ void browser_window_mouse_drag_end(struct browser_window *bw,
* \param radio form control of type GADGET_RADIO
*/
-void browser_radio_set(struct content *content,
+void browser_radio_set(hlcache_handle *content,
struct form_control *radio)
{
struct form_control *control;
@@ -2309,26 +2317,7 @@ void browser_radio_set(struct content *content,
void browser_window_redraw_rect(struct browser_window *bw, int x, int y,
int width, int height)
{
- struct content *c = bw->current_content;
-
- if (c) {
- union content_msg_data data;
-
- data.redraw.x = x;
- data.redraw.y = y;
- data.redraw.width = width;
- data.redraw.height = height;
-
- data.redraw.full_redraw = true;
-
- data.redraw.object = c;
- data.redraw.object_x = 0;
- data.redraw.object_y = 0;
- data.redraw.object_width = c->width;
- data.redraw.object_height = c->height;
-
- content_broadcast(c, CONTENT_MSG_REDRAW, data);
- }
+ content_request_redraw(bw->current_content, x, y, width, height);
}
@@ -2339,29 +2328,15 @@ void browser_window_redraw_rect(struct browser_window *bw, int x, int y,
* \param box box to redraw
*/
-void browser_redraw_box(struct content *c, struct box *box)
+void browser_redraw_box(hlcache_handle *c, struct box *box)
{
int x, y;
- union content_msg_data data;
box_coords(box, &x, &y);
- data.redraw.x = x;
- data.redraw.y = y;
- data.redraw.width = box->padding[LEFT] + box->width +
- box->padding[RIGHT];
- data.redraw.height = box->padding[TOP] + box->height +
- box->padding[BOTTOM];
-
- data.redraw.full_redraw = true;
-
- data.redraw.object = c;
- data.redraw.object_x = 0;
- data.redraw.object_y = 0;
- data.redraw.object_width = c->width;
- data.redraw.object_height = c->height;
-
- content_broadcast(c, CONTENT_MSG_REDRAW, data);
+ content_request_redraw(c, x, y,
+ box->padding[LEFT] + box->width + box->padding[RIGHT],
+ box->padding[TOP] + box->height + box->padding[BOTTOM]);
}
@@ -2441,7 +2416,8 @@ gui_pointer_shape get_pointer_shape(struct browser_window *bw, struct box *box,
assert(bw);
loading = (bw->loading_content != NULL || (bw->current_content &&
- bw->current_content->status == CONTENT_STATUS_READY));
+ content_get_status(bw->current_content) ==
+ CONTENT_STATUS_READY));
if (wallclock() - bw->last_action < 100 && loading)
/* If less than 1 second since last link followed, show
@@ -2540,14 +2516,15 @@ gui_pointer_shape get_pointer_shape(struct browser_window *bw, struct box *box,
* Collect controls and submit a form.
*/
-void browser_form_submit(struct browser_window *bw, struct browser_window *target,
+void browser_form_submit(struct browser_window *bw,
+ struct browser_window *target,
struct form *form, struct form_control *submit_button)
{
char *data = 0, *url = 0;
- struct form_successful_control *success;
+ struct fetch_multipart_data *success;
assert(form);
- assert(bw->current_content->type == CONTENT_HTML);
+ assert(content_get_type(bw->current_content) == CONTENT_HTML);
if (!form_successful_controls(form, submit_button, &success)) {
warn_user("NoMemory", 0);
@@ -2558,14 +2535,14 @@ void browser_form_submit(struct browser_window *bw, struct browser_window *targe
case method_GET:
data = form_url_encode(form, success);
if (!data) {
- form_free_successful(success);
+ fetch_multipart_data_destroy(success);
warn_user("NoMemory", 0);
return;
}
url = calloc(1, strlen(form->action) +
strlen(data) + 2);
if (!url) {
- form_free_successful(success);
+ fetch_multipart_data_destroy(success);
free(data);
warn_user("NoMemory", 0);
return;
@@ -2577,25 +2554,27 @@ void browser_form_submit(struct browser_window *bw, struct browser_window *targe
sprintf(url, "%s?%s", form->action, data);
}
browser_window_go(target, url,
- bw->current_content->url, true);
+ content_get_url(bw->current_content),
+ true);
break;
case method_POST_URLENC:
data = form_url_encode(form, success);
if (!data) {
- form_free_successful(success);
+ fetch_multipart_data_destroy(success);
warn_user("NoMemory", 0);
return;
}
browser_window_go_post(target, form->action, data, 0,
- true, bw->current_content->url,
+ true,
+ content_get_url(bw->current_content),
false, true, 0);
break;
case method_POST_MULTIPART:
browser_window_go_post(target, form->action, 0,
success, true,
- bw->current_content->url,
+ content_get_url(bw->current_content),
false, true, 0);
break;
@@ -2603,7 +2582,7 @@ void browser_form_submit(struct browser_window *bw, struct browser_window *targe
assert(0);
}
- form_free_successful(success);
+ fetch_multipart_data_destroy(success);
free(data);
free(url);
}
@@ -2864,11 +2843,11 @@ bool browser_window_nearest_text_box(struct box *box, int bx, int by,
struct box *browser_window_pick_text_box(struct browser_window *bw,
int x, int y, int dir, int *dx, int *dy)
{
- struct content *c = bw->current_content;
+ hlcache_handle *c = bw->current_content;
struct box *text_box = NULL;
- if (c && c->type == CONTENT_HTML) {
- struct box *box = c->data.html.layout;
+ if (c && content_get_type(c) == CONTENT_HTML) {
+ struct box *box = html_get_box_tree(c);
int nr_xd, nr_yd;
int bx = box->margin[LEFT];
int by = box->margin[TOP];
@@ -3013,5 +2992,6 @@ bool browser_window_stop_available(struct browser_window *bw)
{
return (bw && (bw->loading_content ||
(bw->current_content &&
- (bw->current_content->status != CONTENT_STATUS_DONE))));
+ (content_get_status(bw->current_content) !=
+ CONTENT_STATUS_DONE))));
}
diff --git a/desktop/browser.h b/desktop/browser.h
index 52be9dedb..d72143968 100644
--- a/desktop/browser.h
+++ b/desktop/browser.h
@@ -31,10 +31,9 @@
#include "render/html.h"
struct box;
-struct content;
+struct hlcache_handle;
struct form;
struct form_control;
-struct form_successful_control;
struct gui_window;
struct history;
struct selection;
@@ -44,20 +43,20 @@ struct bitmap;
struct scroll_msg_data;
typedef bool (*browser_caret_callback)(struct browser_window *bw,
- uint32_t key, void *p);
+ uint32_t key, void *p);
typedef bool (*browser_paste_callback)(struct browser_window *bw,
- const char *utf8, unsigned utf8_len, bool last, void *p);
+ const char *utf8, unsigned utf8_len, bool last, void *p);
typedef void (*browser_move_callback)(struct browser_window *bw,
- void *p);
+ void *p);
/** Browser window data. */
struct browser_window {
/** Page currently displayed, or 0. Must have status READY or DONE. */
- struct content *current_content;
+ struct hlcache_handle *current_content;
/** Page being loaded, or 0. */
- struct content *loading_content;
+ struct hlcache_handle *loading_content;
/** Window history structure. */
struct history *history;
@@ -109,9 +108,6 @@ struct browser_window {
/** Scroll capturing all mouse events */
struct scroll *scroll;
- /** Referrer for current fetch, or 0. */
- char *referer;
-
/** Current fetch is download */
bool download;
@@ -230,17 +226,17 @@ extern struct browser_window *current_redraw_browser;
extern bool browser_reformat_pending;
struct browser_window * browser_window_create(const char *url,
- struct browser_window *clone, const char *referrer,
- bool history_add, bool new_tab);
+ struct browser_window *clone, const char *referrer,
+ bool history_add, bool new_tab);
void browser_window_initialise_common(struct browser_window *bw,
- struct browser_window *clone);
+ struct browser_window *clone);
void browser_window_go(struct browser_window *bw, const char *url,
- const char *referrer, bool history_add);
+ const char *referrer, bool history_add);
void browser_window_go_unverifiable(struct browser_window *bw,
- const char *url, const char *referrer, bool history_add,
- struct content *parent);
+ const char *url, const char *referrer, bool history_add,
+ struct hlcache_handle *parent);
void browser_window_download(struct browser_window *bw,
- const char *url, const char *referrer);
+ const char *url, const char *referrer);
void browser_window_update(struct browser_window *bw, bool scroll_to_top);
void browser_window_stop(struct browser_window *bw);
void browser_window_reload(struct browser_window *bw, bool all);
@@ -250,31 +246,32 @@ void browser_window_reformat(struct browser_window *bw, int width, int height);
void browser_window_set_scale(struct browser_window *bw, float scale, bool all);
void browser_window_refresh_url_bar(struct browser_window *bw, const char *url,
- const char *frag);
+ const char *frag);
void browser_window_mouse_click(struct browser_window *bw,
- browser_mouse_state mouse, int x, int y);
+ browser_mouse_state mouse, int x, int y);
void browser_window_mouse_track(struct browser_window *bw,
- browser_mouse_state mouse, int x, int y);
+ browser_mouse_state mouse, int x, int y);
void browser_window_mouse_drag_end(struct browser_window *bw,
- browser_mouse_state mouse, int x, int y);
+ browser_mouse_state mouse, int x, int y);
bool browser_window_key_press(struct browser_window *bw, uint32_t key);
bool browser_window_paste_text(struct browser_window *bw, const char *utf8,
- unsigned utf8_len, bool last);
+ unsigned utf8_len, bool last);
void browser_window_form_select(struct browser_window *bw,
- struct form_control *control, int item);
-void browser_redraw_box(struct content *c, struct box *box);
-void browser_form_submit(struct browser_window *bw, struct browser_window *target,
- struct form *form, struct form_control *submit_button);
+ struct form_control *control, int item);
+void browser_redraw_box(struct hlcache_handle *c, struct box *box);
+void browser_form_submit(struct browser_window *bw,
+ struct browser_window *target, struct form *form,
+ struct form_control *submit_button);
void browser_scroll_callback(void *client_data,
- struct scroll_msg_data *scroll_data);
+ struct scroll_msg_data *scroll_data);
void browser_select_menu_callback(void *client_data,
- int x, int y, int width, int height);
+ int x, int y, int width, int height);
void browser_window_redraw_rect(struct browser_window *bw, int x, int y,
- int width, int height);
+ int width, int height);
bool browser_window_back_available(struct browser_window *bw);
bool browser_window_forward_available(struct browser_window *bw);
@@ -282,7 +279,7 @@ bool browser_window_reload_available(struct browser_window *bw);
bool browser_window_stop_available(struct browser_window *bw);
/* In platform specific hotlist.c. */
-void hotlist_visited(struct content *content);
+void hotlist_visited(struct hlcache_handle *content);
/* In platform specific global_history.c. */
void global_history_add(const char *url);
@@ -290,8 +287,8 @@ void global_history_add_recent(const char *url);
char **global_history_get_recent(int *count);
/* In platform specific thumbnail.c. */
-bool thumbnail_create(struct content *content, struct bitmap *bitmap,
- const char *url);
+bool thumbnail_create(struct hlcache_handle *content, struct bitmap *bitmap,
+ const char *url);
/* In platform specific schedule.c. */
void schedule(int t, void (*callback)(void *p), void *p);
@@ -300,7 +297,7 @@ bool schedule_run(void);
/* In platform specific theme_install.c. */
#ifdef WITH_THEME_INSTALL
-void theme_install_start(struct content *c);
+void theme_install_start(struct hlcache_handle *c);
#endif
#endif
diff --git a/desktop/frames.c b/desktop/frames.c
index acabdc1b9..663ebcdbf 100644
--- a/desktop/frames.c
+++ b/desktop/frames.c
@@ -29,6 +29,7 @@
#include <time.h>
#include <math.h>
#include "utils/config.h"
+#include "content/hlcache.h"
#include "desktop/browser.h"
#include "desktop/frames.h"
#include "desktop/history_core.h"
@@ -105,8 +106,8 @@ void browser_window_create_iframes(struct browser_window *bw,
window = &(bw->iframes[index++]);
if (cur->url)
browser_window_go_unverifiable(window, cur->url,
- bw->current_content->url, false,
- bw->current_content);
+ content_get_url(bw->current_content),
+ false, bw->current_content);
}
}
@@ -155,7 +156,7 @@ void browser_window_create_frameset(struct browser_window *bw,
int row, col, index;
struct content_html_frames *frame;
struct browser_window *window;
- struct content *parent;
+ hlcache_handle *parent;
assert(bw && frameset);
@@ -230,8 +231,9 @@ void browser_window_create_frameset(struct browser_window *bw,
/* Use the URL of the first ancestor window containing html content
* as the referer */
for (window = bw; window->parent; window = window->parent) {
- if (window->current_content &&
- window->current_content->type == CONTENT_HTML)
+ if (window->current_content &&
+ content_get_type(window->current_content) ==
+ CONTENT_HTML)
break;
}
@@ -247,8 +249,7 @@ void browser_window_create_frameset(struct browser_window *bw,
if (frame->url) {
browser_window_go_unverifiable(window,
frame->url,
- parent != NULL
- ? parent->url : NULL,
+ content_get_url(parent),
true,
parent);
}
diff --git a/desktop/gui.h b/desktop/gui.h
index f09e5f20f..162632a1a 100644
--- a/desktop/gui.h
+++ b/desktop/gui.h
@@ -41,6 +41,7 @@ typedef enum {
GUI_SAVE_CLIPBOARD_CONTENTS
} gui_save_type;
+struct fetch;
struct gui_window;
struct gui_download_window;
@@ -55,6 +56,7 @@ typedef enum { GUI_POINTER_DEFAULT, GUI_POINTER_POINT, GUI_POINTER_CARET,
#include <stdbool.h>
#include "utils/config.h"
#include "content/content.h"
+#include "content/hlcache.h"
#include "desktop/browser.h"
#include "desktop/search.h"
@@ -89,8 +91,8 @@ void gui_window_hide_pointer(struct gui_window *g);
void gui_window_set_url(struct gui_window *g, const char *url);
void gui_window_start_throbber(struct gui_window *g);
void gui_window_stop_throbber(struct gui_window *g);
-void gui_window_set_icon(struct gui_window *g, struct content *icon);
-void gui_window_set_search_ico(struct content *ico);
+void gui_window_set_icon(struct gui_window *g, hlcache_handle *icon);
+void gui_window_set_search_ico(hlcache_handle *ico);
void gui_window_place_caret(struct gui_window *g, int x, int y, int height);
void gui_window_remove_caret(struct gui_window *g);
void gui_window_new_content(struct gui_window *g);
@@ -98,7 +100,8 @@ bool gui_window_scroll_start(struct gui_window *g);
bool gui_window_box_scroll_start(struct gui_window *g,
int x0, int y0, int x1, int y1);
bool gui_window_frame_resize_start(struct gui_window *g);
-void gui_window_save_as_link(struct gui_window *g, struct content *c);
+void gui_window_save_link(struct gui_window *g, const char *url,
+ const char *title);
void gui_window_set_scale(struct gui_window *g, float scale);
struct gui_download_window *gui_download_window_create(const char *url,
@@ -110,7 +113,7 @@ void gui_download_window_error(struct gui_download_window *dw,
const char *error_msg);
void gui_download_window_done(struct gui_download_window *dw);
-void gui_drag_save_object(gui_save_type type, struct content *c,
+void gui_drag_save_object(gui_save_type type, hlcache_handle *c,
struct gui_window *g);
void gui_drag_save_selection(struct selection *s, struct gui_window *g);
void gui_start_selection(struct gui_window *g);
@@ -133,7 +136,7 @@ bool gui_search_term_highlighted(struct gui_window *g,
struct ssl_cert_info;
-void gui_cert_verify(struct browser_window *bw, struct content *c,
+void gui_cert_verify(struct browser_window *bw, hlcache_handle *c,
const struct ssl_cert_info *certs, unsigned long num);
#endif
diff --git a/desktop/history_core.c b/desktop/history_core.c
index 197a42327..fc807e928 100644
--- a/desktop/history_core.c
+++ b/desktop/history_core.c
@@ -27,6 +27,7 @@
#include <string.h>
#include <time.h>
#include "content/content.h"
+#include "content/hlcache.h"
#include "content/urldb.h"
#include "css/css.h"
#include "desktop/gui.h"
@@ -220,7 +221,7 @@ struct history_entry *history_clone_entry(struct history *history,
* The page is added after the current entry and becomes current.
*/
-void history_add(struct history *history, struct content *content,
+void history_add(struct history *history, hlcache_handle *content,
char *frag_id)
{
url_func_result res;
@@ -237,14 +238,14 @@ void history_add(struct history *history, struct content *content,
if (entry == NULL)
return;
- res = url_normalize(content->url, &url);
+ res = url_normalize(content_get_url(content), &url);
if (res != URL_FUNC_OK) {
warn_user("NoMemory", 0);
free(entry);
return;
}
- title = strdup(content->title ? content->title : url);
+ title = strdup(content_get_title(content));
if (title == NULL) {
warn_user("NoMemory", 0);
free(url);
@@ -303,11 +304,9 @@ void history_add(struct history *history, struct content *content,
* \param content content for current entry
*/
-void history_update(struct history *history, struct content *content)
+void history_update(struct history *history, hlcache_handle *content)
{
char *title;
- char *url;
- url_func_result res;
if (!history || !history->current || !history->current->bitmap)
return;
@@ -315,19 +314,10 @@ void history_update(struct history *history, struct content *content)
assert(history->current->page.url);
assert(history->current->page.title);
- if (content->title) {
- title = strdup(content->title);
- if (!title) {
- warn_user("NoMemory", 0);
- return;
- }
- } else {
- res = url_normalize(content->url, &url);
- if (res != URL_FUNC_OK) {
- warn_user("NoMemory", 0);
- return;
- }
- title = url;
+ title = strdup(content_get_title(content));
+ if (!title) {
+ warn_user("NoMemory", 0);
+ return;
}
assert(title);
diff --git a/desktop/history_core.h b/desktop/history_core.h
index 46de18848..55b4e0bf1 100644
--- a/desktop/history_core.h
+++ b/desktop/history_core.h
@@ -25,15 +25,15 @@
#include <stdbool.h>
-struct content;
+struct hlcache_handle;
struct history;
struct browser_window;
struct history *history_create(void);
struct history *history_clone(struct history *history);
-void history_add(struct history *history, struct content *content,
+void history_add(struct history *history, struct hlcache_handle *content,
char *frag_id);
-void history_update(struct history *history, struct content *content);
+void history_update(struct history *history, struct hlcache_handle *content);
void history_destroy(struct history *history);
void history_back(struct browser_window *bw, struct history *history);
void history_forward(struct browser_window *bw, struct history *history);
diff --git a/desktop/netsurf.c b/desktop/netsurf.c
index 9acddaf87..192ddc185 100644
--- a/desktop/netsurf.c
+++ b/desktop/netsurf.c
@@ -28,10 +28,13 @@
#include <libxml/globals.h>
#include <libxml/xmlversion.h>
+#include <libwapcaplet/libwapcaplet.h>
+
#include "utils/config.h"
#include "utils/utsname.h"
#include "content/fetch.h"
#include "content/fetchcache.h"
+#include "content/llcache.h"
#include "content/urldb.h"
#include "desktop/netsurf.h"
#include "desktop/browser.h"
@@ -44,39 +47,11 @@
bool netsurf_quit = false;
bool verbose_log = false;
-static void netsurf_poll(void);
-static void lib_init(void);
-
-
-/**
- * Gui NetSurf main().
- */
-
-int netsurf_main(int argc, char** argv)
-{
- netsurf_init(argc, argv);
-
- netsurf_main_loop();
-
- netsurf_exit();
-
- return EXIT_SUCCESS;
-}
-
-
-/**
- * Gui NetSurf main loop.
- */
-
-int netsurf_main_loop(void)
+static void *netsurf_lwc_alloc(void *ptr, size_t len, void *pw)
{
- while (!netsurf_quit)
- netsurf_poll();
-
- return 0;
+ return realloc(ptr, len);
}
-
/**
* Initialise components used by gui NetSurf.
*/
@@ -126,35 +101,30 @@ void netsurf_init(int argc, char** argv)
utsname.nodename, utsname.release,
utsname.version, utsname.machine));
- lib_init();
+ lwc_initialise(netsurf_lwc_alloc, NULL, 0);
url_init();
gui_init(argc, argv);
setlocale(LC_ALL, "C");
fetch_init();
- fetchcache_init();
+ /** \todo The frontend needs to provide the llcache_query_handler */
+ llcache_initialise(NULL, NULL);
gui_init2(argc, argv);
}
+
/**
- * Poll components which require it.
+ * Gui NetSurf main loop.
*/
-
-void netsurf_poll(void)
+int netsurf_main_loop(void)
{
- static unsigned int last_clean = 0;
- unsigned int current_time = wallclock();
-
- /* avoid calling content_clean() more often than once every 5
- * seconds.
- */
- if (last_clean + 500 < current_time) {
- last_clean = current_time;
- content_clean();
+ while (!netsurf_quit) {
+ gui_poll(fetch_active);
+ fetch_poll();
+ llcache_poll();
}
- gui_poll(fetch_active);
- fetch_poll();
-}
+ return 0;
+}
/**
* Clean up components used by gui NetSurf.
@@ -164,8 +134,6 @@ void netsurf_exit(void)
{
LOG(("Closing GUI"));
gui_quit();
- LOG(("Closing content"));
- content_quit();
LOG(("Closing fetches"));
fetch_quit();
LOG(("Closing utf8"));
@@ -176,18 +144,3 @@ void netsurf_exit(void)
}
-/**
- * Initialises the libraries used in NetSurf.
- */
-void lib_init(void)
-{
- LOG(("xmlParserVersion %s, LIBXML_VERSION_STRING %s",
- xmlParserVersion, LIBXML_VERSION_STRING));
-
- /* Using encoding "X-SJIS" (unknown to libxmp2/iconv) instead as
- * "Shift-JIS" is rather popular.
- */
- if (xmlAddEncodingAlias(xmlGetCharEncodingName(
- XML_CHAR_ENCODING_SHIFT_JIS), "X-SJIS") != 0)
- die("Failed to add encoding alias");
-}
diff --git a/desktop/netsurf.h b/desktop/netsurf.h
index 05b870333..33733fa40 100644
--- a/desktop/netsurf.h
+++ b/desktop/netsurf.h
@@ -29,7 +29,6 @@ extern const int netsurf_version_minor;
extern void netsurf_init(int argc, char** argv);
extern void netsurf_exit(void);
-extern int netsurf_main(int argc, char** argv);
extern int netsurf_main_loop(void);
#endif
diff --git a/desktop/print.c b/desktop/print.c
index 4f86bbc22..a5b5c125a 100644
--- a/desktop/print.c
+++ b/desktop/print.c
@@ -26,6 +26,7 @@
#include <string.h>
#include "content/content.h"
+#include "content/hlcache.h"
#include "css/utils.h"
#include "desktop/options.h"
#include "desktop/print.h"
@@ -39,11 +40,11 @@
#define DEFAULT_PAGE_HEIGHT 840
#define DEFAULT_COPIES 1
-static struct content *print_init(struct content *, struct print_settings *);
-static bool print_apply_settings(struct content *, struct print_settings *);
+static hlcache_handle *print_init(hlcache_handle *, struct print_settings *);
+static bool print_apply_settings(hlcache_handle *, struct print_settings *);
static float page_content_width, page_content_height;
-static struct content *printed_content;
+static hlcache_handle *printed_content;
static float done_height;
bool html_redraw_printing = false;
@@ -59,7 +60,7 @@ int html_redraw_printing_top_cropped = 0;
* \param settings The settings for printing to use
* \return true if successful, false otherwise
*/
-bool print_basic_run(struct content *content,
+bool print_basic_run(hlcache_handle *content,
const struct printer *printer,
struct print_settings *settings)
{
@@ -69,8 +70,8 @@ bool print_basic_run(struct content *content,
if (!print_set_up(content, printer, settings, NULL))
ret = false;
-
- while (ret && (done_height < printed_content->height) )
+
+ while (ret && (done_height < content_get_height(printed_content)) )
ret = print_draw_next_page(printer, settings);
print_cleanup(content, printer, settings);
@@ -88,7 +89,7 @@ bool print_basic_run(struct content *content,
* \param height updated to the height of the printed content
* \return true if successful, false otherwise
*/
-bool print_set_up(struct content *content,
+bool print_set_up(hlcache_handle *content,
const struct printer *printer, struct print_settings *settings,
double *height)
{
@@ -100,7 +101,7 @@ bool print_set_up(struct content *content,
print_apply_settings(printed_content, settings);
if (height)
- *height = printed_content->height;
+ *height = content_get_height(printed_content);
printer->print_begin(settings);
@@ -158,11 +159,13 @@ bool print_draw_next_page(const struct printer *printer,
* \param settings The settings for printing to use
* \return true if successful, false otherwise
*/
-struct content *print_init(struct content *content,
+hlcache_handle *print_init(hlcache_handle *content,
struct print_settings *settings)
{
- struct content* printed_content;
- struct content_user *user_sentinel;
+// newcache
+#if 0
+ hlcache_handle* printed_content;
+ hlcache_handle_user *user_sentinel;
content_add_user(content, NULL, (intptr_t) print_init, 0);
@@ -173,7 +176,7 @@ struct content *print_init(struct content *content,
printed_content->data.html.bw = 0;
- user_sentinel = talloc(printed_content, struct content_user);
+ user_sentinel = talloc(printed_content, hlcache_handle_user);
user_sentinel->callback = 0;
user_sentinel->p1 = user_sentinel->p2 = 0;
user_sentinel->next = 0;
@@ -194,6 +197,9 @@ struct content *print_init(struct content *content,
printed_content->data.html.font_func = settings->font_func;
return printed_content;
+#else
+ return NULL;
+#endif
}
/**
@@ -203,7 +209,7 @@ struct content *print_init(struct content *content,
* \param settings The settings for printing to use
* \return true if successful, false otherwise
*/
-bool print_apply_settings(struct content *content,
+bool print_apply_settings(hlcache_handle *content,
struct print_settings *settings)
{
if (settings == NULL)
@@ -222,7 +228,8 @@ bool print_apply_settings(struct content *content,
content_reformat(content, page_content_width, 0);
LOG(("New layout applied.New height = %d ; New width = %d ",
- content->height, content->width));
+ content_get_height(content),
+ content_get_width(content)));
return true;
}
@@ -234,7 +241,7 @@ bool print_apply_settings(struct content *content,
* \param printer The printer interface for the printer to be used
* \return true if successful, false otherwise
*/
-bool print_cleanup(struct content *content, const struct printer *printer,
+bool print_cleanup(hlcache_handle *content, const struct printer *printer,
struct print_settings *settings)
{
printer->print_end();
@@ -242,12 +249,11 @@ bool print_cleanup(struct content *content, const struct printer *printer,
html_redraw_printing = false;
if (printed_content) {
- content_remove_user(printed_content, NULL,
- (intptr_t) print_init, 0);
+ content_remove_user(printed_content, NULL, print_init);
talloc_free(printed_content);
}
- content_remove_user(content, NULL, (intptr_t)print_init, 0);
+ content_remove_user(content, NULL, print_init);
free((void *)settings->output);
free(settings);
diff --git a/desktop/print.h b/desktop/print.h
index fece526be..63c2935f1 100644
--- a/desktop/print.h
+++ b/desktop/print.h
@@ -36,7 +36,7 @@
#include "css/css.h"
-struct content;
+struct hlcache_handle;
struct printer;
enum { MARGINLEFT = 0, MARGINRIGHT = 1, MARGINTOP = 2, MARGINBOTTOM = 3};
@@ -64,13 +64,13 @@ struct print_settings{
};
-bool print_basic_run(struct content *, const struct printer *,
+bool print_basic_run(struct hlcache_handle *, const struct printer *,
struct print_settings *);
-bool print_set_up(struct content *content, const struct printer *printer,
+bool print_set_up(struct hlcache_handle *content, const struct printer *printer,
struct print_settings *settings, double *height);
bool print_draw_next_page(const struct printer *printer,
struct print_settings *settings);
-bool print_cleanup(struct content *, const struct printer *,
+bool print_cleanup(struct hlcache_handle *, const struct printer *,
struct print_settings *settings);
struct print_settings *print_make_settings(print_configuration configuration,
diff --git a/desktop/save_complete.c b/desktop/save_complete.c
index d55cde08f..78b2d7646 100644
--- a/desktop/save_complete.c
+++ b/desktop/save_complete.c
@@ -35,6 +35,7 @@
#include <libxml/parserInternals.h>
#include "utils/config.h"
#include "content/content.h"
+#include "content/hlcache.h"
#include "css/css.h"
#include "render/box.h"
#include "desktop/save_complete.h"
@@ -46,14 +47,14 @@ regex_t save_complete_import_re;
/** An entry in save_complete_list. */
struct save_complete_entry {
- struct content *content;
+ hlcache_handle *content;
struct save_complete_entry *next; /**< Next entry in list */
};
-static bool save_complete_html(struct content *c, const char *path,
+static bool save_complete_html(hlcache_handle *c, const char *path,
bool index, struct save_complete_entry **list);
-static bool save_imported_sheets(struct content *c, const char *path,
- struct save_complete_entry **list);
+static bool save_imported_sheets(struct nscss_import *imports, uint32_t count,
+ const char *path, struct save_complete_entry **list);
static char * rewrite_stylesheet_urls(const char *source, unsigned int size,
int *osize, const char *base,
struct save_complete_entry *list);
@@ -63,11 +64,11 @@ static bool rewrite_urls(xmlNode *n, const char *base,
struct save_complete_entry *list);
static bool rewrite_url(xmlNode *n, const char *attr, const char *base,
struct save_complete_entry *list);
-static bool save_complete_list_add(struct content *content,
+static bool save_complete_list_add(hlcache_handle *content,
struct save_complete_entry **list);
-static struct content * save_complete_list_find(const char *url,
+static hlcache_handle * save_complete_list_find(const char *url,
struct save_complete_entry *list);
-static bool save_complete_list_check(struct content *content,
+static bool save_complete_list_check(hlcache_handle *content,
struct save_complete_entry *list);
/* static void save_complete_list_dump(void); */
static bool save_complete_inventory(const char *path,
@@ -81,7 +82,7 @@ static bool save_complete_inventory(const char *path,
* \return true on success, false on error and error reported
*/
-bool save_complete(struct content *c, const char *path)
+bool save_complete(hlcache_handle *c, const char *path)
{
bool result;
struct save_complete_entry *list = NULL;
@@ -111,50 +112,69 @@ bool save_complete(struct content *c, const char *path)
* \return true on success, false on error and error reported
*/
-bool save_complete_html(struct content *c, const char *path, bool index,
+bool save_complete_html(hlcache_handle *c, const char *path, bool index,
struct save_complete_entry **list)
{
+ struct html_stylesheet *sheets;
+ struct content_html_object *objects;
+ const char *base_url;
char filename[256];
- unsigned int i;
+ unsigned int i, count;
xmlDocPtr doc;
bool res;
- if (c->type != CONTENT_HTML)
+ if (content_get_type(c) != CONTENT_HTML)
return false;
if (save_complete_list_check(c, *list))
return true;
-
+
+ base_url = html_get_base_url(c);
+
/* save stylesheets, ignoring the base and adblocking sheets */
- for (i = STYLESHEET_START; i != c->data.html.stylesheet_count; i++) {
- struct content *css = c->data.html.stylesheets[i].c;
+ sheets = html_get_stylesheets(c, &count);
+
+ for (i = STYLESHEET_START; i != count; i++) {
+ hlcache_handle *css;
+ const char *css_data;
+ unsigned long css_size;
char *source;
int source_len;
- bool is_style;
+ struct nscss_import *imports;
+ uint32_t import_count;
+
+ if (sheets[i].type == HTML_STYLESHEET_INTERNAL) {
+ if (save_imported_sheets(
+ sheets[i].data.internal->imports,
+ sheets[i].data.internal->import_count,
+ path, list) == false)
+ return false;
+
+ continue;
+ }
+
+ css = sheets[i].data.external;
if (!css)
continue;
if (save_complete_list_check(css, *list))
continue;
- is_style = (strcmp(css->url, c->data.html.base_url) == 0);
-
- if (is_style == false) {
- if (!save_complete_list_add(css, list)) {
- warn_user("NoMemory", 0);
- return false;
- }
+ if (!save_complete_list_add(css, list)) {
+ warn_user("NoMemory", 0);
+ return false;
}
- if (!save_imported_sheets(css, path, list))
+ imports = nscss_get_imports(css, &import_count);
+ if (!save_imported_sheets(imports, import_count, path, list))
return false;
- if (is_style)
- continue; /* don't save <style> elements */
-
snprintf(filename, sizeof filename, "%p", css);
- source = rewrite_stylesheet_urls(css->source_data,
- css->source_size, &source_len, css->url,
+
+ css_data = content_get_source_data(css, &css_size);
+
+ source = rewrite_stylesheet_urls(css_data, css_size,
+ &source_len, content_get_url(css),
*list);
if (!source) {
warn_user("NoMemory", 0);
@@ -168,12 +188,21 @@ bool save_complete_html(struct content *c, const char *path, bool index,
}
/* save objects */
- for (i = 0; i != c->data.html.object_count; i++) {
- struct content *obj = c->data.html.object[i].content;
+ objects = html_get_objects(c, &count);
+
+ for (i = 0; i != count; i++) {
+ hlcache_handle *obj = objects[i].content;
+ const char *obj_data;
+ unsigned long obj_size;
- /* skip difficult content types */
- if (!obj || obj->type >= CONTENT_OTHER || !obj->source_data)
+ if (obj == NULL || content_get_type(obj) >= CONTENT_OTHER)
continue;
+
+ obj_data = content_get_source_data(obj, &obj_size);
+
+ if (obj_data == NULL)
+ continue;
+
if (save_complete_list_check(obj, *list))
continue;
@@ -182,7 +211,7 @@ bool save_complete_html(struct content *c, const char *path, bool index,
return false;
}
- if (obj->type == CONTENT_HTML) {
+ if (content_get_type(obj) == CONTENT_HTML) {
if (!save_complete_html(obj, path, false, list))
return false;
continue;
@@ -190,7 +219,7 @@ bool save_complete_html(struct content *c, const char *path, bool index,
snprintf(filename, sizeof filename, "%p", obj);
res = save_complete_gui_save(path, filename,
- obj->source_size, obj->source_data, obj->type);
+ obj_size, obj_data, content_get_type(obj));
if(res == false)
return false;
}
@@ -198,14 +227,14 @@ bool save_complete_html(struct content *c, const char *path, bool index,
/*save_complete_list_dump();*/
/* copy document */
- doc = xmlCopyDoc(c->data.html.document, 1);
+ doc = xmlCopyDoc(html_get_document(c), 1);
if (doc == NULL) {
warn_user("NoMemory", 0);
return false;
}
/* rewrite all urls we know about */
- if (!rewrite_document_urls(doc, c->data.html.base_url, *list)) {
+ if (!rewrite_document_urls(doc, html_get_base_url(c), *list)) {
xmlFreeDoc(doc);
warn_user("NoMemory", 0);
return false;
@@ -237,13 +266,13 @@ bool save_complete_html(struct content *c, const char *path, bool index,
/**
* Save stylesheets imported by a CONTENT_CSS.
*
- * \param c a CONTENT_CSS
- * \param path path to save to
+ * \param imports Array of imports
+ * \param count Number of imports in list
+ * \param path Path to save to
* \return true on success, false on error and error reported
*/
-
-bool save_imported_sheets(struct content *c, const char *path,
- struct save_complete_entry **list)
+bool save_imported_sheets(struct nscss_import *imports, uint32_t count,
+ const char *path, struct save_complete_entry **list)
{
char filename[256];
unsigned int j;
@@ -251,10 +280,14 @@ bool save_imported_sheets(struct content *c, const char *path,
int source_len;
bool res;
- for (j = 0; j != c->data.css.import_count; j++) {
- struct content *css = c->data.css.imports[j].c;
+ for (j = 0; j != count; j++) {
+ hlcache_handle *css = imports[j].c;
+ const char *css_data;
+ unsigned long css_size;
+ struct nscss_import *child_imports;
+ uint32_t child_import_count;
- if (!css)
+ if (css == NULL)
continue;
if (save_complete_list_check(css, *list))
continue;
@@ -264,12 +297,17 @@ bool save_imported_sheets(struct content *c, const char *path,
return false;
}
- if (!save_imported_sheets(css, path, list))
+ child_imports = nscss_get_imports(css, &child_import_count);
+ if (!save_imported_sheets(child_imports, child_import_count,
+ path, list))
return false;
snprintf(filename, sizeof filename, "%p", css);
- source = rewrite_stylesheet_urls(css->source_data,
- css->source_size, &source_len, css->url,
+
+ css_data = content_get_source_data(css, &css_size);
+
+ source = rewrite_stylesheet_urls(css_data, css_size,
+ &source_len, content_get_url(css),
*list);
if (!source) {
warn_user("NoMemory", 0);
@@ -344,7 +382,7 @@ char * rewrite_stylesheet_urls(const char *source, unsigned int size,
char buf[20];
unsigned int offset = 0;
int url_len = 0;
- struct content *content;
+ hlcache_handle *content;
int m;
unsigned int i;
unsigned int imports = 0;
@@ -609,7 +647,7 @@ bool rewrite_url(xmlNode *n, const char *attr, const char *base,
{
char *url, *data;
char rel[20];
- struct content *content;
+ hlcache_handle *content;
url_func_result res;
if (!xmlHasProp(n, (const xmlChar *) attr))
@@ -654,7 +692,7 @@ bool rewrite_url(xmlNode *n, const char *attr, const char *base,
* \return true on success, false on out of memory
*/
-bool save_complete_list_add(struct content *content,
+bool save_complete_list_add(hlcache_handle *content,
struct save_complete_entry **list)
{
struct save_complete_entry *entry;
@@ -675,12 +713,12 @@ bool save_complete_list_add(struct content *content,
* \return content if found, 0 otherwise
*/
-struct content * save_complete_list_find(const char *url,
+hlcache_handle * save_complete_list_find(const char *url,
struct save_complete_entry *list)
{
struct save_complete_entry *entry;
for (entry = list; entry; entry = entry->next)
- if (strcmp(url, entry->content->url) == 0)
+ if (strcmp(url, content_get_url(entry->content)) == 0)
return entry->content;
return 0;
}
@@ -693,7 +731,7 @@ struct content * save_complete_list_find(const char *url,
* \return true if the content is in the save_complete_list
*/
-bool save_complete_list_check(struct content *content,
+bool save_complete_list_check(hlcache_handle *content,
struct save_complete_entry *list)
{
struct save_complete_entry *entry;
@@ -746,8 +784,10 @@ bool save_complete_inventory(const char *path,
return false;
}
- for (entry = list; entry; entry = entry->next)
- fprintf(fp, "%p %s\n", entry->content, entry->content->url);
+ for (entry = list; entry; entry = entry->next) {
+ fprintf(fp, "%p %s\n", entry->content,
+ content_get_url(entry->content));
+ }
fclose(fp);
diff --git a/desktop/save_complete.h b/desktop/save_complete.h
index e23092471..ad31fa486 100644
--- a/desktop/save_complete.h
+++ b/desktop/save_complete.h
@@ -28,10 +28,10 @@
#include <libxml/HTMLtree.h>
#include "content/content.h"
-struct content;
+struct hlcache_handle;
void save_complete_init(void);
-bool save_complete(struct content *c, const char *path);
+bool save_complete(struct hlcache_handle *c, const char *path);
bool save_complete_gui_save(const char *path, const char *filename,
size_t len, const char *sourcedata, content_type type);
diff --git a/desktop/save_pdf/pdf_plotters.c b/desktop/save_pdf/pdf_plotters.c
index 8dbe43971..f33070edb 100644
--- a/desktop/save_pdf/pdf_plotters.c
+++ b/desktop/save_pdf/pdf_plotters.c
@@ -30,6 +30,7 @@
#include <hpdf.h>
+#include "content/hlcache.h"
#include "desktop/options.h"
#include "desktop/plotters.h"
#include "desktop/print.h"
@@ -410,32 +411,37 @@ bool pdf_plot_bitmap_tile(int x, int y, int width, int height,
HPDF_Image pdf_extract_image(struct bitmap *bitmap)
{
HPDF_Image image = NULL;
- struct content *content = NULL;
+ hlcache_handle *content = NULL;
/* TODO - get content from bitmap pointer */
if (content) {
+ const char *source_data;
+ unsigned long source_size;
+
/*Not sure if I don't have to check if downloading has been
finished.
Other way - lock pdf plotting while fetching a website
*/
- switch(content->type){
- /*Handle "embeddable" types of images*/
- case CONTENT_JPEG:
- image = HPDF_LoadJpegImageFromMem(pdf_doc,
- (const HPDF_BYTE *)content->source_data,
- content->source_size);
- break;
-
- /*Disabled until HARU PNG support will be more stable.
-
- case CONTENT_PNG:
- image = HPDF_LoadPngImageFromMem(pdf_doc,
- (const HPDF_BYTE *)content->source_data,
- content->total_size);
- break;*/
- default:
- break;
+ source_data = content_get_source_data(content, &source_size);
+
+ switch(content_get_type(content)){
+ /*Handle "embeddable" types of images*/
+ case CONTENT_JPEG:
+ image = HPDF_LoadJpegImageFromMem(pdf_doc,
+ (const HPDF_BYTE *) source_data,
+ source_size);
+ break;
+
+ /*Disabled until HARU PNG support will be more stable.
+
+ case CONTENT_PNG:
+ image = HPDF_LoadPngImageFromMem(pdf_doc,
+ (const HPDF_BYTE *)content->source_data,
+ content->total_size);
+ break;*/
+ default:
+ break;
}
}
diff --git a/desktop/save_text.c b/desktop/save_text.c
index e34b9ceb0..5e5cef761 100644
--- a/desktop/save_text.c
+++ b/desktop/save_text.c
@@ -27,6 +27,7 @@
#include "utils/config.h"
#include "content/content.h"
+#include "content/hlcache.h"
#include "desktop/save_text.h"
#include "render/box.h"
#include "utils/log.h"
@@ -48,7 +49,7 @@ static bool save_text_add_to_buffer(const char *text, size_t length,
* \param path Path to save text file too.
*/
-void save_as_text(struct content *c, char *path)
+void save_as_text(hlcache_handle *c, char *path)
{
FILE *out;
struct save_text_state save = { NULL, 0, 0 };
@@ -57,11 +58,11 @@ void save_as_text(struct content *c, char *path)
utf8_convert_ret ret;
char *result;
- if (!c || c->type != CONTENT_HTML) {
+ if (!c || content_get_type(c) != CONTENT_HTML) {
return;
}
- extract_text(c->data.html.layout, &first, &before, &save);
+ extract_text(html_get_box_tree(c), &first, &before, &save);
if (!save.block)
return;
diff --git a/desktop/save_text.h b/desktop/save_text.h
index 825d08f63..06446cd58 100644
--- a/desktop/save_text.h
+++ b/desktop/save_text.h
@@ -25,7 +25,7 @@
#define _NETSURF_DESKTOP_SAVE_TEXT_H_
struct box;
-struct content;
+struct hlcache_handle;
/* text currently being saved */
struct save_text_state {
@@ -41,7 +41,7 @@ typedef enum {
WHITESPACE_TWO_NEW_LINES
} save_text_whitespace;
-void save_as_text(struct content *c, char *path);
+void save_as_text(struct hlcache_handle *c, char *path);
void save_text_solve_whitespace(struct box *box, bool *first,
save_text_whitespace *before, const char **whitespace_text,
size_t *whitespace_length);
diff --git a/desktop/search.c b/desktop/search.c
index ba472fd41..f84f1f06e 100644
--- a/desktop/search.c
+++ b/desktop/search.c
@@ -26,6 +26,7 @@
#include <ctype.h>
#include <string.h>
#include "content/content.h"
+#include "content/hlcache.h"
#include "desktop/browser.h"
#include "desktop/gui.h"
#include "desktop/options.h"
@@ -33,6 +34,7 @@
#include "desktop/selection.h"
#include "render/box.h"
#include "render/html.h"
+#include "render/textplain.h"
#include "utils/config.h"
#include "utils/log.h"
#include "utils/messages.h"
@@ -60,7 +62,7 @@ struct list_entry {
struct search_context {
struct browser_window *bw;
- struct content *content;
+ hlcache_handle *content;
char *string;
bool prev_case_sens;
bool newsearch;
@@ -80,7 +82,7 @@ static bool find_occurrences_html(const char *pattern, int p_len,
struct box *cur, bool case_sens,
struct search_context *context);
static bool find_occurrences_text(const char *pattern, int p_len,
- struct content *c, bool case_sens,
+ hlcache_handle *c, bool case_sens,
struct search_context *context);
static struct list_entry *add_entry(unsigned start_idx, unsigned end_idx,
struct search_context *context);
@@ -236,7 +238,7 @@ void search_text(const char *string, int string_len,
struct search_context *context, search_flags_t flags)
{
struct rect bounds;
- struct content *c;
+ hlcache_handle *c;
struct box *box;
bool case_sensitive, forwards, showall;
@@ -250,11 +252,11 @@ void search_text(const char *string, int string_len,
c = context->bw->current_content;
/* only handle html contents */
- if ((!c) || (c->type != CONTENT_HTML &&
- c->type != CONTENT_TEXTPLAIN))
+ if ((!c) || (content_get_type(c) != CONTENT_HTML &&
+ content_get_type(c) != CONTENT_TEXTPLAIN))
return;
- box = c->data.html.layout;
+ box = html_get_box_tree(c);
if (!box)
return;
@@ -282,11 +284,11 @@ void search_text(const char *string, int string_len,
(context->callbacks->hourglass != NULL))
context->callbacks->hourglass(true, context->p);
- if (c->type == CONTENT_HTML)
+ if (content_get_type(c) == CONTENT_HTML)
res = find_occurrences_html(string, string_len,
box, case_sensitive, context);
else {
- assert(c->type == CONTENT_TEXTPLAIN);
+ assert(content_get_type(c) == CONTENT_TEXTPLAIN);
res = find_occurrences_text(string, string_len,
c, case_sensitive, context);
}
@@ -342,7 +344,7 @@ void search_text(const char *string, int string_len,
if (context->current == NULL)
return;
- switch (c->type) {
+ switch (content_get_type(c)) {
case CONTENT_HTML:
/* get box position and jump to it */
box_coords(context->current->start_box,
@@ -356,7 +358,7 @@ void search_text(const char *string, int string_len,
break;
default:
- assert(c->type == CONTENT_TEXTPLAIN);
+ assert(content_get_type(c) == CONTENT_TEXTPLAIN);
textplain_coords_from_range(c,
context->current->start_idx,
context->current->end_idx, &bounds);
@@ -551,7 +553,7 @@ bool find_occurrences_html(const char *pattern, int p_len, struct box *cur,
*/
bool find_occurrences_text(const char *pattern, int p_len,
- struct content *c, bool case_sens,
+ hlcache_handle *c, bool case_sens,
struct search_context *context)
{
int nlines = textplain_line_count(c);
@@ -642,15 +644,15 @@ void search_show_all(bool all, struct search_context *context)
if (add && !a->sel) {
a->sel = selection_create(context->bw);
if (a->sel) {
- struct content *c = context->bw->
+ hlcache_handle *c = context->bw->
current_content;
- switch (c->type) {
+ switch (content_get_type(c)) {
case CONTENT_HTML:
selection_init(a->sel,
- c->data.html.layout);
+ html_get_box_tree(c));
break;
default:
- assert(c->type ==
+ assert(content_get_type(c) ==
CONTENT_TEXTPLAIN);
selection_init(a->sel, NULL);
break;
diff --git a/desktop/searchweb.c b/desktop/searchweb.c
index bc0f71ad4..724edc9dd 100644
--- a/desktop/searchweb.c
+++ b/desktop/searchweb.c
@@ -24,8 +24,7 @@
#include <ctype.h>
#include <string.h>
#include "content/content.h"
-#include "content/fetchcache.h"
-#include "content/fetch.h"
+#include "content/hlcache.h"
#include "desktop/browser.h"
#include "desktop/gui.h"
#include "desktop/options.h"
@@ -43,10 +42,13 @@ static struct search_provider {
char *ico; /** < location of domain's favicon */
} current_search_provider;
-static struct content *search_ico = NULL;
+static hlcache_handle *search_ico = NULL;
char *search_engines_file_location;
char *search_default_ico_location;
+static nserror search_web_ico_callback(hlcache_handle *ico,
+ const hlcache_event *event, void *pw);
+
/**
* creates a new browser window according to the search term
* \param searchterm such as "my search term"
@@ -205,7 +207,8 @@ char *search_web_get_url(const char *encsearchterm)
void search_web_retrieve_ico(bool localdefault)
{
char *url;
- struct content *icocontent;
+ nserror error;
+
if (localdefault) {
if (search_default_ico_location == NULL)
return;
@@ -221,26 +224,17 @@ void search_web_retrieve_ico(bool localdefault)
url = search_web_ico_name();
}
- icocontent = NULL;
if (url == NULL) {
warn_user(messages_get("NoMemory"), 0);
return;
}
- icocontent = fetchcache(url, search_web_ico_callback,
- 0, 0, 20, 20, true, 0,
- 0, false, false);
- free(url);
- if (icocontent == NULL)
- return;
-
- fetchcache_go(icocontent, 0, search_web_ico_callback,
- 0, 0, 20, 20,
- 0, 0, false, 0);
- if (icocontent == NULL)
- LOG(("web search ico loading delayed"));
- else
- search_ico = icocontent;
+ error = hlcache_handle_retrieve(url, 0, NULL, NULL, 20, 20,
+ search_web_ico_callback, NULL, NULL, &search_ico);
+ if (error != NSERROR_OK)
+ search_ico = NULL;
+
+ free(url);
}
/**
@@ -249,7 +243,7 @@ void search_web_retrieve_ico(bool localdefault)
* responsibility
*/
-struct content *search_web_ico(void)
+hlcache_handle *search_web_ico(void)
{
return search_ico;
}
@@ -259,20 +253,18 @@ struct content *search_web_ico(void)
* else retry default from local file system
*/
-void search_web_ico_callback(content_msg msg, struct content *ico,
- intptr_t p1, intptr_t p2, union content_msg_data data)
+nserror search_web_ico_callback(hlcache_handle *ico,
+ const hlcache_event *event, void *pw)
{
-
- switch (msg) {
+ switch (event->type) {
case CONTENT_MSG_LOADING:
case CONTENT_MSG_READY:
break;
case CONTENT_MSG_DONE:
- LOG(("got favicon '%s'", ico->url));
+ LOG(("got favicon '%s'", content_get_url(ico)));
#ifdef WITH_BMP
- if (ico->type == CONTENT_ICO) {
- search_ico = ico; /* cache */
+ if (content_get_type(ico) == CONTENT_ICO) {
gui_window_set_search_ico(search_ico);
} else
#endif
@@ -281,20 +273,20 @@ void search_web_ico_callback(content_msg msg, struct content *ico,
}
break;
- case CONTENT_MSG_LAUNCH:
case CONTENT_MSG_ERROR:
- LOG(("favicon %s error: %s", ico->url, data.error));
- ico = 0;
+ LOG(("favicon %s error: %s",
+ content_get_url(ico), event->data.error));
+ hlcache_handle_release(search_ico);
+ search_ico = NULL;
search_web_retrieve_ico(true);
break;
case CONTENT_MSG_STATUS:
- case CONTENT_MSG_NEWPTR:
- case CONTENT_MSG_AUTH:
- case CONTENT_MSG_SSL:
break;
default:
assert(0);
}
+
+ return NSERROR_OK;
}
diff --git a/desktop/searchweb.h b/desktop/searchweb.h
index f8dcb9db0..6cc23036a 100644
--- a/desktop/searchweb.h
+++ b/desktop/searchweb.h
@@ -20,9 +20,11 @@
#define _NETSURF_DESKTOP_SEARCH_WEB_H_
#include <ctype.h>
+#include <stdbool.h>
#include <string.h>
-#include "content/content.h"
-#include "desktop/browser.h"
+
+struct browser_window;
+struct hlcache_handle;
extern char *search_engines_file_location;
extern char *search_default_ico_location;
@@ -71,9 +73,6 @@ bool search_is_url(const char *url);
void search_web_retrieve_ico(bool localdefault);
-struct content *search_web_ico(void);
-
-void search_web_ico_callback(content_msg msg, struct content *ico,
- intptr_t p1, intptr_t p2, union content_msg_data data);
+struct hlcache_handle *search_web_ico(void);
#endif
diff --git a/desktop/selection.c b/desktop/selection.c
index 93f5cc1a3..821dbb9bc 100644
--- a/desktop/selection.c
+++ b/desktop/selection.c
@@ -27,6 +27,7 @@
#include <stdbool.h>
#include <string.h>
+#include "content/hlcache.h"
#include "desktop/gui.h"
#include "desktop/plotters.h"
#include "desktop/save_text.h"
@@ -155,8 +156,8 @@ void selection_reinit(struct selection *s, struct box *root)
s->max_idx = selection_label_subtree(root, root_idx);
}
else {
- struct content *c = s->bw->current_content;
- if (c && c->type == CONTENT_TEXTPLAIN)
+ hlcache_handle *c = s->bw->current_content;
+ if (c && content_get_type(c) == CONTENT_TEXTPLAIN)
s->max_idx = textplain_size(c);
else
s->max_idx = 0;
@@ -560,7 +561,7 @@ bool traverse_tree(struct box *box, unsigned start_idx, unsigned end_idx,
bool selection_traverse(struct selection *s, seln_traverse_handler handler,
void *handle)
{
- struct content *c;
+ hlcache_handle *c;
save_text_whitespace before = WHITESPACE_NONE;
bool first = true;
const char *text;
@@ -664,8 +665,9 @@ void selection_redraw(struct selection *s, unsigned start_idx, unsigned end_idx)
return;
}
else {
- struct content *c = s->bw->current_content;
- if (c && c->type == CONTENT_TEXTPLAIN && end_idx > start_idx) {
+ hlcache_handle *c = s->bw->current_content;
+ if (c && content_get_type(c) == CONTENT_TEXTPLAIN &&
+ end_idx > start_idx) {
textplain_coords_from_range(c, start_idx,
end_idx, &rdw.r);
rdw.inited = true;
@@ -952,7 +954,7 @@ bool save_handler(const char *text, size_t length, struct box *box,
bool selection_save_text(struct selection *s, const char *path)
{
- struct content *c = s->bw->current_content;
+ hlcache_handle *c = s->bw->current_content;
struct save_text_state sv = { NULL, 0, 0 };
utf8_convert_ret ret;
char *result;
diff --git a/desktop/textinput.c b/desktop/textinput.c
index 5083d8c78..7739140fb 100644
--- a/desktop/textinput.c
+++ b/desktop/textinput.c
@@ -2091,11 +2091,14 @@ bool textarea_cut(struct browser_window *bw,
void textarea_reflow(struct browser_window *bw, struct box *textarea,
struct box *inline_container)
{
+ struct content *c = hlcache_handle_get_content(bw->current_content);
int width = textarea->width;
int height = textarea->height;
+
+ assert(c != NULL);
+
if (!layout_inline_container(inline_container, width,
- textarea, 0, 0,
- bw->current_content))
+ textarea, 0, 0, c))
warn_user("NoMemory", 0);
textarea->width = width;
textarea->height = height;
diff --git a/framebuffer/gui.c b/framebuffer/gui.c
index 05c363c0b..d0f0490fb 100644
--- a/framebuffer/gui.c
+++ b/framebuffer/gui.c
@@ -70,15 +70,6 @@ struct gui_window *window_list = NULL;
bool redraws_pending = false;
-
-#ifndef MIN
-#define MIN(a,b) (((a) < (b)) ? (a) : (b))
-#endif
-
-#ifndef MAX
-#define MAX(a,b) (((a) > (b)) ? (a) : (b))
-#endif
-
/* private data for browser user widget */
struct browser_widget_s {
struct browser_window *bw; /**< The browser window connected to this gui window */
@@ -102,10 +93,10 @@ fb_queue_redraw(struct fbtk_widget_s *widget, int x0, int y0, int x1, int y1)
{
struct browser_widget_s *bwidget = fbtk_get_userpw(widget);
- bwidget->redraw_box.x0 = MIN(bwidget->redraw_box.x0, x0);
- bwidget->redraw_box.y0 = MIN(bwidget->redraw_box.y0, y0);
- bwidget->redraw_box.x1 = MAX(bwidget->redraw_box.x1, x1);
- bwidget->redraw_box.y1 = MAX(bwidget->redraw_box.y1, y1);
+ bwidget->redraw_box.x0 = min(bwidget->redraw_box.x0, x0);
+ bwidget->redraw_box.y0 = min(bwidget->redraw_box.y0, y0);
+ bwidget->redraw_box.x1 = max(bwidget->redraw_box.x1, x1);
+ bwidget->redraw_box.y1 = max(bwidget->redraw_box.y1, y1);
if (fbtk_clip_to_widget(widget, &bwidget->redraw_box)) {
bwidget->redraw_required = true;
@@ -121,7 +112,6 @@ static void fb_pan(fbtk_widget_t *widget,
struct browser_widget_s *bwidget,
struct browser_window *bw)
{
- struct content *c;
int x;
int y;
int width;
@@ -129,13 +119,11 @@ static void fb_pan(fbtk_widget_t *widget,
nsfb_bbox_t srcbox;
nsfb_bbox_t dstbox;
- c = bw->current_content;
-
- if ((!c) || (c->locked))
- return;
-
nsfb_t *nsfb = fbtk_get_nsfb(widget);
+ int content_height = content_get_height(bw->current_content);
+ int content_width = content_get_width(bw->current_content);
+
height = fbtk_get_height(widget);
width = fbtk_get_width(widget);
x = fbtk_get_x(widget);
@@ -146,16 +134,16 @@ static void fb_pan(fbtk_widget_t *widget,
bwidget->pany = - bwidget->scrolly;
/* do not pan off the bottom of the content */
- if ((bwidget->scrolly + bwidget->pany) > (c->height - height))
- bwidget->pany = (c->height - height) - bwidget->scrolly;
+ if ((bwidget->scrolly + bwidget->pany) > (content_height - height))
+ bwidget->pany = (content_height - height) - bwidget->scrolly;
/* dont pan off the left */
if ((bwidget->scrollx + bwidget->panx) < 0)
bwidget->panx = - bwidget->scrollx;
/* do not pan off the right of the content */
- if ((bwidget->scrollx + bwidget->panx) > (c->width - width))
- bwidget->panx = (c->width - width) - bwidget->scrollx;
+ if ((bwidget->scrollx + bwidget->panx) > (content_width - width))
+ bwidget->panx = (content_width - width) - bwidget->scrollx;
LOG(("panning %d, %d",bwidget->panx, bwidget->pany));
@@ -268,16 +256,11 @@ static void fb_redraw(fbtk_widget_t *widget,
struct browser_widget_s *bwidget,
struct browser_window *bw)
{
- struct content *c;
int x;
int y;
int width;
int height;
- c = bw->current_content;
-
- if ((!c) || (c->locked))
- return;
LOG(("redraw box %d,%d to %d,%d",bwidget->redraw_box.x0,bwidget->redraw_box.y0, bwidget->redraw_box.x1, bwidget->redraw_box.y1));
@@ -292,13 +275,11 @@ static void fb_redraw(fbtk_widget_t *widget,
bwidget->redraw_box.x0 += x;
bwidget->redraw_box.x1 += x;
-
-
nsfb_claim(fbtk_get_nsfb(widget), &bwidget->redraw_box);
/* redraw bounding box is relative to window */
current_redraw_browser = bw;
- content_redraw(c,
+ content_redraw(bw->current_content,
x - bwidget->scrollx, y - bwidget->scrolly,
width, height,
bwidget->redraw_box.x0, bwidget->redraw_box.y0,
@@ -328,9 +309,9 @@ fb_browser_window_redraw(fbtk_widget_t *root, fbtk_widget_t *widget, void *pw)
if (bwidget->pan_required) {
int pos;
fb_pan(widget, bwidget, gw->bw);
- pos = (bwidget->scrollx * 100) / gw->bw->current_content->width;
+ pos = (bwidget->scrollx * 100) / content_get_width(gw->bw->current_content);
fbtk_set_scroll_pos(gw->hscroll, pos);
- pos = (bwidget->scrolly * 100) / gw->bw->current_content->height;
+ pos = (bwidget->scrolly * 100) / content_get_height(gw->bw->current_content);
fbtk_set_scroll_pos(gw->vscroll, pos);
}
@@ -409,11 +390,23 @@ static bool process_cmdline(int argc, char** argv)
return true;
}
-/** Normal entry point from OS */
+/** Entry point from OS.
+ *
+ * /param argc The number of arguments in the string vector.
+ * /param argv The argument string vector.
+ * /return The return code to the OS
+ */
int main(int argc, char** argv)
{
setbuf(stderr, NULL);
- return netsurf_main(argc, argv);
+
+ netsurf_init(argc, argv);
+
+ netsurf_main_loop();
+
+ netsurf_exit();
+
+ return 0;
}
void gui_init(int argc, char** argv)
@@ -1176,15 +1169,17 @@ void gui_window_get_dimensions(struct gui_window *g, int *width, int *height,
*height = fbtk_get_height(g->browser);
}
-void gui_window_update_extent(struct gui_window *g)
+void gui_window_update_extent(struct gui_window *gw)
{
int pct;
- pct = (fbtk_get_width(g->browser) * 100) / g->bw->current_content->width;
- fbtk_set_scroll(g->hscroll, pct);
+ pct = (fbtk_get_width(gw->browser) * 100) /
+ content_get_width(gw->bw->current_content);
+ fbtk_set_scroll(gw->hscroll, pct);
- pct = (fbtk_get_height(g->browser) * 100) / g->bw->current_content->height;
- fbtk_set_scroll(g->vscroll, pct);
+ pct = (fbtk_get_height(gw->browser) * 100) /
+ content_get_height(gw->bw->current_content);
+ fbtk_set_scroll(gw->vscroll, pct);
}
@@ -1328,7 +1323,8 @@ bool gui_window_frame_resize_start(struct gui_window *g)
return true;
}
-void gui_window_save_as_link(struct gui_window *g, struct content *c)
+void
+gui_window_save_link(struct gui_window *g, const char *url, const char *title)
{
}
@@ -1340,7 +1336,8 @@ void gui_window_set_scale(struct gui_window *g, float scale)
/**
* set favicon
*/
-void gui_window_set_icon(struct gui_window *g, struct content *icon)
+void
+gui_window_set_icon(struct gui_window *g, hlcache_handle *icon)
{
}
@@ -1349,7 +1346,8 @@ void gui_window_set_icon(struct gui_window *g, struct content *icon)
* \param ico may be NULL for local calls; then access current cache from
* search_web_ico()
*/
-void gui_window_set_search_ico(struct content *ico)
+void
+gui_window_set_search_ico(hlcache_handle *ico)
{
}
@@ -1374,8 +1372,8 @@ void gui_download_window_done(struct gui_download_window *dw)
{
}
-void gui_drag_save_object(gui_save_type type, struct content *c,
- struct gui_window *g)
+void gui_drag_save_object(gui_save_type type, hlcache_handle *c,
+ struct gui_window *w)
{
}
@@ -1420,7 +1418,7 @@ void gui_launch_url(const char *url)
{
}
-void gui_cert_verify(struct browser_window *bw, struct content *c,
+void gui_cert_verify(struct browser_window *bw, struct hlcache_handle *c,
const struct ssl_cert_info *certs, unsigned long num)
{
}
diff --git a/framebuffer/hotlist.c b/framebuffer/hotlist.c
index 48df23bb4..727200fe3 100644
--- a/framebuffer/hotlist.c
+++ b/framebuffer/hotlist.c
@@ -18,6 +18,6 @@
#include "desktop/browser.h"
-void hotlist_visited(struct content *content)
+void hotlist_visited(struct hlcache_handle *content)
{
}
diff --git a/framebuffer/login.c b/framebuffer/login.c
index 306de8459..7cd1cab2e 100644
--- a/framebuffer/login.c
+++ b/framebuffer/login.c
@@ -18,7 +18,7 @@
#include "desktop/401login.h"
-void gui_401login_open(struct browser_window *bw, struct content *c,
+void gui_401login_open(struct browser_window *bw, struct hlcache_handle *c,
const char *realm)
{
}
diff --git a/framebuffer/thumbnail.c b/framebuffer/thumbnail.c
index 5ab7ed431..81419d282 100644
--- a/framebuffer/thumbnail.c
+++ b/framebuffer/thumbnail.c
@@ -18,7 +18,7 @@
#include "desktop/browser.h"
-bool thumbnail_create(struct content *content, struct bitmap *bitmap,
+bool thumbnail_create(struct hlcache_handle *content, struct bitmap *bitmap,
const char *url)
{
return false;
diff --git a/gtk/dialogs/gtk_options.c b/gtk/dialogs/gtk_options.c
index eb7429223..b883195b4 100644
--- a/gtk/dialogs/gtk_options.c
+++ b/gtk/dialogs/gtk_options.c
@@ -570,7 +570,7 @@ ENTRY_CHANGED(entryHomePageURL, option_homepage_url)
END_HANDLER
BUTTON_CLICKED(setCurrentPage)
- const gchar *url = current_browser->current_content->url;
+ const gchar *url = content_get_url(current_browser->current_content);
gtk_entry_set_text(GTK_ENTRY(entryHomePageURL), url);
option_homepage_url =
strdup(gtk_entry_get_text(GTK_ENTRY(entryHomePageURL)));
diff --git a/gtk/dialogs/gtk_source.c b/gtk/dialogs/gtk_source.c
index 7ee3ef849..842d4c4ef 100644
--- a/gtk/dialogs/gtk_source.c
+++ b/gtk/dialogs/gtk_source.c
@@ -107,7 +107,7 @@ void nsgtk_source_dialog_init(GtkWindow *parent, struct browser_window *bw)
{
char glade_Location[strlen(res_dir_location) + SLEN("source.glade")
+ 1];
- if (bw->current_content->type != CONTENT_HTML)
+ if (content_get_type(bw->current_content) != CONTENT_HTML)
return;
if (option_source_tab) {
@@ -121,12 +121,17 @@ void nsgtk_source_dialog_init(GtkWindow *parent, struct browser_window *bw)
LOG(("error loading glade tree"));
}
+ const char *source_data;
+ unsigned long source_size;
char *data = NULL;
+ source_data = content_get_source_data(bw->current_content,
+ &source_size);
+
utf8_convert_ret r = utf8_from_enc(
- bw->current_content->source_data,
- bw->current_content->data.html.encoding,
- bw->current_content->source_size,
+ source_data,
+ html_get_encoding(bw->current_content),
+ source_size,
&data);
if (r == UTF8_CONVERT_NOMEM) {
warn_user("NoMemory",0);
@@ -160,7 +165,7 @@ void nsgtk_source_dialog_init(GtkWindow *parent, struct browser_window *bw)
return;
}
- thiswindow->url = strdup(bw->current_content->url);
+ thiswindow->url = strdup(content_get_url(bw->current_content));
if (thiswindow->url == NULL) {
free(thiswindow);
free(data);
@@ -173,8 +178,8 @@ void nsgtk_source_dialog_init(GtkWindow *parent, struct browser_window *bw)
thiswindow->sourcewindow = wndSource;
thiswindow->bw = bw;
- char title[strlen(bw->current_content->url) + SLEN("Source of ") + 1];
- sprintf(title, "Source of %s", bw->current_content->url);
+ char title[strlen(thiswindow->url) + SLEN("Source of ") + 1];
+ sprintf(title, "Source of %s", thiswindow->url);
thiswindow->next = nsgtk_source_list;
thiswindow->prev = NULL;
@@ -209,11 +214,17 @@ void nsgtk_source_dialog_init(GtkWindow *parent, struct browser_window *bw)
}
void nsgtk_source_tab_init(GtkWindow *parent, struct browser_window *bw)
{
+ const char *source_data;
+ unsigned long source_size;
char *ndata = 0;
+
+ source_data = content_get_source_data(bw->current_content,
+ &source_size);
+
utf8_convert_ret r = utf8_from_enc(
- bw->current_content->source_data,
- bw->current_content->data.html.encoding,
- bw->current_content->source_size,
+ source_data,
+ html_get_encoding(bw->current_content),
+ source_size,
&ndata);
if (r == UTF8_CONVERT_NOMEM) {
warn_user("NoMemory",0);
@@ -245,18 +256,9 @@ void nsgtk_source_tab_init(GtkWindow *parent, struct browser_window *bw)
warn_user(messages_get("NoMemory"), 0);
return;
}
- struct browser_window *newbw = browser_window_create(fileurl, bw,
- NULL, false, true);
+ /* Open tab */
+ browser_window_create(fileurl, bw, NULL, false, true);
free(fileurl);
- if (newbw->current_content) {
- newbw->current_content->title = malloc(
- strlen(bw->current_content->url) +
- SLEN("source of ") + 1);
- if (newbw->current_content->title == NULL)
- return;
- sprintf(newbw->current_content->title, "source of %s",
- bw->current_content->url);
- }
}
diff --git a/gtk/gtk_gui.c b/gtk/gtk_gui.c
index 0251e173f..da8574a79 100644
--- a/gtk/gtk_gui.c
+++ b/gtk/gtk_gui.c
@@ -42,6 +42,7 @@
#include "content/content.h"
#include "content/fetch.h"
#include "content/fetchers/fetch_curl.h"
+#include "content/hlcache.h"
#include "content/urldb.h"
#include "desktop/401login.h"
#include "desktop/browser.h"
@@ -122,7 +123,14 @@ int main(int argc, char** argv)
setbuf(stderr, NULL);
- return netsurf_main(argc, argv);
+ /* initialise netsurf */
+ netsurf_init(argc, argv);
+
+ netsurf_main_loop();
+
+ netsurf_exit();
+
+ return 0;
}
@@ -599,7 +607,8 @@ void gui_create_form_select_menu(struct browser_window *bw,
}
-void gui_window_save_as_link(struct gui_window *g, struct content *c)
+void gui_window_save_link(struct gui_window *g, const char *url,
+ const char *title)
{
}
@@ -630,12 +639,11 @@ void die(const char * const error)
}
-void hotlist_visited(struct content *content)
+void hotlist_visited(hlcache_handle *content)
{
}
-
-void gui_cert_verify(struct browser_window *bw, struct content *c,
+void gui_cert_verify(struct browser_window *bw, hlcache_handle *c,
const struct ssl_cert_info *certs, unsigned long num)
{
GladeXML *x = glade_xml_new(glade_ssl_file_location, NULL, NULL);
@@ -644,7 +652,7 @@ void gui_cert_verify(struct browser_window *bw, struct content *c,
void **session = calloc(sizeof(void *), 4);
session[0] = bw;
- session[1] = strdup(c->url);
+ session[1] = strdup(content_get_url(c));
session[2] = x;
session[3] = wnd;
diff --git a/gtk/gtk_login.c b/gtk/gtk_login.c
index 3bb11a66b..ed6f92407 100644
--- a/gtk/gtk_login.c
+++ b/gtk/gtk_login.c
@@ -25,6 +25,7 @@
#include "utils/log.h"
#include "gtk/gtk_gui.h"
#include "content/content.h"
+#include "content/hlcache.h"
#include "content/urldb.h"
#include "desktop/browser.h"
#include "desktop/401login.h"
@@ -51,16 +52,16 @@ static void nsgtk_login_next(GtkWidget *w, gpointer data);
static void nsgtk_login_ok_clicked(GtkButton *w, gpointer data);
static void nsgtk_login_cancel_clicked(GtkButton *w, gpointer data);
-void gui_401login_open(struct browser_window *bw, struct content *c,
+void gui_401login_open(struct browser_window *bw, hlcache_handle *c,
const char *realm)
{
char *host;
url_func_result res;
- res = url_host(c->url, &host);
+ res = url_host(content_get_url(c), &host);
assert(res == URL_FUNC_OK);
- create_login_window(bw, host, realm, c->url);
+ create_login_window(bw, host, realm, content_get_url(c));
free(host);
}
diff --git a/gtk/gtk_print.c b/gtk/gtk_print.c
index 98b43cb89..f08880157 100644
--- a/gtk/gtk_print.c
+++ b/gtk/gtk_print.c
@@ -32,6 +32,7 @@
#include <gtk/gtk.h>
#include "content/content.h"
+#include "content/hlcache.h"
#include "desktop/options.h"
#include "desktop/plotters.h"
#include "desktop/print.h"
@@ -48,7 +49,7 @@
/* Globals */
cairo_t *gtk_print_current_cr;
static struct print_settings* settings;
-struct content *content_to_print;
+hlcache_handle *content_to_print;
static GdkRectangle cliprect;
static inline void nsgtk_print_set_colour(colour c)
diff --git a/gtk/gtk_print.h b/gtk/gtk_print.h
index d2b89b92d..d44fad31f 100644
--- a/gtk/gtk_print.h
+++ b/gtk/gtk_print.h
@@ -26,9 +26,11 @@
#include <gtk/gtk.h>
+struct hlcache_handle;
+
extern cairo_t *gtk_print_current_cr;
-extern struct content *content_to_print;
+extern struct hlcache_handle *content_to_print;
/*handlers for signals from the GTK print operation*/
diff --git a/gtk/gtk_scaffolding.c b/gtk/gtk_scaffolding.c
index f8ac3daa3..381711377 100644
--- a/gtk/gtk_scaffolding.c
+++ b/gtk/gtk_scaffolding.c
@@ -30,6 +30,7 @@
#include <libxml/debugXML.h>
#include "gtk/gtk_scaffolding.h"
#include "content/content.h"
+#include "content/hlcache.h"
#include "css/utils.h"
#include "desktop/browser.h"
#include "desktop/history_core.h"
@@ -271,8 +272,10 @@ void nsgtk_window_update_back_forward(struct gtk_scaffolding *g)
nsgtk_scaffolding_set_sensitivity(g);
/* update the url bar, particularly necessary when tabbing */
- if (bw->current_content != NULL && bw->current_content->url != NULL)
- browser_window_refresh_url_bar(bw, bw->current_content->url,
+ if (bw->current_content != NULL &&
+ content_get_url(bw->current_content) != NULL)
+ browser_window_refresh_url_bar(bw,
+ content_get_url(bw->current_content),
bw->frag_id);
/* update the local history window, as well as queuing a redraw
@@ -493,8 +496,8 @@ MULTIHANDLER(savepage)
gtk_file_chooser_add_filter(GTK_FILE_CHOOSER(fc), filter);
gtk_file_chooser_set_filter(GTK_FILE_CHOOSER(fc), filter);
- res = url_nice(gui_window_get_browser_window(
- g->top_level)->current_content->url, &path, false);
+ res = url_nice(content_get_url(gui_window_get_browser_window(
+ g->top_level)->current_content), &path, false);
if (res != URL_FUNC_OK) {
path = strdup(messages_get("SaveText"));
if (path == NULL) {
@@ -549,7 +552,7 @@ MULTIHANDLER(pdf)
LOG(("Print preview (generating PDF) started."));
- res = url_nice(bw->current_content->url, &url_name, true);
+ res = url_nice(content_get_url(bw->current_content), &url_name, true);
if (res != URL_FUNC_OK) {
warn_user(messages_get(res == URL_FUNC_NOMEM ? "NoMemory"
: "URIError"), 0);
@@ -622,8 +625,8 @@ MULTIHANDLER(plaintext)
char *filename;
url_func_result res;
- res = url_nice(gui_window_get_browser_window(
- g->top_level)->current_content->url, &filename, false);
+ res = url_nice(content_get_url(gui_window_get_browser_window(
+ g->top_level)->current_content), &filename, false);
if (res != URL_FUNC_OK) {
filename = strdup(messages_get("SaveText"));
if (filename == NULL) {
@@ -710,7 +713,7 @@ MULTIHANDLER(print)
G_CALLBACK(gtk_print_signal_draw_page), NULL);
g_signal_connect(print_op, "end_print",
G_CALLBACK(gtk_print_signal_end_print), settings);
- if (bw->current_content->type != CONTENT_TEXTPLAIN)
+ if (content_get_type(bw->current_content) != CONTENT_TEXTPLAIN)
res = gtk_print_operation_run(print_op,
GTK_PRINT_OPERATION_ACTION_PRINT_DIALOG,
g->window,
@@ -762,7 +765,7 @@ MENUHANDLER(savelink)
return FALSE;
browser_window_download(bw, current_menu_link_box->href,
- bw->current_content->url);
+ content_get_url(bw->current_content));
return TRUE;
}
@@ -1125,11 +1128,11 @@ MULTIHANDLER(saveboxtree)
struct browser_window *bw;
bw = gui_window_get_browser_window(g->top_level);
- if (bw->current_content &&
- bw->current_content->type ==
+ if (bw->current_content &&
+ content_get_type(bw->current_content) ==
CONTENT_HTML) {
box_dump(fh,
- bw->current_content->data.html.layout,
+ html_get_box_tree(bw->current_content),
0);
}
@@ -1174,12 +1177,11 @@ MULTIHANDLER(savedomtree)
struct browser_window *bw;
bw = gui_window_get_browser_window(g->top_level);
- if (bw->current_content &&
- bw->current_content->type ==
+ if (bw->current_content &&
+ content_get_type(bw->current_content) ==
CONTENT_HTML) {
xmlDebugDumpDocument(fh,
- bw->current_content->
- data.html.document);
+ html_get_document(bw->current_content));
}
fclose(fh);
@@ -1871,80 +1873,93 @@ void gui_window_stop_throbber(struct gui_window* _g)
/**
* set favicon
*/
-void gui_window_set_icon(struct gui_window *_g, struct content *icon)
+void gui_window_set_icon(struct gui_window *_g, hlcache_handle *icon)
{
struct gtk_scaffolding *g = nsgtk_get_scaffold(_g);
- GtkImage *iconImage = NULL;
- if (g->icoFav != NULL)
- g_object_unref(g->icoFav);
+ struct bitmap *icon_bitmap;
+ GtkImage *iconImage;
+
+ if (icon == NULL)
+ return;
+
#ifdef WITH_BMP
- if ((icon != NULL) && (icon->type == CONTENT_ICO)) {
+ if (content_get_type(icon) == CONTENT_ICO)
nsico_set_bitmap_from_size(icon, 16, 16);
- }
#endif
- if ((icon != NULL) && (icon->bitmap != NULL)) {
- GdkPixbuf *pb = gtk_bitmap_get_primary(icon->bitmap);
- if ((pb != NULL) && (gdk_pixbuf_get_width(pb) > 0) &&
- (gdk_pixbuf_get_height(pb) > 0)) {
- pb = gdk_pixbuf_scale_simple(pb, 16, 16,
- GDK_INTERP_HYPER);
- iconImage = GTK_IMAGE(
- gtk_image_new_from_pixbuf(pb));
- } else {
- iconImage = NULL;
- }
- }
- if (iconImage == NULL) {
- char imagepath[strlen(res_dir_location) + SLEN("favicon.png")
- + 1];
+
+ icon_bitmap = content_get_bitmap(icon);
+ if (icon_bitmap == NULL)
+ return;
+
+ GdkPixbuf *pb = gtk_bitmap_get_primary(icon_bitmap);
+ if (pb != NULL && gdk_pixbuf_get_width(pb) > 0 &&
+ gdk_pixbuf_get_height(pb) > 0) {
+ pb = gdk_pixbuf_scale_simple(pb, 16, 16, GDK_INTERP_HYPER);
+ iconImage = GTK_IMAGE(gtk_image_new_from_pixbuf(pb));
+ } else {
+ /** \todo Does pb need cleaning up? */
+ char imagepath[strlen(res_dir_location) +
+ SLEN("favicon.png") + 1];
sprintf(imagepath, "%sfavicon.png", res_dir_location);
iconImage = GTK_IMAGE(gtk_image_new_from_file(imagepath));
}
+
+ if (iconImage == NULL)
+ return;
+
+ if (g->icoFav != NULL)
+ g_object_unref(g->icoFav);
g->icoFav = iconImage;
- sexy_icon_entry_set_icon(SEXY_ICON_ENTRY(g->url_bar),
+
+ sexy_icon_entry_set_icon(SEXY_ICON_ENTRY(g->url_bar),
SEXY_ICON_ENTRY_PRIMARY, GTK_IMAGE(g->icoFav));
gtk_widget_show_all(GTK_WIDGET(g->buttons[URL_BAR_ITEM]->button));
}
-void gui_window_set_search_ico(struct content *ico)
+void gui_window_set_search_ico(hlcache_handle *ico)
{
- GdkPixbuf *pbico = NULL;
- GtkImage *searchico = NULL;
+ GdkPixbuf *pbico;
+ GtkImage *searchico;
+ struct bitmap *ico_bitmap;
nsgtk_scaffolding *current;
- if (ico == NULL)
- ico = search_web_ico();
+
+ if (ico == NULL && (ico = search_web_ico()) == NULL)
+ return;
#ifdef WITH_BMP
- if ((ico != NULL) && (ico->type == CONTENT_ICO)) {
+ if (content_get_type(ico) == CONTENT_ICO)
nsico_set_bitmap_from_size(ico, 20, 20);
- }
#endif
- if ((ico != NULL) && (ico->bitmap != NULL)) {
- pbico = gtk_bitmap_get_primary(ico->bitmap);
- if ((pbico != NULL) && (gdk_pixbuf_get_width(pbico) > 0) &&
- (gdk_pixbuf_get_height(pbico) > 0)) {
- pbico = gdk_pixbuf_scale_simple(pbico, 20, 20,
- GDK_INTERP_HYPER);
- current = scaf_list;
- searchico = GTK_IMAGE(
- gtk_image_new_from_pixbuf(pbico));
- } else {
- searchico = NULL;
- }
+ ico_bitmap = content_get_bitmap(ico);
+ if (ico_bitmap == NULL)
+ return;
+
+ pbico = gtk_bitmap_get_primary(ico_bitmap);
+ if (pbico != NULL && gdk_pixbuf_get_width(pbico) > 0 &&
+ gdk_pixbuf_get_height(pbico) > 0) {
+ pbico = gdk_pixbuf_scale_simple(pbico, 20, 20,
+ GDK_INTERP_HYPER);
+ searchico = GTK_IMAGE(gtk_image_new_from_pixbuf(pbico));
+ } else {
+ /** \todo Does pbico need cleaning up? */
+ return;
}
- /* add ico to toolbar */
- current = scaf_list;
- while (current) {
+
+ /* add ico to each window's toolbar */
+ for (current = scaf_list; current != NULL; current = current->next) {
if (searchico != NULL) {
+ /** \todo Are we leaking webSearchIco here? */
current->webSearchIco = searchico;
sexy_icon_entry_set_icon(SEXY_ICON_ENTRY(
current->webSearchEntry),
SEXY_ICON_ENTRY_PRIMARY,
current->webSearchIco);
}
- searchico = GTK_IMAGE(gtk_image_new_from_pixbuf(pbico));
- current = current->next;
+ if (pbico != NULL)
+ searchico = GTK_IMAGE(gtk_image_new_from_pixbuf(pbico));
+ else
+ searchico = NULL;
}
}
@@ -2117,33 +2132,26 @@ void nsgtk_scaffolding_set_top_level (struct gui_window *gw)
nsgtk_get_scaffold(gw)->top_level = gw;
struct browser_window *bw = gui_window_get_browser_window(gw);
+ assert(bw != NULL);
+
/* Synchronise the history (will also update the URL bar) */
nsgtk_window_update_back_forward(nsgtk_get_scaffold(gw));
+
/* clear effects of potential searches */
- if ((bw != NULL) && (bw->search_context != NULL))
+ if (bw->search_context != NULL)
search_destroy_context(bw->search_context);
+
nsgtk_search_set_forward_state(true, bw);
nsgtk_search_set_back_state(true, bw);
/* Ensure the window's title bar as well as favicon are updated */
- if (gui_window_get_browser_window(gw) != NULL &&
- gui_window_get_browser_window(gw)->current_content
- != NULL) {
- if (gui_window_get_browser_window(gw)->current_content->title
- != NULL) {
- gui_window_set_title(gw,
- gui_window_get_browser_window(gw)->
- current_content->title);
- } else {
- gui_window_set_title(gw,
- gui_window_get_browser_window(gw)->
- current_content->url);
- }
- if (gui_window_get_browser_window(gw)->current_content->type
- == CONTENT_HTML)
+ if (bw->current_content != NULL) {
+ gui_window_set_title(gw,
+ content_get_title(bw->current_content));
+
+ if (content_get_type(bw->current_content) == CONTENT_HTML)
gui_window_set_icon(gw,
- gui_window_get_browser_window(gw)->
- current_content->data.html.favicon);
+ html_get_favicon(bw->current_content));
}
}
@@ -2287,7 +2295,8 @@ static guint nsgtk_scaffolding_update_link_operations_sensitivity(
struct browser_window *bw = gui_window_get_browser_window(g->top_level);
current_menu_link_box = NULL;
- if (bw->current_content && bw->current_content->type == CONTENT_HTML) {
+ if (bw->current_content &&
+ content_get_type(bw->current_content) == CONTENT_HTML) {
current_menu_link_box = box_href_at_point(bw->current_content,
x, y);
}
diff --git a/gtk/gtk_search.c b/gtk/gtk_search.c
index bb5d0138c..30075be02 100644
--- a/gtk/gtk_search.c
+++ b/gtk/gtk_search.c
@@ -28,6 +28,7 @@
#include "gtk/gtk_window.h"
#include "utils/config.h"
#include "content/content.h"
+#include "content/hlcache.h"
#include "desktop/browser.h"
#include "desktop/gui.h"
#include "desktop/search.h"
@@ -99,7 +100,7 @@ gboolean nsgtk_search_back_button_clicked(GtkWidget *widget, gpointer data)
void nsgtk_search_init(struct gtk_scaffolding *g)
{
- struct content *c;
+ hlcache_handle *c;
assert(gui_window_get_browser_window(nsgtk_scaffolding_top_level(g))
!= NULL);
@@ -107,7 +108,8 @@ void nsgtk_search_init(struct gtk_scaffolding *g)
c = gui_window_get_browser_window(nsgtk_scaffolding_top_level(g))->
current_content;
- if ((!c) || (c->type != CONTENT_HTML && c->type != CONTENT_TEXTPLAIN))
+ if ((!c) || (content_get_type(c) != CONTENT_HTML &&
+ content_get_type(c) != CONTENT_TEXTPLAIN))
return;
}
diff --git a/gtk/gtk_theme.c b/gtk/gtk_theme.c
index 146d9f158..1995a3774 100644
--- a/gtk/gtk_theme.c
+++ b/gtk/gtk_theme.c
@@ -22,6 +22,7 @@
#include <unistd.h>
#include "content/content.h"
#include "content/content_type.h"
+#include "content/hlcache.h"
#include "gtk/gtk_gui.h"
#include "gtk/gtk_scaffolding.h"
#include "gtk/gtk_menu.h"
@@ -62,10 +63,10 @@ static void nsgtk_theme_cache_searchimage(nsgtk_search_buttons i,
const char *filename, const char *path);
#ifdef WITH_THEME_INSTALL
-static struct content *theme_install_content = NULL;
+static hlcache_handle *theme_install_content = NULL;
-static void theme_install_callback(content_msg msg, struct content *c,
- intptr_t p1, intptr_t p2, union content_msg_data data);
+static void theme_install_callback(hlcache_handle *c, content_msg msg,
+ union content_msg_data data, void *pw);
static bool theme_install_read(const char *data, unsigned long len);
#endif
@@ -674,14 +675,14 @@ GtkImage *nsgtk_theme_image_default(nsgtk_toolbar_button i, GtkIconSize s)
/**
* when CONTENT_THEME needs handling call this function
*/
-void theme_install_start(struct content *c)
+void theme_install_start(hlcache_handle *c)
{
assert(c);
- assert(c->type == CONTENT_THEME);
+ assert(content_get_type(c) == CONTENT_THEME);
/* stop theme sitting in memory cache */
- c->fresh = false;
- if (!content_add_user(c, theme_install_callback, 0, 0)) {
+ content_invalidate_reuse_data(c);
+ if (!content_add_user(c, theme_install_callback, NULL)) {
warn_user("NoMemory", 0);
return;
}
@@ -692,17 +693,25 @@ void theme_install_start(struct content *c)
* Callback for fetchcache() for theme install fetches.
*/
-void theme_install_callback(content_msg msg, struct content *c,
- intptr_t p1, intptr_t p2, union content_msg_data data)
+void theme_install_callback(hlcache_handle *c, content_msg msg,
+ union content_msg_data data, void *pw)
{
switch (msg) {
case CONTENT_MSG_READY:
break;
case CONTENT_MSG_DONE:
+ {
+ const char *source_data;
+ unsigned long source_size;
+
theme_install_content = c;
- if (!theme_install_read(c->source_data, c->source_size))
+
+ source_data = content_get_source_data(c, &source_size);
+
+ if (!theme_install_read(source_data, source_size))
warn_user("ThemeInvalid", 0);
+ }
break;
case CONTENT_MSG_ERROR:
diff --git a/gtk/gtk_thumbnail.c b/gtk/gtk_thumbnail.c
index bbf7c4dd2..ec538da36 100644
--- a/gtk/gtk_thumbnail.c
+++ b/gtk/gtk_thumbnail.c
@@ -27,6 +27,7 @@
#include <assert.h>
#include <gtk/gtk.h>
#include "content/content.h"
+#include "content/hlcache.h"
#include "content/urldb.h"
#include "desktop/plotters.h"
#include "desktop/browser.h"
@@ -45,7 +46,7 @@
* \param bitmap the bitmap to draw to
* \param url the URL the thumnail belongs to, or NULL
*/
-bool thumbnail_create(struct content *content, struct bitmap *bitmap,
+bool thumbnail_create(hlcache_handle *content, struct bitmap *bitmap,
const char *url)
{
GdkPixbuf *pixbuf;
@@ -59,8 +60,8 @@ bool thumbnail_create(struct content *content, struct bitmap *bitmap,
assert(content);
assert(bitmap);
- cwidth = min(content->width, 1024);
- cheight = min(content->height, 768);
+ cwidth = min(content_get_width(content), 1024);
+ cheight = min(content_get_height(content), 768);
pixbuf = gtk_bitmap_get_primary(bitmap);
width = gdk_pixbuf_get_width(pixbuf);
@@ -68,7 +69,8 @@ bool thumbnail_create(struct content *content, struct bitmap *bitmap,
depth = (gdk_screen_get_system_visual(gdk_screen_get_default()))->depth;
LOG(("Trying to create a thumbnail pixmap for a content of %dx%d@%d",
- content->width, content->width, depth));
+ content_get_width(content), content_get_height(content),
+ depth));
pixmap = gdk_pixmap_new(NULL, cwidth, cwidth, depth);
@@ -87,7 +89,8 @@ bool thumbnail_create(struct content *content, struct bitmap *bitmap,
/* set the plotting functions up */
plot = nsgtk_plotters;
- nsgtk_plot_set_scale((double) cwidth / (double) content->width);
+ nsgtk_plot_set_scale((double) cwidth /
+ (double) content_get_width(content));
/* set to plot to pixmap */
current_drawable = pixmap;
@@ -98,8 +101,10 @@ bool thumbnail_create(struct content *content, struct bitmap *bitmap,
plot.rectangle(0, 0, cwidth, cwidth, plot_style_fill_white);
/* render the content */
- content_redraw(content, 0, 0, content->width, content->width,
- 0, 0, content->width, content->width, 1.0, 0xFFFFFF);
+ content_redraw(content, 0, 0, content_get_width(content),
+ content_get_width(content),
+ 0, 0, content_get_width(content),
+ content_get_width(content), 1.0, 0xFFFFFF);
/* resample the large plot down to the size of our thumbnail */
big = gdk_pixbuf_get_from_drawable(NULL, pixmap, NULL, 0, 0, 0, 0,
diff --git a/gtk/gtk_toolbar.c b/gtk/gtk_toolbar.c
index d3a5b52a1..b63163c90 100644
--- a/gtk/gtk_toolbar.c
+++ b/gtk/gtk_toolbar.c
@@ -412,15 +412,16 @@ void nsgtk_toolbar_close(nsgtk_scaffolding *g)
NSGTK_WINDOW_SIGNAL_REDRAW));
if ((gui_window_get_browser_window(nsgtk_scaffolding_top_level(
list))->current_content != NULL) &&
- (gui_window_get_browser_window(
+ (content_get_url(gui_window_get_browser_window(
nsgtk_scaffolding_top_level(list))->
- current_content->url != NULL))
+ current_content) != NULL))
browser_window_refresh_url_bar(
gui_window_get_browser_window(
nsgtk_scaffolding_top_level(list)),
+ content_get_url(
gui_window_get_browser_window(
nsgtk_scaffolding_top_level(list))->
- current_content->url,
+ current_content),
gui_window_get_browser_window(
nsgtk_scaffolding_top_level(list))->
frag_id);
diff --git a/gtk/gtk_window.c b/gtk/gtk_window.c
index 54e9c16a1..29ce2f431 100644
--- a/gtk/gtk_window.c
+++ b/gtk/gtk_window.c
@@ -19,6 +19,7 @@
#include <inttypes.h>
#include <string.h>
+#include "content/hlcache.h"
#include "gtk/gtk_window.h"
#include "desktop/browser.h"
#include "desktop/options.h"
@@ -144,7 +145,7 @@ struct gui_window *gui_create_browser_window(struct browser_window *bw,
struct gui_window *g; /**< what we're creating to return */
GtkPolicyType scrollpolicy;
- g = malloc(sizeof(*g));
+ g = calloc(1, sizeof(*g));
if (!g) {
warn_user("NoMemory", 0);
return 0;
@@ -349,7 +350,7 @@ gboolean nsgtk_window_expose_event(GtkWidget *widget,
GdkEventExpose *event, gpointer data)
{
struct gui_window *g = data;
- struct content *c;
+ hlcache_handle *c;
float scale = g->bw->scale;
assert(g);
@@ -366,7 +367,7 @@ gboolean nsgtk_window_expose_event(GtkWidget *widget,
return FALSE;
/* HTML rendering handles scale itself */
- if (c->type == CONTENT_HTML)
+ if (content_get_type(c) == CONTENT_HTML)
scale = 1;
current_widget = (GtkWidget *)g->drawing_area;
@@ -712,7 +713,7 @@ void gui_window_redraw_window(struct gui_window *g)
void gui_window_update_box(struct gui_window *g,
const union content_msg_data *data)
{
- struct content *c = g->bw->current_content;
+ hlcache_handle *c = g->bw->current_content;
if (c == NULL)
return;
@@ -788,8 +789,8 @@ void gui_window_update_extent(struct gui_window *g)
return;
gtk_widget_set_size_request(GTK_WIDGET(g->drawing_area),
- g->bw->current_content->width * g->bw->scale,
- g->bw->current_content->height * g->bw->scale);
+ content_get_width(g->bw->current_content) * g->bw->scale,
+ content_get_height(g->bw->current_content) * g->bw->scale);
gtk_widget_set_size_request(GTK_WIDGET(g->viewport), 0, 0);
@@ -958,7 +959,7 @@ bool gui_window_box_scroll_start(struct gui_window *g,
return true;
}
-void gui_drag_save_object(gui_save_type type, struct content *c,
+void gui_drag_save_object(gui_save_type type, hlcache_handle *c,
struct gui_window *g)
{
diff --git a/image/bmp.c b/image/bmp.c
index 2a27231ac..1774f945c 100644
--- a/image/bmp.c
+++ b/image/bmp.c
@@ -30,7 +30,7 @@
#include <stdlib.h>
#include <libnsbmp.h>
#include "utils/config.h"
-#include "content/content.h"
+#include "content/content_protected.h"
#include "desktop/plotters.h"
#include "image/bitmap.h"
#include "image/bmp.h"
@@ -49,8 +49,7 @@ bmp_bitmap_callback_vt bmp_bitmap_callbacks = {
.bitmap_get_bpp = bitmap_get_bpp
};
-bool nsbmp_create(struct content *c, struct content *parent,
- const char *params[])
+bool nsbmp_create(struct content *c, const struct http_parameter *params)
{
union content_msg_data msg_data;
@@ -71,12 +70,16 @@ bool nsbmp_convert(struct content *c, int iwidth, int iheight)
bmp_image *bmp;
union content_msg_data msg_data;
uint32_t swidth;
+ const char *data;
+ unsigned long size;
/* set the bmp data */
bmp = c->data.bmp.bmp;
+ data = content__get_source_data(c, &size);
+
/* analyse the BMP */
- res = bmp_analyse(bmp, c->source_size, (unsigned char *)c->source_data);
+ res = bmp_analyse(bmp, size, (unsigned char *) data);
switch (res) {
case BMP_OK:
break;
@@ -98,7 +101,7 @@ bool nsbmp_convert(struct content *c, int iwidth, int iheight)
c->title = malloc(100);
if (c->title)
snprintf(c->title, 100, messages_get("BMPTitle"), c->width,
- c->height, c->source_size);
+ c->height, size);
swidth = bmp->bitmap_callbacks.bitmap_get_bpp(bmp->bitmap) * bmp->width;
c->size += (swidth * bmp->height) + 16 + 44 + 100;
diff --git a/image/bmp.h b/image/bmp.h
index f7b974f03..7d70a952d 100644
--- a/image/bmp.h
+++ b/image/bmp.h
@@ -33,6 +33,7 @@
struct content;
struct bitmap;
+struct http_parameter;
struct content_bmp_data {
bmp_image *bmp; /** BMP image data */
@@ -40,8 +41,7 @@ struct content_bmp_data {
extern bmp_bitmap_callback_vt bmp_bitmap_callbacks; /** Only to be used by ICO code. */
-bool nsbmp_create(struct content *c, struct content *parent,
- const char *params[]);
+bool nsbmp_create(struct content *c, const struct http_parameter *params);
bool nsbmp_convert(struct content *c, int width, int height);
void nsbmp_destroy(struct content *c);
bool nsbmp_redraw(struct content *c, int x, int y,
diff --git a/image/gif.c b/image/gif.c
index 62d73f0b0..81da8bd5d 100644
--- a/image/gif.c
+++ b/image/gif.c
@@ -37,7 +37,7 @@
#include <stdlib.h>
#include <libnsgif.h>
#include "utils/config.h"
-#include "content/content.h"
+#include "content/content_protected.h"
#include "desktop/browser.h"
#include "desktop/options.h"
#include "desktop/plotters.h"
@@ -64,8 +64,7 @@ gif_bitmap_callback_vt gif_bitmap_callbacks = {
};
-bool nsgif_create(struct content *c, struct content *parent,
- const char *params[])
+bool nsgif_create(struct content *c, const struct http_parameter *params)
{
union content_msg_data msg_data;
/* Initialise our data structure */
@@ -85,26 +84,28 @@ bool nsgif_convert(struct content *c, int iwidth, int iheight)
int res;
struct gif_animation *gif;
union content_msg_data msg_data;
+ const char *data;
+ unsigned long size;
/* Get the animation */
gif = c->data.gif.gif;
+ data = content__get_source_data(c, &size);
+
/* Initialise the GIF */
do {
- res = gif_initialise(gif, c->source_size,
- (unsigned char *)c->source_data);
- if (res != GIF_OK && res != GIF_WORKING && res != GIF_INSUFFICIENT_FRAME_DATA) {
- switch (res)
- {
- case GIF_FRAME_DATA_ERROR:
- case GIF_INSUFFICIENT_DATA:
- case GIF_DATA_ERROR:
- msg_data.error = messages_get("BadGIF");
- break;
- case GIF_INSUFFICIENT_MEMORY:
- msg_data.error = messages_get(
- "NoMemory");
- break;
+ res = gif_initialise(gif, size, (unsigned char *) data);
+ if (res != GIF_OK && res != GIF_WORKING &&
+ res != GIF_INSUFFICIENT_FRAME_DATA) {
+ switch (res) {
+ case GIF_FRAME_DATA_ERROR:
+ case GIF_INSUFFICIENT_DATA:
+ case GIF_DATA_ERROR:
+ msg_data.error = messages_get("BadGIF");
+ break;
+ case GIF_INSUFFICIENT_MEMORY:
+ msg_data.error = messages_get("NoMemory");
+ break;
}
content_broadcast(c, CONTENT_MSG_ERROR, msg_data);
return false;
@@ -125,7 +126,7 @@ bool nsgif_convert(struct content *c, int iwidth, int iheight)
c->title = malloc(100);
if (c->title) {
snprintf(c->title, 100, messages_get("GIFTitle"), c->width,
- c->height, c->source_size);
+ c->height, size);
}
c->size += (gif->width * gif->height * 4) + 16 + 44 + 100;
diff --git a/image/gif.h b/image/gif.h
index 0e3ef6605..87f647eba 100644
--- a/image/gif.h
+++ b/image/gif.h
@@ -31,14 +31,14 @@
#include <libnsgif.h>
struct content;
+struct http_parameter;
struct content_gif_data {
struct gif_animation *gif; /**< GIF animation data */
int current_frame; /**< current frame to display [0...(max-1)] */
};
-bool nsgif_create(struct content *c, struct content *parent,
- const char *params[]);
+bool nsgif_create(struct content *c, const struct http_parameter *params);
bool nsgif_convert(struct content *c, int width, int height);
void nsgif_destroy(struct content *c);
bool nsgif_redraw(struct content *c, int x, int y,
diff --git a/image/ico.c b/image/ico.c
index e2fce245a..df07d50ed 100644
--- a/image/ico.c
+++ b/image/ico.c
@@ -29,7 +29,8 @@
#include <stdlib.h>
#include <libnsbmp.h>
#include "utils/config.h"
-#include "content/content.h"
+#include "content/content_protected.h"
+#include "content/hlcache.h"
#include "desktop/plotters.h"
#include "image/bitmap.h"
#include "image/ico.h"
@@ -37,8 +38,7 @@
#include "utils/messages.h"
#include "utils/utils.h"
-bool nsico_create(struct content *c, struct content *parent,
- const char *params[])
+bool nsico_create(struct content *c, const struct http_parameter *params)
{
union content_msg_data msg_data;
c->data.ico.ico = calloc(sizeof(ico_collection), 1);
@@ -58,26 +58,29 @@ bool nsico_convert(struct content *c, int iwidth, int iheight)
bmp_result res;
ico_collection *ico;
union content_msg_data msg_data;
+ const char *data;
+ unsigned long size;
/* set the ico data */
ico = c->data.ico.ico;
+ data = content__get_source_data(c, &size);
+
/* analyse the ico */
- res = ico_analyse(ico, c->source_size, (unsigned char *)
- c->source_data);
+ res = ico_analyse(ico, size, (unsigned char *) data);
switch (res) {
- case BMP_OK:
- break;
- case BMP_INSUFFICIENT_MEMORY:
- msg_data.error = messages_get("NoMemory");
- content_broadcast(c, CONTENT_MSG_ERROR, msg_data);
- return false;
- case BMP_INSUFFICIENT_DATA:
- case BMP_DATA_ERROR:
- msg_data.error = messages_get("BadICO");
- content_broadcast(c, CONTENT_MSG_ERROR, msg_data);
- return false;
+ case BMP_OK:
+ break;
+ case BMP_INSUFFICIENT_MEMORY:
+ msg_data.error = messages_get("NoMemory");
+ content_broadcast(c, CONTENT_MSG_ERROR, msg_data);
+ return false;
+ case BMP_INSUFFICIENT_DATA:
+ case BMP_DATA_ERROR:
+ msg_data.error = messages_get("BadICO");
+ content_broadcast(c, CONTENT_MSG_ERROR, msg_data);
+ return false;
}
/* Store our content width and description */
@@ -86,7 +89,7 @@ bool nsico_convert(struct content *c, int iwidth, int iheight)
c->title = malloc(100);
if (c->title)
snprintf(c->title, 100, messages_get("ICOTitle"), c->width,
- c->height, c->source_size);
+ c->height, size);
c->size += (ico->width * ico->height * 4) + 16 + 44 + 100;
/* exit as a success */
@@ -117,14 +120,22 @@ bool nsico_redraw(struct content *c, int x, int y,
/** sets the bitmap for an ico according to the dimensions */
-bool nsico_set_bitmap_from_size(struct content *c, int width, int height)
+bool nsico_set_bitmap_from_size(hlcache_handle *h, int width, int height)
{
- struct bmp_image *bmp = ico_find(c->data.ico.ico, width, height);
+ struct content *c = hlcache_handle_get_content(h);
+ struct bmp_image *bmp;
+
+ assert(c != NULL);
+
+ bmp = ico_find(c->data.ico.ico, width, height);
if (bmp == NULL)
return false;
+
if ((bmp->decoded == false) && (bmp_decode(bmp) != BMP_OK))
return false;
+
c->bitmap = bmp->bitmap;
+
return true;
}
diff --git a/image/ico.h b/image/ico.h
index f3686c0c5..e25da8361 100644
--- a/image/ico.h
+++ b/image/ico.h
@@ -30,13 +30,14 @@
#include <libnsbmp.h>
struct content;
+struct hlcache_handle;
+struct http_parameter;
struct content_ico_data {
struct ico_collection *ico; /** ICO collection data */
};
-bool nsico_create(struct content *c, struct content *parent,
- const char *params[]);
+bool nsico_create(struct content *c, const struct http_parameter *params);
bool nsico_convert(struct content *c, int width, int height);
void nsico_destroy(struct content *c);
bool nsico_redraw(struct content *c, int x, int y,
@@ -48,7 +49,8 @@ bool nsico_redraw_tiled(struct content *c, int x, int y,
int clip_x0, int clip_y0, int clip_x1, int clip_y1,
float scale, colour background_colour,
bool repeat_x, bool repeat_y);
-bool nsico_set_bitmap_from_size(struct content *c, int width, int height);
+bool nsico_set_bitmap_from_size(struct hlcache_handle *h,
+ int width, int height);
#endif /* WITH_BMP */
diff --git a/image/jpeg.c b/image/jpeg.c
index e96faaa67..1d66b05d3 100644
--- a/image/jpeg.c
+++ b/image/jpeg.c
@@ -27,7 +27,7 @@
#ifdef WITH_JPEG
/* This must come first due to libpng issues */
-#include "content/content.h"
+#include "content/content_protected.h"
#include <assert.h>
#include <setjmp.h>
@@ -89,6 +89,10 @@ bool nsjpeg_convert(struct content *c, int w, int h)
uint8_t * volatile pixels = NULL;
size_t rowstride;
union content_msg_data msg_data;
+ const char *data;
+ unsigned long size;
+
+ data = content__get_source_data(c, &size);
cinfo.err = jpeg_std_error(&jerr.pub);
jerr.pub.error_exit = nsjpeg_error_exit;
@@ -102,8 +106,8 @@ bool nsjpeg_convert(struct content *c, int w, int h)
return false;
}
jpeg_create_decompress(&cinfo);
- source_mgr.next_input_byte = (unsigned char *) c->source_data;
- source_mgr.bytes_in_buffer = c->source_size;
+ source_mgr.next_input_byte = (unsigned char *) data;
+ source_mgr.bytes_in_buffer = size;
cinfo.src = &source_mgr;
jpeg_read_header(&cinfo, TRUE);
cinfo.out_color_space = JCS_RGB;
@@ -161,7 +165,7 @@ bool nsjpeg_convert(struct content *c, int w, int h)
c->title = malloc(100);
if (c->title)
snprintf(c->title, 100, messages_get("JPEGTitle"),
- width, height, c->source_size);
+ width, height, size);
c->size += height * rowstride + 100;
c->status = CONTENT_STATUS_DONE;
/* Done: update status bar */
diff --git a/image/mng.c b/image/mng.c
index d21d9e879..e76125b9b 100644
--- a/image/mng.c
+++ b/image/mng.c
@@ -24,7 +24,7 @@
#ifdef WITH_MNG
/* This must come first due to libpng issues */
-#include "content/content.h"
+#include "content/content_protected.h"
#include <assert.h>
#include <stdbool.h>
@@ -69,8 +69,7 @@ static void nsmng_free(mng_ptr p, mng_size_t n);
#endif
-bool nsmng_create(struct content *c, struct content *parent,
- const char *params[])
+bool nsmng_create(struct content *c, const struct http_parameter *params)
{
mng_retcode code;
union content_msg_data msg_data;
@@ -179,6 +178,8 @@ mng_bool nsmng_readdata(mng_handle mng, mng_ptr buffer, mng_uint32 size,
mng_uint32 *bytesread)
{
struct content *c;
+ const char *data;
+ unsigned long data_size;
assert(mng != NULL);
assert(buffer != NULL);
@@ -186,17 +187,18 @@ mng_bool nsmng_readdata(mng_handle mng, mng_ptr buffer, mng_uint32 size,
/* Get our content back
*/
- c = (struct content *)mng_get_userdata(mng);
+ c = (struct content *) mng_get_userdata(mng);
assert(c != NULL);
/* Copy any data we have (maximum of 'size')
*/
- *bytesread = ((c->source_size - c->data.mng.read_size) < size) ?
- (c->source_size - c->data.mng.read_size) : size;
+ data = content__get_source_data(c, &data_size);
+
+ *bytesread = ((data_size - c->data.mng.read_size) < size) ?
+ (data_size - c->data.mng.read_size) : size;
if ((*bytesread) > 0) {
- memcpy(buffer, c->source_data + c->data.mng.read_size,
- *bytesread);
+ memcpy(buffer, data + c->data.mng.read_size, *bytesread);
c->data.mng.read_size += *bytesread;
}
@@ -302,9 +304,13 @@ bool nsmng_convert(struct content *c, int width, int height)
mng_retcode status;
union content_msg_data msg_data;
+ const char *data;
+ unsigned long size;
assert(c != NULL);
+ data = content__get_source_data(c, &size);
+
/* by this point, the png should have been parsed
* and the bitmap created, so ensure that's the case
*/
@@ -322,13 +328,13 @@ bool nsmng_convert(struct content *c, int width, int height)
if (c->type == CONTENT_MNG) {
snprintf(c->title, 100, messages_get("MNGTitle"),
- c->width, c->height, c->source_size);
+ c->width, c->height, size);
} else if (c->type == CONTENT_PNG) {
snprintf(c->title, 100, messages_get("PNGTitle"),
- c->width, c->height, c->source_size);
+ c->width, c->height, size);
} else {
snprintf(c->title, 100, messages_get("JNGTitle"),
- c->width, c->height, c->source_size);
+ c->width, c->height, size);
}
c->size += c->width * c->height * 4 + 100;
@@ -658,7 +664,8 @@ mng_bool nsmng_errorproc(mng_handle mng, mng_int32 code,
chunk[3] = (char)((chunktype ) & 0xFF);
chunk[4] = '\0';
- LOG(("error playing '%s' chunk %s (%d):", c->url, chunk, chunkseq));
+ LOG(("error playing '%s' chunk %s (%d):",
+ content__get_url(c), chunk, chunkseq));
LOG(("code %d severity %d extra1 %d extra2 %d text:'%s'", code,
severity, extra1, extra2, text));
diff --git a/image/mng.h b/image/mng.h
index 2ea85409c..553fff36f 100644
--- a/image/mng.h
+++ b/image/mng.h
@@ -29,6 +29,7 @@
#include <stdbool.h>
struct content;
+struct http_parameter;
struct content_mng_data {
bool opaque_test_pending;
@@ -40,8 +41,7 @@ struct content_mng_data {
void *handle;
};
-bool nsmng_create(struct content *c, struct content *parent,
- const char *params[]);
+bool nsmng_create(struct content *c, const struct http_parameter *params);
bool nsmng_process_data(struct content *c, char *data, unsigned int size);
bool nsmng_convert(struct content *c, int width, int height);
void nsmng_destroy(struct content *c);
diff --git a/image/nssprite.c b/image/nssprite.c
index d5db6b905..9f48ffccf 100644
--- a/image/nssprite.c
+++ b/image/nssprite.c
@@ -31,7 +31,7 @@
#include "utils/config.h"
#include "desktop/plotters.h"
#include "image/bitmap.h"
-#include "content/content.h"
+#include "content/content_protected.h"
#include "utils/log.h"
#include "utils/messages.h"
#include "utils/utils.h"
@@ -61,8 +61,13 @@ bool nssprite_convert(struct content *c, int width, int height)
union content_msg_data msg_data;
struct rosprite_mem_context* ctx;
- ERRCHK(rosprite_create_mem_context((uint8_t *) c->source_data,
- c->source_size, &ctx));
+
+ const char *data;
+ unsigned long size;
+
+ data = content__get_source_data(c, &size);
+
+ ERRCHK(rosprite_create_mem_context((uint8_t *) data, size, &ctx));
struct rosprite_area* sprite_area;
ERRCHK(rosprite_load(rosprite_mem_reader, ctx, &sprite_area));
diff --git a/image/png.c b/image/png.c
index e8bd55c59..dfb427230 100644
--- a/image/png.c
+++ b/image/png.c
@@ -30,7 +30,7 @@
#include "desktop/plotters.h"
-#include "content/content.h"
+#include "content/content_protected.h"
#include "image/bitmap.h"
@@ -62,8 +62,7 @@ static void row_callback(png_structp png, png_bytep new_row,
static void end_callback(png_structp png, png_infop info);
-bool nspng_create(struct content *c, struct content *parent,
- const char *params[])
+bool nspng_create(struct content *c, const struct http_parameter *params)
{
union content_msg_data msg_data;
@@ -264,16 +263,21 @@ void end_callback(png_structp png, png_infop info)
bool nspng_convert(struct content *c, int width, int height)
{
+ const char *data;
+ unsigned long size;
+
assert(c->data.png.png != NULL);
assert(c->data.png.info != NULL);
+ data = content__get_source_data(c, &size);
+
png_destroy_read_struct(&c->data.png.png, &c->data.png.info, 0);
c->title = malloc(NSPNG_TITLE_LEN);
if (c->title != NULL) {
snprintf(c->title, NSPNG_TITLE_LEN, messages_get("PNGTitle"),
- c->width, c->height, c->source_size);
+ c->width, c->height, size);
}
c->size += (c->width * c->height * 4) + NSPNG_TITLE_LEN;
diff --git a/image/png.h b/image/png.h
index a5fa6dfae..b940434e7 100644
--- a/image/png.h
+++ b/image/png.h
@@ -31,6 +31,7 @@
struct content;
struct bitmap;
+struct http_parameter;
struct content_png_data {
png_structp png;
@@ -41,8 +42,7 @@ struct content_png_data {
size_t rowbytes; /**< Number of bytes per row */
};
-bool nspng_create(struct content *c, struct content *parent,
- const char *params[]);
+bool nspng_create(struct content *c, const struct http_parameter *params);
bool nspng_process_data(struct content *c, char *data, unsigned int size);
bool nspng_convert(struct content *c, int width, int height);
void nspng_destroy(struct content *c);
diff --git a/image/rsvg.c b/image/rsvg.c
index 86e1d5b66..ea4b58b42 100644
--- a/image/rsvg.c
+++ b/image/rsvg.c
@@ -38,7 +38,7 @@
#include <librsvg/rsvg-cairo.h>
#include "image/rsvg.h"
-#include "content/content.h"
+#include "content/content_protected.h"
#include "desktop/plotters.h"
#include "image/bitmap.h"
#include "utils/log.h"
@@ -49,8 +49,7 @@
static inline void rsvg_argb_to_abgr(uint32_t pixels[], int width, int height,
size_t rowstride);
-bool rsvg_create(struct content *c, struct content *parent,
- const char *params[])
+bool rsvg_create(struct content *c, const struct http_parameter *params)
{
struct content_rsvg_data *d = &c->data.rsvg;
union content_msg_data msg_data;
diff --git a/image/rsvg.h b/image/rsvg.h
index b8c962787..ae28d3af1 100644
--- a/image/rsvg.h
+++ b/image/rsvg.h
@@ -33,6 +33,7 @@
#include "image/bitmap.h"
struct content;
+struct http_parameter;
struct content_rsvg_data {
RsvgHandle *rsvgh; /**< Context handle for RSVG renderer */
@@ -41,8 +42,7 @@ struct content_rsvg_data {
struct bitmap *bitmap; /**< Created NetSurf bitmap */
};
-bool rsvg_create(struct content *c, struct content *parent,
- const char *params[]);
+bool rsvg_create(struct content *c, const struct http_parameter *params);
bool rsvg_process_data(struct content *c, char *data, unsigned int size);
bool rsvg_convert(struct content *c, int width, int height);
void rsvg_destroy(struct content *c);
diff --git a/image/svg.c b/image/svg.c
index 4321a9fc3..99c4241eb 100644
--- a/image/svg.c
+++ b/image/svg.c
@@ -40,7 +40,7 @@
* Create a CONTENT_SVG.
*/
-bool svg_create(struct content *c, struct content *parent, const char *params[])
+bool svg_create(struct content *c, const struct http_parameter *params)
{
union content_msg_data msg_data;
diff --git a/image/svg.h b/image/svg.h
index b191c4cd6..fe9bea3d2 100644
--- a/image/svg.h
+++ b/image/svg.h
@@ -26,14 +26,14 @@
#include <stdbool.h>
struct content;
+struct http_parameter;
struct svgtiny_diagram;
struct content_svg_data {
struct svgtiny_diagram *diagram;
};
-bool svg_create(struct content *c, struct content *parent,
- const char *params[]);
+bool svg_create(struct content *c, const struct http_parameter *params);
bool svg_convert(struct content *c, int width, int height);
void svg_destroy(struct content *c);
bool svg_redraw(struct content *c, int x, int y,
diff --git a/render/box.c b/render/box.c
index b355e68d1..e09a4772c 100644
--- a/render/box.c
+++ b/render/box.c
@@ -26,7 +26,8 @@
#include <stdbool.h>
#include <stdio.h>
#include <string.h>
-#include "content/content.h"
+#include "content/content_protected.h"
+#include "content/hlcache.h"
#include "css/css.h"
#include "css/dump.h"
#include "desktop/scroll.h"
@@ -312,7 +313,7 @@ void box_bounds(struct box *box, struct rect *r)
struct box *box_at_point(struct box *box, const int x, const int y,
int *box_x, int *box_y,
- struct content **content)
+ hlcache_handle **content)
{
int bx = *box_x, by = *box_y;
struct box *child, *sibling;
@@ -321,11 +322,14 @@ struct box *box_at_point(struct box *box, const int x, const int y,
assert(box);
/* drill into HTML objects */
- if (box->object) {
- if (box->object->type == CONTENT_HTML &&
- box->object->data.html.layout) {
+ if (box->object != NULL) {
+ struct box *layout;
+
+ if (content_get_type(box->object) == CONTENT_HTML &&
+ (layout = html_get_box_tree(box->object)) !=
+ NULL) {
*content = box->object;
- box = box->object->data.html.layout;
+ box = layout;
} else {
goto siblings;
}
@@ -503,20 +507,24 @@ bool box_contains_point(struct box *box, int x, int y, bool *physically)
/**
* Find the box containing an object at the given coordinates, if any.
*
- * \param c content to search, must have type CONTENT_HTML
+ * \param h content to search, must have type CONTENT_HTML
* \param x coordinates in document units
* \param y coordinates in document units
*/
-struct box *box_object_at_point(struct content *c, int x, int y)
+struct box *box_object_at_point(hlcache_handle *h, int x, int y)
{
- struct box *box = c->data.html.layout;
+ struct content *c = hlcache_handle_get_content(h);
+ struct box *box;
int box_x = 0, box_y = 0;
- struct content *content = c;
+ hlcache_handle *content = h;
struct box *object_box = 0;
+ assert(c != NULL);
assert(c->type == CONTENT_HTML);
+ box = c->data.html.layout;
+
while ((box = box_at_point(box, x, y, &box_x, &box_y, &content))) {
if (box->style && css_computed_visibility(box->style) ==
CSS_VISIBILITY_HIDDEN)
@@ -533,20 +541,24 @@ struct box *box_object_at_point(struct content *c, int x, int y)
/**
* Find the box containing an href at the given coordinates, if any.
*
- * \param c content to search, must have type CONTENT_HTML
+ * \param h content to search, must have type CONTENT_HTML
* \param x coordinates in document units
* \param y coordinates in document units
*/
-struct box *box_href_at_point(struct content *c, int x, int y)
+struct box *box_href_at_point(hlcache_handle *h, int x, int y)
{
- struct box *box = c->data.html.layout;
+ struct content *c = hlcache_handle_get_content(h);
+ struct box *box;
int box_x = 0, box_y = 0;
- struct content *content = c;
+ hlcache_handle *content = h;
struct box *href_box = 0;
+ assert(c != NULL);
assert(c->type == CONTENT_HTML);
+ box = c->data.html.layout;
+
while ((box = box_at_point(box, x, y, &box_x, &box_y, &content))) {
if (box->style && css_computed_visibility(box->style) ==
CSS_VISIBILITY_HIDDEN)
@@ -663,8 +675,10 @@ void box_dump(FILE *stream, struct box *box, unsigned int depth)
(int) box->length, box->text);
if (box->space)
fprintf(stream, "space ");
- if (box->object)
- fprintf(stream, "(object '%s') ", box->object->url);
+ if (box->object) {
+ fprintf(stream, "(object '%s') ",
+ content_get_url(box->object));
+ }
if (box->gadget)
fprintf(stream, "(gadget) ");
if (box->style)
@@ -860,42 +874,42 @@ bool box_duplicate_main_tree(struct box *box, struct content *c, int *count)
box->last = prev;
- if (box->object && option_suppress_images && (
+ if (box->object != NULL && option_suppress_images && (
#ifdef WITH_JPEG
- box->object->type == CONTENT_JPEG ||
+ content_get_type(box->object) == CONTENT_JPEG ||
#endif
#ifdef WITH_GIF
- box->object->type == CONTENT_GIF ||
+ content_get_type(box->object) == CONTENT_GIF ||
#endif
#ifdef WITH_BMP
- box->object->type == CONTENT_BMP ||
- box->object->type == CONTENT_ICO ||
+ content_get_type(box->object) == CONTENT_BMP ||
+ content_get_type(box->object) == CONTENT_ICO ||
#endif
#if defined(WITH_MNG) || defined(WITH_PNG)
- box->object->type == CONTENT_PNG ||
+ content_get_type(box->object) == CONTENT_PNG ||
#endif
#ifdef WITH_MNG
- box->object->type == CONTENT_JNG ||
- box->object->type == CONTENT_MNG ||
+ content_get_type(box->object) == CONTENT_JNG ||
+ content_get_type(box->object) == CONTENT_MNG ||
#endif
#if defined(WITH_SPRITE) || defined(WITH_NSSPRITE)
- box->object->type == CONTENT_SPRITE ||
+ content_get_type(box->object) == CONTENT_SPRITE ||
#endif
#ifdef WITH_DRAW
- box->object->type == CONTENT_DRAW ||
+ content_get_type(box->object) == CONTENT_DRAW ||
#endif
#ifdef WITH_PLUGIN
- box->object->type == CONTENT_PLUGIN ||
+ content_get_type(box->object) == CONTENT_PLUGIN ||
#endif
- box->object->type == CONTENT_DIRECTORY ||
+ content_get_type(box->object) == CONTENT_DIRECTORY ||
#ifdef WITH_THEME_INSTALL
- box->object->type == CONTENT_THEME ||
+ content_get_type(box->object) == CONTENT_THEME ||
#endif
#ifdef WITH_ARTWORKS
- box->object->type == CONTENT_ARTWORKS ||
+ content_get_type(box->object) == CONTENT_ARTWORKS ||
#endif
#if defined(WITH_NS_SVG) || defined(WITH_RSVG)
- box->object->type == CONTENT_SVG ||
+ content_get_type(box->object) == CONTENT_SVG ||
#endif
false))
box->object = NULL;
diff --git a/render/box.h b/render/box.h
index b53e0481c..665565f2f 100644
--- a/render/box.h
+++ b/render/box.h
@@ -239,10 +239,10 @@ struct box {
char *id; /**< value of id attribute (or name for anchors) */
/** Background image for this box, or 0 if none */
- struct content *background;
+ struct hlcache_handle *background;
/** Object in this box (usually an image), or 0 if none. */
- struct content* object;
+ struct hlcache_handle* object;
/** Parameters for the object, or 0. */
struct object_params *object_params;
};
@@ -307,9 +307,9 @@ void box_free_object_params(struct object_params *op);
void box_bounds(struct box *box, struct rect *r);
void box_coords(struct box *box, int *x, int *y);
struct box *box_at_point(struct box *box, const int x, const int y,
- int *box_x, int *box_y, struct content **content);
-struct box *box_object_at_point(struct content *c, int x, int y);
-struct box *box_href_at_point(struct content *c, int x, int y);
+ int *box_x, int *box_y, struct hlcache_handle **content);
+struct box *box_object_at_point(struct hlcache_handle *h, int x, int y);
+struct box *box_href_at_point(struct hlcache_handle *h, int x, int y);
struct box *box_find_by_id(struct box *box, const char *id);
bool box_visible(struct box *box);
void box_dump(FILE *stream, struct box *box, unsigned int depth);
diff --git a/render/box_construct.c b/render/box_construct.c
index bdab6159e..71d30ddae 100644
--- a/render/box_construct.c
+++ b/render/box_construct.c
@@ -35,7 +35,7 @@
#include <libxml/HTMLparser.h>
#include <libxml/parserInternals.h>
#include "utils/config.h"
-#include "content/content.h"
+#include "content/content_protected.h"
#include "css/css.h"
#include "css/utils.h"
#include "css/select.h"
@@ -841,9 +841,9 @@ css_computed_style *box_get_style(struct content *c,
if ((s = (char *) xmlGetProp(n, (const xmlChar *) "style"))) {
inline_style = nscss_create_inline_style(
(uint8_t *) s, strlen(s),
- c->data.html.encoding, c->url,
+ c->data.html.encoding, content__get_url(c),
c->data.html.quirks != BINDING_QUIRKS_MODE_NONE,
- c->data.html.dict, myrealloc, c);
+ myrealloc, c);
xmlFree(s);
diff --git a/render/directory.c b/render/directory.c
index 82f24efa2..9f002d831 100644
--- a/render/directory.c
+++ b/render/directory.c
@@ -28,7 +28,7 @@
#include <stdlib.h>
#include <sys/stat.h>
#include <time.h>
-#include "content/content.h"
+#include "content/content_protected.h"
#include "render/directory.h"
#include "render/html.h"
#include "utils/messages.h"
@@ -40,9 +40,8 @@ static const char header[] = "<html>\n<head>\n<title>\n";
static const char footer[] = "</pre>\n</body>\n</html>\n";
-bool directory_create(struct content *c, struct content *parent,
- const char *params[]) {
- if (!html_create(c, parent, params))
+bool directory_create(struct content *c, const struct http_parameter *params) {
+ if (!html_create(c, params))
/* html_create() must have broadcast MSG_ERROR already, so we
* don't need to. */
return false;
@@ -64,7 +63,7 @@ bool directory_convert(struct content *c, int width, int height) {
bool compare;
char *up;
- path = url_to_path(c->url);
+ path = url_to_path(content__get_url(c));
if (!path) {
msg_data.error = messages_get("NoMemory");
content_broadcast(c, CONTENT_MSG_ERROR, msg_data);
@@ -100,9 +99,9 @@ bool directory_convert(struct content *c, int width, int height) {
binding_parse_chunk(c->data.html.parser_binding,
(uint8_t *) buffer, strlen(buffer));
- res = url_parent(c->url, &up);
+ res = url_parent(content__get_url(c), &up);
if (res == URL_FUNC_OK) {
- res = url_compare(c->url, up, false, &compare);
+ res = url_compare(content__get_url(c), up, false, &compare);
if ((res == URL_FUNC_OK) && !compare) {
snprintf(buffer, sizeof(buffer),
"<a href=\"..\">[..]</a>\n");
@@ -124,7 +123,8 @@ bool directory_convert(struct content *c, int width, int height) {
continue;
snprintf(buffer, sizeof(buffer), "<a href=\"%s/%s\">%s</a>\n",
- c->url, entry->d_name, entry->d_name);
+ content__get_url(c), entry->d_name,
+ entry->d_name);
binding_parse_chunk(c->data.html.parser_binding,
(uint8_t *) buffer, strlen(buffer));
diff --git a/render/directory.h b/render/directory.h
index a54d516fb..766593294 100644
--- a/render/directory.h
+++ b/render/directory.h
@@ -28,9 +28,9 @@
#include <stdbool.h>
#include "content/content_type.h"
+struct http_parameter;
-bool directory_create(struct content *c, struct content *parent,
- const char *params[]);
+bool directory_create(struct content *c, const struct http_parameter *params);
bool directory_convert(struct content *c, int width, int height);
void directory_destroy(struct content *c);
diff --git a/render/favicon.c b/render/favicon.c
index ec5caeae0..191c55e8a 100644
--- a/render/favicon.c
+++ b/render/favicon.c
@@ -18,8 +18,8 @@
*/
#include <string.h>
-#include "content/fetch.h"
-#include "content/fetchcache.h"
+#include "content/content_protected.h"
+#include "content/hlcache.h"
#include "render/favicon.h"
#include "render/html.h"
#include "utils/log.h"
@@ -29,8 +29,8 @@
#include "utils/utils.h"
static char *favicon_get_icon_ref(struct content *c, xmlNode *html);
-static void favicon_callback(content_msg msg, struct content *icon,
- intptr_t p1, intptr_t p2, union content_msg_data data);
+static nserror favicon_callback(hlcache_handle *icon,
+ const hlcache_event *event, void *pw);
/**
* retrieve 1 url reference to 1 favicon
@@ -39,68 +39,80 @@ static void favicon_callback(content_msg msg, struct content *icon,
*/
char *favicon_get_icon_ref(struct content *c, xmlNode *html)
{
- xmlNode *node;
- char *rel, *href, *url, *url2;
+ xmlNode *node = html;
+ char *rel, *href, *url, *url2 = NULL;
url_func_result res;
- union content_msg_data msg_data;
- url2 = NULL;
- node = html;
while (node) {
- if (node->children) { /* children */
+ if (node->children != NULL) { /* children */
node = node->children;
- } else if (node->next) { /* siblings */
+ } else if (node->next != NULL) { /* siblings */
node = node->next;
} else { /* ancestor siblings */
- while (node && !node->next)
+ while (node != NULL && node->next == NULL)
node = node->parent;
- if (!node)
+
+ if (node == NULL)
break;
+
node = node->next;
}
- assert(node);
+
+ assert(node != NULL);
if (node->type != XML_ELEMENT_NODE)
continue;
+
if (strcmp((const char *) node->name, "link") == 0) {
/* rel=<space separated list, including 'icon'> */
if ((rel = (char *) xmlGetProp(node,
(const xmlChar *) "rel")) == NULL)
continue;
+
if (strcasestr(rel, "icon") == 0) {
xmlFree(rel);
continue;
}
- LOG(("icon node found"));
+
if (strcasecmp(rel, "apple-touch-icon") == 0) {
xmlFree(rel);
continue;
}
+
xmlFree(rel);
- if (( href = (char *) xmlGetProp(node,
+
+ if ((href = (char *) xmlGetProp(node,
(const xmlChar *) "href")) == NULL)
continue;
- res = url_join(href, c->data.html.base_url,
- &url);
+
+ res = url_join(href, c->data.html.base_url, &url);
+
xmlFree(href);
+
if (res != URL_FUNC_OK)
continue;
- LOG(("most recent favicon '%s'", url));
+
if (url2 != NULL) {
free(url2);
url2 = NULL;
}
+
res = url_normalize(url, &url2);
+
free(url);
+
if (res != URL_FUNC_OK) {
url2 = NULL;
+
if (res == URL_FUNC_NOMEM)
- goto no_memory;
+ return NULL;
+
continue;
}
}
}
+
if (url2 == NULL) {
char *scheme;
@@ -123,12 +135,8 @@ char *favicon_get_icon_ref(struct content *c, xmlNode *html)
!= URL_FUNC_OK)
return NULL;
}
- LOG(("favicon %s", url2));
+
return url2;
-no_memory:
- msg_data.error = messages_get("NoMemory");
- /* content_broadcast(c, CONTENT_MSG_ERROR, msg_data); */
- return false;
}
/**
@@ -140,31 +148,27 @@ no_memory:
bool favicon_get_icon(struct content *c, xmlNode *html)
{
- char *url = favicon_get_icon_ref(c, html);
- struct content *favcontent = NULL;
+ char *url;
+ nserror error;
+
+ url = favicon_get_icon_ref(c, html);
if (url == NULL)
return false;
-
- favcontent = fetchcache(url, favicon_callback, (intptr_t) c, 0,
- c->width, c->height, true, 0, 0, false, false);
- free(url);
- if (favcontent == NULL)
- return false;
- c->data.html.favicon = favcontent;
-
- fetchcache_go(favcontent, c->url, favicon_callback, (intptr_t) c, 0,
- c->width, c->height, 0, 0, false, c);
+ error = hlcache_handle_retrieve(url, 0, NULL, NULL, c->width, c->height,
+ favicon_callback, c, NULL, &c->data.html.favicon);
+
+ free(url);
- return true;
+ return error == NSERROR_OK;
}
/**
* Callback for fetchcache() for linked favicon
*/
-void favicon_callback(content_msg msg, struct content *icon,
- intptr_t p1, intptr_t p2, union content_msg_data data)
+nserror favicon_callback(hlcache_handle *icon,
+ const hlcache_event *event, void *pw)
{
static const content_type permitted_types[] = {
#ifdef WITH_BMP
@@ -178,88 +182,57 @@ void favicon_callback(content_msg msg, struct content *icon,
#endif
CONTENT_UNKNOWN
};
- struct content *c = (struct content *) p1;
- unsigned int i = p2;
+ struct content *c = pw;
const content_type *type;
-
- switch (msg) {
+ switch (event->type) {
case CONTENT_MSG_LOADING:
/* check that the favicon is really a correct image type */
for (type = permitted_types; *type != CONTENT_UNKNOWN; type++)
- if (icon->type == *type)
+ if (content_get_type(icon) == *type)
break;
if (*type == CONTENT_UNKNOWN) {
- c->data.html.favicon = 0;
- LOG(("%s is not a favicon", icon->url));
+ union content_msg_data msg_data;
+
+ hlcache_handle_release(c->data.html.favicon);
+ c->data.html.favicon = NULL;
+ LOG(("%s is not a favicon", content_get_url(icon)));
content_add_error(c, "NotFavIco", 0);
- html_set_status(c, messages_get("NotFavIco"));
- content_broadcast(c, CONTENT_MSG_STATUS, data);
- content_remove_user(icon,
- favicon_callback,
- (intptr_t) c, i);
- if (!icon->user_list->next) {
- /* we were the only user and we don't want this
- * content, so stop it fetching and mark it as
- * having an error so it gets removed from the
- * cache next time content_clean() gets called
- */
- fetch_abort(icon->fetch);
- icon->fetch = 0;
- icon->status = CONTENT_STATUS_ERROR;
- }
+
+ msg_data.error = messages_get("NotFavIco");
+ content_broadcast(c, CONTENT_MSG_STATUS, msg_data);
}
break;
case CONTENT_MSG_READY:
- break;
-
+ /* Fall through */
case CONTENT_MSG_DONE:
- LOG(("got favicon '%s'", icon->url));
break;
- case CONTENT_MSG_LAUNCH:
- /* Fall through */
case CONTENT_MSG_ERROR:
- LOG(("favicon %s failed: %s", icon->url, data.error));
- /* The favicon we were fetching may have been
- * redirected, in that case, the object pointers
- * will differ, so ensure that the object that's
- * in error is still in use by us before invalidating
- * the pointer */
- if (c->data.html.favicon == icon) {
- c->data.html.favicon = 0;
- content_add_error(c, "?", 0);
- }
- break;
+ LOG(("favicon %s failed: %s",
+ content_get_url(icon), event->data.error));
+ hlcache_handle_release(c->data.html.favicon);
+ c->data.html.favicon = NULL;
- case CONTENT_MSG_STATUS:
- html_set_status(c, icon->status_message);
- content_broadcast(c, CONTENT_MSG_STATUS, data);
- break;
-
- case CONTENT_MSG_NEWPTR:
- c->data.html.favicon = icon;
- break;
-
- case CONTENT_MSG_AUTH:
- c->data.html.favicon = 0;
content_add_error(c, "?", 0);
break;
- case CONTENT_MSG_SSL:
- c->data.html.favicon = 0;
- content_add_error(c, "?", 0);
+ case CONTENT_MSG_STATUS:
+ content_broadcast(c, CONTENT_MSG_STATUS, event->data);
break;
+
case CONTENT_MSG_REDRAW:
- /* currently no support for favicon animations */
+ /* Fall through */
case CONTENT_MSG_REFRESH:
- break;
+ /* Fall through */
case CONTENT_MSG_REFORMAT:
- /* would be unusual :) */
break;
+
default:
assert(0);
}
+
+ return NSERROR_OK;
}
diff --git a/render/favicon.h b/render/favicon.h
index 30030101a..428655ecd 100644
--- a/render/favicon.h
+++ b/render/favicon.h
@@ -20,7 +20,8 @@
#define _NETSURF_RENDER_FAVICON_H_
#include <libxml/tree.h>
-#include "content/content.h"
+
+struct content;
bool favicon_get_icon(struct content *c, xmlNode *html);
diff --git a/render/form.c b/render/form.c
index 968397a21..b81d2ca34 100644
--- a/render/form.c
+++ b/render/form.c
@@ -30,6 +30,7 @@
#include <stdbool.h>
#include <stdio.h>
#include <string.h>
+#include "content/fetch.h"
#include "css/css.h"
#include "css/utils.h"
#include "desktop/gui.h"
@@ -308,18 +309,18 @@ bool form_add_option(struct form_control *control, char *value, char *text,
* \param form form to search for successful controls
* \param submit_button control used to submit the form, if any
* \param successful_controls updated to point to linked list of
- * form_successful_control, 0 if no controls
+ * fetch_multipart_data, 0 if no controls
* \return true on success, false on memory exhaustion
*
* See HTML 4.01 section 17.13.2.
*/
bool form_successful_controls(struct form *form,
struct form_control *submit_button,
- struct form_successful_control **successful_controls)
+ struct fetch_multipart_data **successful_controls)
{
struct form_control *control;
struct form_option *option;
- struct form_successful_control sentinel, *last_success, *success_new;
+ struct fetch_multipart_data sentinel, *last_success, *success_new;
char *value = NULL;
bool had_submit = false;
char *charset;
@@ -603,7 +604,7 @@ bool form_successful_controls(struct form *form,
no_memory:
warn_user("NoMemory", 0);
- form_free_successful(sentinel.next);
+ fetch_multipart_data_destroy(sentinel.next);
return false;
#undef ENCODE_ITEM
@@ -659,12 +660,12 @@ char *form_textarea_value(struct form_control *textarea)
* Encode controls using application/x-www-form-urlencoded.
*
* \param form form to which successful controls relate
- * \param control linked list of form_successful_control
+ * \param control linked list of fetch_multipart_data
* \return URL-encoded form, or 0 on memory exhaustion
*/
char *form_url_encode(struct form *form,
- struct form_successful_control *control)
+ struct fetch_multipart_data *control)
{
char *name, *value;
char *s = malloc(1), *s2;
@@ -713,24 +714,6 @@ char *form_url_encode(struct form *form,
return s;
}
-
-/**
- * Free a linked list of form_successful_control.
- *
- * \param control Pointer to head of list to free
- */
-
-void form_free_successful(struct form_successful_control *control)
-{
- struct form_successful_control *next;
- for (; control; control = next) {
- next = control->next;
- free(control->name);
- free(control->value);
- free(control);
- }
-}
-
/**
* Find an acceptable character set encoding with which to submit the form
*
diff --git a/render/form.h b/render/form.h
index a31c24975..d5026e039 100644
--- a/render/form.h
+++ b/render/form.h
@@ -125,14 +125,6 @@ struct form_option {
struct form_option* next;
};
-/** Successful control, as defined by HTML 4.01 17.13. */
-struct form_successful_control {
- bool file; /**< It's a file */
- char *name; /**< Control name. */
- char *value; /**< Current value. */
- struct form_successful_control *next; /**< Next in linked list. */
-};
-
/**
* Called by the select menu when it wants an area to be redrawn. The
* coordinates are menu origin relative.
@@ -157,10 +149,9 @@ bool form_add_option(struct form_control *control, char *value, char *text,
bool selected);
bool form_successful_controls(struct form *form,
struct form_control *submit_button,
- struct form_successful_control **successful_controls);
+ struct fetch_multipart_data **successful_controls);
char *form_url_encode(struct form *form,
- struct form_successful_control *control);
-void form_free_successful(struct form_successful_control *control);
+ struct fetch_multipart_data *control);
bool form_open_select_menu(void *client_data,
struct form_control *control,
diff --git a/render/html.c b/render/html.c
index 82becef5c..d63c68764 100644
--- a/render/html.c
+++ b/render/html.c
@@ -29,9 +29,10 @@
#include <strings.h>
#include <stdlib.h>
#include "utils/config.h"
-#include "content/content.h"
+#include "content/content_protected.h"
#include "content/fetch.h"
#include "content/fetchcache.h"
+#include "content/hlcache.h"
#include "desktop/browser.h"
#include "desktop/gui.h"
#include "desktop/options.h"
@@ -43,6 +44,7 @@
#include "render/html.h"
#include "render/imagemap.h"
#include "render/layout.h"
+#include "utils/http.h"
#include "utils/log.h"
#include "utils/messages.h"
#include "utils/talloc.h"
@@ -57,16 +59,18 @@
#define ALWAYS_DUMP_FRAMESET 0
#define ALWAYS_DUMP_BOX 0
-static void html_convert_css_callback(content_msg msg, struct content *css,
- intptr_t p1, intptr_t p2, union content_msg_data data);
+static nserror html_convert_css_callback(hlcache_handle *css,
+ const hlcache_event *event, void *pw);
static bool html_meta_refresh(struct content *c, xmlNode *head);
static bool html_head(struct content *c, xmlNode *head);
static bool html_find_stylesheets(struct content *c, xmlNode *html);
static bool html_process_style_element(struct content *c, unsigned int *index,
xmlNode *style);
-static void html_object_callback(content_msg msg, struct content *object,
- intptr_t p1, intptr_t p2, union content_msg_data data);
-static void html_object_done(struct box *box, struct content *object,
+static bool html_replace_object(struct content *c, unsigned int i,
+ const char *url);
+static nserror html_object_callback(hlcache_handle *object,
+ const hlcache_event *event, void *pw);
+static void html_object_done(struct box *box, hlcache_handle *object,
bool background);
static void html_object_failed(struct box *box, struct content *content,
bool background);
@@ -113,57 +117,45 @@ static void *myrealloc(void *ptr, size_t len, void *pw)
* created.
*/
-bool html_create(struct content *c, struct content *parent,
- const char *params[])
+bool html_create(struct content *c, const http_parameter *params)
{
- unsigned int i;
struct content_html_data *html = &c->data.html;
+ const char *charset;
union content_msg_data msg_data;
binding_error error;
- lwc_context *dict;
- lwc_error lerror;
+ nserror nerror;
html->parser_binding = NULL;
- html->document = 0;
+ html->document = NULL;
html->quirks = BINDING_QUIRKS_MODE_NONE;
- html->encoding = 0;
- html->base_url = c->url;
+ html->encoding = NULL;
+ html->base_url = (char *) content__get_url(c);
html->base_target = NULL;
- html->layout = 0;
+ html->layout = NULL;
html->background_colour = NS_TRANSPARENT;
html->stylesheet_count = 0;
html->stylesheets = NULL;
html->select_ctx = NULL;
html->object_count = 0;
- html->object = 0;
- html->forms = 0;
- html->imagemaps = 0;
- html->bw = 0;
- html->frameset = 0;
- html->iframe = 0;
- html->page = 0;
+ html->object = NULL;
+ html->forms = NULL;
+ html->imagemaps = NULL;
+ html->bw = NULL;
+ html->frameset = NULL;
+ html->iframe = NULL;
+ html->page = NULL;
html->index = 0;
- html->box = 0;
+ html->box = NULL;
html->font_func = &nsfont;
- lerror = lwc_create_context(myrealloc, c, &dict);
- if (lerror != lwc_error_ok) {
- error = BINDING_NOMEM;
- goto error;
- }
-
- html->dict = lwc_context_ref(dict);
-
- for (i = 0; params[i]; i += 2) {
- if (strcasecmp(params[i], "charset") == 0) {
- html->encoding = talloc_strdup(c, params[i + 1]);
- if (!html->encoding) {
- error = BINDING_NOMEM;
- goto error;
- }
- html->encoding_source = ENCODING_SOURCE_HEADER;
- break;
+ nerror = http_parameter_list_find_item(params, "charset", &charset);
+ if (nerror == NSERROR_OK) {
+ html->encoding = talloc_strdup(c, charset);
+ if (!html->encoding) {
+ error = BINDING_NOMEM;
+ goto error;
}
+ html->encoding_source = ENCODING_SOURCE_HEADER;
}
/* Create the parser binding */
@@ -294,10 +286,17 @@ encoding_change:
return false;
}
- /* Recurse to reprocess all that data. This is safe because
- * the encoding is now specified at parser-start which means
- * it cannot be changed again. */
- return html_process_data(c, c->source_data, c->source_size);
+ {
+ const char *source_data;
+ unsigned long source_size;
+
+ source_data = content__get_source_data(c, &source_size);
+
+ /* Recurse to reprocess all that data. This is safe because
+ * the encoding is now specified at parser-start which means
+ * it cannot be changed again. */
+ return html_process_data(c, (char *) source_data, source_size);
+ }
}
/**
@@ -321,11 +320,13 @@ bool html_convert(struct content *c, int width, int height)
binding_error err;
xmlNode *html, *head;
union content_msg_data msg_data;
+ unsigned long size;
unsigned int time_before, time_taken;
struct form *f;
/* finish parsing */
- if (c->source_size == 0) {
+ content__get_source_data(c, &size);
+ if (size == 0) {
/* Destroy current binding */
binding_destroy_tree(c->data.html.parser_binding);
@@ -502,8 +503,6 @@ bool html_convert(struct content *c, int width, int height)
binding_destroy_tree(c->data.html.parser_binding);
c->data.html.parser_binding = NULL;
- c->size += lwc_context_size(c->data.html.dict);
-
if (c->active == 0)
c->status = CONTENT_STATUS_DONE;
else
@@ -689,7 +688,7 @@ bool html_meta_refresh(struct content *c, xmlNode *head)
/* Just delay specified, so refresh current page */
xmlFree(content);
- c->refresh = talloc_strdup(c, c->url);
+ c->refresh = talloc_strdup(c, content__get_url(c));
if (!c->refresh) {
msg_data.error = messages_get("NoMemory");
content_broadcast(c,
@@ -808,67 +807,66 @@ bool html_find_stylesheets(struct content *c, xmlNode *html)
unsigned int last_active = 0;
union content_msg_data msg_data;
url_func_result res;
- struct nscss_import *stylesheets;
+ struct html_stylesheet *stylesheets;
+ hlcache_child_context child;
css_error error;
+ nserror ns_error;
+
+ child.charset = c->data.html.encoding;
+ child.quirks = c->quirks;
/* stylesheet 0 is the base style sheet,
* stylesheet 1 is the quirks mode style sheet,
* stylesheet 2 is the adblocking stylesheet */
- c->data.html.stylesheets = talloc_array(c, struct nscss_import,
+ c->data.html.stylesheets = talloc_array(c, struct html_stylesheet,
STYLESHEET_START);
if (c->data.html.stylesheets == NULL)
goto no_memory;
- c->data.html.stylesheets[STYLESHEET_BASE].c = NULL;
- c->data.html.stylesheets[STYLESHEET_BASE].media = CSS_MEDIA_ALL;
- c->data.html.stylesheets[STYLESHEET_QUIRKS].c = NULL;
- c->data.html.stylesheets[STYLESHEET_QUIRKS].media = CSS_MEDIA_ALL;
- c->data.html.stylesheets[STYLESHEET_ADBLOCK].c = NULL;
- c->data.html.stylesheets[STYLESHEET_ADBLOCK].media = CSS_MEDIA_ALL;
+ c->data.html.stylesheets[STYLESHEET_BASE].type =
+ HTML_STYLESHEET_EXTERNAL;
+ c->data.html.stylesheets[STYLESHEET_BASE].data.external = NULL;
+ c->data.html.stylesheets[STYLESHEET_QUIRKS].type =
+ HTML_STYLESHEET_EXTERNAL;
+ c->data.html.stylesheets[STYLESHEET_QUIRKS].data.external = NULL;
+ c->data.html.stylesheets[STYLESHEET_ADBLOCK].type =
+ HTML_STYLESHEET_EXTERNAL;
+ c->data.html.stylesheets[STYLESHEET_ADBLOCK].data.external = NULL;
c->data.html.stylesheet_count = STYLESHEET_START;
c->active = 0;
- c->data.html.stylesheets[STYLESHEET_BASE].c = fetchcache(
- default_stylesheet_url,
- html_convert_css_callback, (intptr_t) c,
- STYLESHEET_BASE, c->width, c->height,
- true, 0, 0, false, false);
- if (c->data.html.stylesheets[STYLESHEET_BASE].c == NULL)
+ ns_error = hlcache_handle_retrieve(default_stylesheet_url, 0,
+ content__get_url(c), NULL, c->width, c->height,
+ html_convert_css_callback, c, &child,
+ &c->data.html.stylesheets[
+ STYLESHEET_BASE].data.external);
+ if (ns_error != NSERROR_OK)
goto no_memory;
+
c->active++;
- fetchcache_go(c->data.html.stylesheets[STYLESHEET_BASE].c,
- c->url, html_convert_css_callback, (intptr_t) c,
- STYLESHEET_BASE, c->width, c->height,
- 0, 0, false, c);
if (c->data.html.quirks == BINDING_QUIRKS_MODE_FULL) {
- c->data.html.stylesheets[STYLESHEET_QUIRKS].c =
- fetchcache(quirks_stylesheet_url,
- html_convert_css_callback, (intptr_t) c,
- STYLESHEET_QUIRKS, c->width, c->height,
- true, 0, 0, false, false);
- if (c->data.html.stylesheets[STYLESHEET_QUIRKS].c == NULL)
+ ns_error = hlcache_handle_retrieve(quirks_stylesheet_url, 0,
+ content__get_url(c), NULL, c->width, c->height,
+ html_convert_css_callback, c, &child,
+ &c->data.html.stylesheets[
+ STYLESHEET_QUIRKS].data.external);
+ if (ns_error != NSERROR_OK)
goto no_memory;
+
c->active++;
- fetchcache_go(c->data.html.stylesheets[STYLESHEET_QUIRKS].c,
- c->url, html_convert_css_callback,
- (intptr_t) c, STYLESHEET_QUIRKS, c->width,
- c->height, 0, 0, false, c);
}
if (option_block_ads) {
- c->data.html.stylesheets[STYLESHEET_ADBLOCK].c =
- fetchcache(adblock_stylesheet_url,
- html_convert_css_callback, (intptr_t) c,
- STYLESHEET_ADBLOCK, c->width,
- c->height, true, 0, 0, false, false);
- if (c->data.html.stylesheets[STYLESHEET_ADBLOCK].c == NULL)
+ ns_error = hlcache_handle_retrieve(adblock_stylesheet_url, 0,
+ content__get_url(c), NULL, c->width, c->height,
+ html_convert_css_callback, c, &child,
+ &c->data.html.stylesheets[
+ STYLESHEET_ADBLOCK].data.external);
+ if (ns_error != NSERROR_OK)
goto no_memory;
+
c->active++;
- fetchcache_go(c->data.html.stylesheets[STYLESHEET_ADBLOCK].c,
- c->url, html_convert_css_callback,
- (intptr_t) c, STYLESHEET_ADBLOCK, c->width,
- c->height, 0, 0, false, c);
}
node = html;
@@ -958,29 +956,30 @@ bool html_find_stylesheets(struct content *c, xmlNode *html)
/* start fetch */
stylesheets = talloc_realloc(c,
c->data.html.stylesheets,
- struct nscss_import, i + 1);
+ struct html_stylesheet, i + 1);
if (stylesheets == NULL) {
free(url2);
goto no_memory;
}
c->data.html.stylesheets = stylesheets;
- /** \todo Reflect actual media specified in link */
- c->data.html.stylesheets[i].media = CSS_MEDIA_ALL;
- c->data.html.stylesheets[i].c = fetchcache(url2,
- html_convert_css_callback,
- (intptr_t) c, i, c->width, c->height,
- true, 0, 0, false, false);
+ c->data.html.stylesheet_count++;
+ c->data.html.stylesheets[i].type =
+ HTML_STYLESHEET_EXTERNAL;
+ ns_error = hlcache_handle_retrieve(url2, 0,
+ content__get_url(c), NULL,
+ c->width, c->height,
+ html_convert_css_callback, c, &child,
+ &c->data.html.stylesheets[i].
+ data.external);
+
free(url2);
- if (c->data.html.stylesheets[i].c == NULL)
+
+ if (ns_error != NSERROR_OK)
goto no_memory;
c->active++;
- fetchcache_go(c->data.html.stylesheets[i].c,
- c->url,
- html_convert_css_callback,
- (intptr_t) c, i, c->width, c->height,
- 0, 0, false, c);
+
i++;
} else if (strcmp((const char *) node->name, "style") == 0) {
if (!html_process_style_element(c, &i, node))
@@ -988,7 +987,7 @@ bool html_find_stylesheets(struct content *c, xmlNode *html)
}
}
- c->data.html.stylesheet_count = i;
+ assert(c->data.html.stylesheet_count == i);
/* complete the fetches */
while (c->active != 0) {
@@ -1002,7 +1001,7 @@ bool html_find_stylesheets(struct content *c, xmlNode *html)
}
/* check that the base stylesheet loaded; layout fails without it */
- if (c->data.html.stylesheets[STYLESHEET_BASE].c == NULL) {
+ if (c->data.html.stylesheets[STYLESHEET_BASE].data.external == NULL) {
msg_data.error = "Base stylesheet failed to load";
content_broadcast(c, CONTENT_MSG_ERROR, msg_data);
return false;
@@ -1015,11 +1014,30 @@ bool html_find_stylesheets(struct content *c, xmlNode *html)
/* Add sheets to it */
for (i = STYLESHEET_BASE; i != c->data.html.stylesheet_count; i++) {
- if (c->data.html.stylesheets[i].c != NULL) {
+ const struct html_stylesheet *hsheet =
+ &c->data.html.stylesheets[i];
+ css_stylesheet *sheet;
+ css_origin origin = CSS_ORIGIN_AUTHOR;
+
+ if (i < STYLESHEET_START)
+ origin = CSS_ORIGIN_UA;
+
+ if (hsheet->type == HTML_STYLESHEET_EXTERNAL &&
+ hsheet->data.external != NULL) {
+ struct content *s = hlcache_handle_get_content(
+ hsheet->data.external);
+
+ sheet = s-> data.css.sheet;
+ } else if (hsheet->type == HTML_STYLESHEET_INTERNAL) {
+ sheet = hsheet->data.internal->sheet;
+ } else {
+ sheet = NULL;
+ }
+
+ if (sheet != NULL) {
error = css_select_ctx_append_sheet(
- c->data.html.select_ctx,
- c->data.html.stylesheets[i].c->
- data.css.sheet);
+ c->data.html.select_ctx, sheet,
+ origin, CSS_MEDIA_SCREEN);
if (error != CSS_OK)
goto no_memory;
}
@@ -1050,9 +1068,9 @@ bool html_process_style_element(struct content *c, unsigned int *index,
xmlNode *child;
char *type, *media, *data;
union content_msg_data msg_data;
- struct nscss_import *stylesheets;
- struct nscss_import *sheet;
- const char *params[] = { 0 };
+ struct html_stylesheet *stylesheets;
+ struct content_css_data *sheet;
+ nserror error;
/* type='text/css', or not present (invalid but common) */
if ((type = (char *) xmlGetProp(style, (const xmlChar *) "type"))) {
@@ -1075,26 +1093,27 @@ bool html_process_style_element(struct content *c, unsigned int *index,
/* Extend array */
stylesheets = talloc_realloc(c, c->data.html.stylesheets,
- struct nscss_import, *index + 1);
+ struct html_stylesheet, *index + 1);
if (stylesheets == NULL)
goto no_memory;
c->data.html.stylesheets = stylesheets;
+ c->data.html.stylesheet_count++;
- /* create stylesheet */
- sheet = &c->data.html.stylesheets[(*index)];
+ c->data.html.stylesheets[(*index)].type = HTML_STYLESHEET_INTERNAL;
+ c->data.html.stylesheets[(*index)].data.internal = NULL;
- /** \todo Reflect specified media */
- sheet->media = CSS_MEDIA_ALL;
- sheet->c = content_create(c->data.html.base_url);
- if (sheet->c == NULL)
+ /* create stylesheet */
+ sheet = talloc(c, struct content_css_data);
+ if (sheet == NULL) {
+ c->data.html.stylesheet_count--;
goto no_memory;
+ }
- if (content_set_type(sheet->c,
- CONTENT_CSS, "text/css", params, c) == false) {
- /** \todo not necessarily caused by
- * memory exhaustion */
- sheet->c = NULL;
+ error = nscss_create_css_data(sheet,
+ c->data.html.base_url, NULL, c->data.html.quirks);
+ if (error != NSERROR_OK) {
+ c->data.html.stylesheet_count--;
goto no_memory;
}
@@ -1103,43 +1122,29 @@ bool html_process_style_element(struct content *c, unsigned int *index,
* the content */
for (child = style->children; child != 0; child = child->next) {
data = (char *) xmlNodeGetContent(child);
- if (content_process_data(sheet->c, data, strlen(data)) ==
+ if (nscss_process_css_data(sheet, data, strlen(data)) ==
false) {
xmlFree(data);
+ nscss_destroy_css_data(sheet);
+ talloc_free(sheet);
+ c->data.html.stylesheet_count--;
/** \todo not necessarily caused by
* memory exhaustion */
- sheet->c = NULL;
goto no_memory;
}
xmlFree(data);
}
/* Convert the content -- manually, as we want the result */
- if (sheet->c->source_allocated != sheet->c->source_size) {
- /* Minimise source data block */
- char *data = talloc_realloc(sheet->c, sheet->c->source_data,
- char, sheet->c->source_size);
-
- if (data != NULL) {
- sheet->c->source_data = data;
- sheet->c->source_allocated = sheet->c->source_size;
- }
- }
-
- if (nscss_convert(sheet->c, c->width, c->height)) {
- if (content_add_user(sheet->c,
- html_convert_css_callback,
- (intptr_t) c, (*index)) == false) {
- /* no memory */
- sheet->c = NULL;
- goto no_memory;
- }
- } else {
+ if (nscss_convert_css_data(sheet, c->width, c->height) != CSS_OK) {
/* conversion failed */
- sheet->c = NULL;
+ nscss_destroy_css_data(sheet);
+ talloc_free(sheet);
+ sheet = NULL;
}
/* Update index */
+ c->data.html.stylesheets[(*index)].data.internal = sheet;
(*index)++;
return true;
@@ -1155,36 +1160,40 @@ no_memory:
* Callback for fetchcache() for linked stylesheets.
*/
-void html_convert_css_callback(content_msg msg, struct content *css,
- intptr_t p1, intptr_t p2, union content_msg_data data)
+nserror html_convert_css_callback(hlcache_handle *css,
+ const hlcache_event *event, void *pw)
{
- struct content *c = (struct content *) p1;
- unsigned int i = p2;
+ struct content *parent = pw;
+ unsigned int i;
+ struct html_stylesheet *s;
+
+ /* Find sheet */
+ for (i = 0, s = parent->data.html.stylesheets;
+ i != parent->data.html.stylesheet_count; i++, s++) {
+ if (s->type == HTML_STYLESHEET_EXTERNAL &&
+ s->data.external == css)
+ break;
+ }
+
+ assert(i != parent->data.html.stylesheet_count);
- switch (msg) {
+ switch (event->type) {
case CONTENT_MSG_LOADING:
/* check that the stylesheet is really CSS */
- if (css->type != CONTENT_CSS) {
- c->data.html.stylesheets[i].c = NULL;
- c->active--;
- LOG(("%s is not CSS", css->url));
- content_add_error(c, "NotCSS", 0);
- html_set_status(c, messages_get("NotCSS"));
- content_broadcast(c, CONTENT_MSG_STATUS, data);
- content_remove_user(css,
- html_convert_css_callback,
- (intptr_t) c, i);
- if (css->user_list->next == NULL) {
- /* we were the only user and we
- * don't want this content, so
- * stop it fetching and mark it
- * as having an error so it gets
- * removed from the cache next time
- * content_clean() gets called */
- fetch_abort(css->fetch);
- css->fetch = 0;
- css->status = CONTENT_STATUS_ERROR;
- }
+ if (content_get_type(css) != CONTENT_CSS) {
+ hlcache_handle_release(css);
+ s->data.external = NULL;
+
+ parent->active--;
+
+ LOG(("%s is not CSS", content_get_url(css)));
+
+ content_add_error(parent, "NotCSS", 0);
+
+ html_set_status(parent, messages_get("NotCSS"));
+
+ content_broadcast(parent, CONTENT_MSG_STATUS,
+ event->data);
}
break;
@@ -1192,50 +1201,29 @@ void html_convert_css_callback(content_msg msg, struct content *css,
break;
case CONTENT_MSG_DONE:
- LOG(("got stylesheet '%s'", css->url));
- c->active--;
+ LOG(("got stylesheet '%s'", content_get_url(css)));
+ parent->active--;
break;
- case CONTENT_MSG_LAUNCH:
- /* Fall through */
case CONTENT_MSG_ERROR:
- LOG(("stylesheet %s failed: %s", css->url, data.error));
- /* The stylesheet we were fetching may have been
- * redirected, in that case, the object pointers
- * will differ, so ensure that the object that's
- * in error is still in use by us before invalidating
- * the pointer */
- if (c->data.html.stylesheets[i].c == css) {
- c->data.html.stylesheets[i].c = NULL;
- c->active--;
- content_add_error(c, "?", 0);
- }
+ LOG(("stylesheet %s failed: %s",
+ content_get_url(css), event->data.error));
+ hlcache_handle_release(css);
+ s->data.external = NULL;
+ parent->active--;
+ content_add_error(parent, "?", 0);
break;
case CONTENT_MSG_STATUS:
- html_set_status(c, css->status_message);
- content_broadcast(c, CONTENT_MSG_STATUS, data);
- break;
-
- case CONTENT_MSG_NEWPTR:
- c->data.html.stylesheets[i].c = css;
- break;
-
- case CONTENT_MSG_AUTH:
- c->data.html.stylesheets[i].c = NULL;
- c->active--;
- content_add_error(c, "?", 0);
- break;
-
- case CONTENT_MSG_SSL:
- c->data.html.stylesheets[i].c = NULL;
- c->active--;
- content_add_error(c, "?", 0);
+ html_set_status(parent, content_get_status_message(css));
+ content_broadcast(parent, CONTENT_MSG_STATUS, event->data);
break;
default:
assert(0);
}
+
+ return NSERROR_OK;
}
@@ -1260,9 +1248,14 @@ bool html_fetch_object(struct content *c, const char *url, struct box *box,
{
unsigned int i = c->data.html.object_count;
struct content_html_object *object;
- struct content *c_fetch;
+ hlcache_handle *c_fetch;
+ hlcache_child_context child;
char *url2;
url_func_result res;
+ nserror error;
+
+ child.charset = c->data.html.encoding;
+ child.quirks = c->quirks;
/* Normalize the URL */
res = url_normalize(url, &url2);
@@ -1271,23 +1264,22 @@ bool html_fetch_object(struct content *c, const char *url, struct box *box,
return res != URL_FUNC_NOMEM;
}
- /* initialise fetch */
- c_fetch = fetchcache(url2, html_object_callback,
- (intptr_t) c, i, available_width, available_height,
- true, 0, 0, false, false);
+ error = hlcache_handle_retrieve(url2, 0, content__get_url(c), NULL,
+ available_width, available_height,
+ html_object_callback, c, &child,
+ &c_fetch);
/* No longer need normalized url */
free(url2);
- if (!c_fetch)
+ if (error != NSERROR_OK)
return false;
/* add to object list */
object = talloc_realloc(c, c->data.html.object,
struct content_html_object, i + 1);
- if (!object) {
- content_remove_user(c_fetch, html_object_callback,
- (intptr_t) c, i);
+ if (object == NULL) {
+ hlcache_handle_release(c_fetch);
return false;
}
c->data.html.object = object;
@@ -1298,12 +1290,6 @@ bool html_fetch_object(struct content *c, const char *url, struct box *box,
c->data.html.object_count++;
c->active++;
- /* start fetch */
- fetchcache_go(c_fetch, c->url,
- html_object_callback, (intptr_t) c, i,
- available_width, available_height,
- 0, 0, false, c);
-
return true;
}
@@ -1314,31 +1300,31 @@ bool html_fetch_object(struct content *c, const char *url, struct box *box,
* \param c content of type CONTENT_HTML
* \param i index of object to replace in c->data.html.object
* \param url URL of object to fetch (copied)
- * \param post_urlenc url encoded post data, or 0 if none
- * \param post_multipart multipart post data, or 0 if none
* \return true on success, false on memory exhaustion
*/
-bool html_replace_object(struct content *c, unsigned int i, char *url,
- char *post_urlenc,
- struct form_successful_control *post_multipart)
+bool html_replace_object(struct content *c, unsigned int i, const char *url)
{
- struct content *c_fetch;
+ hlcache_handle *c_fetch;
+ hlcache_child_context child;
struct content *page;
char *url2;
url_func_result res;
+ nserror error;
assert(c->type == CONTENT_HTML);
+ child.charset = c->data.html.encoding;
+ child.quirks = c->quirks;
+
if (c->data.html.object[i].content) {
/* remove existing object */
- if (c->data.html.object[i].content->status !=
+ if (content_get_status(c->data.html.object[i].content) !=
CONTENT_STATUS_DONE)
c->active--;
- content_remove_user(c->data.html.object[i].content,
- html_object_callback, (intptr_t) c, i);
- c->data.html.object[i].content = 0;
- c->data.html.object[i].box->object = 0;
+ hlcache_handle_release(c->data.html.object[i].content);
+ c->data.html.object[i].content = NULL;
+ c->data.html.object[i].box->object = NULL;
}
res = url_normalize(url, &url2);
@@ -1346,15 +1332,15 @@ bool html_replace_object(struct content *c, unsigned int i, char *url,
return res != URL_FUNC_NOMEM;
/* initialise fetch */
- c_fetch = fetchcache(url2, html_object_callback,
- (intptr_t) c, i,
+ error = hlcache_handle_retrieve(url2, 0, content__get_url(c), NULL,
c->data.html.object[i].box->width,
c->data.html.object[i].box->height,
- false, post_urlenc, post_multipart, false, false);
+ html_object_callback, c, &child,
+ &c_fetch);
free(url2);
- if (!c_fetch)
+ if (error != NSERROR_OK)
return false;
c->data.html.object[i].content = c_fetch;
@@ -1365,13 +1351,6 @@ bool html_replace_object(struct content *c, unsigned int i, char *url,
page->status = CONTENT_STATUS_READY;
}
- /* start fetch */
- fetchcache_go(c_fetch, c->url,
- html_object_callback, (intptr_t) c, i,
- c->data.html.object[i].box->width,
- c->data.html.object[i].box->height,
- post_urlenc, post_multipart, false, c);
-
return true;
}
@@ -1380,157 +1359,146 @@ bool html_replace_object(struct content *c, unsigned int i, char *url,
* Callback for fetchcache() for objects.
*/
-void html_object_callback(content_msg msg, struct content *object,
- intptr_t p1, intptr_t p2, union content_msg_data data)
+nserror html_object_callback(hlcache_handle *object,
+ const hlcache_event *event, void *pw)
{
- struct content *c = (struct content *) p1;
- unsigned int i = p2;
+ struct content *c = pw;
+ unsigned int i;
+ struct content_html_object *o;
int x, y;
- struct box *box = c->data.html.object[i].box;
-
- switch (msg) {
- case CONTENT_MSG_LOADING:
- /* check if the type is acceptable for this object */
- if (html_object_type_permitted(object->type,
- c->data.html.object[i].permitted_types)) {
- if (c->data.html.bw)
- content_open(object,
- c->data.html.bw, c,
- i, box,
- box->object_params);
- break;
- }
+ struct box *box;
- /* not acceptable */
- c->data.html.object[i].content = 0;
- c->active--;
- content_add_error(c, "?", 0);
- html_set_status(c, messages_get("BadObject"));
- content_broadcast(c, CONTENT_MSG_STATUS, data);
- content_remove_user(object, html_object_callback,
- (intptr_t) c, i);
- if (!object->user_list->next) {
- /* we were the only user and we
- * don't want this content, so
- * stop it fetching and mark it
- * as having an error so it gets
- * removed from the cache next time
- * content_clean() gets called */
- fetch_abort(object->fetch);
- object->fetch = 0;
- object->status = CONTENT_STATUS_ERROR;
- }
- html_object_failed(box, c,
- c->data.html.object[i].background);
+ /* Find object record in parent */
+ for (i = 0, o = c->data.html.object; i != c->data.html.object_count;
+ i++, o++) {
+ if (o->content == object)
break;
+ }
- case CONTENT_MSG_READY:
- if (object->type == CONTENT_HTML) {
- html_object_done(box, object,
- c->data.html.object[i].background);
- if (c->status == CONTENT_STATUS_READY ||
- c->status ==
- CONTENT_STATUS_DONE)
- content_reformat(c,
- c->available_width,
- c->height);
- }
- break;
+ assert(i != c->data.html.object_count);
- case CONTENT_MSG_DONE:
- html_object_done(box, object,
- c->data.html.object[i].background);
- c->active--;
- break;
+ box = o->box;
- case CONTENT_MSG_LAUNCH:
- /* Fall through */
- case CONTENT_MSG_ERROR:
- /* The object we were fetching may have been
- * redirected, in that case, the object pointers
- * will differ, so ensure that the object that's
- * in error is still in use by us before invalidating
- * the pointer */
- if (c->data.html.object[i].content == object) {
- c->data.html.object[i].content = 0;
- c->active--;
- content_add_error(c, "?", 0);
- html_set_status(c, data.error);
- content_broadcast(c, CONTENT_MSG_STATUS,
- data);
- html_object_failed(box, c,
- c->data.html.object[i].background);
- }
+ switch (event->type) {
+ case CONTENT_MSG_LOADING:
+ /* check if the type is acceptable for this object */
+ if (html_object_type_permitted(content_get_type(object),
+ o->permitted_types)) {
+ if (c->data.html.bw != NULL)
+ content_open(object,
+ c->data.html.bw, c,
+ i, box,
+ box->object_params);
break;
+ }
- case CONTENT_MSG_STATUS:
- html_set_status(c, object->status_message);
- /* content_broadcast(c, CONTENT_MSG_STATUS, 0); */
- break;
+ /* not acceptable */
+ hlcache_handle_release(object);
- case CONTENT_MSG_REFORMAT:
- break;
+ o->content = NULL;
- case CONTENT_MSG_REDRAW:
- if (!box_visible(box))
- break;
- box_coords(box, &x, &y);
- if (object == data.redraw.object) {
- data.redraw.x = data.redraw.x *
- box->width / object->width;
- data.redraw.y = data.redraw.y *
- box->height / object->height;
- data.redraw.width = data.redraw.width *
- box->width / object->width;
- data.redraw.height = data.redraw.height *
- box->height / object->height;
- data.redraw.object_width = box->width;
- data.redraw.object_height = box->height;
- }
- data.redraw.x += x + box->padding[LEFT];
- data.redraw.y += y + box->padding[TOP];
- data.redraw.object_x += x + box->padding[LEFT];
- data.redraw.object_y += y + box->padding[TOP];
- content_broadcast(c, CONTENT_MSG_REDRAW, data);
- break;
+ c->active--;
- case CONTENT_MSG_NEWPTR:
- c->data.html.object[i].content = object;
- break;
+ content_add_error(c, "?", 0);
+ html_set_status(c, messages_get("BadObject"));
+ content_broadcast(c, CONTENT_MSG_STATUS, event->data);
- case CONTENT_MSG_AUTH:
- c->data.html.object[i].content = 0;
- c->active--;
- content_add_error(c, "?", 0);
- break;
+ html_object_failed(box, c,
+ c->data.html.object[i].background);
+ break;
- case CONTENT_MSG_SSL:
- c->data.html.object[i].content = 0;
- c->active--;
- content_add_error(c, "?", 0);
- break;
+ case CONTENT_MSG_READY:
+ if (content_get_type(object) == CONTENT_HTML) {
+ html_object_done(box, object, o->background);
+ if (c->status == CONTENT_STATUS_READY ||
+ c->status == CONTENT_STATUS_DONE)
+ content__reformat(c,
+ c->available_width,
+ c->height);
+ }
+ break;
+
+ case CONTENT_MSG_DONE:
+ html_object_done(box, object, o->background);
+ c->active--;
+ break;
+
+ case CONTENT_MSG_ERROR:
+ hlcache_handle_release(object);
+
+ o->content = NULL;
+
+ c->active--;
+
+ content_add_error(c, "?", 0);
+ html_set_status(c, event->data.error);
+ content_broadcast(c, CONTENT_MSG_STATUS, event->data);
+ html_object_failed(box, c, o->background);
+ break;
+
+ case CONTENT_MSG_STATUS:
+ html_set_status(c, content_get_status_message(object));
+ /* content_broadcast(c, CONTENT_MSG_STATUS, 0); */
+ break;
+
+ case CONTENT_MSG_REFORMAT:
+ break;
- case CONTENT_MSG_REFRESH:
- if (object->type == CONTENT_HTML)
- /* only for HTML objects */
- schedule(data.delay * 100,
- html_object_refresh, object);
+ case CONTENT_MSG_REDRAW:
+ {
+ union content_msg_data data = event->data;
+
+ if (!box_visible(box))
break;
- default:
- assert(0);
+ box_coords(box, &x, &y);
+
+ if (hlcache_handle_get_content(object) ==
+ event->data.redraw.object) {
+ data.redraw.x = data.redraw.x *
+ box->width / content_get_width(object);
+ data.redraw.y = data.redraw.y *
+ box->height /
+ content_get_height(object);
+ data.redraw.width = data.redraw.width *
+ box->width / content_get_width(object);
+ data.redraw.height = data.redraw.height *
+ box->height /
+ content_get_height(object);
+ data.redraw.object_width = box->width;
+ data.redraw.object_height = box->height;
+ }
+
+ data.redraw.x += x + box->padding[LEFT];
+ data.redraw.y += y + box->padding[TOP];
+ data.redraw.object_x += x + box->padding[LEFT];
+ data.redraw.object_y += y + box->padding[TOP];
+
+ content_broadcast(c, CONTENT_MSG_REDRAW, data);
+ }
+ break;
+
+ case CONTENT_MSG_REFRESH:
+ if (content_get_type(object) == CONTENT_HTML)
+ /* only for HTML objects */
+ schedule(event->data.delay * 100,
+ html_object_refresh, object);
+ break;
+
+ default:
+ assert(0);
}
if (c->status == CONTENT_STATUS_READY && c->active == 0 &&
- (msg == CONTENT_MSG_LOADING ||
- msg == CONTENT_MSG_DONE ||
- msg == CONTENT_MSG_ERROR ||
- msg == CONTENT_MSG_AUTH)) {
+ (event->type == CONTENT_MSG_LOADING ||
+ event->type == CONTENT_MSG_DONE ||
+ event->type == CONTENT_MSG_ERROR)) {
/* all objects have arrived */
- content_reformat(c, c->available_width, c->height);
+ content__reformat(c, c->available_width, c->height);
html_set_status(c, "");
content_set_done(c);
}
+
/* If 1) the configuration option to reflow pages while objects are
* fetched is set
* 2) an object is newly fetched & converted,
@@ -1538,17 +1506,20 @@ void html_object_callback(content_msg msg, struct content *object,
* 4) the time since the previous reformat is more than the
* configured minimum time between reformats
* then reformat the page to display newly fetched objects */
- else if (option_incremental_reflow && msg == CONTENT_MSG_DONE &&
+ else if (option_incremental_reflow &&
+ event->type == CONTENT_MSG_DONE &&
(c->status == CONTENT_STATUS_READY ||
c->status == CONTENT_STATUS_DONE) &&
(wallclock() > c->reformat_time)) {
unsigned int time_before = wallclock(), time_taken;
- content_reformat(c, c->available_width, c->height);
+ content__reformat(c, c->available_width, c->height);
time_taken = wallclock() - time_before;
c->reformat_time = wallclock() +
((time_taken < option_min_reflow_period ?
option_min_reflow_period : time_taken * 1.25));
}
+
+ return NSERROR_OK;
}
@@ -1556,7 +1527,7 @@ void html_object_callback(content_msg msg, struct content *object,
* Update a box whose content has completed rendering.
*/
-void html_object_done(struct box *box, struct content *object,
+void html_object_done(struct box *box, hlcache_handle *object,
bool background)
{
struct box *b;
@@ -1714,7 +1685,7 @@ void html_object_refresh(void *p)
c->fresh = false;
if (!html_replace_object(c->data.html.page, c->data.html.index,
- c->refresh, 0, 0)) {
+ c->refresh)) {
/** \todo handle memory exhaustion */
}
}
@@ -1726,24 +1697,22 @@ void html_object_refresh(void *p)
void html_stop(struct content *c)
{
unsigned int i;
- struct content *object;
+ hlcache_handle *object;
assert(c->status == CONTENT_STATUS_READY);
for (i = 0; i != c->data.html.object_count; i++) {
object = c->data.html.object[i].content;
- if (!object)
+ if (object == NULL)
continue;
- if (object->status == CONTENT_STATUS_DONE)
+ if (content_get_status(object) == CONTENT_STATUS_DONE)
; /* already loaded: do nothing */
- else if (object->status == CONTENT_STATUS_READY)
- content_stop(object, html_object_callback,
- (intptr_t) c, i);
+ else if (content_get_status(object) == CONTENT_STATUS_READY)
+ content_stop(object, html_object_callback, NULL);
else {
- content_remove_user(c->data.html.object[i].content,
- html_object_callback, (intptr_t) c, i);
- c->data.html.object[i].content = 0;
+ hlcache_handle_release(object);
+ c->data.html.object[i].content = NULL;
}
}
c->status = CONTENT_STATUS_DONE;
@@ -1836,11 +1805,14 @@ void html_destroy(struct content *c)
/* Free stylesheets */
if (c->data.html.stylesheet_count) {
for (i = 0; i != c->data.html.stylesheet_count; i++) {
- if (c->data.html.stylesheets[i].c)
- content_remove_user(c->data.html.
- stylesheets[i].c,
- html_convert_css_callback,
- (intptr_t) c, i);
+ if (c->data.html.stylesheets[i].type ==
+ HTML_STYLESHEET_EXTERNAL) {
+ hlcache_handle_release(c->data.html.
+ stylesheets[i].data.external);
+ } else {
+ nscss_destroy_css_data(c->data.html.
+ stylesheets[i].data.internal);
+ }
}
}
@@ -1848,15 +1820,14 @@ 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) {
- content_remove_user(c->data.html.object[i].content,
- html_object_callback, (intptr_t) c, i);
- if (c->data.html.object[i].content->type == CONTENT_HTML)
+ if (content_get_type(c->data.html.object[i].content) ==
+ CONTENT_HTML)
schedule_remove(html_object_refresh,
c->data.html.object[i].content);
+
+ hlcache_handle_release(c->data.html.object[i].content);
}
}
-
- lwc_context_unref(c->data.html.dict);
}
void html_destroy_frameset(struct content_html_frames *frameset) {
@@ -1942,7 +1913,8 @@ void html_open(struct content *c, struct browser_window *bw,
for (i = 0; i != c->data.html.object_count; i++) {
if (c->data.html.object[i].content == 0)
continue;
- if (c->data.html.object[i].content->type == CONTENT_UNKNOWN)
+ if (content_get_type(c->data.html.object[i].content) ==
+ CONTENT_UNKNOWN)
continue;
content_open(c->data.html.object[i].content,
bw, c, i,
@@ -1964,7 +1936,8 @@ void html_close(struct content *c)
for (i = 0; i != c->data.html.object_count; i++) {
if (c->data.html.object[i].content == 0)
continue;
- if (c->data.html.object[i].content->type == CONTENT_UNKNOWN)
+ if (content_get_type(c->data.html.object[i].content) ==
+ CONTENT_UNKNOWN)
continue;
content_close(c->data.html.object[i].content);
}
@@ -2023,3 +1996,173 @@ void html_dump_frameset(struct content_html_frames *frame,
}
#endif
+
+/**
+ * Retrieve HTML document tree
+ *
+ * \param h HTML content to retrieve document tree from
+ * \return Pointer to document tree
+ */
+xmlDoc *html_get_document(hlcache_handle *h)
+{
+ struct content *c = hlcache_handle_get_content(h);
+
+ assert(c != NULL);
+ assert(c->type == CONTENT_HTML);
+
+ return c->data.html.document;
+}
+
+/**
+ * Retrieve box tree
+ *
+ * \param h HTML content to retrieve tree from
+ * \return Pointer to box tree
+ *
+ * \todo This API must die, as must all use of the box tree outside render/
+ */
+struct box *html_get_box_tree(hlcache_handle *h)
+{
+ struct content *c = hlcache_handle_get_content(h);
+
+ assert(c != NULL);
+ assert(c->type == CONTENT_HTML);
+
+ return c->data.html.layout;
+}
+
+/**
+ * Retrieve the charset of an HTML document
+ *
+ * \param h Content to retrieve charset from
+ * \return Pointer to charset, or NULL
+ */
+const char *html_get_encoding(hlcache_handle *h)
+{
+ struct content *c = hlcache_handle_get_content(h);
+
+ assert(c != NULL);
+ assert(c->type == CONTENT_HTML);
+
+ return c->data.html.encoding;
+}
+
+/**
+ * Retrieve framesets used in an HTML document
+ *
+ * \param h Content to inspect
+ * \return Pointer to framesets, or NULL if none
+ */
+struct content_html_frames *html_get_frameset(hlcache_handle *h)
+{
+ struct content *c = hlcache_handle_get_content(h);
+
+ assert(c != NULL);
+ assert(c->type == CONTENT_HTML);
+
+ return c->data.html.frameset;
+}
+
+/**
+ * Retrieve iframes used in an HTML document
+ *
+ * \param h Content to inspect
+ * \return Pointer to iframes, or NULL if none
+ */
+struct content_html_iframe *html_get_iframe(hlcache_handle *h)
+{
+ struct content *c = hlcache_handle_get_content(h);
+
+ assert(c != NULL);
+ assert(c->type == CONTENT_HTML);
+
+ return c->data.html.iframe;
+}
+
+/**
+ * Retrieve an HTML content's base URL
+ *
+ * \param h Content to retrieve base target from
+ * \return Pointer to URL
+ */
+const char *html_get_base_url(hlcache_handle *h)
+{
+ struct content *c = hlcache_handle_get_content(h);
+
+ assert(c != NULL);
+ assert(c->type == CONTENT_HTML);
+
+ return c->data.html.base_url;
+}
+
+/**
+ * Retrieve an HTML content's base target
+ *
+ * \param h Content to retrieve base target from
+ * \return Pointer to target, or NULL if none
+ */
+const char *html_get_base_target(hlcache_handle *h)
+{
+ struct content *c = hlcache_handle_get_content(h);
+
+ assert(c != NULL);
+ assert(c->type == CONTENT_HTML);
+
+ return c->data.html.base_target;
+}
+
+/**
+ * Retrieve stylesheets used by HTML document
+ *
+ * \param h Content to retrieve stylesheets from
+ * \param n Pointer to location to receive number of sheets
+ * \return Pointer to array of stylesheets
+ */
+struct html_stylesheet *html_get_stylesheets(hlcache_handle *h, unsigned int *n)
+{
+ struct content *c = hlcache_handle_get_content(h);
+
+ assert(c != NULL);
+ assert(c->type == CONTENT_HTML);
+ assert(n != NULL);
+
+ *n = c->data.html.stylesheet_count;
+
+ return c->data.html.stylesheets;
+}
+
+/**
+ * Retrieve objects used by HTML document
+ *
+ * \param h Content to retrieve objects from
+ * \param n Pointer to location to receive number of objects
+ * \return Pointer to array of objects
+ */
+struct content_html_object *html_get_objects(hlcache_handle *h, unsigned int *n)
+{
+ struct content *c = hlcache_handle_get_content(h);
+
+ assert(c != NULL);
+ assert(c->type == CONTENT_HTML);
+ assert(n != NULL);
+
+ *n = c->data.html.object_count;
+
+ return c->data.html.object;
+}
+
+/**
+ * Retrieve favicon associated with an HTML document
+ *
+ * \param h HTML document to retrieve favicon from
+ * \return Pointer to favicon, or NULL if none
+ */
+hlcache_handle *html_get_favicon(hlcache_handle *h)
+{
+ struct content *c = hlcache_handle_get_content(h);
+
+ assert(c != NULL);
+ assert(c->type == CONTENT_HTML);
+
+ return c->data.html.favicon;
+}
diff --git a/render/html.h b/render/html.h
index 51abba3ba..5ce92ba3d 100644
--- a/render/html.h
+++ b/render/html.h
@@ -31,11 +31,13 @@
#include "desktop/plot_style.h"
#include "render/parser_binding.h"
+struct fetch_multipart_data;
struct box;
struct rect;
struct browser_window;
struct content;
-struct form_successful_control;
+struct hlcache_handle;
+struct http_parameter;
struct imagemap;
struct object_params;
struct plotters;
@@ -50,6 +52,18 @@ extern char *default_stylesheet_url;
extern char *adblock_stylesheet_url;
extern char *quirks_stylesheet_url;
+/**
+ * Container for stylesheets used by an HTML document
+ */
+struct html_stylesheet {
+ /** Type of sheet */
+ enum { HTML_STYLESHEET_EXTERNAL, HTML_STYLESHEET_INTERNAL } type;
+ union {
+ struct hlcache_handle *external;
+ struct content_css_data *internal;
+ } data; /**< Sheet data */
+};
+
struct frame_dimension {
float value;
enum {
@@ -68,7 +82,7 @@ typedef enum {
/** An object (<img>, <object>, etc.) in a CONTENT_HTML document. */
struct content_html_object {
- struct content *content; /**< Content, or 0. */
+ struct hlcache_handle *content; /**< Content, or 0. */
struct box *box; /**< Node in box tree containing it. */
/** Pointer to array of permitted content_type, terminated by
* CONTENT_UNKNOWN, or 0 if any type is acceptable. */
@@ -120,8 +134,6 @@ struct content_html_data {
xmlDoc *document;
binding_quirks_mode quirks; /**< Quirkyness of document */
- lwc_context *dict; /**< Internment context for this document */
-
char *encoding; /**< Encoding of source, 0 if unknown. */
binding_encoding_source encoding_source;
/**< Source of encoding information. */
@@ -133,12 +145,12 @@ struct content_html_data {
colour background_colour; /**< Document background colour. */
const struct font_functions *font_func;
- struct content *favicon; /**< the favicon for the page */
+ struct hlcache_handle *favicon; /**< the favicon for the page */
/** Number of entries in stylesheet_content. */
unsigned int stylesheet_count;
/** Stylesheets. Each may be 0. */
- struct nscss_import *stylesheets;
+ struct html_stylesheet *stylesheets;
/**< Style selection context */
css_select_ctx *select_ctx;
@@ -173,8 +185,7 @@ struct content_html_data {
extern bool html_redraw_debug;
-bool html_create(struct content *c, struct content *parent,
- const char *params[]);
+bool html_create(struct content *c, const struct http_parameter *params);
bool html_process_data(struct content *c, char *data, unsigned int size);
bool html_convert(struct content *c, int width, int height);
void html_reformat(struct content *c, int width, int height);
@@ -183,9 +194,6 @@ bool html_fetch_object(struct content *c, const char *url, struct box *box,
const content_type *permitted_types,
int available_width, int available_height,
bool background);
-bool html_replace_object(struct content *c, unsigned int i, char *url,
- char *post_urlenc,
- struct form_successful_control *post_multipart);
void html_stop(struct content *c);
void html_open(struct content *c, struct browser_window *bw,
struct content *page, unsigned int index, struct box *box,
@@ -212,4 +220,17 @@ bool text_redraw(const char *utf8_text, size_t utf8_len,
float scale,
bool excluded);
+xmlDoc *html_get_document(struct hlcache_handle *h);
+struct box *html_get_box_tree(struct hlcache_handle *h);
+const char *html_get_encoding(struct hlcache_handle *h);
+struct content_html_frames *html_get_frameset(struct hlcache_handle *h);
+struct content_html_iframe *html_get_iframe(struct hlcache_handle *h);
+const char *html_get_base_url(struct hlcache_handle *h);
+const char *html_get_base_target(struct hlcache_handle *h);
+struct html_stylesheet *html_get_stylesheets(struct hlcache_handle *h,
+ unsigned int *n);
+struct content_html_object *html_get_objects(struct hlcache_handle *h,
+ unsigned int *n);
+struct hlcache_handle *html_get_favicon(struct hlcache_handle *h);
+
#endif
diff --git a/render/html_redraw.c b/render/html_redraw.c
index 2a5154035..3165e1d38 100644
--- a/render/html_redraw.c
+++ b/render/html_redraw.c
@@ -31,7 +31,7 @@
#include <string.h>
#include <math.h>
#include "utils/config.h"
-#include "content/content.h"
+#include "content/content_protected.h"
#include "css/css.h"
#include "css/utils.h"
#include "desktop/gui.h"
@@ -1589,31 +1589,35 @@ bool html_redraw_background(int x, int y, struct box *box, float scale,
}
/* handle background-repeat */
switch (css_computed_background_repeat(background->style)) {
- case CSS_BACKGROUND_REPEAT_REPEAT:
- repeat_x = repeat_y = true;
- /* optimisation: only plot the colour if
- * bitmap is not opaque */
- if (background->background->bitmap)
- plot_colour = !bitmap_get_opaque(
- background->background->bitmap);
- break;
- case CSS_BACKGROUND_REPEAT_REPEAT_X:
- repeat_x = true;
- break;
- case CSS_BACKGROUND_REPEAT_REPEAT_Y:
- repeat_y = true;
- break;
- case CSS_BACKGROUND_REPEAT_NO_REPEAT:
- break;
- default:
- break;
+ case CSS_BACKGROUND_REPEAT_REPEAT:
+ {
+ struct bitmap *bmp = content_get_bitmap(
+ background->background);
+ repeat_x = repeat_y = true;
+ /* optimisation: only plot the colour if
+ * bitmap is not opaque */
+ if (bmp != NULL)
+ plot_colour = !bitmap_get_opaque(bmp);
+ }
+ break;
+ case CSS_BACKGROUND_REPEAT_REPEAT_X:
+ repeat_x = true;
+ break;
+ case CSS_BACKGROUND_REPEAT_REPEAT_Y:
+ repeat_y = true;
+ break;
+ case CSS_BACKGROUND_REPEAT_NO_REPEAT:
+ break;
+ default:
+ break;
}
/* handle background-position */
css_computed_background_position(background->style,
&hpos, &hunit, &vpos, &vunit);
if (hunit == CSS_UNIT_PCT) {
- x += (width - background->background->width) *
+ x += (width -
+ content_get_width(background->background)) *
scale * FIXTOFLT(hpos) / 100.;
} else {
x += (int) (FIXTOFLT(nscss_len2px(hpos, hunit,
@@ -1621,7 +1625,8 @@ bool html_redraw_background(int x, int y, struct box *box, float scale,
}
if (vunit == CSS_UNIT_PCT) {
- y += (height - background->background->height) *
+ y += (height -
+ content_get_height(background->background)) *
scale * FIXTOFLT(vpos) / 100.;
} else {
y += (int) (FIXTOFLT(nscss_len2px(vpos, vunit,
@@ -1651,6 +1656,8 @@ bool html_redraw_background(int x, int y, struct box *box, float scale,
for (; clip_box; clip_box = clip_box->next) {
/* clip to child boxes if needed */
if (clip_to_children) {
+ struct bitmap *bmp = NULL;
+
assert(clip_box->type == BOX_TABLE_CELL);
/* update clip_* to the child cell */
@@ -1668,15 +1675,15 @@ bool html_redraw_background(int x, int y, struct box *box, float scale,
if (clip_x1 > px1) clip_x1 = px1;
if (clip_y1 > py1) clip_y1 = py1;
+ if (clip_box->background != NULL)
+ bmp = content_get_bitmap(clip_box->background);
+
/* <td> attributes override <tr> */
if ((clip_x0 >= clip_x1) || (clip_y0 >= clip_y1) ||
(css_computed_background_color(
clip_box->style, &bgcol) !=
CSS_BACKGROUND_COLOR_TRANSPARENT) ||
- (clip_box->background &&
- clip_box->background->bitmap &&
- bitmap_get_opaque(
- clip_box->background->bitmap)))
+ (bmp != NULL && bitmap_get_opaque(bmp)))
continue;
}
@@ -1693,35 +1700,30 @@ bool html_redraw_background(int x, int y, struct box *box, float scale,
}
/* and plot the image */
if (plot_content) {
+ width = content_get_width(background->background);
+ height = content_get_height(background->background);
+
if (!repeat_x) {
if (clip_x0 < x)
clip_x0 = x;
- if (clip_x1 > x +
- background->background->width *
- scale)
- clip_x1 = x + background->background->
- width * scale;
+ if (clip_x1 > x + width * scale)
+ clip_x1 = x + width * scale;
}
if (!repeat_y) {
if (clip_y0 < y)
clip_y0 = y;
- if (clip_y1 > y +
- background->background->height *
- scale)
- clip_y1 = y + background->background->
- height * scale;
+ if (clip_y1 > y + height * scale)
+ clip_y1 = y + height * scale;
}
/* valid clipping rectangles only */
if ((clip_x0 < clip_x1) && (clip_y0 < clip_y1)) {
if (!plot.clip(clip_x0, clip_y0,
clip_x1, clip_y1))
return false;
- if (!content_redraw_tiled(background->
- background, x, y,
- ceilf(background->background->
- width * scale),
- ceilf(background->background->
- height * scale),
+ if (!content_redraw_tiled(
+ background->background, x, y,
+ ceilf(width * scale),
+ ceilf(height * scale),
clip_x0, clip_y0,
clip_x1, clip_y1,
scale, *background_colour,
@@ -1784,32 +1786,35 @@ bool html_redraw_inline_background(int x, int y, struct box *box, float scale,
if (plot_content) {
/* handle background-repeat */
switch (css_computed_background_repeat(box->style)) {
- case CSS_BACKGROUND_REPEAT_REPEAT:
- repeat_x = repeat_y = true;
- /* optimisation: only plot the colour if
- * bitmap is not opaque */
- if (box->background->bitmap)
- plot_colour = !bitmap_get_opaque(
- box->background->bitmap);
- break;
- case CSS_BACKGROUND_REPEAT_REPEAT_X:
- repeat_x = true;
- break;
- case CSS_BACKGROUND_REPEAT_REPEAT_Y:
- repeat_y = true;
- break;
- case CSS_BACKGROUND_REPEAT_NO_REPEAT:
- break;
- default:
- break;
+ case CSS_BACKGROUND_REPEAT_REPEAT:
+ {
+ struct bitmap *bmp =
+ content_get_bitmap(box->background);
+ repeat_x = repeat_y = true;
+ /* optimisation: only plot the colour if
+ * bitmap is not opaque */
+ if (bmp != NULL)
+ plot_colour = !bitmap_get_opaque(bmp);
+ }
+ break;
+ case CSS_BACKGROUND_REPEAT_REPEAT_X:
+ repeat_x = true;
+ break;
+ case CSS_BACKGROUND_REPEAT_REPEAT_Y:
+ repeat_y = true;
+ break;
+ case CSS_BACKGROUND_REPEAT_NO_REPEAT:
+ break;
+ default:
+ break;
}
/* handle background-position */
css_computed_background_position(box->style,
&hpos, &hunit, &vpos, &vunit);
if (hunit == CSS_UNIT_PCT) {
- x += (px1 - px0 - box->background->width * scale) *
- FIXTOFLT(hpos) / 100.;
+ x += (px1 - px0 - content_get_width(box->background) *
+ scale) * FIXTOFLT(hpos) / 100.;
if (!repeat_x && ((hpos < 2 && !first) ||
(hpos > 98 && !last))){
@@ -1821,8 +1826,8 @@ bool html_redraw_inline_background(int x, int y, struct box *box, float scale,
}
if (vunit == CSS_UNIT_PCT) {
- y += (py1 - py0 - box->background->height * scale) *
- FIXTOFLT(vpos) / 100.;
+ y += (py1 - py0 - content_get_height(box->background) *
+ scale) * FIXTOFLT(vpos) / 100.;
} else {
y += (int) (FIXTOFLT(nscss_len2px(vpos, vunit,
box->style)) * scale);
@@ -1843,35 +1848,29 @@ bool html_redraw_inline_background(int x, int y, struct box *box, float scale,
}
/* and plot the image */
if (plot_content) {
+ int width = content_get_width(box->background);
+ int height = content_get_height(box->background);
+
if (!repeat_x) {
if (clip_x0 < x)
clip_x0 = x;
- if (clip_x1 > x +
- box->background->width *
- scale)
- clip_x1 = x + box->background->
- width * scale;
+ if (clip_x1 > x + width * scale)
+ clip_x1 = x + width * scale;
}
if (!repeat_y) {
if (clip_y0 < y)
clip_y0 = y;
- if (clip_y1 > y +
- box->background->height *
- scale)
- clip_y1 = y + box->background->
- height * scale;
+ if (clip_y1 > y + height * scale)
+ clip_y1 = y + height * scale;
}
/* valid clipping rectangles only */
if ((clip_x0 < clip_x1) && (clip_y0 < clip_y1)) {
if (!plot.clip(clip_x0, clip_y0,
clip_x1, clip_y1))
return false;
- if (!content_redraw_tiled(box->
- background, x, y,
- ceilf(box->background->
- width * scale),
- ceilf(box->background->
- height * scale),
+ if (!content_redraw_tiled(box->background, x, y,
+ ceilf(width * scale),
+ ceilf(height * scale),
clip_x0, clip_y0,
clip_x1, clip_y1,
scale, *background_colour,
diff --git a/render/imagemap.c b/render/imagemap.c
index d52e5bdd4..07a46d404 100644
--- a/render/imagemap.c
+++ b/render/imagemap.c
@@ -24,7 +24,8 @@
#include <stdbool.h>
#include <string.h>
#include <strings.h>
-#include "content/content.h"
+#include "content/content_protected.h"
+#include "content/hlcache.h"
#include "render/box.h"
#include "render/imagemap.h"
#include "utils/log.h"
@@ -626,20 +627,21 @@ void imagemap_freelist(struct mapentry *list)
/**
* Retrieve url associated with imagemap entry
*
- * \param c The containing content
- * \param key The map name to search for
- * \param x The left edge of the containing box
- * \param y The top edge of the containing box
- * \param click_x The horizontal location of the click
- * \param click_y The vertical location of the click
- * \param target Pointer to location to receive target pointer (if any)
+ * \param h The containing content
+ * \param key The map name to search for
+ * \param x The left edge of the containing box
+ * \param y The top edge of the containing box
+ * \param click_x The horizontal location of the click
+ * \param click_y The vertical location of the click
+ * \param target Pointer to location to receive target pointer (if any)
* \return The url associated with this area, or NULL if not found
*/
-const char *imagemap_get(struct content *c, const char *key,
+const char *imagemap_get(hlcache_handle *h, const char *key,
unsigned long x, unsigned long y,
unsigned long click_x, unsigned long click_y,
const char **target)
{
+ struct content *c = hlcache_handle_get_content(h);
unsigned int slot = 0;
struct imagemap *map;
struct mapentry *entry;
diff --git a/render/imagemap.h b/render/imagemap.h
index 34a0c3b5f..87a84c3dd 100644
--- a/render/imagemap.h
+++ b/render/imagemap.h
@@ -22,11 +22,13 @@
#include <libxml/HTMLtree.h>
struct content;
+struct hlcache_handle;
void imagemap_destroy(struct content *c);
void imagemap_dump(struct content *c);
bool imagemap_extract(xmlNode *node, struct content *c);
-const char *imagemap_get(struct content *c, const char *key,
+
+const char *imagemap_get(struct hlcache_handle *h, const char *key,
unsigned long x, unsigned long y,
unsigned long click_x, unsigned long click_y,
const char **target);
diff --git a/render/layout.c b/render/layout.c
index 45a075750..336be3e83 100644
--- a/render/layout.c
+++ b/render/layout.c
@@ -41,7 +41,7 @@
#include <math.h>
#include "css/css.h"
#include "css/utils.h"
-#include "content/content.h"
+#include "content/content_protected.h"
#include "desktop/gui.h"
#include "desktop/options.h"
#include "desktop/scroll.h"
@@ -256,12 +256,14 @@ bool layout_block_context(struct box *block, int viewport_height,
if (!layout_block_object(block))
return false;
if (block->height == AUTO) {
- if (block->object->width)
- block->height = block->object->height *
- (float) block->width /
- block->object->width;
+ if (content_get_width(block->object))
+ block->height =
+ content_get_height(block->object) *
+ (float) block->width /
+ content_get_width(block->object);
else
- block->height = block->object->height;
+ block->height =
+ content_get_height(block->object);
}
return true;
}
@@ -691,13 +693,13 @@ void layout_minmax_block(struct box *block,
}
if (block->object) {
- if (block->object->type == CONTENT_HTML) {
- layout_minmax_block(block->object->data.html.layout,
+ if (content_get_type(block->object) == CONTENT_HTML) {
+ layout_minmax_block(html_get_box_tree(block->object),
font_func);
- min = block->object->data.html.layout->min_width;
- max = block->object->data.html.layout->max_width;
+ min = html_get_box_tree(block->object)->min_width;
+ max = html_get_box_tree(block->object)->max_width;
} else {
- min = max = block->object->width;
+ min = max = content_get_width(block->object);
}
} else {
/* recurse through children */
@@ -795,9 +797,9 @@ bool layout_block_object(struct box *block)
LOG(("block %p, object %s, width %i", block, block->object->url,
block->width));
- if (block->object->type == CONTENT_HTML) {
+ if (content_get_type(block->object) == CONTENT_HTML) {
content_reformat(block->object, block->width, 1);
- block->height = block->object->height;
+ block->height = content_get_height(block->object);
} else {
/* this case handled already in
* layout_block_find_dimensions() */
@@ -837,25 +839,25 @@ void layout_block_find_dimensions(int available_width, int viewport_height,
&width, &height, &max_width, &min_width,
margin, padding, border);
- if (box->object && box->object->type != CONTENT_HTML) {
+ if (box->object && content_get_type(box->object) != CONTENT_HTML) {
/* block-level replaced element, see 10.3.4 and 10.6.2 */
if (width == AUTO && height == AUTO) {
- width = box->object->width;
- height = box->object->height;
+ width = content_get_width(box->object);
+ height = content_get_height(box->object);
} else if (width == AUTO) {
- if (box->object->height)
- width = box->object->width *
+ if (content_get_height(box->object))
+ width = content_get_width(box->object) *
(float) height /
- box->object->height;
+ content_get_height(box->object);
else
- width = box->object->width;
+ width = content_get_width(box->object);
} else if (height == AUTO) {
- if (box->object->width)
- height = box->object->height *
+ if (content_get_width(box->object))
+ height = content_get_height(box->object) *
(float) width /
- box->object->width;
+ content_get_width(box->object);
else
- height = box->object->height;
+ height = content_get_height(box->object);
}
}
@@ -1168,18 +1170,20 @@ void layout_float_find_dimensions(int available_width,
padding[RIGHT] += scrollbar_width;
padding[BOTTOM] += scrollbar_width;
- if (box->object && box->object->type != CONTENT_HTML) {
+ if (box->object && content_get_type(box->object) != CONTENT_HTML) {
/* Floating replaced element, with intrinsic width or height.
* See 10.3.6 and 10.6.2 */
if (width == AUTO && height == AUTO) {
- width = box->object->width;
- height = box->object->height;
+ width = content_get_width(box->object);
+ height = content_get_height(box->object);
} else if (width == AUTO)
- width = box->object->width * (float) height /
- box->object->height;
+ width = content_get_width(box->object) *
+ (float) height /
+ content_get_height(box->object);
else if (height == AUTO)
- height = box->object->height * (float) width /
- box->object->width;
+ height = content_get_height(box->object) *
+ (float) width /
+ content_get_width(box->object);
} else if (box->gadget && (box->gadget->type == GADGET_TEXTBOX ||
box->gadget->type == GADGET_PASSWORD ||
box->gadget->type == GADGET_FILE ||
@@ -2079,22 +2083,25 @@ bool layout_line(struct box *first, int *width, int *y,
if (b->object) {
if (b->width == AUTO && b->height == AUTO) {
- b->width = b->object->width;
- b->height = b->object->height;
+ b->width = content_get_width(b->object);
+ b->height = content_get_height(b->object);
} else if (b->width == AUTO) {
- if (b->object->height)
- b->width = b->object->width *
- (float) b->height /
- b->object->height;
+ if (content_get_height(b->object))
+ b->width =
+ content_get_width(b->object) *
+ (float) b->height /
+ content_get_height(b->object);
else
- b->width = b->object->width;
+ b->width = content_get_width(b->object);
} else if (b->height == AUTO) {
- if (b->object->width)
- b->height = b->object->height *
- (float) b->width /
- b->object->width;
+ if (content_get_width(b->object))
+ b->height =
+ content_get_height(b->object) *
+ (float) b->width /
+ content_get_width(b->object);
else
- b->height = b->object->height;
+ b->height =
+ content_get_height(b->object);
}
} else {
/* form control with no object */
@@ -2106,14 +2113,15 @@ bool layout_line(struct box *first, int *width, int *y,
CSS_UNIT_EM, b->style));
}
- if (b->object && b->object->type == CONTENT_HTML &&
- b->width != b->object->available_width) {
+ if (b->object && content_get_type(b->object) == CONTENT_HTML &&
+ b->width !=
+ content_get_available_width(b->object)) {
htype = css_computed_height(b->style, &value, &unit);
content_reformat(b->object, b->width, b->height);
if (htype == CSS_HEIGHT_AUTO)
- b->height = b->object->height;
+ b->height = content_get_height(b->object);
}
if (height < b->height)
@@ -2745,14 +2753,14 @@ struct box *layout_minmax_line(struct box *first,
if (b->object) {
if (width == AUTO && height == AUTO) {
- width = b->object->width;
+ width = content_get_width(b->object);
} else if (width == AUTO) {
- if (b->object->height)
- width = b->object->width *
- (float) height /
- b->object->height;
+ if (content_get_height(b->object))
+ width = content_get_width(b->object) *
+ (float) height /
+ content_get_height(b->object);
else
- width = b->object->width;
+ width = content_get_width(b->object);
}
fixed = frac = 0;
calculate_mbp_width(b->style, LEFT, true, true, true,
@@ -3709,9 +3717,11 @@ void layout_lists(struct box *box,
if (child->list_marker) {
marker = child->list_marker;
if (marker->object) {
- marker->width = marker->object->width;
+ marker->width =
+ content_get_width(marker->object);
marker->x = -marker->width;
- marker->height = marker->object->height;
+ marker->height =
+ content_get_height(marker->object);
marker->y = (line_height(marker->style) -
marker->height) / 2;
} else if (marker->text) {
diff --git a/render/textplain.c b/render/textplain.c
index 07f37610c..befa9aa50 100644
--- a/render/textplain.c
+++ b/render/textplain.c
@@ -28,7 +28,8 @@
#include <strings.h>
#include <math.h>
#include <iconv.h>
-#include "content/content.h"
+#include "content/content_protected.h"
+#include "content/hlcache.h"
#include "css/css.h"
#include "css/utils.h"
#include "desktop/gui.h"
@@ -39,6 +40,7 @@
#include "render/box.h"
#include "render/font.h"
#include "render/textplain.h"
+#include "utils/http.h"
#include "utils/log.h"
#include "utils/messages.h"
#include "utils/talloc.h"
@@ -72,14 +74,13 @@ static float textplain_line_height(void);
* Create a CONTENT_TEXTPLAIN.
*/
-bool textplain_create(struct content *c, struct content *parent,
- const char *params[])
+bool textplain_create(struct content *c, const http_parameter *params)
{
- unsigned int i;
char *utf8_data;
- const char *encoding = "iso-8859-1";
+ const char *encoding;
iconv_t iconv_cd;
union content_msg_data msg_data;
+ nserror error;
textplain_style.size = (option_font_size * FONT_SIZE_SCALE) / 10;
@@ -87,13 +88,9 @@ bool textplain_create(struct content *c, struct content *parent,
if (!utf8_data)
goto no_memory;
- for (i = 0; params[i]; i += 2) {
- if (strcasecmp(params[i], "charset") == 0) {
- encoding = talloc_strdup(c, params[i + 1]);
- if (!encoding)
- goto no_memory;
- break;
- }
+ error = http_parameter_list_find_item(params, "charset", &encoding);
+ if (error != NSERROR_OK) {
+ encoding = "Windows-1252";
}
iconv_cd = iconv_open("utf-8", encoding);
@@ -141,18 +138,22 @@ bool textplain_process_data(struct content *c, char *data, unsigned int size)
iconv_t iconv_cd = c->data.textplain.iconv_cd;
size_t count;
union content_msg_data msg_data;
+ const char *source_data;
+ unsigned long source_size;
+
+ source_data = content__get_source_data(c, &source_size);
do {
- char *inbuf = c->source_data + c->data.textplain.converted;
- size_t inbytesleft = c->source_size -
+ char *inbuf = (char *) source_data +
c->data.textplain.converted;
+ size_t inbytesleft = source_size - c->data.textplain.converted;
char *outbuf = c->data.textplain.utf8_data +
c->data.textplain.utf8_data_size;
size_t outbytesleft = c->data.textplain.utf8_data_allocated -
c->data.textplain.utf8_data_size;
count = iconv(iconv_cd, &inbuf, &inbytesleft,
&outbuf, &outbytesleft);
- c->data.textplain.converted = inbuf - c->source_data;
+ c->data.textplain.converted = inbuf - source_data;
c->data.textplain.utf8_data_size = c->data.textplain.
utf8_data_allocated - outbytesleft;
@@ -180,7 +181,7 @@ bool textplain_process_data(struct content *c, char *data, unsigned int size)
}
gui_multitask();
- } while (!(c->data.textplain.converted == c->source_size ||
+ } while (!(c->data.textplain.converted == source_size ||
(count == (size_t)(-1) && errno == EINVAL)));
return true;
@@ -466,6 +467,35 @@ bool textplain_redraw(struct content *c, int x, int y,
return true;
}
+/**
+ * Retrieve number of lines in content
+ *
+ * \param h Content to retrieve line count from
+ * \return Number of lines
+ */
+unsigned long textplain_line_count(hlcache_handle *h)
+{
+ struct content *c = hlcache_handle_get_content(h);
+
+ assert(c != NULL);
+
+ return c->data.textplain.physical_line_count;
+}
+
+/**
+ * Retrieve the size (in bytes) of text data
+ *
+ * \param h Content to retrieve size of
+ * \return Size, in bytes, of data
+ */
+size_t textplain_size(hlcache_handle *h)
+{
+ struct content *c = hlcache_handle_get_content(h);
+
+ assert(c != NULL);
+
+ return c->data.textplain.utf8_data_size;
+}
/**
* Return byte offset within UTF8 textplain content, given the co-ordinates
@@ -473,15 +503,16 @@ bool textplain_redraw(struct content *c, int x, int y,
* which to search (-1 = above-left, +1 = below-right) if the co-ordinates are not
* contained within a line.
*
- * \param c content of type CONTENT_TEXTPLAIN
+ * \param h content of type CONTENT_TEXTPLAIN
* \param x x ordinate of point
* \param y y ordinate of point
* \param dir direction of search if not within line
* \return byte offset of character containing (or nearest to) point
*/
-size_t textplain_offset_from_coords(struct content *c, int x, int y, int dir)
+size_t textplain_offset_from_coords(hlcache_handle *h, int x, int y, int dir)
{
+ struct content *c = hlcache_handle_get_content(h);
float line_height = textplain_line_height();
struct textplain_line *line;
const char *text;
@@ -489,6 +520,7 @@ size_t textplain_offset_from_coords(struct content *c, int x, int y, int dir)
size_t length;
int idx;
+ assert(c != NULL);
assert(c->type == CONTENT_TEXTPLAIN);
y = (int)((float)(y - MARGIN) / line_height);
@@ -552,19 +584,24 @@ size_t textplain_offset_from_coords(struct content *c, int x, int y, int dir)
* Given a byte offset within the text, return the line number
* of the line containing that offset (or -1 if offset invalid)
*
- * \param c content of type CONTENT_TEXTPLAIN
+ * \param h content of type CONTENT_TEXTPLAIN
* \param offset byte offset within textual representation
* \return line number, or -1 if offset invalid (larger than size)
*/
-int textplain_find_line(struct content *c, unsigned offset)
+int textplain_find_line(hlcache_handle *h, unsigned offset)
{
- struct textplain_line *line = c->data.textplain.physical_line;
- int nlines = c->data.textplain.physical_line_count;
+ struct content *c = hlcache_handle_get_content(h);
+ struct textplain_line *line;
+ int nlines;
int lineno = 0;
+ assert(c != NULL);
assert(c->type == CONTENT_TEXTPLAIN);
+ line = c->data.textplain.physical_line;
+ nlines = c->data.textplain.physical_line_count;
+
if (offset > c->data.textplain.utf8_data_size)
return -1;
@@ -622,30 +659,33 @@ int textplain_coord_from_offset(const char *text, size_t offset, size_t length)
* Given a range of byte offsets within a UTF8 textplain content,
* return a box that fully encloses the text
*
- * \param c content of type CONTENT_TEXTPLAIN
+ * \param h content of type CONTENT_TEXTPLAIN
* \param start byte offset of start of text range
* \param end byte offset of end
* \param r rectangle to be completed
*/
-void textplain_coords_from_range(struct content *c, unsigned start, unsigned end,
- struct rect *r)
+void textplain_coords_from_range(hlcache_handle *h, unsigned start,
+ unsigned end, struct rect *r)
{
+ struct content *c = hlcache_handle_get_content(h);
float line_height = textplain_line_height();
- char *utf8_data = c->data.textplain.utf8_data;
+ char *utf8_data;
struct textplain_line *line;
unsigned lineno = 0;
unsigned nlines;
+ assert(c != NULL);
assert(c->type == CONTENT_TEXTPLAIN);
assert(start <= end);
assert(end <= c->data.textplain.utf8_data_size);
+ utf8_data = c->data.textplain.utf8_data;
nlines = c->data.textplain.physical_line_count;
line = c->data.textplain.physical_line;
/* find start */
- lineno = textplain_find_line(c, start);
+ lineno = textplain_find_line(h, start);
r->y0 = (int)(MARGIN + lineno * line_height);
@@ -654,7 +694,7 @@ void textplain_coords_from_range(struct content *c, unsigned start, unsigned end
forwards most of the time */
/* find end */
- lineno = textplain_find_line(c, end);
+ lineno = textplain_find_line(h, end);
r->x0 = 0;
r->x1 = c->data.textplain.formatted_width;
@@ -677,18 +717,20 @@ void textplain_coords_from_range(struct content *c, unsigned start, unsigned end
/**
* Return a pointer to the requested line of text.
*
- * \param c content of type CONTENT_TEXTPLAIN
+ * \param h content of type CONTENT_TEXTPLAIN
* \param lineno line number
* \param poffset receives byte offset of line start within text
* \param plen receives length of returned line
* \return pointer to text, or NULL if invalid line number
*/
-char *textplain_get_line(struct content *c, unsigned lineno,
+char *textplain_get_line(hlcache_handle *h, unsigned lineno,
size_t *poffset, size_t *plen)
{
+ struct content *c = hlcache_handle_get_content(h);
struct textplain_line *line;
+ assert(c != NULL);
assert(c->type == CONTENT_TEXTPLAIN);
if (lineno >= c->data.textplain.physical_line_count)
@@ -706,20 +748,24 @@ char *textplain_get_line(struct content *c, unsigned lineno,
* text to fit the window width. Thus only hard newlines are preserved
* in the saved/copied text of a selection.
*
- * \param c content of type CONTENT_TEXTPLAIN
+ * \param h content of type CONTENT_TEXTPLAIN
* \param start starting byte offset within UTF-8 text
* \param end ending byte offset
* \param plen receives validated length
* \return pointer to text, or NULL if no text
*/
-char *textplain_get_raw_data(struct content *c, unsigned start, unsigned end,
+char *textplain_get_raw_data(hlcache_handle *h, unsigned start, unsigned end,
size_t *plen)
{
- size_t utf8_size = c->data.textplain.utf8_data_size;
+ struct content *c = hlcache_handle_get_content(h);
+ size_t utf8_size;
+ assert(c != NULL);
assert(c->type == CONTENT_TEXTPLAIN);
+ utf8_size = c->data.textplain.utf8_data_size;
+
/* any text at all? */
if (!utf8_size) return NULL;
diff --git a/render/textplain.h b/render/textplain.h
index 10609a71b..50e29c5be 100644
--- a/render/textplain.h
+++ b/render/textplain.h
@@ -28,6 +28,8 @@
#include <iconv.h>
struct content;
+struct hlcache_handle;
+struct http_parameter;
struct textplain_line {
size_t start;
@@ -46,8 +48,7 @@ struct content_textplain_data {
int formatted_width;
};
-bool textplain_create(struct content *c, struct content *parent,
- const char *params[]);
+bool textplain_create(struct content *c, const struct http_parameter *params);
bool textplain_process_data(struct content *c, char *data, unsigned int size);
bool textplain_convert(struct content *c, int width, int height);
void textplain_reformat(struct content *c, int width, int height);
@@ -58,16 +59,17 @@ bool textplain_redraw(struct content *c, int x, int y,
float scale, colour background_colour);
/* access to lines for text selection and searching */
-#define textplain_line_count(c) ((c)->data.textplain.physical_line_count)
-#define textplain_size(c) ((c)->data.textplain.utf8_data_size)
+unsigned long textplain_line_count(struct hlcache_handle *h);
+size_t textplain_size(struct hlcache_handle *h);
-size_t textplain_offset_from_coords(struct content *c, int x, int y, int dir);
-void textplain_coords_from_range(struct content *c,
+size_t textplain_offset_from_coords(struct hlcache_handle *h, int x, int y,
+ int dir);
+void textplain_coords_from_range(struct hlcache_handle *h,
unsigned start, unsigned end, struct rect *r);
-char *textplain_get_line(struct content *c, unsigned lineno,
+char *textplain_get_line(struct hlcache_handle *h, unsigned lineno,
size_t *poffset, size_t *plen);
-int textplain_find_line(struct content *c, unsigned offset);
-char *textplain_get_raw_data(struct content *c,
+int textplain_find_line(struct hlcache_handle *h, unsigned offset);
+char *textplain_get_raw_data(struct hlcache_handle *h,
unsigned start, unsigned end, size_t *plen);
#endif
diff --git a/riscos/gui.c b/riscos/gui.c
index a1c1980e2..d2b964146 100644
--- a/riscos/gui.c
+++ b/riscos/gui.c
@@ -279,7 +279,15 @@ static void *myrealloc(void *ptr, size_t len, void *pw)
int main(int argc, char** argv)
{
setbuf(stderr, NULL);
- return netsurf_main(argc, argv);
+
+ /* initialise netsurf */
+ netsurf_init(argc, argv);
+
+ netsurf_main_loop();
+
+ netsurf_exit();
+
+ return 0;
}
/**
diff --git a/riscos/window.c b/riscos/window.c
index effb4dac6..335a36409 100644
--- a/riscos/window.c
+++ b/riscos/window.c
@@ -1396,12 +1396,10 @@ bool gui_window_frame_resize_start(struct gui_window *g)
* \param g gui_window containing the content
* \param c the content to save
*/
-
-void gui_window_save_as_link(struct gui_window *g, struct content *c)
+void gui_window_save_link(struct gui_window *g, const char *url,
+ const char *title)
{
- if (!c)
- return;
- ro_gui_save_prepare(GUI_SAVE_LINK_URL, NULL, NULL, c->url, c->title);
+ ro_gui_save_prepare(GUI_SAVE_LINK_URL, NULL, NULL, url, title);
ro_gui_dialog_open_persistent(g->window, dialog_saveas, true);
}
diff --git a/test/Makefile b/test/Makefile
new file mode 100644
index 000000000..f480f4809
--- /dev/null
+++ b/test/Makefile
@@ -0,0 +1,19 @@
+CFLAGS := -std=c99 -g -O0 -D_BSD_SOURCE -D_POSIX_C_SOURCE -I.. \
+ `pkg-config --cflags libxml-2.0 libcurl libparserutils`
+LDFLAGS := `pkg-config --libs libxml-2.0 libcurl libparserutils`
+
+llcache_SRCS := content/fetch.c content/fetchers/fetch_curl.c \
+ content/fetchers/fetch_data.c content/llcache.c \
+ content/urldb.c desktop/options.c desktop/version.c \
+ utils/base64.c utils/hashtable.c utils/messages.c \
+ utils/url.c utils/useragent.c utils/utf8.c utils/utils.c \
+ test/llcache.c
+
+llcache: $(addprefix ../,$(llcache_SRCS))
+ $(CC) $(CFLAGS) $^ -o $@ $(LDFLAGS)
+
+
+.PHONY: clean
+
+clean:
+ $(RM) llcache
diff --git a/test/llcache.c b/test/llcache.c
new file mode 100644
index 000000000..be0df60ad
--- /dev/null
+++ b/test/llcache.c
@@ -0,0 +1,282 @@
+#include <stdio.h>
+#include <stdlib.h>
+
+#include "content/fetch.h"
+#include "content/llcache.h"
+#include "utils/ring.h"
+#include "utils/url.h"
+
+/******************************************************************************
+ * Things that we'd reasonably expect to have to implement *
+ ******************************************************************************/
+
+/* desktop/netsurf.h */
+bool verbose_log;
+
+/* utils/utils.h */
+void die(const char * const error)
+{
+ fprintf(stderr, "%s\n", error);
+
+ exit(1);
+}
+
+/* utils/utils.h */
+void warn_user(const char *warning, const char *detail)
+{
+ fprintf(stderr, "%s %s\n", warning, detail);
+}
+
+/* content/fetch.h */
+const char *fetch_filetype(const char *unix_path)
+{
+ return NULL;
+}
+
+/* content/fetch.h */
+char *fetch_mimetype(const char *ro_path)
+{
+ return NULL;
+}
+
+/******************************************************************************
+ * Things that are absolutely not reasonable, and should disappear *
+ ******************************************************************************/
+
+#include "desktop/cookies.h"
+#include "desktop/tree.h"
+
+/* desktop/cookies.h -- used by urldb
+ *
+ * URLdb should have a cookies update event + handler registration
+ */
+bool cookies_update(const char *domain, const struct cookie_data *data)
+{
+ return true;
+}
+
+/* image/bitmap.h -- used by urldb
+ *
+ * URLdb shouldn't care about bitmaps.
+ * This is because the legacy RO thumbnail stuff was hacked in and must die.
+ */
+void bitmap_destroy(void *bitmap)
+{
+}
+
+/* desktop/tree.h -- used by options.c
+ *
+ * Why on earth is tree loading and saving in options.c?
+ */
+void tree_initialise(struct tree *tree)
+{
+}
+
+/* desktop/tree.h */
+struct node *tree_create_folder_node(struct node *parent, const char *title)
+{
+ return NULL;
+}
+
+/* desktop/tree.h */
+struct node *tree_create_URL_node(struct node *parent, const char *url,
+ const struct url_data *data, const char *title)
+{
+ return NULL;
+}
+
+/* desktop/tree.h */
+struct node_element *tree_find_element(struct node *node, node_element_data d)
+{
+ return NULL;
+}
+
+/******************************************************************************
+ * test: protocol handler *
+ ******************************************************************************/
+
+typedef struct test_context {
+ struct fetch *parent;
+
+ bool aborted;
+ bool locked;
+
+ struct test_context *r_prev;
+ struct test_context *r_next;
+} test_context;
+
+static test_context *ring;
+
+bool test_initialise(const char *scheme)
+{
+ /* Nothing to do */
+ return true;
+}
+
+void test_finalise(const char *scheme)
+{
+ /* Nothing to do */
+}
+
+void *test_setup_fetch(struct fetch *parent, const char *url, bool only_2xx,
+ const char *post_urlenc,
+ struct fetch_multipart_data *post_multipart,
+ const char **headers)
+{
+ test_context *ctx = calloc(1, sizeof(test_context));
+
+ if (ctx == NULL)
+ return NULL;
+
+ ctx->parent = parent;
+
+ RING_INSERT(ring, ctx);
+
+ return ctx;
+}
+
+bool test_start_fetch(void *handle)
+{
+ /* Nothing to do */
+ return true;
+}
+
+void test_abort_fetch(void *handle)
+{
+ test_context *ctx = handle;
+
+ ctx->aborted = true;
+}
+
+void test_free_fetch(void *handle)
+{
+ test_context *ctx = handle;
+
+ RING_REMOVE(ring, ctx);
+
+ free(ctx);
+}
+
+void test_process(test_context *ctx)
+{
+ /** \todo Implement */
+}
+
+void test_poll(const char *scheme)
+{
+ test_context *ctx, *next;
+
+ if (ring == NULL)
+ return;
+
+ ctx = ring;
+ do {
+ next = ctx->r_next;
+
+ if (ctx->locked)
+ continue;
+
+ if (ctx->aborted == false) {
+ test_process(ctx);
+ }
+
+ fetch_remove_from_queues(ctx->parent);
+ fetch_free(ctx->parent);
+ } while ((ctx = next) != ring && ring != NULL);
+}
+
+/******************************************************************************
+ * The actual test code *
+ ******************************************************************************/
+
+nserror query_handler(const llcache_query *query, void *pw,
+ llcache_query_response cb, void *cbpw)
+{
+ /* I'm too lazy to actually implement this. It should queue the query,
+ * then deliver the response from main(). */
+
+ return NSERROR_OK;
+}
+
+nserror event_handler(const llcache_handle *handle,
+ const llcache_event *event, void *pw)
+{
+ static char *event_names[] = {
+ "HAD_HEADERS", "HAD_DATA", "DONE", "ERROR", "PROGRESS"
+ };
+ bool *done = pw;
+
+ if (event->type != LLCACHE_EVENT_PROGRESS)
+ fprintf(stdout, "%p : %s\n", handle, event_names[event->type]);
+
+ /* Inform main() that the fetch completed */
+ if (event->type == LLCACHE_EVENT_DONE)
+ *done = true;
+
+ return NSERROR_OK;
+}
+
+int main(int argc, char **argv)
+{
+ nserror error;
+ llcache_handle *handle;
+ llcache_handle *handle2;
+ bool done = false;
+
+ /* Initialise subsystems */
+ url_init();
+ fetch_init();
+ fetch_add_fetcher("test", test_initialise, test_setup_fetch,
+ test_start_fetch, test_abort_fetch, test_free_fetch,
+ test_poll, test_finalise);
+
+ /* Initialise low-level cache */
+ error = llcache_initialise(query_handler, NULL);
+ if (error != NSERROR_OK) {
+ fprintf(stderr, "llcache_initialise: %d\n", error);
+ return 1;
+ }
+
+ /* Retrieve an URL from the low-level cache (may trigger fetch) */
+ error = llcache_handle_retrieve("http://www.netsurf-browser.org/",
+ LLCACHE_RETRIEVE_VERIFIABLE, NULL, NULL,
+ event_handler, &done, &handle);
+ if (error != NSERROR_OK) {
+ fprintf(stderr, "llcache_handle_retrieve: %d\n", error);
+ return 1;
+ }
+
+ /* Poll relevant components */
+ while (done == false) {
+ fetch_poll();
+ llcache_poll();
+ }
+
+ done = false;
+ error = llcache_handle_retrieve("http://www.netsurf-browser.org/",
+ LLCACHE_RETRIEVE_VERIFIABLE, NULL, NULL,
+ event_handler, &done, &handle2);
+ if (error != NSERROR_OK) {
+ fprintf(stderr, "llcache_handle_retrieve: %d\n", error);
+ return 1;
+ }
+
+ while (done == false) {
+ fetch_poll();
+ llcache_poll();
+ }
+
+ fprintf(stdout, "%p -> %p\n", handle,
+ llcache_object_from_handle(handle));
+ fprintf(stdout, "%p -> %p\n", handle2,
+ llcache_object_from_handle(handle2));
+
+ /* Cleanup */
+ llcache_handle_release(handle2);
+ llcache_handle_release(handle);
+
+ fetch_quit();
+
+ return 0;
+}
+
diff --git a/utils/errors.h b/utils/errors.h
new file mode 100644
index 000000000..7aa486569
--- /dev/null
+++ b/utils/errors.h
@@ -0,0 +1,40 @@
+/*
+ * Copyright 2009 John-Mark Bell <jmb@netsurf-browser.org>
+ *
+ * This file is part of NetSurf, http://www.netsurf-browser.org/
+ *
+ * NetSurf is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * NetSurf is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+/** \file
+ * Error codes
+ */
+
+#ifndef NETSURF_UTILS_ERRORS_H_
+#define NETSURF_UTILS_ERRORS_H_
+
+/**
+ * Enumeration of error codes
+ */
+typedef enum {
+ NSERROR_OK, /**< No error */
+
+ NSERROR_NOMEM, /**< Memory exhaustion */
+
+ NSERROR_NO_FETCH_HANDLER, /**< No fetch handler for URL scheme */
+
+ NSERROR_NOT_FOUND, /**< Requested item not found */
+} nserror;
+
+#endif
+
diff --git a/utils/http.c b/utils/http.c
new file mode 100644
index 000000000..12672261d
--- /dev/null
+++ b/utils/http.c
@@ -0,0 +1,390 @@
+/*
+ * Copyright 2010 John-Mark Bell <jmb@netsurf-browser.org>
+ *
+ * This file is part of NetSurf, http://www.netsurf-browser.org/
+ *
+ * NetSurf is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * NetSurf is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+/** \file
+ * HTTP header parsing functions
+ */
+
+#include <inttypes.h>
+#include <stdbool.h>
+#include <stddef.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "utils/http.h"
+
+/**
+ * Representation of an HTTP parameter
+ */
+struct http_parameter {
+ struct http_parameter *next; /**< Next parameter in list, or NULL */
+
+ char *name; /**< Parameter name */
+ char *value; /**< Parameter value */
+};
+
+/**
+ * Determine if a character is valid for an HTTP token
+ *
+ * \param c Character to consider
+ * \return True if character is valid, false otherwise
+ */
+static bool http_is_token_char(uint8_t c)
+{
+ /* [ 32 - 126 ] except ()<>@,;:\"/[]?={} SP HT */
+
+ if (c <= ' ' || 126 < c)
+ return false;
+
+ return (strchr("()<>@,;:\\\"/[]?={}", c) == NULL);
+}
+
+/**
+ * Parse an HTTP token
+ *
+ * \param input Pointer to current input byte. Updated on exit.
+ * \param value Pointer to location to receive on-heap token value.
+ * \return NSERROR_OK on success,
+ * NSERROR_NOMEM on memory exhaustion
+ *
+ * The returned value is owned by the caller
+ */
+static nserror http_parse_token(const char **input, char **value)
+{
+ const uint8_t *start = (const uint8_t *) *input;
+ const uint8_t *end;
+ char *token;
+
+ end = start;
+ while (http_is_token_char(*end))
+ end++;
+
+ token = malloc(end - start + 1);
+ if (token == NULL)
+ return NSERROR_NOMEM;
+
+ memcpy(token, start, end - start);
+ token[end - start] = '\0';
+
+ *value = token;
+ *input = (const char *) end;
+
+ return NSERROR_OK;
+}
+
+/**
+ * Parse an HTTP quoted-string
+ *
+ * \param input Pointer to current input byte. Updated on exit.
+ * \param value Pointer to location to receive on-heap string value.
+ * \return NSERROR_OK on success,
+ * NSERROR_NOMEM on memory exhaustion
+ *
+ * The returned value is owned by the caller
+ */
+static nserror http_parse_quoted_string(const char **input, char **value)
+{
+ const uint8_t *start = (const uint8_t *) *input;
+ const uint8_t *end;
+ uint8_t c;
+ char *string_value;
+
+ /* <"> *( qdtext | quoted-pair ) <">
+ * qdtext = any TEXT except <">
+ * quoted-pair = "\" CHAR
+ * TEXT = [ HT, CR, LF, 32-126, 128-255 ]
+ * CHAR = [ 0 - 127 ]
+ *
+ * \todo TEXT may contain non 8859-1 chars encoded per RFC 2047
+ * \todo Support quoted-pairs
+ */
+
+ if (*start == '"') {
+ end = start = start + 1;
+
+ c = *end;
+ while (c == '\t' || c == '\r' || c == '\n' ||
+ c == ' ' || c == '!' ||
+ ('#' <= c && c <= 126) || c > 127) {
+ end++;
+ c = *end;
+ }
+
+ if (*end != '"') {
+ start--;
+ end = start;
+ }
+ }
+
+ string_value = malloc(end - start + 1);
+ if (string_value == NULL)
+ return NSERROR_NOMEM;
+
+ memcpy(string_value, start, end - start);
+ string_value[end - start] = '\0';
+
+ *value = string_value;
+
+ if (end != start)
+ *input = (const char *) end + 1;
+
+ return NSERROR_OK;
+}
+
+/**
+ * Parse an HTTP parameter
+ *
+ * \param input Pointer to current input byte. Updated on exit.
+ * \param parameter Pointer to location to receive on-heap parameter.
+ * \return NSERROR_OK on success,
+ * NSERROR_NOMEM on memory exhaustion
+ *
+ * The returned parameter is owned by the caller.
+ */
+static nserror http_parse_parameter(const char **input,
+ http_parameter **parameter)
+{
+ const char *pos = *input;
+ char *name;
+ char *value;
+ http_parameter *param;
+ nserror error;
+
+ /* token "=" ( token | quoted-string ) */
+
+ error = http_parse_token(&pos, &name);
+ if (error != NSERROR_OK)
+ return error;
+
+ while (*pos == ' ' || *pos == '\t')
+ pos++;
+
+ if (*pos != '=') {
+ value = strdup("");
+ if (value == NULL) {
+ free(name);
+ return NSERROR_NOMEM;
+ }
+ } else {
+ pos++;
+
+ while (*pos == ' ' || *pos == '\t')
+ pos++;
+
+ if (*pos == '"')
+ error = http_parse_quoted_string(&pos, &value);
+ else
+ error = http_parse_token(&pos, &value);
+
+ if (error != NSERROR_OK) {
+ free(name);
+ return error;
+ }
+ }
+
+ param = malloc(sizeof(*param));
+ if (param == NULL) {
+ free(value);
+ free(name);
+ return NSERROR_NOMEM;
+ }
+
+ param->next = NULL;
+ param->name = name;
+ param->value = value;
+
+ *parameter = param;
+ *input = pos;
+
+ return NSERROR_OK;
+}
+
+/**
+ * Parse an HTTP parameter list
+ *
+ * \param input Pointer to current input byte. Updated on exit.
+ * \param parameters Pointer to location to receive on-heap parameter list.
+ * \return NSERROR_OK on success,
+ * NSERROR_NOMEM on memory exhaustion
+ *
+ * The returned parameter list is owned by the caller
+ */
+static nserror http_parse_parameter_list(const char **input,
+ http_parameter **parameters)
+{
+ const char *pos = *input;
+ http_parameter *param;
+ http_parameter *list = NULL;
+ nserror error;
+
+ /* 1*( ";" parameter ) */
+
+ while (*pos == ';') {
+ pos++;
+
+ while (*pos == ' ' || *pos == '\t')
+ pos++;
+
+ error = http_parse_parameter(&pos, &param);
+ if (error != NSERROR_OK) {
+ while (list != NULL) {
+ param = list;
+
+ list = param->next;
+
+ free(param->name);
+ free(param->value);
+ free(param);
+ }
+ return error;
+ }
+
+ if (list != NULL)
+ param->next = list;
+
+ list = param;
+
+ while (*pos == ' ' || *pos == '\t')
+ pos++;
+ }
+
+ *parameters = list;
+ *input = pos;
+
+ return NSERROR_OK;
+}
+
+/* See http.h for documentation */
+nserror http_parse_content_type(const char *header_value, char **media_type,
+ http_parameter **parameters)
+{
+ const char *pos = header_value;
+ char *type;
+ char *subtype = NULL;
+ http_parameter *params = NULL;
+ char *mime;
+ size_t mime_len;
+ nserror error;
+
+ /* type "/" subtype *( ";" parameter ) */
+
+ while (*pos == ' ' || *pos == '\t')
+ pos++;
+
+ error = http_parse_token(&pos, &type);
+ if (error != NSERROR_OK)
+ return error;
+
+ while (*pos == ' ' || *pos == '\t')
+ pos++;
+
+ if (*pos == '/') {
+ pos++;
+
+ while (*pos == ' ' || *pos == '\t')
+ pos++;
+
+ error = http_parse_token(&pos, &subtype);
+ if (error != NSERROR_OK) {
+ free(type);
+ return error;
+ }
+
+ while (*pos == ' ' || *pos == '\t')
+ pos++;
+
+ if (*pos == ';') {
+ pos++;
+
+ while (*pos == ' ' || *pos == '\t')
+ pos++;
+
+ error = http_parse_parameter_list(&pos, &params);
+ if (error != NSERROR_OK) {
+ free(subtype);
+ free(type);
+ return error;
+ }
+ }
+ }
+
+ /* <type> + <subtype> + '/' */
+ mime_len = strlen(type) + (subtype != NULL ? strlen(subtype) : 0) + 1;
+
+ mime = malloc(mime_len + 1);
+ if (mime == NULL) {
+ http_parameter_list_destroy(params);
+ free(subtype);
+ free(type);
+ return NSERROR_OK;
+ }
+
+ sprintf(mime, "%s/%s", type, subtype != NULL ? subtype : "");
+
+ free(subtype);
+ free(type);
+
+ *media_type = mime;
+ *parameters = params;
+
+ return NSERROR_OK;
+}
+
+/* See http.h for documentation */
+nserror http_parameter_list_find_item(const http_parameter *list,
+ const char *name, const char **value)
+{
+ while (list != NULL && strcasecmp(name, list->name) != 0)
+ list = list->next;
+
+ if (list == NULL)
+ return NSERROR_NOT_FOUND;
+
+ *value = list->value;
+
+ return NSERROR_OK;
+}
+
+/* See http.h for documentation */
+const http_parameter *http_parameter_list_iterate(const http_parameter *cur,
+ const char **name, const char **value)
+{
+ if (cur == NULL)
+ return NULL;
+
+ *name = cur->name;
+ *value = cur->value;
+
+ return cur->next;
+}
+
+/* See http.h for documentation */
+void http_parameter_list_destroy(http_parameter *list)
+{
+ while (list != NULL) {
+ http_parameter *victim = list;
+
+ list = victim->next;
+
+ free(victim->name);
+ free(victim->value);
+ free(victim);
+ }
+}
+
diff --git a/utils/http.h b/utils/http.h
new file mode 100644
index 000000000..1d8b4de6c
--- /dev/null
+++ b/utils/http.h
@@ -0,0 +1,73 @@
+/*
+ * Copyright 2010 John-Mark Bell <jmb@netsurf-browser.org>
+ *
+ * This file is part of NetSurf, http://www.netsurf-browser.org/
+ *
+ * NetSurf is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * NetSurf is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+/** \file
+ * HTTP header parsing functions
+ */
+
+#ifndef NETSURF_UTILS_HTTP_H_
+#define NETSURF_UTILS_HTTP_H_
+
+#include "utils/errors.h"
+
+typedef struct http_parameter http_parameter;
+
+/**
+ * Parse an HTTP Content-Type header value
+ *
+ * \param header_value Header value to parse
+ * \param media_type Pointer to location to receive media type
+ * \param parameters Pointer to location to receive parameter list
+ * \return NSERROR_OK on success,
+ * NSERROR_NOMEM on memory exhaustion
+ */
+nserror http_parse_content_type(const char *header_value, char **media_type,
+ http_parameter **parameters);
+
+/**
+ * Find a named item in an HTTP parameter list
+ *
+ * \param list List to search
+ * \param name Name of item to search for
+ * \param value Pointer to location to receive value
+ * \return NSERROR_OK on success,
+ * NSERROR_NOT_FOUND if requested item does not exist
+ */
+nserror http_parameter_list_find_item(const http_parameter *list,
+ const char *name, const char **value);
+
+/**
+ * Iterate over a parameter list
+ *
+ * \param cur Pointer to current iteration position, list head to start
+ * \param name Pointer to location to receive item name
+ * \param value Pointer to location to receive item value
+ * \return Pointer to next iteration position, or NULL for end of iteration
+ */
+const http_parameter *http_parameter_list_iterate(const http_parameter *cur,
+ const char **name, const char **value);
+
+/**
+ * Destroy a list of HTTP parameters
+ *
+ * \param list List to destroy
+ */
+void http_parameter_list_destroy(http_parameter *list);
+
+#endif
+
diff --git a/windows/bitmap.c b/windows/bitmap.c
index 74c104963..0fd323574 100644
--- a/windows/bitmap.c
+++ b/windows/bitmap.c
@@ -19,21 +19,13 @@
#include <inttypes.h>
#include <sys/types.h>
+#include <string.h>
-#include "assert.h"
#include "image/bitmap.h"
#include "windows/bitmap.h"
#include "utils/log.h"
-#ifndef MIN
-#define MIN(a,b) (((a) < (b)) ? (a) : (b))
-#endif
-
-#ifndef MAX
-#define MAX(a,b) (((a) > (b)) ? (a) : (b))
-#endif
-
/**
* Create a bitmap.
*
diff --git a/windows/gui.c b/windows/gui.c
index 248363795..fa0954b20 100644
--- a/windows/gui.c
+++ b/windows/gui.c
@@ -157,7 +157,6 @@ static void redraw(void)
{
struct gui_window *w = window_list;
struct browser_window *bw;
- struct content *c;
HDC hdc;
while (w != NULL) {
@@ -173,20 +172,13 @@ static void redraw(void)
continue;
}
- c = bw->current_content;
-
- if ((c == NULL) || (c->locked)) {
- w = w->next;
- continue;
- }
-
current_hwnd = w->drawingarea;
w->scrolly += w->requestscrolly;
w->scrollx += w->requestscrollx;
w->scrolly = MAX(w->scrolly, 0);
- w->scrolly = MIN(w->scrolly, c->height * w->bw->scale - w->height);
+ w->scrolly = MIN(w->scrolly, content_get_height(bw->current_content) * w->bw->scale - w->height);
w->scrollx = MAX(w->scrollx, 0);
- w->scrollx = MIN(w->scrollx, c->width * w->bw->scale - w->width);
+ w->scrollx = MIN(w->scrollx, content_get_width(bw->current_content) * w->bw->scale - w->width);
/* redraw */
current_redraw_browser = bw;
nsws_plot_set_scale(bw->scale);
@@ -204,9 +196,11 @@ static void redraw(void)
doublebuffering = false;
if (doublebuffering)
bufferdc = w->bufferdc;
- content_redraw(c, -w->scrollx / w->bw->scale,
+ content_redraw(bw->current_content,
+ -w->scrollx / w->bw->scale,
-w->scrolly / w->bw->scale,
- w->width, w->height,
+ w->width,
+ w->height,
w->redraw.left - w->scrollx / w->bw->scale,
w->redraw.top - w->scrolly / w->bw->scale,
w->redraw.right - w->scrollx / w->bw->scale,
@@ -809,13 +803,14 @@ nsws_drawable_hscroll(struct gui_window *gw, HWND hwnd, WPARAM wparam)
si.fMask = SIF_POS;
if ((gw->bw != NULL) && (gw->bw->current_content != NULL))
si.nPos = MIN(si.nPos,
- gw->bw->current_content->width *
+ content_get_width(gw->bw->current_content) *
gw->bw->scale - gw->width);
si.nPos = MAX(si.nPos, 0);
SetScrollInfo(hwnd, SB_HORZ, &si, TRUE);
GetScrollInfo(hwnd, SB_HORZ, &si);
- if (si.nPos != mem)
+ if (si.nPos != mem) {
gui_window_set_scroll(gw, gw->scrollx + gw->requestscrollx + si.nPos - mem, gw->scrolly);
+ }
}
static void
@@ -866,7 +861,7 @@ nsws_drawable_vscroll(struct gui_window *gw, HWND hwnd, WPARAM wparam)
if ((gw->bw != NULL) &&
(gw->bw->current_content != NULL)) {
si.nPos = MIN(si.nPos,
- gw->bw->current_content->height *
+ content_get_height(gw->bw->current_content) *
gw->bw->scale - gw->height);
}
si.nPos = MAX(si.nPos, 0);
@@ -1942,11 +1937,10 @@ void gui_window_set_scroll(struct gui_window *w, int sx, int sy)
si.cbSize = sizeof(si);
si.fMask = SIF_ALL;
si.nMin = 0;
- si.nMax = (w->bw->current_content->height * w->bw->scale) -1;
+ si.nMax = (content_get_height(w->bw->current_content) * w->bw->scale) - 1;
si.nPage = w->height;
si.nPos = MAX(w->scrolly + w->requestscrolly, 0);
- si.nPos = MIN(si.nPos, w->bw->current_content->height * w->bw->scale
- - w->height);
+ si.nPos = MIN(si.nPos, content_get_height(w->bw->current_content) * w->bw->scale - w->height);
SetScrollInfo(w->drawingarea, SB_VERT, &si, TRUE);
LOG(("SetScrollInfo VERT min:%d max:%d page:%d pos:%d", si.nMin, si.nMax, si.nPage, si.nPos));
@@ -1954,11 +1948,10 @@ void gui_window_set_scroll(struct gui_window *w, int sx, int sy)
si.cbSize = sizeof(si);
si.fMask = SIF_ALL;
si.nMin = 0;
- si.nMax = (w->bw->current_content->width * w->bw->scale) -1;
+ si.nMax = (content_get_width(w->bw->current_content) * w->bw->scale) -1;
si.nPage = w->width;
si.nPos = MAX(w->scrollx + w->requestscrollx, 0);
- si.nPos = MIN(si.nPos, w->bw->current_content->width * w->bw->scale
- - w->width);
+ si.nPos = MIN(si.nPos, content_get_width(w->bw->current_content) * w->bw->scale - w->width);
SetScrollInfo(w->drawingarea, SB_HORZ, &si, TRUE);
LOG(("SetScrollInfo HORZ min:%d max:%d page:%d pos:%d", si.nMin, si.nMax, si.nPage, si.nPos));
@@ -2184,12 +2177,12 @@ gui_window_remove_caret(struct gui_window *w)
}
void
-gui_window_set_icon(struct gui_window *g, struct content *icon)
+gui_window_set_icon(struct gui_window *g, hlcache_handle *icon)
{
}
void
-gui_window_set_search_ico(struct content *ico)
+gui_window_set_search_ico(hlcache_handle *ico)
{
}
@@ -2235,7 +2228,8 @@ bool gui_window_frame_resize_start(struct gui_window *w)
return true;
}
-void gui_window_save_as_link(struct gui_window *w, struct content *c)
+void gui_window_save_link(struct gui_window *g, const char *url,
+ const char *title)
{
}
@@ -2247,7 +2241,7 @@ void gui_window_set_scale(struct gui_window *w, float scale)
LOG(("%.2f\n", scale));
}
-void gui_drag_save_object(gui_save_type type, struct content *c,
+void gui_drag_save_object(gui_save_type type, hlcache_handle *c,
struct gui_window *w)
{
}
@@ -2352,7 +2346,7 @@ void gui_launch_url(const char *url)
{
}
-void gui_cert_verify(struct browser_window *bw, struct content *c,
+void gui_cert_verify(struct browser_window *bw, hlcache_handle *c,
const struct ssl_cert_info *certs, unsigned long num)
{
}
@@ -2469,17 +2463,27 @@ WinMain(HINSTANCE hInstance, HINSTANCE hLastInstance, LPSTR lpcli, int ncmd)
argv = malloc(sizeof(char *) * argc);
while (argctemp < argc) {
len = wcstombs(NULL, argvw[argctemp], 0) + 1;
- if (len > 0)
+ if (len > 0) {
argv[argctemp] = malloc(len);
+ }
+
if (argv[argctemp] != NULL) {
wcstombs(argv[argctemp], argvw[argctemp], len);
/* alter windows-style forward slash flags to
- * hypen flags.
+ * hyphen flags.
*/
if (argv[argctemp][0] == '/')
argv[argctemp][0] = '-';
}
argctemp++;
}
- return netsurf_main(argc, argv);
+
+ /* initialise netsurf */
+ netsurf_init(argc, argv);
+
+ netsurf_main_loop();
+
+ netsurf_exit();
+
+ return 0;
}
diff --git a/windows/hotlist.c b/windows/hotlist.c
index 48df23bb4..dab18d11c 100644
--- a/windows/hotlist.c
+++ b/windows/hotlist.c
@@ -17,7 +17,8 @@
*/
#include "desktop/browser.h"
+#include "content/hlcache.h"
-void hotlist_visited(struct content *content)
+void hotlist_visited(hlcache_handle *content)
{
}
diff --git a/windows/login.c b/windows/login.c
index 306de8459..32c87591c 100644
--- a/windows/login.c
+++ b/windows/login.c
@@ -17,8 +17,9 @@
*/
#include "desktop/401login.h"
+#include "content/hlcache.h"
-void gui_401login_open(struct browser_window *bw, struct content *c,
+void gui_401login_open(struct browser_window *bw, hlcache_handle *c,
const char *realm)
{
}
diff --git a/windows/thumbnail.c b/windows/thumbnail.c
index 8305ee1cc..e96c32201 100644
--- a/windows/thumbnail.c
+++ b/windows/thumbnail.c
@@ -23,29 +23,30 @@
#include "windows/bitmap.h"
#include "windows/gui.h"
#include "windows/plot.h"
+#include "content/hlcache.h"
-#ifndef MIN
-#define MIN(a,b) (((a) < (b)) ? (a) : (b))
-#endif
-#ifndef MAX
-#define MAX(a,b) (((a) > (b)) ? (a) : (b))
-#endif
-
-bool thumbnail_create(struct content *content, struct bitmap *bitmap,
- const char *url)
+bool
+thumbnail_create(hlcache_handle *content,
+ struct bitmap *bitmap,
+ const char *url)
{
- LOG(("creating thumbnail %p for url %s content %p", bitmap, url,
- content));
- int width = MIN(content->width, 1024);
- int height = MIN(content->height, 768);
+ int width = content_get_width(content);
+ int height = content_get_height(content);
int i;
uint8_t *pixdata;
HDC hdc, minidc;
HBITMAP bufferbm, minibm, minibm2;
- BITMAPINFO *bmi = (BITMAPINFO *) malloc(sizeof(BITMAPINFOHEADER) +
- (bitmap->width * bitmap->height * 4));
+ BITMAPINFO *bmi;
BITMAPINFOHEADER bmih;
+
+ LOG(("creating thumbnail %p for url %s content %p", bitmap, url, content));
+
+ bmi = malloc(sizeof(BITMAPINFOHEADER) + (bitmap->width * bitmap->height * 4));
+ if (bmi == NULL) {
+ return false;
+ }
+
bmih.biSize = sizeof(bmih);
bmih.biWidth = bitmap->width;
bmih.biHeight = - bitmap->height;
@@ -81,7 +82,7 @@ bool thumbnail_create(struct content *content, struct bitmap *bitmap,
}
SelectObject(bufferdc, bufferbm);
thumbnail = true;
- content_redraw(content, 0, 0, content->width, content->height, 0, 0,
+ content_redraw(content, 0, 0, width, height, 0, 0,
width, height, 1.0, 0xFFFFFF);
thumbnail = false;