diff options
Diffstat (limited to 'render/html.c')
-rw-r--r-- | render/html.c | 925 |
1 files changed, 534 insertions, 391 deletions
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; +} |