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 "bytecode/bytecode.h"
9 #include "bytecode/opcodes.h"
10 #include "select/propset.h"
11 #include "select/propget.h"
12 #include "utils/utils.h"
13 
14 #include "select/properties/properties.h"
15 #include "select/properties/helpers.h"
16 
css__cascade_content(uint32_t opv,css_style * style,css_select_state * state)17 css_error css__cascade_content(uint32_t opv, css_style *style,
18 		css_select_state *state)
19 {
20 	uint16_t value = CSS_CONTENT_INHERIT;
21 	css_computed_content_item *content = NULL;
22 	uint32_t n_contents = 0;
23 
24 	if (isInherit(opv) == false) {
25 		uint32_t v = getValue(opv);
26 
27 		if (v == CONTENT_NORMAL) {
28 			value = CSS_CONTENT_NORMAL;
29 		} else if (v == CONTENT_NONE) {
30 			value = CSS_CONTENT_NONE;
31 		} else {
32 			value = CSS_CONTENT_SET;
33 
34 			while (v != CONTENT_NORMAL) {
35 				lwc_string *he;
36 				css_computed_content_item *temp;
37 
38 				css__stylesheet_string_get(style->sheet,
39 					*((css_code_t *) style->bytecode), &he);
40 
41 				temp = realloc(content,
42 						(n_contents + 1) *
43 						sizeof(css_computed_content_item));
44 				if (temp == NULL) {
45 					if (content != NULL) {
46 						free(content);
47 					}
48 					return CSS_NOMEM;
49 				}
50 
51 				content = temp;
52 				memset(content + n_contents, 0, sizeof(css_computed_content_item));
53 
54 				switch (v & 0xff) {
55 				case CONTENT_COUNTER:
56 					advance_bytecode(style, sizeof(css_code_t));
57 
58 					content[n_contents].type =
59 						CSS_COMPUTED_CONTENT_COUNTER;
60 					content[n_contents].data.counter.name = he;
61 					content[n_contents].data.counter.style = v >> CONTENT_COUNTER_STYLE_SHIFT;
62 					break;
63 				case CONTENT_COUNTERS:
64 				{
65 					lwc_string *sep;
66 
67 					advance_bytecode(style, sizeof(css_code_t));
68 
69 					css__stylesheet_string_get(style->sheet, *((css_code_t *) style->bytecode), &sep);
70 					advance_bytecode(style, sizeof(css_code_t));
71 
72 					content[n_contents].type =
73 						CSS_COMPUTED_CONTENT_COUNTERS;
74 					content[n_contents].data.counters.name = he;
75 					content[n_contents].data.counters.sep = sep;
76 					content[n_contents].data.counters.style = v >> CONTENT_COUNTERS_STYLE_SHIFT;
77 				}
78 					break;
79 				case CONTENT_URI:
80 					advance_bytecode(style, sizeof(css_code_t));
81 
82 					content[n_contents].type =
83 						CSS_COMPUTED_CONTENT_URI;
84 					content[n_contents].data.uri = he;
85 					break;
86 				case CONTENT_ATTR:
87 					advance_bytecode(style, sizeof(css_code_t));
88 
89 					content[n_contents].type =
90 						CSS_COMPUTED_CONTENT_ATTR;
91 					content[n_contents].data.attr = he;
92 					break;
93 				case CONTENT_STRING:
94 					advance_bytecode(style, sizeof(css_code_t));
95 
96 					content[n_contents].type =
97 						CSS_COMPUTED_CONTENT_STRING;
98 					content[n_contents].data.string = he;
99 					break;
100 				case CONTENT_OPEN_QUOTE:
101 					content[n_contents].type =
102 						CSS_COMPUTED_CONTENT_OPEN_QUOTE;
103 					break;
104 				case CONTENT_CLOSE_QUOTE:
105 					content[n_contents].type =
106 						CSS_COMPUTED_CONTENT_CLOSE_QUOTE;
107 					break;
108 				case CONTENT_NO_OPEN_QUOTE:
109 					content[n_contents].type =
110 						CSS_COMPUTED_CONTENT_NO_OPEN_QUOTE;
111 					break;
112 				case CONTENT_NO_CLOSE_QUOTE:
113 					content[n_contents].type =
114 						CSS_COMPUTED_CONTENT_NO_CLOSE_QUOTE;
115 					break;
116 				}
117 
118 				n_contents++;
119 
120 				v = *((uint32_t *) style->bytecode);
121 				advance_bytecode(style, sizeof(v));
122 			}
123 		}
124 	}
125 
126 	/* If we have some content, terminate the array with a blank entry */
127 	if (n_contents > 0) {
128 		css_computed_content_item *temp;
129 
130 		temp = realloc(content, (n_contents + 1) *
131 				sizeof(css_computed_content_item));
132 		if (temp == NULL) {
133 			free(content);
134 			return CSS_NOMEM;
135 		}
136 
137 		content = temp;
138 
139 		content[n_contents].type = CSS_COMPUTED_CONTENT_NONE;
140 	}
141 
142 	if (css__outranks_existing(getOpcode(opv), isImportant(opv), state,
143 			isInherit(opv))) {
144 		css_error error;
145 
146 		error = set_content(state->computed, value, content);
147 		if (error != CSS_OK && content != NULL)
148 			free(content);
149 
150 		return error;
151 	} else if (content != NULL) {
152 		free(content);
153 	}
154 
155 	return CSS_OK;
156 }
157 
css__set_content_from_hint(const css_hint * hint,css_computed_style * style)158 css_error css__set_content_from_hint(const css_hint *hint,
159 		css_computed_style *style)
160 {
161 	css_computed_content_item *item;
162 	css_error error;
163 
164 	error = set_content(style, hint->status, hint->data.content);
165 
166 	for (item = hint->data.content; item != NULL &&
167 			item->type != CSS_COMPUTED_CONTENT_NONE;
168 			item++) {
169 		switch (item->type) {
170 		case CSS_COMPUTED_CONTENT_STRING:
171 			lwc_string_unref(item->data.string);
172 			break;
173 		case CSS_COMPUTED_CONTENT_URI:
174 			lwc_string_unref(item->data.uri);
175 			break;
176 		case CSS_COMPUTED_CONTENT_COUNTER:
177 			lwc_string_unref(item->data.counter.name);
178 			break;
179 		case CSS_COMPUTED_CONTENT_COUNTERS:
180 			lwc_string_unref(item->data.counters.name);
181 			lwc_string_unref(item->data.counters.sep);
182 			break;
183 		case CSS_COMPUTED_CONTENT_ATTR:
184 			lwc_string_unref(item->data.attr);
185 			break;
186 		default:
187 			break;
188 		}
189 	}
190 
191 	if (error != CSS_OK && hint->data.content != NULL)
192 		free(hint->data.content);
193 
194 	return error;
195 }
196 
css__initial_content(css_select_state * state)197 css_error css__initial_content(css_select_state *state)
198 {
199 	return set_content(state->computed, CSS_CONTENT_NORMAL, NULL);
200 }
201 
css__compose_content(const css_computed_style * parent,const css_computed_style * child,css_computed_style * result)202 css_error css__compose_content(const css_computed_style *parent,
203 		const css_computed_style *child,
204 		css_computed_style *result)
205 {
206 	css_error error;
207 	css_computed_content_item *copy = NULL;
208 	const css_computed_content_item *items = NULL;
209 	uint8_t type = get_content(child, &items);
210 
211 	if (type == CSS_CONTENT_INHERIT) {
212 		type = get_content(parent, &items);
213 	}
214 
215 	if (type == CSS_CONTENT_SET) {
216 		size_t n_items = 0;
217 		const css_computed_content_item *i;
218 
219 		for (i = items; i->type != CSS_COMPUTED_CONTENT_NONE;
220 				i++)
221 			n_items++;
222 
223 		copy = malloc((n_items + 1) *
224 				sizeof(css_computed_content_item));
225 		if (copy == NULL)
226 			return CSS_NOMEM;
227 
228 		memcpy(copy, items, (n_items + 1) *
229 				sizeof(css_computed_content_item));
230 	}
231 
232 	error = set_content(result, type, copy);
233 	if (error != CSS_OK && copy != NULL)
234 		free(copy);
235 
236 	return error;
237 }
238