1
0
mirror of https://github.com/rkd77/elinks.git synced 2024-11-04 08:17:17 -05:00
elinks/src/document/css/value.c

328 lines
7.8 KiB
C
Raw Normal View History

/* CSS property value parser */
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include <stdlib.h>
#include <string.h>
#include "elinks.h"
#include "document/css/property.h"
#include "document/css/scanner.h"
#include "document/css/value.h"
#include "document/html/parser.h"
#include "util/color.h"
#include "util/error.h"
#include "util/memory.h"
#include "util/string.h"
int
css_parse_color_value(struct css_property_info *propinfo,
union css_property_value *value,
struct scanner *scanner)
{
struct scanner_token *token = get_scanner_token(scanner);
assert(propinfo->value_type == CSS_VT_COLOR);
if (token->type == CSS_TOKEN_RGB) {
/* RGB function */
int shift;
token = get_next_scanner_token(scanner);
/* First color component is shifted 16, next is shifted 8 and
* last is not shifted. */
for (shift = 16; token && shift >= 0; shift -= 8) {
/* The first two args are terminated by ',' and the
* last one by ')'. */
unsigned char paskynator = shift ? ',' : ')';
unsigned char *nstring = token->string;
int part;
/* Are the current and next token valid? */
if ((token->type != CSS_TOKEN_NUMBER
&& token->type != CSS_TOKEN_PERCENTAGE)
|| !check_next_scanner_token(scanner, paskynator))
return 0;
/* Parse the digit */
part = strtol(token->string, (char **) &nstring, 10);
if (token->string == nstring)
return 0;
/* Adjust percentage values */
if (token->type == CSS_TOKEN_PERCENTAGE) {
int_bounds(&part, 0, 100);
part *= 255;
part /= 100;
}
/* Adjust color component value and add it */
int_bounds(&part, 0, 255);
value->color |= part << shift;
/* Paskynate the token arg and separator */
token = skip_css_tokens(scanner, paskynator);
}
return 1;
}
/* Just a color value we already know how to parse. */
if (token->type != CSS_TOKEN_IDENT
&& token->type != CSS_TOKEN_HEX_COLOR)
return 0;
if (decode_color(token->string, token->length, &value->color) < 0) {
return 0;
}
skip_css_tokens(scanner, token->type);
return 1;
}
int
css_parse_background_value(struct css_property_info *propinfo,
union css_property_value *value,
struct scanner *scanner)
{
int success = 0;
assert(propinfo->value_type == CSS_VT_COLOR);
/* This is pretty naive, we just jump space by space, trying to parse
* each token as a color. */
while (scanner_has_tokens(scanner)) {
struct scanner_token *token = get_scanner_token(scanner);
if (!check_css_precedence(token->type, ';'))
break;
if (token->type == ','
|| !css_parse_color_value(propinfo, value, scanner)) {
skip_scanner_token(scanner);
continue;
}
success++;
}
return success;
}
int
css_parse_font_style_value(struct css_property_info *propinfo,
union css_property_value *value,
struct scanner *scanner)
{
struct scanner_token *token = get_scanner_token(scanner);
assert(propinfo->value_type == CSS_VT_FONT_ATTRIBUTE);
if (token->type != CSS_TOKEN_IDENT) return 0;
if (scanner_token_contains(token, "italic")
|| scanner_token_contains(token, "oblique")) {
value->font_attribute.add |= AT_ITALIC;
} else if (scanner_token_contains(token, "underline")) {
value->font_attribute.add |= AT_UNDERLINE;
} else if (scanner_token_contains(token, "normal")) {
value->font_attribute.rem |= AT_ITALIC;
} else {
return 0;
}
skip_css_tokens(scanner, CSS_TOKEN_IDENT);
return 1;
}
int
css_parse_font_weight_value(struct css_property_info *propinfo,
union css_property_value *value,
struct scanner *scanner)
{
struct scanner_token *token = get_scanner_token(scanner);
unsigned char *nstring;
int weight;
assert(propinfo->value_type == CSS_VT_FONT_ATTRIBUTE);
if (token->type == CSS_TOKEN_IDENT) {
if (scanner_token_contains(token, "bolder")) {
value->font_attribute.add |= AT_BOLD;
} else if (scanner_token_contains(token, "lighter")) {
value->font_attribute.rem |= AT_BOLD;
} else if (scanner_token_contains(token, "bold")) {
value->font_attribute.add |= AT_BOLD;
} else if (scanner_token_contains(token, "normal")) {
value->font_attribute.rem |= AT_BOLD;
} else {
return 0;
}
skip_css_tokens(scanner, CSS_TOKEN_IDENT);
return 1;
}
if (token->type != CSS_TOKEN_NUMBER) return 0;
/* TODO: Comma separated list of weights?! */
weight = strtol(token->string, (char **) &nstring, 10);
if (token->string == nstring) return 0;
skip_css_tokens(scanner, CSS_TOKEN_NUMBER);
/* The font weight(s) have values between 100 to 900. These
* values form an ordered sequence, where each number indicates
* a weight that is at least as dark as its predecessor.
*
* normal -> Same as '400'. bold Same as '700'.
*/
int_bounds(&weight, 100, 900);
if (weight >= 700) value->font_attribute.add |= AT_BOLD;
return 1;
}
int
css_parse_text_align_value(struct css_property_info *propinfo,
union css_property_value *value,
struct scanner *scanner)
{
struct scanner_token *token = get_scanner_token(scanner);
assert(propinfo->value_type == CSS_VT_TEXT_ALIGN);
if (token->type != CSS_TOKEN_IDENT) return 0;
if (scanner_token_contains(token, "left")) {
value->text_align = ALIGN_LEFT;
} else if (scanner_token_contains(token, "right")) {
value->text_align = ALIGN_RIGHT;
} else if (scanner_token_contains(token, "center")) {
value->text_align = ALIGN_CENTER;
} else if (scanner_token_contains(token, "justify")) {
value->text_align = ALIGN_JUSTIFY;
} else {
return 0;
}
skip_css_tokens(scanner, CSS_TOKEN_IDENT);
return 1;
}
int
css_parse_text_decoration_value(struct css_property_info *propinfo,
union css_property_value *value,
struct scanner *scanner)
{
struct scanner_token *token = get_scanner_token(scanner);
assert(propinfo->value_type == CSS_VT_FONT_ATTRIBUTE);
if (token->type != CSS_TOKEN_IDENT) return 0;
/* TODO: It is possible to have multiple values here,
* 'background'-style. --pasky */
if (scanner_token_contains(token, "underline")) {
value->font_attribute.add |= AT_UNDERLINE;
} else if (scanner_token_contains(token, "none")) {
value->font_attribute.rem |= AT_UNDERLINE;
} else {
return 0;
}
skip_css_tokens(scanner, CSS_TOKEN_IDENT);
return 1;
}
int
css_parse_white_space_value(struct css_property_info *propinfo,
union css_property_value *value,
struct scanner *scanner)
{
struct scanner_token *token = get_scanner_token(scanner);
assert(propinfo->value_type == CSS_VT_FONT_ATTRIBUTE);
if (token->type != CSS_TOKEN_IDENT) return 0;
/* FIXME: nowrap */
if (scanner_token_contains(token, "pre")) {
value->font_attribute.add |= AT_PREFORMATTED;
} else if (scanner_token_contains(token, "normal")) {
value->font_attribute.rem |= AT_PREFORMATTED;
} else {
return 0;
}
skip_css_tokens(scanner, CSS_TOKEN_IDENT);
return 1;
}
int
css_parse_display_value(struct css_property_info *propinfo,
union css_property_value *value,
struct scanner *scanner)
{
struct scanner_token *token = get_scanner_token(scanner);
assert(propinfo->value_type == CSS_VT_DISPLAY);
if (token->type != CSS_TOKEN_IDENT) return 0;
/* FIXME: This is _very_ simplistic */
if (scanner_token_contains(token, "inline")) {
value->display = CSS_DISP_INLINE;
} else if (scanner_token_contains(token, "inline-block")) {
value->display = CSS_DISP_INLINE; /* XXX */
} else if (scanner_token_contains(token, "block")) {
value->display = CSS_DISP_BLOCK;
} else {
return 0;
}
skip_css_tokens(scanner, CSS_TOKEN_IDENT);
return 1;
}
int
css_parse_value(struct css_property_info *propinfo,
union css_property_value *value,
struct scanner *scanner)
{
struct scanner_token *token;
assert(scanner && value && propinfo);
assert(propinfo->parser);
/* Check that we actually have some token to pass on */
token = get_scanner_token(scanner);
if (!token) return 0;
return propinfo->parser(propinfo, value, scanner);
}