summaryrefslogtreecommitdiff
path: root/css
diff options
context:
space:
mode:
authorJames Bursa <james@netsurf-browser.org>2003-04-04 15:19:32 +0000
committerJames Bursa <james@netsurf-browser.org>2003-04-04 15:19:32 +0000
commit4421b2e633179bbd8f5331d2bdc33246aa2f40d9 (patch)
treed8b6e38fbb204c661906a872d112f1550b1653bf /css
parenteb256015adc70034e367fe1c564b7fdca964887b (diff)
downloadnetsurf-4421b2e633179bbd8f5331d2bdc33246aa2f40d9.tar.gz
netsurf-4421b2e633179bbd8f5331d2bdc33246aa2f40d9.tar.bz2
[project @ 2003-04-04 15:19:31 by bursa]
New CSS parser. svn path=/import/netsurf/; revision=112
Diffstat (limited to 'css')
-rw-r--r--css/css.c410
-rw-r--r--css/css.h182
-rw-r--r--css/css_enums21
-rwxr-xr-xcss/makeenum38
-rw-r--r--css/parser.y21
-rw-r--r--css/ruleset.c336
6 files changed, 999 insertions, 9 deletions
diff --git a/css/css.c b/css/css.c
new file mode 100644
index 000000000..205fd8a83
--- /dev/null
+++ b/css/css.c
@@ -0,0 +1,410 @@
+/**
+ * $Id: css.c,v 1.1 2003/04/04 15:19:31 bursa Exp $
+ */
+
+#include <assert.h>
+#include <stdlib.h>
+#include <string.h>
+#include <strings.h>
+#define CSS_INTERNALS
+#include "netsurf/content/content.h"
+#include "netsurf/css/css.h"
+#include "netsurf/utils/log.h"
+#include "netsurf/utils/utils.h"
+
+/**
+ * internal structures
+ */
+
+struct decl {
+ unsigned long score;
+ struct rule * rule;
+};
+
+void css_dump_style(const struct css_style * const style);
+
+
+
+const struct css_style css_base_style = {
+ 0xffffff,
+ CSS_CLEAR_NONE,
+ 0x000000,
+ CSS_DISPLAY_BLOCK,
+ CSS_FLOAT_NONE,
+ { CSS_FONT_SIZE_LENGTH, { { 12, CSS_UNIT_PT } } },
+ CSS_FONT_WEIGHT_NORMAL,
+ CSS_FONT_STYLE_NORMAL,
+ { CSS_HEIGHT_AUTO, { 1, CSS_UNIT_EM } },
+ { CSS_LINE_HEIGHT_ABSOLUTE, { 1.2 } },
+ CSS_TEXT_ALIGN_LEFT,
+ { CSS_WIDTH_AUTO, { { 1, CSS_UNIT_EM } } }
+};
+
+const struct css_style css_empty_style = {
+ CSS_COLOR_INHERIT,
+ CSS_CLEAR_INHERIT,
+ CSS_COLOR_INHERIT,
+ CSS_DISPLAY_INHERIT,
+ CSS_FLOAT_INHERIT,
+ { CSS_FONT_SIZE_INHERIT, { { 1, CSS_UNIT_EM } } },
+ CSS_FONT_WEIGHT_INHERIT,
+ CSS_FONT_STYLE_INHERIT,
+ { CSS_HEIGHT_AUTO, { 1, CSS_UNIT_EM } },
+ { CSS_LINE_HEIGHT_INHERIT, { 1.2 } },
+ CSS_TEXT_ALIGN_INHERIT,
+ { CSS_WIDTH_INHERIT, { { 1, CSS_UNIT_EM } } }
+};
+
+const struct css_style css_blank_style = {
+ TRANSPARENT,
+ CSS_CLEAR_NONE,
+ CSS_COLOR_INHERIT,
+ CSS_DISPLAY_INLINE,
+ CSS_FLOAT_NONE,
+ { CSS_FONT_SIZE_INHERIT, { { 1, CSS_UNIT_EM } } },
+ CSS_FONT_WEIGHT_INHERIT,
+ CSS_FONT_STYLE_INHERIT,
+ { CSS_HEIGHT_AUTO, { 1, CSS_UNIT_EM } },
+ { CSS_LINE_HEIGHT_INHERIT, { 1.2 } },
+ CSS_TEXT_ALIGN_INHERIT,
+ { CSS_WIDTH_AUTO, { { 1, CSS_UNIT_EM } } }
+};
+
+
+
+void css_create(struct content *c)
+{
+ LOG(("content %p", c));
+ c->data.css = xcalloc(1, sizeof(*c->data.css));
+ css_lex_init(&c->data.css->lexer);
+ c->data.css->parser = css_parser_Alloc(malloc);
+ c->data.css->rule = 0;
+ c->data.css->last_rule = 0;
+}
+
+
+void css_process_data(struct content *c, char *data, unsigned long size)
+{
+ int token;
+ YY_BUFFER_STATE buffer;
+
+ LOG(("content %p, size %lu", c, size));
+
+ buffer = css__scan_bytes(data, size, c->data.css->lexer);
+ while ((token = css_lex(c->data.css->lexer))) {
+ css_parser_(c->data.css->parser, token,
+ strdup(css_get_text(c->data.css->lexer)),
+ c->data.css);
+ }
+ css__delete_buffer(buffer, c->data.css->lexer);
+}
+
+
+int css_convert(struct content *c, unsigned int width, unsigned int height)
+{
+ LOG(("content %p", c));
+
+ css_parser_(c->data.css->parser, 0, 0, c->data.css);
+
+ css_parser_Free(c->data.css->parser, free);
+ css_lex_destroy(c->data.css->lexer);
+
+ return 0;
+}
+
+
+void css_revive(struct content *c, unsigned int width, unsigned int height)
+{
+}
+
+
+void css_reformat(struct content *c, unsigned int width, unsigned int height)
+{
+}
+
+
+void css_destroy(struct content *c)
+{
+ xfree(c->data.css);
+}
+
+
+/**
+ * parser support functions
+ */
+
+struct node * css_new_node(node_type type, char *data,
+ struct node *left, struct node *right)
+{
+ struct node *node = xcalloc(1, sizeof(*node));
+ node->type = type;
+ node->data = data;
+ node->left = left;
+ node->right = right;
+ node->next = 0;
+ node->comb = COMB_NONE;
+ node->style = 0;
+ return node;
+}
+
+void css_free_node(struct node *node)
+{
+ if (node == 0)
+ return;
+ if (node->left != 0)
+ css_free_node(node->left);
+ if (node->right != 0)
+ css_free_node(node->right);
+ if (node->next != 0)
+ css_free_node(node->next);
+ if (node->data != 0)
+ free(node->data);
+ free(node);
+}
+
+
+
+void css_get_style(struct css_stylesheet * stylesheet, struct css_selector * selector,
+ unsigned int selectors, struct css_style * style)
+{
+ struct node *r, *n, *m;
+ unsigned int i;
+
+ LOG(("stylesheet %p, selectors %u", stylesheet, selectors));
+
+ for (r = stylesheet->rule; r != 0; r = r->next) {
+ i = selectors - 1;
+ n = r;
+ /* compare element */
+ if (strcasecmp(selector[i].element, n->data) != 0)
+ goto not_matched;
+ LOG(("top element '%s' matched", selector[i].element));
+ while (1) {
+ /* class and id */
+ for (m = n->left; m != 0; m = m->next) {
+ if (m->type == NODE_ID) {
+ /* TODO: check if case sensitive */
+ if (strcmp(selector[i].id, m->data) != 0)
+ goto not_matched;
+ } else if (m->type == NODE_CLASS) {
+ /* TODO: check if case sensitive */
+ if (strcmp(selector[i].class, m->data) != 0)
+ goto not_matched;
+ } else {
+ goto not_matched;
+ }
+ }
+ LOG(("class and id matched"));
+ /* ancestors etc. */
+ if (n->comb == COMB_NONE)
+ goto matched; /* match successful */
+ else if (n->comb == COMB_ANCESTOR) {
+ /* search for ancestor */
+ assert(n->right != 0);
+ n = n->right;
+ LOG(("searching for ancestor '%s'", n->data));
+ while (i != 0 && strcasecmp(selector[i - 1].element, n->data) != 0)
+ i--;
+ if (i == 0)
+ goto not_matched;
+ i--;
+ LOG(("found"));
+ } else {
+ /* TODO: COMB_PRECEDED, COMB_PARENT */
+ goto not_matched;
+ }
+ }
+
+matched:
+ /* TODO: sort by specificity */
+ LOG(("matched rule %p", r));
+ css_dump_style(r->style);
+ css_cascade(style, r->style);
+
+not_matched:
+
+ }
+
+ css_dump_style(style);
+}
+
+
+void css_parse_property_list(struct css_style * style, char * str)
+{
+}
+
+
+
+/**
+ * dump a style
+ */
+
+static void dump_length(const struct css_length * const length)
+{
+ LOG(("%g%s", length->value,
+ css_unit_name[length->unit]));
+}
+
+#define DUMP_LENGTH(pre, len, post) LOG((pre "%g%s" post, (len)->value, css_unit_name[(len)->unit]));
+
+void css_dump_style(const struct css_style * const style)
+{
+ LOG(("{ "));
+ LOG(("background-color: #%lx;", style->background_color));
+ LOG(("clear: %s;", css_clear_name[style->clear]));
+ LOG(("color: #%lx;", style->color));
+ LOG(("display: %s;", css_display_name[style->display]));
+ LOG(("float: %s;", css_float_name[style->float_]));
+ switch (style->font_size.size) {
+ case CSS_FONT_SIZE_ABSOLUTE:
+ LOG(("font-size: [%g];", style->font_size.value.absolute)); break;
+ case CSS_FONT_SIZE_LENGTH:
+ DUMP_LENGTH("font-size: ", &style->font_size.value.length, ";"); break;
+ case CSS_FONT_SIZE_PERCENT:
+ LOG(("font-size: %g%%;", style->font_size.value.percent)); break;
+ case CSS_FONT_SIZE_INHERIT: LOG(("font-size: inherit;")); break;
+ default: LOG(("font-size: UNKNOWN;")); break;
+ }
+ switch (style->height.height) {
+ case CSS_HEIGHT_AUTO: LOG(("height: auto;")); break;
+ case CSS_HEIGHT_LENGTH: DUMP_LENGTH("height: ", &style->height.length, ";"); break;
+ default: LOG(("height: UNKNOWN;")); break;
+ }
+ switch (style->line_height.size) {
+ case CSS_LINE_HEIGHT_ABSOLUTE:
+ LOG(("line-height: [%g];", style->line_height.value.absolute)); break;
+ case CSS_LINE_HEIGHT_LENGTH:
+ DUMP_LENGTH("line-height: ", &style->line_height.value.length, ";"); break;
+ case CSS_LINE_HEIGHT_PERCENT:
+ LOG(("line-height: %g%%;", style->line_height.value.percent)); break;
+ case CSS_LINE_HEIGHT_INHERIT: LOG(("line-height: inherit;")); break;
+ default: LOG(("line-height: UNKNOWN;")); break;
+ }
+ LOG(("text-align: %s;", css_text_align_name[style->text_align]));
+ switch (style->width.width) {
+ case CSS_WIDTH_AUTO: LOG(("width: auto;")); break;
+ case CSS_WIDTH_LENGTH:
+ DUMP_LENGTH("width: ", &style->width.value.length, ";"); break;
+ case CSS_WIDTH_PERCENT: LOG(("width: %g%%;", style->width.value.percent)); break;
+ default: LOG(("width: UNKNOWN;")); break;
+ }
+ LOG(("}"));
+}
+#if 0
+static void dump_selector(const struct css_selector * const sel)
+{
+ if (sel->class != 0)
+ LOG(("'%s'.'%s' ", sel->element, sel->class);
+ else if (sel->id != 0)
+ LOG(("'%s'#'%s' ", sel->element, sel->id);
+ else
+ LOG(("'%s' ", sel->element);
+}
+
+static void dump_rule(const struct rule * rule)
+{
+ unsigned int i;
+ for (i = 0; i < rule->selectors; i++)
+ dump_selector(&rule->selector[i]);
+ css_dump_style(rule->style);
+}
+
+void css_dump_stylesheet(const struct css_stylesheet * stylesheet)
+{
+ unsigned int i;
+ for (i = 0; i < HASH_SIZE; i++) {
+ struct rule * rule;
+ LOG(("hash %i:\n", i);
+ for (rule = stylesheet->hash[i]; rule != 0; rule = rule->next)
+ dump_rule(rule);
+ }
+}
+#endif
+/**
+ * cascade styles
+ */
+
+void css_cascade(struct css_style * const style, const struct css_style * const apply)
+{
+ float f;
+
+ if (apply->background_color != CSS_COLOR_INHERIT)
+ style->background_color = apply->background_color;
+ if (apply->clear != CSS_CLEAR_INHERIT)
+ style->clear = apply->clear;
+ if (apply->color != CSS_COLOR_INHERIT)
+ style->color = apply->color;
+ if (apply->display != CSS_DISPLAY_INHERIT)
+ style->display = apply->display;
+ if (apply->float_ != CSS_FLOAT_INHERIT)
+ style->float_ = apply->float_;
+ if (apply->height.height != CSS_HEIGHT_INHERIT)
+ style->height = apply->height;
+ if (apply->text_align != CSS_TEXT_ALIGN_INHERIT)
+ style->text_align = apply->text_align;
+ if (apply->width.width != CSS_WIDTH_INHERIT)
+ style->width = apply->width;
+ if (apply->font_weight != CSS_FONT_WEIGHT_INHERIT)
+ style->font_weight = apply->font_weight;
+ if (apply->font_style != CSS_FONT_STYLE_INHERIT)
+ style->font_style = apply->font_style;
+
+ /* font-size */
+ f = apply->font_size.value.percent / 100;
+ switch (apply->font_size.size) {
+ case CSS_FONT_SIZE_ABSOLUTE:
+ style->font_size = apply->font_size;
+ break;
+ case CSS_FONT_SIZE_LENGTH:
+ switch (apply->font_size.value.length.unit) {
+ case CSS_UNIT_EM:
+ f = apply->font_size.value.length.value;
+ break;
+ case CSS_UNIT_EX:
+ f = apply->font_size.value.length.value * 0.6 /*?*/;
+ break;
+ default:
+ style->font_size = apply->font_size;
+ }
+ if ((apply->font_size.value.length.unit != CSS_UNIT_EM) &&
+ (apply->font_size.value.length.unit != CSS_UNIT_EX))
+ break;
+ /* drop through if EM or EX */
+ case CSS_FONT_SIZE_PERCENT:
+ switch (style->font_size.size) {
+ case CSS_FONT_SIZE_ABSOLUTE:
+ style->font_size.value.absolute *= f;
+ break;
+ case CSS_FONT_SIZE_LENGTH:
+ style->font_size.value.length.value *= f;
+ break;
+ default:
+ die("attempting percentage of unknown font-size");
+ }
+ break;
+ case CSS_FONT_SIZE_INHERIT:
+ default: /* leave unchanged */
+ break;
+ }
+}
+
+
+#ifdef DEBUG
+
+int main()
+{
+ const char data[] = "h1 { blah: foo; display: block; }"
+ "h1.c1 h2#id1 + h3, h4 h5.c2#id2 { size: 100mm; color: red }"
+ "p { background-color: #123; clear: left; color: #ff0000; display: block;"
+ "float: left; font-size: 150%; height: blah; line-height: 100;"
+ "text-align: left right; width: 90%;}";
+ struct content c;
+ css_create(&c);
+ css_process_data(&c, data, 24);
+ css_process_data(&c, data + 24, sizeof(data) - 25);
+ css_convert(&c, 100, 100);
+ return 0;
+}
+
+#endif
+
diff --git a/css/css.h b/css/css.h
new file mode 100644
index 000000000..3b7844b5c
--- /dev/null
+++ b/css/css.h
@@ -0,0 +1,182 @@
+/**
+ * $Id: css.h,v 1.1 2003/04/04 15:19:31 bursa Exp $
+ */
+
+#ifndef _NETSURF_CSS_CSS_H_
+#define _NETSURF_CSS_CSS_H_
+
+#include "css_enum.h"
+
+/**
+ * structures and typedefs
+ */
+
+typedef unsigned long colour; /* 0xbbggrr */
+#define TRANSPARENT 0x1000000
+#define CSS_COLOR_INHERIT 0x2000000
+
+struct css_length {
+ float value;
+ css_unit unit;
+};
+
+struct css_style {
+ colour background_color;
+ css_clear clear;
+ colour color;
+ css_display display;
+ css_float float_;
+
+ struct {
+ enum { CSS_FONT_SIZE_INHERIT,
+ CSS_FONT_SIZE_ABSOLUTE,
+ CSS_FONT_SIZE_LENGTH,
+ CSS_FONT_SIZE_PERCENT } size;
+ union {
+ struct css_length length;
+ float absolute;
+ float percent;
+ } value;
+ } font_size;
+
+ css_font_weight font_weight;
+ css_font_style font_style;
+
+ struct {
+ enum { CSS_HEIGHT_INHERIT,
+ CSS_HEIGHT_AUTO,
+ CSS_HEIGHT_LENGTH } height;
+ struct css_length length;
+ } height;
+
+ struct {
+ enum { CSS_LINE_HEIGHT_INHERIT,
+ CSS_LINE_HEIGHT_ABSOLUTE,
+ CSS_LINE_HEIGHT_LENGTH,
+ CSS_LINE_HEIGHT_PERCENT } size;
+ union {
+ float absolute;
+ struct css_length length;
+ float percent;
+ } value;
+ } line_height;
+
+ css_text_align text_align;
+
+ struct {
+ enum { CSS_WIDTH_INHERIT,
+ CSS_WIDTH_AUTO,
+ CSS_WIDTH_LENGTH,
+ CSS_WIDTH_PERCENT } width;
+ union {
+ struct css_length length;
+ float percent;
+ } value;
+ } width;
+};
+
+struct css_stylesheet;
+
+struct css_selector {
+ const char *element;
+ char *class;
+ char *id;
+};
+
+
+extern const struct css_style css_base_style;
+extern const struct css_style css_empty_style;
+extern const struct css_style css_blank_style;
+
+
+#ifdef CSS_INTERNALS
+
+typedef enum {
+ NODE_BLOCK,
+ NODE_DECLARATION,
+ NODE_IDENT,
+ NODE_NUMBER,
+ NODE_PERCENTAGE,
+ NODE_DIMENSION,
+ NODE_STRING,
+ NODE_DELIM,
+ NODE_URI,
+ NODE_HASH,
+ NODE_UNICODE_RANGE,
+ NODE_INCLUDES,
+ NODE_FUNCTION,
+ NODE_DASHMATCH,
+ NODE_COLON,
+ NODE_COMMA,
+ NODE_PLUS,
+ NODE_GT,
+ NODE_PAREN,
+ NODE_BRAC,
+ NODE_SELECTOR,
+ NODE_ID,
+ NODE_CLASS,
+} node_type;
+
+typedef enum {
+ COMB_NONE,
+ COMB_ANCESTOR,
+ COMB_PARENT,
+ COMB_PRECEDED,
+} combinator;
+
+struct node {
+ node_type type;
+ char *data;
+ struct node *left;
+ struct node *right;
+ struct node *next;
+ combinator comb;
+ struct css_style *style;
+};
+
+#include "netsurf/css/scanner.h"
+
+struct css_stylesheet {
+ yyscan_t lexer;
+ void *parser;
+ struct node *rule;
+ struct node *last_rule;
+};
+
+#endif
+
+/**
+ * interface
+ */
+
+#include "netsurf/content/content.h"
+
+void css_create(struct content *c);
+void css_process_data(struct content *c, char *data, unsigned long size);
+int css_convert(struct content *c, unsigned int width, unsigned int height);
+void css_revive(struct content *c, unsigned int width, unsigned int height);
+void css_reformat(struct content *c, unsigned int width, unsigned int height);
+void css_destroy(struct content *c);
+
+#ifdef CSS_INTERNALS
+
+struct node * css_new_node(node_type type, char *data,
+ struct node *left, struct node *right);
+void css_free_node(struct node *node);
+void css_add_ruleset(struct css_stylesheet *stylesheet,
+ struct node *selector,
+ struct node *declaration);
+
+void css_parser_Trace(FILE *TraceFILE, char *zTracePrompt);
+void *css_parser_Alloc(void *(*mallocProc)(int));
+void css_parser_Free(void *p, void (*freeProc)(void*));
+void css_parser_(void *yyp, int yymajor, char* yyminor, struct css_stylesheet *stylesheet);
+
+#endif
+
+void css_get_style(struct css_stylesheet * stylesheet, struct css_selector * selector,
+ unsigned int selectors, struct css_style * style);
+void css_cascade(struct css_style * const style, const struct css_style * const apply);
+void css_parse_property_list(struct css_style * style, char * str);
+
+#endif
diff --git a/css/css_enums b/css/css_enums
new file mode 100644
index 000000000..1d12aea74
--- /dev/null
+++ b/css/css_enums
@@ -0,0 +1,21 @@
+css_unit em ex px in cm mm pt pc
+css_background_attachment inherit fixed scroll
+css_background_position inherit top center bottom left right length percent
+css_background_repeat inherit repeat repeat_x repeat_y no_repeat
+css_border_width inherit medium thin thick length
+css_border_style inherit none dashed dotted double groove inset outset ridge solid
+css_clear inherit none both left right
+css_display inherit inline block list-item run-in compact marker table inline-table table-row-group table-header-group table-footer-group table-row table-column-group table-column table-cell table-caption none
+css_float inherit none left right
+css_font_style inherit normal italic oblique
+css_font_variant normal smallcaps
+css_font_weight inherit normal bold bolder lighter 100 200 300 400 500 600 700 800 900
+css_letter_spacing normal length
+css_list_style_position outside inside
+css_list_style_type disc circle square decimal lower_alpha lower_roman upper_alpha upper_roman none
+css_margin auto length percent
+css_text_align inherit left right center justify
+css_text_decoration none blink line_through overline underline
+css_text_transform none capitalize lowercase uppercase
+css_vertical_align baseline bottom middle sub super text_bottom text_top top percent
+css_white_space normal nowrap pre
diff --git a/css/makeenum b/css/makeenum
new file mode 100755
index 000000000..6501d3704
--- /dev/null
+++ b/css/makeenum
@@ -0,0 +1,38 @@
+#!/usr/bin/perl -W
+# $Id: makeenum,v 1.1 2003/04/04 15:19:31 bursa Exp $
+
+$out = shift or die "usage: makeenum leafname";
+
+open H, ">$out.h" or die "open 'enum.h' failed";
+open C, ">$out.c" or die "open 'enum.c' failed";
+
+print C "#include \"$out.h\"\n\n";
+
+while (<>) {
+ chomp;
+ @enum = split;
+ $name = shift @enum;
+
+ @uc_enum = map uc, @enum;
+ s/-/_/g foreach (@uc_enum);
+ $uc_name = uc $name;
+
+ print H "extern const char * const ${name}_name[];\n";
+ print H "typedef enum {\n ${uc_name}_";
+ print H join ",\n ${uc_name}_", @uc_enum;
+ print H ",\n ${uc_name}_UNKNOWN\n";
+ print H "} $name;\n";
+ print H "$name ${name}_parse(const char * const s);\n\n";
+
+ print C "/**\n * $name\n */\n\n";
+ print C "const char * const ${name}_name[] = {\n \"";
+ print C join "\",\n \"", @enum;
+ print C "\"\n};\n\n";
+ print C "$name ${name}_parse(const char * const s)\n{\n";
+ foreach $x (@enum) {
+ $ux = uc $x;
+ $ux =~ s/-/_/g;
+ print C " if (strcasecmp(s, \"$x\") == 0) return ${uc_name}_$ux;\n";
+ }
+ print C " return ${uc_name}_UNKNOWN;\n}\n\n";
+}
diff --git a/css/parser.y b/css/parser.y
index 50fbd5d08..5b9751036 100644
--- a/css/parser.y
+++ b/css/parser.y
@@ -1,5 +1,5 @@
/**
- * $Id: parser.y,v 1.3 2003/04/01 21:33:08 bursa Exp $
+ * $Id: parser.y,v 1.4 2003/04/04 15:19:31 bursa Exp $
*/
/*
@@ -47,7 +47,7 @@ block_body ::= block_body SEMI.
ruleset ::= selector_list(A) LBRACE declaration_list(B) RBRACE.
{ css_add_ruleset(stylesheet, A, B);
- css_free_node(A); css_free_node(B); }
+ css_free_node(B); }
ruleset ::= any_list_1(A) LBRACE declaration_list(B) RBRACE.
{ css_free_node(A); css_free_node(B); } /* not CSS2 */
ruleset ::= LBRACE declaration_list RBRACE.
@@ -61,14 +61,14 @@ 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).
- { B->right = D; A->data = C; A = B; }
+ { D->right = B; D->comb = C; A = D; }
combinator(A) ::= .
- { A = 0; }
-combinator(A) ::= PLUS(B).
- { A = B; }
-combinator(A) ::= GT(B).
- { A = B; }
+ { A = COMB_ANCESTOR; }
+combinator(A) ::= PLUS.
+ { A = COMB_PRECEDED; }
+combinator(A) ::= GT.
+ { A = COMB_PARENT; }
simple_selector(A) ::= element_name(B) detail_list(C).
{ A = css_new_node(NODE_SELECTOR, B, C, 0); }
@@ -159,6 +159,7 @@ any(A) ::= LBRAC any_list(B) RBRAC.
%extra_argument { struct css_stylesheet *stylesheet }
%include {
#define CSS_INTERNALS
+#include "netsurf/css/scanner.h"
#include "netsurf/css/css.h"
#include "netsurf/utils/utils.h" }
%name css_parser_
@@ -168,7 +169,7 @@ any(A) ::= LBRAC any_list(B) RBRAC.
%type selector_list { struct node * }
%type selector { struct node * }
-%type combinator { struct node * }
+%type combinator { combinator }
%type simple_selector { struct node * }
%type detail_list { struct node * }
%type declaration_list { struct node * }
@@ -178,7 +179,9 @@ any(A) ::= LBRAC any_list(B) RBRAC.
%type any_list_1 { struct node * }
%type any { struct node * }
+%destructor selector_list { css_free_node($$); }
%destructor selector { css_free_node($$); }
+%destructor simple_selector { css_free_node($$); }
%destructor declaration_list { css_free_node($$); }
%destructor declaration { css_free_node($$); }
%destructor value { css_free_node($$); }
diff --git a/css/ruleset.c b/css/ruleset.c
new file mode 100644
index 000000000..e22a188b8
--- /dev/null
+++ b/css/ruleset.c
@@ -0,0 +1,336 @@
+/**
+ * $Id: ruleset.c,v 1.1 2003/04/04 15:19:31 bursa Exp $
+ */
+
+#include <assert.h>
+#include <stdlib.h>
+#include <string.h>
+#include <strings.h>
+#define CSS_INTERNALS
+#include "netsurf/css/css.h"
+#include "netsurf/utils/log.h"
+#include "netsurf/utils/utils.h"
+
+
+struct property_entry {
+ const char name[20];
+ void (*parse) (struct css_style * const s, const struct node * const v);
+};
+
+struct colour_entry {
+ const char name[12];
+ colour col;
+};
+
+struct font_size_entry {
+ const char name[10];
+ float size;
+};
+
+
+static int parse_length(struct css_length * const length, const struct node * const v);
+static colour parse_colour(const struct node * const v);
+static void parse_background_color(struct css_style * const s, const struct node * const v);
+static void parse_clear(struct css_style * const s, const struct node * const v);
+static void parse_color(struct css_style * const s, const struct node * const v);
+static void parse_display(struct css_style * const s, const struct node * const v);
+static void parse_float(struct css_style * const s, const struct node * const v);
+static void parse_font_size(struct css_style * const s, const struct node * const v);
+static void parse_font_style(struct css_style * const s, const struct node * const v);
+static void parse_font_weight(struct css_style * const s, const struct node * const v);
+static void parse_height(struct css_style * const s, const struct node * const v);
+static void parse_line_height(struct css_style * const s, const struct node * const v);
+static void parse_text_align(struct css_style * const s, const struct node * const v);
+static void parse_width(struct css_style * const s, const struct node * const v);
+
+
+/* table of property parsers: MUST be sorted by property name */
+static const struct property_entry property_table[] = {
+ { "background-color", parse_background_color },
+ { "clear", parse_clear },
+ { "color", parse_color },
+ { "display", parse_display },
+ { "float", parse_float },
+ { "font-size", parse_font_size },
+ { "font-style", parse_font_style },
+ { "font-weight", parse_font_weight },
+ { "height", parse_height },
+ { "line-height", parse_line_height },
+ { "text-align", parse_text_align },
+ { "width", parse_width },
+};
+
+/* table of standard colour names: MUST be sorted by colour name */
+static const struct colour_entry colour_table[] = {
+ { "aqua", 0x00ffff },
+ { "black", 0x000000 },
+ { "blue", 0x0000ff },
+ { "fuchsia", 0xff00ff },
+ { "gray", 0x808080 },
+ { "green", 0x008000 },
+ { "lime", 0x00ff00 },
+ { "maroon", 0x800000 },
+ { "navy", 0x000080 },
+ { "olive", 0x808000 },
+ { "purple", 0x800080 },
+ { "red", 0xff0000 },
+ { "silver", 0xc0c0c0 },
+ { "teal", 0x008080 },
+ { "transparent", TRANSPARENT },
+ { "white", 0xffffff },
+ { "yellow", 0xffff00 },
+};
+
+/* table of font sizes: MUST be sorted by name */
+#define SIZE_FACTOR 1.2
+static const struct font_size_entry font_size_table[] = {
+ { "large", 1.0 * SIZE_FACTOR },
+ { "medium", 1.0 },
+ { "small", 1.0 / SIZE_FACTOR },
+ { "x-large", 1.0 * SIZE_FACTOR * SIZE_FACTOR },
+ { "x-small", 1.0 / (SIZE_FACTOR * SIZE_FACTOR) },
+ { "xx-large", 1.0 * SIZE_FACTOR * SIZE_FACTOR * SIZE_FACTOR },
+ { "xx-small", 1.0 / (SIZE_FACTOR * SIZE_FACTOR * SIZE_FACTOR) },
+};
+
+
+/**
+ * css_add_ruleset -- add a ruleset to a stylesheet
+ */
+
+void css_add_ruleset(struct css_stylesheet *stylesheet,
+ struct node *selector,
+ struct node *declaration)
+{
+ struct node *n, *last;
+ struct css_style *style;
+
+ /* construct the struct css_style */
+ style = xcalloc(1, sizeof(*style));
+ memcpy(style, &css_blank_style, sizeof(*style));
+
+ for (n = declaration; n != 0; n = n->next) {
+ struct property_entry *p;
+ assert(n->type == NODE_DECLARATION && n->data != 0 && n->left != 0);
+ p = bsearch(n->data, property_table,
+ sizeof(property_table) / sizeof(property_table[0]),
+ sizeof(property_table[0]), strcasecmp);
+ if (p == 0)
+ continue;
+ p->parse(style, n->left);
+ }
+
+ /*css_dump_style(style);*/
+
+ /* add selectors to the stylesheet */
+ /* TODO: merge with identical selector */
+ for (n = selector; n != 0; n = n->next) {
+ n->style = style;
+ last = n;
+ }
+
+ if (stylesheet->rule == 0)
+ stylesheet->rule = selector;
+ else
+ stylesheet->last_rule->next = selector;
+ stylesheet->last_rule = last;
+}
+
+
+
+
+/**
+ * property parsers
+ */
+
+int parse_length(struct css_length * const length, const struct node * const v)
+{
+ css_unit u;
+ if (v->type != NODE_DIMENSION)
+ return 1;
+ u = css_unit_parse(v->data + strspn(v->data, "0123456789+-."));
+ if (u == CSS_UNIT_UNKNOWN)
+ return 1;
+ length->unit = u;
+ length->value = atof(v->data);
+ return 0;
+}
+
+
+colour parse_colour(const struct node * const v)
+{
+ colour c = TRANSPARENT;
+ int len;
+ unsigned int r, g, b;
+ struct colour_entry *col;
+
+ switch (v->type) {
+ case NODE_HASH:
+ len = strlen(v->data);
+ if (len == 4) {
+ if (sscanf(v->data + 1, "%1x%1x%1x", &r, &g, &b) == 3)
+ c = (b << 20) | (b << 16) | (g << 12) | (g << 8) | (r << 4) | r;
+ } else if (len == 7) {
+ if (sscanf(v->data + 1, "%2x%2x%2x", &r, &g, &b) == 3)
+ c = (b << 16) | (g << 8) | r;
+ }
+ break;
+
+ case NODE_FUNCTION:
+ /* TODO: rgb(r, g, b) */
+ break;
+
+ case NODE_IDENT:
+ col = bsearch(v->data, colour_table,
+ sizeof(colour_table) / sizeof(colour_table[0]),
+ sizeof(colour_table[0]), strcasecmp);
+ if (col != 0)
+ c = col->col;
+ break;
+
+ default:
+ break;
+ }
+
+ return c;
+}
+
+
+void parse_background_color(struct css_style * const s, const struct node * const v)
+{
+ s->background_color = parse_colour(v);
+}
+
+void parse_clear(struct css_style * const s, const struct node * const v)
+{
+ css_clear z;
+ if (v->type != NODE_IDENT || v->next != 0)
+ return;
+ z = css_clear_parse(v->data);
+ if (z != CSS_CLEAR_UNKNOWN)
+ s->clear = z;
+}
+
+void parse_color(struct css_style * const s, const struct node * const v)
+{
+ s->color = parse_colour(v);
+}
+
+void parse_display(struct css_style * const s, const struct node * const v)
+{
+ css_display z;
+ if (v->type != NODE_IDENT || v->next != 0)
+ return;
+ z = css_display_parse(v->data);
+ if (z != CSS_DISPLAY_UNKNOWN)
+ s->display = z;
+}
+
+void parse_float(struct css_style * const s, const struct node * const v)
+{
+ css_float z;
+ if (v->type != NODE_IDENT || v->next != 0)
+ return;
+ z = css_float_parse(v->data);
+ if (z != CSS_FLOAT_UNKNOWN)
+ s->float_ = z;
+}
+
+void parse_font_size(struct css_style * const s, const struct node * const v)
+{
+ struct font_size_entry *fs;
+ switch (v->type) {
+ case NODE_IDENT:
+ fs = bsearch(v->data, font_size_table,
+ sizeof(font_size_table) / sizeof(font_size_table[0]),
+ sizeof(font_size_table[0]), strcasecmp);
+ if (fs != 0) {
+ s->font_size.size = CSS_FONT_SIZE_LENGTH;
+ s->font_size.value.length.unit = CSS_UNIT_PT;
+ s->font_size.value.length.value = fs->size * 12;
+ } else if (strcasecmp(v->data, "larger") == 0) {
+ s->font_size.size = CSS_FONT_SIZE_PERCENT;
+ s->font_size.value.percent = SIZE_FACTOR * 100;
+ } else if (strcmp(v->data, "smaller") == 0) {
+ s->font_size.size = CSS_FONT_SIZE_PERCENT;
+ s->font_size.value.percent = 1 / SIZE_FACTOR * 100;
+ }
+ break;
+
+ case NODE_PERCENTAGE:
+ s->font_size.size = CSS_FONT_SIZE_PERCENT;
+ s->font_size.value.percent = atof(v->data);
+ break;
+
+ case NODE_DIMENSION:
+ if (parse_length(&s->font_size.value.length, v) == 0)
+ s->font_size.size = CSS_FONT_SIZE_LENGTH;
+ break;
+
+ default:
+ break;
+ }
+}
+
+void parse_font_style(struct css_style * const s, const struct node * const v)
+{
+ css_font_style z;
+ if (v->type != NODE_IDENT || v->next != 0)
+ return;
+ z = css_font_style_parse(v->data);
+ if (z != CSS_FONT_STYLE_UNKNOWN)
+ s->font_style = z;
+}
+
+void parse_font_weight(struct css_style * const s, const struct node * const v)
+{
+ css_font_weight z;
+ if (v->type != NODE_IDENT || v->next != 0)
+ return;
+ z = css_font_weight_parse(v->data);
+ if (z != CSS_FONT_WEIGHT_UNKNOWN)
+ s->font_weight = z;
+}
+void parse_height(struct css_style * const s, const struct node * const v)
+{
+ if (v->type == NODE_IDENT && strcasecmp(v->data, "auto") == 0)
+ s->height.height = CSS_HEIGHT_AUTO;
+ else if (v->type == NODE_DIMENSION && parse_length(&s->height.length, v) == 0)
+ s->height.height = CSS_HEIGHT_LENGTH;
+}
+
+void parse_line_height(struct css_style * const s, const struct node * const v)
+{
+ if (v->type == NODE_IDENT && strcasecmp(v->data, "normal") == 0) {
+ s->line_height.size = CSS_LINE_HEIGHT_ABSOLUTE;
+ s->line_height.value.absolute = 1.0;
+ } else if (v->type == NODE_PERCENTAGE) {
+ s->line_height.size = CSS_LINE_HEIGHT_PERCENT;
+ s->line_height.value.percent = atof(v->data);
+ } else if (v->type == NODE_DIMENSION &&
+ parse_length(&s->line_height.value.length, v) == 0) {
+ s->line_height.size = CSS_LINE_HEIGHT_LENGTH;
+ }
+}
+
+void parse_text_align(struct css_style * const s, const struct node * const v)
+{
+ css_text_align z;
+ if (v->type != NODE_IDENT || v->next != 0)
+ return;
+ z = css_text_align_parse(v->data);
+ if (z != CSS_TEXT_ALIGN_UNKNOWN)
+ s->text_align = z;
+}
+
+void parse_width(struct css_style * const s, const struct node * const v)
+{
+ if (v->type == NODE_IDENT && strcasecmp(v->data, "auto") == 0)
+ s->width.width = CSS_WIDTH_AUTO;
+ else if (v->type == NODE_PERCENTAGE) {
+ s->width.width = CSS_WIDTH_PERCENT;
+ s->width.value.percent = atof(v->data);
+ } else if (v->type == NODE_DIMENSION &&
+ parse_length(&s->width.value.length, v) == 0)
+ s->width.width = CSS_WIDTH_LENGTH;
+}