diff options
Diffstat (limited to 'css/css.c')
-rw-r--r-- | css/css.c | 434 |
1 files changed, 204 insertions, 230 deletions
@@ -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; } |