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 #include "lexbor/html/interfaces/html_element.h"
10 
11 
12 static bool
13 lxb_html_tree_insertion_mode_before_html_open(lxb_html_tree_t *tree,
14                                               lxb_html_token_t *token);
15 
16 static bool
17 lxb_html_tree_insertion_mode_before_html_closed(lxb_html_tree_t *tree,
18                                                 lxb_html_token_t *token);
19 
20 lxb_inline bool
21 lxb_html_tree_insertion_mode_before_html_anything_else(lxb_html_tree_t *tree);
22 
23 lxb_inline lxb_status_t
24 lxb_html_tree_insertion_mode_before_html_html(lxb_html_tree_t *tree,
25                                               lxb_dom_node_t *node_html);
26 
27 
28 bool
lxb_html_tree_insertion_mode_before_html(lxb_html_tree_t * tree,lxb_html_token_t * token)29 lxb_html_tree_insertion_mode_before_html(lxb_html_tree_t *tree,
30                                          lxb_html_token_t *token)
31 {
32     if (token->type & LXB_HTML_TOKEN_TYPE_CLOSE) {
33         return lxb_html_tree_insertion_mode_before_html_closed(tree, token);;
34     }
35 
36     return lxb_html_tree_insertion_mode_before_html_open(tree, token);
37 }
38 
39 static bool
lxb_html_tree_insertion_mode_before_html_open(lxb_html_tree_t * tree,lxb_html_token_t * token)40 lxb_html_tree_insertion_mode_before_html_open(lxb_html_tree_t *tree,
41                                               lxb_html_token_t *token)
42 {
43     switch (token->tag_id) {
44         case LXB_TAG__EM_DOCTYPE:
45             lxb_html_tree_parse_error(tree, token,
46                                       LXB_HTML_RULES_ERROR_DOTOINBEHTMO);
47             break;
48 
49         case LXB_TAG__EM_COMMENT: {
50             lxb_dom_comment_t *comment;
51 
52             comment = lxb_html_tree_insert_comment(tree, token,
53                                         lxb_dom_interface_node(tree->document));
54             if (comment == NULL) {
55                 return lxb_html_tree_process_abort(tree);
56             }
57 
58             break;
59         }
60 
61         case LXB_TAG_HTML: {
62             lxb_dom_node_t *node_html;
63             lxb_html_element_t *element;
64 
65             element = lxb_html_tree_create_element_for_token(tree, token,
66                                             LXB_NS_HTML,
67                                             &tree->document->dom_document.node);
68             if (element == NULL) {
69                 tree->status = LXB_STATUS_ERROR_MEMORY_ALLOCATION;
70 
71                 return lxb_html_tree_process_abort(tree);
72             }
73 
74             node_html = lxb_dom_interface_node(element);
75 
76             tree->status = lxb_html_tree_insertion_mode_before_html_html(tree,
77                                                                      node_html);
78             if (tree->status != LXB_STATUS_OK) {
79                 return lxb_html_tree_process_abort(tree);
80             }
81 
82             tree->has_explicit_html_tag = true;
83 
84             tree->mode = lxb_html_tree_insertion_mode_before_head;
85 
86             break;
87         }
88 
89         case LXB_TAG__TEXT:
90             tree->status = lxb_html_token_data_skip_ws_begin(token);
91             if (tree->status != LXB_STATUS_OK) {
92                 return lxb_html_tree_process_abort(tree);
93             }
94 
95             if (token->text_start == token->text_end) {
96                 return true;
97             }
98             /* fall through */
99 
100         default:
101             return lxb_html_tree_insertion_mode_before_html_anything_else(tree);
102     }
103 
104     return true;
105 }
106 
107 static bool
lxb_html_tree_insertion_mode_before_html_closed(lxb_html_tree_t * tree,lxb_html_token_t * token)108 lxb_html_tree_insertion_mode_before_html_closed(lxb_html_tree_t *tree,
109                                                 lxb_html_token_t *token)
110 {
111     switch (token->tag_id) {
112         case LXB_TAG_HEAD:
113         case LXB_TAG_BODY:
114         case LXB_TAG_HTML:
115         case LXB_TAG_BR:
116             return lxb_html_tree_insertion_mode_before_html_anything_else(tree);
117 
118         default:
119             lxb_html_tree_parse_error(tree, token,
120                                       LXB_HTML_RULES_ERROR_UNCLTOINBEHTMO);
121             break;
122     }
123 
124     return true;
125 }
126 
127 lxb_inline bool
lxb_html_tree_insertion_mode_before_html_anything_else(lxb_html_tree_t * tree)128 lxb_html_tree_insertion_mode_before_html_anything_else(lxb_html_tree_t *tree)
129 {
130     lxb_dom_node_t *node_html;
131 
132     node_html = lxb_html_tree_create_node(tree, LXB_TAG_HTML, LXB_NS_HTML);
133     if (node_html == NULL) {
134         tree->status = LXB_STATUS_ERROR_MEMORY_ALLOCATION;
135         return lxb_html_tree_process_abort(tree);
136     }
137 
138     tree->status = lxb_html_tree_insertion_mode_before_html_html(tree,
139                                                                  node_html);
140     if (tree->status != LXB_STATUS_OK) {
141         return lxb_html_tree_process_abort(tree);
142     }
143 
144     tree->mode = lxb_html_tree_insertion_mode_before_head;
145 
146     return false;
147 }
148 
149 lxb_inline lxb_status_t
lxb_html_tree_insertion_mode_before_html_html(lxb_html_tree_t * tree,lxb_dom_node_t * node_html)150 lxb_html_tree_insertion_mode_before_html_html(lxb_html_tree_t *tree,
151                                               lxb_dom_node_t *node_html)
152 {
153     lxb_status_t status;
154 
155     status = lxb_html_tree_open_elements_push(tree, node_html);
156     if (status != LXB_STATUS_OK) {
157         return status;
158     }
159 
160     lxb_html_tree_insert_node(lxb_dom_interface_node(tree->document),
161                               node_html,
162                               LXB_HTML_TREE_INSERTION_POSITION_CHILD);
163 
164     lxb_dom_document_attach_element(&tree->document->dom_document,
165                                     lxb_dom_interface_element(node_html));
166 
167     return LXB_STATUS_OK;
168 }
169