1 /*
2  * Copyright (C) 2018-2020 Alexander Borisov
3  *
4  * Author: Alexander Borisov <borisov@lexbor.com>
5  */
6 
7 #include "lexbor/html/tree/insertion_mode.h"
8 #include "lexbor/html/tree/open_elements.h"
9 
10 
11 lxb_inline bool
lxb_html_tree_insertion_mode_in_select_text(lxb_html_tree_t * tree,lxb_html_token_t * token)12 lxb_html_tree_insertion_mode_in_select_text(lxb_html_tree_t *tree,
13                                             lxb_html_token_t *token)
14 {
15     lexbor_str_t str;
16 
17     if (token->null_count != 0) {
18         lxb_html_tree_parse_error(tree, token,
19                                   LXB_HTML_RULES_ERROR_NUCH);
20 
21         tree->status = lxb_html_token_make_text_drop_null(token, &str,
22                                                           tree->document->dom_document.text);
23     }
24     else {
25         tree->status = lxb_html_token_make_text(token, &str,
26                                                 tree->document->dom_document.text);
27     }
28 
29     if (tree->status != LXB_STATUS_OK) {
30         return lxb_html_tree_process_abort(tree);
31     }
32 
33     /* Can be zero only if all NULL are gone */
34     if (str.length == 0) {
35         lexbor_str_destroy(&str, tree->document->dom_document.text, false);
36 
37         return true;
38     }
39 
40     tree->status = lxb_html_tree_insert_character_for_data(tree, &str, NULL);
41     if (tree->status != LXB_STATUS_OK) {
42         return lxb_html_tree_process_abort(tree);
43     }
44 
45     return true;
46 }
47 
48 lxb_inline bool
lxb_html_tree_insertion_mode_in_select_comment(lxb_html_tree_t * tree,lxb_html_token_t * token)49 lxb_html_tree_insertion_mode_in_select_comment(lxb_html_tree_t *tree,
50                                                lxb_html_token_t *token)
51 {
52     lxb_dom_comment_t *comment;
53 
54     comment = lxb_html_tree_insert_comment(tree, token, NULL);
55     if (comment == NULL) {
56         tree->status = LXB_STATUS_ERROR_MEMORY_ALLOCATION;
57 
58         return lxb_html_tree_process_abort(tree);
59     }
60 
61     return true;
62 }
63 
64 lxb_inline bool
lxb_html_tree_insertion_mode_in_select_doctype(lxb_html_tree_t * tree,lxb_html_token_t * token)65 lxb_html_tree_insertion_mode_in_select_doctype(lxb_html_tree_t *tree,
66                                                lxb_html_token_t *token)
67 {
68     lxb_html_tree_parse_error(tree, token, LXB_HTML_RULES_ERROR_DOTOINSEMO);
69 
70     return true;
71 }
72 
73 lxb_inline bool
lxb_html_tree_insertion_mode_in_select_html(lxb_html_tree_t * tree,lxb_html_token_t * token)74 lxb_html_tree_insertion_mode_in_select_html(lxb_html_tree_t *tree,
75                                             lxb_html_token_t *token)
76 {
77     return lxb_html_tree_insertion_mode_in_body(tree, token);
78 }
79 
80 lxb_inline bool
lxb_html_tree_insertion_mode_in_select_option(lxb_html_tree_t * tree,lxb_html_token_t * token)81 lxb_html_tree_insertion_mode_in_select_option(lxb_html_tree_t *tree,
82                                               lxb_html_token_t *token)
83 {
84     lxb_html_element_t *element;
85     lxb_dom_node_t *node = lxb_html_tree_current_node(tree);
86 
87     if (lxb_html_tree_node_is(node, LXB_TAG_OPTION)) {
88         lxb_html_tree_open_elements_pop(tree);
89     }
90 
91     element = lxb_html_tree_insert_html_element(tree, token);
92     if (element == NULL) {
93         tree->status = LXB_STATUS_ERROR_MEMORY_ALLOCATION;
94 
95         return lxb_html_tree_process_abort(tree);
96     }
97 
98     return true;
99 }
100 
101 lxb_inline bool
lxb_html_tree_insertion_mode_in_select_optgroup(lxb_html_tree_t * tree,lxb_html_token_t * token)102 lxb_html_tree_insertion_mode_in_select_optgroup(lxb_html_tree_t *tree,
103                                                 lxb_html_token_t *token)
104 {
105     lxb_html_element_t *element;
106     lxb_dom_node_t *node = lxb_html_tree_current_node(tree);
107 
108     if (lxb_html_tree_node_is(node, LXB_TAG_OPTION)) {
109         lxb_html_tree_open_elements_pop(tree);
110     }
111 
112     node = lxb_html_tree_current_node(tree);
113 
114     if (lxb_html_tree_node_is(node, LXB_TAG_OPTGROUP)) {
115         lxb_html_tree_open_elements_pop(tree);
116     }
117 
118     element = lxb_html_tree_insert_html_element(tree, token);
119     if (element == NULL) {
120         tree->status = LXB_STATUS_ERROR_MEMORY_ALLOCATION;
121 
122         return lxb_html_tree_process_abort(tree);
123     }
124 
125     return true;
126 }
127 
128 lxb_inline bool
lxb_html_tree_insertion_mode_in_select_optgroup_closed(lxb_html_tree_t * tree,lxb_html_token_t * token)129 lxb_html_tree_insertion_mode_in_select_optgroup_closed(lxb_html_tree_t *tree,
130                                                        lxb_html_token_t *token)
131 {
132     lxb_dom_node_t *node = lxb_html_tree_current_node(tree);
133 
134     if (lxb_html_tree_node_is(node, LXB_TAG_OPTION)
135         && tree->open_elements->length > 1)
136     {
137         node = lxb_html_tree_open_elements_get(tree,
138                                                tree->open_elements->length - 2);
139         if (node != NULL && lxb_html_tree_node_is(node, LXB_TAG_OPTGROUP)) {
140             lxb_html_tree_open_elements_pop(tree);
141         }
142     }
143 
144     node = lxb_html_tree_current_node(tree);
145 
146     if (lxb_html_tree_node_is(node, LXB_TAG_OPTGROUP) == false) {
147         lxb_html_tree_parse_error(tree, token,
148                                   LXB_HTML_RULES_ERROR_UNELINOPELST);
149         return true;
150     }
151 
152     lxb_html_tree_open_elements_pop(tree);
153 
154     return true;
155 }
156 
157 lxb_inline bool
lxb_html_tree_insertion_mode_in_select_option_closed(lxb_html_tree_t * tree,lxb_html_token_t * token)158 lxb_html_tree_insertion_mode_in_select_option_closed(lxb_html_tree_t *tree,
159                                                      lxb_html_token_t *token)
160 {
161     lxb_dom_node_t *node = lxb_html_tree_current_node(tree);
162 
163     if (lxb_html_tree_node_is(node, LXB_TAG_OPTION) == false) {
164         lxb_html_tree_parse_error(tree, token,
165                                   LXB_HTML_RULES_ERROR_UNELINOPELST);
166         return true;
167     }
168 
169     lxb_html_tree_open_elements_pop(tree);
170 
171     return true;
172 }
173 
174 lxb_inline bool
lxb_html_tree_insertion_mode_in_select_select_closed(lxb_html_tree_t * tree,lxb_html_token_t * token)175 lxb_html_tree_insertion_mode_in_select_select_closed(lxb_html_tree_t *tree,
176                                                      lxb_html_token_t *token)
177 {
178     lxb_dom_node_t *node;
179 
180     node = lxb_html_tree_element_in_scope(tree, LXB_TAG_SELECT, LXB_NS_HTML,
181                                           LXB_HTML_TAG_CATEGORY_SCOPE_SELECT);
182     if (node == NULL) {
183         lxb_html_tree_parse_error(tree, token, LXB_HTML_RULES_ERROR_UNCLTO);
184 
185         return true;
186     }
187 
188     lxb_html_tree_open_elements_pop_until_tag_id(tree, LXB_TAG_SELECT,
189                                                  LXB_NS_HTML, true);
190 
191     lxb_html_tree_reset_insertion_mode_appropriately(tree);
192 
193     return true;
194 }
195 
196 lxb_inline bool
lxb_html_tree_insertion_mode_in_select_select(lxb_html_tree_t * tree,lxb_html_token_t * token)197 lxb_html_tree_insertion_mode_in_select_select(lxb_html_tree_t *tree,
198                                               lxb_html_token_t *token)
199 {
200     lxb_dom_node_t *node;
201 
202     lxb_html_tree_parse_error(tree, token, LXB_HTML_RULES_ERROR_UNTO);
203 
204     node = lxb_html_tree_element_in_scope(tree, LXB_TAG_SELECT, LXB_NS_HTML,
205                                           LXB_HTML_TAG_CATEGORY_SCOPE_SELECT);
206     if (node == NULL) {
207         return true;
208     }
209 
210     lxb_html_tree_open_elements_pop_until_tag_id(tree, LXB_TAG_SELECT,
211                                                  LXB_NS_HTML, true);
212 
213     lxb_html_tree_reset_insertion_mode_appropriately(tree);
214 
215     return true;
216 }
217 
218 /*
219  * "input", "keygen", "textarea"
220  */
221 lxb_inline bool
lxb_html_tree_insertion_mode_in_select_ikt(lxb_html_tree_t * tree,lxb_html_token_t * token)222 lxb_html_tree_insertion_mode_in_select_ikt(lxb_html_tree_t *tree,
223                                            lxb_html_token_t *token)
224 {
225     lxb_dom_node_t *node;
226 
227     lxb_html_tree_parse_error(tree, token, LXB_HTML_RULES_ERROR_UNTO);
228 
229     node = lxb_html_tree_element_in_scope(tree, LXB_TAG_SELECT, LXB_NS_HTML,
230                                           LXB_HTML_TAG_CATEGORY_SCOPE_SELECT);
231     if (node == NULL) {
232         return true;
233     }
234 
235     lxb_html_tree_open_elements_pop_until_tag_id(tree, LXB_TAG_SELECT,
236                                                  LXB_NS_HTML, true);
237 
238     lxb_html_tree_reset_insertion_mode_appropriately(tree);
239 
240     return false;
241 }
242 
243 /*
244  * A start tag whose tag name is one of: "script", "template"
245  * An end tag whose tag name is "template"
246  */
247 lxb_inline bool
lxb_html_tree_insertion_mode_in_select_st_open_closed(lxb_html_tree_t * tree,lxb_html_token_t * token)248 lxb_html_tree_insertion_mode_in_select_st_open_closed(lxb_html_tree_t *tree,
249                                                       lxb_html_token_t *token)
250 {
251     return lxb_html_tree_insertion_mode_in_head(tree, token);
252 }
253 
254 lxb_inline bool
lxb_html_tree_insertion_mode_in_select_end_of_file(lxb_html_tree_t * tree,lxb_html_token_t * token)255 lxb_html_tree_insertion_mode_in_select_end_of_file(lxb_html_tree_t *tree,
256                                                    lxb_html_token_t *token)
257 {
258     return lxb_html_tree_insertion_mode_in_body(tree, token);
259 }
260 
261 lxb_inline bool
lxb_html_tree_insertion_mode_in_select_anything_else(lxb_html_tree_t * tree,lxb_html_token_t * token)262 lxb_html_tree_insertion_mode_in_select_anything_else(lxb_html_tree_t *tree,
263                                                      lxb_html_token_t *token)
264 {
265     lxb_html_tree_parse_error(tree, token, LXB_HTML_RULES_ERROR_UNTO);
266 
267     return true;
268 }
269 
270 lxb_inline bool
lxb_html_tree_insertion_mode_in_select_anything_else_closed(lxb_html_tree_t * tree,lxb_html_token_t * token)271 lxb_html_tree_insertion_mode_in_select_anything_else_closed(lxb_html_tree_t *tree,
272                                                             lxb_html_token_t *token)
273 {
274     lxb_html_tree_parse_error(tree, token, LXB_HTML_RULES_ERROR_UNCLTO);
275 
276     return true;
277 }
278 
279 bool
lxb_html_tree_insertion_mode_in_select(lxb_html_tree_t * tree,lxb_html_token_t * token)280 lxb_html_tree_insertion_mode_in_select(lxb_html_tree_t *tree,
281                                        lxb_html_token_t *token)
282 {
283     if (token->type & LXB_HTML_TOKEN_TYPE_CLOSE) {
284         switch (token->tag_id) {
285             case LXB_TAG_OPTGROUP:
286                 return lxb_html_tree_insertion_mode_in_select_optgroup_closed(tree,
287                                                                               token);
288             case LXB_TAG_OPTION:
289                 return lxb_html_tree_insertion_mode_in_select_option_closed(tree,
290                                                                             token);
291             case LXB_TAG_SELECT:
292                 return lxb_html_tree_insertion_mode_in_select_select_closed(tree,
293                                                                             token);
294             case LXB_TAG_TEMPLATE:
295                 return lxb_html_tree_insertion_mode_in_select_st_open_closed(tree,
296                                                                              token);
297             default:
298                 return lxb_html_tree_insertion_mode_in_select_anything_else_closed(tree,
299                                                                                    token);
300         }
301     }
302 
303     switch (token->tag_id) {
304         case LXB_TAG__TEXT:
305             return lxb_html_tree_insertion_mode_in_select_text(tree, token);
306 
307         case LXB_TAG__EM_COMMENT:
308             return lxb_html_tree_insertion_mode_in_select_comment(tree, token);
309 
310         case LXB_TAG__EM_DOCTYPE:
311             return lxb_html_tree_insertion_mode_in_select_doctype(tree, token);
312 
313         case LXB_TAG_HTML:
314             return lxb_html_tree_insertion_mode_in_select_html(tree, token);
315 
316         case LXB_TAG_OPTION:
317             return lxb_html_tree_insertion_mode_in_select_option(tree, token);
318 
319         case LXB_TAG_OPTGROUP:
320             return lxb_html_tree_insertion_mode_in_select_optgroup(tree, token);
321 
322         case LXB_TAG_SELECT:
323             return lxb_html_tree_insertion_mode_in_select_select(tree, token);
324 
325         case LXB_TAG_INPUT:
326         case LXB_TAG_KEYGEN:
327         case LXB_TAG_TEXTAREA:
328             return lxb_html_tree_insertion_mode_in_select_ikt(tree, token);
329 
330         case LXB_TAG_SCRIPT:
331         case LXB_TAG_TEMPLATE:
332             return lxb_html_tree_insertion_mode_in_select_st_open_closed(tree,
333                                                                          token);
334         case LXB_TAG__END_OF_FILE:
335             return lxb_html_tree_insertion_mode_in_select_end_of_file(tree,
336                                                                       token);
337         default:
338             return lxb_html_tree_insertion_mode_in_select_anything_else(tree,
339                                                                         token);
340     }
341 }
342