/*
* This file is part of LibCSS.
* Licensed under the MIT License,
* http://www.opensource.org/licenses/mit-license.php
* Copyright 2009 John-Mark Bell <jmb@netsurf-browser.org>
*/
#include <assert.h>
#include <string.h>
#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;
}