From f3cf0f579347a16120df8fc1c1ec3cd1f4e6d44e Mon Sep 17 00:00:00 2001 From: Vincent Sanders Date: Sun, 2 Jan 2011 23:20:31 +0000 Subject: simple properties split in parse similar to select in preparation for future generation svn path=/trunk/libcss/; revision=11188 --- src/parse/properties/Makefile | 117 +- src/parse/properties/aural.c | 2156 ------------------------- src/parse/properties/azimuth.c | 245 +++ src/parse/properties/background.c | 508 ------ src/parse/properties/background_attachment.c | 79 + src/parse/properties/background_color.c | 94 ++ src/parse/properties/background_image.c | 99 ++ src/parse/properties/background_position.c | 224 +++ src/parse/properties/background_repeat.c | 87 + src/parse/properties/border.c | 109 ++ src/parse/properties/border_bottom.c | 35 + src/parse/properties/border_bottom_color.c | 36 + src/parse/properties/border_bottom_style.c | 36 + src/parse/properties/border_bottom_width.c | 36 + src/parse/properties/border_collapse.c | 79 + src/parse/properties/border_color.c | 266 +++ src/parse/properties/border_left.c | 35 + src/parse/properties/border_left_color.c | 36 + src/parse/properties/border_left_style.c | 36 + src/parse/properties/border_left_width.c | 36 + src/parse/properties/border_outline.c | 2221 -------------------------- src/parse/properties/border_right.c | 35 + src/parse/properties/border_right_color.c | 36 + src/parse/properties/border_right_style.c | 36 + src/parse/properties/border_right_width.c | 36 + src/parse/properties/border_spacing.c | 143 ++ src/parse/properties/border_style.c | 266 +++ src/parse/properties/border_top.c | 35 + src/parse/properties/border_top_color.c | 36 + src/parse/properties/border_top_style.c | 36 + src/parse/properties/border_top_width.c | 36 + src/parse/properties/border_width.c | 266 +++ src/parse/properties/bottom.c | 35 + src/parse/properties/caption_side.c | 79 + src/parse/properties/clear.c | 87 + src/parse/properties/clip.c | 176 ++ src/parse/properties/color.c | 88 + src/parse/properties/content.c | 134 ++ src/parse/properties/conter_reset.c | 36 + src/parse/properties/counter_increment.c | 36 + src/parse/properties/cue.c | 298 ++++ src/parse/properties/cursor.c | 373 +++++ src/parse/properties/direction.c | 79 + src/parse/properties/display.c | 138 ++ src/parse/properties/display_sizing.c | 811 ---------- src/parse/properties/effects_stacking.c | 402 ----- src/parse/properties/elevation.c | 145 ++ src/parse/properties/empty_cells.c | 79 + src/parse/properties/float.c | 83 + src/parse/properties/font.c | 555 ------- src/parse/properties/font_family.c | 199 +++ src/parse/properties/font_size.c | 158 ++ src/parse/properties/font_style.c | 83 + src/parse/properties/font_variant.c | 79 + src/parse/properties/font_weight.c | 111 ++ src/parse/properties/generated_list.c | 1464 ----------------- src/parse/properties/height.c | 109 ++ src/parse/properties/left.c | 35 + src/parse/properties/letter_spacing.c | 104 ++ src/parse/properties/line_height.c | 129 ++ src/parse/properties/list_style.c | 199 +++ src/parse/properties/list_style_image.c | 99 ++ src/parse/properties/list_style_position.c | 79 + src/parse/properties/list_style_type.c | 78 + src/parse/properties/margin.c | 173 -- src/parse/properties/margin_bottom.c | 36 + src/parse/properties/margin_left.c | 35 + src/parse/properties/margin_right.c | 35 + src/parse/properties/margin_top.c | 35 + src/parse/properties/max_height.c | 109 ++ src/parse/properties/max_width.c | 109 ++ src/parse/properties/min_height.c | 103 ++ src/parse/properties/min_width.c | 103 ++ src/parse/properties/orphans.c | 98 ++ src/parse/properties/outline.c | 197 +++ src/parse/properties/outline_color.c | 94 ++ src/parse/properties/outline_style.c | 58 + src/parse/properties/outline_width.c | 37 + src/parse/properties/overflow.c | 87 + src/parse/properties/padding.c | 181 --- src/parse/properties/padding_bottom.c | 36 + src/parse/properties/padding_left.c | 36 + src/parse/properties/padding_right.c | 36 + src/parse/properties/padding_top.c | 36 + src/parse/properties/page.c | 401 ----- src/parse/properties/page_break_after.c | 91 ++ src/parse/properties/page_break_before.c | 91 ++ src/parse/properties/page_break_inside.c | 79 + src/parse/properties/pause.c | 172 ++ src/parse/properties/pause_after.c | 35 + src/parse/properties/pause_before.c | 36 + src/parse/properties/pitch.c | 133 ++ src/parse/properties/pitch_range.c | 98 ++ src/parse/properties/play_during.c | 142 ++ src/parse/properties/position.c | 87 + src/parse/properties/positioning.c | 540 ------- src/parse/properties/quotes.c | 184 +++ src/parse/properties/richness.c | 98 ++ src/parse/properties/right.c | 35 + src/parse/properties/speak.c | 83 + src/parse/properties/speak_header.c | 79 + src/parse/properties/speak_numeral.c | 79 + src/parse/properties/speak_punctuation.c | 79 + src/parse/properties/speech_rate.c | 136 ++ src/parse/properties/stress.c | 97 ++ src/parse/properties/table.c | 209 --- src/parse/properties/table_layout.c | 80 + src/parse/properties/text.c | 830 ---------- src/parse/properties/text_align.c | 100 ++ src/parse/properties/text_decoration.c | 123 ++ src/parse/properties/text_indent.c | 97 ++ src/parse/properties/text_transform.c | 87 + src/parse/properties/top.c | 35 + src/parse/properties/ui.c | 373 ----- src/parse/properties/unicode_bidi.c | 83 + src/parse/properties/utils.c | 1539 +++++++++++++++++- src/parse/properties/utils.h | 41 + src/parse/properties/vertical_align.c | 147 ++ src/parse/properties/visibility.c | 83 + src/parse/properties/voice_family.c | 182 +++ src/parse/properties/volume.c | 161 ++ src/parse/properties/white_space.c | 91 ++ src/parse/properties/widows.c | 98 ++ src/parse/properties/width.c | 109 ++ src/parse/properties/word_spacing.c | 104 ++ src/parse/properties/z_index.c | 98 ++ 126 files changed, 12341 insertions(+), 10829 deletions(-) delete mode 100644 src/parse/properties/aural.c create mode 100644 src/parse/properties/azimuth.c create mode 100644 src/parse/properties/background_attachment.c create mode 100644 src/parse/properties/background_color.c create mode 100644 src/parse/properties/background_image.c create mode 100644 src/parse/properties/background_position.c create mode 100644 src/parse/properties/background_repeat.c create mode 100644 src/parse/properties/border.c create mode 100644 src/parse/properties/border_bottom.c create mode 100644 src/parse/properties/border_bottom_color.c create mode 100644 src/parse/properties/border_bottom_style.c create mode 100644 src/parse/properties/border_bottom_width.c create mode 100644 src/parse/properties/border_collapse.c create mode 100644 src/parse/properties/border_color.c create mode 100644 src/parse/properties/border_left.c create mode 100644 src/parse/properties/border_left_color.c create mode 100644 src/parse/properties/border_left_style.c create mode 100644 src/parse/properties/border_left_width.c delete mode 100644 src/parse/properties/border_outline.c create mode 100644 src/parse/properties/border_right.c create mode 100644 src/parse/properties/border_right_color.c create mode 100644 src/parse/properties/border_right_style.c create mode 100644 src/parse/properties/border_right_width.c create mode 100644 src/parse/properties/border_spacing.c create mode 100644 src/parse/properties/border_style.c create mode 100644 src/parse/properties/border_top.c create mode 100644 src/parse/properties/border_top_color.c create mode 100644 src/parse/properties/border_top_style.c create mode 100644 src/parse/properties/border_top_width.c create mode 100644 src/parse/properties/border_width.c create mode 100644 src/parse/properties/bottom.c create mode 100644 src/parse/properties/caption_side.c create mode 100644 src/parse/properties/clear.c create mode 100644 src/parse/properties/clip.c create mode 100644 src/parse/properties/color.c create mode 100644 src/parse/properties/content.c create mode 100644 src/parse/properties/conter_reset.c create mode 100644 src/parse/properties/counter_increment.c create mode 100644 src/parse/properties/cue.c create mode 100644 src/parse/properties/cursor.c create mode 100644 src/parse/properties/direction.c create mode 100644 src/parse/properties/display.c delete mode 100644 src/parse/properties/display_sizing.c delete mode 100644 src/parse/properties/effects_stacking.c create mode 100644 src/parse/properties/elevation.c create mode 100644 src/parse/properties/empty_cells.c create mode 100644 src/parse/properties/float.c create mode 100644 src/parse/properties/font_family.c create mode 100644 src/parse/properties/font_size.c create mode 100644 src/parse/properties/font_style.c create mode 100644 src/parse/properties/font_variant.c create mode 100644 src/parse/properties/font_weight.c delete mode 100644 src/parse/properties/generated_list.c create mode 100644 src/parse/properties/height.c create mode 100644 src/parse/properties/left.c create mode 100644 src/parse/properties/letter_spacing.c create mode 100644 src/parse/properties/line_height.c create mode 100644 src/parse/properties/list_style.c create mode 100644 src/parse/properties/list_style_image.c create mode 100644 src/parse/properties/list_style_position.c create mode 100644 src/parse/properties/list_style_type.c create mode 100644 src/parse/properties/margin_bottom.c create mode 100644 src/parse/properties/margin_left.c create mode 100644 src/parse/properties/margin_right.c create mode 100644 src/parse/properties/margin_top.c create mode 100644 src/parse/properties/max_height.c create mode 100644 src/parse/properties/max_width.c create mode 100644 src/parse/properties/min_height.c create mode 100644 src/parse/properties/min_width.c create mode 100644 src/parse/properties/orphans.c create mode 100644 src/parse/properties/outline.c create mode 100644 src/parse/properties/outline_color.c create mode 100644 src/parse/properties/outline_style.c create mode 100644 src/parse/properties/outline_width.c create mode 100644 src/parse/properties/overflow.c create mode 100644 src/parse/properties/padding_bottom.c create mode 100644 src/parse/properties/padding_left.c create mode 100644 src/parse/properties/padding_right.c create mode 100644 src/parse/properties/padding_top.c delete mode 100644 src/parse/properties/page.c create mode 100644 src/parse/properties/page_break_after.c create mode 100644 src/parse/properties/page_break_before.c create mode 100644 src/parse/properties/page_break_inside.c create mode 100644 src/parse/properties/pause.c create mode 100644 src/parse/properties/pause_after.c create mode 100644 src/parse/properties/pause_before.c create mode 100644 src/parse/properties/pitch.c create mode 100644 src/parse/properties/pitch_range.c create mode 100644 src/parse/properties/play_during.c create mode 100644 src/parse/properties/position.c delete mode 100644 src/parse/properties/positioning.c create mode 100644 src/parse/properties/quotes.c create mode 100644 src/parse/properties/richness.c create mode 100644 src/parse/properties/right.c create mode 100644 src/parse/properties/speak.c create mode 100644 src/parse/properties/speak_header.c create mode 100644 src/parse/properties/speak_numeral.c create mode 100644 src/parse/properties/speak_punctuation.c create mode 100644 src/parse/properties/speech_rate.c create mode 100644 src/parse/properties/stress.c delete mode 100644 src/parse/properties/table.c create mode 100644 src/parse/properties/table_layout.c delete mode 100644 src/parse/properties/text.c create mode 100644 src/parse/properties/text_align.c create mode 100644 src/parse/properties/text_decoration.c create mode 100644 src/parse/properties/text_indent.c create mode 100644 src/parse/properties/text_transform.c create mode 100644 src/parse/properties/top.c delete mode 100644 src/parse/properties/ui.c create mode 100644 src/parse/properties/unicode_bidi.c create mode 100644 src/parse/properties/vertical_align.c create mode 100644 src/parse/properties/visibility.c create mode 100644 src/parse/properties/voice_family.c create mode 100644 src/parse/properties/volume.c create mode 100644 src/parse/properties/white_space.c create mode 100644 src/parse/properties/widows.c create mode 100644 src/parse/properties/width.c create mode 100644 src/parse/properties/word_spacing.c create mode 100644 src/parse/properties/z_index.c diff --git a/src/parse/properties/Makefile b/src/parse/properties/Makefile index de19651..9a76d48 100644 --- a/src/parse/properties/Makefile +++ b/src/parse/properties/Makefile @@ -1,6 +1,117 @@ # Sources -DIR_SOURCES := aural.c background.c border_outline.c display_sizing.c \ - effects_stacking.c font.c generated_list.c margin.c padding.c \ - page.c positioning.c properties.c table.c text.c ui.c utils.c +DIR_SOURCES := utils.c properties.c \ + azimuth.c \ + background_attachment.c \ + background.c \ + background_color.c \ + background_image.c \ + background_position.c \ + background_repeat.c \ + border_bottom.c \ + border_bottom_color.c \ + border_bottom_style.c \ + border_bottom_width.c \ + border.c \ + border_collapse.c \ + border_color.c \ + border_left.c \ + border_left_color.c \ + border_left_style.c \ + border_left_width.c \ + border_right.c \ + border_right_color.c \ + border_right_style.c \ + border_right_width.c \ + border_spacing.c \ + border_style.c \ + border_top.c \ + border_top_color.c \ + border_top_style.c \ + border_top_width.c \ + border_width.c \ + bottom.c \ + caption_side.c \ + clear.c \ + clip.c \ + color.c \ + content.c \ + conter_reset.c \ + counter_increment.c \ + cue.c \ + cursor.c \ + direction.c \ + display.c \ + elevation.c \ + empty_cells.c \ + float.c \ + font.c \ + font_family.c \ + font_size.c \ + font_style.c \ + font_variant.c \ + font_weight.c \ + height.c \ + left.c \ + letter_spacing.c \ + line_height.c \ + list_style.c \ + list_style_image.c \ + list_style_position.c \ + list_style_type.c \ + margin_bottom.c \ + margin.c \ + margin_left.c \ + margin_right.c \ + margin_top.c \ + max_height.c \ + max_width.c \ + min_height.c \ + min_width.c \ + orphans.c \ + outline.c \ + outline_color.c \ + outline_style.c \ + outline_width.c \ + overflow.c \ + padding_bottom.c \ + padding.c \ + padding_left.c \ + padding_right.c \ + padding_top.c \ + page_break_after.c \ + page_break_before.c \ + page_break_inside.c \ + pause_after.c \ + pause_before.c \ + pause.c \ + pitch.c \ + pitch_range.c \ + play_during.c \ + position.c \ + quotes.c \ + richness.c \ + right.c \ + speak.c \ + speak_header.c \ + speak_numeral.c \ + speak_punctuation.c \ + speech_rate.c \ + stress.c \ + table_layout.c \ + text_align.c \ + text_decoration.c \ + text_indent.c \ + text_transform.c \ + top.c \ + unicode_bidi.c \ + vertical_align.c \ + visibility.c \ + voice_family.c \ + volume.c \ + white_space.c \ + widows.c \ + width.c \ + word_spacing.c \ + z_index.c include build/makefiles/Makefile.subdir diff --git a/src/parse/properties/aural.c b/src/parse/properties/aural.c deleted file mode 100644 index 8821c5f..0000000 --- a/src/parse/properties/aural.c +++ /dev/null @@ -1,2156 +0,0 @@ -/* - * This file is part of LibCSS. - * Licensed under the MIT License, - * http://www.opensource.org/licenses/mit-license.php - * Copyright 2009 John-Mark Bell - */ - -#include -#include - -#include "bytecode/bytecode.h" -#include "bytecode/opcodes.h" -#include "parse/properties/properties.h" -#include "parse/properties/utils.h" - -static css_error parse_cue_common(css_language *c, - const parserutils_vector *vector, int *ctx, - uint16_t op, css_style **result); -static css_error parse_pause_common(css_language *c, - const parserutils_vector *vector, int *ctx, - uint16_t op, css_style **result); - -/** - * Parse azimuth - * - * \param c Parsing context - * \param vector Vector of tokens to process - * \param ctx Pointer to vector iteration context - * \param result Pointer to location to receive resulting style - * \return CSS_OK on success, - * CSS_NOMEM on memory exhaustion, - * CSS_INVALID if the input is not valid - * - * Post condition: \a *ctx is updated with the next token to process - * If the input is invalid, then \a *ctx remains unchanged. - */ -css_error parse_azimuth(css_language *c, - const parserutils_vector *vector, int *ctx, - css_style **result) -{ - int orig_ctx = *ctx; - css_error error; - const css_token *token; - uint8_t flags = 0; - uint16_t value = 0; - uint32_t opv; - css_fixed length = 0; - uint32_t unit = 0; - uint32_t required_size; - bool match; - - /* angle | [ IDENT(left-side, far-left, left, center-left, center, - * center-right, right, far-right, right-side) || - * IDENT(behind) - * ] - * | IDENT(leftwards, rightwards, inherit) - */ - token = parserutils_vector_peek(vector, *ctx); - if (token == NULL) { - *ctx = orig_ctx; - return CSS_INVALID; - } - - if (token->type == CSS_TOKEN_IDENT && - (lwc_string_caseless_isequal(token->idata, c->strings[INHERIT], - &match) == lwc_error_ok && match)) { - parserutils_vector_iterate(vector, ctx); - flags = FLAG_INHERIT; - } else if (token->type == CSS_TOKEN_IDENT && - (lwc_string_caseless_isequal(token->idata, c->strings[LEFTWARDS], - &match) == lwc_error_ok && match)) { - parserutils_vector_iterate(vector, ctx); - value = AZIMUTH_LEFTWARDS; - } else if (token->type == CSS_TOKEN_IDENT && - (lwc_string_caseless_isequal(token->idata, c->strings[RIGHTWARDS], - &match) == lwc_error_ok && match)) { - parserutils_vector_iterate(vector, ctx); - value = AZIMUTH_RIGHTWARDS; - } else if (token->type == CSS_TOKEN_IDENT) { - parserutils_vector_iterate(vector, ctx); - - /* Now, we may have one of the other keywords or behind, - * potentially followed by behind or other keyword, - * respectively */ - if ((lwc_string_caseless_isequal( - token->idata, c->strings[LEFT_SIDE], - &match) == lwc_error_ok && match)) { - value = AZIMUTH_LEFT_SIDE; - } else if ((lwc_string_caseless_isequal( - token->idata, c->strings[FAR_LEFT], - &match) == lwc_error_ok && match)) { - value = AZIMUTH_FAR_LEFT; - } else if ((lwc_string_caseless_isequal( - token->idata, c->strings[LEFT], - &match) == lwc_error_ok && match)) { - value = AZIMUTH_LEFT; - } else if ((lwc_string_caseless_isequal( - token->idata, c->strings[CENTER_LEFT], - &match) == lwc_error_ok && match)) { - value = AZIMUTH_CENTER_LEFT; - } else if ((lwc_string_caseless_isequal( - token->idata, c->strings[CENTER], - &match) == lwc_error_ok && match)) { - value = AZIMUTH_CENTER; - } else if ((lwc_string_caseless_isequal( - token->idata, c->strings[CENTER_RIGHT], - &match) == lwc_error_ok && match)) { - value = AZIMUTH_CENTER_RIGHT; - } else if ((lwc_string_caseless_isequal( - token->idata, c->strings[RIGHT], - &match) == lwc_error_ok && match)) { - value = AZIMUTH_RIGHT; - } else if ((lwc_string_caseless_isequal( - token->idata, c->strings[FAR_RIGHT], - &match) == lwc_error_ok && match)) { - value = AZIMUTH_FAR_RIGHT; - } else if ((lwc_string_caseless_isequal( - token->idata, c->strings[RIGHT_SIDE], - &match) == lwc_error_ok && match)) { - value = AZIMUTH_RIGHT_SIDE; - } else if ((lwc_string_caseless_isequal( - token->idata, c->strings[BEHIND], - &match) == lwc_error_ok && match)) { - value = AZIMUTH_BEHIND; - } else { - *ctx = orig_ctx; - return CSS_INVALID; - } - - consumeWhitespace(vector, ctx); - - /* Get potential following token */ - token = parserutils_vector_peek(vector, *ctx); - - if (token != NULL && token->type == CSS_TOKEN_IDENT && - value == AZIMUTH_BEHIND) { - parserutils_vector_iterate(vector, ctx); - - if ((lwc_string_caseless_isequal( - token->idata, c->strings[LEFT_SIDE], - &match) == lwc_error_ok && match)) { - value |= AZIMUTH_LEFT_SIDE; - } else if ((lwc_string_caseless_isequal( - token->idata, c->strings[FAR_LEFT], - &match) == lwc_error_ok && match)) { - value |= AZIMUTH_FAR_LEFT; - } else if ((lwc_string_caseless_isequal( - token->idata, c->strings[LEFT], - &match) == lwc_error_ok && match)) { - value |= AZIMUTH_LEFT; - } else if ((lwc_string_caseless_isequal( - token->idata, c->strings[CENTER_LEFT], - &match) == lwc_error_ok && match)) { - value |= AZIMUTH_CENTER_LEFT; - } else if ((lwc_string_caseless_isequal( - token->idata, c->strings[CENTER], - &match) == lwc_error_ok && match)) { - value |= AZIMUTH_CENTER; - } else if ((lwc_string_caseless_isequal( - token->idata, c->strings[CENTER_RIGHT], - &match) == lwc_error_ok && match)) { - value |= AZIMUTH_CENTER_RIGHT; - } else if ((lwc_string_caseless_isequal( - token->idata, c->strings[RIGHT], - &match) == lwc_error_ok && match)) { - value |= AZIMUTH_RIGHT; - } else if ((lwc_string_caseless_isequal( - token->idata, c->strings[FAR_RIGHT], - &match) == lwc_error_ok && match)) { - value |= AZIMUTH_FAR_RIGHT; - } else if ((lwc_string_caseless_isequal( - token->idata, c->strings[RIGHT_SIDE], - &match) == lwc_error_ok && match)) { - value |= AZIMUTH_RIGHT_SIDE; - } else { - *ctx = orig_ctx; - return CSS_INVALID; - } - } else if (token != NULL && token->type == CSS_TOKEN_IDENT && - value != AZIMUTH_BEHIND) { - parserutils_vector_iterate(vector, ctx); - - if ((lwc_string_caseless_isequal( - token->idata, c->strings[BEHIND], - &match) == lwc_error_ok && match)) { - value |= AZIMUTH_BEHIND; - } else { - *ctx = orig_ctx; - return CSS_INVALID; - } - } else if ((token == NULL || token->type != CSS_TOKEN_IDENT) && - value == AZIMUTH_BEHIND) { - value |= AZIMUTH_CENTER; - } - } else { - error = parse_unit_specifier(c, vector, ctx, UNIT_DEG, - &length, &unit); - if (error != CSS_OK) { - *ctx = orig_ctx; - return error; - } - - if ((unit & UNIT_ANGLE) == false) { - *ctx = orig_ctx; - return CSS_INVALID; - } - - /* Valid angles lie between -360 and 360 degrees */ - if (unit == UNIT_DEG) { - if (length < FMULI(F_360, -1) || length > F_360) { - *ctx = orig_ctx; - return CSS_INVALID; - } - } else if (unit == UNIT_GRAD) { - if (length < FMULI(F_400, -1) || length > F_400) { - *ctx = orig_ctx; - return CSS_INVALID; - } - } else if (unit == UNIT_RAD) { - if (length < FMULI(F_2PI, -1) || length > F_2PI) { - *ctx = orig_ctx; - return CSS_INVALID; - } - } - - value = AZIMUTH_ANGLE; - } - - opv = buildOPV(CSS_PROP_AZIMUTH, flags, value); - - required_size = sizeof(opv); - if ((flags & FLAG_INHERIT) == false && value == AZIMUTH_ANGLE) - required_size += sizeof(length) + sizeof(unit); - - /* Allocate result */ - error = css_stylesheet_style_create(c->sheet, required_size, result); - if (error != CSS_OK) { - *ctx = orig_ctx; - return error; - } - - /* Copy the bytecode to it */ - memcpy((*result)->bytecode, &opv, sizeof(opv)); - if ((flags & FLAG_INHERIT) == false && value == AZIMUTH_ANGLE) { - memcpy(((uint8_t *) (*result)->bytecode) + sizeof(opv), - &length, sizeof(length)); - memcpy(((uint8_t *) (*result)->bytecode) + sizeof(opv) + - sizeof(length), &unit, sizeof(unit)); - } - - return CSS_OK; -} - -/** - * Parse cue shorthand - * - * \param c Parsing context - * \param vector Vector of tokens to process - * \param ctx Pointer to vector iteration context - * \param result Pointer to location to receive resulting style - * \return CSS_OK on success, - * CSS_NOMEM on memory exhaustion, - * CSS_INVALID if the input is not valid - * - * Post condition: \a *ctx is updated with the next token to process - * If the input is invalid, then \a *ctx remains unchanged. - */ -css_error parse_cue(css_language *c, - const parserutils_vector *vector, int *ctx, - css_style **result) -{ - int orig_ctx = *ctx; - const css_token *token; - css_style *before = NULL; - css_style *after = NULL; - css_style *ret = NULL; - int num_read = 0; - int prev_ctx; - uint32_t required_size; - bool match; - css_error error; - - /* Deal with inherit */ - token = parserutils_vector_peek(vector, *ctx); - if (token != NULL && token->type == CSS_TOKEN_IDENT && - (lwc_string_caseless_isequal( - token->idata, c->strings[INHERIT], - &match) == lwc_error_ok && match)) { - uint32_t *bytecode; - - error = css_stylesheet_style_create(c->sheet, - 2 * sizeof(uint32_t), &ret); - if (error != CSS_OK) { - *ctx = orig_ctx; - return error; - } - - bytecode = (uint32_t *) ret->bytecode; - - *(bytecode++) = buildOPV(CSS_PROP_CUE_BEFORE, FLAG_INHERIT, 0); - *(bytecode++) = buildOPV(CSS_PROP_CUE_AFTER, FLAG_INHERIT, 0); - - parserutils_vector_iterate(vector, ctx); - - *result = ret; - - return CSS_OK; - } else if (token == NULL) { - /* No tokens -- clearly garbage */ - *ctx = orig_ctx; - return CSS_INVALID; - } - - /* Attempt to read 1 or 2 cues */ - do { - prev_ctx = *ctx; - error = CSS_OK; - - /* Ensure that we're not about to parse another inherit */ - token = parserutils_vector_peek(vector, *ctx); - if (token != NULL && token->type == CSS_TOKEN_IDENT && - (lwc_string_caseless_isequal( - token->idata, c->strings[INHERIT], - &match) == lwc_error_ok && match)) { - error = CSS_INVALID; - goto cleanup; - } - - if (before == NULL && (error = parse_cue_before(c, vector, ctx, - &before)) == CSS_OK) { - num_read = 1; - } else if (after == NULL && - (error = parse_cue_after(c, vector, ctx, - &after)) == CSS_OK) { - num_read = 2; - } - - if (error == CSS_OK) { - consumeWhitespace(vector, ctx); - - token = parserutils_vector_peek(vector, *ctx); - } else { - token = NULL; - } - } while (*ctx != prev_ctx && token != NULL); - - if (num_read == 0) { - error = CSS_INVALID; - goto cleanup; - } - - /* Calculate size of resultant style */ - if (num_read == 1) - required_size = 2 * before->length; - else - required_size = before->length + after->length; - - error = css_stylesheet_style_create(c->sheet, required_size, &ret); - if (error != CSS_OK) - goto cleanup; - - required_size = 0; - - if (num_read == 1) { - uint32_t *opv = ((uint32_t *) before->bytecode); - uint8_t flags = getFlags(*opv); - uint16_t value = getValue(*opv); - - memcpy(((uint8_t *) ret->bytecode) + required_size, - before->bytecode, before->length); - required_size += before->length; - - *opv = buildOPV(CSS_PROP_CUE_AFTER, flags, value); - memcpy(((uint8_t *) ret->bytecode) + required_size, - before->bytecode, before->length); - required_size += before->length; - } else { - memcpy(((uint8_t *) ret->bytecode) + required_size, - before->bytecode, before->length); - required_size += before->length; - - memcpy(((uint8_t *) ret->bytecode) + required_size, - after->bytecode, after->length); - required_size += after->length; - } - - assert(required_size == ret->length); - - /* Write the result */ - *result = ret; - /* Invalidate ret so that cleanup doesn't destroy it */ - ret = NULL; - - /* Clean up after ourselves */ -cleanup: - if (before) - css_stylesheet_style_destroy(c->sheet, before, error == CSS_OK); - if (after) - css_stylesheet_style_destroy(c->sheet, after, error == CSS_OK); - if (ret) - css_stylesheet_style_destroy(c->sheet, ret, error == CSS_OK); - - if (error != CSS_OK) - *ctx = orig_ctx; - - return error; -} - -/** - * Parse cue-after - * - * \param c Parsing context - * \param vector Vector of tokens to process - * \param ctx Pointer to vector iteration context - * \param result Pointer to location to receive resulting style - * \return CSS_OK on success, - * CSS_NOMEM on memory exhaustion, - * CSS_INVALID if the input is not valid - * - * Post condition: \a *ctx is updated with the next token to process - * If the input is invalid, then \a *ctx remains unchanged. - */ -css_error parse_cue_after(css_language *c, - const parserutils_vector *vector, int *ctx, - css_style **result) -{ - return parse_cue_common(c, vector, ctx, CSS_PROP_CUE_AFTER, result); -} - -/** - * Parse cue-before - * - * \param c Parsing context - * \param vector Vector of tokens to process - * \param ctx Pointer to vector iteration context - * \param result Pointer to location to receive resulting style - * \return CSS_OK on success, - * CSS_NOMEM on memory exhaustion, - * CSS_INVALID if the input is not valid - * - * Post condition: \a *ctx is updated with the next token to process - * If the input is invalid, then \a *ctx remains unchanged. - */ -css_error parse_cue_before(css_language *c, - const parserutils_vector *vector, int *ctx, - css_style **result) -{ - return parse_cue_common(c, vector, ctx, CSS_PROP_CUE_BEFORE, result); -} - -/** - * Parse elevation - * - * \param c Parsing context - * \param vector Vector of tokens to process - * \param ctx Pointer to vector iteration context - * \param result Pointer to location to receive resulting style - * \return CSS_OK on success, - * CSS_NOMEM on memory exhaustion, - * CSS_INVALID if the input is not valid - * - * Post condition: \a *ctx is updated with the next token to process - * If the input is invalid, then \a *ctx remains unchanged. - */ -css_error parse_elevation(css_language *c, - const parserutils_vector *vector, int *ctx, - css_style **result) -{ - int orig_ctx = *ctx; - css_error error; - const css_token *token; - uint8_t flags = 0; - uint16_t value = 0; - uint32_t opv; - css_fixed length = 0; - uint32_t unit = 0; - uint32_t required_size; - bool match; - - /* angle | IDENT(below, level, above, higher, lower, inherit) */ - token = parserutils_vector_peek(vector, *ctx); - if (token == NULL) { - *ctx = orig_ctx; - return CSS_INVALID; - } - - if (token->type == CSS_TOKEN_IDENT && - (lwc_string_caseless_isequal( - token->idata, c->strings[INHERIT], - &match) == lwc_error_ok && match)) { - parserutils_vector_iterate(vector, ctx); - flags = FLAG_INHERIT; - } else if (token->type == CSS_TOKEN_IDENT && - (lwc_string_caseless_isequal( - token->idata, c->strings[BELOW], - &match) == lwc_error_ok && match)) { - parserutils_vector_iterate(vector, ctx); - value = ELEVATION_BELOW; - } else if (token->type == CSS_TOKEN_IDENT && - (lwc_string_caseless_isequal( - token->idata, c->strings[LEVEL], - &match) == lwc_error_ok && match)) { - parserutils_vector_iterate(vector, ctx); - value = ELEVATION_LEVEL; - } else if (token->type == CSS_TOKEN_IDENT && - (lwc_string_caseless_isequal( - token->idata, c->strings[ABOVE], - &match) == lwc_error_ok && match)) { - parserutils_vector_iterate(vector, ctx); - value = ELEVATION_ABOVE; - } else if (token->type == CSS_TOKEN_IDENT && - (lwc_string_caseless_isequal( - token->idata, c->strings[HIGHER], - &match) == lwc_error_ok && match)) { - parserutils_vector_iterate(vector, ctx); - value = ELEVATION_HIGHER; - } else if (token->type == CSS_TOKEN_IDENT && - (lwc_string_caseless_isequal( - token->idata, c->strings[LOWER], - &match) == lwc_error_ok && match)) { - parserutils_vector_iterate(vector, ctx); - value = ELEVATION_LOWER; - } else { - error = parse_unit_specifier(c, vector, ctx, UNIT_DEG, - &length, &unit); - if (error != CSS_OK) { - *ctx = orig_ctx; - return error; - } - - if ((unit & UNIT_ANGLE) == false) { - *ctx = orig_ctx; - return CSS_INVALID; - } - - /* Valid angles lie between -90 and 90 degrees */ - if (unit == UNIT_DEG) { - if (length < FMULI(F_90, -1) || length > F_90) { - *ctx = orig_ctx; - return CSS_INVALID; - } - } else if (unit == UNIT_GRAD) { - if (length < FMULI(F_100, -1) || length > F_100) { - *ctx = orig_ctx; - return CSS_INVALID; - } - } else if (unit == UNIT_RAD) { - if (length < FMULI(F_PI_2, -1) || length > F_PI_2) { - *ctx = orig_ctx; - return CSS_INVALID; - } - } - - value = ELEVATION_ANGLE; - } - - opv = buildOPV(CSS_PROP_ELEVATION, flags, value); - - required_size = sizeof(opv); - if ((flags & FLAG_INHERIT) == false && value == ELEVATION_ANGLE) - required_size += sizeof(length) + sizeof(unit); - - /* Allocate result */ - error = css_stylesheet_style_create(c->sheet, required_size, result); - if (error != CSS_OK) { - *ctx = orig_ctx; - return error; - } - - /* Copy the bytecode to it */ - memcpy((*result)->bytecode, &opv, sizeof(opv)); - if ((flags & FLAG_INHERIT) == false && value == ELEVATION_ANGLE) { - memcpy(((uint8_t *) (*result)->bytecode) + sizeof(opv), - &length, sizeof(length)); - memcpy(((uint8_t *) (*result)->bytecode) + sizeof(opv) + - sizeof(length), &unit, sizeof(unit)); - } - - return CSS_OK; -} - -/** - * Parse pause shorthand - * - * \param c Parsing context - * \param vector Vector of tokens to process - * \param ctx Pointer to vector iteration context - * \param result Pointer to location to receive resulting style - * \return CSS_OK on success, - * CSS_NOMEM on memory exhaustion, - * CSS_INVALID if the input is not valid - * - * Post condition: \a *ctx is updated with the next token to process - * If the input is invalid, then \a *ctx remains unchanged. - */ -css_error parse_pause(css_language *c, - const parserutils_vector *vector, int *ctx, - css_style **result) -{ - int orig_ctx = *ctx; - const css_token *token; - css_style *before = NULL; - css_style *after = NULL; - css_style *ret = NULL; - int num_read = 0; - int prev_ctx; - uint32_t required_size; - bool match; - css_error error; - - /* Deal with inherit */ - token = parserutils_vector_peek(vector, *ctx); - if (token != NULL && token->type == CSS_TOKEN_IDENT && - (lwc_string_caseless_isequal( - token->idata, c->strings[INHERIT], - &match) == lwc_error_ok && match)) { - uint32_t *bytecode; - - error = css_stylesheet_style_create(c->sheet, - 2 * sizeof(uint32_t), &ret); - if (error != CSS_OK) { - *ctx = orig_ctx; - return error; - } - - bytecode = (uint32_t *) ret->bytecode; - - *(bytecode++) = buildOPV(CSS_PROP_PAUSE_BEFORE, - FLAG_INHERIT, 0); - *(bytecode++) = buildOPV(CSS_PROP_PAUSE_AFTER, - FLAG_INHERIT, 0); - - parserutils_vector_iterate(vector, ctx); - - *result = ret; - - return CSS_OK; - } else if (token == NULL) { - /* No tokens -- clearly garbage */ - *ctx = orig_ctx; - return CSS_INVALID; - } - - /* Attempt to read 1 or 2 pauses */ - do { - prev_ctx = *ctx; - error = CSS_OK; - - /* Ensure that we're not about to parse another inherit */ - token = parserutils_vector_peek(vector, *ctx); - if (token != NULL && token->type == CSS_TOKEN_IDENT && - (lwc_string_caseless_isequal( - token->idata, c->strings[INHERIT], - &match) == lwc_error_ok && match)) { - error = CSS_INVALID; - goto cleanup; - } - - if (before == NULL && (error = parse_pause_before(c, vector, - ctx, &before)) == CSS_OK) { - num_read = 1; - } else if (after == NULL && - (error = parse_pause_after(c, vector, ctx, - &after)) == CSS_OK) { - num_read = 2; - } - - if (error == CSS_OK) { - consumeWhitespace(vector, ctx); - - token = parserutils_vector_peek(vector, *ctx); - } else { - token = NULL; - } - } while (*ctx != prev_ctx && token != NULL); - - if (num_read == 0) { - error = CSS_INVALID; - goto cleanup; - } - - /* Calculate size of resultant style */ - if (num_read == 1) - required_size = 2 * before->length; - else - required_size = before->length + after->length; - - error = css_stylesheet_style_create(c->sheet, required_size, &ret); - if (error != CSS_OK) - goto cleanup; - - required_size = 0; - - if (num_read == 1) { - uint32_t *opv = ((uint32_t *) before->bytecode); - uint8_t flags = getFlags(*opv); - uint16_t value = getValue(*opv); - - memcpy(((uint8_t *) ret->bytecode) + required_size, - before->bytecode, before->length); - required_size += before->length; - - *opv = buildOPV(CSS_PROP_PAUSE_AFTER, flags, value); - memcpy(((uint8_t *) ret->bytecode) + required_size, - before->bytecode, before->length); - required_size += before->length; - } else { - memcpy(((uint8_t *) ret->bytecode) + required_size, - before->bytecode, before->length); - required_size += before->length; - - memcpy(((uint8_t *) ret->bytecode) + required_size, - after->bytecode, after->length); - required_size += after->length; - } - - assert(required_size == ret->length); - - /* Write the result */ - *result = ret; - /* Invalidate ret so that cleanup doesn't destroy it */ - ret = NULL; - - /* Clean up after ourselves */ -cleanup: - if (before) - css_stylesheet_style_destroy(c->sheet, before, error == CSS_OK); - if (after) - css_stylesheet_style_destroy(c->sheet, after, error == CSS_OK); - if (ret) - css_stylesheet_style_destroy(c->sheet, ret, error == CSS_OK); - - if (error != CSS_OK) - *ctx = orig_ctx; - - return error; -} - -/** - * Parse pause-after - * - * \param c Parsing context - * \param vector Vector of tokens to process - * \param ctx Pointer to vector iteration context - * \param result Pointer to location to receive resulting style - * \return CSS_OK on success, - * CSS_NOMEM on memory exhaustion, - * CSS_INVALID if the input is not valid - * - * Post condition: \a *ctx is updated with the next token to process - * If the input is invalid, then \a *ctx remains unchanged. - */ -css_error parse_pause_after(css_language *c, - const parserutils_vector *vector, int *ctx, - css_style **result) -{ - return parse_pause_common(c, vector, ctx, CSS_PROP_PAUSE_AFTER, result); -} - -/** - * Parse pause-before - * - * \param c Parsing context - * \param vector Vector of tokens to process - * \param ctx Pointer to vector iteration context - * \param result Pointer to location to receive resulting style - * \return CSS_OK on success, - * CSS_NOMEM on memory exhaustion, - * CSS_INVALID if the input is not valid - * - * Post condition: \a *ctx is updated with the next token to process - * If the input is invalid, then \a *ctx remains unchanged. - */ -css_error parse_pause_before(css_language *c, - const parserutils_vector *vector, int *ctx, - css_style **result) -{ - return parse_pause_common(c, vector, ctx, - CSS_PROP_PAUSE_BEFORE, result); -} - -/** - * Parse pitch-range - * - * \param c Parsing context - * \param vector Vector of tokens to process - * \param ctx Pointer to vector iteration context - * \param result Pointer to location to receive resulting style - * \return CSS_OK on success, - * CSS_NOMEM on memory exhaustion, - * CSS_INVALID if the input is not valid - * - * Post condition: \a *ctx is updated with the next token to process - * If the input is invalid, then \a *ctx remains unchanged. - */ -css_error parse_pitch_range(css_language *c, - const parserutils_vector *vector, int *ctx, - css_style **result) -{ - int orig_ctx = *ctx; - css_error error; - const css_token *token; - uint8_t flags = 0; - uint16_t value = 0; - uint32_t opv; - css_fixed num = 0; - uint32_t required_size; - bool match; - - /* number | IDENT (inherit) */ - token = parserutils_vector_iterate(vector, ctx); - if (token == NULL || (token->type != CSS_TOKEN_IDENT && - token->type != CSS_TOKEN_NUMBER)) { - *ctx = orig_ctx; - return CSS_INVALID; - } - - if ((lwc_string_caseless_isequal( - token->idata, c->strings[INHERIT], - &match) == lwc_error_ok && match)) { - flags |= FLAG_INHERIT; - } else if (token->type == CSS_TOKEN_NUMBER) { - size_t consumed = 0; - num = number_from_lwc_string(token->idata, false, &consumed); - /* Invalid if there are trailing characters */ - if (consumed != lwc_string_length(token->idata)) { - *ctx = orig_ctx; - return CSS_INVALID; - } - - /* Must be between 0 and 100 */ - if (num < 0 || num > F_100) { - *ctx = orig_ctx; - return CSS_INVALID; - } - - value = PITCH_RANGE_SET; - } else { - *ctx = orig_ctx; - return CSS_INVALID; - } - - opv = buildOPV(CSS_PROP_PITCH_RANGE, flags, value); - - required_size = sizeof(opv); - if ((flags & FLAG_INHERIT) == false && value == PITCH_RANGE_SET) - required_size += sizeof(num); - - /* Allocate result */ - error = css_stylesheet_style_create(c->sheet, required_size, result); - if (error != CSS_OK) { - *ctx = orig_ctx; - return error; - } - - /* Copy the bytecode to it */ - memcpy((*result)->bytecode, &opv, sizeof(opv)); - if ((flags & FLAG_INHERIT) == false && value == PITCH_RANGE_SET) { - memcpy(((uint8_t *) (*result)->bytecode) + sizeof(opv), - &num, sizeof(num)); - } - - return CSS_OK; -} - -/** - * Parse pitch - * - * \param c Parsing context - * \param vector Vector of tokens to process - * \param ctx Pointer to vector iteration context - * \param result Pointer to location to receive resulting style - * \return CSS_OK on success, - * CSS_NOMEM on memory exhaustion, - * CSS_INVALID if the input is not valid - * - * Post condition: \a *ctx is updated with the next token to process - * If the input is invalid, then \a *ctx remains unchanged. - */ -css_error parse_pitch(css_language *c, - const parserutils_vector *vector, int *ctx, - css_style **result) -{ - int orig_ctx = *ctx; - css_error error; - const css_token *token; - uint8_t flags = 0; - uint16_t value = 0; - uint32_t opv; - css_fixed length = 0; - uint32_t unit = 0; - uint32_t required_size; - bool match; - - /* frequency | IDENT(x-low, low, medium, high, x-high, inherit) */ - token = parserutils_vector_peek(vector, *ctx); - if (token == NULL) { - *ctx = orig_ctx; - return CSS_INVALID; - } - - if (token->type == CSS_TOKEN_IDENT && - (lwc_string_caseless_isequal( - token->idata, c->strings[INHERIT], - &match) == lwc_error_ok && match)) { - parserutils_vector_iterate(vector, ctx); - flags = FLAG_INHERIT; - } else if (token->type == CSS_TOKEN_IDENT && - (lwc_string_caseless_isequal( - token->idata, c->strings[X_LOW], - &match) == lwc_error_ok && match)) { - parserutils_vector_iterate(vector, ctx); - value = PITCH_X_LOW; - } else if (token->type == CSS_TOKEN_IDENT && - (lwc_string_caseless_isequal( - token->idata, c->strings[LOW], - &match) == lwc_error_ok && match)) { - parserutils_vector_iterate(vector, ctx); - value = PITCH_LOW; - } else if (token->type == CSS_TOKEN_IDENT && - (lwc_string_caseless_isequal( - token->idata, c->strings[MEDIUM], - &match) == lwc_error_ok && match)) { - parserutils_vector_iterate(vector, ctx); - value = PITCH_MEDIUM; - } else if (token->type == CSS_TOKEN_IDENT && - (lwc_string_caseless_isequal( - token->idata, c->strings[HIGH], - &match) == lwc_error_ok && match)) { - parserutils_vector_iterate(vector, ctx); - value = PITCH_HIGH; - } else if (token->type == CSS_TOKEN_IDENT && - (lwc_string_caseless_isequal( - token->idata, c->strings[X_HIGH], - &match) == lwc_error_ok && match)) { - parserutils_vector_iterate(vector, ctx); - value = PITCH_X_HIGH; - } else { - error = parse_unit_specifier(c, vector, ctx, UNIT_HZ, - &length, &unit); - if (error != CSS_OK) { - *ctx = orig_ctx; - return error; - } - - if ((unit & UNIT_FREQ) == false) { - *ctx = orig_ctx; - return CSS_INVALID; - } - - /* Negative values are invalid */ - if (length < 0) { - *ctx = orig_ctx; - return CSS_INVALID; - } - - value = PITCH_FREQUENCY; - } - - opv = buildOPV(CSS_PROP_PITCH, flags, value); - - required_size = sizeof(opv); - if ((flags & FLAG_INHERIT) == false && value == PITCH_FREQUENCY) - required_size += sizeof(length) + sizeof(unit); - - /* Allocate result */ - error = css_stylesheet_style_create(c->sheet, required_size, result); - if (error != CSS_OK) { - *ctx = orig_ctx; - return error; - } - - /* Copy the bytecode to it */ - memcpy((*result)->bytecode, &opv, sizeof(opv)); - if ((flags & FLAG_INHERIT) == false && value == PITCH_FREQUENCY) { - memcpy(((uint8_t *) (*result)->bytecode) + sizeof(opv), - &length, sizeof(length)); - memcpy(((uint8_t *) (*result)->bytecode) + sizeof(opv) + - sizeof(length), &unit, sizeof(unit)); - } - - return CSS_OK; -} - -/** - * Parse play-during - * - * \param c Parsing context - * \param vector Vector of tokens to process - * \param ctx Pointer to vector iteration context - * \param result Pointer to location to receive resulting style - * \return CSS_OK on success, - * CSS_NOMEM on memory exhaustion, - * CSS_INVALID if the input is not valid - * - * Post condition: \a *ctx is updated with the next token to process - * If the input is invalid, then \a *ctx remains unchanged. - */ -css_error parse_play_during(css_language *c, - const parserutils_vector *vector, int *ctx, - css_style **result) -{ - int orig_ctx = *ctx; - css_error error; - const css_token *token; - uint8_t flags = 0; - uint16_t value = 0; - uint32_t opv; - uint32_t required_size; - lwc_string *uri; - bool match; - - /* URI [ IDENT(mix) || IDENT(repeat) ]? | IDENT(auto,none,inherit) */ - token = parserutils_vector_iterate(vector, ctx); - if (token == NULL || (token->type != CSS_TOKEN_IDENT && - token->type != CSS_TOKEN_URI)) { - *ctx = orig_ctx; - return CSS_INVALID; - } - - if (token->type == CSS_TOKEN_IDENT) { - if ((lwc_string_caseless_isequal( - token->idata, c->strings[INHERIT], - &match) == lwc_error_ok && match)) { - flags |= FLAG_INHERIT; - } else if ((lwc_string_caseless_isequal( - token->idata, c->strings[NONE], - &match) == lwc_error_ok && match)) { - value = PLAY_DURING_NONE; - } else if ((lwc_string_caseless_isequal( - token->idata, c->strings[AUTO], - &match) == lwc_error_ok && match)) { - value = PLAY_DURING_AUTO; - } else { - *ctx = orig_ctx; - return CSS_INVALID; - } - } else { - int modifiers; - - value = PLAY_DURING_URI; - - error = c->sheet->resolve(c->sheet->resolve_pw, - c->sheet->url, - token->idata, &uri); - if (error != CSS_OK) { - *ctx = orig_ctx; - return error; - } - - for (modifiers = 0; modifiers < 2; modifiers++) { - consumeWhitespace(vector, ctx); - - token = parserutils_vector_peek(vector, *ctx); - if (token != NULL && token->type == CSS_TOKEN_IDENT) { - if ((lwc_string_caseless_isequal( - token->idata, c->strings[MIX], - &match) == lwc_error_ok && - match)) { - if ((value & PLAY_DURING_MIX) == 0) - value |= PLAY_DURING_MIX; - else { - *ctx = orig_ctx; - return CSS_INVALID; - } - } else if (lwc_string_caseless_isequal( - token->idata, - c->strings[REPEAT], - &match) == lwc_error_ok && - match) { - if ((value & PLAY_DURING_REPEAT) == 0) - value |= PLAY_DURING_REPEAT; - else { - *ctx = orig_ctx; - return CSS_INVALID; - } - } else { - *ctx = orig_ctx; - return CSS_INVALID; - } - - parserutils_vector_iterate(vector, ctx); - } - } - } - - opv = buildOPV(CSS_PROP_PLAY_DURING, flags, value); - - required_size = sizeof(opv); - if ((flags & FLAG_INHERIT) == false && - (value & PLAY_DURING_TYPE_MASK) == PLAY_DURING_URI) - required_size += sizeof(lwc_string *); - - /* Allocate result */ - error = css_stylesheet_style_create(c->sheet, required_size, result); - if (error != CSS_OK) { - *ctx = orig_ctx; - return error; - } - - /* Copy the bytecode to it */ - memcpy((*result)->bytecode, &opv, sizeof(opv)); - if ((flags & FLAG_INHERIT) == false && - (value & PLAY_DURING_TYPE_MASK) == PLAY_DURING_URI) { - /* Don't ref URI -- we want to pass ownership to the bytecode */ - memcpy((uint8_t *) (*result)->bytecode + sizeof(opv), - &uri, sizeof(lwc_string *)); - } - - return CSS_OK; -} - -/** - * Parse richness - * - * \param c Parsing context - * \param vector Vector of tokens to process - * \param ctx Pointer to vector iteration context - * \param result Pointer to location to receive resulting style - * \return CSS_OK on success, - * CSS_NOMEM on memory exhaustion, - * CSS_INVALID if the input is not valid - * - * Post condition: \a *ctx is updated with the next token to process - * If the input is invalid, then \a *ctx remains unchanged. - */ -css_error parse_richness(css_language *c, - const parserutils_vector *vector, int *ctx, - css_style **result) -{ - int orig_ctx = *ctx; - css_error error; - const css_token *token; - uint8_t flags = 0; - uint16_t value = 0; - uint32_t opv; - css_fixed num = 0; - uint32_t required_size; - bool match; - - /* number | IDENT (inherit) */ - token = parserutils_vector_iterate(vector, ctx); - if (token == NULL || (token->type != CSS_TOKEN_IDENT && - token->type != CSS_TOKEN_NUMBER)) { - *ctx = orig_ctx; - return CSS_INVALID; - } - - if ((lwc_string_caseless_isequal( - token->idata, c->strings[INHERIT], - &match) == lwc_error_ok && match)) { - flags |= FLAG_INHERIT; - } else if (token->type == CSS_TOKEN_NUMBER) { - size_t consumed = 0; - num = number_from_lwc_string(token->idata, false, &consumed); - /* Invalid if there are trailing characters */ - if (consumed != lwc_string_length(token->idata)) { - *ctx = orig_ctx; - return CSS_INVALID; - } - - /* Must be between 0 and 100 */ - if (num < 0 || num > F_100) { - *ctx = orig_ctx; - return CSS_INVALID; - } - - value = RICHNESS_SET; - } else { - *ctx = orig_ctx; - return CSS_INVALID; - } - - opv = buildOPV(CSS_PROP_RICHNESS, flags, value); - - required_size = sizeof(opv); - if ((flags & FLAG_INHERIT) == false && value == RICHNESS_SET) - required_size += sizeof(num); - - /* Allocate result */ - error = css_stylesheet_style_create(c->sheet, required_size, result); - if (error != CSS_OK) { - *ctx = orig_ctx; - return error; - } - - /* Copy the bytecode to it */ - memcpy((*result)->bytecode, &opv, sizeof(opv)); - if ((flags & FLAG_INHERIT) == false && value == RICHNESS_SET) { - memcpy(((uint8_t *) (*result)->bytecode) + sizeof(opv), - &num, sizeof(num)); - } - - return CSS_OK; -} - -/** - * Parse speak-header - * - * \param c Parsing context - * \param vector Vector of tokens to process - * \param ctx Pointer to vector iteration context - * \param result Pointer to location to receive resulting style - * \return CSS_OK on success, - * CSS_NOMEM on memory exhaustion, - * CSS_INVALID if the input is not valid - * - * Post condition: \a *ctx is updated with the next token to process - * If the input is invalid, then \a *ctx remains unchanged. - */ -css_error parse_speak_header(css_language *c, - const parserutils_vector *vector, int *ctx, - css_style **result) -{ - int orig_ctx = *ctx; - css_error error; - const css_token *ident; - uint8_t flags = 0; - uint16_t value = 0; - uint32_t opv; - bool match; - - /* IDENT (once, always, inherit) */ - ident = parserutils_vector_iterate(vector, ctx); - if (ident == NULL || ident->type != CSS_TOKEN_IDENT) { - *ctx = orig_ctx; - return CSS_INVALID; - } - - if ((lwc_string_caseless_isequal( - ident->idata, c->strings[INHERIT], - &match) == lwc_error_ok && match)) { - flags |= FLAG_INHERIT; - } else if ((lwc_string_caseless_isequal( - ident->idata, c->strings[ONCE], - &match) == lwc_error_ok && match)) { - value = SPEAK_HEADER_ONCE; - } else if ((lwc_string_caseless_isequal( - ident->idata, c->strings[ALWAYS], - &match) == lwc_error_ok && match)) { - value = SPEAK_HEADER_ALWAYS; - } else { - *ctx = orig_ctx; - return CSS_INVALID; - } - - opv = buildOPV(CSS_PROP_SPEAK_HEADER, flags, value); - - /* Allocate result */ - error = css_stylesheet_style_create(c->sheet, sizeof(opv), result); - if (error != CSS_OK) { - *ctx = orig_ctx; - return error; - } - - /* Copy the bytecode to it */ - memcpy((*result)->bytecode, &opv, sizeof(opv)); - - return CSS_OK; -} - -/** - * Parse speak-numeral - * - * \param c Parsing context - * \param vector Vector of tokens to process - * \param ctx Pointer to vector iteration context - * \param result Pointer to location to receive resulting style - * \return CSS_OK on success, - * CSS_NOMEM on memory exhaustion, - * CSS_INVALID if the input is not valid - * - * Post condition: \a *ctx is updated with the next token to process - * If the input is invalid, then \a *ctx remains unchanged. - */ -css_error parse_speak_numeral(css_language *c, - const parserutils_vector *vector, int *ctx, - css_style **result) -{ - int orig_ctx = *ctx; - css_error error; - const css_token *ident; - uint8_t flags = 0; - uint16_t value = 0; - uint32_t opv; - bool match; - - /* IDENT (digits, continuous, inherit) */ - ident = parserutils_vector_iterate(vector, ctx); - if (ident == NULL || ident->type != CSS_TOKEN_IDENT) { - *ctx = orig_ctx; - return CSS_INVALID; - } - - if ((lwc_string_caseless_isequal( - ident->idata, c->strings[INHERIT], - &match) == lwc_error_ok && match)) { - flags |= FLAG_INHERIT; - } else if ((lwc_string_caseless_isequal( - ident->idata, c->strings[DIGITS], - &match) == lwc_error_ok && match)) { - value = SPEAK_NUMERAL_DIGITS; - } else if ((lwc_string_caseless_isequal( - ident->idata, c->strings[CONTINUOUS], - &match) == lwc_error_ok && match)) { - value = SPEAK_NUMERAL_CONTINUOUS; - } else { - *ctx = orig_ctx; - return CSS_INVALID; - } - - opv = buildOPV(CSS_PROP_SPEAK_NUMERAL, flags, value); - - /* Allocate result */ - error = css_stylesheet_style_create(c->sheet, sizeof(opv), result); - if (error != CSS_OK) { - *ctx = orig_ctx; - return error; - } - - /* Copy the bytecode to it */ - memcpy((*result)->bytecode, &opv, sizeof(opv)); - - return CSS_OK; -} - -/** - * Parse speak-punctuation - * - * \param c Parsing context - * \param vector Vector of tokens to process - * \param ctx Pointer to vector iteration context - * \param result Pointer to location to receive resulting style - * \return CSS_OK on success, - * CSS_NOMEM on memory exhaustion, - * CSS_INVALID if the input is not valid - * - * Post condition: \a *ctx is updated with the next token to process - * If the input is invalid, then \a *ctx remains unchanged. - */ -css_error parse_speak_punctuation(css_language *c, - const parserutils_vector *vector, int *ctx, - css_style **result) -{ - int orig_ctx = *ctx; - css_error error; - const css_token *ident; - uint8_t flags = 0; - uint16_t value = 0; - uint32_t opv; - bool match; - - /* IDENT (code, none, inherit) */ - ident = parserutils_vector_iterate(vector, ctx); - if (ident == NULL || ident->type != CSS_TOKEN_IDENT) { - *ctx = orig_ctx; - return CSS_INVALID; - } - - if ((lwc_string_caseless_isequal( - ident->idata, c->strings[INHERIT], - &match) == lwc_error_ok && match)) { - flags |= FLAG_INHERIT; - } else if ((lwc_string_caseless_isequal( - ident->idata, c->strings[CODE], - &match) == lwc_error_ok && match)) { - value = SPEAK_PUNCTUATION_CODE; - } else if ((lwc_string_caseless_isequal( - ident->idata, c->strings[NONE], - &match) == lwc_error_ok && match)) { - value = SPEAK_PUNCTUATION_NONE; - } else { - *ctx = orig_ctx; - return CSS_INVALID; - } - - opv = buildOPV(CSS_PROP_SPEAK_PUNCTUATION, flags, value); - - /* Allocate result */ - error = css_stylesheet_style_create(c->sheet, sizeof(opv), result); - if (error != CSS_OK) { - *ctx = orig_ctx; - return error; - } - - /* Copy the bytecode to it */ - memcpy((*result)->bytecode, &opv, sizeof(opv)); - - return CSS_OK; -} - -/** - * Parse speak - * - * \param c Parsing context - * \param vector Vector of tokens to process - * \param ctx Pointer to vector iteration context - * \param result Pointer to location to receive resulting style - * \return CSS_OK on success, - * CSS_NOMEM on memory exhaustion, - * CSS_INVALID if the input is not valid - * - * Post condition: \a *ctx is updated with the next token to process - * If the input is invalid, then \a *ctx remains unchanged. - */ -css_error parse_speak(css_language *c, - const parserutils_vector *vector, int *ctx, - css_style **result) -{ - int orig_ctx = *ctx; - css_error error; - const css_token *ident; - uint8_t flags = 0; - uint16_t value = 0; - uint32_t opv; - bool match; - - /* IDENT (normal, none, spell-out, inherit) */ - ident = parserutils_vector_iterate(vector, ctx); - if (ident == NULL || ident->type != CSS_TOKEN_IDENT) { - *ctx = orig_ctx; - return CSS_INVALID; - } - - if ((lwc_string_caseless_isequal( - ident->idata, c->strings[INHERIT], - &match) == lwc_error_ok && match)) { - flags |= FLAG_INHERIT; - } else if ((lwc_string_caseless_isequal( - ident->idata, c->strings[NORMAL], - &match) == lwc_error_ok && match)) { - value = SPEAK_NORMAL; - } else if ((lwc_string_caseless_isequal( - ident->idata, c->strings[NONE], - &match) == lwc_error_ok && match)) { - value = SPEAK_NONE; - } else if ((lwc_string_caseless_isequal( - ident->idata, c->strings[SPELL_OUT], - &match) == lwc_error_ok && match)) { - value = SPEAK_SPELL_OUT; - } else { - *ctx = orig_ctx; - return CSS_INVALID; - } - - opv = buildOPV(CSS_PROP_SPEAK, flags, value); - - /* Allocate result */ - error = css_stylesheet_style_create(c->sheet, sizeof(opv), result); - if (error != CSS_OK) { - *ctx = orig_ctx; - return error; - } - - /* Copy the bytecode to it */ - memcpy((*result)->bytecode, &opv, sizeof(opv)); - - return CSS_OK; -} - -/** - * Parse speech-rate - * - * \param c Parsing context - * \param vector Vector of tokens to process - * \param ctx Pointer to vector iteration context - * \param result Pointer to location to receive resulting style - * \return CSS_OK on success, - * CSS_NOMEM on memory exhaustion, - * CSS_INVALID if the input is not valid - * - * Post condition: \a *ctx is updated with the next token to process - * If the input is invalid, then \a *ctx remains unchanged. - */ -css_error parse_speech_rate(css_language *c, - const parserutils_vector *vector, int *ctx, - css_style **result) -{ - int orig_ctx = *ctx; - css_error error; - const css_token *token; - uint8_t flags = 0; - uint16_t value = 0; - uint32_t opv; - css_fixed num = 0; - uint32_t required_size; - bool match; - - /* number | IDENT (x-slow, slow, medium, fast, x-fast, faster, slower, - * inherit) - */ - token = parserutils_vector_iterate(vector, ctx); - if (token == NULL || (token->type != CSS_TOKEN_IDENT && - token->type != CSS_TOKEN_NUMBER)) { - *ctx = orig_ctx; - return CSS_INVALID; - } - - if (token->type == CSS_TOKEN_IDENT && - (lwc_string_caseless_isequal( - token->idata, c->strings[INHERIT], - &match) == lwc_error_ok && match)) { - flags |= FLAG_INHERIT; - } else if (token->type == CSS_TOKEN_IDENT && - (lwc_string_caseless_isequal( - token->idata, c->strings[X_SLOW], - &match) == lwc_error_ok && match)) { - value = SPEECH_RATE_X_SLOW; - } else if (token->type == CSS_TOKEN_IDENT && - (lwc_string_caseless_isequal( - token->idata, c->strings[SLOW], - &match) == lwc_error_ok && match)) { - value = SPEECH_RATE_SLOW; - } else if (token->type == CSS_TOKEN_IDENT && - (lwc_string_caseless_isequal( - token->idata, c->strings[MEDIUM], - &match) == lwc_error_ok && match)) { - value = SPEECH_RATE_MEDIUM; - } else if (token->type == CSS_TOKEN_IDENT && - (lwc_string_caseless_isequal( - token->idata, c->strings[FAST], - &match) == lwc_error_ok && match)) { - value = SPEECH_RATE_FAST; - } else if (token->type == CSS_TOKEN_IDENT && - (lwc_string_caseless_isequal( - token->idata, c->strings[X_FAST], - &match) == lwc_error_ok && match)) { - value = SPEECH_RATE_X_FAST; - } else if (token->type == CSS_TOKEN_IDENT && - (lwc_string_caseless_isequal( - token->idata, c->strings[FASTER], - &match) == lwc_error_ok && match)) { - value = SPEECH_RATE_FASTER; - } else if (token->type == CSS_TOKEN_IDENT && - (lwc_string_caseless_isequal( - token->idata, c->strings[SLOWER], - &match) == lwc_error_ok && match)) { - value = SPEECH_RATE_SLOWER; - } else if (token->type == CSS_TOKEN_NUMBER) { - size_t consumed = 0; - num = number_from_lwc_string(token->idata, false, &consumed); - /* Invalid if there are trailing characters */ - if (consumed != lwc_string_length(token->idata)) { - *ctx = orig_ctx; - return CSS_INVALID; - } - - /* Make negative values invalid */ - if (num < 0) { - *ctx = orig_ctx; - return CSS_INVALID; - } - - value = SPEECH_RATE_SET; - } else { - *ctx = orig_ctx; - return CSS_INVALID; - } - - opv = buildOPV(CSS_PROP_SPEECH_RATE, flags, value); - - required_size = sizeof(opv); - if ((flags & FLAG_INHERIT) == false && value == SPEECH_RATE_SET) - required_size += sizeof(num); - - /* Allocate result */ - error = css_stylesheet_style_create(c->sheet, required_size, result); - if (error != CSS_OK) { - *ctx = orig_ctx; - return error; - } - - /* Copy the bytecode to it */ - memcpy((*result)->bytecode, &opv, sizeof(opv)); - if ((flags & FLAG_INHERIT) == false && value == SPEECH_RATE_SET) { - memcpy(((uint8_t *) (*result)->bytecode) + sizeof(opv), - &num, sizeof(num)); - } - - return CSS_OK; -} - -/** - * Parse stress - * - * \param c Parsing context - * \param vector Vector of tokens to process - * \param ctx Pointer to vector iteration context - * \param result Pointer to location to receive resulting style - * \return CSS_OK on success, - * CSS_NOMEM on memory exhaustion, - * CSS_INVALID if the input is not valid - * - * Post condition: \a *ctx is updated with the next token to process - * If the input is invalid, then \a *ctx remains unchanged. - */ -css_error parse_stress(css_language *c, - const parserutils_vector *vector, int *ctx, - css_style **result) -{ - int orig_ctx = *ctx; - css_error error; - const css_token *token; - uint8_t flags = 0; - uint16_t value = 0; - uint32_t opv; - css_fixed num = 0; - uint32_t required_size; - bool match; - - /* number | IDENT (inherit) */ - token = parserutils_vector_iterate(vector, ctx); - if (token == NULL || (token->type != CSS_TOKEN_IDENT && - token->type != CSS_TOKEN_NUMBER)) { - *ctx = orig_ctx; - return CSS_INVALID; - } - - if ((lwc_string_caseless_isequal( - token->idata, c->strings[INHERIT], - &match) == lwc_error_ok && match)) { - flags |= FLAG_INHERIT; - } else if (token->type == CSS_TOKEN_NUMBER) { - size_t consumed = 0; - num = number_from_lwc_string(token->idata, false, &consumed); - /* Invalid if there are trailing characters */ - if (consumed != lwc_string_length(token->idata)) { - *ctx = orig_ctx; - return CSS_INVALID; - } - - if (num < 0 || num > INTTOFIX(100)) { - *ctx = orig_ctx; - return CSS_INVALID; - } - - value = STRESS_SET; - } else { - *ctx = orig_ctx; - return CSS_INVALID; - } - - opv = buildOPV(CSS_PROP_STRESS, flags, value); - - required_size = sizeof(opv); - if ((flags & FLAG_INHERIT) == false && value == STRESS_SET) - required_size += sizeof(num); - - /* Allocate result */ - error = css_stylesheet_style_create(c->sheet, required_size, result); - if (error != CSS_OK) { - *ctx = orig_ctx; - return error; - } - - /* Copy the bytecode to it */ - memcpy((*result)->bytecode, &opv, sizeof(opv)); - if ((flags & FLAG_INHERIT) == false && value == STRESS_SET) { - memcpy(((uint8_t *) (*result)->bytecode) + sizeof(opv), - &num, sizeof(num)); - } - - return CSS_OK; -} - -/** - * Determine if a given voice-family ident is reserved - * - * \param c Parsing context - * \param ident IDENT to consider - * \return True if IDENT is reserved, false otherwise - */ -static bool voice_family_reserved(css_language *c, const css_token *ident) -{ - bool match; - - return (lwc_string_caseless_isequal( - ident->idata, c->strings[MALE], - &match) == lwc_error_ok && match) || - (lwc_string_caseless_isequal( - ident->idata, c->strings[FEMALE], - &match) == lwc_error_ok && match) || - (lwc_string_caseless_isequal( - ident->idata, c->strings[CHILD], - &match) == lwc_error_ok && match); -} - -/** - * Convert a voice-family token into a bytecode value - * - * \param c Parsing context - * \param token Token to consider - * \return Bytecode value - */ -static uint16_t voice_family_value(css_language *c, const css_token *token) -{ - uint16_t value; - bool match; - - if (token->type == CSS_TOKEN_IDENT) { - if ((lwc_string_caseless_isequal( - token->idata, c->strings[MALE], - &match) == lwc_error_ok && match)) - value = VOICE_FAMILY_MALE; - else if ((lwc_string_caseless_isequal( - token->idata, c->strings[FEMALE], - &match) == lwc_error_ok && match)) - value = VOICE_FAMILY_FEMALE; - else if ((lwc_string_caseless_isequal( - token->idata, c->strings[CHILD], - &match) == lwc_error_ok && match)) - value = VOICE_FAMILY_CHILD; - else - value = VOICE_FAMILY_IDENT_LIST; - } else { - value = VOICE_FAMILY_STRING; - } - - return value; -} - -/** - * Parse voice-family - * - * \param c Parsing context - * \param vector Vector of tokens to process - * \param ctx Pointer to vector iteration context - * \param result Pointer to location to receive resulting style - * \return CSS_OK on success, - * CSS_NOMEM on memory exhaustion, - * CSS_INVALID if the input is not valid - * - * Post condition: \a *ctx is updated with the next token to process - * If the input is invalid, then \a *ctx remains unchanged. - */ -css_error parse_voice_family(css_language *c, - const parserutils_vector *vector, int *ctx, - css_style **result) -{ - int orig_ctx = *ctx; - css_error error; - const css_token *token; - uint8_t flags = 0; - uint16_t value = 0; - uint32_t opv; - uint32_t required_size = sizeof(opv); - int temp_ctx = *ctx; - uint8_t *ptr; - bool match; - - /* [ IDENT+ | STRING ] [ ',' [ IDENT+ | STRING ] ]* | IDENT(inherit) - * - * In the case of IDENT+, any whitespace between tokens is collapsed to - * a single space - */ - - /* Pass 1: validate input and calculate space */ - token = parserutils_vector_iterate(vector, &temp_ctx); - if (token == NULL || (token->type != CSS_TOKEN_IDENT && - token->type != CSS_TOKEN_STRING)) { - *ctx = orig_ctx; - return CSS_INVALID; - } - - if (token->type == CSS_TOKEN_IDENT && - (lwc_string_caseless_isequal( - token->idata, c->strings[INHERIT], - &match) == lwc_error_ok && match)) { - flags = FLAG_INHERIT; - } else { - uint32_t list_size; - - value = voice_family_value(c, token); - - error = comma_list_length(c, vector, &temp_ctx, - token, voice_family_reserved, &list_size); - if (error != CSS_OK) { - *ctx = orig_ctx; - return error; - } - - required_size += list_size; - } - - opv = buildOPV(CSS_PROP_VOICE_FAMILY, flags, value); - - /* Allocate result */ - error = css_stylesheet_style_create(c->sheet, required_size, result); - if (error != CSS_OK) { - *ctx = orig_ctx; - return error; - } - - /* Copy OPV to bytecode */ - ptr = (*result)->bytecode; - memcpy(ptr, &opv, sizeof(opv)); - ptr += sizeof(opv); - - /* Pass 2: populate bytecode */ - token = parserutils_vector_iterate(vector, ctx); - if (token == NULL || (token->type != CSS_TOKEN_IDENT && - token->type != CSS_TOKEN_STRING)) { - css_stylesheet_style_destroy(c->sheet, *result, true); - *result = NULL; - *ctx = orig_ctx; - return CSS_INVALID; - } - - if (token->type == CSS_TOKEN_IDENT && - (lwc_string_caseless_isequal( - token->idata, c->strings[INHERIT], - &match) == lwc_error_ok && match)) { - /* Nothing to do */ - } else { - error = comma_list_to_bytecode(c, vector, ctx, token, - voice_family_reserved, voice_family_value, - &ptr); - if (error != CSS_OK) { - css_stylesheet_style_destroy(c->sheet, *result, true); - *result = NULL; - *ctx = orig_ctx; - return error; - } - - /* Write terminator */ - opv = VOICE_FAMILY_END; - memcpy(ptr, &opv, sizeof(opv)); - ptr += sizeof(opv); - } - - return CSS_OK; -} - -/** - * Parse volume - * - * \param c Parsing context - * \param vector Vector of tokens to process - * \param ctx Pointer to vector iteration context - * \param result Pointer to location to receive resulting style - * \return CSS_OK on success, - * CSS_NOMEM on memory exhaustion, - * CSS_INVALID if the input is not valid - * - * Post condition: \a *ctx is updated with the next token to process - * If the input is invalid, then \a *ctx remains unchanged. - */ -css_error parse_volume(css_language *c, - const parserutils_vector *vector, int *ctx, - css_style **result) -{ - int orig_ctx = *ctx; - css_error error; - const css_token *token; - uint8_t flags = 0; - uint16_t value = 0; - uint32_t opv; - css_fixed length = 0; - uint32_t unit = 0; - uint32_t required_size; - bool match; - - /* number | percentage | IDENT(silent, x-soft, soft, medium, loud, - * x-loud, inherit) - */ - token = parserutils_vector_peek(vector, *ctx); - if (token == NULL) { - *ctx = orig_ctx; - return CSS_INVALID; - } - - if (token->type == CSS_TOKEN_IDENT && - (lwc_string_caseless_isequal( - token->idata, c->strings[INHERIT], - &match) == lwc_error_ok && match)) { - parserutils_vector_iterate(vector, ctx); - flags = FLAG_INHERIT; - } else if (token->type == CSS_TOKEN_IDENT && - (lwc_string_caseless_isequal( - token->idata, c->strings[SILENT], - &match) == lwc_error_ok && match)) { - parserutils_vector_iterate(vector, ctx); - value = VOLUME_SILENT; - } else if (token->type == CSS_TOKEN_IDENT && - (lwc_string_caseless_isequal( - token->idata, c->strings[X_SOFT], - &match) == lwc_error_ok && match)) { - parserutils_vector_iterate(vector, ctx); - value = VOLUME_X_SOFT; - } else if (token->type == CSS_TOKEN_IDENT && - (lwc_string_caseless_isequal( - token->idata, c->strings[SOFT], - &match) == lwc_error_ok && match)) { - parserutils_vector_iterate(vector, ctx); - value = VOLUME_SOFT; - } else if (token->type == CSS_TOKEN_IDENT && - (lwc_string_caseless_isequal( - token->idata, c->strings[MEDIUM], - &match) == lwc_error_ok && match)) { - parserutils_vector_iterate(vector, ctx); - value = VOLUME_MEDIUM; - } else if (token->type == CSS_TOKEN_IDENT && - (lwc_string_caseless_isequal( - token->idata, c->strings[LOUD], - &match) == lwc_error_ok && match)) { - parserutils_vector_iterate(vector, ctx); - value = VOLUME_LOUD; - } else if (token->type == CSS_TOKEN_IDENT && - (lwc_string_caseless_isequal( - token->idata, c->strings[X_LOUD], - &match) == lwc_error_ok && match)) { - parserutils_vector_iterate(vector, ctx); - value = VOLUME_X_LOUD; - } else if (token->type == CSS_TOKEN_NUMBER) { - size_t consumed = 0; - length = number_from_lwc_string(token->idata, false, &consumed); - if (consumed != lwc_string_length(token->idata)) { - *ctx = orig_ctx; - return CSS_INVALID; - } - - /* Must be between 0 and 100 */ - if (length < 0 || length > F_100) { - *ctx = orig_ctx; - return CSS_INVALID; - } - - parserutils_vector_iterate(vector, ctx); - value = VOLUME_NUMBER; - } else { - /* Yes, really UNIT_PX -- percentages MUST have a % sign */ - error = parse_unit_specifier(c, vector, ctx, UNIT_PX, - &length, &unit); - if (error != CSS_OK) { - *ctx = orig_ctx; - return error; - } - - if ((unit & UNIT_PCT) == false) { - *ctx = orig_ctx; - return CSS_INVALID; - } - - /* Must be positive */ - if (length < 0) { - *ctx = orig_ctx; - return CSS_INVALID; - } - - value = VOLUME_DIMENSION; - } - - opv = buildOPV(CSS_PROP_VOLUME, flags, value); - - required_size = sizeof(opv); - if ((flags & FLAG_INHERIT) == false && value == VOLUME_NUMBER) - required_size += sizeof(length); - else if ((flags & FLAG_INHERIT) == false && value == VOLUME_DIMENSION) - required_size += sizeof(length) + sizeof(unit); - - /* Allocate result */ - error = css_stylesheet_style_create(c->sheet, required_size, result); - if (error != CSS_OK) { - *ctx = orig_ctx; - return error; - } - - /* Copy the bytecode to it */ - memcpy((*result)->bytecode, &opv, sizeof(opv)); - if ((flags & FLAG_INHERIT) == false && (value == VOLUME_NUMBER || - value == VOLUME_DIMENSION)) - memcpy(((uint8_t *) (*result)->bytecode) + sizeof(opv), - &length, sizeof(length)); - if ((flags & FLAG_INHERIT) == false && value == VOLUME_DIMENSION) - memcpy(((uint8_t *) (*result)->bytecode) + sizeof(opv) + - sizeof(length), &unit, sizeof(unit)); - - return CSS_OK; -} - -/** - * Common parser for cue-after and cue-before - * - * \param c Parsing context - * \param vector Vector of tokens to process - * \param ctx Pointer to vector iteration context - * \param op Opcode to parse for - * \param result Pointer to location to receive resulting style - * \return CSS_OK on success, - * CSS_NOMEM on memory exhaustion, - * CSS_INVALID if the input is not valid - * - * Post condition: \a *ctx is updated with the next token to process - * If the input is invalid, then \a *ctx remains unchanged. - */ -css_error parse_cue_common(css_language *c, - const parserutils_vector *vector, int *ctx, - uint16_t op, css_style **result) -{ - int orig_ctx = *ctx; - css_error error; - const css_token *token; - uint8_t flags = 0; - uint16_t value = 0; - uint32_t opv; - uint32_t required_size; - lwc_string *uri = NULL; - bool match; - - /* URI | IDENT (none, inherit) */ - token = parserutils_vector_iterate(vector, ctx); - if (token == NULL || (token->type != CSS_TOKEN_IDENT && - token->type != CSS_TOKEN_URI)) { - *ctx = orig_ctx; - return CSS_INVALID; - } - - if (token->type == CSS_TOKEN_IDENT && - (lwc_string_caseless_isequal( - token->idata, c->strings[INHERIT], - &match) == lwc_error_ok && match)) { - flags |= FLAG_INHERIT; - } else if (token->type == CSS_TOKEN_IDENT && - (lwc_string_caseless_isequal( - token->idata, c->strings[NONE], - &match) == lwc_error_ok && match)) { - value = CUE_AFTER_NONE; - } else if (token->type == CSS_TOKEN_URI) { - value = CUE_AFTER_URI; - - error = c->sheet->resolve(c->sheet->resolve_pw, - c->sheet->url, - token->idata, &uri); - if (error != CSS_OK) { - *ctx = orig_ctx; - return error; - } - } else { - *ctx = orig_ctx; - return CSS_INVALID; - } - - opv = buildOPV(op, flags, value); - - required_size = sizeof(opv); - if ((flags & FLAG_INHERIT) == false && value == CUE_AFTER_URI) - required_size += sizeof(lwc_string *); - - /* Allocate result */ - error = css_stylesheet_style_create(c->sheet, required_size, result); - if (error != CSS_OK) { - *ctx = orig_ctx; - return error; - } - - /* Copy the bytecode to it */ - memcpy((*result)->bytecode, &opv, sizeof(opv)); - if ((flags & FLAG_INHERIT) == false && value == CUE_AFTER_URI) { - /* Don't ref URI -- we want to pass ownership to the bytecode */ - memcpy((uint8_t *) (*result)->bytecode + sizeof(opv), - &uri, sizeof(lwc_string *)); - } - - return CSS_OK; -} - -/** - * Common parser for pause-after and pause-before - * - * \param c Parsing context - * \param vector Vector of tokens to process - * \param ctx Pointer to vector iteration context - * \param op Opcode to parse for - * \param result Pointer to location to receive resulting style - * \return CSS_OK on success, - * CSS_NOMEM on memory exhaustion, - * CSS_INVALID if the input is not valid - * - * Post condition: \a *ctx is updated with the next token to process - * If the input is invalid, then \a *ctx remains unchanged. - */ -css_error parse_pause_common(css_language *c, - const parserutils_vector *vector, int *ctx, - uint16_t op, css_style **result) -{ - int orig_ctx = *ctx; - css_error error; - const css_token *token; - uint8_t flags = 0; - uint16_t value = 0; - uint32_t opv; - css_fixed length = 0; - uint32_t unit = 0; - uint32_t required_size; - bool match; - - /* time | percentage | IDENT(inherit) */ - token = parserutils_vector_peek(vector, *ctx); - if (token == NULL) { - *ctx = orig_ctx; - return CSS_INVALID; - } - - if (token->type == CSS_TOKEN_IDENT && - (lwc_string_caseless_isequal( - token->idata, c->strings[INHERIT], - &match) == lwc_error_ok && match)) { - parserutils_vector_iterate(vector, ctx); - flags = FLAG_INHERIT; - } else { - error = parse_unit_specifier(c, vector, ctx, UNIT_S, - &length, &unit); - if (error != CSS_OK) { - *ctx = orig_ctx; - return error; - } - - if ((unit & UNIT_TIME) == false && (unit & UNIT_PCT) == false) { - *ctx = orig_ctx; - return CSS_INVALID; - } - - /* Negative values are illegal */ - if (length < 0) { - *ctx = orig_ctx; - return CSS_INVALID; - } - - value = PAUSE_AFTER_SET; - } - - opv = buildOPV(op, flags, value); - - required_size = sizeof(opv); - if ((flags & FLAG_INHERIT) == false && value == PAUSE_AFTER_SET) - required_size += sizeof(length) + sizeof(unit); - - /* Allocate result */ - error = css_stylesheet_style_create(c->sheet, required_size, result); - if (error != CSS_OK) { - *ctx = orig_ctx; - return error; - } - - /* Copy the bytecode to it */ - memcpy((*result)->bytecode, &opv, sizeof(opv)); - if ((flags & FLAG_INHERIT) == false && value == PAUSE_AFTER_SET) { - memcpy(((uint8_t *) (*result)->bytecode) + sizeof(opv), - &length, sizeof(length)); - memcpy(((uint8_t *) (*result)->bytecode) + sizeof(opv) + - sizeof(length), &unit, sizeof(unit)); - } - - return CSS_OK; -} - diff --git a/src/parse/properties/azimuth.c b/src/parse/properties/azimuth.c new file mode 100644 index 0000000..c5465bd --- /dev/null +++ b/src/parse/properties/azimuth.c @@ -0,0 +1,245 @@ +/* + * This file is part of LibCSS. + * Licensed under the MIT License, + * http://www.opensource.org/licenses/mit-license.php + * Copyright 2009 John-Mark Bell + */ + +#include +#include + +#include "bytecode/bytecode.h" +#include "bytecode/opcodes.h" +#include "parse/properties/properties.h" +#include "parse/properties/utils.h" + +/** + * Parse azimuth + * + * \param c Parsing context + * \param vector Vector of tokens to process + * \param ctx Pointer to vector iteration context + * \param result Pointer to location to receive resulting style + * \return CSS_OK on success, + * CSS_NOMEM on memory exhaustion, + * CSS_INVALID if the input is not valid + * + * Post condition: \a *ctx is updated with the next token to process + * If the input is invalid, then \a *ctx remains unchanged. + */ +css_error parse_azimuth(css_language *c, + const parserutils_vector *vector, int *ctx, + css_style **result) +{ + int orig_ctx = *ctx; + css_error error; + const css_token *token; + uint8_t flags = 0; + uint16_t value = 0; + uint32_t opv; + css_fixed length = 0; + uint32_t unit = 0; + uint32_t required_size; + bool match; + + /* angle | [ IDENT(left-side, far-left, left, center-left, center, + * center-right, right, far-right, right-side) || + * IDENT(behind) + * ] + * | IDENT(leftwards, rightwards, inherit) + */ + token = parserutils_vector_peek(vector, *ctx); + if (token == NULL) { + *ctx = orig_ctx; + return CSS_INVALID; + } + + if (token->type == CSS_TOKEN_IDENT && + (lwc_string_caseless_isequal(token->idata, c->strings[INHERIT], + &match) == lwc_error_ok && match)) { + parserutils_vector_iterate(vector, ctx); + flags = FLAG_INHERIT; + } else if (token->type == CSS_TOKEN_IDENT && + (lwc_string_caseless_isequal(token->idata, c->strings[LEFTWARDS], + &match) == lwc_error_ok && match)) { + parserutils_vector_iterate(vector, ctx); + value = AZIMUTH_LEFTWARDS; + } else if (token->type == CSS_TOKEN_IDENT && + (lwc_string_caseless_isequal(token->idata, c->strings[RIGHTWARDS], + &match) == lwc_error_ok && match)) { + parserutils_vector_iterate(vector, ctx); + value = AZIMUTH_RIGHTWARDS; + } else if (token->type == CSS_TOKEN_IDENT) { + parserutils_vector_iterate(vector, ctx); + + /* Now, we may have one of the other keywords or behind, + * potentially followed by behind or other keyword, + * respectively */ + if ((lwc_string_caseless_isequal( + token->idata, c->strings[LEFT_SIDE], + &match) == lwc_error_ok && match)) { + value = AZIMUTH_LEFT_SIDE; + } else if ((lwc_string_caseless_isequal( + token->idata, c->strings[FAR_LEFT], + &match) == lwc_error_ok && match)) { + value = AZIMUTH_FAR_LEFT; + } else if ((lwc_string_caseless_isequal( + token->idata, c->strings[LEFT], + &match) == lwc_error_ok && match)) { + value = AZIMUTH_LEFT; + } else if ((lwc_string_caseless_isequal( + token->idata, c->strings[CENTER_LEFT], + &match) == lwc_error_ok && match)) { + value = AZIMUTH_CENTER_LEFT; + } else if ((lwc_string_caseless_isequal( + token->idata, c->strings[CENTER], + &match) == lwc_error_ok && match)) { + value = AZIMUTH_CENTER; + } else if ((lwc_string_caseless_isequal( + token->idata, c->strings[CENTER_RIGHT], + &match) == lwc_error_ok && match)) { + value = AZIMUTH_CENTER_RIGHT; + } else if ((lwc_string_caseless_isequal( + token->idata, c->strings[RIGHT], + &match) == lwc_error_ok && match)) { + value = AZIMUTH_RIGHT; + } else if ((lwc_string_caseless_isequal( + token->idata, c->strings[FAR_RIGHT], + &match) == lwc_error_ok && match)) { + value = AZIMUTH_FAR_RIGHT; + } else if ((lwc_string_caseless_isequal( + token->idata, c->strings[RIGHT_SIDE], + &match) == lwc_error_ok && match)) { + value = AZIMUTH_RIGHT_SIDE; + } else if ((lwc_string_caseless_isequal( + token->idata, c->strings[BEHIND], + &match) == lwc_error_ok && match)) { + value = AZIMUTH_BEHIND; + } else { + *ctx = orig_ctx; + return CSS_INVALID; + } + + consumeWhitespace(vector, ctx); + + /* Get potential following token */ + token = parserutils_vector_peek(vector, *ctx); + + if (token != NULL && token->type == CSS_TOKEN_IDENT && + value == AZIMUTH_BEHIND) { + parserutils_vector_iterate(vector, ctx); + + if ((lwc_string_caseless_isequal( + token->idata, c->strings[LEFT_SIDE], + &match) == lwc_error_ok && match)) { + value |= AZIMUTH_LEFT_SIDE; + } else if ((lwc_string_caseless_isequal( + token->idata, c->strings[FAR_LEFT], + &match) == lwc_error_ok && match)) { + value |= AZIMUTH_FAR_LEFT; + } else if ((lwc_string_caseless_isequal( + token->idata, c->strings[LEFT], + &match) == lwc_error_ok && match)) { + value |= AZIMUTH_LEFT; + } else if ((lwc_string_caseless_isequal( + token->idata, c->strings[CENTER_LEFT], + &match) == lwc_error_ok && match)) { + value |= AZIMUTH_CENTER_LEFT; + } else if ((lwc_string_caseless_isequal( + token->idata, c->strings[CENTER], + &match) == lwc_error_ok && match)) { + value |= AZIMUTH_CENTER; + } else if ((lwc_string_caseless_isequal( + token->idata, c->strings[CENTER_RIGHT], + &match) == lwc_error_ok && match)) { + value |= AZIMUTH_CENTER_RIGHT; + } else if ((lwc_string_caseless_isequal( + token->idata, c->strings[RIGHT], + &match) == lwc_error_ok && match)) { + value |= AZIMUTH_RIGHT; + } else if ((lwc_string_caseless_isequal( + token->idata, c->strings[FAR_RIGHT], + &match) == lwc_error_ok && match)) { + value |= AZIMUTH_FAR_RIGHT; + } else if ((lwc_string_caseless_isequal( + token->idata, c->strings[RIGHT_SIDE], + &match) == lwc_error_ok && match)) { + value |= AZIMUTH_RIGHT_SIDE; + } else { + *ctx = orig_ctx; + return CSS_INVALID; + } + } else if (token != NULL && token->type == CSS_TOKEN_IDENT && + value != AZIMUTH_BEHIND) { + parserutils_vector_iterate(vector, ctx); + + if ((lwc_string_caseless_isequal( + token->idata, c->strings[BEHIND], + &match) == lwc_error_ok && match)) { + value |= AZIMUTH_BEHIND; + } else { + *ctx = orig_ctx; + return CSS_INVALID; + } + } else if ((token == NULL || token->type != CSS_TOKEN_IDENT) && + value == AZIMUTH_BEHIND) { + value |= AZIMUTH_CENTER; + } + } else { + error = parse_unit_specifier(c, vector, ctx, UNIT_DEG, + &length, &unit); + if (error != CSS_OK) { + *ctx = orig_ctx; + return error; + } + + if ((unit & UNIT_ANGLE) == false) { + *ctx = orig_ctx; + return CSS_INVALID; + } + + /* Valid angles lie between -360 and 360 degrees */ + if (unit == UNIT_DEG) { + if (length < FMULI(F_360, -1) || length > F_360) { + *ctx = orig_ctx; + return CSS_INVALID; + } + } else if (unit == UNIT_GRAD) { + if (length < FMULI(F_400, -1) || length > F_400) { + *ctx = orig_ctx; + return CSS_INVALID; + } + } else if (unit == UNIT_RAD) { + if (length < FMULI(F_2PI, -1) || length > F_2PI) { + *ctx = orig_ctx; + return CSS_INVALID; + } + } + + value = AZIMUTH_ANGLE; + } + + opv = buildOPV(CSS_PROP_AZIMUTH, flags, value); + + required_size = sizeof(opv); + if ((flags & FLAG_INHERIT) == false && value == AZIMUTH_ANGLE) + required_size += sizeof(length) + sizeof(unit); + + /* Allocate result */ + error = css_stylesheet_style_create(c->sheet, required_size, result); + if (error != CSS_OK) { + *ctx = orig_ctx; + return error; + } + + /* Copy the bytecode to it */ + memcpy((*result)->bytecode, &opv, sizeof(opv)); + if ((flags & FLAG_INHERIT) == false && value == AZIMUTH_ANGLE) { + memcpy(((uint8_t *) (*result)->bytecode) + sizeof(opv), + &length, sizeof(length)); + memcpy(((uint8_t *) (*result)->bytecode) + sizeof(opv) + + sizeof(length), &unit, sizeof(unit)); + } + + return CSS_OK; +} diff --git a/src/parse/properties/background.c b/src/parse/properties/background.c index 7d37a32..25c9315 100644 --- a/src/parse/properties/background.c +++ b/src/parse/properties/background.c @@ -245,516 +245,8 @@ cleanup: return error; } -/** - * Parse background-attachment - * - * \param c Parsing context - * \param vector Vector of tokens to process - * \param ctx Pointer to vector iteration context - * \param result Pointer to location to receive resulting style - * \return CSS_OK on success, - * CSS_NOMEM on memory exhaustion, - * CSS_INVALID if the input is not valid - * - * Post condition: \a *ctx is updated with the next token to process - * If the input is invalid, then \a *ctx remains unchanged. - */ -css_error parse_background_attachment(css_language *c, - const parserutils_vector *vector, int *ctx, - css_style **result) -{ - int orig_ctx = *ctx; - css_error error; - const css_token *ident; - uint8_t flags = 0; - uint16_t value = 0; - uint32_t opv; - bool match; - /* IDENT (fixed, scroll, inherit) */ - ident = parserutils_vector_iterate(vector, ctx); - if (ident == NULL || ident->type != CSS_TOKEN_IDENT) { - *ctx = orig_ctx; - return CSS_INVALID; - } - if ((lwc_string_caseless_isequal( - ident->idata, c->strings[INHERIT], - &match) == lwc_error_ok && match)) { - flags |= FLAG_INHERIT; - } else if ((lwc_string_caseless_isequal( - ident->idata, c->strings[FIXED], - &match) == lwc_error_ok && match)) { - value = BACKGROUND_ATTACHMENT_FIXED; - } else if ((lwc_string_caseless_isequal( - ident->idata, c->strings[SCROLL], - &match) == lwc_error_ok && match)) { - value = BACKGROUND_ATTACHMENT_SCROLL; - } else { - *ctx = orig_ctx; - return CSS_INVALID; - } - opv = buildOPV(CSS_PROP_BACKGROUND_ATTACHMENT, flags, value); - /* Allocate result */ - error = css_stylesheet_style_create(c->sheet, sizeof(opv), result); - if (error != CSS_OK) { - *ctx = orig_ctx; - return error; - } - - /* Copy the bytecode to it */ - memcpy((*result)->bytecode, &opv, sizeof(opv)); - - return CSS_OK; -} - -/** - * Parse background-color - * - * \param c Parsing context - * \param vector Vector of tokens to process - * \param ctx Pointer to vector iteration context - * \param result Pointer to location to receive resulting style - * \return CSS_OK on success, - * CSS_NOMEM on memory exhaustion, - * CSS_INVALID if the input is not valid - * - * Post condition: \a *ctx is updated with the next token to process - * If the input is invalid, then \a *ctx remains unchanged. - */ -css_error parse_background_color(css_language *c, - const parserutils_vector *vector, int *ctx, - css_style **result) -{ - int orig_ctx = *ctx; - css_error error; - const css_token *token; - uint8_t flags = 0; - uint16_t value = 0; - uint32_t opv; - uint32_t colour = 0; - uint32_t required_size; - bool match; - - /* colour | IDENT (transparent, inherit) */ - token = parserutils_vector_peek(vector, *ctx); - if (token == NULL) { - *ctx = orig_ctx; - return CSS_INVALID; - } - - if (token->type == CSS_TOKEN_IDENT && - (lwc_string_caseless_isequal( - token->idata, c->strings[INHERIT], - &match) == lwc_error_ok && match)) { - parserutils_vector_iterate(vector, ctx); - flags |= FLAG_INHERIT; - } else if (token->type == CSS_TOKEN_IDENT && - (lwc_string_caseless_isequal( - token->idata, c->strings[TRANSPARENT], - &match) == lwc_error_ok && match)) { - parserutils_vector_iterate(vector, ctx); - value = BACKGROUND_COLOR_TRANSPARENT; - } else { - error = parse_colour_specifier(c, vector, ctx, &colour); - if (error != CSS_OK) { - *ctx = orig_ctx; - return error; - } - - value = BACKGROUND_COLOR_SET; - } - - opv = buildOPV(CSS_PROP_BACKGROUND_COLOR, flags, value); - - required_size = sizeof(opv); - if ((flags & FLAG_INHERIT) == false && value == BACKGROUND_COLOR_SET) - required_size += sizeof(colour); - - /* Allocate result */ - error = css_stylesheet_style_create(c->sheet, required_size, result); - if (error != CSS_OK) { - *ctx = orig_ctx; - return error; - } - - /* Copy the bytecode to it */ - memcpy((*result)->bytecode, &opv, sizeof(opv)); - if ((flags & FLAG_INHERIT) == false && value == BACKGROUND_COLOR_SET) { - memcpy(((uint8_t *) (*result)->bytecode) + sizeof(opv), - &colour, sizeof(colour)); - } - - return CSS_OK; -} - -/** - * Parse background-image - * - * \param c Parsing context - * \param vector Vector of tokens to process - * \param ctx Pointer to vector iteration context - * \param result Pointer to location to receive resulting style - * \return CSS_OK on success, - * CSS_NOMEM on memory exhaustion, - * CSS_INVALID if the input is not valid - * - * Post condition: \a *ctx is updated with the next token to process - * If the input is invalid, then \a *ctx remains unchanged. - */ -css_error parse_background_image(css_language *c, - const parserutils_vector *vector, int *ctx, - css_style **result) -{ - int orig_ctx = *ctx; - css_error error; - const css_token *token; - uint8_t flags = 0; - uint16_t value = 0; - uint32_t opv; - uint32_t required_size; - bool match; - lwc_string *uri = NULL; - - /* URI | IDENT (none, inherit) */ - token = parserutils_vector_iterate(vector, ctx); - if (token == NULL || (token->type != CSS_TOKEN_IDENT && - token->type != CSS_TOKEN_URI)) { - *ctx = orig_ctx; - return CSS_INVALID; - } - - if (token->type == CSS_TOKEN_IDENT && - (lwc_string_caseless_isequal( - token->idata, c->strings[INHERIT], - &match) == lwc_error_ok && match)) { - flags |= FLAG_INHERIT; - } else if (token->type == CSS_TOKEN_IDENT && - (lwc_string_caseless_isequal( - token->idata, c->strings[NONE], - &match) == lwc_error_ok && match)) { - value = BACKGROUND_IMAGE_NONE; - } else if (token->type == CSS_TOKEN_URI) { - value = BACKGROUND_IMAGE_URI; - - error = c->sheet->resolve(c->sheet->resolve_pw, - c->sheet->url, - token->idata, &uri); - if (error != CSS_OK) { - *ctx = orig_ctx; - return error; - } - } else { - *ctx = orig_ctx; - return CSS_INVALID; - } - - opv = buildOPV(CSS_PROP_BACKGROUND_IMAGE, flags, value); - - required_size = sizeof(opv); - if ((flags & FLAG_INHERIT) == false && value == BACKGROUND_IMAGE_URI) - required_size += sizeof(lwc_string *); - - /* Allocate result */ - error = css_stylesheet_style_create(c->sheet, required_size, result); - if (error != CSS_OK) { - *ctx = orig_ctx; - return error; - } - - /* Copy the bytecode to it */ - memcpy((*result)->bytecode, &opv, sizeof(opv)); - if ((flags & FLAG_INHERIT) == false && value == BACKGROUND_IMAGE_URI) { - /* Don't ref URI -- we want to pass ownership to the bytecode */ - memcpy((uint8_t *) (*result)->bytecode + sizeof(opv), - &uri, sizeof(lwc_string *)); - } - - return CSS_OK; -} - -/** - * Parse background-position - * - * \param c Parsing context - * \param vector Vector of tokens to process - * \param ctx Pointer to vector iteration context - * \param result Pointer to location to receive resulting style - * \return CSS_OK on success, - * CSS_NOMEM on memory exhaustion, - * CSS_INVALID if the input is not valid - * - * Post condition: \a *ctx is updated with the next token to process - * If the input is invalid, then \a *ctx remains unchanged. - */ -css_error parse_background_position(css_language *c, - const parserutils_vector *vector, int *ctx, - css_style **result) -{ - int orig_ctx = *ctx; - css_error error; - const css_token *token; - uint8_t flags = 0; - uint32_t opv; - uint16_t value[2] = { 0 }; - css_fixed length[2] = { 0 }; - uint32_t unit[2] = { 0 }; - uint32_t required_size; - bool match; - - /* [length | percentage | IDENT(left, right, top, bottom, center)]{1,2} - * | IDENT(inherit) */ - token = parserutils_vector_peek(vector, *ctx); - if (token == NULL) { - *ctx = orig_ctx; - return CSS_INVALID; - } - - if (token->type == CSS_TOKEN_IDENT && - (lwc_string_caseless_isequal( - token->idata, c->strings[INHERIT], - &match) == lwc_error_ok && match)) { - parserutils_vector_iterate(vector, ctx); - flags = FLAG_INHERIT; - } else { - int i; - - for (i = 0; i < 2; i++) { - token = parserutils_vector_peek(vector, *ctx); - if (token == NULL) - break; - - if (token->type == CSS_TOKEN_IDENT) { - if ((lwc_string_caseless_isequal( - token->idata, c->strings[LEFT], - &match) == lwc_error_ok && - match)) { - value[i] = - BACKGROUND_POSITION_HORZ_LEFT; - } else if ((lwc_string_caseless_isequal( - token->idata, c->strings[RIGHT], - &match) == lwc_error_ok && - match)) { - value[i] = - BACKGROUND_POSITION_HORZ_RIGHT; - } else if ((lwc_string_caseless_isequal( - token->idata, c->strings[TOP], - &match) == lwc_error_ok && - match)) { - value[i] = BACKGROUND_POSITION_VERT_TOP; - } else if ((lwc_string_caseless_isequal( - token->idata, - c->strings[BOTTOM], - &match) == lwc_error_ok && - match)) { - value[i] = - BACKGROUND_POSITION_VERT_BOTTOM; - } else if ((lwc_string_caseless_isequal( - token->idata, - c->strings[CENTER], - &match) == lwc_error_ok && - match)) { - /* We'll fix this up later */ - value[i] = - BACKGROUND_POSITION_VERT_CENTER; - } else if (i == 1) { - /* Second pass, so ignore this one */ - break; - } else { - /* First pass, so invalid */ - *ctx = orig_ctx; - return CSS_INVALID; - } - - parserutils_vector_iterate(vector, ctx); - } else if (token->type == CSS_TOKEN_DIMENSION || - token->type == CSS_TOKEN_NUMBER || - token->type == CSS_TOKEN_PERCENTAGE) { - error = parse_unit_specifier(c, vector, ctx, - UNIT_PX, &length[i], &unit[i]); - if (error != CSS_OK) { - *ctx = orig_ctx; - return error; - } - - if (unit[i] & UNIT_ANGLE || - unit[i] & UNIT_TIME || - unit[i] & UNIT_FREQ) { - *ctx = orig_ctx; - return CSS_INVALID; - } - - /* We'll fix this up later, too */ - value[i] = BACKGROUND_POSITION_VERT_SET; - } else { - if (i == 1) { - /* Second pass, so ignore */ - break; - } else { - /* First pass, so invalid */ - *ctx = orig_ctx; - return CSS_INVALID; - } - } - - consumeWhitespace(vector, ctx); - } - - assert(i != 0); - - /* Now, sort out the mess we've got */ - if (i == 1) { - assert(BACKGROUND_POSITION_VERT_CENTER == - BACKGROUND_POSITION_HORZ_CENTER); - - /* Only one value, so the other is center */ - switch (value[0]) { - case BACKGROUND_POSITION_HORZ_LEFT: - case BACKGROUND_POSITION_HORZ_RIGHT: - case BACKGROUND_POSITION_VERT_CENTER: - case BACKGROUND_POSITION_VERT_TOP: - case BACKGROUND_POSITION_VERT_BOTTOM: - break; - case BACKGROUND_POSITION_VERT_SET: - value[0] = BACKGROUND_POSITION_HORZ_SET; - break; - } - - value[1] = BACKGROUND_POSITION_VERT_CENTER; - } else if (value[0] != BACKGROUND_POSITION_VERT_SET && - value[1] != BACKGROUND_POSITION_VERT_SET) { - /* Two keywords. Verify the axes differ */ - if (((value[0] & 0xf) != 0 && (value[1] & 0xf) != 0) || - ((value[0] & 0xf0) != 0 && - (value[1] & 0xf0) != 0)) { - *ctx = orig_ctx; - return CSS_INVALID; - } - } else { - /* One or two non-keywords. First is horizontal */ - if (value[0] == BACKGROUND_POSITION_VERT_SET) - value[0] = BACKGROUND_POSITION_HORZ_SET; - - /* Verify the axes differ */ - if (((value[0] & 0xf) != 0 && (value[1] & 0xf) != 0) || - ((value[0] & 0xf0) != 0 && - (value[1] & 0xf0) != 0)) { - *ctx = orig_ctx; - return CSS_INVALID; - } - } - } - - opv = buildOPV(CSS_PROP_BACKGROUND_POSITION, flags, - value[0] | value[1]); - - required_size = sizeof(opv); - if ((flags & FLAG_INHERIT) == false) { - if (value[0] == BACKGROUND_POSITION_HORZ_SET) - required_size += sizeof(length[0]) + sizeof(unit[0]); - if (value[1] == BACKGROUND_POSITION_VERT_SET) - required_size += sizeof(length[1]) + sizeof(unit[1]); - } - - /* Allocate result */ - error = css_stylesheet_style_create(c->sheet, required_size, result); - if (error != CSS_OK) { - *ctx = orig_ctx; - return error; - } - - /* Copy the bytecode to it */ - memcpy((*result)->bytecode, &opv, sizeof(opv)); - if ((flags & FLAG_INHERIT) == false) { - uint8_t *ptr = ((uint8_t *) (*result)->bytecode) + sizeof(opv); - if (value[0] == BACKGROUND_POSITION_HORZ_SET) { - memcpy(ptr, &length[0], sizeof(length[0])); - ptr += sizeof(length[0]); - memcpy(ptr, &unit[0], sizeof(unit[0])); - ptr += sizeof(unit[0]); - } - if (value[1] == BACKGROUND_POSITION_VERT_SET) { - memcpy(ptr, &length[1], sizeof(length[1])); - ptr += sizeof(length[1]); - memcpy(ptr, &unit[1], sizeof(unit[1])); - } - } - - return CSS_OK; -} - -/** - * Parse background-repeat - * - * \param c Parsing context - * \param vector Vector of tokens to process - * \param ctx Pointer to vector iteration context - * \param result Pointer to location to receive resulting style - * \return CSS_OK on success, - * CSS_NOMEM on memory exhaustion, - * CSS_INVALID if the input is not valid - * - * Post condition: \a *ctx is updated with the next token to process - * If the input is invalid, then \a *ctx remains unchanged. - */ -css_error parse_background_repeat(css_language *c, - const parserutils_vector *vector, int *ctx, - css_style **result) -{ - int orig_ctx = *ctx; - css_error error; - const css_token *ident; - uint8_t flags = 0; - uint16_t value = 0; - uint32_t opv; - bool match; - - /* IDENT (no-repeat, repeat-x, repeat-y, repeat, inherit) */ - ident = parserutils_vector_iterate(vector, ctx); - if (ident == NULL || ident->type != CSS_TOKEN_IDENT) { - *ctx = orig_ctx; - return CSS_INVALID; - } - - if ((lwc_string_caseless_isequal( - ident->idata, c->strings[INHERIT], - &match) == lwc_error_ok && match)) { - flags |= FLAG_INHERIT; - } else if ((lwc_string_caseless_isequal( - ident->idata, c->strings[NO_REPEAT], - &match) == lwc_error_ok && match)) { - value = BACKGROUND_REPEAT_NO_REPEAT; - } else if ((lwc_string_caseless_isequal( - ident->idata, c->strings[REPEAT_X], - &match) == lwc_error_ok && match)) { - value = BACKGROUND_REPEAT_REPEAT_X; - } else if ((lwc_string_caseless_isequal( - ident->idata, c->strings[REPEAT_Y], - &match) == lwc_error_ok && match)) { - value = BACKGROUND_REPEAT_REPEAT_Y; - } else if ((lwc_string_caseless_isequal( - ident->idata, c->strings[REPEAT], - &match) == lwc_error_ok && match)) { - value = BACKGROUND_REPEAT_REPEAT; - } else { - *ctx = orig_ctx; - return CSS_INVALID; - } - - opv = buildOPV(CSS_PROP_BACKGROUND_REPEAT, flags, value); - - /* Allocate result */ - error = css_stylesheet_style_create(c->sheet, sizeof(opv), result); - if (error != CSS_OK) { - *ctx = orig_ctx; - return error; - } - - /* Copy the bytecode to it */ - memcpy((*result)->bytecode, &opv, sizeof(opv)); - - return CSS_OK; -} diff --git a/src/parse/properties/background_attachment.c b/src/parse/properties/background_attachment.c new file mode 100644 index 0000000..d1c6da4 --- /dev/null +++ b/src/parse/properties/background_attachment.c @@ -0,0 +1,79 @@ +/* + * This file is part of LibCSS. + * Licensed under the MIT License, + * http://www.opensource.org/licenses/mit-license.php + * Copyright 2009 John-Mark Bell + */ + +#include +#include + +#include "bytecode/bytecode.h" +#include "bytecode/opcodes.h" +#include "parse/properties/properties.h" +#include "parse/properties/utils.h" + +/** + * Parse background-attachment + * + * \param c Parsing context + * \param vector Vector of tokens to process + * \param ctx Pointer to vector iteration context + * \param result Pointer to location to receive resulting style + * \return CSS_OK on success, + * CSS_NOMEM on memory exhaustion, + * CSS_INVALID if the input is not valid + * + * Post condition: \a *ctx is updated with the next token to process + * If the input is invalid, then \a *ctx remains unchanged. + */ +css_error parse_background_attachment(css_language *c, + const parserutils_vector *vector, int *ctx, + css_style **result) +{ + int orig_ctx = *ctx; + css_error error; + const css_token *ident; + uint8_t flags = 0; + uint16_t value = 0; + uint32_t opv; + bool match; + + /* IDENT (fixed, scroll, inherit) */ + ident = parserutils_vector_iterate(vector, ctx); + if (ident == NULL || ident->type != CSS_TOKEN_IDENT) { + *ctx = orig_ctx; + return CSS_INVALID; + } + + if ((lwc_string_caseless_isequal( + ident->idata, c->strings[INHERIT], + &match) == lwc_error_ok && match)) { + flags |= FLAG_INHERIT; + } else if ((lwc_string_caseless_isequal( + ident->idata, c->strings[FIXED], + &match) == lwc_error_ok && match)) { + value = BACKGROUND_ATTACHMENT_FIXED; + } else if ((lwc_string_caseless_isequal( + ident->idata, c->strings[SCROLL], + &match) == lwc_error_ok && match)) { + value = BACKGROUND_ATTACHMENT_SCROLL; + } else { + *ctx = orig_ctx; + return CSS_INVALID; + } + + opv = buildOPV(CSS_PROP_BACKGROUND_ATTACHMENT, flags, value); + + /* Allocate result */ + error = css_stylesheet_style_create(c->sheet, sizeof(opv), result); + if (error != CSS_OK) { + *ctx = orig_ctx; + return error; + } + + /* Copy the bytecode to it */ + memcpy((*result)->bytecode, &opv, sizeof(opv)); + + return CSS_OK; +} diff --git a/src/parse/properties/background_color.c b/src/parse/properties/background_color.c new file mode 100644 index 0000000..bf8d341 --- /dev/null +++ b/src/parse/properties/background_color.c @@ -0,0 +1,94 @@ +/* + * This file is part of LibCSS. + * Licensed under the MIT License, + * http://www.opensource.org/licenses/mit-license.php + * Copyright 2009 John-Mark Bell + */ + +#include +#include + +#include "bytecode/bytecode.h" +#include "bytecode/opcodes.h" +#include "parse/properties/properties.h" +#include "parse/properties/utils.h" + +/** + * Parse background-color + * + * \param c Parsing context + * \param vector Vector of tokens to process + * \param ctx Pointer to vector iteration context + * \param result Pointer to location to receive resulting style + * \return CSS_OK on success, + * CSS_NOMEM on memory exhaustion, + * CSS_INVALID if the input is not valid + * + * Post condition: \a *ctx is updated with the next token to process + * If the input is invalid, then \a *ctx remains unchanged. + */ +css_error parse_background_color(css_language *c, + const parserutils_vector *vector, int *ctx, + css_style **result) +{ + int orig_ctx = *ctx; + css_error error; + const css_token *token; + uint8_t flags = 0; + uint16_t value = 0; + uint32_t opv; + uint32_t colour = 0; + uint32_t required_size; + bool match; + + /* colour | IDENT (transparent, inherit) */ + token = parserutils_vector_peek(vector, *ctx); + if (token == NULL) { + *ctx = orig_ctx; + return CSS_INVALID; + } + + if (token->type == CSS_TOKEN_IDENT && + (lwc_string_caseless_isequal( + token->idata, c->strings[INHERIT], + &match) == lwc_error_ok && match)) { + parserutils_vector_iterate(vector, ctx); + flags |= FLAG_INHERIT; + } else if (token->type == CSS_TOKEN_IDENT && + (lwc_string_caseless_isequal( + token->idata, c->strings[TRANSPARENT], + &match) == lwc_error_ok && match)) { + parserutils_vector_iterate(vector, ctx); + value = BACKGROUND_COLOR_TRANSPARENT; + } else { + error = parse_colour_specifier(c, vector, ctx, &colour); + if (error != CSS_OK) { + *ctx = orig_ctx; + return error; + } + + value = BACKGROUND_COLOR_SET; + } + + opv = buildOPV(CSS_PROP_BACKGROUND_COLOR, flags, value); + + required_size = sizeof(opv); + if ((flags & FLAG_INHERIT) == false && value == BACKGROUND_COLOR_SET) + required_size += sizeof(colour); + + /* Allocate result */ + error = css_stylesheet_style_create(c->sheet, required_size, result); + if (error != CSS_OK) { + *ctx = orig_ctx; + return error; + } + + /* Copy the bytecode to it */ + memcpy((*result)->bytecode, &opv, sizeof(opv)); + if ((flags & FLAG_INHERIT) == false && value == BACKGROUND_COLOR_SET) { + memcpy(((uint8_t *) (*result)->bytecode) + sizeof(opv), + &colour, sizeof(colour)); + } + + return CSS_OK; +} diff --git a/src/parse/properties/background_image.c b/src/parse/properties/background_image.c new file mode 100644 index 0000000..52d3006 --- /dev/null +++ b/src/parse/properties/background_image.c @@ -0,0 +1,99 @@ +/* + * This file is part of LibCSS. + * Licensed under the MIT License, + * http://www.opensource.org/licenses/mit-license.php + * Copyright 2009 John-Mark Bell + */ + +#include +#include + +#include "bytecode/bytecode.h" +#include "bytecode/opcodes.h" +#include "parse/properties/properties.h" +#include "parse/properties/utils.h" + +/** + * Parse background-image + * + * \param c Parsing context + * \param vector Vector of tokens to process + * \param ctx Pointer to vector iteration context + * \param result Pointer to location to receive resulting style + * \return CSS_OK on success, + * CSS_NOMEM on memory exhaustion, + * CSS_INVALID if the input is not valid + * + * Post condition: \a *ctx is updated with the next token to process + * If the input is invalid, then \a *ctx remains unchanged. + */ +css_error parse_background_image(css_language *c, + const parserutils_vector *vector, int *ctx, + css_style **result) +{ + int orig_ctx = *ctx; + css_error error; + const css_token *token; + uint8_t flags = 0; + uint16_t value = 0; + uint32_t opv; + uint32_t required_size; + bool match; + lwc_string *uri = NULL; + + /* URI | IDENT (none, inherit) */ + token = parserutils_vector_iterate(vector, ctx); + if (token == NULL || (token->type != CSS_TOKEN_IDENT && + token->type != CSS_TOKEN_URI)) { + *ctx = orig_ctx; + return CSS_INVALID; + } + + if (token->type == CSS_TOKEN_IDENT && + (lwc_string_caseless_isequal( + token->idata, c->strings[INHERIT], + &match) == lwc_error_ok && match)) { + flags |= FLAG_INHERIT; + } else if (token->type == CSS_TOKEN_IDENT && + (lwc_string_caseless_isequal( + token->idata, c->strings[NONE], + &match) == lwc_error_ok && match)) { + value = BACKGROUND_IMAGE_NONE; + } else if (token->type == CSS_TOKEN_URI) { + value = BACKGROUND_IMAGE_URI; + + error = c->sheet->resolve(c->sheet->resolve_pw, + c->sheet->url, + token->idata, &uri); + if (error != CSS_OK) { + *ctx = orig_ctx; + return error; + } + } else { + *ctx = orig_ctx; + return CSS_INVALID; + } + + opv = buildOPV(CSS_PROP_BACKGROUND_IMAGE, flags, value); + + required_size = sizeof(opv); + if ((flags & FLAG_INHERIT) == false && value == BACKGROUND_IMAGE_URI) + required_size += sizeof(lwc_string *); + + /* Allocate result */ + error = css_stylesheet_style_create(c->sheet, required_size, result); + if (error != CSS_OK) { + *ctx = orig_ctx; + return error; + } + + /* Copy the bytecode to it */ + memcpy((*result)->bytecode, &opv, sizeof(opv)); + if ((flags & FLAG_INHERIT) == false && value == BACKGROUND_IMAGE_URI) { + /* Don't ref URI -- we want to pass ownership to the bytecode */ + memcpy((uint8_t *) (*result)->bytecode + sizeof(opv), + &uri, sizeof(lwc_string *)); + } + + return CSS_OK; +} diff --git a/src/parse/properties/background_position.c b/src/parse/properties/background_position.c new file mode 100644 index 0000000..94bce82 --- /dev/null +++ b/src/parse/properties/background_position.c @@ -0,0 +1,224 @@ +/* + * This file is part of LibCSS. + * Licensed under the MIT License, + * http://www.opensource.org/licenses/mit-license.php + * Copyright 2009 John-Mark Bell + */ + +#include +#include + +#include "bytecode/bytecode.h" +#include "bytecode/opcodes.h" +#include "parse/properties/properties.h" +#include "parse/properties/utils.h" + +/** + * Parse background-position + * + * \param c Parsing context + * \param vector Vector of tokens to process + * \param ctx Pointer to vector iteration context + * \param result Pointer to location to receive resulting style + * \return CSS_OK on success, + * CSS_NOMEM on memory exhaustion, + * CSS_INVALID if the input is not valid + * + * Post condition: \a *ctx is updated with the next token to process + * If the input is invalid, then \a *ctx remains unchanged. + */ +css_error parse_background_position(css_language *c, + const parserutils_vector *vector, int *ctx, + css_style **result) +{ + int orig_ctx = *ctx; + css_error error; + const css_token *token; + uint8_t flags = 0; + uint32_t opv; + uint16_t value[2] = { 0 }; + css_fixed length[2] = { 0 }; + uint32_t unit[2] = { 0 }; + uint32_t required_size; + bool match; + + /* [length | percentage | IDENT(left, right, top, bottom, center)]{1,2} + * | IDENT(inherit) */ + token = parserutils_vector_peek(vector, *ctx); + if (token == NULL) { + *ctx = orig_ctx; + return CSS_INVALID; + } + + if (token->type == CSS_TOKEN_IDENT && + (lwc_string_caseless_isequal( + token->idata, c->strings[INHERIT], + &match) == lwc_error_ok && match)) { + parserutils_vector_iterate(vector, ctx); + flags = FLAG_INHERIT; + } else { + int i; + + for (i = 0; i < 2; i++) { + token = parserutils_vector_peek(vector, *ctx); + if (token == NULL) + break; + + if (token->type == CSS_TOKEN_IDENT) { + if ((lwc_string_caseless_isequal( + token->idata, c->strings[LEFT], + &match) == lwc_error_ok && + match)) { + value[i] = + BACKGROUND_POSITION_HORZ_LEFT; + } else if ((lwc_string_caseless_isequal( + token->idata, c->strings[RIGHT], + &match) == lwc_error_ok && + match)) { + value[i] = + BACKGROUND_POSITION_HORZ_RIGHT; + } else if ((lwc_string_caseless_isequal( + token->idata, c->strings[TOP], + &match) == lwc_error_ok && + match)) { + value[i] = BACKGROUND_POSITION_VERT_TOP; + } else if ((lwc_string_caseless_isequal( + token->idata, + c->strings[BOTTOM], + &match) == lwc_error_ok && + match)) { + value[i] = + BACKGROUND_POSITION_VERT_BOTTOM; + } else if ((lwc_string_caseless_isequal( + token->idata, + c->strings[CENTER], + &match) == lwc_error_ok && + match)) { + /* We'll fix this up later */ + value[i] = + BACKGROUND_POSITION_VERT_CENTER; + } else if (i == 1) { + /* Second pass, so ignore this one */ + break; + } else { + /* First pass, so invalid */ + *ctx = orig_ctx; + return CSS_INVALID; + } + + parserutils_vector_iterate(vector, ctx); + } else if (token->type == CSS_TOKEN_DIMENSION || + token->type == CSS_TOKEN_NUMBER || + token->type == CSS_TOKEN_PERCENTAGE) { + error = parse_unit_specifier(c, vector, ctx, + UNIT_PX, &length[i], &unit[i]); + if (error != CSS_OK) { + *ctx = orig_ctx; + return error; + } + + if (unit[i] & UNIT_ANGLE || + unit[i] & UNIT_TIME || + unit[i] & UNIT_FREQ) { + *ctx = orig_ctx; + return CSS_INVALID; + } + + /* We'll fix this up later, too */ + value[i] = BACKGROUND_POSITION_VERT_SET; + } else { + if (i == 1) { + /* Second pass, so ignore */ + break; + } else { + /* First pass, so invalid */ + *ctx = orig_ctx; + return CSS_INVALID; + } + } + + consumeWhitespace(vector, ctx); + } + + assert(i != 0); + + /* Now, sort out the mess we've got */ + if (i == 1) { + assert(BACKGROUND_POSITION_VERT_CENTER == + BACKGROUND_POSITION_HORZ_CENTER); + + /* Only one value, so the other is center */ + switch (value[0]) { + case BACKGROUND_POSITION_HORZ_LEFT: + case BACKGROUND_POSITION_HORZ_RIGHT: + case BACKGROUND_POSITION_VERT_CENTER: + case BACKGROUND_POSITION_VERT_TOP: + case BACKGROUND_POSITION_VERT_BOTTOM: + break; + case BACKGROUND_POSITION_VERT_SET: + value[0] = BACKGROUND_POSITION_HORZ_SET; + break; + } + + value[1] = BACKGROUND_POSITION_VERT_CENTER; + } else if (value[0] != BACKGROUND_POSITION_VERT_SET && + value[1] != BACKGROUND_POSITION_VERT_SET) { + /* Two keywords. Verify the axes differ */ + if (((value[0] & 0xf) != 0 && (value[1] & 0xf) != 0) || + ((value[0] & 0xf0) != 0 && + (value[1] & 0xf0) != 0)) { + *ctx = orig_ctx; + return CSS_INVALID; + } + } else { + /* One or two non-keywords. First is horizontal */ + if (value[0] == BACKGROUND_POSITION_VERT_SET) + value[0] = BACKGROUND_POSITION_HORZ_SET; + + /* Verify the axes differ */ + if (((value[0] & 0xf) != 0 && (value[1] & 0xf) != 0) || + ((value[0] & 0xf0) != 0 && + (value[1] & 0xf0) != 0)) { + *ctx = orig_ctx; + return CSS_INVALID; + } + } + } + + opv = buildOPV(CSS_PROP_BACKGROUND_POSITION, flags, + value[0] | value[1]); + + required_size = sizeof(opv); + if ((flags & FLAG_INHERIT) == false) { + if (value[0] == BACKGROUND_POSITION_HORZ_SET) + required_size += sizeof(length[0]) + sizeof(unit[0]); + if (value[1] == BACKGROUND_POSITION_VERT_SET) + required_size += sizeof(length[1]) + sizeof(unit[1]); + } + + /* Allocate result */ + error = css_stylesheet_style_create(c->sheet, required_size, result); + if (error != CSS_OK) { + *ctx = orig_ctx; + return error; + } + + /* Copy the bytecode to it */ + memcpy((*result)->bytecode, &opv, sizeof(opv)); + if ((flags & FLAG_INHERIT) == false) { + uint8_t *ptr = ((uint8_t *) (*result)->bytecode) + sizeof(opv); + if (value[0] == BACKGROUND_POSITION_HORZ_SET) { + memcpy(ptr, &length[0], sizeof(length[0])); + ptr += sizeof(length[0]); + memcpy(ptr, &unit[0], sizeof(unit[0])); + ptr += sizeof(unit[0]); + } + if (value[1] == BACKGROUND_POSITION_VERT_SET) { + memcpy(ptr, &length[1], sizeof(length[1])); + ptr += sizeof(length[1]); + memcpy(ptr, &unit[1], sizeof(unit[1])); + } + } + + return CSS_OK; +} diff --git a/src/parse/properties/background_repeat.c b/src/parse/properties/background_repeat.c new file mode 100644 index 0000000..06b2e8d --- /dev/null +++ b/src/parse/properties/background_repeat.c @@ -0,0 +1,87 @@ +/* + * This file is part of LibCSS. + * Licensed under the MIT License, + * http://www.opensource.org/licenses/mit-license.php + * Copyright 2009 John-Mark Bell + */ + +#include +#include + +#include "bytecode/bytecode.h" +#include "bytecode/opcodes.h" +#include "parse/properties/properties.h" +#include "parse/properties/utils.h" + +/** + * Parse background-repeat + * + * \param c Parsing context + * \param vector Vector of tokens to process + * \param ctx Pointer to vector iteration context + * \param result Pointer to location to receive resulting style + * \return CSS_OK on success, + * CSS_NOMEM on memory exhaustion, + * CSS_INVALID if the input is not valid + * + * Post condition: \a *ctx is updated with the next token to process + * If the input is invalid, then \a *ctx remains unchanged. + */ +css_error parse_background_repeat(css_language *c, + const parserutils_vector *vector, int *ctx, + css_style **result) +{ + int orig_ctx = *ctx; + css_error error; + const css_token *ident; + uint8_t flags = 0; + uint16_t value = 0; + uint32_t opv; + bool match; + + /* IDENT (no-repeat, repeat-x, repeat-y, repeat, inherit) */ + ident = parserutils_vector_iterate(vector, ctx); + if (ident == NULL || ident->type != CSS_TOKEN_IDENT) { + *ctx = orig_ctx; + return CSS_INVALID; + } + + if ((lwc_string_caseless_isequal( + ident->idata, c->strings[INHERIT], + &match) == lwc_error_ok && match)) { + flags |= FLAG_INHERIT; + } else if ((lwc_string_caseless_isequal( + ident->idata, c->strings[NO_REPEAT], + &match) == lwc_error_ok && match)) { + value = BACKGROUND_REPEAT_NO_REPEAT; + } else if ((lwc_string_caseless_isequal( + ident->idata, c->strings[REPEAT_X], + &match) == lwc_error_ok && match)) { + value = BACKGROUND_REPEAT_REPEAT_X; + } else if ((lwc_string_caseless_isequal( + ident->idata, c->strings[REPEAT_Y], + &match) == lwc_error_ok && match)) { + value = BACKGROUND_REPEAT_REPEAT_Y; + } else if ((lwc_string_caseless_isequal( + ident->idata, c->strings[REPEAT], + &match) == lwc_error_ok && match)) { + value = BACKGROUND_REPEAT_REPEAT; + } else { + *ctx = orig_ctx; + return CSS_INVALID; + } + + opv = buildOPV(CSS_PROP_BACKGROUND_REPEAT, flags, value); + + /* Allocate result */ + error = css_stylesheet_style_create(c->sheet, sizeof(opv), result); + if (error != CSS_OK) { + *ctx = orig_ctx; + return error; + } + + /* Copy the bytecode to it */ + memcpy((*result)->bytecode, &opv, sizeof(opv)); + + return CSS_OK; +} diff --git a/src/parse/properties/border.c b/src/parse/properties/border.c new file mode 100644 index 0000000..b90ca66 --- /dev/null +++ b/src/parse/properties/border.c @@ -0,0 +1,109 @@ +/* + * This file is part of LibCSS. + * Licensed under the MIT License, + * http://www.opensource.org/licenses/mit-license.php + * Copyright 2009 John-Mark Bell + */ + +#include +#include + +#include "bytecode/bytecode.h" +#include "bytecode/opcodes.h" +#include "parse/properties/properties.h" +#include "parse/properties/utils.h" + +/** + * Parse border shorthand + * + * \param c Parsing context + * \param vector Vector of tokens to process + * \param ctx Pointer to vector iteration context + * \param result Pointer to location to receive resulting style + * \return CSS_OK on success, + * CSS_NOMEM on memory exhaustion, + * CSS_INVALID if the input is not valid + * + * Post condition: \a *ctx is updated with the next token to process + * If the input is invalid, then \a *ctx remains unchanged. + */ +css_error parse_border(css_language *c, + const parserutils_vector *vector, int *ctx, + css_style **result) +{ + int orig_ctx = *ctx; + css_style *top = NULL; + css_style *right = NULL; + css_style *bottom = NULL; + css_style *left = NULL; + css_style *ret = NULL; + uint32_t required_size; + css_error error; + + error = parse_border_side(c, vector, ctx, BORDER_SIDE_TOP, &top); + if (error != CSS_OK) + goto cleanup; + + *ctx = orig_ctx; + error = parse_border_side(c, vector, ctx, BORDER_SIDE_RIGHT, &right); + if (error != CSS_OK) + goto cleanup; + + *ctx = orig_ctx; + error = parse_border_side(c, vector, ctx, BORDER_SIDE_BOTTOM, &bottom); + if (error != CSS_OK) + goto cleanup; + + *ctx = orig_ctx; + error = parse_border_side(c, vector, ctx, BORDER_SIDE_LEFT, &left); + if (error != CSS_OK) + goto cleanup; + + required_size = top->length + right->length + + bottom->length + left->length; + + error = css_stylesheet_style_create(c->sheet, required_size, &ret); + if (error != CSS_OK) + goto cleanup; + + required_size = 0; + + memcpy(((uint8_t *) ret->bytecode) + required_size, + top->bytecode, top->length); + required_size += top->length; + + memcpy(((uint8_t *) ret->bytecode) + required_size, + right->bytecode, right->length); + required_size += right->length; + + memcpy(((uint8_t *) ret->bytecode) + required_size, + bottom->bytecode, bottom->length); + required_size += bottom->length; + + memcpy(((uint8_t *) ret->bytecode) + required_size, + left->bytecode, left->length); + required_size += left->length; + + assert(required_size == ret->length); + + *result = ret; + ret = NULL; + + /* Clean up after ourselves */ +cleanup: + if (top) + css_stylesheet_style_destroy(c->sheet, top, error == CSS_OK); + if (right) + css_stylesheet_style_destroy(c->sheet, right, error == CSS_OK); + if (bottom) + css_stylesheet_style_destroy(c->sheet, bottom, error == CSS_OK); + if (left) + css_stylesheet_style_destroy(c->sheet, left, error == CSS_OK); + if (ret) + css_stylesheet_style_destroy(c->sheet, ret, error == CSS_OK); + + if (error != CSS_OK) + *ctx = orig_ctx; + + return error; +} diff --git a/src/parse/properties/border_bottom.c b/src/parse/properties/border_bottom.c new file mode 100644 index 0000000..0ac1ebc --- /dev/null +++ b/src/parse/properties/border_bottom.c @@ -0,0 +1,35 @@ +/* + * This file is part of LibCSS. + * Licensed under the MIT License, + * http://www.opensource.org/licenses/mit-license.php + * Copyright 2009 John-Mark Bell + */ + +#include +#include + +#include "bytecode/bytecode.h" +#include "bytecode/opcodes.h" +#include "parse/properties/properties.h" +#include "parse/properties/utils.h" + +/** + * Parse border-bottom shorthand + * + * \param c Parsing context + * \param vector Vector of tokens to process + * \param ctx Pointer to vector iteration context + * \param result Pointer to location to receive resulting style + * \return CSS_OK on success, + * CSS_NOMEM on memory exhaustion, + * CSS_INVALID if the input is not valid + * + * Post condition: \a *ctx is updated with the next token to process + * If the input is invalid, then \a *ctx remains unchanged. + */ +css_error parse_border_bottom(css_language *c, + const parserutils_vector *vector, int *ctx, + css_style **result) +{ + return parse_border_side(c, vector, ctx, BORDER_SIDE_BOTTOM, result); +} diff --git a/src/parse/properties/border_bottom_color.c b/src/parse/properties/border_bottom_color.c new file mode 100644 index 0000000..acf417f --- /dev/null +++ b/src/parse/properties/border_bottom_color.c @@ -0,0 +1,36 @@ +/* + * This file is part of LibCSS. + * Licensed under the MIT License, + * http://www.opensource.org/licenses/mit-license.php + * Copyright 2009 John-Mark Bell + */ + +#include +#include + +#include "bytecode/bytecode.h" +#include "bytecode/opcodes.h" +#include "parse/properties/properties.h" +#include "parse/properties/utils.h" + +/** + * Parse border-bottom-color + * + * \param c Parsing context + * \param vector Vector of tokens to process + * \param ctx Pointer to vector iteration context + * \param result Pointer to location to receive resulting style + * \return CSS_OK on success, + * CSS_NOMEM on memory exhaustion, + * CSS_INVALID if the input is not valid + * + * Post condition: \a *ctx is updated with the next token to process + * If the input is invalid, then \a *ctx remains unchanged. + */ +css_error parse_border_bottom_color(css_language *c, + const parserutils_vector *vector, int *ctx, + css_style **result) +{ + return parse_border_side_color(c, vector, ctx, + CSS_PROP_BORDER_BOTTOM_COLOR, result); +} diff --git a/src/parse/properties/border_bottom_style.c b/src/parse/properties/border_bottom_style.c new file mode 100644 index 0000000..2c549fa --- /dev/null +++ b/src/parse/properties/border_bottom_style.c @@ -0,0 +1,36 @@ +/* + * This file is part of LibCSS. + * Licensed under the MIT License, + * http://www.opensource.org/licenses/mit-license.php + * Copyright 2009 John-Mark Bell + */ + +#include +#include + +#include "bytecode/bytecode.h" +#include "bytecode/opcodes.h" +#include "parse/properties/properties.h" +#include "parse/properties/utils.h" + +/** + * Parse border-bottom-style + * + * \param c Parsing context + * \param vector Vector of tokens to process + * \param ctx Pointer to vector iteration context + * \param result Pointer to location to receive resulting style + * \return CSS_OK on success, + * CSS_NOMEM on memory exhaustion, + * CSS_INVALID if the input is not valid + * + * Post condition: \a *ctx is updated with the next token to process + * If the input is invalid, then \a *ctx remains unchanged. + */ +css_error parse_border_bottom_style(css_language *c, + const parserutils_vector *vector, int *ctx, + css_style **result) +{ + return parse_border_side_style(c, vector, ctx, + CSS_PROP_BORDER_BOTTOM_STYLE, result); +} diff --git a/src/parse/properties/border_bottom_width.c b/src/parse/properties/border_bottom_width.c new file mode 100644 index 0000000..56769e8 --- /dev/null +++ b/src/parse/properties/border_bottom_width.c @@ -0,0 +1,36 @@ +/* + * This file is part of LibCSS. + * Licensed under the MIT License, + * http://www.opensource.org/licenses/mit-license.php + * Copyright 2009 John-Mark Bell + */ + +#include +#include + +#include "bytecode/bytecode.h" +#include "bytecode/opcodes.h" +#include "parse/properties/properties.h" +#include "parse/properties/utils.h" + +/** + * Parse border-bottom-width + * + * \param c Parsing context + * \param vector Vector of tokens to process + * \param ctx Pointer to vector iteration context + * \param result Pointer to location to receive resulting style + * \return CSS_OK on success, + * CSS_NOMEM on memory exhaustion, + * CSS_INVALID if the input is not valid + * + * Post condition: \a *ctx is updated with the next token to process + * If the input is invalid, then \a *ctx remains unchanged. + */ +css_error parse_border_bottom_width(css_language *c, + const parserutils_vector *vector, int *ctx, + css_style **result) +{ + return parse_border_side_width(c, vector, ctx, + CSS_PROP_BORDER_BOTTOM_WIDTH, result); +} diff --git a/src/parse/properties/border_collapse.c b/src/parse/properties/border_collapse.c new file mode 100644 index 0000000..8926010 --- /dev/null +++ b/src/parse/properties/border_collapse.c @@ -0,0 +1,79 @@ +/* + * This file is part of LibCSS. + * Licensed under the MIT License, + * http://www.opensource.org/licenses/mit-license.php + * Copyright 2009 John-Mark Bell + */ + +#include +#include + +#include "bytecode/bytecode.h" +#include "bytecode/opcodes.h" +#include "parse/properties/properties.h" +#include "parse/properties/utils.h" + +/** + * Parse border-collapse + * + * \param c Parsing context + * \param vector Vector of tokens to process + * \param ctx Pointer to vector iteration context + * \param result Pointer to location to receive resulting style + * \return CSS_OK on success, + * CSS_NOMEM on memory exhaustion, + * CSS_INVALID if the input is not valid + * + * Post condition: \a *ctx is updated with the next token to process + * If the input is invalid, then \a *ctx remains unchanged. + */ +css_error parse_border_collapse(css_language *c, + const parserutils_vector *vector, int *ctx, + css_style **result) +{ + int orig_ctx = *ctx; + css_error error; + const css_token *ident; + uint8_t flags = 0; + uint16_t value = 0; + uint32_t opv; + bool match; + + /* IDENT (collapse, separate, inherit) */ + ident = parserutils_vector_iterate(vector, ctx); + if (ident == NULL || ident->type != CSS_TOKEN_IDENT) { + *ctx = orig_ctx; + return CSS_INVALID; + } + + if ((lwc_string_caseless_isequal( + ident->idata, c->strings[INHERIT], + &match) == lwc_error_ok && match)) { + flags |= FLAG_INHERIT; + } else if ((lwc_string_caseless_isequal( + ident->idata, c->strings[COLLAPSE], + &match) == lwc_error_ok && match)) { + value = BORDER_COLLAPSE_COLLAPSE; + } else if ((lwc_string_caseless_isequal( + ident->idata, c->strings[SEPARATE], + &match) == lwc_error_ok && match)) { + value = BORDER_COLLAPSE_SEPARATE; + } else { + *ctx = orig_ctx; + return CSS_INVALID; + } + + opv = buildOPV(CSS_PROP_BORDER_COLLAPSE, flags, value); + + /* Allocate result */ + error = css_stylesheet_style_create(c->sheet, sizeof(opv), result); + if (error != CSS_OK) { + *ctx = orig_ctx; + return error; + } + + /* Copy the bytecode to it */ + memcpy((*result)->bytecode, &opv, sizeof(opv)); + + return CSS_OK; +} diff --git a/src/parse/properties/border_color.c b/src/parse/properties/border_color.c new file mode 100644 index 0000000..65f35f3 --- /dev/null +++ b/src/parse/properties/border_color.c @@ -0,0 +1,266 @@ +/* + * This file is part of LibCSS. + * Licensed under the MIT License, + * http://www.opensource.org/licenses/mit-license.php + * Copyright 2009 John-Mark Bell + */ + +#include +#include + +#include "bytecode/bytecode.h" +#include "bytecode/opcodes.h" +#include "parse/properties/properties.h" +#include "parse/properties/utils.h" + +/** + * Parse border-color shorthand + * + * \param c Parsing context + * \param vector Vector of tokens to process + * \param ctx Pointer to vector iteration context + * \param result Pointer to location to receive resulting style + * \return CSS_OK on success, + * CSS_NOMEM on memory exhaustion, + * CSS_INVALID if the input is not valid + * + * Post condition: \a *ctx is updated with the next token to process + * If the input is invalid, then \a *ctx remains unchanged. + */ +css_error parse_border_color(css_language *c, + const parserutils_vector *vector, int *ctx, + css_style **result) +{ + int orig_ctx = *ctx; + int prev_ctx; + const css_token *token; + css_style *top = NULL; + css_style *right = NULL; + css_style *bottom = NULL; + css_style *left = NULL; + css_style *ret = NULL; + uint32_t num_sides = 0; + uint32_t required_size; + bool match; + css_error error; + + /* Firstly, handle inherit */ + token = parserutils_vector_peek(vector, *ctx); + if (token != NULL && token->type == CSS_TOKEN_IDENT && + (lwc_string_caseless_isequal( + token->idata, c->strings[INHERIT], + &match) == lwc_error_ok && match)) { + uint32_t *bytecode; + + error = css_stylesheet_style_create(c->sheet, + 4 * sizeof(uint32_t), &ret); + if (error != CSS_OK) { + *ctx = orig_ctx; + return error; + } + + bytecode = (uint32_t *) ret->bytecode; + + *(bytecode++) = buildOPV(CSS_PROP_BORDER_TOP_COLOR, + FLAG_INHERIT, 0); + *(bytecode++) = buildOPV(CSS_PROP_BORDER_RIGHT_COLOR, + FLAG_INHERIT, 0); + *(bytecode++) = buildOPV(CSS_PROP_BORDER_BOTTOM_COLOR, + FLAG_INHERIT, 0); + *(bytecode++) = buildOPV(CSS_PROP_BORDER_LEFT_COLOR, + FLAG_INHERIT, 0); + + parserutils_vector_iterate(vector, ctx); + + *result = ret; + + return CSS_OK; + } else if (token == NULL) { + /* No tokens -- clearly garbage */ + *ctx = orig_ctx; + return CSS_INVALID; + } + + /* Attempt to parse up to 4 colours */ + do { + prev_ctx = *ctx; + error = CSS_OK; + + /* Ensure that we're not about to parse another inherit */ + token = parserutils_vector_peek(vector, *ctx); + if (token != NULL && token->type == CSS_TOKEN_IDENT && + (lwc_string_caseless_isequal( + token->idata, c->strings[INHERIT], + &match) == lwc_error_ok && match)) { + error = CSS_INVALID; + goto cleanup; + } + + if (top == NULL && + (error = parse_border_side_color(c, vector, + ctx, CSS_PROP_BORDER_TOP_COLOR, &top)) == + CSS_OK) { + num_sides = 1; + } else if (right == NULL && + (error = parse_border_side_color(c, vector, + ctx, CSS_PROP_BORDER_RIGHT_COLOR, &right)) == + CSS_OK) { + num_sides = 2; + } else if (bottom == NULL && + (error = parse_border_side_color(c, vector, + ctx, CSS_PROP_BORDER_BOTTOM_COLOR, &bottom)) == + CSS_OK) { + num_sides = 3; + } else if (left == NULL && + (error = parse_border_side_color(c, vector, + ctx, CSS_PROP_BORDER_LEFT_COLOR, &left)) == + CSS_OK) { + num_sides = 4; + } + + if (error == CSS_OK) { + consumeWhitespace(vector, ctx); + + token = parserutils_vector_peek(vector, *ctx); + } else { + /* Forcibly cause loop to exit */ + token = NULL; + } + } while (*ctx != prev_ctx && token != NULL); + + if (num_sides == 0) { + error = CSS_INVALID; + goto cleanup; + } + + /* Calculate size of resultant style */ + if (num_sides == 1) { + required_size = 4 * top->length; + } else if (num_sides == 2) { + required_size = 2 * top->length + 2 * right->length; + } else if (num_sides == 3) { + required_size = top->length + 2 * right->length + + bottom->length; + } else { + required_size = top->length + right->length + + bottom->length + left->length; + } + + error = css_stylesheet_style_create(c->sheet, required_size, &ret); + if (error != CSS_OK) + goto cleanup; + + required_size = 0; + + if (num_sides == 1) { + uint32_t *opv = ((uint32_t *) top->bytecode); + uint8_t flags = getFlags(*opv); + uint16_t value = getValue(*opv); + + memcpy(((uint8_t *) ret->bytecode) + required_size, + top->bytecode, top->length); + required_size += top->length; + + *opv = buildOPV(CSS_PROP_BORDER_RIGHT_COLOR, flags, value); + memcpy(((uint8_t *) ret->bytecode) + required_size, + top->bytecode, top->length); + required_size += top->length; + + *opv = buildOPV(CSS_PROP_BORDER_BOTTOM_COLOR, flags, value); + memcpy(((uint8_t *) ret->bytecode) + required_size, + top->bytecode, top->length); + required_size += top->length; + + *opv = buildOPV(CSS_PROP_BORDER_LEFT_COLOR, flags, value); + memcpy(((uint8_t *) ret->bytecode) + required_size, + top->bytecode, top->length); + required_size += top->length; + } else if (num_sides == 2) { + uint32_t *vopv = ((uint32_t *) top->bytecode); + uint32_t *hopv = ((uint32_t *) right->bytecode); + uint8_t vflags = getFlags(*vopv); + uint8_t hflags = getFlags(*hopv); + uint16_t vvalue = getValue(*vopv); + uint16_t hvalue = getValue(*hopv); + + memcpy(((uint8_t *) ret->bytecode) + required_size, + top->bytecode, top->length); + required_size += top->length; + + memcpy(((uint8_t *) ret->bytecode) + required_size, + right->bytecode, right->length); + required_size += right->length; + + *vopv = buildOPV(CSS_PROP_BORDER_BOTTOM_COLOR, vflags, vvalue); + memcpy(((uint8_t *) ret->bytecode) + required_size, + top->bytecode, top->length); + required_size += top->length; + + *hopv = buildOPV(CSS_PROP_BORDER_LEFT_COLOR, hflags, hvalue); + memcpy(((uint8_t *) ret->bytecode) + required_size, + right->bytecode, right->length); + required_size += right->length; + } else if (num_sides == 3) { + uint32_t *opv = ((uint32_t *) right->bytecode); + uint8_t flags = getFlags(*opv); + uint16_t value = getValue(*opv); + + memcpy(((uint8_t *) ret->bytecode) + required_size, + top->bytecode, top->length); + required_size += top->length; + + memcpy(((uint8_t *) ret->bytecode) + required_size, + right->bytecode, right->length); + required_size += right->length; + + memcpy(((uint8_t *) ret->bytecode) + required_size, + bottom->bytecode, bottom->length); + required_size += bottom->length; + + *opv = buildOPV(CSS_PROP_BORDER_LEFT_COLOR, flags, value); + memcpy(((uint8_t *) ret->bytecode) + required_size, + right->bytecode, right->length); + required_size += right->length; + } else { + memcpy(((uint8_t *) ret->bytecode) + required_size, + top->bytecode, top->length); + required_size += top->length; + + memcpy(((uint8_t *) ret->bytecode) + required_size, + right->bytecode, right->length); + required_size += right->length; + + memcpy(((uint8_t *) ret->bytecode) + required_size, + bottom->bytecode, bottom->length); + required_size += bottom->length; + + memcpy(((uint8_t *) ret->bytecode) + required_size, + left->bytecode, left->length); + required_size += left->length; + } + + assert(required_size == ret->length); + + /* Write the result */ + *result = ret; + /* Invalidate ret, so that cleanup doesn't destroy it */ + ret = NULL; + + /* Clean up after ourselves */ +cleanup: + if (top) + css_stylesheet_style_destroy(c->sheet, top, error == CSS_OK); + if (right) + css_stylesheet_style_destroy(c->sheet, right, error == CSS_OK); + if (bottom) + css_stylesheet_style_destroy(c->sheet, bottom, error == CSS_OK); + if (left) + css_stylesheet_style_destroy(c->sheet, left, error == CSS_OK); + if (ret) + css_stylesheet_style_destroy(c->sheet, ret, error == CSS_OK); + + if (error != CSS_OK) + *ctx = orig_ctx; + + return error; +} diff --git a/src/parse/properties/border_left.c b/src/parse/properties/border_left.c new file mode 100644 index 0000000..6c395c9 --- /dev/null +++ b/src/parse/properties/border_left.c @@ -0,0 +1,35 @@ +/* + * This file is part of LibCSS. + * Licensed under the MIT License, + * http://www.opensource.org/licenses/mit-license.php + * Copyright 2009 John-Mark Bell + */ + +#include +#include + +#include "bytecode/bytecode.h" +#include "bytecode/opcodes.h" +#include "parse/properties/properties.h" +#include "parse/properties/utils.h" + +/** + * Parse border-left shorthand + * + * \param c Parsing context + * \param vector Vector of tokens to process + * \param ctx Pointer to vector iteration context + * \param result Pointer to location to receive resulting style + * \return CSS_OK on success, + * CSS_NOMEM on memory exhaustion, + * CSS_INVALID if the input is not valid + * + * Post condition: \a *ctx is updated with the next token to process + * If the input is invalid, then \a *ctx remains unchanged. + */ +css_error parse_border_left(css_language *c, + const parserutils_vector *vector, int *ctx, + css_style **result) +{ + return parse_border_side(c, vector, ctx, BORDER_SIDE_LEFT, result); +} diff --git a/src/parse/properties/border_left_color.c b/src/parse/properties/border_left_color.c new file mode 100644 index 0000000..79cf187 --- /dev/null +++ b/src/parse/properties/border_left_color.c @@ -0,0 +1,36 @@ +/* + * This file is part of LibCSS. + * Licensed under the MIT License, + * http://www.opensource.org/licenses/mit-license.php + * Copyright 2009 John-Mark Bell + */ + +#include +#include + +#include "bytecode/bytecode.h" +#include "bytecode/opcodes.h" +#include "parse/properties/properties.h" +#include "parse/properties/utils.h" + +/** + * Parse border-left-color + * + * \param c Parsing context + * \param vector Vector of tokens to process + * \param ctx Pointer to vector iteration context + * \param result Pointer to location to receive resulting style + * \return CSS_OK on success, + * CSS_NOMEM on memory exhaustion, + * CSS_INVALID if the input is not valid + * + * Post condition: \a *ctx is updated with the next token to process + * If the input is invalid, then \a *ctx remains unchanged. + */ +css_error parse_border_left_color(css_language *c, + const parserutils_vector *vector, int *ctx, + css_style **result) +{ + return parse_border_side_color(c, vector, ctx, + CSS_PROP_BORDER_LEFT_COLOR, result); +} diff --git a/src/parse/properties/border_left_style.c b/src/parse/properties/border_left_style.c new file mode 100644 index 0000000..d1e31c4 --- /dev/null +++ b/src/parse/properties/border_left_style.c @@ -0,0 +1,36 @@ +/* + * This file is part of LibCSS. + * Licensed under the MIT License, + * http://www.opensource.org/licenses/mit-license.php + * Copyright 2009 John-Mark Bell + */ + +#include +#include + +#include "bytecode/bytecode.h" +#include "bytecode/opcodes.h" +#include "parse/properties/properties.h" +#include "parse/properties/utils.h" + +/** + * Parse border-left-style + * + * \param c Parsing context + * \param vector Vector of tokens to process + * \param ctx Pointer to vector iteration context + * \param result Pointer to location to receive resulting style + * \return CSS_OK on success, + * CSS_NOMEM on memory exhaustion, + * CSS_INVALID if the input is not valid + * + * Post condition: \a *ctx is updated with the next token to process + * If the input is invalid, then \a *ctx remains unchanged. + */ +css_error parse_border_left_style(css_language *c, + const parserutils_vector *vector, int *ctx, + css_style **result) +{ + return parse_border_side_style(c, vector, ctx, + CSS_PROP_BORDER_LEFT_STYLE, result); +} diff --git a/src/parse/properties/border_left_width.c b/src/parse/properties/border_left_width.c new file mode 100644 index 0000000..6a78bb6 --- /dev/null +++ b/src/parse/properties/border_left_width.c @@ -0,0 +1,36 @@ +/* + * This file is part of LibCSS. + * Licensed under the MIT License, + * http://www.opensource.org/licenses/mit-license.php + * Copyright 2009 John-Mark Bell + */ + +#include +#include + +#include "bytecode/bytecode.h" +#include "bytecode/opcodes.h" +#include "parse/properties/properties.h" +#include "parse/properties/utils.h" + +/** + * Parse border-left-width + * + * \param c Parsing context + * \param vector Vector of tokens to process + * \param ctx Pointer to vector iteration context + * \param result Pointer to location to receive resulting style + * \return CSS_OK on success, + * CSS_NOMEM on memory exhaustion, + * CSS_INVALID if the input is not valid + * + * Post condition: \a *ctx is updated with the next token to process + * If the input is invalid, then \a *ctx remains unchanged. + */ +css_error parse_border_left_width(css_language *c, + const parserutils_vector *vector, int *ctx, + css_style **result) +{ + return parse_border_side_width(c, vector, ctx, + CSS_PROP_BORDER_LEFT_WIDTH, result); +} diff --git a/src/parse/properties/border_outline.c b/src/parse/properties/border_outline.c deleted file mode 100644 index 02d85a7..0000000 --- a/src/parse/properties/border_outline.c +++ /dev/null @@ -1,2221 +0,0 @@ -/* - * This file is part of LibCSS. - * Licensed under the MIT License, - * http://www.opensource.org/licenses/mit-license.php - * Copyright 2009 John-Mark Bell - */ - -#include -#include - -#include "bytecode/bytecode.h" -#include "bytecode/opcodes.h" -#include "parse/properties/properties.h" -#include "parse/properties/utils.h" - -enum { SIDE_TOP = 0, SIDE_RIGHT = 1, SIDE_BOTTOM = 2, SIDE_LEFT = 3 }; - -static css_error parse_border_side(css_language *c, - const parserutils_vector *vector, int *ctx, - uint32_t side, css_style **result); -static css_error parse_border_side_color(css_language *c, - const parserutils_vector *vector, int *ctx, - uint16_t op, css_style **result); -static css_error parse_border_side_style(css_language *c, - const parserutils_vector *vector, int *ctx, - uint16_t op, css_style **result); -static css_error parse_border_side_width(css_language *c, - const parserutils_vector *vector, int *ctx, - uint16_t op, css_style **result); - -/** - * Parse border shorthand - * - * \param c Parsing context - * \param vector Vector of tokens to process - * \param ctx Pointer to vector iteration context - * \param result Pointer to location to receive resulting style - * \return CSS_OK on success, - * CSS_NOMEM on memory exhaustion, - * CSS_INVALID if the input is not valid - * - * Post condition: \a *ctx is updated with the next token to process - * If the input is invalid, then \a *ctx remains unchanged. - */ -css_error parse_border(css_language *c, - const parserutils_vector *vector, int *ctx, - css_style **result) -{ - int orig_ctx = *ctx; - css_style *top = NULL; - css_style *right = NULL; - css_style *bottom = NULL; - css_style *left = NULL; - css_style *ret = NULL; - uint32_t required_size; - css_error error; - - error = parse_border_side(c, vector, ctx, SIDE_TOP, &top); - if (error != CSS_OK) - goto cleanup; - - *ctx = orig_ctx; - error = parse_border_side(c, vector, ctx, SIDE_RIGHT, &right); - if (error != CSS_OK) - goto cleanup; - - *ctx = orig_ctx; - error = parse_border_side(c, vector, ctx, SIDE_BOTTOM, &bottom); - if (error != CSS_OK) - goto cleanup; - - *ctx = orig_ctx; - error = parse_border_side(c, vector, ctx, SIDE_LEFT, &left); - if (error != CSS_OK) - goto cleanup; - - required_size = top->length + right->length + - bottom->length + left->length; - - error = css_stylesheet_style_create(c->sheet, required_size, &ret); - if (error != CSS_OK) - goto cleanup; - - required_size = 0; - - memcpy(((uint8_t *) ret->bytecode) + required_size, - top->bytecode, top->length); - required_size += top->length; - - memcpy(((uint8_t *) ret->bytecode) + required_size, - right->bytecode, right->length); - required_size += right->length; - - memcpy(((uint8_t *) ret->bytecode) + required_size, - bottom->bytecode, bottom->length); - required_size += bottom->length; - - memcpy(((uint8_t *) ret->bytecode) + required_size, - left->bytecode, left->length); - required_size += left->length; - - assert(required_size == ret->length); - - *result = ret; - ret = NULL; - - /* Clean up after ourselves */ -cleanup: - if (top) - css_stylesheet_style_destroy(c->sheet, top, error == CSS_OK); - if (right) - css_stylesheet_style_destroy(c->sheet, right, error == CSS_OK); - if (bottom) - css_stylesheet_style_destroy(c->sheet, bottom, error == CSS_OK); - if (left) - css_stylesheet_style_destroy(c->sheet, left, error == CSS_OK); - if (ret) - css_stylesheet_style_destroy(c->sheet, ret, error == CSS_OK); - - if (error != CSS_OK) - *ctx = orig_ctx; - - return error; -} - -/** - * Parse border-bottom shorthand - * - * \param c Parsing context - * \param vector Vector of tokens to process - * \param ctx Pointer to vector iteration context - * \param result Pointer to location to receive resulting style - * \return CSS_OK on success, - * CSS_NOMEM on memory exhaustion, - * CSS_INVALID if the input is not valid - * - * Post condition: \a *ctx is updated with the next token to process - * If the input is invalid, then \a *ctx remains unchanged. - */ -css_error parse_border_bottom(css_language *c, - const parserutils_vector *vector, int *ctx, - css_style **result) -{ - return parse_border_side(c, vector, ctx, SIDE_BOTTOM, result); -} - -/** - * Parse border-bottom-color - * - * \param c Parsing context - * \param vector Vector of tokens to process - * \param ctx Pointer to vector iteration context - * \param result Pointer to location to receive resulting style - * \return CSS_OK on success, - * CSS_NOMEM on memory exhaustion, - * CSS_INVALID if the input is not valid - * - * Post condition: \a *ctx is updated with the next token to process - * If the input is invalid, then \a *ctx remains unchanged. - */ -css_error parse_border_bottom_color(css_language *c, - const parserutils_vector *vector, int *ctx, - css_style **result) -{ - return parse_border_side_color(c, vector, ctx, - CSS_PROP_BORDER_BOTTOM_COLOR, result); -} - -/** - * Parse border-bottom-style - * - * \param c Parsing context - * \param vector Vector of tokens to process - * \param ctx Pointer to vector iteration context - * \param result Pointer to location to receive resulting style - * \return CSS_OK on success, - * CSS_NOMEM on memory exhaustion, - * CSS_INVALID if the input is not valid - * - * Post condition: \a *ctx is updated with the next token to process - * If the input is invalid, then \a *ctx remains unchanged. - */ -css_error parse_border_bottom_style(css_language *c, - const parserutils_vector *vector, int *ctx, - css_style **result) -{ - return parse_border_side_style(c, vector, ctx, - CSS_PROP_BORDER_BOTTOM_STYLE, result); -} - -/** - * Parse border-bottom-width - * - * \param c Parsing context - * \param vector Vector of tokens to process - * \param ctx Pointer to vector iteration context - * \param result Pointer to location to receive resulting style - * \return CSS_OK on success, - * CSS_NOMEM on memory exhaustion, - * CSS_INVALID if the input is not valid - * - * Post condition: \a *ctx is updated with the next token to process - * If the input is invalid, then \a *ctx remains unchanged. - */ -css_error parse_border_bottom_width(css_language *c, - const parserutils_vector *vector, int *ctx, - css_style **result) -{ - return parse_border_side_width(c, vector, ctx, - CSS_PROP_BORDER_BOTTOM_WIDTH, result); -} - -/** - * Parse border-collapse - * - * \param c Parsing context - * \param vector Vector of tokens to process - * \param ctx Pointer to vector iteration context - * \param result Pointer to location to receive resulting style - * \return CSS_OK on success, - * CSS_NOMEM on memory exhaustion, - * CSS_INVALID if the input is not valid - * - * Post condition: \a *ctx is updated with the next token to process - * If the input is invalid, then \a *ctx remains unchanged. - */ -css_error parse_border_collapse(css_language *c, - const parserutils_vector *vector, int *ctx, - css_style **result) -{ - int orig_ctx = *ctx; - css_error error; - const css_token *ident; - uint8_t flags = 0; - uint16_t value = 0; - uint32_t opv; - bool match; - - /* IDENT (collapse, separate, inherit) */ - ident = parserutils_vector_iterate(vector, ctx); - if (ident == NULL || ident->type != CSS_TOKEN_IDENT) { - *ctx = orig_ctx; - return CSS_INVALID; - } - - if ((lwc_string_caseless_isequal( - ident->idata, c->strings[INHERIT], - &match) == lwc_error_ok && match)) { - flags |= FLAG_INHERIT; - } else if ((lwc_string_caseless_isequal( - ident->idata, c->strings[COLLAPSE], - &match) == lwc_error_ok && match)) { - value = BORDER_COLLAPSE_COLLAPSE; - } else if ((lwc_string_caseless_isequal( - ident->idata, c->strings[SEPARATE], - &match) == lwc_error_ok && match)) { - value = BORDER_COLLAPSE_SEPARATE; - } else { - *ctx = orig_ctx; - return CSS_INVALID; - } - - opv = buildOPV(CSS_PROP_BORDER_COLLAPSE, flags, value); - - /* Allocate result */ - error = css_stylesheet_style_create(c->sheet, sizeof(opv), result); - if (error != CSS_OK) { - *ctx = orig_ctx; - return error; - } - - /* Copy the bytecode to it */ - memcpy((*result)->bytecode, &opv, sizeof(opv)); - - return CSS_OK; -} - -/** - * Parse border-color shorthand - * - * \param c Parsing context - * \param vector Vector of tokens to process - * \param ctx Pointer to vector iteration context - * \param result Pointer to location to receive resulting style - * \return CSS_OK on success, - * CSS_NOMEM on memory exhaustion, - * CSS_INVALID if the input is not valid - * - * Post condition: \a *ctx is updated with the next token to process - * If the input is invalid, then \a *ctx remains unchanged. - */ -css_error parse_border_color(css_language *c, - const parserutils_vector *vector, int *ctx, - css_style **result) -{ - int orig_ctx = *ctx; - int prev_ctx; - const css_token *token; - css_style *top = NULL; - css_style *right = NULL; - css_style *bottom = NULL; - css_style *left = NULL; - css_style *ret = NULL; - uint32_t num_sides = 0; - uint32_t required_size; - bool match; - css_error error; - - /* Firstly, handle inherit */ - token = parserutils_vector_peek(vector, *ctx); - if (token != NULL && token->type == CSS_TOKEN_IDENT && - (lwc_string_caseless_isequal( - token->idata, c->strings[INHERIT], - &match) == lwc_error_ok && match)) { - uint32_t *bytecode; - - error = css_stylesheet_style_create(c->sheet, - 4 * sizeof(uint32_t), &ret); - if (error != CSS_OK) { - *ctx = orig_ctx; - return error; - } - - bytecode = (uint32_t *) ret->bytecode; - - *(bytecode++) = buildOPV(CSS_PROP_BORDER_TOP_COLOR, - FLAG_INHERIT, 0); - *(bytecode++) = buildOPV(CSS_PROP_BORDER_RIGHT_COLOR, - FLAG_INHERIT, 0); - *(bytecode++) = buildOPV(CSS_PROP_BORDER_BOTTOM_COLOR, - FLAG_INHERIT, 0); - *(bytecode++) = buildOPV(CSS_PROP_BORDER_LEFT_COLOR, - FLAG_INHERIT, 0); - - parserutils_vector_iterate(vector, ctx); - - *result = ret; - - return CSS_OK; - } else if (token == NULL) { - /* No tokens -- clearly garbage */ - *ctx = orig_ctx; - return CSS_INVALID; - } - - /* Attempt to parse up to 4 colours */ - do { - prev_ctx = *ctx; - error = CSS_OK; - - /* Ensure that we're not about to parse another inherit */ - token = parserutils_vector_peek(vector, *ctx); - if (token != NULL && token->type == CSS_TOKEN_IDENT && - (lwc_string_caseless_isequal( - token->idata, c->strings[INHERIT], - &match) == lwc_error_ok && match)) { - error = CSS_INVALID; - goto cleanup; - } - - if (top == NULL && - (error = parse_border_side_color(c, vector, - ctx, CSS_PROP_BORDER_TOP_COLOR, &top)) == - CSS_OK) { - num_sides = 1; - } else if (right == NULL && - (error = parse_border_side_color(c, vector, - ctx, CSS_PROP_BORDER_RIGHT_COLOR, &right)) == - CSS_OK) { - num_sides = 2; - } else if (bottom == NULL && - (error = parse_border_side_color(c, vector, - ctx, CSS_PROP_BORDER_BOTTOM_COLOR, &bottom)) == - CSS_OK) { - num_sides = 3; - } else if (left == NULL && - (error = parse_border_side_color(c, vector, - ctx, CSS_PROP_BORDER_LEFT_COLOR, &left)) == - CSS_OK) { - num_sides = 4; - } - - if (error == CSS_OK) { - consumeWhitespace(vector, ctx); - - token = parserutils_vector_peek(vector, *ctx); - } else { - /* Forcibly cause loop to exit */ - token = NULL; - } - } while (*ctx != prev_ctx && token != NULL); - - if (num_sides == 0) { - error = CSS_INVALID; - goto cleanup; - } - - /* Calculate size of resultant style */ - if (num_sides == 1) { - required_size = 4 * top->length; - } else if (num_sides == 2) { - required_size = 2 * top->length + 2 * right->length; - } else if (num_sides == 3) { - required_size = top->length + 2 * right->length + - bottom->length; - } else { - required_size = top->length + right->length + - bottom->length + left->length; - } - - error = css_stylesheet_style_create(c->sheet, required_size, &ret); - if (error != CSS_OK) - goto cleanup; - - required_size = 0; - - if (num_sides == 1) { - uint32_t *opv = ((uint32_t *) top->bytecode); - uint8_t flags = getFlags(*opv); - uint16_t value = getValue(*opv); - - memcpy(((uint8_t *) ret->bytecode) + required_size, - top->bytecode, top->length); - required_size += top->length; - - *opv = buildOPV(CSS_PROP_BORDER_RIGHT_COLOR, flags, value); - memcpy(((uint8_t *) ret->bytecode) + required_size, - top->bytecode, top->length); - required_size += top->length; - - *opv = buildOPV(CSS_PROP_BORDER_BOTTOM_COLOR, flags, value); - memcpy(((uint8_t *) ret->bytecode) + required_size, - top->bytecode, top->length); - required_size += top->length; - - *opv = buildOPV(CSS_PROP_BORDER_LEFT_COLOR, flags, value); - memcpy(((uint8_t *) ret->bytecode) + required_size, - top->bytecode, top->length); - required_size += top->length; - } else if (num_sides == 2) { - uint32_t *vopv = ((uint32_t *) top->bytecode); - uint32_t *hopv = ((uint32_t *) right->bytecode); - uint8_t vflags = getFlags(*vopv); - uint8_t hflags = getFlags(*hopv); - uint16_t vvalue = getValue(*vopv); - uint16_t hvalue = getValue(*hopv); - - memcpy(((uint8_t *) ret->bytecode) + required_size, - top->bytecode, top->length); - required_size += top->length; - - memcpy(((uint8_t *) ret->bytecode) + required_size, - right->bytecode, right->length); - required_size += right->length; - - *vopv = buildOPV(CSS_PROP_BORDER_BOTTOM_COLOR, vflags, vvalue); - memcpy(((uint8_t *) ret->bytecode) + required_size, - top->bytecode, top->length); - required_size += top->length; - - *hopv = buildOPV(CSS_PROP_BORDER_LEFT_COLOR, hflags, hvalue); - memcpy(((uint8_t *) ret->bytecode) + required_size, - right->bytecode, right->length); - required_size += right->length; - } else if (num_sides == 3) { - uint32_t *opv = ((uint32_t *) right->bytecode); - uint8_t flags = getFlags(*opv); - uint16_t value = getValue(*opv); - - memcpy(((uint8_t *) ret->bytecode) + required_size, - top->bytecode, top->length); - required_size += top->length; - - memcpy(((uint8_t *) ret->bytecode) + required_size, - right->bytecode, right->length); - required_size += right->length; - - memcpy(((uint8_t *) ret->bytecode) + required_size, - bottom->bytecode, bottom->length); - required_size += bottom->length; - - *opv = buildOPV(CSS_PROP_BORDER_LEFT_COLOR, flags, value); - memcpy(((uint8_t *) ret->bytecode) + required_size, - right->bytecode, right->length); - required_size += right->length; - } else { - memcpy(((uint8_t *) ret->bytecode) + required_size, - top->bytecode, top->length); - required_size += top->length; - - memcpy(((uint8_t *) ret->bytecode) + required_size, - right->bytecode, right->length); - required_size += right->length; - - memcpy(((uint8_t *) ret->bytecode) + required_size, - bottom->bytecode, bottom->length); - required_size += bottom->length; - - memcpy(((uint8_t *) ret->bytecode) + required_size, - left->bytecode, left->length); - required_size += left->length; - } - - assert(required_size == ret->length); - - /* Write the result */ - *result = ret; - /* Invalidate ret, so that cleanup doesn't destroy it */ - ret = NULL; - - /* Clean up after ourselves */ -cleanup: - if (top) - css_stylesheet_style_destroy(c->sheet, top, error == CSS_OK); - if (right) - css_stylesheet_style_destroy(c->sheet, right, error == CSS_OK); - if (bottom) - css_stylesheet_style_destroy(c->sheet, bottom, error == CSS_OK); - if (left) - css_stylesheet_style_destroy(c->sheet, left, error == CSS_OK); - if (ret) - css_stylesheet_style_destroy(c->sheet, ret, error == CSS_OK); - - if (error != CSS_OK) - *ctx = orig_ctx; - - return error; -} - -/** - * Parse border-left shorthand - * - * \param c Parsing context - * \param vector Vector of tokens to process - * \param ctx Pointer to vector iteration context - * \param result Pointer to location to receive resulting style - * \return CSS_OK on success, - * CSS_NOMEM on memory exhaustion, - * CSS_INVALID if the input is not valid - * - * Post condition: \a *ctx is updated with the next token to process - * If the input is invalid, then \a *ctx remains unchanged. - */ -css_error parse_border_left(css_language *c, - const parserutils_vector *vector, int *ctx, - css_style **result) -{ - return parse_border_side(c, vector, ctx, SIDE_LEFT, result); -} - -/** - * Parse border-left-color - * - * \param c Parsing context - * \param vector Vector of tokens to process - * \param ctx Pointer to vector iteration context - * \param result Pointer to location to receive resulting style - * \return CSS_OK on success, - * CSS_NOMEM on memory exhaustion, - * CSS_INVALID if the input is not valid - * - * Post condition: \a *ctx is updated with the next token to process - * If the input is invalid, then \a *ctx remains unchanged. - */ -css_error parse_border_left_color(css_language *c, - const parserutils_vector *vector, int *ctx, - css_style **result) -{ - return parse_border_side_color(c, vector, ctx, - CSS_PROP_BORDER_LEFT_COLOR, result); -} - -/** - * Parse border-left-style - * - * \param c Parsing context - * \param vector Vector of tokens to process - * \param ctx Pointer to vector iteration context - * \param result Pointer to location to receive resulting style - * \return CSS_OK on success, - * CSS_NOMEM on memory exhaustion, - * CSS_INVALID if the input is not valid - * - * Post condition: \a *ctx is updated with the next token to process - * If the input is invalid, then \a *ctx remains unchanged. - */ -css_error parse_border_left_style(css_language *c, - const parserutils_vector *vector, int *ctx, - css_style **result) -{ - return parse_border_side_style(c, vector, ctx, - CSS_PROP_BORDER_LEFT_STYLE, result); -} - -/** - * Parse border-left-width - * - * \param c Parsing context - * \param vector Vector of tokens to process - * \param ctx Pointer to vector iteration context - * \param result Pointer to location to receive resulting style - * \return CSS_OK on success, - * CSS_NOMEM on memory exhaustion, - * CSS_INVALID if the input is not valid - * - * Post condition: \a *ctx is updated with the next token to process - * If the input is invalid, then \a *ctx remains unchanged. - */ -css_error parse_border_left_width(css_language *c, - const parserutils_vector *vector, int *ctx, - css_style **result) -{ - return parse_border_side_width(c, vector, ctx, - CSS_PROP_BORDER_LEFT_WIDTH, result); -} - -/** - * Parse border-right shorthand - * - * \param c Parsing context - * \param vector Vector of tokens to process - * \param ctx Pointer to vector iteration context - * \param result Pointer to location to receive resulting style - * \return CSS_OK on success, - * CSS_NOMEM on memory exhaustion, - * CSS_INVALID if the input is not valid - * - * Post condition: \a *ctx is updated with the next token to process - * If the input is invalid, then \a *ctx remains unchanged. - */ -css_error parse_border_right(css_language *c, - const parserutils_vector *vector, int *ctx, - css_style **result) -{ - return parse_border_side(c, vector, ctx, SIDE_RIGHT, result); -} - -/** - * Parse border-right-color - * - * \param c Parsing context - * \param vector Vector of tokens to process - * \param ctx Pointer to vector iteration context - * \param result Pointer to location to receive resulting style - * \return CSS_OK on success, - * CSS_NOMEM on memory exhaustion, - * CSS_INVALID if the input is not valid - * - * Post condition: \a *ctx is updated with the next token to process - * If the input is invalid, then \a *ctx remains unchanged. - */ -css_error parse_border_right_color(css_language *c, - const parserutils_vector *vector, int *ctx, - css_style **result) -{ - return parse_border_side_color(c, vector, ctx, - CSS_PROP_BORDER_RIGHT_COLOR, result); -} - -/** - * Parse border-right-style - * - * \param c Parsing context - * \param vector Vector of tokens to process - * \param ctx Pointer to vector iteration context - * \param result Pointer to location to receive resulting style - * \return CSS_OK on success, - * CSS_NOMEM on memory exhaustion, - * CSS_INVALID if the input is not valid - * - * Post condition: \a *ctx is updated with the next token to process - * If the input is invalid, then \a *ctx remains unchanged. - */ -css_error parse_border_right_style(css_language *c, - const parserutils_vector *vector, int *ctx, - css_style **result) -{ - return parse_border_side_style(c, vector, ctx, - CSS_PROP_BORDER_RIGHT_STYLE, result); -} - -/** - * Parse border-right-width - * - * \param c Parsing context - * \param vector Vector of tokens to process - * \param ctx Pointer to vector iteration context - * \param result Pointer to location to receive resulting style - * \return CSS_OK on success, - * CSS_NOMEM on memory exhaustion, - * CSS_INVALID if the input is not valid - * - * Post condition: \a *ctx is updated with the next token to process - * If the input is invalid, then \a *ctx remains unchanged. - */ -css_error parse_border_right_width(css_language *c, - const parserutils_vector *vector, int *ctx, - css_style **result) -{ - return parse_border_side_width(c, vector, ctx, - CSS_PROP_BORDER_RIGHT_WIDTH, result); -} - -/** - * Parse border-spacing - * - * \param c Parsing context - * \param vector Vector of tokens to process - * \param ctx Pointer to vector iteration context - * \param result Pointer to location to receive resulting style - * \return CSS_OK on success, - * CSS_NOMEM on memory exhaustion, - * CSS_INVALID if the input is not valid - * - * Post condition: \a *ctx is updated with the next token to process - * If the input is invalid, then \a *ctx remains unchanged. - */ -css_error parse_border_spacing(css_language *c, - const parserutils_vector *vector, int *ctx, - css_style **result) -{ - int orig_ctx = *ctx; - css_error error; - const css_token *token; - uint8_t flags = 0; - uint16_t value = 0; - uint32_t opv; - css_fixed length[2] = { 0 }; - uint32_t unit[2] = { 0 }; - uint32_t required_size; - bool match; - - /* length length? | IDENT(inherit) */ - token = parserutils_vector_peek(vector, *ctx); - if (token == NULL) { - *ctx = orig_ctx; - return CSS_INVALID; - } - - if (token->type == CSS_TOKEN_IDENT && - (lwc_string_caseless_isequal( - token->idata, c->strings[INHERIT], - &match) == lwc_error_ok && match)) { - parserutils_vector_iterate(vector, ctx); - flags = FLAG_INHERIT; - } else { - int num_lengths = 0; - - error = parse_unit_specifier(c, vector, ctx, UNIT_PX, - &length[0], &unit[0]); - if (error != CSS_OK) { - *ctx = orig_ctx; - return error; - } - - if (unit[0] & UNIT_ANGLE || unit[0] & UNIT_TIME || - unit[0] & UNIT_FREQ || unit[0] & UNIT_PCT) { - *ctx = orig_ctx; - return CSS_INVALID; - } - - num_lengths = 1; - - consumeWhitespace(vector, ctx); - - token = parserutils_vector_peek(vector, *ctx); - if (token != NULL) { - /* Attempt second length, ignoring errors. - * The core !important parser will ensure - * any remaining junk is thrown out. - * Ctx will be preserved on error, as usual - */ - error = parse_unit_specifier(c, vector, ctx, UNIT_PX, - &length[1], &unit[1]); - if (error == CSS_OK) { - if (unit[1] & UNIT_ANGLE || - unit[1] & UNIT_TIME || - unit[1] & UNIT_FREQ || - unit[1] & UNIT_PCT) { - *ctx = orig_ctx; - return CSS_INVALID; - } - - num_lengths = 2; - } - } - - if (num_lengths == 1) { - /* Only one length specified. Use for both axes. */ - length[1] = length[0]; - unit[1] = unit[0]; - } - - /* Lengths must not be negative */ - if (length[0] < 0 || length[1] < 0) { - *ctx = orig_ctx; - return CSS_INVALID; - } - - value = BORDER_SPACING_SET; - } - - opv = buildOPV(CSS_PROP_BORDER_SPACING, flags, value); - - required_size = sizeof(opv); - if ((flags & FLAG_INHERIT) == false && value == BORDER_SPACING_SET) - required_size += 2 * (sizeof(length[0]) + sizeof(unit[0])); - - /* Allocate result */ - error = css_stylesheet_style_create(c->sheet, required_size, result); - if (error != CSS_OK) { - *ctx = orig_ctx; - return error; - } - - /* Copy the bytecode to it */ - memcpy((*result)->bytecode, &opv, sizeof(opv)); - if ((flags & FLAG_INHERIT) == false && value == BORDER_SPACING_SET) { - uint8_t *ptr = ((uint8_t *) (*result)->bytecode) + sizeof(opv); - - memcpy(ptr, &length[0], sizeof(length[0])); - ptr += sizeof(length[0]); - memcpy(ptr, &unit[0], sizeof(unit[0])); - ptr += sizeof(unit[0]); - memcpy(ptr, &length[1], sizeof(length[1])); - ptr += sizeof(length[1]); - memcpy(ptr, &unit[1], sizeof(unit[1])); - } - - return CSS_OK; -} - -/** - * Parse border-style shorthand - * - * \param c Parsing context - * \param vector Vector of tokens to process - * \param ctx Pointer to vector iteration context - * \param result Pointer to location to receive resulting style - * \return CSS_OK on success, - * CSS_NOMEM on memory exhaustion, - * CSS_INVALID if the input is not valid - * - * Post condition: \a *ctx is updated with the next token to process - * If the input is invalid, then \a *ctx remains unchanged. - */ -css_error parse_border_style(css_language *c, - const parserutils_vector *vector, int *ctx, - css_style **result) -{ - int orig_ctx = *ctx; - int prev_ctx; - const css_token *token; - css_style *top = NULL; - css_style *right = NULL; - css_style *bottom = NULL; - css_style *left = NULL; - css_style *ret = NULL; - uint32_t num_sides = 0; - uint32_t required_size; - bool match; - css_error error; - - /* Firstly, handle inherit */ - token = parserutils_vector_peek(vector, *ctx); - if (token != NULL && token->type == CSS_TOKEN_IDENT && - (lwc_string_caseless_isequal( - token->idata, c->strings[INHERIT], - &match) == lwc_error_ok && match)) { - uint32_t *bytecode; - - error = css_stylesheet_style_create(c->sheet, - 4 * sizeof(uint32_t), &ret); - if (error != CSS_OK) { - *ctx = orig_ctx; - return error; - } - - bytecode = (uint32_t *) ret->bytecode; - - *(bytecode++) = buildOPV(CSS_PROP_BORDER_TOP_STYLE, - FLAG_INHERIT, 0); - *(bytecode++) = buildOPV(CSS_PROP_BORDER_RIGHT_STYLE, - FLAG_INHERIT, 0); - *(bytecode++) = buildOPV(CSS_PROP_BORDER_BOTTOM_STYLE, - FLAG_INHERIT, 0); - *(bytecode++) = buildOPV(CSS_PROP_BORDER_LEFT_STYLE, - FLAG_INHERIT, 0); - - parserutils_vector_iterate(vector, ctx); - - *result = ret; - - return CSS_OK; - } else if (token == NULL) { - /* No tokens -- clearly garbage */ - *ctx = orig_ctx; - return CSS_INVALID; - } - - /* Attempt to parse up to 4 styles */ - do { - prev_ctx = *ctx; - error = CSS_OK; - - /* Ensure that we're not about to parse another inherit */ - token = parserutils_vector_peek(vector, *ctx); - if (token != NULL && token->type == CSS_TOKEN_IDENT && - (lwc_string_caseless_isequal( - token->idata, c->strings[INHERIT], - &match) == lwc_error_ok && match)) { - error = CSS_INVALID; - goto cleanup; - } - - if (top == NULL && - (error = parse_border_side_style(c, vector, - ctx, CSS_PROP_BORDER_TOP_STYLE, &top)) == - CSS_OK) { - num_sides = 1; - } else if (right == NULL && - (error = parse_border_side_style(c, vector, - ctx, CSS_PROP_BORDER_RIGHT_STYLE, &right)) == - CSS_OK) { - num_sides = 2; - } else if (bottom == NULL && - (error = parse_border_side_style(c, vector, - ctx, CSS_PROP_BORDER_BOTTOM_STYLE, &bottom)) == - CSS_OK) { - num_sides = 3; - } else if (left == NULL && - (error = parse_border_side_style(c, vector, - ctx, CSS_PROP_BORDER_LEFT_STYLE, &left)) == - CSS_OK) { - num_sides = 4; - } - - if (error == CSS_OK) { - consumeWhitespace(vector, ctx); - - token = parserutils_vector_peek(vector, *ctx); - } else { - /* Forcibly cause loop to exit */ - token = NULL; - } - } while (*ctx != prev_ctx && token != NULL); - - if (num_sides == 0) { - error = CSS_INVALID; - goto cleanup; - } - - /* Calculate size of resultant style */ - if (num_sides == 1) { - required_size = 4 * top->length; - } else if (num_sides == 2) { - required_size = 2 * top->length + 2 * right->length; - } else if (num_sides == 3) { - required_size = top->length + 2 * right->length + - bottom->length; - } else { - required_size = top->length + right->length + - bottom->length + left->length; - } - - error = css_stylesheet_style_create(c->sheet, required_size, &ret); - if (error != CSS_OK) - goto cleanup; - - required_size = 0; - - if (num_sides == 1) { - uint32_t *opv = ((uint32_t *) top->bytecode); - uint8_t flags = getFlags(*opv); - uint16_t value = getValue(*opv); - - memcpy(((uint8_t *) ret->bytecode) + required_size, - top->bytecode, top->length); - required_size += top->length; - - *opv = buildOPV(CSS_PROP_BORDER_RIGHT_STYLE, flags, value); - memcpy(((uint8_t *) ret->bytecode) + required_size, - top->bytecode, top->length); - required_size += top->length; - - *opv = buildOPV(CSS_PROP_BORDER_BOTTOM_STYLE, flags, value); - memcpy(((uint8_t *) ret->bytecode) + required_size, - top->bytecode, top->length); - required_size += top->length; - - *opv = buildOPV(CSS_PROP_BORDER_LEFT_STYLE, flags, value); - memcpy(((uint8_t *) ret->bytecode) + required_size, - top->bytecode, top->length); - required_size += top->length; - } else if (num_sides == 2) { - uint32_t *vopv = ((uint32_t *) top->bytecode); - uint32_t *hopv = ((uint32_t *) right->bytecode); - uint8_t vflags = getFlags(*vopv); - uint8_t hflags = getFlags(*hopv); - uint16_t vvalue = getValue(*vopv); - uint16_t hvalue = getValue(*hopv); - - memcpy(((uint8_t *) ret->bytecode) + required_size, - top->bytecode, top->length); - required_size += top->length; - - memcpy(((uint8_t *) ret->bytecode) + required_size, - right->bytecode, right->length); - required_size += right->length; - - *vopv = buildOPV(CSS_PROP_BORDER_BOTTOM_STYLE, vflags, vvalue); - memcpy(((uint8_t *) ret->bytecode) + required_size, - top->bytecode, top->length); - required_size += top->length; - - *hopv = buildOPV(CSS_PROP_BORDER_LEFT_STYLE, hflags, hvalue); - memcpy(((uint8_t *) ret->bytecode) + required_size, - right->bytecode, right->length); - required_size += right->length; - } else if (num_sides == 3) { - uint32_t *opv = ((uint32_t *) right->bytecode); - uint8_t flags = getFlags(*opv); - uint16_t value = getValue(*opv); - - memcpy(((uint8_t *) ret->bytecode) + required_size, - top->bytecode, top->length); - required_size += top->length; - - memcpy(((uint8_t *) ret->bytecode) + required_size, - right->bytecode, right->length); - required_size += right->length; - - memcpy(((uint8_t *) ret->bytecode) + required_size, - bottom->bytecode, bottom->length); - required_size += bottom->length; - - *opv = buildOPV(CSS_PROP_BORDER_LEFT_STYLE, flags, value); - memcpy(((uint8_t *) ret->bytecode) + required_size, - right->bytecode, right->length); - required_size += right->length; - } else { - memcpy(((uint8_t *) ret->bytecode) + required_size, - top->bytecode, top->length); - required_size += top->length; - - memcpy(((uint8_t *) ret->bytecode) + required_size, - right->bytecode, right->length); - required_size += right->length; - - memcpy(((uint8_t *) ret->bytecode) + required_size, - bottom->bytecode, bottom->length); - required_size += bottom->length; - - memcpy(((uint8_t *) ret->bytecode) + required_size, - left->bytecode, left->length); - required_size += left->length; - } - - assert(required_size == ret->length); - - /* Write the result */ - *result = ret; - /* Invalidate ret, so that cleanup doesn't destroy it */ - ret = NULL; - - /* Clean up after ourselves */ -cleanup: - if (top) - css_stylesheet_style_destroy(c->sheet, top, error == CSS_OK); - if (right) - css_stylesheet_style_destroy(c->sheet, right, error == CSS_OK); - if (bottom) - css_stylesheet_style_destroy(c->sheet, bottom, error == CSS_OK); - if (left) - css_stylesheet_style_destroy(c->sheet, left, error == CSS_OK); - if (ret) - css_stylesheet_style_destroy(c->sheet, ret, error == CSS_OK); - - if (error != CSS_OK) - *ctx = orig_ctx; - - return error; -} - -/** - * Parse border-top shorthand - * - * \param c Parsing context - * \param vector Vector of tokens to process - * \param ctx Pointer to vector iteration context - * \param result Pointer to location to receive resulting style - * \return CSS_OK on success, - * CSS_NOMEM on memory exhaustion, - * CSS_INVALID if the input is not valid - * - * Post condition: \a *ctx is updated with the next token to process - * If the input is invalid, then \a *ctx remains unchanged. - */ -css_error parse_border_top(css_language *c, - const parserutils_vector *vector, int *ctx, - css_style **result) -{ - return parse_border_side(c, vector, ctx, SIDE_TOP, result); -} - -/** - * Parse border-top-color - * - * \param c Parsing context - * \param vector Vector of tokens to process - * \param ctx Pointer to vector iteration context - * \param result Pointer to location to receive resulting style - * \return CSS_OK on success, - * CSS_NOMEM on memory exhaustion, - * CSS_INVALID if the input is not valid - * - * Post condition: \a *ctx is updated with the next token to process - * If the input is invalid, then \a *ctx remains unchanged. - */ -css_error parse_border_top_color(css_language *c, - const parserutils_vector *vector, int *ctx, - css_style **result) -{ - return parse_border_side_color(c, vector, ctx, - CSS_PROP_BORDER_TOP_COLOR, result); -} - -/** - * Parse border-top-style - * - * \param c Parsing context - * \param vector Vector of tokens to process - * \param ctx Pointer to vector iteration context - * \param result Pointer to location to receive resulting style - * \return CSS_OK on success, - * CSS_NOMEM on memory exhaustion, - * CSS_INVALID if the input is not valid - * - * Post condition: \a *ctx is updated with the next token to process - * If the input is invalid, then \a *ctx remains unchanged. - */ -css_error parse_border_top_style(css_language *c, - const parserutils_vector *vector, int *ctx, - css_style **result) -{ - return parse_border_side_style(c, vector, ctx, - CSS_PROP_BORDER_TOP_STYLE, result); -} - -/** - * Parse border-top-width - * - * \param c Parsing context - * \param vector Vector of tokens to process - * \param ctx Pointer to vector iteration context - * \param result Pointer to location to receive resulting style - * \return CSS_OK on success, - * CSS_NOMEM on memory exhaustion, - * CSS_INVALID if the input is not valid - * - * Post condition: \a *ctx is updated with the next token to process - * If the input is invalid, then \a *ctx remains unchanged. - */ -css_error parse_border_top_width(css_language *c, - const parserutils_vector *vector, int *ctx, - css_style **result) -{ - return parse_border_side_width(c, vector, ctx, - CSS_PROP_BORDER_TOP_WIDTH, result); -} - -/** - * Parse border-width shorthand - * - * \param c Parsing context - * \param vector Vector of tokens to process - * \param ctx Pointer to vector iteration context - * \param result Pointer to location to receive resulting style - * \return CSS_OK on success, - * CSS_NOMEM on memory exhaustion, - * CSS_INVALID if the input is not valid - * - * Post condition: \a *ctx is updated with the next token to process - * If the input is invalid, then \a *ctx remains unchanged. - */ -css_error parse_border_width(css_language *c, - const parserutils_vector *vector, int *ctx, - css_style **result) -{ - int orig_ctx = *ctx; - int prev_ctx; - const css_token *token; - css_style *top = NULL; - css_style *right = NULL; - css_style *bottom = NULL; - css_style *left = NULL; - css_style *ret = NULL; - uint32_t num_sides = 0; - uint32_t required_size; - bool match; - css_error error; - - /* Firstly, handle inherit */ - token = parserutils_vector_peek(vector, *ctx); - if (token != NULL && token->type == CSS_TOKEN_IDENT && - (lwc_string_caseless_isequal( - token->idata, c->strings[INHERIT], - &match) == lwc_error_ok && match)) { - uint32_t *bytecode; - - error = css_stylesheet_style_create(c->sheet, - 4 * sizeof(uint32_t), &ret); - if (error != CSS_OK) { - *ctx = orig_ctx; - return error; - } - - bytecode = (uint32_t *) ret->bytecode; - - *(bytecode++) = buildOPV(CSS_PROP_BORDER_TOP_WIDTH, - FLAG_INHERIT, 0); - *(bytecode++) = buildOPV(CSS_PROP_BORDER_RIGHT_WIDTH, - FLAG_INHERIT, 0); - *(bytecode++) = buildOPV(CSS_PROP_BORDER_BOTTOM_WIDTH, - FLAG_INHERIT, 0); - *(bytecode++) = buildOPV(CSS_PROP_BORDER_LEFT_WIDTH, - FLAG_INHERIT, 0); - - parserutils_vector_iterate(vector, ctx); - - *result = ret; - - return CSS_OK; - } else if (token == NULL) { - /* No tokens -- clearly garbage */ - *ctx = orig_ctx; - return CSS_INVALID; - } - - /* Attempt to parse up to 4 widths */ - do { - prev_ctx = *ctx; - error = CSS_OK; - - /* Ensure that we're not about to parse another inherit */ - token = parserutils_vector_peek(vector, *ctx); - if (token != NULL && token->type == CSS_TOKEN_IDENT && - (lwc_string_caseless_isequal( - token->idata, c->strings[INHERIT], - &match) == lwc_error_ok && match)) { - error = CSS_INVALID; - goto cleanup; - } - - if (top == NULL && - (error = parse_border_side_width(c, vector, - ctx, CSS_PROP_BORDER_TOP_WIDTH, &top)) == - CSS_OK) { - num_sides = 1; - } else if (right == NULL && - (error = parse_border_side_width(c, vector, - ctx, CSS_PROP_BORDER_RIGHT_WIDTH, &right)) == - CSS_OK) { - num_sides = 2; - } else if (bottom == NULL && - (error = parse_border_side_width(c, vector, - ctx, CSS_PROP_BORDER_BOTTOM_WIDTH, &bottom)) == - CSS_OK) { - num_sides = 3; - } else if (left == NULL && - (error = parse_border_side_width(c, vector, - ctx, CSS_PROP_BORDER_LEFT_WIDTH, &left)) == - CSS_OK) { - num_sides = 4; - } - - if (error == CSS_OK) { - consumeWhitespace(vector, ctx); - - token = parserutils_vector_peek(vector, *ctx); - } else { - /* Forcibly cause loop to exit */ - token = NULL; - } - } while (*ctx != prev_ctx && token != NULL); - - if (num_sides == 0) { - error = CSS_INVALID; - goto cleanup; - } - - /* Calculate size of resultant style */ - if (num_sides == 1) { - required_size = 4 * top->length; - } else if (num_sides == 2) { - required_size = 2 * top->length + 2 * right->length; - } else if (num_sides == 3) { - required_size = top->length + 2 * right->length + - bottom->length; - } else { - required_size = top->length + right->length + - bottom->length + left->length; - } - - error = css_stylesheet_style_create(c->sheet, required_size, &ret); - if (error != CSS_OK) - goto cleanup; - - required_size = 0; - - if (num_sides == 1) { - uint32_t *opv = ((uint32_t *) top->bytecode); - uint8_t flags = getFlags(*opv); - uint16_t value = getValue(*opv); - - memcpy(((uint8_t *) ret->bytecode) + required_size, - top->bytecode, top->length); - required_size += top->length; - - *opv = buildOPV(CSS_PROP_BORDER_RIGHT_WIDTH, flags, value); - memcpy(((uint8_t *) ret->bytecode) + required_size, - top->bytecode, top->length); - required_size += top->length; - - *opv = buildOPV(CSS_PROP_BORDER_BOTTOM_WIDTH, flags, value); - memcpy(((uint8_t *) ret->bytecode) + required_size, - top->bytecode, top->length); - required_size += top->length; - - *opv = buildOPV(CSS_PROP_BORDER_LEFT_WIDTH, flags, value); - memcpy(((uint8_t *) ret->bytecode) + required_size, - top->bytecode, top->length); - required_size += top->length; - } else if (num_sides == 2) { - uint32_t *vopv = ((uint32_t *) top->bytecode); - uint32_t *hopv = ((uint32_t *) right->bytecode); - uint8_t vflags = getFlags(*vopv); - uint8_t hflags = getFlags(*hopv); - uint16_t vvalue = getValue(*vopv); - uint16_t hvalue = getValue(*hopv); - - memcpy(((uint8_t *) ret->bytecode) + required_size, - top->bytecode, top->length); - required_size += top->length; - - memcpy(((uint8_t *) ret->bytecode) + required_size, - right->bytecode, right->length); - required_size += right->length; - - *vopv = buildOPV(CSS_PROP_BORDER_BOTTOM_WIDTH, vflags, vvalue); - memcpy(((uint8_t *) ret->bytecode) + required_size, - top->bytecode, top->length); - required_size += top->length; - - *hopv = buildOPV(CSS_PROP_BORDER_LEFT_WIDTH, hflags, hvalue); - memcpy(((uint8_t *) ret->bytecode) + required_size, - right->bytecode, right->length); - required_size += right->length; - } else if (num_sides == 3) { - uint32_t *opv = ((uint32_t *) right->bytecode); - uint8_t flags = getFlags(*opv); - uint16_t value = getValue(*opv); - - memcpy(((uint8_t *) ret->bytecode) + required_size, - top->bytecode, top->length); - required_size += top->length; - - memcpy(((uint8_t *) ret->bytecode) + required_size, - right->bytecode, right->length); - required_size += right->length; - - memcpy(((uint8_t *) ret->bytecode) + required_size, - bottom->bytecode, bottom->length); - required_size += bottom->length; - - *opv = buildOPV(CSS_PROP_BORDER_LEFT_WIDTH, flags, value); - memcpy(((uint8_t *) ret->bytecode) + required_size, - right->bytecode, right->length); - required_size += right->length; - } else { - memcpy(((uint8_t *) ret->bytecode) + required_size, - top->bytecode, top->length); - required_size += top->length; - - memcpy(((uint8_t *) ret->bytecode) + required_size, - right->bytecode, right->length); - required_size += right->length; - - memcpy(((uint8_t *) ret->bytecode) + required_size, - bottom->bytecode, bottom->length); - required_size += bottom->length; - - memcpy(((uint8_t *) ret->bytecode) + required_size, - left->bytecode, left->length); - required_size += left->length; - } - - assert(required_size == ret->length); - - /* Write the result */ - *result = ret; - /* Invalidate ret, so that cleanup doesn't destroy it */ - ret = NULL; - - /* Clean up after ourselves */ -cleanup: - if (top) - css_stylesheet_style_destroy(c->sheet, top, error == CSS_OK); - if (right) - css_stylesheet_style_destroy(c->sheet, right, error == CSS_OK); - if (bottom) - css_stylesheet_style_destroy(c->sheet, bottom, error == CSS_OK); - if (left) - css_stylesheet_style_destroy(c->sheet, left, error == CSS_OK); - if (ret) - css_stylesheet_style_destroy(c->sheet, ret, error == CSS_OK); - - if (error != CSS_OK) - *ctx = orig_ctx; - - return error; -} - -/** - * Parse outline shorthand - * - * \param c Parsing context - * \param vector Vector of tokens to process - * \param ctx Pointer to vector iteration context - * \param result Pointer to location to receive resulting style - * \return CSS_OK on success, - * CSS_NOMEM on memory exhaustion, - * CSS_INVALID if the input is not valid - * - * Post condition: \a *ctx is updated with the next token to process - * If the input is invalid, then \a *ctx remains unchanged. - */ -css_error parse_outline(css_language *c, - const parserutils_vector *vector, int *ctx, - css_style **result) -{ - int orig_ctx = *ctx; - int prev_ctx; - const css_token *token; - css_style *color = NULL; - css_style *style = NULL; - css_style *width = NULL; - css_style *ret = NULL; - uint32_t required_size; - bool match; - css_error error; - - /* Firstly, handle inherit */ - token = parserutils_vector_peek(vector, *ctx); - if (token != NULL && token->type == CSS_TOKEN_IDENT && - (lwc_string_caseless_isequal( - token->idata, c->strings[INHERIT], - &match) == lwc_error_ok && match)) { - uint32_t *bytecode; - - error = css_stylesheet_style_create(c->sheet, - 3 * sizeof(uint32_t), &ret); - if (error != CSS_OK) { - *ctx = orig_ctx; - return error; - } - - bytecode = (uint32_t *) ret->bytecode; - - *(bytecode++) = buildOPV(CSS_PROP_OUTLINE_COLOR, - FLAG_INHERIT, 0); - *(bytecode++) = buildOPV(CSS_PROP_OUTLINE_STYLE, - FLAG_INHERIT, 0); - *(bytecode++) = buildOPV(CSS_PROP_OUTLINE_WIDTH, - FLAG_INHERIT, 0); - - parserutils_vector_iterate(vector, ctx); - - *result = ret; - - return CSS_OK; - } else if (token == NULL) { - /* No tokens -- clearly garbage */ - *ctx = orig_ctx; - return CSS_INVALID; - } - - /* Attempt to parse individual properties */ - do { - prev_ctx = *ctx; - error = CSS_OK; - - /* Ensure that we're not about to parse another inherit */ - token = parserutils_vector_peek(vector, *ctx); - if (token != NULL && token->type == CSS_TOKEN_IDENT && - (lwc_string_caseless_isequal( - token->idata, c->strings[INHERIT], - &match) == lwc_error_ok && match)) { - error = CSS_INVALID; - goto cleanup; - } - - if (color == NULL && - (error = parse_outline_color(c, vector, - ctx, &color)) == CSS_OK) { - } else if (style == NULL && - (error = parse_outline_style(c, vector, - ctx, &style)) == CSS_OK) { - } else if (width == NULL && - (error = parse_outline_width(c, vector, - ctx, &width)) == CSS_OK) { - } - - if (error == CSS_OK) { - consumeWhitespace(vector, ctx); - - token = parserutils_vector_peek(vector, *ctx); - } else { - /* Forcibly cause loop to exit */ - token = NULL; - } - } while (*ctx != prev_ctx && token != NULL); - - /* Calculate size of resultant style */ - required_size = 0; - if (color) - required_size += color->length; - else - required_size += sizeof(uint32_t); - - if (style) - required_size += style->length; - else - required_size += sizeof(uint32_t); - - if (width) - required_size += width->length; - else - required_size += sizeof(uint32_t); - - error = css_stylesheet_style_create(c->sheet, required_size, &ret); - if (error != CSS_OK) - goto cleanup; - - required_size = 0; - - if (color) { - memcpy(((uint8_t *) ret->bytecode) + required_size, - color->bytecode, color->length); - required_size += color->length; - } else { - void *bc = ((uint8_t *) ret->bytecode) + required_size; - - *((uint32_t *) bc) = buildOPV(CSS_PROP_OUTLINE_COLOR, - 0, OUTLINE_COLOR_INVERT); - required_size += sizeof(uint32_t); - } - - if (style) { - memcpy(((uint8_t *) ret->bytecode) + required_size, - style->bytecode, style->length); - required_size += style->length; - } else { - void *bc = ((uint8_t *) ret->bytecode) + required_size; - - *((uint32_t *) bc) = buildOPV(CSS_PROP_OUTLINE_STYLE, - 0, OUTLINE_STYLE_NONE); - required_size += sizeof(uint32_t); - } - - if (width) { - memcpy(((uint8_t *) ret->bytecode) + required_size, - width->bytecode, width->length); - required_size += width->length; - } else { - void *bc = ((uint8_t *) ret->bytecode) + required_size; - - *((uint32_t *) bc) = buildOPV(CSS_PROP_OUTLINE_WIDTH, - 0, OUTLINE_WIDTH_MEDIUM); - required_size += sizeof(uint32_t); - } - - assert(required_size == ret->length); - - /* Write the result */ - *result = ret; - /* Invalidate ret, so that cleanup doesn't destroy it */ - ret = NULL; - - /* Clean up after ourselves */ -cleanup: - if (color) - css_stylesheet_style_destroy(c->sheet, color, error == CSS_OK); - if (style) - css_stylesheet_style_destroy(c->sheet, style, error == CSS_OK); - if (width) - css_stylesheet_style_destroy(c->sheet, width, error == CSS_OK); - if (ret) - css_stylesheet_style_destroy(c->sheet, ret, error == CSS_OK); - - if (error != CSS_OK) - *ctx = orig_ctx; - - return error; -} - -/** - * Parse outline-color - * - * \param c Parsing context - * \param vector Vector of tokens to process - * \param ctx Pointer to vector iteration context - * \param result Pointer to location to receive resulting style - * \return CSS_OK on success, - * CSS_NOMEM on memory exhaustion, - * CSS_INVALID if the input is not valid - * - * Post condition: \a *ctx is updated with the next token to process - * If the input is invalid, then \a *ctx remains unchanged. - */ -css_error parse_outline_color(css_language *c, - const parserutils_vector *vector, int *ctx, - css_style **result) -{ - int orig_ctx = *ctx; - css_error error; - const css_token *token; - uint8_t flags = 0; - uint16_t value = 0; - uint32_t opv; - uint32_t colour = 0; - uint32_t required_size; - bool match; - - /* colour | IDENT (invert, inherit) */ - token = parserutils_vector_peek(vector, *ctx); - if (token == NULL) { - *ctx = orig_ctx; - return CSS_INVALID; - } - - if (token->type == CSS_TOKEN_IDENT && - (lwc_string_caseless_isequal( - token->idata, c->strings[INHERIT], - &match) == lwc_error_ok && match)) { - parserutils_vector_iterate(vector, ctx); - flags |= FLAG_INHERIT; - } else if (token->type == CSS_TOKEN_IDENT && - (lwc_string_caseless_isequal( - token->idata, c->strings[INVERT], - &match) == lwc_error_ok && match)) { - parserutils_vector_iterate(vector, ctx); - value = OUTLINE_COLOR_INVERT; - } else { - error = parse_colour_specifier(c, vector, ctx, &colour); - if (error != CSS_OK) { - *ctx = orig_ctx; - return error; - } - - value = OUTLINE_COLOR_SET; - } - - opv = buildOPV(CSS_PROP_OUTLINE_COLOR, flags, value); - - required_size = sizeof(opv); - if ((flags & FLAG_INHERIT) == false && value == OUTLINE_COLOR_SET) - required_size += sizeof(colour); - - /* Allocate result */ - error = css_stylesheet_style_create(c->sheet, required_size, result); - if (error != CSS_OK) { - *ctx = orig_ctx; - return error; - } - - /* Copy the bytecode to it */ - memcpy((*result)->bytecode, &opv, sizeof(opv)); - if ((flags & FLAG_INHERIT) == false && value == OUTLINE_COLOR_SET) { - memcpy(((uint8_t *) (*result)->bytecode) + sizeof(opv), - &colour, sizeof(colour)); - } - - return CSS_OK; -} - -/** - * Parse outline-style - * - * \param c Parsing context - * \param vector Vector of tokens to process - * \param ctx Pointer to vector iteration context - * \param result Pointer to location to receive resulting style - * \return CSS_OK on success, - * CSS_NOMEM on memory exhaustion, - * CSS_INVALID if the input is not valid - * - * Post condition: \a *ctx is updated with the next token to process - * If the input is invalid, then \a *ctx remains unchanged. - */ -css_error parse_outline_style(css_language *c, - const parserutils_vector *vector, int *ctx, - css_style **result) -{ - int orig_ctx = *ctx; - css_error error; - uint32_t opv; - uint16_t value; - - /* Parse as a border style */ - error = parse_border_side_style(c, vector, ctx, - CSS_PROP_OUTLINE_STYLE, result); - if (error != CSS_OK) { - *ctx = orig_ctx; - return error; - } - - opv = *((uint32_t *) (*result)->bytecode); - - value = getValue(opv); - - /* Hidden is invalid */ - if (value == BORDER_STYLE_HIDDEN) { - *ctx = orig_ctx; - return CSS_INVALID; - } - - return CSS_OK; -} - -/** - * Parse outline-width - * - * \param c Parsing context - * \param vector Vector of tokens to process - * \param ctx Pointer to vector iteration context - * \param result Pointer to location to receive resulting style - * \return CSS_OK on success, - * CSS_NOMEM on memory exhaustion, - * CSS_INVALID if the input is not valid - * - * Post condition: \a *ctx is updated with the next token to process - * If the input is invalid, then \a *ctx remains unchanged. - */ -css_error parse_outline_width(css_language *c, - const parserutils_vector *vector, int *ctx, - css_style **result) -{ - /* Parse as border width */ - return parse_border_side_width(c, vector, ctx, - CSS_PROP_OUTLINE_WIDTH, result); -} - -/** - * Parse border-{top,right,bottom,left} shorthand - * - * \param c Parsing context - * \param vector Vector of tokens to process - * \param ctx Pointer to vector iteration context - * \param side The side we're parsing for - * \param result Pointer to location to receive resulting style - * \return CSS_OK on success, - * CSS_NOMEM on memory exhaustion, - * CSS_INVALID if the input is not valid - * - * Post condition: \a *ctx is updated with the next token to process - * If the input is invalid, then \a *ctx remains unchanged. - */ -css_error parse_border_side(css_language *c, - const parserutils_vector *vector, int *ctx, - uint32_t side, css_style **result) -{ - int orig_ctx = *ctx; - int prev_ctx; - const css_token *token; - css_style *color = NULL; - css_style *style = NULL; - css_style *width = NULL; - css_style *ret = NULL; - uint32_t required_size; - bool match; - css_error error; - - /* Firstly, handle inherit */ - token = parserutils_vector_peek(vector, *ctx); - if (token != NULL && token->type == CSS_TOKEN_IDENT && - (lwc_string_caseless_isequal( - token->idata, c->strings[INHERIT], - &match) == lwc_error_ok && match)) { - uint32_t *bytecode; - - error = css_stylesheet_style_create(c->sheet, - 3 * sizeof(uint32_t), &ret); - if (error != CSS_OK) { - *ctx = orig_ctx; - return error; - } - - bytecode = (uint32_t *) ret->bytecode; - - *(bytecode++) = buildOPV(CSS_PROP_BORDER_TOP_COLOR + side, - FLAG_INHERIT, 0); - *(bytecode++) = buildOPV(CSS_PROP_BORDER_TOP_STYLE + side, - FLAG_INHERIT, 0); - *(bytecode++) = buildOPV(CSS_PROP_BORDER_TOP_WIDTH + side, - FLAG_INHERIT, 0); - - parserutils_vector_iterate(vector, ctx); - - *result = ret; - - return CSS_OK; - } else if (token == NULL) { - /* No tokens -- clearly garbage */ - *ctx = orig_ctx; - return CSS_INVALID; - } - - /* Attempt to parse individual properties */ - do { - prev_ctx = *ctx; - error = CSS_OK; - - /* Ensure that we're not about to parse another inherit */ - token = parserutils_vector_peek(vector, *ctx); - if (token != NULL && token->type == CSS_TOKEN_IDENT && - (lwc_string_caseless_isequal( - token->idata, c->strings[INHERIT], - &match) == lwc_error_ok && match)) { - error = CSS_INVALID; - goto cleanup; - } - - if (color == NULL && - (error = parse_border_side_color(c, vector, ctx, - CSS_PROP_BORDER_TOP_COLOR + side, &color)) == - CSS_OK) { - } else if (style == NULL && - (error = parse_border_side_style(c, vector, ctx, - CSS_PROP_BORDER_TOP_STYLE + side, &style)) == - CSS_OK) { - } else if (width == NULL && - (error = parse_border_side_width(c, vector, ctx, - CSS_PROP_BORDER_TOP_WIDTH + side, &width)) == - CSS_OK) { - } - - if (error == CSS_OK) { - consumeWhitespace(vector, ctx); - - token = parserutils_vector_peek(vector, *ctx); - } else { - /* Forcibly cause loop to exit */ - token = NULL; - } - } while (*ctx != prev_ctx && token != NULL); - - /* Calculate size of resultant style */ - required_size = 0; - if (color) - required_size += color->length; - - if (style) - required_size += style->length; - else - required_size += sizeof(uint32_t); - - if (width) - required_size += width->length; - else - required_size += sizeof(uint32_t); - - error = css_stylesheet_style_create(c->sheet, required_size, &ret); - if (error != CSS_OK) - goto cleanup; - - required_size = 0; - - if (color) { - memcpy(((uint8_t *) ret->bytecode) + required_size, - color->bytecode, color->length); - required_size += color->length; - } - - if (style) { - memcpy(((uint8_t *) ret->bytecode) + required_size, - style->bytecode, style->length); - required_size += style->length; - } else { - void *bc = ((uint8_t *) ret->bytecode) + required_size; - - *((uint32_t *) bc) = buildOPV(CSS_PROP_BORDER_TOP_STYLE + side, - 0, BORDER_STYLE_NONE); - required_size += sizeof(uint32_t); - } - - if (width) { - memcpy(((uint8_t *) ret->bytecode) + required_size, - width->bytecode, width->length); - required_size += width->length; - } else { - void *bc = ((uint8_t *) ret->bytecode) + required_size; - - *((uint32_t *) bc) = buildOPV(CSS_PROP_BORDER_TOP_WIDTH + side, - 0, BORDER_WIDTH_MEDIUM); - required_size += sizeof(uint32_t); - } - - assert(required_size == ret->length); - - /* Write the result */ - *result = ret; - /* Invalidate ret, so that cleanup doesn't destroy it */ - ret = NULL; - - /* Clean up after ourselves */ -cleanup: - if (color) - css_stylesheet_style_destroy(c->sheet, color, error == CSS_OK); - if (style) - css_stylesheet_style_destroy(c->sheet, style, error == CSS_OK); - if (width) - css_stylesheet_style_destroy(c->sheet, width, error == CSS_OK); - if (ret) - css_stylesheet_style_destroy(c->sheet, ret, error == CSS_OK); - - if (error != CSS_OK) - *ctx = orig_ctx; - - return error; -} - -/** - * Parse border-{top,right,bottom,left}-color - * - * \param c Parsing context - * \param vector Vector of tokens to process - * \param ctx Pointer to vector iteration context - * \param op Opcode to parse for (encodes side) - * \param result Pointer to location to receive resulting style - * \return CSS_OK on success, - * CSS_NOMEM on memory exhaustion, - * CSS_INVALID if the input is not valid - * - * Post condition: \a *ctx is updated with the next token to process - * If the input is invalid, then \a *ctx remains unchanged. - */ -css_error parse_border_side_color(css_language *c, - const parserutils_vector *vector, int *ctx, - uint16_t op, css_style **result) -{ - int orig_ctx = *ctx; - css_error error; - const css_token *token; - uint32_t opv; - uint8_t flags = 0; - uint16_t value = 0; - uint32_t colour = 0; - uint32_t required_size; - bool match; - - /* colour | IDENT (transparent, inherit) */ - token= parserutils_vector_peek(vector, *ctx); - if (token == NULL) { - *ctx = orig_ctx; - return CSS_INVALID; - } - - if (token->type == CSS_TOKEN_IDENT && - (lwc_string_caseless_isequal( - token->idata, c->strings[INHERIT], - &match) == lwc_error_ok && match)) { - parserutils_vector_iterate(vector, ctx); - flags |= FLAG_INHERIT; - } else if (token->type == CSS_TOKEN_IDENT && - (lwc_string_caseless_isequal( - token->idata, c->strings[TRANSPARENT], - &match) == lwc_error_ok && match)) { - parserutils_vector_iterate(vector, ctx); - value = BORDER_COLOR_TRANSPARENT; - } else { - error = parse_colour_specifier(c, vector, ctx, &colour); - if (error != CSS_OK) { - *ctx = orig_ctx; - return error; - } - - value = BORDER_COLOR_SET; - } - - opv = buildOPV(op, flags, value); - - required_size = sizeof(opv); - if ((flags & FLAG_INHERIT) == false && value == BORDER_COLOR_SET) - required_size += sizeof(colour); - - /* Allocate result */ - error = css_stylesheet_style_create(c->sheet, required_size, result); - if (error != CSS_OK) { - *ctx = orig_ctx; - return error; - } - - /* Copy the bytecode to it */ - memcpy((*result)->bytecode, &opv, sizeof(opv)); - if ((flags & FLAG_INHERIT) == false && value == BORDER_COLOR_SET) { - memcpy(((uint8_t *) (*result)->bytecode) + sizeof(opv), - &colour, sizeof(colour)); - } - - return CSS_OK; -} - -/** - * Parse border-{top,right,bottom,left}-style - * - * \param c Parsing context - * \param vector Vector of tokens to process - * \param ctx Pointer to vector iteration context - * \param op Opcode to parse for (encodes side) - * \param result Pointer to location to receive resulting style - * \return CSS_OK on success, - * CSS_NOMEM on memory exhaustion, - * CSS_INVALID if the input is not valid - * - * Post condition: \a *ctx is updated with the next token to process - * If the input is invalid, then \a *ctx remains unchanged. - */ -css_error parse_border_side_style(css_language *c, - const parserutils_vector *vector, int *ctx, - uint16_t op, css_style **result) -{ - int orig_ctx = *ctx; - css_error error; - const css_token *ident; - uint8_t flags = 0; - uint16_t value = 0; - uint32_t opv; - bool match; - - /* IDENT (none, hidden, dotted, dashed, solid, double, groove, - * ridge, inset, outset, inherit) */ - ident = parserutils_vector_iterate(vector, ctx); - if (ident == NULL || ident->type != CSS_TOKEN_IDENT) { - *ctx = orig_ctx; - return CSS_INVALID; - } - - if ((lwc_string_caseless_isequal( - ident->idata, c->strings[INHERIT], - &match) == lwc_error_ok && match)) { - flags |= FLAG_INHERIT; - } else if ((lwc_string_caseless_isequal( - ident->idata, c->strings[NONE], - &match) == lwc_error_ok && match)) { - value = BORDER_STYLE_NONE; - } else if ((lwc_string_caseless_isequal( - ident->idata, c->strings[HIDDEN], - &match) == lwc_error_ok && match)) { - value = BORDER_STYLE_HIDDEN; - } else if ((lwc_string_caseless_isequal( - ident->idata, c->strings[DOTTED], - &match) == lwc_error_ok && match)) { - value = BORDER_STYLE_DOTTED; - } else if ((lwc_string_caseless_isequal( - ident->idata, c->strings[DASHED], - &match) == lwc_error_ok && match)) { - value = BORDER_STYLE_DASHED; - } else if ((lwc_string_caseless_isequal( - ident->idata, c->strings[SOLID], - &match) == lwc_error_ok && match)) { - value = BORDER_STYLE_SOLID; - } else if ((lwc_string_caseless_isequal( - ident->idata, c->strings[LIBCSS_DOUBLE], - &match) == lwc_error_ok && match)) { - value = BORDER_STYLE_DOUBLE; - } else if ((lwc_string_caseless_isequal( - ident->idata, c->strings[GROOVE], - &match) == lwc_error_ok && match)) { - value = BORDER_STYLE_GROOVE; - } else if ((lwc_string_caseless_isequal( - ident->idata, c->strings[RIDGE], - &match) == lwc_error_ok && match)) { - value = BORDER_STYLE_RIDGE; - } else if ((lwc_string_caseless_isequal( - ident->idata, c->strings[INSET], - &match) == lwc_error_ok && match)) { - value = BORDER_STYLE_INSET; - } else if ((lwc_string_caseless_isequal( - ident->idata, c->strings[OUTSET], - &match) == lwc_error_ok && match)) { - value = BORDER_STYLE_OUTSET; - } else { - *ctx = orig_ctx; - return CSS_INVALID; - } - - opv = buildOPV(op, flags, value); - - /* Allocate result */ - error = css_stylesheet_style_create(c->sheet, sizeof(opv), result); - if (error != CSS_OK) { - *ctx = orig_ctx; - return error; - } - - /* Copy the bytecode to it */ - memcpy((*result)->bytecode, &opv, sizeof(opv)); - - return CSS_OK; -} - -/** - * Parse border-{top,right,bottom,left}-width - * - * \param c Parsing context - * \param vector Vector of tokens to process - * \param ctx Pointer to vector iteration context - * \param op Opcode to parse for (encodes side) - * \param result Pointer to location to receive resulting style - * \return CSS_OK on success, - * CSS_NOMEM on memory exhaustion, - * CSS_INVALID if the input is not valid - * - * Post condition: \a *ctx is updated with the next token to process - * If the input is invalid, then \a *ctx remains unchanged. - */ -css_error parse_border_side_width(css_language *c, - const parserutils_vector *vector, int *ctx, - uint16_t op, css_style **result) -{ - int orig_ctx = *ctx; - css_error error; - const css_token *token; - uint8_t flags = 0; - uint16_t value = 0; - uint32_t opv; - css_fixed length = 0; - uint32_t unit = 0; - uint32_t required_size; - bool match; - - /* length | IDENT(thin, medium, thick, inherit) */ - token= parserutils_vector_peek(vector, *ctx); - if (token == NULL) { - *ctx = orig_ctx; - return CSS_INVALID; - } - - if (token->type == CSS_TOKEN_IDENT && - (lwc_string_caseless_isequal( - token->idata, c->strings[INHERIT], - &match) == lwc_error_ok && match)) { - parserutils_vector_iterate(vector, ctx); - flags |= FLAG_INHERIT; - } else if (token->type == CSS_TOKEN_IDENT && - (lwc_string_caseless_isequal( - token->idata, c->strings[THIN], - &match) == lwc_error_ok && match)) { - parserutils_vector_iterate(vector, ctx); - value = BORDER_WIDTH_THIN; - } else if (token->type == CSS_TOKEN_IDENT && - (lwc_string_caseless_isequal( - token->idata, c->strings[MEDIUM], - &match) == lwc_error_ok && match)) { - parserutils_vector_iterate(vector, ctx); - value = BORDER_WIDTH_MEDIUM; - } else if (token->type == CSS_TOKEN_IDENT && - (lwc_string_caseless_isequal( - token->idata, c->strings[THICK], - &match) == lwc_error_ok && match)) { - parserutils_vector_iterate(vector, ctx); - value = BORDER_WIDTH_THICK; - } else { - error = parse_unit_specifier(c, vector, ctx, UNIT_PX, - &length, &unit); - if (error != CSS_OK) { - *ctx = orig_ctx; - return error; - } - - if (unit == UNIT_PCT || unit & UNIT_ANGLE || - unit & UNIT_TIME || unit & UNIT_FREQ) { - *ctx = orig_ctx; - return CSS_INVALID; - } - - /* Length must be positive */ - if (length < 0) { - *ctx = orig_ctx; - return CSS_INVALID; - } - - value = BORDER_WIDTH_SET; - } - - opv = buildOPV(op, flags, value); - - required_size = sizeof(opv); - if ((flags & FLAG_INHERIT) == false && value == BORDER_WIDTH_SET) - required_size += sizeof(length) + sizeof(unit); - - /* Allocate result */ - error = css_stylesheet_style_create(c->sheet, required_size, result); - if (error != CSS_OK) { - *ctx = orig_ctx; - return error; - } - - /* Copy the bytecode to it */ - memcpy((*result)->bytecode, &opv, sizeof(opv)); - if ((flags & FLAG_INHERIT) == false && value == BORDER_WIDTH_SET) { - memcpy(((uint8_t *) (*result)->bytecode) + sizeof(opv), - &length, sizeof(length)); - memcpy(((uint8_t *) (*result)->bytecode) + sizeof(opv) + - sizeof(length), &unit, sizeof(unit)); - } - - return CSS_OK; -} - diff --git a/src/parse/properties/border_right.c b/src/parse/properties/border_right.c new file mode 100644 index 0000000..b8433f1 --- /dev/null +++ b/src/parse/properties/border_right.c @@ -0,0 +1,35 @@ +/* + * This file is part of LibCSS. + * Licensed under the MIT License, + * http://www.opensource.org/licenses/mit-license.php + * Copyright 2009 John-Mark Bell + */ + +#include +#include + +#include "bytecode/bytecode.h" +#include "bytecode/opcodes.h" +#include "parse/properties/properties.h" +#include "parse/properties/utils.h" + +/** + * Parse border-right shorthand + * + * \param c Parsing context + * \param vector Vector of tokens to process + * \param ctx Pointer to vector iteration context + * \param result Pointer to location to receive resulting style + * \return CSS_OK on success, + * CSS_NOMEM on memory exhaustion, + * CSS_INVALID if the input is not valid + * + * Post condition: \a *ctx is updated with the next token to process + * If the input is invalid, then \a *ctx remains unchanged. + */ +css_error parse_border_right(css_language *c, + const parserutils_vector *vector, int *ctx, + css_style **result) +{ + return parse_border_side(c, vector, ctx, BORDER_SIDE_RIGHT, result); +} diff --git a/src/parse/properties/border_right_color.c b/src/parse/properties/border_right_color.c new file mode 100644 index 0000000..dc1412c --- /dev/null +++ b/src/parse/properties/border_right_color.c @@ -0,0 +1,36 @@ +/* + * This file is part of LibCSS. + * Licensed under the MIT License, + * http://www.opensource.org/licenses/mit-license.php + * Copyright 2009 John-Mark Bell + */ + +#include +#include + +#include "bytecode/bytecode.h" +#include "bytecode/opcodes.h" +#include "parse/properties/properties.h" +#include "parse/properties/utils.h" + +/** + * Parse border-right-color + * + * \param c Parsing context + * \param vector Vector of tokens to process + * \param ctx Pointer to vector iteration context + * \param result Pointer to location to receive resulting style + * \return CSS_OK on success, + * CSS_NOMEM on memory exhaustion, + * CSS_INVALID if the input is not valid + * + * Post condition: \a *ctx is updated with the next token to process + * If the input is invalid, then \a *ctx remains unchanged. + */ +css_error parse_border_right_color(css_language *c, + const parserutils_vector *vector, int *ctx, + css_style **result) +{ + return parse_border_side_color(c, vector, ctx, + CSS_PROP_BORDER_RIGHT_COLOR, result); +} diff --git a/src/parse/properties/border_right_style.c b/src/parse/properties/border_right_style.c new file mode 100644 index 0000000..eb33c4f --- /dev/null +++ b/src/parse/properties/border_right_style.c @@ -0,0 +1,36 @@ +/* + * This file is part of LibCSS. + * Licensed under the MIT License, + * http://www.opensource.org/licenses/mit-license.php + * Copyright 2009 John-Mark Bell + */ + +#include +#include + +#include "bytecode/bytecode.h" +#include "bytecode/opcodes.h" +#include "parse/properties/properties.h" +#include "parse/properties/utils.h" + +/** + * Parse border-right-style + * + * \param c Parsing context + * \param vector Vector of tokens to process + * \param ctx Pointer to vector iteration context + * \param result Pointer to location to receive resulting style + * \return CSS_OK on success, + * CSS_NOMEM on memory exhaustion, + * CSS_INVALID if the input is not valid + * + * Post condition: \a *ctx is updated with the next token to process + * If the input is invalid, then \a *ctx remains unchanged. + */ +css_error parse_border_right_style(css_language *c, + const parserutils_vector *vector, int *ctx, + css_style **result) +{ + return parse_border_side_style(c, vector, ctx, + CSS_PROP_BORDER_RIGHT_STYLE, result); +} diff --git a/src/parse/properties/border_right_width.c b/src/parse/properties/border_right_width.c new file mode 100644 index 0000000..a4739fb --- /dev/null +++ b/src/parse/properties/border_right_width.c @@ -0,0 +1,36 @@ +/* + * This file is part of LibCSS. + * Licensed under the MIT License, + * http://www.opensource.org/licenses/mit-license.php + * Copyright 2009 John-Mark Bell + */ + +#include +#include + +#include "bytecode/bytecode.h" +#include "bytecode/opcodes.h" +#include "parse/properties/properties.h" +#include "parse/properties/utils.h" + +/** + * Parse border-right-width + * + * \param c Parsing context + * \param vector Vector of tokens to process + * \param ctx Pointer to vector iteration context + * \param result Pointer to location to receive resulting style + * \return CSS_OK on success, + * CSS_NOMEM on memory exhaustion, + * CSS_INVALID if the input is not valid + * + * Post condition: \a *ctx is updated with the next token to process + * If the input is invalid, then \a *ctx remains unchanged. + */ +css_error parse_border_right_width(css_language *c, + const parserutils_vector *vector, int *ctx, + css_style **result) +{ + return parse_border_side_width(c, vector, ctx, + CSS_PROP_BORDER_RIGHT_WIDTH, result); +} diff --git a/src/parse/properties/border_spacing.c b/src/parse/properties/border_spacing.c new file mode 100644 index 0000000..623f616 --- /dev/null +++ b/src/parse/properties/border_spacing.c @@ -0,0 +1,143 @@ +/* + * This file is part of LibCSS. + * Licensed under the MIT License, + * http://www.opensource.org/licenses/mit-license.php + * Copyright 2009 John-Mark Bell + */ + +#include +#include + +#include "bytecode/bytecode.h" +#include "bytecode/opcodes.h" +#include "parse/properties/properties.h" +#include "parse/properties/utils.h" + +/** + * Parse border-spacing + * + * \param c Parsing context + * \param vector Vector of tokens to process + * \param ctx Pointer to vector iteration context + * \param result Pointer to location to receive resulting style + * \return CSS_OK on success, + * CSS_NOMEM on memory exhaustion, + * CSS_INVALID if the input is not valid + * + * Post condition: \a *ctx is updated with the next token to process + * If the input is invalid, then \a *ctx remains unchanged. + */ +css_error parse_border_spacing(css_language *c, + const parserutils_vector *vector, int *ctx, + css_style **result) +{ + int orig_ctx = *ctx; + css_error error; + const css_token *token; + uint8_t flags = 0; + uint16_t value = 0; + uint32_t opv; + css_fixed length[2] = { 0 }; + uint32_t unit[2] = { 0 }; + uint32_t required_size; + bool match; + + /* length length? | IDENT(inherit) */ + token = parserutils_vector_peek(vector, *ctx); + if (token == NULL) { + *ctx = orig_ctx; + return CSS_INVALID; + } + + if (token->type == CSS_TOKEN_IDENT && + (lwc_string_caseless_isequal( + token->idata, c->strings[INHERIT], + &match) == lwc_error_ok && match)) { + parserutils_vector_iterate(vector, ctx); + flags = FLAG_INHERIT; + } else { + int num_lengths = 0; + + error = parse_unit_specifier(c, vector, ctx, UNIT_PX, + &length[0], &unit[0]); + if (error != CSS_OK) { + *ctx = orig_ctx; + return error; + } + + if (unit[0] & UNIT_ANGLE || unit[0] & UNIT_TIME || + unit[0] & UNIT_FREQ || unit[0] & UNIT_PCT) { + *ctx = orig_ctx; + return CSS_INVALID; + } + + num_lengths = 1; + + consumeWhitespace(vector, ctx); + + token = parserutils_vector_peek(vector, *ctx); + if (token != NULL) { + /* Attempt second length, ignoring errors. + * The core !important parser will ensure + * any remaining junk is thrown out. + * Ctx will be preserved on error, as usual + */ + error = parse_unit_specifier(c, vector, ctx, UNIT_PX, + &length[1], &unit[1]); + if (error == CSS_OK) { + if (unit[1] & UNIT_ANGLE || + unit[1] & UNIT_TIME || + unit[1] & UNIT_FREQ || + unit[1] & UNIT_PCT) { + *ctx = orig_ctx; + return CSS_INVALID; + } + + num_lengths = 2; + } + } + + if (num_lengths == 1) { + /* Only one length specified. Use for both axes. */ + length[1] = length[0]; + unit[1] = unit[0]; + } + + /* Lengths must not be negative */ + if (length[0] < 0 || length[1] < 0) { + *ctx = orig_ctx; + return CSS_INVALID; + } + + value = BORDER_SPACING_SET; + } + + opv = buildOPV(CSS_PROP_BORDER_SPACING, flags, value); + + required_size = sizeof(opv); + if ((flags & FLAG_INHERIT) == false && value == BORDER_SPACING_SET) + required_size += 2 * (sizeof(length[0]) + sizeof(unit[0])); + + /* Allocate result */ + error = css_stylesheet_style_create(c->sheet, required_size, result); + if (error != CSS_OK) { + *ctx = orig_ctx; + return error; + } + + /* Copy the bytecode to it */ + memcpy((*result)->bytecode, &opv, sizeof(opv)); + if ((flags & FLAG_INHERIT) == false && value == BORDER_SPACING_SET) { + uint8_t *ptr = ((uint8_t *) (*result)->bytecode) + sizeof(opv); + + memcpy(ptr, &length[0], sizeof(length[0])); + ptr += sizeof(length[0]); + memcpy(ptr, &unit[0], sizeof(unit[0])); + ptr += sizeof(unit[0]); + memcpy(ptr, &length[1], sizeof(length[1])); + ptr += sizeof(length[1]); + memcpy(ptr, &unit[1], sizeof(unit[1])); + } + + return CSS_OK; +} diff --git a/src/parse/properties/border_style.c b/src/parse/properties/border_style.c new file mode 100644 index 0000000..ed3a7ac --- /dev/null +++ b/src/parse/properties/border_style.c @@ -0,0 +1,266 @@ +/* + * This file is part of LibCSS. + * Licensed under the MIT License, + * http://www.opensource.org/licenses/mit-license.php + * Copyright 2009 John-Mark Bell + */ + +#include +#include + +#include "bytecode/bytecode.h" +#include "bytecode/opcodes.h" +#include "parse/properties/properties.h" +#include "parse/properties/utils.h" + +/** + * Parse border-style shorthand + * + * \param c Parsing context + * \param vector Vector of tokens to process + * \param ctx Pointer to vector iteration context + * \param result Pointer to location to receive resulting style + * \return CSS_OK on success, + * CSS_NOMEM on memory exhaustion, + * CSS_INVALID if the input is not valid + * + * Post condition: \a *ctx is updated with the next token to process + * If the input is invalid, then \a *ctx remains unchanged. + */ +css_error parse_border_style(css_language *c, + const parserutils_vector *vector, int *ctx, + css_style **result) +{ + int orig_ctx = *ctx; + int prev_ctx; + const css_token *token; + css_style *top = NULL; + css_style *right = NULL; + css_style *bottom = NULL; + css_style *left = NULL; + css_style *ret = NULL; + uint32_t num_sides = 0; + uint32_t required_size; + bool match; + css_error error; + + /* Firstly, handle inherit */ + token = parserutils_vector_peek(vector, *ctx); + if (token != NULL && token->type == CSS_TOKEN_IDENT && + (lwc_string_caseless_isequal( + token->idata, c->strings[INHERIT], + &match) == lwc_error_ok && match)) { + uint32_t *bytecode; + + error = css_stylesheet_style_create(c->sheet, + 4 * sizeof(uint32_t), &ret); + if (error != CSS_OK) { + *ctx = orig_ctx; + return error; + } + + bytecode = (uint32_t *) ret->bytecode; + + *(bytecode++) = buildOPV(CSS_PROP_BORDER_TOP_STYLE, + FLAG_INHERIT, 0); + *(bytecode++) = buildOPV(CSS_PROP_BORDER_RIGHT_STYLE, + FLAG_INHERIT, 0); + *(bytecode++) = buildOPV(CSS_PROP_BORDER_BOTTOM_STYLE, + FLAG_INHERIT, 0); + *(bytecode++) = buildOPV(CSS_PROP_BORDER_LEFT_STYLE, + FLAG_INHERIT, 0); + + parserutils_vector_iterate(vector, ctx); + + *result = ret; + + return CSS_OK; + } else if (token == NULL) { + /* No tokens -- clearly garbage */ + *ctx = orig_ctx; + return CSS_INVALID; + } + + /* Attempt to parse up to 4 styles */ + do { + prev_ctx = *ctx; + error = CSS_OK; + + /* Ensure that we're not about to parse another inherit */ + token = parserutils_vector_peek(vector, *ctx); + if (token != NULL && token->type == CSS_TOKEN_IDENT && + (lwc_string_caseless_isequal( + token->idata, c->strings[INHERIT], + &match) == lwc_error_ok && match)) { + error = CSS_INVALID; + goto cleanup; + } + + if (top == NULL && + (error = parse_border_side_style(c, vector, + ctx, CSS_PROP_BORDER_TOP_STYLE, &top)) == + CSS_OK) { + num_sides = 1; + } else if (right == NULL && + (error = parse_border_side_style(c, vector, + ctx, CSS_PROP_BORDER_RIGHT_STYLE, &right)) == + CSS_OK) { + num_sides = 2; + } else if (bottom == NULL && + (error = parse_border_side_style(c, vector, + ctx, CSS_PROP_BORDER_BOTTOM_STYLE, &bottom)) == + CSS_OK) { + num_sides = 3; + } else if (left == NULL && + (error = parse_border_side_style(c, vector, + ctx, CSS_PROP_BORDER_LEFT_STYLE, &left)) == + CSS_OK) { + num_sides = 4; + } + + if (error == CSS_OK) { + consumeWhitespace(vector, ctx); + + token = parserutils_vector_peek(vector, *ctx); + } else { + /* Forcibly cause loop to exit */ + token = NULL; + } + } while (*ctx != prev_ctx && token != NULL); + + if (num_sides == 0) { + error = CSS_INVALID; + goto cleanup; + } + + /* Calculate size of resultant style */ + if (num_sides == 1) { + required_size = 4 * top->length; + } else if (num_sides == 2) { + required_size = 2 * top->length + 2 * right->length; + } else if (num_sides == 3) { + required_size = top->length + 2 * right->length + + bottom->length; + } else { + required_size = top->length + right->length + + bottom->length + left->length; + } + + error = css_stylesheet_style_create(c->sheet, required_size, &ret); + if (error != CSS_OK) + goto cleanup; + + required_size = 0; + + if (num_sides == 1) { + uint32_t *opv = ((uint32_t *) top->bytecode); + uint8_t flags = getFlags(*opv); + uint16_t value = getValue(*opv); + + memcpy(((uint8_t *) ret->bytecode) + required_size, + top->bytecode, top->length); + required_size += top->length; + + *opv = buildOPV(CSS_PROP_BORDER_RIGHT_STYLE, flags, value); + memcpy(((uint8_t *) ret->bytecode) + required_size, + top->bytecode, top->length); + required_size += top->length; + + *opv = buildOPV(CSS_PROP_BORDER_BOTTOM_STYLE, flags, value); + memcpy(((uint8_t *) ret->bytecode) + required_size, + top->bytecode, top->length); + required_size += top->length; + + *opv = buildOPV(CSS_PROP_BORDER_LEFT_STYLE, flags, value); + memcpy(((uint8_t *) ret->bytecode) + required_size, + top->bytecode, top->length); + required_size += top->length; + } else if (num_sides == 2) { + uint32_t *vopv = ((uint32_t *) top->bytecode); + uint32_t *hopv = ((uint32_t *) right->bytecode); + uint8_t vflags = getFlags(*vopv); + uint8_t hflags = getFlags(*hopv); + uint16_t vvalue = getValue(*vopv); + uint16_t hvalue = getValue(*hopv); + + memcpy(((uint8_t *) ret->bytecode) + required_size, + top->bytecode, top->length); + required_size += top->length; + + memcpy(((uint8_t *) ret->bytecode) + required_size, + right->bytecode, right->length); + required_size += right->length; + + *vopv = buildOPV(CSS_PROP_BORDER_BOTTOM_STYLE, vflags, vvalue); + memcpy(((uint8_t *) ret->bytecode) + required_size, + top->bytecode, top->length); + required_size += top->length; + + *hopv = buildOPV(CSS_PROP_BORDER_LEFT_STYLE, hflags, hvalue); + memcpy(((uint8_t *) ret->bytecode) + required_size, + right->bytecode, right->length); + required_size += right->length; + } else if (num_sides == 3) { + uint32_t *opv = ((uint32_t *) right->bytecode); + uint8_t flags = getFlags(*opv); + uint16_t value = getValue(*opv); + + memcpy(((uint8_t *) ret->bytecode) + required_size, + top->bytecode, top->length); + required_size += top->length; + + memcpy(((uint8_t *) ret->bytecode) + required_size, + right->bytecode, right->length); + required_size += right->length; + + memcpy(((uint8_t *) ret->bytecode) + required_size, + bottom->bytecode, bottom->length); + required_size += bottom->length; + + *opv = buildOPV(CSS_PROP_BORDER_LEFT_STYLE, flags, value); + memcpy(((uint8_t *) ret->bytecode) + required_size, + right->bytecode, right->length); + required_size += right->length; + } else { + memcpy(((uint8_t *) ret->bytecode) + required_size, + top->bytecode, top->length); + required_size += top->length; + + memcpy(((uint8_t *) ret->bytecode) + required_size, + right->bytecode, right->length); + required_size += right->length; + + memcpy(((uint8_t *) ret->bytecode) + required_size, + bottom->bytecode, bottom->length); + required_size += bottom->length; + + memcpy(((uint8_t *) ret->bytecode) + required_size, + left->bytecode, left->length); + required_size += left->length; + } + + assert(required_size == ret->length); + + /* Write the result */ + *result = ret; + /* Invalidate ret, so that cleanup doesn't destroy it */ + ret = NULL; + + /* Clean up after ourselves */ +cleanup: + if (top) + css_stylesheet_style_destroy(c->sheet, top, error == CSS_OK); + if (right) + css_stylesheet_style_destroy(c->sheet, right, error == CSS_OK); + if (bottom) + css_stylesheet_style_destroy(c->sheet, bottom, error == CSS_OK); + if (left) + css_stylesheet_style_destroy(c->sheet, left, error == CSS_OK); + if (ret) + css_stylesheet_style_destroy(c->sheet, ret, error == CSS_OK); + + if (error != CSS_OK) + *ctx = orig_ctx; + + return error; +} diff --git a/src/parse/properties/border_top.c b/src/parse/properties/border_top.c new file mode 100644 index 0000000..01993d7 --- /dev/null +++ b/src/parse/properties/border_top.c @@ -0,0 +1,35 @@ +/* + * This file is part of LibCSS. + * Licensed under the MIT License, + * http://www.opensource.org/licenses/mit-license.php + * Copyright 2009 John-Mark Bell + */ + +#include +#include + +#include "bytecode/bytecode.h" +#include "bytecode/opcodes.h" +#include "parse/properties/properties.h" +#include "parse/properties/utils.h" + +/** + * Parse border-top shorthand + * + * \param c Parsing context + * \param vector Vector of tokens to process + * \param ctx Pointer to vector iteration context + * \param result Pointer to location to receive resulting style + * \return CSS_OK on success, + * CSS_NOMEM on memory exhaustion, + * CSS_INVALID if the input is not valid + * + * Post condition: \a *ctx is updated with the next token to process + * If the input is invalid, then \a *ctx remains unchanged. + */ +css_error parse_border_top(css_language *c, + const parserutils_vector *vector, int *ctx, + css_style **result) +{ + return parse_border_side(c, vector, ctx, BORDER_SIDE_TOP, result); +} diff --git a/src/parse/properties/border_top_color.c b/src/parse/properties/border_top_color.c new file mode 100644 index 0000000..2d02451 --- /dev/null +++ b/src/parse/properties/border_top_color.c @@ -0,0 +1,36 @@ +/* + * This file is part of LibCSS. + * Licensed under the MIT License, + * http://www.opensource.org/licenses/mit-license.php + * Copyright 2009 John-Mark Bell + */ + +#include +#include + +#include "bytecode/bytecode.h" +#include "bytecode/opcodes.h" +#include "parse/properties/properties.h" +#include "parse/properties/utils.h" + +/** + * Parse border-top-color + * + * \param c Parsing context + * \param vector Vector of tokens to process + * \param ctx Pointer to vector iteration context + * \param result Pointer to location to receive resulting style + * \return CSS_OK on success, + * CSS_NOMEM on memory exhaustion, + * CSS_INVALID if the input is not valid + * + * Post condition: \a *ctx is updated with the next token to process + * If the input is invalid, then \a *ctx remains unchanged. + */ +css_error parse_border_top_color(css_language *c, + const parserutils_vector *vector, int *ctx, + css_style **result) +{ + return parse_border_side_color(c, vector, ctx, + CSS_PROP_BORDER_TOP_COLOR, result); +} diff --git a/src/parse/properties/border_top_style.c b/src/parse/properties/border_top_style.c new file mode 100644 index 0000000..f98b608 --- /dev/null +++ b/src/parse/properties/border_top_style.c @@ -0,0 +1,36 @@ +/* + * This file is part of LibCSS. + * Licensed under the MIT License, + * http://www.opensource.org/licenses/mit-license.php + * Copyright 2009 John-Mark Bell + */ + +#include +#include + +#include "bytecode/bytecode.h" +#include "bytecode/opcodes.h" +#include "parse/properties/properties.h" +#include "parse/properties/utils.h" + +/** + * Parse border-top-style + * + * \param c Parsing context + * \param vector Vector of tokens to process + * \param ctx Pointer to vector iteration context + * \param result Pointer to location to receive resulting style + * \return CSS_OK on success, + * CSS_NOMEM on memory exhaustion, + * CSS_INVALID if the input is not valid + * + * Post condition: \a *ctx is updated with the next token to process + * If the input is invalid, then \a *ctx remains unchanged. + */ +css_error parse_border_top_style(css_language *c, + const parserutils_vector *vector, int *ctx, + css_style **result) +{ + return parse_border_side_style(c, vector, ctx, + CSS_PROP_BORDER_TOP_STYLE, result); +} diff --git a/src/parse/properties/border_top_width.c b/src/parse/properties/border_top_width.c new file mode 100644 index 0000000..d71b39c --- /dev/null +++ b/src/parse/properties/border_top_width.c @@ -0,0 +1,36 @@ +/* + * This file is part of LibCSS. + * Licensed under the MIT License, + * http://www.opensource.org/licenses/mit-license.php + * Copyright 2009 John-Mark Bell + */ + +#include +#include + +#include "bytecode/bytecode.h" +#include "bytecode/opcodes.h" +#include "parse/properties/properties.h" +#include "parse/properties/utils.h" + +/** + * Parse border-top-width + * + * \param c Parsing context + * \param vector Vector of tokens to process + * \param ctx Pointer to vector iteration context + * \param result Pointer to location to receive resulting style + * \return CSS_OK on success, + * CSS_NOMEM on memory exhaustion, + * CSS_INVALID if the input is not valid + * + * Post condition: \a *ctx is updated with the next token to process + * If the input is invalid, then \a *ctx remains unchanged. + */ +css_error parse_border_top_width(css_language *c, + const parserutils_vector *vector, int *ctx, + css_style **result) +{ + return parse_border_side_width(c, vector, ctx, + CSS_PROP_BORDER_TOP_WIDTH, result); +} diff --git a/src/parse/properties/border_width.c b/src/parse/properties/border_width.c new file mode 100644 index 0000000..74d3ee8 --- /dev/null +++ b/src/parse/properties/border_width.c @@ -0,0 +1,266 @@ +/* + * This file is part of LibCSS. + * Licensed under the MIT License, + * http://www.opensource.org/licenses/mit-license.php + * Copyright 2009 John-Mark Bell + */ + +#include +#include + +#include "bytecode/bytecode.h" +#include "bytecode/opcodes.h" +#include "parse/properties/properties.h" +#include "parse/properties/utils.h" + +/** + * Parse border-width shorthand + * + * \param c Parsing context + * \param vector Vector of tokens to process + * \param ctx Pointer to vector iteration context + * \param result Pointer to location to receive resulting style + * \return CSS_OK on success, + * CSS_NOMEM on memory exhaustion, + * CSS_INVALID if the input is not valid + * + * Post condition: \a *ctx is updated with the next token to process + * If the input is invalid, then \a *ctx remains unchanged. + */ +css_error parse_border_width(css_language *c, + const parserutils_vector *vector, int *ctx, + css_style **result) +{ + int orig_ctx = *ctx; + int prev_ctx; + const css_token *token; + css_style *top = NULL; + css_style *right = NULL; + css_style *bottom = NULL; + css_style *left = NULL; + css_style *ret = NULL; + uint32_t num_sides = 0; + uint32_t required_size; + bool match; + css_error error; + + /* Firstly, handle inherit */ + token = parserutils_vector_peek(vector, *ctx); + if (token != NULL && token->type == CSS_TOKEN_IDENT && + (lwc_string_caseless_isequal( + token->idata, c->strings[INHERIT], + &match) == lwc_error_ok && match)) { + uint32_t *bytecode; + + error = css_stylesheet_style_create(c->sheet, + 4 * sizeof(uint32_t), &ret); + if (error != CSS_OK) { + *ctx = orig_ctx; + return error; + } + + bytecode = (uint32_t *) ret->bytecode; + + *(bytecode++) = buildOPV(CSS_PROP_BORDER_TOP_WIDTH, + FLAG_INHERIT, 0); + *(bytecode++) = buildOPV(CSS_PROP_BORDER_RIGHT_WIDTH, + FLAG_INHERIT, 0); + *(bytecode++) = buildOPV(CSS_PROP_BORDER_BOTTOM_WIDTH, + FLAG_INHERIT, 0); + *(bytecode++) = buildOPV(CSS_PROP_BORDER_LEFT_WIDTH, + FLAG_INHERIT, 0); + + parserutils_vector_iterate(vector, ctx); + + *result = ret; + + return CSS_OK; + } else if (token == NULL) { + /* No tokens -- clearly garbage */ + *ctx = orig_ctx; + return CSS_INVALID; + } + + /* Attempt to parse up to 4 widths */ + do { + prev_ctx = *ctx; + error = CSS_OK; + + /* Ensure that we're not about to parse another inherit */ + token = parserutils_vector_peek(vector, *ctx); + if (token != NULL && token->type == CSS_TOKEN_IDENT && + (lwc_string_caseless_isequal( + token->idata, c->strings[INHERIT], + &match) == lwc_error_ok && match)) { + error = CSS_INVALID; + goto cleanup; + } + + if (top == NULL && + (error = parse_border_side_width(c, vector, + ctx, CSS_PROP_BORDER_TOP_WIDTH, &top)) == + CSS_OK) { + num_sides = 1; + } else if (right == NULL && + (error = parse_border_side_width(c, vector, + ctx, CSS_PROP_BORDER_RIGHT_WIDTH, &right)) == + CSS_OK) { + num_sides = 2; + } else if (bottom == NULL && + (error = parse_border_side_width(c, vector, + ctx, CSS_PROP_BORDER_BOTTOM_WIDTH, &bottom)) == + CSS_OK) { + num_sides = 3; + } else if (left == NULL && + (error = parse_border_side_width(c, vector, + ctx, CSS_PROP_BORDER_LEFT_WIDTH, &left)) == + CSS_OK) { + num_sides = 4; + } + + if (error == CSS_OK) { + consumeWhitespace(vector, ctx); + + token = parserutils_vector_peek(vector, *ctx); + } else { + /* Forcibly cause loop to exit */ + token = NULL; + } + } while (*ctx != prev_ctx && token != NULL); + + if (num_sides == 0) { + error = CSS_INVALID; + goto cleanup; + } + + /* Calculate size of resultant style */ + if (num_sides == 1) { + required_size = 4 * top->length; + } else if (num_sides == 2) { + required_size = 2 * top->length + 2 * right->length; + } else if (num_sides == 3) { + required_size = top->length + 2 * right->length + + bottom->length; + } else { + required_size = top->length + right->length + + bottom->length + left->length; + } + + error = css_stylesheet_style_create(c->sheet, required_size, &ret); + if (error != CSS_OK) + goto cleanup; + + required_size = 0; + + if (num_sides == 1) { + uint32_t *opv = ((uint32_t *) top->bytecode); + uint8_t flags = getFlags(*opv); + uint16_t value = getValue(*opv); + + memcpy(((uint8_t *) ret->bytecode) + required_size, + top->bytecode, top->length); + required_size += top->length; + + *opv = buildOPV(CSS_PROP_BORDER_RIGHT_WIDTH, flags, value); + memcpy(((uint8_t *) ret->bytecode) + required_size, + top->bytecode, top->length); + required_size += top->length; + + *opv = buildOPV(CSS_PROP_BORDER_BOTTOM_WIDTH, flags, value); + memcpy(((uint8_t *) ret->bytecode) + required_size, + top->bytecode, top->length); + required_size += top->length; + + *opv = buildOPV(CSS_PROP_BORDER_LEFT_WIDTH, flags, value); + memcpy(((uint8_t *) ret->bytecode) + required_size, + top->bytecode, top->length); + required_size += top->length; + } else if (num_sides == 2) { + uint32_t *vopv = ((uint32_t *) top->bytecode); + uint32_t *hopv = ((uint32_t *) right->bytecode); + uint8_t vflags = getFlags(*vopv); + uint8_t hflags = getFlags(*hopv); + uint16_t vvalue = getValue(*vopv); + uint16_t hvalue = getValue(*hopv); + + memcpy(((uint8_t *) ret->bytecode) + required_size, + top->bytecode, top->length); + required_size += top->length; + + memcpy(((uint8_t *) ret->bytecode) + required_size, + right->bytecode, right->length); + required_size += right->length; + + *vopv = buildOPV(CSS_PROP_BORDER_BOTTOM_WIDTH, vflags, vvalue); + memcpy(((uint8_t *) ret->bytecode) + required_size, + top->bytecode, top->length); + required_size += top->length; + + *hopv = buildOPV(CSS_PROP_BORDER_LEFT_WIDTH, hflags, hvalue); + memcpy(((uint8_t *) ret->bytecode) + required_size, + right->bytecode, right->length); + required_size += right->length; + } else if (num_sides == 3) { + uint32_t *opv = ((uint32_t *) right->bytecode); + uint8_t flags = getFlags(*opv); + uint16_t value = getValue(*opv); + + memcpy(((uint8_t *) ret->bytecode) + required_size, + top->bytecode, top->length); + required_size += top->length; + + memcpy(((uint8_t *) ret->bytecode) + required_size, + right->bytecode, right->length); + required_size += right->length; + + memcpy(((uint8_t *) ret->bytecode) + required_size, + bottom->bytecode, bottom->length); + required_size += bottom->length; + + *opv = buildOPV(CSS_PROP_BORDER_LEFT_WIDTH, flags, value); + memcpy(((uint8_t *) ret->bytecode) + required_size, + right->bytecode, right->length); + required_size += right->length; + } else { + memcpy(((uint8_t *) ret->bytecode) + required_size, + top->bytecode, top->length); + required_size += top->length; + + memcpy(((uint8_t *) ret->bytecode) + required_size, + right->bytecode, right->length); + required_size += right->length; + + memcpy(((uint8_t *) ret->bytecode) + required_size, + bottom->bytecode, bottom->length); + required_size += bottom->length; + + memcpy(((uint8_t *) ret->bytecode) + required_size, + left->bytecode, left->length); + required_size += left->length; + } + + assert(required_size == ret->length); + + /* Write the result */ + *result = ret; + /* Invalidate ret, so that cleanup doesn't destroy it */ + ret = NULL; + + /* Clean up after ourselves */ +cleanup: + if (top) + css_stylesheet_style_destroy(c->sheet, top, error == CSS_OK); + if (right) + css_stylesheet_style_destroy(c->sheet, right, error == CSS_OK); + if (bottom) + css_stylesheet_style_destroy(c->sheet, bottom, error == CSS_OK); + if (left) + css_stylesheet_style_destroy(c->sheet, left, error == CSS_OK); + if (ret) + css_stylesheet_style_destroy(c->sheet, ret, error == CSS_OK); + + if (error != CSS_OK) + *ctx = orig_ctx; + + return error; +} diff --git a/src/parse/properties/bottom.c b/src/parse/properties/bottom.c new file mode 100644 index 0000000..d1e3dc8 --- /dev/null +++ b/src/parse/properties/bottom.c @@ -0,0 +1,35 @@ +/* + * This file is part of LibCSS. + * Licensed under the MIT License, + * http://www.opensource.org/licenses/mit-license.php + * Copyright 2009 John-Mark Bell + */ + +#include +#include + +#include "bytecode/bytecode.h" +#include "bytecode/opcodes.h" +#include "parse/properties/properties.h" +#include "parse/properties/utils.h" + +/** + * Parse bottom + * + * \param c Parsing context + * \param vector Vector of tokens to process + * \param ctx Pointer to vector iteration context + * \param result Pointer to location to receive resulting style + * \return CSS_OK on success, + * CSS_NOMEM on memory exhaustion, + * CSS_INVALID if the input is not valid + * + * Post condition: \a *ctx is updated with the next token to process + * If the input is invalid, then \a *ctx remains unchanged. + */ +css_error parse_bottom(css_language *c, + const parserutils_vector *vector, int *ctx, + css_style **result) +{ + return parse_side(c, vector, ctx, CSS_PROP_BOTTOM, result); +} diff --git a/src/parse/properties/caption_side.c b/src/parse/properties/caption_side.c new file mode 100644 index 0000000..69cc945 --- /dev/null +++ b/src/parse/properties/caption_side.c @@ -0,0 +1,79 @@ +/* + * This file is part of LibCSS. + * Licensed under the MIT License, + * http://www.opensource.org/licenses/mit-license.php + * Copyright 2009 John-Mark Bell + */ + +#include +#include + +#include "bytecode/bytecode.h" +#include "bytecode/opcodes.h" +#include "parse/properties/properties.h" +#include "parse/properties/utils.h" + +/** + * Parse caption-side + * + * \param c Parsing context + * \param vector Vector of tokens to process + * \param ctx Pointer to vector iteration context + * \param result Pointer to location to receive resulting style + * \return CSS_OK on success, + * CSS_NOMEM on memory exhaustion, + * CSS_INVALID if the input is not valid + * + * Post condition: \a *ctx is updated with the next token to process + * If the input is invalid, then \a *ctx remains unchanged. + */ +css_error parse_caption_side(css_language *c, + const parserutils_vector *vector, int *ctx, + css_style **result) +{ + int orig_ctx = *ctx; + css_error error; + const css_token *ident; + uint8_t flags = 0; + uint16_t value = 0; + uint32_t opv; + bool match; + + /* IDENT (top, bottom, inherit) */ + ident = parserutils_vector_iterate(vector, ctx); + if (ident == NULL || ident->type != CSS_TOKEN_IDENT) { + *ctx = orig_ctx; + return CSS_INVALID; + } + + if ((lwc_string_caseless_isequal( + ident->idata, c->strings[INHERIT], + &match) == lwc_error_ok && match)) { + flags |= FLAG_INHERIT; + } else if ((lwc_string_caseless_isequal( + ident->idata, c->strings[TOP], + &match) == lwc_error_ok && match)) { + value = CAPTION_SIDE_TOP; + } else if ((lwc_string_caseless_isequal( + ident->idata, c->strings[BOTTOM], + &match) == lwc_error_ok && match)) { + value = CAPTION_SIDE_BOTTOM; + } else { + *ctx = orig_ctx; + return CSS_INVALID; + } + + opv = buildOPV(CSS_PROP_CAPTION_SIDE, flags, value); + + /* Allocate result */ + error = css_stylesheet_style_create(c->sheet, sizeof(opv), result); + if (error != CSS_OK) { + *ctx = orig_ctx; + return error; + } + + /* Copy the bytecode to it */ + memcpy((*result)->bytecode, &opv, sizeof(opv)); + + return CSS_OK; +} diff --git a/src/parse/properties/clear.c b/src/parse/properties/clear.c new file mode 100644 index 0000000..8673557 --- /dev/null +++ b/src/parse/properties/clear.c @@ -0,0 +1,87 @@ +/* + * This file is part of LibCSS. + * Licensed under the MIT License, + * http://www.opensource.org/licenses/mit-license.php + * Copyright 2009 John-Mark Bell + */ + +#include +#include + +#include "bytecode/bytecode.h" +#include "bytecode/opcodes.h" +#include "parse/properties/properties.h" +#include "parse/properties/utils.h" + +/** + * Parse clear + * + * \param c Parsing context + * \param vector Vector of tokens to process + * \param ctx Pointer to vector iteration context + * \param result Pointer to location to receive resulting style + * \return CSS_OK on success, + * CSS_NOMEM on memory exhaustion, + * CSS_INVALID if the input is not valid + * + * Post condition: \a *ctx is updated with the next token to process + * If the input is invalid, then \a *ctx remains unchanged. + */ +css_error parse_clear(css_language *c, + const parserutils_vector *vector, int *ctx, + css_style **result) +{ + int orig_ctx = *ctx; + css_error error; + const css_token *ident; + uint8_t flags = 0; + uint16_t value = 0; + uint32_t opv; + bool match; + + /* IDENT (left, right, both, none, inherit) */ + ident = parserutils_vector_iterate(vector, ctx); + if (ident == NULL || ident->type != CSS_TOKEN_IDENT) { + *ctx = orig_ctx; + return CSS_INVALID; + } + + if ((lwc_string_caseless_isequal( + ident->idata, c->strings[INHERIT], + &match) == lwc_error_ok && match)) { + flags |= FLAG_INHERIT; + } else if ((lwc_string_caseless_isequal( + ident->idata, c->strings[RIGHT], + &match) == lwc_error_ok && match)) { + value = CLEAR_RIGHT; + } else if ((lwc_string_caseless_isequal( + ident->idata, c->strings[LEFT], + &match) == lwc_error_ok && match)) { + value = CLEAR_LEFT; + } else if ((lwc_string_caseless_isequal( + ident->idata, c->strings[BOTH], + &match) == lwc_error_ok && match)) { + value = CLEAR_BOTH; + } else if ((lwc_string_caseless_isequal( + ident->idata, c->strings[NONE], + &match) == lwc_error_ok && match)) { + value = CLEAR_NONE; + } else { + *ctx = orig_ctx; + return CSS_INVALID; + } + + opv = buildOPV(CSS_PROP_CLEAR, flags, value); + + /* Allocate result */ + error = css_stylesheet_style_create(c->sheet, sizeof(opv), result); + if (error != CSS_OK) { + *ctx = orig_ctx; + return error; + } + + /* Copy the bytecode to it */ + memcpy((*result)->bytecode, &opv, sizeof(opv)); + + return CSS_OK; +} diff --git a/src/parse/properties/clip.c b/src/parse/properties/clip.c new file mode 100644 index 0000000..dce2915 --- /dev/null +++ b/src/parse/properties/clip.c @@ -0,0 +1,176 @@ +/* + * This file is part of LibCSS. + * Licensed under the MIT License, + * http://www.opensource.org/licenses/mit-license.php + * Copyright 2009 John-Mark Bell + */ + +#include +#include + +#include "bytecode/bytecode.h" +#include "bytecode/opcodes.h" +#include "parse/properties/properties.h" +#include "parse/properties/utils.h" + +/** + * Parse clip + * + * \param c Parsing context + * \param vector Vector of tokens to process + * \param ctx Pointer to vector iteration context + * \param result Pointer to location to receive resulting style + * \return CSS_OK on success, + * CSS_NOMEM on memory exhaustion, + * CSS_INVALID if the input is not valid + * + * Post condition: \a *ctx is updated with the next token to process + * If the input is invalid, then \a *ctx remains unchanged. + */ +css_error parse_clip(css_language *c, + const parserutils_vector *vector, int *ctx, + css_style **result) +{ + int orig_ctx = *ctx; + css_error error; + const css_token *token; + uint8_t flags = 0; + uint16_t value = 0; + uint32_t opv; + int num_lengths = 0; + css_fixed length[4] = { 0 }; + uint32_t unit[4] = { 0 }; + uint32_t required_size; + bool match; + + /* FUNCTION(rect) [ [ IDENT(auto) | length ] CHAR(,)? ]{3} + * [ IDENT(auto) | length ] CHAR{)} | + * IDENT(auto, inherit) */ + token = parserutils_vector_iterate(vector, ctx); + if (token == NULL) { + *ctx = orig_ctx; + return CSS_INVALID; + } + + if (token->type == CSS_TOKEN_IDENT && + (lwc_string_caseless_isequal( + token->idata, c->strings[INHERIT], + &match) == lwc_error_ok && match)) { + flags = FLAG_INHERIT; + } else if (token->type == CSS_TOKEN_IDENT && + (lwc_string_caseless_isequal( + token->idata, c->strings[AUTO], + &match) == lwc_error_ok && match)) { + value = CLIP_AUTO; + } else if (token->type == CSS_TOKEN_FUNCTION && + (lwc_string_caseless_isequal( + token->idata, c->strings[RECT], + &match) == lwc_error_ok && match)) { + int i; + value = CLIP_SHAPE_RECT; + + for (i = 0; i < 4; i++) { + consumeWhitespace(vector, ctx); + + token = parserutils_vector_peek(vector, *ctx); + if (token == NULL) { + *ctx = orig_ctx; + return CSS_INVALID; + } + + if (token->type == CSS_TOKEN_IDENT) { + /* Slightly magical way of generating the auto + * values. These are bits 3-6 of the value. */ + if ((lwc_string_caseless_isequal( + token->idata, c->strings[AUTO], + &match) == lwc_error_ok && + match)) + value |= 1 << (i + 3); + else { + *ctx = orig_ctx; + return CSS_INVALID; + } + + parserutils_vector_iterate(vector, ctx); + } else { + error = parse_unit_specifier(c, vector, ctx, + UNIT_PX, + &length[num_lengths], + &unit[num_lengths]); + if (error != CSS_OK) { + *ctx = orig_ctx; + return error; + } + + if (unit[num_lengths] & UNIT_ANGLE || + unit[num_lengths] & UNIT_TIME || + unit[num_lengths] & UNIT_FREQ || + unit[num_lengths] & UNIT_PCT) { + *ctx = orig_ctx; + return CSS_INVALID; + } + + num_lengths++; + } + + consumeWhitespace(vector, ctx); + + /* Consume optional comma after first 3 parameters */ + if (i < 3) { + token = parserutils_vector_peek(vector, *ctx); + if (token == NULL) { + *ctx = orig_ctx; + return CSS_INVALID; + } + + if (tokenIsChar(token, ',')) + parserutils_vector_iterate(vector, ctx); + } + } + + consumeWhitespace(vector, ctx); + + /* Finally, consume closing parenthesis */ + token = parserutils_vector_iterate(vector, ctx); + if (token == NULL || tokenIsChar(token, ')') == false) { + *ctx = orig_ctx; + return CSS_INVALID; + } + } else { + *ctx = orig_ctx; + return CSS_INVALID; + } + + opv = buildOPV(CSS_PROP_CLIP, flags, value); + + required_size = sizeof(opv); + if ((flags & FLAG_INHERIT) == false && + (value & CLIP_SHAPE_MASK) == CLIP_SHAPE_RECT) { + required_size += + num_lengths * (sizeof(length[0]) + sizeof(unit[0])); + } + + /* Allocate result */ + error = css_stylesheet_style_create(c->sheet, required_size, result); + if (error != CSS_OK) { + *ctx = orig_ctx; + return error; + } + + /* Copy the bytecode to it */ + memcpy((*result)->bytecode, &opv, sizeof(opv)); + if ((flags & FLAG_INHERIT) == false && + (value & CLIP_SHAPE_MASK) == CLIP_SHAPE_RECT) { + int i; + uint8_t *ptr = ((uint8_t *) (*result)->bytecode) + sizeof(opv); + + for (i = 0; i < num_lengths; i++) { + memcpy(ptr, &length[i], sizeof(length[i])); + ptr += sizeof(length[i]); + memcpy(ptr, &unit[i], sizeof(unit[i])); + ptr += sizeof(unit[i]); + } + } + + return CSS_OK; +} diff --git a/src/parse/properties/color.c b/src/parse/properties/color.c new file mode 100644 index 0000000..f809518 --- /dev/null +++ b/src/parse/properties/color.c @@ -0,0 +1,88 @@ +/* + * This file is part of LibCSS. + * Licensed under the MIT License, + * http://www.opensource.org/licenses/mit-license.php + * Copyright 2009 John-Mark Bell + */ + +#include +#include + +#include "bytecode/bytecode.h" +#include "bytecode/opcodes.h" +#include "parse/properties/properties.h" +#include "parse/properties/utils.h" + +/** + * Parse color + * + * \param c Parsing context + * \param vector Vector of tokens to process + * \param ctx Pointer to vector iteration context + * \param result Pointer to location to receive resulting style + * \return CSS_OK on success, + * CSS_NOMEM on memory exhaustion, + * CSS_INVALID if the input is not valid + * + * Post condition: \a *ctx is updated with the next token to process + * If the input is invalid, then \a *ctx remains unchanged. + */ +css_error parse_color(css_language *c, + const parserutils_vector *vector, int *ctx, + css_style **result) +{ + int orig_ctx = *ctx; + css_error error; + const css_token *token; + uint8_t flags = 0; + uint16_t value = 0; + uint32_t opv; + uint32_t colour = 0; + uint32_t required_size; + bool match; + + /* colour | IDENT (inherit) */ + token= parserutils_vector_peek(vector, *ctx); + if (token == NULL) { + *ctx = orig_ctx; + return CSS_INVALID; + } + + if (token->type == CSS_TOKEN_IDENT && + (lwc_string_caseless_isequal( + token->idata, c->strings[INHERIT], + &match) == lwc_error_ok && match)) { + parserutils_vector_iterate(vector, ctx); + flags |= FLAG_INHERIT; + } else { + error = parse_colour_specifier(c, vector, ctx, &colour); + if (error != CSS_OK) { + *ctx = orig_ctx; + return error; + } + + value = COLOR_SET; + } + + opv = buildOPV(CSS_PROP_COLOR, flags, value); + + required_size = sizeof(opv); + if ((flags & FLAG_INHERIT) == false && value == COLOR_SET) + required_size += sizeof(colour); + + /* Allocate result */ + error = css_stylesheet_style_create(c->sheet, required_size, result); + if (error != CSS_OK) { + *ctx = orig_ctx; + return error; + } + + /* Copy the bytecode to it */ + memcpy((*result)->bytecode, &opv, sizeof(opv)); + if ((flags & FLAG_INHERIT) == false && value == COLOR_SET) { + memcpy(((uint8_t *) (*result)->bytecode) + sizeof(opv), + &colour, sizeof(colour)); + } + + return CSS_OK; +} diff --git a/src/parse/properties/content.c b/src/parse/properties/content.c new file mode 100644 index 0000000..7f37400 --- /dev/null +++ b/src/parse/properties/content.c @@ -0,0 +1,134 @@ +/* + * This file is part of LibCSS. + * Licensed under the MIT License, + * http://www.opensource.org/licenses/mit-license.php + * Copyright 2009 John-Mark Bell + */ + +#include +#include + +#include "bytecode/bytecode.h" +#include "bytecode/opcodes.h" +#include "parse/properties/properties.h" +#include "parse/properties/utils.h" + +/** + * Parse content + * + * \param c Parsing context + * \param vector Vector of tokens to process + * \param ctx Pointer to vector iteration context + * \param result Pointer to location to receive resulting style + * \return CSS_OK on success, + * CSS_NOMEM on memory exhaustion, + * CSS_INVALID if the input is not valid + * + * Post condition: \a *ctx is updated with the next token to process + * If the input is invalid, then \a *ctx remains unchanged. + */ +css_error parse_content(css_language *c, + const parserutils_vector *vector, int *ctx, + css_style **result) +{ + int orig_ctx = *ctx; + css_error error; + const css_token *token; + uint8_t flags = 0; + uint16_t value = 0; + uint32_t opv; + uint32_t required_size = sizeof(opv); + int temp_ctx = *ctx; + uint8_t *ptr; + bool match; + + /* IDENT(normal, none, inherit) | + * [ + * IDENT(open-quote, close-quote, no-open-quote, no-close-quote) | + * STRING | URI | + * FUNCTION(attr) IDENT ')' | + * FUNCTION(counter) IDENT IDENT? ')' | + * FUNCTION(counters) IDENT STRING IDENT? ')' + * ]+ + */ + + /* Pass 1: Calculate required size & validate input */ + token = parserutils_vector_peek(vector, temp_ctx); + if (token == NULL) { + *ctx = orig_ctx; + return CSS_INVALID; + } + + if (token->type == CSS_TOKEN_IDENT && + (lwc_string_caseless_isequal( + token->idata, c->strings[INHERIT], + &match) == lwc_error_ok && match)) { + flags = FLAG_INHERIT; + parserutils_vector_iterate(vector, &temp_ctx); + } else if (token->type == CSS_TOKEN_IDENT && + (lwc_string_caseless_isequal( + token->idata, c->strings[NORMAL], + &match) == lwc_error_ok && match)) { + value = CONTENT_NORMAL; + parserutils_vector_iterate(vector, &temp_ctx); + } else if (token->type == CSS_TOKEN_IDENT && + (lwc_string_caseless_isequal( + token->idata, c->strings[NONE], + &match) == lwc_error_ok && match)) { + value = CONTENT_NONE; + parserutils_vector_iterate(vector, &temp_ctx); + } else { + uint32_t len; + + error = parse_content_list(c, vector, &temp_ctx, &value, + NULL, &len); + if (error != CSS_OK) { + *ctx = orig_ctx; + return error; + } + + required_size += len; + } + + opv = buildOPV(CSS_PROP_CONTENT, flags, value); + + /* Allocate result */ + error = css_stylesheet_style_create(c->sheet, required_size, result); + if (error != CSS_OK) { + *ctx = orig_ctx; + return error; + } + + /* Copy OPV to bytecode */ + ptr = (*result)->bytecode; + memcpy(ptr, &opv, sizeof(opv)); + ptr += sizeof(opv); + + /* Pass 2: construct bytecode */ + token = parserutils_vector_peek(vector, *ctx); + if (token == NULL) { + *ctx = orig_ctx; + return CSS_INVALID; + } + + if (token->type == CSS_TOKEN_IDENT && + ((lwc_string_caseless_isequal( + token->idata, c->strings[INHERIT], + &match) == lwc_error_ok && match) || + (lwc_string_caseless_isequal( + token->idata, c->strings[NORMAL], + &match) == lwc_error_ok && match) || + (lwc_string_caseless_isequal( + token->idata, c->strings[NONE], + &match) == lwc_error_ok && match))) { + parserutils_vector_iterate(vector, ctx); + } else { + error = parse_content_list(c, vector, ctx, NULL, ptr, NULL); + if (error != CSS_OK) { + *ctx = orig_ctx; + return error; + } + } + + return CSS_OK; +} diff --git a/src/parse/properties/conter_reset.c b/src/parse/properties/conter_reset.c new file mode 100644 index 0000000..74f8f36 --- /dev/null +++ b/src/parse/properties/conter_reset.c @@ -0,0 +1,36 @@ +/* + * This file is part of LibCSS. + * Licensed under the MIT License, + * http://www.opensource.org/licenses/mit-license.php + * Copyright 2009 John-Mark Bell + */ + +#include +#include + +#include "bytecode/bytecode.h" +#include "bytecode/opcodes.h" +#include "parse/properties/properties.h" +#include "parse/properties/utils.h" + +/** + * Parse counter-reset + * + * \param c Parsing context + * \param vector Vector of tokens to process + * \param ctx Pointer to vector iteration context + * \param result Pointer to location to receive resulting style + * \return CSS_OK on success, + * CSS_NOMEM on memory exhaustion, + * CSS_INVALID if the input is not valid + * + * Post condition: \a *ctx is updated with the next token to process + * If the input is invalid, then \a *ctx remains unchanged. + */ +css_error parse_counter_reset(css_language *c, + const parserutils_vector *vector, int *ctx, + css_style **result) +{ + return parse_counter_common(c, vector, ctx, + CSS_PROP_COUNTER_RESET, result); +} diff --git a/src/parse/properties/counter_increment.c b/src/parse/properties/counter_increment.c new file mode 100644 index 0000000..b5ea5e6 --- /dev/null +++ b/src/parse/properties/counter_increment.c @@ -0,0 +1,36 @@ +/* + * This file is part of LibCSS. + * Licensed under the MIT License, + * http://www.opensource.org/licenses/mit-license.php + * Copyright 2009 John-Mark Bell + */ + +#include +#include + +#include "bytecode/bytecode.h" +#include "bytecode/opcodes.h" +#include "parse/properties/properties.h" +#include "parse/properties/utils.h" + +/** + * Parse counter-increment + * + * \param c Parsing context + * \param vector Vector of tokens to process + * \param ctx Pointer to vector iteration context + * \param result Pointer to location to receive resulting style + * \return CSS_OK on success, + * CSS_NOMEM on memory exhaustion, + * CSS_INVALID if the input is not valid + * + * Post condition: \a *ctx is updated with the next token to process + * If the input is invalid, then \a *ctx remains unchanged. + */ +css_error parse_counter_increment(css_language *c, + const parserutils_vector *vector, int *ctx, + css_style **result) +{ + return parse_counter_common(c, vector, ctx, + CSS_PROP_COUNTER_INCREMENT, result); +} diff --git a/src/parse/properties/cue.c b/src/parse/properties/cue.c new file mode 100644 index 0000000..982405f --- /dev/null +++ b/src/parse/properties/cue.c @@ -0,0 +1,298 @@ +/* + * This file is part of LibCSS. + * Licensed under the MIT License, + * http://www.opensource.org/licenses/mit-license.php + * Copyright 2009 John-Mark Bell + */ + +#include +#include + +#include "bytecode/bytecode.h" +#include "bytecode/opcodes.h" +#include "parse/properties/properties.h" +#include "parse/properties/utils.h" + +/** + * Common parser for cue-after and cue-before + * + * \param c Parsing context + * \param vector Vector of tokens to process + * \param ctx Pointer to vector iteration context + * \param op Opcode to parse for + * \param result Pointer to location to receive resulting style + * \return CSS_OK on success, + * CSS_NOMEM on memory exhaustion, + * CSS_INVALID if the input is not valid + * + * Post condition: \a *ctx is updated with the next token to process + * If the input is invalid, then \a *ctx remains unchanged. + */ +static css_error parse_cue_common(css_language *c, + const parserutils_vector *vector, int *ctx, + uint16_t op, css_style **result) +{ + int orig_ctx = *ctx; + css_error error; + const css_token *token; + uint8_t flags = 0; + uint16_t value = 0; + uint32_t opv; + uint32_t required_size; + lwc_string *uri = NULL; + bool match; + + /* URI | IDENT (none, inherit) */ + token = parserutils_vector_iterate(vector, ctx); + if (token == NULL || (token->type != CSS_TOKEN_IDENT && + token->type != CSS_TOKEN_URI)) { + *ctx = orig_ctx; + return CSS_INVALID; + } + + if (token->type == CSS_TOKEN_IDENT && + (lwc_string_caseless_isequal( + token->idata, c->strings[INHERIT], + &match) == lwc_error_ok && match)) { + flags |= FLAG_INHERIT; + } else if (token->type == CSS_TOKEN_IDENT && + (lwc_string_caseless_isequal( + token->idata, c->strings[NONE], + &match) == lwc_error_ok && match)) { + value = CUE_AFTER_NONE; + } else if (token->type == CSS_TOKEN_URI) { + value = CUE_AFTER_URI; + + error = c->sheet->resolve(c->sheet->resolve_pw, + c->sheet->url, + token->idata, &uri); + if (error != CSS_OK) { + *ctx = orig_ctx; + return error; + } + } else { + *ctx = orig_ctx; + return CSS_INVALID; + } + + opv = buildOPV(op, flags, value); + + required_size = sizeof(opv); + if ((flags & FLAG_INHERIT) == false && value == CUE_AFTER_URI) + required_size += sizeof(lwc_string *); + + /* Allocate result */ + error = css_stylesheet_style_create(c->sheet, required_size, result); + if (error != CSS_OK) { + *ctx = orig_ctx; + return error; + } + + /* Copy the bytecode to it */ + memcpy((*result)->bytecode, &opv, sizeof(opv)); + if ((flags & FLAG_INHERIT) == false && value == CUE_AFTER_URI) { + /* Don't ref URI -- we want to pass ownership to the bytecode */ + memcpy((uint8_t *) (*result)->bytecode + sizeof(opv), + &uri, sizeof(lwc_string *)); + } + + return CSS_OK; +} + +/** + * Parse cue-after + * + * \param c Parsing context + * \param vector Vector of tokens to process + * \param ctx Pointer to vector iteration context + * \param result Pointer to location to receive resulting style + * \return CSS_OK on success, + * CSS_NOMEM on memory exhaustion, + * CSS_INVALID if the input is not valid + * + * Post condition: \a *ctx is updated with the next token to process + * If the input is invalid, then \a *ctx remains unchanged. + */ +css_error parse_cue_after(css_language *c, + const parserutils_vector *vector, int *ctx, + css_style **result) +{ + return parse_cue_common(c, vector, ctx, CSS_PROP_CUE_AFTER, result); +} + +/** + * Parse cue-before + * + * \param c Parsing context + * \param vector Vector of tokens to process + * \param ctx Pointer to vector iteration context + * \param result Pointer to location to receive resulting style + * \return CSS_OK on success, + * CSS_NOMEM on memory exhaustion, + * CSS_INVALID if the input is not valid + * + * Post condition: \a *ctx is updated with the next token to process + * If the input is invalid, then \a *ctx remains unchanged. + */ +css_error parse_cue_before(css_language *c, + const parserutils_vector *vector, int *ctx, + css_style **result) +{ + return parse_cue_common(c, vector, ctx, CSS_PROP_CUE_BEFORE, result); +} + +/** + * Parse cue shorthand + * + * \param c Parsing context + * \param vector Vector of tokens to process + * \param ctx Pointer to vector iteration context + * \param result Pointer to location to receive resulting style + * \return CSS_OK on success, + * CSS_NOMEM on memory exhaustion, + * CSS_INVALID if the input is not valid + * + * Post condition: \a *ctx is updated with the next token to process + * If the input is invalid, then \a *ctx remains unchanged. + */ +css_error parse_cue(css_language *c, + const parserutils_vector *vector, int *ctx, + css_style **result) +{ + int orig_ctx = *ctx; + const css_token *token; + css_style *before = NULL; + css_style *after = NULL; + css_style *ret = NULL; + int num_read = 0; + int prev_ctx; + uint32_t required_size; + bool match; + css_error error; + + /* Deal with inherit */ + token = parserutils_vector_peek(vector, *ctx); + if (token != NULL && token->type == CSS_TOKEN_IDENT && + (lwc_string_caseless_isequal( + token->idata, c->strings[INHERIT], + &match) == lwc_error_ok && match)) { + uint32_t *bytecode; + + error = css_stylesheet_style_create(c->sheet, + 2 * sizeof(uint32_t), &ret); + if (error != CSS_OK) { + *ctx = orig_ctx; + return error; + } + + bytecode = (uint32_t *) ret->bytecode; + + *(bytecode++) = buildOPV(CSS_PROP_CUE_BEFORE, FLAG_INHERIT, 0); + *(bytecode++) = buildOPV(CSS_PROP_CUE_AFTER, FLAG_INHERIT, 0); + + parserutils_vector_iterate(vector, ctx); + + *result = ret; + + return CSS_OK; + } else if (token == NULL) { + /* No tokens -- clearly garbage */ + *ctx = orig_ctx; + return CSS_INVALID; + } + + /* Attempt to read 1 or 2 cues */ + do { + prev_ctx = *ctx; + error = CSS_OK; + + /* Ensure that we're not about to parse another inherit */ + token = parserutils_vector_peek(vector, *ctx); + if (token != NULL && token->type == CSS_TOKEN_IDENT && + (lwc_string_caseless_isequal( + token->idata, c->strings[INHERIT], + &match) == lwc_error_ok && match)) { + error = CSS_INVALID; + goto cleanup; + } + + if (before == NULL && (error = parse_cue_before(c, vector, ctx, + &before)) == CSS_OK) { + num_read = 1; + } else if (after == NULL && + (error = parse_cue_after(c, vector, ctx, + &after)) == CSS_OK) { + num_read = 2; + } + + if (error == CSS_OK) { + consumeWhitespace(vector, ctx); + + token = parserutils_vector_peek(vector, *ctx); + } else { + token = NULL; + } + } while (*ctx != prev_ctx && token != NULL); + + if (num_read == 0) { + error = CSS_INVALID; + goto cleanup; + } + + /* Calculate size of resultant style */ + if (num_read == 1) + required_size = 2 * before->length; + else + required_size = before->length + after->length; + + error = css_stylesheet_style_create(c->sheet, required_size, &ret); + if (error != CSS_OK) + goto cleanup; + + required_size = 0; + + if (num_read == 1) { + uint32_t *opv = ((uint32_t *) before->bytecode); + uint8_t flags = getFlags(*opv); + uint16_t value = getValue(*opv); + + memcpy(((uint8_t *) ret->bytecode) + required_size, + before->bytecode, before->length); + required_size += before->length; + + *opv = buildOPV(CSS_PROP_CUE_AFTER, flags, value); + memcpy(((uint8_t *) ret->bytecode) + required_size, + before->bytecode, before->length); + required_size += before->length; + } else { + memcpy(((uint8_t *) ret->bytecode) + required_size, + before->bytecode, before->length); + required_size += before->length; + + memcpy(((uint8_t *) ret->bytecode) + required_size, + after->bytecode, after->length); + required_size += after->length; + } + + assert(required_size == ret->length); + + /* Write the result */ + *result = ret; + /* Invalidate ret so that cleanup doesn't destroy it */ + ret = NULL; + + /* Clean up after ourselves */ +cleanup: + if (before) + css_stylesheet_style_destroy(c->sheet, before, error == CSS_OK); + if (after) + css_stylesheet_style_destroy(c->sheet, after, error == CSS_OK); + if (ret) + css_stylesheet_style_destroy(c->sheet, ret, error == CSS_OK); + + if (error != CSS_OK) + *ctx = orig_ctx; + + return error; +} + diff --git a/src/parse/properties/cursor.c b/src/parse/properties/cursor.c new file mode 100644 index 0000000..725e7b7 --- /dev/null +++ b/src/parse/properties/cursor.c @@ -0,0 +1,373 @@ +/* + * This file is part of LibCSS. + * Licensed under the MIT License, + * http://www.opensource.org/licenses/mit-license.php + * Copyright 2009 John-Mark Bell + */ + +#include + +#include "bytecode/bytecode.h" +#include "bytecode/opcodes.h" +#include "parse/properties/properties.h" +#include "parse/properties/utils.h" + +/** + * Parse cursor + * + * \param c Parsing context + * \param vector Vector of tokens to process + * \param ctx Pointer to vector iteration context + * \param result Pointer to location to receive resulting style + * \return CSS_OK on success, + * CSS_NOMEM on memory exhaustion, + * CSS_INVALID if the input is not valid + * + * Post condition: \a *ctx is updated with the next token to process + * If the input is invalid, then \a *ctx remains unchanged. + */ +css_error parse_cursor(css_language *c, + const parserutils_vector *vector, int *ctx, + css_style **result) +{ + int orig_ctx = *ctx; + css_error error; + const css_token *token; + uint8_t flags = 0; + uint16_t value = 0; + uint32_t opv; + uint32_t required_size = sizeof(opv); + int temp_ctx = *ctx; + uint8_t *ptr; + bool match; + + /* [ (URI ',')* IDENT(auto, crosshair, default, pointer, move, e-resize, + * ne-resize, nw-resize, n-resize, se-resize, sw-resize, + * s-resize, w-resize, text, wait, help, progress) ] + * | IDENT(inherit) + */ + + /* Pass 1: validate input and calculate bytecode size */ + token = parserutils_vector_iterate(vector, &temp_ctx); + if (token == NULL || (token->type != CSS_TOKEN_IDENT && + token->type != CSS_TOKEN_URI)) { + *ctx = orig_ctx; + return CSS_INVALID; + } + + if (token->type == CSS_TOKEN_IDENT && + (lwc_string_caseless_isequal( + token->idata, c->strings[INHERIT], + &match) == lwc_error_ok && match)) { + flags = FLAG_INHERIT; + } else { + bool first = true; + + /* URI* */ + while (token != NULL && token->type == CSS_TOKEN_URI) { + lwc_string *uri = token->idata; + + if (first == false) { + required_size += sizeof(opv); + } else { + value = CURSOR_URI; + } + required_size += sizeof(uri); + + consumeWhitespace(vector, &temp_ctx); + + /* Expect ',' */ + token = parserutils_vector_iterate(vector, &temp_ctx); + if (token == NULL || tokenIsChar(token, ',') == false) { + *ctx = orig_ctx; + return CSS_INVALID; + } + + consumeWhitespace(vector, &temp_ctx); + + /* Expect either URI or IDENT */ + token = parserutils_vector_iterate(vector, &temp_ctx); + if (token == NULL || (token->type != CSS_TOKEN_IDENT && + token->type != CSS_TOKEN_URI)) { + *ctx = orig_ctx; + return CSS_INVALID; + } + + first = false; + } + + /* IDENT */ + if (token != NULL && token->type == CSS_TOKEN_IDENT) { + if ((lwc_string_caseless_isequal( + token->idata, c->strings[AUTO], + &match) == lwc_error_ok && match)) { + if (first) { + value = CURSOR_AUTO; + } + } else if ((lwc_string_caseless_isequal( + token->idata, c->strings[CROSSHAIR], + &match) == lwc_error_ok && match)) { + if (first) { + value = CURSOR_CROSSHAIR; + } + } else if ((lwc_string_caseless_isequal( + token->idata, c->strings[DEFAULT], + &match) == lwc_error_ok && match)) { + if (first) { + value = CURSOR_DEFAULT; + } + } else if ((lwc_string_caseless_isequal( + token->idata, c->strings[POINTER], + &match) == lwc_error_ok && match)) { + if (first) { + value = CURSOR_POINTER; + } + } else if ((lwc_string_caseless_isequal( + token->idata, c->strings[MOVE], + &match) == lwc_error_ok && match)) { + if (first) { + value = CURSOR_MOVE; + } + } else if ((lwc_string_caseless_isequal( + token->idata, c->strings[E_RESIZE], + &match) == lwc_error_ok && match)) { + if (first) { + value = CURSOR_E_RESIZE; + } + } else if ((lwc_string_caseless_isequal( + token->idata, c->strings[NE_RESIZE], + &match) == lwc_error_ok && match)) { + if (first) { + value = CURSOR_NE_RESIZE; + } + } else if ((lwc_string_caseless_isequal( + token->idata, c->strings[NW_RESIZE], + &match) == lwc_error_ok && match)) { + if (first) { + value = CURSOR_NW_RESIZE; + } + } else if ((lwc_string_caseless_isequal( + token->idata, c->strings[N_RESIZE], + &match) == lwc_error_ok && match)) { + if (first) { + value = CURSOR_N_RESIZE; + } + } else if ((lwc_string_caseless_isequal( + token->idata, c->strings[SE_RESIZE], + &match) == lwc_error_ok && match)) { + if (first) { + value = CURSOR_SE_RESIZE; + } + } else if ((lwc_string_caseless_isequal( + token->idata, c->strings[SW_RESIZE], + &match) == lwc_error_ok && match)) { + if (first) { + value = CURSOR_SW_RESIZE; + } + } else if ((lwc_string_caseless_isequal( + token->idata, c->strings[S_RESIZE], + &match) == lwc_error_ok && match)) { + if (first) { + value = CURSOR_S_RESIZE; + } + } else if ((lwc_string_caseless_isequal( + token->idata, c->strings[W_RESIZE], + &match) == lwc_error_ok && match)) { + if (first) { + value = CURSOR_W_RESIZE; + } + } else if ((lwc_string_caseless_isequal( + token->idata, c->strings[LIBCSS_TEXT], + &match) == lwc_error_ok && match)) { + if (first) { + value = CURSOR_TEXT; + } + } else if ((lwc_string_caseless_isequal( + token->idata, c->strings[WAIT], + &match) == lwc_error_ok && match)) { + if (first) { + value = CURSOR_WAIT; + } + } else if ((lwc_string_caseless_isequal( + token->idata, c->strings[HELP], + &match) == lwc_error_ok && match)) { + if (first) { + value = CURSOR_HELP; + } + } else if ((lwc_string_caseless_isequal( + token->idata, c->strings[PROGRESS], + &match) == lwc_error_ok && match)) { + if (first) { + value = CURSOR_PROGRESS; + } + } else { + *ctx = orig_ctx; + return CSS_INVALID; + } + + if (first == false) { + required_size += sizeof(opv); + } + } + } + + opv = buildOPV(CSS_PROP_CURSOR, flags, value); + + /* Allocate result */ + error = css_stylesheet_style_create(c->sheet, required_size, result); + if (error != CSS_OK) { + *ctx = orig_ctx; + return error; + } + + /* Copy OPV to bytecode */ + ptr = (*result)->bytecode; + memcpy(ptr, &opv, sizeof(opv)); + ptr += sizeof(opv); + + /* Pass 2: construct bytecode */ + token = parserutils_vector_iterate(vector, ctx); + if (token == NULL || (token->type != CSS_TOKEN_IDENT && + token->type != CSS_TOKEN_URI)) { + *ctx = orig_ctx; + return CSS_INVALID; + } + + if (token->type == CSS_TOKEN_IDENT && + (lwc_string_caseless_isequal( + token->idata, c->strings[INHERIT], + &match) == lwc_error_ok && match)) { + /* Nothing to do */ + } else { + bool first = true; + + /* URI* */ + while (token != NULL && token->type == CSS_TOKEN_URI) { + lwc_string *uri; + + error = c->sheet->resolve(c->sheet->resolve_pw, + c->sheet->url, + token->idata, &uri); + if (error != CSS_OK) { + *ctx = orig_ctx; + return error; + } + + if (first == false) { + opv = CURSOR_URI; + memcpy(ptr, &opv, sizeof(opv)); + ptr += sizeof(opv); + } + + /* Don't ref URI -- we want to pass ownership to the + * bytecode */ + memcpy(ptr, &uri, sizeof(uri)); + ptr += sizeof(uri); + + consumeWhitespace(vector, ctx); + + /* Expect ',' */ + token = parserutils_vector_iterate(vector, ctx); + if (token == NULL || tokenIsChar(token, ',') == false) { + *ctx = orig_ctx; + return CSS_INVALID; + } + + consumeWhitespace(vector, ctx); + + /* Expect either URI or IDENT */ + token = parserutils_vector_iterate(vector, ctx); + if (token == NULL || (token->type != CSS_TOKEN_IDENT && + token->type != CSS_TOKEN_URI)) { + *ctx = orig_ctx; + return CSS_INVALID; + } + + first = false; + } + + /* IDENT */ + if (token != NULL && token->type == CSS_TOKEN_IDENT) { + if ((lwc_string_caseless_isequal( + token->idata, c->strings[AUTO], + &match) == lwc_error_ok && match)) { + opv = CURSOR_AUTO; + } else if ((lwc_string_caseless_isequal( + token->idata, c->strings[CROSSHAIR], + &match) == lwc_error_ok && match)) { + opv = CURSOR_CROSSHAIR; + } else if ((lwc_string_caseless_isequal( + token->idata, c->strings[DEFAULT], + &match) == lwc_error_ok && match)) { + opv = CURSOR_DEFAULT; + } else if ((lwc_string_caseless_isequal( + token->idata, c->strings[POINTER], + &match) == lwc_error_ok && match)) { + opv = CURSOR_POINTER; + } else if ((lwc_string_caseless_isequal( + token->idata, c->strings[MOVE], + &match) == lwc_error_ok && match)) { + opv = CURSOR_MOVE; + } else if ((lwc_string_caseless_isequal( + token->idata, c->strings[E_RESIZE], + &match) == lwc_error_ok && match)) { + opv = CURSOR_E_RESIZE; + } else if ((lwc_string_caseless_isequal( + token->idata, c->strings[NE_RESIZE], + &match) == lwc_error_ok && match)) { + opv = CURSOR_NE_RESIZE; + } else if ((lwc_string_caseless_isequal( + token->idata, c->strings[NW_RESIZE], + &match) == lwc_error_ok && match)) { + opv = CURSOR_NW_RESIZE; + } else if ((lwc_string_caseless_isequal( + token->idata, c->strings[N_RESIZE], + &match) == lwc_error_ok && match)) { + opv = CURSOR_N_RESIZE; + } else if ((lwc_string_caseless_isequal( + token->idata, c->strings[SE_RESIZE], + &match) == lwc_error_ok && match)) { + opv = CURSOR_SE_RESIZE; + } else if ((lwc_string_caseless_isequal( + token->idata, c->strings[SW_RESIZE], + &match) == lwc_error_ok && match)) { + opv = CURSOR_SW_RESIZE; + } else if ((lwc_string_caseless_isequal( + token->idata, c->strings[S_RESIZE], + &match) == lwc_error_ok && match)) { + opv = CURSOR_S_RESIZE; + } else if ((lwc_string_caseless_isequal( + token->idata, c->strings[W_RESIZE], + &match) == lwc_error_ok && match)) { + opv = CURSOR_W_RESIZE; + } else if ((lwc_string_caseless_isequal( + token->idata, c->strings[LIBCSS_TEXT], + &match) == lwc_error_ok && match)) { + opv = CURSOR_TEXT; + } else if ((lwc_string_caseless_isequal( + token->idata, c->strings[WAIT], + &match) == lwc_error_ok && match)) { + opv = CURSOR_WAIT; + } else if ((lwc_string_caseless_isequal( + token->idata, c->strings[HELP], + &match) == lwc_error_ok && match)) { + opv = CURSOR_HELP; + } else if ((lwc_string_caseless_isequal( + token->idata, c->strings[PROGRESS], + &match) == lwc_error_ok && match)) { + opv = CURSOR_PROGRESS; + } else { + *ctx = orig_ctx; + return CSS_INVALID; + } + + if (first == false) { + memcpy(ptr, &opv, sizeof(opv)); + ptr += sizeof(opv); + } + } + } + + return CSS_OK; +} + diff --git a/src/parse/properties/direction.c b/src/parse/properties/direction.c new file mode 100644 index 0000000..2d9fc96 --- /dev/null +++ b/src/parse/properties/direction.c @@ -0,0 +1,79 @@ +/* + * This file is part of LibCSS. + * Licensed under the MIT License, + * http://www.opensource.org/licenses/mit-license.php + * Copyright 2009 John-Mark Bell + */ + +#include +#include + +#include "bytecode/bytecode.h" +#include "bytecode/opcodes.h" +#include "parse/properties/properties.h" +#include "parse/properties/utils.h" + +/** + * Parse direction + * + * \param c Parsing context + * \param vector Vector of tokens to process + * \param ctx Pointer to vector iteration context + * \param result Pointer to location to receive resulting style + * \return CSS_OK on success, + * CSS_NOMEM on memory exhaustion, + * CSS_INVALID if the input is not valid + * + * Post condition: \a *ctx is updated with the next token to process + * If the input is invalid, then \a *ctx remains unchanged. + */ +css_error parse_direction(css_language *c, + const parserutils_vector *vector, int *ctx, + css_style **result) +{ + int orig_ctx = *ctx; + css_error error; + const css_token *ident; + uint8_t flags = 0; + uint16_t value = 0; + uint32_t opv; + bool match; + + /* IDENT (ltr, rtl, inherit) */ + ident = parserutils_vector_iterate(vector, ctx); + if (ident == NULL || ident->type != CSS_TOKEN_IDENT) { + *ctx = orig_ctx; + return CSS_INVALID; + } + + if ((lwc_string_caseless_isequal( + ident->idata, c->strings[INHERIT], + &match) == lwc_error_ok && match)) { + flags |= FLAG_INHERIT; + } else if ((lwc_string_caseless_isequal( + ident->idata, c->strings[LTR], + &match) == lwc_error_ok && match)) { + value = DIRECTION_LTR; + } else if ((lwc_string_caseless_isequal( + ident->idata, c->strings[RTL], + &match) == lwc_error_ok && match)) { + value = DIRECTION_RTL; + } else { + *ctx = orig_ctx; + return CSS_INVALID; + } + + opv = buildOPV(CSS_PROP_DIRECTION, flags, value); + + /* Allocate result */ + error = css_stylesheet_style_create(c->sheet, sizeof(opv), result); + if (error != CSS_OK) { + *ctx = orig_ctx; + return error; + } + + /* Copy the bytecode to it */ + memcpy((*result)->bytecode, &opv, sizeof(opv)); + + return CSS_OK; +} diff --git a/src/parse/properties/display.c b/src/parse/properties/display.c new file mode 100644 index 0000000..b96b159 --- /dev/null +++ b/src/parse/properties/display.c @@ -0,0 +1,138 @@ +/* + * This file is part of LibCSS. + * Licensed under the MIT License, + * http://www.opensource.org/licenses/mit-license.php + * Copyright 2009 John-Mark Bell + */ + +#include +#include + +#include "bytecode/bytecode.h" +#include "bytecode/opcodes.h" +#include "parse/properties/properties.h" +#include "parse/properties/utils.h" + +/** + * Parse display + * + * \param c Parsing context + * \param vector Vector of tokens to process + * \param ctx Pointer to vector iteration context + * \param result Pointer to location to receive resulting style + * \return CSS_OK on success, + * CSS_NOMEM on memory exhaustion, + * CSS_INVALID if the input is not valid + * + * Post condition: \a *ctx is updated with the next token to process + * If the input is invalid, then \a *ctx remains unchanged. + */ +css_error parse_display(css_language *c, + const parserutils_vector *vector, int *ctx, + css_style **result) +{ + int orig_ctx = *ctx; + css_error error; + const css_token *ident; + uint8_t flags = 0; + uint16_t value = 0; + uint32_t opv; + bool match; + + /* IDENT (inline, block, list-item, run-in, inline-block, table, + * inline-table, table-row-group, table-header-group, + * table-footer-group, table-row, table-column-group, table-column, + * table-cell, table-caption, none, inherit) */ + ident = parserutils_vector_iterate(vector, ctx); + if (ident == NULL || ident->type != CSS_TOKEN_IDENT) { + *ctx = orig_ctx; + return CSS_INVALID; + } + + if ((lwc_string_caseless_isequal( + ident->idata, c->strings[INHERIT], + &match) == lwc_error_ok && match)) { + flags |= FLAG_INHERIT; + } else if ((lwc_string_caseless_isequal( + ident->idata, c->strings[INLINE], + &match) == lwc_error_ok && match)) { + value = DISPLAY_INLINE; + } else if ((lwc_string_caseless_isequal( + ident->idata, c->strings[BLOCK], + &match) == lwc_error_ok && match)) { + value = DISPLAY_BLOCK; + } else if ((lwc_string_caseless_isequal( + ident->idata, c->strings[LIST_ITEM], + &match) == lwc_error_ok && match)) { + value = DISPLAY_LIST_ITEM; + } else if ((lwc_string_caseless_isequal( + ident->idata, c->strings[RUN_IN], + &match) == lwc_error_ok && match)) { + value = DISPLAY_RUN_IN; + } else if ((lwc_string_caseless_isequal( + ident->idata, c->strings[INLINE_BLOCK], + &match) == lwc_error_ok && match)) { + value = DISPLAY_INLINE_BLOCK; + } else if ((lwc_string_caseless_isequal( + ident->idata, c->strings[TABLE], + &match) == lwc_error_ok && match)) { + value = DISPLAY_TABLE; + } else if ((lwc_string_caseless_isequal( + ident->idata, c->strings[INLINE_TABLE], + &match) == lwc_error_ok && match)) { + value = DISPLAY_INLINE_TABLE; + } else if ((lwc_string_caseless_isequal( + ident->idata, c->strings[TABLE_ROW_GROUP], + &match) == lwc_error_ok && match)) { + value = DISPLAY_TABLE_ROW_GROUP; + } else if ((lwc_string_caseless_isequal( + ident->idata, c->strings[TABLE_HEADER_GROUP], + &match) == lwc_error_ok && match)) { + value = DISPLAY_TABLE_HEADER_GROUP; + } else if ((lwc_string_caseless_isequal( + ident->idata, c->strings[TABLE_FOOTER_GROUP], + &match) == lwc_error_ok && match)) { + value = DISPLAY_TABLE_FOOTER_GROUP; + } else if ((lwc_string_caseless_isequal( + ident->idata, c->strings[TABLE_ROW], + &match) == lwc_error_ok && match)) { + value = DISPLAY_TABLE_ROW; + } else if ((lwc_string_caseless_isequal( + ident->idata, c->strings[TABLE_COLUMN_GROUP], + &match) == lwc_error_ok && match)) { + value = DISPLAY_TABLE_COLUMN_GROUP; + } else if ((lwc_string_caseless_isequal( + ident->idata, c->strings[TABLE_COLUMN], + &match) == lwc_error_ok && match)) { + value = DISPLAY_TABLE_COLUMN; + } else if ((lwc_string_caseless_isequal( + ident->idata, c->strings[TABLE_CELL], + &match) == lwc_error_ok && match)) { + value = DISPLAY_TABLE_CELL; + } else if ((lwc_string_caseless_isequal( + ident->idata, c->strings[TABLE_CAPTION], + &match) == lwc_error_ok && match)) { + value = DISPLAY_TABLE_CAPTION; + } else if ((lwc_string_caseless_isequal( + ident->idata, c->strings[NONE], + &match) == lwc_error_ok && match)) { + value = DISPLAY_NONE; + } else { + *ctx = orig_ctx; + return CSS_INVALID; + } + + opv = buildOPV(CSS_PROP_DISPLAY, flags, value); + + /* Allocate result */ + error = css_stylesheet_style_create(c->sheet, sizeof(opv), result); + if (error != CSS_OK) { + *ctx = orig_ctx; + return error; + } + + /* Copy the bytecode to it */ + memcpy((*result)->bytecode, &opv, sizeof(opv)); + + return CSS_OK; +} diff --git a/src/parse/properties/display_sizing.c b/src/parse/properties/display_sizing.c deleted file mode 100644 index 7647d22..0000000 --- a/src/parse/properties/display_sizing.c +++ /dev/null @@ -1,811 +0,0 @@ -/* - * This file is part of LibCSS. - * Licensed under the MIT License, - * http://www.opensource.org/licenses/mit-license.php - * Copyright 2009 John-Mark Bell - */ - -#include - -#include "bytecode/bytecode.h" -#include "bytecode/opcodes.h" -#include "parse/properties/properties.h" -#include "parse/properties/utils.h" - -/** - * Parse display - * - * \param c Parsing context - * \param vector Vector of tokens to process - * \param ctx Pointer to vector iteration context - * \param result Pointer to location to receive resulting style - * \return CSS_OK on success, - * CSS_NOMEM on memory exhaustion, - * CSS_INVALID if the input is not valid - * - * Post condition: \a *ctx is updated with the next token to process - * If the input is invalid, then \a *ctx remains unchanged. - */ -css_error parse_display(css_language *c, - const parserutils_vector *vector, int *ctx, - css_style **result) -{ - int orig_ctx = *ctx; - css_error error; - const css_token *ident; - uint8_t flags = 0; - uint16_t value = 0; - uint32_t opv; - bool match; - - /* IDENT (inline, block, list-item, run-in, inline-block, table, - * inline-table, table-row-group, table-header-group, - * table-footer-group, table-row, table-column-group, table-column, - * table-cell, table-caption, none, inherit) */ - ident = parserutils_vector_iterate(vector, ctx); - if (ident == NULL || ident->type != CSS_TOKEN_IDENT) { - *ctx = orig_ctx; - return CSS_INVALID; - } - - if ((lwc_string_caseless_isequal( - ident->idata, c->strings[INHERIT], - &match) == lwc_error_ok && match)) { - flags |= FLAG_INHERIT; - } else if ((lwc_string_caseless_isequal( - ident->idata, c->strings[INLINE], - &match) == lwc_error_ok && match)) { - value = DISPLAY_INLINE; - } else if ((lwc_string_caseless_isequal( - ident->idata, c->strings[BLOCK], - &match) == lwc_error_ok && match)) { - value = DISPLAY_BLOCK; - } else if ((lwc_string_caseless_isequal( - ident->idata, c->strings[LIST_ITEM], - &match) == lwc_error_ok && match)) { - value = DISPLAY_LIST_ITEM; - } else if ((lwc_string_caseless_isequal( - ident->idata, c->strings[RUN_IN], - &match) == lwc_error_ok && match)) { - value = DISPLAY_RUN_IN; - } else if ((lwc_string_caseless_isequal( - ident->idata, c->strings[INLINE_BLOCK], - &match) == lwc_error_ok && match)) { - value = DISPLAY_INLINE_BLOCK; - } else if ((lwc_string_caseless_isequal( - ident->idata, c->strings[TABLE], - &match) == lwc_error_ok && match)) { - value = DISPLAY_TABLE; - } else if ((lwc_string_caseless_isequal( - ident->idata, c->strings[INLINE_TABLE], - &match) == lwc_error_ok && match)) { - value = DISPLAY_INLINE_TABLE; - } else if ((lwc_string_caseless_isequal( - ident->idata, c->strings[TABLE_ROW_GROUP], - &match) == lwc_error_ok && match)) { - value = DISPLAY_TABLE_ROW_GROUP; - } else if ((lwc_string_caseless_isequal( - ident->idata, c->strings[TABLE_HEADER_GROUP], - &match) == lwc_error_ok && match)) { - value = DISPLAY_TABLE_HEADER_GROUP; - } else if ((lwc_string_caseless_isequal( - ident->idata, c->strings[TABLE_FOOTER_GROUP], - &match) == lwc_error_ok && match)) { - value = DISPLAY_TABLE_FOOTER_GROUP; - } else if ((lwc_string_caseless_isequal( - ident->idata, c->strings[TABLE_ROW], - &match) == lwc_error_ok && match)) { - value = DISPLAY_TABLE_ROW; - } else if ((lwc_string_caseless_isequal( - ident->idata, c->strings[TABLE_COLUMN_GROUP], - &match) == lwc_error_ok && match)) { - value = DISPLAY_TABLE_COLUMN_GROUP; - } else if ((lwc_string_caseless_isequal( - ident->idata, c->strings[TABLE_COLUMN], - &match) == lwc_error_ok && match)) { - value = DISPLAY_TABLE_COLUMN; - } else if ((lwc_string_caseless_isequal( - ident->idata, c->strings[TABLE_CELL], - &match) == lwc_error_ok && match)) { - value = DISPLAY_TABLE_CELL; - } else if ((lwc_string_caseless_isequal( - ident->idata, c->strings[TABLE_CAPTION], - &match) == lwc_error_ok && match)) { - value = DISPLAY_TABLE_CAPTION; - } else if ((lwc_string_caseless_isequal( - ident->idata, c->strings[NONE], - &match) == lwc_error_ok && match)) { - value = DISPLAY_NONE; - } else { - *ctx = orig_ctx; - return CSS_INVALID; - } - - opv = buildOPV(CSS_PROP_DISPLAY, flags, value); - - /* Allocate result */ - error = css_stylesheet_style_create(c->sheet, sizeof(opv), result); - if (error != CSS_OK) { - *ctx = orig_ctx; - return error; - } - - /* Copy the bytecode to it */ - memcpy((*result)->bytecode, &opv, sizeof(opv)); - - return CSS_OK; -} - -/** - * Parse height - * - * \param c Parsing context - * \param vector Vector of tokens to process - * \param ctx Pointer to vector iteration context - * \param result Pointer to location to receive resulting style - * \return CSS_OK on success, - * CSS_NOMEM on memory exhaustion, - * CSS_INVALID if the input is not valid - * - * Post condition: \a *ctx is updated with the next token to process - * If the input is invalid, then \a *ctx remains unchanged. - */ -css_error parse_height(css_language *c, - const parserutils_vector *vector, int *ctx, - css_style **result) -{ - int orig_ctx = *ctx; - css_error error; - const css_token *token; - uint8_t flags = 0; - uint16_t value = 0; - uint32_t opv; - css_fixed length = 0; - uint32_t unit = 0; - uint32_t required_size; - bool match; - - /* length | percentage | IDENT(auto, inherit) */ - token = parserutils_vector_peek(vector, *ctx); - if (token == NULL) { - *ctx = orig_ctx; - return CSS_INVALID; - } - - if (token->type == CSS_TOKEN_IDENT && - (lwc_string_caseless_isequal( - token->idata, c->strings[INHERIT], - &match) == lwc_error_ok && match)) { - parserutils_vector_iterate(vector, ctx); - flags = FLAG_INHERIT; - } else if (token->type == CSS_TOKEN_IDENT && - (lwc_string_caseless_isequal( - token->idata, c->strings[AUTO], - &match) == lwc_error_ok && match)) { - parserutils_vector_iterate(vector, ctx); - value = HEIGHT_AUTO; - } else { - error = parse_unit_specifier(c, vector, ctx, UNIT_PX, - &length, &unit); - if (error != CSS_OK) { - *ctx = orig_ctx; - return error; - } - - if (unit & UNIT_ANGLE || unit & UNIT_TIME || unit & UNIT_FREQ) { - *ctx = orig_ctx; - return CSS_INVALID; - } - - /* Negative height is illegal */ - if (length < 0) { - *ctx = orig_ctx; - return CSS_INVALID; - } - - value = HEIGHT_SET; - } - - opv = buildOPV(CSS_PROP_HEIGHT, flags, value); - - required_size = sizeof(opv); - if ((flags & FLAG_INHERIT) == false && value == HEIGHT_SET) - required_size += sizeof(length) + sizeof(unit); - - /* Allocate result */ - error = css_stylesheet_style_create(c->sheet, required_size, result); - if (error != CSS_OK) { - *ctx = orig_ctx; - return error; - } - - /* Copy the bytecode to it */ - memcpy((*result)->bytecode, &opv, sizeof(opv)); - if ((flags & FLAG_INHERIT) == false && value == HEIGHT_SET) { - memcpy(((uint8_t *) (*result)->bytecode) + sizeof(opv), - &length, sizeof(length)); - memcpy(((uint8_t *) (*result)->bytecode) + sizeof(opv) + - sizeof(length), &unit, sizeof(unit)); - } - - return CSS_OK; -} - -/** - * Parse line-height - * - * \param c Parsing context - * \param vector Vector of tokens to process - * \param ctx Pointer to vector iteration context - * \param result Pointer to location to receive resulting style - * \return CSS_OK on success, - * CSS_NOMEM on memory exhaustion, - * CSS_INVALID if the input is not valid - * - * Post condition: \a *ctx is updated with the next token to process - * If the input is invalid, then \a *ctx remains unchanged. - */ -css_error parse_line_height(css_language *c, - const parserutils_vector *vector, int *ctx, - css_style **result) -{ - int orig_ctx = *ctx; - css_error error; - const css_token *token; - uint8_t flags = 0; - uint16_t value = 0; - uint32_t opv; - css_fixed length = 0; - uint32_t unit = 0; - uint32_t required_size; - bool match; - - /* number | length | percentage | IDENT(normal, inherit) */ - token = parserutils_vector_peek(vector, *ctx); - if (token == NULL) { - *ctx = orig_ctx; - return CSS_INVALID; - } - - if (token->type == CSS_TOKEN_IDENT && - (lwc_string_caseless_isequal( - token->idata, c->strings[INHERIT], - &match) == lwc_error_ok && match)) { - parserutils_vector_iterate(vector, ctx); - flags = FLAG_INHERIT; - } else if (token->type == CSS_TOKEN_IDENT && - (lwc_string_caseless_isequal( - token->idata, c->strings[NORMAL], - &match) == lwc_error_ok && match)) { - parserutils_vector_iterate(vector, ctx); - value = LINE_HEIGHT_NORMAL; - } else if (token->type == CSS_TOKEN_NUMBER) { - size_t consumed = 0; - length = number_from_lwc_string(token->idata, false, &consumed); - if (consumed != lwc_string_length(token->idata)) { - *ctx = orig_ctx; - return CSS_INVALID; - } - - /* Negative values are illegal */ - if (length < 0) { - *ctx = orig_ctx; - return CSS_INVALID; - } - - parserutils_vector_iterate(vector, ctx); - value = LINE_HEIGHT_NUMBER; - } else { - error = parse_unit_specifier(c, vector, ctx, UNIT_PX, - &length, &unit); - if (error != CSS_OK) { - *ctx = orig_ctx; - return error; - } - - if (unit & UNIT_ANGLE || unit & UNIT_TIME || unit & UNIT_FREQ) { - *ctx = orig_ctx; - return CSS_INVALID; - } - - /* Negative values are illegal */ - if (length < 0) { - *ctx = orig_ctx; - return CSS_INVALID; - } - - value = LINE_HEIGHT_DIMENSION; - } - - opv = buildOPV(CSS_PROP_LINE_HEIGHT, flags, value); - - required_size = sizeof(opv); - if ((flags & FLAG_INHERIT) == false && value == LINE_HEIGHT_NUMBER) - required_size += sizeof(length); - else if ((flags & FLAG_INHERIT) == false && - value == LINE_HEIGHT_DIMENSION) - required_size += sizeof(length) + sizeof(unit); - - /* Allocate result */ - error = css_stylesheet_style_create(c->sheet, required_size, result); - if (error != CSS_OK) { - *ctx = orig_ctx; - return error; - } - - /* Copy the bytecode to it */ - memcpy((*result)->bytecode, &opv, sizeof(opv)); - if ((flags & FLAG_INHERIT) == false && (value == LINE_HEIGHT_NUMBER || - value == LINE_HEIGHT_DIMENSION)) - memcpy(((uint8_t *) (*result)->bytecode) + sizeof(opv), - &length, sizeof(length)); - if ((flags & FLAG_INHERIT) == false && value == LINE_HEIGHT_DIMENSION) - memcpy(((uint8_t *) (*result)->bytecode) + sizeof(opv) + - sizeof(length), &unit, sizeof(unit)); - - return CSS_OK; -} - -/** - * Parse max-height - * - * \param c Parsing context - * \param vector Vector of tokens to process - * \param ctx Pointer to vector iteration context - * \param result Pointer to location to receive resulting style - * \return CSS_OK on success, - * CSS_NOMEM on memory exhaustion, - * CSS_INVALID if the input is not valid - * - * Post condition: \a *ctx is updated with the next token to process - * If the input is invalid, then \a *ctx remains unchanged. - */ -css_error parse_max_height(css_language *c, - const parserutils_vector *vector, int *ctx, - css_style **result) -{ - int orig_ctx = *ctx; - css_error error; - const css_token *token; - uint8_t flags = 0; - uint16_t value = 0; - uint32_t opv; - css_fixed length = 0; - uint32_t unit = 0; - uint32_t required_size; - bool match; - - /* length | percentage | IDENT(none, inherit) */ - token = parserutils_vector_peek(vector, *ctx); - if (token == NULL) { - *ctx = orig_ctx; - return CSS_INVALID; - } - - if (token->type == CSS_TOKEN_IDENT && - (lwc_string_caseless_isequal( - token->idata, c->strings[INHERIT], - &match) == lwc_error_ok && match)) { - parserutils_vector_iterate(vector, ctx); - flags = FLAG_INHERIT; - } else if (token->type == CSS_TOKEN_IDENT && - (lwc_string_caseless_isequal( - token->idata, c->strings[NONE], - &match) == lwc_error_ok && match)) { - parserutils_vector_iterate(vector, ctx); - value = MAX_HEIGHT_NONE; - } else { - error = parse_unit_specifier(c, vector, ctx, UNIT_PX, - &length, &unit); - if (error != CSS_OK) { - *ctx = orig_ctx; - return error; - } - - if (unit & UNIT_ANGLE || unit & UNIT_TIME || unit & UNIT_FREQ) { - *ctx = orig_ctx; - return CSS_INVALID; - } - - /* Negative values are illegal */ - if (length < 0) { - *ctx = orig_ctx; - return CSS_INVALID; - } - - value = MAX_HEIGHT_SET; - } - - opv = buildOPV(CSS_PROP_MAX_HEIGHT, flags, value); - - required_size = sizeof(opv); - if ((flags & FLAG_INHERIT) == false && value == MAX_HEIGHT_SET) - required_size += sizeof(length) + sizeof(unit); - - /* Allocate result */ - error = css_stylesheet_style_create(c->sheet, required_size, result); - if (error != CSS_OK) { - *ctx = orig_ctx; - return error; - } - - /* Copy the bytecode to it */ - memcpy((*result)->bytecode, &opv, sizeof(opv)); - if ((flags & FLAG_INHERIT) == false && value == MAX_HEIGHT_SET) { - memcpy(((uint8_t *) (*result)->bytecode) + sizeof(opv), - &length, sizeof(length)); - memcpy(((uint8_t *) (*result)->bytecode) + sizeof(opv) + - sizeof(length), &unit, sizeof(unit)); - } - - return CSS_OK; -} - -/** - * Parse max-width - * - * \param c Parsing context - * \param vector Vector of tokens to process - * \param ctx Pointer to vector iteration context - * \param result Pointer to location to receive resulting style - * \return CSS_OK on success, - * CSS_NOMEM on memory exhaustion, - * CSS_INVALID if the input is not valid - * - * Post condition: \a *ctx is updated with the next token to process - * If the input is invalid, then \a *ctx remains unchanged. - */ -css_error parse_max_width(css_language *c, - const parserutils_vector *vector, int *ctx, - css_style **result) -{ - int orig_ctx = *ctx; - css_error error; - const css_token *token; - uint8_t flags = 0; - uint16_t value = 0; - uint32_t opv; - css_fixed length = 0; - uint32_t unit = 0; - uint32_t required_size; - bool match; - - /* length | percentage | IDENT(none, inherit) */ - token = parserutils_vector_peek(vector, *ctx); - if (token == NULL) { - *ctx = orig_ctx; - return CSS_INVALID; - } - - if (token->type == CSS_TOKEN_IDENT && - (lwc_string_caseless_isequal( - token->idata, c->strings[INHERIT], - &match) == lwc_error_ok && match)) { - parserutils_vector_iterate(vector, ctx); - flags = FLAG_INHERIT; - } else if (token->type == CSS_TOKEN_IDENT && - (lwc_string_caseless_isequal( - token->idata, c->strings[NONE], - &match) == lwc_error_ok && match)) { - parserutils_vector_iterate(vector, ctx); - value = MAX_WIDTH_NONE; - } else { - error = parse_unit_specifier(c, vector, ctx, UNIT_PX, - &length, &unit); - if (error != CSS_OK) { - *ctx = orig_ctx; - return error; - } - - if (unit & UNIT_ANGLE || unit & UNIT_TIME || unit & UNIT_FREQ) { - *ctx = orig_ctx; - return CSS_INVALID; - } - - /* Negative values are illegal */ - if (length < 0) { - *ctx = orig_ctx; - return CSS_INVALID; - } - - value = MAX_WIDTH_SET; - } - - opv = buildOPV(CSS_PROP_MAX_WIDTH, flags, value); - - required_size = sizeof(opv); - if ((flags & FLAG_INHERIT) == false && value == MAX_WIDTH_SET) - required_size += sizeof(length) + sizeof(unit); - - /* Allocate result */ - error = css_stylesheet_style_create(c->sheet, required_size, result); - if (error != CSS_OK) { - *ctx = orig_ctx; - return error; - } - - /* Copy the bytecode to it */ - memcpy((*result)->bytecode, &opv, sizeof(opv)); - if ((flags & FLAG_INHERIT) == false && value == MAX_WIDTH_SET) { - memcpy(((uint8_t *) (*result)->bytecode) + sizeof(opv), - &length, sizeof(length)); - memcpy(((uint8_t *) (*result)->bytecode) + sizeof(opv) + - sizeof(length), &unit, sizeof(unit)); - } - - return CSS_OK; -} - -/** - * Parse min-height - * - * \param c Parsing context - * \param vector Vector of tokens to process - * \param ctx Pointer to vector iteration context - * \param result Pointer to location to receive resulting style - * \return CSS_OK on success, - * CSS_NOMEM on memory exhaustion, - * CSS_INVALID if the input is not valid - * - * Post condition: \a *ctx is updated with the next token to process - * If the input is invalid, then \a *ctx remains unchanged. - */ -css_error parse_min_height(css_language *c, - const parserutils_vector *vector, int *ctx, - css_style **result) -{ - int orig_ctx = *ctx; - css_error error; - const css_token *token; - uint8_t flags = 0; - uint16_t value = 0; - uint32_t opv; - css_fixed length = 0; - uint32_t unit = 0; - uint32_t required_size; - bool match; - - /* length | percentage | IDENT(inherit) */ - token = parserutils_vector_peek(vector, *ctx); - if (token == NULL) { - *ctx = orig_ctx; - return CSS_INVALID; - } - - if (token->type == CSS_TOKEN_IDENT && - (lwc_string_caseless_isequal( - token->idata, c->strings[INHERIT], - &match) == lwc_error_ok && match)) { - parserutils_vector_iterate(vector, ctx); - flags = FLAG_INHERIT; - } else { - error = parse_unit_specifier(c, vector, ctx, UNIT_PX, - &length, &unit); - if (error != CSS_OK) { - *ctx = orig_ctx; - return error; - } - - if (unit & UNIT_ANGLE || unit & UNIT_TIME || unit & UNIT_FREQ) { - *ctx = orig_ctx; - return CSS_INVALID; - } - - /* Negative values are illegal */ - if (length < 0) { - *ctx = orig_ctx; - return CSS_INVALID; - } - - value = MIN_HEIGHT_SET; - } - - opv = buildOPV(CSS_PROP_MIN_HEIGHT, flags, value); - - required_size = sizeof(opv); - if ((flags & FLAG_INHERIT) == false && value == MIN_HEIGHT_SET) - required_size += sizeof(length) + sizeof(unit); - - /* Allocate result */ - error = css_stylesheet_style_create(c->sheet, required_size, result); - if (error != CSS_OK) { - *ctx = orig_ctx; - return error; - } - - /* Copy the bytecode to it */ - memcpy((*result)->bytecode, &opv, sizeof(opv)); - if ((flags & FLAG_INHERIT) == false && value == MIN_HEIGHT_SET) { - memcpy(((uint8_t *) (*result)->bytecode) + sizeof(opv), - &length, sizeof(length)); - memcpy(((uint8_t *) (*result)->bytecode) + sizeof(opv) + - sizeof(length), &unit, sizeof(unit)); - } - - return CSS_OK; -} - -/** - * Parse min-width - * - * \param c Parsing context - * \param vector Vector of tokens to process - * \param ctx Pointer to vector iteration context - * \param result Pointer to location to receive resulting style - * \return CSS_OK on success, - * CSS_NOMEM on memory exhaustion, - * CSS_INVALID if the input is not valid - * - * Post condition: \a *ctx is updated with the next token to process - * If the input is invalid, then \a *ctx remains unchanged. - */ -css_error parse_min_width(css_language *c, - const parserutils_vector *vector, int *ctx, - css_style **result) -{ - int orig_ctx = *ctx; - css_error error; - const css_token *token; - uint8_t flags = 0; - uint16_t value = 0; - uint32_t opv; - css_fixed length = 0; - uint32_t unit = 0; - uint32_t required_size; - bool match; - - /* length | percentage | IDENT(inherit) */ - token = parserutils_vector_peek(vector, *ctx); - if (token == NULL) { - *ctx = orig_ctx; - return CSS_INVALID; - } - - if (token->type == CSS_TOKEN_IDENT && - (lwc_string_caseless_isequal( - token->idata, c->strings[INHERIT], - &match) == lwc_error_ok && match)) { - parserutils_vector_iterate(vector, ctx); - flags = FLAG_INHERIT; - } else { - error = parse_unit_specifier(c, vector, ctx, UNIT_PX, - &length, &unit); - if (error != CSS_OK) { - *ctx = orig_ctx; - return error; - } - - if (unit & UNIT_ANGLE || unit & UNIT_TIME || unit & UNIT_FREQ) { - *ctx = orig_ctx; - return CSS_INVALID; - } - - /* Negative values are illegal */ - if (length < 0) { - *ctx = orig_ctx; - return CSS_INVALID; - } - - value = MIN_WIDTH_SET; - } - - opv = buildOPV(CSS_PROP_MIN_WIDTH, flags, value); - - required_size = sizeof(opv); - if ((flags & FLAG_INHERIT) == false && value == MIN_WIDTH_SET) - required_size += sizeof(length) + sizeof(unit); - - /* Allocate result */ - error = css_stylesheet_style_create(c->sheet, required_size, result); - if (error != CSS_OK) { - *ctx = orig_ctx; - return error; - } - - /* Copy the bytecode to it */ - memcpy((*result)->bytecode, &opv, sizeof(opv)); - if ((flags & FLAG_INHERIT) == false && value == MIN_WIDTH_SET) { - memcpy(((uint8_t *) (*result)->bytecode) + sizeof(opv), - &length, sizeof(length)); - memcpy(((uint8_t *) (*result)->bytecode) + sizeof(opv) + - sizeof(length), &unit, sizeof(unit)); - } - - return CSS_OK; -} - -/** - * Parse width - * - * \param c Parsing context - * \param vector Vector of tokens to process - * \param ctx Pointer to vector iteration context - * \param result Pointer to location to receive resulting style - * \return CSS_OK on success, - * CSS_NOMEM on memory exhaustion, - * CSS_INVALID if the input is not valid - * - * Post condition: \a *ctx is updated with the next token to process - * If the input is invalid, then \a *ctx remains unchanged. - */ -css_error parse_width(css_language *c, - const parserutils_vector *vector, int *ctx, - css_style **result) -{ - int orig_ctx = *ctx; - css_error error; - const css_token *token; - uint8_t flags = 0; - uint16_t value = 0; - uint32_t opv; - css_fixed length = 0; - uint32_t unit = 0; - uint32_t required_size; - bool match; - - /* length | percentage | IDENT(auto, inherit) */ - token = parserutils_vector_peek(vector, *ctx); - if (token == NULL) { - *ctx = orig_ctx; - return CSS_INVALID; - } - - if (token->type == CSS_TOKEN_IDENT && - (lwc_string_caseless_isequal( - token->idata, c->strings[INHERIT], - &match) == lwc_error_ok && match)) { - parserutils_vector_iterate(vector, ctx); - flags = FLAG_INHERIT; - } else if (token->type == CSS_TOKEN_IDENT && - (lwc_string_caseless_isequal( - token->idata, c->strings[AUTO], - &match) == lwc_error_ok && match)) { - parserutils_vector_iterate(vector, ctx); - value = WIDTH_AUTO; - } else { - error = parse_unit_specifier(c, vector, ctx, UNIT_PX, - &length, &unit); - if (error != CSS_OK) { - *ctx = orig_ctx; - return error; - } - - if (unit & UNIT_ANGLE || unit & UNIT_TIME || unit & UNIT_FREQ) { - *ctx = orig_ctx; - return CSS_INVALID; - } - - /* Must be positive */ - if (length < 0) { - *ctx = orig_ctx; - return CSS_INVALID; - } - - value = WIDTH_SET; - } - - opv = buildOPV(CSS_PROP_WIDTH, flags, value); - - required_size = sizeof(opv); - if ((flags & FLAG_INHERIT) == false && value == WIDTH_SET) - required_size += sizeof(length) + sizeof(unit); - - /* Allocate result */ - error = css_stylesheet_style_create(c->sheet, required_size, result); - if (error != CSS_OK) { - *ctx = orig_ctx; - return error; - } - - /* Copy the bytecode to it */ - memcpy((*result)->bytecode, &opv, sizeof(opv)); - if ((flags & FLAG_INHERIT) == false && value == WIDTH_SET) { - memcpy(((uint8_t *) (*result)->bytecode) + sizeof(opv), - &length, sizeof(length)); - memcpy(((uint8_t *) (*result)->bytecode) + sizeof(opv) + - sizeof(length), &unit, sizeof(unit)); - } - - return CSS_OK; -} - diff --git a/src/parse/properties/effects_stacking.c b/src/parse/properties/effects_stacking.c deleted file mode 100644 index f032db4..0000000 --- a/src/parse/properties/effects_stacking.c +++ /dev/null @@ -1,402 +0,0 @@ -/* - * This file is part of LibCSS. - * Licensed under the MIT License, - * http://www.opensource.org/licenses/mit-license.php - * Copyright 2009 John-Mark Bell - */ - -#include - -#include "bytecode/bytecode.h" -#include "bytecode/opcodes.h" -#include "parse/properties/properties.h" -#include "parse/properties/utils.h" - -/** - * Parse clip - * - * \param c Parsing context - * \param vector Vector of tokens to process - * \param ctx Pointer to vector iteration context - * \param result Pointer to location to receive resulting style - * \return CSS_OK on success, - * CSS_NOMEM on memory exhaustion, - * CSS_INVALID if the input is not valid - * - * Post condition: \a *ctx is updated with the next token to process - * If the input is invalid, then \a *ctx remains unchanged. - */ -css_error parse_clip(css_language *c, - const parserutils_vector *vector, int *ctx, - css_style **result) -{ - int orig_ctx = *ctx; - css_error error; - const css_token *token; - uint8_t flags = 0; - uint16_t value = 0; - uint32_t opv; - int num_lengths = 0; - css_fixed length[4] = { 0 }; - uint32_t unit[4] = { 0 }; - uint32_t required_size; - bool match; - - /* FUNCTION(rect) [ [ IDENT(auto) | length ] CHAR(,)? ]{3} - * [ IDENT(auto) | length ] CHAR{)} | - * IDENT(auto, inherit) */ - token = parserutils_vector_iterate(vector, ctx); - if (token == NULL) { - *ctx = orig_ctx; - return CSS_INVALID; - } - - if (token->type == CSS_TOKEN_IDENT && - (lwc_string_caseless_isequal( - token->idata, c->strings[INHERIT], - &match) == lwc_error_ok && match)) { - flags = FLAG_INHERIT; - } else if (token->type == CSS_TOKEN_IDENT && - (lwc_string_caseless_isequal( - token->idata, c->strings[AUTO], - &match) == lwc_error_ok && match)) { - value = CLIP_AUTO; - } else if (token->type == CSS_TOKEN_FUNCTION && - (lwc_string_caseless_isequal( - token->idata, c->strings[RECT], - &match) == lwc_error_ok && match)) { - int i; - value = CLIP_SHAPE_RECT; - - for (i = 0; i < 4; i++) { - consumeWhitespace(vector, ctx); - - token = parserutils_vector_peek(vector, *ctx); - if (token == NULL) { - *ctx = orig_ctx; - return CSS_INVALID; - } - - if (token->type == CSS_TOKEN_IDENT) { - /* Slightly magical way of generating the auto - * values. These are bits 3-6 of the value. */ - if ((lwc_string_caseless_isequal( - token->idata, c->strings[AUTO], - &match) == lwc_error_ok && - match)) - value |= 1 << (i + 3); - else { - *ctx = orig_ctx; - return CSS_INVALID; - } - - parserutils_vector_iterate(vector, ctx); - } else { - error = parse_unit_specifier(c, vector, ctx, - UNIT_PX, - &length[num_lengths], - &unit[num_lengths]); - if (error != CSS_OK) { - *ctx = orig_ctx; - return error; - } - - if (unit[num_lengths] & UNIT_ANGLE || - unit[num_lengths] & UNIT_TIME || - unit[num_lengths] & UNIT_FREQ || - unit[num_lengths] & UNIT_PCT) { - *ctx = orig_ctx; - return CSS_INVALID; - } - - num_lengths++; - } - - consumeWhitespace(vector, ctx); - - /* Consume optional comma after first 3 parameters */ - if (i < 3) { - token = parserutils_vector_peek(vector, *ctx); - if (token == NULL) { - *ctx = orig_ctx; - return CSS_INVALID; - } - - if (tokenIsChar(token, ',')) - parserutils_vector_iterate(vector, ctx); - } - } - - consumeWhitespace(vector, ctx); - - /* Finally, consume closing parenthesis */ - token = parserutils_vector_iterate(vector, ctx); - if (token == NULL || tokenIsChar(token, ')') == false) { - *ctx = orig_ctx; - return CSS_INVALID; - } - } else { - *ctx = orig_ctx; - return CSS_INVALID; - } - - opv = buildOPV(CSS_PROP_CLIP, flags, value); - - required_size = sizeof(opv); - if ((flags & FLAG_INHERIT) == false && - (value & CLIP_SHAPE_MASK) == CLIP_SHAPE_RECT) { - required_size += - num_lengths * (sizeof(length[0]) + sizeof(unit[0])); - } - - /* Allocate result */ - error = css_stylesheet_style_create(c->sheet, required_size, result); - if (error != CSS_OK) { - *ctx = orig_ctx; - return error; - } - - /* Copy the bytecode to it */ - memcpy((*result)->bytecode, &opv, sizeof(opv)); - if ((flags & FLAG_INHERIT) == false && - (value & CLIP_SHAPE_MASK) == CLIP_SHAPE_RECT) { - int i; - uint8_t *ptr = ((uint8_t *) (*result)->bytecode) + sizeof(opv); - - for (i = 0; i < num_lengths; i++) { - memcpy(ptr, &length[i], sizeof(length[i])); - ptr += sizeof(length[i]); - memcpy(ptr, &unit[i], sizeof(unit[i])); - ptr += sizeof(unit[i]); - } - } - - return CSS_OK; -} - -/** - * Parse overflow - * - * \param c Parsing context - * \param vector Vector of tokens to process - * \param ctx Pointer to vector iteration context - * \param result Pointer to location to receive resulting style - * \return CSS_OK on success, - * CSS_NOMEM on memory exhaustion, - * CSS_INVALID if the input is not valid - * - * Post condition: \a *ctx is updated with the next token to process - * If the input is invalid, then \a *ctx remains unchanged. - */ -css_error parse_overflow(css_language *c, - const parserutils_vector *vector, int *ctx, - css_style **result) -{ - int orig_ctx = *ctx; - css_error error; - const css_token *ident; - uint8_t flags = 0; - uint16_t value = 0; - uint32_t opv; - bool match; - - /* IDENT (visible, hidden, scroll, auto, inherit) */ - ident = parserutils_vector_iterate(vector, ctx); - if (ident == NULL || ident->type != CSS_TOKEN_IDENT) { - *ctx = orig_ctx; - return CSS_INVALID; - } - - if ((lwc_string_caseless_isequal( - ident->idata, c->strings[INHERIT], - &match) == lwc_error_ok && match)) { - flags |= FLAG_INHERIT; - } else if ((lwc_string_caseless_isequal( - ident->idata, c->strings[VISIBLE], - &match) == lwc_error_ok && match)) { - value = OVERFLOW_VISIBLE; - } else if ((lwc_string_caseless_isequal( - ident->idata, c->strings[HIDDEN], - &match) == lwc_error_ok && match)) { - value = OVERFLOW_HIDDEN; - } else if ((lwc_string_caseless_isequal( - ident->idata, c->strings[SCROLL], - &match) == lwc_error_ok && match)) { - value = OVERFLOW_SCROLL; - } else if ((lwc_string_caseless_isequal( - ident->idata, c->strings[AUTO], - &match) == lwc_error_ok && match)) { - value = OVERFLOW_AUTO; - } else { - *ctx = orig_ctx; - return CSS_INVALID; - } - - opv = buildOPV(CSS_PROP_OVERFLOW, flags, value); - - /* Allocate result */ - error = css_stylesheet_style_create(c->sheet, sizeof(opv), result); - if (error != CSS_OK) { - *ctx = orig_ctx; - return error; - } - - /* Copy the bytecode to it */ - memcpy((*result)->bytecode, &opv, sizeof(opv)); - - return CSS_OK; -} - -/** - * Parse visibility - * - * \param c Parsing context - * \param vector Vector of tokens to process - * \param ctx Pointer to vector iteration context - * \param result Pointer to location to receive resulting style - * \return CSS_OK on success, - * CSS_NOMEM on memory exhaustion, - * CSS_INVALID if the input is not valid - * - * Post condition: \a *ctx is updated with the next token to process - * If the input is invalid, then \a *ctx remains unchanged. - */ -css_error parse_visibility(css_language *c, - const parserutils_vector *vector, int *ctx, - css_style **result) -{ - int orig_ctx = *ctx; - css_error error; - const css_token *ident; - uint8_t flags = 0; - uint16_t value = 0; - uint32_t opv; - bool match; - - /* IDENT (visible, hidden, collapse, inherit) */ - ident = parserutils_vector_iterate(vector, ctx); - if (ident == NULL || ident->type != CSS_TOKEN_IDENT) { - *ctx = orig_ctx; - return CSS_INVALID; - } - - if ((lwc_string_caseless_isequal( - ident->idata, c->strings[INHERIT], - &match) == lwc_error_ok && match)) { - flags |= FLAG_INHERIT; - } else if ((lwc_string_caseless_isequal( - ident->idata, c->strings[VISIBLE], - &match) == lwc_error_ok && match)) { - value = VISIBILITY_VISIBLE; - } else if ((lwc_string_caseless_isequal( - ident->idata, c->strings[HIDDEN], - &match) == lwc_error_ok && match)) { - value = VISIBILITY_HIDDEN; - } else if ((lwc_string_caseless_isequal( - ident->idata, c->strings[COLLAPSE], - &match) == lwc_error_ok && match)) { - value = VISIBILITY_COLLAPSE; - } else { - *ctx = orig_ctx; - return CSS_INVALID; - } - - opv = buildOPV(CSS_PROP_VISIBILITY, flags, value); - - /* Allocate result */ - error = css_stylesheet_style_create(c->sheet, sizeof(opv), result); - if (error != CSS_OK) { - *ctx = orig_ctx; - return error; - } - - /* Copy the bytecode to it */ - memcpy((*result)->bytecode, &opv, sizeof(opv)); - - return CSS_OK; -} - -/** - * Parse z-index - * - * \param c Parsing context - * \param vector Vector of tokens to process - * \param ctx Pointer to vector iteration context - * \param result Pointer to location to receive resulting style - * \return CSS_OK on success, - * CSS_NOMEM on memory exhaustion, - * CSS_INVALID if the input is not valid - * - * Post condition: \a *ctx is updated with the next token to process - * If the input is invalid, then \a *ctx remains unchanged. - */ -css_error parse_z_index(css_language *c, - const parserutils_vector *vector, int *ctx, - css_style **result) -{ - int orig_ctx = *ctx; - css_error error; - const css_token *token; - uint8_t flags = 0; - uint16_t value = 0; - uint32_t opv; - css_fixed num = 0; - uint32_t required_size; - bool match; - - /* | IDENT (auto, inherit) */ - token = parserutils_vector_iterate(vector, ctx); - if (token == NULL || (token->type != CSS_TOKEN_IDENT && - token->type != CSS_TOKEN_NUMBER)) { - *ctx = orig_ctx; - return CSS_INVALID; - } - - if (token->type == CSS_TOKEN_IDENT && - (lwc_string_caseless_isequal( - token->idata, c->strings[INHERIT], - &match) == lwc_error_ok && match)) { - flags |= FLAG_INHERIT; - } else if (token->type == CSS_TOKEN_IDENT && - (lwc_string_caseless_isequal( - token->idata, c->strings[AUTO], - &match) == lwc_error_ok && match)) { - value = Z_INDEX_AUTO; - } else if (token->type == CSS_TOKEN_NUMBER) { - size_t consumed = 0; - num = number_from_lwc_string(token->idata, true, &consumed); - /* Invalid if there are trailing characters */ - if (consumed != lwc_string_length(token->idata)) { - *ctx = orig_ctx; - return CSS_INVALID; - } - - value = Z_INDEX_SET; - } else { - *ctx = orig_ctx; - return CSS_INVALID; - } - - opv = buildOPV(CSS_PROP_Z_INDEX, flags, value); - - required_size = sizeof(opv); - if ((flags & FLAG_INHERIT) == false && value == Z_INDEX_SET) - required_size += sizeof(num); - - /* Allocate result */ - error = css_stylesheet_style_create(c->sheet, required_size, result); - if (error != CSS_OK) { - *ctx = orig_ctx; - return error; - } - - /* Copy the bytecode to it */ - memcpy((*result)->bytecode, &opv, sizeof(opv)); - if ((flags & FLAG_INHERIT) == false && value == Z_INDEX_SET) { - memcpy(((uint8_t *) (*result)->bytecode) + sizeof(opv), - &num, sizeof(num)); - } - - return CSS_OK; -} - diff --git a/src/parse/properties/elevation.c b/src/parse/properties/elevation.c new file mode 100644 index 0000000..d29a9b7 --- /dev/null +++ b/src/parse/properties/elevation.c @@ -0,0 +1,145 @@ +/* + * This file is part of LibCSS. + * Licensed under the MIT License, + * http://www.opensource.org/licenses/mit-license.php + * Copyright 2009 John-Mark Bell + */ + +#include +#include + +#include "bytecode/bytecode.h" +#include "bytecode/opcodes.h" +#include "parse/properties/properties.h" +#include "parse/properties/utils.h" + +/** + * Parse elevation + * + * \param c Parsing context + * \param vector Vector of tokens to process + * \param ctx Pointer to vector iteration context + * \param result Pointer to location to receive resulting style + * \return CSS_OK on success, + * CSS_NOMEM on memory exhaustion, + * CSS_INVALID if the input is not valid + * + * Post condition: \a *ctx is updated with the next token to process + * If the input is invalid, then \a *ctx remains unchanged. + */ +css_error parse_elevation(css_language *c, + const parserutils_vector *vector, int *ctx, + css_style **result) +{ + int orig_ctx = *ctx; + css_error error; + const css_token *token; + uint8_t flags = 0; + uint16_t value = 0; + uint32_t opv; + css_fixed length = 0; + uint32_t unit = 0; + uint32_t required_size; + bool match; + + /* angle | IDENT(below, level, above, higher, lower, inherit) */ + token = parserutils_vector_peek(vector, *ctx); + if (token == NULL) { + *ctx = orig_ctx; + return CSS_INVALID; + } + + if (token->type == CSS_TOKEN_IDENT && + (lwc_string_caseless_isequal( + token->idata, c->strings[INHERIT], + &match) == lwc_error_ok && match)) { + parserutils_vector_iterate(vector, ctx); + flags = FLAG_INHERIT; + } else if (token->type == CSS_TOKEN_IDENT && + (lwc_string_caseless_isequal( + token->idata, c->strings[BELOW], + &match) == lwc_error_ok && match)) { + parserutils_vector_iterate(vector, ctx); + value = ELEVATION_BELOW; + } else if (token->type == CSS_TOKEN_IDENT && + (lwc_string_caseless_isequal( + token->idata, c->strings[LEVEL], + &match) == lwc_error_ok && match)) { + parserutils_vector_iterate(vector, ctx); + value = ELEVATION_LEVEL; + } else if (token->type == CSS_TOKEN_IDENT && + (lwc_string_caseless_isequal( + token->idata, c->strings[ABOVE], + &match) == lwc_error_ok && match)) { + parserutils_vector_iterate(vector, ctx); + value = ELEVATION_ABOVE; + } else if (token->type == CSS_TOKEN_IDENT && + (lwc_string_caseless_isequal( + token->idata, c->strings[HIGHER], + &match) == lwc_error_ok && match)) { + parserutils_vector_iterate(vector, ctx); + value = ELEVATION_HIGHER; + } else if (token->type == CSS_TOKEN_IDENT && + (lwc_string_caseless_isequal( + token->idata, c->strings[LOWER], + &match) == lwc_error_ok && match)) { + parserutils_vector_iterate(vector, ctx); + value = ELEVATION_LOWER; + } else { + error = parse_unit_specifier(c, vector, ctx, UNIT_DEG, + &length, &unit); + if (error != CSS_OK) { + *ctx = orig_ctx; + return error; + } + + if ((unit & UNIT_ANGLE) == false) { + *ctx = orig_ctx; + return CSS_INVALID; + } + + /* Valid angles lie between -90 and 90 degrees */ + if (unit == UNIT_DEG) { + if (length < FMULI(F_90, -1) || length > F_90) { + *ctx = orig_ctx; + return CSS_INVALID; + } + } else if (unit == UNIT_GRAD) { + if (length < FMULI(F_100, -1) || length > F_100) { + *ctx = orig_ctx; + return CSS_INVALID; + } + } else if (unit == UNIT_RAD) { + if (length < FMULI(F_PI_2, -1) || length > F_PI_2) { + *ctx = orig_ctx; + return CSS_INVALID; + } + } + + value = ELEVATION_ANGLE; + } + + opv = buildOPV(CSS_PROP_ELEVATION, flags, value); + + required_size = sizeof(opv); + if ((flags & FLAG_INHERIT) == false && value == ELEVATION_ANGLE) + required_size += sizeof(length) + sizeof(unit); + + /* Allocate result */ + error = css_stylesheet_style_create(c->sheet, required_size, result); + if (error != CSS_OK) { + *ctx = orig_ctx; + return error; + } + + /* Copy the bytecode to it */ + memcpy((*result)->bytecode, &opv, sizeof(opv)); + if ((flags & FLAG_INHERIT) == false && value == ELEVATION_ANGLE) { + memcpy(((uint8_t *) (*result)->bytecode) + sizeof(opv), + &length, sizeof(length)); + memcpy(((uint8_t *) (*result)->bytecode) + sizeof(opv) + + sizeof(length), &unit, sizeof(unit)); + } + + return CSS_OK; +} diff --git a/src/parse/properties/empty_cells.c b/src/parse/properties/empty_cells.c new file mode 100644 index 0000000..ca3ddf4 --- /dev/null +++ b/src/parse/properties/empty_cells.c @@ -0,0 +1,79 @@ +/* + * This file is part of LibCSS. + * Licensed under the MIT License, + * http://www.opensource.org/licenses/mit-license.php + * Copyright 2009 John-Mark Bell + */ + +#include +#include + +#include "bytecode/bytecode.h" +#include "bytecode/opcodes.h" +#include "parse/properties/properties.h" +#include "parse/properties/utils.h" + +/** + * Parse empty-cells + * + * \param c Parsing context + * \param vector Vector of tokens to process + * \param ctx Pointer to vector iteration context + * \param result Pointer to location to receive resulting style + * \return CSS_OK on success, + * CSS_NOMEM on memory exhaustion, + * CSS_INVALID if the input is not valid + * + * Post condition: \a *ctx is updated with the next token to process + * If the input is invalid, then \a *ctx remains unchanged. + */ +css_error parse_empty_cells(css_language *c, + const parserutils_vector *vector, int *ctx, + css_style **result) +{ + int orig_ctx = *ctx; + css_error error; + const css_token *ident; + uint8_t flags = 0; + uint16_t value = 0; + uint32_t opv; + bool match; + + /* IDENT (show, hide, inherit) */ + ident = parserutils_vector_iterate(vector, ctx); + if (ident == NULL || ident->type != CSS_TOKEN_IDENT) { + *ctx = orig_ctx; + return CSS_INVALID; + } + + if ((lwc_string_caseless_isequal( + ident->idata, c->strings[INHERIT], + &match) == lwc_error_ok && match)) { + flags |= FLAG_INHERIT; + } else if ((lwc_string_caseless_isequal( + ident->idata, c->strings[SHOW], + &match) == lwc_error_ok && match)) { + value = EMPTY_CELLS_SHOW; + } else if ((lwc_string_caseless_isequal( + ident->idata, c->strings[HIDE], + &match) == lwc_error_ok && match)) { + value = EMPTY_CELLS_HIDE; + } else { + *ctx = orig_ctx; + return CSS_INVALID; + } + + opv = buildOPV(CSS_PROP_EMPTY_CELLS, flags, value); + + /* Allocate result */ + error = css_stylesheet_style_create(c->sheet, sizeof(opv), result); + if (error != CSS_OK) { + *ctx = orig_ctx; + return error; + } + + /* Copy the bytecode to it */ + memcpy((*result)->bytecode, &opv, sizeof(opv)); + + return CSS_OK; +} diff --git a/src/parse/properties/float.c b/src/parse/properties/float.c new file mode 100644 index 0000000..78a33fe --- /dev/null +++ b/src/parse/properties/float.c @@ -0,0 +1,83 @@ +/* + * This file is part of LibCSS. + * Licensed under the MIT License, + * http://www.opensource.org/licenses/mit-license.php + * Copyright 2009 John-Mark Bell + */ + +#include +#include + +#include "bytecode/bytecode.h" +#include "bytecode/opcodes.h" +#include "parse/properties/properties.h" +#include "parse/properties/utils.h" + +/** + * Parse float + * + * \param c Parsing context + * \param vector Vector of tokens to process + * \param ctx Pointer to vector iteration context + * \param result Pointer to location to receive resulting style + * \return CSS_OK on success, + * CSS_NOMEM on memory exhaustion, + * CSS_INVALID if the input is not valid + * + * Post condition: \a *ctx is updated with the next token to process + * If the input is invalid, then \a *ctx remains unchanged. + */ +css_error parse_float(css_language *c, + const parserutils_vector *vector, int *ctx, + css_style **result) +{ + int orig_ctx = *ctx; + css_error error; + const css_token *ident; + uint8_t flags = 0; + uint16_t value = 0; + uint32_t opv; + bool match; + + /* IDENT (left, right, none, inherit) */ + ident = parserutils_vector_iterate(vector, ctx); + if (ident == NULL || ident->type != CSS_TOKEN_IDENT) { + *ctx = orig_ctx; + return CSS_INVALID; + } + + if ((lwc_string_caseless_isequal( + ident->idata, c->strings[INHERIT], + &match) == lwc_error_ok && match)) { + flags |= FLAG_INHERIT; + } else if ((lwc_string_caseless_isequal( + ident->idata, c->strings[LEFT], + &match) == lwc_error_ok && match)) { + value = FLOAT_LEFT; + } else if ((lwc_string_caseless_isequal( + ident->idata, c->strings[RIGHT], + &match) == lwc_error_ok && match)) { + value = FLOAT_RIGHT; + } else if ((lwc_string_caseless_isequal( + ident->idata, c->strings[NONE], + &match) == lwc_error_ok && match)) { + value = FLOAT_NONE; + } else { + *ctx = orig_ctx; + return CSS_INVALID; + } + + opv = buildOPV(CSS_PROP_FLOAT, flags, value); + + /* Allocate result */ + error = css_stylesheet_style_create(c->sheet, sizeof(opv), result); + if (error != CSS_OK) { + *ctx = orig_ctx; + return error; + } + + /* Copy the bytecode to it */ + memcpy((*result)->bytecode, &opv, sizeof(opv)); + + return CSS_OK; +} diff --git a/src/parse/properties/font.c b/src/parse/properties/font.c index af8c19f..c759dde 100644 --- a/src/parse/properties/font.c +++ b/src/parse/properties/font.c @@ -306,563 +306,8 @@ cleanup: return error; } -/** - * Determine if a given font-family ident is reserved - * - * \param c Parsing context - * \param ident IDENT to consider - * \return True if IDENT is reserved, false otherwise - */ -static bool font_family_reserved(css_language *c, const css_token *ident) -{ - bool match; - - return (lwc_string_caseless_isequal( - ident->idata, c->strings[SERIF], - &match) == lwc_error_ok && match) || - (lwc_string_caseless_isequal( - ident->idata, c->strings[SANS_SERIF], - &match) == lwc_error_ok && match) || - (lwc_string_caseless_isequal( - ident->idata, c->strings[CURSIVE], - &match) == lwc_error_ok && match) || - (lwc_string_caseless_isequal( - ident->idata, c->strings[FANTASY], - &match) == lwc_error_ok && match) || - (lwc_string_caseless_isequal( - ident->idata, c->strings[MONOSPACE], - &match) == lwc_error_ok && match); -} - -/** - * Convert a font-family token into a bytecode value - * - * \param c Parsing context - * \param token Token to consider - * \return Bytecode value - */ -static uint16_t font_family_value(css_language *c, const css_token *token) -{ - uint16_t value; - bool match; - - if (token->type == CSS_TOKEN_IDENT) { - if ((lwc_string_caseless_isequal( - token->idata, c->strings[SERIF], - &match) == lwc_error_ok && match)) - value = FONT_FAMILY_SERIF; - else if ((lwc_string_caseless_isequal( - token->idata, c->strings[SANS_SERIF], - &match) == lwc_error_ok && match)) - value = FONT_FAMILY_SANS_SERIF; - else if ((lwc_string_caseless_isequal( - token->idata, c->strings[CURSIVE], - &match) == lwc_error_ok && match)) - value = FONT_FAMILY_CURSIVE; - else if ((lwc_string_caseless_isequal( - token->idata, c->strings[FANTASY], - &match) == lwc_error_ok && match)) - value = FONT_FAMILY_FANTASY; - else if ((lwc_string_caseless_isequal( - token->idata, c->strings[MONOSPACE], - &match) == lwc_error_ok && match)) - value = FONT_FAMILY_MONOSPACE; - else - value = FONT_FAMILY_IDENT_LIST; - } else { - value = FONT_FAMILY_STRING; - } - - return value; -} - -/** - * Parse font-family - * - * \param c Parsing context - * \param vector Vector of tokens to process - * \param ctx Pointer to vector iteration context - * \param result Pointer to location to receive resulting style - * \return CSS_OK on success, - * CSS_NOMEM on memory exhaustion, - * CSS_INVALID if the input is not valid - * - * Post condition: \a *ctx is updated with the next token to process - * If the input is invalid, then \a *ctx remains unchanged. - */ -css_error parse_font_family(css_language *c, - const parserutils_vector *vector, int *ctx, - css_style **result) -{ - int orig_ctx = *ctx; - css_error error; - const css_token *token; - uint8_t flags = 0; - uint16_t value = 0; - uint32_t opv; - uint32_t required_size = sizeof(opv); - int temp_ctx = *ctx; - uint8_t *ptr; - bool match; - - /* [ IDENT+ | STRING ] [ ',' [ IDENT+ | STRING ] ]* | IDENT(inherit) - * - * In the case of IDENT+, any whitespace between tokens is collapsed to - * a single space - * - * \todo Mozilla makes the comma optional. - * Perhaps this is a quirk we should inherit? - */ - - /* Pass 1: validate input and calculate space */ - token = parserutils_vector_iterate(vector, &temp_ctx); - if (token == NULL || (token->type != CSS_TOKEN_IDENT && - token->type != CSS_TOKEN_STRING)) { - *ctx = orig_ctx; - return CSS_INVALID; - } - - if (token->type == CSS_TOKEN_IDENT && - (lwc_string_caseless_isequal( - token->idata, c->strings[INHERIT], - &match) == lwc_error_ok && match)) { - flags = FLAG_INHERIT; - } else { - uint32_t list_size; - - value = font_family_value(c, token); - - error = comma_list_length(c, vector, &temp_ctx, - token, font_family_reserved, &list_size); - if (error != CSS_OK) { - *ctx = orig_ctx; - return error; - } - - required_size += list_size; - } - - opv = buildOPV(CSS_PROP_FONT_FAMILY, flags, value); - - /* Allocate result */ - error = css_stylesheet_style_create(c->sheet, required_size, result); - if (error != CSS_OK) { - *ctx = orig_ctx; - return error; - } - - /* Copy OPV to bytecode */ - ptr = (*result)->bytecode; - memcpy(ptr, &opv, sizeof(opv)); - ptr += sizeof(opv); - - /* Pass 2: populate bytecode */ - token = parserutils_vector_iterate(vector, ctx); - if (token == NULL || (token->type != CSS_TOKEN_IDENT && - token->type != CSS_TOKEN_STRING)) { - css_stylesheet_style_destroy(c->sheet, *result, false); - *result = NULL; - *ctx = orig_ctx; - return CSS_INVALID; - } - - if (token->type == CSS_TOKEN_IDENT && - (lwc_string_caseless_isequal( - token->idata, c->strings[INHERIT], - &match) == lwc_error_ok && match)) { - /* Nothing to do */ - } else { - error = comma_list_to_bytecode(c, vector, ctx, token, - font_family_reserved, font_family_value, - &ptr); - if (error != CSS_OK) { - css_stylesheet_style_destroy(c->sheet, *result, false); - *result = NULL; - *ctx = orig_ctx; - return error; - } - /* Write terminator */ - opv = FONT_FAMILY_END; - memcpy(ptr, &opv, sizeof(opv)); - ptr += sizeof(opv); - } - return CSS_OK; -} -/** - * Parse font-size - * - * \param c Parsing context - * \param vector Vector of tokens to process - * \param ctx Pointer to vector iteration context - * \param result Pointer to location to receive resulting style - * \return CSS_OK on success, - * CSS_NOMEM on memory exhaustion, - * CSS_INVALID if the input is not valid - * - * Post condition: \a *ctx is updated with the next token to process - * If the input is invalid, then \a *ctx remains unchanged. - */ -css_error parse_font_size(css_language *c, - const parserutils_vector *vector, int *ctx, - css_style **result) -{ - int orig_ctx = *ctx; - css_error error; - const css_token *token; - uint8_t flags = 0; - uint16_t value = 0; - uint32_t opv; - css_fixed length = 0; - uint32_t unit = 0; - uint32_t required_size; - bool match; - /* length | percentage | IDENT(xx-small, x-small, small, medium, - * large, x-large, xx-large, larger, smaller, inherit) */ - token = parserutils_vector_peek(vector, *ctx); - if (token == NULL) { - *ctx = orig_ctx; - return CSS_INVALID; - } - - if (token->type == CSS_TOKEN_IDENT && - (lwc_string_caseless_isequal( - token->idata, c->strings[INHERIT], - &match) == lwc_error_ok && match)) { - parserutils_vector_iterate(vector, ctx); - flags = FLAG_INHERIT; - } else if (token->type == CSS_TOKEN_IDENT && - (lwc_string_caseless_isequal( - token->idata, c->strings[XX_SMALL], - &match) == lwc_error_ok && match)) { - parserutils_vector_iterate(vector, ctx); - value = FONT_SIZE_XX_SMALL; - } else if (token->type == CSS_TOKEN_IDENT && - (lwc_string_caseless_isequal( - token->idata, c->strings[X_SMALL], - &match) == lwc_error_ok && match)) { - parserutils_vector_iterate(vector, ctx); - value = FONT_SIZE_X_SMALL; - } else if (token->type == CSS_TOKEN_IDENT && - (lwc_string_caseless_isequal( - token->idata, c->strings[SMALL], - &match) == lwc_error_ok && match)) { - parserutils_vector_iterate(vector, ctx); - value = FONT_SIZE_SMALL; - } else if (token->type == CSS_TOKEN_IDENT && - (lwc_string_caseless_isequal( - token->idata, c->strings[MEDIUM], - &match) == lwc_error_ok && match)) { - parserutils_vector_iterate(vector, ctx); - value = FONT_SIZE_MEDIUM; - } else if (token->type == CSS_TOKEN_IDENT && - (lwc_string_caseless_isequal( - token->idata, c->strings[LARGE], - &match) == lwc_error_ok && match)) { - parserutils_vector_iterate(vector, ctx); - value = FONT_SIZE_LARGE; - } else if (token->type == CSS_TOKEN_IDENT && - (lwc_string_caseless_isequal( - token->idata, c->strings[X_LARGE], - &match) == lwc_error_ok && match)) { - parserutils_vector_iterate(vector, ctx); - value = FONT_SIZE_X_LARGE; - } else if (token->type == CSS_TOKEN_IDENT && - (lwc_string_caseless_isequal( - token->idata, c->strings[XX_LARGE], - &match) == lwc_error_ok && match)) { - parserutils_vector_iterate(vector, ctx); - value = FONT_SIZE_XX_LARGE; - } else if (token->type == CSS_TOKEN_IDENT && - (lwc_string_caseless_isequal( - token->idata, c->strings[LARGER], - &match) == lwc_error_ok && match)) { - parserutils_vector_iterate(vector, ctx); - value = FONT_SIZE_LARGER; - } else if (token->type == CSS_TOKEN_IDENT && - (lwc_string_caseless_isequal( - token->idata, c->strings[SMALLER], - &match) == lwc_error_ok && match)) { - parserutils_vector_iterate(vector, ctx); - value = FONT_SIZE_SMALLER; - } else { - error = parse_unit_specifier(c, vector, ctx, UNIT_PX, - &length, &unit); - if (error != CSS_OK) { - *ctx = orig_ctx; - return error; - } - - if (unit & UNIT_ANGLE || unit & UNIT_TIME || unit & UNIT_FREQ) { - *ctx = orig_ctx; - return CSS_INVALID; - } - - /* Negative values are not permitted */ - if (length < 0) { - *ctx = orig_ctx; - return CSS_INVALID; - } - - value = FONT_SIZE_DIMENSION; - } - - opv = buildOPV(CSS_PROP_FONT_SIZE, flags, value); - - required_size = sizeof(opv); - if ((flags & FLAG_INHERIT) == false && value == FONT_SIZE_DIMENSION) - required_size += sizeof(length) + sizeof(unit); - - /* Allocate result */ - error = css_stylesheet_style_create(c->sheet, required_size, result); - if (error != CSS_OK) { - *ctx = orig_ctx; - return error; - } - - /* Copy the bytecode to it */ - memcpy((*result)->bytecode, &opv, sizeof(opv)); - if ((flags & FLAG_INHERIT) == false && value == FONT_SIZE_DIMENSION) { - memcpy(((uint8_t *) (*result)->bytecode) + sizeof(opv), - &length, sizeof(length)); - memcpy(((uint8_t *) (*result)->bytecode) + sizeof(opv) + - sizeof(length), &unit, sizeof(unit)); - } - - return CSS_OK; -} - -/** - * Parse font-style - * - * \param c Parsing context - * \param vector Vector of tokens to process - * \param ctx Pointer to vector iteration context - * \param result Pointer to location to receive resulting style - * \return CSS_OK on success, - * CSS_NOMEM on memory exhaustion, - * CSS_INVALID if the input is not valid - * - * Post condition: \a *ctx is updated with the next token to process - * If the input is invalid, then \a *ctx remains unchanged. - */ -css_error parse_font_style(css_language *c, - const parserutils_vector *vector, int *ctx, - css_style **result) -{ - int orig_ctx = *ctx; - css_error error; - const css_token *ident; - uint8_t flags = 0; - uint16_t value = 0; - uint32_t opv; - bool match; - - /* IDENT (normal, italic, oblique, inherit) */ - ident = parserutils_vector_iterate(vector, ctx); - if (ident == NULL || ident->type != CSS_TOKEN_IDENT) { - *ctx = orig_ctx; - return CSS_INVALID; - } - - if ((lwc_string_caseless_isequal( - ident->idata, c->strings[INHERIT], - &match) == lwc_error_ok && match)) { - flags |= FLAG_INHERIT; - } else if ((lwc_string_caseless_isequal( - ident->idata, c->strings[NORMAL], - &match) == lwc_error_ok && match)) { - value = FONT_STYLE_NORMAL; - } else if ((lwc_string_caseless_isequal( - ident->idata, c->strings[ITALIC], - &match) == lwc_error_ok && match)) { - value = FONT_STYLE_ITALIC; - } else if ((lwc_string_caseless_isequal( - ident->idata, c->strings[OBLIQUE], - &match) == lwc_error_ok && match)) { - value = FONT_STYLE_OBLIQUE; - } else { - *ctx = orig_ctx; - return CSS_INVALID; - } - - opv = buildOPV(CSS_PROP_FONT_STYLE, flags, value); - - /* Allocate result */ - error = css_stylesheet_style_create(c->sheet, sizeof(opv), result); - if (error != CSS_OK) { - *ctx = orig_ctx; - return error; - } - - /* Copy the bytecode to it */ - memcpy((*result)->bytecode, &opv, sizeof(opv)); - - return CSS_OK; -} - -/** - * Parse font-variant - * - * \param c Parsing context - * \param vector Vector of tokens to process - * \param ctx Pointer to vector iteration context - * \param result Pointer to location to receive resulting style - * \return CSS_OK on success, - * CSS_NOMEM on memory exhaustion, - * CSS_INVALID if the input is not valid - * - * Post condition: \a *ctx is updated with the next token to process - * If the input is invalid, then \a *ctx remains unchanged. - */ -css_error parse_font_variant(css_language *c, - const parserutils_vector *vector, int *ctx, - css_style **result) -{ - int orig_ctx = *ctx; - css_error error; - const css_token *ident; - uint8_t flags = 0; - uint16_t value = 0; - uint32_t opv; - bool match; - - /* IDENT (normal, small-caps, inherit) */ - ident = parserutils_vector_iterate(vector, ctx); - if (ident == NULL || ident->type != CSS_TOKEN_IDENT) { - *ctx = orig_ctx; - return CSS_INVALID; - } - - if ((lwc_string_caseless_isequal( - ident->idata, c->strings[INHERIT], - &match) == lwc_error_ok && match)) { - flags |= FLAG_INHERIT; - } else if ((lwc_string_caseless_isequal( - ident->idata, c->strings[NORMAL], - &match) == lwc_error_ok && match)) { - value = FONT_VARIANT_NORMAL; - } else if ((lwc_string_caseless_isequal( - ident->idata, c->strings[SMALL_CAPS], - &match) == lwc_error_ok && match)) { - value = FONT_VARIANT_SMALL_CAPS; - } else { - *ctx = orig_ctx; - return CSS_INVALID; - } - - opv = buildOPV(CSS_PROP_FONT_VARIANT, flags, value); - - /* Allocate result */ - error = css_stylesheet_style_create(c->sheet, sizeof(opv), result); - if (error != CSS_OK) { - *ctx = orig_ctx; - return error; - } - - /* Copy the bytecode to it */ - memcpy((*result)->bytecode, &opv, sizeof(opv)); - - return CSS_OK; -} - -/** - * Parse font-weight - * - * \param c Parsing context - * \param vector Vector of tokens to process - * \param ctx Pointer to vector iteration context - * \param result Pointer to location to receive resulting style - * \return CSS_OK on success, - * CSS_NOMEM on memory exhaustion, - * CSS_INVALID if the input is not valid - * - * Post condition: \a *ctx is updated with the next token to process - * If the input is invalid, then \a *ctx remains unchanged. - */ -css_error parse_font_weight(css_language *c, - const parserutils_vector *vector, int *ctx, - css_style **result) -{ - int orig_ctx = *ctx; - css_error error; - const css_token *token; - uint8_t flags = 0; - uint16_t value = 0; - uint32_t opv; - bool match; - - /* NUMBER (100, 200, 300, 400, 500, 600, 700, 800, 900) | - * IDENT (normal, bold, bolder, lighter, inherit) */ - token = parserutils_vector_iterate(vector, ctx); - if (token == NULL || (token->type != CSS_TOKEN_IDENT && - token->type != CSS_TOKEN_NUMBER)) { - *ctx = orig_ctx; - return CSS_INVALID; - } - - if ((lwc_string_caseless_isequal( - token->idata, c->strings[INHERIT], - &match) == lwc_error_ok && match)) { - flags |= FLAG_INHERIT; - } else if (token->type == CSS_TOKEN_NUMBER) { - size_t consumed = 0; - css_fixed num = number_from_lwc_string(token->idata, - true, &consumed); - /* Invalid if there are trailing characters */ - if (consumed != lwc_string_length(token->idata)) { - *ctx = orig_ctx; - return CSS_INVALID; - } - - switch (FIXTOINT(num)) { - case 100: value = FONT_WEIGHT_100; break; - case 200: value = FONT_WEIGHT_200; break; - case 300: value = FONT_WEIGHT_300; break; - case 400: value = FONT_WEIGHT_400; break; - case 500: value = FONT_WEIGHT_500; break; - case 600: value = FONT_WEIGHT_600; break; - case 700: value = FONT_WEIGHT_700; break; - case 800: value = FONT_WEIGHT_800; break; - case 900: value = FONT_WEIGHT_900; break; - default: *ctx = orig_ctx; return CSS_INVALID; - } - } else if ((lwc_string_caseless_isequal( - token->idata, c->strings[NORMAL], - &match) == lwc_error_ok && match)) { - value = FONT_WEIGHT_NORMAL; - } else if ((lwc_string_caseless_isequal( - token->idata, c->strings[BOLD], - &match) == lwc_error_ok && match)) { - value = FONT_WEIGHT_BOLD; - } else if ((lwc_string_caseless_isequal( - token->idata, c->strings[BOLDER], - &match) == lwc_error_ok && match)) { - value = FONT_WEIGHT_BOLDER; - } else if ((lwc_string_caseless_isequal( - token->idata, c->strings[LIGHTER], - &match) == lwc_error_ok && match)) { - value = FONT_WEIGHT_LIGHTER; - } else { - *ctx = orig_ctx; - return CSS_INVALID; - } - - opv = buildOPV(CSS_PROP_FONT_WEIGHT, flags, value); - - /* Allocate result */ - error = css_stylesheet_style_create(c->sheet, sizeof(opv), result); - if (error != CSS_OK) { - *ctx = orig_ctx; - return error; - } - - /* Copy the bytecode to it */ - memcpy((*result)->bytecode, &opv, sizeof(opv)); - - return CSS_OK; -} diff --git a/src/parse/properties/font_family.c b/src/parse/properties/font_family.c new file mode 100644 index 0000000..d551e5d --- /dev/null +++ b/src/parse/properties/font_family.c @@ -0,0 +1,199 @@ +/* + * This file is part of LibCSS. + * Licensed under the MIT License, + * http://www.opensource.org/licenses/mit-license.php + * Copyright 2009 John-Mark Bell + */ + +#include +#include + +#include "bytecode/bytecode.h" +#include "bytecode/opcodes.h" +#include "parse/properties/properties.h" +#include "parse/properties/utils.h" + +/** + * Determine if a given font-family ident is reserved + * + * \param c Parsing context + * \param ident IDENT to consider + * \return True if IDENT is reserved, false otherwise + */ +static bool font_family_reserved(css_language *c, const css_token *ident) +{ + bool match; + + return (lwc_string_caseless_isequal( + ident->idata, c->strings[SERIF], + &match) == lwc_error_ok && match) || + (lwc_string_caseless_isequal( + ident->idata, c->strings[SANS_SERIF], + &match) == lwc_error_ok && match) || + (lwc_string_caseless_isequal( + ident->idata, c->strings[CURSIVE], + &match) == lwc_error_ok && match) || + (lwc_string_caseless_isequal( + ident->idata, c->strings[FANTASY], + &match) == lwc_error_ok && match) || + (lwc_string_caseless_isequal( + ident->idata, c->strings[MONOSPACE], + &match) == lwc_error_ok && match); +} + +/** + * Convert a font-family token into a bytecode value + * + * \param c Parsing context + * \param token Token to consider + * \return Bytecode value + */ +static uint16_t font_family_value(css_language *c, const css_token *token) +{ + uint16_t value; + bool match; + + if (token->type == CSS_TOKEN_IDENT) { + if ((lwc_string_caseless_isequal( + token->idata, c->strings[SERIF], + &match) == lwc_error_ok && match)) + value = FONT_FAMILY_SERIF; + else if ((lwc_string_caseless_isequal( + token->idata, c->strings[SANS_SERIF], + &match) == lwc_error_ok && match)) + value = FONT_FAMILY_SANS_SERIF; + else if ((lwc_string_caseless_isequal( + token->idata, c->strings[CURSIVE], + &match) == lwc_error_ok && match)) + value = FONT_FAMILY_CURSIVE; + else if ((lwc_string_caseless_isequal( + token->idata, c->strings[FANTASY], + &match) == lwc_error_ok && match)) + value = FONT_FAMILY_FANTASY; + else if ((lwc_string_caseless_isequal( + token->idata, c->strings[MONOSPACE], + &match) == lwc_error_ok && match)) + value = FONT_FAMILY_MONOSPACE; + else + value = FONT_FAMILY_IDENT_LIST; + } else { + value = FONT_FAMILY_STRING; + } + + return value; +} + +/** + * Parse font-family + * + * \param c Parsing context + * \param vector Vector of tokens to process + * \param ctx Pointer to vector iteration context + * \param result Pointer to location to receive resulting style + * \return CSS_OK on success, + * CSS_NOMEM on memory exhaustion, + * CSS_INVALID if the input is not valid + * + * Post condition: \a *ctx is updated with the next token to process + * If the input is invalid, then \a *ctx remains unchanged. + */ +css_error parse_font_family(css_language *c, + const parserutils_vector *vector, int *ctx, + css_style **result) +{ + int orig_ctx = *ctx; + css_error error; + const css_token *token; + uint8_t flags = 0; + uint16_t value = 0; + uint32_t opv; + uint32_t required_size = sizeof(opv); + int temp_ctx = *ctx; + uint8_t *ptr; + bool match; + + /* [ IDENT+ | STRING ] [ ',' [ IDENT+ | STRING ] ]* | IDENT(inherit) + * + * In the case of IDENT+, any whitespace between tokens is collapsed to + * a single space + * + * \todo Mozilla makes the comma optional. + * Perhaps this is a quirk we should inherit? + */ + + /* Pass 1: validate input and calculate space */ + token = parserutils_vector_iterate(vector, &temp_ctx); + if (token == NULL || (token->type != CSS_TOKEN_IDENT && + token->type != CSS_TOKEN_STRING)) { + *ctx = orig_ctx; + return CSS_INVALID; + } + + if (token->type == CSS_TOKEN_IDENT && + (lwc_string_caseless_isequal( + token->idata, c->strings[INHERIT], + &match) == lwc_error_ok && match)) { + flags = FLAG_INHERIT; + } else { + uint32_t list_size; + + value = font_family_value(c, token); + + error = comma_list_length(c, vector, &temp_ctx, + token, font_family_reserved, &list_size); + if (error != CSS_OK) { + *ctx = orig_ctx; + return error; + } + + required_size += list_size; + } + + opv = buildOPV(CSS_PROP_FONT_FAMILY, flags, value); + + /* Allocate result */ + error = css_stylesheet_style_create(c->sheet, required_size, result); + if (error != CSS_OK) { + *ctx = orig_ctx; + return error; + } + + /* Copy OPV to bytecode */ + ptr = (*result)->bytecode; + memcpy(ptr, &opv, sizeof(opv)); + ptr += sizeof(opv); + + /* Pass 2: populate bytecode */ + token = parserutils_vector_iterate(vector, ctx); + if (token == NULL || (token->type != CSS_TOKEN_IDENT && + token->type != CSS_TOKEN_STRING)) { + css_stylesheet_style_destroy(c->sheet, *result, false); + *result = NULL; + *ctx = orig_ctx; + return CSS_INVALID; + } + + if (token->type == CSS_TOKEN_IDENT && + (lwc_string_caseless_isequal( + token->idata, c->strings[INHERIT], + &match) == lwc_error_ok && match)) { + /* Nothing to do */ + } else { + error = comma_list_to_bytecode(c, vector, ctx, token, + font_family_reserved, font_family_value, + &ptr); + if (error != CSS_OK) { + css_stylesheet_style_destroy(c->sheet, *result, false); + *result = NULL; + *ctx = orig_ctx; + return error; + } + + /* Write terminator */ + opv = FONT_FAMILY_END; + memcpy(ptr, &opv, sizeof(opv)); + ptr += sizeof(opv); + } + + return CSS_OK; +} diff --git a/src/parse/properties/font_size.c b/src/parse/properties/font_size.c new file mode 100644 index 0000000..8b02362 --- /dev/null +++ b/src/parse/properties/font_size.c @@ -0,0 +1,158 @@ +/* + * This file is part of LibCSS. + * Licensed under the MIT License, + * http://www.opensource.org/licenses/mit-license.php + * Copyright 2009 John-Mark Bell + */ + +#include +#include + +#include "bytecode/bytecode.h" +#include "bytecode/opcodes.h" +#include "parse/properties/properties.h" +#include "parse/properties/utils.h" + +/** + * Parse font-size + * + * \param c Parsing context + * \param vector Vector of tokens to process + * \param ctx Pointer to vector iteration context + * \param result Pointer to location to receive resulting style + * \return CSS_OK on success, + * CSS_NOMEM on memory exhaustion, + * CSS_INVALID if the input is not valid + * + * Post condition: \a *ctx is updated with the next token to process + * If the input is invalid, then \a *ctx remains unchanged. + */ +css_error parse_font_size(css_language *c, + const parserutils_vector *vector, int *ctx, + css_style **result) +{ + int orig_ctx = *ctx; + css_error error; + const css_token *token; + uint8_t flags = 0; + uint16_t value = 0; + uint32_t opv; + css_fixed length = 0; + uint32_t unit = 0; + uint32_t required_size; + bool match; + + /* length | percentage | IDENT(xx-small, x-small, small, medium, + * large, x-large, xx-large, larger, smaller, inherit) */ + token = parserutils_vector_peek(vector, *ctx); + if (token == NULL) { + *ctx = orig_ctx; + return CSS_INVALID; + } + + if (token->type == CSS_TOKEN_IDENT && + (lwc_string_caseless_isequal( + token->idata, c->strings[INHERIT], + &match) == lwc_error_ok && match)) { + parserutils_vector_iterate(vector, ctx); + flags = FLAG_INHERIT; + } else if (token->type == CSS_TOKEN_IDENT && + (lwc_string_caseless_isequal( + token->idata, c->strings[XX_SMALL], + &match) == lwc_error_ok && match)) { + parserutils_vector_iterate(vector, ctx); + value = FONT_SIZE_XX_SMALL; + } else if (token->type == CSS_TOKEN_IDENT && + (lwc_string_caseless_isequal( + token->idata, c->strings[X_SMALL], + &match) == lwc_error_ok && match)) { + parserutils_vector_iterate(vector, ctx); + value = FONT_SIZE_X_SMALL; + } else if (token->type == CSS_TOKEN_IDENT && + (lwc_string_caseless_isequal( + token->idata, c->strings[SMALL], + &match) == lwc_error_ok && match)) { + parserutils_vector_iterate(vector, ctx); + value = FONT_SIZE_SMALL; + } else if (token->type == CSS_TOKEN_IDENT && + (lwc_string_caseless_isequal( + token->idata, c->strings[MEDIUM], + &match) == lwc_error_ok && match)) { + parserutils_vector_iterate(vector, ctx); + value = FONT_SIZE_MEDIUM; + } else if (token->type == CSS_TOKEN_IDENT && + (lwc_string_caseless_isequal( + token->idata, c->strings[LARGE], + &match) == lwc_error_ok && match)) { + parserutils_vector_iterate(vector, ctx); + value = FONT_SIZE_LARGE; + } else if (token->type == CSS_TOKEN_IDENT && + (lwc_string_caseless_isequal( + token->idata, c->strings[X_LARGE], + &match) == lwc_error_ok && match)) { + parserutils_vector_iterate(vector, ctx); + value = FONT_SIZE_X_LARGE; + } else if (token->type == CSS_TOKEN_IDENT && + (lwc_string_caseless_isequal( + token->idata, c->strings[XX_LARGE], + &match) == lwc_error_ok && match)) { + parserutils_vector_iterate(vector, ctx); + value = FONT_SIZE_XX_LARGE; + } else if (token->type == CSS_TOKEN_IDENT && + (lwc_string_caseless_isequal( + token->idata, c->strings[LARGER], + &match) == lwc_error_ok && match)) { + parserutils_vector_iterate(vector, ctx); + value = FONT_SIZE_LARGER; + } else if (token->type == CSS_TOKEN_IDENT && + (lwc_string_caseless_isequal( + token->idata, c->strings[SMALLER], + &match) == lwc_error_ok && match)) { + parserutils_vector_iterate(vector, ctx); + value = FONT_SIZE_SMALLER; + } else { + error = parse_unit_specifier(c, vector, ctx, UNIT_PX, + &length, &unit); + if (error != CSS_OK) { + *ctx = orig_ctx; + return error; + } + + if (unit & UNIT_ANGLE || unit & UNIT_TIME || unit & UNIT_FREQ) { + *ctx = orig_ctx; + return CSS_INVALID; + } + + /* Negative values are not permitted */ + if (length < 0) { + *ctx = orig_ctx; + return CSS_INVALID; + } + + value = FONT_SIZE_DIMENSION; + } + + opv = buildOPV(CSS_PROP_FONT_SIZE, flags, value); + + required_size = sizeof(opv); + if ((flags & FLAG_INHERIT) == false && value == FONT_SIZE_DIMENSION) + required_size += sizeof(length) + sizeof(unit); + + /* Allocate result */ + error = css_stylesheet_style_create(c->sheet, required_size, result); + if (error != CSS_OK) { + *ctx = orig_ctx; + return error; + } + + /* Copy the bytecode to it */ + memcpy((*result)->bytecode, &opv, sizeof(opv)); + if ((flags & FLAG_INHERIT) == false && value == FONT_SIZE_DIMENSION) { + memcpy(((uint8_t *) (*result)->bytecode) + sizeof(opv), + &length, sizeof(length)); + memcpy(((uint8_t *) (*result)->bytecode) + sizeof(opv) + + sizeof(length), &unit, sizeof(unit)); + } + + return CSS_OK; +} diff --git a/src/parse/properties/font_style.c b/src/parse/properties/font_style.c new file mode 100644 index 0000000..1deeb83 --- /dev/null +++ b/src/parse/properties/font_style.c @@ -0,0 +1,83 @@ +/* + * This file is part of LibCSS. + * Licensed under the MIT License, + * http://www.opensource.org/licenses/mit-license.php + * Copyright 2009 John-Mark Bell + */ + +#include +#include + +#include "bytecode/bytecode.h" +#include "bytecode/opcodes.h" +#include "parse/properties/properties.h" +#include "parse/properties/utils.h" + +/** + * Parse font-style + * + * \param c Parsing context + * \param vector Vector of tokens to process + * \param ctx Pointer to vector iteration context + * \param result Pointer to location to receive resulting style + * \return CSS_OK on success, + * CSS_NOMEM on memory exhaustion, + * CSS_INVALID if the input is not valid + * + * Post condition: \a *ctx is updated with the next token to process + * If the input is invalid, then \a *ctx remains unchanged. + */ +css_error parse_font_style(css_language *c, + const parserutils_vector *vector, int *ctx, + css_style **result) +{ + int orig_ctx = *ctx; + css_error error; + const css_token *ident; + uint8_t flags = 0; + uint16_t value = 0; + uint32_t opv; + bool match; + + /* IDENT (normal, italic, oblique, inherit) */ + ident = parserutils_vector_iterate(vector, ctx); + if (ident == NULL || ident->type != CSS_TOKEN_IDENT) { + *ctx = orig_ctx; + return CSS_INVALID; + } + + if ((lwc_string_caseless_isequal( + ident->idata, c->strings[INHERIT], + &match) == lwc_error_ok && match)) { + flags |= FLAG_INHERIT; + } else if ((lwc_string_caseless_isequal( + ident->idata, c->strings[NORMAL], + &match) == lwc_error_ok && match)) { + value = FONT_STYLE_NORMAL; + } else if ((lwc_string_caseless_isequal( + ident->idata, c->strings[ITALIC], + &match) == lwc_error_ok && match)) { + value = FONT_STYLE_ITALIC; + } else if ((lwc_string_caseless_isequal( + ident->idata, c->strings[OBLIQUE], + &match) == lwc_error_ok && match)) { + value = FONT_STYLE_OBLIQUE; + } else { + *ctx = orig_ctx; + return CSS_INVALID; + } + + opv = buildOPV(CSS_PROP_FONT_STYLE, flags, value); + + /* Allocate result */ + error = css_stylesheet_style_create(c->sheet, sizeof(opv), result); + if (error != CSS_OK) { + *ctx = orig_ctx; + return error; + } + + /* Copy the bytecode to it */ + memcpy((*result)->bytecode, &opv, sizeof(opv)); + + return CSS_OK; +} diff --git a/src/parse/properties/font_variant.c b/src/parse/properties/font_variant.c new file mode 100644 index 0000000..b350e86 --- /dev/null +++ b/src/parse/properties/font_variant.c @@ -0,0 +1,79 @@ +/* + * This file is part of LibCSS. + * Licensed under the MIT License, + * http://www.opensource.org/licenses/mit-license.php + * Copyright 2009 John-Mark Bell + */ + +#include +#include + +#include "bytecode/bytecode.h" +#include "bytecode/opcodes.h" +#include "parse/properties/properties.h" +#include "parse/properties/utils.h" + +/** + * Parse font-variant + * + * \param c Parsing context + * \param vector Vector of tokens to process + * \param ctx Pointer to vector iteration context + * \param result Pointer to location to receive resulting style + * \return CSS_OK on success, + * CSS_NOMEM on memory exhaustion, + * CSS_INVALID if the input is not valid + * + * Post condition: \a *ctx is updated with the next token to process + * If the input is invalid, then \a *ctx remains unchanged. + */ +css_error parse_font_variant(css_language *c, + const parserutils_vector *vector, int *ctx, + css_style **result) +{ + int orig_ctx = *ctx; + css_error error; + const css_token *ident; + uint8_t flags = 0; + uint16_t value = 0; + uint32_t opv; + bool match; + + /* IDENT (normal, small-caps, inherit) */ + ident = parserutils_vector_iterate(vector, ctx); + if (ident == NULL || ident->type != CSS_TOKEN_IDENT) { + *ctx = orig_ctx; + return CSS_INVALID; + } + + if ((lwc_string_caseless_isequal( + ident->idata, c->strings[INHERIT], + &match) == lwc_error_ok && match)) { + flags |= FLAG_INHERIT; + } else if ((lwc_string_caseless_isequal( + ident->idata, c->strings[NORMAL], + &match) == lwc_error_ok && match)) { + value = FONT_VARIANT_NORMAL; + } else if ((lwc_string_caseless_isequal( + ident->idata, c->strings[SMALL_CAPS], + &match) == lwc_error_ok && match)) { + value = FONT_VARIANT_SMALL_CAPS; + } else { + *ctx = orig_ctx; + return CSS_INVALID; + } + + opv = buildOPV(CSS_PROP_FONT_VARIANT, flags, value); + + /* Allocate result */ + error = css_stylesheet_style_create(c->sheet, sizeof(opv), result); + if (error != CSS_OK) { + *ctx = orig_ctx; + return error; + } + + /* Copy the bytecode to it */ + memcpy((*result)->bytecode, &opv, sizeof(opv)); + + return CSS_OK; +} diff --git a/src/parse/properties/font_weight.c b/src/parse/properties/font_weight.c new file mode 100644 index 0000000..df35c0d --- /dev/null +++ b/src/parse/properties/font_weight.c @@ -0,0 +1,111 @@ +/* + * This file is part of LibCSS. + * Licensed under the MIT License, + * http://www.opensource.org/licenses/mit-license.php + * Copyright 2009 John-Mark Bell + */ + +#include +#include + +#include "bytecode/bytecode.h" +#include "bytecode/opcodes.h" +#include "parse/properties/properties.h" +#include "parse/properties/utils.h" + +/** + * Parse font-weight + * + * \param c Parsing context + * \param vector Vector of tokens to process + * \param ctx Pointer to vector iteration context + * \param result Pointer to location to receive resulting style + * \return CSS_OK on success, + * CSS_NOMEM on memory exhaustion, + * CSS_INVALID if the input is not valid + * + * Post condition: \a *ctx is updated with the next token to process + * If the input is invalid, then \a *ctx remains unchanged. + */ +css_error parse_font_weight(css_language *c, + const parserutils_vector *vector, int *ctx, + css_style **result) +{ + int orig_ctx = *ctx; + css_error error; + const css_token *token; + uint8_t flags = 0; + uint16_t value = 0; + uint32_t opv; + bool match; + + /* NUMBER (100, 200, 300, 400, 500, 600, 700, 800, 900) | + * IDENT (normal, bold, bolder, lighter, inherit) */ + token = parserutils_vector_iterate(vector, ctx); + if (token == NULL || (token->type != CSS_TOKEN_IDENT && + token->type != CSS_TOKEN_NUMBER)) { + *ctx = orig_ctx; + return CSS_INVALID; + } + + if ((lwc_string_caseless_isequal( + token->idata, c->strings[INHERIT], + &match) == lwc_error_ok && match)) { + flags |= FLAG_INHERIT; + } else if (token->type == CSS_TOKEN_NUMBER) { + size_t consumed = 0; + css_fixed num = number_from_lwc_string(token->idata, + true, &consumed); + /* Invalid if there are trailing characters */ + if (consumed != lwc_string_length(token->idata)) { + *ctx = orig_ctx; + return CSS_INVALID; + } + + switch (FIXTOINT(num)) { + case 100: value = FONT_WEIGHT_100; break; + case 200: value = FONT_WEIGHT_200; break; + case 300: value = FONT_WEIGHT_300; break; + case 400: value = FONT_WEIGHT_400; break; + case 500: value = FONT_WEIGHT_500; break; + case 600: value = FONT_WEIGHT_600; break; + case 700: value = FONT_WEIGHT_700; break; + case 800: value = FONT_WEIGHT_800; break; + case 900: value = FONT_WEIGHT_900; break; + default: *ctx = orig_ctx; return CSS_INVALID; + } + } else if ((lwc_string_caseless_isequal( + token->idata, c->strings[NORMAL], + &match) == lwc_error_ok && match)) { + value = FONT_WEIGHT_NORMAL; + } else if ((lwc_string_caseless_isequal( + token->idata, c->strings[BOLD], + &match) == lwc_error_ok && match)) { + value = FONT_WEIGHT_BOLD; + } else if ((lwc_string_caseless_isequal( + token->idata, c->strings[BOLDER], + &match) == lwc_error_ok && match)) { + value = FONT_WEIGHT_BOLDER; + } else if ((lwc_string_caseless_isequal( + token->idata, c->strings[LIGHTER], + &match) == lwc_error_ok && match)) { + value = FONT_WEIGHT_LIGHTER; + } else { + *ctx = orig_ctx; + return CSS_INVALID; + } + + opv = buildOPV(CSS_PROP_FONT_WEIGHT, flags, value); + + /* Allocate result */ + error = css_stylesheet_style_create(c->sheet, sizeof(opv), result); + if (error != CSS_OK) { + *ctx = orig_ctx; + return error; + } + + /* Copy the bytecode to it */ + memcpy((*result)->bytecode, &opv, sizeof(opv)); + + return CSS_OK; +} diff --git a/src/parse/properties/generated_list.c b/src/parse/properties/generated_list.c deleted file mode 100644 index f20eade..0000000 --- a/src/parse/properties/generated_list.c +++ /dev/null @@ -1,1464 +0,0 @@ -/* - * This file is part of LibCSS. - * Licensed under the MIT License, - * http://www.opensource.org/licenses/mit-license.php - * Copyright 2009 John-Mark Bell - */ - -#include -#include - -#include "bytecode/bytecode.h" -#include "bytecode/opcodes.h" -#include "parse/properties/properties.h" -#include "parse/properties/utils.h" - -static css_error parse_list_style_type_value(css_language *c, - const css_token *token, uint16_t *value); -static css_error parse_content_list(css_language *c, - const parserutils_vector *vector, int *ctx, - uint16_t *value, uint8_t *buffer, uint32_t *buflen); -static css_error parse_counter_common(css_language *c, - const parserutils_vector *vector, int *ctx, - uint16_t op, css_style **result); - -/** - * Parse content - * - * \param c Parsing context - * \param vector Vector of tokens to process - * \param ctx Pointer to vector iteration context - * \param result Pointer to location to receive resulting style - * \return CSS_OK on success, - * CSS_NOMEM on memory exhaustion, - * CSS_INVALID if the input is not valid - * - * Post condition: \a *ctx is updated with the next token to process - * If the input is invalid, then \a *ctx remains unchanged. - */ -css_error parse_content(css_language *c, - const parserutils_vector *vector, int *ctx, - css_style **result) -{ - int orig_ctx = *ctx; - css_error error; - const css_token *token; - uint8_t flags = 0; - uint16_t value = 0; - uint32_t opv; - uint32_t required_size = sizeof(opv); - int temp_ctx = *ctx; - uint8_t *ptr; - bool match; - - /* IDENT(normal, none, inherit) | - * [ - * IDENT(open-quote, close-quote, no-open-quote, no-close-quote) | - * STRING | URI | - * FUNCTION(attr) IDENT ')' | - * FUNCTION(counter) IDENT IDENT? ')' | - * FUNCTION(counters) IDENT STRING IDENT? ')' - * ]+ - */ - - /* Pass 1: Calculate required size & validate input */ - token = parserutils_vector_peek(vector, temp_ctx); - if (token == NULL) { - *ctx = orig_ctx; - return CSS_INVALID; - } - - if (token->type == CSS_TOKEN_IDENT && - (lwc_string_caseless_isequal( - token->idata, c->strings[INHERIT], - &match) == lwc_error_ok && match)) { - flags = FLAG_INHERIT; - parserutils_vector_iterate(vector, &temp_ctx); - } else if (token->type == CSS_TOKEN_IDENT && - (lwc_string_caseless_isequal( - token->idata, c->strings[NORMAL], - &match) == lwc_error_ok && match)) { - value = CONTENT_NORMAL; - parserutils_vector_iterate(vector, &temp_ctx); - } else if (token->type == CSS_TOKEN_IDENT && - (lwc_string_caseless_isequal( - token->idata, c->strings[NONE], - &match) == lwc_error_ok && match)) { - value = CONTENT_NONE; - parserutils_vector_iterate(vector, &temp_ctx); - } else { - uint32_t len; - - error = parse_content_list(c, vector, &temp_ctx, &value, - NULL, &len); - if (error != CSS_OK) { - *ctx = orig_ctx; - return error; - } - - required_size += len; - } - - opv = buildOPV(CSS_PROP_CONTENT, flags, value); - - /* Allocate result */ - error = css_stylesheet_style_create(c->sheet, required_size, result); - if (error != CSS_OK) { - *ctx = orig_ctx; - return error; - } - - /* Copy OPV to bytecode */ - ptr = (*result)->bytecode; - memcpy(ptr, &opv, sizeof(opv)); - ptr += sizeof(opv); - - /* Pass 2: construct bytecode */ - token = parserutils_vector_peek(vector, *ctx); - if (token == NULL) { - *ctx = orig_ctx; - return CSS_INVALID; - } - - if (token->type == CSS_TOKEN_IDENT && - ((lwc_string_caseless_isequal( - token->idata, c->strings[INHERIT], - &match) == lwc_error_ok && match) || - (lwc_string_caseless_isequal( - token->idata, c->strings[NORMAL], - &match) == lwc_error_ok && match) || - (lwc_string_caseless_isequal( - token->idata, c->strings[NONE], - &match) == lwc_error_ok && match))) { - parserutils_vector_iterate(vector, ctx); - } else { - error = parse_content_list(c, vector, ctx, NULL, ptr, NULL); - if (error != CSS_OK) { - *ctx = orig_ctx; - return error; - } - } - - return CSS_OK; -} - -/** - * Parse counter-increment - * - * \param c Parsing context - * \param vector Vector of tokens to process - * \param ctx Pointer to vector iteration context - * \param result Pointer to location to receive resulting style - * \return CSS_OK on success, - * CSS_NOMEM on memory exhaustion, - * CSS_INVALID if the input is not valid - * - * Post condition: \a *ctx is updated with the next token to process - * If the input is invalid, then \a *ctx remains unchanged. - */ -css_error parse_counter_increment(css_language *c, - const parserutils_vector *vector, int *ctx, - css_style **result) -{ - return parse_counter_common(c, vector, ctx, - CSS_PROP_COUNTER_INCREMENT, result); -} - -/** - * Parse counter-reset - * - * \param c Parsing context - * \param vector Vector of tokens to process - * \param ctx Pointer to vector iteration context - * \param result Pointer to location to receive resulting style - * \return CSS_OK on success, - * CSS_NOMEM on memory exhaustion, - * CSS_INVALID if the input is not valid - * - * Post condition: \a *ctx is updated with the next token to process - * If the input is invalid, then \a *ctx remains unchanged. - */ -css_error parse_counter_reset(css_language *c, - const parserutils_vector *vector, int *ctx, - css_style **result) -{ - return parse_counter_common(c, vector, ctx, - CSS_PROP_COUNTER_RESET, result); -} - -/** - * Parse list-style - * - * \param c Parsing context - * \param vector Vector of tokens to process - * \param ctx Pointer to vector iteration context - * \param result Pointer to location to receive resulting style - * \return CSS_OK on success, - * CSS_NOMEM on memory exhaustion, - * CSS_INVALID if the input is not valid - * - * Post condition: \a *ctx is updated with the next token to process - * If the input is invalid, then \a *ctx remains unchanged. - */ -css_error parse_list_style(css_language *c, - const parserutils_vector *vector, int *ctx, - css_style **result) -{ - int orig_ctx = *ctx; - int prev_ctx; - const css_token *token; - css_style *image = NULL; - css_style *position = NULL; - css_style *type = NULL; - css_style *ret = NULL; - uint32_t required_size; - bool match; - css_error error; - - /* Firstly, handle inherit */ - token = parserutils_vector_peek(vector, *ctx); - if (token != NULL && token->type == CSS_TOKEN_IDENT && - (lwc_string_caseless_isequal( - token->idata, c->strings[INHERIT], - &match) == lwc_error_ok && match)) { - uint32_t *bytecode; - - error = css_stylesheet_style_create(c->sheet, - 3 * sizeof(uint32_t), &ret); - if (error != CSS_OK) { - *ctx = orig_ctx; - return error; - } - - bytecode = (uint32_t *) ret->bytecode; - - *(bytecode++) = buildOPV(CSS_PROP_LIST_STYLE_IMAGE, - FLAG_INHERIT, 0); - *(bytecode++) = buildOPV(CSS_PROP_LIST_STYLE_POSITION, - FLAG_INHERIT, 0); - *(bytecode++) = buildOPV(CSS_PROP_LIST_STYLE_TYPE, - FLAG_INHERIT, 0); - - parserutils_vector_iterate(vector, ctx); - - *result = ret; - - return CSS_OK; - } else if (token == NULL) { - /* No tokens -- clearly garbage */ - *ctx = orig_ctx; - return CSS_INVALID; - } - - /* Attempt to parse the various longhand properties */ - do { - prev_ctx = *ctx; - error = CSS_OK; - - /* Ensure that we're not about to parse another inherit */ - token = parserutils_vector_peek(vector, *ctx); - if (token != NULL && token->type == CSS_TOKEN_IDENT && - (lwc_string_caseless_isequal( - token->idata, c->strings[INHERIT], - &match) == lwc_error_ok && match)) { - error = CSS_INVALID; - goto cleanup; - } - - if (type == NULL && (error = parse_list_style_type(c, vector, - ctx, &type)) == CSS_OK) { - } else if (position == NULL && - (error = parse_list_style_position(c, vector, - ctx, &position)) == CSS_OK) { - } else if (image == NULL && - (error = parse_list_style_image(c, vector, ctx, - &image)) == CSS_OK) { - } - - if (error == CSS_OK) { - consumeWhitespace(vector, ctx); - - token = parserutils_vector_peek(vector, *ctx); - } else { - /* Forcibly cause loop to exit */ - token = NULL; - } - } while (*ctx != prev_ctx && token != NULL); - - /* Calculate the required size of the resultant style, - * defaulting the unspecified properties to their initial values */ - required_size = 0; - - if (image) - required_size += image->length; - else - required_size += sizeof(uint32_t); - - if (position) - required_size += position->length; - else - required_size += sizeof(uint32_t); - - if (type) - required_size += type->length; - else - required_size += sizeof(uint32_t); - - /* Create and populate it */ - error = css_stylesheet_style_create(c->sheet, required_size, &ret); - if (error != CSS_OK) - goto cleanup; - - required_size = 0; - - if (image) { - memcpy(((uint8_t *) ret->bytecode) + required_size, - image->bytecode, image->length); - required_size += image->length; - } else { - void *bc = ((uint8_t *) ret->bytecode) + required_size; - - *((uint32_t *) bc) = buildOPV(CSS_PROP_LIST_STYLE_IMAGE, - 0, LIST_STYLE_IMAGE_NONE); - required_size += sizeof(uint32_t); - } - - if (position) { - memcpy(((uint8_t *) ret->bytecode) + required_size, - position->bytecode, position->length); - required_size += position->length; - } else { - void *bc = ((uint8_t *) ret->bytecode) + required_size; - - *((uint32_t *) bc) = buildOPV(CSS_PROP_LIST_STYLE_POSITION, - 0, LIST_STYLE_POSITION_OUTSIDE); - required_size += sizeof(uint32_t); - } - - if (type) { - memcpy(((uint8_t *) ret->bytecode) + required_size, - type->bytecode, type->length); - required_size += type->length; - } else { - void *bc = ((uint8_t *) ret->bytecode) + required_size; - - *((uint32_t *) bc) = buildOPV(CSS_PROP_LIST_STYLE_TYPE, - 0, LIST_STYLE_TYPE_DISC); - required_size += sizeof(uint32_t); - } - - assert(required_size == ret->length); - - /* Write the result */ - *result = ret; - /* Invalidate ret, so that cleanup doesn't destroy it */ - ret = NULL; - - /* Clean up after ourselves */ -cleanup: - if (image) - css_stylesheet_style_destroy(c->sheet, image, error == CSS_OK); - if (position) - css_stylesheet_style_destroy(c->sheet, position, error == CSS_OK); - if (type) - css_stylesheet_style_destroy(c->sheet, type, error == CSS_OK); - if (ret) - css_stylesheet_style_destroy(c->sheet, ret, error == CSS_OK); - - if (error != CSS_OK) - *ctx = orig_ctx; - - return error; -} - -/** - * Parse list-style-image - * - * \param c Parsing context - * \param vector Vector of tokens to process - * \param ctx Pointer to vector iteration context - * \param result Pointer to location to receive resulting style - * \return CSS_OK on success, - * CSS_NOMEM on memory exhaustion, - * CSS_INVALID if the input is not valid - * - * Post condition: \a *ctx is updated with the next token to process - * If the input is invalid, then \a *ctx remains unchanged. - */ -css_error parse_list_style_image(css_language *c, - const parserutils_vector *vector, int *ctx, - css_style **result) -{ - int orig_ctx = *ctx; - css_error error; - const css_token *token; - uint8_t flags = 0; - uint16_t value = 0; - uint32_t opv; - uint32_t required_size; - bool match; - lwc_string *uri = NULL; - - /* URI | IDENT (none, inherit) */ - token = parserutils_vector_iterate(vector, ctx); - if (token == NULL || (token->type != CSS_TOKEN_IDENT && - token->type != CSS_TOKEN_URI)) { - *ctx = orig_ctx; - return CSS_INVALID; - } - - if (token->type == CSS_TOKEN_IDENT && - (lwc_string_caseless_isequal( - token->idata, c->strings[INHERIT], - &match) == lwc_error_ok && match)) { - flags |= FLAG_INHERIT; - } else if (token->type == CSS_TOKEN_IDENT && - (lwc_string_caseless_isequal( - token->idata, c->strings[NONE], - &match) == lwc_error_ok && match)) { - value = LIST_STYLE_IMAGE_NONE; - } else if (token->type == CSS_TOKEN_URI) { - value = LIST_STYLE_IMAGE_URI; - - error = c->sheet->resolve(c->sheet->resolve_pw, - c->sheet->url, - token->idata, &uri); - if (error != CSS_OK) { - *ctx = orig_ctx; - return error; - } - } else { - *ctx = orig_ctx; - return CSS_INVALID; - } - - opv = buildOPV(CSS_PROP_LIST_STYLE_IMAGE, flags, value); - - required_size = sizeof(opv); - if ((flags & FLAG_INHERIT) == false && value == LIST_STYLE_IMAGE_URI) - required_size += sizeof(lwc_string *); - - /* Allocate result */ - error = css_stylesheet_style_create(c->sheet, required_size, result); - if (error != CSS_OK) { - *ctx = orig_ctx; - return error; - } - - /* Copy the bytecode to it */ - memcpy((*result)->bytecode, &opv, sizeof(opv)); - if ((flags & FLAG_INHERIT) == false && value == LIST_STYLE_IMAGE_URI) { - /* Don't ref URI -- we want to pass ownership to the bytecode */ - memcpy((uint8_t *) (*result)->bytecode + sizeof(opv), - &uri, sizeof(lwc_string *)); - } - - return CSS_OK; -} - -/** - * Parse list-style-position - * - * \param c Parsing context - * \param vector Vector of tokens to process - * \param ctx Pointer to vector iteration context - * \param result Pointer to location to receive resulting style - * \return CSS_OK on success, - * CSS_NOMEM on memory exhaustion, - * CSS_INVALID if the input is not valid - * - * Post condition: \a *ctx is updated with the next token to process - * If the input is invalid, then \a *ctx remains unchanged. - */ -css_error parse_list_style_position(css_language *c, - const parserutils_vector *vector, int *ctx, - css_style **result) -{ - int orig_ctx = *ctx; - css_error error; - const css_token *ident; - uint8_t flags = 0; - uint16_t value = 0; - uint32_t opv; - bool match; - - /* IDENT (inside, outside, inherit) */ - ident = parserutils_vector_iterate(vector, ctx); - if (ident == NULL || ident->type != CSS_TOKEN_IDENT) { - *ctx = orig_ctx; - return CSS_INVALID; - } - - if ((lwc_string_caseless_isequal( - ident->idata, c->strings[INHERIT], - &match) == lwc_error_ok && match)) { - flags |= FLAG_INHERIT; - } else if ((lwc_string_caseless_isequal( - ident->idata, c->strings[INSIDE], - &match) == lwc_error_ok && match)) { - value = LIST_STYLE_POSITION_INSIDE; - } else if ((lwc_string_caseless_isequal( - ident->idata, c->strings[OUTSIDE], - &match) == lwc_error_ok && match)) { - value = LIST_STYLE_POSITION_OUTSIDE; - } else { - *ctx = orig_ctx; - return CSS_INVALID; - } - - opv = buildOPV(CSS_PROP_LIST_STYLE_POSITION, flags, value); - - /* Allocate result */ - error = css_stylesheet_style_create(c->sheet, sizeof(opv), result); - if (error != CSS_OK) { - *ctx = orig_ctx; - return error; - } - - /* Copy the bytecode to it */ - memcpy((*result)->bytecode, &opv, sizeof(opv)); - - return CSS_OK; -} - -/** - * Parse list-style-type - * - * \param c Parsing context - * \param vector Vector of tokens to process - * \param ctx Pointer to vector iteration context - * \param result Pointer to location to receive resulting style - * \return CSS_OK on success, - * CSS_NOMEM on memory exhaustion, - * CSS_INVALID if the input is not valid - * - * Post condition: \a *ctx is updated with the next token to process - * If the input is invalid, then \a *ctx remains unchanged. - */ -css_error parse_list_style_type(css_language *c, - const parserutils_vector *vector, int *ctx, - css_style **result) -{ - int orig_ctx = *ctx; - css_error error; - const css_token *ident; - uint8_t flags = 0; - uint16_t value = 0; - uint32_t opv; - bool match; - - /* IDENT (disc, circle, square, decimal, decimal-leading-zero, - * lower-roman, upper-roman, lower-greek, lower-latin, - * upper-latin, armenian, georgian, lower-alpha, upper-alpha, - * none, inherit) - */ - ident = parserutils_vector_iterate(vector, ctx); - if (ident == NULL || ident->type != CSS_TOKEN_IDENT) { - *ctx = orig_ctx; - return CSS_INVALID; - } - - if ((lwc_string_caseless_isequal( - ident->idata, c->strings[INHERIT], - &match) == lwc_error_ok && match)) { - flags |= FLAG_INHERIT; - } else { - error = parse_list_style_type_value(c, ident, &value); - if (error != CSS_OK) { - *ctx = orig_ctx; - return error; - } - } - - opv = buildOPV(CSS_PROP_LIST_STYLE_TYPE, flags, value); - - /* Allocate result */ - error = css_stylesheet_style_create(c->sheet, sizeof(opv), result); - if (error != CSS_OK) { - *ctx = orig_ctx; - return error; - } - - /* Copy the bytecode to it */ - memcpy((*result)->bytecode, &opv, sizeof(opv)); - - return CSS_OK; -} - -/** - * Parse quotes - * - * \param c Parsing context - * \param vector Vector of tokens to process - * \param ctx Pointer to vector iteration context - * \param result Pointer to location to receive resulting style - * \return CSS_OK on success, - * CSS_NOMEM on memory exhaustion, - * CSS_INVALID if the input is not valid - * - * Post condition: \a *ctx is updated with the next token to process - * If the input is invalid, then \a *ctx remains unchanged. - */ -css_error parse_quotes(css_language *c, - const parserutils_vector *vector, int *ctx, - css_style **result) -{ - int orig_ctx = *ctx; - css_error error; - const css_token *token; - uint8_t flags = 0; - uint16_t value = 0; - uint32_t opv; - uint32_t required_size = sizeof(opv); - int temp_ctx = *ctx; - uint8_t *ptr; - bool match; - - /* [ STRING STRING ]+ | IDENT(none,inherit) */ - - /* Pass 1: validate input and calculate bytecode size */ - token = parserutils_vector_iterate(vector, &temp_ctx); - if (token == NULL || (token->type != CSS_TOKEN_IDENT && - token->type != CSS_TOKEN_STRING)) { - *ctx = orig_ctx; - return CSS_INVALID; - } - - if (token->type == CSS_TOKEN_IDENT) { - if ((lwc_string_caseless_isequal( - token->idata, c->strings[INHERIT], - &match) == lwc_error_ok && match)) { - flags = FLAG_INHERIT; - } else if ((lwc_string_caseless_isequal( - token->idata, c->strings[NONE], - &match) == lwc_error_ok && match)) { - value = QUOTES_NONE; - } else { - *ctx = orig_ctx; - return CSS_INVALID; - } - } else { - bool first = true; - - /* [ STRING STRING ] + */ - while (token != NULL && token->type == CSS_TOKEN_STRING) { - lwc_string *open = token->idata; - lwc_string *close; - - consumeWhitespace(vector, &temp_ctx); - - token = parserutils_vector_peek(vector, temp_ctx); - if (token == NULL || token->type != CSS_TOKEN_STRING) { - *ctx = orig_ctx; - return CSS_INVALID; - } - - close = token->idata; - - parserutils_vector_iterate(vector, &temp_ctx); - - consumeWhitespace(vector, &temp_ctx); - - if (first == false) { - required_size += sizeof(opv); - } else { - value = QUOTES_STRING; - } - required_size += sizeof(open) + sizeof(close); - - first = false; - - token = parserutils_vector_peek(vector, temp_ctx); - if (token == NULL || token->type != CSS_TOKEN_STRING) - break; - token = parserutils_vector_iterate(vector, &temp_ctx); - } - - /* Terminator */ - required_size += sizeof(opv); - } - - opv = buildOPV(CSS_PROP_QUOTES, flags, value); - - /* Allocate result */ - error = css_stylesheet_style_create(c->sheet, required_size, result); - if (error != CSS_OK) { - *ctx = orig_ctx; - return error; - } - - /* Copy OPV to bytecode */ - ptr = (*result)->bytecode; - memcpy(ptr, &opv, sizeof(opv)); - ptr += sizeof(opv); - - /* Pass 2: construct bytecode */ - token = parserutils_vector_iterate(vector, ctx); - if (token == NULL || (token->type != CSS_TOKEN_IDENT && - token->type != CSS_TOKEN_STRING)) { - *ctx = orig_ctx; - return CSS_INVALID; - } - - if (token->type == CSS_TOKEN_IDENT) { - /* Nothing to do */ - } else { - bool first = true; - - /* [ STRING STRING ]+ */ - while (token != NULL && token->type == CSS_TOKEN_STRING) { - lwc_string *open = token->idata; - lwc_string *close; - - consumeWhitespace(vector, ctx); - - token = parserutils_vector_peek(vector, *ctx); - if (token == NULL || token->type != CSS_TOKEN_STRING) { - *ctx = orig_ctx; - return CSS_INVALID; - } - - close = token->idata; - - parserutils_vector_iterate(vector, ctx); - - consumeWhitespace(vector, ctx); - - if (first == false) { - opv = QUOTES_STRING; - memcpy(ptr, &opv, sizeof(opv)); - ptr += sizeof(opv); - } - - lwc_string_ref(open); - memcpy(ptr, &open, sizeof(open)); - ptr += sizeof(open); - - lwc_string_ref(close); - memcpy(ptr, &close, sizeof(close)); - ptr += sizeof(close); - - first = false; - - token = parserutils_vector_peek(vector, *ctx); - if (token == NULL || token->type != CSS_TOKEN_STRING) - break; - token = parserutils_vector_iterate(vector, ctx); - } - - /* Terminator */ - opv = QUOTES_NONE; - memcpy(ptr, &opv, sizeof(opv)); - ptr += sizeof(opv); - } - - return CSS_OK; -} - -/** - * Parse list-style-type value - * - * \param c Parsing context - * \param ident Identifier to consider - * \param value Pointer to location to receive value - * \return CSS_OK on success, - * CSS_INVALID if the input is not valid - */ -css_error parse_list_style_type_value(css_language *c, const css_token *ident, - uint16_t *value) -{ - bool match; - - /* IDENT (disc, circle, square, decimal, decimal-leading-zero, - * lower-roman, upper-roman, lower-greek, lower-latin, - * upper-latin, armenian, georgian, lower-alpha, upper-alpha, - * none) - */ - if ((lwc_string_caseless_isequal( - ident->idata, c->strings[DISC], - &match) == lwc_error_ok && match)) { - *value = LIST_STYLE_TYPE_DISC; - } else if ((lwc_string_caseless_isequal( - ident->idata, c->strings[CIRCLE], - &match) == lwc_error_ok && match)) { - *value = LIST_STYLE_TYPE_CIRCLE; - } else if ((lwc_string_caseless_isequal( - ident->idata, c->strings[SQUARE], - &match) == lwc_error_ok && match)) { - *value = LIST_STYLE_TYPE_SQUARE; - } else if ((lwc_string_caseless_isequal( - ident->idata, c->strings[DECIMAL], - &match) == lwc_error_ok && match)) { - *value = LIST_STYLE_TYPE_DECIMAL; - } else if ((lwc_string_caseless_isequal( - ident->idata, c->strings[DECIMAL_LEADING_ZERO], - &match) == lwc_error_ok && match)) { - *value = LIST_STYLE_TYPE_DECIMAL_LEADING_ZERO; - } else if ((lwc_string_caseless_isequal( - ident->idata, c->strings[LOWER_ROMAN], - &match) == lwc_error_ok && match)) { - *value = LIST_STYLE_TYPE_LOWER_ROMAN; - } else if ((lwc_string_caseless_isequal( - ident->idata, c->strings[UPPER_ROMAN], - &match) == lwc_error_ok && match)) { - *value = LIST_STYLE_TYPE_UPPER_ROMAN; - } else if ((lwc_string_caseless_isequal( - ident->idata, c->strings[LOWER_GREEK], - &match) == lwc_error_ok && match)) { - *value = LIST_STYLE_TYPE_LOWER_GREEK; - } else if ((lwc_string_caseless_isequal( - ident->idata, c->strings[LOWER_LATIN], - &match) == lwc_error_ok && match)) { - *value = LIST_STYLE_TYPE_LOWER_LATIN; - } else if ((lwc_string_caseless_isequal( - ident->idata, c->strings[UPPER_LATIN], - &match) == lwc_error_ok && match)) { - *value = LIST_STYLE_TYPE_UPPER_LATIN; - } else if ((lwc_string_caseless_isequal( - ident->idata, c->strings[ARMENIAN], - &match) == lwc_error_ok && match)) { - *value = LIST_STYLE_TYPE_ARMENIAN; - } else if ((lwc_string_caseless_isequal( - ident->idata, c->strings[GEORGIAN], - &match) == lwc_error_ok && match)) { - *value = LIST_STYLE_TYPE_GEORGIAN; - } else if ((lwc_string_caseless_isequal( - ident->idata, c->strings[LOWER_ALPHA], - &match) == lwc_error_ok && match)) { - *value = LIST_STYLE_TYPE_LOWER_ALPHA; - } else if ((lwc_string_caseless_isequal( - ident->idata, c->strings[UPPER_ALPHA], - &match) == lwc_error_ok && match)) { - *value = LIST_STYLE_TYPE_UPPER_ALPHA; - } else if ((lwc_string_caseless_isequal( - ident->idata, c->strings[NONE], - &match) == lwc_error_ok && match)) { - *value = LIST_STYLE_TYPE_NONE; - } else - return CSS_INVALID; - - return CSS_OK; -} - -/** - * Parse content list - * - * \param c Parsing context - * \param vector Vector of tokens to process - * \param ctx Pointer to vector iteration context - * \param value Pointer to location to receive value - * \param buffer Pointer to output buffer, or NULL to read required length - * \param buflen Pointer to location to receive buffer length - * \return CSS_OK on success, - * CSS_NOMEM on memory exhaustion, - * CSS_INVALID if the input is not valid - * - * Post condition: \a *ctx is updated with the next token to process - * If the input is invalid, then \a *ctx remains unchanged. - */ -css_error parse_content_list(css_language *c, - const parserutils_vector *vector, int *ctx, - uint16_t *value, uint8_t *buffer, uint32_t *buflen) -{ - int orig_ctx = *ctx; - int prev_ctx = *ctx; - css_error error; - const css_token *token; - bool first = true; - uint32_t offset = 0; - uint32_t opv; - bool match; - - /* [ - * IDENT(open-quote, close-quote, no-open-quote, no-close-quote) | - * STRING | URI | - * FUNCTION(attr) IDENT ')' | - * FUNCTION(counter) IDENT (',' IDENT)? ')' | - * FUNCTION(counters) IDENT ',' STRING (',' IDENT)? ')' - * ]+ - */ - token = parserutils_vector_iterate(vector, ctx); - if (token == NULL) { - *ctx = orig_ctx; - return CSS_INVALID; - } - - while (token != NULL) { - if (token->type == CSS_TOKEN_IDENT && - (lwc_string_caseless_isequal( - token->idata, c->strings[OPEN_QUOTE], - &match) == lwc_error_ok && match)) { - opv = CONTENT_OPEN_QUOTE; - - if (first == false) { - if (buffer != NULL) { - memcpy(buffer + offset, - &opv, sizeof(opv)); - } - - offset += sizeof(opv); - } - } else if (token->type == CSS_TOKEN_IDENT && - (lwc_string_caseless_isequal( - token->idata, c->strings[CLOSE_QUOTE], - &match) == lwc_error_ok && match)) { - opv = CONTENT_CLOSE_QUOTE; - - if (first == false) { - if (buffer != NULL) { - memcpy(buffer + offset, - &opv, sizeof(opv)); - } - - offset += sizeof(opv); - } - } else if (token->type == CSS_TOKEN_IDENT && - (lwc_string_caseless_isequal( - token->idata, c->strings[NO_OPEN_QUOTE], - &match) == lwc_error_ok && match)) { - opv = CONTENT_NO_OPEN_QUOTE; - - if (first == false) { - if (buffer != NULL) { - memcpy(buffer + offset, - &opv, sizeof(opv)); - } - - offset += sizeof(opv); - } - } else if (token->type == CSS_TOKEN_IDENT && - (lwc_string_caseless_isequal( - token->idata, c->strings[NO_CLOSE_QUOTE], - &match) == lwc_error_ok && match)) { - opv = CONTENT_NO_CLOSE_QUOTE; - - if (first == false) { - if (buffer != NULL) { - memcpy(buffer + offset, - &opv, sizeof(opv)); - } - - offset += sizeof(opv); - } - } else if (token->type == CSS_TOKEN_STRING) { - opv = CONTENT_STRING; - - if (first == false) { - if (buffer != NULL) { - memcpy(buffer + offset, - &opv, sizeof(opv)); - } - - offset += sizeof(opv); - } - - if (buffer != NULL) { - lwc_string_ref(token->idata); - memcpy(buffer + offset, &token->idata, - sizeof(token->idata)); - } - - offset += sizeof(token->idata); - } else if (token->type == CSS_TOKEN_URI) { - lwc_string *uri; - - opv = CONTENT_URI; - - if (first == false) { - if (buffer != NULL) { - memcpy(buffer + offset, - &opv, sizeof(opv)); - } - - offset += sizeof(opv); - } - - if (buffer != NULL) { - error = c->sheet->resolve(c->sheet->resolve_pw, - c->sheet->url, - token->idata, &uri); - if (error != CSS_OK) { - *ctx = orig_ctx; - return error; - } - - /* Don't ref URI -- we want to pass ownership - * to the bytecode */ - memcpy(buffer + offset, &uri, sizeof(uri)); - } - - offset += sizeof(uri); - } else if (token->type == CSS_TOKEN_FUNCTION && - (lwc_string_caseless_isequal( - token->idata, c->strings[ATTR], - &match) == lwc_error_ok && match)) { - opv = CONTENT_ATTR; - - if (first == false) { - if (buffer != NULL) { - memcpy(buffer + offset, - &opv, sizeof(opv)); - } - - offset += sizeof(opv); - } - - consumeWhitespace(vector, ctx); - - /* Expect IDENT */ - token = parserutils_vector_iterate(vector, ctx); - if (token == NULL || token->type != CSS_TOKEN_IDENT) { - *ctx = orig_ctx; - return CSS_INVALID; - } - - if (buffer != NULL) { - lwc_string_ref(token->idata); - memcpy(buffer + offset, &token->idata, - sizeof(token->idata)); - } - - offset += sizeof(token->idata); - - consumeWhitespace(vector, ctx); - - /* Expect ')' */ - token = parserutils_vector_iterate(vector, ctx); - if (token == NULL || tokenIsChar(token, ')') == false) { - *ctx = orig_ctx; - return CSS_INVALID; - } - } else if (token->type == CSS_TOKEN_FUNCTION && - (lwc_string_caseless_isequal( - token->idata, c->strings[COUNTER], - &match) == lwc_error_ok && match)) { - lwc_string *name; - - opv = CONTENT_COUNTER; - - consumeWhitespace(vector, ctx); - - /* Expect IDENT */ - token = parserutils_vector_iterate(vector, ctx); - if (token == NULL || token->type != CSS_TOKEN_IDENT) { - *ctx = orig_ctx; - return CSS_INVALID; - } - - name = token->idata; - - consumeWhitespace(vector, ctx); - - /* Possible ',' */ - token = parserutils_vector_peek(vector, *ctx); - if (token == NULL || - (tokenIsChar(token, ',') == false && - tokenIsChar(token, ')') == false)) { - *ctx = orig_ctx; - return CSS_INVALID; - } - - if (tokenIsChar(token, ',')) { - uint16_t v; - - parserutils_vector_iterate(vector, ctx); - - consumeWhitespace(vector, ctx); - - /* Expect IDENT */ - token = parserutils_vector_peek(vector, *ctx); - if (token == NULL || token->type != - CSS_TOKEN_IDENT) { - *ctx = orig_ctx; - return CSS_INVALID; - } - - error = parse_list_style_type_value(c, - token, &v); - if (error != CSS_OK) { - *ctx = orig_ctx; - return error; - } - - opv |= v << CONTENT_COUNTER_STYLE_SHIFT; - - parserutils_vector_iterate(vector, ctx); - - consumeWhitespace(vector, ctx); - } else { - opv |= LIST_STYLE_TYPE_DECIMAL << - CONTENT_COUNTER_STYLE_SHIFT; - } - - /* Expect ')' */ - token = parserutils_vector_iterate(vector, ctx); - if (token == NULL || tokenIsChar(token, ')') == false) { - *ctx = orig_ctx; - return CSS_INVALID; - } - - if (first == false) { - if (buffer != NULL) { - memcpy(buffer + offset, - &opv, sizeof(opv)); - } - - offset += sizeof(opv); - } - - if (buffer != NULL) { - lwc_string_ref(name); - memcpy(buffer + offset, &name, sizeof(name)); - } - - offset += sizeof(name); - } else if (token->type == CSS_TOKEN_FUNCTION && - (lwc_string_caseless_isequal( - token->idata, c->strings[COUNTERS], - &match) == lwc_error_ok && match)) { - lwc_string *name; - lwc_string *sep; - - opv = CONTENT_COUNTERS; - - consumeWhitespace(vector, ctx); - - /* Expect IDENT */ - token = parserutils_vector_iterate(vector, ctx); - if (token == NULL || token->type != CSS_TOKEN_IDENT) { - *ctx = orig_ctx; - return CSS_INVALID; - } - - name = token->idata; - - consumeWhitespace(vector, ctx); - - /* Expect ',' */ - token = parserutils_vector_iterate(vector, ctx); - if (token == NULL || tokenIsChar(token, ',') == false) { - *ctx = orig_ctx; - return CSS_INVALID; - } - - consumeWhitespace(vector, ctx); - - /* Expect STRING */ - token = parserutils_vector_iterate(vector, ctx); - if (token == NULL || token->type != CSS_TOKEN_STRING) { - *ctx = orig_ctx; - return CSS_INVALID; - } - - sep = token->idata; - - consumeWhitespace(vector, ctx); - - /* Possible ',' */ - token = parserutils_vector_peek(vector, *ctx); - if (token == NULL || - (tokenIsChar(token, ',') == false && - tokenIsChar(token, ')') == false)) { - *ctx = orig_ctx; - return CSS_INVALID; - } - - if (tokenIsChar(token, ',')) { - uint16_t v; - - parserutils_vector_iterate(vector, ctx); - - consumeWhitespace(vector, ctx); - - /* Expect IDENT */ - token = parserutils_vector_peek(vector, *ctx); - if (token == NULL || token->type != - CSS_TOKEN_IDENT) { - *ctx = orig_ctx; - return CSS_INVALID; - } - - error = parse_list_style_type_value(c, - token, &v); - if (error != CSS_OK) { - *ctx = orig_ctx; - return error; - } - - opv |= v << CONTENT_COUNTERS_STYLE_SHIFT; - - parserutils_vector_iterate(vector, ctx); - - consumeWhitespace(vector, ctx); - } else { - opv |= LIST_STYLE_TYPE_DECIMAL << - CONTENT_COUNTERS_STYLE_SHIFT; - } - - /* Expect ')' */ - token = parserutils_vector_iterate(vector, ctx); - if (token == NULL || tokenIsChar(token, ')') == false) { - *ctx = orig_ctx; - return CSS_INVALID; - } - - if (first == false) { - if (buffer != NULL) { - memcpy(buffer + offset, - &opv, sizeof(opv)); - } - - offset += sizeof(opv); - } - - if (buffer != NULL) { - lwc_string_ref(name); - memcpy(buffer + offset, &name, sizeof(name)); - } - - offset += sizeof(name); - - if (buffer != NULL) { - lwc_string_ref(sep); - memcpy(buffer + offset, &sep, sizeof(sep)); - } - - offset += sizeof(sep); - } else if (first) { - /* Invalid if this is the first iteration */ - *ctx = orig_ctx; - return CSS_INVALID; - } else { - /* Give up, ensuring current token is reprocessed */ - *ctx = prev_ctx; - break; - } - - if (first && value != NULL) { - *value = opv; - } - first = false; - - consumeWhitespace(vector, ctx); - - prev_ctx = *ctx; - token = parserutils_vector_iterate(vector, ctx); - } - - /* Write list terminator */ - opv = CONTENT_NORMAL; - - if (buffer != NULL) { - memcpy(buffer + offset, &opv, sizeof(opv)); - } - - offset += sizeof(opv); - - if (buflen != NULL) { - *buflen = offset; - } - - return CSS_OK; -} - -/** - * Common parser for counter-increment and counter-reset - * - * \param c Parsing context - * \param vector Vector of tokens to process - * \param ctx Pointer to vector iteration context - * \param op Opcode to parse for - * \param result Pointer to location to receive resulting style - * \return CSS_OK on success, - * CSS_NOMEM on memory exhaustion, - * CSS_INVALID if the input is not valid - * - * Post condition: \a *ctx is updated with the next token to process - * If the input is invalid, then \a *ctx remains unchanged. - */ -css_error parse_counter_common(css_language *c, - const parserutils_vector *vector, int *ctx, - uint16_t op, css_style **result) -{ - int orig_ctx = *ctx; - css_error error; - const css_token *token; - uint8_t flags = 0; - uint16_t value = 0; - uint32_t opv; - uint32_t required_size = sizeof(opv); - int temp_ctx = *ctx; - uint8_t *ptr; - bool match; - - /* [IDENT ? ]+ | IDENT(none, inherit) */ - - /* Pass 1: validate input and calculate bytecode size */ - token = parserutils_vector_iterate(vector, &temp_ctx); - if (token == NULL || token->type != CSS_TOKEN_IDENT) { - *ctx = orig_ctx; - return CSS_INVALID; - } - - if ((lwc_string_caseless_isequal( - token->idata, c->strings[INHERIT], - &match) == lwc_error_ok && match)) { - flags = FLAG_INHERIT; - } else if ((lwc_string_caseless_isequal( - token->idata, c->strings[NONE], - &match) == lwc_error_ok && match)) { - value = COUNTER_INCREMENT_NONE; - } else { - bool first = true; - - value = COUNTER_INCREMENT_NAMED; - - while (token != NULL) { - lwc_string *name = token->idata; - css_fixed increment = - (op == CSS_PROP_COUNTER_INCREMENT) - ? INTTOFIX(1) : INTTOFIX(0); - - consumeWhitespace(vector, &temp_ctx); - - /* Optional integer */ - token = parserutils_vector_peek(vector, temp_ctx); - if (token != NULL && token->type != CSS_TOKEN_IDENT && - token->type != CSS_TOKEN_NUMBER) { - *ctx = orig_ctx; - return CSS_INVALID; - } - - if (token != NULL && token->type == CSS_TOKEN_NUMBER) { - size_t consumed = 0; - - increment = number_from_lwc_string( - token->idata, true, &consumed); - - if (consumed != lwc_string_length( - token->idata)) { - *ctx = orig_ctx; - return CSS_INVALID; - } - - parserutils_vector_iterate(vector, &temp_ctx); - - consumeWhitespace(vector, &temp_ctx); - } - - if (first == false) { - required_size += sizeof(opv); - } - required_size += sizeof(name) + sizeof(increment); - - first = false; - - token = parserutils_vector_peek(vector, temp_ctx); - if (token != NULL && token->type != CSS_TOKEN_IDENT) { - break; - } - - token = parserutils_vector_iterate(vector, &temp_ctx); - } - - /* And for the terminator */ - required_size += sizeof(opv); - } - - opv = buildOPV(op, flags, value); - - /* Allocate result */ - error = css_stylesheet_style_create(c->sheet, required_size, result); - if (error != CSS_OK) { - *ctx = orig_ctx; - return error; - } - - /* Copy OPV to bytecode */ - ptr = (*result)->bytecode; - memcpy(ptr, &opv, sizeof(opv)); - ptr += sizeof(opv); - - /* Pass 2: construct bytecode */ - token = parserutils_vector_iterate(vector, ctx); - if (token == NULL || token->type != CSS_TOKEN_IDENT) { - *ctx = orig_ctx; - return CSS_INVALID; - } - - if ((lwc_string_caseless_isequal( - token->idata, c->strings[INHERIT], - &match) == lwc_error_ok && match) || - (lwc_string_caseless_isequal( - token->idata, c->strings[NONE], - &match) == lwc_error_ok && match)) { - /* Nothing to do */ - } else { - bool first = true; - - opv = COUNTER_INCREMENT_NAMED; - - while (token != NULL) { - lwc_string *name = token->idata; - css_fixed increment = - (op == CSS_PROP_COUNTER_INCREMENT) - ? INTTOFIX(1) : INTTOFIX(0); - - consumeWhitespace(vector, ctx); - - /* Optional integer */ - token = parserutils_vector_peek(vector, *ctx); - if (token != NULL && token->type != CSS_TOKEN_IDENT && - token->type != CSS_TOKEN_NUMBER) { - *ctx = orig_ctx; - return CSS_INVALID; - } - - if (token != NULL && token->type == CSS_TOKEN_NUMBER) { - size_t consumed = 0; - - increment = number_from_lwc_string( - token->idata, true, &consumed); - - if (consumed != lwc_string_length( - token->idata)) { - *ctx = orig_ctx; - return CSS_INVALID; - } - - parserutils_vector_iterate(vector, ctx); - - consumeWhitespace(vector, ctx); - } - - if (first == false) { - memcpy(ptr, &opv, sizeof(opv)); - ptr += sizeof(opv); - } - - lwc_string_ref(name); - memcpy(ptr, &name, sizeof(name)); - ptr += sizeof(name); - - memcpy(ptr, &increment, sizeof(increment)); - ptr += sizeof(increment); - - first = false; - - token = parserutils_vector_peek(vector, *ctx); - if (token != NULL && token->type != CSS_TOKEN_IDENT) { - break; - } - - token = parserutils_vector_iterate(vector, ctx); - } - - /* And for the terminator */ - opv = COUNTER_INCREMENT_NONE; - memcpy(ptr, &opv, sizeof(opv)); - ptr += sizeof(opv); - } - - return CSS_OK; -} - diff --git a/src/parse/properties/height.c b/src/parse/properties/height.c new file mode 100644 index 0000000..1611651 --- /dev/null +++ b/src/parse/properties/height.c @@ -0,0 +1,109 @@ +/* + * This file is part of LibCSS. + * Licensed under the MIT License, + * http://www.opensource.org/licenses/mit-license.php + * Copyright 2009 John-Mark Bell + */ + +#include +#include + +#include "bytecode/bytecode.h" +#include "bytecode/opcodes.h" +#include "parse/properties/properties.h" +#include "parse/properties/utils.h" + +/** + * Parse height + * + * \param c Parsing context + * \param vector Vector of tokens to process + * \param ctx Pointer to vector iteration context + * \param result Pointer to location to receive resulting style + * \return CSS_OK on success, + * CSS_NOMEM on memory exhaustion, + * CSS_INVALID if the input is not valid + * + * Post condition: \a *ctx is updated with the next token to process + * If the input is invalid, then \a *ctx remains unchanged. + */ +css_error parse_height(css_language *c, + const parserutils_vector *vector, int *ctx, + css_style **result) +{ + int orig_ctx = *ctx; + css_error error; + const css_token *token; + uint8_t flags = 0; + uint16_t value = 0; + uint32_t opv; + css_fixed length = 0; + uint32_t unit = 0; + uint32_t required_size; + bool match; + + /* length | percentage | IDENT(auto, inherit) */ + token = parserutils_vector_peek(vector, *ctx); + if (token == NULL) { + *ctx = orig_ctx; + return CSS_INVALID; + } + + if (token->type == CSS_TOKEN_IDENT && + (lwc_string_caseless_isequal( + token->idata, c->strings[INHERIT], + &match) == lwc_error_ok && match)) { + parserutils_vector_iterate(vector, ctx); + flags = FLAG_INHERIT; + } else if (token->type == CSS_TOKEN_IDENT && + (lwc_string_caseless_isequal( + token->idata, c->strings[AUTO], + &match) == lwc_error_ok && match)) { + parserutils_vector_iterate(vector, ctx); + value = HEIGHT_AUTO; + } else { + error = parse_unit_specifier(c, vector, ctx, UNIT_PX, + &length, &unit); + if (error != CSS_OK) { + *ctx = orig_ctx; + return error; + } + + if (unit & UNIT_ANGLE || unit & UNIT_TIME || unit & UNIT_FREQ) { + *ctx = orig_ctx; + return CSS_INVALID; + } + + /* Negative height is illegal */ + if (length < 0) { + *ctx = orig_ctx; + return CSS_INVALID; + } + + value = HEIGHT_SET; + } + + opv = buildOPV(CSS_PROP_HEIGHT, flags, value); + + required_size = sizeof(opv); + if ((flags & FLAG_INHERIT) == false && value == HEIGHT_SET) + required_size += sizeof(length) + sizeof(unit); + + /* Allocate result */ + error = css_stylesheet_style_create(c->sheet, required_size, result); + if (error != CSS_OK) { + *ctx = orig_ctx; + return error; + } + + /* Copy the bytecode to it */ + memcpy((*result)->bytecode, &opv, sizeof(opv)); + if ((flags & FLAG_INHERIT) == false && value == HEIGHT_SET) { + memcpy(((uint8_t *) (*result)->bytecode) + sizeof(opv), + &length, sizeof(length)); + memcpy(((uint8_t *) (*result)->bytecode) + sizeof(opv) + + sizeof(length), &unit, sizeof(unit)); + } + + return CSS_OK; +} diff --git a/src/parse/properties/left.c b/src/parse/properties/left.c new file mode 100644 index 0000000..dc04c40 --- /dev/null +++ b/src/parse/properties/left.c @@ -0,0 +1,35 @@ +/* + * This file is part of LibCSS. + * Licensed under the MIT License, + * http://www.opensource.org/licenses/mit-license.php + * Copyright 2009 John-Mark Bell + */ + +#include +#include + +#include "bytecode/bytecode.h" +#include "bytecode/opcodes.h" +#include "parse/properties/properties.h" +#include "parse/properties/utils.h" + +/** + * Parse left + * + * \param c Parsing context + * \param vector Vector of tokens to process + * \param ctx Pointer to vector iteration context + * \param result Pointer to location to receive resulting style + * \return CSS_OK on success, + * CSS_NOMEM on memory exhaustion, + * CSS_INVALID if the input is not valid + * + * Post condition: \a *ctx is updated with the next token to process + * If the input is invalid, then \a *ctx remains unchanged. + */ +css_error parse_left(css_language *c, + const parserutils_vector *vector, int *ctx, + css_style **result) +{ + return parse_side(c, vector, ctx, CSS_PROP_LEFT, result); +} diff --git a/src/parse/properties/letter_spacing.c b/src/parse/properties/letter_spacing.c new file mode 100644 index 0000000..c5566e2 --- /dev/null +++ b/src/parse/properties/letter_spacing.c @@ -0,0 +1,104 @@ +/* + * This file is part of LibCSS. + * Licensed under the MIT License, + * http://www.opensource.org/licenses/mit-license.php + * Copyright 2009 John-Mark Bell + */ + +#include +#include + +#include "bytecode/bytecode.h" +#include "bytecode/opcodes.h" +#include "parse/properties/properties.h" +#include "parse/properties/utils.h" + +/** + * Parse letter-spacing + * + * \param c Parsing context + * \param vector Vector of tokens to process + * \param ctx Pointer to vector iteration context + * \param result Pointer to location to receive resulting style + * \return CSS_OK on success, + * CSS_NOMEM on memory exhaustion, + * CSS_INVALID if the input is not valid + * + * Post condition: \a *ctx is updated with the next token to process + * If the input is invalid, then \a *ctx remains unchanged. + */ +css_error parse_letter_spacing(css_language *c, + const parserutils_vector *vector, int *ctx, + css_style **result) +{ + int orig_ctx = *ctx; + css_error error; + const css_token *token; + uint8_t flags = 0; + uint16_t value = 0; + uint32_t opv; + css_fixed length = 0; + uint32_t unit = 0; + uint32_t required_size; + bool match; + + /* length | IDENT(normal, inherit) */ + token = parserutils_vector_peek(vector, *ctx); + if (token == NULL) { + *ctx = orig_ctx; + return CSS_INVALID; + } + + if (token->type == CSS_TOKEN_IDENT && + (lwc_string_caseless_isequal( + token->idata, c->strings[INHERIT], + &match) == lwc_error_ok && match)) { + parserutils_vector_iterate(vector, ctx); + flags = FLAG_INHERIT; + } else if (token->type == CSS_TOKEN_IDENT && + (lwc_string_caseless_isequal( + token->idata, c->strings[NORMAL], + &match) == lwc_error_ok && match)) { + parserutils_vector_iterate(vector, ctx); + value = LETTER_SPACING_NORMAL; + } else { + error = parse_unit_specifier(c, vector, ctx, UNIT_PX, + &length, &unit); + if (error != CSS_OK) { + *ctx = orig_ctx; + return error; + } + + if (unit & UNIT_ANGLE || unit & UNIT_TIME || unit & UNIT_FREQ || + unit & UNIT_PCT) { + *ctx = orig_ctx; + return CSS_INVALID; + } + + value = LETTER_SPACING_SET; + } + + opv = buildOPV(CSS_PROP_LETTER_SPACING, flags, value); + + required_size = sizeof(opv); + if ((flags & FLAG_INHERIT) == false && value == LETTER_SPACING_SET) + required_size += sizeof(length) + sizeof(unit); + + /* Allocate result */ + error = css_stylesheet_style_create(c->sheet, required_size, result); + if (error != CSS_OK) { + *ctx = orig_ctx; + return error; + } + + /* Copy the bytecode to it */ + memcpy((*result)->bytecode, &opv, sizeof(opv)); + if ((flags & FLAG_INHERIT) == false && value == LETTER_SPACING_SET) { + memcpy(((uint8_t *) (*result)->bytecode) + sizeof(opv), + &length, sizeof(length)); + memcpy(((uint8_t *) (*result)->bytecode) + sizeof(opv) + + sizeof(length), &unit, sizeof(unit)); + } + + return CSS_OK; +} diff --git a/src/parse/properties/line_height.c b/src/parse/properties/line_height.c new file mode 100644 index 0000000..8b1c995 --- /dev/null +++ b/src/parse/properties/line_height.c @@ -0,0 +1,129 @@ +/* + * This file is part of LibCSS. + * Licensed under the MIT License, + * http://www.opensource.org/licenses/mit-license.php + * Copyright 2009 John-Mark Bell + */ + +#include +#include + +#include "bytecode/bytecode.h" +#include "bytecode/opcodes.h" +#include "parse/properties/properties.h" +#include "parse/properties/utils.h" + +/** + * Parse line-height + * + * \param c Parsing context + * \param vector Vector of tokens to process + * \param ctx Pointer to vector iteration context + * \param result Pointer to location to receive resulting style + * \return CSS_OK on success, + * CSS_NOMEM on memory exhaustion, + * CSS_INVALID if the input is not valid + * + * Post condition: \a *ctx is updated with the next token to process + * If the input is invalid, then \a *ctx remains unchanged. + */ +css_error parse_line_height(css_language *c, + const parserutils_vector *vector, int *ctx, + css_style **result) +{ + int orig_ctx = *ctx; + css_error error; + const css_token *token; + uint8_t flags = 0; + uint16_t value = 0; + uint32_t opv; + css_fixed length = 0; + uint32_t unit = 0; + uint32_t required_size; + bool match; + + /* number | length | percentage | IDENT(normal, inherit) */ + token = parserutils_vector_peek(vector, *ctx); + if (token == NULL) { + *ctx = orig_ctx; + return CSS_INVALID; + } + + if (token->type == CSS_TOKEN_IDENT && + (lwc_string_caseless_isequal( + token->idata, c->strings[INHERIT], + &match) == lwc_error_ok && match)) { + parserutils_vector_iterate(vector, ctx); + flags = FLAG_INHERIT; + } else if (token->type == CSS_TOKEN_IDENT && + (lwc_string_caseless_isequal( + token->idata, c->strings[NORMAL], + &match) == lwc_error_ok && match)) { + parserutils_vector_iterate(vector, ctx); + value = LINE_HEIGHT_NORMAL; + } else if (token->type == CSS_TOKEN_NUMBER) { + size_t consumed = 0; + length = number_from_lwc_string(token->idata, false, &consumed); + if (consumed != lwc_string_length(token->idata)) { + *ctx = orig_ctx; + return CSS_INVALID; + } + + /* Negative values are illegal */ + if (length < 0) { + *ctx = orig_ctx; + return CSS_INVALID; + } + + parserutils_vector_iterate(vector, ctx); + value = LINE_HEIGHT_NUMBER; + } else { + error = parse_unit_specifier(c, vector, ctx, UNIT_PX, + &length, &unit); + if (error != CSS_OK) { + *ctx = orig_ctx; + return error; + } + + if (unit & UNIT_ANGLE || unit & UNIT_TIME || unit & UNIT_FREQ) { + *ctx = orig_ctx; + return CSS_INVALID; + } + + /* Negative values are illegal */ + if (length < 0) { + *ctx = orig_ctx; + return CSS_INVALID; + } + + value = LINE_HEIGHT_DIMENSION; + } + + opv = buildOPV(CSS_PROP_LINE_HEIGHT, flags, value); + + required_size = sizeof(opv); + if ((flags & FLAG_INHERIT) == false && value == LINE_HEIGHT_NUMBER) + required_size += sizeof(length); + else if ((flags & FLAG_INHERIT) == false && + value == LINE_HEIGHT_DIMENSION) + required_size += sizeof(length) + sizeof(unit); + + /* Allocate result */ + error = css_stylesheet_style_create(c->sheet, required_size, result); + if (error != CSS_OK) { + *ctx = orig_ctx; + return error; + } + + /* Copy the bytecode to it */ + memcpy((*result)->bytecode, &opv, sizeof(opv)); + if ((flags & FLAG_INHERIT) == false && (value == LINE_HEIGHT_NUMBER || + value == LINE_HEIGHT_DIMENSION)) + memcpy(((uint8_t *) (*result)->bytecode) + sizeof(opv), + &length, sizeof(length)); + if ((flags & FLAG_INHERIT) == false && value == LINE_HEIGHT_DIMENSION) + memcpy(((uint8_t *) (*result)->bytecode) + sizeof(opv) + + sizeof(length), &unit, sizeof(unit)); + + return CSS_OK; +} diff --git a/src/parse/properties/list_style.c b/src/parse/properties/list_style.c new file mode 100644 index 0000000..4c2043e --- /dev/null +++ b/src/parse/properties/list_style.c @@ -0,0 +1,199 @@ +/* + * This file is part of LibCSS. + * Licensed under the MIT License, + * http://www.opensource.org/licenses/mit-license.php + * Copyright 2009 John-Mark Bell + */ + +#include +#include + +#include "bytecode/bytecode.h" +#include "bytecode/opcodes.h" +#include "parse/properties/properties.h" +#include "parse/properties/utils.h" + +/** + * Parse list-style + * + * \param c Parsing context + * \param vector Vector of tokens to process + * \param ctx Pointer to vector iteration context + * \param result Pointer to location to receive resulting style + * \return CSS_OK on success, + * CSS_NOMEM on memory exhaustion, + * CSS_INVALID if the input is not valid + * + * Post condition: \a *ctx is updated with the next token to process + * If the input is invalid, then \a *ctx remains unchanged. + */ +css_error parse_list_style(css_language *c, + const parserutils_vector *vector, int *ctx, + css_style **result) +{ + int orig_ctx = *ctx; + int prev_ctx; + const css_token *token; + css_style *image = NULL; + css_style *position = NULL; + css_style *type = NULL; + css_style *ret = NULL; + uint32_t required_size; + bool match; + css_error error; + + /* Firstly, handle inherit */ + token = parserutils_vector_peek(vector, *ctx); + if (token != NULL && token->type == CSS_TOKEN_IDENT && + (lwc_string_caseless_isequal( + token->idata, c->strings[INHERIT], + &match) == lwc_error_ok && match)) { + uint32_t *bytecode; + + error = css_stylesheet_style_create(c->sheet, + 3 * sizeof(uint32_t), &ret); + if (error != CSS_OK) { + *ctx = orig_ctx; + return error; + } + + bytecode = (uint32_t *) ret->bytecode; + + *(bytecode++) = buildOPV(CSS_PROP_LIST_STYLE_IMAGE, + FLAG_INHERIT, 0); + *(bytecode++) = buildOPV(CSS_PROP_LIST_STYLE_POSITION, + FLAG_INHERIT, 0); + *(bytecode++) = buildOPV(CSS_PROP_LIST_STYLE_TYPE, + FLAG_INHERIT, 0); + + parserutils_vector_iterate(vector, ctx); + + *result = ret; + + return CSS_OK; + } else if (token == NULL) { + /* No tokens -- clearly garbage */ + *ctx = orig_ctx; + return CSS_INVALID; + } + + /* Attempt to parse the various longhand properties */ + do { + prev_ctx = *ctx; + error = CSS_OK; + + /* Ensure that we're not about to parse another inherit */ + token = parserutils_vector_peek(vector, *ctx); + if (token != NULL && token->type == CSS_TOKEN_IDENT && + (lwc_string_caseless_isequal( + token->idata, c->strings[INHERIT], + &match) == lwc_error_ok && match)) { + error = CSS_INVALID; + goto cleanup; + } + + if (type == NULL && (error = parse_list_style_type(c, vector, + ctx, &type)) == CSS_OK) { + } else if (position == NULL && + (error = parse_list_style_position(c, vector, + ctx, &position)) == CSS_OK) { + } else if (image == NULL && + (error = parse_list_style_image(c, vector, ctx, + &image)) == CSS_OK) { + } + + if (error == CSS_OK) { + consumeWhitespace(vector, ctx); + + token = parserutils_vector_peek(vector, *ctx); + } else { + /* Forcibly cause loop to exit */ + token = NULL; + } + } while (*ctx != prev_ctx && token != NULL); + + /* Calculate the required size of the resultant style, + * defaulting the unspecified properties to their initial values */ + required_size = 0; + + if (image) + required_size += image->length; + else + required_size += sizeof(uint32_t); + + if (position) + required_size += position->length; + else + required_size += sizeof(uint32_t); + + if (type) + required_size += type->length; + else + required_size += sizeof(uint32_t); + + /* Create and populate it */ + error = css_stylesheet_style_create(c->sheet, required_size, &ret); + if (error != CSS_OK) + goto cleanup; + + required_size = 0; + + if (image) { + memcpy(((uint8_t *) ret->bytecode) + required_size, + image->bytecode, image->length); + required_size += image->length; + } else { + void *bc = ((uint8_t *) ret->bytecode) + required_size; + + *((uint32_t *) bc) = buildOPV(CSS_PROP_LIST_STYLE_IMAGE, + 0, LIST_STYLE_IMAGE_NONE); + required_size += sizeof(uint32_t); + } + + if (position) { + memcpy(((uint8_t *) ret->bytecode) + required_size, + position->bytecode, position->length); + required_size += position->length; + } else { + void *bc = ((uint8_t *) ret->bytecode) + required_size; + + *((uint32_t *) bc) = buildOPV(CSS_PROP_LIST_STYLE_POSITION, + 0, LIST_STYLE_POSITION_OUTSIDE); + required_size += sizeof(uint32_t); + } + + if (type) { + memcpy(((uint8_t *) ret->bytecode) + required_size, + type->bytecode, type->length); + required_size += type->length; + } else { + void *bc = ((uint8_t *) ret->bytecode) + required_size; + + *((uint32_t *) bc) = buildOPV(CSS_PROP_LIST_STYLE_TYPE, + 0, LIST_STYLE_TYPE_DISC); + required_size += sizeof(uint32_t); + } + + assert(required_size == ret->length); + + /* Write the result */ + *result = ret; + /* Invalidate ret, so that cleanup doesn't destroy it */ + ret = NULL; + + /* Clean up after ourselves */ +cleanup: + if (image) + css_stylesheet_style_destroy(c->sheet, image, error == CSS_OK); + if (position) + css_stylesheet_style_destroy(c->sheet, position, error == CSS_OK); + if (type) + css_stylesheet_style_destroy(c->sheet, type, error == CSS_OK); + if (ret) + css_stylesheet_style_destroy(c->sheet, ret, error == CSS_OK); + + if (error != CSS_OK) + *ctx = orig_ctx; + + return error; +} diff --git a/src/parse/properties/list_style_image.c b/src/parse/properties/list_style_image.c new file mode 100644 index 0000000..a200323 --- /dev/null +++ b/src/parse/properties/list_style_image.c @@ -0,0 +1,99 @@ +/* + * This file is part of LibCSS. + * Licensed under the MIT License, + * http://www.opensource.org/licenses/mit-license.php + * Copyright 2009 John-Mark Bell + */ + +#include +#include + +#include "bytecode/bytecode.h" +#include "bytecode/opcodes.h" +#include "parse/properties/properties.h" +#include "parse/properties/utils.h" + +/** + * Parse list-style-image + * + * \param c Parsing context + * \param vector Vector of tokens to process + * \param ctx Pointer to vector iteration context + * \param result Pointer to location to receive resulting style + * \return CSS_OK on success, + * CSS_NOMEM on memory exhaustion, + * CSS_INVALID if the input is not valid + * + * Post condition: \a *ctx is updated with the next token to process + * If the input is invalid, then \a *ctx remains unchanged. + */ +css_error parse_list_style_image(css_language *c, + const parserutils_vector *vector, int *ctx, + css_style **result) +{ + int orig_ctx = *ctx; + css_error error; + const css_token *token; + uint8_t flags = 0; + uint16_t value = 0; + uint32_t opv; + uint32_t required_size; + bool match; + lwc_string *uri = NULL; + + /* URI | IDENT (none, inherit) */ + token = parserutils_vector_iterate(vector, ctx); + if (token == NULL || (token->type != CSS_TOKEN_IDENT && + token->type != CSS_TOKEN_URI)) { + *ctx = orig_ctx; + return CSS_INVALID; + } + + if (token->type == CSS_TOKEN_IDENT && + (lwc_string_caseless_isequal( + token->idata, c->strings[INHERIT], + &match) == lwc_error_ok && match)) { + flags |= FLAG_INHERIT; + } else if (token->type == CSS_TOKEN_IDENT && + (lwc_string_caseless_isequal( + token->idata, c->strings[NONE], + &match) == lwc_error_ok && match)) { + value = LIST_STYLE_IMAGE_NONE; + } else if (token->type == CSS_TOKEN_URI) { + value = LIST_STYLE_IMAGE_URI; + + error = c->sheet->resolve(c->sheet->resolve_pw, + c->sheet->url, + token->idata, &uri); + if (error != CSS_OK) { + *ctx = orig_ctx; + return error; + } + } else { + *ctx = orig_ctx; + return CSS_INVALID; + } + + opv = buildOPV(CSS_PROP_LIST_STYLE_IMAGE, flags, value); + + required_size = sizeof(opv); + if ((flags & FLAG_INHERIT) == false && value == LIST_STYLE_IMAGE_URI) + required_size += sizeof(lwc_string *); + + /* Allocate result */ + error = css_stylesheet_style_create(c->sheet, required_size, result); + if (error != CSS_OK) { + *ctx = orig_ctx; + return error; + } + + /* Copy the bytecode to it */ + memcpy((*result)->bytecode, &opv, sizeof(opv)); + if ((flags & FLAG_INHERIT) == false && value == LIST_STYLE_IMAGE_URI) { + /* Don't ref URI -- we want to pass ownership to the bytecode */ + memcpy((uint8_t *) (*result)->bytecode + sizeof(opv), + &uri, sizeof(lwc_string *)); + } + + return CSS_OK; +} diff --git a/src/parse/properties/list_style_position.c b/src/parse/properties/list_style_position.c new file mode 100644 index 0000000..7fc680d --- /dev/null +++ b/src/parse/properties/list_style_position.c @@ -0,0 +1,79 @@ +/* + * This file is part of LibCSS. + * Licensed under the MIT License, + * http://www.opensource.org/licenses/mit-license.php + * Copyright 2009 John-Mark Bell + */ + +#include +#include + +#include "bytecode/bytecode.h" +#include "bytecode/opcodes.h" +#include "parse/properties/properties.h" +#include "parse/properties/utils.h" + +/** + * Parse list-style-position + * + * \param c Parsing context + * \param vector Vector of tokens to process + * \param ctx Pointer to vector iteration context + * \param result Pointer to location to receive resulting style + * \return CSS_OK on success, + * CSS_NOMEM on memory exhaustion, + * CSS_INVALID if the input is not valid + * + * Post condition: \a *ctx is updated with the next token to process + * If the input is invalid, then \a *ctx remains unchanged. + */ +css_error parse_list_style_position(css_language *c, + const parserutils_vector *vector, int *ctx, + css_style **result) +{ + int orig_ctx = *ctx; + css_error error; + const css_token *ident; + uint8_t flags = 0; + uint16_t value = 0; + uint32_t opv; + bool match; + + /* IDENT (inside, outside, inherit) */ + ident = parserutils_vector_iterate(vector, ctx); + if (ident == NULL || ident->type != CSS_TOKEN_IDENT) { + *ctx = orig_ctx; + return CSS_INVALID; + } + + if ((lwc_string_caseless_isequal( + ident->idata, c->strings[INHERIT], + &match) == lwc_error_ok && match)) { + flags |= FLAG_INHERIT; + } else if ((lwc_string_caseless_isequal( + ident->idata, c->strings[INSIDE], + &match) == lwc_error_ok && match)) { + value = LIST_STYLE_POSITION_INSIDE; + } else if ((lwc_string_caseless_isequal( + ident->idata, c->strings[OUTSIDE], + &match) == lwc_error_ok && match)) { + value = LIST_STYLE_POSITION_OUTSIDE; + } else { + *ctx = orig_ctx; + return CSS_INVALID; + } + + opv = buildOPV(CSS_PROP_LIST_STYLE_POSITION, flags, value); + + /* Allocate result */ + error = css_stylesheet_style_create(c->sheet, sizeof(opv), result); + if (error != CSS_OK) { + *ctx = orig_ctx; + return error; + } + + /* Copy the bytecode to it */ + memcpy((*result)->bytecode, &opv, sizeof(opv)); + + return CSS_OK; +} diff --git a/src/parse/properties/list_style_type.c b/src/parse/properties/list_style_type.c new file mode 100644 index 0000000..1d1fe42 --- /dev/null +++ b/src/parse/properties/list_style_type.c @@ -0,0 +1,78 @@ +/* + * This file is part of LibCSS. + * Licensed under the MIT License, + * http://www.opensource.org/licenses/mit-license.php + * Copyright 2009 John-Mark Bell + */ + +#include +#include + +#include "bytecode/bytecode.h" +#include "bytecode/opcodes.h" +#include "parse/properties/properties.h" +#include "parse/properties/utils.h" + +/** + * Parse list-style-type + * + * \param c Parsing context + * \param vector Vector of tokens to process + * \param ctx Pointer to vector iteration context + * \param result Pointer to location to receive resulting style + * \return CSS_OK on success, + * CSS_NOMEM on memory exhaustion, + * CSS_INVALID if the input is not valid + * + * Post condition: \a *ctx is updated with the next token to process + * If the input is invalid, then \a *ctx remains unchanged. + */ +css_error parse_list_style_type(css_language *c, + const parserutils_vector *vector, int *ctx, + css_style **result) +{ + int orig_ctx = *ctx; + css_error error; + const css_token *ident; + uint8_t flags = 0; + uint16_t value = 0; + uint32_t opv; + bool match; + + /* IDENT (disc, circle, square, decimal, decimal-leading-zero, + * lower-roman, upper-roman, lower-greek, lower-latin, + * upper-latin, armenian, georgian, lower-alpha, upper-alpha, + * none, inherit) + */ + ident = parserutils_vector_iterate(vector, ctx); + if (ident == NULL || ident->type != CSS_TOKEN_IDENT) { + *ctx = orig_ctx; + return CSS_INVALID; + } + + if ((lwc_string_caseless_isequal( + ident->idata, c->strings[INHERIT], + &match) == lwc_error_ok && match)) { + flags |= FLAG_INHERIT; + } else { + error = parse_list_style_type_value(c, ident, &value); + if (error != CSS_OK) { + *ctx = orig_ctx; + return error; + } + } + + opv = buildOPV(CSS_PROP_LIST_STYLE_TYPE, flags, value); + + /* Allocate result */ + error = css_stylesheet_style_create(c->sheet, sizeof(opv), result); + if (error != CSS_OK) { + *ctx = orig_ctx; + return error; + } + + /* Copy the bytecode to it */ + memcpy((*result)->bytecode, &opv, sizeof(opv)); + + return CSS_OK; +} diff --git a/src/parse/properties/margin.c b/src/parse/properties/margin.c index b3b390c..5614024 100644 --- a/src/parse/properties/margin.c +++ b/src/parse/properties/margin.c @@ -13,10 +13,6 @@ #include "parse/properties/properties.h" #include "parse/properties/utils.h" -static css_error parse_margin_side(css_language *c, - const parserutils_vector *vector, int *ctx, - uint16_t op, css_style **result); - /** * Parse margin shorthand * @@ -265,177 +261,8 @@ cleanup: return error; } -/** - * Parse margin-bottom - * - * \param c Parsing context - * \param vector Vector of tokens to process - * \param ctx Pointer to vector iteration context - * \param result Pointer to location to receive resulting style - * \return CSS_OK on success, - * CSS_NOMEM on memory exhaustion, - * CSS_INVALID if the input is not valid - * - * Post condition: \a *ctx is updated with the next token to process - * If the input is invalid, then \a *ctx remains unchanged. - */ -css_error parse_margin_bottom(css_language *c, - const parserutils_vector *vector, int *ctx, - css_style **result) -{ - return parse_margin_side(c, vector, ctx, - CSS_PROP_MARGIN_BOTTOM, result); -} - -/** - * Parse margin-left - * - * \param c Parsing context - * \param vector Vector of tokens to process - * \param ctx Pointer to vector iteration context - * \param result Pointer to location to receive resulting style - * \return CSS_OK on success, - * CSS_NOMEM on memory exhaustion, - * CSS_INVALID if the input is not valid - * - * Post condition: \a *ctx is updated with the next token to process - * If the input is invalid, then \a *ctx remains unchanged. - */ -css_error parse_margin_left(css_language *c, - const parserutils_vector *vector, int *ctx, - css_style **result) -{ - return parse_margin_side(c, vector, ctx, CSS_PROP_MARGIN_LEFT, result); -} - -/** - * Parse margin-right - * - * \param c Parsing context - * \param vector Vector of tokens to process - * \param ctx Pointer to vector iteration context - * \param result Pointer to location to receive resulting style - * \return CSS_OK on success, - * CSS_NOMEM on memory exhaustion, - * CSS_INVALID if the input is not valid - * - * Post condition: \a *ctx is updated with the next token to process - * If the input is invalid, then \a *ctx remains unchanged. - */ -css_error parse_margin_right(css_language *c, - const parserutils_vector *vector, int *ctx, - css_style **result) -{ - return parse_margin_side(c, vector, ctx, CSS_PROP_MARGIN_RIGHT, result); -} - -/** - * Parse margin-top - * - * \param c Parsing context - * \param vector Vector of tokens to process - * \param ctx Pointer to vector iteration context - * \param result Pointer to location to receive resulting style - * \return CSS_OK on success, - * CSS_NOMEM on memory exhaustion, - * CSS_INVALID if the input is not valid - * - * Post condition: \a *ctx is updated with the next token to process - * If the input is invalid, then \a *ctx remains unchanged. - */ -css_error parse_margin_top(css_language *c, - const parserutils_vector *vector, int *ctx, - css_style **result) -{ - return parse_margin_side(c, vector, ctx, CSS_PROP_MARGIN_TOP, result); -} - -/** - * Parse margin-{top,right,bottom,left} - * - * \param c Parsing context - * \param vector Vector of tokens to process - * \param ctx Pointer to vector iteration context - * \param result Pointer to location to receive resulting style - * \return CSS_OK on success, - * CSS_NOMEM on memory exhaustion, - * CSS_INVALID if the input is not valid - * - * Post condition: \a *ctx is updated with the next token to process - * If the input is invalid, then \a *ctx remains unchanged. - */ -css_error parse_margin_side(css_language *c, - const parserutils_vector *vector, int *ctx, - uint16_t op, css_style **result) -{ - int orig_ctx = *ctx; - css_error error; - const css_token *token; - uint8_t flags = 0; - uint16_t value = 0; - uint32_t opv; - css_fixed length = 0; - uint32_t unit = 0; - uint32_t required_size; - bool match; - /* length | percentage | IDENT(auto, inherit) */ - token = parserutils_vector_peek(vector, *ctx); - if (token == NULL) { - *ctx = orig_ctx; - return CSS_INVALID; - } - if (token->type == CSS_TOKEN_IDENT && - (lwc_string_caseless_isequal( - token->idata, c->strings[INHERIT], - &match) == lwc_error_ok && match)) { - parserutils_vector_iterate(vector, ctx); - flags = FLAG_INHERIT; - } else if (token->type == CSS_TOKEN_IDENT && - (lwc_string_caseless_isequal( - token->idata, c->strings[AUTO], - &match) == lwc_error_ok && match)) { - parserutils_vector_iterate(vector, ctx); - value = MARGIN_AUTO; - } else { - error = parse_unit_specifier(c, vector, ctx, UNIT_PX, - &length, &unit); - if (error != CSS_OK) { - *ctx = orig_ctx; - return error; - } - - if (unit & UNIT_ANGLE || unit & UNIT_TIME || unit & UNIT_FREQ) { - *ctx = orig_ctx; - return CSS_INVALID; - } - - value = MARGIN_SET; - } - opv = buildOPV(op, flags, value); - required_size = sizeof(opv); - if ((flags & FLAG_INHERIT) == false && value == MARGIN_SET) - required_size += sizeof(length) + sizeof(unit); - - /* Allocate result */ - error = css_stylesheet_style_create(c->sheet, required_size, result); - if (error != CSS_OK) { - *ctx = orig_ctx; - return error; - } - - /* Copy the bytecode to it */ - memcpy((*result)->bytecode, &opv, sizeof(opv)); - if ((flags & FLAG_INHERIT) == false && value == MARGIN_SET) { - memcpy(((uint8_t *) (*result)->bytecode) + sizeof(opv), - &length, sizeof(length)); - memcpy(((uint8_t *) (*result)->bytecode) + sizeof(opv) + - sizeof(length), &unit, sizeof(unit)); - } - - return CSS_OK; -} diff --git a/src/parse/properties/margin_bottom.c b/src/parse/properties/margin_bottom.c new file mode 100644 index 0000000..1c922ea --- /dev/null +++ b/src/parse/properties/margin_bottom.c @@ -0,0 +1,36 @@ +/* + * This file is part of LibCSS. + * Licensed under the MIT License, + * http://www.opensource.org/licenses/mit-license.php + * Copyright 2009 John-Mark Bell + */ + +#include +#include + +#include "bytecode/bytecode.h" +#include "bytecode/opcodes.h" +#include "parse/properties/properties.h" +#include "parse/properties/utils.h" + +/** + * Parse margin-bottom + * + * \param c Parsing context + * \param vector Vector of tokens to process + * \param ctx Pointer to vector iteration context + * \param result Pointer to location to receive resulting style + * \return CSS_OK on success, + * CSS_NOMEM on memory exhaustion, + * CSS_INVALID if the input is not valid + * + * Post condition: \a *ctx is updated with the next token to process + * If the input is invalid, then \a *ctx remains unchanged. + */ +css_error parse_margin_bottom(css_language *c, + const parserutils_vector *vector, int *ctx, + css_style **result) +{ + return parse_margin_side(c, vector, ctx, + CSS_PROP_MARGIN_BOTTOM, result); +} diff --git a/src/parse/properties/margin_left.c b/src/parse/properties/margin_left.c new file mode 100644 index 0000000..2fb4597 --- /dev/null +++ b/src/parse/properties/margin_left.c @@ -0,0 +1,35 @@ +/* + * This file is part of LibCSS. + * Licensed under the MIT License, + * http://www.opensource.org/licenses/mit-license.php + * Copyright 2009 John-Mark Bell + */ + +#include +#include + +#include "bytecode/bytecode.h" +#include "bytecode/opcodes.h" +#include "parse/properties/properties.h" +#include "parse/properties/utils.h" + +/** + * Parse margin-left + * + * \param c Parsing context + * \param vector Vector of tokens to process + * \param ctx Pointer to vector iteration context + * \param result Pointer to location to receive resulting style + * \return CSS_OK on success, + * CSS_NOMEM on memory exhaustion, + * CSS_INVALID if the input is not valid + * + * Post condition: \a *ctx is updated with the next token to process + * If the input is invalid, then \a *ctx remains unchanged. + */ +css_error parse_margin_left(css_language *c, + const parserutils_vector *vector, int *ctx, + css_style **result) +{ + return parse_margin_side(c, vector, ctx, CSS_PROP_MARGIN_LEFT, result); +} diff --git a/src/parse/properties/margin_right.c b/src/parse/properties/margin_right.c new file mode 100644 index 0000000..4fe0363 --- /dev/null +++ b/src/parse/properties/margin_right.c @@ -0,0 +1,35 @@ +/* + * This file is part of LibCSS. + * Licensed under the MIT License, + * http://www.opensource.org/licenses/mit-license.php + * Copyright 2009 John-Mark Bell + */ + +#include +#include + +#include "bytecode/bytecode.h" +#include "bytecode/opcodes.h" +#include "parse/properties/properties.h" +#include "parse/properties/utils.h" + +/** + * Parse margin-right + * + * \param c Parsing context + * \param vector Vector of tokens to process + * \param ctx Pointer to vector iteration context + * \param result Pointer to location to receive resulting style + * \return CSS_OK on success, + * CSS_NOMEM on memory exhaustion, + * CSS_INVALID if the input is not valid + * + * Post condition: \a *ctx is updated with the next token to process + * If the input is invalid, then \a *ctx remains unchanged. + */ +css_error parse_margin_right(css_language *c, + const parserutils_vector *vector, int *ctx, + css_style **result) +{ + return parse_margin_side(c, vector, ctx, CSS_PROP_MARGIN_RIGHT, result); +} diff --git a/src/parse/properties/margin_top.c b/src/parse/properties/margin_top.c new file mode 100644 index 0000000..7bba06b --- /dev/null +++ b/src/parse/properties/margin_top.c @@ -0,0 +1,35 @@ +/* + * This file is part of LibCSS. + * Licensed under the MIT License, + * http://www.opensource.org/licenses/mit-license.php + * Copyright 2009 John-Mark Bell + */ + +#include +#include + +#include "bytecode/bytecode.h" +#include "bytecode/opcodes.h" +#include "parse/properties/properties.h" +#include "parse/properties/utils.h" + +/** + * Parse margin-top + * + * \param c Parsing context + * \param vector Vector of tokens to process + * \param ctx Pointer to vector iteration context + * \param result Pointer to location to receive resulting style + * \return CSS_OK on success, + * CSS_NOMEM on memory exhaustion, + * CSS_INVALID if the input is not valid + * + * Post condition: \a *ctx is updated with the next token to process + * If the input is invalid, then \a *ctx remains unchanged. + */ +css_error parse_margin_top(css_language *c, + const parserutils_vector *vector, int *ctx, + css_style **result) +{ + return parse_margin_side(c, vector, ctx, CSS_PROP_MARGIN_TOP, result); +} diff --git a/src/parse/properties/max_height.c b/src/parse/properties/max_height.c new file mode 100644 index 0000000..cbabf24 --- /dev/null +++ b/src/parse/properties/max_height.c @@ -0,0 +1,109 @@ +/* + * This file is part of LibCSS. + * Licensed under the MIT License, + * http://www.opensource.org/licenses/mit-license.php + * Copyright 2009 John-Mark Bell + */ + +#include +#include + +#include "bytecode/bytecode.h" +#include "bytecode/opcodes.h" +#include "parse/properties/properties.h" +#include "parse/properties/utils.h" + +/** + * Parse max-height + * + * \param c Parsing context + * \param vector Vector of tokens to process + * \param ctx Pointer to vector iteration context + * \param result Pointer to location to receive resulting style + * \return CSS_OK on success, + * CSS_NOMEM on memory exhaustion, + * CSS_INVALID if the input is not valid + * + * Post condition: \a *ctx is updated with the next token to process + * If the input is invalid, then \a *ctx remains unchanged. + */ +css_error parse_max_height(css_language *c, + const parserutils_vector *vector, int *ctx, + css_style **result) +{ + int orig_ctx = *ctx; + css_error error; + const css_token *token; + uint8_t flags = 0; + uint16_t value = 0; + uint32_t opv; + css_fixed length = 0; + uint32_t unit = 0; + uint32_t required_size; + bool match; + + /* length | percentage | IDENT(none, inherit) */ + token = parserutils_vector_peek(vector, *ctx); + if (token == NULL) { + *ctx = orig_ctx; + return CSS_INVALID; + } + + if (token->type == CSS_TOKEN_IDENT && + (lwc_string_caseless_isequal( + token->idata, c->strings[INHERIT], + &match) == lwc_error_ok && match)) { + parserutils_vector_iterate(vector, ctx); + flags = FLAG_INHERIT; + } else if (token->type == CSS_TOKEN_IDENT && + (lwc_string_caseless_isequal( + token->idata, c->strings[NONE], + &match) == lwc_error_ok && match)) { + parserutils_vector_iterate(vector, ctx); + value = MAX_HEIGHT_NONE; + } else { + error = parse_unit_specifier(c, vector, ctx, UNIT_PX, + &length, &unit); + if (error != CSS_OK) { + *ctx = orig_ctx; + return error; + } + + if (unit & UNIT_ANGLE || unit & UNIT_TIME || unit & UNIT_FREQ) { + *ctx = orig_ctx; + return CSS_INVALID; + } + + /* Negative values are illegal */ + if (length < 0) { + *ctx = orig_ctx; + return CSS_INVALID; + } + + value = MAX_HEIGHT_SET; + } + + opv = buildOPV(CSS_PROP_MAX_HEIGHT, flags, value); + + required_size = sizeof(opv); + if ((flags & FLAG_INHERIT) == false && value == MAX_HEIGHT_SET) + required_size += sizeof(length) + sizeof(unit); + + /* Allocate result */ + error = css_stylesheet_style_create(c->sheet, required_size, result); + if (error != CSS_OK) { + *ctx = orig_ctx; + return error; + } + + /* Copy the bytecode to it */ + memcpy((*result)->bytecode, &opv, sizeof(opv)); + if ((flags & FLAG_INHERIT) == false && value == MAX_HEIGHT_SET) { + memcpy(((uint8_t *) (*result)->bytecode) + sizeof(opv), + &length, sizeof(length)); + memcpy(((uint8_t *) (*result)->bytecode) + sizeof(opv) + + sizeof(length), &unit, sizeof(unit)); + } + + return CSS_OK; +} diff --git a/src/parse/properties/max_width.c b/src/parse/properties/max_width.c new file mode 100644 index 0000000..4ee9572 --- /dev/null +++ b/src/parse/properties/max_width.c @@ -0,0 +1,109 @@ +/* + * This file is part of LibCSS. + * Licensed under the MIT License, + * http://www.opensource.org/licenses/mit-license.php + * Copyright 2009 John-Mark Bell + */ + +#include +#include + +#include "bytecode/bytecode.h" +#include "bytecode/opcodes.h" +#include "parse/properties/properties.h" +#include "parse/properties/utils.h" + +/** + * Parse max-width + * + * \param c Parsing context + * \param vector Vector of tokens to process + * \param ctx Pointer to vector iteration context + * \param result Pointer to location to receive resulting style + * \return CSS_OK on success, + * CSS_NOMEM on memory exhaustion, + * CSS_INVALID if the input is not valid + * + * Post condition: \a *ctx is updated with the next token to process + * If the input is invalid, then \a *ctx remains unchanged. + */ +css_error parse_max_width(css_language *c, + const parserutils_vector *vector, int *ctx, + css_style **result) +{ + int orig_ctx = *ctx; + css_error error; + const css_token *token; + uint8_t flags = 0; + uint16_t value = 0; + uint32_t opv; + css_fixed length = 0; + uint32_t unit = 0; + uint32_t required_size; + bool match; + + /* length | percentage | IDENT(none, inherit) */ + token = parserutils_vector_peek(vector, *ctx); + if (token == NULL) { + *ctx = orig_ctx; + return CSS_INVALID; + } + + if (token->type == CSS_TOKEN_IDENT && + (lwc_string_caseless_isequal( + token->idata, c->strings[INHERIT], + &match) == lwc_error_ok && match)) { + parserutils_vector_iterate(vector, ctx); + flags = FLAG_INHERIT; + } else if (token->type == CSS_TOKEN_IDENT && + (lwc_string_caseless_isequal( + token->idata, c->strings[NONE], + &match) == lwc_error_ok && match)) { + parserutils_vector_iterate(vector, ctx); + value = MAX_WIDTH_NONE; + } else { + error = parse_unit_specifier(c, vector, ctx, UNIT_PX, + &length, &unit); + if (error != CSS_OK) { + *ctx = orig_ctx; + return error; + } + + if (unit & UNIT_ANGLE || unit & UNIT_TIME || unit & UNIT_FREQ) { + *ctx = orig_ctx; + return CSS_INVALID; + } + + /* Negative values are illegal */ + if (length < 0) { + *ctx = orig_ctx; + return CSS_INVALID; + } + + value = MAX_WIDTH_SET; + } + + opv = buildOPV(CSS_PROP_MAX_WIDTH, flags, value); + + required_size = sizeof(opv); + if ((flags & FLAG_INHERIT) == false && value == MAX_WIDTH_SET) + required_size += sizeof(length) + sizeof(unit); + + /* Allocate result */ + error = css_stylesheet_style_create(c->sheet, required_size, result); + if (error != CSS_OK) { + *ctx = orig_ctx; + return error; + } + + /* Copy the bytecode to it */ + memcpy((*result)->bytecode, &opv, sizeof(opv)); + if ((flags & FLAG_INHERIT) == false && value == MAX_WIDTH_SET) { + memcpy(((uint8_t *) (*result)->bytecode) + sizeof(opv), + &length, sizeof(length)); + memcpy(((uint8_t *) (*result)->bytecode) + sizeof(opv) + + sizeof(length), &unit, sizeof(unit)); + } + + return CSS_OK; +} diff --git a/src/parse/properties/min_height.c b/src/parse/properties/min_height.c new file mode 100644 index 0000000..36adbd5 --- /dev/null +++ b/src/parse/properties/min_height.c @@ -0,0 +1,103 @@ +/* + * This file is part of LibCSS. + * Licensed under the MIT License, + * http://www.opensource.org/licenses/mit-license.php + * Copyright 2009 John-Mark Bell + */ + +#include +#include + +#include "bytecode/bytecode.h" +#include "bytecode/opcodes.h" +#include "parse/properties/properties.h" +#include "parse/properties/utils.h" + +/** + * Parse min-height + * + * \param c Parsing context + * \param vector Vector of tokens to process + * \param ctx Pointer to vector iteration context + * \param result Pointer to location to receive resulting style + * \return CSS_OK on success, + * CSS_NOMEM on memory exhaustion, + * CSS_INVALID if the input is not valid + * + * Post condition: \a *ctx is updated with the next token to process + * If the input is invalid, then \a *ctx remains unchanged. + */ +css_error parse_min_height(css_language *c, + const parserutils_vector *vector, int *ctx, + css_style **result) +{ + int orig_ctx = *ctx; + css_error error; + const css_token *token; + uint8_t flags = 0; + uint16_t value = 0; + uint32_t opv; + css_fixed length = 0; + uint32_t unit = 0; + uint32_t required_size; + bool match; + + /* length | percentage | IDENT(inherit) */ + token = parserutils_vector_peek(vector, *ctx); + if (token == NULL) { + *ctx = orig_ctx; + return CSS_INVALID; + } + + if (token->type == CSS_TOKEN_IDENT && + (lwc_string_caseless_isequal( + token->idata, c->strings[INHERIT], + &match) == lwc_error_ok && match)) { + parserutils_vector_iterate(vector, ctx); + flags = FLAG_INHERIT; + } else { + error = parse_unit_specifier(c, vector, ctx, UNIT_PX, + &length, &unit); + if (error != CSS_OK) { + *ctx = orig_ctx; + return error; + } + + if (unit & UNIT_ANGLE || unit & UNIT_TIME || unit & UNIT_FREQ) { + *ctx = orig_ctx; + return CSS_INVALID; + } + + /* Negative values are illegal */ + if (length < 0) { + *ctx = orig_ctx; + return CSS_INVALID; + } + + value = MIN_HEIGHT_SET; + } + + opv = buildOPV(CSS_PROP_MIN_HEIGHT, flags, value); + + required_size = sizeof(opv); + if ((flags & FLAG_INHERIT) == false && value == MIN_HEIGHT_SET) + required_size += sizeof(length) + sizeof(unit); + + /* Allocate result */ + error = css_stylesheet_style_create(c->sheet, required_size, result); + if (error != CSS_OK) { + *ctx = orig_ctx; + return error; + } + + /* Copy the bytecode to it */ + memcpy((*result)->bytecode, &opv, sizeof(opv)); + if ((flags & FLAG_INHERIT) == false && value == MIN_HEIGHT_SET) { + memcpy(((uint8_t *) (*result)->bytecode) + sizeof(opv), + &length, sizeof(length)); + memcpy(((uint8_t *) (*result)->bytecode) + sizeof(opv) + + sizeof(length), &unit, sizeof(unit)); + } + + return CSS_OK; +} diff --git a/src/parse/properties/min_width.c b/src/parse/properties/min_width.c new file mode 100644 index 0000000..fba6518 --- /dev/null +++ b/src/parse/properties/min_width.c @@ -0,0 +1,103 @@ +/* + * This file is part of LibCSS. + * Licensed under the MIT License, + * http://www.opensource.org/licenses/mit-license.php + * Copyright 2009 John-Mark Bell + */ + +#include +#include + +#include "bytecode/bytecode.h" +#include "bytecode/opcodes.h" +#include "parse/properties/properties.h" +#include "parse/properties/utils.h" + +/** + * Parse min-width + * + * \param c Parsing context + * \param vector Vector of tokens to process + * \param ctx Pointer to vector iteration context + * \param result Pointer to location to receive resulting style + * \return CSS_OK on success, + * CSS_NOMEM on memory exhaustion, + * CSS_INVALID if the input is not valid + * + * Post condition: \a *ctx is updated with the next token to process + * If the input is invalid, then \a *ctx remains unchanged. + */ +css_error parse_min_width(css_language *c, + const parserutils_vector *vector, int *ctx, + css_style **result) +{ + int orig_ctx = *ctx; + css_error error; + const css_token *token; + uint8_t flags = 0; + uint16_t value = 0; + uint32_t opv; + css_fixed length = 0; + uint32_t unit = 0; + uint32_t required_size; + bool match; + + /* length | percentage | IDENT(inherit) */ + token = parserutils_vector_peek(vector, *ctx); + if (token == NULL) { + *ctx = orig_ctx; + return CSS_INVALID; + } + + if (token->type == CSS_TOKEN_IDENT && + (lwc_string_caseless_isequal( + token->idata, c->strings[INHERIT], + &match) == lwc_error_ok && match)) { + parserutils_vector_iterate(vector, ctx); + flags = FLAG_INHERIT; + } else { + error = parse_unit_specifier(c, vector, ctx, UNIT_PX, + &length, &unit); + if (error != CSS_OK) { + *ctx = orig_ctx; + return error; + } + + if (unit & UNIT_ANGLE || unit & UNIT_TIME || unit & UNIT_FREQ) { + *ctx = orig_ctx; + return CSS_INVALID; + } + + /* Negative values are illegal */ + if (length < 0) { + *ctx = orig_ctx; + return CSS_INVALID; + } + + value = MIN_WIDTH_SET; + } + + opv = buildOPV(CSS_PROP_MIN_WIDTH, flags, value); + + required_size = sizeof(opv); + if ((flags & FLAG_INHERIT) == false && value == MIN_WIDTH_SET) + required_size += sizeof(length) + sizeof(unit); + + /* Allocate result */ + error = css_stylesheet_style_create(c->sheet, required_size, result); + if (error != CSS_OK) { + *ctx = orig_ctx; + return error; + } + + /* Copy the bytecode to it */ + memcpy((*result)->bytecode, &opv, sizeof(opv)); + if ((flags & FLAG_INHERIT) == false && value == MIN_WIDTH_SET) { + memcpy(((uint8_t *) (*result)->bytecode) + sizeof(opv), + &length, sizeof(length)); + memcpy(((uint8_t *) (*result)->bytecode) + sizeof(opv) + + sizeof(length), &unit, sizeof(unit)); + } + + return CSS_OK; +} diff --git a/src/parse/properties/orphans.c b/src/parse/properties/orphans.c new file mode 100644 index 0000000..735db60 --- /dev/null +++ b/src/parse/properties/orphans.c @@ -0,0 +1,98 @@ +/* + * This file is part of LibCSS. + * Licensed under the MIT License, + * http://www.opensource.org/licenses/mit-license.php + * Copyright 2009 John-Mark Bell + */ + +#include +#include + +#include "bytecode/bytecode.h" +#include "bytecode/opcodes.h" +#include "parse/properties/properties.h" +#include "parse/properties/utils.h" + +/** + * Parse orphans + * + * \param c Parsing context + * \param vector Vector of tokens to process + * \param ctx Pointer to vector iteration context + * \param result Pointer to location to receive resulting style + * \return CSS_OK on success, + * CSS_NOMEM on memory exhaustion, + * CSS_INVALID if the input is not valid + * + * Post condition: \a *ctx is updated with the next token to process + * If the input is invalid, then \a *ctx remains unchanged. + */ +css_error parse_orphans(css_language *c, + const parserutils_vector *vector, int *ctx, + css_style **result) +{ + int orig_ctx = *ctx; + css_error error; + const css_token *token; + uint8_t flags = 0; + uint16_t value = 0; + uint32_t opv; + css_fixed num = 0; + uint32_t required_size; + bool match; + + /* | IDENT (inherit) */ + token = parserutils_vector_iterate(vector, ctx); + if (token == NULL || (token->type != CSS_TOKEN_IDENT && + token->type != CSS_TOKEN_NUMBER)) { + *ctx = orig_ctx; + return CSS_INVALID; + } + + if ((lwc_string_caseless_isequal( + token->idata, c->strings[INHERIT], + &match) == lwc_error_ok && match)) { + flags |= FLAG_INHERIT; + } else if (token->type == CSS_TOKEN_NUMBER) { + size_t consumed = 0; + num = number_from_lwc_string(token->idata, true, &consumed); + /* Invalid if there are trailing characters */ + if (consumed != lwc_string_length(token->idata)) { + *ctx = orig_ctx; + return CSS_INVALID; + } + + /* Negative values are nonsensical */ + if (num < 0) { + *ctx = orig_ctx; + return CSS_INVALID; + } + + value = ORPHANS_SET; + } else { + *ctx = orig_ctx; + return CSS_INVALID; + } + + opv = buildOPV(CSS_PROP_ORPHANS, flags, value); + + required_size = sizeof(opv); + if ((flags & FLAG_INHERIT) == false && value == ORPHANS_SET) + required_size += sizeof(num); + + /* Allocate result */ + error = css_stylesheet_style_create(c->sheet, required_size, result); + if (error != CSS_OK) { + *ctx = orig_ctx; + return error; + } + + /* Copy the bytecode to it */ + memcpy((*result)->bytecode, &opv, sizeof(opv)); + if ((flags & FLAG_INHERIT) == false && value == ORPHANS_SET) { + memcpy(((uint8_t *) (*result)->bytecode) + sizeof(opv), + &num, sizeof(num)); + } + + return CSS_OK; +} diff --git a/src/parse/properties/outline.c b/src/parse/properties/outline.c new file mode 100644 index 0000000..b262609 --- /dev/null +++ b/src/parse/properties/outline.c @@ -0,0 +1,197 @@ +/* + * This file is part of LibCSS. + * Licensed under the MIT License, + * http://www.opensource.org/licenses/mit-license.php + * Copyright 2009 John-Mark Bell + */ + +#include +#include + +#include "bytecode/bytecode.h" +#include "bytecode/opcodes.h" +#include "parse/properties/properties.h" +#include "parse/properties/utils.h" + +/** + * Parse outline shorthand + * + * \param c Parsing context + * \param vector Vector of tokens to process + * \param ctx Pointer to vector iteration context + * \param result Pointer to location to receive resulting style + * \return CSS_OK on success, + * CSS_NOMEM on memory exhaustion, + * CSS_INVALID if the input is not valid + * + * Post condition: \a *ctx is updated with the next token to process + * If the input is invalid, then \a *ctx remains unchanged. + */ +css_error parse_outline(css_language *c, + const parserutils_vector *vector, int *ctx, + css_style **result) +{ + int orig_ctx = *ctx; + int prev_ctx; + const css_token *token; + css_style *color = NULL; + css_style *style = NULL; + css_style *width = NULL; + css_style *ret = NULL; + uint32_t required_size; + bool match; + css_error error; + + /* Firstly, handle inherit */ + token = parserutils_vector_peek(vector, *ctx); + if (token != NULL && token->type == CSS_TOKEN_IDENT && + (lwc_string_caseless_isequal( + token->idata, c->strings[INHERIT], + &match) == lwc_error_ok && match)) { + uint32_t *bytecode; + + error = css_stylesheet_style_create(c->sheet, + 3 * sizeof(uint32_t), &ret); + if (error != CSS_OK) { + *ctx = orig_ctx; + return error; + } + + bytecode = (uint32_t *) ret->bytecode; + + *(bytecode++) = buildOPV(CSS_PROP_OUTLINE_COLOR, + FLAG_INHERIT, 0); + *(bytecode++) = buildOPV(CSS_PROP_OUTLINE_STYLE, + FLAG_INHERIT, 0); + *(bytecode++) = buildOPV(CSS_PROP_OUTLINE_WIDTH, + FLAG_INHERIT, 0); + + parserutils_vector_iterate(vector, ctx); + + *result = ret; + + return CSS_OK; + } else if (token == NULL) { + /* No tokens -- clearly garbage */ + *ctx = orig_ctx; + return CSS_INVALID; + } + + /* Attempt to parse individual properties */ + do { + prev_ctx = *ctx; + error = CSS_OK; + + /* Ensure that we're not about to parse another inherit */ + token = parserutils_vector_peek(vector, *ctx); + if (token != NULL && token->type == CSS_TOKEN_IDENT && + (lwc_string_caseless_isequal( + token->idata, c->strings[INHERIT], + &match) == lwc_error_ok && match)) { + error = CSS_INVALID; + goto cleanup; + } + + if (color == NULL && + (error = parse_outline_color(c, vector, + ctx, &color)) == CSS_OK) { + } else if (style == NULL && + (error = parse_outline_style(c, vector, + ctx, &style)) == CSS_OK) { + } else if (width == NULL && + (error = parse_outline_width(c, vector, + ctx, &width)) == CSS_OK) { + } + + if (error == CSS_OK) { + consumeWhitespace(vector, ctx); + + token = parserutils_vector_peek(vector, *ctx); + } else { + /* Forcibly cause loop to exit */ + token = NULL; + } + } while (*ctx != prev_ctx && token != NULL); + + /* Calculate size of resultant style */ + required_size = 0; + if (color) + required_size += color->length; + else + required_size += sizeof(uint32_t); + + if (style) + required_size += style->length; + else + required_size += sizeof(uint32_t); + + if (width) + required_size += width->length; + else + required_size += sizeof(uint32_t); + + error = css_stylesheet_style_create(c->sheet, required_size, &ret); + if (error != CSS_OK) + goto cleanup; + + required_size = 0; + + if (color) { + memcpy(((uint8_t *) ret->bytecode) + required_size, + color->bytecode, color->length); + required_size += color->length; + } else { + void *bc = ((uint8_t *) ret->bytecode) + required_size; + + *((uint32_t *) bc) = buildOPV(CSS_PROP_OUTLINE_COLOR, + 0, OUTLINE_COLOR_INVERT); + required_size += sizeof(uint32_t); + } + + if (style) { + memcpy(((uint8_t *) ret->bytecode) + required_size, + style->bytecode, style->length); + required_size += style->length; + } else { + void *bc = ((uint8_t *) ret->bytecode) + required_size; + + *((uint32_t *) bc) = buildOPV(CSS_PROP_OUTLINE_STYLE, + 0, OUTLINE_STYLE_NONE); + required_size += sizeof(uint32_t); + } + + if (width) { + memcpy(((uint8_t *) ret->bytecode) + required_size, + width->bytecode, width->length); + required_size += width->length; + } else { + void *bc = ((uint8_t *) ret->bytecode) + required_size; + + *((uint32_t *) bc) = buildOPV(CSS_PROP_OUTLINE_WIDTH, + 0, OUTLINE_WIDTH_MEDIUM); + required_size += sizeof(uint32_t); + } + + assert(required_size == ret->length); + + /* Write the result */ + *result = ret; + /* Invalidate ret, so that cleanup doesn't destroy it */ + ret = NULL; + + /* Clean up after ourselves */ +cleanup: + if (color) + css_stylesheet_style_destroy(c->sheet, color, error == CSS_OK); + if (style) + css_stylesheet_style_destroy(c->sheet, style, error == CSS_OK); + if (width) + css_stylesheet_style_destroy(c->sheet, width, error == CSS_OK); + if (ret) + css_stylesheet_style_destroy(c->sheet, ret, error == CSS_OK); + + if (error != CSS_OK) + *ctx = orig_ctx; + + return error; +} diff --git a/src/parse/properties/outline_color.c b/src/parse/properties/outline_color.c new file mode 100644 index 0000000..402dee3 --- /dev/null +++ b/src/parse/properties/outline_color.c @@ -0,0 +1,94 @@ +/* + * This file is part of LibCSS. + * Licensed under the MIT License, + * http://www.opensource.org/licenses/mit-license.php + * Copyright 2009 John-Mark Bell + */ + +#include +#include + +#include "bytecode/bytecode.h" +#include "bytecode/opcodes.h" +#include "parse/properties/properties.h" +#include "parse/properties/utils.h" + +/** + * Parse outline-color + * + * \param c Parsing context + * \param vector Vector of tokens to process + * \param ctx Pointer to vector iteration context + * \param result Pointer to location to receive resulting style + * \return CSS_OK on success, + * CSS_NOMEM on memory exhaustion, + * CSS_INVALID if the input is not valid + * + * Post condition: \a *ctx is updated with the next token to process + * If the input is invalid, then \a *ctx remains unchanged. + */ +css_error parse_outline_color(css_language *c, + const parserutils_vector *vector, int *ctx, + css_style **result) +{ + int orig_ctx = *ctx; + css_error error; + const css_token *token; + uint8_t flags = 0; + uint16_t value = 0; + uint32_t opv; + uint32_t colour = 0; + uint32_t required_size; + bool match; + + /* colour | IDENT (invert, inherit) */ + token = parserutils_vector_peek(vector, *ctx); + if (token == NULL) { + *ctx = orig_ctx; + return CSS_INVALID; + } + + if (token->type == CSS_TOKEN_IDENT && + (lwc_string_caseless_isequal( + token->idata, c->strings[INHERIT], + &match) == lwc_error_ok && match)) { + parserutils_vector_iterate(vector, ctx); + flags |= FLAG_INHERIT; + } else if (token->type == CSS_TOKEN_IDENT && + (lwc_string_caseless_isequal( + token->idata, c->strings[INVERT], + &match) == lwc_error_ok && match)) { + parserutils_vector_iterate(vector, ctx); + value = OUTLINE_COLOR_INVERT; + } else { + error = parse_colour_specifier(c, vector, ctx, &colour); + if (error != CSS_OK) { + *ctx = orig_ctx; + return error; + } + + value = OUTLINE_COLOR_SET; + } + + opv = buildOPV(CSS_PROP_OUTLINE_COLOR, flags, value); + + required_size = sizeof(opv); + if ((flags & FLAG_INHERIT) == false && value == OUTLINE_COLOR_SET) + required_size += sizeof(colour); + + /* Allocate result */ + error = css_stylesheet_style_create(c->sheet, required_size, result); + if (error != CSS_OK) { + *ctx = orig_ctx; + return error; + } + + /* Copy the bytecode to it */ + memcpy((*result)->bytecode, &opv, sizeof(opv)); + if ((flags & FLAG_INHERIT) == false && value == OUTLINE_COLOR_SET) { + memcpy(((uint8_t *) (*result)->bytecode) + sizeof(opv), + &colour, sizeof(colour)); + } + + return CSS_OK; +} diff --git a/src/parse/properties/outline_style.c b/src/parse/properties/outline_style.c new file mode 100644 index 0000000..0263d68 --- /dev/null +++ b/src/parse/properties/outline_style.c @@ -0,0 +1,58 @@ +/* + * This file is part of LibCSS. + * Licensed under the MIT License, + * http://www.opensource.org/licenses/mit-license.php + * Copyright 2009 John-Mark Bell + */ + +#include +#include + +#include "bytecode/bytecode.h" +#include "bytecode/opcodes.h" +#include "parse/properties/properties.h" +#include "parse/properties/utils.h" + +/** + * Parse outline-style + * + * \param c Parsing context + * \param vector Vector of tokens to process + * \param ctx Pointer to vector iteration context + * \param result Pointer to location to receive resulting style + * \return CSS_OK on success, + * CSS_NOMEM on memory exhaustion, + * CSS_INVALID if the input is not valid + * + * Post condition: \a *ctx is updated with the next token to process + * If the input is invalid, then \a *ctx remains unchanged. + */ +css_error parse_outline_style(css_language *c, + const parserutils_vector *vector, int *ctx, + css_style **result) +{ + int orig_ctx = *ctx; + css_error error; + uint32_t opv; + uint16_t value; + + /* Parse as a border style */ + error = parse_border_side_style(c, vector, ctx, + CSS_PROP_OUTLINE_STYLE, result); + if (error != CSS_OK) { + *ctx = orig_ctx; + return error; + } + + opv = *((uint32_t *) (*result)->bytecode); + + value = getValue(opv); + + /* Hidden is invalid */ + if (value == BORDER_STYLE_HIDDEN) { + *ctx = orig_ctx; + return CSS_INVALID; + } + + return CSS_OK; +} diff --git a/src/parse/properties/outline_width.c b/src/parse/properties/outline_width.c new file mode 100644 index 0000000..54a669a --- /dev/null +++ b/src/parse/properties/outline_width.c @@ -0,0 +1,37 @@ +/* + * This file is part of LibCSS. + * Licensed under the MIT License, + * http://www.opensource.org/licenses/mit-license.php + * Copyright 2009 John-Mark Bell + */ + +#include +#include + +#include "bytecode/bytecode.h" +#include "bytecode/opcodes.h" +#include "parse/properties/properties.h" +#include "parse/properties/utils.h" + +/** + * Parse outline-width + * + * \param c Parsing context + * \param vector Vector of tokens to process + * \param ctx Pointer to vector iteration context + * \param result Pointer to location to receive resulting style + * \return CSS_OK on success, + * CSS_NOMEM on memory exhaustion, + * CSS_INVALID if the input is not valid + * + * Post condition: \a *ctx is updated with the next token to process + * If the input is invalid, then \a *ctx remains unchanged. + */ +css_error parse_outline_width(css_language *c, + const parserutils_vector *vector, int *ctx, + css_style **result) +{ + /* Parse as border width */ + return parse_border_side_width(c, vector, ctx, + CSS_PROP_OUTLINE_WIDTH, result); +} diff --git a/src/parse/properties/overflow.c b/src/parse/properties/overflow.c new file mode 100644 index 0000000..5d5ade0 --- /dev/null +++ b/src/parse/properties/overflow.c @@ -0,0 +1,87 @@ +/* + * This file is part of LibCSS. + * Licensed under the MIT License, + * http://www.opensource.org/licenses/mit-license.php + * Copyright 2009 John-Mark Bell + */ + +#include +#include + +#include "bytecode/bytecode.h" +#include "bytecode/opcodes.h" +#include "parse/properties/properties.h" +#include "parse/properties/utils.h" + +/** + * Parse overflow + * + * \param c Parsing context + * \param vector Vector of tokens to process + * \param ctx Pointer to vector iteration context + * \param result Pointer to location to receive resulting style + * \return CSS_OK on success, + * CSS_NOMEM on memory exhaustion, + * CSS_INVALID if the input is not valid + * + * Post condition: \a *ctx is updated with the next token to process + * If the input is invalid, then \a *ctx remains unchanged. + */ +css_error parse_overflow(css_language *c, + const parserutils_vector *vector, int *ctx, + css_style **result) +{ + int orig_ctx = *ctx; + css_error error; + const css_token *ident; + uint8_t flags = 0; + uint16_t value = 0; + uint32_t opv; + bool match; + + /* IDENT (visible, hidden, scroll, auto, inherit) */ + ident = parserutils_vector_iterate(vector, ctx); + if (ident == NULL || ident->type != CSS_TOKEN_IDENT) { + *ctx = orig_ctx; + return CSS_INVALID; + } + + if ((lwc_string_caseless_isequal( + ident->idata, c->strings[INHERIT], + &match) == lwc_error_ok && match)) { + flags |= FLAG_INHERIT; + } else if ((lwc_string_caseless_isequal( + ident->idata, c->strings[VISIBLE], + &match) == lwc_error_ok && match)) { + value = OVERFLOW_VISIBLE; + } else if ((lwc_string_caseless_isequal( + ident->idata, c->strings[HIDDEN], + &match) == lwc_error_ok && match)) { + value = OVERFLOW_HIDDEN; + } else if ((lwc_string_caseless_isequal( + ident->idata, c->strings[SCROLL], + &match) == lwc_error_ok && match)) { + value = OVERFLOW_SCROLL; + } else if ((lwc_string_caseless_isequal( + ident->idata, c->strings[AUTO], + &match) == lwc_error_ok && match)) { + value = OVERFLOW_AUTO; + } else { + *ctx = orig_ctx; + return CSS_INVALID; + } + + opv = buildOPV(CSS_PROP_OVERFLOW, flags, value); + + /* Allocate result */ + error = css_stylesheet_style_create(c->sheet, sizeof(opv), result); + if (error != CSS_OK) { + *ctx = orig_ctx; + return error; + } + + /* Copy the bytecode to it */ + memcpy((*result)->bytecode, &opv, sizeof(opv)); + + return CSS_OK; +} diff --git a/src/parse/properties/padding.c b/src/parse/properties/padding.c index 767c1f1..753b530 100644 --- a/src/parse/properties/padding.c +++ b/src/parse/properties/padding.c @@ -13,10 +13,6 @@ #include "parse/properties/properties.h" #include "parse/properties/utils.h" -static css_error parse_padding_side(css_language *c, - const parserutils_vector *vector, int *ctx, - uint16_t op, css_style **result); - /** * Parse padding shorthand * @@ -265,180 +261,3 @@ cleanup: return error; } -/** - * Parse padding-bottom - * - * \param c Parsing context - * \param vector Vector of tokens to process - * \param ctx Pointer to vector iteration context - * \param result Pointer to location to receive resulting style - * \return CSS_OK on success, - * CSS_NOMEM on memory exhaustion, - * CSS_INVALID if the input is not valid - * - * Post condition: \a *ctx is updated with the next token to process - * If the input is invalid, then \a *ctx remains unchanged. - */ -css_error parse_padding_bottom(css_language *c, - const parserutils_vector *vector, int *ctx, - css_style **result) -{ - return parse_padding_side(c, vector, ctx, - CSS_PROP_PADDING_BOTTOM, result); -} - -/** - * Parse padding-left - * - * \param c Parsing context - * \param vector Vector of tokens to process - * \param ctx Pointer to vector iteration context - * \param result Pointer to location to receive resulting style - * \return CSS_OK on success, - * CSS_NOMEM on memory exhaustion, - * CSS_INVALID if the input is not valid - * - * Post condition: \a *ctx is updated with the next token to process - * If the input is invalid, then \a *ctx remains unchanged. - */ -css_error parse_padding_left(css_language *c, - const parserutils_vector *vector, int *ctx, - css_style **result) -{ - return parse_padding_side(c, vector, ctx, - CSS_PROP_PADDING_LEFT, result); -} - -/** - * Parse padding-right - * - * \param c Parsing context - * \param vector Vector of tokens to process - * \param ctx Pointer to vector iteration context - * \param result Pointer to location to receive resulting style - * \return CSS_OK on success, - * CSS_NOMEM on memory exhaustion, - * CSS_INVALID if the input is not valid - * - * Post condition: \a *ctx is updated with the next token to process - * If the input is invalid, then \a *ctx remains unchanged. - */ -css_error parse_padding_right(css_language *c, - const parserutils_vector *vector, int *ctx, - css_style **result) -{ - return parse_padding_side(c, vector, ctx, - CSS_PROP_PADDING_RIGHT, result); -} - -/** - * Parse padding-top - * - * \param c Parsing context - * \param vector Vector of tokens to process - * \param ctx Pointer to vector iteration context - * \param result Pointer to location to receive resulting style - * \return CSS_OK on success, - * CSS_NOMEM on memory exhaustion, - * CSS_INVALID if the input is not valid - * - * Post condition: \a *ctx is updated with the next token to process - * If the input is invalid, then \a *ctx remains unchanged. - */ -css_error parse_padding_top(css_language *c, - const parserutils_vector *vector, int *ctx, - css_style **result) -{ - return parse_padding_side(c, vector, ctx, - CSS_PROP_PADDING_TOP, result); -} - -/** - * Parse padding-{top,right,bottom,left} - * - * \param c Parsing context - * \param vector Vector of tokens to process - * \param ctx Pointer to vector iteration context - * \param result Pointer to location to receive resulting style - * \return CSS_OK on success, - * CSS_NOMEM on memory exhaustion, - * CSS_INVALID if the input is not valid - * - * Post condition: \a *ctx is updated with the next token to process - * If the input is invalid, then \a *ctx remains unchanged. - */ -css_error parse_padding_side(css_language *c, - const parserutils_vector *vector, int *ctx, - uint16_t op, css_style **result) -{ - int orig_ctx = *ctx; - css_error error; - const css_token *token; - uint8_t flags = 0; - uint16_t value = 0; - uint32_t opv; - css_fixed length = 0; - uint32_t unit = 0; - uint32_t required_size; - bool match; - - /* length | percentage | IDENT(inherit) */ - token = parserutils_vector_peek(vector, *ctx); - if (token == NULL) { - *ctx = orig_ctx; - return CSS_INVALID; - } - - if (token->type == CSS_TOKEN_IDENT && - (lwc_string_caseless_isequal( - token->idata, c->strings[INHERIT], - &match) == lwc_error_ok && match)) { - parserutils_vector_iterate(vector, ctx); - flags = FLAG_INHERIT; - } else { - error = parse_unit_specifier(c, vector, ctx, UNIT_PX, - &length, &unit); - if (error != CSS_OK) { - *ctx = orig_ctx; - return error; - } - - if (unit & UNIT_ANGLE || unit & UNIT_TIME || unit & UNIT_FREQ) { - *ctx = orig_ctx; - return CSS_INVALID; - } - - /* Negative lengths are invalid */ - if (length < 0) { - *ctx = orig_ctx; - return CSS_INVALID; - } - - value = PADDING_SET; - } - - opv = buildOPV(op, flags, value); - - required_size = sizeof(opv); - if ((flags & FLAG_INHERIT) == false && value == PADDING_SET) - required_size += sizeof(length) + sizeof(unit); - - /* Allocate result */ - error = css_stylesheet_style_create(c->sheet, required_size, result); - if (error != CSS_OK) { - *ctx = orig_ctx; - return error; - } - - /* Copy the bytecode to it */ - memcpy((*result)->bytecode, &opv, sizeof(opv)); - if ((flags & FLAG_INHERIT) == false && value == PADDING_SET) { - memcpy(((uint8_t *) (*result)->bytecode) + sizeof(opv), - &length, sizeof(length)); - memcpy(((uint8_t *) (*result)->bytecode) + sizeof(opv) + - sizeof(length), &unit, sizeof(unit)); - } - - return CSS_OK; -} - diff --git a/src/parse/properties/padding_bottom.c b/src/parse/properties/padding_bottom.c new file mode 100644 index 0000000..41ba95b --- /dev/null +++ b/src/parse/properties/padding_bottom.c @@ -0,0 +1,36 @@ +/* + * This file is part of LibCSS. + * Licensed under the MIT License, + * http://www.opensource.org/licenses/mit-license.php + * Copyright 2009 John-Mark Bell + */ + +#include +#include + +#include "bytecode/bytecode.h" +#include "bytecode/opcodes.h" +#include "parse/properties/properties.h" +#include "parse/properties/utils.h" + +/** + * Parse padding-bottom + * + * \param c Parsing context + * \param vector Vector of tokens to process + * \param ctx Pointer to vector iteration context + * \param result Pointer to location to receive resulting style + * \return CSS_OK on success, + * CSS_NOMEM on memory exhaustion, + * CSS_INVALID if the input is not valid + * + * Post condition: \a *ctx is updated with the next token to process + * If the input is invalid, then \a *ctx remains unchanged. + */ +css_error parse_padding_bottom(css_language *c, + const parserutils_vector *vector, int *ctx, + css_style **result) +{ + return parse_padding_side(c, vector, ctx, + CSS_PROP_PADDING_BOTTOM, result); +} diff --git a/src/parse/properties/padding_left.c b/src/parse/properties/padding_left.c new file mode 100644 index 0000000..6bb3cd4 --- /dev/null +++ b/src/parse/properties/padding_left.c @@ -0,0 +1,36 @@ +/* + * This file is part of LibCSS. + * Licensed under the MIT License, + * http://www.opensource.org/licenses/mit-license.php + * Copyright 2009 John-Mark Bell + */ + +#include +#include + +#include "bytecode/bytecode.h" +#include "bytecode/opcodes.h" +#include "parse/properties/properties.h" +#include "parse/properties/utils.h" + +/** + * Parse padding-left + * + * \param c Parsing context + * \param vector Vector of tokens to process + * \param ctx Pointer to vector iteration context + * \param result Pointer to location to receive resulting style + * \return CSS_OK on success, + * CSS_NOMEM on memory exhaustion, + * CSS_INVALID if the input is not valid + * + * Post condition: \a *ctx is updated with the next token to process + * If the input is invalid, then \a *ctx remains unchanged. + */ +css_error parse_padding_left(css_language *c, + const parserutils_vector *vector, int *ctx, + css_style **result) +{ + return parse_padding_side(c, vector, ctx, + CSS_PROP_PADDING_LEFT, result); +} diff --git a/src/parse/properties/padding_right.c b/src/parse/properties/padding_right.c new file mode 100644 index 0000000..834e586 --- /dev/null +++ b/src/parse/properties/padding_right.c @@ -0,0 +1,36 @@ +/* + * This file is part of LibCSS. + * Licensed under the MIT License, + * http://www.opensource.org/licenses/mit-license.php + * Copyright 2009 John-Mark Bell + */ + +#include +#include + +#include "bytecode/bytecode.h" +#include "bytecode/opcodes.h" +#include "parse/properties/properties.h" +#include "parse/properties/utils.h" + +/** + * Parse padding-right + * + * \param c Parsing context + * \param vector Vector of tokens to process + * \param ctx Pointer to vector iteration context + * \param result Pointer to location to receive resulting style + * \return CSS_OK on success, + * CSS_NOMEM on memory exhaustion, + * CSS_INVALID if the input is not valid + * + * Post condition: \a *ctx is updated with the next token to process + * If the input is invalid, then \a *ctx remains unchanged. + */ +css_error parse_padding_right(css_language *c, + const parserutils_vector *vector, int *ctx, + css_style **result) +{ + return parse_padding_side(c, vector, ctx, + CSS_PROP_PADDING_RIGHT, result); +} diff --git a/src/parse/properties/padding_top.c b/src/parse/properties/padding_top.c new file mode 100644 index 0000000..c93dd6b --- /dev/null +++ b/src/parse/properties/padding_top.c @@ -0,0 +1,36 @@ +/* + * This file is part of LibCSS. + * Licensed under the MIT License, + * http://www.opensource.org/licenses/mit-license.php + * Copyright 2009 John-Mark Bell + */ + +#include +#include + +#include "bytecode/bytecode.h" +#include "bytecode/opcodes.h" +#include "parse/properties/properties.h" +#include "parse/properties/utils.h" + +/** + * Parse padding-top + * + * \param c Parsing context + * \param vector Vector of tokens to process + * \param ctx Pointer to vector iteration context + * \param result Pointer to location to receive resulting style + * \return CSS_OK on success, + * CSS_NOMEM on memory exhaustion, + * CSS_INVALID if the input is not valid + * + * Post condition: \a *ctx is updated with the next token to process + * If the input is invalid, then \a *ctx remains unchanged. + */ +css_error parse_padding_top(css_language *c, + const parserutils_vector *vector, int *ctx, + css_style **result) +{ + return parse_padding_side(c, vector, ctx, + CSS_PROP_PADDING_TOP, result); +} diff --git a/src/parse/properties/page.c b/src/parse/properties/page.c deleted file mode 100644 index d28ed15..0000000 --- a/src/parse/properties/page.c +++ /dev/null @@ -1,401 +0,0 @@ -/* - * This file is part of LibCSS. - * Licensed under the MIT License, - * http://www.opensource.org/licenses/mit-license.php - * Copyright 2009 John-Mark Bell - */ - -#include - -#include "bytecode/bytecode.h" -#include "bytecode/opcodes.h" -#include "parse/properties/properties.h" -#include "parse/properties/utils.h" - -/** - * Parse orphans - * - * \param c Parsing context - * \param vector Vector of tokens to process - * \param ctx Pointer to vector iteration context - * \param result Pointer to location to receive resulting style - * \return CSS_OK on success, - * CSS_NOMEM on memory exhaustion, - * CSS_INVALID if the input is not valid - * - * Post condition: \a *ctx is updated with the next token to process - * If the input is invalid, then \a *ctx remains unchanged. - */ -css_error parse_orphans(css_language *c, - const parserutils_vector *vector, int *ctx, - css_style **result) -{ - int orig_ctx = *ctx; - css_error error; - const css_token *token; - uint8_t flags = 0; - uint16_t value = 0; - uint32_t opv; - css_fixed num = 0; - uint32_t required_size; - bool match; - - /* | IDENT (inherit) */ - token = parserutils_vector_iterate(vector, ctx); - if (token == NULL || (token->type != CSS_TOKEN_IDENT && - token->type != CSS_TOKEN_NUMBER)) { - *ctx = orig_ctx; - return CSS_INVALID; - } - - if ((lwc_string_caseless_isequal( - token->idata, c->strings[INHERIT], - &match) == lwc_error_ok && match)) { - flags |= FLAG_INHERIT; - } else if (token->type == CSS_TOKEN_NUMBER) { - size_t consumed = 0; - num = number_from_lwc_string(token->idata, true, &consumed); - /* Invalid if there are trailing characters */ - if (consumed != lwc_string_length(token->idata)) { - *ctx = orig_ctx; - return CSS_INVALID; - } - - /* Negative values are nonsensical */ - if (num < 0) { - *ctx = orig_ctx; - return CSS_INVALID; - } - - value = ORPHANS_SET; - } else { - *ctx = orig_ctx; - return CSS_INVALID; - } - - opv = buildOPV(CSS_PROP_ORPHANS, flags, value); - - required_size = sizeof(opv); - if ((flags & FLAG_INHERIT) == false && value == ORPHANS_SET) - required_size += sizeof(num); - - /* Allocate result */ - error = css_stylesheet_style_create(c->sheet, required_size, result); - if (error != CSS_OK) { - *ctx = orig_ctx; - return error; - } - - /* Copy the bytecode to it */ - memcpy((*result)->bytecode, &opv, sizeof(opv)); - if ((flags & FLAG_INHERIT) == false && value == ORPHANS_SET) { - memcpy(((uint8_t *) (*result)->bytecode) + sizeof(opv), - &num, sizeof(num)); - } - - return CSS_OK; -} - -/** - * Parse page-break-after - * - * \param c Parsing context - * \param vector Vector of tokens to process - * \param ctx Pointer to vector iteration context - * \param result Pointer to location to receive resulting style - * \return CSS_OK on success, - * CSS_NOMEM on memory exhaustion, - * CSS_INVALID if the input is not valid - * - * Post condition: \a *ctx is updated with the next token to process - * If the input is invalid, then \a *ctx remains unchanged. - */ -css_error parse_page_break_after(css_language *c, - const parserutils_vector *vector, int *ctx, - css_style **result) -{ - int orig_ctx = *ctx; - css_error error; - const css_token *ident; - uint8_t flags = 0; - uint16_t value = 0; - uint32_t opv; - bool match; - - /* IDENT (auto, always, avoid, left, right, inherit) */ - ident = parserutils_vector_iterate(vector, ctx); - if (ident == NULL || ident->type != CSS_TOKEN_IDENT) { - *ctx = orig_ctx; - return CSS_INVALID; - } - - if ((lwc_string_caseless_isequal( - ident->idata, c->strings[INHERIT], - &match) == lwc_error_ok && match)) { - flags |= FLAG_INHERIT; - } else if ((lwc_string_caseless_isequal( - ident->idata, c->strings[AUTO], - &match) == lwc_error_ok && match)) { - value = PAGE_BREAK_AFTER_AUTO; - } else if ((lwc_string_caseless_isequal( - ident->idata, c->strings[ALWAYS], - &match) == lwc_error_ok && match)) { - value = PAGE_BREAK_AFTER_ALWAYS; - } else if ((lwc_string_caseless_isequal( - ident->idata, c->strings[AVOID], - &match) == lwc_error_ok && match)) { - value = PAGE_BREAK_AFTER_AVOID; - } else if ((lwc_string_caseless_isequal( - ident->idata, c->strings[LEFT], - &match) == lwc_error_ok && match)) { - value = PAGE_BREAK_AFTER_LEFT; - } else if ((lwc_string_caseless_isequal( - ident->idata, c->strings[RIGHT], - &match) == lwc_error_ok && match)) { - value = PAGE_BREAK_AFTER_RIGHT; - } else { - *ctx = orig_ctx; - return CSS_INVALID; - } - - opv = buildOPV(CSS_PROP_PAGE_BREAK_AFTER, flags, value); - - /* Allocate result */ - error = css_stylesheet_style_create(c->sheet, sizeof(opv), result); - if (error != CSS_OK) { - *ctx = orig_ctx; - return error; - } - - /* Copy the bytecode to it */ - memcpy((*result)->bytecode, &opv, sizeof(opv)); - - return CSS_OK; -} - -/** - * Parse page-break-before - * - * \param c Parsing context - * \param vector Vector of tokens to process - * \param ctx Pointer to vector iteration context - * \param result Pointer to location to receive resulting style - * \return CSS_OK on success, - * CSS_NOMEM on memory exhaustion, - * CSS_INVALID if the input is not valid - * - * Post condition: \a *ctx is updated with the next token to process - * If the input is invalid, then \a *ctx remains unchanged. - */ -css_error parse_page_break_before(css_language *c, - const parserutils_vector *vector, int *ctx, - css_style **result) -{ - int orig_ctx = *ctx; - css_error error; - const css_token *ident; - uint8_t flags = 0; - uint16_t value = 0; - uint32_t opv; - bool match; - - /* IDENT (auto, always, avoid, left, right, inherit) */ - ident = parserutils_vector_iterate(vector, ctx); - if (ident == NULL || ident->type != CSS_TOKEN_IDENT) { - *ctx = orig_ctx; - return CSS_INVALID; - } - - if ((lwc_string_caseless_isequal( - ident->idata, c->strings[INHERIT], - &match) == lwc_error_ok && match)) { - flags |= FLAG_INHERIT; - } else if ((lwc_string_caseless_isequal( - ident->idata, c->strings[AUTO], - &match) == lwc_error_ok && match)) { - value = PAGE_BREAK_BEFORE_AUTO; - } else if ((lwc_string_caseless_isequal( - ident->idata, c->strings[ALWAYS], - &match) == lwc_error_ok && match)) { - value = PAGE_BREAK_BEFORE_ALWAYS; - } else if ((lwc_string_caseless_isequal( - ident->idata, c->strings[AVOID], - &match) == lwc_error_ok && match)) { - value = PAGE_BREAK_BEFORE_AVOID; - } else if ((lwc_string_caseless_isequal( - ident->idata, c->strings[LEFT], - &match) == lwc_error_ok && match)) { - value = PAGE_BREAK_BEFORE_LEFT; - } else if ((lwc_string_caseless_isequal( - ident->idata, c->strings[RIGHT], - &match) == lwc_error_ok && match)) { - value = PAGE_BREAK_BEFORE_RIGHT; - } else { - *ctx = orig_ctx; - return CSS_INVALID; - } - - opv = buildOPV(CSS_PROP_PAGE_BREAK_BEFORE, flags, value); - - /* Allocate result */ - error = css_stylesheet_style_create(c->sheet, sizeof(opv), result); - if (error != CSS_OK) { - *ctx = orig_ctx; - return error; - } - - /* Copy the bytecode to it */ - memcpy((*result)->bytecode, &opv, sizeof(opv)); - - return CSS_OK; -} - -/** - * Parse page-break-inside - * - * \param c Parsing context - * \param vector Vector of tokens to process - * \param ctx Pointer to vector iteration context - * \param result Pointer to location to receive resulting style - * \return CSS_OK on success, - * CSS_NOMEM on memory exhaustion, - * CSS_INVALID if the input is not valid - * - * Post condition: \a *ctx is updated with the next token to process - * If the input is invalid, then \a *ctx remains unchanged. - */ -css_error parse_page_break_inside(css_language *c, - const parserutils_vector *vector, int *ctx, - css_style **result) -{ - int orig_ctx = *ctx; - css_error error; - const css_token *ident; - uint8_t flags = 0; - uint16_t value = 0; - uint32_t opv; - bool match; - - /* IDENT (auto, avoid, inherit) */ - ident = parserutils_vector_iterate(vector, ctx); - if (ident == NULL || ident->type != CSS_TOKEN_IDENT) { - *ctx = orig_ctx; - return CSS_INVALID; - } - - if ((lwc_string_caseless_isequal( - ident->idata, c->strings[INHERIT], - &match) == lwc_error_ok && match)) { - flags |= FLAG_INHERIT; - } else if ((lwc_string_caseless_isequal( - ident->idata, c->strings[AUTO], - &match) == lwc_error_ok && match)) { - value = PAGE_BREAK_INSIDE_AUTO; - } else if ((lwc_string_caseless_isequal( - ident->idata, c->strings[AVOID], - &match) == lwc_error_ok && match)) { - value = PAGE_BREAK_INSIDE_AVOID; - } else { - *ctx = orig_ctx; - return CSS_INVALID; - } - - opv = buildOPV(CSS_PROP_PAGE_BREAK_INSIDE, flags, value); - - /* Allocate result */ - error = css_stylesheet_style_create(c->sheet, sizeof(opv), result); - if (error != CSS_OK) { - *ctx = orig_ctx; - return error; - } - - /* Copy the bytecode to it */ - memcpy((*result)->bytecode, &opv, sizeof(opv)); - - return CSS_OK; -} - -/** - * Parse widows - * - * \param c Parsing context - * \param vector Vector of tokens to process - * \param ctx Pointer to vector iteration context - * \param result Pointer to location to receive resulting style - * \return CSS_OK on success, - * CSS_NOMEM on memory exhaustion, - * CSS_INVALID if the input is not valid - * - * Post condition: \a *ctx is updated with the next token to process - * If the input is invalid, then \a *ctx remains unchanged. - */ -css_error parse_widows(css_language *c, - const parserutils_vector *vector, int *ctx, - css_style **result) -{ - int orig_ctx = *ctx; - css_error error; - const css_token *token; - uint8_t flags = 0; - uint16_t value = 0; - uint32_t opv; - css_fixed num = 0; - uint32_t required_size; - bool match; - - /* | IDENT (inherit) */ - token = parserutils_vector_iterate(vector, ctx); - if (token == NULL || (token->type != CSS_TOKEN_IDENT && - token->type != CSS_TOKEN_NUMBER)) { - *ctx = orig_ctx; - return CSS_INVALID; - } - - if ((lwc_string_caseless_isequal( - token->idata, c->strings[INHERIT], - &match) == lwc_error_ok && match)) { - flags |= FLAG_INHERIT; - } else if (token->type == CSS_TOKEN_NUMBER) { - size_t consumed = 0; - num = number_from_lwc_string(token->idata, true, &consumed); - /* Invalid if there are trailing characters */ - if (consumed != lwc_string_length(token->idata)) { - *ctx = orig_ctx; - return CSS_INVALID; - } - - /* Negative values are nonsensical */ - if (num < 0) { - *ctx = orig_ctx; - return CSS_INVALID; - } - - value = WIDOWS_SET; - } else { - *ctx = orig_ctx; - return CSS_INVALID; - } - - opv = buildOPV(CSS_PROP_WIDOWS, flags, value); - - required_size = sizeof(opv); - if ((flags & FLAG_INHERIT) == false && value == WIDOWS_SET) - required_size += sizeof(num); - - /* Allocate result */ - error = css_stylesheet_style_create(c->sheet, required_size, result); - if (error != CSS_OK) { - *ctx = orig_ctx; - return error; - } - - /* Copy the bytecode to it */ - memcpy((*result)->bytecode, &opv, sizeof(opv)); - if ((flags & FLAG_INHERIT) == false && value == WIDOWS_SET) { - memcpy(((uint8_t *) (*result)->bytecode) + sizeof(opv), - &num, sizeof(num)); - } - - return CSS_OK; -} - diff --git a/src/parse/properties/page_break_after.c b/src/parse/properties/page_break_after.c new file mode 100644 index 0000000..8b6fc79 --- /dev/null +++ b/src/parse/properties/page_break_after.c @@ -0,0 +1,91 @@ +/* + * This file is part of LibCSS. + * Licensed under the MIT License, + * http://www.opensource.org/licenses/mit-license.php + * Copyright 2009 John-Mark Bell + */ + +#include +#include + +#include "bytecode/bytecode.h" +#include "bytecode/opcodes.h" +#include "parse/properties/properties.h" +#include "parse/properties/utils.h" + +/** + * Parse page-break-after + * + * \param c Parsing context + * \param vector Vector of tokens to process + * \param ctx Pointer to vector iteration context + * \param result Pointer to location to receive resulting style + * \return CSS_OK on success, + * CSS_NOMEM on memory exhaustion, + * CSS_INVALID if the input is not valid + * + * Post condition: \a *ctx is updated with the next token to process + * If the input is invalid, then \a *ctx remains unchanged. + */ +css_error parse_page_break_after(css_language *c, + const parserutils_vector *vector, int *ctx, + css_style **result) +{ + int orig_ctx = *ctx; + css_error error; + const css_token *ident; + uint8_t flags = 0; + uint16_t value = 0; + uint32_t opv; + bool match; + + /* IDENT (auto, always, avoid, left, right, inherit) */ + ident = parserutils_vector_iterate(vector, ctx); + if (ident == NULL || ident->type != CSS_TOKEN_IDENT) { + *ctx = orig_ctx; + return CSS_INVALID; + } + + if ((lwc_string_caseless_isequal( + ident->idata, c->strings[INHERIT], + &match) == lwc_error_ok && match)) { + flags |= FLAG_INHERIT; + } else if ((lwc_string_caseless_isequal( + ident->idata, c->strings[AUTO], + &match) == lwc_error_ok && match)) { + value = PAGE_BREAK_AFTER_AUTO; + } else if ((lwc_string_caseless_isequal( + ident->idata, c->strings[ALWAYS], + &match) == lwc_error_ok && match)) { + value = PAGE_BREAK_AFTER_ALWAYS; + } else if ((lwc_string_caseless_isequal( + ident->idata, c->strings[AVOID], + &match) == lwc_error_ok && match)) { + value = PAGE_BREAK_AFTER_AVOID; + } else if ((lwc_string_caseless_isequal( + ident->idata, c->strings[LEFT], + &match) == lwc_error_ok && match)) { + value = PAGE_BREAK_AFTER_LEFT; + } else if ((lwc_string_caseless_isequal( + ident->idata, c->strings[RIGHT], + &match) == lwc_error_ok && match)) { + value = PAGE_BREAK_AFTER_RIGHT; + } else { + *ctx = orig_ctx; + return CSS_INVALID; + } + + opv = buildOPV(CSS_PROP_PAGE_BREAK_AFTER, flags, value); + + /* Allocate result */ + error = css_stylesheet_style_create(c->sheet, sizeof(opv), result); + if (error != CSS_OK) { + *ctx = orig_ctx; + return error; + } + + /* Copy the bytecode to it */ + memcpy((*result)->bytecode, &opv, sizeof(opv)); + + return CSS_OK; +} diff --git a/src/parse/properties/page_break_before.c b/src/parse/properties/page_break_before.c new file mode 100644 index 0000000..515412d --- /dev/null +++ b/src/parse/properties/page_break_before.c @@ -0,0 +1,91 @@ +/* + * This file is part of LibCSS. + * Licensed under the MIT License, + * http://www.opensource.org/licenses/mit-license.php + * Copyright 2009 John-Mark Bell + */ + +#include +#include + +#include "bytecode/bytecode.h" +#include "bytecode/opcodes.h" +#include "parse/properties/properties.h" +#include "parse/properties/utils.h" + +/** + * Parse page-break-before + * + * \param c Parsing context + * \param vector Vector of tokens to process + * \param ctx Pointer to vector iteration context + * \param result Pointer to location to receive resulting style + * \return CSS_OK on success, + * CSS_NOMEM on memory exhaustion, + * CSS_INVALID if the input is not valid + * + * Post condition: \a *ctx is updated with the next token to process + * If the input is invalid, then \a *ctx remains unchanged. + */ +css_error parse_page_break_before(css_language *c, + const parserutils_vector *vector, int *ctx, + css_style **result) +{ + int orig_ctx = *ctx; + css_error error; + const css_token *ident; + uint8_t flags = 0; + uint16_t value = 0; + uint32_t opv; + bool match; + + /* IDENT (auto, always, avoid, left, right, inherit) */ + ident = parserutils_vector_iterate(vector, ctx); + if (ident == NULL || ident->type != CSS_TOKEN_IDENT) { + *ctx = orig_ctx; + return CSS_INVALID; + } + + if ((lwc_string_caseless_isequal( + ident->idata, c->strings[INHERIT], + &match) == lwc_error_ok && match)) { + flags |= FLAG_INHERIT; + } else if ((lwc_string_caseless_isequal( + ident->idata, c->strings[AUTO], + &match) == lwc_error_ok && match)) { + value = PAGE_BREAK_BEFORE_AUTO; + } else if ((lwc_string_caseless_isequal( + ident->idata, c->strings[ALWAYS], + &match) == lwc_error_ok && match)) { + value = PAGE_BREAK_BEFORE_ALWAYS; + } else if ((lwc_string_caseless_isequal( + ident->idata, c->strings[AVOID], + &match) == lwc_error_ok && match)) { + value = PAGE_BREAK_BEFORE_AVOID; + } else if ((lwc_string_caseless_isequal( + ident->idata, c->strings[LEFT], + &match) == lwc_error_ok && match)) { + value = PAGE_BREAK_BEFORE_LEFT; + } else if ((lwc_string_caseless_isequal( + ident->idata, c->strings[RIGHT], + &match) == lwc_error_ok && match)) { + value = PAGE_BREAK_BEFORE_RIGHT; + } else { + *ctx = orig_ctx; + return CSS_INVALID; + } + + opv = buildOPV(CSS_PROP_PAGE_BREAK_BEFORE, flags, value); + + /* Allocate result */ + error = css_stylesheet_style_create(c->sheet, sizeof(opv), result); + if (error != CSS_OK) { + *ctx = orig_ctx; + return error; + } + + /* Copy the bytecode to it */ + memcpy((*result)->bytecode, &opv, sizeof(opv)); + + return CSS_OK; +} diff --git a/src/parse/properties/page_break_inside.c b/src/parse/properties/page_break_inside.c new file mode 100644 index 0000000..0d11a19 --- /dev/null +++ b/src/parse/properties/page_break_inside.c @@ -0,0 +1,79 @@ +/* + * This file is part of LibCSS. + * Licensed under the MIT License, + * http://www.opensource.org/licenses/mit-license.php + * Copyright 2009 John-Mark Bell + */ + +#include +#include + +#include "bytecode/bytecode.h" +#include "bytecode/opcodes.h" +#include "parse/properties/properties.h" +#include "parse/properties/utils.h" + +/** + * Parse page-break-inside + * + * \param c Parsing context + * \param vector Vector of tokens to process + * \param ctx Pointer to vector iteration context + * \param result Pointer to location to receive resulting style + * \return CSS_OK on success, + * CSS_NOMEM on memory exhaustion, + * CSS_INVALID if the input is not valid + * + * Post condition: \a *ctx is updated with the next token to process + * If the input is invalid, then \a *ctx remains unchanged. + */ +css_error parse_page_break_inside(css_language *c, + const parserutils_vector *vector, int *ctx, + css_style **result) +{ + int orig_ctx = *ctx; + css_error error; + const css_token *ident; + uint8_t flags = 0; + uint16_t value = 0; + uint32_t opv; + bool match; + + /* IDENT (auto, avoid, inherit) */ + ident = parserutils_vector_iterate(vector, ctx); + if (ident == NULL || ident->type != CSS_TOKEN_IDENT) { + *ctx = orig_ctx; + return CSS_INVALID; + } + + if ((lwc_string_caseless_isequal( + ident->idata, c->strings[INHERIT], + &match) == lwc_error_ok && match)) { + flags |= FLAG_INHERIT; + } else if ((lwc_string_caseless_isequal( + ident->idata, c->strings[AUTO], + &match) == lwc_error_ok && match)) { + value = PAGE_BREAK_INSIDE_AUTO; + } else if ((lwc_string_caseless_isequal( + ident->idata, c->strings[AVOID], + &match) == lwc_error_ok && match)) { + value = PAGE_BREAK_INSIDE_AVOID; + } else { + *ctx = orig_ctx; + return CSS_INVALID; + } + + opv = buildOPV(CSS_PROP_PAGE_BREAK_INSIDE, flags, value); + + /* Allocate result */ + error = css_stylesheet_style_create(c->sheet, sizeof(opv), result); + if (error != CSS_OK) { + *ctx = orig_ctx; + return error; + } + + /* Copy the bytecode to it */ + memcpy((*result)->bytecode, &opv, sizeof(opv)); + + return CSS_OK; +} diff --git a/src/parse/properties/pause.c b/src/parse/properties/pause.c new file mode 100644 index 0000000..82a199e --- /dev/null +++ b/src/parse/properties/pause.c @@ -0,0 +1,172 @@ +/* + * This file is part of LibCSS. + * Licensed under the MIT License, + * http://www.opensource.org/licenses/mit-license.php + * Copyright 2009 John-Mark Bell + */ + +#include +#include + +#include "bytecode/bytecode.h" +#include "bytecode/opcodes.h" +#include "parse/properties/properties.h" +#include "parse/properties/utils.h" + +/** + * Parse pause shorthand + * + * \param c Parsing context + * \param vector Vector of tokens to process + * \param ctx Pointer to vector iteration context + * \param result Pointer to location to receive resulting style + * \return CSS_OK on success, + * CSS_NOMEM on memory exhaustion, + * CSS_INVALID if the input is not valid + * + * Post condition: \a *ctx is updated with the next token to process + * If the input is invalid, then \a *ctx remains unchanged. + */ +css_error parse_pause(css_language *c, + const parserutils_vector *vector, int *ctx, + css_style **result) +{ + int orig_ctx = *ctx; + const css_token *token; + css_style *before = NULL; + css_style *after = NULL; + css_style *ret = NULL; + int num_read = 0; + int prev_ctx; + uint32_t required_size; + bool match; + css_error error; + + /* Deal with inherit */ + token = parserutils_vector_peek(vector, *ctx); + if (token != NULL && token->type == CSS_TOKEN_IDENT && + (lwc_string_caseless_isequal( + token->idata, c->strings[INHERIT], + &match) == lwc_error_ok && match)) { + uint32_t *bytecode; + + error = css_stylesheet_style_create(c->sheet, + 2 * sizeof(uint32_t), &ret); + if (error != CSS_OK) { + *ctx = orig_ctx; + return error; + } + + bytecode = (uint32_t *) ret->bytecode; + + *(bytecode++) = buildOPV(CSS_PROP_PAUSE_BEFORE, + FLAG_INHERIT, 0); + *(bytecode++) = buildOPV(CSS_PROP_PAUSE_AFTER, + FLAG_INHERIT, 0); + + parserutils_vector_iterate(vector, ctx); + + *result = ret; + + return CSS_OK; + } else if (token == NULL) { + /* No tokens -- clearly garbage */ + *ctx = orig_ctx; + return CSS_INVALID; + } + + /* Attempt to read 1 or 2 pauses */ + do { + prev_ctx = *ctx; + error = CSS_OK; + + /* Ensure that we're not about to parse another inherit */ + token = parserutils_vector_peek(vector, *ctx); + if (token != NULL && token->type == CSS_TOKEN_IDENT && + (lwc_string_caseless_isequal( + token->idata, c->strings[INHERIT], + &match) == lwc_error_ok && match)) { + error = CSS_INVALID; + goto cleanup; + } + + if (before == NULL && (error = parse_pause_before(c, vector, + ctx, &before)) == CSS_OK) { + num_read = 1; + } else if (after == NULL && + (error = parse_pause_after(c, vector, ctx, + &after)) == CSS_OK) { + num_read = 2; + } + + if (error == CSS_OK) { + consumeWhitespace(vector, ctx); + + token = parserutils_vector_peek(vector, *ctx); + } else { + token = NULL; + } + } while (*ctx != prev_ctx && token != NULL); + + if (num_read == 0) { + error = CSS_INVALID; + goto cleanup; + } + + /* Calculate size of resultant style */ + if (num_read == 1) + required_size = 2 * before->length; + else + required_size = before->length + after->length; + + error = css_stylesheet_style_create(c->sheet, required_size, &ret); + if (error != CSS_OK) + goto cleanup; + + required_size = 0; + + if (num_read == 1) { + uint32_t *opv = ((uint32_t *) before->bytecode); + uint8_t flags = getFlags(*opv); + uint16_t value = getValue(*opv); + + memcpy(((uint8_t *) ret->bytecode) + required_size, + before->bytecode, before->length); + required_size += before->length; + + *opv = buildOPV(CSS_PROP_PAUSE_AFTER, flags, value); + memcpy(((uint8_t *) ret->bytecode) + required_size, + before->bytecode, before->length); + required_size += before->length; + } else { + memcpy(((uint8_t *) ret->bytecode) + required_size, + before->bytecode, before->length); + required_size += before->length; + + memcpy(((uint8_t *) ret->bytecode) + required_size, + after->bytecode, after->length); + required_size += after->length; + } + + assert(required_size == ret->length); + + /* Write the result */ + *result = ret; + /* Invalidate ret so that cleanup doesn't destroy it */ + ret = NULL; + + /* Clean up after ourselves */ +cleanup: + if (before) + css_stylesheet_style_destroy(c->sheet, before, error == CSS_OK); + if (after) + css_stylesheet_style_destroy(c->sheet, after, error == CSS_OK); + if (ret) + css_stylesheet_style_destroy(c->sheet, ret, error == CSS_OK); + + if (error != CSS_OK) + *ctx = orig_ctx; + + return error; +} + diff --git a/src/parse/properties/pause_after.c b/src/parse/properties/pause_after.c new file mode 100644 index 0000000..a627440 --- /dev/null +++ b/src/parse/properties/pause_after.c @@ -0,0 +1,35 @@ +/* + * This file is part of LibCSS. + * Licensed under the MIT License, + * http://www.opensource.org/licenses/mit-license.php + * Copyright 2009 John-Mark Bell + */ + +#include +#include + +#include "bytecode/bytecode.h" +#include "bytecode/opcodes.h" +#include "parse/properties/properties.h" +#include "parse/properties/utils.h" + +/** + * Parse pause-after + * + * \param c Parsing context + * \param vector Vector of tokens to process + * \param ctx Pointer to vector iteration context + * \param result Pointer to location to receive resulting style + * \return CSS_OK on success, + * CSS_NOMEM on memory exhaustion, + * CSS_INVALID if the input is not valid + * + * Post condition: \a *ctx is updated with the next token to process + * If the input is invalid, then \a *ctx remains unchanged. + */ +css_error parse_pause_after(css_language *c, + const parserutils_vector *vector, int *ctx, + css_style **result) +{ + return parse_pause_common(c, vector, ctx, CSS_PROP_PAUSE_AFTER, result); +} diff --git a/src/parse/properties/pause_before.c b/src/parse/properties/pause_before.c new file mode 100644 index 0000000..0ced812 --- /dev/null +++ b/src/parse/properties/pause_before.c @@ -0,0 +1,36 @@ +/* + * This file is part of LibCSS. + * Licensed under the MIT License, + * http://www.opensource.org/licenses/mit-license.php + * Copyright 2009 John-Mark Bell + */ + +#include +#include + +#include "bytecode/bytecode.h" +#include "bytecode/opcodes.h" +#include "parse/properties/properties.h" +#include "parse/properties/utils.h" + +/** + * Parse pause-before + * + * \param c Parsing context + * \param vector Vector of tokens to process + * \param ctx Pointer to vector iteration context + * \param result Pointer to location to receive resulting style + * \return CSS_OK on success, + * CSS_NOMEM on memory exhaustion, + * CSS_INVALID if the input is not valid + * + * Post condition: \a *ctx is updated with the next token to process + * If the input is invalid, then \a *ctx remains unchanged. + */ +css_error parse_pause_before(css_language *c, + const parserutils_vector *vector, int *ctx, + css_style **result) +{ + return parse_pause_common(c, vector, ctx, + CSS_PROP_PAUSE_BEFORE, result); +} diff --git a/src/parse/properties/pitch.c b/src/parse/properties/pitch.c new file mode 100644 index 0000000..f821adb --- /dev/null +++ b/src/parse/properties/pitch.c @@ -0,0 +1,133 @@ +/* + * This file is part of LibCSS. + * Licensed under the MIT License, + * http://www.opensource.org/licenses/mit-license.php + * Copyright 2009 John-Mark Bell + */ + +#include +#include + +#include "bytecode/bytecode.h" +#include "bytecode/opcodes.h" +#include "parse/properties/properties.h" +#include "parse/properties/utils.h" + +/** + * Parse pitch + * + * \param c Parsing context + * \param vector Vector of tokens to process + * \param ctx Pointer to vector iteration context + * \param result Pointer to location to receive resulting style + * \return CSS_OK on success, + * CSS_NOMEM on memory exhaustion, + * CSS_INVALID if the input is not valid + * + * Post condition: \a *ctx is updated with the next token to process + * If the input is invalid, then \a *ctx remains unchanged. + */ +css_error parse_pitch(css_language *c, + const parserutils_vector *vector, int *ctx, + css_style **result) +{ + int orig_ctx = *ctx; + css_error error; + const css_token *token; + uint8_t flags = 0; + uint16_t value = 0; + uint32_t opv; + css_fixed length = 0; + uint32_t unit = 0; + uint32_t required_size; + bool match; + + /* frequency | IDENT(x-low, low, medium, high, x-high, inherit) */ + token = parserutils_vector_peek(vector, *ctx); + if (token == NULL) { + *ctx = orig_ctx; + return CSS_INVALID; + } + + if (token->type == CSS_TOKEN_IDENT && + (lwc_string_caseless_isequal( + token->idata, c->strings[INHERIT], + &match) == lwc_error_ok && match)) { + parserutils_vector_iterate(vector, ctx); + flags = FLAG_INHERIT; + } else if (token->type == CSS_TOKEN_IDENT && + (lwc_string_caseless_isequal( + token->idata, c->strings[X_LOW], + &match) == lwc_error_ok && match)) { + parserutils_vector_iterate(vector, ctx); + value = PITCH_X_LOW; + } else if (token->type == CSS_TOKEN_IDENT && + (lwc_string_caseless_isequal( + token->idata, c->strings[LOW], + &match) == lwc_error_ok && match)) { + parserutils_vector_iterate(vector, ctx); + value = PITCH_LOW; + } else if (token->type == CSS_TOKEN_IDENT && + (lwc_string_caseless_isequal( + token->idata, c->strings[MEDIUM], + &match) == lwc_error_ok && match)) { + parserutils_vector_iterate(vector, ctx); + value = PITCH_MEDIUM; + } else if (token->type == CSS_TOKEN_IDENT && + (lwc_string_caseless_isequal( + token->idata, c->strings[HIGH], + &match) == lwc_error_ok && match)) { + parserutils_vector_iterate(vector, ctx); + value = PITCH_HIGH; + } else if (token->type == CSS_TOKEN_IDENT && + (lwc_string_caseless_isequal( + token->idata, c->strings[X_HIGH], + &match) == lwc_error_ok && match)) { + parserutils_vector_iterate(vector, ctx); + value = PITCH_X_HIGH; + } else { + error = parse_unit_specifier(c, vector, ctx, UNIT_HZ, + &length, &unit); + if (error != CSS_OK) { + *ctx = orig_ctx; + return error; + } + + if ((unit & UNIT_FREQ) == false) { + *ctx = orig_ctx; + return CSS_INVALID; + } + + /* Negative values are invalid */ + if (length < 0) { + *ctx = orig_ctx; + return CSS_INVALID; + } + + value = PITCH_FREQUENCY; + } + + opv = buildOPV(CSS_PROP_PITCH, flags, value); + + required_size = sizeof(opv); + if ((flags & FLAG_INHERIT) == false && value == PITCH_FREQUENCY) + required_size += sizeof(length) + sizeof(unit); + + /* Allocate result */ + error = css_stylesheet_style_create(c->sheet, required_size, result); + if (error != CSS_OK) { + *ctx = orig_ctx; + return error; + } + + /* Copy the bytecode to it */ + memcpy((*result)->bytecode, &opv, sizeof(opv)); + if ((flags & FLAG_INHERIT) == false && value == PITCH_FREQUENCY) { + memcpy(((uint8_t *) (*result)->bytecode) + sizeof(opv), + &length, sizeof(length)); + memcpy(((uint8_t *) (*result)->bytecode) + sizeof(opv) + + sizeof(length), &unit, sizeof(unit)); + } + + return CSS_OK; +} diff --git a/src/parse/properties/pitch_range.c b/src/parse/properties/pitch_range.c new file mode 100644 index 0000000..1c3e590 --- /dev/null +++ b/src/parse/properties/pitch_range.c @@ -0,0 +1,98 @@ +/* + * This file is part of LibCSS. + * Licensed under the MIT License, + * http://www.opensource.org/licenses/mit-license.php + * Copyright 2009 John-Mark Bell + */ + +#include +#include + +#include "bytecode/bytecode.h" +#include "bytecode/opcodes.h" +#include "parse/properties/properties.h" +#include "parse/properties/utils.h" + +/** + * Parse pitch-range + * + * \param c Parsing context + * \param vector Vector of tokens to process + * \param ctx Pointer to vector iteration context + * \param result Pointer to location to receive resulting style + * \return CSS_OK on success, + * CSS_NOMEM on memory exhaustion, + * CSS_INVALID if the input is not valid + * + * Post condition: \a *ctx is updated with the next token to process + * If the input is invalid, then \a *ctx remains unchanged. + */ +css_error parse_pitch_range(css_language *c, + const parserutils_vector *vector, int *ctx, + css_style **result) +{ + int orig_ctx = *ctx; + css_error error; + const css_token *token; + uint8_t flags = 0; + uint16_t value = 0; + uint32_t opv; + css_fixed num = 0; + uint32_t required_size; + bool match; + + /* number | IDENT (inherit) */ + token = parserutils_vector_iterate(vector, ctx); + if (token == NULL || (token->type != CSS_TOKEN_IDENT && + token->type != CSS_TOKEN_NUMBER)) { + *ctx = orig_ctx; + return CSS_INVALID; + } + + if ((lwc_string_caseless_isequal( + token->idata, c->strings[INHERIT], + &match) == lwc_error_ok && match)) { + flags |= FLAG_INHERIT; + } else if (token->type == CSS_TOKEN_NUMBER) { + size_t consumed = 0; + num = number_from_lwc_string(token->idata, false, &consumed); + /* Invalid if there are trailing characters */ + if (consumed != lwc_string_length(token->idata)) { + *ctx = orig_ctx; + return CSS_INVALID; + } + + /* Must be between 0 and 100 */ + if (num < 0 || num > F_100) { + *ctx = orig_ctx; + return CSS_INVALID; + } + + value = PITCH_RANGE_SET; + } else { + *ctx = orig_ctx; + return CSS_INVALID; + } + + opv = buildOPV(CSS_PROP_PITCH_RANGE, flags, value); + + required_size = sizeof(opv); + if ((flags & FLAG_INHERIT) == false && value == PITCH_RANGE_SET) + required_size += sizeof(num); + + /* Allocate result */ + error = css_stylesheet_style_create(c->sheet, required_size, result); + if (error != CSS_OK) { + *ctx = orig_ctx; + return error; + } + + /* Copy the bytecode to it */ + memcpy((*result)->bytecode, &opv, sizeof(opv)); + if ((flags & FLAG_INHERIT) == false && value == PITCH_RANGE_SET) { + memcpy(((uint8_t *) (*result)->bytecode) + sizeof(opv), + &num, sizeof(num)); + } + + return CSS_OK; +} diff --git a/src/parse/properties/play_during.c b/src/parse/properties/play_during.c new file mode 100644 index 0000000..f4b0ba4 --- /dev/null +++ b/src/parse/properties/play_during.c @@ -0,0 +1,142 @@ +/* + * This file is part of LibCSS. + * Licensed under the MIT License, + * http://www.opensource.org/licenses/mit-license.php + * Copyright 2009 John-Mark Bell + */ + +#include +#include + +#include "bytecode/bytecode.h" +#include "bytecode/opcodes.h" +#include "parse/properties/properties.h" +#include "parse/properties/utils.h" + +/** + * Parse play-during + * + * \param c Parsing context + * \param vector Vector of tokens to process + * \param ctx Pointer to vector iteration context + * \param result Pointer to location to receive resulting style + * \return CSS_OK on success, + * CSS_NOMEM on memory exhaustion, + * CSS_INVALID if the input is not valid + * + * Post condition: \a *ctx is updated with the next token to process + * If the input is invalid, then \a *ctx remains unchanged. + */ +css_error parse_play_during(css_language *c, + const parserutils_vector *vector, int *ctx, + css_style **result) +{ + int orig_ctx = *ctx; + css_error error; + const css_token *token; + uint8_t flags = 0; + uint16_t value = 0; + uint32_t opv; + uint32_t required_size; + lwc_string *uri; + bool match; + + /* URI [ IDENT(mix) || IDENT(repeat) ]? | IDENT(auto,none,inherit) */ + token = parserutils_vector_iterate(vector, ctx); + if (token == NULL || (token->type != CSS_TOKEN_IDENT && + token->type != CSS_TOKEN_URI)) { + *ctx = orig_ctx; + return CSS_INVALID; + } + + if (token->type == CSS_TOKEN_IDENT) { + if ((lwc_string_caseless_isequal( + token->idata, c->strings[INHERIT], + &match) == lwc_error_ok && match)) { + flags |= FLAG_INHERIT; + } else if ((lwc_string_caseless_isequal( + token->idata, c->strings[NONE], + &match) == lwc_error_ok && match)) { + value = PLAY_DURING_NONE; + } else if ((lwc_string_caseless_isequal( + token->idata, c->strings[AUTO], + &match) == lwc_error_ok && match)) { + value = PLAY_DURING_AUTO; + } else { + *ctx = orig_ctx; + return CSS_INVALID; + } + } else { + int modifiers; + + value = PLAY_DURING_URI; + + error = c->sheet->resolve(c->sheet->resolve_pw, + c->sheet->url, + token->idata, &uri); + if (error != CSS_OK) { + *ctx = orig_ctx; + return error; + } + + for (modifiers = 0; modifiers < 2; modifiers++) { + consumeWhitespace(vector, ctx); + + token = parserutils_vector_peek(vector, *ctx); + if (token != NULL && token->type == CSS_TOKEN_IDENT) { + if ((lwc_string_caseless_isequal( + token->idata, c->strings[MIX], + &match) == lwc_error_ok && + match)) { + if ((value & PLAY_DURING_MIX) == 0) + value |= PLAY_DURING_MIX; + else { + *ctx = orig_ctx; + return CSS_INVALID; + } + } else if (lwc_string_caseless_isequal( + token->idata, + c->strings[REPEAT], + &match) == lwc_error_ok && + match) { + if ((value & PLAY_DURING_REPEAT) == 0) + value |= PLAY_DURING_REPEAT; + else { + *ctx = orig_ctx; + return CSS_INVALID; + } + } else { + *ctx = orig_ctx; + return CSS_INVALID; + } + + parserutils_vector_iterate(vector, ctx); + } + } + } + + opv = buildOPV(CSS_PROP_PLAY_DURING, flags, value); + + required_size = sizeof(opv); + if ((flags & FLAG_INHERIT) == false && + (value & PLAY_DURING_TYPE_MASK) == PLAY_DURING_URI) + required_size += sizeof(lwc_string *); + + /* Allocate result */ + error = css_stylesheet_style_create(c->sheet, required_size, result); + if (error != CSS_OK) { + *ctx = orig_ctx; + return error; + } + + /* Copy the bytecode to it */ + memcpy((*result)->bytecode, &opv, sizeof(opv)); + if ((flags & FLAG_INHERIT) == false && + (value & PLAY_DURING_TYPE_MASK) == PLAY_DURING_URI) { + /* Don't ref URI -- we want to pass ownership to the bytecode */ + memcpy((uint8_t *) (*result)->bytecode + sizeof(opv), + &uri, sizeof(lwc_string *)); + } + + return CSS_OK; +} diff --git a/src/parse/properties/position.c b/src/parse/properties/position.c new file mode 100644 index 0000000..563f0bd --- /dev/null +++ b/src/parse/properties/position.c @@ -0,0 +1,87 @@ +/* + * This file is part of LibCSS. + * Licensed under the MIT License, + * http://www.opensource.org/licenses/mit-license.php + * Copyright 2009 John-Mark Bell + */ + +#include +#include + +#include "bytecode/bytecode.h" +#include "bytecode/opcodes.h" +#include "parse/properties/properties.h" +#include "parse/properties/utils.h" + +/** + * Parse position + * + * \param c Parsing context + * \param vector Vector of tokens to process + * \param ctx Pointer to vector iteration context + * \param result Pointer to location to receive resulting style + * \return CSS_OK on success, + * CSS_NOMEM on memory exhaustion, + * CSS_INVALID if the input is not valid + * + * Post condition: \a *ctx is updated with the next token to process + * If the input is invalid, then \a *ctx remains unchanged. + */ +css_error parse_position(css_language *c, + const parserutils_vector *vector, int *ctx, + css_style **result) +{ + int orig_ctx = *ctx; + css_error error; + const css_token *ident; + uint8_t flags = 0; + uint16_t value = 0; + uint32_t opv; + bool match; + + /* IDENT (static, relative, absolute, fixed, inherit) */ + ident = parserutils_vector_iterate(vector, ctx); + if (ident == NULL || ident->type != CSS_TOKEN_IDENT) { + *ctx = orig_ctx; + return CSS_INVALID; + } + + if ((lwc_string_caseless_isequal( + ident->idata, c->strings[INHERIT], + &match) == lwc_error_ok && match)) { + flags |= FLAG_INHERIT; + } else if ((lwc_string_caseless_isequal( + ident->idata, c->strings[LIBCSS_STATIC], + &match) == lwc_error_ok && match)) { + value = POSITION_STATIC; + } else if ((lwc_string_caseless_isequal( + ident->idata, c->strings[RELATIVE], + &match) == lwc_error_ok && match)) { + value = POSITION_RELATIVE; + } else if ((lwc_string_caseless_isequal( + ident->idata, c->strings[ABSOLUTE], + &match) == lwc_error_ok && match)) { + value = POSITION_ABSOLUTE; + } else if ((lwc_string_caseless_isequal( + ident->idata, c->strings[FIXED], + &match) == lwc_error_ok && match)) { + value = POSITION_FIXED; + } else { + *ctx = orig_ctx; + return CSS_INVALID; + } + + opv = buildOPV(CSS_PROP_POSITION, flags, value); + + /* Allocate result */ + error = css_stylesheet_style_create(c->sheet, sizeof(opv), result); + if (error != CSS_OK) { + *ctx = orig_ctx; + return error; + } + + /* Copy the bytecode to it */ + memcpy((*result)->bytecode, &opv, sizeof(opv)); + + return CSS_OK; +} diff --git a/src/parse/properties/positioning.c b/src/parse/properties/positioning.c deleted file mode 100644 index 9e5ac73..0000000 --- a/src/parse/properties/positioning.c +++ /dev/null @@ -1,540 +0,0 @@ -/* - * This file is part of LibCSS. - * Licensed under the MIT License, - * http://www.opensource.org/licenses/mit-license.php - * Copyright 2009 John-Mark Bell - */ - -#include - -#include "bytecode/bytecode.h" -#include "bytecode/opcodes.h" -#include "parse/properties/properties.h" -#include "parse/properties/utils.h" - -static css_error parse_side(css_language *c, - const parserutils_vector *vector, int *ctx, - uint16_t op, css_style **result); - -/** - * Parse bottom - * - * \param c Parsing context - * \param vector Vector of tokens to process - * \param ctx Pointer to vector iteration context - * \param result Pointer to location to receive resulting style - * \return CSS_OK on success, - * CSS_NOMEM on memory exhaustion, - * CSS_INVALID if the input is not valid - * - * Post condition: \a *ctx is updated with the next token to process - * If the input is invalid, then \a *ctx remains unchanged. - */ -css_error parse_bottom(css_language *c, - const parserutils_vector *vector, int *ctx, - css_style **result) -{ - return parse_side(c, vector, ctx, CSS_PROP_BOTTOM, result); -} - -/** - * Parse left - * - * \param c Parsing context - * \param vector Vector of tokens to process - * \param ctx Pointer to vector iteration context - * \param result Pointer to location to receive resulting style - * \return CSS_OK on success, - * CSS_NOMEM on memory exhaustion, - * CSS_INVALID if the input is not valid - * - * Post condition: \a *ctx is updated with the next token to process - * If the input is invalid, then \a *ctx remains unchanged. - */ -css_error parse_left(css_language *c, - const parserutils_vector *vector, int *ctx, - css_style **result) -{ - return parse_side(c, vector, ctx, CSS_PROP_LEFT, result); -} - -/** - * Parse right - * - * \param c Parsing context - * \param vector Vector of tokens to process - * \param ctx Pointer to vector iteration context - * \param result Pointer to location to receive resulting style - * \return CSS_OK on success, - * CSS_NOMEM on memory exhaustion, - * CSS_INVALID if the input is not valid - * - * Post condition: \a *ctx is updated with the next token to process - * If the input is invalid, then \a *ctx remains unchanged. - */ -css_error parse_right(css_language *c, - const parserutils_vector *vector, int *ctx, - css_style **result) -{ - return parse_side(c, vector, ctx, CSS_PROP_RIGHT, result); -} - -/** - * Parse top - * - * \param c Parsing context - * \param vector Vector of tokens to process - * \param ctx Pointer to vector iteration context - * \param result Pointer to location to receive resulting style - * \return CSS_OK on success, - * CSS_NOMEM on memory exhaustion, - * CSS_INVALID if the input is not valid - * - * Post condition: \a *ctx is updated with the next token to process - * If the input is invalid, then \a *ctx remains unchanged. - */ -css_error parse_top(css_language *c, - const parserutils_vector *vector, int *ctx, - css_style **result) -{ - return parse_side(c, vector, ctx, CSS_PROP_TOP, result); -} - -/** - * Parse position - * - * \param c Parsing context - * \param vector Vector of tokens to process - * \param ctx Pointer to vector iteration context - * \param result Pointer to location to receive resulting style - * \return CSS_OK on success, - * CSS_NOMEM on memory exhaustion, - * CSS_INVALID if the input is not valid - * - * Post condition: \a *ctx is updated with the next token to process - * If the input is invalid, then \a *ctx remains unchanged. - */ -css_error parse_position(css_language *c, - const parserutils_vector *vector, int *ctx, - css_style **result) -{ - int orig_ctx = *ctx; - css_error error; - const css_token *ident; - uint8_t flags = 0; - uint16_t value = 0; - uint32_t opv; - bool match; - - /* IDENT (static, relative, absolute, fixed, inherit) */ - ident = parserutils_vector_iterate(vector, ctx); - if (ident == NULL || ident->type != CSS_TOKEN_IDENT) { - *ctx = orig_ctx; - return CSS_INVALID; - } - - if ((lwc_string_caseless_isequal( - ident->idata, c->strings[INHERIT], - &match) == lwc_error_ok && match)) { - flags |= FLAG_INHERIT; - } else if ((lwc_string_caseless_isequal( - ident->idata, c->strings[LIBCSS_STATIC], - &match) == lwc_error_ok && match)) { - value = POSITION_STATIC; - } else if ((lwc_string_caseless_isequal( - ident->idata, c->strings[RELATIVE], - &match) == lwc_error_ok && match)) { - value = POSITION_RELATIVE; - } else if ((lwc_string_caseless_isequal( - ident->idata, c->strings[ABSOLUTE], - &match) == lwc_error_ok && match)) { - value = POSITION_ABSOLUTE; - } else if ((lwc_string_caseless_isequal( - ident->idata, c->strings[FIXED], - &match) == lwc_error_ok && match)) { - value = POSITION_FIXED; - } else { - *ctx = orig_ctx; - return CSS_INVALID; - } - - opv = buildOPV(CSS_PROP_POSITION, flags, value); - - /* Allocate result */ - error = css_stylesheet_style_create(c->sheet, sizeof(opv), result); - if (error != CSS_OK) { - *ctx = orig_ctx; - return error; - } - - /* Copy the bytecode to it */ - memcpy((*result)->bytecode, &opv, sizeof(opv)); - - return CSS_OK; -} - -/** - * Parse clear - * - * \param c Parsing context - * \param vector Vector of tokens to process - * \param ctx Pointer to vector iteration context - * \param result Pointer to location to receive resulting style - * \return CSS_OK on success, - * CSS_NOMEM on memory exhaustion, - * CSS_INVALID if the input is not valid - * - * Post condition: \a *ctx is updated with the next token to process - * If the input is invalid, then \a *ctx remains unchanged. - */ -css_error parse_clear(css_language *c, - const parserutils_vector *vector, int *ctx, - css_style **result) -{ - int orig_ctx = *ctx; - css_error error; - const css_token *ident; - uint8_t flags = 0; - uint16_t value = 0; - uint32_t opv; - bool match; - - /* IDENT (left, right, both, none, inherit) */ - ident = parserutils_vector_iterate(vector, ctx); - if (ident == NULL || ident->type != CSS_TOKEN_IDENT) { - *ctx = orig_ctx; - return CSS_INVALID; - } - - if ((lwc_string_caseless_isequal( - ident->idata, c->strings[INHERIT], - &match) == lwc_error_ok && match)) { - flags |= FLAG_INHERIT; - } else if ((lwc_string_caseless_isequal( - ident->idata, c->strings[RIGHT], - &match) == lwc_error_ok && match)) { - value = CLEAR_RIGHT; - } else if ((lwc_string_caseless_isequal( - ident->idata, c->strings[LEFT], - &match) == lwc_error_ok && match)) { - value = CLEAR_LEFT; - } else if ((lwc_string_caseless_isequal( - ident->idata, c->strings[BOTH], - &match) == lwc_error_ok && match)) { - value = CLEAR_BOTH; - } else if ((lwc_string_caseless_isequal( - ident->idata, c->strings[NONE], - &match) == lwc_error_ok && match)) { - value = CLEAR_NONE; - } else { - *ctx = orig_ctx; - return CSS_INVALID; - } - - opv = buildOPV(CSS_PROP_CLEAR, flags, value); - - /* Allocate result */ - error = css_stylesheet_style_create(c->sheet, sizeof(opv), result); - if (error != CSS_OK) { - *ctx = orig_ctx; - return error; - } - - /* Copy the bytecode to it */ - memcpy((*result)->bytecode, &opv, sizeof(opv)); - - return CSS_OK; -} - -/** - * Parse float - * - * \param c Parsing context - * \param vector Vector of tokens to process - * \param ctx Pointer to vector iteration context - * \param result Pointer to location to receive resulting style - * \return CSS_OK on success, - * CSS_NOMEM on memory exhaustion, - * CSS_INVALID if the input is not valid - * - * Post condition: \a *ctx is updated with the next token to process - * If the input is invalid, then \a *ctx remains unchanged. - */ -css_error parse_float(css_language *c, - const parserutils_vector *vector, int *ctx, - css_style **result) -{ - int orig_ctx = *ctx; - css_error error; - const css_token *ident; - uint8_t flags = 0; - uint16_t value = 0; - uint32_t opv; - bool match; - - /* IDENT (left, right, none, inherit) */ - ident = parserutils_vector_iterate(vector, ctx); - if (ident == NULL || ident->type != CSS_TOKEN_IDENT) { - *ctx = orig_ctx; - return CSS_INVALID; - } - - if ((lwc_string_caseless_isequal( - ident->idata, c->strings[INHERIT], - &match) == lwc_error_ok && match)) { - flags |= FLAG_INHERIT; - } else if ((lwc_string_caseless_isequal( - ident->idata, c->strings[LEFT], - &match) == lwc_error_ok && match)) { - value = FLOAT_LEFT; - } else if ((lwc_string_caseless_isequal( - ident->idata, c->strings[RIGHT], - &match) == lwc_error_ok && match)) { - value = FLOAT_RIGHT; - } else if ((lwc_string_caseless_isequal( - ident->idata, c->strings[NONE], - &match) == lwc_error_ok && match)) { - value = FLOAT_NONE; - } else { - *ctx = orig_ctx; - return CSS_INVALID; - } - - opv = buildOPV(CSS_PROP_FLOAT, flags, value); - - /* Allocate result */ - error = css_stylesheet_style_create(c->sheet, sizeof(opv), result); - if (error != CSS_OK) { - *ctx = orig_ctx; - return error; - } - - /* Copy the bytecode to it */ - memcpy((*result)->bytecode, &opv, sizeof(opv)); - - return CSS_OK; -} - -/** - * Parse vertical-align - * - * \param c Parsing context - * \param vector Vector of tokens to process - * \param ctx Pointer to vector iteration context - * \param result Pointer to location to receive resulting style - * \return CSS_OK on success, - * CSS_NOMEM on memory exhaustion, - * CSS_INVALID if the input is not valid - * - * Post condition: \a *ctx is updated with the next token to process - * If the input is invalid, then \a *ctx remains unchanged. - */ -css_error parse_vertical_align(css_language *c, - const parserutils_vector *vector, int *ctx, - css_style **result) -{ - int orig_ctx = *ctx; - css_error error; - const css_token *token; - uint8_t flags = 0; - uint16_t value = 0; - uint32_t opv; - css_fixed length = 0; - uint32_t unit = 0; - uint32_t required_size; - bool match; - - /* length | percentage | IDENT(baseline, sub, super, top, text-top, - * middle, bottom, text-bottom, inherit) - */ - token = parserutils_vector_peek(vector, *ctx); - if (token == NULL) { - *ctx = orig_ctx; - return CSS_INVALID; - } - - if (token->type == CSS_TOKEN_IDENT && - (lwc_string_caseless_isequal( - token->idata, c->strings[INHERIT], - &match) == lwc_error_ok && match)) { - parserutils_vector_iterate(vector, ctx); - flags = FLAG_INHERIT; - } else if (token->type == CSS_TOKEN_IDENT && - (lwc_string_caseless_isequal( - token->idata, c->strings[BASELINE], - &match) == lwc_error_ok && match)) { - parserutils_vector_iterate(vector, ctx); - value = VERTICAL_ALIGN_BASELINE; - } else if (token->type == CSS_TOKEN_IDENT && - (lwc_string_caseless_isequal( - token->idata, c->strings[SUB], - &match) == lwc_error_ok && match)) { - parserutils_vector_iterate(vector, ctx); - value = VERTICAL_ALIGN_SUB; - } else if (token->type == CSS_TOKEN_IDENT && - (lwc_string_caseless_isequal( - token->idata, c->strings[SUPER], - &match) == lwc_error_ok && match)) { - parserutils_vector_iterate(vector, ctx); - value = VERTICAL_ALIGN_SUPER; - } else if (token->type == CSS_TOKEN_IDENT && - (lwc_string_caseless_isequal( - token->idata, c->strings[TOP], - &match) == lwc_error_ok && match)) { - parserutils_vector_iterate(vector, ctx); - value = VERTICAL_ALIGN_TOP; - } else if (token->type == CSS_TOKEN_IDENT && - (lwc_string_caseless_isequal( - token->idata, c->strings[TEXT_TOP], - &match) == lwc_error_ok && match)) { - parserutils_vector_iterate(vector, ctx); - value = VERTICAL_ALIGN_TEXT_TOP; - } else if (token->type == CSS_TOKEN_IDENT && - (lwc_string_caseless_isequal( - token->idata, c->strings[MIDDLE], - &match) == lwc_error_ok && match)) { - parserutils_vector_iterate(vector, ctx); - value = VERTICAL_ALIGN_MIDDLE; - } else if (token->type == CSS_TOKEN_IDENT && - (lwc_string_caseless_isequal( - token->idata, c->strings[BOTTOM], - &match) == lwc_error_ok && match)) { - parserutils_vector_iterate(vector, ctx); - value = VERTICAL_ALIGN_BOTTOM; - } else if (token->type == CSS_TOKEN_IDENT && - (lwc_string_caseless_isequal( - token->idata, c->strings[TEXT_BOTTOM], - &match) == lwc_error_ok && match)) { - parserutils_vector_iterate(vector, ctx); - value = VERTICAL_ALIGN_TEXT_BOTTOM; - } else { - error = parse_unit_specifier(c, vector, ctx, UNIT_PX, - &length, &unit); - if (error != CSS_OK) { - *ctx = orig_ctx; - return error; - } - - if (unit & UNIT_ANGLE || unit & UNIT_TIME || unit & UNIT_FREQ) { - *ctx = orig_ctx; - return CSS_INVALID; - } - - value = VERTICAL_ALIGN_SET; - } - - opv = buildOPV(CSS_PROP_VERTICAL_ALIGN, flags, value); - - required_size = sizeof(opv); - if ((flags & FLAG_INHERIT) == false && value == VERTICAL_ALIGN_SET) - required_size += sizeof(length) + sizeof(unit); - - /* Allocate result */ - error = css_stylesheet_style_create(c->sheet, required_size, result); - if (error != CSS_OK) { - *ctx = orig_ctx; - return error; - } - - /* Copy the bytecode to it */ - memcpy((*result)->bytecode, &opv, sizeof(opv)); - if ((flags & FLAG_INHERIT) == false && value == VERTICAL_ALIGN_SET) { - memcpy(((uint8_t *) (*result)->bytecode) + sizeof(opv), - &length, sizeof(length)); - memcpy(((uint8_t *) (*result)->bytecode) + sizeof(opv) + - sizeof(length), &unit, sizeof(unit)); - } - - return CSS_OK; -} - -/** - * Parse {top,right,bottom,left} - * - * \param c Parsing context - * \param vector Vector of tokens to process - * \param ctx Pointer to vector iteration context - * \param op Opcode to parse for - * \param result Pointer to location to receive resulting style - * \return CSS_OK on success, - * CSS_NOMEM on memory exhaustion, - * CSS_INVALID if the input is not valid - * - * Post condition: \a *ctx is updated with the next token to process - * If the input is invalid, then \a *ctx remains unchanged. - */ -css_error parse_side(css_language *c, - const parserutils_vector *vector, int *ctx, - uint16_t op, css_style **result) -{ - int orig_ctx = *ctx; - css_error error; - const css_token *token; - uint8_t flags = 0; - uint16_t value = 0; - uint32_t opv; - css_fixed length = 0; - uint32_t unit = 0; - uint32_t required_size; - bool match; - - /* length | percentage | IDENT(auto, inherit) */ - token = parserutils_vector_peek(vector, *ctx); - if (token == NULL) { - *ctx = orig_ctx; - return CSS_INVALID; - } - - if (token->type == CSS_TOKEN_IDENT && - (lwc_string_caseless_isequal( - token->idata, c->strings[INHERIT], - &match) == lwc_error_ok && match)) { - parserutils_vector_iterate(vector, ctx); - flags = FLAG_INHERIT; - } else if (token->type == CSS_TOKEN_IDENT && - (lwc_string_caseless_isequal( - token->idata, c->strings[AUTO], - &match) == lwc_error_ok && match)) { - parserutils_vector_iterate(vector, ctx); - value = BOTTOM_AUTO; - } else { - error = parse_unit_specifier(c, vector, ctx, UNIT_PX, - &length, &unit); - if (error != CSS_OK) { - *ctx = orig_ctx; - return error; - } - - if (unit & UNIT_ANGLE || unit & UNIT_TIME || unit & UNIT_FREQ) { - *ctx = orig_ctx; - return CSS_INVALID; - } - - value = BOTTOM_SET; - } - - opv = buildOPV(op, flags, value); - - required_size = sizeof(opv); - if ((flags & FLAG_INHERIT) == false && value == BOTTOM_SET) - required_size += sizeof(length) + sizeof(unit); - - /* Allocate result */ - error = css_stylesheet_style_create(c->sheet, required_size, result); - if (error != CSS_OK) { - *ctx = orig_ctx; - return error; - } - - /* Copy the bytecode to it */ - memcpy((*result)->bytecode, &opv, sizeof(opv)); - if ((flags & FLAG_INHERIT) == false && value == BOTTOM_SET) { - memcpy(((uint8_t *) (*result)->bytecode) + sizeof(opv), - &length, sizeof(length)); - memcpy(((uint8_t *) (*result)->bytecode) + sizeof(opv) + - sizeof(length), &unit, sizeof(unit)); - } - - return CSS_OK; -} - diff --git a/src/parse/properties/quotes.c b/src/parse/properties/quotes.c new file mode 100644 index 0000000..0488660 --- /dev/null +++ b/src/parse/properties/quotes.c @@ -0,0 +1,184 @@ +/* + * This file is part of LibCSS. + * Licensed under the MIT License, + * http://www.opensource.org/licenses/mit-license.php + * Copyright 2009 John-Mark Bell + */ + +#include +#include + +#include "bytecode/bytecode.h" +#include "bytecode/opcodes.h" +#include "parse/properties/properties.h" +#include "parse/properties/utils.h" + +/** + * Parse quotes + * + * \param c Parsing context + * \param vector Vector of tokens to process + * \param ctx Pointer to vector iteration context + * \param result Pointer to location to receive resulting style + * \return CSS_OK on success, + * CSS_NOMEM on memory exhaustion, + * CSS_INVALID if the input is not valid + * + * Post condition: \a *ctx is updated with the next token to process + * If the input is invalid, then \a *ctx remains unchanged. + */ +css_error parse_quotes(css_language *c, + const parserutils_vector *vector, int *ctx, + css_style **result) +{ + int orig_ctx = *ctx; + css_error error; + const css_token *token; + uint8_t flags = 0; + uint16_t value = 0; + uint32_t opv; + uint32_t required_size = sizeof(opv); + int temp_ctx = *ctx; + uint8_t *ptr; + bool match; + + /* [ STRING STRING ]+ | IDENT(none,inherit) */ + + /* Pass 1: validate input and calculate bytecode size */ + token = parserutils_vector_iterate(vector, &temp_ctx); + if (token == NULL || (token->type != CSS_TOKEN_IDENT && + token->type != CSS_TOKEN_STRING)) { + *ctx = orig_ctx; + return CSS_INVALID; + } + + if (token->type == CSS_TOKEN_IDENT) { + if ((lwc_string_caseless_isequal( + token->idata, c->strings[INHERIT], + &match) == lwc_error_ok && match)) { + flags = FLAG_INHERIT; + } else if ((lwc_string_caseless_isequal( + token->idata, c->strings[NONE], + &match) == lwc_error_ok && match)) { + value = QUOTES_NONE; + } else { + *ctx = orig_ctx; + return CSS_INVALID; + } + } else { + bool first = true; + + /* [ STRING STRING ] + */ + while (token != NULL && token->type == CSS_TOKEN_STRING) { + lwc_string *open = token->idata; + lwc_string *close; + + consumeWhitespace(vector, &temp_ctx); + + token = parserutils_vector_peek(vector, temp_ctx); + if (token == NULL || token->type != CSS_TOKEN_STRING) { + *ctx = orig_ctx; + return CSS_INVALID; + } + + close = token->idata; + + parserutils_vector_iterate(vector, &temp_ctx); + + consumeWhitespace(vector, &temp_ctx); + + if (first == false) { + required_size += sizeof(opv); + } else { + value = QUOTES_STRING; + } + required_size += sizeof(open) + sizeof(close); + + first = false; + + token = parserutils_vector_peek(vector, temp_ctx); + if (token == NULL || token->type != CSS_TOKEN_STRING) + break; + token = parserutils_vector_iterate(vector, &temp_ctx); + } + + /* Terminator */ + required_size += sizeof(opv); + } + + opv = buildOPV(CSS_PROP_QUOTES, flags, value); + + /* Allocate result */ + error = css_stylesheet_style_create(c->sheet, required_size, result); + if (error != CSS_OK) { + *ctx = orig_ctx; + return error; + } + + /* Copy OPV to bytecode */ + ptr = (*result)->bytecode; + memcpy(ptr, &opv, sizeof(opv)); + ptr += sizeof(opv); + + /* Pass 2: construct bytecode */ + token = parserutils_vector_iterate(vector, ctx); + if (token == NULL || (token->type != CSS_TOKEN_IDENT && + token->type != CSS_TOKEN_STRING)) { + *ctx = orig_ctx; + return CSS_INVALID; + } + + if (token->type == CSS_TOKEN_IDENT) { + /* Nothing to do */ + } else { + bool first = true; + + /* [ STRING STRING ]+ */ + while (token != NULL && token->type == CSS_TOKEN_STRING) { + lwc_string *open = token->idata; + lwc_string *close; + + consumeWhitespace(vector, ctx); + + token = parserutils_vector_peek(vector, *ctx); + if (token == NULL || token->type != CSS_TOKEN_STRING) { + *ctx = orig_ctx; + return CSS_INVALID; + } + + close = token->idata; + + parserutils_vector_iterate(vector, ctx); + + consumeWhitespace(vector, ctx); + + if (first == false) { + opv = QUOTES_STRING; + memcpy(ptr, &opv, sizeof(opv)); + ptr += sizeof(opv); + } + + lwc_string_ref(open); + memcpy(ptr, &open, sizeof(open)); + ptr += sizeof(open); + + lwc_string_ref(close); + memcpy(ptr, &close, sizeof(close)); + ptr += sizeof(close); + + first = false; + + token = parserutils_vector_peek(vector, *ctx); + if (token == NULL || token->type != CSS_TOKEN_STRING) + break; + token = parserutils_vector_iterate(vector, ctx); + } + + /* Terminator */ + opv = QUOTES_NONE; + memcpy(ptr, &opv, sizeof(opv)); + ptr += sizeof(opv); + } + + return CSS_OK; +} diff --git a/src/parse/properties/richness.c b/src/parse/properties/richness.c new file mode 100644 index 0000000..ff8504d --- /dev/null +++ b/src/parse/properties/richness.c @@ -0,0 +1,98 @@ +/* + * This file is part of LibCSS. + * Licensed under the MIT License, + * http://www.opensource.org/licenses/mit-license.php + * Copyright 2009 John-Mark Bell + */ + +#include +#include + +#include "bytecode/bytecode.h" +#include "bytecode/opcodes.h" +#include "parse/properties/properties.h" +#include "parse/properties/utils.h" + +/** + * Parse richness + * + * \param c Parsing context + * \param vector Vector of tokens to process + * \param ctx Pointer to vector iteration context + * \param result Pointer to location to receive resulting style + * \return CSS_OK on success, + * CSS_NOMEM on memory exhaustion, + * CSS_INVALID if the input is not valid + * + * Post condition: \a *ctx is updated with the next token to process + * If the input is invalid, then \a *ctx remains unchanged. + */ +css_error parse_richness(css_language *c, + const parserutils_vector *vector, int *ctx, + css_style **result) +{ + int orig_ctx = *ctx; + css_error error; + const css_token *token; + uint8_t flags = 0; + uint16_t value = 0; + uint32_t opv; + css_fixed num = 0; + uint32_t required_size; + bool match; + + /* number | IDENT (inherit) */ + token = parserutils_vector_iterate(vector, ctx); + if (token == NULL || (token->type != CSS_TOKEN_IDENT && + token->type != CSS_TOKEN_NUMBER)) { + *ctx = orig_ctx; + return CSS_INVALID; + } + + if ((lwc_string_caseless_isequal( + token->idata, c->strings[INHERIT], + &match) == lwc_error_ok && match)) { + flags |= FLAG_INHERIT; + } else if (token->type == CSS_TOKEN_NUMBER) { + size_t consumed = 0; + num = number_from_lwc_string(token->idata, false, &consumed); + /* Invalid if there are trailing characters */ + if (consumed != lwc_string_length(token->idata)) { + *ctx = orig_ctx; + return CSS_INVALID; + } + + /* Must be between 0 and 100 */ + if (num < 0 || num > F_100) { + *ctx = orig_ctx; + return CSS_INVALID; + } + + value = RICHNESS_SET; + } else { + *ctx = orig_ctx; + return CSS_INVALID; + } + + opv = buildOPV(CSS_PROP_RICHNESS, flags, value); + + required_size = sizeof(opv); + if ((flags & FLAG_INHERIT) == false && value == RICHNESS_SET) + required_size += sizeof(num); + + /* Allocate result */ + error = css_stylesheet_style_create(c->sheet, required_size, result); + if (error != CSS_OK) { + *ctx = orig_ctx; + return error; + } + + /* Copy the bytecode to it */ + memcpy((*result)->bytecode, &opv, sizeof(opv)); + if ((flags & FLAG_INHERIT) == false && value == RICHNESS_SET) { + memcpy(((uint8_t *) (*result)->bytecode) + sizeof(opv), + &num, sizeof(num)); + } + + return CSS_OK; +} diff --git a/src/parse/properties/right.c b/src/parse/properties/right.c new file mode 100644 index 0000000..903dac0 --- /dev/null +++ b/src/parse/properties/right.c @@ -0,0 +1,35 @@ +/* + * This file is part of LibCSS. + * Licensed under the MIT License, + * http://www.opensource.org/licenses/mit-license.php + * Copyright 2009 John-Mark Bell + */ + +#include +#include + +#include "bytecode/bytecode.h" +#include "bytecode/opcodes.h" +#include "parse/properties/properties.h" +#include "parse/properties/utils.h" + +/** + * Parse right + * + * \param c Parsing context + * \param vector Vector of tokens to process + * \param ctx Pointer to vector iteration context + * \param result Pointer to location to receive resulting style + * \return CSS_OK on success, + * CSS_NOMEM on memory exhaustion, + * CSS_INVALID if the input is not valid + * + * Post condition: \a *ctx is updated with the next token to process + * If the input is invalid, then \a *ctx remains unchanged. + */ +css_error parse_right(css_language *c, + const parserutils_vector *vector, int *ctx, + css_style **result) +{ + return parse_side(c, vector, ctx, CSS_PROP_RIGHT, result); +} diff --git a/src/parse/properties/speak.c b/src/parse/properties/speak.c new file mode 100644 index 0000000..f62bffc --- /dev/null +++ b/src/parse/properties/speak.c @@ -0,0 +1,83 @@ +/* + * This file is part of LibCSS. + * Licensed under the MIT License, + * http://www.opensource.org/licenses/mit-license.php + * Copyright 2009 John-Mark Bell + */ + +#include +#include + +#include "bytecode/bytecode.h" +#include "bytecode/opcodes.h" +#include "parse/properties/properties.h" +#include "parse/properties/utils.h" + +/** + * Parse speak + * + * \param c Parsing context + * \param vector Vector of tokens to process + * \param ctx Pointer to vector iteration context + * \param result Pointer to location to receive resulting style + * \return CSS_OK on success, + * CSS_NOMEM on memory exhaustion, + * CSS_INVALID if the input is not valid + * + * Post condition: \a *ctx is updated with the next token to process + * If the input is invalid, then \a *ctx remains unchanged. + */ +css_error parse_speak(css_language *c, + const parserutils_vector *vector, int *ctx, + css_style **result) +{ + int orig_ctx = *ctx; + css_error error; + const css_token *ident; + uint8_t flags = 0; + uint16_t value = 0; + uint32_t opv; + bool match; + + /* IDENT (normal, none, spell-out, inherit) */ + ident = parserutils_vector_iterate(vector, ctx); + if (ident == NULL || ident->type != CSS_TOKEN_IDENT) { + *ctx = orig_ctx; + return CSS_INVALID; + } + + if ((lwc_string_caseless_isequal( + ident->idata, c->strings[INHERIT], + &match) == lwc_error_ok && match)) { + flags |= FLAG_INHERIT; + } else if ((lwc_string_caseless_isequal( + ident->idata, c->strings[NORMAL], + &match) == lwc_error_ok && match)) { + value = SPEAK_NORMAL; + } else if ((lwc_string_caseless_isequal( + ident->idata, c->strings[NONE], + &match) == lwc_error_ok && match)) { + value = SPEAK_NONE; + } else if ((lwc_string_caseless_isequal( + ident->idata, c->strings[SPELL_OUT], + &match) == lwc_error_ok && match)) { + value = SPEAK_SPELL_OUT; + } else { + *ctx = orig_ctx; + return CSS_INVALID; + } + + opv = buildOPV(CSS_PROP_SPEAK, flags, value); + + /* Allocate result */ + error = css_stylesheet_style_create(c->sheet, sizeof(opv), result); + if (error != CSS_OK) { + *ctx = orig_ctx; + return error; + } + + /* Copy the bytecode to it */ + memcpy((*result)->bytecode, &opv, sizeof(opv)); + + return CSS_OK; +} diff --git a/src/parse/properties/speak_header.c b/src/parse/properties/speak_header.c new file mode 100644 index 0000000..b0c5f92 --- /dev/null +++ b/src/parse/properties/speak_header.c @@ -0,0 +1,79 @@ +/* + * This file is part of LibCSS. + * Licensed under the MIT License, + * http://www.opensource.org/licenses/mit-license.php + * Copyright 2009 John-Mark Bell + */ + +#include +#include + +#include "bytecode/bytecode.h" +#include "bytecode/opcodes.h" +#include "parse/properties/properties.h" +#include "parse/properties/utils.h" + +/** + * Parse speak-header + * + * \param c Parsing context + * \param vector Vector of tokens to process + * \param ctx Pointer to vector iteration context + * \param result Pointer to location to receive resulting style + * \return CSS_OK on success, + * CSS_NOMEM on memory exhaustion, + * CSS_INVALID if the input is not valid + * + * Post condition: \a *ctx is updated with the next token to process + * If the input is invalid, then \a *ctx remains unchanged. + */ +css_error parse_speak_header(css_language *c, + const parserutils_vector *vector, int *ctx, + css_style **result) +{ + int orig_ctx = *ctx; + css_error error; + const css_token *ident; + uint8_t flags = 0; + uint16_t value = 0; + uint32_t opv; + bool match; + + /* IDENT (once, always, inherit) */ + ident = parserutils_vector_iterate(vector, ctx); + if (ident == NULL || ident->type != CSS_TOKEN_IDENT) { + *ctx = orig_ctx; + return CSS_INVALID; + } + + if ((lwc_string_caseless_isequal( + ident->idata, c->strings[INHERIT], + &match) == lwc_error_ok && match)) { + flags |= FLAG_INHERIT; + } else if ((lwc_string_caseless_isequal( + ident->idata, c->strings[ONCE], + &match) == lwc_error_ok && match)) { + value = SPEAK_HEADER_ONCE; + } else if ((lwc_string_caseless_isequal( + ident->idata, c->strings[ALWAYS], + &match) == lwc_error_ok && match)) { + value = SPEAK_HEADER_ALWAYS; + } else { + *ctx = orig_ctx; + return CSS_INVALID; + } + + opv = buildOPV(CSS_PROP_SPEAK_HEADER, flags, value); + + /* Allocate result */ + error = css_stylesheet_style_create(c->sheet, sizeof(opv), result); + if (error != CSS_OK) { + *ctx = orig_ctx; + return error; + } + + /* Copy the bytecode to it */ + memcpy((*result)->bytecode, &opv, sizeof(opv)); + + return CSS_OK; +} diff --git a/src/parse/properties/speak_numeral.c b/src/parse/properties/speak_numeral.c new file mode 100644 index 0000000..7d9f7f1 --- /dev/null +++ b/src/parse/properties/speak_numeral.c @@ -0,0 +1,79 @@ +/* + * This file is part of LibCSS. + * Licensed under the MIT License, + * http://www.opensource.org/licenses/mit-license.php + * Copyright 2009 John-Mark Bell + */ + +#include +#include + +#include "bytecode/bytecode.h" +#include "bytecode/opcodes.h" +#include "parse/properties/properties.h" +#include "parse/properties/utils.h" + +/** + * Parse speak-numeral + * + * \param c Parsing context + * \param vector Vector of tokens to process + * \param ctx Pointer to vector iteration context + * \param result Pointer to location to receive resulting style + * \return CSS_OK on success, + * CSS_NOMEM on memory exhaustion, + * CSS_INVALID if the input is not valid + * + * Post condition: \a *ctx is updated with the next token to process + * If the input is invalid, then \a *ctx remains unchanged. + */ +css_error parse_speak_numeral(css_language *c, + const parserutils_vector *vector, int *ctx, + css_style **result) +{ + int orig_ctx = *ctx; + css_error error; + const css_token *ident; + uint8_t flags = 0; + uint16_t value = 0; + uint32_t opv; + bool match; + + /* IDENT (digits, continuous, inherit) */ + ident = parserutils_vector_iterate(vector, ctx); + if (ident == NULL || ident->type != CSS_TOKEN_IDENT) { + *ctx = orig_ctx; + return CSS_INVALID; + } + + if ((lwc_string_caseless_isequal( + ident->idata, c->strings[INHERIT], + &match) == lwc_error_ok && match)) { + flags |= FLAG_INHERIT; + } else if ((lwc_string_caseless_isequal( + ident->idata, c->strings[DIGITS], + &match) == lwc_error_ok && match)) { + value = SPEAK_NUMERAL_DIGITS; + } else if ((lwc_string_caseless_isequal( + ident->idata, c->strings[CONTINUOUS], + &match) == lwc_error_ok && match)) { + value = SPEAK_NUMERAL_CONTINUOUS; + } else { + *ctx = orig_ctx; + return CSS_INVALID; + } + + opv = buildOPV(CSS_PROP_SPEAK_NUMERAL, flags, value); + + /* Allocate result */ + error = css_stylesheet_style_create(c->sheet, sizeof(opv), result); + if (error != CSS_OK) { + *ctx = orig_ctx; + return error; + } + + /* Copy the bytecode to it */ + memcpy((*result)->bytecode, &opv, sizeof(opv)); + + return CSS_OK; +} diff --git a/src/parse/properties/speak_punctuation.c b/src/parse/properties/speak_punctuation.c new file mode 100644 index 0000000..c4b9ec9 --- /dev/null +++ b/src/parse/properties/speak_punctuation.c @@ -0,0 +1,79 @@ +/* + * This file is part of LibCSS. + * Licensed under the MIT License, + * http://www.opensource.org/licenses/mit-license.php + * Copyright 2009 John-Mark Bell + */ + +#include +#include + +#include "bytecode/bytecode.h" +#include "bytecode/opcodes.h" +#include "parse/properties/properties.h" +#include "parse/properties/utils.h" + +/** + * Parse speak-punctuation + * + * \param c Parsing context + * \param vector Vector of tokens to process + * \param ctx Pointer to vector iteration context + * \param result Pointer to location to receive resulting style + * \return CSS_OK on success, + * CSS_NOMEM on memory exhaustion, + * CSS_INVALID if the input is not valid + * + * Post condition: \a *ctx is updated with the next token to process + * If the input is invalid, then \a *ctx remains unchanged. + */ +css_error parse_speak_punctuation(css_language *c, + const parserutils_vector *vector, int *ctx, + css_style **result) +{ + int orig_ctx = *ctx; + css_error error; + const css_token *ident; + uint8_t flags = 0; + uint16_t value = 0; + uint32_t opv; + bool match; + + /* IDENT (code, none, inherit) */ + ident = parserutils_vector_iterate(vector, ctx); + if (ident == NULL || ident->type != CSS_TOKEN_IDENT) { + *ctx = orig_ctx; + return CSS_INVALID; + } + + if ((lwc_string_caseless_isequal( + ident->idata, c->strings[INHERIT], + &match) == lwc_error_ok && match)) { + flags |= FLAG_INHERIT; + } else if ((lwc_string_caseless_isequal( + ident->idata, c->strings[CODE], + &match) == lwc_error_ok && match)) { + value = SPEAK_PUNCTUATION_CODE; + } else if ((lwc_string_caseless_isequal( + ident->idata, c->strings[NONE], + &match) == lwc_error_ok && match)) { + value = SPEAK_PUNCTUATION_NONE; + } else { + *ctx = orig_ctx; + return CSS_INVALID; + } + + opv = buildOPV(CSS_PROP_SPEAK_PUNCTUATION, flags, value); + + /* Allocate result */ + error = css_stylesheet_style_create(c->sheet, sizeof(opv), result); + if (error != CSS_OK) { + *ctx = orig_ctx; + return error; + } + + /* Copy the bytecode to it */ + memcpy((*result)->bytecode, &opv, sizeof(opv)); + + return CSS_OK; +} diff --git a/src/parse/properties/speech_rate.c b/src/parse/properties/speech_rate.c new file mode 100644 index 0000000..616c182 --- /dev/null +++ b/src/parse/properties/speech_rate.c @@ -0,0 +1,136 @@ +/* + * This file is part of LibCSS. + * Licensed under the MIT License, + * http://www.opensource.org/licenses/mit-license.php + * Copyright 2009 John-Mark Bell + */ + +#include +#include + +#include "bytecode/bytecode.h" +#include "bytecode/opcodes.h" +#include "parse/properties/properties.h" +#include "parse/properties/utils.h" + +/** + * Parse speech-rate + * + * \param c Parsing context + * \param vector Vector of tokens to process + * \param ctx Pointer to vector iteration context + * \param result Pointer to location to receive resulting style + * \return CSS_OK on success, + * CSS_NOMEM on memory exhaustion, + * CSS_INVALID if the input is not valid + * + * Post condition: \a *ctx is updated with the next token to process + * If the input is invalid, then \a *ctx remains unchanged. + */ +css_error parse_speech_rate(css_language *c, + const parserutils_vector *vector, int *ctx, + css_style **result) +{ + int orig_ctx = *ctx; + css_error error; + const css_token *token; + uint8_t flags = 0; + uint16_t value = 0; + uint32_t opv; + css_fixed num = 0; + uint32_t required_size; + bool match; + + /* number | IDENT (x-slow, slow, medium, fast, x-fast, faster, slower, + * inherit) + */ + token = parserutils_vector_iterate(vector, ctx); + if (token == NULL || (token->type != CSS_TOKEN_IDENT && + token->type != CSS_TOKEN_NUMBER)) { + *ctx = orig_ctx; + return CSS_INVALID; + } + + if (token->type == CSS_TOKEN_IDENT && + (lwc_string_caseless_isequal( + token->idata, c->strings[INHERIT], + &match) == lwc_error_ok && match)) { + flags |= FLAG_INHERIT; + } else if (token->type == CSS_TOKEN_IDENT && + (lwc_string_caseless_isequal( + token->idata, c->strings[X_SLOW], + &match) == lwc_error_ok && match)) { + value = SPEECH_RATE_X_SLOW; + } else if (token->type == CSS_TOKEN_IDENT && + (lwc_string_caseless_isequal( + token->idata, c->strings[SLOW], + &match) == lwc_error_ok && match)) { + value = SPEECH_RATE_SLOW; + } else if (token->type == CSS_TOKEN_IDENT && + (lwc_string_caseless_isequal( + token->idata, c->strings[MEDIUM], + &match) == lwc_error_ok && match)) { + value = SPEECH_RATE_MEDIUM; + } else if (token->type == CSS_TOKEN_IDENT && + (lwc_string_caseless_isequal( + token->idata, c->strings[FAST], + &match) == lwc_error_ok && match)) { + value = SPEECH_RATE_FAST; + } else if (token->type == CSS_TOKEN_IDENT && + (lwc_string_caseless_isequal( + token->idata, c->strings[X_FAST], + &match) == lwc_error_ok && match)) { + value = SPEECH_RATE_X_FAST; + } else if (token->type == CSS_TOKEN_IDENT && + (lwc_string_caseless_isequal( + token->idata, c->strings[FASTER], + &match) == lwc_error_ok && match)) { + value = SPEECH_RATE_FASTER; + } else if (token->type == CSS_TOKEN_IDENT && + (lwc_string_caseless_isequal( + token->idata, c->strings[SLOWER], + &match) == lwc_error_ok && match)) { + value = SPEECH_RATE_SLOWER; + } else if (token->type == CSS_TOKEN_NUMBER) { + size_t consumed = 0; + num = number_from_lwc_string(token->idata, false, &consumed); + /* Invalid if there are trailing characters */ + if (consumed != lwc_string_length(token->idata)) { + *ctx = orig_ctx; + return CSS_INVALID; + } + + /* Make negative values invalid */ + if (num < 0) { + *ctx = orig_ctx; + return CSS_INVALID; + } + + value = SPEECH_RATE_SET; + } else { + *ctx = orig_ctx; + return CSS_INVALID; + } + + opv = buildOPV(CSS_PROP_SPEECH_RATE, flags, value); + + required_size = sizeof(opv); + if ((flags & FLAG_INHERIT) == false && value == SPEECH_RATE_SET) + required_size += sizeof(num); + + /* Allocate result */ + error = css_stylesheet_style_create(c->sheet, required_size, result); + if (error != CSS_OK) { + *ctx = orig_ctx; + return error; + } + + /* Copy the bytecode to it */ + memcpy((*result)->bytecode, &opv, sizeof(opv)); + if ((flags & FLAG_INHERIT) == false && value == SPEECH_RATE_SET) { + memcpy(((uint8_t *) (*result)->bytecode) + sizeof(opv), + &num, sizeof(num)); + } + + return CSS_OK; +} diff --git a/src/parse/properties/stress.c b/src/parse/properties/stress.c new file mode 100644 index 0000000..c04d22e --- /dev/null +++ b/src/parse/properties/stress.c @@ -0,0 +1,97 @@ +/* + * This file is part of LibCSS. + * Licensed under the MIT License, + * http://www.opensource.org/licenses/mit-license.php + * Copyright 2009 John-Mark Bell + */ + +#include +#include + +#include "bytecode/bytecode.h" +#include "bytecode/opcodes.h" +#include "parse/properties/properties.h" +#include "parse/properties/utils.h" + +/** + * Parse stress + * + * \param c Parsing context + * \param vector Vector of tokens to process + * \param ctx Pointer to vector iteration context + * \param result Pointer to location to receive resulting style + * \return CSS_OK on success, + * CSS_NOMEM on memory exhaustion, + * CSS_INVALID if the input is not valid + * + * Post condition: \a *ctx is updated with the next token to process + * If the input is invalid, then \a *ctx remains unchanged. + */ +css_error parse_stress(css_language *c, + const parserutils_vector *vector, int *ctx, + css_style **result) +{ + int orig_ctx = *ctx; + css_error error; + const css_token *token; + uint8_t flags = 0; + uint16_t value = 0; + uint32_t opv; + css_fixed num = 0; + uint32_t required_size; + bool match; + + /* number | IDENT (inherit) */ + token = parserutils_vector_iterate(vector, ctx); + if (token == NULL || (token->type != CSS_TOKEN_IDENT && + token->type != CSS_TOKEN_NUMBER)) { + *ctx = orig_ctx; + return CSS_INVALID; + } + + if ((lwc_string_caseless_isequal( + token->idata, c->strings[INHERIT], + &match) == lwc_error_ok && match)) { + flags |= FLAG_INHERIT; + } else if (token->type == CSS_TOKEN_NUMBER) { + size_t consumed = 0; + num = number_from_lwc_string(token->idata, false, &consumed); + /* Invalid if there are trailing characters */ + if (consumed != lwc_string_length(token->idata)) { + *ctx = orig_ctx; + return CSS_INVALID; + } + + if (num < 0 || num > INTTOFIX(100)) { + *ctx = orig_ctx; + return CSS_INVALID; + } + + value = STRESS_SET; + } else { + *ctx = orig_ctx; + return CSS_INVALID; + } + + opv = buildOPV(CSS_PROP_STRESS, flags, value); + + required_size = sizeof(opv); + if ((flags & FLAG_INHERIT) == false && value == STRESS_SET) + required_size += sizeof(num); + + /* Allocate result */ + error = css_stylesheet_style_create(c->sheet, required_size, result); + if (error != CSS_OK) { + *ctx = orig_ctx; + return error; + } + + /* Copy the bytecode to it */ + memcpy((*result)->bytecode, &opv, sizeof(opv)); + if ((flags & FLAG_INHERIT) == false && value == STRESS_SET) { + memcpy(((uint8_t *) (*result)->bytecode) + sizeof(opv), + &num, sizeof(num)); + } + + return CSS_OK; +} diff --git a/src/parse/properties/table.c b/src/parse/properties/table.c deleted file mode 100644 index 61c0d85..0000000 --- a/src/parse/properties/table.c +++ /dev/null @@ -1,209 +0,0 @@ -/* - * This file is part of LibCSS. - * Licensed under the MIT License, - * http://www.opensource.org/licenses/mit-license.php - * Copyright 2009 John-Mark Bell - */ - -#include - -#include "bytecode/bytecode.h" -#include "bytecode/opcodes.h" -#include "parse/properties/properties.h" -#include "parse/properties/utils.h" - -/** - * Parse caption-side - * - * \param c Parsing context - * \param vector Vector of tokens to process - * \param ctx Pointer to vector iteration context - * \param result Pointer to location to receive resulting style - * \return CSS_OK on success, - * CSS_NOMEM on memory exhaustion, - * CSS_INVALID if the input is not valid - * - * Post condition: \a *ctx is updated with the next token to process - * If the input is invalid, then \a *ctx remains unchanged. - */ -css_error parse_caption_side(css_language *c, - const parserutils_vector *vector, int *ctx, - css_style **result) -{ - int orig_ctx = *ctx; - css_error error; - const css_token *ident; - uint8_t flags = 0; - uint16_t value = 0; - uint32_t opv; - bool match; - - /* IDENT (top, bottom, inherit) */ - ident = parserutils_vector_iterate(vector, ctx); - if (ident == NULL || ident->type != CSS_TOKEN_IDENT) { - *ctx = orig_ctx; - return CSS_INVALID; - } - - if ((lwc_string_caseless_isequal( - ident->idata, c->strings[INHERIT], - &match) == lwc_error_ok && match)) { - flags |= FLAG_INHERIT; - } else if ((lwc_string_caseless_isequal( - ident->idata, c->strings[TOP], - &match) == lwc_error_ok && match)) { - value = CAPTION_SIDE_TOP; - } else if ((lwc_string_caseless_isequal( - ident->idata, c->strings[BOTTOM], - &match) == lwc_error_ok && match)) { - value = CAPTION_SIDE_BOTTOM; - } else { - *ctx = orig_ctx; - return CSS_INVALID; - } - - opv = buildOPV(CSS_PROP_CAPTION_SIDE, flags, value); - - /* Allocate result */ - error = css_stylesheet_style_create(c->sheet, sizeof(opv), result); - if (error != CSS_OK) { - *ctx = orig_ctx; - return error; - } - - /* Copy the bytecode to it */ - memcpy((*result)->bytecode, &opv, sizeof(opv)); - - return CSS_OK; -} - -/** - * Parse empty-cells - * - * \param c Parsing context - * \param vector Vector of tokens to process - * \param ctx Pointer to vector iteration context - * \param result Pointer to location to receive resulting style - * \return CSS_OK on success, - * CSS_NOMEM on memory exhaustion, - * CSS_INVALID if the input is not valid - * - * Post condition: \a *ctx is updated with the next token to process - * If the input is invalid, then \a *ctx remains unchanged. - */ -css_error parse_empty_cells(css_language *c, - const parserutils_vector *vector, int *ctx, - css_style **result) -{ - int orig_ctx = *ctx; - css_error error; - const css_token *ident; - uint8_t flags = 0; - uint16_t value = 0; - uint32_t opv; - bool match; - - /* IDENT (show, hide, inherit) */ - ident = parserutils_vector_iterate(vector, ctx); - if (ident == NULL || ident->type != CSS_TOKEN_IDENT) { - *ctx = orig_ctx; - return CSS_INVALID; - } - - if ((lwc_string_caseless_isequal( - ident->idata, c->strings[INHERIT], - &match) == lwc_error_ok && match)) { - flags |= FLAG_INHERIT; - } else if ((lwc_string_caseless_isequal( - ident->idata, c->strings[SHOW], - &match) == lwc_error_ok && match)) { - value = EMPTY_CELLS_SHOW; - } else if ((lwc_string_caseless_isequal( - ident->idata, c->strings[HIDE], - &match) == lwc_error_ok && match)) { - value = EMPTY_CELLS_HIDE; - } else { - *ctx = orig_ctx; - return CSS_INVALID; - } - - opv = buildOPV(CSS_PROP_EMPTY_CELLS, flags, value); - - /* Allocate result */ - error = css_stylesheet_style_create(c->sheet, sizeof(opv), result); - if (error != CSS_OK) { - *ctx = orig_ctx; - return error; - } - - /* Copy the bytecode to it */ - memcpy((*result)->bytecode, &opv, sizeof(opv)); - - return CSS_OK; -} - -/** - * Parse table-layout - * - * \param c Parsing context - * \param vector Vector of tokens to process - * \param ctx Pointer to vector iteration context - * \param result Pointer to location to receive resulting style - * \return CSS_OK on success, - * CSS_NOMEM on memory exhaustion, - * CSS_INVALID if the input is not valid - * - * Post condition: \a *ctx is updated with the next token to process - * If the input is invalid, then \a *ctx remains unchanged. - */ -css_error parse_table_layout(css_language *c, - const parserutils_vector *vector, int *ctx, - css_style **result) -{ - int orig_ctx = *ctx; - css_error error; - const css_token *ident; - uint8_t flags = 0; - uint16_t value = 0; - uint32_t opv; - bool match; - - /* IDENT (auto, fixed, inherit) */ - ident = parserutils_vector_iterate(vector, ctx); - if (ident == NULL || ident->type != CSS_TOKEN_IDENT) { - *ctx = orig_ctx; - return CSS_INVALID; - } - - if ((lwc_string_caseless_isequal( - ident->idata, c->strings[INHERIT], - &match) == lwc_error_ok && match)) { - flags |= FLAG_INHERIT; - } else if ((lwc_string_caseless_isequal( - ident->idata, c->strings[AUTO], - &match) == lwc_error_ok && match)) { - value = TABLE_LAYOUT_AUTO; - } else if ((lwc_string_caseless_isequal( - ident->idata, c->strings[FIXED], - &match) == lwc_error_ok && match)) { - value = TABLE_LAYOUT_FIXED; - } else { - *ctx = orig_ctx; - return CSS_INVALID; - } - - opv = buildOPV(CSS_PROP_TABLE_LAYOUT, flags, value); - - /* Allocate result */ - error = css_stylesheet_style_create(c->sheet, sizeof(opv), result); - if (error != CSS_OK) { - *ctx = orig_ctx; - return error; - } - - /* Copy the bytecode to it */ - memcpy((*result)->bytecode, &opv, sizeof(opv)); - - return CSS_OK; -} - diff --git a/src/parse/properties/table_layout.c b/src/parse/properties/table_layout.c new file mode 100644 index 0000000..7bc34d5 --- /dev/null +++ b/src/parse/properties/table_layout.c @@ -0,0 +1,80 @@ +/* + * This file is part of LibCSS. + * Licensed under the MIT License, + * http://www.opensource.org/licenses/mit-license.php + * Copyright 2009 John-Mark Bell + */ + +#include +#include + +#include "bytecode/bytecode.h" +#include "bytecode/opcodes.h" +#include "parse/properties/properties.h" +#include "parse/properties/utils.h" + +/** + * Parse table-layout + * + * \param c Parsing context + * \param vector Vector of tokens to process + * \param ctx Pointer to vector iteration context + * \param result Pointer to location to receive resulting style + * \return CSS_OK on success, + * CSS_NOMEM on memory exhaustion, + * CSS_INVALID if the input is not valid + * + * Post condition: \a *ctx is updated with the next token to process + * If the input is invalid, then \a *ctx remains unchanged. + */ +css_error parse_table_layout(css_language *c, + const parserutils_vector *vector, int *ctx, + css_style **result) +{ + int orig_ctx = *ctx; + css_error error; + const css_token *ident; + uint8_t flags = 0; + uint16_t value = 0; + uint32_t opv; + bool match; + + /* IDENT (auto, fixed, inherit) */ + ident = parserutils_vector_iterate(vector, ctx); + if (ident == NULL || ident->type != CSS_TOKEN_IDENT) { + *ctx = orig_ctx; + return CSS_INVALID; + } + + if ((lwc_string_caseless_isequal( + ident->idata, c->strings[INHERIT], + &match) == lwc_error_ok && match)) { + flags |= FLAG_INHERIT; + } else if ((lwc_string_caseless_isequal( + ident->idata, c->strings[AUTO], + &match) == lwc_error_ok && match)) { + value = TABLE_LAYOUT_AUTO; + } else if ((lwc_string_caseless_isequal( + ident->idata, c->strings[FIXED], + &match) == lwc_error_ok && match)) { + value = TABLE_LAYOUT_FIXED; + } else { + *ctx = orig_ctx; + return CSS_INVALID; + } + + opv = buildOPV(CSS_PROP_TABLE_LAYOUT, flags, value); + + /* Allocate result */ + error = css_stylesheet_style_create(c->sheet, sizeof(opv), result); + if (error != CSS_OK) { + *ctx = orig_ctx; + return error; + } + + /* Copy the bytecode to it */ + memcpy((*result)->bytecode, &opv, sizeof(opv)); + + return CSS_OK; +} + diff --git a/src/parse/properties/text.c b/src/parse/properties/text.c deleted file mode 100644 index b019692..0000000 --- a/src/parse/properties/text.c +++ /dev/null @@ -1,830 +0,0 @@ -/* - * This file is part of LibCSS. - * Licensed under the MIT License, - * http://www.opensource.org/licenses/mit-license.php - * Copyright 2009 John-Mark Bell - */ - -#include - -#include "bytecode/bytecode.h" -#include "bytecode/opcodes.h" -#include "parse/properties/properties.h" -#include "parse/properties/utils.h" - -/** - * Parse color - * - * \param c Parsing context - * \param vector Vector of tokens to process - * \param ctx Pointer to vector iteration context - * \param result Pointer to location to receive resulting style - * \return CSS_OK on success, - * CSS_NOMEM on memory exhaustion, - * CSS_INVALID if the input is not valid - * - * Post condition: \a *ctx is updated with the next token to process - * If the input is invalid, then \a *ctx remains unchanged. - */ -css_error parse_color(css_language *c, - const parserutils_vector *vector, int *ctx, - css_style **result) -{ - int orig_ctx = *ctx; - css_error error; - const css_token *token; - uint8_t flags = 0; - uint16_t value = 0; - uint32_t opv; - uint32_t colour = 0; - uint32_t required_size; - bool match; - - /* colour | IDENT (inherit) */ - token= parserutils_vector_peek(vector, *ctx); - if (token == NULL) { - *ctx = orig_ctx; - return CSS_INVALID; - } - - if (token->type == CSS_TOKEN_IDENT && - (lwc_string_caseless_isequal( - token->idata, c->strings[INHERIT], - &match) == lwc_error_ok && match)) { - parserutils_vector_iterate(vector, ctx); - flags |= FLAG_INHERIT; - } else { - error = parse_colour_specifier(c, vector, ctx, &colour); - if (error != CSS_OK) { - *ctx = orig_ctx; - return error; - } - - value = COLOR_SET; - } - - opv = buildOPV(CSS_PROP_COLOR, flags, value); - - required_size = sizeof(opv); - if ((flags & FLAG_INHERIT) == false && value == COLOR_SET) - required_size += sizeof(colour); - - /* Allocate result */ - error = css_stylesheet_style_create(c->sheet, required_size, result); - if (error != CSS_OK) { - *ctx = orig_ctx; - return error; - } - - /* Copy the bytecode to it */ - memcpy((*result)->bytecode, &opv, sizeof(opv)); - if ((flags & FLAG_INHERIT) == false && value == COLOR_SET) { - memcpy(((uint8_t *) (*result)->bytecode) + sizeof(opv), - &colour, sizeof(colour)); - } - - return CSS_OK; -} - -/** - * Parse direction - * - * \param c Parsing context - * \param vector Vector of tokens to process - * \param ctx Pointer to vector iteration context - * \param result Pointer to location to receive resulting style - * \return CSS_OK on success, - * CSS_NOMEM on memory exhaustion, - * CSS_INVALID if the input is not valid - * - * Post condition: \a *ctx is updated with the next token to process - * If the input is invalid, then \a *ctx remains unchanged. - */ -css_error parse_direction(css_language *c, - const parserutils_vector *vector, int *ctx, - css_style **result) -{ - int orig_ctx = *ctx; - css_error error; - const css_token *ident; - uint8_t flags = 0; - uint16_t value = 0; - uint32_t opv; - bool match; - - /* IDENT (ltr, rtl, inherit) */ - ident = parserutils_vector_iterate(vector, ctx); - if (ident == NULL || ident->type != CSS_TOKEN_IDENT) { - *ctx = orig_ctx; - return CSS_INVALID; - } - - if ((lwc_string_caseless_isequal( - ident->idata, c->strings[INHERIT], - &match) == lwc_error_ok && match)) { - flags |= FLAG_INHERIT; - } else if ((lwc_string_caseless_isequal( - ident->idata, c->strings[LTR], - &match) == lwc_error_ok && match)) { - value = DIRECTION_LTR; - } else if ((lwc_string_caseless_isequal( - ident->idata, c->strings[RTL], - &match) == lwc_error_ok && match)) { - value = DIRECTION_RTL; - } else { - *ctx = orig_ctx; - return CSS_INVALID; - } - - opv = buildOPV(CSS_PROP_DIRECTION, flags, value); - - /* Allocate result */ - error = css_stylesheet_style_create(c->sheet, sizeof(opv), result); - if (error != CSS_OK) { - *ctx = orig_ctx; - return error; - } - - /* Copy the bytecode to it */ - memcpy((*result)->bytecode, &opv, sizeof(opv)); - - return CSS_OK; -} - -/** - * Parse letter-spacing - * - * \param c Parsing context - * \param vector Vector of tokens to process - * \param ctx Pointer to vector iteration context - * \param result Pointer to location to receive resulting style - * \return CSS_OK on success, - * CSS_NOMEM on memory exhaustion, - * CSS_INVALID if the input is not valid - * - * Post condition: \a *ctx is updated with the next token to process - * If the input is invalid, then \a *ctx remains unchanged. - */ -css_error parse_letter_spacing(css_language *c, - const parserutils_vector *vector, int *ctx, - css_style **result) -{ - int orig_ctx = *ctx; - css_error error; - const css_token *token; - uint8_t flags = 0; - uint16_t value = 0; - uint32_t opv; - css_fixed length = 0; - uint32_t unit = 0; - uint32_t required_size; - bool match; - - /* length | IDENT(normal, inherit) */ - token = parserutils_vector_peek(vector, *ctx); - if (token == NULL) { - *ctx = orig_ctx; - return CSS_INVALID; - } - - if (token->type == CSS_TOKEN_IDENT && - (lwc_string_caseless_isequal( - token->idata, c->strings[INHERIT], - &match) == lwc_error_ok && match)) { - parserutils_vector_iterate(vector, ctx); - flags = FLAG_INHERIT; - } else if (token->type == CSS_TOKEN_IDENT && - (lwc_string_caseless_isequal( - token->idata, c->strings[NORMAL], - &match) == lwc_error_ok && match)) { - parserutils_vector_iterate(vector, ctx); - value = LETTER_SPACING_NORMAL; - } else { - error = parse_unit_specifier(c, vector, ctx, UNIT_PX, - &length, &unit); - if (error != CSS_OK) { - *ctx = orig_ctx; - return error; - } - - if (unit & UNIT_ANGLE || unit & UNIT_TIME || unit & UNIT_FREQ || - unit & UNIT_PCT) { - *ctx = orig_ctx; - return CSS_INVALID; - } - - value = LETTER_SPACING_SET; - } - - opv = buildOPV(CSS_PROP_LETTER_SPACING, flags, value); - - required_size = sizeof(opv); - if ((flags & FLAG_INHERIT) == false && value == LETTER_SPACING_SET) - required_size += sizeof(length) + sizeof(unit); - - /* Allocate result */ - error = css_stylesheet_style_create(c->sheet, required_size, result); - if (error != CSS_OK) { - *ctx = orig_ctx; - return error; - } - - /* Copy the bytecode to it */ - memcpy((*result)->bytecode, &opv, sizeof(opv)); - if ((flags & FLAG_INHERIT) == false && value == LETTER_SPACING_SET) { - memcpy(((uint8_t *) (*result)->bytecode) + sizeof(opv), - &length, sizeof(length)); - memcpy(((uint8_t *) (*result)->bytecode) + sizeof(opv) + - sizeof(length), &unit, sizeof(unit)); - } - - return CSS_OK; -} - -/** - * Parse text-align - * - * \param c Parsing context - * \param vector Vector of tokens to process - * \param ctx Pointer to vector iteration context - * \param result Pointer to location to receive resulting style - * \return CSS_OK on success, - * CSS_NOMEM on memory exhaustion, - * CSS_INVALID if the input is not valid - * - * Post condition: \a *ctx is updated with the next token to process - * If the input is invalid, then \a *ctx remains unchanged. - */ -css_error parse_text_align(css_language *c, - const parserutils_vector *vector, int *ctx, - css_style **result) -{ - int orig_ctx = *ctx; - css_error error; - const css_token *ident; - uint8_t flags = 0; - uint16_t value = 0; - uint32_t opv; - bool match; - - /* IDENT (left, right, center, justify, -libcss-left, -libcss-center, - * -libcss-right, inherit) */ - ident = parserutils_vector_iterate(vector, ctx); - if (ident == NULL || ident->type != CSS_TOKEN_IDENT) { - *ctx = orig_ctx; - return CSS_INVALID; - } - - if ((lwc_string_caseless_isequal( - ident->idata, c->strings[INHERIT], - &match) == lwc_error_ok && match)) { - flags |= FLAG_INHERIT; - } else if ((lwc_string_caseless_isequal( - ident->idata, c->strings[LEFT], - &match) == lwc_error_ok && match)) { - value = TEXT_ALIGN_LEFT; - } else if ((lwc_string_caseless_isequal( - ident->idata, c->strings[RIGHT], - &match) == lwc_error_ok && match)) { - value = TEXT_ALIGN_RIGHT; - } else if ((lwc_string_caseless_isequal( - ident->idata, c->strings[CENTER], - &match) == lwc_error_ok && match)) { - value = TEXT_ALIGN_CENTER; - } else if ((lwc_string_caseless_isequal( - ident->idata, c->strings[JUSTIFY], - &match) == lwc_error_ok && match)) { - value = TEXT_ALIGN_JUSTIFY; - } else if ((lwc_string_caseless_isequal( - ident->idata, c->strings[LIBCSS_LEFT], - &match) == lwc_error_ok && match)) { - value = TEXT_ALIGN_LIBCSS_LEFT; - } else if ((lwc_string_caseless_isequal( - ident->idata, c->strings[LIBCSS_CENTER], - &match) == lwc_error_ok && match)) { - value = TEXT_ALIGN_LIBCSS_CENTER; - } else if ((lwc_string_caseless_isequal( - ident->idata, c->strings[LIBCSS_RIGHT], - &match) == lwc_error_ok && match)) { - value = TEXT_ALIGN_LIBCSS_RIGHT; - } else { - *ctx = orig_ctx; - return CSS_INVALID; - } - - opv = buildOPV(CSS_PROP_TEXT_ALIGN, flags, value); - - /* Allocate result */ - error = css_stylesheet_style_create(c->sheet, sizeof(opv), result); - if (error != CSS_OK) { - *ctx = orig_ctx; - return error; - } - - /* Copy the bytecode to it */ - memcpy((*result)->bytecode, &opv, sizeof(opv)); - - return CSS_OK; -} - -/** - * Parse text-decoration - * - * \param c Parsing context - * \param vector Vector of tokens to process - * \param ctx Pointer to vector iteration context - * \param result Pointer to location to receive resulting style - * \return CSS_OK on success, - * CSS_NOMEM on memory exhaustion, - * CSS_INVALID if the input is not valid - * - * Post condition: \a *ctx is updated with the next token to process - * If the input is invalid, then \a *ctx remains unchanged. - */ -css_error parse_text_decoration(css_language *c, - const parserutils_vector *vector, int *ctx, - css_style **result) -{ - int orig_ctx = *ctx; - css_error error; - const css_token *ident; - uint8_t flags = 0; - uint16_t value = 0; - uint32_t opv; - bool match; - - /* IDENT([ underline || overline || line-through || blink ]) - * | IDENT (none, inherit) */ - ident = parserutils_vector_iterate(vector, ctx); - if (ident == NULL || ident->type != CSS_TOKEN_IDENT) { - *ctx = orig_ctx; - return CSS_INVALID; - } - - if ((lwc_string_caseless_isequal( - ident->idata, c->strings[INHERIT], - &match) == lwc_error_ok && match)) { - flags |= FLAG_INHERIT; - } else if ((lwc_string_caseless_isequal( - ident->idata, c->strings[NONE], - &match) == lwc_error_ok && match)) { - value = TEXT_DECORATION_NONE; - } else { - while (ident != NULL) { - if ((lwc_string_caseless_isequal( - ident->idata, c->strings[UNDERLINE], - &match) == lwc_error_ok && match)) { - if ((value & TEXT_DECORATION_UNDERLINE) == 0) - value |= TEXT_DECORATION_UNDERLINE; - else { - *ctx = orig_ctx; - return CSS_INVALID; - } - } else if ((lwc_string_caseless_isequal( - ident->idata, c->strings[OVERLINE], - &match) == lwc_error_ok && match)) { - if ((value & TEXT_DECORATION_OVERLINE) == 0) - value |= TEXT_DECORATION_OVERLINE; - else { - *ctx = orig_ctx; - return CSS_INVALID; - } - } else if ((lwc_string_caseless_isequal( - ident->idata, c->strings[LINE_THROUGH], - &match) == lwc_error_ok && match)) { - if ((value & TEXT_DECORATION_LINE_THROUGH) == 0) - value |= TEXT_DECORATION_LINE_THROUGH; - else { - *ctx = orig_ctx; - return CSS_INVALID; - } - } else if ((lwc_string_caseless_isequal( - ident->idata, c->strings[BLINK], - &match) == lwc_error_ok && match)) { - if ((value & TEXT_DECORATION_BLINK) == 0) - value |= TEXT_DECORATION_BLINK; - else { - *ctx = orig_ctx; - return CSS_INVALID; - } - } else { - *ctx = orig_ctx; - return CSS_INVALID; - } - - consumeWhitespace(vector, ctx); - - ident = parserutils_vector_peek(vector, *ctx); - if (ident != NULL && ident->type != CSS_TOKEN_IDENT) - break; - ident = parserutils_vector_iterate(vector, ctx); - } - } - - opv = buildOPV(CSS_PROP_TEXT_DECORATION, flags, value); - - /* Allocate result */ - error = css_stylesheet_style_create(c->sheet, sizeof(opv), result); - if (error != CSS_OK) { - *ctx = orig_ctx; - return error; - } - - /* Copy the bytecode to it */ - memcpy((*result)->bytecode, &opv, sizeof(opv)); - - return CSS_OK; -} - -/** - * Parse text-indent - * - * \param c Parsing context - * \param vector Vector of tokens to process - * \param ctx Pointer to vector iteration context - * \param result Pointer to location to receive resulting style - * \return CSS_OK on success, - * CSS_NOMEM on memory exhaustion, - * CSS_INVALID if the input is not valid - * - * Post condition: \a *ctx is updated with the next token to process - * If the input is invalid, then \a *ctx remains unchanged. - */ -css_error parse_text_indent(css_language *c, - const parserutils_vector *vector, int *ctx, - css_style **result) -{ - int orig_ctx = *ctx; - css_error error; - const css_token *token; - uint8_t flags = 0; - uint16_t value = 0; - uint32_t opv; - css_fixed length = 0; - uint32_t unit = 0; - uint32_t required_size; - bool match; - - /* length | percentage | IDENT(inherit) */ - token = parserutils_vector_peek(vector, *ctx); - if (token == NULL) { - *ctx = orig_ctx; - return CSS_INVALID; - } - - if (token->type == CSS_TOKEN_IDENT && - (lwc_string_caseless_isequal( - token->idata, c->strings[INHERIT], - &match) == lwc_error_ok && match)) { - parserutils_vector_iterate(vector, ctx); - flags = FLAG_INHERIT; - } else { - error = parse_unit_specifier(c, vector, ctx, UNIT_PX, - &length, &unit); - if (error != CSS_OK) { - *ctx = orig_ctx; - return error; - } - - if (unit & UNIT_ANGLE || unit & UNIT_TIME || unit & UNIT_FREQ) { - *ctx = orig_ctx; - return CSS_INVALID; - } - - value = TEXT_INDENT_SET; - } - - opv = buildOPV(CSS_PROP_TEXT_INDENT, flags, value); - - required_size = sizeof(opv); - if ((flags & FLAG_INHERIT) == false && value == TEXT_INDENT_SET) - required_size += sizeof(length) + sizeof(unit); - - /* Allocate result */ - error = css_stylesheet_style_create(c->sheet, required_size, result); - if (error != CSS_OK) { - *ctx = orig_ctx; - return error; - } - - /* Copy the bytecode to it */ - memcpy((*result)->bytecode, &opv, sizeof(opv)); - if ((flags & FLAG_INHERIT) == false && value == TEXT_INDENT_SET) { - memcpy(((uint8_t *) (*result)->bytecode) + sizeof(opv), - &length, sizeof(length)); - memcpy(((uint8_t *) (*result)->bytecode) + sizeof(opv) + - sizeof(length), &unit, sizeof(unit)); - } - - return CSS_OK; -} - -/** - * Parse text-transform - * - * \param c Parsing context - * \param vector Vector of tokens to process - * \param ctx Pointer to vector iteration context - * \param result Pointer to location to receive resulting style - * \return CSS_OK on success, - * CSS_NOMEM on memory exhaustion, - * CSS_INVALID if the input is not valid - * - * Post condition: \a *ctx is updated with the next token to process - * If the input is invalid, then \a *ctx remains unchanged. - */ -css_error parse_text_transform(css_language *c, - const parserutils_vector *vector, int *ctx, - css_style **result) -{ - int orig_ctx = *ctx; - css_error error; - const css_token *ident; - uint8_t flags = 0; - uint16_t value = 0; - uint32_t opv; - bool match; - - /* IDENT (capitalize, uppercase, lowercase, none, inherit) */ - ident = parserutils_vector_iterate(vector, ctx); - if (ident == NULL || ident->type != CSS_TOKEN_IDENT) { - *ctx = orig_ctx; - return CSS_INVALID; - } - - if ((lwc_string_caseless_isequal( - ident->idata, c->strings[INHERIT], - &match) == lwc_error_ok && match)) { - flags |= FLAG_INHERIT; - } else if ((lwc_string_caseless_isequal( - ident->idata, c->strings[CAPITALIZE], - &match) == lwc_error_ok && match)) { - value = TEXT_TRANSFORM_CAPITALIZE; - } else if ((lwc_string_caseless_isequal( - ident->idata, c->strings[UPPERCASE], - &match) == lwc_error_ok && match)) { - value = TEXT_TRANSFORM_UPPERCASE; - } else if ((lwc_string_caseless_isequal( - ident->idata, c->strings[LOWERCASE], - &match) == lwc_error_ok && match)) { - value = TEXT_TRANSFORM_LOWERCASE; - } else if ((lwc_string_caseless_isequal( - ident->idata, c->strings[NONE], - &match) == lwc_error_ok && match)) { - value = TEXT_TRANSFORM_NONE; - } else { - *ctx = orig_ctx; - return CSS_INVALID; - } - - opv = buildOPV(CSS_PROP_TEXT_TRANSFORM, flags, value); - - /* Allocate result */ - error = css_stylesheet_style_create(c->sheet, sizeof(opv), result); - if (error != CSS_OK) { - *ctx = orig_ctx; - return error; - } - - /* Copy the bytecode to it */ - memcpy((*result)->bytecode, &opv, sizeof(opv)); - - return CSS_OK; -} - -/** - * Parse unicode-bidi - * - * \param c Parsing context - * \param vector Vector of tokens to process - * \param ctx Pointer to vector iteration context - * \param result Pointer to location to receive resulting style - * \return CSS_OK on success, - * CSS_NOMEM on memory exhaustion, - * CSS_INVALID if the input is not valid - * - * Post condition: \a *ctx is updated with the next token to process - * If the input is invalid, then \a *ctx remains unchanged. - */ -css_error parse_unicode_bidi(css_language *c, - const parserutils_vector *vector, int *ctx, - css_style **result) -{ - int orig_ctx = *ctx; - css_error error; - const css_token *ident; - uint8_t flags = 0; - uint16_t value = 0; - uint32_t opv; - bool match; - - /* IDENT (normal, embed, bidi-override, inherit) */ - ident = parserutils_vector_iterate(vector, ctx); - if (ident == NULL || ident->type != CSS_TOKEN_IDENT) { - *ctx = orig_ctx; - return CSS_INVALID; - } - - if ((lwc_string_caseless_isequal( - ident->idata, c->strings[INHERIT], - &match) == lwc_error_ok && match)) { - flags |= FLAG_INHERIT; - } else if ((lwc_string_caseless_isequal( - ident->idata, c->strings[NORMAL], - &match) == lwc_error_ok && match)) { - value = UNICODE_BIDI_NORMAL; - } else if ((lwc_string_caseless_isequal( - ident->idata, c->strings[EMBED], - &match) == lwc_error_ok && match)) { - value = UNICODE_BIDI_EMBED; - } else if ((lwc_string_caseless_isequal( - ident->idata, c->strings[BIDI_OVERRIDE], - &match) == lwc_error_ok && match)) { - value = UNICODE_BIDI_BIDI_OVERRIDE; - } else { - *ctx = orig_ctx; - return CSS_INVALID; - } - - opv = buildOPV(CSS_PROP_UNICODE_BIDI, flags, value); - - /* Allocate result */ - error = css_stylesheet_style_create(c->sheet, sizeof(opv), result); - if (error != CSS_OK) { - *ctx = orig_ctx; - return error; - } - - /* Copy the bytecode to it */ - memcpy((*result)->bytecode, &opv, sizeof(opv)); - - return CSS_OK; -} - -/** - * Parse white-space - * - * \param c Parsing context - * \param vector Vector of tokens to process - * \param ctx Pointer to vector iteration context - * \param result Pointer to location to receive resulting style - * \return CSS_OK on success, - * CSS_NOMEM on memory exhaustion, - * CSS_INVALID if the input is not valid - * - * Post condition: \a *ctx is updated with the next token to process - * If the input is invalid, then \a *ctx remains unchanged. - */ -css_error parse_white_space(css_language *c, - const parserutils_vector *vector, int *ctx, - css_style **result) -{ - int orig_ctx = *ctx; - css_error error; - const css_token *ident; - uint8_t flags = 0; - uint16_t value = 0; - uint32_t opv; - bool match; - - /* IDENT (normal, pre, nowrap, pre-wrap, pre-line, inherit) */ - ident = parserutils_vector_iterate(vector, ctx); - if (ident == NULL || ident->type != CSS_TOKEN_IDENT) { - *ctx = orig_ctx; - return CSS_INVALID; - } - - if ((lwc_string_caseless_isequal( - ident->idata, c->strings[INHERIT], - &match) == lwc_error_ok && match)) { - flags |= FLAG_INHERIT; - } else if ((lwc_string_caseless_isequal( - ident->idata, c->strings[NORMAL], - &match) == lwc_error_ok && match)) { - value = WHITE_SPACE_NORMAL; - } else if ((lwc_string_caseless_isequal( - ident->idata, c->strings[PRE], - &match) == lwc_error_ok && match)) { - value = WHITE_SPACE_PRE; - } else if ((lwc_string_caseless_isequal( - ident->idata, c->strings[NOWRAP], - &match) == lwc_error_ok && match)) { - value = WHITE_SPACE_NOWRAP; - } else if ((lwc_string_caseless_isequal( - ident->idata, c->strings[PRE_WRAP], - &match) == lwc_error_ok && match)) { - value = WHITE_SPACE_PRE_WRAP; - } else if ((lwc_string_caseless_isequal( - ident->idata, c->strings[PRE_LINE], - &match) == lwc_error_ok && match)) { - value = WHITE_SPACE_PRE_LINE; - } else { - *ctx = orig_ctx; - return CSS_INVALID; - } - - opv = buildOPV(CSS_PROP_WHITE_SPACE, flags, value); - - /* Allocate result */ - error = css_stylesheet_style_create(c->sheet, sizeof(opv), result); - if (error != CSS_OK) { - *ctx = orig_ctx; - return error; - } - - /* Copy the bytecode to it */ - memcpy((*result)->bytecode, &opv, sizeof(opv)); - - return CSS_OK; -} - -/** - * Parse word-spacing - * - * \param c Parsing context - * \param vector Vector of tokens to process - * \param ctx Pointer to vector iteration context - * \param result Pointer to location to receive resulting style - * \return CSS_OK on success, - * CSS_NOMEM on memory exhaustion, - * CSS_INVALID if the input is not valid - * - * Post condition: \a *ctx is updated with the next token to process - * If the input is invalid, then \a *ctx remains unchanged. - */ -css_error parse_word_spacing(css_language *c, - const parserutils_vector *vector, int *ctx, - css_style **result) -{ - int orig_ctx = *ctx; - css_error error; - const css_token *token; - uint8_t flags = 0; - uint16_t value = 0; - uint32_t opv; - css_fixed length = 0; - uint32_t unit = 0; - uint32_t required_size; - bool match; - - /* length | IDENT(normal, inherit) */ - token = parserutils_vector_peek(vector, *ctx); - if (token == NULL) { - *ctx = orig_ctx; - return CSS_INVALID; - } - - if (token->type == CSS_TOKEN_IDENT && - (lwc_string_caseless_isequal( - token->idata, c->strings[INHERIT], - &match) == lwc_error_ok && match)) { - parserutils_vector_iterate(vector, ctx); - flags = FLAG_INHERIT; - } else if (token->type == CSS_TOKEN_IDENT && - (lwc_string_caseless_isequal( - token->idata, c->strings[NORMAL], - &match) == lwc_error_ok && match)) { - parserutils_vector_iterate(vector, ctx); - value = WORD_SPACING_NORMAL; - } else { - error = parse_unit_specifier(c, vector, ctx, UNIT_PX, - &length, &unit); - if (error != CSS_OK) { - *ctx = orig_ctx; - return error; - } - - if (unit & UNIT_ANGLE || unit & UNIT_TIME || unit & UNIT_FREQ || - unit & UNIT_PCT) { - *ctx = orig_ctx; - return CSS_INVALID; - } - - value = WORD_SPACING_SET; - } - - opv = buildOPV(CSS_PROP_WORD_SPACING, flags, value); - - required_size = sizeof(opv); - if ((flags & FLAG_INHERIT) == false && value == WORD_SPACING_SET) - required_size += sizeof(length) + sizeof(unit); - - /* Allocate result */ - error = css_stylesheet_style_create(c->sheet, required_size, result); - if (error != CSS_OK) { - *ctx = orig_ctx; - return error; - } - - /* Copy the bytecode to it */ - memcpy((*result)->bytecode, &opv, sizeof(opv)); - if ((flags & FLAG_INHERIT) == false && value == WORD_SPACING_SET) { - memcpy(((uint8_t *) (*result)->bytecode) + sizeof(opv), - &length, sizeof(length)); - memcpy(((uint8_t *) (*result)->bytecode) + sizeof(opv) + - sizeof(length), &unit, sizeof(unit)); - } - - return CSS_OK; -} - diff --git a/src/parse/properties/text_align.c b/src/parse/properties/text_align.c new file mode 100644 index 0000000..0df4eab --- /dev/null +++ b/src/parse/properties/text_align.c @@ -0,0 +1,100 @@ +/* + * This file is part of LibCSS. + * Licensed under the MIT License, + * http://www.opensource.org/licenses/mit-license.php + * Copyright 2009 John-Mark Bell + */ + +#include +#include + +#include "bytecode/bytecode.h" +#include "bytecode/opcodes.h" +#include "parse/properties/properties.h" +#include "parse/properties/utils.h" + +/** + * Parse text-align + * + * \param c Parsing context + * \param vector Vector of tokens to process + * \param ctx Pointer to vector iteration context + * \param result Pointer to location to receive resulting style + * \return CSS_OK on success, + * CSS_NOMEM on memory exhaustion, + * CSS_INVALID if the input is not valid + * + * Post condition: \a *ctx is updated with the next token to process + * If the input is invalid, then \a *ctx remains unchanged. + */ +css_error parse_text_align(css_language *c, + const parserutils_vector *vector, int *ctx, + css_style **result) +{ + int orig_ctx = *ctx; + css_error error; + const css_token *ident; + uint8_t flags = 0; + uint16_t value = 0; + uint32_t opv; + bool match; + + /* IDENT (left, right, center, justify, -libcss-left, -libcss-center, + * -libcss-right, inherit) */ + ident = parserutils_vector_iterate(vector, ctx); + if (ident == NULL || ident->type != CSS_TOKEN_IDENT) { + *ctx = orig_ctx; + return CSS_INVALID; + } + + if ((lwc_string_caseless_isequal( + ident->idata, c->strings[INHERIT], + &match) == lwc_error_ok && match)) { + flags |= FLAG_INHERIT; + } else if ((lwc_string_caseless_isequal( + ident->idata, c->strings[LEFT], + &match) == lwc_error_ok && match)) { + value = TEXT_ALIGN_LEFT; + } else if ((lwc_string_caseless_isequal( + ident->idata, c->strings[RIGHT], + &match) == lwc_error_ok && match)) { + value = TEXT_ALIGN_RIGHT; + } else if ((lwc_string_caseless_isequal( + ident->idata, c->strings[CENTER], + &match) == lwc_error_ok && match)) { + value = TEXT_ALIGN_CENTER; + } else if ((lwc_string_caseless_isequal( + ident->idata, c->strings[JUSTIFY], + &match) == lwc_error_ok && match)) { + value = TEXT_ALIGN_JUSTIFY; + } else if ((lwc_string_caseless_isequal( + ident->idata, c->strings[LIBCSS_LEFT], + &match) == lwc_error_ok && match)) { + value = TEXT_ALIGN_LIBCSS_LEFT; + } else if ((lwc_string_caseless_isequal( + ident->idata, c->strings[LIBCSS_CENTER], + &match) == lwc_error_ok && match)) { + value = TEXT_ALIGN_LIBCSS_CENTER; + } else if ((lwc_string_caseless_isequal( + ident->idata, c->strings[LIBCSS_RIGHT], + &match) == lwc_error_ok && match)) { + value = TEXT_ALIGN_LIBCSS_RIGHT; + } else { + *ctx = orig_ctx; + return CSS_INVALID; + } + + opv = buildOPV(CSS_PROP_TEXT_ALIGN, flags, value); + + /* Allocate result */ + error = css_stylesheet_style_create(c->sheet, sizeof(opv), result); + if (error != CSS_OK) { + *ctx = orig_ctx; + return error; + } + + /* Copy the bytecode to it */ + memcpy((*result)->bytecode, &opv, sizeof(opv)); + + return CSS_OK; +} diff --git a/src/parse/properties/text_decoration.c b/src/parse/properties/text_decoration.c new file mode 100644 index 0000000..0c63c39 --- /dev/null +++ b/src/parse/properties/text_decoration.c @@ -0,0 +1,123 @@ +/* + * This file is part of LibCSS. + * Licensed under the MIT License, + * http://www.opensource.org/licenses/mit-license.php + * Copyright 2009 John-Mark Bell + */ + +#include +#include + +#include "bytecode/bytecode.h" +#include "bytecode/opcodes.h" +#include "parse/properties/properties.h" +#include "parse/properties/utils.h" + +/** + * Parse text-decoration + * + * \param c Parsing context + * \param vector Vector of tokens to process + * \param ctx Pointer to vector iteration context + * \param result Pointer to location to receive resulting style + * \return CSS_OK on success, + * CSS_NOMEM on memory exhaustion, + * CSS_INVALID if the input is not valid + * + * Post condition: \a *ctx is updated with the next token to process + * If the input is invalid, then \a *ctx remains unchanged. + */ +css_error parse_text_decoration(css_language *c, + const parserutils_vector *vector, int *ctx, + css_style **result) +{ + int orig_ctx = *ctx; + css_error error; + const css_token *ident; + uint8_t flags = 0; + uint16_t value = 0; + uint32_t opv; + bool match; + + /* IDENT([ underline || overline || line-through || blink ]) + * | IDENT (none, inherit) */ + ident = parserutils_vector_iterate(vector, ctx); + if (ident == NULL || ident->type != CSS_TOKEN_IDENT) { + *ctx = orig_ctx; + return CSS_INVALID; + } + + if ((lwc_string_caseless_isequal( + ident->idata, c->strings[INHERIT], + &match) == lwc_error_ok && match)) { + flags |= FLAG_INHERIT; + } else if ((lwc_string_caseless_isequal( + ident->idata, c->strings[NONE], + &match) == lwc_error_ok && match)) { + value = TEXT_DECORATION_NONE; + } else { + while (ident != NULL) { + if ((lwc_string_caseless_isequal( + ident->idata, c->strings[UNDERLINE], + &match) == lwc_error_ok && match)) { + if ((value & TEXT_DECORATION_UNDERLINE) == 0) + value |= TEXT_DECORATION_UNDERLINE; + else { + *ctx = orig_ctx; + return CSS_INVALID; + } + } else if ((lwc_string_caseless_isequal( + ident->idata, c->strings[OVERLINE], + &match) == lwc_error_ok && match)) { + if ((value & TEXT_DECORATION_OVERLINE) == 0) + value |= TEXT_DECORATION_OVERLINE; + else { + *ctx = orig_ctx; + return CSS_INVALID; + } + } else if ((lwc_string_caseless_isequal( + ident->idata, c->strings[LINE_THROUGH], + &match) == lwc_error_ok && match)) { + if ((value & TEXT_DECORATION_LINE_THROUGH) == 0) + value |= TEXT_DECORATION_LINE_THROUGH; + else { + *ctx = orig_ctx; + return CSS_INVALID; + } + } else if ((lwc_string_caseless_isequal( + ident->idata, c->strings[BLINK], + &match) == lwc_error_ok && match)) { + if ((value & TEXT_DECORATION_BLINK) == 0) + value |= TEXT_DECORATION_BLINK; + else { + *ctx = orig_ctx; + return CSS_INVALID; + } + } else { + *ctx = orig_ctx; + return CSS_INVALID; + } + + consumeWhitespace(vector, ctx); + + ident = parserutils_vector_peek(vector, *ctx); + if (ident != NULL && ident->type != CSS_TOKEN_IDENT) + break; + ident = parserutils_vector_iterate(vector, ctx); + } + } + + opv = buildOPV(CSS_PROP_TEXT_DECORATION, flags, value); + + /* Allocate result */ + error = css_stylesheet_style_create(c->sheet, sizeof(opv), result); + if (error != CSS_OK) { + *ctx = orig_ctx; + return error; + } + + /* Copy the bytecode to it */ + memcpy((*result)->bytecode, &opv, sizeof(opv)); + + return CSS_OK; +} diff --git a/src/parse/properties/text_indent.c b/src/parse/properties/text_indent.c new file mode 100644 index 0000000..4198cf6 --- /dev/null +++ b/src/parse/properties/text_indent.c @@ -0,0 +1,97 @@ +/* + * This file is part of LibCSS. + * Licensed under the MIT License, + * http://www.opensource.org/licenses/mit-license.php + * Copyright 2009 John-Mark Bell + */ + +#include +#include + +#include "bytecode/bytecode.h" +#include "bytecode/opcodes.h" +#include "parse/properties/properties.h" +#include "parse/properties/utils.h" + +/** + * Parse text-indent + * + * \param c Parsing context + * \param vector Vector of tokens to process + * \param ctx Pointer to vector iteration context + * \param result Pointer to location to receive resulting style + * \return CSS_OK on success, + * CSS_NOMEM on memory exhaustion, + * CSS_INVALID if the input is not valid + * + * Post condition: \a *ctx is updated with the next token to process + * If the input is invalid, then \a *ctx remains unchanged. + */ +css_error parse_text_indent(css_language *c, + const parserutils_vector *vector, int *ctx, + css_style **result) +{ + int orig_ctx = *ctx; + css_error error; + const css_token *token; + uint8_t flags = 0; + uint16_t value = 0; + uint32_t opv; + css_fixed length = 0; + uint32_t unit = 0; + uint32_t required_size; + bool match; + + /* length | percentage | IDENT(inherit) */ + token = parserutils_vector_peek(vector, *ctx); + if (token == NULL) { + *ctx = orig_ctx; + return CSS_INVALID; + } + + if (token->type == CSS_TOKEN_IDENT && + (lwc_string_caseless_isequal( + token->idata, c->strings[INHERIT], + &match) == lwc_error_ok && match)) { + parserutils_vector_iterate(vector, ctx); + flags = FLAG_INHERIT; + } else { + error = parse_unit_specifier(c, vector, ctx, UNIT_PX, + &length, &unit); + if (error != CSS_OK) { + *ctx = orig_ctx; + return error; + } + + if (unit & UNIT_ANGLE || unit & UNIT_TIME || unit & UNIT_FREQ) { + *ctx = orig_ctx; + return CSS_INVALID; + } + + value = TEXT_INDENT_SET; + } + + opv = buildOPV(CSS_PROP_TEXT_INDENT, flags, value); + + required_size = sizeof(opv); + if ((flags & FLAG_INHERIT) == false && value == TEXT_INDENT_SET) + required_size += sizeof(length) + sizeof(unit); + + /* Allocate result */ + error = css_stylesheet_style_create(c->sheet, required_size, result); + if (error != CSS_OK) { + *ctx = orig_ctx; + return error; + } + + /* Copy the bytecode to it */ + memcpy((*result)->bytecode, &opv, sizeof(opv)); + if ((flags & FLAG_INHERIT) == false && value == TEXT_INDENT_SET) { + memcpy(((uint8_t *) (*result)->bytecode) + sizeof(opv), + &length, sizeof(length)); + memcpy(((uint8_t *) (*result)->bytecode) + sizeof(opv) + + sizeof(length), &unit, sizeof(unit)); + } + + return CSS_OK; +} diff --git a/src/parse/properties/text_transform.c b/src/parse/properties/text_transform.c new file mode 100644 index 0000000..b727046 --- /dev/null +++ b/src/parse/properties/text_transform.c @@ -0,0 +1,87 @@ +/* + * This file is part of LibCSS. + * Licensed under the MIT License, + * http://www.opensource.org/licenses/mit-license.php + * Copyright 2009 John-Mark Bell + */ + +#include +#include + +#include "bytecode/bytecode.h" +#include "bytecode/opcodes.h" +#include "parse/properties/properties.h" +#include "parse/properties/utils.h" + +/** + * Parse text-transform + * + * \param c Parsing context + * \param vector Vector of tokens to process + * \param ctx Pointer to vector iteration context + * \param result Pointer to location to receive resulting style + * \return CSS_OK on success, + * CSS_NOMEM on memory exhaustion, + * CSS_INVALID if the input is not valid + * + * Post condition: \a *ctx is updated with the next token to process + * If the input is invalid, then \a *ctx remains unchanged. + */ +css_error parse_text_transform(css_language *c, + const parserutils_vector *vector, int *ctx, + css_style **result) +{ + int orig_ctx = *ctx; + css_error error; + const css_token *ident; + uint8_t flags = 0; + uint16_t value = 0; + uint32_t opv; + bool match; + + /* IDENT (capitalize, uppercase, lowercase, none, inherit) */ + ident = parserutils_vector_iterate(vector, ctx); + if (ident == NULL || ident->type != CSS_TOKEN_IDENT) { + *ctx = orig_ctx; + return CSS_INVALID; + } + + if ((lwc_string_caseless_isequal( + ident->idata, c->strings[INHERIT], + &match) == lwc_error_ok && match)) { + flags |= FLAG_INHERIT; + } else if ((lwc_string_caseless_isequal( + ident->idata, c->strings[CAPITALIZE], + &match) == lwc_error_ok && match)) { + value = TEXT_TRANSFORM_CAPITALIZE; + } else if ((lwc_string_caseless_isequal( + ident->idata, c->strings[UPPERCASE], + &match) == lwc_error_ok && match)) { + value = TEXT_TRANSFORM_UPPERCASE; + } else if ((lwc_string_caseless_isequal( + ident->idata, c->strings[LOWERCASE], + &match) == lwc_error_ok && match)) { + value = TEXT_TRANSFORM_LOWERCASE; + } else if ((lwc_string_caseless_isequal( + ident->idata, c->strings[NONE], + &match) == lwc_error_ok && match)) { + value = TEXT_TRANSFORM_NONE; + } else { + *ctx = orig_ctx; + return CSS_INVALID; + } + + opv = buildOPV(CSS_PROP_TEXT_TRANSFORM, flags, value); + + /* Allocate result */ + error = css_stylesheet_style_create(c->sheet, sizeof(opv), result); + if (error != CSS_OK) { + *ctx = orig_ctx; + return error; + } + + /* Copy the bytecode to it */ + memcpy((*result)->bytecode, &opv, sizeof(opv)); + + return CSS_OK; +} diff --git a/src/parse/properties/top.c b/src/parse/properties/top.c new file mode 100644 index 0000000..7325a24 --- /dev/null +++ b/src/parse/properties/top.c @@ -0,0 +1,35 @@ +/* + * This file is part of LibCSS. + * Licensed under the MIT License, + * http://www.opensource.org/licenses/mit-license.php + * Copyright 2009 John-Mark Bell + */ + +#include +#include + +#include "bytecode/bytecode.h" +#include "bytecode/opcodes.h" +#include "parse/properties/properties.h" +#include "parse/properties/utils.h" + +/** + * Parse top + * + * \param c Parsing context + * \param vector Vector of tokens to process + * \param ctx Pointer to vector iteration context + * \param result Pointer to location to receive resulting style + * \return CSS_OK on success, + * CSS_NOMEM on memory exhaustion, + * CSS_INVALID if the input is not valid + * + * Post condition: \a *ctx is updated with the next token to process + * If the input is invalid, then \a *ctx remains unchanged. + */ +css_error parse_top(css_language *c, + const parserutils_vector *vector, int *ctx, + css_style **result) +{ + return parse_side(c, vector, ctx, CSS_PROP_TOP, result); +} diff --git a/src/parse/properties/ui.c b/src/parse/properties/ui.c deleted file mode 100644 index 725e7b7..0000000 --- a/src/parse/properties/ui.c +++ /dev/null @@ -1,373 +0,0 @@ -/* - * This file is part of LibCSS. - * Licensed under the MIT License, - * http://www.opensource.org/licenses/mit-license.php - * Copyright 2009 John-Mark Bell - */ - -#include - -#include "bytecode/bytecode.h" -#include "bytecode/opcodes.h" -#include "parse/properties/properties.h" -#include "parse/properties/utils.h" - -/** - * Parse cursor - * - * \param c Parsing context - * \param vector Vector of tokens to process - * \param ctx Pointer to vector iteration context - * \param result Pointer to location to receive resulting style - * \return CSS_OK on success, - * CSS_NOMEM on memory exhaustion, - * CSS_INVALID if the input is not valid - * - * Post condition: \a *ctx is updated with the next token to process - * If the input is invalid, then \a *ctx remains unchanged. - */ -css_error parse_cursor(css_language *c, - const parserutils_vector *vector, int *ctx, - css_style **result) -{ - int orig_ctx = *ctx; - css_error error; - const css_token *token; - uint8_t flags = 0; - uint16_t value = 0; - uint32_t opv; - uint32_t required_size = sizeof(opv); - int temp_ctx = *ctx; - uint8_t *ptr; - bool match; - - /* [ (URI ',')* IDENT(auto, crosshair, default, pointer, move, e-resize, - * ne-resize, nw-resize, n-resize, se-resize, sw-resize, - * s-resize, w-resize, text, wait, help, progress) ] - * | IDENT(inherit) - */ - - /* Pass 1: validate input and calculate bytecode size */ - token = parserutils_vector_iterate(vector, &temp_ctx); - if (token == NULL || (token->type != CSS_TOKEN_IDENT && - token->type != CSS_TOKEN_URI)) { - *ctx = orig_ctx; - return CSS_INVALID; - } - - if (token->type == CSS_TOKEN_IDENT && - (lwc_string_caseless_isequal( - token->idata, c->strings[INHERIT], - &match) == lwc_error_ok && match)) { - flags = FLAG_INHERIT; - } else { - bool first = true; - - /* URI* */ - while (token != NULL && token->type == CSS_TOKEN_URI) { - lwc_string *uri = token->idata; - - if (first == false) { - required_size += sizeof(opv); - } else { - value = CURSOR_URI; - } - required_size += sizeof(uri); - - consumeWhitespace(vector, &temp_ctx); - - /* Expect ',' */ - token = parserutils_vector_iterate(vector, &temp_ctx); - if (token == NULL || tokenIsChar(token, ',') == false) { - *ctx = orig_ctx; - return CSS_INVALID; - } - - consumeWhitespace(vector, &temp_ctx); - - /* Expect either URI or IDENT */ - token = parserutils_vector_iterate(vector, &temp_ctx); - if (token == NULL || (token->type != CSS_TOKEN_IDENT && - token->type != CSS_TOKEN_URI)) { - *ctx = orig_ctx; - return CSS_INVALID; - } - - first = false; - } - - /* IDENT */ - if (token != NULL && token->type == CSS_TOKEN_IDENT) { - if ((lwc_string_caseless_isequal( - token->idata, c->strings[AUTO], - &match) == lwc_error_ok && match)) { - if (first) { - value = CURSOR_AUTO; - } - } else if ((lwc_string_caseless_isequal( - token->idata, c->strings[CROSSHAIR], - &match) == lwc_error_ok && match)) { - if (first) { - value = CURSOR_CROSSHAIR; - } - } else if ((lwc_string_caseless_isequal( - token->idata, c->strings[DEFAULT], - &match) == lwc_error_ok && match)) { - if (first) { - value = CURSOR_DEFAULT; - } - } else if ((lwc_string_caseless_isequal( - token->idata, c->strings[POINTER], - &match) == lwc_error_ok && match)) { - if (first) { - value = CURSOR_POINTER; - } - } else if ((lwc_string_caseless_isequal( - token->idata, c->strings[MOVE], - &match) == lwc_error_ok && match)) { - if (first) { - value = CURSOR_MOVE; - } - } else if ((lwc_string_caseless_isequal( - token->idata, c->strings[E_RESIZE], - &match) == lwc_error_ok && match)) { - if (first) { - value = CURSOR_E_RESIZE; - } - } else if ((lwc_string_caseless_isequal( - token->idata, c->strings[NE_RESIZE], - &match) == lwc_error_ok && match)) { - if (first) { - value = CURSOR_NE_RESIZE; - } - } else if ((lwc_string_caseless_isequal( - token->idata, c->strings[NW_RESIZE], - &match) == lwc_error_ok && match)) { - if (first) { - value = CURSOR_NW_RESIZE; - } - } else if ((lwc_string_caseless_isequal( - token->idata, c->strings[N_RESIZE], - &match) == lwc_error_ok && match)) { - if (first) { - value = CURSOR_N_RESIZE; - } - } else if ((lwc_string_caseless_isequal( - token->idata, c->strings[SE_RESIZE], - &match) == lwc_error_ok && match)) { - if (first) { - value = CURSOR_SE_RESIZE; - } - } else if ((lwc_string_caseless_isequal( - token->idata, c->strings[SW_RESIZE], - &match) == lwc_error_ok && match)) { - if (first) { - value = CURSOR_SW_RESIZE; - } - } else if ((lwc_string_caseless_isequal( - token->idata, c->strings[S_RESIZE], - &match) == lwc_error_ok && match)) { - if (first) { - value = CURSOR_S_RESIZE; - } - } else if ((lwc_string_caseless_isequal( - token->idata, c->strings[W_RESIZE], - &match) == lwc_error_ok && match)) { - if (first) { - value = CURSOR_W_RESIZE; - } - } else if ((lwc_string_caseless_isequal( - token->idata, c->strings[LIBCSS_TEXT], - &match) == lwc_error_ok && match)) { - if (first) { - value = CURSOR_TEXT; - } - } else if ((lwc_string_caseless_isequal( - token->idata, c->strings[WAIT], - &match) == lwc_error_ok && match)) { - if (first) { - value = CURSOR_WAIT; - } - } else if ((lwc_string_caseless_isequal( - token->idata, c->strings[HELP], - &match) == lwc_error_ok && match)) { - if (first) { - value = CURSOR_HELP; - } - } else if ((lwc_string_caseless_isequal( - token->idata, c->strings[PROGRESS], - &match) == lwc_error_ok && match)) { - if (first) { - value = CURSOR_PROGRESS; - } - } else { - *ctx = orig_ctx; - return CSS_INVALID; - } - - if (first == false) { - required_size += sizeof(opv); - } - } - } - - opv = buildOPV(CSS_PROP_CURSOR, flags, value); - - /* Allocate result */ - error = css_stylesheet_style_create(c->sheet, required_size, result); - if (error != CSS_OK) { - *ctx = orig_ctx; - return error; - } - - /* Copy OPV to bytecode */ - ptr = (*result)->bytecode; - memcpy(ptr, &opv, sizeof(opv)); - ptr += sizeof(opv); - - /* Pass 2: construct bytecode */ - token = parserutils_vector_iterate(vector, ctx); - if (token == NULL || (token->type != CSS_TOKEN_IDENT && - token->type != CSS_TOKEN_URI)) { - *ctx = orig_ctx; - return CSS_INVALID; - } - - if (token->type == CSS_TOKEN_IDENT && - (lwc_string_caseless_isequal( - token->idata, c->strings[INHERIT], - &match) == lwc_error_ok && match)) { - /* Nothing to do */ - } else { - bool first = true; - - /* URI* */ - while (token != NULL && token->type == CSS_TOKEN_URI) { - lwc_string *uri; - - error = c->sheet->resolve(c->sheet->resolve_pw, - c->sheet->url, - token->idata, &uri); - if (error != CSS_OK) { - *ctx = orig_ctx; - return error; - } - - if (first == false) { - opv = CURSOR_URI; - memcpy(ptr, &opv, sizeof(opv)); - ptr += sizeof(opv); - } - - /* Don't ref URI -- we want to pass ownership to the - * bytecode */ - memcpy(ptr, &uri, sizeof(uri)); - ptr += sizeof(uri); - - consumeWhitespace(vector, ctx); - - /* Expect ',' */ - token = parserutils_vector_iterate(vector, ctx); - if (token == NULL || tokenIsChar(token, ',') == false) { - *ctx = orig_ctx; - return CSS_INVALID; - } - - consumeWhitespace(vector, ctx); - - /* Expect either URI or IDENT */ - token = parserutils_vector_iterate(vector, ctx); - if (token == NULL || (token->type != CSS_TOKEN_IDENT && - token->type != CSS_TOKEN_URI)) { - *ctx = orig_ctx; - return CSS_INVALID; - } - - first = false; - } - - /* IDENT */ - if (token != NULL && token->type == CSS_TOKEN_IDENT) { - if ((lwc_string_caseless_isequal( - token->idata, c->strings[AUTO], - &match) == lwc_error_ok && match)) { - opv = CURSOR_AUTO; - } else if ((lwc_string_caseless_isequal( - token->idata, c->strings[CROSSHAIR], - &match) == lwc_error_ok && match)) { - opv = CURSOR_CROSSHAIR; - } else if ((lwc_string_caseless_isequal( - token->idata, c->strings[DEFAULT], - &match) == lwc_error_ok && match)) { - opv = CURSOR_DEFAULT; - } else if ((lwc_string_caseless_isequal( - token->idata, c->strings[POINTER], - &match) == lwc_error_ok && match)) { - opv = CURSOR_POINTER; - } else if ((lwc_string_caseless_isequal( - token->idata, c->strings[MOVE], - &match) == lwc_error_ok && match)) { - opv = CURSOR_MOVE; - } else if ((lwc_string_caseless_isequal( - token->idata, c->strings[E_RESIZE], - &match) == lwc_error_ok && match)) { - opv = CURSOR_E_RESIZE; - } else if ((lwc_string_caseless_isequal( - token->idata, c->strings[NE_RESIZE], - &match) == lwc_error_ok && match)) { - opv = CURSOR_NE_RESIZE; - } else if ((lwc_string_caseless_isequal( - token->idata, c->strings[NW_RESIZE], - &match) == lwc_error_ok && match)) { - opv = CURSOR_NW_RESIZE; - } else if ((lwc_string_caseless_isequal( - token->idata, c->strings[N_RESIZE], - &match) == lwc_error_ok && match)) { - opv = CURSOR_N_RESIZE; - } else if ((lwc_string_caseless_isequal( - token->idata, c->strings[SE_RESIZE], - &match) == lwc_error_ok && match)) { - opv = CURSOR_SE_RESIZE; - } else if ((lwc_string_caseless_isequal( - token->idata, c->strings[SW_RESIZE], - &match) == lwc_error_ok && match)) { - opv = CURSOR_SW_RESIZE; - } else if ((lwc_string_caseless_isequal( - token->idata, c->strings[S_RESIZE], - &match) == lwc_error_ok && match)) { - opv = CURSOR_S_RESIZE; - } else if ((lwc_string_caseless_isequal( - token->idata, c->strings[W_RESIZE], - &match) == lwc_error_ok && match)) { - opv = CURSOR_W_RESIZE; - } else if ((lwc_string_caseless_isequal( - token->idata, c->strings[LIBCSS_TEXT], - &match) == lwc_error_ok && match)) { - opv = CURSOR_TEXT; - } else if ((lwc_string_caseless_isequal( - token->idata, c->strings[WAIT], - &match) == lwc_error_ok && match)) { - opv = CURSOR_WAIT; - } else if ((lwc_string_caseless_isequal( - token->idata, c->strings[HELP], - &match) == lwc_error_ok && match)) { - opv = CURSOR_HELP; - } else if ((lwc_string_caseless_isequal( - token->idata, c->strings[PROGRESS], - &match) == lwc_error_ok && match)) { - opv = CURSOR_PROGRESS; - } else { - *ctx = orig_ctx; - return CSS_INVALID; - } - - if (first == false) { - memcpy(ptr, &opv, sizeof(opv)); - ptr += sizeof(opv); - } - } - } - - return CSS_OK; -} - diff --git a/src/parse/properties/unicode_bidi.c b/src/parse/properties/unicode_bidi.c new file mode 100644 index 0000000..e960d5e --- /dev/null +++ b/src/parse/properties/unicode_bidi.c @@ -0,0 +1,83 @@ +/* + * This file is part of LibCSS. + * Licensed under the MIT License, + * http://www.opensource.org/licenses/mit-license.php + * Copyright 2009 John-Mark Bell + */ + +#include +#include + +#include "bytecode/bytecode.h" +#include "bytecode/opcodes.h" +#include "parse/properties/properties.h" +#include "parse/properties/utils.h" + +/** + * Parse unicode-bidi + * + * \param c Parsing context + * \param vector Vector of tokens to process + * \param ctx Pointer to vector iteration context + * \param result Pointer to location to receive resulting style + * \return CSS_OK on success, + * CSS_NOMEM on memory exhaustion, + * CSS_INVALID if the input is not valid + * + * Post condition: \a *ctx is updated with the next token to process + * If the input is invalid, then \a *ctx remains unchanged. + */ +css_error parse_unicode_bidi(css_language *c, + const parserutils_vector *vector, int *ctx, + css_style **result) +{ + int orig_ctx = *ctx; + css_error error; + const css_token *ident; + uint8_t flags = 0; + uint16_t value = 0; + uint32_t opv; + bool match; + + /* IDENT (normal, embed, bidi-override, inherit) */ + ident = parserutils_vector_iterate(vector, ctx); + if (ident == NULL || ident->type != CSS_TOKEN_IDENT) { + *ctx = orig_ctx; + return CSS_INVALID; + } + + if ((lwc_string_caseless_isequal( + ident->idata, c->strings[INHERIT], + &match) == lwc_error_ok && match)) { + flags |= FLAG_INHERIT; + } else if ((lwc_string_caseless_isequal( + ident->idata, c->strings[NORMAL], + &match) == lwc_error_ok && match)) { + value = UNICODE_BIDI_NORMAL; + } else if ((lwc_string_caseless_isequal( + ident->idata, c->strings[EMBED], + &match) == lwc_error_ok && match)) { + value = UNICODE_BIDI_EMBED; + } else if ((lwc_string_caseless_isequal( + ident->idata, c->strings[BIDI_OVERRIDE], + &match) == lwc_error_ok && match)) { + value = UNICODE_BIDI_BIDI_OVERRIDE; + } else { + *ctx = orig_ctx; + return CSS_INVALID; + } + + opv = buildOPV(CSS_PROP_UNICODE_BIDI, flags, value); + + /* Allocate result */ + error = css_stylesheet_style_create(c->sheet, sizeof(opv), result); + if (error != CSS_OK) { + *ctx = orig_ctx; + return error; + } + + /* Copy the bytecode to it */ + memcpy((*result)->bytecode, &opv, sizeof(opv)); + + return CSS_OK; +} diff --git a/src/parse/properties/utils.c b/src/parse/properties/utils.c index c1c8b16..f2447a7 100644 --- a/src/parse/properties/utils.c +++ b/src/parse/properties/utils.c @@ -1,17 +1,1552 @@ /* * This file is part of LibCSS. * Licensed under the MIT License, - * http://www.opensource.org/licenses/mit-license.php - * Copyright 2008 John-Mark Bell + * http://www.opensource.org/licenses/mit-license.php + * Copyright 2009 John-Mark Bell */ +#include #include #include "stylesheet.h" #include "bytecode/bytecode.h" #include "bytecode/opcodes.h" +#include "parse/properties/properties.h" #include "parse/properties/utils.h" +/** + * Common parser for pause-after and pause-before + * + * \param c Parsing context + * \param vector Vector of tokens to process + * \param ctx Pointer to vector iteration context + * \param op Opcode to parse for + * \param result Pointer to location to receive resulting style + * \return CSS_OK on success, + * CSS_NOMEM on memory exhaustion, + * CSS_INVALID if the input is not valid + * + * Post condition: \a *ctx is updated with the next token to process + * If the input is invalid, then \a *ctx remains unchanged. + */ +css_error parse_pause_common(css_language *c, + const parserutils_vector *vector, int *ctx, + uint16_t op, css_style **result) +{ + int orig_ctx = *ctx; + css_error error; + const css_token *token; + uint8_t flags = 0; + uint16_t value = 0; + uint32_t opv; + css_fixed length = 0; + uint32_t unit = 0; + uint32_t required_size; + bool match; + + /* time | percentage | IDENT(inherit) */ + token = parserutils_vector_peek(vector, *ctx); + if (token == NULL) { + *ctx = orig_ctx; + return CSS_INVALID; + } + + if (token->type == CSS_TOKEN_IDENT && + (lwc_string_caseless_isequal( + token->idata, c->strings[INHERIT], + &match) == lwc_error_ok && match)) { + parserutils_vector_iterate(vector, ctx); + flags = FLAG_INHERIT; + } else { + error = parse_unit_specifier(c, vector, ctx, UNIT_S, + &length, &unit); + if (error != CSS_OK) { + *ctx = orig_ctx; + return error; + } + + if ((unit & UNIT_TIME) == false && (unit & UNIT_PCT) == false) { + *ctx = orig_ctx; + return CSS_INVALID; + } + + /* Negative values are illegal */ + if (length < 0) { + *ctx = orig_ctx; + return CSS_INVALID; + } + + value = PAUSE_AFTER_SET; + } + + opv = buildOPV(op, flags, value); + + required_size = sizeof(opv); + if ((flags & FLAG_INHERIT) == false && value == PAUSE_AFTER_SET) + required_size += sizeof(length) + sizeof(unit); + + /* Allocate result */ + error = css_stylesheet_style_create(c->sheet, required_size, result); + if (error != CSS_OK) { + *ctx = orig_ctx; + return error; + } + + /* Copy the bytecode to it */ + memcpy((*result)->bytecode, &opv, sizeof(opv)); + if ((flags & FLAG_INHERIT) == false && value == PAUSE_AFTER_SET) { + memcpy(((uint8_t *) (*result)->bytecode) + sizeof(opv), + &length, sizeof(length)); + memcpy(((uint8_t *) (*result)->bytecode) + sizeof(opv) + + sizeof(length), &unit, sizeof(unit)); + } + + return CSS_OK; +} + +/** + * Parse list-style-type value + * + * \param c Parsing context + * \param ident Identifier to consider + * \param value Pointer to location to receive value + * \return CSS_OK on success, + * CSS_INVALID if the input is not valid + */ +css_error parse_list_style_type_value(css_language *c, const css_token *ident, + uint16_t *value) +{ + bool match; + + /* IDENT (disc, circle, square, decimal, decimal-leading-zero, + * lower-roman, upper-roman, lower-greek, lower-latin, + * upper-latin, armenian, georgian, lower-alpha, upper-alpha, + * none) + */ + if ((lwc_string_caseless_isequal( + ident->idata, c->strings[DISC], + &match) == lwc_error_ok && match)) { + *value = LIST_STYLE_TYPE_DISC; + } else if ((lwc_string_caseless_isequal( + ident->idata, c->strings[CIRCLE], + &match) == lwc_error_ok && match)) { + *value = LIST_STYLE_TYPE_CIRCLE; + } else if ((lwc_string_caseless_isequal( + ident->idata, c->strings[SQUARE], + &match) == lwc_error_ok && match)) { + *value = LIST_STYLE_TYPE_SQUARE; + } else if ((lwc_string_caseless_isequal( + ident->idata, c->strings[DECIMAL], + &match) == lwc_error_ok && match)) { + *value = LIST_STYLE_TYPE_DECIMAL; + } else if ((lwc_string_caseless_isequal( + ident->idata, c->strings[DECIMAL_LEADING_ZERO], + &match) == lwc_error_ok && match)) { + *value = LIST_STYLE_TYPE_DECIMAL_LEADING_ZERO; + } else if ((lwc_string_caseless_isequal( + ident->idata, c->strings[LOWER_ROMAN], + &match) == lwc_error_ok && match)) { + *value = LIST_STYLE_TYPE_LOWER_ROMAN; + } else if ((lwc_string_caseless_isequal( + ident->idata, c->strings[UPPER_ROMAN], + &match) == lwc_error_ok && match)) { + *value = LIST_STYLE_TYPE_UPPER_ROMAN; + } else if ((lwc_string_caseless_isequal( + ident->idata, c->strings[LOWER_GREEK], + &match) == lwc_error_ok && match)) { + *value = LIST_STYLE_TYPE_LOWER_GREEK; + } else if ((lwc_string_caseless_isequal( + ident->idata, c->strings[LOWER_LATIN], + &match) == lwc_error_ok && match)) { + *value = LIST_STYLE_TYPE_LOWER_LATIN; + } else if ((lwc_string_caseless_isequal( + ident->idata, c->strings[UPPER_LATIN], + &match) == lwc_error_ok && match)) { + *value = LIST_STYLE_TYPE_UPPER_LATIN; + } else if ((lwc_string_caseless_isequal( + ident->idata, c->strings[ARMENIAN], + &match) == lwc_error_ok && match)) { + *value = LIST_STYLE_TYPE_ARMENIAN; + } else if ((lwc_string_caseless_isequal( + ident->idata, c->strings[GEORGIAN], + &match) == lwc_error_ok && match)) { + *value = LIST_STYLE_TYPE_GEORGIAN; + } else if ((lwc_string_caseless_isequal( + ident->idata, c->strings[LOWER_ALPHA], + &match) == lwc_error_ok && match)) { + *value = LIST_STYLE_TYPE_LOWER_ALPHA; + } else if ((lwc_string_caseless_isequal( + ident->idata, c->strings[UPPER_ALPHA], + &match) == lwc_error_ok && match)) { + *value = LIST_STYLE_TYPE_UPPER_ALPHA; + } else if ((lwc_string_caseless_isequal( + ident->idata, c->strings[NONE], + &match) == lwc_error_ok && match)) { + *value = LIST_STYLE_TYPE_NONE; + } else + return CSS_INVALID; + + return CSS_OK; +} + +/** + * Parse content list + * + * \param c Parsing context + * \param vector Vector of tokens to process + * \param ctx Pointer to vector iteration context + * \param value Pointer to location to receive value + * \param buffer Pointer to output buffer, or NULL to read required length + * \param buflen Pointer to location to receive buffer length + * \return CSS_OK on success, + * CSS_NOMEM on memory exhaustion, + * CSS_INVALID if the input is not valid + * + * Post condition: \a *ctx is updated with the next token to process + * If the input is invalid, then \a *ctx remains unchanged. + */ +css_error parse_content_list(css_language *c, + const parserutils_vector *vector, int *ctx, + uint16_t *value, uint8_t *buffer, uint32_t *buflen) +{ + int orig_ctx = *ctx; + int prev_ctx = *ctx; + css_error error; + const css_token *token; + bool first = true; + uint32_t offset = 0; + uint32_t opv; + bool match; + + /* [ + * IDENT(open-quote, close-quote, no-open-quote, no-close-quote) | + * STRING | URI | + * FUNCTION(attr) IDENT ')' | + * FUNCTION(counter) IDENT (',' IDENT)? ')' | + * FUNCTION(counters) IDENT ',' STRING (',' IDENT)? ')' + * ]+ + */ + token = parserutils_vector_iterate(vector, ctx); + if (token == NULL) { + *ctx = orig_ctx; + return CSS_INVALID; + } + + while (token != NULL) { + if (token->type == CSS_TOKEN_IDENT && + (lwc_string_caseless_isequal( + token->idata, c->strings[OPEN_QUOTE], + &match) == lwc_error_ok && match)) { + opv = CONTENT_OPEN_QUOTE; + + if (first == false) { + if (buffer != NULL) { + memcpy(buffer + offset, + &opv, sizeof(opv)); + } + + offset += sizeof(opv); + } + } else if (token->type == CSS_TOKEN_IDENT && + (lwc_string_caseless_isequal( + token->idata, c->strings[CLOSE_QUOTE], + &match) == lwc_error_ok && match)) { + opv = CONTENT_CLOSE_QUOTE; + + if (first == false) { + if (buffer != NULL) { + memcpy(buffer + offset, + &opv, sizeof(opv)); + } + + offset += sizeof(opv); + } + } else if (token->type == CSS_TOKEN_IDENT && + (lwc_string_caseless_isequal( + token->idata, c->strings[NO_OPEN_QUOTE], + &match) == lwc_error_ok && match)) { + opv = CONTENT_NO_OPEN_QUOTE; + + if (first == false) { + if (buffer != NULL) { + memcpy(buffer + offset, + &opv, sizeof(opv)); + } + + offset += sizeof(opv); + } + } else if (token->type == CSS_TOKEN_IDENT && + (lwc_string_caseless_isequal( + token->idata, c->strings[NO_CLOSE_QUOTE], + &match) == lwc_error_ok && match)) { + opv = CONTENT_NO_CLOSE_QUOTE; + + if (first == false) { + if (buffer != NULL) { + memcpy(buffer + offset, + &opv, sizeof(opv)); + } + + offset += sizeof(opv); + } + } else if (token->type == CSS_TOKEN_STRING) { + opv = CONTENT_STRING; + + if (first == false) { + if (buffer != NULL) { + memcpy(buffer + offset, + &opv, sizeof(opv)); + } + + offset += sizeof(opv); + } + + if (buffer != NULL) { + lwc_string_ref(token->idata); + memcpy(buffer + offset, &token->idata, + sizeof(token->idata)); + } + + offset += sizeof(token->idata); + } else if (token->type == CSS_TOKEN_URI) { + lwc_string *uri; + + opv = CONTENT_URI; + + if (first == false) { + if (buffer != NULL) { + memcpy(buffer + offset, + &opv, sizeof(opv)); + } + + offset += sizeof(opv); + } + + if (buffer != NULL) { + error = c->sheet->resolve(c->sheet->resolve_pw, + c->sheet->url, + token->idata, &uri); + if (error != CSS_OK) { + *ctx = orig_ctx; + return error; + } + + /* Don't ref URI -- we want to pass ownership + * to the bytecode */ + memcpy(buffer + offset, &uri, sizeof(uri)); + } + + offset += sizeof(uri); + } else if (token->type == CSS_TOKEN_FUNCTION && + (lwc_string_caseless_isequal( + token->idata, c->strings[ATTR], + &match) == lwc_error_ok && match)) { + opv = CONTENT_ATTR; + + if (first == false) { + if (buffer != NULL) { + memcpy(buffer + offset, + &opv, sizeof(opv)); + } + + offset += sizeof(opv); + } + + consumeWhitespace(vector, ctx); + + /* Expect IDENT */ + token = parserutils_vector_iterate(vector, ctx); + if (token == NULL || token->type != CSS_TOKEN_IDENT) { + *ctx = orig_ctx; + return CSS_INVALID; + } + + if (buffer != NULL) { + lwc_string_ref(token->idata); + memcpy(buffer + offset, &token->idata, + sizeof(token->idata)); + } + + offset += sizeof(token->idata); + + consumeWhitespace(vector, ctx); + + /* Expect ')' */ + token = parserutils_vector_iterate(vector, ctx); + if (token == NULL || tokenIsChar(token, ')') == false) { + *ctx = orig_ctx; + return CSS_INVALID; + } + } else if (token->type == CSS_TOKEN_FUNCTION && + (lwc_string_caseless_isequal( + token->idata, c->strings[COUNTER], + &match) == lwc_error_ok && match)) { + lwc_string *name; + + opv = CONTENT_COUNTER; + + consumeWhitespace(vector, ctx); + + /* Expect IDENT */ + token = parserutils_vector_iterate(vector, ctx); + if (token == NULL || token->type != CSS_TOKEN_IDENT) { + *ctx = orig_ctx; + return CSS_INVALID; + } + + name = token->idata; + + consumeWhitespace(vector, ctx); + + /* Possible ',' */ + token = parserutils_vector_peek(vector, *ctx); + if (token == NULL || + (tokenIsChar(token, ',') == false && + tokenIsChar(token, ')') == false)) { + *ctx = orig_ctx; + return CSS_INVALID; + } + + if (tokenIsChar(token, ',')) { + uint16_t v; + + parserutils_vector_iterate(vector, ctx); + + consumeWhitespace(vector, ctx); + + /* Expect IDENT */ + token = parserutils_vector_peek(vector, *ctx); + if (token == NULL || token->type != + CSS_TOKEN_IDENT) { + *ctx = orig_ctx; + return CSS_INVALID; + } + + error = parse_list_style_type_value(c, + token, &v); + if (error != CSS_OK) { + *ctx = orig_ctx; + return error; + } + + opv |= v << CONTENT_COUNTER_STYLE_SHIFT; + + parserutils_vector_iterate(vector, ctx); + + consumeWhitespace(vector, ctx); + } else { + opv |= LIST_STYLE_TYPE_DECIMAL << + CONTENT_COUNTER_STYLE_SHIFT; + } + + /* Expect ')' */ + token = parserutils_vector_iterate(vector, ctx); + if (token == NULL || tokenIsChar(token, ')') == false) { + *ctx = orig_ctx; + return CSS_INVALID; + } + + if (first == false) { + if (buffer != NULL) { + memcpy(buffer + offset, + &opv, sizeof(opv)); + } + + offset += sizeof(opv); + } + + if (buffer != NULL) { + lwc_string_ref(name); + memcpy(buffer + offset, &name, sizeof(name)); + } + + offset += sizeof(name); + } else if (token->type == CSS_TOKEN_FUNCTION && + (lwc_string_caseless_isequal( + token->idata, c->strings[COUNTERS], + &match) == lwc_error_ok && match)) { + lwc_string *name; + lwc_string *sep; + + opv = CONTENT_COUNTERS; + + consumeWhitespace(vector, ctx); + + /* Expect IDENT */ + token = parserutils_vector_iterate(vector, ctx); + if (token == NULL || token->type != CSS_TOKEN_IDENT) { + *ctx = orig_ctx; + return CSS_INVALID; + } + + name = token->idata; + + consumeWhitespace(vector, ctx); + + /* Expect ',' */ + token = parserutils_vector_iterate(vector, ctx); + if (token == NULL || tokenIsChar(token, ',') == false) { + *ctx = orig_ctx; + return CSS_INVALID; + } + + consumeWhitespace(vector, ctx); + + /* Expect STRING */ + token = parserutils_vector_iterate(vector, ctx); + if (token == NULL || token->type != CSS_TOKEN_STRING) { + *ctx = orig_ctx; + return CSS_INVALID; + } + + sep = token->idata; + + consumeWhitespace(vector, ctx); + + /* Possible ',' */ + token = parserutils_vector_peek(vector, *ctx); + if (token == NULL || + (tokenIsChar(token, ',') == false && + tokenIsChar(token, ')') == false)) { + *ctx = orig_ctx; + return CSS_INVALID; + } + + if (tokenIsChar(token, ',')) { + uint16_t v; + + parserutils_vector_iterate(vector, ctx); + + consumeWhitespace(vector, ctx); + + /* Expect IDENT */ + token = parserutils_vector_peek(vector, *ctx); + if (token == NULL || token->type != + CSS_TOKEN_IDENT) { + *ctx = orig_ctx; + return CSS_INVALID; + } + + error = parse_list_style_type_value(c, + token, &v); + if (error != CSS_OK) { + *ctx = orig_ctx; + return error; + } + + opv |= v << CONTENT_COUNTERS_STYLE_SHIFT; + + parserutils_vector_iterate(vector, ctx); + + consumeWhitespace(vector, ctx); + } else { + opv |= LIST_STYLE_TYPE_DECIMAL << + CONTENT_COUNTERS_STYLE_SHIFT; + } + + /* Expect ')' */ + token = parserutils_vector_iterate(vector, ctx); + if (token == NULL || tokenIsChar(token, ')') == false) { + *ctx = orig_ctx; + return CSS_INVALID; + } + + if (first == false) { + if (buffer != NULL) { + memcpy(buffer + offset, + &opv, sizeof(opv)); + } + + offset += sizeof(opv); + } + + if (buffer != NULL) { + lwc_string_ref(name); + memcpy(buffer + offset, &name, sizeof(name)); + } + + offset += sizeof(name); + + if (buffer != NULL) { + lwc_string_ref(sep); + memcpy(buffer + offset, &sep, sizeof(sep)); + } + + offset += sizeof(sep); + } else if (first) { + /* Invalid if this is the first iteration */ + *ctx = orig_ctx; + return CSS_INVALID; + } else { + /* Give up, ensuring current token is reprocessed */ + *ctx = prev_ctx; + break; + } + + if (first && value != NULL) { + *value = opv; + } + first = false; + + consumeWhitespace(vector, ctx); + + prev_ctx = *ctx; + token = parserutils_vector_iterate(vector, ctx); + } + + /* Write list terminator */ + opv = CONTENT_NORMAL; + + if (buffer != NULL) { + memcpy(buffer + offset, &opv, sizeof(opv)); + } + + offset += sizeof(opv); + + if (buflen != NULL) { + *buflen = offset; + } + + return CSS_OK; +} + +/** + * Common parser for counter-increment and counter-reset + * + * \param c Parsing context + * \param vector Vector of tokens to process + * \param ctx Pointer to vector iteration context + * \param op Opcode to parse for + * \param result Pointer to location to receive resulting style + * \return CSS_OK on success, + * CSS_NOMEM on memory exhaustion, + * CSS_INVALID if the input is not valid + * + * Post condition: \a *ctx is updated with the next token to process + * If the input is invalid, then \a *ctx remains unchanged. + */ +css_error parse_counter_common(css_language *c, + const parserutils_vector *vector, int *ctx, + uint16_t op, css_style **result) +{ + int orig_ctx = *ctx; + css_error error; + const css_token *token; + uint8_t flags = 0; + uint16_t value = 0; + uint32_t opv; + uint32_t required_size = sizeof(opv); + int temp_ctx = *ctx; + uint8_t *ptr; + bool match; + + /* [IDENT ? ]+ | IDENT(none, inherit) */ + + /* Pass 1: validate input and calculate bytecode size */ + token = parserutils_vector_iterate(vector, &temp_ctx); + if (token == NULL || token->type != CSS_TOKEN_IDENT) { + *ctx = orig_ctx; + return CSS_INVALID; + } + + if ((lwc_string_caseless_isequal( + token->idata, c->strings[INHERIT], + &match) == lwc_error_ok && match)) { + flags = FLAG_INHERIT; + } else if ((lwc_string_caseless_isequal( + token->idata, c->strings[NONE], + &match) == lwc_error_ok && match)) { + value = COUNTER_INCREMENT_NONE; + } else { + bool first = true; + + value = COUNTER_INCREMENT_NAMED; + + while (token != NULL) { + lwc_string *name = token->idata; + css_fixed increment = + (op == CSS_PROP_COUNTER_INCREMENT) + ? INTTOFIX(1) : INTTOFIX(0); + + consumeWhitespace(vector, &temp_ctx); + + /* Optional integer */ + token = parserutils_vector_peek(vector, temp_ctx); + if (token != NULL && token->type != CSS_TOKEN_IDENT && + token->type != CSS_TOKEN_NUMBER) { + *ctx = orig_ctx; + return CSS_INVALID; + } + + if (token != NULL && token->type == CSS_TOKEN_NUMBER) { + size_t consumed = 0; + + increment = number_from_lwc_string( + token->idata, true, &consumed); + + if (consumed != lwc_string_length( + token->idata)) { + *ctx = orig_ctx; + return CSS_INVALID; + } + + parserutils_vector_iterate(vector, &temp_ctx); + + consumeWhitespace(vector, &temp_ctx); + } + + if (first == false) { + required_size += sizeof(opv); + } + required_size += sizeof(name) + sizeof(increment); + + first = false; + + token = parserutils_vector_peek(vector, temp_ctx); + if (token != NULL && token->type != CSS_TOKEN_IDENT) { + break; + } + + token = parserutils_vector_iterate(vector, &temp_ctx); + } + + /* And for the terminator */ + required_size += sizeof(opv); + } + + opv = buildOPV(op, flags, value); + + /* Allocate result */ + error = css_stylesheet_style_create(c->sheet, required_size, result); + if (error != CSS_OK) { + *ctx = orig_ctx; + return error; + } + + /* Copy OPV to bytecode */ + ptr = (*result)->bytecode; + memcpy(ptr, &opv, sizeof(opv)); + ptr += sizeof(opv); + + /* Pass 2: construct bytecode */ + token = parserutils_vector_iterate(vector, ctx); + if (token == NULL || token->type != CSS_TOKEN_IDENT) { + *ctx = orig_ctx; + return CSS_INVALID; + } + + if ((lwc_string_caseless_isequal( + token->idata, c->strings[INHERIT], + &match) == lwc_error_ok && match) || + (lwc_string_caseless_isequal( + token->idata, c->strings[NONE], + &match) == lwc_error_ok && match)) { + /* Nothing to do */ + } else { + bool first = true; + + opv = COUNTER_INCREMENT_NAMED; + + while (token != NULL) { + lwc_string *name = token->idata; + css_fixed increment = + (op == CSS_PROP_COUNTER_INCREMENT) + ? INTTOFIX(1) : INTTOFIX(0); + + consumeWhitespace(vector, ctx); + + /* Optional integer */ + token = parserutils_vector_peek(vector, *ctx); + if (token != NULL && token->type != CSS_TOKEN_IDENT && + token->type != CSS_TOKEN_NUMBER) { + *ctx = orig_ctx; + return CSS_INVALID; + } + + if (token != NULL && token->type == CSS_TOKEN_NUMBER) { + size_t consumed = 0; + + increment = number_from_lwc_string( + token->idata, true, &consumed); + + if (consumed != lwc_string_length( + token->idata)) { + *ctx = orig_ctx; + return CSS_INVALID; + } + + parserutils_vector_iterate(vector, ctx); + + consumeWhitespace(vector, ctx); + } + + if (first == false) { + memcpy(ptr, &opv, sizeof(opv)); + ptr += sizeof(opv); + } + + lwc_string_ref(name); + memcpy(ptr, &name, sizeof(name)); + ptr += sizeof(name); + + memcpy(ptr, &increment, sizeof(increment)); + ptr += sizeof(increment); + + first = false; + + token = parserutils_vector_peek(vector, *ctx); + if (token != NULL && token->type != CSS_TOKEN_IDENT) { + break; + } + + token = parserutils_vector_iterate(vector, ctx); + } + + /* And for the terminator */ + opv = COUNTER_INCREMENT_NONE; + memcpy(ptr, &opv, sizeof(opv)); + ptr += sizeof(opv); + } + + return CSS_OK; +} + +/** + * Parse border-{top,right,bottom,left} shorthand + * + * \param c Parsing context + * \param vector Vector of tokens to process + * \param ctx Pointer to vector iteration context + * \param side The side we're parsing for + * \param result Pointer to location to receive resulting style + * \return CSS_OK on success, + * CSS_NOMEM on memory exhaustion, + * CSS_INVALID if the input is not valid + * + * Post condition: \a *ctx is updated with the next token to process + * If the input is invalid, then \a *ctx remains unchanged. + */ +css_error parse_border_side(css_language *c, + const parserutils_vector *vector, int *ctx, + uint32_t side, css_style **result) +{ + int orig_ctx = *ctx; + int prev_ctx; + const css_token *token; + css_style *color = NULL; + css_style *style = NULL; + css_style *width = NULL; + css_style *ret = NULL; + uint32_t required_size; + bool match; + css_error error; + + /* Firstly, handle inherit */ + token = parserutils_vector_peek(vector, *ctx); + if (token != NULL && token->type == CSS_TOKEN_IDENT && + (lwc_string_caseless_isequal( + token->idata, c->strings[INHERIT], + &match) == lwc_error_ok && match)) { + uint32_t *bytecode; + + error = css_stylesheet_style_create(c->sheet, + 3 * sizeof(uint32_t), &ret); + if (error != CSS_OK) { + *ctx = orig_ctx; + return error; + } + + bytecode = (uint32_t *) ret->bytecode; + + *(bytecode++) = buildOPV(CSS_PROP_BORDER_TOP_COLOR + side, + FLAG_INHERIT, 0); + *(bytecode++) = buildOPV(CSS_PROP_BORDER_TOP_STYLE + side, + FLAG_INHERIT, 0); + *(bytecode++) = buildOPV(CSS_PROP_BORDER_TOP_WIDTH + side, + FLAG_INHERIT, 0); + + parserutils_vector_iterate(vector, ctx); + + *result = ret; + + return CSS_OK; + } else if (token == NULL) { + /* No tokens -- clearly garbage */ + *ctx = orig_ctx; + return CSS_INVALID; + } + + /* Attempt to parse individual properties */ + do { + prev_ctx = *ctx; + error = CSS_OK; + + /* Ensure that we're not about to parse another inherit */ + token = parserutils_vector_peek(vector, *ctx); + if (token != NULL && token->type == CSS_TOKEN_IDENT && + (lwc_string_caseless_isequal( + token->idata, c->strings[INHERIT], + &match) == lwc_error_ok && match)) { + error = CSS_INVALID; + goto cleanup; + } + + if (color == NULL && + (error = parse_border_side_color(c, vector, ctx, + CSS_PROP_BORDER_TOP_COLOR + side, &color)) == + CSS_OK) { + } else if (style == NULL && + (error = parse_border_side_style(c, vector, ctx, + CSS_PROP_BORDER_TOP_STYLE + side, &style)) == + CSS_OK) { + } else if (width == NULL && + (error = parse_border_side_width(c, vector, ctx, + CSS_PROP_BORDER_TOP_WIDTH + side, &width)) == + CSS_OK) { + } + + if (error == CSS_OK) { + consumeWhitespace(vector, ctx); + + token = parserutils_vector_peek(vector, *ctx); + } else { + /* Forcibly cause loop to exit */ + token = NULL; + } + } while (*ctx != prev_ctx && token != NULL); + + /* Calculate size of resultant style */ + required_size = 0; + if (color) + required_size += color->length; + + if (style) + required_size += style->length; + else + required_size += sizeof(uint32_t); + + if (width) + required_size += width->length; + else + required_size += sizeof(uint32_t); + + error = css_stylesheet_style_create(c->sheet, required_size, &ret); + if (error != CSS_OK) + goto cleanup; + + required_size = 0; + + if (color) { + memcpy(((uint8_t *) ret->bytecode) + required_size, + color->bytecode, color->length); + required_size += color->length; + } + + if (style) { + memcpy(((uint8_t *) ret->bytecode) + required_size, + style->bytecode, style->length); + required_size += style->length; + } else { + void *bc = ((uint8_t *) ret->bytecode) + required_size; + + *((uint32_t *) bc) = buildOPV(CSS_PROP_BORDER_TOP_STYLE + side, + 0, BORDER_STYLE_NONE); + required_size += sizeof(uint32_t); + } + + if (width) { + memcpy(((uint8_t *) ret->bytecode) + required_size, + width->bytecode, width->length); + required_size += width->length; + } else { + void *bc = ((uint8_t *) ret->bytecode) + required_size; + + *((uint32_t *) bc) = buildOPV(CSS_PROP_BORDER_TOP_WIDTH + side, + 0, BORDER_WIDTH_MEDIUM); + required_size += sizeof(uint32_t); + } + + assert(required_size == ret->length); + + /* Write the result */ + *result = ret; + /* Invalidate ret, so that cleanup doesn't destroy it */ + ret = NULL; + + /* Clean up after ourselves */ +cleanup: + if (color) + css_stylesheet_style_destroy(c->sheet, color, error == CSS_OK); + if (style) + css_stylesheet_style_destroy(c->sheet, style, error == CSS_OK); + if (width) + css_stylesheet_style_destroy(c->sheet, width, error == CSS_OK); + if (ret) + css_stylesheet_style_destroy(c->sheet, ret, error == CSS_OK); + + if (error != CSS_OK) + *ctx = orig_ctx; + + return error; +} + +/** + * Parse border-{top,right,bottom,left}-color + * + * \param c Parsing context + * \param vector Vector of tokens to process + * \param ctx Pointer to vector iteration context + * \param op Opcode to parse for (encodes side) + * \param result Pointer to location to receive resulting style + * \return CSS_OK on success, + * CSS_NOMEM on memory exhaustion, + * CSS_INVALID if the input is not valid + * + * Post condition: \a *ctx is updated with the next token to process + * If the input is invalid, then \a *ctx remains unchanged. + */ +css_error parse_border_side_color(css_language *c, + const parserutils_vector *vector, int *ctx, + uint16_t op, css_style **result) +{ + int orig_ctx = *ctx; + css_error error; + const css_token *token; + uint32_t opv; + uint8_t flags = 0; + uint16_t value = 0; + uint32_t colour = 0; + uint32_t required_size; + bool match; + + /* colour | IDENT (transparent, inherit) */ + token= parserutils_vector_peek(vector, *ctx); + if (token == NULL) { + *ctx = orig_ctx; + return CSS_INVALID; + } + + if (token->type == CSS_TOKEN_IDENT && + (lwc_string_caseless_isequal( + token->idata, c->strings[INHERIT], + &match) == lwc_error_ok && match)) { + parserutils_vector_iterate(vector, ctx); + flags |= FLAG_INHERIT; + } else if (token->type == CSS_TOKEN_IDENT && + (lwc_string_caseless_isequal( + token->idata, c->strings[TRANSPARENT], + &match) == lwc_error_ok && match)) { + parserutils_vector_iterate(vector, ctx); + value = BORDER_COLOR_TRANSPARENT; + } else { + error = parse_colour_specifier(c, vector, ctx, &colour); + if (error != CSS_OK) { + *ctx = orig_ctx; + return error; + } + + value = BORDER_COLOR_SET; + } + + opv = buildOPV(op, flags, value); + + required_size = sizeof(opv); + if ((flags & FLAG_INHERIT) == false && value == BORDER_COLOR_SET) + required_size += sizeof(colour); + + /* Allocate result */ + error = css_stylesheet_style_create(c->sheet, required_size, result); + if (error != CSS_OK) { + *ctx = orig_ctx; + return error; + } + + /* Copy the bytecode to it */ + memcpy((*result)->bytecode, &opv, sizeof(opv)); + if ((flags & FLAG_INHERIT) == false && value == BORDER_COLOR_SET) { + memcpy(((uint8_t *) (*result)->bytecode) + sizeof(opv), + &colour, sizeof(colour)); + } + + return CSS_OK; +} + +/** + * Parse border-{top,right,bottom,left}-style + * + * \param c Parsing context + * \param vector Vector of tokens to process + * \param ctx Pointer to vector iteration context + * \param op Opcode to parse for (encodes side) + * \param result Pointer to location to receive resulting style + * \return CSS_OK on success, + * CSS_NOMEM on memory exhaustion, + * CSS_INVALID if the input is not valid + * + * Post condition: \a *ctx is updated with the next token to process + * If the input is invalid, then \a *ctx remains unchanged. + */ +css_error parse_border_side_style(css_language *c, + const parserutils_vector *vector, int *ctx, + uint16_t op, css_style **result) +{ + int orig_ctx = *ctx; + css_error error; + const css_token *ident; + uint8_t flags = 0; + uint16_t value = 0; + uint32_t opv; + bool match; + + /* IDENT (none, hidden, dotted, dashed, solid, double, groove, + * ridge, inset, outset, inherit) */ + ident = parserutils_vector_iterate(vector, ctx); + if (ident == NULL || ident->type != CSS_TOKEN_IDENT) { + *ctx = orig_ctx; + return CSS_INVALID; + } + + if ((lwc_string_caseless_isequal( + ident->idata, c->strings[INHERIT], + &match) == lwc_error_ok && match)) { + flags |= FLAG_INHERIT; + } else if ((lwc_string_caseless_isequal( + ident->idata, c->strings[NONE], + &match) == lwc_error_ok && match)) { + value = BORDER_STYLE_NONE; + } else if ((lwc_string_caseless_isequal( + ident->idata, c->strings[HIDDEN], + &match) == lwc_error_ok && match)) { + value = BORDER_STYLE_HIDDEN; + } else if ((lwc_string_caseless_isequal( + ident->idata, c->strings[DOTTED], + &match) == lwc_error_ok && match)) { + value = BORDER_STYLE_DOTTED; + } else if ((lwc_string_caseless_isequal( + ident->idata, c->strings[DASHED], + &match) == lwc_error_ok && match)) { + value = BORDER_STYLE_DASHED; + } else if ((lwc_string_caseless_isequal( + ident->idata, c->strings[SOLID], + &match) == lwc_error_ok && match)) { + value = BORDER_STYLE_SOLID; + } else if ((lwc_string_caseless_isequal( + ident->idata, c->strings[LIBCSS_DOUBLE], + &match) == lwc_error_ok && match)) { + value = BORDER_STYLE_DOUBLE; + } else if ((lwc_string_caseless_isequal( + ident->idata, c->strings[GROOVE], + &match) == lwc_error_ok && match)) { + value = BORDER_STYLE_GROOVE; + } else if ((lwc_string_caseless_isequal( + ident->idata, c->strings[RIDGE], + &match) == lwc_error_ok && match)) { + value = BORDER_STYLE_RIDGE; + } else if ((lwc_string_caseless_isequal( + ident->idata, c->strings[INSET], + &match) == lwc_error_ok && match)) { + value = BORDER_STYLE_INSET; + } else if ((lwc_string_caseless_isequal( + ident->idata, c->strings[OUTSET], + &match) == lwc_error_ok && match)) { + value = BORDER_STYLE_OUTSET; + } else { + *ctx = orig_ctx; + return CSS_INVALID; + } + + opv = buildOPV(op, flags, value); + + /* Allocate result */ + error = css_stylesheet_style_create(c->sheet, sizeof(opv), result); + if (error != CSS_OK) { + *ctx = orig_ctx; + return error; + } + + /* Copy the bytecode to it */ + memcpy((*result)->bytecode, &opv, sizeof(opv)); + + return CSS_OK; +} + +/** + * Parse border-{top,right,bottom,left}-width + * + * \param c Parsing context + * \param vector Vector of tokens to process + * \param ctx Pointer to vector iteration context + * \param op Opcode to parse for (encodes side) + * \param result Pointer to location to receive resulting style + * \return CSS_OK on success, + * CSS_NOMEM on memory exhaustion, + * CSS_INVALID if the input is not valid + * + * Post condition: \a *ctx is updated with the next token to process + * If the input is invalid, then \a *ctx remains unchanged. + */ +css_error parse_border_side_width(css_language *c, + const parserutils_vector *vector, int *ctx, + uint16_t op, css_style **result) +{ + int orig_ctx = *ctx; + css_error error; + const css_token *token; + uint8_t flags = 0; + uint16_t value = 0; + uint32_t opv; + css_fixed length = 0; + uint32_t unit = 0; + uint32_t required_size; + bool match; + + /* length | IDENT(thin, medium, thick, inherit) */ + token= parserutils_vector_peek(vector, *ctx); + if (token == NULL) { + *ctx = orig_ctx; + return CSS_INVALID; + } + + if (token->type == CSS_TOKEN_IDENT && + (lwc_string_caseless_isequal( + token->idata, c->strings[INHERIT], + &match) == lwc_error_ok && match)) { + parserutils_vector_iterate(vector, ctx); + flags |= FLAG_INHERIT; + } else if (token->type == CSS_TOKEN_IDENT && + (lwc_string_caseless_isequal( + token->idata, c->strings[THIN], + &match) == lwc_error_ok && match)) { + parserutils_vector_iterate(vector, ctx); + value = BORDER_WIDTH_THIN; + } else if (token->type == CSS_TOKEN_IDENT && + (lwc_string_caseless_isequal( + token->idata, c->strings[MEDIUM], + &match) == lwc_error_ok && match)) { + parserutils_vector_iterate(vector, ctx); + value = BORDER_WIDTH_MEDIUM; + } else if (token->type == CSS_TOKEN_IDENT && + (lwc_string_caseless_isequal( + token->idata, c->strings[THICK], + &match) == lwc_error_ok && match)) { + parserutils_vector_iterate(vector, ctx); + value = BORDER_WIDTH_THICK; + } else { + error = parse_unit_specifier(c, vector, ctx, UNIT_PX, + &length, &unit); + if (error != CSS_OK) { + *ctx = orig_ctx; + return error; + } + + if (unit == UNIT_PCT || unit & UNIT_ANGLE || + unit & UNIT_TIME || unit & UNIT_FREQ) { + *ctx = orig_ctx; + return CSS_INVALID; + } + + /* Length must be positive */ + if (length < 0) { + *ctx = orig_ctx; + return CSS_INVALID; + } + + value = BORDER_WIDTH_SET; + } + + opv = buildOPV(op, flags, value); + + required_size = sizeof(opv); + if ((flags & FLAG_INHERIT) == false && value == BORDER_WIDTH_SET) + required_size += sizeof(length) + sizeof(unit); + + /* Allocate result */ + error = css_stylesheet_style_create(c->sheet, required_size, result); + if (error != CSS_OK) { + *ctx = orig_ctx; + return error; + } + + /* Copy the bytecode to it */ + memcpy((*result)->bytecode, &opv, sizeof(opv)); + if ((flags & FLAG_INHERIT) == false && value == BORDER_WIDTH_SET) { + memcpy(((uint8_t *) (*result)->bytecode) + sizeof(opv), + &length, sizeof(length)); + memcpy(((uint8_t *) (*result)->bytecode) + sizeof(opv) + + sizeof(length), &unit, sizeof(unit)); + } + + return CSS_OK; +} + +/** + * Parse margin-{top,right,bottom,left} + * + * \param c Parsing context + * \param vector Vector of tokens to process + * \param ctx Pointer to vector iteration context + * \param result Pointer to location to receive resulting style + * \return CSS_OK on success, + * CSS_NOMEM on memory exhaustion, + * CSS_INVALID if the input is not valid + * + * Post condition: \a *ctx is updated with the next token to process + * If the input is invalid, then \a *ctx remains unchanged. + */ +css_error parse_margin_side(css_language *c, + const parserutils_vector *vector, int *ctx, + uint16_t op, css_style **result) +{ + int orig_ctx = *ctx; + css_error error; + const css_token *token; + uint8_t flags = 0; + uint16_t value = 0; + uint32_t opv; + css_fixed length = 0; + uint32_t unit = 0; + uint32_t required_size; + bool match; + + /* length | percentage | IDENT(auto, inherit) */ + token = parserutils_vector_peek(vector, *ctx); + if (token == NULL) { + *ctx = orig_ctx; + return CSS_INVALID; + } + + if (token->type == CSS_TOKEN_IDENT && + (lwc_string_caseless_isequal( + token->idata, c->strings[INHERIT], + &match) == lwc_error_ok && match)) { + parserutils_vector_iterate(vector, ctx); + flags = FLAG_INHERIT; + } else if (token->type == CSS_TOKEN_IDENT && + (lwc_string_caseless_isequal( + token->idata, c->strings[AUTO], + &match) == lwc_error_ok && match)) { + parserutils_vector_iterate(vector, ctx); + value = MARGIN_AUTO; + } else { + error = parse_unit_specifier(c, vector, ctx, UNIT_PX, + &length, &unit); + if (error != CSS_OK) { + *ctx = orig_ctx; + return error; + } + + if (unit & UNIT_ANGLE || unit & UNIT_TIME || unit & UNIT_FREQ) { + *ctx = orig_ctx; + return CSS_INVALID; + } + + value = MARGIN_SET; + } + + opv = buildOPV(op, flags, value); + + required_size = sizeof(opv); + if ((flags & FLAG_INHERIT) == false && value == MARGIN_SET) + required_size += sizeof(length) + sizeof(unit); + + /* Allocate result */ + error = css_stylesheet_style_create(c->sheet, required_size, result); + if (error != CSS_OK) { + *ctx = orig_ctx; + return error; + } + + /* Copy the bytecode to it */ + memcpy((*result)->bytecode, &opv, sizeof(opv)); + if ((flags & FLAG_INHERIT) == false && value == MARGIN_SET) { + memcpy(((uint8_t *) (*result)->bytecode) + sizeof(opv), + &length, sizeof(length)); + memcpy(((uint8_t *) (*result)->bytecode) + sizeof(opv) + + sizeof(length), &unit, sizeof(unit)); + } + + return CSS_OK; +} + +/** + * Parse padding-{top,right,bottom,left} + * + * \param c Parsing context + * \param vector Vector of tokens to process + * \param ctx Pointer to vector iteration context + * \param result Pointer to location to receive resulting style + * \return CSS_OK on success, + * CSS_NOMEM on memory exhaustion, + * CSS_INVALID if the input is not valid + * + * Post condition: \a *ctx is updated with the next token to process + * If the input is invalid, then \a *ctx remains unchanged. + */ +css_error parse_padding_side(css_language *c, + const parserutils_vector *vector, int *ctx, + uint16_t op, css_style **result) +{ + int orig_ctx = *ctx; + css_error error; + const css_token *token; + uint8_t flags = 0; + uint16_t value = 0; + uint32_t opv; + css_fixed length = 0; + uint32_t unit = 0; + uint32_t required_size; + bool match; + + /* length | percentage | IDENT(inherit) */ + token = parserutils_vector_peek(vector, *ctx); + if (token == NULL) { + *ctx = orig_ctx; + return CSS_INVALID; + } + + if (token->type == CSS_TOKEN_IDENT && + (lwc_string_caseless_isequal( + token->idata, c->strings[INHERIT], + &match) == lwc_error_ok && match)) { + parserutils_vector_iterate(vector, ctx); + flags = FLAG_INHERIT; + } else { + error = parse_unit_specifier(c, vector, ctx, UNIT_PX, + &length, &unit); + if (error != CSS_OK) { + *ctx = orig_ctx; + return error; + } + + if (unit & UNIT_ANGLE || unit & UNIT_TIME || unit & UNIT_FREQ) { + *ctx = orig_ctx; + return CSS_INVALID; + } + + /* Negative lengths are invalid */ + if (length < 0) { + *ctx = orig_ctx; + return CSS_INVALID; + } + + value = PADDING_SET; + } + + opv = buildOPV(op, flags, value); + + required_size = sizeof(opv); + if ((flags & FLAG_INHERIT) == false && value == PADDING_SET) + required_size += sizeof(length) + sizeof(unit); + + /* Allocate result */ + error = css_stylesheet_style_create(c->sheet, required_size, result); + if (error != CSS_OK) { + *ctx = orig_ctx; + return error; + } + + /* Copy the bytecode to it */ + memcpy((*result)->bytecode, &opv, sizeof(opv)); + if ((flags & FLAG_INHERIT) == false && value == PADDING_SET) { + memcpy(((uint8_t *) (*result)->bytecode) + sizeof(opv), + &length, sizeof(length)); + memcpy(((uint8_t *) (*result)->bytecode) + sizeof(opv) + + sizeof(length), &unit, sizeof(unit)); + } + + return CSS_OK; +} + +/** + * Parse {top,right,bottom,left} + * + * \param c Parsing context + * \param vector Vector of tokens to process + * \param ctx Pointer to vector iteration context + * \param op Opcode to parse for + * \param result Pointer to location to receive resulting style + * \return CSS_OK on success, + * CSS_NOMEM on memory exhaustion, + * CSS_INVALID if the input is not valid + * + * Post condition: \a *ctx is updated with the next token to process + * If the input is invalid, then \a *ctx remains unchanged. + */ +css_error parse_side(css_language *c, + const parserutils_vector *vector, int *ctx, + uint16_t op, css_style **result) +{ + int orig_ctx = *ctx; + css_error error; + const css_token *token; + uint8_t flags = 0; + uint16_t value = 0; + uint32_t opv; + css_fixed length = 0; + uint32_t unit = 0; + uint32_t required_size; + bool match; + + /* length | percentage | IDENT(auto, inherit) */ + token = parserutils_vector_peek(vector, *ctx); + if (token == NULL) { + *ctx = orig_ctx; + return CSS_INVALID; + } + + if (token->type == CSS_TOKEN_IDENT && + (lwc_string_caseless_isequal( + token->idata, c->strings[INHERIT], + &match) == lwc_error_ok && match)) { + parserutils_vector_iterate(vector, ctx); + flags = FLAG_INHERIT; + } else if (token->type == CSS_TOKEN_IDENT && + (lwc_string_caseless_isequal( + token->idata, c->strings[AUTO], + &match) == lwc_error_ok && match)) { + parserutils_vector_iterate(vector, ctx); + value = BOTTOM_AUTO; + } else { + error = parse_unit_specifier(c, vector, ctx, UNIT_PX, + &length, &unit); + if (error != CSS_OK) { + *ctx = orig_ctx; + return error; + } + + if (unit & UNIT_ANGLE || unit & UNIT_TIME || unit & UNIT_FREQ) { + *ctx = orig_ctx; + return CSS_INVALID; + } + + value = BOTTOM_SET; + } + + opv = buildOPV(op, flags, value); + + required_size = sizeof(opv); + if ((flags & FLAG_INHERIT) == false && value == BOTTOM_SET) + required_size += sizeof(length) + sizeof(unit); + + /* Allocate result */ + error = css_stylesheet_style_create(c->sheet, required_size, result); + if (error != CSS_OK) { + *ctx = orig_ctx; + return error; + } + + /* Copy the bytecode to it */ + memcpy((*result)->bytecode, &opv, sizeof(opv)); + if ((flags & FLAG_INHERIT) == false && value == BOTTOM_SET) { + memcpy(((uint8_t *) (*result)->bytecode) + sizeof(opv), + &length, sizeof(length)); + memcpy(((uint8_t *) (*result)->bytecode) + sizeof(opv) + + sizeof(length), &unit, sizeof(unit)); + } + + return CSS_OK; +} + /** * Parse a colour specifier * diff --git a/src/parse/properties/utils.h b/src/parse/properties/utils.h index 86a90f5..c5bef1c 100644 --- a/src/parse/properties/utils.h +++ b/src/parse/properties/utils.h @@ -10,6 +10,47 @@ #include "parse/language.h" +css_error parse_pause_common(css_language *c, + const parserutils_vector *vector, int *ctx, + uint16_t op, css_style **result); + +css_error parse_list_style_type_value(css_language *c, + const css_token *token, uint16_t *value); +css_error parse_content_list(css_language *c, + const parserutils_vector *vector, int *ctx, + uint16_t *value, uint8_t *buffer, uint32_t *buflen); +css_error parse_counter_common(css_language *c, + const parserutils_vector *vector, int *ctx, + uint16_t op, css_style **result); + + +enum { BORDER_SIDE_TOP = 0, BORDER_SIDE_RIGHT = 1, BORDER_SIDE_BOTTOM = 2, BORDER_SIDE_LEFT = 3 }; + +css_error parse_border_side(css_language *c, + const parserutils_vector *vector, int *ctx, + uint32_t side, css_style **result); +css_error parse_border_side_color(css_language *c, + const parserutils_vector *vector, int *ctx, + uint16_t op, css_style **result); +css_error parse_border_side_style(css_language *c, + const parserutils_vector *vector, int *ctx, + uint16_t op, css_style **result); +css_error parse_border_side_width(css_language *c, + const parserutils_vector *vector, int *ctx, + uint16_t op, css_style **result); + +css_error parse_margin_side(css_language *c, + const parserutils_vector *vector, int *ctx, + uint16_t op, css_style **result); + +css_error parse_side(css_language *c, + const parserutils_vector *vector, int *ctx, + uint16_t op, css_style **result); + +css_error parse_padding_side(css_language *c, + const parserutils_vector *vector, int *ctx, + uint16_t op, css_style **result); + css_error parse_colour_specifier(css_language *c, const parserutils_vector *vector, int *ctx, uint32_t *result); diff --git a/src/parse/properties/vertical_align.c b/src/parse/properties/vertical_align.c new file mode 100644 index 0000000..46e83c3 --- /dev/null +++ b/src/parse/properties/vertical_align.c @@ -0,0 +1,147 @@ +/* + * This file is part of LibCSS. + * Licensed under the MIT License, + * http://www.opensource.org/licenses/mit-license.php + * Copyright 2009 John-Mark Bell + */ + +#include +#include + +#include "bytecode/bytecode.h" +#include "bytecode/opcodes.h" +#include "parse/properties/properties.h" +#include "parse/properties/utils.h" + +/** + * Parse vertical-align + * + * \param c Parsing context + * \param vector Vector of tokens to process + * \param ctx Pointer to vector iteration context + * \param result Pointer to location to receive resulting style + * \return CSS_OK on success, + * CSS_NOMEM on memory exhaustion, + * CSS_INVALID if the input is not valid + * + * Post condition: \a *ctx is updated with the next token to process + * If the input is invalid, then \a *ctx remains unchanged. + */ +css_error parse_vertical_align(css_language *c, + const parserutils_vector *vector, int *ctx, + css_style **result) +{ + int orig_ctx = *ctx; + css_error error; + const css_token *token; + uint8_t flags = 0; + uint16_t value = 0; + uint32_t opv; + css_fixed length = 0; + uint32_t unit = 0; + uint32_t required_size; + bool match; + + /* length | percentage | IDENT(baseline, sub, super, top, text-top, + * middle, bottom, text-bottom, inherit) + */ + token = parserutils_vector_peek(vector, *ctx); + if (token == NULL) { + *ctx = orig_ctx; + return CSS_INVALID; + } + + if (token->type == CSS_TOKEN_IDENT && + (lwc_string_caseless_isequal( + token->idata, c->strings[INHERIT], + &match) == lwc_error_ok && match)) { + parserutils_vector_iterate(vector, ctx); + flags = FLAG_INHERIT; + } else if (token->type == CSS_TOKEN_IDENT && + (lwc_string_caseless_isequal( + token->idata, c->strings[BASELINE], + &match) == lwc_error_ok && match)) { + parserutils_vector_iterate(vector, ctx); + value = VERTICAL_ALIGN_BASELINE; + } else if (token->type == CSS_TOKEN_IDENT && + (lwc_string_caseless_isequal( + token->idata, c->strings[SUB], + &match) == lwc_error_ok && match)) { + parserutils_vector_iterate(vector, ctx); + value = VERTICAL_ALIGN_SUB; + } else if (token->type == CSS_TOKEN_IDENT && + (lwc_string_caseless_isequal( + token->idata, c->strings[SUPER], + &match) == lwc_error_ok && match)) { + parserutils_vector_iterate(vector, ctx); + value = VERTICAL_ALIGN_SUPER; + } else if (token->type == CSS_TOKEN_IDENT && + (lwc_string_caseless_isequal( + token->idata, c->strings[TOP], + &match) == lwc_error_ok && match)) { + parserutils_vector_iterate(vector, ctx); + value = VERTICAL_ALIGN_TOP; + } else if (token->type == CSS_TOKEN_IDENT && + (lwc_string_caseless_isequal( + token->idata, c->strings[TEXT_TOP], + &match) == lwc_error_ok && match)) { + parserutils_vector_iterate(vector, ctx); + value = VERTICAL_ALIGN_TEXT_TOP; + } else if (token->type == CSS_TOKEN_IDENT && + (lwc_string_caseless_isequal( + token->idata, c->strings[MIDDLE], + &match) == lwc_error_ok && match)) { + parserutils_vector_iterate(vector, ctx); + value = VERTICAL_ALIGN_MIDDLE; + } else if (token->type == CSS_TOKEN_IDENT && + (lwc_string_caseless_isequal( + token->idata, c->strings[BOTTOM], + &match) == lwc_error_ok && match)) { + parserutils_vector_iterate(vector, ctx); + value = VERTICAL_ALIGN_BOTTOM; + } else if (token->type == CSS_TOKEN_IDENT && + (lwc_string_caseless_isequal( + token->idata, c->strings[TEXT_BOTTOM], + &match) == lwc_error_ok && match)) { + parserutils_vector_iterate(vector, ctx); + value = VERTICAL_ALIGN_TEXT_BOTTOM; + } else { + error = parse_unit_specifier(c, vector, ctx, UNIT_PX, + &length, &unit); + if (error != CSS_OK) { + *ctx = orig_ctx; + return error; + } + + if (unit & UNIT_ANGLE || unit & UNIT_TIME || unit & UNIT_FREQ) { + *ctx = orig_ctx; + return CSS_INVALID; + } + + value = VERTICAL_ALIGN_SET; + } + + opv = buildOPV(CSS_PROP_VERTICAL_ALIGN, flags, value); + + required_size = sizeof(opv); + if ((flags & FLAG_INHERIT) == false && value == VERTICAL_ALIGN_SET) + required_size += sizeof(length) + sizeof(unit); + + /* Allocate result */ + error = css_stylesheet_style_create(c->sheet, required_size, result); + if (error != CSS_OK) { + *ctx = orig_ctx; + return error; + } + + /* Copy the bytecode to it */ + memcpy((*result)->bytecode, &opv, sizeof(opv)); + if ((flags & FLAG_INHERIT) == false && value == VERTICAL_ALIGN_SET) { + memcpy(((uint8_t *) (*result)->bytecode) + sizeof(opv), + &length, sizeof(length)); + memcpy(((uint8_t *) (*result)->bytecode) + sizeof(opv) + + sizeof(length), &unit, sizeof(unit)); + } + + return CSS_OK; +} diff --git a/src/parse/properties/visibility.c b/src/parse/properties/visibility.c new file mode 100644 index 0000000..b6b6c11 --- /dev/null +++ b/src/parse/properties/visibility.c @@ -0,0 +1,83 @@ +/* + * This file is part of LibCSS. + * Licensed under the MIT License, + * http://www.opensource.org/licenses/mit-license.php + * Copyright 2009 John-Mark Bell + */ + +#include +#include + +#include "bytecode/bytecode.h" +#include "bytecode/opcodes.h" +#include "parse/properties/properties.h" +#include "parse/properties/utils.h" + +/** + * Parse visibility + * + * \param c Parsing context + * \param vector Vector of tokens to process + * \param ctx Pointer to vector iteration context + * \param result Pointer to location to receive resulting style + * \return CSS_OK on success, + * CSS_NOMEM on memory exhaustion, + * CSS_INVALID if the input is not valid + * + * Post condition: \a *ctx is updated with the next token to process + * If the input is invalid, then \a *ctx remains unchanged. + */ +css_error parse_visibility(css_language *c, + const parserutils_vector *vector, int *ctx, + css_style **result) +{ + int orig_ctx = *ctx; + css_error error; + const css_token *ident; + uint8_t flags = 0; + uint16_t value = 0; + uint32_t opv; + bool match; + + /* IDENT (visible, hidden, collapse, inherit) */ + ident = parserutils_vector_iterate(vector, ctx); + if (ident == NULL || ident->type != CSS_TOKEN_IDENT) { + *ctx = orig_ctx; + return CSS_INVALID; + } + + if ((lwc_string_caseless_isequal( + ident->idata, c->strings[INHERIT], + &match) == lwc_error_ok && match)) { + flags |= FLAG_INHERIT; + } else if ((lwc_string_caseless_isequal( + ident->idata, c->strings[VISIBLE], + &match) == lwc_error_ok && match)) { + value = VISIBILITY_VISIBLE; + } else if ((lwc_string_caseless_isequal( + ident->idata, c->strings[HIDDEN], + &match) == lwc_error_ok && match)) { + value = VISIBILITY_HIDDEN; + } else if ((lwc_string_caseless_isequal( + ident->idata, c->strings[COLLAPSE], + &match) == lwc_error_ok && match)) { + value = VISIBILITY_COLLAPSE; + } else { + *ctx = orig_ctx; + return CSS_INVALID; + } + + opv = buildOPV(CSS_PROP_VISIBILITY, flags, value); + + /* Allocate result */ + error = css_stylesheet_style_create(c->sheet, sizeof(opv), result); + if (error != CSS_OK) { + *ctx = orig_ctx; + return error; + } + + /* Copy the bytecode to it */ + memcpy((*result)->bytecode, &opv, sizeof(opv)); + + return CSS_OK; +} diff --git a/src/parse/properties/voice_family.c b/src/parse/properties/voice_family.c new file mode 100644 index 0000000..beca662 --- /dev/null +++ b/src/parse/properties/voice_family.c @@ -0,0 +1,182 @@ +/* + * This file is part of LibCSS. + * Licensed under the MIT License, + * http://www.opensource.org/licenses/mit-license.php + * Copyright 2009 John-Mark Bell + */ + +#include +#include + +#include "bytecode/bytecode.h" +#include "bytecode/opcodes.h" +#include "parse/properties/properties.h" +#include "parse/properties/utils.h" + +/** + * Determine if a given voice-family ident is reserved + * + * \param c Parsing context + * \param ident IDENT to consider + * \return True if IDENT is reserved, false otherwise + */ +static bool voice_family_reserved(css_language *c, const css_token *ident) +{ + bool match; + + return (lwc_string_caseless_isequal( + ident->idata, c->strings[MALE], + &match) == lwc_error_ok && match) || + (lwc_string_caseless_isequal( + ident->idata, c->strings[FEMALE], + &match) == lwc_error_ok && match) || + (lwc_string_caseless_isequal( + ident->idata, c->strings[CHILD], + &match) == lwc_error_ok && match); +} + +/** + * Convert a voice-family token into a bytecode value + * + * \param c Parsing context + * \param token Token to consider + * \return Bytecode value + */ +static uint16_t voice_family_value(css_language *c, const css_token *token) +{ + uint16_t value; + bool match; + + if (token->type == CSS_TOKEN_IDENT) { + if ((lwc_string_caseless_isequal( + token->idata, c->strings[MALE], + &match) == lwc_error_ok && match)) + value = VOICE_FAMILY_MALE; + else if ((lwc_string_caseless_isequal( + token->idata, c->strings[FEMALE], + &match) == lwc_error_ok && match)) + value = VOICE_FAMILY_FEMALE; + else if ((lwc_string_caseless_isequal( + token->idata, c->strings[CHILD], + &match) == lwc_error_ok && match)) + value = VOICE_FAMILY_CHILD; + else + value = VOICE_FAMILY_IDENT_LIST; + } else { + value = VOICE_FAMILY_STRING; + } + + return value; +} + +/** + * Parse voice-family + * + * \param c Parsing context + * \param vector Vector of tokens to process + * \param ctx Pointer to vector iteration context + * \param result Pointer to location to receive resulting style + * \return CSS_OK on success, + * CSS_NOMEM on memory exhaustion, + * CSS_INVALID if the input is not valid + * + * Post condition: \a *ctx is updated with the next token to process + * If the input is invalid, then \a *ctx remains unchanged. + */ +css_error parse_voice_family(css_language *c, + const parserutils_vector *vector, int *ctx, + css_style **result) +{ + int orig_ctx = *ctx; + css_error error; + const css_token *token; + uint8_t flags = 0; + uint16_t value = 0; + uint32_t opv; + uint32_t required_size = sizeof(opv); + int temp_ctx = *ctx; + uint8_t *ptr; + bool match; + + /* [ IDENT+ | STRING ] [ ',' [ IDENT+ | STRING ] ]* | IDENT(inherit) + * + * In the case of IDENT+, any whitespace between tokens is collapsed to + * a single space + */ + + /* Pass 1: validate input and calculate space */ + token = parserutils_vector_iterate(vector, &temp_ctx); + if (token == NULL || (token->type != CSS_TOKEN_IDENT && + token->type != CSS_TOKEN_STRING)) { + *ctx = orig_ctx; + return CSS_INVALID; + } + + if (token->type == CSS_TOKEN_IDENT && + (lwc_string_caseless_isequal( + token->idata, c->strings[INHERIT], + &match) == lwc_error_ok && match)) { + flags = FLAG_INHERIT; + } else { + uint32_t list_size; + + value = voice_family_value(c, token); + + error = comma_list_length(c, vector, &temp_ctx, + token, voice_family_reserved, &list_size); + if (error != CSS_OK) { + *ctx = orig_ctx; + return error; + } + + required_size += list_size; + } + + opv = buildOPV(CSS_PROP_VOICE_FAMILY, flags, value); + + /* Allocate result */ + error = css_stylesheet_style_create(c->sheet, required_size, result); + if (error != CSS_OK) { + *ctx = orig_ctx; + return error; + } + + /* Copy OPV to bytecode */ + ptr = (*result)->bytecode; + memcpy(ptr, &opv, sizeof(opv)); + ptr += sizeof(opv); + + /* Pass 2: populate bytecode */ + token = parserutils_vector_iterate(vector, ctx); + if (token == NULL || (token->type != CSS_TOKEN_IDENT && + token->type != CSS_TOKEN_STRING)) { + css_stylesheet_style_destroy(c->sheet, *result, true); + *result = NULL; + *ctx = orig_ctx; + return CSS_INVALID; + } + + if (token->type == CSS_TOKEN_IDENT && + (lwc_string_caseless_isequal( + token->idata, c->strings[INHERIT], + &match) == lwc_error_ok && match)) { + /* Nothing to do */ + } else { + error = comma_list_to_bytecode(c, vector, ctx, token, + voice_family_reserved, voice_family_value, + &ptr); + if (error != CSS_OK) { + css_stylesheet_style_destroy(c->sheet, *result, true); + *result = NULL; + *ctx = orig_ctx; + return error; + } + + /* Write terminator */ + opv = VOICE_FAMILY_END; + memcpy(ptr, &opv, sizeof(opv)); + ptr += sizeof(opv); + } + + return CSS_OK; +} diff --git a/src/parse/properties/volume.c b/src/parse/properties/volume.c new file mode 100644 index 0000000..2d4c90e --- /dev/null +++ b/src/parse/properties/volume.c @@ -0,0 +1,161 @@ +/* + * This file is part of LibCSS. + * Licensed under the MIT License, + * http://www.opensource.org/licenses/mit-license.php + * Copyright 2009 John-Mark Bell + */ + +#include +#include + +#include "bytecode/bytecode.h" +#include "bytecode/opcodes.h" +#include "parse/properties/properties.h" +#include "parse/properties/utils.h" + +/** + * Parse volume + * + * \param c Parsing context + * \param vector Vector of tokens to process + * \param ctx Pointer to vector iteration context + * \param result Pointer to location to receive resulting style + * \return CSS_OK on success, + * CSS_NOMEM on memory exhaustion, + * CSS_INVALID if the input is not valid + * + * Post condition: \a *ctx is updated with the next token to process + * If the input is invalid, then \a *ctx remains unchanged. + */ +css_error parse_volume(css_language *c, + const parserutils_vector *vector, int *ctx, + css_style **result) +{ + int orig_ctx = *ctx; + css_error error; + const css_token *token; + uint8_t flags = 0; + uint16_t value = 0; + uint32_t opv; + css_fixed length = 0; + uint32_t unit = 0; + uint32_t required_size; + bool match; + + /* number | percentage | IDENT(silent, x-soft, soft, medium, loud, + * x-loud, inherit) + */ + token = parserutils_vector_peek(vector, *ctx); + if (token == NULL) { + *ctx = orig_ctx; + return CSS_INVALID; + } + + if (token->type == CSS_TOKEN_IDENT && + (lwc_string_caseless_isequal( + token->idata, c->strings[INHERIT], + &match) == lwc_error_ok && match)) { + parserutils_vector_iterate(vector, ctx); + flags = FLAG_INHERIT; + } else if (token->type == CSS_TOKEN_IDENT && + (lwc_string_caseless_isequal( + token->idata, c->strings[SILENT], + &match) == lwc_error_ok && match)) { + parserutils_vector_iterate(vector, ctx); + value = VOLUME_SILENT; + } else if (token->type == CSS_TOKEN_IDENT && + (lwc_string_caseless_isequal( + token->idata, c->strings[X_SOFT], + &match) == lwc_error_ok && match)) { + parserutils_vector_iterate(vector, ctx); + value = VOLUME_X_SOFT; + } else if (token->type == CSS_TOKEN_IDENT && + (lwc_string_caseless_isequal( + token->idata, c->strings[SOFT], + &match) == lwc_error_ok && match)) { + parserutils_vector_iterate(vector, ctx); + value = VOLUME_SOFT; + } else if (token->type == CSS_TOKEN_IDENT && + (lwc_string_caseless_isequal( + token->idata, c->strings[MEDIUM], + &match) == lwc_error_ok && match)) { + parserutils_vector_iterate(vector, ctx); + value = VOLUME_MEDIUM; + } else if (token->type == CSS_TOKEN_IDENT && + (lwc_string_caseless_isequal( + token->idata, c->strings[LOUD], + &match) == lwc_error_ok && match)) { + parserutils_vector_iterate(vector, ctx); + value = VOLUME_LOUD; + } else if (token->type == CSS_TOKEN_IDENT && + (lwc_string_caseless_isequal( + token->idata, c->strings[X_LOUD], + &match) == lwc_error_ok && match)) { + parserutils_vector_iterate(vector, ctx); + value = VOLUME_X_LOUD; + } else if (token->type == CSS_TOKEN_NUMBER) { + size_t consumed = 0; + length = number_from_lwc_string(token->idata, false, &consumed); + if (consumed != lwc_string_length(token->idata)) { + *ctx = orig_ctx; + return CSS_INVALID; + } + + /* Must be between 0 and 100 */ + if (length < 0 || length > F_100) { + *ctx = orig_ctx; + return CSS_INVALID; + } + + parserutils_vector_iterate(vector, ctx); + value = VOLUME_NUMBER; + } else { + /* Yes, really UNIT_PX -- percentages MUST have a % sign */ + error = parse_unit_specifier(c, vector, ctx, UNIT_PX, + &length, &unit); + if (error != CSS_OK) { + *ctx = orig_ctx; + return error; + } + + if ((unit & UNIT_PCT) == false) { + *ctx = orig_ctx; + return CSS_INVALID; + } + + /* Must be positive */ + if (length < 0) { + *ctx = orig_ctx; + return CSS_INVALID; + } + + value = VOLUME_DIMENSION; + } + + opv = buildOPV(CSS_PROP_VOLUME, flags, value); + + required_size = sizeof(opv); + if ((flags & FLAG_INHERIT) == false && value == VOLUME_NUMBER) + required_size += sizeof(length); + else if ((flags & FLAG_INHERIT) == false && value == VOLUME_DIMENSION) + required_size += sizeof(length) + sizeof(unit); + + /* Allocate result */ + error = css_stylesheet_style_create(c->sheet, required_size, result); + if (error != CSS_OK) { + *ctx = orig_ctx; + return error; + } + + /* Copy the bytecode to it */ + memcpy((*result)->bytecode, &opv, sizeof(opv)); + if ((flags & FLAG_INHERIT) == false && (value == VOLUME_NUMBER || + value == VOLUME_DIMENSION)) + memcpy(((uint8_t *) (*result)->bytecode) + sizeof(opv), + &length, sizeof(length)); + if ((flags & FLAG_INHERIT) == false && value == VOLUME_DIMENSION) + memcpy(((uint8_t *) (*result)->bytecode) + sizeof(opv) + + sizeof(length), &unit, sizeof(unit)); + + return CSS_OK; +} diff --git a/src/parse/properties/white_space.c b/src/parse/properties/white_space.c new file mode 100644 index 0000000..3d57586 --- /dev/null +++ b/src/parse/properties/white_space.c @@ -0,0 +1,91 @@ +/* + * This file is part of LibCSS. + * Licensed under the MIT License, + * http://www.opensource.org/licenses/mit-license.php + * Copyright 2009 John-Mark Bell + */ + +#include +#include + +#include "bytecode/bytecode.h" +#include "bytecode/opcodes.h" +#include "parse/properties/properties.h" +#include "parse/properties/utils.h" + +/** + * Parse white-space + * + * \param c Parsing context + * \param vector Vector of tokens to process + * \param ctx Pointer to vector iteration context + * \param result Pointer to location to receive resulting style + * \return CSS_OK on success, + * CSS_NOMEM on memory exhaustion, + * CSS_INVALID if the input is not valid + * + * Post condition: \a *ctx is updated with the next token to process + * If the input is invalid, then \a *ctx remains unchanged. + */ +css_error parse_white_space(css_language *c, + const parserutils_vector *vector, int *ctx, + css_style **result) +{ + int orig_ctx = *ctx; + css_error error; + const css_token *ident; + uint8_t flags = 0; + uint16_t value = 0; + uint32_t opv; + bool match; + + /* IDENT (normal, pre, nowrap, pre-wrap, pre-line, inherit) */ + ident = parserutils_vector_iterate(vector, ctx); + if (ident == NULL || ident->type != CSS_TOKEN_IDENT) { + *ctx = orig_ctx; + return CSS_INVALID; + } + + if ((lwc_string_caseless_isequal( + ident->idata, c->strings[INHERIT], + &match) == lwc_error_ok && match)) { + flags |= FLAG_INHERIT; + } else if ((lwc_string_caseless_isequal( + ident->idata, c->strings[NORMAL], + &match) == lwc_error_ok && match)) { + value = WHITE_SPACE_NORMAL; + } else if ((lwc_string_caseless_isequal( + ident->idata, c->strings[PRE], + &match) == lwc_error_ok && match)) { + value = WHITE_SPACE_PRE; + } else if ((lwc_string_caseless_isequal( + ident->idata, c->strings[NOWRAP], + &match) == lwc_error_ok && match)) { + value = WHITE_SPACE_NOWRAP; + } else if ((lwc_string_caseless_isequal( + ident->idata, c->strings[PRE_WRAP], + &match) == lwc_error_ok && match)) { + value = WHITE_SPACE_PRE_WRAP; + } else if ((lwc_string_caseless_isequal( + ident->idata, c->strings[PRE_LINE], + &match) == lwc_error_ok && match)) { + value = WHITE_SPACE_PRE_LINE; + } else { + *ctx = orig_ctx; + return CSS_INVALID; + } + + opv = buildOPV(CSS_PROP_WHITE_SPACE, flags, value); + + /* Allocate result */ + error = css_stylesheet_style_create(c->sheet, sizeof(opv), result); + if (error != CSS_OK) { + *ctx = orig_ctx; + return error; + } + + /* Copy the bytecode to it */ + memcpy((*result)->bytecode, &opv, sizeof(opv)); + + return CSS_OK; +} diff --git a/src/parse/properties/widows.c b/src/parse/properties/widows.c new file mode 100644 index 0000000..21101ce --- /dev/null +++ b/src/parse/properties/widows.c @@ -0,0 +1,98 @@ +/* + * This file is part of LibCSS. + * Licensed under the MIT License, + * http://www.opensource.org/licenses/mit-license.php + * Copyright 2009 John-Mark Bell + */ + +#include +#include + +#include "bytecode/bytecode.h" +#include "bytecode/opcodes.h" +#include "parse/properties/properties.h" +#include "parse/properties/utils.h" + +/** + * Parse widows + * + * \param c Parsing context + * \param vector Vector of tokens to process + * \param ctx Pointer to vector iteration context + * \param result Pointer to location to receive resulting style + * \return CSS_OK on success, + * CSS_NOMEM on memory exhaustion, + * CSS_INVALID if the input is not valid + * + * Post condition: \a *ctx is updated with the next token to process + * If the input is invalid, then \a *ctx remains unchanged. + */ +css_error parse_widows(css_language *c, + const parserutils_vector *vector, int *ctx, + css_style **result) +{ + int orig_ctx = *ctx; + css_error error; + const css_token *token; + uint8_t flags = 0; + uint16_t value = 0; + uint32_t opv; + css_fixed num = 0; + uint32_t required_size; + bool match; + + /* | IDENT (inherit) */ + token = parserutils_vector_iterate(vector, ctx); + if (token == NULL || (token->type != CSS_TOKEN_IDENT && + token->type != CSS_TOKEN_NUMBER)) { + *ctx = orig_ctx; + return CSS_INVALID; + } + + if ((lwc_string_caseless_isequal( + token->idata, c->strings[INHERIT], + &match) == lwc_error_ok && match)) { + flags |= FLAG_INHERIT; + } else if (token->type == CSS_TOKEN_NUMBER) { + size_t consumed = 0; + num = number_from_lwc_string(token->idata, true, &consumed); + /* Invalid if there are trailing characters */ + if (consumed != lwc_string_length(token->idata)) { + *ctx = orig_ctx; + return CSS_INVALID; + } + + /* Negative values are nonsensical */ + if (num < 0) { + *ctx = orig_ctx; + return CSS_INVALID; + } + + value = WIDOWS_SET; + } else { + *ctx = orig_ctx; + return CSS_INVALID; + } + + opv = buildOPV(CSS_PROP_WIDOWS, flags, value); + + required_size = sizeof(opv); + if ((flags & FLAG_INHERIT) == false && value == WIDOWS_SET) + required_size += sizeof(num); + + /* Allocate result */ + error = css_stylesheet_style_create(c->sheet, required_size, result); + if (error != CSS_OK) { + *ctx = orig_ctx; + return error; + } + + /* Copy the bytecode to it */ + memcpy((*result)->bytecode, &opv, sizeof(opv)); + if ((flags & FLAG_INHERIT) == false && value == WIDOWS_SET) { + memcpy(((uint8_t *) (*result)->bytecode) + sizeof(opv), + &num, sizeof(num)); + } + + return CSS_OK; +} diff --git a/src/parse/properties/width.c b/src/parse/properties/width.c new file mode 100644 index 0000000..233a7e8 --- /dev/null +++ b/src/parse/properties/width.c @@ -0,0 +1,109 @@ +/* + * This file is part of LibCSS. + * Licensed under the MIT License, + * http://www.opensource.org/licenses/mit-license.php + * Copyright 2009 John-Mark Bell + */ + +#include +#include + +#include "bytecode/bytecode.h" +#include "bytecode/opcodes.h" +#include "parse/properties/properties.h" +#include "parse/properties/utils.h" + +/** + * Parse width + * + * \param c Parsing context + * \param vector Vector of tokens to process + * \param ctx Pointer to vector iteration context + * \param result Pointer to location to receive resulting style + * \return CSS_OK on success, + * CSS_NOMEM on memory exhaustion, + * CSS_INVALID if the input is not valid + * + * Post condition: \a *ctx is updated with the next token to process + * If the input is invalid, then \a *ctx remains unchanged. + */ +css_error parse_width(css_language *c, + const parserutils_vector *vector, int *ctx, + css_style **result) +{ + int orig_ctx = *ctx; + css_error error; + const css_token *token; + uint8_t flags = 0; + uint16_t value = 0; + uint32_t opv; + css_fixed length = 0; + uint32_t unit = 0; + uint32_t required_size; + bool match; + + /* length | percentage | IDENT(auto, inherit) */ + token = parserutils_vector_peek(vector, *ctx); + if (token == NULL) { + *ctx = orig_ctx; + return CSS_INVALID; + } + + if (token->type == CSS_TOKEN_IDENT && + (lwc_string_caseless_isequal( + token->idata, c->strings[INHERIT], + &match) == lwc_error_ok && match)) { + parserutils_vector_iterate(vector, ctx); + flags = FLAG_INHERIT; + } else if (token->type == CSS_TOKEN_IDENT && + (lwc_string_caseless_isequal( + token->idata, c->strings[AUTO], + &match) == lwc_error_ok && match)) { + parserutils_vector_iterate(vector, ctx); + value = WIDTH_AUTO; + } else { + error = parse_unit_specifier(c, vector, ctx, UNIT_PX, + &length, &unit); + if (error != CSS_OK) { + *ctx = orig_ctx; + return error; + } + + if (unit & UNIT_ANGLE || unit & UNIT_TIME || unit & UNIT_FREQ) { + *ctx = orig_ctx; + return CSS_INVALID; + } + + /* Must be positive */ + if (length < 0) { + *ctx = orig_ctx; + return CSS_INVALID; + } + + value = WIDTH_SET; + } + + opv = buildOPV(CSS_PROP_WIDTH, flags, value); + + required_size = sizeof(opv); + if ((flags & FLAG_INHERIT) == false && value == WIDTH_SET) + required_size += sizeof(length) + sizeof(unit); + + /* Allocate result */ + error = css_stylesheet_style_create(c->sheet, required_size, result); + if (error != CSS_OK) { + *ctx = orig_ctx; + return error; + } + + /* Copy the bytecode to it */ + memcpy((*result)->bytecode, &opv, sizeof(opv)); + if ((flags & FLAG_INHERIT) == false && value == WIDTH_SET) { + memcpy(((uint8_t *) (*result)->bytecode) + sizeof(opv), + &length, sizeof(length)); + memcpy(((uint8_t *) (*result)->bytecode) + sizeof(opv) + + sizeof(length), &unit, sizeof(unit)); + } + + return CSS_OK; +} diff --git a/src/parse/properties/word_spacing.c b/src/parse/properties/word_spacing.c new file mode 100644 index 0000000..8466c7f --- /dev/null +++ b/src/parse/properties/word_spacing.c @@ -0,0 +1,104 @@ +/* + * This file is part of LibCSS. + * Licensed under the MIT License, + * http://www.opensource.org/licenses/mit-license.php + * Copyright 2009 John-Mark Bell + */ + +#include +#include + +#include "bytecode/bytecode.h" +#include "bytecode/opcodes.h" +#include "parse/properties/properties.h" +#include "parse/properties/utils.h" + +/** + * Parse word-spacing + * + * \param c Parsing context + * \param vector Vector of tokens to process + * \param ctx Pointer to vector iteration context + * \param result Pointer to location to receive resulting style + * \return CSS_OK on success, + * CSS_NOMEM on memory exhaustion, + * CSS_INVALID if the input is not valid + * + * Post condition: \a *ctx is updated with the next token to process + * If the input is invalid, then \a *ctx remains unchanged. + */ +css_error parse_word_spacing(css_language *c, + const parserutils_vector *vector, int *ctx, + css_style **result) +{ + int orig_ctx = *ctx; + css_error error; + const css_token *token; + uint8_t flags = 0; + uint16_t value = 0; + uint32_t opv; + css_fixed length = 0; + uint32_t unit = 0; + uint32_t required_size; + bool match; + + /* length | IDENT(normal, inherit) */ + token = parserutils_vector_peek(vector, *ctx); + if (token == NULL) { + *ctx = orig_ctx; + return CSS_INVALID; + } + + if (token->type == CSS_TOKEN_IDENT && + (lwc_string_caseless_isequal( + token->idata, c->strings[INHERIT], + &match) == lwc_error_ok && match)) { + parserutils_vector_iterate(vector, ctx); + flags = FLAG_INHERIT; + } else if (token->type == CSS_TOKEN_IDENT && + (lwc_string_caseless_isequal( + token->idata, c->strings[NORMAL], + &match) == lwc_error_ok && match)) { + parserutils_vector_iterate(vector, ctx); + value = WORD_SPACING_NORMAL; + } else { + error = parse_unit_specifier(c, vector, ctx, UNIT_PX, + &length, &unit); + if (error != CSS_OK) { + *ctx = orig_ctx; + return error; + } + + if (unit & UNIT_ANGLE || unit & UNIT_TIME || unit & UNIT_FREQ || + unit & UNIT_PCT) { + *ctx = orig_ctx; + return CSS_INVALID; + } + + value = WORD_SPACING_SET; + } + + opv = buildOPV(CSS_PROP_WORD_SPACING, flags, value); + + required_size = sizeof(opv); + if ((flags & FLAG_INHERIT) == false && value == WORD_SPACING_SET) + required_size += sizeof(length) + sizeof(unit); + + /* Allocate result */ + error = css_stylesheet_style_create(c->sheet, required_size, result); + if (error != CSS_OK) { + *ctx = orig_ctx; + return error; + } + + /* Copy the bytecode to it */ + memcpy((*result)->bytecode, &opv, sizeof(opv)); + if ((flags & FLAG_INHERIT) == false && value == WORD_SPACING_SET) { + memcpy(((uint8_t *) (*result)->bytecode) + sizeof(opv), + &length, sizeof(length)); + memcpy(((uint8_t *) (*result)->bytecode) + sizeof(opv) + + sizeof(length), &unit, sizeof(unit)); + } + + return CSS_OK; +} diff --git a/src/parse/properties/z_index.c b/src/parse/properties/z_index.c new file mode 100644 index 0000000..340626e --- /dev/null +++ b/src/parse/properties/z_index.c @@ -0,0 +1,98 @@ +/* + * This file is part of LibCSS. + * Licensed under the MIT License, + * http://www.opensource.org/licenses/mit-license.php + * Copyright 2009 John-Mark Bell + */ + +#include +#include + +#include "bytecode/bytecode.h" +#include "bytecode/opcodes.h" +#include "parse/properties/properties.h" +#include "parse/properties/utils.h" + +/** + * Parse z-index + * + * \param c Parsing context + * \param vector Vector of tokens to process + * \param ctx Pointer to vector iteration context + * \param result Pointer to location to receive resulting style + * \return CSS_OK on success, + * CSS_NOMEM on memory exhaustion, + * CSS_INVALID if the input is not valid + * + * Post condition: \a *ctx is updated with the next token to process + * If the input is invalid, then \a *ctx remains unchanged. + */ +css_error parse_z_index(css_language *c, + const parserutils_vector *vector, int *ctx, + css_style **result) +{ + int orig_ctx = *ctx; + css_error error; + const css_token *token; + uint8_t flags = 0; + uint16_t value = 0; + uint32_t opv; + css_fixed num = 0; + uint32_t required_size; + bool match; + + /* | IDENT (auto, inherit) */ + token = parserutils_vector_iterate(vector, ctx); + if (token == NULL || (token->type != CSS_TOKEN_IDENT && + token->type != CSS_TOKEN_NUMBER)) { + *ctx = orig_ctx; + return CSS_INVALID; + } + + if (token->type == CSS_TOKEN_IDENT && + (lwc_string_caseless_isequal( + token->idata, c->strings[INHERIT], + &match) == lwc_error_ok && match)) { + flags |= FLAG_INHERIT; + } else if (token->type == CSS_TOKEN_IDENT && + (lwc_string_caseless_isequal( + token->idata, c->strings[AUTO], + &match) == lwc_error_ok && match)) { + value = Z_INDEX_AUTO; + } else if (token->type == CSS_TOKEN_NUMBER) { + size_t consumed = 0; + num = number_from_lwc_string(token->idata, true, &consumed); + /* Invalid if there are trailing characters */ + if (consumed != lwc_string_length(token->idata)) { + *ctx = orig_ctx; + return CSS_INVALID; + } + + value = Z_INDEX_SET; + } else { + *ctx = orig_ctx; + return CSS_INVALID; + } + + opv = buildOPV(CSS_PROP_Z_INDEX, flags, value); + + required_size = sizeof(opv); + if ((flags & FLAG_INHERIT) == false && value == Z_INDEX_SET) + required_size += sizeof(num); + + /* Allocate result */ + error = css_stylesheet_style_create(c->sheet, required_size, result); + if (error != CSS_OK) { + *ctx = orig_ctx; + return error; + } + + /* Copy the bytecode to it */ + memcpy((*result)->bytecode, &opv, sizeof(opv)); + if ((flags & FLAG_INHERIT) == false && value == Z_INDEX_SET) { + memcpy(((uint8_t *) (*result)->bytecode) + sizeof(opv), + &num, sizeof(num)); + } + + return CSS_OK; +} -- cgit v1.2.3