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