Bug Summary

File:select/select.c
Warning:line 1187, column 6
Array access (via field 'style') results in a null pointer dereference

Annotated Source Code

Press '?' to see keyboard shortcuts

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