Add simple support for the display CSS property
[elinks/images.git] / src / document / css / value.c
blobbd186edaa63d92de53e520b947702f25606f91bf
1 /* CSS property value parser */
2 /* $Id: value.c,v 1.55 2004/06/30 06:00:11 jonas Exp $ */
4 #ifdef HAVE_CONFIG_H
5 #include "config.h"
6 #endif
8 #include <stdlib.h>
9 #include <string.h>
11 #include "elinks.h"
13 #include "document/css/property.h"
14 #include "document/css/scanner.h"
15 #include "document/css/value.h"
16 #include "document/html/parser.h"
17 #include "util/color.h"
18 #include "util/error.h"
19 #include "util/memory.h"
20 #include "util/string.h"
23 int
24 css_parse_color_value(struct css_property_info *propinfo,
25 union css_property_value *value,
26 struct scanner *scanner)
28 struct scanner_token *token = get_scanner_token(scanner);
30 assert(propinfo->value_type == CSS_VT_COLOR);
32 if (token->type == CSS_TOKEN_RGB) {
33 /* RGB function */
34 int shift;
36 token = get_next_scanner_token(scanner);
38 /* First color component is shifted 16, next is shifted 8 and
39 * last is not shifted. */
40 for (shift = 16; token && shift >= 0; shift -= 8) {
41 /* The first two args are terminated by ',' and the
42 * last one by ')'. */
43 unsigned char paskynator = shift ? ',' : ')';
44 unsigned char *nstring = token->string;
45 int part;
47 /* Are the current and next token valid? */
48 if ((token->type != CSS_TOKEN_NUMBER
49 && token->type != CSS_TOKEN_PERCENTAGE)
50 || !check_next_scanner_token(scanner, paskynator))
51 return 0;
53 /* Parse the digit */
54 part = strtol(token->string, (char **) &nstring, 10);
55 if (token->string == nstring)
56 return 0;
58 /* Adjust percentage values */
59 if (token->type == CSS_TOKEN_PERCENTAGE) {
60 int_bounds(&part, 0, 100);
61 part *= 255;
62 part /= 100;
65 /* Adjust color component value and add it */
66 int_bounds(&part, 0, 255);
67 value->color |= part << shift;
69 /* Paskynate the token arg and separator */
70 token = skip_css_tokens(scanner, paskynator);
73 return 1;
76 /* Just a color value we already know how to parse. */
77 if (token->type != CSS_TOKEN_IDENT
78 && token->type != CSS_TOKEN_HEX_COLOR)
79 return 0;
81 if (decode_color(token->string, token->length, &value->color) < 0) {
82 return 0;
85 skip_css_tokens(scanner, token->type);
86 return 1;
89 int
90 css_parse_background_value(struct css_property_info *propinfo,
91 union css_property_value *value,
92 struct scanner *scanner)
94 int success = 0;
96 assert(propinfo->value_type == CSS_VT_COLOR);
98 /* This is pretty naive, we just jump space by space, trying to parse
99 * each token as a color. */
101 while (scanner_has_tokens(scanner)) {
102 struct scanner_token *token = get_scanner_token(scanner);
104 if (!check_css_precedence(token->type, ';'))
105 break;
107 if (token->type == ','
108 || !css_parse_color_value(propinfo, value, scanner)) {
109 skip_scanner_token(scanner);
110 continue;
113 success++;
116 return success;
121 css_parse_font_style_value(struct css_property_info *propinfo,
122 union css_property_value *value,
123 struct scanner *scanner)
125 struct scanner_token *token = get_scanner_token(scanner);
127 assert(propinfo->value_type == CSS_VT_FONT_ATTRIBUTE);
129 if (token->type != CSS_TOKEN_IDENT) return 0;
131 if (scanner_token_contains(token, "italic")
132 || scanner_token_contains(token, "oblique")) {
133 value->font_attribute.add |= AT_ITALIC;
135 } else if (scanner_token_contains(token, "underline")) {
136 value->font_attribute.add |= AT_UNDERLINE;
138 } else if (scanner_token_contains(token, "normal")) {
139 value->font_attribute.rem |= AT_ITALIC;
141 } else {
142 return 0;
145 skip_css_tokens(scanner, CSS_TOKEN_IDENT);
146 return 1;
151 css_parse_font_weight_value(struct css_property_info *propinfo,
152 union css_property_value *value,
153 struct scanner *scanner)
155 struct scanner_token *token = get_scanner_token(scanner);
156 unsigned char *nstring;
157 int weight;
159 assert(propinfo->value_type == CSS_VT_FONT_ATTRIBUTE);
161 if (token->type == CSS_TOKEN_IDENT) {
162 if (scanner_token_contains(token, "bolder")) {
163 value->font_attribute.add |= AT_BOLD;
165 } else if (scanner_token_contains(token, "lighter")) {
166 value->font_attribute.rem |= AT_BOLD;
168 } else if (scanner_token_contains(token, "bold")) {
169 value->font_attribute.add |= AT_BOLD;
171 } else if (scanner_token_contains(token, "normal")) {
172 value->font_attribute.rem |= AT_BOLD;
174 } else {
175 return 0;
178 skip_css_tokens(scanner, CSS_TOKEN_IDENT);
179 return 1;
182 if (token->type != CSS_TOKEN_NUMBER) return 0;
184 /* TODO: Comma separated list of weights?! */
185 weight = strtol(token->string, (char **) &nstring, 10);
186 if (token->string == nstring) return 0;
188 skip_css_tokens(scanner, CSS_TOKEN_NUMBER);
189 /* The font weight(s) have values between 100 to 900. These
190 * values form an ordered sequence, where each number indicates
191 * a weight that is at least as dark as its predecessor.
193 * normal -> Same as '400'. bold Same as '700'.
195 int_bounds(&weight, 100, 900);
196 if (weight >= 700) value->font_attribute.add |= AT_BOLD;
197 return 1;
202 css_parse_text_align_value(struct css_property_info *propinfo,
203 union css_property_value *value,
204 struct scanner *scanner)
206 struct scanner_token *token = get_scanner_token(scanner);
208 assert(propinfo->value_type == CSS_VT_TEXT_ALIGN);
210 if (token->type != CSS_TOKEN_IDENT) return 0;
212 if (scanner_token_contains(token, "left")) {
213 value->text_align = ALIGN_LEFT;
215 } else if (scanner_token_contains(token, "right")) {
216 value->text_align = ALIGN_RIGHT;
218 } else if (scanner_token_contains(token, "center")) {
219 value->text_align = ALIGN_CENTER;
221 } else if (scanner_token_contains(token, "justify")) {
222 value->text_align = ALIGN_JUSTIFY;
224 } else {
225 return 0;
228 skip_css_tokens(scanner, CSS_TOKEN_IDENT);
229 return 1;
234 css_parse_text_decoration_value(struct css_property_info *propinfo,
235 union css_property_value *value,
236 struct scanner *scanner)
238 struct scanner_token *token = get_scanner_token(scanner);
240 assert(propinfo->value_type == CSS_VT_FONT_ATTRIBUTE);
242 if (token->type != CSS_TOKEN_IDENT) return 0;
244 /* TODO: It is possible to have multiple values here,
245 * 'background'-style. --pasky */
246 if (scanner_token_contains(token, "underline")) {
247 value->font_attribute.add |= AT_UNDERLINE;
249 } else if (scanner_token_contains(token, "none")) {
250 value->font_attribute.rem |= AT_UNDERLINE;
252 } else {
253 return 0;
256 skip_css_tokens(scanner, CSS_TOKEN_IDENT);
257 return 1;
261 css_parse_white_space_value(struct css_property_info *propinfo,
262 union css_property_value *value,
263 struct scanner *scanner)
265 struct scanner_token *token = get_scanner_token(scanner);
267 assert(propinfo->value_type == CSS_VT_FONT_ATTRIBUTE);
269 if (token->type != CSS_TOKEN_IDENT) return 0;
271 /* FIXME: nowrap */
272 if (scanner_token_contains(token, "pre")) {
273 value->font_attribute.add |= AT_PREFORMATTED;
275 } else if (scanner_token_contains(token, "normal")) {
276 value->font_attribute.rem |= AT_PREFORMATTED;
278 } else {
279 return 0;
282 skip_css_tokens(scanner, CSS_TOKEN_IDENT);
283 return 1;
287 css_parse_display_value(struct css_property_info *propinfo,
288 union css_property_value *value,
289 struct scanner *scanner)
291 struct scanner_token *token = get_scanner_token(scanner);
293 assert(propinfo->value_type == CSS_VT_DISPLAY);
295 if (token->type != CSS_TOKEN_IDENT) return 0;
297 /* FIXME: This is _very_ simplistic */
298 if (scanner_token_contains(token, "inline")) {
299 value->display = CSS_DISP_INLINE;
300 } else if (scanner_token_contains(token, "inline-block")) {
301 value->display = CSS_DISP_INLINE; /* XXX */
302 } else if (scanner_token_contains(token, "block")) {
303 value->display = CSS_DISP_BLOCK;
304 } else {
305 return 0;
308 skip_css_tokens(scanner, CSS_TOKEN_IDENT);
309 return 1;
314 css_parse_value(struct css_property_info *propinfo,
315 union css_property_value *value,
316 struct scanner *scanner)
318 struct scanner_token *token;
320 assert(scanner && value && propinfo);
321 assert(propinfo->parser);
323 /* Check that we actually have some token to pass on */
324 token = get_scanner_token(scanner);
325 if (!token) return 0;
327 return propinfo->parser(propinfo, value, scanner);