Bug Summary

File:parse/properties/utils.c
Warning:line 373, column 7
1st function call argument is an uninitialized value

Annotated Source Code

Press '?' to see keyboard shortcuts

clang -cc1 -cc1 -triple x86_64-pc-linux-gnu -analyze -disable-free -clear-ast-before-backend -disable-llvm-verifier -discard-value-names -main-file-name utils.c -analyzer-checker=core -analyzer-checker=apiModeling -analyzer-checker=unix -analyzer-checker=deadcode -analyzer-checker=security.insecureAPI.UncheckedReturn -analyzer-checker=security.insecureAPI.getpw -analyzer-checker=security.insecureAPI.gets -analyzer-checker=security.insecureAPI.mktemp -analyzer-checker=security.insecureAPI.mkstemp -analyzer-checker=security.insecureAPI.vfork -analyzer-checker=nullability.NullPassedToNonnull -analyzer-checker=nullability.NullReturnedFromNonnull -analyzer-output plist -w -setup-static-analyzer -mrelocation-model pic -pic-level 2 -pic-is-pie -mframe-pointer=none -fmath-errno -ffp-contract=on -fno-rounding-math -mconstructor-aliases -funwind-tables=2 -target-cpu x86-64 -tune-cpu generic -debugger-tuning=gdb -fdebug-compilation-dir=/var/lib/jenkins/workspace/scan-build-libcss -fcoverage-compilation-dir=/var/lib/jenkins/workspace/scan-build-libcss -resource-dir /usr/lib/llvm-19/lib/clang/19 -D _BSD_SOURCE -D _DEFAULT_SOURCE -I /var/lib/jenkins/workspace/scan-build-libcss/include/ -I /var/lib/jenkins/workspace/scan-build-libcss/src -D _ALIGNED=__attribute__((aligned)) -D STMTEXPR=1 -D DEBUG -I /var/lib/jenkins/artifacts-x86_64-linux-gnu/include -internal-isystem /usr/lib/llvm-19/lib/clang/19/include -internal-isystem /usr/local/include -internal-isystem /usr/lib/gcc/x86_64-linux-gnu/14/../../../../x86_64-linux-gnu/include -internal-externc-isystem /usr/include/x86_64-linux-gnu -internal-externc-isystem /include -internal-externc-isystem /usr/include -Og -Wwrite-strings -Wno-error -std=c99 -fconst-strings -ferror-limit 19 -fgnuc-version=4.2.1 -fskip-odr-check-in-gmf -analyzer-display-progress -analyzer-output=html -faddrsig -D__GCC_HAVE_DWARF2_CFI_ASM=1 -o /var/lib/jenkins/workspace/scan-build-libcss/clangScanBuildReports/2025-11-29-162650-2786852-1 -x c src/parse/properties/utils.c
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#include <strings.h>
11
12#include "stylesheet.h"
13#include "bytecode/bytecode.h"
14#include "bytecode/opcodes.h"
15#include "parse/properties/properties.h"
16#include "parse/properties/utils.h"
17#include "utils/parserutilserror.h"
18
19
20/**
21 * Parse list-style-type value
22 *
23 * \param c Parsing context
24 * \param ident Identifier to consider
25 * \param value Pointer to location to receive value
26 * \return CSS_OK on success,
27 * CSS_INVALID if the input is not valid
28 */
29css_error css__parse_list_style_type_value(css_language *c, const css_token *ident,
30 uint16_t *value)
31{
32 /* IDENT (disc, circle, square, decimal, decimal-leading-zero,
33 * lower-roman, upper-roman, lower-greek, lower-latin,
34 * upper-latin, armenian, georgian, lower-alpha, upper-alpha,
35 * none)
36 */
37 #define MAP_ENTRIES52 52
38 bool_Bool match;
39 int midx;
40 const struct {
41 int stringid;
42 int value;
43 } mapping[MAP_ENTRIES52] = {
44 { DISC, LIST_STYLE_TYPE_DISC },
45 { CIRCLE, LIST_STYLE_TYPE_CIRCLE },
46 { SQUARE, LIST_STYLE_TYPE_SQUARE },
47 { DECIMAL, LIST_STYLE_TYPE_DECIMAL },
48 { DECIMAL_LEADING_ZERO, LIST_STYLE_TYPE_DECIMAL_LEADING_ZERO },
49 { LOWER_ROMAN, LIST_STYLE_TYPE_LOWER_ROMAN },
50 { UPPER_ROMAN, LIST_STYLE_TYPE_UPPER_ROMAN },
51 { LOWER_GREEK, LIST_STYLE_TYPE_LOWER_GREEK },
52 { LOWER_LATIN, LIST_STYLE_TYPE_LOWER_LATIN },
53 { UPPER_LATIN, LIST_STYLE_TYPE_UPPER_LATIN },
54 { ARMENIAN, LIST_STYLE_TYPE_ARMENIAN },
55 { GEORGIAN, LIST_STYLE_TYPE_GEORGIAN },
56 { LOWER_ALPHA, LIST_STYLE_TYPE_LOWER_ALPHA },
57 { UPPER_ALPHA, LIST_STYLE_TYPE_UPPER_ALPHA },
58 { NONE, LIST_STYLE_TYPE_NONE },
59 { BINARY, LIST_STYLE_TYPE_BINARY },
60 { OCTAL, LIST_STYLE_TYPE_OCTAL},
61 { LOWER_HEXADECIMAL, LIST_STYLE_TYPE_LOWER_HEXADECIMAL },
62 { UPPER_HEXADECIMAL, LIST_STYLE_TYPE_UPPER_HEXADECIMAL },
63 { ARABIC_INDIC, LIST_STYLE_TYPE_ARABIC_INDIC },
64 { LOWER_ARMENIAN, LIST_STYLE_TYPE_LOWER_ARMENIAN },
65 { UPPER_ARMENIAN, LIST_STYLE_TYPE_UPPER_ARMENIAN },
66 { BENGALI, LIST_STYLE_TYPE_BENGALI },
67 { CAMBODIAN, LIST_STYLE_TYPE_CAMBODIAN },
68 { KHMER, LIST_STYLE_TYPE_KHMER },
69 { CJK_DECIMAL, LIST_STYLE_TYPE_CJK_DECIMAL },
70 { DEVANAGARI, LIST_STYLE_TYPE_DEVANAGARI },
71 { GUJARATI, LIST_STYLE_TYPE_GUJARATI },
72 { GURMUKHI, LIST_STYLE_TYPE_GURMUKHI },
73 { HEBREW, LIST_STYLE_TYPE_HEBREW },
74 { KANNADA, LIST_STYLE_TYPE_KANNADA },
75 { LAO, LIST_STYLE_TYPE_LAO },
76 { MALAYALAM, LIST_STYLE_TYPE_MALAYALAM },
77 { MONGOLIAN, LIST_STYLE_TYPE_MONGOLIAN },
78 { MYANMAR, LIST_STYLE_TYPE_MYANMAR },
79 { ORIYA, LIST_STYLE_TYPE_ORIYA },
80 { PERSIAN, LIST_STYLE_TYPE_PERSIAN },
81 { TAMIL, LIST_STYLE_TYPE_TAMIL },
82 { TELUGU, LIST_STYLE_TYPE_TELUGU },
83 { THAI, LIST_STYLE_TYPE_THAI },
84 { TIBETAN, LIST_STYLE_TYPE_TIBETAN },
85 { CJK_EARTHLY_BRANCH, LIST_STYLE_TYPE_CJK_EARTHLY_BRANCH },
86 { CJK_HEAVENLY_STEM, LIST_STYLE_TYPE_CJK_HEAVENLY_STEM },
87 { HIAGANA, LIST_STYLE_TYPE_HIAGANA },
88 { HIAGANA_IROHA, LIST_STYLE_TYPE_HIAGANA_IROHA },
89 { KATAKANA, LIST_STYLE_TYPE_KATAKANA },
90 { KATAKANA_IROHA, LIST_STYLE_TYPE_KATAKANA_IROHA },
91 { JAPANESE_INFORMAL, LIST_STYLE_TYPE_JAPANESE_INFORMAL },
92 { JAPANESE_FORMAL, LIST_STYLE_TYPE_JAPANESE_FORMAL },
93 { KOREAN_HANGUL_FORMAL, LIST_STYLE_TYPE_KOREAN_HANGUL_FORMAL },
94 { KOREAN_HANJA_INFORMAL, LIST_STYLE_TYPE_KOREAN_HANJA_INFORMAL },
95 { KOREAN_HANJA_FORMAL, LIST_STYLE_TYPE_KOREAN_HANJA_FORMAL }
96 };
97
98 for (midx = 0; midx < MAP_ENTRIES52; midx++) {
99 if ((lwc_string_caseless_isequal(({ lwc_error __lwc_err = lwc_error_ok; lwc_string *__lwc_str1
= (ident->idata); lwc_string *__lwc_str2 = (c->strings
[mapping[midx].stringid]); _Bool *__lwc_ret = (&match); if
(__lwc_str1->insensitive == ((void*)0)) { __lwc_err = lwc__intern_caseless_string
(__lwc_str1); } if (__lwc_err == lwc_error_ok && __lwc_str2
->insensitive == ((void*)0)) { __lwc_err = lwc__intern_caseless_string
(__lwc_str2); } if (__lwc_err == lwc_error_ok) *__lwc_ret = (
__lwc_str1->insensitive == __lwc_str2->insensitive); __lwc_err
; })
100 ident->idata,({ lwc_error __lwc_err = lwc_error_ok; lwc_string *__lwc_str1
= (ident->idata); lwc_string *__lwc_str2 = (c->strings
[mapping[midx].stringid]); _Bool *__lwc_ret = (&match); if
(__lwc_str1->insensitive == ((void*)0)) { __lwc_err = lwc__intern_caseless_string
(__lwc_str1); } if (__lwc_err == lwc_error_ok && __lwc_str2
->insensitive == ((void*)0)) { __lwc_err = lwc__intern_caseless_string
(__lwc_str2); } if (__lwc_err == lwc_error_ok) *__lwc_ret = (
__lwc_str1->insensitive == __lwc_str2->insensitive); __lwc_err
; })
101 c->strings[mapping[midx].stringid],({ lwc_error __lwc_err = lwc_error_ok; lwc_string *__lwc_str1
= (ident->idata); lwc_string *__lwc_str2 = (c->strings
[mapping[midx].stringid]); _Bool *__lwc_ret = (&match); if
(__lwc_str1->insensitive == ((void*)0)) { __lwc_err = lwc__intern_caseless_string
(__lwc_str1); } if (__lwc_err == lwc_error_ok && __lwc_str2
->insensitive == ((void*)0)) { __lwc_err = lwc__intern_caseless_string
(__lwc_str2); } if (__lwc_err == lwc_error_ok) *__lwc_ret = (
__lwc_str1->insensitive == __lwc_str2->insensitive); __lwc_err
; })
102 &match)({ lwc_error __lwc_err = lwc_error_ok; lwc_string *__lwc_str1
= (ident->idata); lwc_string *__lwc_str2 = (c->strings
[mapping[midx].stringid]); _Bool *__lwc_ret = (&match); if
(__lwc_str1->insensitive == ((void*)0)) { __lwc_err = lwc__intern_caseless_string
(__lwc_str1); } if (__lwc_err == lwc_error_ok && __lwc_str2
->insensitive == ((void*)0)) { __lwc_err = lwc__intern_caseless_string
(__lwc_str2); } if (__lwc_err == lwc_error_ok) *__lwc_ret = (
__lwc_str1->insensitive == __lwc_str2->insensitive); __lwc_err
; })
== lwc_error_ok && match)) {
103 *value = mapping[midx].value;
104 return CSS_OK;
105 }
106 }
107
108 return CSS_INVALID;
109}
110
111
112
113/**
114 * Parse border-{top,right,bottom,left} shorthand
115 *
116 * \param c Parsing context
117 * \param vector Vector of tokens to process
118 * \param ctx Pointer to vector iteration context
119 * \param side The side we're parsing for
120 * \param result Pointer to location to receive resulting style
121 * \return CSS_OK on success,
122 * CSS_NOMEM on memory exhaustion,
123 * CSS_INVALID if the input is not valid
124 *
125 * Post condition: \a *ctx is updated with the next token to process
126 * If the input is invalid, then \a *ctx remains unchanged.
127 */
128css_error css__parse_border_side(css_language *c,
129 const parserutils_vector *vector, int32_t *ctx,
130 css_style *result, enum border_side_e side)
131{
132 int32_t orig_ctx = *ctx;
133 int prev_ctx;
134 const css_token *token;
135 css_error error = CSS_OK;
136 bool_Bool color = true1;
137 bool_Bool style = true1;
138 bool_Bool width = true1;
139 css_style *color_style;
140 css_style *style_style;
141 css_style *width_style;
142
143 /* Firstly, handle inherit */
144 token = parserutils_vector_peek(vector, *ctx);
145 if (token == NULL((void*)0))
146 return CSS_INVALID;
147
148 if (is_css_inherit(c, token)) {
149 error = css_stylesheet_style_inherit(result, CSS_PROP_BORDER_TOP_COLOR + side);
150 if (error != CSS_OK)
151 return error;
152
153 error = css_stylesheet_style_inherit(result, CSS_PROP_BORDER_TOP_STYLE + side);
154 if (error != CSS_OK)
155 return error;
156
157 error = css_stylesheet_style_inherit(result, CSS_PROP_BORDER_TOP_WIDTH + side);
158 if (error == CSS_OK)
159 parserutils_vector_iterate(vector, ctx);
160
161 return error;
162 }
163
164 /* allocate styles */
165 error = css__stylesheet_style_create(c->sheet, &color_style);
166 if (error != CSS_OK)
167 return error;
168
169 error = css__stylesheet_style_create(c->sheet, &style_style);
170 if (error != CSS_OK) {
171 css__stylesheet_style_destroy(color_style);
172 return error;
173 }
174
175 error = css__stylesheet_style_create(c->sheet, &width_style);
176 if (error != CSS_OK) {
177 css__stylesheet_style_destroy(color_style);
178 css__stylesheet_style_destroy(style_style);
179 return error;
180 }
181
182 /* Attempt to parse the various longhand properties */
183 do {
184 prev_ctx = *ctx;
185 error = CSS_OK;
186
187 /* Ensure that we're not about to parse another inherit */
188 token = parserutils_vector_peek(vector, *ctx);
189 if (token != NULL((void*)0) && is_css_inherit(c, token)) {
190 error = CSS_INVALID;
191 goto css__parse_border_side_cleanup;
192 }
193
194 /* Try each property parser in turn, but only if we
195 * haven't already got a value for this property.
196 */
197 if ((color) &&
198 (error = css__parse_border_side_color(c, vector, ctx,
199 color_style, CSS_PROP_BORDER_TOP_COLOR + side)) == CSS_OK) {
200 color = false0;
201 } else if ((style) &&
202 (error = css__parse_border_side_style(c, vector, ctx,
203 style_style, CSS_PROP_BORDER_TOP_STYLE + side)) == CSS_OK) {
204 style = false0;
205 } else if ((width) &&
206 (error = css__parse_border_side_width(c, vector, ctx,
207 width_style, CSS_PROP_BORDER_TOP_WIDTH + side)) == CSS_OK) {
208 width = false0;
209 }
210
211 if (error == CSS_OK) {
212 consumeWhitespace(vector, ctx);
213
214 token = parserutils_vector_peek(vector, *ctx);
215 } else {
216 /* Forcibly cause loop to exit */
217 token = NULL((void*)0);
218 }
219 } while (*ctx != prev_ctx && token != NULL((void*)0));
220
221 if (style) {
222 error = css__stylesheet_style_appendOPV(style_style,
223 CSS_PROP_BORDER_TOP_STYLE + side, 0,
224 BORDER_STYLE_NONE);
225 if (error != CSS_OK)
226 goto css__parse_border_side_cleanup;
227 }
228
229 if (width) {
230 error = css__stylesheet_style_appendOPV(width_style,
231 CSS_PROP_BORDER_TOP_WIDTH + side, 0,
232 BORDER_WIDTH_MEDIUM);
233 if (error != CSS_OK)
234 goto css__parse_border_side_cleanup;
235 }
236
237 if (color) {
238 error = css__stylesheet_style_appendOPV(color_style,
239 CSS_PROP_BORDER_TOP_COLOR + side, 0,
240 BORDER_COLOR_CURRENT_COLOR);
241 if (error != CSS_OK)
242 goto css__parse_border_side_cleanup;
243 }
244
245 error = css__stylesheet_merge_style(result, color_style);
246 if (error != CSS_OK)
247 goto css__parse_border_side_cleanup;
248
249 error = css__stylesheet_merge_style(result, style_style);
250 if (error != CSS_OK)
251 goto css__parse_border_side_cleanup;
252
253 error = css__stylesheet_merge_style(result, width_style);
254
255css__parse_border_side_cleanup:
256 css__stylesheet_style_destroy(color_style);
257 css__stylesheet_style_destroy(style_style);
258 css__stylesheet_style_destroy(width_style);
259
260 if (error != CSS_OK)
261 *ctx = orig_ctx;
262
263 return error;
264}
265
266/**
267 * Convert Hue Saturation Lightness value to RGB.
268 *
269 * \param[in] hue Hue in degrees 0..360
270 * \param[in] sat Saturation value in percent 0..100
271 * \param[in] lit Lightness value in percent 0..100
272 * \param[out] r red component (0..25500)
273 * \param[out] g green component (0..25500)
274 * \param[out] b blue component (0..25500)
275 */
276static void HSL_to_RGB_fixed(
277 css_fixed hue, css_fixed sat, css_fixed lit,
278 css_fixed *r, css_fixed *g, css_fixed *b)
279{
280 css_fixed min_rgb, max_rgb, chroma;
281 css_fixed relative_hue, scaled_hue, mid1, mid2;
282 int sextant;
283
284#define ORGB(R, G, B) \
285 *r = FMUL((R), F_255)(css_multiply_fixed(((R)), (0x0003FC00))); \
286 *g = FMUL((G), F_255)(css_multiply_fixed(((G)), (0x0003FC00))); \
287 *b = FMUL((B), F_255)(css_multiply_fixed(((B)), (0x0003FC00)))
288
289 /* If saturation is zero there is no hue and r = g = b = lit */
290 if (sat == INTTOFIX(0)(css_int_to_fixed(0))) {
74
Assuming the condition is false
75
Taking false branch
291 ORGB(lit, lit, lit);
292 return;
293 }
294
295 /* Compute max(r,g,b) */
296 if (lit <= INTTOFIX(50)(css_int_to_fixed(50))) {
76
Assuming the condition is false
77
Taking false branch
297 max_rgb = FDIV(FMUL(lit, FADD(sat, F_100)), F_100)(css_divide_fixed(((css_multiply_fixed((lit), ((css_add_fixed
((sat), (0x00019000))))))), (0x00019000)))
;
298 } else {
299 max_rgb = FDIV(FSUB(FMUL(FADD(lit, sat), F_100), FMUL(lit, sat)), F_100)(css_divide_fixed(((css_subtract_fixed(((css_multiply_fixed((
(css_add_fixed((lit), (sat)))), (0x00019000)))), ((css_multiply_fixed
((lit), (sat))))))), (0x00019000)))
;
300 }
301
302 /* Compute min(r,g,b) */
303 min_rgb = FSUB(FMUL(lit, INTTOFIX(2)), max_rgb)(css_subtract_fixed(((css_multiply_fixed((lit), ((css_int_to_fixed
(2)))))), (max_rgb)))
;
304
305 /* We know that the value of at least one of the components is
306 * max(r,g,b) and that the value of at least one of the other
307 * components is min(r,g,b).
308 *
309 * We can determine which components have these values by
310 * considering which the sextant of the hexcone the hue lies
311 * in:
312 *
313 * Sextant: max(r,g,b): min(r,g,b):
314 *
315 * 0 r b
316 * 1 g b
317 * 2 g r
318 * 3 b r
319 * 4 b g
320 * 5 r g
321 *
322 * Thus, we need only compute the value of the third component
323 */
324
325 /* Chroma is the difference between min and max */
326 chroma = FSUB(max_rgb, min_rgb)(css_subtract_fixed((max_rgb), (min_rgb)));
327
328 /* Compute which sextant the hue lies in (truncates result) */
329 hue = FDIV(FMUL(hue, INTTOFIX(6)), F_360)(css_divide_fixed(((css_multiply_fixed((hue), ((css_int_to_fixed
(6)))))), (0x0005a000)))
;
330 sextant = FIXTOINT(hue)((hue) >> 10);
331
332 /* Compute offset of hue from start of sextant */
333 relative_hue = FSUB(hue, INTTOFIX(sextant))(css_subtract_fixed((hue), ((css_int_to_fixed(sextant)))));
334
335 /* Scale offset by chroma */
336 scaled_hue = FMUL(relative_hue, chroma)(css_multiply_fixed((relative_hue), (chroma)));
337
338 /* Compute potential values of the third colour component */
339 mid1 = FADD(min_rgb, scaled_hue)(css_add_fixed((min_rgb), (scaled_hue)));
340 mid2 = FSUB(max_rgb, scaled_hue)(css_subtract_fixed((max_rgb), (scaled_hue)));
341
342 /* Populate result */
343 switch (sextant) {
78
'Default' branch taken. Execution continues on line 343
344 case 0: ORGB(max_rgb, mid1, min_rgb); break;
345 case 1: ORGB(mid2, max_rgb, min_rgb); break;
346 case 2: ORGB(min_rgb, max_rgb, mid1); break;
347 case 3: ORGB(min_rgb, mid2, max_rgb); break;
348 case 4: ORGB(mid1, min_rgb, max_rgb); break;
349 case 5: ORGB(max_rgb, min_rgb, mid2); break;
350 }
351
352#undef ORGB
353}
79
Returning without writing to '*r'
354
355/**
356 * Convert Hue Saturation Lightness value to RGB.
357 *
358 * \param hue Hue in degrees 0..360
359 * \param sat Saturation value in percent 0..100
360 * \param lit Lightness value in percent 0..100
361 * \param r red component
362 * \param g green component
363 * \param b blue component
364 */
365static void HSL_to_RGB(
366 css_fixed hue, css_fixed sat, css_fixed lit,
367 uint8_t *r, uint8_t *g, uint8_t *b)
368{
369 css_fixed rf, gf, bf;
72
'rf' declared without an initial value
370
371 HSL_to_RGB_fixed(hue, sat, lit, &rf, &gf, &bf);
73
Calling 'HSL_to_RGB_fixed'
80
Returning from 'HSL_to_RGB_fixed'
372
373 *r = FIXTOINT(FDIV(rf, F_100))(((css_divide_fixed((rf), (0x00019000)))) >> 10);
81
1st function call argument is an uninitialized value
374 *g = FIXTOINT(FDIV(gf, F_100))(((css_divide_fixed((gf), (0x00019000)))) >> 10);
375 *b = FIXTOINT(FDIV(bf, F_100))(((css_divide_fixed((bf), (0x00019000)))) >> 10);
376}
377
378/**
379 * Convert Hue Saturation Lightness value to RGB.
380 *
381 * \param hue Hue in degrees 0..360
382 * \param white Whiteness value in percent 0..100
383 * \param black Blackness value in percent 0..100
384 * \param r red component
385 * \param g green component
386 * \param b blue component
387 */
388static void HWB_to_RGB(
389 css_fixed hue, css_fixed white, css_fixed black,
390 uint8_t *r, uint8_t *g, uint8_t *b)
391{
392 if (FADD(white, black)(css_add_fixed((white), (black))) >= F_1000x00019000) {
393 css_fixed grey = (FDIV(FMUL(white, F_255), FADD(white, black))(css_divide_fixed(((css_multiply_fixed((white), (0x0003FC00))
)), ((css_add_fixed((white), (black))))))
);
394 uint8_t grey_int = FIXTOINT(grey)((grey) >> 10);
395
396 *r = grey_int;
397 *g = grey_int;
398 *b = grey_int;
399 } else {
400 css_fixed rf, gf, bf; // 0..25500
401 css_fixed val = FSUB(F_100, FADD(white, black))(css_subtract_fixed((0x00019000), ((css_add_fixed((white), (black
))))))
; // 0..100
402
403 HSL_to_RGB_fixed(hue, INTTOFIX(100)(css_int_to_fixed(100)), INTTOFIX(50)(css_int_to_fixed(50)),
404 &rf, &gf, &bf);
405
406 *r = FIXTOINT(FDIV(FADD(FMUL(FDIV(rf, F_100), val), FMUL(white, F_255)), F_100))(((css_divide_fixed(((css_add_fixed(((css_multiply_fixed(((css_divide_fixed
((rf), (0x00019000)))), (val)))), ((css_multiply_fixed((white
), (0x0003FC00))))))), (0x00019000)))) >> 10)
;
407 *g = FIXTOINT(FDIV(FADD(FMUL(FDIV(gf, F_100), val), FMUL(white, F_255)), F_100))(((css_divide_fixed(((css_add_fixed(((css_multiply_fixed(((css_divide_fixed
((gf), (0x00019000)))), (val)))), ((css_multiply_fixed((white
), (0x0003FC00))))))), (0x00019000)))) >> 10)
;
408 *b = FIXTOINT(FDIV(FADD(FMUL(FDIV(bf, F_100), val), FMUL(white, F_255)), F_100))(((css_divide_fixed(((css_add_fixed(((css_multiply_fixed(((css_divide_fixed
((bf), (0x00019000)))), (val)))), ((css_multiply_fixed((white
), (0x0003FC00))))))), (0x00019000)))) >> 10)
;
409 }
410}
411
412/**
413 * Parse a RGB(A) colour specifier
414 *
415 * It's up to the caller to reset the ctx if this fails.
416 *
417 * \param c Parsing context
418 * \param vector Vector of tokens to process
419 * \param ctx Pointer to vector iteration context
420 * \param result Pointer to location to receive result (AARRGGBB)
421 * \return true on success, false on error.
422 */
423static bool_Bool parse_rgb(
424 css_language *c,
425 const parserutils_vector *vector,
426 int32_t *ctx,
427 uint32_t *result)
428{
429 const css_token *token;
430 css_token_type valid = CSS_TOKEN_NUMBER;
431 uint8_t r = 0, g = 0, b = 0, a = 0xff;
432 uint8_t *components[4] = { &r, &g, &b, &a };
433 bool_Bool legacy = false0;
434 bool_Bool had_none = false0;
435
436 for (int i = 0; i < 4; i++) {
437 uint8_t *component;
438 css_fixed num;
439 size_t consumed = 0;
440 int32_t intval;
441 bool_Bool int_only;
442 bool_Bool match;
443
444 component = components[i];
445
446 consumeWhitespace(vector, ctx);
447
448 token = parserutils_vector_peek(vector, *ctx);
449 if (token == NULL((void*)0)) {
450 return false0;
451 } else if (!legacy && token->type == CSS_TOKEN_IDENT &&
452 lwc_string_caseless_isequal(({ lwc_error __lwc_err = lwc_error_ok; lwc_string *__lwc_str1
= (token->idata); lwc_string *__lwc_str2 = (c->strings
[NONE]); _Bool *__lwc_ret = (&match); if (__lwc_str1->
insensitive == ((void*)0)) { __lwc_err = lwc__intern_caseless_string
(__lwc_str1); } if (__lwc_err == lwc_error_ok && __lwc_str2
->insensitive == ((void*)0)) { __lwc_err = lwc__intern_caseless_string
(__lwc_str2); } if (__lwc_err == lwc_error_ok) *__lwc_ret = (
__lwc_str1->insensitive == __lwc_str2->insensitive); __lwc_err
; })
453 token->idata, c->strings[NONE],({ lwc_error __lwc_err = lwc_error_ok; lwc_string *__lwc_str1
= (token->idata); lwc_string *__lwc_str2 = (c->strings
[NONE]); _Bool *__lwc_ret = (&match); if (__lwc_str1->
insensitive == ((void*)0)) { __lwc_err = lwc__intern_caseless_string
(__lwc_str1); } if (__lwc_err == lwc_error_ok && __lwc_str2
->insensitive == ((void*)0)) { __lwc_err = lwc__intern_caseless_string
(__lwc_str2); } if (__lwc_err == lwc_error_ok) *__lwc_ret = (
__lwc_str1->insensitive == __lwc_str2->insensitive); __lwc_err
; })
454 &match)({ lwc_error __lwc_err = lwc_error_ok; lwc_string *__lwc_str1
= (token->idata); lwc_string *__lwc_str2 = (c->strings
[NONE]); _Bool *__lwc_ret = (&match); if (__lwc_str1->
insensitive == ((void*)0)) { __lwc_err = lwc__intern_caseless_string
(__lwc_str1); } if (__lwc_err == lwc_error_ok && __lwc_str2
->insensitive == ((void*)0)) { __lwc_err = lwc__intern_caseless_string
(__lwc_str2); } if (__lwc_err == lwc_error_ok) *__lwc_ret = (
__lwc_str1->insensitive == __lwc_str2->insensitive); __lwc_err
; })
== lwc_error_ok && match) {
455 had_none = true1;
456 } else {
457 if (token->type != CSS_TOKEN_NUMBER &&
458 token->type != CSS_TOKEN_PERCENTAGE) {
459 return false0;
460 }
461
462 if (i == 0) {
463 valid = token->type;
464 } else if (legacy && i < 3 && token->type != valid) {
465 return false0;
466 } else {
467 valid = token->type;
468 }
469
470 /* The alpha channel may be a float */
471 if (i < 3) {
472 int_only = (valid == CSS_TOKEN_NUMBER);
473 } else {
474 int_only = false0;
475 }
476
477 num = css__number_from_lwc_string(token->idata,
478 int_only, &consumed);
479 if (consumed != lwc_string_length(token->idata)({((token->idata != ((void*)0)) ? (void) (0) : __assert_fail
("token->idata != NULL", "src/parse/properties/utils.c", 479
, __extension__ __PRETTY_FUNCTION__)); (token->idata)->
len;})
) {
480 return false0;
481 }
482
483 if (valid == CSS_TOKEN_NUMBER) {
484 if (i == 3) {
485 /* alpha channel */
486 intval = FIXTOINT(FMUL(num, F_255))(((css_multiply_fixed((num), (0x0003FC00)))) >> 10);
487 } else {
488 /* colour channels */
489 intval = FIXTOINT(num)((num) >> 10);
490 }
491 } else {
492 intval = FIXTOINT((((css_divide_fixed(((css_multiply_fixed((num), (0x0003FC00))
)), (0x00019000)))) >> 10)
493 FDIV(FMUL(num, F_255), F_100))(((css_divide_fixed(((css_multiply_fixed((num), (0x0003FC00))
)), (0x00019000)))) >> 10)
;
494 }
495
496 if (intval > 255) {
497 *component = 255;
498 } else if (intval < 0) {
499 *component = 0;
500 } else {
501 *component = intval;
502 }
503 }
504
505 parserutils_vector_iterate(vector, ctx);
506
507 consumeWhitespace(vector, ctx);
508
509 token = parserutils_vector_peek(vector, *ctx);
510 if (token == NULL((void*)0)) {
511 return false0;
512 }
513
514 if (i == 0 && tokenIsChar(token, ',') && !had_none) {
515 legacy = true1;
516 }
517
518 if (i >= 2 && tokenIsChar(token, ')')) {
519 parserutils_vector_iterate(vector, ctx);
520 break;
521
522 } else if (legacy) {
523 if (!tokenIsChar(token, ',')) {
524 return false0;
525 }
526 parserutils_vector_iterate(vector, ctx);
527
528 } else if (i == 2) {
529 if (!tokenIsChar(token, '/')) {
530 return false0;
531 }
532 parserutils_vector_iterate(vector, ctx);
533 }
534 }
535
536 *result = ((unsigned)a << 24) | (r << 16) | (g << 8) | b;
537
538 return true1;
539}
540
541/**
542 * Parse a HSL(A) colour specifier (hue, saturation, lightness)
543 *
544 * It's up to the caller to reset the ctx if this fails.
545 *
546 * \param vector Vector of tokens to process
547 * \param ctx Pointer to vector iteration context
548 * \param result Pointer to location to receive result (AARRGGBB)
549 * \return true on success, false on error.
550 */
551static bool_Bool parse_hsl(
552 const parserutils_vector *vector,
553 int32_t *ctx,
554 uint32_t *result)
555{
556 const css_token *token;
557 size_t consumed = 0;
558 css_fixed hue, sat, lit;
559 int32_t alpha = 255;
560 bool_Bool legacy = false0;
561 css_error error;
562 uint8_t r = 0, g = 0, b = 0, a = 0xff;
563
564 /* hue is a number without a unit representing an
565 * angle (0-360) degrees, or it can be an angle dimension.
566 */
567 consumeWhitespace(vector, ctx);
568
569 token = parserutils_vector_iterate(vector, ctx);
570 if ((token == NULL((void*)0)) ||
30
Assuming 'token' is not equal to NULL
571 (token->type != CSS_TOKEN_NUMBER &&
31
Assuming field 'type' is equal to CSS_TOKEN_NUMBER
572 token->type != CSS_TOKEN_DIMENSION)) {
573 return false0;
574 }
575
576 hue = css__number_from_lwc_string(token->idata, false0, &consumed);
577
578 switch (token->type) {
32
Control jumps to 'case CSS_TOKEN_NUMBER:' at line 579
579 case CSS_TOKEN_NUMBER:
580 if (consumed != lwc_string_length(token->idata)({((token->idata != ((void*)0)) ? (void) (0) : __assert_fail
("token->idata != NULL", "src/parse/properties/utils.c", 580
, __extension__ __PRETTY_FUNCTION__)); (token->idata)->
len;})
) {
33
Assuming field 'idata' is not equal to null
34
'?' condition is true
35
Assuming the condition is false
36
Taking false branch
581 return false0; /* failed to consume the whole string as a number */
582 }
583 break;
584 case CSS_TOKEN_DIMENSION: {
585 size_t len = lwc_string_length(token->idata)({((token->idata != ((void*)0)) ? (void) (0) : __assert_fail
("token->idata != NULL", "src/parse/properties/utils.c", 585
, __extension__ __PRETTY_FUNCTION__)); (token->idata)->
len;})
;
586 const char *data = lwc_string_data(token->idata)({((token->idata != ((void*)0)) ? (void) (0) : __assert_fail
("token->idata != NULL", "src/parse/properties/utils.c", 586
, __extension__ __PRETTY_FUNCTION__)); (const char *)((token->
idata)+1);})
;
587 uint32_t unit = UNIT_DEG;
588
589 error = css__parse_unit_keyword(
590 data + consumed,
591 len - consumed,
592 &unit);
593 if (error != CSS_OK) {
594 return false0;
595 }
596
597 switch (unit) {
598 case UNIT_DEG:
599 break;
600 case UNIT_RAD:
601 hue = FDIV(FMUL(hue, F_180), F_PI)(css_divide_fixed(((css_multiply_fixed((hue), (0x0002d000))))
, (0x00000c91)))
;
602 break;
603 case UNIT_GRAD:
604 hue = FMUL(hue, FLTTOFIX(0.9))(css_multiply_fixed((hue), (((css_fixed) ((0.9) * (float) (1 <<
10))))))
;
605 break;
606 case UNIT_TURN:
607 hue = FMUL(hue, F_360)(css_multiply_fixed((hue), (0x0005a000)));
608 break;
609 default:
610 return false0;
611 }
612 }
613 break;
614 default:
615 return false0; /* unexpected token type */
616 }
617
618 /* Normalise hue to the range [0, 360) */
619 while (hue < 0)
37
Execution continues on line 619
38
Assuming 'hue' is >= 0
39
Loop condition is false. Execution continues on line 621
620 hue += F_3600x0005a000;
621 while (hue >= F_3600x0005a000)
40
Assuming 'hue' is < F_360
41
Loop condition is false. Execution continues on line 624
622 hue -= F_3600x0005a000;
623
624 consumeWhitespace(vector, ctx);
625
626 token = parserutils_vector_peek(vector, *ctx);
627 if (token == NULL((void*)0)) {
42
Assuming 'token' is not equal to NULL
43
Taking false branch
628 return false0;
629 }
630
631 if (tokenIsChar(token, ',')) {
44
Assuming the condition is false
45
Taking false branch
632 parserutils_vector_iterate(vector, ctx);
633 consumeWhitespace(vector, ctx);
634 legacy = true1;
635 }
636
637 /* saturation */
638 token = parserutils_vector_iterate(vector, ctx);
639 if (token == NULL((void*)0))
46
Assuming 'token' is not equal to NULL
640 return false0;
641
642 if ((token->type != CSS_TOKEN_PERCENTAGE) &&
47
Assuming field 'type' is equal to CSS_TOKEN_PERCENTAGE
643 (token->type != CSS_TOKEN_NUMBER || legacy)) {
644 return false0;
645 }
646
647 sat = css__number_from_lwc_string(token->idata, false0, &consumed);
648 if (consumed != lwc_string_length(token->idata)({((token->idata != ((void*)0)) ? (void) (0) : __assert_fail
("token->idata != NULL", "src/parse/properties/utils.c", 648
, __extension__ __PRETTY_FUNCTION__)); (token->idata)->
len;})
) {
48
Assuming field 'idata' is not equal to null
49
'?' condition is true
50
Assuming the condition is false
51
Taking false branch
649 /* failed to consume the whole string as a number */
650 return false0;
651 }
652
653 /* Normalise saturation to the range [0, 100] */
654 if (sat < INTTOFIX(0)(css_int_to_fixed(0)))
52
Assuming the condition is false
53
Taking false branch
655 sat = INTTOFIX(0)(css_int_to_fixed(0));
656 else if (sat > INTTOFIX(100)(css_int_to_fixed(100)))
54
Assuming the condition is false
55
Taking false branch
657 sat = INTTOFIX(100)(css_int_to_fixed(100));
658
659 consumeWhitespace(vector, ctx);
660
661 if (legacy
55.1
'legacy' is false
) {
56
Taking false branch
662 token = parserutils_vector_iterate(vector, ctx);
663 if (token == NULL((void*)0) || !tokenIsChar(token, ',')) {
664 return false0;
665 }
666
667 consumeWhitespace(vector, ctx);
668 }
669
670 /* lightness */
671 token = parserutils_vector_iterate(vector, ctx);
672 if (token == NULL((void*)0))
57
Assuming 'token' is not equal to NULL
673 return false0;
674
675 if ((token->type != CSS_TOKEN_PERCENTAGE) &&
58
Assuming field 'type' is equal to CSS_TOKEN_PERCENTAGE
676 (token->type != CSS_TOKEN_NUMBER || legacy)) {
677 return false0;
678 }
679
680 lit = css__number_from_lwc_string(token->idata, false0, &consumed);
681 if (consumed != lwc_string_length(token->idata)({((token->idata != ((void*)0)) ? (void) (0) : __assert_fail
("token->idata != NULL", "src/parse/properties/utils.c", 681
, __extension__ __PRETTY_FUNCTION__)); (token->idata)->
len;})
) {
59
Assuming field 'idata' is not equal to null
60
'?' condition is true
61
Assuming the condition is false
62
Taking false branch
682 /* failed to consume the whole string as a number */
683 return false0;
684 }
685
686 /* Normalise lightness to the range [0, 100] */
687 if (lit < INTTOFIX(0)(css_int_to_fixed(0)))
63
Assuming the condition is false
64
Taking false branch
688 lit = INTTOFIX(0)(css_int_to_fixed(0));
689 else if (lit > INTTOFIX(100)(css_int_to_fixed(100)))
65
Assuming the condition is false
66
Taking false branch
690 lit = INTTOFIX(100)(css_int_to_fixed(100));
691
692 consumeWhitespace(vector, ctx);
693
694 token = parserutils_vector_iterate(vector, ctx);
695
696 if (( legacy
66.1
'legacy' is false
&& tokenIsChar(token, ',')) ||
68
Taking false branch
697 (!legacy
66.2
'legacy' is false
&& tokenIsChar(token, '/'))) {
67
Assuming the condition is false
698 consumeWhitespace(vector, ctx);
699
700 token = parserutils_vector_iterate(vector, ctx);
701 if ((token == NULL((void*)0)) ||
702 (token->type != CSS_TOKEN_NUMBER &&
703 token->type != CSS_TOKEN_PERCENTAGE)) {
704 return false0;
705 }
706
707 alpha = css__number_from_lwc_string(token->idata, false0, &consumed);
708 if (consumed != lwc_string_length(token->idata)({((token->idata != ((void*)0)) ? (void) (0) : __assert_fail
("token->idata != NULL", "src/parse/properties/utils.c", 708
, __extension__ __PRETTY_FUNCTION__)); (token->idata)->
len;})
) {
709 /* failed to consume the whole string as a number */
710 return false0;
711 }
712
713 if (token->type == CSS_TOKEN_NUMBER) {
714 alpha = FIXTOINT(FMUL(alpha, F_255))(((css_multiply_fixed((alpha), (0x0003FC00)))) >> 10);
715 } else {
716 alpha = FIXTOINT(FDIV(FMUL(alpha, F_255), F_100))(((css_divide_fixed(((css_multiply_fixed((alpha), (0x0003FC00
)))), (0x00019000)))) >> 10)
;
717 }
718
719 consumeWhitespace(vector, ctx);
720
721 token = parserutils_vector_iterate(vector, ctx);
722 }
723
724 if (!tokenIsChar(token, ')'))
69
Assuming the condition is false
70
Taking false branch
725 return false0;
726
727 /* have a valid HSV entry, convert to RGB */
728 HSL_to_RGB(hue, sat, lit, &r, &g, &b);
71
Calling 'HSL_to_RGB'
729
730 /* apply alpha */
731 if (alpha > 255) {
732 a = 255;
733 } else if (alpha < 0) {
734 a = 0;
735 } else {
736 a = alpha;
737 }
738
739 *result = ((unsigned)a << 24) | (r << 16) | (g << 8) | b;
740 return true1;
741}
742
743/**
744 * Parse a HWB colour specifier (hue, whiteness, blackness)
745 *
746 * It's up to the caller to reset the ctx if this fails.
747 *
748 * \param vector Vector of tokens to process
749 * \param ctx Pointer to vector iteration context
750 * \param result Pointer to location to receive result (AARRGGBB)
751 * \return true on success, false on error.
752 */
753static bool_Bool parse_hwb(
754 const parserutils_vector *vector,
755 int32_t *ctx,
756 uint32_t *result)
757{
758 const css_token *token;
759 size_t consumed = 0;
760 css_fixed hue, white, black;
761 int32_t alpha = 255;
762 css_error error;
763 uint8_t r = 0, g = 0, b = 0, a = 0xff;
764
765 /* hue is a number without a unit representing an
766 * angle (0-360) degrees, or it can be an angle dimension.
767 */
768 consumeWhitespace(vector, ctx);
769
770 token = parserutils_vector_iterate(vector, ctx);
771 if ((token == NULL((void*)0)) ||
772 (token->type != CSS_TOKEN_NUMBER &&
773 token->type != CSS_TOKEN_DIMENSION)) {
774 return false0;
775 }
776
777 hue = css__number_from_lwc_string(token->idata, false0, &consumed);
778
779 switch (token->type) {
780 case CSS_TOKEN_NUMBER:
781 if (consumed != lwc_string_length(token->idata)({((token->idata != ((void*)0)) ? (void) (0) : __assert_fail
("token->idata != NULL", "src/parse/properties/utils.c", 781
, __extension__ __PRETTY_FUNCTION__)); (token->idata)->
len;})
) {
782 return false0; /* failed to consume the whole string as a number */
783 }
784 break;
785 case CSS_TOKEN_DIMENSION: {
786 size_t len = lwc_string_length(token->idata)({((token->idata != ((void*)0)) ? (void) (0) : __assert_fail
("token->idata != NULL", "src/parse/properties/utils.c", 786
, __extension__ __PRETTY_FUNCTION__)); (token->idata)->
len;})
;
787 const char *data = lwc_string_data(token->idata)({((token->idata != ((void*)0)) ? (void) (0) : __assert_fail
("token->idata != NULL", "src/parse/properties/utils.c", 787
, __extension__ __PRETTY_FUNCTION__)); (const char *)((token->
idata)+1);})
;
788 uint32_t unit = UNIT_DEG;
789
790 error = css__parse_unit_keyword(
791 data + consumed,
792 len - consumed,
793 &unit);
794 if (error != CSS_OK) {
795 return false0;
796 }
797
798 switch (unit) {
799 case UNIT_DEG:
800 break;
801 case UNIT_RAD:
802 hue = FDIV(FMUL(hue, F_180), F_PI)(css_divide_fixed(((css_multiply_fixed((hue), (0x0002d000))))
, (0x00000c91)))
;
803 break;
804 case UNIT_GRAD:
805 hue = FMUL(hue, FLTTOFIX(0.9))(css_multiply_fixed((hue), (((css_fixed) ((0.9) * (float) (1 <<
10))))))
;
806 break;
807 case UNIT_TURN:
808 hue = FMUL(hue, F_360)(css_multiply_fixed((hue), (0x0005a000)));
809 break;
810 default:
811 return false0;
812 }
813 }
814 break;
815 default:
816 return false0; /* unexpected token type */
817 }
818
819 /* Normalise hue to the range [0, 360) */
820 while (hue < 0)
821 hue += F_3600x0005a000;
822 while (hue >= F_3600x0005a000)
823 hue -= F_3600x0005a000;
824
825 consumeWhitespace(vector, ctx);
826
827 /* whiteness */
828 token = parserutils_vector_iterate(vector, ctx);
829 if (token == NULL((void*)0))
830 return false0;
831
832 if ((token->type != CSS_TOKEN_PERCENTAGE) &&
833 (token->type != CSS_TOKEN_NUMBER)) {
834 return false0;
835 }
836
837 white = css__number_from_lwc_string(token->idata, false0, &consumed);
838 if (consumed != lwc_string_length(token->idata)({((token->idata != ((void*)0)) ? (void) (0) : __assert_fail
("token->idata != NULL", "src/parse/properties/utils.c", 838
, __extension__ __PRETTY_FUNCTION__)); (token->idata)->
len;})
) {
839 /* failed to consume the whole string as a number */
840 return false0;
841 }
842
843 /* Normalise whiteness to the range [0, 100] */
844 if (white < INTTOFIX(0)(css_int_to_fixed(0)))
845 white = INTTOFIX(0)(css_int_to_fixed(0));
846 else if (white > INTTOFIX(100)(css_int_to_fixed(100)))
847 white = INTTOFIX(100)(css_int_to_fixed(100));
848
849 consumeWhitespace(vector, ctx);
850
851 /* blackness */
852 token = parserutils_vector_iterate(vector, ctx);
853 if (token == NULL((void*)0))
854 return false0;
855
856 if ((token->type != CSS_TOKEN_PERCENTAGE) &&
857 (token->type != CSS_TOKEN_NUMBER)) {
858 return false0;
859 }
860
861 black = css__number_from_lwc_string(token->idata, false0, &consumed);
862 if (consumed != lwc_string_length(token->idata)({((token->idata != ((void*)0)) ? (void) (0) : __assert_fail
("token->idata != NULL", "src/parse/properties/utils.c", 862
, __extension__ __PRETTY_FUNCTION__)); (token->idata)->
len;})
) {
863 /* failed to consume the whole string as a number */
864 return false0;
865 }
866
867 /* Normalise blackness to the range [0, 100] */
868 if (black < INTTOFIX(0)(css_int_to_fixed(0)))
869 black = INTTOFIX(0)(css_int_to_fixed(0));
870 else if (black > INTTOFIX(100)(css_int_to_fixed(100)))
871 black = INTTOFIX(100)(css_int_to_fixed(100));
872
873 consumeWhitespace(vector, ctx);
874
875 token = parserutils_vector_iterate(vector, ctx);
876
877 if (tokenIsChar(token, '/')) {
878 consumeWhitespace(vector, ctx);
879
880 token = parserutils_vector_iterate(vector, ctx);
881 if ((token == NULL((void*)0)) ||
882 (token->type != CSS_TOKEN_NUMBER &&
883 token->type != CSS_TOKEN_PERCENTAGE)) {
884 return false0;
885 }
886
887 alpha = css__number_from_lwc_string(token->idata, false0, &consumed);
888 if (consumed != lwc_string_length(token->idata)({((token->idata != ((void*)0)) ? (void) (0) : __assert_fail
("token->idata != NULL", "src/parse/properties/utils.c", 888
, __extension__ __PRETTY_FUNCTION__)); (token->idata)->
len;})
) {
889 /* failed to consume the whole string as a number */
890 return false0;
891 }
892
893 if (token->type == CSS_TOKEN_NUMBER) {
894 alpha = FIXTOINT(FMUL(alpha, F_255))(((css_multiply_fixed((alpha), (0x0003FC00)))) >> 10);
895 } else {
896 alpha = FIXTOINT(FDIV(FMUL(alpha, F_255), F_100))(((css_divide_fixed(((css_multiply_fixed((alpha), (0x0003FC00
)))), (0x00019000)))) >> 10)
;
897 }
898
899 consumeWhitespace(vector, ctx);
900
901 token = parserutils_vector_iterate(vector, ctx);
902 }
903
904 if (!tokenIsChar(token, ')'))
905 return false0;
906
907 /* have a valid HSV entry, convert to RGB */
908 HWB_to_RGB(hue, white, black, &r, &g, &b);
909
910 /* apply alpha */
911 if (alpha > 255) {
912 a = 255;
913 } else if (alpha < 0) {
914 a = 0;
915 } else {
916 a = alpha;
917 }
918
919 *result = ((unsigned)a << 24) | (r << 16) | (g << 8) | b;
920 return true1;
921}
922
923/**
924 * Parse a colour specifier
925 *
926 * \param c Parsing context
927 * \param vector Vector of tokens to process
928 * \param ctx Pointer to vector iteration context
929 * \param value Pointer to location to receive value
930 * \param result Pointer to location to receive result (AARRGGBB)
931 * \return CSS_OK on success,
932 * CSS_INVALID if the input is invalid
933 *
934 * Post condition: \a *ctx is updated with the next token to process
935 * If the input is invalid, then \a *ctx remains unchanged.
936 */
937css_error css__parse_colour_specifier(css_language *c,
1
[debug] analyzing from css__parse_colour_specifier
938 const parserutils_vector *vector, int32_t *ctx,
939 uint16_t *value, uint32_t *result)
940{
941 int32_t orig_ctx = *ctx;
942 const css_token *token;
943 bool_Bool match;
944 css_error error;
945
946 consumeWhitespace(vector, ctx);
947
948 /* IDENT(<colour name>) |
949 * HASH(rgb | rgba | rrggbb | rrggbbaa) |
950 * FUNCTION(rgb) [ [ NUMBER | PERCENTAGE ] ',' ] {3} ')'
951 * FUNCTION(rgba) [ [ NUMBER | PERCENTAGE ] ',' ] {4} ')'
952 * FUNCTION(hsl) ANGLE ',' PERCENTAGE ',' PERCENTAGE ')'
953 * FUNCTION(hsla) ANGLE ',' PERCENTAGE ',' PERCENTAGE ',' NUMBER ')'
954 *
955 * For quirks, NUMBER | DIMENSION | IDENT, too
956 * I.E. "123456" -> NUMBER, "1234f0" -> DIMENSION, "f00000" -> IDENT
957 */
958 token = parserutils_vector_iterate(vector, ctx);
959 if (token == NULL((void*)0) || (token->type != CSS_TOKEN_IDENT &&
2
Assuming 'token' is not equal to NULL
3
Assuming field 'type' is not equal to CSS_TOKEN_IDENT
6
Taking false branch
960 token->type != CSS_TOKEN_HASH &&
4
Assuming field 'type' is not equal to CSS_TOKEN_HASH
961 token->type != CSS_TOKEN_FUNCTION)) {
5
Assuming field 'type' is equal to CSS_TOKEN_FUNCTION
962 if (c->sheet->quirks_allowed == false0 ||
963 token == NULL((void*)0) ||
964 (token->type != CSS_TOKEN_NUMBER &&
965 token->type != CSS_TOKEN_DIMENSION))
966 goto invalid;
967 }
968
969 if (token->type
6.1
Field 'type' is not equal to CSS_TOKEN_IDENT
== CSS_TOKEN_IDENT) {
7
Taking false branch
970 if ((lwc_string_caseless_isequal(({ lwc_error __lwc_err = lwc_error_ok; lwc_string *__lwc_str1
= (token->idata); lwc_string *__lwc_str2 = (c->strings
[TRANSPARENT]); _Bool *__lwc_ret = (&match); if (__lwc_str1
->insensitive == ((void*)0)) { __lwc_err = lwc__intern_caseless_string
(__lwc_str1); } if (__lwc_err == lwc_error_ok && __lwc_str2
->insensitive == ((void*)0)) { __lwc_err = lwc__intern_caseless_string
(__lwc_str2); } if (__lwc_err == lwc_error_ok) *__lwc_ret = (
__lwc_str1->insensitive == __lwc_str2->insensitive); __lwc_err
; })
971 token->idata, c->strings[TRANSPARENT],({ lwc_error __lwc_err = lwc_error_ok; lwc_string *__lwc_str1
= (token->idata); lwc_string *__lwc_str2 = (c->strings
[TRANSPARENT]); _Bool *__lwc_ret = (&match); if (__lwc_str1
->insensitive == ((void*)0)) { __lwc_err = lwc__intern_caseless_string
(__lwc_str1); } if (__lwc_err == lwc_error_ok && __lwc_str2
->insensitive == ((void*)0)) { __lwc_err = lwc__intern_caseless_string
(__lwc_str2); } if (__lwc_err == lwc_error_ok) *__lwc_ret = (
__lwc_str1->insensitive == __lwc_str2->insensitive); __lwc_err
; })
972 &match)({ lwc_error __lwc_err = lwc_error_ok; lwc_string *__lwc_str1
= (token->idata); lwc_string *__lwc_str2 = (c->strings
[TRANSPARENT]); _Bool *__lwc_ret = (&match); if (__lwc_str1
->insensitive == ((void*)0)) { __lwc_err = lwc__intern_caseless_string
(__lwc_str1); } if (__lwc_err == lwc_error_ok && __lwc_str2
->insensitive == ((void*)0)) { __lwc_err = lwc__intern_caseless_string
(__lwc_str2); } if (__lwc_err == lwc_error_ok) *__lwc_ret = (
__lwc_str1->insensitive == __lwc_str2->insensitive); __lwc_err
; })
== lwc_error_ok && match)) {
973 *value = COLOR_TRANSPARENT;
974 *result = 0; /* black transparent */
975 return CSS_OK;
976 } else if ((lwc_string_caseless_isequal(({ lwc_error __lwc_err = lwc_error_ok; lwc_string *__lwc_str1
= (token->idata); lwc_string *__lwc_str2 = (c->strings
[CURRENTCOLOR]); _Bool *__lwc_ret = (&match); if (__lwc_str1
->insensitive == ((void*)0)) { __lwc_err = lwc__intern_caseless_string
(__lwc_str1); } if (__lwc_err == lwc_error_ok && __lwc_str2
->insensitive == ((void*)0)) { __lwc_err = lwc__intern_caseless_string
(__lwc_str2); } if (__lwc_err == lwc_error_ok) *__lwc_ret = (
__lwc_str1->insensitive == __lwc_str2->insensitive); __lwc_err
; })
977 token->idata, c->strings[CURRENTCOLOR],({ lwc_error __lwc_err = lwc_error_ok; lwc_string *__lwc_str1
= (token->idata); lwc_string *__lwc_str2 = (c->strings
[CURRENTCOLOR]); _Bool *__lwc_ret = (&match); if (__lwc_str1
->insensitive == ((void*)0)) { __lwc_err = lwc__intern_caseless_string
(__lwc_str1); } if (__lwc_err == lwc_error_ok && __lwc_str2
->insensitive == ((void*)0)) { __lwc_err = lwc__intern_caseless_string
(__lwc_str2); } if (__lwc_err == lwc_error_ok) *__lwc_ret = (
__lwc_str1->insensitive == __lwc_str2->insensitive); __lwc_err
; })
978 &match)({ lwc_error __lwc_err = lwc_error_ok; lwc_string *__lwc_str1
= (token->idata); lwc_string *__lwc_str2 = (c->strings
[CURRENTCOLOR]); _Bool *__lwc_ret = (&match); if (__lwc_str1
->insensitive == ((void*)0)) { __lwc_err = lwc__intern_caseless_string
(__lwc_str1); } if (__lwc_err == lwc_error_ok && __lwc_str2
->insensitive == ((void*)0)) { __lwc_err = lwc__intern_caseless_string
(__lwc_str2); } if (__lwc_err == lwc_error_ok) *__lwc_ret = (
__lwc_str1->insensitive == __lwc_str2->insensitive); __lwc_err
; })
== lwc_error_ok && match)) {
979 *value = COLOR_CURRENT_COLOR;
980 *result = 0;
981 return CSS_OK;
982 }
983
984 error = css__parse_named_colour(c, token->idata, result);
985 if (error != CSS_OK && c->sheet->quirks_allowed) {
986 error = css__parse_hash_colour(token->idata, result);
987 if (error == CSS_OK)
988 c->sheet->quirks_used = true1;
989 }
990
991 if (error != CSS_OK)
992 goto invalid;
993 } else if (token->type
7.1
Field 'type' is not equal to CSS_TOKEN_HASH
== CSS_TOKEN_HASH) {
994 error = css__parse_hash_colour(token->idata, result);
995 if (error != CSS_OK)
996 goto invalid;
997 } else if (c->sheet->quirks_allowed &&
8
Assuming field 'quirks_allowed' is false
998 token->type == CSS_TOKEN_NUMBER) {
999 error = css__parse_hash_colour(token->idata, result);
1000 if (error == CSS_OK)
1001 c->sheet->quirks_used = true1;
1002 else
1003 goto invalid;
1004 } else if (c->sheet->quirks_allowed
8.1
Field 'quirks_allowed' is false
&&
1005 token->type == CSS_TOKEN_DIMENSION) {
1006 error = css__parse_hash_colour(token->idata, result);
1007 if (error == CSS_OK)
1008 c->sheet->quirks_used = true1;
1009 else
1010 goto invalid;
1011 } else if (token->type
8.2
Field 'type' is equal to CSS_TOKEN_FUNCTION
== CSS_TOKEN_FUNCTION) {
9
Taking true branch
1012 if ((lwc_string_caseless_isequal(({ lwc_error __lwc_err = lwc_error_ok; lwc_string *__lwc_str1
= (token->idata); lwc_string *__lwc_str2 = (c->strings
[RGB]); _Bool *__lwc_ret = (&match); if (__lwc_str1->insensitive
== ((void*)0)) { __lwc_err = lwc__intern_caseless_string(__lwc_str1
); } if (__lwc_err == lwc_error_ok && __lwc_str2->
insensitive == ((void*)0)) { __lwc_err = lwc__intern_caseless_string
(__lwc_str2); } if (__lwc_err == lwc_error_ok) *__lwc_ret = (
__lwc_str1->insensitive == __lwc_str2->insensitive); __lwc_err
; })
10
Assuming field 'insensitive' is not equal to null
11
Taking false branch
12
Assuming field 'insensitive' is not equal to null
13
Taking false branch
14
Taking true branch
15
Assuming '' is not equal to ''
16
Taking false branch
1013 token->idata, c->strings[RGB],({ lwc_error __lwc_err = lwc_error_ok; lwc_string *__lwc_str1
= (token->idata); lwc_string *__lwc_str2 = (c->strings
[RGB]); _Bool *__lwc_ret = (&match); if (__lwc_str1->insensitive
== ((void*)0)) { __lwc_err = lwc__intern_caseless_string(__lwc_str1
); } if (__lwc_err == lwc_error_ok && __lwc_str2->
insensitive == ((void*)0)) { __lwc_err = lwc__intern_caseless_string
(__lwc_str2); } if (__lwc_err == lwc_error_ok) *__lwc_ret = (
__lwc_str1->insensitive == __lwc_str2->insensitive); __lwc_err
; })
1014 &match)({ lwc_error __lwc_err = lwc_error_ok; lwc_string *__lwc_str1
= (token->idata); lwc_string *__lwc_str2 = (c->strings
[RGB]); _Bool *__lwc_ret = (&match); if (__lwc_str1->insensitive
== ((void*)0)) { __lwc_err = lwc__intern_caseless_string(__lwc_str1
); } if (__lwc_err == lwc_error_ok && __lwc_str2->
insensitive == ((void*)0)) { __lwc_err = lwc__intern_caseless_string
(__lwc_str2); } if (__lwc_err == lwc_error_ok) *__lwc_ret = (
__lwc_str1->insensitive == __lwc_str2->insensitive); __lwc_err
; })
== lwc_error_ok && match
15.1
'match' is false
)) {
1015 if (!parse_rgb(c, vector, ctx, result)) {
1016 goto invalid;
1017 }
1018 } else if ((lwc_string_caseless_isequal(({ lwc_error __lwc_err = lwc_error_ok; lwc_string *__lwc_str1
= (token->idata); lwc_string *__lwc_str2 = (c->strings
[RGBA]); _Bool *__lwc_ret = (&match); if (__lwc_str1->
insensitive == ((void*)0)) { __lwc_err = lwc__intern_caseless_string
(__lwc_str1); } if (__lwc_err == lwc_error_ok && __lwc_str2
->insensitive == ((void*)0)) { __lwc_err = lwc__intern_caseless_string
(__lwc_str2); } if (__lwc_err == lwc_error_ok) *__lwc_ret = (
__lwc_str1->insensitive == __lwc_str2->insensitive); __lwc_err
; })
17
Taking false branch
18
Assuming field 'insensitive' is not equal to null
19
Taking false branch
20
Taking true branch
21
Assuming '' is not equal to ''
22
Taking false branch
1019 token->idata, c->strings[RGBA],({ lwc_error __lwc_err = lwc_error_ok; lwc_string *__lwc_str1
= (token->idata); lwc_string *__lwc_str2 = (c->strings
[RGBA]); _Bool *__lwc_ret = (&match); if (__lwc_str1->
insensitive == ((void*)0)) { __lwc_err = lwc__intern_caseless_string
(__lwc_str1); } if (__lwc_err == lwc_error_ok && __lwc_str2
->insensitive == ((void*)0)) { __lwc_err = lwc__intern_caseless_string
(__lwc_str2); } if (__lwc_err == lwc_error_ok) *__lwc_ret = (
__lwc_str1->insensitive == __lwc_str2->insensitive); __lwc_err
; })
1020 &match)({ lwc_error __lwc_err = lwc_error_ok; lwc_string *__lwc_str1
= (token->idata); lwc_string *__lwc_str2 = (c->strings
[RGBA]); _Bool *__lwc_ret = (&match); if (__lwc_str1->
insensitive == ((void*)0)) { __lwc_err = lwc__intern_caseless_string
(__lwc_str1); } if (__lwc_err == lwc_error_ok && __lwc_str2
->insensitive == ((void*)0)) { __lwc_err = lwc__intern_caseless_string
(__lwc_str2); } if (__lwc_err == lwc_error_ok) *__lwc_ret = (
__lwc_str1->insensitive == __lwc_str2->insensitive); __lwc_err
; })
== lwc_error_ok && match
21.1
'match' is false
)) {
1021 if (!parse_rgb(c, vector, ctx, result)) {
1022 goto invalid;
1023 }
1024 } else if ((lwc_string_caseless_isequal(({ lwc_error __lwc_err = lwc_error_ok; lwc_string *__lwc_str1
= (token->idata); lwc_string *__lwc_str2 = (c->strings
[HSL]); _Bool *__lwc_ret = (&match); if (__lwc_str1->insensitive
== ((void*)0)) { __lwc_err = lwc__intern_caseless_string(__lwc_str1
); } if (__lwc_err == lwc_error_ok && __lwc_str2->
insensitive == ((void*)0)) { __lwc_err = lwc__intern_caseless_string
(__lwc_str2); } if (__lwc_err == lwc_error_ok) *__lwc_ret = (
__lwc_str1->insensitive == __lwc_str2->insensitive); __lwc_err
; })
23
Taking false branch
24
Assuming field 'insensitive' is not equal to null
25
Taking false branch
26
Taking true branch
27
Assuming '' is equal to ''
28
Taking true branch
1025 token->idata, c->strings[HSL],({ lwc_error __lwc_err = lwc_error_ok; lwc_string *__lwc_str1
= (token->idata); lwc_string *__lwc_str2 = (c->strings
[HSL]); _Bool *__lwc_ret = (&match); if (__lwc_str1->insensitive
== ((void*)0)) { __lwc_err = lwc__intern_caseless_string(__lwc_str1
); } if (__lwc_err == lwc_error_ok && __lwc_str2->
insensitive == ((void*)0)) { __lwc_err = lwc__intern_caseless_string
(__lwc_str2); } if (__lwc_err == lwc_error_ok) *__lwc_ret = (
__lwc_str1->insensitive == __lwc_str2->insensitive); __lwc_err
; })
1026 &match)({ lwc_error __lwc_err = lwc_error_ok; lwc_string *__lwc_str1
= (token->idata); lwc_string *__lwc_str2 = (c->strings
[HSL]); _Bool *__lwc_ret = (&match); if (__lwc_str1->insensitive
== ((void*)0)) { __lwc_err = lwc__intern_caseless_string(__lwc_str1
); } if (__lwc_err == lwc_error_ok && __lwc_str2->
insensitive == ((void*)0)) { __lwc_err = lwc__intern_caseless_string
(__lwc_str2); } if (__lwc_err == lwc_error_ok) *__lwc_ret = (
__lwc_str1->insensitive == __lwc_str2->insensitive); __lwc_err
; })
== lwc_error_ok && match
27.1
'match' is true
)) {
1027 if (!parse_hsl(vector, ctx, result)) {
29
Calling 'parse_hsl'
1028 goto invalid;
1029 }
1030 } else if ((lwc_string_caseless_isequal(({ lwc_error __lwc_err = lwc_error_ok; lwc_string *__lwc_str1
= (token->idata); lwc_string *__lwc_str2 = (c->strings
[HSLA]); _Bool *__lwc_ret = (&match); if (__lwc_str1->
insensitive == ((void*)0)) { __lwc_err = lwc__intern_caseless_string
(__lwc_str1); } if (__lwc_err == lwc_error_ok && __lwc_str2
->insensitive == ((void*)0)) { __lwc_err = lwc__intern_caseless_string
(__lwc_str2); } if (__lwc_err == lwc_error_ok) *__lwc_ret = (
__lwc_str1->insensitive == __lwc_str2->insensitive); __lwc_err
; })
1031 token->idata, c->strings[HSLA],({ lwc_error __lwc_err = lwc_error_ok; lwc_string *__lwc_str1
= (token->idata); lwc_string *__lwc_str2 = (c->strings
[HSLA]); _Bool *__lwc_ret = (&match); if (__lwc_str1->
insensitive == ((void*)0)) { __lwc_err = lwc__intern_caseless_string
(__lwc_str1); } if (__lwc_err == lwc_error_ok && __lwc_str2
->insensitive == ((void*)0)) { __lwc_err = lwc__intern_caseless_string
(__lwc_str2); } if (__lwc_err == lwc_error_ok) *__lwc_ret = (
__lwc_str1->insensitive == __lwc_str2->insensitive); __lwc_err
; })
1032 &match)({ lwc_error __lwc_err = lwc_error_ok; lwc_string *__lwc_str1
= (token->idata); lwc_string *__lwc_str2 = (c->strings
[HSLA]); _Bool *__lwc_ret = (&match); if (__lwc_str1->
insensitive == ((void*)0)) { __lwc_err = lwc__intern_caseless_string
(__lwc_str1); } if (__lwc_err == lwc_error_ok && __lwc_str2
->insensitive == ((void*)0)) { __lwc_err = lwc__intern_caseless_string
(__lwc_str2); } if (__lwc_err == lwc_error_ok) *__lwc_ret = (
__lwc_str1->insensitive == __lwc_str2->insensitive); __lwc_err
; })
== lwc_error_ok && match)) {
1033 if (!parse_hsl(vector, ctx, result)) {
1034 goto invalid;
1035 }
1036 } else if ((lwc_string_caseless_isequal(({ lwc_error __lwc_err = lwc_error_ok; lwc_string *__lwc_str1
= (token->idata); lwc_string *__lwc_str2 = (c->strings
[HWB]); _Bool *__lwc_ret = (&match); if (__lwc_str1->insensitive
== ((void*)0)) { __lwc_err = lwc__intern_caseless_string(__lwc_str1
); } if (__lwc_err == lwc_error_ok && __lwc_str2->
insensitive == ((void*)0)) { __lwc_err = lwc__intern_caseless_string
(__lwc_str2); } if (__lwc_err == lwc_error_ok) *__lwc_ret = (
__lwc_str1->insensitive == __lwc_str2->insensitive); __lwc_err
; })
1037 token->idata, c->strings[HWB],({ lwc_error __lwc_err = lwc_error_ok; lwc_string *__lwc_str1
= (token->idata); lwc_string *__lwc_str2 = (c->strings
[HWB]); _Bool *__lwc_ret = (&match); if (__lwc_str1->insensitive
== ((void*)0)) { __lwc_err = lwc__intern_caseless_string(__lwc_str1
); } if (__lwc_err == lwc_error_ok && __lwc_str2->
insensitive == ((void*)0)) { __lwc_err = lwc__intern_caseless_string
(__lwc_str2); } if (__lwc_err == lwc_error_ok) *__lwc_ret = (
__lwc_str1->insensitive == __lwc_str2->insensitive); __lwc_err
; })
1038 &match)({ lwc_error __lwc_err = lwc_error_ok; lwc_string *__lwc_str1
= (token->idata); lwc_string *__lwc_str2 = (c->strings
[HWB]); _Bool *__lwc_ret = (&match); if (__lwc_str1->insensitive
== ((void*)0)) { __lwc_err = lwc__intern_caseless_string(__lwc_str1
); } if (__lwc_err == lwc_error_ok && __lwc_str2->
insensitive == ((void*)0)) { __lwc_err = lwc__intern_caseless_string
(__lwc_str2); } if (__lwc_err == lwc_error_ok) *__lwc_ret = (
__lwc_str1->insensitive == __lwc_str2->insensitive); __lwc_err
; })
== lwc_error_ok && match)) {
1039 if (!parse_hwb(vector, ctx, result)) {
1040 goto invalid;
1041 }
1042 } else {
1043 goto invalid;
1044 }
1045 }
1046
1047 *value = COLOR_SET;
1048
1049 return CSS_OK;
1050
1051invalid:
1052 *ctx = orig_ctx;
1053 return CSS_INVALID;
1054}
1055
1056/**
1057 * Parse a named colour
1058 *
1059 * \param c Parsing context
1060 * \param data Colour name string
1061 * \param result Pointer to location to receive result
1062 * \return CSS_OK on success,
1063 * CSS_INVALID if the colour name is unknown
1064 */
1065css_error css__parse_named_colour(css_language *c, lwc_string *data,
1066 uint32_t *result)
1067{
1068 static const uint32_t colourmap[LAST_COLOUR + 1 - FIRST_COLOUR] = {
1069 0xfff0f8ff, /* ALICEBLUE */
1070 0xfffaebd7, /* ANTIQUEWHITE */
1071 0xff00ffff, /* AQUA */
1072 0xff7fffd4, /* AQUAMARINE */
1073 0xfff0ffff, /* AZURE */
1074 0xfff5f5dc, /* BEIGE */
1075 0xffffe4c4, /* BISQUE */
1076 0xff000000, /* BLACK */
1077 0xffffebcd, /* BLANCHEDALMOND */
1078 0xff0000ff, /* BLUE */
1079 0xff8a2be2, /* BLUEVIOLET */
1080 0xffa52a2a, /* BROWN */
1081 0xffdeb887, /* BURLYWOOD */
1082 0xff5f9ea0, /* CADETBLUE */
1083 0xff7fff00, /* CHARTREUSE */
1084 0xffd2691e, /* CHOCOLATE */
1085 0xffff7f50, /* CORAL */
1086 0xff6495ed, /* CORNFLOWERBLUE */
1087 0xfffff8dc, /* CORNSILK */
1088 0xffdc143c, /* CRIMSON */
1089 0xff00ffff, /* CYAN */
1090 0xff00008b, /* DARKBLUE */
1091 0xff008b8b, /* DARKCYAN */
1092 0xffb8860b, /* DARKGOLDENROD */
1093 0xffa9a9a9, /* DARKGRAY */
1094 0xff006400, /* DARKGREEN */
1095 0xffa9a9a9, /* DARKGREY */
1096 0xffbdb76b, /* DARKKHAKI */
1097 0xff8b008b, /* DARKMAGENTA */
1098 0xff556b2f, /* DARKOLIVEGREEN */
1099 0xffff8c00, /* DARKORANGE */
1100 0xff9932cc, /* DARKORCHID */
1101 0xff8b0000, /* DARKRED */
1102 0xffe9967a, /* DARKSALMON */
1103 0xff8fbc8f, /* DARKSEAGREEN */
1104 0xff483d8b, /* DARKSLATEBLUE */
1105 0xff2f4f4f, /* DARKSLATEGRAY */
1106 0xff2f4f4f, /* DARKSLATEGREY */
1107 0xff00ced1, /* DARKTURQUOISE */
1108 0xff9400d3, /* DARKVIOLET */
1109 0xffff1493, /* DEEPPINK */
1110 0xff00bfff, /* DEEPSKYBLUE */
1111 0xff696969, /* DIMGRAY */
1112 0xff696969, /* DIMGREY */
1113 0xff1e90ff, /* DODGERBLUE */
1114 0xffd19275, /* FELDSPAR */
1115 0xffb22222, /* FIREBRICK */
1116 0xfffffaf0, /* FLORALWHITE */
1117 0xff228b22, /* FORESTGREEN */
1118 0xffff00ff, /* FUCHSIA */
1119 0xffdcdcdc, /* GAINSBORO */
1120 0xfff8f8ff, /* GHOSTWHITE */
1121 0xffffd700, /* GOLD */
1122 0xffdaa520, /* GOLDENROD */
1123 0xff808080, /* GRAY */
1124 0xff008000, /* GREEN */
1125 0xffadff2f, /* GREENYELLOW */
1126 0xff808080, /* GREY */
1127 0xfff0fff0, /* HONEYDEW */
1128 0xffff69b4, /* HOTPINK */
1129 0xffcd5c5c, /* INDIANRED */
1130 0xff4b0082, /* INDIGO */
1131 0xfffffff0, /* IVORY */
1132 0xfff0e68c, /* KHAKI */
1133 0xffe6e6fa, /* LAVENDER */
1134 0xfffff0f5, /* LAVENDERBLUSH */
1135 0xff7cfc00, /* LAWNGREEN */
1136 0xfffffacd, /* LEMONCHIFFON */
1137 0xffadd8e6, /* LIGHTBLUE */
1138 0xfff08080, /* LIGHTCORAL */
1139 0xffe0ffff, /* LIGHTCYAN */
1140 0xfffafad2, /* LIGHTGOLDENRODYELLOW */
1141 0xffd3d3d3, /* LIGHTGRAY */
1142 0xff90ee90, /* LIGHTGREEN */
1143 0xffd3d3d3, /* LIGHTGREY */
1144 0xffffb6c1, /* LIGHTPINK */
1145 0xffffa07a, /* LIGHTSALMON */
1146 0xff20b2aa, /* LIGHTSEAGREEN */
1147 0xff87cefa, /* LIGHTSKYBLUE */
1148 0xff8470ff, /* LIGHTSLATEBLUE */
1149 0xff778899, /* LIGHTSLATEGRAY */
1150 0xff778899, /* LIGHTSLATEGREY */
1151 0xffb0c4de, /* LIGHTSTEELBLUE */
1152 0xffffffe0, /* LIGHTYELLOW */
1153 0xff00ff00, /* LIME */
1154 0xff32cd32, /* LIMEGREEN */
1155 0xfffaf0e6, /* LINEN */
1156 0xffff00ff, /* MAGENTA */
1157 0xff800000, /* MAROON */
1158 0xff66cdaa, /* MEDIUMAQUAMARINE */
1159 0xff0000cd, /* MEDIUMBLUE */
1160 0xffba55d3, /* MEDIUMORCHID */
1161 0xff9370db, /* MEDIUMPURPLE */
1162 0xff3cb371, /* MEDIUMSEAGREEN */
1163 0xff7b68ee, /* MEDIUMSLATEBLUE */
1164 0xff00fa9a, /* MEDIUMSPRINGGREEN */
1165 0xff48d1cc, /* MEDIUMTURQUOISE */
1166 0xffc71585, /* MEDIUMVIOLETRED */
1167 0xff191970, /* MIDNIGHTBLUE */
1168 0xfff5fffa, /* MINTCREAM */
1169 0xffffe4e1, /* MISTYROSE */
1170 0xffffe4b5, /* MOCCASIN */
1171 0xffffdead, /* NAVAJOWHITE */
1172 0xff000080, /* NAVY */
1173 0xfffdf5e6, /* OLDLACE */
1174 0xff808000, /* OLIVE */
1175 0xff6b8e23, /* OLIVEDRAB */
1176 0xffffa500, /* ORANGE */
1177 0xffff4500, /* ORANGERED */
1178 0xffda70d6, /* ORCHID */
1179 0xffeee8aa, /* PALEGOLDENROD */
1180 0xff98fb98, /* PALEGREEN */
1181 0xffafeeee, /* PALETURQUOISE */
1182 0xffdb7093, /* PALEVIOLETRED */
1183 0xffffefd5, /* PAPAYAWHIP */
1184 0xffffdab9, /* PEACHPUFF */
1185 0xffcd853f, /* PERU */
1186 0xffffc0cb, /* PINK */
1187 0xffdda0dd, /* PLUM */
1188 0xffb0e0e6, /* POWDERBLUE */
1189 0xff800080, /* PURPLE */
1190 0xffff0000, /* RED */
1191 0xffbc8f8f, /* ROSYBROWN */
1192 0xff4169e1, /* ROYALBLUE */
1193 0xff8b4513, /* SADDLEBROWN */
1194 0xfffa8072, /* SALMON */
1195 0xfff4a460, /* SANDYBROWN */
1196 0xff2e8b57, /* SEAGREEN */
1197 0xfffff5ee, /* SEASHELL */
1198 0xffa0522d, /* SIENNA */
1199 0xffc0c0c0, /* SILVER */
1200 0xff87ceeb, /* SKYBLUE */
1201 0xff6a5acd, /* SLATEBLUE */
1202 0xff708090, /* SLATEGRAY */
1203 0xff708090, /* SLATEGREY */
1204 0xfffffafa, /* SNOW */
1205 0xff00ff7f, /* SPRINGGREEN */
1206 0xff4682b4, /* STEELBLUE */
1207 0xffd2b48c, /* TAN */
1208 0xff008080, /* TEAL */
1209 0xffd8bfd8, /* THISTLE */
1210 0xffff6347, /* TOMATO */
1211 0xff40e0d0, /* TURQUOISE */
1212 0xffee82ee, /* VIOLET */
1213 0xffd02090, /* VIOLETRED */
1214 0xfff5deb3, /* WHEAT */
1215 0xffffffff, /* WHITE */
1216 0xfff5f5f5, /* WHITESMOKE */
1217 0xffffff00, /* YELLOW */
1218 0xff9acd32 /* YELLOWGREEN */
1219 };
1220 /** Legacy system colour mapping */
1221 static const int deprecatedmap[LAST_DEPRECATEDCOLOUR + 1 - FIRST_DEPRECATEDCOLOUR] = {
1222 BUTTONBORDER, /* ACTIVEBORDER */
1223 CANVAS, /* ACTIVECAPTION */
1224 CANVAS, /* APPWORKSPACE */
1225 CANVAS, /* BACKGROUND */
1226 BUTTONFACE, /* BUTTONHIGHLIGHT */
1227 BUTTONFACE, /* BUTTONSHADOW */
1228 CANVASTEXT, /* CAPTIONTEXT */
1229 BUTTONBORDER, /* INACTIVEBORDER */
1230 CANVAS, /* INACTIVECAPTION */
1231 GRAYTEXT, /* INACTIVECAPTIONTEXT */
1232 CANVAS, /* INFOBACKGROUND */
1233 CANVASTEXT, /* INFOTEXT */
1234 CANVAS, /* MENU */
1235 CANVASTEXT, /* MENUTEXT */
1236 CANVAS, /* SCROLLBAR */
1237 BUTTONBORDER, /* THREEDDARKSHADOW */
1238 BUTTONFACE, /* THREEDFACE */
1239 BUTTONBORDER, /* THREEDHIGHLIGHT */
1240 BUTTONBORDER, /* THREEDLIGHTSHADOW */
1241 BUTTONBORDER, /* THREEDSHADOW */
1242 CANVAS, /* WINDOW */
1243 BUTTONBORDER, /* WINDOWFRAME */
1244 CANVASTEXT, /* WINDOWTEXT */
1245 };
1246 int i;
1247 bool_Bool match;
1248
1249 /* try to match a named colour */
1250 for (i = FIRST_COLOUR; i <= LAST_COLOUR; i++) {
1251 if (lwc_string_caseless_isequal(data, c->strings[i], &match)({ lwc_error __lwc_err = lwc_error_ok; lwc_string *__lwc_str1
= (data); lwc_string *__lwc_str2 = (c->strings[i]); _Bool
*__lwc_ret = (&match); if (__lwc_str1->insensitive ==
((void*)0)) { __lwc_err = lwc__intern_caseless_string(__lwc_str1
); } if (__lwc_err == lwc_error_ok && __lwc_str2->
insensitive == ((void*)0)) { __lwc_err = lwc__intern_caseless_string
(__lwc_str2); } if (__lwc_err == lwc_error_ok) *__lwc_ret = (
__lwc_str1->insensitive == __lwc_str2->insensitive); __lwc_err
; })
==
1252 lwc_error_ok &&
1253 match) {
1254 /* Known named colour */
1255 *result = colourmap[i - FIRST_COLOUR];
1256 return CSS_OK;
1257 }
1258 }
1259
1260 /* map deprecated system colours to current system colours */
1261 for (i = FIRST_DEPRECATEDCOLOUR; i <= LAST_DEPRECATEDCOLOUR; i++) {
1262 if (lwc_string_caseless_isequal(data, c->strings[i], &match)({ lwc_error __lwc_err = lwc_error_ok; lwc_string *__lwc_str1
= (data); lwc_string *__lwc_str2 = (c->strings[i]); _Bool
*__lwc_ret = (&match); if (__lwc_str1->insensitive ==
((void*)0)) { __lwc_err = lwc__intern_caseless_string(__lwc_str1
); } if (__lwc_err == lwc_error_ok && __lwc_str2->
insensitive == ((void*)0)) { __lwc_err = lwc__intern_caseless_string
(__lwc_str2); } if (__lwc_err == lwc_error_ok) *__lwc_ret = (
__lwc_str1->insensitive == __lwc_str2->insensitive); __lwc_err
; })
==
1263 lwc_error_ok &&
1264 match) {
1265 /* Known legacy system named colour */
1266 data = c->strings[deprecatedmap[i - FIRST_DEPRECATEDCOLOUR]];
1267 break;
1268 }
1269 }
1270
1271 /* attempt to get client to map colour */
1272 if (c->sheet->color != NULL((void*)0))
1273 return c->sheet->color(c->sheet->color_pw, data, result);
1274
1275 /* Invalid colour name */
1276 return CSS_INVALID;
1277}
1278
1279/**
1280 * Parse a hash colour (#rgb, #rgba, #rrggbb or #rrggbbaa)
1281 *
1282 * \param data Pointer to colour string
1283 * \param result Pointer to location to receive result (AARRGGBB)
1284 * \return CSS_OK on success,
1285 * CSS_INVALID if the input is invalid
1286 */
1287css_error css__parse_hash_colour(lwc_string *data, uint32_t *result)
1288{
1289 uint8_t r = 0, g = 0, b = 0, a = 0xff;
1290 size_t len = lwc_string_length(data)({((data != ((void*)0)) ? (void) (0) : __assert_fail ("data != NULL"
, "src/parse/properties/utils.c", 1290, __extension__ __PRETTY_FUNCTION__
)); (data)->len;})
;
1291 const char *input = lwc_string_data(data)({((data != ((void*)0)) ? (void) (0) : __assert_fail ("data != NULL"
, "src/parse/properties/utils.c", 1291, __extension__ __PRETTY_FUNCTION__
)); (const char *)((data)+1);})
;
1292
1293 switch (len) {
1294 case 4:
1295 if (!isHex(input[3])) {
1296 return CSS_INVALID;
1297 }
1298 a = charToHex(input[3]);
1299 a |= (a << 4);
1300 /* Fall through */
1301 case 3:
1302 if (!isHex(input[0]) || !isHex(input[1]) || !isHex(input[2])) {
1303 return CSS_INVALID;
1304 }
1305 r = charToHex(input[0]);
1306 g = charToHex(input[1]);
1307 b = charToHex(input[2]);
1308
1309 r |= (r << 4);
1310 g |= (g << 4);
1311 b |= (b << 4);
1312 break;
1313 case 8:
1314 if (!isHex(input[6]) || !isHex(input[7])) {
1315 return CSS_INVALID;
1316 }
1317 a = (charToHex(input[6]) << 4);
1318 a |= charToHex(input[7]);
1319 /* Fall through */
1320 case 6:
1321 if (!isHex(input[0]) || !isHex(input[1]) ||
1322 !isHex(input[2]) || !isHex(input[3]) ||
1323 !isHex(input[4]) || !isHex(input[5])) {
1324 return CSS_INVALID;
1325 }
1326 r = (charToHex(input[0]) << 4);
1327 r |= charToHex(input[1]);
1328 g = (charToHex(input[2]) << 4);
1329 g |= charToHex(input[3]);
1330 b = (charToHex(input[4]) << 4);
1331 b |= charToHex(input[5]);
1332 break;
1333 default:
1334 return CSS_INVALID;
1335 }
1336
1337 *result = ((unsigned)a << 24) | (r << 16) | (g << 8) | b;
1338
1339 return CSS_OK;
1340}
1341
1342/**
1343 * Parse a unit specifier
1344 *
1345 * \param c Parsing context
1346 * \param vector Vector of tokens to process
1347 * \param ctx Pointer to current vector iteration context
1348 * \param default_unit The default unit to use if none specified
1349 * \param length Pointer to location to receive length
1350 * \param unit Pointer to location to receive unit
1351 * \return CSS_OK on success,
1352 * CSS_INVALID if the tokens do not form a valid unit
1353 *
1354 * Post condition: \a *ctx is updated with the next token to process
1355 * If the input is invalid, then \a *ctx remains unchanged.
1356 */
1357css_error css__parse_unit_specifier(css_language *c,
1358 const parserutils_vector *vector, int32_t *ctx,
1359 uint32_t default_unit,
1360 css_fixed *length, uint32_t *unit)
1361{
1362 int32_t orig_ctx = *ctx;
1363 const css_token *token;
1364 css_fixed num;
1365 size_t consumed = 0;
1366 css_error error;
1367
1368 consumeWhitespace(vector, ctx);
1369
1370 token = parserutils_vector_iterate(vector, ctx);
1371 if (token == NULL((void*)0) || (token->type != CSS_TOKEN_DIMENSION &&
1372 token->type != CSS_TOKEN_NUMBER &&
1373 token->type != CSS_TOKEN_PERCENTAGE)) {
1374 *ctx = orig_ctx;
1375 return CSS_INVALID;
1376 }
1377
1378 num = css__number_from_lwc_string(token->idata, false0, &consumed);
1379
1380 if (token->type == CSS_TOKEN_DIMENSION) {
1381 size_t len = lwc_string_length(token->idata)({((token->idata != ((void*)0)) ? (void) (0) : __assert_fail
("token->idata != NULL", "src/parse/properties/utils.c", 1381
, __extension__ __PRETTY_FUNCTION__)); (token->idata)->
len;})
;
1382 const char *data = lwc_string_data(token->idata)({((token->idata != ((void*)0)) ? (void) (0) : __assert_fail
("token->idata != NULL", "src/parse/properties/utils.c", 1382
, __extension__ __PRETTY_FUNCTION__)); (const char *)((token->
idata)+1);})
;
1383 uint32_t temp_unit = CSS_UNIT_PX;
1384
1385 error = css__parse_unit_keyword(data + consumed, len - consumed,
1386 &temp_unit);
1387 if (error != CSS_OK) {
1388 *ctx = orig_ctx;
1389 return error;
1390 }
1391
1392 *unit = temp_unit;
1393 } else if (token->type == CSS_TOKEN_NUMBER) {
1394 /* Non-zero values are permitted in quirks mode */
1395 if (num != 0) {
1396 if (c->sheet->quirks_allowed) {
1397 c->sheet->quirks_used = true1;
1398 } else {
1399 *ctx = orig_ctx;
1400 return CSS_INVALID;
1401 }
1402 }
1403
1404 *unit = default_unit;
1405
1406 if (c->sheet->quirks_allowed) {
1407 /* Also, in quirks mode, we need to cater for
1408 * dimensions separated from their units by whitespace
1409 * (e.g. "0 px")
1410 */
1411 int32_t temp_ctx = *ctx;
1412 uint32_t temp_unit;
1413
1414 consumeWhitespace(vector, &temp_ctx);
1415
1416 /* Try to parse the unit keyword, ignoring errors */
1417 token = parserutils_vector_iterate(vector, &temp_ctx);
1418 if (token != NULL((void*)0) && token->type == CSS_TOKEN_IDENT) {
1419 error = css__parse_unit_keyword(
1420 lwc_string_data(token->idata)({((token->idata != ((void*)0)) ? (void) (0) : __assert_fail
("token->idata != NULL", "src/parse/properties/utils.c", 1420
, __extension__ __PRETTY_FUNCTION__)); (const char *)((token->
idata)+1);})
,
1421 lwc_string_length(token->idata)({((token->idata != ((void*)0)) ? (void) (0) : __assert_fail
("token->idata != NULL", "src/parse/properties/utils.c", 1421
, __extension__ __PRETTY_FUNCTION__)); (token->idata)->
len;})
,
1422 &temp_unit);
1423 if (error == CSS_OK) {
1424 c->sheet->quirks_used = true1;
1425 *ctx = temp_ctx;
1426 *unit = temp_unit;
1427 }
1428 }
1429 }
1430 } else {
1431 /* Percentage -- number must be entire token data */
1432 if (consumed != lwc_string_length(token->idata)({((token->idata != ((void*)0)) ? (void) (0) : __assert_fail
("token->idata != NULL", "src/parse/properties/utils.c", 1432
, __extension__ __PRETTY_FUNCTION__)); (token->idata)->
len;})
) {
1433 *ctx = orig_ctx;
1434 return CSS_INVALID;
1435 }
1436 *unit = UNIT_PCT;
1437 }
1438
1439 *length = num;
1440
1441 return CSS_OK;
1442}
1443
1444/**
1445 * Parse a unit keyword
1446 *
1447 * \param ptr Pointer to keyword string
1448 * \param len Length, in bytes, of string
1449 * \param unit Pointer to location to receive computed unit
1450 * \return CSS_OK on success,
1451 * CSS_INVALID on encountering an unknown keyword
1452 */
1453css_error css__parse_unit_keyword(const char *ptr, size_t len, uint32_t *unit)
1454{
1455 if (len == 4) {
1456 if (strncasecmp(ptr, "grad", 4) == 0)
1457 *unit = UNIT_GRAD;
1458 else if (strncasecmp(ptr, "turn", 4) == 0)
1459 *unit = UNIT_TURN;
1460 else if (strncasecmp(ptr, "dppx", 4) == 0)
1461 *unit = UNIT_DPPX;
1462 else if (strncasecmp(ptr, "dpcm", 4) == 0)
1463 *unit = UNIT_DPCM;
1464 else if (strncasecmp(ptr, "vmin", 4) == 0)
1465 *unit = UNIT_VMIN;
1466 else if (strncasecmp(ptr, "vmax", 4) == 0)
1467 *unit = UNIT_VMAX;
1468 else
1469 return CSS_INVALID;
1470 } else if (len == 3) {
1471 if (strncasecmp(ptr, "kHz", 3) == 0)
1472 *unit = UNIT_KHZ;
1473 else if (strncasecmp(ptr, "deg", 3) == 0)
1474 *unit = UNIT_DEG;
1475 else if (strncasecmp(ptr, "rad", 3) == 0)
1476 *unit = UNIT_RAD;
1477 else if (strncasecmp(ptr, "rem", 3) == 0)
1478 *unit = UNIT_REM;
1479 else if (strncasecmp(ptr, "dpi", 3) == 0)
1480 *unit = UNIT_DPI;
1481 else
1482 return CSS_INVALID;
1483 } else if (len == 2) {
1484 if (strncasecmp(ptr, "Hz", 2) == 0)
1485 *unit = UNIT_HZ;
1486 else if (strncasecmp(ptr, "ms", 2) == 0)
1487 *unit = UNIT_MS;
1488 else if (strncasecmp(ptr, "px", 2) == 0)
1489 *unit = UNIT_PX;
1490 else if (strncasecmp(ptr, "ex", 2) == 0)
1491 *unit = UNIT_EX;
1492 else if (strncasecmp(ptr, "em", 2) == 0)
1493 *unit = UNIT_EM;
1494 else if (strncasecmp(ptr, "in", 2) == 0)
1495 *unit = UNIT_IN;
1496 else if (strncasecmp(ptr, "cm", 2) == 0)
1497 *unit = UNIT_CM;
1498 else if (strncasecmp(ptr, "mm", 2) == 0)
1499 *unit = UNIT_MM;
1500 else if (strncasecmp(ptr, "pt", 2) == 0)
1501 *unit = UNIT_PT;
1502 else if (strncasecmp(ptr, "pc", 2) == 0)
1503 *unit = UNIT_PC;
1504 else if (strncasecmp(ptr, "ch", 2) == 0)
1505 *unit = UNIT_CH;
1506 else if (strncasecmp(ptr, "lh", 2) == 0)
1507 *unit = UNIT_LH;
1508 else if (strncasecmp(ptr, "vh", 2) == 0)
1509 *unit = UNIT_VH;
1510 else if (strncasecmp(ptr, "vw", 2) == 0)
1511 *unit = UNIT_VW;
1512 else if (strncasecmp(ptr, "vi", 2) == 0)
1513 *unit = UNIT_VI;
1514 else if (strncasecmp(ptr, "vb", 2) == 0)
1515 *unit = UNIT_VB;
1516 else
1517 return CSS_INVALID;
1518 } else if (len == 1) {
1519 if (strncasecmp(ptr, "s", 1) == 0)
1520 *unit = UNIT_S;
1521 else if (strncasecmp(ptr, "q", 1) == 0)
1522 *unit = UNIT_Q;
1523 else
1524 return CSS_INVALID;
1525 } else
1526 return CSS_INVALID;
1527
1528 return CSS_OK;
1529}
1530
1531/**
1532 * Create a string from a list of IDENT/S tokens if the next token is IDENT
1533 * or references the next token's string if it is a STRING
1534 *
1535 * \param c Parsing context
1536 * \param vector Vector containing tokens
1537 * \param ctx Vector iteration context
1538 * \param reserved Callback to determine if an identifier is reserved
1539 * \param result Pointer to location to receive resulting string
1540 * \return CSS_OK on success, appropriate error otherwise.
1541 *
1542 * Post condition: \a *ctx is updated with the next token to process
1543 * If the input is invalid, then \a *ctx remains unchanged.
1544 *
1545 * The resulting string's reference is passed to the caller
1546 */
1547css_error css__ident_list_or_string_to_string(css_language *c,
1548 const parserutils_vector *vector, int32_t *ctx,
1549 bool_Bool (*reserved)(css_language *c, const css_token *ident),
1550 lwc_string **result)
1551{
1552 const css_token *token;
1553
1554 token = parserutils_vector_peek(vector, *ctx);
1555 if (token == NULL((void*)0))
1556 return CSS_INVALID;
1557
1558 if (token->type == CSS_TOKEN_STRING) {
1559 token = parserutils_vector_iterate(vector, ctx);
1560 *result = lwc_string_ref(token->idata)({lwc_string *__lwc_s = (token->idata); ((__lwc_s != ((void
*)0)) ? (void) (0) : __assert_fail ("__lwc_s != NULL", "src/parse/properties/utils.c"
, 1560, __extension__ __PRETTY_FUNCTION__)); __lwc_s->refcnt
++; __lwc_s;})
;
1561 return CSS_OK;
1562 } else if(token->type == CSS_TOKEN_IDENT) {
1563 return css__ident_list_to_string(c, vector, ctx, reserved,
1564 result);
1565 }
1566
1567 return CSS_INVALID;
1568}
1569
1570/**
1571 * Create a string from a list of IDENT/S tokens
1572 *
1573 * \param c Parsing context
1574 * \param vector Vector containing tokens
1575 * \param ctx Vector iteration context
1576 * \param reserved Callback to determine if an identifier is reserved
1577 * \param result Pointer to location to receive resulting string
1578 * \return CSS_OK on success, appropriate error otherwise.
1579 *
1580 * Post condition: \a *ctx is updated with the next token to process
1581 * If the input is invalid, then \a *ctx remains unchanged.
1582 *
1583 * The resulting string's reference is passed to the caller
1584 */
1585css_error css__ident_list_to_string(css_language *c,
1586 const parserutils_vector *vector, int32_t *ctx,
1587 bool_Bool (*reserved)(css_language *c, const css_token *ident),
1588 lwc_string **result)
1589{
1590 int32_t orig_ctx = *ctx;
1591 const css_token *token;
1592 css_error error = CSS_OK;
1593 parserutils_buffer *buffer;
1594 parserutils_error perror;
1595 lwc_string *interned;
1596 lwc_error lerror;
1597
1598 perror = parserutils_buffer_create(&buffer);
1599 if (perror != PARSERUTILS_OK)
1600 return css_error_from_parserutils_error(perror);
1601
1602 /* We know this token exists, and is an IDENT */
1603 token = parserutils_vector_iterate(vector, ctx);
1604
1605 /* Consume all subsequent IDENT or S tokens */
1606 while (token != NULL((void*)0) && (token->type == CSS_TOKEN_IDENT ||
1607 token->type == CSS_TOKEN_S)) {
1608 if (token->type == CSS_TOKEN_IDENT) {
1609 /* IDENT -- if reserved, reject style */
1610 if (reserved != NULL((void*)0) && reserved(c, token)) {
1611 error = CSS_INVALID;
1612 goto cleanup;
1613 }
1614
1615 perror = parserutils_buffer_append(buffer,
1616 (const uint8_t *) lwc_string_data(token->idata)({((token->idata != ((void*)0)) ? (void) (0) : __assert_fail
("token->idata != NULL", "src/parse/properties/utils.c", 1616
, __extension__ __PRETTY_FUNCTION__)); (const char *)((token->
idata)+1);})
,
1617 lwc_string_length(token->idata)({((token->idata != ((void*)0)) ? (void) (0) : __assert_fail
("token->idata != NULL", "src/parse/properties/utils.c", 1617
, __extension__ __PRETTY_FUNCTION__)); (token->idata)->
len;})
);
1618 } else {
1619 /* S */
1620 perror = parserutils_buffer_append(buffer,
1621 (const uint8_t *) " ", 1);
1622 }
1623
1624 if (perror != PARSERUTILS_OK) {
1625 error = css_error_from_parserutils_error(perror);
1626 goto cleanup;
1627 }
1628
1629 token = parserutils_vector_iterate(vector, ctx);
1630 }
1631
1632 /* Rewind context by one step if we consumed an unacceptable token */
1633 if (token != NULL((void*)0))
1634 *ctx = *ctx - 1;
1635
1636 /* Strip trailing whitespace */
1637 while (buffer->length > 0 && buffer->data[buffer->length - 1] == ' ')
1638 buffer->length--;
1639
1640 /* Intern the buffer contents */
1641 lerror = lwc_intern_string((char *) buffer->data, buffer->length, &interned);
1642 if (lerror != lwc_error_ok) {
1643 error = css_error_from_lwc_error(lerror);
1644 goto cleanup;
1645 }
1646
1647 *result = interned;
1648
1649cleanup:
1650 parserutils_buffer_destroy(buffer);
1651
1652 if (error != CSS_OK)
1653 *ctx = orig_ctx;
1654
1655 return error;
1656}
1657
1658/**
1659 * Parse a comma separated list, converting to bytecode
1660 *
1661 * \param c Parsing context
1662 * \param vector Vector of tokens to process
1663 * \param ctx Pointer to vector iteration context
1664 * \param reserved Callback to determine if an identifier is reserved
1665 * \param get_value Callback to retrieve bytecode value for a token
1666 * \param style Pointer to output style
1667 * \return CSS_OK on success,
1668 * CSS_INVALID if the input is invalid
1669 *
1670 * Post condition: \a *ctx is updated with the next token to process
1671 * If the input is invalid, then \a *ctx remains unchanged.
1672 */
1673css_error css__comma_list_to_style(css_language *c,
1674 const parserutils_vector *vector, int32_t *ctx,
1675 bool_Bool (*reserved)(css_language *c, const css_token *ident),
1676 css_code_t (*get_value)(css_language *c, const css_token *token, bool_Bool first),
1677 css_style *result)
1678{
1679 int32_t orig_ctx = *ctx;
1680 int prev_ctx = orig_ctx;
1681 const css_token *token;
1682 bool_Bool first = true1;
1683 css_error error = CSS_OK;
1684
1685 token = parserutils_vector_iterate(vector, ctx);
1686 if (token == NULL((void*)0)) {
1687 *ctx = orig_ctx;
1688 return CSS_INVALID;
1689 }
1690
1691 while (token != NULL((void*)0)) {
1692 if (token->type == CSS_TOKEN_IDENT) {
1693 css_code_t value = get_value(c, token, first);
1694
1695 if (reserved(c, token) == false0) {
1696 lwc_string *str = NULL((void*)0);
1697 uint32_t snumber;
1698
1699 *ctx = prev_ctx;
1700
1701 error = css__ident_list_to_string(c, vector, ctx,
1702 reserved, &str);
1703 if (error != CSS_OK)
1704 goto cleanup;
1705
1706 error = css__stylesheet_string_add(c->sheet,
1707 str, &snumber);
1708 if (error != CSS_OK)
1709 goto cleanup;
1710
1711 error = css__stylesheet_style_append(result,
1712 value);
1713 if (error != CSS_OK)
1714 goto cleanup;
1715
1716 error = css__stylesheet_style_append(result,
1717 snumber);
1718 if (error != CSS_OK)
1719 goto cleanup;
1720 } else {
1721 error = css__stylesheet_style_append(result,
1722 value);
1723 if (error != CSS_OK)
1724 goto cleanup;
1725 }
1726 } else if (token->type == CSS_TOKEN_STRING) {
1727 css_code_t value = get_value(c, token, first);
1728 uint32_t snumber;
1729
1730 error = css__stylesheet_string_add(c->sheet,
1731 lwc_string_ref(token->idata)({lwc_string *__lwc_s = (token->idata); ((__lwc_s != ((void
*)0)) ? (void) (0) : __assert_fail ("__lwc_s != NULL", "src/parse/properties/utils.c"
, 1731, __extension__ __PRETTY_FUNCTION__)); __lwc_s->refcnt
++; __lwc_s;})
, &snumber);
1732 if (error != CSS_OK)
1733 goto cleanup;
1734
1735 error = css__stylesheet_style_append(result, value);
1736 if (error != CSS_OK)
1737 goto cleanup;
1738
1739 error = css__stylesheet_style_append(result, snumber);
1740 if (error != CSS_OK)
1741 goto cleanup;
1742 } else {
1743 error = CSS_INVALID;
1744 goto cleanup;
1745 }
1746
1747 consumeWhitespace(vector, ctx);
1748
1749 token = parserutils_vector_peek(vector, *ctx);
1750 if (token != NULL((void*)0) && tokenIsChar(token, ',')) {
1751 parserutils_vector_iterate(vector, ctx);
1752
1753 consumeWhitespace(vector, ctx);
1754
1755 token = parserutils_vector_peek(vector, *ctx);
1756 if (token == NULL((void*)0) || (token->type != CSS_TOKEN_IDENT &&
1757 token->type != CSS_TOKEN_STRING)) {
1758 error = CSS_INVALID;
1759 goto cleanup;
1760 }
1761 } else {
1762 break;
1763 }
1764
1765 first = false0;
1766
1767 prev_ctx = *ctx;
1768
1769 token = parserutils_vector_iterate(vector, ctx);
1770 }
1771
1772cleanup:
1773 if (error != CSS_OK)
1774 *ctx = orig_ctx;
1775
1776 return error;
1777}
1778
1779/******************************************************************************/
1780
1781/* CALC
1782 *
1783 * calc( <calc-sum> )
1784 *
1785 * where
1786 * <calc-sum> = <calc-product> [ [ '+' | '-' ] <calc-product> ]*
1787 *
1788 * where
1789 * <calc-product> = <calc-value> [ '*' <calc-value> | '/' <number> ]*
1790 *
1791 * where
1792 * <calc-value> = <number> | <dimension> | <percentage> | ( <calc-sum> )
1793 *
1794 *
1795 * Once a calc() expression is parsed, it generates into the bytecode as
1796 * an opV where the V is VALUE_IS_CALC, then a unit kind which is the
1797 * expected resolved type for the calc, and a string index. The string is
1798 * another kind of bytecode, essentially it's a sequence of stack machine
1799 * operations which are one of the calc_opcodes enum. They are:
1800 *
1801 * * CALC_PUSH_NUMBER (N)
1802 * - takes a css_fixed and pushes it onto the operand stack
1803 * * CALC_PUSH_VALUE (V)
1804 * - takes a css_fixed and a unit, and pushes them
1805 * * CALC_{ADD,SUBTRACT,MULTIPLY,DIVIDE} (+ - * /)
1806 * - pop two values, perform the operation, push the result
1807 * * CALC_FINISH (=)
1808 * - pop the top value from the stack and return it.
1809 *
1810 * As an example:
1811 *
1812 * calc(10px + (4rem / 2)) =>
1813 * V 10 px
1814 * V 4 rem
1815 * N 2
1816 * /
1817 * +
1818 * =
1819 */
1820
1821static css_error
1822css__parse_calc_sum(css_language *c,
1823 enum css_properties_e property,
1824 const parserutils_vector *vector, int *ctx,
1825 parserutils_buffer *result);
1826
1827static css_error
1828css__parse_calc_number(
1829 const parserutils_vector *vector, int *ctx,
1830 parserutils_buffer *result)
1831{
1832 const css_token *token;
1833 css_fixed num;
1834 size_t consumed;
1835 css_code_t push = CALC_PUSH_NUMBER;
1836
1837 /* Consume the number token */
1838 token = parserutils_vector_iterate(vector, ctx);
1839 if (token == NULL((void*)0) || token->type != CSS_TOKEN_NUMBER) {
1840 return CSS_INVALID;
1841 }
1842
1843 num = css__number_from_string((const uint8_t *)lwc_string_data(token->idata)({((token->idata != ((void*)0)) ? (void) (0) : __assert_fail
("token->idata != NULL", "src/parse/properties/utils.c", 1843
, __extension__ __PRETTY_FUNCTION__)); (const char *)((token->
idata)+1);})
,
1844 lwc_string_length(token->idata)({((token->idata != ((void*)0)) ? (void) (0) : __assert_fail
("token->idata != NULL", "src/parse/properties/utils.c", 1844
, __extension__ __PRETTY_FUNCTION__)); (token->idata)->
len;})
, false0, &consumed);
1845
1846 if (consumed != lwc_string_length(token->idata)({((token->idata != ((void*)0)) ? (void) (0) : __assert_fail
("token->idata != NULL", "src/parse/properties/utils.c", 1846
, __extension__ __PRETTY_FUNCTION__)); (token->idata)->
len;})
) {
1847 return CSS_INVALID;
1848 }
1849
1850 return css_error_from_parserutils_error(
1851 parserutils_buffer_appendv(result, 2,
1852 &push, sizeof(push),
1853 &num, sizeof(num)
1854 )
1855 );
1856}
1857
1858static css_error
1859css__parse_calc_value(css_language *c,
1860 enum css_properties_e property,
1861 const parserutils_vector *vector, int *ctx,
1862 parserutils_buffer *result)
1863{
1864 css_error error;
1865 int orig_ctx = *ctx;
1866 const css_token *token;
1867
1868 /* On entry, we are already pointing at the value to parse, so peek it */
1869 token = parserutils_vector_peek(vector, *ctx);
1870 if (tokenIsChar(token, '(')) {
1871 parserutils_vector_iterate(vector, ctx);
1872 consumeWhitespace(vector, ctx);
1873 error = css__parse_calc_sum(c, property, vector, ctx, result);
1874 if (error != CSS_OK) {
1875 return error;
1876 }
1877
1878 token = parserutils_vector_peek(vector, *ctx);
1879 if (!tokenIsChar(token, ')')) {
1880 return CSS_INVALID;
1881 }
1882 /* Consume the close-paren to complete this value */
1883 parserutils_vector_iterate(vector, ctx);
1884 } else switch (token->type) {
1885 case CSS_TOKEN_NUMBER:
1886 error = css__parse_calc_number(vector, ctx, result);
1887 if (error != CSS_OK) {
1888 return error;
1889 }
1890 break;
1891 case CSS_TOKEN_DIMENSION: /* Fall through */
1892 case CSS_TOKEN_PERCENTAGE:
1893 {
1894 css_fixed length = 0;
1895 uint32_t unit = 0;
1896 css_code_t push = CALC_PUSH_VALUE;
1897 *ctx = orig_ctx;
1898
1899 error = css__parse_unit_specifier(c, vector, ctx, UNIT_CALC_NUMBER, &length, &unit);
1900 if (error != CSS_OK) {
1901 *ctx = orig_ctx;
1902 return error;
1903 }
1904
1905 if (!(unit & property_unit_mask[property])) {
1906 /* This unit is not valid for this property. */
1907 return CSS_INVALID;
1908 }
1909
1910 error = css_error_from_parserutils_error(
1911 parserutils_buffer_appendv(result, 3,
1912 &push, sizeof(push),
1913 &length, sizeof(length),
1914 &unit, sizeof(unit)
1915 )
1916 );
1917
1918 }
1919 break;
1920
1921 default:
1922 error = CSS_INVALID;
1923 break;
1924 }
1925
1926 consumeWhitespace(vector, ctx);
1927 return error;
1928}
1929
1930/* Both this, and css_parse_calc_sum must stop when it encounters a close-paren.
1931 * If it hasn't had any useful tokens before that, it's an error. It does not
1932 * need to restore ctx before returning an error but it does need to ensure that
1933 * the close paren has not been consumed
1934 */
1935static css_error
1936css__parse_calc_product(css_language *c,
1937 enum css_properties_e property,
1938 const parserutils_vector *vector, int *ctx,
1939 parserutils_buffer *result)
1940{
1941 css_error error = CSS_OK;
1942 const css_token *token;
1943 css_code_t operator;
1944
1945 /* First parse a value */
1946 error = css__parse_calc_value(c, property, vector, ctx, result);
1947 if (error != CSS_OK) {
1948 return error;
1949 }
1950
1951 do {
1952 /* What is our next token? */
1953 token = parserutils_vector_peek(vector, *ctx);
1954 if (token == NULL((void*)0)) {
1955 error = CSS_INVALID;
1956 break;
1957 } else if (
1958 tokenIsChar(token, ')') ||
1959 tokenIsChar(token, '+') ||
1960 tokenIsChar(token, '-'))
1961 break;
1962 else if (tokenIsChar(token, '*'))
1963 operator = CALC_MULTIPLY;
1964 else if (tokenIsChar(token, '/'))
1965 operator = CALC_DIVIDE;
1966 else {
1967 error = CSS_INVALID;
1968 break;
1969 }
1970 /* Consume that * or / now */
1971 parserutils_vector_iterate(vector, ctx);
1972
1973 consumeWhitespace(vector, ctx);
1974
1975 if (operator == CALC_MULTIPLY) {
1976 /* parse another value */
1977 error = css__parse_calc_value(c, property, vector,
1978 ctx, result);
1979 } else {
1980 error = css__parse_calc_number(vector, ctx, result);
1981 }
1982 if (error != CSS_OK)
1983 break;
1984
1985 /* emit the multiplication/division operator */
1986 error = css_error_from_parserutils_error(
1987 parserutils_buffer_append(result, (const uint8_t *)&operator, sizeof(operator))
1988 );
1989 } while (1);
1990 /* We've fallen off, either we had an error or we're left with ')' */
1991 return error;
1992}
1993
1994
1995css_error
1996css__parse_calc_sum(css_language *c,
1997 enum css_properties_e property,
1998 const parserutils_vector *vector, int *ctx,
1999 parserutils_buffer *result)
2000{
2001 css_error error = CSS_OK;
2002 const css_token *token;
2003 css_code_t operator;
2004
2005 /* First parse a product */
2006 error = css__parse_calc_product(c, property, vector, ctx, result);
2007 if (error != CSS_OK) {
2008 return error;
2009 }
2010
2011 do {
2012 /* What is our next token? */
2013 token = parserutils_vector_peek(vector, *ctx);
2014 if (token == NULL((void*)0)) {
2015 error = CSS_INVALID;
2016 break;
2017 } else if (tokenIsChar(token, ')'))
2018 break;
2019 else if (tokenIsChar(token, '+'))
2020 operator = CALC_ADD;
2021 else if (tokenIsChar(token, '-'))
2022 operator = CALC_SUBTRACT;
2023 else {
2024 error = CSS_INVALID;
2025 break;
2026 }
2027 /* Consume that + or - now */
2028 parserutils_vector_iterate(vector, ctx);
2029 consumeWhitespace(vector, ctx);
2030
2031 /* parse another product */
2032 error = css__parse_calc_product(c, property, vector, ctx, result);
2033 if (error != CSS_OK)
2034 break;
2035
2036 /* emit the addition/subtraction operator */
2037 error = css_error_from_parserutils_error(
2038 parserutils_buffer_append(result, (const uint8_t *)&operator, sizeof(operator))
2039 );
2040 } while (1);
2041 /* We've fallen off, either we had an error or we're left with ')' */
2042 return error;
2043}
2044
2045/* Documented in utils.h */
2046css_error css__parse_calc(css_language *c,
2047 const parserutils_vector *vector, int *ctx,
2048 css_style *result,
2049 css_code_t OPV,
2050 uint32_t unit)
2051{
2052 int orig_ctx = *ctx;
2053 const css_token *token;
2054 css_error error = CSS_OK;
2055 css_style *calc_style = NULL((void*)0);
2056 parserutils_buffer *calc_buffer = NULL((void*)0);
2057 lwc_string *calc_expr = NULL((void*)0);
2058 uint32_t expr_index = 0;
2059 css_code_t finish = CALC_FINISH;
2060 enum css_properties_e property = getOpcode(OPV);
2061
2062 consumeWhitespace(vector, ctx);
2063
2064 token = parserutils_vector_peek(vector, *ctx);
2065 if (token == NULL((void*)0)) {
2066 *ctx = orig_ctx;
2067 return CSS_INVALID;
2068 }
2069
2070 if (parserutils_buffer_create(&calc_buffer) != PARSERUTILS_OK) {
2071 /* Since &calc_buffer is valid, the only error case is NONMEM */
2072 *ctx = orig_ctx;
2073 return CSS_NOMEM;
2074 }
2075
2076 error = css__stylesheet_style_create(c->sheet, &calc_style);
2077 if (error != CSS_OK)
2078 goto cleanup;
2079
2080 error = css__stylesheet_style_append(calc_style, OPV);
2081 if (error != CSS_OK)
2082 goto cleanup;
2083
2084 error = css__stylesheet_style_append(calc_style, (css_code_t) unit);
2085 if (error != CSS_OK)
2086 goto cleanup;
2087
2088 error = css__parse_calc_sum(c, property, vector, ctx, calc_buffer);
2089 if (error != CSS_OK)
2090 goto cleanup;
2091
2092 consumeWhitespace(vector, ctx);
2093 token = parserutils_vector_peek(vector, *ctx);
2094 if (!tokenIsChar(token, ')')) {
2095 /* If we don't get a close-paren, give up now */
2096 error = CSS_INVALID;
2097 goto cleanup;
2098 }
2099
2100 /* Append the indicator that the calc is finished */
2101 error = css_error_from_parserutils_error(
2102 parserutils_buffer_append(calc_buffer, (const uint8_t *)&finish, sizeof(finish))
2103 );
2104 if (error != CSS_OK)
2105 goto cleanup;
2106
2107 /* Swallow that close paren */
2108 parserutils_vector_iterate(vector, ctx);
2109
2110 /* Create the lwc string representing the calculation and store it in */
2111 error = css_error_from_lwc_error(
2112 lwc_intern_string((const char *)calc_buffer->data, calc_buffer->length, &calc_expr)
2113 );
2114 if (error != CSS_OK)
2115 goto cleanup;
2116
2117 /* This always takes ownership of calc_expr, so we should not use after this */
2118 error = css__stylesheet_string_add(calc_style->sheet, calc_expr, &expr_index);
2119 if (error != CSS_OK)
2120 goto cleanup;
2121
2122 error = css__stylesheet_style_append(calc_style,
2123 (css_code_t) expr_index);
2124 if (error != CSS_OK) {
2125 goto cleanup;
2126 }
2127
2128 error = css__stylesheet_merge_style(result, calc_style);
2129cleanup:
2130 css__stylesheet_style_destroy(calc_style);
2131 parserutils_buffer_destroy(calc_buffer);
2132 /* We do not need to clean up calc_expr, it will never leak */
2133 if (error != CSS_OK) {
2134 *ctx = orig_ctx;
2135 }
2136
2137 return error;
2138}