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_font_family(uint32_t opv,css_style * style,css_select_state * state)17 css_error css__cascade_font_family(uint32_t opv, css_style *style,
18 		css_select_state *state)
19 {
20 	uint16_t value = CSS_FONT_FAMILY_INHERIT;
21 	lwc_string **fonts = NULL;
22 	uint32_t n_fonts = 0;
23 
24 	if (isInherit(opv) == false) {
25 		uint32_t v = getValue(opv);
26 
27 		while (v != FONT_FAMILY_END) {
28 			lwc_string *font = NULL;
29 			lwc_string **temp;
30 
31 			switch (v) {
32 			case FONT_FAMILY_STRING:
33 			case FONT_FAMILY_IDENT_LIST:
34 				css__stylesheet_string_get(style->sheet,
35 					*((css_code_t *) style->bytecode),
36 					&font);
37 				advance_bytecode(style, sizeof(css_code_t));
38 				break;
39 			case FONT_FAMILY_SERIF:
40 				if (value == CSS_FONT_FAMILY_INHERIT)
41 					value = CSS_FONT_FAMILY_SERIF;
42 				break;
43 			case FONT_FAMILY_SANS_SERIF:
44 				if (value == CSS_FONT_FAMILY_INHERIT)
45 					value = CSS_FONT_FAMILY_SANS_SERIF;
46 				break;
47 			case FONT_FAMILY_CURSIVE:
48 				if (value == CSS_FONT_FAMILY_INHERIT)
49 					value = CSS_FONT_FAMILY_CURSIVE;
50 				break;
51 			case FONT_FAMILY_FANTASY:
52 				if (value == CSS_FONT_FAMILY_INHERIT)
53 					value = CSS_FONT_FAMILY_FANTASY;
54 				break;
55 			case FONT_FAMILY_MONOSPACE:
56 				if (value == CSS_FONT_FAMILY_INHERIT)
57 					value = CSS_FONT_FAMILY_MONOSPACE;
58 				break;
59 			}
60 
61 			/* Only use family-names which occur before the first
62 			 * generic-family. Any values which occur after the
63 			 * first generic-family are ignored. */
64 			/** \todo Do this at bytecode generation time? */
65 			if (value == CSS_FONT_FAMILY_INHERIT && font != NULL) {
66 				temp = realloc(fonts,
67 					(n_fonts + 1) * sizeof(lwc_string *));
68 				if (temp == NULL) {
69 					if (fonts != NULL) {
70 						free(fonts);
71 					}
72 					return CSS_NOMEM;
73 				}
74 
75 				fonts = temp;
76 
77 				fonts[n_fonts] = font;
78 
79 				n_fonts++;
80 			}
81 
82 			v = *((uint32_t *) style->bytecode);
83 			advance_bytecode(style, sizeof(v));
84 		}
85 	}
86 
87 	/* Terminate array with blank entry, if needed */
88 	if (n_fonts > 0) {
89 		lwc_string **temp;
90 
91 		temp = realloc(fonts, (n_fonts + 1) * sizeof(lwc_string *));
92 		if (temp == NULL) {
93 			free(fonts);
94 			return CSS_NOMEM;
95 		}
96 
97 		fonts = temp;
98 
99 		fonts[n_fonts] = NULL;
100 
101 		if (value == CSS_FONT_FAMILY_INHERIT) {
102 			/* The stylesheet doesn't specify a generic family,
103 			 * but it has specified named fonts.
104 			 * Fall back to the user agent's default family.
105 			 * We don't want to inherit, because that will
106 			 * incorrectly overwrite the named fonts list too.
107 			 */
108 			css_hint hint;
109 			css_error error;
110 
111 			error = state->handler->ua_default_for_property(
112 					state->pw, CSS_PROP_FONT_FAMILY, &hint);
113 			if (error == CSS_OK) {
114 				lwc_string **item;
115 
116 				value = hint.status;
117 
118 				for (item = hint.data.strings;
119 						item != NULL && (*item) != NULL;
120 						item++) {
121 					lwc_string_unref(*item);
122 				}
123 
124 				if (hint.data.strings != NULL) {
125 					free(hint.data.strings);
126 				}
127 			}
128 
129 			if (value == CSS_FONT_FAMILY_INHERIT) {
130 				/* No sane UA default: assume sans-serif */
131 				value = CSS_FONT_FAMILY_SANS_SERIF;
132 			}
133 		}
134 	}
135 
136 	if (css__outranks_existing(getOpcode(opv), isImportant(opv), state,
137 			isInherit(opv))) {
138 		css_error error;
139 
140 		error = set_font_family(state->computed, value, fonts);
141 		if (error != CSS_OK && n_fonts > 0)
142 			free(fonts);
143 
144 		return error;
145 	} else {
146 		if (n_fonts > 0)
147 			free(fonts);
148 	}
149 
150 	return CSS_OK;
151 }
152 
css__set_font_family_from_hint(const css_hint * hint,css_computed_style * style)153 css_error css__set_font_family_from_hint(const css_hint *hint,
154 		css_computed_style *style)
155 {
156 	lwc_string **item;
157 	css_error error;
158 
159 	error = set_font_family(style, hint->status, hint->data.strings);
160 
161 	for (item = hint->data.strings;
162 			item != NULL && (*item) != NULL; item++) {
163 		lwc_string_unref(*item);
164 	}
165 
166 	if (error != CSS_OK && hint->data.strings != NULL)
167 		free(hint->data.strings);
168 
169 	return error;
170 }
171 
css__initial_font_family(css_select_state * state)172 css_error css__initial_font_family(css_select_state *state)
173 {
174 	css_hint hint;
175 	css_error error;
176 
177 	error = state->handler->ua_default_for_property(state->pw,
178 			CSS_PROP_FONT_FAMILY, &hint);
179 	if (error != CSS_OK)
180 		return error;
181 
182 	return css__set_font_family_from_hint(&hint, state->computed);
183 }
184 
css__compose_font_family(const css_computed_style * parent,const css_computed_style * child,css_computed_style * result)185 css_error css__compose_font_family(const css_computed_style *parent,
186 		const css_computed_style *child,
187 		css_computed_style *result)
188 {
189 	css_error error;
190 	lwc_string **names = NULL;
191 	uint8_t type = get_font_family(child, &names);
192 
193 	if (type == CSS_FONT_FAMILY_INHERIT || result != child) {
194 		size_t n_names = 0;
195 		lwc_string **copy = NULL;
196 
197 		if (type == CSS_FONT_FAMILY_INHERIT)
198 			type = get_font_family(parent, &names);
199 
200 		if (names != NULL) {
201 			lwc_string **i;
202 
203 			for (i = names; (*i) != NULL; i++)
204 				n_names++;
205 
206 			copy = malloc((n_names + 1) * sizeof(lwc_string *));
207 			if (copy == NULL)
208 				return CSS_NOMEM;
209 
210 			memcpy(copy, names, (n_names + 1) *
211 					sizeof(lwc_string *));
212 		}
213 
214 		error = set_font_family(result, type, copy);
215 		if (error != CSS_OK && copy != NULL)
216 			free(copy);
217 
218 		return error;
219 	}
220 
221 	return CSS_OK;
222 }
223 
224