diff options
Diffstat (limited to 'src/parse/properties')
-rw-r--r-- | src/parse/properties/border_outline.c | 1182 | ||||
-rw-r--r-- | src/parse/properties/properties.c | 9 | ||||
-rw-r--r-- | src/parse/properties/properties.h | 27 |
3 files changed, 1218 insertions, 0 deletions
diff --git a/src/parse/properties/border_outline.c b/src/parse/properties/border_outline.c index 7245fa6..0c101bc 100644 --- a/src/parse/properties/border_outline.c +++ b/src/parse/properties/border_outline.c @@ -5,6 +5,7 @@ * Copyright 2009 John-Mark Bell <jmb@netsurf-browser.org> */ +#include <assert.h> #include <string.h> #include "bytecode/bytecode.h" @@ -12,6 +13,11 @@ #include "parse/properties/properties.h" #include "parse/properties/utils.h" +enum { SIDE_TOP = 0, SIDE_RIGHT = 1, SIDE_BOTTOM = 2, SIDE_LEFT = 3 }; + +static css_error parse_border_side(css_language *c, + const parserutils_vector *vector, int *ctx, + uint32_t side, css_style **result); static css_error parse_border_side_color(css_language *c, const parserutils_vector *vector, int *ctx, uint16_t op, css_style **result); @@ -22,6 +28,108 @@ static css_error parse_border_side_width(css_language *c, const parserutils_vector *vector, int *ctx, uint16_t op, css_style **result); +/** + * Parse border shorthand + * + * \param c Parsing context + * \param vector Vector of tokens to process + * \param ctx Pointer to vector iteration context + * \param result Pointer to location to receive resulting style + * \return CSS_OK on success, + * CSS_NOMEM on memory exhaustion, + * CSS_INVALID if the input is not valid + * + * Post condition: \a *ctx is updated with the next token to process + * If the input is invalid, then \a *ctx remains unchanged. + */ +css_error parse_border(css_language *c, + const parserutils_vector *vector, int *ctx, + css_style **result) +{ + int orig_ctx = *ctx; + css_style *top = NULL; + css_style *right = NULL; + css_style *bottom = NULL; + css_style *left = NULL; + css_style *ret = NULL; + uint32_t required_size; + css_error error; + + error = parse_border_side(c, vector, ctx, SIDE_TOP, &top); + if (error != CSS_OK) + goto cleanup; + + *ctx = orig_ctx; + error = parse_border_side(c, vector, ctx, SIDE_RIGHT, &right); + if (error != CSS_OK) + goto cleanup; + + *ctx = orig_ctx; + error = parse_border_side(c, vector, ctx, SIDE_BOTTOM, &bottom); + if (error != CSS_OK) + goto cleanup; + + *ctx = orig_ctx; + error = parse_border_side(c, vector, ctx, SIDE_LEFT, &left); + if (error != CSS_OK) + goto cleanup; + + required_size = top->length + right->length + + bottom->length + left->length; + + error = css_stylesheet_style_create(c->sheet, required_size, &ret); + if (error != CSS_OK) + goto cleanup; + + required_size = 0; + + memcpy(((uint8_t *) ret->bytecode) + required_size, + top->bytecode, top->length); + required_size += top->length; + + memcpy(((uint8_t *) ret->bytecode) + required_size, + right->bytecode, right->length); + required_size += right->length; + + memcpy(((uint8_t *) ret->bytecode) + required_size, + bottom->bytecode, bottom->length); + required_size += bottom->length; + + memcpy(((uint8_t *) ret->bytecode) + required_size, + left->bytecode, left->length); + required_size += left->length; + + assert(required_size == ret->length); + + *result = ret; + ret = NULL; + + /* Clean up after ourselves */ +cleanup: + if (top) + css_stylesheet_style_destroy(c->sheet, top); + if (right) + css_stylesheet_style_destroy(c->sheet, right); + if (bottom) + css_stylesheet_style_destroy(c->sheet, bottom); + if (left) + css_stylesheet_style_destroy(c->sheet, left); + if (ret) + css_stylesheet_style_destroy(c->sheet, ret); + + if (error != CSS_OK) + *ctx = orig_ctx; + + return error; +} + +css_error parse_border_bottom(css_language *c, + const parserutils_vector *vector, int *ctx, + css_style **result) +{ + return parse_border_side(c, vector, ctx, SIDE_BOTTOM, result); +} + css_error parse_border_bottom_color(css_language *c, const parserutils_vector *vector, int *ctx, css_style **result) @@ -104,6 +212,252 @@ css_error parse_border_collapse(css_language *c, return CSS_OK; } +/** + * Parse border-color shorthand + * + * \param c Parsing context + * \param vector Vector of tokens to process + * \param ctx Pointer to vector iteration context + * \param result Pointer to location to receive resulting style + * \return CSS_OK on success, + * CSS_NOMEM on memory exhaustion, + * CSS_INVALID if the input is not valid + * + * Post condition: \a *ctx is updated with the next token to process + * If the input is invalid, then \a *ctx remains unchanged. + */ +css_error parse_border_color(css_language *c, + const parserutils_vector *vector, int *ctx, + css_style **result) +{ + int orig_ctx = *ctx; + int prev_ctx; + const css_token *token; + css_style *top = NULL; + css_style *right = NULL; + css_style *bottom = NULL; + css_style *left = NULL; + css_style *ret = NULL; + uint32_t num_sides = 0; + uint32_t required_size; + css_error error; + + /* Firstly, handle inherit */ + token = parserutils_vector_peek(vector, *ctx); + if (token != NULL && token->type == CSS_TOKEN_IDENT && + token->ilower == c->strings[INHERIT]) { + uint32_t *bytecode; + + error = css_stylesheet_style_create(c->sheet, + 4 * sizeof(uint32_t), &ret); + if (error != CSS_OK) { + *ctx = orig_ctx; + return error; + } + + bytecode = (uint32_t *) ret->bytecode; + + *(bytecode++) = buildOPV(CSS_PROP_BORDER_TOP_COLOR, + FLAG_INHERIT, 0); + *(bytecode++) = buildOPV(CSS_PROP_BORDER_RIGHT_COLOR, + FLAG_INHERIT, 0); + *(bytecode++) = buildOPV(CSS_PROP_BORDER_BOTTOM_COLOR, + FLAG_INHERIT, 0); + *(bytecode++) = buildOPV(CSS_PROP_BORDER_LEFT_COLOR, + FLAG_INHERIT, 0); + + parserutils_vector_iterate(vector, ctx); + + *result = ret; + + return CSS_OK; + } else if (token == NULL) { + /* No tokens -- clearly garbage */ + *ctx = orig_ctx; + return CSS_INVALID; + } + + /* Attempt to parse up to 4 colours */ + do { + prev_ctx = *ctx; + error = CSS_OK; + + if (top == NULL && + (error = parse_border_side_color(c, vector, + ctx, CSS_PROP_BORDER_TOP_COLOR, &top)) == + CSS_OK) { + num_sides = 1; + } else if (right == NULL && + (error = parse_border_side_color(c, vector, + ctx, CSS_PROP_BORDER_RIGHT_COLOR, &right)) == + CSS_OK) { + num_sides = 2; + } else if (bottom == NULL && + (error = parse_border_side_color(c, vector, + ctx, CSS_PROP_BORDER_BOTTOM_COLOR, &bottom)) == + CSS_OK) { + num_sides = 3; + } else if (left == NULL && + (error = parse_border_side_color(c, vector, + ctx, CSS_PROP_BORDER_LEFT_COLOR, &left)) == + CSS_OK) { + num_sides = 4; + } + + if (error == CSS_OK) { + consumeWhitespace(vector, ctx); + + token = parserutils_vector_peek(vector, *ctx); + } else { + /* Forcibly cause loop to exit */ + token = NULL; + } + } while (*ctx != prev_ctx && token != NULL); + + if (num_sides == 0) { + error = CSS_INVALID; + goto cleanup; + } + + /* Calculate size of resultant style */ + if (num_sides == 1) { + required_size = 4 * top->length; + } else if (num_sides == 2) { + required_size = 2 * top->length + 2 * right->length; + } else if (num_sides == 3) { + required_size = top->length + 2 * right->length + + bottom->length; + } else { + required_size = top->length + right->length + + bottom->length + left->length; + } + + error = css_stylesheet_style_create(c->sheet, required_size, &ret); + if (error != CSS_OK) + goto cleanup; + + required_size = 0; + + if (num_sides == 1) { + uint32_t *opv = ((uint32_t *) top->bytecode); + uint8_t flags = getFlags(*opv); + uint16_t value = getValue(*opv); + + memcpy(((uint8_t *) ret->bytecode) + required_size, + top->bytecode, top->length); + required_size += top->length; + + *opv = buildOPV(CSS_PROP_BORDER_RIGHT_COLOR, flags, value); + memcpy(((uint8_t *) ret->bytecode) + required_size, + top->bytecode, top->length); + required_size += top->length; + + *opv = buildOPV(CSS_PROP_BORDER_BOTTOM_COLOR, flags, value); + memcpy(((uint8_t *) ret->bytecode) + required_size, + top->bytecode, top->length); + required_size += top->length; + + *opv = buildOPV(CSS_PROP_BORDER_LEFT_COLOR, flags, value); + memcpy(((uint8_t *) ret->bytecode) + required_size, + top->bytecode, top->length); + required_size += top->length; + } else if (num_sides == 2) { + uint32_t *vopv = ((uint32_t *) top->bytecode); + uint32_t *hopv = ((uint32_t *) right->bytecode); + uint8_t vflags = getFlags(*vopv); + uint8_t hflags = getFlags(*hopv); + uint16_t vvalue = getValue(*vopv); + uint16_t hvalue = getValue(*hopv); + + memcpy(((uint8_t *) ret->bytecode) + required_size, + top->bytecode, top->length); + required_size += top->length; + + memcpy(((uint8_t *) ret->bytecode) + required_size, + right->bytecode, right->length); + required_size += right->length; + + *vopv = buildOPV(CSS_PROP_BORDER_BOTTOM_COLOR, vflags, vvalue); + memcpy(((uint8_t *) ret->bytecode) + required_size, + top->bytecode, top->length); + required_size += top->length; + + *hopv = buildOPV(CSS_PROP_BORDER_LEFT_COLOR, hflags, hvalue); + memcpy(((uint8_t *) ret->bytecode) + required_size, + right->bytecode, right->length); + required_size += right->length; + } else if (num_sides == 3) { + uint32_t *opv = ((uint32_t *) right->bytecode); + uint8_t flags = getFlags(*opv); + uint16_t value = getValue(*opv); + + memcpy(((uint8_t *) ret->bytecode) + required_size, + top->bytecode, top->length); + required_size += top->length; + + memcpy(((uint8_t *) ret->bytecode) + required_size, + right->bytecode, right->length); + required_size += right->length; + + memcpy(((uint8_t *) ret->bytecode) + required_size, + bottom->bytecode, bottom->length); + required_size += bottom->length; + + *opv = buildOPV(CSS_PROP_BORDER_LEFT_COLOR, flags, value); + memcpy(((uint8_t *) ret->bytecode) + required_size, + right->bytecode, right->length); + required_size += right->length; + } else { + memcpy(((uint8_t *) ret->bytecode) + required_size, + top->bytecode, top->length); + required_size += top->length; + + memcpy(((uint8_t *) ret->bytecode) + required_size, + right->bytecode, right->length); + required_size += right->length; + + memcpy(((uint8_t *) ret->bytecode) + required_size, + bottom->bytecode, bottom->length); + required_size += bottom->length; + + memcpy(((uint8_t *) ret->bytecode) + required_size, + left->bytecode, left->length); + required_size += left->length; + } + + assert(required_size == ret->length); + + /* Write the result */ + *result = ret; + /* Invalidate ret, so that cleanup doesn't destroy it */ + ret = NULL; + + /* Clean up after ourselves */ +cleanup: + if (top) + css_stylesheet_style_destroy(c->sheet, top); + if (right) + css_stylesheet_style_destroy(c->sheet, right); + if (bottom) + css_stylesheet_style_destroy(c->sheet, bottom); + if (left) + css_stylesheet_style_destroy(c->sheet, left); + if (ret) + css_stylesheet_style_destroy(c->sheet, ret); + + if (error != CSS_OK) + *ctx = orig_ctx; + + return error; +} + +css_error parse_border_left(css_language *c, + const parserutils_vector *vector, int *ctx, + css_style **result) +{ + return parse_border_side(c, vector, ctx, SIDE_LEFT, result); +} + css_error parse_border_left_color(css_language *c, const parserutils_vector *vector, int *ctx, css_style **result) @@ -128,6 +482,13 @@ css_error parse_border_left_width(css_language *c, CSS_PROP_BORDER_LEFT_WIDTH, result); } +css_error parse_border_right(css_language *c, + const parserutils_vector *vector, int *ctx, + css_style **result) +{ + return parse_border_side(c, vector, ctx, SIDE_RIGHT, result); +} + css_error parse_border_right_color(css_language *c, const parserutils_vector *vector, int *ctx, css_style **result) @@ -278,6 +639,252 @@ css_error parse_border_spacing(css_language *c, return CSS_OK; } +/** + * Parse border-style shorthand + * + * \param c Parsing context + * \param vector Vector of tokens to process + * \param ctx Pointer to vector iteration context + * \param result Pointer to location to receive resulting style + * \return CSS_OK on success, + * CSS_NOMEM on memory exhaustion, + * CSS_INVALID if the input is not valid + * + * Post condition: \a *ctx is updated with the next token to process + * If the input is invalid, then \a *ctx remains unchanged. + */ +css_error parse_border_style(css_language *c, + const parserutils_vector *vector, int *ctx, + css_style **result) +{ + int orig_ctx = *ctx; + int prev_ctx; + const css_token *token; + css_style *top = NULL; + css_style *right = NULL; + css_style *bottom = NULL; + css_style *left = NULL; + css_style *ret = NULL; + uint32_t num_sides = 0; + uint32_t required_size; + css_error error; + + /* Firstly, handle inherit */ + token = parserutils_vector_peek(vector, *ctx); + if (token != NULL && token->type == CSS_TOKEN_IDENT && + token->ilower == c->strings[INHERIT]) { + uint32_t *bytecode; + + error = css_stylesheet_style_create(c->sheet, + 4 * sizeof(uint32_t), &ret); + if (error != CSS_OK) { + *ctx = orig_ctx; + return error; + } + + bytecode = (uint32_t *) ret->bytecode; + + *(bytecode++) = buildOPV(CSS_PROP_BORDER_TOP_STYLE, + FLAG_INHERIT, 0); + *(bytecode++) = buildOPV(CSS_PROP_BORDER_RIGHT_STYLE, + FLAG_INHERIT, 0); + *(bytecode++) = buildOPV(CSS_PROP_BORDER_BOTTOM_STYLE, + FLAG_INHERIT, 0); + *(bytecode++) = buildOPV(CSS_PROP_BORDER_LEFT_STYLE, + FLAG_INHERIT, 0); + + parserutils_vector_iterate(vector, ctx); + + *result = ret; + + return CSS_OK; + } else if (token == NULL) { + /* No tokens -- clearly garbage */ + *ctx = orig_ctx; + return CSS_INVALID; + } + + /* Attempt to parse up to 4 styles */ + do { + prev_ctx = *ctx; + error = CSS_OK; + + if (top == NULL && + (error = parse_border_side_style(c, vector, + ctx, CSS_PROP_BORDER_TOP_STYLE, &top)) == + CSS_OK) { + num_sides = 1; + } else if (right == NULL && + (error = parse_border_side_style(c, vector, + ctx, CSS_PROP_BORDER_RIGHT_STYLE, &right)) == + CSS_OK) { + num_sides = 2; + } else if (bottom == NULL && + (error = parse_border_side_style(c, vector, + ctx, CSS_PROP_BORDER_BOTTOM_STYLE, &bottom)) == + CSS_OK) { + num_sides = 3; + } else if (left == NULL && + (error = parse_border_side_style(c, vector, + ctx, CSS_PROP_BORDER_LEFT_STYLE, &left)) == + CSS_OK) { + num_sides = 4; + } + + if (error == CSS_OK) { + consumeWhitespace(vector, ctx); + + token = parserutils_vector_peek(vector, *ctx); + } else { + /* Forcibly cause loop to exit */ + token = NULL; + } + } while (*ctx != prev_ctx && token != NULL); + + if (num_sides == 0) { + error = CSS_INVALID; + goto cleanup; + } + + /* Calculate size of resultant style */ + if (num_sides == 1) { + required_size = 4 * top->length; + } else if (num_sides == 2) { + required_size = 2 * top->length + 2 * right->length; + } else if (num_sides == 3) { + required_size = top->length + 2 * right->length + + bottom->length; + } else { + required_size = top->length + right->length + + bottom->length + left->length; + } + + error = css_stylesheet_style_create(c->sheet, required_size, &ret); + if (error != CSS_OK) + goto cleanup; + + required_size = 0; + + if (num_sides == 1) { + uint32_t *opv = ((uint32_t *) top->bytecode); + uint8_t flags = getFlags(*opv); + uint16_t value = getValue(*opv); + + memcpy(((uint8_t *) ret->bytecode) + required_size, + top->bytecode, top->length); + required_size += top->length; + + *opv = buildOPV(CSS_PROP_BORDER_RIGHT_STYLE, flags, value); + memcpy(((uint8_t *) ret->bytecode) + required_size, + top->bytecode, top->length); + required_size += top->length; + + *opv = buildOPV(CSS_PROP_BORDER_BOTTOM_STYLE, flags, value); + memcpy(((uint8_t *) ret->bytecode) + required_size, + top->bytecode, top->length); + required_size += top->length; + + *opv = buildOPV(CSS_PROP_BORDER_LEFT_STYLE, flags, value); + memcpy(((uint8_t *) ret->bytecode) + required_size, + top->bytecode, top->length); + required_size += top->length; + } else if (num_sides == 2) { + uint32_t *vopv = ((uint32_t *) top->bytecode); + uint32_t *hopv = ((uint32_t *) right->bytecode); + uint8_t vflags = getFlags(*vopv); + uint8_t hflags = getFlags(*hopv); + uint16_t vvalue = getValue(*vopv); + uint16_t hvalue = getValue(*hopv); + + memcpy(((uint8_t *) ret->bytecode) + required_size, + top->bytecode, top->length); + required_size += top->length; + + memcpy(((uint8_t *) ret->bytecode) + required_size, + right->bytecode, right->length); + required_size += right->length; + + *vopv = buildOPV(CSS_PROP_BORDER_BOTTOM_STYLE, vflags, vvalue); + memcpy(((uint8_t *) ret->bytecode) + required_size, + top->bytecode, top->length); + required_size += top->length; + + *hopv = buildOPV(CSS_PROP_BORDER_LEFT_STYLE, hflags, hvalue); + memcpy(((uint8_t *) ret->bytecode) + required_size, + right->bytecode, right->length); + required_size += right->length; + } else if (num_sides == 3) { + uint32_t *opv = ((uint32_t *) right->bytecode); + uint8_t flags = getFlags(*opv); + uint16_t value = getValue(*opv); + + memcpy(((uint8_t *) ret->bytecode) + required_size, + top->bytecode, top->length); + required_size += top->length; + + memcpy(((uint8_t *) ret->bytecode) + required_size, + right->bytecode, right->length); + required_size += right->length; + + memcpy(((uint8_t *) ret->bytecode) + required_size, + bottom->bytecode, bottom->length); + required_size += bottom->length; + + *opv = buildOPV(CSS_PROP_BORDER_LEFT_STYLE, flags, value); + memcpy(((uint8_t *) ret->bytecode) + required_size, + right->bytecode, right->length); + required_size += right->length; + } else { + memcpy(((uint8_t *) ret->bytecode) + required_size, + top->bytecode, top->length); + required_size += top->length; + + memcpy(((uint8_t *) ret->bytecode) + required_size, + right->bytecode, right->length); + required_size += right->length; + + memcpy(((uint8_t *) ret->bytecode) + required_size, + bottom->bytecode, bottom->length); + required_size += bottom->length; + + memcpy(((uint8_t *) ret->bytecode) + required_size, + left->bytecode, left->length); + required_size += left->length; + } + + assert(required_size == ret->length); + + /* Write the result */ + *result = ret; + /* Invalidate ret, so that cleanup doesn't destroy it */ + ret = NULL; + + /* Clean up after ourselves */ +cleanup: + if (top) + css_stylesheet_style_destroy(c->sheet, top); + if (right) + css_stylesheet_style_destroy(c->sheet, right); + if (bottom) + css_stylesheet_style_destroy(c->sheet, bottom); + if (left) + css_stylesheet_style_destroy(c->sheet, left); + if (ret) + css_stylesheet_style_destroy(c->sheet, ret); + + if (error != CSS_OK) + *ctx = orig_ctx; + + return error; +} + +css_error parse_border_top(css_language *c, + const parserutils_vector *vector, int *ctx, + css_style **result) +{ + return parse_border_side(c, vector, ctx, SIDE_TOP, result); +} + css_error parse_border_top_color(css_language *c, const parserutils_vector *vector, int *ctx, css_style **result) @@ -303,6 +910,415 @@ css_error parse_border_top_width(css_language *c, } /** + * Parse border-width shorthand + * + * \param c Parsing context + * \param vector Vector of tokens to process + * \param ctx Pointer to vector iteration context + * \param result Pointer to location to receive resulting style + * \return CSS_OK on success, + * CSS_NOMEM on memory exhaustion, + * CSS_INVALID if the input is not valid + * + * Post condition: \a *ctx is updated with the next token to process + * If the input is invalid, then \a *ctx remains unchanged. + */ +css_error parse_border_width(css_language *c, + const parserutils_vector *vector, int *ctx, + css_style **result) +{ + int orig_ctx = *ctx; + int prev_ctx; + const css_token *token; + css_style *top = NULL; + css_style *right = NULL; + css_style *bottom = NULL; + css_style *left = NULL; + css_style *ret = NULL; + uint32_t num_sides = 0; + uint32_t required_size; + css_error error; + + /* Firstly, handle inherit */ + token = parserutils_vector_peek(vector, *ctx); + if (token != NULL && token->type == CSS_TOKEN_IDENT && + token->ilower == c->strings[INHERIT]) { + uint32_t *bytecode; + + error = css_stylesheet_style_create(c->sheet, + 4 * sizeof(uint32_t), &ret); + if (error != CSS_OK) { + *ctx = orig_ctx; + return error; + } + + bytecode = (uint32_t *) ret->bytecode; + + *(bytecode++) = buildOPV(CSS_PROP_BORDER_TOP_WIDTH, + FLAG_INHERIT, 0); + *(bytecode++) = buildOPV(CSS_PROP_BORDER_RIGHT_WIDTH, + FLAG_INHERIT, 0); + *(bytecode++) = buildOPV(CSS_PROP_BORDER_BOTTOM_WIDTH, + FLAG_INHERIT, 0); + *(bytecode++) = buildOPV(CSS_PROP_BORDER_LEFT_WIDTH, + FLAG_INHERIT, 0); + + parserutils_vector_iterate(vector, ctx); + + *result = ret; + + return CSS_OK; + } else if (token == NULL) { + /* No tokens -- clearly garbage */ + *ctx = orig_ctx; + return CSS_INVALID; + } + + /* Attempt to parse up to 4 widths */ + do { + prev_ctx = *ctx; + error = CSS_OK; + + if (top == NULL && + (error = parse_border_side_width(c, vector, + ctx, CSS_PROP_BORDER_TOP_WIDTH, &top)) == + CSS_OK) { + num_sides = 1; + } else if (right == NULL && + (error = parse_border_side_width(c, vector, + ctx, CSS_PROP_BORDER_RIGHT_WIDTH, &right)) == + CSS_OK) { + num_sides = 2; + } else if (bottom == NULL && + (error = parse_border_side_width(c, vector, + ctx, CSS_PROP_BORDER_BOTTOM_WIDTH, &bottom)) == + CSS_OK) { + num_sides = 3; + } else if (left == NULL && + (error = parse_border_side_width(c, vector, + ctx, CSS_PROP_BORDER_LEFT_WIDTH, &left)) == + CSS_OK) { + num_sides = 4; + } + + if (error == CSS_OK) { + consumeWhitespace(vector, ctx); + + token = parserutils_vector_peek(vector, *ctx); + } else { + /* Forcibly cause loop to exit */ + token = NULL; + } + } while (*ctx != prev_ctx && token != NULL); + + if (num_sides == 0) { + error = CSS_INVALID; + goto cleanup; + } + + /* Calculate size of resultant style */ + if (num_sides == 1) { + required_size = 4 * top->length; + } else if (num_sides == 2) { + required_size = 2 * top->length + 2 * right->length; + } else if (num_sides == 3) { + required_size = top->length + 2 * right->length + + bottom->length; + } else { + required_size = top->length + right->length + + bottom->length + left->length; + } + + error = css_stylesheet_style_create(c->sheet, required_size, &ret); + if (error != CSS_OK) + goto cleanup; + + required_size = 0; + + if (num_sides == 1) { + uint32_t *opv = ((uint32_t *) top->bytecode); + uint8_t flags = getFlags(*opv); + uint16_t value = getValue(*opv); + + memcpy(((uint8_t *) ret->bytecode) + required_size, + top->bytecode, top->length); + required_size += top->length; + + *opv = buildOPV(CSS_PROP_BORDER_RIGHT_WIDTH, flags, value); + memcpy(((uint8_t *) ret->bytecode) + required_size, + top->bytecode, top->length); + required_size += top->length; + + *opv = buildOPV(CSS_PROP_BORDER_BOTTOM_WIDTH, flags, value); + memcpy(((uint8_t *) ret->bytecode) + required_size, + top->bytecode, top->length); + required_size += top->length; + + *opv = buildOPV(CSS_PROP_BORDER_LEFT_WIDTH, flags, value); + memcpy(((uint8_t *) ret->bytecode) + required_size, + top->bytecode, top->length); + required_size += top->length; + } else if (num_sides == 2) { + uint32_t *vopv = ((uint32_t *) top->bytecode); + uint32_t *hopv = ((uint32_t *) right->bytecode); + uint8_t vflags = getFlags(*vopv); + uint8_t hflags = getFlags(*hopv); + uint16_t vvalue = getValue(*vopv); + uint16_t hvalue = getValue(*hopv); + + memcpy(((uint8_t *) ret->bytecode) + required_size, + top->bytecode, top->length); + required_size += top->length; + + memcpy(((uint8_t *) ret->bytecode) + required_size, + right->bytecode, right->length); + required_size += right->length; + + *vopv = buildOPV(CSS_PROP_BORDER_BOTTOM_WIDTH, vflags, vvalue); + memcpy(((uint8_t *) ret->bytecode) + required_size, + top->bytecode, top->length); + required_size += top->length; + + *hopv = buildOPV(CSS_PROP_BORDER_LEFT_WIDTH, hflags, hvalue); + memcpy(((uint8_t *) ret->bytecode) + required_size, + right->bytecode, right->length); + required_size += right->length; + } else if (num_sides == 3) { + uint32_t *opv = ((uint32_t *) right->bytecode); + uint8_t flags = getFlags(*opv); + uint16_t value = getValue(*opv); + + memcpy(((uint8_t *) ret->bytecode) + required_size, + top->bytecode, top->length); + required_size += top->length; + + memcpy(((uint8_t *) ret->bytecode) + required_size, + right->bytecode, right->length); + required_size += right->length; + + memcpy(((uint8_t *) ret->bytecode) + required_size, + bottom->bytecode, bottom->length); + required_size += bottom->length; + + *opv = buildOPV(CSS_PROP_BORDER_LEFT_WIDTH, flags, value); + memcpy(((uint8_t *) ret->bytecode) + required_size, + right->bytecode, right->length); + required_size += right->length; + } else { + memcpy(((uint8_t *) ret->bytecode) + required_size, + top->bytecode, top->length); + required_size += top->length; + + memcpy(((uint8_t *) ret->bytecode) + required_size, + right->bytecode, right->length); + required_size += right->length; + + memcpy(((uint8_t *) ret->bytecode) + required_size, + bottom->bytecode, bottom->length); + required_size += bottom->length; + + memcpy(((uint8_t *) ret->bytecode) + required_size, + left->bytecode, left->length); + required_size += left->length; + } + + assert(required_size == ret->length); + + /* Write the result */ + *result = ret; + /* Invalidate ret, so that cleanup doesn't destroy it */ + ret = NULL; + + /* Clean up after ourselves */ +cleanup: + if (top) + css_stylesheet_style_destroy(c->sheet, top); + if (right) + css_stylesheet_style_destroy(c->sheet, right); + if (bottom) + css_stylesheet_style_destroy(c->sheet, bottom); + if (left) + css_stylesheet_style_destroy(c->sheet, left); + if (ret) + css_stylesheet_style_destroy(c->sheet, ret); + + if (error != CSS_OK) + *ctx = orig_ctx; + + return error; +} + +/** + * Parse outline shorthand + * + * \param c Parsing context + * \param vector Vector of tokens to process + * \param ctx Pointer to vector iteration context + * \param result Pointer to location to receive resulting style + * \return CSS_OK on success, + * CSS_NOMEM on memory exhaustion, + * CSS_INVALID if the input is not valid + * + * Post condition: \a *ctx is updated with the next token to process + * If the input is invalid, then \a *ctx remains unchanged. + */ +css_error parse_outline(css_language *c, + const parserutils_vector *vector, int *ctx, + css_style **result) +{ + int orig_ctx = *ctx; + int prev_ctx; + const css_token *token; + css_style *color = NULL; + css_style *style = NULL; + css_style *width = NULL; + css_style *ret = NULL; + uint32_t required_size; + css_error error; + + /* Firstly, handle inherit */ + token = parserutils_vector_peek(vector, *ctx); + if (token != NULL && token->type == CSS_TOKEN_IDENT && + token->ilower == c->strings[INHERIT]) { + uint32_t *bytecode; + + error = css_stylesheet_style_create(c->sheet, + 3 * sizeof(uint32_t), &ret); + if (error != CSS_OK) { + *ctx = orig_ctx; + return error; + } + + bytecode = (uint32_t *) ret->bytecode; + + *(bytecode++) = buildOPV(CSS_PROP_OUTLINE_COLOR, + FLAG_INHERIT, 0); + *(bytecode++) = buildOPV(CSS_PROP_OUTLINE_STYLE, + FLAG_INHERIT, 0); + *(bytecode++) = buildOPV(CSS_PROP_OUTLINE_WIDTH, + FLAG_INHERIT, 0); + + parserutils_vector_iterate(vector, ctx); + + *result = ret; + + return CSS_OK; + } else if (token == NULL) { + /* No tokens -- clearly garbage */ + *ctx = orig_ctx; + return CSS_INVALID; + } + + /* Attempt to parse individual properties */ + do { + prev_ctx = *ctx; + error = CSS_OK; + + if (color == NULL && + (error = parse_outline_color(c, vector, + ctx, &color)) == CSS_OK) { + } else if (style == NULL && + (error = parse_outline_style(c, vector, + ctx, &style)) == CSS_OK) { + } else if (width == NULL && + (error = parse_outline_width(c, vector, + ctx, &width)) == CSS_OK) { + } + + if (error == CSS_OK) { + consumeWhitespace(vector, ctx); + + token = parserutils_vector_peek(vector, *ctx); + } else { + /* Forcibly cause loop to exit */ + token = NULL; + } + } while (*ctx != prev_ctx && token != NULL); + + /* Calculate size of resultant style */ + required_size = 0; + if (color) + required_size += color->length; + else + required_size += sizeof(uint32_t); + + if (style) + required_size += style->length; + else + required_size += sizeof(uint32_t); + + if (width) + required_size += width->length; + else + required_size += sizeof(uint32_t); + + error = css_stylesheet_style_create(c->sheet, required_size, &ret); + if (error != CSS_OK) + goto cleanup; + + required_size = 0; + + if (color) { + memcpy(((uint8_t *) ret->bytecode) + required_size, + color->bytecode, color->length); + required_size += color->length; + } else { + void *bc = ((uint8_t *) ret->bytecode) + required_size; + + *((uint32_t *) bc) = buildOPV(CSS_PROP_OUTLINE_COLOR, + 0, OUTLINE_COLOR_INVERT); + required_size += sizeof(uint32_t); + } + + if (style) { + memcpy(((uint8_t *) ret->bytecode) + required_size, + style->bytecode, style->length); + required_size += style->length; + } else { + void *bc = ((uint8_t *) ret->bytecode) + required_size; + + *((uint32_t *) bc) = buildOPV(CSS_PROP_OUTLINE_STYLE, + 0, OUTLINE_STYLE_NONE); + required_size += sizeof(uint32_t); + } + + if (width) { + memcpy(((uint8_t *) ret->bytecode) + required_size, + width->bytecode, width->length); + required_size += width->length; + } else { + void *bc = ((uint8_t *) ret->bytecode) + required_size; + + *((uint32_t *) bc) = buildOPV(CSS_PROP_OUTLINE_WIDTH, + 0, OUTLINE_WIDTH_MEDIUM); + required_size += sizeof(uint32_t); + } + + assert(required_size == ret->length); + + /* Write the result */ + *result = ret; + /* Invalidate ret, so that cleanup doesn't destroy it */ + ret = NULL; + + /* Clean up after ourselves */ +cleanup: + if (color) + css_stylesheet_style_destroy(c->sheet, color); + if (style) + css_stylesheet_style_destroy(c->sheet, style); + if (width) + css_stylesheet_style_destroy(c->sheet, width); + if (ret) + css_stylesheet_style_destroy(c->sheet, ret); + + if (error != CSS_OK) + *ctx = orig_ctx; + + return error; +} + +/** * Parse outline-color * * \param c Parsing context @@ -431,6 +1447,172 @@ css_error parse_outline_width(css_language *c, } /** + * Parse border-{top,right,bottom,left} shorthand + * + * \param c Parsing context + * \param vector Vector of tokens to process + * \param ctx Pointer to vector iteration context + * \param side The side we're parsing for + * \param result Pointer to location to receive resulting style + * \return CSS_OK on success, + * CSS_NOMEM on memory exhaustion, + * CSS_INVALID if the input is not valid + * + * Post condition: \a *ctx is updated with the next token to process + * If the input is invalid, then \a *ctx remains unchanged. + */ +css_error parse_border_side(css_language *c, + const parserutils_vector *vector, int *ctx, + uint32_t side, css_style **result) +{ + int orig_ctx = *ctx; + int prev_ctx; + const css_token *token; + css_style *color = NULL; + css_style *style = NULL; + css_style *width = NULL; + css_style *ret = NULL; + uint32_t required_size; + css_error error; + + /* Firstly, handle inherit */ + token = parserutils_vector_peek(vector, *ctx); + if (token != NULL && token->type == CSS_TOKEN_IDENT && + token->ilower == c->strings[INHERIT]) { + uint32_t *bytecode; + + error = css_stylesheet_style_create(c->sheet, + 3 * sizeof(uint32_t), &ret); + if (error != CSS_OK) { + *ctx = orig_ctx; + return error; + } + + bytecode = (uint32_t *) ret->bytecode; + + *(bytecode++) = buildOPV(CSS_PROP_BORDER_TOP_COLOR + side, + FLAG_INHERIT, 0); + *(bytecode++) = buildOPV(CSS_PROP_BORDER_TOP_STYLE + side, + FLAG_INHERIT, 0); + *(bytecode++) = buildOPV(CSS_PROP_BORDER_TOP_WIDTH + side, + FLAG_INHERIT, 0); + + parserutils_vector_iterate(vector, ctx); + + *result = ret; + + return CSS_OK; + } else if (token == NULL) { + /* No tokens -- clearly garbage */ + *ctx = orig_ctx; + return CSS_INVALID; + } + + /* Attempt to parse individual properties */ + do { + prev_ctx = *ctx; + error = CSS_OK; + + if (color == NULL && + (error = parse_border_side_color(c, vector, ctx, + CSS_PROP_BORDER_TOP_COLOR + side, &color)) == + CSS_OK) { + } else if (style == NULL && + (error = parse_border_side_style(c, vector, ctx, + CSS_PROP_BORDER_TOP_STYLE + side, &style)) == + CSS_OK) { + } else if (width == NULL && + (error = parse_border_side_width(c, vector, ctx, + CSS_PROP_BORDER_TOP_WIDTH + side, &width)) == + CSS_OK) { + } + + if (error == CSS_OK) { + consumeWhitespace(vector, ctx); + + token = parserutils_vector_peek(vector, *ctx); + } else { + /* Forcibly cause loop to exit */ + token = NULL; + } + } while (*ctx != prev_ctx && token != NULL); + + /* Calculate size of resultant style */ + required_size = 0; + if (color) + required_size += color->length; + + if (style) + required_size += style->length; + else + required_size += sizeof(uint32_t); + + if (width) + required_size += width->length; + else + required_size += sizeof(uint32_t); + + error = css_stylesheet_style_create(c->sheet, required_size, &ret); + if (error != CSS_OK) + goto cleanup; + + required_size = 0; + + if (color) { + memcpy(((uint8_t *) ret->bytecode) + required_size, + color->bytecode, color->length); + required_size += color->length; + } + + if (style) { + memcpy(((uint8_t *) ret->bytecode) + required_size, + style->bytecode, style->length); + required_size += style->length; + } else { + void *bc = ((uint8_t *) ret->bytecode) + required_size; + + *((uint32_t *) bc) = buildOPV(CSS_PROP_BORDER_TOP_STYLE + side, + 0, BORDER_STYLE_NONE); + required_size += sizeof(uint32_t); + } + + if (width) { + memcpy(((uint8_t *) ret->bytecode) + required_size, + width->bytecode, width->length); + required_size += width->length; + } else { + void *bc = ((uint8_t *) ret->bytecode) + required_size; + + *((uint32_t *) bc) = buildOPV(CSS_PROP_BORDER_TOP_WIDTH + side, + 0, BORDER_WIDTH_MEDIUM); + required_size += sizeof(uint32_t); + } + + assert(required_size == ret->length); + + /* Write the result */ + *result = ret; + /* Invalidate ret, so that cleanup doesn't destroy it */ + ret = NULL; + + /* Clean up after ourselves */ +cleanup: + if (color) + css_stylesheet_style_destroy(c->sheet, color); + if (style) + css_stylesheet_style_destroy(c->sheet, style); + if (width) + css_stylesheet_style_destroy(c->sheet, width); + if (ret) + css_stylesheet_style_destroy(c->sheet, ret); + + if (error != CSS_OK) + *ctx = orig_ctx; + + return error; +} + +/** * Parse border-{top,right,bottom,left}-color * * \param c Parsing context diff --git a/src/parse/properties/properties.c b/src/parse/properties/properties.c index 8da730d..de92933 100644 --- a/src/parse/properties/properties.c +++ b/src/parse/properties/properties.c @@ -19,20 +19,28 @@ const css_prop_handler property_handlers[LAST_PROP + 1 - FIRST_PROP] = parse_background_image, parse_background_position, parse_background_repeat, + parse_border, + parse_border_bottom, parse_border_bottom_color, parse_border_bottom_style, parse_border_bottom_width, parse_border_collapse, + parse_border_color, + parse_border_left, parse_border_left_color, parse_border_left_style, parse_border_left_width, + parse_border_right, parse_border_right_color, parse_border_right_style, parse_border_right_width, parse_border_spacing, + parse_border_style, + parse_border_top, parse_border_top_color, parse_border_top_style, parse_border_top_width, + parse_border_width, parse_bottom, parse_caption_side, parse_clear, @@ -70,6 +78,7 @@ const css_prop_handler property_handlers[LAST_PROP + 1 - FIRST_PROP] = parse_min_height, parse_min_width, parse_orphans, + parse_outline, parse_outline_color, parse_outline_style, parse_outline_width, diff --git a/src/parse/properties/properties.h b/src/parse/properties/properties.h index a41f2c9..78a37d8 100644 --- a/src/parse/properties/properties.h +++ b/src/parse/properties/properties.h @@ -43,6 +43,12 @@ css_error parse_background_position(css_language *c, css_error parse_background_repeat(css_language *c, const parserutils_vector *vector, int *ctx, css_style **result); +css_error parse_border(css_language *c, + const parserutils_vector *vector, int *ctx, + css_style **result); +css_error parse_border_bottom(css_language *c, + const parserutils_vector *vector, int *ctx, + css_style **result); css_error parse_border_bottom_color(css_language *c, const parserutils_vector *vector, int *ctx, css_style **result); @@ -52,9 +58,15 @@ css_error parse_border_bottom_style(css_language *c, css_error parse_border_bottom_width(css_language *c, const parserutils_vector *vector, int *ctx, css_style **result); +css_error parse_border_color(css_language *c, + const parserutils_vector *vector, int *ctx, + css_style **result); css_error parse_border_collapse(css_language *c, const parserutils_vector *vector, int *ctx, css_style **result); +css_error parse_border_left(css_language *c, + const parserutils_vector *vector, int *ctx, + css_style **result); css_error parse_border_left_color(css_language *c, const parserutils_vector *vector, int *ctx, css_style **result); @@ -64,6 +76,9 @@ css_error parse_border_left_style(css_language *c, css_error parse_border_left_width(css_language *c, const parserutils_vector *vector, int *ctx, css_style **result); +css_error parse_border_right(css_language *c, + const parserutils_vector *vector, int *ctx, + css_style **result); css_error parse_border_right_color(css_language *c, const parserutils_vector *vector, int *ctx, css_style **result); @@ -76,6 +91,12 @@ css_error parse_border_right_width(css_language *c, css_error parse_border_spacing(css_language *c, const parserutils_vector *vector, int *ctx, css_style **result); +css_error parse_border_style(css_language *c, + const parserutils_vector *vector, int *ctx, + css_style **result); +css_error parse_border_top(css_language *c, + const parserutils_vector *vector, int *ctx, + css_style **result); css_error parse_border_top_color(css_language *c, const parserutils_vector *vector, int *ctx, css_style **result); @@ -85,6 +106,9 @@ css_error parse_border_top_style(css_language *c, css_error parse_border_top_width(css_language *c, const parserutils_vector *vector, int *ctx, css_style **result); +css_error parse_border_width(css_language *c, + const parserutils_vector *vector, int *ctx, + css_style **result); css_error parse_bottom(css_language *c, const parserutils_vector *vector, int *ctx, css_style **result); @@ -196,6 +220,9 @@ css_error parse_min_width(css_language *c, css_error parse_orphans(css_language *c, const parserutils_vector *vector, int *ctx, css_style **result); +css_error parse_outline(css_language *c, + const parserutils_vector *vector, int *ctx, + css_style **result); css_error parse_outline_color(css_language *c, const parserutils_vector *vector, int *ctx, css_style **result); |