summaryrefslogtreecommitdiff
path: root/src/parse/properties
diff options
context:
space:
mode:
authorJohn Mark Bell <jmb@netsurf-browser.org>2009-06-25 01:26:30 +0000
committerJohn Mark Bell <jmb@netsurf-browser.org>2009-06-25 01:26:30 +0000
commita8aacc54b11fd1fc9d84c7d85dd058d3f90e7c32 (patch)
tree0dd82a8963180a42e2e446de8a509cc42b5d171e /src/parse/properties
parent60b5130daa08928bcc86f69b018c0466ebdda582 (diff)
downloadlibcss-a8aacc54b11fd1fc9d84c7d85dd058d3f90e7c32.tar.gz
libcss-a8aacc54b11fd1fc9d84c7d85dd058d3f90e7c32.tar.bz2
Border and outline shorthand property parsers
svn path=/trunk/libcss/; revision=7956
Diffstat (limited to 'src/parse/properties')
-rw-r--r--src/parse/properties/border_outline.c1182
-rw-r--r--src/parse/properties/properties.c9
-rw-r--r--src/parse/properties/properties.h27
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);