summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorVincent Sanders <vince@netsurf-browser.org>2011-01-02 23:20:31 +0000
committerVincent Sanders <vince@netsurf-browser.org>2011-01-02 23:20:31 +0000
commitf3cf0f579347a16120df8fc1c1ec3cd1f4e6d44e (patch)
tree4b98d88fc719198ebfa28f37a58fb61e8bddfcb8 /src
parent606cf0251feacadcaa63191a643dc8fc57a7c613 (diff)
downloadlibcss-f3cf0f579347a16120df8fc1c1ec3cd1f4e6d44e.tar.gz
libcss-f3cf0f579347a16120df8fc1c1ec3cd1f4e6d44e.tar.bz2
simple properties split in parse similar to select in preparation for future generation
svn path=/trunk/libcss/; revision=11188
Diffstat (limited to 'src')
-rw-r--r--src/parse/properties/Makefile117
-rw-r--r--src/parse/properties/aural.c2156
-rw-r--r--src/parse/properties/azimuth.c245
-rw-r--r--src/parse/properties/background.c508
-rw-r--r--src/parse/properties/background_attachment.c79
-rw-r--r--src/parse/properties/background_color.c94
-rw-r--r--src/parse/properties/background_image.c99
-rw-r--r--src/parse/properties/background_position.c224
-rw-r--r--src/parse/properties/background_repeat.c87
-rw-r--r--src/parse/properties/border.c109
-rw-r--r--src/parse/properties/border_bottom.c35
-rw-r--r--src/parse/properties/border_bottom_color.c36
-rw-r--r--src/parse/properties/border_bottom_style.c36
-rw-r--r--src/parse/properties/border_bottom_width.c36
-rw-r--r--src/parse/properties/border_collapse.c79
-rw-r--r--src/parse/properties/border_color.c266
-rw-r--r--src/parse/properties/border_left.c35
-rw-r--r--src/parse/properties/border_left_color.c36
-rw-r--r--src/parse/properties/border_left_style.c36
-rw-r--r--src/parse/properties/border_left_width.c36
-rw-r--r--src/parse/properties/border_outline.c2221
-rw-r--r--src/parse/properties/border_right.c35
-rw-r--r--src/parse/properties/border_right_color.c36
-rw-r--r--src/parse/properties/border_right_style.c36
-rw-r--r--src/parse/properties/border_right_width.c36
-rw-r--r--src/parse/properties/border_spacing.c143
-rw-r--r--src/parse/properties/border_style.c266
-rw-r--r--src/parse/properties/border_top.c35
-rw-r--r--src/parse/properties/border_top_color.c36
-rw-r--r--src/parse/properties/border_top_style.c36
-rw-r--r--src/parse/properties/border_top_width.c36
-rw-r--r--src/parse/properties/border_width.c266
-rw-r--r--src/parse/properties/bottom.c35
-rw-r--r--src/parse/properties/caption_side.c79
-rw-r--r--src/parse/properties/clear.c87
-rw-r--r--src/parse/properties/clip.c176
-rw-r--r--src/parse/properties/color.c88
-rw-r--r--src/parse/properties/content.c134
-rw-r--r--src/parse/properties/conter_reset.c36
-rw-r--r--src/parse/properties/counter_increment.c36
-rw-r--r--src/parse/properties/cue.c298
-rw-r--r--src/parse/properties/cursor.c (renamed from src/parse/properties/ui.c)0
-rw-r--r--src/parse/properties/direction.c79
-rw-r--r--src/parse/properties/display.c138
-rw-r--r--src/parse/properties/display_sizing.c811
-rw-r--r--src/parse/properties/effects_stacking.c402
-rw-r--r--src/parse/properties/elevation.c145
-rw-r--r--src/parse/properties/empty_cells.c79
-rw-r--r--src/parse/properties/float.c83
-rw-r--r--src/parse/properties/font.c555
-rw-r--r--src/parse/properties/font_family.c199
-rw-r--r--src/parse/properties/font_size.c158
-rw-r--r--src/parse/properties/font_style.c83
-rw-r--r--src/parse/properties/font_variant.c79
-rw-r--r--src/parse/properties/font_weight.c111
-rw-r--r--src/parse/properties/generated_list.c1464
-rw-r--r--src/parse/properties/height.c109
-rw-r--r--src/parse/properties/left.c35
-rw-r--r--src/parse/properties/letter_spacing.c104
-rw-r--r--src/parse/properties/line_height.c129
-rw-r--r--src/parse/properties/list_style.c199
-rw-r--r--src/parse/properties/list_style_image.c99
-rw-r--r--src/parse/properties/list_style_position.c79
-rw-r--r--src/parse/properties/list_style_type.c78
-rw-r--r--src/parse/properties/margin.c173
-rw-r--r--src/parse/properties/margin_bottom.c36
-rw-r--r--src/parse/properties/margin_left.c35
-rw-r--r--src/parse/properties/margin_right.c35
-rw-r--r--src/parse/properties/margin_top.c35
-rw-r--r--src/parse/properties/max_height.c109
-rw-r--r--src/parse/properties/max_width.c109
-rw-r--r--src/parse/properties/min_height.c103
-rw-r--r--src/parse/properties/min_width.c103
-rw-r--r--src/parse/properties/orphans.c98
-rw-r--r--src/parse/properties/outline.c197
-rw-r--r--src/parse/properties/outline_color.c94
-rw-r--r--src/parse/properties/outline_style.c58
-rw-r--r--src/parse/properties/outline_width.c37
-rw-r--r--src/parse/properties/overflow.c87
-rw-r--r--src/parse/properties/padding.c181
-rw-r--r--src/parse/properties/padding_bottom.c36
-rw-r--r--src/parse/properties/padding_left.c36
-rw-r--r--src/parse/properties/padding_right.c36
-rw-r--r--src/parse/properties/padding_top.c36
-rw-r--r--src/parse/properties/page.c401
-rw-r--r--src/parse/properties/page_break_after.c91
-rw-r--r--src/parse/properties/page_break_before.c91
-rw-r--r--src/parse/properties/page_break_inside.c79
-rw-r--r--src/parse/properties/pause.c172
-rw-r--r--src/parse/properties/pause_after.c35
-rw-r--r--src/parse/properties/pause_before.c36
-rw-r--r--src/parse/properties/pitch.c133
-rw-r--r--src/parse/properties/pitch_range.c98
-rw-r--r--src/parse/properties/play_during.c142
-rw-r--r--src/parse/properties/position.c87
-rw-r--r--src/parse/properties/positioning.c540
-rw-r--r--src/parse/properties/quotes.c184
-rw-r--r--src/parse/properties/richness.c98
-rw-r--r--src/parse/properties/right.c35
-rw-r--r--src/parse/properties/speak.c83
-rw-r--r--src/parse/properties/speak_header.c79
-rw-r--r--src/parse/properties/speak_numeral.c79
-rw-r--r--src/parse/properties/speak_punctuation.c79
-rw-r--r--src/parse/properties/speech_rate.c136
-rw-r--r--src/parse/properties/stress.c97
-rw-r--r--src/parse/properties/table.c209
-rw-r--r--src/parse/properties/table_layout.c80
-rw-r--r--src/parse/properties/text.c830
-rw-r--r--src/parse/properties/text_align.c100
-rw-r--r--src/parse/properties/text_decoration.c123
-rw-r--r--src/parse/properties/text_indent.c97
-rw-r--r--src/parse/properties/text_transform.c87
-rw-r--r--src/parse/properties/top.c35
-rw-r--r--src/parse/properties/unicode_bidi.c83
-rw-r--r--src/parse/properties/utils.c1539
-rw-r--r--src/parse/properties/utils.h41
-rw-r--r--src/parse/properties/vertical_align.c147
-rw-r--r--src/parse/properties/visibility.c83
-rw-r--r--src/parse/properties/voice_family.c182
-rw-r--r--src/parse/properties/volume.c161
-rw-r--r--src/parse/properties/white_space.c91
-rw-r--r--src/parse/properties/widows.c98
-rw-r--r--src/parse/properties/width.c109
-rw-r--r--src/parse/properties/word_spacing.c104
-rw-r--r--src/parse/properties/z_index.c98
125 files changed, 11968 insertions, 10456 deletions
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 <jmb@netsurf-browser.org>
- */
-
-#include <assert.h>
-#include <string.h>
-
-#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 <jmb@netsurf-browser.org>
+ */
+
+#include <assert.h>
+#include <string.h>
+
+#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 <jmb@netsurf-browser.org>
+ */
+
+#include <assert.h>
+#include <string.h>
+
+#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 <jmb@netsurf-browser.org>
+ */
+
+#include <assert.h>
+#include <string.h>
+
+#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 <jmb@netsurf-browser.org>
+ */
+
+#include <assert.h>
+#include <string.h>
+
+#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 <jmb@netsurf-browser.org>
+ */
+
+#include <assert.h>
+#include <string.h>
+
+#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 <jmb@netsurf-browser.org>
+ */
+
+#include <assert.h>
+#include <string.h>
+
+#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 <jmb@netsurf-browser.org>
+ */
+
+#include <assert.h>
+#include <string.h>
+
+#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 <jmb@netsurf-browser.org>
+ */
+
+#include <assert.h>
+#include <string.h>
+
+#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 <jmb@netsurf-browser.org>
+ */
+
+#include <assert.h>
+#include <string.h>
+
+#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 <jmb@netsurf-browser.org>
+ */
+
+#include <assert.h>
+#include <string.h>
+
+#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 <jmb@netsurf-browser.org>
+ */
+
+#include <assert.h>
+#include <string.h>
+
+#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 <jmb@netsurf-browser.org>
+ */
+
+#include <assert.h>
+#include <string.h>
+
+#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 <jmb@netsurf-browser.org>
+ */
+
+#include <assert.h>
+#include <string.h>
+
+#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 <jmb@netsurf-browser.org>
+ */
+
+#include <assert.h>
+#include <string.h>
+
+#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 <jmb@netsurf-browser.org>
+ */
+
+#include <assert.h>
+#include <string.h>
+
+#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 <jmb@netsurf-browser.org>
+ */
+
+#include <assert.h>
+#include <string.h>
+
+#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 <jmb@netsurf-browser.org>
+ */
+
+#include <assert.h>
+#include <string.h>
+
+#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 <jmb@netsurf-browser.org>
- */
-
-#include <assert.h>
-#include <string.h>
-
-#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 <jmb@netsurf-browser.org>
+ */
+
+#include <assert.h>
+#include <string.h>
+
+#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 <jmb@netsurf-browser.org>
+ */
+
+#include <assert.h>
+#include <string.h>
+
+#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 <jmb@netsurf-browser.org>
+ */
+
+#include <assert.h>
+#include <string.h>
+
+#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 <jmb@netsurf-browser.org>
+ */
+
+#include <assert.h>
+#include <string.h>
+
+#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 <jmb@netsurf-browser.org>
+ */
+
+#include <assert.h>
+#include <string.h>
+
+#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 <jmb@netsurf-browser.org>
+ */
+
+#include <assert.h>
+#include <string.h>
+
+#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 <jmb@netsurf-browser.org>
+ */
+
+#include <assert.h>
+#include <string.h>
+
+#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 <jmb@netsurf-browser.org>
+ */
+
+#include <assert.h>
+#include <string.h>
+
+#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 <jmb@netsurf-browser.org>
+ */
+
+#include <assert.h>
+#include <string.h>
+
+#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 <jmb@netsurf-browser.org>
+ */
+
+#include <assert.h>
+#include <string.h>
+
+#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 <jmb@netsurf-browser.org>
+ */
+
+#include <assert.h>
+#include <string.h>
+
+#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 <jmb@netsurf-browser.org>
+ */
+
+#include <assert.h>
+#include <string.h>
+
+#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 <jmb@netsurf-browser.org>
+ */
+
+#include <assert.h>
+#include <string.h>
+
+#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 <jmb@netsurf-browser.org>
+ */
+
+#include <assert.h>
+#include <string.h>
+
+#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 <jmb@netsurf-browser.org>
+ */
+
+#include <assert.h>
+#include <string.h>
+
+#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 <jmb@netsurf-browser.org>
+ */
+
+#include <assert.h>
+#include <string.h>
+
+#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 <jmb@netsurf-browser.org>
+ */
+
+#include <assert.h>
+#include <string.h>
+
+#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 <jmb@netsurf-browser.org>
+ */
+
+#include <assert.h>
+#include <string.h>
+
+#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 <jmb@netsurf-browser.org>
+ */
+
+#include <assert.h>
+#include <string.h>
+
+#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 <jmb@netsurf-browser.org>
+ */
+
+#include <assert.h>
+#include <string.h>
+
+#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/ui.c b/src/parse/properties/cursor.c
index 725e7b7..725e7b7 100644
--- a/src/parse/properties/ui.c
+++ b/src/parse/properties/cursor.c
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 <jmb@netsurf-browser.org>
+ */
+
+#include <assert.h>
+#include <string.h>
+
+#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 <jmb@netsurf-browser.org>
+ */
+
+#include <assert.h>
+#include <string.h>
+
+#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 <jmb@netsurf-browser.org>
- */
-
-#include <string.h>
-
-#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 <jmb@netsurf-browser.org>
- */
-
-#include <string.h>
-
-#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;
-
- /* <integer> | 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 <jmb@netsurf-browser.org>
+ */
+
+#include <assert.h>
+#include <string.h>
+
+#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 <jmb@netsurf-browser.org>
+ */
+
+#include <assert.h>
+#include <string.h>
+
+#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 <jmb@netsurf-browser.org>
+ */
+
+#include <assert.h>
+#include <string.h>
+
+#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 <jmb@netsurf-browser.org>
+ */
+
+#include <assert.h>
+#include <string.h>
+
+#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 <jmb@netsurf-browser.org>
+ */
+
+#include <assert.h>
+#include <string.h>
+
+#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 <jmb@netsurf-browser.org>
+ */
+
+#include <assert.h>
+#include <string.h>
+
+#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 <jmb@netsurf-browser.org>
+ */
+
+#include <assert.h>
+#include <string.h>
+
+#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 <jmb@netsurf-browser.org>
+ */
+
+#include <assert.h>
+#include <string.h>
+
+#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 <jmb@netsurf-browser.org>
- */
-
-#include <assert.h>
-#include <string.h>
-
-#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 <integer>? ]+ | 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 <jmb@netsurf-browser.org>
+ */
+
+#include <assert.h>
+#include <string.h>
+
+#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 <jmb@netsurf-browser.org>
+ */
+
+#include <assert.h>
+#include <string.h>
+
+#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 <jmb@netsurf-browser.org>
+ */
+
+#include <assert.h>
+#include <string.h>
+
+#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 <jmb@netsurf-browser.org>
+ */
+
+#include <assert.h>
+#include <string.h>
+
+#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 <jmb@netsurf-browser.org>
+ */
+
+#include <assert.h>
+#include <string.h>
+
+#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 <jmb@netsurf-browser.org>
+ */
+
+#include <assert.h>
+#include <string.h>
+
+#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 <jmb@netsurf-browser.org>
+ */
+
+#include <assert.h>
+#include <string.h>
+
+#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 <jmb@netsurf-browser.org>
+ */
+
+#include <assert.h>
+#include <string.h>
+
+#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 <jmb@netsurf-browser.org>
+ */
+
+#include <assert.h>
+#include <string.h>
+
+#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 <jmb@netsurf-browser.org>
+ */
+
+#include <assert.h>
+#include <string.h>
+
+#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 <jmb@netsurf-browser.org>
+ */
+
+#include <assert.h>
+#include <string.h>
+
+#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 <jmb@netsurf-browser.org>
+ */
+
+#include <assert.h>
+#include <string.h>
+
+#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 <jmb@netsurf-browser.org>
+ */
+
+#include <assert.h>
+#include <string.h>
+
+#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 <jmb@netsurf-browser.org>
+ */
+
+#include <assert.h>
+#include <string.h>
+
+#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 <jmb@netsurf-browser.org>
+ */
+
+#include <assert.h>
+#include <string.h>
+
+#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 <jmb@netsurf-browser.org>
+ */
+
+#include <assert.h>
+#include <string.h>
+
+#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 <jmb@netsurf-browser.org>
+ */
+
+#include <assert.h>
+#include <string.h>
+
+#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;
+
+ /* <integer> | 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 <jmb@netsurf-browser.org>
+ */
+
+#include <assert.h>
+#include <string.h>
+
+#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 <jmb@netsurf-browser.org>
+ */
+
+#include <assert.h>
+#include <string.h>
+
+#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 <jmb@netsurf-browser.org>
+ */
+
+#include <assert.h>
+#include <string.h>
+
+#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 <jmb@netsurf-browser.org>
+ */
+
+#include <assert.h>
+#include <string.h>
+
+#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 <jmb@netsurf-browser.org>
+ */
+
+#include <assert.h>
+#include <string.h>
+
+#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 <jmb@netsurf-browser.org>
+ */
+
+#include <assert.h>
+#include <string.h>
+
+#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 <jmb@netsurf-browser.org>
+ */
+
+#include <assert.h>
+#include <string.h>
+
+#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 <jmb@netsurf-browser.org>
+ */
+
+#include <assert.h>
+#include <string.h>
+
+#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 <jmb@netsurf-browser.org>
+ */
+
+#include <assert.h>
+#include <string.h>
+
+#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 <jmb@netsurf-browser.org>
- */
-
-#include <string.h>
-
-#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;
-
- /* <integer> | 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;
-
- /* <integer> | 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 <jmb@netsurf-browser.org>
+ */
+
+#include <assert.h>
+#include <string.h>
+
+#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 <jmb@netsurf-browser.org>
+ */
+
+#include <assert.h>
+#include <string.h>
+
+#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 <jmb@netsurf-browser.org>
+ */
+
+#include <assert.h>
+#include <string.h>
+
+#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 <jmb@netsurf-browser.org>
+ */
+
+#include <assert.h>
+#include <string.h>
+
+#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 <jmb@netsurf-browser.org>
+ */
+
+#include <assert.h>
+#include <string.h>
+
+#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 <jmb@netsurf-browser.org>
+ */
+
+#include <assert.h>
+#include <string.h>
+
+#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 <jmb@netsurf-browser.org>
+ */
+
+#include <assert.h>
+#include <string.h>
+
+#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 <jmb@netsurf-browser.org>
+ */
+
+#include <assert.h>
+#include <string.h>
+
+#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 <jmb@netsurf-browser.org>
+ */
+
+#include <assert.h>
+#include <string.h>
+
+#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 <jmb@netsurf-browser.org>
+ */
+
+#include <assert.h>
+#include <string.h>
+
+#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 <jmb@netsurf-browser.org>
- */
-
-#include <string.h>
-
-#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 <jmb@netsurf-browser.org>
+ */
+
+#include <assert.h>
+#include <string.h>
+
+#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 <jmb@netsurf-browser.org>
+ */
+
+#include <assert.h>
+#include <string.h>
+
+#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 <jmb@netsurf-browser.org>
+ */
+
+#include <assert.h>
+#include <string.h>
+
+#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 <jmb@netsurf-browser.org>
+ */
+
+#include <assert.h>
+#include <string.h>
+
+#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 <jmb@netsurf-browser.org>
+ */
+
+#include <assert.h>
+#include <string.h>
+
+#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 <jmb@netsurf-browser.org>
+ */
+
+#include <assert.h>
+#include <string.h>
+
+#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 <jmb@netsurf-browser.org>
+ */
+
+#include <assert.h>
+#include <string.h>
+
+#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 <jmb@netsurf-browser.org>
+ */
+
+#include <assert.h>
+#include <string.h>
+
+#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 <jmb@netsurf-browser.org>
+ */
+
+#include <assert.h>
+#include <string.h>
+
+#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 <jmb@netsurf-browser.org>
- */
-
-#include <string.h>
-
-#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 <jmb@netsurf-browser.org>
+ */
+
+#include <assert.h>
+#include <string.h>
+
+#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 <jmb@netsurf-browser.org>
- */
-
-#include <string.h>
-
-#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 <jmb@netsurf-browser.org>
+ */
+
+#include <assert.h>
+#include <string.h>
+
+#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 <jmb@netsurf-browser.org>
+ */
+
+#include <assert.h>
+#include <string.h>
+
+#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 <jmb@netsurf-browser.org>
+ */
+
+#include <assert.h>
+#include <string.h>
+
+#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 <jmb@netsurf-browser.org>
+ */
+
+#include <assert.h>
+#include <string.h>
+
+#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 <jmb@netsurf-browser.org>
+ */
+
+#include <assert.h>
+#include <string.h>
+
+#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/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 <jmb@netsurf-browser.org>
+ */
+
+#include <assert.h>
+#include <string.h>
+
+#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,18 +1,1553 @@
/*
* This file is part of LibCSS.
* Licensed under the MIT License,
- * http://www.opensource.org/licenses/mit-license.php
- * Copyright 2008 John-Mark Bell <jmb@netsurf-browser.org>
+ * http://www.opensource.org/licenses/mit-license.php
+ * Copyright 2009 John-Mark Bell <jmb@netsurf-browser.org>
*/
+#include <assert.h>
#include <string.h>
#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 <integer>? ]+ | 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
*
* \param c Parsing context
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 <jmb@netsurf-browser.org>
+ */
+
+#include <assert.h>
+#include <string.h>
+
+#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 <jmb@netsurf-browser.org>
+ */
+
+#include <assert.h>
+#include <string.h>
+
+#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 <jmb@netsurf-browser.org>
+ */
+
+#include <assert.h>
+#include <string.h>
+
+#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 <jmb@netsurf-browser.org>
+ */
+
+#include <assert.h>
+#include <string.h>
+
+#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 <jmb@netsurf-browser.org>
+ */
+
+#include <assert.h>
+#include <string.h>
+
+#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 <jmb@netsurf-browser.org>
+ */
+
+#include <assert.h>
+#include <string.h>
+
+#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;
+
+ /* <integer> | 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 <jmb@netsurf-browser.org>
+ */
+
+#include <assert.h>
+#include <string.h>
+
+#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 <jmb@netsurf-browser.org>
+ */
+
+#include <assert.h>
+#include <string.h>
+
+#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 <jmb@netsurf-browser.org>
+ */
+
+#include <assert.h>
+#include <string.h>
+
+#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;
+
+ /* <integer> | 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;
+}