From 74ef206f532445a03a9463d4c0a5e0715e9808b4 Mon Sep 17 00:00:00 2001 From: James Bursa Date: Tue, 18 Jun 2002 21:24:21 +0000 Subject: [project @ 2002-06-18 21:24:21 by bursa] Improved inline and float layout, new CSS properties, better debug output. svn path=/import/netsurf/; revision=20 --- render/box.c | 34 +++--- render/box.h | 3 +- render/css.c | 112 +++++++++++++------- render/css.h | 19 +++- render/css_enums | 3 +- render/font.c | 7 +- render/font.h | 3 +- render/layout.c | 316 +++++++++++++++++++++++++++++++++++++++++++------------ render/render.c | 23 ++-- render/show.tcl | 2 +- utils/utils.c | 30 +++--- 11 files changed, 399 insertions(+), 153 deletions(-) diff --git a/render/box.c b/render/box.c index cb94fca36..79327602d 100644 --- a/render/box.c +++ b/render/box.c @@ -1,5 +1,5 @@ /** - * $Id: box.c,v 1.4 2002/05/21 21:32:35 bursa Exp $ + * $Id: box.c,v 1.5 2002/06/18 21:24:21 bursa Exp $ */ #include @@ -62,13 +62,15 @@ struct box * xml_to_box(xmlNode * n, struct css_style * parent_style, struct css struct box * inline_container_c; struct css_style * style; xmlNode * c; + xmlChar * s; if (n->type == XML_ELEMENT_NODE) { /* work out the style for this element */ *selector = xrealloc(*selector, (depth + 1) * sizeof(struct css_selector)); (*selector)[depth].element = n->name; (*selector)[depth].class = (*selector)[depth].id = 0; - + if ((s = xmlGetProp(n, "class"))) + (*selector)[depth].class = s; style = box_get_style(stylesheet, parent_style, n, *selector, depth + 1); } @@ -87,6 +89,7 @@ struct box * xml_to_box(xmlNode * n, struct css_style * parent_style, struct css if (n->type == XML_TEXT_NODE) { box->type = BOX_INLINE; box->text = squash_whitespace(n->content); + box->length = strlen(box->text); } else { box->type = BOX_FLOAT; box->style = style; @@ -204,23 +207,26 @@ void box_dump(struct box * box, unsigned int depth) { unsigned int i; struct box * c; - + for (i = 0; i < depth; i++) - printf(" "); + fprintf(stderr, " "); - printf("x%li y%li w%li h%li ", box->x, box->y, box->width, box->height); + fprintf(stderr, "x%li y%li w%li h%li ", box->x, box->y, box->width, box->height); switch (box->type) { - case BOX_BLOCK: printf("BOX_BLOCK <%s>\n", box->node->name); break; - case BOX_INLINE_CONTAINER: printf("BOX_INLINE_CONTAINER\n"); break; - case BOX_INLINE: printf("BOX_INLINE '%s'\n", box->text); break; - case BOX_TABLE: printf("BOX_TABLE <%s>\n", box->node->name); break; - case BOX_TABLE_ROW: printf("BOX_TABLE_ROW <%s>\n", box->node->name); break; - case BOX_TABLE_CELL: printf("BOX_TABLE_CELL <%s>\n", box->node->name); break; - case BOX_FLOAT: printf("BOX_FLOAT <%s>\n", box->node->name); break; - default: printf("Unknown box type\n"); + case BOX_BLOCK: fprintf(stderr, "BOX_BLOCK <%s> ", box->node->name); break; + case BOX_INLINE_CONTAINER: fprintf(stderr, "BOX_INLINE_CONTAINER "); break; + case BOX_INLINE: fprintf(stderr, "BOX_INLINE '%.*s' ", box->length, box->text); break; + case BOX_TABLE: fprintf(stderr, "BOX_TABLE <%s> ", box->node->name); break; + case BOX_TABLE_ROW: fprintf(stderr, "BOX_TABLE_ROW <%s> ", box->node->name); break; + case BOX_TABLE_CELL: fprintf(stderr, "BOX_TABLE_CELL <%s> ", box->node->name); break; + case BOX_FLOAT: fprintf(stderr, "BOX_FLOAT <%s> ", box->node->name); break; + default: fprintf(stderr, "Unknown box type "); } - + if (box->style) + css_dump_style(box->style); + fprintf(stderr, "\n"); + for (c = box->children; c != 0; c = c->next) box_dump(c, depth + 1); } diff --git a/render/box.h b/render/box.h index 9140fd9ed..0aa8e56f3 100644 --- a/render/box.h +++ b/render/box.h @@ -1,5 +1,5 @@ /** - * $Id: box.h,v 1.2 2002/05/27 23:21:11 bursa Exp $ + * $Id: box.h,v 1.3 2002/06/18 21:24:21 bursa Exp $ */ /** @@ -20,7 +20,6 @@ struct box { struct box * parent; struct box * float_children; struct box * next_float; - font_id font; }; /** diff --git a/render/css.c b/render/css.c index beb3afa1a..2e59027c8 100644 --- a/render/css.c +++ b/render/css.c @@ -1,5 +1,5 @@ /** - * $Id: css.c,v 1.3 2002/05/18 08:23:39 bursa Exp $ + * $Id: css.c,v 1.4 2002/06/18 21:24:21 bursa Exp $ */ #include @@ -35,6 +35,7 @@ static void parse_display(struct css_style * const style, const char * const val static void parse_float(struct css_style * const style, const char * const value); static void parse_font_size(struct css_style * const style, const char * const value); static void parse_height(struct css_style * const style, const char * const value); +static void parse_text_align(struct css_style * const style, const char * const value); static void parse_width(struct css_style * const style, const char * const value); static void parse_selector(struct css_selector * sel, char * const str); static unsigned int hash_str(const char * str); @@ -48,13 +49,14 @@ static void update_style(struct css_stylesheet * stylesheet, struct css_selector static void dump_length(const struct css_length * const length); static void dump_selector(const struct css_selector * const sel); static void dump_rule(const struct rule * rule); -static void css_dump_stylesheet(const struct css_stylesheet * stylesheet); const struct css_style css_base_style = { CSS_DISPLAY_BLOCK, CSS_FLOAT_NONE, - { CSS_FONT_SIZE_ABSOLUTE, 10.0 }, + { CSS_FONT_SIZE_LENGTH, {12, CSS_UNIT_PT} }, { CSS_HEIGHT_AUTO }, + { CSS_LINE_HEIGHT_ABSOLUTE, 1.2 }, + CSS_TEXT_ALIGN_LEFT, { CSS_WIDTH_AUTO } }; @@ -63,6 +65,8 @@ const struct css_style css_empty_style = { CSS_FLOAT_INHERIT, { CSS_FONT_SIZE_INHERIT }, { CSS_HEIGHT_AUTO }, + { CSS_LINE_HEIGHT_INHERIT }, + CSS_TEXT_ALIGN_INHERIT, { CSS_WIDTH_AUTO } }; @@ -71,6 +75,8 @@ const struct css_style css_blank_style = { CSS_FLOAT_NONE, { CSS_FONT_SIZE_INHERIT }, { CSS_HEIGHT_AUTO }, + { CSS_LINE_HEIGHT_INHERIT }, + CSS_TEXT_ALIGN_INHERIT, { CSS_WIDTH_AUTO } }; @@ -118,8 +124,9 @@ static void parse_font_size(struct css_style * const style, const char * const v unsigned int i; for (i = 0; i < sizeof(font_size) / sizeof(struct font_size); i++) { if (strcmp(value, font_size[i].keyword) == 0) { - style->font_size.size = CSS_FONT_SIZE_ABSOLUTE; - style->font_size.value.absolute = font_size[i].size; + style->font_size.size = CSS_FONT_SIZE_LENGTH; + style->font_size.value.length.unit = CSS_UNIT_PT; + style->font_size.value.length.value = font_size[i].size * 12; return; } } @@ -144,6 +151,23 @@ static void parse_height(struct css_style * const style, const char * const valu style->height.height = CSS_HEIGHT_LENGTH; } +static void parse_line_height(struct css_style * const style, const char * const value) +{ + if (strcmp(value, "normal") == 0) + style->line_height.size = CSS_LINE_HEIGHT_ABSOLUTE, + style->line_height.value.absolute = 1.0; + else if (strrchr(value, '%')) + style->line_height.size = CSS_LINE_HEIGHT_PERCENT, + style->line_height.value.percent = atof(value); + else if (parse_length(&style->line_height.value.length, value) == 0) + style->line_height.size = CSS_LINE_HEIGHT_LENGTH; +} + +static void parse_text_align(struct css_style * const style, const char * const value) +{ + style->text_align = css_text_align_parse(value); +} + static void parse_width(struct css_style * const style, const char * const value) { if (strcmp(value, "auto") == 0) @@ -163,6 +187,8 @@ static struct property { { "float", parse_float }, { "font-size", parse_font_size }, { "height", parse_height }, + { "line-height", parse_line_height }, + { "text-align", parse_text_align }, { "width", parse_width }, }; @@ -183,7 +209,7 @@ void css_parse_property_list(struct css_style * style, char * str) *value = 0; value++; prop = strip(str); value = strip(value); - /*printf("css_parse: '%s' => '%s'\n", prop, value);*/ + /*fprintf(stderr, "css_parse: '%s' => '%s'\n", prop, value);*/ for (i = 0; i < sizeof(property) / sizeof(struct property); i++) { if (strcmp(prop, property[i].name) == 0) { @@ -325,10 +351,10 @@ void css_get_style(struct css_stylesheet * stylesheet, struct css_selector * sel } else { qsort(decl, decls, sizeof(struct decl), (int (*) (const void *, const void *)) cmpdecl); - + for (d = 0; d < decls; d++) { -/* printf("%i: 0x%lx\n", d, decl[d].score); */ -/* css_dump_rule(decl[d].rule); */ +/* fprintf(stderr, "%i: 0x%lx\n", d, decl[d].score); */ +/* dump_rule(decl[d].rule);*/ css_cascade(style, decl[d].rule->style); } } @@ -340,7 +366,7 @@ static void update_style(struct css_stylesheet * stylesheet, struct css_selector struct rule * rule = find_rule(stylesheet, selector, selectors); if (rule == 0) { unsigned int h = hash_str(selector[selectors - 1].element); - /*printf("update_style: not present - adding\n");*/ + /*fprintf(stderr, "update_style: not present - adding\n");*/ rule = xcalloc(1, sizeof(struct rule)); rule->selector = selector; rule->selectors = selectors; @@ -350,7 +376,7 @@ static void update_style(struct css_stylesheet * stylesheet, struct css_selector rule->next = stylesheet->hash[h]; stylesheet->hash[h] = rule; } else { - /*printf("update_style: already present - updating\n");*/ + /*fprintf(stderr, "update_style: already present - updating\n");*/ css_parse_property_list(rule->style, str); free(selector); } @@ -392,7 +418,7 @@ void css_parse_stylesheet(struct css_stylesheet * stylesheet, char * str) if (comma != 0) *comma = 0; sel_str = strip(sels_str); - /*printf("css_parse_stylesheet: %s\n", sel_str);*/ + /*fprintf(stderr, "css_parse_stylesheet: %s\n", sel_str);*/ do { space = strchr(sel_str, ' '); if (space != 0) *space = 0; @@ -418,50 +444,60 @@ void css_parse_stylesheet(struct css_stylesheet * stylesheet, char * str) static void dump_length(const struct css_length * const length) { - printf("%g%s", length->value, + fprintf(stderr, "%g%s", length->value, css_unit_name[length->unit]); } void css_dump_style(const struct css_style * const style) { - puts("{"); - printf("\tdisplay: %s;\n", css_display_name[style->display]); - printf("\tfloat: %s;\n", css_float_name[style->float_]); - printf("\tfont-size: "); + fprintf(stderr, "{ "); + fprintf(stderr, "display: %s; ", css_display_name[style->display]); + fprintf(stderr, "float: %s; ", css_float_name[style->float_]); + fprintf(stderr, "font-size: "); switch (style->font_size.size) { - case CSS_FONT_SIZE_ABSOLUTE: printf("[%g]", style->font_size.value.absolute); break; + case CSS_FONT_SIZE_ABSOLUTE: fprintf(stderr, "[%g]", style->font_size.value.absolute); break; case CSS_FONT_SIZE_LENGTH: dump_length(&style->font_size.value.length); break; - case CSS_FONT_SIZE_PERCENT: printf("%g%%", style->font_size.value.percent); break; - case CSS_FONT_SIZE_INHERIT: printf("inherit"); break; - default: printf("UNKNOWN"); break; + case CSS_FONT_SIZE_PERCENT: fprintf(stderr, "%g%%", style->font_size.value.percent); break; + case CSS_FONT_SIZE_INHERIT: fprintf(stderr, "inherit"); break; + default: fprintf(stderr, "UNKNOWN"); break; } - puts(";"); - printf("\theight: "); + fprintf(stderr, "; "); + fprintf(stderr, "height: "); switch (style->height.height) { - case CSS_HEIGHT_AUTO: printf("auto"); break; + case CSS_HEIGHT_AUTO: fprintf(stderr, "auto"); break; case CSS_HEIGHT_LENGTH: dump_length(&style->height.length); break; - default: printf("UNKNOWN"); break; + default: fprintf(stderr, "UNKNOWN"); break; + } + fprintf(stderr, "; "); + fprintf(stderr, "line-height: "); + switch (style->line_height.size) { + case CSS_LINE_HEIGHT_ABSOLUTE: fprintf(stderr, "[%g]", style->line_height.value.absolute); break; + case CSS_LINE_HEIGHT_LENGTH: dump_length(&style->line_height.value.length); break; + case CSS_LINE_HEIGHT_PERCENT: fprintf(stderr, "%g%%", style->line_height.value.percent); break; + case CSS_LINE_HEIGHT_INHERIT: fprintf(stderr, "inherit"); break; + default: fprintf(stderr, "UNKNOWN"); break; } - puts(";"); - printf("\twidth: "); + fprintf(stderr, "; "); + fprintf(stderr, "text-align: %s; ", css_text_align_name[style->text_align]); + fprintf(stderr, "width: "); switch (style->width.width) { - case CSS_WIDTH_AUTO: printf("auto"); break; + case CSS_WIDTH_AUTO: fprintf(stderr, "auto"); break; case CSS_WIDTH_LENGTH: dump_length(&style->width.value.length); break; - case CSS_WIDTH_PERCENT: printf("%g%%", style->width.value.percent); break; - default: printf("UNKNOWN"); break; + case CSS_WIDTH_PERCENT: fprintf(stderr, "%g%%", style->width.value.percent); break; + default: fprintf(stderr, "UNKNOWN"); break; } - puts(";"); - puts("}"); + fprintf(stderr, "; "); + fprintf(stderr, "}"); } static void dump_selector(const struct css_selector * const sel) { if (sel->class != 0) - printf("%s.%s ", sel->element, sel->class); + fprintf(stderr, "'%s'.'%s' ", sel->element, sel->class); else if (sel->id != 0) - printf("%s#%s ", sel->element, sel->id); + fprintf(stderr, "'%s'#'%s' ", sel->element, sel->id); else - printf("%s ", sel->element); + fprintf(stderr, "'%s' ", sel->element); } static void dump_rule(const struct rule * rule) @@ -472,12 +508,12 @@ static void dump_rule(const struct rule * rule) css_dump_style(rule->style); } -static void css_dump_stylesheet(const struct css_stylesheet * stylesheet) +void css_dump_stylesheet(const struct css_stylesheet * stylesheet) { unsigned int i; for (i = 0; i < HASH_SIZE; i++) { struct rule * rule; - printf("hash %i:\n", i); + fprintf(stderr, "hash %i:\n", i); for (rule = stylesheet->hash[i]; rule != 0; rule = rule->next) dump_rule(rule); } @@ -552,7 +588,7 @@ int main(int argv, char *argc[]) css_dump_style(style); } -/* printf("%x %x\n", r, r2); */ +/* fprintf(stderr, "%x %x\n", r, r2); */ /* struct css_style *s; struct css_selector *sel; diff --git a/render/css.h b/render/css.h index 425db27f4..2a963f4f3 100644 --- a/render/css.h +++ b/render/css.h @@ -1,5 +1,5 @@ /** - * $Id: css.h,v 1.2 2002/05/04 21:17:06 bursa Exp $ + * $Id: css.h,v 1.3 2002/06/18 21:24:21 bursa Exp $ */ #include "css_enum.h" @@ -38,6 +38,20 @@ struct css_style { struct css_length length; } height; + struct { + enum { CSS_LINE_HEIGHT_INHERIT, + CSS_LINE_HEIGHT_ABSOLUTE, + CSS_LINE_HEIGHT_LENGTH, + CSS_LINE_HEIGHT_PERCENT } size; + union { + float absolute; + struct css_length length; + float percent; + } value; + } line_height; + + css_text_align text_align; + struct { enum { CSS_WIDTH_AUTO, CSS_WIDTH_LENGTH, @@ -52,7 +66,7 @@ struct css_style { struct css_stylesheet; struct css_selector { - char * element; + const char * element; char * class; char * id; }; @@ -69,6 +83,7 @@ void css_get_style(struct css_stylesheet * stylesheet, struct css_selector * sel unsigned int selectors, struct css_style * style); void css_parse_stylesheet(struct css_stylesheet * stylesheet, char * str); void css_dump_style(const struct css_style * const style); +void css_dump_stylesheet(const struct css_stylesheet * stylesheet); void css_cascade(struct css_style * const style, const struct css_style * const apply); void css_parse_property_list(struct css_style * style, char * str); diff --git a/render/css_enums b/render/css_enums index 4f8a3f8b0..0f5b7a87e 100644 --- a/render/css_enums +++ b/render/css_enums @@ -11,11 +11,10 @@ css_font_style normal italic oblique css_font_variant normal smallcaps css_font_weight normal bold bolder lighter 100 200 300 400 500 600 700 800 900 css_letter_spacing normal length -css_line_height normal length number percent 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 left right center justify +css_text_align inherit left right center justify css_text_decoration none blink line_through overline underline css_text_transform none capitalize lowercase uppercase css_vertical_align baseline bottom middle sub super text_bottom text_top top percent diff --git a/render/font.c b/render/font.c index 6ac3a656a..01f3cde09 100644 --- a/render/font.c +++ b/render/font.c @@ -1,11 +1,12 @@ /** - * $Id: font.c,v 1.2 2002/05/11 15:22:24 bursa Exp $ + * $Id: font.c,v 1.3 2002/06/18 21:24:21 bursa Exp $ */ #include #include #include #include +#include "css.h" #include "font.h" /** @@ -66,4 +67,8 @@ struct font_split font_split(struct font_set * font_set, font_id id, const char return split; } +unsigned long font_width(struct css_style * style, const char * text, unsigned int length) +{ + return length * 7; +} diff --git a/render/font.h b/render/font.h index 4d789a208..2ab98aaef 100644 --- a/render/font.h +++ b/render/font.h @@ -1,5 +1,5 @@ /** - * $Id: font.h,v 1.2 2002/05/11 15:22:24 bursa Exp $ + * $Id: font.h,v 1.3 2002/06/18 21:24:21 bursa Exp $ */ /** @@ -24,4 +24,5 @@ font_id font_add(struct font_set * font_set, const char * name, unsigned int wei void font_set_free(struct font_set * font_set); struct font_split font_split(struct font_set * font_set, font_id id, const char * text, unsigned long width, int force); +unsigned long font_width(struct css_style * style, const char * text, unsigned int length); diff --git a/render/layout.c b/render/layout.c index b7030a658..36c018a9e 100644 --- a/render/layout.c +++ b/render/layout.c @@ -1,5 +1,5 @@ /** - * $Id: layout.c,v 1.5 2002/05/27 23:21:11 bursa Exp $ + * $Id: layout.c,v 1.6 2002/06/18 21:24:21 bursa Exp $ */ #include @@ -18,16 +18,20 @@ * internal functions */ -signed long len(struct css_length * length, unsigned long em); +signed long len(struct css_length * length, struct css_style * style); void layout_block(struct box * box, unsigned long width, struct box * cont, unsigned long cx, unsigned long cy); unsigned long layout_block_children(struct box * box, unsigned long width, struct box * cont, unsigned long cx, unsigned long cy); void find_sides(struct box * fl, unsigned long y0, unsigned long y1, - unsigned long * x0, unsigned long * x1); + unsigned long * x0, unsigned long * x1, struct box ** left, struct box ** right); void layout_inline_container(struct box * box, unsigned long width, struct box * cont, unsigned long cx, unsigned long cy); +signed long line_height(struct css_style * style); +struct box * layout_line(struct box * first, unsigned long width, unsigned long * y, + unsigned long cy, struct box * cont); +void place_float_below(struct box * c, unsigned long width, unsigned long y, struct box * cont); void layout_table(struct box * box, unsigned long width, struct box * cont, unsigned long cx, unsigned long cy); @@ -35,11 +39,12 @@ void layout_table(struct box * box, unsigned long width, struct box * cont, * convert a struct css_length to pixels */ -signed long len(struct css_length * length, unsigned long em) +signed long len(struct css_length * length, struct css_style * style) { + assert(!((length->unit == CSS_UNIT_EM || length->unit == CSS_UNIT_EX) && style == 0)); switch (length->unit) { - case CSS_UNIT_EM: return length->value * em; - case CSS_UNIT_EX: return length->value * em * 0.6; + case CSS_UNIT_EM: return length->value * len(&style->font_size.value.length, 0); + case CSS_UNIT_EX: return length->value * len(&style->font_size.value.length, 0) * 0.6; case CSS_UNIT_PX: return length->value; case CSS_UNIT_IN: return length->value * 90.0; case CSS_UNIT_CM: return length->value * 35.0; @@ -55,22 +60,43 @@ signed long len(struct css_length * length, unsigned long em) * layout algorithm */ +/** + * layout_document -- calculate positions of boxes in a document + * + * doc root of document box tree + * width page width + */ + void layout_document(struct box * doc, unsigned long width) { doc->float_children = 0; layout_block(doc, width, doc, 0, 0); } + +/** + * layout_block -- position block and recursively layout children + * + * 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 + */ + void layout_block(struct box * box, unsigned long width, struct box * cont, unsigned long cx, unsigned long cy) { struct css_style * style = box->style; + + assert(box->type == BOX_BLOCK || box->type == BOX_FLOAT); + switch (style->width.width) { case CSS_WIDTH_AUTO: + /* take all available width */ box->width = width; break; case CSS_WIDTH_LENGTH: - box->width = len(&style->width.value.length, 20); + box->width = len(&style->width.value.length, box->style); break; case CSS_WIDTH_PERCENT: box->width = width * style->width.value.percent / 100; @@ -79,19 +105,29 @@ void layout_block(struct box * box, unsigned long width, struct box * cont, box->height = layout_block_children(box, box->width, cont, cx, cy); switch (style->height.height) { case CSS_HEIGHT_AUTO: + /* use the computed height */ break; case CSS_HEIGHT_LENGTH: - box->height = len(&style->height.length, 20); + box->height = len(&style->height.length, box->style); break; } } + +/** + * layout_block_children -- recursively layout block children + * + * (as above) + */ + unsigned long layout_block_children(struct box * box, unsigned long width, struct box * cont, unsigned long cx, unsigned long cy) { struct box * c; unsigned long y = 0; - + + assert(box->type == BOX_BLOCK || box->type == BOX_FLOAT || box->type == BOX_TABLE_CELL); + for (c = box->children; c != 0; c = c->next) { switch (c->type) { case BOX_BLOCK: @@ -122,91 +158,233 @@ unsigned long layout_block_children(struct box * box, unsigned long width, struc return y; } + +/** + * find_sides -- find left and right margins + * + * fl first float in float list + * y0, y1 y range to search + * x1, x1 margins updated + * left float on left if present + * right float on right if present + */ + void find_sides(struct box * fl, unsigned long y0, unsigned long y1, - unsigned long * x0, unsigned long * x1) + unsigned long * x0, unsigned long * x1, struct box ** left, struct box ** right) { + *left = *right = 0; for (; fl; fl = fl->next_float) { if (y0 <= fl->y + fl->height && fl->y <= y1) { - if (fl->style->float_ == CSS_FLOAT_LEFT && *x0 < fl->x + fl->width) + if (fl->style->float_ == CSS_FLOAT_LEFT && *x0 < fl->x + fl->width) { *x0 = fl->x + fl->width; - else if (fl->style->float_ == CSS_FLOAT_RIGHT && fl->x < *x1) + *left = fl; + } else if (fl->style->float_ == CSS_FLOAT_RIGHT && fl->x < *x1) { *x1 = fl->x; + *right = fl; + } } } fprintf(stderr, "find_sides: y0 %li y1 %li => x0 %li x1 %li\n", y0, y1, *x0, *x1); } + +/** + * layout_inline_container -- layout lines of text or inline boxes with floats + * + * box inline container + * width horizontal space available + * cont ancestor box which defines horizontal space, for inlines + * cx, cy box position relative to cont + */ + void layout_inline_container(struct box * box, unsigned long width, struct box * cont, unsigned long cx, unsigned long cy) { - /* TODO: write this */ struct box * c; unsigned long y = 0; - unsigned long x = 0; - unsigned long x0 = cx, x1 = cx + width; - const char * end; - struct box * c2; - struct font_split split; - find_sides(cont->float_children, cy + y, cy + y, &x0, &x1); - x = x0; + assert(box->type == BOX_INLINE_CONTAINER); for (c = box->children; c != 0; ) { - if (c->type == BOX_FLOAT) { - c->float_children = 0; - layout_block(c, width, c, 0, 0); - c->x = cx; - c->y = cy + y + 30; - fprintf(stderr, "float at %li %li, size %li %li\n", c->x, c->y, c->width, c->height); - c->next_float = cont->float_children; - cont->float_children = c; - c = c->next; - continue; + c = layout_line(c, width, &y, cy + y, cont); + } + + box->width = width; + box->height = y; +} + + +signed long line_height(struct css_style * style) +{ + assert(style->line_height.size == CSS_LINE_HEIGHT_LENGTH || + style->line_height.size == CSS_LINE_HEIGHT_ABSOLUTE); + + if (style->line_height.size == CSS_LINE_HEIGHT_LENGTH) + return len(&style->line_height.value.length, style); + else + return style->line_height.value.absolute * len(&style->font_size.value.length, 0); +} + + +struct box * layout_line(struct box * first, unsigned long width, unsigned long * y, + unsigned long cy, struct box * cont) +{ + unsigned long height; + unsigned long x0 = 0; + unsigned long x1 = width; + unsigned long x, h, xp; + struct box * left; + struct box * right; + struct box * b; + struct box * c; + struct box * d; + + fprintf(stderr, "layout_line: '%.*s' %li %li %li\n", first->length, first->text, width, *y, cy); + + /* find sides at top of line */ + find_sides(cont->float_children, cy, cy, &x0, &x1, &left, &right); + + /* get minimum line height from containing block */ + height = line_height(first->parent->parent->style); + + /* pass 1: find height of line assuming sides at top of line */ + for (x = 0, b = first; x < x1 - x0 && b != 0; b = b->next) { + assert(b->type == BOX_INLINE || b->type == BOX_FLOAT); + if (b->type == BOX_INLINE) { + h = line_height(b->style ? b->style : b->parent->parent->style); + b->height = h; + if (h > height) height = h; + x += font_width(b->style, b->text, b->length); } - - assert(c->type == BOX_INLINE); - - split = font_split(0, c->font, c->text, x1 - x, x == x0); - if (*(split.end) == 0) { - /* fits into this line */ - c->x = x; - c->y = y; - c->width = split.width; - c->height = split.height; - c->length = split.end - c->text; - x += c->width; - c = c->next; - } else if (split.end == c->text) { - /* doesn't fit at all: move down a line */ - y += 30; - x0 = cx; - x1 = cx + width; - find_sides(cont->float_children, cy + y, cy + y, &x0, &x1); - x = x0; + } + + /* find new sides using this height */ + find_sides(cont->float_children, cy, cy + height, &x0, &x1, &left, &right); + + /* pass 2: place boxes in line */ + for (x = xp = 0, b = first; x < x1 - x0 && b != 0; b = b->next) { + if (b->type == BOX_INLINE) { + b->x = x; + xp = x; + b->width = font_width(b->style, b->text, b->length); + x += b->width; + c = b; + fprintf(stderr, "layout_line: '%.*s' %li %li\n", b->length, b->text, xp, x); + } else { + b->float_children = 0; + css_dump_style(b->style); + layout_block(b, width, b, 0, 0); + if (b->width < (x1 - x0) - x || (left == 0 && right == 0 && x == 0)) { + /* fits next to this line, or this line is empty with no floats */ + if (b->style->float_ == CSS_FLOAT_LEFT) { + b->x = x0; + x0 += b->width; + left = b; + } else { + b->x = x1 - b->width; + x1 -= b->width; + right = b; + } + b->y = cy; + fprintf(stderr, "layout_line: float fits %li %li, edges %li %li\n", + b->x, b->y, x0, x1); + } else { + /* doesn't fit: place below */ + place_float_below(b, width, cy + height + 1, cont); + fprintf(stderr, "layout_line: float doesn't fit %li %li\n", b->x, b->y); + } + b->next_float = cont->float_children; + cont->float_children = b; + } + } + + if (x1 - x0 < x) { + /* the last box went over the end */ + char * space = strchr(c->text, ' '); + char * space2 = space; + unsigned long w = font_width(c->style, c->text, space - c->text), wp = w; + struct box * c2; + + if (x1 - x0 < xp + w && left == 0 && right == 0 && c == first) { + /* first word doesn't fit, but no floats and first on line so force in */ + c2 = memcpy(xcalloc(1, sizeof(struct box)), c, sizeof(struct box)); + c2->text = space + 1; + c2->length = c->length - (c2->text - c->text); + c->length = space - c->text; + c2->next = c->next; + c->next = c2; + b = c2; + fprintf(stderr, "layout_line: overflow, forcing\n"); + } else if (x1 - x0 < xp + w) { + /* first word doesn't fit, but full width not available so leave for later */ + b = c; + fprintf(stderr, "layout_line: overflow, leaving\n"); } else { - /* split into two lines */ - c->x = x; - c->y = y; - c->width = split.width; - c->height = split.height; - c->length = split.end - c->text; - y += 30; - x0 = cx; - x1 = cx + width; - find_sides(cont->float_children, cy + y, cy + y, &x0, &x1); - x = x0; + /* fit as many words as possible */ + while (xp + w < x1 - x0) { + fprintf(stderr, "%li + %li = %li < %li = %li - %li\n", + xp, w, xp + w, x1 - x0, x1, x0); + space = space2; + wp = w; + space2 = strchr(space + 1, ' '); + w = font_width(c->style, c->text, space2 - c->text); + } c2 = memcpy(xcalloc(1, sizeof(struct box)), c, sizeof(struct box)); - c2->text = split.end; + c2->text = space + 1; + c2->length = c->length - (c2->text - c->text); + c->length = space - c->text; c2->next = c->next; c->next = c2; - c = c2; + b = c2; + fprintf(stderr, "layout_line: overflow, fit\n"); } + c->width = wp; } - box->width = width; - box->height = y + 30; + /* set positions */ + for (d = first; d != b; d = d->next) { + if (d->type == BOX_INLINE) { + d->x += x0; + d->y = *y; + } + } + + *y += height + 1; + return b; } + + +void place_float_below(struct box * c, unsigned long width, unsigned long y, struct box * cont) +{ + unsigned long x0, x1, yy = y; + struct box * left; + struct box * right; + do { + y = yy; + x0 = 0; + x1 = width; + find_sides(cont->float_children, y, y, &x0, &x1, &left, &right); + if (left != 0 && right != 0) { + yy = (left->y + left->height < right->y + right->height ? + left->y + left->height : right->y + right->height) + 1; + } else if (left == 0 && right != 0) { + yy = right->y + right->height + 1; + } else if (left != 0 && right == 0) { + yy = left->y + left->height + 1; + } + } while (!((left == 0 && right == 0) || (c->width < x1 - x0))); + + if (c->style->float_ == CSS_FLOAT_LEFT) { + c->x = x0; + } else { + c->x = x1 - c->width; + } + c->y = y; +} + + + /** * layout a table * @@ -235,7 +413,7 @@ void layout_table(struct box * table, unsigned long width, struct box * cont, /* find table width */ switch (table->style->width.width) { case CSS_WIDTH_LENGTH: - table_width = len(&table->style->width.value.length, 20); + table_width = len(&table->style->width.value.length, table->style); break; case CSS_WIDTH_PERCENT: table_width = width * table->style->width.value.percent / 100; @@ -252,7 +430,7 @@ void layout_table(struct box * table, unsigned long width, struct box * cont, assert(c->type == BOX_TABLE_CELL); switch (c->style->width.width) { case CSS_WIDTH_LENGTH: - used_width += len(&c->style->width.value.length, 20); + used_width += len(&c->style->width.value.length, c->style); break; case CSS_WIDTH_PERCENT: used_width += table_width * c->style->width.value.percent / 100; @@ -277,7 +455,7 @@ void layout_table(struct box * table, unsigned long width, struct box * cont, for (i = 1, c = table->children->children; c != 0; i++, c = c->next) { switch (c->style->width.width) { case CSS_WIDTH_LENGTH: - x += len(&c->style->width.value.length, 10) + extra_width; + x += len(&c->style->width.value.length, c->style) + extra_width; break; case CSS_WIDTH_PERCENT: x += table_width * c->style->width.value.percent / 100 + extra_width; @@ -305,7 +483,7 @@ void layout_table(struct box * table, unsigned long width, struct box * cont, case CSS_HEIGHT_AUTO: break; case CSS_HEIGHT_LENGTH: - c->height = len(&c->style->height.length, 10); + c->height = len(&c->style->height.length, c->style); break; } c->x = xs[i]; diff --git a/render/render.c b/render/render.c index 0ec17fb37..66009fe65 100644 --- a/render/render.c +++ b/render/render.c @@ -1,5 +1,5 @@ /** - * $Id: render.c,v 1.12 2002/05/27 23:21:11 bursa Exp $ + * $Id: render.c,v 1.13 2002/06/18 21:24:21 bursa Exp $ */ #include @@ -15,7 +15,7 @@ #include "layout.h" /** - * internal functions + * internal functions */ void render_plain_element(char * g, struct box * box, unsigned long x, unsigned long y); @@ -141,9 +141,11 @@ int main(int argc, char *argv[]) xmlDoc * doc; struct box * doc_box = xcalloc(1, sizeof(struct box)); struct box * html_box; + char * f; if (argc < 3) die("usage: render htmlfile cssfile"); - + + fprintf(stderr, "Parsing html...\n"); doc = htmlParseFile(argv[1], 0); if (doc == 0) die("htmlParseFile failed"); @@ -152,22 +154,29 @@ int main(int argc, char *argv[]) if (c == 0) die("no element in document"); if (strcmp(c->name, "html")) die("document is not html"); + fprintf(stderr, "Parsing css...\n"); + f = load(argv[2]); stylesheet = css_new_stylesheet(); - css_parse_stylesheet(stylesheet, load(argv[2])); + css_parse_stylesheet(stylesheet, f); +/* css_dump_stylesheet(stylesheet);*/ memcpy(style, &css_base_style, sizeof(struct css_style)); doc_box->type = BOX_BLOCK; doc_box->node = c; + fprintf(stderr, "XML tree to box tree...\n"); xml_to_box(c, style, stylesheet, &selector, 0, doc_box, 0); html_box = doc_box->children; - /*box_dump(html_box, 0);*/ + box_dump(html_box, 0); + fprintf(stderr, "Layout document...\n"); layout_document(html_box, 600); -/* box_dump(html_box, 0);*/ + box_dump(html_box, 0); /* render_plain(html_box);*/ + + fprintf(stderr, "Rendering...\n"); printf("%li %li\n", html_box->width, html_box->height); render_dump(html_box, 0, 0); - + return 0; } diff --git a/render/show.tcl b/render/show.tcl index 4adc48287..2688c6cc8 100644 --- a/render/show.tcl +++ b/render/show.tcl @@ -10,7 +10,7 @@ proc rect {x y w h n t c} { set y [expr $y+8] .can create rectangle $x $y [expr $x+$w] [expr $y+$h] -fill $c .can create text $x $y -anchor nw -text $n -fill red -font "arial 18 bold" - .can create text $x [expr $y+$h] -anchor sw -text $t -font "courier 32" + .can create text $x [expr $y+$h] -anchor sw -text $t -font "courier 12" } while {-1 != [gets stdin line]} { diff --git a/utils/utils.c b/utils/utils.c index 8440c7b12..857c205c1 100644 --- a/utils/utils.c +++ b/utils/utils.c @@ -1,5 +1,5 @@ /** - * $Id: utils.c,v 1.2 2002/05/21 21:27:29 bursa Exp $ + * $Id: utils.c,v 1.3 2002/06/18 21:24:21 bursa Exp $ */ #include @@ -54,23 +54,21 @@ char * xstrdup(const char * const s) return c; } -#define CHUNK 0x100 - char * load(const char * const path) { - FILE * fp = fopen(path, "r"); - unsigned int l = 0; - char * buf = malloc(CHUNK); - if (buf == 0) die("Out of memory in load()"); - while (1) { - unsigned int i; - for (i = 0; i != CHUNK && (buf[l] = fgetc(fp)) != EOF; i++, l++) - ; - if (i != CHUNK) break; - buf = xrealloc(buf, l + CHUNK); - } - buf[l] = 0; - fclose(fp); + FILE * fp = fopen(path, "rb"); + char * buf; + long size, read; + + if (fp == 0) die("Failed to open file"); + if (fseek(fp, 0, SEEK_END) != 0) die("fseek() failed"); + if ((size = ftell(fp)) == -1) die("ftell() failed"); + buf = xcalloc(size, 1); + + if (fseek(fp, 0, SEEK_SET) != 0) die("fseek() failed"); + read = fread(buf, 1, size, fp); + if (read < size) die("fread() failed"); + return buf; } -- cgit v1.2.3