summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJames Bursa <james@netsurf-browser.org>2005-07-02 18:17:51 +0000
committerJames Bursa <james@netsurf-browser.org>2005-07-02 18:17:51 +0000
commit9b78daf135d7fa555990454c219649e4d54157d2 (patch)
treed5d8c1d773d0ef51afbe055dcff60607821f7a9c
parent894ba8b6230ffa57e1a5037adbd1b246a9a877da (diff)
downloadnetsurf-9b78daf135d7fa555990454c219649e4d54157d2.tar.gz
netsurf-9b78daf135d7fa555990454c219649e4d54157d2.tar.bz2
[project @ 2005-07-02 18:17:51 by bursa]
Rewrite calculation of box minimum and maximum widths to improve layout of many pages. Move calculation of column types and border collapsing to box tree normalising stage, since they are layout independent. Add window height parameter to layout and make <html> and <body> at least window height. svn path=/import/netsurf/; revision=1777
-rw-r--r--desktop/browser.c30
-rw-r--r--desktop/gui.h1
-rw-r--r--makefile2
-rw-r--r--render/box_normalise.c10
-rw-r--r--render/html.c4
-rw-r--r--render/layout.c1153
-rw-r--r--render/layout.h2
-rw-r--r--riscos/print.c9
-rw-r--r--riscos/save_draw.c6
-rw-r--r--riscos/window.c32
10 files changed, 542 insertions, 707 deletions
diff --git a/desktop/browser.c b/desktop/browser.c
index e65fa38c6..d048e7ca5 100644
--- a/desktop/browser.c
+++ b/desktop/browser.c
@@ -213,7 +213,8 @@ void browser_window_go_post(struct browser_window *bw, const char *url,
bw->history_add = history_add;
bw->time0 = clock();
c = fetchcache(url2, browser_window_callback, bw, 0,
- gui_window_get_width(bw->window), 0,
+ gui_window_get_width(bw->window),
+ gui_window_get_height(bw->window),
false,
post_urlenc, post_multipart, true, download);
free(url2);
@@ -235,7 +236,8 @@ void browser_window_go_post(struct browser_window *bw, const char *url,
fetchcache_go(c, option_send_referer ? referer : 0,
browser_window_callback, bw, 0,
- gui_window_get_width(bw->window), 0,
+ gui_window_get_width(bw->window),
+ gui_window_get_height(bw->window),
post_urlenc, post_multipart, true);
}
@@ -738,7 +740,6 @@ void browser_window_mouse_action_html(struct browser_window *bw,
browser_mouse_state mouse, int x, int y)
{
char *base_url = 0;
- char *href = 0;
char *title = 0;
char *url = 0;
char status_buffer[200];
@@ -774,16 +775,12 @@ void browser_window_mouse_action_html(struct browser_window *bw,
if (box->object)
object = box->object;
- if (box->href) {
- base_url = content->data.html.base_url;
- href = box->href;
- }
+ if (box->href)
+ url = box->href;
- if (box->usemap) {
- base_url = content->data.html.base_url;
- href = imagemap_get(content, box->usemap,
+ if (box->usemap)
+ url = imagemap_get(content, box->usemap,
box_x, box_y, x, y);
- }
if (box->gadget) {
gadget_content = content;
@@ -802,6 +799,7 @@ void browser_window_mouse_action_html(struct browser_window *bw,
if (box->style && box->type != BOX_BR &&
box->type != BOX_INLINE &&
+ box->type != BOX_TEXT &&
(box->style->overflow == CSS_OVERFLOW_SCROLL ||
box->style->overflow == CSS_OVERFLOW_AUTO) &&
((box_vscrollbar_present(box) &&
@@ -918,14 +916,10 @@ void browser_window_mouse_action_html(struct browser_window *bw,
/* \todo should have a drag-saving object msg */
status = c->status_message;
- } else if (href) {
- res = url_join(href, base_url, &url);
- if (res != URL_FUNC_OK)
- return;
-
+ } else if (url) {
if (title) {
snprintf(status_buffer, sizeof status_buffer, "%s: %s",
- title, url);
+ url, title);
status = status_buffer;
} else
status = url;
@@ -1000,8 +994,6 @@ void browser_window_mouse_action_html(struct browser_window *bw,
browser_window_set_status(bw, status);
browser_window_set_pointer(pointer);
-
- free(url);
}
diff --git a/desktop/gui.h b/desktop/gui.h
index c56b2d504..59d7e6933 100644
--- a/desktop/gui.h
+++ b/desktop/gui.h
@@ -60,6 +60,7 @@ void gui_window_update_box(struct gui_window *g,
bool gui_window_get_scroll(struct gui_window *g, int *sx, int *sy);
void gui_window_set_scroll(struct gui_window *g, int sx, int sy);
int gui_window_get_width(struct gui_window *g);
+int gui_window_get_height(struct gui_window *g);
void gui_window_set_extent(struct gui_window *g, int width, int height);
void gui_window_set_status(struct gui_window *g, const char *text);
void gui_window_set_pointer(gui_pointer_shape shape);
diff --git a/makefile b/makefile
index 1005c25da..12d276024 100644
--- a/makefile
+++ b/makefile
@@ -20,7 +20,7 @@
OBJECTS_COMMON = content.o fetch.o fetchcache.o url_store.o # content/
OBJECTS_COMMON += css.o css_enum.o parser.o ruleset.o scanner.o # css/
OBJECTS_COMMON += box.o box_construct.o box_normalise.o form.o html.o \
- html_redraw.o layout.o list.o textplain.o # render/
+ html_redraw.o layout.o list.o table.o textplain.o # render/
OBJECTS_COMMON += messages.o talloc.o url.o utf8.o \
utils.o # utils/
OBJECTS_COMMON += imagemap.o loginlist.o options.o tree.o # desktop/
diff --git a/render/box_normalise.c b/render/box_normalise.c
index 22971af8c..5fd78f419 100644
--- a/render/box_normalise.c
+++ b/render/box_normalise.c
@@ -16,6 +16,7 @@
#include <stdbool.h>
#include "netsurf/css/css.h"
#include "netsurf/render/box.h"
+#include "netsurf/render/table.h"
#ifdef riscos
#include "netsurf/desktop/gui.h"
#endif
@@ -267,8 +268,6 @@ bool box_normalise_table(struct box *table, struct content * c)
table->rows = col_info.num_rows;
free(col_info.spans);
- box_normalise_table_spans(table);
-
if (table->children == 0) {
LOG(("table->children == 0, removing"));
if (table->prev == 0)
@@ -278,6 +277,13 @@ bool box_normalise_table(struct box *table, struct content * c)
if (table->next != 0)
table->next->prev = table->prev;
box_free(table);
+ } else {
+ box_normalise_table_spans(table);
+ if (!table_calculate_column_types(table))
+ return false;
+ if (table->style->border_collapse ==
+ CSS_BORDER_COLLAPSE_COLLAPSE)
+ table_collapse_borders(table);
}
LOG(("table %p done", table));
diff --git a/render/html.c b/render/html.c
index fe3488709..7e7062df9 100644
--- a/render/html.c
+++ b/render/html.c
@@ -338,7 +338,7 @@ bool html_convert(struct content *c, int width, int height)
content_set_status(c, messages_get("Formatting"));
content_broadcast(c, CONTENT_MSG_STATUS, msg_data);
LOG(("Layout document"));
- layout_document(c, width);
+ layout_document(c, width, height);
/*box_dump(c->data.html.layout->children, 0);*/
c->width = c->data.html.layout->descendant_x1;
c->height = c->data.html.layout->descendant_y1;
@@ -1126,7 +1126,7 @@ void html_stop(struct content *c)
void html_reformat(struct content *c, int width, int height)
{
- layout_document(c, width);
+ layout_document(c, width, height);
c->width = c->data.html.layout->descendant_x1;
c->height = c->data.html.layout->descendant_y1;
}
diff --git a/render/layout.c b/render/layout.c
index c8633d8f6..0a88ff4ac 100644
--- a/render/layout.c
+++ b/render/layout.c
@@ -10,8 +10,13 @@
/** \file
* HTML layout (implementation).
*
- * Layout is carried out in a single pass through the box tree, except for
- * precalculation of minimum / maximum box widths.
+ * Layout is carried out in two stages:
+ *
+ * - calculation of minimum / maximum box widths
+ * - layout (position and dimensions)
+ *
+ * In most cases the functions for the two stages are a corresponding pair
+ * layout_minmax_X() and layout_X().
*/
#define _GNU_SOURCE /* for strndup */
@@ -40,6 +45,7 @@
#define AUTO INT_MIN
+static void layout_minmax_block(struct box *block);
static void layout_block_find_dimensions(int available_width, struct box *box);
static int layout_solve_width(int available_width, int width,
int margin[4], int padding[4], int border[4]);
@@ -51,42 +57,34 @@ static void layout_find_dimensions(int available_width,
static int layout_clear(struct box *fl, css_clear clear);
static void find_sides(struct box *fl, int y0, int y1,
int *x0, int *x1, struct box **left, struct box **right);
+static void layout_minmax_inline_container(struct box *inline_container);
static int line_height(struct css_style *style);
static bool layout_line(struct box *first, int width, int *y,
int cx, int cy, struct box *cont, bool indent,
struct content *content, struct box **next_box);
+static struct box *layout_minmax_line(struct box *first, int *min, int *max);
static int layout_text_indent(struct css_style *style, int width);
static bool layout_float(struct box *b, int width, struct content *content);
static void place_float_below(struct box *c, int width, int cx, int y,
struct box *cont);
static bool layout_table(struct box *box, int available_width,
struct content *content);
+static void layout_minmax_table(struct box *table);
static void layout_move_children(struct box *box, int x, int y);
-static bool calculate_widths(struct box *box);
-static bool calculate_block_widths(struct box *box, int *min, int *max,
- int *max_sum);
-static bool calculate_inline_container_widths(struct box *box);
-static void calculate_inline_replaced_widths(struct box *box, int *min,
- int *max, int *line_max);
-static void calculate_inline_widths(struct box *box, int *min, int *line_max);
-static bool calculate_table_widths(struct box *table);
-void table_collapse_borders_h(struct box *parent, struct box *child, bool *first);
-void table_collapse_borders_v(struct box *row, struct box *cell, unsigned int columns);
-void table_collapse_borders_cell(struct box *cell, struct box *right,
- struct box *bottom);
-void table_remove_borders(struct css_style *style);
-struct box *table_find_cell(struct box *table, unsigned int x, unsigned int y);
+static void calculate_mbp_width(struct css_style *style, int *fixed,
+ float *frac);
/**
* Calculate positions of boxes in a document.
*
* \param doc content of type CONTENT_HTML
- * \param width available page width
+ * \param width available width
+ * \param height available height
* \return true on success, false on memory exhaustion
*/
-bool layout_document(struct content *content, int width)
+bool layout_document(struct content *content, int width, int height)
{
bool ret;
struct box *doc = content->data.html.layout;
@@ -95,18 +93,37 @@ bool layout_document(struct content *content, int width)
doc->float_children = 0;
- if (!calculate_widths(doc))
- return false;
+ layout_minmax_block(doc);
layout_block_find_dimensions(width, 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];
+ width -= doc->margin[LEFT] + doc->border[LEFT] + doc->padding[LEFT] +
+ doc->padding[RIGHT] + doc->border[RIGHT] +
+ doc->margin[RIGHT];
+ if (width < 0)
+ width = 0;
doc->width = width;
ret = layout_block_context(doc, content);
+ /* make <html> and <body> fill available height */
+ if (doc->y + doc->padding[TOP] + doc->height + doc->padding[BOTTOM] +
+ doc->border[BOTTOM] + doc->margin[BOTTOM] <
+ height) {
+ doc->height = height - (doc->y + doc->padding[TOP] +
+ doc->padding[BOTTOM] + doc->border[BOTTOM] +
+ doc->margin[BOTTOM]);
+ if (doc->children)
+ doc->children->height = doc->height -
+ (doc->children->margin[TOP] +
+ doc->children->border[TOP] +
+ doc->children->padding[TOP] +
+ doc->children->padding[BOTTOM] +
+ doc->children->border[BOTTOM] +
+ doc->children->margin[BOTTOM]);
+ }
+
layout_calculate_descendant_bboxes(doc);
return ret;
@@ -302,6 +319,69 @@ bool layout_block_context(struct box *block, struct content *content)
/**
+ * Calculate minimum and maximum width of a block.
+ *
+ * \param block box of type BLOCK, INLINE_BLOCK, or TABLE_CELL
+ */
+
+void layout_minmax_block(struct box *block)
+{
+ struct box *child;
+ int min = 0, max = 0;
+ int extra_fixed = 0;
+ float extra_frac = 0;
+
+ assert(block->type == BOX_BLOCK ||
+ block->type == BOX_INLINE_BLOCK ||
+ block->type == BOX_TABLE_CELL);
+
+ /* check if the widths have already been calculated */
+ if (block->max_width != UNKNOWN_MAX_WIDTH)
+ return;
+
+ /* recurse through children */
+ for (child = block->children; child; child = child->next) {
+ switch (child->type) {
+ case BOX_BLOCK:
+ layout_minmax_block(child);
+ break;
+ case BOX_INLINE_CONTAINER:
+ layout_minmax_inline_container(child);
+ break;
+ case BOX_TABLE:
+ layout_minmax_table(child);
+ break;
+ default:
+ assert(0);
+ }
+ assert(child->max_width != UNKNOWN_MAX_WIDTH);
+ if (min < child->min_width)
+ min = child->min_width;
+ if (max < child->max_width)
+ max = child->max_width;
+ }
+
+ if (max < min) {
+ box_dump(block, 0);
+ assert(0);
+ }
+
+ /* fixed width takes priority */
+ if (block->type != BOX_TABLE_CELL &&
+ block->style->width.width == CSS_WIDTH_LENGTH)
+ min = max = css_len2px(&block->style->width.value.length,
+ block->style);
+
+ /* add margins, border, padding to min, max widths */
+ calculate_mbp_width(block->style, &extra_fixed, &extra_frac);
+ if (1.0 <= extra_frac)
+ extra_frac = 0.9;
+ block->min_width = (min + extra_fixed) / (1.0 - extra_frac);
+ block->max_width = (max + extra_fixed) / (1.0 - extra_frac);
+}
+
+
+/**
* Compute dimensions of box, margins, paddings, and borders for a block-level
* element.
*
@@ -319,10 +399,11 @@ void layout_block_find_dimensions(int available_width, struct box *box)
/* calculate box width */
switch (style->width.width) {
case CSS_WIDTH_LENGTH:
- width = (int)css_len2px(&style->width.value.length, style);
+ width = css_len2px(&style->width.value.length, style);
break;
case CSS_WIDTH_PERCENT:
- width = available_width * style->width.value.percent / 100;
+ width = available_width *
+ style->width.value.percent / 100;
break;
case CSS_WIDTH_AUTO:
default:
@@ -333,7 +414,7 @@ void layout_block_find_dimensions(int available_width, struct box *box)
/* height */
switch (style->height.height) {
case CSS_HEIGHT_LENGTH:
- box->height = (int)css_len2px(&style->height.length, style);
+ box->height = css_len2px(&style->height.length, style);
break;
case CSS_HEIGHT_AUTO:
default:
@@ -405,7 +486,7 @@ int layout_solve_width(int available_width, int width,
margin[RIGHT] = 0;
width = available_width -
(margin[LEFT] + border[LEFT] + padding[LEFT] +
- padding[RIGHT] + border[RIGHT] + margin[RIGHT]);
+ 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 -
@@ -418,7 +499,7 @@ int layout_solve_width(int available_width, int width,
} else if (margin[LEFT] == AUTO) {
margin[LEFT] = available_width -
(border[LEFT] + padding[LEFT] + width +
- padding[RIGHT] + border[RIGHT] + margin[RIGHT]);
+ padding[RIGHT] + border[RIGHT] + margin[RIGHT]);
} else {
/* margin-right auto or "over-constained" */
margin[RIGHT] = available_width -
@@ -453,7 +534,8 @@ void layout_float_find_dimensions(int available_width,
/* calculate box width */
switch (style->width.width) {
case CSS_WIDTH_LENGTH:
- box->width = (int)css_len2px(&style->width.value.length, style);
+ box->width = css_len2px(&style->width.value.length,
+ style);
break;
case CSS_WIDTH_PERCENT:
box->width = available_width *
@@ -468,7 +550,8 @@ void layout_float_find_dimensions(int available_width,
/* height */
switch (style->height.height) {
case CSS_HEIGHT_LENGTH:
- box->height = (int)css_len2px(&style->height.length, style);
+ box->height = css_len2px(&style->height.length,
+ style);
break;
case CSS_HEIGHT_AUTO:
default:
@@ -531,7 +614,7 @@ void layout_find_dimensions(int available_width,
if (margin) {
switch (style->margin[i].margin) {
case CSS_MARGIN_LENGTH:
- margin[i] = (int) css_len2px(&style->margin[i].
+ margin[i] = css_len2px(&style->margin[i].
value.length, style);
break;
case CSS_MARGIN_PERCENT:
@@ -552,7 +635,7 @@ void layout_find_dimensions(int available_width,
break;
case CSS_PADDING_LENGTH:
default:
- padding[i] = (int) css_len2px(&style->padding[i].
+ padding[i] = css_len2px(&style->padding[i].
value.length, style);
break;
}
@@ -562,7 +645,7 @@ void layout_find_dimensions(int available_width,
/* spec unclear: following Mozilla */
border[i] = 0;
else
- border[i] = (int) css_len2px(&style->border[i].
+ border[i] = css_len2px(&style->border[i].
width.value, style);
}
}
@@ -646,19 +729,19 @@ void find_sides(struct box *fl, int y0, int y1,
* \return true on success, false on memory exhaustion
*/
-bool layout_inline_container(struct box *box, int width,
+bool layout_inline_container(struct box *inline_container, int width,
struct box *cont, int cx, int cy, struct content *content)
{
bool first_line = true;
struct box *c, *next;
int y = 0;
- assert(box->type == BOX_INLINE_CONTAINER);
+ assert(inline_container->type == BOX_INLINE_CONTAINER);
- LOG(("box %p, width %i, cont %p, cx %i, cy %i",
- box, width, cont, cx, cy));
+ LOG(("inline_container %p, width %i, cont %p, cx %i, cy %i",
+ inline_container, width, cont, cx, cy));
- for (c = box->children; c; ) {
+ for (c = inline_container->children; c; ) {
LOG(("c %p", c));
if (!layout_line(c, width, &y, cx, cy + y, cont, first_line,
content, &next))
@@ -667,14 +750,45 @@ bool layout_inline_container(struct box *box, int width,
first_line = false;
}
- box->width = width;
- box->height = y;
+ inline_container->width = width;
+ inline_container->height = y;
return true;
}
/**
+ * Calculate minimum and maximum width of an inline container.
+ *
+ * \param inline_container box of type INLINE_CONTAINER
+ */
+
+void layout_minmax_inline_container(struct box *inline_container)
+{
+ struct box *child;
+ int line_min = 0, line_max = 0;
+ int min = 0, max = 0;
+
+ assert(inline_container->type == BOX_INLINE_CONTAINER);
+
+ /* check if the widths have already been calculated */
+ if (inline_container->max_width != UNKNOWN_MAX_WIDTH)
+ return;
+
+ for (child = inline_container->children; child; ) {
+ child = layout_minmax_line(child, &line_min, &line_max);
+ if (min < line_min)
+ min = line_min;
+ if (max < line_max)
+ max = line_max;
+ }
+
+ inline_container->min_width = min;
+ inline_container->max_width = max;
+}
+
+
+/**
* Calculate line height from a style.
*/
@@ -758,7 +872,8 @@ bool layout_line(struct box *first, int width, int *y,
x1 = x0;
/* pass 1: find height of line assuming sides at top of line: loop
- * body executed at least once */
+ * body executed at least once
+ * keep in sync with the loop in layout_minmax_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 ||
@@ -768,6 +883,12 @@ bool layout_line(struct box *first, int width, int *y,
x += space_after;
+ if (b->type == BOX_BR)
+ break;
+
+ if (b->type == BOX_FLOAT_LEFT || b->type == BOX_FLOAT_RIGHT)
+ continue;
+
if (b->type == BOX_INLINE_BLOCK) {
if (b->width == UNKNOWN_WIDTH)
if (!layout_float(b, width, content))
@@ -782,14 +903,8 @@ bool layout_line(struct box *first, int width, int *y,
b->padding[RIGHT] + b->border[RIGHT] +
b->margin[RIGHT];
space_after = 0;
- }
-
- if (b->type == BOX_BR)
- break;
-
- if (b->type != BOX_INLINE && b->type != BOX_TEXT &&
- b->type != BOX_INLINE_END)
continue;
+ }
if (b->type == BOX_INLINE) {
/* calculate borders, margins, and padding */
@@ -823,24 +938,23 @@ bool layout_line(struct box *first, int width, int *y,
if (height < b->height)
height = b->height;
- if (b->text) {
- if (b->width == UNKNOWN_WIDTH)
- /** \todo handle errors */
- nsfont_width(b->style, b->text,
- b->length, &b->width);
- x += b->width;
- if (b->space) {
- /** \todo optimize out */
- nsfont_width(b->style, " ", 1,
- &space_after);
- }
- else
- space_after = 0;
- } else {
+ if (!b->text) {
b->width = 0;
space_after = 0;
+ continue;
}
+ if (b->width == UNKNOWN_WIDTH)
+ /** \todo handle errors */
+ nsfont_width(b->style, b->text, b->length,
+ &b->width);
+ x += b->width;
+ if (b->space)
+ /** \todo optimize out */
+ nsfont_width(b->style, " ", 1, &space_after);
+ else
+ space_after = 0;
+
continue;
}
@@ -852,8 +966,8 @@ bool layout_line(struct box *first, int width, int *y,
/* calculate box width */
switch (b->style->width.width) {
case CSS_WIDTH_LENGTH:
- b->width = (int)css_len2px(&b->style->width.value.length,
- b->style);
+ b->width = css_len2px(&b->style->width.value.
+ length, b->style);
break;
case CSS_WIDTH_PERCENT:
b->width = width *
@@ -869,7 +983,7 @@ bool layout_line(struct box *first, int width, int *y,
/* height */
switch (b->style->height.height) {
case CSS_HEIGHT_LENGTH:
- b->height = (int)css_len2px(&b->style->height.length,
+ b->height = css_len2px(&b->style->height.length,
b->style);
break;
case CSS_HEIGHT_AUTO:
@@ -1179,6 +1293,159 @@ bool layout_line(struct box *first, int width, int *y,
/**
+ * Calculate minimum and maximum width of a line.
+ *
+ * \param first a box in an inline container
+ * \param line_min updated to minimum width of line starting at first
+ * \param line_max updated to maximum width of line starting at first
+ * \return first box in next line, or 0 if no more lines
+ */
+
+struct box *layout_minmax_line(struct box *first,
+ int *line_min, int *line_max)
+{
+ int min = 0, max = 0, width, height;
+ size_t i, j;
+ struct box *b;
+
+ /* corresponds to the pass 1 loop in layout_line() */
+ for (b = first; b; b = b->next) {
+ assert(b->type == BOX_INLINE || b->type == BOX_INLINE_BLOCK ||
+ b->type == BOX_FLOAT_LEFT ||
+ b->type == BOX_FLOAT_RIGHT ||
+ b->type == BOX_BR || b->type == BOX_TEXT ||
+ b->type == BOX_INLINE_END);
+
+ if (b->type == BOX_BR) {
+ b = b->next;
+ break;
+ }
+
+ if (b->type == BOX_FLOAT_LEFT || b->type == BOX_FLOAT_RIGHT) {
+ assert(b->children);
+ if (b->children->type == BOX_BLOCK)
+ layout_minmax_block(b->children);
+ else
+ layout_minmax_table(b->children);
+ b->min_width = b->children->min_width;
+ b->max_width = b->children->max_width;
+ if (min < b->min_width)
+ min = b->min_width;
+ max += b->max_width;
+ continue;
+ }
+
+ if (b->type == BOX_INLINE_BLOCK) {
+ layout_minmax_block(b);
+ if (min < b->min_width)
+ min = b->min_width;
+ max += b->max_width;
+ continue;
+ }
+
+ if (b->type == BOX_INLINE) {
+ /* \todo */
+ /* calculate borders, margins, and padding */
+ } else if (b->type == BOX_INLINE_END) {
+ continue;
+ }
+
+ if (!b->object && !b->gadget) {
+ /* inline non-replaced, 10.3.1 and 10.6.1 */
+ if (!b->text)
+ continue;
+
+ if (b->width == UNKNOWN_WIDTH)
+ /** \todo handle errors */
+ nsfont_width(b->style, b->text, b->length,
+ &b->width);
+ max += b->width;
+ if (b->next && b->space) {
+ nsfont_width(b->style, " ", 1, &width);
+ max += width;
+ }
+
+ /* min = widest word */
+ i = 0;
+ do {
+ for (j = i; j != b->length &&
+ b->text[j] != ' '; j++)
+ ;
+ nsfont_width(b->style, b->text + i,
+ j - i, &width);
+ if (min < width)
+ min = width;
+ i = j + 1;
+ } while (j != b->length);
+
+ continue;
+ }
+
+ /* inline replaced, 10.3.2 and 10.6.2 */
+ assert(b->style);
+
+ /* calculate box width */
+ switch (b->style->width.width) {
+ case CSS_WIDTH_LENGTH:
+ width = css_len2px(&b->style->width.value.
+ length, b->style);
+ break;
+ case CSS_WIDTH_PERCENT:
+ /*b->width = width *
+ b->style->width.value.percent /
+ 100;
+ break;*/
+ case CSS_WIDTH_AUTO:
+ default:
+ width = AUTO;
+ break;
+ }
+
+ /* height */
+ switch (b->style->height.height) {
+ case CSS_HEIGHT_LENGTH:
+ height = css_len2px(&b->style->height.length,
+ b->style);
+ break;
+ case CSS_HEIGHT_AUTO:
+ default:
+ height = AUTO;
+ break;
+ }
+
+ if (b->object) {
+ if (width == AUTO && height == AUTO) {
+ width = b->object->width;
+ } else if (width == AUTO) {
+ if (b->object->height)
+ width = b->object->width *
+ (float) height /
+ b->object->height;
+ else
+ width = b->object->width;
+ }
+ } else {
+ /* form control with no object */
+ if (width == AUTO)
+ width = 0;
+ }
+
+ if (min < width)
+ min = width;
+ max += width;
+ }
+
+ /* \todo first line text-indent */
+
+ *line_min = min;
+ *line_max = max;
+
+ assert(b != first);
+ return b;
+}
+
+
+/**
* Calculate the text-indent length.
*
* \param style style of block
@@ -1190,7 +1457,8 @@ int layout_text_indent(struct css_style *style, int width)
{
switch (style->text_indent.size) {
case CSS_TEXT_INDENT_LENGTH:
- return (int)css_len2px(&style->text_indent.value.length, style);
+ return css_len2px(&style->text_indent.value.length,
+ style);
case CSS_TEXT_INDENT_PERCENT:
return width * style->text_indent.value.percent / 100;
default:
@@ -1246,8 +1514,10 @@ void place_float_below(struct box *c, int width, int cx, int y,
x1 = cx + width;
find_sides(cont->float_children, y, y, &x0, &x1, &left, &right);
if (left != 0 && right != 0) {
- yy = (left->y + left->height < right->y + right->height ?
- left->y + left->height : right->y + right->height) + 1;
+ yy = (left->y + left->height <
+ right->y + right->height ?
+ left->y + left->height :
+ right->y + right->height) + 1;
} else if (left == 0 && right != 0) {
yy = right->y + right->height + 1;
} else if (left != 0 && right == 0) {
@@ -1343,17 +1613,16 @@ bool layout_table(struct box *table, int available_width,
/* border-spacing is used in the separated borders model */
if (style->border_collapse == CSS_BORDER_COLLAPSE_SEPARATE) {
- border_spacing_h = (int) css_len2px(&style->border_spacing.horz,
+ border_spacing_h = css_len2px(&style->border_spacing.horz,
style);
- border_spacing_v = (int) css_len2px(&style->border_spacing.vert,
+ border_spacing_v = css_len2px(&style->border_spacing.vert,
style);
}
/* find specified table width, or available width if auto-width */
switch (style->width.width) {
case CSS_WIDTH_LENGTH:
- table_width = (int) css_len2px(&style->width.value.length,
- style);
+ table_width = css_len2px(&style->width.value.length, style);
auto_width = table_width;
break;
case CSS_WIDTH_PERCENT:
@@ -1444,7 +1713,8 @@ bool layout_table(struct box *table, int available_width,
spare_width = 0;
for (i = 0; i != columns; i++) {
if (col[i].type == COLUMN_WIDTH_RELATIVE) {
- col[i].min = ceil(col[i].max = (float) spare_width
+ col[i].min = ceil(col[i].max =
+ (float) spare_width
* (float) col[i].width
/ relative_sum);
min_width += col[i].min;
@@ -1683,666 +1953,200 @@ bool layout_table(struct box *table, int available_width,
/**
- * Moves the children of a box by a specified amount
- *
- * \param box top of tree of boxes
- * \param x the amount to move children by horizontally
- * \param y the amount to move children by vertically
- */
-
-void layout_move_children(struct box *box, int x, int y) {
- assert(box);
-
- for (box = box->children; box; box = box->next) {
- box->x += x;
- box->y += y;
- }
-}
-
-
-/**
- * Find min, max widths required by boxes.
- *
- * \param box top of tree of boxes
- * \return true on success, false on memory exhaustion
- *
- * The min_width and max_width fields of each box in the tree are computed.
- */
-
-bool calculate_widths(struct box *box)
-{
- struct box *child;
- int min = 0, max = 0, extra_fixed = 0;
- float extra_frac = 0;
- unsigned int side;
- struct css_style *style = box->style;
-
- 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 (box->max_width != UNKNOWN_MAX_WIDTH)
- return true;
-
- for (child = box->children; child != 0; child = child->next) {
- switch (child->type) {
- case BOX_BLOCK:
- case BOX_TABLE:
- if (!calculate_block_widths(child, &min, &max,
- 0))
- return false;
- break;
-
- case BOX_INLINE_CONTAINER:
- if (!calculate_inline_container_widths(child))
- return false;
- if (min < child->min_width)
- min = child->min_width;
- if (max < child->max_width)
- max = child->max_width;
- break;
-
- default:
- break;
- }
- }
-
- /* add margins, border, padding to min, max widths */
- if (style) {
- for (side = 1; side != 5; side += 2) { /* RIGHT, LEFT */
- if (style->padding[side].padding == CSS_PADDING_LENGTH)
- extra_fixed += css_len2px(&style->padding[side].
- value.length, style);
- else if (style->padding[side].padding ==
- CSS_PADDING_PERCENT)
- extra_frac += style->padding[side].value.
- percent * 0.01;
-
- if (style->border[side].style != CSS_BORDER_STYLE_NONE)
- extra_fixed += css_len2px(&style->border[side].
- width.value, style);
-
- if (style->margin[side].margin == CSS_MARGIN_LENGTH)
- extra_fixed += css_len2px(&style->margin[side].
- value.length, style);
- else if (style->margin[side].margin ==
- CSS_MARGIN_PERCENT)
- extra_frac += style->margin[side].value.
- percent * 0.01;
- }
- }
-
- if (1.0 <= extra_frac)
- extra_frac = 0.9;
-
- box->min_width = (min + extra_fixed) / (1.0 - extra_frac);
- box->max_width = (max + extra_fixed) / (1.0 - extra_frac);
-
- return true;
-}
-
-
-/**
- * Find min, max widths for a BOX_BLOCK, BOX_INLINE_BLOCK, BOX_FLOAT_*,
- * or BOX_TABLE.
+ * Calculate minimum and maximum width of a table.
*
- * \param box BLOCK, INLINE_BLOCK, FLOAT, or TABLE box
- * \param min current min, updated to new min
- * \param max current max, updated to new max
- * \param max_sum sum of maximum widths, updated, or 0 if not required
- * \return true on success, false on memory exhaustion
+ * \param table box of type TABLE
*/
-bool calculate_block_widths(struct box *box, int *min, int *max,
- int *max_sum)
-{
- int width;
-
- if (box->type == BOX_TABLE) {
- if (!calculate_table_widths(box))
- return false;
- } else {
- if (!calculate_widths(box))
- return false;
- }
-
- if (box->style->width.width == CSS_WIDTH_LENGTH) {
- width = (int)css_len2px(&box->style->width.value.length, box->style);
- if (*min < width) *min = width;
- if (*max < width) *max = width;
- if (max_sum) *max_sum += width;
- } else if (box->style->width.width == CSS_WIDTH_AUTO && box->object) {
- /* replaced element */
- if (box->style->height.height == CSS_HEIGHT_AUTO)
- width = box->object->width;
- else
- width = box->object->width *
- css_len2px(&box->style->height.length,
- box->style) / box->object->height;
- if (*min < width) *min = width;
- if (*max < width) *max = width;
- if (max_sum) *max_sum += width;
- } else {
- if (*min < box->min_width) *min = box->min_width;
- if (*max < box->max_width) *max = box->max_width;
- if (max_sum) *max_sum += box->max_width;
- }
-
- return true;
-}
-
-
-/**
- * Find min, max width for an inline container.
- */
-
-bool calculate_inline_container_widths(struct box *box)
-{
- struct box *child;
- int min = 0, max = 0, line_max = 0;
-
- for (child = box->children; child != 0; child = child->next) {
- switch (child->type) {
- case BOX_INLINE:
- case BOX_TEXT:
- if (child->object)
- calculate_inline_replaced_widths(child,
- &min, &max, &line_max);
- else if (child->text)
- calculate_inline_widths(child,
- &min, &line_max);
- else
- child->width = 0;
- break;
-
- case BOX_INLINE_END:
- break;
-
- case BOX_INLINE_BLOCK:
- if (!calculate_block_widths(child, &min, &max,
- &line_max))
- return false;
- break;
-
- case BOX_FLOAT_LEFT:
- case BOX_FLOAT_RIGHT:
- if (!calculate_block_widths(child->children,
- &min, &max, 0))
- return false;
- break;
-
- case BOX_BR:
- if (max < line_max)
- max = line_max;
- line_max = 0;
- break;
-
- default:
- assert(0);
- }
- }
-
- if (max < line_max)
- max = line_max;
-
- if (box->parent && box->parent->style &&
- (box->parent->style->white_space == CSS_WHITE_SPACE_PRE ||
- box->parent->style->white_space == CSS_WHITE_SPACE_NOWRAP))
- min = max;
-
- assert(min <= max);
- box->min_width = min;
- box->max_width = max;
-
- return true;
-}
-
-
-/**
- * Find min, max width for an inline replaced box.
- */
-
-void calculate_inline_replaced_widths(struct box *box, int *min,
- int *max, int *line_max)
-{
- int width;
-
- if (box->style->width.width == CSS_WIDTH_LENGTH) {
- box->width = (int)css_len2px(&box->style->width.value.length, box->style);
- *line_max += box->width;
- if (*min < box->width)
- *min = box->width;
- } else if (box->style->width.width == CSS_WIDTH_AUTO) {
- if (box->style->height.height == CSS_HEIGHT_AUTO)
- width = box->object->width;
- else
- width = box->object->width *
- css_len2px(&box->style->height.length,
- box->style) / box->object->height;
- if (*min < width) *min = width;
- if (*max < width) *max = width;
- }
-}
-
-
-/**
- * Find min, max width for an inline text box.
- */
-
-void calculate_inline_widths(struct box *box, int *min, int *line_max)
-{
- unsigned int i, j;
- int width;
-
- /* max = all one line */
- /** \todo handle errors */
- nsfont_width(box->style, box->text, box->length, &box->width);
- *line_max += box->width;
- if (box->next && box->space) {
- nsfont_width(box->style, " ", 1, &width);
- *line_max += width;
- }
-
- /* min = widest word */
- i = 0;
- do {
- for (j = i; j != box->length && box->text[j] != ' '; j++)
- ;
- nsfont_width(box->style, box->text + i, j - i, &width);
- if (*min < width)
- *min = width;
- i = j + 1;
- } while (j != box->length);
-}
-
-
-/**
- * Find min, max widths for a table and determine column width types.
- *
- * \param table table box to calculate widths
- * \return true on success, false on memory exhaustion
- *
- * If table->max_width is not UNKNOWN_MAX_WIDTH, returns with no change to
- * table.
- *
- * If table->col is 0, it is created and filled in completely.
- *
- * If table->col exists, the type and width fields are left unchanged, and the
- * min and max fields are updated.
- *
- * table->min_width and table->max_width are set.
- */
-
-bool calculate_table_widths(struct box *table)
+void layout_minmax_table(struct box *table)
{
unsigned int i, j;
+ int border_spacing_h = 0;
+ int table_min = 0, table_max = 0;
+ int extra_fixed = 0;
+ float extra_frac = 0;
+ struct column *col = table->col;
struct box *row_group, *row, *cell;
- int width, min_width = 0, max_width = 0;
- struct column *col;
- bool first;
-
- LOG(("table %p, columns %u", table, table->columns));
/* check if the widths have already been calculated */
if (table->max_width != UNKNOWN_MAX_WIDTH)
- return true;
+ return;
- if ((col = table->col) == NULL) {
- col = table->col = malloc(table->columns * sizeof *col);
- if (!col)
- return false;
- for (i = 0; i != table->columns; i++)
- col[i].type = COLUMN_WIDTH_UNKNOWN;
- }
for (i = 0; i != table->columns; i++)
col[i].min = col[i].max = 0;
- assert(table->children && table->children->children);
-
- /* handle collapsing border model */
- assert(table->style);
- if (table->style->border_collapse == CSS_BORDER_COLLAPSE_COLLAPSE) {
-
- /* 1st stage: collapse all borders down to the cells */
- first = true;
- for (row_group = table->children; row_group;
- row_group = row_group->next) {
- assert(row_group->type == BOX_TABLE_ROW_GROUP);
- assert(row_group->style);
- table_collapse_borders_h(table, row_group, &first);
- first = (row_group->children);
- for (row = row_group->children; row; row = row->next) {
- assert(row->type == BOX_TABLE_ROW);
- assert(row->style);
- table_collapse_borders_h(row_group, row, &first);
- for (cell = row->children; cell; cell = cell->next) {
- assert(cell->type == BOX_TABLE_CELL);
- assert(cell->style);
- table_collapse_borders_v(row, cell, table->columns);
- }
- table_remove_borders(row->style);
- }
- table_remove_borders(row_group->style);
- }
- table_remove_borders(table->style);
-
- /* 2nd stage: rather than building a grid of cells, we slowly look up the
- * cell we want to collapse with */
- for (i = 0; i < table->columns; i++) {
- for (j = 0; j < table->rows; j++) {
- table_collapse_borders_cell(
- table_find_cell(table, i, j),
- table_find_cell(table, i + 1, j),
- table_find_cell(table, i, j + 1));
- }
- }
-
- /* 3rd stage: remove redundant borders */
- first = true;
- for (row_group = table->children; row_group;
- row_group = row_group->next) {
- for (row = row_group->children; row; row = row->next) {
- for (cell = row->children; cell; cell = cell->next) {
- if (!first) {
- cell->style->border[TOP].style =
- CSS_BORDER_STYLE_NONE;
- cell->style->border[TOP].width.value.value =
- 0;
- cell->style->border[TOP].width.value.unit =
- CSS_UNIT_PX;
- }
- if (cell->start_column > 0) {
- cell->style->border[LEFT].style =
- CSS_BORDER_STYLE_NONE;
- cell->style->border[LEFT].width.value.value =
- 0;
- cell->style->border[LEFT].width.value.unit =
- CSS_UNIT_PX;
- }
- }
- first = false;
- }
- }
- }
+ /* border-spacing is used in the separated borders model */
+ if (table->style->border_collapse == CSS_BORDER_COLLAPSE_SEPARATE)
+ border_spacing_h = css_len2px(&table->style->
+ border_spacing.horz, table->style);
/* 1st pass: consider cells with colspan 1 only */
- for (row_group = table->children; row_group;
- row_group = row_group->next) {
- assert(row_group->type == BOX_TABLE_ROW_GROUP);
- for (row = row_group->children; row; row = row->next) {
- assert(row->type == BOX_TABLE_ROW);
- for (cell = row->children; cell; cell = cell->next) {
- assert(cell->type == BOX_TABLE_CELL);
- assert(cell->style);
+ for (row_group = table->children; row_group; row_group =row_group->next)
+ for (row = row_group->children; row; row = row->next)
+ for (cell = row->children; cell; cell = cell->next) {
+ assert(cell->type == BOX_TABLE_CELL);
+ assert(cell->style);
- if (cell->columns != 1)
- continue;
+ if (cell->columns != 1)
+ continue;
- if (!calculate_widths(cell))
- return false;
- i = cell->start_column;
-
- /* update column min, max widths
- * using cell widths */
- if (col[i].min < cell->min_width)
- col[i].min = cell->min_width;
- if (col[i].max < cell->max_width)
- col[i].max = cell->max_width;
-
- /* fixed width takes priority over any
- * other width type */
- if (col[i].type != COLUMN_WIDTH_FIXED &&
- cell->style->width.width ==
- CSS_WIDTH_LENGTH) {
- col[i].type = COLUMN_WIDTH_FIXED;
- col[i].width = (int)css_len2px(&cell->style->
- width.value.length,
- cell->style);
- continue;
- }
+ layout_minmax_block(cell);
+ i = cell->start_column;
- if (col[i].type != COLUMN_WIDTH_UNKNOWN)
- continue;
-
- if (cell->style->width.width ==
- CSS_WIDTH_PERCENT) {
- col[i].type = COLUMN_WIDTH_PERCENT;
- col[i].width = cell->style->
- width.value.percent;
- } else if (cell->style->width.width ==
- CSS_WIDTH_AUTO) {
- col[i].type = COLUMN_WIDTH_AUTO;
- }
- }
- }
+ /* update column min, max widths using cell widths */
+ if (col[i].min < cell->min_width)
+ col[i].min = cell->min_width;
+ if (col[i].max < cell->max_width)
+ col[i].max = cell->max_width;
}
/* 2nd pass: cells which span multiple columns */
- for (row_group = table->children; row_group;
- row_group = row_group->next) {
- for (row = row_group->children; row; row = row->next) {
- for (cell = row->children; cell; cell = cell->next) {
- unsigned int flexible_columns = 0;
- int min = 0, max = 0, fixed_width = 0, cell_min;
- signed long extra;
+ for (row_group = table->children; row_group; row_group =row_group->next)
+ for (row = row_group->children; row; row = row->next)
+ for (cell = row->children; cell; cell = cell->next) {
+ unsigned int flexible_columns = 0;
+ int min = 0, max = 0, fixed_width = 0, extra;
- if (cell->columns == 1)
- continue;
+ if (cell->columns == 1)
+ continue;
- if (!calculate_widths(cell))
- return false;
- i = cell->start_column;
- cell_min = cell->min_width;
+ layout_minmax_block(cell);
+ i = cell->start_column;
- /* find min, max width so far of
- * spanned columns */
- for (j = 0; j != cell->columns; j++) {
- max += col[i + j].max;
- if (col[i + j].type == COLUMN_WIDTH_FIXED) {
- if (col[i + j].min < col[i + j].width)
- min += col[i + j].width;
- else
- min += col[i + j].min;
- fixed_width += col[i + j].width;
- } else {
- min += col[i + j].min;
- flexible_columns++;
- }
- }
+ /* find min width so far of spanned columns, and count
+ * number of non-fixed spanned columns and total fixed width */
+ for (j = 0; j != cell->columns; j++) {
+ min += col[i + j].min;
+ if (col[i + j].type == COLUMN_WIDTH_FIXED)
+ fixed_width += col[i + j].width;
+ else
+ flexible_columns++;
+ }
+ min += (cell->columns - 1) * border_spacing_h;
- if (cell->style->width.width == CSS_WIDTH_LENGTH) {
- width = (int)css_len2px(&cell->style->width.value.length,
- cell->style);
- if (cell_min < width)
- cell_min = width;
+ /* distribute extra min to spanned columns */
+ if (min < cell->min_width) {
+ if (flexible_columns == 0) {
+ extra = 1 + (cell->min_width - min) /
+ cell->columns;
+ for (j = 0; j != cell->columns; j++) {
+ col[i + j].min += extra;
+ if (col[i + j].max < col[i + j].min)
+ col[i + j].max = col[i + j].min;
}
-
- /* distribute extra min, max to spanned columns */
- if (min < cell_min) {
- if (flexible_columns == 0) {
- extra = 1 + (cell_min - min)
- / cell->columns;
- for (j = 0; j != cell->columns; j++) {
- col[i + j].min += extra;
- if (col[i + j].max < col[i + j].min)
- col[i + j].max = col[i + j].min;
- }
- } else {
- extra = 1 + (cell_min - min)
- / flexible_columns;
- max = 0;
- for (j = 0; j != cell->columns; j++) {
- if (col[i + j].type != COLUMN_WIDTH_FIXED) {
- col[i + j].min += extra;
- if (col[i + j].max < col[i + j].min)
- col[i + j].max = col[i + j].min;
- }
- max += col[i + j].max;
- }
+ } else {
+ extra = 1 + (cell->min_width - min) /
+ flexible_columns;
+ for (j = 0; j != cell->columns; j++) {
+ if (col[i + j].type !=
+ COLUMN_WIDTH_FIXED) {
+ col[i + j].min += extra;
+ if (col[i + j].max <
+ col[i + j].min)
+ col[i + j].max =
+ col[i + j].min;
}
}
- if (max < cell->max_width && flexible_columns != 0) {
- extra = 1 + (cell->max_width - max)
- / flexible_columns;
- for (j = 0; j != cell->columns; j++)
- if (col[i + j].type != COLUMN_WIDTH_FIXED)
- col[i + j].max += extra;
- }
}
}
- }
- for (i = 0; i < table->columns; i++) {
- 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;
- max_width += col[i].max;
+ /* find max width so far of spanned columns */
+ for (j = 0; j != cell->columns; j++)
+ max += col[i + j].max;
+ max += (cell->columns - 1) * border_spacing_h;
+
+ /* distribute extra max to spanned columns */
+ if (max < cell->max_width && flexible_columns) {
+ extra = 1 + (cell->max_width - max) / flexible_columns;
+ for (j = 0; j != cell->columns; j++)
+ if (col[i + j].type != COLUMN_WIDTH_FIXED)
+ col[i + j].max += extra;
+ }
}
- table->min_width = min_width;
- table->max_width = max_width;
- LOG(("min_width %i, max_width %i", min_width, max_width));
+ for (i = 0; i != table->columns; i++) {
+ if (col[i].max < col[i].min) {
+ box_dump(table, 0);
+ assert(0);
+ }
+ table_min += col[i].min;
+ table_max += col[i].max;
+ }
- return true;
+ /* add margins, border, padding to min, max widths */
+ calculate_mbp_width(table->style, &extra_fixed, &extra_frac);
+ if (1.0 <= extra_frac)
+ extra_frac = 0.9;
+ table->min_width = (table_min + extra_fixed) / (1.0 - extra_frac);
+ table->max_width = (table_max + extra_fixed) / (1.0 - extra_frac);
+ table->min_width += (table->columns + 1) * border_spacing_h;
+ table->max_width += (table->columns + 1) * border_spacing_h;
}
/**
- * Collapse the borders of two boxes together.
+ * Moves the children of a box by a specified amount
+ *
+ * \param box top of tree of boxes
+ * \param x the amount to move children by horizontally
+ * \param y the amount to move children by vertically
*/
-void table_collapse_borders_v(struct box *row, struct box *cell, unsigned int columns)
+void layout_move_children(struct box *box, int x, int y)
{
- struct css_border *border;
+ assert(box);
- if (cell->start_column == 0) {
- border = css_eyecatching_border(&row->style->border[LEFT], row->style,
- &cell->style->border[LEFT], cell->style);
- cell->style->border[LEFT] = *border;
- }
- border = css_eyecatching_border(&row->style->border[TOP], row->style,
- &cell->style->border[TOP], cell->style);
- cell->style->border[TOP] = *border;
- border = css_eyecatching_border(&row->style->border[BOTTOM], row->style,
- &cell->style->border[BOTTOM], cell->style);
- cell->style->border[BOTTOM] = *border;
- if ((cell->start_column + cell->columns) == columns) {
- border = css_eyecatching_border(&row->style->border[RIGHT], row->style,
- &cell->style->border[RIGHT], cell->style);
- cell->style->border[RIGHT] = *border;
+ for (box = box->children; box; box = box->next) {
+ box->x += x;
+ box->y += y;
}
}
/**
- * Collapse the borders of two boxes together.
+ * Determine width of horizontal margin, borders, and padding.
+ *
+ * \param style style to measure
+ * \param fixed updated to sum of fixed left and right margins, borders, and
+ * padding
+ * \param frac updated to sum of fractional left and right margins, borders,
+ * and padding
*/
-void table_collapse_borders_h(struct box *parent, struct box *child, bool *first)
+void calculate_mbp_width(struct css_style *style, int *fixed,
+ float *frac)
{
- struct css_border *border;
-
- if (*first) {
- border = css_eyecatching_border(&parent->style->border[TOP], parent->style,
- &child->style->border[TOP], child->style);
- child->style->border[TOP] = *border;
- *first = false;
- }
- border = css_eyecatching_border(&parent->style->border[LEFT], parent->style,
- &child->style->border[LEFT], child->style);
- child->style->border[LEFT] = *border;
- border = css_eyecatching_border(&parent->style->border[RIGHT], parent->style,
- &child->style->border[RIGHT], child->style);
- child->style->border[RIGHT] = *border;
- if (!child->next) {
- border = css_eyecatching_border(&parent->style->border[BOTTOM], parent->style,
- &child->style->border[BOTTOM], child->style);
- child->style->border[BOTTOM] = *border;
- }
-}
-
-
-/**
- * Collapse the borders of two boxes together.
- */
-
-void table_collapse_borders_cell(struct box *cell, struct box *right,
- struct box *bottom) {
- struct css_border *border;
-
- if (!cell)
- return;
-
- if ((right) && (right != cell)) {
- border = css_eyecatching_border(&cell->style->border[RIGHT], cell->style,
- &right->style->border[LEFT], right->style);
- cell->style->border[RIGHT] = *border;
+ unsigned int side;
- }
- if ((bottom) && (bottom != cell)) {
- border = css_eyecatching_border(&cell->style->border[BOTTOM], cell->style,
- &bottom->style->border[TOP], bottom->style);
- cell->style->border[BOTTOM] = *border;
- }
-}
+ assert(style);
+ *fixed = 0;
+ *frac = 0;
-/**
- * Removes all borders.
- */
+ for (side = 1; side != 5; side += 2) { /* RIGHT, LEFT */
+ /* margin */
+ if (style->margin[side].margin == CSS_MARGIN_LENGTH)
+ *fixed += css_len2px(&style->margin[side].value.length,
+ style);
+ else if (style->margin[side].margin == CSS_MARGIN_PERCENT)
+ *frac += style->margin[side].value.percent * 0.01;
-void table_remove_borders(struct css_style *style)
-{
- int i;
+ /* border */
+ if (style->border[side].style != CSS_BORDER_STYLE_NONE)
+ *fixed += css_len2px(&style->border[side].width.value,
+ style);
- for (i = 0; i < 4; i++) {
- style->border[i].style = CSS_BORDER_STYLE_NONE;
- style->border[i].width.value.value = 0;
- style->border[i].width.value.unit = CSS_UNIT_PX;
+ /* padding */
+ if (style->padding[side].padding == CSS_PADDING_LENGTH)
+ *fixed += css_len2px(&style->padding[side].value.length,
+ style);
+ else if (style->padding[side].padding == CSS_PADDING_PERCENT)
+ *frac += style->padding[side].value.percent * 0.01;
}
}
/**
- * Find a cell occupying a particular position in a table grid
- */
-
-struct box *table_find_cell(struct box *table, unsigned int x,
- unsigned int y)
-{
- struct box *row_group, *row, *cell;
- struct box *match = NULL;
- unsigned int cur_row = 0;
-
- if ((x > table->columns) || (y > table->rows))
- return NULL;
-
- /* this code uses brute-force and should be re-implemented using a faster
- * algorithm */
- for (row_group = table->children; row_group;
- row_group = row_group->next) {
- for (row = row_group->children; row; row = row->next) {
- for (cell = row->children; cell; cell = cell->next) {
- if (cell->start_column > x)
- break;
- if ((cell->start_column <= x) &&
- (x < (cell->start_column +
- cell->columns)))
- match = cell;
- }
- if (cur_row == y)
- return match;
- if (++cur_row > y)
- return NULL;
- }
- }
-
- return NULL;
-}
-
-/**
* Recursively calculate the descendant_[xy][01] values for a laid-out box tree.
*
* \param box tree of boxes to update
@@ -2352,8 +2156,9 @@ void layout_calculate_descendant_bboxes(struct box *box)
{
struct box *child;
- if (box->width == UNKNOWN_WIDTH) {
- LOG(("%p UNKNOWN_WIDTH", box));
+ if (box->width == UNKNOWN_WIDTH /*||
+ box->width < 0 || box->height < 0*/) {
+ LOG(("%p has bad width or height", box));
while (box->parent)
box = box->parent;
box_dump(box, 0);
diff --git a/render/layout.h b/render/layout.h
index c56b42d9c..f37f8fd7c 100644
--- a/render/layout.h
+++ b/render/layout.h
@@ -20,7 +20,7 @@
struct box;
-bool layout_document(struct content *content, int width);
+bool layout_document(struct content *content, int width, int height);
bool layout_block_context(struct box *block, struct content *content);
bool layout_inline_container(struct box *box, int width,
struct box *cont, int cx, int cy, struct content *content);
diff --git a/riscos/print.c b/riscos/print.c
index 94f067783..29663f259 100644
--- a/riscos/print.c
+++ b/riscos/print.c
@@ -469,7 +469,7 @@ void print_cleanup(void)
bool print_document(struct gui_window *g, const char *filename)
{
int left, right, top, bottom, width, height;
- int saved_width;
+ int saved_width, saved_height;
int yscroll = 0, sheets = print_max_sheets;
struct content *c = g->bw->current_content;
const char *error_message;
@@ -506,8 +506,9 @@ bool print_document(struct gui_window *g, const char *filename)
/* layout the document to the correct width */
saved_width = c->width;
+ saved_height = c->height;
if (c->type == CONTENT_HTML)
- layout_document(c, width);
+ layout_document(c, width, height);
/* open printer file */
error = xosfind_openoutw(osfind_NO_PATH | osfind_ERROR_IF_DIR |
@@ -645,7 +646,7 @@ bool print_document(struct gui_window *g, const char *filename)
/* restore document layout */
if (c->type == CONTENT_HTML)
- layout_document(c, saved_width);
+ layout_document(c, saved_width, saved_height);
return true;
@@ -663,7 +664,7 @@ error:
/* restore document layout */
if (c->type == CONTENT_HTML)
- layout_document(c, saved_width);
+ layout_document(c, saved_width, saved_height);
return false;
}
diff --git a/riscos/save_draw.c b/riscos/save_draw.c
index ba4842ca2..46622f0e1 100644
--- a/riscos/save_draw.c
+++ b/riscos/save_draw.c
@@ -146,7 +146,7 @@ bool save_as_draw(struct content *c, const char *path)
memcpy(diagram->source, "NetSurf ", 12);
/* recalculate box widths for an A4 page */
- if (!layout_document(c, A4PAGEWIDTH)) {
+ if (!layout_document(c, A4PAGEWIDTH, A4PAGEWIDTH)) {
warn_user("NoMemory", 0);
goto draw_save_error;
}
@@ -185,7 +185,7 @@ bool save_as_draw(struct content *c, const char *path)
drawbuf_free();
/* reset layout to current window width */
- if (!layout_document(c, current_width)) {
+ if (!layout_document(c, current_width, current_width)) {
warn_user("NoMemory", 0);
return false;
}
@@ -195,7 +195,7 @@ bool save_as_draw(struct content *c, const char *path)
draw_save_error:
drawbuf_free();
/* attempt to reflow back on failure */
- (void)layout_document(c, current_width);
+ (void)layout_document(c, current_width, current_width);
return false;
}
diff --git a/riscos/window.c b/riscos/window.c
index 12729853b..3d65abfdc 100644
--- a/riscos/window.c
+++ b/riscos/window.c
@@ -819,6 +819,32 @@ int gui_window_get_width(struct gui_window *g)
/**
+ * Find the current height of a browser window.
+ *
+ * \param g gui_window to measure
+ * \return height of window
+ */
+
+int gui_window_get_height(struct gui_window *g)
+{
+ wimp_window_state state;
+ os_error *error;
+
+ state.w = g->window;
+ error = xwimp_get_window_state(&state);
+ if (error) {
+ LOG(("xwimp_get_window_state: 0x%x: %s",
+ error->errnum, error->errmess));
+ warn_user("WimpError", error->errmess);
+ return 800;
+ }
+ return (state.visible.y1 - state.visible.y0 - (g->toolbar ?
+ ro_gui_theme_toolbar_full_height(g->toolbar) : 0)) /
+ 2 / g->option.scale;
+}
+
+
+/**
* Set the extent of the inside of a browser window.
*
* \param g gui_window to resize
@@ -1878,6 +1904,10 @@ bool ro_gui_window_keypress(struct gui_window *g, int key, bool toolbar)
}
return true;
+ case wimp_KEY_CONTROL + wimp_KEY_SHIFT + wimp_KEY_F9:
+ talloc_report_full(0, stderr);
+ return true;
+
case wimp_KEY_CONTROL + wimp_KEY_F9: /* Dump url_store. */
url_store_dump();
return true;
@@ -2259,7 +2289,7 @@ void ro_gui_window_process_reformats(void)
continue;
content_reformat(g->bw->current_content,
g->old_width / 2 / g->option.scale,
- 1000);
+ gui_window_get_height(g));
g->reformat_pending = false;
}
gui_reformat_pending = false;