1 /*
2 Copyright (C) 2016-2017 Alexander Borisov
3
4 This library is free software; you can redistribute it and/or
5 modify it under the terms of the GNU Lesser General Public
6 License as published by the Free Software Foundation; either
7 version 2.1 of the License, or (at your option) any later version.
8
9 This library is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 Lesser General Public License for more details.
13
14 You should have received a copy of the GNU Lesser General Public
15 License along with this library; if not, write to the Free Software
16 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
17
18 Author: lex.borisov@gmail.com (Alexander Borisov)
19 */
20
21 #include "modest/finder/finder.h"
22 #include "modest/finder/resource.h"
23
modest_finder_create(void)24 modest_finder_t * modest_finder_create(void)
25 {
26 return (modest_finder_t*)mycore_calloc(1, sizeof(modest_finder_t));
27 }
28
modest_finder_init(modest_finder_t * finder)29 mystatus_t modest_finder_init(modest_finder_t* finder)
30 {
31 return MODEST_STATUS_OK;
32 }
33
modest_finder_clean(modest_finder_t * finder)34 void modest_finder_clean(modest_finder_t* finder)
35 {
36
37 }
38
modest_finder_destroy(modest_finder_t * finder,bool self_destroy)39 modest_finder_t * modest_finder_destroy(modest_finder_t* finder, bool self_destroy)
40 {
41 if(finder == NULL)
42 return NULL;
43
44 if(self_destroy) {
45 mycore_free(finder);
46 return NULL;
47 }
48
49 return finder;
50 }
51
modest_finder_create_simple(void)52 modest_finder_t * modest_finder_create_simple(void)
53 {
54 modest_finder_t *finder = modest_finder_create();
55
56 if(finder == NULL)
57 return NULL;
58
59 if(modest_finder_init(finder) != MODEST_STATUS_OK)
60 return modest_finder_destroy(finder, true);
61
62 return finder;
63 }
64
modest_finder_callback_found_with_collection(modest_finder_t * finder,myhtml_tree_node_t * node,mycss_selectors_list_t * selector_list,mycss_selectors_entry_t * selector,mycss_selectors_specificity_t * spec,void * ctx)65 void modest_finder_callback_found_with_collection(modest_finder_t* finder, myhtml_tree_node_t* node, mycss_selectors_list_t* selector_list, mycss_selectors_entry_t* selector, mycss_selectors_specificity_t* spec, void* ctx)
66 {
67 myhtml_collection_t* collection = (myhtml_collection_t*)ctx;
68
69 if(myhtml_collection_check_size(collection, 1, 1024) == MyHTML_STATUS_OK) {
70 collection->list[ collection->length ] = node;
71 collection->length++;
72 }
73 }
74
modest_finder_callback_found_with_bool(modest_finder_t * finder,myhtml_tree_node_t * node,mycss_selectors_list_t * selector_list,mycss_selectors_entry_t * selector,mycss_selectors_specificity_t * spec,void * ctx)75 void modest_finder_callback_found_with_bool(modest_finder_t* finder, myhtml_tree_node_t* node, mycss_selectors_list_t* selector_list, mycss_selectors_entry_t* selector, mycss_selectors_specificity_t* spec, void* ctx)
76 {
77 bool *is = (bool*)ctx;
78
79 if(*is == false)
80 *is = true;
81 }
82
modest_finder_specificity_inc(mycss_selectors_entry_t * selector,mycss_selectors_specificity_t * spec)83 void modest_finder_specificity_inc(mycss_selectors_entry_t* selector, mycss_selectors_specificity_t* spec)
84 {
85 switch (selector->type) {
86 case MyCSS_SELECTORS_TYPE_ID:
87 spec->a++;
88 break;
89
90 case MyCSS_SELECTORS_TYPE_CLASS:
91 case MyCSS_SELECTORS_TYPE_ATTRIBUTE:
92 case MyCSS_SELECTORS_TYPE_PSEUDO_CLASS_FUNCTION:
93 case MyCSS_SELECTORS_TYPE_PSEUDO_CLASS:
94 spec->b++;
95 break;
96
97 case MyCSS_SELECTORS_TYPE_ELEMENT:
98 case MyCSS_SELECTORS_TYPE_PSEUDO_ELEMENT_FUNCTION:
99 case MyCSS_SELECTORS_TYPE_PSEUDO_ELEMENT:
100 spec->c++;
101 break;
102 default:
103 break;
104 }
105 }
106
modest_finder_by_stylesheet(mycss_stylesheet_t * stylesheet,myhtml_collection_t ** collection,myhtml_tree_node_t * base_node)107 modest_finder_t * modest_finder_by_stylesheet(mycss_stylesheet_t *stylesheet, myhtml_collection_t** collection, myhtml_tree_node_t* base_node)
108 {
109 if(collection == NULL || base_node == NULL || stylesheet == NULL)
110 return NULL;
111
112 modest_finder_t *finder = modest_finder_create();
113
114 if(finder == NULL)
115 return NULL;
116
117 mystatus_t status = modest_finder_init(finder);
118
119 if(status != MODEST_STATUS_OK) {
120 modest_finder_destroy(finder, true);
121 return NULL;
122 }
123
124 if(*collection == NULL) {
125 mystatus_t status;
126 *collection = myhtml_collection_create(4096, &status);
127
128 if(status) {
129 modest_finder_destroy(finder, true);
130 return NULL;
131 }
132 }
133 else
134 myhtml_collection_clean(*collection);
135
136 mycss_selectors_list_t *selector_list = stylesheet->sel_list_first;
137
138 while(selector_list) {
139 for(size_t i = 0; i < selector_list->entries_list_length; i++) {
140 mycss_selectors_specificity_t spec = selector_list->entries_list[i].specificity;
141
142 modest_finder_node_combinator_begin(finder, base_node, selector_list, selector_list->entries_list[i].entry, &spec, modest_finder_callback_found_with_collection, *collection);
143 }
144
145 selector_list = selector_list->next;
146 }
147
148 return finder;
149 }
150
modest_finder_by_selectors_list(modest_finder_t * finder,myhtml_tree_node_t * scope_node,mycss_selectors_list_t * selector_list,myhtml_collection_t ** collection)151 mystatus_t modest_finder_by_selectors_list(modest_finder_t* finder, myhtml_tree_node_t* scope_node,
152 mycss_selectors_list_t* selector_list, myhtml_collection_t** collection)
153 {
154 if(finder == NULL || selector_list == NULL || scope_node == NULL || collection == NULL)
155 return MODEST_STATUS_ERROR;
156
157 if(*collection == NULL) {
158 mystatus_t status;
159 *collection = myhtml_collection_create(4096, &status);
160
161 if(status)
162 return MODEST_STATUS_ERROR_MEMORY_ALLOCATION;
163 }
164
165 for(size_t i = 0; i < selector_list->entries_list_length; i++) {
166 mycss_selectors_specificity_t spec = selector_list->entries_list[i].specificity;
167
168 modest_finder_node_combinator_begin(finder, scope_node, selector_list, selector_list->entries_list[i].entry, &spec,
169 modest_finder_callback_found_with_collection, *collection);
170 }
171
172 return MODEST_STATUS_OK;
173 }
174
modest_finder_node_combinator_begin(modest_finder_t * finder,myhtml_tree_node_t * base_node,mycss_selectors_list_t * selector_list,mycss_selectors_entry_t * selector,mycss_selectors_specificity_t * spec,modest_finder_callback_f callback_found,void * ctx)175 myhtml_tree_node_t * modest_finder_node_combinator_begin(modest_finder_t* finder, myhtml_tree_node_t* base_node,
176 mycss_selectors_list_t* selector_list, mycss_selectors_entry_t* selector,
177 mycss_selectors_specificity_t* spec, modest_finder_callback_f callback_found, void* ctx)
178 {
179 if(selector == NULL)
180 return NULL;
181
182
183 myhtml_tree_node_t *node = base_node;
184
185 while(node) {
186 if(node->tag_id != MyHTML_TAG__TEXT && node->tag_id != MyHTML_TAG__COMMENT &&
187 modest_finder_static_selector_type_map[selector->type](finder, node, selector, spec))
188 {
189 if(selector->next == NULL) {
190 if(callback_found)
191 callback_found(finder, node, selector_list, selector, spec, ctx);
192 }
193 else {
194 myhtml_tree_node_t *find_node = modest_finder_static_selector_combinator_map[selector->next->combinator](finder, node, selector_list, selector->next, spec, callback_found, ctx);
195
196 if(find_node == NULL) {
197 while(node != base_node && node->next == NULL)
198 node = node->parent;
199
200 if(node == base_node)
201 break;
202
203 node = node->next;
204 continue;
205 }
206 }
207 }
208
209 if(node->child)
210 node = node->child;
211 else {
212 while(node != base_node && node->next == NULL)
213 node = node->parent;
214
215 if(node == base_node)
216 break;
217
218 node = node->next;
219 }
220 }
221
222 return NULL;
223 }
224
225 /* some */
modest_finder_node_combinator_undef(modest_finder_t * finder,myhtml_tree_node_t * base_node,mycss_selectors_list_t * selector_list,mycss_selectors_entry_t * selector,mycss_selectors_specificity_t * spec,modest_finder_callback_f callback_found,void * ctx)226 myhtml_tree_node_t * modest_finder_node_combinator_undef(modest_finder_t* finder, myhtml_tree_node_t* base_node,
227 mycss_selectors_list_t* selector_list, mycss_selectors_entry_t* selector,
228 mycss_selectors_specificity_t* spec, modest_finder_callback_f callback_found, void* ctx)
229 {
230 if(selector == NULL)
231 return NULL;
232
233 mycss_selectors_specificity_t match_spec = *spec;
234
235 if(base_node->tag_id != MyHTML_TAG__TEXT && base_node->tag_id != MyHTML_TAG__COMMENT &&
236 modest_finder_static_selector_type_map[selector->type](finder, base_node, selector, &match_spec)) {
237 if(selector->next == NULL) {
238 if(callback_found)
239 callback_found(finder, base_node, selector_list, selector, &match_spec, ctx);
240 }
241 else {
242 modest_finder_static_selector_combinator_map[selector->next->combinator](finder, base_node, selector_list, selector->next, &match_spec, callback_found, ctx);
243 }
244 }
245
246 return base_node;
247 }
248
249 /* E F or E >> F */
modest_finder_node_combinator_descendant(modest_finder_t * finder,myhtml_tree_node_t * base_node,mycss_selectors_list_t * selector_list,mycss_selectors_entry_t * selector,mycss_selectors_specificity_t * spec,modest_finder_callback_f callback_found,void * ctx)250 myhtml_tree_node_t * modest_finder_node_combinator_descendant(modest_finder_t* finder, myhtml_tree_node_t* base_node,
251 mycss_selectors_list_t* selector_list, mycss_selectors_entry_t* selector,
252 mycss_selectors_specificity_t* spec, modest_finder_callback_f callback_found, void* ctx)
253 {
254 if(selector == NULL)
255 return NULL;
256
257 myhtml_tree_node_t *node = base_node->child;
258
259 while(node) {
260 mycss_selectors_specificity_t match_spec = *spec;
261
262 if(node->tag_id != MyHTML_TAG__TEXT && node->tag_id != MyHTML_TAG__COMMENT &&
263 modest_finder_static_selector_type_map[selector->type](finder, node, selector, &match_spec))
264 {
265 if(selector->next == NULL) {
266 if(callback_found)
267 callback_found(finder, node, selector_list, selector, &match_spec, ctx);
268 }
269 else {
270 myhtml_tree_node_t *find_node = modest_finder_static_selector_combinator_map[selector->next->combinator](finder, node, selector_list, selector->next, &match_spec, callback_found, ctx);
271
272 if(find_node == NULL) {
273 while(node != base_node && node->next == NULL)
274 node = node->parent;
275
276 if(node == base_node)
277 break;
278
279 node = node->next;
280 continue;
281 }
282 }
283 }
284
285 if(node->child)
286 node = node->child;
287 else {
288 while(node != base_node && node->next == NULL)
289 node = node->parent;
290
291 if(node == base_node)
292 break;
293
294 node = node->next;
295 }
296 }
297
298 return NULL;
299 }
300
301 /* E > F */
modest_finder_node_combinator_child(modest_finder_t * finder,myhtml_tree_node_t * base_node,mycss_selectors_list_t * selector_list,mycss_selectors_entry_t * selector,mycss_selectors_specificity_t * spec,modest_finder_callback_f callback_found,void * ctx)302 myhtml_tree_node_t * modest_finder_node_combinator_child(modest_finder_t* finder, myhtml_tree_node_t* base_node,
303 mycss_selectors_list_t* selector_list, mycss_selectors_entry_t* selector,
304 mycss_selectors_specificity_t* spec, modest_finder_callback_f callback_found, void* ctx)
305 {
306 if(selector == NULL)
307 return NULL;
308
309 myhtml_tree_node_t *node = base_node->child;
310
311 while(node) {
312 mycss_selectors_specificity_t match_spec = *spec;
313
314 if(node->tag_id != MyHTML_TAG__TEXT && node->tag_id != MyHTML_TAG__COMMENT &&
315 modest_finder_static_selector_type_map[selector->type](finder, node, selector, &match_spec))
316 {
317 if(selector->next == NULL) {
318 if(callback_found)
319 callback_found(finder, node, selector_list ,selector, &match_spec, ctx);
320 }
321 else {
322 modest_finder_static_selector_combinator_map[selector->next->combinator](finder, node, selector_list, selector->next, &match_spec, callback_found, ctx);
323 }
324 }
325
326 node = node->next;
327 }
328
329 return base_node;
330 }
331
332 /* E + F */
modest_finder_node_combinator_next_sibling(modest_finder_t * finder,myhtml_tree_node_t * base_node,mycss_selectors_list_t * selector_list,mycss_selectors_entry_t * selector,mycss_selectors_specificity_t * spec,modest_finder_callback_f callback_found,void * ctx)333 myhtml_tree_node_t * modest_finder_node_combinator_next_sibling(modest_finder_t* finder, myhtml_tree_node_t* base_node,
334 mycss_selectors_list_t* selector_list, mycss_selectors_entry_t* selector,
335 mycss_selectors_specificity_t* spec, modest_finder_callback_f callback_found, void* ctx)
336 {
337 if(selector == NULL)
338 return NULL;
339
340 myhtml_tree_node_t *node = base_node->next;
341
342 while(node) {
343 if(node->tag_id != MyHTML_TAG__TEXT && node->tag_id != MyHTML_TAG__COMMENT)
344 {
345 mycss_selectors_specificity_t match_spec = *spec;
346
347 if(modest_finder_static_selector_type_map[selector->type](finder, node, selector, &match_spec)) {
348 if(selector->next == NULL) {
349 if(callback_found)
350 callback_found(finder, node, selector_list, selector, &match_spec, ctx);
351 }
352 else {
353 modest_finder_static_selector_combinator_map[selector->next->combinator](finder, node, selector_list, selector->next, &match_spec, callback_found, ctx);
354 }
355 }
356
357 break;
358 }
359
360 node = node->next;
361 }
362
363 return base_node;
364 }
365
366 /* E ~ F */
modest_finder_node_combinator_following_sibling(modest_finder_t * finder,myhtml_tree_node_t * base_node,mycss_selectors_list_t * selector_list,mycss_selectors_entry_t * selector,mycss_selectors_specificity_t * spec,modest_finder_callback_f callback_found,void * ctx)367 myhtml_tree_node_t * modest_finder_node_combinator_following_sibling(modest_finder_t* finder, myhtml_tree_node_t* base_node,
368 mycss_selectors_list_t* selector_list, mycss_selectors_entry_t* selector,
369 mycss_selectors_specificity_t* spec, modest_finder_callback_f callback_found, void* ctx)
370 {
371 if(selector == NULL)
372 return NULL;
373
374 myhtml_tree_node_t *node = base_node->next;
375
376 while(node) {
377 mycss_selectors_specificity_t match_spec = *spec;
378
379 if(node->tag_id != MyHTML_TAG__TEXT && node->tag_id != MyHTML_TAG__COMMENT &&
380 modest_finder_static_selector_type_map[selector->type](finder, node, selector, &match_spec))
381 {
382 if(selector->next == NULL) {
383 if(callback_found)
384 callback_found(finder, node, selector_list, selector, &match_spec, ctx);
385 }
386 else {
387 modest_finder_static_selector_combinator_map[selector->next->combinator](finder, node, selector_list, selector->next, &match_spec, callback_found, ctx);
388 }
389 }
390
391 node = node->next;
392 }
393
394 return base_node;
395 }
396
397 /* E || F */
modest_finder_node_combinator_column(modest_finder_t * finder,myhtml_tree_node_t * base_node,mycss_selectors_list_t * selector_list,mycss_selectors_entry_t * selector,mycss_selectors_specificity_t * spec,modest_finder_callback_f callback_found,void * ctx)398 myhtml_tree_node_t * modest_finder_node_combinator_column(modest_finder_t* finder, myhtml_tree_node_t* base_node,
399 mycss_selectors_list_t* selector_list, mycss_selectors_entry_t* selector,
400 mycss_selectors_specificity_t* spec, modest_finder_callback_f callback_found, void* ctx)
401 {
402 if(selector == NULL)
403 return NULL;
404
405 return base_node;
406 }
407
408
409