Bug Summary

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