1 /*
2  * Copyright (C) 2018 Alexander Borisov
3  *
4  * Author: Alexander Borisov <borisov@lexbor.com>
5  */
6 
7 #include "lexbor/html/tree/open_elements.h"
8 #include "lexbor/html/tree.h"
9 
10 
11 LXB_API void
lxb_html_tree_open_elements_remove_by_node(lxb_html_tree_t * tree,lxb_dom_node_t * node)12 lxb_html_tree_open_elements_remove_by_node(lxb_html_tree_t *tree,
13                                            lxb_dom_node_t *node)
14 {
15     size_t delta;
16     void **list = tree->open_elements->list;
17     size_t len = tree->open_elements->length;
18 
19     while (len != 0) {
20         len--;
21 
22         if (list[len] == node) {
23             delta = tree->open_elements->length - len - 1;
24 
25             memmove(list + len, list + len + 1, sizeof(void *) * delta);
26 
27             tree->open_elements->length--;
28 
29             break;
30         }
31     }
32 }
33 
34 void
lxb_html_tree_open_elements_pop_until_tag_id(lxb_html_tree_t * tree,lxb_tag_id_t tag_id,lxb_ns_id_t ns,bool exclude)35 lxb_html_tree_open_elements_pop_until_tag_id(lxb_html_tree_t *tree,
36                                              lxb_tag_id_t tag_id,
37                                              lxb_ns_id_t ns,
38                                              bool exclude)
39 {
40     void **list = tree->open_elements->list;
41     lxb_dom_node_t *node;
42 
43     while (tree->open_elements->length != 0) {
44         tree->open_elements->length--;
45 
46         node = list[ tree->open_elements->length ];
47 
48         if (node->local_name == tag_id && node->ns == ns) {
49             if (exclude == false) {
50                 tree->open_elements->length++;
51             }
52 
53             break;
54         }
55     }
56 }
57 
58 void
lxb_html_tree_open_elements_pop_until_h123456(lxb_html_tree_t * tree)59 lxb_html_tree_open_elements_pop_until_h123456(lxb_html_tree_t *tree)
60 {
61     void **list = tree->open_elements->list;
62     lxb_dom_node_t *node;
63 
64     while (tree->open_elements->length != 0) {
65         tree->open_elements->length--;
66 
67         node = list[ tree->open_elements->length ];
68 
69         switch (node->local_name) {
70             case LXB_TAG_H1:
71             case LXB_TAG_H2:
72             case LXB_TAG_H3:
73             case LXB_TAG_H4:
74             case LXB_TAG_H5:
75             case LXB_TAG_H6:
76                 if (node->ns == LXB_NS_HTML) {
77                     return;
78                 }
79 
80                 break;
81 
82             default:
83                 break;
84         }
85     }
86 }
87 
88 void
lxb_html_tree_open_elements_pop_until_td_th(lxb_html_tree_t * tree)89 lxb_html_tree_open_elements_pop_until_td_th(lxb_html_tree_t *tree)
90 {
91     void **list = tree->open_elements->list;
92     lxb_dom_node_t *node;
93 
94     while (tree->open_elements->length != 0) {
95         tree->open_elements->length--;
96 
97         node = list[ tree->open_elements->length ];
98 
99         switch (node->local_name) {
100             case LXB_TAG_TD:
101             case LXB_TAG_TH:
102                 if (node->ns == LXB_NS_HTML) {
103                     return;
104                 }
105 
106                 break;
107 
108             default:
109                 break;
110         }
111     }
112 }
113 
114 void
lxb_html_tree_open_elements_pop_until_node(lxb_html_tree_t * tree,lxb_dom_node_t * node,bool exclude)115 lxb_html_tree_open_elements_pop_until_node(lxb_html_tree_t *tree,
116                                            lxb_dom_node_t *node,
117                                            bool exclude)
118 {
119     void **list = tree->open_elements->list;
120 
121     while (tree->open_elements->length != 0) {
122         tree->open_elements->length--;
123 
124         if (list[ tree->open_elements->length ] == node) {
125             if (exclude == false) {
126                 tree->open_elements->length++;
127             }
128 
129             break;
130         }
131     }
132 }
133 
134 void
lxb_html_tree_open_elements_pop_until(lxb_html_tree_t * tree,size_t idx,bool exclude)135 lxb_html_tree_open_elements_pop_until(lxb_html_tree_t *tree, size_t idx,
136                                       bool exclude)
137 {
138     tree->open_elements->length = idx;
139 
140     if (exclude == false) {
141         tree->open_elements->length++;
142     }
143 }
144 
145 bool
lxb_html_tree_open_elements_find_by_node(lxb_html_tree_t * tree,lxb_dom_node_t * node,size_t * return_pos)146 lxb_html_tree_open_elements_find_by_node(lxb_html_tree_t *tree,
147                                          lxb_dom_node_t *node,
148                                          size_t *return_pos)
149 {
150     void **list = tree->open_elements->list;
151 
152     for (size_t i = 0; i < tree->open_elements->length; i++) {
153         if (list[i] == node) {
154             if (return_pos) {
155                 *return_pos = i;
156             }
157 
158             return true;
159         }
160     }
161 
162     if (return_pos) {
163         *return_pos = 0;
164     }
165 
166     return false;
167 }
168 
169 bool
lxb_html_tree_open_elements_find_by_node_reverse(lxb_html_tree_t * tree,lxb_dom_node_t * node,size_t * return_pos)170 lxb_html_tree_open_elements_find_by_node_reverse(lxb_html_tree_t *tree,
171                                                  lxb_dom_node_t *node,
172                                                  size_t *return_pos)
173 {
174     void **list = tree->open_elements->list;
175     size_t len = tree->open_elements->length;
176 
177     while (len != 0) {
178         len--;
179 
180         if (list[len] == node) {
181             if (return_pos) {
182                 *return_pos = len;
183             }
184 
185             return true;
186         }
187     }
188 
189     if (return_pos) {
190         *return_pos = 0;
191     }
192 
193     return false;
194 }
195 
196 lxb_dom_node_t *
lxb_html_tree_open_elements_find(lxb_html_tree_t * tree,lxb_tag_id_t tag_id,lxb_ns_id_t ns,size_t * return_index)197 lxb_html_tree_open_elements_find(lxb_html_tree_t *tree,
198                                  lxb_tag_id_t tag_id, lxb_ns_id_t ns,
199                                  size_t *return_index)
200 {
201     void **list = tree->open_elements->list;
202     lxb_dom_node_t *node;
203 
204     for (size_t i = 0; i < tree->open_elements->length; i++) {
205         node = list[i];
206 
207         if (node->local_name == tag_id && node->ns == ns) {
208             if (return_index) {
209                 *return_index = i;
210             }
211 
212             return node;
213         }
214     }
215 
216     if (return_index) {
217         *return_index = 0;
218     }
219 
220     return NULL;
221 }
222 
223 lxb_dom_node_t *
lxb_html_tree_open_elements_find_reverse(lxb_html_tree_t * tree,lxb_tag_id_t tag_id,lxb_ns_id_t ns,size_t * return_index)224 lxb_html_tree_open_elements_find_reverse(lxb_html_tree_t *tree,
225                                          lxb_tag_id_t tag_id, lxb_ns_id_t ns,
226                                          size_t *return_index)
227 {
228     void **list = tree->open_elements->list;
229     size_t len = tree->open_elements->length;
230 
231     lxb_dom_node_t *node;
232 
233     while (len != 0) {
234         len--;
235         node = list[len];
236 
237         if (node->local_name == tag_id && node->ns == ns) {
238             if (return_index) {
239                 *return_index = len;
240             }
241 
242             return node;
243         }
244     }
245 
246     if (return_index) {
247         *return_index = 0;
248     }
249 
250     return NULL;
251 }
252