1 /*
2 * This file is part of LibCSS.
3 * Licensed under the MIT License,
4 * http://www.opensource.org/licenses/mit-license.php
5 * Copyright 2009 John-Mark Bell <jmb@netsurf-browser.org>
6 */
7
8 #include <assert.h>
9 #include <string.h>
10
11 #include "bytecode/bytecode.h"
12 #include "bytecode/opcodes.h"
13 #include "parse/properties/properties.h"
14 #include "parse/properties/utils.h"
15
16 /**
17 * Parse padding shorthand
18 *
19 * \param c Parsing context
20 * \param vector Vector of tokens to process
21 * \param ctx Pointer to vector iteration context
22 * \param result Pointer to location to receive resulting style
23 * \return CSS_OK on success,
24 * CSS_NOMEM on memory exhaustion,
25 * CSS_INVALID if the input is not valid
26 *
27 * Post condition: \a *ctx is updated with the next token to process
28 * If the input is invalid, then \a *ctx remains unchanged.
29 */
css__parse_padding(css_language * c,const parserutils_vector * vector,int * ctx,css_style * result)30 css_error css__parse_padding(css_language *c,
31 const parserutils_vector *vector, int *ctx,
32 css_style *result)
33 {
34 int orig_ctx = *ctx;
35 int prev_ctx;
36 const css_token *token;
37 css_fixed side_length[4];
38 uint32_t side_unit[4];
39 uint32_t side_count = 0;
40 css_error error;
41
42 /* Firstly, handle inherit */
43 token = parserutils_vector_peek(vector, *ctx);
44 if (token == NULL)
45 return CSS_INVALID;
46
47 if (is_css_inherit(c, token)) {
48 error = css_stylesheet_style_inherit(result, CSS_PROP_PADDING_TOP);
49 if (error != CSS_OK)
50 return error;
51
52 error = css_stylesheet_style_inherit(result, CSS_PROP_PADDING_RIGHT);
53 if (error != CSS_OK)
54 return error;
55
56 error = css_stylesheet_style_inherit(result, CSS_PROP_PADDING_BOTTOM);
57 if (error != CSS_OK)
58 return error;
59
60 error = css_stylesheet_style_inherit(result, CSS_PROP_PADDING_LEFT);
61 if (error == CSS_OK)
62 parserutils_vector_iterate(vector, ctx);
63
64 return error;
65 }
66
67 /* Attempt to parse up to 4 widths */
68 do {
69 prev_ctx = *ctx;
70
71 if ((token != NULL) && is_css_inherit(c, token)) {
72 *ctx = orig_ctx;
73 return CSS_INVALID;
74 }
75
76 error = css__parse_unit_specifier(c, vector, ctx, UNIT_PX, &side_length[side_count], &side_unit[side_count]);
77 if (error == CSS_OK) {
78 if (side_unit[side_count] & UNIT_ANGLE ||
79 side_unit[side_count] & UNIT_TIME ||
80 side_unit[side_count] & UNIT_FREQ) {
81 *ctx = orig_ctx;
82 return CSS_INVALID;
83 }
84
85 if (side_length[side_count] < 0) {
86 *ctx = orig_ctx;
87 return CSS_INVALID;
88 }
89
90 side_count++;
91
92 consumeWhitespace(vector, ctx);
93
94 token = parserutils_vector_peek(vector, *ctx);
95 } else {
96 /* Forcibly cause loop to exit */
97 token = NULL;
98 }
99 } while ((*ctx != prev_ctx) && (token != NULL) && (side_count < 4));
100
101 #define SIDE_APPEND(OP,NUM) \
102 error = css__stylesheet_style_appendOPV(result, (OP), 0, PADDING_SET); \
103 if (error != CSS_OK) \
104 break; \
105 error = css__stylesheet_style_append(result, side_length[(NUM)]); \
106 if (error != CSS_OK) \
107 break; \
108 error = css__stylesheet_style_append(result, side_unit[(NUM)]); \
109 if (error != CSS_OK) \
110 break;
111
112 switch (side_count) {
113 case 1:
114 SIDE_APPEND(CSS_PROP_PADDING_TOP, 0);
115 SIDE_APPEND(CSS_PROP_PADDING_RIGHT, 0);
116 SIDE_APPEND(CSS_PROP_PADDING_BOTTOM, 0);
117 SIDE_APPEND(CSS_PROP_PADDING_LEFT, 0);
118 break;
119 case 2:
120 SIDE_APPEND(CSS_PROP_PADDING_TOP, 0);
121 SIDE_APPEND(CSS_PROP_PADDING_RIGHT, 1);
122 SIDE_APPEND(CSS_PROP_PADDING_BOTTOM, 0);
123 SIDE_APPEND(CSS_PROP_PADDING_LEFT, 1);
124 break;
125 case 3:
126 SIDE_APPEND(CSS_PROP_PADDING_TOP, 0);
127 SIDE_APPEND(CSS_PROP_PADDING_RIGHT, 1);
128 SIDE_APPEND(CSS_PROP_PADDING_BOTTOM, 2);
129 SIDE_APPEND(CSS_PROP_PADDING_LEFT, 1);
130 break;
131 case 4:
132 SIDE_APPEND(CSS_PROP_PADDING_TOP, 0);
133 SIDE_APPEND(CSS_PROP_PADDING_RIGHT, 1);
134 SIDE_APPEND(CSS_PROP_PADDING_BOTTOM, 2);
135 SIDE_APPEND(CSS_PROP_PADDING_LEFT, 3);
136 break;
137 default:
138 error = CSS_INVALID;
139 break;
140 }
141
142 if (error != CSS_OK)
143 *ctx = orig_ctx;
144
145 return error;
146 }
147
148