bool favicon_get_icon(struct content *c, xmlNode *html) { static const content_type permitted_types[] = { #ifdef WITH_BMP CONTENT_ICO, #endif #if defined(WITH_MNG) || defined(WITH_PNG) CONTENT_PNG, #endif #ifdef WITH_GIF CONTENT_GIF, #endif CONTENT_UNKNOWN }; char *url; nserror error; url = favicon_get_icon_ref(c, html); if (url == NULL) return false; error = hlcache_handle_retrieve(url, LLCACHE_RETRIEVE_NO_ERROR_PAGES, content__get_url(c), NULL, favicon_callback, c, NULL, permitted_types, &c->data.html.favicon); if (error == NSERROR_OK) { c->active += 1; } free(url); return error == NSERROR_OK; }
/* exported interface documented in render/html_internal.h */ nserror html_css_quirks_stylesheets(html_content *c) { nserror ns_error = NSERROR_OK; hlcache_child_context child; assert(c->stylesheets != NULL); if (c->quirks == DOM_DOCUMENT_QUIRKS_MODE_FULL) { child.charset = c->encoding; child.quirks = c->base.quirks; ns_error = hlcache_handle_retrieve(html_quirks_stylesheet_url, 0, content_get_url(&c->base), NULL, html_convert_css_callback, c, &child, CONTENT_CSS, &c->stylesheets[STYLESHEET_QUIRKS].sheet); if (ns_error != NSERROR_OK) { return ns_error; } c->base.active++; LOG("%d fetches active", c->base.active); } return ns_error; }
static nserror html_stylesheet_from_domnode(html_content *c, dom_node *node, hlcache_handle **sheet) { hlcache_child_context child; dom_string *style; nsurl *url; dom_exception exc; nserror error; uint32_t key; char urlbuf[64]; child.charset = c->encoding; child.quirks = c->base.quirks; exc = dom_node_get_text_content(node, &style); if ((exc != DOM_NO_ERR) || (style == NULL)) { LOG("No text content"); return NSERROR_OK; } error = html_css_fetcher_add_item(style, c->base_url, &key); if (error != NSERROR_OK) { dom_string_unref(style); return error; } dom_string_unref(style); snprintf(urlbuf, sizeof(urlbuf), "x-ns-css:%u", key); error = nsurl_create(urlbuf, &url); if (error != NSERROR_OK) { return error; } error = hlcache_handle_retrieve(url, 0, content_get_url(&c->base), NULL, html_convert_css_callback, c, &child, CONTENT_CSS, sheet); if (error != NSERROR_OK) { nsurl_unref(url); return error; } nsurl_unref(url); c->base.active++; LOG("%d fetches active", c->base.active); return NSERROR_OK; }
/* exported interface documented in render/html_internal.h */ bool html_fetch_object(html_content *c, nsurl *url, struct box *box, content_type permitted_types, int available_width, int available_height, bool background) { struct content_html_object *object; hlcache_child_context child; nserror error; /* If we've already been aborted, don't bother attempting the fetch */ if (c->aborted) return true; child.charset = c->encoding; child.quirks = c->base.quirks; object = calloc(1, sizeof(struct content_html_object)); if (object == NULL) { return false; } object->parent = (struct content *) c; object->next = NULL; object->content = NULL; object->box = box; object->permitted_types = permitted_types; object->background = background; error = hlcache_handle_retrieve(url, HLCACHE_RETRIEVE_SNIFF_TYPE, content_get_url(&c->base), NULL, html_object_callback, object, &child, object->permitted_types, &object->content); if (error != NSERROR_OK) { free(object); return error != NSERROR_NOMEM; } /* add to content object list */ object->next = c->object_list; c->object_list = object; c->num_objects++; if (box != NULL) { c->base.active++; LOG("%d fetches active", c->base.active); } return true; }
static bool html_replace_object(struct content_html_object *object, nsurl *url) { html_content *c; hlcache_child_context child; html_content *page; nserror error; assert(object != NULL); assert(object->box != NULL); c = (html_content *) object->parent; child.charset = c->encoding; child.quirks = c->base.quirks; if (object->content != NULL) { /* remove existing object */ if (content_get_status(object->content) != CONTENT_STATUS_DONE) { c->base.active--; LOG("%d fetches active", c->base.active); } hlcache_handle_release(object->content); object->content = NULL; object->box->object = NULL; } /* initialise fetch */ error = hlcache_handle_retrieve(url, HLCACHE_RETRIEVE_SNIFF_TYPE, content_get_url(&c->base), NULL, html_object_callback, object, &child, object->permitted_types, &object->content); if (error != NSERROR_OK) return false; for (page = c; page != NULL; page = page->page) { page->base.active++; LOG("%d fetches active", c->base.active); page->base.status = CONTENT_STATUS_READY; } return true; }
/** * Handle notification of the need for an imported stylesheet * * \param pw CSS object requesting the import * \param parent Stylesheet requesting the import * \param url URL of the imported sheet * \param media Applicable media for the imported sheet * \return CSS_OK on success, appropriate error otherwise */ css_error nscss_handle_import(void *pw, css_stylesheet *parent, lwc_string *url, uint64_t media) { content_type accept = CONTENT_CSS; struct content_css_data *c = pw; nscss_import_ctx *ctx; hlcache_child_context child; struct nscss_import *imports; const char *referer; css_error error; nserror nerror; nsurl *ns_url; nsurl *ns_ref; assert(parent == c->sheet); error = css_stylesheet_get_url(c->sheet, &referer); if (error != CSS_OK) { return error; } ctx = malloc(sizeof(*ctx)); if (ctx == NULL) return CSS_NOMEM; ctx->css = c; ctx->index = c->import_count; /* Increase space in table */ imports = realloc(c->imports, (c->import_count + 1) * sizeof(struct nscss_import)); if (imports == NULL) { free(ctx); return CSS_NOMEM; } c->imports = imports; /** \todo fallback charset */ child.charset = NULL; error = css_stylesheet_quirks_allowed(c->sheet, &child.quirks); if (error != CSS_OK) { free(ctx); return error; } /* Create content */ c->imports[c->import_count].media = media; /* TODO: Why aren't we getting a relative url part, to join? */ nerror = nsurl_create(lwc_string_data(url), &ns_url); if (nerror != NSERROR_OK) { free(ctx); return CSS_NOMEM; } /* TODO: Constructing nsurl for referer here is silly, avoid */ nerror = nsurl_create(referer, &ns_ref); if (nerror != NSERROR_OK) { nsurl_unref(ns_url); free(ctx); return CSS_NOMEM; } /* Avoid importing ourself */ if (nsurl_compare(ns_url, ns_ref, NSURL_COMPLETE)) { c->imports[c->import_count].c = NULL; /* No longer require context as we're not fetching anything */ free(ctx); ctx = NULL; } else { nerror = hlcache_handle_retrieve(ns_url, 0, ns_ref, NULL, nscss_import, ctx, &child, accept, &c->imports[c->import_count].c); if (nerror != NSERROR_OK) { free(ctx); return CSS_NOMEM; } } nsurl_unref(ns_url); nsurl_unref(ns_ref); #ifdef NSCSS_IMPORT_TRACE LOG(("Import %d '%s' -> (handle: %p ctx: %p)", c->import_count, lwc_string_data(url), c->imports[c->import_count].c, ctx)); #endif c->import_count++; return CSS_OK; }
/* exported interface documented in render/html_internal.h */ nserror html_css_new_stylesheets(html_content *c) { nserror ns_error; hlcache_child_context child; if (c->stylesheets != NULL) { return NSERROR_OK; /* already initialised */ } /* stylesheet 0 is the base style sheet, * stylesheet 1 is the quirks mode style sheet, * stylesheet 2 is the adblocking stylesheet, * stylesheet 3 is the user stylesheet */ c->stylesheets = calloc(STYLESHEET_START, sizeof(struct html_stylesheet)); if (c->stylesheets == NULL) { return NSERROR_NOMEM; } c->stylesheets[STYLESHEET_BASE].sheet = NULL; c->stylesheets[STYLESHEET_QUIRKS].sheet = NULL; c->stylesheets[STYLESHEET_ADBLOCK].sheet = NULL; c->stylesheets[STYLESHEET_USER].sheet = NULL; c->stylesheet_count = STYLESHEET_START; child.charset = c->encoding; child.quirks = c->base.quirks; ns_error = hlcache_handle_retrieve(html_default_stylesheet_url, 0, content_get_url(&c->base), NULL, html_convert_css_callback, c, &child, CONTENT_CSS, &c->stylesheets[STYLESHEET_BASE].sheet); if (ns_error != NSERROR_OK) { return ns_error; } c->base.active++; LOG("%d fetches active", c->base.active); if (nsoption_bool(block_advertisements)) { ns_error = hlcache_handle_retrieve(html_adblock_stylesheet_url, 0, content_get_url(&c->base), NULL, html_convert_css_callback, c, &child, CONTENT_CSS, &c->stylesheets[STYLESHEET_ADBLOCK].sheet); if (ns_error != NSERROR_OK) { return ns_error; } c->base.active++; LOG("%d fetches active", c->base.active); } ns_error = hlcache_handle_retrieve(html_user_stylesheet_url, 0, content_get_url(&c->base), NULL, html_convert_css_callback, c, &child, CONTENT_CSS, &c->stylesheets[STYLESHEET_USER].sheet); if (ns_error != NSERROR_OK) { return ns_error; } c->base.active++; LOG("%d fetches active", c->base.active); return ns_error; }
bool html_css_process_link(html_content *htmlc, dom_node *node) { dom_string *rel, *type_attr, *media, *href; struct html_stylesheet *stylesheets; nsurl *joined; dom_exception exc; nserror ns_error; hlcache_child_context child; /* rel=<space separated list, including 'stylesheet'> */ exc = dom_element_get_attribute(node, corestring_dom_rel, &rel); if (exc != DOM_NO_ERR || rel == NULL) return true; if (strcasestr(dom_string_data(rel), "stylesheet") == 0) { dom_string_unref(rel); return true; } else if (strcasestr(dom_string_data(rel), "alternate") != 0) { /* Ignore alternate stylesheets */ dom_string_unref(rel); return true; } dom_string_unref(rel); /* type='text/css' or not present */ exc = dom_element_get_attribute(node, corestring_dom_type, &type_attr); if (exc == DOM_NO_ERR && type_attr != NULL) { if (!dom_string_caseless_lwc_isequal(type_attr, corestring_lwc_text_css)) { dom_string_unref(type_attr); return true; } dom_string_unref(type_attr); } /* media contains 'screen' or 'all' or not present */ exc = dom_element_get_attribute(node, corestring_dom_media, &media); if (exc == DOM_NO_ERR && media != NULL) { if (strcasestr(dom_string_data(media), "screen") == NULL && strcasestr(dom_string_data(media), "all") == NULL) { dom_string_unref(media); return true; } dom_string_unref(media); } /* href='...' */ exc = dom_element_get_attribute(node, corestring_dom_href, &href); if (exc != DOM_NO_ERR || href == NULL) return true; /* TODO: only the first preferred stylesheets (ie. * those with a title attribute) should be loaded * (see HTML4 14.3) */ ns_error = nsurl_join(htmlc->base_url, dom_string_data(href), &joined); if (ns_error != NSERROR_OK) { dom_string_unref(href); goto no_memory; } dom_string_unref(href); LOG("linked stylesheet %i '%s'", htmlc->stylesheet_count, nsurl_access(joined)); /* extend stylesheets array to allow for new sheet */ stylesheets = realloc(htmlc->stylesheets, sizeof(struct html_stylesheet) * (htmlc->stylesheet_count + 1)); if (stylesheets == NULL) { nsurl_unref(joined); ns_error = NSERROR_NOMEM; goto no_memory; } htmlc->stylesheets = stylesheets; htmlc->stylesheets[htmlc->stylesheet_count].node = NULL; htmlc->stylesheets[htmlc->stylesheet_count].modified = false; /* start fetch */ child.charset = htmlc->encoding; child.quirks = htmlc->base.quirks; ns_error = hlcache_handle_retrieve(joined, 0, content_get_url(&htmlc->base), NULL, html_convert_css_callback, htmlc, &child, CONTENT_CSS, &htmlc->stylesheets[htmlc->stylesheet_count].sheet); nsurl_unref(joined); if (ns_error != NSERROR_OK) goto no_memory; htmlc->stylesheet_count++; htmlc->base.active++; LOG("%d fetches active", htmlc->base.active); return true; no_memory: content_broadcast_errorcode(&htmlc->base, ns_error); return false; }
/** * process a script with a src tag */ static dom_hubbub_error exec_src_script(html_content *c, dom_node *node, dom_string *mimetype, dom_string *src) { nserror ns_error; nsurl *joined; hlcache_child_context child; struct html_script *nscript; union content_msg_data msg_data; bool async; bool defer; enum html_script_type script_type; hlcache_handle_callback script_cb; dom_hubbub_error ret = DOM_HUBBUB_OK; dom_exception exc; /* returned by libdom functions */ /* src url */ ns_error = nsurl_join(c->base_url, dom_string_data(src), &joined); if (ns_error != NSERROR_OK) { msg_data.error = messages_get("NoMemory"); content_broadcast(&c->base, CONTENT_MSG_ERROR, msg_data); return DOM_HUBBUB_NOMEM; } LOG(("script %i '%s'", c->scripts_count, nsurl_access(joined))); /* there are three ways to process the script tag at this point: * * Syncronously pause the parent parse and continue after * the script has downloaded and executed. (default) * Async Start the script downloading and execute it when it * becomes available. * Defered Start the script downloading and execute it when * the page has completed parsing, may be set along * with async where it is ignored. */ /* we interpret the presence of the async and defer attribute * as true and ignore its value, technically only the empty * value or the attribute name itself are valid. However * various browsers interpret this in various ways the most * compatible approach is to be liberal and accept any * value. Note setting the values to "false" still makes them true! */ exc = dom_element_has_attribute(node, corestring_dom_async, &async); if (exc != DOM_NO_ERR) { return DOM_HUBBUB_OK; /* dom error */ } if (async) { /* asyncronous script */ script_type = HTML_SCRIPT_ASYNC; script_cb = convert_script_async_cb; } else { exc = dom_element_has_attribute(node, corestring_dom_defer, &defer); if (exc != DOM_NO_ERR) { return DOM_HUBBUB_OK; /* dom error */ } if (defer) { /* defered script */ script_type = HTML_SCRIPT_DEFER; script_cb = convert_script_defer_cb; } else { /* syncronous script */ script_type = HTML_SCRIPT_SYNC; script_cb = convert_script_sync_cb; } } nscript = html_process_new_script(c, mimetype, script_type); if (nscript == NULL) { nsurl_unref(joined); msg_data.error = messages_get("NoMemory"); content_broadcast(&c->base, CONTENT_MSG_ERROR, msg_data); return DOM_HUBBUB_NOMEM; } /* set up child fetch encoding and quirks */ child.charset = c->encoding; child.quirks = c->base.quirks; ns_error = hlcache_handle_retrieve(joined, 0, content_get_url(&c->base), NULL, script_cb, c, &child, CONTENT_SCRIPT, &nscript->data.handle); nsurl_unref(joined); if (ns_error != NSERROR_OK) { /* @todo Deal with fetch error better. currently assume * fetch never became active */ /* mark duff script fetch as already started */ nscript->already_started = true; LOG(("Fetch failed with error %d",ns_error)); } else { /* update base content active fetch count */ c->base.active++; LOG(("%d fetches active", c->base.active)); switch (script_type) { case HTML_SCRIPT_SYNC: ret = DOM_HUBBUB_HUBBUB_ERR | HUBBUB_PAUSED; case HTML_SCRIPT_ASYNC: break; case HTML_SCRIPT_DEFER: break; default: assert(0); } } return ret; }