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 static bool
12 lxb_html_tree_insertion_mode_after_head_open(lxb_html_tree_t *tree,
13                                              lxb_html_token_t *token);
14 static bool
15 lxb_html_tree_insertion_mode_after_head_closed(lxb_html_tree_t *tree,
16                                                lxb_html_token_t *token);
17 
18 lxb_inline bool
19 lxb_html_tree_insertion_mode_after_head_anything_else(lxb_html_tree_t *tree);
20 
21 lxb_inline lxb_html_element_t *
22 lxb_html_tree_insertion_mode_after_head_create_body(lxb_html_tree_t *tree,
23                                                     lxb_html_token_t *token);
24 
25 
26 bool
lxb_html_tree_insertion_mode_after_head(lxb_html_tree_t * tree,lxb_html_token_t * token)27 lxb_html_tree_insertion_mode_after_head(lxb_html_tree_t *tree,
28                                         lxb_html_token_t *token)
29 {
30     if (token->type & LXB_HTML_TOKEN_TYPE_CLOSE) {
31         return lxb_html_tree_insertion_mode_after_head_closed(tree, token);
32     }
33 
34     return lxb_html_tree_insertion_mode_after_head_open(tree, token);
35 }
36 
37 static bool
lxb_html_tree_insertion_mode_after_head_open(lxb_html_tree_t * tree,lxb_html_token_t * token)38 lxb_html_tree_insertion_mode_after_head_open(lxb_html_tree_t *tree,
39                                              lxb_html_token_t *token)
40 {
41     switch (token->tag_id) {
42         case LXB_TAG__EM_COMMENT: {
43             lxb_dom_comment_t *comment;
44 
45             comment = lxb_html_tree_insert_comment(tree, token, NULL);
46             if (comment == NULL) {
47                 tree->status = LXB_STATUS_ERROR_MEMORY_ALLOCATION;
48 
49                 return lxb_html_tree_process_abort(tree);
50             }
51 
52             break;
53         }
54 
55         case LXB_TAG__EM_DOCTYPE:
56             lxb_html_tree_parse_error(tree, token,
57                                       LXB_HTML_RULES_ERROR_DOTOAFHEMO);
58             break;
59 
60         case LXB_TAG_HTML:
61             return lxb_html_tree_insertion_mode_in_body(tree, token);
62 
63         case LXB_TAG_BODY: {
64             lxb_html_element_t *element;
65 
66             element = lxb_html_tree_insertion_mode_after_head_create_body(tree,
67                                                                           token);
68             if (element == NULL) {
69                 tree->status = LXB_STATUS_ERROR_MEMORY_ALLOCATION;
70 
71                 return lxb_html_tree_process_abort(tree);
72             }
73 
74             tree->has_explicit_body_tag = true;
75             tree->frameset_ok = false;
76             tree->mode = lxb_html_tree_insertion_mode_in_body;
77 
78             break;
79         }
80 
81         case LXB_TAG_FRAMESET: {
82             lxb_html_element_t *element;
83 
84             element = lxb_html_tree_insert_html_element(tree, token);
85             if (element == NULL) {
86                 tree->status = LXB_STATUS_ERROR_MEMORY_ALLOCATION;
87 
88                 return lxb_html_tree_process_abort(tree);
89             }
90 
91             tree->mode = lxb_html_tree_insertion_mode_in_frameset;
92 
93             break;
94         }
95 
96         case LXB_TAG_BASE:
97         case LXB_TAG_BASEFONT:
98         case LXB_TAG_BGSOUND:
99         case LXB_TAG_LINK:
100         case LXB_TAG_META:
101         case LXB_TAG_NOFRAMES:
102         case LXB_TAG_SCRIPT:
103         case LXB_TAG_STYLE:
104         case LXB_TAG_TEMPLATE:
105         case LXB_TAG_TITLE: {
106             lxb_dom_node_t *head_node;
107 
108             head_node = lxb_dom_interface_node(tree->document->head);
109             if (head_node == NULL) {
110                 tree->status = LXB_STATUS_ERROR;
111 
112                 return lxb_html_tree_process_abort(tree);
113             }
114 
115             lxb_html_tree_parse_error(tree, token, LXB_HTML_RULES_ERROR_UNTO);
116 
117             tree->status = lxb_html_tree_open_elements_push(tree, head_node);
118             if (tree->status != LXB_STATUS_OK) {
119                 return lxb_html_tree_process_abort(tree);
120             }
121 
122             lxb_html_tree_insertion_mode_in_head(tree, token);
123             if (tree->status != LXB_STATUS_OK) {
124                 return lxb_html_tree_process_abort(tree);
125             }
126 
127             lxb_html_tree_open_elements_remove_by_node(tree, head_node);
128 
129             break;
130         }
131 
132         case LXB_TAG_HEAD:
133             lxb_html_tree_parse_error(tree, token,
134                                       LXB_HTML_RULES_ERROR_HETOAFHEMO);
135             break;
136 
137         case LXB_TAG__TEXT: {
138             lxb_html_token_t ws_token = {0};
139 
140             tree->status = lxb_html_token_data_split_ws_begin(token, &ws_token);
141             if (tree->status != LXB_STATUS_OK) {
142                 return lxb_html_tree_process_abort(tree);
143             }
144 
145             if (ws_token.text_start != ws_token.text_end) {
146                 tree->status = lxb_html_tree_insert_character(tree, &ws_token,
147                                                               NULL);
148                 if (tree->status != LXB_STATUS_OK) {
149                     return lxb_html_tree_process_abort(tree);
150                 }
151             }
152 
153             if (token->text_start == token->text_end) {
154                 return true;
155             }
156         }
157         /* fall through */
158 
159         default:
160             return lxb_html_tree_insertion_mode_after_head_anything_else(tree);
161     }
162 
163     return true;
164 }
165 
166 static bool
lxb_html_tree_insertion_mode_after_head_closed(lxb_html_tree_t * tree,lxb_html_token_t * token)167 lxb_html_tree_insertion_mode_after_head_closed(lxb_html_tree_t *tree,
168                                                lxb_html_token_t *token)
169 {
170     switch (token->tag_id) {
171         case LXB_TAG_TEMPLATE:
172             return lxb_html_tree_insertion_mode_in_head(tree, token);
173 
174         case LXB_TAG_BODY:
175         case LXB_TAG_HTML:
176         case LXB_TAG_BR:
177             return lxb_html_tree_insertion_mode_after_head_anything_else(tree);
178 
179         default:
180             lxb_html_tree_parse_error(tree, token, LXB_HTML_RULES_ERROR_UNCLTO);
181 
182             break;
183     }
184 
185     return true;
186 }
187 
188 lxb_inline bool
lxb_html_tree_insertion_mode_after_head_anything_else(lxb_html_tree_t * tree)189 lxb_html_tree_insertion_mode_after_head_anything_else(lxb_html_tree_t *tree)
190 {
191     lxb_html_element_t *element;
192     lxb_html_token_t fake_token = {0};
193 
194     fake_token.tag_id = LXB_TAG_BODY;
195 
196     element = lxb_html_tree_insertion_mode_after_head_create_body(tree,
197                                                                   &fake_token);
198     if (element == NULL) {
199         tree->status = LXB_STATUS_ERROR_MEMORY_ALLOCATION;
200 
201         return lxb_html_tree_process_abort(tree);
202     }
203 
204     tree->mode = lxb_html_tree_insertion_mode_in_body;
205 
206     return false;
207 }
208 
209 lxb_inline lxb_html_element_t *
lxb_html_tree_insertion_mode_after_head_create_body(lxb_html_tree_t * tree,lxb_html_token_t * token)210 lxb_html_tree_insertion_mode_after_head_create_body(lxb_html_tree_t *tree,
211                                                     lxb_html_token_t *token)
212 {
213     lxb_html_element_t *element;
214 
215     element = lxb_html_tree_insert_html_element(tree, token);
216     if (element == NULL) {
217         return NULL;
218     }
219 
220     tree->document->body = lxb_html_interface_body(element);
221 
222     return element;
223 }
224