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