Bug Summary

File:select/select.c
Warning:line 2100, column 12
Called function pointer is an uninitialized pointer 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 select.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/select/select.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
11#include <libwapcaplet/libwapcaplet.h>
12
13#include <libcss/select.h>
14
15#include "bytecode/bytecode.h"
16#include "bytecode/opcodes.h"
17#include "stylesheet.h"
18#include "select/arena.h"
19#include "select/calc.h"
20#include "select/computed.h"
21#include "select/dispatch.h"
22#include "select/hash.h"
23#include "select/mq.h"
24#include "select/propset.h"
25#include "select/font_face.h"
26#include "select/select.h"
27#include "select/strings.h"
28#include "select/unit.h"
29#include "utils/parserutilserror.h"
30#include "utils/utils.h"
31
32/* Define this to enable verbose messages when matching selector chains */
33#undef DEBUG_CHAIN_MATCHING
34
35/* Define this to enable verbose messages when attempting to share styles */
36#undef DEBUG_STYLE_SHARING
37
38/**
39 * Container for stylesheet selection info
40 */
41typedef struct css_select_sheet {
42 const css_stylesheet *sheet; /**< Stylesheet */
43 css_origin origin; /**< Stylesheet origin */
44 css_mq_query *media; /**< Applicable media */
45} css_select_sheet;
46
47/**
48 * CSS selection context
49 */
50struct css_select_ctx {
51 uint32_t n_sheets; /**< Number of sheets */
52
53 css_select_sheet *sheets; /**< Array of sheets */
54
55 void *pw; /**< Client's private selection context */
56
57 bool_Bool uses_revert; /**< A sheet used revert property value */
58
59 css_select_strings str;
60
61 css_calculator *calc; /**< A calculator to hand off to computed styles */
62
63 /* Interned default style */
64 css_computed_style *default_style;
65};
66
67/**
68 * Container for selected font faces
69 */
70typedef struct css_select_font_faces_list {
71 const css_font_face **font_faces;
72 size_t count;
73} css_select_font_faces_list;
74
75/**
76 * Font face selection state
77 */
78typedef struct css_select_font_faces_state {
79 lwc_string *font_family;
80 const css_media *media;
81 const css_unit_ctx *unit_ctx;
82
83 css_select_font_faces_list ua_font_faces;
84 css_select_font_faces_list user_font_faces;
85 css_select_font_faces_list author_font_faces;
86} css_select_font_faces_state;
87
88/**
89 * CSS rule source
90 */
91typedef struct css_select_rule_source {
92 enum {
93 CSS_SELECT_RULE_SRC_ELEMENT,
94 CSS_SELECT_RULE_SRC_CLASS,
95 CSS_SELECT_RULE_SRC_ID,
96 CSS_SELECT_RULE_SRC_UNIVERSAL
97 } source;
98 uint32_t class;
99} css_select_rule_source;
100
101
102static css_error set_hint(css_select_state *state, css_hint *hint);
103static css_error set_initial(css_select_state *state,
104 uint32_t prop, css_pseudo_element pseudo,
105 void *parent);
106
107static css_error select_from_sheet(css_select_ctx *ctx,
108 const css_stylesheet *sheet, css_origin origin,
109 css_select_state *state);
110static css_error match_selectors_in_sheet(css_select_ctx *ctx,
111 const css_stylesheet *sheet, css_select_state *state);
112static css_error match_selector_chain(css_select_ctx *ctx,
113 const css_selector *selector, css_select_state *state);
114static css_error match_named_combinator(css_select_ctx *ctx,
115 css_combinator type, const css_selector *selector,
116 css_select_state *state, void *node, void **next_node);
117static css_error match_universal_combinator(css_select_ctx *ctx,
118 css_combinator type, const css_selector *selector,
119 css_select_state *state, void *node, bool_Bool may_optimise,
120 bool_Bool *rejected_by_cache, void **next_node);
121static css_error match_details(css_select_ctx *ctx, void *node,
122 const css_selector_detail *detail, css_select_state *state,
123 bool_Bool *match, css_pseudo_element *pseudo_element);
124static css_error match_detail(css_select_ctx *ctx, void *node,
125 const css_selector_detail *detail, css_select_state *state,
126 bool_Bool *match, css_pseudo_element *pseudo_element);
127static css_error cascade_style(const css_style *style, css_select_state *state);
128
129static css_error select_font_faces_from_sheet(
130 const css_stylesheet *sheet,
131 css_origin origin,
132 css_select_font_faces_state *state,
133 const css_select_strings *str);
134
135#ifdef DEBUG_CHAIN_MATCHING
136static void dump_chain(const css_selector *selector);
137#endif
138
139
140static css_bloom *css__get_empty_bloom(void)
141{
142 static css_bloom empty_bloom[CSS_BLOOM_SIZE4];
143 return empty_bloom;
144}
145
146
147static css_error css__create_node_data(struct css_node_data **node_data)
148{
149 struct css_node_data *nd;
150
151 nd = calloc(1, sizeof(struct css_node_data));
152 if (nd == NULL((void*)0)) {
153 return CSS_NOMEM;
154 }
155
156 *node_data = nd;
157
158 return CSS_OK;
159}
160
161static void css__destroy_node_data(struct css_node_data *node_data)
162{
163 int i;
164
165 assert(node_data != NULL)((node_data != ((void*)0)) ? (void) (0) : __assert_fail ("node_data != NULL"
, "src/select/select.c", 165, __extension__ __PRETTY_FUNCTION__
))
;
166
167 if (node_data->bloom != NULL((void*)0) &&
168 node_data->bloom != css__get_empty_bloom()) {
169 free(node_data->bloom);
170 }
171
172 for (i = 0; i < CSS_PSEUDO_ELEMENT_COUNT; i++) {
173 if (node_data->partial.styles[i] != NULL((void*)0)) {
174 css_computed_style_destroy(
175 node_data->partial.styles[i]);
176 }
177 }
178
179 free(node_data);
180}
181
182
183/* Exported function documented in public select.h header. */
184css_error css_libcss_node_data_handler(css_select_handler *handler,
185 css_node_data_action action, void *pw, void *node,
186 void *clone_node, void *libcss_node_data)
187{
188 struct css_node_data *node_data = libcss_node_data;
189 css_error error;
190
191 UNUSED(clone_node)((void)(clone_node));
192
193 if (handler == NULL((void*)0) || libcss_node_data == NULL((void*)0) ||
194 handler->handler_version != CSS_SELECT_HANDLER_VERSION_1) {
195 return CSS_BADPARM;
196 }
197
198 switch (action) {
199 case CSS_NODE_DELETED:
200 css__destroy_node_data(node_data);
201 break;
202
203 case CSS_NODE_MODIFIED:
204 case CSS_NODE_ANCESTORS_MODIFIED:
205 if (node == NULL((void*)0)) {
206 return CSS_BADPARM;
207 }
208
209 css__destroy_node_data(node_data);
210
211 /* Don't bother rebuilding node_data, it can be done
212 * when the node is selected for. Just ensure the
213 * client drops its reference to the libcss_node_data. */
214 error = handler->set_libcss_node_data(pw, node, NULL((void*)0));
215 if (error != CSS_OK) {
216 return error;
217 }
218 break;
219
220 case CSS_NODE_CLONED:
221 /* TODO: is it worth cloning libcss data? We only store
222 * data on the nodes as an optimisation, which is
223 * unlikely to be valid for most cloning cases.
224 */
225 break;
226
227 default:
228 return CSS_BADPARM;
229 }
230
231 return CSS_OK;
232}
233
234/**
235 * Create a selection context
236 *
237 * \param result Pointer to location to receive created context
238 * \return CSS_OK on success, appropriate error otherwise.
239 */
240css_error css_select_ctx_create(css_select_ctx **result)
241{
242 css_select_ctx *c;
243 css_error error;
244
245 if (result == NULL((void*)0))
246 return CSS_BADPARM;
247
248 c = calloc(1, sizeof(css_select_ctx));
249 if (c == NULL((void*)0))
250 return CSS_NOMEM;
251
252 error = css_calculator_create(&c->calc);
253 if (error != CSS_OK) {
254 free(c);
255 return error;
256 }
257
258 error = css_select_strings_intern(&c->str);
259 if (error != CSS_OK) {
260 css_calculator_unref(c->calc);
261 free(c);
262 return error;
263 }
264
265 *result = c;
266
267 return CSS_OK;
268}
269
270/**
271 * Destroy a selection context
272 *
273 * \param ctx The context to destroy
274 * \return CSS_OK on success, appropriate error otherwise
275 */
276css_error css_select_ctx_destroy(css_select_ctx *ctx)
277{
278 if (ctx == NULL((void*)0))
279 return CSS_BADPARM;
280
281 css_select_strings_unref(&ctx->str);
282
283 if (ctx->default_style != NULL((void*)0))
284 css_computed_style_destroy(ctx->default_style);
285
286 if (ctx->sheets != NULL((void*)0)) {
287 for (uint32_t index = 0; index < ctx->n_sheets; index++) {
288 css__mq_query_destroy(ctx->sheets[index].media);
289 }
290 free(ctx->sheets);
291 }
292
293 css_calculator_unref(ctx->calc);
294
295 free(ctx);
296
297 return CSS_OK;
298}
299
300/**
301 * Append a stylesheet to a selection context
302 *
303 * \param ctx The context to append to
304 * \param sheet The sheet to append
305 * \param origin Origin of the sheet
306 * \param media Media string for the stylesheet
307 * \return CSS_OK on success, appropriate error otherwise
308 */
309css_error css_select_ctx_append_sheet(css_select_ctx *ctx,
310 const css_stylesheet *sheet, css_origin origin,
311 const char *media)
312{
313 if (ctx == NULL((void*)0) || sheet == NULL((void*)0))
314 return CSS_BADPARM;
315
316 return css_select_ctx_insert_sheet(ctx, sheet, ctx->n_sheets,
317 origin, media);
318}
319
320/**
321 * Insert a stylesheet into a selection context
322 *
323 * \param ctx The context to insert into
324 * \param sheet Sheet to insert
325 * \param index Index in context to insert sheet
326 * \param origin Origin of the sheet
327 * \param media Media string for the stylesheet
328 * \return CSS_OK on success, appropriate error otherwise
329 */
330css_error css_select_ctx_insert_sheet(css_select_ctx *ctx,
331 const css_stylesheet *sheet, uint32_t index,
332 css_origin origin, const char *media)
333{
334 css_select_sheet *temp;
335 css_mq_query *mq;
336 css_error error;
337
338 if (ctx == NULL((void*)0) || sheet == NULL((void*)0))
339 return CSS_BADPARM;
340
341 /* Inline styles cannot be inserted into a selection context */
342 if (sheet->inline_style)
343 return CSS_INVALID;
344
345 /* Index must be in the range [0, n_sheets]
346 * The latter being equivalent to append */
347 if (index > ctx->n_sheets)
348 return CSS_INVALID;
349
350 temp = realloc(ctx->sheets,
351 (ctx->n_sheets + 1) * sizeof(css_select_sheet));
352 if (temp == NULL((void*)0))
353 return CSS_NOMEM;
354
355 ctx->sheets = temp;
356
357 if (index < ctx->n_sheets) {
358 memmove(&ctx->sheets[index + 1], &ctx->sheets[index],
359 (ctx->n_sheets - index) * sizeof(css_select_sheet));
360 }
361
362 error = css_parse_media_query(sheet->propstrings,
363 (const uint8_t *)media,
364 (media == NULL((void*)0)) ? 0 : strlen(media), &mq);
365 if (error == CSS_NOMEM) {
366 return error;
367 } else if (error != CSS_OK) {
368 /* Fall back to default media: "all". */
369 mq = calloc(1, sizeof(*mq));
370 if (mq == NULL((void*)0)) {
371 return CSS_NOMEM;
372 }
373 mq->type = CSS_MEDIA_ALL;
374 }
375
376 ctx->sheets[index].sheet = sheet;
377 ctx->sheets[index].origin = origin;
378 ctx->sheets[index].media = mq;
379
380 ctx->uses_revert |= sheet->uses_revert;
381
382 ctx->n_sheets++;
383
384 return CSS_OK;
385}
386
387/**
388 * Remove a sheet from a selection context
389 *
390 * \param ctx The context to remove from
391 * \param sheet Sheet to remove
392 * \return CSS_OK on success, appropriate error otherwise
393 */
394css_error css_select_ctx_remove_sheet(css_select_ctx *ctx,
395 const css_stylesheet *sheet)
396{
397 uint32_t index;
398
399 if (ctx == NULL((void*)0) || sheet == NULL((void*)0))
400 return CSS_BADPARM;
401
402 for (index = 0; index < ctx->n_sheets; index++) {
403 if (ctx->sheets[index].sheet == sheet)
404 break;
405 }
406
407 if (index == ctx->n_sheets)
408 return CSS_INVALID;
409
410 css__mq_query_destroy(ctx->sheets[index].media);
411
412 ctx->n_sheets--;
413
414 memmove(&ctx->sheets[index], &ctx->sheets[index + 1],
415 (ctx->n_sheets - index) * sizeof(css_select_sheet));
416
417 return CSS_OK;
418
419}
420
421/**
422 * Count the number of top-level sheets in a selection context
423 *
424 * \param ctx Context to consider
425 * \param count Pointer to location to receive count of sheets
426 * \return CSS_OK on success, appropriate error otherwise
427 */
428css_error css_select_ctx_count_sheets(css_select_ctx *ctx, uint32_t *count)
429{
430 if (ctx == NULL((void*)0) || count == NULL((void*)0))
431 return CSS_BADPARM;
432
433 *count = ctx->n_sheets;
434
435 return CSS_OK;
436}
437
438/**
439 * Retrieve a sheet from a selection context
440 *
441 * \param ctx Context to look in
442 * \param index Index in context to look
443 * \param sheet Pointer to location to receive sheet
444 * \return CSS_OK on success, appropriate error otherwise
445 */
446css_error css_select_ctx_get_sheet(css_select_ctx *ctx, uint32_t index,
447 const css_stylesheet **sheet)
448{
449 if (ctx == NULL((void*)0) || sheet == NULL((void*)0))
450 return CSS_BADPARM;
451
452 if (index > ctx->n_sheets)
453 return CSS_INVALID;
454
455 *sheet = ctx->sheets[index].sheet;
456
457 return CSS_OK;
458}
459
460
461/**
462 * Create a default style on the selection context
463 *
464 * \param ctx Context to create default style in
465 * \param handler Dispatch table of handler functions
466 * \param pw Client-specific private data for handler functions
467 * \return CSS_OK on success, appropriate error otherwise
468 */
469static css_error css__select_ctx_create_default_style(css_select_ctx *ctx,
470 css_select_handler *handler, void *pw)
471{
472 css_computed_style *style;
473 css_error error;
474
475 /* Need to construct the default style */
476 error = css__computed_style_create(&style, ctx->calc);
477 if (error != CSS_OK)
478 return error;
479
480 error = css__computed_style_initialise(style, handler, pw);
481 if (error != CSS_OK) {
482 css_computed_style_destroy(style);
483 return error;
484 }
485
486 /* Neither create nor initialise intern the style, so intern it now */
487 error = css__arena_intern_style(&style);
488 if (error != CSS_OK)
489 return error;
490
491 /* Store it on the ctx */
492 ctx->default_style = style;
493
494 return CSS_OK;
495}
496
497
498/**
499 * Get a default style, e.g. for an implied element's anonymous box
500 *
501 * \param ctx Selection context (used to avoid recreating default)
502 * \param handler Dispatch table of handler functions
503 * \param pw Client-specific private data for handler functions
504 * \param style Pointer to location to receive default style
505 * \return CSS_OK on success, appropriate error otherwise.
506 */
507css_error css_select_default_style(css_select_ctx *ctx,
508 css_select_handler *handler, void *pw,
509 css_computed_style **style)
510{
511 css_error error;
512
513 if (ctx == NULL((void*)0) || style == NULL((void*)0) || handler == NULL((void*)0) ||
514 handler->handler_version !=
515 CSS_SELECT_HANDLER_VERSION_1)
516 return CSS_BADPARM;
517
518 /* Ensure the ctx has a default style */
519 if (ctx->default_style == NULL((void*)0)) {
520 error = css__select_ctx_create_default_style(ctx, handler, pw);
521 if (error != CSS_OK) {
522 return error;
523 }
524 }
525
526 /* Pass a ref back to the client */
527 *style = css__computed_style_ref(ctx->default_style);
528 return CSS_OK;
529}
530
531
532/**
533 * Get a bloom filter for the parent node
534 *
535 * \param parent Parent node to get bloom filter for
536 * \param handler Dispatch table of handler functions
537 * \param pw Client-specific private data for handler functions
538 * \param parent_bloom Updated to parent bloom to use.
539 * Note: if there's no parent, the caller must free
540 * the returned parent bloom, since it has no node to
541 * own it.
542 * \return CSS_OK on success, appropriate error otherwise.
543 */
544static css_error css__get_parent_bloom(void *parent,
545 css_select_handler *handler, void *pw,
546 css_bloom **parent_bloom)
547{
548 struct css_node_data *node_data = NULL((void*)0);
549 css_bloom *bloom = NULL((void*)0);
550 css_error error;
551
552 /* Get parent node's bloom filter */
553 if (parent != NULL((void*)0)) {
554 /* Get parent bloom filter */
555 struct css_node_data *node_data;
556
557 /* Hideous casting to avoid warnings on all platforms
558 * we build for. */
559 error = handler->get_libcss_node_data(pw, parent,
560 (void **) (void *) &node_data);
561 if (error != CSS_OK) {
562 return error;
563 }
564 if (node_data != NULL((void*)0)) {
565 bloom = node_data->bloom;
566 }
567 }
568
569 if (bloom == NULL((void*)0)) {
570 uint32_t i;
571 /* Need to create parent bloom */
572
573 if (parent != NULL((void*)0)) {
574 /* TODO:
575 * Build & set the parent node's bloom properly.
576 * This will speed up the case where DOM change
577 * has caused bloom to get deleted. For now we
578 * fall back to a fully saturated bloom filter,
579 * which is slower but perfectly valid.
580 */
581 bloom = malloc(sizeof(css_bloom) * CSS_BLOOM_SIZE4);
582 if (bloom == NULL((void*)0)) {
583 return CSS_NOMEM;
584 }
585
586 for (i = 0; i < CSS_BLOOM_SIZE4; i++) {
587 bloom[i] = ~0;
588 }
589
590 if (node_data == NULL((void*)0)) {
591 error = css__create_node_data(&node_data);
592 if (error != CSS_OK) {
593 free(bloom);
594 return error;
595 }
596 node_data->bloom = bloom;
597
598 /* Set parent node bloom filter */
599 error = handler->set_libcss_node_data(pw,
600 parent, node_data);
601 if (error != CSS_OK) {
602 css__destroy_node_data(node_data);
603 return error;
604 }
605 }
606 } else {
607 /* No ancestors; empty bloom filter */
608 /* The parent bloom is owned by the parent node's
609 * node data. However, for the root node, there is
610 * no parent node to own the bloom filter.
611 * As such, we just use a pointer to static storage
612 * so calling code doesn't need to worry about
613 * whether the returned parent bloom is owned
614 * by something or not.
615 * Note, parent bloom is only read from, and not
616 * written to. */
617 bloom = css__get_empty_bloom();
618 }
619 }
620
621 *parent_bloom = bloom;
622 return CSS_OK;
623}
624
625static css_error css__create_node_bloom(
626 css_bloom **node_bloom, css_select_state *state)
627{
628 css_error error;
629 css_bloom *bloom;
630 lwc_hash hash;
631
632 *node_bloom = NULL((void*)0);
633
634 /* Create the node's bloom */
635 bloom = calloc(CSS_BLOOM_SIZE4, sizeof(css_bloom));
636 if (bloom == NULL((void*)0)) {
637 return CSS_NOMEM;
638 }
639
640 /* Add node name to bloom */
641 if (lwc_string_caseless_hash_value(state->element.name,
642 &hash) != lwc_error_ok) {
643 error = CSS_NOMEM;
644 goto cleanup;
645 }
646 css_bloom_add_hash(bloom, hash);
647
648 /* Add id name to bloom */
649 if (state->id != NULL((void*)0)) {
650 if (lwc_string_caseless_hash_value(state->id,
651 &hash) != lwc_error_ok) {
652 error = CSS_NOMEM;
653 goto cleanup;
654 }
655 css_bloom_add_hash(bloom, hash);
656 }
657
658 /* Add class names to bloom */
659 if (state->classes != NULL((void*)0)) {
660 for (uint32_t i = 0; i < state->n_classes; i++) {
661 lwc_string *s = state->classes[i];
662 if (lwc_string_caseless_hash_value(s,
663 &hash) != lwc_error_ok) {
664 error = CSS_NOMEM;
665 goto cleanup;
666 }
667 css_bloom_add_hash(bloom, hash);
668 }
669 }
670
671 /* Merge parent bloom into node bloom */
672 css_bloom_merge(state->node_data->bloom, bloom);
673 *node_bloom = bloom;
674
675 return CSS_OK;
676
677cleanup:
678 free(bloom);
679
680 return error;
681}
682
683/**
684 * Set a node's data
685 *
686 * \param node Node to set node data for
687 * \param state Selection state for node
688 * \param handler Dispatch table of handler functions
689 * \param pw Client-specific private data for handler functions
690 * \return CSS_OK on success, appropriate error otherwise.
691 */
692static css_error css__set_node_data(void *node, css_select_state *state,
693 css_select_handler *handler, void *pw)
694{
695 int i;
696 css_error error;
697 css_bloom *bloom;
698 css_select_results *results;
699
700 struct css_node_data *node_data = state->node_data;
701
702 /* Set node bloom filter */
703 error = css__create_node_bloom(&bloom, state);
704 if (error != CSS_OK) {
705 return error;
706 }
707 node_data->bloom = bloom;
708
709 /* Set selection results */
710 results = state->results;
711 for (i = 0; i < CSS_PSEUDO_ELEMENT_COUNT; i++) {
712 node_data->partial.styles[i] =
713 css__computed_style_ref(results->styles[i]);
714 }
715
716 error = handler->set_libcss_node_data(pw, node, node_data);
717 if (error != CSS_OK) {
718 css__destroy_node_data(node_data);
719 state->node_data = NULL((void*)0);
720 return error;
721 }
722
723 state->node_data = NULL((void*)0);
724
725 return CSS_OK;
726}
727
728
729/** The releationship of a share candidate node to the selection node. */
730enum share_candidate_type {
731 CANDIDATE_SIBLING,
732 CANDIDATE_COUSIN,
733};
734
735
736/**
737 * Get node_data for candidate node if we can reuse its style.
738 *
739 * \param[in] state The selection state for current node.
740 * \param[in] share_candidate_node The node to test id and classes of.
741 * \param[in] type The candidate's relation to selection node.
742 * \param[out] sharable_node_data Returns node_data or NULL.
743 * \return CSS_OK on success, appropriate error otherwise.
744 */
745static css_error css_select_style__get_sharable_node_data_for_candidate(
746 css_select_state *state,
747 void *share_candidate_node,
748 enum share_candidate_type type,
749 struct css_node_data **sharable_node_data)
750{
751 css_error error;
752 lwc_string *share_candidate_id;
753 uint32_t share_candidate_n_classes;
754 lwc_string **share_candidate_classes;
755 struct css_node_data *node_data;
756
757 UNUSED(type)((void)(type));
758
759 *sharable_node_data = NULL((void*)0);
760
761 /* We get the candidate node data first, as if it has none, we can't
762 * share its data anyway.
763 * Hideous casting to avoid warnings on all platforms we build for. */
764 error = state->handler->get_libcss_node_data(state->pw,
765 share_candidate_node, (void **) (void *) &node_data);
766 if (error != CSS_OK || node_data == NULL((void*)0)) {
767#ifdef DEBUG_STYLE_SHARING
768 printf(" \t%s\tno share: no candidate node data\n",
769 lwc_string_data(state->element.name)({((state->element.name != ((void*)0)) ? (void) (0) : __assert_fail
("state->element.name != NULL", "src/select/select.c", 769
, __extension__ __PRETTY_FUNCTION__)); (const char *)((state->
element.name)+1);})
);
770#endif
771 return error;
772 }
773
774 /* If one node has hints and other doesn't then can't share */
775 if ((node_data->flags & CSS_NODE_FLAGS_HAS_HINTS) !=
776 (state->node_data->flags & CSS_NODE_FLAGS_HAS_HINTS)) {
777#ifdef DEBUG_STYLE_SHARING
778 printf(" \t%s\tno share: have hints mismatch\n",
779 lwc_string_data(state->element.name)({((state->element.name != ((void*)0)) ? (void) (0) : __assert_fail
("state->element.name != NULL", "src/select/select.c", 779
, __extension__ __PRETTY_FUNCTION__)); (const char *)((state->
element.name)+1);})
);
780#endif
781 return CSS_OK;
782 }
783
784 /* If the node and candidate node had different pseudo classes, we
785 * can't share. */
786 if ((node_data->flags & CSS_NODE_FLAGS__PSEUDO_CLASSES_MASK) !=
787 (state->node_data->flags &
788 CSS_NODE_FLAGS__PSEUDO_CLASSES_MASK)) {
789#ifdef DEBUG_STYLE_SHARING
790 printf(" \t%s\tno share: different pseudo classes\n",
791 lwc_string_data(state->element.name)({((state->element.name != ((void*)0)) ? (void) (0) : __assert_fail
("state->element.name != NULL", "src/select/select.c", 791
, __extension__ __PRETTY_FUNCTION__)); (const char *)((state->
element.name)+1);})
);
792#endif
793 return CSS_OK;
794
795 }
796
797 /* If the node was affected by attribute or pseudo class rules,
798 * or had an inline style, it's not a candidate for sharing */
799 if (node_data->flags & (
800 CSS_NODE_FLAGS_TAINT_PSEUDO_CLASS |
801 CSS_NODE_FLAGS_TAINT_ATTRIBUTE |
802 CSS_NODE_FLAGS_TAINT_SIBLING |
803 CSS_NODE_FLAGS_HAS_INLINE_STYLE)) {
804#ifdef DEBUG_STYLE_SHARING
805 printf(" \t%s\tno share: candidate flags: %s%s%s%s\n",
806 lwc_string_data(state->element.name)({((state->element.name != ((void*)0)) ? (void) (0) : __assert_fail
("state->element.name != NULL", "src/select/select.c", 806
, __extension__ __PRETTY_FUNCTION__)); (const char *)((state->
element.name)+1);})
,
807 (node_data->flags &
808 CSS_NODE_FLAGS_TAINT_PSEUDO_CLASS) ?
809 "PSEUDOCLASS" : "",
810 (node_data->flags &
811 CSS_NODE_FLAGS_TAINT_ATTRIBUTE) ?
812 " ATTRIBUTE" : "",
813 (node_data->flags &
814 CSS_NODE_FLAGS_TAINT_SIBLING) ?
815 " SIBLING" : "",
816 (node_data->flags &
817 CSS_NODE_FLAGS_HAS_INLINE_STYLE) ?
818 " INLINE_STYLE" : "");
819#endif
820 return CSS_OK;
821 }
822
823 /* Check candidate ID doesn't prevent sharing */
824 error = state->handler->node_id(state->pw,
825 share_candidate_node,
826 &share_candidate_id);
827 if (error != CSS_OK) {
828 return error;
829
830 } else if (share_candidate_id != NULL((void*)0)) {
831 lwc_string_unref(share_candidate_id){ lwc_string *__lwc_s = (share_candidate_id); if (__lwc_s != (
(void*)0)) { __lwc_s->refcnt--; if ((__lwc_s->refcnt ==
0) || ((__lwc_s->refcnt == 1) && (__lwc_s->insensitive
== __lwc_s))) lwc_string_destroy(__lwc_s); } }
;
832#ifdef DEBUG_STYLE_SHARING
833 printf(" \t%s\tno share: candidate id\n",
834 lwc_string_data(state->element.name)({((state->element.name != ((void*)0)) ? (void) (0) : __assert_fail
("state->element.name != NULL", "src/select/select.c", 834
, __extension__ __PRETTY_FUNCTION__)); (const char *)((state->
element.name)+1);})
);
835#endif
836 return CSS_OK;
837 }
838
839 /* Check candidate classes don't prevent sharing */
840 error = state->handler->node_classes(state->pw,
841 share_candidate_node,
842 &share_candidate_classes,
843 &share_candidate_n_classes);
844 if (error != CSS_OK) {
845 return error;
846 }
847
848 if (state->n_classes != share_candidate_n_classes) {
849#ifdef DEBUG_STYLE_SHARING
850 printf(" \t%s\tno share: class count mismatch\n",
851 lwc_string_data(state->element.name)({((state->element.name != ((void*)0)) ? (void) (0) : __assert_fail
("state->element.name != NULL", "src/select/select.c", 851
, __extension__ __PRETTY_FUNCTION__)); (const char *)((state->
element.name)+1);})
);
852#endif
853 goto cleanup;
854 }
855
856 /* TODO: no need to care about the order, but it's simpler to
857 * have an ordered match, and authors are more likely to be
858 * consistent than not. */
859 for (uint32_t i = 0; i < share_candidate_n_classes; i++) {
860 bool_Bool match;
861 if (lwc_string_caseless_isequal(({ lwc_error __lwc_err = lwc_error_ok; lwc_string *__lwc_str1
= (state->classes[i]); lwc_string *__lwc_str2 = (share_candidate_classes
[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
; })
862 state->classes[i],({ lwc_error __lwc_err = lwc_error_ok; lwc_string *__lwc_str1
= (state->classes[i]); lwc_string *__lwc_str2 = (share_candidate_classes
[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
; })
863 share_candidate_classes[i],({ lwc_error __lwc_err = lwc_error_ok; lwc_string *__lwc_str1
= (state->classes[i]); lwc_string *__lwc_str2 = (share_candidate_classes
[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
; })
864 &match)({ lwc_error __lwc_err = lwc_error_ok; lwc_string *__lwc_str1
= (state->classes[i]); lwc_string *__lwc_str2 = (share_candidate_classes
[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
; })
== lwc_error_ok &&
865 match == false0) {
866#ifdef DEBUG_STYLE_SHARING
867 printf(" \t%s\tno share: class mismatch\n",
868 lwc_string_data(state->element.name)({((state->element.name != ((void*)0)) ? (void) (0) : __assert_fail
("state->element.name != NULL", "src/select/select.c", 868
, __extension__ __PRETTY_FUNCTION__)); (const char *)((state->
element.name)+1);})
);
869#endif
870 goto cleanup;
871 }
872 }
873
874 if (node_data->flags & CSS_NODE_FLAGS_HAS_HINTS) {
875 /* TODO: check hints match. For now, just prevent sharing */
876#ifdef DEBUG_STYLE_SHARING
877 printf(" \t%s\tno share: hints\n",
878 lwc_string_data(state->element.name)({((state->element.name != ((void*)0)) ? (void) (0) : __assert_fail
("state->element.name != NULL", "src/select/select.c", 878
, __extension__ __PRETTY_FUNCTION__)); (const char *)((state->
element.name)+1);})
);
879#endif
880 goto cleanup;
881 }
882
883 *sharable_node_data = node_data;
884
885cleanup:
886 if (share_candidate_classes != NULL((void*)0)) {
887 for (uint32_t i = 0; i < share_candidate_n_classes; i++) {
888 lwc_string_unref(share_candidate_classes[i]){ lwc_string *__lwc_s = (share_candidate_classes[i]); if (__lwc_s
!= ((void*)0)) { __lwc_s->refcnt--; if ((__lwc_s->refcnt
== 0) || ((__lwc_s->refcnt == 1) && (__lwc_s->
insensitive == __lwc_s))) lwc_string_destroy(__lwc_s); } }
;
889 }
890 }
891
892 return CSS_OK;
893}
894
895
896/**
897 * Get previous named cousin node.
898 *
899 * \param[in] state The selection state for current node.
900 * \param[in] node The node to get the cousin of.
901 * \param[out] cousin_out Returns a cousin node or NULL.
902 * \return CSS_OK on success or appropriate error otherwise.
903 */
904static css_error css_select_style__get_named_cousin(
905 css_select_state *state, void *node,
906 void **cousin_out)
907{
908 /* TODO:
909 *
910 * Consider cousin nodes; Go to parent's previous sibling's last child.
911 * The parent and the parent's sibling must be "similar".
912 */
913 UNUSED(state)((void)(state));
914 UNUSED(node)((void)(node));
915
916 *cousin_out = NULL((void*)0);
917
918 return CSS_OK;
919}
920
921
922/**
923 * Get node_data for any node that we can reuse the style for.
924 *
925 * This is an optimisation to needing to perform selection for a node,
926 * by sharing the style for a previous node.
927 *
928 * \param[in] node Node we're selecting for.
929 * \param[in] state The current selection state.
930 * \param[out] sharable_node_data Returns node_data or NULL.
931 * \return CSS_OK on success or appropriate error otherwise.
932 */
933static css_error css_select_style__get_sharable_node_data(
934 void *node, css_select_state *state,
935 struct css_node_data **sharable_node_data)
936{
937 css_error error;
938 enum share_candidate_type type = CANDIDATE_SIBLING;
939
940 *sharable_node_data = NULL((void*)0);
941
942 /* TODO: move this test to caller? */
943 if (state->id != NULL((void*)0)) {
944 /* If the node has an ID can't share another node's style. */
945 /* TODO: Consider whether this ID exists in the ID hash tables.
946 * (If not, the ID cannot affect the node's style.)
947 *
948 * Call css__selector_hash_find_by_id, for each sheet,
949 * and if we get a non-NULL "matched" then return.
950 *
951 * Check overhead is worth cost. */
952#ifdef DEBUG_STYLE_SHARING
953printf(" \t%s\tno share: node id (%s)\n", lwc_string_data(state->element.name)({((state->element.name != ((void*)0)) ? (void) (0) : __assert_fail
("state->element.name != NULL", "src/select/select.c", 953
, __extension__ __PRETTY_FUNCTION__)); (const char *)((state->
element.name)+1);})
, lwc_string_data(state->id)({((state->id != ((void*)0)) ? (void) (0) : __assert_fail (
"state->id != NULL", "src/select/select.c", 953, __extension__
__PRETTY_FUNCTION__)); (const char *)((state->id)+1);})
);
954#endif
955 return CSS_OK;
956 }
957 if (state->node_data->flags & CSS_NODE_FLAGS_HAS_INLINE_STYLE) {
958#ifdef DEBUG_STYLE_SHARING
959printf(" \t%s\tno share: inline style\n");
960#endif
961 return CSS_OK;
962 }
963
964 while (true1) {
965 void *share_candidate_node;
966
967 /* Get previous sibling with same element name */
968 error = state->handler->named_generic_sibling_node(state->pw,
969 node, &state->element, &share_candidate_node);
970 if (error != CSS_OK) {
971 return error;
972 } else {
973 if (share_candidate_node == NULL((void*)0)) {
974 error = css_select_style__get_named_cousin(
975 state, node,
976 &share_candidate_node);
977 if (error != CSS_OK) {
978 return error;
979 } else {
980 if (share_candidate_node == NULL((void*)0)) {
981 break;
982 }
983 }
984 type = CANDIDATE_COUSIN;
985 }
986 }
987
988 /* Check whether we can share the candidate node's
989 * style. We already know the element names match,
990 * check that candidate node's ID and class won't
991 * prevent sharing. */
992 error = css_select_style__get_sharable_node_data_for_candidate(
993 state, share_candidate_node,
994 type, sharable_node_data);
995 if (error != CSS_OK) {
996 return error;
997 }
998
999 if (*sharable_node_data != NULL((void*)0)) {
1000 /* Found style date we can share */
1001 break;
1002 }
1003
1004 /* Can't share with this; look for another */
1005 node = share_candidate_node;
1006 }
1007
1008 return CSS_OK;
1009}
1010
1011
1012/**
1013 * Finalise a selection state, releasing any resources it owns
1014 *
1015 * \param[in] state The selection state to finalise.
1016 */
1017static void css_select__finalise_selection_state(
1018 css_select_state *state)
1019{
1020 if (state->results != NULL((void*)0)) {
1021 css_select_results_destroy(state->results);
1022 }
1023
1024 if (state->node_data != NULL((void*)0)) {
1025 css__destroy_node_data(state->node_data);
1026 }
1027
1028 if (state->classes != NULL((void*)0)) {
1029 for (uint32_t i = 0; i < state->n_classes; i++) {
1030 lwc_string_unref(state->classes[i]){ lwc_string *__lwc_s = (state->classes[i]); if (__lwc_s !=
((void*)0)) { __lwc_s->refcnt--; if ((__lwc_s->refcnt ==
0) || ((__lwc_s->refcnt == 1) && (__lwc_s->insensitive
== __lwc_s))) lwc_string_destroy(__lwc_s); } }
;
1031 }
1032 }
1033
1034 lwc_string_unref(state->id){ lwc_string *__lwc_s = (state->id); if (__lwc_s != ((void
*)0)) { __lwc_s->refcnt--; if ((__lwc_s->refcnt == 0) ||
((__lwc_s->refcnt == 1) && (__lwc_s->insensitive
== __lwc_s))) lwc_string_destroy(__lwc_s); } }
;
1035 lwc_string_unref(state->element.ns){ lwc_string *__lwc_s = (state->element.ns); if (__lwc_s !=
((void*)0)) { __lwc_s->refcnt--; if ((__lwc_s->refcnt ==
0) || ((__lwc_s->refcnt == 1) && (__lwc_s->insensitive
== __lwc_s))) lwc_string_destroy(__lwc_s); } }
;
1036 lwc_string_unref(state->element.name){ lwc_string *__lwc_s = (state->element.name); if (__lwc_s
!= ((void*)0)) { __lwc_s->refcnt--; if ((__lwc_s->refcnt
== 0) || ((__lwc_s->refcnt == 1) && (__lwc_s->
insensitive == __lwc_s))) lwc_string_destroy(__lwc_s); } }
;
1037
1038 if (state->revert != NULL((void*)0)) {
1039 for (size_t i = 0; i < CSS_ORIGIN_AUTHOR; i++) {
1040 for (size_t j = 0; j < CSS_PSEUDO_ELEMENT_COUNT; j++) {
1041 if (state->revert[i].style[j] == NULL((void*)0)) {
1042 continue;
1043 }
1044 css_computed_style_destroy(
1045 state->revert[i].style[j]);
1046 }
1047 }
1048 free(state->revert);
1049 }
1050}
1051
1052
1053/**
1054 * Initialise a selection state.
1055 *
1056 * \param[in] state The selection state to initialise
1057 * \param[in] node The node we are selecting for.
1058 * \param[in] parent The node's parent node, or NULL.
1059 * \param[in] media The media specification we're selecting for.
1060 * \param[in] unit_ctx Unit conversion context.
1061 * \param[in] handler The client selection callback table.
1062 * \param[in] pw The client private data, passed out to callbacks.
1063 * \return CSS_OK or appropriate error otherwise.
1064 */
1065static css_error css_select__initialise_selection_state(
1066 css_select_state *state,
1067 void *node,
1068 void *parent,
1069 const css_media *media,
1070 const css_unit_ctx *unit_ctx,
1071 css_select_handler *handler,
1072 void *pw)
1073{
1074 css_error error;
1075 bool_Bool match;
1076
1077 /* Set up the selection state */
1078 memset(state, 0, sizeof(*state));
1079 state->node = node;
1080 state->media = media;
1081 state->unit_ctx = unit_ctx;
1082 state->handler = handler;
1083 state->pw = pw;
1084 state->next_reject = state->reject_cache +
1085 (N_ELEMENTS(state->reject_cache)(sizeof((state->reject_cache)) / sizeof((state->reject_cache
)[0]))
- 1);
1086
1087 /* Allocate the result set */
1088 state->results = calloc(1, sizeof(css_select_results));
1089 if (state->results == NULL((void*)0)) {
1090 return CSS_NOMEM;
1091 }
1092
1093 error = css__create_node_data(&state->node_data);
1094 if (error != CSS_OK) {
1095 goto failed;
1096 }
1097
1098 error = css__get_parent_bloom(parent, handler, pw,
1099 &state->node_data->bloom);
1100 if (error != CSS_OK) {
1101 goto failed;
1102 }
1103
1104 /* Get node's name */
1105 error = handler->node_name(pw, node, &state->element);
1106 if (error != CSS_OK){
1107 goto failed;
1108 }
1109
1110 /* Get node's ID, if any */
1111 error = handler->node_id(pw, node, &state->id);
1112 if (error != CSS_OK){
1113 goto failed;
1114 }
1115
1116 /* Get node's classes, if any */
1117 error = handler->node_classes(pw, node,
1118 &state->classes, &state->n_classes);
1119 if (error != CSS_OK){
1120 goto failed;
1121 }
1122
1123 /* Node pseudo classes */
1124 error = handler->node_is_link(pw, node, &match);
1125 if (error != CSS_OK){
1126 goto failed;
1127 } else if (match) {
1128 state->node_data->flags |= CSS_NODE_FLAGS_PSEUDO_CLASS_LINK;
1129 }
1130
1131 error = handler->node_is_visited(pw, node, &match);
1132 if (error != CSS_OK){
1133 goto failed;
1134 } else if (match) {
1135 state->node_data->flags |= CSS_NODE_FLAGS_PSEUDO_CLASS_VISITED;
1136 }
1137
1138 error = handler->node_is_hover(pw, node, &match);
1139 if (error != CSS_OK){
1140 goto failed;
1141 } else if (match) {
1142 state->node_data->flags |= CSS_NODE_FLAGS_PSEUDO_CLASS_HOVER;
1143 }
1144
1145 error = handler->node_is_active(pw, node, &match);
1146 if (error != CSS_OK){
1147 goto failed;
1148 } else if (match) {
1149 state->node_data->flags |= CSS_NODE_FLAGS_PSEUDO_CLASS_ACTIVE;
1150 }
1151
1152 error = handler->node_is_focus(pw, node, &match);
1153 if (error != CSS_OK){
1154 goto failed;
1155 } else if (match) {
1156 state->node_data->flags |= CSS_NODE_FLAGS_PSEUDO_CLASS_FOCUS;
1157 }
1158
1159 return CSS_OK;
1160
1161failed:
1162 css_select__finalise_selection_state(state);
1163 return error;
1164}
1165
1166static css_error css__select_revert_property_to_origin(
1167 css_select_state *select_state,
1168 prop_state *prop_state,
1169 css_origin origin,
1170 enum css_pseudo_element pseudo,
1171 enum css_properties_e property)
1172{
1173 css_error error;
1174
1175 if (select_state->results->styles[pseudo] == NULL((void*)0)) {
1176 return CSS_OK;
1177 }
1178
1179 if (select_state->revert[origin].style[pseudo] == NULL((void*)0)) {
1180 return prop_dispatch[property].initial(select_state);
1181 }
1182
1183 error = prop_dispatch[property].copy(
1184 select_state->revert[origin].style[pseudo],
1185 select_state->results->styles[pseudo]);
1186 if (error != CSS_OK) {
1187 return error;
1188 }
1189
1190 *prop_state = select_state->revert[origin].props[property][pseudo];
1191 return CSS_OK;
1192}
1193
1194static css_error css__select_revert_property(
1195 css_select_state *select_state,
1196 prop_state *prop_state,
1197 enum css_pseudo_element pseudo,
1198 enum css_properties_e property)
1199{
1200 css_error error;
1201
1202 switch (prop_state->origin) {
1203 case CSS_ORIGIN_AUTHOR:
1204 error = css__select_revert_property_to_origin(
1205 select_state, prop_state, CSS_ORIGIN_USER,
1206 pseudo, property);
1207 if (error != CSS_OK) {
1208 return error;
1209 }
1210 if (prop_state->explicit_default != FLAG_VALUE_REVERT) {
1211 break;
1212 }
1213 /* Fall-through */
1214 case CSS_ORIGIN_USER:
1215 error = css__select_revert_property_to_origin(
1216 select_state, prop_state, CSS_ORIGIN_UA,
1217 pseudo, property);
1218 if (error != CSS_OK) {
1219 return error;
1220 }
1221 if (prop_state->explicit_default != FLAG_VALUE_REVERT) {
1222 break;
1223 }
1224 /* Fall-through */
1225 case CSS_ORIGIN_UA:
1226 prop_state->explicit_default = FLAG_VALUE_UNSET;
1227 break;
1228 }
1229
1230 return CSS_OK;
1231}
1232
1233/**
1234 * Select a style for the given node
1235 *
1236 * \param ctx Selection context to use
1237 * \param node Node to select style for
1238 * \param unit_ctx Context for length unit conversions.
1239 * \param media Currently active media specification
1240 * \param inline_style Corresponding inline style for node, or NULL
1241 * \param handler Dispatch table of handler functions
1242 * \param pw Client-specific private data for handler functions
1243 * \param result Pointer to location to receive result set
1244 * \return CSS_OK on success, appropriate error otherwise.
1245 *
1246 * In computing the style, no reference is made to the parent node's
1247 * style. Therefore, the resultant computed style is not ready for
1248 * immediate use, as some properties may be marked as inherited.
1249 * Use css_computed_style_compose() to obtain a fully computed style.
1250 *
1251 * This two-step approach to style computation is designed to allow
1252 * the client to store the partially computed style and efficiently
1253 * update the fully computed style for a node when layout changes.
1254 */
1255css_error css_select_style(css_select_ctx *ctx, void *node,
1
[debug] analyzing from css_select_style
1256 const css_unit_ctx *unit_ctx,
1257 const css_media *media, const css_stylesheet *inline_style,
1258 css_select_handler *handler, void *pw,
1259 css_select_results **result)
1260{
1261 css_origin origin = CSS_ORIGIN_UA;
1262 uint32_t i, j, nhints;
1263 css_error error;
1264 css_select_state state;
1265 css_hint *hints = NULL((void*)0);
1266 void *parent = NULL((void*)0);
1267 struct css_node_data *share;
1268
1269 if (ctx == NULL((void*)0) || node == NULL((void*)0) || result == NULL((void*)0) || handler == NULL((void*)0) ||
2
Assuming 'ctx' is not equal to NULL
3
Assuming 'node' is not equal to NULL
4
Assuming 'result' is not equal to NULL
5
Assuming 'handler' is not equal to NULL
7
Taking false branch
1270 handler->handler_version != CSS_SELECT_HANDLER_VERSION_1)
6
Assuming field 'handler_version' is equal to CSS_SELECT_HANDLER_VERSION_1
1271 return CSS_BADPARM;
1272
1273 error = handler->parent_node(pw, node, &parent);
1274 if (error != CSS_OK)
8
Assuming 'error' is equal to CSS_OK
9
Taking false branch
1275 return error;
1276
1277 error = css_select__initialise_selection_state(
1278 &state, node, parent, media, unit_ctx, handler, pw);
1279 if (error
9.1
'error' is equal to CSS_OK
!= CSS_OK)
10
Taking false branch
1280 return error;
1281
1282 /* Fetch presentational hints */
1283 error = handler->node_presentational_hint(pw, node, &nhints, &hints);
1284 if (error != CSS_OK)
11
Assuming 'error' is equal to CSS_OK
12
Taking false branch
1285 goto cleanup;
1286 if (nhints > 0) {
13
Assuming 'nhints' is <= 0
14
Taking false branch
1287 state.node_data->flags |= CSS_NODE_FLAGS_HAS_HINTS;
1288 }
1289
1290 if (inline_style != NULL((void*)0)) {
15
Assuming 'inline_style' is equal to NULL
16
Taking false branch
1291 state.node_data->flags |= CSS_NODE_FLAGS_HAS_INLINE_STYLE;
1292 }
1293
1294 /* Check if we can share another node's style */
1295 error = css_select_style__get_sharable_node_data(node, &state, &share);
1296 if (error
16.1
'error' is equal to CSS_OK
!= CSS_OK) {
17
Taking false branch
1297 goto cleanup;
1298 } else if (share
17.1
'share' is equal to NULL
!= NULL((void*)0)) {
1299 css_computed_style **styles = share->partial.styles;
1300 for (i = 0; i < CSS_PSEUDO_ELEMENT_COUNT; i++) {
1301 state.results->styles[i] =
1302 css__computed_style_ref(styles[i]);
1303 }
1304#ifdef DEBUG_STYLE_SHARING
1305 printf("style:\t%s\tSHARED!\n",
1306 lwc_string_data(state.element.name)({((state.element.name != ((void*)0)) ? (void) (0) : __assert_fail
("state.element.name != NULL", "src/select/select.c", 1306, __extension__
__PRETTY_FUNCTION__)); (const char *)((state.element.name)+1
);})
);
1307#endif
1308 goto complete;
1309 }
1310#ifdef DEBUG_STYLE_SHARING
1311 printf("style:\t%s\tSELECTED\n", lwc_string_data(state.element.name)({((state.element.name != ((void*)0)) ? (void) (0) : __assert_fail
("state.element.name != NULL", "src/select/select.c", 1311, __extension__
__PRETTY_FUNCTION__)); (const char *)((state.element.name)+1
);})
);
1312#endif
1313
1314 /* Not sharing; need to select. */
1315 if (ctx->uses_revert ||
18
Assuming field 'uses_revert' is false
1316 (inline_style
18.1
'inline_style' is equal to NULL
!= NULL((void*)0) && inline_style->uses_revert)) {
1317 /* Need to track UA and USER origin styles for revert. */
1318 state.revert = calloc(CSS_ORIGIN_AUTHOR, sizeof(*state.revert));
1319 if (state.revert == NULL((void*)0)) {
1320 error = CSS_NOMEM;
1321 goto cleanup;
1322 }
1323 }
1324
1325 /* Base element style is guaranteed to exist
1326 */
1327 error = css__computed_style_create(
1328 &state.results->styles[CSS_PSEUDO_ELEMENT_NONE], ctx->calc);
1329 if (error != CSS_OK) {
19
Assuming 'error' is equal to CSS_OK
20
Taking false branch
1330 goto cleanup;
1331 }
1332
1333 /* Apply any hints */
1334 if (nhints
20.1
'nhints' is <= 0
> 0) {
21
Taking false branch
1335 /* Ensure that the appropriate computed style exists */
1336 struct css_computed_style *computed_style =
1337 state.results->styles[CSS_PSEUDO_ELEMENT_NONE];
1338 state.computed = computed_style;
1339
1340 for (i = 0; i < nhints; i++) {
1341 error = set_hint(&state, &hints[i]);
1342 if (error != CSS_OK)
1343 goto cleanup;
1344 }
1345 }
1346
1347 /* Iterate through the top-level stylesheets, selecting styles
1348 * from those which apply to our current media requirements and
1349 * are not disabled */
1350 if (ctx->n_sheets > 0) {
22
Assuming field 'n_sheets' is > 0
23
Taking true branch
1351 origin = ctx->sheets[0].origin;
1352 }
1353 for (i = 0; i
23.1
'i' is < field 'n_sheets'
< ctx->n_sheets; i++) {
24
Loop condition is true. Entering loop body
1354 const css_select_sheet s = ctx->sheets[i];
1355
1356 if (state.revert != NULL((void*)0) && s.origin != origin) {
25
Assuming field 'revert' is equal to NULL
1357 for (j = 0; j < CSS_PSEUDO_ELEMENT_COUNT; j++) {
1358 if (state.results->styles[j] == NULL((void*)0)) {
1359 continue;
1360 }
1361 error = css__computed_style_clone(
1362 state.results->styles[j],
1363 &state.revert[origin].style[j]);
1364 if (error != CSS_OK) {
1365 goto cleanup;
1366 }
1367 memcpy(state.revert[origin].props,
1368 state.props, sizeof(state.props));
1369 }
1370 origin = s.origin;
1371 }
1372
1373 if (mq__list_match(s.media, unit_ctx, media, &ctx->str) &&
27
Taking true branch
1374 s.sheet->disabled == false0) {
26
Assuming field 'disabled' is equal to false
1375 error = select_from_sheet(ctx, s.sheet,
28
Calling 'select_from_sheet'
1376 s.origin, &state);
1377 if (error != CSS_OK)
1378 goto cleanup;
1379 }
1380 }
1381
1382 /* Consider any inline style for the node */
1383 if (inline_style != NULL((void*)0)) {
1384 css_rule_selector *sel =
1385 (css_rule_selector *) inline_style->rule_list;
1386
1387 /* Sanity check style */
1388 if (inline_style->rule_count != 1 ||
1389 inline_style->rule_list->type != CSS_RULE_SELECTOR ||
1390 inline_style->rule_list->items != 0) {
1391 error = CSS_INVALID;
1392 goto cleanup;
1393 }
1394
1395 /* No bytecode if input was empty or wholly invalid */
1396 if (sel->style != NULL((void*)0)) {
1397 /* Inline style applies to base element only */
1398 state.current_pseudo = CSS_PSEUDO_ELEMENT_NONE;
1399 state.computed = state.results->styles[
1400 CSS_PSEUDO_ELEMENT_NONE];
1401
1402 error = cascade_style(sel->style, &state);
1403 if (error != CSS_OK)
1404 goto cleanup;
1405 }
1406 }
1407
1408 /* Fix up any remaining unset properties. */
1409
1410 /* Base element */
1411 state.current_pseudo = CSS_PSEUDO_ELEMENT_NONE;
1412 state.computed = state.results->styles[CSS_PSEUDO_ELEMENT_NONE];
1413 for (i = 0; i < CSS_N_PROPERTIES; i++) {
1414 prop_state *prop = &state.props[i][CSS_PSEUDO_ELEMENT_NONE];
1415
1416 if (prop->explicit_default == FLAG_VALUE_REVERT) {
1417 error = css__select_revert_property(&state, prop,
1418 CSS_PSEUDO_ELEMENT_NONE, i);
1419 if (error != CSS_OK) {
1420 goto cleanup;
1421 }
1422 }
1423
1424 if (prop->explicit_default == FLAG_VALUE_UNSET) {
1425 if (prop_dispatch[i].inherited == true1) {
1426 prop->explicit_default = FLAG_VALUE_INHERIT;
1427 } else {
1428 prop->explicit_default = FLAG_VALUE_INITIAL;
1429 }
1430 }
1431
1432 /* If the property is still unset or it's set to inherit
1433 * and we're the root element, then set it to its initial
1434 * value. */
1435 if (prop->explicit_default == FLAG_VALUE_INITIAL ||
1436 prop->set == false0 ||
1437 (parent == NULL((void*)0) &&
1438 prop->explicit_default == FLAG_VALUE_INHERIT)) {
1439 error = set_initial(&state, i,
1440 CSS_PSEUDO_ELEMENT_NONE, parent);
1441 if (error != CSS_OK)
1442 goto cleanup;
1443 }
1444 }
1445
1446 /* Pseudo elements, if any */
1447 for (j = CSS_PSEUDO_ELEMENT_NONE + 1; j < CSS_PSEUDO_ELEMENT_COUNT; j++) {
1448 state.current_pseudo = j;
1449 state.computed = state.results->styles[j];
1450
1451 /* Skip non-existent pseudo elements */
1452 if (state.computed == NULL((void*)0))
1453 continue;
1454
1455 for (i = 0; i < CSS_N_PROPERTIES; i++) {
1456 prop_state *prop = &state.props[i][j];
1457
1458 if (prop->explicit_default == FLAG_VALUE_REVERT) {
1459 error = css__select_revert_property(&state,
1460 prop, j, i);
1461 if (error != CSS_OK) {
1462 goto cleanup;
1463 }
1464 }
1465
1466 if (prop->explicit_default == FLAG_VALUE_UNSET) {
1467 if (prop_dispatch[i].inherited == true1) {
1468 prop->explicit_default = FLAG_VALUE_INHERIT;
1469 } else {
1470 prop->explicit_default = FLAG_VALUE_INITIAL;
1471 }
1472 }
1473
1474 /* If the property is still unset then set it
1475 * to its initial value. */
1476 if (prop->explicit_default == FLAG_VALUE_INITIAL ||
1477 prop->set == false0) {
1478 error = set_initial(&state, i, j, parent);
1479 if (error != CSS_OK)
1480 goto cleanup;
1481 }
1482 }
1483 }
1484
1485 /* If this is the root element, then we must ensure that all
1486 * length values are absolute, display and float are correctly
1487 * computed, and the default border-{top,right,bottom,left}-color
1488 * is set to the computed value of color. */
1489 if (parent == NULL((void*)0)) {
1490 /* Only compute absolute values for the base element */
1491 error = css__compute_absolute_values(NULL((void*)0),
1492 state.results->styles[CSS_PSEUDO_ELEMENT_NONE],
1493 unit_ctx);
1494 if (error != CSS_OK)
1495 goto cleanup;
1496 }
1497
1498 /* Intern the partial computed styles */
1499 for (j = CSS_PSEUDO_ELEMENT_NONE; j < CSS_PSEUDO_ELEMENT_COUNT; j++) {
1500 /* Skip non-existent pseudo elements */
1501 if (state.results->styles[j] == NULL((void*)0))
1502 continue;
1503
1504 error = css__arena_intern_style(&state.results->styles[j]);
1505 if (error != CSS_OK) {
1506 goto cleanup;
1507 }
1508 }
1509
1510complete:
1511 error = css__set_node_data(node, &state, handler, pw);
1512 if (error != CSS_OK) {
1513 goto cleanup;
1514 }
1515
1516 /* Steal the results from the selection state, so they don't get
1517 * freed when the selection state is finalised */
1518 *result = state.results;
1519 state.results = NULL((void*)0);
1520
1521 error = CSS_OK;
1522
1523cleanup:
1524 css_select__finalise_selection_state(&state);
1525
1526 return error;
1527}
1528
1529/**
1530 * Destroy a selection result set
1531 *
1532 * \param results Result set to destroy
1533 * \return CSS_OK on success, appropriate error otherwise
1534 */
1535css_error css_select_results_destroy(css_select_results *results)
1536{
1537 uint32_t i;
1538
1539 if (results == NULL((void*)0))
1540 return CSS_BADPARM;
1541
1542 for (i = 0; i < CSS_PSEUDO_ELEMENT_COUNT; i++) {
1543 if (results->styles[i] != NULL((void*)0))
1544 css_computed_style_destroy(results->styles[i]);
1545 }
1546
1547 free(results);
1548
1549 return CSS_OK;
1550}
1551
1552/**
1553 * Search a selection context for defined font faces
1554 *
1555 * \param ctx Selection context
1556 * \param media Currently active media spec
1557 * \param unit_ctx Current unit conversion context.
1558 * \param font_family Font family to search for
1559 * \param result Pointer to location to receive result
1560 * \return CSS_OK on success, appropriate error otherwise.
1561 */
1562css_error css_select_font_faces(css_select_ctx *ctx,
1563 const css_media *media,
1564 const css_unit_ctx *unit_ctx,
1565 lwc_string *font_family,
1566 css_select_font_faces_results **result)
1567{
1568 uint32_t i;
1569 css_error error;
1570 css_select_font_faces_state state;
1571 uint32_t n_font_faces;
1572
1573 if (ctx == NULL((void*)0) || font_family == NULL((void*)0) || result == NULL((void*)0))
1574 return CSS_BADPARM;
1575
1576 memset(&state, 0, sizeof(css_select_font_faces_state));
1577 state.font_family = font_family;
1578 state.media = media;
1579 state.unit_ctx = unit_ctx;
1580
1581 /* Iterate through the top-level stylesheets, selecting font-faces
1582 * from those which apply to our current media requirements and
1583 * are not disabled */
1584 for (i = 0; i < ctx->n_sheets; i++) {
1585 const css_select_sheet s = ctx->sheets[i];
1586
1587 if (mq__list_match(s.media, unit_ctx, media, &ctx->str) &&
1588 s.sheet->disabled == false0) {
1589 error = select_font_faces_from_sheet(s.sheet,
1590 s.origin, &state, &ctx->str);
1591 if (error != CSS_OK)
1592 goto cleanup;
1593 }
1594 }
1595
1596 n_font_faces = state.ua_font_faces.count +
1597 state.user_font_faces.count +
1598 state.author_font_faces.count;
1599
1600
1601 if (n_font_faces > 0) {
1602 /* We found some matching faces. Make a results structure with
1603 * the font faces in priority order. */
1604 css_select_font_faces_results *results;
1605
1606 results = malloc(sizeof(css_select_font_faces_results));
1607 if (results == NULL((void*)0)) {
1608 error = CSS_NOMEM;
1609 goto cleanup;
1610 }
1611
1612 results->font_faces = malloc(
1613 n_font_faces * sizeof(css_font_face *));
1614 if (results->font_faces == NULL((void*)0)) {
1615 free(results);
1616 error = CSS_NOMEM;
1617 goto cleanup;
1618 }
1619
1620 results->n_font_faces = n_font_faces;
1621
1622 i = 0;
1623 if (state.ua_font_faces.count != 0) {
1624 memcpy(results->font_faces,
1625 state.ua_font_faces.font_faces,
1626 sizeof(css_font_face *) *
1627 state.ua_font_faces.count);
1628
1629 i += state.ua_font_faces.count;
1630 }
1631
1632 if (state.user_font_faces.count != 0) {
1633 memcpy(results->font_faces + i,
1634 state.user_font_faces.font_faces,
1635 sizeof(css_font_face *) *
1636 state.user_font_faces.count);
1637 i += state.user_font_faces.count;
1638 }
1639
1640 if (state.author_font_faces.count != 0) {
1641 memcpy(results->font_faces + i,
1642 state.author_font_faces.font_faces,
1643 sizeof(css_font_face *) *
1644 state.author_font_faces.count);
1645 }
1646
1647 *result = results;
1648 }
1649
1650 error = CSS_OK;
1651
1652cleanup:
1653 if (state.ua_font_faces.count != 0)
1654 free(state.ua_font_faces.font_faces);
1655
1656 if (state.user_font_faces.count != 0)
1657 free(state.user_font_faces.font_faces);
1658
1659 if (state.author_font_faces.count != 0)
1660 free(state.author_font_faces.font_faces);
1661
1662 return error;
1663}
1664
1665/**
1666 * Destroy a font-face result set
1667 *
1668 * \param results Result set to destroy
1669 * \return CSS_OK on success, appropriate error otherwise
1670 */
1671css_error css_select_font_faces_results_destroy(
1672 css_select_font_faces_results *results)
1673{
1674 if (results == NULL((void*)0))
1675 return CSS_BADPARM;
1676
1677 if (results->font_faces != NULL((void*)0)) {
1678 /* Don't destroy the individual css_font_faces, they're owned
1679 by their respective sheets */
1680 free(results->font_faces);
1681 }
1682
1683 free(results);
1684
1685 return CSS_OK;
1686}
1687
1688/******************************************************************************
1689 * Selection engine internals below here *
1690 ******************************************************************************/
1691
1692
1693css_error set_hint(css_select_state *state, css_hint *hint)
1694{
1695 uint32_t prop = hint->prop;
1696 prop_state *existing = &state->props[prop][CSS_PSEUDO_ELEMENT_NONE];
1697 css_error error;
1698
1699 /* Hint defined -- set it in the result */
1700 error = prop_dispatch[prop].set_from_hint(hint, state->computed);
1701 if (error != CSS_OK)
1702 return error;
1703
1704 /* Keep selection state in sync with reality */
1705 existing->set = 1;
1706 existing->specificity = 0;
1707 existing->origin = CSS_ORIGIN_AUTHOR;
1708 existing->important = 0;
1709 existing->explicit_default = (hint->status == 0) ?
1710 FLAG_VALUE_INHERIT : FLAG_VALUE__NONE;
1711
1712 return CSS_OK;
1713}
1714
1715css_error set_initial(css_select_state *state,
1716 uint32_t prop, css_pseudo_element pseudo,
1717 void *parent)
1718{
1719 css_error error;
1720
1721 /* Do nothing if this property is inherited (the default state
1722 * of a clean computed style is for everything to be set to inherit)
1723 *
1724 * If the node is tree root and we're dealing with the base element,
1725 * everything should be defaulted.
1726 */
1727 if (state->props[prop][pseudo].explicit_default == FLAG_VALUE_INITIAL ||
1728 prop_dispatch[prop].inherited == false0 ||
1729 (pseudo == CSS_PSEUDO_ELEMENT_NONE && parent == NULL((void*)0))) {
1730 error = prop_dispatch[prop].initial(state);
1731 if (error != CSS_OK)
1732 return error;
1733 }
1734
1735 return CSS_OK;
1736}
1737
1738#define IMPORT_STACK_SIZE 256
1739
1740css_error select_from_sheet(css_select_ctx *ctx, const css_stylesheet *sheet,
1741 css_origin origin, css_select_state *state)
1742{
1743 const css_stylesheet *s = sheet;
1744 const css_rule *rule = s->rule_list;
1745 uint32_t sp = 0;
1746 const css_rule *import_stack[IMPORT_STACK_SIZE];
1747
1748 do {
1749 /* Find first non-charset rule, if we're at the list head */
1750 if (rule
28.1
'rule' is equal to field 'rule_list'
== s->rule_list) {
1751 while (rule != NULL((void*)0) && rule->type == CSS_RULE_CHARSET)
29
Assuming 'rule' is equal to NULL
1752 rule = rule->next;
1753 }
1754
1755 if (rule
29.1
'rule' is equal to NULL
!= NULL((void*)0) && rule->type == CSS_RULE_IMPORT) {
1756 /* Current rule is an import */
1757 const css_rule_import *import =
1758 (const css_rule_import *) rule;
1759
1760 if (import->sheet != NULL((void*)0) &&
1761 mq__list_match(import->media,
1762 state->unit_ctx,
1763 state->media,
1764 &ctx->str)) {
1765 /* It's applicable, so process it */
1766 if (sp >= IMPORT_STACK_SIZE)
1767 return CSS_NOMEM;
1768
1769 import_stack[sp++] = rule;
1770
1771 s = import->sheet;
1772 rule = s->rule_list;
1773 } else {
1774 /* Not applicable; skip over it */
1775 rule = rule->next;
1776 }
1777 } else {
1778 /* Gone past import rules in this sheet */
1779 css_error error;
1780
1781 /* Process this sheet */
1782 state->sheet = s;
1783 state->current_origin = origin;
1784
1785 error = match_selectors_in_sheet(ctx, s, state);
30
Calling 'match_selectors_in_sheet'
1786 if (error != CSS_OK)
1787 return error;
1788
1789 /* Find next sheet to process */
1790 if (sp > 0) {
1791 sp--;
1792 rule = import_stack[sp]->next;
1793 s = import_stack[sp]->parent;
1794 } else {
1795 s = NULL((void*)0);
1796 }
1797 }
1798 } while (s != NULL((void*)0));
1799
1800 return CSS_OK;
1801}
1802
1803static css_error _select_font_face_from_rule(
1804 const css_rule_font_face *rule, css_origin origin,
1805 css_select_font_faces_state *state,
1806 const css_select_strings *str)
1807{
1808 if (mq_rule_good_for_media((const css_rule *) rule,
1809 state->unit_ctx, state->media, str)) {
1810 bool_Bool correct_family = false0;
1811
1812 if (lwc_string_isequal(((*(&correct_family) = ((rule->font_face->font_family
) == (state->font_family))), lwc_error_ok)
1813 rule->font_face->font_family,((*(&correct_family) = ((rule->font_face->font_family
) == (state->font_family))), lwc_error_ok)
1814 state->font_family,((*(&correct_family) = ((rule->font_face->font_family
) == (state->font_family))), lwc_error_ok)
1815 &correct_family)((*(&correct_family) = ((rule->font_face->font_family
) == (state->font_family))), lwc_error_ok)
== lwc_error_ok &&
1816 correct_family) {
1817 css_select_font_faces_list *faces = NULL((void*)0);
1818 const css_font_face **new_faces;
1819 uint32_t index;
1820 size_t new_size;
1821
1822 switch (origin) {
1823 case CSS_ORIGIN_UA:
1824 faces = &state->ua_font_faces;
1825 break;
1826 case CSS_ORIGIN_USER:
1827 faces = &state->user_font_faces;
1828 break;
1829 case CSS_ORIGIN_AUTHOR:
1830 faces = &state->author_font_faces;
1831 break;
1832 }
1833
1834 index = faces->count++;
1835 new_size = faces->count * sizeof(css_font_face *);
1836
1837 new_faces = realloc(faces->font_faces, new_size);
1838 if (new_faces == NULL((void*)0)) {
1839 return CSS_NOMEM;
1840 }
1841 faces->font_faces = new_faces;
1842
1843 faces->font_faces[index] = rule->font_face;
1844 }
1845 }
1846
1847 return CSS_OK;
1848}
1849
1850static css_error select_font_faces_from_sheet(
1851 const css_stylesheet *sheet,
1852 css_origin origin,
1853 css_select_font_faces_state *state,
1854 const css_select_strings *str)
1855{
1856 const css_stylesheet *s = sheet;
1857 const css_rule *rule = s->rule_list;
1858 uint32_t sp = 0;
1859 const css_rule *import_stack[IMPORT_STACK_SIZE];
1860
1861 do {
1862 /* Find first non-charset rule, if we're at the list head */
1863 if (rule == s->rule_list) {
1864 while (rule != NULL((void*)0) && rule->type == CSS_RULE_CHARSET)
1865 rule = rule->next;
1866 }
1867
1868 if (rule != NULL((void*)0) && rule->type == CSS_RULE_IMPORT) {
1869 /* Current rule is an import */
1870 const css_rule_import *import =
1871 (const css_rule_import *) rule;
1872
1873 if (import->sheet != NULL((void*)0) &&
1874 mq__list_match(import->media,
1875 state->unit_ctx,
1876 state->media,
1877 str)) {
1878 /* It's applicable, so process it */
1879 if (sp >= IMPORT_STACK_SIZE)
1880 return CSS_NOMEM;
1881
1882 import_stack[sp++] = rule;
1883
1884 s = import->sheet;
1885 rule = s->rule_list;
1886 } else {
1887 /* Not applicable; skip over it */
1888 rule = rule->next;
1889 }
1890 } else if (rule != NULL((void*)0) && rule->type == CSS_RULE_FONT_FACE) {
1891 css_error error;
1892
1893 error = _select_font_face_from_rule(
1894 (const css_rule_font_face *) rule,
1895 origin, state, str);
1896
1897 if (error != CSS_OK)
1898 return error;
1899
1900 rule = rule->next;
1901 } else if (rule == NULL((void*)0)) {
1902 /* Find next sheet to process */
1903 if (sp > 0) {
1904 sp--;
1905 rule = import_stack[sp]->next;
1906 s = import_stack[sp]->parent;
1907 } else {
1908 s = NULL((void*)0);
1909 }
1910 } else {
1911 rule = rule->next;
1912 }
1913 } while (s != NULL((void*)0));
1914
1915 return CSS_OK;
1916}
1917
1918#undef IMPORT_STACK_SIZE
1919
1920static inline bool_Bool _selectors_pending(const css_selector **node,
1921 const css_selector **id, const css_selector ***classes,
1922 uint32_t n_classes, const css_selector **univ)
1923{
1924 bool_Bool pending = false0;
1925 uint32_t i;
1926
1927 pending |= *node != NULL((void*)0);
1928 pending |= *id != NULL((void*)0);
1929 pending |= *univ != NULL((void*)0);
1930
1931 if (classes != NULL((void*)0) && n_classes > 0) {
1932 for (i = 0; i < n_classes; i++)
1933 pending |= *(classes[i]) != NULL((void*)0);
1934 }
1935
1936 return pending;
1937}
1938
1939static inline bool_Bool _selector_less_specific(const css_selector *ref,
1940 const css_selector *cand)
1941{
1942 bool_Bool result = true1;
1943
1944 if (cand == NULL((void*)0))
1945 return false0;
1946
1947 if (ref == NULL((void*)0))
1948 return true1;
1949
1950 /* Sort by specificity */
1951 if (cand->specificity < ref->specificity) {
1952 result = true1;
1953 } else if (ref->specificity < cand->specificity) {
1954 result = false0;
1955 } else {
1956 /* Then by rule index -- earliest wins */
1957 if (cand->rule->index < ref->rule->index)
1958 result = true1;
1959 else
1960 result = false0;
1961 }
1962
1963 return result;
1964}
1965
1966static const css_selector *_selector_next(const css_selector **node,
1967 const css_selector **id, const css_selector ***classes,
1968 uint32_t n_classes, const css_selector **univ,
1969 css_select_rule_source *src)
1970{
1971 const css_selector *ret = NULL((void*)0);
1972
1973 if (_selector_less_specific(ret, *node)) {
39
Taking false branch
1974 ret = *node;
1975 src->source = CSS_SELECT_RULE_SRC_ELEMENT;
1976 }
1977
1978 if (_selector_less_specific(ret, *id)) {
40
Taking true branch
1979 ret = *id;
1980 src->source = CSS_SELECT_RULE_SRC_ID;
41
The value 2 is assigned to 'src.source', which participates in a condition later
1981 }
1982
1983 if (_selector_less_specific(ret, *univ)) {
1984 ret = *univ;
1985 src->source = CSS_SELECT_RULE_SRC_UNIVERSAL;
1986 }
1987
1988 if (classes
41.1
'classes' is equal to NULL
!= NULL((void*)0) && n_classes > 0) {
1989 uint32_t i;
1990
1991 for (i = 0; i < n_classes; i++) {
1992 if (_selector_less_specific(ret, *(classes[i]))) {
1993 ret = *(classes[i]);
1994 src->source = CSS_SELECT_RULE_SRC_CLASS;
1995 src->class = i;
1996 }
1997 }
1998 }
1999
2000 return ret;
2001}
2002
2003css_error match_selectors_in_sheet(css_select_ctx *ctx,
2004 const css_stylesheet *sheet, css_select_state *state)
2005{
2006 static const css_selector *empty_selector = NULL((void*)0);
2007 const uint32_t n_classes = state->n_classes;
2008 uint32_t i = 0;
2009 const css_selector **node_selectors = &empty_selector;
2010 css_selector_hash_iterator node_iterator;
2011 const css_selector **id_selectors = &empty_selector;
2012 css_selector_hash_iterator id_iterator;
31
'id_iterator' declared without an initial value
2013 const css_selector ***class_selectors = NULL((void*)0);
2014 css_selector_hash_iterator class_iterator;
2015 const css_selector **univ_selectors = &empty_selector;
2016 css_selector_hash_iterator univ_iterator;
2017 css_select_rule_source src = { CSS_SELECT_RULE_SRC_ELEMENT, 0 };
2018 struct css_hash_selection_requirments req;
2019 css_error error;
2020
2021 /* Set up general selector chain requirments */
2022 req.media = state->media;
2023 req.unit_ctx = state->unit_ctx;
2024 req.node_bloom = state->node_data->bloom;
2025 req.str = &ctx->str;
2026
2027 /* Find hash chain that applies to current node */
2028 req.qname = state->element;
2029 error = css__selector_hash_find(sheet->selectors,
2030 &req, &node_iterator,
2031 &node_selectors);
2032 if (error != CSS_OK)
32
Assuming 'error' is equal to CSS_OK
2033 goto cleanup;
2034
2035 if (state->classes != NULL((void*)0) && n_classes > 0) {
33
Assuming field 'classes' is equal to NULL
2036 /* Find hash chains for node classes */
2037 class_selectors = malloc(n_classes * sizeof(css_selector **));
2038 if (class_selectors == NULL((void*)0)) {
2039 error = CSS_NOMEM;
2040 goto cleanup;
2041 }
2042
2043 for (i = 0; i < n_classes; i++) {
2044 req.class = state->classes[i];
2045 error = css__selector_hash_find_by_class(
2046 sheet->selectors, &req,
2047 &class_iterator, &class_selectors[i]);
2048 if (error != CSS_OK)
2049 goto cleanup;
2050 }
2051 }
2052
2053 if (state->id
33.1
Field 'id' is equal to NULL
!= NULL((void*)0)) {
34
Taking false branch
2054 /* Find hash chain for node ID */
2055 req.id = state->id;
2056 error = css__selector_hash_find_by_id(sheet->selectors,
2057 &req, &id_iterator, &id_selectors);
2058 if (error != CSS_OK)
2059 goto cleanup;
2060 }
2061
2062 /* Find hash chain for universal selector */
2063 error = css__selector_hash_find_universal(sheet->selectors, &req,
2064 &univ_iterator, &univ_selectors);
2065 if (error != CSS_OK)
35
Assuming 'error' is equal to CSS_OK
36
Taking false branch
2066 goto cleanup;
2067
2068 /* Process matching selectors, if any */
2069 while (_selectors_pending(node_selectors, id_selectors,
37
Loop condition is true. Entering loop body
2070 class_selectors, n_classes, univ_selectors)) {
2071 const css_selector *selector;
2072
2073 /* Selectors must be matched in ascending order of specificity
2074 * and rule index. (c.f. css__outranks_existing())
2075 *
2076 * Pick the least specific/earliest occurring selector.
2077 */
2078 selector = _selector_next(node_selectors, id_selectors,
38
Calling '_selector_next'
42
Returning from '_selector_next'
2079 class_selectors, n_classes, univ_selectors,
2080 &src);
2081
2082 /* We know there are selectors pending, so should have a
2083 * selector here */
2084 assert(selector != NULL)((selector != ((void*)0)) ? (void) (0) : __assert_fail ("selector != NULL"
, "src/select/select.c", 2084, __extension__ __PRETTY_FUNCTION__
))
;
43
'?' condition is true
2085
2086 /* Match and handle the selector chain */
2087 error = match_selector_chain(ctx, selector, state);
2088 if (error
43.1
'error' is equal to CSS_OK
!= CSS_OK)
44
Taking false branch
2089 goto cleanup;
2090
2091 /* Advance to next selector in whichever chain we extracted
2092 * the processed selector from. */
2093 switch (src.source) {
45
Control jumps to 'case CSS_SELECT_RULE_SRC_ID:' at line 2099
2094 case CSS_SELECT_RULE_SRC_ELEMENT:
2095 error = node_iterator(&req, node_selectors,
2096 &node_selectors);
2097 break;
2098
2099 case CSS_SELECT_RULE_SRC_ID:
2100 error = id_iterator(&req, id_selectors,
46
Called function pointer is an uninitialized pointer value
2101 &id_selectors);
2102 break;
2103
2104 case CSS_SELECT_RULE_SRC_UNIVERSAL:
2105 error = univ_iterator(&req, univ_selectors,
2106 &univ_selectors);
2107 break;
2108
2109 case CSS_SELECT_RULE_SRC_CLASS:
2110 req.class = state->classes[src.class];
2111 error = class_iterator(&req, class_selectors[src.class],
2112 &class_selectors[src.class]);
2113 break;
2114 }
2115
2116 if (error != CSS_OK)
2117 goto cleanup;
2118 }
2119
2120 error = CSS_OK;
2121cleanup:
2122 if (class_selectors != NULL((void*)0))
2123 free(class_selectors);
2124
2125 return error;
2126}
2127
2128static void update_reject_cache(css_select_state *state,
2129 css_combinator comb, const css_selector *s)
2130{
2131 const css_selector_detail *detail = &s->data;
2132 const css_selector_detail *next_detail = NULL((void*)0);
2133
2134 if (detail->next)
2135 next_detail = detail + 1;
2136
2137 if (state->next_reject < state->reject_cache ||
2138 comb != CSS_COMBINATOR_ANCESTOR ||
2139 next_detail == NULL((void*)0) ||
2140 next_detail->next != 0 ||
2141 (next_detail->type != CSS_SELECTOR_CLASS &&
2142 next_detail->type != CSS_SELECTOR_ID))
2143 return;
2144
2145 /* Insert */
2146 state->next_reject->type = next_detail->type;
2147 state->next_reject->value = next_detail->qname.name;
2148 state->next_reject--;
2149}
2150
2151css_error match_selector_chain(css_select_ctx *ctx,
2152 const css_selector *selector, css_select_state *state)
2153{
2154 const css_selector *s = selector;
2155 void *node = state->node;
2156 const css_selector_detail *detail = &s->data;
2157 bool_Bool match = false0, may_optimise = true1;
2158 bool_Bool rejected_by_cache;
2159 css_pseudo_element pseudo;
2160 css_error error;
2161
2162#ifdef DEBUG_CHAIN_MATCHING
2163 fprintf(stderrstderr, "matching: ");
2164 dump_chain(selector);
2165 fprintf(stderrstderr, "\n");
2166#endif
2167
2168 /* Match the details of the first selector in the chain.
2169 *
2170 * Note that pseudo elements will only appear as details of
2171 * the first selector in the chain, as the parser will reject
2172 * any selector chains containing pseudo elements anywhere
2173 * else.
2174 */
2175 error = match_details(ctx, node, detail, state, &match, &pseudo);
2176 if (error != CSS_OK)
2177 return error;
2178
2179 /* Details don't match, so reject selector chain */
2180 if (match == false0)
2181 return CSS_OK;
2182
2183 /* Iterate up the selector chain, matching combinators */
2184 do {
2185 void *next_node = NULL((void*)0);
2186
2187 /* Consider any combinator on this selector */
2188 if (s->data.comb != CSS_COMBINATOR_NONE &&
2189 s->combinator->data.qname.name !=
2190 ctx->str.universal) {
2191 /* Named combinator */
2192 may_optimise &=
2193 (s->data.comb == CSS_COMBINATOR_ANCESTOR ||
2194 s->data.comb == CSS_COMBINATOR_PARENT);
2195
2196 error = match_named_combinator(ctx, s->data.comb,
2197 s->combinator, state, node, &next_node);
2198 if (error != CSS_OK)
2199 return error;
2200
2201 /* No match for combinator, so reject selector chain */
2202 if (next_node == NULL((void*)0))
2203 return CSS_OK;
2204 } else if (s->data.comb != CSS_COMBINATOR_NONE) {
2205 /* Universal combinator */
2206 may_optimise &=
2207 (s->data.comb == CSS_COMBINATOR_ANCESTOR ||
2208 s->data.comb == CSS_COMBINATOR_PARENT);
2209
2210 error = match_universal_combinator(ctx, s->data.comb,
2211 s->combinator, state, node,
2212 may_optimise, &rejected_by_cache,
2213 &next_node);
2214 if (error != CSS_OK)
2215 return error;
2216
2217 /* No match for combinator, so reject selector chain */
2218 if (next_node == NULL((void*)0)) {
2219 if (may_optimise && s == selector &&
2220 rejected_by_cache == false0) {
2221 update_reject_cache(state, s->data.comb,
2222 s->combinator);
2223 }
2224
2225 return CSS_OK;
2226 }
2227 }
2228
2229 /* Details matched, so progress to combining selector */
2230 s = s->combinator;
2231 node = next_node;
2232 } while (s != NULL((void*)0));
2233
2234 /* If we got here, then the entire selector chain matched, so cascade */
2235 state->current_specificity = selector->specificity;
2236
2237 /* Ensure that the appropriate computed style exists */
2238 if (state->results->styles[pseudo] == NULL((void*)0)) {
2239 error = css__computed_style_create(
2240 &state->results->styles[pseudo], ctx->calc);
2241 if (error != CSS_OK)
2242 return error;
2243 }
2244
2245 state->current_pseudo = pseudo;
2246 state->computed = state->results->styles[pseudo];
2247
2248 return cascade_style(((css_rule_selector *) selector->rule)->style,
2249 state);
2250}
2251
2252css_error match_named_combinator(css_select_ctx *ctx, css_combinator type,
2253 const css_selector *selector, css_select_state *state,
2254 void *node, void **next_node)
2255{
2256 const css_selector_detail *detail = &selector->data;
2257 void *n = node;
2258 css_error error;
2259
2260 do {
2261 bool_Bool match = false0;
2262
2263 /* Find candidate node */
2264 switch (type) {
2265 case CSS_COMBINATOR_ANCESTOR:
2266 error = state->handler->named_ancestor_node(state->pw,
2267 n, &selector->data.qname, &n);
2268 if (error != CSS_OK)
2269 return error;
2270 break;
2271 case CSS_COMBINATOR_PARENT:
2272 error = state->handler->named_parent_node(state->pw,
2273 n, &selector->data.qname, &n);
2274 if (error != CSS_OK)
2275 return error;
2276 break;
2277 case CSS_COMBINATOR_SIBLING:
2278 error = state->handler->named_sibling_node(state->pw,
2279 n, &selector->data.qname, &n);
2280 if (error != CSS_OK)
2281 return error;
2282 if (node == state->node) {
2283 state->node_data->flags |=
2284 CSS_NODE_FLAGS_TAINT_SIBLING;
2285 }
2286 break;
2287 case CSS_COMBINATOR_GENERIC_SIBLING:
2288 error = state->handler->named_generic_sibling_node(
2289 state->pw, n, &selector->data.qname,
2290 &n);
2291 if (error != CSS_OK)
2292 return error;
2293 if (node == state->node) {
2294 state->node_data->flags |=
2295 CSS_NODE_FLAGS_TAINT_SIBLING;
2296 }
2297 case CSS_COMBINATOR_NONE:
2298 break;
2299 }
2300
2301 if (n != NULL((void*)0)) {
2302 /* Match its details */
2303 error = match_details(ctx, n, detail, state,
2304 &match, NULL((void*)0));
2305 if (error != CSS_OK)
2306 return error;
2307
2308 /* If we found a match, use it */
2309 if (match == true1)
2310 break;
2311
2312 /* For parent and sibling selectors, only adjacent
2313 * nodes are valid. Thus, if we failed to match,
2314 * give up. */
2315 if (type == CSS_COMBINATOR_PARENT ||
2316 type == CSS_COMBINATOR_SIBLING)
2317 n = NULL((void*)0);
2318 }
2319 } while (n != NULL((void*)0));
2320
2321 *next_node = n;
2322
2323 return CSS_OK;
2324}
2325
2326static inline void add_node_flags(const void *node,
2327 const css_select_state *state, css_node_flags flags)
2328{
2329 /* If the node in question is the node we're selecting for then its
2330 * style has been tainted by particular rules that affect whether the
2331 * node's style can be shared. We don't care whether the rule matched
2332 * or not, just that such a rule has been considered. */
2333 if (node == state->node) {
2334 state->node_data->flags |= flags;
2335 }
2336}
2337
2338css_error match_universal_combinator(css_select_ctx *ctx, css_combinator type,
2339 const css_selector *selector, css_select_state *state,
2340 void *node, bool_Bool may_optimise, bool_Bool *rejected_by_cache,
2341 void **next_node)
2342{
2343 const css_selector_detail *detail = &selector->data;
2344 const css_selector_detail *next_detail = NULL((void*)0);
2345 void *n = node;
2346 css_error error;
2347
2348 if (detail->next)
2349 next_detail = detail + 1;
2350
2351 *rejected_by_cache = false0;
2352
2353 /* Consult reject cache first */
2354 if (may_optimise && (type == CSS_COMBINATOR_ANCESTOR ||
2355 type == CSS_COMBINATOR_PARENT) &&
2356 next_detail != NULL((void*)0) &&
2357 (next_detail->type == CSS_SELECTOR_CLASS ||
2358 next_detail->type == CSS_SELECTOR_ID)) {
2359 reject_item *reject = state->next_reject + 1;
2360 reject_item *last = state->reject_cache +
2361 N_ELEMENTS(state->reject_cache)(sizeof((state->reject_cache)) / sizeof((state->reject_cache
)[0]))
- 1;
2362 bool_Bool match = false0;
2363
2364 while (reject <= last) {
2365 /* Perform pessimistic matching (may hurt quirks) */
2366 if (reject->type == next_detail->type &&
2367 lwc_string_isequal(reject->value,((*(&match) = ((reject->value) == (next_detail->qname
.name))), lwc_error_ok)
2368 next_detail->qname.name,((*(&match) = ((reject->value) == (next_detail->qname
.name))), lwc_error_ok)
2369 &match)((*(&match) = ((reject->value) == (next_detail->qname
.name))), lwc_error_ok)
== lwc_error_ok &&
2370 match) {
2371 /* Found it: can't match */
2372 *next_node = NULL((void*)0);
2373 *rejected_by_cache = true1;
2374 return CSS_OK;
2375 }
2376
2377 reject++;
2378 }
2379 }
2380
2381 do {
2382 bool_Bool match = false0;
2383
2384 /* Find candidate node */
2385 switch (type) {
2386 case CSS_COMBINATOR_ANCESTOR:
2387 case CSS_COMBINATOR_PARENT:
2388 error = state->handler->parent_node(state->pw, n, &n);
2389 if (error != CSS_OK)
2390 return error;
2391 break;
2392 case CSS_COMBINATOR_SIBLING:
2393 case CSS_COMBINATOR_GENERIC_SIBLING:
2394 error = state->handler->sibling_node(state->pw, n, &n);
2395 if (error != CSS_OK)
2396 return error;
2397 add_node_flags(node, state,
2398 CSS_NODE_FLAGS_TAINT_SIBLING);
2399 break;
2400 case CSS_COMBINATOR_NONE:
2401 break;
2402 }
2403
2404 if (n != NULL((void*)0)) {
2405 /* Match its details */
2406 error = match_details(ctx, n, detail, state,
2407 &match, NULL((void*)0));
2408 if (error != CSS_OK)
2409 return error;
2410
2411 /* If we found a match, use it */
2412 if (match == true1)
2413 break;
2414
2415 /* For parent and sibling selectors, only adjacent
2416 * nodes are valid. Thus, if we failed to match,
2417 * give up. */
2418 if (type == CSS_COMBINATOR_PARENT ||
2419 type == CSS_COMBINATOR_SIBLING)
2420 n = NULL((void*)0);
2421 }
2422 } while (n != NULL((void*)0));
2423
2424 *next_node = n;
2425
2426 return CSS_OK;
2427}
2428
2429css_error match_details(css_select_ctx *ctx, void *node,
2430 const css_selector_detail *detail, css_select_state *state,
2431 bool_Bool *match, css_pseudo_element *pseudo_element)
2432{
2433 css_error error;
2434 css_pseudo_element pseudo = CSS_PSEUDO_ELEMENT_NONE;
2435
2436 /* Skip the element selector detail, which is always first.
2437 * (Named elements are handled by match_named_combinator, so the
2438 * element selector detail always matches here.) */
2439 if (detail->next)
2440 detail++;
2441 else
2442 detail = NULL((void*)0);
2443
2444 /* We match by default (if there are no details other than the element
2445 * selector, then we must match) */
2446 *match = true1;
2447
2448 /** \todo Some details are easier to test than others (e.g. dashmatch
2449 * actually requires looking at data rather than simply comparing
2450 * pointers). Should we consider sorting the detail list such that the
2451 * simpler details come first (and thus the expensive match routines
2452 * can be avoided unless absolutely necessary)? */
2453
2454 while (detail != NULL((void*)0)) {
2455 error = match_detail(ctx, node, detail, state, match, &pseudo);
2456 if (error != CSS_OK)
2457 return error;
2458
2459 /* Detail doesn't match, so reject selector chain */
2460 if (*match == false0)
2461 return CSS_OK;
2462
2463 if (detail->next)
2464 detail++;
2465 else
2466 detail = NULL((void*)0);
2467 }
2468
2469 /* Return the applicable pseudo element, if required */
2470 if (pseudo_element != NULL((void*)0))
2471 *pseudo_element = pseudo;
2472
2473 return CSS_OK;
2474}
2475
2476static inline bool_Bool match_nth(int32_t a, int32_t b, int32_t count)
2477{
2478 if (a == 0) {
2479 return count == b;
2480 } else {
2481 const int32_t delta = count - b;
2482
2483 /* (count - b) / a is positive or (count - b) is 0 */
2484 if (((delta > 0) == (a > 0)) || delta == 0) {
2485 /* (count - b) / a is integer */
2486 return (delta % a == 0);
2487 }
2488
2489 return false0;
2490 }
2491}
2492
2493css_error match_detail(css_select_ctx *ctx, void *node,
2494 const css_selector_detail *detail, css_select_state *state,
2495 bool_Bool *match, css_pseudo_element *pseudo_element)
2496{
2497 bool_Bool is_root = false0;
2498 css_error error = CSS_OK;
2499 css_node_flags flags = CSS_NODE_FLAGS_TAINT_PSEUDO_CLASS;
2500
2501 switch (detail->type) {
2502 case CSS_SELECTOR_ELEMENT:
2503 if (detail->negate != 0) {
2504 /* Only need to test this inside not(), since
2505 * it will have been considered as a named node
2506 * otherwise. */
2507 error = state->handler->node_has_name(state->pw, node,
2508 &detail->qname, match);
2509 }
2510 break;
2511 case CSS_SELECTOR_CLASS:
2512 error = state->handler->node_has_class(state->pw, node,
2513 detail->qname.name, match);
2514 break;
2515 case CSS_SELECTOR_ID:
2516 error = state->handler->node_has_id(state->pw, node,
2517 detail->qname.name, match);
2518 break;
2519 case CSS_SELECTOR_PSEUDO_CLASS:
2520 error = state->handler->node_is_root(state->pw, node, &is_root);
2521 if (error != CSS_OK)
2522 return error;
2523
2524 if (is_root == false0 &&
2525 detail->qname.name == ctx->str.first_child) {
2526 int32_t num_before = 0;
2527
2528 error = state->handler->node_count_siblings(state->pw,
2529 node, false0, false0, &num_before);
2530 if (error == CSS_OK)
2531 *match = (num_before == 0);
2532 } else if (is_root == false0 &&
2533 detail->qname.name == ctx->str.nth_child) {
2534 int32_t num_before = 0;
2535
2536 error = state->handler->node_count_siblings(state->pw,
2537 node, false0, false0, &num_before);
2538 if (error == CSS_OK) {
2539 int32_t a = detail->value.nth.a;
2540 int32_t b = detail->value.nth.b;
2541
2542 *match = match_nth(a, b, num_before + 1);
2543 }
2544 } else if (is_root == false0 &&
2545 detail->qname.name == ctx->str.nth_last_child) {
2546 int32_t num_after = 0;
2547
2548 error = state->handler->node_count_siblings(state->pw,
2549 node, false0, true1, &num_after);
2550 if (error == CSS_OK) {
2551 int32_t a = detail->value.nth.a;
2552 int32_t b = detail->value.nth.b;
2553
2554 *match = match_nth(a, b, num_after + 1);
2555 }
2556 } else if (is_root == false0 &&
2557 detail->qname.name == ctx->str.nth_of_type) {
2558 int32_t num_before = 0;
2559
2560 error = state->handler->node_count_siblings(state->pw,
2561 node, true1, false0, &num_before);
2562 if (error == CSS_OK) {
2563 int32_t a = detail->value.nth.a;
2564 int32_t b = detail->value.nth.b;
2565
2566 *match = match_nth(a, b, num_before + 1);
2567 }
2568 } else if (is_root == false0 &&
2569 detail->qname.name == ctx->str.nth_last_of_type) {
2570 int32_t num_after = 0;
2571
2572 error = state->handler->node_count_siblings(state->pw,
2573 node, true1, true1, &num_after);
2574 if (error == CSS_OK) {
2575 int32_t a = detail->value.nth.a;
2576 int32_t b = detail->value.nth.b;
2577
2578 *match = match_nth(a, b, num_after + 1);
2579 }
2580 } else if (is_root == false0 &&
2581 detail->qname.name == ctx->str.last_child) {
2582 int32_t num_after = 0;
2583
2584 error = state->handler->node_count_siblings(state->pw,
2585 node, false0, true1, &num_after);
2586 if (error == CSS_OK)
2587 *match = (num_after == 0);
2588 } else if (is_root == false0 &&
2589 detail->qname.name == ctx->str.first_of_type) {
2590 int32_t num_before = 0;
2591
2592 error = state->handler->node_count_siblings(state->pw,
2593 node, true1, false0, &num_before);
2594 if (error == CSS_OK)
2595 *match = (num_before == 0);
2596 } else if (is_root == false0 &&
2597 detail->qname.name == ctx->str.last_of_type) {
2598 int32_t num_after = 0;
2599
2600 error = state->handler->node_count_siblings(state->pw,
2601 node, true1, true1, &num_after);
2602 if (error == CSS_OK)
2603 *match = (num_after == 0);
2604 } else if (is_root == false0 &&
2605 detail->qname.name == ctx->str.only_child) {
2606 int32_t num_before = 0, num_after = 0;
2607
2608 error = state->handler->node_count_siblings(state->pw,
2609 node, false0, false0, &num_before);
2610 if (error == CSS_OK) {
2611 error = state->handler->node_count_siblings(
2612 state->pw, node, false0, true1,
2613 &num_after);
2614 if (error == CSS_OK)
2615 *match = (num_before == 0) &&
2616 (num_after == 0);
2617 }
2618 } else if (is_root == false0 &&
2619 detail->qname.name == ctx->str.only_of_type) {
2620 int32_t num_before = 0, num_after = 0;
2621
2622 error = state->handler->node_count_siblings(state->pw,
2623 node, true1, false0, &num_before);
2624 if (error == CSS_OK) {
2625 error = state->handler->node_count_siblings(
2626 state->pw, node, true1, true1,
2627 &num_after);
2628 if (error == CSS_OK)
2629 *match = (num_before == 0) &&
2630 (num_after == 0);
2631 }
2632 } else if (detail->qname.name == ctx->str.root) {
2633 *match = is_root;
2634 } else if (detail->qname.name == ctx->str.empty) {
2635 error = state->handler->node_is_empty(state->pw,
2636 node, match);
2637 } else if (detail->qname.name == ctx->str.link) {
2638 error = state->handler->node_is_link(state->pw,
2639 node, match);
2640 flags = CSS_NODE_FLAGS_NONE;
2641 } else if (detail->qname.name == ctx->str.visited) {
2642 error = state->handler->node_is_visited(state->pw,
2643 node, match);
2644 flags = CSS_NODE_FLAGS_NONE;
2645 } else if (detail->qname.name == ctx->str.hover) {
2646 error = state->handler->node_is_hover(state->pw,
2647 node, match);
2648 flags = CSS_NODE_FLAGS_NONE;
2649 } else if (detail->qname.name == ctx->str.active) {
2650 error = state->handler->node_is_active(state->pw,
2651 node, match);
2652 flags = CSS_NODE_FLAGS_NONE;
2653 } else if (detail->qname.name == ctx->str.focus) {
2654 error = state->handler->node_is_focus(state->pw,
2655 node, match);
2656 flags = CSS_NODE_FLAGS_NONE;
2657 } else if (detail->qname.name == ctx->str.target) {
2658 error = state->handler->node_is_target(state->pw,
2659 node, match);
2660 } else if (detail->qname.name == ctx->str.lang) {
2661 error = state->handler->node_is_lang(state->pw,
2662 node, detail->value.string, match);
2663 } else if (detail->qname.name == ctx->str.enabled) {
2664 error = state->handler->node_is_enabled(state->pw,
2665 node, match);
2666 } else if (detail->qname.name == ctx->str.disabled) {
2667 error = state->handler->node_is_disabled(state->pw,
2668 node, match);
2669 } else if (detail->qname.name == ctx->str.checked) {
2670 error = state->handler->node_is_checked(state->pw,
2671 node, match);
2672 } else {
2673 *match = false0;
2674 }
2675 add_node_flags(node, state, flags);
2676 break;
2677 case CSS_SELECTOR_PSEUDO_ELEMENT:
2678 *match = true1;
2679
2680 if (detail->qname.name == ctx->str.first_line) {
2681 *pseudo_element = CSS_PSEUDO_ELEMENT_FIRST_LINE;
2682 } else if (detail->qname.name == ctx->str.first_letter) {
2683 *pseudo_element = CSS_PSEUDO_ELEMENT_FIRST_LETTER;
2684 } else if (detail->qname.name == ctx->str.before) {
2685 *pseudo_element = CSS_PSEUDO_ELEMENT_BEFORE;
2686 } else if (detail->qname.name == ctx->str.after) {
2687 *pseudo_element = CSS_PSEUDO_ELEMENT_AFTER;
2688 } else
2689 *match = false0;
2690 break;
2691 case CSS_SELECTOR_ATTRIBUTE:
2692 error = state->handler->node_has_attribute(state->pw, node,
2693 &detail->qname, match);
2694 add_node_flags(node, state, CSS_NODE_FLAGS_TAINT_ATTRIBUTE);
2695 break;
2696 case CSS_SELECTOR_ATTRIBUTE_EQUAL:
2697 error = state->handler->node_has_attribute_equal(state->pw,
2698 node, &detail->qname, detail->value.string,
2699 match);
2700 add_node_flags(node, state, CSS_NODE_FLAGS_TAINT_ATTRIBUTE);
2701 break;
2702 case CSS_SELECTOR_ATTRIBUTE_DASHMATCH:
2703 error = state->handler->node_has_attribute_dashmatch(state->pw,
2704 node, &detail->qname, detail->value.string,
2705 match);
2706 add_node_flags(node, state, CSS_NODE_FLAGS_TAINT_ATTRIBUTE);
2707 break;
2708 case CSS_SELECTOR_ATTRIBUTE_INCLUDES:
2709 error = state->handler->node_has_attribute_includes(state->pw,
2710 node, &detail->qname, detail->value.string,
2711 match);
2712 add_node_flags(node, state, CSS_NODE_FLAGS_TAINT_ATTRIBUTE);
2713 break;
2714 case CSS_SELECTOR_ATTRIBUTE_PREFIX:
2715 error = state->handler->node_has_attribute_prefix(state->pw,
2716 node, &detail->qname, detail->value.string,
2717 match);
2718 add_node_flags(node, state, CSS_NODE_FLAGS_TAINT_ATTRIBUTE);
2719 break;
2720 case CSS_SELECTOR_ATTRIBUTE_SUFFIX:
2721 error = state->handler->node_has_attribute_suffix(state->pw,
2722 node, &detail->qname, detail->value.string,
2723 match);
2724 add_node_flags(node, state, CSS_NODE_FLAGS_TAINT_ATTRIBUTE);
2725 break;
2726 case CSS_SELECTOR_ATTRIBUTE_SUBSTRING:
2727 error = state->handler->node_has_attribute_substring(state->pw,
2728 node, &detail->qname, detail->value.string,
2729 match);
2730 add_node_flags(node, state, CSS_NODE_FLAGS_TAINT_ATTRIBUTE);
2731 break;
2732 }
2733
2734 /* Invert match, if the detail requests it */
2735 if (error == CSS_OK && detail->negate != 0)
2736 *match = !*match;
2737
2738 return error;
2739}
2740
2741css_error cascade_style(const css_style *style, css_select_state *state)
2742{
2743 css_style s = *style;
2744
2745 while (s.used > 0) {
2746 opcode_t op;
2747 css_error error;
2748 css_code_t opv = *s.bytecode;
2749
2750 advance_bytecode(&s, sizeof(opv));
2751
2752 op = getOpcode(opv);
2753
2754 error = prop_dispatch[op].cascade(opv, &s, state);
2755 if (error != CSS_OK)
2756 return error;
2757 }
2758
2759 return CSS_OK;
2760}
2761
2762bool_Bool css__outranks_existing(uint16_t op, bool_Bool important, css_select_state *state,
2763 enum flag_value explicit_default)
2764{
2765 prop_state *existing = &state->props[op][state->current_pseudo];
2766 bool_Bool outranks = false0;
2767
2768 /* Sorting on origin & importance gives the following:
2769 *
2770 * | UA, - | UA, i | USER, - | USER, i | AUTHOR, - | AUTHOR, i
2771 * |----------------------------------------------------------
2772 * UA , - | S S Y Y Y Y
2773 * UA , i | S S Y Y Y Y
2774 * USER , - | - - S Y Y Y
2775 * USER , i | - - - S - -
2776 * AUTHOR, - | - - - Y S Y
2777 * AUTHOR, i | - - - Y - S
2778 *
2779 * Where the columns represent the origin/importance of the property
2780 * being considered and the rows represent the origin/importance of
2781 * the existing property.
2782 *
2783 * - means that the existing property must be preserved
2784 * Y means that the new property must be applied
2785 * S means that the specificities of the rules must be considered.
2786 *
2787 * If specificities are considered, the highest specificity wins.
2788 * If specificities are equal, then the rule defined last wins.
2789 *
2790 * We have no need to explicitly consider the ordering of rules if
2791 * the specificities are the same because:
2792 *
2793 * a) We process stylesheets in order
2794 * b) The selector hash chains within a sheet are ordered such that
2795 * more specific rules come after less specific ones and, when
2796 * specificities are identical, rules defined later occur after
2797 * those defined earlier.
2798 *
2799 * Therefore, where we consider specificity, below, the property
2800 * currently being considered will always be applied if its specificity
2801 * is greater than or equal to that of the existing property.
2802 */
2803
2804 if (existing->set == 0) {
2805 /* Property hasn't been set before, new one wins */
2806 outranks = true1;
2807 } else {
2808 assert(CSS_ORIGIN_UA < CSS_ORIGIN_USER)((CSS_ORIGIN_UA < CSS_ORIGIN_USER) ? (void) (0) : __assert_fail
("CSS_ORIGIN_UA < CSS_ORIGIN_USER", "src/select/select.c"
, 2808, __extension__ __PRETTY_FUNCTION__))
;
2809 assert(CSS_ORIGIN_USER < CSS_ORIGIN_AUTHOR)((CSS_ORIGIN_USER < CSS_ORIGIN_AUTHOR) ? (void) (0) : __assert_fail
("CSS_ORIGIN_USER < CSS_ORIGIN_AUTHOR", "src/select/select.c"
, 2809, __extension__ __PRETTY_FUNCTION__))
;
2810
2811 if (existing->origin < state->current_origin) {
2812 /* New origin has more weight than existing one.
2813 * Thus, new property wins, except when the existing
2814 * one is USER, i. */
2815 if (existing->important == 0 ||
2816 existing->origin != CSS_ORIGIN_USER) {
2817 outranks = true1;
2818 }
2819 } else if (existing->origin == state->current_origin) {
2820 /* Origins are identical, consider importance, except
2821 * for UA stylesheets, when specificity is always
2822 * considered (as importance is meaningless) */
2823 if (existing->origin == CSS_ORIGIN_UA) {
2824 if (state->current_specificity >=
2825 existing->specificity) {
2826 outranks = true1;
2827 }
2828 } else if (existing->important == 0 && important) {
2829 /* New is more important than old. */
2830 outranks = true1;
2831 } else if (existing->important && important == false0) {
2832 /* Old is more important than new */
2833 } else {
2834 /* Same importance, consider specificity */
2835 if (state->current_specificity >=
2836 existing->specificity) {
2837 outranks = true1;
2838 }
2839 }
2840 } else {
2841 /* Existing origin has more weight than new one.
2842 * Thus, existing property wins, except when the new
2843 * one is USER, i. */
2844 if (state->current_origin == CSS_ORIGIN_USER &&
2845 important) {
2846 outranks = true1;
2847 }
2848 }
2849 }
2850
2851 if (outranks) {
2852 /* The new property is about to replace the old one.
2853 * Update our state to reflect this. */
2854 existing->set = 1;
2855 existing->specificity = state->current_specificity;
2856 existing->origin = state->current_origin;
2857 existing->important = important;
2858 existing->explicit_default = explicit_default;
2859 }
2860
2861 return outranks;
2862}
2863
2864/******************************************************************************
2865 * Debug helpers *
2866 ******************************************************************************/
2867#ifdef DEBUG_CHAIN_MATCHING
2868void dump_chain(const css_selector *selector)
2869{
2870 const css_selector_detail *detail = &selector->data;
2871
2872 if (selector->data.comb != CSS_COMBINATOR_NONE)
2873 dump_chain(selector->combinator);
2874
2875 if (selector->data.comb == CSS_COMBINATOR_ANCESTOR)
2876 fprintf(stderrstderr, " ");
2877 else if (selector->data.comb == CSS_COMBINATOR_SIBLING)
2878 fprintf(stderrstderr, " + ");
2879 else if (selector->data.comb == CSS_COMBINATOR_PARENT)
2880 fprintf(stderrstderr, " > ");
2881
2882 do {
2883 switch (detail->type) {
2884 case CSS_SELECTOR_ELEMENT:
2885 if (lwc_string_length(detail->name)({((detail->name != ((void*)0)) ? (void) (0) : __assert_fail
("detail->name != NULL", "src/select/select.c", 2885, __extension__
__PRETTY_FUNCTION__)); (detail->name)->len;})
== 1 &&
2886 lwc_string_data(detail->name)({((detail->name != ((void*)0)) ? (void) (0) : __assert_fail
("detail->name != NULL", "src/select/select.c", 2886, __extension__
__PRETTY_FUNCTION__)); (const char *)((detail->name)+1);}
)
[0] == '*' &&
2887 detail->next == 1) {
2888 break;
2889 }
2890 fprintf(stderrstderr, "%.*s",
2891 (int) lwc_string_length(detail->name)({((detail->name != ((void*)0)) ? (void) (0) : __assert_fail
("detail->name != NULL", "src/select/select.c", 2891, __extension__
__PRETTY_FUNCTION__)); (detail->name)->len;})
,
2892 lwc_string_data(detail->name)({((detail->name != ((void*)0)) ? (void) (0) : __assert_fail
("detail->name != NULL", "src/select/select.c", 2892, __extension__
__PRETTY_FUNCTION__)); (const char *)((detail->name)+1);}
)
);
2893 break;
2894 case CSS_SELECTOR_CLASS:
2895 fprintf(stderrstderr, ".%.*s",
2896 (int) lwc_string_length(detail->name)({((detail->name != ((void*)0)) ? (void) (0) : __assert_fail
("detail->name != NULL", "src/select/select.c", 2896, __extension__
__PRETTY_FUNCTION__)); (detail->name)->len;})
,
2897 lwc_string_data(detail->name)({((detail->name != ((void*)0)) ? (void) (0) : __assert_fail
("detail->name != NULL", "src/select/select.c", 2897, __extension__
__PRETTY_FUNCTION__)); (const char *)((detail->name)+1);}
)
);
2898 break;
2899 case CSS_SELECTOR_ID:
2900 fprintf(stderrstderr, "#%.*s",
2901 (int) lwc_string_length(detail->name)({((detail->name != ((void*)0)) ? (void) (0) : __assert_fail
("detail->name != NULL", "src/select/select.c", 2901, __extension__
__PRETTY_FUNCTION__)); (detail->name)->len;})
,
2902 lwc_string_data(detail->name)({((detail->name != ((void*)0)) ? (void) (0) : __assert_fail
("detail->name != NULL", "src/select/select.c", 2902, __extension__
__PRETTY_FUNCTION__)); (const char *)((detail->name)+1);}
)
);
2903 break;
2904 case CSS_SELECTOR_PSEUDO_CLASS:
2905 case CSS_SELECTOR_PSEUDO_ELEMENT:
2906 fprintf(stderrstderr, ":%.*s",
2907 (int) lwc_string_length(detail->name)({((detail->name != ((void*)0)) ? (void) (0) : __assert_fail
("detail->name != NULL", "src/select/select.c", 2907, __extension__
__PRETTY_FUNCTION__)); (detail->name)->len;})
,
2908 lwc_string_data(detail->name)({((detail->name != ((void*)0)) ? (void) (0) : __assert_fail
("detail->name != NULL", "src/select/select.c", 2908, __extension__
__PRETTY_FUNCTION__)); (const char *)((detail->name)+1);}
)
);
2909
2910 if (detail->value != NULL((void*)0)) {
2911 fprintf(stderrstderr, "(%.*s)",
2912 (int) lwc_string_length(detail->value)({((detail->value != ((void*)0)) ? (void) (0) : __assert_fail
("detail->value != NULL", "src/select/select.c", 2912, __extension__
__PRETTY_FUNCTION__)); (detail->value)->len;})
,
2913 lwc_string_data(detail->value)({((detail->value != ((void*)0)) ? (void) (0) : __assert_fail
("detail->value != NULL", "src/select/select.c", 2913, __extension__
__PRETTY_FUNCTION__)); (const char *)((detail->value)+1);
})
);
2914 }
2915 break;
2916 case CSS_SELECTOR_ATTRIBUTE:
2917 fprintf(stderrstderr, "[%.*s]",
2918 (int) lwc_string_length(detail->name)({((detail->name != ((void*)0)) ? (void) (0) : __assert_fail
("detail->name != NULL", "src/select/select.c", 2918, __extension__
__PRETTY_FUNCTION__)); (detail->name)->len;})
,
2919 lwc_string_data(detail->name)({((detail->name != ((void*)0)) ? (void) (0) : __assert_fail
("detail->name != NULL", "src/select/select.c", 2919, __extension__
__PRETTY_FUNCTION__)); (const char *)((detail->name)+1);}
)
);
2920 break;
2921 case CSS_SELECTOR_ATTRIBUTE_EQUAL:
2922 fprintf(stderrstderr, "[%.*s=\"%.*s\"]",
2923 (int) lwc_string_length(detail->name)({((detail->name != ((void*)0)) ? (void) (0) : __assert_fail
("detail->name != NULL", "src/select/select.c", 2923, __extension__
__PRETTY_FUNCTION__)); (detail->name)->len;})
,
2924 lwc_string_data(detail->name)({((detail->name != ((void*)0)) ? (void) (0) : __assert_fail
("detail->name != NULL", "src/select/select.c", 2924, __extension__
__PRETTY_FUNCTION__)); (const char *)((detail->name)+1);}
)
,
2925 (int) lwc_string_length(detail->value)({((detail->value != ((void*)0)) ? (void) (0) : __assert_fail
("detail->value != NULL", "src/select/select.c", 2925, __extension__
__PRETTY_FUNCTION__)); (detail->value)->len;})
,
2926 lwc_string_data(detail->value)({((detail->value != ((void*)0)) ? (void) (0) : __assert_fail
("detail->value != NULL", "src/select/select.c", 2926, __extension__
__PRETTY_FUNCTION__)); (const char *)((detail->value)+1);
})
);
2927 break;
2928 case CSS_SELECTOR_ATTRIBUTE_DASHMATCH:
2929 fprintf(stderrstderr, "[%.*s|=\"%.*s\"]",
2930 (int) lwc_string_length(detail->name)({((detail->name != ((void*)0)) ? (void) (0) : __assert_fail
("detail->name != NULL", "src/select/select.c", 2930, __extension__
__PRETTY_FUNCTION__)); (detail->name)->len;})
,
2931 lwc_string_data(detail->name)({((detail->name != ((void*)0)) ? (void) (0) : __assert_fail
("detail->name != NULL", "src/select/select.c", 2931, __extension__
__PRETTY_FUNCTION__)); (const char *)((detail->name)+1);}
)
,
2932 (int) lwc_string_length(detail->value)({((detail->value != ((void*)0)) ? (void) (0) : __assert_fail
("detail->value != NULL", "src/select/select.c", 2932, __extension__
__PRETTY_FUNCTION__)); (detail->value)->len;})
,
2933 lwc_string_data(detail->value)({((detail->value != ((void*)0)) ? (void) (0) : __assert_fail
("detail->value != NULL", "src/select/select.c", 2933, __extension__
__PRETTY_FUNCTION__)); (const char *)((detail->value)+1);
})
);
2934 break;
2935 case CSS_SELECTOR_ATTRIBUTE_INCLUDES:
2936 fprintf(stderrstderr, "[%.*s~=\"%.*s\"]",
2937 (int) lwc_string_length(detail->name)({((detail->name != ((void*)0)) ? (void) (0) : __assert_fail
("detail->name != NULL", "src/select/select.c", 2937, __extension__
__PRETTY_FUNCTION__)); (detail->name)->len;})
,
2938 lwc_string_data(detail->name)({((detail->name != ((void*)0)) ? (void) (0) : __assert_fail
("detail->name != NULL", "src/select/select.c", 2938, __extension__
__PRETTY_FUNCTION__)); (const char *)((detail->name)+1);}
)
,
2939 (int) lwc_string_length(detail->value)({((detail->value != ((void*)0)) ? (void) (0) : __assert_fail
("detail->value != NULL", "src/select/select.c", 2939, __extension__
__PRETTY_FUNCTION__)); (detail->value)->len;})
,
2940 lwc_string_data(detail->value)({((detail->value != ((void*)0)) ? (void) (0) : __assert_fail
("detail->value != NULL", "src/select/select.c", 2940, __extension__
__PRETTY_FUNCTION__)); (const char *)((detail->value)+1);
})
);
2941 break;
2942 case CSS_SELECTOR_ATTRIBUTE_PREFIX:
2943 fprintf(stderrstderr, "[%.*s^=\"%.*s\"]",
2944 (int) lwc_string_length(detail->name)({((detail->name != ((void*)0)) ? (void) (0) : __assert_fail
("detail->name != NULL", "src/select/select.c", 2944, __extension__
__PRETTY_FUNCTION__)); (detail->name)->len;})
,
2945 lwc_string_data(detail->name)({((detail->name != ((void*)0)) ? (void) (0) : __assert_fail
("detail->name != NULL", "src/select/select.c", 2945, __extension__
__PRETTY_FUNCTION__)); (const char *)((detail->name)+1);}
)
,
2946 (int) lwc_string_length(detail->value)({((detail->value != ((void*)0)) ? (void) (0) : __assert_fail
("detail->value != NULL", "src/select/select.c", 2946, __extension__
__PRETTY_FUNCTION__)); (detail->value)->len;})
,
2947 lwc_string_data(detail->value)({((detail->value != ((void*)0)) ? (void) (0) : __assert_fail
("detail->value != NULL", "src/select/select.c", 2947, __extension__
__PRETTY_FUNCTION__)); (const char *)((detail->value)+1);
})
);
2948 break;
2949 case CSS_SELECTOR_ATTRIBUTE_SUFFIX:
2950 fprintf(stderrstderr, "[%.*s$=\"%.*s\"]",
2951 (int) lwc_string_length(detail->name)({((detail->name != ((void*)0)) ? (void) (0) : __assert_fail
("detail->name != NULL", "src/select/select.c", 2951, __extension__
__PRETTY_FUNCTION__)); (detail->name)->len;})
,
2952 lwc_string_data(detail->name)({((detail->name != ((void*)0)) ? (void) (0) : __assert_fail
("detail->name != NULL", "src/select/select.c", 2952, __extension__
__PRETTY_FUNCTION__)); (const char *)((detail->name)+1);}
)
,
2953 (int) lwc_string_length(detail->value)({((detail->value != ((void*)0)) ? (void) (0) : __assert_fail
("detail->value != NULL", "src/select/select.c", 2953, __extension__
__PRETTY_FUNCTION__)); (detail->value)->len;})
,
2954 lwc_string_data(detail->value)({((detail->value != ((void*)0)) ? (void) (0) : __assert_fail
("detail->value != NULL", "src/select/select.c", 2954, __extension__
__PRETTY_FUNCTION__)); (const char *)((detail->value)+1);
})
);
2955 break;
2956 case CSS_SELECTOR_ATTRIBUTE_SUBSTRING:
2957 fprintf(stderrstderr, "[%.*s*=\"%.*s\"]",
2958 (int) lwc_string_length(detail->name)({((detail->name != ((void*)0)) ? (void) (0) : __assert_fail
("detail->name != NULL", "src/select/select.c", 2958, __extension__
__PRETTY_FUNCTION__)); (detail->name)->len;})
,
2959 lwc_string_data(detail->name)({((detail->name != ((void*)0)) ? (void) (0) : __assert_fail
("detail->name != NULL", "src/select/select.c", 2959, __extension__
__PRETTY_FUNCTION__)); (const char *)((detail->name)+1);}
)
,
2960 (int) lwc_string_length(detail->value)({((detail->value != ((void*)0)) ? (void) (0) : __assert_fail
("detail->value != NULL", "src/select/select.c", 2960, __extension__
__PRETTY_FUNCTION__)); (detail->value)->len;})
,
2961 lwc_string_data(detail->value)({((detail->value != ((void*)0)) ? (void) (0) : __assert_fail
("detail->value != NULL", "src/select/select.c", 2961, __extension__
__PRETTY_FUNCTION__)); (const char *)((detail->value)+1);
})
);
2962 break;
2963 }
2964
2965 if (detail->next)
2966 detail++;
2967 else
2968 detail = NULL((void*)0);
2969 } while (detail);
2970}
2971#endif
2972