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 elevation
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_elevation(css_language * c,const parserutils_vector * vector,int * ctx,css_style * result)30 css_error css__parse_elevation(css_language *c,
31 		const parserutils_vector *vector, int *ctx,
32 		css_style *result)
33 {
34 	int orig_ctx = *ctx;
35 	css_error error;
36 	const css_token *token;
37 	uint8_t flags = 0;
38 	uint16_t value = 0;
39 	css_fixed length = 0;
40 	uint32_t unit = 0;
41 	bool match;
42 
43 	/* angle | IDENT(below, level, above, higher, lower, inherit) */
44 	token = parserutils_vector_peek(vector, *ctx);
45 	if (token == NULL) {
46 		*ctx = orig_ctx;
47 		return CSS_INVALID;
48 	}
49 
50 	if (token->type == CSS_TOKEN_IDENT &&
51 		(lwc_string_caseless_isequal(
52 			token->idata, c->strings[INHERIT],
53 			&match) == lwc_error_ok && match)) {
54 		parserutils_vector_iterate(vector, ctx);
55 		flags = FLAG_INHERIT;
56 	} else if (token->type == CSS_TOKEN_IDENT &&
57 		(lwc_string_caseless_isequal(
58 			token->idata, c->strings[BELOW],
59 			&match) == lwc_error_ok && match)) {
60 		parserutils_vector_iterate(vector, ctx);
61 		value = ELEVATION_BELOW;
62 	} else if (token->type == CSS_TOKEN_IDENT &&
63 		(lwc_string_caseless_isequal(
64 			token->idata, c->strings[LEVEL],
65 			&match) == lwc_error_ok && match)) {
66 		parserutils_vector_iterate(vector, ctx);
67 		value = ELEVATION_LEVEL;
68 	} else if (token->type == CSS_TOKEN_IDENT &&
69 		(lwc_string_caseless_isequal(
70 			token->idata, c->strings[ABOVE],
71 			&match) == lwc_error_ok && match)) {
72 		parserutils_vector_iterate(vector, ctx);
73 		value = ELEVATION_ABOVE;
74 	} else if (token->type == CSS_TOKEN_IDENT &&
75 		(lwc_string_caseless_isequal(
76 			token->idata, c->strings[HIGHER],
77 			&match) == lwc_error_ok && match)) {
78 		parserutils_vector_iterate(vector, ctx);
79 		value = ELEVATION_HIGHER;
80 	} else if (token->type == CSS_TOKEN_IDENT &&
81 		(lwc_string_caseless_isequal(
82 			token->idata, c->strings[LOWER],
83 			&match) == lwc_error_ok && match)) {
84 		parserutils_vector_iterate(vector, ctx);
85 		value = ELEVATION_LOWER;
86 	} else {
87 		error = css__parse_unit_specifier(c, vector, ctx, UNIT_DEG,
88 				&length, &unit);
89 		if (error != CSS_OK) {
90 			*ctx = orig_ctx;
91 			return error;
92 		}
93 
94 		if ((unit & UNIT_ANGLE) == false) {
95 			*ctx = orig_ctx;
96 			return CSS_INVALID;
97 		}
98 
99 		/* Valid angles lie between -90 and 90 degrees */
100 		if (unit == UNIT_DEG) {
101 			if (length < -F_90 || length > F_90) {
102 				*ctx = orig_ctx;
103 				return CSS_INVALID;
104 			}
105 		} else if (unit == UNIT_GRAD) {
106 			if (length < -F_100 || length > F_100) {
107 				*ctx = orig_ctx;
108 				return CSS_INVALID;
109 			}
110 		} else if (unit == UNIT_RAD) {
111 			if (length < -F_PI_2 || length > F_PI_2) {
112 				*ctx = orig_ctx;
113 				return CSS_INVALID;
114 			}
115 		}
116 
117 		value = ELEVATION_ANGLE;
118 	}
119 
120 	error = css__stylesheet_style_appendOPV(result, CSS_PROP_ELEVATION, flags, value);
121 	if (error != CSS_OK) {
122 		*ctx = orig_ctx;
123 		return error;
124 	}
125 
126 	if (((flags & FLAG_INHERIT) == false) && (value == ELEVATION_ANGLE)) {
127 		error = css__stylesheet_style_vappend(result, 2, length, unit);
128 		if (error != CSS_OK) {
129 			*ctx = orig_ctx;
130 			return error;
131 		}
132 	}
133 
134 	return CSS_OK;
135 }
136