From aa6e904604cde92ff4883725caa69472be9159aa Mon Sep 17 00:00:00 2001 From: James Bursa Date: Fri, 25 Jun 2004 14:28:29 +0000 Subject: [project @ 2004-06-25 14:28:29 by bursa] Parse CSS background shorthand property. Background rendering improvements. svn path=/import/netsurf/; revision=1006 --- css/css.c | 7 +- css/css.h | 76 ++++++------- css/ruleset.c | 357 +++++++++++++++++++++++++++++++++++++++------------------- 3 files changed, 285 insertions(+), 155 deletions(-) (limited to 'css') diff --git a/css/css.c b/css/css.c index b4d05c2b6..66d0c7d4d 100644 --- a/css/css.c +++ b/css/css.c @@ -1005,10 +1005,10 @@ void css_dump_style(const struct css_style * const style) break; } fprintf(stderr, " %s %s ", - css_background_attachment_name[ - style->background_attachment], css_background_repeat_name[ - style->background_repeat]); + style->background_repeat], + css_background_attachment_name[ + style->background_attachment]); switch (style->background_position.horz.pos) { case CSS_BACKGROUND_POSITION_LENGTH: css_dump_length(&style->background_position. @@ -1038,6 +1038,7 @@ void css_dump_style(const struct css_style * const style) vert.value.percent); break; case CSS_BACKGROUND_POSITION_INHERIT: + fprintf(stderr, "inherit"); break; default: fprintf(stderr, "UNKNOWN"); diff --git a/css/css.h b/css/css.h index c2ff62ef0..f134f75df 100644 --- a/css/css.h +++ b/css/css.h @@ -54,42 +54,42 @@ typedef enum { } css_text_decoration; typedef enum { - CSS_BACKGROUND_POSITION_LENGTH, - CSS_BACKGROUND_POSITION_PERCENT, - CSS_BACKGROUND_POSITION_INHERIT -} css_background_position; + CSS_BACKGROUND_IMAGE_NONE, + CSS_BACKGROUND_IMAGE_INHERIT, + CSS_BACKGROUND_IMAGE_URI +} css_background_image_type; + +/** Part of struct css_style, for convenience. */ +struct css_background_position { + enum { + CSS_BACKGROUND_POSITION_LENGTH, + CSS_BACKGROUND_POSITION_PERCENT, + CSS_BACKGROUND_POSITION_INHERIT + } pos; + union { + float percent; + struct css_length length; + } value; +}; + /** Representation of a complete CSS 2 style. */ struct css_style { colour background_color; - css_background_attachment background_attachment; + css_background_attachment background_attachment; struct { - enum { CSS_BACKGROUND_IMAGE_NONE, - CSS_BACKGROUND_IMAGE_INHERIT, - CSS_BACKGROUND_IMAGE_URI } type; - char *uri; + css_background_image_type type; + char *uri; } background_image; - struct { - struct { - css_background_position pos; - union { - float percent; - struct css_length length; - } value; - } horz; - struct { - css_background_position pos; - union { - float percent; - struct css_length length; - } value; - } vert; - } background_position; - - css_background_repeat background_repeat; + struct { + struct css_background_position horz; + struct css_background_position vert; + } background_position; + + css_background_repeat background_repeat; struct { colour color; @@ -119,7 +119,7 @@ struct css_style { } value; } font_size; - css_font_family font_family; + css_font_family font_family; css_font_weight font_weight; css_font_style font_style; css_font_variant font_variant; @@ -167,14 +167,14 @@ struct css_style { css_text_align text_align; css_text_decoration text_decoration; struct { - enum { CSS_TEXT_INDENT_INHERIT, - CSS_TEXT_INDENT_LENGTH, - CSS_TEXT_INDENT_PERCENT } size; - union { - struct css_length length; - float percent; - } value ; - } text_indent; + enum { CSS_TEXT_INDENT_INHERIT, + CSS_TEXT_INDENT_LENGTH, + CSS_TEXT_INDENT_PERCENT } size; + union { + struct css_length length; + float percent; + } value ; + } text_indent; css_text_transform text_transform; css_visibility visibility; @@ -317,7 +317,7 @@ void css_destroy(struct content *c); #ifdef CSS_INTERNALS struct css_node * css_new_node(struct content *stylesheet, - css_node_type type, + css_node_type type, const char *data, unsigned int data_length); void css_free_node(struct css_node *node); struct css_selector * css_new_selector(css_selector_type type, @@ -349,7 +349,7 @@ void css_cascade(struct css_style * const style, void css_merge(struct css_style * const style, const struct css_style * const apply); void css_parse_property_list(struct content *c, struct css_style * style, - char * str); + char * str); colour named_colour(const char *name); void css_dump_style(const struct css_style * const style); void css_dump_stylesheet(const struct css_stylesheet * stylesheet); diff --git a/css/ruleset.c b/css/ruleset.c index e842ec59a..38418e2e0 100644 --- a/css/ruleset.c +++ b/css/ruleset.c @@ -11,6 +11,10 @@ * This file implements the last stage of CSS parsing. It converts trees of * struct css_node produced by the parser into struct style, and adds them to a * stylesheet. + * + * This code is complicated by the CSS error handling rules. According to + * CSS 2.1 4.2 "Illegal values", the whole of a declaration must be legal for + * any of it to be used. */ #include @@ -34,13 +38,21 @@ static int parse_length(struct css_length * const length, const struct css_node * const v, bool non_negative); static colour parse_colour(const struct css_node * const v); static colour css_parse_rgb(struct css_node *v); -static void parse_background(struct css_style * const s, const struct css_node * v); +static void parse_background(struct css_style * const s, + const struct css_node * v); static void parse_background_attachment(struct css_style * const s, const struct css_node * const v); static void parse_background_color(struct css_style * const s, const struct css_node * const v); -static void parse_background_image(struct css_style * const s, const struct css_node * const v); +static void parse_background_image(struct css_style * const s, + const struct css_node * const v); +static bool css_background_image_parse(const struct css_node *v, + css_background_image_type *type, char **uri); static struct css_background_entry *css_background_lookup( const struct css_node *v); -static void parse_background_position(struct css_style * const s, const struct css_node * const v); +static void parse_background_position(struct css_style * const s, + const struct css_node * const v); +static bool css_background_position_parse(const struct css_node **node, + struct css_background_position *horz, + struct css_background_position *vert); static void parse_background_repeat(struct css_style * const s, const struct css_node * const v); static void parse_border(struct css_style * const s, const struct css_node * v); static void parse_border_bottom(struct css_style * const s, const struct css_node * v); @@ -522,52 +534,113 @@ colour css_parse_rgb(struct css_node *v) } -void parse_background(struct css_style * const s, const struct css_node * v) +/** + * \name Individual property parsers. + * \{ + */ + +void parse_background(struct css_style * const s, + const struct css_node * v) { - colour c; - css_background_attachment ba; - css_background_repeat br; - for (; v; v = v->next) { + colour c = TRANSPARENT, c2; + css_background_image_type bi = CSS_BACKGROUND_IMAGE_NONE, bi2; + char *bi_uri = 0; + css_background_repeat br = CSS_BACKGROUND_REPEAT_REPEAT, br2; + css_background_attachment ba = CSS_BACKGROUND_ATTACHMENT_SCROLL, ba2; + struct css_background_position horz = + { CSS_BACKGROUND_POSITION_PERCENT, { 0 } }; + struct css_background_position vert = + { CSS_BACKGROUND_POSITION_PERCENT, { 0 } }; + struct css_background_position horz2, vert2; + + while (v) { switch (v->type) { - /**\todo background-position */ case CSS_NODE_URI: case CSS_NODE_STRING: - parse_background_image(s, v); + /* background-image */ + if (!css_background_image_parse(v, &bi2, + &bi_uri)) + return; + bi = bi2; + v = v->next; break; - /*case CSS_NODE_DIMENSION: + + case CSS_NODE_DIMENSION: case CSS_NODE_PERCENTAGE: - parse_background_position(s, v); - v = v->naxt; - break;*/ + /* background-position */ + if (!css_background_position_parse(&v, + &horz2, &vert2)) + return; + horz = horz2; + vert = vert2; + break; + case CSS_NODE_IDENT: - /* background-attachment */ - ba = css_background_attachment_parse(v->data, v->data_length); - if (ba != CSS_BACKGROUND_ATTACHMENT_UNKNOWN) { - s->background_attachment = ba; + /* could be background-image: none */ + if (v->data_length == 4 && + strncasecmp(v->data, "none", + 4) == 0) { + bi = CSS_BACKGROUND_IMAGE_NONE; + v = v->next; break; } /* background-repeat */ - br = css_background_repeat_parse(v->data, v->data_length); - if (br != CSS_BACKGROUND_REPEAT_UNKNOWN) { - s->background_repeat = br; + br2 = css_background_repeat_parse(v->data, + v->data_length); + if (br2 != CSS_BACKGROUND_REPEAT_UNKNOWN) { + br = br2; + v = v->next; + break; + } + + /* background-attachment */ + ba2 = css_background_attachment_parse(v->data, + v->data_length); + if (ba2 != CSS_BACKGROUND_ATTACHMENT_UNKNOWN) { + ba = ba2; + v = v->next; + break; + } + + /* background-position */ + if (css_background_position_parse(&v, + &horz2, &vert2)) { + horz = horz2; + vert = vert2; break; } /* fall through */ case CSS_NODE_HASH: case CSS_NODE_FUNCTION: - c = parse_colour(v); - if (c != CSS_COLOR_NONE) - s->background_color = c; - break; + /* background-color */ + c2 = parse_colour(v); + if (c2 != CSS_COLOR_NONE) { + c = c2; + v = v->next; + break; + } + + /* fall through */ default: - break; + /* parsing failed */ + return; } } + + s->background_color = c; + s->background_image.type = bi; + s->background_image.uri = bi_uri; + s->background_repeat = br; + s->background_attachment = ba; + s->background_position.horz = horz; + s->background_position.vert = vert; } -void parse_background_attachment(struct css_style * const s, const struct css_node * const v) + +void parse_background_attachment(struct css_style * const s, + const struct css_node * const v) { css_background_attachment z; if (v->type != CSS_NODE_IDENT || v->next != 0) @@ -577,19 +650,51 @@ void parse_background_attachment(struct css_style * const s, const struct css_no s->background_attachment = z; } -void parse_background_color(struct css_style * const s, const struct css_node * const v) + +void parse_background_color(struct css_style * const s, + const struct css_node * const v) { - colour c = parse_colour(v); + colour c; + if (v->next) + return; + c = parse_colour(v); if (c != CSS_COLOR_NONE) s->background_color = c; } -void parse_background_image(struct css_style * const s, const struct css_node * const v) + +void parse_background_image(struct css_style * const s, + const struct css_node * const v) +{ + css_background_image_type type; + char *uri = 0; + + if (v->next) + return; + if (!css_background_image_parse(v, &type, &uri)) + return; + + s->background_image.type = type; + s->background_image.uri = uri; +} + + +/** + * Parse a background-image property. + * + * \param node node to parse + * \param type updated to background image type + * \param uri updated to background image uri, if type is + * CSS_BACKGROUND_IMAGE_URI + * \return true on success, false on parse failure + */ + +bool css_background_image_parse(const struct css_node *v, + css_background_image_type *type, char **uri) { bool string = false; const char *u; char *t, *url; - s->background_image.uri = 0; switch (v->type) { case CSS_NODE_URI: @@ -603,9 +708,8 @@ void parse_background_image(struct css_style * const s, const struct css_node * u++; } url = strndup(u, v->data_length - (u - v->data)); - if (!url) { - return; - } + if (!url) + return false; for (t = url + strlen(url) - 2; *t == ' ' || *t == '\t' || *t == '\r' || *t == '\n' || *t == '\f'; @@ -620,32 +724,37 @@ void parse_background_image(struct css_style * const s, const struct css_node * * content is the parent HTML content */ if (v->stylesheet->type == CONTENT_HTML) - s->background_image.uri = url_join(url, v->stylesheet->data.html.base_url); + *uri = url_join(url, v->stylesheet->data.html.base_url); else - s->background_image.uri = url_join(url, v->stylesheet->url); + *uri = url_join(url, v->stylesheet->url); free(url); - if (!s->background_image.uri) return; - s->background_image.type = CSS_BACKGROUND_IMAGE_URI; + if (!*uri) + return false; + *type = CSS_BACKGROUND_IMAGE_URI; break; case CSS_NODE_STRING: url = strndup(v->data, v->data_length); if (!url) - return; + return false; - s->background_image.uri = url_join(url, v->stylesheet->url); + *uri = url_join(url, v->stylesheet->url); free(url); - if (!s->background_image.uri) return; - s->background_image.type = CSS_BACKGROUND_IMAGE_URI; + if (!*uri) + return false; + *type = CSS_BACKGROUND_IMAGE_URI; break; case CSS_NODE_IDENT: - if (v->data_length == 7 && strncasecmp(v->data, "inherit", 7) == 0) - s->background_image.type = CSS_BACKGROUND_IMAGE_INHERIT; - else if (v->data_length == 4 && strncasecmp(v->data, "none", 4) == 0) - s->background_image.type = CSS_BACKGROUND_IMAGE_NONE; + if (v->data_length == 7 && + strncasecmp(v->data, "inherit", 7) == 0) + *type = CSS_BACKGROUND_IMAGE_INHERIT; + else if (v->data_length == 4 && + strncasecmp(v->data, "none", 4) == 0) + *type = CSS_BACKGROUND_IMAGE_NONE; break; default: - break; + return false; } + return true; } @@ -695,128 +804,146 @@ struct css_background_entry *css_background_lookup( void parse_background_position(struct css_style * const s, const struct css_node * v) { - struct css_node *w = v->next; - struct css_background_entry *bg = 0, *bg2 = 0; + const struct css_node *node = v; + struct css_background_position horz, vert; - if (w && w->next) + if (v->next && v->next->next) + /* more than two nodes */ return; - if (!w) { /* only one value specified */ + if (!css_background_position_parse(&node, &horz, &vert)) + return; + if (node) + /* didn't parse all the nodes */ + return; + + s->background_position.horz = horz; + s->background_position.vert = vert; +} + + +/** + * Parse a background-position property. + * + * \param node list of nodes, updated to first unused node + * \param horz updated to horizontal background position + * \param vert updated to vertical background position + * \return true on success, false on parse failure + */ + +bool css_background_position_parse(const struct css_node **node, + struct css_background_position *horz, + struct css_background_position *vert) +{ + const struct css_node *v = *node; + const struct css_node *w = v->next; + struct css_background_entry *bg = 0, *bg2 = 0; + + if (v->type == CSS_NODE_IDENT) + bg = css_background_lookup(v); + if (w && w->type == CSS_NODE_IDENT) + bg2 = css_background_lookup(w); + + if (!(w && ((w->type == CSS_NODE_IDENT && bg2) || + w->type == CSS_NODE_PERCENTAGE || + w->type == CSS_NODE_DIMENSION))) { + /* only one value specified */ if (v->type == CSS_NODE_IDENT) { if (v->data_length == 7 && strncasecmp(v->data, "inherit", 7) == 0) { - s->background_position.horz.pos = - s->background_position.vert.pos = + horz->pos = vert->pos = CSS_BACKGROUND_POSITION_INHERIT; - return; + return false; } - bg = css_background_lookup(v); if (!bg) - return; - s->background_position.horz.pos = - s->background_position.vert.pos = - CSS_BACKGROUND_POSITION_PERCENT; - s->background_position.horz.value.percent = - bg->horizontal ? bg->value : 50; - s->background_position.vert.value.percent = - bg->vertical ? bg->value : 50; + return false; + horz->pos = vert->pos = CSS_BACKGROUND_POSITION_PERCENT; + horz->value.percent = bg->horizontal ? bg->value : 50; + vert->value.percent = bg->vertical ? bg->value : 50; } else if (v->type == CSS_NODE_PERCENTAGE) { - s->background_position.horz.pos = - s->background_position.vert.pos = - CSS_BACKGROUND_POSITION_PERCENT; - s->background_position.horz.value.percent = - atof(v->data); - s->background_position.vert.value.percent = 50.0; + horz->pos = vert->pos = CSS_BACKGROUND_POSITION_PERCENT; + horz->value.percent = atof(v->data); + vert->value.percent = 50.0; } else if (v->type == CSS_NODE_DIMENSION) { - if (parse_length(&s->background_position.horz.value. + if (parse_length(&horz->value. length, v, false) == 0) { - s->background_position.horz.pos = - CSS_BACKGROUND_POSITION_LENGTH; - s->background_position.vert.pos = - CSS_BACKGROUND_POSITION_PERCENT; - s->background_position.vert.value.percent = - 50.0; + horz->pos = CSS_BACKGROUND_POSITION_LENGTH; + vert->pos = CSS_BACKGROUND_POSITION_PERCENT; + vert->value.percent = 50.0; } } - return; + *node = w; + return true; } /* two values specified */ if (v->type == CSS_NODE_IDENT && w->type == CSS_NODE_IDENT) { /* both keywords */ - bg = css_background_lookup(v); - bg2 = css_background_lookup(w); if (!bg || !bg2) - return; + return false; if ((bg->horizontal && bg2->horizontal) || (bg->vertical && bg2->vertical)) - return; - s->background_position.horz.pos = - s->background_position.vert.pos = - CSS_BACKGROUND_POSITION_PERCENT; - s->background_position.horz.value.percent = - s->background_position.vert.value.percent = 50; + return false; + horz->pos = vert->pos = CSS_BACKGROUND_POSITION_PERCENT; + horz->value.percent = vert->value.percent = 50; if (bg->horizontal) - s->background_position.horz.value.percent = bg->value; + horz->value.percent = bg->value; else if (bg2->horizontal) - s->background_position.horz.value.percent = bg2->value; + horz->value.percent = bg2->value; if (bg->vertical) - s->background_position.vert.value.percent = bg->value; + vert->value.percent = bg->value; else if (bg2->vertical) - s->background_position.vert.value.percent = bg2->value; + vert->value.percent = bg2->value; - return; + *node = w->next; + return true; } if (v->type == CSS_NODE_IDENT) { /* horizontal value */ - bg = css_background_lookup(v); if (!bg || bg->vertical) - return; + return false; } if (w->type == CSS_NODE_IDENT) { /* vertical value */ - bg2 = css_background_lookup(w); if (!bg2 || bg2->horizontal) - return; + return false; } if (v->type == CSS_NODE_IDENT) { /* horizontal value */ - s->background_position.horz.pos = - CSS_BACKGROUND_POSITION_PERCENT; - s->background_position.horz.value.percent = bg->value; + horz->pos = CSS_BACKGROUND_POSITION_PERCENT; + horz->value.percent = bg->value; } else if (v->type == CSS_NODE_PERCENTAGE) { - s->background_position.horz.pos = - CSS_BACKGROUND_POSITION_PERCENT; - s->background_position.horz.value.percent = atof(v->data); + horz->pos = CSS_BACKGROUND_POSITION_PERCENT; + horz->value.percent = atof(v->data); } else if (v->type == CSS_NODE_DIMENSION) { - if (parse_length(&s->background_position.horz.value.length, + if (parse_length(&horz->value.length, v, false) == 0) - s->background_position.horz.pos = - CSS_BACKGROUND_POSITION_LENGTH; + horz->pos = CSS_BACKGROUND_POSITION_LENGTH; } if (w->type == CSS_NODE_IDENT) { /* vertical value */ - s->background_position.vert.pos = - CSS_BACKGROUND_POSITION_PERCENT; - s->background_position.vert.value.percent = bg2->value; + vert->pos = CSS_BACKGROUND_POSITION_PERCENT; + vert->value.percent = bg2->value; } else if (w->type == CSS_NODE_PERCENTAGE) { - s->background_position.vert.pos = - CSS_BACKGROUND_POSITION_PERCENT; - s->background_position.vert.value.percent = atof(w->data); + vert->pos = CSS_BACKGROUND_POSITION_PERCENT; + vert->value.percent = atof(w->data); } else if (w->type == CSS_NODE_DIMENSION) { - if (parse_length(&s->background_position.vert.value.length, + if (parse_length(&vert->value.length, w, false) == 0) - s->background_position.vert.pos = - CSS_BACKGROUND_POSITION_LENGTH; + vert->pos = CSS_BACKGROUND_POSITION_LENGTH; } + + *node = w->next; + return true; } -void parse_background_repeat(struct css_style * const s, const struct css_node * const v) +void parse_background_repeat(struct css_style * const s, + const struct css_node * const v) { css_background_repeat z; if (v->type != CSS_NODE_IDENT || v->next != 0) @@ -826,6 +953,7 @@ void parse_background_repeat(struct css_style * const s, const struct css_node * s->background_repeat = z; } + void parse_border_width(struct css_style * const s, const struct css_node * const v) { @@ -1616,3 +1744,4 @@ css_text_decoration css_text_decoration_parse(const char * const s, return CSS_TEXT_DECORATION_UNKNOWN; } +/** \} */ -- cgit v1.2.3