From 50d95fdf6f598dc679c7065cd5ced044d5abcd8e Mon Sep 17 00:00:00 2001 From: James Bursa Date: Sat, 4 May 2002 19:57:18 +0000 Subject: [project @ 2002-05-04 19:57:18 by bursa] Split box and layout modules from render.c. svn path=/import/netsurf/; revision=13 --- render/layout.c | 267 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 267 insertions(+) create mode 100644 render/layout.c (limited to 'render/layout.c') diff --git a/render/layout.c b/render/layout.c new file mode 100644 index 000000000..af0760362 --- /dev/null +++ b/render/layout.c @@ -0,0 +1,267 @@ +/** + * $Id: layout.c,v 1.1 2002/05/04 19:57:18 bursa Exp $ + */ + +#include +#include +#include +#include +#include +#include "libxml/HTMLparser.h" +#include "css.h" +#include "font.h" +#include "box.h" +#include "utils.h" + +/** + * internal functions + */ + +signed long len(struct css_length * length, unsigned long em); + +unsigned long layout_block_children(struct box * box, unsigned long width); +void layout_inline_container(struct box * box, unsigned long width); +void layout_table(struct box * box, unsigned long width); + + +/** + * convert a struct css_length to pixels + */ + +signed long len(struct css_length * length, unsigned long em) +{ + switch (length->unit) { + case CSS_UNIT_EM: return length->value * em; + case CSS_UNIT_EX: return length->value * em * 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; + case CSS_UNIT_MM: return length->value * 3.5; + case CSS_UNIT_PT: return length->value * 90.0 / 72.0; + case CSS_UNIT_PC: return length->value * 90.0 / 6.0; + default: return 0; + } + return 0; +} + +/** + * layout algorithm + */ + +void layout_block(struct box * box, unsigned long width) +{ + struct css_style * style = box->style; + switch (style->width.width) { + case CSS_WIDTH_AUTO: + box->width = width; + break; + case CSS_WIDTH_LENGTH: + box->width = len(&style->width.value.length, 10); + break; + case CSS_WIDTH_PERCENT: + box->width = width * style->width.value.percent / 100; + break; + } + box->height = layout_block_children(box, box->width); + switch (style->height.height) { + case CSS_HEIGHT_AUTO: + break; + case CSS_HEIGHT_LENGTH: + box->height = len(&style->height.length, 10); + break; + } +} + +unsigned long layout_block_children(struct box * box, unsigned long width) +{ + struct box * c; + unsigned long y = 1; + + for (c = box->children; c != 0; c = c->next) { + switch (c->type) { + case BOX_BLOCK: + layout_block(c, width-4); + c->x = 2; + c->y = y; + y += c->height + 1; + break; + case BOX_INLINE_CONTAINER: + layout_inline_container(c, width-4); + c->x = 2; + c->y = y; + y += c->height + 1; + break; + case BOX_TABLE: + layout_table(c, width-4); + c->x = 2; + c->y = y; + y += c->height + 1; + break; + default: + die("block child not block, table, or inline container"); + } + } + return y; +} + +void layout_inline_container(struct box * box, unsigned long width) +{ + /* TODO: write this */ + struct box * c; + unsigned long y = 1; + unsigned long x = 2; + const char * end; + struct box * new; + + for (c = box->children; c != 0; ) { + c->width = font_split(0, c->font, c->text, width-2-x, &end)+1; + if (*end == 0) { + /* fits into this line */ + c->x = x; + c->y = y; + c->height = 2; + x += c->width; + c = c->next; + continue; + } + if (end == c->text) { + /* doesn't fit at all: move down a line */ + x = 2; + y += 3; + c->width = font_split(0, c->font, c->text, width-2-x, &end)+1; + if (end == c->text) end = strchr(c->text, ' '); + if (end == 0) end = c->text + 1; + } + /* split into two lines */ + c->x = x; + c->y = y; + c->height = 2; + x = 2; + y += 3; + new = memcpy(xcalloc(1, sizeof(struct box)), c, sizeof(struct box)); + new->text = end + 1; + new->next = c->next; + c->next = new; + c = new; + } + + box->width = width; + box->height = y + 3; +} + +/** + * layout a table + * + * this is the fixed table layout algorithm, + * + */ + +void layout_table(struct box * table, unsigned long width) +{ + unsigned int columns; /* total columns */ + unsigned int auto_columns; /* number of columns with auto width */ + unsigned long table_width; + unsigned long used_width = 0; /* width used by fixed or percent columns */ + 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 = 1; + unsigned long * xs; + unsigned int i; + struct box * c; + struct box * r; + + assert(table->type == BOX_TABLE); + + /* find table width */ + switch (table->style->width.width) { + case CSS_WIDTH_LENGTH: + table_width = len(&table->style->width.value.length, 10); + break; + case CSS_WIDTH_PERCENT: + table_width = width * table->style->width.value.percent / 100; + break; + case CSS_WIDTH_AUTO: + default: + table_width = width; + break; + } + + /* calculate column statistics */ + for (columns = 0, auto_columns = 0, c = table->children->children; + c != 0; c = c->next) { + assert(c->type == BOX_TABLE_CELL); + switch (c->style->width.width) { + case CSS_WIDTH_LENGTH: + used_width += len(&c->style->width.value.length, 10); + break; + case CSS_WIDTH_PERCENT: + used_width += table_width * c->style->width.value.percent / 100; + break; + case CSS_WIDTH_AUTO: + auto_columns++; + break; + } + columns++; + } + + if (auto_columns == 0 && table->style->width.width != CSS_WIDTH_AUTO) + extra_width = (table_width - used_width) / columns; + else if (auto_columns != 0) + auto_width = (table_width - used_width) / auto_columns; + + /*printf("%i %i %i %i %i\n", table_width, columns, auto_columns, used_width, auto_width);*/ + + /* find column widths */ + xs = xcalloc(columns + 1, sizeof(*xs)); + xs[0] = x = 0; + 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; + break; + case CSS_WIDTH_PERCENT: + x += table_width * c->style->width.value.percent / 100 + extra_width; + break; + case CSS_WIDTH_AUTO: + x += auto_width; + break; + } + xs[i] = x; + printf("%i ", x); + } + printf("\n"); + + if (auto_columns == 0 && table->style->width.width == CSS_WIDTH_AUTO) + table_width = used_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 = c->next) { + c->width = xs[i+1] - xs[i]; + c->height = layout_block_children(c, c->width); + switch (c->style->height.height) { + case CSS_HEIGHT_AUTO: + break; + case CSS_HEIGHT_LENGTH: + c->height = len(&c->style->height.length, 10); + break; + } + c->x = xs[i]; + c->y = 1; + if (c->height > height) height = c->height; + } + r->x = 0; + r->y = y; + r->width = table_width; + r->height = height + 2; + y += height + 3; + } + + free(xs); + + table->width = table_width; + table->height = y; +} + -- cgit v1.2.3