From 78594f3f60a2ce28f1d6ee95676bfa10492320fe Mon Sep 17 00:00:00 2001 From: John Mark Bell Date: Wed, 9 Jun 2004 19:55:06 +0000 Subject: [project @ 2004-06-09 19:55:06 by jmb] Implement background-image, background-repeat, background-position and background-attachment CSS properties. background-attachment and background-position need more work. Some redraw issues remain. svn path=/import/netsurf/; revision=938 --- css/css.c | 55 ++++++++++- css/css.h | 38 ++++++- css/css_enums | 3 +- css/parser.y | 58 +++++++---- css/ruleset.c | 277 +++++++++++++++++++++++++++++++++++++++++++++++++++- render/box.c | 72 +++++++++----- render/box.h | 4 + render/html.c | 21 +++- render/html.h | 2 + riscos/htmlredraw.c | 125 +++++++++++++++++++++++- 10 files changed, 597 insertions(+), 58 deletions(-) diff --git a/css/css.c b/css/css.c index ebf446dba..c42ad3d21 100644 --- a/css/css.c +++ b/css/css.c @@ -103,6 +103,11 @@ static void css_dump_selector(const struct css_selector *r); * spec. */ const struct css_style css_base_style = { 0xffffff, + CSS_BACKGROUND_ATTACHMENT_SCROLL, + { CSS_BACKGROUND_IMAGE_NONE, 0 }, + { { CSS_BACKGROUND_POSITION_PERCENT, { 0.0 } }, + { CSS_BACKGROUND_POSITION_PERCENT, { 0.0 } } }, + CSS_BACKGROUND_REPEAT_REPEAT, { { 0x000000, { CSS_BORDER_WIDTH_LENGTH, { 2, CSS_UNIT_PX } }, CSS_BORDER_STYLE_NONE }, { 0x000000, { CSS_BORDER_WIDTH_LENGTH, @@ -143,6 +148,11 @@ const struct css_style css_base_style = { /** Style with no values set. */ const struct css_style css_empty_style = { CSS_COLOR_INHERIT, + CSS_BACKGROUND_ATTACHMENT_INHERIT, + { CSS_BACKGROUND_IMAGE_INHERIT, 0 }, + { { CSS_BACKGROUND_POSITION_INHERIT, { 0.0 } }, + { CSS_BACKGROUND_POSITION_INHERIT, { 0.0 } } }, + CSS_BACKGROUND_REPEAT_INHERIT, { { CSS_COLOR_INHERIT, { CSS_BORDER_WIDTH_INHERIT, { 0, CSS_UNIT_PX } }, CSS_BORDER_STYLE_INHERIT }, { CSS_COLOR_INHERIT, { CSS_BORDER_WIDTH_INHERIT, @@ -184,6 +194,11 @@ const struct css_style css_empty_style = { * and the 'Initial value' otherwise. */ const struct css_style css_blank_style = { TRANSPARENT, + CSS_BACKGROUND_ATTACHMENT_SCROLL, + { CSS_BACKGROUND_IMAGE_NONE, 0 }, + { { CSS_BACKGROUND_POSITION_PERCENT, { 0.0 } }, + { CSS_BACKGROUND_POSITION_PERCENT, { 0.0 } } }, + CSS_BACKGROUND_REPEAT_REPEAT, { { 0x000000, { CSS_BORDER_WIDTH_LENGTH, { 2, CSS_UNIT_PX } }, CSS_BORDER_STYLE_NONE }, { 0x000000, { CSS_BORDER_WIDTH_LENGTH, @@ -332,8 +347,11 @@ void css_destroy(struct content *c) struct css_selector *r; for (i = 0; i != HASH_SIZE; i++) { - for (r = c->data.css.css->rule[i]; r != 0; r = r->next) + for (r = c->data.css.css->rule[i]; r != 0; r = r->next) { + if (r->style->background_image.uri != NULL) + free(r->style->background_image.uri); free(r->style); + } css_free_selector(c->data.css.css->rule[i]); } free(c->data.css.css); @@ -361,7 +379,8 @@ void css_destroy(struct content *c) * Used by the parser. */ -struct css_node * css_new_node(css_node_type type, +struct css_node * css_new_node(struct content *stylesheet, + css_node_type type, const char *data, unsigned int data_length) { struct css_node *node = malloc(sizeof *node); @@ -375,6 +394,7 @@ struct css_node * css_new_node(css_node_type type, node->comb = CSS_COMB_NONE; node->style = 0; node->specificity = 0; + node->stylesheet = stylesheet; return node; } @@ -976,7 +996,9 @@ void css_dump_style(const struct css_style * const style) if (style->z != css_empty_style.z) \ fprintf(stderr, s ": %s; ", n[style->z]); + DUMP_KEYWORD(background_attachment, "background-attachment", css_background_attachment_name); DUMP_COLOR(background_color, "background-color"); + DUMP_KEYWORD(background_repeat, "background-repeat", css_background_repeat_name); DUMP_KEYWORD(clear, "clear", css_clear_name); DUMP_COLOR(color, "color"); DUMP_KEYWORD(cursor, "cursor", css_cursor_name); @@ -1294,9 +1316,14 @@ void css_cascade(struct css_style * const style, style->text_decoration = apply->text_decoration; /* if (style->display == CSS_DISPLAY_INLINE && apply->display != CSS_DISPLAY_INLINE) style->text_decoration = CSS_TEXT_DECORATION_NONE;*/ - + if (apply->background_attachment != CSS_BACKGROUND_ATTACHMENT_INHERIT) + style->background_attachment = apply->background_attachment; if (apply->background_color != CSS_COLOR_INHERIT) style->background_color = apply->background_color; + if (apply->background_image.type != CSS_BACKGROUND_IMAGE_INHERIT) + style->background_image = apply->background_image; + if (apply->background_repeat != CSS_BACKGROUND_REPEAT_INHERIT) + style->background_repeat = apply->background_repeat; if (apply->clear != CSS_CLEAR_INHERIT) style->clear = apply->clear; if (apply->color != CSS_COLOR_INHERIT) @@ -1332,6 +1359,14 @@ void css_cascade(struct css_style * const style, if (apply->white_space != CSS_WHITE_SPACE_INHERIT) style->white_space = apply->white_space; + /* background-position */ + if (apply->background_position.horz.pos != CSS_BACKGROUND_POSITION_INHERIT) { + style->background_position.horz = apply->background_position.horz; + } + if (apply->background_position.vert.pos != CSS_BACKGROUND_POSITION_INHERIT) { + style->background_position.vert = apply->background_position.vert; + } + /* font-size */ f = apply->font_size.value.percent / 100; switch (apply->font_size.size) { @@ -1402,8 +1437,14 @@ void css_merge(struct css_style * const style, { unsigned int i; + if (apply->background_attachment != CSS_BACKGROUND_ATTACHMENT_INHERIT) + style->background_attachment = apply->background_attachment; if (apply->background_color != CSS_COLOR_INHERIT) style->background_color = apply->background_color; + if (apply->background_image.type != CSS_BACKGROUND_IMAGE_INHERIT) + style->background_image = apply->background_image; + if (apply->background_repeat != CSS_BACKGROUND_REPEAT_INHERIT) + style->background_repeat = apply->background_repeat; if (apply->clear != CSS_CLEAR_INHERIT) style->clear = apply->clear; if (apply->color != CSS_COLOR_INHERIT) @@ -1443,6 +1484,14 @@ void css_merge(struct css_style * const style, if (apply->white_space != CSS_WHITE_SPACE_INHERIT) style->white_space = apply->white_space; + /* background-position */ + if (apply->background_position.horz.pos != CSS_BACKGROUND_POSITION_INHERIT) { + style->background_position.horz = apply->background_position.horz; + } + if (apply->background_position.vert.pos != CSS_BACKGROUND_POSITION_INHERIT) { + style->background_position.vert = apply->background_position.vert; + } + for (i = 0; i != 4; i++) { if (apply->border[i].color != CSS_COLOR_INHERIT) style->border[i].color = apply->border[i].color; diff --git a/css/css.h b/css/css.h index 14c53a065..d80df9333 100644 --- a/css/css.h +++ b/css/css.h @@ -53,10 +53,44 @@ typedef enum { CSS_TEXT_DECORATION_UNKNOWN = 0x1000 } css_text_decoration; +typedef enum { + CSS_BACKGROUND_POSITION_LENGTH, + CSS_BACKGROUND_POSITION_PERCENT, + CSS_BACKGROUND_POSITION_INHERIT +} css_background_position; + /** Representation of a complete CSS 2 style. */ struct css_style { colour background_color; + css_background_attachment background_attachment; + + struct { + enum { CSS_BACKGROUND_IMAGE_NONE, + CSS_BACKGROUND_IMAGE_INHERIT, + CSS_BACKGROUND_IMAGE_URI } 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 { colour color; struct { @@ -246,6 +280,7 @@ struct css_node { css_combinator comb; struct css_style *style; unsigned long specificity; + struct content *stylesheet; }; @@ -282,7 +317,8 @@ void css_destroy(struct content *c); #ifdef CSS_INTERNALS -struct css_node * css_new_node(css_node_type type, +struct css_node * css_new_node(struct content *stylesheet, + 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, diff --git a/css/css_enums b/css/css_enums index 2cccda18a..9df8c81aa 100644 --- a/css/css_enums +++ b/css/css_enums @@ -1,7 +1,6 @@ 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_background_repeat inherit repeat repeat-x repeat-y no-repeat css_border_style inherit none hidden dotted dashed solid double groove ridge inset outset css_clear inherit none both left right css_cursor inherit auto crosshair default pointer move e-resize ne-resize nw-resize n-resize se-resize sw-resize s-resize w-resize text wait help diff --git a/css/parser.y b/css/parser.y index fc7a56289..b0f0aeba3 100644 --- a/css/parser.y +++ b/css/parser.y @@ -211,7 +211,8 @@ declaration_list(A) ::= declaration(B) SEMI declaration_list(C). { if (B) { B->next = C; A = B; } else { A = C; } } declaration(A) ::= property(B) COLON value(C). - { if (C && (A = css_new_node(CSS_NODE_DECLARATION, + { if (C && (A = css_new_node(param->stylesheet, + CSS_NODE_DECLARATION, B.text, B.length))) A->value = C; else { @@ -245,58 +246,71 @@ any_list_1(A) ::= any(B) any_list(C). { if (B) { B->next = C; A = B; } else { css_free_node(B); css_free_node(C); A = 0; } } any(A) ::= IDENT(B). - { A = css_new_node(CSS_NODE_IDENT, B.text, B.length); + { A = css_new_node(param->stylesheet, CSS_NODE_IDENT, + B.text, B.length); if (!A) param->memory_error = true; } any(A) ::= NUMBER(B). - { A = css_new_node(CSS_NODE_NUMBER, B.text, B.length); + { A = css_new_node(param->stylesheet, CSS_NODE_NUMBER, + B.text, B.length); if (!A) param->memory_error = true; } any(A) ::= PERCENTAGE(B). - { A = css_new_node(CSS_NODE_PERCENTAGE, B.text, B.length); + { A = css_new_node(param->stylesheet, CSS_NODE_PERCENTAGE, + B.text, B.length); if (!A) param->memory_error = true; } any(A) ::= DIMENSION(B). - { A = css_new_node(CSS_NODE_DIMENSION, B.text, B.length); + { A = css_new_node(param->stylesheet, CSS_NODE_DIMENSION, + B.text, B.length); if (!A) param->memory_error = true; } any(A) ::= STRING(B). - { A = css_new_node(CSS_NODE_STRING, B.text + 1, B.length - 2); + { A = css_new_node(param->stylesheet, CSS_NODE_STRING, + B.text + 1, B.length - 2); if (!A) param->memory_error = true; } any(A) ::= DELIM(B). - { A = css_new_node(CSS_NODE_DELIM, B.text, B.length); + { A = css_new_node(param->stylesheet, CSS_NODE_DELIM, + B.text, B.length); if (!A) param->memory_error = true; } any(A) ::= URI(B). - { A = css_new_node(CSS_NODE_URI, B.text, B.length); + { A = css_new_node(param->stylesheet, CSS_NODE_URI, + B.text, B.length); if (!A) param->memory_error = true; } any(A) ::= HASH(B). - { A = css_new_node(CSS_NODE_HASH, B.text, B.length); + { A = css_new_node(param->stylesheet, CSS_NODE_HASH, + B.text, B.length); if (!A) param->memory_error = true; } any(A) ::= UNICODE_RANGE(B). - { A = css_new_node(CSS_NODE_UNICODE_RANGE, B.text, B.length); + { A = css_new_node(param->stylesheet, CSS_NODE_UNICODE_RANGE, + B.text, B.length); if (!A) param->memory_error = true; } any(A) ::= INCLUDES. - { A = css_new_node(CSS_NODE_INCLUDES, 0, 0); + { A = css_new_node(param->stylesheet, CSS_NODE_INCLUDES, + 0, 0); if (!A) param->memory_error = true; } any(A) ::= FUNCTION(B). - { A = css_new_node(CSS_NODE_FUNCTION, B.text, B.length); + { A = css_new_node(param->stylesheet, CSS_NODE_FUNCTION, + B.text, B.length); if (!A) param->memory_error = true; } any(A) ::= DASHMATCH. - { A = css_new_node(CSS_NODE_DASHMATCH, 0, 0); + { A = css_new_node(param->stylesheet, CSS_NODE_DASHMATCH, + 0, 0); if (!A) param->memory_error = true; } any(A) ::= COLON. - { A = css_new_node(CSS_NODE_COLON, 0, 0); + { A = css_new_node(param->stylesheet, CSS_NODE_COLON, 0, 0); if (!A) param->memory_error = true; } any(A) ::= COMMA. - { A = css_new_node(CSS_NODE_COMMA, 0, 0); + { A = css_new_node(param->stylesheet, CSS_NODE_COMMA, 0, 0); if (!A) param->memory_error = true; } any(A) ::= DOT. - { A = css_new_node(CSS_NODE_DOT, 0, 0); + { A = css_new_node(param->stylesheet, CSS_NODE_DOT, 0, 0); if (!A) param->memory_error = true; } any(A) ::= PLUS. - { A = css_new_node(CSS_NODE_PLUS, 0, 0); + { A = css_new_node(param->stylesheet, CSS_NODE_PLUS, 0, 0); if (!A) param->memory_error = true; } any(A) ::= GT. - { A = css_new_node(CSS_NODE_GT, 0, 0); + { A = css_new_node(param->stylesheet, CSS_NODE_GT, 0, 0); if (!A) param->memory_error = true; } any(A) ::= LPAREN any_list(B) RPAREN. - { if ((A = css_new_node(CSS_NODE_PAREN, 0, 0))) + { if ((A = css_new_node(param->stylesheet, CSS_NODE_PAREN, + 0, 0))) A->value = B; else { param->memory_error = true; @@ -304,7 +318,8 @@ any(A) ::= LPAREN any_list(B) RPAREN. A = 0; } } any(A) ::= LBRAC any_list(B) RBRAC. - { if ((A = css_new_node(CSS_NODE_BRAC, 0, 0))) + { if ((A = css_new_node(param->stylesheet, CSS_NODE_BRAC, + 0, 0))) A->value = B; else { param->memory_error = true; @@ -312,7 +327,8 @@ any(A) ::= LBRAC any_list(B) RBRAC. A = 0; } } any(A) ::= ASTERISK(B). - { A = css_new_node(CSS_NODE_DELIM, B.text, B.length); + { A = css_new_node(param->stylesheet, CSS_NODE_DELIM, + B.text, B.length); if (!A) param->memory_error = true; } diff --git a/css/ruleset.c b/css/ruleset.c index e2e0d03bd..345b86225 100644 --- a/css/ruleset.c +++ b/css/ruleset.c @@ -23,6 +23,7 @@ #include "netsurf/content/content.h" #include "netsurf/desktop/options.h" #include "netsurf/utils/log.h" +#include "netsurf/utils/url.h" #include "netsurf/utils/utils.h" @@ -33,7 +34,11 @@ 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 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_position(struct css_style * const s, const struct css_node * const v); +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); static void parse_border_bottom_color(struct css_style * const s, const struct css_node * v); @@ -102,7 +107,7 @@ static css_text_decoration css_text_decoration_parse(const char * const s, /** An entry in css_property_table. */ struct css_property_entry { - const char name[20]; + const char name[25]; void (*parse) (struct css_style * const s, const struct css_node * const v); }; @@ -110,7 +115,11 @@ struct css_property_entry { /** Table of property parsers. MUST be sorted by property name. */ static const struct css_property_entry css_property_table[] = { { "background", parse_background }, + { "background-attachment", parse_background_attachment }, { "background-color", parse_background_color }, + { "background-image", parse_background_image }, + { "background-position", parse_background_position }, + { "background-repeat", parse_background_repeat }, { "border", parse_border }, { "border-bottom", parse_border_bottom }, { "border-bottom-color", parse_border_bottom_color }, @@ -481,6 +490,16 @@ void parse_background(struct css_style * const s, const struct css_node * 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) + return; + z = css_background_attachment_parse(v->data, v->data_length); + if (z != CSS_BACKGROUND_ATTACHMENT_UNKNOWN) + s->background_attachment = z; +} + void parse_background_color(struct css_style * const s, const struct css_node * const v) { colour c = parse_colour(v); @@ -488,6 +507,262 @@ void parse_background_color(struct css_style * const s, const struct css_node * s->background_color = c; } +void parse_background_image(struct css_style * const s, const struct css_node * const v) +{ + bool string = false; + const char *u; + char *t, *url; + s->background_image.uri = 0; + + switch (v->type) { + case CSS_NODE_URI: + for (u = v->data + 4; + *u == ' ' || *u == '\t' || *u == '\r' || + *u == '\n' || *u == '\f'; + u++) + ; + if (*u == '\'' || *u == '"') { + string = true; + u++; + } + url = strndup(u, v->data_length - (u - v->data)); + if (!url) { + return; + } + for (t = url + strlen(url) - 2; + *t == ' ' || *t == '\t' || *t == '\r' || + *t == '\n' || *t == '\f'; + t--) + ; + if (string) + *t = 0; + else + *(t + 1) = 0; + + s->background_image.uri = url_join(url, v->stylesheet->url); + free(url); + if (!s->background_image.uri) return; + s->background_image.type = CSS_BACKGROUND_IMAGE_URI; + break; + case CSS_NODE_STRING: + url = strndup(v->data, v->data_length); + if (!url) + return; + + s->background_image.uri = url_join(url, v->stylesheet->url); + free(url); + if (!s->background_image.uri) return; + s->background_image.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; + break; + default: + break; + } +} + +void parse_background_position(struct css_style * const s, const struct css_node * v) +{ + struct css_node *w = v->next; + + if (!w) { /* only one value specified */ + if (v->type == CSS_NODE_IDENT) { + if (v->data_length == 3 && strncasecmp(v->data, "top", 3) == 0) { + s->background_position.horz.pos = CSS_BACKGROUND_POSITION_PERCENT; + s->background_position.horz.value.percent = 50.0; + s->background_position.vert.pos = CSS_BACKGROUND_POSITION_PERCENT; + s->background_position.vert.value.percent = 0.0; + } + else if (v->data_length == 4 && strncasecmp(v->data, "left", 4) == 0) { + s->background_position.horz.pos = CSS_BACKGROUND_POSITION_PERCENT; + s->background_position.horz.value.percent = 0.0; + s->background_position.vert.pos = CSS_BACKGROUND_POSITION_PERCENT; + s->background_position.vert.value.percent = 50.0; + } + else if (v->data_length == 6 && strncasecmp(v->data, "center", 6) == 0) { + s->background_position.horz.pos = CSS_BACKGROUND_POSITION_PERCENT; + s->background_position.horz.value.percent = 50.0; + s->background_position.vert.pos = CSS_BACKGROUND_POSITION_PERCENT; + s->background_position.vert.value.percent = 50.0; + } + else if (v->data_length == 5 && strncasecmp(v->data, "right", 5) == 0) { + s->background_position.horz.pos = CSS_BACKGROUND_POSITION_PERCENT; + s->background_position.horz.value.percent = 100.0; + s->background_position.vert.pos = CSS_BACKGROUND_POSITION_PERCENT; + s->background_position.vert.value.percent = 50.0; + } + else if (v->data_length == 6 && strncasecmp(v->data, "bottom", 6) == 0) { + s->background_position.horz.pos = CSS_BACKGROUND_POSITION_PERCENT; + s->background_position.horz.value.percent = 50.0; + s->background_position.vert.pos = CSS_BACKGROUND_POSITION_PERCENT; + s->background_position.vert.value.percent = 100.0; + } + } + 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); + s->background_position.vert.pos = CSS_BACKGROUND_POSITION_PERCENT; + s->background_position.vert.value.percent = 50.0; + } + else if (v->type == CSS_NODE_DIMENSION) { + + if (parse_length(&s->background_position.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; + } + } + } + + /* two values specified */ + if (v->type == CSS_NODE_IDENT && w->type == CSS_NODE_IDENT) { + /* both keywords */ + if ((v->data_length == 3 && strncasecmp(v->data, "top", 3) == 0 && w->data_length == 4 && strncasecmp(w->data, "left", 4) == 0) || + (v->data_length == 4 && strncasecmp(v->data, "left", 4) == 0 && w->data_length == 3 && strncasecmp(w->data, "top", 3) == 0)) { + /* top left / left top */ + s->background_position.horz.pos = CSS_BACKGROUND_POSITION_PERCENT; + s->background_position.horz.value.percent = 0.0; + s->background_position.vert.pos = CSS_BACKGROUND_POSITION_PERCENT; + s->background_position.vert.value.percent = 0.0; + } + else if ((v->data_length == 3 && strncasecmp(v->data, "top", 3) == 0 && w->data_length == 6 && strncasecmp(w->data, "center", 6) == 0) || + (v->data_length == 6 && strncasecmp(v->data, "center", 6) == 0 && w->data_length == 3 && strncasecmp(w->data, "top", 3) == 0)) { + /* top center / center top */ + s->background_position.horz.pos = CSS_BACKGROUND_POSITION_PERCENT; + s->background_position.horz.value.percent = 50.0; + s->background_position.vert.pos = CSS_BACKGROUND_POSITION_PERCENT; + s->background_position.vert.value.percent = 0.0; + } + else if ((v->data_length == 3 && strncasecmp(v->data, "top", 3) == 0 && w->data_length == 5 && strncasecmp(w->data, "right", 5) == 0) || + (v->data_length == 5 && strncasecmp(v->data, "right", 5) == 0 && w->data_length == 3 && strncasecmp(w->data, "top", 3) == 0)) { + /* top right / right top */ + s->background_position.horz.pos = CSS_BACKGROUND_POSITION_PERCENT; + s->background_position.horz.value.percent = 100.0; + s->background_position.vert.pos = CSS_BACKGROUND_POSITION_PERCENT; + s->background_position.vert.value.percent = 0.0; + } + else if ((v->data_length == 4 && strncasecmp(v->data, "left", 4) == 0 && w->data_length == 6 && strncasecmp(w->data, "center", 6) == 0) || + (v->data_length == 6 && strncasecmp(v->data, "center", 6) == 0 && w->data_length == 4 && strncasecmp(w->data, "left", 4) == 0)) { + /* left center / center left */ + s->background_position.horz.pos = CSS_BACKGROUND_POSITION_PERCENT; + s->background_position.horz.value.percent = 0.0; + s->background_position.vert.pos = CSS_BACKGROUND_POSITION_PERCENT; + s->background_position.vert.value.percent = 50.0; + } + else if (v->data_length == 6 && strncasecmp(v->data, "center", 6) == 0 && w->data_length == 6 && strncasecmp(w->data, "center", 6) == 0) { + /* center center */ + s->background_position.horz.pos = CSS_BACKGROUND_POSITION_PERCENT; + s->background_position.horz.value.percent = 50.0; + s->background_position.vert.pos = CSS_BACKGROUND_POSITION_PERCENT; + s->background_position.vert.value.percent = 50.0; + } + else if ((v->data_length == 5 && strncasecmp(v->data, "right", 5) == 0 && w->data_length == 6 && strncasecmp(w->data, "center", 6) == 0) || + (v->data_length == 6 && strncasecmp(v->data, "center", 6) == 0 && w->data_length == 5 && strncasecmp(w->data, "right", 5) == 0)) { + /* right center / center right */ + s->background_position.horz.pos = CSS_BACKGROUND_POSITION_PERCENT; + s->background_position.horz.value.percent = 100.0; + s->background_position.vert.pos = CSS_BACKGROUND_POSITION_PERCENT; + s->background_position.vert.value.percent = 50.0; + } + else if ((v->data_length == 6 && strncasecmp(v->data, "bottom", 6) == 0 && w->data_length == 4 && strncasecmp(w->data, "left", 4) == 0) || + (v->data_length == 4 && strncasecmp(v->data, "left", 4) == 0 && w->data_length == 6 && strncasecmp(w->data, "bottom", 6) == 0)) { + /* bottom left / left bottom */ + s->background_position.horz.pos = CSS_BACKGROUND_POSITION_PERCENT; + s->background_position.horz.value.percent = 0.0; + s->background_position.vert.pos = CSS_BACKGROUND_POSITION_PERCENT; + s->background_position.vert.value.percent = 100.0; + } + else if ((v->data_length == 6 && strncasecmp(v->data, "bottom", 6) == 0 && w->data_length == 6 && strncasecmp(w->data, "center", 6) == 0) || + (v->data_length == 6 && strncasecmp(v->data, "center", 6) == 0 && w->data_length == 6 && strncasecmp(w->data, "bottom", 6) == 0)) { + /* bottom center / center bottom */ + s->background_position.horz.pos = CSS_BACKGROUND_POSITION_PERCENT; + s->background_position.horz.value.percent = 50.0; + s->background_position.vert.pos = CSS_BACKGROUND_POSITION_PERCENT; + s->background_position.vert.value.percent = 100.0; + } + else if ((v->data_length == 6 && strncasecmp(v->data, "bottom", 6) == 0 && w->data_length == 5 && strncasecmp(w->data, "right", 5) == 0) || + (v->data_length == 5 && strncasecmp(v->data, "right", 5) == 0 && w->data_length == 6 && strncasecmp(w->data, "bottom", 6) == 0)) { + /* bottom right / right bottom */ + s->background_position.horz.pos = CSS_BACKGROUND_POSITION_PERCENT; + s->background_position.horz.value.percent = 100.0; + s->background_position.vert.pos = CSS_BACKGROUND_POSITION_PERCENT; + s->background_position.vert.value.percent = 100.0; + } + } + else { + switch (v->type) { /* horizontal value */ + case CSS_NODE_IDENT: + if (v->data_length == 7 && strncasecmp(v->data, "inherit", 7) == 0) + s->background_position.horz.pos = CSS_BACKGROUND_POSITION_INHERIT; + else if (v->data_length == 4 && strncasecmp(v->data, "left", 4) == 0) { + s->background_position.horz.pos = CSS_BACKGROUND_POSITION_PERCENT; + s->background_position.horz.value.percent = 0.0; + } + else if (v->data_length == 5 && strncasecmp(v->data, "right", 5) == 0) { + s->background_position.horz.pos = CSS_BACKGROUND_POSITION_PERCENT; + s->background_position.horz.value.percent = 100.0; + } + else if (v->data_length == 6 && strncasecmp(v->data, "center", 6) == 0) { + s->background_position.horz.pos = CSS_BACKGROUND_POSITION_PERCENT; + s->background_position.horz.value.percent = 50.0; + } + break; + case CSS_NODE_PERCENTAGE: + s->background_position.horz.pos = CSS_BACKGROUND_POSITION_PERCENT; + s->background_position.horz.value.percent = atof(v->data); + break; + case CSS_NODE_DIMENSION: + if (parse_length(&s->background_position.horz.value.length, v, false) == 0) + s->background_position.horz.pos = CSS_BACKGROUND_POSITION_LENGTH; + break; + default: + break; + } + switch (w->type) { /* vertical value */ + case CSS_NODE_IDENT: + if (v->data_length == 7 && strncasecmp(v->data, "inherit", 7) == 0) + s->background_position.vert.pos = CSS_BACKGROUND_POSITION_INHERIT; + else if (v->data_length == 3 && strncasecmp(v->data, "top", 3) == 0) { + s->background_position.vert.pos = CSS_BACKGROUND_POSITION_PERCENT; + s->background_position.vert.value.percent = 0.0; + } + else if (v->data_length == 6 && strncasecmp(v->data, "bottom", 6) == 0) { + s->background_position.vert.pos = CSS_BACKGROUND_POSITION_PERCENT; + s->background_position.vert.value.percent = 100.0; + } + else if (v->data_length == 6 && strncasecmp(v->data, "center", 6) == 0) { + s->background_position.vert.pos = CSS_BACKGROUND_POSITION_PERCENT; + s->background_position.vert.value.percent = 50.0; + } + break; + case CSS_NODE_PERCENTAGE: + s->background_position.vert.pos = CSS_BACKGROUND_POSITION_PERCENT; + s->background_position.vert.value.percent = atof(v->data); + break; + case CSS_NODE_DIMENSION: + if (parse_length(&s->background_position.vert.value.length, v, false) == 0) + s->background_position.vert.pos = CSS_BACKGROUND_POSITION_LENGTH; + break; + default: + break; + } + } +} + +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) + return; + z = css_background_repeat_parse(v->data, v->data_length); + if (z != CSS_BACKGROUND_REPEAT_UNKNOWN) + s->background_repeat = z; +} + void parse_border_width(struct css_style * const s, const struct css_node * const v) { diff --git a/render/box.c b/render/box.c index fdda43c94..eb0befdfd 100644 --- a/render/box.c +++ b/render/box.c @@ -60,12 +60,30 @@ struct box_multi_length { float value; }; +static const content_type image_types[] = { +#ifdef WITH_JPEG + CONTENT_JPEG, +#endif +#ifdef WITH_GIF + CONTENT_GIF, +#endif +#ifdef WITH_PNG + CONTENT_PNG, +#endif +#ifdef WITH_SPRITE + CONTENT_SPRITE, +#endif +#ifdef WITH_DRAW + CONTENT_DRAW, +#endif + CONTENT_UNKNOWN }; static struct box * convert_xml_to_box(xmlNode * n, struct content *content, struct css_style * parent_style, struct box * parent, struct box *inline_container, struct box_status status); -static struct css_style * box_get_style(struct content ** stylesheet, +static struct css_style * box_get_style(struct content *c, + struct content ** stylesheet, unsigned int stylesheet_count, struct css_style * parent_style, xmlNode * n); static void box_text_transform(char *s, unsigned int len, @@ -195,6 +213,7 @@ struct box * box_create(struct css_style * style, box->font = 0; box->gadget = 0; box->usemap = 0; + box->background = 0; box->object = 0; box->object_params = 0; box->object_state = 0; @@ -312,7 +331,7 @@ struct box * convert_xml_to_box(xmlNode * n, struct content *content, gui_multitask(); - style = box_get_style(content->data.html.stylesheet_content, + style = box_get_style(content, content->data.html.stylesheet_content, content->data.html.stylesheet_count, parent_style, n); LOG(("display: %s", css_display_name[style->display])); if (style->display == CSS_DISPLAY_NONE) { @@ -551,6 +570,17 @@ end: if (!href_in) xmlFree(status.href); + /* Now fetch any background image for this box */ + if (box && box->style && + box->style->background_image.type == CSS_BACKGROUND_IMAGE_URI) { + /* start fetch */ + html_fetch_object(content, box->style->background_image.uri, + box, + image_types, + content->available_width, + 1000); + } + LOG(("node %p, node type %i END", n, n->type)); return inline_container; } @@ -565,7 +595,8 @@ end: * 3. the 'style' attribute */ -struct css_style * box_get_style(struct content ** stylesheet, +struct css_style * box_get_style(struct content *c, + struct content ** stylesheet, unsigned int stylesheet_count, struct css_style * parent_style, xmlNode * n) { @@ -584,6 +615,19 @@ struct css_style * box_get_style(struct content ** stylesheet, } css_cascade(style, &style_new); + /* This property only applies to the body element, if you believe + the spec. Many browsers seem to allow it on other elements too, + so let's be generic ;) + */ + if ((s = (char *) xmlGetProp(n, (const xmlChar *) "background"))) { + style->background_image.type = CSS_BACKGROUND_IMAGE_URI; + /**\todo This will leak memory. */ + style->background_image.uri = url_join(s, c->data.html.base_url); + if (!style->background_image.uri) + style->background_image.type = CSS_BACKGROUND_IMAGE_NONE; + 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) @@ -747,7 +791,6 @@ void box_text_transform(char *s, unsigned int len, * have been processed in some way by the function). If box is 0, no box will * be created for that element, and convert_children must be 0. */ - struct box_result box_a(xmlNode *n, struct box_status *status, struct css_style *style) { @@ -765,8 +808,9 @@ struct box_result box_body(xmlNode *n, struct box_status *status, { struct box *box; status->content->data.html.background_colour = style->background_color; - box = box_create(style, status->href, status->title, + box = box_create(style, status->href, status->title, status->content->data.html.box_pool); + return (struct box_result) {box, true, false}; } @@ -780,24 +824,6 @@ struct box_result box_br(xmlNode *n, struct box_status *status, return (struct box_result) {box, false, false}; } -static const content_type image_types[] = { -#ifdef WITH_JPEG - CONTENT_JPEG, -#endif -#ifdef WITH_GIF - CONTENT_GIF, -#endif -#ifdef WITH_PNG - CONTENT_PNG, -#endif -#ifdef WITH_SPRITE - CONTENT_SPRITE, -#endif -#ifdef WITH_DRAW - CONTENT_DRAW, -#endif - CONTENT_UNKNOWN }; - struct box_result box_image(xmlNode *n, struct box_status *status, struct css_style *style) { diff --git a/render/box.h b/render/box.h index b4ecfa631..c1250469a 100644 --- a/render/box.h +++ b/render/box.h @@ -77,6 +77,7 @@ #include #include "libxml/HTMLparser.h" #include "netsurf/utils/config.h" +#include "netsurf/content/content_type.h" #include "netsurf/css/css.h" #include "netsurf/render/font.h" #include "netsurf/utils/pool.h" @@ -189,6 +190,9 @@ struct box { char *usemap; /** (Image)map to use with this object, or 0 if none */ + /** Background image for this box, or 0 if none */ + struct content *background; + /** Object in this box (usually an image), or 0 if none. */ struct content* object; /** Parameters for the object, or 0. */ diff --git a/render/html.c b/render/html.c index 722fcc5ba..12f286579 100644 --- a/render/html.c +++ b/render/html.c @@ -38,7 +38,8 @@ static void html_head(struct content *c, xmlNode *head); static void html_find_stylesheets(struct content *c, xmlNode *head); static void html_object_callback(content_msg msg, struct content *object, void *p1, void *p2, union content_msg_data data); -static void html_object_done(struct box *box, struct content *object); +static void html_object_done(struct box *box, struct content *object, + bool background); static bool html_object_type_permitted(const content_type type, const content_type *permitted_types); @@ -537,6 +538,10 @@ void html_fetch_object(struct content *c, char *url, struct box *box, c->data.html.object[i].url = url; c->data.html.object[i].box = box; c->data.html.object[i].permitted_types = permitted_types; + if (box->style->background_image.type == CSS_BACKGROUND_IMAGE_URI) + c->data.html.object[i].background = true; + else + c->data.html.object[i].background = false; /* start fetch */ c->data.html.object[i].content = fetchcache(url, c->url, @@ -591,13 +596,13 @@ void html_object_callback(content_msg msg, struct content *object, case CONTENT_MSG_READY: if (object->type == CONTENT_HTML) { - html_object_done(box, object); + html_object_done(box, object, c->data.html.object[i].background); content_reformat(c, c->available_width, 0); } break; case CONTENT_MSG_DONE: - html_object_done(box, object); + html_object_done(box, object, c->data.html.object[i].background); c->active--; break; @@ -696,11 +701,17 @@ void html_object_callback(content_msg msg, struct content *object, * Update a box whose content has completed rendering. */ -void html_object_done(struct box *box, struct content *object) +void html_object_done(struct box *box, struct content *object, + bool background) { struct box *b; - box->object = object; + if (background) { + box->background = object; + } + else { + box->object = object; + } if (box->width != UNKNOWN_WIDTH && object->available_width != box->width) diff --git a/render/html.h b/render/html.h index 8446b651e..860af9680 100644 --- a/render/html.h +++ b/render/html.h @@ -14,6 +14,7 @@ #ifndef _NETSURF_RENDER_HTML_H_ #define _NETSURF_RENDER_HTML_H_ +#include #include "libxml/HTMLparser.h" #include "netsurf/content/content_type.h" #include "netsurf/css/css.h" @@ -72,6 +73,7 @@ struct content_html_data { /** Pointer to array of permitted content_type, terminated by * CONTENT_UNKNOWN, or 0 if any type is acceptable. */ const content_type *permitted_types; + bool background; /** Is this object a background image? */ } *object; struct imagemap **imagemaps; /**< Hashtable of imagemaps */ diff --git a/riscos/htmlredraw.c b/riscos/htmlredraw.c index 2d85204fb..be16fee17 100644 --- a/riscos/htmlredraw.c +++ b/riscos/htmlredraw.c @@ -12,11 +12,15 @@ #include "oslib/colourtrans.h" #include "oslib/draw.h" #include "oslib/font.h" +#include "swis.h" +#include "netsurf/utils/config.h" #include "netsurf/css/css.h" #include "netsurf/content/content.h" #include "netsurf/render/form.h" #include "netsurf/render/html.h" #include "netsurf/riscos/gui.h" +#include "netsurf/riscos/options.h" +#include "netsurf/riscos/tinct.h" #include "netsurf/utils/log.h" #include "netsurf/utils/messages.h" #include "netsurf/utils/utils.h" @@ -44,6 +48,8 @@ static void html_redraw_radio(int x, int y, int width, int height, bool selected); static void html_redraw_file(int x, int y, int width, int height, struct box *box, float scale); +static void html_redraw_background(long x, long y, int width, int height, + struct box *box); bool gui_redraw_debug = false; @@ -194,7 +200,7 @@ void html_redraw_box(struct content *content, struct box * box, if (clip_x1 < x1) x1 = clip_x1; if (clip_y1 < y1) y1 = clip_y1; /* clip to it */ - html_redraw_clip(x0, y0, x1, y1); + html_redraw_clip(x0, y0, x1, y1); } else { /* clip box unchanged */ x0 = clip_x0; @@ -210,6 +216,8 @@ void html_redraw_box(struct content *content, struct box * box, int py0 = y - padding_height < y0 ? y0 : y - padding_height; int px1 = x + padding_width < x1 ? x + padding_width : x1; int py1 = y < y1 ? y : y1; + /* clip to it */ + html_redraw_clip(px0, py0, px1, py1); colourtrans_set_gcol(box->style->background_color << 8, colourtrans_USE_ECFS, os_ACTION_OVERWRITE, 0); os_plot(os_MOVE_TO, px0, py0); @@ -218,6 +226,9 @@ void html_redraw_box(struct content *content, struct box * box, current_background_color = box->style->background_color; } + /* plot background image */ + html_redraw_background(x, y, width, clip_y1-clip_y0, box); + if (box->object) { content_redraw(box->object, x + padding_left, y - padding_top, width, height, x0, y0, x1, y1, scale); @@ -365,7 +376,7 @@ void html_redraw_box(struct content *content, struct box * box, if (box->type == BOX_BLOCK || box->type == BOX_INLINE_BLOCK || box->type == BOX_TABLE_CELL || box->object) - html_redraw_clip(clip_x0, clip_y0, clip_x1, clip_y1); + html_redraw_clip(clip_x0, clip_y0, clip_x1, clip_y1); /* } else { if (content->data.html.text_selection.selected == 1) { @@ -542,3 +553,113 @@ void html_redraw_file(int x, int y, int width, int height, /* xwimpspriteop_put_sprite_user_coords(sprite, x + 4, */ /* y - height / 2 - 17, os_ACTION_OVERWRITE); */ } + +void html_redraw_background(long xi, long yi, int width, int height, + struct box *box) +{ + unsigned int tinct_options = 0; + long x = 0; + long y = 0; + float multiplier; + bool fixed = false; + + if (box->background == 0) return; + + if (ro_gui_current_redraw_gui) { + tinct_options = (ro_gui_current_redraw_gui->option_filter_sprites?tinct_BILINEAR_FILTER:0) | + (ro_gui_current_redraw_gui->option_dither_sprites?tinct_DITHER:0); + } else { + tinct_options = (option_filter_sprites?tinct_BILINEAR_FILTER:0) | + (option_dither_sprites?tinct_DITHER:0); + } + + /* handle background-attachment */ + switch (box->style->background_attachment) { + case CSS_BACKGROUND_ATTACHMENT_FIXED: + fixed = true; + break; + case CSS_BACKGROUND_ATTACHMENT_SCROLL: + break; + default: + break; + } + + /* handle background-repeat */ + switch (box->style->background_repeat) { + case CSS_BACKGROUND_REPEAT_REPEAT: + tinct_options |= tinct_FILL_HORIZONTALLY | tinct_FILL_VERTICALLY; + break; + case CSS_BACKGROUND_REPEAT_REPEAT_X: + tinct_options |= tinct_FILL_HORIZONTALLY; + break; + case CSS_BACKGROUND_REPEAT_REPEAT_Y: + tinct_options |= tinct_FILL_VERTICALLY; + break; + case CSS_BACKGROUND_REPEAT_NO_REPEAT: + x = xi; + if (fixed) + /**\todo fixed background attachments */ + y = yi/*-height*/; + else + y = yi-height; + break; + default: + break; + } + + /* handle background-position */ + switch (box->style->background_position.horz.pos) { + case CSS_BACKGROUND_POSITION_PERCENT: + multiplier = + box->style->background_position.horz.value.percent / 100; + x += box->x + (box->width * multiplier) - + (box->background->width * multiplier); + break; + case CSS_BACKGROUND_POSITION_LENGTH: + x += box->x + len(&box->style->background_position.horz.value.length, box->style); + break; + default: + break; + } + + switch (box->style->background_position.vert.pos) { + case CSS_BACKGROUND_POSITION_PERCENT: + multiplier = + box->style->background_position.vert.value.percent / 100; + y += box->y + (box->height * multiplier) - + (box->background->height * multiplier); + break; + case CSS_BACKGROUND_POSITION_LENGTH: + y += box->y + len(&box->style->background_position.vert.value.length, box->style); + break; + default: + break; + } + +// LOG(("Body [%ld, %ld], Image: [%ld, %ld], Flags: %x", xi, yi, x, y, tinct_options)); + + /* and plot the image */ + switch (box->background->type) { +#ifdef WITH_PNG + case CONTENT_PNG: + _swix(Tinct_PlotAlpha, _INR(2,4) | _IN(7), + ((char*) box->background->data.png.sprite_area + box->background->data.png.sprite_area->first), x, y, tinct_options); + break; +#endif +#ifdef WITH_JPEG + case CONTENT_JPEG: + _swix(Tinct_Plot, _INR(2,4) | _IN(7), + ((char*) box->background->data.jpeg.sprite_area + box->background->data.jpeg.sprite_area->first), x, -y, tinct_options); + break; +#endif +#ifdef WITH_GIF + case CONTENT_GIF: + _swix(Tinct_PlotAlpha, _INR(2,4) | _IN(7), + (char*) box->background->data.gif.gif->frame_image, x, -y, tinct_options); + break; +#endif + /**\todo Add draw/sprite background support? */ + default: + break; + } +} -- cgit v1.2.3