From 0f77b057a1f2210addb40c6b528c917affda6720 Mon Sep 17 00:00:00 2001 From: John Mark Bell Date: Wed, 25 Jan 2006 06:52:38 +0000 Subject: [PATCH] [project @ 2006-01-25 06:52:38 by jmb] Meta refresh support svn path=/import/netsurf/; revision=2039 --- content/content.c | 1 + content/content.h | 5 ++ desktop/browser.c | 26 +++++++++++ render/html.c | 116 ++++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 148 insertions(+) diff --git a/content/content.c b/content/content.c index 70f280c3d..11effac45 100644 --- a/content/content.c +++ b/content/content.c @@ -295,6 +295,7 @@ struct content * content_create(const char *url) c->width = 0; c->height = 0; c->available_width = 0; + c->refresh = 0; c->bitmap = 0; c->fresh = false; c->size = sizeof(struct content); diff --git a/content/content.h b/content/content.h index 897b81370..3e24ccbc0 100644 --- a/content/content.h +++ b/content/content.h @@ -150,6 +150,7 @@ typedef enum { CONTENT_MSG_REFORMAT, /**< content_reformat done */ CONTENT_MSG_REDRAW, /**< needs redraw (eg. new animation frame) */ CONTENT_MSG_NEWPTR, /**< address of structure has changed */ + CONTENT_MSG_REFRESH, /**< wants refresh */ #ifdef WITH_AUTH CONTENT_MSG_AUTH /**< authentication required */ #endif @@ -173,6 +174,7 @@ union content_msg_data { float object_width, object_height; } redraw; char *auth_realm; /**< Realm, for CONTENT_MSG_AUTH. */ + int delay; /**< Minimum delay, for CONTENT_MSG_REFRESH */ }; /** Linked list of users of a content. */ @@ -233,6 +235,9 @@ struct content { #endif } data; + /**< URL for refresh request, in standard form as from url_join. */ + char *refresh; + /** Bitmap, for various image contents. */ struct bitmap *bitmap; diff --git a/desktop/browser.c b/desktop/browser.c index 41b1baed5..d4cec3fcd 100644 --- a/desktop/browser.c +++ b/desktop/browser.c @@ -51,6 +51,7 @@ struct browser_window *current_redraw_browser; static void browser_window_callback(content_msg msg, struct content *c, intptr_t p1, intptr_t p2, union content_msg_data data); +static void browser_window_refresh(void *p); static void browser_window_convert_to_download(struct browser_window *bw); static void browser_window_start_throbber(struct browser_window *bw); static void browser_window_stop_throbber(struct browser_window *bw); @@ -414,12 +415,37 @@ void browser_window_callback(content_msg msg, struct content *c, break; #endif + case CONTENT_MSG_REFRESH: + schedule(data.delay * 100, + browser_window_refresh, bw); + break; + default: assert(0); } } +/** + * Refresh browser window + * + * \param p Browser window to refresh + */ + +void browser_window_refresh(void *p) +{ + struct browser_window *bw = p; + + assert(bw->current_content->status == CONTENT_STATUS_READY || + bw->current_content->status == CONTENT_STATUS_DONE); + + /* mark this content as invalid so it gets flushed from the cache */ + bw->current_content->fresh = false; + + browser_window_go(bw, bw->current_content->refresh, + bw->current_content->url); +} + /** * Transfer the loading_content to a new download window. */ diff --git a/render/html.c b/render/html.c index a2dac2ec5..c092df8c2 100644 --- a/render/html.c +++ b/render/html.c @@ -20,6 +20,7 @@ #include "netsurf/content/content.h" #include "netsurf/content/fetch.h" #include "netsurf/content/fetchcache.h" +#include "netsurf/desktop/browser.h" #include "netsurf/desktop/gui.h" #include "netsurf/desktop/options.h" #include "netsurf/render/box.h" @@ -40,6 +41,7 @@ static bool html_set_parser_encoding(struct content *c, const char *encoding); static const char *html_detect_encoding(const char *data, unsigned int size); static void html_convert_css_callback(content_msg msg, struct content *css, intptr_t p1, intptr_t p2, union content_msg_data data); +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 *head); static void html_object_callback(content_msg msg, struct content *object, @@ -50,6 +52,7 @@ static void html_object_failed(struct box *box, struct content *content, bool background); static bool html_object_type_permitted(const content_type type, const content_type *permitted_types); +static void html_object_refresh(void *p); static bool html_find_frame(struct content *c, const char *frame, struct content **page, unsigned int *i); @@ -308,6 +311,10 @@ bool html_convert(struct content *c, int width, int height) content_broadcast(c, CONTENT_MSG_ERROR, msg_data); return false; } + + /* handle meta refresh */ + if (!html_meta_refresh(c, head)) + return false; } /* get stylesheets */ @@ -362,6 +369,90 @@ bool html_convert(struct content *c, int width, int height) return true; } +/** + * Search for meta refresh + * + * \param c content structure + * \param head xml node of head element + * \return true on success, false otherwise (error reported) + */ + +bool html_meta_refresh(struct content *c, xmlNode *head) +{ + xmlNode *n; + xmlChar *equiv, *content; + union content_msg_data msg_data; + char *url, *end, *refresh; + url_func_result res; + + for (n = head == 0 ? 0 : head->children; n; n = n->next) { + if (n->type != XML_ELEMENT_NODE) + continue; + + if (strcmp((const char *)n->name, "meta")) + continue; + + equiv = xmlGetProp(n, (const xmlChar *)"http-equiv"); + if (!equiv) + continue; + + if (strcasecmp((const char *)equiv, "refresh")) { + xmlFree(equiv); + continue; + } + + xmlFree(equiv); + + content = xmlGetProp(n, (const xmlChar *)"content"); + if (!content) + continue; + + end = (char *)content + strlen(content); + + msg_data.delay = (int)strtol((char *) content, &url, 10); + + for ( ; url <= end - 4; url++) { + if (!strncasecmp(url, "url=", 4)) + break; + } + + if (url <= end - 4) { + res = url_join(url + 4, c->data.html.base_url, + &refresh); + + xmlFree(content); + + if (res == URL_FUNC_NOMEM) { + msg_data.error = messages_get("NoMemory"); + content_broadcast(c, + CONTENT_MSG_ERROR, msg_data); + return false; + } + else if (res == URL_FUNC_FAILED) { + /* This isn't fatal so carry on looking */ + continue; + } + + c->refresh = talloc_strdup(c, refresh); + + free(refresh); + + if (!c->refresh) { + msg_data.error = messages_get("NoMemory"); + content_broadcast(c, + CONTENT_MSG_ERROR, msg_data); + return false; + } + + content_broadcast(c, CONTENT_MSG_REFRESH, msg_data); + break; + } + + xmlFree(content); + } + + return true; +} /** * Process elements in . @@ -1018,6 +1109,13 @@ void html_object_callback(content_msg msg, struct content *object, break; #endif + case CONTENT_MSG_REFRESH: + if (object->type == CONTENT_HTML) + /* only for HTML objects */ + schedule(data.delay * 100, + html_object_refresh, object); + break; + default: assert(0); } @@ -1177,6 +1275,24 @@ bool html_object_type_permitted(const content_type type, } +/** + * schedule() callback for object refresh + */ + +void html_object_refresh(void *p) +{ + struct content *c = (struct content *)p; + + assert(c->type == CONTENT_HTML && c->refresh); + + c->fresh = false; + + if (!html_replace_object(c->data.html.page, c->data.html.index, + c->refresh, 0, 0)) { + /** \todo handle memory exhaustion */ + } +} + /** * Stop loading a CONTENT_HTML in state READY. */