1 /*
2 * Copyright (C) 2018 Alexander Borisov
3 *
4 * Author: Alexander Borisov <borisov@lexbor.com>
5 */
6
7 #include "lexbor/dom/interfaces/node.h"
8
9 #include "lexbor/html/tree/active_formatting.h"
10 #include "lexbor/html/tree/open_elements.h"
11 #include "lexbor/html/interfaces/element.h"
12
13
14 static lxb_html_element_t lxb_html_tree_active_formatting_marker_static;
15
16 static lxb_dom_node_t *lxb_html_tree_active_formatting_marker_node_static =
17 (lxb_dom_node_t *) &lxb_html_tree_active_formatting_marker_static;
18
19
20 lxb_html_element_t *
lxb_html_tree_active_formatting_marker(void)21 lxb_html_tree_active_formatting_marker(void)
22 {
23 return &lxb_html_tree_active_formatting_marker_static;
24 }
25
26 void
lxb_html_tree_active_formatting_up_to_last_marker(lxb_html_tree_t * tree)27 lxb_html_tree_active_formatting_up_to_last_marker(lxb_html_tree_t *tree)
28 {
29 void **list = tree->active_formatting->list;
30
31 while (tree->active_formatting->length != 0) {
32 tree->active_formatting->length--;
33
34 if (list[tree->active_formatting->length]
35 == &lxb_html_tree_active_formatting_marker_static)
36 {
37 break;
38 }
39 }
40 }
41
42 void
lxb_html_tree_active_formatting_remove_by_node(lxb_html_tree_t * tree,lxb_dom_node_t * node)43 lxb_html_tree_active_formatting_remove_by_node(lxb_html_tree_t *tree,
44 lxb_dom_node_t *node)
45 {
46 size_t delta;
47 void **list = tree->active_formatting->list;
48 size_t idx = tree->active_formatting->length;
49
50 while (idx != 0) {
51 idx--;
52
53 if (list[idx] == node) {
54 delta = tree->active_formatting->length - idx - 1;
55
56 memmove(list + idx, list + idx + 1, sizeof(void *) * delta);
57
58 tree->active_formatting->length--;
59
60 break;
61 }
62 }
63 }
64
65 bool
lxb_html_tree_active_formatting_find_by_node(lxb_html_tree_t * tree,lxb_dom_node_t * node,size_t * return_pos)66 lxb_html_tree_active_formatting_find_by_node(lxb_html_tree_t *tree,
67 lxb_dom_node_t *node,
68 size_t *return_pos)
69 {
70 void **list = tree->active_formatting->list;
71
72 for (size_t i = 0; i < tree->active_formatting->length; i++) {
73 if (list[i] == node) {
74 if (return_pos) {
75 *return_pos = i;
76 }
77
78 return true;
79 }
80 }
81
82 if (return_pos) {
83 *return_pos = 0;
84 }
85
86 return false;
87 }
88
89 bool
lxb_html_tree_active_formatting_find_by_node_reverse(lxb_html_tree_t * tree,lxb_dom_node_t * node,size_t * return_pos)90 lxb_html_tree_active_formatting_find_by_node_reverse(lxb_html_tree_t *tree,
91 lxb_dom_node_t *node,
92 size_t *return_pos)
93 {
94 void **list = tree->active_formatting->list;
95 size_t len = tree->active_formatting->length;
96
97 while (len != 0) {
98 len--;
99
100 if (list[len] == node) {
101 if (return_pos) {
102 *return_pos = len;
103 }
104
105 return true;
106 }
107 }
108
109 if (return_pos) {
110 *return_pos = 0;
111 }
112
113 return false;
114 }
115
116 lxb_status_t
lxb_html_tree_active_formatting_reconstruct_elements(lxb_html_tree_t * tree)117 lxb_html_tree_active_formatting_reconstruct_elements(lxb_html_tree_t *tree)
118 {
119 /* Step 1 */
120 if (tree->active_formatting->length == 0) {
121 return LXB_STATUS_OK;
122 }
123
124 lexbor_array_t *af = tree->active_formatting;
125 void **list = af->list;
126
127 /* Step 2-3 */
128 size_t af_idx = af->length - 1;
129
130 if(list[af_idx] == &lxb_html_tree_active_formatting_marker_static
131 || lxb_html_tree_open_elements_find_by_node_reverse(tree, list[af_idx],
132 NULL))
133 {
134 return LXB_STATUS_OK;
135 }
136
137 /*
138 * Step 4-6
139 * Rewind
140 */
141 while (af_idx != 0) {
142 af_idx--;
143
144 if(list[af_idx] == &lxb_html_tree_active_formatting_marker_static ||
145 lxb_html_tree_open_elements_find_by_node_reverse(tree, list[af_idx],
146 NULL))
147 {
148 /* Step 7 */
149 af_idx++;
150
151 break;
152 }
153 }
154
155 /*
156 * Step 8-10
157 * Create
158 */
159 lxb_dom_node_t *node;
160 lxb_html_element_t *element;
161 lxb_html_token_t fake_token = {0};
162
163 while (af_idx < af->length) {
164 node = list[af_idx];
165
166 fake_token.tag_id = node->local_name;
167 fake_token.base_element = node;
168
169 element = lxb_html_tree_insert_html_element(tree, &fake_token);
170 if (element == NULL) {
171 return LXB_STATUS_ERROR_MEMORY_ALLOCATION;
172 }
173
174 /* Step 9 */
175 list[af_idx] = lxb_dom_interface_node(element);
176
177 /* Step 10 */
178 af_idx++;
179 }
180
181 return LXB_STATUS_OK;
182 }
183
184 lxb_dom_node_t *
lxb_html_tree_active_formatting_between_last_marker(lxb_html_tree_t * tree,lxb_tag_id_t tag_idx,size_t * return_idx)185 lxb_html_tree_active_formatting_between_last_marker(lxb_html_tree_t *tree,
186 lxb_tag_id_t tag_idx,
187 size_t *return_idx)
188 {
189 lxb_dom_node_t **list = (lxb_dom_node_t **) tree->active_formatting->list;
190 size_t idx = tree->active_formatting->length;
191
192 while (idx) {
193 idx--;
194
195 if (list[idx] == lxb_html_tree_active_formatting_marker_node_static) {
196 return NULL;
197 }
198
199 if (list[idx]->local_name == tag_idx && list[idx]->ns == LXB_NS_HTML) {
200 if (return_idx) {
201 *return_idx = idx;
202 }
203
204 return list[idx];
205 }
206 }
207
208 return NULL;
209 }
210
211 void
lxb_html_tree_active_formatting_push_with_check_dupl(lxb_html_tree_t * tree,lxb_dom_node_t * node)212 lxb_html_tree_active_formatting_push_with_check_dupl(lxb_html_tree_t *tree,
213 lxb_dom_node_t *node)
214 {
215 lxb_dom_node_t **list = (lxb_dom_node_t **) tree->active_formatting->list;
216 size_t idx = tree->active_formatting->length;
217 size_t earliest_idx = (idx ? (idx - 1) : 0);
218 size_t count = 0;
219
220 while (idx) {
221 idx--;
222
223 if (list[idx] == lxb_html_tree_active_formatting_marker_node_static) {
224 break;
225 }
226
227 if(list[idx]->local_name == node->local_name && list[idx]->ns == node->ns
228 && lxb_dom_element_compare(lxb_dom_interface_element(list[idx]),
229 lxb_dom_interface_element(node)))
230 {
231 count++;
232 earliest_idx = idx;
233 }
234 }
235
236 if(count >= 3) {
237 lxb_html_tree_active_formatting_remove(tree, earliest_idx);
238 }
239
240 lxb_html_tree_active_formatting_push(tree, node);
241 }
242