From 26bd729fd03c23e7b7c945f21b98cf43007d246e Mon Sep 17 00:00:00 2001 From: John Mark Bell Date: Thu, 25 Jun 2009 23:11:39 +0000 Subject: Margin shorthand parser svn path=/trunk/libcss/; revision=7997 --- src/parse/properties/margin.c | 236 ++++++++++++++++++++++++++++++++++++++ src/parse/properties/properties.c | 1 + src/parse/properties/properties.h | 3 + 3 files changed, 240 insertions(+) (limited to 'src/parse/properties') diff --git a/src/parse/properties/margin.c b/src/parse/properties/margin.c index 7ab185c..76147f1 100644 --- a/src/parse/properties/margin.c +++ b/src/parse/properties/margin.c @@ -5,6 +5,7 @@ * Copyright 2009 John-Mark Bell */ +#include #include #include "bytecode/bytecode.h" @@ -16,6 +17,241 @@ static css_error parse_margin_side(css_language *c, const parserutils_vector *vector, int *ctx, uint16_t op, css_style **result); +/** + * Parse margin 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_margin(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_MARGIN_TOP, + FLAG_INHERIT, 0); + *(bytecode++) = buildOPV(CSS_PROP_MARGIN_RIGHT, + FLAG_INHERIT, 0); + *(bytecode++) = buildOPV(CSS_PROP_MARGIN_BOTTOM, + FLAG_INHERIT, 0); + *(bytecode++) = buildOPV(CSS_PROP_MARGIN_LEFT, + 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_margin_side(c, vector, ctx, + CSS_PROP_MARGIN_TOP, &top)) == CSS_OK) { + num_sides = 1; + } else if (right == NULL && + (error = parse_margin_side(c, vector, ctx, + CSS_PROP_MARGIN_RIGHT, &right)) == CSS_OK) { + num_sides = 2; + } else if (bottom == NULL && + (error = parse_margin_side(c, vector, ctx, + CSS_PROP_MARGIN_BOTTOM, &bottom)) == CSS_OK) { + num_sides = 3; + } else if (left == NULL && + (error = parse_margin_side(c, vector, ctx, + CSS_PROP_MARGIN_LEFT, &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_MARGIN_RIGHT, flags, value); + memcpy(((uint8_t *) ret->bytecode) + required_size, + top->bytecode, top->length); + required_size += top->length; + + *opv = buildOPV(CSS_PROP_MARGIN_BOTTOM, flags, value); + memcpy(((uint8_t *) ret->bytecode) + required_size, + top->bytecode, top->length); + required_size += top->length; + + *opv = buildOPV(CSS_PROP_MARGIN_LEFT, 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_MARGIN_BOTTOM, vflags, vvalue); + memcpy(((uint8_t *) ret->bytecode) + required_size, + top->bytecode, top->length); + required_size += top->length; + + *hopv = buildOPV(CSS_PROP_MARGIN_LEFT, 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_MARGIN_LEFT, 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 margin-bottom * diff --git a/src/parse/properties/properties.c b/src/parse/properties/properties.c index 0fd5747..28b92b7 100644 --- a/src/parse/properties/properties.c +++ b/src/parse/properties/properties.c @@ -72,6 +72,7 @@ const css_prop_handler property_handlers[LAST_PROP + 1 - FIRST_PROP] = parse_list_style_image, parse_list_style_position, parse_list_style_type, + parse_margin, parse_margin_bottom, parse_margin_left, parse_margin_right, diff --git a/src/parse/properties/properties.h b/src/parse/properties/properties.h index 976766d..7c7268a 100644 --- a/src/parse/properties/properties.h +++ b/src/parse/properties/properties.h @@ -202,6 +202,9 @@ css_error parse_list_style_position(css_language *c, css_error parse_list_style_type(css_language *c, const parserutils_vector *vector, int *ctx, css_style **result); +css_error parse_margin(css_language *c, + const parserutils_vector *vector, int *ctx, + css_style **result); css_error parse_margin_bottom(css_language *c, const parserutils_vector *vector, int *ctx, css_style **result); -- cgit v1.2.3