aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorJohannes Hofmann <Johannes.Hofmann@gmx.de>2011-08-24 23:13:40 +0200
committerJohannes Hofmann <Johannes.Hofmann@gmx.de>2011-08-24 23:13:40 +0200
commit7ef21cbd8de03848230ca6d75f349bd586926aaa (patch)
tree2cd07d0ac7a0c0b3517cdc6672c8828bea93e133 /src
parentb245b5abf8e48ab81bbaaec9edb56a4a4b51af6e (diff)
add support for CSS adjacent sibling selectors
Diffstat (limited to 'src')
-rw-r--r--src/css.cc13
-rw-r--r--src/cssparser.cc3
-rw-r--r--src/doctree.hh54
3 files changed, 50 insertions, 20 deletions
diff --git a/src/css.cc b/src/css.cc
index 8b3e5371..aa799002 100644
--- a/src/css.cc
+++ b/src/css.cc
@@ -104,6 +104,7 @@ CssSelector::CssSelector () {
cs = selectorList->getRef (selectorList->size () - 1);
cs->notMatchingBefore = -1;
+ cs->combinator = CHILD;
cs->selector = new CssSimpleSelector ();
};
@@ -133,6 +134,7 @@ bool CssSelector::match (Doctree *docTree, const DoctreeNode *node) {
switch (comb) {
case CHILD:
+ case ADJACENT_SIBLING:
if (!sel->match (node))
return false;
break;
@@ -148,7 +150,7 @@ bool CssSelector::match (Doctree *docTree, const DoctreeNode *node) {
if (sel->match (node))
break;
- node = docTree->parent (node);
+ node = node->parent;
}
break;
default:
@@ -156,7 +158,11 @@ bool CssSelector::match (Doctree *docTree, const DoctreeNode *node) {
}
comb = cs->combinator;
- node = docTree->parent (node);
+
+ if (comb == ADJACENT_SIBLING)
+ node = node->sibling;
+ else
+ node = node->parent;
}
return true;
@@ -200,6 +206,9 @@ void CssSelector::print () {
case DESCENDANT:
fprintf (stderr, "\" \" ");
break;
+ case ADJACENT_SIBLING:
+ fprintf (stderr, "+ ");
+ break;
default:
fprintf (stderr, "? ");
break;
diff --git a/src/cssparser.cc b/src/cssparser.cc
index 3d62b31d..73b4331a 100644
--- a/src/cssparser.cc
+++ b/src/cssparser.cc
@@ -1289,6 +1289,9 @@ CssSelector *CssParser::parseSelector()
} else if (ttype == CSS_TK_CHAR && tval[0] == '>') {
selector->addSimpleSelector (CssSelector::CHILD);
nextToken();
+ } else if (ttype == CSS_TK_CHAR && tval[0] == '+') {
+ selector->addSimpleSelector (CssSelector::ADJACENT_SIBLING);
+ nextToken();
} else if (ttype != CSS_TK_END && spaceSeparated) {
selector->addSimpleSelector (CssSelector::DESCENDANT);
} else {
diff --git a/src/doctree.hh b/src/doctree.hh
index ef7faa7c..c46a5a10 100644
--- a/src/doctree.hh
+++ b/src/doctree.hh
@@ -6,6 +6,8 @@
class DoctreeNode {
public:
DoctreeNode *parent;
+ DoctreeNode *sibling;
+ DoctreeNode *lastChild;
int num; // unique ascending id
int element;
lout::misc::SimpleVector<char*> *klass;
@@ -14,11 +16,27 @@ class DoctreeNode {
DoctreeNode () {
parent = NULL;
+ sibling = NULL;
+ lastChild = NULL;
klass = NULL;
pseudo = NULL;
id = NULL;
element = 0;
};
+
+ ~DoctreeNode () {
+ dFree ((void*) id);
+ while (lastChild) {
+ DoctreeNode *n = lastChild;
+ lastChild = lastChild->sibling;
+ delete n;
+ }
+ if (klass) {
+ for (int i = 0; i < klass->size (); i++)
+ dFree (klass->get(i));
+ delete klass;
+ }
+ }
};
/**
@@ -26,47 +44,47 @@ class DoctreeNode {
*
* The Doctree class defines the interface to the parsed HTML document tree
* as it is used for CSS selector matching.
- * Currently the Doctree can be represented as stack, however to support
- * CSS adjacent siblings or for future JavaScript support it may have to
- * be extended to a real tree.
*/
class Doctree {
private:
DoctreeNode *topNode;
+ DoctreeNode *rootNode;
int num;
public:
Doctree () {
topNode = NULL;
+ rootNode = NULL;
num = 0;
};
- ~Doctree () { while (top ()) pop (); };
+
+ ~Doctree () {
+ if (rootNode)
+ delete rootNode;
+ };
+
DoctreeNode *push () {
DoctreeNode *dn = new DoctreeNode ();
dn->parent = topNode;
+ if (dn->parent) {
+ dn->sibling = dn->parent->lastChild;
+ dn->parent->lastChild = dn;
+ }
dn->num = num++;
+ if (!rootNode)
+ rootNode = dn;
topNode = dn;
return dn;
};
+
void pop () {
- DoctreeNode *dn = topNode;
- if (dn) {
- dFree ((void*) dn->id);
- if (dn->klass) {
- for (int i = 0; i < dn->klass->size (); i++)
- dFree (dn->klass->get(i));
- delete dn->klass;
- }
- topNode = dn->parent;
- delete dn;
- }
+ if (topNode)
+ topNode = topNode->parent;
};
+
inline DoctreeNode *top () {
return topNode;
};
- inline DoctreeNode *parent (const DoctreeNode *node) {
- return node->parent;
- };
};
#endif