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