1 /* CSS property value parser */
2 /* $Id: value.c,v 1.55 2004/06/30 06:00:11 jonas Exp $ */
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"
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
) {
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
43 unsigned char paskynator
= shift
? ',' : ')';
44 unsigned char *nstring
= token
->string
;
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
))
54 part
= strtol(token
->string
, (char **) &nstring
, 10);
55 if (token
->string
== nstring
)
58 /* Adjust percentage values */
59 if (token
->type
== CSS_TOKEN_PERCENTAGE
) {
60 int_bounds(&part
, 0, 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
);
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
)
81 if (decode_color(token
->string
, token
->length
, &value
->color
) < 0) {
85 skip_css_tokens(scanner
, token
->type
);
90 css_parse_background_value(struct css_property_info
*propinfo
,
91 union css_property_value
*value
,
92 struct scanner
*scanner
)
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
, ';'))
107 if (token
->type
== ','
108 || !css_parse_color_value(propinfo
, value
, scanner
)) {
109 skip_scanner_token(scanner
);
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
;
145 skip_css_tokens(scanner
, CSS_TOKEN_IDENT
);
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
;
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
;
178 skip_css_tokens(scanner
, CSS_TOKEN_IDENT
);
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
;
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
;
228 skip_css_tokens(scanner
, CSS_TOKEN_IDENT
);
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
;
256 skip_css_tokens(scanner
, CSS_TOKEN_IDENT
);
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;
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
;
282 skip_css_tokens(scanner
, CSS_TOKEN_IDENT
);
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
;
308 skip_css_tokens(scanner
, CSS_TOKEN_IDENT
);
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
);