summaryrefslogtreecommitdiff
path: root/css
diff options
context:
space:
mode:
Diffstat (limited to 'css')
-rw-r--r--css/css.c46
-rw-r--r--css/css.h2
-rw-r--r--css/parser.y35
-rw-r--r--css/ruleset.c32
4 files changed, 82 insertions, 33 deletions
diff --git a/css/css.c b/css/css.c
index 3330acf13..735412e0d 100644
--- a/css/css.c
+++ b/css/css.c
@@ -207,6 +207,7 @@ struct node * css_new_node(node_type type, char *data,
node->next = 0;
node->comb = COMB_NONE;
node->style = 0;
+ node->specificity = 0;
return node;
}
@@ -225,6 +226,14 @@ void css_free_node(struct node *node)
free(node);
}
+char *css_unquote(char *s)
+{
+ unsigned int len = strlen(s);
+ memmove(s, s + 1, len);
+ s[len - 2] = 0;
+ return s;
+}
+
void css_atimport(struct content *c, struct node *node)
{
@@ -260,8 +269,7 @@ void css_atimport(struct content *c, struct node *node)
break;
case NODE_STRING:
LOG(("STRING '%s'", node->data));
- url = xstrdup(node->data + 1);
- *(url + strlen(url) - 1) = 0;
+ url = xstrdup(node->data);
break;
default:
return;
@@ -372,6 +380,12 @@ void css_get_style(struct content *css, xmlNode *element,
struct node *rule;
unsigned int hash, i;
+ /* imported stylesheets */
+ for (i = 0; i != css->data.css.import_count; i++)
+ if (css->data.css.import_content[i] != 0)
+ css_get_style(css->data.css.import_content[i],
+ element, style);
+
/* match rules which end with the same element */
hash = css_hash((char *) element->name);
for (rule = stylesheet->rule[hash]; rule; rule = rule->next)
@@ -382,12 +396,6 @@ void css_get_style(struct content *css, xmlNode *element,
for (rule = stylesheet->rule[0]; rule; rule = rule->next)
if (css_match_rule(rule, element))
css_merge(style, rule->style);
-
- /* imported stylesheets */
- for (i = 0; i != css->data.css.import_count; i++)
- if (css->data.css.import_content[i] != 0)
- css_get_style(css->data.css.import_content[i],
- element, style);
}
@@ -411,14 +419,25 @@ bool css_match_rule(struct node *rule, xmlNode *element)
switch (detail->type) {
case NODE_ID:
s = (char *) xmlGetProp(element, (const xmlChar *) "id");
- if (s && strcasecmp(detail->data, s) == 0)
+ if (s && strcasecmp(detail->data + 1, s) == 0)
match = true;
break;
case NODE_CLASS:
s = (char *) xmlGetProp(element, (const xmlChar *) "class");
- if (s && strcasecmp(detail->data, s) == 0)
- match = true;
+ if (s) {
+ word = s;
+ do {
+ space = strchr(word, ' ');
+ if (space)
+ *space = 0;
+ if (strcasecmp(word, detail->data) == 0) {
+ match = true;
+ break;
+ }
+ word = space + 1;
+ } while (space);
+ }
break;
case NODE_ATTRIB:
@@ -449,8 +468,8 @@ bool css_match_rule(struct node *rule, xmlNode *element)
match = true;
break;
}
- word = space;
- } while (word);
+ word = space + 1;
+ } while (space);
}
break;
@@ -619,6 +638,7 @@ void css_dump_stylesheet(const struct css_stylesheet * stylesheet)
}
fprintf(stderr, " ");
}
+ fprintf(stderr, "%lx ", r->specificity);
css_dump_style(r->style);
fprintf(stderr, "\n");
}
diff --git a/css/css.h b/css/css.h
index f09cf55a0..378dc5304 100644
--- a/css/css.h
+++ b/css/css.h
@@ -148,6 +148,7 @@ struct node {
struct node *next;
combinator comb;
struct css_style *style;
+ unsigned long specificity;
};
#include "netsurf/css/scanner.h"
@@ -186,6 +187,7 @@ void css_destroy(struct content *c);
struct node * css_new_node(node_type type, char *data,
struct node *left, struct node *right);
void css_free_node(struct node *node);
+char *css_unquote(char *s);
void css_atimport(struct content *c, struct node *node);
void css_add_ruleset(struct content *c,
struct node *selector,
diff --git a/css/parser.y b/css/parser.y
index 0e2ff02ab..75706eb16 100644
--- a/css/parser.y
+++ b/css/parser.y
@@ -70,7 +70,8 @@ selector_list(A) ::= selector_list(B) COMMA selector(C).
selector(A) ::= simple_selector(B).
{ A = B; }
selector(A) ::= selector(B) combinator(C) simple_selector(D).
- { D->right = B; D->comb = C; A = D; }
+ { D->right = B; D->comb = C; A = D;
+ A->specificity += B->specificity; }
combinator(A) ::= .
{ A = COMB_ANCESTOR; }
@@ -80,7 +81,8 @@ combinator(A) ::= GT.
{ A = COMB_PARENT; }
simple_selector(A) ::= element_name(B) detail_list(C).
- { A = css_new_node(NODE_SELECTOR, B, C, 0); }
+ { A = css_new_node(NODE_SELECTOR, B, C, 0);
+ A->specificity = (B ? 1 : 0) + (C ? C->specificity : 0); }
element_name(A) ::= .
{ A = 0; }
@@ -90,23 +92,32 @@ element_name(A) ::= IDENT(B).
detail_list(A) ::= .
{ A = 0; }
detail_list(A) ::= HASH(B) detail_list(C).
- { A = css_new_node(NODE_ID, B, 0, 0); A->next = C; }
+ { A = css_new_node(NODE_ID, B, 0, 0);
+ A->specificity = 0x10000 + (C ? C->specificity : 0); A->next = C; }
detail_list(A) ::= DOT IDENT(B) detail_list(C).
- { A = css_new_node(NODE_CLASS, B, 0, 0); A->next = C; }
+ { A = css_new_node(NODE_CLASS, B, 0, 0);
+ A->specificity = 0x100 + (C ? C->specificity : 0); A->next = C; }
detail_list(A) ::= LBRAC IDENT(B) RBRAC detail_list(C).
- { A = css_new_node(NODE_ATTRIB, B, 0, 0); A->next = C; }
+ { A = css_new_node(NODE_ATTRIB, B, 0, 0);
+ A->specificity = 0x100 + (C ? C->specificity : 0); A->next = C; }
detail_list(A) ::= LBRAC IDENT(B) EQUALS IDENT(C) RBRAC detail_list(D).
- { A = css_new_node(NODE_ATTRIB_EQ, B, 0, 0); A->data2 = C; A->next = D; }
+ { A = css_new_node(NODE_ATTRIB_EQ, B, 0, 0); A->data2 = C;
+ A->specificity = 0x100 + (D ? D->specificity : 0); A->next = D; }
detail_list(A) ::= LBRAC IDENT(B) EQUALS STRING(C) RBRAC detail_list(D).
- { A = css_new_node(NODE_ATTRIB_EQ, B, 0, 0); A->data2 = C; A->next = D; }
+ { A = css_new_node(NODE_ATTRIB_EQ, B, 0, 0); A->data2 = css_unquote(C);
+ A->specificity = 0x100 + (D ? D->specificity : 0); A->next = D; }
detail_list(A) ::= LBRAC IDENT(B) INCLUDES IDENT(C) RBRAC detail_list(D).
- { A = css_new_node(NODE_ATTRIB_INC, B, 0, 0); A->data2 = C; A->next = D; }
+ { A = css_new_node(NODE_ATTRIB_INC, B, 0, 0); A->data2 = C;
+ A->specificity = 0x100 + (D ? D->specificity : 0); A->next = D; }
detail_list(A) ::= LBRAC IDENT(B) INCLUDES STRING(C) RBRAC detail_list(D).
- { A = css_new_node(NODE_ATTRIB_INC, B, 0, 0); A->data2 = C; A->next = D; }
+ { A = css_new_node(NODE_ATTRIB_INC, B, 0, 0); A->data2 = css_unquote(C);
+ A->specificity = 0x100 + (D ? D->specificity : 0); A->next = D; }
detail_list(A) ::= LBRAC IDENT(B) DASHMATCH IDENT(C) RBRAC detail_list(D).
- { A = css_new_node(NODE_ATTRIB_DM, B, 0, 0); A->data2 = C; A->next = D; }
+ { A = css_new_node(NODE_ATTRIB_DM, B, 0, 0); A->data2 = C;
+ A->specificity = 0x100 + (D ? D->specificity : 0); A->next = D; }
detail_list(A) ::= LBRAC IDENT(B) DASHMATCH STRING(C) RBRAC detail_list(D).
- { A = css_new_node(NODE_ATTRIB_DM, B, 0, 0); A->data2 = C; A->next = D; }
+ { A = css_new_node(NODE_ATTRIB_DM, B, 0, 0); A->data2 = css_unquote(C);
+ A->specificity = 0x100 + (D ? D->specificity : 0); A->next = D; }
/* TODO: pseudo */
declaration_list(A) ::= .
@@ -148,7 +159,7 @@ any(A) ::= PERCENTAGE(B).
any(A) ::= DIMENSION(B).
{ A = css_new_node(NODE_DIMENSION, B, 0, 0); }
any(A) ::= STRING(B).
- { A = css_new_node(NODE_STRING, B, 0, 0); }
+ { A = css_new_node(NODE_STRING, css_unquote(B), 0, 0); }
any(A) ::= DELIM(B).
{ A = css_new_node(NODE_DELIM, B, 0, 0); }
any(A) ::= URI(B).
diff --git a/css/ruleset.c b/css/ruleset.c
index a211bfb10..52403c241 100644
--- a/css/ruleset.c
+++ b/css/ruleset.c
@@ -33,7 +33,7 @@ struct font_size_entry {
};
-static int compare_selectors(struct node *n0, struct node *n1);
+static int compare_selectors(const struct node *n0, const struct node *n1);
static int parse_length(struct css_length * const length,
const struct node * const v, bool non_negative);
static colour parse_colour(const struct node * const v);
@@ -110,8 +110,9 @@ void css_add_ruleset(struct content *c,
struct node *selector,
struct node *declaration)
{
+ bool found;
struct css_stylesheet *stylesheet = c->data.css.css;
- struct node *n, *sel, *next_sel;
+ struct node *n, *sel, *next_sel, *prev;
struct css_style *style;
unsigned int hash;
@@ -139,18 +140,33 @@ void css_add_ruleset(struct content *c,
continue;
/* check if this selector is already present */
+ found = false;
+ prev = 0;
hash = css_hash(sel->data);
- for (n = stylesheet->rule[hash]; n != 0; n = n->next)
- if (compare_selectors(sel, n))
+ /* selectors are ordered by specificity in the hash chain */
+ for (n = stylesheet->rule[hash];
+ n && n->specificity < sel->specificity;
+ n = n->next)
+ prev = n;
+ for ( ; n && n->specificity == sel->specificity;
+ n = n->next) {
+ prev = n;
+ if (compare_selectors(sel, n)) {
+ found = true;
break;
- if (n == 0) {
+ }
+ }
+ if (!found) {
/* not present: construct a new struct css_style */
LOG(("constructing new style"));
style = xcalloc(1, sizeof(*style));
memcpy(style, &css_empty_style, sizeof(*style));
sel->style = style;
- sel->next = stylesheet->rule[hash];
- stylesheet->rule[hash] = sel;
+ sel->next = n;
+ if (prev)
+ prev->next = sel;
+ else
+ stylesheet->rule[hash] = sel;
c->size += sizeof(*style);
} else {
/* already exists: augument existing style */
@@ -182,7 +198,7 @@ void css_add_declarations(struct css_style *style, struct node *declaration)
}
-int compare_selectors(struct node *n0, struct node *n1)
+int compare_selectors(const struct node *n0, const struct node *n1)
{
struct node *m0, *m1;
unsigned int count0 = 0, count1 = 0;