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