1 /** CSS property value parser
13 #include "document/css/property.h"
14 #include "document/css/scanner.h"
15 #include "document/css/value.h"
16 #include "util/color.h"
17 #include "util/error.h"
18 #include "util/memory.h"
19 #include "util/string.h"
23 css_parse_color_value(struct css_property_info
*propinfo
,
24 union css_property_value
*value
,
25 struct scanner
*scanner
)
27 struct scanner_token
*token
= get_scanner_token(scanner
);
29 assert(propinfo
->value_type
== CSS_VT_COLOR
);
31 if (token
->type
== CSS_TOKEN_RGB
) {
35 token
= get_next_scanner_token(scanner
);
37 /* First color component is shifted 16, next is shifted 8 and
38 * last is not shifted. */
39 for (shift
= 16; token
&& shift
>= 0; shift
-= 8) {
40 /* The first two args are terminated by ',' and the
42 unsigned char paskynator
= shift
? ',' : ')';
43 const unsigned char *nstring
= token
->string
;
46 /* Are the current and next token valid? */
47 if ((token
->type
!= CSS_TOKEN_NUMBER
48 && token
->type
!= CSS_TOKEN_PERCENTAGE
)
49 || !check_next_scanner_token(scanner
, paskynator
))
53 part
= strtol(token
->string
, (char **) &nstring
, 10);
54 if (token
->string
== nstring
)
57 /* Adjust percentage values */
58 if (token
->type
== CSS_TOKEN_PERCENTAGE
) {
59 int_bounds(&part
, 0, 100);
64 /* Adjust color component value and add it */
65 int_bounds(&part
, 0, 255);
66 value
->color
|= part
<< shift
;
68 /* Paskynate the token arg and separator */
69 token
= skip_css_tokens(scanner
, paskynator
);
75 /* Just a color value we already know how to parse. */
76 if (token
->type
!= CSS_TOKEN_IDENT
77 && token
->type
!= CSS_TOKEN_HEX_COLOR
)
80 if (decode_color(token
->string
, token
->length
, &value
->color
) < 0) {
84 skip_css_tokens(scanner
, token
->type
);
89 css_parse_background_value(struct css_property_info
*propinfo
,
90 union css_property_value
*value
,
91 struct scanner
*scanner
)
95 assert(propinfo
->value_type
== CSS_VT_COLOR
);
97 /* This is pretty naive, we just jump space by space, trying to parse
98 * each token as a color. */
100 while (scanner_has_tokens(scanner
)) {
101 struct scanner_token
*token
= get_scanner_token(scanner
);
103 if (!check_css_precedence(token
->type
, ';'))
106 if (token
->type
== ','
107 || !css_parse_color_value(propinfo
, value
, scanner
)) {
108 skip_scanner_token(scanner
);
120 css_parse_font_style_value(struct css_property_info
*propinfo
,
121 union css_property_value
*value
,
122 struct scanner
*scanner
)
124 struct scanner_token
*token
= get_scanner_token(scanner
);
126 assert(propinfo
->value_type
== CSS_VT_FONT_ATTRIBUTE
);
128 if (token
->type
!= CSS_TOKEN_IDENT
) return 0;
130 if (scanner_token_contains(token
, "italic")
131 || scanner_token_contains(token
, "oblique")) {
132 value
->font_attribute
.add
|= AT_ITALIC
;
134 } else if (scanner_token_contains(token
, "underline")) {
135 value
->font_attribute
.add
|= AT_UNDERLINE
;
137 } else if (scanner_token_contains(token
, "normal")) {
138 value
->font_attribute
.rem
|= AT_ITALIC
;
144 skip_css_tokens(scanner
, CSS_TOKEN_IDENT
);
150 css_parse_font_weight_value(struct css_property_info
*propinfo
,
151 union css_property_value
*value
,
152 struct scanner
*scanner
)
154 struct scanner_token
*token
= get_scanner_token(scanner
);
155 unsigned char *nstring
;
158 assert(propinfo
->value_type
== CSS_VT_FONT_ATTRIBUTE
);
160 if (token
->type
== CSS_TOKEN_IDENT
) {
161 if (scanner_token_contains(token
, "bolder")) {
162 value
->font_attribute
.add
|= AT_BOLD
;
164 } else if (scanner_token_contains(token
, "lighter")) {
165 value
->font_attribute
.rem
|= AT_BOLD
;
167 } else if (scanner_token_contains(token
, "bold")) {
168 value
->font_attribute
.add
|= AT_BOLD
;
170 } else if (scanner_token_contains(token
, "normal")) {
171 value
->font_attribute
.rem
|= AT_BOLD
;
177 skip_css_tokens(scanner
, CSS_TOKEN_IDENT
);
181 if (token
->type
!= CSS_TOKEN_NUMBER
) return 0;
183 /* TODO: Comma separated list of weights?! */
184 weight
= strtol(token
->string
, (char **) &nstring
, 10);
185 if (token
->string
== nstring
) return 0;
187 skip_css_tokens(scanner
, CSS_TOKEN_NUMBER
);
188 /* The font weight(s) have values between 100 to 900. These
189 * values form an ordered sequence, where each number indicates
190 * a weight that is at least as dark as its predecessor.
192 * normal -> Same as '400'. bold Same as '700'.
194 int_bounds(&weight
, 100, 900);
195 if (weight
>= 700) value
->font_attribute
.add
|= AT_BOLD
;
201 css_parse_list_style_value(struct css_property_info
*propinfo
,
202 union css_property_value
*value
,
203 struct scanner
*scanner
)
205 struct scanner_token
*token
= get_scanner_token(scanner
);
207 assert(propinfo
->value_type
== CSS_VT_LIST_STYLE
);
209 if (token
->type
!= CSS_TOKEN_IDENT
) return 0;
211 if (scanner_token_contains(token
, "none")) {
212 value
->list_style
= CSS_LIST_NONE
;
214 } else if (scanner_token_contains(token
, "disc")) {
215 value
->list_style
= CSS_LIST_DISC
;
217 } else if (scanner_token_contains(token
, "circle")) {
218 value
->list_style
= CSS_LIST_CIRCLE
;
220 } else if (scanner_token_contains(token
, "square")) {
221 value
->list_style
= CSS_LIST_SQUARE
;
223 } else if (scanner_token_contains(token
, "decimal")) {
224 value
->list_style
= CSS_LIST_DECIMAL
;
226 } else if (scanner_token_contains(token
, "decimal-leading-zero")) {
227 value
->list_style
= CSS_LIST_DECIMAL_LEADING_ZERO
;
229 } else if (scanner_token_contains(token
, "lower-roman")) {
230 value
->list_style
= CSS_LIST_LOWER_ROMAN
;
232 } else if (scanner_token_contains(token
, "upper-roman")) {
233 value
->list_style
= CSS_LIST_UPPER_ROMAN
;
235 } else if (scanner_token_contains(token
, "lower-alpha")) {
236 value
->list_style
= CSS_LIST_LOWER_ALPHA
;
238 } else if (scanner_token_contains(token
, "upper-alpha")) {
239 value
->list_style
= CSS_LIST_UPPER_ALPHA
;
241 } else if (scanner_token_contains(token
, "lower-greek")) {
242 value
->list_style
= CSS_LIST_LOWER_GREEK
;
244 } else if (scanner_token_contains(token
, "lower-latin")) {
245 value
->list_style
= CSS_LIST_LOWER_LATIN
;
247 } else if (scanner_token_contains(token
, "upper-latin")) {
248 value
->list_style
= CSS_LIST_UPPER_LATIN
;
250 } else if (scanner_token_contains(token
, "hebrew")) {
251 value
->list_style
= CSS_LIST_HEBREW
;
253 } else if (scanner_token_contains(token
, "armenian")) {
254 value
->list_style
= CSS_LIST_ARMENIAN
;
256 } else if (scanner_token_contains(token
, "georgian")) {
257 value
->list_style
= CSS_LIST_GEORGIAN
;
259 } else if (scanner_token_contains(token
, "cjk-ideographic")) {
260 value
->list_style
= CSS_LIST_CJK_IDEOGRAPHIC
;
262 } else if (scanner_token_contains(token
, "hiragana")) {
263 value
->list_style
= CSS_LIST_HIRAGANA
;
265 } else if (scanner_token_contains(token
, "katakana")) {
266 value
->list_style
= CSS_LIST_KATAKANA
;
268 } else if (scanner_token_contains(token
, "hiragana-iroha")) {
269 value
->list_style
= CSS_LIST_HIRAGANA_IROHA
;
271 } else if (scanner_token_contains(token
, "katakana-iroha")) {
272 value
->list_style
= CSS_LIST_KATAKANA_IROHA
;
278 skip_css_tokens(scanner
, CSS_TOKEN_IDENT
);
283 css_parse_text_align_value(struct css_property_info
*propinfo
,
284 union css_property_value
*value
,
285 struct scanner
*scanner
)
287 struct scanner_token
*token
= get_scanner_token(scanner
);
289 assert(propinfo
->value_type
== CSS_VT_TEXT_ALIGN
);
291 if (token
->type
!= CSS_TOKEN_IDENT
) return 0;
293 if (scanner_token_contains(token
, "left")) {
294 value
->text_align
= ALIGN_LEFT
;
296 } else if (scanner_token_contains(token
, "right")) {
297 value
->text_align
= ALIGN_RIGHT
;
299 } else if (scanner_token_contains(token
, "center")) {
300 value
->text_align
= ALIGN_CENTER
;
302 } else if (scanner_token_contains(token
, "justify")) {
303 value
->text_align
= ALIGN_JUSTIFY
;
309 skip_css_tokens(scanner
, CSS_TOKEN_IDENT
);
315 css_parse_text_decoration_value(struct css_property_info
*propinfo
,
316 union css_property_value
*value
,
317 struct scanner
*scanner
)
319 struct scanner_token
*token
= get_scanner_token(scanner
);
321 assert(propinfo
->value_type
== CSS_VT_FONT_ATTRIBUTE
);
323 if (token
->type
!= CSS_TOKEN_IDENT
) return 0;
325 /* TODO: It is possible to have multiple values here,
326 * 'background'-style. --pasky */
327 if (scanner_token_contains(token
, "underline")) {
328 value
->font_attribute
.add
|= AT_UNDERLINE
;
330 } else if (scanner_token_contains(token
, "none")) {
331 value
->font_attribute
.rem
|= AT_UNDERLINE
;
337 skip_css_tokens(scanner
, CSS_TOKEN_IDENT
);
342 css_parse_white_space_value(struct css_property_info
*propinfo
,
343 union css_property_value
*value
,
344 struct scanner
*scanner
)
346 struct scanner_token
*token
= get_scanner_token(scanner
);
348 assert(propinfo
->value_type
== CSS_VT_FONT_ATTRIBUTE
);
350 if (token
->type
!= CSS_TOKEN_IDENT
) return 0;
353 if (scanner_token_contains(token
, "pre")) {
354 value
->font_attribute
.add
|= AT_PREFORMATTED
;
356 } else if (scanner_token_contains(token
, "normal")) {
357 value
->font_attribute
.rem
|= AT_PREFORMATTED
;
363 skip_css_tokens(scanner
, CSS_TOKEN_IDENT
);
368 css_parse_display_value(struct css_property_info
*propinfo
,
369 union css_property_value
*value
,
370 struct scanner
*scanner
)
372 struct scanner_token
*token
= get_scanner_token(scanner
);
374 assert(propinfo
->value_type
== CSS_VT_DISPLAY
);
376 if (token
->type
!= CSS_TOKEN_IDENT
) return 0;
378 /* FIXME: This is _very_ simplistic */
379 if (scanner_token_contains(token
, "inline")) {
380 value
->display
= CSS_DISP_INLINE
;
381 } else if (scanner_token_contains(token
, "inline-block")) {
382 value
->display
= CSS_DISP_INLINE
; /* XXX */
383 } else if (scanner_token_contains(token
, "block")) {
384 value
->display
= CSS_DISP_BLOCK
;
385 } else if (scanner_token_contains(token
, "none")) {
386 value
->display
= CSS_DISP_NONE
;
391 skip_css_tokens(scanner
, CSS_TOKEN_IDENT
);
397 css_parse_value(struct css_property_info
*propinfo
,
398 union css_property_value
*value
,
399 struct scanner
*scanner
)
401 struct scanner_token
*token
;
403 assert(scanner
&& value
&& propinfo
);
404 assert(propinfo
->parser
);
406 /* Check that we actually have some token to pass on */
407 token
= get_scanner_token(scanner
);
408 if (!token
) return 0;
410 return propinfo
->parser(propinfo
, value
, scanner
);