[project @ 2004-02-28 17:23:07 by bursa]

Fix float-related crashes.

svn path=/import/netsurf/; revision=577
This commit is contained in:
James Bursa 2004-02-28 17:23:07 +00:00
parent 7f68e012cc
commit 2d816dda23
1 changed files with 123 additions and 93 deletions

View File

@ -54,6 +54,7 @@ static void layout_inline_container(struct box *box, int width,
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 int layout_text_indent(struct css_style *style, int width);
static void place_float_below(struct box *c, int width, int y,
struct box *cont);
static void layout_table(struct box *box);
@ -484,6 +485,7 @@ void layout_inline_container(struct box *box, int width,
box, width, cont, cx, cy));
for (c = box->children; c; ) {
LOG(("c %p", c));
c = layout_line(c, width, &y, cx, cy + y, cont, first_line);
first_line = false;
}
@ -539,12 +541,12 @@ struct box * layout_line(struct box *first, int width, int *y,
int x0 = 0;
int x1 = width;
int x, h, x_previous;
struct box * left;
struct box * right;
struct box * b;
struct box * c;
struct box * d;
struct box * fl;
struct box *left;
struct box *right;
struct box *b;
struct box *split_box = 0;
struct box *d;
struct box *fl;
int move_y = 0;
int space_before = 0, space_after = 0;
@ -564,62 +566,57 @@ struct box * layout_line(struct box *first, int width, int *y,
/* 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_INLINE_BLOCK ||
b->type == BOX_FLOAT_LEFT || b->type == BOX_FLOAT_RIGHT);
if (b->type == BOX_INLINE) {
if ((b->object || b->gadget) && b->style && b->style->height.height == CSS_HEIGHT_LENGTH)
h = len(&b->style->height.length, b->style);
else
h = line_height(b->style ? b->style : b->parent->parent->style);
b->height = h;
b->type == BOX_FLOAT_LEFT ||
b->type == BOX_FLOAT_RIGHT);
if (b->type != BOX_INLINE)
continue;
if (h > height) height = h;
if ((b->object || b->gadget) && b->style &&
b->style->height.height == CSS_HEIGHT_LENGTH)
h = len(&b->style->height.length, b->style);
else
h = line_height(b->style ? b->style :
b->parent->parent->style);
b->height = h;
if ((b->object || b->gadget) && b->style && b->style->width.width == CSS_WIDTH_LENGTH)
b->width = len(&b->style->width.value.length, b->style);
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 (b->width == UNKNOWN_WIDTH)
b->width = font_width(b->font, b->text, b->length);
} else
b->width = 0;
if (height < h)
height = h;
if (b->text != 0)
x += b->width + b->space ? b->font->space_width : 0;
else
x += b->width;
}
if ((b->object || b->gadget) && b->style &&
b->style->width.width == CSS_WIDTH_LENGTH)
b->width = len(&b->style->width.value.length, b->style);
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 (b->width == UNKNOWN_WIDTH)
b->width = font_width(b->font, b->text,
b->length);
} else
b->width = 0;
if (b->text)
x += b->width + b->space ? b->font->space_width : 0;
else
x += b->width;
}
/* find new sides using this height */
x0 = cx;
x1 = cx + width;
find_sides(cont->float_children, cy, cy + height, &x0, &x1, &left, &right);
find_sides(cont->float_children, cy, cy + height, &x0, &x1,
&left, &right);
x0 -= cx;
x1 -= cx;
/* text-indent */
/* TODO - fix <BR> related b0rkage */
if (indent) {
switch (first->parent->parent->style->text_indent.size) {
case CSS_TEXT_INDENT_LENGTH:
x0 += len(&first->parent->parent->style->text_indent.value.length, first->parent->parent->style);
if (x0 + x > x1)
x1 = x0 + x;
break;
case CSS_TEXT_INDENT_PERCENT:
x0 += ((x1-x0) * first->parent->parent->style->text_indent.value.percent) / 100;
if (x0 + x > x1)
x1 = x0 + x;
break;
default:
break;
}
}
if (indent)
x0 += layout_text_indent(first->parent->parent->style, width);
c = first;
/* pass 2: place boxes in line */
for (x = x_previous = 0, b = first; x <= x1 - x0 && b != 0; b = b->next) {
if (x1 < x0)
x1 = x0;
/* pass 2: place boxes in line: loop body executed at least once */
for (x = x_previous = 0, b = first; x <= x1 - x0 && b; b = b->next) {
if (b->type == BOX_INLINE || b->type == BOX_INLINE_BLOCK) {
x_previous = x;
x += space_after;
@ -645,7 +642,7 @@ struct box * layout_line(struct box *first, int width, int *y,
space_after = b->space ? b->font->space_width : 0;
else
space_after = 0;
c = b;
split_box = b;
move_y = 1;
/* fprintf(stderr, "layout_line: '%.*s' %li %li\n", b->length, b->text, xp, x); */
} else {
@ -693,48 +690,57 @@ struct box * layout_line(struct box *first, int width, int *y,
assert(cont->float_children != b);
b->next_float = cont->float_children;
cont->float_children = b;
split_box = 0;
}
}
if (x1 - x0 < x) {
if (x1 - x0 < x && split_box) {
/* the last box went over the end */
char * space = 0;
unsigned int i;
unsigned int space = 0;
int w;
struct box * c2;
x = x_previous;
if (!c->object && !c->gadget && c->text)
space = strchr(c->text, ' ');
if (space != 0 && c->length <= (unsigned int) (space - c->text))
/* space after end of string */
space = 0;
if (!split_box->object && !split_box->gadget &&
split_box->text) {
for (i = 0; i != split_box->length &&
split_box->text[i] != ' '; i++)
;
if (split_box->text[i] == ' ')
space = i;
}
/* space != 0 implies c->text != 0 */
/* space != 0 implies split_box->text != 0 */
if (space == 0)
w = c->width;
w = split_box->width;
else
w = font_width(c->font, c->text, (unsigned int) (space - c->text));
w = font_width(split_box->font, split_box->text, space);
if (x1 - x0 <= x + space_before + w && left == 0 && right == 0 && c == first) {
/* first word doesn't fit, but no floats and first on line so force in */
if (x1 - x0 <= x + space_before + w && !left && !right &&
split_box == first) {
/* first word doesn't fit, but no floats and first
on line so force in */
if (space == 0) {
/* only one word in this box or not text */
b = c->next;
b = split_box->next;
} else {
/* cut off first word for this line */
c2 = memcpy(xcalloc(1, sizeof(struct box)), c, sizeof(struct box));
c2->text = xstrdup(space + 1);
c2->length = c->length - ((space + 1) - c->text);
/* \todo allocate from box_pool */
c2 = memcpy(xcalloc(1, sizeof (struct box)),
split_box, sizeof (struct box));
c2->text = xstrdup(split_box->text + space + 1);
c2->length = split_box->length - (space + 1);
c2->width = UNKNOWN_WIDTH;
c2->clone = 1;
c->length = space - c->text;
c->width = w;
c->space = 1;
c2->next = c->next;
c->next = c2;
c2->prev = c;
split_box->length = space;
split_box->width = w;
split_box->space = 1;
c2->next = split_box->next;
split_box->next = c2;
c2->prev = split_box;
if (c2->next)
c2->next->prev = c2;
else
@ -745,30 +751,33 @@ struct box * layout_line(struct box *first, int width, int *y,
/* fprintf(stderr, "layout_line: overflow, forcing\n"); */
} else if (x1 - x0 <= x + space_before + w) {
/* first word doesn't fit, but full width not available so leave for later */
b = c;
b = split_box;
assert(used_height);
/* fprintf(stderr, "layout_line: overflow, leaving\n"); */
} else {
/* fit as many words as possible */
assert(space != 0);
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,
(x1 - x0), space - c->text, *space, w));
/* assert(space != c->text); */
if (space == c->text)
space = c->text + 1;
c2 = memcpy(xcalloc(1, sizeof(struct box)), c, sizeof(struct box));
c2->text = xstrdup(space + 1);
c2->length = c->length - ((space + 1) - c->text);
space = font_split(split_box->font, split_box->text,
split_box->length,
x1 - x0 - x - space_before, &w)
- split_box->text;
LOG(("'%.*s' %i %u %i", (int) split_box->length,
split_box->text, x1 - x0, space, w));
/* assert(space != split_box->text); */
if (space == 0)
space = 1;
c2 = memcpy(xcalloc(1, sizeof (struct box)), split_box,
sizeof (struct box));
c2->text = xstrdup(split_box->text + space + 1);
c2->length = split_box->length - (space + 1);
c2->width = UNKNOWN_WIDTH;
c2->clone = 1;
c->length = space - c->text;
c->width = w;
c->space = 1;
c2->next = c->next;
c->next = c2;
c2->prev = c;
split_box->length = space;
split_box->width = w;
split_box->space = 1;
c2->next = split_box->next;
split_box->next = c2;
c2->prev = split_box;
if (c2->next)
c2->next->prev = c2;
else
@ -801,6 +810,27 @@ struct box * layout_line(struct box *first, int width, int *y,
}
/**
* Calculate the text-indent length.
*
* \param style style of block
* \param width width of containing block
* \return length of indent
*/
int layout_text_indent(struct css_style *style, int width)
{
switch (style->text_indent.size) {
case CSS_TEXT_INDENT_LENGTH:
return len(&style->text_indent.value.length, style);
case CSS_TEXT_INDENT_PERCENT:
return width * style->text_indent.value.percent / 100;
default:
return 0;
}
}
/**
* Position a float in the first available space.
*
@ -873,7 +903,7 @@ void layout_table(struct box *table)
table_width = table->width;
LOG(("width %lu, min %lu, max %lu", table_width, table->min_width, table->max_width));
LOG(("width %i, min %i, max %i", table_width, table->min_width, table->max_width));
for (i = 0; i != columns; i++) {
if (col[i].type == COLUMN_WIDTH_FIXED)
@ -1369,7 +1399,7 @@ void calculate_table_widths(struct box *table)
}
for (i = 0; i < table->columns; i++) {
LOG(("col %u, type %i, min %lu, max %lu, width %lu",
LOG(("col %u, type %i, min %i, max %i, width %i",
i, col[i].type, col[i].min, col[i].max, col[i].width));
assert(col[i].min <= col[i].max);
min_width += col[i].min;
@ -1378,5 +1408,5 @@ void calculate_table_widths(struct box *table)
table->min_width = min_width;
table->max_width = max_width;
LOG(("min_width %lu, max_width %lu", min_width, max_width));
LOG(("min_width %i, max_width %i", min_width, max_width));
}