summaryrefslogtreecommitdiff
path: root/render/layout.c
diff options
context:
space:
mode:
Diffstat (limited to 'render/layout.c')
-rw-r--r--render/layout.c74
1 files changed, 60 insertions, 14 deletions
diff --git a/render/layout.c b/render/layout.c
index 7905eabb7..b7d9e2034 100644
--- a/render/layout.c
+++ b/render/layout.c
@@ -227,6 +227,7 @@ bool layout_block_context(struct box *block, int viewport_height,
assert(block->width != AUTO);
block->float_children = NULL;
+ block->cached_place_below_level = 0;
block->clear_level = 0;
/* special case if the block contains an object */
@@ -2062,8 +2063,14 @@ void find_sides(struct box *fl, int y0, int y1,
*left = *right = 0;
for (; fl; fl = fl->next_float) {
- fy0 = fl->y;
fy1 = fl->y + fl->height;
+ if (fy1 < y0) {
+ /* Floats are sorted in order of decreasing bottom pos.
+ * Past here, all floats will be too high to concern us.
+ */
+ return;
+ }
+ fy0 = fl->y;
if (y0 < fy1 && fy0 <= y1) {
if (fl->type == BOX_FLOAT_LEFT) {
fx1 = fl->x + fl->width;
@@ -2071,7 +2078,7 @@ void find_sides(struct box *fl, int y0, int y1,
*x0 = fx1;
*left = fl;
}
- } else if (fl->type == BOX_FLOAT_RIGHT) {
+ } else {
fx0 = fl->x;
if (fx0 < *x1) {
*x1 = fx0;
@@ -2088,6 +2095,44 @@ void find_sides(struct box *fl, int y0, int y1,
/**
+ * Insert a float into a container.
+ *
+ * \param cont block formatting context block, used to contain float
+ * \param b box to add to float
+ *
+ * This sorts floats in order of descending bottom edges.
+ */
+static void add_float_to_container(struct box *cont, struct box *b)
+{
+ struct box *box = cont->float_children;
+ int b_bottom = b->y + b->height;
+
+ assert(b->type == BOX_FLOAT_LEFT || b->type == BOX_FLOAT_RIGHT);
+
+ if (box == NULL) {
+ /* No other float children */
+ b->next_float = NULL;
+ cont->float_children = b;
+ return;
+ } else if (b_bottom >= box->y + box->height) {
+ /* Goes at start of list */
+ b->next_float = cont->float_children;
+ cont->float_children = b;
+ } else {
+ struct box *prev = NULL;
+ while (box != NULL && b_bottom < box->y + box->height) {
+ prev = box;
+ box = box->next_float;
+ }
+ if (prev != NULL) {
+ b->next_float = prev->next_float;
+ prev->next_float = b;
+ }
+ }
+}
+
+
+/**
* Layout lines of text or inline boxes with floats.
*
* \param inline_container inline container box
@@ -2693,6 +2738,7 @@ bool layout_line(struct box *first, int *width, int *y,
d = b->children;
d->float_children = 0;
+ d->cached_place_below_level = 0;
b->float_container = d->float_container = cont;
if (!layout_float(d, *width, content))
@@ -2729,7 +2775,8 @@ bool layout_line(struct box *first, int *width, int *y,
left == 0 && right == 0)) &&
(!place_below ||
(left == 0 && right == 0 && x == 0)) &&
- cy >= cont->clear_level) {
+ cy >= cont->clear_level &&
+ cy >= cont->cached_place_below_level) {
/* + not cleared or,
* cleared and there are no floats to clear
* + fits without needing to be placed below or,
@@ -2754,6 +2801,9 @@ bool layout_line(struct box *first, int *width, int *y,
/* place below into next available space */
int fcy = (cy > cont->clear_level) ? cy :
cont->clear_level;
+ fcy = (fcy > cont->cached_place_below_level) ?
+ fcy :
+ cont->cached_place_below_level;
fy = (fy > fcy) ? fy : fcy;
fy = (fy == cy) ? fy + height : fy;
@@ -2787,16 +2837,7 @@ bool layout_line(struct box *first, int *width, int *y,
else
right = b;
}
- if (cont->float_children == b) {
-#ifdef LAYOUT_DEBUG
- LOG("float %p already placed", b);
-#endif
-
- box_dump(stderr, cont, 0, true);
- assert(0);
- }
- b->next_float = cont->float_children;
- cont->float_children = b;
+ add_float_to_container(cont, b);
split_box = 0;
}
@@ -3404,10 +3445,13 @@ bool layout_float(struct box *b, int width, html_content *content)
void place_float_below(struct box *c, int width, int cx, int y,
struct box *cont)
{
- int x0, x1, yy = y;
+ int x0, x1, yy;
struct box *left;
struct box *right;
+ yy = y > cont->cached_place_below_level ?
+ y : cont->cached_place_below_level;
+
#ifdef LAYOUT_DEBUG
LOG("c %p, width %i, cx %i, y %i, cont %p", c, width, cx, y, cont);
#endif
@@ -3436,6 +3480,7 @@ void place_float_below(struct box *c, int width, int cx, int y,
c->x = x1 - c->width;
}
c->y = y;
+ cont->cached_place_below_level = y;
}
@@ -3829,6 +3874,7 @@ bool layout_table(struct box *table, int available_width,
c->padding[RIGHT] -
c->border[RIGHT].width;
c->float_children = 0;
+ c->cached_place_below_level = 0;
c->height = AUTO;
if (!layout_block_context(c, -1, content)) {