/* * This file is part of LibCSS * Licensed under the MIT License, * http://www.opensource.org/licenses/mit-license.php * Copyright 2009 John-Mark Bell <jmb@netsurf-browser.org> */ #include <assert.h>#include <string.h> #include <libcss/select.h> #include "bytecode/bytecode.h"#include "bytecode/opcodes.h"#include "stylesheet.h"#include "select/computed.h"#include "select/dispatch.h"#include "select/hash.h"#include "select/propset.h"#include "select/select.h"#include "utils/parserutilserror.h"#include "utils/utils.h" /* Define this to enable verbose messages when matching selector chains */#undef DEBUG_CHAIN_MATCHING /** * Container for stylesheet selection info */typedef struct css_select_sheet { const css_stylesheet *sheet; /**< Stylesheet */ css_origin origin; /**< Stylesheet origin */ uint64_t media; /**< Applicable media */} css_select_sheet; /** * CSS selection context */struct css_select_ctx { uint32_t n_sheets; /**< Number of sheets */ css_select_sheet *sheets; /**< Array of sheets */ css_allocator_fn alloc; /**< Allocation routine */ void *pw; /**< Client-specific private data */ /* Useful interned strings */ lwc_string *universal; lwc_string *first_child; lwc_string *link; lwc_string *visited; lwc_string *hover; lwc_string *active; lwc_string *focus; lwc_string *nth_child; lwc_string *nth_last_child; lwc_string *nth_of_type; lwc_string *nth_last_of_type; lwc_string *last_child; lwc_string *first_of_type; lwc_string *last_of_type; lwc_string *only_child; lwc_string *only_of_type; lwc_string *root; lwc_string *empty; lwc_string *target; lwc_string *lang; lwc_string *enabled; lwc_string *disabled; lwc_string *checked; lwc_string *first_line; lwc_string *first_letter; lwc_string *before; lwc_string *after;}; static css_error set_hint(css_select_state *state, uint32_t prop);static css_error set_initial(css_select_state *state, uint32_t prop, css_pseudo_element pseudo, void *parent); static css_error intern_strings(css_select_ctx *ctx);static void destroy_strings(css_select_ctx *ctx); static css_error select_from_sheet(css_select_ctx *ctx, const css_stylesheet *sheet, css_origin origin, css_select_state *state);static css_error match_selectors_in_sheet(css_select_ctx *ctx, const css_stylesheet *sheet, css_select_state *state);static css_error match_selector_chain(css_select_ctx *ctx, const css_selector *selector, css_select_state *state);static css_error match_named_combinator(css_select_ctx *ctx, css_combinator type, const css_selector *selector, css_select_state *state, void *node, void **next_node);static css_error match_universal_combinator(css_select_ctx *ctx, css_combinator type, const css_selector *selector, css_select_state *state, void *node, void **next_node);static css_error match_details(css_select_ctx *ctx, void *node, const css_selector_detail *detail, css_select_state *state, bool *match, css_pseudo_element *pseudo_element);static css_error match_detail(css_select_ctx *ctx, void *node, const css_selector_detail *detail, css_select_state *state, bool *match, css_pseudo_element *pseudo_element);static css_error cascade_style(const css_style *style, css_select_state *state); #ifdef DEBUG_CHAIN_MATCHINGstatic void dump_chain(const css_selector *selector);#endif /** * 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_select_ctx *c; css_error error; if (alloc == NULL || result == NULL) return CSS_BADPARM; c = alloc(NULL, sizeof(css_select_ctx), pw); if (c == NULL) return CSS_NOMEM; memset(c, 0, sizeof(css_select_ctx)); error = intern_strings(c); if (error != CSS_OK) { alloc(c, 0, pw); return error; } c->alloc = alloc; c->pw = pw; *result = c; return CSS_OK;} /** * Destroy a selection context * * \param ctx The context to destroy * \return CSS_OK on success, appropriate error otherwise */css_error css_select_ctx_destroy(css_select_ctx *ctx){ if (ctx == NULL) return CSS_BADPARM; destroy_strings(ctx); if (ctx->sheets != NULL) ctx->alloc(ctx->sheets, 0, ctx->pw); ctx->alloc(ctx, 0, ctx->pw); return CSS_OK;} /** * Append a stylesheet to a selection context * * \param ctx The context to append to * \param sheet The sheet to append * \param origin Origin of the sheet * \param media Media types to which the sheet applies * \return CSS_OK on success, appropriate error otherwise */css_error css_select_ctx_append_sheet(css_select_ctx *ctx, const css_stylesheet *sheet, css_origin origin, uint64_t media){ if (ctx == NULL || sheet == NULL) return CSS_BADPARM; return css_select_ctx_insert_sheet(ctx, sheet, ctx->n_sheets, origin, media);} /** * Insert a stylesheet into a selection context * * \param ctx The context to insert into * \param sheet Sheet to insert * \param index Index in context to insert sheet * \param origin Origin of the sheet * \param media Media types to which the sheet applies * \return CSS_OK on success, appropriate error otherwise */css_error css_select_ctx_insert_sheet(css_select_ctx *ctx, const css_stylesheet *sheet, uint32_t index, css_origin origin, uint64_t media){ css_select_sheet *temp; if (ctx == NULL || sheet == NULL) return CSS_BADPARM; /* Inline styles cannot be inserted into a selection context */ if (sheet->inline_style) return CSS_INVALID; /* Index must be in the range [0, n_sheets] * The latter being equivalent to append */ if (index > ctx->n_sheets) return CSS_INVALID; temp = ctx->alloc(ctx->sheets, (ctx->n_sheets + 1) * sizeof(css_select_sheet), ctx->pw); if (temp == NULL) return CSS_NOMEM; ctx->sheets = temp; if (index < ctx->n_sheets) { memmove(&ctx->sheets[index + 1], &ctx->sheets[index], (ctx->n_sheets - index) * sizeof(css_select_sheet)); } ctx->sheets[index].sheet = sheet; ctx->sheets[index].origin = origin; ctx->sheets[index].media = media; ctx->n_sheets++; return CSS_OK;} /** * Remove a sheet from a selection context * * \param ctx The context to remove from * \param sheet Sheet to remove * \return CSS_OK on success, appropriate error otherwise */css_error css_select_ctx_remove_sheet(css_select_ctx *ctx, const css_stylesheet *sheet){ uint32_t index; if (ctx == NULL || sheet == NULL) return CSS_BADPARM; for (index = 0; index < ctx->n_sheets; index++) { if (ctx->sheets[index].sheet == sheet) break; } if (index == ctx->n_sheets) return CSS_INVALID; memmove(&ctx->sheets[index], &ctx->sheets[index + 1], (ctx->n_sheets - index) * sizeof(css_select_sheet)); ctx->n_sheets--; return CSS_OK; } /** * Count the number of top-level sheets in a selection context * * \param ctx Context to consider * \param count Pointer to location to receive count of sheets * \return CSS_OK on success, appropriate error otherwise */css_error css_select_ctx_count_sheets(css_select_ctx *ctx, uint32_t *count){ if (ctx == NULL || count == NULL) return CSS_BADPARM; *count = ctx->n_sheets; return CSS_OK;} /** * Retrieve a sheet from a selection context * * \param ctx Context to look in * \param index Index in context to look * \param sheet Pointer to location to receive sheet * \return CSS_OK on success, appropriate error otherwise */css_error css_select_ctx_get_sheet(css_select_ctx *ctx, uint32_t index, const css_stylesheet **sheet){ if (ctx == NULL || sheet == NULL) return CSS_BADPARM; if (index > ctx->n_sheets) return CSS_INVALID; *sheet = ctx->sheets[index].sheet; return CSS_OK;} /** * Select a style for the given node * * \param ctx Selection context to use * \param node Node to select style for * \param media Currently active media types * \param inline_style Corresponding inline style for node, or NULL * \param handler Dispatch table of handler functions * \param pw Client-specific private data for handler functions * \param result Pointer to location to receive result set * \return CSS_OK on success, appropriate error otherwise. * * In computing the style, no reference is made to the parent node's * style. Therefore, the resultant computed style is not ready for * immediate use, as some properties may be marked as inherited. * Use css_computed_style_compose() to obtain a fully computed style. * * This two-step approach to style computation is designed to allow * the client to store the partially computed style and efficiently * update the fully computed style for a node when layout changes. */css_error css_select_style(css_select_ctx *ctx, void *node, uint64_t media, const css_stylesheet *inline_style, css_select_handler *handler, void *pw, css_select_results **result){ uint32_t i, j; css_error error; css_select_state state; void *parent = NULL; if (ctx == NULL || node == NULL || result == NULL || handler == NULL || handler->handler_version != CSS_SELECT_HANDLER_VERSION_1) return CSS_BADPARM; /* Set up the selection state */ memset(&state, 0, sizeof(css_select_state)); state.node = node; state.media = media; state.handler = handler; state.pw = pw; /* Allocate the result set */ state.results = ctx->alloc(NULL, sizeof(css_select_results), ctx->pw); 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, &state.results->styles[CSS_PSEUDO_ELEMENT_NONE]); if (error != CSS_OK) { ctx->alloc(state.results, 0, ctx->pw); return error; } error = handler->parent_node(pw, node, &parent); if (error != CSS_OK) goto cleanup; /* Get node's name */ error = handler->node_name(pw, node, &state.element); if (error != CSS_OK) return error; /* Get node's ID, if any */ error = handler->node_id(pw, node, &state.id); if (error != CSS_OK) 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, &state.classes, &state.n_classes); if (error != CSS_OK) goto cleanup; /* Iterate through the top-level stylesheets, selecting styles * from those which apply to our current media requirements and * are not disabled */ for (i = 0; i < ctx->n_sheets; i++) { const css_select_sheet s = ctx->sheets[i]; if ((s.media & media) != 0 && s.sheet->disabled == false) { error = select_from_sheet(ctx, s.sheet, s.origin, &state); if (error != CSS_OK) goto cleanup; } } /* Consider any inline style for the node */ if (inline_style != NULL) { css_rule_selector *sel = (css_rule_selector *) inline_style->rule_list; /* Sanity check style */ if (inline_style->rule_count != 1 || inline_style->rule_list->type != CSS_RULE_SELECTOR || inline_style->rule_list->items != 0) { error = CSS_INVALID; goto cleanup; } /* No bytecode if input was empty or wholly invalid */ if (sel->style != NULL) { /* Inline style applies to base element only */ state.current_pseudo = CSS_PSEUDO_ELEMENT_NONE; state.computed = state.results->styles[ CSS_PSEUDO_ELEMENT_NONE]; error = cascade_style(sel->style, &state); if (error != CSS_OK) goto cleanup; } } /* Take account of presentational hints and fix up any remaining * unset properties. */ /* Base element */ state.current_pseudo = CSS_PSEUDO_ELEMENT_NONE; state.computed = state.results->styles[CSS_PSEUDO_ELEMENT_NONE]; for (i = 0; i < CSS_N_PROPERTIES; i++) { const prop_state *prop = &state.props[i][CSS_PSEUDO_ELEMENT_NONE]; /* Apply presentational hints if the property is unset or * the existing property value did not come from an author * stylesheet or a user sheet using !important. */ if (prop->set == false || (prop->origin != CSS_ORIGIN_AUTHOR && prop->important == false)) { error = set_hint(&state, i); if (error != CSS_OK) goto cleanup; } /* If the property is still unset or it's set to inherit * and we're the root element, then set it to its initial * value. */ if (prop->set == false || (parent == NULL && prop->inherit == true)) { error = set_initial(&state, i, CSS_PSEUDO_ELEMENT_NONE, parent); if (error != CSS_OK) goto cleanup; } } /* Pseudo elements, if any */ for (j = CSS_PSEUDO_ELEMENT_NONE + 1; j < CSS_PSEUDO_ELEMENT_COUNT; j++) { state.current_pseudo = j; state.computed = state.results->styles[j]; /* Skip non-existent pseudo elements */ if (state.computed == NULL) continue; for (i = 0; i < CSS_N_PROPERTIES; i++) { const prop_state *prop = &state.props[i][j]; /* If the property is still unset then set it * to its initial value. */ if (prop->set == false) { error = set_initial(&state, i, j, parent); if (error != CSS_OK) goto cleanup; } } } /* If this is the root element, then we must ensure that all * length values are absolute, display and float are correctly * computed, and the default border-{top,right,bottom,left}-color * is set to the computed value of color. */ if (parent == NULL) { /* Only compute absolute values for the base element */ error = css__compute_absolute_values(NULL, state.results->styles[CSS_PSEUDO_ELEMENT_NONE], handler->compute_font_size, pw);Lines 1–500 of 1855. Load more
/* * This file is part of LibCSS * Licensed under the MIT License, * http://www.opensource.org/licenses/mit-license.php * Copyright 2009 John-Mark Bell <jmb@netsurf-browser.org> */ #include <assert.h> #include <string.h> #include <libcss/select.h> #include "bytecode/bytecode.h" #include "bytecode/opcodes.h" #include "stylesheet.h" #include "select/computed.h" #include "select/dispatch.h" #include "select/hash.h" #include "select/propset.h" #include "select/select.h" #include "utils/parserutilserror.h" #include "utils/utils.h" /* Define this to enable verbose messages when matching selector chains */ #undef DEBUG_CHAIN_MATCHING /** * Container for stylesheet selection info */ typedef struct css_select_sheet { const css_stylesheet *sheet; /**< Stylesheet */ css_origin origin; /**< Stylesheet origin */ uint64_t media; /**< Applicable media */ } css_select_sheet; /** * CSS selection context */ struct css_select_ctx { uint32_t n_sheets; /**< Number of sheets */ css_select_sheet *sheets; /**< Array of sheets */ css_allocator_fn alloc; /**< Allocation routine */ void *pw; /**< Client-specific private data */ /* Useful interned strings */ lwc_string *universal; lwc_string *first_child; lwc_string *link; lwc_string *visited; lwc_string *hover; lwc_string *active; lwc_string *focus; lwc_string *nth_child; lwc_string *nth_last_child; lwc_string *nth_of_type; lwc_string *nth_last_of_type; lwc_string *last_child; lwc_string *first_of_type; lwc_string *last_of_type; lwc_string *only_child; lwc_string *only_of_type; lwc_string *root; lwc_string *empty; lwc_string *target; lwc_string *lang; lwc_string *enabled; lwc_string *disabled; lwc_string *checked; lwc_string *first_line; lwc_string *first_letter; lwc_string *before; lwc_string *after; }; static css_error set_hint(css_select_state *state, uint32_t prop); static css_error set_initial(css_select_state *state, uint32_t prop, css_pseudo_element pseudo, void *parent); static css_error intern_strings(css_select_ctx *ctx); static void destroy_strings(css_select_ctx *ctx); static css_error select_from_sheet(css_select_ctx *ctx, const css_stylesheet *sheet, css_origin origin, css_select_state *state); static css_error match_selectors_in_sheet(css_select_ctx *ctx, const css_stylesheet *sheet, css_select_state *state); static css_error match_selector_chain(css_select_ctx *ctx, const css_selector *selector, css_select_state *state); static css_error match_named_combinator(css_select_ctx *ctx, css_combinator type, const css_selector *selector, css_select_state *state, void *node, void **next_node); static css_error match_universal_combinator(css_select_ctx *ctx, css_combinator type, const css_selector *selector, css_select_state *state, void *node, void **next_node); static css_error match_details(css_select_ctx *ctx, void *node, const css_selector_detail *detail, css_select_state *state, bool *match, css_pseudo_element *pseudo_element); static css_error match_detail(css_select_ctx *ctx, void *node, const css_selector_detail *detail, css_select_state *state, bool *match, css_pseudo_element *pseudo_element); static css_error cascade_style(const css_style *style, css_select_state *state); #ifdef DEBUG_CHAIN_MATCHING static void dump_chain(const css_selector *selector); #endif /** * 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_select_ctx *c; css_error error; if (alloc == NULL || result == NULL) return CSS_BADPARM; c = alloc(NULL, sizeof(css_select_ctx), pw); if (c == NULL) return CSS_NOMEM; memset(c, 0, sizeof(css_select_ctx)); error = intern_strings(c); if (error != CSS_OK) { alloc(c, 0, pw); return error; } c->alloc = alloc; c->pw = pw; *result = c; return CSS_OK; } /** * Destroy a selection context * * \param ctx The context to destroy * \return CSS_OK on success, appropriate error otherwise */ css_error css_select_ctx_destroy(css_select_ctx *ctx) { if (ctx == NULL) return CSS_BADPARM; destroy_strings(ctx); if (ctx->sheets != NULL) ctx->alloc(ctx->sheets, 0, ctx->pw); ctx->alloc(ctx, 0, ctx->pw); return CSS_OK; } /** * Append a stylesheet to a selection context * * \param ctx The context to append to * \param sheet The sheet to append * \param origin Origin of the sheet * \param media Media types to which the sheet applies * \return CSS_OK on success, appropriate error otherwise */ css_error css_select_ctx_append_sheet(css_select_ctx *ctx, const css_stylesheet *sheet, css_origin origin, uint64_t media) { if (ctx == NULL || sheet == NULL) return CSS_BADPARM; return css_select_ctx_insert_sheet(ctx, sheet, ctx->n_sheets, origin, media); } /** * Insert a stylesheet into a selection context * * \param ctx The context to insert into * \param sheet Sheet to insert * \param index Index in context to insert sheet * \param origin Origin of the sheet * \param media Media types to which the sheet applies * \return CSS_OK on success, appropriate error otherwise */ css_error css_select_ctx_insert_sheet(css_select_ctx *ctx, const css_stylesheet *sheet, uint32_t index, css_origin origin, uint64_t media) { css_select_sheet *temp; if (ctx == NULL || sheet == NULL) return CSS_BADPARM; /* Inline styles cannot be inserted into a selection context */ if (sheet->inline_style) return CSS_INVALID; /* Index must be in the range [0, n_sheets] * The latter being equivalent to append */ if (index > ctx->n_sheets) return CSS_INVALID; temp = ctx->alloc(ctx->sheets, (ctx->n_sheets + 1) * sizeof(css_select_sheet), ctx->pw); if (temp == NULL) return CSS_NOMEM; ctx->sheets = temp; if (index < ctx->n_sheets) { memmove(&ctx->sheets[index + 1], &ctx->sheets[index], (ctx->n_sheets - index) * sizeof(css_select_sheet)); } ctx->sheets[index].sheet = sheet; ctx->sheets[index].origin = origin; ctx->sheets[index].media = media; ctx->n_sheets++; return CSS_OK; } /** * Remove a sheet from a selection context * * \param ctx The context to remove from * \param sheet Sheet to remove * \return CSS_OK on success, appropriate error otherwise */ css_error css_select_ctx_remove_sheet(css_select_ctx *ctx, const css_stylesheet *sheet) { uint32_t index; if (ctx == NULL || sheet == NULL) return CSS_BADPARM; for (index = 0; index < ctx->n_sheets; index++) { if (ctx->sheets[index].sheet == sheet) break; } if (index == ctx->n_sheets) return CSS_INVALID; memmove(&ctx->sheets[index], &ctx->sheets[index + 1], (ctx->n_sheets - index) * sizeof(css_select_sheet)); ctx->n_sheets--; return CSS_OK; } /** * Count the number of top-level sheets in a selection context * * \param ctx Context to consider * \param count Pointer to location to receive count of sheets * \return CSS_OK on success, appropriate error otherwise */ css_error css_select_ctx_count_sheets(css_select_ctx *ctx, uint32_t *count) { if (ctx == NULL || count == NULL) return CSS_BADPARM; *count = ctx->n_sheets; return CSS_OK; } /** * Retrieve a sheet from a selection context * * \param ctx Context to look in * \param index Index in context to look * \param sheet Pointer to location to receive sheet * \return CSS_OK on success, appropriate error otherwise */ css_error css_select_ctx_get_sheet(css_select_ctx *ctx, uint32_t index, const css_stylesheet **sheet) { if (ctx == NULL || sheet == NULL) return CSS_BADPARM; if (index > ctx->n_sheets) return CSS_INVALID; *sheet = ctx->sheets[index].sheet; return CSS_OK; } /** * Select a style for the given node * * \param ctx Selection context to use * \param node Node to select style for * \param media Currently active media types * \param inline_style Corresponding inline style for node, or NULL * \param handler Dispatch table of handler functions * \param pw Client-specific private data for handler functions * \param result Pointer to location to receive result set * \return CSS_OK on success, appropriate error otherwise. * * In computing the style, no reference is made to the parent node's * style. Therefore, the resultant computed style is not ready for * immediate use, as some properties may be marked as inherited. * Use css_computed_style_compose() to obtain a fully computed style. * * This two-step approach to style computation is designed to allow * the client to store the partially computed style and efficiently * update the fully computed style for a node when layout changes. */ css_error css_select_style(css_select_ctx *ctx, void *node, uint64_t media, const css_stylesheet *inline_style, css_select_handler *handler, void *pw, css_select_results **result) { uint32_t i, j; css_error error; css_select_state state; void *parent = NULL; if (ctx == NULL || node == NULL || result == NULL || handler == NULL || handler->handler_version != CSS_SELECT_HANDLER_VERSION_1) return CSS_BADPARM; /* Set up the selection state */ memset(&state, 0, sizeof(css_select_state)); state.node = node; state.media = media; state.handler = handler; state.pw = pw; /* Allocate the result set */ state.results = ctx->alloc(NULL, sizeof(css_select_results), ctx->pw); 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, &state.results->styles[CSS_PSEUDO_ELEMENT_NONE]); if (error != CSS_OK) { ctx->alloc(state.results, 0, ctx->pw); return error; } error = handler->parent_node(pw, node, &parent); if (error != CSS_OK) goto cleanup; /* Get node's name */ error = handler->node_name(pw, node, &state.element); if (error != CSS_OK) return error; /* Get node's ID, if any */ error = handler->node_id(pw, node, &state.id); if (error != CSS_OK) 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, &state.classes, &state.n_classes); if (error != CSS_OK) goto cleanup; /* Iterate through the top-level stylesheets, selecting styles * from those which apply to our current media requirements and * are not disabled */ for (i = 0; i < ctx->n_sheets; i++) { const css_select_sheet s = ctx->sheets[i]; if ((s.media & media) != 0 && s.sheet->disabled == false) { error = select_from_sheet(ctx, s.sheet, s.origin, &state); if (error != CSS_OK) goto cleanup; } } /* Consider any inline style for the node */ if (inline_style != NULL) { css_rule_selector *sel = (css_rule_selector *) inline_style->rule_list; /* Sanity check style */ if (inline_style->rule_count != 1 || inline_style->rule_list->type != CSS_RULE_SELECTOR || inline_style->rule_list->items != 0) { error = CSS_INVALID; goto cleanup; } /* No bytecode if input was empty or wholly invalid */ if (sel->style != NULL) { /* Inline style applies to base element only */ state.current_pseudo = CSS_PSEUDO_ELEMENT_NONE; state.computed = state.results->styles[ CSS_PSEUDO_ELEMENT_NONE]; error = cascade_style(sel->style, &state); if (error != CSS_OK) goto cleanup; } } /* Take account of presentational hints and fix up any remaining * unset properties. */ /* Base element */ state.current_pseudo = CSS_PSEUDO_ELEMENT_NONE; state.computed = state.results->styles[CSS_PSEUDO_ELEMENT_NONE]; for (i = 0; i < CSS_N_PROPERTIES; i++) { const prop_state *prop = &state.props[i][CSS_PSEUDO_ELEMENT_NONE]; /* Apply presentational hints if the property is unset or * the existing property value did not come from an author * stylesheet or a user sheet using !important. */ if (prop->set == false || (prop->origin != CSS_ORIGIN_AUTHOR && prop->important == false)) { error = set_hint(&state, i); if (error != CSS_OK) goto cleanup; } /* If the property is still unset or it's set to inherit * and we're the root element, then set it to its initial * value. */ if (prop->set == false || (parent == NULL && prop->inherit == true)) { error = set_initial(&state, i, CSS_PSEUDO_ELEMENT_NONE, parent); if (error != CSS_OK) goto cleanup; } } /* Pseudo elements, if any */ for (j = CSS_PSEUDO_ELEMENT_NONE + 1; j < CSS_PSEUDO_ELEMENT_COUNT; j++) { state.current_pseudo = j; state.computed = state.results->styles[j]; /* Skip non-existent pseudo elements */ if (state.computed == NULL) continue; for (i = 0; i < CSS_N_PROPERTIES; i++) { const prop_state *prop = &state.props[i][j]; /* If the property is still unset then set it * to its initial value. */ if (prop->set == false) { error = set_initial(&state, i, j, parent); if (error != CSS_OK) goto cleanup; } } } /* If this is the root element, then we must ensure that all * length values are absolute, display and float are correctly * computed, and the default border-{top,right,bottom,left}-color * is set to the computed value of color. */ if (parent == NULL) { /* Only compute absolute values for the base element */ error = css__compute_absolute_values(NULL, state.results->styles[CSS_PSEUDO_ELEMENT_NONE], handler->compute_font_size, pw);