From 1b95fec601a3d006ba6b99e1dea3f61c3c8318fc Mon Sep 17 00:00:00 2001 From: Michael Drake Date: Fri, 13 Dec 2013 20:16:52 +0000 Subject: Various changes which modify API and ABI: - Remove client allocation function. - Change node_classes callback not to yield array ownership to libcss. - Node bloom filters now built by, during selection libcss. - Added selection callbacks to get and set data on document nodes. Test suite, example, and documentation updated to match. --- Makefile | 1 - docs/API | 202 ++-- docs/API-ABI-Changes | 37 + examples/example1.c | 45 +- include/libcss/bloom.h | 205 ---- include/libcss/computed.h | 3 +- include/libcss/functypes.h | 3 - include/libcss/libcss.h | 1 - include/libcss/select.h | 74 +- include/libcss/stylesheet.h | 1 - src/lex/lex.c | 18 +- src/lex/lex.h | 3 +- src/parse/font_face.c | 10 +- src/parse/language.c | 27 +- src/parse/language.h | 5 +- src/parse/parse.c | 55 +- src/parse/parse.h | 4 +- src/parse/properties/utils.c | 3 +- src/select/bloom.h | 205 ++++ src/select/computed.c | 34 +- src/select/computed.h | 3 - src/select/font_face.c | 20 +- src/select/font_face.h | 6 +- src/select/hash.c | 54 +- src/select/hash.h | 6 +- src/select/properties/content.c | 31 +- src/select/properties/counter_increment.c | 9 +- src/select/properties/counter_reset.c | 9 +- src/select/properties/cursor.c | 32 +- src/select/properties/font_family.c | 30 +- src/select/properties/helpers.c | 19 +- src/select/properties/quotes.c | 34 +- src/select/properties/voice_family.c | 22 +- src/select/propset.h | 18 +- src/select/select.c | 261 +++-- src/select/select.h | 4 +- src/stylesheet.c | 128 +-- src/stylesheet.h | 3 - src/utils/utils.c | 16 + src/utils/utils.h | 8 +- test/INDEX | 22 +- test/Makefile | 2 +- test/css21.c | 12 +- test/lex-auto.c | 2 +- test/lex.c | 2 +- test/parse-auto.c | 12 +- test/parse.c | 9 +- test/parse2-auto.c | 10 +- test/select-auto.c | 1586 ---------------------------- test/select-bloom-auto.c | 1631 ----------------------------- test/select-common.c | 1608 ++++++++++++++++++++++++++++ test/select-nd.c | 14 + test/select-no-nd.c | 14 + 53 files changed, 2539 insertions(+), 4034 deletions(-) create mode 100644 docs/API-ABI-Changes delete mode 100644 include/libcss/bloom.h create mode 100644 src/select/bloom.h delete mode 100644 test/select-auto.c delete mode 100644 test/select-bloom-auto.c create mode 100644 test/select-common.c create mode 100644 test/select-nd.c create mode 100644 test/select-no-nd.c diff --git a/Makefile b/Makefile index d9a2b9b..68ec9ba 100644 --- a/Makefile +++ b/Makefile @@ -46,7 +46,6 @@ include $(NSBUILD)/Makefile.top # Extra installation rules I := /include/libcss -INSTALL_ITEMS := $(INSTALL_ITEMS) $(I):include/libcss/bloom.h INSTALL_ITEMS := $(INSTALL_ITEMS) $(I):include/libcss/computed.h INSTALL_ITEMS := $(INSTALL_ITEMS) $(I):include/libcss/errors.h INSTALL_ITEMS := $(INSTALL_ITEMS) $(I):include/libcss/font_face.h diff --git a/docs/API b/docs/API index a213871..421d720 100644 --- a/docs/API +++ b/docs/API @@ -16,51 +16,6 @@ Using the library consists of the following general steps: Please see example1.c for a demonstration of these steps. -Initialize the library ----------------------- - -The library is initialized using css_initialise(): - - css_initialise("Aliases", myrealloc, 0); - -The first argument is the pathname of an Aliases file, which maps character -encoding names to their canonical form. For an example, see test/data/Aliases. - -The 2nd argument is an allocation function. All allocations required by library -initialization will be made by calling this function. It takes the same -arguments as realloc(); a pointer and a size. If pointer is NULL a new block is -being requested. If size is 0 the block should be freed. Otherwise an existing -block is being resized. In many cases this function can simply call realloc(). - -The allocation function also takes a private data pointer, which is the third -argument to css_initialise(). This is not used by LibCSS but may be used to -communicate context to the allocation function. - -The allocation function pointer and private data pointer are arguments to many -LibCSS functions and work in the same way. - -css_initialise() returns a css_error value. It is CSS_OK if everything worked, -and an error code otherwise. The error codes are defined in libcss/errors.h. - -Many LibCSS functions return a css_error value. Checking the return value of -every call that does is advised, for example: - - css_error code; - code = css_initialise("../test/data/Aliases", myrealloc, 0); - if (code != CSS_OK) { - fprintf(stderr, "ERROR: css_initialise failed: %s\n", - css_error_to_string(code)); - exit(EXIT_FAILURE); - } - -LibCSS depends on LibWapcaplet. This must be initialized before LibCSS. For -example: - - lwc_code = lwc_initialise(myrealloc, NULL, 0); - if (lwc_code != lwc_error_ok) - ... - - Load one or more CSS files -------------------------- @@ -68,49 +23,69 @@ A stylesheet is represented by the opaque type css_stylesheet. To create one, use css_stylesheet_create(), for example: css_stylesheet *sheet; - code = css_stylesheet_create(CSS_LEVEL_DEFAULT, "UTF-8", "", NULL, - false, false, myrealloc, 0, resolve_url, 0, &sheet); + css_stylesheet_params params; + /* Set params */ + ... + code = css_stylesheet_create(¶ms, &sheet); if (code != CSS_OK) ... The arguments are as follows: - css_language_level level - Which version of CSS the stylesheet should be treated as. It currently has - no effect and is reserved for future use. The recommended value is - CSS_LEVEL_DEFAULT. - - const char *charset - The encoding of the stylesheet data, or NULL if LibCSS should attempt to - detect it. If the encoding is known, for example from the Content-Type - header or a file attribute, then it should be supplied here. - - const char *url - The URL that the stylesheet was retrieved from. LibCSS uses this along with - the resolve function (see below) to convert relative URLs in the stylesheet - (e.g. imports, background images) to absolute URLs. If the stylesheet has - no URL, use "". - - const char *title - This is intended for the stylesheet title (for example from the tag). - The title is not used by LibCSS but may be retrieved using - css_stylesheet_get_title(). May be NULL if there is no title. - - bool allow_quirks - - - bool inline_style - - - css_allocator_fn alloc - void *alloc_pw - - - css_url_resolution_fn resolve - void *resolve_pw - - - css_stylesheet **stylesheet ++ css_stylesheet_params params +| + uint32_t params_version +| | Version of the params struct. +| | +| + css_language_level level +| | Which version of CSS the stylesheet should be treated as. It currently has +| | no effect and is reserved for future use. The recommended value is +| | CSS_LEVEL_DEFAULT. +| | +| + const char *charset +| | The encoding of the stylesheet data, or NULL if LibCSS should attempt to +| | detect it. If the encoding is known, for example from the Content-Type +| | header or a file attribute, then it should be supplied here. +| | +| + const char *url +| | The URL that the stylesheet was retrieved from. LibCSS uses this along +| | with the resolve function (see below) to convert relative URLs in the +| | stylesheet (e.g. imports, background images) to absolute URLs. If the +| | stylesheet has no URL, use "". +| | +| + const char *title +| | This is intended for the stylesheet title (for example from the +| | tag). The title is not used by LibCSS but may be retrieved using +| | css_stylesheet_get_title(). May be NULL if there is no title. +| | +| + bool allow_quirks +| | +| + bool inline_style +| | +| + css_url_resolution_fn resolve +| | Function for resolving releative URLs into absolute URLs. +| | +| + void *resolve_pw +| | Client data passed back to resolve function. +| | +| + css_import_notification_fn import +| | Import notification function. +| | +| + void *import_pw +| | Client data passed back to import function. +| | +| + css_color_resolution_fn color +| | Colour resolution function. +| | +| + void *color_pw +| | Client data passed back to color function. +| | +| + css_font_resolution_fn font +| | Font resolution function. +| | +| + void *font_pw +| Client data passed back to import function. +| ++ css_stylesheet **stylesheet Updated with the newly created stylesheet object. Once the stylesheet has been created, CSS source data can be added to it. LibCSS @@ -165,7 +140,7 @@ is a list of the stylesheets to be used. A context is created using css_select_ctx_create(): css_select_ctx *select_ctx; - code = css_select_ctx_create(myrealloc, 0, &select_ctx); + code = css_select_ctx_create(&select_ctx); if (code != CSS_OK) ... @@ -184,7 +159,7 @@ Alternatively stylesheets may be added using css_select_ctx_insert_sheet(). After the context has been prepared, an empty computed style is created: css_computed_style *style; - code = css_computed_style_create(myrealloc, 0, &style); + code = css_computed_style_create(&style); if (code != CSS_OK) ... @@ -198,35 +173,34 @@ The style is then determined for a document node using css_select_style(): The arguments are as follows: - css_select_ctx *ctx - The selection context, as described above. - - void *node - A pointer to the document node for which the style is required. This is a - void pointer and may therefore be of any desired type. LibCSS can not use it - directly; instead it gets information about it through the functions given - in the handler argument, described below. Usually this will be a node in a - document tree. - - uint32_t pseudo_element - - uint64_t media - The media that the style should apply to. The computed style will only - consider stylesheets or @media blocks that include this media. See the CSS - specification for more details. - - const css_stylesheet *inline_style - - css_computed_style *result - Updated to the computed style for the node. - - css_select_handler *handler - This is a table of functions that are used to get information from and to - navigate the document tree, in order to determine if a CSS selector matches - the document node. Further details are below. - - void *pw - A private data pointer that is passed to each of the handler functions. ++ css_select_ctx *ctx +| The selection context, as described above. +| ++ void *node +| A pointer to the document node for which the style is required. This is a +| void pointer and may therefore be of any desired type. LibCSS can not use it +| directly; instead it gets information about it through the functions given +| in the handler argument, described below. Usually this will be a node in a +| document tree. +| ++ uint64_t media +| The media that the style should apply to. The computed style will only +| consider stylesheets or @media blocks that include this media. See the CSS +| specification for more details. +| ++ const css_stylesheet *inline_style +| ++ css_select_handler *handler +| This is a table of functions that are used to get information from and to +| navigate the document tree, in order to determine if a CSS selector matches +| the document node. Further details are below. +| ++ void *pw +| A private data pointer that is passed to each of the handler functions. +| ++ css_computed_style **result + Updated to the computed styles for the node. Array indexed by + css_pseudo_element. The types of the handler functions that need to be supplied and the definition of css_select_handler are given in libcss/select.h. The functions all have the diff --git a/docs/API-ABI-Changes b/docs/API-ABI-Changes new file mode 100644 index 0000000..c70c6f0 --- /dev/null +++ b/docs/API-ABI-Changes @@ -0,0 +1,37 @@ +LibCSS API & ABI Changes +======================== + + This document explains how to upgrade clients to use new versions of LibCSS. + + +LibCSS 0.2.0 --> LibCSS 0.3.0 +----------------------------- + + Both the API and ABI are changed. + + LibCSS nolonger lets clients provide a memory allocator function. + This change affects the following functions: + + From include/libcss/computed.h -- css_computed_style_create() + + From include/libcss/select.h -- css_select_ctx_create() + + From incluce/libcss/stylesheet.h -- css_stylesheet_create() + + + There are changes to selection handler callback table: + + node_classes + LibCSS nolonger frees the any array of classes passed to the + node_classes callback. It does still unref the individual strings. + This means clients need not allocate a new array each call, but can + keep the array cached on the node. + + set_libcss_node_data + New selection handler function used to store a private cache belonging + to libcss on document element nodes. When the node is deleted or + modified, clients should call css_libcss_node_data_handler(). + + get_libcss_node_data + New selection handler function used to retrieve private cache belonging + to libcss from document element nodes. diff --git a/examples/example1.c b/examples/example1.c index b092cfd..511771d 100644 --- a/examples/example1.c +++ b/examples/example1.c @@ -19,7 +19,6 @@ /* Function declarations. */ -static void *myrealloc(void *ptr, size_t len, void *pw); static css_error resolve_url(void *pw, const char *base, lwc_string *rel, lwc_string **abs); static void die(const char *text, css_error code); @@ -101,6 +100,10 @@ static css_error ua_default_for_property(void *pw, uint32_t property, css_hint *hint); static css_error compute_font_size(void *pw, const css_hint *parent, css_hint *size); +static css_error set_libcss_node_data(void *pw, void *n, + void *libcss_node_data); +static css_error get_libcss_node_data(void *pw, void *n, + void **libcss_node_data); /* Table of function pointers for the LibCSS Select API. */ static css_select_handler select_handler = { @@ -140,7 +143,9 @@ static css_select_handler select_handler = { node_is_lang, node_presentational_hint, ua_default_for_property, - compute_font_size + compute_font_size, + set_libcss_node_data, + get_libcss_node_data }; @@ -177,7 +182,7 @@ int main(int argc, char **argv) params.font_pw = NULL; /* create a stylesheet */ - code = css_stylesheet_create(¶ms, myrealloc, NULL, &sheet); + code = css_stylesheet_create(¶ms, &sheet); if (code != CSS_OK) die("css_stylesheet_create", code); code = css_stylesheet_size(sheet, &size); @@ -201,7 +206,7 @@ int main(int argc, char **argv) /* prepare a selection context containing the stylesheet */ - code = css_select_ctx_create(myrealloc, 0, &select_ctx); + code = css_select_ctx_create(&select_ctx); if (code != CSS_OK) die("css_select_ctx_create", code); code = css_select_ctx_append_sheet(select_ctx, sheet, CSS_ORIGIN_AUTHOR, @@ -263,15 +268,6 @@ int main(int argc, char **argv) } -void *myrealloc(void *ptr, size_t len, void *pw) -{ - UNUSED(pw); - /*printf("myrealloc(%p, %zu)\n", ptr, len);*/ - - return realloc(ptr, len); -} - - css_error resolve_url(void *pw, const char *base, lwc_string *rel, lwc_string **abs) { @@ -725,4 +721,27 @@ css_error compute_font_size(void *pw, const css_hint *parent, css_hint *size) return CSS_OK; } +static css_error set_libcss_node_data(void *pw, void *n, + void *libcss_node_data) +{ + UNUSED(pw); + UNUSED(n); + + /* Since we're not storing it, ensure node data gets deleted */ + css_libcss_node_data_handler(&select_handler, CSS_NODE_DELETED, + pw, n, NULL, libcss_node_data); + + return CSS_OK; +} + +static css_error get_libcss_node_data(void *pw, void *n, + void **libcss_node_data) +{ + UNUSED(pw); + UNUSED(n); + *libcss_node_data = NULL; + + return CSS_OK; +} + diff --git a/include/libcss/bloom.h b/include/libcss/bloom.h deleted file mode 100644 index 8c1da3f..0000000 --- a/include/libcss/bloom.h +++ /dev/null @@ -1,205 +0,0 @@ -/* - * This file is part of LibCSS. - * Licensed under the MIT License, - * http://www.opensource.org/licenses/mit-license.php - * Copyright 2013 Michael Drake - */ - -/** \file - * Bloom filter for CSS style selection optimisation. - * - * Attempting to match CSS rules by querying the client about DOM nodes via - * the selection callbacks is slow. To avoid this, clients may pass a node - * bloom filter to css_get_style. This bloom filter has bits set according - * to the node's ancestor element names, class names and id names. - * - * Generate the bloom filter by adding calling css_bloom_add_hash() on each - * ancestor element name, class name and id name for the node. - * - * Use the insesnsitive lwc_string: - * - * lwc_string_hash_value(str->insensitive) - */ - -#ifndef libcss_bloom_h_ -#define libcss_bloom_h_ - -#ifdef __cplusplus -extern "C" -{ -#endif - -#include - -/* Size of bloom filter as multiple of 32 bits. - * Has to be 4, 8, or 16. - * Larger increases optimisation of style selection engine but uses more memory. - */ -#define CSS_BLOOM_SIZE 4 - - - -/* Check valid bloom filter size */ -#if !(CSS_BLOOM_SIZE == 4 || CSS_BLOOM_SIZE == 8 || CSS_BLOOM_SIZE == 16) -# error Unsupported bloom filter size. Size must be {4|8|16}. -#endif - -/* Setup index bit mask */ -#define INDEX_BITS_N (CSS_BLOOM_SIZE - 1) - - - -/* type for bloom */ -typedef uint32_t css_bloom; - - -/** - * Add a hash value to the bloom filter. - * - * \param bloom bloom filter to insert into - * \param hash libwapcaplet hash value to insert - */ -static inline void css_bloom_add_hash(css_bloom bloom[CSS_BLOOM_SIZE], - lwc_hash hash) -{ - unsigned int bit = hash & 0x1f; /* Top 5 bits */ - unsigned int index = (hash >> 5) & INDEX_BITS_N; /* Next N bits */ - - bloom[index] |= (1 << bit); -} - - -/** - * Test whether bloom filter contains given hash value. - * - * \param bloom bloom filter to check inside - * \param hash libwapcaplet hash value to look for - * \return true hash value is already set in bloom - */ -static inline bool css_bloom_has_hash(const css_bloom bloom[CSS_BLOOM_SIZE], - lwc_hash hash) -{ - unsigned int bit = hash & 0x1f; /* Top 5 bits */ - unsigned int index = (hash >> 5) & INDEX_BITS_N; /* Next N bits */ - - return (bloom[index] & (1 << bit)); -} - - -/** - * Test whether bloom 'a' is a subset of bloom 'b'. - * - * \param a potential subset bloom to test - * \param b superset bloom - * \return true iff 'a' is subset of 'b' - */ -static inline bool css_bloom_in_bloom(const css_bloom a[CSS_BLOOM_SIZE], - const css_bloom b[CSS_BLOOM_SIZE]) -{ - if ((a[0] & b[0]) != a[0]) - return false; - if ((a[1] & b[1]) != a[1]) - return false; - if ((a[2] & b[2]) != a[2]) - return false; - if ((a[3] & b[3]) != a[3]) - return false; -#if (CSS_BLOOM_SIZE > 4) - if ((a[4] & b[4]) != a[4]) - return false; - if ((a[5] & b[5]) != a[5]) - return false; - if ((a[6] & b[6]) != a[6]) - return false; - if ((a[7] & b[7]) != a[7]) - return false; -#endif -#if (CSS_BLOOM_SIZE > 8) - if ((a[8] & b[8]) != a[8]) - return false; - if ((a[9] & b[9]) != a[9]) - return false; - if ((a[10] & b[10]) != a[10]) - return false; - if ((a[11] & b[11]) != a[11]) - return false; - if ((a[12] & b[12]) != a[12]) - return false; - if ((a[13] & b[13]) != a[13]) - return false; - if ((a[14] & b[14]) != a[14]) - return false; - if ((a[15] & b[15]) != a[15]) - return false; -#endif - return true; -} - - -/** - * Merge bloom 'a' into bloom 'b'. - * - * \param a bloom to insert - * \param b target bloom - */ -static inline void css_bloom_merge(const css_bloom a[CSS_BLOOM_SIZE], - css_bloom b[CSS_BLOOM_SIZE]) -{ - b[0] |= a[0]; - b[1] |= a[1]; - b[2] |= a[2]; - b[3] |= a[3]; -#if (CSS_BLOOM_SIZE > 4) - b[4] |= a[4]; - b[5] |= a[5]; - b[6] |= a[6]; - b[7] |= a[7]; -#endif -#if (CSS_BLOOM_SIZE > 8) - b[8] |= a[8]; - b[9] |= a[9]; - b[10] |= a[10]; - b[11] |= a[11]; - b[12] |= a[12]; - b[13] |= a[13]; - b[14] |= a[14]; - b[15] |= a[15]; -#endif -} - - -/** - * Initialise a bloom filter to 0 - * - * \param bloom bloom filter to initialise - */ -static inline void css_bloom_init(css_bloom bloom[CSS_BLOOM_SIZE]) -{ - bloom[0] = 0; - bloom[1] = 0; - bloom[2] = 0; - bloom[3] = 0; -#if (CSS_BLOOM_SIZE > 4) - bloom[4] = 0; - bloom[5] = 0; - bloom[6] = 0; - bloom[7] = 0; -#endif -#if (CSS_BLOOM_SIZE > 8) - bloom[8] = 0; - bloom[9] = 0; - bloom[10] = 0; - bloom[11] = 0; - bloom[12] = 0; - bloom[13] = 0; - bloom[14] = 0; - bloom[15] = 0; -#endif -} - -#ifdef __cplusplus -} -#endif - -#endif - diff --git a/include/libcss/computed.h b/include/libcss/computed.h index 6e04e61..324af3f 100644 --- a/include/libcss/computed.h +++ b/include/libcss/computed.h @@ -76,8 +76,7 @@ typedef struct css_computed_content_item { } data; } css_computed_content_item; -css_error css_computed_style_create(css_allocator_fn alloc, void *pw, - css_computed_style **result); +css_error css_computed_style_create(css_computed_style **result); css_error css_computed_style_destroy(css_computed_style *style); css_error css_computed_style_initialise(css_computed_style *style, diff --git a/include/libcss/functypes.h b/include/libcss/functypes.h index 2acd44a..68a3f09 100644 --- a/include/libcss/functypes.h +++ b/include/libcss/functypes.h @@ -19,9 +19,6 @@ extern "C" #include -/* Type of allocation function for libcss */ -typedef void *(*css_allocator_fn)(void *ptr, size_t size, void *pw); - #ifdef __cplusplus } #endif diff --git a/include/libcss/libcss.h b/include/libcss/libcss.h index bde2707..89e83b5 100644 --- a/include/libcss/libcss.h +++ b/include/libcss/libcss.h @@ -15,7 +15,6 @@ extern "C" #include -#include #include #include #include diff --git a/include/libcss/select.h b/include/libcss/select.h index 9ab2550..d504e81 100644 --- a/include/libcss/select.h +++ b/include/libcss/select.h @@ -13,7 +13,6 @@ extern "C" { #endif -#include #include #include #include @@ -34,9 +33,6 @@ typedef enum css_pseudo_element { * Style selection result set */ typedef struct css_select_results { - css_allocator_fn alloc; - void *pw; - /** * Array of pointers to computed styles, * indexed by css_pseudo_element. If there @@ -129,15 +125,37 @@ typedef struct css_select_handler { css_error (*compute_font_size)(void *pw, const css_hint *parent, css_hint *size); + + /** + * Set libcss_node_data on a DOM node. + * + * Replaces any existing libcss_node_data. If node is deleted, cloned, + * or its ancestors are modified, call css_libcss_node_data_handler for + * any non-NULL libcss_node_data. + * + * \param pw Client data + * \param node DOM node to set data for + * \param libcss_node_data Data to set on node, or NULL + * \return CSS_OK on success, or appropriate error otherwise + */ + css_error (*set_libcss_node_data)(void *pw, void *node, + void *libcss_node_data); + /** + * Get libcss_node_data from a DOM node. + * + * \param pw Client data + * \param node DOM node to get data from + * \param libcss_node_data Updated to node data, else set to NULL. + * \return CSS_OK on success, or appropriate error otherwise + */ + css_error (*get_libcss_node_data)(void *pw, void *node, + void **libcss_node_data); } css_select_handler; /** * Font face selection result set */ typedef struct css_select_font_faces_results { - css_allocator_fn alloc; - void *pw; - /** * Array of pointers to computed font faces. */ @@ -145,8 +163,45 @@ typedef struct css_select_font_faces_results { uint32_t n_font_faces; } css_select_font_faces_results; -css_error css_select_ctx_create(css_allocator_fn alloc, void *pw, - css_select_ctx **result); +typedef enum { + CSS_NODE_DELETED, + CSS_NODE_MODIFIED, + CSS_NODE_ANCESTORS_MODIFIED, + CSS_NODE_CLONED +} css_node_data_action; + +/** + * Handle libcss_node_data on DOM changes/deletion. + * + * When a DOM node is deleted, if it has libcss_node_data, call with + * action CSS_NODE_DELETED, to ensure the libcss_node_data is not leaked. + * Does not call handler->set_libcss_node_data. + * + * When a DOM node is modified, if the node has libcss_node_data, + * call with CSS_NODE_MODIFIED. This will result in a call to + * handler->set_libcss_node_data for the node. + * + * When a DOM node's ancestors are modified, if the node has libcss_node_data, + * call with CSS_NODE_ANCESTORS_MODIFIED. This will result in a call to + * handler->set_libcss_node_data for the node. + * + * When a DOM node with libcss_node_data is cloned, and its ancestors are + * also clones, call with CSS_NODE_CLONED. This will result in a call to + * handler->set_libcss_node_data for the clone node. + * + * \param handler Selection handler vtable + * \param action Type of node action. + * \param pw Client data + * \param node DOM node to get data from + * \param clone_node Clone node, or NULL + * \param libcss_node_data Node data (non-NULL) + * \return CSS_OK on success, or appropriate error otherwise + */ +css_error css_libcss_node_data_handler(css_select_handler *handler, + css_node_data_action action, void *pw, void *node, + void *clone_node, void *libcss_node_data); + +css_error css_select_ctx_create(css_select_ctx **result); css_error css_select_ctx_destroy(css_select_ctx *ctx); css_error css_select_ctx_append_sheet(css_select_ctx *ctx, @@ -163,7 +218,6 @@ css_error css_select_ctx_get_sheet(css_select_ctx *ctx, uint32_t index, const css_stylesheet **sheet); css_error css_select_style(css_select_ctx *ctx, void *node, - const css_bloom bloom[CSS_BLOOM_SIZE], uint64_t media, const css_stylesheet *inline_style, css_select_handler *handler, void *pw, css_select_results **result); diff --git a/include/libcss/stylesheet.h b/include/libcss/stylesheet.h index 86a0917..f92d870 100644 --- a/include/libcss/stylesheet.h +++ b/include/libcss/stylesheet.h @@ -137,7 +137,6 @@ typedef struct css_stylesheet_params { } css_stylesheet_params; css_error css_stylesheet_create(const css_stylesheet_params *params, - css_allocator_fn alloc, void *alloc_pw, css_stylesheet **stylesheet); css_error css_stylesheet_destroy(css_stylesheet *sheet); diff --git a/src/lex/lex.c b/src/lex/lex.c index aba86c5..2ab21d1 100644 --- a/src/lex/lex.c +++ b/src/lex/lex.c @@ -108,9 +108,6 @@ struct css_lexer uint32_t currentCol; /**< Current column in source */ uint32_t currentLine; /**< Current line in source */ - - css_allocator_fn alloc; /**< Memory (de)allocation function */ - void *pw; /**< Pointer to client-specific data */ }; #define APPEND(lexer, data, len) \ @@ -169,22 +166,19 @@ static inline bool isSpace(uint8_t c); * Create a lexer instance * * \param input The inputstream to read from - * \param alloc Memory (de)allocation function - * \param pw Pointer to client-specific private data * \param lexer Pointer to location to receive lexer instance * \return CSS_OK on success, * CSS_BADPARM on bad parameters, * CSS_NOMEM on memory exhaustion */ -css_error css__lexer_create(parserutils_inputstream *input, - css_allocator_fn alloc, void *pw, css_lexer **lexer) +css_error css__lexer_create(parserutils_inputstream *input, css_lexer **lexer) { css_lexer *lex; - if (input == NULL || alloc == NULL || lexer == NULL) + if (input == NULL || lexer == NULL) return CSS_BADPARM; - lex = alloc(NULL, sizeof(css_lexer), pw); + lex = malloc(sizeof(css_lexer)); if (lex == NULL) return CSS_NOMEM; @@ -200,8 +194,6 @@ css_error css__lexer_create(parserutils_inputstream *input, lex->emit_comments = false; lex->currentCol = 1; lex->currentLine = 1; - lex->alloc = alloc; - lex->pw = pw; *lexer = lex; @@ -222,7 +214,7 @@ css_error css__lexer_destroy(css_lexer *lexer) if (lexer->unescapedTokenData != NULL) parserutils_buffer_destroy(lexer->unescapedTokenData); - lexer->alloc(lexer, 0, lexer->pw); + free(lexer); return CSS_OK; } @@ -1715,7 +1707,7 @@ css_error consumeEscape(css_lexer *lexer, bool nl) /* Create unescaped buffer, if it doesn't already exist */ if (lexer->unescapedTokenData == NULL) { - perror = parserutils_buffer_create(lexer->alloc, lexer->pw, + perror = parserutils_buffer_create(css_alloc, CSS_ALLOC_PW, &lexer->unescapedTokenData); if (perror != PARSERUTILS_OK) return css_error_from_parserutils_error(perror); diff --git a/src/lex/lex.h b/src/lex/lex.h index 16ba77d..4a663ea 100644 --- a/src/lex/lex.h +++ b/src/lex/lex.h @@ -66,8 +66,7 @@ typedef struct css_token { uint32_t line; } css_token; -css_error css__lexer_create(parserutils_inputstream *input, - css_allocator_fn alloc, void *pw, css_lexer **lexer); +css_error css__lexer_create(parserutils_inputstream *input, css_lexer **lexer); css_error css__lexer_destroy(css_lexer *lexer); css_error css__lexer_setopt(css_lexer *lexer, css_lexer_opttype type, diff --git a/src/parse/font_face.c b/src/parse/font_face.c index 14a715d..8eab006 100644 --- a/src/parse/font_face.c +++ b/src/parse/font_face.c @@ -228,9 +228,8 @@ static css_error font_face_parse_src(css_language *c, /* This will be inefficient if there are a lot of locations - * probably not a problem in practice. */ - new_srcs = c->alloc(srcs, - (n_srcs + 1) * sizeof(css_font_face_src), - c->pw); + new_srcs = realloc(srcs, + (n_srcs + 1) * sizeof(css_font_face_src)); if (new_srcs == NULL) { error = CSS_NOMEM; goto cleanup; @@ -252,7 +251,7 @@ cleanup: if (error != CSS_OK) { *ctx = orig_ctx; if (srcs != NULL) - c->alloc(srcs, 0, c->pw); + free(srcs); } return error; @@ -382,8 +381,7 @@ css_error css__parse_font_descriptor(css_language *c, bool match; if (font_face == NULL) { - error = css__font_face_create(c->sheet->alloc, - c->sheet->pw, &font_face); + error = css__font_face_create(&font_face); if (error != CSS_OK) { return error; } diff --git a/src/parse/language.c b/src/parse/language.c index 7003f0b..5dac773 100644 --- a/src/parse/language.c +++ b/src/parse/language.c @@ -108,34 +108,30 @@ static css_error parseProperty(css_language *c, * * \param sheet The stylesheet object to parse for * \param parser The core parser object to use - * \param alloc Memory (de)allocation function - * \param pw Pointer to client-specific private data * \param language Pointer to location to receive parser object * \return CSS_OK on success, * CSS_BADPARM on bad parameters, * CSS_NOMEM on memory exhaustion */ css_error css__language_create(css_stylesheet *sheet, css_parser *parser, - css_allocator_fn alloc, void *pw, void **language) + void **language) { css_language *c; css_parser_optparams params; parserutils_error perror; css_error error; - if (sheet == NULL || parser == NULL || alloc == NULL || - language == NULL) + if (sheet == NULL || parser == NULL || language == NULL) return CSS_BADPARM; - c = alloc(NULL, sizeof(css_language), pw); + c = malloc(sizeof(css_language)); if (c == NULL) return CSS_NOMEM; perror = parserutils_stack_create(sizeof(context_entry), - STACK_CHUNK, (parserutils_alloc) alloc, pw, - &c->context); + STACK_CHUNK, css_alloc, CSS_ALLOC_PW, &c->context); if (perror != PARSERUTILS_OK) { - alloc(c, 0, pw); + free(c); return css_error_from_parserutils_error(perror); } @@ -144,7 +140,7 @@ css_error css__language_create(css_stylesheet *sheet, css_parser *parser, error = css__parser_setopt(parser, CSS_PARSER_EVENT_HANDLER, ¶ms); if (error != CSS_OK) { parserutils_stack_destroy(c->context); - alloc(c, 0, pw); + free(c); return error; } @@ -154,8 +150,6 @@ css_error css__language_create(css_stylesheet *sheet, css_parser *parser, c->namespaces = NULL; c->num_namespaces = 0; c->strings = sheet->propstrings; - c->alloc = alloc; - c->pw = pw; *language = c; @@ -184,12 +178,12 @@ css_error css__language_destroy(css_language *language) lwc_string_unref(language->namespaces[i].uri); } - language->alloc(language->namespaces, 0, language->pw); + free(language->namespaces); } parserutils_stack_destroy(language->context); - language->alloc(language, 0, language->pw); + free(language); return CSS_OK; } @@ -914,10 +908,9 @@ css_error addNamespace(css_language *c, lwc_string *prefix, lwc_string *uri) if (idx == c->num_namespaces) { /* Not found, create a new mapping */ - css_namespace *ns = c->alloc(c->namespaces, + css_namespace *ns = realloc(c->namespaces, sizeof(css_namespace) * - (c->num_namespaces + 1), - c->pw); + (c->num_namespaces + 1)); if (ns == NULL) return CSS_NOMEM; diff --git a/src/parse/language.h b/src/parse/language.h index efbfaa1..f7c8536 100644 --- a/src/parse/language.h +++ b/src/parse/language.h @@ -48,13 +48,10 @@ typedef struct css_language { lwc_string *default_namespace; /**< Default namespace URI */ css_namespace *namespaces; /**< Array of namespace mappings */ uint32_t num_namespaces; /**< Number of namespace mappings */ - - css_allocator_fn alloc; /**< Memory (de)allocation function */ - void *pw; /**< Client's private data */ } css_language; css_error css__language_create(css_stylesheet *sheet, css_parser *parser, - css_allocator_fn alloc, void *pw, void **language); + void **language); css_error css__language_destroy(css_language *language); /****************************************************************************** diff --git a/src/parse/parse.c b/src/parse/parse.c index d8281ae..b52e9f1 100644 --- a/src/parse/parse.c +++ b/src/parse/parse.c @@ -105,14 +105,10 @@ struct css_parser css_parser_event_handler event; /**< Client's event handler */ void *event_pw; /**< Client data for event handler */ - - css_allocator_fn alloc; /**< Memory (de)allocation function */ - void *pw; /**< Client-specific private data */ }; static css_error css__parser_create_internal(const char *charset, - css_charset_source cs_source, - css_allocator_fn alloc, void *pw, parser_state initial, + css_charset_source cs_source, parser_state initial, css_parser **parser); static css_error transition(css_parser *parser, parser_state to, @@ -190,21 +186,18 @@ static css_error (*parseFuncs[])(css_parser *parser) = { * * \param charset Charset of data, if known, or NULL * \param cs_source Source of charset information, or CSS_CHARSET_DEFAULT - * \param alloc Memory (de)allocation function - * \param pw Pointer to client-specific private data * \param parser Pointer to location to receive parser instance * \return CSS_OK on success, * CSS_BADPARM on bad parameters, * CSS_NOMEM on memory exhaustion */ css_error css__parser_create(const char *charset, css_charset_source cs_source, - css_allocator_fn alloc, void *pw, css_parser **parser) { parser_state initial = { sStart, 0 }; return css__parser_create_internal(charset, cs_source, - alloc, pw, initial, parser); + initial, parser); } /** @@ -212,21 +205,18 @@ css_error css__parser_create(const char *charset, css_charset_source cs_source, * * \param charset Charset of data, if known, or NULL * \param cs_source Source of charset information, or CSS_CHARSET_DEFAULT - * \param alloc Memory (de)allocation function - * \param pw Pointer to client-specific private data * \param parser Pointer to location to receive parser instance * \return CSS_OK on success, * CSS_BADPARM on bad parameters, * CSS_NOMEM on memory exhaustion */ css_error css__parser_create_for_inline_style(const char *charset, - css_charset_source cs_source, - css_allocator_fn alloc, void *pw, css_parser **parser) + css_charset_source cs_source, css_parser **parser) { parser_state initial = { sInlineStyle, 0 }; return css__parser_create_internal(charset, cs_source, - alloc, pw, initial, parser); + initial, parser); } /** @@ -250,7 +240,7 @@ css_error css__parser_destroy(css_parser *parser) parserutils_inputstream_destroy(parser->stream); - parser->alloc(parser, 0, parser->pw); + free(parser); return CSS_OK; } @@ -390,8 +380,6 @@ bool css__parser_quirks_permitted(css_parser *parser) * * \param charset Charset of data, if known, or NULL * \param cs_source Source of charset information, or CSS_CHARSET_DEFAULT - * \param alloc Memory (de)allocation function - * \param pw Pointer to client-specific private data * \param initial The required initial state of the parser * \param parser Pointer to location to receive parser instance * \return CSS_OK on success, @@ -399,66 +387,63 @@ bool css__parser_quirks_permitted(css_parser *parser) * CSS_NOMEM on memory exhaustion */ css_error css__parser_create_internal(const char *charset, - css_charset_source cs_source, - css_allocator_fn alloc, void *pw, parser_state initial, + css_charset_source cs_source, parser_state initial, css_parser **parser) { css_parser *p; parserutils_error perror; css_error error; - if (alloc == NULL || parser == NULL) + if (parser == NULL) return CSS_BADPARM; - p = alloc(NULL, sizeof(css_parser), pw); + p = malloc(sizeof(css_parser)); if (p == NULL) return CSS_NOMEM; perror = parserutils_inputstream_create(charset, cs_source, - css__charset_extract, (parserutils_alloc) alloc, pw, + css__charset_extract, css_alloc, CSS_ALLOC_PW, &p->stream); if (perror != PARSERUTILS_OK) { - alloc(p, 0, pw); + free(p); return css_error_from_parserutils_error(perror); } - error = css__lexer_create(p->stream, alloc, pw, &p->lexer); + error = css__lexer_create(p->stream, &p->lexer); if (error != CSS_OK) { parserutils_inputstream_destroy(p->stream); - alloc(p, 0, pw); + free(p); return error; } perror = parserutils_stack_create(sizeof(parser_state), - STACK_CHUNK, (parserutils_alloc) alloc, pw, + STACK_CHUNK, css_alloc, CSS_ALLOC_PW, &p->states); if (perror != PARSERUTILS_OK) { css__lexer_destroy(p->lexer); parserutils_inputstream_destroy(p->stream); - alloc(p, 0, pw); + free(p); return css_error_from_parserutils_error(perror); } perror = parserutils_vector_create(sizeof(css_token), - STACK_CHUNK, (parserutils_alloc) alloc, pw, - &p->tokens); + STACK_CHUNK, css_alloc, CSS_ALLOC_PW, &p->tokens); if (perror != PARSERUTILS_OK) { parserutils_stack_destroy(p->states); css__lexer_destroy(p->lexer); parserutils_inputstream_destroy(p->stream); - alloc(p, 0, pw); + free(p); return css_error_from_parserutils_error(perror); } perror = parserutils_stack_create(sizeof(char), - STACK_CHUNK, (parserutils_alloc) alloc, pw, - &p->open_items); + STACK_CHUNK, css_alloc, CSS_ALLOC_PW, &p->open_items); if (perror != PARSERUTILS_OK) { parserutils_vector_destroy(p->tokens); parserutils_stack_destroy(p->states); css__lexer_destroy(p->lexer); parserutils_inputstream_destroy(p->stream); - alloc(p, 0, pw); + free(p); return css_error_from_parserutils_error(perror); } @@ -469,7 +454,7 @@ css_error css__parser_create_internal(const char *charset, parserutils_stack_destroy(p->states); css__lexer_destroy(p->lexer); parserutils_inputstream_destroy(p->stream); - alloc(p, 0, pw); + free(p); return css_error_from_parserutils_error(perror); } @@ -480,8 +465,6 @@ css_error css__parser_create_internal(const char *charset, p->event = NULL; p->last_was_ws = false; p->event_pw = NULL; - p->alloc = alloc; - p->pw = pw; *parser = p; diff --git a/src/parse/parse.h b/src/parse/parse.h index e9dbe64..6b95acb 100644 --- a/src/parse/parse.h +++ b/src/parse/parse.h @@ -58,11 +58,9 @@ typedef union css_parser_optparams { } css_parser_optparams; css_error css__parser_create(const char *charset, css_charset_source cs_source, - css_allocator_fn alloc, void *pw, css_parser **parser); css_error css__parser_create_for_inline_style(const char *charset, - css_charset_source cs_source, - css_allocator_fn alloc, void *pw, css_parser **parser); + css_charset_source cs_source, css_parser **parser); css_error css__parser_destroy(css_parser *parser); css_error css__parser_setopt(css_parser *parser, css_parser_opttype type, diff --git a/src/parse/properties/utils.c b/src/parse/properties/utils.c index e018599..4e43c8c 100644 --- a/src/parse/properties/utils.c +++ b/src/parse/properties/utils.c @@ -1118,8 +1118,7 @@ css_error css__ident_list_to_string(css_language *c, lwc_string *interned; lwc_error lerror; - perror = parserutils_buffer_create((parserutils_alloc) c->alloc, - c->pw, &buffer); + perror = parserutils_buffer_create(css_alloc, CSS_ALLOC_PW, &buffer); if (perror != PARSERUTILS_OK) return css_error_from_parserutils_error(perror); diff --git a/src/select/bloom.h b/src/select/bloom.h new file mode 100644 index 0000000..8c1da3f --- /dev/null +++ b/src/select/bloom.h @@ -0,0 +1,205 @@ +/* + * This file is part of LibCSS. + * Licensed under the MIT License, + * http://www.opensource.org/licenses/mit-license.php + * Copyright 2013 Michael Drake + */ + +/** \file + * Bloom filter for CSS style selection optimisation. + * + * Attempting to match CSS rules by querying the client about DOM nodes via + * the selection callbacks is slow. To avoid this, clients may pass a node + * bloom filter to css_get_style. This bloom filter has bits set according + * to the node's ancestor element names, class names and id names. + * + * Generate the bloom filter by adding calling css_bloom_add_hash() on each + * ancestor element name, class name and id name for the node. + * + * Use the insesnsitive lwc_string: + * + * lwc_string_hash_value(str->insensitive) + */ + +#ifndef libcss_bloom_h_ +#define libcss_bloom_h_ + +#ifdef __cplusplus +extern "C" +{ +#endif + +#include + +/* Size of bloom filter as multiple of 32 bits. + * Has to be 4, 8, or 16. + * Larger increases optimisation of style selection engine but uses more memory. + */ +#define CSS_BLOOM_SIZE 4 + + + +/* Check valid bloom filter size */ +#if !(CSS_BLOOM_SIZE == 4 || CSS_BLOOM_SIZE == 8 || CSS_BLOOM_SIZE == 16) +# error Unsupported bloom filter size. Size must be {4|8|16}. +#endif + +/* Setup index bit mask */ +#define INDEX_BITS_N (CSS_BLOOM_SIZE - 1) + + + +/* type for bloom */ +typedef uint32_t css_bloom; + + +/** + * Add a hash value to the bloom filter. + * + * \param bloom bloom filter to insert into + * \param hash libwapcaplet hash value to insert + */ +static inline void css_bloom_add_hash(css_bloom bloom[CSS_BLOOM_SIZE], + lwc_hash hash) +{ + unsigned int bit = hash & 0x1f; /* Top 5 bits */ + unsigned int index = (hash >> 5) & INDEX_BITS_N; /* Next N bits */ + + bloom[index] |= (1 << bit); +} + + +/** + * Test whether bloom filter contains given hash value. + * + * \param bloom bloom filter to check inside + * \param hash libwapcaplet hash value to look for + * \return true hash value is already set in bloom + */ +static inline bool css_bloom_has_hash(const css_bloom bloom[CSS_BLOOM_SIZE], + lwc_hash hash) +{ + unsigned int bit = hash & 0x1f; /* Top 5 bits */ + unsigned int index = (hash >> 5) & INDEX_BITS_N; /* Next N bits */ + + return (bloom[index] & (1 << bit)); +} + + +/** + * Test whether bloom 'a' is a subset of bloom 'b'. + * + * \param a potential subset bloom to test + * \param b superset bloom + * \return true iff 'a' is subset of 'b' + */ +static inline bool css_bloom_in_bloom(const css_bloom a[CSS_BLOOM_SIZE], + const css_bloom b[CSS_BLOOM_SIZE]) +{ + if ((a[0] & b[0]) != a[0]) + return false; + if ((a[1] & b[1]) != a[1]) + return false; + if ((a[2] & b[2]) != a[2]) + return false; + if ((a[3] & b[3]) != a[3]) + return false; +#if (CSS_BLOOM_SIZE > 4) + if ((a[4] & b[4]) != a[4]) + return false; + if ((a[5] & b[5]) != a[5]) + return false; + if ((a[6] & b[6]) != a[6]) + return false; + if ((a[7] & b[7]) != a[7]) + return false; +#endif +#if (CSS_BLOOM_SIZE > 8) + if ((a[8] & b[8]) != a[8]) + return false; + if ((a[9] & b[9]) != a[9]) + return false; + if ((a[10] & b[10]) != a[10]) + return false; + if ((a[11] & b[11]) != a[11]) + return false; + if ((a[12] & b[12]) != a[12]) + return false; + if ((a[13] & b[13]) != a[13]) + return false; + if ((a[14] & b[14]) != a[14]) + return false; + if ((a[15] & b[15]) != a[15]) + return false; +#endif + return true; +} + + +/** + * Merge bloom 'a' into bloom 'b'. + * + * \param a bloom to insert + * \param b target bloom + */ +static inline void css_bloom_merge(const css_bloom a[CSS_BLOOM_SIZE], + css_bloom b[CSS_BLOOM_SIZE]) +{ + b[0] |= a[0]; + b[1] |= a[1]; + b[2] |= a[2]; + b[3] |= a[3]; +#if (CSS_BLOOM_SIZE > 4) + b[4] |= a[4]; + b[5] |= a[5]; + b[6] |= a[6]; + b[7] |= a[7]; +#endif +#if (CSS_BLOOM_SIZE > 8) + b[8] |= a[8]; + b[9] |= a[9]; + b[10] |= a[10]; + b[11] |= a[11]; + b[12] |= a[12]; + b[13] |= a[13]; + b[14] |= a[14]; + b[15] |= a[15]; +#endif +} + + +/** + * Initialise a bloom filter to 0 + * + * \param bloom bloom filter to initialise + */ +static inline void css_bloom_init(css_bloom bloom[CSS_BLOOM_SIZE]) +{ + bloom[0] = 0; + bloom[1] = 0; + bloom[2] = 0; + bloom[3] = 0; +#if (CSS_BLOOM_SIZE > 4) + bloom[4] = 0; + bloom[5] = 0; + bloom[6] = 0; + bloom[7] = 0; +#endif +#if (CSS_BLOOM_SIZE > 8) + bloom[8] = 0; + bloom[9] = 0; + bloom[10] = 0; + bloom[11] = 0; + bloom[12] = 0; + bloom[13] = 0; + bloom[14] = 0; + bloom[15] = 0; +#endif +} + +#ifdef __cplusplus +} +#endif + +#endif + diff --git a/src/select/computed.c b/src/select/computed.c index 059c76f..682fe05 100644 --- a/src/select/computed.c +++ b/src/select/computed.c @@ -77,30 +77,24 @@ static css_error compute_absolute_length_pair(css_computed_style *style, /** * Create a computed style * - * \param alloc Memory (de)allocation function - * \param pw Pointer to client-specific data * \param result Pointer to location to receive result * \return CSS_OK on success, * CSS_NOMEM on memory exhaustion, * CSS_BADPARM on bad parameters. */ -css_error css_computed_style_create(css_allocator_fn alloc, void *pw, - css_computed_style **result) +css_error css_computed_style_create(css_computed_style **result) { css_computed_style *s; - if (alloc == NULL || result == NULL) + if (result == NULL) return CSS_BADPARM; - s = alloc(NULL, sizeof(css_computed_style), pw); + s = malloc(sizeof(css_computed_style)); if (s == NULL) return CSS_NOMEM; memset(s, 0, sizeof(css_computed_style)); - s->alloc = alloc; - s->pw = pw; - *result = s; return CSS_OK; @@ -126,8 +120,7 @@ css_error css_computed_style_destroy(css_computed_style *style) lwc_string_unref(c->name); } - style->alloc(style->uncommon->counter_increment, 0, - style->pw); + free(style->uncommon->counter_increment); } if (style->uncommon->counter_reset != NULL) { @@ -138,8 +131,7 @@ css_error css_computed_style_destroy(css_computed_style *style) lwc_string_unref(c->name); } - style->alloc(style->uncommon->counter_reset, 0, - style->pw); + free(style->uncommon->counter_reset); } if (style->uncommon->cursor != NULL) { @@ -149,7 +141,7 @@ css_error css_computed_style_destroy(css_computed_style *style) lwc_string_unref(*s); } - style->alloc(style->uncommon->cursor, 0, style->pw); + free(style->uncommon->cursor); } if (style->uncommon->content != NULL) { @@ -180,18 +172,18 @@ css_error css_computed_style_destroy(css_computed_style *style) } } - style->alloc(style->uncommon->content, 0, style->pw); + free(style->uncommon->content); } - style->alloc(style->uncommon, 0, style->pw); + free(style->uncommon); } if (style->page != NULL) { - style->alloc(style->page, 0, style->pw); + free(style->page); } if (style->aural != NULL) { - style->alloc(style->aural, 0, style->pw); + free(style->aural); } if (style->font_family != NULL) { @@ -201,7 +193,7 @@ css_error css_computed_style_destroy(css_computed_style *style) lwc_string_unref(*s); } - style->alloc(style->font_family, 0, style->pw); + free(style->font_family); } if (style->quotes != NULL) { @@ -211,7 +203,7 @@ css_error css_computed_style_destroy(css_computed_style *style) lwc_string_unref(*s); } - style->alloc(style->quotes, 0, style->pw); + free(style->quotes); } if (style->list_style_image != NULL) @@ -220,7 +212,7 @@ css_error css_computed_style_destroy(css_computed_style *style) if (style->background_image != NULL) lwc_string_unref(style->background_image); - style->alloc(style, 0, style->pw); + free(style); return CSS_OK; } diff --git a/src/select/computed.h b/src/select/computed.h index 8be3873..1f2cded 100644 --- a/src/select/computed.h +++ b/src/select/computed.h @@ -285,9 +285,6 @@ struct css_computed_style { css_computed_uncommon *uncommon;/**< Uncommon properties */ void *aural; /**< Aural properties */ css_computed_page *page; /**< Page properties */ - - css_allocator_fn alloc; - void *pw; }; css_error css__compute_absolute_values(const css_computed_style *parent, diff --git a/src/select/font_face.c b/src/select/font_face.c index cd6556a..ea790eb 100644 --- a/src/select/font_face.c +++ b/src/select/font_face.c @@ -21,7 +21,7 @@ static void font_faces_srcs_destroy(css_font_face *font_face) } } - font_face->alloc(srcs, 0, font_face->pw); + free(srcs); font_face->srcs = NULL; } @@ -29,38 +29,30 @@ static const css_font_face default_font_face = { NULL, NULL, 0, - { (CSS_FONT_WEIGHT_NORMAL << 2) | CSS_FONT_STYLE_NORMAL }, - NULL, - NULL + { (CSS_FONT_WEIGHT_NORMAL << 2) | CSS_FONT_STYLE_NORMAL } }; /** * Create a font-face * - * \param alloc Memory (de)allocation function - * \param pw Pointer to client-specific data * \param result Pointer to location to receive result * \return CSS_OK on success, * CSS_NOMEM on memory exhaustion, * CSS_BADPARM on bad parameters. */ -css_error css__font_face_create(css_allocator_fn alloc, void *pw, - css_font_face **result) +css_error css__font_face_create(css_font_face **result) { css_font_face *f; - if (alloc == NULL || result == NULL) + if (result == NULL) return CSS_BADPARM; - f = alloc(NULL, sizeof(css_font_face), pw); + f = malloc(sizeof(css_font_face)); if (f == NULL) return CSS_NOMEM; memcpy(f, &default_font_face, sizeof(css_font_face)); - f->alloc = alloc; - f->pw = pw; - *result = f; return CSS_OK; @@ -83,7 +75,7 @@ css_error css__font_face_destroy(css_font_face *font_face) if (font_face->srcs != NULL) font_faces_srcs_destroy(font_face); - font_face->alloc(font_face, 0, font_face->pw); + free(font_face); return CSS_OK; } diff --git a/src/select/font_face.h b/src/select/font_face.h index 3572de8..4e6d094 100644 --- a/src/select/font_face.h +++ b/src/select/font_face.h @@ -35,13 +35,9 @@ struct css_font_face { * 1 __wwwwss font-weight | font-style */ uint8_t bits[1]; - - css_allocator_fn alloc; - void *pw; }; -css_error css__font_face_create(css_allocator_fn alloc, void *pw, - css_font_face **result); +css_error css__font_face_create(css_font_face **result); css_error css__font_face_destroy(css_font_face *font_face); css_error css__font_face_set_font_family(css_font_face *font_face, diff --git a/src/select/hash.c b/src/select/hash.c index 79c324b..249aeb6 100644 --- a/src/select/hash.c +++ b/src/select/hash.c @@ -37,9 +37,6 @@ struct css_selector_hash { hash_entry universal; size_t hash_size; - - css_allocator_fn alloc; - void *pw; }; static hash_entry empty_slot; @@ -143,48 +140,45 @@ static inline bool _rule_good_for_media(const css_rule *rule, uint64_t media) /** * Create a hash * - * \param alloc Memory (de)allocation function - * \param pw Pointer to client-specific private data * \param hash Pointer to location to receive result * \return CSS_OK on success, appropriate error otherwise */ -css_error css__selector_hash_create(css_allocator_fn alloc, void *pw, - css_selector_hash **hash) +css_error css__selector_hash_create(css_selector_hash **hash) { css_selector_hash *h; - if (alloc == NULL || hash == NULL) + if (hash == NULL) return CSS_BADPARM; - h = alloc(0, sizeof(css_selector_hash), pw); + h = malloc(sizeof(css_selector_hash)); if (h == NULL) return CSS_NOMEM; /* Element hash */ - h->elements.slots = alloc(0, DEFAULT_SLOTS * sizeof(hash_entry), pw); + h->elements.slots = malloc(DEFAULT_SLOTS * sizeof(hash_entry)); if (h->elements.slots == NULL) { - alloc(h, 0, pw); + free(h); return CSS_NOMEM; } memset(h->elements.slots, 0, DEFAULT_SLOTS * sizeof(hash_entry)); h->elements.n_slots = DEFAULT_SLOTS; /* Class hash */ - h->classes.slots = alloc(0, DEFAULT_SLOTS * sizeof(hash_entry), pw); + h->classes.slots = malloc(DEFAULT_SLOTS * sizeof(hash_entry)); if (h->classes.slots == NULL) { - alloc(h->elements.slots, 0, pw); - alloc(h, 0, pw); + free(h->elements.slots); + free(h); return CSS_NOMEM; } memset(h->classes.slots, 0, DEFAULT_SLOTS * sizeof(hash_entry)); h->classes.n_slots = DEFAULT_SLOTS; /* ID hash */ - h->ids.slots = alloc(0, DEFAULT_SLOTS * sizeof(hash_entry), pw); + h->ids.slots = malloc(DEFAULT_SLOTS * sizeof(hash_entry)); if (h->ids.slots == NULL) { - alloc(h->classes.slots, 0, pw); - alloc(h->elements.slots, 0, pw); - alloc(h, 0, pw); + free(h->classes.slots); + free(h->elements.slots); + free(h); return CSS_NOMEM; } memset(h->ids.slots, 0, DEFAULT_SLOTS * sizeof(hash_entry)); @@ -198,9 +192,6 @@ css_error css__selector_hash_create(css_allocator_fn alloc, void *pw, DEFAULT_SLOTS * sizeof(hash_entry) + DEFAULT_SLOTS * sizeof(hash_entry); - h->alloc = alloc; - h->pw = pw; - *hash = h; return CSS_OK; @@ -225,39 +216,39 @@ css_error css__selector_hash_destroy(css_selector_hash *hash) for (d = hash->elements.slots[i].next; d != NULL; d = e) { e = d->next; - hash->alloc(d, 0, hash->pw); + free(d); } } - hash->alloc(hash->elements.slots, 0, hash->pw); + free(hash->elements.slots); /* Class hash */ for (i = 0; i < hash->classes.n_slots; i++) { for (d = hash->classes.slots[i].next; d != NULL; d = e) { e = d->next; - hash->alloc(d, 0, hash->pw); + free(d); } } - hash->alloc(hash->classes.slots, 0, hash->pw); + free(hash->classes.slots); /* ID hash */ for (i = 0; i < hash->ids.n_slots; i++) { for (d = hash->ids.slots[i].next; d != NULL; d = e) { e = d->next; - hash->alloc(d, 0, hash->pw); + free(d); } } - hash->alloc(hash->ids.slots, 0, hash->pw); + free(hash->ids.slots); /* Universal chain */ for (d = hash->universal.next; d != NULL; d = e) { e = d->next; - hash->alloc(d, 0, hash->pw); + free(d); } - hash->alloc(hash, 0, hash->pw); + free(hash); return CSS_OK; } @@ -837,8 +828,7 @@ css_error _insert_into_chain(css_selector_hash *ctx, hash_entry *head, } else { hash_entry *search = head; hash_entry *prev = NULL; - hash_entry *entry = - ctx->alloc(NULL, sizeof(hash_entry), ctx->pw); + hash_entry *entry = malloc(sizeof(hash_entry)); if (entry == NULL) return CSS_NOMEM; @@ -920,7 +910,7 @@ css_error _remove_from_chain(css_selector_hash *ctx, hash_entry *head, } else { prev->next = search->next; - ctx->alloc(search, 0, ctx->pw); + free(search); ctx->hash_size -= sizeof(hash_entry); } diff --git a/src/select/hash.h b/src/select/hash.h index f572048..71f610f 100644 --- a/src/select/hash.h +++ b/src/select/hash.h @@ -10,10 +10,11 @@ #include -#include #include #include +#include "select/bloom.h" + /* Ugh. We need this to avoid circular includes. Happy! */ struct css_selector; @@ -33,8 +34,7 @@ typedef css_error (*css_selector_hash_iterator)( const struct css_selector **current, const struct css_selector ***next); -css_error css__selector_hash_create(css_allocator_fn alloc, void *pw, - css_selector_hash **hash); +css_error css__selector_hash_create(css_selector_hash **hash); css_error css__selector_hash_destroy(css_selector_hash *hash); css_error css__selector_hash_insert(css_selector_hash *hash, diff --git a/src/select/properties/content.c b/src/select/properties/content.c index 1d033f2..c79dd0d 100644 --- a/src/select/properties/content.c +++ b/src/select/properties/content.c @@ -35,16 +35,15 @@ css_error css__cascade_content(uint32_t opv, css_style *style, lwc_string *he; css_computed_content_item *temp; - css__stylesheet_string_get(style->sheet, *((css_code_t *) style->bytecode), &he); + css__stylesheet_string_get(style->sheet, + *((css_code_t *) style->bytecode), &he); - temp = state->computed->alloc(content, + temp = realloc(content, (n_contents + 1) * - sizeof(css_computed_content_item), - state->computed->pw); + sizeof(css_computed_content_item)); if (temp == NULL) { if (content != NULL) { - state->computed->alloc(content, - 0, state->computed->pw); + free(content); } return CSS_NOMEM; } @@ -127,11 +126,10 @@ css_error css__cascade_content(uint32_t opv, css_style *style, if (n_contents > 0) { css_computed_content_item *temp; - temp = state->computed->alloc(content, - (n_contents + 1) * sizeof(css_computed_content_item), - state->computed->pw); + temp = realloc(content, (n_contents + 1) * + sizeof(css_computed_content_item)); if (temp == NULL) { - state->computed->alloc(content, 0, state->computed->pw); + free(content); return CSS_NOMEM; } @@ -146,11 +144,11 @@ css_error css__cascade_content(uint32_t opv, css_style *style, error = set_content(state->computed, value, content); if (error != CSS_OK && content != NULL) - state->computed->alloc(content, 0, state->computed->pw); + free(content); return error; } else if (content != NULL) { - state->computed->alloc(content, 0, state->computed->pw); + free(content); } return CSS_OK; @@ -190,7 +188,7 @@ css_error css__set_content_from_hint(const css_hint *hint, } if (error != CSS_OK && hint->data.content != NULL) - style->alloc(hint->data.content, 0, style->pw); + free(hint->data.content); return error; } @@ -226,9 +224,8 @@ css_error css__compose_content(const css_computed_style *parent, i++) n_items++; - copy = result->alloc(NULL, (n_items + 1) * - sizeof(css_computed_content_item), - result->pw); + copy = malloc((n_items + 1) * + sizeof(css_computed_content_item)); if (copy == NULL) return CSS_NOMEM; @@ -238,7 +235,7 @@ css_error css__compose_content(const css_computed_style *parent, error = set_content(result, type, copy); if (error != CSS_OK && copy != NULL) - result->alloc(copy, 0, result->pw); + free(copy); return error; } diff --git a/src/select/properties/counter_increment.c b/src/select/properties/counter_increment.c index 26419a2..429e558 100644 --- a/src/select/properties/counter_increment.c +++ b/src/select/properties/counter_increment.c @@ -37,7 +37,7 @@ css_error css__set_counter_increment_from_hint(const css_hint *hint, } if (error != CSS_OK && hint->data.counter != NULL) - style->alloc(hint->data.counter, 0, style->pw); + free(hint->data.counter); return error; } @@ -73,9 +73,8 @@ css_error css__compose_counter_increment(const css_computed_style *parent, for (i = items; i->name != NULL; i++) n_items++; - copy = result->alloc(NULL, (n_items + 1) * - sizeof(css_computed_counter), - result->pw); + copy = malloc((n_items + 1) * + sizeof(css_computed_counter)); if (copy == NULL) return CSS_NOMEM; @@ -85,7 +84,7 @@ css_error css__compose_counter_increment(const css_computed_style *parent, error = set_counter_increment(result, type, copy); if (error != CSS_OK && copy != NULL) - result->alloc(copy, 0, result->pw); + free(copy); return error; } diff --git a/src/select/properties/counter_reset.c b/src/select/properties/counter_reset.c index 362c86d..ddf54aa 100644 --- a/src/select/properties/counter_reset.c +++ b/src/select/properties/counter_reset.c @@ -37,7 +37,7 @@ css_error css__set_counter_reset_from_hint(const css_hint *hint, } if (error != CSS_OK && hint->data.counter != NULL) - style->alloc(hint->data.counter, 0, style->pw); + free(hint->data.counter); return error; } @@ -72,9 +72,8 @@ css_error css__compose_counter_reset(const css_computed_style *parent, for (i = items; i->name != NULL; i++) n_items++; - copy = result->alloc(NULL, (n_items + 1) * - sizeof(css_computed_counter), - result->pw); + copy = malloc((n_items + 1) * + sizeof(css_computed_counter)); if (copy == NULL) return CSS_NOMEM; @@ -84,7 +83,7 @@ css_error css__compose_counter_reset(const css_computed_style *parent, error = set_counter_reset(result, type, copy); if (error != CSS_OK && copy != NULL) - result->alloc(copy, 0, result->pw); + free(copy); return error; } diff --git a/src/select/properties/cursor.c b/src/select/properties/cursor.c index d4785b1..a77d21b 100644 --- a/src/select/properties/cursor.c +++ b/src/select/properties/cursor.c @@ -28,16 +28,16 @@ css_error css__cascade_cursor(uint32_t opv, css_style *style, lwc_string *uri; lwc_string **temp; - css__stylesheet_string_get(style->sheet, *((css_code_t *) style->bytecode), &uri); + css__stylesheet_string_get(style->sheet, + *((css_code_t *) style->bytecode), + &uri); advance_bytecode(style, sizeof(css_code_t)); - temp = state->computed->alloc(uris, - (n_uris + 1) * sizeof(lwc_string *), - state->computed->pw); + temp = realloc(uris, + (n_uris + 1) * sizeof(lwc_string *)); if (temp == NULL) { if (uris != NULL) { - state->computed->alloc(uris, 0, - state->computed->pw); + free(uris); } return CSS_NOMEM; } @@ -111,11 +111,10 @@ css_error css__cascade_cursor(uint32_t opv, css_style *style, if (n_uris > 0) { lwc_string **temp; - temp = state->computed->alloc(uris, - (n_uris + 1) * sizeof(lwc_string *), - state->computed->pw); + temp = realloc(uris, + (n_uris + 1) * sizeof(lwc_string *)); if (temp == NULL) { - state->computed->alloc(uris, 0, state->computed->pw); + free(uris); return CSS_NOMEM; } @@ -130,12 +129,12 @@ css_error css__cascade_cursor(uint32_t opv, css_style *style, error = set_cursor(state->computed, value, uris); if (error != CSS_OK && n_uris > 0) - state->computed->alloc(uris, 0, state->computed->pw); + free(uris); return error; } else { if (n_uris > 0) - state->computed->alloc(uris, 0, state->computed->pw); + free(uris); } return CSS_OK; @@ -155,7 +154,7 @@ css_error css__set_cursor_from_hint(const css_hint *hint, } if (error != CSS_OK && hint->data.strings != NULL) - style->alloc(hint->data.strings, 0, style->pw); + free(hint->data.strings); return error; } @@ -190,9 +189,8 @@ css_error css__compose_cursor(const css_computed_style *parent, for (i = urls; (*i) != NULL; i++) n_urls++; - copy = result->alloc(NULL, (n_urls + 1) * - sizeof(lwc_string *), - result->pw); + copy = malloc((n_urls + 1) * + sizeof(lwc_string *)); if (copy == NULL) return CSS_NOMEM; @@ -202,7 +200,7 @@ css_error css__compose_cursor(const css_computed_style *parent, error = set_cursor(result, type, copy); if (error != CSS_OK && copy != NULL) - result->alloc(copy, 0, result->pw); + free(copy); return error; } diff --git a/src/select/properties/font_family.c b/src/select/properties/font_family.c index 44860f9..514a43a 100644 --- a/src/select/properties/font_family.c +++ b/src/select/properties/font_family.c @@ -63,13 +63,11 @@ css_error css__cascade_font_family(uint32_t opv, css_style *style, * first generic-family are ignored. */ /** \todo Do this at bytecode generation time? */ if (value == CSS_FONT_FAMILY_INHERIT && font != NULL) { - temp = state->computed->alloc(fonts, - (n_fonts + 1) * sizeof(lwc_string *), - state->computed->pw); + temp = realloc(fonts, + (n_fonts + 1) * sizeof(lwc_string *)); if (temp == NULL) { if (fonts != NULL) { - state->computed->alloc(fonts, 0, - state->computed->pw); + free(fonts); } return CSS_NOMEM; } @@ -90,11 +88,9 @@ css_error css__cascade_font_family(uint32_t opv, css_style *style, if (n_fonts > 0) { lwc_string **temp; - temp = state->computed->alloc(fonts, - (n_fonts + 1) * sizeof(lwc_string *), - state->computed->pw); + temp = realloc(fonts, (n_fonts + 1) * sizeof(lwc_string *)); if (temp == NULL) { - state->computed->alloc(fonts, 0, state->computed->pw); + free(fonts); return CSS_NOMEM; } @@ -126,9 +122,7 @@ css_error css__cascade_font_family(uint32_t opv, css_style *style, } if (hint.data.strings != NULL) { - state->computed->alloc( - hint.data.strings, - 0, state->computed->pw); + free(hint.data.strings); } } @@ -145,12 +139,12 @@ css_error css__cascade_font_family(uint32_t opv, css_style *style, error = set_font_family(state->computed, value, fonts); if (error != CSS_OK && n_fonts > 0) - state->computed->alloc(fonts, 0, state->computed->pw); + free(fonts); return error; } else { if (n_fonts > 0) - state->computed->alloc(fonts, 0, state->computed->pw); + free(fonts); } return CSS_OK; @@ -170,7 +164,7 @@ css_error css__set_font_family_from_hint(const css_hint *hint, } if (error != CSS_OK && hint->data.strings != NULL) - style->alloc(hint->data.strings, 0, style->pw); + free(hint->data.strings); return error; } @@ -209,9 +203,7 @@ css_error css__compose_font_family(const css_computed_style *parent, for (i = names; (*i) != NULL; i++) n_names++; - copy = result->alloc(NULL, (n_names + 1) * - sizeof(lwc_string *), - result->pw); + copy = malloc((n_names + 1) * sizeof(lwc_string *)); if (copy == NULL) return CSS_NOMEM; @@ -221,7 +213,7 @@ css_error css__compose_font_family(const css_computed_style *parent, error = set_font_family(result, type, copy); if (error != CSS_OK && copy != NULL) - result->alloc(copy, 0, result->pw); + free(copy); return error; } diff --git a/src/select/properties/helpers.c b/src/select/properties/helpers.c index 28ecdcc..df076db 100644 --- a/src/select/properties/helpers.c +++ b/src/select/properties/helpers.c @@ -421,14 +421,12 @@ css_error css__cascade_counter_increment_reset(uint32_t opv, css_style *style, val = *((css_fixed *) style->bytecode); advance_bytecode(style, sizeof(css_code_t)); - temp = state->computed->alloc(counters, + temp = realloc(counters, (n_counters + 1) * - sizeof(css_computed_counter), - state->computed->pw); + sizeof(css_computed_counter)); if (temp == NULL) { if (counters != NULL) { - state->computed->alloc(counters, - 0, state->computed->pw); + free(counters); } return CSS_NOMEM; } @@ -455,11 +453,10 @@ css_error css__cascade_counter_increment_reset(uint32_t opv, css_style *style, if (n_counters > 0) { css_computed_counter *temp; - temp = state->computed->alloc(counters, - (n_counters + 1) * sizeof(css_computed_counter), - state->computed->pw); + temp = realloc(counters, (n_counters + 1) * + sizeof(css_computed_counter)); if (temp == NULL) { - state->computed->alloc(counters, 0, state->computed->pw); + free(counters); return CSS_NOMEM; } @@ -475,11 +472,11 @@ css_error css__cascade_counter_increment_reset(uint32_t opv, css_style *style, error = fun(state->computed, value, counters); if (error != CSS_OK && n_counters > 0) - state->computed->alloc(counters, 0, state->computed->pw); + free(counters); return error; } else if (n_counters > 0) { - state->computed->alloc(counters, 0, state->computed->pw); + free(counters); } return CSS_OK; diff --git a/src/select/properties/quotes.c b/src/select/properties/quotes.c index 7671c1d..2dd6af4 100644 --- a/src/select/properties/quotes.c +++ b/src/select/properties/quotes.c @@ -30,19 +30,21 @@ css_error css__cascade_quotes(uint32_t opv, css_style *style, lwc_string *open, *close; lwc_string **temp; - css__stylesheet_string_get(style->sheet, *((css_code_t *) style->bytecode), &open); + css__stylesheet_string_get(style->sheet, + *((css_code_t *) style->bytecode), + &open); advance_bytecode(style, sizeof(css_code_t)); - css__stylesheet_string_get(style->sheet, *((css_code_t *) style->bytecode), &close); + css__stylesheet_string_get(style->sheet, + *((css_code_t *) style->bytecode), + &close); advance_bytecode(style, sizeof(css_code_t)); - temp = state->computed->alloc(quotes, - (n_quotes + 2) * sizeof(lwc_string *), - state->computed->pw); + temp = realloc(quotes, + (n_quotes + 2) * sizeof(lwc_string *)); if (temp == NULL) { if (quotes != NULL) { - state->computed->alloc(quotes, 0, - state->computed->pw); + free(quotes); } return CSS_NOMEM; } @@ -61,11 +63,9 @@ css_error css__cascade_quotes(uint32_t opv, css_style *style, if (n_quotes > 0) { lwc_string **temp; - temp = state->computed->alloc(quotes, - (n_quotes + 1) * sizeof(lwc_string *), - state->computed->pw); + temp = realloc(quotes, (n_quotes + 1) * sizeof(lwc_string *)); if (temp == NULL) { - state->computed->alloc(quotes, 0, state->computed->pw); + free(quotes); return CSS_NOMEM; } @@ -80,12 +80,12 @@ css_error css__cascade_quotes(uint32_t opv, css_style *style, error = set_quotes(state->computed, value, quotes); if (error != CSS_OK && quotes != NULL) - state->computed->alloc(quotes, 0, state->computed->pw); + free(quotes); return error; } else { if (quotes != NULL) - state->computed->alloc(quotes, 0, state->computed->pw); + free(quotes); } return CSS_OK; @@ -105,7 +105,7 @@ css_error css__set_quotes_from_hint(const css_hint *hint, } if (error != CSS_OK && hint->data.strings != NULL) - style->alloc(hint->data.strings, 0, style->pw); + free(hint->data.strings); return error; } @@ -145,9 +145,7 @@ css_error css__compose_quotes(const css_computed_style *parent, for (i = quotes; (*i) != NULL; i++) n_quotes++; - copy = result->alloc(NULL, (n_quotes + 1) * - sizeof(lwc_string *), - result->pw); + copy = malloc((n_quotes + 1) * sizeof(lwc_string *)); if (copy == NULL) return CSS_NOMEM; @@ -157,7 +155,7 @@ css_error css__compose_quotes(const css_computed_style *parent, error = set_quotes(result, type, copy); if (error != CSS_OK && copy != NULL) - result->alloc(copy, 0, result->pw); + free(copy); return error; } diff --git a/src/select/properties/voice_family.c b/src/select/properties/voice_family.c index e61d2c6..5c70d1e 100644 --- a/src/select/properties/voice_family.c +++ b/src/select/properties/voice_family.c @@ -31,7 +31,9 @@ css_error css__cascade_voice_family(uint32_t opv, css_style *style, switch (v) { case VOICE_FAMILY_STRING: case VOICE_FAMILY_IDENT_LIST: - css__stylesheet_string_get(style->sheet, *((css_code_t *) style->bytecode), &voice); + css__stylesheet_string_get(style->sheet, + *((css_code_t *) style->bytecode), + &voice); advance_bytecode(style, sizeof(css_code_t)); break; case VOICE_FAMILY_MALE: @@ -53,13 +55,11 @@ css_error css__cascade_voice_family(uint32_t opv, css_style *style, * first generic-family are ignored. */ /** \todo Do this at bytecode generation time? */ if (value == 0 && voice != NULL) { - temp = state->computed->alloc(voices, - (n_voices + 1) * sizeof(lwc_string *), - state->computed->pw); + temp = realloc(voices, + (n_voices + 1) * sizeof(lwc_string *)); if (temp == NULL) { if (voices != NULL) { - state->computed->alloc(voices, 0, - state->computed->pw); + free(voices); } return CSS_NOMEM; } @@ -80,11 +80,9 @@ css_error css__cascade_voice_family(uint32_t opv, css_style *style, if (n_voices > 0) { lwc_string **temp; - temp = state->computed->alloc(voices, - (n_voices + 1) * sizeof(lwc_string *), - state->computed->pw); + temp = realloc(voices, (n_voices + 1) * sizeof(lwc_string *)); if (temp == NULL) { - state->computed->alloc(voices, 0, state->computed->pw); + free(voices); return CSS_NOMEM; } @@ -97,10 +95,10 @@ css_error css__cascade_voice_family(uint32_t opv, css_style *style, isInherit(opv))) { /** \todo voice-family */ if (n_voices > 0) - state->computed->alloc(voices, 0, state->computed->pw); + free(voices); } else { if (n_voices > 0) - state->computed->alloc(voices, 0, state->computed->pw); + free(voices); } return CSS_OK; diff --git a/src/select/propset.h b/src/select/propset.h index ddd5642..5af7e8b 100644 --- a/src/select/propset.h +++ b/src/select/propset.h @@ -41,8 +41,7 @@ static const css_computed_uncommon default_uncommon = { #define ENSURE_UNCOMMON do { \ if (style->uncommon == NULL) { \ - style->uncommon = style->alloc(NULL, \ - sizeof(css_computed_uncommon), style->pw); \ + style->uncommon = malloc(sizeof(css_computed_uncommon));\ if (style->uncommon == NULL) \ return CSS_NOMEM; \ \ @@ -65,8 +64,7 @@ static const css_computed_page default_page = { #define ENSURE_PAGE do { \ if (style->page == NULL) { \ - style->page = style->alloc(NULL, \ - sizeof(css_computed_page), style->pw); \ + style->page = malloc(sizeof(css_computed_page)); \ if (style->page == NULL) \ return CSS_NOMEM; \ \ @@ -264,7 +262,7 @@ static inline css_error set_counter_increment( lwc_string_unref(c->name); if (oldcounters != counters) - style->alloc(oldcounters, 0, style->pw); + free(oldcounters); } return CSS_OK; @@ -304,7 +302,7 @@ static inline css_error set_counter_reset( lwc_string_unref(c->name); if (oldcounters != counters) - style->alloc(oldcounters, 0, style->pw); + free(oldcounters); } return CSS_OK; @@ -344,7 +342,7 @@ static inline css_error set_cursor( lwc_string_unref(*s); if (oldurls != urls) - style->alloc(oldurls, 0, style->pw); + free(oldurls); } return CSS_OK; @@ -482,7 +480,7 @@ static inline css_error set_content( } if (oldcontent != content) - style->alloc(oldcontent, 0, style->pw); + free(oldcontent); } return CSS_OK; @@ -717,7 +715,7 @@ static inline css_error set_quotes( lwc_string_unref(*s); if (oldquotes != quotes) - style->alloc(oldquotes, 0, style->pw); + free(oldquotes); } return CSS_OK; @@ -1641,7 +1639,7 @@ static inline css_error set_font_family( lwc_string_unref(*s); if (oldnames != names) - style->alloc(oldnames, 0, style->pw); + free(oldnames); } return CSS_OK; diff --git a/src/select/select.c b/src/select/select.c index c8567f8..06ed2bf 100644 --- a/src/select/select.c +++ b/src/select/select.c @@ -44,8 +44,7 @@ struct css_select_ctx { css_select_sheet *sheets; /**< Array of sheets */ - css_allocator_fn alloc; /**< Allocation routine */ - void *pw; /**< Client-specific private data */ + void *pw; /**< Client's private selection context */ /* Useful interned strings */ lwc_string *universal; @@ -141,7 +140,7 @@ static css_error match_detail(css_select_ctx *ctx, void *node, bool *match, css_pseudo_element *pseudo_element); static css_error cascade_style(const css_style *style, css_select_state *state); -static css_error select_font_faces_from_sheet(css_select_ctx *ctx, +static css_error select_font_faces_from_sheet( const css_stylesheet *sheet, css_origin origin, css_select_font_faces_state *state); @@ -151,24 +150,87 @@ static void dump_chain(const css_selector *selector); #endif +/* Exported function documented in public select.h header. */ +css_error css_libcss_node_data_handler(css_select_handler *handler, + css_node_data_action action, void *pw, void *node, + void *clone_node, void *libcss_node_data) +{ + css_bloom *bloom = libcss_node_data; + css_bloom *clone_bloom = NULL; + css_error error; + unsigned int i; + + if (handler == NULL || libcss_node_data == NULL || + handler->handler_version != CSS_SELECT_HANDLER_VERSION_1) { + return CSS_BADPARM; + } + + switch (action) { + case CSS_NODE_DELETED: + free(bloom); + break; + + case CSS_NODE_MODIFIED: + case CSS_NODE_ANCESTORS_MODIFIED: + if (node == NULL) { + return CSS_BADPARM; + } + + free(bloom); + + /* Don't bother rebuilding bloom here, it can be done + * when the node is selected for. Just ensure the + * client drops its reference to the libcss_node_data. */ + error = handler->set_libcss_node_data(pw, node, NULL); + if (error != CSS_OK) { + return error; + } + break; + + case CSS_NODE_CLONED: + if (node == NULL || clone_node == NULL) { + return CSS_BADPARM; + } + + clone_bloom = malloc(sizeof(css_bloom) * CSS_BLOOM_SIZE); + if (clone_bloom == NULL) { + return CSS_NOMEM; + } + + for (i = 0; i < CSS_BLOOM_SIZE; i++) { + clone_bloom[i] = bloom[i]; + } + + error = handler->set_libcss_node_data(pw, clone_node, + clone_bloom); + if (error != CSS_OK) { + free(clone_bloom); + return error; + } + break; + + default: + return CSS_BADPARM; + } + + return CSS_OK; +} + /** * Create a selection context * - * \param alloc Memory (de)allocation function - * \param pw Client-specific private data * \param result Pointer to location to receive created context * \return CSS_OK on success, appropriate error otherwise. */ -css_error css_select_ctx_create(css_allocator_fn alloc, void *pw, - css_select_ctx **result) +css_error css_select_ctx_create(css_select_ctx **result) { css_select_ctx *c; css_error error; - if (alloc == NULL || result == NULL) + if (result == NULL) return CSS_BADPARM; - c = alloc(NULL, sizeof(css_select_ctx), pw); + c = malloc(sizeof(css_select_ctx)); if (c == NULL) return CSS_NOMEM; @@ -176,13 +238,10 @@ css_error css_select_ctx_create(css_allocator_fn alloc, void *pw, error = intern_strings(c); if (error != CSS_OK) { - alloc(c, 0, pw); + free(c); return error; } - c->alloc = alloc; - c->pw = pw; - *result = c; return CSS_OK; @@ -202,9 +261,9 @@ css_error css_select_ctx_destroy(css_select_ctx *ctx) destroy_strings(ctx); if (ctx->sheets != NULL) - ctx->alloc(ctx->sheets, 0, ctx->pw); + free(ctx->sheets); - ctx->alloc(ctx, 0, ctx->pw); + free(ctx); return CSS_OK; } @@ -257,9 +316,8 @@ css_error css_select_ctx_insert_sheet(css_select_ctx *ctx, if (index > ctx->n_sheets) return CSS_INVALID; - temp = ctx->alloc(ctx->sheets, - (ctx->n_sheets + 1) * sizeof(css_select_sheet), - ctx->pw); + temp = realloc(ctx->sheets, + (ctx->n_sheets + 1) * sizeof(css_select_sheet)); if (temp == NULL) return CSS_NOMEM; @@ -373,7 +431,6 @@ css_error css_select_ctx_get_sheet(css_select_ctx *ctx, uint32_t index, * update the fully computed style for a node when layout changes. */ css_error css_select_style(css_select_ctx *ctx, void *node, - const css_bloom bloom[CSS_BLOOM_SIZE], uint64_t media, const css_stylesheet *inline_style, css_select_handler *handler, void *pw, css_select_results **result) @@ -382,10 +439,11 @@ css_error css_select_style(css_select_ctx *ctx, void *node, css_error error; css_select_state state; void *parent = NULL; + css_bloom *bloom = NULL; + css_bloom *parent_bloom = NULL; if (ctx == NULL || node == NULL || result == NULL || handler == NULL || - handler->handler_version != - CSS_SELECT_HANDLER_VERSION_1) + handler->handler_version != CSS_SELECT_HANDLER_VERSION_1) return CSS_BADPARM; /* Set up the selection state */ @@ -396,31 +454,68 @@ css_error css_select_style(css_select_ctx *ctx, void *node, state.pw = pw; state.next_reject = state.reject_cache + (N_ELEMENTS(state.reject_cache) - 1); - state.bloom = bloom; /* Allocate the result set */ - state.results = ctx->alloc(NULL, sizeof(css_select_results), ctx->pw); + state.results = malloc(sizeof(css_select_results)); if (state.results == NULL) return CSS_NOMEM; - state.results->alloc = ctx->alloc; - state.results->pw = ctx->pw; - for (i = 0; i < CSS_PSEUDO_ELEMENT_COUNT; i++) state.results->styles[i] = NULL; /* Base element style is guaranteed to exist */ - error = css_computed_style_create(ctx->alloc, ctx->pw, + error = css_computed_style_create( &state.results->styles[CSS_PSEUDO_ELEMENT_NONE]); if (error != CSS_OK) { - ctx->alloc(state.results, 0, ctx->pw); + free(state.results); return error; } + /* Create the node's bloom */ + bloom = calloc(sizeof(css_bloom), CSS_BLOOM_SIZE); + if (bloom == NULL) { + error = CSS_NOMEM; + goto cleanup; + } + error = handler->parent_node(pw, node, &parent); if (error != CSS_OK) goto cleanup; + /* Get parent node's bloom filter */ + if (parent != NULL) { + /* Get parent bloom filter */ + error = handler->get_libcss_node_data(pw, parent, + (void **) &state.bloom); + if (error != CSS_OK) + goto cleanup; + /* TODO: + * If state.bloom == NULL, build and set parent bloom. + */ + } + + if (state.bloom == NULL) { + /* Need to create parent bloom */ + parent_bloom = malloc(sizeof(css_bloom) * CSS_BLOOM_SIZE); + if (parent_bloom == NULL) { + error = CSS_NOMEM; + goto cleanup; + } + if (parent != NULL) { + /* Have to make up fully saturated bloom filter */ + for (i = 0; i < CSS_BLOOM_SIZE; i++) { + parent_bloom[i] = ~0; + } + } else { + /* Empty bloom filter */ + for (i = 0; i < CSS_BLOOM_SIZE; i++) { + parent_bloom[i] = 0; + } + } + + state.bloom = parent_bloom; + } + /* Get node's name */ error = handler->node_name(pw, node, &state.element); if (error != CSS_OK) @@ -432,10 +527,7 @@ css_error css_select_style(css_select_ctx *ctx, void *node, goto cleanup; /* Get node's classes, if any */ - /** \todo Do we really want to force the client to allocate a new array - * every time we call this? It seems hugely inefficient, given they can - * cache the data. */ - error = handler->node_classes(pw, node, + error = handler->node_classes(pw, node, &state.classes, &state.n_classes); if (error != CSS_OK) goto cleanup; @@ -550,6 +642,57 @@ css_error css_select_style(css_select_ctx *ctx, void *node, goto cleanup; } + /* Add node name to bloom */ + if (state.element.name->insensitive == NULL) { + if (lwc__intern_caseless_string( + state.element.name) != lwc_error_ok) { + error = CSS_NOMEM; + goto cleanup; + } + } + css_bloom_add_hash(bloom, lwc_string_hash_value( + state.element.name->insensitive)); + + /* Add id name to bloom */ + if (state.id != NULL) { + if (state.id->insensitive == NULL) { + if (lwc__intern_caseless_string(state.id) != + lwc_error_ok) { + error = CSS_NOMEM; + goto cleanup; + } + } + css_bloom_add_hash(bloom, lwc_string_hash_value( + state.id->insensitive)); + } + + /* Add class names to bloom */ + if (state.classes != NULL) { + lwc_string *s; + for (i = 0; i < state.n_classes; i++) { + s = state.classes[i]; + if (s->insensitive == NULL) { + if (lwc__intern_caseless_string(s) != + lwc_error_ok) { + error = CSS_NOMEM; + goto cleanup; + } + } + css_bloom_add_hash(bloom, lwc_string_hash_value( + s->insensitive)); + } + } + + /* Merge parent bloom into node bloom */ + css_bloom_merge(state.bloom, bloom); + + /* Set node bloom filter */ + error = handler->set_libcss_node_data(pw, node, bloom); + if (error != CSS_OK) + goto cleanup; + + bloom = NULL; + *result = state.results; error = CSS_OK; @@ -561,11 +704,17 @@ cleanup: css_select_results_destroy(state.results); } + if (parent_bloom != NULL) { + free(parent_bloom); + } + + if (bloom != NULL) { + free(bloom); + } + if (state.classes != NULL) { for (i = 0; i < state.n_classes; i++) lwc_string_unref(state.classes[i]); - - ctx->alloc(state.classes, 0, ctx->pw); } if (state.id != NULL) @@ -596,7 +745,7 @@ css_error css_select_results_destroy(css_select_results *results) css_computed_style_destroy(results->styles[i]); } - results->alloc(results, 0, results->pw); + free(results); return CSS_OK; } @@ -634,7 +783,7 @@ css_error css_select_font_faces(css_select_ctx *ctx, if ((s.media & media) != 0 && s.sheet->disabled == false) { - error = select_font_faces_from_sheet(ctx, s.sheet, + error = select_font_faces_from_sheet(s.sheet, s.origin, &state); if (error != CSS_OK) goto cleanup; @@ -651,22 +800,16 @@ css_error css_select_font_faces(css_select_ctx *ctx, * the font faces in priority order. */ css_select_font_faces_results *results; - results = ctx->alloc(NULL, - sizeof(css_select_font_faces_results), - ctx->pw); + results = malloc(sizeof(css_select_font_faces_results)); if (results == NULL) { error = CSS_NOMEM; goto cleanup; } - results->alloc = ctx->alloc; - results->pw = ctx->pw; - - results->font_faces = ctx->alloc(NULL, - n_font_faces * sizeof(css_font_face *), - ctx->pw); + results->font_faces = malloc( + n_font_faces * sizeof(css_font_face *)); if (results->font_faces == NULL) { - ctx->alloc(results, 0, ctx->pw); + free(results); error = CSS_NOMEM; goto cleanup; } @@ -705,13 +848,13 @@ css_error css_select_font_faces(css_select_ctx *ctx, cleanup: if (state.ua_font_faces.count != 0) - ctx->alloc(state.ua_font_faces.font_faces, 0, ctx->pw); + free(state.ua_font_faces.font_faces); if (state.user_font_faces.count != 0) - ctx->alloc(state.user_font_faces.font_faces, 0, ctx->pw); + free(state.user_font_faces.font_faces); if (state.author_font_faces.count != 0) - ctx->alloc(state.author_font_faces.font_faces, 0, ctx->pw); + free(state.author_font_faces.font_faces); return error; } @@ -731,10 +874,10 @@ css_error css_select_font_faces_results_destroy( if (results->font_faces != NULL) { /* Don't destroy the individual css_font_faces, they're owned by their respective sheets */ - results->alloc(results->font_faces, 0, results->pw); + free(results->font_faces); } - results->alloc(results, 0, results->pw); + free(results); return CSS_OK; } @@ -1136,7 +1279,7 @@ static inline bool _rule_applies_to_media(const css_rule *rule, uint64_t media) return applies; } -static css_error _select_font_face_from_rule(css_select_ctx *ctx, +static css_error _select_font_face_from_rule( const css_rule_font_face *rule, css_origin origin, css_select_font_faces_state *state) { @@ -1168,8 +1311,7 @@ static css_error _select_font_face_from_rule(css_select_ctx *ctx, index = faces->count++; new_size = faces->count * sizeof(css_font_face *); - new_faces = ctx->alloc(faces->font_faces, - new_size, ctx->pw); + new_faces = realloc(faces->font_faces, new_size); if (new_faces == NULL) { faces->count = 0; return CSS_NOMEM; @@ -1183,7 +1325,7 @@ static css_error _select_font_face_from_rule(css_select_ctx *ctx, return CSS_OK; } -static css_error select_font_faces_from_sheet(css_select_ctx *ctx, +static css_error select_font_faces_from_sheet( const css_stylesheet *sheet, css_origin origin, css_select_font_faces_state *state) @@ -1223,7 +1365,6 @@ static css_error select_font_faces_from_sheet(css_select_ctx *ctx, css_error error; error = _select_font_face_from_rule( - ctx, (const css_rule_font_face *) rule, origin, state); @@ -1367,9 +1508,7 @@ css_error match_selectors_in_sheet(css_select_ctx *ctx, if (state->classes != NULL && n_classes > 0) { /* Find hash chains for node classes */ - class_selectors = ctx->alloc(NULL, - n_classes * sizeof(css_selector **), - ctx->pw); + class_selectors = malloc(n_classes * sizeof(css_selector **)); if (class_selectors == NULL) { error = CSS_NOMEM; goto cleanup; @@ -1455,7 +1594,7 @@ css_error match_selectors_in_sheet(css_select_ctx *ctx, error = CSS_OK; cleanup: if (class_selectors != NULL) - ctx->alloc(class_selectors, 0, ctx->pw); + free(class_selectors); return error; } @@ -1571,7 +1710,7 @@ css_error match_selector_chain(css_select_ctx *ctx, /* Ensure that the appropriate computed style exists */ if (state->results->styles[pseudo] == NULL) { - error = css_computed_style_create(ctx->alloc, ctx->pw, + error = css_computed_style_create( &state->results->styles[pseudo]); if (error != CSS_OK) return error; diff --git a/src/select/select.h b/src/select/select.h index 43c29d2..fad86ac 100644 --- a/src/select/select.h +++ b/src/select/select.h @@ -69,8 +69,8 @@ static inline void advance_bytecode(css_style *style, uint32_t n_bytes) style->bytecode = style->bytecode + (n_bytes / sizeof(css_code_t)); } -bool css__outranks_existing(uint16_t op, bool important, css_select_state *state, - bool inherit); +bool css__outranks_existing(uint16_t op, bool important, + css_select_state *state, bool inherit); #endif diff --git a/src/stylesheet.c b/src/stylesheet.c index c724864..0a281e7 100644 --- a/src/stylesheet.c +++ b/src/stylesheet.c @@ -71,7 +71,8 @@ css_error css__stylesheet_string_add(css_stylesheet *sheet, lwc_string *string, uint32_t new_vector_len; new_vector_len = sheet->string_vector_l + 256; - new_vector = sheet->alloc(sheet->string_vector, new_vector_len * sizeof(lwc_string *), sheet->pw); + new_vector = realloc(sheet->string_vector, + new_vector_len * sizeof(lwc_string *)); if (new_vector == NULL) { lwc_string_unref(string); @@ -97,7 +98,8 @@ css_error css__stylesheet_string_add(css_stylesheet *sheet, lwc_string *string, * \return CSS_OK on success, * CSS_BADPARM on bad parameters, */ -css_error css__stylesheet_string_get(css_stylesheet *sheet, uint32_t string_number, lwc_string **string) +css_error css__stylesheet_string_get(css_stylesheet *sheet, + uint32_t string_number, lwc_string **string) { /* External string numbers = index into vector + 1 */ string_number--; @@ -114,37 +116,31 @@ css_error css__stylesheet_string_get(css_stylesheet *sheet, uint32_t string_numb * Create a stylesheet * * \param params Stylesheet parameters - * \param alloc Memory (de)allocation function - * \param alloc_pw Client private data for alloc * \param stylesheet Pointer to location to receive stylesheet * \return CSS_OK on success, * CSS_BADPARM on bad parameters, * CSS_NOMEM on memory exhaustion */ css_error css_stylesheet_create(const css_stylesheet_params *params, - css_allocator_fn alloc, void *alloc_pw, css_stylesheet **stylesheet) { css_parser_optparams optparams; css_error error; css_stylesheet *sheet; - size_t len; if (params == NULL || params->params_version != CSS_STYLESHEET_PARAMS_VERSION_1 || - params->url == NULL || alloc == NULL || - params->resolve == NULL || stylesheet == NULL) + params->url == NULL || params->resolve == NULL || + stylesheet == NULL) return CSS_BADPARM; - sheet = alloc(NULL, sizeof(css_stylesheet), alloc_pw); + sheet = calloc(1, sizeof(css_stylesheet)); if (sheet == NULL) return CSS_NOMEM; - memset(sheet, 0, sizeof(css_stylesheet)); - error = css__propstrings_get(&sheet->propstrings); if (error != CSS_OK) { - alloc(sheet, 0, alloc_pw); + free(sheet); return error; } @@ -152,19 +148,19 @@ css_error css_stylesheet_create(const css_stylesheet_params *params, if (params->inline_style) { error = css__parser_create_for_inline_style(params->charset, - params->charset != NULL - ? CSS_CHARSET_DICTATED : CSS_CHARSET_DEFAULT, - alloc, alloc_pw, &sheet->parser); + (params->charset != NULL) ? + CSS_CHARSET_DICTATED : CSS_CHARSET_DEFAULT, + &sheet->parser); } else { error = css__parser_create(params->charset, - params->charset != NULL - ? CSS_CHARSET_DICTATED : CSS_CHARSET_DEFAULT, - alloc, alloc_pw, &sheet->parser); + (params->charset != NULL) ? + CSS_CHARSET_DICTATED : CSS_CHARSET_DEFAULT, + &sheet->parser); } if (error != CSS_OK) { css__propstrings_unref(); - alloc(sheet, 0, alloc_pw); + free(sheet); return error; } @@ -178,56 +174,51 @@ css_error css_stylesheet_create(const css_stylesheet_params *params, if (error != CSS_OK) { css__parser_destroy(sheet->parser); css__propstrings_unref(); - alloc(sheet, 0, alloc_pw); + free(sheet); return error; } } sheet->level = params->level; - error = css__language_create(sheet, sheet->parser, alloc, alloc_pw, + error = css__language_create(sheet, sheet->parser, &sheet->parser_frontend); if (error != CSS_OK) { css__parser_destroy(sheet->parser); css__propstrings_unref(); - alloc(sheet, 0, alloc_pw); + free(sheet); return error; } - error = css__selector_hash_create(alloc, alloc_pw, - &sheet->selectors); + error = css__selector_hash_create(&sheet->selectors); if (error != CSS_OK) { css__language_destroy(sheet->parser_frontend); css__parser_destroy(sheet->parser); css__propstrings_unref(); - alloc(sheet, 0, alloc_pw); + free(sheet); return error; } - len = strlen(params->url) + 1; - sheet->url = alloc(NULL, len, alloc_pw); + sheet->url = strdup(params->url); if (sheet->url == NULL) { css__selector_hash_destroy(sheet->selectors); css__language_destroy(sheet->parser_frontend); css__parser_destroy(sheet->parser); css__propstrings_unref(); - alloc(sheet, 0, alloc_pw); + free(sheet); return CSS_NOMEM; } - memcpy(sheet->url, params->url, len); if (params->title != NULL) { - len = strlen(params->title) + 1; - sheet->title = alloc(NULL, len, alloc_pw); + sheet->title = strdup(params->title); if (sheet->title == NULL) { - alloc(sheet->url, 0, alloc_pw); + free(sheet->url); css__selector_hash_destroy(sheet->selectors); css__language_destroy(sheet->parser_frontend); css__parser_destroy(sheet->parser); css__propstrings_unref(); - alloc(sheet, 0, alloc_pw); + free(sheet); return CSS_NOMEM; } - memcpy(sheet->title, params->title, len); } sheet->resolve = params->resolve; @@ -242,9 +233,6 @@ css_error css_stylesheet_create(const css_stylesheet_params *params, sheet->font = params->font; sheet->font_pw = params->font_pw; - sheet->alloc = alloc; - sheet->pw = alloc_pw; - sheet->size = sizeof(css_stylesheet) + strlen(sheet->url); if (sheet->title != NULL) sheet->size += strlen(sheet->title); @@ -269,9 +257,9 @@ css_error css_stylesheet_destroy(css_stylesheet *sheet) return CSS_BADPARM; if (sheet->title != NULL) - sheet->alloc(sheet->title, 0, sheet->pw); + free(sheet->title); - sheet->alloc(sheet->url, 0, sheet->pw); + free(sheet->url); for (r = sheet->rule_list; r != NULL; r = s) { s = r->next; @@ -297,18 +285,16 @@ css_error css_stylesheet_destroy(css_stylesheet *sheet) css__stylesheet_style_destroy(sheet->cached_style); /* destroy string vector */ - for (index = 0; - index < sheet->string_vector_c; - index++) { + for (index = 0; index < sheet->string_vector_c; index++) { lwc_string_unref(sheet->string_vector[index]); } if (sheet->string_vector != NULL) - sheet->alloc(sheet->string_vector, 0, sheet->pw); + free(sheet->string_vector); css__propstrings_unref(); - sheet->alloc(sheet, 0, sheet->pw); + free(sheet); return CSS_OK; } @@ -664,14 +650,14 @@ css_error css__stylesheet_style_create(css_stylesheet *sheet, css_style **style) return CSS_OK; } - s = sheet->alloc(NULL, sizeof(css_style), sheet->pw); + s = malloc(sizeof(css_style)); if (s == NULL) return CSS_NOMEM; - s->bytecode = sheet->alloc(NULL, sizeof(css_code_t) * CSS_STYLE_DEFAULT_SIZE, sheet->pw); + s->bytecode = malloc(sizeof(css_code_t) * CSS_STYLE_DEFAULT_SIZE); if (s->bytecode == NULL) { - sheet->alloc(s, 0, sheet->pw); /* do not leak */ + free(s); /* do not leak */ return CSS_NOMEM; } @@ -688,18 +674,17 @@ css_error css__stylesheet_merge_style(css_style *target, css_style *style) { css_code_t *newcode; uint32_t newcode_len; - css_stylesheet *sheet; if (target == NULL || style == NULL) return CSS_BADPARM; - sheet = target->sheet; newcode_len = target->used + style->used ; if (newcode_len > target->allocated) { newcode_len += CSS_STYLE_DEFAULT_SIZE - 1; newcode_len &= ~(CSS_STYLE_DEFAULT_SIZE - 1); - newcode = sheet->alloc(target->bytecode, newcode_len * sizeof(css_code_t), sheet->pw); + newcode = realloc(target->bytecode, + newcode_len * sizeof(css_code_t)); if (newcode == NULL) return CSS_NOMEM; @@ -708,7 +693,8 @@ css_error css__stylesheet_merge_style(css_style *target, css_style *style) target->allocated = newcode_len; } - memcpy(target->bytecode + target->used, style->bytecode, style->used * sizeof(css_code_t)); + memcpy(target->bytecode + target->used, style->bytecode, + style->used * sizeof(css_code_t)); target->used += style->used; @@ -738,18 +724,15 @@ css_error css__stylesheet_style_vappend(css_style *style, uint32_t style_count, /** append a css code entry to a style */ css_error css__stylesheet_style_append(css_style *style, css_code_t css_code) { - css_stylesheet *sheet; - if (style == NULL) return CSS_BADPARM; - sheet = style->sheet; - if (style->allocated == style->used) { /* space not available to append, extend allocation */ css_code_t *newcode; uint32_t newcode_len = style->allocated * 2; - newcode = sheet->alloc(style->bytecode, sizeof(css_code_t) * newcode_len, sheet->pw); + newcode = realloc(style->bytecode, + sizeof(css_code_t) * newcode_len); if (newcode == NULL) return CSS_NOMEM; style->bytecode = newcode; @@ -782,13 +765,13 @@ css_error css__stylesheet_style_destroy(css_style *style) sheet->cached_style = style; style->used = 0; } else if (sheet->cached_style->allocated < style->allocated) { - sheet->alloc(sheet->cached_style->bytecode, 0, sheet->pw); - sheet->alloc(sheet->cached_style, 0, sheet->pw); + free(sheet->cached_style->bytecode); + free(sheet->cached_style); sheet->cached_style = style; style->used = 0; } else { - sheet->alloc(style->bytecode, 0, sheet->pw); - sheet->alloc(style, 0, sheet->pw); + free(style->bytecode); + free(style); } return CSS_OK; @@ -813,7 +796,7 @@ css_error css__stylesheet_selector_create(css_stylesheet *sheet, selector == NULL) return CSS_BADPARM; - sel = sheet->alloc(NULL, sizeof(css_selector), sheet->pw); + sel = malloc(sizeof(css_selector)); if (sel == NULL) return CSS_NOMEM; @@ -886,7 +869,7 @@ css_error css__stylesheet_selector_destroy(css_stylesheet *sheet, detail = NULL; } - sheet->alloc(c, 0, sheet->pw); + free(c); } for (detail = &selector->data; detail;) { @@ -907,7 +890,7 @@ css_error css__stylesheet_selector_destroy(css_stylesheet *sheet, /* Destroy this selector */ - sheet->alloc(selector, 0, sheet->pw); + free(selector); return CSS_OK; } @@ -977,9 +960,8 @@ css_error css__stylesheet_selector_append_specific(css_stylesheet *sheet, num_details++; /* Grow selector by one detail block */ - temp = sheet->alloc((*parent), sizeof(css_selector) + - (num_details + 1) * sizeof(css_selector_detail), - sheet->pw); + temp = realloc((*parent), sizeof(css_selector) + + (num_details + 1) * sizeof(css_selector_detail)); if (temp == NULL) return CSS_NOMEM; @@ -1107,7 +1089,7 @@ css_error css__stylesheet_rule_create(css_stylesheet *sheet, css_rule_type type, break; } - r = sheet->alloc(NULL, required, sheet->pw); + r = malloc(required); if (r == NULL) return CSS_NOMEM; @@ -1155,7 +1137,7 @@ css_error css__stylesheet_rule_destroy(css_stylesheet *sheet, css_rule *rule) } if (s->selectors != NULL) - sheet->alloc(s->selectors, 0, sheet->pw); + free(s->selectors); if (s->style != NULL) css__stylesheet_style_destroy(s->style); @@ -1217,7 +1199,7 @@ css_error css__stylesheet_rule_destroy(css_stylesheet *sheet, css_rule *rule) } /* Destroy rule */ - sheet->alloc(rule, 0, sheet->pw); + free(rule); return CSS_OK; } @@ -1242,9 +1224,8 @@ css_error css__stylesheet_rule_add_selector(css_stylesheet *sheet, /* Ensure rule is a CSS_RULE_SELECTOR */ assert(rule->type == CSS_RULE_SELECTOR); - sels = sheet->alloc(r->selectors, - (r->base.items + 1) * sizeof(css_selector *), - sheet->pw); + sels = realloc(r->selectors, + (r->base.items + 1) * sizeof(css_selector *)); if (sels == NULL) return CSS_NOMEM; @@ -1564,7 +1545,8 @@ css_error _add_selectors(css_stylesheet *sheet, css_rule *rule) for (i = 0; i < rule->items; i++) { css_selector *sel = s->selectors[i]; - error = css__selector_hash_insert(sheet->selectors, sel); + error = css__selector_hash_insert( + sheet->selectors, sel); if (error != CSS_OK) { /* Failed, revert our changes */ for (i--; i >= 0; i--) { diff --git a/src/stylesheet.h b/src/stylesheet.h index d48d0a9..a2b3fd5 100644 --- a/src/stylesheet.h +++ b/src/stylesheet.h @@ -203,9 +203,6 @@ struct css_stylesheet { /** System font resolution function */ css_font_resolution_fn font; void *font_pw; /**< Private word */ - - css_allocator_fn alloc; /**< Allocation function */ - void *pw; /**< Private word */ css_style *cached_style; /**< Cache for style parsing */ diff --git a/src/utils/utils.c b/src/utils/utils.c index 1745ea0..1899b23 100644 --- a/src/utils/utils.c +++ b/src/utils/utils.c @@ -130,3 +130,19 @@ css_fixed css__number_from_string(const uint8_t *data, size_t len, return (intpart << 10) | fracpart; } + +/* Allocator to pass to libparserutils */ +void *css_alloc(void *data, size_t len, void *pw) +{ + UNUSED(pw); + + if (data == NULL) { + return (len > 0) ? malloc(len) : NULL; + } + if (len == 0) { + free(data); + return NULL; + } + return realloc(data, len); +} + diff --git a/src/utils/utils.h b/src/utils/utils.h index 1f7ed8c..3f7fcd0 100644 --- a/src/utils/utils.h +++ b/src/utils/utils.h @@ -62,8 +62,7 @@ static inline uint32_t charToHex(uint8_t c) return c; } -static inline css_error -css_error_from_lwc_error(lwc_error err) +static inline css_error css_error_from_lwc_error(lwc_error err) { switch (err) { case lwc_error_ok: @@ -78,4 +77,9 @@ css_error_from_lwc_error(lwc_error err) return CSS_INVALID; } + +/* Allocator to pass to libparserutils */ +#define CSS_ALLOC_PW NULL +void *css_alloc(void *data, size_t len, void *pw); + #endif diff --git a/test/INDEX b/test/INDEX index 1c776c6..cf1a3cb 100644 --- a/test/INDEX +++ b/test/INDEX @@ -1,17 +1,17 @@ # Index of testcases # -# Test Description DataDir +# Test Description DataDir -csdetect Character set detection csdetect -#lex Lexing css -lex-auto Automated lexer tests lex -number Conversion of numbers to fixed point number -#parse Parsing (core syntax) css -#css21 Parsing (CSS2.1 specifics) css -parse-auto Automated parser tests (bytecode) parse -parse2-auto Automated parser tests (om & invalid) parse2 -select-auto Automated selection engine tests select -sel-bloom-auto Automated selection tests with bloom select +csdetect Character set detection csdetect +#lex Lexing css +lex-auto Automated lexer tests lex +number Conversion of numbers to fixed point number +#parse Parsing (core syntax) css +#css21 Parsing (CSS2.1 specifics) css +parse-auto Automated parser tests (bytecode) parse +parse2-auto Automated parser tests (om & invalid) parse2 +select-no-nd Automated selection engine tests (no node_data) select +select-nd Automated selection engine tests (with node_data) select # Regression tests diff --git a/test/Makefile b/test/Makefile index 23d4442..021d829 100644 --- a/test/Makefile +++ b/test/Makefile @@ -2,6 +2,6 @@ DIR_TEST_ITEMS := csdetect:csdetect.c css21:css21.c lex:lex.c \ lex-auto:lex-auto.c number:number.c \ parse:parse.c parse-auto:parse-auto.c parse2-auto:parse2-auto.c \ - select-auto:select-auto.c sel-bloom-auto:select-bloom-auto.c + select-no-nd:select-no-nd.c select-nd:select-nd.c include $(NSBUILD)/Makefile.subdir diff --git a/test/css21.c b/test/css21.c index 7a2997a..cc9acab 100644 --- a/test/css21.c +++ b/test/css21.c @@ -13,13 +13,6 @@ #include "testutils.h" -static void *myrealloc(void *ptr, size_t len, void *pw) -{ - UNUSED(pw); - - return realloc(ptr, len); -} - static css_error resolve_url(void *pw, const char *base, lwc_string *rel, lwc_string **abs) { @@ -66,8 +59,7 @@ int main(int argc, char **argv) for (count = 0; count < ITERATIONS; count++) { - assert(css_stylesheet_create(¶ms, myrealloc, NULL, - &sheet) == CSS_OK); + assert(css_stylesheet_create(¶ms, &sheet) == CSS_OK); fp = fopen(argv[1], "rb"); if (fp == NULL) { @@ -124,7 +116,7 @@ int main(int argc, char **argv) params.url = buf; assert(css_stylesheet_create(¶ms, - myrealloc, NULL, &import) == CSS_OK); + &import) == CSS_OK); assert(css_stylesheet_data_done(import) == CSS_OK); diff --git a/test/lex-auto.c b/test/lex-auto.c index 62479a4..6b22f6f 100644 --- a/test/lex-auto.c +++ b/test/lex-auto.c @@ -277,7 +277,7 @@ void run_test(const uint8_t *data, size_t len, exp_entry *exp, size_t explen) css__charset_extract, myrealloc, NULL, &input) == PARSERUTILS_OK); - assert(css__lexer_create(input, myrealloc, NULL, &lexer) == CSS_OK); + assert(css__lexer_create(input, &lexer) == CSS_OK); assert(parserutils_inputstream_append(input, data, len) == PARSERUTILS_OK); diff --git a/test/lex.c b/test/lex.c index 0d42df4..2bce4c0 100644 --- a/test/lex.c +++ b/test/lex.c @@ -141,7 +141,7 @@ int main(int argc, char **argv) (parserutils_alloc) myrealloc, NULL, &stream) == PARSERUTILS_OK); - assert(css__lexer_create(stream, myrealloc, NULL, &lexer) == + assert(css__lexer_create(stream, &lexer) == CSS_OK); fp = fopen(argv[1], "rb"); diff --git a/test/parse-auto.c b/test/parse-auto.c index 0549f45..2bbe61e 100644 --- a/test/parse-auto.c +++ b/test/parse-auto.c @@ -60,13 +60,6 @@ static void dump_selector(css_selector *selector, char **ptr); static void dump_selector_detail(css_selector_detail *detail, char **ptr); static void dump_string(lwc_string *string, char **ptr); -static void *myrealloc(void *data, size_t len, void *pw) -{ - UNUSED(pw); - - return realloc(data, len); -} - static css_error resolve_url(void *pw, const char *base, lwc_string *rel, lwc_string **abs) { @@ -387,8 +380,7 @@ void run_test(const uint8_t *data, size_t len, exp_entry *exp, size_t explen) params.font = NULL; params.font_pw = NULL; - assert(css_stylesheet_create(¶ms, myrealloc, NULL, - &sheet) == CSS_OK); + assert(css_stylesheet_create(¶ms, &sheet) == CSS_OK); error = css_stylesheet_append_data(sheet, data, len); if (error != CSS_OK && error != CSS_NEEDDATA) { @@ -418,7 +410,7 @@ void run_test(const uint8_t *data, size_t len, exp_entry *exp, size_t explen) params.url = buf; assert(css_stylesheet_create(¶ms, - myrealloc, NULL, &import) == CSS_OK); + &import) == CSS_OK); assert(css_stylesheet_register_import(sheet, import) == CSS_OK); diff --git a/test/parse.c b/test/parse.c index 887eebc..dbbf91f 100644 --- a/test/parse.c +++ b/test/parse.c @@ -29,13 +29,6 @@ static const char *event_names[] = { }; #endif -static void *myrealloc(void *data, size_t len, void *pw) -{ - UNUSED(pw); - - return realloc(data, len); -} - static css_error event_handler(css_parser_event type, const parserutils_vector *tokens, void *pw) { @@ -91,7 +84,7 @@ int main(int argc, char **argv) for (i = 0; i < ITERATIONS; i++) { assert(css__parser_create("UTF-8", CSS_CHARSET_DICTATED, - myrealloc, NULL, &parser) == CSS_OK); + &parser) == CSS_OK); params.event_handler.handler = event_handler; params.event_handler.pw = NULL; diff --git a/test/parse2-auto.c b/test/parse2-auto.c index 2ae7cae..1d5ba57 100644 --- a/test/parse2-auto.c +++ b/test/parse2-auto.c @@ -34,13 +34,6 @@ static void css__parse_expected(line_ctx *ctx, const char *data, size_t len); static void run_test(const uint8_t *data, size_t len, const char *exp, size_t explen); -static void *myrealloc(void *data, size_t len, void *pw) -{ - UNUSED(pw); - - return realloc(data, len); -} - static css_error resolve_url(void *pw, const char *base, lwc_string *rel, lwc_string **abs) { @@ -212,8 +205,7 @@ void run_test(const uint8_t *data, size_t len, const char *exp, size_t explen) params.font = NULL; params.font_pw = NULL; - assert(css_stylesheet_create(¶ms, myrealloc, NULL, - &sheet) == CSS_OK); + assert(css_stylesheet_create(¶ms, &sheet) == CSS_OK); error = css_stylesheet_append_data(sheet, data, len); if (error != CSS_OK && error != CSS_NEEDDATA) { diff --git a/test/select-auto.c b/test/select-auto.c deleted file mode 100644 index 9c1a52b..0000000 --- a/test/select-auto.c +++ /dev/null @@ -1,1586 +0,0 @@ -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include - -#include "utils/utils.h" - -#include "dump_computed.h" -#include "testutils.h" - -typedef struct attribute { - lwc_string *name; - lwc_string *value; -} attribute; - -typedef struct node { - lwc_string *name; - - uint32_t n_attrs; - attribute *attrs; - - struct node *parent; - struct node *next; - struct node *prev; - struct node *children; - struct node *last_child; -} node; - -typedef struct sheet_ctx { - css_stylesheet *sheet; - css_origin origin; - uint64_t media; -} sheet_ctx; - -typedef struct line_ctx { - size_t explen; - size_t expused; - char *exp; - - bool intree; - bool insheet; - bool inerrors; - bool inexp; - - node *tree; - node *current; - uint32_t depth; - - uint32_t n_sheets; - sheet_ctx *sheets; - - uint64_t media; - uint32_t pseudo_element; - node *target; - - lwc_string *attr_class; - lwc_string *attr_id; -} line_ctx; - -static bool handle_line(const char *data, size_t datalen, void *pw); -static void css__parse_tree(line_ctx *ctx, const char *data, size_t len); -static void css__parse_tree_data(line_ctx *ctx, const char *data, size_t len); -static void css__parse_sheet(line_ctx *ctx, const char *data, size_t len); -static void css__parse_media_list(const char **data, size_t *len, uint64_t *media); -static void css__parse_pseudo_list(const char **data, size_t *len, - uint32_t *element); -static void css__parse_expected(line_ctx *ctx, const char *data, size_t len); -static void run_test(line_ctx *ctx, const char *exp, size_t explen); -static void destroy_tree(node *root); - -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_ancestor_node(void *pw, void *node, - const css_qname *qname, - void **ancestor); -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_visited(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 node_presentational_hint(void *pw, void *node, - uint32_t property, css_hint *hint); -static css_error ua_default_for_property(void *pw, uint32_t property, - css_hint *hint); -static css_error compute_font_size(void *pw, const css_hint *parent, - css_hint *size); - -static css_select_handler select_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, - compute_font_size -}; - -static void *myrealloc(void *data, size_t len, void *pw) -{ - UNUSED(pw); - - return realloc(data, len); -} - -static css_error resolve_url(void *pw, - const char *base, lwc_string *rel, lwc_string **abs) -{ - UNUSED(pw); - UNUSED(base); - - /* About as useless as possible */ - *abs = lwc_string_ref(rel); - - return CSS_OK; -} - -static bool fail_because_lwc_leaked = false; - -static void -printing_lwc_iterator(lwc_string *str, void *pw) -{ - UNUSED(pw); - - printf(" DICT: %*s\n", (int)(lwc_string_length(str)), lwc_string_data(str)); - fail_because_lwc_leaked = true; -} - -int main(int argc, char **argv) -{ - line_ctx ctx; - - if (argc != 2) { - printf("Usage: %s \n", argv[0]); - return 1; - } - - memset(&ctx, 0, sizeof(ctx)); - - - lwc_intern_string("class", SLEN("class"), &ctx.attr_class); - lwc_intern_string("id", SLEN("id"), &ctx.attr_id); - - assert(css__parse_testfile(argv[1], handle_line, &ctx) == true); - - /* and run final test */ - if (ctx.tree != NULL) - run_test(&ctx, ctx.exp, ctx.expused); - - free(ctx.exp); - - lwc_string_unref(ctx.attr_class); - lwc_string_unref(ctx.attr_id); - - lwc_iterate_strings(printing_lwc_iterator, NULL); - - assert(fail_because_lwc_leaked == false); - - printf("PASS\n"); - return 0; -} - -bool handle_line(const char *data, size_t datalen, void *pw) -{ - line_ctx *ctx = (line_ctx *) pw; - css_error error; - - if (data[0] == '#') { - if (ctx->intree) { - if (strncasecmp(data+1, "errors", 6) == 0) { - ctx->intree = false; - ctx->insheet = false; - ctx->inerrors = true; - ctx->inexp = false; - } else { - /* Assume start of stylesheet */ - css__parse_sheet(ctx, data + 1, datalen - 1); - - ctx->intree = false; - ctx->insheet = true; - ctx->inerrors = false; - ctx->inexp = false; - } - } else if (ctx->insheet) { - if (strncasecmp(data+1, "errors", 6) == 0) { - assert(css_stylesheet_data_done( - ctx->sheets[ctx->n_sheets - 1].sheet) - == CSS_OK); - - ctx->intree = false; - ctx->insheet = false; - ctx->inerrors = true; - ctx->inexp = false; - } else if (strncasecmp(data+1, "ua", 2) == 0 || - strncasecmp(data+1, "user", 4) == 0 || - strncasecmp(data+1, "author", 6) == 0) { - assert(css_stylesheet_data_done( - ctx->sheets[ctx->n_sheets - 1].sheet) - == CSS_OK); - - css__parse_sheet(ctx, data + 1, datalen - 1); - } else { - error = css_stylesheet_append_data( - ctx->sheets[ctx->n_sheets - 1].sheet, - (const uint8_t *) data, - datalen); - assert(error == CSS_OK || - error == CSS_NEEDDATA); - } - } else if (ctx->inerrors) { - ctx->intree = false; - ctx->insheet = false; - ctx->inerrors = false; - ctx->inexp = true; - } else if (ctx->inexp) { - /* This marks end of testcase, so run it */ - run_test(ctx, ctx->exp, ctx->expused); - - ctx->expused = 0; - - ctx->intree = false; - ctx->insheet = false; - ctx->inerrors = false; - ctx->inexp = false; - } else { - /* Start state */ - if (strncasecmp(data+1, "tree", 4) == 0) { - css__parse_tree(ctx, data + 5, datalen - 5); - - ctx->intree = true; - ctx->insheet = false; - ctx->inerrors = false; - ctx->inexp = false; - } - } - } else { - if (ctx->intree) { - /* Not interested in the '|' */ - css__parse_tree_data(ctx, data + 1, datalen - 1); - } else if (ctx->insheet) { - error = css_stylesheet_append_data( - ctx->sheets[ctx->n_sheets - 1].sheet, - (const uint8_t *) data, datalen); - assert(error == CSS_OK || error == CSS_NEEDDATA); - } else if (ctx->inexp) { - css__parse_expected(ctx, data, datalen); - } - } - - return true; -} - -void css__parse_tree(line_ctx *ctx, const char *data, size_t len) -{ - const char *p = data; - const char *end = data + len; - size_t left; - - /* [ ? ] ? */ - - ctx->media = CSS_MEDIA_ALL; - ctx->pseudo_element = CSS_PSEUDO_ELEMENT_NONE; - - /* Consume any leading whitespace */ - while (p < end && isspace(*p)) - p++; - - if (p < end) { - left = end - p; - - css__parse_media_list(&p, &left, &ctx->media); - - end = p + left; - } - - if (p < end) { - left = end - p; - - css__parse_pseudo_list(&p, &left, &ctx->pseudo_element); - } -} - -void css__parse_tree_data(line_ctx *ctx, const char *data, size_t len) -{ - const char *p = data; - const char *end = data + len; - const char *name = NULL; - const char *value = NULL; - size_t namelen = 0; - size_t valuelen = 0; - uint32_t depth = 0; - bool target = false; - - /* ' '{depth+1} [ '*'? | ] - * - * ::= [^=*[:space:]]+ - * ::= [^=*[:space:]]+ '=' [^[:space:]]* - */ - - while (p < end && isspace(*p)) { - depth++; - p++; - } - depth--; - - /* Get element/attribute name */ - name = p; - while (p < end && *p != '=' && *p != '*' && isspace(*p) == false) { - namelen++; - p++; - } - - /* Skip whitespace */ - while (p < end && isspace(*p)) - p++; - - if (p < end && *p == '=') { - /* Attribute value */ - p++; - - value = p; - - while (p < end && isspace(*p) == false) { - valuelen++; - p++; - } - } else if (p < end && *p == '*') { - /* Element is target node */ - target = true; - } - - if (value == NULL) { - /* We have an element, so create it */ - node *n = malloc(sizeof(node)); - assert(n != NULL); - - memset(n, 0, sizeof(node)); - - lwc_intern_string(name, namelen, &n->name); - - /* Insert it into tree */ - if (ctx->tree == NULL) { - ctx->tree = n; - } else { - assert(depth > 0); - assert(depth <= ctx->depth + 1); - - /* Find node to insert into */ - while (depth <= ctx->depth) { - ctx->depth--; - ctx->current = ctx->current->parent; - } - - /* Insert into current node */ - if (ctx->current->children == NULL) { - ctx->current->children = n; - ctx->current->last_child = n; - } else { - ctx->current->last_child->next = n; - n->prev = ctx->current->last_child; - - ctx->current->last_child = n; - } - n->parent = ctx->current; - } - - ctx->current = n; - ctx->depth = depth; - - /* Mark the target, if it's us */ - if (target) - ctx->target = n; - } else { - /* New attribute */ - attribute *attr; - - attribute *temp = realloc(ctx->current->attrs, - (ctx->current->n_attrs + 1) * sizeof(attribute)); - assert(temp != NULL); - - ctx->current->attrs = temp; - - attr = &ctx->current->attrs[ctx->current->n_attrs]; - - lwc_intern_string(name, namelen, &attr->name); - lwc_intern_string(value, valuelen, &attr->value); - - ctx->current->n_attrs++; - } -} - -void css__parse_sheet(line_ctx *ctx, const char *data, size_t len) -{ - css_stylesheet_params params; - const char *p; - const char *end = data + len; - css_origin origin = CSS_ORIGIN_AUTHOR; - uint64_t media = CSS_MEDIA_ALL; - css_stylesheet *sheet; - sheet_ctx *temp; - - /* ? */ - - /* Find end of origin */ - for (p = data; p < end; p++) { - if (isspace(*p)) - break; - } - - if (p - data == 6 && strncasecmp(data, "author", 6) == 0) - origin = CSS_ORIGIN_AUTHOR; - else if (p - data == 4 && strncasecmp(data, "user", 4) == 0) - origin = CSS_ORIGIN_USER; - else if (p - data == 2 && strncasecmp(data, "ua", 2) == 0) - origin = CSS_ORIGIN_UA; - else - assert(0 && "Unknown stylesheet origin"); - - /* Skip any whitespace */ - while (p < end && isspace(*p)) - p++; - - if (p < end) { - size_t ignored = end - p; - - css__parse_media_list(&p, &ignored, &media); - } - - params.params_version = CSS_STYLESHEET_PARAMS_VERSION_1; - params.level = CSS_LEVEL_21; - params.charset = "UTF-8"; - params.url = "foo"; - params.title = "foo"; - params.allow_quirks = false; - params.inline_style = false; - params.resolve = resolve_url; - params.resolve_pw = NULL; - params.import = NULL; - params.import_pw = NULL; - params.color = NULL; - params.color_pw = NULL; - params.font = NULL; - params.font_pw = NULL; - - /** \todo How are we going to handle @import? */ - assert(css_stylesheet_create(¶ms, myrealloc, NULL, - &sheet) == CSS_OK); - - /* Extend array of sheets and append new sheet to it */ - temp = realloc(ctx->sheets, - (ctx->n_sheets + 1) * sizeof(sheet_ctx)); - assert(temp != NULL); - - ctx->sheets = temp; - - ctx->sheets[ctx->n_sheets].sheet = sheet; - ctx->sheets[ctx->n_sheets].origin = origin; - ctx->sheets[ctx->n_sheets].media = media; - - ctx->n_sheets++; -} - -void css__parse_media_list(const char **data, size_t *len, uint64_t *media) -{ - const char *p = *data; - const char *end = p + *len; - uint64_t result = 0; - - /* [ ',' ]* */ - - while (p < end) { - const char *start = p; - - /* consume a medium */ - while (isspace(*p) == false && *p != ',') - p++; - - if (p - start == 10 && - strncasecmp(start, "projection", 10) == 0) - result |= CSS_MEDIA_PROJECTION; - else if (p - start == 8 && - strncasecmp(start, "handheld", 8) == 0) - result |= CSS_MEDIA_HANDHELD; - else if (p - start == 8 && - strncasecmp(start, "embossed", 8) == 0) - result |= CSS_MEDIA_EMBOSSED; - else if (p - start == 7 && - strncasecmp(start, "braille", 7) == 0) - result |= CSS_MEDIA_BRAILLE; - else if (p - start == 6 && - strncasecmp(start, "speech", 6) == 0) - result |= CSS_MEDIA_SPEECH; - else if (p - start == 6 && - strncasecmp(start, "screen", 6) == 0) - result |= CSS_MEDIA_SCREEN; - else if (p - start == 5 && - strncasecmp(start, "print", 5) == 0) - result |= CSS_MEDIA_PRINT; - else if (p - start == 5 && - strncasecmp(start, "aural", 5) == 0) - result |= CSS_MEDIA_AURAL; - else if (p - start == 3 && - strncasecmp(start, "tty", 3) == 0) - result |= CSS_MEDIA_TTY; - else if (p - start == 3 && - strncasecmp(start, "all", 3) == 0) - result |= CSS_MEDIA_ALL; - else if (p - start == 2 && - strncasecmp(start, "tv", 2) == 0) - result |= CSS_MEDIA_TV; - else - assert(0 && "Unknown media type"); - - /* Consume whitespace */ - while (p < end && isspace(*p)) - p++; - - /* Stop if we've reached the end */ - if (p == end || *p != ',') - break; - - /* Consume comma */ - p++; - - /* Consume whitespace */ - while (p < end && isspace(*p)) - p++; - } - - *media = result; - - *data = p; - *len = end - p; -} - -void css__parse_pseudo_list(const char **data, size_t *len, uint32_t *element) -{ - const char *p = *data; - const char *end = p + *len; - - /* [ ',' ]* */ - - *element = CSS_PSEUDO_ELEMENT_NONE; - - while (p < end) { - const char *start = p; - - /* consume a pseudo */ - while (isspace(*p) == false && *p != ',') - p++; - - /* Pseudo elements */ - if (p - start == 12 && - strncasecmp(start, "first-letter", 12) == 0) - *element = CSS_PSEUDO_ELEMENT_FIRST_LETTER; - else if (p - start == 10 && - strncasecmp(start, "first-line", 10) == 0) - *element = CSS_PSEUDO_ELEMENT_FIRST_LINE; - else if (p - start == 6 && - strncasecmp(start, "before", 6) == 0) - *element = CSS_PSEUDO_ELEMENT_BEFORE; - else if (p - start == 5 && - strncasecmp(start, "after", 5) == 0) - *element = CSS_PSEUDO_ELEMENT_AFTER; - else - assert(0 && "Unknown pseudo"); - - /* Consume whitespace */ - while (p < end && isspace(*p)) - p++; - - /* Stop if we've reached the end */ - if (p == end || *p != ',') - break; - - /* Consume comma */ - p++; - - /* Consume whitespace */ - while (p < end && isspace(*p)) - p++; - } - - *data = p; - *len = end - p; -} - -void css__parse_expected(line_ctx *ctx, const char *data, size_t len) -{ - while (ctx->expused + len >= ctx->explen) { - size_t required = ctx->explen == 0 ? 64 : ctx->explen * 2; - char *temp = realloc(ctx->exp, required); - if (temp == NULL) { - assert(0 && "No memory for expected output"); - } - - ctx->exp = temp; - ctx->explen = required; - } - - memcpy(ctx->exp + ctx->expused, data, len); - - ctx->expused += len; -} - -void run_test(line_ctx *ctx, const char *exp, size_t explen) -{ - css_select_ctx *select; - css_select_results *results; - uint32_t i; - char *buf; - size_t buflen; - static int testnum; - css_bloom node_bloom[CSS_BLOOM_SIZE]; - - UNUSED(exp); - - buf = malloc(8192); - if (buf == NULL) { - assert(0 && "No memory for result data"); - } - buflen = 8192; - - assert(css_select_ctx_create(myrealloc, NULL, &select) == CSS_OK); - - for (i = 0; i < ctx->n_sheets; i++) { - assert(css_select_ctx_append_sheet(select, - ctx->sheets[i].sheet, ctx->sheets[i].origin, - ctx->sheets[i].media) == CSS_OK); - } - - testnum++; - - /* Not testing bloom functionality here, just set all bits */ - for (i = 0; i < CSS_BLOOM_SIZE; i++) { - node_bloom[i] = ~0; - } - - assert(css_select_style(select, ctx->target, node_bloom, ctx->media, NULL, - &select_handler, ctx, &results) == CSS_OK); - - assert(results->styles[ctx->pseudo_element] != NULL); - - dump_computed_style(results->styles[ctx->pseudo_element], buf, &buflen); - - if (8192 - buflen != explen || memcmp(buf, exp, explen) != 0) { - printf("Expected (%u):\n%.*s\n", - (int) explen, (int) explen, exp); - printf("Result (%u):\n%.*s\n", (int) (8192 - buflen), - (int) (8192 - buflen), buf); - assert(0 && "Result doesn't match expected"); - } - - /* Clean up */ - css_select_results_destroy(results); - css_select_ctx_destroy(select); - - destroy_tree(ctx->tree); - - for (i = 0; i < ctx->n_sheets; i++) { - css_stylesheet_destroy(ctx->sheets[i].sheet); - } - - ctx->tree = NULL; - ctx->current = NULL; - ctx->depth = 0; - ctx->n_sheets = 0; - free(ctx->sheets); - ctx->sheets = NULL; - ctx->target = NULL; - - free(buf); - - printf("Test %d: PASS\n", testnum); -} - -void destroy_tree(node *root) -{ - node *n, *p; - uint32_t i; - - for (n = root->children; n != NULL; n = p) { - p = n->next; - - destroy_tree(n); - } - - for (i = 0; i < root->n_attrs; ++i) { - lwc_string_unref(root->attrs[i].name); - lwc_string_unref(root->attrs[i].value); - } - - free(root->attrs); - - lwc_string_unref(root->name); - free(root); -} - - -css_error node_name(void *pw, void *n, css_qname *qname) -{ - node *node = n; - - UNUSED(pw); - - qname->name = lwc_string_ref(node->name); - - return CSS_OK; -} - -css_error node_classes(void *pw, void *n, - lwc_string ***classes, uint32_t *n_classes) -{ - node *node = n; - uint32_t i; - line_ctx *lc = pw; - - for (i = 0; i < node->n_attrs; i++) { - bool amatch = false; - assert(lwc_string_caseless_isequal( - node->attrs[i].name, lc->attr_class, &amatch) == - lwc_error_ok); - if (amatch == true) - break; - } - - if (i != node->n_attrs) { - *classes = realloc(NULL, sizeof(lwc_string **)); - if (*classes == NULL) - return CSS_NOMEM; - - *(classes[0]) = - lwc_string_ref(node->attrs[i].value); - *n_classes = 1; - } else { - *classes = NULL; - *n_classes = 0; - } - - return CSS_OK; - -} - -css_error node_id(void *pw, void *n, - lwc_string **id) -{ - node *node = n; - uint32_t i; - line_ctx *lc = pw; - - for (i = 0; i < node->n_attrs; i++) { - bool amatch = false; - assert(lwc_string_caseless_isequal( - node->attrs[i].name, lc->attr_id, &amatch) == - lwc_error_ok); - if (amatch == true) - break; - } - - if (i != node->n_attrs) - *id = lwc_string_ref(node->attrs[i].value); - else - *id = NULL; - - return CSS_OK; -} - -css_error named_ancestor_node(void *pw, void *n, - const css_qname *qname, - void **ancestor) -{ - node *node = n; - UNUSED(pw); - - for (node = node->parent; node != NULL; node = node->parent) { - bool match = false; - assert(lwc_string_caseless_isequal( - qname->name, node->name, - &match) == lwc_error_ok); - if (match == true) - break; - } - - *ancestor = (void *) node; - - return CSS_OK; -} - -css_error named_parent_node(void *pw, void *n, - const css_qname *qname, - void **parent) -{ - node *node = n; - UNUSED(pw); - - *parent = NULL; - if (node->parent != NULL) { - bool match = false; - assert(lwc_string_caseless_isequal( - qname->name, node->parent->name, &match) == - lwc_error_ok); - if (match == true) - *parent = (void *) node->parent; - } - - return CSS_OK; -} - -css_error named_sibling_node(void *pw, void *n, - const css_qname *qname, - void **sibling) -{ - node *node = n; - UNUSED(pw); - - *sibling = NULL; - if (node->prev != NULL) { - bool match = false; - assert(lwc_string_caseless_isequal( - qname->name, node->prev->name, &match) == - lwc_error_ok); - if (match == true) - *sibling = (void *) node->prev; - } - - return CSS_OK; -} - -css_error named_generic_sibling_node(void *pw, void *n, - const css_qname *qname, - void **sibling) -{ - node *node = n; - UNUSED(pw); - - for (node = node->prev; node != NULL; node = node->prev) { - bool match = false; - assert(lwc_string_caseless_isequal( - qname->name, node->name, - &match) == lwc_error_ok); - if (match == true) - break; - } - - *sibling = (void *) node; - - return CSS_OK; -} - -css_error parent_node(void *pw, void *n, void **parent) -{ - node *node = n; - - UNUSED(pw); - - *parent = (void *) node->parent; - - return CSS_OK; -} - -css_error sibling_node(void *pw, void *n, void **sibling) -{ - node *node = n; - - UNUSED(pw); - - *sibling = (void *) node->prev; - - return CSS_OK; -} - -css_error node_has_name(void *pw, void *n, - const css_qname *qname, - bool *match) -{ - node *node = n; - UNUSED(pw); - - if (lwc_string_length(qname->name) == 1 && - lwc_string_data(qname->name)[0] == '*') - *match = true; - else - assert(lwc_string_caseless_isequal(node->name, - qname->name, match) == lwc_error_ok); - - return CSS_OK; -} - -css_error node_has_class(void *pw, void *n, - lwc_string *name, - bool *match) -{ - node *node = n; - uint32_t i; - line_ctx *ctx = pw; - - for (i = 0; i < node->n_attrs; i++) { - bool amatch = false; - assert(lwc_string_caseless_isequal( - node->attrs[i].name, ctx->attr_class, - &amatch) == lwc_error_ok); - if (amatch == true) - break; - } - - /* Classes are case-sensitive in HTML */ - if (i != node->n_attrs && name == node->attrs[i].value) - *match = true; - else - *match = false; - - return CSS_OK; -} - -css_error node_has_id(void *pw, void *n, - lwc_string *name, - bool *match) -{ - node *node = n; - uint32_t i; - line_ctx *ctx = pw; - - for (i = 0; i < node->n_attrs; i++) { - bool amatch = false; - assert(lwc_string_caseless_isequal( - node->attrs[i].name, ctx->attr_id, &amatch) == - lwc_error_ok); - if (amatch == true) - break; - } - - /* IDs are case-sensitive in HTML */ - if (i != node->n_attrs && name == node->attrs[i].value) - *match = true; - else - *match = false; - - return CSS_OK; -} - -css_error node_has_attribute(void *pw, void *n, - const css_qname *qname, - bool *match) -{ - node *node = n; - uint32_t i; - UNUSED(pw); - - *match = false; - for (i = 0; i < node->n_attrs; i++) { - assert(lwc_string_caseless_isequal( - node->attrs[i].name, qname->name, match) == - lwc_error_ok); - if (*match == true) - break; - } - - return CSS_OK; -} - -css_error node_has_attribute_equal(void *pw, void *n, - const css_qname *qname, - lwc_string *value, - bool *match) -{ - node *node = n; - uint32_t i; - UNUSED(pw); - - *match = false; - - for (i = 0; i < node->n_attrs; i++) { - assert(lwc_string_caseless_isequal( - node->attrs[i].name, qname->name, match) == - lwc_error_ok); - if (*match == true) - break; - } - - if (*match == true) { - assert(lwc_string_caseless_isequal( - node->attrs[i].name, value, match) == - lwc_error_ok); - } - - return CSS_OK; -} - -css_error node_has_attribute_includes(void *pw, void *n, - const css_qname *qname, - lwc_string *value, - bool *match) -{ - node *node = n; - uint32_t i; - size_t vlen = lwc_string_length(value); - UNUSED(pw); - - *match = false; - - for (i = 0; i < node->n_attrs; i++) { - assert(lwc_string_caseless_isequal( - node->attrs[i].name, qname->name, match) == - lwc_error_ok); - if (*match == true) - break; - } - - if (*match == true) { - const char *p; - const char *start = lwc_string_data(node->attrs[i].value); - const char *end = start + - lwc_string_length(node->attrs[i].value); - - *match = false; - - for (p = start; p < end; p++) { - if (*p == ' ') { - if ((size_t) (p - start) == vlen && - strncasecmp(start, - lwc_string_data(value), - vlen) == 0) { - *match = true; - break; - } - - start = p + 1; - } - } - } - - return CSS_OK; -} - -css_error node_has_attribute_dashmatch(void *pw, void *n, - const css_qname *qname, - lwc_string *value, - bool *match) -{ - node *node = n; - uint32_t i; - size_t vlen = lwc_string_length(value); - UNUSED(pw); - - *match = false; - - for (i = 0; i < node->n_attrs; i++) { - assert(lwc_string_caseless_isequal( - node->attrs[i].name, qname->name, match) == - lwc_error_ok); - if (*match == true) - break; - } - - if (*match == true) { - const char *p; - const char *start = lwc_string_data(node->attrs[i].value); - const char *end = start + - lwc_string_length(node->attrs[i].value); - - *match = false; - - for (p = start; p < end; p++) { - if (*p == '-') { - if ((size_t) (p - start) == vlen && - strncasecmp(start, - lwc_string_data(value), - vlen) == 0) { - *match = true; - break; - } - - start = p + 1; - } - } - } - - return CSS_OK; -} - -css_error node_has_attribute_prefix(void *pw, void *n, - const css_qname *qname, - lwc_string *value, - bool *match) -{ - node *node = n; - uint32_t i; - UNUSED(pw); - - *match = false; - - for (i = 0; i < node->n_attrs; i++) { - assert(lwc_string_caseless_isequal( - node->attrs[i].name, qname->name, match) == - lwc_error_ok); - if (*match == true) - break; - } - - if (*match == true) { - size_t len = lwc_string_length(node->attrs[i].value); - const char *data = lwc_string_data(node->attrs[i].value); - - size_t vlen = lwc_string_length(value); - const char *vdata = lwc_string_data(value); - - if (len < vlen) - *match = false; - else - *match = (strncasecmp(data, vdata, vlen) == 0); - } - - return CSS_OK; -} - -css_error node_has_attribute_suffix(void *pw, void *n, - const css_qname *qname, - lwc_string *value, - bool *match) -{ - node *node = n; - uint32_t i; - UNUSED(pw); - - *match = false; - - for (i = 0; i < node->n_attrs; i++) { - assert(lwc_string_caseless_isequal( - node->attrs[i].name, qname->name, match) == - lwc_error_ok); - if (*match == true) - break; - } - - if (*match == true) { - size_t len = lwc_string_length(node->attrs[i].value); - const char *data = lwc_string_data(node->attrs[i].value); - - size_t vlen = lwc_string_length(value); - const char *vdata = lwc_string_data(value); - - size_t suffix_start = len - vlen; - - if (len < vlen) - *match = false; - else { - *match = (strncasecmp(data + suffix_start, - vdata, vlen) == 0); - } - } - - return CSS_OK; -} - -css_error node_has_attribute_substring(void *pw, void *n, - const css_qname *qname, - lwc_string *value, - bool *match) -{ - node *node = n; - uint32_t i; - UNUSED(pw); - - *match = false; - - for (i = 0; i < node->n_attrs; i++) { - assert(lwc_string_caseless_isequal( - node->attrs[i].name, qname->name, match) == - lwc_error_ok); - if (*match == true) - break; - } - - if (*match == true) { - size_t len = lwc_string_length(node->attrs[i].value); - const char *data = lwc_string_data(node->attrs[i].value); - - size_t vlen = lwc_string_length(value); - const char *vdata = lwc_string_data(value); - - const char *last_start = data + len - vlen; - - if (len < vlen) - *match = false; - else { - while (data <= last_start) { - if (strncasecmp(data, vdata, vlen) == 0) { - *match = true; - break; - } - - data++; - } - - if (data > last_start) - *match = false; - } - } - - return CSS_OK; -} - -css_error node_is_root(void *pw, void *n, bool *match) -{ - node *node = n; - UNUSED(pw); - - *match = (node->parent == NULL); - - return CSS_OK; -} - -css_error node_count_siblings(void *pw, void *n, - bool same_name, bool after, int32_t *count) -{ - int32_t cnt = 0; - bool match = false; - node *node = n; - lwc_string *name = node->name; - UNUSED(pw); - - if (after) { - while (node->next != NULL) { - if (same_name) { - assert(lwc_string_caseless_isequal( - name, node->next->name, &match) == - lwc_error_ok); - - if (match) - cnt++; - } else { - cnt++; - } - - node = node->next; - } - } else { - while (node->prev != NULL) { - if (same_name) { - assert(lwc_string_caseless_isequal( - name, node->prev->name, &match) == - lwc_error_ok); - - if (match) - cnt++; - } else { - cnt++; - } - - node = node->prev; - } - } - - *count = cnt; - - return CSS_OK; -} - -css_error node_is_empty(void *pw, void *n, bool *match) -{ - node *node = n; - UNUSED(pw); - - *match = (node->children == NULL); - - return CSS_OK; -} - -css_error node_is_link(void *pw, void *n, bool *match) -{ - node *node = n; - - UNUSED(pw); - UNUSED(node); - - *match = false; - - return CSS_OK; -} - -css_error node_is_visited(void *pw, void *n, bool *match) -{ - node *node = n; - - UNUSED(pw); - UNUSED(node); - - *match = false; - - return CSS_OK; -} - -css_error node_is_hover(void *pw, void *n, bool *match) -{ - node *node = n; - - UNUSED(pw); - UNUSED(node); - - *match = false; - - return CSS_OK; -} - -css_error node_is_active(void *pw, void *n, bool *match) -{ - node *node = n; - - UNUSED(pw); - UNUSED(node); - - *match = false; - - return CSS_OK; -} - -css_error node_is_focus(void *pw, void *n, bool *match) -{ - node *node = n; - - UNUSED(pw); - UNUSED(node); - - *match = false; - - return CSS_OK; -} - -css_error node_is_enabled(void *pw, void *n, bool *match) -{ - node *node = n; - - UNUSED(pw); - UNUSED(node); - - *match = false; - - return CSS_OK; -} - -css_error node_is_disabled(void *pw, void *n, bool *match) -{ - node *node = n; - - UNUSED(pw); - UNUSED(node); - - *match = false; - - return CSS_OK; -} - -css_error node_is_checked(void *pw, void *n, bool *match) -{ - node *node = n; - - UNUSED(pw); - UNUSED(node); - - *match = false; - - return CSS_OK; -} - -css_error node_is_target(void *pw, void *n, bool *match) -{ - node *node = n; - - UNUSED(pw); - UNUSED(node); - - *match = false; - - return CSS_OK; -} - -css_error node_is_lang(void *pw, void *n, - lwc_string *lang, - bool *match) -{ - node *node = n; - - UNUSED(pw); - UNUSED(node); - UNUSED(lang); - - *match = false; - - return CSS_OK; -} - -css_error node_presentational_hint(void *pw, void *node, - uint32_t property, css_hint *hint) -{ - UNUSED(pw); - UNUSED(node); - UNUSED(property); - UNUSED(hint); - - return CSS_PROPERTY_NOT_SET; -} - -css_error ua_default_for_property(void *pw, uint32_t property, css_hint *hint) -{ - UNUSED(pw); - - 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; - hint->status = CSS_FONT_FAMILY_SANS_SERIF; - } else if (property == CSS_PROP_QUOTES) { - /* 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 compute_font_size(void *pw, const css_hint *parent, css_hint *size) -{ - static css_hint_length sizes[] = { - { FLTTOFIX(6.75), CSS_UNIT_PT }, - { FLTTOFIX(7.50), CSS_UNIT_PT }, - { FLTTOFIX(9.75), CSS_UNIT_PT }, - { FLTTOFIX(12.0), CSS_UNIT_PT }, - { FLTTOFIX(13.5), CSS_UNIT_PT }, - { FLTTOFIX(18.0), CSS_UNIT_PT }, - { FLTTOFIX(24.0), CSS_UNIT_PT } - }; - const css_hint_length *parent_size; - - UNUSED(pw); - - /* Grab parent size, defaulting to medium if none */ - if (parent == NULL) { - parent_size = &sizes[CSS_FONT_SIZE_MEDIUM - 1]; - } else { - assert(parent->status == CSS_FONT_SIZE_DIMENSION); - assert(parent->data.length.unit != CSS_UNIT_EM); - assert(parent->data.length.unit != CSS_UNIT_EX); - parent_size = &parent->data.length; - } - - assert(size->status != CSS_FONT_SIZE_INHERIT); - - if (size->status < CSS_FONT_SIZE_LARGER) { - /* Keyword -- simple */ - size->data.length = sizes[size->status - 1]; - } 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 = - FMUL(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) { - 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), FLTTOFIX(100)); - size->data.length.unit = parent_size->unit; - } - - size->status = CSS_FONT_SIZE_DIMENSION; - - return CSS_OK; -} - diff --git a/test/select-bloom-auto.c b/test/select-bloom-auto.c deleted file mode 100644 index 2d8628d..0000000 --- a/test/select-bloom-auto.c +++ /dev/null @@ -1,1631 +0,0 @@ -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include - -#include "utils/utils.h" - -#include "dump_computed.h" -#include "testutils.h" - -typedef struct attribute { - lwc_string *name; - lwc_string *value; -} attribute; - -typedef struct node { - lwc_string *name; - - uint32_t n_attrs; - attribute *attrs; - - struct node *parent; - struct node *next; - struct node *prev; - struct node *children; - struct node *last_child; -} node; - -typedef struct sheet_ctx { - css_stylesheet *sheet; - css_origin origin; - uint64_t media; -} sheet_ctx; - -typedef struct line_ctx { - size_t explen; - size_t expused; - char *exp; - - bool intree; - bool insheet; - bool inerrors; - bool inexp; - - node *tree; - node *current; - uint32_t depth; - - uint32_t n_sheets; - sheet_ctx *sheets; - - uint64_t media; - uint32_t pseudo_element; - node *target; - - lwc_string *attr_class; - lwc_string *attr_id; -} line_ctx; - -static bool handle_line(const char *data, size_t datalen, void *pw); -static void css__parse_tree(line_ctx *ctx, const char *data, size_t len); -static void css__parse_tree_data(line_ctx *ctx, const char *data, size_t len); -static void css__parse_sheet(line_ctx *ctx, const char *data, size_t len); -static void css__parse_media_list(const char **data, size_t *len, uint64_t *media); -static void css__parse_pseudo_list(const char **data, size_t *len, - uint32_t *element); -static void css__parse_expected(line_ctx *ctx, const char *data, size_t len); -static void run_test(line_ctx *ctx, const char *exp, size_t explen); -static void destroy_tree(node *root); - -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_ancestor_node(void *pw, void *node, - const css_qname *qname, - void **ancestor); -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_visited(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 node_presentational_hint(void *pw, void *node, - uint32_t property, css_hint *hint); -static css_error ua_default_for_property(void *pw, uint32_t property, - css_hint *hint); -static css_error compute_font_size(void *pw, const css_hint *parent, - css_hint *size); - -static css_select_handler select_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, - compute_font_size -}; - -static void *myrealloc(void *data, size_t len, void *pw) -{ - UNUSED(pw); - - return realloc(data, len); -} - -static css_error resolve_url(void *pw, - const char *base, lwc_string *rel, lwc_string **abs) -{ - UNUSED(pw); - UNUSED(base); - - /* About as useless as possible */ - *abs = lwc_string_ref(rel); - - return CSS_OK; -} - -static bool fail_because_lwc_leaked = false; - -static void -printing_lwc_iterator(lwc_string *str, void *pw) -{ - UNUSED(pw); - - printf(" DICT: %*s\n", (int)(lwc_string_length(str)), lwc_string_data(str)); - fail_because_lwc_leaked = true; -} - -int main(int argc, char **argv) -{ - line_ctx ctx; - - if (argc != 2) { - printf("Usage: %s \n", argv[0]); - return 1; - } - - memset(&ctx, 0, sizeof(ctx)); - - - lwc_intern_string("class", SLEN("class"), &ctx.attr_class); - lwc_intern_string("id", SLEN("id"), &ctx.attr_id); - - assert(css__parse_testfile(argv[1], handle_line, &ctx) == true); - - /* and run final test */ - if (ctx.tree != NULL) - run_test(&ctx, ctx.exp, ctx.expused); - - free(ctx.exp); - - lwc_string_unref(ctx.attr_class); - lwc_string_unref(ctx.attr_id); - - lwc_iterate_strings(printing_lwc_iterator, NULL); - - assert(fail_because_lwc_leaked == false); - - printf("PASS\n"); - return 0; -} - -bool handle_line(const char *data, size_t datalen, void *pw) -{ - line_ctx *ctx = (line_ctx *) pw; - css_error error; - - if (data[0] == '#') { - if (ctx->intree) { - if (strncasecmp(data+1, "errors", 6) == 0) { - ctx->intree = false; - ctx->insheet = false; - ctx->inerrors = true; - ctx->inexp = false; - } else { - /* Assume start of stylesheet */ - css__parse_sheet(ctx, data + 1, datalen - 1); - - ctx->intree = false; - ctx->insheet = true; - ctx->inerrors = false; - ctx->inexp = false; - } - } else if (ctx->insheet) { - if (strncasecmp(data+1, "errors", 6) == 0) { - assert(css_stylesheet_data_done( - ctx->sheets[ctx->n_sheets - 1].sheet) - == CSS_OK); - - ctx->intree = false; - ctx->insheet = false; - ctx->inerrors = true; - ctx->inexp = false; - } else if (strncasecmp(data+1, "ua", 2) == 0 || - strncasecmp(data+1, "user", 4) == 0 || - strncasecmp(data+1, "author", 6) == 0) { - assert(css_stylesheet_data_done( - ctx->sheets[ctx->n_sheets - 1].sheet) - == CSS_OK); - - css__parse_sheet(ctx, data + 1, datalen - 1); - } else { - error = css_stylesheet_append_data( - ctx->sheets[ctx->n_sheets - 1].sheet, - (const uint8_t *) data, - datalen); - assert(error == CSS_OK || - error == CSS_NEEDDATA); - } - } else if (ctx->inerrors) { - ctx->intree = false; - ctx->insheet = false; - ctx->inerrors = false; - ctx->inexp = true; - } else if (ctx->inexp) { - /* This marks end of testcase, so run it */ - run_test(ctx, ctx->exp, ctx->expused); - - ctx->expused = 0; - - ctx->intree = false; - ctx->insheet = false; - ctx->inerrors = false; - ctx->inexp = false; - } else { - /* Start state */ - if (strncasecmp(data+1, "tree", 4) == 0) { - css__parse_tree(ctx, data + 5, datalen - 5); - - ctx->intree = true; - ctx->insheet = false; - ctx->inerrors = false; - ctx->inexp = false; - } - } - } else { - if (ctx->intree) { - /* Not interested in the '|' */ - css__parse_tree_data(ctx, data + 1, datalen - 1); - } else if (ctx->insheet) { - error = css_stylesheet_append_data( - ctx->sheets[ctx->n_sheets - 1].sheet, - (const uint8_t *) data, datalen); - assert(error == CSS_OK || error == CSS_NEEDDATA); - } else if (ctx->inexp) { - css__parse_expected(ctx, data, datalen); - } - } - - return true; -} - -void css__parse_tree(line_ctx *ctx, const char *data, size_t len) -{ - const char *p = data; - const char *end = data + len; - size_t left; - - /* [ ? ] ? */ - - ctx->media = CSS_MEDIA_ALL; - ctx->pseudo_element = CSS_PSEUDO_ELEMENT_NONE; - - /* Consume any leading whitespace */ - while (p < end && isspace(*p)) - p++; - - if (p < end) { - left = end - p; - - css__parse_media_list(&p, &left, &ctx->media); - - end = p + left; - } - - if (p < end) { - left = end - p; - - css__parse_pseudo_list(&p, &left, &ctx->pseudo_element); - } -} - -void css__parse_tree_data(line_ctx *ctx, const char *data, size_t len) -{ - const char *p = data; - const char *end = data + len; - const char *name = NULL; - const char *value = NULL; - size_t namelen = 0; - size_t valuelen = 0; - uint32_t depth = 0; - bool target = false; - - /* ' '{depth+1} [ '*'? | ] - * - * ::= [^=*[:space:]]+ - * ::= [^=*[:space:]]+ '=' [^[:space:]]* - */ - - while (p < end && isspace(*p)) { - depth++; - p++; - } - depth--; - - /* Get element/attribute name */ - name = p; - while (p < end && *p != '=' && *p != '*' && isspace(*p) == false) { - namelen++; - p++; - } - - /* Skip whitespace */ - while (p < end && isspace(*p)) - p++; - - if (p < end && *p == '=') { - /* Attribute value */ - p++; - - value = p; - - while (p < end && isspace(*p) == false) { - valuelen++; - p++; - } - } else if (p < end && *p == '*') { - /* Element is target node */ - target = true; - } - - if (value == NULL) { - /* We have an element, so create it */ - node *n = malloc(sizeof(node)); - assert(n != NULL); - - memset(n, 0, sizeof(node)); - - lwc_intern_string(name, namelen, &n->name); - - /* Insert it into tree */ - if (ctx->tree == NULL) { - ctx->tree = n; - } else { - assert(depth > 0); - assert(depth <= ctx->depth + 1); - - /* Find node to insert into */ - while (depth <= ctx->depth) { - ctx->depth--; - ctx->current = ctx->current->parent; - } - - /* Insert into current node */ - if (ctx->current->children == NULL) { - ctx->current->children = n; - ctx->current->last_child = n; - } else { - ctx->current->last_child->next = n; - n->prev = ctx->current->last_child; - - ctx->current->last_child = n; - } - n->parent = ctx->current; - } - - ctx->current = n; - ctx->depth = depth; - - /* Mark the target, if it's us */ - if (target) - ctx->target = n; - } else { - /* New attribute */ - attribute *attr; - - attribute *temp = realloc(ctx->current->attrs, - (ctx->current->n_attrs + 1) * sizeof(attribute)); - assert(temp != NULL); - - ctx->current->attrs = temp; - - attr = &ctx->current->attrs[ctx->current->n_attrs]; - - lwc_intern_string(name, namelen, &attr->name); - lwc_intern_string(value, valuelen, &attr->value); - - ctx->current->n_attrs++; - } -} - -void css__parse_sheet(line_ctx *ctx, const char *data, size_t len) -{ - css_stylesheet_params params; - const char *p; - const char *end = data + len; - css_origin origin = CSS_ORIGIN_AUTHOR; - uint64_t media = CSS_MEDIA_ALL; - css_stylesheet *sheet; - sheet_ctx *temp; - - /* ? */ - - /* Find end of origin */ - for (p = data; p < end; p++) { - if (isspace(*p)) - break; - } - - if (p - data == 6 && strncasecmp(data, "author", 6) == 0) - origin = CSS_ORIGIN_AUTHOR; - else if (p - data == 4 && strncasecmp(data, "user", 4) == 0) - origin = CSS_ORIGIN_USER; - else if (p - data == 2 && strncasecmp(data, "ua", 2) == 0) - origin = CSS_ORIGIN_UA; - else - assert(0 && "Unknown stylesheet origin"); - - /* Skip any whitespace */ - while (p < end && isspace(*p)) - p++; - - if (p < end) { - size_t ignored = end - p; - - css__parse_media_list(&p, &ignored, &media); - } - - params.params_version = CSS_STYLESHEET_PARAMS_VERSION_1; - params.level = CSS_LEVEL_21; - params.charset = "UTF-8"; - params.url = "foo"; - params.title = "foo"; - params.allow_quirks = false; - params.inline_style = false; - params.resolve = resolve_url; - params.resolve_pw = NULL; - params.import = NULL; - params.import_pw = NULL; - params.color = NULL; - params.color_pw = NULL; - params.font = NULL; - params.font_pw = NULL; - - /** \todo How are we going to handle @import? */ - assert(css_stylesheet_create(¶ms, myrealloc, NULL, - &sheet) == CSS_OK); - - /* Extend array of sheets and append new sheet to it */ - temp = realloc(ctx->sheets, - (ctx->n_sheets + 1) * sizeof(sheet_ctx)); - assert(temp != NULL); - - ctx->sheets = temp; - - ctx->sheets[ctx->n_sheets].sheet = sheet; - ctx->sheets[ctx->n_sheets].origin = origin; - ctx->sheets[ctx->n_sheets].media = media; - - ctx->n_sheets++; -} - -void css__parse_media_list(const char **data, size_t *len, uint64_t *media) -{ - const char *p = *data; - const char *end = p + *len; - uint64_t result = 0; - - /* [ ',' ]* */ - - while (p < end) { - const char *start = p; - - /* consume a medium */ - while (isspace(*p) == false && *p != ',') - p++; - - if (p - start == 10 && - strncasecmp(start, "projection", 10) == 0) - result |= CSS_MEDIA_PROJECTION; - else if (p - start == 8 && - strncasecmp(start, "handheld", 8) == 0) - result |= CSS_MEDIA_HANDHELD; - else if (p - start == 8 && - strncasecmp(start, "embossed", 8) == 0) - result |= CSS_MEDIA_EMBOSSED; - else if (p - start == 7 && - strncasecmp(start, "braille", 7) == 0) - result |= CSS_MEDIA_BRAILLE; - else if (p - start == 6 && - strncasecmp(start, "speech", 6) == 0) - result |= CSS_MEDIA_SPEECH; - else if (p - start == 6 && - strncasecmp(start, "screen", 6) == 0) - result |= CSS_MEDIA_SCREEN; - else if (p - start == 5 && - strncasecmp(start, "print", 5) == 0) - result |= CSS_MEDIA_PRINT; - else if (p - start == 5 && - strncasecmp(start, "aural", 5) == 0) - result |= CSS_MEDIA_AURAL; - else if (p - start == 3 && - strncasecmp(start, "tty", 3) == 0) - result |= CSS_MEDIA_TTY; - else if (p - start == 3 && - strncasecmp(start, "all", 3) == 0) - result |= CSS_MEDIA_ALL; - else if (p - start == 2 && - strncasecmp(start, "tv", 2) == 0) - result |= CSS_MEDIA_TV; - else - assert(0 && "Unknown media type"); - - /* Consume whitespace */ - while (p < end && isspace(*p)) - p++; - - /* Stop if we've reached the end */ - if (p == end || *p != ',') - break; - - /* Consume comma */ - p++; - - /* Consume whitespace */ - while (p < end && isspace(*p)) - p++; - } - - *media = result; - - *data = p; - *len = end - p; -} - -void css__parse_pseudo_list(const char **data, size_t *len, uint32_t *element) -{ - const char *p = *data; - const char *end = p + *len; - - /* [ ',' ]* */ - - *element = CSS_PSEUDO_ELEMENT_NONE; - - while (p < end) { - const char *start = p; - - /* consume a pseudo */ - while (isspace(*p) == false && *p != ',') - p++; - - /* Pseudo elements */ - if (p - start == 12 && - strncasecmp(start, "first-letter", 12) == 0) - *element = CSS_PSEUDO_ELEMENT_FIRST_LETTER; - else if (p - start == 10 && - strncasecmp(start, "first-line", 10) == 0) - *element = CSS_PSEUDO_ELEMENT_FIRST_LINE; - else if (p - start == 6 && - strncasecmp(start, "before", 6) == 0) - *element = CSS_PSEUDO_ELEMENT_BEFORE; - else if (p - start == 5 && - strncasecmp(start, "after", 5) == 0) - *element = CSS_PSEUDO_ELEMENT_AFTER; - else - assert(0 && "Unknown pseudo"); - - /* Consume whitespace */ - while (p < end && isspace(*p)) - p++; - - /* Stop if we've reached the end */ - if (p == end || *p != ',') - break; - - /* Consume comma */ - p++; - - /* Consume whitespace */ - while (p < end && isspace(*p)) - p++; - } - - *data = p; - *len = end - p; -} - -void css__parse_expected(line_ctx *ctx, const char *data, size_t len) -{ - while (ctx->expused + len >= ctx->explen) { - size_t required = ctx->explen == 0 ? 64 : ctx->explen * 2; - char *temp = realloc(ctx->exp, required); - if (temp == NULL) { - assert(0 && "No memory for expected output"); - } - - ctx->exp = temp; - ctx->explen = required; - } - - memcpy(ctx->exp + ctx->expused, data, len); - - ctx->expused += len; -} - -static void get_bloom_for_target_node(line_ctx *ctx, - css_bloom bloom[CSS_BLOOM_SIZE]) -{ - node *n = ctx->target; - bool match; - uint32_t i; - - css_bloom_init(bloom); - - while (n->parent != NULL) { - n = n->parent; - - /* Element name */ - if (n->name->insensitive == NULL) - assert(lwc__intern_caseless_string(n->name) == - lwc_error_ok); - - css_bloom_add_hash(bloom, - lwc_string_hash_value(n->name->insensitive)); - - /* Id */ - for (i = 0; i < n->n_attrs; i++) { - assert(lwc_string_caseless_isequal( - n->attrs[i].name, ctx->attr_id, - &match) == lwc_error_ok); - if (match == true) { - css_bloom_add_hash(bloom, - lwc_string_hash_value( - n->attrs[i].value)); - break; - } - } - - /* Classes */ - for (i = 0; i < n->n_attrs; i++) { - assert(lwc_string_caseless_isequal( - n->attrs[i].name, ctx->attr_class, - &match) == lwc_error_ok); - if (match == true) { - css_bloom_add_hash(bloom, - lwc_string_hash_value( - n->attrs[i].value)); - break; - } - } - } -} - -void run_test(line_ctx *ctx, const char *exp, size_t explen) -{ - css_select_ctx *select; - css_select_results *results; - uint32_t i; - char *buf; - size_t buflen; - static int testnum; - css_bloom node_bloom[CSS_BLOOM_SIZE]; - - UNUSED(exp); - - buf = malloc(8192); - if (buf == NULL) { - assert(0 && "No memory for result data"); - } - buflen = 8192; - - assert(css_select_ctx_create(myrealloc, NULL, &select) == CSS_OK); - - for (i = 0; i < ctx->n_sheets; i++) { - assert(css_select_ctx_append_sheet(select, - ctx->sheets[i].sheet, ctx->sheets[i].origin, - ctx->sheets[i].media) == CSS_OK); - } - - testnum++; - - get_bloom_for_target_node(ctx, node_bloom); - - assert(css_select_style(select, ctx->target, node_bloom, ctx->media, NULL, - &select_handler, ctx, &results) == CSS_OK); - - assert(results->styles[ctx->pseudo_element] != NULL); - - dump_computed_style(results->styles[ctx->pseudo_element], buf, &buflen); - - if (8192 - buflen != explen || memcmp(buf, exp, explen) != 0) { - printf("Expected (%u):\n%.*s\n", - (int) explen, (int) explen, exp); - printf("Result (%u):\n%.*s\n", (int) (8192 - buflen), - (int) (8192 - buflen), buf); - assert(0 && "Result doesn't match expected"); - } - - /* Clean up */ - css_select_results_destroy(results); - css_select_ctx_destroy(select); - - destroy_tree(ctx->tree); - - for (i = 0; i < ctx->n_sheets; i++) { - css_stylesheet_destroy(ctx->sheets[i].sheet); - } - - ctx->tree = NULL; - ctx->current = NULL; - ctx->depth = 0; - ctx->n_sheets = 0; - free(ctx->sheets); - ctx->sheets = NULL; - ctx->target = NULL; - - free(buf); - - printf("Test %d: PASS\n", testnum); -} - -void destroy_tree(node *root) -{ - node *n, *p; - uint32_t i; - - for (n = root->children; n != NULL; n = p) { - p = n->next; - - destroy_tree(n); - } - - for (i = 0; i < root->n_attrs; ++i) { - lwc_string_unref(root->attrs[i].name); - lwc_string_unref(root->attrs[i].value); - } - - free(root->attrs); - - lwc_string_unref(root->name); - free(root); -} - - -css_error node_name(void *pw, void *n, css_qname *qname) -{ - node *node = n; - - UNUSED(pw); - - qname->name = lwc_string_ref(node->name); - - return CSS_OK; -} - -css_error node_classes(void *pw, void *n, - lwc_string ***classes, uint32_t *n_classes) -{ - node *node = n; - uint32_t i; - line_ctx *lc = pw; - - for (i = 0; i < node->n_attrs; i++) { - bool amatch = false; - assert(lwc_string_caseless_isequal( - node->attrs[i].name, lc->attr_class, &amatch) == - lwc_error_ok); - if (amatch == true) - break; - } - - if (i != node->n_attrs) { - *classes = realloc(NULL, sizeof(lwc_string **)); - if (*classes == NULL) - return CSS_NOMEM; - - *(classes[0]) = - lwc_string_ref(node->attrs[i].value); - *n_classes = 1; - } else { - *classes = NULL; - *n_classes = 0; - } - - return CSS_OK; - -} - -css_error node_id(void *pw, void *n, - lwc_string **id) -{ - node *node = n; - uint32_t i; - line_ctx *lc = pw; - - for (i = 0; i < node->n_attrs; i++) { - bool amatch = false; - assert(lwc_string_caseless_isequal( - node->attrs[i].name, lc->attr_id, &amatch) == - lwc_error_ok); - if (amatch == true) - break; - } - - if (i != node->n_attrs) - *id = lwc_string_ref(node->attrs[i].value); - else - *id = NULL; - - return CSS_OK; -} - -css_error named_ancestor_node(void *pw, void *n, - const css_qname *qname, - void **ancestor) -{ - node *node = n; - UNUSED(pw); - - for (node = node->parent; node != NULL; node = node->parent) { - bool match = false; - assert(lwc_string_caseless_isequal( - qname->name, node->name, - &match) == lwc_error_ok); - if (match == true) - break; - } - - *ancestor = (void *) node; - - return CSS_OK; -} - -css_error named_parent_node(void *pw, void *n, - const css_qname *qname, - void **parent) -{ - node *node = n; - UNUSED(pw); - - *parent = NULL; - if (node->parent != NULL) { - bool match = false; - assert(lwc_string_caseless_isequal( - qname->name, node->parent->name, &match) == - lwc_error_ok); - if (match == true) - *parent = (void *) node->parent; - } - - return CSS_OK; -} - -css_error named_sibling_node(void *pw, void *n, - const css_qname *qname, - void **sibling) -{ - node *node = n; - UNUSED(pw); - - *sibling = NULL; - if (node->prev != NULL) { - bool match = false; - assert(lwc_string_caseless_isequal( - qname->name, node->prev->name, &match) == - lwc_error_ok); - if (match == true) - *sibling = (void *) node->prev; - } - - return CSS_OK; -} - -css_error named_generic_sibling_node(void *pw, void *n, - const css_qname *qname, - void **sibling) -{ - node *node = n; - UNUSED(pw); - - for (node = node->prev; node != NULL; node = node->prev) { - bool match = false; - assert(lwc_string_caseless_isequal( - qname->name, node->name, - &match) == lwc_error_ok); - if (match == true) - break; - } - - *sibling = (void *) node; - - return CSS_OK; -} - -css_error parent_node(void *pw, void *n, void **parent) -{ - node *node = n; - - UNUSED(pw); - - *parent = (void *) node->parent; - - return CSS_OK; -} - -css_error sibling_node(void *pw, void *n, void **sibling) -{ - node *node = n; - - UNUSED(pw); - - *sibling = (void *) node->prev; - - return CSS_OK; -} - -css_error node_has_name(void *pw, void *n, - const css_qname *qname, - bool *match) -{ - node *node = n; - UNUSED(pw); - - if (lwc_string_length(qname->name) == 1 && - lwc_string_data(qname->name)[0] == '*') - *match = true; - else - assert(lwc_string_caseless_isequal(node->name, - qname->name, match) == lwc_error_ok); - - return CSS_OK; -} - -css_error node_has_class(void *pw, void *n, - lwc_string *name, - bool *match) -{ - node *node = n; - uint32_t i; - line_ctx *ctx = pw; - - for (i = 0; i < node->n_attrs; i++) { - bool amatch = false; - assert(lwc_string_caseless_isequal( - node->attrs[i].name, ctx->attr_class, - &amatch) == lwc_error_ok); - if (amatch == true) - break; - } - - /* Classes are case-sensitive in HTML */ - if (i != node->n_attrs && name == node->attrs[i].value) - *match = true; - else - *match = false; - - return CSS_OK; -} - -css_error node_has_id(void *pw, void *n, - lwc_string *name, - bool *match) -{ - node *node = n; - uint32_t i; - line_ctx *ctx = pw; - - for (i = 0; i < node->n_attrs; i++) { - bool amatch = false; - assert(lwc_string_caseless_isequal( - node->attrs[i].name, ctx->attr_id, &amatch) == - lwc_error_ok); - if (amatch == true) - break; - } - - /* IDs are case-sensitive in HTML */ - if (i != node->n_attrs && name == node->attrs[i].value) - *match = true; - else - *match = false; - - return CSS_OK; -} - -css_error node_has_attribute(void *pw, void *n, - const css_qname *qname, - bool *match) -{ - node *node = n; - uint32_t i; - UNUSED(pw); - - *match = false; - for (i = 0; i < node->n_attrs; i++) { - assert(lwc_string_caseless_isequal( - node->attrs[i].name, qname->name, match) == - lwc_error_ok); - if (*match == true) - break; - } - - return CSS_OK; -} - -css_error node_has_attribute_equal(void *pw, void *n, - const css_qname *qname, - lwc_string *value, - bool *match) -{ - node *node = n; - uint32_t i; - UNUSED(pw); - - *match = false; - - for (i = 0; i < node->n_attrs; i++) { - assert(lwc_string_caseless_isequal( - node->attrs[i].name, qname->name, match) == - lwc_error_ok); - if (*match == true) - break; - } - - if (*match == true) { - assert(lwc_string_caseless_isequal( - node->attrs[i].name, value, match) == - lwc_error_ok); - } - - return CSS_OK; -} - -css_error node_has_attribute_includes(void *pw, void *n, - const css_qname *qname, - lwc_string *value, - bool *match) -{ - node *node = n; - uint32_t i; - size_t vlen = lwc_string_length(value); - UNUSED(pw); - - *match = false; - - for (i = 0; i < node->n_attrs; i++) { - assert(lwc_string_caseless_isequal( - node->attrs[i].name, qname->name, match) == - lwc_error_ok); - if (*match == true) - break; - } - - if (*match == true) { - const char *p; - const char *start = lwc_string_data(node->attrs[i].value); - const char *end = start + - lwc_string_length(node->attrs[i].value); - - *match = false; - - for (p = start; p < end; p++) { - if (*p == ' ') { - if ((size_t) (p - start) == vlen && - strncasecmp(start, - lwc_string_data(value), - vlen) == 0) { - *match = true; - break; - } - - start = p + 1; - } - } - } - - return CSS_OK; -} - -css_error node_has_attribute_dashmatch(void *pw, void *n, - const css_qname *qname, - lwc_string *value, - bool *match) -{ - node *node = n; - uint32_t i; - size_t vlen = lwc_string_length(value); - UNUSED(pw); - - *match = false; - - for (i = 0; i < node->n_attrs; i++) { - assert(lwc_string_caseless_isequal( - node->attrs[i].name, qname->name, match) == - lwc_error_ok); - if (*match == true) - break; - } - - if (*match == true) { - const char *p; - const char *start = lwc_string_data(node->attrs[i].value); - const char *end = start + - lwc_string_length(node->attrs[i].value); - - *match = false; - - for (p = start; p < end; p++) { - if (*p == '-') { - if ((size_t) (p - start) == vlen && - strncasecmp(start, - lwc_string_data(value), - vlen) == 0) { - *match = true; - break; - } - - start = p + 1; - } - } - } - - return CSS_OK; -} - -css_error node_has_attribute_prefix(void *pw, void *n, - const css_qname *qname, - lwc_string *value, - bool *match) -{ - node *node = n; - uint32_t i; - UNUSED(pw); - - *match = false; - - for (i = 0; i < node->n_attrs; i++) { - assert(lwc_string_caseless_isequal( - node->attrs[i].name, qname->name, match) == - lwc_error_ok); - if (*match == true) - break; - } - - if (*match == true) { - size_t len = lwc_string_length(node->attrs[i].value); - const char *data = lwc_string_data(node->attrs[i].value); - - size_t vlen = lwc_string_length(value); - const char *vdata = lwc_string_data(value); - - if (len < vlen) - *match = false; - else - *match = (strncasecmp(data, vdata, vlen) == 0); - } - - return CSS_OK; -} - -css_error node_has_attribute_suffix(void *pw, void *n, - const css_qname *qname, - lwc_string *value, - bool *match) -{ - node *node = n; - uint32_t i; - UNUSED(pw); - - *match = false; - - for (i = 0; i < node->n_attrs; i++) { - assert(lwc_string_caseless_isequal( - node->attrs[i].name, qname->name, match) == - lwc_error_ok); - if (*match == true) - break; - } - - if (*match == true) { - size_t len = lwc_string_length(node->attrs[i].value); - const char *data = lwc_string_data(node->attrs[i].value); - - size_t vlen = lwc_string_length(value); - const char *vdata = lwc_string_data(value); - - size_t suffix_start = len - vlen; - - if (len < vlen) - *match = false; - else { - *match = (strncasecmp(data + suffix_start, - vdata, vlen) == 0); - } - } - - return CSS_OK; -} - -css_error node_has_attribute_substring(void *pw, void *n, - const css_qname *qname, - lwc_string *value, - bool *match) -{ - node *node = n; - uint32_t i; - UNUSED(pw); - - *match = false; - - for (i = 0; i < node->n_attrs; i++) { - assert(lwc_string_caseless_isequal( - node->attrs[i].name, qname->name, match) == - lwc_error_ok); - if (*match == true) - break; - } - - if (*match == true) { - size_t len = lwc_string_length(node->attrs[i].value); - const char *data = lwc_string_data(node->attrs[i].value); - - size_t vlen = lwc_string_length(value); - const char *vdata = lwc_string_data(value); - - const char *last_start = data + len - vlen; - - if (len < vlen) - *match = false; - else { - while (data <= last_start) { - if (strncasecmp(data, vdata, vlen) == 0) { - *match = true; - break; - } - - data++; - } - - if (data > last_start) - *match = false; - } - } - - return CSS_OK; -} - -css_error node_is_root(void *pw, void *n, bool *match) -{ - node *node = n; - UNUSED(pw); - - *match = (node->parent == NULL); - - return CSS_OK; -} - -css_error node_count_siblings(void *pw, void *n, - bool same_name, bool after, int32_t *count) -{ - int32_t cnt = 0; - bool match = false; - node *node = n; - lwc_string *name = node->name; - UNUSED(pw); - - if (after) { - while (node->next != NULL) { - if (same_name) { - assert(lwc_string_caseless_isequal( - name, node->next->name, &match) == - lwc_error_ok); - - if (match) - cnt++; - } else { - cnt++; - } - - node = node->next; - } - } else { - while (node->prev != NULL) { - if (same_name) { - assert(lwc_string_caseless_isequal( - name, node->prev->name, &match) == - lwc_error_ok); - - if (match) - cnt++; - } else { - cnt++; - } - - node = node->prev; - } - } - - *count = cnt; - - return CSS_OK; -} - -css_error node_is_empty(void *pw, void *n, bool *match) -{ - node *node = n; - UNUSED(pw); - - *match = (node->children == NULL); - - return CSS_OK; -} - -css_error node_is_link(void *pw, void *n, bool *match) -{ - node *node = n; - - UNUSED(pw); - UNUSED(node); - - *match = false; - - return CSS_OK; -} - -css_error node_is_visited(void *pw, void *n, bool *match) -{ - node *node = n; - - UNUSED(pw); - UNUSED(node); - - *match = false; - - return CSS_OK; -} - -css_error node_is_hover(void *pw, void *n, bool *match) -{ - node *node = n; - - UNUSED(pw); - UNUSED(node); - - *match = false; - - return CSS_OK; -} - -css_error node_is_active(void *pw, void *n, bool *match) -{ - node *node = n; - - UNUSED(pw); - UNUSED(node); - - *match = false; - - return CSS_OK; -} - -css_error node_is_focus(void *pw, void *n, bool *match) -{ - node *node = n; - - UNUSED(pw); - UNUSED(node); - - *match = false; - - return CSS_OK; -} - -css_error node_is_enabled(void *pw, void *n, bool *match) -{ - node *node = n; - - UNUSED(pw); - UNUSED(node); - - *match = false; - - return CSS_OK; -} - -css_error node_is_disabled(void *pw, void *n, bool *match) -{ - node *node = n; - - UNUSED(pw); - UNUSED(node); - - *match = false; - - return CSS_OK; -} - -css_error node_is_checked(void *pw, void *n, bool *match) -{ - node *node = n; - - UNUSED(pw); - UNUSED(node); - - *match = false; - - return CSS_OK; -} - -css_error node_is_target(void *pw, void *n, bool *match) -{ - node *node = n; - - UNUSED(pw); - UNUSED(node); - - *match = false; - - return CSS_OK; -} - -css_error node_is_lang(void *pw, void *n, - lwc_string *lang, - bool *match) -{ - node *node = n; - - UNUSED(pw); - UNUSED(node); - UNUSED(lang); - - *match = false; - - return CSS_OK; -} - -css_error node_presentational_hint(void *pw, void *node, - uint32_t property, css_hint *hint) -{ - UNUSED(pw); - UNUSED(node); - UNUSED(property); - UNUSED(hint); - - return CSS_PROPERTY_NOT_SET; -} - -css_error ua_default_for_property(void *pw, uint32_t property, css_hint *hint) -{ - UNUSED(pw); - - 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; - hint->status = CSS_FONT_FAMILY_SANS_SERIF; - } else if (property == CSS_PROP_QUOTES) { - /* 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 compute_font_size(void *pw, const css_hint *parent, css_hint *size) -{ - static css_hint_length sizes[] = { - { FLTTOFIX(6.75), CSS_UNIT_PT }, - { FLTTOFIX(7.50), CSS_UNIT_PT }, - { FLTTOFIX(9.75), CSS_UNIT_PT }, - { FLTTOFIX(12.0), CSS_UNIT_PT }, - { FLTTOFIX(13.5), CSS_UNIT_PT }, - { FLTTOFIX(18.0), CSS_UNIT_PT }, - { FLTTOFIX(24.0), CSS_UNIT_PT } - }; - const css_hint_length *parent_size; - - UNUSED(pw); - - /* Grab parent size, defaulting to medium if none */ - if (parent == NULL) { - parent_size = &sizes[CSS_FONT_SIZE_MEDIUM - 1]; - } else { - assert(parent->status == CSS_FONT_SIZE_DIMENSION); - assert(parent->data.length.unit != CSS_UNIT_EM); - assert(parent->data.length.unit != CSS_UNIT_EX); - parent_size = &parent->data.length; - } - - assert(size->status != CSS_FONT_SIZE_INHERIT); - - if (size->status < CSS_FONT_SIZE_LARGER) { - /* Keyword -- simple */ - size->data.length = sizes[size->status - 1]; - } 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 = - FMUL(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) { - 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), FLTTOFIX(100)); - size->data.length.unit = parent_size->unit; - } - - size->status = CSS_FONT_SIZE_DIMENSION; - - return CSS_OK; -} - diff --git a/test/select-common.c b/test/select-common.c new file mode 100644 index 0000000..783790a --- /dev/null +++ b/test/select-common.c @@ -0,0 +1,1608 @@ +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include "utils/utils.h" + +#include "dump_computed.h" +#include "testutils.h" + +typedef struct attribute { + lwc_string *name; + lwc_string *value; +} attribute; + +typedef struct node { + lwc_string *name; + + uint32_t n_classes; + lwc_string **classes; + + uint32_t n_attrs; + attribute *attrs; + + void *libcss_node_data; + + struct node *parent; + struct node *next; + struct node *prev; + struct node *children; + struct node *last_child; +} node; + +typedef struct sheet_ctx { + css_stylesheet *sheet; + css_origin origin; + uint64_t media; +} sheet_ctx; + +typedef struct line_ctx { + size_t explen; + size_t expused; + char *exp; + + bool intree; + bool insheet; + bool inerrors; + bool inexp; + + node *tree; + node *current; + uint32_t depth; + + uint32_t n_sheets; + sheet_ctx *sheets; + + uint64_t media; + uint32_t pseudo_element; + node *target; + + lwc_string *attr_class; + lwc_string *attr_id; +} line_ctx; + + + + +static bool handle_line(const char *data, size_t datalen, void *pw); +static void css__parse_tree(line_ctx *ctx, const char *data, size_t len); +static void css__parse_tree_data(line_ctx *ctx, const char *data, size_t len); +static void css__parse_sheet(line_ctx *ctx, const char *data, size_t len); +static void css__parse_media_list(const char **data, size_t *len, uint64_t *media); +static void css__parse_pseudo_list(const char **data, size_t *len, + uint32_t *element); +static void css__parse_expected(line_ctx *ctx, const char *data, size_t len); +static void run_test(line_ctx *ctx, const char *exp, size_t explen); +static void destroy_tree(node *root); + +static css_error node_name(void *pw, void *node, + css_qname *qname); +static css_error node_classes(void *pw, void *n, + lwc_string ***classes, uint32_t *n_classes); +static css_error node_id(void *pw, void *node, + lwc_string **id); +static css_error named_ancestor_node(void *pw, void *node, + const css_qname *qname, + void **ancestor); +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_visited(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 node_presentational_hint(void *pw, void *node, + uint32_t property, css_hint *hint); +static css_error ua_default_for_property(void *pw, uint32_t property, + css_hint *hint); +static css_error compute_font_size(void *pw, const css_hint *parent, + css_hint *size); +static css_error set_libcss_node_data(void *pw, void *n, + void *libcss_node_data); +static css_error get_libcss_node_data(void *pw, void *n, + void **libcss_node_data); + +static css_select_handler select_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, + compute_font_size, + set_libcss_node_data, + get_libcss_node_data +}; + +static css_error resolve_url(void *pw, + const char *base, lwc_string *rel, lwc_string **abs) +{ + UNUSED(pw); + UNUSED(base); + + /* About as useless as possible */ + *abs = lwc_string_ref(rel); + + return CSS_OK; +} + +static bool fail_because_lwc_leaked = false; + +static void +printing_lwc_iterator(lwc_string *str, void *pw) +{ + UNUSED(pw); + + printf(" DICT: %*s\n", (int)(lwc_string_length(str)), lwc_string_data(str)); + fail_because_lwc_leaked = true; +} + +int main(int argc, char **argv) +{ + line_ctx ctx; + + if (argc != 2) { + printf("Usage: %s \n", argv[0]); + return 1; + } + + memset(&ctx, 0, sizeof(ctx)); + + + lwc_intern_string("class", SLEN("class"), &ctx.attr_class); + lwc_intern_string("id", SLEN("id"), &ctx.attr_id); + + assert(css__parse_testfile(argv[1], handle_line, &ctx) == true); + + /* and run final test */ + if (ctx.tree != NULL) + run_test(&ctx, ctx.exp, ctx.expused); + + free(ctx.exp); + + lwc_string_unref(ctx.attr_class); + lwc_string_unref(ctx.attr_id); + + lwc_iterate_strings(printing_lwc_iterator, NULL); + + assert(fail_because_lwc_leaked == false); + + printf("PASS\n"); + return 0; +} + +bool handle_line(const char *data, size_t datalen, void *pw) +{ + line_ctx *ctx = (line_ctx *) pw; + css_error error; + + if (data[0] == '#') { + if (ctx->intree) { + if (strncasecmp(data+1, "errors", 6) == 0) { + ctx->intree = false; + ctx->insheet = false; + ctx->inerrors = true; + ctx->inexp = false; + } else { + /* Assume start of stylesheet */ + css__parse_sheet(ctx, data + 1, datalen - 1); + + ctx->intree = false; + ctx->insheet = true; + ctx->inerrors = false; + ctx->inexp = false; + } + } else if (ctx->insheet) { + if (strncasecmp(data+1, "errors", 6) == 0) { + assert(css_stylesheet_data_done( + ctx->sheets[ctx->n_sheets - 1].sheet) + == CSS_OK); + + ctx->intree = false; + ctx->insheet = false; + ctx->inerrors = true; + ctx->inexp = false; + } else if (strncasecmp(data+1, "ua", 2) == 0 || + strncasecmp(data+1, "user", 4) == 0 || + strncasecmp(data+1, "author", 6) == 0) { + assert(css_stylesheet_data_done( + ctx->sheets[ctx->n_sheets - 1].sheet) + == CSS_OK); + + css__parse_sheet(ctx, data + 1, datalen - 1); + } else { + error = css_stylesheet_append_data( + ctx->sheets[ctx->n_sheets - 1].sheet, + (const uint8_t *) data, + datalen); + assert(error == CSS_OK || + error == CSS_NEEDDATA); + } + } else if (ctx->inerrors) { + ctx->intree = false; + ctx->insheet = false; + ctx->inerrors = false; + ctx->inexp = true; + } else if (ctx->inexp) { + /* This marks end of testcase, so run it */ + run_test(ctx, ctx->exp, ctx->expused); + + ctx->expused = 0; + + ctx->intree = false; + ctx->insheet = false; + ctx->inerrors = false; + ctx->inexp = false; + } else { + /* Start state */ + if (strncasecmp(data+1, "tree", 4) == 0) { + css__parse_tree(ctx, data + 5, datalen - 5); + + ctx->intree = true; + ctx->insheet = false; + ctx->inerrors = false; + ctx->inexp = false; + } + } + } else { + if (ctx->intree) { + /* Not interested in the '|' */ + css__parse_tree_data(ctx, data + 1, datalen - 1); + } else if (ctx->insheet) { + error = css_stylesheet_append_data( + ctx->sheets[ctx->n_sheets - 1].sheet, + (const uint8_t *) data, datalen); + assert(error == CSS_OK || error == CSS_NEEDDATA); + } else if (ctx->inexp) { + css__parse_expected(ctx, data, datalen); + } + } + + return true; +} + +void css__parse_tree(line_ctx *ctx, const char *data, size_t len) +{ + const char *p = data; + const char *end = data + len; + size_t left; + + /* [ ? ] ? */ + + ctx->media = CSS_MEDIA_ALL; + ctx->pseudo_element = CSS_PSEUDO_ELEMENT_NONE; + + /* Consume any leading whitespace */ + while (p < end && isspace(*p)) + p++; + + if (p < end) { + left = end - p; + + css__parse_media_list(&p, &left, &ctx->media); + + end = p + left; + } + + if (p < end) { + left = end - p; + + css__parse_pseudo_list(&p, &left, &ctx->pseudo_element); + } +} + +void css__parse_tree_data(line_ctx *ctx, const char *data, size_t len) +{ + const char *p = data; + const char *end = data + len; + const char *name = NULL; + const char *value = NULL; + size_t namelen = 0; + size_t valuelen = 0; + uint32_t depth = 0; + bool target = false; + + /* ' '{depth+1} [ '*'? | ] + * + * ::= [^=*[:space:]]+ + * ::= [^=*[:space:]]+ '=' [^[:space:]]* + */ + + while (p < end && isspace(*p)) { + depth++; + p++; + } + depth--; + + /* Get element/attribute name */ + name = p; + while (p < end && *p != '=' && *p != '*' && isspace(*p) == false) { + namelen++; + p++; + } + + /* Skip whitespace */ + while (p < end && isspace(*p)) + p++; + + if (p < end && *p == '=') { + /* Attribute value */ + p++; + + value = p; + + while (p < end && isspace(*p) == false) { + valuelen++; + p++; + } + } else if (p < end && *p == '*') { + /* Element is target node */ + target = true; + } + + if (value == NULL) { + /* We have an element, so create it */ + node *n = malloc(sizeof(node)); + assert(n != NULL); + + memset(n, 0, sizeof(node)); + + lwc_intern_string(name, namelen, &n->name); + + /* Insert it into tree */ + if (ctx->tree == NULL) { + ctx->tree = n; + } else { + assert(depth > 0); + assert(depth <= ctx->depth + 1); + + /* Find node to insert into */ + while (depth <= ctx->depth) { + ctx->depth--; + ctx->current = ctx->current->parent; + } + + /* Insert into current node */ + if (ctx->current->children == NULL) { + ctx->current->children = n; + ctx->current->last_child = n; + } else { + ctx->current->last_child->next = n; + n->prev = ctx->current->last_child; + + ctx->current->last_child = n; + } + n->parent = ctx->current; + } + + ctx->current = n; + ctx->depth = depth; + + /* Mark the target, if it's us */ + if (target) + ctx->target = n; + } else { + /* New attribute */ + bool amatch = false; + attribute *attr; + node *n = ctx->current; + + attribute *temp = realloc(n->attrs, + (n->n_attrs + 1) * sizeof(attribute)); + assert(temp != NULL); + + n->attrs = temp; + + attr = &n->attrs[n->n_attrs]; + + lwc_intern_string(name, namelen, &attr->name); + lwc_intern_string(value, valuelen, &attr->value); + + assert(lwc_string_caseless_isequal( + n->attrs[n->n_attrs].name, + ctx->attr_class, &amatch) == lwc_error_ok); + if (amatch == true) { + n->classes = realloc(NULL, sizeof(lwc_string **)); + assert(n->classes != NULL); + + n->classes[0] = lwc_string_ref( + n->attrs[n->n_attrs]. + value); + n->n_classes = 1; + } + + n->n_attrs++; + } +} + +void css__parse_sheet(line_ctx *ctx, const char *data, size_t len) +{ + css_stylesheet_params params; + const char *p; + const char *end = data + len; + css_origin origin = CSS_ORIGIN_AUTHOR; + uint64_t media = CSS_MEDIA_ALL; + css_stylesheet *sheet; + sheet_ctx *temp; + + /* ? */ + + /* Find end of origin */ + for (p = data; p < end; p++) { + if (isspace(*p)) + break; + } + + if (p - data == 6 && strncasecmp(data, "author", 6) == 0) + origin = CSS_ORIGIN_AUTHOR; + else if (p - data == 4 && strncasecmp(data, "user", 4) == 0) + origin = CSS_ORIGIN_USER; + else if (p - data == 2 && strncasecmp(data, "ua", 2) == 0) + origin = CSS_ORIGIN_UA; + else + assert(0 && "Unknown stylesheet origin"); + + /* Skip any whitespace */ + while (p < end && isspace(*p)) + p++; + + if (p < end) { + size_t ignored = end - p; + + css__parse_media_list(&p, &ignored, &media); + } + + params.params_version = CSS_STYLESHEET_PARAMS_VERSION_1; + params.level = CSS_LEVEL_21; + params.charset = "UTF-8"; + params.url = "foo"; + params.title = "foo"; + params.allow_quirks = false; + params.inline_style = false; + params.resolve = resolve_url; + params.resolve_pw = NULL; + params.import = NULL; + params.import_pw = NULL; + params.color = NULL; + params.color_pw = NULL; + params.font = NULL; + params.font_pw = NULL; + + /** \todo How are we going to handle @import? */ + assert(css_stylesheet_create(¶ms, &sheet) == CSS_OK); + + /* Extend array of sheets and append new sheet to it */ + temp = realloc(ctx->sheets, + (ctx->n_sheets + 1) * sizeof(sheet_ctx)); + assert(temp != NULL); + + ctx->sheets = temp; + + ctx->sheets[ctx->n_sheets].sheet = sheet; + ctx->sheets[ctx->n_sheets].origin = origin; + ctx->sheets[ctx->n_sheets].media = media; + + ctx->n_sheets++; +} + +void css__parse_media_list(const char **data, size_t *len, uint64_t *media) +{ + const char *p = *data; + const char *end = p + *len; + uint64_t result = 0; + + /* [ ',' ]* */ + + while (p < end) { + const char *start = p; + + /* consume a medium */ + while (isspace(*p) == false && *p != ',') + p++; + + if (p - start == 10 && + strncasecmp(start, "projection", 10) == 0) + result |= CSS_MEDIA_PROJECTION; + else if (p - start == 8 && + strncasecmp(start, "handheld", 8) == 0) + result |= CSS_MEDIA_HANDHELD; + else if (p - start == 8 && + strncasecmp(start, "embossed", 8) == 0) + result |= CSS_MEDIA_EMBOSSED; + else if (p - start == 7 && + strncasecmp(start, "braille", 7) == 0) + result |= CSS_MEDIA_BRAILLE; + else if (p - start == 6 && + strncasecmp(start, "speech", 6) == 0) + result |= CSS_MEDIA_SPEECH; + else if (p - start == 6 && + strncasecmp(start, "screen", 6) == 0) + result |= CSS_MEDIA_SCREEN; + else if (p - start == 5 && + strncasecmp(start, "print", 5) == 0) + result |= CSS_MEDIA_PRINT; + else if (p - start == 5 && + strncasecmp(start, "aural", 5) == 0) + result |= CSS_MEDIA_AURAL; + else if (p - start == 3 && + strncasecmp(start, "tty", 3) == 0) + result |= CSS_MEDIA_TTY; + else if (p - start == 3 && + strncasecmp(start, "all", 3) == 0) + result |= CSS_MEDIA_ALL; + else if (p - start == 2 && + strncasecmp(start, "tv", 2) == 0) + result |= CSS_MEDIA_TV; + else + assert(0 && "Unknown media type"); + + /* Consume whitespace */ + while (p < end && isspace(*p)) + p++; + + /* Stop if we've reached the end */ + if (p == end || *p != ',') + break; + + /* Consume comma */ + p++; + + /* Consume whitespace */ + while (p < end && isspace(*p)) + p++; + } + + *media = result; + + *data = p; + *len = end - p; +} + +void css__parse_pseudo_list(const char **data, size_t *len, uint32_t *element) +{ + const char *p = *data; + const char *end = p + *len; + + /* [ ',' ]* */ + + *element = CSS_PSEUDO_ELEMENT_NONE; + + while (p < end) { + const char *start = p; + + /* consume a pseudo */ + while (isspace(*p) == false && *p != ',') + p++; + + /* Pseudo elements */ + if (p - start == 12 && + strncasecmp(start, "first-letter", 12) == 0) + *element = CSS_PSEUDO_ELEMENT_FIRST_LETTER; + else if (p - start == 10 && + strncasecmp(start, "first-line", 10) == 0) + *element = CSS_PSEUDO_ELEMENT_FIRST_LINE; + else if (p - start == 6 && + strncasecmp(start, "before", 6) == 0) + *element = CSS_PSEUDO_ELEMENT_BEFORE; + else if (p - start == 5 && + strncasecmp(start, "after", 5) == 0) + *element = CSS_PSEUDO_ELEMENT_AFTER; + else + assert(0 && "Unknown pseudo"); + + /* Consume whitespace */ + while (p < end && isspace(*p)) + p++; + + /* Stop if we've reached the end */ + if (p == end || *p != ',') + break; + + /* Consume comma */ + p++; + + /* Consume whitespace */ + while (p < end && isspace(*p)) + p++; + } + + *data = p; + *len = end - p; +} + +void css__parse_expected(line_ctx *ctx, const char *data, size_t len) +{ + while (ctx->expused + len >= ctx->explen) { + size_t required = ctx->explen == 0 ? 64 : ctx->explen * 2; + char *temp = realloc(ctx->exp, required); + if (temp == NULL) { + assert(0 && "No memory for expected output"); + } + + ctx->exp = temp; + ctx->explen = required; + } + + memcpy(ctx->exp + ctx->expused, data, len); + + ctx->expused += len; +} + +void run_test(line_ctx *ctx, const char *exp, size_t explen) +{ + css_select_ctx *select; + css_select_results *results; + uint32_t i; + char *buf; + size_t buflen; + static int testnum; + + UNUSED(exp); + + buf = malloc(8192); + if (buf == NULL) { + assert(0 && "No memory for result data"); + } + buflen = 8192; + + assert(css_select_ctx_create(&select) == CSS_OK); + + for (i = 0; i < ctx->n_sheets; i++) { + assert(css_select_ctx_append_sheet(select, + ctx->sheets[i].sheet, ctx->sheets[i].origin, + ctx->sheets[i].media) == CSS_OK); + } + + testnum++; + + assert(css_select_style(select, ctx->target, ctx->media, NULL, + &select_handler, ctx, &results) == CSS_OK); + + assert(results->styles[ctx->pseudo_element] != NULL); + + dump_computed_style(results->styles[ctx->pseudo_element], buf, &buflen); + + if (8192 - buflen != explen || memcmp(buf, exp, explen) != 0) { + printf("Expected (%u):\n%.*s\n", + (int) explen, (int) explen, exp); + printf("Result (%u):\n%.*s\n", (int) (8192 - buflen), + (int) (8192 - buflen), buf); + assert(0 && "Result doesn't match expected"); + } + + /* Clean up */ + css_select_results_destroy(results); + css_select_ctx_destroy(select); + + destroy_tree(ctx->tree); + + for (i = 0; i < ctx->n_sheets; i++) { + css_stylesheet_destroy(ctx->sheets[i].sheet); + } + + ctx->tree = NULL; + ctx->current = NULL; + ctx->depth = 0; + ctx->n_sheets = 0; + free(ctx->sheets); + ctx->sheets = NULL; + ctx->target = NULL; + + free(buf); + + printf("Test %d: PASS\n", testnum); +} + +void destroy_tree(node *root) +{ + node *n, *p; + uint32_t i; + + for (n = root->children; n != NULL; n = p) { + p = n->next; + + destroy_tree(n); + } + + for (i = 0; i < root->n_attrs; ++i) { + lwc_string_unref(root->attrs[i].name); + lwc_string_unref(root->attrs[i].value); + } + free(root->attrs); + + if (root->classes != NULL) { + for (i = 0; i < root->n_classes; ++i) { + lwc_string_unref(root->classes[i]); + } + free(root->classes); + } + + if (root->libcss_node_data != NULL) { + css_libcss_node_data_handler(&select_handler, CSS_NODE_DELETED, + NULL, root, NULL, root->libcss_node_data); + } + + lwc_string_unref(root->name); + free(root); +} + + +css_error node_name(void *pw, void *n, css_qname *qname) +{ + node *node = n; + + UNUSED(pw); + + qname->name = lwc_string_ref(node->name); + + return CSS_OK; +} + +static css_error node_classes(void *pw, void *n, + lwc_string ***classes, uint32_t *n_classes) +{ + unsigned int i; + node *node = n; + UNUSED(pw); + + *classes = node->classes; + *n_classes = node->n_classes; + + for (i = 0; i < *n_classes; i++) + (*classes)[i] = lwc_string_ref(node->classes[i]); + + return CSS_OK; + +} + +css_error node_id(void *pw, void *n, + lwc_string **id) +{ + node *node = n; + uint32_t i; + line_ctx *lc = pw; + + for (i = 0; i < node->n_attrs; i++) { + bool amatch = false; + assert(lwc_string_caseless_isequal( + node->attrs[i].name, lc->attr_id, &amatch) == + lwc_error_ok); + if (amatch == true) + break; + } + + if (i != node->n_attrs) + *id = lwc_string_ref(node->attrs[i].value); + else + *id = NULL; + + return CSS_OK; +} + +css_error named_ancestor_node(void *pw, void *n, + const css_qname *qname, + void **ancestor) +{ + node *node = n; + UNUSED(pw); + + for (node = node->parent; node != NULL; node = node->parent) { + bool match = false; + assert(lwc_string_caseless_isequal( + qname->name, node->name, + &match) == lwc_error_ok); + if (match == true) + break; + } + + *ancestor = (void *) node; + + return CSS_OK; +} + +css_error named_parent_node(void *pw, void *n, + const css_qname *qname, + void **parent) +{ + node *node = n; + UNUSED(pw); + + *parent = NULL; + if (node->parent != NULL) { + bool match = false; + assert(lwc_string_caseless_isequal( + qname->name, node->parent->name, &match) == + lwc_error_ok); + if (match == true) + *parent = (void *) node->parent; + } + + return CSS_OK; +} + +css_error named_sibling_node(void *pw, void *n, + const css_qname *qname, + void **sibling) +{ + node *node = n; + UNUSED(pw); + + *sibling = NULL; + if (node->prev != NULL) { + bool match = false; + assert(lwc_string_caseless_isequal( + qname->name, node->prev->name, &match) == + lwc_error_ok); + if (match == true) + *sibling = (void *) node->prev; + } + + return CSS_OK; +} + +css_error named_generic_sibling_node(void *pw, void *n, + const css_qname *qname, + void **sibling) +{ + node *node = n; + UNUSED(pw); + + for (node = node->prev; node != NULL; node = node->prev) { + bool match = false; + assert(lwc_string_caseless_isequal( + qname->name, node->name, + &match) == lwc_error_ok); + if (match == true) + break; + } + + *sibling = (void *) node; + + return CSS_OK; +} + +css_error parent_node(void *pw, void *n, void **parent) +{ + node *node = n; + + UNUSED(pw); + + *parent = (void *) node->parent; + + return CSS_OK; +} + +css_error sibling_node(void *pw, void *n, void **sibling) +{ + node *node = n; + + UNUSED(pw); + + *sibling = (void *) node->prev; + + return CSS_OK; +} + +css_error node_has_name(void *pw, void *n, + const css_qname *qname, + bool *match) +{ + node *node = n; + UNUSED(pw); + + if (lwc_string_length(qname->name) == 1 && + lwc_string_data(qname->name)[0] == '*') + *match = true; + else + assert(lwc_string_caseless_isequal(node->name, + qname->name, match) == lwc_error_ok); + + return CSS_OK; +} + +css_error node_has_class(void *pw, void *n, + lwc_string *name, + bool *match) +{ + node *node = n; + uint32_t i; + line_ctx *ctx = pw; + + for (i = 0; i < node->n_attrs; i++) { + bool amatch = false; + assert(lwc_string_caseless_isequal( + node->attrs[i].name, ctx->attr_class, + &amatch) == lwc_error_ok); + if (amatch == true) + break; + } + + /* Classes are case-sensitive in HTML */ + if (i != node->n_attrs && name == node->attrs[i].value) + *match = true; + else + *match = false; + + return CSS_OK; +} + +css_error node_has_id(void *pw, void *n, + lwc_string *name, + bool *match) +{ + node *node = n; + uint32_t i; + line_ctx *ctx = pw; + + for (i = 0; i < node->n_attrs; i++) { + bool amatch = false; + assert(lwc_string_caseless_isequal( + node->attrs[i].name, ctx->attr_id, &amatch) == + lwc_error_ok); + if (amatch == true) + break; + } + + /* IDs are case-sensitive in HTML */ + if (i != node->n_attrs && name == node->attrs[i].value) + *match = true; + else + *match = false; + + return CSS_OK; +} + +css_error node_has_attribute(void *pw, void *n, + const css_qname *qname, + bool *match) +{ + node *node = n; + uint32_t i; + UNUSED(pw); + + *match = false; + for (i = 0; i < node->n_attrs; i++) { + assert(lwc_string_caseless_isequal( + node->attrs[i].name, qname->name, match) == + lwc_error_ok); + if (*match == true) + break; + } + + return CSS_OK; +} + +css_error node_has_attribute_equal(void *pw, void *n, + const css_qname *qname, + lwc_string *value, + bool *match) +{ + node *node = n; + uint32_t i; + UNUSED(pw); + + *match = false; + + for (i = 0; i < node->n_attrs; i++) { + assert(lwc_string_caseless_isequal( + node->attrs[i].name, qname->name, match) == + lwc_error_ok); + if (*match == true) + break; + } + + if (*match == true) { + assert(lwc_string_caseless_isequal( + node->attrs[i].name, value, match) == + lwc_error_ok); + } + + return CSS_OK; +} + +css_error node_has_attribute_includes(void *pw, void *n, + const css_qname *qname, + lwc_string *value, + bool *match) +{ + node *node = n; + uint32_t i; + size_t vlen = lwc_string_length(value); + UNUSED(pw); + + *match = false; + + for (i = 0; i < node->n_attrs; i++) { + assert(lwc_string_caseless_isequal( + node->attrs[i].name, qname->name, match) == + lwc_error_ok); + if (*match == true) + break; + } + + if (*match == true) { + const char *p; + const char *start = lwc_string_data(node->attrs[i].value); + const char *end = start + + lwc_string_length(node->attrs[i].value); + + *match = false; + + for (p = start; p < end; p++) { + if (*p == ' ') { + if ((size_t) (p - start) == vlen && + strncasecmp(start, + lwc_string_data(value), + vlen) == 0) { + *match = true; + break; + } + + start = p + 1; + } + } + } + + return CSS_OK; +} + +css_error node_has_attribute_dashmatch(void *pw, void *n, + const css_qname *qname, + lwc_string *value, + bool *match) +{ + node *node = n; + uint32_t i; + size_t vlen = lwc_string_length(value); + UNUSED(pw); + + *match = false; + + for (i = 0; i < node->n_attrs; i++) { + assert(lwc_string_caseless_isequal( + node->attrs[i].name, qname->name, match) == + lwc_error_ok); + if (*match == true) + break; + } + + if (*match == true) { + const char *p; + const char *start = lwc_string_data(node->attrs[i].value); + const char *end = start + + lwc_string_length(node->attrs[i].value); + + *match = false; + + for (p = start; p < end; p++) { + if (*p == '-') { + if ((size_t) (p - start) == vlen && + strncasecmp(start, + lwc_string_data(value), + vlen) == 0) { + *match = true; + break; + } + + start = p + 1; + } + } + } + + return CSS_OK; +} + +css_error node_has_attribute_prefix(void *pw, void *n, + const css_qname *qname, + lwc_string *value, + bool *match) +{ + node *node = n; + uint32_t i; + UNUSED(pw); + + *match = false; + + for (i = 0; i < node->n_attrs; i++) { + assert(lwc_string_caseless_isequal( + node->attrs[i].name, qname->name, match) == + lwc_error_ok); + if (*match == true) + break; + } + + if (*match == true) { + size_t len = lwc_string_length(node->attrs[i].value); + const char *data = lwc_string_data(node->attrs[i].value); + + size_t vlen = lwc_string_length(value); + const char *vdata = lwc_string_data(value); + + if (len < vlen) + *match = false; + else + *match = (strncasecmp(data, vdata, vlen) == 0); + } + + return CSS_OK; +} + +css_error node_has_attribute_suffix(void *pw, void *n, + const css_qname *qname, + lwc_string *value, + bool *match) +{ + node *node = n; + uint32_t i; + UNUSED(pw); + + *match = false; + + for (i = 0; i < node->n_attrs; i++) { + assert(lwc_string_caseless_isequal( + node->attrs[i].name, qname->name, match) == + lwc_error_ok); + if (*match == true) + break; + } + + if (*match == true) { + size_t len = lwc_string_length(node->attrs[i].value); + const char *data = lwc_string_data(node->attrs[i].value); + + size_t vlen = lwc_string_length(value); + const char *vdata = lwc_string_data(value); + + size_t suffix_start = len - vlen; + + if (len < vlen) + *match = false; + else { + *match = (strncasecmp(data + suffix_start, + vdata, vlen) == 0); + } + } + + return CSS_OK; +} + +css_error node_has_attribute_substring(void *pw, void *n, + const css_qname *qname, + lwc_string *value, + bool *match) +{ + node *node = n; + uint32_t i; + UNUSED(pw); + + *match = false; + + for (i = 0; i < node->n_attrs; i++) { + assert(lwc_string_caseless_isequal( + node->attrs[i].name, qname->name, match) == + lwc_error_ok); + if (*match == true) + break; + } + + if (*match == true) { + size_t len = lwc_string_length(node->attrs[i].value); + const char *data = lwc_string_data(node->attrs[i].value); + + size_t vlen = lwc_string_length(value); + const char *vdata = lwc_string_data(value); + + const char *last_start = data + len - vlen; + + if (len < vlen) + *match = false; + else { + while (data <= last_start) { + if (strncasecmp(data, vdata, vlen) == 0) { + *match = true; + break; + } + + data++; + } + + if (data > last_start) + *match = false; + } + } + + return CSS_OK; +} + +css_error node_is_root(void *pw, void *n, bool *match) +{ + node *node = n; + UNUSED(pw); + + *match = (node->parent == NULL); + + return CSS_OK; +} + +css_error node_count_siblings(void *pw, void *n, + bool same_name, bool after, int32_t *count) +{ + int32_t cnt = 0; + bool match = false; + node *node = n; + lwc_string *name = node->name; + UNUSED(pw); + + if (after) { + while (node->next != NULL) { + if (same_name) { + assert(lwc_string_caseless_isequal( + name, node->next->name, &match) == + lwc_error_ok); + + if (match) + cnt++; + } else { + cnt++; + } + + node = node->next; + } + } else { + while (node->prev != NULL) { + if (same_name) { + assert(lwc_string_caseless_isequal( + name, node->prev->name, &match) == + lwc_error_ok); + + if (match) + cnt++; + } else { + cnt++; + } + + node = node->prev; + } + } + + *count = cnt; + + return CSS_OK; +} + +css_error node_is_empty(void *pw, void *n, bool *match) +{ + node *node = n; + UNUSED(pw); + + *match = (node->children == NULL); + + return CSS_OK; +} + +css_error node_is_link(void *pw, void *n, bool *match) +{ + node *node = n; + + UNUSED(pw); + UNUSED(node); + + *match = false; + + return CSS_OK; +} + +css_error node_is_visited(void *pw, void *n, bool *match) +{ + node *node = n; + + UNUSED(pw); + UNUSED(node); + + *match = false; + + return CSS_OK; +} + +css_error node_is_hover(void *pw, void *n, bool *match) +{ + node *node = n; + + UNUSED(pw); + UNUSED(node); + + *match = false; + + return CSS_OK; +} + +css_error node_is_active(void *pw, void *n, bool *match) +{ + node *node = n; + + UNUSED(pw); + UNUSED(node); + + *match = false; + + return CSS_OK; +} + +css_error node_is_focus(void *pw, void *n, bool *match) +{ + node *node = n; + + UNUSED(pw); + UNUSED(node); + + *match = false; + + return CSS_OK; +} + +css_error node_is_enabled(void *pw, void *n, bool *match) +{ + node *node = n; + + UNUSED(pw); + UNUSED(node); + + *match = false; + + return CSS_OK; +} + +css_error node_is_disabled(void *pw, void *n, bool *match) +{ + node *node = n; + + UNUSED(pw); + UNUSED(node); + + *match = false; + + return CSS_OK; +} + +css_error node_is_checked(void *pw, void *n, bool *match) +{ + node *node = n; + + UNUSED(pw); + UNUSED(node); + + *match = false; + + return CSS_OK; +} + +css_error node_is_target(void *pw, void *n, bool *match) +{ + node *node = n; + + UNUSED(pw); + UNUSED(node); + + *match = false; + + return CSS_OK; +} + +css_error node_is_lang(void *pw, void *n, + lwc_string *lang, + bool *match) +{ + node *node = n; + + UNUSED(pw); + UNUSED(node); + UNUSED(lang); + + *match = false; + + return CSS_OK; +} + +css_error node_presentational_hint(void *pw, void *node, + uint32_t property, css_hint *hint) +{ + UNUSED(pw); + UNUSED(node); + UNUSED(property); + UNUSED(hint); + + return CSS_PROPERTY_NOT_SET; +} + +css_error ua_default_for_property(void *pw, uint32_t property, css_hint *hint) +{ + UNUSED(pw); + + 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; + hint->status = CSS_FONT_FAMILY_SANS_SERIF; + } else if (property == CSS_PROP_QUOTES) { + /* 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 compute_font_size(void *pw, const css_hint *parent, css_hint *size) +{ + static css_hint_length sizes[] = { + { FLTTOFIX(6.75), CSS_UNIT_PT }, + { FLTTOFIX(7.50), CSS_UNIT_PT }, + { FLTTOFIX(9.75), CSS_UNIT_PT }, + { FLTTOFIX(12.0), CSS_UNIT_PT }, + { FLTTOFIX(13.5), CSS_UNIT_PT }, + { FLTTOFIX(18.0), CSS_UNIT_PT }, + { FLTTOFIX(24.0), CSS_UNIT_PT } + }; + const css_hint_length *parent_size; + + UNUSED(pw); + + /* Grab parent size, defaulting to medium if none */ + if (parent == NULL) { + parent_size = &sizes[CSS_FONT_SIZE_MEDIUM - 1]; + } else { + assert(parent->status == CSS_FONT_SIZE_DIMENSION); + assert(parent->data.length.unit != CSS_UNIT_EM); + assert(parent->data.length.unit != CSS_UNIT_EX); + parent_size = &parent->data.length; + } + + assert(size->status != CSS_FONT_SIZE_INHERIT); + + if (size->status < CSS_FONT_SIZE_LARGER) { + /* Keyword -- simple */ + size->data.length = sizes[size->status - 1]; + } 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 = + FMUL(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) { + 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), FLTTOFIX(100)); + size->data.length.unit = parent_size->unit; + } + + size->status = CSS_FONT_SIZE_DIMENSION; + + return CSS_OK; +} + +static css_error set_libcss_node_data(void *pw, void *n, + void *libcss_node_data) +{ + node *node = n; + UNUSED(pw); + + node->libcss_node_data = libcss_node_data; + + return CSS_OK; +} + + diff --git a/test/select-nd.c b/test/select-nd.c new file mode 100644 index 0000000..6469267 --- /dev/null +++ b/test/select-nd.c @@ -0,0 +1,14 @@ + +#include "select-common.c" + +static css_error get_libcss_node_data(void *pw, void *n, + void **libcss_node_data) +{ + node *node = n; + UNUSED(pw); + + /* Pass any node data back to libcss */ + *libcss_node_data = node->libcss_node_data; + + return CSS_OK; +} diff --git a/test/select-no-nd.c b/test/select-no-nd.c new file mode 100644 index 0000000..8eb3735 --- /dev/null +++ b/test/select-no-nd.c @@ -0,0 +1,14 @@ + +#include "select-common.c" + +static css_error get_libcss_node_data(void *pw, void *n, + void **libcss_node_data) +{ + UNUSED(pw); + UNUSED(n); + + /* Test case were node data is deleted, by not passing any node data */ + *libcss_node_data = NULL; + + return CSS_OK; +} -- cgit v1.2.3