From a21d245091e7f7d6ae6a9e08dc107b9dd495e4fb Mon Sep 17 00:00:00 2001 From: James Bursa Date: Sun, 18 Aug 2002 16:46:45 +0000 Subject: [project @ 2002-08-18 16:46:45 by bursa] Big changes to xml_to_box(), table row groups. svn path=/import/netsurf/; revision=31 --- render/box.c | 416 +++++++++++++++++++++++++++++++++++++++++++++----------- render/box.h | 5 +- render/layout.c | 78 ++++++----- 3 files changed, 384 insertions(+), 115 deletions(-) diff --git a/render/box.c b/render/box.c index 24eb231ed..beda7c153 100644 --- a/render/box.c +++ b/render/box.c @@ -1,5 +1,5 @@ /** - * $Id: box.c,v 1.10 2002/08/11 23:00:24 bursa Exp $ + * $Id: box.c,v 1.11 2002/08/18 16:46:45 bursa Exp $ */ #include @@ -8,10 +8,10 @@ #include #include #include "libxml/HTMLparser.h" -#include "css.h" -#include "font.h" -#include "box.h" -#include "utils.h" +#include "netsurf/render/css.h" +#include "netsurf/render/font.h" +#include "netsurf/render/box.h" +#include "netsurf/render/utils.h" /** * internal functions @@ -20,8 +20,18 @@ void box_add_child(struct box * parent, struct box * child); struct box * box_create(xmlNode * node, box_type type, struct css_style * style, const char *href); +struct box * convert_xml_to_box(xmlNode * n, struct css_style * parent_style, + struct css_stylesheet * stylesheet, + struct css_selector ** selector, unsigned int depth, + struct box * parent, struct box * inline_container, + const char *href); struct css_style * box_get_style(struct css_stylesheet * stylesheet, struct css_style * parent_style, xmlNode * n, struct css_selector * selector, unsigned int depth); +void box_normalise_block(struct box *block); +void box_normalise_table(struct box *table); +void box_normalise_table_row_group(struct box *row_group); +void box_normalise_table_row(struct box *row); +void box_normalise_inline_container(struct box *cont); /** @@ -30,7 +40,7 @@ struct css_style * box_get_style(struct css_stylesheet * stylesheet, struct css_ void box_add_child(struct box * parent, struct box * child) { - if (parent->children) /* has children already */ + if (parent->children != 0) /* has children already */ parent->last->next = child; else /* this is the first child */ parent->children = child; @@ -47,11 +57,19 @@ struct box * box_create(xmlNode * node, box_type type, struct css_style * style, const char *href) { struct box * box = xcalloc(1, sizeof(struct box)); - box->node = node; box->type = type; + box->node = node; box->style = style; box->text = 0; box->href = href; + box->length = 0; + box->colspan = 1; + box->next = 0; + box->children = 0; + box->last = 0; + box->parent = 0; + box->float_children = 0; + box->next_float = 0; return box; } @@ -71,7 +89,20 @@ struct box * box_create(xmlNode * node, box_type type, struct css_style * style, * updated current inline container */ -struct box * xml_to_box(xmlNode * n, struct css_style * parent_style, struct css_stylesheet * stylesheet, +void xml_to_box(xmlNode * n, struct css_style * parent_style, + struct css_stylesheet * stylesheet, + struct css_selector ** selector, unsigned int depth, + struct box * parent, struct box * inline_container, + const char *href) +{ + convert_xml_to_box(n, parent_style, stylesheet, + selector, depth, parent, inline_container, href); + box_normalise_block(parent->children); +} + + +struct box * convert_xml_to_box(xmlNode * n, struct css_style * parent_style, + struct css_stylesheet * stylesheet, struct css_selector ** selector, unsigned int depth, struct box * parent, struct box * inline_container, const char *href) @@ -110,34 +141,6 @@ struct box * xml_to_box(xmlNode * n, struct css_style * parent_style, struct css if (inline_container == 0) { /* this is the first inline node: make a container */ inline_container = xcalloc(1, sizeof(struct box)); inline_container->type = BOX_INLINE_CONTAINER; - switch (parent->type) { - case BOX_TABLE: - /* insert implied table row and cell */ - style2 = xcalloc(1, sizeof(struct css_style)); - memcpy(style2, parent_style, sizeof(struct css_style)); - css_cascade(style2, &css_blank_style); - box = box_create(0, BOX_TABLE_ROW, style2, href); - box_add_child(parent, box); - parent = box; - /* fall through */ - case BOX_TABLE_ROW: - /* insert implied table cell */ - style2 = xcalloc(1, sizeof(struct css_style)); - memcpy(style2, parent_style, sizeof(struct css_style)); - css_cascade(style2, &css_blank_style); - box = box_create(0, BOX_TABLE_CELL, style2, href); - box->colspan = 1; - box_add_child(parent, box); - parent = box; - break; - case BOX_BLOCK: - case BOX_TABLE_CELL: - case BOX_FLOAT_LEFT: - case BOX_FLOAT_RIGHT: - break; - default: - assert(0); - } box_add_child(parent, inline_container); } if (n->type == XML_TEXT_NODE) { @@ -159,46 +162,18 @@ struct box * xml_to_box(xmlNode * n, struct css_style * parent_style, struct css if (n->type == XML_ELEMENT_NODE) { switch (style->display) { case CSS_DISPLAY_BLOCK: /* blocks get a node in the box tree */ - switch (parent->type) { - case BOX_TABLE: - /* insert implied table row and cell */ - style2 = xcalloc(1, sizeof(struct css_style)); - memcpy(style2, parent_style, sizeof(struct css_style)); - css_cascade(style2, &css_blank_style); - box = box_create(0, BOX_TABLE_ROW, style2, href); - box_add_child(parent, box); - parent = box; - /* fall through */ - case BOX_TABLE_ROW: - /* insert implied table cell */ - style2 = xcalloc(1, sizeof(struct css_style)); - memcpy(style2, parent_style, sizeof(struct css_style)); - css_cascade(style2, &css_blank_style); - box = box_create(0, BOX_TABLE_CELL, style2, href); - box->colspan = 1; - box_add_child(parent, box); - parent = box; - break; - case BOX_BLOCK: - case BOX_TABLE_CELL: - case BOX_FLOAT_LEFT: - case BOX_FLOAT_RIGHT: - break; - default: - assert(0); - } box = box_create(n, BOX_BLOCK, style, href); box_add_child(parent, box); inline_container_c = 0; for (c = n->children; c != 0; c = c->next) - inline_container_c = xml_to_box(c, style, stylesheet, + inline_container_c = convert_xml_to_box(c, style, stylesheet, selector, depth + 1, box, inline_container_c, href); inline_container = 0; break; case CSS_DISPLAY_INLINE: /* inline elements get no box, but their children do */ for (c = n->children; c != 0; c = c->next) - inline_container = xml_to_box(c, style, stylesheet, + inline_container = convert_xml_to_box(c, style, stylesheet, selector, depth + 1, parent, inline_container, href); break; @@ -206,32 +181,33 @@ struct box * xml_to_box(xmlNode * n, struct css_style * parent_style, struct css box = box_create(n, BOX_TABLE, style, href); box_add_child(parent, box); for (c = n->children; c != 0; c = c->next) - xml_to_box(c, style, stylesheet, + convert_xml_to_box(c, style, stylesheet, selector, depth + 1, box, 0, href); inline_container = 0; break; + case CSS_DISPLAY_TABLE_ROW_GROUP: + case CSS_DISPLAY_TABLE_HEADER_GROUP: + case CSS_DISPLAY_TABLE_FOOTER_GROUP: + box = box_create(n, BOX_TABLE_ROW_GROUP, style, href); + box_add_child(parent, box); + inline_container_c = 0; + for (c = n->children; c != 0; c = c->next) + inline_container_c = convert_xml_to_box(c, style, stylesheet, + selector, depth + 1, box, inline_container_c, + href); + inline_container = 0; + break; case CSS_DISPLAY_TABLE_ROW: - if (parent->type != BOX_TABLE) { - /* insert implied table */ - style2 = xcalloc(1, sizeof(struct css_style)); - memcpy(style2, parent_style, sizeof(struct css_style)); - css_cascade(style2, &css_blank_style); - box = box_create(0, BOX_TABLE, style2, href); - box_add_child(parent, box); - parent = box; - } - assert(parent->type == BOX_TABLE); box = box_create(n, BOX_TABLE_ROW, style, href); box_add_child(parent, box); for (c = n->children; c != 0; c = c->next) - xml_to_box(c, style, stylesheet, + convert_xml_to_box(c, style, stylesheet, selector, depth + 1, box, 0, href); inline_container = 0; break; case CSS_DISPLAY_TABLE_CELL: - assert(parent->type == BOX_TABLE_ROW); box = box_create(n, BOX_TABLE_CELL, style, href); if ((s = (char *) xmlGetProp(n, (xmlChar *) "colspan"))) { if ((box->colspan = strtol(s, 0, 10)) == 0) @@ -241,7 +217,7 @@ struct box * xml_to_box(xmlNode * n, struct css_style * parent_style, struct css box_add_child(parent, box); inline_container_c = 0; for (c = n->children; c != 0; c = c->next) - inline_container_c = xml_to_box(c, style, stylesheet, + inline_container_c = convert_xml_to_box(c, style, stylesheet, selector, depth + 1, box, inline_container_c, href); inline_container = 0; @@ -335,6 +311,7 @@ void box_dump(struct box * box, unsigned int depth) case BOX_TABLE_ROW: fprintf(stderr, "BOX_TABLE_ROW "); break; case BOX_TABLE_CELL: fprintf(stderr, "BOX_TABLE_CELL [colspan %i] ", box->colspan); break; + case BOX_TABLE_ROW_GROUP: fprintf(stderr, "BOX_TABLE_ROW_GROUP "); break; case BOX_FLOAT_LEFT: fprintf(stderr, "BOX_FLOAT_LEFT "); break; case BOX_FLOAT_RIGHT: fprintf(stderr, "BOX_FLOAT_RIGHT "); break; default: fprintf(stderr, "Unknown box type "); @@ -351,3 +328,282 @@ void box_dump(struct box * box, unsigned int depth) box_dump(c, depth + 1); } + +/* + * ensure the box tree is correctly nested + */ + +void box_normalise_block(struct box *block) +{ + struct box *child; + struct box *prev_child = 0; + struct box *table; + struct css_style *style; + + assert(block->type == BOX_BLOCK || block->type == BOX_TABLE_CELL); + + for (child = block->children; child != 0; prev_child = child, child = child->next) { + switch (child->type) { + case BOX_BLOCK: + /* ok */ + box_normalise_block(child); + break; + case BOX_INLINE_CONTAINER: + box_normalise_inline_container(child); + break; + case BOX_TABLE: + box_normalise_table(child); + break; + case BOX_INLINE: + case BOX_FLOAT_LEFT: + case BOX_FLOAT_RIGHT: + /* should have been wrapped in inline + container by convert_xml_to_box() */ + assert(0); + break; + case BOX_TABLE_ROW_GROUP: + case BOX_TABLE_ROW: + case BOX_TABLE_CELL: + /* insert implied table */ + style = xcalloc(1, sizeof(struct css_style)); + memcpy(style, block->style, sizeof(struct css_style)); + css_cascade(style, &css_blank_style); + table = box_create(0, BOX_TABLE, style, block->href); + if (prev_child == 0) + block->children = table; + else + prev_child->next = table; + while (child != 0 && ( + child->type == BOX_TABLE_ROW_GROUP || + child->type == BOX_TABLE_ROW || + child->type == BOX_TABLE_CELL)) { + box_add_child(table, child); + prev_child = child; + child = child->next; + } + prev_child->next = 0; + table->next = child; + box_normalise_table(table); + child = table; + break; + default: + assert(0); + } + } +} + + +void box_normalise_table(struct box *table) +{ + struct box *child; + struct box *prev_child = 0; + struct box *row_group; + struct css_style *style; + + assert(table->type == BOX_TABLE); + + for (child = table->children; child != 0; prev_child = child, child = child->next) { + switch (child->type) { + case BOX_TABLE_ROW_GROUP: + /* ok */ + box_normalise_table_row_group(child); + break; + case BOX_BLOCK: + case BOX_INLINE_CONTAINER: + case BOX_TABLE: + case BOX_TABLE_ROW: + case BOX_TABLE_CELL: + /* insert implied table row group */ + fprintf(stderr, "inserting implied table row group\n"); + style = xcalloc(1, sizeof(struct css_style)); + memcpy(style, table->style, sizeof(struct css_style)); + css_cascade(style, &css_blank_style); + row_group = box_create(0, BOX_TABLE_ROW_GROUP, style, table->href); + if (prev_child == 0) + table->children = row_group; + else + prev_child->next = row_group; + while (child != 0 && ( + child->type == BOX_BLOCK || + child->type == BOX_INLINE_CONTAINER || + child->type == BOX_TABLE || + child->type == BOX_TABLE_ROW || + child->type == BOX_TABLE_CELL)) { + box_add_child(row_group, child); + prev_child = child; + child = child->next; + } + prev_child->next = 0; + row_group->next = child; + box_normalise_table_row_group(row_group); + child = row_group; + break; + case BOX_INLINE: + case BOX_FLOAT_LEFT: + case BOX_FLOAT_RIGHT: + /* should have been wrapped in inline + container by convert_xml_to_box() */ + assert(0); + break; + default: + fprintf(stderr, "%i\n", child->type); + assert(0); + } + } +} + + +void box_normalise_table_row_group(struct box *row_group) +{ + struct box *child; + struct box *prev_child = 0; + struct box *row; + struct css_style *style; + + assert(row_group->type == BOX_TABLE_ROW_GROUP); + + for (child = row_group->children; child != 0; prev_child = child, child = child->next) { + switch (child->type) { + case BOX_TABLE_ROW: + /* ok */ + box_normalise_table_row(child); + break; + case BOX_BLOCK: + case BOX_INLINE_CONTAINER: + case BOX_TABLE: + case BOX_TABLE_ROW_GROUP: + case BOX_TABLE_CELL: + /* insert implied table row */ + style = xcalloc(1, sizeof(struct css_style)); + memcpy(style, row_group->style, sizeof(struct css_style)); + css_cascade(style, &css_blank_style); + row = box_create(0, BOX_TABLE_ROW, style, row_group->href); + if (prev_child == 0) + row_group->children = row; + else + prev_child->next = row; + while (child != 0 && ( + child->type == BOX_BLOCK || + child->type == BOX_INLINE_CONTAINER || + child->type == BOX_TABLE || + child->type == BOX_TABLE_ROW_GROUP || + child->type == BOX_TABLE_CELL)) { + box_add_child(row, child); + prev_child = child; + child = child->next; + } + prev_child->next = 0; + row->next = child; + box_normalise_table_row(row); + child = row; + break; + case BOX_INLINE: + case BOX_FLOAT_LEFT: + case BOX_FLOAT_RIGHT: + /* should have been wrapped in inline + container by convert_xml_to_box() */ + assert(0); + break; + default: + assert(0); + } + } +} + + +void box_normalise_table_row(struct box *row) +{ + struct box *child; + struct box *prev_child = 0; + struct box *cell; + struct css_style *style; + + assert(row->type == BOX_TABLE_ROW); + + for (child = row->children; child != 0; prev_child = child, child = child->next) { + switch (child->type) { + case BOX_TABLE_CELL: + /* ok */ + box_normalise_block(child); + break; + case BOX_BLOCK: + case BOX_INLINE_CONTAINER: + case BOX_TABLE: + case BOX_TABLE_ROW_GROUP: + case BOX_TABLE_ROW: + /* insert implied table cell */ + style = xcalloc(1, sizeof(struct css_style)); + memcpy(style, row->style, sizeof(struct css_style)); + css_cascade(style, &css_blank_style); + cell = box_create(0, BOX_TABLE_CELL, style, row->href); + if (prev_child == 0) + row->children = cell; + else + prev_child->next = cell; + while (child != 0 && ( + child->type == BOX_BLOCK || + child->type == BOX_INLINE_CONTAINER || + child->type == BOX_TABLE || + child->type == BOX_TABLE_ROW_GROUP || + child->type == BOX_TABLE_ROW)) { + box_add_child(cell, child); + prev_child = child; + child = child->next; + } + prev_child->next = 0; + cell->next = child; + box_normalise_block(cell); + child = cell; + break; + case BOX_INLINE: + case BOX_FLOAT_LEFT: + case BOX_FLOAT_RIGHT: + /* should have been wrapped in inline + container by convert_xml_to_box() */ + assert(0); + break; + default: + assert(0); + } + } +} + + +void box_normalise_inline_container(struct box *cont) +{ + struct box *child; + struct box *prev_child = 0; + + assert(cont->type == BOX_INLINE_CONTAINER); + + for (child = cont->children; child != 0; prev_child = child, child = child->next) { + switch (child->type) { + case BOX_INLINE: + /* ok */ + break; + case BOX_FLOAT_LEFT: + case BOX_FLOAT_RIGHT: + /* ok */ + assert(child->children != 0); + switch (child->children->type) { + case BOX_BLOCK: + box_normalise_block(child->children); + break; + case BOX_TABLE: + box_normalise_table(child->children); + break; + default: + assert(0); + } + break; + case BOX_BLOCK: + case BOX_INLINE_CONTAINER: + case BOX_TABLE: + case BOX_TABLE_ROW_GROUP: + case BOX_TABLE_ROW: + case BOX_TABLE_CELL: + default: + assert(0); + } + } +} diff --git a/render/box.h b/render/box.h index ed4000d86..50b2538fa 100644 --- a/render/box.h +++ b/render/box.h @@ -1,5 +1,5 @@ /** - * $Id: box.h,v 1.6 2002/08/11 23:01:02 bursa Exp $ + * $Id: box.h,v 1.7 2002/08/18 16:46:45 bursa Exp $ */ #ifndef _NETSURF_RENDER_BOX_H_ @@ -15,6 +15,7 @@ typedef enum { BOX_BLOCK, BOX_INLINE_CONTAINER, BOX_INLINE, BOX_TABLE, BOX_TABLE_ROW, BOX_TABLE_CELL, + BOX_TABLE_ROW_GROUP, BOX_FLOAT_LEFT, BOX_FLOAT_RIGHT } box_type; @@ -39,7 +40,7 @@ struct box { * interface */ -struct box * xml_to_box(xmlNode * n, struct css_style * parent_style, struct css_stylesheet * stylesheet, +void xml_to_box(xmlNode * n, struct css_style * parent_style, struct css_stylesheet * stylesheet, struct css_selector ** selector, unsigned int depth, struct box * parent, struct box * inline_container, const char *href); diff --git a/render/layout.c b/render/layout.c index 29286e4e5..f2548d3cc 100644 --- a/render/layout.c +++ b/render/layout.c @@ -1,5 +1,5 @@ /** - * $Id: layout.c,v 1.12 2002/08/05 20:34:45 bursa Exp $ + * $Id: layout.c,v 1.13 2002/08/18 16:46:45 bursa Exp $ */ #include @@ -14,7 +14,7 @@ #include "netsurf/render/utils.h" #include "netsurf/render/layout.h" -#define DEBUG_LAYOUT +/* #define DEBUG_LAYOUT */ /** * internal functions @@ -116,6 +116,7 @@ void layout_block(struct box * box, unsigned long width, struct box * cont, struct css_style * style = box->style; assert(box->type == BOX_BLOCK); + assert(style != 0); #ifdef DEBUG_LAYOUT fprintf(stderr, "layout_block(%p, %lu, %p, %lu, %lu)\n", @@ -168,7 +169,7 @@ unsigned long layout_block_children(struct box * box, unsigned long width, struc #endif for (c = box->children; c != 0; c = c->next) { - if (c->style && c->style->clear != CSS_CLEAR_NONE) { + if (c->style != 0 && c->style->clear != CSS_CLEAR_NONE) { unsigned long x0, x1; struct box * left, * right; do { @@ -260,6 +261,7 @@ void layout_inline_container(struct box * box, unsigned long width, struct box * signed long line_height(struct css_style * style) { + assert(style != 0); assert(style->line_height.size == CSS_LINE_HEIGHT_LENGTH || style->line_height.size == CSS_LINE_HEIGHT_ABSOLUTE); @@ -472,14 +474,16 @@ void layout_table(struct box * table, unsigned long width, struct box * cont, unsigned long auto_width; /* width of each auto column (all equal) */ unsigned long extra_width = 0; /* extra width for each column if table is wider than columns */ unsigned long x; - unsigned long y = 0; - unsigned long * xs; + unsigned long table_height = 0; + unsigned long *xs; /* array of column x positions */ unsigned int i; unsigned int subcol; - struct box * c; - struct box * r; + struct box *c; + struct box *row; + struct box *row_group; assert(table->type == BOX_TABLE); + assert(table->style != 0); #ifdef DEBUG_LAYOUT fprintf(stderr, "layout_table(%p, %lu, %p, %lu, %lu)\n", @@ -503,8 +507,10 @@ void layout_table(struct box * table, unsigned long width, struct box * cont, /* fprintf(stderr, "table width %lu\n", table_width); */ /* calculate number of columns and width used by fixed columns */ - for (c = table->children->children; c != 0; c = c->next) { + assert(table->children != 0 && table->children->children != 0); + for (c = table->children->children->children; c != 0; c = c->next) { assert(c->type == BOX_TABLE_CELL); + assert(c->style != 0); switch (c->style->width.width) { case CSS_WIDTH_LENGTH: used_width += len(&c->style->width.value.length, c->style); @@ -516,13 +522,14 @@ void layout_table(struct box * table, unsigned long width, struct box * cont, default: break; } + assert(c->colspan != 0); columns += c->colspan; } assert(columns != 0); /* percentages are relative to remaining width */ percent_width = used_width < table_width ? table_width - used_width : 0; - for (c = table->children->children; c != 0; c = c->next) + for (c = table->children->children->children; c != 0; c = c->next) if (c->style->width.width == CSS_WIDTH_PERCENT) used_width += percent_width * c->style->width.value.percent / 100; @@ -542,7 +549,7 @@ void layout_table(struct box * table, unsigned long width, struct box * cont, /* find column widths */ xs = xcalloc(columns + 1, sizeof(*xs)); xs[0] = x = 0; - for (i = 1, c = table->children->children, subcol = 1; c != 0; i++) { + for (i = 1, c = table->children->children->children, subcol = 1; c != 0; i++) { switch (c->style->width.width) { case CSS_WIDTH_LENGTH: assert(c->colspan != 0); @@ -558,11 +565,12 @@ void layout_table(struct box * table, unsigned long width, struct box * cont, x += auto_width; break; } + assert(i < columns + 1); xs[i] = x; - if (subcol == c->colspan) - c = c->next, + if (subcol == c->colspan) { + c = c->next; subcol = 1; - else + } else subcol++; /* fprintf(stderr, "%i\n", x); */ } @@ -574,33 +582,37 @@ void layout_table(struct box * table, unsigned long width, struct box * cont, /* fprintf(stderr, "table width %lu\n", table_width); */ /* position cells */ - for (r = table->children; r != 0; r = r->next) { - unsigned long height = 0; - for (i = 0, c = r->children; c != 0; i += c->colspan, c = c->next) { - c->width = xs[i + c->colspan] - xs[i]; - c->float_children = 0; - c->height = layout_block_children(c, c->width, c, 0, 0); - switch (c->style->height.height) { - case CSS_HEIGHT_AUTO: - break; - case CSS_HEIGHT_LENGTH: + for (row_group = table->children; row_group != 0; row_group = row_group->next) { + unsigned long row_group_height = 0; + for (row = row_group->children; row != 0; row = row->next) { + unsigned long row_height = 0; + for (i = 0, c = row->children; c != 0; i += c->colspan, c = c->next) { + assert(c->style != 0); + c->width = xs[i + c->colspan] - xs[i]; + c->float_children = 0; + c->height = layout_block_children(c, c->width, c, 0, 0); + if (c->style->height.height == CSS_HEIGHT_LENGTH) c->height = len(&c->style->height.length, c->style); - break; + c->x = xs[i]; + c->y = 0; + if (c->height > row_height) row_height = c->height; } - c->x = xs[i]; - c->y = 0; - if (c->height > height) height = c->height; + row->x = 0; + row->y = row_group_height; + row->width = table_width; + row->height = row_height; + row_group_height += row_height; } - r->x = 0; - r->y = y; - r->width = table_width; - r->height = height; - y += height; + row_group->x = 0; + row_group->y = table_height; + row_group->width = table_width; + row_group->height = row_group_height; + table_height += row_group_height; } free(xs); table->width = table_width; - table->height = y; + table->height = table_height; } -- cgit v1.2.3