From fc09dd686bd7b131f7ee743a392900bf3f741498 Mon Sep 17 00:00:00 2001 From: John Mark Bell Date: Thu, 25 Jun 2009 18:24:26 +0000 Subject: Documentation and context restoration on error. Make font-family parser use generic comma-separated list parser svn path=/trunk/libcss/; revision=7985 --- src/parse/properties/font.c | 496 +++++++++++++++++--------------------------- 1 file changed, 196 insertions(+), 300 deletions(-) (limited to 'src/parse') diff --git a/src/parse/properties/font.c b/src/parse/properties/font.c index 17cac76..e964cba 100644 --- a/src/parse/properties/font.c +++ b/src/parse/properties/font.c @@ -12,10 +12,72 @@ #include "parse/properties/properties.h" #include "parse/properties/utils.h" +/** + * Determine if a given font-family ident is reserved + * + * \param c Parsing context + * \param ident IDENT to consider + * \return True if IDENT is reserved, false otherwise + */ +static bool font_family_reserved(css_language *c, const css_token *ident) +{ + return ident->ilower == c->strings[SERIF] || + ident->ilower == c->strings[SANS_SERIF] || + ident->ilower == c->strings[CURSIVE] || + ident->ilower == c->strings[FANTASY] || + ident->ilower == c->strings[MONOSPACE]; +} + +/** + * Convert a font-family token into a bytecode value + * + * \param c Parsing context + * \param token Token to consider + * \return Bytecode value + */ +static uint16_t font_family_value(css_language *c, const css_token *token) +{ + uint16_t value; + + if (token->type == CSS_TOKEN_IDENT) { + if (token->ilower == c->strings[SERIF]) + value = FONT_FAMILY_SERIF; + else if (token->ilower == c->strings[SANS_SERIF]) + value = FONT_FAMILY_SANS_SERIF; + else if (token->ilower == c->strings[CURSIVE]) + value = FONT_FAMILY_CURSIVE; + else if (token->ilower == c->strings[FANTASY]) + value = FONT_FAMILY_FANTASY; + else if (token->ilower == c->strings[MONOSPACE]) + value = FONT_FAMILY_MONOSPACE; + else + value = FONT_FAMILY_IDENT_LIST; + } else { + value = FONT_FAMILY_STRING; + } + + return value; +} + +/** + * Parse font-family + * + * \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_font_family(css_language *c, const parserutils_vector *vector, int *ctx, css_style **result) { + int orig_ctx = *ctx; css_error error; const css_token *token; uint8_t flags = 0; @@ -37,129 +99,37 @@ css_error parse_font_family(css_language *c, /* Pass 1: validate input and calculate space */ token = parserutils_vector_iterate(vector, &temp_ctx); if (token == NULL || (token->type != CSS_TOKEN_IDENT && - token->type != CSS_TOKEN_STRING)) + token->type != CSS_TOKEN_STRING)) { + *ctx = orig_ctx; return CSS_INVALID; + } if (token->type == CSS_TOKEN_IDENT && token->ilower == c->strings[INHERIT]) { flags = FLAG_INHERIT; } else { - bool first = true; - - while (token != NULL) { - if (token->type == CSS_TOKEN_IDENT) { - if (first == false) { - required_size += sizeof(opv); - } - - if (token->ilower == c->strings[SERIF]) { - if (first) { - value = FONT_FAMILY_SERIF; - } - } else if (token->ilower == - c->strings[SANS_SERIF]) { - if (first) { - value = FONT_FAMILY_SANS_SERIF; - } - } else if (token->ilower == - c->strings[CURSIVE]) { - if (first) { - value = FONT_FAMILY_CURSIVE; - } - } else if (token->ilower == - c->strings[FANTASY]) { - if (first) { - value = FONT_FAMILY_FANTASY; - } - } else if (token->ilower == - c->strings[MONOSPACE]) { - if (first) { - value = FONT_FAMILY_MONOSPACE; - } - } else { - if (first) { - value = FONT_FAMILY_IDENT_LIST; - } - - required_size += - sizeof(lwc_string *); - - /* Skip past [ IDENT* S* ]* */ - while (token != NULL) { - token = parserutils_vector_peek( - vector, - temp_ctx); - if (token == NULL || - (token->type != - CSS_TOKEN_IDENT && - token->type != - CSS_TOKEN_S)) { - break; - } - - /* idents must not match - * generic families */ - if (token->type == CSS_TOKEN_IDENT && - (token->ilower == c->strings[SERIF] || - token->ilower == c->strings[SANS_SERIF] || - token->ilower == c->strings[CURSIVE] || - token->ilower == c->strings[FANTASY] || - token->ilower == c->strings[MONOSPACE])) - return CSS_INVALID; - token = parserutils_vector_iterate( - vector, &temp_ctx); - } - } - } else if (token->type == CSS_TOKEN_STRING) { - if (first == false) { - required_size += sizeof(opv); - } else { - value = FONT_FAMILY_STRING; - } - - required_size += - sizeof(lwc_string *); - } else { - return CSS_INVALID; - } - - consumeWhitespace(vector, &temp_ctx); - - token = parserutils_vector_peek(vector, temp_ctx); - if (token != NULL && tokenIsChar(token, ',') == false && - tokenIsChar(token, '!') == false) { - return CSS_INVALID; - } - - if (token != NULL && tokenIsChar(token, ',')) { - parserutils_vector_iterate(vector, &temp_ctx); - - consumeWhitespace(vector, &temp_ctx); - - token = parserutils_vector_peek(vector, - temp_ctx); - if (token == NULL || tokenIsChar(token, '!')) - return CSS_INVALID; - } - - first = false; - - token = parserutils_vector_peek(vector, temp_ctx); - if (token != NULL && tokenIsChar(token, '!')) - break; - - token = parserutils_vector_iterate(vector, &temp_ctx); + uint32_t list_size; + + value = font_family_value(c, token); + + error = comma_list_length(c, vector, &temp_ctx, + token, font_family_reserved, &list_size); + if (error != CSS_OK) { + *ctx = orig_ctx; + return error; } - required_size += sizeof(opv); + required_size += list_size; } opv = buildOPV(CSS_PROP_FONT_FAMILY, flags, value); /* Allocate result */ error = css_stylesheet_style_create(c->sheet, required_size, result); - if (error != CSS_OK) + if (error != CSS_OK) { + *ctx = orig_ctx; return error; + } /* Copy OPV to bytecode */ ptr = (*result)->bytecode; @@ -172,6 +142,7 @@ css_error parse_font_family(css_language *c, token->type != CSS_TOKEN_STRING)) { css_stylesheet_style_destroy(c->sheet, *result); *result = NULL; + *ctx = orig_ctx; return CSS_INVALID; } @@ -179,181 +150,14 @@ css_error parse_font_family(css_language *c, token->ilower == c->strings[INHERIT]) { /* Nothing to do */ } else { - bool first = true; - - while (token != NULL) { - if (token->type == CSS_TOKEN_IDENT) { - lwc_string *tok_idata = token->idata; - lwc_string *name = tok_idata; - lwc_string *newname; - - if (token->ilower == c->strings[SERIF]) { - opv = FONT_FAMILY_SERIF; - } else if (token->ilower == - c->strings[SANS_SERIF]) { - opv = FONT_FAMILY_SANS_SERIF; - } else if (token->ilower == - c->strings[CURSIVE]) { - opv = FONT_FAMILY_CURSIVE; - } else if (token->ilower == - c->strings[FANTASY]) { - opv = FONT_FAMILY_FANTASY; - } else if (token->ilower == - c->strings[MONOSPACE]) { - opv = FONT_FAMILY_MONOSPACE; - } else { - uint16_t len = lwc_string_length(token->idata); - const css_token *temp_token = token; - lwc_error lerror; - uint8_t *buf; - uint8_t *p; - - temp_ctx = *ctx; - - opv = FONT_FAMILY_IDENT_LIST; - - /* Build string from idents */ - while (temp_token != NULL) { - temp_token = parserutils_vector_peek( - vector, temp_ctx); - if (temp_token == NULL || - (temp_token->type != - CSS_TOKEN_IDENT && - temp_token->type != - CSS_TOKEN_S)) { - break; - } - - if (temp_token->type == - CSS_TOKEN_IDENT) { - len += lwc_string_length(temp_token->idata); - } else { - len += 1; - } - - temp_token = parserutils_vector_iterate( - vector, &temp_ctx); - } - - /** \todo Don't use alloca */ - buf = alloca(len); - p = buf; - - memcpy(p, lwc_string_data(token->idata), lwc_string_length(token->idata)); - p += lwc_string_length(token->idata); - - while (token != NULL) { - token = parserutils_vector_peek( - vector, *ctx); - if (token == NULL || - (token->type != - CSS_TOKEN_IDENT && - token->type != - CSS_TOKEN_S)) { - break; - } - - if (token->type == - CSS_TOKEN_IDENT) { - memcpy(p, - lwc_string_data(token->idata), - lwc_string_length(token->idata)); - p += lwc_string_length(token->idata); - } else { - *p++ = ' '; - } - - token = parserutils_vector_iterate( - vector, ctx); - } - - /* Strip trailing whitespace */ - while (p > buf && p[-1] == ' ') - p--; - - /* Insert into hash, if it's different - * from the name we already have */ - - lerror = lwc_context_intern(c->sheet->dictionary, - (char *)buf, len, &newname); - if (lerror != lwc_error_ok) { - css_stylesheet_style_destroy(c->sheet, *result); - *result = NULL; - return css_error_from_lwc_error(lerror); - } - - if (newname == name) - lwc_context_string_unref(c->sheet->dictionary, - newname); - - name = newname; - - } - - if (first == false) { - memcpy(ptr, &opv, sizeof(opv)); - ptr += sizeof(opv); - } - - if (opv == FONT_FAMILY_IDENT_LIST) { - /* Only ref 'name' again if the token owns it, - * otherwise we already own the only ref to the - * new name generated above. - */ - if (name == tok_idata) - lwc_context_string_ref(c->sheet->dictionary, name); - memcpy(ptr, &name, sizeof(name)); - ptr += sizeof(name); - } - } else if (token->type == CSS_TOKEN_STRING) { - opv = FONT_FAMILY_STRING; - - if (first == false) { - memcpy(ptr, &opv, sizeof(opv)); - ptr += sizeof(opv); - } - - lwc_context_string_ref(c->sheet->dictionary, token->idata); - memcpy(ptr, &token->idata, - sizeof(token->idata)); - ptr += sizeof(token->idata); - } else { - css_stylesheet_style_destroy(c->sheet, *result); - *result = NULL; - return CSS_INVALID; - } - - consumeWhitespace(vector, ctx); - - token = parserutils_vector_peek(vector, *ctx); - if (token != NULL && tokenIsChar(token, ',') == false && - tokenIsChar(token, '!') == false) { - css_stylesheet_style_destroy(c->sheet, *result); - *result = NULL; - return CSS_INVALID; - } - - if (token != NULL && tokenIsChar(token, ',')) { - parserutils_vector_iterate(vector, ctx); - - consumeWhitespace(vector, ctx); - - token = parserutils_vector_peek(vector, *ctx); - if (token == NULL || tokenIsChar(token, '!')) { - css_stylesheet_style_destroy(c->sheet, - *result); - *result = NULL; - return CSS_INVALID; - } - } - - first = false; - - token = parserutils_vector_peek(vector, *ctx); - if (token != NULL && tokenIsChar(token, '!')) - break; - - token = parserutils_vector_iterate(vector, ctx); + error = comma_list_to_bytecode(c, vector, ctx, token, + font_family_reserved, font_family_value, + &ptr); + if (error != CSS_OK) { + css_stylesheet_style_destroy(c->sheet, *result); + *result = NULL; + *ctx = orig_ctx; + return error; } /* Write terminator */ @@ -365,10 +169,25 @@ css_error parse_font_family(css_language *c, return CSS_OK; } +/** + * Parse font-size + * + * \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_font_size(css_language *c, const parserutils_vector *vector, int *ctx, css_style **result) { + int orig_ctx = *ctx; css_error error; const css_token *token; uint8_t flags = 0; @@ -381,8 +200,10 @@ css_error parse_font_size(css_language *c, /* length | percentage | IDENT(xx-small, x-small, small, medium, * large, x-large, xx-large, larger, smaller, inherit) */ token = parserutils_vector_peek(vector, *ctx); - if (token == NULL) + if (token == NULL) { + *ctx = orig_ctx; return CSS_INVALID; + } if (token->type == CSS_TOKEN_IDENT && token->ilower == c->strings[INHERIT]) { @@ -427,15 +248,21 @@ css_error parse_font_size(css_language *c, } else { error = parse_unit_specifier(c, vector, ctx, UNIT_PX, &length, &unit); - if (error != CSS_OK) + if (error != CSS_OK) { + *ctx = orig_ctx; return error; + } - if (unit & UNIT_ANGLE || unit & UNIT_TIME || unit & UNIT_FREQ) + if (unit & UNIT_ANGLE || unit & UNIT_TIME || unit & UNIT_FREQ) { + *ctx = orig_ctx; return CSS_INVALID; + } /* Negative values are not permitted */ - if (length < 0) + if (length < 0) { + *ctx = orig_ctx; return CSS_INVALID; + } value = FONT_SIZE_DIMENSION; } @@ -448,8 +275,10 @@ css_error parse_font_size(css_language *c, /* Allocate result */ error = css_stylesheet_style_create(c->sheet, required_size, result); - if (error != CSS_OK) + if (error != CSS_OK) { + *ctx = orig_ctx; return error; + } /* Copy the bytecode to it */ memcpy((*result)->bytecode, &opv, sizeof(opv)); @@ -463,10 +292,25 @@ css_error parse_font_size(css_language *c, return CSS_OK; } +/** + * Parse font-style + * + * \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_font_style(css_language *c, const parserutils_vector *vector, int *ctx, css_style **result) { + int orig_ctx = *ctx; css_error error; const css_token *ident; uint8_t flags = 0; @@ -475,8 +319,10 @@ css_error parse_font_style(css_language *c, /* IDENT (normal, italic, oblique, inherit) */ ident = parserutils_vector_iterate(vector, ctx); - if (ident == NULL || ident->type != CSS_TOKEN_IDENT) + if (ident == NULL || ident->type != CSS_TOKEN_IDENT) { + *ctx = orig_ctx; return CSS_INVALID; + } if (ident->ilower == c->strings[INHERIT]) { flags |= FLAG_INHERIT; @@ -486,15 +332,19 @@ css_error parse_font_style(css_language *c, value = FONT_STYLE_ITALIC; } else if (ident->ilower == c->strings[OBLIQUE]) { value = FONT_STYLE_OBLIQUE; - } else + } else { + *ctx = orig_ctx; return CSS_INVALID; + } opv = buildOPV(CSS_PROP_FONT_STYLE, flags, value); /* Allocate result */ error = css_stylesheet_style_create(c->sheet, sizeof(opv), result); - if (error != CSS_OK) + if (error != CSS_OK) { + *ctx = orig_ctx; return error; + } /* Copy the bytecode to it */ memcpy((*result)->bytecode, &opv, sizeof(opv)); @@ -502,10 +352,25 @@ css_error parse_font_style(css_language *c, return CSS_OK; } +/** + * Parse font-variant + * + * \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_font_variant(css_language *c, const parserutils_vector *vector, int *ctx, css_style **result) { + int orig_ctx = *ctx; css_error error; const css_token *ident; uint8_t flags = 0; @@ -514,8 +379,10 @@ css_error parse_font_variant(css_language *c, /* IDENT (normal, small-caps, inherit) */ ident = parserutils_vector_iterate(vector, ctx); - if (ident == NULL || ident->type != CSS_TOKEN_IDENT) + if (ident == NULL || ident->type != CSS_TOKEN_IDENT) { + *ctx = orig_ctx; return CSS_INVALID; + } if (ident->ilower == c->strings[INHERIT]) { flags |= FLAG_INHERIT; @@ -523,15 +390,19 @@ css_error parse_font_variant(css_language *c, value = FONT_VARIANT_NORMAL; } else if (ident->ilower == c->strings[SMALL_CAPS]) { value = FONT_VARIANT_SMALL_CAPS; - } else + } else { + *ctx = orig_ctx; return CSS_INVALID; + } opv = buildOPV(CSS_PROP_FONT_VARIANT, flags, value); /* Allocate result */ error = css_stylesheet_style_create(c->sheet, sizeof(opv), result); - if (error != CSS_OK) + if (error != CSS_OK) { + *ctx = orig_ctx; return error; + } /* Copy the bytecode to it */ memcpy((*result)->bytecode, &opv, sizeof(opv)); @@ -539,10 +410,25 @@ css_error parse_font_variant(css_language *c, return CSS_OK; } +/** + * Parse font-weight + * + * \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_font_weight(css_language *c, const parserutils_vector *vector, int *ctx, css_style **result) { + int orig_ctx = *ctx; css_error error; const css_token *token; uint8_t flags = 0; @@ -553,17 +439,23 @@ css_error parse_font_weight(css_language *c, * IDENT (normal, bold, bolder, lighter, inherit) */ token = parserutils_vector_iterate(vector, ctx); if (token == NULL || (token->type != CSS_TOKEN_IDENT && - token->type != CSS_TOKEN_NUMBER)) + token->type != CSS_TOKEN_NUMBER)) { + *ctx = orig_ctx; return CSS_INVALID; + } if (token->ilower == c->strings[INHERIT]) { flags |= FLAG_INHERIT; } else if (token->type == CSS_TOKEN_NUMBER) { size_t consumed = 0; - css_fixed num = number_from_lwc_string(token->ilower, true, &consumed); + css_fixed num = number_from_lwc_string(token->ilower, + true, &consumed); /* Invalid if there are trailing characters */ - if (consumed != lwc_string_length(token->ilower)) + if (consumed != lwc_string_length(token->ilower)) { + *ctx = orig_ctx; return CSS_INVALID; + } + switch (FIXTOINT(num)) { case 100: value = FONT_WEIGHT_100; break; case 200: value = FONT_WEIGHT_200; break; @@ -574,7 +466,7 @@ css_error parse_font_weight(css_language *c, case 700: value = FONT_WEIGHT_700; break; case 800: value = FONT_WEIGHT_800; break; case 900: value = FONT_WEIGHT_900; break; - default: return CSS_INVALID; + default: *ctx = orig_ctx; return CSS_INVALID; } } else if (token->ilower == c->strings[NORMAL]) { value = FONT_WEIGHT_NORMAL; @@ -584,15 +476,19 @@ css_error parse_font_weight(css_language *c, value = FONT_WEIGHT_BOLDER; } else if (token->ilower == c->strings[LIGHTER]) { value = FONT_WEIGHT_LIGHTER; - } else + } else { + *ctx = orig_ctx; return CSS_INVALID; + } opv = buildOPV(CSS_PROP_FONT_WEIGHT, flags, value); /* Allocate result */ error = css_stylesheet_style_create(c->sheet, sizeof(opv), result); - if (error != CSS_OK) + if (error != CSS_OK) { + *ctx = orig_ctx; return error; + } /* Copy the bytecode to it */ memcpy((*result)->bytecode, &opv, sizeof(opv)); -- cgit v1.2.3