aboutsummaryrefslogtreecommitdiff
path: root/src/css.cc
diff options
context:
space:
mode:
Diffstat (limited to 'src/css.cc')
-rw-r--r--src/css.cc83
1 files changed, 38 insertions, 45 deletions
diff --git a/src/css.cc b/src/css.cc
index c95e43d9..c6c74f60 100644
--- a/src/css.cc
+++ b/src/css.cc
@@ -102,7 +102,7 @@ CssSelector::CssSelector () {
cs = selectorList->getRef (selectorList->size () - 1);
cs->notMatchingBefore = -1;
- cs->combinator = CHILD;
+ cs->combinator = COMB_NONE;
cs->selector = new CssSimpleSelector ();
};
@@ -115,55 +115,47 @@ CssSelector::~CssSelector () {
/**
* \brief Return whether selector matches at a given node in the document tree.
*/
-bool CssSelector::match (Doctree *docTree, const DoctreeNode *node) {
- CssSimpleSelector *sel;
- Combinator comb = CHILD;
- int *notMatchingBefore;
- const DoctreeNode *n;
+bool CssSelector::match (Doctree *docTree, const DoctreeNode *node,
+ int i, Combinator comb) {
+ assert (node);
- for (int i = selectorList->size () - 1; i >= 0; i--) {
- struct CombinatorAndSelector *cs = selectorList->getRef (i);
+ if (i < 0)
+ return true;
- sel = cs->selector;
- notMatchingBefore = &cs->notMatchingBefore;
+ struct CombinatorAndSelector *cs = selectorList->getRef (i);
+ CssSimpleSelector *sel = cs->selector;
- if (node == NULL)
- return false;
-
- switch (comb) {
- case CHILD:
- case ADJACENT_SIBLING:
- if (!sel->match (node))
- return false;
- break;
- case DESCENDANT:
- n = node;
-
- while (true) {
- if (node == NULL || node->num <= *notMatchingBefore) {
- *notMatchingBefore = n->num;
- return false;
- }
-
- if (sel->match (node))
- break;
+ switch (comb) {
+ case COMB_NONE:
+ break;
+ case COMB_CHILD:
+ node = docTree->parent (node);
+ break;
+ case COMB_ADJACENT_SIBLING:
+ node = docTree->sibling (node);
+ break;
+ case COMB_DESCENDANT:
+ node = docTree->parent (node);
- node = docTree->parent (node);
- }
- break;
- default:
- return false; // \todo implement other combinators
- }
+ for (const DoctreeNode *n = node;
+ n && n->num > cs->notMatchingBefore; n = docTree->parent (n))
+ if (sel->match (n) && match (docTree, n, i - 1, cs->combinator))
+ return true;
- comb = cs->combinator;
+ if (node) // remember that it didn't match to avoid future tests
+ cs->notMatchingBefore = node->num;
- if (comb == ADJACENT_SIBLING)
- node = docTree->sibling (node);
- else
- node = docTree->parent (node);
+ return false;
+ break;
+ default:
+ return false; // \todo implement other combinators
}
- return true;
+ if (!node || !sel->match (node))
+ return false;
+
+ // tail recursion should be optimized by the compiler
+ return match (docTree, node, i - 1, cs->combinator);
}
void CssSelector::addSimpleSelector (Combinator c) {
@@ -198,13 +190,13 @@ void CssSelector::print () {
if (i < selectorList->size () - 1) {
switch (selectorList->getRef (i + 1)->combinator) {
- case CHILD:
+ case COMB_CHILD:
fprintf (stderr, "> ");
break;
- case DESCENDANT:
+ case COMB_DESCENDANT:
fprintf (stderr, "\" \" ");
break;
- case ADJACENT_SIBLING:
+ case COMB_ADJACENT_SIBLING:
fprintf (stderr, "+ ");
break;
default:
@@ -260,6 +252,7 @@ void CssSimpleSelector::setSelect (SelectType t, const char *v) {
* the document tree.
*/
bool CssSimpleSelector::match (const DoctreeNode *n) {
+ assert (n);
if (element != ELEMENT_ANY && element != n->element)
return false;
if (pseudo != NULL &&