Bug Summary

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