php-internal-docs 8.4.8
Unofficial docs for php/php-src
Loading...
Searching...
No Matches
selectors.c
Go to the documentation of this file.
1/*
2 * Copyright (C) 2021-2024 Alexander Borisov
3 *
4 * Author: Alexander Borisov <borisov@lexbor.com>
5 */
6
8
9#include <math.h>
10
11
12static lxb_status_t
13lxb_selectors_state_tree(lxb_selectors_t *selectors, lxb_dom_node_t *root,
14 const lxb_css_selector_list_t *list);
15
16static lxb_status_t
17lxb_selectors_state_run(lxb_selectors_t *selectors, lxb_dom_node_t *node,
18 const lxb_css_selector_list_t *list);
19
21lxb_selectors_state_find(lxb_selectors_t *selectors,
23
25lxb_selectors_state_find_check(lxb_selectors_t *selectors, lxb_dom_node_t *node,
26 const lxb_css_selector_t *selector,
28
30lxb_selectors_state_pseudo_class_function(lxb_selectors_t *selectors,
32
33static lxb_dom_node_t *
34lxb_selectors_next_node(lxb_selectors_nested_t *main);
35
36static lxb_dom_node_t *
37lxb_selectors_state_has_relative(lxb_dom_node_t *node,
38 const lxb_css_selector_t *selector);
39
41lxb_selectors_state_after_find_has(lxb_selectors_t *selectors,
43
45lxb_selectors_state_after_find(lxb_selectors_t *selectors,
47
49lxb_selectors_state_after_nth_child(lxb_selectors_t *selectors,
51
52static bool
53lxb_selectors_match(lxb_selectors_t *selectors, lxb_selectors_entry_t *entry,
54 const lxb_css_selector_t *selector, lxb_dom_node_t *node);
55
56static bool
57lxb_selectors_match_element(const lxb_css_selector_t *selector,
59
60static bool
61lxb_selectors_match_id(const lxb_css_selector_t *selector, lxb_dom_node_t *node);
62
63static bool
64lxb_selectors_match_class(const lexbor_str_t *target, const lexbor_str_t *src,
65 bool quirks);
66
67static bool
68lxb_selectors_match_attribute(const lxb_css_selector_t *selector,
70
71static bool
72lxb_selectors_pseudo_class(const lxb_css_selector_t *selector,
73 const lxb_dom_node_t *node);
74
75static bool
76lxb_selectors_pseudo_class_function(const lxb_css_selector_t *selector,
77 lxb_dom_node_t *node);
78
79static bool
80lxb_selectors_pseudo_element(const lxb_css_selector_t *selector,
81 const lxb_dom_node_t *node);
82
83static bool
84lxb_selectors_pseudo_class_disabled(const lxb_dom_node_t *node);
85
86static bool
87lxb_selectors_pseudo_class_first_child(const lxb_dom_node_t *node);
88
89static bool
90lxb_selectors_pseudo_class_first_of_type(const lxb_dom_node_t *node);
91
92static bool
93lxb_selectors_pseudo_class_last_child(const lxb_dom_node_t *node);
94
95static bool
96lxb_selectors_pseudo_class_last_of_type(const lxb_dom_node_t *node);
97
98static bool
99lxb_selectors_pseudo_class_read_write(const lxb_dom_node_t *node);
100
101static bool
102lxb_selectors_anb_calc(lxb_css_selector_anb_of_t *anb, size_t index);
103
104static lxb_status_t
105lxb_selectors_cb_ok(lxb_dom_node_t *node,
106 lxb_css_selector_specificity_t spec, void *ctx);
107
108static lxb_status_t
109lxb_selectors_cb_not(lxb_dom_node_t *node,
110 lxb_css_selector_specificity_t spec, void *ctx);
111
112
115{
116 return lexbor_calloc(1, sizeof(lxb_selectors_t));
117}
118
121{
123
124 if (selectors == NULL) {
126 }
127
128 selectors->objs = lexbor_dobject_create();
129 status = lexbor_dobject_init(selectors->objs,
130 128, sizeof(lxb_selectors_entry_t));
131 if (status != LXB_STATUS_OK) {
132 return status;
133 }
134
135 selectors->nested = lexbor_dobject_create();
136 status = lexbor_dobject_init(selectors->nested,
137 64, sizeof(lxb_selectors_nested_t));
138 if (status != LXB_STATUS_OK) {
139 return status;
140 }
141
143
144 return LXB_STATUS_OK;
145}
146
147void
149{
150 lexbor_dobject_clean(selectors->objs);
151 lexbor_dobject_clean(selectors->nested);
152}
153
155lxb_selectors_destroy(lxb_selectors_t *selectors, bool self_destroy)
156{
157 if (selectors == NULL) {
158 return NULL;
159 }
160
161 selectors->objs = lexbor_dobject_destroy(selectors->objs, true);
162 selectors->nested = lexbor_dobject_destroy(selectors->nested, true);
163
164 if (self_destroy) {
165 return lexbor_free(selectors);
166 }
167
168 return selectors;
169}
170
174 const lxb_css_selector_t *selector,
175 lxb_dom_node_t *node)
176{
177 node = node->parent;
178
179 while (node != NULL) {
181 && lxb_selectors_match(selectors, entry, selector, node))
182 {
183 return node;
184 }
185
186 node = node->parent;
187 }
188
189 return NULL;
190}
191
194 const lxb_css_selector_t *selector, lxb_dom_node_t *node)
195{
196 if (lxb_selectors_match(selectors, entry, selector, node)) {
197 return node;
198 }
199
200 return NULL;
201}
202
205 const lxb_css_selector_t *selector, lxb_dom_node_t *root)
206{
207 root = root->parent;
208
209 if (root != NULL && root->type == LXB_DOM_NODE_TYPE_ELEMENT
210 && lxb_selectors_match(selectors, entry, selector, root))
211 {
212 return root;
213 }
214
215 return NULL;
216}
217
220 const lxb_css_selector_t *selector, lxb_dom_node_t *node)
221{
222 node = node->prev;
223
224 while (node != NULL) {
225 if (node->type == LXB_DOM_NODE_TYPE_ELEMENT) {
226 if (lxb_selectors_match(selectors, entry, selector, node)) {
227 return node;
228 }
229
230 return NULL;
231 }
232
233 node = node->prev;
234 }
235
236 return NULL;
237}
238
241 const lxb_css_selector_t *selector, lxb_dom_node_t *node)
242{
243 node = node->prev;
244
245 while (node != NULL) {
246 if (node->type == LXB_DOM_NODE_TYPE_ELEMENT &&
247 lxb_selectors_match(selectors, entry, selector, node))
248 {
249 return node;
250 }
251
252 node = node->prev;
253 }
254
255 return NULL;
256}
257
260 const lxb_css_selector_list_t *list,
261 lxb_selectors_cb_f cb, void *ctx)
262{
265
266 entry = lexbor_dobject_calloc(selectors->objs);
267 if (entry == NULL) {
269 }
270
272 entry->selector = list->last;
273
274 nested.parent = NULL;
275 nested.entry = entry;
276 nested.cb = cb;
277 nested.ctx = ctx;
278
279 selectors->current = &nested;
280 selectors->status = LXB_STATUS_OK;
281
282 return lxb_selectors_state_tree(selectors, root, list);
283}
284
287 const lxb_css_selector_list_t *list,
288 lxb_selectors_cb_f cb, void *ctx)
289{
293
294 if (node->type != LXB_DOM_NODE_TYPE_ELEMENT) {
295 return LXB_STATUS_OK;
296 }
297
298 entry = lexbor_dobject_calloc(selectors->objs);
299 if (entry == NULL) {
301 }
302
304 entry->selector = list->last;
305
306 nested.parent = NULL;
307 nested.entry = entry;
308 nested.cb = cb;
309 nested.ctx = ctx;
310
311 selectors->current = &nested;
312 selectors->status = LXB_STATUS_OK;
313
314 status = lxb_selectors_state_run(selectors, node, list);
315
316 lxb_selectors_clean(selectors);
317
318 return status;
319}
320
324 lxb_selectors_cb_f cb, void *ctx)
325{
326 return lxb_selectors_find(selectors, root, list, cb, ctx);
327}
328
329static lxb_status_t
330lxb_selectors_state_tree(lxb_selectors_t *selectors, lxb_dom_node_t *root,
331 const lxb_css_selector_list_t *list)
332{
334 lxb_dom_node_t *node;
335
336 if (selectors->options & LXB_SELECTORS_OPT_MATCH_ROOT) {
337 node = root;
338
339 if (node->type == LXB_DOM_NODE_TYPE_DOCUMENT) {
340 node = root->first_child;
341 }
342 }
343 else {
344 node = root->first_child;
345 }
346
347 if (node == NULL) {
348 goto out;
349 }
350
351 do {
352 if (node->type != LXB_DOM_NODE_TYPE_ELEMENT) {
353 goto next;
354 }
355
356 status = lxb_selectors_state_run(selectors, node, list);
357 if (status != LXB_STATUS_OK) {
358 if (status == LXB_STATUS_STOP) {
359 break;
360 }
361
362 lxb_selectors_clean(selectors);
363
364 return status;
365 }
366
367 if (node->first_child != NULL) {
368 node = node->first_child;
369 }
370 else {
371
372 next:
373
374 while (node != root && node->next == NULL) {
375 node = node->parent;
376 }
377
378 if (node == root) {
379 break;
380 }
381
382 node = node->next;
383 }
384 }
385 while (true);
386
387out:
388 lxb_selectors_clean(selectors);
389
390 return LXB_STATUS_OK;
391}
392
393static lxb_status_t
394lxb_selectors_state_run(lxb_selectors_t *selectors, lxb_dom_node_t *node,
395 const lxb_css_selector_list_t *list)
396{
398
399 entry = selectors->current->entry;
400
401 entry->node = node;
402 selectors->state = lxb_selectors_state_find;
403 selectors->first = entry;
404
405again:
406
407 do {
408 entry = selectors->state(selectors, entry);
409 }
410 while (entry != NULL);
411
412 if (selectors->current->parent != NULL
413 && selectors->status == LXB_STATUS_OK)
414 {
415 entry = selectors->current->entry;
416 selectors->state = selectors->current->return_state;
417
418 goto again;
419 }
420
421 return selectors->status;
422}
423
425lxb_selectors_state_find(lxb_selectors_t *selectors,
427{
428 lxb_dom_node_t *node;
430 const lxb_css_selector_t *selector;
431 const lxb_css_selector_anb_of_t *anb;
432 const lxb_css_selector_pseudo_t *pseudo;
433
434 selector = entry->selector;
435
437 pseudo = &selector->u.pseudo;
438
439 /* Optimizing. */
440
441 switch (pseudo->type) {
444 anb = pseudo->data;
445
446 if (anb->of != NULL) {
447 break;
448 }
449
450 goto godoit;
451
454 goto godoit;
455
456 default:
457 break;
458 }
459
460 if (entry->nested == NULL) {
461 next = lexbor_dobject_calloc(selectors->objs);
462 if (next == NULL) {
464 return NULL;
465 }
466
468
469 entry->nested = lexbor_dobject_calloc(selectors->nested);
470 if (entry->nested == NULL) {
472 return NULL;
473 }
474
475 entry->nested->entry = next;
476 entry->nested->parent = selectors->current;
477 }
478
479 selectors->state = lxb_selectors_state_pseudo_class_function;
480 selectors->current->last = entry;
481 selectors->current = entry->nested;
482
483 next = entry->nested->entry;
484 next->node = entry->node;
485
486 return next;
487 }
488
489godoit:
490
491 switch (entry->combinator) {
493 node = lxb_selectors_descendant(selectors, entry,
494 selector, entry->node);
495 break;
496
498 node = lxb_selectors_close(selectors, entry,
499 selector, entry->node);
500 break;
501
503 node = lxb_selectors_child(selectors, entry,
504 selector, entry->node);
505 break;
506
508 node = lxb_selectors_sibling(selectors, entry,
509 selector, entry->node);
510 break;
511
513 node = lxb_selectors_following(selectors, entry,
514 selector, entry->node);
515 break;
516
518 default:
519 selectors->status = LXB_STATUS_ERROR;
520 return NULL;
521 }
522
523 return lxb_selectors_state_find_check(selectors, node, selector, entry);
524}
525
527lxb_selectors_state_find_check(lxb_selectors_t *selectors, lxb_dom_node_t *node,
528 const lxb_css_selector_t *selector,
530{
533
534 if (node == NULL) {
535
536 try_next:
537
538 if (entry->next == NULL) {
539
540 try_next_list:
541
542 if (selector->list->next == NULL) {
543 return NULL;
544 }
545
546 /*
547 * Try the following selectors from the selector list.
548 */
549
550 if (entry->following != NULL) {
551 entry->following->node = entry->node;
552
553 if (selectors->current->parent == NULL) {
554 selectors->first = entry->following;
555 }
556
557 return entry->following;
558 }
559
560 next = lexbor_dobject_calloc(selectors->objs);
561 if (next == NULL) {
563 return NULL;
564 }
565
567 next->selector = selector->list->next->last;
568 next->node = entry->node;
569
570 entry->following = next;
571
572 if (selectors->current->parent == NULL) {
573 selectors->first = next;
574 }
575
576 return next;
577 }
578
579 do {
580 entry = entry->next;
581
583 if (entry->next == NULL) {
584 selector = entry->selector;
585 goto try_next;
586 }
587
588 entry = entry->next;
589 }
590
591 switch (entry->combinator) {
593 node = entry->node->parent;
594
595 if (node == NULL
597 {
598 node = NULL;
599 }
600
601 break;
602
604 node = entry->node->prev;
605 break;
606
610 node = NULL;
611 break;
612
614 default:
615 selectors->status = LXB_STATUS_ERROR;
616 return NULL;
617 }
618 }
619 while (node == NULL);
620
621 entry->node = node;
622
623 return entry;
624 }
625
626 if (selector->prev == NULL) {
627 current = selectors->current;
628
629 selectors->status = current->cb(current->entry->node,
630 selector->list->specificity,
631 current->ctx);
632
633 if ((selectors->options & LXB_SELECTORS_OPT_MATCH_FIRST) == 0
634 && current->parent == NULL)
635 {
636 if (selectors->status == LXB_STATUS_OK) {
637 entry = selectors->first;
638 goto try_next_list;
639 }
640 }
641
642 return NULL;
643 }
644
645 if (entry->prev == NULL) {
646 next = lexbor_dobject_calloc(selectors->objs);
647 if (next == NULL) {
649 return NULL;
650 }
651
652 next->combinator = selector->combinator;
653 next->selector = selector->prev;
654 next->node = node;
655
656 next->next = entry;
657 entry->prev = next;
658
659 return next;
660 }
661
662 entry->prev->node = node;
663
664 return entry->prev;
665}
666
668lxb_selectors_state_pseudo_class_function(lxb_selectors_t *selectors,
670{
671 lxb_dom_node_t *node, *base;
673 const lxb_css_selector_list_t *list;
675 const lxb_css_selector_pseudo_t *pseudo;
676
677 current = selectors->current;
678
679 base = lxb_selectors_next_node(current);
680 if (base == NULL) {
681 goto not_found;
682 }
683
684 pseudo = &current->parent->last->selector->u.pseudo;
685
686 switch (pseudo->type) {
688 list = (lxb_css_selector_list_t *) pseudo->data;
689 node = lxb_selectors_state_has_relative(base, list->first);
690
691 if (node == NULL) {
692 selectors->current = selectors->current->parent;
693 entry = selectors->current->last;
694
695 selectors->state = lxb_selectors_state_find;
696
697 return lxb_selectors_state_find_check(selectors, NULL,
698 entry->selector, entry);
699 }
700
701 current->root = base;
702
703 current->entry->selector = list->last;
704 current->entry->node = node;
705 current->return_state = lxb_selectors_state_after_find_has;
706 current->cb = lxb_selectors_cb_ok;
707 current->ctx = &current->found;
708 current->found = false;
709
710 selectors->state = lxb_selectors_state_find;
711
712 return entry;
713
717 current->entry->selector = ((lxb_css_selector_list_t *) pseudo->data)->last;
718 current->entry->node = base;
719 current->return_state = lxb_selectors_state_after_find;
720 current->cb = lxb_selectors_cb_ok;
721 current->ctx = &current->found;
722 current->found = false;
723
724 selectors->state = lxb_selectors_state_find;
725
726 return entry;
727
729 current->entry->selector = ((lxb_css_selector_list_t *) pseudo->data)->last;
730 current->entry->node = base;
731 current->return_state = lxb_selectors_state_after_find;
732 current->cb = lxb_selectors_cb_not;
733 current->ctx = &current->found;
734 current->found = true;
735
736 selectors->state = lxb_selectors_state_find;
737
738 return entry;
739
742 anb = pseudo->data;
743
744 current->entry->selector = anb->of->last;
745 current->entry->node = base;
746 current->return_state = lxb_selectors_state_after_nth_child;
747 current->cb = lxb_selectors_cb_ok;
748 current->ctx = &current->found;
749 current->root = base;
750 current->index = 0;
751 current->found = false;
752
753 selectors->state = lxb_selectors_state_find;
754
755 return entry;
756
757 /*
758 * This one can only happen if the user has somehow messed up the
759 * selector.
760 */
761
768 default:
769 break;
770 }
771
772not_found:
773
774 selectors->current = selectors->current->parent;
775 entry = selectors->current->last;
776
777 selectors->state = lxb_selectors_state_find;
778
779 return lxb_selectors_state_find_check(selectors, NULL,
780 entry->selector, entry);
781}
782
783static lxb_dom_node_t *
784lxb_selectors_next_node(lxb_selectors_nested_t *main)
785{
786 lxb_dom_node_t *node = main->entry->node;
787
788 switch (main->parent->last->combinator) {
791 if (node->parent == NULL
793 {
794 return NULL;
795 }
796
797 return node->parent;
798
800 return node;
801
804 node = node->prev;
805 break;
806
807 default:
808 return NULL;
809 }
810
811 while (node != NULL) {
812 if (node->type == LXB_DOM_NODE_TYPE_ELEMENT) {
813 break;
814 }
815
816 node = node->prev;
817 }
818
819 return node;
820}
821
822static lxb_dom_node_t *
823lxb_selectors_state_has_relative(lxb_dom_node_t *node,
824 const lxb_css_selector_t *selector)
825{
826 lxb_dom_node_t *root = node;
827
828 switch (selector->combinator) {
831 node = node->first_child;
832 break;
833
836 node = node->next;
837 break;
838
839 default:
840 return NULL;
841 }
842
843 while (node != NULL) {
844 if (node->type == LXB_DOM_NODE_TYPE_ELEMENT) {
845 break;
846 }
847
848 while (node !=root && node->next == NULL) {
849 node = node->parent;
850 }
851
852 if (node == root) {
853 return NULL;
854 }
855
856 node = node->next;
857 }
858
859 return node;
860}
861
863lxb_selectors_state_after_find_has(lxb_selectors_t *selectors,
865{
866 lxb_dom_node_t *node;
867 lxb_selectors_entry_t *parent;
869
870 if (selectors->current->found) {
871 node = selectors->current->root;
872
873 selectors->current = selectors->current->parent;
874 parent = selectors->current->last;
875
876 selectors->state = lxb_selectors_state_find;
877
878 return lxb_selectors_state_find_check(selectors, node,
879 parent->selector, parent);
880 }
881
882 current = selectors->current;
883 node = entry->node;
884
885 switch (entry->selector->list->first->combinator) {
887 if (node->first_child != NULL) {
888 node = node->first_child;
889 }
890 else {
891
892 next:
893
894 while (node != current->root && node->next == NULL) {
895 node = node->parent;
896 }
897
898 if (node == current->root) {
899 goto failed;
900 }
901
902 node = node->next;
903 }
904
905 if (node->type != LXB_DOM_NODE_TYPE_ELEMENT) {
906 goto next;
907 }
908
909 break;
910
913 node = node->next;
914
915 while (node != NULL && node->type != LXB_DOM_NODE_TYPE_ELEMENT) {
916 node = node->next;
917 }
918
919 if (node == NULL) {
920 goto failed;
921 }
922
923 break;
924
926 goto failed;
927
930 default:
931 selectors->status = LXB_STATUS_ERROR;
932 return NULL;
933 }
934
935 entry->node = node;
936 selectors->state = lxb_selectors_state_find;
937
938 return entry;
939
940failed:
941
942 selectors->current = selectors->current->parent;
943 parent = selectors->current->last;
944
945 selectors->state = lxb_selectors_state_find;
946
947 return lxb_selectors_state_find_check(selectors, NULL,
948 parent->selector, parent);
949}
950
951
953lxb_selectors_state_after_find(lxb_selectors_t *selectors,
955{
956 lxb_dom_node_t *node;
957 lxb_selectors_entry_t *parent;
959
960 current = selectors->current;
961
962 if (current->found) {
963 node = entry->node;
964
965 selectors->current = current->parent;
966 parent = selectors->current->last;
967
968 selectors->state = lxb_selectors_state_find;
969
970 return lxb_selectors_state_find_check(selectors, node,
971 parent->selector, parent);
972 }
973
974 node = entry->node;
975
976 switch (current->parent->last->combinator) {
978 if (node->parent != NULL
980 {
981 node = node->parent;
982 }
983 else {
984 node = NULL;
985 }
986
987 break;
988
990 node = node->prev;
991
992 while (node != NULL && node->type != LXB_DOM_NODE_TYPE_ELEMENT) {
993 node = node->prev;
994 }
995
996 break;
997
1001 node = NULL;
1002 break;
1003
1005 default:
1006 selectors->status = LXB_STATUS_ERROR;
1007 return NULL;
1008 }
1009
1010 if (node == NULL) {
1011 selectors->current = current->parent;
1012 parent = selectors->current->last;
1013
1014 selectors->state = lxb_selectors_state_find;
1015
1016 return lxb_selectors_state_find_check(selectors, node,
1017 parent->selector, parent);
1018 }
1019
1020 entry->node = node;
1021 selectors->state = lxb_selectors_state_find;
1022
1023 return entry;
1024}
1025
1026static lxb_selectors_entry_t *
1027lxb_selectors_state_after_nth_child(lxb_selectors_t *selectors,
1028 lxb_selectors_entry_t *entry)
1029{
1030 bool found;
1031 lxb_dom_node_t *node;
1032 lxb_selectors_entry_t *parent;
1034 const lxb_css_selector_t *selector;
1035 const lxb_css_selector_pseudo_t *pseudo;
1036
1037 current = selectors->current;
1038 selector = current->parent->last->selector;
1039 pseudo = &selector->u.pseudo;
1040
1041 node = entry->node;
1042
1043 if (current->found) {
1044 current->index += 1;
1045 }
1046 else if (current->root == node) {
1047 node = NULL;
1048 goto done;
1049 }
1050
1052 node = node->prev;
1053
1054 while (node != NULL) {
1055 if (node->type == LXB_DOM_NODE_TYPE_ELEMENT) {
1056 break;
1057 }
1058
1059 node = node->prev;
1060 }
1061 }
1062 else {
1063 node = node->next;
1064
1065 while (node != NULL) {
1066 if (node->type == LXB_DOM_NODE_TYPE_ELEMENT) {
1067 break;
1068 }
1069
1070 node = node->next;
1071 }
1072 }
1073
1074 if (node == NULL) {
1075 goto done;
1076 }
1077
1078 entry->node = node;
1079 current->found = false;
1080 selectors->state = lxb_selectors_state_find;
1081
1082 return entry;
1083
1084done:
1085
1086 if (current->index > 0) {
1087 found = lxb_selectors_anb_calc(pseudo->data, current->index);
1088
1089 node = (found) ? current->root : NULL;
1090 }
1091
1092 selectors->state = lxb_selectors_state_find;
1093 selectors->current = selectors->current->parent;
1094
1095 parent = selectors->current->last;
1096
1097 return lxb_selectors_state_find_check(selectors, node,
1098 parent->selector, parent);
1099}
1100
1101static bool
1102lxb_selectors_match(lxb_selectors_t *selectors, lxb_selectors_entry_t *entry,
1103 const lxb_css_selector_t *selector, lxb_dom_node_t *node)
1104{
1105 lxb_dom_element_t *element;
1106
1107 switch (selector->type) {
1109 return true;
1110
1112 return lxb_selectors_match_element(selector, node, entry);
1113
1115 return lxb_selectors_match_id(selector, node);
1116
1118 element = lxb_dom_interface_element(node);
1119
1120 if (element->attr_class == NULL
1121 || element->attr_class->value == NULL)
1122 {
1123 return false;
1124 }
1125
1126 return lxb_selectors_match_class(element->attr_class->value,
1127 &selector->name, true);
1128
1130 return lxb_selectors_match_attribute(selector, node, entry);
1131
1133 return lxb_selectors_pseudo_class(selector, node);
1134
1136 return lxb_selectors_pseudo_class_function(selector, node);
1137
1139 return lxb_selectors_pseudo_element(selector, node);
1140
1142 return false;
1143
1144 default:
1145 break;
1146 }
1147
1148 return false;
1149}
1150
1151static bool
1152lxb_selectors_match_element(const lxb_css_selector_t *selector,
1154{
1155 lxb_tag_id_t tag_id;
1156
1157 if (entry->id == 0) {
1158 tag_id = lxb_tag_id_by_name(node->owner_document->tags,
1159 selector->name.data, selector->name.length);
1160 if (tag_id == LXB_TAG__UNDEF) {
1161 return false;
1162 }
1163
1164 entry->id = tag_id;
1165 }
1166
1167 return node->local_name == entry->id;
1168}
1169
1170static bool
1171lxb_selectors_match_id(const lxb_css_selector_t *selector, lxb_dom_node_t *node)
1172{
1173 const lexbor_str_t *trg, *src;
1174 lxb_dom_element_t *element;
1175
1176 element = lxb_dom_interface_element(node);
1177
1178 if (element->attr_id == NULL || element->attr_id->value == NULL) {
1179 return false;
1180 }
1181
1182 trg = element->attr_id->value;
1183 src = &selector->name;
1184
1185 return trg->length == src->length
1186 && lexbor_str_data_ncasecmp(trg->data, src->data, src->length);
1187}
1188
1189static bool
1190lxb_selectors_match_class(const lexbor_str_t *target, const lexbor_str_t *src,
1191 bool quirks)
1192{
1194
1195 if (target->length < src->length) {
1196 return false;
1197 }
1198
1199 bool is_it = false;
1200
1201 const lxb_char_t *data = target->data;
1202 const lxb_char_t *pos = data;
1203 const lxb_char_t *end = data + target->length;
1204
1205 for (; data < end; data++) {
1206 chr = *data;
1207
1208 if (lexbor_utils_whitespace(chr, ==, ||)) {
1209
1210 if ((size_t) (data - pos) == src->length) {
1211 if (quirks) {
1212 is_it = lexbor_str_data_ncasecmp(pos, src->data, src->length);
1213 }
1214 else {
1215 is_it = lexbor_str_data_ncmp(pos, src->data, src->length);
1216 }
1217
1218 if (is_it) {
1219 return true;
1220 }
1221 }
1222
1223 if ((size_t) (end - data) < src->length) {
1224 return false;
1225 }
1226
1227 pos = data + 1;
1228 }
1229 }
1230
1231 if ((size_t) (end - pos) == src->length && src->length != 0) {
1232 if (quirks) {
1233 is_it = lexbor_str_data_ncasecmp(pos, src->data, src->length);
1234 }
1235 else {
1236 is_it = lexbor_str_data_ncmp(pos, src->data, src->length);
1237 }
1238 }
1239
1240 return is_it;
1241}
1242
1243static bool
1244lxb_selectors_match_attribute(const lxb_css_selector_t *selector,
1246{
1247 bool res, ins;
1248 lxb_dom_attr_t *dom_attr;
1249 lxb_dom_element_t *element;
1250 const lexbor_str_t *trg, *src;
1251 const lxb_dom_attr_data_t *attr_data;
1253
1254 static const lexbor_str_t lxb_blank_str = {
1255 .data = (lxb_char_t *) "",
1256 .length = 0
1257 };
1258
1259 element = lxb_dom_interface_element(node);
1260 attr = &selector->u.attribute;
1261
1262 if (entry->id == 0) {
1264 selector->name.data, selector->name.length);
1265 if (attr_data == NULL) {
1266 return false;
1267 }
1268
1269 entry->id = attr_data->attr_id;
1270 }
1271
1272 dom_attr = lxb_dom_element_attr_by_id(element, entry->id);
1273 if (dom_attr == NULL) {
1274 return false;
1275 }
1276
1277 trg = dom_attr->value;
1278 src = &attr->value;
1279
1280 if (src->data == NULL) {
1281 return true;
1282 }
1283
1284 if (trg == NULL) {
1285 trg = &lxb_blank_str;
1286 }
1287
1288 ins = attr->modifier == LXB_CSS_SELECTOR_MODIFIER_I;
1289
1290 switch (attr->match) {
1291 case LXB_CSS_SELECTOR_MATCH_EQUAL: /* = */
1292 if (trg->length == src->length) {
1293 if (ins) {
1294 return lexbor_str_data_ncasecmp(trg->data, src->data,
1295 src->length);
1296 }
1297
1298 return lexbor_str_data_ncmp(trg->data, src->data,
1299 src->length);
1300 }
1301
1302 return false;
1303
1304 case LXB_CSS_SELECTOR_MATCH_INCLUDE: /* ~= */
1305 return lxb_selectors_match_class(trg, src, ins);
1306
1307 case LXB_CSS_SELECTOR_MATCH_DASH: /* |= */
1308 if (trg->length == src->length) {
1309 if (ins) {
1310 return lexbor_str_data_ncasecmp(trg->data, src->data,
1311 src->length);
1312 }
1313
1314 return lexbor_str_data_ncmp(trg->data, src->data,
1315 src->length);
1316 }
1317
1318 if (trg->length > src->length) {
1319 if (ins) {
1321 src->data, src->length);
1322 }
1323 else {
1325 src->data, src->length);
1326 }
1327
1328 if (res && trg->data[src->length] == '-') {
1329 return true;
1330 }
1331 }
1332
1333 return false;
1334
1335 case LXB_CSS_SELECTOR_MATCH_PREFIX: /* ^= */
1336 if (src->length != 0 && trg->length >= src->length) {
1337 if (ins) {
1338 return lexbor_str_data_ncasecmp(trg->data, src->data,
1339 src->length);
1340 }
1341
1342 return lexbor_str_data_ncmp(trg->data, src->data,
1343 src->length);
1344 }
1345
1346 return false;
1347
1348 case LXB_CSS_SELECTOR_MATCH_SUFFIX: /* $= */
1349 if (src->length != 0 && trg->length >= src->length) {
1350 size_t dif = trg->length - src->length;
1351
1352 if (ins) {
1353 return lexbor_str_data_ncasecmp(trg->data + dif,
1354 src->data, src->length);
1355 }
1356
1357 return lexbor_str_data_ncmp(trg->data + dif, src->data,
1358 src->length);
1359 }
1360
1361 return false;
1362
1364 if (src->length == 0) {
1365 return false;
1366 }
1367
1368 if (ins) {
1370 src->data, src->length);
1371 }
1372
1373 return lexbor_str_data_ncmp_contain(trg->data, trg->length,
1374 src->data, src->length);
1375 default:
1376 break;
1377 }
1378
1379 return false;
1380}
1381
1382static bool
1383lxb_selectors_pseudo_class(const lxb_css_selector_t *selector,
1384 const lxb_dom_node_t *node)
1385{
1386 lexbor_str_t *str;
1388 const lxb_dom_node_t *root;
1389 const lxb_css_selector_pseudo_t *pseudo = &selector->u.pseudo;
1390
1391 static const lxb_char_t checkbox[] = "checkbox";
1392 static const size_t checkbox_length = sizeof(checkbox) / sizeof(lxb_char_t) - 1;
1393
1394 static const lxb_char_t radio[] = "radio";
1395 static const size_t radio_length = sizeof(radio) / sizeof(lxb_char_t) - 1;
1396
1397 switch (pseudo->type) {
1401 return attr != NULL;
1402
1404 if(node->local_name == LXB_TAG_A ||
1405 node->local_name == LXB_TAG_AREA ||
1406 node->local_name == LXB_TAG_MAP)
1407 {
1410 return attr != NULL;
1411 }
1412
1413 return false;
1414
1416 return lxb_dom_node_is_empty(node);
1417
1419 if (node->local_name == LXB_TAG_INPUT) {
1422 if (attr == NULL) {
1423 return false;
1424 }
1425
1426 if (attr->value == NULL) {
1427 return false;
1428 }
1429
1430 str = attr->value;
1431
1432 if(str->length == 8) {
1433 if (lexbor_str_data_ncasecmp(checkbox, str->data, checkbox_length)) {
1434 goto check;
1435 }
1436 }
1437 else if(str->length == 5) {
1438 if (lexbor_str_data_ncasecmp(radio, str->data, radio_length)) {
1439 goto check;
1440 }
1441 }
1442 }
1443 else if(node->local_name == LXB_TAG_OPTION) {
1446 if (attr != NULL) {
1447 return true;
1448 }
1449 }
1450 else if(node->local_name >= LXB_TAG__LAST_ENTRY) {
1451 goto check;
1452 }
1453
1454 return false;
1455
1456 check:
1457
1460 if (attr != NULL) {
1461 return true;
1462 }
1463
1464 return false;
1465
1468 return false;
1469
1471 return lxb_selectors_pseudo_class_disabled(node);
1472
1474 root = node;
1475 node = node->first_child;
1476
1477 while (node != NULL) {
1478 if (node->local_name != LXB_TAG__EM_COMMENT) {
1479 return false;
1480 }
1481
1482 if (node->first_child != NULL) {
1483 node = node->first_child;
1484 }
1485 else {
1486 while (node != root && node->next == NULL) {
1487 node = node->parent;
1488 }
1489
1490 if (node == root) {
1491 break;
1492 }
1493
1494 node = node->next;
1495 }
1496 }
1497
1498 return true;
1499
1501 return !lxb_selectors_pseudo_class_disabled(node);
1502
1504 return lxb_selectors_pseudo_class_first_child(node);
1505
1507 return lxb_selectors_pseudo_class_first_of_type(node);
1508
1512 return attr != NULL;
1513
1515 break;
1516
1518 break;
1519
1521 break;
1522
1524 break;
1525
1529 return attr != NULL;
1530
1532 break;
1533
1535 break;
1536
1538 break;
1539
1541 return lxb_selectors_pseudo_class_last_child(node);
1542
1544 return lxb_selectors_pseudo_class_last_of_type(node);
1545
1547 if (node->local_name == LXB_TAG_A
1548 || node->local_name == LXB_TAG_AREA
1549 || node->local_name == LXB_TAG_LINK)
1550 {
1553 return attr != NULL;
1554 }
1555
1556 return false;
1557
1559 break;
1560
1562 return lxb_selectors_pseudo_class_first_child(node)
1563 && lxb_selectors_pseudo_class_last_child(node);
1564
1566 return lxb_selectors_pseudo_class_first_of_type(node)
1567 && lxb_selectors_pseudo_class_last_of_type(node);
1568
1570 if (node->local_name == LXB_TAG_INPUT
1571 || node->local_name == LXB_TAG_SELECT
1572 || node->local_name == LXB_TAG_TEXTAREA)
1573 {
1576 return attr == NULL;
1577 }
1578
1579 return false;
1580
1582 break;
1583
1585 break;
1586
1588 if (node->local_name == LXB_TAG_INPUT
1589 || node->local_name == LXB_TAG_TEXTAREA)
1590 {
1593 return attr != NULL;
1594 }
1595
1596 return false;
1597
1599 return !lxb_selectors_pseudo_class_read_write(node);
1600
1602 return lxb_selectors_pseudo_class_read_write(node);
1603
1605 if (node->local_name == LXB_TAG_INPUT
1606 || node->local_name == LXB_TAG_SELECT
1607 || node->local_name == LXB_TAG_TEXTAREA)
1608 {
1611 return attr != NULL;
1612 }
1613
1614 return false;
1615
1617 return lxb_dom_document_root(node->owner_document) == node;
1618
1620 break;
1621
1623 break;
1624
1626 break;
1627
1629 break;
1630
1632 break;
1633
1635 break;
1636
1638 break;
1639 }
1640
1641 return false;
1642}
1643
1644static bool
1645lxb_selectors_pseudo_class_function(const lxb_css_selector_t *selector,
1646 lxb_dom_node_t *node)
1647{
1648 size_t index;
1649 lxb_dom_node_t *base;
1650 const lxb_css_selector_pseudo_t *pseudo;
1651
1652 pseudo = &selector->u.pseudo;
1653
1654 switch (pseudo->type) {
1657 index = 0;
1658
1660 while (node != NULL) {
1661 if (node->local_name != LXB_TAG__TEXT
1662 && node->local_name != LXB_TAG__EM_COMMENT)
1663 {
1664 index++;
1665 }
1666
1667 node = node->prev;
1668 }
1669 }
1670 else {
1671 while (node != NULL) {
1672 if (node->local_name != LXB_TAG__TEXT
1673 && node->local_name != LXB_TAG__EM_COMMENT)
1674 {
1675 index++;
1676 }
1677
1678 node = node->next;
1679 }
1680 }
1681
1682 return lxb_selectors_anb_calc(pseudo->data, index);
1683
1686 index = 0;
1687 base = node;
1688
1690 while (node != NULL) {
1691 if(node->local_name == base->local_name
1692 && node->ns == base->ns)
1693 {
1694 index++;
1695 }
1696
1697 node = node->prev;
1698 }
1699 }
1700 else {
1701 while (node != NULL) {
1702 if(node->local_name == base->local_name
1703 && node->ns == base->ns)
1704 {
1705 index++;
1706 }
1707
1708 node = node->next;
1709 }
1710 }
1711
1712 return lxb_selectors_anb_calc(pseudo->data, index);
1713
1718 default:
1719 break;
1720 }
1721
1722 return false;
1723}
1724
1725static bool
1726lxb_selectors_pseudo_element(const lxb_css_selector_t *selector,
1727 const lxb_dom_node_t *node)
1728{
1729 const lxb_css_selector_pseudo_t *pseudo = &selector->u.pseudo;
1730
1731 switch (pseudo->type) {
1744 break;
1745 }
1746
1747 return false;
1748}
1749
1750static bool
1751lxb_selectors_pseudo_class_disabled(const lxb_dom_node_t *node)
1752{
1754 uintptr_t tag_id = node->local_name;
1755
1758 if (attr == NULL) {
1759 return false;
1760 }
1761
1762 if (tag_id == LXB_TAG_BUTTON || tag_id == LXB_TAG_INPUT ||
1763 tag_id == LXB_TAG_SELECT || tag_id == LXB_TAG_TEXTAREA ||
1764 tag_id >= LXB_TAG__LAST_ENTRY)
1765 {
1766 return true;
1767 }
1768
1769 node = node->parent;
1770
1771 while (node != NULL) {
1772 if (node->local_name == LXB_TAG_FIELDSET
1774 {
1775 return true;
1776 }
1777
1778 node = node->parent;
1779 }
1780
1781 return false;
1782}
1783
1784static bool
1785lxb_selectors_pseudo_class_first_child(const lxb_dom_node_t *node)
1786{
1787 node = node->prev;
1788
1789 while (node != NULL) {
1790 if (node->local_name != LXB_TAG__TEXT
1791 && node->local_name != LXB_TAG__EM_COMMENT)
1792 {
1793 return false;
1794 }
1795
1796 node = node->prev;
1797 }
1798
1799 return true;
1800}
1801
1802static bool
1803lxb_selectors_pseudo_class_first_of_type(const lxb_dom_node_t *node)
1804{
1805 const lxb_dom_node_t *root = node;
1806 node = node->prev;
1807
1808 while (node) {
1809 if (node->local_name == root->local_name
1810 && node->ns == root->ns)
1811 {
1812 return false;
1813 }
1814
1815 node = node->prev;
1816 }
1817
1818 return true;
1819}
1820
1821static bool
1822lxb_selectors_pseudo_class_last_child(const lxb_dom_node_t *node)
1823{
1824 node = node->next;
1825
1826 while (node != NULL) {
1827 if (node->local_name != LXB_TAG__TEXT
1828 && node->local_name != LXB_TAG__EM_COMMENT)
1829 {
1830 return false;
1831 }
1832
1833 node = node->next;
1834 }
1835
1836 return true;
1837}
1838
1839static bool
1840lxb_selectors_pseudo_class_last_of_type(const lxb_dom_node_t *node)
1841{
1842 const lxb_dom_node_t *root = node;
1843 node = node->next;
1844
1845 while (node) {
1846 if (node->local_name == root->local_name
1847 && node->ns == root->ns)
1848 {
1849 return false;
1850 }
1851
1852 node = node->next;
1853 }
1854
1855 return true;
1856}
1857
1858static bool
1859lxb_selectors_pseudo_class_read_write(const lxb_dom_node_t *node)
1860{
1862
1863 if (node->local_name == LXB_TAG_INPUT
1864 || node->local_name == LXB_TAG_TEXTAREA)
1865 {
1868 if (attr != NULL) {
1869 return false;
1870 }
1871
1872 return !lxb_selectors_pseudo_class_disabled(node);
1873 }
1874
1875 return false;
1876}
1877
1878static bool
1879lxb_selectors_anb_calc(lxb_css_selector_anb_of_t *anb, size_t index)
1880{
1881 double num;
1882
1883 if (anb->anb.a == 0) {
1884 if (anb->anb.b >= 0 && (size_t) anb->anb.b == index) {
1885 return true;
1886 }
1887 }
1888 else {
1889 num = ((double) index - (double) anb->anb.b) / (double) anb->anb.a;
1890
1891 if (num >= 0.0f && (num - trunc(num)) == 0.0f) {
1892 return true;
1893 }
1894 }
1895
1896 return false;
1897}
1898
1899static lxb_status_t
1900lxb_selectors_cb_ok(lxb_dom_node_t *node,
1901 lxb_css_selector_specificity_t spec, void *ctx)
1902{
1903 *((bool *) ctx) = true;
1904 return LXB_STATUS_OK;
1905}
1906
1907static lxb_status_t
1908lxb_selectors_cb_not(lxb_dom_node_t *node,
1909 lxb_css_selector_specificity_t spec, void *ctx)
1910{
1911 *((bool *) ctx) = false;
1912 return LXB_STATUS_OK;
1913}
1914
1915void
1920
1923{
1924 return lxb_selectors_selector(selectors);
1925}
char * cb
Definition assert.c:26
@ LXB_DOM_ATTR_HREF
Definition attr_const.h:36
@ LXB_DOM_ATTR_CHECKED
Definition attr_const.h:25
@ LXB_DOM_ATTR_REQUIRED
Definition attr_const.h:46
@ LXB_DOM_ATTR_ACTIVE
Definition attr_const.h:22
@ LXB_DOM_ATTR_PLACEHOLDER
Definition attr_const.h:42
@ LXB_DOM_ATTR_TYPE
Definition attr_const.h:55
@ LXB_DOM_ATTR_READONLY
Definition attr_const.h:45
@ LXB_DOM_ATTR_DISABLED
Definition attr_const.h:30
@ LXB_DOM_ATTR_FOCUS
Definition attr_const.h:32
@ LXB_DOM_ATTR_HOVER
Definition attr_const.h:35
@ LXB_DOM_ATTR_SELECTED
Definition attr_const.h:48
chr(int $codepoint)
@ LXB_STATUS_ERROR_INCOMPLETE_OBJECT
Definition base.h:54
@ LXB_STATUS_ERROR_MEMORY_ALLOCATION
Definition base.h:51
@ LXB_STATUS_STOP
Definition base.h:68
@ LXB_STATUS_OK
Definition base.h:49
@ LXB_STATUS_ERROR
Definition base.h:50
struct lxb_css_selector lxb_css_selector_t
Definition base.h:39
struct lxb_css_selector_list lxb_css_selector_list_t
Definition base.h:40
DNS_STATUS status
Definition dns_win32.c:49
void * lexbor_dobject_calloc(lexbor_dobject_t *dobject)
Definition dobject.c:123
lxb_status_t lexbor_dobject_init(lexbor_dobject_t *dobject, size_t chunk_size, size_t struct_size)
Definition dobject.c:22
void lexbor_dobject_clean(lexbor_dobject_t *dobject)
Definition dobject.c:64
lexbor_dobject_t * lexbor_dobject_destroy(lexbor_dobject_t *dobject, bool destroy_self)
Definition dobject.c:75
lexbor_dobject_t * lexbor_dobject_create(void)
Definition dobject.c:16
#define lxb_dom_interface_element(obj)
Definition interface.h:28
struct lxb_dom_node lxb_dom_node_t
Definition interface.h:38
struct lxb_dom_attr lxb_dom_attr_t
Definition interface.h:40
struct lxb_dom_element lxb_dom_element_t
Definition interface.h:39
@ LXB_DOM_NODE_TYPE_DOCUMENT
Definition node.h:33
@ LXB_DOM_NODE_TYPE_ELEMENT
Definition node.h:25
zend_string * res
Definition ffi.c:4692
new_type attr
Definition ffi.c:4364
int main(int argc, char **argv)
Definition gd2copypal.c:12
#define NULL
Definition gdcache.h:45
const lxb_dom_attr_data_t * lxb_dom_attr_data_by_local_name(lexbor_hash_t *hash, const lxb_char_t *name, size_t length)
Definition attr.c:425
lxb_dom_node_t * lxb_dom_document_root(lxb_dom_document_t *document)
Definition document.c:412
lxb_dom_attr_t * lxb_dom_element_attr_by_id(lxb_dom_element_t *element, lxb_dom_attr_id_t attr_id)
Definition element.c:460
bool lxb_dom_node_is_empty(const lxb_dom_node_t *root)
Definition node.c:1242
LXB_API void * lexbor_free(void *dst)
Definition memory.c:33
LXB_API void * lexbor_calloc(size_t num, size_t size)
Definition memory.c:27
#define next(ls)
Definition minilua.c:2661
unsigned const char * end
Definition php_ffi.h:51
unsigned const char * pos
Definition php_ffi.h:52
zend_constant * data
@ LXB_CSS_SELECTOR_PSEUDO_CLASS_IN_RANGE
@ LXB_CSS_SELECTOR_PSEUDO_CLASS_ACTIVE
@ LXB_CSS_SELECTOR_PSEUDO_CLASS_PAST
@ LXB_CSS_SELECTOR_PSEUDO_CLASS_ENABLED
@ LXB_CSS_SELECTOR_PSEUDO_CLASS_ANY_LINK
@ LXB_CSS_SELECTOR_PSEUDO_CLASS_WARNING
@ LXB_CSS_SELECTOR_PSEUDO_CLASS_TARGET_WITHIN
@ LXB_CSS_SELECTOR_PSEUDO_CLASS_LOCAL_LINK
@ LXB_CSS_SELECTOR_PSEUDO_CLASS_FULLSCREEN
@ LXB_CSS_SELECTOR_PSEUDO_CLASS_CURRENT
@ LXB_CSS_SELECTOR_PSEUDO_CLASS_ROOT
@ LXB_CSS_SELECTOR_PSEUDO_CLASS_LINK
@ LXB_CSS_SELECTOR_PSEUDO_CLASS_VISITED
@ LXB_CSS_SELECTOR_PSEUDO_CLASS_READ_ONLY
@ LXB_CSS_SELECTOR_PSEUDO_CLASS_FOCUS_WITHIN
@ LXB_CSS_SELECTOR_PSEUDO_CLASS_FOCUS
@ LXB_CSS_SELECTOR_PSEUDO_CLASS_INDETERMINATE
@ LXB_CSS_SELECTOR_PSEUDO_CLASS_FUTURE
@ LXB_CSS_SELECTOR_PSEUDO_CLASS_FIRST_CHILD
@ LXB_CSS_SELECTOR_PSEUDO_CLASS_FOCUS_VISIBLE
@ LXB_CSS_SELECTOR_PSEUDO_CLASS_LAST_OF_TYPE
@ LXB_CSS_SELECTOR_PSEUDO_CLASS_USER_INVALID
@ LXB_CSS_SELECTOR_PSEUDO_CLASS_VALID
@ LXB_CSS_SELECTOR_PSEUDO_CLASS_OPTIONAL
@ LXB_CSS_SELECTOR_PSEUDO_CLASS_SCOPE
@ LXB_CSS_SELECTOR_PSEUDO_CLASS_DISABLED
@ LXB_CSS_SELECTOR_PSEUDO_CLASS_EMPTY
@ LXB_CSS_SELECTOR_PSEUDO_CLASS_DEFAULT
@ LXB_CSS_SELECTOR_PSEUDO_CLASS_READ_WRITE
@ LXB_CSS_SELECTOR_PSEUDO_CLASS_PLACEHOLDER_SHOWN
@ LXB_CSS_SELECTOR_PSEUDO_CLASS_ONLY_OF_TYPE
@ LXB_CSS_SELECTOR_PSEUDO_CLASS_FIRST_OF_TYPE
@ LXB_CSS_SELECTOR_PSEUDO_CLASS_INVALID
@ LXB_CSS_SELECTOR_PSEUDO_CLASS_CHECKED
@ LXB_CSS_SELECTOR_PSEUDO_CLASS_BLANK
@ LXB_CSS_SELECTOR_PSEUDO_CLASS_REQUIRED
@ LXB_CSS_SELECTOR_PSEUDO_CLASS_ONLY_CHILD
@ LXB_CSS_SELECTOR_PSEUDO_CLASS_HOVER
@ LXB_CSS_SELECTOR_PSEUDO_CLASS_TARGET
@ LXB_CSS_SELECTOR_PSEUDO_CLASS_OUT_OF_RANGE
@ LXB_CSS_SELECTOR_PSEUDO_CLASS_LAST_CHILD
@ LXB_CSS_SELECTOR_PSEUDO_CLASS_FUNCTION_NTH_LAST_COL
@ LXB_CSS_SELECTOR_PSEUDO_CLASS_FUNCTION_NTH_LAST_OF_TYPE
@ LXB_CSS_SELECTOR_PSEUDO_CLASS_FUNCTION_IS
@ LXB_CSS_SELECTOR_PSEUDO_CLASS_FUNCTION_DIR
@ LXB_CSS_SELECTOR_PSEUDO_CLASS_FUNCTION_HAS
@ LXB_CSS_SELECTOR_PSEUDO_CLASS_FUNCTION_NTH_COL
@ LXB_CSS_SELECTOR_PSEUDO_CLASS_FUNCTION_CURRENT
@ LXB_CSS_SELECTOR_PSEUDO_CLASS_FUNCTION_LANG
@ LXB_CSS_SELECTOR_PSEUDO_CLASS_FUNCTION_WHERE
@ LXB_CSS_SELECTOR_PSEUDO_CLASS_FUNCTION_NTH_CHILD
@ LXB_CSS_SELECTOR_PSEUDO_CLASS_FUNCTION_NTH_OF_TYPE
@ LXB_CSS_SELECTOR_PSEUDO_CLASS_FUNCTION_NOT
@ LXB_CSS_SELECTOR_PSEUDO_CLASS_FUNCTION_NTH_LAST_CHILD
@ LXB_CSS_SELECTOR_PSEUDO_ELEMENT_SELECTION
@ LXB_CSS_SELECTOR_PSEUDO_ELEMENT_BACKDROP
@ LXB_CSS_SELECTOR_PSEUDO_ELEMENT_AFTER
@ LXB_CSS_SELECTOR_PSEUDO_ELEMENT_GRAMMAR_ERROR
@ LXB_CSS_SELECTOR_PSEUDO_ELEMENT_TARGET_TEXT
@ LXB_CSS_SELECTOR_PSEUDO_ELEMENT_PLACEHOLDER
@ LXB_CSS_SELECTOR_PSEUDO_ELEMENT_FIRST_LINE
@ LXB_CSS_SELECTOR_PSEUDO_ELEMENT_BEFORE
@ LXB_CSS_SELECTOR_PSEUDO_ELEMENT_INACTIVE_SELECTION
@ LXB_CSS_SELECTOR_PSEUDO_ELEMENT_SPELLING_ERROR
@ LXB_CSS_SELECTOR_PSEUDO_ELEMENT_MARKER
@ LXB_CSS_SELECTOR_PSEUDO_ELEMENT_FIRST_LETTER
uint32_t lxb_css_selector_specificity_t
Definition selector.h:107
@ LXB_CSS_SELECTOR_COMBINATOR_CELL
Definition selector.h:40
@ LXB_CSS_SELECTOR_COMBINATOR_CLOSE
Definition selector.h:36
@ LXB_CSS_SELECTOR_COMBINATOR_DESCENDANT
Definition selector.h:35
@ LXB_CSS_SELECTOR_COMBINATOR_SIBLING
Definition selector.h:38
@ LXB_CSS_SELECTOR_COMBINATOR_CHILD
Definition selector.h:37
@ LXB_CSS_SELECTOR_COMBINATOR_FOLLOWING
Definition selector.h:39
@ LXB_CSS_SELECTOR_TYPE_ELEMENT
Definition selector.h:22
@ LXB_CSS_SELECTOR_TYPE_PSEUDO_CLASS_FUNCTION
Definition selector.h:27
@ LXB_CSS_SELECTOR_TYPE_PSEUDO_CLASS
Definition selector.h:26
@ LXB_CSS_SELECTOR_TYPE_ATTRIBUTE
Definition selector.h:25
@ LXB_CSS_SELECTOR_TYPE_PSEUDO_ELEMENT_FUNCTION
Definition selector.h:29
@ LXB_CSS_SELECTOR_TYPE_ID
Definition selector.h:23
@ LXB_CSS_SELECTOR_TYPE_CLASS
Definition selector.h:24
@ LXB_CSS_SELECTOR_TYPE_PSEUDO_ELEMENT
Definition selector.h:28
@ LXB_CSS_SELECTOR_TYPE_ANY
Definition selector.h:21
@ LXB_CSS_SELECTOR_MODIFIER_I
Definition selector.h:58
@ LXB_CSS_SELECTOR_MATCH_PREFIX
Definition selector.h:49
@ LXB_CSS_SELECTOR_MATCH_SUBSTRING
Definition selector.h:51
@ LXB_CSS_SELECTOR_MATCH_DASH
Definition selector.h:48
@ LXB_CSS_SELECTOR_MATCH_SUFFIX
Definition selector.h:50
@ LXB_CSS_SELECTOR_MATCH_INCLUDE
Definition selector.h:47
@ LXB_CSS_SELECTOR_MATCH_EQUAL
Definition selector.h:46
lxb_status_t lxb_selectors_find(lxb_selectors_t *selectors, const xmlNode *root, const lxb_css_selector_list_t *list, lxb_selectors_cb_f cb, void *ctx)
Definition selectors.c:410
void lxb_selectors_destroy(lxb_selectors_t *selectors)
Definition selectors.c:316
lxb_inline const xmlNode * lxb_selectors_close(lxb_selectors_t *selectors, lxb_selectors_entry_t *entry, const lxb_css_selector_t *selector, const xmlNode *node)
Definition selectors.c:344
lxb_status_t lxb_selectors_init(lxb_selectors_t *selectors)
Definition selectors.c:285
lxb_inline const xmlNode * lxb_selectors_sibling(lxb_selectors_t *selectors, lxb_selectors_entry_t *entry, const lxb_css_selector_t *selector, const xmlNode *node)
Definition selectors.c:370
lxb_status_t lxb_selectors_match_node(lxb_selectors_t *selectors, const xmlNode *node, const lxb_css_selector_list_t *list, lxb_selectors_cb_f cb, void *ctx)
Definition selectors.c:434
void lxb_selectors_clean(lxb_selectors_t *selectors)
Definition selectors.c:309
lxb_inline const xmlNode * lxb_selectors_child(lxb_selectors_t *selectors, lxb_selectors_entry_t *entry, const lxb_css_selector_t *selector, const xmlNode *root)
Definition selectors.c:355
lxb_inline const xmlNode * lxb_selectors_following(lxb_selectors_t *selectors, lxb_selectors_entry_t *entry, const lxb_css_selector_t *selector, const xmlNode *node)
Definition selectors.c:391
lxb_inline const xmlNode * lxb_selectors_descendant(lxb_selectors_t *selectors, lxb_selectors_entry_t *entry, const lxb_css_selector_t *selector, const xmlNode *node)
Definition selectors.c:323
struct lxb_selectors_entry lxb_selectors_entry_t
Definition selectors.h:67
struct lxb_selectors lxb_selectors_t
Definition selectors.h:66
struct lxb_selectors_nested lxb_selectors_nested_t
Definition selectors.h:68
lxb_inline void lxb_selectors_opt_set(lxb_selectors_t *selectors, lxb_selectors_opt_t opt)
Definition selectors.h:230
lxb_inline const lxb_css_selector_list_t * lxb_selectors_selector(const lxb_selectors_t *selectors)
Definition selectors.h:246
lxb_selectors_opt_t
Definition selectors.h:23
@ LXB_SELECTORS_OPT_DEFAULT
Definition selectors.h:24
@ LXB_SELECTORS_OPT_MATCH_FIRST
Definition selectors.h:59
@ LXB_SELECTORS_OPT_MATCH_ROOT
Definition selectors.h:38
lxb_status_t(* lxb_selectors_cb_f)(const xmlNode *node, lxb_css_selector_specificity_t spec, void *ctx)
Definition selectors.h:71
lxb_status_t lxb_selectors_find_reverse(lxb_selectors_t *selectors, lxb_dom_node_t *root, lxb_css_selector_list_t *list, lxb_selectors_cb_f cb, void *ctx)
Definition selectors.c:322
void lxb_selectors_opt_set_noi(lxb_selectors_t *selectors, lxb_selectors_opt_t opt)
Definition selectors.c:1916
lxb_selectors_t * lxb_selectors_create(void)
Definition selectors.c:114
const lxb_css_selector_list_t * lxb_selectors_selector_noi(const lxb_selectors_t *selectors)
Definition selectors.c:1922
zval * current
Definition session.c:1024
bool lexbor_str_data_ncmp_contain(const lxb_char_t *where, size_t where_size, const lxb_char_t *what, size_t what_size)
Definition str.c:510
bool lexbor_str_data_ncasecmp(const lxb_char_t *first, const lxb_char_t *sec, size_t size)
Definition str.c:435
bool lexbor_str_data_ncmp(const lxb_char_t *first, const lxb_char_t *sec, size_t size)
Definition str.c:523
bool lexbor_str_data_ncasecmp_contain(const lxb_char_t *where, size_t where_size, const lxb_char_t *what, size_t what_size)
Definition str.c:422
lxb_char_t * data
Definition str.h:47
size_t length
Definition str.h:48
lxb_css_selector_list_t * of
Definition selector.h:79
lxb_css_syntax_anb_t anb
Definition selector.h:78
lxb_css_selector_list_t * next
Definition selector.h:171
lxb_css_selector_t * last
Definition selector.h:167
lxb_css_selector_specificity_t specificity
Definition selector.h:176
lxb_css_selector_t * first
Definition selector.h:166
lxb_css_selector_type_t type
Definition selector.h:84
lxb_css_selector_t * prev
Definition selector.h:97
lxb_css_selector_list_t * list
Definition selector.h:99
union lxb_css_selector::lxb_css_selector_u u
lxb_css_selector_combinator_t combinator
Definition selector.h:85
lexbor_str_t name
Definition selector.h:87
lxb_dom_attr_id_t attr_id
Definition attr.h:27
lexbor_str_t * value
Definition attr.h:42
lexbor_hash_t * tags
Definition document.h:55
lexbor_hash_t * attrs
Definition document.h:56
lxb_dom_attr_t * attr_class
Definition element.h:49
lxb_dom_attr_t * attr_id
Definition element.h:48
lxb_dom_node_t * prev
Definition node.h:53
uintptr_t ns
Definition node.h:48
lxb_dom_node_t * first_child
Definition node.h:55
lxb_dom_document_t * owner_document
Definition node.h:50
lxb_dom_node_type_t type
Definition node.h:59
uintptr_t local_name
Definition node.h:46
lxb_dom_node_t * parent
Definition node.h:54
lxb_dom_node_t * next
Definition node.h:52
lxb_selectors_entry_t * following
Definition selectors.h:91
lxb_selectors_entry_t * prev
Definition selectors.h:90
lxb_selectors_nested_t * nested
Definition selectors.h:92
const xmlNode * node
Definition selectors.h:88
lxb_selectors_adapted_id id
Definition selectors.h:85
const lxb_css_selector_t * selector
Definition selectors.h:87
lxb_selectors_entry_t * next
Definition selectors.h:89
lxb_css_selector_combinator_t combinator
Definition selectors.h:86
lxb_selectors_cb_f cb
Definition selectors.h:99
const xmlNode * root
Definition selectors.h:102
lxb_selectors_state_cb_f return_state
Definition selectors.h:97
lxb_selectors_nested_t * parent
Definition selectors.h:104
lxb_selectors_entry_t * entry
Definition selectors.h:96
lxb_selectors_entry_t * last
Definition selectors.h:103
lxb_selectors_state_cb_f state
Definition selectors.h:111
lxb_selectors_opt_t options
Definition selectors.h:118
lexbor_dobject_t * nested
Definition selectors.h:113
lxb_selectors_entry_t * first
Definition selectors.h:116
lxb_selectors_nested_t * current
Definition selectors.h:115
lexbor_dobject_t * objs
Definition selectors.h:112
lxb_status_t status
Definition selectors.h:119
@ LXB_TAG_OPTION
Definition const.h:167
@ LXB_TAG_BUTTON
Definition const.h:57
@ LXB_TAG_AREA
Definition const.h:42
@ LXB_TAG_INPUT
Definition const.h:130
@ LXB_TAG_FIELDSET
Definition const.h:105
@ LXB_TAG__EM_COMMENT
Definition const.h:28
@ LXB_TAG_LEGEND
Definition const.h:136
@ LXB_TAG__LAST_ENTRY
Definition const.h:220
@ LXB_TAG_LINK
Definition const.h:139
@ LXB_TAG_TEXTAREA
Definition const.h:204
@ LXB_TAG_A
Definition const.h:30
@ LXB_TAG__TEXT
Definition const.h:26
@ LXB_TAG_MAP
Definition const.h:143
@ LXB_TAG_SELECT
Definition const.h:187
@ LXB_TAG__UNDEF
Definition const.h:24
uintptr_t lxb_tag_id_t
Definition const.h:21
lxb_inline lxb_tag_id_t lxb_tag_id_by_name(lexbor_hash_t *hash, const lxb_char_t *name, size_t len)
Definition tag.h:83
unsigned int lxb_status_t
Definition types.h:28
#define lxb_inline
Definition types.h:21
unsigned char lxb_char_t
Definition types.h:27
lxb_css_selector_attribute_t attribute
Definition selector.h:91
lxb_css_selector_pseudo_t pseudo
Definition selector.h:92
#define lexbor_utils_whitespace(onechar, action, logic)
Definition utils.h:17
out($f, $s)