From a8aacc54b11fd1fc9d84c7d85dd058d3f90e7c32 Mon Sep 17 00:00:00 2001 From: John Mark Bell Date: Thu, 25 Jun 2009 01:26:30 +0000 Subject: Border and outline shorthand property parsers svn path=/trunk/libcss/; revision=7956 --- src/parse/properties/border_outline.c | 1182 +++++++++++++++++++++++++++++++++ src/parse/properties/properties.c | 9 + src/parse/properties/properties.h | 27 + src/parse/propstrings.c | 9 + src/parse/propstrings.h | 40 +- 5 files changed, 1248 insertions(+), 19 deletions(-) (limited to 'src/parse') 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 */ +#include #include #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) @@ -302,6 +909,415 @@ css_error parse_border_top_width(css_language *c, CSS_PROP_BORDER_TOP_WIDTH, result); } +/** + * Parse border-width shorthand + * + * \param c Parsing context + * \param vector Vector of tokens to process + * \param ctx Pointer to vector iteration context + * \param result Pointer to location to receive resulting style + * \return CSS_OK on success, + * CSS_NOMEM on memory exhaustion, + * CSS_INVALID if the input is not valid + * + * Post condition: \a *ctx is updated with the next token to process + * If the input is invalid, then \a *ctx remains unchanged. + */ +css_error parse_border_width(css_language *c, + const parserutils_vector *vector, int *ctx, + css_style **result) +{ + int orig_ctx = *ctx; + int prev_ctx; + const css_token *token; + css_style *top = NULL; + css_style *right = NULL; + css_style *bottom = NULL; + css_style *left = NULL; + css_style *ret = NULL; + uint32_t num_sides = 0; + uint32_t required_size; + 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 * @@ -430,6 +1446,172 @@ css_error parse_outline_width(css_language *c, CSS_PROP_OUTLINE_WIDTH, result); } +/** + * Parse border-{top,right,bottom,left} shorthand + * + * \param c Parsing context + * \param vector Vector of tokens to process + * \param ctx Pointer to vector iteration context + * \param side The side we're parsing for + * \param result Pointer to location to receive resulting style + * \return CSS_OK on success, + * CSS_NOMEM on memory exhaustion, + * CSS_INVALID if the input is not valid + * + * Post condition: \a *ctx is updated with the next token to process + * If the input is invalid, then \a *ctx remains unchanged. + */ +css_error parse_border_side(css_language *c, + const parserutils_vector *vector, int *ctx, + uint32_t side, css_style **result) +{ + int orig_ctx = *ctx; + int prev_ctx; + const css_token *token; + css_style *color = NULL; + css_style *style = NULL; + css_style *width = NULL; + css_style *ret = NULL; + uint32_t required_size; + 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 * 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); diff --git a/src/parse/propstrings.c b/src/parse/propstrings.c index 2098b60..fbe2d66 100644 --- a/src/parse/propstrings.c +++ b/src/parse/propstrings.c @@ -49,20 +49,28 @@ const stringmap_entry stringmap[LAST_KNOWN] = { { "background-image", SLEN("background-image") }, { "background-position", SLEN("background-position") }, { "background-repeat", SLEN("background-repeat") }, + { "border", SLEN("border") }, + { "border-bottom", SLEN("border-bottom") }, { "border-bottom-color", SLEN("border-bottom-color") }, { "border-bottom-style", SLEN("border-bottom-style") }, { "border-bottom-width", SLEN("border-bottom-width") }, { "border-collapse", SLEN("border-collapse") }, + { "border-color", SLEN("border-color") }, + { "border-left", SLEN("border-left") }, { "border-left-color", SLEN("border-left-color") }, { "border-left-style", SLEN("border-left-style") }, { "border-left-width", SLEN("border-left-width") }, + { "border-right", SLEN("border-right") }, { "border-right-color", SLEN("border-right-color") }, { "border-right-style", SLEN("border-right-style") }, { "border-right-width", SLEN("border-right-width") }, { "border-spacing", SLEN("border-spacing") }, + { "border-style", SLEN("border-style") }, + { "border-top", SLEN("border-top") }, { "border-top-color", SLEN("border-top-color") }, { "border-top-style", SLEN("border-top-style") }, { "border-top-width", SLEN("border-top-width") }, + { "border-width", SLEN("border-width") }, { "bottom", SLEN("bottom") }, { "caption-side", SLEN("caption-side") }, { "clear", SLEN("clear") }, @@ -100,6 +108,7 @@ const stringmap_entry stringmap[LAST_KNOWN] = { { "min-height", SLEN("min-height") }, { "min-width", SLEN("min-width") }, { "orphans", SLEN("orphans") }, + { "outline", SLEN("outline") }, { "outline-color", SLEN("outline-color") }, { "outline-style", SLEN("outline-style") }, { "outline-width", SLEN("outline-width") }, diff --git a/src/parse/propstrings.h b/src/parse/propstrings.h index 7f25c81..3ea8858 100644 --- a/src/parse/propstrings.h +++ b/src/parse/propstrings.h @@ -33,26 +33,28 @@ enum { AZIMUTH = FIRST_PROP, BACKGROUND, BACKGROUND_ATTACHMENT, BACKGROUND_COLOR, BACKGROUND_IMAGE, BACKGROUND_POSITION, - BACKGROUND_REPEAT, BORDER_BOTTOM_COLOR, BORDER_BOTTOM_STYLE, - BORDER_BOTTOM_WIDTH, BORDER_COLLAPSE, BORDER_LEFT_COLOR, - BORDER_LEFT_STYLE, BORDER_LEFT_WIDTH, BORDER_RIGHT_COLOR, + BACKGROUND_REPEAT, BORDER, BORDER_BOTTOM, BORDER_BOTTOM_COLOR, + BORDER_BOTTOM_STYLE, BORDER_BOTTOM_WIDTH, BORDER_COLLAPSE, + BORDER_COLOR, BORDER_LEFT, BORDER_LEFT_COLOR, BORDER_LEFT_STYLE, + BORDER_LEFT_WIDTH, BORDER_RIGHT, BORDER_RIGHT_COLOR, BORDER_RIGHT_STYLE, BORDER_RIGHT_WIDTH, BORDER_SPACING, - BORDER_TOP_COLOR, BORDER_TOP_STYLE, BORDER_TOP_WIDTH, BOTTOM, - CAPTION_SIDE, CLEAR, CLIP, COLOR, CONTENT, - COUNTER_INCREMENT, COUNTER_RESET, CUE_AFTER, CUE_BEFORE, CURSOR, - DIRECTION, DISPLAY, ELEVATION, EMPTY_CELLS, FLOAT, FONT_FAMILY, - FONT_SIZE, FONT_STYLE, FONT_VARIANT, FONT_WEIGHT, HEIGHT, LEFT, - LETTER_SPACING, LINE_HEIGHT, LIST_STYLE_IMAGE, LIST_STYLE_POSITION, - LIST_STYLE_TYPE, MARGIN_BOTTOM, MARGIN_LEFT, MARGIN_RIGHT, MARGIN_TOP, - MAX_HEIGHT, MAX_WIDTH, MIN_HEIGHT, MIN_WIDTH, ORPHANS, OUTLINE_COLOR, - OUTLINE_STYLE, OUTLINE_WIDTH, OVERFLOW, PADDING_BOTTOM, PADDING_LEFT, - PADDING_RIGHT, PADDING_TOP, PAGE_BREAK_AFTER, PAGE_BREAK_BEFORE, - PAGE_BREAK_INSIDE, PAUSE_AFTER, PAUSE_BEFORE, PITCH_RANGE, PITCH, - PLAY_DURING, POSITION, QUOTES, RICHNESS, RIGHT, SPEAK_HEADER, - SPEAK_NUMERAL, SPEAK_PUNCTUATION, SPEAK, SPEECH_RATE, STRESS, - TABLE_LAYOUT, TEXT_ALIGN, TEXT_DECORATION, TEXT_INDENT, TEXT_TRANSFORM, - TOP, UNICODE_BIDI, VERTICAL_ALIGN, VISIBILITY, VOICE_FAMILY, VOLUME, - WHITE_SPACE, WIDOWS, WIDTH, WORD_SPACING, Z_INDEX, + BORDER_STYLE, BORDER_TOP, BORDER_TOP_COLOR, BORDER_TOP_STYLE, + BORDER_TOP_WIDTH, BORDER_WIDTH, BOTTOM, CAPTION_SIDE, CLEAR, + CLIP, COLOR, CONTENT, COUNTER_INCREMENT, COUNTER_RESET, CUE_AFTER, + CUE_BEFORE, CURSOR, DIRECTION, DISPLAY, ELEVATION, EMPTY_CELLS, FLOAT, + FONT_FAMILY, FONT_SIZE, FONT_STYLE, FONT_VARIANT, FONT_WEIGHT, HEIGHT, + LEFT, LETTER_SPACING, LINE_HEIGHT, LIST_STYLE_IMAGE, + LIST_STYLE_POSITION, LIST_STYLE_TYPE, MARGIN_BOTTOM, MARGIN_LEFT, + MARGIN_RIGHT, MARGIN_TOP, MAX_HEIGHT, MAX_WIDTH, MIN_HEIGHT, MIN_WIDTH, + ORPHANS, OUTLINE, OUTLINE_COLOR, OUTLINE_STYLE, OUTLINE_WIDTH, + OVERFLOW, PADDING_BOTTOM, PADDING_LEFT, PADDING_RIGHT, PADDING_TOP, + PAGE_BREAK_AFTER, PAGE_BREAK_BEFORE, PAGE_BREAK_INSIDE, PAUSE_AFTER, + PAUSE_BEFORE, PITCH_RANGE, PITCH, PLAY_DURING, POSITION, QUOTES, + RICHNESS, RIGHT, SPEAK_HEADER, SPEAK_NUMERAL, SPEAK_PUNCTUATION, SPEAK, + SPEECH_RATE, STRESS, TABLE_LAYOUT, TEXT_ALIGN, TEXT_DECORATION, + TEXT_INDENT, TEXT_TRANSFORM, TOP, UNICODE_BIDI, VERTICAL_ALIGN, + VISIBILITY, VOICE_FAMILY, VOLUME, WHITE_SPACE, WIDOWS, WIDTH, + WORD_SPACING, Z_INDEX, LAST_PROP = Z_INDEX, -- cgit v1.2.3