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 
parse_system_font(css_language * c,css_style * result,css_system_font * system_font)17 static css_error parse_system_font(css_language *c,
18 		css_style *result, css_system_font *system_font)
19 {
20 	css_error error;
21 	bool match;
22 
23 	/* style */
24 	switch (system_font->style) {
25 	case CSS_FONT_STYLE_NORMAL:
26 		error = css__stylesheet_style_appendOPV(result, CSS_PROP_FONT_STYLE, 0, FONT_STYLE_NORMAL);
27 		break;
28 
29 	case CSS_FONT_STYLE_ITALIC:
30 		error = css__stylesheet_style_appendOPV(result, CSS_PROP_FONT_STYLE, 0, FONT_STYLE_ITALIC);
31 		break;
32 
33 	case CSS_FONT_STYLE_OBLIQUE:
34 		error = css__stylesheet_style_appendOPV(result, CSS_PROP_FONT_STYLE, 0, FONT_STYLE_OBLIQUE);
35 		break;
36 
37 	default:
38 		error = CSS_BADPARM;
39 		break;
40 	}
41 	if (error != CSS_OK)
42 		return error;
43 
44 	/* variant */
45 	switch (system_font->variant) {
46 	case CSS_FONT_VARIANT_NORMAL:
47 		error = css__stylesheet_style_appendOPV(result, CSS_PROP_FONT_VARIANT, 0, FONT_VARIANT_NORMAL);
48 		break;
49 
50 	case CSS_FONT_VARIANT_SMALL_CAPS:
51 		error = css__stylesheet_style_appendOPV(result, CSS_PROP_FONT_VARIANT, 0, FONT_VARIANT_SMALL_CAPS);
52 		break;
53 
54 	default:
55 		error = CSS_BADPARM;
56 		break;
57 	}
58 	if (error != CSS_OK)
59 		return error;
60 
61 	/* weight */
62 	switch(system_font->weight) {
63 	case CSS_FONT_WEIGHT_NORMAL:
64 		error = css__stylesheet_style_appendOPV(result, CSS_PROP_FONT_WEIGHT, 0, FONT_WEIGHT_NORMAL);
65 		break;
66 
67 	case CSS_FONT_WEIGHT_BOLD:
68 		error = css__stylesheet_style_appendOPV(result, CSS_PROP_FONT_WEIGHT, 0, FONT_WEIGHT_BOLD);
69 		break;
70 
71 	case CSS_FONT_WEIGHT_BOLDER:
72 		error = css__stylesheet_style_appendOPV(result, CSS_PROP_FONT_WEIGHT, 0, FONT_WEIGHT_BOLDER);
73 		break;
74 
75 	case CSS_FONT_WEIGHT_LIGHTER:
76 		error = css__stylesheet_style_appendOPV(result, CSS_PROP_FONT_WEIGHT, 0, FONT_WEIGHT_LIGHTER);
77 		break;
78 
79 	case CSS_FONT_WEIGHT_100:
80 		error = css__stylesheet_style_appendOPV(result, CSS_PROP_FONT_WEIGHT, 0, FONT_WEIGHT_100);
81 		break;
82 
83 	case CSS_FONT_WEIGHT_200:
84 		error = css__stylesheet_style_appendOPV(result, CSS_PROP_FONT_WEIGHT, 0, FONT_WEIGHT_200);
85 		break;
86 
87 	case CSS_FONT_WEIGHT_300:
88 		error = css__stylesheet_style_appendOPV(result, CSS_PROP_FONT_WEIGHT, 0, FONT_WEIGHT_300);
89 		break;
90 
91 	case CSS_FONT_WEIGHT_400:
92 		error = css__stylesheet_style_appendOPV(result, CSS_PROP_FONT_WEIGHT, 0, FONT_WEIGHT_400);
93 		break;
94 
95 	case CSS_FONT_WEIGHT_500:
96 		error = css__stylesheet_style_appendOPV(result, CSS_PROP_FONT_WEIGHT, 0, FONT_WEIGHT_500);
97 		break;
98 
99 	case CSS_FONT_WEIGHT_600:
100 		error = css__stylesheet_style_appendOPV(result, CSS_PROP_FONT_WEIGHT, 0, FONT_WEIGHT_600);
101 		break;
102 
103 	case CSS_FONT_WEIGHT_700:
104 		error = css__stylesheet_style_appendOPV(result, CSS_PROP_FONT_WEIGHT, 0, FONT_WEIGHT_700);
105 		break;
106 
107 	case CSS_FONT_WEIGHT_800:
108 		error = css__stylesheet_style_appendOPV(result, CSS_PROP_FONT_WEIGHT, 0, FONT_WEIGHT_800);
109 		break;
110 
111 	case CSS_FONT_WEIGHT_900:
112 		error = css__stylesheet_style_appendOPV(result, CSS_PROP_FONT_WEIGHT, 0, FONT_WEIGHT_900);
113 		break;
114 
115 	default:
116 		error = CSS_BADPARM;
117 		break;
118 	}
119 	if (error != CSS_OK)
120 		return error;
121 
122 	/* size */
123 	error = css__stylesheet_style_appendOPV(result, CSS_PROP_FONT_SIZE, 0,  FONT_SIZE_DIMENSION);
124 	if (error != CSS_OK)
125 		return error;
126 
127 	error = css__stylesheet_style_vappend(result, 2, system_font->size.size, system_font->size.unit);
128 	if (error != CSS_OK)
129 		return error;
130 
131 	/* line height */
132 	error = css__stylesheet_style_appendOPV(result, CSS_PROP_LINE_HEIGHT, 0, LINE_HEIGHT_DIMENSION);
133 	if (error != CSS_OK)
134 		return error;
135 
136 	error = css__stylesheet_style_vappend(result, 2, system_font->line_height.size, system_font->line_height.unit);
137 	if (error != CSS_OK)
138 		return error;
139 
140 	/* font family */
141 	if ((lwc_string_caseless_isequal(system_font->family, c->strings[SERIF], &match) == lwc_error_ok && match))
142 		error = css__stylesheet_style_appendOPV(result, CSS_PROP_FONT_FAMILY, 0, FONT_FAMILY_SERIF);
143 	else if ((lwc_string_caseless_isequal(system_font->family, c->strings[SANS_SERIF], &match) == lwc_error_ok && match))
144 		error = css__stylesheet_style_appendOPV(result, CSS_PROP_FONT_FAMILY, 0, FONT_FAMILY_SANS_SERIF);
145 	else if ((lwc_string_caseless_isequal(system_font->family, c->strings[CURSIVE], &match) == lwc_error_ok && match))
146 		error = css__stylesheet_style_appendOPV(result, CSS_PROP_FONT_FAMILY, 0, FONT_FAMILY_CURSIVE);
147 	else if ((lwc_string_caseless_isequal(system_font->family, c->strings[FANTASY], &match) == lwc_error_ok && match))
148 		error = css__stylesheet_style_appendOPV(result, CSS_PROP_FONT_FAMILY, 0, FONT_FAMILY_FANTASY);
149 	else if ((lwc_string_caseless_isequal(system_font->family, c->strings[MONOSPACE], &match) == lwc_error_ok && match))
150 		error = css__stylesheet_style_appendOPV(result, CSS_PROP_FONT_FAMILY, 0, FONT_FAMILY_MONOSPACE);
151 	else {
152 		uint32_t snumber;
153 
154 		error = css__stylesheet_string_add(c->sheet, lwc_string_ref(system_font->family), &snumber);
155 		if (error != CSS_OK)
156 			return error;
157 
158 		error = css__stylesheet_style_appendOPV(result, CSS_PROP_FONT_FAMILY, 0, FONT_FAMILY_STRING);
159 		if (error != CSS_OK)
160 			return error;
161 
162 		error = css__stylesheet_style_append(result, snumber);
163 	}
164 	if (error != CSS_OK)
165 		return error;
166 
167 	error = css__stylesheet_style_append(result, FONT_FAMILY_END);
168 
169 	return error;
170 }
171 
172 /**
173  * Parse font
174  *
175  * \param c	  Parsing context
176  * \param vector  Vector of tokens to process
177  * \param ctx	  Pointer to vector iteration context
178  * \param result  Pointer to location to receive resulting style
179  * \return CSS_OK on success,
180  *	   CSS_NOMEM on memory exhaustion,
181  *	   CSS_INVALID if the input is not valid
182  *
183  * Post condition: \a *ctx is updated with the next token to process
184  *		   If the input is invalid, then \a *ctx remains unchanged.
185  */
css__parse_font(css_language * c,const parserutils_vector * vector,int * ctx,css_style * result)186 css_error css__parse_font(css_language *c,
187 		const parserutils_vector *vector, int *ctx,
188 		css_style *result)
189 {
190 	const css_token *token;
191 	css_error error;
192 	int orig_ctx = *ctx;
193 	int prev_ctx;
194 	css_system_font system_font;
195 
196 	bool style = true;
197 	bool variant = true;
198 	bool weight = true;
199 	bool line_height = true;
200 	css_style *style_style;
201 	css_style *variant_style;
202 	css_style *weight_style;
203 	css_style *size_style;
204 	css_style *line_height_style;
205 	css_style *family_style;
206 	int svw;
207 
208 	/* Firstly, handle inherit */
209 	token = parserutils_vector_peek(vector, *ctx);
210 	if (token == NULL)
211 		return CSS_INVALID;
212 
213 	if (is_css_inherit(c, token)) {
214 		error = css_stylesheet_style_inherit(result, CSS_PROP_FONT_STYLE);
215 		if (error != CSS_OK)
216 			return error;
217 
218 		error = css_stylesheet_style_inherit(result, CSS_PROP_FONT_VARIANT);
219 		if (error != CSS_OK)
220 			return error;
221 
222 		error = css_stylesheet_style_inherit(result, CSS_PROP_FONT_WEIGHT);
223 		if (error != CSS_OK)
224 			return error;
225 
226 		error = css_stylesheet_style_inherit(result, CSS_PROP_FONT_SIZE);
227 		if (error != CSS_OK)
228 			return error;
229 
230 		error = css_stylesheet_style_inherit(result, CSS_PROP_LINE_HEIGHT);
231 		if (error != CSS_OK)
232 			return error;
233 
234 		error = css_stylesheet_style_inherit(result, CSS_PROP_FONT_FAMILY);
235 		if (error == CSS_OK)
236 			parserutils_vector_iterate(vector, ctx);
237 
238 		return error;
239 	}
240 
241 	/* Perhaps an unknown font name; ask the client */
242 	if ((token->type == CSS_TOKEN_IDENT) &&
243 	    (c->sheet->font != NULL) &&
244 	    (c->sheet->font(c->sheet->font_pw,
245 			    token->idata,
246 			    &system_font) == CSS_OK)) {
247 
248 		error = parse_system_font(c, result, &system_font);
249 
250 		if (error == CSS_OK)
251 			parserutils_vector_iterate(vector, ctx);
252 
253 		return error;
254 	}
255 
256 
257 	/* allocate styles */
258 	error = css__stylesheet_style_create(c->sheet, &style_style);
259 	if (error != CSS_OK)
260 		return error;
261 
262 	error = css__stylesheet_style_create(c->sheet, &variant_style);
263 	if (error != CSS_OK) {
264 		css__stylesheet_style_destroy(style_style);
265 		return error;
266 	}
267 
268 	error = css__stylesheet_style_create(c->sheet, &weight_style);
269 	if (error != CSS_OK) {
270 		css__stylesheet_style_destroy(style_style);
271 		css__stylesheet_style_destroy(variant_style);
272 		return error;
273 	}
274 
275 	error = css__stylesheet_style_create(c->sheet, &size_style);
276 	if (error != CSS_OK) {
277 		css__stylesheet_style_destroy(style_style);
278 		css__stylesheet_style_destroy(variant_style);
279 		css__stylesheet_style_destroy(weight_style);
280 		return error;
281 	}
282 
283 	error = css__stylesheet_style_create(c->sheet, &line_height_style);
284 	if (error != CSS_OK) {
285 		css__stylesheet_style_destroy(style_style);
286 		css__stylesheet_style_destroy(variant_style);
287 		css__stylesheet_style_destroy(weight_style);
288 		css__stylesheet_style_destroy(size_style);
289 		return error;
290 	}
291 
292 	error = css__stylesheet_style_create(c->sheet, &family_style);
293 	if (error != CSS_OK) {
294 		css__stylesheet_style_destroy(style_style);
295 		css__stylesheet_style_destroy(variant_style);
296 		css__stylesheet_style_destroy(weight_style);
297 		css__stylesheet_style_destroy(size_style);
298 		css__stylesheet_style_destroy(line_height_style);
299 		return error;
300 	}
301 
302 
303 	/* Attempt to parse the optional style, variant, and weight */
304 	for (svw = 0; svw < 3; svw++) {
305 		prev_ctx = *ctx;
306 		error = CSS_OK;
307 
308 		/* Ensure that we're not about to parse another inherit */
309 		token = parserutils_vector_peek(vector, *ctx);
310 		if ((token != NULL) && is_css_inherit(c, token)) {
311 			error = CSS_INVALID;
312 			goto css__parse_font_cleanup;
313 		}
314 
315 		if ((style) &&
316 		    (error = css__parse_font_style(c, vector,
317 					ctx, style_style)) == CSS_OK) {
318 			style = false;
319 		} else if ((variant) &&
320 			   (error = css__parse_font_variant(c, vector, ctx,
321 					variant_style)) == CSS_OK) {
322 			variant = false;
323 		} else if ((weight) &&
324 			   (error = css__parse_font_weight(c, vector, ctx,
325 				weight_style)) == CSS_OK) {
326 			weight = false;
327 		}
328 
329 		if (error == CSS_OK) {
330 			consumeWhitespace(vector, ctx);
331 		} else {
332 			break;
333 		}
334 
335 		if (*ctx == prev_ctx)
336 			break;
337 	}
338 
339 	consumeWhitespace(vector, ctx);
340 
341 	/* Ensure that we're not about to parse another inherit */
342 	token = parserutils_vector_peek(vector, *ctx);
343 	if ((token != NULL) && is_css_inherit(c, token)) {
344 		error = CSS_INVALID;
345 		goto css__parse_font_cleanup;
346 	}
347 
348 	/* Now expect a font-size */
349 	error = css__parse_font_size(c, vector, ctx, size_style);
350 	if (error != CSS_OK)
351 		goto css__parse_font_cleanup;
352 
353 	consumeWhitespace(vector, ctx);
354 
355 	/* Potential line-height */
356 	token = parserutils_vector_peek(vector, *ctx);
357 	if ((token != NULL) && tokenIsChar(token, '/')) {
358 		parserutils_vector_iterate(vector, ctx);
359 
360 		consumeWhitespace(vector, ctx);
361 
362 		/* Ensure that we're not about to parse another inherit */
363 		token = parserutils_vector_peek(vector, *ctx);
364 		if ((token != NULL) && is_css_inherit(c, token)) {
365 			error = CSS_INVALID;
366 			goto css__parse_font_cleanup;
367 		}
368 
369 		error = css__parse_line_height(c, vector, ctx, line_height_style);
370 		if (error != CSS_OK)
371 			goto css__parse_font_cleanup;
372 
373 		line_height = false;
374 	}
375 
376 	consumeWhitespace(vector, ctx);
377 
378 	/* Ensure that we're not about to parse another inherit */
379 	token = parserutils_vector_peek(vector, *ctx);
380 	if ((token != NULL) && is_css_inherit(c, token)) {
381 		error = CSS_INVALID;
382 		goto css__parse_font_cleanup;
383 	}
384 
385 	/* Now expect a font-family */
386 	error = css__parse_font_family(c, vector, ctx, family_style);
387 	if (error != CSS_OK)
388 		goto css__parse_font_cleanup;
389 
390 	/* defaults */
391 	if (style) {
392 		error = css__stylesheet_style_appendOPV(style_style,
393 				CSS_PROP_FONT_STYLE, 0,
394 				FONT_STYLE_NORMAL);
395 		if (error != CSS_OK)
396 			goto css__parse_font_cleanup;
397 	}
398 
399 	if (variant) {
400 		error = css__stylesheet_style_appendOPV(variant_style,
401 				CSS_PROP_FONT_VARIANT, 0,
402 				FONT_VARIANT_NORMAL);
403 		if (error != CSS_OK)
404 			goto css__parse_font_cleanup;
405 	}
406 
407 	if (weight) {
408 		error = css__stylesheet_style_appendOPV(weight_style,
409 				CSS_PROP_FONT_WEIGHT,
410 				0, FONT_WEIGHT_NORMAL);
411 		if (error != CSS_OK)
412 			goto css__parse_font_cleanup;
413 	}
414 
415 	if (line_height) {
416 		error = css__stylesheet_style_appendOPV(line_height_style,
417 				CSS_PROP_LINE_HEIGHT,
418 				0, LINE_HEIGHT_NORMAL);
419 		if (error != CSS_OK)
420 			goto css__parse_font_cleanup;
421 	}
422 
423 	/* merge final output */
424 	error = css__stylesheet_merge_style(result, style_style);
425 		if (error != CSS_OK)
426 			goto css__parse_font_cleanup;
427 
428 	error = css__stylesheet_merge_style(result, variant_style);
429 		if (error != CSS_OK)
430 			goto css__parse_font_cleanup;
431 
432 	error = css__stylesheet_merge_style(result, weight_style);
433 		if (error != CSS_OK)
434 			goto css__parse_font_cleanup;
435 
436 	error = css__stylesheet_merge_style(result, size_style);
437 		if (error != CSS_OK)
438 			goto css__parse_font_cleanup;
439 
440 	error = css__stylesheet_merge_style(result, line_height_style);
441 		if (error != CSS_OK)
442 			goto css__parse_font_cleanup;
443 
444 	error = css__stylesheet_merge_style(result, family_style);
445 
446 
447 
448 css__parse_font_cleanup:
449 	css__stylesheet_style_destroy(style_style);
450 	css__stylesheet_style_destroy(variant_style);
451 	css__stylesheet_style_destroy(weight_style);
452 	css__stylesheet_style_destroy(size_style);
453 	css__stylesheet_style_destroy(line_height_style);
454 	css__stylesheet_style_destroy(family_style);
455 
456 	if (error != CSS_OK)
457 		*ctx = orig_ctx;
458 
459 	return error;
460 }
461 
462 
463 
464 
465 
466 
467