/* * This file is part of LibCSS. * Licensed under the MIT License, * http://www.opensource.org/licenses/mit-license.php * Copyright 2009 John-Mark Bell */ #include #include #include "bytecode/bytecode.h" #include "bytecode/opcodes.h" #include "parse/properties/properties.h" #include "parse/properties/utils.h" static css_error parse_system_font(css_language *c, css_style *result, css_system_font *system_font) { css_error error; bool match; /* style */ switch (system_font->style) { case CSS_FONT_STYLE_NORMAL: error = css__stylesheet_style_appendOPV(result, CSS_PROP_FONT_STYLE, 0, FONT_STYLE_NORMAL); break; case CSS_FONT_STYLE_ITALIC: error = css__stylesheet_style_appendOPV(result, CSS_PROP_FONT_STYLE, 0, FONT_STYLE_ITALIC); break; case CSS_FONT_STYLE_OBLIQUE: error = css__stylesheet_style_appendOPV(result, CSS_PROP_FONT_STYLE, 0, FONT_STYLE_OBLIQUE); break; default: error = CSS_BADPARM; break; } if (error != CSS_OK) return error; /* variant */ switch (system_font->variant) { case CSS_FONT_VARIANT_NORMAL: error = css__stylesheet_style_appendOPV(result, CSS_PROP_FONT_VARIANT, 0, FONT_VARIANT_NORMAL); break; case CSS_FONT_VARIANT_SMALL_CAPS: error = css__stylesheet_style_appendOPV(result, CSS_PROP_FONT_VARIANT, 0, FONT_VARIANT_SMALL_CAPS); break; default: error = CSS_BADPARM; break; } if (error != CSS_OK) return error; /* weight */ switch(system_font->weight) { case CSS_FONT_WEIGHT_NORMAL: error = css__stylesheet_style_appendOPV(result, CSS_PROP_FONT_WEIGHT, 0, FONT_WEIGHT_NORMAL); break; case CSS_FONT_WEIGHT_BOLD: error = css__stylesheet_style_appendOPV(result, CSS_PROP_FONT_WEIGHT, 0, FONT_WEIGHT_BOLD); break; case CSS_FONT_WEIGHT_BOLDER: error = css__stylesheet_style_appendOPV(result, CSS_PROP_FONT_WEIGHT, 0, FONT_WEIGHT_BOLDER); break; case CSS_FONT_WEIGHT_LIGHTER: error = css__stylesheet_style_appendOPV(result, CSS_PROP_FONT_WEIGHT, 0, FONT_WEIGHT_LIGHTER); break; case CSS_FONT_WEIGHT_100: error = css__stylesheet_style_appendOPV(result, CSS_PROP_FONT_WEIGHT, 0, FONT_WEIGHT_100); break; case CSS_FONT_WEIGHT_200: error = css__stylesheet_style_appendOPV(result, CSS_PROP_FONT_WEIGHT, 0, FONT_WEIGHT_200); break; case CSS_FONT_WEIGHT_300: error = css__stylesheet_style_appendOPV(result, CSS_PROP_FONT_WEIGHT, 0, FONT_WEIGHT_300); break; case CSS_FONT_WEIGHT_400: error = css__stylesheet_style_appendOPV(result, CSS_PROP_FONT_WEIGHT, 0, FONT_WEIGHT_400); break; case CSS_FONT_WEIGHT_500: error = css__stylesheet_style_appendOPV(result, CSS_PROP_FONT_WEIGHT, 0, FONT_WEIGHT_500); break; case CSS_FONT_WEIGHT_600: error = css__stylesheet_style_appendOPV(result, CSS_PROP_FONT_WEIGHT, 0, FONT_WEIGHT_600); break; case CSS_FONT_WEIGHT_700: error = css__stylesheet_style_appendOPV(result, CSS_PROP_FONT_WEIGHT, 0, FONT_WEIGHT_700); break; case CSS_FONT_WEIGHT_800: error = css__stylesheet_style_appendOPV(result, CSS_PROP_FONT_WEIGHT, 0, FONT_WEIGHT_800); break; case CSS_FONT_WEIGHT_900: error = css__stylesheet_style_appendOPV(result, CSS_PROP_FONT_WEIGHT, 0, FONT_WEIGHT_900); break; default: error = CSS_BADPARM; break; } if (error != CSS_OK) return error; /* size */ error = css__stylesheet_style_appendOPV(result, CSS_PROP_FONT_SIZE, 0, FONT_SIZE_DIMENSION); if (error != CSS_OK) return error; error = css__stylesheet_style_vappend(result, 2, system_font->size.size, system_font->size.unit); if (error != CSS_OK) return error; /* line height */ error = css__stylesheet_style_appendOPV(result, CSS_PROP_LINE_HEIGHT, 0, LINE_HEIGHT_DIMENSION); if (error != CSS_OK) return error; error = css__stylesheet_style_vappend(result, 2, system_font->line_height.size, system_font->line_height.unit); if (error != CSS_OK) return error; /* font family */ if ((lwc_string_caseless_isequal(system_font->family, c->strings[SERIF], &match) == lwc_error_ok && match)) error = css__stylesheet_style_appendOPV(result, CSS_PROP_FONT_FAMILY, 0, FONT_FAMILY_SERIF); else if ((lwc_string_caseless_isequal(system_font->family, c->strings[SANS_SERIF], &match) == lwc_error_ok && match)) error = css__stylesheet_style_appendOPV(result, CSS_PROP_FONT_FAMILY, 0, FONT_FAMILY_SANS_SERIF); else if ((lwc_string_caseless_isequal(system_font->family, c->strings[CURSIVE], &match) == lwc_error_ok && match)) error = css__stylesheet_style_appendOPV(result, CSS_PROP_FONT_FAMILY, 0, FONT_FAMILY_CURSIVE); else if ((lwc_string_caseless_isequal(system_font->family, c->strings[FANTASY], &match) == lwc_error_ok && match)) error = css__stylesheet_style_appendOPV(result, CSS_PROP_FONT_FAMILY, 0, FONT_FAMILY_FANTASY); else if ((lwc_string_caseless_isequal(system_font->family, c->strings[MONOSPACE], &match) == lwc_error_ok && match)) error = css__stylesheet_style_appendOPV(result, CSS_PROP_FONT_FAMILY, 0, FONT_FAMILY_MONOSPACE); else { uint32_t snumber; error = css__stylesheet_string_add(c->sheet, lwc_string_ref(system_font->family), &snumber); if (error != CSS_OK) return error; error = css__stylesheet_style_appendOPV(result, CSS_PROP_FONT_FAMILY, 0, FONT_FAMILY_STRING); if (error != CSS_OK) return error; error = css__stylesheet_style_append(result, snumber); } if (error != CSS_OK) return error; error = css__stylesheet_style_append(result, FONT_FAMILY_END); return error; } /** * Parse font * * \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 css__parse_font(css_language *c, const parserutils_vector *vector, int *ctx, css_style *result) { const css_token *token; css_error error; int orig_ctx = *ctx; int prev_ctx; css_system_font system_font; bool style = true; bool variant = true; bool weight = true; bool line_height = true; css_style *style_style; css_style *variant_style; css_style *weight_style; css_style *size_style; css_style *line_height_style; css_style *family_style; int svw; /* Firstly, handle inherit */ token = parserutils_vector_peek(vector, *ctx); if (token == NULL) return CSS_INVALID; if (is_css_inherit(c, token)) { error = css_stylesheet_style_inherit(result, CSS_PROP_FONT_STYLE); if (error != CSS_OK) return error; error = css_stylesheet_style_inherit(result, CSS_PROP_FONT_VARIANT); if (error != CSS_OK) return error; error = css_stylesheet_style_inherit(result, CSS_PROP_FONT_WEIGHT); if (error != CSS_OK) return error; error = css_stylesheet_style_inherit(result, CSS_PROP_FONT_SIZE); if (error != CSS_OK) return error; error = css_stylesheet_style_inherit(result, CSS_PROP_LINE_HEIGHT); if (error != CSS_OK) return error; error = css_stylesheet_style_inherit(result, CSS_PROP_FONT_FAMILY); if (error == CSS_OK) parserutils_vector_iterate(vector, ctx); return error; } /* Perhaps an unknown font name; ask the client */ if ((token->type == CSS_TOKEN_IDENT) && (c->sheet->font != NULL) && (c->sheet->font(c->sheet->font_pw, token->idata, &system_font) == CSS_OK)) { error = parse_system_font(c, result, &system_font); if (error == CSS_OK) parserutils_vector_iterate(vector, ctx); return error; } /* allocate styles */ error = css__stylesheet_style_create(c->sheet, &style_style); if (error != CSS_OK) return error; error = css__stylesheet_style_create(c->sheet, &variant_style); if (error != CSS_OK) { css__stylesheet_style_destroy(style_style); return error; } error = css__stylesheet_style_create(c->sheet, &weight_style); if (error != CSS_OK) { css__stylesheet_style_destroy(style_style); css__stylesheet_style_destroy(variant_style); return error; } error = css__stylesheet_style_create(c->sheet, &size_style); if (error != CSS_OK) { css__stylesheet_style_destroy(style_style); css__stylesheet_style_destroy(variant_style); css__stylesheet_style_destroy(weight_style); return error; } error = css__stylesheet_style_create(c->sheet, &line_height_style); if (error != CSS_OK) { css__stylesheet_style_destroy(style_style); css__stylesheet_style_destroy(variant_style); css__stylesheet_style_destroy(weight_style); css__stylesheet_style_destroy(size_style); return error; } error = css__stylesheet_style_create(c->sheet, &family_style); if (error != CSS_OK) { css__stylesheet_style_destroy(style_style); css__stylesheet_style_destroy(variant_style); css__stylesheet_style_destroy(weight_style); css__stylesheet_style_destroy(size_style); css__stylesheet_style_destroy(line_height_style); return error; } /* Attempt to parse the optional style, variant, and weight */ for (svw = 0; svw < 3; svw++) { prev_ctx = *ctx; error = CSS_OK; /* Ensure that we're not about to parse another inherit */ token = parserutils_vector_peek(vector, *ctx); if ((token != NULL) && is_css_inherit(c, token)) { error = CSS_INVALID; goto css__parse_font_cleanup; } if ((style) && (error = css__parse_font_style(c, vector, ctx, style_style)) == CSS_OK) { style = false; } else if ((variant) && (error = css__parse_font_variant(c, vector, ctx, variant_style)) == CSS_OK) { variant = false; } else if ((weight) && (error = css__parse_font_weight(c, vector, ctx, weight_style)) == CSS_OK) { weight = false; } if (error == CSS_OK) { consumeWhitespace(vector, ctx); } else { break; } if (*ctx == prev_ctx) break; } consumeWhitespace(vector, ctx); /* Ensure that we're not about to parse another inherit */ token = parserutils_vector_peek(vector, *ctx); if ((token != NULL) && is_css_inherit(c, token)) { error = CSS_INVALID; goto css__parse_font_cleanup; } /* Now expect a font-size */ error = css__parse_font_size(c, vector, ctx, size_style); if (error != CSS_OK) goto css__parse_font_cleanup; consumeWhitespace(vector, ctx); /* Potential line-height */ token = parserutils_vector_peek(vector, *ctx); if ((token != NULL) && tokenIsChar(token, '/')) { parserutils_vector_iterate(vector, ctx); consumeWhitespace(vector, ctx); /* Ensure that we're not about to parse another inherit */ token = parserutils_vector_peek(vector, *ctx); if ((token != NULL) && is_css_inherit(c, token)) { error = CSS_INVALID; goto css__parse_font_cleanup; } error = css__parse_line_height(c, vector, ctx, line_height_style); if (error != CSS_OK) goto css__parse_font_cleanup; line_height = false; } consumeWhitespace(vector, ctx); /* Ensure that we're not about to parse another inherit */ token = parserutils_vector_peek(vector, *ctx); if ((token != NULL) && is_css_inherit(c, token)) { error = CSS_INVALID; goto css__parse_font_cleanup; } /* Now expect a font-family */ error = css__parse_font_family(c, vector, ctx, family_style); if (error != CSS_OK) goto css__parse_font_cleanup; /* defaults */ if (style) { error = css__stylesheet_style_appendOPV(style_style, CSS_PROP_FONT_STYLE, 0, FONT_STYLE_NORMAL); if (error != CSS_OK) goto css__parse_font_cleanup; } if (variant) { error = css__stylesheet_style_appendOPV(variant_style, CSS_PROP_FONT_VARIANT, 0, FONT_VARIANT_NORMAL); if (error != CSS_OK) goto css__parse_font_cleanup; } if (weight) { error = css__stylesheet_style_appendOPV(weight_style, CSS_PROP_FONT_WEIGHT, 0, FONT_WEIGHT_NORMAL); if (error != CSS_OK) goto css__parse_font_cleanup; } if (line_height) { error = css__stylesheet_style_appendOPV(line_height_style, CSS_PROP_LINE_HEIGHT, 0, LINE_HEIGHT_NORMAL); if (error != CSS_OK) goto css__parse_font_cleanup; } /* merge final output */ error = css__stylesheet_merge_style(result, style_style); if (error != CSS_OK) goto css__parse_font_cleanup; error = css__stylesheet_merge_style(result, variant_style); if (error != CSS_OK) goto css__parse_font_cleanup; error = css__stylesheet_merge_style(result, weight_style); if (error != CSS_OK) goto css__parse_font_cleanup; error = css__stylesheet_merge_style(result, size_style); if (error != CSS_OK) goto css__parse_font_cleanup; error = css__stylesheet_merge_style(result, line_height_style); if (error != CSS_OK) goto css__parse_font_cleanup; error = css__stylesheet_merge_style(result, family_style); css__parse_font_cleanup: css__stylesheet_style_destroy(style_style); css__stylesheet_style_destroy(variant_style); css__stylesheet_style_destroy(weight_style); css__stylesheet_style_destroy(size_style); css__stylesheet_style_destroy(line_height_style); css__stylesheet_style_destroy(family_style); if (error != CSS_OK) *ctx = orig_ctx; return error; }