From 6722943b81c0dba84ed187b2d117cc92972117ed Mon Sep 17 00:00:00 2001 From: Vincent Sanders Date: Thu, 26 May 2016 11:18:41 +0100 Subject: move the CSS content handler --- Docs/Doxyfile | 3 +- Makefile | 7 +- content/handlers/Makefile | 7 +- content/handlers/css/Makefile | 4 + content/handlers/css/css.c | 834 ++++++++++++++++++ content/handlers/css/css.h | 62 ++ content/handlers/css/dump.c | 1793 +++++++++++++++++++++++++++++++++++++ content/handlers/css/dump.h | 30 + content/handlers/css/hints.c | 1604 +++++++++++++++++++++++++++++++++ content/handlers/css/hints.h | 55 ++ content/handlers/css/internal.c | 63 ++ content/handlers/css/internal.h | 35 + content/handlers/css/select.c | 1854 +++++++++++++++++++++++++++++++++++++++ content/handlers/css/select.h | 58 ++ content/handlers/css/utils.c | 127 +++ content/handlers/css/utils.h | 49 ++ content/handlers/image/Makefile | 2 +- content/handlers/image/svg.c | 2 +- css/Makefile | 5 - css/css.c | 847 ------------------ css/css.h | 44 - css/dump.c | 1806 -------------------------------------- css/dump.h | 26 - css/hints.c | 1611 ---------------------------------- css/hints.h | 49 -- css/internal.c | 73 -- css/internal.h | 27 - css/select.c | 1854 --------------------------------------- css/select.h | 57 -- css/utils.c | 142 --- css/utils.h | 70 -- desktop/browser.c | 2 +- desktop/browser_history.c | 1 - desktop/font_haru.c | 3 - desktop/netsurf.c | 2 +- desktop/print.c | 2 +- desktop/print.h | 3 +- desktop/save_complete.c | 2 +- desktop/save_pdf.c | 11 +- desktop/system_colour.c | 4 +- desktop/textarea.c | 2 +- desktop/tree.c | 1 - desktop/treeview.c | 2 +- frontends/amiga/plotters.c | 2 +- include/netsurf/css.h | 65 ++ render/box.c | 5 +- render/box.h | 3 +- render/box_construct.c | 7 +- render/box_normalise.c | 8 +- render/font.c | 3 +- render/form.c | 3 +- render/html.h | 1 - render/html_css.c | 1 + render/html_internal.h | 5 +- render/html_object.c | 2 +- render/html_redraw.c | 3 +- render/layout.c | 5 +- render/table.c | 9 +- render/textplain.c | 3 +- 59 files changed, 6688 insertions(+), 6672 deletions(-) create mode 100644 content/handlers/css/Makefile create mode 100644 content/handlers/css/css.c create mode 100644 content/handlers/css/css.h create mode 100644 content/handlers/css/dump.c create mode 100644 content/handlers/css/dump.h create mode 100644 content/handlers/css/hints.c create mode 100644 content/handlers/css/hints.h create mode 100644 content/handlers/css/internal.c create mode 100644 content/handlers/css/internal.h create mode 100644 content/handlers/css/select.c create mode 100644 content/handlers/css/select.h create mode 100644 content/handlers/css/utils.c create mode 100644 content/handlers/css/utils.h delete mode 100644 css/Makefile delete mode 100644 css/css.c delete mode 100644 css/css.h delete mode 100644 css/dump.c delete mode 100644 css/dump.h delete mode 100644 css/hints.c delete mode 100644 css/hints.h delete mode 100644 css/internal.c delete mode 100644 css/internal.h delete mode 100644 css/select.c delete mode 100644 css/select.h delete mode 100644 css/utils.c delete mode 100644 css/utils.h create mode 100644 include/netsurf/css.h diff --git a/Docs/Doxyfile b/Docs/Doxyfile index 5b8b25316..24cc3da77 100644 --- a/Docs/Doxyfile +++ b/Docs/Doxyfile @@ -672,12 +672,13 @@ INPUT = frontends/amiga \ frontends/riscos/templates \ frontends/riscos/scripts \ frontends/windows \ - css \ + include/netsurf \ render \ desktop \ content \ content/fetchers \ content/handlers/image \ + content/handlers/css \ javascript \ javascript/jsapi \ utils \ diff --git a/Makefile b/Makefile index 35e734e60..fe97f1c4d 100644 --- a/Makefile +++ b/Makefile @@ -539,8 +539,8 @@ $(eval $(call pkg_config_find_and_add_enabled,NSSVG,libsvgtiny,SVG)) $(eval $(call pkg_config_find_and_add_enabled,ROSPRITE,librosprite,Sprite)) # add top level and build directory to include search path -CFLAGS += -I. -Ifrontends -I$(OBJROOT) -CXXFLAGS += -I. -Ifrontends -I$(OBJROOT) +CFLAGS += -I. -Iinclude -Ifrontends -I$(OBJROOT) +CXXFLAGS += -I. -Iinclude -Ifrontends -I$(OBJROOT) # export the user agent format CFLAGS += -DNETSURF_UA_FORMAT_STRING=\"$(NETSURF_UA_FORMAT_STRING)\" @@ -585,9 +585,6 @@ include frontends/Makefile # Content sources include content/Makefile -# CSS sources -include css/Makefile - # render sources include render/Makefile diff --git a/content/handlers/Makefile b/content/handlers/Makefile index 97d2813b4..a12d8cc21 100644 --- a/content/handlers/Makefile +++ b/content/handlers/Makefile @@ -1,4 +1,9 @@ # Image content handler sources include content/handlers/image/Makefile -S_IMAGE := $(addprefix content/handlers/,$(S_IMAGE)) +S_IMAGE := $(addprefix content/handlers/image/,$(S_IMAGE)) + +# CSS sources +include content/handlers/css/Makefile + +S_CSS := $(addprefix content/handlers/css/,$(S_CSS)) diff --git a/content/handlers/css/Makefile b/content/handlers/css/Makefile new file mode 100644 index 000000000..bbfc8d7b4 --- /dev/null +++ b/content/handlers/css/Makefile @@ -0,0 +1,4 @@ +# CSS sources + +S_CSS := css.c dump.c internal.c hints.c select.c utils.c + diff --git a/content/handlers/css/css.c b/content/handlers/css/css.c new file mode 100644 index 000000000..4c0cb7a4c --- /dev/null +++ b/content/handlers/css/css.c @@ -0,0 +1,834 @@ +/* + * Copyright 2009 John-Mark Bell + * + * 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 . + */ + +#include +#include +#include + +#include "content/content_protected.h" +#include "content/fetch.h" +#include "content/hlcache.h" +#include "desktop/system_colour.h" +#include "utils/corestrings.h" +#include "utils/utils.h" +#include "utils/http.h" +#include "utils/log.h" +#include "utils/messages.h" + +#include "css.h" +#include "hints.h" +#include "internal.h" + +/* Define to trace import fetches */ +#undef NSCSS_IMPORT_TRACE + +struct content_css_data; + +/** + * Type of callback called when a CSS object has finished + * + * \param css CSS object that has completed + * \param pw Client-specific data + */ +typedef void (*nscss_done_callback)(struct content_css_data *css, void *pw); + +/** + * CSS content data + */ +struct content_css_data +{ + css_stylesheet *sheet; /**< Stylesheet object */ + char *charset; /**< Character set of stylesheet */ + struct nscss_import *imports; /**< Array of imported sheets */ + uint32_t import_count; /**< Number of sheets imported */ + uint32_t next_to_register; /**< Index of next import to register */ + nscss_done_callback done; /**< Completion callback */ + void *pw; /**< Client data */ +}; + +/** + * CSS content data + */ +typedef struct nscss_content +{ + struct content base; /**< Underlying content object */ + + struct content_css_data data; /**< CSS data */ +} nscss_content; + +/** + * Context for import fetches + */ +typedef struct { + struct content_css_data *css; /**< Object containing import */ + uint32_t index; /**< Index into parent sheet's + * imports array */ +} nscss_import_ctx; + +static bool nscss_process_data(struct content *c, const char *data, + unsigned int size); +static bool nscss_convert(struct content *c); +static void nscss_destroy(struct content *c); +static nserror nscss_clone(const struct content *old, struct content **newc); +static bool nscss_matches_quirks(const struct content *c, bool quirks); +static content_type nscss_content_type(void); + +static nserror nscss_create_css_data(struct content_css_data *c, + const char *url, const char *charset, bool quirks, + nscss_done_callback done, void *pw); +static css_error nscss_process_css_data(struct content_css_data *c, const char *data, + unsigned int size); +static css_error nscss_convert_css_data(struct content_css_data *c); +static void nscss_destroy_css_data(struct content_css_data *c); + +static void nscss_content_done(struct content_css_data *css, void *pw); +static css_error nscss_handle_import(void *pw, css_stylesheet *parent, + lwc_string *url, uint64_t media); +static nserror nscss_import(hlcache_handle *handle, + const hlcache_event *event, void *pw); +static css_error nscss_import_complete(nscss_import_ctx *ctx); + +static css_error nscss_register_imports(struct content_css_data *c); +static css_error nscss_register_import(struct content_css_data *c, + const hlcache_handle *import); + + +static css_stylesheet *blank_import; + + +/** + * Initialise a CSS content + * + * \param handler content handler + * \param imime_type mime-type + * \param params Content-Type parameters + * \param llcache handle to content + * \param fallback_charset The character set to fallback to. + * \param quirks allow quirks + * \param c Content to initialise + * \return NSERROR_OK or error cod eon faliure + */ +static nserror +nscss_create(const content_handler *handler, + lwc_string *imime_type, + const http_parameter *params, + llcache_handle *llcache, + const char *fallback_charset, + bool quirks, + struct content **c) +{ + nscss_content *result; + const char *charset = NULL; + const char *xnsbase = NULL; + lwc_string *charset_value = NULL; + union content_msg_data msg_data; + nserror error; + + result = calloc(1, sizeof(nscss_content)); + if (result == NULL) + return NSERROR_NOMEM; + + error = content__init(&result->base, handler, imime_type, + params, llcache, fallback_charset, quirks); + if (error != NSERROR_OK) { + free(result); + return error; + } + + /* Find charset specified on HTTP layer, if any */ + error = http_parameter_list_find_item(params, corestring_lwc_charset, + &charset_value); + if (error != NSERROR_OK || lwc_string_length(charset_value) == 0) { + /* No charset specified, use fallback, if any */ + /** \todo libcss will take this as gospel, which is wrong */ + charset = fallback_charset; + } else { + charset = lwc_string_data(charset_value); + } + + /* Compute base URL for stylesheet */ + xnsbase = llcache_handle_get_header(llcache, "X-NS-Base"); + if (xnsbase == NULL) { + xnsbase = nsurl_access(content_get_url(&result->base)); + } + + error = nscss_create_css_data(&result->data, + xnsbase, charset, result->base.quirks, + nscss_content_done, result); + if (error != NSERROR_OK) { + msg_data.error = messages_get("NoMemory"); + content_broadcast(&result->base, CONTENT_MSG_ERROR, msg_data); + if (charset_value != NULL) + lwc_string_unref(charset_value); + free(result); + return error; + } + + if (charset_value != NULL) + lwc_string_unref(charset_value); + + *c = (struct content *) result; + + return NSERROR_OK; +} + +/** + * 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 + * \param done Callback to call when content has completed + * \param pw Client data for \a done + * \return NSERROR_OK on success, NSERROR_NOMEM on memory exhaustion + */ +static nserror nscss_create_css_data(struct content_css_data *c, + const char *url, const char *charset, bool quirks, + nscss_done_callback done, void *pw) +{ + css_error error; + css_stylesheet_params params; + + c->pw = pw; + c->done = done; + c->next_to_register = (uint32_t) -1; + c->import_count = 0; + c->imports = NULL; + if (charset != NULL) + c->charset = strdup(charset); + else + c->charset = NULL; + + params.params_version = CSS_STYLESHEET_PARAMS_VERSION_1; + params.level = CSS_LEVEL_DEFAULT; + params.charset = charset; + params.url = url; + params.title = NULL; + params.allow_quirks = quirks; + params.inline_style = false; + params.resolve = nscss_resolve_url; + params.resolve_pw = NULL; + params.import = nscss_handle_import; + params.import_pw = c; + params.color = ns_system_colour; + params.color_pw = NULL; + params.font = NULL; + params.font_pw = NULL; + + error = css_stylesheet_create(¶ms, &c->sheet); + if (error != CSS_OK) { + return NSERROR_NOMEM; + } + + return NSERROR_OK; +} + +/** + * Process CSS source data + * + * \param c Content structure + * \param data Data to process + * \param size Number of bytes to process + * \return true on success, false on failure + */ +bool nscss_process_data(struct content *c, const char *data, unsigned int size) +{ + nscss_content *css = (nscss_content *) c; + union content_msg_data msg_data; + css_error error; + + error = nscss_process_css_data(&css->data, data, size); + if (error != CSS_OK && error != CSS_NEEDDATA) { + msg_data.error = "?"; + content_broadcast(c, CONTENT_MSG_ERROR, msg_data); + } + + return (error == CSS_OK || error == CSS_NEEDDATA); +} + +/** + * 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 + */ +static css_error nscss_process_css_data(struct content_css_data *c, + const 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 + * \return true on success, false on failure + */ +bool nscss_convert(struct content *c) +{ + nscss_content *css = (nscss_content *) c; + union content_msg_data msg_data; + css_error error; + + error = nscss_convert_css_data(&css->data); + if (error != CSS_OK) { + msg_data.error = "?"; + content_broadcast(c, CONTENT_MSG_ERROR, msg_data); + return false; + } + + return true; +} + +/** + * Convert CSS data ready for use + * + * \param c CSS data to convert + * \return CSS error + */ +static css_error nscss_convert_css_data(struct content_css_data *c) +{ + css_error error; + + error = css_stylesheet_data_done(c->sheet); + + /* Process pending imports */ + if (error == CSS_IMPORTS_PENDING) { + /* We must not have registered any imports yet */ + assert(c->next_to_register == (uint32_t) -1); + + /* Start registering, until we find one that + * hasn't finished fetching */ + c->next_to_register = 0; + error = nscss_register_imports(c); + } else if (error == CSS_OK) { + /* No imports, and no errors, so complete conversion */ + c->done(c, c->pw); + } else { + const char *url; + + if (css_stylesheet_get_url(c->sheet, &url) == CSS_OK) { + LOG("Failed converting %p %s (%d)", c, url, error); + } else { + LOG("Failed converting %p (%d)", c, error); + } + } + + return error; +} + +/** + * Clean up a CSS content + * + * \param c Content to clean up + */ +void nscss_destroy(struct content *c) +{ + nscss_content *css = (nscss_content *) c; + + nscss_destroy_css_data(&css->data); +} + +/** + * Clean up CSS data + * + * \param c CSS data to clean up + */ +static void nscss_destroy_css_data(struct content_css_data *c) +{ + uint32_t i; + + for (i = 0; i < c->import_count; i++) { + if (c->imports[i].c != NULL) { + hlcache_handle_release(c->imports[i].c); + } + c->imports[i].c = NULL; + } + + free(c->imports); + + if (c->sheet != NULL) { + css_stylesheet_destroy(c->sheet); + c->sheet = NULL; + } + + free(c->charset); +} + +nserror nscss_clone(const struct content *old, struct content **newc) +{ + const nscss_content *old_css = (const nscss_content *) old; + nscss_content *new_css; + const char *data; + unsigned long size; + nserror error; + + new_css = calloc(1, sizeof(nscss_content)); + if (new_css == NULL) + return NSERROR_NOMEM; + + /* Clone content */ + error = content__clone(old, &new_css->base); + if (error != NSERROR_OK) { + content_destroy(&new_css->base); + return error; + } + + /* Simply replay create/process/convert */ + error = nscss_create_css_data(&new_css->data, + nsurl_access(content_get_url(&new_css->base)), + old_css->data.charset, + new_css->base.quirks, + nscss_content_done, new_css); + if (error != NSERROR_OK) { + content_destroy(&new_css->base); + return error; + } + + data = content__get_source_data(&new_css->base, &size); + if (size > 0) { + if (nscss_process_data(&new_css->base, data, size) == false) { + content_destroy(&new_css->base); + return NSERROR_CLONE_FAILED; + } + } + + if (old->status == CONTENT_STATUS_READY || + old->status == CONTENT_STATUS_DONE) { + if (nscss_convert(&new_css->base) == false) { + content_destroy(&new_css->base); + return NSERROR_CLONE_FAILED; + } + } + + *newc = (struct content *) new_css; + + return NSERROR_OK; +} + +bool nscss_matches_quirks(const struct content *c, bool quirks) +{ + return c->quirks == quirks; +} + +/* exported interface documented in netsurf/css.h */ +css_stylesheet *nscss_get_stylesheet(struct hlcache_handle *h) +{ + nscss_content *c = (nscss_content *) hlcache_handle_get_content(h); + + assert(c != NULL); + + return c->data.sheet; +} + +/* exported interface documented in netsurf/css.h */ +struct nscss_import *nscss_get_imports(hlcache_handle *h, uint32_t *n) +{ + nscss_content *c = (nscss_content *) hlcache_handle_get_content(h); + + assert(c != NULL); + assert(n != NULL); + + *n = c->data.import_count; + + return c->data.imports; +} + +/** + * Compute the type of a content + * + * \return CONTENT_CSS + */ +content_type nscss_content_type(void) +{ + return CONTENT_CSS; +} + +/***************************************************************************** + * Object completion * + *****************************************************************************/ + +/** + * Handle notification that a CSS object is done + * + * \param css CSS object + * \param pw Private data + */ +void nscss_content_done(struct content_css_data *css, void *pw) +{ + union content_msg_data msg_data; + struct content *c = pw; + uint32_t i; + size_t size; + css_error error; + + /* Retrieve the size of this sheet */ + error = css_stylesheet_size(css->sheet, &size); + if (error != CSS_OK) { + msg_data.error = "?"; + content_broadcast(c, CONTENT_MSG_ERROR, msg_data); + content_set_error(c); + return; + } + c->size += size; + + /* Add on the size of the imported sheets */ + for (i = 0; i < css->import_count; i++) { + if (css->imports[i].c != NULL) { + struct content *import = hlcache_handle_get_content( + css->imports[i].c); + + if (import != NULL) { + c->size += import->size; + } + } + } + + /* Finally, catch the content's users up with reality */ + content_set_ready(c); + content_set_done(c); +} + +/***************************************************************************** + * Import handling * + *****************************************************************************/ + +/** + * 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; +} + +/** + * Handler for imported stylesheet events + * + * \param handle Handle for stylesheet + * \param event Event object + * \param pw Callback context + * \return NSERROR_OK on success, appropriate error otherwise + */ +nserror nscss_import(hlcache_handle *handle, + const hlcache_event *event, void *pw) +{ + nscss_import_ctx *ctx = pw; + css_error error = CSS_OK; + +#ifdef NSCSS_IMPORT_TRACE + LOG("Event %d for %p (%p)", event->type, handle, ctx); +#endif + + assert(ctx->css->imports[ctx->index].c == handle); + + switch (event->type) { + case CONTENT_MSG_DONE: + error = nscss_import_complete(ctx); + break; + + case CONTENT_MSG_ERROR: + hlcache_handle_release(handle); + ctx->css->imports[ctx->index].c = NULL; + + error = nscss_import_complete(ctx); + /* Already released handle */ + break; + + default: + break; + } + + /* Preserve out-of-memory. Anything else is OK */ + return error == CSS_NOMEM ? NSERROR_NOMEM : NSERROR_OK; +} + +/** + * Handle an imported stylesheet completing + * + * \param ctx Import context + * \return CSS_OK on success, appropriate error otherwise + */ +css_error nscss_import_complete(nscss_import_ctx *ctx) +{ + css_error error = CSS_OK; + + /* If this import is the next to be registered, do so */ + if (ctx->css->next_to_register == ctx->index) + error = nscss_register_imports(ctx->css); + +#ifdef NSCSS_IMPORT_TRACE + LOG("Destroying import context %p for %d", ctx, ctx->index); +#endif + + /* No longer need import context */ + free(ctx); + + return error; +} + +/***************************************************************************** + * Import registration * + *****************************************************************************/ + +/** + * Register imports with a stylesheet + * + * \param c CSS object containing the imports + * \return CSS_OK on success, appropriate error otherwise + */ +css_error nscss_register_imports(struct content_css_data *c) +{ + uint32_t index; + css_error error; + + assert(c->next_to_register != (uint32_t) -1); + assert(c->next_to_register < c->import_count); + + /* Register imported sheets */ + for (index = c->next_to_register; index < c->import_count; index++) { + /* Stop registering if we encounter one whose fetch hasn't + * completed yet. We'll resume at this point when it has + * completed. + */ + if (c->imports[index].c != NULL && + content_get_status(c->imports[index].c) != + CONTENT_STATUS_DONE) { + break; + } + + error = nscss_register_import(c, c->imports[index].c); + if (error != CSS_OK) + return error; + } + + /* Record identity of the next import to register */ + c->next_to_register = (uint32_t) index; + + if (c->next_to_register == c->import_count) { + /* No more imports: notify parent that we're DONE */ + c->done(c, c->pw); + } + + return CSS_OK; +} + + +/** + * Register an import with a stylesheet + * + * \param c CSS object that requested the import + * \param import Cache handle of import, or NULL for blank + * \return CSS_OK on success, appropriate error otherwise + */ +css_error nscss_register_import(struct content_css_data *c, + const hlcache_handle *import) +{ + css_stylesheet *sheet; + css_error error; + + if (import != NULL) { + nscss_content *s = + (nscss_content *) hlcache_handle_get_content(import); + sheet = s->data.sheet; + } else { + /* Create a blank sheet if needed. */ + if (blank_import == NULL) { + css_stylesheet_params params; + + params.params_version = CSS_STYLESHEET_PARAMS_VERSION_1; + params.level = CSS_LEVEL_DEFAULT; + params.charset = NULL; + params.url = ""; + params.title = NULL; + params.allow_quirks = false; + params.inline_style = false; + params.resolve = nscss_resolve_url; + params.resolve_pw = NULL; + params.import = NULL; + params.import_pw = NULL; + params.color = ns_system_colour; + params.color_pw = NULL; + params.font = NULL; + params.font_pw = NULL; + + error = css_stylesheet_create(¶ms, &blank_import); + if (error != CSS_OK) { + return error; + } + + error = css_stylesheet_data_done(blank_import); + if (error != CSS_OK) { + css_stylesheet_destroy(blank_import); + return error; + } + } + + sheet = blank_import; + } + + error = css_stylesheet_register_import(c->sheet, sheet); + if (error != CSS_OK) { + return error; + } + + return error; +} + +/** + * Clean up after the CSS content handler + */ +static void nscss_fini(void) +{ + if (blank_import != NULL) { + css_stylesheet_destroy(blank_import); + blank_import = NULL; + } + css_hint_fini(); +} + +static const content_handler css_content_handler = { + .fini = nscss_fini, + .create = nscss_create, + .process_data = nscss_process_data, + .data_complete = nscss_convert, + .destroy = nscss_destroy, + .clone = nscss_clone, + .matches_quirks = nscss_matches_quirks, + .type = nscss_content_type, + .no_share = false, +}; + +/* exported interface documented in netsurf/css.h */ +nserror nscss_init(void) +{ + nserror error; + + error = content_factory_register_handler("text/css", + &css_content_handler); + if (error != NSERROR_OK) + goto error; + + error = css_hint_init(); + if (error != NSERROR_OK) + goto error; + + return NSERROR_OK; + +error: + nscss_fini(); + + return error; +} diff --git a/content/handlers/css/css.h b/content/handlers/css/css.h new file mode 100644 index 000000000..4b38829f0 --- /dev/null +++ b/content/handlers/css/css.h @@ -0,0 +1,62 @@ +/* + * Copyright 2009 John-Mark Bell + * + * 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 . + */ + +#ifndef netsurf_css_css_h_ +#define netsurf_css_css_h_ + +#include + +#include + +#include "utils/errors.h" + +struct hlcache_handle; + +/** + * Imported stylesheet record + */ +struct nscss_import { + struct hlcache_handle *c; /**< Content containing sheet */ + uint64_t media; /**< Media types that sheet applies to */ +}; + +/** + * Initialise the CSS content handler + * + * \return NSERROR_OK on success or error code on faliure + */ +nserror nscss_init(void); + +/** + * Retrieve the stylesheet object associated with a CSS content + * + * \param h Stylesheet content + * \return Pointer to stylesheet object + */ +css_stylesheet *nscss_get_stylesheet(struct hlcache_handle *h); + +/** + * 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(struct hlcache_handle *h, uint32_t *n); + +#endif diff --git a/content/handlers/css/dump.c b/content/handlers/css/dump.c new file mode 100644 index 000000000..125b133cf --- /dev/null +++ b/content/handlers/css/dump.c @@ -0,0 +1,1793 @@ +/* + * Copyright 2009 John-Mark Bell + * + * 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 . + */ + +#include +#include + +#include "dump.h" + +/** + * Dump a fixed point value to the stream in a textual form. + * + * \param stream Stream to write to + * \param f Value to write + */ +static void dump_css_fixed(FILE *stream, css_fixed f) +{ +#define NSCSS_ABS(x) (uint32_t)((x) < 0 ? -(x) : (x)) + uint32_t uintpart = FIXTOINT(NSCSS_ABS(f)); + /* + 500 to ensure round to nearest (division will truncate) */ + uint32_t fracpart = ((NSCSS_ABS(f) & 0x3ff) * 1000 + 500) / (1 << 10); +#undef NSCSS_ABS + + fprintf(stream, "%s%d.%03d", f < 0 ? "-" : "", uintpart, fracpart); +} + +/** + * Dump a numeric value to the stream in a textual form. + * + * \param stream Stream to write to + * \param val Value to write + */ +static void dump_css_number(FILE *stream, css_fixed val) +{ + if (INTTOFIX(FIXTOINT(val)) == val) + fprintf(stream, "%d", FIXTOINT(val)); + else + dump_css_fixed(stream, val); +} + +/** + * Dump a dimension to the stream in a textual form. + * + * \param stream Stream to write to + * \param val Value to write + * \param unit Unit to write + */ +static void dump_css_unit(FILE *stream, css_fixed val, css_unit unit) +{ + dump_css_number(stream, val); + + switch (unit) { + case CSS_UNIT_PX: + fprintf(stream, "px"); + break; + case CSS_UNIT_EX: + fprintf(stream, "ex"); + break; + case CSS_UNIT_EM: + fprintf(stream, "em"); + break; + case CSS_UNIT_IN: + fprintf(stream, "in"); + break; + case CSS_UNIT_CM: + fprintf(stream, "cm"); + break; + case CSS_UNIT_MM: + fprintf(stream, "mm"); + break; + case CSS_UNIT_PT: + fprintf(stream, "pt"); + break; + case CSS_UNIT_PC: + fprintf(stream, "pc"); + break; + case CSS_UNIT_PCT: + fprintf(stream, "%%"); + break; + case CSS_UNIT_DEG: + fprintf(stream, "deg"); + break; + case CSS_UNIT_GRAD: + fprintf(stream, "grad"); + break; + case CSS_UNIT_RAD: + fprintf(stream, "rad"); + break; + case CSS_UNIT_MS: + fprintf(stream, "ms"); + break; + case CSS_UNIT_S: + fprintf(stream, "s"); + break; + case CSS_UNIT_HZ: + fprintf(stream, "Hz"); + break; + case CSS_UNIT_KHZ: + fprintf(stream, "kHz"); + break; + } +} + +/* exported interface documented in content/handlers/css/dump.h */ +void nscss_dump_computed_style(FILE *stream, const css_computed_style *style) +{ + uint8_t val; + css_color color = 0; + lwc_string *url = NULL; + css_fixed len1 = 0, len2 = 0; + css_unit unit1 = CSS_UNIT_PX, unit2 = CSS_UNIT_PX; + css_computed_clip_rect rect = { 0, 0, 0, 0, CSS_UNIT_PX, CSS_UNIT_PX, + CSS_UNIT_PX, CSS_UNIT_PX, true, true, + true, true }; + const css_computed_content_item *content = NULL; + const css_computed_counter *counter = NULL; + lwc_string **string_list = NULL; + int32_t zindex = 0; + + fprintf(stream, "{ "); + + /* background-attachment */ + val = css_computed_background_attachment(style); + switch (val) { + case CSS_BACKGROUND_ATTACHMENT_FIXED: + fprintf(stream, "background-attachment: fixed "); + break; + case CSS_BACKGROUND_ATTACHMENT_SCROLL: + fprintf(stream, "background-attachment: scroll "); + break; + default: + break; + } + + /* background-color */ + val = css_computed_background_color(style, &color); + switch (val) { + case CSS_BACKGROUND_COLOR_COLOR: + fprintf(stream, "background-color: #%08x ", color); + break; + default: + break; + } + + /* background-image */ + val = css_computed_background_image(style, &url); + if (val == CSS_BACKGROUND_IMAGE_IMAGE && url != NULL) { + fprintf(stream, "background-image: url('%.*s') ", + (int) lwc_string_length(url), + lwc_string_data(url)); + } else if (val == CSS_BACKGROUND_IMAGE_NONE) { + fprintf(stream, "background-image: none "); + } + + /* background-position */ + val = css_computed_background_position(style, &len1, &unit1, + &len2, &unit2); + if (val == CSS_BACKGROUND_POSITION_SET) { + fprintf(stream, "background-position: "); + dump_css_unit(stream, len1, unit1); + fprintf(stream, " "); + dump_css_unit(stream, len2, unit2); + fprintf(stream, " "); + } + + /* background-repeat */ + val = css_computed_background_repeat(style); + switch (val) { + case CSS_BACKGROUND_REPEAT_REPEAT_X: + fprintf(stream, "background-repeat: repeat-x "); + break; + case CSS_BACKGROUND_REPEAT_REPEAT_Y: + fprintf(stream, "background-repeat: repeat-y "); + break; + case CSS_BACKGROUND_REPEAT_REPEAT: + fprintf(stream, "background-repeat: repeat "); + break; + case CSS_BACKGROUND_REPEAT_NO_REPEAT: + fprintf(stream, "background-repeat: no-repeat "); + break; + default: + break; + } + + /* border-collapse */ + val = css_computed_border_collapse(style); + switch (val) { + case CSS_BORDER_COLLAPSE_SEPARATE: + fprintf(stream, "border-collapse: separate "); + break; + case CSS_BORDER_COLLAPSE_COLLAPSE: + fprintf(stream, "border-collapse: collapse "); + break; + default: + + break; + } + + /* border-spacing */ + val = css_computed_border_spacing(style, &len1, &unit1, &len2, &unit2); + if (val == CSS_BORDER_SPACING_SET) { + fprintf(stream, "border-spacing: "); + dump_css_unit(stream, len1, unit1); + fprintf(stream, " "); + dump_css_unit(stream, len2, unit2); + fprintf(stream, " "); + } + + /* border-top-color */ + val = css_computed_border_top_color(style, &color); + switch (val) { + case CSS_BORDER_COLOR_COLOR: + fprintf(stream, "border-top-color: #%08x ", color); + break; + default: + break; + } + + /* border-right-color */ + val = css_computed_border_right_color(style, &color); + switch (val) { + case CSS_BORDER_COLOR_COLOR: + fprintf(stream, "border-right-color: #%08x ", color); + break; + default: + break; + } + + /* border-bottom-color */ + val = css_computed_border_bottom_color(style, &color); + switch (val) { + case CSS_BORDER_COLOR_COLOR: + fprintf(stream, "border-bottom-color: #%08x ", color); + break; + default: + break; + } + + /* border-left-color */ + val = css_computed_border_left_color(style, &color); + switch (val) { + case CSS_BORDER_COLOR_COLOR: + fprintf(stream, "border-left-color: #%08x ", color); + break; + default: + break; + } + + /* border-top-style */ + val = css_computed_border_top_style(style); + switch (val) { + case CSS_BORDER_STYLE_NONE: + fprintf(stream, "border-top-style: none "); + break; + case CSS_BORDER_STYLE_HIDDEN: + fprintf(stream, "border-top-style: hidden "); + break; + case CSS_BORDER_STYLE_DOTTED: + fprintf(stream, "border-top-style: dotted "); + break; + case CSS_BORDER_STYLE_DASHED: + fprintf(stream, "border-top-style: dashed "); + break; + case CSS_BORDER_STYLE_SOLID: + fprintf(stream, "border-top-style: solid "); + break; + case CSS_BORDER_STYLE_DOUBLE: + fprintf(stream, "border-top-style: double "); + break; + case CSS_BORDER_STYLE_GROOVE: + fprintf(stream, "border-top-style: groove "); + break; + case CSS_BORDER_STYLE_RIDGE: + fprintf(stream, "border-top-style: ridge "); + break; + case CSS_BORDER_STYLE_INSET: + fprintf(stream, "border-top-style: inset "); + break; + case CSS_BORDER_STYLE_OUTSET: + fprintf(stream, "border-top-style: outset "); + break; + default: + break; + } + + /* border-right-style */ + val = css_computed_border_right_style(style); + switch (val) { + case CSS_BORDER_STYLE_NONE: + fprintf(stream, "border-right-style: none "); + break; + case CSS_BORDER_STYLE_HIDDEN: + fprintf(stream, "border-right-style: hidden "); + break; + case CSS_BORDER_STYLE_DOTTED: + fprintf(stream, "border-right-style: dotted "); + break; + case CSS_BORDER_STYLE_DASHED: + fprintf(stream, "border-right-style: dashed "); + break; + case CSS_BORDER_STYLE_SOLID: + fprintf(stream, "border-right-style: solid "); + break; + case CSS_BORDER_STYLE_DOUBLE: + fprintf(stream, "border-right-style: double "); + break; + case CSS_BORDER_STYLE_GROOVE: + fprintf(stream, "border-right-style: groove "); + break; + case CSS_BORDER_STYLE_RIDGE: + fprintf(stream, "border-right-style: ridge "); + break; + case CSS_BORDER_STYLE_INSET: + fprintf(stream, "border-right-style: inset "); + break; + case CSS_BORDER_STYLE_OUTSET: + fprintf(stream, "border-right-style: outset "); + break; + default: + break; + } + + /* border-bottom-style */ + val = css_computed_border_bottom_style(style); + switch (val) { + case CSS_BORDER_STYLE_NONE: + fprintf(stream, "border-bottom-style: none "); + break; + case CSS_BORDER_STYLE_HIDDEN: + fprintf(stream, "border-bottom-style: hidden "); + break; + case CSS_BORDER_STYLE_DOTTED: + fprintf(stream, "border-bottom-style: dotted "); + break; + case CSS_BORDER_STYLE_DASHED: + fprintf(stream, "border-bottom-style: dashed "); + break; + case CSS_BORDER_STYLE_SOLID: + fprintf(stream, "border-bottom-style: solid "); + break; + case CSS_BORDER_STYLE_DOUBLE: + fprintf(stream, "border-bottom-style: double "); + break; + case CSS_BORDER_STYLE_GROOVE: + fprintf(stream, "border-bottom-style: groove "); + break; + case CSS_BORDER_STYLE_RIDGE: + fprintf(stream, "border-bottom-style: ridge "); + break; + case CSS_BORDER_STYLE_INSET: + fprintf(stream, "border-bottom-style: inset "); + break; + case CSS_BORDER_STYLE_OUTSET: + fprintf(stream, "border-bottom-style: outset "); + break; + default: + break; + } + + /* border-left-style */ + val = css_computed_border_left_style(style); + switch (val) { + case CSS_BORDER_STYLE_NONE: + fprintf(stream, "border-left-style: none "); + break; + case CSS_BORDER_STYLE_HIDDEN: + fprintf(stream, "border-left-style: hidden "); + break; + case CSS_BORDER_STYLE_DOTTED: + fprintf(stream, "border-left-style: dotted "); + break; + case CSS_BORDER_STYLE_DASHED: + fprintf(stream, "border-left-style: dashed "); + break; + case CSS_BORDER_STYLE_SOLID: + fprintf(stream, "border-left-style: solid "); + break; + case CSS_BORDER_STYLE_DOUBLE: + fprintf(stream, "border-left-style: double "); + break; + case CSS_BORDER_STYLE_GROOVE: + fprintf(stream, "border-left-style: groove "); + break; + case CSS_BORDER_STYLE_RIDGE: + fprintf(stream, "border-left-style: ridge "); + break; + case CSS_BORDER_STYLE_INSET: + fprintf(stream, "border-left-style: inset "); + break; + case CSS_BORDER_STYLE_OUTSET: + fprintf(stream, "border-left-style: outset "); + break; + default: + break; + } + + /* border-top-width */ + val = css_computed_border_top_width(style, &len1, &unit1); + switch (val) { + case CSS_BORDER_WIDTH_THIN: + fprintf(stream, "border-top-width: thin "); + break; + case CSS_BORDER_WIDTH_MEDIUM: + fprintf(stream, "border-top-width: medium "); + break; + case CSS_BORDER_WIDTH_THICK: + fprintf(stream, "border-top-width: thick "); + break; + case CSS_BORDER_WIDTH_WIDTH: + fprintf(stream, "border-top-width: "); + dump_css_unit(stream, len1, unit1); + fprintf(stream, " "); + break; + default: + break; + } + + /* border-right-width */ + val = css_computed_border_right_width(style, &len1, &unit1); + switch (val) { + case CSS_BORDER_WIDTH_THIN: + fprintf(stream, "border-right-width: thin "); + break; + case CSS_BORDER_WIDTH_MEDIUM: + fprintf(stream, "border-right-width: medium "); + break; + case CSS_BORDER_WIDTH_THICK: + fprintf(stream, "border-right-width: thick "); + break; + case CSS_BORDER_WIDTH_WIDTH: + fprintf(stream, "border-right-width: "); + dump_css_unit(stream, len1, unit1); + fprintf(stream, " "); + break; + default: + break; + } + + /* border-bottom-width */ + val = css_computed_border_bottom_width(style, &len1, &unit1); + switch (val) { + case CSS_BORDER_WIDTH_THIN: + fprintf(stream, "border-bottom-width: thin "); + break; + case CSS_BORDER_WIDTH_MEDIUM: + fprintf(stream, "border-bottom-width: medium "); + break; + case CSS_BORDER_WIDTH_THICK: + fprintf(stream, "border-bottom-width: thick "); + break; + case CSS_BORDER_WIDTH_WIDTH: + fprintf(stream, "border-bottom-width: "); + dump_css_unit(stream, len1, unit1); + fprintf(stream, " "); + break; + default: + break; + } + + /* border-left-width */ + val = css_computed_border_left_width(style, &len1, &unit1); + switch (val) { + case CSS_BORDER_WIDTH_THIN: + fprintf(stream, "border-left-width: thin "); + break; + case CSS_BORDER_WIDTH_MEDIUM: + fprintf(stream, "border-left-width: medium "); + break; + case CSS_BORDER_WIDTH_THICK: + fprintf(stream, "border-left-width: thick "); + break; + case CSS_BORDER_WIDTH_WIDTH: + fprintf(stream, "border-left-width: "); + dump_css_unit(stream, len1, unit1); + fprintf(stream, " "); + break; + default: + break; + } + + /* bottom */ + val = css_computed_bottom(style, &len1, &unit1); + switch (val) { + case CSS_BOTTOM_AUTO: + fprintf(stream, "bottom: auto "); + break; + case CSS_BOTTOM_SET: + fprintf(stream, "bottom: "); + dump_css_unit(stream, len1, unit1); + fprintf(stream, " "); + break; + default: + break; + } + + /* caption-side */ + val = css_computed_caption_side(style); + switch (val) { + case CSS_CAPTION_SIDE_TOP: + fprintf(stream, "caption_side: top "); + break; + case CSS_CAPTION_SIDE_BOTTOM: + fprintf(stream, "caption_side: bottom "); + break; + default: + break; + } + + /* clear */ + val = css_computed_clear(style); + switch (val) { + case CSS_CLEAR_NONE: + fprintf(stream, "clear: none "); + break; + case CSS_CLEAR_LEFT: + fprintf(stream, "clear: left "); + break; + case CSS_CLEAR_RIGHT: + fprintf(stream, "clear: right "); + break; + case CSS_CLEAR_BOTH: + fprintf(stream, "clear: both "); + break; + default: + break; + } + + /* clip */ + val = css_computed_clip(style, &rect); + switch (val) { + case CSS_CLIP_AUTO: + fprintf(stream, "clip: auto "); + break; + case CSS_CLIP_RECT: + fprintf(stream, "clip: rect( "); + + if (rect.top_auto) + fprintf(stream, "auto"); + else + dump_css_unit(stream, rect.top, rect.tunit); + fprintf(stream, ", "); + + if (rect.right_auto) + fprintf(stream, "auto"); + else + dump_css_unit(stream, rect.right, rect.runit); + fprintf(stream, ", "); + + if (rect.bottom_auto) + fprintf(stream, "auto"); + else + dump_css_unit(stream, rect.bottom, rect.bunit); + fprintf(stream, ", "); + + if (rect.left_auto) + fprintf(stream, "auto"); + else + dump_css_unit(stream, rect.left, rect.lunit); + fprintf(stream, ") "); + break; + default: + break; + } + + /* color */ + val = css_computed_color(style, &color); + if (val == CSS_COLOR_COLOR) { + fprintf(stream, "color: #%08x ", color); + } + + /* content */ + val = css_computed_content(style, &content); + switch (val) { + case CSS_CONTENT_NONE: + fprintf(stream, "content: none "); + break; + case CSS_CONTENT_NORMAL: + fprintf(stream, "content: normal "); + break; + case CSS_CONTENT_SET: + fprintf(stream, "content:"); + + while (content->type != CSS_COMPUTED_CONTENT_NONE) { + fprintf(stream, " "); + + switch (content->type) { + case CSS_COMPUTED_CONTENT_STRING: + fprintf(stream, "\"%.*s\"", + (int) lwc_string_length( + content->data.string), + lwc_string_data( + content->data.string)); + break; + case CSS_COMPUTED_CONTENT_URI: + fprintf(stream, "uri(\"%.*s\")", + (int) lwc_string_length( + content->data.uri), + lwc_string_data( + content->data.uri)); + break; + case CSS_COMPUTED_CONTENT_COUNTER: + fprintf(stream, "counter(%.*s)", + (int) lwc_string_length( + content->data.counter.name), + lwc_string_data( + content->data.counter.name)); + break; + case CSS_COMPUTED_CONTENT_COUNTERS: + fprintf(stream, "counters(%.*s, \"%.*s\")", + (int) lwc_string_length( + content->data.counters.name), + lwc_string_data( + content->data.counters.name), + (int) lwc_string_length( + content->data.counters.sep), + lwc_string_data( + content->data.counters.sep)); + break; + case CSS_COMPUTED_CONTENT_ATTR: + fprintf(stream, "attr(%.*s)", + (int) lwc_string_length( + content->data.attr), + lwc_string_data( + content->data.attr)); + break; + case CSS_COMPUTED_CONTENT_OPEN_QUOTE: + fprintf(stream, "open-quote"); + break; + case CSS_COMPUTED_CONTENT_CLOSE_QUOTE: + fprintf(stream, "close-quote"); + break; + case CSS_COMPUTED_CONTENT_NO_OPEN_QUOTE: + fprintf(stream, "no-open-quote"); + break; + case CSS_COMPUTED_CONTENT_NO_CLOSE_QUOTE: + fprintf(stream, "no-close-quote"); + break; + } + + content++; + } + + fprintf(stream, " "); + break; + default: + break; + } + + /* counter-increment */ + val = css_computed_counter_increment(style, &counter); + if ((val == CSS_COUNTER_INCREMENT_NONE) || (counter == NULL)) { + fprintf(stream, "counter-increment: none "); + } else { + fprintf(stream, "counter-increment:"); + + while (counter->name != NULL) { + fprintf(stream, " %.*s ", + (int) lwc_string_length(counter->name), + lwc_string_data(counter->name)); + + dump_css_fixed(stream, counter->value); + + counter++; + } + + fprintf(stream, " "); + } + + /* counter-reset */ + val = css_computed_counter_reset(style, &counter); + if ((val == CSS_COUNTER_RESET_NONE) || (counter == NULL)) { + fprintf(stream, "counter-reset: none "); + } else { + fprintf(stream, "counter-reset:"); + + while (counter->name != NULL) { + fprintf(stream, " %.*s ", + (int) lwc_string_length(counter->name), + lwc_string_data(counter->name)); + + dump_css_fixed(stream, counter->value); + + counter++; + } + + fprintf(stream, " "); + } + + /* cursor */ + val = css_computed_cursor(style, &string_list); + fprintf(stream, "cursor:"); + + if (string_list != NULL) { + while (*string_list != NULL) { + fprintf(stream, " url\"%.*s\")", + (int) lwc_string_length(*string_list), + lwc_string_data(*string_list)); + + string_list++; + } + } + switch (val) { + case CSS_CURSOR_AUTO: + fprintf(stream, " auto "); + break; + case CSS_CURSOR_CROSSHAIR: + fprintf(stream, " crosshair "); + break; + case CSS_CURSOR_DEFAULT: + fprintf(stream, " default "); + break; + case CSS_CURSOR_POINTER: + fprintf(stream, " pointer "); + break; + case CSS_CURSOR_MOVE: + fprintf(stream, " move "); + break; + case CSS_CURSOR_E_RESIZE: + fprintf(stream, " e-resize "); + break; + case CSS_CURSOR_NE_RESIZE: + fprintf(stream, " ne-resize "); + break; + case CSS_CURSOR_NW_RESIZE: + fprintf(stream, " nw-resize "); + break; + case CSS_CURSOR_N_RESIZE: + fprintf(stream, " n-resize "); + break; + case CSS_CURSOR_SE_RESIZE: + fprintf(stream, " se-resize "); + break; + case CSS_CURSOR_SW_RESIZE: + fprintf(stream, " sw-resize "); + break; + case CSS_CURSOR_S_RESIZE: + fprintf(stream, " s-resize "); + break; + case CSS_CURSOR_W_RESIZE: + fprintf(stream, " w-resize "); + break; + case CSS_CURSOR_TEXT: + fprintf(stream, " text "); + break; + case CSS_CURSOR_WAIT: + fprintf(stream, " wait "); + break; + case CSS_CURSOR_HELP: + fprintf(stream, " help "); + break; + case CSS_CURSOR_PROGRESS: + fprintf(stream, " progress "); + break; + default: + break; + } + + /* direction */ + val = css_computed_direction(style); + switch (val) { + case CSS_DIRECTION_LTR: + fprintf(stream, "direction: ltr "); + break; + case CSS_DIRECTION_RTL: + fprintf(stream, "direction: rtl "); + break; + default: + break; + } + + /* display */ + val = css_computed_display_static(style); + switch (val) { + case CSS_DISPLAY_INLINE: + fprintf(stream, "display: inline "); + break; + case CSS_DISPLAY_BLOCK: + fprintf(stream, "display: block "); + break; + case CSS_DISPLAY_LIST_ITEM: + fprintf(stream, "display: list-item "); + break; + case CSS_DISPLAY_RUN_IN: + fprintf(stream, "display: run-in "); + break; + case CSS_DISPLAY_INLINE_BLOCK: + fprintf(stream, "display: inline-block "); + break; + case CSS_DISPLAY_TABLE: + fprintf(stream, "display: table "); + break; + case CSS_DISPLAY_INLINE_TABLE: + fprintf(stream, "display: inline-table "); + break; + case CSS_DISPLAY_TABLE_ROW_GROUP: + fprintf(stream, "display: table-row-group "); + break; + case CSS_DISPLAY_TABLE_HEADER_GROUP: + fprintf(stream, "display: table-header-group "); + break; + case CSS_DISPLAY_TABLE_FOOTER_GROUP: + fprintf(stream, "display: table-footer-group "); + break; + case CSS_DISPLAY_TABLE_ROW: + fprintf(stream, "display: table-row "); + break; + case CSS_DISPLAY_TABLE_COLUMN_GROUP: + fprintf(stream, "display: table-column-group "); + break; + case CSS_DISPLAY_TABLE_COLUMN: + fprintf(stream, "display: table-column "); + break; + case CSS_DISPLAY_TABLE_CELL: + fprintf(stream, "display: table-cell "); + break; + case CSS_DISPLAY_TABLE_CAPTION: + fprintf(stream, "display: table-caption "); + break; + case CSS_DISPLAY_NONE: + fprintf(stream, "display: none "); + break; + default: + break; + } + + /* empty-cells */ + val = css_computed_empty_cells(style); + switch (val) { + case CSS_EMPTY_CELLS_SHOW: + fprintf(stream, "empty-cells: show "); + break; + case CSS_EMPTY_CELLS_HIDE: + fprintf(stream, "empty-cells: hide "); + break; + default: + break; + } + + /* float */ + val = css_computed_float(style); + switch (val) { + case CSS_FLOAT_LEFT: + fprintf(stream, "float: left "); + break; + case CSS_FLOAT_RIGHT: + fprintf(stream, "float: right "); + break; + case CSS_FLOAT_NONE: + fprintf(stream, "float: none "); + break; + default: + break; + } + + /* font-family */ + val = css_computed_font_family(style, &string_list); + if (val != CSS_FONT_FAMILY_INHERIT) { + fprintf(stream, "font-family:"); + + if (string_list != NULL) { + while (*string_list != NULL) { + fprintf(stream, " \"%.*s\"", + (int) lwc_string_length(*string_list), + lwc_string_data(*string_list)); + + string_list++; + } + } + switch (val) { + case CSS_FONT_FAMILY_SERIF: + fprintf(stream, " serif "); + break; + case CSS_FONT_FAMILY_SANS_SERIF: + fprintf(stream, " sans-serif "); + break; + case CSS_FONT_FAMILY_CURSIVE: + fprintf(stream, " cursive "); + break; + case CSS_FONT_FAMILY_FANTASY: + fprintf(stream, " fantasy "); + break; + case CSS_FONT_FAMILY_MONOSPACE: + fprintf(stream, " monospace "); + break; + } + } + + /* font-size */ + val = css_computed_font_size(style, &len1, &unit1); + switch (val) { + case CSS_FONT_SIZE_XX_SMALL: + fprintf(stream, "font-size: xx-small "); + break; + case CSS_FONT_SIZE_X_SMALL: + fprintf(stream, "font-size: x-small "); + break; + case CSS_FONT_SIZE_SMALL: + fprintf(stream, "font-size: small "); + break; + case CSS_FONT_SIZE_MEDIUM: + fprintf(stream, "font-size: medium "); + break; + case CSS_FONT_SIZE_LARGE: + fprintf(stream, "font-size: large "); + break; + case CSS_FONT_SIZE_X_LARGE: + fprintf(stream, "font-size: x-large "); + break; + case CSS_FONT_SIZE_XX_LARGE: + fprintf(stream, "font-size: xx-large "); + break; + case CSS_FONT_SIZE_LARGER: + fprintf(stream, "font-size: larger "); + break; + case CSS_FONT_SIZE_SMALLER: + fprintf(stream, "font-size: smaller "); + break; + case CSS_FONT_SIZE_DIMENSION: + fprintf(stream, "font-size: "); + + dump_css_unit(stream, len1, unit1); + + fprintf(stream, " "); + break; + default: + break; + } + + /* font-style */ + val = css_computed_font_style(style); + switch (val) { + case CSS_FONT_STYLE_NORMAL: + fprintf(stream, "font-style: normal "); + break; + case CSS_FONT_STYLE_ITALIC: + fprintf(stream, "font-style: italic "); + break; + case CSS_FONT_STYLE_OBLIQUE: + fprintf(stream, "font-style: oblique "); + break; + default: + break; + } + + /* font-variant */ + val = css_computed_font_variant(style); + switch (val) { + case CSS_FONT_VARIANT_NORMAL: + fprintf(stream, "font-variant: normal "); + break; + case CSS_FONT_VARIANT_SMALL_CAPS: + fprintf(stream, "font-variant: small-caps "); + break; + default: + break; + } + + /* font-weight */ + val = css_computed_font_weight(style); + switch (val) { + case CSS_FONT_WEIGHT_NORMAL: + fprintf(stream, "font-weight: normal "); + break; + case CSS_FONT_WEIGHT_BOLD: + fprintf(stream, "font-weight: bold "); + break; + case CSS_FONT_WEIGHT_BOLDER: + fprintf(stream, "font-weight: bolder "); + break; + case CSS_FONT_WEIGHT_LIGHTER: + fprintf(stream, "font-weight: lighter "); + break; + case CSS_FONT_WEIGHT_100: + fprintf(stream, "font-weight: 100 "); + break; + case CSS_FONT_WEIGHT_200: + fprintf(stream, "font-weight: 200 "); + break; + case CSS_FONT_WEIGHT_300: + fprintf(stream, "font-weight: 300 "); + break; + case CSS_FONT_WEIGHT_400: + fprintf(stream, "font-weight: 400 "); + break; + case CSS_FONT_WEIGHT_500: + fprintf(stream, "font-weight: 500 "); + break; + case CSS_FONT_WEIGHT_600: + fprintf(stream, "font-weight: 600 "); + break; + case CSS_FONT_WEIGHT_700: + fprintf(stream, "font-weight: 700 "); + break; + case CSS_FONT_WEIGHT_800: + fprintf(stream, "font-weight: 800 "); + break; + case CSS_FONT_WEIGHT_900: + fprintf(stream, "font-weight: 900 "); + break; + default: + break; + } + + /* height */ + val = css_computed_height(style, &len1, &unit1); + switch (val) { + case CSS_HEIGHT_AUTO: + fprintf(stream, "height: auto "); + break; + case CSS_HEIGHT_SET: + fprintf(stream, "height: "); + + dump_css_unit(stream, len1, unit1); + + fprintf(stream, " "); + break; + default: + break; + } + + /* left */ + val = css_computed_left(style, &len1, &unit1); + switch (val) { + case CSS_LEFT_AUTO: + fprintf(stream, "left: auto "); + break; + case CSS_LEFT_SET: + fprintf(stream, "left: "); + + dump_css_unit(stream, len1, unit1); + + fprintf(stream, " "); + break; + default: + break; + } + + /* letter-spacing */ + val = css_computed_letter_spacing(style, &len1, &unit1); + switch (val) { + case CSS_LETTER_SPACING_NORMAL: + fprintf(stream, "letter-spacing: normal "); + break; + case CSS_LETTER_SPACING_SET: + fprintf(stream, "letter-spacing: "); + + dump_css_unit(stream, len1, unit1); + + fprintf(stream, " "); + break; + default: + break; + } + + /* line-height */ + val = css_computed_line_height(style, &len1, &unit1); + switch (val) { + case CSS_LINE_HEIGHT_NORMAL: + fprintf(stream, "line-height: normal "); + break; + case CSS_LINE_HEIGHT_NUMBER: + fprintf(stream, "line-height: "); + + dump_css_fixed(stream, len1); + + fprintf(stream, " "); + break; + case CSS_LINE_HEIGHT_DIMENSION: + fprintf(stream, "line-height: "); + + dump_css_unit(stream, len1, unit1); + + fprintf(stream, " "); + break; + default: + break; + } + + /* list-style-image */ + val = css_computed_list_style_image(style, &url); + if (url != NULL) { + fprintf(stream, "list-style-image: url('%.*s') ", + (int) lwc_string_length(url), + lwc_string_data(url)); + } else if (val == CSS_LIST_STYLE_IMAGE_NONE) { + fprintf(stream, "list-style-image: none "); + } + + /* list-style-position */ + val = css_computed_list_style_position(style); + switch (val) { + case CSS_LIST_STYLE_POSITION_INSIDE: + fprintf(stream, "list-style-position: inside "); + break; + case CSS_LIST_STYLE_POSITION_OUTSIDE: + fprintf(stream, "list-style-position: outside "); + break; + default: + break; + } + + /* list-style-type */ + val = css_computed_list_style_type(style); + switch (val) { + case CSS_LIST_STYLE_TYPE_DISC: + fprintf(stream, "list-style-type: disc "); + break; + case CSS_LIST_STYLE_TYPE_CIRCLE: + fprintf(stream, "list-style-type: circle "); + break; + case CSS_LIST_STYLE_TYPE_SQUARE: + fprintf(stream, "list-style-type: square "); + break; + case CSS_LIST_STYLE_TYPE_DECIMAL: + fprintf(stream, "list-style-type: decimal "); + break; + case CSS_LIST_STYLE_TYPE_DECIMAL_LEADING_ZERO: + fprintf(stream, "list-style-type: decimal-leading-zero "); + break; + case CSS_LIST_STYLE_TYPE_LOWER_ROMAN: + fprintf(stream, "list-style-type: lower-roman "); + break; + case CSS_LIST_STYLE_TYPE_UPPER_ROMAN: + fprintf(stream, "list-style-type: upper-roman "); + break; + case CSS_LIST_STYLE_TYPE_LOWER_GREEK: + fprintf(stream, "list-style-type: lower-greek "); + break; + case CSS_LIST_STYLE_TYPE_LOWER_LATIN: + fprintf(stream, "list-style-type: lower-latin "); + break; + case CSS_LIST_STYLE_TYPE_UPPER_LATIN: + fprintf(stream, "list-style-type: upper-latin "); + break; + case CSS_LIST_STYLE_TYPE_ARMENIAN: + fprintf(stream, "list-style-type: armenian "); + break; + case CSS_LIST_STYLE_TYPE_GEORGIAN: + fprintf(stream, "list-style-type: georgian "); + break; + case CSS_LIST_STYLE_TYPE_LOWER_ALPHA: + fprintf(stream, "list-style-type: lower-alpha "); + break; + case CSS_LIST_STYLE_TYPE_UPPER_ALPHA: + fprintf(stream, "list-style-type: upper-alpha "); + break; + case CSS_LIST_STYLE_TYPE_NONE: + fprintf(stream, "list-style-type: none "); + break; + default: + break; + } + + /* margin-top */ + val = css_computed_margin_top(style, &len1, &unit1); + switch (val) { + case CSS_MARGIN_AUTO: + fprintf(stream, "margin-top: auto "); + break; + case CSS_MARGIN_SET: + fprintf(stream, "margin-top: "); + + dump_css_unit(stream, len1, unit1); + + fprintf(stream, " "); + break; + default: + break; + } + + /* margin-right */ + val = css_computed_margin_right(style, &len1, &unit1); + switch (val) { + case CSS_MARGIN_AUTO: + fprintf(stream, "margin-right: auto "); + break; + case CSS_MARGIN_SET: + fprintf(stream, "margin-right: "); + + dump_css_unit(stream, len1, unit1); + + fprintf(stream, " "); + break; + default: + break; + } + + /* margin-bottom */ + val = css_computed_margin_bottom(style, &len1, &unit1); + switch (val) { + case CSS_MARGIN_AUTO: + fprintf(stream, "margin-bottom: auto "); + break; + case CSS_MARGIN_SET: + fprintf(stream, "margin-bottom: "); + + dump_css_unit(stream, len1, unit1); + + fprintf(stream, " "); + break; + default: + break; + } + + /* margin-left */ + val = css_computed_margin_left(style, &len1, &unit1); + switch (val) { + case CSS_MARGIN_AUTO: + fprintf(stream, "margin-left: auto "); + break; + case CSS_MARGIN_SET: + fprintf(stream, "margin-left: "); + + dump_css_unit(stream, len1, unit1); + + fprintf(stream, " "); + break; + default: + break; + } + + /* max-height */ + val = css_computed_max_height(style, &len1, &unit1); + switch (val) { + case CSS_MAX_HEIGHT_NONE: + fprintf(stream, "max-height: none "); + break; + case CSS_MAX_HEIGHT_SET: + fprintf(stream, "max-height: "); + + dump_css_unit(stream, len1, unit1); + + fprintf(stream, " "); + break; + default: + break; + } + + /* max-width */ + val = css_computed_max_width(style, &len1, &unit1); + switch (val) { + case CSS_MAX_WIDTH_NONE: + fprintf(stream, "max-width: none "); + break; + case CSS_MAX_WIDTH_SET: + fprintf(stream, "max-width: "); + + dump_css_unit(stream, len1, unit1); + + fprintf(stream, " "); + break; + default: + break; + } + + /* min-height */ + val = css_computed_min_height(style, &len1, &unit1); + switch (val) { + case CSS_MIN_HEIGHT_SET: + fprintf(stream, "min-height: "); + + dump_css_unit(stream, len1, unit1); + + fprintf(stream, " "); + break; + default: + break; + } + + /* min-width */ + val = css_computed_min_width(style, &len1, &unit1); + switch (val) { + case CSS_MIN_WIDTH_SET: + fprintf(stream, "min-width: "); + + dump_css_unit(stream, len1, unit1); + + fprintf(stream, " "); + break; + default: + break; + } + + /* opacity */ + val = css_computed_opacity(style, &len1); + switch (val) { + case CSS_OPACITY_SET: + fprintf(stream, "opacity: "); + + dump_css_fixed(stream, len1); + + fprintf(stream, " "); + break; + default: + break; + } + + /* outline-color */ + val = css_computed_outline_color(style, &color); + switch (val) { + case CSS_OUTLINE_COLOR_INVERT: + fprintf(stream, "outline-color: invert "); + break; + case CSS_OUTLINE_COLOR_COLOR: + fprintf(stream, "outline-color: #%08x ", color); + break; + default: + break; + } + + /* outline-style */ + val = css_computed_outline_style(style); + switch (val) { + case CSS_OUTLINE_STYLE_NONE: + fprintf(stream, "outline-style: none "); + break; + case CSS_OUTLINE_STYLE_DOTTED: + fprintf(stream, "outline-style: dotted "); + break; + case CSS_OUTLINE_STYLE_DASHED: + fprintf(stream, "outline-style: dashed "); + break; + case CSS_OUTLINE_STYLE_SOLID: + fprintf(stream, "outline-style: solid "); + break; + case CSS_OUTLINE_STYLE_DOUBLE: + fprintf(stream, "outline-style: double "); + break; + case CSS_OUTLINE_STYLE_GROOVE: + fprintf(stream, "outline-style: groove "); + break; + case CSS_OUTLINE_STYLE_RIDGE: + fprintf(stream, "outline-style: ridge "); + break; + case CSS_OUTLINE_STYLE_INSET: + fprintf(stream, "outline-style: inset "); + break; + case CSS_OUTLINE_STYLE_OUTSET: + fprintf(stream, "outline-style: outset "); + break; + default: + break; + } + + /* outline-width */ + val = css_computed_outline_width(style, &len1, &unit1); + switch (val) { + case CSS_OUTLINE_WIDTH_THIN: + fprintf(stream, "outline-width: thin "); + break; + case CSS_OUTLINE_WIDTH_MEDIUM: + fprintf(stream, "outline-width: medium "); + break; + case CSS_OUTLINE_WIDTH_THICK: + fprintf(stream, "outline-width: thick "); + break; + case CSS_OUTLINE_WIDTH_WIDTH: + fprintf(stream, "outline-width: "); + + dump_css_unit(stream, len1, unit1); + + fprintf(stream, " "); + break; + default: + break; + } + + /* overflow */ + val = css_computed_overflow_x(style); + switch (val) { + case CSS_OVERFLOW_VISIBLE: + fprintf(stream, "overflow-x: visible "); + break; + case CSS_OVERFLOW_HIDDEN: + fprintf(stream, "overflow-x: hidden "); + break; + case CSS_OVERFLOW_SCROLL: + fprintf(stream, "overflow-x: scroll "); + break; + case CSS_OVERFLOW_AUTO: + fprintf(stream, "overflow-x auto "); + break; + default: + break; + } + + /* overflow */ + val = css_computed_overflow_y(style); + switch (val) { + case CSS_OVERFLOW_VISIBLE: + fprintf(stream, "overflow-y: visible "); + break; + case CSS_OVERFLOW_HIDDEN: + fprintf(stream, "overflow-y: hidden "); + break; + case CSS_OVERFLOW_SCROLL: + fprintf(stream, "overflow-y: scroll "); + break; + case CSS_OVERFLOW_AUTO: + fprintf(stream, "overflow-y: auto "); + break; + default: + break; + } + + /* padding-top */ + val = css_computed_padding_top(style, &len1, &unit1); + switch (val) { + case CSS_PADDING_SET: + fprintf(stream, "padding-top: "); + + dump_css_unit(stream, len1, unit1); + + fprintf(stream, " "); + break; + default: + break; + } + + /* padding-right */ + val = css_computed_padding_right(style, &len1, &unit1); + switch (val) { + case CSS_PADDING_SET: + fprintf(stream, "padding-right: "); + + dump_css_unit(stream, len1, unit1); + + fprintf(stream, " "); + break; + default: + break; + } + + /* padding-bottom */ + val = css_computed_padding_bottom(style, &len1, &unit1); + switch (val) { + case CSS_PADDING_SET: + fprintf(stream, "padding-bottom: "); + + dump_css_unit(stream, len1, unit1); + + fprintf(stream, " "); + break; + default: + break; + } + + /* padding-left */ + val = css_computed_padding_left(style, &len1, &unit1); + switch (val) { + case CSS_PADDING_SET: + fprintf(stream, "padding-left: "); + + dump_css_unit(stream, len1, unit1); + + fprintf(stream, " "); + break; + default: + break; + } + + /* position */ + val = css_computed_position(style); + switch (val) { + case CSS_POSITION_STATIC: + fprintf(stream, "position: static "); + break; + case CSS_POSITION_RELATIVE: + fprintf(stream, "position: relative "); + break; + case CSS_POSITION_ABSOLUTE: + fprintf(stream, "position: absolute "); + break; + case CSS_POSITION_FIXED: + fprintf(stream, "position: fixed "); + break; + default: + break; + } + + /* quotes */ + val = css_computed_quotes(style, &string_list); + if (val == CSS_QUOTES_STRING && string_list != NULL) { + fprintf(stream, "quotes:"); + + while (*string_list != NULL) { + fprintf(stream, " \"%.*s\"", + (int) lwc_string_length(*string_list), + lwc_string_data(*string_list)); + + string_list++; + } + + fprintf(stream, " "); + } else { + switch (val) { + case CSS_QUOTES_NONE: + fprintf(stream, "quotes: none "); + break; + default: + break; + } + } + + /* right */ + val = css_computed_right(style, &len1, &unit1); + switch (val) { + case CSS_RIGHT_AUTO: + fprintf(stream, "right: auto "); + break; + case CSS_RIGHT_SET: + fprintf(stream, "right: "); + + dump_css_unit(stream, len1, unit1); + + fprintf(stream, " "); + break; + default: + break; + } + + /* table-layout */ + val = css_computed_table_layout(style); + switch (val) { + case CSS_TABLE_LAYOUT_AUTO: + fprintf(stream, "table-layout: auto "); + break; + case CSS_TABLE_LAYOUT_FIXED: + fprintf(stream, "table-layout: fixed "); + break; + default: + break; + } + + /* text-align */ + val = css_computed_text_align(style); + switch (val) { + case CSS_TEXT_ALIGN_LEFT: + fprintf(stream, "text-align: left "); + break; + case CSS_TEXT_ALIGN_RIGHT: + fprintf(stream, "text-align: right "); + break; + case CSS_TEXT_ALIGN_CENTER: + fprintf(stream, "text-align: center "); + break; + case CSS_TEXT_ALIGN_JUSTIFY: + fprintf(stream, "text-align: justify "); + break; + case CSS_TEXT_ALIGN_DEFAULT: + fprintf(stream, "text-align: default "); + break; + case CSS_TEXT_ALIGN_LIBCSS_LEFT: + fprintf(stream, "text-align: -libcss-left "); + break; + case CSS_TEXT_ALIGN_LIBCSS_CENTER: + fprintf(stream, "text-align: -libcss-center "); + break; + case CSS_TEXT_ALIGN_LIBCSS_RIGHT: + fprintf(stream, "text-align: -libcss-right "); + break; + default: + break; + } + + /* text-decoration */ + val = css_computed_text_decoration(style); + if (val == CSS_TEXT_DECORATION_NONE) { + fprintf(stream, "text-decoration: none "); + } else { + fprintf(stream, "text-decoration:"); + + if (val & CSS_TEXT_DECORATION_BLINK) { + fprintf(stream, " blink"); + } + if (val & CSS_TEXT_DECORATION_LINE_THROUGH) { + fprintf(stream, " line-through"); + } + if (val & CSS_TEXT_DECORATION_OVERLINE) { + fprintf(stream, " overline"); + } + if (val & CSS_TEXT_DECORATION_UNDERLINE) { + fprintf(stream, " underline"); + } + + fprintf(stream, " "); + } + + /* text-indent */ + val = css_computed_text_indent(style, &len1, &unit1); + switch (val) { + case CSS_TEXT_INDENT_SET: + fprintf(stream, "text-indent: "); + + dump_css_unit(stream, len1, unit1); + + fprintf(stream, " "); + break; + default: + break; + } + + /* text-transform */ + val = css_computed_text_transform(style); + switch (val) { + case CSS_TEXT_TRANSFORM_CAPITALIZE: + fprintf(stream, "text-transform: capitalize "); + break; + case CSS_TEXT_TRANSFORM_UPPERCASE: + fprintf(stream, "text-transform: uppercase "); + break; + case CSS_TEXT_TRANSFORM_LOWERCASE: + fprintf(stream, "text-transform: lowercase "); + break; + case CSS_TEXT_TRANSFORM_NONE: + fprintf(stream, "text-transform: none "); + break; + default: + break; + } + + /* top */ + val = css_computed_top(style, &len1, &unit1); + switch (val) { + case CSS_TOP_AUTO: + fprintf(stream, "top: auto "); + break; + case CSS_TOP_SET: + fprintf(stream, "top: "); + + dump_css_unit(stream, len1, unit1); + + fprintf(stream, " "); + break; + default: + break; + } + + /* unicode-bidi */ + val = css_computed_unicode_bidi(style); + switch (val) { + case CSS_UNICODE_BIDI_NORMAL: + fprintf(stream, "unicode-bidi: normal "); + break; + case CSS_UNICODE_BIDI_EMBED: + fprintf(stream, "unicode-bidi: embed "); + break; + case CSS_UNICODE_BIDI_BIDI_OVERRIDE: + fprintf(stream, "unicode-bidi: bidi-override "); + break; + default: + break; + } + + /* vertical-align */ + val = css_computed_vertical_align(style, &len1, &unit1); + switch (val) { + case CSS_VERTICAL_ALIGN_BASELINE: + fprintf(stream, "vertical-align: baseline "); + break; + case CSS_VERTICAL_ALIGN_SUB: + fprintf(stream, "vertical-align: sub "); + break; + case CSS_VERTICAL_ALIGN_SUPER: + fprintf(stream, "vertical-align: super "); + break; + case CSS_VERTICAL_ALIGN_TOP: + fprintf(stream, "vertical-align: top "); + break; + case CSS_VERTICAL_ALIGN_TEXT_TOP: + fprintf(stream, "vertical-align: text-top "); + break; + case CSS_VERTICAL_ALIGN_MIDDLE: + fprintf(stream, "vertical-align: middle "); + break; + case CSS_VERTICAL_ALIGN_BOTTOM: + fprintf(stream, "vertical-align: bottom "); + break; + case CSS_VERTICAL_ALIGN_TEXT_BOTTOM: + fprintf(stream, "vertical-align: text-bottom "); + break; + case CSS_VERTICAL_ALIGN_SET: + fprintf(stream, "vertical-align: "); + + dump_css_unit(stream, len1, unit1); + + fprintf(stream, " "); + break; + default: + break; + } + + /* visibility */ + val = css_computed_visibility(style); + switch (val) { + case CSS_VISIBILITY_VISIBLE: + fprintf(stream, "visibility: visible "); + break; + case CSS_VISIBILITY_HIDDEN: + fprintf(stream, "visibility: hidden "); + break; + case CSS_VISIBILITY_COLLAPSE: + fprintf(stream, "visibility: collapse "); + break; + default: + break; + } + + /* white-space */ + val = css_computed_white_space(style); + switch (val) { + case CSS_WHITE_SPACE_NORMAL: + fprintf(stream, "white-space: normal "); + break; + case CSS_WHITE_SPACE_PRE: + fprintf(stream, "white-space: pre "); + break; + case CSS_WHITE_SPACE_NOWRAP: + fprintf(stream, "white-space: nowrap "); + break; + case CSS_WHITE_SPACE_PRE_WRAP: + fprintf(stream, "white-space: pre-wrap "); + break; + case CSS_WHITE_SPACE_PRE_LINE: + fprintf(stream, "white-space: pre-line "); + break; + default: + break; + } + + /* width */ + val = css_computed_width(style, &len1, &unit1); + switch (val) { + case CSS_WIDTH_AUTO: + fprintf(stream, "width: auto "); + break; + case CSS_WIDTH_SET: + fprintf(stream, "width: "); + + dump_css_unit(stream, len1, unit1); + + fprintf(stream, " "); + break; + default: + break; + } + + /* word-spacing */ + val = css_computed_word_spacing(style, &len1, &unit1); + switch (val) { + case CSS_WORD_SPACING_NORMAL: + fprintf(stream, "word-spacing: normal "); + break; + case CSS_WORD_SPACING_SET: + fprintf(stream, "word-spacing: "); + + dump_css_unit(stream, len1, unit1); + + fprintf(stream, " "); + break; + default: + break; + } + + /* z-index */ + val = css_computed_z_index(style, &zindex); + switch (val) { + case CSS_Z_INDEX_AUTO: + fprintf(stream, "z-index: auto "); + break; + case CSS_Z_INDEX_SET: + fprintf(stream, "z-index: %d ", zindex); + break; + default: + break; + } + + fprintf(stream, "}"); +} diff --git a/content/handlers/css/dump.h b/content/handlers/css/dump.h new file mode 100644 index 000000000..470e56481 --- /dev/null +++ b/content/handlers/css/dump.h @@ -0,0 +1,30 @@ +/* + * Copyright 2009 John-Mark Bell + * + * 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 . + */ + +#ifndef NETSURF_CSS_DUMP_H_ +#define NETSURF_CSS_DUMP_H_ + +/** + * Dump a computed style \a style to the give file handle \a stream. + * + * \param stream Stream to write to + * \param style Computed style to dump + */ +void nscss_dump_computed_style(FILE *stream, const css_computed_style *style); + +#endif diff --git a/content/handlers/css/hints.c b/content/handlers/css/hints.c new file mode 100644 index 000000000..f394ea836 --- /dev/null +++ b/content/handlers/css/hints.c @@ -0,0 +1,1604 @@ +/* + * Copyright 2009 John-Mark Bell + * + * 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 . + */ + +#include +#include + +#include "utils/nsoption.h" +#include "utils/corestrings.h" +#include "utils/log.h" +#include "utils/nsurl.h" +#include "utils/utils.h" + +#include "hints.h" +#include "select.h" + +#define LOG_STATS +#undef LOG_STATS + +/****************************************************************************** + * Utility functions * + ******************************************************************************/ + +/** + * Determine if a given character is whitespace + * + * \param c Character to consider + * \return true if character is whitespace, false otherwise + */ +static bool isWhitespace(char c) +{ + return c == ' ' || c == '\t' || c == '\f' || c == '\r' || c == '\n'; +} + +/** + * Determine if a given character is a valid hex digit + * + * \param c Character to consider + * \return true if character is a valid hex digit, false otherwise + */ +static bool isHex(char c) +{ + return ('0' <= c && c <= '9') || + ('A' <= (c & ~0x20) && (c & ~0x20) <= 'F'); +} + +/** + * Convert a character representing a hex digit to the corresponding hex value + * + * \param c Character to convert + * \return Hex value represented by character + * + * \note This function assumes an ASCII-compatible character set + */ +static uint8_t charToHex(char c) +{ + /* 0-9 */ + c -= '0'; + + /* A-F */ + if (c > 9) + c -= 'A' - '9' - 1; + + /* a-f */ + if (c > 15) + c -= 'a' - 'A'; + + return c; +} + + +/****************************************************************************** + * Common parsing functions * + ******************************************************************************/ + +/** + * Parse a number string + * + * \param data Data to parse (NUL-terminated) + * \param maybe_negative Negative numbers permitted + * \param real Floating point numbers permitted + * \param value Pointer to location to receive numeric value + * \param consumed Pointer to location to receive number of input + * bytes consumed + * \return true on success, false on invalid input + */ +static bool parse_number(const char *data, bool maybe_negative, bool real, + css_fixed *value, size_t *consumed) +{ + size_t len; + const uint8_t *ptr; + int32_t intpart = 0; + int32_t fracpart = 0; + int32_t pwr = 1; + int sign = 1; + + *consumed = 0; + + len = strlen(data); + ptr = (const uint8_t *) data; + + if (len == 0) + return false; + + /* Skip leading whitespace */ + while (len > 0 && isWhitespace(ptr[0])) { + len--; + ptr++; + } + + if (len == 0) + return false; + + /* Extract sign, if any */ + if (ptr[0] == '+') { + len--; + ptr++; + } else if (ptr[0] == '-' && maybe_negative) { + sign = -1; + len--; + ptr++; + } + + if (len == 0) + return false; + + /* Must have a digit [0,9] */ + if ('0' > ptr[0] || ptr[0] > '9') + return false; + + /* Now extract intpart, assuming base 10 */ + while (len > 0) { + /* Stop on first non-digit */ + if (ptr[0] < '0' || '9' < ptr[0]) + break; + + /* Prevent overflow of 'intpart'; proper clamping below */ + if (intpart < (1 << 22)) { + intpart *= 10; + intpart += ptr[0] - '0'; + } + ptr++; + len--; + } + + /* And fracpart, again, assuming base 10 */ + if (real && len > 1 && ptr[0] == '.' && + ('0' <= ptr[1] && ptr[1] <= '9')) { + ptr++; + len--; + + while (len > 0) { + if (ptr[0] < '0' || '9' < ptr[0]) + break; + + if (pwr < 1000000) { + pwr *= 10; + fracpart *= 10; + fracpart += ptr[0] - '0'; + } + ptr++; + len--; + } + + fracpart = ((1 << 10) * fracpart + pwr/2) / pwr; + if (fracpart >= (1 << 10)) { + intpart++; + fracpart &= (1 << 10) - 1; + } + } + + if (sign > 0) { + /* If the result is larger than we can represent, + * then clamp to the maximum value we can store. */ + if (intpart >= (1 << 21)) { + intpart = (1 << 21) - 1; + fracpart = (1 << 10) - 1; + } + } else { + /* If the negated result is smaller than we can represent + * then clamp to the minimum value we can store. */ + if (intpart >= (1 << 21)) { + intpart = -(1 << 21); + fracpart = 0; + } else { + intpart = -intpart; + if (fracpart) { + fracpart = (1 << 10) - fracpart; + intpart--; + } + } + } + + *value = (intpart << 10) | fracpart; + + *consumed = ptr - (const uint8_t *) data; + + return true; +} + +/** + * Parse a dimension string + * + * \param data Data to parse (NUL-terminated) + * \param strict Whether to enforce strict parsing rules + * \param length Pointer to location to receive dimension's length + * \param unit Pointer to location to receive dimension's unit + * \return true on success, false on invalid input + */ +static bool parse_dimension(const char *data, bool strict, css_fixed *length, + css_unit *unit) +{ + size_t len; + size_t read; + css_fixed value; + + len = strlen(data); + + if (parse_number(data, false, true, &value, &read) == false) + return false; + + if (strict && value < INTTOFIX(1)) + return false; + + *length = value; + + if (len > read && data[read] == '%') + *unit = CSS_UNIT_PCT; + else + *unit = CSS_UNIT_PX; + + return true; +} + +/** + * Mapping of colour name to CSS color + */ +struct colour_map { + const char *name; + css_color color; +}; + +/** + * Name comparator for named colour matching + * + * \param a Name to match + * \param b Colour map entry to consider + * \return 0 on match, + * < 0 if a < b, + * > 0 if b > a. + */ +static int cmp_colour_name(const void *a, const void *b) +{ + const char *aa = a; + const struct colour_map *bb = b; + + return strcasecmp(aa, bb->name); +} + +/** + * Parse a named colour + * + * \param name Name to parse + * \param result Pointer to location to receive css_color + * \return true on success, false on invalid input + */ +static bool parse_named_colour(const char *name, css_color *result) +{ + static const struct colour_map named_colours[] = { + { "aliceblue", 0xfff0f8ff }, + { "antiquewhite", 0xfffaebd7 }, + { "aqua", 0xff00ffff }, + { "aquamarine", 0xff7fffd4 }, + { "azure", 0xfff0ffff }, + { "beige", 0xfff5f5dc }, + { "bisque", 0xffffe4c4 }, + { "black", 0xff000000 }, + { "blanchedalmond", 0xffffebcd }, + { "blue", 0xff0000ff }, + { "blueviolet", 0xff8a2be2 }, + { "brown", 0xffa52a2a }, + { "burlywood", 0xffdeb887 }, + { "cadetblue", 0xff5f9ea0 }, + { "chartreuse", 0xff7fff00 }, + { "chocolate", 0xffd2691e }, + { "coral", 0xffff7f50 }, + { "cornflowerblue", 0xff6495ed }, + { "cornsilk", 0xfffff8dc }, + { "crimson", 0xffdc143c }, + { "cyan", 0xff00ffff }, + { "darkblue", 0xff00008b }, + { "darkcyan", 0xff008b8b }, + { "darkgoldenrod", 0xffb8860b }, + { "darkgray", 0xffa9a9a9 }, + { "darkgreen", 0xff006400 }, + { "darkgrey", 0xffa9a9a9 }, + { "darkkhaki", 0xffbdb76b }, + { "darkmagenta", 0xff8b008b }, + { "darkolivegreen", 0xff556b2f }, + { "darkorange", 0xffff8c00 }, + { "darkorchid", 0xff9932cc }, + { "darkred", 0xff8b0000 }, + { "darksalmon", 0xffe9967a }, + { "darkseagreen", 0xff8fbc8f }, + { "darkslateblue", 0xff483d8b }, + { "darkslategray", 0xff2f4f4f }, + { "darkslategrey", 0xff2f4f4f }, + { "darkturquoise", 0xff00ced1 }, + { "darkviolet", 0xff9400d3 }, + { "deeppink", 0xffff1493 }, + { "deepskyblue", 0xff00bfff }, + { "dimgray", 0xff696969 }, + { "dimgrey", 0xff696969 }, + { "dodgerblue", 0xff1e90ff }, + { "feldspar", 0xffd19275 }, + { "firebrick", 0xffb22222 }, + { "floralwhite", 0xfffffaf0 }, + { "forestgreen", 0xff228b22 }, + { "fuchsia", 0xffff00ff }, + { "gainsboro", 0xffdcdcdc }, + { "ghostwhite", 0xfff8f8ff }, + { "gold", 0xffffd700 }, + { "goldenrod", 0xffdaa520 }, + { "gray", 0xff808080 }, + { "green", 0xff008000 }, + { "greenyellow", 0xffadff2f }, + { "grey", 0xff808080 }, + { "honeydew", 0xfff0fff0 }, + { "hotpink", 0xffff69b4 }, + { "indianred", 0xffcd5c5c }, + { "indigo", 0xff4b0082 }, + { "ivory", 0xfffffff0 }, + { "khaki", 0xfff0e68c }, + { "lavender", 0xffe6e6fa }, + { "lavenderblush", 0xfffff0f5 }, + { "lawngreen", 0xff7cfc00 }, + { "lemonchiffon", 0xfffffacd }, + { "lightblue", 0xffadd8e6 }, + { "lightcoral", 0xfff08080 }, + { "lightcyan", 0xffe0ffff }, + { "lightgoldenrodyellow", 0xfffafad2 }, + { "lightgray", 0xffd3d3d3 }, + { "lightgreen", 0xff90ee90 }, + { "lightgrey", 0xffd3d3d3 }, + { "lightpink", 0xffffb6c1 }, + { "lightsalmon", 0xffffa07a }, + { "lightseagreen", 0xff20b2aa }, + { "lightskyblue", 0xff87cefa }, + { "lightslateblue", 0xff8470ff }, + { "lightslategray", 0xff778899 }, + { "lightslategrey", 0xff778899 }, + { "lightsteelblue", 0xffb0c4de }, + { "lightyellow", 0xffffffe0 }, + { "lime", 0xff00ff00 }, + { "limegreen", 0xff32cd32 }, + { "linen", 0xfffaf0e6 }, + { "magenta", 0xffff00ff }, + { "maroon", 0xff800000 }, + { "mediumaquamarine", 0xff66cdaa }, + { "mediumblue", 0xff0000cd }, + { "mediumorchid", 0xffba55d3 }, + { "mediumpurple", 0xff9370db }, + { "mediumseagreen", 0xff3cb371 }, + { "mediumslateblue", 0xff7b68ee }, + { "mediumspringgreen", 0xff00fa9a }, + { "mediumturquoise", 0xff48d1cc }, + { "mediumvioletred", 0xffc71585 }, + { "midnightblue", 0xff191970 }, + { "mintcream", 0xfff5fffa }, + { "mistyrose", 0xffffe4e1 }, + { "moccasin", 0xffffe4b5 }, + { "navajowhite", 0xffffdead }, + { "navy", 0xff000080 }, + { "oldlace", 0xfffdf5e6 }, + { "olive", 0xff808000 }, + { "olivedrab", 0xff6b8e23 }, + { "orange", 0xffffa500 }, + { "orangered", 0xffff4500 }, + { "orchid", 0xffda70d6 }, + { "palegoldenrod", 0xffeee8aa }, + { "palegreen", 0xff98fb98 }, + { "paleturquoise", 0xffafeeee }, + { "palevioletred", 0xffdb7093 }, + { "papayawhip", 0xffffefd5 }, + { "peachpuff", 0xffffdab9 }, + { "peru", 0xffcd853f }, + { "pink", 0xffffc0cb }, + { "plum", 0xffdda0dd }, + { "powderblue", 0xffb0e0e6 }, + { "purple", 0xff800080 }, + { "red", 0xffff0000 }, + { "rosybrown", 0xffbc8f8f }, + { "royalblue", 0xff4169e1 }, + { "saddlebrown", 0xff8b4513 }, + { "salmon", 0xfffa8072 }, + { "sandybrown", 0xfff4a460 }, + { "seagreen", 0xff2e8b57 }, + { "seashell", 0xfffff5ee }, + { "sienna", 0xffa0522d }, + { "silver", 0xffc0c0c0 }, + { "skyblue", 0xff87ceeb }, + { "slateblue", 0xff6a5acd }, + { "slategray", 0xff708090 }, + { "slategrey", 0xff708090 }, + { "snow", 0xfffffafa }, + { "springgreen", 0xff00ff7f }, + { "steelblue", 0xff4682b4 }, + { "tan", 0xffd2b48c }, + { "teal", 0xff008080 }, + { "thistle", 0xffd8bfd8 }, + { "tomato", 0xffff6347 }, + { "turquoise", 0xff40e0d0 }, + { "violet", 0xffee82ee }, + { "violetred", 0xffd02090 }, + { "wheat", 0xfff5deb3 }, + { "white", 0xffffffff }, + { "whitesmoke", 0xfff5f5f5 }, + { "yellow", 0xffffff00 }, + { "yellowgreen", 0xff9acd32 } + }; + const struct colour_map *entry; + + entry = bsearch(name, named_colours, + sizeof(named_colours) / sizeof(named_colours[0]), + sizeof(named_colours[0]), + cmp_colour_name); + + if (entry != NULL) + *result = entry->color; + + return entry != NULL; +} + +/* exported interface documented in content/handlers/css/hints.h */ +bool nscss_parse_colour(const char *data, css_color *result) +{ + size_t len = strlen(data); + uint8_t r, g, b; + + /* 2 */ + if (len == 0) + return false; + + /* 3 */ + if (len == SLEN("transparent") && strcasecmp(data, "transparent") == 0) + return false; + + /* 4 */ + if (parse_named_colour(data, result)) + return true; + + /** \todo Implement HTML5's utterly insane legacy colour parsing */ + + if (data[0] == '#') { + data++; + len--; + } + + if (len == 3 && isHex(data[0]) && isHex(data[1]) && isHex(data[2])) { + r = charToHex(data[0]); + g = charToHex(data[1]); + b = charToHex(data[2]); + + r |= (r << 4); + g |= (g << 4); + b |= (b << 4); + + *result = (0xff << 24) | (r << 16) | (g << 8) | b; + + return true; + } else if (len == 6 && isHex(data[0]) && isHex(data[1]) && + isHex(data[2]) && isHex(data[3]) && isHex(data[4]) && + isHex(data[5])) { + r = (charToHex(data[0]) << 4) | charToHex(data[1]); + g = (charToHex(data[2]) << 4) | charToHex(data[3]); + b = (charToHex(data[4]) << 4) | charToHex(data[5]); + + *result = (0xff << 24) | (r << 16) | (g << 8) | b; + + return true; + } + + return false; +} + +/** + * Parse a font \@size attribute + * + * \param size Data to parse (NUL-terminated) + * \param val Pointer to location to receive enum value + * \param len Pointer to location to receive length + * \param unit Pointer to location to receive unit + * \return True on success, false on failure + */ +static bool parse_font_size(const char *size, uint8_t *val, + css_fixed *len, css_unit *unit) +{ + static const uint8_t size_map[] = { + CSS_FONT_SIZE_XX_SMALL, + CSS_FONT_SIZE_SMALL, + CSS_FONT_SIZE_MEDIUM, + CSS_FONT_SIZE_LARGE, + CSS_FONT_SIZE_X_LARGE, + CSS_FONT_SIZE_XX_LARGE, + CSS_FONT_SIZE_DIMENSION /* xxx-large (see below) */ + }; + + const char *p = size; + char mode; + int value = 0; + + /* Skip whitespace */ + while (*p != '\0' && isWhitespace(*p)) + p++; + + mode = *p; + + /* Skip +/- */ + if (mode == '+' || mode == '-') + p++; + + /* Need at least one digit */ + if (*p < '0' || *p > '9') { + return false; + } + + /* Consume digits, computing value */ + while ('0' <= *p && *p <= '9') { + value = value * 10 + (*p - '0'); + p++; + } + + /* Resolve relative sizes */ + if (mode == '+') + value += 3; + else if (mode == '-') + value = 3 - value; + + /* Clamp to range [1,7] */ + if (value < 1) + value = 1; + else if (value > 7) + value = 7; + + if (value == 7) { + /* Manufacture xxx-large */ + *len = FDIV(FMUL(INTTOFIX(3), INTTOFIX(nsoption_int(font_size))), + F_10); + } else { + /* Len is irrelevant */ + *len = 0; + } + + *unit = CSS_UNIT_PT; + *val = size_map[value - 1]; + + return true; +} + + +/****************************************************************************** + * Hint context management * + ******************************************************************************/ + +#define MAX_HINTS_PER_ELEMENT 32 + +struct css_hint_ctx { + struct css_hint *hints; + uint32_t len; +}; + +struct css_hint_ctx hint_ctx; + +nserror css_hint_init(void) +{ + hint_ctx.hints = malloc(sizeof(struct css_hint) * + MAX_HINTS_PER_ELEMENT); + if (hint_ctx.hints == NULL) { + return NSERROR_NOMEM; + } + + return NSERROR_OK; +} + +void css_hint_fini(void) +{ + hint_ctx.len = 0; + free(hint_ctx.hints); +} + +static void css_hint_clean(void) +{ + hint_ctx.len = 0; +} + +static inline struct css_hint * css_hint_advance(struct css_hint *hint) +{ + hint_ctx.len++; + assert(hint_ctx.len < MAX_HINTS_PER_ELEMENT); + + return ++hint; +} + +static void css_hint_get_hints(struct css_hint **hints, uint32_t *nhints) +{ + *hints = hint_ctx.hints; + *nhints = hint_ctx.len; +} + + +/****************************************************************************** + * Presentational hint handlers * + ******************************************************************************/ + +static void css_hint_table_cell_border_padding( + nscss_select_ctx *ctx, + dom_node *node) +{ + struct css_hint *hint = &hint_ctx.hints[hint_ctx.len]; + css_qname qs; + dom_string *attr = NULL; + dom_node *tablenode = NULL; + dom_exception exc; + + qs.ns = NULL; + qs.name = lwc_string_ref(corestring_lwc_table); + if (named_ancestor_node(ctx, node, &qs, + (void *)&tablenode) != CSS_OK) { + /* Didn't find, or had error */ + lwc_string_unref(qs.name); + return; + } + lwc_string_unref(qs.name); + + if (tablenode == NULL) { + return; + } + /* No need to unref tablenode, named_ancestor_node does not + * return a reffed node to the CSS + */ + + exc = dom_element_get_attribute(tablenode, + corestring_dom_border, &attr); + + if (exc == DOM_NO_ERR && attr != NULL) { + uint32_t hint_prop; + css_hint_length hint_length; + + if (parse_dimension( + dom_string_data(attr), false, + &hint_length.value, + &hint_length.unit) && + INTTOFIX(0) != hint_length.value) { + + for (hint_prop = CSS_PROP_BORDER_TOP_STYLE; + hint_prop <= CSS_PROP_BORDER_LEFT_STYLE; + hint_prop++) { + hint->prop = hint_prop; + hint->status = CSS_BORDER_STYLE_INSET; + hint = css_hint_advance(hint); + } + + for (hint_prop = CSS_PROP_BORDER_TOP_WIDTH; + hint_prop <= CSS_PROP_BORDER_LEFT_WIDTH; + hint_prop++) { + hint->prop = hint_prop; + hint->data.length.value = INTTOFIX(1); + hint->data.length.unit = CSS_UNIT_PX; + hint->status = CSS_BORDER_WIDTH_WIDTH; + hint = css_hint_advance(hint); + } + } + dom_string_unref(attr); + } + + exc = dom_element_get_attribute(tablenode, + corestring_dom_bordercolor, &attr); + + if (exc == DOM_NO_ERR && attr != NULL) { + uint32_t hint_prop; + css_color hint_color; + + if (nscss_parse_colour( + (const char *)dom_string_data(attr), + &hint_color)) { + + for (hint_prop = CSS_PROP_BORDER_TOP_COLOR; + hint_prop <= CSS_PROP_BORDER_LEFT_COLOR; + hint_prop++) { + hint->prop = hint_prop; + hint->data.color = hint_color; + hint->status = CSS_BORDER_COLOR_COLOR; + hint = css_hint_advance(hint); + } + } + dom_string_unref(attr); + } + + exc = dom_element_get_attribute(tablenode, + corestring_dom_cellpadding, &attr); + + if (exc == DOM_NO_ERR && attr != NULL) { + uint32_t hint_prop; + css_hint_length hint_length; + + if (parse_dimension( + dom_string_data(attr), false, + &hint_length.value, + &hint_length.unit)) { + + for (hint_prop = CSS_PROP_PADDING_TOP; + hint_prop <= CSS_PROP_PADDING_LEFT; + hint_prop++) { + hint->prop = hint_prop; + hint->data.length.value = hint_length.value; + hint->data.length.unit = hint_length.unit; + hint->status = CSS_PADDING_SET; + hint = css_hint_advance(hint); + } + } + dom_string_unref(attr); + } +} + +static void css_hint_vertical_align_table_cells( + nscss_select_ctx *ctx, + dom_node *node) +{ + struct css_hint *hint = &hint_ctx.hints[hint_ctx.len]; + dom_string *attr = NULL; + dom_exception err; + + err = dom_element_get_attribute(node, + corestring_dom_valign, &attr); + + if (err == DOM_NO_ERR && attr != NULL) { + if (dom_string_caseless_lwc_isequal(attr, + corestring_lwc_top)) { + hint->prop = CSS_PROP_VERTICAL_ALIGN; + hint->status = CSS_VERTICAL_ALIGN_TOP; + hint = css_hint_advance(hint); + + } else if (dom_string_caseless_lwc_isequal(attr, + corestring_lwc_middle)) { + hint->prop = CSS_PROP_VERTICAL_ALIGN; + hint->status = CSS_VERTICAL_ALIGN_MIDDLE; + hint = css_hint_advance(hint); + + } else if (dom_string_caseless_lwc_isequal(attr, + corestring_lwc_bottom)) { + hint->prop = CSS_PROP_VERTICAL_ALIGN; + hint->status = CSS_VERTICAL_ALIGN_BOTTOM; + hint = css_hint_advance(hint); + + } else if (dom_string_caseless_lwc_isequal(attr, + corestring_lwc_baseline)) { + hint->prop = CSS_PROP_VERTICAL_ALIGN; + hint->status = CSS_VERTICAL_ALIGN_BASELINE; + hint = css_hint_advance(hint); + } + dom_string_unref(attr); + } +} + +static void css_hint_vertical_align_replaced( + nscss_select_ctx *ctx, + dom_node *node) +{ + struct css_hint *hint = &hint_ctx.hints[hint_ctx.len]; + dom_string *attr = NULL; + dom_exception err; + + err = dom_element_get_attribute(node, + corestring_dom_valign, &attr); + + if (err == DOM_NO_ERR && attr != NULL) { + if (dom_string_caseless_lwc_isequal(attr, + corestring_lwc_top)) { + hint->prop = CSS_PROP_VERTICAL_ALIGN; + hint->status = CSS_VERTICAL_ALIGN_TOP; + hint = css_hint_advance(hint); + + } else if (dom_string_caseless_lwc_isequal(attr, + corestring_lwc_bottom) || + dom_string_caseless_lwc_isequal(attr, + corestring_lwc_baseline)) { + hint->prop = CSS_PROP_VERTICAL_ALIGN; + hint->status = CSS_VERTICAL_ALIGN_BASELINE; + hint = css_hint_advance(hint); + + } else if (dom_string_caseless_lwc_isequal(attr, + corestring_lwc_texttop)) { + hint->prop = CSS_PROP_VERTICAL_ALIGN; + hint->status = CSS_VERTICAL_ALIGN_TEXT_TOP; + hint = css_hint_advance(hint); + + } else if (dom_string_caseless_lwc_isequal(attr, + corestring_lwc_absmiddle) || + dom_string_caseless_lwc_isequal(attr, + corestring_lwc_abscenter)) { + hint->prop = CSS_PROP_VERTICAL_ALIGN; + hint->status = CSS_VERTICAL_ALIGN_MIDDLE; + hint = css_hint_advance(hint); + } + dom_string_unref(attr); + } +} + +static void css_hint_text_align_normal( + nscss_select_ctx *ctx, + dom_node *node) +{ + struct css_hint *hint = &hint_ctx.hints[hint_ctx.len]; + dom_string *align = NULL; + dom_exception err; + + err = dom_element_get_attribute(node, + corestring_dom_align, &align); + if (err == DOM_NO_ERR && align != NULL) { + if (dom_string_caseless_lwc_isequal(align, + corestring_lwc_left)) { + hint->prop = CSS_PROP_TEXT_ALIGN; + hint->status = CSS_TEXT_ALIGN_LEFT; + hint = css_hint_advance(hint); + + } else if (dom_string_caseless_lwc_isequal(align, + corestring_lwc_center)) { + hint->prop = CSS_PROP_TEXT_ALIGN; + hint->status = CSS_TEXT_ALIGN_CENTER; + hint = css_hint_advance(hint); + + } else if (dom_string_caseless_lwc_isequal(align, + corestring_lwc_right)) { + hint->prop = CSS_PROP_TEXT_ALIGN; + hint->status = CSS_TEXT_ALIGN_RIGHT; + hint = css_hint_advance(hint); + + } else if (dom_string_caseless_lwc_isequal(align, + corestring_lwc_justify)) { + hint->prop = CSS_PROP_TEXT_ALIGN; + hint->status = CSS_TEXT_ALIGN_JUSTIFY; + hint = css_hint_advance(hint); + } + dom_string_unref(align); + } +} + +static void css_hint_text_align_center( + nscss_select_ctx *ctx, + dom_node *node) +{ + struct css_hint *hint = &hint_ctx.hints[hint_ctx.len]; + + hint->prop = CSS_PROP_TEXT_ALIGN; + hint->status = CSS_TEXT_ALIGN_LIBCSS_CENTER; + hint = css_hint_advance(hint); +} + +static void css_hint_margin_left_right_align_center( + nscss_select_ctx *ctx, + dom_node *node) +{ + struct css_hint *hint = &hint_ctx.hints[hint_ctx.len]; + dom_string *attr; + dom_exception exc; + + exc = dom_element_get_attribute(node, + corestring_dom_align, &attr); + + if (exc == DOM_NO_ERR && attr != NULL) { + if (dom_string_caseless_lwc_isequal(attr, + corestring_lwc_center) || + dom_string_caseless_lwc_isequal(attr, + corestring_lwc_abscenter) || + dom_string_caseless_lwc_isequal(attr, + corestring_lwc_middle) || + dom_string_caseless_lwc_isequal(attr, + corestring_lwc_absmiddle)) { + hint->prop = CSS_PROP_MARGIN_LEFT; + hint->status = CSS_MARGIN_AUTO; + hint = css_hint_advance(hint); + + hint->prop = CSS_PROP_MARGIN_RIGHT; + hint->status = CSS_MARGIN_AUTO; + hint = css_hint_advance(hint); + } + dom_string_unref(attr); + } +} + +static void css_hint_text_align_special( + nscss_select_ctx *ctx, + dom_node *node) +{ + struct css_hint *hint = &hint_ctx.hints[hint_ctx.len]; + dom_string *align = NULL; + dom_exception err; + + err = dom_element_get_attribute(node, + corestring_dom_align, &align); + + if (err == DOM_NO_ERR && align != NULL) { + if (dom_string_caseless_lwc_isequal(align, + corestring_lwc_center)) { + hint->prop = CSS_PROP_TEXT_ALIGN; + hint->status = CSS_TEXT_ALIGN_LIBCSS_CENTER; + hint = css_hint_advance(hint); + + } else if (dom_string_caseless_lwc_isequal(align, + corestring_lwc_left)) { + hint->prop = CSS_PROP_TEXT_ALIGN; + hint->status = CSS_TEXT_ALIGN_LIBCSS_LEFT; + hint = css_hint_advance(hint); + + } else if (dom_string_caseless_lwc_isequal(align, + corestring_lwc_right)) { + hint->prop = CSS_PROP_TEXT_ALIGN; + hint->status = CSS_TEXT_ALIGN_LIBCSS_RIGHT; + hint = css_hint_advance(hint); + + } else if (dom_string_caseless_lwc_isequal(align, + corestring_lwc_justify)) { + hint->prop = CSS_PROP_TEXT_ALIGN; + hint->status = CSS_TEXT_ALIGN_JUSTIFY; + hint = css_hint_advance(hint); + } + dom_string_unref(align); + } +} + +static void css_hint_text_align_table_special( + nscss_select_ctx *ctx, + dom_node *node) +{ + struct css_hint *hint = &hint_ctx.hints[hint_ctx.len]; + + hint->prop = CSS_PROP_TEXT_ALIGN; + hint->status = CSS_TEXT_ALIGN_INHERIT_IF_NON_MAGIC; + hint = css_hint_advance(hint); +} + +static void css_hint_margin_hspace_vspace( + nscss_select_ctx *ctx, + dom_node *node) +{ + struct css_hint *hint = &hint_ctx.hints[hint_ctx.len]; + dom_string *attr = NULL; + dom_exception exc; + + exc = dom_element_get_attribute(node, + corestring_dom_vspace, &attr); + + if (exc == DOM_NO_ERR && attr != NULL) { + css_hint_length hint_length; + if (parse_dimension( + dom_string_data(attr), false, + &hint_length.value, + &hint_length.unit)) { + hint->prop = CSS_PROP_MARGIN_TOP; + hint->data.length.value = hint_length.value; + hint->data.length.unit = hint_length.unit; + hint->status = CSS_MARGIN_SET; + hint = css_hint_advance(hint); + + hint->prop = CSS_PROP_MARGIN_BOTTOM; + hint->data.length.value = hint_length.value; + hint->data.length.unit = hint_length.unit; + hint->status = CSS_MARGIN_SET; + hint = css_hint_advance(hint); + } + dom_string_unref(attr); + } + + exc = dom_element_get_attribute(node, + corestring_dom_hspace, &attr); + + if (exc == DOM_NO_ERR && attr != NULL) { + css_hint_length hint_length; + if (parse_dimension( + dom_string_data(attr), false, + &hint_length.value, + &hint_length.unit)) { + hint->prop = CSS_PROP_MARGIN_LEFT; + hint->data.length.value = hint_length.value; + hint->data.length.unit = hint_length.unit; + hint->status = CSS_MARGIN_SET; + hint = css_hint_advance(hint); + + hint->prop = CSS_PROP_MARGIN_RIGHT; + hint->data.length.value = hint_length.value; + hint->data.length.unit = hint_length.unit; + hint->status = CSS_MARGIN_SET; + hint = css_hint_advance(hint); + } + dom_string_unref(attr); + } +} + +static void css_hint_margin_left_right_hr( + nscss_select_ctx *ctx, + dom_node *node) +{ + struct css_hint *hint = &hint_ctx.hints[hint_ctx.len]; + dom_string *attr; + dom_exception exc; + + exc = dom_element_get_attribute(node, + corestring_dom_align, &attr); + + if (exc == DOM_NO_ERR && attr != NULL) { + if (dom_string_caseless_lwc_isequal(attr, + corestring_lwc_left)) { + hint->prop = CSS_PROP_MARGIN_LEFT; + hint->data.length.value = 0; + hint->data.length.unit = CSS_UNIT_PX; + hint->status = CSS_MARGIN_SET; + hint = css_hint_advance(hint); + + hint->prop = CSS_PROP_MARGIN_RIGHT; + hint->status = CSS_MARGIN_AUTO; + hint = css_hint_advance(hint); + + } else if (dom_string_caseless_lwc_isequal(attr, + corestring_lwc_center)) { + hint->prop = CSS_PROP_MARGIN_LEFT; + hint->status = CSS_MARGIN_AUTO; + hint = css_hint_advance(hint); + + hint->prop = CSS_PROP_MARGIN_RIGHT; + hint->status = CSS_MARGIN_AUTO; + hint = css_hint_advance(hint); + + } else if (dom_string_caseless_lwc_isequal(attr, + corestring_lwc_right)) { + hint->prop = CSS_PROP_MARGIN_LEFT; + hint->status = CSS_MARGIN_AUTO; + hint = css_hint_advance(hint); + + hint->prop = CSS_PROP_MARGIN_RIGHT; + hint->data.length.value = 0; + hint->data.length.unit = CSS_UNIT_PX; + hint->status = CSS_MARGIN_SET; + hint = css_hint_advance(hint); + } + dom_string_unref(attr); + } +} + +static void css_hint_table_spacing_border( + nscss_select_ctx *ctx, + dom_node *node) +{ + struct css_hint *hint = &hint_ctx.hints[hint_ctx.len]; + dom_exception exc; + dom_string *attr = NULL; + + exc = dom_element_get_attribute(node, corestring_dom_border, &attr); + + if (exc == DOM_NO_ERR && attr != NULL) { + uint32_t hint_prop; + css_hint_length hint_length; + + for (hint_prop = CSS_PROP_BORDER_TOP_STYLE; + hint_prop <= CSS_PROP_BORDER_LEFT_STYLE; + hint_prop++) { + hint->prop = hint_prop; + hint->status = CSS_BORDER_STYLE_OUTSET; + hint = css_hint_advance(hint); + } + + if (parse_dimension( + dom_string_data(attr), false, + &hint_length.value, + &hint_length.unit)) { + + for (hint_prop = CSS_PROP_BORDER_TOP_WIDTH; + hint_prop <= CSS_PROP_BORDER_LEFT_WIDTH; + hint_prop++) { + hint->prop = hint_prop; + hint->data.length.value = hint_length.value; + hint->data.length.unit = hint_length.unit; + hint->status = CSS_BORDER_WIDTH_WIDTH; + hint = css_hint_advance(hint); + } + } + dom_string_unref(attr); + } + + exc = dom_element_get_attribute(node, + corestring_dom_bordercolor, &attr); + + if (exc == DOM_NO_ERR && attr != NULL) { + uint32_t hint_prop; + css_color hint_color; + + if (nscss_parse_colour( + (const char *)dom_string_data(attr), + &hint_color)) { + + for (hint_prop = CSS_PROP_BORDER_TOP_COLOR; + hint_prop <= CSS_PROP_BORDER_LEFT_COLOR; + hint_prop++) { + hint->prop = hint_prop; + hint->data.color = hint_color; + hint->status = CSS_BORDER_COLOR_COLOR; + hint = css_hint_advance(hint); + } + } + dom_string_unref(attr); + } + + exc = dom_element_get_attribute(node, + corestring_dom_cellspacing, &attr); + + if (exc == DOM_NO_ERR && attr != NULL) { + if (parse_dimension( + (const char *)dom_string_data(attr), false, + &hint->data.position.h.value, + &hint->data.position.h.unit)) { + hint->prop = CSS_PROP_BORDER_SPACING; + hint->data.position.v = hint->data.position.h; + hint->status = CSS_BORDER_SPACING_SET; + hint = css_hint_advance(hint); + } + dom_string_unref(attr); + } +} + +static void css_hint_height( + nscss_select_ctx *ctx, + dom_node *node) +{ + struct css_hint *hint = &hint_ctx.hints[hint_ctx.len]; + dom_string *attr = NULL; + dom_exception err; + + err = dom_element_get_attribute(node, + corestring_dom_height, &attr); + + if (err == DOM_NO_ERR && attr != NULL) { + if (parse_dimension( + (const char *)dom_string_data(attr), false, + &hint->data.length.value, + &hint->data.length.unit)) { + hint->prop = CSS_PROP_HEIGHT; + hint->status = CSS_HEIGHT_SET; + hint = css_hint_advance(hint); + } + dom_string_unref(attr); + } +} + +static void css_hint_width( + nscss_select_ctx *ctx, + dom_node *node) +{ + struct css_hint *hint = &hint_ctx.hints[hint_ctx.len]; + dom_string *attr = NULL; + dom_exception err; + + err = dom_element_get_attribute(node, + corestring_dom_width, &attr); + + if (err == DOM_NO_ERR && attr != NULL) { + if (parse_dimension( + (const char *)dom_string_data(attr), false, + &hint->data.length.value, + &hint->data.length.unit)) { + hint->prop = CSS_PROP_WIDTH; + hint->status = CSS_WIDTH_SET; + hint = css_hint_advance(hint); + } + dom_string_unref(attr); + } +} + +static void css_hint_height_width_textarea( + nscss_select_ctx *ctx, + dom_node *node) +{ + struct css_hint *hint = &hint_ctx.hints[hint_ctx.len]; + dom_string *attr = NULL; + dom_exception err; + + err = dom_element_get_attribute(node, + corestring_dom_rows, &attr); + + if (err == DOM_NO_ERR && attr != NULL) { + if (parse_dimension( + (const char *)dom_string_data(attr), false, + &hint->data.length.value, + &hint->data.length.unit)) { + hint->prop = CSS_PROP_HEIGHT; + hint->data.length.unit = CSS_UNIT_EM; + hint->status = CSS_HEIGHT_SET; + hint = css_hint_advance(hint); + } + dom_string_unref(attr); + } + + err = dom_element_get_attribute(node, + corestring_dom_cols, &attr); + + if (err == DOM_NO_ERR && attr != NULL) { + if (parse_dimension( + (const char *)dom_string_data(attr), false, + &hint->data.length.value, + &hint->data.length.unit)) { + hint->prop = CSS_PROP_WIDTH; + hint->data.length.unit = CSS_UNIT_EX; + hint->status = CSS_WIDTH_SET; + hint = css_hint_advance(hint); + } + dom_string_unref(attr); + } +} + +static void css_hint_width_input( + nscss_select_ctx *ctx, + dom_node *node) +{ + struct css_hint *hint = &(hint_ctx.hints[hint_ctx.len]); + dom_string *attr = NULL; + dom_exception err; + + err = dom_element_get_attribute(node, + corestring_dom_size, &attr); + + if (err == DOM_NO_ERR && attr != NULL) { + if (parse_dimension( + (const char *)dom_string_data(attr), false, + &hint->data.length.value, + &hint->data.length.unit)) { + dom_string *attr2 = NULL; + + err = dom_element_get_attribute(node, + corestring_dom_type, &attr2); + if (err == DOM_NO_ERR) { + + hint->prop = CSS_PROP_WIDTH; + hint->status = CSS_WIDTH_SET; + + if (attr2 == NULL || + dom_string_caseless_lwc_isequal( + attr2, + corestring_lwc_text) || + dom_string_caseless_lwc_isequal( + attr2, + corestring_lwc_search) || + dom_string_caseless_lwc_isequal( + attr2, + corestring_lwc_password) || + dom_string_caseless_lwc_isequal( + attr2, + corestring_lwc_file)) { + hint->data.length.unit = CSS_UNIT_EX; + } + if (attr2 != NULL) { + dom_string_unref(attr2); + } + hint = css_hint_advance(hint); + } + } + dom_string_unref(attr); + } +} + +static void css_hint_anchor_color( + nscss_select_ctx *ctx, + dom_node *node) +{ + struct css_hint *hint = &hint_ctx.hints[hint_ctx.len]; + css_error error; + dom_exception err; + dom_string *color; + dom_node *bodynode = NULL; + + /* find body node */ + css_qname qs; + bool is_visited; + + qs.ns = NULL; + qs.name = lwc_string_ref(corestring_lwc_body); + if (named_ancestor_node(ctx, node, &qs, + (void *)&bodynode) != CSS_OK) { + /* Didn't find, or had error */ + lwc_string_unref(qs.name); + return ; + } + lwc_string_unref(qs.name); + + if (bodynode == NULL) { + return; + } + + error = node_is_visited(ctx, node, &is_visited); + if (error != CSS_OK) + return; + + if (is_visited) { + err = dom_element_get_attribute(bodynode, + corestring_dom_vlink, &color); + } else { + err = dom_element_get_attribute(bodynode, + corestring_dom_link, &color); + } + + if (err == DOM_NO_ERR && color != NULL) { + if (nscss_parse_colour( + (const char *)dom_string_data(color), + &hint->data.color)) { + hint->prop = CSS_PROP_COLOR; + hint->status = CSS_COLOR_COLOR; + hint = css_hint_advance(hint); + } + dom_string_unref(color); + } +} + +static void css_hint_body_color( + nscss_select_ctx *ctx, + dom_node *node) +{ + struct css_hint *hint = &hint_ctx.hints[hint_ctx.len]; + dom_exception err; + dom_string *color; + + err = dom_element_get_attribute(node, corestring_dom_text, &color); + + if (err == DOM_NO_ERR && color != NULL) { + if (nscss_parse_colour( + (const char *)dom_string_data(color), + &hint->data.color)) { + hint->prop = CSS_PROP_COLOR; + hint->status = CSS_COLOR_COLOR; + hint = css_hint_advance(hint); + } + dom_string_unref(color); + } +} + +static void css_hint_color( + nscss_select_ctx *ctx, + dom_node *node) +{ + struct css_hint *hint = &hint_ctx.hints[hint_ctx.len]; + dom_exception err; + dom_string *color; + + err = dom_element_get_attribute(node, corestring_dom_color, &color); + + if (err == DOM_NO_ERR && color != NULL) { + if (nscss_parse_colour( + (const char *)dom_string_data(color), + &hint->data.color)) { + hint->prop = CSS_PROP_COLOR; + hint->status = CSS_COLOR_COLOR; + hint = css_hint_advance(hint); + } + dom_string_unref(color); + } +} + +static void css_hint_font_size( + nscss_select_ctx *ctx, + dom_node *node) +{ + struct css_hint *hint = &hint_ctx.hints[hint_ctx.len]; + dom_exception err; + dom_string *size; + + err = dom_element_get_attribute(node, corestring_dom_size, &size); + if (err == DOM_NO_ERR && size != NULL) { + if (parse_font_size( + (const char *)dom_string_data(size), + &hint->status, + &hint->data.length.value, + &hint->data.length.unit)) { + hint->prop = CSS_PROP_FONT_SIZE; + hint = css_hint_advance(hint); + } + dom_string_unref(size); + } +} + +static void css_hint_float( + nscss_select_ctx *ctx, + dom_node *node) +{ + struct css_hint *hint = &hint_ctx.hints[hint_ctx.len]; + dom_exception err; + dom_string *align; + + err = dom_element_get_attribute(node, corestring_dom_align, &align); + if (err == DOM_NO_ERR && align != NULL) { + if (dom_string_caseless_lwc_isequal(align, + corestring_lwc_left)) { + hint->prop = CSS_PROP_FLOAT; + hint->status = CSS_FLOAT_LEFT; + hint = css_hint_advance(hint); + + } else if (dom_string_caseless_lwc_isequal(align, + corestring_lwc_right)) { + hint->prop = CSS_PROP_FLOAT; + hint->status = CSS_FLOAT_RIGHT; + hint = css_hint_advance(hint); + } + dom_string_unref(align); + } +} + +static void css_hint_caption_side( + nscss_select_ctx *ctx, + dom_node *node) +{ + struct css_hint *hint = &hint_ctx.hints[hint_ctx.len]; + dom_exception err; + dom_string *align = NULL; + + err = dom_element_get_attribute(node, corestring_dom_align, &align); + if (err == DOM_NO_ERR && align != NULL) { + if (dom_string_caseless_lwc_isequal(align, + corestring_lwc_bottom)) { + hint->prop = CSS_PROP_CAPTION_SIDE; + hint->status = CSS_CAPTION_SIDE_BOTTOM; + hint = css_hint_advance(hint); + } + dom_string_unref(align); + } +} + +static void css_hint_bg_color( + nscss_select_ctx *ctx, + dom_node *node) +{ + struct css_hint *hint = &hint_ctx.hints[hint_ctx.len]; + dom_exception err; + dom_string *bgcolor; + + err = dom_element_get_attribute(node, + corestring_dom_bgcolor, &bgcolor); + if (err == DOM_NO_ERR && bgcolor != NULL) { + if (nscss_parse_colour( + (const char *)dom_string_data(bgcolor), + &hint->data.color)) { + hint->prop = CSS_PROP_BACKGROUND_COLOR; + hint->status = CSS_BACKGROUND_COLOR_COLOR; + hint = css_hint_advance(hint); + } + dom_string_unref(bgcolor); + } +} + +static void css_hint_bg_image( + nscss_select_ctx *ctx, + dom_node *node) +{ + struct css_hint *hint = &(hint_ctx.hints[hint_ctx.len]); + dom_exception err; + dom_string *attr; + + err = dom_element_get_attribute(node, + corestring_dom_background, &attr); + if (err == DOM_NO_ERR && attr != NULL) { + nsurl *url; + nserror error = nsurl_join(ctx->base_url, + (const char *)dom_string_data(attr), &url); + dom_string_unref(attr); + + if (error == NSERROR_OK) { + lwc_string *iurl; + lwc_error lerror = lwc_intern_string(nsurl_access(url), + nsurl_length(url), &iurl); + nsurl_unref(url); + + if (lerror == lwc_error_ok) { + hint->prop = CSS_PROP_BACKGROUND_IMAGE; + hint->data.string = iurl; + hint->status = CSS_BACKGROUND_IMAGE_IMAGE; + hint = css_hint_advance(hint); + } + } + } +} + + +/* Exported function, documeted in css/hints.h */ +css_error node_presentational_hint(void *pw, void *node, + uint32_t *nhints, css_hint **hints) +{ + dom_exception exc; + dom_html_element_type tag_type; + + css_hint_clean(); + + exc = dom_html_element_get_tag_type(node, &tag_type); + if (exc != DOM_NO_ERR) { + tag_type = DOM_HTML_ELEMENT_TYPE__UNKNOWN; + } + + switch (tag_type) { + case DOM_HTML_ELEMENT_TYPE_TH: + case DOM_HTML_ELEMENT_TYPE_TD: + css_hint_width(pw, node); + css_hint_table_cell_border_padding(pw, node); + /* fallthrough */ + case DOM_HTML_ELEMENT_TYPE_TR: + css_hint_height(pw, node); + /* fallthrough */ + case DOM_HTML_ELEMENT_TYPE_THEAD: + case DOM_HTML_ELEMENT_TYPE_TBODY: + case DOM_HTML_ELEMENT_TYPE_TFOOT: + css_hint_text_align_special(pw, node); + /* fallthrough */ + case DOM_HTML_ELEMENT_TYPE_COL: + css_hint_vertical_align_table_cells(pw, node); + break; + case DOM_HTML_ELEMENT_TYPE_APPLET: + case DOM_HTML_ELEMENT_TYPE_IMG: + css_hint_margin_hspace_vspace(pw, node); + /* fallthrough */ + case DOM_HTML_ELEMENT_TYPE_EMBED: + case DOM_HTML_ELEMENT_TYPE_IFRAME: + case DOM_HTML_ELEMENT_TYPE_OBJECT: + css_hint_height(pw, node); + css_hint_width(pw, node); + css_hint_vertical_align_replaced(pw, node); + css_hint_float(pw, node); + break; + case DOM_HTML_ELEMENT_TYPE_P: + case DOM_HTML_ELEMENT_TYPE_H1: + case DOM_HTML_ELEMENT_TYPE_H2: + case DOM_HTML_ELEMENT_TYPE_H3: + case DOM_HTML_ELEMENT_TYPE_H4: + case DOM_HTML_ELEMENT_TYPE_H5: + case DOM_HTML_ELEMENT_TYPE_H6: + css_hint_text_align_normal(pw, node); + break; + case DOM_HTML_ELEMENT_TYPE_CENTER: + css_hint_text_align_center(pw, node); + break; + case DOM_HTML_ELEMENT_TYPE_CAPTION: + css_hint_caption_side(pw, node); + /* fallthrough */ + case DOM_HTML_ELEMENT_TYPE_DIV: + css_hint_text_align_special(pw, node); + break; + case DOM_HTML_ELEMENT_TYPE_TABLE: + css_hint_text_align_table_special(pw, node); + css_hint_table_spacing_border(pw, node); + css_hint_float(pw, node); + css_hint_margin_left_right_align_center(pw, node); + css_hint_width(pw, node); + break; + case DOM_HTML_ELEMENT_TYPE_HR: + css_hint_margin_left_right_hr(pw, node); + break; + case DOM_HTML_ELEMENT_TYPE_TEXTAREA: + css_hint_height_width_textarea(pw, node); + break; + case DOM_HTML_ELEMENT_TYPE_INPUT: + css_hint_width_input(pw, node); + break; + case DOM_HTML_ELEMENT_TYPE_A: + css_hint_anchor_color(pw, node); + break; + case DOM_HTML_ELEMENT_TYPE_FONT: + css_hint_font_size(pw, node); + break; + case DOM_HTML_ELEMENT_TYPE_BODY: + css_hint_body_color(pw, node); + break; + default: + break; + } + + if (tag_type != DOM_HTML_ELEMENT_TYPE__UNKNOWN) { + css_hint_color(pw, node); + css_hint_bg_color(pw, node); + css_hint_bg_image(pw, node); + } + +#ifdef LOG_STATS + LOG("Properties with hints: %i", hint_ctx.len); +#endif + + css_hint_get_hints(hints, nhints); + + return CSS_OK; +} diff --git a/content/handlers/css/hints.h b/content/handlers/css/hints.h new file mode 100644 index 000000000..2c1835970 --- /dev/null +++ b/content/handlers/css/hints.h @@ -0,0 +1,55 @@ +/* + * Copyright 2009 John-Mark Bell + * + * 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 . + */ + +#ifndef NETSURF_CSS_HINTS_H_ +#define NETSURF_CSS_HINTS_H_ + +#include + +#include + +nserror css_hint_init(void); +void css_hint_fini(void); + +/** + * Callback to retrieve presentational hints for a node + * + * \param[in] pw HTML document + * \param[in] node DOM node + * \param[out] nhints number of hints retrived + * \param[out] hints retrived hints + * \return CSS_OK on success, + * CSS_PROPERTY_NOT_SET if there is no hint for the requested property, + * CSS_NOMEM on memory exhaustion. + */ +css_error node_presentational_hint( + void *pw, + void *node, + uint32_t *nhints, + css_hint **hints); + +/** + * Parser for colours specified in attribute values. + * + * \param data Data to parse (NUL-terminated) + * \param result Pointer to location to receive resulting css_color + * \return true on success, false on invalid input + */ +bool nscss_parse_colour(const char *data, css_color *result); + +#endif diff --git a/content/handlers/css/internal.c b/content/handlers/css/internal.c new file mode 100644 index 000000000..d66b87a54 --- /dev/null +++ b/content/handlers/css/internal.c @@ -0,0 +1,63 @@ +/* + * Copyright 2009 John-Mark Bell + * + * 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 . + */ + +#include +#include + +#include "utils/nsurl.h" + +#include "internal.h" + +/* exported interface documented in content/handlers/css/internal.h */ +css_error nscss_resolve_url(void *pw, const char *base, + lwc_string *rel, lwc_string **abs) +{ + lwc_error lerror; + nserror error; + nsurl *nsbase; + nsurl *nsabs; + + /* Create nsurl from base */ + /* TODO: avoid this */ + error = nsurl_create(base, &nsbase); + if (error != NSERROR_OK) { + return error == NSERROR_NOMEM ? CSS_NOMEM : CSS_INVALID; + } + + /* Resolve URI */ + error = nsurl_join(nsbase, lwc_string_data(rel), &nsabs); + if (error != NSERROR_OK) { + nsurl_unref(nsbase); + return error == NSERROR_NOMEM ? CSS_NOMEM : CSS_INVALID; + } + + nsurl_unref(nsbase); + + /* Intern it */ + lerror = lwc_intern_string(nsurl_access(nsabs), + nsurl_length(nsabs), abs); + if (lerror != lwc_error_ok) { + *abs = NULL; + nsurl_unref(nsabs); + return lerror == lwc_error_oom ? CSS_NOMEM : CSS_INVALID; + } + + nsurl_unref(nsabs); + + return CSS_OK; +} diff --git a/content/handlers/css/internal.h b/content/handlers/css/internal.h new file mode 100644 index 000000000..5c539c843 --- /dev/null +++ b/content/handlers/css/internal.h @@ -0,0 +1,35 @@ +/* + * Copyright 2009 John-Mark Bell + * + * 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 . + */ + +#ifndef NETSURF_CSS_INTERNAL_H_ +#define NETSURF_CSS_INTERNAL_H_ + +/** + * URL resolution callback for libcss + * + * \param pw Resolution context + * \param base Base URI + * \param rel Relative URL + * \param abs Pointer to location to receive resolved URL + * \return CSS_OK on success, + * CSS_NOMEM on memory exhaustion, + * CSS_INVALID if resolution failed. + */ +css_error nscss_resolve_url(void *pw, const char *base, lwc_string *rel, lwc_string **abs); + +#endif diff --git a/content/handlers/css/select.c b/content/handlers/css/select.c new file mode 100644 index 000000000..ea324e773 --- /dev/null +++ b/content/handlers/css/select.c @@ -0,0 +1,1854 @@ +/* + * Copyright 2009 John-Mark Bell + * + * 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 . + */ + +#include +#include +#include + +#include "content/urldb.h" +#include "desktop/system_colour.h" +#include "utils/nsoption.h" +#include "utils/corestrings.h" +#include "utils/log.h" + +#include "internal.h" +#include "hints.h" +#include "select.h" + +static css_error node_name(void *pw, void *node, css_qname *qname); +static css_error node_classes(void *pw, void *node, + lwc_string ***classes, uint32_t *n_classes); +static css_error node_id(void *pw, void *node, lwc_string **id); +static css_error named_parent_node(void *pw, void *node, + const css_qname *qname, void **parent); +static css_error named_sibling_node(void *pw, void *node, + const css_qname *qname, void **sibling); +static css_error named_generic_sibling_node(void *pw, void *node, + const css_qname *qname, void **sibling); +static css_error parent_node(void *pw, void *node, void **parent); +static css_error sibling_node(void *pw, void *node, void **sibling); +static css_error node_has_name(void *pw, void *node, + const css_qname *qname, bool *match); +static css_error node_has_class(void *pw, void *node, + lwc_string *name, bool *match); +static css_error node_has_id(void *pw, void *node, + lwc_string *name, bool *match); +static css_error node_has_attribute(void *pw, void *node, + const css_qname *qname, bool *match); +static css_error node_has_attribute_equal(void *pw, void *node, + const css_qname *qname, lwc_string *value, + bool *match); +static css_error node_has_attribute_dashmatch(void *pw, void *node, + const css_qname *qname, lwc_string *value, + bool *match); +static css_error node_has_attribute_includes(void *pw, void *node, + const css_qname *qname, lwc_string *value, + bool *match); +static css_error node_has_attribute_prefix(void *pw, void *node, + const css_qname *qname, lwc_string *value, + bool *match); +static css_error node_has_attribute_suffix(void *pw, void *node, + const css_qname *qname, lwc_string *value, + bool *match); +static css_error node_has_attribute_substring(void *pw, void *node, + const css_qname *qname, lwc_string *value, + bool *match); +static css_error node_is_root(void *pw, void *node, bool *match); +static css_error node_count_siblings(void *pw, void *node, + bool same_name, bool after, int32_t *count); +static css_error node_is_empty(void *pw, void *node, bool *match); +static css_error node_is_link(void *pw, void *node, bool *match); +static css_error node_is_hover(void *pw, void *node, bool *match); +static css_error node_is_active(void *pw, void *node, bool *match); +static css_error node_is_focus(void *pw, void *node, bool *match); +static css_error node_is_enabled(void *pw, void *node, bool *match); +static css_error node_is_disabled(void *pw, void *node, bool *match); +static css_error node_is_checked(void *pw, void *node, bool *match); +static css_error node_is_target(void *pw, void *node, bool *match); +static css_error node_is_lang(void *pw, void *node, + lwc_string *lang, bool *match); +static css_error ua_default_for_property(void *pw, uint32_t property, + css_hint *hint); +static css_error set_libcss_node_data(void *pw, void *node, + void *libcss_node_data); +static css_error get_libcss_node_data(void *pw, void *node, + void **libcss_node_data); + +static css_error nscss_compute_font_size(void *pw, const css_hint *parent, + css_hint *size); + + +/** + * Selection callback table for libcss + */ +static css_select_handler selection_handler = { + CSS_SELECT_HANDLER_VERSION_1, + + node_name, + node_classes, + node_id, + named_ancestor_node, + named_parent_node, + named_sibling_node, + named_generic_sibling_node, + parent_node, + sibling_node, + node_has_name, + node_has_class, + node_has_id, + node_has_attribute, + node_has_attribute_equal, + node_has_attribute_dashmatch, + node_has_attribute_includes, + node_has_attribute_prefix, + node_has_attribute_suffix, + node_has_attribute_substring, + node_is_root, + node_count_siblings, + node_is_empty, + node_is_link, + node_is_visited, + node_is_hover, + node_is_active, + node_is_focus, + node_is_enabled, + node_is_disabled, + node_is_checked, + node_is_target, + node_is_lang, + node_presentational_hint, + ua_default_for_property, + nscss_compute_font_size, + set_libcss_node_data, + get_libcss_node_data +}; + +/** + * Create an inline style + * + * \param data Source data + * \param len Length of data in bytes + * \param charset Charset of data, or NULL if unknown + * \param url Base URL of document containing data + * \param allow_quirks True to permit CSS parsing quirks + * \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) +{ + css_stylesheet_params params; + css_stylesheet *sheet; + css_error error; + + params.params_version = CSS_STYLESHEET_PARAMS_VERSION_1; + params.level = CSS_LEVEL_DEFAULT; + params.charset = charset; + params.url = url; + params.title = NULL; + params.allow_quirks = allow_quirks; + params.inline_style = true; + params.resolve = nscss_resolve_url; + params.resolve_pw = NULL; + params.import = NULL; + params.import_pw = NULL; + params.color = ns_system_colour; + params.color_pw = NULL; + params.font = NULL; + params.font_pw = NULL; + + error = css_stylesheet_create(¶ms, &sheet); + if (error != CSS_OK) { + LOG("Failed creating sheet: %d", error); + return NULL; + } + + error = css_stylesheet_append_data(sheet, data, len); + if (error != CSS_OK && error != CSS_NEEDDATA) { + LOG("failed appending data: %d", error); + css_stylesheet_destroy(sheet); + return NULL; + } + + error = css_stylesheet_data_done(sheet); + if (error != CSS_OK) { + LOG("failed completing parse: %d", error); + css_stylesheet_destroy(sheet); + return NULL; + } + + return sheet; +} + +/* Handler for libcss_node_data, stored as libdom node user data */ +static void nscss_dom_user_data_handler(dom_node_operation operation, + dom_string *key, void *data, struct dom_node *src, + struct dom_node *dst) +{ + css_error error; + + if (dom_string_isequal(corestring_dom___ns_key_libcss_node_data, + key) == false || data == NULL) { + return; + } + + switch (operation) { + case DOM_NODE_CLONED: + error = css_libcss_node_data_handler(&selection_handler, + CSS_NODE_CLONED, + NULL, src, dst, data); + if (error != CSS_OK) + LOG("Failed to clone libcss_node_data."); + break; + + case DOM_NODE_RENAMED: + error = css_libcss_node_data_handler(&selection_handler, + CSS_NODE_MODIFIED, + NULL, src, NULL, data); + if (error != CSS_OK) + LOG("Failed to update libcss_node_data."); + break; + + case DOM_NODE_IMPORTED: + case DOM_NODE_ADOPTED: + case DOM_NODE_DELETED: + error = css_libcss_node_data_handler(&selection_handler, + CSS_NODE_DELETED, + NULL, src, NULL, data); + if (error != CSS_OK) + LOG("Failed to delete libcss_node_data."); + break; + + default: + LOG("User data operation not handled."); + assert(0); + } +} + +/** + * Get style selection results for an element + * + * \param ctx CSS selection context + * \param n Element to select for + * \param media Permitted media types + * \param inline_style Inline style associated with element, or NULL + * \return Pointer to selection results (containing computed styles), + * or NULL on failure + */ +css_select_results *nscss_get_style(nscss_select_ctx *ctx, dom_node *n, + uint64_t media, const css_stylesheet *inline_style) +{ + css_select_results *styles; + int pseudo_element; + css_error error; + + /* Select style for node */ + error = css_select_style(ctx->ctx, n, media, inline_style, + &selection_handler, ctx, &styles); + + if (error != CSS_OK || styles == NULL) { + /* Failed selecting partial style -- bail out */ + return NULL; + } + + /* If there's a parent style, compose with partial to obtain + * complete computed style for element */ + if (ctx->parent_style != NULL) { + /* Complete the computed style, by composing with the parent + * element's style */ + error = css_computed_style_compose(ctx->parent_style, + styles->styles[CSS_PSEUDO_ELEMENT_NONE], + nscss_compute_font_size, NULL, + styles->styles[CSS_PSEUDO_ELEMENT_NONE]); + if (error != CSS_OK) { + css_select_results_destroy(styles); + return NULL; + } + } + + for (pseudo_element = CSS_PSEUDO_ELEMENT_NONE + 1; + pseudo_element < CSS_PSEUDO_ELEMENT_COUNT; + pseudo_element++) { + + if (pseudo_element == CSS_PSEUDO_ELEMENT_FIRST_LETTER || + pseudo_element == CSS_PSEUDO_ELEMENT_FIRST_LINE) + /* TODO: Handle first-line and first-letter pseudo + * element computed style completion */ + continue; + + if (styles->styles[pseudo_element] == NULL) + /* There were no rules concerning this pseudo element */ + continue; + + /* Complete the pseudo element's computed style, by composing + * with the base element's style */ + error = css_computed_style_compose( + styles->styles[CSS_PSEUDO_ELEMENT_NONE], + styles->styles[pseudo_element], + nscss_compute_font_size, NULL, + styles->styles[pseudo_element]); + if (error != CSS_OK) { + /* TODO: perhaps this shouldn't be quite so + * catastrophic? */ + css_select_results_destroy(styles); + return NULL; + } + } + + return styles; +} + +/** + * Get an initial style + * + * \param ctx CSS selection context + * \return Pointer to partial computed style, or NULL on failure + */ +static css_computed_style *nscss_get_initial_style(nscss_select_ctx *ctx) +{ + css_computed_style *style; + css_error error; + + error = css_computed_style_create(&style); + if (error != CSS_OK) + return NULL; + + error = css_computed_style_initialise(style, &selection_handler, ctx); + if (error != CSS_OK) { + css_computed_style_destroy(style); + return NULL; + } + + return style; +} + +/** + * Get a blank style + * + * \param ctx CSS selection context + * \param parent Parent style to cascade inherited properties from + * \return Pointer to blank style, or NULL on failure + */ +css_computed_style *nscss_get_blank_style(nscss_select_ctx *ctx, + const css_computed_style *parent) +{ + css_computed_style *partial; + css_error error; + + partial = nscss_get_initial_style(ctx); + if (partial == NULL) + return NULL; + + error = css_computed_style_compose(parent, partial, + nscss_compute_font_size, NULL, partial); + if (error != CSS_OK) { + css_computed_style_destroy(partial); + return NULL; + } + + return partial; +} + +/** + * Font size computation callback for libcss + * + * \param pw Computation context + * \param parent Parent font size (absolute) + * \param size Font size to compute + * \return CSS_OK on success + * + * \post \a size will be an absolute font size + */ +css_error nscss_compute_font_size(void *pw, const css_hint *parent, + css_hint *size) +{ + /** + * Table of font-size keyword scale factors + * + * These are multiplied by the configured default font size + * to produce an absolute size for the relevant keyword + */ + static const css_fixed factors[] = { + FLTTOFIX(0.5625), /* xx-small */ + FLTTOFIX(0.6250), /* x-small */ + FLTTOFIX(0.8125), /* small */ + FLTTOFIX(1.0000), /* medium */ + FLTTOFIX(1.1250), /* large */ + FLTTOFIX(1.5000), /* x-large */ + FLTTOFIX(2.0000) /* xx-large */ + }; + css_hint_length parent_size; + + /* Grab parent size, defaulting to medium if none */ + if (parent == NULL) { + parent_size.value = FDIV(FMUL(factors[CSS_FONT_SIZE_MEDIUM - 1], + INTTOFIX(nsoption_int(font_size))), + INTTOFIX(10)); + parent_size.unit = CSS_UNIT_PT; + } else { + assert(parent->status == CSS_FONT_SIZE_DIMENSION); + assert(parent->data.length.unit != CSS_UNIT_EM); + assert(parent->data.length.unit != CSS_UNIT_EX); + assert(parent->data.length.unit != CSS_UNIT_PCT); + + parent_size = parent->data.length; + } + + assert(size->status != CSS_FONT_SIZE_INHERIT); + + if (size->status < CSS_FONT_SIZE_LARGER) { + /* Keyword -- simple */ + size->data.length.value = FDIV(FMUL(factors[size->status - 1], + INTTOFIX(nsoption_int(font_size))), F_10); + size->data.length.unit = CSS_UNIT_PT; + } else if (size->status == CSS_FONT_SIZE_LARGER) { + /** \todo Step within table, if appropriate */ + size->data.length.value = + FMUL(parent_size.value, FLTTOFIX(1.2)); + size->data.length.unit = parent_size.unit; + } else if (size->status == CSS_FONT_SIZE_SMALLER) { + /** \todo Step within table, if appropriate */ + size->data.length.value = + FDIV(parent_size.value, FLTTOFIX(1.2)); + size->data.length.unit = parent_size.unit; + } else if (size->data.length.unit == CSS_UNIT_EM || + size->data.length.unit == CSS_UNIT_EX) { + size->data.length.value = + FMUL(size->data.length.value, parent_size.value); + + if (size->data.length.unit == CSS_UNIT_EX) { + /* 1ex = 0.6em in NetSurf */ + size->data.length.value = FMUL(size->data.length.value, + FLTTOFIX(0.6)); + } + + size->data.length.unit = parent_size.unit; + } else if (size->data.length.unit == CSS_UNIT_PCT) { + size->data.length.value = FDIV(FMUL(size->data.length.value, + parent_size.value), INTTOFIX(100)); + size->data.length.unit = parent_size.unit; + } + + size->status = CSS_FONT_SIZE_DIMENSION; + + return CSS_OK; +} + +/****************************************************************************** + * Style selection callbacks * + ******************************************************************************/ + +/** + * Callback to retrieve a node's name. + * + * \param pw HTML document + * \param node DOM node + * \param qname 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, css_qname *qname) +{ + dom_node *n = node; + dom_string *name; + dom_exception err; + + err = dom_node_get_node_name(n, &name); + if (err != DOM_NO_ERR) + return CSS_NOMEM; + + qname->ns = NULL; + + err = dom_string_intern(name, &qname->name); + if (err != DOM_NO_ERR) { + dom_string_unref(name); + return CSS_NOMEM; + } + + dom_string_unref(name); + + return CSS_OK; +} + +/** + * Callback to retrieve a node's classes. + * + * \param pw HTML document + * \param node DOM node + * \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, + * CSS_NOMEM on memory exhaustion. + * + * \note The returned array will be destroyed by libcss. Therefore, it must + * be allocated using the same allocator as used by libcss during style + * selection. + */ +css_error node_classes(void *pw, void *node, + lwc_string ***classes, uint32_t *n_classes) +{ + dom_node *n = node; + dom_exception err; + + *classes = NULL; + *n_classes = 0; + + err = dom_element_get_classes(n, classes, n_classes); + if (err != DOM_NO_ERR) + return CSS_NOMEM; + + return CSS_OK; +} + +/** + * Callback to retrieve a node's ID. + * + * \param pw HTML document + * \param node DOM node + * \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_string **id) +{ + dom_node *n = node; + dom_string *attr; + dom_exception err; + + *id = NULL; + + /** \todo Assumes an HTML DOM */ + err = dom_html_element_get_id(n, &attr); + if (err != DOM_NO_ERR) + return CSS_NOMEM; + + if (attr != NULL) { + err = dom_string_intern(attr, id); + if (err != DOM_NO_ERR) { + dom_string_unref(attr); + return CSS_NOMEM; + } + dom_string_unref(attr); + } + + return CSS_OK; +} + +/** + * Callback to find a named ancestor node. + * + * \param pw HTML document + * \param node DOM node + * \param qname Node name to search for + * \param ancestor Pointer to location to receive ancestor + * \return CSS_OK. + * + * \post \a ancestor will contain the result, or NULL if there is no match + */ +css_error named_ancestor_node(void *pw, void *node, + const css_qname *qname, void **ancestor) +{ + dom_element_named_ancestor_node(node, qname->name, + (struct dom_element **)ancestor); + + return CSS_OK; +} + +/** + * Callback to find a named parent node + * + * \param pw HTML document + * \param node DOM node + * \param qname Node name to search for + * \param parent Pointer to location to receive parent + * \return CSS_OK. + * + * \post \a parent will contain the result, or NULL if there is no match + */ +css_error named_parent_node(void *pw, void *node, + const css_qname *qname, void **parent) +{ + dom_element_named_parent_node(node, qname->name, + (struct dom_element **)parent); + + return CSS_OK; +} + +/** + * Callback to find a named sibling node. + * + * \param pw HTML document + * \param node DOM node + * \param qname Node name to search for + * \param sibling Pointer to location to receive sibling + * \return CSS_OK. + * + * \post \a sibling will contain the result, or NULL if there is no match + */ +css_error named_sibling_node(void *pw, void *node, + const css_qname *qname, void **sibling) +{ + dom_node *n = node; + dom_node *prev; + dom_exception err; + + *sibling = NULL; + + /* Find sibling element */ + err = dom_node_get_previous_sibling(n, &n); + if (err != DOM_NO_ERR) + return CSS_OK; + + while (n != NULL) { + dom_node_type type; + + err = dom_node_get_node_type(n, &type); + if (err != DOM_NO_ERR) { + dom_node_unref(n); + return CSS_OK; + } + + if (type == DOM_ELEMENT_NODE) + break; + + err = dom_node_get_previous_sibling(n, &prev); + if (err != DOM_NO_ERR) { + dom_node_unref(n); + return CSS_OK; + } + + dom_node_unref(n); + n = prev; + } + + if (n != NULL) { + dom_string *name; + + err = dom_node_get_node_name(n, &name); + if (err != DOM_NO_ERR) { + dom_node_unref(n); + return CSS_OK; + } + + dom_node_unref(n); + + if (dom_string_caseless_lwc_isequal(name, qname->name)) { + *sibling = n; + } + + dom_string_unref(name); + } + + return CSS_OK; +} + +/** + * Callback to find a named generic sibling node. + * + * \param pw HTML document + * \param node DOM node + * \param qname Node name to search for + * \param sibling Pointer to location to receive ancestor + * \return CSS_OK. + * + * \post \a sibling will contain the result, or NULL if there is no match + */ +css_error named_generic_sibling_node(void *pw, void *node, + const css_qname *qname, void **sibling) +{ + dom_node *n = node; + dom_node *prev; + dom_exception err; + + *sibling = NULL; + + err = dom_node_get_previous_sibling(n, &n); + if (err != DOM_NO_ERR) + return CSS_OK; + + while (n != NULL) { + dom_node_type type; + dom_string *name; + + err = dom_node_get_node_type(n, &type); + if (err != DOM_NO_ERR) { + dom_node_unref(n); + return CSS_OK; + } + + if (type == DOM_ELEMENT_NODE) { + err = dom_node_get_node_name(n, &name); + if (err != DOM_NO_ERR) { + dom_node_unref(n); + return CSS_OK; + } + + if (dom_string_caseless_lwc_isequal(name, + qname->name)) { + dom_string_unref(name); + dom_node_unref(n); + *sibling = n; + break; + } + dom_string_unref(name); + } + + err = dom_node_get_previous_sibling(n, &prev); + if (err != DOM_NO_ERR) { + dom_node_unref(n); + return CSS_OK; + } + + dom_node_unref(n); + n = prev; + } + + return CSS_OK; +} + +/** + * Callback to retrieve the parent of a node. + * + * \param pw HTML document + * \param node DOM node + * \param parent Pointer to location to receive parent + * \return CSS_OK. + * + * \post \a parent will contain the result, or NULL if there is no match + */ +css_error parent_node(void *pw, void *node, void **parent) +{ + dom_element_parent_node(node, (struct dom_element **)parent); + + return CSS_OK; +} + +/** + * Callback to retrieve the preceding sibling of a node. + * + * \param pw HTML document + * \param node DOM node + * \param sibling Pointer to location to receive sibling + * \return CSS_OK. + * + * \post \a sibling will contain the result, or NULL if there is no match + */ +css_error sibling_node(void *pw, void *node, void **sibling) +{ + dom_node *n = node; + dom_node *prev; + dom_exception err; + + *sibling = NULL; + + /* Find sibling element */ + err = dom_node_get_previous_sibling(n, &n); + if (err != DOM_NO_ERR) + return CSS_OK; + + while (n != NULL) { + dom_node_type type; + + err = dom_node_get_node_type(n, &type); + if (err != DOM_NO_ERR) { + dom_node_unref(n); + return CSS_OK; + } + + if (type == DOM_ELEMENT_NODE) + break; + + err = dom_node_get_previous_sibling(n, &prev); + if (err != DOM_NO_ERR) { + dom_node_unref(n); + return CSS_OK; + } + + dom_node_unref(n); + n = prev; + } + + if (n != NULL) { + /** \todo Sort out reference counting */ + dom_node_unref(n); + + *sibling = n; + } + + return CSS_OK; +} + +/** + * Callback to determine if a node has the given name. + * + * \param pw HTML document + * \param node DOM node + * \param qname Name to match + * \param match Pointer to location to receive result + * \return CSS_OK. + * + * \post \a match will contain true if the node matches and false otherwise. + */ +css_error node_has_name(void *pw, void *node, + const css_qname *qname, bool *match) +{ + nscss_select_ctx *ctx = pw; + dom_node *n = node; + + if (lwc_string_isequal(qname->name, ctx->universal, match) == + lwc_error_ok && *match == false) { + dom_string *name; + dom_exception err; + + err = dom_node_get_node_name(n, &name); + if (err != DOM_NO_ERR) + return CSS_OK; + + /* Element names are case insensitive in HTML */ + *match = dom_string_caseless_lwc_isequal(name, qname->name); + + dom_string_unref(name); + } + + return CSS_OK; +} + +/** + * Callback to determine if a node has the given class. + * + * \param pw HTML document + * \param node DOM node + * \param name Name to match + * \param match Pointer to location to receive result + * \return CSS_OK. + * + * \post \a match will contain true if the node matches and false otherwise. + */ +css_error node_has_class(void *pw, void *node, + lwc_string *name, bool *match) +{ + dom_node *n = node; + dom_exception err; + + /** \todo: Ensure that libdom performs case-insensitive + * matching in quirks mode */ + err = dom_element_has_class(n, name, match); + + assert(err == DOM_NO_ERR); + + return CSS_OK; +} + +/** + * Callback to determine if a node has the given id. + * + * \param pw HTML document + * \param node DOM node + * \param name Name to match + * \param match Pointer to location to receive result + * \return CSS_OK. + * + * \post \a match will contain true if the node matches and false otherwise. + */ +css_error node_has_id(void *pw, void *node, + lwc_string *name, bool *match) +{ + dom_node *n = node; + dom_string *attr; + dom_exception err; + + *match = false; + + /** \todo Assumes an HTML DOM */ + err = dom_html_element_get_id(n, &attr); + if (err != DOM_NO_ERR) + return CSS_OK; + + if (attr != NULL) { + *match = dom_string_lwc_isequal(attr, name); + + dom_string_unref(attr); + } + + return CSS_OK; +} + +/** + * Callback to determine if a node has an attribute with the given name. + * + * \param pw HTML document + * \param node DOM node + * \param qname Name to match + * \param match Pointer to location to receive result + * \return CSS_OK on success, + * CSS_NOMEM on memory exhaustion. + * + * \post \a match will contain true if the node matches and false otherwise. + */ +css_error node_has_attribute(void *pw, void *node, + const css_qname *qname, bool *match) +{ + dom_node *n = node; + dom_string *name; + dom_exception err; + + err = dom_string_create_interned( + (const uint8_t *) lwc_string_data(qname->name), + lwc_string_length(qname->name), &name); + if (err != DOM_NO_ERR) + return CSS_NOMEM; + + err = dom_element_has_attribute(n, name, match); + if (err != DOM_NO_ERR) { + dom_string_unref(name); + return CSS_OK; + } + + dom_string_unref(name); + + return CSS_OK; +} + +/** + * Callback to determine if a node has an attribute with given name and value. + * + * \param pw HTML document + * \param node DOM node + * \param qname Name to match + * \param value Value to match + * \param match Pointer to location to receive result + * \return CSS_OK on success, + * CSS_NOMEM on memory exhaustion. + * + * \post \a match will contain true if the node matches and false otherwise. + */ +css_error node_has_attribute_equal(void *pw, void *node, + const css_qname *qname, lwc_string *value, + bool *match) +{ + dom_node *n = node; + dom_string *name; + dom_string *atr_val; + dom_exception err; + + size_t vlen = lwc_string_length(value); + + if (vlen == 0) { + *match = false; + return CSS_OK; + } + + err = dom_string_create_interned( + (const uint8_t *) lwc_string_data(qname->name), + lwc_string_length(qname->name), &name); + if (err != DOM_NO_ERR) + return CSS_NOMEM; + + err = dom_element_get_attribute(n, name, &atr_val); + if ((err != DOM_NO_ERR) || (atr_val == NULL)) { + dom_string_unref(name); + *match = false; + return CSS_OK; + } + + dom_string_unref(name); + + *match = dom_string_caseless_lwc_isequal(atr_val, value); + + dom_string_unref(atr_val); + + return CSS_OK; +} + +/** + * Callback to determine if a node has an attribute with the given name whose + * value dashmatches that given. + * + * \param pw HTML document + * \param node DOM node + * \param qname Name to match + * \param value Value to match + * \param match Pointer to location to receive result + * \return CSS_OK on success, + * CSS_NOMEM on memory exhaustion. + * + * \post \a match will contain true if the node matches and false otherwise. + */ +css_error node_has_attribute_dashmatch(void *pw, void *node, + const css_qname *qname, lwc_string *value, + bool *match) +{ + dom_node *n = node; + dom_string *name; + dom_string *atr_val; + dom_exception err; + + size_t vlen = lwc_string_length(value); + + if (vlen == 0) { + *match = false; + return CSS_OK; + } + + err = dom_string_create_interned( + (const uint8_t *) lwc_string_data(qname->name), + lwc_string_length(qname->name), &name); + if (err != DOM_NO_ERR) + return CSS_NOMEM; + + err = dom_element_get_attribute(n, name, &atr_val); + if ((err != DOM_NO_ERR) || (atr_val == NULL)) { + dom_string_unref(name); + *match = false; + return CSS_OK; + } + + dom_string_unref(name); + + /* check for exact match */ + *match = dom_string_caseless_lwc_isequal(atr_val, value); + + /* check for dashmatch */ + if (*match == false) { + const char *vdata = lwc_string_data(value); + const char *data = (const char *) dom_string_data(atr_val); + size_t len = dom_string_byte_length(atr_val); + + if (len > vlen && data[vlen] == '-' && + strncasecmp(data, vdata, vlen) == 0) { + *match = true; + } + } + + dom_string_unref(atr_val); + + return CSS_OK; +} + +/** + * Callback to determine if a node has an attribute with the given name whose + * value includes that given. + * + * \param pw HTML document + * \param node DOM node + * \param qname Name to match + * \param value Value to match + * \param match Pointer to location to receive result + * \return CSS_OK on success, + * CSS_NOMEM on memory exhaustion. + * + * \post \a match will contain true if the node matches and false otherwise. + */ +css_error node_has_attribute_includes(void *pw, void *node, + const css_qname *qname, lwc_string *value, + bool *match) +{ + dom_node *n = node; + dom_string *name; + dom_string *atr_val; + dom_exception err; + size_t vlen = lwc_string_length(value); + const char *p; + const char *start; + const char *end; + + *match = false; + + if (vlen == 0) { + return CSS_OK; + } + + err = dom_string_create_interned( + (const uint8_t *) lwc_string_data(qname->name), + lwc_string_length(qname->name), &name); + if (err != DOM_NO_ERR) + return CSS_NOMEM; + + err = dom_element_get_attribute(n, name, &atr_val); + if ((err != DOM_NO_ERR) || (atr_val == NULL)) { + dom_string_unref(name); + *match = false; + return CSS_OK; + } + + dom_string_unref(name); + + /* check for match */ + start = (const char *) dom_string_data(atr_val); + end = start + dom_string_byte_length(atr_val); + + for (p = start; p <= end; p++) { + if (*p == ' ' || *p == '\0') { + if ((size_t) (p - start) == vlen && + strncasecmp(start, + lwc_string_data(value), + vlen) == 0) { + *match = true; + break; + } + + start = p + 1; + } + } + + dom_string_unref(atr_val); + + return CSS_OK; +} + +/** + * Callback to determine if a node has an attribute with the given name whose + * value has the prefix given. + * + * \param pw HTML document + * \param node DOM node + * \param qname Name to match + * \param value Value to match + * \param match Pointer to location to receive result + * \return CSS_OK on success, + * CSS_NOMEM on memory exhaustion. + * + * \post \a match will contain true if the node matches and false otherwise. + */ +css_error node_has_attribute_prefix(void *pw, void *node, + const css_qname *qname, lwc_string *value, + bool *match) +{ + dom_node *n = node; + dom_string *name; + dom_string *atr_val; + dom_exception err; + + size_t vlen = lwc_string_length(value); + + if (vlen == 0) { + *match = false; + return CSS_OK; + } + + err = dom_string_create_interned( + (const uint8_t *) lwc_string_data(qname->name), + lwc_string_length(qname->name), &name); + if (err != DOM_NO_ERR) + return CSS_NOMEM; + + err = dom_element_get_attribute(n, name, &atr_val); + if ((err != DOM_NO_ERR) || (atr_val == NULL)) { + dom_string_unref(name); + *match = false; + return CSS_OK; + } + + dom_string_unref(name); + + /* check for exact match */ + *match = dom_string_caseless_lwc_isequal(atr_val, value); + + /* check for prefix match */ + if (*match == false) { + const char *data = (const char *) dom_string_data(atr_val); + size_t len = dom_string_byte_length(atr_val); + + if ((len >= vlen) && + (strncasecmp(data, lwc_string_data(value), vlen) == 0)) { + *match = true; + } + } + + dom_string_unref(atr_val); + + return CSS_OK; +} + +/** + * Callback to determine if a node has an attribute with the given name whose + * value has the suffix given. + * + * \param pw HTML document + * \param node DOM node + * \param qname Name to match + * \param value Value to match + * \param match Pointer to location to receive result + * \return CSS_OK on success, + * CSS_NOMEM on memory exhaustion. + * + * \post \a match will contain true if the node matches and false otherwise. + */ +css_error node_has_attribute_suffix(void *pw, void *node, + const css_qname *qname, lwc_string *value, + bool *match) +{ + dom_node *n = node; + dom_string *name; + dom_string *atr_val; + dom_exception err; + + size_t vlen = lwc_string_length(value); + + if (vlen == 0) { + *match = false; + return CSS_OK; + } + + err = dom_string_create_interned( + (const uint8_t *) lwc_string_data(qname->name), + lwc_string_length(qname->name), &name); + if (err != DOM_NO_ERR) + return CSS_NOMEM; + + err = dom_element_get_attribute(n, name, &atr_val); + if ((err != DOM_NO_ERR) || (atr_val == NULL)) { + dom_string_unref(name); + *match = false; + return CSS_OK; + } + + dom_string_unref(name); + + /* check for exact match */ + *match = dom_string_caseless_lwc_isequal(atr_val, value); + + /* check for prefix match */ + if (*match == false) { + const char *data = (const char *) dom_string_data(atr_val); + size_t len = dom_string_byte_length(atr_val); + + const char *start = (char *) data + len - vlen; + + if ((len >= vlen) && + (strncasecmp(start, lwc_string_data(value), vlen) == 0)) { + *match = true; + } + + + } + + dom_string_unref(atr_val); + + return CSS_OK; +} + +/** + * Callback to determine if a node has an attribute with the given name whose + * value contains the substring given. + * + * \param pw HTML document + * \param node DOM node + * \param qname Name to match + * \param value Value to match + * \param match Pointer to location to receive result + * \return CSS_OK on success, + * CSS_NOMEM on memory exhaustion. + * + * \post \a match will contain true if the node matches and false otherwise. + */ +css_error node_has_attribute_substring(void *pw, void *node, + const css_qname *qname, lwc_string *value, + bool *match) +{ + dom_node *n = node; + dom_string *name; + dom_string *atr_val; + dom_exception err; + + size_t vlen = lwc_string_length(value); + + if (vlen == 0) { + *match = false; + return CSS_OK; + } + + err = dom_string_create_interned( + (const uint8_t *) lwc_string_data(qname->name), + lwc_string_length(qname->name), &name); + if (err != DOM_NO_ERR) + return CSS_NOMEM; + + err = dom_element_get_attribute(n, name, &atr_val); + if ((err != DOM_NO_ERR) || (atr_val == NULL)) { + dom_string_unref(name); + *match = false; + return CSS_OK; + } + + dom_string_unref(name); + + /* check for exact match */ + *match = dom_string_caseless_lwc_isequal(atr_val, value); + + /* check for prefix match */ + if (*match == false) { + const char *vdata = lwc_string_data(value); + const char *start = (const char *) dom_string_data(atr_val); + size_t len = dom_string_byte_length(atr_val); + const char *last_start = start + len - vlen; + + if (len >= vlen) { + while (start <= last_start) { + if (strncasecmp(start, vdata, + vlen) == 0) { + *match = true; + break; + } + + start++; + } + } + } + + dom_string_unref(atr_val); + + return CSS_OK; +} + +/** + * Callback to determine if a node is the root node of the document. + * + * \param pw HTML document + * \param node DOM node + * \param match Pointer to location to receive result + * \return CSS_OK. + * + * \post \a match will contain true if the node matches and false otherwise. + */ +css_error node_is_root(void *pw, void *node, bool *match) +{ + dom_node *n = node; + dom_node *parent; + dom_node_type type; + dom_exception err; + + err = dom_node_get_parent_node(n, &parent); + if (err != DOM_NO_ERR) { + return CSS_NOMEM; + } + + if (parent != NULL) { + err = dom_node_get_node_type(parent, &type); + + dom_node_unref(parent); + + if (err != DOM_NO_ERR) + return CSS_NOMEM; + + if (type != DOM_DOCUMENT_NODE) { + *match = false; + return CSS_OK; + } + } + + *match = true; + + return CSS_OK; +} + +static int +node_count_siblings_check(dom_node *node, + bool check_name, + dom_string *name) +{ + dom_node_type type; + int ret = 0; + dom_exception exc; + + if (node == NULL) + return 0; + + exc = dom_node_get_node_type(node, &type); + if ((exc != DOM_NO_ERR) || (type != DOM_ELEMENT_NODE)) { + return 0; + } + + if (check_name) { + dom_string *node_name = NULL; + exc = dom_node_get_node_name(node, &node_name); + + if ((exc == DOM_NO_ERR) && (node_name != NULL)) { + + if (dom_string_caseless_isequal(name, + node_name)) { + ret = 1; + } + dom_string_unref(node_name); + } + } else { + ret = 1; + } + + return ret; +} + +/** + * Callback to count a node's siblings. + * + * \param pw HTML document + * \param n DOM node + * \param same_name Only count siblings with the same name, or all + * \param after Count anteceding instead of preceding siblings + * \param count Pointer to location to receive result + * \return CSS_OK. + * + * \post \a count will contain the number of siblings + */ +css_error node_count_siblings(void *pw, void *n, bool same_name, + bool after, int32_t *count) +{ + int32_t cnt = 0; + dom_exception exc; + dom_string *node_name = NULL; + + if (same_name) { + dom_node *node = n; + exc = dom_node_get_node_name(node, &node_name); + if ((exc != DOM_NO_ERR) || (node_name == NULL)) { + return CSS_NOMEM; + } + } + + if (after) { + dom_node *node = dom_node_ref(n); + dom_node *next; + + do { + exc = dom_node_get_next_sibling(node, &next); + if ((exc != DOM_NO_ERR)) + break; + + dom_node_unref(node); + node = next; + + cnt += node_count_siblings_check(node, same_name, node_name); + } while (node != NULL); + } else { + dom_node *node = dom_node_ref(n); + dom_node *next; + + do { + exc = dom_node_get_previous_sibling(node, &next); + if ((exc != DOM_NO_ERR)) + break; + + dom_node_unref(node); + node = next; + + cnt += node_count_siblings_check(node, same_name, node_name); + + } while (node != NULL); + } + + if (node_name != NULL) { + dom_string_unref(node_name); + } + + *count = cnt; + return CSS_OK; +} + +/** + * Callback to determine if a node is empty. + * + * \param pw HTML document + * \param node DOM node + * \param match Pointer to location to receive result + * \return CSS_OK. + * + * \post \a match will contain true if the node is empty and false otherwise. + */ +css_error node_is_empty(void *pw, void *node, bool *match) +{ + dom_node *n = node, *next; + dom_exception err; + + *match = true; + + err = dom_node_get_first_child(n, &n); + if (err != DOM_NO_ERR) { + return CSS_BADPARM; + } + + while (n != NULL) { + dom_node_type ntype; + err = dom_node_get_node_type(n, &ntype); + if (err != DOM_NO_ERR) { + dom_node_unref(n); + return CSS_BADPARM; + } + + if (ntype == DOM_ELEMENT_NODE || + ntype == DOM_TEXT_NODE) { + *match = false; + dom_node_unref(n); + break; + } + + err = dom_node_get_next_sibling(n, &next); + if (err != DOM_NO_ERR) { + dom_node_unref(n); + return CSS_BADPARM; + } + dom_node_unref(n); + n = next; + } + + return CSS_OK; +} + +/** + * Callback to determine if a node is a linking element. + * + * \param pw HTML document + * \param n DOM node + * \param match Pointer to location to receive result + * \return CSS_OK. + * + * \post \a match will contain true if the node matches and false otherwise. + */ +css_error node_is_link(void *pw, void *n, bool *match) +{ + dom_node *node = n; + dom_exception exc; + dom_string *node_name = NULL; + + exc = dom_node_get_node_name(node, &node_name); + if ((exc != DOM_NO_ERR) || (node_name == NULL)) { + return CSS_NOMEM; + } + + if (dom_string_caseless_lwc_isequal(node_name, corestring_lwc_a)) { + bool has_href; + exc = dom_element_has_attribute(node, corestring_dom_href, + &has_href); + if ((exc == DOM_NO_ERR) && (has_href)) { + *match = true; + } else { + *match = false; + } + } else { + *match = false; + } + dom_string_unref(node_name); + + return CSS_OK; +} + +/** + * Callback to determine if a node is a linking element whose target has been + * visited. + * + * \param pw HTML document + * \param node DOM node + * \param match Pointer to location to receive result + * \return CSS_OK. + * + * \post \a match will contain true if the node matches and false otherwise. + */ +css_error node_is_visited(void *pw, void *node, bool *match) +{ + nscss_select_ctx *ctx = pw; + nsurl *url; + nserror error; + const struct url_data *data; + + dom_exception exc; + dom_node *n = node; + dom_string *s = NULL; + + *match = false; + + exc = dom_node_get_node_name(n, &s); + if ((exc != DOM_NO_ERR) || (s == NULL)) { + return CSS_NOMEM; + } + + if (!dom_string_caseless_lwc_isequal(s, corestring_lwc_a)) { + /* Can't be visited; not ancher element */ + dom_string_unref(s); + return CSS_OK; + } + + /* Finished with node name string */ + dom_string_unref(s); + s = NULL; + + exc = dom_element_get_attribute(n, corestring_dom_href, &s); + if ((exc != DOM_NO_ERR) || (s == NULL)) { + /* Can't be visited; not got a URL */ + return CSS_OK; + } + + /* Make href absolute */ + /* TODO: this duplicates what we do for box->href + * should we put the absolute URL on the dom node? */ + error = nsurl_join(ctx->base_url, dom_string_data(s), &url); + + /* Finished with href string */ + dom_string_unref(s); + + if (error != NSERROR_OK) { + /* Couldn't make nsurl object */ + return CSS_NOMEM; + } + + data = urldb_get_url_data(url); + + /* Visited if in the db and has + * non-zero visit count */ + if (data != NULL && data->visits > 0) + *match = true; + + nsurl_unref(url); + + return CSS_OK; +} + +/** + * Callback to determine if a node is currently being hovered over. + * + * \param pw HTML document + * \param node DOM node + * \param match Pointer to location to receive result + * \return CSS_OK. + * + * \post \a match will contain true if the node matches and false otherwise. + */ +css_error node_is_hover(void *pw, void *node, bool *match) +{ + /** \todo Support hovering */ + + *match = false; + + return CSS_OK; +} + +/** + * Callback to determine if a node is currently activated. + * + * \param pw HTML document + * \param node DOM node + * \param match Pointer to location to receive result + * \return CSS_OK. + * + * \post \a match will contain true if the node matches and false otherwise. + */ +css_error node_is_active(void *pw, void *node, bool *match) +{ + /** \todo Support active nodes */ + + *match = false; + + return CSS_OK; +} + +/** + * Callback to determine if a node has the input focus. + * + * \param pw HTML document + * \param node DOM node + * \param match Pointer to location to receive result + * \return CSS_OK. + * + * \post \a match will contain true if the node matches and false otherwise. + */ +css_error node_is_focus(void *pw, void *node, bool *match) +{ + /** \todo Support focussed nodes */ + + *match = false; + + return CSS_OK; +} + +/** + * Callback to determine if a node is enabled. + * + * \param pw HTML document + * \param node DOM node + * \param match Pointer to location to receive result + * \return CSS_OK. + * + * \post \a match with contain true if the node is enabled and false otherwise. + */ +css_error node_is_enabled(void *pw, void *node, bool *match) +{ + /** \todo Support enabled nodes */ + + *match = false; + + return CSS_OK; +} + +/** + * Callback to determine if a node is disabled. + * + * \param pw HTML document + * \param node DOM node + * \param match Pointer to location to receive result + * \return CSS_OK. + * + * \post \a match with contain true if the node is disabled and false otherwise. + */ +css_error node_is_disabled(void *pw, void *node, bool *match) +{ + /** \todo Support disabled nodes */ + + *match = false; + + return CSS_OK; +} + +/** + * Callback to determine if a node is checked. + * + * \param pw HTML document + * \param node DOM node + * \param match Pointer to location to receive result + * \return CSS_OK. + * + * \post \a match with contain true if the node is checked and false otherwise. + */ +css_error node_is_checked(void *pw, void *node, bool *match) +{ + /** \todo Support checked nodes */ + + *match = false; + + return CSS_OK; +} + +/** + * Callback to determine if a node is the target of the document URL. + * + * \param pw HTML document + * \param node DOM node + * \param match Pointer to location to receive result + * \return CSS_OK. + * + * \post \a match with contain true if the node matches and false otherwise. + */ +css_error node_is_target(void *pw, void *node, bool *match) +{ + /** \todo Support target */ + + *match = false; + + return CSS_OK; +} + +/** + * Callback to determine if a node has the given language + * + * \param pw HTML document + * \param node DOM node + * \param lang Language specifier to match + * \param match Pointer to location to receive result + * \return CSS_OK. + * + * \post \a match will contain true if the node matches and false otherwise. + */ +css_error node_is_lang(void *pw, void *node, + lwc_string *lang, bool *match) +{ + /** \todo Support languages */ + + *match = false; + + return CSS_OK; +} + +/** + * Callback to retrieve the User-Agent defaults for a CSS property. + * + * \param pw HTML document + * \param property Property to retrieve defaults for + * \param hint Pointer to hint object to populate + * \return CSS_OK on success, + * CSS_INVALID if the property should not have a user-agent default. + */ +css_error ua_default_for_property(void *pw, uint32_t property, css_hint *hint) +{ + if (property == CSS_PROP_COLOR) { + hint->data.color = 0xff000000; + hint->status = CSS_COLOR_COLOR; + } else if (property == CSS_PROP_FONT_FAMILY) { + hint->data.strings = NULL; + switch (nsoption_int(font_default)) { + case PLOT_FONT_FAMILY_SANS_SERIF: + hint->status = CSS_FONT_FAMILY_SANS_SERIF; + break; + case PLOT_FONT_FAMILY_SERIF: + hint->status = CSS_FONT_FAMILY_SERIF; + break; + case PLOT_FONT_FAMILY_MONOSPACE: + hint->status = CSS_FONT_FAMILY_MONOSPACE; + break; + case PLOT_FONT_FAMILY_CURSIVE: + hint->status = CSS_FONT_FAMILY_CURSIVE; + break; + case PLOT_FONT_FAMILY_FANTASY: + hint->status = CSS_FONT_FAMILY_FANTASY; + break; + } + } else if (property == CSS_PROP_QUOTES) { + /** \todo Not exactly useful :) */ + hint->data.strings = NULL; + hint->status = CSS_QUOTES_NONE; + } else if (property == CSS_PROP_VOICE_FAMILY) { + /** \todo Fix this when we have voice-family done */ + hint->data.strings = NULL; + hint->status = 0; + } else { + return CSS_INVALID; + } + + return CSS_OK; +} + +css_error set_libcss_node_data(void *pw, void *node, void *libcss_node_data) +{ + dom_node *n = node; + dom_exception err; + void *old_node_data; + + /* Set this node's node data */ + err = dom_node_set_user_data(n, + corestring_dom___ns_key_libcss_node_data, + libcss_node_data, nscss_dom_user_data_handler, + (void *) &old_node_data); + if (err != DOM_NO_ERR) { + return CSS_NOMEM; + } + + assert(old_node_data == NULL); + + return CSS_OK; +} + +css_error get_libcss_node_data(void *pw, void *node, void **libcss_node_data) +{ + dom_node *n = node; + dom_exception err; + + /* Get this node's node data */ + err = dom_node_get_user_data(n, + corestring_dom___ns_key_libcss_node_data, + libcss_node_data); + if (err != DOM_NO_ERR) { + return CSS_NOMEM; + } + + return CSS_OK; +} diff --git a/content/handlers/css/select.h b/content/handlers/css/select.h new file mode 100644 index 000000000..abfb85814 --- /dev/null +++ b/content/handlers/css/select.h @@ -0,0 +1,58 @@ +/* + * Copyright 2009 John-Mark Bell + * + * 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 . + */ + +#ifndef NETSURF_CSS_SELECT_H_ +#define NETSURF_CSS_SELECT_H_ + +#include + +#include + +#include + +struct content; +struct nsurl; + +/** + * Selection context + */ +typedef struct nscss_select_ctx +{ + css_select_ctx *ctx; + bool quirks; + struct nsurl *base_url; + lwc_string *universal; + const css_computed_style *parent_style; +} nscss_select_ctx; + +css_stylesheet *nscss_create_inline_style(const uint8_t *data, size_t len, + const char *charset, const char *url, bool allow_quirks); + +css_select_results *nscss_get_style(nscss_select_ctx *ctx, dom_node *n, + uint64_t media, const css_stylesheet *inline_style); + +css_computed_style *nscss_get_blank_style(nscss_select_ctx *ctx, + const css_computed_style *parent); + + +css_error named_ancestor_node(void *pw, void *node, + const css_qname *qname, void **ancestor); + +css_error node_is_visited(void *pw, void *node, bool *match); + +#endif diff --git a/content/handlers/css/utils.c b/content/handlers/css/utils.c new file mode 100644 index 000000000..59ad41216 --- /dev/null +++ b/content/handlers/css/utils.c @@ -0,0 +1,127 @@ +/* + * Copyright 2004 James Bursa + * Copyright 2009 John-Mark Bell + * + * 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 . + */ + +#include + +#include "utils/nsoption.h" +#include "utils/log.h" + +#include "utils.h" + +/** Screen DPI in fixed point units: defaults to 90, which RISC OS uses */ +css_fixed nscss_screen_dpi = F_90; + +/* exported interface documented in content/handlers/css/utils.h */ +css_fixed nscss_len2pt(css_fixed length, css_unit unit) +{ + /* Length must not be relative */ + assert(unit != CSS_UNIT_EM && unit != CSS_UNIT_EX); + + switch (unit) { + /* We assume the screen and any other output has the same dpi */ + /* 1in = DPIpx => 1px = (72/DPI)pt */ + case CSS_UNIT_PX: return FDIV(FMUL(length, F_72), nscss_screen_dpi); + /* 1in = 72pt */ + case CSS_UNIT_IN: return FMUL(length, F_72); + /* 1in = 2.54cm => 1cm = (72/2.54)pt */ + case CSS_UNIT_CM: return FMUL(length, + FDIV(F_72, FLTTOFIX(2.54))); + /* 1in = 25.4mm => 1mm = (72/25.4)pt */ + case CSS_UNIT_MM: return FMUL(length, + FDIV(F_72, FLTTOFIX(25.4))); + case CSS_UNIT_PT: return length; + /* 1pc = 12pt */ + case CSS_UNIT_PC: return FMUL(length, INTTOFIX(12)); + default: break; + } + + return 0; +} + + +/* exported interface documented in content/handlers/css/utils.h */ +css_fixed nscss_len2px(css_fixed length, css_unit unit, + const css_computed_style *style) +{ + /* We assume the screen and any other output has the same dpi */ + css_fixed px_per_unit; + + assert(style != NULL || (unit != CSS_UNIT_EM && unit != CSS_UNIT_EX)); + + switch (unit) { + case CSS_UNIT_EM: + case CSS_UNIT_EX: + { + css_fixed font_size = 0; + css_unit font_unit = CSS_UNIT_PT; + + css_computed_font_size(style, &font_size, &font_unit); + + /* Convert to points */ + font_size = nscss_len2pt(font_size, font_unit); + + /* Clamp to configured minimum */ + if (font_size < FDIV(INTTOFIX(nsoption_int(font_min_size)), F_10)) { + font_size = FDIV(INTTOFIX(nsoption_int(font_min_size)), F_10); + } + + /* Convert to pixels (manually, to maximise precision) + * 1in = 72pt => 1pt = (DPI/72)px */ + px_per_unit = FDIV(FMUL(font_size, nscss_screen_dpi), F_72); + + /* Scale ex units: we use a fixed ratio of 1ex = 0.6em */ + if (unit == CSS_UNIT_EX) + px_per_unit = FMUL(px_per_unit, FLTTOFIX(0.6)); + } + break; + case CSS_UNIT_PX: + px_per_unit = F_1; + break; + /* 1in = DPIpx */ + case CSS_UNIT_IN: + px_per_unit = nscss_screen_dpi; + break; + /* 1in = 2.54cm => 1cm = (DPI/2.54)px */ + case CSS_UNIT_CM: + px_per_unit = FDIV(nscss_screen_dpi, FLTTOFIX(2.54)); + break; + /* 1in = 25.4mm => 1mm = (DPI/25.4)px */ + case CSS_UNIT_MM: + px_per_unit = FDIV(nscss_screen_dpi, FLTTOFIX(25.4)); + break; + /* 1in = 72pt => 1pt = (DPI/72)px */ + case CSS_UNIT_PT: + px_per_unit = FDIV(nscss_screen_dpi, F_72); + break; + /* 1pc = 12pt => 1in = 6pc => 1pc = (DPI/6)px */ + case CSS_UNIT_PC: + px_per_unit = FDIV(nscss_screen_dpi, INTTOFIX(6)); + break; + default: + px_per_unit = 0; + break; + } + + /* Ensure we round px_per_unit to the nearest whole number of pixels: + * the use of FIXTOINT() below will truncate. */ + px_per_unit += F_0_5; + + /* Calculate total number of pixels */ + return FMUL(length, TRUNCATEFIX(px_per_unit)); +} diff --git a/content/handlers/css/utils.h b/content/handlers/css/utils.h new file mode 100644 index 000000000..58a5ea6e6 --- /dev/null +++ b/content/handlers/css/utils.h @@ -0,0 +1,49 @@ +/* + * Copyright 2009 John-Mark Bell + * + * 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 . + */ + +#ifndef NETSURF_CSS_UTILS_H_ +#define NETSURF_CSS_UTILS_H_ + +#include + +#include "netsurf/css.h" + +/** DPI of the screen, in fixed point units */ +extern css_fixed nscss_screen_dpi; + +/** + * Convert an absolute CSS length to points. + * + * \param[in] length Absolute CSS length. + * \param[in] unit Unit of the length. + * \return length in points + */ +css_fixed nscss_len2pt(css_fixed length, css_unit unit); + +/** + * Convert a CSS length to pixels. + * + * \param length Length to convert + * \param unit Corresponding unit + * \param style Computed style applying to length. May be NULL if unit is + * neither em nor ex + * \return length in pixels + */ +css_fixed nscss_len2px(css_fixed length, css_unit unit, const css_computed_style *style); + +#endif diff --git a/content/handlers/image/Makefile b/content/handlers/image/Makefile index 5851a1c43..541cd2cf9 100644 --- a/content/handlers/image/Makefile +++ b/content/handlers/image/Makefile @@ -12,4 +12,4 @@ S_IMAGE_$(NETSURF_USE_NSSVG) += svg.c S_IMAGE_$(NETSURF_USE_RSVG) += rsvg.c S_IMAGE_$(NETSURF_USE_VIDEO) += video.c -S_IMAGE := $(addprefix image/,$(S_IMAGE_YES)) +S_IMAGE := $(S_IMAGE_YES) diff --git a/content/handlers/image/svg.c b/content/handlers/image/svg.c index c91b00650..3eff684fd 100644 --- a/content/handlers/image/svg.c +++ b/content/handlers/image/svg.c @@ -23,13 +23,13 @@ #include #include #include +#include #include #include "utils/messages.h" #include "utils/utils.h" #include "content/content_protected.h" -#include "css/css.h" #include "desktop/plotters.h" #include "svg.h" diff --git a/css/Makefile b/css/Makefile deleted file mode 100644 index 127dbaa32..000000000 --- a/css/Makefile +++ /dev/null @@ -1,5 +0,0 @@ -# CSS sources - -S_CSS := css.c dump.c internal.c hints.c select.c utils.c - -S_CSS := $(addprefix css/,$(S_CSS)) diff --git a/css/css.c b/css/css.c deleted file mode 100644 index 66dc6d4ba..000000000 --- a/css/css.c +++ /dev/null @@ -1,847 +0,0 @@ -/* - * Copyright 2009 John-Mark Bell - * - * 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 . - */ - -#include -#include -#include - -#include "content/content_protected.h" -#include "content/fetch.h" -#include "content/hlcache.h" -#include "desktop/system_colour.h" -#include "utils/corestrings.h" -#include "utils/utils.h" -#include "utils/http.h" -#include "utils/log.h" -#include "utils/messages.h" - -#include "css/css.h" -#include "css/hints.h" -#include "css/internal.h" - -/* Define to trace import fetches */ -#undef NSCSS_IMPORT_TRACE - -struct content_css_data; - -/** - * Type of callback called when a CSS object has finished - * - * \param css CSS object that has completed - * \param pw Client-specific data - */ -typedef void (*nscss_done_callback)(struct content_css_data *css, void *pw); - -/** - * CSS content data - */ -struct content_css_data -{ - css_stylesheet *sheet; /**< Stylesheet object */ - char *charset; /**< Character set of stylesheet */ - struct nscss_import *imports; /**< Array of imported sheets */ - uint32_t import_count; /**< Number of sheets imported */ - uint32_t next_to_register; /**< Index of next import to register */ - nscss_done_callback done; /**< Completion callback */ - void *pw; /**< Client data */ -}; - -/** - * CSS content data - */ -typedef struct nscss_content -{ - struct content base; /**< Underlying content object */ - - struct content_css_data data; /**< CSS data */ -} nscss_content; - -/** - * Context for import fetches - */ -typedef struct { - struct content_css_data *css; /**< Object containing import */ - uint32_t index; /**< Index into parent sheet's - * imports array */ -} nscss_import_ctx; - -static bool nscss_process_data(struct content *c, const char *data, - unsigned int size); -static bool nscss_convert(struct content *c); -static void nscss_destroy(struct content *c); -static nserror nscss_clone(const struct content *old, struct content **newc); -static bool nscss_matches_quirks(const struct content *c, bool quirks); -static content_type nscss_content_type(void); - -static nserror nscss_create_css_data(struct content_css_data *c, - const char *url, const char *charset, bool quirks, - nscss_done_callback done, void *pw); -static css_error nscss_process_css_data(struct content_css_data *c, const char *data, - unsigned int size); -static css_error nscss_convert_css_data(struct content_css_data *c); -static void nscss_destroy_css_data(struct content_css_data *c); - -static void nscss_content_done(struct content_css_data *css, void *pw); -static css_error nscss_handle_import(void *pw, css_stylesheet *parent, - lwc_string *url, uint64_t media); -static nserror nscss_import(hlcache_handle *handle, - const hlcache_event *event, void *pw); -static css_error nscss_import_complete(nscss_import_ctx *ctx); - -static css_error nscss_register_imports(struct content_css_data *c); -static css_error nscss_register_import(struct content_css_data *c, - const hlcache_handle *import); - - -static css_stylesheet *blank_import; - - -/** - * Initialise a CSS content - * - * \param handler content handler - * \param imime_type mime-type - * \param params Content-Type parameters - * \param llcache handle to content - * \param fallback_charset The character set to fallback to. - * \param quirks allow quirks - * \param c Content to initialise - * \return NSERROR_OK or error cod eon faliure - */ -static nserror -nscss_create(const content_handler *handler, - lwc_string *imime_type, - const http_parameter *params, - llcache_handle *llcache, - const char *fallback_charset, - bool quirks, - struct content **c) -{ - nscss_content *result; - const char *charset = NULL; - const char *xnsbase = NULL; - lwc_string *charset_value = NULL; - union content_msg_data msg_data; - nserror error; - - result = calloc(1, sizeof(nscss_content)); - if (result == NULL) - return NSERROR_NOMEM; - - error = content__init(&result->base, handler, imime_type, - params, llcache, fallback_charset, quirks); - if (error != NSERROR_OK) { - free(result); - return error; - } - - /* Find charset specified on HTTP layer, if any */ - error = http_parameter_list_find_item(params, corestring_lwc_charset, - &charset_value); - if (error != NSERROR_OK || lwc_string_length(charset_value) == 0) { - /* No charset specified, use fallback, if any */ - /** \todo libcss will take this as gospel, which is wrong */ - charset = fallback_charset; - } else { - charset = lwc_string_data(charset_value); - } - - /* Compute base URL for stylesheet */ - xnsbase = llcache_handle_get_header(llcache, "X-NS-Base"); - if (xnsbase == NULL) { - xnsbase = nsurl_access(content_get_url(&result->base)); - } - - error = nscss_create_css_data(&result->data, - xnsbase, charset, result->base.quirks, - nscss_content_done, result); - if (error != NSERROR_OK) { - msg_data.error = messages_get("NoMemory"); - content_broadcast(&result->base, CONTENT_MSG_ERROR, msg_data); - if (charset_value != NULL) - lwc_string_unref(charset_value); - free(result); - return error; - } - - if (charset_value != NULL) - lwc_string_unref(charset_value); - - *c = (struct content *) result; - - return NSERROR_OK; -} - -/** - * 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 - * \param done Callback to call when content has completed - * \param pw Client data for \a done - * \return NSERROR_OK on success, NSERROR_NOMEM on memory exhaustion - */ -static nserror nscss_create_css_data(struct content_css_data *c, - const char *url, const char *charset, bool quirks, - nscss_done_callback done, void *pw) -{ - css_error error; - css_stylesheet_params params; - - c->pw = pw; - c->done = done; - c->next_to_register = (uint32_t) -1; - c->import_count = 0; - c->imports = NULL; - if (charset != NULL) - c->charset = strdup(charset); - else - c->charset = NULL; - - params.params_version = CSS_STYLESHEET_PARAMS_VERSION_1; - params.level = CSS_LEVEL_DEFAULT; - params.charset = charset; - params.url = url; - params.title = NULL; - params.allow_quirks = quirks; - params.inline_style = false; - params.resolve = nscss_resolve_url; - params.resolve_pw = NULL; - params.import = nscss_handle_import; - params.import_pw = c; - params.color = ns_system_colour; - params.color_pw = NULL; - params.font = NULL; - params.font_pw = NULL; - - error = css_stylesheet_create(¶ms, &c->sheet); - if (error != CSS_OK) { - return NSERROR_NOMEM; - } - - return NSERROR_OK; -} - -/** - * Process CSS source data - * - * \param c Content structure - * \param data Data to process - * \param size Number of bytes to process - * \return true on success, false on failure - */ -bool nscss_process_data(struct content *c, const char *data, unsigned int size) -{ - nscss_content *css = (nscss_content *) c; - union content_msg_data msg_data; - css_error error; - - error = nscss_process_css_data(&css->data, data, size); - if (error != CSS_OK && error != CSS_NEEDDATA) { - msg_data.error = "?"; - content_broadcast(c, CONTENT_MSG_ERROR, msg_data); - } - - return (error == CSS_OK || error == CSS_NEEDDATA); -} - -/** - * 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 - */ -static css_error nscss_process_css_data(struct content_css_data *c, - const 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 - * \return true on success, false on failure - */ -bool nscss_convert(struct content *c) -{ - nscss_content *css = (nscss_content *) c; - union content_msg_data msg_data; - css_error error; - - error = nscss_convert_css_data(&css->data); - if (error != CSS_OK) { - msg_data.error = "?"; - content_broadcast(c, CONTENT_MSG_ERROR, msg_data); - return false; - } - - return true; -} - -/** - * Convert CSS data ready for use - * - * \param c CSS data to convert - * \return CSS error - */ -static css_error nscss_convert_css_data(struct content_css_data *c) -{ - css_error error; - - error = css_stylesheet_data_done(c->sheet); - - /* Process pending imports */ - if (error == CSS_IMPORTS_PENDING) { - /* We must not have registered any imports yet */ - assert(c->next_to_register == (uint32_t) -1); - - /* Start registering, until we find one that - * hasn't finished fetching */ - c->next_to_register = 0; - error = nscss_register_imports(c); - } else if (error == CSS_OK) { - /* No imports, and no errors, so complete conversion */ - c->done(c, c->pw); - } else { - const char *url; - - if (css_stylesheet_get_url(c->sheet, &url) == CSS_OK) { - LOG("Failed converting %p %s (%d)", c, url, error); - } else { - LOG("Failed converting %p (%d)", c, error); - } - } - - return error; -} - -/** - * Clean up a CSS content - * - * \param c Content to clean up - */ -void nscss_destroy(struct content *c) -{ - nscss_content *css = (nscss_content *) c; - - nscss_destroy_css_data(&css->data); -} - -/** - * Clean up CSS data - * - * \param c CSS data to clean up - */ -static void nscss_destroy_css_data(struct content_css_data *c) -{ - uint32_t i; - - for (i = 0; i < c->import_count; i++) { - if (c->imports[i].c != NULL) { - hlcache_handle_release(c->imports[i].c); - } - c->imports[i].c = NULL; - } - - free(c->imports); - - if (c->sheet != NULL) { - css_stylesheet_destroy(c->sheet); - c->sheet = NULL; - } - - free(c->charset); -} - -nserror nscss_clone(const struct content *old, struct content **newc) -{ - const nscss_content *old_css = (const nscss_content *) old; - nscss_content *new_css; - const char *data; - unsigned long size; - nserror error; - - new_css = calloc(1, sizeof(nscss_content)); - if (new_css == NULL) - return NSERROR_NOMEM; - - /* Clone content */ - error = content__clone(old, &new_css->base); - if (error != NSERROR_OK) { - content_destroy(&new_css->base); - return error; - } - - /* Simply replay create/process/convert */ - error = nscss_create_css_data(&new_css->data, - nsurl_access(content_get_url(&new_css->base)), - old_css->data.charset, - new_css->base.quirks, - nscss_content_done, new_css); - if (error != NSERROR_OK) { - content_destroy(&new_css->base); - return error; - } - - data = content__get_source_data(&new_css->base, &size); - if (size > 0) { - if (nscss_process_data(&new_css->base, data, size) == false) { - content_destroy(&new_css->base); - return NSERROR_CLONE_FAILED; - } - } - - if (old->status == CONTENT_STATUS_READY || - old->status == CONTENT_STATUS_DONE) { - if (nscss_convert(&new_css->base) == false) { - content_destroy(&new_css->base); - return NSERROR_CLONE_FAILED; - } - } - - *newc = (struct content *) new_css; - - return NSERROR_OK; -} - -bool nscss_matches_quirks(const struct content *c, bool quirks) -{ - return c->quirks == quirks; -} - -/** - * Retrieve the stylesheet object associated with a CSS content - * - * \param h Stylesheet content - * \return Pointer to stylesheet object - */ -css_stylesheet *nscss_get_stylesheet(struct hlcache_handle *h) -{ - nscss_content *c = (nscss_content *) hlcache_handle_get_content(h); - - assert(c != NULL); - - return c->data.sheet; -} - -/** - * 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) -{ - nscss_content *c = (nscss_content *) hlcache_handle_get_content(h); - - assert(c != NULL); - assert(n != NULL); - - *n = c->data.import_count; - - return c->data.imports; -} - -/** - * Compute the type of a content - * - * \return CONTENT_CSS - */ -content_type nscss_content_type(void) -{ - return CONTENT_CSS; -} - -/***************************************************************************** - * Object completion * - *****************************************************************************/ - -/** - * Handle notification that a CSS object is done - * - * \param css CSS object - * \param pw Private data - */ -void nscss_content_done(struct content_css_data *css, void *pw) -{ - union content_msg_data msg_data; - struct content *c = pw; - uint32_t i; - size_t size; - css_error error; - - /* Retrieve the size of this sheet */ - error = css_stylesheet_size(css->sheet, &size); - if (error != CSS_OK) { - msg_data.error = "?"; - content_broadcast(c, CONTENT_MSG_ERROR, msg_data); - content_set_error(c); - return; - } - c->size += size; - - /* Add on the size of the imported sheets */ - for (i = 0; i < css->import_count; i++) { - if (css->imports[i].c != NULL) { - struct content *import = hlcache_handle_get_content( - css->imports[i].c); - - if (import != NULL) { - c->size += import->size; - } - } - } - - /* Finally, catch the content's users up with reality */ - content_set_ready(c); - content_set_done(c); -} - -/***************************************************************************** - * Import handling * - *****************************************************************************/ - -/** - * 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; -} - -/** - * Handler for imported stylesheet events - * - * \param handle Handle for stylesheet - * \param event Event object - * \param pw Callback context - * \return NSERROR_OK on success, appropriate error otherwise - */ -nserror nscss_import(hlcache_handle *handle, - const hlcache_event *event, void *pw) -{ - nscss_import_ctx *ctx = pw; - css_error error = CSS_OK; - -#ifdef NSCSS_IMPORT_TRACE - LOG("Event %d for %p (%p)", event->type, handle, ctx); -#endif - - assert(ctx->css->imports[ctx->index].c == handle); - - switch (event->type) { - case CONTENT_MSG_DONE: - error = nscss_import_complete(ctx); - break; - - case CONTENT_MSG_ERROR: - hlcache_handle_release(handle); - ctx->css->imports[ctx->index].c = NULL; - - error = nscss_import_complete(ctx); - /* Already released handle */ - break; - - default: - break; - } - - /* Preserve out-of-memory. Anything else is OK */ - return error == CSS_NOMEM ? NSERROR_NOMEM : NSERROR_OK; -} - -/** - * Handle an imported stylesheet completing - * - * \param ctx Import context - * \return CSS_OK on success, appropriate error otherwise - */ -css_error nscss_import_complete(nscss_import_ctx *ctx) -{ - css_error error = CSS_OK; - - /* If this import is the next to be registered, do so */ - if (ctx->css->next_to_register == ctx->index) - error = nscss_register_imports(ctx->css); - -#ifdef NSCSS_IMPORT_TRACE - LOG("Destroying import context %p for %d", ctx, ctx->index); -#endif - - /* No longer need import context */ - free(ctx); - - return error; -} - -/***************************************************************************** - * Import registration * - *****************************************************************************/ - -/** - * Register imports with a stylesheet - * - * \param c CSS object containing the imports - * \return CSS_OK on success, appropriate error otherwise - */ -css_error nscss_register_imports(struct content_css_data *c) -{ - uint32_t index; - css_error error; - - assert(c->next_to_register != (uint32_t) -1); - assert(c->next_to_register < c->import_count); - - /* Register imported sheets */ - for (index = c->next_to_register; index < c->import_count; index++) { - /* Stop registering if we encounter one whose fetch hasn't - * completed yet. We'll resume at this point when it has - * completed. - */ - if (c->imports[index].c != NULL && - content_get_status(c->imports[index].c) != - CONTENT_STATUS_DONE) { - break; - } - - error = nscss_register_import(c, c->imports[index].c); - if (error != CSS_OK) - return error; - } - - /* Record identity of the next import to register */ - c->next_to_register = (uint32_t) index; - - if (c->next_to_register == c->import_count) { - /* No more imports: notify parent that we're DONE */ - c->done(c, c->pw); - } - - return CSS_OK; -} - - -/** - * Register an import with a stylesheet - * - * \param c CSS object that requested the import - * \param import Cache handle of import, or NULL for blank - * \return CSS_OK on success, appropriate error otherwise - */ -css_error nscss_register_import(struct content_css_data *c, - const hlcache_handle *import) -{ - css_stylesheet *sheet; - css_error error; - - if (import != NULL) { - nscss_content *s = - (nscss_content *) hlcache_handle_get_content(import); - sheet = s->data.sheet; - } else { - /* Create a blank sheet if needed. */ - if (blank_import == NULL) { - css_stylesheet_params params; - - params.params_version = CSS_STYLESHEET_PARAMS_VERSION_1; - params.level = CSS_LEVEL_DEFAULT; - params.charset = NULL; - params.url = ""; - params.title = NULL; - params.allow_quirks = false; - params.inline_style = false; - params.resolve = nscss_resolve_url; - params.resolve_pw = NULL; - params.import = NULL; - params.import_pw = NULL; - params.color = ns_system_colour; - params.color_pw = NULL; - params.font = NULL; - params.font_pw = NULL; - - error = css_stylesheet_create(¶ms, &blank_import); - if (error != CSS_OK) { - return error; - } - - error = css_stylesheet_data_done(blank_import); - if (error != CSS_OK) { - css_stylesheet_destroy(blank_import); - return error; - } - } - - sheet = blank_import; - } - - error = css_stylesheet_register_import(c->sheet, sheet); - if (error != CSS_OK) { - return error; - } - - return error; -} - -/** - * Clean up after the CSS content handler - */ -static void nscss_fini(void) -{ - if (blank_import != NULL) { - css_stylesheet_destroy(blank_import); - blank_import = NULL; - } - css_hint_fini(); -} - -static const content_handler css_content_handler = { - .fini = nscss_fini, - .create = nscss_create, - .process_data = nscss_process_data, - .data_complete = nscss_convert, - .destroy = nscss_destroy, - .clone = nscss_clone, - .matches_quirks = nscss_matches_quirks, - .type = nscss_content_type, - .no_share = false, -}; - -/** - * Initialise the CSS content handler - */ -nserror nscss_init(void) -{ - nserror error; - - error = content_factory_register_handler("text/css", - &css_content_handler); - if (error != NSERROR_OK) - goto error; - - error = css_hint_init(); - if (error != NSERROR_OK) - goto error; - - return NSERROR_OK; - -error: - nscss_fini(); - - return error; -} diff --git a/css/css.h b/css/css.h deleted file mode 100644 index be8d4bcd8..000000000 --- a/css/css.h +++ /dev/null @@ -1,44 +0,0 @@ -/* - * Copyright 2009 John-Mark Bell - * - * 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 . - */ - -#ifndef netsurf_css_css_h_ -#define netsurf_css_css_h_ - -#include - -#include - -#include "utils/errors.h" - -struct hlcache_handle; - -/** - * Imported stylesheet record - */ -struct nscss_import { - struct hlcache_handle *c; /**< Content containing sheet */ - uint64_t media; /**< Media types that sheet applies to */ -}; - -nserror nscss_init(void); - -css_stylesheet *nscss_get_stylesheet(struct hlcache_handle *h); -struct nscss_import *nscss_get_imports(struct hlcache_handle *h, uint32_t *n); - -#endif - diff --git a/css/dump.c b/css/dump.c deleted file mode 100644 index d3ebc9481..000000000 --- a/css/dump.c +++ /dev/null @@ -1,1806 +0,0 @@ -/* - * Copyright 2009 John-Mark Bell - * - * 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 . - */ - -#include - -#include "css/dump.h" - -static void dump_css_fixed(FILE *stream, css_fixed f); -static void dump_css_number(FILE *stream, css_fixed val); -static void dump_css_unit(FILE *stream, css_fixed val, css_unit unit); - -/** - * Dump a computed style \a style to the give file handle \a stream. - * - * \param stream Stream to write to - * \param style Computed style to dump - */ -void nscss_dump_computed_style(FILE *stream, const css_computed_style *style) -{ - uint8_t val; - css_color color = 0; - lwc_string *url = NULL; - css_fixed len1 = 0, len2 = 0; - css_unit unit1 = CSS_UNIT_PX, unit2 = CSS_UNIT_PX; - css_computed_clip_rect rect = { 0, 0, 0, 0, CSS_UNIT_PX, CSS_UNIT_PX, - CSS_UNIT_PX, CSS_UNIT_PX, true, true, - true, true }; - const css_computed_content_item *content = NULL; - const css_computed_counter *counter = NULL; - lwc_string **string_list = NULL; - int32_t zindex = 0; - - fprintf(stream, "{ "); - - /* background-attachment */ - val = css_computed_background_attachment(style); - switch (val) { - case CSS_BACKGROUND_ATTACHMENT_FIXED: - fprintf(stream, "background-attachment: fixed "); - break; - case CSS_BACKGROUND_ATTACHMENT_SCROLL: - fprintf(stream, "background-attachment: scroll "); - break; - default: - break; - } - - /* background-color */ - val = css_computed_background_color(style, &color); - switch (val) { - case CSS_BACKGROUND_COLOR_COLOR: - fprintf(stream, "background-color: #%08x ", color); - break; - default: - break; - } - - /* background-image */ - val = css_computed_background_image(style, &url); - if (val == CSS_BACKGROUND_IMAGE_IMAGE && url != NULL) { - fprintf(stream, "background-image: url('%.*s') ", - (int) lwc_string_length(url), - lwc_string_data(url)); - } else if (val == CSS_BACKGROUND_IMAGE_NONE) { - fprintf(stream, "background-image: none "); - } - - /* background-position */ - val = css_computed_background_position(style, &len1, &unit1, - &len2, &unit2); - if (val == CSS_BACKGROUND_POSITION_SET) { - fprintf(stream, "background-position: "); - dump_css_unit(stream, len1, unit1); - fprintf(stream, " "); - dump_css_unit(stream, len2, unit2); - fprintf(stream, " "); - } - - /* background-repeat */ - val = css_computed_background_repeat(style); - switch (val) { - case CSS_BACKGROUND_REPEAT_REPEAT_X: - fprintf(stream, "background-repeat: repeat-x "); - break; - case CSS_BACKGROUND_REPEAT_REPEAT_Y: - fprintf(stream, "background-repeat: repeat-y "); - break; - case CSS_BACKGROUND_REPEAT_REPEAT: - fprintf(stream, "background-repeat: repeat "); - break; - case CSS_BACKGROUND_REPEAT_NO_REPEAT: - fprintf(stream, "background-repeat: no-repeat "); - break; - default: - break; - } - - /* border-collapse */ - val = css_computed_border_collapse(style); - switch (val) { - case CSS_BORDER_COLLAPSE_SEPARATE: - fprintf(stream, "border-collapse: separate "); - break; - case CSS_BORDER_COLLAPSE_COLLAPSE: - fprintf(stream, "border-collapse: collapse "); - break; - default: - - break; - } - - /* border-spacing */ - val = css_computed_border_spacing(style, &len1, &unit1, &len2, &unit2); - if (val == CSS_BORDER_SPACING_SET) { - fprintf(stream, "border-spacing: "); - dump_css_unit(stream, len1, unit1); - fprintf(stream, " "); - dump_css_unit(stream, len2, unit2); - fprintf(stream, " "); - } - - /* border-top-color */ - val = css_computed_border_top_color(style, &color); - switch (val) { - case CSS_BORDER_COLOR_COLOR: - fprintf(stream, "border-top-color: #%08x ", color); - break; - default: - break; - } - - /* border-right-color */ - val = css_computed_border_right_color(style, &color); - switch (val) { - case CSS_BORDER_COLOR_COLOR: - fprintf(stream, "border-right-color: #%08x ", color); - break; - default: - break; - } - - /* border-bottom-color */ - val = css_computed_border_bottom_color(style, &color); - switch (val) { - case CSS_BORDER_COLOR_COLOR: - fprintf(stream, "border-bottom-color: #%08x ", color); - break; - default: - break; - } - - /* border-left-color */ - val = css_computed_border_left_color(style, &color); - switch (val) { - case CSS_BORDER_COLOR_COLOR: - fprintf(stream, "border-left-color: #%08x ", color); - break; - default: - break; - } - - /* border-top-style */ - val = css_computed_border_top_style(style); - switch (val) { - case CSS_BORDER_STYLE_NONE: - fprintf(stream, "border-top-style: none "); - break; - case CSS_BORDER_STYLE_HIDDEN: - fprintf(stream, "border-top-style: hidden "); - break; - case CSS_BORDER_STYLE_DOTTED: - fprintf(stream, "border-top-style: dotted "); - break; - case CSS_BORDER_STYLE_DASHED: - fprintf(stream, "border-top-style: dashed "); - break; - case CSS_BORDER_STYLE_SOLID: - fprintf(stream, "border-top-style: solid "); - break; - case CSS_BORDER_STYLE_DOUBLE: - fprintf(stream, "border-top-style: double "); - break; - case CSS_BORDER_STYLE_GROOVE: - fprintf(stream, "border-top-style: groove "); - break; - case CSS_BORDER_STYLE_RIDGE: - fprintf(stream, "border-top-style: ridge "); - break; - case CSS_BORDER_STYLE_INSET: - fprintf(stream, "border-top-style: inset "); - break; - case CSS_BORDER_STYLE_OUTSET: - fprintf(stream, "border-top-style: outset "); - break; - default: - break; - } - - /* border-right-style */ - val = css_computed_border_right_style(style); - switch (val) { - case CSS_BORDER_STYLE_NONE: - fprintf(stream, "border-right-style: none "); - break; - case CSS_BORDER_STYLE_HIDDEN: - fprintf(stream, "border-right-style: hidden "); - break; - case CSS_BORDER_STYLE_DOTTED: - fprintf(stream, "border-right-style: dotted "); - break; - case CSS_BORDER_STYLE_DASHED: - fprintf(stream, "border-right-style: dashed "); - break; - case CSS_BORDER_STYLE_SOLID: - fprintf(stream, "border-right-style: solid "); - break; - case CSS_BORDER_STYLE_DOUBLE: - fprintf(stream, "border-right-style: double "); - break; - case CSS_BORDER_STYLE_GROOVE: - fprintf(stream, "border-right-style: groove "); - break; - case CSS_BORDER_STYLE_RIDGE: - fprintf(stream, "border-right-style: ridge "); - break; - case CSS_BORDER_STYLE_INSET: - fprintf(stream, "border-right-style: inset "); - break; - case CSS_BORDER_STYLE_OUTSET: - fprintf(stream, "border-right-style: outset "); - break; - default: - break; - } - - /* border-bottom-style */ - val = css_computed_border_bottom_style(style); - switch (val) { - case CSS_BORDER_STYLE_NONE: - fprintf(stream, "border-bottom-style: none "); - break; - case CSS_BORDER_STYLE_HIDDEN: - fprintf(stream, "border-bottom-style: hidden "); - break; - case CSS_BORDER_STYLE_DOTTED: - fprintf(stream, "border-bottom-style: dotted "); - break; - case CSS_BORDER_STYLE_DASHED: - fprintf(stream, "border-bottom-style: dashed "); - break; - case CSS_BORDER_STYLE_SOLID: - fprintf(stream, "border-bottom-style: solid "); - break; - case CSS_BORDER_STYLE_DOUBLE: - fprintf(stream, "border-bottom-style: double "); - break; - case CSS_BORDER_STYLE_GROOVE: - fprintf(stream, "border-bottom-style: groove "); - break; - case CSS_BORDER_STYLE_RIDGE: - fprintf(stream, "border-bottom-style: ridge "); - break; - case CSS_BORDER_STYLE_INSET: - fprintf(stream, "border-bottom-style: inset "); - break; - case CSS_BORDER_STYLE_OUTSET: - fprintf(stream, "border-bottom-style: outset "); - break; - default: - break; - } - - /* border-left-style */ - val = css_computed_border_left_style(style); - switch (val) { - case CSS_BORDER_STYLE_NONE: - fprintf(stream, "border-left-style: none "); - break; - case CSS_BORDER_STYLE_HIDDEN: - fprintf(stream, "border-left-style: hidden "); - break; - case CSS_BORDER_STYLE_DOTTED: - fprintf(stream, "border-left-style: dotted "); - break; - case CSS_BORDER_STYLE_DASHED: - fprintf(stream, "border-left-style: dashed "); - break; - case CSS_BORDER_STYLE_SOLID: - fprintf(stream, "border-left-style: solid "); - break; - case CSS_BORDER_STYLE_DOUBLE: - fprintf(stream, "border-left-style: double "); - break; - case CSS_BORDER_STYLE_GROOVE: - fprintf(stream, "border-left-style: groove "); - break; - case CSS_BORDER_STYLE_RIDGE: - fprintf(stream, "border-left-style: ridge "); - break; - case CSS_BORDER_STYLE_INSET: - fprintf(stream, "border-left-style: inset "); - break; - case CSS_BORDER_STYLE_OUTSET: - fprintf(stream, "border-left-style: outset "); - break; - default: - break; - } - - /* border-top-width */ - val = css_computed_border_top_width(style, &len1, &unit1); - switch (val) { - case CSS_BORDER_WIDTH_THIN: - fprintf(stream, "border-top-width: thin "); - break; - case CSS_BORDER_WIDTH_MEDIUM: - fprintf(stream, "border-top-width: medium "); - break; - case CSS_BORDER_WIDTH_THICK: - fprintf(stream, "border-top-width: thick "); - break; - case CSS_BORDER_WIDTH_WIDTH: - fprintf(stream, "border-top-width: "); - dump_css_unit(stream, len1, unit1); - fprintf(stream, " "); - break; - default: - break; - } - - /* border-right-width */ - val = css_computed_border_right_width(style, &len1, &unit1); - switch (val) { - case CSS_BORDER_WIDTH_THIN: - fprintf(stream, "border-right-width: thin "); - break; - case CSS_BORDER_WIDTH_MEDIUM: - fprintf(stream, "border-right-width: medium "); - break; - case CSS_BORDER_WIDTH_THICK: - fprintf(stream, "border-right-width: thick "); - break; - case CSS_BORDER_WIDTH_WIDTH: - fprintf(stream, "border-right-width: "); - dump_css_unit(stream, len1, unit1); - fprintf(stream, " "); - break; - default: - break; - } - - /* border-bottom-width */ - val = css_computed_border_bottom_width(style, &len1, &unit1); - switch (val) { - case CSS_BORDER_WIDTH_THIN: - fprintf(stream, "border-bottom-width: thin "); - break; - case CSS_BORDER_WIDTH_MEDIUM: - fprintf(stream, "border-bottom-width: medium "); - break; - case CSS_BORDER_WIDTH_THICK: - fprintf(stream, "border-bottom-width: thick "); - break; - case CSS_BORDER_WIDTH_WIDTH: - fprintf(stream, "border-bottom-width: "); - dump_css_unit(stream, len1, unit1); - fprintf(stream, " "); - break; - default: - break; - } - - /* border-left-width */ - val = css_computed_border_left_width(style, &len1, &unit1); - switch (val) { - case CSS_BORDER_WIDTH_THIN: - fprintf(stream, "border-left-width: thin "); - break; - case CSS_BORDER_WIDTH_MEDIUM: - fprintf(stream, "border-left-width: medium "); - break; - case CSS_BORDER_WIDTH_THICK: - fprintf(stream, "border-left-width: thick "); - break; - case CSS_BORDER_WIDTH_WIDTH: - fprintf(stream, "border-left-width: "); - dump_css_unit(stream, len1, unit1); - fprintf(stream, " "); - break; - default: - break; - } - - /* bottom */ - val = css_computed_bottom(style, &len1, &unit1); - switch (val) { - case CSS_BOTTOM_AUTO: - fprintf(stream, "bottom: auto "); - break; - case CSS_BOTTOM_SET: - fprintf(stream, "bottom: "); - dump_css_unit(stream, len1, unit1); - fprintf(stream, " "); - break; - default: - break; - } - - /* caption-side */ - val = css_computed_caption_side(style); - switch (val) { - case CSS_CAPTION_SIDE_TOP: - fprintf(stream, "caption_side: top "); - break; - case CSS_CAPTION_SIDE_BOTTOM: - fprintf(stream, "caption_side: bottom "); - break; - default: - break; - } - - /* clear */ - val = css_computed_clear(style); - switch (val) { - case CSS_CLEAR_NONE: - fprintf(stream, "clear: none "); - break; - case CSS_CLEAR_LEFT: - fprintf(stream, "clear: left "); - break; - case CSS_CLEAR_RIGHT: - fprintf(stream, "clear: right "); - break; - case CSS_CLEAR_BOTH: - fprintf(stream, "clear: both "); - break; - default: - break; - } - - /* clip */ - val = css_computed_clip(style, &rect); - switch (val) { - case CSS_CLIP_AUTO: - fprintf(stream, "clip: auto "); - break; - case CSS_CLIP_RECT: - fprintf(stream, "clip: rect( "); - - if (rect.top_auto) - fprintf(stream, "auto"); - else - dump_css_unit(stream, rect.top, rect.tunit); - fprintf(stream, ", "); - - if (rect.right_auto) - fprintf(stream, "auto"); - else - dump_css_unit(stream, rect.right, rect.runit); - fprintf(stream, ", "); - - if (rect.bottom_auto) - fprintf(stream, "auto"); - else - dump_css_unit(stream, rect.bottom, rect.bunit); - fprintf(stream, ", "); - - if (rect.left_auto) - fprintf(stream, "auto"); - else - dump_css_unit(stream, rect.left, rect.lunit); - fprintf(stream, ") "); - break; - default: - break; - } - - /* color */ - val = css_computed_color(style, &color); - if (val == CSS_COLOR_COLOR) { - fprintf(stream, "color: #%08x ", color); - } - - /* content */ - val = css_computed_content(style, &content); - switch (val) { - case CSS_CONTENT_NONE: - fprintf(stream, "content: none "); - break; - case CSS_CONTENT_NORMAL: - fprintf(stream, "content: normal "); - break; - case CSS_CONTENT_SET: - fprintf(stream, "content:"); - - while (content->type != CSS_COMPUTED_CONTENT_NONE) { - fprintf(stream, " "); - - switch (content->type) { - case CSS_COMPUTED_CONTENT_STRING: - fprintf(stream, "\"%.*s\"", - (int) lwc_string_length( - content->data.string), - lwc_string_data( - content->data.string)); - break; - case CSS_COMPUTED_CONTENT_URI: - fprintf(stream, "uri(\"%.*s\")", - (int) lwc_string_length( - content->data.uri), - lwc_string_data( - content->data.uri)); - break; - case CSS_COMPUTED_CONTENT_COUNTER: - fprintf(stream, "counter(%.*s)", - (int) lwc_string_length( - content->data.counter.name), - lwc_string_data( - content->data.counter.name)); - break; - case CSS_COMPUTED_CONTENT_COUNTERS: - fprintf(stream, "counters(%.*s, \"%.*s\")", - (int) lwc_string_length( - content->data.counters.name), - lwc_string_data( - content->data.counters.name), - (int) lwc_string_length( - content->data.counters.sep), - lwc_string_data( - content->data.counters.sep)); - break; - case CSS_COMPUTED_CONTENT_ATTR: - fprintf(stream, "attr(%.*s)", - (int) lwc_string_length( - content->data.attr), - lwc_string_data( - content->data.attr)); - break; - case CSS_COMPUTED_CONTENT_OPEN_QUOTE: - fprintf(stream, "open-quote"); - break; - case CSS_COMPUTED_CONTENT_CLOSE_QUOTE: - fprintf(stream, "close-quote"); - break; - case CSS_COMPUTED_CONTENT_NO_OPEN_QUOTE: - fprintf(stream, "no-open-quote"); - break; - case CSS_COMPUTED_CONTENT_NO_CLOSE_QUOTE: - fprintf(stream, "no-close-quote"); - break; - } - - content++; - } - - fprintf(stream, " "); - break; - default: - break; - } - - /* counter-increment */ - val = css_computed_counter_increment(style, &counter); - if ((val == CSS_COUNTER_INCREMENT_NONE) || (counter == NULL)) { - fprintf(stream, "counter-increment: none "); - } else { - fprintf(stream, "counter-increment:"); - - while (counter->name != NULL) { - fprintf(stream, " %.*s ", - (int) lwc_string_length(counter->name), - lwc_string_data(counter->name)); - - dump_css_fixed(stream, counter->value); - - counter++; - } - - fprintf(stream, " "); - } - - /* counter-reset */ - val = css_computed_counter_reset(style, &counter); - if ((val == CSS_COUNTER_RESET_NONE) || (counter == NULL)) { - fprintf(stream, "counter-reset: none "); - } else { - fprintf(stream, "counter-reset:"); - - while (counter->name != NULL) { - fprintf(stream, " %.*s ", - (int) lwc_string_length(counter->name), - lwc_string_data(counter->name)); - - dump_css_fixed(stream, counter->value); - - counter++; - } - - fprintf(stream, " "); - } - - /* cursor */ - val = css_computed_cursor(style, &string_list); - fprintf(stream, "cursor:"); - - if (string_list != NULL) { - while (*string_list != NULL) { - fprintf(stream, " url\"%.*s\")", - (int) lwc_string_length(*string_list), - lwc_string_data(*string_list)); - - string_list++; - } - } - switch (val) { - case CSS_CURSOR_AUTO: - fprintf(stream, " auto "); - break; - case CSS_CURSOR_CROSSHAIR: - fprintf(stream, " crosshair "); - break; - case CSS_CURSOR_DEFAULT: - fprintf(stream, " default "); - break; - case CSS_CURSOR_POINTER: - fprintf(stream, " pointer "); - break; - case CSS_CURSOR_MOVE: - fprintf(stream, " move "); - break; - case CSS_CURSOR_E_RESIZE: - fprintf(stream, " e-resize "); - break; - case CSS_CURSOR_NE_RESIZE: - fprintf(stream, " ne-resize "); - break; - case CSS_CURSOR_NW_RESIZE: - fprintf(stream, " nw-resize "); - break; - case CSS_CURSOR_N_RESIZE: - fprintf(stream, " n-resize "); - break; - case CSS_CURSOR_SE_RESIZE: - fprintf(stream, " se-resize "); - break; - case CSS_CURSOR_SW_RESIZE: - fprintf(stream, " sw-resize "); - break; - case CSS_CURSOR_S_RESIZE: - fprintf(stream, " s-resize "); - break; - case CSS_CURSOR_W_RESIZE: - fprintf(stream, " w-resize "); - break; - case CSS_CURSOR_TEXT: - fprintf(stream, " text "); - break; - case CSS_CURSOR_WAIT: - fprintf(stream, " wait "); - break; - case CSS_CURSOR_HELP: - fprintf(stream, " help "); - break; - case CSS_CURSOR_PROGRESS: - fprintf(stream, " progress "); - break; - default: - break; - } - - /* direction */ - val = css_computed_direction(style); - switch (val) { - case CSS_DIRECTION_LTR: - fprintf(stream, "direction: ltr "); - break; - case CSS_DIRECTION_RTL: - fprintf(stream, "direction: rtl "); - break; - default: - break; - } - - /* display */ - val = css_computed_display_static(style); - switch (val) { - case CSS_DISPLAY_INLINE: - fprintf(stream, "display: inline "); - break; - case CSS_DISPLAY_BLOCK: - fprintf(stream, "display: block "); - break; - case CSS_DISPLAY_LIST_ITEM: - fprintf(stream, "display: list-item "); - break; - case CSS_DISPLAY_RUN_IN: - fprintf(stream, "display: run-in "); - break; - case CSS_DISPLAY_INLINE_BLOCK: - fprintf(stream, "display: inline-block "); - break; - case CSS_DISPLAY_TABLE: - fprintf(stream, "display: table "); - break; - case CSS_DISPLAY_INLINE_TABLE: - fprintf(stream, "display: inline-table "); - break; - case CSS_DISPLAY_TABLE_ROW_GROUP: - fprintf(stream, "display: table-row-group "); - break; - case CSS_DISPLAY_TABLE_HEADER_GROUP: - fprintf(stream, "display: table-header-group "); - break; - case CSS_DISPLAY_TABLE_FOOTER_GROUP: - fprintf(stream, "display: table-footer-group "); - break; - case CSS_DISPLAY_TABLE_ROW: - fprintf(stream, "display: table-row "); - break; - case CSS_DISPLAY_TABLE_COLUMN_GROUP: - fprintf(stream, "display: table-column-group "); - break; - case CSS_DISPLAY_TABLE_COLUMN: - fprintf(stream, "display: table-column "); - break; - case CSS_DISPLAY_TABLE_CELL: - fprintf(stream, "display: table-cell "); - break; - case CSS_DISPLAY_TABLE_CAPTION: - fprintf(stream, "display: table-caption "); - break; - case CSS_DISPLAY_NONE: - fprintf(stream, "display: none "); - break; - default: - break; - } - - /* empty-cells */ - val = css_computed_empty_cells(style); - switch (val) { - case CSS_EMPTY_CELLS_SHOW: - fprintf(stream, "empty-cells: show "); - break; - case CSS_EMPTY_CELLS_HIDE: - fprintf(stream, "empty-cells: hide "); - break; - default: - break; - } - - /* float */ - val = css_computed_float(style); - switch (val) { - case CSS_FLOAT_LEFT: - fprintf(stream, "float: left "); - break; - case CSS_FLOAT_RIGHT: - fprintf(stream, "float: right "); - break; - case CSS_FLOAT_NONE: - fprintf(stream, "float: none "); - break; - default: - break; - } - - /* font-family */ - val = css_computed_font_family(style, &string_list); - if (val != CSS_FONT_FAMILY_INHERIT) { - fprintf(stream, "font-family:"); - - if (string_list != NULL) { - while (*string_list != NULL) { - fprintf(stream, " \"%.*s\"", - (int) lwc_string_length(*string_list), - lwc_string_data(*string_list)); - - string_list++; - } - } - switch (val) { - case CSS_FONT_FAMILY_SERIF: - fprintf(stream, " serif "); - break; - case CSS_FONT_FAMILY_SANS_SERIF: - fprintf(stream, " sans-serif "); - break; - case CSS_FONT_FAMILY_CURSIVE: - fprintf(stream, " cursive "); - break; - case CSS_FONT_FAMILY_FANTASY: - fprintf(stream, " fantasy "); - break; - case CSS_FONT_FAMILY_MONOSPACE: - fprintf(stream, " monospace "); - break; - } - } - - /* font-size */ - val = css_computed_font_size(style, &len1, &unit1); - switch (val) { - case CSS_FONT_SIZE_XX_SMALL: - fprintf(stream, "font-size: xx-small "); - break; - case CSS_FONT_SIZE_X_SMALL: - fprintf(stream, "font-size: x-small "); - break; - case CSS_FONT_SIZE_SMALL: - fprintf(stream, "font-size: small "); - break; - case CSS_FONT_SIZE_MEDIUM: - fprintf(stream, "font-size: medium "); - break; - case CSS_FONT_SIZE_LARGE: - fprintf(stream, "font-size: large "); - break; - case CSS_FONT_SIZE_X_LARGE: - fprintf(stream, "font-size: x-large "); - break; - case CSS_FONT_SIZE_XX_LARGE: - fprintf(stream, "font-size: xx-large "); - break; - case CSS_FONT_SIZE_LARGER: - fprintf(stream, "font-size: larger "); - break; - case CSS_FONT_SIZE_SMALLER: - fprintf(stream, "font-size: smaller "); - break; - case CSS_FONT_SIZE_DIMENSION: - fprintf(stream, "font-size: "); - - dump_css_unit(stream, len1, unit1); - - fprintf(stream, " "); - break; - default: - break; - } - - /* font-style */ - val = css_computed_font_style(style); - switch (val) { - case CSS_FONT_STYLE_NORMAL: - fprintf(stream, "font-style: normal "); - break; - case CSS_FONT_STYLE_ITALIC: - fprintf(stream, "font-style: italic "); - break; - case CSS_FONT_STYLE_OBLIQUE: - fprintf(stream, "font-style: oblique "); - break; - default: - break; - } - - /* font-variant */ - val = css_computed_font_variant(style); - switch (val) { - case CSS_FONT_VARIANT_NORMAL: - fprintf(stream, "font-variant: normal "); - break; - case CSS_FONT_VARIANT_SMALL_CAPS: - fprintf(stream, "font-variant: small-caps "); - break; - default: - break; - } - - /* font-weight */ - val = css_computed_font_weight(style); - switch (val) { - case CSS_FONT_WEIGHT_NORMAL: - fprintf(stream, "font-weight: normal "); - break; - case CSS_FONT_WEIGHT_BOLD: - fprintf(stream, "font-weight: bold "); - break; - case CSS_FONT_WEIGHT_BOLDER: - fprintf(stream, "font-weight: bolder "); - break; - case CSS_FONT_WEIGHT_LIGHTER: - fprintf(stream, "font-weight: lighter "); - break; - case CSS_FONT_WEIGHT_100: - fprintf(stream, "font-weight: 100 "); - break; - case CSS_FONT_WEIGHT_200: - fprintf(stream, "font-weight: 200 "); - break; - case CSS_FONT_WEIGHT_300: - fprintf(stream, "font-weight: 300 "); - break; - case CSS_FONT_WEIGHT_400: - fprintf(stream, "font-weight: 400 "); - break; - case CSS_FONT_WEIGHT_500: - fprintf(stream, "font-weight: 500 "); - break; - case CSS_FONT_WEIGHT_600: - fprintf(stream, "font-weight: 600 "); - break; - case CSS_FONT_WEIGHT_700: - fprintf(stream, "font-weight: 700 "); - break; - case CSS_FONT_WEIGHT_800: - fprintf(stream, "font-weight: 800 "); - break; - case CSS_FONT_WEIGHT_900: - fprintf(stream, "font-weight: 900 "); - break; - default: - break; - } - - /* height */ - val = css_computed_height(style, &len1, &unit1); - switch (val) { - case CSS_HEIGHT_AUTO: - fprintf(stream, "height: auto "); - break; - case CSS_HEIGHT_SET: - fprintf(stream, "height: "); - - dump_css_unit(stream, len1, unit1); - - fprintf(stream, " "); - break; - default: - break; - } - - /* left */ - val = css_computed_left(style, &len1, &unit1); - switch (val) { - case CSS_LEFT_AUTO: - fprintf(stream, "left: auto "); - break; - case CSS_LEFT_SET: - fprintf(stream, "left: "); - - dump_css_unit(stream, len1, unit1); - - fprintf(stream, " "); - break; - default: - break; - } - - /* letter-spacing */ - val = css_computed_letter_spacing(style, &len1, &unit1); - switch (val) { - case CSS_LETTER_SPACING_NORMAL: - fprintf(stream, "letter-spacing: normal "); - break; - case CSS_LETTER_SPACING_SET: - fprintf(stream, "letter-spacing: "); - - dump_css_unit(stream, len1, unit1); - - fprintf(stream, " "); - break; - default: - break; - } - - /* line-height */ - val = css_computed_line_height(style, &len1, &unit1); - switch (val) { - case CSS_LINE_HEIGHT_NORMAL: - fprintf(stream, "line-height: normal "); - break; - case CSS_LINE_HEIGHT_NUMBER: - fprintf(stream, "line-height: "); - - dump_css_fixed(stream, len1); - - fprintf(stream, " "); - break; - case CSS_LINE_HEIGHT_DIMENSION: - fprintf(stream, "line-height: "); - - dump_css_unit(stream, len1, unit1); - - fprintf(stream, " "); - break; - default: - break; - } - - /* list-style-image */ - val = css_computed_list_style_image(style, &url); - if (url != NULL) { - fprintf(stream, "list-style-image: url('%.*s') ", - (int) lwc_string_length(url), - lwc_string_data(url)); - } else if (val == CSS_LIST_STYLE_IMAGE_NONE) { - fprintf(stream, "list-style-image: none "); - } - - /* list-style-position */ - val = css_computed_list_style_position(style); - switch (val) { - case CSS_LIST_STYLE_POSITION_INSIDE: - fprintf(stream, "list-style-position: inside "); - break; - case CSS_LIST_STYLE_POSITION_OUTSIDE: - fprintf(stream, "list-style-position: outside "); - break; - default: - break; - } - - /* list-style-type */ - val = css_computed_list_style_type(style); - switch (val) { - case CSS_LIST_STYLE_TYPE_DISC: - fprintf(stream, "list-style-type: disc "); - break; - case CSS_LIST_STYLE_TYPE_CIRCLE: - fprintf(stream, "list-style-type: circle "); - break; - case CSS_LIST_STYLE_TYPE_SQUARE: - fprintf(stream, "list-style-type: square "); - break; - case CSS_LIST_STYLE_TYPE_DECIMAL: - fprintf(stream, "list-style-type: decimal "); - break; - case CSS_LIST_STYLE_TYPE_DECIMAL_LEADING_ZERO: - fprintf(stream, "list-style-type: decimal-leading-zero "); - break; - case CSS_LIST_STYLE_TYPE_LOWER_ROMAN: - fprintf(stream, "list-style-type: lower-roman "); - break; - case CSS_LIST_STYLE_TYPE_UPPER_ROMAN: - fprintf(stream, "list-style-type: upper-roman "); - break; - case CSS_LIST_STYLE_TYPE_LOWER_GREEK: - fprintf(stream, "list-style-type: lower-greek "); - break; - case CSS_LIST_STYLE_TYPE_LOWER_LATIN: - fprintf(stream, "list-style-type: lower-latin "); - break; - case CSS_LIST_STYLE_TYPE_UPPER_LATIN: - fprintf(stream, "list-style-type: upper-latin "); - break; - case CSS_LIST_STYLE_TYPE_ARMENIAN: - fprintf(stream, "list-style-type: armenian "); - break; - case CSS_LIST_STYLE_TYPE_GEORGIAN: - fprintf(stream, "list-style-type: georgian "); - break; - case CSS_LIST_STYLE_TYPE_LOWER_ALPHA: - fprintf(stream, "list-style-type: lower-alpha "); - break; - case CSS_LIST_STYLE_TYPE_UPPER_ALPHA: - fprintf(stream, "list-style-type: upper-alpha "); - break; - case CSS_LIST_STYLE_TYPE_NONE: - fprintf(stream, "list-style-type: none "); - break; - default: - break; - } - - /* margin-top */ - val = css_computed_margin_top(style, &len1, &unit1); - switch (val) { - case CSS_MARGIN_AUTO: - fprintf(stream, "margin-top: auto "); - break; - case CSS_MARGIN_SET: - fprintf(stream, "margin-top: "); - - dump_css_unit(stream, len1, unit1); - - fprintf(stream, " "); - break; - default: - break; - } - - /* margin-right */ - val = css_computed_margin_right(style, &len1, &unit1); - switch (val) { - case CSS_MARGIN_AUTO: - fprintf(stream, "margin-right: auto "); - break; - case CSS_MARGIN_SET: - fprintf(stream, "margin-right: "); - - dump_css_unit(stream, len1, unit1); - - fprintf(stream, " "); - break; - default: - break; - } - - /* margin-bottom */ - val = css_computed_margin_bottom(style, &len1, &unit1); - switch (val) { - case CSS_MARGIN_AUTO: - fprintf(stream, "margin-bottom: auto "); - break; - case CSS_MARGIN_SET: - fprintf(stream, "margin-bottom: "); - - dump_css_unit(stream, len1, unit1); - - fprintf(stream, " "); - break; - default: - break; - } - - /* margin-left */ - val = css_computed_margin_left(style, &len1, &unit1); - switch (val) { - case CSS_MARGIN_AUTO: - fprintf(stream, "margin-left: auto "); - break; - case CSS_MARGIN_SET: - fprintf(stream, "margin-left: "); - - dump_css_unit(stream, len1, unit1); - - fprintf(stream, " "); - break; - default: - break; - } - - /* max-height */ - val = css_computed_max_height(style, &len1, &unit1); - switch (val) { - case CSS_MAX_HEIGHT_NONE: - fprintf(stream, "max-height: none "); - break; - case CSS_MAX_HEIGHT_SET: - fprintf(stream, "max-height: "); - - dump_css_unit(stream, len1, unit1); - - fprintf(stream, " "); - break; - default: - break; - } - - /* max-width */ - val = css_computed_max_width(style, &len1, &unit1); - switch (val) { - case CSS_MAX_WIDTH_NONE: - fprintf(stream, "max-width: none "); - break; - case CSS_MAX_WIDTH_SET: - fprintf(stream, "max-width: "); - - dump_css_unit(stream, len1, unit1); - - fprintf(stream, " "); - break; - default: - break; - } - - /* min-height */ - val = css_computed_min_height(style, &len1, &unit1); - switch (val) { - case CSS_MIN_HEIGHT_SET: - fprintf(stream, "min-height: "); - - dump_css_unit(stream, len1, unit1); - - fprintf(stream, " "); - break; - default: - break; - } - - /* min-width */ - val = css_computed_min_width(style, &len1, &unit1); - switch (val) { - case CSS_MIN_WIDTH_SET: - fprintf(stream, "min-width: "); - - dump_css_unit(stream, len1, unit1); - - fprintf(stream, " "); - break; - default: - break; - } - - /* opacity */ - val = css_computed_opacity(style, &len1); - switch (val) { - case CSS_OPACITY_SET: - fprintf(stream, "opacity: "); - - dump_css_fixed(stream, len1); - - fprintf(stream, " "); - break; - default: - break; - } - - /* outline-color */ - val = css_computed_outline_color(style, &color); - switch (val) { - case CSS_OUTLINE_COLOR_INVERT: - fprintf(stream, "outline-color: invert "); - break; - case CSS_OUTLINE_COLOR_COLOR: - fprintf(stream, "outline-color: #%08x ", color); - break; - default: - break; - } - - /* outline-style */ - val = css_computed_outline_style(style); - switch (val) { - case CSS_OUTLINE_STYLE_NONE: - fprintf(stream, "outline-style: none "); - break; - case CSS_OUTLINE_STYLE_DOTTED: - fprintf(stream, "outline-style: dotted "); - break; - case CSS_OUTLINE_STYLE_DASHED: - fprintf(stream, "outline-style: dashed "); - break; - case CSS_OUTLINE_STYLE_SOLID: - fprintf(stream, "outline-style: solid "); - break; - case CSS_OUTLINE_STYLE_DOUBLE: - fprintf(stream, "outline-style: double "); - break; - case CSS_OUTLINE_STYLE_GROOVE: - fprintf(stream, "outline-style: groove "); - break; - case CSS_OUTLINE_STYLE_RIDGE: - fprintf(stream, "outline-style: ridge "); - break; - case CSS_OUTLINE_STYLE_INSET: - fprintf(stream, "outline-style: inset "); - break; - case CSS_OUTLINE_STYLE_OUTSET: - fprintf(stream, "outline-style: outset "); - break; - default: - break; - } - - /* outline-width */ - val = css_computed_outline_width(style, &len1, &unit1); - switch (val) { - case CSS_OUTLINE_WIDTH_THIN: - fprintf(stream, "outline-width: thin "); - break; - case CSS_OUTLINE_WIDTH_MEDIUM: - fprintf(stream, "outline-width: medium "); - break; - case CSS_OUTLINE_WIDTH_THICK: - fprintf(stream, "outline-width: thick "); - break; - case CSS_OUTLINE_WIDTH_WIDTH: - fprintf(stream, "outline-width: "); - - dump_css_unit(stream, len1, unit1); - - fprintf(stream, " "); - break; - default: - break; - } - - /* overflow */ - val = css_computed_overflow_x(style); - switch (val) { - case CSS_OVERFLOW_VISIBLE: - fprintf(stream, "overflow-x: visible "); - break; - case CSS_OVERFLOW_HIDDEN: - fprintf(stream, "overflow-x: hidden "); - break; - case CSS_OVERFLOW_SCROLL: - fprintf(stream, "overflow-x: scroll "); - break; - case CSS_OVERFLOW_AUTO: - fprintf(stream, "overflow-x auto "); - break; - default: - break; - } - - /* overflow */ - val = css_computed_overflow_y(style); - switch (val) { - case CSS_OVERFLOW_VISIBLE: - fprintf(stream, "overflow-y: visible "); - break; - case CSS_OVERFLOW_HIDDEN: - fprintf(stream, "overflow-y: hidden "); - break; - case CSS_OVERFLOW_SCROLL: - fprintf(stream, "overflow-y: scroll "); - break; - case CSS_OVERFLOW_AUTO: - fprintf(stream, "overflow-y: auto "); - break; - default: - break; - } - - /* padding-top */ - val = css_computed_padding_top(style, &len1, &unit1); - switch (val) { - case CSS_PADDING_SET: - fprintf(stream, "padding-top: "); - - dump_css_unit(stream, len1, unit1); - - fprintf(stream, " "); - break; - default: - break; - } - - /* padding-right */ - val = css_computed_padding_right(style, &len1, &unit1); - switch (val) { - case CSS_PADDING_SET: - fprintf(stream, "padding-right: "); - - dump_css_unit(stream, len1, unit1); - - fprintf(stream, " "); - break; - default: - break; - } - - /* padding-bottom */ - val = css_computed_padding_bottom(style, &len1, &unit1); - switch (val) { - case CSS_PADDING_SET: - fprintf(stream, "padding-bottom: "); - - dump_css_unit(stream, len1, unit1); - - fprintf(stream, " "); - break; - default: - break; - } - - /* padding-left */ - val = css_computed_padding_left(style, &len1, &unit1); - switch (val) { - case CSS_PADDING_SET: - fprintf(stream, "padding-left: "); - - dump_css_unit(stream, len1, unit1); - - fprintf(stream, " "); - break; - default: - break; - } - - /* position */ - val = css_computed_position(style); - switch (val) { - case CSS_POSITION_STATIC: - fprintf(stream, "position: static "); - break; - case CSS_POSITION_RELATIVE: - fprintf(stream, "position: relative "); - break; - case CSS_POSITION_ABSOLUTE: - fprintf(stream, "position: absolute "); - break; - case CSS_POSITION_FIXED: - fprintf(stream, "position: fixed "); - break; - default: - break; - } - - /* quotes */ - val = css_computed_quotes(style, &string_list); - if (val == CSS_QUOTES_STRING && string_list != NULL) { - fprintf(stream, "quotes:"); - - while (*string_list != NULL) { - fprintf(stream, " \"%.*s\"", - (int) lwc_string_length(*string_list), - lwc_string_data(*string_list)); - - string_list++; - } - - fprintf(stream, " "); - } else { - switch (val) { - case CSS_QUOTES_NONE: - fprintf(stream, "quotes: none "); - break; - default: - break; - } - } - - /* right */ - val = css_computed_right(style, &len1, &unit1); - switch (val) { - case CSS_RIGHT_AUTO: - fprintf(stream, "right: auto "); - break; - case CSS_RIGHT_SET: - fprintf(stream, "right: "); - - dump_css_unit(stream, len1, unit1); - - fprintf(stream, " "); - break; - default: - break; - } - - /* table-layout */ - val = css_computed_table_layout(style); - switch (val) { - case CSS_TABLE_LAYOUT_AUTO: - fprintf(stream, "table-layout: auto "); - break; - case CSS_TABLE_LAYOUT_FIXED: - fprintf(stream, "table-layout: fixed "); - break; - default: - break; - } - - /* text-align */ - val = css_computed_text_align(style); - switch (val) { - case CSS_TEXT_ALIGN_LEFT: - fprintf(stream, "text-align: left "); - break; - case CSS_TEXT_ALIGN_RIGHT: - fprintf(stream, "text-align: right "); - break; - case CSS_TEXT_ALIGN_CENTER: - fprintf(stream, "text-align: center "); - break; - case CSS_TEXT_ALIGN_JUSTIFY: - fprintf(stream, "text-align: justify "); - break; - case CSS_TEXT_ALIGN_DEFAULT: - fprintf(stream, "text-align: default "); - break; - case CSS_TEXT_ALIGN_LIBCSS_LEFT: - fprintf(stream, "text-align: -libcss-left "); - break; - case CSS_TEXT_ALIGN_LIBCSS_CENTER: - fprintf(stream, "text-align: -libcss-center "); - break; - case CSS_TEXT_ALIGN_LIBCSS_RIGHT: - fprintf(stream, "text-align: -libcss-right "); - break; - default: - break; - } - - /* text-decoration */ - val = css_computed_text_decoration(style); - if (val == CSS_TEXT_DECORATION_NONE) { - fprintf(stream, "text-decoration: none "); - } else { - fprintf(stream, "text-decoration:"); - - if (val & CSS_TEXT_DECORATION_BLINK) { - fprintf(stream, " blink"); - } - if (val & CSS_TEXT_DECORATION_LINE_THROUGH) { - fprintf(stream, " line-through"); - } - if (val & CSS_TEXT_DECORATION_OVERLINE) { - fprintf(stream, " overline"); - } - if (val & CSS_TEXT_DECORATION_UNDERLINE) { - fprintf(stream, " underline"); - } - - fprintf(stream, " "); - } - - /* text-indent */ - val = css_computed_text_indent(style, &len1, &unit1); - switch (val) { - case CSS_TEXT_INDENT_SET: - fprintf(stream, "text-indent: "); - - dump_css_unit(stream, len1, unit1); - - fprintf(stream, " "); - break; - default: - break; - } - - /* text-transform */ - val = css_computed_text_transform(style); - switch (val) { - case CSS_TEXT_TRANSFORM_CAPITALIZE: - fprintf(stream, "text-transform: capitalize "); - break; - case CSS_TEXT_TRANSFORM_UPPERCASE: - fprintf(stream, "text-transform: uppercase "); - break; - case CSS_TEXT_TRANSFORM_LOWERCASE: - fprintf(stream, "text-transform: lowercase "); - break; - case CSS_TEXT_TRANSFORM_NONE: - fprintf(stream, "text-transform: none "); - break; - default: - break; - } - - /* top */ - val = css_computed_top(style, &len1, &unit1); - switch (val) { - case CSS_TOP_AUTO: - fprintf(stream, "top: auto "); - break; - case CSS_TOP_SET: - fprintf(stream, "top: "); - - dump_css_unit(stream, len1, unit1); - - fprintf(stream, " "); - break; - default: - break; - } - - /* unicode-bidi */ - val = css_computed_unicode_bidi(style); - switch (val) { - case CSS_UNICODE_BIDI_NORMAL: - fprintf(stream, "unicode-bidi: normal "); - break; - case CSS_UNICODE_BIDI_EMBED: - fprintf(stream, "unicode-bidi: embed "); - break; - case CSS_UNICODE_BIDI_BIDI_OVERRIDE: - fprintf(stream, "unicode-bidi: bidi-override "); - break; - default: - break; - } - - /* vertical-align */ - val = css_computed_vertical_align(style, &len1, &unit1); - switch (val) { - case CSS_VERTICAL_ALIGN_BASELINE: - fprintf(stream, "vertical-align: baseline "); - break; - case CSS_VERTICAL_ALIGN_SUB: - fprintf(stream, "vertical-align: sub "); - break; - case CSS_VERTICAL_ALIGN_SUPER: - fprintf(stream, "vertical-align: super "); - break; - case CSS_VERTICAL_ALIGN_TOP: - fprintf(stream, "vertical-align: top "); - break; - case CSS_VERTICAL_ALIGN_TEXT_TOP: - fprintf(stream, "vertical-align: text-top "); - break; - case CSS_VERTICAL_ALIGN_MIDDLE: - fprintf(stream, "vertical-align: middle "); - break; - case CSS_VERTICAL_ALIGN_BOTTOM: - fprintf(stream, "vertical-align: bottom "); - break; - case CSS_VERTICAL_ALIGN_TEXT_BOTTOM: - fprintf(stream, "vertical-align: text-bottom "); - break; - case CSS_VERTICAL_ALIGN_SET: - fprintf(stream, "vertical-align: "); - - dump_css_unit(stream, len1, unit1); - - fprintf(stream, " "); - break; - default: - break; - } - - /* visibility */ - val = css_computed_visibility(style); - switch (val) { - case CSS_VISIBILITY_VISIBLE: - fprintf(stream, "visibility: visible "); - break; - case CSS_VISIBILITY_HIDDEN: - fprintf(stream, "visibility: hidden "); - break; - case CSS_VISIBILITY_COLLAPSE: - fprintf(stream, "visibility: collapse "); - break; - default: - break; - } - - /* white-space */ - val = css_computed_white_space(style); - switch (val) { - case CSS_WHITE_SPACE_NORMAL: - fprintf(stream, "white-space: normal "); - break; - case CSS_WHITE_SPACE_PRE: - fprintf(stream, "white-space: pre "); - break; - case CSS_WHITE_SPACE_NOWRAP: - fprintf(stream, "white-space: nowrap "); - break; - case CSS_WHITE_SPACE_PRE_WRAP: - fprintf(stream, "white-space: pre-wrap "); - break; - case CSS_WHITE_SPACE_PRE_LINE: - fprintf(stream, "white-space: pre-line "); - break; - default: - break; - } - - /* width */ - val = css_computed_width(style, &len1, &unit1); - switch (val) { - case CSS_WIDTH_AUTO: - fprintf(stream, "width: auto "); - break; - case CSS_WIDTH_SET: - fprintf(stream, "width: "); - - dump_css_unit(stream, len1, unit1); - - fprintf(stream, " "); - break; - default: - break; - } - - /* word-spacing */ - val = css_computed_word_spacing(style, &len1, &unit1); - switch (val) { - case CSS_WORD_SPACING_NORMAL: - fprintf(stream, "word-spacing: normal "); - break; - case CSS_WORD_SPACING_SET: - fprintf(stream, "word-spacing: "); - - dump_css_unit(stream, len1, unit1); - - fprintf(stream, " "); - break; - default: - break; - } - - /* z-index */ - val = css_computed_z_index(style, &zindex); - switch (val) { - case CSS_Z_INDEX_AUTO: - fprintf(stream, "z-index: auto "); - break; - case CSS_Z_INDEX_SET: - fprintf(stream, "z-index: %d ", zindex); - break; - default: - break; - } - - fprintf(stream, "}"); -} - -/****************************************************************************** - * Helper functions for nscss_dump_computed_style * - ******************************************************************************/ - -/** - * Dump a fixed point value to the stream in a textual form. - * - * \param stream Stream to write to - * \param f Value to write - */ -void dump_css_fixed(FILE *stream, css_fixed f) -{ -#define NSCSS_ABS(x) (uint32_t)((x) < 0 ? -(x) : (x)) - uint32_t uintpart = FIXTOINT(NSCSS_ABS(f)); - /* + 500 to ensure round to nearest (division will truncate) */ - uint32_t fracpart = ((NSCSS_ABS(f) & 0x3ff) * 1000 + 500) / (1 << 10); -#undef NSCSS_ABS - - fprintf(stream, "%s%d.%03d", f < 0 ? "-" : "", uintpart, fracpart); -} - -/** - * Dump a numeric value to the stream in a textual form. - * - * \param stream Stream to write to - * \param val Value to write - */ -void dump_css_number(FILE *stream, css_fixed val) -{ - if (INTTOFIX(FIXTOINT(val)) == val) - fprintf(stream, "%d", FIXTOINT(val)); - else - dump_css_fixed(stream, val); -} - -/** - * Dump a dimension to the stream in a textual form. - * - * \param stream Stream to write to - * \param val Value to write - * \param unit Unit to write - */ -void dump_css_unit(FILE *stream, css_fixed val, css_unit unit) -{ - dump_css_number(stream, val); - - switch (unit) { - case CSS_UNIT_PX: - fprintf(stream, "px"); - break; - case CSS_UNIT_EX: - fprintf(stream, "ex"); - break; - case CSS_UNIT_EM: - fprintf(stream, "em"); - break; - case CSS_UNIT_IN: - fprintf(stream, "in"); - break; - case CSS_UNIT_CM: - fprintf(stream, "cm"); - break; - case CSS_UNIT_MM: - fprintf(stream, "mm"); - break; - case CSS_UNIT_PT: - fprintf(stream, "pt"); - break; - case CSS_UNIT_PC: - fprintf(stream, "pc"); - break; - case CSS_UNIT_PCT: - fprintf(stream, "%%"); - break; - case CSS_UNIT_DEG: - fprintf(stream, "deg"); - break; - case CSS_UNIT_GRAD: - fprintf(stream, "grad"); - break; - case CSS_UNIT_RAD: - fprintf(stream, "rad"); - break; - case CSS_UNIT_MS: - fprintf(stream, "ms"); - break; - case CSS_UNIT_S: - fprintf(stream, "s"); - break; - case CSS_UNIT_HZ: - fprintf(stream, "Hz"); - break; - case CSS_UNIT_KHZ: - fprintf(stream, "kHz"); - break; - } -} - diff --git a/css/dump.h b/css/dump.h deleted file mode 100644 index 25d283e9e..000000000 --- a/css/dump.h +++ /dev/null @@ -1,26 +0,0 @@ -/* - * Copyright 2009 John-Mark Bell - * - * 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 . - */ - -#ifndef NETSURF_CSS_DUMP_H_ -#define NETSURF_CSS_DUMP_H_ - -#include "css/css.h" - -void nscss_dump_computed_style(FILE *stream, const css_computed_style *style); - -#endif diff --git a/css/hints.c b/css/hints.c deleted file mode 100644 index 356153983..000000000 --- a/css/hints.c +++ /dev/null @@ -1,1611 +0,0 @@ -/* - * Copyright 2009 John-Mark Bell - * - * 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 . - */ - -#include -#include - -#include "utils/nsoption.h" -#include "utils/corestrings.h" -#include "utils/log.h" -#include "utils/nsurl.h" -#include "utils/utils.h" - -#include "css/hints.h" -#include "css/select.h" - -#define LOG_STATS -#undef LOG_STATS - -/****************************************************************************** - * Utility functions * - ******************************************************************************/ - -/** - * Determine if a given character is whitespace - * - * \param c Character to consider - * \return true if character is whitespace, false otherwise - */ -static bool isWhitespace(char c) -{ - return c == ' ' || c == '\t' || c == '\f' || c == '\r' || c == '\n'; -} - -/** - * Determine if a given character is a valid hex digit - * - * \param c Character to consider - * \return true if character is a valid hex digit, false otherwise - */ -static bool isHex(char c) -{ - return ('0' <= c && c <= '9') || - ('A' <= (c & ~0x20) && (c & ~0x20) <= 'F'); -} - -/** - * Convert a character representing a hex digit to the corresponding hex value - * - * \param c Character to convert - * \return Hex value represented by character - * - * \note This function assumes an ASCII-compatible character set - */ -static uint8_t charToHex(char c) -{ - /* 0-9 */ - c -= '0'; - - /* A-F */ - if (c > 9) - c -= 'A' - '9' - 1; - - /* a-f */ - if (c > 15) - c -= 'a' - 'A'; - - return c; -} - - -/****************************************************************************** - * Common parsing functions * - ******************************************************************************/ - -/** - * Parse a number string - * - * \param data Data to parse (NUL-terminated) - * \param maybe_negative Negative numbers permitted - * \param real Floating point numbers permitted - * \param value Pointer to location to receive numeric value - * \param consumed Pointer to location to receive number of input - * bytes consumed - * \return true on success, false on invalid input - */ -static bool parse_number(const char *data, bool maybe_negative, bool real, - css_fixed *value, size_t *consumed) -{ - size_t len; - const uint8_t *ptr; - int32_t intpart = 0; - int32_t fracpart = 0; - int32_t pwr = 1; - int sign = 1; - - *consumed = 0; - - len = strlen(data); - ptr = (const uint8_t *) data; - - if (len == 0) - return false; - - /* Skip leading whitespace */ - while (len > 0 && isWhitespace(ptr[0])) { - len--; - ptr++; - } - - if (len == 0) - return false; - - /* Extract sign, if any */ - if (ptr[0] == '+') { - len--; - ptr++; - } else if (ptr[0] == '-' && maybe_negative) { - sign = -1; - len--; - ptr++; - } - - if (len == 0) - return false; - - /* Must have a digit [0,9] */ - if ('0' > ptr[0] || ptr[0] > '9') - return false; - - /* Now extract intpart, assuming base 10 */ - while (len > 0) { - /* Stop on first non-digit */ - if (ptr[0] < '0' || '9' < ptr[0]) - break; - - /* Prevent overflow of 'intpart'; proper clamping below */ - if (intpart < (1 << 22)) { - intpart *= 10; - intpart += ptr[0] - '0'; - } - ptr++; - len--; - } - - /* And fracpart, again, assuming base 10 */ - if (real && len > 1 && ptr[0] == '.' && - ('0' <= ptr[1] && ptr[1] <= '9')) { - ptr++; - len--; - - while (len > 0) { - if (ptr[0] < '0' || '9' < ptr[0]) - break; - - if (pwr < 1000000) { - pwr *= 10; - fracpart *= 10; - fracpart += ptr[0] - '0'; - } - ptr++; - len--; - } - - fracpart = ((1 << 10) * fracpart + pwr/2) / pwr; - if (fracpart >= (1 << 10)) { - intpart++; - fracpart &= (1 << 10) - 1; - } - } - - if (sign > 0) { - /* If the result is larger than we can represent, - * then clamp to the maximum value we can store. */ - if (intpart >= (1 << 21)) { - intpart = (1 << 21) - 1; - fracpart = (1 << 10) - 1; - } - } else { - /* If the negated result is smaller than we can represent - * then clamp to the minimum value we can store. */ - if (intpart >= (1 << 21)) { - intpart = -(1 << 21); - fracpart = 0; - } else { - intpart = -intpart; - if (fracpart) { - fracpart = (1 << 10) - fracpart; - intpart--; - } - } - } - - *value = (intpart << 10) | fracpart; - - *consumed = ptr - (const uint8_t *) data; - - return true; -} - -/** - * Parse a dimension string - * - * \param data Data to parse (NUL-terminated) - * \param strict Whether to enforce strict parsing rules - * \param length Pointer to location to receive dimension's length - * \param unit Pointer to location to receive dimension's unit - * \return true on success, false on invalid input - */ -static bool parse_dimension(const char *data, bool strict, css_fixed *length, - css_unit *unit) -{ - size_t len; - size_t read; - css_fixed value; - - len = strlen(data); - - if (parse_number(data, false, true, &value, &read) == false) - return false; - - if (strict && value < INTTOFIX(1)) - return false; - - *length = value; - - if (len > read && data[read] == '%') - *unit = CSS_UNIT_PCT; - else - *unit = CSS_UNIT_PX; - - return true; -} - -/** - * Mapping of colour name to CSS color - */ -struct colour_map { - const char *name; - css_color color; -}; - -/** - * Name comparator for named colour matching - * - * \param a Name to match - * \param b Colour map entry to consider - * \return 0 on match, - * < 0 if a < b, - * > 0 if b > a. - */ -static int cmp_colour_name(const void *a, const void *b) -{ - const char *aa = a; - const struct colour_map *bb = b; - - return strcasecmp(aa, bb->name); -} - -/** - * Parse a named colour - * - * \param name Name to parse - * \param result Pointer to location to receive css_color - * \return true on success, false on invalid input - */ -static bool parse_named_colour(const char *name, css_color *result) -{ - static const struct colour_map named_colours[] = { - { "aliceblue", 0xfff0f8ff }, - { "antiquewhite", 0xfffaebd7 }, - { "aqua", 0xff00ffff }, - { "aquamarine", 0xff7fffd4 }, - { "azure", 0xfff0ffff }, - { "beige", 0xfff5f5dc }, - { "bisque", 0xffffe4c4 }, - { "black", 0xff000000 }, - { "blanchedalmond", 0xffffebcd }, - { "blue", 0xff0000ff }, - { "blueviolet", 0xff8a2be2 }, - { "brown", 0xffa52a2a }, - { "burlywood", 0xffdeb887 }, - { "cadetblue", 0xff5f9ea0 }, - { "chartreuse", 0xff7fff00 }, - { "chocolate", 0xffd2691e }, - { "coral", 0xffff7f50 }, - { "cornflowerblue", 0xff6495ed }, - { "cornsilk", 0xfffff8dc }, - { "crimson", 0xffdc143c }, - { "cyan", 0xff00ffff }, - { "darkblue", 0xff00008b }, - { "darkcyan", 0xff008b8b }, - { "darkgoldenrod", 0xffb8860b }, - { "darkgray", 0xffa9a9a9 }, - { "darkgreen", 0xff006400 }, - { "darkgrey", 0xffa9a9a9 }, - { "darkkhaki", 0xffbdb76b }, - { "darkmagenta", 0xff8b008b }, - { "darkolivegreen", 0xff556b2f }, - { "darkorange", 0xffff8c00 }, - { "darkorchid", 0xff9932cc }, - { "darkred", 0xff8b0000 }, - { "darksalmon", 0xffe9967a }, - { "darkseagreen", 0xff8fbc8f }, - { "darkslateblue", 0xff483d8b }, - { "darkslategray", 0xff2f4f4f }, - { "darkslategrey", 0xff2f4f4f }, - { "darkturquoise", 0xff00ced1 }, - { "darkviolet", 0xff9400d3 }, - { "deeppink", 0xffff1493 }, - { "deepskyblue", 0xff00bfff }, - { "dimgray", 0xff696969 }, - { "dimgrey", 0xff696969 }, - { "dodgerblue", 0xff1e90ff }, - { "feldspar", 0xffd19275 }, - { "firebrick", 0xffb22222 }, - { "floralwhite", 0xfffffaf0 }, - { "forestgreen", 0xff228b22 }, - { "fuchsia", 0xffff00ff }, - { "gainsboro", 0xffdcdcdc }, - { "ghostwhite", 0xfff8f8ff }, - { "gold", 0xffffd700 }, - { "goldenrod", 0xffdaa520 }, - { "gray", 0xff808080 }, - { "green", 0xff008000 }, - { "greenyellow", 0xffadff2f }, - { "grey", 0xff808080 }, - { "honeydew", 0xfff0fff0 }, - { "hotpink", 0xffff69b4 }, - { "indianred", 0xffcd5c5c }, - { "indigo", 0xff4b0082 }, - { "ivory", 0xfffffff0 }, - { "khaki", 0xfff0e68c }, - { "lavender", 0xffe6e6fa }, - { "lavenderblush", 0xfffff0f5 }, - { "lawngreen", 0xff7cfc00 }, - { "lemonchiffon", 0xfffffacd }, - { "lightblue", 0xffadd8e6 }, - { "lightcoral", 0xfff08080 }, - { "lightcyan", 0xffe0ffff }, - { "lightgoldenrodyellow", 0xfffafad2 }, - { "lightgray", 0xffd3d3d3 }, - { "lightgreen", 0xff90ee90 }, - { "lightgrey", 0xffd3d3d3 }, - { "lightpink", 0xffffb6c1 }, - { "lightsalmon", 0xffffa07a }, - { "lightseagreen", 0xff20b2aa }, - { "lightskyblue", 0xff87cefa }, - { "lightslateblue", 0xff8470ff }, - { "lightslategray", 0xff778899 }, - { "lightslategrey", 0xff778899 }, - { "lightsteelblue", 0xffb0c4de }, - { "lightyellow", 0xffffffe0 }, - { "lime", 0xff00ff00 }, - { "limegreen", 0xff32cd32 }, - { "linen", 0xfffaf0e6 }, - { "magenta", 0xffff00ff }, - { "maroon", 0xff800000 }, - { "mediumaquamarine", 0xff66cdaa }, - { "mediumblue", 0xff0000cd }, - { "mediumorchid", 0xffba55d3 }, - { "mediumpurple", 0xff9370db }, - { "mediumseagreen", 0xff3cb371 }, - { "mediumslateblue", 0xff7b68ee }, - { "mediumspringgreen", 0xff00fa9a }, - { "mediumturquoise", 0xff48d1cc }, - { "mediumvioletred", 0xffc71585 }, - { "midnightblue", 0xff191970 }, - { "mintcream", 0xfff5fffa }, - { "mistyrose", 0xffffe4e1 }, - { "moccasin", 0xffffe4b5 }, - { "navajowhite", 0xffffdead }, - { "navy", 0xff000080 }, - { "oldlace", 0xfffdf5e6 }, - { "olive", 0xff808000 }, - { "olivedrab", 0xff6b8e23 }, - { "orange", 0xffffa500 }, - { "orangered", 0xffff4500 }, - { "orchid", 0xffda70d6 }, - { "palegoldenrod", 0xffeee8aa }, - { "palegreen", 0xff98fb98 }, - { "paleturquoise", 0xffafeeee }, - { "palevioletred", 0xffdb7093 }, - { "papayawhip", 0xffffefd5 }, - { "peachpuff", 0xffffdab9 }, - { "peru", 0xffcd853f }, - { "pink", 0xffffc0cb }, - { "plum", 0xffdda0dd }, - { "powderblue", 0xffb0e0e6 }, - { "purple", 0xff800080 }, - { "red", 0xffff0000 }, - { "rosybrown", 0xffbc8f8f }, - { "royalblue", 0xff4169e1 }, - { "saddlebrown", 0xff8b4513 }, - { "salmon", 0xfffa8072 }, - { "sandybrown", 0xfff4a460 }, - { "seagreen", 0xff2e8b57 }, - { "seashell", 0xfffff5ee }, - { "sienna", 0xffa0522d }, - { "silver", 0xffc0c0c0 }, - { "skyblue", 0xff87ceeb }, - { "slateblue", 0xff6a5acd }, - { "slategray", 0xff708090 }, - { "slategrey", 0xff708090 }, - { "snow", 0xfffffafa }, - { "springgreen", 0xff00ff7f }, - { "steelblue", 0xff4682b4 }, - { "tan", 0xffd2b48c }, - { "teal", 0xff008080 }, - { "thistle", 0xffd8bfd8 }, - { "tomato", 0xffff6347 }, - { "turquoise", 0xff40e0d0 }, - { "violet", 0xffee82ee }, - { "violetred", 0xffd02090 }, - { "wheat", 0xfff5deb3 }, - { "white", 0xffffffff }, - { "whitesmoke", 0xfff5f5f5 }, - { "yellow", 0xffffff00 }, - { "yellowgreen", 0xff9acd32 } - }; - const struct colour_map *entry; - - entry = bsearch(name, named_colours, - sizeof(named_colours) / sizeof(named_colours[0]), - sizeof(named_colours[0]), - cmp_colour_name); - - if (entry != NULL) - *result = entry->color; - - return entry != NULL; -} - -/** - * Parser for colours specified in attribute values. - * - * \param data Data to parse (NUL-terminated) - * \param result Pointer to location to receive resulting css_color - * \return true on success, false on invalid input - */ -bool nscss_parse_colour(const char *data, css_color *result) -{ - size_t len = strlen(data); - uint8_t r, g, b; - - /* 2 */ - if (len == 0) - return false; - - /* 3 */ - if (len == SLEN("transparent") && strcasecmp(data, "transparent") == 0) - return false; - - /* 4 */ - if (parse_named_colour(data, result)) - return true; - - /** \todo Implement HTML5's utterly insane legacy colour parsing */ - - if (data[0] == '#') { - data++; - len--; - } - - if (len == 3 && isHex(data[0]) && isHex(data[1]) && isHex(data[2])) { - r = charToHex(data[0]); - g = charToHex(data[1]); - b = charToHex(data[2]); - - r |= (r << 4); - g |= (g << 4); - b |= (b << 4); - - *result = (0xff << 24) | (r << 16) | (g << 8) | b; - - return true; - } else if (len == 6 && isHex(data[0]) && isHex(data[1]) && - isHex(data[2]) && isHex(data[3]) && isHex(data[4]) && - isHex(data[5])) { - r = (charToHex(data[0]) << 4) | charToHex(data[1]); - g = (charToHex(data[2]) << 4) | charToHex(data[3]); - b = (charToHex(data[4]) << 4) | charToHex(data[5]); - - *result = (0xff << 24) | (r << 16) | (g << 8) | b; - - return true; - } - - return false; -} - -/** - * Parse a font \@size attribute - * - * \param size Data to parse (NUL-terminated) - * \param val Pointer to location to receive enum value - * \param len Pointer to location to receive length - * \param unit Pointer to location to receive unit - * \return True on success, false on failure - */ -static bool parse_font_size(const char *size, uint8_t *val, - css_fixed *len, css_unit *unit) -{ - static const uint8_t size_map[] = { - CSS_FONT_SIZE_XX_SMALL, - CSS_FONT_SIZE_SMALL, - CSS_FONT_SIZE_MEDIUM, - CSS_FONT_SIZE_LARGE, - CSS_FONT_SIZE_X_LARGE, - CSS_FONT_SIZE_XX_LARGE, - CSS_FONT_SIZE_DIMENSION /* xxx-large (see below) */ - }; - - const char *p = size; - char mode; - int value = 0; - - /* Skip whitespace */ - while (*p != '\0' && isWhitespace(*p)) - p++; - - mode = *p; - - /* Skip +/- */ - if (mode == '+' || mode == '-') - p++; - - /* Need at least one digit */ - if (*p < '0' || *p > '9') { - return false; - } - - /* Consume digits, computing value */ - while ('0' <= *p && *p <= '9') { - value = value * 10 + (*p - '0'); - p++; - } - - /* Resolve relative sizes */ - if (mode == '+') - value += 3; - else if (mode == '-') - value = 3 - value; - - /* Clamp to range [1,7] */ - if (value < 1) - value = 1; - else if (value > 7) - value = 7; - - if (value == 7) { - /* Manufacture xxx-large */ - *len = FDIV(FMUL(INTTOFIX(3), INTTOFIX(nsoption_int(font_size))), - F_10); - } else { - /* Len is irrelevant */ - *len = 0; - } - - *unit = CSS_UNIT_PT; - *val = size_map[value - 1]; - - return true; -} - - -/****************************************************************************** - * Hint context management * - ******************************************************************************/ - -#define MAX_HINTS_PER_ELEMENT 32 - -struct css_hint_ctx { - struct css_hint *hints; - uint32_t len; -}; - -struct css_hint_ctx hint_ctx; - -nserror css_hint_init(void) -{ - hint_ctx.hints = malloc(sizeof(struct css_hint) * - MAX_HINTS_PER_ELEMENT); - if (hint_ctx.hints == NULL) { - return NSERROR_NOMEM; - } - - return NSERROR_OK; -} - -void css_hint_fini(void) -{ - hint_ctx.len = 0; - free(hint_ctx.hints); -} - -static void css_hint_clean(void) -{ - hint_ctx.len = 0; -} - -static inline struct css_hint * css_hint_advance(struct css_hint *hint) -{ - hint_ctx.len++; - assert(hint_ctx.len < MAX_HINTS_PER_ELEMENT); - - return ++hint; -} - -static void css_hint_get_hints(struct css_hint **hints, uint32_t *nhints) -{ - *hints = hint_ctx.hints; - *nhints = hint_ctx.len; -} - - -/****************************************************************************** - * Presentational hint handlers * - ******************************************************************************/ - -static void css_hint_table_cell_border_padding( - nscss_select_ctx *ctx, - dom_node *node) -{ - struct css_hint *hint = &hint_ctx.hints[hint_ctx.len]; - css_qname qs; - dom_string *attr = NULL; - dom_node *tablenode = NULL; - dom_exception exc; - - qs.ns = NULL; - qs.name = lwc_string_ref(corestring_lwc_table); - if (named_ancestor_node(ctx, node, &qs, - (void *)&tablenode) != CSS_OK) { - /* Didn't find, or had error */ - lwc_string_unref(qs.name); - return; - } - lwc_string_unref(qs.name); - - if (tablenode == NULL) { - return; - } - /* No need to unref tablenode, named_ancestor_node does not - * return a reffed node to the CSS - */ - - exc = dom_element_get_attribute(tablenode, - corestring_dom_border, &attr); - - if (exc == DOM_NO_ERR && attr != NULL) { - uint32_t hint_prop; - css_hint_length hint_length; - - if (parse_dimension( - dom_string_data(attr), false, - &hint_length.value, - &hint_length.unit) && - INTTOFIX(0) != hint_length.value) { - - for (hint_prop = CSS_PROP_BORDER_TOP_STYLE; - hint_prop <= CSS_PROP_BORDER_LEFT_STYLE; - hint_prop++) { - hint->prop = hint_prop; - hint->status = CSS_BORDER_STYLE_INSET; - hint = css_hint_advance(hint); - } - - for (hint_prop = CSS_PROP_BORDER_TOP_WIDTH; - hint_prop <= CSS_PROP_BORDER_LEFT_WIDTH; - hint_prop++) { - hint->prop = hint_prop; - hint->data.length.value = INTTOFIX(1); - hint->data.length.unit = CSS_UNIT_PX; - hint->status = CSS_BORDER_WIDTH_WIDTH; - hint = css_hint_advance(hint); - } - } - dom_string_unref(attr); - } - - exc = dom_element_get_attribute(tablenode, - corestring_dom_bordercolor, &attr); - - if (exc == DOM_NO_ERR && attr != NULL) { - uint32_t hint_prop; - css_color hint_color; - - if (nscss_parse_colour( - (const char *)dom_string_data(attr), - &hint_color)) { - - for (hint_prop = CSS_PROP_BORDER_TOP_COLOR; - hint_prop <= CSS_PROP_BORDER_LEFT_COLOR; - hint_prop++) { - hint->prop = hint_prop; - hint->data.color = hint_color; - hint->status = CSS_BORDER_COLOR_COLOR; - hint = css_hint_advance(hint); - } - } - dom_string_unref(attr); - } - - exc = dom_element_get_attribute(tablenode, - corestring_dom_cellpadding, &attr); - - if (exc == DOM_NO_ERR && attr != NULL) { - uint32_t hint_prop; - css_hint_length hint_length; - - if (parse_dimension( - dom_string_data(attr), false, - &hint_length.value, - &hint_length.unit)) { - - for (hint_prop = CSS_PROP_PADDING_TOP; - hint_prop <= CSS_PROP_PADDING_LEFT; - hint_prop++) { - hint->prop = hint_prop; - hint->data.length.value = hint_length.value; - hint->data.length.unit = hint_length.unit; - hint->status = CSS_PADDING_SET; - hint = css_hint_advance(hint); - } - } - dom_string_unref(attr); - } -} - -static void css_hint_vertical_align_table_cells( - nscss_select_ctx *ctx, - dom_node *node) -{ - struct css_hint *hint = &hint_ctx.hints[hint_ctx.len]; - dom_string *attr = NULL; - dom_exception err; - - err = dom_element_get_attribute(node, - corestring_dom_valign, &attr); - - if (err == DOM_NO_ERR && attr != NULL) { - if (dom_string_caseless_lwc_isequal(attr, - corestring_lwc_top)) { - hint->prop = CSS_PROP_VERTICAL_ALIGN; - hint->status = CSS_VERTICAL_ALIGN_TOP; - hint = css_hint_advance(hint); - - } else if (dom_string_caseless_lwc_isequal(attr, - corestring_lwc_middle)) { - hint->prop = CSS_PROP_VERTICAL_ALIGN; - hint->status = CSS_VERTICAL_ALIGN_MIDDLE; - hint = css_hint_advance(hint); - - } else if (dom_string_caseless_lwc_isequal(attr, - corestring_lwc_bottom)) { - hint->prop = CSS_PROP_VERTICAL_ALIGN; - hint->status = CSS_VERTICAL_ALIGN_BOTTOM; - hint = css_hint_advance(hint); - - } else if (dom_string_caseless_lwc_isequal(attr, - corestring_lwc_baseline)) { - hint->prop = CSS_PROP_VERTICAL_ALIGN; - hint->status = CSS_VERTICAL_ALIGN_BASELINE; - hint = css_hint_advance(hint); - } - dom_string_unref(attr); - } -} - -static void css_hint_vertical_align_replaced( - nscss_select_ctx *ctx, - dom_node *node) -{ - struct css_hint *hint = &hint_ctx.hints[hint_ctx.len]; - dom_string *attr = NULL; - dom_exception err; - - err = dom_element_get_attribute(node, - corestring_dom_valign, &attr); - - if (err == DOM_NO_ERR && attr != NULL) { - if (dom_string_caseless_lwc_isequal(attr, - corestring_lwc_top)) { - hint->prop = CSS_PROP_VERTICAL_ALIGN; - hint->status = CSS_VERTICAL_ALIGN_TOP; - hint = css_hint_advance(hint); - - } else if (dom_string_caseless_lwc_isequal(attr, - corestring_lwc_bottom) || - dom_string_caseless_lwc_isequal(attr, - corestring_lwc_baseline)) { - hint->prop = CSS_PROP_VERTICAL_ALIGN; - hint->status = CSS_VERTICAL_ALIGN_BASELINE; - hint = css_hint_advance(hint); - - } else if (dom_string_caseless_lwc_isequal(attr, - corestring_lwc_texttop)) { - hint->prop = CSS_PROP_VERTICAL_ALIGN; - hint->status = CSS_VERTICAL_ALIGN_TEXT_TOP; - hint = css_hint_advance(hint); - - } else if (dom_string_caseless_lwc_isequal(attr, - corestring_lwc_absmiddle) || - dom_string_caseless_lwc_isequal(attr, - corestring_lwc_abscenter)) { - hint->prop = CSS_PROP_VERTICAL_ALIGN; - hint->status = CSS_VERTICAL_ALIGN_MIDDLE; - hint = css_hint_advance(hint); - } - dom_string_unref(attr); - } -} - -static void css_hint_text_align_normal( - nscss_select_ctx *ctx, - dom_node *node) -{ - struct css_hint *hint = &hint_ctx.hints[hint_ctx.len]; - dom_string *align = NULL; - dom_exception err; - - err = dom_element_get_attribute(node, - corestring_dom_align, &align); - if (err == DOM_NO_ERR && align != NULL) { - if (dom_string_caseless_lwc_isequal(align, - corestring_lwc_left)) { - hint->prop = CSS_PROP_TEXT_ALIGN; - hint->status = CSS_TEXT_ALIGN_LEFT; - hint = css_hint_advance(hint); - - } else if (dom_string_caseless_lwc_isequal(align, - corestring_lwc_center)) { - hint->prop = CSS_PROP_TEXT_ALIGN; - hint->status = CSS_TEXT_ALIGN_CENTER; - hint = css_hint_advance(hint); - - } else if (dom_string_caseless_lwc_isequal(align, - corestring_lwc_right)) { - hint->prop = CSS_PROP_TEXT_ALIGN; - hint->status = CSS_TEXT_ALIGN_RIGHT; - hint = css_hint_advance(hint); - - } else if (dom_string_caseless_lwc_isequal(align, - corestring_lwc_justify)) { - hint->prop = CSS_PROP_TEXT_ALIGN; - hint->status = CSS_TEXT_ALIGN_JUSTIFY; - hint = css_hint_advance(hint); - } - dom_string_unref(align); - } -} - -static void css_hint_text_align_center( - nscss_select_ctx *ctx, - dom_node *node) -{ - struct css_hint *hint = &hint_ctx.hints[hint_ctx.len]; - - hint->prop = CSS_PROP_TEXT_ALIGN; - hint->status = CSS_TEXT_ALIGN_LIBCSS_CENTER; - hint = css_hint_advance(hint); -} - -static void css_hint_margin_left_right_align_center( - nscss_select_ctx *ctx, - dom_node *node) -{ - struct css_hint *hint = &hint_ctx.hints[hint_ctx.len]; - dom_string *attr; - dom_exception exc; - - exc = dom_element_get_attribute(node, - corestring_dom_align, &attr); - - if (exc == DOM_NO_ERR && attr != NULL) { - if (dom_string_caseless_lwc_isequal(attr, - corestring_lwc_center) || - dom_string_caseless_lwc_isequal(attr, - corestring_lwc_abscenter) || - dom_string_caseless_lwc_isequal(attr, - corestring_lwc_middle) || - dom_string_caseless_lwc_isequal(attr, - corestring_lwc_absmiddle)) { - hint->prop = CSS_PROP_MARGIN_LEFT; - hint->status = CSS_MARGIN_AUTO; - hint = css_hint_advance(hint); - - hint->prop = CSS_PROP_MARGIN_RIGHT; - hint->status = CSS_MARGIN_AUTO; - hint = css_hint_advance(hint); - } - dom_string_unref(attr); - } -} - -static void css_hint_text_align_special( - nscss_select_ctx *ctx, - dom_node *node) -{ - struct css_hint *hint = &hint_ctx.hints[hint_ctx.len]; - dom_string *align = NULL; - dom_exception err; - - err = dom_element_get_attribute(node, - corestring_dom_align, &align); - - if (err == DOM_NO_ERR && align != NULL) { - if (dom_string_caseless_lwc_isequal(align, - corestring_lwc_center)) { - hint->prop = CSS_PROP_TEXT_ALIGN; - hint->status = CSS_TEXT_ALIGN_LIBCSS_CENTER; - hint = css_hint_advance(hint); - - } else if (dom_string_caseless_lwc_isequal(align, - corestring_lwc_left)) { - hint->prop = CSS_PROP_TEXT_ALIGN; - hint->status = CSS_TEXT_ALIGN_LIBCSS_LEFT; - hint = css_hint_advance(hint); - - } else if (dom_string_caseless_lwc_isequal(align, - corestring_lwc_right)) { - hint->prop = CSS_PROP_TEXT_ALIGN; - hint->status = CSS_TEXT_ALIGN_LIBCSS_RIGHT; - hint = css_hint_advance(hint); - - } else if (dom_string_caseless_lwc_isequal(align, - corestring_lwc_justify)) { - hint->prop = CSS_PROP_TEXT_ALIGN; - hint->status = CSS_TEXT_ALIGN_JUSTIFY; - hint = css_hint_advance(hint); - } - dom_string_unref(align); - } -} - -static void css_hint_text_align_table_special( - nscss_select_ctx *ctx, - dom_node *node) -{ - struct css_hint *hint = &hint_ctx.hints[hint_ctx.len]; - - hint->prop = CSS_PROP_TEXT_ALIGN; - hint->status = CSS_TEXT_ALIGN_INHERIT_IF_NON_MAGIC; - hint = css_hint_advance(hint); -} - -static void css_hint_margin_hspace_vspace( - nscss_select_ctx *ctx, - dom_node *node) -{ - struct css_hint *hint = &hint_ctx.hints[hint_ctx.len]; - dom_string *attr = NULL; - dom_exception exc; - - exc = dom_element_get_attribute(node, - corestring_dom_vspace, &attr); - - if (exc == DOM_NO_ERR && attr != NULL) { - css_hint_length hint_length; - if (parse_dimension( - dom_string_data(attr), false, - &hint_length.value, - &hint_length.unit)) { - hint->prop = CSS_PROP_MARGIN_TOP; - hint->data.length.value = hint_length.value; - hint->data.length.unit = hint_length.unit; - hint->status = CSS_MARGIN_SET; - hint = css_hint_advance(hint); - - hint->prop = CSS_PROP_MARGIN_BOTTOM; - hint->data.length.value = hint_length.value; - hint->data.length.unit = hint_length.unit; - hint->status = CSS_MARGIN_SET; - hint = css_hint_advance(hint); - } - dom_string_unref(attr); - } - - exc = dom_element_get_attribute(node, - corestring_dom_hspace, &attr); - - if (exc == DOM_NO_ERR && attr != NULL) { - css_hint_length hint_length; - if (parse_dimension( - dom_string_data(attr), false, - &hint_length.value, - &hint_length.unit)) { - hint->prop = CSS_PROP_MARGIN_LEFT; - hint->data.length.value = hint_length.value; - hint->data.length.unit = hint_length.unit; - hint->status = CSS_MARGIN_SET; - hint = css_hint_advance(hint); - - hint->prop = CSS_PROP_MARGIN_RIGHT; - hint->data.length.value = hint_length.value; - hint->data.length.unit = hint_length.unit; - hint->status = CSS_MARGIN_SET; - hint = css_hint_advance(hint); - } - dom_string_unref(attr); - } -} - -static void css_hint_margin_left_right_hr( - nscss_select_ctx *ctx, - dom_node *node) -{ - struct css_hint *hint = &hint_ctx.hints[hint_ctx.len]; - dom_string *attr; - dom_exception exc; - - exc = dom_element_get_attribute(node, - corestring_dom_align, &attr); - - if (exc == DOM_NO_ERR && attr != NULL) { - if (dom_string_caseless_lwc_isequal(attr, - corestring_lwc_left)) { - hint->prop = CSS_PROP_MARGIN_LEFT; - hint->data.length.value = 0; - hint->data.length.unit = CSS_UNIT_PX; - hint->status = CSS_MARGIN_SET; - hint = css_hint_advance(hint); - - hint->prop = CSS_PROP_MARGIN_RIGHT; - hint->status = CSS_MARGIN_AUTO; - hint = css_hint_advance(hint); - - } else if (dom_string_caseless_lwc_isequal(attr, - corestring_lwc_center)) { - hint->prop = CSS_PROP_MARGIN_LEFT; - hint->status = CSS_MARGIN_AUTO; - hint = css_hint_advance(hint); - - hint->prop = CSS_PROP_MARGIN_RIGHT; - hint->status = CSS_MARGIN_AUTO; - hint = css_hint_advance(hint); - - } else if (dom_string_caseless_lwc_isequal(attr, - corestring_lwc_right)) { - hint->prop = CSS_PROP_MARGIN_LEFT; - hint->status = CSS_MARGIN_AUTO; - hint = css_hint_advance(hint); - - hint->prop = CSS_PROP_MARGIN_RIGHT; - hint->data.length.value = 0; - hint->data.length.unit = CSS_UNIT_PX; - hint->status = CSS_MARGIN_SET; - hint = css_hint_advance(hint); - } - dom_string_unref(attr); - } -} - -static void css_hint_table_spacing_border( - nscss_select_ctx *ctx, - dom_node *node) -{ - struct css_hint *hint = &hint_ctx.hints[hint_ctx.len]; - dom_exception exc; - dom_string *attr = NULL; - - exc = dom_element_get_attribute(node, corestring_dom_border, &attr); - - if (exc == DOM_NO_ERR && attr != NULL) { - uint32_t hint_prop; - css_hint_length hint_length; - - for (hint_prop = CSS_PROP_BORDER_TOP_STYLE; - hint_prop <= CSS_PROP_BORDER_LEFT_STYLE; - hint_prop++) { - hint->prop = hint_prop; - hint->status = CSS_BORDER_STYLE_OUTSET; - hint = css_hint_advance(hint); - } - - if (parse_dimension( - dom_string_data(attr), false, - &hint_length.value, - &hint_length.unit)) { - - for (hint_prop = CSS_PROP_BORDER_TOP_WIDTH; - hint_prop <= CSS_PROP_BORDER_LEFT_WIDTH; - hint_prop++) { - hint->prop = hint_prop; - hint->data.length.value = hint_length.value; - hint->data.length.unit = hint_length.unit; - hint->status = CSS_BORDER_WIDTH_WIDTH; - hint = css_hint_advance(hint); - } - } - dom_string_unref(attr); - } - - exc = dom_element_get_attribute(node, - corestring_dom_bordercolor, &attr); - - if (exc == DOM_NO_ERR && attr != NULL) { - uint32_t hint_prop; - css_color hint_color; - - if (nscss_parse_colour( - (const char *)dom_string_data(attr), - &hint_color)) { - - for (hint_prop = CSS_PROP_BORDER_TOP_COLOR; - hint_prop <= CSS_PROP_BORDER_LEFT_COLOR; - hint_prop++) { - hint->prop = hint_prop; - hint->data.color = hint_color; - hint->status = CSS_BORDER_COLOR_COLOR; - hint = css_hint_advance(hint); - } - } - dom_string_unref(attr); - } - - exc = dom_element_get_attribute(node, - corestring_dom_cellspacing, &attr); - - if (exc == DOM_NO_ERR && attr != NULL) { - if (parse_dimension( - (const char *)dom_string_data(attr), false, - &hint->data.position.h.value, - &hint->data.position.h.unit)) { - hint->prop = CSS_PROP_BORDER_SPACING; - hint->data.position.v = hint->data.position.h; - hint->status = CSS_BORDER_SPACING_SET; - hint = css_hint_advance(hint); - } - dom_string_unref(attr); - } -} - -static void css_hint_height( - nscss_select_ctx *ctx, - dom_node *node) -{ - struct css_hint *hint = &hint_ctx.hints[hint_ctx.len]; - dom_string *attr = NULL; - dom_exception err; - - err = dom_element_get_attribute(node, - corestring_dom_height, &attr); - - if (err == DOM_NO_ERR && attr != NULL) { - if (parse_dimension( - (const char *)dom_string_data(attr), false, - &hint->data.length.value, - &hint->data.length.unit)) { - hint->prop = CSS_PROP_HEIGHT; - hint->status = CSS_HEIGHT_SET; - hint = css_hint_advance(hint); - } - dom_string_unref(attr); - } -} - -static void css_hint_width( - nscss_select_ctx *ctx, - dom_node *node) -{ - struct css_hint *hint = &hint_ctx.hints[hint_ctx.len]; - dom_string *attr = NULL; - dom_exception err; - - err = dom_element_get_attribute(node, - corestring_dom_width, &attr); - - if (err == DOM_NO_ERR && attr != NULL) { - if (parse_dimension( - (const char *)dom_string_data(attr), false, - &hint->data.length.value, - &hint->data.length.unit)) { - hint->prop = CSS_PROP_WIDTH; - hint->status = CSS_WIDTH_SET; - hint = css_hint_advance(hint); - } - dom_string_unref(attr); - } -} - -static void css_hint_height_width_textarea( - nscss_select_ctx *ctx, - dom_node *node) -{ - struct css_hint *hint = &hint_ctx.hints[hint_ctx.len]; - dom_string *attr = NULL; - dom_exception err; - - err = dom_element_get_attribute(node, - corestring_dom_rows, &attr); - - if (err == DOM_NO_ERR && attr != NULL) { - if (parse_dimension( - (const char *)dom_string_data(attr), false, - &hint->data.length.value, - &hint->data.length.unit)) { - hint->prop = CSS_PROP_HEIGHT; - hint->data.length.unit = CSS_UNIT_EM; - hint->status = CSS_HEIGHT_SET; - hint = css_hint_advance(hint); - } - dom_string_unref(attr); - } - - err = dom_element_get_attribute(node, - corestring_dom_cols, &attr); - - if (err == DOM_NO_ERR && attr != NULL) { - if (parse_dimension( - (const char *)dom_string_data(attr), false, - &hint->data.length.value, - &hint->data.length.unit)) { - hint->prop = CSS_PROP_WIDTH; - hint->data.length.unit = CSS_UNIT_EX; - hint->status = CSS_WIDTH_SET; - hint = css_hint_advance(hint); - } - dom_string_unref(attr); - } -} - -static void css_hint_width_input( - nscss_select_ctx *ctx, - dom_node *node) -{ - struct css_hint *hint = &(hint_ctx.hints[hint_ctx.len]); - dom_string *attr = NULL; - dom_exception err; - - err = dom_element_get_attribute(node, - corestring_dom_size, &attr); - - if (err == DOM_NO_ERR && attr != NULL) { - if (parse_dimension( - (const char *)dom_string_data(attr), false, - &hint->data.length.value, - &hint->data.length.unit)) { - dom_string *attr2 = NULL; - - err = dom_element_get_attribute(node, - corestring_dom_type, &attr2); - if (err == DOM_NO_ERR) { - - hint->prop = CSS_PROP_WIDTH; - hint->status = CSS_WIDTH_SET; - - if (attr2 == NULL || - dom_string_caseless_lwc_isequal( - attr2, - corestring_lwc_text) || - dom_string_caseless_lwc_isequal( - attr2, - corestring_lwc_search) || - dom_string_caseless_lwc_isequal( - attr2, - corestring_lwc_password) || - dom_string_caseless_lwc_isequal( - attr2, - corestring_lwc_file)) { - hint->data.length.unit = CSS_UNIT_EX; - } - if (attr2 != NULL) { - dom_string_unref(attr2); - } - hint = css_hint_advance(hint); - } - } - dom_string_unref(attr); - } -} - -static void css_hint_anchor_color( - nscss_select_ctx *ctx, - dom_node *node) -{ - struct css_hint *hint = &hint_ctx.hints[hint_ctx.len]; - css_error error; - dom_exception err; - dom_string *color; - dom_node *bodynode = NULL; - - /* find body node */ - css_qname qs; - bool is_visited; - - qs.ns = NULL; - qs.name = lwc_string_ref(corestring_lwc_body); - if (named_ancestor_node(ctx, node, &qs, - (void *)&bodynode) != CSS_OK) { - /* Didn't find, or had error */ - lwc_string_unref(qs.name); - return ; - } - lwc_string_unref(qs.name); - - if (bodynode == NULL) { - return; - } - - error = node_is_visited(ctx, node, &is_visited); - if (error != CSS_OK) - return; - - if (is_visited) { - err = dom_element_get_attribute(bodynode, - corestring_dom_vlink, &color); - } else { - err = dom_element_get_attribute(bodynode, - corestring_dom_link, &color); - } - - if (err == DOM_NO_ERR && color != NULL) { - if (nscss_parse_colour( - (const char *)dom_string_data(color), - &hint->data.color)) { - hint->prop = CSS_PROP_COLOR; - hint->status = CSS_COLOR_COLOR; - hint = css_hint_advance(hint); - } - dom_string_unref(color); - } -} - -static void css_hint_body_color( - nscss_select_ctx *ctx, - dom_node *node) -{ - struct css_hint *hint = &hint_ctx.hints[hint_ctx.len]; - dom_exception err; - dom_string *color; - - err = dom_element_get_attribute(node, corestring_dom_text, &color); - - if (err == DOM_NO_ERR && color != NULL) { - if (nscss_parse_colour( - (const char *)dom_string_data(color), - &hint->data.color)) { - hint->prop = CSS_PROP_COLOR; - hint->status = CSS_COLOR_COLOR; - hint = css_hint_advance(hint); - } - dom_string_unref(color); - } -} - -static void css_hint_color( - nscss_select_ctx *ctx, - dom_node *node) -{ - struct css_hint *hint = &hint_ctx.hints[hint_ctx.len]; - dom_exception err; - dom_string *color; - - err = dom_element_get_attribute(node, corestring_dom_color, &color); - - if (err == DOM_NO_ERR && color != NULL) { - if (nscss_parse_colour( - (const char *)dom_string_data(color), - &hint->data.color)) { - hint->prop = CSS_PROP_COLOR; - hint->status = CSS_COLOR_COLOR; - hint = css_hint_advance(hint); - } - dom_string_unref(color); - } -} - -static void css_hint_font_size( - nscss_select_ctx *ctx, - dom_node *node) -{ - struct css_hint *hint = &hint_ctx.hints[hint_ctx.len]; - dom_exception err; - dom_string *size; - - err = dom_element_get_attribute(node, corestring_dom_size, &size); - if (err == DOM_NO_ERR && size != NULL) { - if (parse_font_size( - (const char *)dom_string_data(size), - &hint->status, - &hint->data.length.value, - &hint->data.length.unit)) { - hint->prop = CSS_PROP_FONT_SIZE; - hint = css_hint_advance(hint); - } - dom_string_unref(size); - } -} - -static void css_hint_float( - nscss_select_ctx *ctx, - dom_node *node) -{ - struct css_hint *hint = &hint_ctx.hints[hint_ctx.len]; - dom_exception err; - dom_string *align; - - err = dom_element_get_attribute(node, corestring_dom_align, &align); - if (err == DOM_NO_ERR && align != NULL) { - if (dom_string_caseless_lwc_isequal(align, - corestring_lwc_left)) { - hint->prop = CSS_PROP_FLOAT; - hint->status = CSS_FLOAT_LEFT; - hint = css_hint_advance(hint); - - } else if (dom_string_caseless_lwc_isequal(align, - corestring_lwc_right)) { - hint->prop = CSS_PROP_FLOAT; - hint->status = CSS_FLOAT_RIGHT; - hint = css_hint_advance(hint); - } - dom_string_unref(align); - } -} - -static void css_hint_caption_side( - nscss_select_ctx *ctx, - dom_node *node) -{ - struct css_hint *hint = &hint_ctx.hints[hint_ctx.len]; - dom_exception err; - dom_string *align = NULL; - - err = dom_element_get_attribute(node, corestring_dom_align, &align); - if (err == DOM_NO_ERR && align != NULL) { - if (dom_string_caseless_lwc_isequal(align, - corestring_lwc_bottom)) { - hint->prop = CSS_PROP_CAPTION_SIDE; - hint->status = CSS_CAPTION_SIDE_BOTTOM; - hint = css_hint_advance(hint); - } - dom_string_unref(align); - } -} - -static void css_hint_bg_color( - nscss_select_ctx *ctx, - dom_node *node) -{ - struct css_hint *hint = &hint_ctx.hints[hint_ctx.len]; - dom_exception err; - dom_string *bgcolor; - - err = dom_element_get_attribute(node, - corestring_dom_bgcolor, &bgcolor); - if (err == DOM_NO_ERR && bgcolor != NULL) { - if (nscss_parse_colour( - (const char *)dom_string_data(bgcolor), - &hint->data.color)) { - hint->prop = CSS_PROP_BACKGROUND_COLOR; - hint->status = CSS_BACKGROUND_COLOR_COLOR; - hint = css_hint_advance(hint); - } - dom_string_unref(bgcolor); - } -} - -static void css_hint_bg_image( - nscss_select_ctx *ctx, - dom_node *node) -{ - struct css_hint *hint = &(hint_ctx.hints[hint_ctx.len]); - dom_exception err; - dom_string *attr; - - err = dom_element_get_attribute(node, - corestring_dom_background, &attr); - if (err == DOM_NO_ERR && attr != NULL) { - nsurl *url; - nserror error = nsurl_join(ctx->base_url, - (const char *)dom_string_data(attr), &url); - dom_string_unref(attr); - - if (error == NSERROR_OK) { - lwc_string *iurl; - lwc_error lerror = lwc_intern_string(nsurl_access(url), - nsurl_length(url), &iurl); - nsurl_unref(url); - - if (lerror == lwc_error_ok) { - hint->prop = CSS_PROP_BACKGROUND_IMAGE; - hint->data.string = iurl; - hint->status = CSS_BACKGROUND_IMAGE_IMAGE; - hint = css_hint_advance(hint); - } - } - } -} - - -/* Exported function, documeted in css/hints.h */ -css_error node_presentational_hint(void *pw, void *node, - uint32_t *nhints, css_hint **hints) -{ - dom_exception exc; - dom_html_element_type tag_type; - - css_hint_clean(); - - exc = dom_html_element_get_tag_type(node, &tag_type); - if (exc != DOM_NO_ERR) { - tag_type = DOM_HTML_ELEMENT_TYPE__UNKNOWN; - } - - switch (tag_type) { - case DOM_HTML_ELEMENT_TYPE_TH: - case DOM_HTML_ELEMENT_TYPE_TD: - css_hint_width(pw, node); - css_hint_table_cell_border_padding(pw, node); - /* fallthrough */ - case DOM_HTML_ELEMENT_TYPE_TR: - css_hint_height(pw, node); - /* fallthrough */ - case DOM_HTML_ELEMENT_TYPE_THEAD: - case DOM_HTML_ELEMENT_TYPE_TBODY: - case DOM_HTML_ELEMENT_TYPE_TFOOT: - css_hint_text_align_special(pw, node); - /* fallthrough */ - case DOM_HTML_ELEMENT_TYPE_COL: - css_hint_vertical_align_table_cells(pw, node); - break; - case DOM_HTML_ELEMENT_TYPE_APPLET: - case DOM_HTML_ELEMENT_TYPE_IMG: - css_hint_margin_hspace_vspace(pw, node); - /* fallthrough */ - case DOM_HTML_ELEMENT_TYPE_EMBED: - case DOM_HTML_ELEMENT_TYPE_IFRAME: - case DOM_HTML_ELEMENT_TYPE_OBJECT: - css_hint_height(pw, node); - css_hint_width(pw, node); - css_hint_vertical_align_replaced(pw, node); - css_hint_float(pw, node); - break; - case DOM_HTML_ELEMENT_TYPE_P: - case DOM_HTML_ELEMENT_TYPE_H1: - case DOM_HTML_ELEMENT_TYPE_H2: - case DOM_HTML_ELEMENT_TYPE_H3: - case DOM_HTML_ELEMENT_TYPE_H4: - case DOM_HTML_ELEMENT_TYPE_H5: - case DOM_HTML_ELEMENT_TYPE_H6: - css_hint_text_align_normal(pw, node); - break; - case DOM_HTML_ELEMENT_TYPE_CENTER: - css_hint_text_align_center(pw, node); - break; - case DOM_HTML_ELEMENT_TYPE_CAPTION: - css_hint_caption_side(pw, node); - /* fallthrough */ - case DOM_HTML_ELEMENT_TYPE_DIV: - css_hint_text_align_special(pw, node); - break; - case DOM_HTML_ELEMENT_TYPE_TABLE: - css_hint_text_align_table_special(pw, node); - css_hint_table_spacing_border(pw, node); - css_hint_float(pw, node); - css_hint_margin_left_right_align_center(pw, node); - css_hint_width(pw, node); - break; - case DOM_HTML_ELEMENT_TYPE_HR: - css_hint_margin_left_right_hr(pw, node); - break; - case DOM_HTML_ELEMENT_TYPE_TEXTAREA: - css_hint_height_width_textarea(pw, node); - break; - case DOM_HTML_ELEMENT_TYPE_INPUT: - css_hint_width_input(pw, node); - break; - case DOM_HTML_ELEMENT_TYPE_A: - css_hint_anchor_color(pw, node); - break; - case DOM_HTML_ELEMENT_TYPE_FONT: - css_hint_font_size(pw, node); - break; - case DOM_HTML_ELEMENT_TYPE_BODY: - css_hint_body_color(pw, node); - break; - default: - break; - } - - if (tag_type != DOM_HTML_ELEMENT_TYPE__UNKNOWN) { - css_hint_color(pw, node); - css_hint_bg_color(pw, node); - css_hint_bg_image(pw, node); - } - -#ifdef LOG_STATS - LOG("Properties with hints: %i", hint_ctx.len); -#endif - - css_hint_get_hints(hints, nhints); - - return CSS_OK; -} - diff --git a/css/hints.h b/css/hints.h deleted file mode 100644 index fda1bec7e..000000000 --- a/css/hints.h +++ /dev/null @@ -1,49 +0,0 @@ -/* - * Copyright 2009 John-Mark Bell - * - * 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 . - */ - -#ifndef NETSURF_CSS_HINTS_H_ -#define NETSURF_CSS_HINTS_H_ - -#include - -#include "css/css.h" - -nserror css_hint_init(void); -void css_hint_fini(void); - - -/** - * Callback to retrieve presentational hints for a node - * - * \param[in] pw HTML document - * \param[in] node DOM node - * \param[out] nhints number of hints retrived - * \param[out] hints retrived hints - * \return CSS_OK on success, - * CSS_PROPERTY_NOT_SET if there is no hint for the requested property, - * CSS_NOMEM on memory exhaustion. - */ -css_error node_presentational_hint( - void *pw, - void *node, - uint32_t *nhints, - css_hint **hints); - -bool nscss_parse_colour(const char *data, css_color *result); - -#endif diff --git a/css/internal.c b/css/internal.c deleted file mode 100644 index 46c529b03..000000000 --- a/css/internal.c +++ /dev/null @@ -1,73 +0,0 @@ -/* - * Copyright 2009 John-Mark Bell - * - * 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 . - */ - -#include - -#include "css/internal.h" - -#include "utils/nsurl.h" - -/** - * URL resolution callback for libcss - * - * \param pw Resolution context - * \param base Base URI - * \param rel Relative URL - * \param abs Pointer to location to receive resolved URL - * \return CSS_OK on success, - * CSS_NOMEM on memory exhaustion, - * CSS_INVALID if resolution failed. - */ -css_error nscss_resolve_url(void *pw, const char *base, - lwc_string *rel, lwc_string **abs) -{ - lwc_error lerror; - nserror error; - nsurl *nsbase; - nsurl *nsabs; - - /* Create nsurl from base */ - /* TODO: avoid this */ - error = nsurl_create(base, &nsbase); - if (error != NSERROR_OK) { - return error == NSERROR_NOMEM ? CSS_NOMEM : CSS_INVALID; - } - - /* Resolve URI */ - error = nsurl_join(nsbase, lwc_string_data(rel), &nsabs); - if (error != NSERROR_OK) { - nsurl_unref(nsbase); - return error == NSERROR_NOMEM ? CSS_NOMEM : CSS_INVALID; - } - - nsurl_unref(nsbase); - - /* Intern it */ - lerror = lwc_intern_string(nsurl_access(nsabs), - nsurl_length(nsabs), abs); - if (lerror != lwc_error_ok) { - *abs = NULL; - nsurl_unref(nsabs); - return lerror == lwc_error_oom ? CSS_NOMEM : CSS_INVALID; - } - - nsurl_unref(nsabs); - - return CSS_OK; -} - diff --git a/css/internal.h b/css/internal.h deleted file mode 100644 index 0344d6b32..000000000 --- a/css/internal.h +++ /dev/null @@ -1,27 +0,0 @@ -/* - * Copyright 2009 John-Mark Bell - * - * 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 . - */ - -#ifndef NETSURF_CSS_INTERNAL_H_ -#define NETSURF_CSS_INTERNAL_H_ - -#include "css/css.h" - -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 deleted file mode 100644 index a929cf10a..000000000 --- a/css/select.c +++ /dev/null @@ -1,1854 +0,0 @@ -/* - * Copyright 2009 John-Mark Bell - * - * 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 . - */ - -#include -#include -#include - -#include "content/urldb.h" -#include "desktop/system_colour.h" -#include "utils/nsoption.h" -#include "utils/corestrings.h" -#include "utils/log.h" - -#include "css/internal.h" -#include "css/hints.h" -#include "css/select.h" - -static css_error node_name(void *pw, void *node, css_qname *qname); -static css_error node_classes(void *pw, void *node, - lwc_string ***classes, uint32_t *n_classes); -static css_error node_id(void *pw, void *node, lwc_string **id); -static css_error named_parent_node(void *pw, void *node, - const css_qname *qname, void **parent); -static css_error named_sibling_node(void *pw, void *node, - const css_qname *qname, void **sibling); -static css_error named_generic_sibling_node(void *pw, void *node, - const css_qname *qname, void **sibling); -static css_error parent_node(void *pw, void *node, void **parent); -static css_error sibling_node(void *pw, void *node, void **sibling); -static css_error node_has_name(void *pw, void *node, - const css_qname *qname, bool *match); -static css_error node_has_class(void *pw, void *node, - lwc_string *name, bool *match); -static css_error node_has_id(void *pw, void *node, - lwc_string *name, bool *match); -static css_error node_has_attribute(void *pw, void *node, - const css_qname *qname, bool *match); -static css_error node_has_attribute_equal(void *pw, void *node, - const css_qname *qname, lwc_string *value, - bool *match); -static css_error node_has_attribute_dashmatch(void *pw, void *node, - const css_qname *qname, lwc_string *value, - bool *match); -static css_error node_has_attribute_includes(void *pw, void *node, - const css_qname *qname, lwc_string *value, - bool *match); -static css_error node_has_attribute_prefix(void *pw, void *node, - const css_qname *qname, lwc_string *value, - bool *match); -static css_error node_has_attribute_suffix(void *pw, void *node, - const css_qname *qname, lwc_string *value, - bool *match); -static css_error node_has_attribute_substring(void *pw, void *node, - const css_qname *qname, lwc_string *value, - bool *match); -static css_error node_is_root(void *pw, void *node, bool *match); -static css_error node_count_siblings(void *pw, void *node, - bool same_name, bool after, int32_t *count); -static css_error node_is_empty(void *pw, void *node, bool *match); -static css_error node_is_link(void *pw, void *node, bool *match); -static css_error node_is_hover(void *pw, void *node, bool *match); -static css_error node_is_active(void *pw, void *node, bool *match); -static css_error node_is_focus(void *pw, void *node, bool *match); -static css_error node_is_enabled(void *pw, void *node, bool *match); -static css_error node_is_disabled(void *pw, void *node, bool *match); -static css_error node_is_checked(void *pw, void *node, bool *match); -static css_error node_is_target(void *pw, void *node, bool *match); -static css_error node_is_lang(void *pw, void *node, - lwc_string *lang, bool *match); -static css_error ua_default_for_property(void *pw, uint32_t property, - css_hint *hint); -static css_error set_libcss_node_data(void *pw, void *node, - void *libcss_node_data); -static css_error get_libcss_node_data(void *pw, void *node, - void **libcss_node_data); - -static css_error nscss_compute_font_size(void *pw, const css_hint *parent, - css_hint *size); - - -/** - * Selection callback table for libcss - */ -static css_select_handler selection_handler = { - CSS_SELECT_HANDLER_VERSION_1, - - node_name, - node_classes, - node_id, - named_ancestor_node, - named_parent_node, - named_sibling_node, - named_generic_sibling_node, - parent_node, - sibling_node, - node_has_name, - node_has_class, - node_has_id, - node_has_attribute, - node_has_attribute_equal, - node_has_attribute_dashmatch, - node_has_attribute_includes, - node_has_attribute_prefix, - node_has_attribute_suffix, - node_has_attribute_substring, - node_is_root, - node_count_siblings, - node_is_empty, - node_is_link, - node_is_visited, - node_is_hover, - node_is_active, - node_is_focus, - node_is_enabled, - node_is_disabled, - node_is_checked, - node_is_target, - node_is_lang, - node_presentational_hint, - ua_default_for_property, - nscss_compute_font_size, - set_libcss_node_data, - get_libcss_node_data -}; - -/** - * Create an inline style - * - * \param data Source data - * \param len Length of data in bytes - * \param charset Charset of data, or NULL if unknown - * \param url Base URL of document containing data - * \param allow_quirks True to permit CSS parsing quirks - * \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) -{ - css_stylesheet_params params; - css_stylesheet *sheet; - css_error error; - - params.params_version = CSS_STYLESHEET_PARAMS_VERSION_1; - params.level = CSS_LEVEL_DEFAULT; - params.charset = charset; - params.url = url; - params.title = NULL; - params.allow_quirks = allow_quirks; - params.inline_style = true; - params.resolve = nscss_resolve_url; - params.resolve_pw = NULL; - params.import = NULL; - params.import_pw = NULL; - params.color = ns_system_colour; - params.color_pw = NULL; - params.font = NULL; - params.font_pw = NULL; - - error = css_stylesheet_create(¶ms, &sheet); - if (error != CSS_OK) { - LOG("Failed creating sheet: %d", error); - return NULL; - } - - error = css_stylesheet_append_data(sheet, data, len); - if (error != CSS_OK && error != CSS_NEEDDATA) { - LOG("failed appending data: %d", error); - css_stylesheet_destroy(sheet); - return NULL; - } - - error = css_stylesheet_data_done(sheet); - if (error != CSS_OK) { - LOG("failed completing parse: %d", error); - css_stylesheet_destroy(sheet); - return NULL; - } - - return sheet; -} - -/* Handler for libcss_node_data, stored as libdom node user data */ -static void nscss_dom_user_data_handler(dom_node_operation operation, - dom_string *key, void *data, struct dom_node *src, - struct dom_node *dst) -{ - css_error error; - - if (dom_string_isequal(corestring_dom___ns_key_libcss_node_data, - key) == false || data == NULL) { - return; - } - - switch (operation) { - case DOM_NODE_CLONED: - error = css_libcss_node_data_handler(&selection_handler, - CSS_NODE_CLONED, - NULL, src, dst, data); - if (error != CSS_OK) - LOG("Failed to clone libcss_node_data."); - break; - - case DOM_NODE_RENAMED: - error = css_libcss_node_data_handler(&selection_handler, - CSS_NODE_MODIFIED, - NULL, src, NULL, data); - if (error != CSS_OK) - LOG("Failed to update libcss_node_data."); - break; - - case DOM_NODE_IMPORTED: - case DOM_NODE_ADOPTED: - case DOM_NODE_DELETED: - error = css_libcss_node_data_handler(&selection_handler, - CSS_NODE_DELETED, - NULL, src, NULL, data); - if (error != CSS_OK) - LOG("Failed to delete libcss_node_data."); - break; - - default: - LOG("User data operation not handled."); - assert(0); - } -} - -/** - * Get style selection results for an element - * - * \param ctx CSS selection context - * \param n Element to select for - * \param media Permitted media types - * \param inline_style Inline style associated with element, or NULL - * \return Pointer to selection results (containing computed styles), - * or NULL on failure - */ -css_select_results *nscss_get_style(nscss_select_ctx *ctx, dom_node *n, - uint64_t media, const css_stylesheet *inline_style) -{ - css_select_results *styles; - int pseudo_element; - css_error error; - - /* Select style for node */ - error = css_select_style(ctx->ctx, n, media, inline_style, - &selection_handler, ctx, &styles); - - if (error != CSS_OK || styles == NULL) { - /* Failed selecting partial style -- bail out */ - return NULL; - } - - /* If there's a parent style, compose with partial to obtain - * complete computed style for element */ - if (ctx->parent_style != NULL) { - /* Complete the computed style, by composing with the parent - * element's style */ - error = css_computed_style_compose(ctx->parent_style, - styles->styles[CSS_PSEUDO_ELEMENT_NONE], - nscss_compute_font_size, NULL, - styles->styles[CSS_PSEUDO_ELEMENT_NONE]); - if (error != CSS_OK) { - css_select_results_destroy(styles); - return NULL; - } - } - - for (pseudo_element = CSS_PSEUDO_ELEMENT_NONE + 1; - pseudo_element < CSS_PSEUDO_ELEMENT_COUNT; - pseudo_element++) { - - if (pseudo_element == CSS_PSEUDO_ELEMENT_FIRST_LETTER || - pseudo_element == CSS_PSEUDO_ELEMENT_FIRST_LINE) - /* TODO: Handle first-line and first-letter pseudo - * element computed style completion */ - continue; - - if (styles->styles[pseudo_element] == NULL) - /* There were no rules concerning this pseudo element */ - continue; - - /* Complete the pseudo element's computed style, by composing - * with the base element's style */ - error = css_computed_style_compose( - styles->styles[CSS_PSEUDO_ELEMENT_NONE], - styles->styles[pseudo_element], - nscss_compute_font_size, NULL, - styles->styles[pseudo_element]); - if (error != CSS_OK) { - /* TODO: perhaps this shouldn't be quite so - * catastrophic? */ - css_select_results_destroy(styles); - return NULL; - } - } - - return styles; -} - -/** - * Get an initial style - * - * \param ctx CSS selection context - * \return Pointer to partial computed style, or NULL on failure - */ -static css_computed_style *nscss_get_initial_style(nscss_select_ctx *ctx) -{ - css_computed_style *style; - css_error error; - - error = css_computed_style_create(&style); - if (error != CSS_OK) - return NULL; - - error = css_computed_style_initialise(style, &selection_handler, ctx); - if (error != CSS_OK) { - css_computed_style_destroy(style); - return NULL; - } - - return style; -} - -/** - * Get a blank style - * - * \param ctx CSS selection context - * \param parent Parent style to cascade inherited properties from - * \return Pointer to blank style, or NULL on failure - */ -css_computed_style *nscss_get_blank_style(nscss_select_ctx *ctx, - const css_computed_style *parent) -{ - css_computed_style *partial; - css_error error; - - partial = nscss_get_initial_style(ctx); - if (partial == NULL) - return NULL; - - error = css_computed_style_compose(parent, partial, - nscss_compute_font_size, NULL, partial); - if (error != CSS_OK) { - css_computed_style_destroy(partial); - return NULL; - } - - return partial; -} - -/** - * Font size computation callback for libcss - * - * \param pw Computation context - * \param parent Parent font size (absolute) - * \param size Font size to compute - * \return CSS_OK on success - * - * \post \a size will be an absolute font size - */ -css_error nscss_compute_font_size(void *pw, const css_hint *parent, - css_hint *size) -{ - /** - * Table of font-size keyword scale factors - * - * These are multiplied by the configured default font size - * to produce an absolute size for the relevant keyword - */ - static const css_fixed factors[] = { - FLTTOFIX(0.5625), /* xx-small */ - FLTTOFIX(0.6250), /* x-small */ - FLTTOFIX(0.8125), /* small */ - FLTTOFIX(1.0000), /* medium */ - FLTTOFIX(1.1250), /* large */ - FLTTOFIX(1.5000), /* x-large */ - FLTTOFIX(2.0000) /* xx-large */ - }; - css_hint_length parent_size; - - /* Grab parent size, defaulting to medium if none */ - if (parent == NULL) { - parent_size.value = FDIV(FMUL(factors[CSS_FONT_SIZE_MEDIUM - 1], - INTTOFIX(nsoption_int(font_size))), - INTTOFIX(10)); - parent_size.unit = CSS_UNIT_PT; - } else { - assert(parent->status == CSS_FONT_SIZE_DIMENSION); - assert(parent->data.length.unit != CSS_UNIT_EM); - assert(parent->data.length.unit != CSS_UNIT_EX); - assert(parent->data.length.unit != CSS_UNIT_PCT); - - parent_size = parent->data.length; - } - - assert(size->status != CSS_FONT_SIZE_INHERIT); - - if (size->status < CSS_FONT_SIZE_LARGER) { - /* Keyword -- simple */ - size->data.length.value = FDIV(FMUL(factors[size->status - 1], - INTTOFIX(nsoption_int(font_size))), F_10); - size->data.length.unit = CSS_UNIT_PT; - } else if (size->status == CSS_FONT_SIZE_LARGER) { - /** \todo Step within table, if appropriate */ - size->data.length.value = - FMUL(parent_size.value, FLTTOFIX(1.2)); - size->data.length.unit = parent_size.unit; - } else if (size->status == CSS_FONT_SIZE_SMALLER) { - /** \todo Step within table, if appropriate */ - size->data.length.value = - FDIV(parent_size.value, FLTTOFIX(1.2)); - size->data.length.unit = parent_size.unit; - } else if (size->data.length.unit == CSS_UNIT_EM || - size->data.length.unit == CSS_UNIT_EX) { - size->data.length.value = - FMUL(size->data.length.value, parent_size.value); - - if (size->data.length.unit == CSS_UNIT_EX) { - /* 1ex = 0.6em in NetSurf */ - size->data.length.value = FMUL(size->data.length.value, - FLTTOFIX(0.6)); - } - - size->data.length.unit = parent_size.unit; - } else if (size->data.length.unit == CSS_UNIT_PCT) { - size->data.length.value = FDIV(FMUL(size->data.length.value, - parent_size.value), INTTOFIX(100)); - size->data.length.unit = parent_size.unit; - } - - size->status = CSS_FONT_SIZE_DIMENSION; - - return CSS_OK; -} - -/****************************************************************************** - * Style selection callbacks * - ******************************************************************************/ - -/** - * Callback to retrieve a node's name. - * - * \param pw HTML document - * \param node DOM node - * \param qname 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, css_qname *qname) -{ - dom_node *n = node; - dom_string *name; - dom_exception err; - - err = dom_node_get_node_name(n, &name); - if (err != DOM_NO_ERR) - return CSS_NOMEM; - - qname->ns = NULL; - - err = dom_string_intern(name, &qname->name); - if (err != DOM_NO_ERR) { - dom_string_unref(name); - return CSS_NOMEM; - } - - dom_string_unref(name); - - return CSS_OK; -} - -/** - * Callback to retrieve a node's classes. - * - * \param pw HTML document - * \param node DOM node - * \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, - * CSS_NOMEM on memory exhaustion. - * - * \note The returned array will be destroyed by libcss. Therefore, it must - * be allocated using the same allocator as used by libcss during style - * selection. - */ -css_error node_classes(void *pw, void *node, - lwc_string ***classes, uint32_t *n_classes) -{ - dom_node *n = node; - dom_exception err; - - *classes = NULL; - *n_classes = 0; - - err = dom_element_get_classes(n, classes, n_classes); - if (err != DOM_NO_ERR) - return CSS_NOMEM; - - return CSS_OK; -} - -/** - * Callback to retrieve a node's ID. - * - * \param pw HTML document - * \param node DOM node - * \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_string **id) -{ - dom_node *n = node; - dom_string *attr; - dom_exception err; - - *id = NULL; - - /** \todo Assumes an HTML DOM */ - err = dom_html_element_get_id(n, &attr); - if (err != DOM_NO_ERR) - return CSS_NOMEM; - - if (attr != NULL) { - err = dom_string_intern(attr, id); - if (err != DOM_NO_ERR) { - dom_string_unref(attr); - return CSS_NOMEM; - } - dom_string_unref(attr); - } - - return CSS_OK; -} - -/** - * Callback to find a named ancestor node. - * - * \param pw HTML document - * \param node DOM node - * \param qname Node name to search for - * \param ancestor Pointer to location to receive ancestor - * \return CSS_OK. - * - * \post \a ancestor will contain the result, or NULL if there is no match - */ -css_error named_ancestor_node(void *pw, void *node, - const css_qname *qname, void **ancestor) -{ - dom_element_named_ancestor_node(node, qname->name, - (struct dom_element **)ancestor); - - return CSS_OK; -} - -/** - * Callback to find a named parent node - * - * \param pw HTML document - * \param node DOM node - * \param qname Node name to search for - * \param parent Pointer to location to receive parent - * \return CSS_OK. - * - * \post \a parent will contain the result, or NULL if there is no match - */ -css_error named_parent_node(void *pw, void *node, - const css_qname *qname, void **parent) -{ - dom_element_named_parent_node(node, qname->name, - (struct dom_element **)parent); - - return CSS_OK; -} - -/** - * Callback to find a named sibling node. - * - * \param pw HTML document - * \param node DOM node - * \param qname Node name to search for - * \param sibling Pointer to location to receive sibling - * \return CSS_OK. - * - * \post \a sibling will contain the result, or NULL if there is no match - */ -css_error named_sibling_node(void *pw, void *node, - const css_qname *qname, void **sibling) -{ - dom_node *n = node; - dom_node *prev; - dom_exception err; - - *sibling = NULL; - - /* Find sibling element */ - err = dom_node_get_previous_sibling(n, &n); - if (err != DOM_NO_ERR) - return CSS_OK; - - while (n != NULL) { - dom_node_type type; - - err = dom_node_get_node_type(n, &type); - if (err != DOM_NO_ERR) { - dom_node_unref(n); - return CSS_OK; - } - - if (type == DOM_ELEMENT_NODE) - break; - - err = dom_node_get_previous_sibling(n, &prev); - if (err != DOM_NO_ERR) { - dom_node_unref(n); - return CSS_OK; - } - - dom_node_unref(n); - n = prev; - } - - if (n != NULL) { - dom_string *name; - - err = dom_node_get_node_name(n, &name); - if (err != DOM_NO_ERR) { - dom_node_unref(n); - return CSS_OK; - } - - dom_node_unref(n); - - if (dom_string_caseless_lwc_isequal(name, qname->name)) { - *sibling = n; - } - - dom_string_unref(name); - } - - return CSS_OK; -} - -/** - * Callback to find a named generic sibling node. - * - * \param pw HTML document - * \param node DOM node - * \param qname Node name to search for - * \param sibling Pointer to location to receive ancestor - * \return CSS_OK. - * - * \post \a sibling will contain the result, or NULL if there is no match - */ -css_error named_generic_sibling_node(void *pw, void *node, - const css_qname *qname, void **sibling) -{ - dom_node *n = node; - dom_node *prev; - dom_exception err; - - *sibling = NULL; - - err = dom_node_get_previous_sibling(n, &n); - if (err != DOM_NO_ERR) - return CSS_OK; - - while (n != NULL) { - dom_node_type type; - dom_string *name; - - err = dom_node_get_node_type(n, &type); - if (err != DOM_NO_ERR) { - dom_node_unref(n); - return CSS_OK; - } - - if (type == DOM_ELEMENT_NODE) { - err = dom_node_get_node_name(n, &name); - if (err != DOM_NO_ERR) { - dom_node_unref(n); - return CSS_OK; - } - - if (dom_string_caseless_lwc_isequal(name, - qname->name)) { - dom_string_unref(name); - dom_node_unref(n); - *sibling = n; - break; - } - dom_string_unref(name); - } - - err = dom_node_get_previous_sibling(n, &prev); - if (err != DOM_NO_ERR) { - dom_node_unref(n); - return CSS_OK; - } - - dom_node_unref(n); - n = prev; - } - - return CSS_OK; -} - -/** - * Callback to retrieve the parent of a node. - * - * \param pw HTML document - * \param node DOM node - * \param parent Pointer to location to receive parent - * \return CSS_OK. - * - * \post \a parent will contain the result, or NULL if there is no match - */ -css_error parent_node(void *pw, void *node, void **parent) -{ - dom_element_parent_node(node, (struct dom_element **)parent); - - return CSS_OK; -} - -/** - * Callback to retrieve the preceding sibling of a node. - * - * \param pw HTML document - * \param node DOM node - * \param sibling Pointer to location to receive sibling - * \return CSS_OK. - * - * \post \a sibling will contain the result, or NULL if there is no match - */ -css_error sibling_node(void *pw, void *node, void **sibling) -{ - dom_node *n = node; - dom_node *prev; - dom_exception err; - - *sibling = NULL; - - /* Find sibling element */ - err = dom_node_get_previous_sibling(n, &n); - if (err != DOM_NO_ERR) - return CSS_OK; - - while (n != NULL) { - dom_node_type type; - - err = dom_node_get_node_type(n, &type); - if (err != DOM_NO_ERR) { - dom_node_unref(n); - return CSS_OK; - } - - if (type == DOM_ELEMENT_NODE) - break; - - err = dom_node_get_previous_sibling(n, &prev); - if (err != DOM_NO_ERR) { - dom_node_unref(n); - return CSS_OK; - } - - dom_node_unref(n); - n = prev; - } - - if (n != NULL) { - /** \todo Sort out reference counting */ - dom_node_unref(n); - - *sibling = n; - } - - return CSS_OK; -} - -/** - * Callback to determine if a node has the given name. - * - * \param pw HTML document - * \param node DOM node - * \param qname Name to match - * \param match Pointer to location to receive result - * \return CSS_OK. - * - * \post \a match will contain true if the node matches and false otherwise. - */ -css_error node_has_name(void *pw, void *node, - const css_qname *qname, bool *match) -{ - nscss_select_ctx *ctx = pw; - dom_node *n = node; - - if (lwc_string_isequal(qname->name, ctx->universal, match) == - lwc_error_ok && *match == false) { - dom_string *name; - dom_exception err; - - err = dom_node_get_node_name(n, &name); - if (err != DOM_NO_ERR) - return CSS_OK; - - /* Element names are case insensitive in HTML */ - *match = dom_string_caseless_lwc_isequal(name, qname->name); - - dom_string_unref(name); - } - - return CSS_OK; -} - -/** - * Callback to determine if a node has the given class. - * - * \param pw HTML document - * \param node DOM node - * \param name Name to match - * \param match Pointer to location to receive result - * \return CSS_OK. - * - * \post \a match will contain true if the node matches and false otherwise. - */ -css_error node_has_class(void *pw, void *node, - lwc_string *name, bool *match) -{ - dom_node *n = node; - dom_exception err; - - /** \todo: Ensure that libdom performs case-insensitive - * matching in quirks mode */ - err = dom_element_has_class(n, name, match); - - assert(err == DOM_NO_ERR); - - return CSS_OK; -} - -/** - * Callback to determine if a node has the given id. - * - * \param pw HTML document - * \param node DOM node - * \param name Name to match - * \param match Pointer to location to receive result - * \return CSS_OK. - * - * \post \a match will contain true if the node matches and false otherwise. - */ -css_error node_has_id(void *pw, void *node, - lwc_string *name, bool *match) -{ - dom_node *n = node; - dom_string *attr; - dom_exception err; - - *match = false; - - /** \todo Assumes an HTML DOM */ - err = dom_html_element_get_id(n, &attr); - if (err != DOM_NO_ERR) - return CSS_OK; - - if (attr != NULL) { - *match = dom_string_lwc_isequal(attr, name); - - dom_string_unref(attr); - } - - return CSS_OK; -} - -/** - * Callback to determine if a node has an attribute with the given name. - * - * \param pw HTML document - * \param node DOM node - * \param qname Name to match - * \param match Pointer to location to receive result - * \return CSS_OK on success, - * CSS_NOMEM on memory exhaustion. - * - * \post \a match will contain true if the node matches and false otherwise. - */ -css_error node_has_attribute(void *pw, void *node, - const css_qname *qname, bool *match) -{ - dom_node *n = node; - dom_string *name; - dom_exception err; - - err = dom_string_create_interned( - (const uint8_t *) lwc_string_data(qname->name), - lwc_string_length(qname->name), &name); - if (err != DOM_NO_ERR) - return CSS_NOMEM; - - err = dom_element_has_attribute(n, name, match); - if (err != DOM_NO_ERR) { - dom_string_unref(name); - return CSS_OK; - } - - dom_string_unref(name); - - return CSS_OK; -} - -/** - * Callback to determine if a node has an attribute with given name and value. - * - * \param pw HTML document - * \param node DOM node - * \param qname Name to match - * \param value Value to match - * \param match Pointer to location to receive result - * \return CSS_OK on success, - * CSS_NOMEM on memory exhaustion. - * - * \post \a match will contain true if the node matches and false otherwise. - */ -css_error node_has_attribute_equal(void *pw, void *node, - const css_qname *qname, lwc_string *value, - bool *match) -{ - dom_node *n = node; - dom_string *name; - dom_string *atr_val; - dom_exception err; - - size_t vlen = lwc_string_length(value); - - if (vlen == 0) { - *match = false; - return CSS_OK; - } - - err = dom_string_create_interned( - (const uint8_t *) lwc_string_data(qname->name), - lwc_string_length(qname->name), &name); - if (err != DOM_NO_ERR) - return CSS_NOMEM; - - err = dom_element_get_attribute(n, name, &atr_val); - if ((err != DOM_NO_ERR) || (atr_val == NULL)) { - dom_string_unref(name); - *match = false; - return CSS_OK; - } - - dom_string_unref(name); - - *match = dom_string_caseless_lwc_isequal(atr_val, value); - - dom_string_unref(atr_val); - - return CSS_OK; -} - -/** - * Callback to determine if a node has an attribute with the given name whose - * value dashmatches that given. - * - * \param pw HTML document - * \param node DOM node - * \param qname Name to match - * \param value Value to match - * \param match Pointer to location to receive result - * \return CSS_OK on success, - * CSS_NOMEM on memory exhaustion. - * - * \post \a match will contain true if the node matches and false otherwise. - */ -css_error node_has_attribute_dashmatch(void *pw, void *node, - const css_qname *qname, lwc_string *value, - bool *match) -{ - dom_node *n = node; - dom_string *name; - dom_string *atr_val; - dom_exception err; - - size_t vlen = lwc_string_length(value); - - if (vlen == 0) { - *match = false; - return CSS_OK; - } - - err = dom_string_create_interned( - (const uint8_t *) lwc_string_data(qname->name), - lwc_string_length(qname->name), &name); - if (err != DOM_NO_ERR) - return CSS_NOMEM; - - err = dom_element_get_attribute(n, name, &atr_val); - if ((err != DOM_NO_ERR) || (atr_val == NULL)) { - dom_string_unref(name); - *match = false; - return CSS_OK; - } - - dom_string_unref(name); - - /* check for exact match */ - *match = dom_string_caseless_lwc_isequal(atr_val, value); - - /* check for dashmatch */ - if (*match == false) { - const char *vdata = lwc_string_data(value); - const char *data = (const char *) dom_string_data(atr_val); - size_t len = dom_string_byte_length(atr_val); - - if (len > vlen && data[vlen] == '-' && - strncasecmp(data, vdata, vlen) == 0) { - *match = true; - } - } - - dom_string_unref(atr_val); - - return CSS_OK; -} - -/** - * Callback to determine if a node has an attribute with the given name whose - * value includes that given. - * - * \param pw HTML document - * \param node DOM node - * \param qname Name to match - * \param value Value to match - * \param match Pointer to location to receive result - * \return CSS_OK on success, - * CSS_NOMEM on memory exhaustion. - * - * \post \a match will contain true if the node matches and false otherwise. - */ -css_error node_has_attribute_includes(void *pw, void *node, - const css_qname *qname, lwc_string *value, - bool *match) -{ - dom_node *n = node; - dom_string *name; - dom_string *atr_val; - dom_exception err; - size_t vlen = lwc_string_length(value); - const char *p; - const char *start; - const char *end; - - *match = false; - - if (vlen == 0) { - return CSS_OK; - } - - err = dom_string_create_interned( - (const uint8_t *) lwc_string_data(qname->name), - lwc_string_length(qname->name), &name); - if (err != DOM_NO_ERR) - return CSS_NOMEM; - - err = dom_element_get_attribute(n, name, &atr_val); - if ((err != DOM_NO_ERR) || (atr_val == NULL)) { - dom_string_unref(name); - *match = false; - return CSS_OK; - } - - dom_string_unref(name); - - /* check for match */ - start = (const char *) dom_string_data(atr_val); - end = start + dom_string_byte_length(atr_val); - - for (p = start; p <= end; p++) { - if (*p == ' ' || *p == '\0') { - if ((size_t) (p - start) == vlen && - strncasecmp(start, - lwc_string_data(value), - vlen) == 0) { - *match = true; - break; - } - - start = p + 1; - } - } - - dom_string_unref(atr_val); - - return CSS_OK; -} - -/** - * Callback to determine if a node has an attribute with the given name whose - * value has the prefix given. - * - * \param pw HTML document - * \param node DOM node - * \param qname Name to match - * \param value Value to match - * \param match Pointer to location to receive result - * \return CSS_OK on success, - * CSS_NOMEM on memory exhaustion. - * - * \post \a match will contain true if the node matches and false otherwise. - */ -css_error node_has_attribute_prefix(void *pw, void *node, - const css_qname *qname, lwc_string *value, - bool *match) -{ - dom_node *n = node; - dom_string *name; - dom_string *atr_val; - dom_exception err; - - size_t vlen = lwc_string_length(value); - - if (vlen == 0) { - *match = false; - return CSS_OK; - } - - err = dom_string_create_interned( - (const uint8_t *) lwc_string_data(qname->name), - lwc_string_length(qname->name), &name); - if (err != DOM_NO_ERR) - return CSS_NOMEM; - - err = dom_element_get_attribute(n, name, &atr_val); - if ((err != DOM_NO_ERR) || (atr_val == NULL)) { - dom_string_unref(name); - *match = false; - return CSS_OK; - } - - dom_string_unref(name); - - /* check for exact match */ - *match = dom_string_caseless_lwc_isequal(atr_val, value); - - /* check for prefix match */ - if (*match == false) { - const char *data = (const char *) dom_string_data(atr_val); - size_t len = dom_string_byte_length(atr_val); - - if ((len >= vlen) && - (strncasecmp(data, lwc_string_data(value), vlen) == 0)) { - *match = true; - } - } - - dom_string_unref(atr_val); - - return CSS_OK; -} - -/** - * Callback to determine if a node has an attribute with the given name whose - * value has the suffix given. - * - * \param pw HTML document - * \param node DOM node - * \param qname Name to match - * \param value Value to match - * \param match Pointer to location to receive result - * \return CSS_OK on success, - * CSS_NOMEM on memory exhaustion. - * - * \post \a match will contain true if the node matches and false otherwise. - */ -css_error node_has_attribute_suffix(void *pw, void *node, - const css_qname *qname, lwc_string *value, - bool *match) -{ - dom_node *n = node; - dom_string *name; - dom_string *atr_val; - dom_exception err; - - size_t vlen = lwc_string_length(value); - - if (vlen == 0) { - *match = false; - return CSS_OK; - } - - err = dom_string_create_interned( - (const uint8_t *) lwc_string_data(qname->name), - lwc_string_length(qname->name), &name); - if (err != DOM_NO_ERR) - return CSS_NOMEM; - - err = dom_element_get_attribute(n, name, &atr_val); - if ((err != DOM_NO_ERR) || (atr_val == NULL)) { - dom_string_unref(name); - *match = false; - return CSS_OK; - } - - dom_string_unref(name); - - /* check for exact match */ - *match = dom_string_caseless_lwc_isequal(atr_val, value); - - /* check for prefix match */ - if (*match == false) { - const char *data = (const char *) dom_string_data(atr_val); - size_t len = dom_string_byte_length(atr_val); - - const char *start = (char *) data + len - vlen; - - if ((len >= vlen) && - (strncasecmp(start, lwc_string_data(value), vlen) == 0)) { - *match = true; - } - - - } - - dom_string_unref(atr_val); - - return CSS_OK; -} - -/** - * Callback to determine if a node has an attribute with the given name whose - * value contains the substring given. - * - * \param pw HTML document - * \param node DOM node - * \param qname Name to match - * \param value Value to match - * \param match Pointer to location to receive result - * \return CSS_OK on success, - * CSS_NOMEM on memory exhaustion. - * - * \post \a match will contain true if the node matches and false otherwise. - */ -css_error node_has_attribute_substring(void *pw, void *node, - const css_qname *qname, lwc_string *value, - bool *match) -{ - dom_node *n = node; - dom_string *name; - dom_string *atr_val; - dom_exception err; - - size_t vlen = lwc_string_length(value); - - if (vlen == 0) { - *match = false; - return CSS_OK; - } - - err = dom_string_create_interned( - (const uint8_t *) lwc_string_data(qname->name), - lwc_string_length(qname->name), &name); - if (err != DOM_NO_ERR) - return CSS_NOMEM; - - err = dom_element_get_attribute(n, name, &atr_val); - if ((err != DOM_NO_ERR) || (atr_val == NULL)) { - dom_string_unref(name); - *match = false; - return CSS_OK; - } - - dom_string_unref(name); - - /* check for exact match */ - *match = dom_string_caseless_lwc_isequal(atr_val, value); - - /* check for prefix match */ - if (*match == false) { - const char *vdata = lwc_string_data(value); - const char *start = (const char *) dom_string_data(atr_val); - size_t len = dom_string_byte_length(atr_val); - const char *last_start = start + len - vlen; - - if (len >= vlen) { - while (start <= last_start) { - if (strncasecmp(start, vdata, - vlen) == 0) { - *match = true; - break; - } - - start++; - } - } - } - - dom_string_unref(atr_val); - - return CSS_OK; -} - -/** - * Callback to determine if a node is the root node of the document. - * - * \param pw HTML document - * \param node DOM node - * \param match Pointer to location to receive result - * \return CSS_OK. - * - * \post \a match will contain true if the node matches and false otherwise. - */ -css_error node_is_root(void *pw, void *node, bool *match) -{ - dom_node *n = node; - dom_node *parent; - dom_node_type type; - dom_exception err; - - err = dom_node_get_parent_node(n, &parent); - if (err != DOM_NO_ERR) { - return CSS_NOMEM; - } - - if (parent != NULL) { - err = dom_node_get_node_type(parent, &type); - - dom_node_unref(parent); - - if (err != DOM_NO_ERR) - return CSS_NOMEM; - - if (type != DOM_DOCUMENT_NODE) { - *match = false; - return CSS_OK; - } - } - - *match = true; - - return CSS_OK; -} - -static int -node_count_siblings_check(dom_node *node, - bool check_name, - dom_string *name) -{ - dom_node_type type; - int ret = 0; - dom_exception exc; - - if (node == NULL) - return 0; - - exc = dom_node_get_node_type(node, &type); - if ((exc != DOM_NO_ERR) || (type != DOM_ELEMENT_NODE)) { - return 0; - } - - if (check_name) { - dom_string *node_name = NULL; - exc = dom_node_get_node_name(node, &node_name); - - if ((exc == DOM_NO_ERR) && (node_name != NULL)) { - - if (dom_string_caseless_isequal(name, - node_name)) { - ret = 1; - } - dom_string_unref(node_name); - } - } else { - ret = 1; - } - - return ret; -} - -/** - * Callback to count a node's siblings. - * - * \param pw HTML document - * \param n DOM node - * \param same_name Only count siblings with the same name, or all - * \param after Count anteceding instead of preceding siblings - * \param count Pointer to location to receive result - * \return CSS_OK. - * - * \post \a count will contain the number of siblings - */ -css_error node_count_siblings(void *pw, void *n, bool same_name, - bool after, int32_t *count) -{ - int32_t cnt = 0; - dom_exception exc; - dom_string *node_name = NULL; - - if (same_name) { - dom_node *node = n; - exc = dom_node_get_node_name(node, &node_name); - if ((exc != DOM_NO_ERR) || (node_name == NULL)) { - return CSS_NOMEM; - } - } - - if (after) { - dom_node *node = dom_node_ref(n); - dom_node *next; - - do { - exc = dom_node_get_next_sibling(node, &next); - if ((exc != DOM_NO_ERR)) - break; - - dom_node_unref(node); - node = next; - - cnt += node_count_siblings_check(node, same_name, node_name); - } while (node != NULL); - } else { - dom_node *node = dom_node_ref(n); - dom_node *next; - - do { - exc = dom_node_get_previous_sibling(node, &next); - if ((exc != DOM_NO_ERR)) - break; - - dom_node_unref(node); - node = next; - - cnt += node_count_siblings_check(node, same_name, node_name); - - } while (node != NULL); - } - - if (node_name != NULL) { - dom_string_unref(node_name); - } - - *count = cnt; - return CSS_OK; -} - -/** - * Callback to determine if a node is empty. - * - * \param pw HTML document - * \param node DOM node - * \param match Pointer to location to receive result - * \return CSS_OK. - * - * \post \a match will contain true if the node is empty and false otherwise. - */ -css_error node_is_empty(void *pw, void *node, bool *match) -{ - dom_node *n = node, *next; - dom_exception err; - - *match = true; - - err = dom_node_get_first_child(n, &n); - if (err != DOM_NO_ERR) { - return CSS_BADPARM; - } - - while (n != NULL) { - dom_node_type ntype; - err = dom_node_get_node_type(n, &ntype); - if (err != DOM_NO_ERR) { - dom_node_unref(n); - return CSS_BADPARM; - } - - if (ntype == DOM_ELEMENT_NODE || - ntype == DOM_TEXT_NODE) { - *match = false; - dom_node_unref(n); - break; - } - - err = dom_node_get_next_sibling(n, &next); - if (err != DOM_NO_ERR) { - dom_node_unref(n); - return CSS_BADPARM; - } - dom_node_unref(n); - n = next; - } - - return CSS_OK; -} - -/** - * Callback to determine if a node is a linking element. - * - * \param pw HTML document - * \param n DOM node - * \param match Pointer to location to receive result - * \return CSS_OK. - * - * \post \a match will contain true if the node matches and false otherwise. - */ -css_error node_is_link(void *pw, void *n, bool *match) -{ - dom_node *node = n; - dom_exception exc; - dom_string *node_name = NULL; - - exc = dom_node_get_node_name(node, &node_name); - if ((exc != DOM_NO_ERR) || (node_name == NULL)) { - return CSS_NOMEM; - } - - if (dom_string_caseless_lwc_isequal(node_name, corestring_lwc_a)) { - bool has_href; - exc = dom_element_has_attribute(node, corestring_dom_href, - &has_href); - if ((exc == DOM_NO_ERR) && (has_href)) { - *match = true; - } else { - *match = false; - } - } else { - *match = false; - } - dom_string_unref(node_name); - - return CSS_OK; -} - -/** - * Callback to determine if a node is a linking element whose target has been - * visited. - * - * \param pw HTML document - * \param node DOM node - * \param match Pointer to location to receive result - * \return CSS_OK. - * - * \post \a match will contain true if the node matches and false otherwise. - */ -css_error node_is_visited(void *pw, void *node, bool *match) -{ - nscss_select_ctx *ctx = pw; - nsurl *url; - nserror error; - const struct url_data *data; - - dom_exception exc; - dom_node *n = node; - dom_string *s = NULL; - - *match = false; - - exc = dom_node_get_node_name(n, &s); - if ((exc != DOM_NO_ERR) || (s == NULL)) { - return CSS_NOMEM; - } - - if (!dom_string_caseless_lwc_isequal(s, corestring_lwc_a)) { - /* Can't be visited; not ancher element */ - dom_string_unref(s); - return CSS_OK; - } - - /* Finished with node name string */ - dom_string_unref(s); - s = NULL; - - exc = dom_element_get_attribute(n, corestring_dom_href, &s); - if ((exc != DOM_NO_ERR) || (s == NULL)) { - /* Can't be visited; not got a URL */ - return CSS_OK; - } - - /* Make href absolute */ - /* TODO: this duplicates what we do for box->href - * should we put the absolute URL on the dom node? */ - error = nsurl_join(ctx->base_url, dom_string_data(s), &url); - - /* Finished with href string */ - dom_string_unref(s); - - if (error != NSERROR_OK) { - /* Couldn't make nsurl object */ - return CSS_NOMEM; - } - - data = urldb_get_url_data(url); - - /* Visited if in the db and has - * non-zero visit count */ - if (data != NULL && data->visits > 0) - *match = true; - - nsurl_unref(url); - - return CSS_OK; -} - -/** - * Callback to determine if a node is currently being hovered over. - * - * \param pw HTML document - * \param node DOM node - * \param match Pointer to location to receive result - * \return CSS_OK. - * - * \post \a match will contain true if the node matches and false otherwise. - */ -css_error node_is_hover(void *pw, void *node, bool *match) -{ - /** \todo Support hovering */ - - *match = false; - - return CSS_OK; -} - -/** - * Callback to determine if a node is currently activated. - * - * \param pw HTML document - * \param node DOM node - * \param match Pointer to location to receive result - * \return CSS_OK. - * - * \post \a match will contain true if the node matches and false otherwise. - */ -css_error node_is_active(void *pw, void *node, bool *match) -{ - /** \todo Support active nodes */ - - *match = false; - - return CSS_OK; -} - -/** - * Callback to determine if a node has the input focus. - * - * \param pw HTML document - * \param node DOM node - * \param match Pointer to location to receive result - * \return CSS_OK. - * - * \post \a match will contain true if the node matches and false otherwise. - */ -css_error node_is_focus(void *pw, void *node, bool *match) -{ - /** \todo Support focussed nodes */ - - *match = false; - - return CSS_OK; -} - -/** - * Callback to determine if a node is enabled. - * - * \param pw HTML document - * \param node DOM node - * \param match Pointer to location to receive result - * \return CSS_OK. - * - * \post \a match with contain true if the node is enabled and false otherwise. - */ -css_error node_is_enabled(void *pw, void *node, bool *match) -{ - /** \todo Support enabled nodes */ - - *match = false; - - return CSS_OK; -} - -/** - * Callback to determine if a node is disabled. - * - * \param pw HTML document - * \param node DOM node - * \param match Pointer to location to receive result - * \return CSS_OK. - * - * \post \a match with contain true if the node is disabled and false otherwise. - */ -css_error node_is_disabled(void *pw, void *node, bool *match) -{ - /** \todo Support disabled nodes */ - - *match = false; - - return CSS_OK; -} - -/** - * Callback to determine if a node is checked. - * - * \param pw HTML document - * \param node DOM node - * \param match Pointer to location to receive result - * \return CSS_OK. - * - * \post \a match with contain true if the node is checked and false otherwise. - */ -css_error node_is_checked(void *pw, void *node, bool *match) -{ - /** \todo Support checked nodes */ - - *match = false; - - return CSS_OK; -} - -/** - * Callback to determine if a node is the target of the document URL. - * - * \param pw HTML document - * \param node DOM node - * \param match Pointer to location to receive result - * \return CSS_OK. - * - * \post \a match with contain true if the node matches and false otherwise. - */ -css_error node_is_target(void *pw, void *node, bool *match) -{ - /** \todo Support target */ - - *match = false; - - return CSS_OK; -} - -/** - * Callback to determine if a node has the given language - * - * \param pw HTML document - * \param node DOM node - * \param lang Language specifier to match - * \param match Pointer to location to receive result - * \return CSS_OK. - * - * \post \a match will contain true if the node matches and false otherwise. - */ -css_error node_is_lang(void *pw, void *node, - lwc_string *lang, bool *match) -{ - /** \todo Support languages */ - - *match = false; - - return CSS_OK; -} - -/** - * Callback to retrieve the User-Agent defaults for a CSS property. - * - * \param pw HTML document - * \param property Property to retrieve defaults for - * \param hint Pointer to hint object to populate - * \return CSS_OK on success, - * CSS_INVALID if the property should not have a user-agent default. - */ -css_error ua_default_for_property(void *pw, uint32_t property, css_hint *hint) -{ - if (property == CSS_PROP_COLOR) { - hint->data.color = 0xff000000; - hint->status = CSS_COLOR_COLOR; - } else if (property == CSS_PROP_FONT_FAMILY) { - hint->data.strings = NULL; - switch (nsoption_int(font_default)) { - case PLOT_FONT_FAMILY_SANS_SERIF: - hint->status = CSS_FONT_FAMILY_SANS_SERIF; - break; - case PLOT_FONT_FAMILY_SERIF: - hint->status = CSS_FONT_FAMILY_SERIF; - break; - case PLOT_FONT_FAMILY_MONOSPACE: - hint->status = CSS_FONT_FAMILY_MONOSPACE; - break; - case PLOT_FONT_FAMILY_CURSIVE: - hint->status = CSS_FONT_FAMILY_CURSIVE; - break; - case PLOT_FONT_FAMILY_FANTASY: - hint->status = CSS_FONT_FAMILY_FANTASY; - break; - } - } else if (property == CSS_PROP_QUOTES) { - /** \todo Not exactly useful :) */ - hint->data.strings = NULL; - hint->status = CSS_QUOTES_NONE; - } else if (property == CSS_PROP_VOICE_FAMILY) { - /** \todo Fix this when we have voice-family done */ - hint->data.strings = NULL; - hint->status = 0; - } else { - return CSS_INVALID; - } - - return CSS_OK; -} - -css_error set_libcss_node_data(void *pw, void *node, void *libcss_node_data) -{ - dom_node *n = node; - dom_exception err; - void *old_node_data; - - /* Set this node's node data */ - err = dom_node_set_user_data(n, - corestring_dom___ns_key_libcss_node_data, - libcss_node_data, nscss_dom_user_data_handler, - (void *) &old_node_data); - if (err != DOM_NO_ERR) { - return CSS_NOMEM; - } - - assert(old_node_data == NULL); - - return CSS_OK; -} - -css_error get_libcss_node_data(void *pw, void *node, void **libcss_node_data) -{ - dom_node *n = node; - dom_exception err; - - /* Get this node's node data */ - err = dom_node_get_user_data(n, - corestring_dom___ns_key_libcss_node_data, - libcss_node_data); - if (err != DOM_NO_ERR) { - return CSS_NOMEM; - } - - return CSS_OK; -} diff --git a/css/select.h b/css/select.h deleted file mode 100644 index 0e0be9578..000000000 --- a/css/select.h +++ /dev/null @@ -1,57 +0,0 @@ -/* - * Copyright 2009 John-Mark Bell - * - * 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 . - */ - -#ifndef NETSURF_CSS_SELECT_H_ -#define NETSURF_CSS_SELECT_H_ - -#include - -#include - -#include "css/css.h" - -struct content; -struct nsurl; - -/** - * Selection context - */ -typedef struct nscss_select_ctx -{ - css_select_ctx *ctx; - bool quirks; - struct nsurl *base_url; - lwc_string *universal; - const css_computed_style *parent_style; -} nscss_select_ctx; - -css_stylesheet *nscss_create_inline_style(const uint8_t *data, size_t len, - const char *charset, const char *url, bool allow_quirks); - -css_select_results *nscss_get_style(nscss_select_ctx *ctx, dom_node *n, - uint64_t media, const css_stylesheet *inline_style); - -css_computed_style *nscss_get_blank_style(nscss_select_ctx *ctx, - const css_computed_style *parent); - - -css_error named_ancestor_node(void *pw, void *node, - const css_qname *qname, void **ancestor); -css_error node_is_visited(void *pw, void *node, bool *match); - -#endif diff --git a/css/utils.c b/css/utils.c deleted file mode 100644 index 9bf743cac..000000000 --- a/css/utils.c +++ /dev/null @@ -1,142 +0,0 @@ -/* - * Copyright 2004 James Bursa - * Copyright 2009 John-Mark Bell - * - * 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 . - */ - -#include - -#include "css/utils.h" - -#include "utils/nsoption.h" -#include "utils/log.h" - -/** Screen DPI in fixed point units: defaults to 90, which RISC OS uses */ -css_fixed nscss_screen_dpi = F_90; - -/** - * Convert an absolute CSS length to points. - * - * \param length Length to convert - * \param unit Corresponding unit - * \return length in points - */ -css_fixed nscss_len2pt(css_fixed length, css_unit unit) -{ - /* Length must not be relative */ - assert(unit != CSS_UNIT_EM && unit != CSS_UNIT_EX); - - switch (unit) { - /* We assume the screen and any other output has the same dpi */ - /* 1in = DPIpx => 1px = (72/DPI)pt */ - case CSS_UNIT_PX: return FDIV(FMUL(length, F_72), nscss_screen_dpi); - /* 1in = 72pt */ - case CSS_UNIT_IN: return FMUL(length, F_72); - /* 1in = 2.54cm => 1cm = (72/2.54)pt */ - case CSS_UNIT_CM: return FMUL(length, - FDIV(F_72, FLTTOFIX(2.54))); - /* 1in = 25.4mm => 1mm = (72/25.4)pt */ - case CSS_UNIT_MM: return FMUL(length, - FDIV(F_72, FLTTOFIX(25.4))); - case CSS_UNIT_PT: return length; - /* 1pc = 12pt */ - case CSS_UNIT_PC: return FMUL(length, INTTOFIX(12)); - default: break; - } - - return 0; -} - - -/** - * Convert a CSS length to pixels. - * - * \param length Length to convert - * \param unit Corresponding unit - * \param style Computed style applying to length. May be NULL if unit is - * neither em nor ex - * \return length in pixels - */ -css_fixed nscss_len2px(css_fixed length, css_unit unit, - const css_computed_style *style) -{ - /* We assume the screen and any other output has the same dpi */ - css_fixed px_per_unit; - - assert(style != NULL || (unit != CSS_UNIT_EM && unit != CSS_UNIT_EX)); - - switch (unit) { - case CSS_UNIT_EM: - case CSS_UNIT_EX: - { - css_fixed font_size = 0; - css_unit font_unit = CSS_UNIT_PT; - - css_computed_font_size(style, &font_size, &font_unit); - - /* Convert to points */ - font_size = nscss_len2pt(font_size, font_unit); - - /* Clamp to configured minimum */ - if (font_size < FDIV(INTTOFIX(nsoption_int(font_min_size)), F_10)) { - font_size = FDIV(INTTOFIX(nsoption_int(font_min_size)), F_10); - } - - /* Convert to pixels (manually, to maximise precision) - * 1in = 72pt => 1pt = (DPI/72)px */ - px_per_unit = FDIV(FMUL(font_size, nscss_screen_dpi), F_72); - - /* Scale ex units: we use a fixed ratio of 1ex = 0.6em */ - if (unit == CSS_UNIT_EX) - px_per_unit = FMUL(px_per_unit, FLTTOFIX(0.6)); - } - break; - case CSS_UNIT_PX: - px_per_unit = F_1; - break; - /* 1in = DPIpx */ - case CSS_UNIT_IN: - px_per_unit = nscss_screen_dpi; - break; - /* 1in = 2.54cm => 1cm = (DPI/2.54)px */ - case CSS_UNIT_CM: - px_per_unit = FDIV(nscss_screen_dpi, FLTTOFIX(2.54)); - break; - /* 1in = 25.4mm => 1mm = (DPI/25.4)px */ - case CSS_UNIT_MM: - px_per_unit = FDIV(nscss_screen_dpi, FLTTOFIX(25.4)); - break; - /* 1in = 72pt => 1pt = (DPI/72)px */ - case CSS_UNIT_PT: - px_per_unit = FDIV(nscss_screen_dpi, F_72); - break; - /* 1pc = 12pt => 1in = 6pc => 1pc = (DPI/6)px */ - case CSS_UNIT_PC: - px_per_unit = FDIV(nscss_screen_dpi, INTTOFIX(6)); - break; - default: - px_per_unit = 0; - break; - } - - /* Ensure we round px_per_unit to the nearest whole number of pixels: - * the use of FIXTOINT() below will truncate. */ - px_per_unit += F_0_5; - - /* Calculate total number of pixels */ - return FMUL(length, TRUNCATEFIX(px_per_unit)); -} - diff --git a/css/utils.h b/css/utils.h deleted file mode 100644 index e9650db97..000000000 --- a/css/utils.h +++ /dev/null @@ -1,70 +0,0 @@ -/* - * Copyright 2009 John-Mark Bell - * - * 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 . - */ - -#ifndef NETSURF_CSS_UTILS_H_ -#define NETSURF_CSS_UTILS_H_ - -#include "css/css.h" -#include "desktop/plot_style.h" - -/* DPI of the screen, in fixed point units */ -extern css_fixed nscss_screen_dpi; - -/** - * Convert a CSS color to a NetSurf colour primitive - * - * ARGB -> (1-A)BGR - * - * \param c The CSS color to convert - * \return Corresponding NetSurf colour primitive - */ -#define nscss_color_to_ns(c) \ - ( ((~c) & 0xff000000) | \ - ((( c) & 0xff0000 ) >> 16) | \ - (( c) & 0xff00 ) | \ - ((( c) & 0xff ) << 16)) - - -/** - * Convert a NetSurf color to a CSS colour primitive - * - * (1-A)BGR -> ARGB - * - * \param c The NetSurf color to convert - * \return Corresponding CSS colour primitive - */ -#define ns_color_to_nscss(c) \ - ( ((~c) & 0xff000000) | \ - ((( c) & 0xff0000 ) >> 16) | \ - (( c) & 0xff00 ) | \ - ((( c) & 0xff ) << 16)) - -/** - * Determine if a CSS color primitive is transparent - * - * \param color The CSS color to consider - * \return True if the color is transparent, false otherwise - */ -#define nscss_color_is_transparent(color) \ - (((color) >> 24) == 0) - -css_fixed nscss_len2pt(css_fixed length, css_unit unit); -css_fixed nscss_len2px(css_fixed length, css_unit unit, - const css_computed_style *style); - -#endif diff --git a/desktop/browser.c b/desktop/browser.c index 4cd017d57..2ee36fd7d 100644 --- a/desktop/browser.c +++ b/desktop/browser.c @@ -52,11 +52,11 @@ #include "content/fetch.h" #include "content/hlcache.h" #include "content/urldb.h" +#include "content/handlers/css/utils.h" #include "render/form_internal.h" #include "render/html.h" #include "render/box.h" #include "curl/curl.h" -#include "css/utils.h" #include "javascript/js.h" #include "desktop/browser_history.h" diff --git a/desktop/browser_history.c b/desktop/browser_history.c index b90884e04..b3d12d525 100644 --- a/desktop/browser_history.c +++ b/desktop/browser_history.c @@ -34,7 +34,6 @@ #include "content/content.h" #include "content/hlcache.h" #include "content/urldb.h" -#include "css/css.h" #include "content/handlers/image/bitmap.h" #include "desktop/gui_layout.h" diff --git a/desktop/font_haru.c b/desktop/font_haru.c index d2d7efdaf..caa751bcb 100644 --- a/desktop/font_haru.c +++ b/desktop/font_haru.c @@ -36,9 +36,6 @@ #include -#include "css/css.h" -#include "css/utils.h" - #include "utils/nsoption.h" #include "desktop/save_pdf/font_haru.h" #include "desktop/font.h" diff --git a/desktop/netsurf.c b/desktop/netsurf.c index 440e14081..d3d45ca66 100644 --- a/desktop/netsurf.c +++ b/desktop/netsurf.c @@ -37,7 +37,7 @@ #include "content/hlcache.h" #include "content/mimesniff.h" #include "content/urldb.h" -#include "css/css.h" +#include "content/handlers/css/css.h" #include "content/handlers/image/image.h" #include "content/handlers/image/image_cache.h" #include "javascript/js.h" diff --git a/desktop/print.c b/desktop/print.c index 711e907e2..c3cfefc0b 100644 --- a/desktop/print.c +++ b/desktop/print.c @@ -32,7 +32,7 @@ #include "utils/talloc.h" #include "content/content.h" #include "content/hlcache.h" -#include "css/utils.h" +#include "content/handlers/css/utils.h" #include "render/box.h" #include "desktop/plotters.h" diff --git a/desktop/print.h b/desktop/print.h index 5c51981d1..fb1fd63ac 100644 --- a/desktop/print.h +++ b/desktop/print.h @@ -33,8 +33,7 @@ #define NETSURF_DESKTOP_PRINT_H #include - -#include "css/css.h" +#include struct hlcache_handle; struct printer; diff --git a/desktop/save_complete.c b/desktop/save_complete.c index 98b0304f8..6f63960aa 100644 --- a/desktop/save_complete.c +++ b/desktop/save_complete.c @@ -41,7 +41,7 @@ #include "utils/messages.h" #include "content/content.h" #include "content/hlcache.h" -#include "css/css.h" +#include "content/handlers/css/css.h" #include "render/box.h" #include "render/html.h" diff --git a/desktop/save_pdf.c b/desktop/save_pdf.c index 0168d0203..40082f23c 100644 --- a/desktop/save_pdf.c +++ b/desktop/save_pdf.c @@ -44,6 +44,7 @@ */ #include "utils/config.h" +#include "utils/errors.h" #include "desktop/save_pdf.h" @@ -52,18 +53,18 @@ #include #include #include - #include +#include "utils/log.h" +#include "utils/utils.h" +#include "utils/useragent.h" #include "content/hlcache.h" #include "utils/nsoption.h" +#include "content/handlers/image/bitmap.h" + #include "desktop/plotters.h" #include "desktop/print.h" #include "desktop/printer.h" -#include "content/handlers/image/bitmap.h" -#include "utils/log.h" -#include "utils/utils.h" -#include "utils/useragent.h" #include "font_haru.h" diff --git a/desktop/system_colour.c b/desktop/system_colour.c index 178c03536..f33b57a37 100644 --- a/desktop/system_colour.c +++ b/desktop/system_colour.c @@ -26,10 +26,10 @@ #include "utils/config.h" #include "utils/utils.h" #include "utils/log.h" -#include "css/utils.h" -#include "desktop/system_colour.h" #include "utils/nsoption.h" +#include "netsurf/css.h" +#include "desktop/system_colour.h" #define colour_list_len ((NSOPTION_SYS_COLOUR_END - NSOPTION_SYS_COLOUR_START) + 1) diff --git a/desktop/textarea.c b/desktop/textarea.c index 467965d39..96a1713ef 100644 --- a/desktop/textarea.c +++ b/desktop/textarea.c @@ -26,10 +26,10 @@ #include #include -#include "css/utils.h" #include "utils/log.h" #include "utils/utf8.h" #include "utils/utils.h" +#include "content/handlers/css/utils.h" #include "desktop/browser.h" #include "desktop/mouse.h" diff --git a/desktop/tree.c b/desktop/tree.c index c5bca61da..e9a2dfdcc 100644 --- a/desktop/tree.c +++ b/desktop/tree.c @@ -32,7 +32,6 @@ #include "utils/utils.h" #include "content/content.h" #include "content/hlcache.h" -#include "css/utils.h" #include "utils/nsoption.h" #include "desktop/browser.h" diff --git a/desktop/treeview.c b/desktop/treeview.c index 6b04eacb9..c12ecd98e 100644 --- a/desktop/treeview.c +++ b/desktop/treeview.c @@ -23,9 +23,9 @@ */ #include "utils/log.h" -#include "css/utils.h" #include "content/handlers/image/bitmap.h" #include "content/hlcache.h" +#include "content/handlers/css/utils.h" #include "desktop/system_colour.h" #include "desktop/knockout.h" diff --git a/frontends/amiga/plotters.c b/frontends/amiga/plotters.c index 23a73f84a..fb9c92394 100644 --- a/frontends/amiga/plotters.c +++ b/frontends/amiga/plotters.c @@ -37,7 +37,7 @@ #include "utils/nsoption.h" #include "utils/utils.h" #include "utils/log.h" -#include "css/utils.h" +#include "netsurf/css.h" #include "desktop/mouse.h" #include "desktop/gui_window.h" diff --git a/include/netsurf/css.h b/include/netsurf/css.h new file mode 100644 index 000000000..bd95eaeeb --- /dev/null +++ b/include/netsurf/css.h @@ -0,0 +1,65 @@ +/* + * Copyright 2009 John-Mark Bell + * + * 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 . + */ + +/** + * \file + * Netsurf core css API + */ + +#ifndef NETSURF_CSS_H_ +#define NETSURF_CSS_H_ + +/** + * Convert a CSS color to a NetSurf colour primitive + * + * ARGB -> (1-A)BGR + * + * \param c The CSS color to convert + * \return Corresponding NetSurf colour primitive + */ +#define nscss_color_to_ns(c) \ + ( ((~c) & 0xff000000) | \ + ((( c) & 0xff0000 ) >> 16) | \ + (( c) & 0xff00 ) | \ + ((( c) & 0xff ) << 16)) + + +/** + * Convert a NetSurf color to a CSS colour primitive + * + * (1-A)BGR -> ARGB + * + * \param c The NetSurf color to convert + * \return Corresponding CSS colour primitive + */ +#define ns_color_to_nscss(c) \ + ( ((~c) & 0xff000000) | \ + ((( c) & 0xff0000 ) >> 16) | \ + (( c) & 0xff00 ) | \ + ((( c) & 0xff ) << 16)) + +/** + * Determine if a CSS color primitive is transparent + * + * \param color The CSS color to consider + * \return True if the color is transparent, false otherwise + */ +#define nscss_color_is_transparent(color) \ + (((color) >> 24) == 0) + +#endif diff --git a/render/box.c b/render/box.c index bb1800b00..07ea114d4 100644 --- a/render/box.c +++ b/render/box.c @@ -35,9 +35,8 @@ #include "utils/utils.h" #include "content/content_protected.h" #include "content/hlcache.h" -#include "css/css.h" -#include "css/utils.h" -#include "css/dump.h" +#include "content/handlers/css/utils.h" +#include "content/handlers/css/dump.h" #include "desktop/scrollbar.h" #include "desktop/gui_misc.h" #include "desktop/gui_internal.h" diff --git a/render/box.h b/render/box.h index 4ac3453aa..c3f95c21c 100644 --- a/render/box.h +++ b/render/box.h @@ -89,8 +89,7 @@ #include #include #include - -#include "css/css.h" +#include struct content; struct box; diff --git a/render/box_construct.c b/render/box_construct.c index 7e982d7a3..6dce5c690 100644 --- a/render/box_construct.c +++ b/render/box_construct.c @@ -43,10 +43,9 @@ #include "utils/utils.h" #include "utils/string.h" #include "content/content_protected.h" -#include "css/css.h" -#include "css/hints.h" -#include "css/select.h" -#include "css/utils.h" +#include "content/handlers/css/hints.h" +#include "content/handlers/css/select.h" +#include "netsurf/css.h" #include "desktop/gui_misc.h" #include "desktop/gui_internal.h" diff --git a/render/box_normalise.c b/render/box_normalise.c index 1010c408b..76767a2a9 100644 --- a/render/box_normalise.c +++ b/render/box_normalise.c @@ -26,12 +26,14 @@ #include #include #include -#include "css/css.h" -#include "css/select.h" + +#include "utils/log.h" +#include "utils/errors.h" +#include "content/handlers/css/select.h" + #include "render/box.h" #include "render/html_internal.h" #include "render/table.h" -#include "utils/log.h" /* Define to enable box normalise debug */ #undef BOX_NORMALISE_DEBUG diff --git a/render/font.c b/render/font.c index 0b059a218..831097e21 100644 --- a/render/font.c +++ b/render/font.c @@ -22,9 +22,8 @@ * Renderer internal font handling implementation. */ -#include "css/css.h" -#include "css/utils.h" #include "utils/nsoption.h" +#include "content/handlers/css/utils.h" #include "render/font.h" diff --git a/render/form.c b/render/form.c index dce906437..75d16d83b 100644 --- a/render/form.c +++ b/render/form.c @@ -42,8 +42,7 @@ #include "utils/utils.h" #include "content/fetch.h" #include "content/hlcache.h" -#include "css/css.h" -#include "css/utils.h" +#include "content/handlers/css/utils.h" #include "desktop/browser.h" #include "desktop/mouse.h" #include "desktop/knockout.h" diff --git a/render/html.h b/render/html.h index ee204d3d6..215bfbbe6 100644 --- a/render/html.h +++ b/render/html.h @@ -31,7 +31,6 @@ #include #include "content/content_type.h" -#include "css/css.h" #include "desktop/browser.h" #include "desktop/mouse.h" #include "desktop/plot_style.h" diff --git a/render/html_css.c b/render/html_css.c index 6761a6502..0c8ee3351 100644 --- a/render/html_css.c +++ b/render/html_css.c @@ -28,6 +28,7 @@ #include #include "content/hlcache.h" +#include "content/handlers/css/css.h" #include "utils/nsoption.h" #include "utils/corestrings.h" #include "utils/config.h" diff --git a/render/html_internal.h b/render/html_internal.h index de28726fb..f0e98158f 100644 --- a/render/html_internal.h +++ b/render/html_internal.h @@ -16,13 +16,16 @@ * along with this program. If not, see . */ -/** \file +/** + * \file * Content for text/html (private data). */ #ifndef NETSURF_RENDER_HTML_INTERNAL_H_ #define NETSURF_RENDER_HTML_INTERNAL_H_ +#include + #include "content/content_protected.h" #include "desktop/selection.h" #include "render/html.h" diff --git a/render/html_object.c b/render/html_object.c index 22c9b712a..9e5e26730 100644 --- a/render/html_object.c +++ b/render/html_object.c @@ -33,7 +33,7 @@ #include "utils/log.h" #include "utils/nsoption.h" #include "content/hlcache.h" -#include "css/utils.h" +#include "content/handlers/css/utils.h" #include "desktop/scrollbar.h" #include "desktop/gui_misc.h" #include "desktop/gui_internal.h" diff --git a/render/html_redraw.c b/render/html_redraw.c index 93c136fb0..7f8391cf9 100644 --- a/render/html_redraw.c +++ b/render/html_redraw.c @@ -41,8 +41,7 @@ #include "utils/utils.h" #include "utils/nsoption.h" #include "content/content_protected.h" -#include "css/css.h" -#include "css/utils.h" +#include "content/handlers/css/utils.h" #include "desktop/browser.h" #include "desktop/plotters.h" #include "desktop/selection.h" diff --git a/render/layout.c b/render/layout.c index e80ec994a..a7f2e8db5 100644 --- a/render/layout.c +++ b/render/layout.c @@ -46,10 +46,9 @@ #include "utils/log.h" #include "utils/talloc.h" #include "utils/utils.h" -#include "css/css.h" -#include "css/utils.h" -#include "content/content_protected.h" #include "utils/nsoption.h" +#include "content/content_protected.h" +#include "content/handlers/css/utils.h" #include "desktop/browser.h" #include "desktop/scrollbar.h" #include "desktop/textarea.h" diff --git a/render/table.c b/render/table.c index 656386491..62553ecdd 100644 --- a/render/table.c +++ b/render/table.c @@ -22,15 +22,14 @@ */ #include - #include -#include "css/css.h" -#include "css/utils.h" -#include "render/box.h" -#include "render/table.h" #include "utils/log.h" #include "utils/talloc.h" +#include "content/handlers/css/utils.h" + +#include "render/box.h" +#include "render/table.h" /* Define to enable verbose table debug */ #undef TABLE_DEBUG diff --git a/render/textplain.c b/render/textplain.c index c825b7946..5ecf1436d 100644 --- a/render/textplain.c +++ b/render/textplain.c @@ -39,8 +39,7 @@ #include "utils/utf8.h" #include "content/content_protected.h" #include "content/hlcache.h" -#include "css/css.h" -#include "css/utils.h" +#include "content/handlers/css/utils.h" #include "desktop/browser.h" #include "utils/nsoption.h" #include "desktop/plotters.h" -- cgit v1.2.3