From 2d816dda237a80f413a9d90031c7f5aff01e7a83 Mon Sep 17 00:00:00 2001 From: James Bursa Date: Sat, 28 Feb 2004 17:23:07 +0000 Subject: [project @ 2004-02-28 17:23:07 by bursa] Fix float-related crashes. svn path=/import/netsurf/; revision=577 --- render/layout.c | 220 ++++++++++++++++++++++++++++++++------------------------ 1 file changed, 125 insertions(+), 95 deletions(-) (limited to 'render/layout.c') diff --git a/render/layout.c b/render/layout.c index b5fdc0723..c0c39526a 100644 --- a/render/layout.c +++ b/render/layout.c @@ -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; - - if (h > height) 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; + b->type == BOX_FLOAT_LEFT || + b->type == BOX_FLOAT_RIGHT); + if (b->type != BOX_INLINE) + continue; + + 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 (height < h) + 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 (b->text != 0) - x += b->width + b->space ? b->font->space_width : 0; - else - x += b->width; - } + 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
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)); } -- cgit v1.2.3