mirror of
https://github.com/netsurf-browser/netsurf
synced 2024-12-24 04:56:50 +03:00
[project @ 2003-09-28 17:37:43 by bursa]
Implement CSS specificity and fix bugs. svn path=/import/netsurf/; revision=329
This commit is contained in:
parent
c48e0ce8dc
commit
fd7078b1ad
@ -38,7 +38,21 @@ hr { background-color: #000; height: 1px; }
|
||||
center { text-align: center; }
|
||||
small { font-size: smaller; }
|
||||
big { font-size: larger; }
|
||||
input, select { width: 10em; height: 2em; background-color: #eeeebb; }
|
||||
textarea { display: inline-block; width: 20em; height: 4em; background-color: #eeeebb; }
|
||||
button { background-color: #ddd; }
|
||||
select, input { background-color: #eeb; color: #000; width: 10em; height: 2em; }
|
||||
textarea { background-color: #eeb; color: #000; }
|
||||
input[type=button], input[type=image], input[type=reset], input[type=submit],
|
||||
button { background-color: #ddd; color: #000; width: auto;
|
||||
height: auto; }
|
||||
input[type=checkbox], input[type=radio] { background-color: transparent;
|
||||
width: 22px; height: 22px; }
|
||||
|
||||
[align=left] { text-align: left; }
|
||||
[align=center] { text-align: center; }
|
||||
[align=right] { text-align: right; }
|
||||
img[align=left], table[align=left] { float: left; }
|
||||
img[align=right], table[align=right] { float: right; text-align: left; }
|
||||
|
||||
[clear=all] { clear: both; }
|
||||
[clear=left] { clear: left; }
|
||||
[clear=right] { clear: right; }
|
||||
|
||||
|
46
css/css.c
46
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");
|
||||
}
|
||||
|
@ -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,
|
||||
|
35
css/parser.y
35
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).
|
||||
|
@ -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;
|
||||
|
20
render/box.c
20
render/box.c
@ -485,19 +485,6 @@ struct css_style * box_get_style(struct content ** stylesheet,
|
||||
css_cascade(style, style_new);
|
||||
free(style_new);
|
||||
|
||||
if ((s = (char *) xmlGetProp(n, (const xmlChar *) "align"))) {
|
||||
if (strcmp((const char *) n->name, "table") == 0 ||
|
||||
strcmp((const char *) n->name, "img") == 0) {
|
||||
if (stricmp(s, "left") == 0) style->float_ = CSS_FLOAT_LEFT;
|
||||
else if (stricmp(s, "right") == 0) style->float_ = CSS_FLOAT_RIGHT;
|
||||
} else {
|
||||
if (stricmp(s, "left") == 0) style->text_align = CSS_TEXT_ALIGN_LEFT;
|
||||
else if (stricmp(s, "center") == 0) style->text_align = CSS_TEXT_ALIGN_CENTER;
|
||||
else if (stricmp(s, "right") == 0) style->text_align = CSS_TEXT_ALIGN_RIGHT;
|
||||
}
|
||||
xmlFree(s);
|
||||
}
|
||||
|
||||
if ((s = (char *) xmlGetProp(n, (const xmlChar *) "bgcolor"))) {
|
||||
unsigned int r, g, b;
|
||||
if (s[0] == '#' && sscanf(s + 1, "%2x%2x%2x", &r, &g, &b) == 3)
|
||||
@ -507,13 +494,6 @@ struct css_style * box_get_style(struct content ** stylesheet,
|
||||
xmlFree(s);
|
||||
}
|
||||
|
||||
if ((s = (char *) xmlGetProp(n, (const xmlChar *) "clear"))) {
|
||||
if (stricmp(s, "all") == 0) style->clear = CSS_CLEAR_BOTH;
|
||||
else if (stricmp(s, "left") == 0) style->clear = CSS_CLEAR_LEFT;
|
||||
else if (stricmp(s, "right") == 0) style->clear = CSS_CLEAR_RIGHT;
|
||||
xmlFree(s);
|
||||
}
|
||||
|
||||
if ((s = (char *) xmlGetProp(n, (const xmlChar *) "color"))) {
|
||||
unsigned int r, g, b;
|
||||
if (s[0] == '#' && sscanf(s + 1, "%2x%2x%2x", &r, &g, &b) == 3)
|
||||
|
Loading…
Reference in New Issue
Block a user