diff options
-rw-r--r-- | src/parse/properties/Makefile | 2 | ||||
-rw-r--r-- | src/parse/properties/aural.c | 1554 | ||||
-rw-r--r-- | src/parse/properties/properties.c | 2069 | ||||
-rw-r--r-- | src/parse/properties/utils.c | 486 | ||||
-rw-r--r-- | src/parse/properties/utils.h | 29 |
5 files changed, 2091 insertions, 2049 deletions
diff --git a/src/parse/properties/Makefile b/src/parse/properties/Makefile index 3afed97..bfca56e 100644 --- a/src/parse/properties/Makefile +++ b/src/parse/properties/Makefile @@ -1,4 +1,4 @@ # Sources -DIR_SOURCES := properties.c +DIR_SOURCES := aural.c properties.c utils.c include build/makefiles/Makefile.subdir diff --git a/src/parse/properties/aural.c b/src/parse/properties/aural.c new file mode 100644 index 0000000..c548ff1 --- /dev/null +++ b/src/parse/properties/aural.c @@ -0,0 +1,1554 @@ +/* + * 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" + +css_error parse_azimuth(css_language *c, + const parserutils_vector *vector, int *ctx, + css_style **result) +{ + 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; + + /* 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) + return CSS_INVALID; + + if (token->type == CSS_TOKEN_IDENT && + token->ilower == c->strings[INHERIT]) { + parserutils_vector_iterate(vector, ctx); + flags = FLAG_INHERIT; + } else if (token->type == CSS_TOKEN_IDENT && + token->ilower == c->strings[LEFTWARDS]) { + parserutils_vector_iterate(vector, ctx); + value = AZIMUTH_LEFTWARDS; + } else if (token->type == CSS_TOKEN_IDENT && + token->ilower == c->strings[RIGHTWARDS]) { + 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 (token->ilower == c->strings[LEFT_SIDE]) { + value = AZIMUTH_LEFT_SIDE; + } else if (token->ilower == c->strings[FAR_LEFT]) { + value = AZIMUTH_FAR_LEFT; + } else if (token->ilower == c->strings[LEFT]) { + value = AZIMUTH_LEFT; + } else if (token->ilower == c->strings[CENTER_LEFT]) { + value = AZIMUTH_CENTER_LEFT; + } else if (token->ilower == c->strings[CENTER]) { + value = AZIMUTH_CENTER; + } else if (token->ilower == c->strings[CENTER_RIGHT]) { + value = AZIMUTH_CENTER_RIGHT; + } else if (token->ilower == c->strings[RIGHT]) { + value = AZIMUTH_RIGHT; + } else if (token->ilower == c->strings[FAR_RIGHT]) { + value = AZIMUTH_FAR_RIGHT; + } else if (token->ilower == c->strings[RIGHT_SIDE]) { + value = AZIMUTH_RIGHT_SIDE; + } else if (token->ilower == c->strings[BEHIND]) { + value = AZIMUTH_BEHIND; + } else { + return CSS_INVALID; + } + + consumeWhitespace(vector, ctx); + + /* Get potential following token */ + token = parserutils_vector_peek(vector, *ctx); + if (token != NULL && token->type != CSS_TOKEN_IDENT && + tokenIsChar(token, '!') == false) + return CSS_INVALID; + + if (token != NULL && token->type == CSS_TOKEN_IDENT && + value == AZIMUTH_BEHIND) { + parserutils_vector_iterate(vector, ctx); + + if (token->ilower == c->strings[LEFT_SIDE]) { + value |= AZIMUTH_LEFT_SIDE; + } else if (token->ilower == c->strings[FAR_LEFT]) { + value |= AZIMUTH_FAR_LEFT; + } else if (token->ilower == c->strings[LEFT]) { + value |= AZIMUTH_LEFT; + } else if (token->ilower == c->strings[CENTER-LEFT]) { + value |= AZIMUTH_CENTER_LEFT; + } else if (token->ilower == c->strings[CENTER]) { + value |= AZIMUTH_CENTER; + } else if (token->ilower == c->strings[CENTER-RIGHT]) { + value |= AZIMUTH_CENTER_RIGHT; + } else if (token->ilower == c->strings[RIGHT]) { + value |= AZIMUTH_RIGHT; + } else if (token->ilower == c->strings[FAR_RIGHT]) { + value |= AZIMUTH_FAR_RIGHT; + } else if (token->ilower == c->strings[RIGHT_SIDE]) { + value |= AZIMUTH_RIGHT_SIDE; + } else { + return CSS_INVALID; + } + } else if (token != NULL && token->type == CSS_TOKEN_IDENT && + value != AZIMUTH_BEHIND) { + parserutils_vector_iterate(vector, ctx); + + if (token->ilower == c->strings[BEHIND]) { + value |= AZIMUTH_BEHIND; + } else { + 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) + return error; + + if ((unit & UNIT_ANGLE) == false) + return CSS_INVALID; + + /* Valid angles lie between -360 and 360 degrees */ + if (unit == UNIT_DEG) { + if (length < FMULI(F_360, -1) || length > F_360) + return CSS_INVALID; + } else if (unit == UNIT_GRAD) { + if (length < FMULI(F_400, -1) || length > F_400) + return CSS_INVALID; + } else if (unit == UNIT_RAD) { + if (length < FMULI(F_2PI, -1) || length > F_2PI) + return CSS_INVALID; + } + + value = AZIMUTH_ANGLE; + } + + error = parse_important(c, vector, ctx, &flags); + if (error != CSS_OK) + return error; + + 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) + 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; +} + +css_error parse_cue_after(css_language *c, + const parserutils_vector *vector, int *ctx, + css_style **result) +{ + css_error error; + const css_token *token; + uint8_t flags = 0; + uint16_t value = 0; + uint32_t opv; + uint32_t required_size; + + /* URI | IDENT (none, inherit) */ + token = parserutils_vector_iterate(vector, ctx); + if (token == NULL || (token->type != CSS_TOKEN_IDENT && + token->type != CSS_TOKEN_URI)) + return CSS_INVALID; + + error = parse_important(c, vector, ctx, &flags); + if (error != CSS_OK) + return error; + + if (token->type == CSS_TOKEN_IDENT && + token->ilower == c->strings[INHERIT]) { + flags |= FLAG_INHERIT; + } else if (token->type == CSS_TOKEN_IDENT && + token->ilower == c->strings[NONE]) { + value = CUE_AFTER_NONE; + } else if (token->type == CSS_TOKEN_URI) { + value = CUE_AFTER_URI; + } else + return CSS_INVALID; + + opv = buildOPV(CSS_PROP_CUE_AFTER, 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) + return error; + + /* Copy the bytecode to it */ + memcpy((*result)->bytecode, &opv, sizeof(opv)); + if ((flags & FLAG_INHERIT) == false && value == CUE_AFTER_URI) { + lwc_context_string_ref(c->sheet->dictionary, token->idata); + memcpy((uint8_t *) (*result)->bytecode + sizeof(opv), + &token->idata, + sizeof(lwc_string *)); + } + + return CSS_OK; +} + +css_error parse_cue_before(css_language *c, + const parserutils_vector *vector, int *ctx, + css_style **result) +{ + css_error error; + const css_token *token; + uint8_t flags = 0; + uint16_t value = 0; + uint32_t opv; + uint32_t required_size; + + /* URI | IDENT (none, inherit) */ + token = parserutils_vector_iterate(vector, ctx); + if (token == NULL || (token->type != CSS_TOKEN_IDENT && + token->type != CSS_TOKEN_URI)) + return CSS_INVALID; + + error = parse_important(c, vector, ctx, &flags); + if (error != CSS_OK) + return error; + + if (token->type == CSS_TOKEN_IDENT && + token->ilower == c->strings[INHERIT]) { + flags |= FLAG_INHERIT; + } else if (token->type == CSS_TOKEN_IDENT && + token->ilower == c->strings[NONE]) { + value = CUE_BEFORE_NONE; + } else if (token->type == CSS_TOKEN_URI) { + value = CUE_BEFORE_URI; + } else + return CSS_INVALID; + + opv = buildOPV(CSS_PROP_CUE_BEFORE, flags, value); + + required_size = sizeof(opv); + if ((flags & FLAG_INHERIT) == false && value == CUE_BEFORE_URI) + required_size += sizeof(lwc_string *); + + /* Allocate result */ + error = css_stylesheet_style_create(c->sheet, required_size, result); + if (error != CSS_OK) + return error; + + /* Copy the bytecode to it */ + memcpy((*result)->bytecode, &opv, sizeof(opv)); + if ((flags & FLAG_INHERIT) == false && value == CUE_BEFORE_URI) { + lwc_context_string_ref(c->sheet->dictionary, token->idata); + memcpy((uint8_t *) (*result)->bytecode + sizeof(opv), + &token->idata, + sizeof(lwc_string *)); + } + + return CSS_OK; +} + +css_error parse_elevation(css_language *c, + const parserutils_vector *vector, int *ctx, + css_style **result) +{ + 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; + + /* angle | IDENT(below, level, above, higher, lower, inherit) */ + token = parserutils_vector_peek(vector, *ctx); + if (token == NULL) + return CSS_INVALID; + + if (token->type == CSS_TOKEN_IDENT && + token->ilower == c->strings[INHERIT]) { + parserutils_vector_iterate(vector, ctx); + flags = FLAG_INHERIT; + } else if (token->type == CSS_TOKEN_IDENT && + token->ilower == c->strings[BELOW]) { + parserutils_vector_iterate(vector, ctx); + value = ELEVATION_BELOW; + } else if (token->type == CSS_TOKEN_IDENT && + token->ilower == c->strings[LEVEL]) { + parserutils_vector_iterate(vector, ctx); + value = ELEVATION_LEVEL; + } else if (token->type == CSS_TOKEN_IDENT && + token->ilower == c->strings[ABOVE]) { + parserutils_vector_iterate(vector, ctx); + value = ELEVATION_ABOVE; + } else if (token->type == CSS_TOKEN_IDENT && + token->ilower == c->strings[HIGHER]) { + parserutils_vector_iterate(vector, ctx); + value = ELEVATION_HIGHER; + } else if (token->type == CSS_TOKEN_IDENT && + token->ilower == c->strings[LOWER]) { + parserutils_vector_iterate(vector, ctx); + value = ELEVATION_LOWER; + } else { + error = parse_unit_specifier(c, vector, ctx, UNIT_DEG, + &length, &unit); + if (error != CSS_OK) + return error; + + if ((unit & UNIT_ANGLE) == false) + return CSS_INVALID; + + /* Valid angles lie between -90 and 90 degrees */ + if (unit == UNIT_DEG) { + if (length < FMULI(F_90, -1) || length > F_90) + return CSS_INVALID; + } else if (unit == UNIT_GRAD) { + if (length < FMULI(F_100, -1) || length > F_100) + return CSS_INVALID; + } else if (unit == UNIT_RAD) { + if (length < FMULI(F_PI_2, -1) || length > F_PI_2) + return CSS_INVALID; + } + + value = ELEVATION_ANGLE; + } + + error = parse_important(c, vector, ctx, &flags); + if (error != CSS_OK) + return error; + + 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) + 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; +} + +css_error parse_pause_after(css_language *c, + const parserutils_vector *vector, int *ctx, + css_style **result) +{ + 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; + + /* time | percentage | IDENT(inherit) */ + token = parserutils_vector_peek(vector, *ctx); + if (token == NULL) + return CSS_INVALID; + + if (token->type == CSS_TOKEN_IDENT && + token->ilower == c->strings[INHERIT]) { + parserutils_vector_iterate(vector, ctx); + flags = FLAG_INHERIT; + } else { + error = parse_unit_specifier(c, vector, ctx, UNIT_S, + &length, &unit); + if (error != CSS_OK) + return error; + + if ((unit & UNIT_TIME) == false && (unit & UNIT_PCT) == false) + return CSS_INVALID; + + /* Negative values are illegal */ + if (length < 0) + return CSS_INVALID; + + value = PAUSE_AFTER_SET; + } + + error = parse_important(c, vector, ctx, &flags); + if (error != CSS_OK) + return error; + + opv = buildOPV(CSS_PROP_PAUSE_AFTER, 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) + 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; +} + +css_error parse_pause_before(css_language *c, + const parserutils_vector *vector, int *ctx, + css_style **result) +{ + 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; + + /* time | percentage | IDENT(inherit) */ + token = parserutils_vector_peek(vector, *ctx); + if (token == NULL) + return CSS_INVALID; + + if (token->type == CSS_TOKEN_IDENT && + token->ilower == c->strings[INHERIT]) { + parserutils_vector_iterate(vector, ctx); + flags = FLAG_INHERIT; + } else { + error = parse_unit_specifier(c, vector, ctx, UNIT_S, + &length, &unit); + if (error != CSS_OK) + return error; + + if ((unit & UNIT_TIME) == false && (unit & UNIT_PCT) == false) + return CSS_INVALID; + + /* Negative values are illegal */ + if (length < 0) + return CSS_INVALID; + + value = PAUSE_BEFORE_SET; + } + + error = parse_important(c, vector, ctx, &flags); + if (error != CSS_OK) + return error; + + opv = buildOPV(CSS_PROP_PAUSE_BEFORE, flags, value); + + required_size = sizeof(opv); + if ((flags & FLAG_INHERIT) == false && value == PAUSE_BEFORE_SET) + required_size += sizeof(length) + sizeof(unit); + + /* Allocate result */ + error = css_stylesheet_style_create(c->sheet, required_size, result); + if (error != CSS_OK) + return error; + + /* Copy the bytecode to it */ + memcpy((*result)->bytecode, &opv, sizeof(opv)); + if ((flags & FLAG_INHERIT) == false && value == PAUSE_BEFORE_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; +} + +css_error parse_pitch_range(css_language *c, + const parserutils_vector *vector, int *ctx, + css_style **result) +{ + 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; + + /* number | IDENT (inherit) */ + token = parserutils_vector_iterate(vector, ctx); + if (token == NULL || (token->type != CSS_TOKEN_IDENT && + token->type != CSS_TOKEN_NUMBER)) + return CSS_INVALID; + + error = parse_important(c, vector, ctx, &flags); + if (error != CSS_OK) + return error; + + if (token->ilower == c->strings[INHERIT]) { + flags |= FLAG_INHERIT; + } else if (token->type == CSS_TOKEN_NUMBER) { + size_t consumed = 0; + num = number_from_lwc_string(token->ilower, false, &consumed); + /* Invalid if there are trailing characters */ + if (consumed != lwc_string_length(token->ilower)) + return CSS_INVALID; + + /* Must be between 0 and 100 */ + if (num < 0 || num > F_100) + return CSS_INVALID; + + value = PITCH_RANGE_SET; + } else + 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) + 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; +} + +css_error parse_pitch(css_language *c, + const parserutils_vector *vector, int *ctx, + css_style **result) +{ + 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; + + /* frequency | IDENT(x-low, low, medium, high, x-high, inherit) */ + token = parserutils_vector_peek(vector, *ctx); + if (token == NULL) + return CSS_INVALID; + + if (token->type == CSS_TOKEN_IDENT && + token->ilower == c->strings[INHERIT]) { + parserutils_vector_iterate(vector, ctx); + flags = FLAG_INHERIT; + } else if (token->type == CSS_TOKEN_IDENT && + token->ilower == c->strings[X_LOW]) { + parserutils_vector_iterate(vector, ctx); + value = PITCH_X_LOW; + } else if (token->type == CSS_TOKEN_IDENT && + token->ilower == c->strings[LOW]) { + parserutils_vector_iterate(vector, ctx); + value = PITCH_LOW; + } else if (token->type == CSS_TOKEN_IDENT && + token->ilower == c->strings[MEDIUM]) { + parserutils_vector_iterate(vector, ctx); + value = PITCH_MEDIUM; + } else if (token->type == CSS_TOKEN_IDENT && + token->ilower == c->strings[HIGH]) { + parserutils_vector_iterate(vector, ctx); + value = PITCH_HIGH; + } else if (token->type == CSS_TOKEN_IDENT && + token->ilower == c->strings[X_HIGH]) { + 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) + return error; + + if ((unit & UNIT_FREQ) == false) + return CSS_INVALID; + + /* Negative values are invalid */ + if (length < 0) + return CSS_INVALID; + + value = PITCH_FREQUENCY; + } + + error = parse_important(c, vector, ctx, &flags); + if (error != CSS_OK) + return error; + + 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) + 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; +} + +css_error parse_play_during(css_language *c, + const parserutils_vector *vector, int *ctx, + css_style **result) +{ + 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; + + /* 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)) + return CSS_INVALID; + + if (token->type == CSS_TOKEN_IDENT) { + if (token->ilower == c->strings[INHERIT]) { + flags |= FLAG_INHERIT; + } else if (token->ilower == c->strings[NONE]) { + value = PLAY_DURING_NONE; + } else if (token->ilower == c->strings[AUTO]) { + value = PLAY_DURING_AUTO; + } else + return CSS_INVALID; + } else { + int flags; + + value = PLAY_DURING_URI; + uri = token->idata; + + for (flags = 0; flags < 2; flags++) { + consumeWhitespace(vector, ctx); + + token = parserutils_vector_peek(vector, *ctx); + if (token != NULL && token->type == CSS_TOKEN_IDENT) { + if (token->ilower == c->strings[MIX]) { + if ((value & PLAY_DURING_MIX) == 0) + value |= PLAY_DURING_MIX; + else + return CSS_INVALID; + } else if (token->ilower == + c->strings[REPEAT]) { + if ((value & PLAY_DURING_REPEAT) == 0) + value |= PLAY_DURING_REPEAT; + else + return CSS_INVALID; + } else + return CSS_INVALID; + + parserutils_vector_iterate(vector, ctx); + } + } + } + + error = parse_important(c, vector, ctx, &flags); + if (error != CSS_OK) + return error; + + 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) + 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) { + lwc_context_string_ref(c->sheet->dictionary, uri); + memcpy((uint8_t *) (*result)->bytecode + sizeof(opv), + &uri, sizeof(lwc_string *)); + } + + return CSS_OK; +} + +css_error parse_richness(css_language *c, + const parserutils_vector *vector, int *ctx, + css_style **result) +{ + 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; + + /* number | IDENT (inherit) */ + token = parserutils_vector_iterate(vector, ctx); + if (token == NULL || (token->type != CSS_TOKEN_IDENT && + token->type != CSS_TOKEN_NUMBER)) + return CSS_INVALID; + + error = parse_important(c, vector, ctx, &flags); + if (error != CSS_OK) + return error; + + if (token->ilower == c->strings[INHERIT]) { + flags |= FLAG_INHERIT; + } else if (token->type == CSS_TOKEN_NUMBER) { + size_t consumed = 0; + num = number_from_lwc_string(token->ilower, false, &consumed); + /* Invalid if there are trailing characters */ + if (consumed != lwc_string_length(token->ilower)) + return CSS_INVALID; + + /* Must be between 0 and 100 */ + if (num < 0 || num > F_100) + return CSS_INVALID; + + value = RICHNESS_SET; + } else + 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) + 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; +} + +css_error parse_speak_header(css_language *c, + const parserutils_vector *vector, int *ctx, + css_style **result) +{ + css_error error; + const css_token *ident; + uint8_t flags = 0; + uint16_t value = 0; + uint32_t opv; + + /* IDENT (once, always, inherit) */ + ident = parserutils_vector_iterate(vector, ctx); + if (ident == NULL || ident->type != CSS_TOKEN_IDENT) + return CSS_INVALID; + + error = parse_important(c, vector, ctx, &flags); + if (error != CSS_OK) + return error; + + if (ident->ilower == c->strings[INHERIT]) { + flags |= FLAG_INHERIT; + } else if (ident->ilower == c->strings[ONCE]) { + value = SPEAK_HEADER_ONCE; + } else if (ident->ilower == c->strings[ALWAYS]) { + value = SPEAK_HEADER_ALWAYS; + } else + 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) + return error; + + /* Copy the bytecode to it */ + memcpy((*result)->bytecode, &opv, sizeof(opv)); + + return CSS_OK; +} + +css_error parse_speak_numeral(css_language *c, + const parserutils_vector *vector, int *ctx, + css_style **result) +{ + css_error error; + const css_token *ident; + uint8_t flags = 0; + uint16_t value = 0; + uint32_t opv; + + /* IDENT (digits, continuous, inherit) */ + ident = parserutils_vector_iterate(vector, ctx); + if (ident == NULL || ident->type != CSS_TOKEN_IDENT) + return CSS_INVALID; + + error = parse_important(c, vector, ctx, &flags); + if (error != CSS_OK) + return error; + + if (ident->ilower == c->strings[INHERIT]) { + flags |= FLAG_INHERIT; + } else if (ident->ilower == c->strings[DIGITS]) { + value = SPEAK_NUMERAL_DIGITS; + } else if (ident->ilower == c->strings[CONTINUOUS]) { + value = SPEAK_NUMERAL_CONTINUOUS; + } else + 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) + return error; + + /* Copy the bytecode to it */ + memcpy((*result)->bytecode, &opv, sizeof(opv)); + + return CSS_OK; +} + +css_error parse_speak_punctuation(css_language *c, + const parserutils_vector *vector, int *ctx, + css_style **result) +{ + css_error error; + const css_token *ident; + uint8_t flags = 0; + uint16_t value = 0; + uint32_t opv; + + /* IDENT (code, none, inherit) */ + ident = parserutils_vector_iterate(vector, ctx); + if (ident == NULL || ident->type != CSS_TOKEN_IDENT) + return CSS_INVALID; + + error = parse_important(c, vector, ctx, &flags); + if (error != CSS_OK) + return error; + + if (ident->ilower == c->strings[INHERIT]) { + flags |= FLAG_INHERIT; + } else if (ident->ilower == c->strings[CODE]) { + value = SPEAK_PUNCTUATION_CODE; + } else if (ident->ilower == c->strings[NONE]) { + value = SPEAK_PUNCTUATION_NONE; + } else + 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) + return error; + + /* Copy the bytecode to it */ + memcpy((*result)->bytecode, &opv, sizeof(opv)); + + return CSS_OK; +} + +css_error parse_speak(css_language *c, + const parserutils_vector *vector, int *ctx, + css_style **result) +{ + css_error error; + const css_token *ident; + uint8_t flags = 0; + uint16_t value = 0; + uint32_t opv; + + /* IDENT (normal, none, spell-out, inherit) */ + ident = parserutils_vector_iterate(vector, ctx); + if (ident == NULL || ident->type != CSS_TOKEN_IDENT) + return CSS_INVALID; + + error = parse_important(c, vector, ctx, &flags); + if (error != CSS_OK) + return error; + + if (ident->ilower == c->strings[INHERIT]) { + flags |= FLAG_INHERIT; + } else if (ident->ilower == c->strings[NORMAL]) { + value = SPEAK_NORMAL; + } else if (ident->ilower == c->strings[NONE]) { + value = SPEAK_NONE; + } else if (ident->ilower == c->strings[SPELL_OUT]) { + value = SPEAK_SPELL_OUT; + } else + 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) + return error; + + /* Copy the bytecode to it */ + memcpy((*result)->bytecode, &opv, sizeof(opv)); + + return CSS_OK; +} + +css_error parse_speech_rate(css_language *c, + const parserutils_vector *vector, int *ctx, + css_style **result) +{ + 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; + + /* 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)) + return CSS_INVALID; + + error = parse_important(c, vector, ctx, &flags); + if (error != CSS_OK) + return error; + + if (token->type == CSS_TOKEN_IDENT && + token->ilower == c->strings[INHERIT]) { + flags |= FLAG_INHERIT; + } else if (token->type == CSS_TOKEN_IDENT && + token->ilower == c->strings[X_SLOW]) { + value = SPEECH_RATE_X_SLOW; + } else if (token->type == CSS_TOKEN_IDENT && + token->ilower == c->strings[SLOW]) { + value = SPEECH_RATE_SLOW; + } else if (token->type == CSS_TOKEN_IDENT && + token->ilower == c->strings[MEDIUM]) { + value = SPEECH_RATE_MEDIUM; + } else if (token->type == CSS_TOKEN_IDENT && + token->ilower == c->strings[FAST]) { + value = SPEECH_RATE_FAST; + } else if (token->type == CSS_TOKEN_IDENT && + token->ilower == c->strings[X_FAST]) { + value = SPEECH_RATE_X_FAST; + } else if (token->type == CSS_TOKEN_IDENT && + token->ilower == c->strings[FASTER]) { + value = SPEECH_RATE_FASTER; + } else if (token->type == CSS_TOKEN_IDENT && + token->ilower == c->strings[SLOWER]) { + value = SPEECH_RATE_SLOWER; + } else if (token->type == CSS_TOKEN_NUMBER) { + size_t consumed = 0; + num = number_from_lwc_string(token->ilower, false, &consumed); + /* Invalid if there are trailing characters */ + if (consumed != lwc_string_length(token->ilower)) + return CSS_INVALID; + + /* Make negative values invalid */ + if (num < 0) + return CSS_INVALID; + + value = SPEECH_RATE_SET; + } else + 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) + 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; +} + +css_error parse_stress(css_language *c, + const parserutils_vector *vector, int *ctx, + css_style **result) +{ + 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; + + /* number | IDENT (inherit) */ + token = parserutils_vector_iterate(vector, ctx); + if (token == NULL || (token->type != CSS_TOKEN_IDENT && + token->type != CSS_TOKEN_NUMBER)) + return CSS_INVALID; + + error = parse_important(c, vector, ctx, &flags); + if (error != CSS_OK) + return error; + + if (token->ilower == c->strings[INHERIT]) { + flags |= FLAG_INHERIT; + } else if (token->type == CSS_TOKEN_NUMBER) { + size_t consumed = 0; + num = number_from_lwc_string(token->ilower, false, &consumed); + /* Invalid if there are trailing characters */ + if (consumed != lwc_string_length(token->ilower)) + return CSS_INVALID; + + if (num < 0 || num > INTTOFIX(100)) + return CSS_INVALID; + + value = STRESS_SET; + } else + 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) + 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; +} + +css_error parse_voice_family(css_language *c, + const parserutils_vector *vector, int *ctx, + css_style **result) +{ + 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; + + /* [ 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)) + return CSS_INVALID; + + if (token->type == CSS_TOKEN_IDENT && + token->ilower == c->strings[INHERIT]) { + flags = FLAG_INHERIT; + } else { + bool first = true; + + while (token != NULL) { + if (token->type == CSS_TOKEN_IDENT) { + if (first == false) { + required_size += sizeof(opv); + } + + if (token->ilower == c->strings[MALE]) { + if (first) { + value = VOICE_FAMILY_MALE; + } + } else if (token->ilower == + c->strings[FEMALE]) { + if (first) { + value = VOICE_FAMILY_FEMALE; + } + } else if (token->ilower == c->strings[CHILD]) { + if (first) { + value = VOICE_FAMILY_CHILD; + } + } else { + if (first) { + value = VOICE_FAMILY_IDENT_LIST; + } + + required_size += + sizeof(lwc_string *); + + /* Skip past [ IDENT* S* ]* */ + while (token != NULL) { + token = parserutils_vector_peek( + vector, + temp_ctx); + if (token != NULL && + token->type != + CSS_TOKEN_IDENT && + token->type != + CSS_TOKEN_S) { + break; + } + + /* idents must not match + * generic families */ + if (token != NULL && token->type == CSS_TOKEN_IDENT && + (token->ilower == c->strings[MALE] || + token->ilower == c->strings[FEMALE] || + token->ilower == c->strings[CHILD])) + return CSS_INVALID; + token = parserutils_vector_iterate( + vector, &temp_ctx); + } + } + } else if (token->type == CSS_TOKEN_STRING) { + if (first == false) { + required_size += sizeof(opv); + } else { + value = VOICE_FAMILY_STRING; + } + + required_size += + sizeof(lwc_string *); + } else { + return CSS_INVALID; + } + + consumeWhitespace(vector, &temp_ctx); + + token = parserutils_vector_peek(vector, temp_ctx); + if (token != NULL && tokenIsChar(token, ',') == false && + tokenIsChar(token, '!') == false) { + return CSS_INVALID; + } + + if (token != NULL && tokenIsChar(token, ',')) { + parserutils_vector_iterate(vector, &temp_ctx); + + consumeWhitespace(vector, &temp_ctx); + + token = parserutils_vector_peek(vector, + temp_ctx); + if (token == NULL || tokenIsChar(token, '!')) + return CSS_INVALID; + } + + first = false; + + token = parserutils_vector_peek(vector, temp_ctx); + if (token != NULL && tokenIsChar(token, '!')) + break; + + token = parserutils_vector_iterate(vector, &temp_ctx); + } + + required_size += sizeof(opv); + } + + error = parse_important(c, vector, &temp_ctx, &flags); + if (error != CSS_OK) + return error; + + opv = buildOPV(CSS_PROP_VOICE_FAMILY, flags, value); + + /* Allocate result */ + error = css_stylesheet_style_create(c->sheet, required_size, result); + if (error != CSS_OK) + 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); + *result = NULL; + return CSS_INVALID; + } + + if (token->type == CSS_TOKEN_IDENT && + token->ilower == c->strings[INHERIT]) { + /* Nothing to do */ + } else { + bool first = true; + + while (token != NULL) { + if (token->type == CSS_TOKEN_IDENT) { + lwc_string *tok_idata = token->idata; + lwc_string *name = tok_idata; + lwc_string *newname; + + if (token->ilower == c->strings[MALE]) { + opv = VOICE_FAMILY_MALE; + } else if (token->ilower == + c->strings[FEMALE]) { + opv = VOICE_FAMILY_FEMALE; + } else if (token->ilower == c->strings[CHILD]) { + opv = VOICE_FAMILY_CHILD; + } else { + uint16_t len = lwc_string_length(token->idata); + const css_token *temp_token = token; + lwc_error lerror; + uint8_t *buf; + uint8_t *p; + + temp_ctx = *ctx; + + opv = VOICE_FAMILY_IDENT_LIST; + + /* Build string from idents */ + while (temp_token != NULL) { + temp_token = parserutils_vector_peek( + vector, temp_ctx); + if (temp_token != NULL && + temp_token->type != + CSS_TOKEN_IDENT && + temp_token->type != + CSS_TOKEN_S) { + break; + } + + if (temp_token != NULL && temp_token->type == CSS_TOKEN_IDENT) { + len += lwc_string_length(temp_token->idata); + } else if (temp_token != NULL) { + len += 1; + } + + temp_token = parserutils_vector_iterate( + vector, &temp_ctx); + } + + /** \todo Don't use alloca */ + buf = alloca(len); + p = buf; + + memcpy(p, lwc_string_data(token->idata), lwc_string_length(token->idata)); + p += lwc_string_length(token->idata); + + while (token != NULL) { + token = parserutils_vector_peek( + vector, *ctx); + if (token != NULL && + token->type != + CSS_TOKEN_IDENT && + token->type != + CSS_TOKEN_S) { + break; + } + + if (token != NULL && + token->type == + CSS_TOKEN_IDENT) { + memcpy(p, + lwc_string_data(token->idata), + lwc_string_length(token->idata)); + p += lwc_string_length(token->idata); + } else if (token != NULL) { + *p++ = ' '; + } + + token = parserutils_vector_iterate( + vector, ctx); + } + + /* Strip trailing whitespace */ + while (p > buf && p[-1] == ' ') + p--; + + /* Insert into hash, if it's different + * from the name we already have */ + lerror = lwc_context_intern(c->sheet->dictionary, + (char *)buf, len, &newname); + if (lerror != lwc_error_ok) { + css_stylesheet_style_destroy(c->sheet, *result); + *result = NULL; + return css_error_from_lwc_error(lerror); + } + + if (newname == name) + lwc_context_string_unref(c->sheet->dictionary, + newname); + + name = newname; + } + + if (first == false) { + memcpy(ptr, &opv, sizeof(opv)); + ptr += sizeof(opv); + } + + if (opv == VOICE_FAMILY_IDENT_LIST) { + /* Only ref 'name' again if the token owns it, + * otherwise we already own the only ref to the + * new name generated above. + */ + if (name == tok_idata) + lwc_context_string_ref(c->sheet->dictionary, name); + memcpy(ptr, &name, sizeof(name)); + ptr += sizeof(name); + } + } else if (token->type == CSS_TOKEN_STRING) { + opv = VOICE_FAMILY_STRING; + + if (first == false) { + memcpy(ptr, &opv, sizeof(opv)); + ptr += sizeof(opv); + } + + lwc_context_string_ref(c->sheet->dictionary, token->idata); + memcpy(ptr, &token->idata, + sizeof(token->idata)); + ptr += sizeof(token->idata); + } else { + css_stylesheet_style_destroy(c->sheet, *result); + *result = NULL; + return CSS_INVALID; + } + + consumeWhitespace(vector, ctx); + + token = parserutils_vector_peek(vector, *ctx); + if (token != NULL && tokenIsChar(token, ',') == false && + tokenIsChar(token, '!') == false) { + css_stylesheet_style_destroy(c->sheet, *result); + *result = NULL; + return CSS_INVALID; + } + + if (token != NULL && tokenIsChar(token, ',')) { + parserutils_vector_iterate(vector, ctx); + + consumeWhitespace(vector, ctx); + + token = parserutils_vector_peek(vector, *ctx); + if (token == NULL || tokenIsChar(token, '!')) { + css_stylesheet_style_destroy(c->sheet, + *result); + *result = NULL; + return CSS_INVALID; + } + } + + first = false; + + token = parserutils_vector_peek(vector, *ctx); + if (token != NULL && tokenIsChar(token, '!')) + break; + + token = parserutils_vector_iterate(vector, ctx); + } + + /* Write terminator */ + opv = VOICE_FAMILY_END; + memcpy(ptr, &opv, sizeof(opv)); + ptr += sizeof(opv); + } + + error = parse_important(c, vector, ctx, &flags); + if (error != CSS_OK) { + css_stylesheet_style_destroy(c->sheet, *result); + *result = NULL; + return error; + } + + return CSS_OK; +} + +css_error parse_volume(css_language *c, + const parserutils_vector *vector, int *ctx, + css_style **result) +{ + 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; + + /* number | percentage | IDENT(silent, x-soft, soft, medium, loud, + * x-loud, inherit) + */ + token = parserutils_vector_peek(vector, *ctx); + if (token == NULL) + return CSS_INVALID; + + if (token->type == CSS_TOKEN_IDENT && + token->ilower == c->strings[INHERIT]) { + parserutils_vector_iterate(vector, ctx); + flags = FLAG_INHERIT; + } else if (token->type == CSS_TOKEN_IDENT && + token->ilower == c->strings[SILENT]) { + parserutils_vector_iterate(vector, ctx); + value = VOLUME_SILENT; + } else if (token->type == CSS_TOKEN_IDENT && + token->ilower == c->strings[X_SOFT]) { + parserutils_vector_iterate(vector, ctx); + value = VOLUME_X_SOFT; + } else if (token->type == CSS_TOKEN_IDENT && + token->ilower == c->strings[SOFT]) { + parserutils_vector_iterate(vector, ctx); + value = VOLUME_SOFT; + } else if (token->type == CSS_TOKEN_IDENT && + token->ilower == c->strings[MEDIUM]) { + parserutils_vector_iterate(vector, ctx); + value = VOLUME_MEDIUM; + } else if (token->type == CSS_TOKEN_IDENT && + token->ilower == c->strings[LOUD]) { + parserutils_vector_iterate(vector, ctx); + value = VOLUME_LOUD; + } else if (token->type == CSS_TOKEN_IDENT && + token->ilower == c->strings[X_LOUD]) { + 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->ilower, false, &consumed); + if (consumed != lwc_string_length(token->ilower)) + return CSS_INVALID; + + /* Must be between 0 and 100 */ + if (length < 0 || length > F_100) + 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) + return error; + + if ((unit & UNIT_PCT) == false) + return CSS_INVALID; + + /* Must be positive */ + if (length < 0) + return CSS_INVALID; + + value = VOLUME_DIMENSION; + } + + error = parse_important(c, vector, ctx, &flags); + if (error != CSS_OK) + return error; + + 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) + 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/properties.c b/src/parse/properties/properties.c index 0442543..8033cf1 100644 --- a/src/parse/properties/properties.c +++ b/src/parse/properties/properties.c @@ -11,43 +11,7 @@ #include "bytecode/bytecode.h" #include "bytecode/opcodes.h" #include "parse/properties/properties.h" - -static inline css_error parse_important(css_language *c, - const parserutils_vector *vector, int *ctx, - uint8_t *result); -static inline css_error parse_colour_specifier(css_language *c, - const parserutils_vector *vector, int *ctx, - uint32_t *result); -static css_error parse_named_colour(css_language *c, lwc_string *data, - uint32_t *result); -static inline css_error parse_hash_colour(lwc_string *data, uint32_t *result); -static inline css_error parse_unit_specifier(css_language *c, - const parserutils_vector *vector, int *ctx, - uint32_t default_unit, - css_fixed *length, uint32_t *unit); -static inline css_error parse_unit_keyword(const char *ptr, size_t len, - css_unit *unit); - -static inline css_error parse_border_side_color(css_language *c, - const parserutils_vector *vector, int *ctx, - uint16_t op, css_style **result); -static inline css_error parse_border_side_style(css_language *c, - const parserutils_vector *vector, int *ctx, - uint16_t op, css_style **result); -static inline css_error parse_border_side_width(css_language *c, - const parserutils_vector *vector, int *ctx, - uint16_t op, css_style **result); -static inline css_error parse_margin_side(css_language *c, - const parserutils_vector *vector, int *ctx, - uint16_t op, css_style **result); -static inline css_error parse_padding_side(css_language *c, - const parserutils_vector *vector, int *ctx, - uint16_t op, css_style **result); -static inline css_error parse_list_style_type_value(css_language *c, - const css_token *token, uint16_t *value); -static inline css_error parse_content_list(css_language *c, - const parserutils_vector *vector, int *ctx, - uint16_t *value, uint8_t *buffer, uint32_t *buflen); +#include "parse/properties/utils.h" /** * Dispatch table of property handlers, indexed by property enum @@ -155,167 +119,26 @@ const css_prop_handler property_handlers[LAST_PROP + 1 - FIRST_PROP] = parse_z_index, }; -css_error parse_azimuth(css_language *c, - const parserutils_vector *vector, int *ctx, - css_style **result) -{ - 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; - - /* 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) - return CSS_INVALID; - - if (token->type == CSS_TOKEN_IDENT && - token->ilower == c->strings[INHERIT]) { - parserutils_vector_iterate(vector, ctx); - flags = FLAG_INHERIT; - } else if (token->type == CSS_TOKEN_IDENT && - token->ilower == c->strings[LEFTWARDS]) { - parserutils_vector_iterate(vector, ctx); - value = AZIMUTH_LEFTWARDS; - } else if (token->type == CSS_TOKEN_IDENT && - token->ilower == c->strings[RIGHTWARDS]) { - 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 (token->ilower == c->strings[LEFT_SIDE]) { - value = AZIMUTH_LEFT_SIDE; - } else if (token->ilower == c->strings[FAR_LEFT]) { - value = AZIMUTH_FAR_LEFT; - } else if (token->ilower == c->strings[LEFT]) { - value = AZIMUTH_LEFT; - } else if (token->ilower == c->strings[CENTER_LEFT]) { - value = AZIMUTH_CENTER_LEFT; - } else if (token->ilower == c->strings[CENTER]) { - value = AZIMUTH_CENTER; - } else if (token->ilower == c->strings[CENTER_RIGHT]) { - value = AZIMUTH_CENTER_RIGHT; - } else if (token->ilower == c->strings[RIGHT]) { - value = AZIMUTH_RIGHT; - } else if (token->ilower == c->strings[FAR_RIGHT]) { - value = AZIMUTH_FAR_RIGHT; - } else if (token->ilower == c->strings[RIGHT_SIDE]) { - value = AZIMUTH_RIGHT_SIDE; - } else if (token->ilower == c->strings[BEHIND]) { - value = AZIMUTH_BEHIND; - } else { - return CSS_INVALID; - } - - consumeWhitespace(vector, ctx); - - /* Get potential following token */ - token = parserutils_vector_peek(vector, *ctx); - if (token != NULL && token->type != CSS_TOKEN_IDENT && - tokenIsChar(token, '!') == false) - return CSS_INVALID; - - if (token != NULL && token->type == CSS_TOKEN_IDENT && - value == AZIMUTH_BEHIND) { - parserutils_vector_iterate(vector, ctx); - - if (token->ilower == c->strings[LEFT_SIDE]) { - value |= AZIMUTH_LEFT_SIDE; - } else if (token->ilower == c->strings[FAR_LEFT]) { - value |= AZIMUTH_FAR_LEFT; - } else if (token->ilower == c->strings[LEFT]) { - value |= AZIMUTH_LEFT; - } else if (token->ilower == c->strings[CENTER-LEFT]) { - value |= AZIMUTH_CENTER_LEFT; - } else if (token->ilower == c->strings[CENTER]) { - value |= AZIMUTH_CENTER; - } else if (token->ilower == c->strings[CENTER-RIGHT]) { - value |= AZIMUTH_CENTER_RIGHT; - } else if (token->ilower == c->strings[RIGHT]) { - value |= AZIMUTH_RIGHT; - } else if (token->ilower == c->strings[FAR_RIGHT]) { - value |= AZIMUTH_FAR_RIGHT; - } else if (token->ilower == c->strings[RIGHT_SIDE]) { - value |= AZIMUTH_RIGHT_SIDE; - } else { - return CSS_INVALID; - } - } else if (token != NULL && token->type == CSS_TOKEN_IDENT && - value != AZIMUTH_BEHIND) { - parserutils_vector_iterate(vector, ctx); - - if (token->ilower == c->strings[BEHIND]) { - value |= AZIMUTH_BEHIND; - } else { - 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) - return error; - - if ((unit & UNIT_ANGLE) == false) - return CSS_INVALID; - - /* Valid angles lie between -360 and 360 degrees */ - if (unit == UNIT_DEG) { - if (length < FMULI(F_360, -1) || length > F_360) - return CSS_INVALID; - } else if (unit == UNIT_GRAD) { - if (length < FMULI(F_400, -1) || length > F_400) - return CSS_INVALID; - } else if (unit == UNIT_RAD) { - if (length < FMULI(F_2PI, -1) || length > F_2PI) - return CSS_INVALID; - } - - value = AZIMUTH_ANGLE; - } - - error = parse_important(c, vector, ctx, &flags); - if (error != CSS_OK) - return error; - - 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) - 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; -} +static inline css_error parse_border_side_color(css_language *c, + const parserutils_vector *vector, int *ctx, + uint16_t op, css_style **result); +static inline css_error parse_border_side_style(css_language *c, + const parserutils_vector *vector, int *ctx, + uint16_t op, css_style **result); +static inline css_error parse_border_side_width(css_language *c, + const parserutils_vector *vector, int *ctx, + uint16_t op, css_style **result); +static inline css_error parse_margin_side(css_language *c, + const parserutils_vector *vector, int *ctx, + uint16_t op, css_style **result); +static inline css_error parse_padding_side(css_language *c, + const parserutils_vector *vector, int *ctx, + uint16_t op, css_style **result); +static inline css_error parse_list_style_type_value(css_language *c, + const css_token *token, uint16_t *value); +static inline 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_background_attachment(css_language *c, const parserutils_vector *vector, int *ctx, @@ -1662,116 +1485,6 @@ css_error parse_counter_reset(css_language *c, return CSS_OK; } -css_error parse_cue_after(css_language *c, - const parserutils_vector *vector, int *ctx, - css_style **result) -{ - css_error error; - const css_token *token; - uint8_t flags = 0; - uint16_t value = 0; - uint32_t opv; - uint32_t required_size; - - /* URI | IDENT (none, inherit) */ - token = parserutils_vector_iterate(vector, ctx); - if (token == NULL || (token->type != CSS_TOKEN_IDENT && - token->type != CSS_TOKEN_URI)) - return CSS_INVALID; - - error = parse_important(c, vector, ctx, &flags); - if (error != CSS_OK) - return error; - - if (token->type == CSS_TOKEN_IDENT && - token->ilower == c->strings[INHERIT]) { - flags |= FLAG_INHERIT; - } else if (token->type == CSS_TOKEN_IDENT && - token->ilower == c->strings[NONE]) { - value = CUE_AFTER_NONE; - } else if (token->type == CSS_TOKEN_URI) { - value = CUE_AFTER_URI; - } else - return CSS_INVALID; - - opv = buildOPV(CSS_PROP_CUE_AFTER, 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) - return error; - - /* Copy the bytecode to it */ - memcpy((*result)->bytecode, &opv, sizeof(opv)); - if ((flags & FLAG_INHERIT) == false && value == CUE_AFTER_URI) { - lwc_context_string_ref(c->sheet->dictionary, token->idata); - memcpy((uint8_t *) (*result)->bytecode + sizeof(opv), - &token->idata, - sizeof(lwc_string *)); - } - - return CSS_OK; -} - -css_error parse_cue_before(css_language *c, - const parserutils_vector *vector, int *ctx, - css_style **result) -{ - css_error error; - const css_token *token; - uint8_t flags = 0; - uint16_t value = 0; - uint32_t opv; - uint32_t required_size; - - /* URI | IDENT (none, inherit) */ - token = parserutils_vector_iterate(vector, ctx); - if (token == NULL || (token->type != CSS_TOKEN_IDENT && - token->type != CSS_TOKEN_URI)) - return CSS_INVALID; - - error = parse_important(c, vector, ctx, &flags); - if (error != CSS_OK) - return error; - - if (token->type == CSS_TOKEN_IDENT && - token->ilower == c->strings[INHERIT]) { - flags |= FLAG_INHERIT; - } else if (token->type == CSS_TOKEN_IDENT && - token->ilower == c->strings[NONE]) { - value = CUE_BEFORE_NONE; - } else if (token->type == CSS_TOKEN_URI) { - value = CUE_BEFORE_URI; - } else - return CSS_INVALID; - - opv = buildOPV(CSS_PROP_CUE_BEFORE, flags, value); - - required_size = sizeof(opv); - if ((flags & FLAG_INHERIT) == false && value == CUE_BEFORE_URI) - required_size += sizeof(lwc_string *); - - /* Allocate result */ - error = css_stylesheet_style_create(c->sheet, required_size, result); - if (error != CSS_OK) - return error; - - /* Copy the bytecode to it */ - memcpy((*result)->bytecode, &opv, sizeof(opv)); - if ((flags & FLAG_INHERIT) == false && value == CUE_BEFORE_URI) { - lwc_context_string_ref(c->sheet->dictionary, token->idata); - memcpy((uint8_t *) (*result)->bytecode + sizeof(opv), - &token->idata, - sizeof(lwc_string *)); - } - - return CSS_OK; -} - css_error parse_cursor(css_language *c, const parserutils_vector *vector, int *ctx, css_style **result) @@ -2151,99 +1864,6 @@ css_error parse_display(css_language *c, return CSS_OK; } -css_error parse_elevation(css_language *c, - const parserutils_vector *vector, int *ctx, - css_style **result) -{ - 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; - - /* angle | IDENT(below, level, above, higher, lower, inherit) */ - token = parserutils_vector_peek(vector, *ctx); - if (token == NULL) - return CSS_INVALID; - - if (token->type == CSS_TOKEN_IDENT && - token->ilower == c->strings[INHERIT]) { - parserutils_vector_iterate(vector, ctx); - flags = FLAG_INHERIT; - } else if (token->type == CSS_TOKEN_IDENT && - token->ilower == c->strings[BELOW]) { - parserutils_vector_iterate(vector, ctx); - value = ELEVATION_BELOW; - } else if (token->type == CSS_TOKEN_IDENT && - token->ilower == c->strings[LEVEL]) { - parserutils_vector_iterate(vector, ctx); - value = ELEVATION_LEVEL; - } else if (token->type == CSS_TOKEN_IDENT && - token->ilower == c->strings[ABOVE]) { - parserutils_vector_iterate(vector, ctx); - value = ELEVATION_ABOVE; - } else if (token->type == CSS_TOKEN_IDENT && - token->ilower == c->strings[HIGHER]) { - parserutils_vector_iterate(vector, ctx); - value = ELEVATION_HIGHER; - } else if (token->type == CSS_TOKEN_IDENT && - token->ilower == c->strings[LOWER]) { - parserutils_vector_iterate(vector, ctx); - value = ELEVATION_LOWER; - } else { - error = parse_unit_specifier(c, vector, ctx, UNIT_DEG, - &length, &unit); - if (error != CSS_OK) - return error; - - if ((unit & UNIT_ANGLE) == false) - return CSS_INVALID; - - /* Valid angles lie between -90 and 90 degrees */ - if (unit == UNIT_DEG) { - if (length < FMULI(F_90, -1) || length > F_90) - return CSS_INVALID; - } else if (unit == UNIT_GRAD) { - if (length < FMULI(F_100, -1) || length > F_100) - return CSS_INVALID; - } else if (unit == UNIT_RAD) { - if (length < FMULI(F_PI_2, -1) || length > F_PI_2) - return CSS_INVALID; - } - - value = ELEVATION_ANGLE; - } - - error = parse_important(c, vector, ctx, &flags); - if (error != CSS_OK) - return error; - - 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) - 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; -} - css_error parse_empty_cells(css_language *c, const parserutils_vector *vector, int *ctx, css_style **result) @@ -4029,366 +3649,6 @@ css_error parse_page_break_inside(css_language *c, return CSS_OK; } -css_error parse_pause_after(css_language *c, - const parserutils_vector *vector, int *ctx, - css_style **result) -{ - 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; - - /* time | percentage | IDENT(inherit) */ - token = parserutils_vector_peek(vector, *ctx); - if (token == NULL) - return CSS_INVALID; - - if (token->type == CSS_TOKEN_IDENT && - token->ilower == c->strings[INHERIT]) { - parserutils_vector_iterate(vector, ctx); - flags = FLAG_INHERIT; - } else { - error = parse_unit_specifier(c, vector, ctx, UNIT_S, - &length, &unit); - if (error != CSS_OK) - return error; - - if ((unit & UNIT_TIME) == false && (unit & UNIT_PCT) == false) - return CSS_INVALID; - - /* Negative values are illegal */ - if (length < 0) - return CSS_INVALID; - - value = PAUSE_AFTER_SET; - } - - error = parse_important(c, vector, ctx, &flags); - if (error != CSS_OK) - return error; - - opv = buildOPV(CSS_PROP_PAUSE_AFTER, 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) - 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; -} - -css_error parse_pause_before(css_language *c, - const parserutils_vector *vector, int *ctx, - css_style **result) -{ - 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; - - /* time | percentage | IDENT(inherit) */ - token = parserutils_vector_peek(vector, *ctx); - if (token == NULL) - return CSS_INVALID; - - if (token->type == CSS_TOKEN_IDENT && - token->ilower == c->strings[INHERIT]) { - parserutils_vector_iterate(vector, ctx); - flags = FLAG_INHERIT; - } else { - error = parse_unit_specifier(c, vector, ctx, UNIT_S, - &length, &unit); - if (error != CSS_OK) - return error; - - if ((unit & UNIT_TIME) == false && (unit & UNIT_PCT) == false) - return CSS_INVALID; - - /* Negative values are illegal */ - if (length < 0) - return CSS_INVALID; - - value = PAUSE_BEFORE_SET; - } - - error = parse_important(c, vector, ctx, &flags); - if (error != CSS_OK) - return error; - - opv = buildOPV(CSS_PROP_PAUSE_BEFORE, flags, value); - - required_size = sizeof(opv); - if ((flags & FLAG_INHERIT) == false && value == PAUSE_BEFORE_SET) - required_size += sizeof(length) + sizeof(unit); - - /* Allocate result */ - error = css_stylesheet_style_create(c->sheet, required_size, result); - if (error != CSS_OK) - return error; - - /* Copy the bytecode to it */ - memcpy((*result)->bytecode, &opv, sizeof(opv)); - if ((flags & FLAG_INHERIT) == false && value == PAUSE_BEFORE_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; -} - -css_error parse_pitch_range(css_language *c, - const parserutils_vector *vector, int *ctx, - css_style **result) -{ - 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; - - /* number | IDENT (inherit) */ - token = parserutils_vector_iterate(vector, ctx); - if (token == NULL || (token->type != CSS_TOKEN_IDENT && - token->type != CSS_TOKEN_NUMBER)) - return CSS_INVALID; - - error = parse_important(c, vector, ctx, &flags); - if (error != CSS_OK) - return error; - - if (token->ilower == c->strings[INHERIT]) { - flags |= FLAG_INHERIT; - } else if (token->type == CSS_TOKEN_NUMBER) { - size_t consumed = 0; - num = number_from_lwc_string(token->ilower, false, &consumed); - /* Invalid if there are trailing characters */ - if (consumed != lwc_string_length(token->ilower)) - return CSS_INVALID; - - /* Must be between 0 and 100 */ - if (num < 0 || num > F_100) - return CSS_INVALID; - - value = PITCH_RANGE_SET; - } else - 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) - 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; -} - -css_error parse_pitch(css_language *c, - const parserutils_vector *vector, int *ctx, - css_style **result) -{ - 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; - - /* frequency | IDENT(x-low, low, medium, high, x-high, inherit) */ - token = parserutils_vector_peek(vector, *ctx); - if (token == NULL) - return CSS_INVALID; - - if (token->type == CSS_TOKEN_IDENT && - token->ilower == c->strings[INHERIT]) { - parserutils_vector_iterate(vector, ctx); - flags = FLAG_INHERIT; - } else if (token->type == CSS_TOKEN_IDENT && - token->ilower == c->strings[X_LOW]) { - parserutils_vector_iterate(vector, ctx); - value = PITCH_X_LOW; - } else if (token->type == CSS_TOKEN_IDENT && - token->ilower == c->strings[LOW]) { - parserutils_vector_iterate(vector, ctx); - value = PITCH_LOW; - } else if (token->type == CSS_TOKEN_IDENT && - token->ilower == c->strings[MEDIUM]) { - parserutils_vector_iterate(vector, ctx); - value = PITCH_MEDIUM; - } else if (token->type == CSS_TOKEN_IDENT && - token->ilower == c->strings[HIGH]) { - parserutils_vector_iterate(vector, ctx); - value = PITCH_HIGH; - } else if (token->type == CSS_TOKEN_IDENT && - token->ilower == c->strings[X_HIGH]) { - 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) - return error; - - if ((unit & UNIT_FREQ) == false) - return CSS_INVALID; - - /* Negative values are invalid */ - if (length < 0) - return CSS_INVALID; - - value = PITCH_FREQUENCY; - } - - error = parse_important(c, vector, ctx, &flags); - if (error != CSS_OK) - return error; - - 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) - 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; -} - -css_error parse_play_during(css_language *c, - const parserutils_vector *vector, int *ctx, - css_style **result) -{ - 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; - - /* 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)) - return CSS_INVALID; - - if (token->type == CSS_TOKEN_IDENT) { - if (token->ilower == c->strings[INHERIT]) { - flags |= FLAG_INHERIT; - } else if (token->ilower == c->strings[NONE]) { - value = PLAY_DURING_NONE; - } else if (token->ilower == c->strings[AUTO]) { - value = PLAY_DURING_AUTO; - } else - return CSS_INVALID; - } else { - int flags; - - value = PLAY_DURING_URI; - uri = token->idata; - - for (flags = 0; flags < 2; flags++) { - consumeWhitespace(vector, ctx); - - token = parserutils_vector_peek(vector, *ctx); - if (token != NULL && token->type == CSS_TOKEN_IDENT) { - if (token->ilower == c->strings[MIX]) { - if ((value & PLAY_DURING_MIX) == 0) - value |= PLAY_DURING_MIX; - else - return CSS_INVALID; - } else if (token->ilower == - c->strings[REPEAT]) { - if ((value & PLAY_DURING_REPEAT) == 0) - value |= PLAY_DURING_REPEAT; - else - return CSS_INVALID; - } else - return CSS_INVALID; - - parserutils_vector_iterate(vector, ctx); - } - } - } - - error = parse_important(c, vector, ctx, &flags); - if (error != CSS_OK) - return error; - - 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) - 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) { - lwc_context_string_ref(c->sheet->dictionary, uri); - memcpy((uint8_t *) (*result)->bytecode + sizeof(opv), - &uri, sizeof(lwc_string *)); - } - - return CSS_OK; -} - css_error parse_position(css_language *c, const parserutils_vector *vector, int *ctx, css_style **result) @@ -4592,66 +3852,6 @@ css_error parse_quotes(css_language *c, return CSS_OK; } -css_error parse_richness(css_language *c, - const parserutils_vector *vector, int *ctx, - css_style **result) -{ - 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; - - /* number | IDENT (inherit) */ - token = parserutils_vector_iterate(vector, ctx); - if (token == NULL || (token->type != CSS_TOKEN_IDENT && - token->type != CSS_TOKEN_NUMBER)) - return CSS_INVALID; - - error = parse_important(c, vector, ctx, &flags); - if (error != CSS_OK) - return error; - - if (token->ilower == c->strings[INHERIT]) { - flags |= FLAG_INHERIT; - } else if (token->type == CSS_TOKEN_NUMBER) { - size_t consumed = 0; - num = number_from_lwc_string(token->ilower, false, &consumed); - /* Invalid if there are trailing characters */ - if (consumed != lwc_string_length(token->ilower)) - return CSS_INVALID; - - /* Must be between 0 and 100 */ - if (num < 0 || num > F_100) - return CSS_INVALID; - - value = RICHNESS_SET; - } else - 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) - 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; -} - css_error parse_right(css_language *c, const parserutils_vector *vector, int *ctx, css_style **result) @@ -4717,315 +3917,6 @@ css_error parse_right(css_language *c, return CSS_OK; } -css_error parse_speak_header(css_language *c, - const parserutils_vector *vector, int *ctx, - css_style **result) -{ - css_error error; - const css_token *ident; - uint8_t flags = 0; - uint16_t value = 0; - uint32_t opv; - - /* IDENT (once, always, inherit) */ - ident = parserutils_vector_iterate(vector, ctx); - if (ident == NULL || ident->type != CSS_TOKEN_IDENT) - return CSS_INVALID; - - error = parse_important(c, vector, ctx, &flags); - if (error != CSS_OK) - return error; - - if (ident->ilower == c->strings[INHERIT]) { - flags |= FLAG_INHERIT; - } else if (ident->ilower == c->strings[ONCE]) { - value = SPEAK_HEADER_ONCE; - } else if (ident->ilower == c->strings[ALWAYS]) { - value = SPEAK_HEADER_ALWAYS; - } else - 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) - return error; - - /* Copy the bytecode to it */ - memcpy((*result)->bytecode, &opv, sizeof(opv)); - - return CSS_OK; -} - -css_error parse_speak_numeral(css_language *c, - const parserutils_vector *vector, int *ctx, - css_style **result) -{ - css_error error; - const css_token *ident; - uint8_t flags = 0; - uint16_t value = 0; - uint32_t opv; - - /* IDENT (digits, continuous, inherit) */ - ident = parserutils_vector_iterate(vector, ctx); - if (ident == NULL || ident->type != CSS_TOKEN_IDENT) - return CSS_INVALID; - - error = parse_important(c, vector, ctx, &flags); - if (error != CSS_OK) - return error; - - if (ident->ilower == c->strings[INHERIT]) { - flags |= FLAG_INHERIT; - } else if (ident->ilower == c->strings[DIGITS]) { - value = SPEAK_NUMERAL_DIGITS; - } else if (ident->ilower == c->strings[CONTINUOUS]) { - value = SPEAK_NUMERAL_CONTINUOUS; - } else - 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) - return error; - - /* Copy the bytecode to it */ - memcpy((*result)->bytecode, &opv, sizeof(opv)); - - return CSS_OK; -} - -css_error parse_speak_punctuation(css_language *c, - const parserutils_vector *vector, int *ctx, - css_style **result) -{ - css_error error; - const css_token *ident; - uint8_t flags = 0; - uint16_t value = 0; - uint32_t opv; - - /* IDENT (code, none, inherit) */ - ident = parserutils_vector_iterate(vector, ctx); - if (ident == NULL || ident->type != CSS_TOKEN_IDENT) - return CSS_INVALID; - - error = parse_important(c, vector, ctx, &flags); - if (error != CSS_OK) - return error; - - if (ident->ilower == c->strings[INHERIT]) { - flags |= FLAG_INHERIT; - } else if (ident->ilower == c->strings[CODE]) { - value = SPEAK_PUNCTUATION_CODE; - } else if (ident->ilower == c->strings[NONE]) { - value = SPEAK_PUNCTUATION_NONE; - } else - 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) - return error; - - /* Copy the bytecode to it */ - memcpy((*result)->bytecode, &opv, sizeof(opv)); - - return CSS_OK; -} - -css_error parse_speak(css_language *c, - const parserutils_vector *vector, int *ctx, - css_style **result) -{ - css_error error; - const css_token *ident; - uint8_t flags = 0; - uint16_t value = 0; - uint32_t opv; - - /* IDENT (normal, none, spell-out, inherit) */ - ident = parserutils_vector_iterate(vector, ctx); - if (ident == NULL || ident->type != CSS_TOKEN_IDENT) - return CSS_INVALID; - - error = parse_important(c, vector, ctx, &flags); - if (error != CSS_OK) - return error; - - if (ident->ilower == c->strings[INHERIT]) { - flags |= FLAG_INHERIT; - } else if (ident->ilower == c->strings[NORMAL]) { - value = SPEAK_NORMAL; - } else if (ident->ilower == c->strings[NONE]) { - value = SPEAK_NONE; - } else if (ident->ilower == c->strings[SPELL_OUT]) { - value = SPEAK_SPELL_OUT; - } else - 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) - return error; - - /* Copy the bytecode to it */ - memcpy((*result)->bytecode, &opv, sizeof(opv)); - - return CSS_OK; -} - -css_error parse_speech_rate(css_language *c, - const parserutils_vector *vector, int *ctx, - css_style **result) -{ - 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; - - /* 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)) - return CSS_INVALID; - - error = parse_important(c, vector, ctx, &flags); - if (error != CSS_OK) - return error; - - if (token->type == CSS_TOKEN_IDENT && - token->ilower == c->strings[INHERIT]) { - flags |= FLAG_INHERIT; - } else if (token->type == CSS_TOKEN_IDENT && - token->ilower == c->strings[X_SLOW]) { - value = SPEECH_RATE_X_SLOW; - } else if (token->type == CSS_TOKEN_IDENT && - token->ilower == c->strings[SLOW]) { - value = SPEECH_RATE_SLOW; - } else if (token->type == CSS_TOKEN_IDENT && - token->ilower == c->strings[MEDIUM]) { - value = SPEECH_RATE_MEDIUM; - } else if (token->type == CSS_TOKEN_IDENT && - token->ilower == c->strings[FAST]) { - value = SPEECH_RATE_FAST; - } else if (token->type == CSS_TOKEN_IDENT && - token->ilower == c->strings[X_FAST]) { - value = SPEECH_RATE_X_FAST; - } else if (token->type == CSS_TOKEN_IDENT && - token->ilower == c->strings[FASTER]) { - value = SPEECH_RATE_FASTER; - } else if (token->type == CSS_TOKEN_IDENT && - token->ilower == c->strings[SLOWER]) { - value = SPEECH_RATE_SLOWER; - } else if (token->type == CSS_TOKEN_NUMBER) { - size_t consumed = 0; - num = number_from_lwc_string(token->ilower, false, &consumed); - /* Invalid if there are trailing characters */ - if (consumed != lwc_string_length(token->ilower)) - return CSS_INVALID; - - /* Make negative values invalid */ - if (num < 0) - return CSS_INVALID; - - value = SPEECH_RATE_SET; - } else - 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) - 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; -} - -css_error parse_stress(css_language *c, - const parserutils_vector *vector, int *ctx, - css_style **result) -{ - 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; - - /* number | IDENT (inherit) */ - token = parserutils_vector_iterate(vector, ctx); - if (token == NULL || (token->type != CSS_TOKEN_IDENT && - token->type != CSS_TOKEN_NUMBER)) - return CSS_INVALID; - - error = parse_important(c, vector, ctx, &flags); - if (error != CSS_OK) - return error; - - if (token->ilower == c->strings[INHERIT]) { - flags |= FLAG_INHERIT; - } else if (token->type == CSS_TOKEN_NUMBER) { - size_t consumed = 0; - num = number_from_lwc_string(token->ilower, false, &consumed); - /* Invalid if there are trailing characters */ - if (consumed != lwc_string_length(token->ilower)) - return CSS_INVALID; - - if (num < 0 || num > INTTOFIX(100)) - return CSS_INVALID; - - value = STRESS_SET; - } else - 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) - 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; -} - css_error parse_table_layout(css_language *c, const parserutils_vector *vector, int *ctx, css_style **result) @@ -5535,452 +4426,6 @@ css_error parse_visibility(css_language *c, return CSS_OK; } -css_error parse_voice_family(css_language *c, - const parserutils_vector *vector, int *ctx, - css_style **result) -{ - 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; - - /* [ 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)) - return CSS_INVALID; - - if (token->type == CSS_TOKEN_IDENT && - token->ilower == c->strings[INHERIT]) { - flags = FLAG_INHERIT; - } else { - bool first = true; - - while (token != NULL) { - if (token->type == CSS_TOKEN_IDENT) { - if (first == false) { - required_size += sizeof(opv); - } - - if (token->ilower == c->strings[MALE]) { - if (first) { - value = VOICE_FAMILY_MALE; - } - } else if (token->ilower == - c->strings[FEMALE]) { - if (first) { - value = VOICE_FAMILY_FEMALE; - } - } else if (token->ilower == c->strings[CHILD]) { - if (first) { - value = VOICE_FAMILY_CHILD; - } - } else { - if (first) { - value = VOICE_FAMILY_IDENT_LIST; - } - - required_size += - sizeof(lwc_string *); - - /* Skip past [ IDENT* S* ]* */ - while (token != NULL) { - token = parserutils_vector_peek( - vector, - temp_ctx); - if (token != NULL && - token->type != - CSS_TOKEN_IDENT && - token->type != - CSS_TOKEN_S) { - break; - } - - /* idents must not match - * generic families */ - if (token != NULL && token->type == CSS_TOKEN_IDENT && - (token->ilower == c->strings[MALE] || - token->ilower == c->strings[FEMALE] || - token->ilower == c->strings[CHILD])) - return CSS_INVALID; - token = parserutils_vector_iterate( - vector, &temp_ctx); - } - } - } else if (token->type == CSS_TOKEN_STRING) { - if (first == false) { - required_size += sizeof(opv); - } else { - value = VOICE_FAMILY_STRING; - } - - required_size += - sizeof(lwc_string *); - } else { - return CSS_INVALID; - } - - consumeWhitespace(vector, &temp_ctx); - - token = parserutils_vector_peek(vector, temp_ctx); - if (token != NULL && tokenIsChar(token, ',') == false && - tokenIsChar(token, '!') == false) { - return CSS_INVALID; - } - - if (token != NULL && tokenIsChar(token, ',')) { - parserutils_vector_iterate(vector, &temp_ctx); - - consumeWhitespace(vector, &temp_ctx); - - token = parserutils_vector_peek(vector, - temp_ctx); - if (token == NULL || tokenIsChar(token, '!')) - return CSS_INVALID; - } - - first = false; - - token = parserutils_vector_peek(vector, temp_ctx); - if (token != NULL && tokenIsChar(token, '!')) - break; - - token = parserutils_vector_iterate(vector, &temp_ctx); - } - - required_size += sizeof(opv); - } - - error = parse_important(c, vector, &temp_ctx, &flags); - if (error != CSS_OK) - return error; - - opv = buildOPV(CSS_PROP_VOICE_FAMILY, flags, value); - - /* Allocate result */ - error = css_stylesheet_style_create(c->sheet, required_size, result); - if (error != CSS_OK) - 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); - *result = NULL; - return CSS_INVALID; - } - - if (token->type == CSS_TOKEN_IDENT && - token->ilower == c->strings[INHERIT]) { - /* Nothing to do */ - } else { - bool first = true; - - while (token != NULL) { - if (token->type == CSS_TOKEN_IDENT) { - lwc_string *tok_idata = token->idata; - lwc_string *name = tok_idata; - lwc_string *newname; - - if (token->ilower == c->strings[MALE]) { - opv = VOICE_FAMILY_MALE; - } else if (token->ilower == - c->strings[FEMALE]) { - opv = VOICE_FAMILY_FEMALE; - } else if (token->ilower == c->strings[CHILD]) { - opv = VOICE_FAMILY_CHILD; - } else { - uint16_t len = lwc_string_length(token->idata); - const css_token *temp_token = token; - lwc_error lerror; - uint8_t *buf; - uint8_t *p; - - temp_ctx = *ctx; - - opv = VOICE_FAMILY_IDENT_LIST; - - /* Build string from idents */ - while (temp_token != NULL) { - temp_token = parserutils_vector_peek( - vector, temp_ctx); - if (temp_token != NULL && - temp_token->type != - CSS_TOKEN_IDENT && - temp_token->type != - CSS_TOKEN_S) { - break; - } - - if (temp_token != NULL && temp_token->type == CSS_TOKEN_IDENT) { - len += lwc_string_length(temp_token->idata); - } else if (temp_token != NULL) { - len += 1; - } - - temp_token = parserutils_vector_iterate( - vector, &temp_ctx); - } - - /** \todo Don't use alloca */ - buf = alloca(len); - p = buf; - - memcpy(p, lwc_string_data(token->idata), lwc_string_length(token->idata)); - p += lwc_string_length(token->idata); - - while (token != NULL) { - token = parserutils_vector_peek( - vector, *ctx); - if (token != NULL && - token->type != - CSS_TOKEN_IDENT && - token->type != - CSS_TOKEN_S) { - break; - } - - if (token != NULL && - token->type == - CSS_TOKEN_IDENT) { - memcpy(p, - lwc_string_data(token->idata), - lwc_string_length(token->idata)); - p += lwc_string_length(token->idata); - } else if (token != NULL) { - *p++ = ' '; - } - - token = parserutils_vector_iterate( - vector, ctx); - } - - /* Strip trailing whitespace */ - while (p > buf && p[-1] == ' ') - p--; - - /* Insert into hash, if it's different - * from the name we already have */ - lerror = lwc_context_intern(c->sheet->dictionary, - (char *)buf, len, &newname); - if (lerror != lwc_error_ok) { - css_stylesheet_style_destroy(c->sheet, *result); - *result = NULL; - return css_error_from_lwc_error(lerror); - } - - if (newname == name) - lwc_context_string_unref(c->sheet->dictionary, - newname); - - name = newname; - } - - if (first == false) { - memcpy(ptr, &opv, sizeof(opv)); - ptr += sizeof(opv); - } - - if (opv == VOICE_FAMILY_IDENT_LIST) { - /* Only ref 'name' again if the token owns it, - * otherwise we already own the only ref to the - * new name generated above. - */ - if (name == tok_idata) - lwc_context_string_ref(c->sheet->dictionary, name); - memcpy(ptr, &name, sizeof(name)); - ptr += sizeof(name); - } - } else if (token->type == CSS_TOKEN_STRING) { - opv = VOICE_FAMILY_STRING; - - if (first == false) { - memcpy(ptr, &opv, sizeof(opv)); - ptr += sizeof(opv); - } - - lwc_context_string_ref(c->sheet->dictionary, token->idata); - memcpy(ptr, &token->idata, - sizeof(token->idata)); - ptr += sizeof(token->idata); - } else { - css_stylesheet_style_destroy(c->sheet, *result); - *result = NULL; - return CSS_INVALID; - } - - consumeWhitespace(vector, ctx); - - token = parserutils_vector_peek(vector, *ctx); - if (token != NULL && tokenIsChar(token, ',') == false && - tokenIsChar(token, '!') == false) { - css_stylesheet_style_destroy(c->sheet, *result); - *result = NULL; - return CSS_INVALID; - } - - if (token != NULL && tokenIsChar(token, ',')) { - parserutils_vector_iterate(vector, ctx); - - consumeWhitespace(vector, ctx); - - token = parserutils_vector_peek(vector, *ctx); - if (token == NULL || tokenIsChar(token, '!')) { - css_stylesheet_style_destroy(c->sheet, - *result); - *result = NULL; - return CSS_INVALID; - } - } - - first = false; - - token = parserutils_vector_peek(vector, *ctx); - if (token != NULL && tokenIsChar(token, '!')) - break; - - token = parserutils_vector_iterate(vector, ctx); - } - - /* Write terminator */ - opv = VOICE_FAMILY_END; - memcpy(ptr, &opv, sizeof(opv)); - ptr += sizeof(opv); - } - - error = parse_important(c, vector, ctx, &flags); - if (error != CSS_OK) { - css_stylesheet_style_destroy(c->sheet, *result); - *result = NULL; - return error; - } - - return CSS_OK; -} - -css_error parse_volume(css_language *c, - const parserutils_vector *vector, int *ctx, - css_style **result) -{ - 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; - - /* number | percentage | IDENT(silent, x-soft, soft, medium, loud, - * x-loud, inherit) - */ - token = parserutils_vector_peek(vector, *ctx); - if (token == NULL) - return CSS_INVALID; - - if (token->type == CSS_TOKEN_IDENT && - token->ilower == c->strings[INHERIT]) { - parserutils_vector_iterate(vector, ctx); - flags = FLAG_INHERIT; - } else if (token->type == CSS_TOKEN_IDENT && - token->ilower == c->strings[SILENT]) { - parserutils_vector_iterate(vector, ctx); - value = VOLUME_SILENT; - } else if (token->type == CSS_TOKEN_IDENT && - token->ilower == c->strings[X_SOFT]) { - parserutils_vector_iterate(vector, ctx); - value = VOLUME_X_SOFT; - } else if (token->type == CSS_TOKEN_IDENT && - token->ilower == c->strings[SOFT]) { - parserutils_vector_iterate(vector, ctx); - value = VOLUME_SOFT; - } else if (token->type == CSS_TOKEN_IDENT && - token->ilower == c->strings[MEDIUM]) { - parserutils_vector_iterate(vector, ctx); - value = VOLUME_MEDIUM; - } else if (token->type == CSS_TOKEN_IDENT && - token->ilower == c->strings[LOUD]) { - parserutils_vector_iterate(vector, ctx); - value = VOLUME_LOUD; - } else if (token->type == CSS_TOKEN_IDENT && - token->ilower == c->strings[X_LOUD]) { - 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->ilower, false, &consumed); - if (consumed != lwc_string_length(token->ilower)) - return CSS_INVALID; - - /* Must be between 0 and 100 */ - if (length < 0 || length > F_100) - 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) - return error; - - if ((unit & UNIT_PCT) == false) - return CSS_INVALID; - - /* Must be positive */ - if (length < 0) - return CSS_INVALID; - - value = VOLUME_DIMENSION; - } - - error = parse_important(c, vector, ctx, &flags); - if (error != CSS_OK) - return error; - - 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) - 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; -} - css_error parse_white_space(css_language *c, const parserutils_vector *vector, int *ctx, css_style **result) @@ -6283,478 +4728,6 @@ css_error parse_z_index(css_language *c, return CSS_OK; } -css_error parse_important(css_language *c, - const parserutils_vector *vector, int *ctx, - uint8_t *result) -{ - const css_token *token; - - consumeWhitespace(vector, ctx); - - token = parserutils_vector_iterate(vector, ctx); - if (token != NULL && tokenIsChar(token, '!')) { - consumeWhitespace(vector, ctx); - - token = parserutils_vector_iterate(vector, ctx); - if (token == NULL || token->type != CSS_TOKEN_IDENT) - return CSS_INVALID; - - if (token->ilower == c->strings[IMPORTANT]) - *result |= FLAG_IMPORTANT; - } else if (token != NULL) - return CSS_INVALID; - - return CSS_OK; -} - -css_error parse_colour_specifier(css_language *c, - const parserutils_vector *vector, int *ctx, - uint32_t *result) -{ - const css_token *token; - uint8_t r = 0, g = 0, b = 0; - css_error error; - - UNUSED(c); - - consumeWhitespace(vector, ctx); - - /* IDENT(<colour name>) | HASH(rgb | rrggbb) | - * FUNCTION(rgb) [ [ NUMBER | PERCENTAGE ] ',' ] {3} ')' - * - * For quirks, NUMBER | DIMENSION | IDENT, too - * I.E. "123456" -> NUMBER, "1234f0" -> DIMENSION, "f00000" -> IDENT - */ - token = parserutils_vector_iterate(vector, ctx); - if (token == NULL || (token->type != CSS_TOKEN_IDENT && - token->type != CSS_TOKEN_HASH && - token->type != CSS_TOKEN_FUNCTION)) { - if (c->sheet->quirks_allowed == false || - (token->type != CSS_TOKEN_NUMBER && - token->type != CSS_TOKEN_DIMENSION)) - return CSS_INVALID; - } - - if (token->type == CSS_TOKEN_IDENT) { - error = parse_named_colour(c, token->idata, result); - if (error != CSS_OK && c->sheet->quirks_allowed) { - error = parse_hash_colour(token->idata, result); - if (error == CSS_OK) - c->sheet->quirks_used = true; - } - - return error; - } else if (token->type == CSS_TOKEN_HASH) { - return parse_hash_colour(token->idata, result); - } else if (c->sheet->quirks_allowed && - token->type == CSS_TOKEN_NUMBER) { - error = parse_hash_colour(token->idata, result); - if (error == CSS_OK) - c->sheet->quirks_used = true; - return error; - } else if (c->sheet->quirks_allowed && - token->type == CSS_TOKEN_DIMENSION) { - error = parse_hash_colour(token->idata, result); - if (error == CSS_OK) - c->sheet->quirks_used = true; - return error; - } else if (token->type == CSS_TOKEN_FUNCTION) { - if (token->ilower == c->strings[RGB]) { - int i; - css_token_type valid = CSS_TOKEN_NUMBER; - - for (i = 0; i < 3; i++) { - css_fixed num; - size_t consumed = 0; - uint8_t *component = i == 0 ? &r - : i == 1 ? &b : &g; - int32_t intval; - - consumeWhitespace(vector, ctx); - - token = parserutils_vector_peek(vector, *ctx); - if (token == NULL || (token->type != - CSS_TOKEN_NUMBER && - token->type != - CSS_TOKEN_PERCENTAGE)) - return CSS_INVALID; - - if (i == 0) - valid = token->type; - else if (token->type != valid) - return CSS_INVALID; - - num = number_from_lwc_string(token->idata, - valid == CSS_TOKEN_NUMBER, - &consumed); - if (consumed != lwc_string_length(token->idata)) - return CSS_INVALID; - - if (valid == CSS_TOKEN_NUMBER) { - intval = FIXTOINT(num); - } else { - intval = FIXTOINT( - FDIVI(FMULI(num, 255), 100)); - } - - if (intval > 255) - *component = 255; - else if (intval < 0) - *component = 0; - else - *component = intval; - - parserutils_vector_iterate(vector, ctx); - - consumeWhitespace(vector, ctx); - - token = parserutils_vector_peek(vector, *ctx); - if (token == NULL) - return CSS_INVALID; - - if (i != 2 && tokenIsChar(token, ',')) - parserutils_vector_iterate(vector, ctx); - else if (i == 2 && tokenIsChar(token, ')')) - parserutils_vector_iterate(vector, ctx); - else - return CSS_INVALID; - } - } else - return CSS_INVALID; - } - - *result = (r << 24) | (g << 16) | (b << 8); - - return CSS_OK; -} - -css_error parse_named_colour(css_language *c, lwc_string *data, - uint32_t *result) -{ - static const uint32_t colourmap[LAST_COLOUR + 1 - FIRST_COLOUR] = { - 0xf0f8ff00, /* ALICEBLUE */ - 0xfaebd700, /* ANTIQUEWHITE */ - 0x00ffff00, /* AQUA */ - 0x7fffd400, /* AQUAMARINE */ - 0xf0ffff00, /* AZURE */ - 0xf5f5dc00, /* BEIGE */ - 0xffe4c400, /* BISQUE */ - 0x00000000, /* BLACK */ - 0xffebcd00, /* BLANCHEDALMOND */ - 0x0000ff00, /* BLUE */ - 0x8a2be200, /* BLUEVIOLET */ - 0xa52a2a00, /* BROWN */ - 0xdeb88700, /* BURLYWOOD */ - 0x5f9ea000, /* CADETBLUE */ - 0x7fff0000, /* CHARTREUSE */ - 0xd2691e00, /* CHOCOLATE */ - 0xff7f5000, /* CORAL */ - 0x6495ed00, /* CORNFLOWERBLUE */ - 0xfff8dc00, /* CORNSILK */ - 0xdc143c00, /* CRIMSON */ - 0x00ffff00, /* CYAN */ - 0x00008b00, /* DARKBLUE */ - 0x008b8b00, /* DARKCYAN */ - 0xb8860b00, /* DARKGOLDENROD */ - 0xa9a9a900, /* DARKGRAY */ - 0x00640000, /* DARKGREEN */ - 0xa9a9a900, /* DARKGREY */ - 0xbdb76b00, /* DARKKHAKI */ - 0x8b008b00, /* DARKMAGENTA */ - 0x556b2f00, /* DARKOLIVEGREEN */ - 0xff8c0000, /* DARKORANGE */ - 0x9932cc00, /* DARKORCHID */ - 0x8b000000, /* DARKRED */ - 0xe9967a00, /* DARKSALMON */ - 0x8fbc8f00, /* DARKSEAGREEN */ - 0x483d8b00, /* DARKSLATEBLUE */ - 0x2f4f4f00, /* DARKSLATEGRAY */ - 0x2f4f4f00, /* DARKSLATEGREY */ - 0x00ced100, /* DARKTURQUOISE */ - 0x9400d300, /* DARKVIOLET */ - 0xff149300, /* DEEPPINK */ - 0x00bfff00, /* DEEPSKYBLUE */ - 0x69696900, /* DIMGRAY */ - 0x69696900, /* DIMGREY */ - 0x1e90ff00, /* DODGERBLUE */ - 0xd1927500, /* FELDSPAR */ - 0xb2222200, /* FIREBRICK */ - 0xfffaf000, /* FLORALWHITE */ - 0x228b2200, /* FORESTGREEN */ - 0xff00ff00, /* FUCHSIA */ - 0xdcdcdc00, /* GAINSBORO */ - 0xf8f8ff00, /* GHOSTWHITE */ - 0xffd70000, /* GOLD */ - 0xdaa52000, /* GOLDENROD */ - 0x80808000, /* GRAY */ - 0x00800000, /* GREEN */ - 0xadff2f00, /* GREENYELLOW */ - 0x80808000, /* GREY */ - 0xf0fff000, /* HONEYDEW */ - 0xff69b400, /* HOTPINK */ - 0xcd5c5c00, /* INDIANRED */ - 0x4b008200, /* INDIGO */ - 0xfffff000, /* IVORY */ - 0xf0e68c00, /* KHAKI */ - 0xe6e6fa00, /* LAVENDER */ - 0xfff0f500, /* LAVENDERBLUSH */ - 0x7cfc0000, /* LAWNGREEN */ - 0xfffacd00, /* LEMONCHIFFON */ - 0xadd8e600, /* LIGHTBLUE */ - 0xf0808000, /* LIGHTCORAL */ - 0xe0ffff00, /* LIGHTCYAN */ - 0xfafad200, /* LIGHTGOLDENRODYELLOW */ - 0xd3d3d300, /* LIGHTGRAY */ - 0x90ee9000, /* LIGHTGREEN */ - 0xd3d3d300, /* LIGHTGREY */ - 0xffb6c100, /* LIGHTPINK */ - 0xffa07a00, /* LIGHTSALMON */ - 0x20b2aa00, /* LIGHTSEAGREEN */ - 0x87cefa00, /* LIGHTSKYBLUE */ - 0x8470ff00, /* LIGHTSLATEBLUE */ - 0x77889900, /* LIGHTSLATEGRAY */ - 0x77889900, /* LIGHTSLATEGREY */ - 0xb0c4de00, /* LIGHTSTEELBLUE */ - 0xffffe000, /* LIGHTYELLOW */ - 0x00ff0000, /* LIME */ - 0x32cd3200, /* LIMEGREEN */ - 0xfaf0e600, /* LINEN */ - 0xff00ff00, /* MAGENTA */ - 0x80000000, /* MAROON */ - 0x66cdaa00, /* MEDIUMAQUAMARINE */ - 0x0000cd00, /* MEDIUMBLUE */ - 0xba55d300, /* MEDIUMORCHID */ - 0x9370db00, /* MEDIUMPURPLE */ - 0x3cb37100, /* MEDIUMSEAGREEN */ - 0x7b68ee00, /* MEDIUMSLATEBLUE */ - 0x00fa9a00, /* MEDIUMSPRINGGREEN */ - 0x48d1cc00, /* MEDIUMTURQUOISE */ - 0xc7158500, /* MEDIUMVIOLETRED */ - 0x19197000, /* MIDNIGHTBLUE */ - 0xf5fffa00, /* MINTCREAM */ - 0xffe4e100, /* MISTYROSE */ - 0xffe4b500, /* MOCCASIN */ - 0xffdead00, /* NAVAJOWHITE */ - 0x00008000, /* NAVY */ - 0xfdf5e600, /* OLDLACE */ - 0x80800000, /* OLIVE */ - 0x6b8e2300, /* OLIVEDRAB */ - 0xffa50000, /* ORANGE */ - 0xff450000, /* ORANGERED */ - 0xda70d600, /* ORCHID */ - 0xeee8aa00, /* PALEGOLDENROD */ - 0x98fb9800, /* PALEGREEN */ - 0xafeeee00, /* PALETURQUOISE */ - 0xdb709300, /* PALEVIOLETRED */ - 0xffefd500, /* PAPAYAWHIP */ - 0xffdab900, /* PEACHPUFF */ - 0xcd853f00, /* PERU */ - 0xffc0cb00, /* PINK */ - 0xdda0dd00, /* PLUM */ - 0xb0e0e600, /* POWDERBLUE */ - 0x80008000, /* PURPLE */ - 0xff000000, /* RED */ - 0xbc8f8f00, /* ROSYBROWN */ - 0x4169e100, /* ROYALBLUE */ - 0x8b451300, /* SADDLEBROWN */ - 0xfa807200, /* SALMON */ - 0xf4a46000, /* SANDYBROWN */ - 0x2e8b5700, /* SEAGREEN */ - 0xfff5ee00, /* SEASHELL */ - 0xa0522d00, /* SIENNA */ - 0xc0c0c000, /* SILVER */ - 0x87ceeb00, /* SKYBLUE */ - 0x6a5acd00, /* SLATEBLUE */ - 0x70809000, /* SLATEGRAY */ - 0x70809000, /* SLATEGREY */ - 0xfffafa00, /* SNOW */ - 0x00ff7f00, /* SPRINGGREEN */ - 0x4682b400, /* STEELBLUE */ - 0xd2b48c00, /* TAN */ - 0x00808000, /* TEAL */ - 0xd8bfd800, /* THISTLE */ - 0xff634700, /* TOMATO */ - 0x40e0d000, /* TURQUOISE */ - 0xee82ee00, /* VIOLET */ - 0xd0209000, /* VIOLETRED */ - 0xf5deb300, /* WHEAT */ - 0xffffff00, /* WHITE */ - 0xf5f5f500, /* WHITESMOKE */ - 0xffff0000, /* YELLOW */ - 0x9acd3200 /* YELLOWGREEN */ - }; - int i; - - for (i = FIRST_COLOUR; i <= LAST_COLOUR; i++) { - if (data == c->strings[i]) - break; - } - if (i == LAST_COLOUR + 1) - return CSS_INVALID; - - *result = colourmap[i - FIRST_COLOUR]; - - return CSS_OK; -} - -css_error parse_hash_colour(lwc_string *data, uint32_t *result) -{ - uint8_t r = 0, g = 0, b = 0; - size_t len = lwc_string_length(data); - const char *input = lwc_string_data(data); - - if (len == 3 && isHex(input[0]) && isHex(input[1]) && - isHex(input[2])) { - r = charToHex(input[0]); - g = charToHex(input[1]); - b = charToHex(input[2]); - - r |= (r << 4); - g |= (g << 4); - b |= (b << 4); - } else if (len == 6 && isHex(input[0]) && isHex(input[1]) && - isHex(input[2]) && isHex(input[3]) && - isHex(input[4]) && isHex(input[5])) { - r = (charToHex(input[0]) << 4); - r |= charToHex(input[1]); - g = (charToHex(input[2]) << 4); - g |= charToHex(input[3]); - b = (charToHex(input[4]) << 4); - b |= charToHex(input[5]); - } else - return CSS_INVALID; - - *result = (r << 24) | (g << 16) | (b << 8); - - return CSS_OK; -} - -css_error parse_unit_specifier(css_language *c, - const parserutils_vector *vector, int *ctx, - uint32_t default_unit, - css_fixed *length, uint32_t *unit) -{ - const css_token *token; - css_fixed num; - size_t consumed = 0; - css_error error; - - UNUSED(c); - - consumeWhitespace(vector, ctx); - - token = parserutils_vector_iterate(vector, ctx); - if (token == NULL || (token->type != CSS_TOKEN_DIMENSION && - token->type != CSS_TOKEN_NUMBER && - token->type != CSS_TOKEN_PERCENTAGE)) - return CSS_INVALID; - - num = number_from_lwc_string(token->idata, false, &consumed); - - if (token->type == CSS_TOKEN_DIMENSION) { - size_t len = lwc_string_length(token->idata); - const char *data = lwc_string_data(token->idata); - - error = parse_unit_keyword(data + consumed, len - consumed, - unit); - if (error != CSS_OK) - return error; - } else if (token->type == CSS_TOKEN_NUMBER) { - /* Non-zero values are permitted in quirks mode */ - if (num != 0) { - if (c->sheet->quirks_allowed) - c->sheet->quirks_used = true; - else - return CSS_INVALID; - } - - *unit = default_unit; - - if (c->sheet->quirks_allowed) { - /* Also, in quirks mode, we need to cater for - * dimensions separated from their units by whitespace - * (e.g. "0 px") - */ - int temp_ctx = *ctx; - uint32_t temp_unit; - - consumeWhitespace(vector, &temp_ctx); - - token = parserutils_vector_iterate(vector, &temp_ctx); - if (token != NULL && token->type == CSS_TOKEN_IDENT) { - error = parse_unit_keyword( - lwc_string_data(token->idata), - lwc_string_length(token->idata), - &temp_unit); - if (error == CSS_OK) { - c->sheet->quirks_used = true; - *ctx = temp_ctx; - *unit = temp_unit; - } - } - } - - } else { - if (consumed != lwc_string_length(token->idata)) - return CSS_INVALID; - *unit = UNIT_PCT; - } - - *length = num; - - return CSS_OK; -} - -css_error parse_unit_keyword(const char *ptr, size_t len, css_unit *unit) -{ - if (len == 4) { - if (strncasecmp(ptr, "grad", 4) == 0) - *unit = UNIT_GRAD; - else - return CSS_INVALID; - } else if (len == 3) { - if (strncasecmp(ptr, "kHz", 3) == 0) - *unit = UNIT_KHZ; - else if (strncasecmp(ptr, "deg", 3) == 0) - *unit = UNIT_DEG; - else if (strncasecmp(ptr, "rad", 3) == 0) - *unit = UNIT_RAD; - else - return CSS_INVALID; - } else if (len == 2) { - if (strncasecmp(ptr, "Hz", 2) == 0) - *unit = UNIT_HZ; - else if (strncasecmp(ptr, "ms", 2) == 0) - *unit = UNIT_MS; - else if (strncasecmp(ptr, "px", 2) == 0) - *unit = UNIT_PX; - else if (strncasecmp(ptr, "ex", 2) == 0) - *unit = UNIT_EX; - else if (strncasecmp(ptr, "em", 2) == 0) - *unit = UNIT_EM; - else if (strncasecmp(ptr, "in", 2) == 0) - *unit = UNIT_IN; - else if (strncasecmp(ptr, "cm", 2) == 0) - *unit = UNIT_CM; - else if (strncasecmp(ptr, "mm", 2) == 0) - *unit = UNIT_MM; - else if (strncasecmp(ptr, "pt", 2) == 0) - *unit = UNIT_PT; - else if (strncasecmp(ptr, "pc", 2) == 0) - *unit = UNIT_PC; - else - return CSS_INVALID; - } else if (len == 1) { - if (strncasecmp(ptr, "s", 1) == 0) - *unit = UNIT_S; - else - return CSS_INVALID; - } else - return CSS_INVALID; - - return CSS_OK; -} - css_error parse_border_side_color(css_language *c, const parserutils_vector *vector, int *ctx, uint16_t op, css_style **result) diff --git a/src/parse/properties/utils.c b/src/parse/properties/utils.c new file mode 100644 index 0000000..4fb1fca --- /dev/null +++ b/src/parse/properties/utils.c @@ -0,0 +1,486 @@ +/* + * 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> + */ + +#include <string.h> + +#include "stylesheet.h" +#include "bytecode/bytecode.h" +#include "bytecode/opcodes.h" +#include "parse/properties/utils.h" + +css_error parse_important(css_language *c, + const parserutils_vector *vector, int *ctx, + uint8_t *result) +{ + const css_token *token; + + consumeWhitespace(vector, ctx); + + token = parserutils_vector_iterate(vector, ctx); + if (token != NULL && tokenIsChar(token, '!')) { + consumeWhitespace(vector, ctx); + + token = parserutils_vector_iterate(vector, ctx); + if (token == NULL || token->type != CSS_TOKEN_IDENT) + return CSS_INVALID; + + if (token->ilower == c->strings[IMPORTANT]) + *result |= FLAG_IMPORTANT; + } else if (token != NULL) + return CSS_INVALID; + + return CSS_OK; +} + +css_error parse_colour_specifier(css_language *c, + const parserutils_vector *vector, int *ctx, + uint32_t *result) +{ + const css_token *token; + uint8_t r = 0, g = 0, b = 0; + css_error error; + + UNUSED(c); + + consumeWhitespace(vector, ctx); + + /* IDENT(<colour name>) | HASH(rgb | rrggbb) | + * FUNCTION(rgb) [ [ NUMBER | PERCENTAGE ] ',' ] {3} ')' + * + * For quirks, NUMBER | DIMENSION | IDENT, too + * I.E. "123456" -> NUMBER, "1234f0" -> DIMENSION, "f00000" -> IDENT + */ + token = parserutils_vector_iterate(vector, ctx); + if (token == NULL || (token->type != CSS_TOKEN_IDENT && + token->type != CSS_TOKEN_HASH && + token->type != CSS_TOKEN_FUNCTION)) { + if (c->sheet->quirks_allowed == false || + (token->type != CSS_TOKEN_NUMBER && + token->type != CSS_TOKEN_DIMENSION)) + return CSS_INVALID; + } + + if (token->type == CSS_TOKEN_IDENT) { + error = parse_named_colour(c, token->idata, result); + if (error != CSS_OK && c->sheet->quirks_allowed) { + error = parse_hash_colour(token->idata, result); + if (error == CSS_OK) + c->sheet->quirks_used = true; + } + + return error; + } else if (token->type == CSS_TOKEN_HASH) { + return parse_hash_colour(token->idata, result); + } else if (c->sheet->quirks_allowed && + token->type == CSS_TOKEN_NUMBER) { + error = parse_hash_colour(token->idata, result); + if (error == CSS_OK) + c->sheet->quirks_used = true; + return error; + } else if (c->sheet->quirks_allowed && + token->type == CSS_TOKEN_DIMENSION) { + error = parse_hash_colour(token->idata, result); + if (error == CSS_OK) + c->sheet->quirks_used = true; + return error; + } else if (token->type == CSS_TOKEN_FUNCTION) { + if (token->ilower == c->strings[RGB]) { + int i; + css_token_type valid = CSS_TOKEN_NUMBER; + + for (i = 0; i < 3; i++) { + css_fixed num; + size_t consumed = 0; + uint8_t *component = i == 0 ? &r + : i == 1 ? &b : &g; + int32_t intval; + + consumeWhitespace(vector, ctx); + + token = parserutils_vector_peek(vector, *ctx); + if (token == NULL || (token->type != + CSS_TOKEN_NUMBER && + token->type != + CSS_TOKEN_PERCENTAGE)) + return CSS_INVALID; + + if (i == 0) + valid = token->type; + else if (token->type != valid) + return CSS_INVALID; + + num = number_from_lwc_string(token->idata, + valid == CSS_TOKEN_NUMBER, + &consumed); + if (consumed != lwc_string_length(token->idata)) + return CSS_INVALID; + + if (valid == CSS_TOKEN_NUMBER) { + intval = FIXTOINT(num); + } else { + intval = FIXTOINT( + FDIVI(FMULI(num, 255), 100)); + } + + if (intval > 255) + *component = 255; + else if (intval < 0) + *component = 0; + else + *component = intval; + + parserutils_vector_iterate(vector, ctx); + + consumeWhitespace(vector, ctx); + + token = parserutils_vector_peek(vector, *ctx); + if (token == NULL) + return CSS_INVALID; + + if (i != 2 && tokenIsChar(token, ',')) + parserutils_vector_iterate(vector, ctx); + else if (i == 2 && tokenIsChar(token, ')')) + parserutils_vector_iterate(vector, ctx); + else + return CSS_INVALID; + } + } else + return CSS_INVALID; + } + + *result = (r << 24) | (g << 16) | (b << 8); + + return CSS_OK; +} + +css_error parse_named_colour(css_language *c, lwc_string *data, + uint32_t *result) +{ + static const uint32_t colourmap[LAST_COLOUR + 1 - FIRST_COLOUR] = { + 0xf0f8ff00, /* ALICEBLUE */ + 0xfaebd700, /* ANTIQUEWHITE */ + 0x00ffff00, /* AQUA */ + 0x7fffd400, /* AQUAMARINE */ + 0xf0ffff00, /* AZURE */ + 0xf5f5dc00, /* BEIGE */ + 0xffe4c400, /* BISQUE */ + 0x00000000, /* BLACK */ + 0xffebcd00, /* BLANCHEDALMOND */ + 0x0000ff00, /* BLUE */ + 0x8a2be200, /* BLUEVIOLET */ + 0xa52a2a00, /* BROWN */ + 0xdeb88700, /* BURLYWOOD */ + 0x5f9ea000, /* CADETBLUE */ + 0x7fff0000, /* CHARTREUSE */ + 0xd2691e00, /* CHOCOLATE */ + 0xff7f5000, /* CORAL */ + 0x6495ed00, /* CORNFLOWERBLUE */ + 0xfff8dc00, /* CORNSILK */ + 0xdc143c00, /* CRIMSON */ + 0x00ffff00, /* CYAN */ + 0x00008b00, /* DARKBLUE */ + 0x008b8b00, /* DARKCYAN */ + 0xb8860b00, /* DARKGOLDENROD */ + 0xa9a9a900, /* DARKGRAY */ + 0x00640000, /* DARKGREEN */ + 0xa9a9a900, /* DARKGREY */ + 0xbdb76b00, /* DARKKHAKI */ + 0x8b008b00, /* DARKMAGENTA */ + 0x556b2f00, /* DARKOLIVEGREEN */ + 0xff8c0000, /* DARKORANGE */ + 0x9932cc00, /* DARKORCHID */ + 0x8b000000, /* DARKRED */ + 0xe9967a00, /* DARKSALMON */ + 0x8fbc8f00, /* DARKSEAGREEN */ + 0x483d8b00, /* DARKSLATEBLUE */ + 0x2f4f4f00, /* DARKSLATEGRAY */ + 0x2f4f4f00, /* DARKSLATEGREY */ + 0x00ced100, /* DARKTURQUOISE */ + 0x9400d300, /* DARKVIOLET */ + 0xff149300, /* DEEPPINK */ + 0x00bfff00, /* DEEPSKYBLUE */ + 0x69696900, /* DIMGRAY */ + 0x69696900, /* DIMGREY */ + 0x1e90ff00, /* DODGERBLUE */ + 0xd1927500, /* FELDSPAR */ + 0xb2222200, /* FIREBRICK */ + 0xfffaf000, /* FLORALWHITE */ + 0x228b2200, /* FORESTGREEN */ + 0xff00ff00, /* FUCHSIA */ + 0xdcdcdc00, /* GAINSBORO */ + 0xf8f8ff00, /* GHOSTWHITE */ + 0xffd70000, /* GOLD */ + 0xdaa52000, /* GOLDENROD */ + 0x80808000, /* GRAY */ + 0x00800000, /* GREEN */ + 0xadff2f00, /* GREENYELLOW */ + 0x80808000, /* GREY */ + 0xf0fff000, /* HONEYDEW */ + 0xff69b400, /* HOTPINK */ + 0xcd5c5c00, /* INDIANRED */ + 0x4b008200, /* INDIGO */ + 0xfffff000, /* IVORY */ + 0xf0e68c00, /* KHAKI */ + 0xe6e6fa00, /* LAVENDER */ + 0xfff0f500, /* LAVENDERBLUSH */ + 0x7cfc0000, /* LAWNGREEN */ + 0xfffacd00, /* LEMONCHIFFON */ + 0xadd8e600, /* LIGHTBLUE */ + 0xf0808000, /* LIGHTCORAL */ + 0xe0ffff00, /* LIGHTCYAN */ + 0xfafad200, /* LIGHTGOLDENRODYELLOW */ + 0xd3d3d300, /* LIGHTGRAY */ + 0x90ee9000, /* LIGHTGREEN */ + 0xd3d3d300, /* LIGHTGREY */ + 0xffb6c100, /* LIGHTPINK */ + 0xffa07a00, /* LIGHTSALMON */ + 0x20b2aa00, /* LIGHTSEAGREEN */ + 0x87cefa00, /* LIGHTSKYBLUE */ + 0x8470ff00, /* LIGHTSLATEBLUE */ + 0x77889900, /* LIGHTSLATEGRAY */ + 0x77889900, /* LIGHTSLATEGREY */ + 0xb0c4de00, /* LIGHTSTEELBLUE */ + 0xffffe000, /* LIGHTYELLOW */ + 0x00ff0000, /* LIME */ + 0x32cd3200, /* LIMEGREEN */ + 0xfaf0e600, /* LINEN */ + 0xff00ff00, /* MAGENTA */ + 0x80000000, /* MAROON */ + 0x66cdaa00, /* MEDIUMAQUAMARINE */ + 0x0000cd00, /* MEDIUMBLUE */ + 0xba55d300, /* MEDIUMORCHID */ + 0x9370db00, /* MEDIUMPURPLE */ + 0x3cb37100, /* MEDIUMSEAGREEN */ + 0x7b68ee00, /* MEDIUMSLATEBLUE */ + 0x00fa9a00, /* MEDIUMSPRINGGREEN */ + 0x48d1cc00, /* MEDIUMTURQUOISE */ + 0xc7158500, /* MEDIUMVIOLETRED */ + 0x19197000, /* MIDNIGHTBLUE */ + 0xf5fffa00, /* MINTCREAM */ + 0xffe4e100, /* MISTYROSE */ + 0xffe4b500, /* MOCCASIN */ + 0xffdead00, /* NAVAJOWHITE */ + 0x00008000, /* NAVY */ + 0xfdf5e600, /* OLDLACE */ + 0x80800000, /* OLIVE */ + 0x6b8e2300, /* OLIVEDRAB */ + 0xffa50000, /* ORANGE */ + 0xff450000, /* ORANGERED */ + 0xda70d600, /* ORCHID */ + 0xeee8aa00, /* PALEGOLDENROD */ + 0x98fb9800, /* PALEGREEN */ + 0xafeeee00, /* PALETURQUOISE */ + 0xdb709300, /* PALEVIOLETRED */ + 0xffefd500, /* PAPAYAWHIP */ + 0xffdab900, /* PEACHPUFF */ + 0xcd853f00, /* PERU */ + 0xffc0cb00, /* PINK */ + 0xdda0dd00, /* PLUM */ + 0xb0e0e600, /* POWDERBLUE */ + 0x80008000, /* PURPLE */ + 0xff000000, /* RED */ + 0xbc8f8f00, /* ROSYBROWN */ + 0x4169e100, /* ROYALBLUE */ + 0x8b451300, /* SADDLEBROWN */ + 0xfa807200, /* SALMON */ + 0xf4a46000, /* SANDYBROWN */ + 0x2e8b5700, /* SEAGREEN */ + 0xfff5ee00, /* SEASHELL */ + 0xa0522d00, /* SIENNA */ + 0xc0c0c000, /* SILVER */ + 0x87ceeb00, /* SKYBLUE */ + 0x6a5acd00, /* SLATEBLUE */ + 0x70809000, /* SLATEGRAY */ + 0x70809000, /* SLATEGREY */ + 0xfffafa00, /* SNOW */ + 0x00ff7f00, /* SPRINGGREEN */ + 0x4682b400, /* STEELBLUE */ + 0xd2b48c00, /* TAN */ + 0x00808000, /* TEAL */ + 0xd8bfd800, /* THISTLE */ + 0xff634700, /* TOMATO */ + 0x40e0d000, /* TURQUOISE */ + 0xee82ee00, /* VIOLET */ + 0xd0209000, /* VIOLETRED */ + 0xf5deb300, /* WHEAT */ + 0xffffff00, /* WHITE */ + 0xf5f5f500, /* WHITESMOKE */ + 0xffff0000, /* YELLOW */ + 0x9acd3200 /* YELLOWGREEN */ + }; + int i; + + for (i = FIRST_COLOUR; i <= LAST_COLOUR; i++) { + if (data == c->strings[i]) + break; + } + if (i == LAST_COLOUR + 1) + return CSS_INVALID; + + *result = colourmap[i - FIRST_COLOUR]; + + return CSS_OK; +} + +css_error parse_hash_colour(lwc_string *data, uint32_t *result) +{ + uint8_t r = 0, g = 0, b = 0; + size_t len = lwc_string_length(data); + const char *input = lwc_string_data(data); + + if (len == 3 && isHex(input[0]) && isHex(input[1]) && + isHex(input[2])) { + r = charToHex(input[0]); + g = charToHex(input[1]); + b = charToHex(input[2]); + + r |= (r << 4); + g |= (g << 4); + b |= (b << 4); + } else if (len == 6 && isHex(input[0]) && isHex(input[1]) && + isHex(input[2]) && isHex(input[3]) && + isHex(input[4]) && isHex(input[5])) { + r = (charToHex(input[0]) << 4); + r |= charToHex(input[1]); + g = (charToHex(input[2]) << 4); + g |= charToHex(input[3]); + b = (charToHex(input[4]) << 4); + b |= charToHex(input[5]); + } else + return CSS_INVALID; + + *result = (r << 24) | (g << 16) | (b << 8); + + return CSS_OK; +} + +css_error parse_unit_specifier(css_language *c, + const parserutils_vector *vector, int *ctx, + uint32_t default_unit, + css_fixed *length, uint32_t *unit) +{ + const css_token *token; + css_fixed num; + size_t consumed = 0; + css_error error; + + UNUSED(c); + + consumeWhitespace(vector, ctx); + + token = parserutils_vector_iterate(vector, ctx); + if (token == NULL || (token->type != CSS_TOKEN_DIMENSION && + token->type != CSS_TOKEN_NUMBER && + token->type != CSS_TOKEN_PERCENTAGE)) + return CSS_INVALID; + + num = number_from_lwc_string(token->idata, false, &consumed); + + if (token->type == CSS_TOKEN_DIMENSION) { + size_t len = lwc_string_length(token->idata); + const char *data = lwc_string_data(token->idata); + + error = parse_unit_keyword(data + consumed, len - consumed, + unit); + if (error != CSS_OK) + return error; + } else if (token->type == CSS_TOKEN_NUMBER) { + /* Non-zero values are permitted in quirks mode */ + if (num != 0) { + if (c->sheet->quirks_allowed) + c->sheet->quirks_used = true; + else + return CSS_INVALID; + } + + *unit = default_unit; + + if (c->sheet->quirks_allowed) { + /* Also, in quirks mode, we need to cater for + * dimensions separated from their units by whitespace + * (e.g. "0 px") + */ + int temp_ctx = *ctx; + uint32_t temp_unit; + + consumeWhitespace(vector, &temp_ctx); + + token = parserutils_vector_iterate(vector, &temp_ctx); + if (token != NULL && token->type == CSS_TOKEN_IDENT) { + error = parse_unit_keyword( + lwc_string_data(token->idata), + lwc_string_length(token->idata), + &temp_unit); + if (error == CSS_OK) { + c->sheet->quirks_used = true; + *ctx = temp_ctx; + *unit = temp_unit; + } + } + } + + } else { + if (consumed != lwc_string_length(token->idata)) + return CSS_INVALID; + *unit = UNIT_PCT; + } + + *length = num; + + return CSS_OK; +} + +css_error parse_unit_keyword(const char *ptr, size_t len, css_unit *unit) +{ + if (len == 4) { + if (strncasecmp(ptr, "grad", 4) == 0) + *unit = UNIT_GRAD; + else + return CSS_INVALID; + } else if (len == 3) { + if (strncasecmp(ptr, "kHz", 3) == 0) + *unit = UNIT_KHZ; + else if (strncasecmp(ptr, "deg", 3) == 0) + *unit = UNIT_DEG; + else if (strncasecmp(ptr, "rad", 3) == 0) + *unit = UNIT_RAD; + else + return CSS_INVALID; + } else if (len == 2) { + if (strncasecmp(ptr, "Hz", 2) == 0) + *unit = UNIT_HZ; + else if (strncasecmp(ptr, "ms", 2) == 0) + *unit = UNIT_MS; + else if (strncasecmp(ptr, "px", 2) == 0) + *unit = UNIT_PX; + else if (strncasecmp(ptr, "ex", 2) == 0) + *unit = UNIT_EX; + else if (strncasecmp(ptr, "em", 2) == 0) + *unit = UNIT_EM; + else if (strncasecmp(ptr, "in", 2) == 0) + *unit = UNIT_IN; + else if (strncasecmp(ptr, "cm", 2) == 0) + *unit = UNIT_CM; + else if (strncasecmp(ptr, "mm", 2) == 0) + *unit = UNIT_MM; + else if (strncasecmp(ptr, "pt", 2) == 0) + *unit = UNIT_PT; + else if (strncasecmp(ptr, "pc", 2) == 0) + *unit = UNIT_PC; + else + return CSS_INVALID; + } else if (len == 1) { + if (strncasecmp(ptr, "s", 1) == 0) + *unit = UNIT_S; + else + return CSS_INVALID; + } else + return CSS_INVALID; + + return CSS_OK; +} + diff --git a/src/parse/properties/utils.h b/src/parse/properties/utils.h new file mode 100644 index 0000000..923ffb5 --- /dev/null +++ b/src/parse/properties/utils.h @@ -0,0 +1,29 @@ +/* + * 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> + */ + +#ifndef css_parse_properties_utils_h_ +#define css_parse_properties_utils_h_ + +#include "parse/language.h" + +css_error parse_important(css_language *c, + const parserutils_vector *vector, int *ctx, + uint8_t *result); +css_error parse_colour_specifier(css_language *c, + const parserutils_vector *vector, int *ctx, + uint32_t *result); +css_error parse_named_colour(css_language *c, lwc_string *data, + uint32_t *result); +css_error parse_hash_colour(lwc_string *data, uint32_t *result); +css_error parse_unit_specifier(css_language *c, + const parserutils_vector *vector, int *ctx, + uint32_t default_unit, + css_fixed *length, uint32_t *unit); +css_error parse_unit_keyword(const char *ptr, size_t len, + css_unit *unit); + +#endif |