1 /*
2  * Copyright (C) 2018-2019 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 #include "lexbor/html/tree/active_formatting.h"
10 
11 
12 static void
lxb_html_tree_clear_stack_back_to_table_row(lxb_html_tree_t * tree)13 lxb_html_tree_clear_stack_back_to_table_row(lxb_html_tree_t *tree)
14 {
15     lxb_dom_node_t *current = lxb_html_tree_current_node(tree);
16 
17     while ((current->local_name != LXB_TAG_TR
18             && current->local_name != LXB_TAG_TEMPLATE
19             && current->local_name != LXB_TAG_HTML)
20            || current->ns != LXB_NS_HTML)
21     {
22         lxb_html_tree_open_elements_pop(tree);
23         current = lxb_html_tree_current_node(tree);
24     }
25 }
26 
27 /*
28  * "th", "td"
29  */
30 lxb_inline bool
lxb_html_tree_insertion_mode_in_row_thtd(lxb_html_tree_t * tree,lxb_html_token_t * token)31 lxb_html_tree_insertion_mode_in_row_thtd(lxb_html_tree_t *tree,
32                                          lxb_html_token_t *token)
33 {
34     lxb_html_element_t *element;
35 
36     lxb_html_tree_clear_stack_back_to_table_row(tree);
37 
38     element = lxb_html_tree_insert_html_element(tree, token);
39     if (element == NULL) {
40         tree->status = LXB_STATUS_ERROR_MEMORY_ALLOCATION;
41 
42         return lxb_html_tree_process_abort(tree);
43     }
44 
45     tree->mode = lxb_html_tree_insertion_mode_in_cell;
46 
47     tree->status = lxb_html_tree_active_formatting_push_marker(tree);
48     if (tree->status != LXB_STATUS_OK) {
49         return lxb_html_tree_process_abort(tree);
50     }
51 
52     return true;
53 }
54 
55 lxb_inline bool
lxb_html_tree_insertion_mode_in_row_tr_closed(lxb_html_tree_t * tree,lxb_html_token_t * token)56 lxb_html_tree_insertion_mode_in_row_tr_closed(lxb_html_tree_t *tree,
57                                               lxb_html_token_t *token)
58 {
59     lxb_dom_node_t *node;
60 
61     node = lxb_html_tree_element_in_scope(tree, LXB_TAG_TR, LXB_NS_HTML,
62                                           LXB_HTML_TAG_CATEGORY_SCOPE_TABLE);
63     if (node == NULL) {
64         lxb_html_tree_parse_error(tree, token, LXB_HTML_RULES_ERROR_UNCLTO);
65 
66         return true;
67     }
68 
69     lxb_html_tree_clear_stack_back_to_table_row(tree);
70     lxb_html_tree_open_elements_pop(tree);
71 
72     tree->mode = lxb_html_tree_insertion_mode_in_table_body;
73 
74     return true;
75 }
76 
77 /*
78  * A start tag whose tag name is one of: "caption", "col", "colgroup", "tbody",
79  * "tfoot", "thead", "tr"
80  * An end tag whose tag name is "table"
81  */
82 lxb_inline bool
lxb_html_tree_insertion_mode_in_row_ct_open_closed(lxb_html_tree_t * tree,lxb_html_token_t * token)83 lxb_html_tree_insertion_mode_in_row_ct_open_closed(lxb_html_tree_t *tree,
84                                                    lxb_html_token_t *token)
85 {
86     lxb_dom_node_t *node;
87 
88     node = lxb_html_tree_element_in_scope(tree, LXB_TAG_TR, LXB_NS_HTML,
89                                           LXB_HTML_TAG_CATEGORY_SCOPE_TABLE);
90     if (node == NULL) {
91         lxb_html_tree_parse_error(tree, token, LXB_HTML_RULES_ERROR_UNTO);
92 
93         return true;
94     }
95 
96     lxb_html_tree_clear_stack_back_to_table_row(tree);
97     lxb_html_tree_open_elements_pop(tree);
98 
99     tree->mode = lxb_html_tree_insertion_mode_in_table_body;
100 
101     return false;
102 }
103 
104 /*
105  * "tbody", "tfoot", "thead"
106  */
107 lxb_inline bool
lxb_html_tree_insertion_mode_in_row_tbtfth_closed(lxb_html_tree_t * tree,lxb_html_token_t * token)108 lxb_html_tree_insertion_mode_in_row_tbtfth_closed(lxb_html_tree_t *tree,
109                                                   lxb_html_token_t *token)
110 {
111     lxb_dom_node_t *node;
112 
113     node = lxb_html_tree_element_in_scope(tree, token->tag_id, LXB_NS_HTML,
114                                           LXB_HTML_TAG_CATEGORY_SCOPE_TABLE);
115     if (node == NULL) {
116         lxb_html_tree_parse_error(tree, token, LXB_HTML_RULES_ERROR_UNCLTO);
117 
118         return true;
119     }
120 
121     node = lxb_html_tree_element_in_scope(tree, LXB_TAG_TR, LXB_NS_HTML,
122                                           LXB_HTML_TAG_CATEGORY_SCOPE_TABLE);
123     if (node == NULL) {
124         return true;
125     }
126 
127     lxb_html_tree_clear_stack_back_to_table_row(tree);
128     lxb_html_tree_open_elements_pop(tree);
129 
130     tree->mode = lxb_html_tree_insertion_mode_in_table_body;
131 
132     return false;
133 }
134 
135 /*
136  * "body", "caption", "col", "colgroup", "html", "td", "th"
137  */
138 lxb_inline bool
lxb_html_tree_insertion_mode_in_row_bcht_closed(lxb_html_tree_t * tree,lxb_html_token_t * token)139 lxb_html_tree_insertion_mode_in_row_bcht_closed(lxb_html_tree_t *tree,
140                                                 lxb_html_token_t *token)
141 {
142     lxb_html_tree_parse_error(tree, token, LXB_HTML_RULES_ERROR_UNCLTO);
143 
144     return true;
145 }
146 
147 lxb_inline bool
lxb_html_tree_insertion_mode_in_row_anything_else(lxb_html_tree_t * tree,lxb_html_token_t * token)148 lxb_html_tree_insertion_mode_in_row_anything_else(lxb_html_tree_t *tree,
149                                                   lxb_html_token_t *token)
150 {
151     return lxb_html_tree_insertion_mode_in_table(tree, token);
152 }
153 
154 lxb_inline bool
lxb_html_tree_insertion_mode_in_row_anything_else_closed(lxb_html_tree_t * tree,lxb_html_token_t * token)155 lxb_html_tree_insertion_mode_in_row_anything_else_closed(lxb_html_tree_t *tree,
156                                                          lxb_html_token_t *token)
157 {
158     return lxb_html_tree_insertion_mode_in_row_anything_else(tree, token);
159 }
160 
161 bool
lxb_html_tree_insertion_mode_in_row(lxb_html_tree_t * tree,lxb_html_token_t * token)162 lxb_html_tree_insertion_mode_in_row(lxb_html_tree_t *tree,
163                                     lxb_html_token_t *token)
164 {
165     if (token->type & LXB_HTML_TOKEN_TYPE_CLOSE) {
166         switch (token->tag_id) {
167             case LXB_TAG_TR:
168                 return lxb_html_tree_insertion_mode_in_row_tr_closed(tree,
169                                                                      token);
170             case LXB_TAG_TABLE:
171                 return lxb_html_tree_insertion_mode_in_row_ct_open_closed(tree,
172                                                                           token);
173             case LXB_TAG_TBODY:
174             case LXB_TAG_TFOOT:
175             case LXB_TAG_THEAD:
176                 return lxb_html_tree_insertion_mode_in_row_tbtfth_closed(tree,
177                                                                          token);
178             case LXB_TAG_BODY:
179             case LXB_TAG_CAPTION:
180             case LXB_TAG_COL:
181             case LXB_TAG_COLGROUP:
182             case LXB_TAG_HTML:
183             case LXB_TAG_TD:
184             case LXB_TAG_TH:
185                 return lxb_html_tree_insertion_mode_in_row_bcht_closed(tree,
186                                                                        token);
187             default:
188                 return lxb_html_tree_insertion_mode_in_row_anything_else_closed(tree,
189                                                                                 token);
190         }
191     }
192 
193     switch (token->tag_id) {
194         case LXB_TAG_TH:
195         case LXB_TAG_TD:
196             return lxb_html_tree_insertion_mode_in_row_thtd(tree, token);
197 
198         case LXB_TAG_CAPTION:
199         case LXB_TAG_COL:
200         case LXB_TAG_COLGROUP:
201         case LXB_TAG_TBODY:
202         case LXB_TAG_TFOOT:
203         case LXB_TAG_THEAD:
204         case LXB_TAG_TR:
205             return lxb_html_tree_insertion_mode_in_row_ct_open_closed(tree,
206                                                                       token);
207         default:
208             return lxb_html_tree_insertion_mode_in_row_anything_else(tree,
209                                                                      token);
210     }
211 }
212