From b0c5b7498704aff375da29fc701b1a7e6941b6ba Mon Sep 17 00:00:00 2001 From: James Bursa Date: Mon, 2 Feb 2004 00:22:59 +0000 Subject: [project @ 2004-02-02 00:22:59 by bursa] Start at margin / padding / border support. svn path=/import/netsurf/; revision=529 --- css/css.c | 106 ++++++++++++++++++++++ css/css.h | 36 ++++++++ css/css_enums | 4 +- css/ruleset.c | 257 +++++++++++++++++++++++++++++++++++++++++++++++++++- render/box.c | 3 + render/box.h | 6 +- render/layout.c | 198 +++++++++++++++++++++++++++++----------- riscos/gui.h | 1 + riscos/htmlredraw.c | 120 +++++++++--------------- riscos/window.c | 5 + 10 files changed, 599 insertions(+), 137 deletions(-) diff --git a/css/css.c b/css/css.c index 4b2ca4845..3f967b548 100644 --- a/css/css.c +++ b/css/css.c @@ -38,6 +38,14 @@ static bool css_match_rule(struct css_node *rule, xmlNode *element); const struct css_style css_base_style = { 0xffffff, + { { 0x000000, { CSS_BORDER_WIDTH_LENGTH, + { 2, CSS_UNIT_PX } }, CSS_BORDER_STYLE_NONE }, + { 0x000000, { CSS_BORDER_WIDTH_LENGTH, + { 2, CSS_UNIT_PX } }, CSS_BORDER_STYLE_NONE }, + { 0x000000, { CSS_BORDER_WIDTH_LENGTH, + { 2, CSS_UNIT_PX } }, CSS_BORDER_STYLE_NONE }, + { 0x000000, { CSS_BORDER_WIDTH_LENGTH, + { 2, CSS_UNIT_PX } }, CSS_BORDER_STYLE_NONE } }, CSS_CLEAR_NONE, 0x000000, CSS_DISPLAY_BLOCK, @@ -49,6 +57,14 @@ const struct css_style css_base_style = { CSS_FONT_VARIANT_NORMAL, { CSS_HEIGHT_AUTO, { 1, CSS_UNIT_EM } }, { CSS_LINE_HEIGHT_ABSOLUTE, { 1.3 } }, + { { CSS_MARGIN_LENGTH, { { 0, CSS_UNIT_PX } } }, + { CSS_MARGIN_LENGTH, { { 0, CSS_UNIT_PX } } }, + { CSS_MARGIN_LENGTH, { { 0, CSS_UNIT_PX } } }, + { CSS_MARGIN_LENGTH, { { 0, CSS_UNIT_PX } } } }, + { { CSS_PADDING_LENGTH, { { 0, CSS_UNIT_PX } } }, + { CSS_PADDING_LENGTH, { { 0, CSS_UNIT_PX } } }, + { CSS_PADDING_LENGTH, { { 0, CSS_UNIT_PX } } }, + { CSS_PADDING_LENGTH, { { 0, CSS_UNIT_PX } } } }, CSS_TEXT_ALIGN_LEFT, CSS_TEXT_DECORATION_NONE, { CSS_TEXT_INDENT_LENGTH, { { 0, CSS_UNIT_EM } } }, @@ -60,6 +76,14 @@ const struct css_style css_base_style = { const struct css_style css_empty_style = { CSS_COLOR_INHERIT, + { { CSS_COLOR_INHERIT, { CSS_BORDER_WIDTH_INHERIT, + { 0, CSS_UNIT_PX } }, CSS_BORDER_STYLE_INHERIT }, + { CSS_COLOR_INHERIT, { CSS_BORDER_WIDTH_INHERIT, + { 0, CSS_UNIT_PX } }, CSS_BORDER_STYLE_INHERIT }, + { CSS_COLOR_INHERIT, { CSS_BORDER_WIDTH_INHERIT, + { 0, CSS_UNIT_PX } }, CSS_BORDER_STYLE_INHERIT }, + { CSS_COLOR_INHERIT, { CSS_BORDER_WIDTH_INHERIT, + { 0, CSS_UNIT_PX } }, CSS_BORDER_STYLE_INHERIT } }, CSS_CLEAR_INHERIT, CSS_COLOR_INHERIT, CSS_DISPLAY_INHERIT, @@ -71,6 +95,14 @@ const struct css_style css_empty_style = { CSS_FONT_VARIANT_INHERIT, { CSS_HEIGHT_INHERIT, { 1, CSS_UNIT_EM } }, { CSS_LINE_HEIGHT_INHERIT, { 1.3 } }, + { { CSS_MARGIN_INHERIT, { { 0, CSS_UNIT_PX } } }, + { CSS_MARGIN_INHERIT, { { 0, CSS_UNIT_PX } } }, + { CSS_MARGIN_INHERIT, { { 0, CSS_UNIT_PX } } }, + { CSS_MARGIN_INHERIT, { { 0, CSS_UNIT_PX } } } }, + { { CSS_PADDING_INHERIT, { { 0, CSS_UNIT_PX } } }, + { CSS_PADDING_INHERIT, { { 0, CSS_UNIT_PX } } }, + { CSS_PADDING_INHERIT, { { 0, CSS_UNIT_PX } } }, + { CSS_PADDING_INHERIT, { { 0, CSS_UNIT_PX } } } }, CSS_TEXT_ALIGN_INHERIT, CSS_TEXT_DECORATION_INHERIT, { CSS_TEXT_INDENT_INHERIT, { { 0, CSS_UNIT_EM } } }, @@ -82,6 +114,14 @@ const struct css_style css_empty_style = { const struct css_style css_blank_style = { TRANSPARENT, + { { 0x000000, { CSS_BORDER_WIDTH_LENGTH, + { 2, CSS_UNIT_PX } }, CSS_BORDER_STYLE_NONE }, + { 0x000000, { CSS_BORDER_WIDTH_LENGTH, + { 2, CSS_UNIT_PX } }, CSS_BORDER_STYLE_NONE }, + { 0x000000, { CSS_BORDER_WIDTH_LENGTH, + { 2, CSS_UNIT_PX } }, CSS_BORDER_STYLE_NONE }, + { 0x000000, { CSS_BORDER_WIDTH_LENGTH, + { 2, CSS_UNIT_PX } }, CSS_BORDER_STYLE_NONE } }, CSS_CLEAR_NONE, CSS_COLOR_INHERIT, CSS_DISPLAY_INLINE, @@ -93,6 +133,14 @@ const struct css_style css_blank_style = { CSS_FONT_VARIANT_INHERIT, { CSS_HEIGHT_AUTO, { 1, CSS_UNIT_EM } }, { CSS_LINE_HEIGHT_INHERIT, { 1.3 } }, + { { CSS_MARGIN_LENGTH, { { 0, CSS_UNIT_PX } } }, + { CSS_MARGIN_LENGTH, { { 0, CSS_UNIT_PX } } }, + { CSS_MARGIN_LENGTH, { { 0, CSS_UNIT_PX } } }, + { CSS_MARGIN_LENGTH, { { 0, CSS_UNIT_PX } } } }, + { { CSS_PADDING_LENGTH, { { 0, CSS_UNIT_PX } } }, + { CSS_PADDING_LENGTH, { { 0, CSS_UNIT_PX } } }, + { CSS_PADDING_LENGTH, { { 0, CSS_UNIT_PX } } }, + { CSS_PADDING_LENGTH, { { 0, CSS_UNIT_PX } } } }, CSS_TEXT_ALIGN_INHERIT, CSS_TEXT_DECORATION_INHERIT, { CSS_TEXT_INDENT_INHERIT, { { 0, CSS_UNIT_EM } } }, @@ -643,6 +691,7 @@ static void dump_length(const struct css_length * const length) void css_dump_style(const struct css_style * const style) { + unsigned int i; fprintf(stderr, "{ "); fprintf(stderr, "background-color: #%lx; ", style->background_color); fprintf(stderr, "clear: %s; ", css_clear_name[style->clear]); @@ -676,6 +725,29 @@ void css_dump_style(const struct css_style * const style) default: fprintf(stderr, "UNKNOWN"); break; } fprintf(stderr, "; "); + fprintf(stderr, "margin:"); + for (i = 0; i != 4; i++) { + switch (style->margin[i].margin) { + case CSS_MARGIN_INHERIT: fprintf(stderr, " inherit"); break; + case CSS_MARGIN_LENGTH: fprintf(stderr, " "); + dump_length(&style->margin[i].value.length); break; + case CSS_MARGIN_PERCENT: fprintf(stderr, " %g%%", style->margin[i].value.percent); + case CSS_MARGIN_AUTO: fprintf(stderr, " auto"); break; + default: fprintf(stderr, "UNKNOWN"); break; + } + } + fprintf(stderr, "; "); + fprintf(stderr, "padding:"); + for (i = 0; i != 4; i++) { + switch (style->padding[i].padding) { + case CSS_PADDING_INHERIT: fprintf(stderr, " inherit"); break; + case CSS_PADDING_LENGTH: fprintf(stderr, " "); + dump_length(&style->padding[i].value.length); break; + case CSS_PADDING_PERCENT: fprintf(stderr, " %g%%", style->padding[i].value.percent); + default: fprintf(stderr, "UNKNOWN"); break; + } + } + fprintf(stderr, "; "); fprintf(stderr, "text-align: %s; ", css_text_align_name[style->text_align]); fprintf(stderr, "text-decoration:"); switch (style->text_decoration) { @@ -704,6 +776,7 @@ void css_dump_style(const struct css_style * const style) fprintf(stderr, "visibility: %s; ", css_visibility_name[style->visibility]); fprintf(stderr, "width: "); switch (style->width.width) { + case CSS_WIDTH_INHERIT: fprintf(stderr, "inherit"); break; case CSS_WIDTH_AUTO: fprintf(stderr, "auto"); break; case CSS_WIDTH_LENGTH: dump_length(&style->width.value.length); break; case CSS_WIDTH_PERCENT: fprintf(stderr, "%g%%", style->width.value.percent); break; @@ -753,6 +826,7 @@ void css_dump_stylesheet(const struct css_stylesheet * stylesheet) void css_cascade(struct css_style * const style, const struct css_style * const apply) { + unsigned int i; float f; /* text-decoration: approximate CSS 2.1 by inheriting into inline elements */ @@ -833,11 +907,28 @@ void css_cascade(struct css_style * const style, const struct css_style * const default: /* leave unchanged */ break; } + + for (i = 0; i != 4; i++) { + if (apply->border[i].color != CSS_COLOR_INHERIT) + style->border[i].color = apply->border[i].color; + if (apply->border[i].width.width != CSS_BORDER_WIDTH_INHERIT) + style->border[i].width = apply->border[i].width; + if (apply->border[i].style != CSS_BORDER_STYLE_INHERIT) + style->border[i].style = apply->border[i].style; + + if (apply->margin[i].margin != CSS_MARGIN_INHERIT) + style->margin[i] = apply->margin[i]; + + if (apply->padding[i].padding != CSS_PADDING_INHERIT) + style->padding[i] = apply->padding[i]; + } } void css_merge(struct css_style * const style, const struct css_style * const apply) { + unsigned int i; + if (apply->background_color != CSS_COLOR_INHERIT) style->background_color = apply->background_color; if (apply->clear != CSS_CLEAR_INHERIT) @@ -876,6 +967,21 @@ void css_merge(struct css_style * const style, const struct css_style * const ap style->width = apply->width; if (apply->white_space != CSS_WHITE_SPACE_INHERIT) style->white_space = apply->white_space; + + for (i = 0; i != 4; i++) { + if (apply->border[i].color != CSS_COLOR_INHERIT) + style->border[i].color = apply->border[i].color; + if (apply->border[i].width.width != CSS_BORDER_WIDTH_INHERIT) + style->border[i].width = apply->border[i].width; + if (apply->border[i].style != CSS_BORDER_STYLE_INHERIT) + style->border[i].style = apply->border[i].style; + + if (apply->margin[i].margin != CSS_MARGIN_INHERIT) + style->margin[i] = apply->margin[i]; + + if (apply->padding[i].padding != CSS_PADDING_INHERIT) + style->padding[i] = apply->padding[i]; + } } diff --git a/css/css.h b/css/css.h index 0482932f8..71caabfdd 100644 --- a/css/css.h +++ b/css/css.h @@ -35,6 +35,10 @@ typedef unsigned long colour; /* 0xbbggrr */ #define TRANSPARENT 0x1000000 #define CSS_COLOR_INHERIT 0x2000000 #define CSS_COLOR_NONE 0x3000000 +#define TOP 0 +#define RIGHT 1 +#define BOTTOM 2 +#define LEFT 3 /** Representation of a CSS 2 length. */ struct css_length { @@ -55,6 +59,17 @@ typedef enum { /** Representation of a complete CSS 2 style. */ struct css_style { colour background_color; + + struct { + colour color; + struct { + enum { CSS_BORDER_WIDTH_INHERIT, + CSS_BORDER_WIDTH_LENGTH } width; + struct css_length value; + } width; + css_border_style style; + } border[4]; /**< top, right, bottom, left */ + css_clear clear; colour color; css_display display; @@ -96,6 +111,27 @@ struct css_style { } value; } line_height; + struct { + enum { CSS_MARGIN_INHERIT, + CSS_MARGIN_LENGTH, + CSS_MARGIN_PERCENT, + CSS_MARGIN_AUTO } margin; + union { + struct css_length length; + float percent; + } value; + } margin[4]; /**< top, right, bottom, left */ + + struct { + enum { CSS_PADDING_INHERIT, + CSS_PADDING_LENGTH, + CSS_PADDING_PERCENT } padding; + union { + struct css_length length; + float percent; + } value; + } padding[4]; /**< top, right, bottom, left */ + css_text_align text_align; css_text_decoration text_decoration; struct { diff --git a/css/css_enums b/css/css_enums index aaaed1419..e8d85ae5e 100644 --- a/css/css_enums +++ b/css/css_enums @@ -2,8 +2,7 @@ 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_border_style inherit none hidden dotted dashed solid double groove ridge inset outset css_clear inherit none both left right css_display inherit inline block list-item run-in inline-block 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 @@ -14,7 +13,6 @@ css_font_weight inherit normal bold bolder lighter 100 200 300 400 500 600 700 8 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_transform inherit none capitalize lowercase uppercase css_vertical_align baseline bottom middle sub super text_bottom text_top top percent diff --git a/css/ruleset.c b/css/ruleset.c index fa3fe775e..82385956d 100644 --- a/css/ruleset.c +++ b/css/ruleset.c @@ -39,6 +39,26 @@ static int parse_length(struct css_length * const length, 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_color(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); +static void parse_border_bottom_style(struct css_style * const s, const struct css_node * v); +static void parse_border_bottom_width(struct css_style * const s, const struct css_node * v); +static void parse_border_color(struct css_style * const s, const struct css_node * v); +static void parse_border_left(struct css_style * const s, const struct css_node * v); +static void parse_border_left_color(struct css_style * const s, const struct css_node * v); +static void parse_border_left_style(struct css_style * const s, const struct css_node * v); +static void parse_border_left_width(struct css_style * const s, const struct css_node * v); +static void parse_border_right(struct css_style * const s, const struct css_node * v); +static void parse_border_right_color(struct css_style * const s, const struct css_node * v); +static void parse_border_right_style(struct css_style * const s, const struct css_node * v); +static void parse_border_right_width(struct css_style * const s, const struct css_node * v); +static void parse_border_style(struct css_style * const s, const struct css_node * v); +static void parse_border_top(struct css_style * const s, const struct css_node * v); +static void parse_border_top_color(struct css_style * const s, const struct css_node * v); +static void parse_border_top_style(struct css_style * const s, const struct css_node * v); +static void parse_border_top_width(struct css_style * const s, const struct css_node * v); +static void parse_border_width(struct css_style * const s, const struct css_node * v); static void parse_clear(struct css_style * const s, const struct css_node * const v); static void parse_color(struct css_style * const s, const struct css_node * const v); static void parse_display(struct css_style * const s, const struct css_node * const v); @@ -51,6 +71,20 @@ static void parse_font_variant(struct css_style * const s, const struct css_node static void parse_font_weight(struct css_style * const s, const struct css_node * const v); static void parse_height(struct css_style * const s, const struct css_node * const v); static void parse_line_height(struct css_style * const s, const struct css_node * const v); +static void parse_margin(struct css_style * const s, const struct css_node * const v); +static void parse_margin_bottom(struct css_style * const s, const struct css_node * const v); +static void parse_margin_left(struct css_style * const s, const struct css_node * const v); +static void parse_margin_right(struct css_style * const s, const struct css_node * const v); +static void parse_margin_top(struct css_style * const s, const struct css_node * const v); +static void parse_margin_side(struct css_style * const s, const struct css_node * const v, + unsigned int i); +static void parse_padding(struct css_style * const s, const struct css_node * const v); +static void parse_padding_bottom(struct css_style * const s, const struct css_node * const v); +static void parse_padding_left(struct css_style * const s, const struct css_node * const v); +static void parse_padding_right(struct css_style * const s, const struct css_node * const v); +static void parse_padding_top(struct css_style * const s, const struct css_node * const v); +static void parse_padding_side(struct css_style * const s, const struct css_node * const v, + unsigned int i); static void parse_text_align(struct css_style * const s, const struct css_node * const v); static void parse_text_decoration(struct css_style * const s, const struct css_node * const v); static void parse_text_indent(struct css_style * const s, const struct css_node * const v); @@ -65,6 +99,26 @@ static css_text_decoration css_text_decoration_parse(const char * const s); static const struct property_entry property_table[] = { { "background", parse_background }, { "background-color", parse_background_color }, +/* { "border", parse_border }, + { "border-bottom", parse_border_bottom }, + { "border-bottom-color", parse_border_bottom_color }, + { "border-bottom-style", parse_border_bottom_style }, + { "border-bottom-width", parse_border_bottom_width }, + { "border-color", parse_border_color }, + { "border-left", parse_border_left }, + { "border-left-color", parse_border_left_color }, + { "border-left-style", parse_border_left_style }, + { "border-left-width", parse_border_left_width }, + { "border-right", parse_border_right }, + { "border-right-color", parse_border_right_color }, + { "border-right-style", parse_border_right_style }, + { "border-right-width", parse_border_right_width }, + { "border-style", parse_border_style }, + { "border-top", parse_border_top }, + { "border-top-color", parse_border_top_color }, + { "border-top-style", parse_border_top_style }, + { "border-top-width", parse_border_top_width }, + { "border-width", parse_border_width },*/ { "clear", parse_clear }, { "color", parse_color }, { "display", parse_display }, @@ -77,6 +131,16 @@ static const struct property_entry property_table[] = { { "font-weight", parse_font_weight }, { "height", parse_height }, { "line-height", parse_line_height }, + { "margin", parse_margin }, + { "margin-bottom", parse_margin_bottom }, + { "margin-left", parse_margin_left }, + { "margin-right", parse_margin_right }, + { "margin-top", parse_margin_top }, + { "padding", parse_padding }, + { "padding-bottom", parse_padding_bottom }, + { "padding-left", parse_padding_left }, + { "padding-right", parse_padding_right }, + { "padding-top", parse_padding_top }, { "text-align", parse_text_align }, { "text-decoration", parse_text_decoration }, { "text-indent", parse_text_indent }, @@ -274,6 +338,11 @@ int parse_length(struct css_length * const length, { css_unit u; float value; + if (v->type == CSS_NODE_NUMBER && atof(v->data) == 0) { + length->unit = CSS_UNIT_EM; + length->value = 0; + return 0; + } if (v->type != CSS_NODE_DIMENSION) return 1; u = css_unit_parse(v->data + strspn(v->data, "0123456789+-.")); @@ -542,7 +611,8 @@ void parse_height(struct css_style * const s, const struct css_node * const v) { if (v->type == CSS_NODE_IDENT && strcasecmp(v->data, "auto") == 0) s->height.height = CSS_HEIGHT_AUTO; - else if (v->type == CSS_NODE_DIMENSION && parse_length(&s->height.length, v, true) == 0) + else if ((v->type == CSS_NODE_DIMENSION || v->type == CSS_NODE_NUMBER) && + parse_length(&s->height.length, v, true) == 0) s->height.height = CSS_HEIGHT_LENGTH; } @@ -563,6 +633,186 @@ void parse_line_height(struct css_style * const s, const struct css_node * const } } +void parse_margin(struct css_style * const s, const struct css_node * const v) +{ + unsigned int count = 0; + const struct css_node *w; + + for (w = v; w; w = w->next, count++) + if (!((w->type == CSS_NODE_IDENT && ( + (strcasecmp(w->data, "inherit") == 0) || + (strcasecmp(w->data, "auto") == 0))) || + (w->type == CSS_NODE_PERCENTAGE) || + (w->type == CSS_NODE_DIMENSION) || + (w->type == CSS_NODE_NUMBER))) + return; + + switch (count) { + case 1: /* one value: applies to all sides */ + parse_margin_side(s, v, 0); + parse_margin_side(s, v, 1); + parse_margin_side(s, v, 2); + parse_margin_side(s, v, 3); + break; + case 2: /* (top and bottom), (left and right) */ + parse_margin_side(s, v, 0); + parse_margin_side(s, v, 2); + v = v->next; + parse_margin_side(s, v, 1); + parse_margin_side(s, v, 3); + break; + case 3: /* top, (left and right), bottom */ + parse_margin_side(s, v, 0); + v = v->next; + parse_margin_side(s, v, 1); + parse_margin_side(s, v, 3); + v = v->next; + parse_margin_side(s, v, 2); + break; + case 4: /* top, right, bottom, left */ + parse_margin_side(s, v, 0); + v = v->next; + parse_margin_side(s, v, 1); + v = v->next; + parse_margin_side(s, v, 2); + v = v->next; + parse_margin_side(s, v, 3); + break; + } +} + +void parse_margin_top(struct css_style * const s, const struct css_node * const v) +{ + if (v->next != 0) + return; + parse_margin_side(s, v, 0); +} + +void parse_margin_right(struct css_style * const s, const struct css_node * const v) +{ + if (v->next != 0) + return; + parse_margin_side(s, v, 1); +} + +void parse_margin_bottom(struct css_style * const s, const struct css_node * const v) +{ + if (v->next != 0) + return; + parse_margin_side(s, v, 2); +} + +void parse_margin_left(struct css_style * const s, const struct css_node * const v) +{ + if (v->next != 0) + return; + parse_margin_side(s, v, 3); +} + +void parse_margin_side(struct css_style * const s, const struct css_node * const v, + unsigned int i) +{ + if (v->type == CSS_NODE_IDENT && strcasecmp(v->data, "inherit") == 0) + s->margin[i].margin = CSS_MARGIN_INHERIT; + else if (v->type == CSS_NODE_IDENT && strcasecmp(v->data, "auto") == 0) + s->margin[i].margin = CSS_MARGIN_AUTO; + else if (v->type == CSS_NODE_PERCENTAGE) { + s->margin[i].margin = CSS_MARGIN_PERCENT; + s->margin[i].value.percent = atof(v->data); + } else if ((v->type == CSS_NODE_DIMENSION || v->type == CSS_NODE_NUMBER) && + parse_length(&s->margin[i].value.length, v, false) == 0) { + s->margin[i].margin = CSS_MARGIN_LENGTH; + } +} + +void parse_padding(struct css_style * const s, const struct css_node * const v) +{ + unsigned int count = 0; + const struct css_node *w; + + for (w = v; w; w = w->next, count++) + if (!((w->type == CSS_NODE_IDENT && strcasecmp(w->data, "inherit") == 0) || + (w->type == CSS_NODE_PERCENTAGE) || + (w->type == CSS_NODE_DIMENSION) || + (w->type == CSS_NODE_NUMBER))) + return; + + switch (count) { + case 1: /* one value: applies to all sides */ + parse_padding_side(s, v, 0); + parse_padding_side(s, v, 1); + parse_padding_side(s, v, 2); + parse_padding_side(s, v, 3); + break; + case 2: /* (top and bottom), (left and right) */ + parse_padding_side(s, v, 0); + parse_padding_side(s, v, 2); + v = v->next; + parse_padding_side(s, v, 1); + parse_padding_side(s, v, 3); + break; + case 3: /* top, (left and right), bottom */ + parse_padding_side(s, v, 0); + v = v->next; + parse_padding_side(s, v, 1); + parse_padding_side(s, v, 3); + v = v->next; + parse_padding_side(s, v, 2); + break; + case 4: /* top, right, bottom, left */ + parse_padding_side(s, v, 0); + v = v->next; + parse_padding_side(s, v, 1); + v = v->next; + parse_padding_side(s, v, 2); + v = v->next; + parse_padding_side(s, v, 3); + break; + } +} + +void parse_padding_top(struct css_style * const s, const struct css_node * const v) +{ + if (v->next != 0) + return; + parse_padding_side(s, v, 0); +} + +void parse_padding_right(struct css_style * const s, const struct css_node * const v) +{ + if (v->next != 0) + return; + parse_padding_side(s, v, 1); +} + +void parse_padding_bottom(struct css_style * const s, const struct css_node * const v) +{ + if (v->next != 0) + return; + parse_padding_side(s, v, 2); +} + +void parse_padding_left(struct css_style * const s, const struct css_node * const v) +{ + if (v->next != 0) + return; + parse_padding_side(s, v, 3); +} + +void parse_padding_side(struct css_style * const s, const struct css_node * const v, + unsigned int i) +{ + if (v->type == CSS_NODE_IDENT && strcasecmp(v->data, "inherit") == 0) + s->padding[i].padding = CSS_PADDING_INHERIT; + else if (v->type == CSS_NODE_PERCENTAGE) { + s->padding[i].padding = CSS_PADDING_PERCENT; + s->padding[i].value.percent = atof(v->data); + } else if ((v->type == CSS_NODE_DIMENSION || v->type == CSS_NODE_NUMBER) && + parse_length(&s->padding[i].value.length, v, true) == 0) { + s->padding[i].padding = CSS_PADDING_LENGTH; + } +} + void parse_text_align(struct css_style * const s, const struct css_node * const v) { css_text_align z; @@ -580,7 +830,8 @@ void parse_text_indent(struct css_style * const s, const struct css_node * const } else if (v->type == CSS_NODE_PERCENTAGE) { s->text_indent.size = CSS_TEXT_INDENT_PERCENT; s->text_indent.value.percent = atof(v->data); - } else if (v->type == CSS_NODE_DIMENSION && parse_length(&s->text_indent.value.length, v, true) == 0) { + } else if ((v->type == CSS_NODE_DIMENSION || v->type == CSS_NODE_NUMBER) && + parse_length(&s->text_indent.value.length, v, true) == 0) { s->text_indent.size = CSS_TEXT_INDENT_LENGTH; } } @@ -633,7 +884,7 @@ void parse_width(struct css_style * const s, const struct css_node * const v) else if (v->type == CSS_NODE_PERCENTAGE) { s->width.width = CSS_WIDTH_PERCENT; s->width.value.percent = atof(v->data); - } else if (v->type == CSS_NODE_DIMENSION && + } else if ((v->type == CSS_NODE_DIMENSION || v->type == CSS_NODE_NUMBER) && parse_length(&s->width.value.length, v, true) == 0) s->width.width = CSS_WIDTH_LENGTH; } diff --git a/render/box.c b/render/box.c index d50b897cd..4057ba181 100644 --- a/render/box.c +++ b/render/box.c @@ -162,6 +162,7 @@ void box_add_child(struct box * parent, struct box * child) struct box * box_create(struct css_style * style, char *href, char *title, pool box_pool) { + unsigned int i; struct box *box = pool_alloc(box_pool, sizeof (struct box)); assert(box); box->type = BOX_INLINE; @@ -195,6 +196,8 @@ struct box * box_create(struct css_style * style, #endif box->x = box->y = 0; box->height = 0; + for (i = 0; i != 4; i++) + box->margin[i] = box->padding[i] = box->border[i] = 0; return box; } diff --git a/render/box.h b/render/box.h index b41e52c7c..f711a0f79 100644 --- a/render/box.h +++ b/render/box.h @@ -72,7 +72,11 @@ struct plugin_params {}; struct box { box_type type; struct css_style * style; - long x, y, width, height; + int x; /**< Coordinate of left padding edge relative to parent box. */ + int y; /**< Coordinate of top padding edge relative to parent box. */ + int width; /**< Width of content box (excluding padding etc.). */ + int height; /**< Height of content box (excluding padding etc.). */ + int margin[4], padding[4], border[4]; long min_width, max_width; char * text; unsigned int space : 1; /* 1 <=> followed by a space */ diff --git a/render/layout.c b/render/layout.c index 2ee2abb09..30be0144a 100644 --- a/render/layout.c +++ b/render/layout.c @@ -26,13 +26,16 @@ #include "netsurf/utils/log.h" #include "netsurf/utils/utils.h" -/** - * internal functions - */ + +#define AUTO INT_MIN + static void layout_node(struct box * box, unsigned long width, struct box * cont, unsigned long cx, unsigned long cy); -static unsigned long layout_block_children(struct box * box, unsigned long width, struct box * cont, +static int layout_block_find_dimensions(unsigned long available_width, + struct css_style *style, + int margin[4], int padding[4], int border[4]); +static void layout_block_children(struct box *box, struct box *cont, unsigned long cx, unsigned long cy); static void find_sides(struct box * fl, unsigned long y0, unsigned long y1, unsigned long * x0, unsigned long * x1, struct box ** left, struct box ** right); @@ -50,20 +53,17 @@ static void calculate_table_widths(struct box *table); /** - * layout algorithm - */ - -/** - * layout_document -- calculate positions of boxes in a document + * Calculate positions of boxes in a document. * - * doc root of document box tree - * width page width + * \param doc root of document box tree + * \param width page width */ void layout_document(struct box * doc, unsigned long width) { struct box *box; doc->float_children = 0; + doc->x = doc->y = 0; layout_node(doc, width, doc, 0, 0); for (box = doc->float_children; box != 0; box = box->next_float) if (doc->height < box->y + box->height) @@ -71,6 +71,16 @@ void layout_document(struct box * doc, unsigned long width) } +/** + * Layout the children of a box. + * + * \param box box to layout + * \param width horizontal space available + * \param cont ancestor box which defines horizontal space, for inlines + * \param cx box position relative to cont + * \param cy box position relative to cont + */ + void layout_node(struct box * box, unsigned long width, struct box * cont, unsigned long cx, unsigned long cy) { @@ -78,6 +88,13 @@ void layout_node(struct box * box, unsigned long width, struct box * cont, gui_multitask(); + if (box->style) { + box->width = layout_block_find_dimensions(width, box->style, + box->margin, box->padding, box->border); + box->x += box->margin[LEFT] + box->border[LEFT]; + box->y += box->margin[TOP] + box->border[TOP]; + } + switch (box->type) { case BOX_BLOCK: case BOX_INLINE_BLOCK: @@ -96,12 +113,13 @@ void layout_node(struct box * box, unsigned long width, struct box * cont, /** - * layout_block -- position block and recursively layout children + * Layout the children of a block box. * - * box block box to layout - * width horizontal space available - * cont ancestor box which defines horizontal space, for inlines - * cx, cy box position relative to cont + * \param box block box to layout + * \param width horizontal space available + * \param cont ancestor box which defines horizontal space, for inlines + * \param cx box position relative to cont + * \param cy box position relative to cont */ void layout_block(struct box * box, unsigned long width, struct box * cont, @@ -114,43 +132,132 @@ void layout_block(struct box * box, unsigned long width, struct box * cont, LOG(("box %p, width %lu, cont %p, cx %lu, cy %lu", box, width, cont, cx, cy)); + layout_block_children(box, cont, cx, cy); + switch (style->height.height) { + case CSS_HEIGHT_LENGTH: + box->height = len(&style->height.length, style); + break; + case CSS_HEIGHT_AUTO: + default: + /* use the computed height */ + break; + } +} + + +/** + * Compute dimensions of box, margins, paddings, and borders for a block box. + */ + +int layout_block_find_dimensions(unsigned long available_width, + struct css_style *style, + int margin[4], int padding[4], int border[4]) +{ + unsigned int i; + int width; + + /* calculate box width */ switch (style->width.width) { case CSS_WIDTH_LENGTH: - box->width = len(&style->width.value.length, style); + width = len(&style->width.value.length, style); break; case CSS_WIDTH_PERCENT: - box->width = width * style->width.value.percent / 100; + width = available_width * style->width.value.percent / 100; break; case CSS_WIDTH_AUTO: default: - /* take all available width */ - box->width = width; + width = AUTO; break; } - box->height = layout_block_children(box, (unsigned int)box->width, cont, cx, cy); - switch (style->height.height) { - case CSS_HEIGHT_LENGTH: - box->height = len(&style->height.length, style); - break; - case CSS_HEIGHT_AUTO: - default: - /* use the computed height */ - break; + + /* calculate size of margins, paddings, and borders */ + for (i = 0; i != 4; i++) { + switch (style->margin[i].margin) { + case CSS_MARGIN_LENGTH: + margin[i] = len(&style->margin[i].value.length, style); + break; + case CSS_MARGIN_PERCENT: + margin[i] = available_width * + style->margin[i].value.percent / 100; + break; + case CSS_MARGIN_AUTO: + default: + margin[i] = AUTO; + break; + } + + switch (style->padding[i].padding) { + case CSS_MARGIN_PERCENT: + padding[i] = available_width * + style->padding[i].value.percent / 100; + break; + case CSS_PADDING_LENGTH: + default: + padding[i] = len(&style->padding[i].value.length, style); + break; + } + + if (style->border[i].style == CSS_BORDER_STYLE_NONE || + style->border[i].style == CSS_BORDER_STYLE_HIDDEN) + /* spec unclear: following Mozilla */ + border[i] = 0; + else + border[i] = len(&style->border[i].width.value, style); } + + /* solve the width constraint as given in CSS 2.1 section 10.3.3 */ + if (width == AUTO) { + /* any other 'auto' become 0 */ + if (margin[LEFT] == AUTO) + margin[LEFT] = 0; + if (margin[RIGHT] == AUTO) + margin[RIGHT] = 0; + width = available_width - + (margin[LEFT] + border[LEFT] + padding[LEFT] + + padding[RIGHT] + border[RIGHT] + margin[RIGHT]); + } else if (margin[LEFT] == AUTO && margin[RIGHT] == AUTO) { + /* make the margins equal, centering the element */ + margin[LEFT] = margin[RIGHT] = (available_width - + (border[LEFT] + padding[LEFT] + width + + padding[RIGHT] + border[RIGHT])) / 2; + } else if (margin[LEFT] == AUTO) { + margin[LEFT] = available_width - + (border[LEFT] + padding[LEFT] + width + + padding[RIGHT] + border[RIGHT] + margin[RIGHT]); + } else { + /* margin-right auto or "over-constained" */ + margin[RIGHT] = available_width - + (margin[LEFT] + border[LEFT] + padding[LEFT] + + width + padding[RIGHT] + border[RIGHT]); + } + + if (margin[TOP] == AUTO) + margin[TOP] = 0; + if (margin[BOTTOM] == AUTO) + margin[BOTTOM] = 0; + + return width; } /** - * layout_block_children -- recursively layout block children + * Recursively layout block children. * - * (as above) + * \param box block box to layout + * \param cont ancestor box which defines horizontal space, for inlines + * \param cx box position relative to cont + * \param cy box position relative to cont + * + * box->width, box->margin, box->padding and box->border must be valid. + * box->height is filled in. */ -unsigned long layout_block_children(struct box * box, unsigned long width, struct box * cont, +void layout_block_children(struct box *box, struct box *cont, unsigned long cx, unsigned long cy) { - struct box * c; - unsigned long y = 0; + struct box *c; + int width = box->width; + int y = box->padding[TOP]; assert(box->type == BOX_BLOCK || box->type == BOX_INLINE_BLOCK || box->type == BOX_FLOAT_LEFT || box->type == BOX_FLOAT_RIGHT || @@ -179,14 +286,15 @@ unsigned long layout_block_children(struct box * box, unsigned long width, struc (c->style->clear == CSS_CLEAR_BOTH && (left != 0 || right != 0))); } - c->x = 0; + c->x = box->padding[LEFT]; c->y = y; layout_node(c, width, cont, cx, cy + y); - y = c->y + c->height; + y = c->y + c->height + c->padding[TOP] + c->padding[BOTTOM] + + c->border[BOTTOM] + c->margin[BOTTOM]; if (box->width < c->width) box->width = c->width; } - return y; + box->height = y - box->padding[TOP]; } @@ -593,19 +701,7 @@ void layout_table(struct box * table, unsigned long width, struct box * cont, calculate_table_widths(table); memcpy(col, table->col, sizeof(col[0]) * columns); - /* find table width */ - switch (table->style->width.width) { - case CSS_WIDTH_LENGTH: - table_width = len(&table->style->width.value.length, table->style); - break; - case CSS_WIDTH_PERCENT: - table_width = width * table->style->width.value.percent / 100; - break; - case CSS_WIDTH_AUTO: - default: - table_width = width; - break; - } + table_width = table->width; LOG(("width %lu, min %lu, max %lu", table_width, table->min_width, table->max_width)); @@ -710,7 +806,7 @@ void layout_table(struct box * table, unsigned long width, struct box * cont, assert(c->style != 0); c->width = xs[c->start_column + c->columns] - xs[c->start_column]; c->float_children = 0; - c->height = layout_block_children(c, (unsigned long)c->width, c, 0, 0); + layout_block_children(c, c, 0, 0); if (c->style->height.height == CSS_HEIGHT_LENGTH) { /* some sites use height="1" or similar to attempt * to make cells as small as possible, so treat diff --git a/riscos/gui.h b/riscos/gui.h index a943851b8..dab34561d 100644 --- a/riscos/gui.h +++ b/riscos/gui.h @@ -28,6 +28,7 @@ extern int current_menu_x, current_menu_y, iconbar_menu_height; extern struct form_control *current_gadget; extern gui_window *window_list; extern bool gui_reformat_pending; +extern bool gui_redraw_debug; struct gui_window { diff --git a/riscos/htmlredraw.c b/riscos/htmlredraw.c index 108e2029a..825c5c793 100644 --- a/riscos/htmlredraw.c +++ b/riscos/htmlredraw.c @@ -28,6 +28,10 @@ static void html_redraw_box(struct content *content, struct box * box, long clip_x0, long clip_y0, long clip_x1, long clip_y1); static void html_redraw_clip(long clip_x0, long clip_y0, long clip_x1, long clip_y1); +void html_redraw_rectangle(int x0, int y0, int width, int height, + os_colour colour); + +bool gui_redraw_debug = false; void html_redraw(struct content *c, long x, long y, @@ -57,13 +61,9 @@ void html_redraw(struct content *c, long x, long y, /* validation strings can't be const */ -static char validation_select[] = "R2"; static char validation_checkbox_selected[] = "Sopton"; static char validation_checkbox_unselected[] = "Soptoff"; -static char select_text_multiple[] = ""; /* TODO: read from messages */ -static char select_text_none[] = ""; - static char empty_text[] = ""; void html_redraw_box(struct content *content, struct box * box, @@ -74,29 +74,39 @@ void html_redraw_box(struct content *content, struct box * box, long clip_x0, long clip_y0, long clip_x1, long clip_y1) { struct box *c; - char *select_text; - struct form_option *opt; int width, height, x0, y0, x1, y1, colour; x += box->x * 2; y -= box->y * 2; - width = box->width * 2; - height = box->height * 2; + width = (box->padding[LEFT] + box->width + box->padding[RIGHT]) * 2; + height = (box->padding[TOP] + box->height + box->padding[BOTTOM]) * 2; x0 = x; y1 = y - 1; x1 = x0 + width - 1; y0 = y1 - height + 1; - /* return if visibility is hidden or inherited visibility is hidden - */ - if (box->style->visibility == CSS_VISIBILITY_HIDDEN) { - for (c=box->children;c!=0;c=c->next) - html_redraw_box(content, c, x, y, current_background_color, - gadget_subtract_x, gadget_subtract_y, select_on, - x0, y0, x1, y1); - return; - } + /* if visibility is hidden render children only */ + if (box->style->visibility == CSS_VISIBILITY_HIDDEN) { + for (c = box->children; c; c = c->next) + html_redraw_box(content, c, x, y, current_background_color, + gadget_subtract_x, gadget_subtract_y, select_on, + x0, y0, x1, y1); + return; + } + + if (gui_redraw_debug) { + html_redraw_rectangle(x, y, width, height, os_COLOUR_MAGENTA); + html_redraw_rectangle(x + box->padding[LEFT] * 2, y - box->padding[TOP] * 2, + box->width * 2, box->height * 2, os_COLOUR_CYAN); + html_redraw_rectangle(x - (box->border[LEFT] + box->margin[LEFT]) * 2, + y + (box->border[TOP] + box->margin[TOP]) * 2, + width + (box->border[LEFT] + box->margin[LEFT] + + box->border[RIGHT] + box->margin[RIGHT]) * 2, + height + (box->border[TOP] + box->margin[TOP] + + box->border[BOTTOM] + box->margin[BOTTOM]) * 2, + os_COLOUR_YELLOW); + } /* return if the box is completely outside the clip rectangle, except * for table rows which may contain cells spanning into other rows */ @@ -124,13 +134,14 @@ void html_redraw_box(struct content *content, struct box * box, /* background colour */ if (box->style != 0 && box->style->background_color != TRANSPARENT) { - colourtrans_set_gcol(box->style->background_color << 8, colourtrans_USE_ECFS, os_ACTION_OVERWRITE, 0); + colourtrans_set_gcol(box->style->background_color << 8, + colourtrans_USE_ECFS, os_ACTION_OVERWRITE, 0); os_plot(os_MOVE_TO, x, y); os_plot(os_PLOT_RECTANGLE | os_PLOT_BY, width, -height); current_background_color = box->style->background_color; } - if (box->object /*&& box->object->type != CONTENT_HTML*/) { + if (box->object) { content_redraw(box->object, x, y, (unsigned int)width, (unsigned int)height, x0, y0, x1, y1); @@ -145,66 +156,6 @@ void html_redraw_box(struct content *content, struct box * box, icon.extent.y1 = -gadget_subtract_y + y; switch (box->gadget->type) { - case GADGET_SELECT: - icon.flags = wimp_ICON_TEXT | wimp_ICON_BORDER | - wimp_ICON_VCENTRED | wimp_ICON_FILLED | - wimp_ICON_INDIRECTED | wimp_ICON_HCENTRED | - (wimp_COLOUR_BLACK << wimp_ICON_FG_COLOUR_SHIFT) | - (wimp_COLOUR_VERY_LIGHT_GREY << wimp_ICON_BG_COLOUR_SHIFT); - select_text = 0; - opt = box->gadget->data.select.items; -// if (box->gadget->data.select.size == 1) { - while (opt != NULL) - { - if (opt->selected) - { - if (select_text == 0) - select_text = opt->text; - else - select_text = select_text_multiple; - } - opt = opt->next; - } - if (select_text == 0) - select_text = select_text_none; -/* } - else { - while (opt != NULL) - { - if (opt->selected) - { - select_text = opt->text; - opt = opt->next; - break; - } - opt = opt->next; - } - if (select_text == 0) { - // display the first n options - opt = box->gadget->data.select.items; - select_text = opt->text; - opt = opt->next; - for(i = box->gadget->data.select.size-1; - i != 0; i--, opt=opt->next) { - strcat(select_text, "\n"); - strcat(select_text, opt->text); - } - } - else { - for(i = box->gadget->data.select.size-1; - i != 0; i--, opt=opt->next) { - strcat(select_text, "\n"); - strcat(select_text, opt->text); - } - } - } -*/ icon.data.indirected_text.text = select_text; - icon.data.indirected_text.size = strlen(icon.data.indirected_text.text); - icon.data.indirected_text.validation = validation_select; - LOG(("writing GADGET ACTION")); - wimp_plot_icon(&icon); - break; - case GADGET_CHECKBOX: icon.flags = wimp_ICON_TEXT | wimp_ICON_SPRITE | wimp_ICON_VCENTRED | wimp_ICON_HCENTRED | wimp_ICON_INDIRECTED; @@ -380,3 +331,14 @@ void html_redraw_clip(long clip_x0, long clip_y0, os_writec((char) (clip_y1 & 0xff)); os_writec((char) (clip_y1 >> 8)); } + +void html_redraw_rectangle(int x0, int y0, int width, int height, + os_colour colour) +{ + colourtrans_set_gcol(colour, 0, os_ACTION_OVERWRITE, 0); + os_plot(os_MOVE_TO, x0, y0); + os_plot(os_PLOT_DOTTED | os_PLOT_BY, width, 0); + os_plot(os_PLOT_DOTTED | os_PLOT_BY, 0, -height); + os_plot(os_PLOT_DOTTED | os_PLOT_BY, -width, 0); + os_plot(os_PLOT_DOTTED | os_PLOT_BY, 0, height); +} diff --git a/riscos/window.c b/riscos/window.c index 58b852b9d..b2f5fcc56 100644 --- a/riscos/window.c +++ b/riscos/window.c @@ -726,6 +726,11 @@ bool ro_gui_window_keypress(gui_window *g, int key, bool toolbar) cache_dump(); return true; + case wimp_KEY_F11: /* Toggle display of box outlines. */ + gui_redraw_debug = !gui_redraw_debug; + gui_window_redraw_window(g); + return true; + case wimp_KEY_CONTROL + wimp_KEY_F2: /* Close window. */ browser_window_destroy(g->data.browser.bw #ifdef WITH_FRAMES -- cgit v1.2.3