00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024 #include <string.h>
00025 #include "cr-sel-eng.h"
00026
00027
00028
00029
00030
00031
00032
00033
00034
00035 #define PRIVATE(a_this) (a_this)->priv
00036
00037 struct CRPseudoClassSelHandlerEntry {
00038 guchar *name;
00039 enum CRPseudoType type;
00040 CRPseudoClassSelectorHandler handler;
00041 };
00042
00043 struct _CRSelEngPriv {
00044
00045 gboolean case_sensitive;
00046
00047 CRStyleSheet *sheet;
00048
00049
00050
00051
00052
00053 CRStatement *cur_stmt;
00054 GList *pcs_handlers;
00055 gint pcs_handlers_size;
00056 } ;
00057
00058 static gboolean class_add_sel_matches_node (CRAdditionalSel * a_add_sel,
00059 xmlNode * a_node);
00060
00061 static gboolean id_add_sel_matches_node (CRAdditionalSel * a_add_sel,
00062 xmlNode * a_node);
00063
00064 static gboolean attr_add_sel_matches_node (CRAdditionalSel * a_add_sel,
00065 xmlNode * a_node);
00066
00067 static enum CRStatus sel_matches_node_real (CRSelEng * a_this,
00068 CRSimpleSel * a_sel,
00069 xmlNode * a_node,
00070 gboolean * a_result,
00071 gboolean a_eval_sel_list_from_end,
00072 gboolean a_recurse);
00073
00074 static enum CRStatus cr_sel_eng_get_matched_rulesets_real (CRSelEng * a_this,
00075 CRStyleSheet *
00076 a_stylesheet,
00077 xmlNode * a_node,
00078 CRStatement **
00079 a_rulesets,
00080 gulong * a_len);
00081
00082 static enum CRStatus put_css_properties_in_props_list (CRPropList ** a_props,
00083 CRStatement *
00084 a_ruleset);
00085
00086 static gboolean pseudo_class_add_sel_matches_node (CRSelEng * a_this,
00087 CRAdditionalSel *
00088 a_add_sel,
00089 xmlNode * a_node);
00090
00091 static gboolean lang_pseudo_class_handler (CRSelEng * a_this,
00092 CRAdditionalSel * a_sel,
00093 xmlNode * a_node);
00094
00095 static gboolean first_child_pseudo_class_handler (CRSelEng * a_this,
00096 CRAdditionalSel * a_sel,
00097 xmlNode * a_node);
00098
00099 static xmlNode *get_next_element_node (xmlNode * a_node);
00100
00101 static xmlNode *get_next_child_element_node (xmlNode * a_node);
00102
00103 static xmlNode *get_prev_element_node (xmlNode * a_node);
00104
00105 static xmlNode *get_next_parent_element_node (xmlNode * a_node);
00106
00107 static gboolean
00108 lang_pseudo_class_handler (CRSelEng * a_this,
00109 CRAdditionalSel * a_sel, xmlNode * a_node)
00110 {
00111 xmlNode *node = a_node;
00112 xmlChar *val = NULL;
00113 gboolean result = FALSE;
00114
00115 g_return_val_if_fail (a_this && PRIVATE (a_this)
00116 && a_sel && a_sel->content.pseudo
00117 && a_sel->content.pseudo
00118 && a_sel->content.pseudo->name
00119 && a_sel->content.pseudo->name->stryng
00120 && a_node, CR_BAD_PARAM_ERROR);
00121
00122 if (strncmp (a_sel->content.pseudo->name->stryng->str,
00123 "lang", 4)
00124 || !a_sel->content.pseudo->type == FUNCTION_PSEUDO) {
00125 cr_utils_trace_info ("This handler is for :lang only");
00126 return CR_BAD_PSEUDO_CLASS_SEL_HANDLER_ERROR;
00127 }
00128
00129 if (!a_sel->content.pseudo->extra
00130 || !a_sel->content.pseudo->extra->stryng
00131 || a_sel->content.pseudo->extra->stryng->len < 2)
00132 return FALSE;
00133 for (; node; node = get_next_parent_element_node (node)) {
00134 val = xmlGetProp (node, "lang");
00135 if (val
00136 && !strncmp (val,
00137 a_sel->content.pseudo->extra->stryng->str,
00138 a_sel->content.pseudo->extra->stryng->len)) {
00139 result = TRUE;
00140 }
00141 if (val) {
00142 xmlFree (val);
00143 val = NULL;
00144 }
00145 }
00146
00147 return result;
00148 }
00149
00150 static gboolean
00151 first_child_pseudo_class_handler (CRSelEng * a_this,
00152 CRAdditionalSel * a_sel, xmlNode * a_node)
00153 {
00154 xmlNode *node = NULL;
00155
00156 g_return_val_if_fail (a_this && PRIVATE (a_this)
00157 && a_sel && a_sel->content.pseudo
00158 && a_sel->content.pseudo
00159 && a_sel->content.pseudo->name
00160 && a_sel->content.pseudo->name->stryng
00161 && a_node, CR_BAD_PARAM_ERROR);
00162
00163 if (strcmp (a_sel->content.pseudo->name->stryng->str,
00164 "first-child")
00165 || !a_sel->content.pseudo->type == IDENT_PSEUDO) {
00166 cr_utils_trace_info ("This handler is for :first-child only");
00167 return CR_BAD_PSEUDO_CLASS_SEL_HANDLER_ERROR;
00168 }
00169 if (!a_node->parent)
00170 return FALSE;
00171 node = get_next_child_element_node (a_node->parent);
00172 if (node == a_node)
00173 return TRUE;
00174 return FALSE;
00175 }
00176
00177 static gboolean
00178 pseudo_class_add_sel_matches_node (CRSelEng * a_this,
00179 CRAdditionalSel * a_add_sel,
00180 xmlNode * a_node)
00181 {
00182 enum CRStatus status = CR_OK;
00183 CRPseudoClassSelectorHandler handler = NULL;
00184
00185 g_return_val_if_fail (a_this && PRIVATE (a_this)
00186 && a_add_sel
00187 && a_add_sel->content.pseudo
00188 && a_add_sel->content.pseudo->name
00189 && a_add_sel->content.pseudo->name->stryng
00190 && a_add_sel->content.pseudo->name->stryng->str
00191 && a_node, CR_BAD_PARAM_ERROR);
00192
00193 status = cr_sel_eng_get_pseudo_class_selector_handler
00194 (a_this, a_add_sel->content.pseudo->name->stryng->str,
00195 a_add_sel->content.pseudo->type, &handler);
00196 if (status != CR_OK || !handler)
00197 return FALSE;
00198
00199 return handler (a_this, a_add_sel, a_node);
00200 }
00201
00202
00203
00204
00205
00206
00207
00208 static gboolean
00209 class_add_sel_matches_node (CRAdditionalSel * a_add_sel, xmlNode * a_node)
00210 {
00211 gboolean result = FALSE;
00212 xmlChar *klass = NULL,
00213 *cur = NULL;
00214
00215 g_return_val_if_fail (a_add_sel
00216 && a_add_sel->type == CLASS_ADD_SELECTOR
00217 && a_add_sel->content.class_name
00218 && a_add_sel->content.class_name->stryng
00219 && a_add_sel->content.class_name->stryng->str
00220 && a_node, FALSE);
00221
00222 if (xmlHasProp (a_node, "class")) {
00223 klass = xmlGetProp (a_node, "class");
00224 for (cur = klass; cur && *cur; cur++) {
00225 while (cur && *cur
00226 && cr_utils_is_white_space (*cur)
00227 == TRUE)
00228 cur++;
00229
00230 if (!strncmp (cur,
00231 a_add_sel->content.class_name->stryng->str,
00232 a_add_sel->content.class_name->stryng->len)) {
00233 cur += a_add_sel->content.class_name->stryng->len;
00234 if ((cur && !*cur)
00235 || cr_utils_is_white_space (*cur) == TRUE)
00236 result = TRUE;
00237 }
00238 if (cur && !*cur)
00239 break ;
00240 }
00241 }
00242 if (klass) {
00243 xmlFree (klass);
00244 klass = NULL;
00245 }
00246 return result;
00247
00248 }
00249
00250
00251
00252
00253
00254
00255
00256 static gboolean
00257 id_add_sel_matches_node (CRAdditionalSel * a_add_sel, xmlNode * a_node)
00258 {
00259 gboolean result = FALSE;
00260 xmlChar *id = NULL;
00261
00262 g_return_val_if_fail (a_add_sel
00263 && a_add_sel->type == ID_ADD_SELECTOR
00264 && a_add_sel->content.id_name
00265 && a_add_sel->content.id_name->stryng
00266 && a_add_sel->content.id_name->stryng->str
00267 && a_node, FALSE);
00268 g_return_val_if_fail (a_add_sel
00269 && a_add_sel->type == ID_ADD_SELECTOR
00270 && a_node, FALSE);
00271
00272 if (xmlHasProp (a_node, "id")) {
00273 id = xmlGetProp (a_node, "id");
00274 if (!strncmp (id, a_add_sel->content.id_name->stryng->str,
00275 a_add_sel->content.id_name->stryng->len)) {
00276 result = TRUE;
00277 }
00278 }
00279 if (id) {
00280 xmlFree (id);
00281 id = NULL;
00282 }
00283 return result;
00284 }
00285
00286
00287
00288
00289
00290
00291
00292
00293
00294
00295 static gboolean
00296 attr_add_sel_matches_node (CRAdditionalSel * a_add_sel, xmlNode * a_node)
00297 {
00298 CRAttrSel *cur_sel = NULL;
00299
00300 g_return_val_if_fail (a_add_sel
00301 && a_add_sel->type == ATTRIBUTE_ADD_SELECTOR
00302 && a_node, FALSE);
00303
00304 for (cur_sel = a_add_sel->content.attr_sel;
00305 cur_sel; cur_sel = cur_sel->next) {
00306 switch (cur_sel->match_way) {
00307 case SET:
00308 if (!cur_sel->name
00309 || !cur_sel->name->stryng
00310 || !cur_sel->name->stryng->str)
00311 return FALSE;
00312
00313 if (!xmlHasProp (a_node,
00314 cur_sel->name->stryng->str))
00315 return FALSE;
00316 break;
00317
00318 case EQUALS:
00319 {
00320 xmlChar *value = NULL;
00321
00322 if (!cur_sel->name
00323 || !cur_sel->name->stryng
00324 || !cur_sel->name->stryng->str
00325 || !cur_sel->value
00326 || !cur_sel->value->stryng
00327 || !cur_sel->value->stryng->str)
00328 return FALSE;
00329
00330 if (!xmlHasProp
00331 (a_node,
00332 cur_sel->name->stryng->str))
00333 return FALSE;
00334
00335 value = xmlGetProp
00336 (a_node,
00337 cur_sel->name->stryng->str);
00338
00339 if (value
00340 && strcmp
00341 (value,
00342 cur_sel->value->stryng->str)) {
00343 xmlFree (value);
00344 return FALSE;
00345 }
00346 xmlFree (value);
00347 }
00348 break;
00349
00350 case INCLUDES:
00351 {
00352 xmlChar *value = NULL,
00353 *ptr1 = NULL,
00354 *ptr2 = NULL,
00355 *cur = NULL;
00356 gboolean found = FALSE;
00357
00358 if (!xmlHasProp
00359 (a_node,
00360 cur_sel->name->stryng->str))
00361 return FALSE;
00362 value = xmlGetProp
00363 (a_node,
00364 cur_sel->name->stryng->str);
00365
00366 if (!value)
00367 return FALSE;
00368
00369
00370
00371
00372
00373
00374 for (cur = value; *cur; cur++) {
00375
00376
00377
00378
00379 while (cr_utils_is_white_space
00380 (*cur) == TRUE && *cur)
00381 cur++;
00382 if (!*cur)
00383 break;
00384 ptr1 = cur;
00385
00386
00387
00388
00389 while (cr_utils_is_white_space
00390 (*cur) == FALSE && *cur)
00391 cur++;
00392 cur--;
00393 ptr2 = cur;
00394
00395 if (!strncmp
00396 (ptr1,
00397 cur_sel->value->stryng->str,
00398 ptr2 - ptr1 + 1)) {
00399 found = TRUE;
00400 break;
00401 }
00402 ptr1 = ptr2 = NULL;
00403 }
00404
00405 if (found == FALSE) {
00406 xmlFree (value);
00407 return FALSE;
00408 }
00409 xmlFree (value);
00410 }
00411 break;
00412
00413 case DASHMATCH:
00414 {
00415 xmlChar *value = NULL,
00416 *ptr1 = NULL,
00417 *ptr2 = NULL,
00418 *cur = NULL;
00419 gboolean found = FALSE;
00420
00421 if (!xmlHasProp
00422 (a_node,
00423 cur_sel->name->stryng->str))
00424 return FALSE;
00425 value = xmlGetProp
00426 (a_node,
00427 cur_sel->name->stryng->str);
00428
00429
00430
00431
00432
00433
00434 for (cur = value; *cur; cur++) {
00435 if (*cur == '-')
00436 cur++;
00437 ptr1 = cur;
00438
00439 while (*cur != '-' && *cur)
00440 cur++;
00441 cur--;
00442 ptr2 = cur;
00443
00444 if (g_strstr_len
00445 (ptr1, ptr2 - ptr1 + 1,
00446 cur_sel->value->stryng->str)
00447 == (gchar *) ptr1) {
00448 found = TRUE;
00449 break;
00450 }
00451 }
00452
00453 if (found == FALSE) {
00454 xmlFree (value);
00455 return FALSE;
00456 }
00457 xmlFree (value);
00458 }
00459 break;
00460 default:
00461 return FALSE;
00462 }
00463 }
00464
00465 return TRUE;
00466 }
00467
00468
00469
00470
00471
00472
00473
00474 static gboolean
00475 additional_selector_matches_node (CRSelEng * a_this,
00476 CRAdditionalSel * a_add_sel,
00477 xmlNode * a_node)
00478 {
00479 CRAdditionalSel *cur_add_sel = NULL, *tail = NULL ;
00480 gboolean evaluated = FALSE ;
00481
00482 for (tail = a_add_sel ;
00483 tail && tail->next;
00484 tail = tail->next) ;
00485
00486 g_return_val_if_fail (tail, FALSE) ;
00487
00488 for (cur_add_sel = tail ;
00489 cur_add_sel ;
00490 cur_add_sel = cur_add_sel->prev) {
00491
00492 evaluated = TRUE ;
00493 if (cur_add_sel->type == NO_ADD_SELECTOR) {
00494 return FALSE;
00495 }
00496
00497 if (cur_add_sel->type == CLASS_ADD_SELECTOR
00498 && cur_add_sel->content.class_name
00499 && cur_add_sel->content.class_name->stryng
00500 && cur_add_sel->content.class_name->stryng->str) {
00501 if (class_add_sel_matches_node (cur_add_sel,
00502 a_node) == FALSE) {
00503 return FALSE;
00504 }
00505 continue ;
00506 } else if (cur_add_sel->type == ID_ADD_SELECTOR
00507 && cur_add_sel->content.id_name
00508 && cur_add_sel->content.id_name->stryng
00509 && cur_add_sel->content.id_name->stryng->str) {
00510 if (id_add_sel_matches_node (cur_add_sel, a_node) == FALSE) {
00511 return FALSE;
00512 }
00513 continue ;
00514 } else if (cur_add_sel->type == ATTRIBUTE_ADD_SELECTOR
00515 && cur_add_sel->content.attr_sel) {
00516
00517
00518
00519
00520
00521 if (attr_add_sel_matches_node (cur_add_sel, a_node)
00522 == FALSE) {
00523 return FALSE;
00524 }
00525 continue ;
00526 } else if (cur_add_sel->type == PSEUDO_CLASS_ADD_SELECTOR
00527 && cur_add_sel->content.pseudo) {
00528 if (pseudo_class_add_sel_matches_node
00529 (a_this, cur_add_sel, a_node) == TRUE) {
00530 return TRUE;
00531 }
00532 return FALSE;
00533 }
00534 }
00535 if (evaluated == TRUE)
00536 return TRUE;
00537 return FALSE ;
00538 }
00539
00540 static xmlNode *
00541 get_next_element_node (xmlNode * a_node)
00542 {
00543 xmlNode *cur_node = NULL;
00544
00545 g_return_val_if_fail (a_node, NULL);
00546
00547 cur_node = a_node->next;
00548 while (cur_node && cur_node->type != XML_ELEMENT_NODE) {
00549 cur_node = cur_node->next;
00550 }
00551 return cur_node;
00552 }
00553
00554 static xmlNode *
00555 get_next_child_element_node (xmlNode * a_node)
00556 {
00557 xmlNode *cur_node = NULL;
00558
00559 g_return_val_if_fail (a_node, NULL);
00560
00561 cur_node = a_node->children;
00562 if (!cur_node)
00563 return cur_node;
00564 if (a_node->children->type == XML_ELEMENT_NODE)
00565 return a_node->children;
00566 return get_next_element_node (a_node->children);
00567 }
00568
00569 static xmlNode *
00570 get_prev_element_node (xmlNode * a_node)
00571 {
00572 xmlNode *cur_node = NULL;
00573
00574 g_return_val_if_fail (a_node, NULL);
00575
00576 cur_node = a_node->prev;
00577 while (cur_node && cur_node->type != XML_ELEMENT_NODE) {
00578 cur_node = cur_node->prev;
00579 }
00580 return cur_node;
00581 }
00582
00583 static xmlNode *
00584 get_next_parent_element_node (xmlNode * a_node)
00585 {
00586 xmlNode *cur_node = NULL;
00587
00588 g_return_val_if_fail (a_node, NULL);
00589
00590 cur_node = a_node->parent;
00591 while (cur_node && cur_node->type != XML_ELEMENT_NODE) {
00592 cur_node = cur_node->parent;
00593 }
00594 return cur_node;
00595 }
00596
00597
00598
00599
00600
00601
00602
00603
00604
00605
00606
00607
00608
00609
00610
00611
00612
00613
00614
00615 static enum CRStatus
00616 sel_matches_node_real (CRSelEng * a_this, CRSimpleSel * a_sel,
00617 xmlNode * a_node, gboolean * a_result,
00618 gboolean a_eval_sel_list_from_end,
00619 gboolean a_recurse)
00620 {
00621 CRSimpleSel *cur_sel = NULL;
00622 xmlNode *cur_node = NULL;
00623
00624 g_return_val_if_fail (a_this && PRIVATE (a_this)
00625 && a_this && a_node
00626 && a_result, CR_BAD_PARAM_ERROR);
00627
00628 *a_result = FALSE;
00629
00630 if (a_node->type != XML_ELEMENT_NODE)
00631 return CR_OK;
00632
00633 if (a_eval_sel_list_from_end == TRUE) {
00634
00635 for (cur_sel = a_sel;
00636 cur_sel && cur_sel->next; cur_sel = cur_sel->next) ;
00637 } else {
00638 cur_sel = a_sel;
00639 }
00640
00641 for (cur_node = a_node; cur_sel; cur_sel = cur_sel->prev) {
00642 if (((cur_sel->type_mask & TYPE_SELECTOR)
00643 && (cur_sel->name
00644 && cur_sel->name->stryng
00645 && cur_sel->name->stryng->str)
00646 && (!strcmp (cur_sel->name->stryng->str,
00647 cur_node->name)))
00648 || (cur_sel->type_mask & UNIVERSAL_SELECTOR)) {
00649
00650
00651
00652
00653
00654
00655
00656 if (cur_sel->add_sel) {
00657 if (additional_selector_matches_node (a_this, cur_sel->add_sel,
00658 cur_node) == TRUE) {
00659 goto walk_a_step_in_expr;
00660 } else {
00661 goto done;
00662 }
00663 } else {
00664 goto walk_a_step_in_expr;
00665 }
00666 }
00667 if (!(cur_sel->type_mask & TYPE_SELECTOR)
00668 && !(cur_sel->type_mask & UNIVERSAL_SELECTOR)) {
00669 if (!cur_sel->add_sel) {
00670 goto done;
00671 }
00672 if (additional_selector_matches_node
00673 (a_this, cur_sel->add_sel, cur_node)
00674 == TRUE) {
00675 goto walk_a_step_in_expr;
00676 } else {
00677 goto done;
00678 }
00679 } else {
00680 goto done ;
00681 }
00682
00683 walk_a_step_in_expr:
00684 if (a_recurse == FALSE) {
00685 *a_result = TRUE;
00686 goto done;
00687 }
00688
00689
00690
00691
00692
00693
00694 if (!cur_sel->prev)
00695 break;
00696
00697 switch (cur_sel->combinator) {
00698 case NO_COMBINATOR:
00699 break;
00700
00701 case COMB_WS:
00702 {
00703 xmlNode *n = NULL;
00704 enum CRStatus status = CR_OK;
00705 gboolean matches = FALSE;
00706
00707
00708
00709
00710
00711 for (n = cur_node->parent; n; n = n->parent) {
00712 status = sel_matches_node_real
00713 (a_this, cur_sel->prev,
00714 n, &matches, FALSE, TRUE);
00715
00716 if (status != CR_OK)
00717 goto done;
00718
00719 if (matches == TRUE) {
00720 cur_node = n ;
00721 break;
00722 }
00723 }
00724
00725 if (!n) {
00726
00727
00728
00729
00730 goto done;
00731 }
00732
00733
00734
00735
00736
00737
00738
00739
00740 break;
00741 }
00742
00743 case COMB_PLUS:
00744 cur_node = get_prev_element_node (cur_node);
00745 if (!cur_node)
00746 goto done;
00747 break;
00748
00749 case COMB_GT:
00750 cur_node = get_next_parent_element_node (cur_node);
00751 if (!cur_node)
00752 goto done;
00753 break;
00754
00755 default:
00756 goto done;
00757 }
00758 continue;
00759 }
00760
00761
00762
00763
00764
00765 *a_result = TRUE;
00766
00767 done:
00768 return CR_OK;
00769 }
00770
00771
00772
00773
00774
00775
00776
00777
00778
00779
00780
00781
00782
00783
00784
00785
00786
00787
00788
00789
00790
00791
00792
00793
00794
00795
00796
00797
00798
00799
00800
00801
00802
00803
00804
00805
00806
00807
00808
00809 static enum CRStatus
00810 cr_sel_eng_get_matched_rulesets_real (CRSelEng * a_this,
00811 CRStyleSheet * a_stylesheet,
00812 xmlNode * a_node,
00813 CRStatement ** a_rulesets,
00814 gulong * a_len)
00815 {
00816 CRStatement *cur_stmt = NULL;
00817 CRSelector *sel_list = NULL,
00818 *cur_sel = NULL;
00819 gboolean matches = FALSE;
00820 enum CRStatus status = CR_OK;
00821 gulong i = 0;
00822
00823 g_return_val_if_fail (a_this
00824 && a_stylesheet
00825 && a_node && a_rulesets, CR_BAD_PARAM_ERROR);
00826
00827 if (!a_stylesheet->statements) {
00828 *a_rulesets = NULL;
00829 *a_len = 0;
00830 return CR_OK;
00831 }
00832
00833
00834
00835
00836
00837 if (PRIVATE (a_this)->sheet != a_stylesheet) {
00838 PRIVATE (a_this)->sheet = a_stylesheet;
00839 PRIVATE (a_this)->cur_stmt = a_stylesheet->statements;
00840 }
00841
00842
00843
00844
00845
00846
00847
00848 for (cur_stmt = PRIVATE (a_this)->cur_stmt, i = 0;
00849 (PRIVATE (a_this)->cur_stmt = cur_stmt);
00850 cur_stmt = cur_stmt->next) {
00851
00852
00853
00854
00855 sel_list = NULL;
00856
00857
00858
00859
00860
00861 switch (cur_stmt->type) {
00862 case RULESET_STMT:
00863 if (cur_stmt->kind.ruleset
00864 && cur_stmt->kind.ruleset->sel_list) {
00865 sel_list = cur_stmt->kind.ruleset->sel_list;
00866 }
00867 break;
00868
00869 case AT_MEDIA_RULE_STMT:
00870 if (cur_stmt->kind.media_rule
00871 && cur_stmt->kind.media_rule->rulesets
00872 && cur_stmt->kind.media_rule->rulesets->
00873 kind.ruleset
00874 && cur_stmt->kind.media_rule->rulesets->
00875 kind.ruleset->sel_list) {
00876 sel_list =
00877 cur_stmt->kind.media_rule->
00878 rulesets->kind.ruleset->sel_list;
00879 }
00880 break;
00881
00882 case AT_IMPORT_RULE_STMT:
00883
00884
00885
00886
00887 break;
00888 default:
00889 break;
00890 }
00891
00892 if (!sel_list)
00893 continue;
00894
00895
00896
00897
00898
00899
00900 for (cur_sel = sel_list; cur_sel; cur_sel = cur_sel->next) {
00901 if (!cur_sel->simple_sel)
00902 continue;
00903
00904 status = cr_sel_eng_matches_node
00905 (a_this, cur_sel->simple_sel,
00906 a_node, &matches);
00907
00908 if (status == CR_OK && matches == TRUE) {
00909
00910
00911
00912
00913
00914
00915 if (i < *a_len) {
00916 a_rulesets[i] = cur_stmt;
00917 i++;
00918
00919
00920
00921
00922
00923
00924
00925
00926
00927
00928 status = cr_simple_sel_compute_specificity (cur_sel->simple_sel);
00929
00930 g_return_val_if_fail (status == CR_OK,
00931 CR_ERROR);
00932 cur_stmt->specificity =
00933 cur_sel->simple_sel->
00934 specificity;
00935 } else
00936 {
00937 *a_len = i;
00938 return CR_OUTPUT_TOO_SHORT_ERROR;
00939 }
00940 }
00941 }
00942 }
00943
00944
00945
00946
00947
00948
00949
00950 g_return_val_if_fail (!PRIVATE (a_this)->cur_stmt, CR_ERROR);
00951 PRIVATE (a_this)->sheet = NULL;
00952 *a_len = i;
00953 return CR_OK;
00954 }
00955
00956 static enum CRStatus
00957 put_css_properties_in_props_list (CRPropList ** a_props, CRStatement * a_stmt)
00958 {
00959 CRPropList *props = NULL,
00960 *pair = NULL,
00961 *tmp_props = NULL;
00962 CRDeclaration *cur_decl = NULL;
00963
00964 g_return_val_if_fail (a_props && a_stmt
00965 && a_stmt->type == RULESET_STMT
00966 && a_stmt->kind.ruleset, CR_BAD_PARAM_ERROR);
00967
00968 props = *a_props;
00969
00970 for (cur_decl = a_stmt->kind.ruleset->decl_list;
00971 cur_decl; cur_decl = cur_decl->next) {
00972 CRDeclaration *decl;
00973
00974 decl = NULL;
00975 pair = NULL;
00976
00977 if (!cur_decl->property
00978 || !cur_decl->property->stryng
00979 || !cur_decl->property->stryng->str)
00980 continue;
00981
00982
00983
00984
00985
00986
00987
00988 cr_prop_list_lookup_prop (props,
00989 cur_decl->property,
00990 &pair);
00991
00992 if (!pair) {
00993 tmp_props = cr_prop_list_append2
00994 (props, cur_decl->property, cur_decl);
00995 if (tmp_props) {
00996 props = tmp_props;
00997 tmp_props = NULL;
00998 }
00999 continue;
01000 }
01001
01002
01003
01004
01005
01006
01007
01008 cr_prop_list_get_decl (pair, &decl);
01009 g_return_val_if_fail (decl, CR_ERROR);
01010
01011
01012
01013
01014
01015
01016
01017
01018
01019 if (decl->parent_statement
01020 && decl->parent_statement->parent_sheet
01021 && (decl->parent_statement->parent_sheet->origin
01022 < a_stmt->parent_sheet->origin)) {
01023
01024
01025
01026
01027
01028
01029
01030 if (decl->important == TRUE
01031 && decl->parent_statement->parent_sheet->origin
01032 != ORIGIN_UA) {
01033 continue;
01034 }
01035 tmp_props = cr_prop_list_unlink (props, pair);
01036 if (props) {
01037 cr_prop_list_destroy (pair);
01038 }
01039 props = tmp_props;
01040 tmp_props = NULL;
01041 props = cr_prop_list_append2
01042 (props, cur_decl->property, cur_decl);
01043
01044 continue;
01045 } else if (decl->parent_statement
01046 && decl->parent_statement->parent_sheet
01047 && (decl->parent_statement->
01048 parent_sheet->origin
01049 > a_stmt->parent_sheet->origin)) {
01050 cr_utils_trace_info
01051 ("We should not reach this line\n");
01052 continue;
01053 }
01054
01055
01056
01057
01058
01059
01060
01061
01062
01063
01064
01065
01066
01067 if (a_stmt->specificity
01068 >= decl->parent_statement->specificity) {
01069 if (decl->important == TRUE)
01070 continue;
01071 props = cr_prop_list_unlink (props, pair);
01072 if (pair) {
01073 cr_prop_list_destroy (pair);
01074 pair = NULL;
01075 }
01076 props = cr_prop_list_append2 (props,
01077 cur_decl->property,
01078 cur_decl);
01079 }
01080 }
01081
01082 *a_props = props;
01083
01084 return CR_OK;
01085 }
01086
01087 static void
01088 set_style_from_props (CRStyle * a_style, CRPropList * a_props)
01089 {
01090 CRPropList *cur = NULL;
01091 CRDeclaration *decl = NULL;
01092
01093 for (cur = a_props; cur; cur = cr_prop_list_get_next (cur)) {
01094 cr_prop_list_get_decl (cur, &decl);
01095 cr_style_set_style_from_decl (a_style, decl);
01096 decl = NULL;
01097 }
01098 }
01099
01100
01101
01102
01103
01104
01105
01106
01107
01108
01109 CRSelEng *
01110 cr_sel_eng_new (void)
01111 {
01112 CRSelEng *result = NULL;
01113
01114 result = g_try_malloc (sizeof (CRSelEng));
01115 if (!result) {
01116 cr_utils_trace_info ("Out of memory");
01117 return NULL;
01118 }
01119 memset (result, 0, sizeof (CRSelEng));
01120
01121 PRIVATE (result) = g_try_malloc (sizeof (CRSelEngPriv));
01122 if (!PRIVATE (result)) {
01123 cr_utils_trace_info ("Out of memory");
01124 g_free (result);
01125 return NULL;
01126 }
01127 memset (PRIVATE (result), 0, sizeof (CRSelEngPriv));
01128 cr_sel_eng_register_pseudo_class_sel_handler
01129 (result, (guchar *) "first-child",
01130 IDENT_PSEUDO, (CRPseudoClassSelectorHandler)
01131 first_child_pseudo_class_handler);
01132 cr_sel_eng_register_pseudo_class_sel_handler
01133 (result, (guchar *) "lang",
01134 FUNCTION_PSEUDO, (CRPseudoClassSelectorHandler)
01135 lang_pseudo_class_handler);
01136
01137 return result;
01138 }
01139
01140
01141
01142
01143
01144
01145
01146
01147
01148
01149 enum CRStatus
01150 cr_sel_eng_register_pseudo_class_sel_handler (CRSelEng * a_this,
01151 guchar * a_name,
01152 enum CRPseudoType a_type,
01153 CRPseudoClassSelectorHandler
01154 a_handler)
01155 {
01156 struct CRPseudoClassSelHandlerEntry *handler_entry = NULL;
01157 GList *list = NULL;
01158
01159 g_return_val_if_fail (a_this && PRIVATE (a_this)
01160 && a_handler && a_name, CR_BAD_PARAM_ERROR);
01161
01162 handler_entry = g_try_malloc
01163 (sizeof (struct CRPseudoClassSelHandlerEntry));
01164 if (!handler_entry) {
01165 return CR_OUT_OF_MEMORY_ERROR;
01166 }
01167 memset (handler_entry, 0,
01168 sizeof (struct CRPseudoClassSelHandlerEntry));
01169 handler_entry->name = g_strdup (a_name);
01170 handler_entry->type = a_type;
01171 handler_entry->handler = a_handler;
01172 list = g_list_append (PRIVATE (a_this)->pcs_handlers, handler_entry);
01173 if (!list) {
01174 return CR_OUT_OF_MEMORY_ERROR;
01175 }
01176 PRIVATE (a_this)->pcs_handlers = list;
01177 return CR_OK;
01178 }
01179
01180 enum CRStatus
01181 cr_sel_eng_unregister_pseudo_class_sel_handler (CRSelEng * a_this,
01182 guchar * a_name,
01183 enum CRPseudoType a_type)
01184 {
01185 GList *elem = NULL,
01186 *deleted_elem = NULL;
01187 gboolean found = FALSE;
01188 struct CRPseudoClassSelHandlerEntry *entry = NULL;
01189
01190 g_return_val_if_fail (a_this && PRIVATE (a_this), CR_BAD_PARAM_ERROR);
01191
01192 for (elem = PRIVATE (a_this)->pcs_handlers;
01193 elem; elem = g_list_next (elem)) {
01194 entry = elem->data;
01195 if (!strcmp (entry->name, a_name)
01196 && entry->type == a_type) {
01197 found = TRUE;
01198 break;
01199 }
01200 }
01201 if (found == FALSE)
01202 return CR_PSEUDO_CLASS_SEL_HANDLER_NOT_FOUND_ERROR;
01203 PRIVATE (a_this)->pcs_handlers = g_list_delete_link
01204 (PRIVATE (a_this)->pcs_handlers, elem);
01205 entry = elem->data;
01206 if (entry->name)
01207 g_free (entry->name);
01208 g_free (elem);
01209 g_list_free (deleted_elem);
01210
01211 return CR_OK;
01212 }
01213
01214
01215
01216
01217
01218
01219
01220
01221 enum CRStatus
01222 cr_sel_eng_unregister_all_pseudo_class_sel_handlers (CRSelEng * a_this)
01223 {
01224 GList *elem = NULL;
01225 struct CRPseudoClassSelHandlerEntry *entry = NULL;
01226
01227 g_return_val_if_fail (a_this && PRIVATE (a_this), CR_BAD_PARAM_ERROR);
01228
01229 if (!PRIVATE (a_this)->pcs_handlers)
01230 return CR_OK;
01231 for (elem = PRIVATE (a_this)->pcs_handlers;
01232 elem; elem = g_list_next (elem)) {
01233 entry = elem->data;
01234 if (!entry)
01235 continue;
01236 if (entry->name) {
01237 g_free (entry->name);
01238 entry->name = NULL;
01239 }
01240 g_free (entry);
01241 elem->data = NULL;
01242 }
01243 g_list_free (PRIVATE (a_this)->pcs_handlers);
01244 PRIVATE (a_this)->pcs_handlers = NULL;
01245 return CR_OK;
01246 }
01247
01248 enum CRStatus
01249 cr_sel_eng_get_pseudo_class_selector_handler (CRSelEng * a_this,
01250 guchar * a_name,
01251 enum CRPseudoType a_type,
01252 CRPseudoClassSelectorHandler *
01253 a_handler)
01254 {
01255 GList *elem = NULL;
01256 struct CRPseudoClassSelHandlerEntry *entry = NULL;
01257 gboolean found = FALSE;
01258
01259 g_return_val_if_fail (a_this && PRIVATE (a_this)
01260 && a_name, CR_BAD_PARAM_ERROR);
01261
01262 for (elem = PRIVATE (a_this)->pcs_handlers;
01263 elem; elem = g_list_next (elem)) {
01264 entry = elem->data;
01265 if (!strcmp (a_name, entry->name)
01266 && entry->type == a_type) {
01267 found = TRUE;
01268 break;
01269 }
01270 }
01271
01272 if (found == FALSE)
01273 return CR_PSEUDO_CLASS_SEL_HANDLER_NOT_FOUND_ERROR;
01274 *a_handler = entry->handler;
01275 return CR_OK;
01276 }
01277
01278
01279
01280
01281
01282
01283
01284
01285
01286
01287
01288
01289
01290
01291 enum CRStatus
01292 cr_sel_eng_matches_node (CRSelEng * a_this, CRSimpleSel * a_sel,
01293 xmlNode * a_node, gboolean * a_result)
01294 {
01295 g_return_val_if_fail (a_this && PRIVATE (a_this)
01296 && a_this && a_node
01297 && a_result, CR_BAD_PARAM_ERROR);
01298
01299 if (a_node->type != XML_ELEMENT_NODE) {
01300 *a_result = FALSE;
01301 return CR_OK;
01302 }
01303
01304 return sel_matches_node_real (a_this, a_sel,
01305 a_node, a_result,
01306 TRUE, TRUE);
01307 }
01308
01309
01310
01311
01312
01313
01314
01315
01316
01317
01318
01319
01320
01321
01322
01323
01324
01325 enum CRStatus
01326 cr_sel_eng_get_matched_rulesets (CRSelEng * a_this,
01327 CRStyleSheet * a_sheet,
01328 xmlNode * a_node,
01329 CRStatement *** a_rulesets, gulong * a_len)
01330 {
01331 CRStatement **stmts_tab = NULL;
01332 enum CRStatus status = CR_OK;
01333 gulong tab_size = 0,
01334 tab_len = 0,
01335 index = 0;
01336 gushort stmts_chunck_size = 8;
01337
01338 g_return_val_if_fail (a_this
01339 && a_sheet
01340 && a_node
01341 && a_rulesets && *a_rulesets == NULL
01342 && a_len, CR_BAD_PARAM_ERROR);
01343
01344 stmts_tab = g_try_malloc (stmts_chunck_size * sizeof (CRStatement *));
01345
01346 if (!stmts_tab) {
01347 cr_utils_trace_info ("Out of memory");
01348 status = CR_ERROR;
01349 goto error;
01350 }
01351 memset (stmts_tab, 0, stmts_chunck_size * sizeof (CRStatement *));
01352
01353 tab_size = stmts_chunck_size;
01354 tab_len = tab_size;
01355
01356 while ((status = cr_sel_eng_get_matched_rulesets_real
01357 (a_this, a_sheet, a_node, stmts_tab + index, &tab_len))
01358 == CR_OUTPUT_TOO_SHORT_ERROR) {
01359 stmts_tab = g_try_realloc (stmts_tab,
01360 (tab_size + stmts_chunck_size)
01361 * sizeof (CRStatement *));
01362 if (!stmts_tab) {
01363 cr_utils_trace_info ("Out of memory");
01364 status = CR_ERROR;
01365 goto error;
01366 }
01367 tab_size += stmts_chunck_size;
01368 index += tab_len;
01369 tab_len = tab_size - index;
01370 }
01371
01372 tab_len = tab_size - stmts_chunck_size + tab_len;
01373 *a_rulesets = stmts_tab;
01374 *a_len = tab_len;
01375
01376 return CR_OK;
01377
01378 error:
01379
01380 if (stmts_tab) {
01381 g_free (stmts_tab);
01382 stmts_tab = NULL;
01383
01384 }
01385
01386 *a_len = 0;
01387 return status;
01388 }
01389
01390
01391 enum CRStatus
01392 cr_sel_eng_get_matched_properties_from_cascade (CRSelEng * a_this,
01393 CRCascade * a_cascade,
01394 xmlNode * a_node,
01395 CRPropList ** a_props)
01396 {
01397 CRStatement **stmts_tab = NULL;
01398 enum CRStatus status = CR_OK;
01399 gulong tab_size = 0,
01400 tab_len = 0,
01401 i = 0,
01402 index = 0;
01403 enum CRStyleOrigin origin = 0;
01404 gushort stmts_chunck_size = 8;
01405 CRStyleSheet *sheet = NULL;
01406
01407 g_return_val_if_fail (a_this
01408 && a_cascade
01409 && a_node && a_props, CR_BAD_PARAM_ERROR);
01410
01411 for (origin = ORIGIN_UA; origin < NB_ORIGINS; origin++) {
01412 sheet = cr_cascade_get_sheet (a_cascade, origin);
01413 if (!sheet)
01414 continue;
01415 if (tab_size - index < 1) {
01416 stmts_tab = g_try_realloc
01417 (stmts_tab, (tab_size + stmts_chunck_size)
01418 * sizeof (CRStatement *));
01419 if (!stmts_tab) {
01420 cr_utils_trace_info ("Out of memory");
01421 status = CR_ERROR;
01422 goto cleanup;
01423 }
01424 tab_size += stmts_chunck_size;
01425
01426
01427
01428
01429 tab_len = tab_size - index;
01430 }
01431 while ((status = cr_sel_eng_get_matched_rulesets_real
01432 (a_this, sheet, a_node, stmts_tab + index, &tab_len))
01433 == CR_OUTPUT_TOO_SHORT_ERROR) {
01434 stmts_tab = g_try_realloc
01435 (stmts_tab, (tab_size + stmts_chunck_size)
01436 * sizeof (CRStatement *));
01437 if (!stmts_tab) {
01438 cr_utils_trace_info ("Out of memory");
01439 status = CR_ERROR;
01440 goto cleanup;
01441 }
01442 tab_size += stmts_chunck_size;
01443 index += tab_len;
01444
01445
01446
01447
01448 tab_len = tab_size - index;
01449 }
01450 if (status != CR_OK) {
01451 cr_utils_trace_info ("Error while running "
01452 "selector engine");
01453 goto cleanup;
01454 }
01455 index += tab_len;
01456 tab_len = tab_size - index;
01457 }
01458
01459
01460
01461
01462
01463
01464
01465 for (i = 0; i < index; i++) {
01466 CRStatement *stmt = stmts_tab[i];
01467
01468 if (!stmt)
01469 continue;
01470 switch (stmt->type) {
01471 case RULESET_STMT:
01472 if (!stmt->parent_sheet)
01473 continue;
01474 status = put_css_properties_in_props_list
01475 (a_props, stmt);
01476 break;
01477 default:
01478 break;
01479 }
01480
01481 }
01482 status = CR_OK ;
01483 cleanup:
01484 if (stmts_tab) {
01485 g_free (stmts_tab);
01486 stmts_tab = NULL;
01487 }
01488
01489 return status;
01490 }
01491
01492 enum CRStatus
01493 cr_sel_eng_get_matched_style (CRSelEng * a_this,
01494 CRCascade * a_cascade,
01495 xmlNode * a_node,
01496 CRStyle * a_parent_style,
01497 CRStyle ** a_style,
01498 gboolean a_set_props_to_initial_values)
01499 {
01500 enum CRStatus status = CR_OK;
01501
01502 CRPropList *props = NULL;
01503
01504 g_return_val_if_fail (a_this && a_cascade
01505 && a_node && a_style, CR_BAD_PARAM_ERROR);
01506
01507 status = cr_sel_eng_get_matched_properties_from_cascade
01508 (a_this, a_cascade, a_node, &props);
01509
01510 g_return_val_if_fail (status == CR_OK, status);
01511 if (props) {
01512 if (!*a_style) {
01513 *a_style = cr_style_new (a_set_props_to_initial_values) ;
01514 g_return_val_if_fail (*a_style, CR_ERROR);
01515 } else {
01516 if (a_set_props_to_initial_values == TRUE) {
01517 cr_style_set_props_to_initial_values (*a_style) ;
01518 } else {
01519 cr_style_set_props_to_default_values (*a_style);
01520 }
01521 }
01522 (*a_style)->parent_style = a_parent_style;
01523
01524 set_style_from_props (*a_style, props);
01525 if (props) {
01526 cr_prop_list_destroy (props);
01527 props = NULL;
01528 }
01529 }
01530 return CR_OK;
01531 }
01532
01533
01534
01535
01536
01537 void
01538 cr_sel_eng_destroy (CRSelEng * a_this)
01539 {
01540 g_return_if_fail (a_this);
01541
01542 if (!PRIVATE (a_this))
01543 goto end ;
01544 if (PRIVATE (a_this)->pcs_handlers) {
01545 cr_sel_eng_unregister_all_pseudo_class_sel_handlers
01546 (a_this) ;
01547 PRIVATE (a_this)->pcs_handlers = NULL ;
01548 }
01549 g_free (PRIVATE (a_this));
01550 PRIVATE (a_this) = NULL;
01551 end:
01552 if (a_this) {
01553 g_free (a_this);
01554 }
01555 }