summaryrefslogtreecommitdiff
path: root/render
diff options
context:
space:
mode:
authorJames Bursa <james@netsurf-browser.org>2004-02-11 17:15:36 +0000
committerJames Bursa <james@netsurf-browser.org>2004-02-11 17:15:36 +0000
commit9aabe954c0914a998ae1ad0069e0d2ddbea4bf57 (patch)
treeb2d64031dd6b6bd8f3abac09579a3ec8d45f3e0a /render
parentd642474df13a68c69623a81e434e86d07968a879 (diff)
downloadnetsurf-9aabe954c0914a998ae1ad0069e0d2ddbea4bf57.tar.gz
netsurf-9aabe954c0914a998ae1ad0069e0d2ddbea4bf57.tar.bz2
[project @ 2004-02-11 17:15:36 by bursa]
Work on margins etc., clean up many parts of layout code. svn path=/import/netsurf/; revision=534
Diffstat (limited to 'render')
-rw-r--r--render/box.h8
-rw-r--r--render/layout.c615
-rw-r--r--render/layout.h17
3 files changed, 384 insertions, 256 deletions
diff --git a/render/box.h b/render/box.h
index f711a0f79..713baafdd 100644
--- a/render/box.h
+++ b/render/box.h
@@ -32,7 +32,7 @@ typedef enum {
struct column {
enum { COLUMN_WIDTH_UNKNOWN = 0, COLUMN_WIDTH_FIXED,
COLUMN_WIDTH_AUTO, COLUMN_WIDTH_PERCENT } type;
- unsigned long min, max, width;
+ int min, max, width;
};
struct box;
@@ -77,7 +77,7 @@ struct 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;
+ int min_width, max_width;
char * text;
unsigned int space : 1; /* 1 <=> followed by a space */
unsigned int clone : 1;
@@ -120,8 +120,8 @@ struct page_elements
};
-#define UNKNOWN_WIDTH ULONG_MAX
-#define UNKNOWN_MAX_WIDTH ULONG_MAX
+#define UNKNOWN_WIDTH INT_MAX
+#define UNKNOWN_MAX_WIDTH INT_MAX
/**
* interface
diff --git a/render/layout.c b/render/layout.c
index 30be0144a..474474d73 100644
--- a/render/layout.c
+++ b/render/layout.c
@@ -6,6 +6,13 @@
* Copyright 2003 Phil Mellor <monkeyson@users.sourceforge.net>
*/
+/** \file
+ * HTML layout (implementation).
+ *
+ * Layout is carried out in a single pass through the box tree, except for
+ * precalculation of minimum / maximum box widths.
+ */
+
#include <assert.h>
#include <ctype.h>
#include <limits.h>
@@ -13,8 +20,6 @@
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
-#include "libxml/HTMLparser.h"
-#include "netsurf/content/content.h"
#include "netsurf/css/css.h"
#ifdef riscos
#include "netsurf/desktop/gui.h"
@@ -30,23 +35,27 @@
#define AUTO INT_MIN
-static void layout_node(struct box * box, unsigned long width, struct box * cont,
- unsigned long cx, unsigned long cy);
-static int layout_block_find_dimensions(unsigned long available_width,
+static void layout_node(struct box *box, int width, struct box *cont,
+ int cx, int cy);
+static void layout_block_find_dimensions(int available_width,
+ struct css_style *style, struct box *box);
+static void layout_float_find_dimensions(int available_width,
+ struct css_style *style, struct box *box);
+static void layout_find_dimensions(int 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);
-static void layout_inline_container(struct box * box, unsigned long width, struct box * cont,
- unsigned long cx, unsigned long cy);
-static signed long line_height(struct css_style * style);
-static struct box * layout_line(struct box * first, unsigned long width, unsigned long * y,
- unsigned long cy, struct box * cont, bool indent);
-static void place_float_below(struct box * c, unsigned long width, unsigned long y, struct box * cont);
-static void layout_table(struct box * box, unsigned long width, struct box * cont,
- unsigned long cx, unsigned long cy);
+ int cx, int cy);
+static void find_sides(struct box *fl, int y0, int y1,
+ int *x0, int *x1, struct box **left, struct box **right);
+static void layout_inline_container(struct box *box, int width,
+ struct box *cont, int cx, int cy);
+static int line_height(struct css_style *style);
+static struct box * layout_line(struct box *first, int width, int *y,
+ int cx, int cy, struct box *cont, bool indent);
+static void place_float_below(struct box *c, int width, int y,
+ struct box *cont);
+static void layout_table(struct box *box);
static void calculate_widths(struct box *box);
static void calculate_inline_container_widths(struct box *box);
static void calculate_table_widths(struct box *table);
@@ -56,15 +65,23 @@ static void calculate_table_widths(struct box *table);
* Calculate positions of boxes in a document.
*
* \param doc root of document box tree
- * \param width page width
+ * \param width available page width
*/
-void layout_document(struct box * doc, unsigned long width)
+void layout_document(struct box *doc, int width)
{
struct box *box;
doc->float_children = 0;
- doc->x = doc->y = 0;
+
+ calculate_widths(doc);
+
+ layout_block_find_dimensions(width, doc->style, doc);
+ doc->x = doc->margin[LEFT] + doc->border[LEFT];
+ doc->y = doc->margin[TOP] + doc->border[TOP];
+ width -= doc->margin[LEFT] + doc->border[LEFT] +
+ doc->border[RIGHT] + doc->margin[RIGHT];
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)
doc->height = box->y + box->height;
@@ -76,35 +93,57 @@ void layout_document(struct box * doc, unsigned long width)
*
* \param box box to layout
* \param width horizontal space available
- * \param cont ancestor box which defines horizontal space, for inlines
+ * \param cont ancestor box which defines horizontal space, for floats
* \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)
+void layout_node(struct box *box, int width, struct box *cont,
+ int cx, int cy)
{
- LOG(("box %p, width %lu, cont %p, cx %lu, cy %lu", box, width, cont, cx, cy));
+ int cy1, x0, x1, table_width;
+ struct box *left, *right;
- gui_multitask();
+ LOG(("box %p, width %i, cont %p, cx %i, cy %i",
+ box, width, cont, cx, cy));
- 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];
- }
+ gui_multitask();
switch (box->type) {
case BOX_BLOCK:
case BOX_INLINE_BLOCK:
- layout_block(box, width, cont, cx, cy);
+ layout_block(box, cont, cx, cy);
break;
case BOX_INLINE_CONTAINER:
- layout_inline_container(box, width, cont, cx, cy);
+ layout_inline_container(box, box->width, cont, cx, cy);
break;
case BOX_TABLE:
- layout_table(box, width, cont, cx, cy);
+ layout_table(box);
+ /* find sides and move table down if it doesn't fit
+ in available width */
+ cy1 = cy;
+ table_width = box->width;
+ while (1) {
+ x0 = cx;
+ x1 = cx + width;
+ find_sides(cont->float_children, cy1, cy1 + box->height,
+ &x0, &x1, &left, &right);
+ if (table_width <= x1 - x0)
+ break;
+ if (left == 0 && right == 0)
+ break;
+ /* move down to the next place where the space may increase */
+ if (left == 0)
+ cy1 = right->y + right->height + 1;
+ else if (right == 0)
+ cy1 = left->y + left->height + 1;
+ else if (left->y + left->height < right->y + right->height)
+ cy1 = left->y + left->height + 1;
+ else
+ cy1 = right->y + right->height + 1;
+ }
+ box->x = x0;
+ box->y += cy1 - cy;
break;
default:
assert(0);
@@ -116,21 +155,19 @@ void layout_node(struct box * box, unsigned long width, struct box * cont,
* Layout the children of a block box.
*
* \param box block box to layout
- * \param width horizontal space available
- * \param cont ancestor box which defines horizontal space, for inlines
+ * \param cont ancestor box which defines horizontal space, for floats
* \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,
- unsigned long cx, unsigned long cy)
+void layout_block(struct box *box, struct box *cont, int cx, int cy)
{
- struct css_style * style = box->style;
+ struct css_style *style = box->style;
assert(box->type == BOX_BLOCK || box->type == BOX_INLINE_BLOCK);
assert(style != 0);
- LOG(("box %p, width %lu, cont %p, cx %lu, cy %lu", box, width, cont, cx, cy));
+ LOG(("box %p, cont %p, cx %i, cy %i", box, cont, cx, cy));
layout_block_children(box, cont, cx, cy);
switch (style->height.height) {
@@ -146,15 +183,17 @@ void layout_block(struct box * box, unsigned long width, struct box * cont,
/**
- * Compute dimensions of box, margins, paddings, and borders for a block box.
+ * Compute dimensions of box, margins, paddings, and borders for a block-level
+ * element.
*/
-int layout_block_find_dimensions(unsigned long available_width,
- struct css_style *style,
- int margin[4], int padding[4], int border[4])
+void layout_block_find_dimensions(int available_width,
+ struct css_style *style, struct box *box)
{
- unsigned int i;
int width;
+ int *margin = box->margin;
+ int *padding = box->padding;
+ int *border = box->border;
/* calculate box width */
switch (style->width.width) {
@@ -170,7 +209,94 @@ int layout_block_find_dimensions(unsigned long available_width,
break;
}
- /* calculate size of margins, paddings, and borders */
+ layout_find_dimensions(available_width, style, margin, padding, border);
+
+ /* 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;
+
+ box->width = width;
+}
+
+
+/**
+ * Compute dimensions of box, margins, paddings, and borders for a floating
+ * element.
+ */
+
+void layout_float_find_dimensions(int available_width,
+ struct css_style *style, struct box *box)
+{
+ layout_find_dimensions(available_width, style,
+ box->margin, box->padding, box->border);
+
+ if (box->margin[LEFT] == AUTO)
+ box->margin[LEFT] = 0;
+ if (box->margin[RIGHT] == AUTO)
+ box->margin[RIGHT] = 0;
+
+ /* calculate box width */
+ switch (style->width.width) {
+ case CSS_WIDTH_LENGTH:
+ box->width = len(&style->width.value.length, style);
+ break;
+ case CSS_WIDTH_PERCENT:
+ box->width = available_width *
+ style->width.value.percent / 100;
+ break;
+ case CSS_WIDTH_AUTO:
+ default:
+ /* CSS 2.1 section 10.3.5 */
+ available_width -= box->margin[LEFT] + box->border[LEFT] +
+ box->padding[LEFT] + box->padding[RIGHT] +
+ box->border[RIGHT] + box->margin[RIGHT];
+ if (box->min_width < available_width)
+ box->width = available_width;
+ else
+ box->width = box->min_width;
+ if (box->max_width < box->width)
+ box->width = box->max_width;
+ break;
+ }
+}
+
+
+/**
+ * Calculate size of margins, paddings, and borders.
+ */
+
+void layout_find_dimensions(int available_width,
+ struct css_style *style,
+ int margin[4], int padding[4], int border[4])
+{
+ unsigned int i;
for (i = 0; i != 4; i++) {
switch (style->margin[i].margin) {
case CSS_MARGIN_LENGTH:
@@ -204,39 +330,6 @@ int layout_block_find_dimensions(unsigned long available_width,
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;
}
@@ -244,7 +337,7 @@ int layout_block_find_dimensions(unsigned long available_width,
* Recursively layout block children.
*
* \param box block box to layout
- * \param cont ancestor box which defines horizontal space, for inlines
+ * \param cont ancestor box which defines horizontal space, for floats
* \param cx box position relative to cont
* \param cy box position relative to cont
*
@@ -253,7 +346,7 @@ int layout_block_find_dimensions(unsigned long available_width,
*/
void layout_block_children(struct box *box, struct box *cont,
- unsigned long cx, unsigned long cy)
+ int cx, int cy)
{
struct box *c;
int width = box->width;
@@ -263,11 +356,12 @@ void layout_block_children(struct box *box, struct box *cont,
box->type == BOX_FLOAT_LEFT || box->type == BOX_FLOAT_RIGHT ||
box->type == BOX_TABLE_CELL);
- LOG(("box %p, width %lu, cont %p, cx %lu, cy %lu", box, width, cont, cx, cy));
+ LOG(("box %p, width %i, cont %p, cx %i, cy %i",
+ box, width, cont, cx, cy));
for (c = box->children; c != 0; c = c->next) {
if (c->style != 0 && c->style->clear != CSS_CLEAR_NONE) {
- unsigned long x0, x1;
+ int x0, x1;
struct box * left, * right;
do {
x0 = cx;
@@ -279,7 +373,7 @@ void layout_block_children(struct box *box, struct box *cont,
y = left->y + left->height - cy + 1;
if ((c->style->clear == CSS_CLEAR_RIGHT || c->style->clear == CSS_CLEAR_BOTH)
&& right != 0)
- if (cy + y < (unsigned long)(right->y + right->height + 1))
+ if (cy + y < (right->y + right->height + 1))
y = right->y + right->height - cy + 1;
} while ((c->style->clear == CSS_CLEAR_LEFT && left != 0) ||
(c->style->clear == CSS_CLEAR_RIGHT && right != 0) ||
@@ -288,7 +382,16 @@ void layout_block_children(struct box *box, struct box *cont,
c->x = box->padding[LEFT];
c->y = y;
- layout_node(c, width, cont, cx, cy + y);
+
+ if (c->style) {
+ layout_block_find_dimensions(width, c->style, c);
+ c->x += c->margin[LEFT] + c->border[LEFT];
+ c->y += c->margin[TOP] + c->border[TOP];
+ } else {
+ c->width = box->width;
+ }
+
+ layout_node(c, width, cont, cx + c->x, cy + c->y);
y = c->y + c->height + c->padding[TOP] + c->padding[BOTTOM] +
c->border[BOTTOM] + c->margin[BOTTOM];
if (box->width < c->width)
@@ -299,58 +402,71 @@ void layout_block_children(struct box *box, struct box *cont,
/**
- * find_sides -- find left and right margins
+ * Find left and right edges in a vertical range.
*
- * 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
+ * \param fl first float in float list
+ * \param y0 start of y range to search
+ * \param y1 end of y range to search
+ * \param x0 start left edge, updated to available left edge
+ * \param x1 start right edge, updated to available right edge
+ * \param left returns float on left if present
+ * \param right returns float on right if present
*/
-void find_sides(struct box * fl, unsigned long y0, unsigned long y1,
- unsigned long * x0, unsigned long * x1, struct box ** left, struct box ** right)
+void find_sides(struct box *fl, int y0, int y1,
+ int *x0, int *x1, struct box **left, struct box **right)
{
-/* fprintf(stderr, "find_sides: y0 %li y1 %li x0 %li x1 %li => ", y0, y1, *x0, *x1); */
+ int fy0, fy1, fx0, fx1;
+ LOG(("y0 %i, y1 %i, x0 %i, x1 %i", y0, y1, *x0, *x1));
*left = *right = 0;
for (; fl; fl = fl->next_float) {
- if (y0 <= (unsigned long)(fl->y + fl->height) &&
- (unsigned long)fl->y <= y1) {
- if (fl->type == BOX_FLOAT_LEFT && *x0 < (unsigned long)(fl->x + fl->width)) {
- *x0 = fl->x + fl->width;
- *left = fl;
- } else if (fl->type == BOX_FLOAT_RIGHT && (unsigned long)fl->x < *x1) {
- *x1 = fl->x;
- *right = fl;
+ fy0 = fl->y;
+ fy1 = fl->y + fl->height;
+ if (y0 <= fy1 && fy0 <= y1) {
+ if (fl->type == BOX_FLOAT_LEFT) {
+ fx1 = fl->x + fl->width;
+ if (*x0 < fx1) {
+ *x0 = fx1;
+ *left = fl;
+ }
+ } else if (fl->type == BOX_FLOAT_RIGHT) {
+ fx0 = fl->x;
+ if (fx0 < *x1) {
+ *x1 = fx0;
+ *right = fl;
+ }
}
}
}
-/* fprintf(stderr, "x0 %li x1 %li left 0x%x right 0x%x\n", *x0, *x1, *left, *right); */
+ LOG(("x0 %i, x1 %i, left %p, right %p", *x0, *x1, *left, *right));
}
/**
- * layout_inline_container -- layout lines of text or inline boxes with floats
+ * 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
+ * \param box inline container
+ * \param width horizontal space available
+ * \param cont ancestor box which defines horizontal space, for floats
+ * \param cx box position relative to cont
+ * \param 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)
+void layout_inline_container(struct box *box, int width,
+ struct box *cont, int cx, int cy)
{
- struct box * c;
- unsigned long y = 0;
+ bool first_line = true;
+ struct box *c;
+ int y = 0;
assert(box->type == BOX_INLINE_CONTAINER);
- LOG(("box %p, width %lu, cont %p, cx %lu, cy %lu", box, width, cont, cx, cy));
+ LOG(("box %p, width %i, cont %p, cx %i, cy %i",
+ box, width, cont, cx, cy));
- for (c = box->children; c != 0; ) {
- c = layout_line(c, width, &y, cy + y, cont,
- c == box->children ? true : false);
+ for (c = box->children; c; ) {
+ c = layout_line(c, width, &y, cx, cy + y, cont, first_line);
+ first_line = false;
}
box->width = width;
@@ -358,29 +474,52 @@ void layout_inline_container(struct box * box, unsigned long width, struct box *
}
-signed long line_height(struct css_style * style)
+/**
+ * Calculate line height from a style.
+ */
+
+int line_height(struct css_style *style)
{
- assert(style != 0);
+ assert(style);
assert(style->line_height.size == CSS_LINE_HEIGHT_LENGTH ||
style->line_height.size == CSS_LINE_HEIGHT_ABSOLUTE ||
style->line_height.size == CSS_LINE_HEIGHT_PERCENT);
- if (style->line_height.size == CSS_LINE_HEIGHT_LENGTH)
- return len(&style->line_height.value.length, style);
- else if (style->line_height.size == CSS_LINE_HEIGHT_ABSOLUTE)
- return style->line_height.value.absolute * len(&style->font_size.value.length, 0);
- else
- return style->line_height.value.percent * len(&style->font_size.value.length, 0) / 100.0;
+ switch (style->line_height.size) {
+ case CSS_LINE_HEIGHT_LENGTH:
+ return len(&style->line_height.value.length, style);
+
+ case CSS_LINE_HEIGHT_ABSOLUTE:
+ return style->line_height.value.absolute *
+ len(&style->font_size.value.length, 0);
+
+ case CSS_LINE_HEIGHT_PERCENT:
+ default:
+ return style->line_height.value.percent *
+ len(&style->font_size.value.length, 0)
+ / 100.0;
+ }
}
-struct box * layout_line(struct box * first, unsigned long width, unsigned long * y,
- unsigned long cy, struct box * cont, bool indent)
+/**
+ * Position a line of boxes in inline formatting context.
+ *
+ * \param first box at start of line
+ * \param width available width
+ * \param y coordinate of top of line, updated on exit to bottom
+ * \param cy coordinate of top of line relative to cont
+ * \param cont ancestor box which defines horizontal space, for floats
+ * \param indent apply any first-line indent
+ */
+
+struct box * layout_line(struct box *first, int width, int *y,
+ int cx, int cy, struct box *cont, bool indent)
{
- unsigned long height, used_height;
- unsigned long x0 = 0;
- unsigned long x1 = width;
- unsigned long x, h, x_previous;
+ int height, used_height;
+ int x0 = 0;
+ int x1 = width;
+ int x, h, x_previous;
struct box * left;
struct box * right;
struct box * b;
@@ -388,12 +527,17 @@ struct box * layout_line(struct box * first, unsigned long width, unsigned long
struct box * d;
struct box * fl;
int move_y = 0;
- unsigned int space_before = 0, space_after = 0;
+ int space_before = 0, space_after = 0;
-/* fprintf(stderr, "layout_line: '%.*s' %li %li %li\n", first->length, first->text, width, *y, cy); */
+ LOG(("first->text '%.*s', width %i, y %i, cy %i",
+ first->length, first->text, width, *y, cy));
/* find sides at top of line */
+ x0 += cx;
+ x1 += cx;
find_sides(cont->float_children, cy, cy, &x0, &x1, &left, &right);
+ x0 -= cx;
+ x1 -= cx;
/* get minimum line height from containing block */
used_height = height = line_height(first->parent->parent->style);
@@ -416,7 +560,7 @@ struct box * layout_line(struct box * first, unsigned long width, unsigned long
else if ((b->object || b->gadget) && b->style && b->style->width.width == CSS_WIDTH_PERCENT)
b->width = width * b->style->width.value.percent / 100;
else if (b->text) {
- if ((unsigned long)b->width == UNKNOWN_WIDTH)
+ if (b->width == UNKNOWN_WIDTH)
b->width = font_width(b->font, b->text, b->length);
} else
b->width = 0;
@@ -429,9 +573,11 @@ struct box * layout_line(struct box * first, unsigned long width, unsigned long
}
/* find new sides using this height */
- x0 = 0;
- x1 = width;
+ x0 = cx;
+ x1 = cx + width;
find_sides(cont->float_children, cy, cy + height, &x0, &x1, &left, &right);
+ x0 -= cx;
+ x1 -= cx;
/* text-indent */
/* TODO - fix <BR> related b0rkage */
@@ -455,25 +601,23 @@ struct box * layout_line(struct box * first, unsigned long width, unsigned long
/* pass 2: place boxes in line */
for (x = x_previous = 0, b = first; x <= x1 - x0 && b != 0; b = b->next) {
if (b->type == BOX_INLINE || b->type == BOX_INLINE_BLOCK) {
+ x_previous = x;
+ x += space_after;
+ b->x = x;
+
if (b->type == BOX_INLINE_BLOCK) {
- unsigned long w = width;
- if (b->style->width.width == CSS_WIDTH_AUTO) {
- calculate_widths(b);
- if ((unsigned long)b->max_width < width)
- w = b->max_width;
- else
- w = b->min_width;
- }
- layout_node(b, w, b, 0, 0);
+ layout_float_find_dimensions(width, b->style, b);
+ b->x += b->margin[LEFT] + b->border[LEFT];
+ layout_node(b, b->width, b, 0, 0);
/* increase height to contain any floats inside */
for (fl = b->float_children; fl != 0; fl = fl->next_float)
if (b->height < fl->y + fl->height)
b->height = fl->y + fl->height;
- }
- x_previous = x;
- x += space_after;
- b->x = x;
- x += b->width;
+ x = b->x + b->padding[LEFT] + b->width + b->padding[RIGHT] +
+ b->border[RIGHT] + b->margin[RIGHT];
+ } else
+ x += b->width;
+
space_before = space_after;
if (b->object)
space_after = 0;
@@ -486,28 +630,28 @@ struct box * layout_line(struct box * first, unsigned long width, unsigned long
/* fprintf(stderr, "layout_line: '%.*s' %li %li\n", b->length, b->text, xp, x); */
} else {
/* float */
- unsigned long w = width;
d = b->children;
d->float_children = 0;
/* css_dump_style(b->style); */
- if (d->style->width.width == CSS_WIDTH_AUTO) {
- /* either a float with no width specified (contravenes standard)
- * or we don't know the width for some reason, eg. image not loaded */
- calculate_widths(b);
- if ((unsigned long)d->max_width < width)
- w = d->max_width;
- else
- w = d->min_width;
- }
- layout_node(d, w, d, 0, 0);
+
+ layout_float_find_dimensions(width, d->style, d);
+
+ layout_node(d, d->width, d, 0, 0);
/* increase height to contain any floats inside */
for (fl = d->float_children; fl != 0; fl = fl->next_float)
if (d->height < fl->y + fl->height)
d->height = fl->y + fl->height;
- d->x = d->y = 0;
- b->width = d->width;
- b->height = d->height;
- if ((unsigned long)b->width < (x1 - x0) - x || (left == 0 && right == 0 && x == 0)) {
+ d->x = d->margin[LEFT] + d->border[LEFT];
+ d->y = d->margin[TOP] + d->border[TOP];
+ b->width = d->margin[LEFT] + d->border[LEFT] +
+ d->padding[LEFT] + d->width +
+ d->padding[RIGHT] + d->border[RIGHT] +
+ d->margin[RIGHT];
+ b->height = d->margin[TOP] + d->border[TOP] +
+ d->padding[TOP] + d->height +
+ d->padding[BOTTOM] + d->border[BOTTOM] +
+ d->margin[BOTTOM];
+ 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->type == BOX_FLOAT_LEFT) {
b->x = x0;
@@ -534,7 +678,7 @@ struct box * layout_line(struct box * first, unsigned long width, unsigned long
if (x1 - x0 < x) {
/* the last box went over the end */
char * space = 0;
- unsigned int w;
+ int w;
struct box * c2;
x = x_previous;
@@ -581,6 +725,7 @@ struct box * layout_line(struct box * first, unsigned long width, unsigned long
} else if (x1 - x0 <= x + space_before + w) {
/* first word doesn't fit, but full width not available so leave for later */
b = c;
+ assert(used_height);
/* fprintf(stderr, "layout_line: overflow, leaving\n"); */
} else {
/* fit as many words as possible */
@@ -588,7 +733,7 @@ struct box * layout_line(struct box * first, unsigned long width, unsigned long
space = font_split(c->font, c->text, c->length,
x1 - x0 - x - space_before, &w);
LOG(("'%.*s' %lu %u (%c) %u", (int) c->length, c->text,
- (unsigned long) (x1 - x0), space - c->text, *space, w));
+ (x1 - x0), space - c->text, *space, w));
/* assert(space != c->text); */
if (space == c->text)
space = c->text + 1;
@@ -625,7 +770,7 @@ struct box * layout_line(struct box * first, unsigned long width, unsigned long
if (d->type == BOX_INLINE || d->type == BOX_INLINE_BLOCK) {
d->x += x0;
d->y = *y;
- if (used_height < (unsigned long)d->height)
+ if (used_height < d->height)
used_height = d->height;
}
}
@@ -635,10 +780,19 @@ struct box * layout_line(struct box * first, unsigned long width, unsigned long
}
+/**
+ * Position a float in the first available space.
+ *
+ * \param c float box to position
+ * \param width available width
+ * \param y y coordinate relative to cont to place float below
+ * \param cont ancestor box which defines horizontal space, for floats
+ */
-void place_float_below(struct box * c, unsigned long width, unsigned long y, struct box * cont)
+void place_float_below(struct box *c, int width, int y,
+ struct box *cont)
{
- unsigned long x0, x1, yy = y;
+ int x0, x1, yy = y;
struct box * left;
struct box * right;
do {
@@ -654,7 +808,7 @@ void place_float_below(struct box * c, unsigned long width, unsigned long y, str
} else if (left != 0 && right == 0) {
yy = left->y + left->height + 1;
}
- } while (!((left == 0 && right == 0) || ((unsigned long)c->width < x1 - x0)));
+ } while (!((left == 0 && right == 0) || (c->width < x1 - x0)));
if (c->type == BOX_FLOAT_LEFT) {
c->x = x0;
@@ -670,20 +824,17 @@ void place_float_below(struct box * c, unsigned long width, unsigned long y, str
* layout a table
*/
-void layout_table(struct box * table, unsigned long width, struct box * cont,
- unsigned long cx, unsigned long cy)
+void layout_table(struct box *table)
{
unsigned int columns = table->columns; /* total columns */
unsigned int i;
- unsigned int *row_span, *excess_y;
- unsigned long table_width, min_width = 0, max_width = 0;
- unsigned long required_width = 0;
- unsigned long x, x0, x1;
- unsigned long table_height = 0;
- unsigned long *xs; /* array of column x positions */
- unsigned long cy1;
- struct box *left;
- struct box *right;
+ unsigned int *row_span;
+ int *excess_y;
+ int table_width, min_width = 0, max_width = 0;
+ int required_width = 0;
+ int x;
+ int table_height = 0;
+ int *xs; /* array of column x positions */
struct box *c;
struct box *row;
struct box *row_group;
@@ -696,9 +847,8 @@ void layout_table(struct box * table, unsigned long width, struct box * cont,
assert(table->children != 0 && table->children->children != 0);
assert(columns != 0);
- LOG(("table %p, width %lu, cont %p, cx %lu, cy %lu", table, width, cont, cx, cy));
+ LOG(("table %p", table));
- calculate_table_widths(table);
memcpy(col, table->col, sizeof(col[0]) * columns);
table_width = table->width;
@@ -709,7 +859,7 @@ void layout_table(struct box * table, unsigned long width, struct box * cont,
if (col[i].type == COLUMN_WIDTH_FIXED)
required_width += col[i].width;
else if (col[i].type == COLUMN_WIDTH_PERCENT) {
- unsigned long width = col[i].width * table_width / 100;
+ int width = col[i].width * table_width / 100;
required_width += col[i].min < width ? width : col[i].min;
} else
required_width += col[i].min;
@@ -731,7 +881,7 @@ void layout_table(struct box * table, unsigned long width, struct box * cont,
/* take percentages exactly */
for (i = 0; i != columns; i++) {
if (col[i].type == COLUMN_WIDTH_PERCENT) {
- unsigned long width = table_width * col[i].width / 100;
+ int width = table_width * col[i].width / 100;
if (width < col[i].min)
width = col[i].min;
col[i].min = col[i].width = col[i].max = width;
@@ -763,11 +913,11 @@ void layout_table(struct box * table, unsigned long width, struct box * cont,
if (col[i].type != COLUMN_WIDTH_FIXED)
flexible_columns++;
if (flexible_columns == 0) {
- unsigned long extra = (table_width - max_width) / columns;
+ int extra = (table_width - max_width) / columns;
for (i = 0; i != columns; i++)
col[i].width = col[i].max + extra;
} else {
- unsigned long extra = (table_width - max_width) / flexible_columns;
+ int extra = (table_width - max_width) / flexible_columns;
for (i = 0; i != columns; i++)
if (col[i].type != COLUMN_WIDTH_FIXED)
col[i].width = col[i].max + extra;
@@ -799,9 +949,9 @@ void layout_table(struct box * table, unsigned long width, struct box * cont,
/* position cells */
for (row_group = table->children; row_group != 0; row_group = row_group->next) {
- unsigned long row_group_height = 0;
+ int row_group_height = 0;
for (row = row_group->children; row != 0; row = row->next) {
- unsigned long row_height = 0;
+ int row_height = 0;
for (c = row->children; c != 0; c = c->next) {
assert(c->style != 0);
c->width = xs[c->start_column + c->columns] - xs[c->start_column];
@@ -811,8 +961,8 @@ void layout_table(struct box * table, unsigned long width, struct box * cont,
/* some sites use height="1" or similar to attempt
* to make cells as small as possible, so treat
* it as a minimum */
- unsigned long h = len(&c->style->height.length, c->style);
- if ((unsigned long)c->height < h)
+ int h = len(&c->style->height.length, c->style);
+ if (c->height < h)
c->height = h;
}
/* increase height to contain any floats inside */
@@ -874,34 +1024,9 @@ void layout_table(struct box * table, unsigned long width, struct box * cont,
table->width = table_width;
table->height = table_height;
-
- /* find sides and move table down if it doesn't fit in available width */
- cy1 = cy;
- while (1) {
- x0 = 0;
- x1 = width;
- find_sides(cont->float_children, cy1, cy1 + table_height,
- &x0, &x1, &left, &right);
- if (table_width <= x1 - x0)
- break;
- if (left == 0 && right == 0)
- break;
- /* move down to the next place where the space may increase */
- if (left == 0)
- cy1 = right->y + right->height + 1;
- else if (right == 0)
- cy1 = left->y + left->height + 1;
- else if (left->y + left->height < right->y + right->height)
- cy1 = left->y + left->height + 1;
- else
- cy1 = right->y + right->height + 1;
- }
- table->x = x0;
- table->y += cy1 - cy;
}
-
/**
* find min, max widths required by boxes
*/
@@ -909,39 +1034,39 @@ void layout_table(struct box * table, unsigned long width, struct box * cont,
void calculate_widths(struct box *box)
{
struct box *child;
- unsigned long min = 0, max = 0, width;
+ int min = 0, max = 0, width;
assert(box->type == BOX_TABLE_CELL ||
box->type == BOX_BLOCK || box->type == BOX_INLINE_BLOCK ||
box->type == BOX_FLOAT_LEFT || box->type == BOX_FLOAT_RIGHT);
/* check if the widths have already been calculated */
- if ((unsigned long)box->max_width != UNKNOWN_MAX_WIDTH)
+ if (box->max_width != UNKNOWN_MAX_WIDTH)
return;
for (child = box->children; child != 0; child = child->next) {
switch (child->type) {
case BOX_BLOCK:
case BOX_TABLE:
+ if (child->type == BOX_TABLE)
+ calculate_table_widths(child);
+ else
+ calculate_widths(child);
if (child->style->width.width == CSS_WIDTH_LENGTH) {
width = len(&child->style->width.value.length,
child->style);
if (min < width) min = width;
if (max < width) max = width;
} else {
- if (child->type == BOX_TABLE)
- calculate_table_widths(child);
- else
- calculate_widths(child);
- if (min < (unsigned long)child->min_width) min = child->min_width;
- if (max < (unsigned long)child->max_width) max = child->max_width;
+ if (min < child->min_width) min = child->min_width;
+ if (max < child->max_width) max = child->max_width;
}
break;
case BOX_INLINE_CONTAINER:
calculate_inline_container_widths(child);
- if (min < (unsigned long)child->min_width) min = child->min_width;
- if (max < (unsigned long)child->max_width) max = child->max_width;
+ if (min < child->min_width) min = child->min_width;
+ if (max < child->max_width) max = child->max_width;
break;
default:
@@ -958,8 +1083,8 @@ void calculate_widths(struct box *box)
void calculate_inline_container_widths(struct box *box)
{
struct box *child;
- unsigned long min = 0, max = 0, width;
- int i, j;
+ int min = 0, max = 0, width;
+ unsigned int i, j;
for (child = box->children; child != 0; child = child->next) {
switch (child->type) {
@@ -969,7 +1094,7 @@ void calculate_inline_container_widths(struct box *box)
child->width = len(&child->style->width.value.length,
child->style);
max += child->width;
- if (min < (unsigned long)child->width)
+ if (min < child->width)
min = child->width;
}
@@ -984,16 +1109,17 @@ void calculate_inline_container_widths(struct box *box)
/* min = widest word */
i = 0;
do {
- for (j = i; (unsigned long)j != child->length && child->text[j] != ' '; j++)
+ for (j = i; j != child->length && child->text[j] != ' '; j++)
;
- width = font_width(child->font, child->text + i, (unsigned long)(j - i));
+ width = font_width(child->font, child->text + i, (j - i));
if (min < width) min = width;
i = j + 1;
- } while ((unsigned long)j != child->length);
+ } while (j != child->length);
}
break;
case BOX_INLINE_BLOCK:
+ calculate_widths(child);
if (child->style != 0 &&
child->style->width.width == CSS_WIDTH_LENGTH) {
width = len(&child->style->width.value.length,
@@ -1001,14 +1127,14 @@ void calculate_inline_container_widths(struct box *box)
if (min < width) min = width;
max += width;
} else {
- calculate_widths(child);
- if (min < (unsigned long)child->min_width) min = child->min_width;
+ if (min < child->min_width) min = child->min_width;
max += child->max_width;
}
break;
case BOX_FLOAT_LEFT:
case BOX_FLOAT_RIGHT:
+ calculate_widths(child);
if (child->style != 0 &&
child->style->width.width == CSS_WIDTH_LENGTH) {
width = len(&child->style->width.value.length,
@@ -1016,9 +1142,8 @@ void calculate_inline_container_widths(struct box *box)
if (min < width) min = width;
if (max < width) max = width;
} else {
- calculate_widths(child);
- if (min < (unsigned long)child->min_width) min = child->min_width;
- if (max < (unsigned long)child->max_width) max = child->max_width;
+ if (min < child->min_width) min = child->min_width;
+ if (max < child->max_width) max = child->max_width;
}
break;
@@ -1043,13 +1168,13 @@ void calculate_table_widths(struct box *table)
{
unsigned int i, j;
struct box *row_group, *row, *cell;
- unsigned long width, min_width = 0, max_width = 0;
+ int width, min_width = 0, max_width = 0;
struct column *col;
LOG(("table %p, columns %u", table, table->columns));
/* check if the widths have already been calculated */
- if ((unsigned long)table->max_width != UNKNOWN_MAX_WIDTH)
+ if (table->max_width != UNKNOWN_MAX_WIDTH)
return;
free(table->col);
@@ -1073,15 +1198,15 @@ void calculate_table_widths(struct box *table)
i = cell->start_column;
if (col[i].type == COLUMN_WIDTH_FIXED) {
- if (col[i].width < (unsigned long)cell->min_width)
+ if (col[i].width < cell->min_width)
col[i].min = col[i].width = col[i].max = cell->min_width;
continue;
}
/* update column min, max widths using cell widths */
- if (col[i].min < (unsigned long)cell->min_width)
+ if (col[i].min < cell->min_width)
col[i].min = cell->min_width;
- if (col[i].max < (unsigned long)cell->max_width)
+ if (col[i].max < cell->max_width)
col[i].max = cell->max_width;
if (col[i].type != COLUMN_WIDTH_FIXED &&
@@ -1113,7 +1238,7 @@ void calculate_table_widths(struct box *table)
for (row = row_group->children; row != 0; row = row->next) {
for (cell = row->children; cell != 0; cell = cell->next) {
unsigned int flexible_columns = 0;
- unsigned long min = 0, max = 0, fixed_width = 0;
+ int min = 0, max = 0, fixed_width = 0;
signed long extra;
if (cell->columns == 1)
@@ -1139,7 +1264,7 @@ void calculate_table_widths(struct box *table)
* columns which aren't fixed width yet */
width = len(&cell->style->width.value.length,
cell->style);
- if (width < (unsigned long)cell->min_width)
+ if (width < cell->min_width)
width = cell->min_width;
extra = width - fixed_width;
for (j = 0; j != cell->columns; j++)
@@ -1160,7 +1285,7 @@ void calculate_table_widths(struct box *table)
}
/* distribute extra min, max to spanned columns */
- if (min < (unsigned long)cell->min_width) {
+ if (min < cell->min_width) {
if (flexible_columns == 0) {
extra = 1 + (cell->min_width - min)
/ cell->columns;
@@ -1181,7 +1306,7 @@ void calculate_table_widths(struct box *table)
}
}
}
- if (max < (unsigned long)cell->max_width && flexible_columns != 0) {
+ if (max < cell->max_width && flexible_columns != 0) {
extra = 1 + (cell->max_width - max)
/ flexible_columns;
for (j = 0; j != cell->columns; j++)
diff --git a/render/layout.h b/render/layout.h
index 4a70cc7e4..ec52d745d 100644
--- a/render/layout.h
+++ b/render/layout.h
@@ -5,15 +5,18 @@
* Copyright 2003 James Bursa <bursa@users.sourceforge.net>
*/
+/** \file
+ * HTML layout (interface).
+ *
+ * The main interface to the layout code is layout_document(), which takes a
+ * normalized box tree and assigns coordinates and dimensions to the boxes, and
+ * also adds boxes to the tree (eg. when formatting lines of text).
+ */
+
#ifndef _NETSURF_RENDER_LAYOUT_H_
#define _NETSURF_RENDER_LAYOUT_H_
-/**
- * interface
- */
-
-void layout_document(struct box * box, unsigned long width);
-void layout_block(struct box * box, unsigned long width, struct box * cont,
- unsigned long cx, unsigned long cy);
+void layout_document(struct box *box, int width);
+void layout_block(struct box *box, struct box *cont, int cx, int cy);
#endif