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 
9 
10 static bool
11 lxb_html_tree_insertion_mode_before_head_open(lxb_html_tree_t *tree,
12                                               lxb_html_token_t *token);
13 
14 static bool
15 lxb_html_tree_insertion_mode_before_head_closed(lxb_html_tree_t *tree,
16                                                 lxb_html_token_t *token);
17 
18 lxb_inline bool
19 lxb_html_tree_insertion_mode_before_head_anything_else(lxb_html_tree_t *tree);
20 
21 lxb_inline lxb_status_t
22 lxb_html_tree_insertion_mode_before_head_head(lxb_html_tree_t *tree,
23                                               lxb_html_token_t *token);
24 
25 
26 bool
lxb_html_tree_insertion_mode_before_head(lxb_html_tree_t * tree,lxb_html_token_t * token)27 lxb_html_tree_insertion_mode_before_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_before_head_closed(tree, token);
32     }
33 
34     return lxb_html_tree_insertion_mode_before_head_open(tree, token);
35 }
36 
37 static bool
lxb_html_tree_insertion_mode_before_head_open(lxb_html_tree_t * tree,lxb_html_token_t * token)38 lxb_html_tree_insertion_mode_before_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_DOTOINBEHEMO);
58             break;
59 
60         case LXB_TAG_HTML:
61             return lxb_html_tree_insertion_mode_in_body(tree, token);
62 
63         case LXB_TAG_HEAD:
64             tree->status = lxb_html_tree_insertion_mode_before_head_head(tree,
65                                                                          token);
66             if (tree->status != LXB_STATUS_OK) {
67                 return lxb_html_tree_process_abort(tree);
68             }
69 
70             tree->has_explicit_head_tag = true;
71 
72             tree->mode = lxb_html_tree_insertion_mode_in_head;
73 
74             break;
75 
76         case LXB_TAG__TEXT:
77             tree->status = lxb_html_token_data_skip_ws_begin(token);
78             if (tree->status != LXB_STATUS_OK) {
79                 return lxb_html_tree_process_abort(tree);
80             }
81 
82             if (token->text_start == token->text_end) {
83                 return true;
84             }
85             /* fall through */
86 
87         default:
88             return lxb_html_tree_insertion_mode_before_head_anything_else(tree);
89     }
90 
91     return true;
92 }
93 
94 static bool
lxb_html_tree_insertion_mode_before_head_closed(lxb_html_tree_t * tree,lxb_html_token_t * token)95 lxb_html_tree_insertion_mode_before_head_closed(lxb_html_tree_t *tree,
96                                                 lxb_html_token_t *token)
97 {
98     switch (token->tag_id) {
99         case LXB_TAG_HEAD:
100         case LXB_TAG_BODY:
101         case LXB_TAG_HTML:
102         case LXB_TAG_BR:
103             return lxb_html_tree_insertion_mode_before_head_anything_else(tree);
104 
105         default:
106             lxb_html_tree_parse_error(tree, token,
107                                       LXB_HTML_RULES_ERROR_UNCLTOINBEHEMO);
108             break;
109     }
110 
111     return true;
112 }
113 
114 lxb_inline bool
lxb_html_tree_insertion_mode_before_head_anything_else(lxb_html_tree_t * tree)115 lxb_html_tree_insertion_mode_before_head_anything_else(lxb_html_tree_t *tree)
116 {
117     lxb_html_token_t fake_token = {0};
118 
119     fake_token.tag_id = LXB_TAG_HEAD;
120 
121     tree->status = lxb_html_tree_insertion_mode_before_head_head(tree,
122                                                                  &fake_token);
123     if (tree->status != LXB_STATUS_OK) {
124         return lxb_html_tree_process_abort(tree);
125     }
126 
127     tree->mode = lxb_html_tree_insertion_mode_in_head;
128 
129     return false;
130 }
131 
132 lxb_inline lxb_status_t
lxb_html_tree_insertion_mode_before_head_head(lxb_html_tree_t * tree,lxb_html_token_t * token)133 lxb_html_tree_insertion_mode_before_head_head(lxb_html_tree_t *tree,
134                                               lxb_html_token_t *token)
135 {
136     lxb_html_element_t *element;
137 
138     element = lxb_html_tree_insert_html_element(tree, token);
139     if (element == NULL) {
140         return LXB_STATUS_ERROR_MEMORY_ALLOCATION;
141     }
142 
143     tree->document->head = lxb_html_interface_head(element);
144 
145     return LXB_STATUS_OK;
146 }
147