summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--content/handlers/css/dump.c39
-rw-r--r--content/handlers/css/select.c52
-rw-r--r--content/handlers/css/select.h1
-rw-r--r--content/handlers/css/utils.c144
-rw-r--r--content/handlers/css/utils.h46
-rw-r--r--desktop/print.c37
-rw-r--r--desktop/selection.c67
-rw-r--r--desktop/selection.h7
-rw-r--r--desktop/textarea.c46
-rw-r--r--desktop/textarea.h8
-rw-r--r--render/box.c41
-rw-r--r--render/box.h11
-rw-r--r--render/box_construct.c23
-rw-r--r--render/box_normalise.c97
-rw-r--r--render/box_textarea.c11
-rw-r--r--render/font.c8
-rw-r--r--render/font.h11
-rw-r--r--render/form.c3
-rw-r--r--render/html.c15
-rw-r--r--render/html_interaction.c12
-rw-r--r--render/html_internal.h4
-rw-r--r--render/html_object.c6
-rw-r--r--render/html_redraw.c41
-rw-r--r--render/layout.c3267
-rw-r--r--render/layout.h31
-rw-r--r--render/search.c5
-rw-r--r--render/table.c319
-rw-r--r--render/table.h8
-rw-r--r--render/textplain.c2
29 files changed, 2496 insertions, 1866 deletions
diff --git a/content/handlers/css/dump.c b/content/handlers/css/dump.c
index 529bd4a88..b12e1d9e8 100644
--- a/content/handlers/css/dump.c
+++ b/content/handlers/css/dump.c
@@ -113,6 +113,45 @@ static void dump_css_unit(FILE *stream, css_fixed val, css_unit unit)
case CSS_UNIT_KHZ:
fprintf(stream, "kHz");
break;
+ case CSS_UNIT_CAP:
+ fprintf(stream, "cap");
+ break;
+ case CSS_UNIT_CH:
+ fprintf(stream, "ch");
+ break;
+ case CSS_UNIT_IC:
+ fprintf(stream, "ic");
+ break;
+ case CSS_UNIT_REM:
+ fprintf(stream, "rem");
+ break;
+ case CSS_UNIT_LH:
+ fprintf(stream, "lh");
+ break;
+ case CSS_UNIT_RLH:
+ fprintf(stream, "rlh");
+ break;
+ case CSS_UNIT_VH:
+ fprintf(stream, "vh");
+ break;
+ case CSS_UNIT_VW:
+ fprintf(stream, "vw");
+ break;
+ case CSS_UNIT_VI:
+ fprintf(stream, "vi");
+ break;
+ case CSS_UNIT_VB:
+ fprintf(stream, "vb");
+ break;
+ case CSS_UNIT_VMIN:
+ fprintf(stream, "vmin");
+ break;
+ case CSS_UNIT_VMAX:
+ fprintf(stream, "vmax");
+ break;
+ case CSS_UNIT_Q:
+ fprintf(stream, "q");
+ break;
}
}
diff --git a/content/handlers/css/select.c b/content/handlers/css/select.c
index 328d6a711..ee79eb394 100644
--- a/content/handlers/css/select.c
+++ b/content/handlers/css/select.c
@@ -278,7 +278,7 @@ css_select_results *nscss_get_style(nscss_select_ctx *ctx, dom_node *n,
* element's style */
error = css_computed_style_compose(ctx->parent_style,
styles->styles[CSS_PSEUDO_ELEMENT_NONE],
- nscss_compute_font_size, NULL,
+ nscss_compute_font_size, ctx,
&composed);
if (error != CSS_OK) {
css_select_results_destroy(styles);
@@ -310,7 +310,7 @@ css_select_results *nscss_get_style(nscss_select_ctx *ctx, dom_node *n,
error = css_computed_style_compose(
styles->styles[CSS_PSEUDO_ELEMENT_NONE],
styles->styles[pseudo_element],
- nscss_compute_font_size, NULL,
+ nscss_compute_font_size, ctx,
&composed);
if (error != CSS_OK) {
/* TODO: perhaps this shouldn't be quite so
@@ -349,7 +349,7 @@ css_computed_style *nscss_get_blank_style(nscss_select_ctx *ctx,
/* TODO: Do we really need to compose? Initial style shouldn't
* have any inherited properties. */
error = css_computed_style_compose(parent, partial,
- nscss_compute_font_size, NULL, &composed);
+ nscss_compute_font_size, ctx, &composed);
css_computed_style_destroy(partial);
if (error != CSS_OK) {
css_computed_style_destroy(composed);
@@ -422,14 +422,37 @@ css_error nscss_compute_font_size(void *pw, const css_hint *parent,
FDIV(parent_size.value, FLTTOFIX(1.2));
size->data.length.unit = parent_size.unit;
} else if (size->data.length.unit == CSS_UNIT_EM ||
- size->data.length.unit == CSS_UNIT_EX) {
+ size->data.length.unit == CSS_UNIT_EX ||
+ size->data.length.unit == CSS_UNIT_CAP ||
+ size->data.length.unit == CSS_UNIT_CH ||
+ size->data.length.unit == CSS_UNIT_IC) {
size->data.length.value =
FMUL(size->data.length.value, parent_size.value);
- if (size->data.length.unit == CSS_UNIT_EX) {
+ switch (size->data.length.unit) {
+ case CSS_UNIT_EX:
/* 1ex = 0.6em in NetSurf */
size->data.length.value = FMUL(size->data.length.value,
FLTTOFIX(0.6));
+ break;
+ case CSS_UNIT_CAP:
+ /* Height of captals. 1cap = 0.9em in NetSurf. */
+ size->data.length.value = FMUL(size->data.length.value,
+ FLTTOFIX(0.9));
+ break;
+ case CSS_UNIT_CH:
+ /* Width of '0'. 1ch = 0.4em in NetSurf. */
+ size->data.length.value = FMUL(size->data.length.value,
+ FLTTOFIX(0.4));
+ break;
+ case CSS_UNIT_IC:
+ /* Width of U+6C43. 1ic = 1.1em in NetSurf. */
+ size->data.length.value = FMUL(size->data.length.value,
+ FLTTOFIX(1.1));
+ break;
+ default:
+ /* No scaling required for EM. */
+ break;
}
size->data.length.unit = parent_size.unit;
@@ -437,6 +460,25 @@ css_error nscss_compute_font_size(void *pw, const css_hint *parent,
size->data.length.value = FDIV(FMUL(size->data.length.value,
parent_size.value), INTTOFIX(100));
size->data.length.unit = parent_size.unit;
+ } else if (size->data.length.unit == CSS_UNIT_REM) {
+ nscss_select_ctx *ctx = pw;
+ if (parent == NULL) {
+ size->data.length.value = parent_size.value;
+ size->data.length.unit = parent_size.unit;
+ } else {
+ css_computed_font_size(ctx->root_style,
+ &parent_size.value,
+ &size->data.length.unit);
+ size->data.length.value = FMUL(
+ size->data.length.value,
+ parent_size.value);
+ }
+ } else if (size->data.length.unit == CSS_UNIT_RLH) {
+ /** TODO: Convert root element line-height to absolute value. */
+ size->data.length.value = FMUL(size->data.length.value, FDIV(
+ INTTOFIX(nsoption_int(font_size)),
+ INTTOFIX(10)));
+ size->data.length.unit = CSS_UNIT_PT;
}
size->status = CSS_FONT_SIZE_DIMENSION;
diff --git a/content/handlers/css/select.h b/content/handlers/css/select.h
index abfb85814..9fa6d3a56 100644
--- a/content/handlers/css/select.h
+++ b/content/handlers/css/select.h
@@ -37,6 +37,7 @@ typedef struct nscss_select_ctx
bool quirks;
struct nsurl *base_url;
lwc_string *universal;
+ const css_computed_style *root_style;
const css_computed_style *parent_style;
} nscss_select_ctx;
diff --git a/content/handlers/css/utils.c b/content/handlers/css/utils.c
index 5c7cbd9a7..8fe157bd2 100644
--- a/content/handlers/css/utils.c
+++ b/content/handlers/css/utils.c
@@ -27,11 +27,75 @@
/** Screen DPI in fixed point units: defaults to 90, which RISC OS uses */
css_fixed nscss_screen_dpi = F_90;
+
+/**
+ * Map viewport-relative length units to either vh or vw.
+ *
+ * Non-viewport-relative units are unchanged.
+ *
+ * \param[in] ctx Length conversion context.
+ * \param[in] unit Unit to map.
+ * \return the mapped unit.
+ */
+static inline css_unit css_utils__fudge_viewport_units(
+ const nscss_len_ctx *ctx,
+ css_unit unit)
+{
+ switch (unit) {
+ case CSS_UNIT_VI:
+ assert(ctx->root_style != NULL);
+ if (css_computed_writing_mode(ctx->root_style) ==
+ CSS_WRITING_MODE_HORIZONTAL_TB) {
+ unit = CSS_UNIT_VW;
+ } else {
+ unit = CSS_UNIT_VH;
+ }
+ break;
+ case CSS_UNIT_VB:
+ assert(ctx->root_style != NULL);
+ if (css_computed_writing_mode(ctx->root_style) ==
+ CSS_WRITING_MODE_HORIZONTAL_TB) {
+ unit = CSS_UNIT_VH;
+ } else {
+ unit = CSS_UNIT_VW;
+ }
+ break;
+ case CSS_UNIT_VMIN:
+ if (ctx->vh < ctx->vw) {
+ unit = CSS_UNIT_VH;
+ } else {
+ unit = CSS_UNIT_VW;
+ }
+ break;
+ case CSS_UNIT_VMAX:
+ if (ctx->vh > ctx->vw) {
+ unit = CSS_UNIT_VH;
+ } else {
+ unit = CSS_UNIT_VW;
+ }
+ break;
+ default: break;
+ }
+
+ return unit;
+}
+
/* exported interface documented in content/handlers/css/utils.h */
-css_fixed nscss_len2pt(css_fixed length, css_unit unit)
+css_fixed nscss_len2pt(
+ const nscss_len_ctx *ctx,
+ css_fixed length,
+ css_unit unit)
{
/* Length must not be relative */
- assert(unit != CSS_UNIT_EM && unit != CSS_UNIT_EX);
+ assert(unit != CSS_UNIT_EM &&
+ unit != CSS_UNIT_EX &&
+ unit != CSS_UNIT_CAP &&
+ unit != CSS_UNIT_CH &&
+ unit != CSS_UNIT_IC &&
+ unit != CSS_UNIT_REM &&
+ unit != CSS_UNIT_RLH);
+
+ unit = css_utils__fudge_viewport_units(ctx, unit);
switch (unit) {
/* We assume the screen and any other output has the same dpi */
@@ -45,36 +109,50 @@ css_fixed nscss_len2pt(css_fixed length, css_unit unit)
/* 1in = 25.4mm => 1mm = (72/25.4)pt */
case CSS_UNIT_MM: return FMUL(length,
FDIV(F_72, FLTTOFIX(25.4)));
+ /* 1in = 101.6q => 1mm = (72/101.6)pt */
+ case CSS_UNIT_Q: return FMUL(length,
+ FDIV(F_72, FLTTOFIX(101.6)));
case CSS_UNIT_PT: return length;
/* 1pc = 12pt */
case CSS_UNIT_PC: return FMUL(length, INTTOFIX(12));
+ case CSS_UNIT_VH: return FDIV(FMUL(FDIV((length * ctx->vh), F_100),
+ F_72), nscss_screen_dpi);
+ case CSS_UNIT_VW: return FDIV(FMUL(FDIV((length * ctx->vw), F_100),
+ F_72), nscss_screen_dpi);
default: break;
}
return 0;
}
-
/* exported interface documented in content/handlers/css/utils.h */
-css_fixed nscss_len2px(css_fixed length, css_unit unit,
+css_fixed nscss_len2px(
+ const nscss_len_ctx *ctx,
+ css_fixed length,
+ css_unit unit,
const css_computed_style *style)
{
/* We assume the screen and any other output has the same dpi */
css_fixed px_per_unit;
- assert(style != NULL || (unit != CSS_UNIT_EM && unit != CSS_UNIT_EX));
+ unit = css_utils__fudge_viewport_units(ctx, unit);
switch (unit) {
case CSS_UNIT_EM:
case CSS_UNIT_EX:
+ case CSS_UNIT_CAP:
+ case CSS_UNIT_CH:
+ case CSS_UNIT_IC:
{
css_fixed font_size = 0;
css_unit font_unit = CSS_UNIT_PT;
+ assert(style != NULL);
+
css_computed_font_size(style, &font_size, &font_unit);
/* Convert to points */
- font_size = nscss_len2pt(font_size, font_unit);
+ font_size = nscss_len2pt(ctx, font_size, font_unit);
/* Clamp to configured minimum */
if (font_size < FDIV(INTTOFIX(nsoption_int(font_min_size)), F_10)) {
@@ -85,9 +163,22 @@ css_fixed nscss_len2px(css_fixed length, css_unit unit,
* 1in = 72pt => 1pt = (DPI/72)px */
px_per_unit = FDIV(FMUL(font_size, nscss_screen_dpi), F_72);
- /* Scale ex units: we use a fixed ratio of 1ex = 0.6em */
- if (unit == CSS_UNIT_EX)
+ /* Scale non-em units to em. We have fixed ratios. */
+ switch (unit) {
+ case CSS_UNIT_EX:
px_per_unit = FMUL(px_per_unit, FLTTOFIX(0.6));
+ break;
+ case CSS_UNIT_CAP:
+ px_per_unit = FMUL(px_per_unit, FLTTOFIX(0.9));
+ break;
+ case CSS_UNIT_CH:
+ px_per_unit = FMUL(px_per_unit, FLTTOFIX(0.4));
+ break;
+ case CSS_UNIT_IC:
+ px_per_unit = FMUL(px_per_unit, FLTTOFIX(1.1));
+ break;
+ default: break;
+ }
}
break;
case CSS_UNIT_PX:
@@ -105,6 +196,10 @@ css_fixed nscss_len2px(css_fixed length, css_unit unit,
case CSS_UNIT_MM:
px_per_unit = FDIV(nscss_screen_dpi, FLTTOFIX(25.4));
break;
+ /* 1in = 101.6q => 1q = (DPI/101.6)px */
+ case CSS_UNIT_Q:
+ px_per_unit = FDIV(nscss_screen_dpi, FLTTOFIX(101.6));
+ break;
/* 1in = 72pt => 1pt = (DPI/72)px */
case CSS_UNIT_PT:
px_per_unit = FDIV(nscss_screen_dpi, F_72);
@@ -113,6 +208,39 @@ css_fixed nscss_len2px(css_fixed length, css_unit unit,
case CSS_UNIT_PC:
px_per_unit = FDIV(nscss_screen_dpi, INTTOFIX(6));
break;
+ case CSS_UNIT_REM:
+ {
+ css_fixed font_size = 0;
+ css_unit font_unit = CSS_UNIT_PT;
+
+ assert(ctx->root_style != NULL);
+
+ css_computed_font_size(ctx->root_style,
+ &font_size, &font_unit);
+
+ /* Convert to points */
+ font_size = nscss_len2pt(ctx, font_size, font_unit);
+
+ /* Clamp to configured minimum */
+ if (font_size < FDIV(INTTOFIX(nsoption_int(font_min_size)), F_10)) {
+ font_size = FDIV(INTTOFIX(nsoption_int(font_min_size)), F_10);
+ }
+
+ /* Convert to pixels (manually, to maximise precision)
+ * 1in = 72pt => 1pt = (DPI/72)px */
+ px_per_unit = FDIV(FMUL(font_size, nscss_screen_dpi), F_72);
+ break;
+ }
+ /* 1rlh = <user_font_size>pt => 1rlh = (DPI/user_font_size)px */
+ case CSS_UNIT_RLH:
+ px_per_unit = FDIV(nscss_screen_dpi, FDIV(
+ INTTOFIX(nsoption_int(font_size)),
+ INTTOFIX(10)));
+ break;
+ case CSS_UNIT_VH:
+ return TRUNCATEFIX((FDIV((length * ctx->vh), F_100) + F_0_5));
+ case CSS_UNIT_VW:
+ return TRUNCATEFIX((FDIV((length * ctx->vw), F_100) + F_0_5));
default:
px_per_unit = 0;
break;
diff --git a/content/handlers/css/utils.h b/content/handlers/css/utils.h
index 21cb4973b..c8f4c82f4 100644
--- a/content/handlers/css/utils.h
+++ b/content/handlers/css/utils.h
@@ -27,24 +27,54 @@
extern css_fixed nscss_screen_dpi;
/**
+ * Length conversion context data.
+ */
+typedef struct nscss_len_ctx {
+ /**
+ * Viewport width in px.
+ * Only used if unit is vh, vw, vi, vb, vmin, or vmax.
+ */
+ int vw;
+ /**
+ * Viewport height in px.
+ * Only used if unit is vh, vw, vi, vb, vmin, or vmax.
+ */
+ int vh;
+ /**
+ * Computed style for the document root element.
+ * May be NULL if unit is not rem, or rlh.
+ */
+ const css_computed_style *root_style;
+} nscss_len_ctx;
+
+/**
* Convert an absolute CSS length to points.
*
- * \param[in] length Absolute CSS length.
- * \param[in] unit Unit of the length.
+ * \param[in] ctx Length conversion context.
+ * \param[in] length Absolute CSS length.
+ * \param[in] unit Unit of the length.
* \return length in points
*/
-css_fixed nscss_len2pt(css_fixed length, css_unit unit);
+css_fixed nscss_len2pt(
+ const nscss_len_ctx *ctx,
+ css_fixed length,
+ css_unit unit);
/**
* Convert a CSS length to pixels.
*
- * \param length Length to convert
- * \param unit Corresponding unit
- * \param style Computed style applying to length. May be NULL if unit is
- * neither em nor ex
+ * \param[in] ctx Length conversion context.
+ * \param[in] length Length to convert.
+ * \param[in] unit Corresponding unit.
+ * \param[in] style Computed style applying to length.
+ * May be NULL if unit is not em, ex, cap, ch, or ic.
* \return length in pixels
*/
-css_fixed nscss_len2px(css_fixed length, css_unit unit, const css_computed_style *style);
+css_fixed nscss_len2px(
+ const nscss_len_ctx *ctx,
+ css_fixed length,
+ css_unit unit,
+ const css_computed_style *style);
/**
diff --git a/desktop/print.c b/desktop/print.c
index 54cc5451a..5c0333a96 100644
--- a/desktop/print.c
+++ b/desktop/print.c
@@ -257,6 +257,11 @@ struct print_settings *print_make_settings(print_configuration configuration,
struct print_settings *settings;
css_fixed length = 0;
css_unit unit = CSS_UNIT_MM;
+ nscss_len_ctx len_ctx = {
+ .vw = DEFAULT_PAGE_WIDTH,
+ .vh = DEFAULT_PAGE_HEIGHT,
+ .root_style = NULL,
+ };
switch (configuration){
case PRINT_DEFAULT:
@@ -272,17 +277,17 @@ struct print_settings *print_make_settings(print_configuration configuration,
settings->scale = DEFAULT_EXPORT_SCALE;
length = INTTOFIX(DEFAULT_MARGIN_LEFT_MM);
- settings->margins[MARGINLEFT] =
- nscss_len2px(length, unit, NULL);
+ settings->margins[MARGINLEFT] = nscss_len2px(
+ &len_ctx, length, unit, NULL);
length = INTTOFIX(DEFAULT_MARGIN_RIGHT_MM);
- settings->margins[MARGINRIGHT] =
- nscss_len2px(length, unit, NULL);
+ settings->margins[MARGINRIGHT] = nscss_len2px(
+ &len_ctx, length, unit, NULL);
length = INTTOFIX(DEFAULT_MARGIN_TOP_MM);
- settings->margins[MARGINTOP] =
- nscss_len2px(length, unit, NULL);
+ settings->margins[MARGINTOP] = nscss_len2px(
+ &len_ctx, length, unit, NULL);
length = INTTOFIX(DEFAULT_MARGIN_BOTTOM_MM);
- settings->margins[MARGINBOTTOM] =
- nscss_len2px(length, unit, NULL);
+ settings->margins[MARGINBOTTOM] = nscss_len2px(
+ &len_ctx, length, unit, NULL);
break;
/* use settings from the Export options tab */
case PRINT_OPTIONS:
@@ -298,17 +303,17 @@ struct print_settings *print_make_settings(print_configuration configuration,
settings->scale = (float)nsoption_int(export_scale) / 100;
length = INTTOFIX(nsoption_int(margin_left));
- settings->margins[MARGINLEFT] =
- nscss_len2px(length, unit, NULL);
+ settings->margins[MARGINLEFT] = nscss_len2px(
+ &len_ctx, length, unit, NULL);
length = INTTOFIX(nsoption_int(margin_right));
- settings->margins[MARGINRIGHT] =
- nscss_len2px(length, unit, NULL);
+ settings->margins[MARGINRIGHT] = nscss_len2px(
+ &len_ctx, length, unit, NULL);
length = INTTOFIX(nsoption_int(margin_top));
- settings->margins[MARGINTOP] =
- nscss_len2px(length, unit, NULL);
+ settings->margins[MARGINTOP] = nscss_len2px(
+ &len_ctx, length, unit, NULL);
length = INTTOFIX(nsoption_int(margin_bottom));
- settings->margins[MARGINBOTTOM] =
- nscss_len2px(length, unit, NULL);
+ settings->margins[MARGINBOTTOM] = nscss_len2px(
+ &len_ctx, length, unit, NULL);
break;
default:
return NULL;
diff --git a/desktop/selection.c b/desktop/selection.c
index 7506af0ef..5cb43b8c3 100644
--- a/desktop/selection.c
+++ b/desktop/selection.c
@@ -70,18 +70,20 @@ struct selection_string {
typedef bool (*seln_traverse_handler)(const char *text, size_t length,
- struct box *box, void *handle, const char *whitespace_text,
- size_t whitespace_length);
+ struct box *box, const nscss_len_ctx *len_ctx, void *handle,
+ const char *whitespace_text, size_t whitespace_length);
-static bool redraw_handler(const char *text, size_t length, struct box *box,
+static bool redraw_handler(const char *text, size_t length,
+ struct box *box, const nscss_len_ctx *len_ctx,
void *handle, const char *whitespace_text,
size_t whitespace_length);
static void selection_redraw(struct selection *s, unsigned start_idx,
unsigned end_idx);
static bool selected_part(struct box *box, unsigned start_idx, unsigned end_idx,
unsigned *start_offset, unsigned *end_offset);
-static bool traverse_tree(struct box *box, unsigned start_idx, unsigned end_idx,
+static bool traverse_tree(struct box *box, const nscss_len_ctx *len_ctx,
+ unsigned start_idx, unsigned end_idx,
seln_traverse_handler handler,
void *handle, save_text_whitespace *before, bool *first,
bool do_marker);
@@ -198,7 +200,10 @@ void selection_reinit(struct selection *s, struct box *root)
* \param root the root box for html document or NULL for text/plain
*/
-void selection_init(struct selection *s, struct box *root)
+void selection_init(
+ struct selection *s,
+ struct box *root,
+ const nscss_len_ctx *len_ctx)
{
if (s->defined)
selection_clear(s, true);
@@ -207,6 +212,13 @@ void selection_init(struct selection *s, struct box *root)
s->start_idx = 0;
s->end_idx = 0;
s->drag_state = DRAG_NONE;
+ if (len_ctx != NULL) {
+ s->len_ctx = *len_ctx;
+ } else {
+ s->len_ctx.vw = 0;
+ s->len_ctx.vh = 0;
+ s->len_ctx.root_style = NULL;
+ }
selection_reinit(s, root);
}
@@ -442,6 +454,7 @@ bool selected_part(struct box *box, unsigned start_idx, unsigned end_idx,
* for all boxes that lie (partially) within the given range
*
* \param box box subtree
+ * \param len_ctx Length conversion context.
* \param start_idx start of range within textual representation (bytes)
* \param end_idx end of range
* \param handler handler function to call
@@ -452,7 +465,9 @@ bool selected_part(struct box *box, unsigned start_idx, unsigned end_idx,
* \return false iff traversal abandoned part-way through
*/
-bool traverse_tree(struct box *box, unsigned start_idx, unsigned end_idx,
+bool traverse_tree(
+ struct box *box, const nscss_len_ctx *len_ctx,
+ unsigned start_idx, unsigned end_idx,
seln_traverse_handler handler,
void *handle, save_text_whitespace *before, bool *first,
bool do_marker)
@@ -473,9 +488,9 @@ bool traverse_tree(struct box *box, unsigned start_idx, unsigned end_idx,
if (box->list_marker) {
/* do the marker box before continuing with the rest of the
* list element */
- if (!traverse_tree(box->list_marker, start_idx, end_idx,
- handler, handle, before, first,
- true))
+ if (!traverse_tree(box->list_marker, len_ctx,
+ start_idx, end_idx, handler, handle,
+ before, first, true))
return false;
}
@@ -506,7 +521,7 @@ bool traverse_tree(struct box *box, unsigned start_idx, unsigned end_idx,
&end_offset)) {
if (!handler(box->text + start_offset, min(box->length,
end_offset) - start_offset,
- box, handle, whitespace_text,
+ box, len_ctx, handle, whitespace_text,
whitespace_length))
return false;
if (before) {
@@ -533,7 +548,7 @@ bool traverse_tree(struct box *box, unsigned start_idx, unsigned end_idx,
* the tree */
struct box *next = child->next;
- if (!traverse_tree(child, start_idx, end_idx,
+ if (!traverse_tree(child, len_ctx, start_idx, end_idx,
handler, handle, before, first, false))
return false;
@@ -568,14 +583,16 @@ static bool selection_traverse(struct selection *s,
if (s->root) {
/* HTML */
- return traverse_tree(s->root, s->start_idx, s->end_idx,
- handler, handle, &before, &first, false);
+ return traverse_tree(s->root, &s->len_ctx,
+ s->start_idx, s->end_idx,
+ handler, handle,
+ &before, &first, false);
}
/* Text */
text = textplain_get_raw_data(s->c, s->start_idx, s->end_idx, &length);
- if (text && !handler(text, length, NULL, handle, NULL, 0))
+ if (text && !handler(text, length, NULL, NULL, handle, NULL, 0))
return false;
return true;
@@ -597,8 +614,8 @@ static bool selection_traverse(struct selection *s,
*/
bool redraw_handler(const char *text, size_t length, struct box *box,
- void *handle, const char *whitespace_text,
- size_t whitespace_length)
+ const nscss_len_ctx *len_ctx, void *handle,
+ const char *whitespace_text, size_t whitespace_length)
{
if (box) {
struct rdw_info *r = (struct rdw_info*)handle;
@@ -606,7 +623,7 @@ bool redraw_handler(const char *text, size_t length, struct box *box,
int x, y;
plot_font_style_t fstyle;
- font_plot_style_from_css(box->style, &fstyle);
+ font_plot_style_from_css(len_ctx, box->style, &fstyle);
/* \todo - it should be possible to reduce the redrawn area by
* considering the 'text', 'length' and 'space' parameters */
@@ -652,7 +669,7 @@ void selection_redraw(struct selection *s, unsigned start_idx, unsigned end_idx)
rdw.inited = false;
if (s->root) {
- if (!traverse_tree(s->root, start_idx, end_idx,
+ if (!traverse_tree(s->root, &s->len_ctx, start_idx, end_idx,
redraw_handler, &rdw,
NULL, NULL, false))
return;
@@ -739,10 +756,11 @@ static bool selection_string_append(const char *text, size_t length, bool space,
/**
* Selection traversal routine for appending text to a string
*
- * \param text pointer to text being added, or NULL for newline
- * \param length length of text to be appended (bytes)
- * \param box pointer to text box, or NULL if from textplain
- * \param handle selection string to append to
+ * \param text pointer to text being added, or NULL for newline
+ * \param length length of text to be appended (bytes)
+ * \param box pointer to text box, or NULL if from textplain
+ * \param len_ctx Length conversion context
+ * \param handle selection string to append to
* \param whitespace_text whitespace to place before text for formatting
* may be NULL
* \param whitespace_length length of whitespace_text
@@ -750,7 +768,8 @@ static bool selection_string_append(const char *text, size_t length, bool space,
*/
static bool selection_copy_handler(const char *text, size_t length,
- struct box *box, void *handle, const char *whitespace_text,
+ struct box *box, const nscss_len_ctx *len_ctx,
+ void *handle, const char *whitespace_text,
size_t whitespace_length)
{
bool add_space = false;
@@ -771,7 +790,7 @@ static bool selection_copy_handler(const char *text, size_t length,
if (box->style != NULL) {
/* Override default font style */
- font_plot_style_from_css(box->style, &style);
+ font_plot_style_from_css(len_ctx, box->style, &style);
pstyle = &style;
} else {
/* If there's no style, there must be no text */
diff --git a/desktop/selection.h b/desktop/selection.h
index e2bc3b31d..2f3f6dcfe 100644
--- a/desktop/selection.h
+++ b/desktop/selection.h
@@ -25,6 +25,7 @@
#include <stdbool.h>
#include "netsurf/mouse.h"
+#include "content/handlers/css/utils.h"
struct box;
@@ -43,6 +44,7 @@ struct selection
{
struct content *c;
struct box *root;
+ nscss_len_ctx len_ctx;
unsigned max_idx; /* total bytes in text representation */
@@ -60,7 +62,10 @@ struct selection *selection_create(struct content *c, bool is_html);
void selection_prepare(struct selection *s, struct content *c, bool is_html);
void selection_destroy(struct selection *s);
-void selection_init(struct selection *s, struct box *root);
+void selection_init(
+ struct selection *s,
+ struct box *root,
+ const nscss_len_ctx *len_ctx);
void selection_reinit(struct selection *s, struct box *root);
/* struct box *selection_root(struct selection *s); */
diff --git a/desktop/textarea.c b/desktop/textarea.c
index 149ca26b1..3fd4c9804 100644
--- a/desktop/textarea.c
+++ b/desktop/textarea.c
@@ -1803,6 +1803,10 @@ static void textarea_setup_text_offsets(struct textarea *ta)
{
int text_y_offset, text_y_offset_baseline;
+ ta->line_height = FIXTOINT(FMUL(FLTTOFIX(1.3), FDIV(FMUL(
+ nscss_screen_dpi, FDIV(INTTOFIX(ta->fstyle.size),
+ INTTOFIX(FONT_SIZE_SCALE))), F_72)));
+
text_y_offset = text_y_offset_baseline = ta->border_width;
if (ta->flags & TEXTAREA_MULTILINE) {
/* Multiline textarea */
@@ -1822,6 +1826,27 @@ static void textarea_setup_text_offsets(struct textarea *ta)
}
+/**
+ * Set font styles up for a textarea.
+ *
+ * \param[in] ta Textarea to update.
+ * \param[in] fstyle Font style to set in textarea.
+ * \param[in] selected_text Textarea selected text colour.
+ * \param[in] selected_bg Textarea selection background colour.
+ */
+static void textarea_set_text_style(
+ struct textarea *ta,
+ const plot_font_style_t *fstyle,
+ colour selected_text,
+ colour selected_bg)
+{
+ ta->fstyle = *fstyle;
+
+ ta->sel_fstyle = *fstyle;
+ ta->sel_fstyle.foreground = selected_text;
+ ta->sel_fstyle.background = selected_bg;
+}
+
/* exported interface, documented in textarea.h */
struct textarea *textarea_create(const textarea_flags flags,
@@ -1861,11 +1886,10 @@ struct textarea *textarea_create(const textarea_flags flags,
ret->border_width = setup->border_width;
ret->border_col = setup->border_col;
- ret->fstyle = setup->text;
-
- ret->sel_fstyle = setup->text;
- ret->sel_fstyle.foreground = setup->selected_text;
- ret->sel_fstyle.background = setup->selected_bg;
+ textarea_set_text_style(ret,
+ &setup->text,
+ setup->selected_text,
+ setup->selected_bg);
ret->scroll_x = 0;
ret->scroll_y = 0;
@@ -3220,8 +3244,12 @@ void textarea_set_dimensions(struct textarea *ta, int width, int height)
/* exported interface, documented in textarea.h */
-void textarea_set_layout(struct textarea *ta, int width, int height,
- int top, int right, int bottom, int left)
+void textarea_set_layout(
+ struct textarea *ta,
+ const plot_font_style_t *fstyle,
+ int width, int height,
+ int top, int right,
+ int bottom, int left)
{
struct rect r = {0, 0, 0, 0};
@@ -3232,6 +3260,10 @@ void textarea_set_layout(struct textarea *ta, int width, int height,
ta->pad_bottom = bottom + ((ta->bar_x == NULL) ? 0 : SCROLLBAR_WIDTH);
ta->pad_left = left;
+ textarea_set_text_style(ta, fstyle,
+ ta->sel_fstyle.foreground,
+ ta->sel_fstyle.background);
+
textarea_setup_text_offsets(ta);
if (ta->flags & TEXTAREA_MULTILINE) {
diff --git a/desktop/textarea.h b/desktop/textarea.h
index b386e50e8..82e0de95b 100644
--- a/desktop/textarea.h
+++ b/desktop/textarea.h
@@ -329,8 +329,12 @@ void textarea_set_dimensions(struct textarea *ta, int width, int height);
* \param bottom the new bottom padding of the textarea
* \param left the new left padding of the textarea
*/
-void textarea_set_layout(struct textarea *ta, int width, int height,
- int top, int right, int bottom, int left);
+void textarea_set_layout(
+ struct textarea *ta,
+ const plot_font_style_t *fstyle,
+ int width, int height,
+ int top, int right,
+ int bottom, int left);
/**
diff --git a/render/box.c b/render/box.c
index 8b9c89ee6..c97e8982b 100644
--- a/render/box.c
+++ b/render/box.c
@@ -342,20 +342,27 @@ void box_bounds(struct box *box, struct rect *r)
/**
* Determine if a point lies within a box.
*
- * \param box box to consider
- * \param x coordinate relative to box
- * \param y coordinate relative to box
- * \param physically if function returning true, physically is set true if
- * point is within the box's physical dimensions and false
- * if the point is not within the box's physical dimensions
- * but is in the area defined by the box's descendants.
- * if function returning false, physically is undefined.
+ * \param[in] len_ctx CSS length conversion context to use.
+ * \param[in] box Box to consider
+ * \param[in] x Coordinate relative to box
+ * \param[in] y Coordinate relative to box
+ * \param[out] physically If function returning true, physically is set true
+ * iff point is within the box's physical dimensions and
+ * false if the point is not within the box's physical
+ * dimensions but is in the area defined by the box's
+ * descendants. If function returns false, physically
+ * is undefined.
* \return true if the point is within the box or a descendant box
*
* This is a helper function for box_at_point().
*/
-static bool box_contains_point(struct box *box, int x, int y, bool *physically)
+static bool box_contains_point(
+ const nscss_len_ctx *len_ctx,
+ const struct box *box,
+ int x,
+ int y,
+ bool *physically)
{
css_computed_clip_rect css_rect;
@@ -382,25 +389,25 @@ static bool box_contains_point(struct box *box, int x, int y, bool *physically)
/* Adjust rect to css clip region */
if (css_rect.left_auto == false) {
- r.x0 += FIXTOINT(nscss_len2px(
+ r.x0 += FIXTOINT(nscss_len2px(len_ctx,
css_rect.left, css_rect.lunit,
box->style));
}
if (css_rect.top_auto == false) {
- r.y0 += FIXTOINT(nscss_len2px(
+ r.y0 += FIXTOINT(nscss_len2px(len_ctx,
css_rect.top, css_rect.tunit,
box->style));
}
if (css_rect.right_auto == false) {
r.x1 = box->border[LEFT].width +
- FIXTOINT(nscss_len2px(
+ FIXTOINT(nscss_len2px(len_ctx,
css_rect.right,
css_rect.runit,
box->style));
}
if (css_rect.bottom_auto == false) {
r.y1 = box->border[TOP].width +
- FIXTOINT(nscss_len2px(
+ FIXTOINT(nscss_len2px(len_ctx,
css_rect.bottom,
css_rect.bunit,
box->style));
@@ -659,6 +666,7 @@ skip_children:
/**
* Find the boxes at a point.
*
+ * \param len_ctx CSS length conversion context for document.
* \param box box to search children of
* \param x point to find, in global document coordinates
* \param y point to find, in global document coordinates
@@ -674,13 +682,14 @@ skip_children:
* struct box *box = top_of_document_to_search;
* int box_x = 0, box_y = 0;
*
- * while ((box = box_at_point(box, x, y, &box_x, &box_y))) {
+ * while ((box = box_at_point(len_ctx, box, x, y, &box_x, &box_y))) {
* // process box
* }
* \endcode
*/
-struct box *box_at_point(struct box *box, const int x, const int y,
+struct box *box_at_point(const nscss_len_ctx *len_ctx,
+ struct box *box, const int x, const int y,
int *box_x, int *box_y)
{
bool skip_children;
@@ -690,7 +699,7 @@ struct box *box_at_point(struct box *box, const int x, const int y,
skip_children = false;
while ((box = box_next_xy(box, box_x, box_y, skip_children))) {
- if (box_contains_point(box, x - *box_x, y - *box_y,
+ if (box_contains_point(len_ctx, box, x - *box_x, y - *box_y,
&physically)) {
*box_x -= scrollbar_get_offset(box->scroll_x);
*box_y -= scrollbar_get_offset(box->scroll_y);
diff --git a/render/box.h b/render/box.h
index 2800d4026..1af0a8b73 100644
--- a/render/box.h
+++ b/render/box.h
@@ -91,6 +91,8 @@
#include <stdio.h>
#include <libcss/libcss.h>
+#include "content/handlers/css/utils.h"
+
struct content;
struct box;
struct browser_window;
@@ -328,7 +330,9 @@ void box_free(struct box *box);
void box_free_box(struct box *box);
void box_bounds(struct box *box, struct rect *r);
void box_coords(struct box *box, int *x, int *y);
-struct box *box_at_point(struct box *box, const int x, const int y,
+struct box *box_at_point(
+ const nscss_len_ctx *len_ctx,
+ struct box *box, const int x, const int y,
int *box_x, int *box_y);
struct box *box_pick_text_box(struct html_content *html,
int x, int y, int dir, int *dx, int *dy);
@@ -356,6 +360,9 @@ bool box_hscrollbar_present(const struct box *box);
nserror dom_to_box(struct dom_node *n, struct html_content *c,
box_construct_complete_cb cb);
-bool box_normalise_block(struct box *block, struct html_content *c);
+bool box_normalise_block(
+ struct box *block,
+ const struct box *root,
+ struct html_content *c);
#endif
diff --git a/render/box_construct.c b/render/box_construct.c
index 1982622f9..1aa99e2d1 100644
--- a/render/box_construct.c
+++ b/render/box_construct.c
@@ -104,7 +104,8 @@ static bool box_construct_element(struct box_construct_ctx *ctx,
static void box_construct_element_after(dom_node *n, html_content *content);
static bool box_construct_text(struct box_construct_ctx *ctx);
static css_select_results * box_get_style(html_content *c,
- const css_computed_style *parent_style, dom_node *n);
+ const css_computed_style *parent_style,
+ const css_computed_style *root_style, dom_node *n);
static void box_text_transform(char *s, unsigned int len,
enum css_text_transform_e tt);
#define BOX_SPECIAL_PARAMS dom_node *n, html_content *content, \
@@ -429,7 +430,8 @@ void convert_xml_to_box(struct box_construct_ctx *ctx)
root.children->parent = &root;
/** \todo Remove box_normalise_block */
- if (box_normalise_block(&root, ctx->content) == false) {
+ if (box_normalise_block(&root, ctx->root_box,
+ ctx->content) == false) {
ctx->cb(ctx->content, false);
} else {
ctx->content->layout = root.children;
@@ -741,6 +743,7 @@ bool box_construct_element(struct box_construct_ctx *ctx,
lwc_string *bgimage_uri;
dom_exception err;
struct box_construct_props props;
+ const css_computed_style *root_style = NULL;
assert(ctx->n != NULL);
@@ -753,7 +756,12 @@ bool box_construct_element(struct box_construct_ctx *ctx,
props.containing_block->flags &= ~PRE_STRIP;
}
- styles = box_get_style(ctx->content, props.parent_style, ctx->n);
+ if (props.node_is_root == false) {
+ root_style = ctx->root_box->style;
+ }
+
+ styles = box_get_style(ctx->content, props.parent_style, root_style,
+ ctx->n);
if (styles == NULL)
return false;
@@ -1321,13 +1329,15 @@ bool box_construct_text(struct box_construct_ctx *ctx)
/**
* Get the style for an element.
*
- * \param c content of type CONTENT_HTML that is being processed
+ * \param c content of type CONTENT_HTML that is being processed
* \param parent_style style at this point in xml tree, or NULL for root
- * \param n node in xml tree
+ * \param root_style root node's style, or NULL for root
+ * \param n node in xml tree
* \return the new style, or NULL on memory exhaustion
*/
css_select_results *box_get_style(html_content *c,
- const css_computed_style *parent_style, dom_node *n)
+ const css_computed_style *parent_style,
+ const css_computed_style *root_style, dom_node *n)
{
dom_string *s;
dom_exception err;
@@ -1359,6 +1369,7 @@ css_select_results *box_get_style(html_content *c,
ctx.quirks = (c->quirks == DOM_DOCUMENT_QUIRKS_MODE_FULL);
ctx.base_url = c->base_url;
ctx.universal = c->universal;
+ ctx.root_style = root_style;
ctx.parent_style = parent_style;
/* Select style for element */
diff --git a/render/box_normalise.c b/render/box_normalise.c
index 9f78f75ac..8da245754 100644
--- a/render/box_normalise.c
+++ b/render/box_normalise.c
@@ -65,24 +65,38 @@ struct columns {
};
-static bool box_normalise_table(struct box *table, html_content *c);
-static bool box_normalise_table_spans(struct box *table,
- struct span_info *spans, html_content *c);
-static bool box_normalise_table_row_group(struct box *row_group,
+static bool box_normalise_table(
+ struct box *table,
+ const struct box *root,
+ html_content *c);
+static bool box_normalise_table_spans(
+ struct box *table,
+ const struct box *root,
+ struct span_info *spans,
+ html_content *c);
+static bool box_normalise_table_row_group(
+ struct box *row_group,
+ const struct box *root,
struct columns *col_info,
html_content *c);
-static bool box_normalise_table_row(struct box *row,
+static bool box_normalise_table_row(
+ struct box *row,
+ const struct box *root,
struct columns *col_info,
html_content *c);
static bool calculate_table_row(struct columns *col_info,
unsigned int col_span, unsigned int row_span,
unsigned int *start_column, struct box *cell);
-static bool box_normalise_inline_container(struct box *cont, html_content *c);
+static bool box_normalise_inline_container(
+ struct box *cont,
+ const struct box *root,
+ html_content *c);
/**
* Ensure the box tree is correctly nested by adding and removing nodes.
*
* \param block box of type BLOCK, INLINE_BLOCK, or TABLE_CELL
+ * \param root root box of document
* \param c content of boxes
* \return true on success, false on memory exhaustion
*
@@ -100,7 +114,10 @@ static bool box_normalise_inline_container(struct box *cont, html_content *c);
* \endcode
*/
-bool box_normalise_block(struct box *block, html_content *c)
+bool box_normalise_block(
+ struct box *block,
+ const struct box *root,
+ html_content *c)
{
struct box *child;
struct box *next_child;
@@ -109,6 +126,9 @@ bool box_normalise_block(struct box *block, html_content *c)
nscss_select_ctx ctx;
assert(block != NULL);
+ assert(root != NULL);
+
+ ctx.root_style = root->style;
#ifdef BOX_NORMALISE_DEBUG
NSLOG(netsurf, INFO, "block %p, block->type %u", block, block->type);
@@ -128,15 +148,15 @@ bool box_normalise_block(struct box *block, html_content *c)
switch (child->type) {
case BOX_BLOCK:
/* ok */
- if (box_normalise_block(child, c) == false)
+ if (box_normalise_block(child, root, c) == false)
return false;
break;
case BOX_INLINE_CONTAINER:
- if (box_normalise_inline_container(child, c) == false)
+ if (box_normalise_inline_container(child, root, c) == false)
return false;
break;
case BOX_TABLE:
- if (box_normalise_table(child, c) == false)
+ if (box_normalise_table(child, root, c) == false)
return false;
break;
case BOX_INLINE:
@@ -199,7 +219,7 @@ bool box_normalise_block(struct box *block, html_content *c)
block->last = table;
table->parent = block;
- if (box_normalise_table(table, c) == false)
+ if (box_normalise_table(table, root, c) == false)
return false;
break;
default:
@@ -211,7 +231,10 @@ bool box_normalise_block(struct box *block, html_content *c)
}
-bool box_normalise_table(struct box *table, html_content * c)
+bool box_normalise_table(
+ struct box *table,
+ const struct box *root,
+ html_content * c)
{
struct box *child;
struct box *next_child;
@@ -223,6 +246,8 @@ bool box_normalise_table(struct box *table, html_content * c)
assert(table != NULL);
assert(table->type == BOX_TABLE);
+ ctx.root_style = root->style;
+
#ifdef BOX_NORMALISE_DEBUG
NSLOG(netsurf, INFO, "table %p", table);
#endif
@@ -243,7 +268,7 @@ bool box_normalise_table(struct box *table, html_content * c)
switch (child->type) {
case BOX_TABLE_ROW_GROUP:
/* ok */
- if (box_normalise_table_row_group(child,
+ if (box_normalise_table_row_group(child, root,
&col_info, c) == false) {
free(col_info.spans);
return false;
@@ -308,7 +333,7 @@ bool box_normalise_table(struct box *table, html_content * c)
table->last = row_group;
row_group->parent = table;
- if (box_normalise_table_row_group(row_group,
+ if (box_normalise_table_row_group(row_group, root,
&col_info, c) == false) {
free(col_info.spans);
return false;
@@ -390,16 +415,13 @@ bool box_normalise_table(struct box *table, html_content * c)
table->rows = 1;
}
- if (box_normalise_table_spans(table, col_info.spans, c) == false) {
+ if (box_normalise_table_spans(table, root, col_info.spans, c) == false) {
free(col_info.spans);
return false;
}
free(col_info.spans);
- if (table_calculate_column_types(table) == false)
- return false;
-
#ifdef BOX_NORMALISE_DEBUG
NSLOG(netsurf, INFO, "table %p done", table);
#endif
@@ -413,12 +435,16 @@ bool box_normalise_table(struct box *table, html_content * c)
* Additionally, generate empty cells.
*
* \param table Table to process
+ * \param root root box of document
* \param spans Array of length table->columns for use in empty cell detection
* \param c Content containing table
* \return True on success, false on memory exhaustion.
*/
-bool box_normalise_table_spans(struct box *table, struct span_info *spans,
+bool box_normalise_table_spans(
+ struct box *table,
+ const struct box *root,
+ struct span_info *spans,
html_content *c)
{
struct box *table_row_group;
@@ -429,6 +455,8 @@ bool box_normalise_table_spans(struct box *table, struct span_info *spans,
unsigned int col;
nscss_select_ctx ctx;
+ ctx.root_style = root->style;
+
/* Clear span data */
memset(spans, 0, table->columns * sizeof(struct span_info));
@@ -572,7 +600,9 @@ bool box_normalise_table_spans(struct box *table, struct span_info *spans,
}
-bool box_normalise_table_row_group(struct box *row_group,
+bool box_normalise_table_row_group(
+ struct box *row_group,
+ const struct box *root,
struct columns *col_info,
html_content * c)
{
@@ -586,6 +616,8 @@ bool box_normalise_table_row_group(struct box *row_group,
assert(row_group != 0);
assert(row_group->type == BOX_TABLE_ROW_GROUP);
+ ctx.root_style = root->style;
+
#ifdef BOX_NORMALISE_DEBUG
NSLOG(netsurf, INFO, "row_group %p", row_group);
#endif
@@ -597,7 +629,7 @@ bool box_normalise_table_row_group(struct box *row_group,
case BOX_TABLE_ROW:
/* ok */
group_row_count++;
- if (box_normalise_table_row(child, col_info,
+ if (box_normalise_table_row(child, root, col_info,
c) == false)
return false;
break;
@@ -657,7 +689,7 @@ bool box_normalise_table_row_group(struct box *row_group,
row->parent = row_group;
group_row_count++;
- if (box_normalise_table_row(row, col_info,
+ if (box_normalise_table_row(row, root, col_info,
c) == false)
return false;
break;
@@ -722,7 +754,9 @@ bool box_normalise_table_row_group(struct box *row_group,
}
-bool box_normalise_table_row(struct box *row,
+bool box_normalise_table_row(
+ struct box *row,
+ const struct box *root,
struct columns *col_info,
html_content * c)
{
@@ -736,6 +770,8 @@ bool box_normalise_table_row(struct box *row,
assert(row != NULL);
assert(row->type == BOX_TABLE_ROW);
+ ctx.root_style = root->style;
+
#ifdef BOX_NORMALISE_DEBUG
NSLOG(netsurf, INFO, "row %p", row);
#endif
@@ -746,7 +782,7 @@ bool box_normalise_table_row(struct box *row,
switch (child->type) {
case BOX_TABLE_CELL:
/* ok */
- if (box_normalise_block(child, c) == false)
+ if (box_normalise_block(child, root, c) == false)
return false;
cell = child;
break;
@@ -805,7 +841,7 @@ bool box_normalise_table_row(struct box *row,
row->last = cell;
cell->parent = row;
- if (box_normalise_block(cell, c) == false)
+ if (box_normalise_block(cell, root, c) == false)
return false;
break;
case BOX_INLINE:
@@ -928,7 +964,10 @@ bool calculate_table_row(struct columns *col_info,
}
-bool box_normalise_inline_container(struct box *cont, html_content * c)
+bool box_normalise_inline_container(
+ struct box *cont,
+ const struct box *root,
+ html_content * c)
{
struct box *child;
struct box *next_child;
@@ -951,7 +990,7 @@ bool box_normalise_inline_container(struct box *cont, html_content * c)
break;
case BOX_INLINE_BLOCK:
/* ok */
- if (box_normalise_block(child, c) == false)
+ if (box_normalise_block(child, root, c) == false)
return false;
break;
case BOX_FLOAT_LEFT:
@@ -961,12 +1000,12 @@ bool box_normalise_inline_container(struct box *cont, html_content * c)
switch (child->children->type) {
case BOX_BLOCK:
- if (box_normalise_block(child->children,
+ if (box_normalise_block(child->children, root,
c) == false)
return false;
break;
case BOX_TABLE:
- if (box_normalise_table(child->children,
+ if (box_normalise_table(child->children, root,
c) == false)
return false;
break;
diff --git a/render/box_textarea.c b/render/box_textarea.c
index 3b1e7750c..a60984235 100644
--- a/render/box_textarea.c
+++ b/render/box_textarea.c
@@ -239,7 +239,14 @@ bool box_textarea_create_textarea(html_content *html,
dom_exception err;
textarea_setup ta_setup;
textarea_flags ta_flags;
- plot_font_style_t fstyle;
+ plot_font_style_t fstyle = {
+ .family = PLOT_FONT_FAMILY_SANS_SERIF,
+ .size = 10 * FONT_SIZE_SCALE,
+ .weight = 400,
+ .flags = FONTF_NONE,
+ .background = 0,
+ .foreground = 0,
+ };
bool read_only = false;
bool disabled = false;
struct form_control *gadget = box->gadget;
@@ -307,8 +314,6 @@ bool box_textarea_create_textarea(html_content *html,
gadget->data.text.data.gadget = gadget;
- font_plot_style_from_css(gadget->box->style, &fstyle);
-
/* Reset to correct values by layout */
ta_setup.width = 200;
ta_setup.height = 20;
diff --git a/render/font.c b/render/font.c
index 94ef877c7..a769b476f 100644
--- a/render/font.c
+++ b/render/font.c
@@ -131,8 +131,10 @@ static plot_font_flags_t plot_font_flags(enum css_font_style_e style,
}
-/* exported function documented in render/font_internal.h */
-void font_plot_style_from_css(const css_computed_style *css,
+/* exported function documented in render/font.h */
+void font_plot_style_from_css(
+ const nscss_len_ctx *len_ctx,
+ const css_computed_style *css,
plot_font_style_t *fstyle)
{
lwc_string **families;
@@ -144,7 +146,7 @@ void font_plot_style_from_css(const css_computed_style *css,
css_computed_font_family(css, &families));
css_computed_font_size(css, &length, &unit);
- fstyle->size = FIXTOINT(FMUL(nscss_len2pt(length, unit),
+ fstyle->size = FIXTOINT(FMUL(nscss_len2pt(len_ctx, length, unit),
INTTOFIX(FONT_SIZE_SCALE)));
/* Clamp font size to configured minimum */
diff --git a/render/font.h b/render/font.h
index fba368a97..52f5a62c2 100644
--- a/render/font.h
+++ b/render/font.h
@@ -32,10 +32,13 @@ struct plot_font_style;
/**
* Populate a font style using data from a computed CSS style
*
- * \param css Computed style to consider
- * \param fstyle Font style to populate
+ * \param len_ctx Length conversion context
+ * \param css Computed style to consider
+ * \param fstyle Font style to populate
*/
-void font_plot_style_from_css(const css_computed_style *css,
- struct plot_font_style *fstyle);
+void font_plot_style_from_css(
+ const nscss_len_ctx *len_ctx,
+ const css_computed_style *css,
+ struct plot_font_style *fstyle);
#endif
diff --git a/render/form.c b/render/form.c
index 904272d3a..432002564 100644
--- a/render/form.c
+++ b/render/form.c
@@ -1133,6 +1133,7 @@ bool form_open_select_menu(void *client_data,
plot_font_style_t fstyle;
int total_height;
struct form_select_menu *menu;
+ html_content *html = (html_content *)c;
/* if the menu is opened for the first time */
@@ -1153,7 +1154,7 @@ bool form_open_select_menu(void *client_data,
box->border[LEFT].width +
box->padding[RIGHT] + box->padding[LEFT];
- font_plot_style_from_css(control->box->style,
+ font_plot_style_from_css(&html->len_ctx, control->box->style,
&fstyle);
menu->f_size = fstyle.size;
diff --git a/render/html.c b/render/html.c
index 3cfc5e236..b7d7aa313 100644
--- a/render/html.c
+++ b/render/html.c
@@ -1398,6 +1398,10 @@ static void html_reformat(struct content *c, int width, int height)
htmlc->reflowing = true;
+ htmlc->len_ctx.vw = width;
+ htmlc->len_ctx.vh = height;
+ htmlc->len_ctx.root_style = htmlc->layout->style;
+
layout_document(htmlc, width, height);
layout = htmlc->layout;
@@ -1647,7 +1651,7 @@ html_open(struct content *c,
html->drag_owner.no_owner = true;
/* text selection */
- selection_init(&html->sel, html->layout);
+ selection_init(&html->sel, html->layout, &html->len_ctx);
html->selection_type = HTML_SELECTION_NONE;
html->selection_owner.none = true;
@@ -1768,7 +1772,8 @@ html_get_contextual_content(struct content *c, int x, int y,
struct box *next;
int box_x = 0, box_y = 0;
- while ((next = box_at_point(box, x, y, &box_x, &box_y)) != NULL) {
+ while ((next = box_at_point(&html->len_ctx, box, x, y,
+ &box_x, &box_y)) != NULL) {
box = next;
/* hidden boxes are ignored */
@@ -1845,7 +1850,8 @@ html_scroll_at_point(struct content *c, int x, int y, int scrx, int scry)
/* TODO: invert order; visit deepest box first */
- while ((next = box_at_point(box, x, y, &box_x, &box_y)) != NULL) {
+ while ((next = box_at_point(&html->len_ctx, box, x, y,
+ &box_x, &box_y)) != NULL) {
box = next;
if (box->style && css_computed_visibility(box->style) ==
@@ -1987,7 +1993,8 @@ static bool html_drop_file_at_point(struct content *c, int x, int y, char *file)
int box_x = 0, box_y = 0;
/* Scan box tree for boxes that can handle drop */
- while ((next = box_at_point(box, x, y, &box_x, &box_y)) != NULL) {
+ while ((next = box_at_point(&html->len_ctx, box, x, y,
+ &box_x, &box_y)) != NULL) {
box = next;
if (box->style && css_computed_visibility(box->style) ==
diff --git a/render/html_interaction.c b/render/html_interaction.c
index 30adaa080..2d14ed2ae 100644
--- a/render/html_interaction.c
+++ b/render/html_interaction.c
@@ -208,7 +208,7 @@ static size_t html_selection_drag_end(struct html_content *html,
if (box) {
plot_font_style_t fstyle;
- font_plot_style_from_css(box->style, &fstyle);
+ font_plot_style_from_css(&html->len_ctx, box->style, &fstyle);
guit->layout->position(&fstyle, box->text, box->length,
dx, &idx, &pixel_offset);
@@ -415,7 +415,8 @@ void html_mouse_action(struct content *c, struct browser_window *bw,
size_t idx;
plot_font_style_t fstyle;
- font_plot_style_from_css(box->style, &fstyle);
+ font_plot_style_from_css(&html->len_ctx,
+ box->style, &fstyle);
guit->layout->position(&fstyle,
box->text, box->length,
@@ -649,7 +650,8 @@ void html_mouse_action(struct content *c, struct browser_window *bw,
text_box = box;
text_box_x = box_x;
}
- } while ((box = box_at_point(box, x, y, &box_x, &box_y)) != NULL);
+ } while ((box = box_at_point(&html->len_ctx, box, x, y,
+ &box_x, &box_y)) != NULL);
/* use of box_x, box_y, or content below this point is probably a
* mistake; they will refer to the last box returned by box_at_point */
@@ -910,8 +912,8 @@ void html_mouse_action(struct content *c, struct browser_window *bw,
int pixel_offset;
size_t idx;
- font_plot_style_from_css(text_box->style,
- &fstyle);
+ font_plot_style_from_css(&html->len_ctx,
+ text_box->style, &fstyle);
guit->layout->position(&fstyle,
text_box->text,
diff --git a/render/html_internal.h b/render/html_internal.h
index 2f84cf869..66ecb2b36 100644
--- a/render/html_internal.h
+++ b/render/html_internal.h
@@ -26,6 +26,7 @@
#include <libcss/libcss.h>
+#include "content/handlers/css/utils.h"
#include "content/content_protected.h"
#include "desktop/selection.h"
#include "render/html.h"
@@ -94,6 +95,9 @@ typedef struct html_content {
/** Base target */
char *base_target;
+ /** CSS length conversion context for document. */
+ nscss_len_ctx len_ctx;
+
/** Content has been aborted in the LOADING state */
bool aborted;
diff --git a/render/html_object.c b/render/html_object.c
index e98bdba0b..fb9e7b090 100644
--- a/render/html_object.c
+++ b/render/html_object.c
@@ -227,7 +227,8 @@ html_object_callback(hlcache_handle *object,
if (hunit == CSS_UNIT_PCT) {
l = (width - w) * hpos / INTTOFIX(100);
} else {
- l = FIXTOINT(nscss_len2px(hpos, hunit,
+ l = FIXTOINT(nscss_len2px(&c->len_ctx,
+ hpos, hunit,
box->style));
}
@@ -235,7 +236,8 @@ html_object_callback(hlcache_handle *object,
if (vunit == CSS_UNIT_PCT) {
t = (height - h) * vpos / INTTOFIX(100);
} else {
- t = FIXTOINT(nscss_len2px(vpos, vunit,
+ t = FIXTOINT(nscss_len2px(&c->len_ctx,
+ vpos, vunit,
box->style));
}
diff --git a/render/html_redraw.c b/render/html_redraw.c
index 2f8730634..9a97e5ec5 100644
--- a/render/html_redraw.c
+++ b/render/html_redraw.c
@@ -521,12 +521,14 @@ static bool html_redraw_radio(int x, int y, int width, int height,
* \param box box of input
* \param scale scale for redraw
* \param background_colour current background colour
+ * \param len_ctx Length conversion context
* \param ctx current redraw context
* \return true if successful, false otherwise
*/
static bool html_redraw_file(int x, int y, int width, int height,
struct box *box, float scale, colour background_colour,
+ const nscss_len_ctx *len_ctx,
const struct redraw_context *ctx)
{
int text_width;
@@ -535,7 +537,7 @@ static bool html_redraw_file(int x, int y, int width, int height,
plot_font_style_t fstyle;
nserror res;
- font_plot_style_from_css(box->style, &fstyle);
+ font_plot_style_from_css(len_ctx, box->style, &fstyle);
fstyle.background = background_colour;
if (box->gadget->value) {
@@ -578,13 +580,16 @@ static bool html_redraw_file(int x, int y, int width, int height,
* \param clip current clip rectangle
* \param background_colour current background colour
* \param background box containing background details (usually \a box)
- * \param ctx current redraw context
+ * \param len_ctx Length conversion context
+ * \param ctx current redraw context
* \return true if successful, false otherwise
*/
static bool html_redraw_background(int x, int y, struct box *box, float scale,
const struct rect *clip, colour *background_colour,
- struct box *background, const struct redraw_context *ctx)
+ struct box *background,
+ const nscss_len_ctx *len_ctx,
+ const struct redraw_context *ctx)
{
bool repeat_x = false;
bool repeat_y = false;
@@ -660,7 +665,7 @@ static bool html_redraw_background(int x, int y, struct box *box, float scale,
content_get_width(background->background)) *
scale * FIXTOFLT(hpos) / 100.;
} else {
- x += (int) (FIXTOFLT(nscss_len2px(hpos, hunit,
+ x += (int) (FIXTOFLT(nscss_len2px(len_ctx, hpos, hunit,
background->style)) * scale);
}
@@ -669,7 +674,7 @@ static bool html_redraw_background(int x, int y, struct box *box, float scale,
content_get_height(background->background)) *
scale * FIXTOFLT(vpos) / 100.;
} else {
- y += (int) (FIXTOFLT(nscss_len2px(vpos, vunit,
+ y += (int) (FIXTOFLT(nscss_len2px(len_ctx, vpos, vunit,
background->style)) * scale);
}
}
@@ -802,13 +807,15 @@ static bool html_redraw_background(int x, int y, struct box *box, float scale,
* \param first true if this is the first rectangle associated with the inline
* \param last true if this is the last rectangle associated with the inline
* \param background_colour updated to current background colour if plotted
- * \param ctx current redraw context
+ * \param len_ctx Length conversion context
+ * \param ctx current redraw context
* \return true if successful, false otherwise
*/
static bool html_redraw_inline_background(int x, int y, struct box *box,
float scale, const struct rect *clip, struct rect b,
bool first, bool last, colour *background_colour,
+ const nscss_len_ctx *len_ctx,
const struct redraw_context *ctx)
{
struct rect r = *clip;
@@ -869,7 +876,7 @@ static bool html_redraw_inline_background(int x, int y, struct box *box,
plot_content = false;
}
} else {
- x += (int) (FIXTOFLT(nscss_len2px(hpos, hunit,
+ x += (int) (FIXTOFLT(nscss_len2px(len_ctx, hpos, hunit,
box->style)) * scale);
}
@@ -878,7 +885,7 @@ static bool html_redraw_inline_background(int x, int y, struct box *box,
content_get_height(box->background) *
scale) * FIXTOFLT(vpos) / 100.;
} else {
- y += (int) (FIXTOFLT(nscss_len2px(vpos, vunit,
+ y += (int) (FIXTOFLT(nscss_len2px(len_ctx, vpos, vunit,
box->style)) * scale);
}
}
@@ -1120,7 +1127,7 @@ static bool html_redraw_text_box(const html_content *html, struct box *box,
bool excluded = (box->object != NULL);
plot_font_style_t fstyle;
- font_plot_style_from_css(box->style, &fstyle);
+ font_plot_style_from_css(&html->len_ctx, box->style, &fstyle);
fstyle.background = current_background_color;
if (!text_redraw(box->text, box->length, box->byte_offset,
@@ -1382,21 +1389,25 @@ bool html_redraw_box(const html_content *html, struct box *box,
/* We have an absolutly positioned box with a clip rect */
if (css_rect.left_auto == false)
r.x0 = x - border_left + FIXTOINT(nscss_len2px(
+ &html->len_ctx,
css_rect.left, css_rect.lunit,
box->style));
if (css_rect.top_auto == false)
r.y0 = y - border_top + FIXTOINT(nscss_len2px(
+ &html->len_ctx,
css_rect.top, css_rect.tunit,
box->style));
if (css_rect.right_auto == false)
r.x1 = x - border_left + FIXTOINT(nscss_len2px(
+ &html->len_ctx,
css_rect.right, css_rect.runit,
box->style));
if (css_rect.bottom_auto == false)
r.y1 = y - border_top + FIXTOINT(nscss_len2px(
+ &html->len_ctx,
css_rect.bottom, css_rect.bunit,
box->style));
@@ -1486,7 +1497,8 @@ bool html_redraw_box(const html_content *html, struct box *box,
if ((p.x0 < p.x1) && (p.y0 < p.y1)) {
/* plot background */
if (!html_redraw_background(x, y, box, scale, &p,
- &current_background_color, bg_box, ctx))
+ &current_background_color, bg_box,
+ &html->len_ctx, ctx))
return false;
/* restore previous graphics window */
if (ctx->plot->clip(ctx, &r) != NSERROR_OK)
@@ -1565,7 +1577,8 @@ bool html_redraw_box(const html_content *html, struct box *box,
if (!html_redraw_inline_background(
x, y, box, scale, &p, b,
first, false,
- &current_background_color, ctx))
+ &current_background_color,
+ &html->len_ctx, ctx))
return false;
/* restore previous graphics window */
if (ctx->plot->clip(ctx, &r) != NSERROR_OK)
@@ -1597,7 +1610,8 @@ bool html_redraw_box(const html_content *html, struct box *box,
/* plot background and borders for last rectangle of
* the inline */
if (!html_redraw_inline_background(x, ib_y, box, scale, &p, b,
- first, true, &current_background_color, ctx))
+ first, true, &current_background_color,
+ &html->len_ctx, ctx))
return false;
/* restore previous graphics window */
if (ctx->plot->clip(ctx, &r) != NSERROR_OK)
@@ -1768,7 +1782,6 @@ bool html_redraw_box(const html_content *html, struct box *box,
obj, sizeof(obj) - 1) != NSERROR_OK)
return false;
}
-
} else if (box->iframe) {
/* Offset is passed to browser window redraw unscaled */
@@ -1789,7 +1802,7 @@ bool html_redraw_box(const html_content *html, struct box *box,
} else if (box->gadget && box->gadget->type == GADGET_FILE) {
if (!html_redraw_file(x + padding_left, y + padding_top,
width, height, box, scale,
- current_background_color, ctx))
+ current_background_color, &html->len_ctx, ctx))
return false;
} else if (box->gadget &&
diff --git a/render/layout.c b/render/layout.c
index 7ca688fab..15eb1e846 100644
--- a/render/layout.c
+++ b/render/layout.c
@@ -69,8 +69,14 @@
#define FPCT_OF_INT_TOINT(a, b) (FIXTOINT(FDIV((a * b), F_100)))
/* forward declaration to break cycles */
-static bool layout_block_context(struct box *block, int viewport_height, html_content *content);
-static void layout_minmax_block(struct box *block, const struct gui_layout_table *font_func);
+static bool layout_block_context(
+ struct box *block,
+ int viewport_height,
+ html_content *content);
+static void layout_minmax_block(
+ struct box *block,
+ const struct gui_layout_table *font_func,
+ const html_content *content);
/**
@@ -179,7 +185,9 @@ layout_get_object_dimensions(struct box *box,
* \param width width of containing block
* \return length of indent
*/
-static int layout_text_indent(const css_computed_style *style, int width)
+static int layout_text_indent(
+ const nscss_len_ctx *len_ctx,
+ const css_computed_style *style, int width)
{
css_fixed value = 0;
css_unit unit = CSS_UNIT_PX;
@@ -189,7 +197,7 @@ static int layout_text_indent(const css_computed_style *style, int width)
if (unit == CSS_UNIT_PCT) {
return FPCT_OF_INT_TOINT(value, width);
} else {
- return FIXTOINT(nscss_len2px(value, unit, style));
+ return FIXTOINT(nscss_len2px(len_ctx, value, unit, style));
}
}
@@ -197,6 +205,7 @@ static int layout_text_indent(const css_computed_style *style, int width)
/**
* Determine width of margin, borders, and padding on one side of a box.
*
+ * \param len_ctx CSS length conversion context for document
* \param style style to measure
* \param side side of box to measure
* \param margin whether margin width is required
@@ -206,7 +215,8 @@ static int layout_text_indent(const css_computed_style *style, int width)
* \param frac increased by sum of fractional margin and padding
*/
static void
-calculate_mbp_width(const css_computed_style *style,
+calculate_mbp_width(const nscss_len_ctx *len_ctx,
+ const css_computed_style *style,
unsigned int side,
bool margin,
bool border,
@@ -217,19 +227,19 @@ calculate_mbp_width(const css_computed_style *style,
typedef uint8_t (*len_func)(const css_computed_style *style,
css_fixed *length, css_unit *unit);
- static len_func margin_funcs[4] = {
+ static const len_func margin_funcs[4] = {
css_computed_margin_top,
css_computed_margin_right,
css_computed_margin_bottom,
css_computed_margin_left
};
- static len_func padding_funcs[4] = {
+ static const len_func padding_funcs[4] = {
css_computed_padding_top,
css_computed_padding_right,
css_computed_padding_bottom,
css_computed_padding_left
};
- static struct {
+ static const struct {
len_func width;
uint8_t (*style)(const css_computed_style *style);
} border_funcs[4] = {
@@ -257,8 +267,8 @@ calculate_mbp_width(const css_computed_style *style,
if (unit == CSS_UNIT_PCT) {
*frac += FIXTOINT(FDIV(value, F_100));
} else {
- *fixed += FIXTOINT(nscss_len2px(value, unit,
- style));
+ *fixed += FIXTOINT(nscss_len2px(len_ctx,
+ value, unit, style));
}
}
}
@@ -269,7 +279,8 @@ calculate_mbp_width(const css_computed_style *style,
CSS_BORDER_STYLE_NONE) {
border_funcs[side].width(style, &value, &unit);
- *fixed += FIXTOINT(nscss_len2px(value, unit, style));
+ *fixed += FIXTOINT(nscss_len2px(len_ctx,
+ value, unit, style));
}
}
@@ -279,13 +290,201 @@ calculate_mbp_width(const css_computed_style *style,
if (unit == CSS_UNIT_PCT) {
*frac += FIXTOINT(FDIV(value, F_100));
} else {
- *fixed += FIXTOINT(nscss_len2px(value, unit, style));
+ *fixed += FIXTOINT(nscss_len2px(len_ctx,
+ value, unit, style));
}
}
}
/**
+ * Calculate minimum and maximum width of a table.
+ *
+ * \param table box of type TABLE
+ * \param font_func Font functions
+ * \param content The HTML content we are laying out.
+ * \post table->min_width and table->max_width filled in,
+ * 0 <= table->min_width <= table->max_width
+ */
+static void layout_minmax_table(struct box *table,
+ const struct gui_layout_table *font_func,
+ const html_content *content)
+{
+ 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;
+ struct box *row_group, *row, *cell;
+ enum css_width_e wtype;
+ css_fixed value = 0;
+ css_unit unit = CSS_UNIT_PX;
+
+ /* check if the widths have already been calculated */
+ if (table->max_width != UNKNOWN_MAX_WIDTH)
+ return;
+
+ if (table_calculate_column_types(&content->len_ctx, table) == false) {
+ NSLOG(netsurf, WARNING,
+ "Could not establish table column types.");
+ return;
+ }
+ col = table->col;
+
+ /* start with 0 except for fixed-width columns */
+ for (i = 0; i != table->columns; i++) {
+ if (col[i].type == COLUMN_WIDTH_FIXED)
+ col[i].min = col[i].max = col[i].width;
+ else
+ col[i].min = col[i].max = 0;
+ }
+
+ /* border-spacing is used in the separated borders model */
+ if (css_computed_border_collapse(table->style) ==
+ CSS_BORDER_COLLAPSE_SEPARATE) {
+ css_fixed h = 0, v = 0;
+ css_unit hu = CSS_UNIT_PX, vu = CSS_UNIT_PX;
+
+ css_computed_border_spacing(table->style, &h, &hu, &v, &vu);
+
+ border_spacing_h = FIXTOINT(nscss_len2px(&content->len_ctx,
+ h, hu, table->style));
+ }
+
+ /* 1st pass: consider cells with colspan 1 only */
+ 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);
+ /** TODO: Handle colspan="0" correctly.
+ * It's currently converted to 1 in box normaisation */
+ assert(cell->columns != 0);
+
+ if (cell->columns != 1)
+ continue;
+
+ layout_minmax_block(cell, font_func, content);
+ i = cell->start_column;
+
+ if (col[i].positioned)
+ continue;
+
+ /* 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, extra;
+
+ if (cell->columns == 1)
+ continue;
+
+ layout_minmax_block(cell, font_func, content);
+ i = cell->start_column;
+
+ /* 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;
+
+ /* 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;
+ }
+ } 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;
+ }
+ }
+ }
+ }
+
+ /* 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;
+ }
+ }
+
+ for (i = 0; i != table->columns; i++) {
+ if (col[i].max < col[i].min) {
+ box_dump(stderr, table, 0, true);
+ assert(0);
+ }
+ table_min += col[i].min;
+ table_max += col[i].max;
+ }
+
+ /* fixed width takes priority, unless it is too narrow */
+ wtype = css_computed_width(table->style, &value, &unit);
+ if (wtype == CSS_WIDTH_SET && unit != CSS_UNIT_PCT) {
+ int width = FIXTOINT(nscss_len2px(&content->len_ctx,
+ value, unit, table->style));
+ if (table_min < width)
+ table_min = width;
+ if (table_max < width)
+ table_max = width;
+ }
+
+ /* add margins, border, padding to min, max widths */
+ calculate_mbp_width(&content->len_ctx,
+ table->style, LEFT, true, true, true,
+ &extra_fixed, &extra_frac);
+ calculate_mbp_width(&content->len_ctx,
+ table->style, RIGHT, true, true, true,
+ &extra_fixed, &extra_frac);
+ if (extra_fixed < 0)
+ extra_fixed = 0;
+ if (extra_frac < 0)
+ extra_frac = 0;
+ 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;
+
+ assert(0 <= table->min_width && table->min_width <= table->max_width);
+}
+
+
+/**
* Calculate minimum and maximum width of a line.
*
* \param first a box in an inline container
@@ -303,7 +502,8 @@ layout_minmax_line(struct box *first,
int *line_max,
bool first_line,
bool *line_has_height,
- const struct gui_layout_table *font_func)
+ const struct gui_layout_table *font_func,
+ const html_content *content)
{
int min = 0, max = 0, width, height, fixed;
float frac;
@@ -349,9 +549,11 @@ layout_minmax_line(struct box *first,
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, font_func);
+ layout_minmax_block(b->children, font_func,
+ content);
else
- layout_minmax_table(b->children, font_func);
+ layout_minmax_table(b->children, font_func,
+ content);
b->min_width = b->children->min_width;
b->max_width = b->children->max_width;
if (min < b->min_width)
@@ -361,7 +563,7 @@ layout_minmax_line(struct box *first,
}
if (b->type == BOX_INLINE_BLOCK) {
- layout_minmax_block(b, font_func);
+ layout_minmax_block(b, font_func, content);
if (min < b->min_width)
min = b->min_width;
max += b->max_width;
@@ -372,16 +574,18 @@ layout_minmax_line(struct box *first,
}
assert(b->style);
- font_plot_style_from_css(b->style, &fstyle);
+ font_plot_style_from_css(&content->len_ctx, b->style, &fstyle);
if (b->type == BOX_INLINE && !b->object &&
!(b->flags & REPLACE_DIM) &&
!(b->flags & IFRAME)) {
fixed = frac = 0;
- calculate_mbp_width(b->style, LEFT, true, true, true,
+ calculate_mbp_width(&content->len_ctx,
+ b->style, LEFT, true, true, true,
&fixed, &frac);
if (!b->inline_end)
- calculate_mbp_width(b->style, RIGHT,
+ calculate_mbp_width(&content->len_ctx,
+ b->style, RIGHT,
true, true, true,
&fixed, &frac);
if (0 < fixed)
@@ -390,7 +594,8 @@ layout_minmax_line(struct box *first,
/* \todo update min width, consider fractional extra */
} else if (b->type == BOX_INLINE_END) {
fixed = frac = 0;
- calculate_mbp_width(b->inline_end->style, RIGHT,
+ calculate_mbp_width(&content->len_ctx,
+ b->inline_end->style, RIGHT,
true, true, true,
&fixed, &frac);
if (0 < fixed)
@@ -511,15 +716,17 @@ layout_minmax_line(struct box *first,
width = AUTO;
} else {
- width = FIXTOINT(nscss_len2px(value, unit,
- b->style));
+ width = FIXTOINT(nscss_len2px(&content->len_ctx,
+ value, unit, b->style));
if (bs == CSS_BOX_SIZING_BORDER_BOX) {
fixed = frac = 0;
- calculate_mbp_width(block->style, LEFT,
+ calculate_mbp_width(&content->len_ctx,
+ block->style, LEFT,
false, true, true,
&fixed, &frac);
- calculate_mbp_width(block->style, RIGHT,
+ calculate_mbp_width(&content->len_ctx,
+ block->style, RIGHT,
false, true, true,
&fixed, &frac);
if (width < fixed) {
@@ -536,7 +743,8 @@ layout_minmax_line(struct box *first,
/* height */
htype = css_computed_height(b->style, &value, &unit);
if (htype == CSS_HEIGHT_SET) {
- height = FIXTOINT(nscss_len2px(value, unit, b->style));
+ height = FIXTOINT(nscss_len2px(&content->len_ctx,
+ value, unit, b->style));
} else {
height = AUTO;
}
@@ -552,17 +760,21 @@ layout_minmax_line(struct box *first,
fixed = frac = 0;
if (bs == CSS_BOX_SIZING_BORDER_BOX) {
- calculate_mbp_width(b->style, LEFT,
+ calculate_mbp_width(&content->len_ctx,
+ b->style, LEFT,
true, false, false,
&fixed, &frac);
- calculate_mbp_width(b->style, RIGHT,
+ calculate_mbp_width(&content->len_ctx,
+ b->style, RIGHT,
true, false, false,
&fixed, &frac);
} else {
- calculate_mbp_width(b->style, LEFT,
+ calculate_mbp_width(&content->len_ctx,
+ b->style, LEFT,
true, true, true,
&fixed, &frac);
- calculate_mbp_width(b->style, RIGHT,
+ calculate_mbp_width(&content->len_ctx,
+ b->style, RIGHT,
true, true, true,
&fixed, &frac);
}
@@ -575,17 +787,21 @@ layout_minmax_line(struct box *first,
fixed = frac = 0;
if (bs == CSS_BOX_SIZING_BORDER_BOX) {
- calculate_mbp_width(b->style, LEFT,
+ calculate_mbp_width(&content->len_ctx,
+ b->style, LEFT,
true, false, false,
&fixed, &frac);
- calculate_mbp_width(b->style, RIGHT,
+ calculate_mbp_width(&content->len_ctx,
+ b->style, RIGHT,
true, false, false,
&fixed, &frac);
} else {
- calculate_mbp_width(b->style, LEFT,
+ calculate_mbp_width(&content->len_ctx,
+ b->style, LEFT,
true, true, true,
&fixed, &frac);
- calculate_mbp_width(b->style, RIGHT,
+ calculate_mbp_width(&content->len_ctx,
+ b->style, RIGHT,
true, true, true,
&fixed, &frac);
}
@@ -596,8 +812,10 @@ layout_minmax_line(struct box *first,
} else {
/* form control with no object */
if (width == AUTO)
- width = FIXTOINT(nscss_len2px(INTTOFIX(1),
- CSS_UNIT_EM, b->style));
+ width = FIXTOINT(nscss_len2px(
+ &content->len_ctx,
+ INTTOFIX(1), CSS_UNIT_EM,
+ b->style));
}
if (min < width)
@@ -610,7 +828,7 @@ layout_minmax_line(struct box *first,
if (first_line) {
/* todo: handle percentage values properly */
/* todo: handle text-indent interaction with floats */
- int text_indent = layout_text_indent(
+ int text_indent = layout_text_indent(&content->len_ctx,
first->parent->parent->style, 100);
min = (min + text_indent < 0) ? 0 : min + text_indent;
max = (max + text_indent < 0) ? 0 : max + text_indent;
@@ -640,7 +858,8 @@ layout_minmax_line(struct box *first,
static void
layout_minmax_inline_container(struct box *inline_container,
bool *has_height,
- const struct gui_layout_table *font_func)
+ const struct gui_layout_table *font_func,
+ const html_content *content)
{
struct box *child;
int line_min = 0, line_max = 0;
@@ -658,7 +877,8 @@ layout_minmax_inline_container(struct box *inline_container,
for (child = inline_container->children; child; ) {
child = layout_minmax_line(child, &line_min, &line_max,
- first_line, &line_has_height, font_func);
+ first_line, &line_has_height, font_func,
+ content);
if (min < line_min)
min = line_min;
if (max < line_max)
@@ -681,11 +901,14 @@ layout_minmax_inline_container(struct box *inline_container,
*
* \param block box of type BLOCK, INLINE_BLOCK, or TABLE_CELL
* \param font_func font functions
+ * \param content The HTML content being layed out.
* \post block->min_width and block->max_width filled in,
* 0 <= block->min_width <= block->max_width
*/
-static void
-layout_minmax_block(struct box *block, const struct gui_layout_table *font_func)
+static void layout_minmax_block(
+ struct box *block,
+ const struct gui_layout_table *font_func,
+ const html_content *content)
{
struct box *child;
int min = 0, max = 0;
@@ -738,7 +961,8 @@ layout_minmax_block(struct box *block, const struct gui_layout_table *font_func)
css_fixed size = INTTOFIX(10);
css_unit unit = CSS_UNIT_EM;
- min = max = FIXTOINT(nscss_len2px(size, unit, block->style));
+ min = max = FIXTOINT(nscss_len2px(&content->len_ctx,
+ size, unit, block->style));
block->flags |= HAS_HEIGHT;
}
@@ -751,7 +975,8 @@ layout_minmax_block(struct box *block, const struct gui_layout_table *font_func)
/* form checkbox or radio button
* if width is AUTO, set it to 1em */
- min = max = FIXTOINT(nscss_len2px(size, unit, block->style));
+ min = max = FIXTOINT(nscss_len2px(&content->len_ctx,
+ size, unit, block->style));
block->flags |= HAS_HEIGHT;
}
@@ -759,7 +984,7 @@ layout_minmax_block(struct box *block, const struct gui_layout_table *font_func)
if (block->object) {
if (content_get_type(block->object) == CONTENT_HTML) {
layout_minmax_block(html_get_box_tree(block->object),
- font_func);
+ font_func, content);
min = html_get_box_tree(block->object)->min_width;
max = html_get_box_tree(block->object)->max_width;
} else {
@@ -776,7 +1001,8 @@ layout_minmax_block(struct box *block, const struct gui_layout_table *font_func)
for (child = block->children; child; child = child->next) {
switch (child->type) {
case BOX_BLOCK:
- layout_minmax_block(child, font_func);
+ layout_minmax_block(child, font_func,
+ content);
if (child->flags & HAS_HEIGHT)
child_has_height = true;
break;
@@ -785,7 +1011,8 @@ layout_minmax_block(struct box *block, const struct gui_layout_table *font_func)
child->flags |= NEED_MIN;
layout_minmax_inline_container(child,
- &child_has_height, font_func);
+ &child_has_height, font_func,
+ content);
if (child_has_height &&
child ==
child->parent->children) {
@@ -793,7 +1020,8 @@ layout_minmax_block(struct box *block, const struct gui_layout_table *font_func)
}
break;
case BOX_TABLE:
- layout_minmax_table(child, font_func);
+ layout_minmax_table(child, font_func,
+ content);
/* todo: fix for zero height tables */
child_has_height = true;
child->flags |= MAKE_HEIGHT;
@@ -831,14 +1059,17 @@ layout_minmax_block(struct box *block, const struct gui_layout_table *font_func)
/* fixed width takes priority */
if (block->type != BOX_TABLE_CELL && wtype == CSS_WIDTH_SET &&
wunit != CSS_UNIT_PCT) {
- min = max = FIXTOINT(nscss_len2px(width, wunit, block->style));
+ min = max = FIXTOINT(nscss_len2px(&content->len_ctx,
+ width, wunit, block->style));
if (bs == CSS_BOX_SIZING_BORDER_BOX) {
int border_box_fixed = 0;
float border_box_frac = 0;
- calculate_mbp_width(block->style, LEFT,
+ calculate_mbp_width(&content->len_ctx,
+ block->style, LEFT,
false, true, true,
&border_box_fixed, &border_box_frac);
- calculate_mbp_width(block->style, RIGHT,
+ calculate_mbp_width(&content->len_ctx,
+ block->style, RIGHT,
false, true, true,
&border_box_fixed, &border_box_frac);
if (min < border_box_fixed) {
@@ -858,14 +1089,18 @@ layout_minmax_block(struct box *block, const struct gui_layout_table *font_func)
* and paddings are wrong. */
if (bs == CSS_BOX_SIZING_BORDER_BOX && wtype == CSS_WIDTH_SET) {
/* Border and padding included in width, so just get margin */
- calculate_mbp_width(block->style, LEFT, true, false, false,
+ calculate_mbp_width(&content->len_ctx,
+ block->style, LEFT, true, false, false,
&extra_fixed, &extra_frac);
- calculate_mbp_width(block->style, RIGHT, true, false, false,
+ calculate_mbp_width(&content->len_ctx,
+ block->style, RIGHT, true, false, false,
&extra_fixed, &extra_frac);
} else {
- calculate_mbp_width(block->style, LEFT, true, true, true,
+ calculate_mbp_width(&content->len_ctx,
+ block->style, LEFT, true, true, true,
&extra_fixed, &extra_frac);
- calculate_mbp_width(block->style, RIGHT, true, true, true,
+ calculate_mbp_width(&content->len_ctx,
+ block->style, RIGHT, true, true, true,
&extra_fixed, &extra_frac);
}
if (extra_fixed < 0)
@@ -895,6 +1130,7 @@ layout_minmax_block(struct box *block, const struct gui_layout_table *font_func)
*
* This turns the specified dimension into a content-box dimension.
*
+ * \param len_ctx Length conversion context
* \param box gadget to adjust dimensions of
* \param available_width width of containing block
* \param setwidth set true if the dimension to be tweaked is a width,
@@ -904,6 +1140,7 @@ layout_minmax_block(struct box *block, const struct gui_layout_table *font_func)
* gadget properties.
*/
static void layout_handle_box_sizing(
+ const nscss_len_ctx *len_ctx,
struct box *box,
int available_width,
bool setwidth,
@@ -920,9 +1157,11 @@ static void layout_handle_box_sizing(
int fixed = 0;
float frac = 0;
- calculate_mbp_width(box->style, setwidth ? LEFT : TOP,
+ calculate_mbp_width(len_ctx, box->style,
+ setwidth ? LEFT : TOP,
false, true, true, &fixed, &frac);
- calculate_mbp_width(box->style, setwidth ? RIGHT : BOTTOM,
+ calculate_mbp_width(len_ctx, box->style,
+ setwidth ? RIGHT : BOTTOM,
false, true, true, &fixed, &frac);
orig -= frac * available_width + fixed;
*dimension = orig > 0 ? orig : 0;
@@ -933,6 +1172,7 @@ static void layout_handle_box_sizing(
/**
* Calculate width, height, and thickness of margins, paddings, and borders.
*
+ * \param len_ctx Length conversion context
* \param available_width width of containing block
* \param viewport_height height of viewport in pixels or -ve if unknown
* \param box current box
@@ -949,7 +1189,8 @@ static void layout_handle_box_sizing(
* \param border filled with border widths, may be NULL
*/
static void
-layout_find_dimensions(int available_width,
+layout_find_dimensions(const nscss_len_ctx *len_ctx,
+ int available_width,
int viewport_height,
struct box *box,
const css_computed_style *style,
@@ -978,15 +1219,15 @@ layout_find_dimensions(int available_width,
*width = FPCT_OF_INT_TOINT(
value, available_width);
} else {
- *width = FIXTOINT(nscss_len2px(value, unit,
- style));
+ *width = FIXTOINT(nscss_len2px(len_ctx,
+ value, unit, style));
}
} else {
*width = AUTO;
}
if (*width != AUTO) {
- layout_handle_box_sizing(box, available_width,
+ layout_handle_box_sizing(len_ctx, box, available_width,
true, width);
}
}
@@ -1066,15 +1307,15 @@ layout_find_dimensions(int available_width,
*height = AUTO;
}
} else {
- *height = FIXTOINT(nscss_len2px(value, unit,
- style));
+ *height = FIXTOINT(nscss_len2px(len_ctx,
+ value, unit, style));
}
} else {
*height = AUTO;
}
if (*height != AUTO) {
- layout_handle_box_sizing(box, available_width,
+ layout_handle_box_sizing(len_ctx, box, available_width,
false, height);
}
}
@@ -1091,8 +1332,8 @@ layout_find_dimensions(int available_width,
*max_width = FPCT_OF_INT_TOINT(value,
available_width);
} else {
- *max_width = FIXTOINT(nscss_len2px(value, unit,
- style));
+ *max_width = FIXTOINT(nscss_len2px(len_ctx,
+ value, unit, style));
}
} else {
/* Inadmissible */
@@ -1100,7 +1341,7 @@ layout_find_dimensions(int available_width,
}
if (*max_width != -1) {
- layout_handle_box_sizing(box, available_width,
+ layout_handle_box_sizing(len_ctx, box, available_width,
true, max_width);
}
}
@@ -1117,8 +1358,8 @@ layout_find_dimensions(int available_width,
*min_width = FPCT_OF_INT_TOINT(value,
available_width);
} else {
- *min_width = FIXTOINT(nscss_len2px(value, unit,
- style));
+ *min_width = FIXTOINT(nscss_len2px(len_ctx,
+ value, unit, style));
}
} else {
/* Inadmissible */
@@ -1126,7 +1367,7 @@ layout_find_dimensions(int available_width,
}
if (*min_width != 0) {
- layout_handle_box_sizing(box, available_width,
+ layout_handle_box_sizing(len_ctx, box, available_width,
true, min_width);
}
}
@@ -1143,8 +1384,8 @@ layout_find_dimensions(int available_width,
/* TODO: handle percentage */
*max_height = -1;
} else {
- *max_height = FIXTOINT(nscss_len2px(value, unit,
- style));
+ *max_height = FIXTOINT(nscss_len2px(len_ctx,
+ value, unit, style));
}
} else {
/* Inadmissible */
@@ -1164,8 +1405,8 @@ layout_find_dimensions(int available_width,
/* TODO: handle percentage */
*min_height = 0;
} else {
- *min_height = FIXTOINT(nscss_len2px(value, unit,
- style));
+ *min_height = FIXTOINT(nscss_len2px(len_ctx,
+ value, unit, style));
}
} else {
/* Inadmissible */
@@ -1203,8 +1444,9 @@ layout_find_dimensions(int available_width,
margin[i] = FPCT_OF_INT_TOINT(value,
available_width);
} else {
- margin[i] = FIXTOINT(nscss_len2px(value,
- unit, style));
+ margin[i] = FIXTOINT(nscss_len2px(
+ len_ctx,
+ value, unit, style));
}
} else {
margin[i] = AUTO;
@@ -1236,8 +1478,8 @@ layout_find_dimensions(int available_width,
padding[i] = FPCT_OF_INT_TOINT(value,
available_width);
} else {
- padding[i] = FIXTOINT(nscss_len2px(value, unit,
- style));
+ padding[i] = FIXTOINT(nscss_len2px(len_ctx,
+ value, unit, style));
}
}
@@ -1284,8 +1526,8 @@ layout_find_dimensions(int available_width,
/* spec unclear: following Mozilla */
border[i].width = 0;
else
- border[i].width = FIXTOINT(nscss_len2px(value,
- unit, style));
+ border[i].width = FIXTOINT(nscss_len2px(len_ctx,
+ value, unit, style));
/* Special case for border-collapse: make all borders
* on table/table-row-group/table-row zero width. */
@@ -1303,6 +1545,7 @@ layout_find_dimensions(int available_width,
/**
* Find next block that current margin collapses to.
*
+ * \param len_ctx Length conversion context
* \param box box to start tree-order search from (top margin is included)
* \param block box responsible for current block fromatting context
* \param viewport_height height of viewport in px
@@ -1311,7 +1554,8 @@ layout_find_dimensions(int available_width,
* \return next box that current margin collapses to, or NULL if none.
*/
static struct box*
-layout_next_margin_block(struct box *box,
+layout_next_margin_block(const nscss_len_ctx *len_ctx,
+ struct box *box,
struct box *block,
int viewport_height,
int *max_pos_margin,
@@ -1330,7 +1574,8 @@ layout_next_margin_block(struct box *box,
/* Get margins */
if (box->style) {
- layout_find_dimensions(box->parent->width,
+ layout_find_dimensions(len_ctx,
+ box->parent->width,
viewport_height, box,
box->style,
NULL, NULL, NULL, NULL,
@@ -1404,7 +1649,8 @@ layout_next_margin_block(struct box *box,
/* Get margins */
if (box->style) {
- layout_find_dimensions(box->parent->width,
+ layout_find_dimensions(len_ctx,
+ box->parent->width,
viewport_height, box,
box->style,
NULL, NULL, NULL, NULL,
@@ -1640,6 +1886,7 @@ layout_solve_width(struct box *box,
* Compute dimensions of box, margins, paddings, and borders for a block-level
* element.
*
+ * \param len_ctx Length conversion context
* \param available_width Max width available in pixels
* \param viewport_height Height of viewport in pixels or -ve if unknown
* \param lm min left margin required to avoid floats in px.
@@ -1652,7 +1899,8 @@ layout_solve_width(struct box *box,
* See CSS 2.1 10.3.3, 10.3.4, 10.6.2, and 10.6.3.
*/
static void
-layout_block_find_dimensions(int available_width,
+layout_block_find_dimensions(const nscss_len_ctx *len_ctx,
+ int available_width,
int viewport_height,
int lm,
int rm,
@@ -1665,8 +1913,8 @@ layout_block_find_dimensions(int available_width,
struct box_border *border = box->border;
const css_computed_style *style = box->style;
- layout_find_dimensions(available_width, viewport_height, box, style,
- &width, &height, &max_width, &min_width,
+ layout_find_dimensions(len_ctx, available_width, viewport_height, box,
+ style, &width, &height, &max_width, &min_width,
&max_height, &min_height, margin, padding, border);
if (box->object && !(box->flags & REPLACE_DIM) &&
@@ -1819,8 +2067,9 @@ static bool layout_table(struct box *table, int available_width,
memcpy(col, table->col, sizeof(col[0]) * columns);
/* find margins, paddings, and borders for table and cells */
- layout_find_dimensions(available_width, -1, table, style, 0, 0, 0, 0,
- 0, 0, table->margin, table->padding, table->border);
+ layout_find_dimensions(&content->len_ctx, available_width, -1, table,
+ style, 0, 0, 0, 0, 0, 0, table->margin, table->padding,
+ table->border);
for (row_group = table->children; row_group;
row_group = row_group->next) {
for (row = row_group->children; row; row = row->next) {
@@ -1829,9 +2078,11 @@ static bool layout_table(struct box *table, int available_width,
enum css_overflow_e overflow_y;
assert(c->style);
- table_used_border_for_cell(c);
- layout_find_dimensions(available_width, -1,
- c, c->style, 0, 0, 0, 0, 0, 0,
+ table_used_border_for_cell(
+ &content->len_ctx, c);
+ layout_find_dimensions(&content->len_ctx,
+ available_width, -1, c,
+ c->style, 0, 0, 0, 0, 0, 0,
0, c->padding, c->border);
overflow_x = css_computed_overflow_x(c->style);
@@ -1859,8 +2110,10 @@ static bool layout_table(struct box *table, int available_width,
css_computed_border_spacing(style, &h, &hu, &v, &vu);
- border_spacing_h = FIXTOINT(nscss_len2px(h, hu, style));
- border_spacing_v = FIXTOINT(nscss_len2px(v, vu, style));
+ border_spacing_h = FIXTOINT(nscss_len2px(&content->len_ctx,
+ h, hu, style));
+ border_spacing_v = FIXTOINT(nscss_len2px(&content->len_ctx,
+ v, vu, style));
}
/* find specified table width, or available width if auto-width */
@@ -1870,7 +2123,8 @@ static bool layout_table(struct box *table, int available_width,
table_width = FPCT_OF_INT_TOINT(value, available_width);
} else {
table_width =
- FIXTOINT(nscss_len2px(value, unit, style));
+ FIXTOINT(nscss_len2px(&content->len_ctx,
+ value, unit, style));
}
/* specified width includes border */
@@ -1948,7 +2202,8 @@ static bool layout_table(struct box *table, int available_width,
} else {
/* This is the minimum height for the table
* (see 17.5.3) */
- min_height = FIXTOINT(nscss_len2px(value, unit, style));
+ min_height = FIXTOINT(nscss_len2px(&content->len_ctx,
+ value, unit, style));
}
}
@@ -2138,8 +2393,9 @@ static bool layout_table(struct box *table, int available_width,
htype = css_computed_height(row->style, &value, &unit);
if (htype == CSS_HEIGHT_SET && unit != CSS_UNIT_PCT) {
- row_height = FIXTOINT(nscss_len2px(value, unit,
- row->style));
+ row_height = FIXTOINT(nscss_len2px(
+ &content->len_ctx,
+ value, unit, row->style));
}
for (c = row->children; c; c = c->next) {
assert(c->style);
@@ -2176,8 +2432,9 @@ static bool layout_table(struct box *table, int available_width,
/* some sites use height="1" or similar
* to attempt to make cells as small as
* possible, so treat it as a minimum */
- int h = FIXTOINT(nscss_len2px(value,
- unit, c->style));
+ int h = FIXTOINT(nscss_len2px(
+ &content->len_ctx,
+ value, unit, c->style));
if (c->height < h)
c->height = h;
}
@@ -2321,12 +2578,16 @@ static bool layout_table(struct box *table, int available_width,
/**
* Manimpulate box height according to CSS min-height and max-height properties
*
+ * \param len_ctx CSS length conversion context for document.
* \param box block to modify with any min-height or max-height
* \param container containing block for absolutely positioned elements, or
* NULL for non absolutely positioned elements.
* \return whether the height has been changed
*/
-static bool layout_apply_minmax_height(struct box *box, struct box *container)
+static bool layout_apply_minmax_height(
+ const nscss_len_ctx *len_ctx,
+ struct box *box,
+ struct box *container)
{
int h;
struct box *containing_block = NULL;
@@ -2385,8 +2646,8 @@ static bool layout_apply_minmax_height(struct box *box, struct box *container)
}
}
} else {
- h = FIXTOINT(nscss_len2px(value, unit,
- box->style));
+ h = FIXTOINT(nscss_len2px(len_ctx,
+ value, unit, box->style));
if (h < box->height) {
box->height = h;
updated = true;
@@ -2415,8 +2676,8 @@ static bool layout_apply_minmax_height(struct box *box, struct box *container)
}
}
} else {
- h = FIXTOINT(nscss_len2px(value, unit,
- box->style));
+ h = FIXTOINT(nscss_len2px(len_ctx,
+ value, unit, box->style));
if (h > box->height) {
box->height = h;
updated = true;
@@ -2459,6 +2720,1211 @@ static bool layout_block_object(struct box *block)
/**
+ * 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;
+ }
+ }
+}
+
+
+/**
+ * Split a text box.
+ *
+ * \param content memory pool for any new boxes
+ * \param fstyle style for text in text box
+ * \param split_box box with text to split
+ * \param new_length new length for text in split_box, after splitting
+ * \param new_width new width for text in split_box, after splitting
+ * \return true on success, false on memory exhaustion
+ *
+ * A new box is created and inserted into the box tree after split_box,
+ * containing the text after new_length excluding the initial space character.
+ */
+static bool
+layout_text_box_split(html_content *content,
+ plot_font_style_t *fstyle,
+ struct box *split_box,
+ size_t new_length,
+ int new_width)
+{
+ int space_width = split_box->space;
+ struct box *c2;
+ const struct gui_layout_table *font_func = content->font_func;
+ bool space = (split_box->text[new_length] == ' ');
+ int used_length = new_length + (space ? 1 : 0);
+
+ if ((space && space_width == 0) || space_width == UNKNOWN_WIDTH) {
+ /* We're need to add a space, and we don't know how big
+ * it's to be, OR we have a space of unknown width anyway;
+ * Calculate space width */
+ font_func->width(fstyle, " ", 1, &space_width);
+ }
+
+ if (split_box->space == UNKNOWN_WIDTH)
+ split_box->space = space_width;
+ if (!space)
+ space_width = 0;
+
+ /* Create clone of split_box, c2 */
+ c2 = talloc_memdup(content->bctx, split_box, sizeof *c2);
+ if (!c2)
+ return false;
+ c2->flags |= CLONE;
+
+ /* Set remaining text in c2 */
+ c2->text += used_length;
+
+ /* Set c2 according to the remaining text */
+ c2->width -= new_width + space_width;
+ c2->flags &= ~MEASURED; /* width has been estimated */
+ c2->length = split_box->length - used_length;
+
+ /* Update split_box for its reduced text */
+ split_box->width = new_width;
+ split_box->flags |= MEASURED;
+ split_box->length = new_length;
+ split_box->space = space_width;
+
+ /* Insert c2 into box list */
+ c2->next = split_box->next;
+ split_box->next = c2;
+ c2->prev = split_box;
+ if (c2->next)
+ c2->next->prev = c2;
+ else
+ c2->parent->last = c2;
+
+ NSLOG(layout, DEBUG,
+ "split_box %p len: %" PRIsizet " \"%.*s\"",
+ split_box,
+ split_box->length,
+ (int)split_box->length,
+ split_box->text);
+ NSLOG(layout, DEBUG,
+ " new_box %p len: %" PRIsizet " \"%.*s\"",
+ c2,
+ c2->length,
+ (int)c2->length,
+ c2->text);
+
+ return true;
+}
+
+
+/**
+ * Compute dimensions of box, margins, paddings, and borders for a floating
+ * element using shrink-to-fit. Also used for inline-blocks.
+ *
+ * \param len_ctx CSS length conversion context for document.
+ * \param available_width Max width available in pixels
+ * \param style Box's style
+ * \param box Box for which to find dimensions
+ * Box margins, borders, paddings, width and
+ * height are updated.
+ */
+static void
+layout_float_find_dimensions(
+ const nscss_len_ctx *len_ctx,
+ int available_width,
+ const css_computed_style *style,
+ struct box *box)
+{
+ int width, height, max_width, min_width, max_height, min_height;
+ int *margin = box->margin;
+ int *padding = box->padding;
+ struct box_border *border = box->border;
+ enum css_overflow_e overflow_x = css_computed_overflow_x(style);
+ enum css_overflow_e overflow_y = css_computed_overflow_y(style);
+ int scrollbar_width_x =
+ (overflow_x == CSS_OVERFLOW_SCROLL ||
+ overflow_x == CSS_OVERFLOW_AUTO) ?
+ SCROLLBAR_WIDTH : 0;
+ int scrollbar_width_y =
+ (overflow_y == CSS_OVERFLOW_SCROLL ||
+ overflow_y == CSS_OVERFLOW_AUTO) ?
+ SCROLLBAR_WIDTH : 0;
+
+ layout_find_dimensions(len_ctx, available_width, -1, box, style,
+ &width, &height, &max_width, &min_width,
+ &max_height, &min_height, margin, padding, border);
+
+ if (margin[LEFT] == AUTO)
+ margin[LEFT] = 0;
+ if (margin[RIGHT] == AUTO)
+ margin[RIGHT] = 0;
+
+ if (box->gadget == NULL) {
+ padding[RIGHT] += scrollbar_width_y;
+ padding[BOTTOM] += scrollbar_width_x;
+ }
+
+ if (box->object && !(box->flags & REPLACE_DIM) &&
+ content_get_type(box->object) != CONTENT_HTML) {
+ /* Floating replaced element, with intrinsic width or height.
+ * See 10.3.6 and 10.6.2 */
+ layout_get_object_dimensions(box, &width, &height,
+ min_width, max_width, min_height, max_height);
+ } else if (box->gadget && (box->gadget->type == GADGET_TEXTBOX ||
+ box->gadget->type == GADGET_PASSWORD ||
+ box->gadget->type == GADGET_FILE ||
+ box->gadget->type == GADGET_TEXTAREA)) {
+ css_fixed size = 0;
+ css_unit unit = CSS_UNIT_EM;
+
+ /* Give sensible dimensions to gadgets, with auto width/height,
+ * that don't shrink to fit contained text. */
+ assert(box->style);
+
+ if (box->gadget->type == GADGET_TEXTBOX ||
+ box->gadget->type == GADGET_PASSWORD ||
+ box->gadget->type == GADGET_FILE) {
+ if (width == AUTO) {
+ size = INTTOFIX(10);
+ width = FIXTOINT(nscss_len2px(len_ctx,
+ size, unit, box->style));
+ }
+ if (box->gadget->type == GADGET_FILE &&
+ height == AUTO) {
+ size = FLTTOFIX(1.5);
+ height = FIXTOINT(nscss_len2px(len_ctx,
+ size, unit, box->style));
+ }
+ }
+ if (box->gadget->type == GADGET_TEXTAREA) {
+ if (width == AUTO) {
+ size = INTTOFIX(10);
+ width = FIXTOINT(nscss_len2px(len_ctx,
+ size, unit, box->style));
+ }
+ if (height == AUTO) {
+ size = INTTOFIX(4);
+ height = FIXTOINT(nscss_len2px(len_ctx,
+ size, unit, box->style));
+ }
+ }
+ } else if (width == AUTO) {
+ /* CSS 2.1 section 10.3.5 */
+ width = min(max(box->min_width, available_width),
+ box->max_width);
+
+ /* width includes margin, borders and padding */
+ if (width == available_width) {
+ width -= box->margin[LEFT] + box->border[LEFT].width +
+ box->padding[LEFT] +
+ box->padding[RIGHT] +
+ box->border[RIGHT].width +
+ box->margin[RIGHT];
+ } else {
+ /* width was obtained from a min_width or max_width
+ * value, so need to use the same method for calculating
+ * mbp as was used in layout_minmax_block() */
+ int fixed = 0;
+ float frac = 0;
+ calculate_mbp_width(len_ctx, box->style, LEFT,
+ true, true, true, &fixed, &frac);
+ calculate_mbp_width(len_ctx, box->style, RIGHT,
+ true, true, true, &fixed, &frac);
+ if (fixed < 0)
+ fixed = 0;
+
+ width -= fixed;
+ }
+
+ if (max_width >= 0 && width > max_width) width = max_width;
+ if (min_width > 0 && width < min_width) width = min_width;
+
+ } else {
+ if (max_width >= 0 && width > max_width) width = max_width;
+ if (min_width > 0 && width < min_width) width = min_width;
+ width -= scrollbar_width_y;
+ }
+
+ box->width = width;
+ box->height = height;
+
+ if (margin[TOP] == AUTO)
+ margin[TOP] = 0;
+ if (margin[BOTTOM] == AUTO)
+ margin[BOTTOM] = 0;
+}
+
+
+/**
+ * Layout the contents of a float or inline block.
+ *
+ * \param b float or inline block box
+ * \param width available width
+ * \param content memory pool for any new boxes
+ * \return true on success, false on memory exhaustion
+ */
+static bool layout_float(struct box *b, int width, html_content *content)
+{
+ assert(b->type == BOX_TABLE || b->type == BOX_BLOCK ||
+ b->type == BOX_INLINE_BLOCK);
+ layout_float_find_dimensions(&content->len_ctx, width, b->style, b);
+ if (b->type == BOX_TABLE) {
+ if (!layout_table(b, width, content))
+ return false;
+ if (b->margin[LEFT] == AUTO)
+ b->margin[LEFT] = 0;
+ if (b->margin[RIGHT] == AUTO)
+ b->margin[RIGHT] = 0;
+ if (b->margin[TOP] == AUTO)
+ b->margin[TOP] = 0;
+ if (b->margin[BOTTOM] == AUTO)
+ b->margin[BOTTOM] = 0;
+ } else
+ return layout_block_context(b, -1, content);
+ return true;
+}
+
+
+/**
+ * Position a float in the first available space.
+ *
+ * \param c float box to position
+ * \param width available width
+ * \param cx x coordinate relative to cont to place float right of
+ * \param y y coordinate relative to cont to place float below
+ * \param cont ancestor box which defines horizontal space, for floats
+ */
+static void
+place_float_below(struct box *c, int width, int cx, int y, struct box *cont)
+{
+ int x0, x1, yy;
+ struct box *left;
+ struct box *right;
+
+ yy = y > cont->cached_place_below_level ?
+ y : cont->cached_place_below_level;
+
+ NSLOG(layout, DEBUG,
+ "c %p, width %i, cx %i, y %i, cont %p", c,
+ width, cx, y, cont);
+
+ do {
+ y = yy;
+ x0 = cx;
+ x1 = cx + width;
+ find_sides(cont->float_children, y, y + c->height, &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);
+ } else if (left == 0 && right != 0) {
+ yy = right->y + right->height;
+ } else if (left != 0 && right == 0) {
+ yy = left->y + left->height;
+ }
+ } while ((left != 0 || right != 0) && (c->width > x1 - x0));
+
+ if (c->type == BOX_FLOAT_LEFT) {
+ c->x = x0;
+ } else {
+ c->x = x1 - c->width;
+ }
+ c->y = y;
+ cont->cached_place_below_level = y;
+}
+
+
+/**
+ * Calculate line height from a style.
+ */
+static int line_height(
+ const nscss_len_ctx *len_ctx,
+ const css_computed_style *style)
+{
+ enum css_line_height_e lhtype;
+ css_fixed lhvalue = 0;
+ css_unit lhunit = CSS_UNIT_PX;
+ css_fixed line_height;
+
+ assert(style);
+
+ lhtype = css_computed_line_height(style, &lhvalue, &lhunit);
+ if (lhtype == CSS_LINE_HEIGHT_NORMAL) {
+ /* Normal => use a constant of 1.3 * font-size */
+ lhvalue = FLTTOFIX(1.3);
+ lhtype = CSS_LINE_HEIGHT_NUMBER;
+ }
+
+ if (lhtype == CSS_LINE_HEIGHT_NUMBER ||
+ lhunit == CSS_UNIT_PCT) {
+ line_height = nscss_len2px(len_ctx,
+ lhvalue, CSS_UNIT_EM, style);
+
+ if (lhtype != CSS_LINE_HEIGHT_NUMBER)
+ line_height = FDIV(line_height, F_100);
+ } else {
+ assert(lhunit != CSS_UNIT_PCT);
+
+ line_height = nscss_len2px(len_ctx,
+ lhvalue, lhunit, style);
+ }
+
+ return FIXTOINT(line_height);
+}
+
+
+/**
+ * Position a line of boxes in inline formatting context.
+ *
+ * \param first box at start of line
+ * \param width available width on input, updated with actual width on output
+ * (may be incorrect if the line gets split?)
+ * \param y coordinate of top of line, updated on exit to bottom
+ * \param cx coordinate of left of line relative to cont
+ * \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
+ * \param has_text_children at least one TEXT in the inline_container
+ * \param next_box updated to first box for next line, or 0 at end
+ * \param content memory pool for any new boxes
+ * \return true on success, false on memory exhaustion
+ */
+static bool
+layout_line(struct box *first,
+ int *width,
+ int *y,
+ int cx,
+ int cy,
+ struct box *cont,
+ bool indent,
+ bool has_text_children,
+ html_content *content,
+ struct box **next_box)
+{
+ int height, used_height;
+ int x0 = 0;
+ int x1 = *width;
+ int x, h, x_previous;
+ int fy = cy;
+ struct box *left;
+ struct box *right;
+ struct box *b;
+ struct box *split_box = 0;
+ struct box *d;
+ struct box *br_box = 0;
+ bool move_y = false;
+ bool place_below = false;
+ int space_before = 0, space_after = 0;
+ unsigned int inline_count = 0;
+ unsigned int i;
+ const struct gui_layout_table *font_func = content->font_func;
+ plot_font_style_t fstyle;
+
+ NSLOG(layout, DEBUG,
+ "first %p, first->text '%.*s', width %i, y %i, cx %i, cy %i",
+ first,
+ (int)first->length,
+ first->text,
+ *width,
+ *y,
+ cx,
+ 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;
+
+ if (indent)
+ x0 += layout_text_indent(&content->len_ctx,
+ first->parent->parent->style, *width);
+
+ if (x1 < x0)
+ x1 = x0;
+
+ /* get minimum line height from containing block.
+ * this is the line-height if there are text children and also in the
+ * case of an initially empty text input */
+ if (has_text_children || first->parent->parent->gadget)
+ used_height = height = line_height(&content->len_ctx,
+ first->parent->parent->style);
+ else
+ /* inline containers with no text are usually for layout and
+ * look better with no minimum line-height */
+ used_height = height = 0;
+
+ /* pass 1: find height of line assuming sides at top of line: loop
+ * body executed at least once
+ * keep in sync with the loop in layout_minmax_line() */
+
+ NSLOG(layout, DEBUG, "x0 %i, x1 %i, x1 - x0 %i", x0, x1, x1 - x0);
+
+
+ for (x = 0, b = first; x <= x1 - x0 && b != 0; b = b->next) {
+ int min_width, max_width, min_height, max_height;
+
+ 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);
+
+
+ NSLOG(layout, DEBUG, "pass 1: b %p, x %i", b, x);
+
+
+ if (b->type == BOX_BR)
+ break;
+
+ if (b->type == BOX_FLOAT_LEFT || b->type == BOX_FLOAT_RIGHT)
+ continue;
+ if (b->type == BOX_INLINE_BLOCK &&
+ (css_computed_position(b->style) ==
+ CSS_POSITION_ABSOLUTE ||
+ css_computed_position(b->style) ==
+ CSS_POSITION_FIXED))
+ continue;
+
+ assert(b->style != NULL);
+ font_plot_style_from_css(&content->len_ctx, b->style, &fstyle);
+
+ x += space_after;
+
+ if (b->type == BOX_INLINE_BLOCK) {
+ if (b->max_width != UNKNOWN_WIDTH)
+ if (!layout_float(b, *width, content))
+ return false;
+ h = b->border[TOP].width + b->padding[TOP] + b->height +
+ b->padding[BOTTOM] +
+ b->border[BOTTOM].width;
+ if (height < h)
+ height = h;
+ x += b->margin[LEFT] + b->border[LEFT].width +
+ b->padding[LEFT] + b->width +
+ b->padding[RIGHT] +
+ b->border[RIGHT].width +
+ b->margin[RIGHT];
+ space_after = 0;
+ continue;
+ }
+
+ if (b->type == BOX_INLINE) {
+ /* calculate borders, margins, and padding */
+ layout_find_dimensions(&content->len_ctx,
+ *width, -1, b, b->style, 0, 0, 0, 0,
+ 0, 0, b->margin, b->padding, b->border);
+ for (i = 0; i != 4; i++)
+ if (b->margin[i] == AUTO)
+ b->margin[i] = 0;
+ x += b->margin[LEFT] + b->border[LEFT].width +
+ b->padding[LEFT];
+ if (b->inline_end) {
+ b->inline_end->margin[RIGHT] = b->margin[RIGHT];
+ b->inline_end->padding[RIGHT] =
+ b->padding[RIGHT];
+ b->inline_end->border[RIGHT] =
+ b->border[RIGHT];
+ } else {
+ x += b->padding[RIGHT] +
+ b->border[RIGHT].width +
+ b->margin[RIGHT];
+ }
+ } else if (b->type == BOX_INLINE_END) {
+ b->width = 0;
+ if (b->space == UNKNOWN_WIDTH) {
+ font_func->width(&fstyle, " ", 1, &b->space);
+ /** \todo handle errors */
+ }
+ space_after = b->space;
+
+ x += b->padding[RIGHT] + b->border[RIGHT].width +
+ b->margin[RIGHT];
+ continue;
+ }
+
+ if (!b->object && !(b->flags & IFRAME) && !b->gadget &&
+ !(b->flags & REPLACE_DIM)) {
+ /* inline non-replaced, 10.3.1 and 10.6.1 */
+ b->height = line_height(&content->len_ctx,
+ b->style ? b->style :
+ b->parent->parent->style);
+ if (height < b->height)
+ height = b->height;
+
+ if (!b->text) {
+ b->width = 0;
+ space_after = 0;
+ continue;
+ }
+
+ if (b->width == UNKNOWN_WIDTH) {
+ /** \todo handle errors */
+
+ /* If it's a select element, we must use the
+ * width of the widest option text */
+ if (b->parent->parent->gadget &&
+ b->parent->parent->gadget->type
+ == GADGET_SELECT) {
+ int opt_maxwidth = 0;
+ struct form_option *o;
+
+ for (o = b->parent->parent->gadget->
+ data.select.items; o;
+ o = o->next) {
+ int opt_width;
+ font_func->width(&fstyle,
+ o->text,
+ strlen(o->text),
+ &opt_width);
+
+ if (opt_maxwidth < opt_width)
+ opt_maxwidth =opt_width;
+ }
+ b->width = opt_maxwidth;
+ if (nsoption_bool(core_select_menu))
+ b->width += SCROLLBAR_WIDTH;
+ } else {
+ font_func->width(&fstyle, b->text,
+ b->length, &b->width);
+ b->flags |= MEASURED;
+ }
+ }
+
+ /* If the current text has not been measured (i.e. its
+ * width was estimated after splitting), and it fits on
+ * the line, measure it properly, so next box is placed
+ * correctly. */
+ if (b->text && (x + b->width < x1 - x0) &&
+ !(b->flags & MEASURED) &&
+ b->next) {
+ font_func->width(&fstyle, b->text,
+ b->length, &b->width);
+ b->flags |= MEASURED;
+ }
+
+ x += b->width;
+ if (b->space == UNKNOWN_WIDTH) {
+ font_func->width(&fstyle, " ", 1, &b->space);
+ /** \todo handle errors */
+ }
+ space_after = b->space;
+ continue;
+ }
+
+ space_after = 0;
+
+ /* inline replaced, 10.3.2 and 10.6.2 */
+ assert(b->style);
+
+ layout_find_dimensions(&content->len_ctx,
+ *width, -1, b, b->style,
+ &b->width, &b->height,
+ &max_width, &min_width,
+ &max_height, &min_height,
+ NULL, NULL, NULL);
+
+ if (b->object && !(b->flags & REPLACE_DIM)) {
+ layout_get_object_dimensions(b, &b->width, &b->height,
+ min_width, max_width,
+ min_height, max_height);
+ } else if (b->flags & IFRAME) {
+ /* TODO: should we look at the content dimensions? */
+ if (b->width == AUTO)
+ b->width = 400;
+ if (b->height == AUTO)
+ b->height = 300;
+
+ /* We reformat the iframe browser window to new
+ * dimensions in pass 2 */
+ } else {
+ /* form control with no object */
+ if (b->width == AUTO)
+ b->width = FIXTOINT(nscss_len2px(
+ &content->len_ctx, INTTOFIX(1),
+ CSS_UNIT_EM, b->style));
+ if (b->height == AUTO)
+ b->height = FIXTOINT(nscss_len2px(
+ &content->len_ctx, INTTOFIX(1),
+ CSS_UNIT_EM, b->style));
+ }
+
+ /* Reformat object to new box size */
+ if (b->object && content_get_type(b->object) == CONTENT_HTML &&
+ b->width !=
+ content_get_available_width(b->object)) {
+ css_fixed value = 0;
+ css_unit unit = CSS_UNIT_PX;
+ enum css_height_e htype = css_computed_height(b->style,
+ &value, &unit);
+
+ content_reformat(b->object, false, b->width, b->height);
+
+ if (htype == CSS_HEIGHT_AUTO)
+ b->height = content_get_height(b->object);
+ }
+
+ if (height < b->height)
+ height = b->height;
+
+ 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);
+ x0 -= cx;
+ x1 -= cx;
+
+ if (indent)
+ x0 += layout_text_indent(&content->len_ctx,
+ first->parent->parent->style, *width);
+
+ if (x1 < x0)
+ x1 = x0;
+
+ space_after = space_before = 0;
+
+ /* pass 2: place boxes in line: loop body executed at least once */
+
+ NSLOG(layout, DEBUG, "x0 %i, x1 %i, x1 - x0 %i", x0, x1, x1 - x0);
+
+ for (x = x_previous = 0, b = first; x <= x1 - x0 && b; b = b->next) {
+
+ NSLOG(layout, DEBUG, "pass 2: b %p, x %i", b, x);
+
+ if (b->type == BOX_INLINE_BLOCK &&
+ (css_computed_position(b->style) ==
+ CSS_POSITION_ABSOLUTE ||
+ css_computed_position(b->style) ==
+ CSS_POSITION_FIXED)) {
+ b->x = x + space_after;
+
+ } else if (b->type == BOX_INLINE ||
+ b->type == BOX_INLINE_BLOCK ||
+ b->type == BOX_TEXT ||
+ b->type == BOX_INLINE_END) {
+ assert(b->width != UNKNOWN_WIDTH);
+
+ x_previous = x;
+ x += space_after;
+ b->x = x;
+
+ if ((b->type == BOX_INLINE && !b->inline_end) ||
+ b->type == BOX_INLINE_BLOCK) {
+ b->x += b->margin[LEFT] + b->border[LEFT].width;
+ x = b->x + b->padding[LEFT] + b->width +
+ b->padding[RIGHT] +
+ b->border[RIGHT].width +
+ b->margin[RIGHT];
+ } else if (b->type == BOX_INLINE) {
+ b->x += b->margin[LEFT] + b->border[LEFT].width;
+ x = b->x + b->padding[LEFT] + b->width;
+ } else if (b->type == BOX_INLINE_END) {
+ b->height = b->inline_end->height;
+ x += b->padding[RIGHT] +
+ b->border[RIGHT].width +
+ b->margin[RIGHT];
+ } else {
+ x += b->width;
+ }
+
+ space_before = space_after;
+ if (b->object || b->flags & REPLACE_DIM ||
+ b->flags & IFRAME)
+ space_after = 0;
+ else if (b->text || b->type == BOX_INLINE_END) {
+ if (b->space == UNKNOWN_WIDTH) {
+ font_plot_style_from_css(
+ &content->len_ctx,
+ b->style, &fstyle);
+ /** \todo handle errors */
+ font_func->width(&fstyle, " ", 1,
+ &b->space);
+ }
+ space_after = b->space;
+ } else {
+ space_after = 0;
+ }
+ split_box = b;
+ move_y = true;
+ inline_count++;
+ } else if (b->type == BOX_BR) {
+ b->x = x;
+ b->width = 0;
+ br_box = b;
+ b = b->next;
+ split_box = 0;
+ move_y = true;
+ break;
+
+ } else {
+ /* float */
+ NSLOG(layout, DEBUG, "float %p", b);
+
+ 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))
+ return false;
+
+ NSLOG(layout, DEBUG,
+ "%p : %d %d",
+ d,
+ d->margin[TOP],
+ d->border[TOP].width);
+
+ d->x = d->margin[LEFT] + d->border[LEFT].width;
+ d->y = d->margin[TOP] + d->border[TOP].width;
+ b->width = d->margin[LEFT] + d->border[LEFT].width +
+ d->padding[LEFT] + d->width +
+ d->padding[RIGHT] +
+ d->border[RIGHT].width +
+ d->margin[RIGHT];
+ b->height = d->margin[TOP] + d->border[TOP].width +
+ d->padding[TOP] + d->height +
+ d->padding[BOTTOM] +
+ d->border[BOTTOM].width +
+ d->margin[BOTTOM];
+
+ if (b->width > (x1 - x0) - x)
+ place_below = true;
+ if (d->style && (css_computed_clear(d->style) ==
+ CSS_CLEAR_NONE ||
+ (css_computed_clear(d->style) ==
+ CSS_CLEAR_LEFT && left == 0) ||
+ (css_computed_clear(d->style) ==
+ CSS_CLEAR_RIGHT &&
+ right == 0) ||
+ (css_computed_clear(d->style) ==
+ CSS_CLEAR_BOTH &&
+ left == 0 && right == 0)) &&
+ (!place_below ||
+ (left == 0 && right == 0 && x == 0)) &&
+ 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,
+ * this line is empty with no floats
+ * + current y, cy, is below the clear level
+ *
+ * Float affects current line */
+ if (b->type == BOX_FLOAT_LEFT) {
+ b->x = cx + x0;
+ if (b->width > 0)
+ x0 += b->width;
+ left = b;
+ } else {
+ b->x = cx + x1 - b->width;
+ if (b->width > 0)
+ x1 -= b->width;
+ right = b;
+ }
+ b->y = cy;
+ } else {
+ /* cleared or doesn't fit on line */
+ /* 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;
+
+ place_float_below(b, *width, cx, fy, cont);
+ fy = b->y;
+ if (d->style && (
+ (css_computed_clear(d->style) ==
+ CSS_CLEAR_LEFT && left != 0) ||
+ (css_computed_clear(d->style) ==
+ CSS_CLEAR_RIGHT &&
+ right != 0) ||
+ (css_computed_clear(d->style) ==
+ CSS_CLEAR_BOTH &&
+ (left != 0 || right != 0)))) {
+ /* to be cleared below existing
+ * floats */
+ if (b->type == BOX_FLOAT_LEFT)
+ b->x = cx;
+ else
+ b->x = cx + *width - b->width;
+
+ fcy = layout_clear(cont->float_children,
+ css_computed_clear(d->style));
+ if (fcy > cont->clear_level)
+ cont->clear_level = fcy;
+ if (b->y < fcy)
+ b->y = fcy;
+ }
+ if (b->type == BOX_FLOAT_LEFT)
+ left = b;
+ else
+ right = b;
+ }
+ add_float_to_container(cont, b);
+
+ split_box = 0;
+ }
+ }
+
+ if (x1 - x0 < x && split_box) {
+ /* the last box went over the end */
+ size_t split = 0;
+ int w;
+ bool no_wrap = css_computed_white_space(
+ split_box->style) == CSS_WHITE_SPACE_NOWRAP ||
+ css_computed_white_space(
+ split_box->style) == CSS_WHITE_SPACE_PRE;
+
+ x = x_previous;
+
+ if (!no_wrap &&
+ (split_box->type == BOX_INLINE ||
+ split_box->type == BOX_TEXT) &&
+ !split_box->object &&
+ !(split_box->flags & REPLACE_DIM) &&
+ !(split_box->flags & IFRAME) &&
+ !split_box->gadget && split_box->text) {
+
+ font_plot_style_from_css(&content->len_ctx,
+ split_box->style, &fstyle);
+ /** \todo handle errors */
+ font_func->split(&fstyle,
+ split_box->text,
+ split_box->length,
+ x1 - x0 - x - space_before,
+ &split,
+ &w);
+ }
+
+ /* split == 0 implies that text can't be split */
+
+ if (split == 0)
+ w = split_box->width;
+
+
+ NSLOG(layout, DEBUG,
+ "splitting: split_box %p \"%.*s\", spilt %zu, w %i, "
+ "left %p, right %p, inline_count %u",
+ split_box,
+ (int)split_box->length,
+ split_box->text,
+ split,
+ w,
+ left,
+ right,
+ inline_count);
+
+ if ((split == 0 || x1 - x0 <= x + space_before + w) &&
+ !left && !right && inline_count == 1) {
+ /* first word of box doesn't fit, but no floats and
+ * first box on line so force in */
+ if (split == 0 || split == split_box->length) {
+ /* only one word in this box, or not text
+ * or white-space:nowrap */
+ b = split_box->next;
+ } else {
+ /* cut off first word for this line */
+ if (!layout_text_box_split(content, &fstyle,
+ split_box, split, w))
+ return false;
+ b = split_box->next;
+ }
+ x += space_before + w;
+
+ NSLOG(layout, DEBUG, "forcing");
+
+ } else if ((split == 0 || x1 - x0 <= x + space_before + w) &&
+ inline_count == 1) {
+ /* first word of first box doesn't fit, but a float is
+ * taking some of the width so move below it */
+ assert(left || right);
+ used_height = 0;
+ if (left) {
+
+ NSLOG(layout, DEBUG,
+ "cy %i, left->y %i, left->height %i",
+ cy,
+ left->y,
+ left->height);
+
+ used_height = left->y + left->height - cy + 1;
+
+ NSLOG(layout, DEBUG, "used_height %i",
+ used_height);
+
+ }
+ if (right && used_height <
+ right->y + right->height - cy + 1)
+ used_height = right->y + right->height - cy + 1;
+
+ if (used_height < 0)
+ used_height = 0;
+
+ b = split_box;
+
+ NSLOG(layout, DEBUG, "moving below float");
+
+ } else if (split == 0 || x1 - x0 <= x + space_before + w) {
+ /* first word of box doesn't fit so leave box for next
+ * line */
+ b = split_box;
+
+ NSLOG(layout, DEBUG, "leaving for next line");
+
+ } else {
+ /* fit as many words as possible */
+ assert(split != 0);
+
+ NSLOG(layout, DEBUG, "'%.*s' %i %zu %i",
+ (int)split_box->length, split_box->text,
+ x1 - x0, split, w);
+
+ if (split != split_box->length) {
+ if (!layout_text_box_split(content, &fstyle,
+ split_box, split, w))
+ return false;
+ b = split_box->next;
+ }
+ x += space_before + w;
+
+ NSLOG(layout, DEBUG, "fitting words");
+
+ }
+ move_y = true;
+ }
+
+ /* set positions */
+ switch (css_computed_text_align(first->parent->parent->style)) {
+ case CSS_TEXT_ALIGN_RIGHT:
+ case CSS_TEXT_ALIGN_LIBCSS_RIGHT:
+ x0 = x1 - x;
+ break;
+ case CSS_TEXT_ALIGN_CENTER:
+ case CSS_TEXT_ALIGN_LIBCSS_CENTER:
+ x0 = (x0 + (x1 - x)) / 2;
+ break;
+ case CSS_TEXT_ALIGN_LEFT:
+ case CSS_TEXT_ALIGN_LIBCSS_LEFT:
+ case CSS_TEXT_ALIGN_JUSTIFY:
+ /* leave on left */
+ break;
+ case CSS_TEXT_ALIGN_DEFAULT:
+ /* None; consider text direction */
+ switch (css_computed_direction(first->parent->parent->style)) {
+ case CSS_DIRECTION_LTR:
+ /* leave on left */
+ break;
+ case CSS_DIRECTION_RTL:
+ x0 = x1 - x;
+ break;
+ }
+ break;
+ }
+
+ for (d = first; d != b; d = d->next) {
+ d->flags &= ~NEW_LINE;
+
+ if (d->type == BOX_INLINE_BLOCK &&
+ (css_computed_position(d->style) ==
+ CSS_POSITION_ABSOLUTE ||
+ css_computed_position(d->style) ==
+ CSS_POSITION_FIXED)) {
+ /* positioned inline-blocks:
+ * set static position (x,y) only, rest of positioning
+ * is handled later */
+ d->x += x0;
+ d->y = *y;
+ continue;
+ } else if ((d->type == BOX_INLINE &&
+ ((d->object || d->gadget) == false) &&
+ !(d->flags & IFRAME) &&
+ !(d->flags & REPLACE_DIM)) ||
+ d->type == BOX_BR ||
+ d->type == BOX_TEXT ||
+ d->type == BOX_INLINE_END) {
+ /* regular (non-replaced) inlines */
+ d->x += x0;
+ d->y = *y - d->padding[TOP];
+
+ if (d->type == BOX_TEXT && d->height > used_height) {
+ /* text */
+ used_height = d->height;
+ }
+ } else if ((d->type == BOX_INLINE) ||
+ d->type == BOX_INLINE_BLOCK) {
+ /* replaced inlines and inline-blocks */
+ d->x += x0;
+ d->y = *y + d->border[TOP].width + d->margin[TOP];
+ h = d->margin[TOP] + d->border[TOP].width +
+ d->padding[TOP] + d->height +
+ d->padding[BOTTOM] +
+ d->border[BOTTOM].width +
+ d->margin[BOTTOM];
+ if (used_height < h)
+ used_height = h;
+ }
+ }
+
+ first->flags |= NEW_LINE;
+
+ assert(b != first || (move_y && 0 < used_height && (left || right)));
+
+ /* handle vertical-align by adjusting box y values */
+ /** \todo proper vertical alignment handling */
+ for (d = first; d != b; d = d->next) {
+ if ((d->type == BOX_INLINE && d->inline_end) ||
+ d->type == BOX_BR ||
+ d->type == BOX_TEXT ||
+ d->type == BOX_INLINE_END) {
+ css_fixed value = 0;
+ css_unit unit = CSS_UNIT_PX;
+ switch (css_computed_vertical_align(d->style, &value,
+ &unit)) {
+ case CSS_VERTICAL_ALIGN_SUPER:
+ case CSS_VERTICAL_ALIGN_TOP:
+ case CSS_VERTICAL_ALIGN_TEXT_TOP:
+ /* already at top */
+ break;
+ case CSS_VERTICAL_ALIGN_SUB:
+ case CSS_VERTICAL_ALIGN_BOTTOM:
+ case CSS_VERTICAL_ALIGN_TEXT_BOTTOM:
+ d->y += used_height - d->height;
+ break;
+ default:
+ case CSS_VERTICAL_ALIGN_BASELINE:
+ d->y += 0.75 * (used_height - d->height);
+ break;
+ }
+ }
+ }
+
+ /* handle clearance for br */
+ if (br_box && css_computed_clear(br_box->style) != CSS_CLEAR_NONE) {
+ int clear_y = layout_clear(cont->float_children,
+ css_computed_clear(br_box->style));
+ if (used_height < clear_y - cy)
+ used_height = clear_y - cy;
+ }
+
+ if (move_y)
+ *y += used_height;
+ *next_box = b;
+ *width = x; /* return actual width */
+ return true;
+}
+
+
+/**
+ * Layout lines of text or inline boxes with floats.
+ *
+ * \param box inline container box
+ * \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
+ * \param content memory pool for any new boxes
+ * \return true on success, false on memory exhaustion
+ */
+static bool layout_inline_container(struct box *inline_container, int width,
+ struct box *cont, int cx, int cy, html_content *content)
+{
+ bool first_line = true;
+ bool has_text_children;
+ struct box *c, *next;
+ int y = 0;
+ int curwidth,maxwidth = width;
+
+ assert(inline_container->type == BOX_INLINE_CONTAINER);
+
+ NSLOG(layout, DEBUG,
+ "inline_container %p, width %i, cont %p, cx %i, cy %i",
+ inline_container,
+ width,
+ cont,
+ cx,
+ cy);
+
+
+ has_text_children = false;
+ for (c = inline_container->children; c; c = c->next) {
+ bool is_pre = false;
+
+ if (c->style) {
+ enum css_white_space_e whitespace;
+
+ whitespace = css_computed_white_space(c->style);
+
+ is_pre = (whitespace == CSS_WHITE_SPACE_PRE ||
+ whitespace == CSS_WHITE_SPACE_PRE_LINE ||
+ whitespace == CSS_WHITE_SPACE_PRE_WRAP);
+ }
+
+ if ((!c->object && !(c->flags & REPLACE_DIM) &&
+ !(c->flags & IFRAME) &&
+ c->text && (c->length || is_pre)) ||
+ c->type == BOX_BR)
+ has_text_children = true;
+ }
+
+ /** \todo fix wrapping so that a box with horizontal scrollbar will
+ * shrink back to 'width' if no word is wider than 'width' (Or just set
+ * curwidth = width and have the multiword lines wrap to the min width)
+ */
+ for (c = inline_container->children; c; ) {
+
+ NSLOG(layout, DEBUG, "c %p", c);
+
+ curwidth = inline_container->width;
+ if (!layout_line(c, &curwidth, &y, cx, cy + y, cont, first_line,
+ has_text_children, content, &next))
+ return false;
+ maxwidth = max(maxwidth,curwidth);
+ c = next;
+ first_line = false;
+ }
+
+ inline_container->width = maxwidth;
+ inline_container->height = y;
+
+ return true;
+}
+
+
+/**
* Layout a block formatting context.
*
* \param block BLOCK, INLINE_BLOCK, or TABLE_CELL to layout
@@ -2516,7 +3982,8 @@ layout_block_context(struct box *block,
gadget_unit = CSS_UNIT_EM;
gadget_size = INTTOFIX(1);
if (block->height == AUTO)
- block->height = FIXTOINT(nscss_len2px(gadget_size,
+ block->height = FIXTOINT(nscss_len2px(
+ &content->len_ctx, gadget_size,
gadget_unit, block->style));
}
@@ -2580,7 +4047,8 @@ layout_block_context(struct box *block,
/* If we don't know which box the current margin collapses
* through to, find out. Update the pos/neg margin values. */
if (margin_collapse == NULL) {
- margin_collapse = layout_next_margin_block(box, block,
+ margin_collapse = layout_next_margin_block(
+ &content->len_ctx, box, block,
viewport_height,
&max_pos_margin, &max_neg_margin);
/* We have a margin that has not yet been applied. */
@@ -2631,7 +4099,8 @@ layout_block_context(struct box *block,
box->parent->padding[RIGHT] -
x1;
}
- layout_block_find_dimensions(box->parent->width,
+ layout_block_find_dimensions(&content->len_ctx,
+ box->parent->width,
viewport_height, lm, rm, box);
if (box->type == BOX_BLOCK && !(box->flags & IFRAME)) {
layout_block_add_scrollbar(box, RIGHT);
@@ -2871,8 +4340,9 @@ layout_block_context(struct box *block,
if (box->style &&
css_computed_position(box->style) !=
CSS_POSITION_ABSOLUTE &&
- layout_apply_minmax_height(box,
- NULL)) {
+ layout_apply_minmax_height(
+ &content->len_ctx,
+ box, NULL)) {
/* Height altered */
/* Set current cy */
cy += box->height -
@@ -2928,19 +4398,23 @@ layout_block_context(struct box *block,
if (block->style && css_computed_position(block->style) !=
CSS_POSITION_ABSOLUTE) {
/* Block is in normal flow */
- layout_apply_minmax_height(block, NULL);
+ layout_apply_minmax_height(&content->len_ctx, block, NULL);
}
if (block->gadget &&
(block->gadget->type == GADGET_TEXTAREA ||
block->gadget->type == GADGET_PASSWORD ||
block->gadget->type == GADGET_TEXTBOX)) {
+ plot_font_style_t fstyle;
int ta_width = block->padding[LEFT] + block->width +
block->padding[RIGHT];
int ta_height = block->padding[TOP] + block->height +
block->padding[BOTTOM];
+ font_plot_style_from_css(&content->len_ctx,
+ block->style, &fstyle);
+ fstyle.background = NS_TRANSPARENT;
textarea_set_layout(block->gadget->data.text.ta,
- ta_width, ta_height,
+ &fstyle, ta_width, ta_height,
block->padding[TOP], block->padding[RIGHT],
block->padding[BOTTOM], block->padding[LEFT]);
}
@@ -2950,46 +4424,12 @@ layout_block_context(struct box *block,
/**
- * Calculate line height from a style.
- */
-static int line_height(const css_computed_style *style)
-{
- enum css_line_height_e lhtype;
- css_fixed lhvalue = 0;
- css_unit lhunit = CSS_UNIT_PX;
- css_fixed line_height;
-
- assert(style);
-
- lhtype = css_computed_line_height(style, &lhvalue, &lhunit);
- if (lhtype == CSS_LINE_HEIGHT_NORMAL) {
- /* Normal => use a constant of 1.3 * font-size */
- lhvalue = FLTTOFIX(1.3);
- lhtype = CSS_LINE_HEIGHT_NUMBER;
- }
-
- if (lhtype == CSS_LINE_HEIGHT_NUMBER ||
- lhunit == CSS_UNIT_PCT) {
- line_height = nscss_len2px(lhvalue, CSS_UNIT_EM, style);
-
- if (lhtype != CSS_LINE_HEIGHT_NUMBER)
- line_height = FDIV(line_height, F_100);
- } else {
- assert(lhunit != CSS_UNIT_PCT);
-
- line_height = nscss_len2px(lhvalue, lhunit, style);
- }
-
- return FIXTOINT(line_height);
-}
-
-
-/**
* Layout list markers.
*/
static void
layout_lists(struct box *box,
- const struct gui_layout_table *font_func)
+ const struct gui_layout_table *font_func,
+ const nscss_len_ctx *len_ctx)
{
struct box *child;
struct box *marker;
@@ -3004,12 +4444,13 @@ layout_lists(struct box *box,
marker->x = -marker->width;
marker->height =
content_get_height(marker->object);
- marker->y = (line_height(marker->style) -
+ marker->y = (line_height(len_ctx,
+ marker->style) -
marker->height) / 2;
} else if (marker->text) {
if (marker->width == UNKNOWN_WIDTH) {
- font_plot_style_from_css(marker->style,
- &fstyle);
+ font_plot_style_from_css(len_ctx,
+ marker->style, &fstyle);
font_func->width(&fstyle,
marker->text,
marker->length,
@@ -3018,7 +4459,8 @@ layout_lists(struct box *box,
}
marker->x = -marker->width;
marker->y = 0;
- marker->height = line_height(marker->style);
+ marker->height = line_height(len_ctx,
+ marker->style);
} else {
marker->x = 0;
marker->y = 0;
@@ -3028,7 +4470,7 @@ layout_lists(struct box *box,
/* Gap between marker and content */
marker->x -= 4;
}
- layout_lists(child, font_func);
+ layout_lists(child, font_func, len_ctx);
}
}
@@ -3037,6 +4479,7 @@ layout_lists(struct box *box,
* Compute box offsets for a relatively or absolutely positioned box with
* respect to a box.
*
+ * \param len_ctx Length conversion context
* \param box box to compute offsets for
* \param containing_block box to compute percentages with respect to
* \param top updated to top offset, or AUTO
@@ -3047,7 +4490,8 @@ layout_lists(struct box *box,
* See CSS 2.1 9.3.2. containing_block must have width and height.
*/
static void
-layout_compute_offsets(struct box *box,
+layout_compute_offsets(const nscss_len_ctx *len_ctx,
+ struct box *box,
struct box *containing_block,
int *top,
int *right,
@@ -3069,7 +4513,8 @@ layout_compute_offsets(struct box *box,
*left = FPCT_OF_INT_TOINT(value,
containing_block->width);
} else {
- *left = FIXTOINT(nscss_len2px(value, unit, box->style));
+ *left = FIXTOINT(nscss_len2px(len_ctx,
+ value, unit, box->style));
}
} else {
*left = AUTO;
@@ -3082,8 +4527,8 @@ layout_compute_offsets(struct box *box,
*right = FPCT_OF_INT_TOINT(value,
containing_block->width);
} else {
- *right = FIXTOINT(nscss_len2px(value, unit,
- box->style));
+ *right = FIXTOINT(nscss_len2px(len_ctx,
+ value, unit, box->style));
}
} else {
*right = AUTO;
@@ -3096,7 +4541,8 @@ layout_compute_offsets(struct box *box,
*top = FPCT_OF_INT_TOINT(value,
containing_block->height);
} else {
- *top = FIXTOINT(nscss_len2px(value, unit, box->style));
+ *top = FIXTOINT(nscss_len2px(len_ctx,
+ value, unit, box->style));
}
} else {
*top = AUTO;
@@ -3109,8 +4555,8 @@ layout_compute_offsets(struct box *box,
*bottom = FPCT_OF_INT_TOINT(value,
containing_block->height);
} else {
- *bottom = FIXTOINT(nscss_len2px(value, unit,
- box->style));
+ *bottom = FIXTOINT(nscss_len2px(len_ctx,
+ value, unit, box->style));
}
} else {
*bottom = AUTO;
@@ -3166,16 +4612,17 @@ layout_absolute(struct box *box,
/** \todo inline containers */
}
- layout_compute_offsets(box, containing_block,
+ layout_compute_offsets(&content->len_ctx, box, containing_block,
&top, &right, &bottom, &left);
/* Pass containing block into layout_find_dimensions via the float
* containing block box member. This is unused for absolutely positioned
* boxes because a box can't be floated and absolutely positioned. */
box->float_container = containing_block;
- layout_find_dimensions(available_width, -1, box, box->style,
- &width, &height, &max_width, &min_width,
- 0, 0, margin, padding, border);
+ layout_find_dimensions(&content->len_ctx, available_width, -1,
+ box, box->style, &width, &height,
+ &max_width, &min_width, 0, 0,
+ margin, padding, border);
box->float_container = NULL;
/* 10.3.7 */
@@ -3490,7 +4937,7 @@ layout_absolute(struct box *box,
/** \todo Inline ancestors */
}
box->height = height;
- layout_apply_minmax_height(box, containing_block);
+ layout_apply_minmax_height(&content->len_ctx, box, containing_block);
return true;
}
@@ -3567,11 +5014,16 @@ layout_position_absolute(struct box *box,
/**
* Compute a box's relative offset as per CSS 2.1 9.4.3
*
+ * \param len_ctx Length conversion context
* \param box Box to compute relative offsets for.
* \param x Receives relative offset in x.
* \param y Receives relative offset in y.
*/
-static void layout_compute_relative_offset(struct box *box, int *x, int *y)
+static void layout_compute_relative_offset(
+ const nscss_len_ctx *len_ctx,
+ struct box *box,
+ int *x,
+ int *y)
{
int left, right, top, bottom;
struct box *containing_block;
@@ -3588,7 +5040,7 @@ static void layout_compute_relative_offset(struct box *box, int *x, int *y)
containing_block = box->parent;
}
- layout_compute_offsets(box, containing_block,
+ layout_compute_offsets(len_ctx, box, containing_block,
&top, &right, &bottom, &left);
if (left == AUTO && right == AUTO)
@@ -3636,6 +5088,7 @@ static void layout_compute_relative_offset(struct box *box, int *x, int *y)
/**
* Adjust positions of relatively positioned boxes.
*
+ * \param len_ctx Length conversion context
* \param root box to adjust the position of
* \param fp box which forms the block formatting context for children of
* "root" which are floats
@@ -3647,7 +5100,12 @@ static void layout_compute_relative_offset(struct box *box, int *x, int *y)
* box, "fp", for float children of "root"
*/
static void
-layout_position_relative(struct box *root, struct box *fp, int fx, int fy)
+layout_position_relative(
+ const nscss_len_ctx *len_ctx,
+ struct box *root,
+ struct box *fp,
+ int fx,
+ int fy)
{
struct box *box; /* for children of "root" */
struct box *fn; /* for block formatting context box for children of
@@ -3671,7 +5129,8 @@ layout_position_relative(struct box *root, struct box *fp, int fx, int fy)
/* If relatively positioned, get offsets */
if (box->style && css_computed_position(box->style) ==
CSS_POSITION_RELATIVE)
- layout_compute_relative_offset(box, &x, &y);
+ layout_compute_relative_offset(
+ len_ctx, box, &x, &y);
else
x = y = 0;
@@ -3707,7 +5166,7 @@ layout_position_relative(struct box *root, struct box *fp, int fx, int fy)
}
/* recurse first */
- layout_position_relative(box, fn, fnx, fny);
+ layout_position_relative(len_ctx, box, fn, fnx, fny);
/* Ignore things we're not interested in. */
if (!box->style || (box->style &&
@@ -3733,1369 +5192,10 @@ layout_position_relative(struct box *root, struct box *fp, int fx, int fy)
}
-/* exported function documented in render/layout.h */
-bool layout_document(html_content *content, int width, int height)
-{
- bool ret;
- struct box *doc = content->layout;
- const struct gui_layout_table *font_func = content->font_func;
-
- layout_minmax_block(doc, font_func);
-
- layout_block_find_dimensions(width, height, 0, 0, doc);
- doc->x = doc->margin[LEFT] + doc->border[LEFT].width;
- doc->y = doc->margin[TOP] + doc->border[TOP].width;
- width -= doc->margin[LEFT] + doc->border[LEFT].width +
- doc->padding[LEFT] + doc->padding[RIGHT] +
- doc->border[RIGHT].width + doc->margin[RIGHT];
- if (width < 0) {
- width = 0;
- }
- doc->width = width;
-
- ret = layout_block_context(doc, height, content);
-
- /* make <html> and <body> fill available height */
- if (doc->y + doc->padding[TOP] + doc->height + doc->padding[BOTTOM] +
- doc->border[BOTTOM].width + doc->margin[BOTTOM] <
- height) {
- doc->height = height - (doc->y + doc->padding[TOP] +
- doc->padding[BOTTOM] +
- doc->border[BOTTOM].width +
- doc->margin[BOTTOM]);
- if (doc->children)
- doc->children->height = doc->height -
- (doc->children->margin[TOP] +
- doc->children->border[TOP].width +
- doc->children->padding[TOP] +
- doc->children->padding[BOTTOM] +
- doc->children->border[BOTTOM].width +
- doc->children->margin[BOTTOM]);
- }
-
- layout_lists(doc, font_func);
- layout_position_absolute(doc, doc, 0, 0, content);
- layout_position_relative(doc, doc, 0, 0);
-
- layout_calculate_descendant_bboxes(doc);
-
- return ret;
-}
-
-
-/**
- * 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;
- }
- }
-}
-
-
-/**
- * Split a text box.
- *
- * \param content memory pool for any new boxes
- * \param fstyle style for text in text box
- * \param split_box box with text to split
- * \param new_length new length for text in split_box, after splitting
- * \param new_width new width for text in split_box, after splitting
- * \return true on success, false on memory exhaustion
- *
- * A new box is created and inserted into the box tree after split_box,
- * containing the text after new_length excluding the initial space character.
- */
-static bool
-layout_text_box_split(html_content *content,
- plot_font_style_t *fstyle,
- struct box *split_box,
- size_t new_length,
- int new_width)
-{
- int space_width = split_box->space;
- struct box *c2;
- const struct gui_layout_table *font_func = content->font_func;
- bool space = (split_box->text[new_length] == ' ');
- int used_length = new_length + (space ? 1 : 0);
-
- if ((space && space_width == 0) || space_width == UNKNOWN_WIDTH) {
- /* We're need to add a space, and we don't know how big
- * it's to be, OR we have a space of unknown width anyway;
- * Calculate space width */
- font_func->width(fstyle, " ", 1, &space_width);
- }
-
- if (split_box->space == UNKNOWN_WIDTH)
- split_box->space = space_width;
- if (!space)
- space_width = 0;
-
- /* Create clone of split_box, c2 */
- c2 = talloc_memdup(content->bctx, split_box, sizeof *c2);
- if (!c2)
- return false;
- c2->flags |= CLONE;
-
- /* Set remaining text in c2 */
- c2->text += used_length;
-
- /* Set c2 according to the remaining text */
- c2->width -= new_width + space_width;
- c2->flags &= ~MEASURED; /* width has been estimated */
- c2->length = split_box->length - used_length;
-
- /* Update split_box for its reduced text */
- split_box->width = new_width;
- split_box->flags |= MEASURED;
- split_box->length = new_length;
- split_box->space = space_width;
-
- /* Insert c2 into box list */
- c2->next = split_box->next;
- split_box->next = c2;
- c2->prev = split_box;
- if (c2->next)
- c2->next->prev = c2;
- else
- c2->parent->last = c2;
-
- NSLOG(layout, DEBUG,
- "split_box %p len: %" PRIsizet " \"%.*s\"",
- split_box,
- split_box->length,
- (int)split_box->length,
- split_box->text);
- NSLOG(layout, DEBUG,
- " new_box %p len: %" PRIsizet " \"%.*s\"",
- c2,
- c2->length,
- (int)c2->length,
- c2->text);
-
- return true;
-}
-
-
-/**
- * Compute dimensions of box, margins, paddings, and borders for a floating
- * element using shrink-to-fit. Also used for inline-blocks.
- *
- * \param available_width Max width available in pixels
- * \param style Box's style
- * \param box Box for which to find dimensions
- * Box margins, borders, paddings, width and
- * height are updated.
- */
-static void
-layout_float_find_dimensions(int available_width,
- const css_computed_style *style,
- struct box *box)
-{
- int width, height, max_width, min_width, max_height, min_height;
- int *margin = box->margin;
- int *padding = box->padding;
- struct box_border *border = box->border;
- enum css_overflow_e overflow_x = css_computed_overflow_x(style);
- enum css_overflow_e overflow_y = css_computed_overflow_y(style);
- int scrollbar_width_x =
- (overflow_x == CSS_OVERFLOW_SCROLL ||
- overflow_x == CSS_OVERFLOW_AUTO) ?
- SCROLLBAR_WIDTH : 0;
- int scrollbar_width_y =
- (overflow_y == CSS_OVERFLOW_SCROLL ||
- overflow_y == CSS_OVERFLOW_AUTO) ?
- SCROLLBAR_WIDTH : 0;
-
- layout_find_dimensions(available_width, -1, box, style, &width, &height,
- &max_width, &min_width, &max_height, &min_height,
- margin, padding, border);
-
- if (margin[LEFT] == AUTO)
- margin[LEFT] = 0;
- if (margin[RIGHT] == AUTO)
- margin[RIGHT] = 0;
-
- if (box->gadget == NULL) {
- padding[RIGHT] += scrollbar_width_y;
- padding[BOTTOM] += scrollbar_width_x;
- }
-
- if (box->object && !(box->flags & REPLACE_DIM) &&
- content_get_type(box->object) != CONTENT_HTML) {
- /* Floating replaced element, with intrinsic width or height.
- * See 10.3.6 and 10.6.2 */
- layout_get_object_dimensions(box, &width, &height,
- min_width, max_width, min_height, max_height);
- } else if (box->gadget && (box->gadget->type == GADGET_TEXTBOX ||
- box->gadget->type == GADGET_PASSWORD ||
- box->gadget->type == GADGET_FILE ||
- box->gadget->type == GADGET_TEXTAREA)) {
- css_fixed size = 0;
- css_unit unit = CSS_UNIT_EM;
-
- /* Give sensible dimensions to gadgets, with auto width/height,
- * that don't shrink to fit contained text. */
- assert(box->style);
-
- if (box->gadget->type == GADGET_TEXTBOX ||
- box->gadget->type == GADGET_PASSWORD ||
- box->gadget->type == GADGET_FILE) {
- if (width == AUTO) {
- size = INTTOFIX(10);
- width = FIXTOINT(nscss_len2px(size, unit,
- box->style));
- }
- if (box->gadget->type == GADGET_FILE &&
- height == AUTO) {
- size = FLTTOFIX(1.5);
- height = FIXTOINT(nscss_len2px(size, unit,
- box->style));
- }
- }
- if (box->gadget->type == GADGET_TEXTAREA) {
- if (width == AUTO) {
- size = INTTOFIX(10);
- width = FIXTOINT(nscss_len2px(size, unit,
- box->style));
- }
- if (height == AUTO) {
- size = INTTOFIX(4);
- height = FIXTOINT(nscss_len2px(size, unit,
- box->style));
- }
- }
- } else if (width == AUTO) {
- /* CSS 2.1 section 10.3.5 */
- width = min(max(box->min_width, available_width),
- box->max_width);
-
- /* width includes margin, borders and padding */
- if (width == available_width) {
- width -= box->margin[LEFT] + box->border[LEFT].width +
- box->padding[LEFT] +
- box->padding[RIGHT] +
- box->border[RIGHT].width +
- box->margin[RIGHT];
- } else {
- /* width was obtained from a min_width or max_width
- * value, so need to use the same method for calculating
- * mbp as was used in layout_minmax_block() */
- int fixed = 0;
- float frac = 0;
- calculate_mbp_width(box->style, LEFT, true, true, true,
- &fixed, &frac);
- calculate_mbp_width(box->style, RIGHT, true, true, true,
- &fixed, &frac);
- if (fixed < 0)
- fixed = 0;
-
- width -= fixed;
- }
-
- if (max_width >= 0 && width > max_width) width = max_width;
- if (min_width > 0 && width < min_width) width = min_width;
-
- } else {
- if (max_width >= 0 && width > max_width) width = max_width;
- if (min_width > 0 && width < min_width) width = min_width;
- width -= scrollbar_width_y;
- }
-
- box->width = width;
- box->height = height;
-
- if (margin[TOP] == AUTO)
- margin[TOP] = 0;
- if (margin[BOTTOM] == AUTO)
- margin[BOTTOM] = 0;
-}
-
-
-/**
- * Layout the contents of a float or inline block.
- *
- * \param b float or inline block box
- * \param width available width
- * \param content memory pool for any new boxes
- * \return true on success, false on memory exhaustion
- */
-static bool layout_float(struct box *b, int width, html_content *content)
-{
- assert(b->type == BOX_TABLE || b->type == BOX_BLOCK ||
- b->type == BOX_INLINE_BLOCK);
- layout_float_find_dimensions(width, b->style, b);
- if (b->type == BOX_TABLE) {
- if (!layout_table(b, width, content))
- return false;
- if (b->margin[LEFT] == AUTO)
- b->margin[LEFT] = 0;
- if (b->margin[RIGHT] == AUTO)
- b->margin[RIGHT] = 0;
- if (b->margin[TOP] == AUTO)
- b->margin[TOP] = 0;
- if (b->margin[BOTTOM] == AUTO)
- b->margin[BOTTOM] = 0;
- } else
- return layout_block_context(b, -1, content);
- return true;
-}
-
-
-/**
- * Position a float in the first available space.
- *
- * \param c float box to position
- * \param width available width
- * \param cx x coordinate relative to cont to place float right of
- * \param y y coordinate relative to cont to place float below
- * \param cont ancestor box which defines horizontal space, for floats
- */
-static void
-place_float_below(struct box *c, int width, int cx, int y, struct box *cont)
-{
- int x0, x1, yy;
- struct box *left;
- struct box *right;
-
- yy = y > cont->cached_place_below_level ?
- y : cont->cached_place_below_level;
-
- NSLOG(layout, DEBUG,
- "c %p, width %i, cx %i, y %i, cont %p", c,
- width, cx, y, cont);
-
- do {
- y = yy;
- x0 = cx;
- x1 = cx + width;
- find_sides(cont->float_children, y, y + c->height, &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);
- } else if (left == 0 && right != 0) {
- yy = right->y + right->height;
- } else if (left != 0 && right == 0) {
- yy = left->y + left->height;
- }
- } while ((left != 0 || right != 0) && (c->width > x1 - x0));
-
- if (c->type == BOX_FLOAT_LEFT) {
- c->x = x0;
- } else {
- c->x = x1 - c->width;
- }
- c->y = y;
- cont->cached_place_below_level = y;
-}
-
-
-/**
- * Position a line of boxes in inline formatting context.
- *
- * \param first box at start of line
- * \param width available width on input, updated with actual width on output
- * (may be incorrect if the line gets split?)
- * \param y coordinate of top of line, updated on exit to bottom
- * \param cx coordinate of left of line relative to cont
- * \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
- * \param has_text_children at least one TEXT in the inline_container
- * \param next_box updated to first box for next line, or 0 at end
- * \param content memory pool for any new boxes
- * \return true on success, false on memory exhaustion
- */
-static bool
-layout_line(struct box *first,
- int *width,
- int *y,
- int cx,
- int cy,
- struct box *cont,
- bool indent,
- bool has_text_children,
- html_content *content,
- struct box **next_box)
-{
- int height, used_height;
- int x0 = 0;
- int x1 = *width;
- int x, h, x_previous;
- int fy = cy;
- struct box *left;
- struct box *right;
- struct box *b;
- struct box *split_box = 0;
- struct box *d;
- struct box *br_box = 0;
- bool move_y = false;
- bool place_below = false;
- int space_before = 0, space_after = 0;
- unsigned int inline_count = 0;
- unsigned int i;
- const struct gui_layout_table *font_func = content->font_func;
- plot_font_style_t fstyle;
-
- NSLOG(layout, DEBUG,
- "first %p, first->text '%.*s', width %i, y %i, cx %i, cy %i",
- first,
- (int)first->length,
- first->text,
- *width,
- *y,
- cx,
- 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;
-
- if (indent)
- x0 += layout_text_indent(first->parent->parent->style, *width);
-
- if (x1 < x0)
- x1 = x0;
-
- /* get minimum line height from containing block.
- * this is the line-height if there are text children and also in the
- * case of an initially empty text input */
- if (has_text_children || first->parent->parent->gadget)
- used_height = height =
- line_height(first->parent->parent->style);
- else
- /* inline containers with no text are usually for layout and
- * look better with no minimum line-height */
- used_height = height = 0;
-
- /* pass 1: find height of line assuming sides at top of line: loop
- * body executed at least once
- * keep in sync with the loop in layout_minmax_line() */
-
- NSLOG(layout, DEBUG, "x0 %i, x1 %i, x1 - x0 %i", x0, x1, x1 - x0);
-
-
- for (x = 0, b = first; x <= x1 - x0 && b != 0; b = b->next) {
- int min_width, max_width, min_height, max_height;
-
- 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);
-
-
- NSLOG(layout, DEBUG, "pass 1: b %p, x %i", b, x);
-
-
- if (b->type == BOX_BR)
- break;
-
- if (b->type == BOX_FLOAT_LEFT || b->type == BOX_FLOAT_RIGHT)
- continue;
- if (b->type == BOX_INLINE_BLOCK &&
- (css_computed_position(b->style) ==
- CSS_POSITION_ABSOLUTE ||
- css_computed_position(b->style) ==
- CSS_POSITION_FIXED))
- continue;
-
- assert(b->style != NULL);
- font_plot_style_from_css(b->style, &fstyle);
-
- x += space_after;
-
- if (b->type == BOX_INLINE_BLOCK) {
- if (b->max_width != UNKNOWN_WIDTH)
- if (!layout_float(b, *width, content))
- return false;
- h = b->border[TOP].width + b->padding[TOP] + b->height +
- b->padding[BOTTOM] +
- b->border[BOTTOM].width;
- if (height < h)
- height = h;
- x += b->margin[LEFT] + b->border[LEFT].width +
- b->padding[LEFT] + b->width +
- b->padding[RIGHT] +
- b->border[RIGHT].width +
- b->margin[RIGHT];
- space_after = 0;
- continue;
- }
-
- if (b->type == BOX_INLINE) {
- /* calculate borders, margins, and padding */
- layout_find_dimensions(*width, -1, b, b->style, 0, 0,
- 0, 0, 0, 0, b->margin, b->padding,
- b->border);
- for (i = 0; i != 4; i++)
- if (b->margin[i] == AUTO)
- b->margin[i] = 0;
- x += b->margin[LEFT] + b->border[LEFT].width +
- b->padding[LEFT];
- if (b->inline_end) {
- b->inline_end->margin[RIGHT] = b->margin[RIGHT];
- b->inline_end->padding[RIGHT] =
- b->padding[RIGHT];
- b->inline_end->border[RIGHT] =
- b->border[RIGHT];
- } else {
- x += b->padding[RIGHT] +
- b->border[RIGHT].width +
- b->margin[RIGHT];
- }
- } else if (b->type == BOX_INLINE_END) {
- b->width = 0;
- if (b->space == UNKNOWN_WIDTH) {
- font_func->width(&fstyle, " ", 1, &b->space);
- /** \todo handle errors */
- }
- space_after = b->space;
-
- x += b->padding[RIGHT] + b->border[RIGHT].width +
- b->margin[RIGHT];
- continue;
- }
-
- if (!b->object && !(b->flags & IFRAME) && !b->gadget &&
- !(b->flags & REPLACE_DIM)) {
- /* inline non-replaced, 10.3.1 and 10.6.1 */
- b->height = line_height(b->style ? b->style :
- b->parent->parent->style);
- if (height < b->height)
- height = b->height;
-
- if (!b->text) {
- b->width = 0;
- space_after = 0;
- continue;
- }
-
- if (b->width == UNKNOWN_WIDTH) {
- /** \todo handle errors */
-
- /* If it's a select element, we must use the
- * width of the widest option text */
- if (b->parent->parent->gadget &&
- b->parent->parent->gadget->type
- == GADGET_SELECT) {
- int opt_maxwidth = 0;
- struct form_option *o;
-
- for (o = b->parent->parent->gadget->
- data.select.items; o;
- o = o->next) {
- int opt_width;
- font_func->width(&fstyle,
- o->text,
- strlen(o->text),
- &opt_width);
-
- if (opt_maxwidth < opt_width)
- opt_maxwidth =opt_width;
- }
- b->width = opt_maxwidth;
- if (nsoption_bool(core_select_menu))
- b->width += SCROLLBAR_WIDTH;
- } else {
- font_func->width(&fstyle, b->text,
- b->length, &b->width);
- b->flags |= MEASURED;
- }
- }
-
- /* If the current text has not been measured (i.e. its
- * width was estimated after splitting), and it fits on
- * the line, measure it properly, so next box is placed
- * correctly. */
- if (b->text && (x + b->width < x1 - x0) &&
- !(b->flags & MEASURED) &&
- b->next) {
- font_func->width(&fstyle, b->text,
- b->length, &b->width);
- b->flags |= MEASURED;
- }
-
- x += b->width;
- if (b->space == UNKNOWN_WIDTH) {
- font_func->width(&fstyle, " ", 1, &b->space);
- /** \todo handle errors */
- }
- space_after = b->space;
- continue;
- }
-
- space_after = 0;
-
- /* inline replaced, 10.3.2 and 10.6.2 */
- assert(b->style);
-
- layout_find_dimensions(*width, -1, b, b->style,
- &b->width, &b->height, &max_width, &min_width,
- &max_height, &min_height, NULL, NULL, NULL);
-
- if (b->object && !(b->flags & REPLACE_DIM)) {
- layout_get_object_dimensions(b, &b->width, &b->height,
- min_width, max_width,
- min_height, max_height);
- } else if (b->flags & IFRAME) {
- /* TODO: should we look at the content dimensions? */
- if (b->width == AUTO)
- b->width = 400;
- if (b->height == AUTO)
- b->height = 300;
-
- /* We reformat the iframe browser window to new
- * dimensions in pass 2 */
- } else {
- /* form control with no object */
- if (b->width == AUTO)
- b->width = FIXTOINT(nscss_len2px(INTTOFIX(1),
- CSS_UNIT_EM, b->style));
- if (b->height == AUTO)
- b->height = FIXTOINT(nscss_len2px(INTTOFIX(1),
- CSS_UNIT_EM, b->style));
- }
-
- /* Reformat object to new box size */
- if (b->object && content_get_type(b->object) == CONTENT_HTML &&
- b->width !=
- content_get_available_width(b->object)) {
- css_fixed value = 0;
- css_unit unit = CSS_UNIT_PX;
- enum css_height_e htype = css_computed_height(b->style,
- &value, &unit);
-
- content_reformat(b->object, false, b->width, b->height);
-
- if (htype == CSS_HEIGHT_AUTO)
- b->height = content_get_height(b->object);
- }
-
- if (height < b->height)
- height = b->height;
-
- 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);
- x0 -= cx;
- x1 -= cx;
-
- if (indent)
- x0 += layout_text_indent(first->parent->parent->style, *width);
-
- if (x1 < x0)
- x1 = x0;
-
- space_after = space_before = 0;
-
- /* pass 2: place boxes in line: loop body executed at least once */
-
- NSLOG(layout, DEBUG, "x0 %i, x1 %i, x1 - x0 %i", x0, x1, x1 - x0);
-
- for (x = x_previous = 0, b = first; x <= x1 - x0 && b; b = b->next) {
-
- NSLOG(layout, DEBUG, "pass 2: b %p, x %i", b, x);
-
- if (b->type == BOX_INLINE_BLOCK &&
- (css_computed_position(b->style) ==
- CSS_POSITION_ABSOLUTE ||
- css_computed_position(b->style) ==
- CSS_POSITION_FIXED)) {
- b->x = x + space_after;
-
- } else if (b->type == BOX_INLINE ||
- b->type == BOX_INLINE_BLOCK ||
- b->type == BOX_TEXT ||
- b->type == BOX_INLINE_END) {
- assert(b->width != UNKNOWN_WIDTH);
-
- x_previous = x;
- x += space_after;
- b->x = x;
-
- if ((b->type == BOX_INLINE && !b->inline_end) ||
- b->type == BOX_INLINE_BLOCK) {
- b->x += b->margin[LEFT] + b->border[LEFT].width;
- x = b->x + b->padding[LEFT] + b->width +
- b->padding[RIGHT] +
- b->border[RIGHT].width +
- b->margin[RIGHT];
- } else if (b->type == BOX_INLINE) {
- b->x += b->margin[LEFT] + b->border[LEFT].width;
- x = b->x + b->padding[LEFT] + b->width;
- } else if (b->type == BOX_INLINE_END) {
- b->height = b->inline_end->height;
- x += b->padding[RIGHT] +
- b->border[RIGHT].width +
- b->margin[RIGHT];
- } else {
- x += b->width;
- }
-
- space_before = space_after;
- if (b->object || b->flags & REPLACE_DIM ||
- b->flags & IFRAME)
- space_after = 0;
- else if (b->text || b->type == BOX_INLINE_END) {
- if (b->space == UNKNOWN_WIDTH) {
- font_plot_style_from_css(b->style,
- &fstyle);
- /** \todo handle errors */
- font_func->width(&fstyle, " ", 1,
- &b->space);
- }
- space_after = b->space;
- } else {
- space_after = 0;
- }
- split_box = b;
- move_y = true;
- inline_count++;
- } else if (b->type == BOX_BR) {
- b->x = x;
- b->width = 0;
- br_box = b;
- b = b->next;
- split_box = 0;
- move_y = true;
- break;
-
- } else {
- /* float */
- NSLOG(layout, DEBUG, "float %p", b);
-
- 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))
- return false;
-
- NSLOG(layout, DEBUG,
- "%p : %d %d",
- d,
- d->margin[TOP],
- d->border[TOP].width);
-
- d->x = d->margin[LEFT] + d->border[LEFT].width;
- d->y = d->margin[TOP] + d->border[TOP].width;
- b->width = d->margin[LEFT] + d->border[LEFT].width +
- d->padding[LEFT] + d->width +
- d->padding[RIGHT] +
- d->border[RIGHT].width +
- d->margin[RIGHT];
- b->height = d->margin[TOP] + d->border[TOP].width +
- d->padding[TOP] + d->height +
- d->padding[BOTTOM] +
- d->border[BOTTOM].width +
- d->margin[BOTTOM];
-
- if (b->width > (x1 - x0) - x)
- place_below = true;
- if (d->style && (css_computed_clear(d->style) ==
- CSS_CLEAR_NONE ||
- (css_computed_clear(d->style) ==
- CSS_CLEAR_LEFT && left == 0) ||
- (css_computed_clear(d->style) ==
- CSS_CLEAR_RIGHT &&
- right == 0) ||
- (css_computed_clear(d->style) ==
- CSS_CLEAR_BOTH &&
- left == 0 && right == 0)) &&
- (!place_below ||
- (left == 0 && right == 0 && x == 0)) &&
- 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,
- * this line is empty with no floats
- * + current y, cy, is below the clear level
- *
- * Float affects current line */
- if (b->type == BOX_FLOAT_LEFT) {
- b->x = cx + x0;
- if (b->width > 0)
- x0 += b->width;
- left = b;
- } else {
- b->x = cx + x1 - b->width;
- if (b->width > 0)
- x1 -= b->width;
- right = b;
- }
- b->y = cy;
- } else {
- /* cleared or doesn't fit on line */
- /* 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;
-
- place_float_below(b, *width, cx, fy, cont);
- fy = b->y;
- if (d->style && (
- (css_computed_clear(d->style) ==
- CSS_CLEAR_LEFT && left != 0) ||
- (css_computed_clear(d->style) ==
- CSS_CLEAR_RIGHT &&
- right != 0) ||
- (css_computed_clear(d->style) ==
- CSS_CLEAR_BOTH &&
- (left != 0 || right != 0)))) {
- /* to be cleared below existing
- * floats */
- if (b->type == BOX_FLOAT_LEFT)
- b->x = cx;
- else
- b->x = cx + *width - b->width;
-
- fcy = layout_clear(cont->float_children,
- css_computed_clear(d->style));
- if (fcy > cont->clear_level)
- cont->clear_level = fcy;
- if (b->y < fcy)
- b->y = fcy;
- }
- if (b->type == BOX_FLOAT_LEFT)
- left = b;
- else
- right = b;
- }
- add_float_to_container(cont, b);
-
- split_box = 0;
- }
- }
-
- if (x1 - x0 < x && split_box) {
- /* the last box went over the end */
- size_t split = 0;
- int w;
- bool no_wrap = css_computed_white_space(
- split_box->style) == CSS_WHITE_SPACE_NOWRAP ||
- css_computed_white_space(
- split_box->style) == CSS_WHITE_SPACE_PRE;
-
- x = x_previous;
-
- if (!no_wrap &&
- (split_box->type == BOX_INLINE ||
- split_box->type == BOX_TEXT) &&
- !split_box->object &&
- !(split_box->flags & REPLACE_DIM) &&
- !(split_box->flags & IFRAME) &&
- !split_box->gadget && split_box->text) {
-
- font_plot_style_from_css(split_box->style, &fstyle);
- /** \todo handle errors */
- font_func->split(&fstyle,
- split_box->text,
- split_box->length,
- x1 - x0 - x - space_before,
- &split,
- &w);
- }
-
- /* split == 0 implies that text can't be split */
-
- if (split == 0)
- w = split_box->width;
-
-
- NSLOG(layout, DEBUG,
- "splitting: split_box %p \"%.*s\", spilt %zu, w %i, "
- "left %p, right %p, inline_count %u",
- split_box,
- (int)split_box->length,
- split_box->text,
- split,
- w,
- left,
- right,
- inline_count);
-
- if ((split == 0 || x1 - x0 <= x + space_before + w) &&
- !left && !right && inline_count == 1) {
- /* first word of box doesn't fit, but no floats and
- * first box on line so force in */
- if (split == 0 || split == split_box->length) {
- /* only one word in this box, or not text
- * or white-space:nowrap */
- b = split_box->next;
- } else {
- /* cut off first word for this line */
- if (!layout_text_box_split(content, &fstyle,
- split_box, split, w))
- return false;
- b = split_box->next;
- }
- x += space_before + w;
-
- NSLOG(layout, DEBUG, "forcing");
-
- } else if ((split == 0 || x1 - x0 <= x + space_before + w) &&
- inline_count == 1) {
- /* first word of first box doesn't fit, but a float is
- * taking some of the width so move below it */
- assert(left || right);
- used_height = 0;
- if (left) {
-
- NSLOG(layout, DEBUG,
- "cy %i, left->y %i, left->height %i",
- cy,
- left->y,
- left->height);
-
- used_height = left->y + left->height - cy + 1;
-
- NSLOG(layout, DEBUG, "used_height %i",
- used_height);
-
- }
- if (right && used_height <
- right->y + right->height - cy + 1)
- used_height = right->y + right->height - cy + 1;
-
- if (used_height < 0)
- used_height = 0;
-
- b = split_box;
-
- NSLOG(layout, DEBUG, "moving below float");
-
- } else if (split == 0 || x1 - x0 <= x + space_before + w) {
- /* first word of box doesn't fit so leave box for next
- * line */
- b = split_box;
-
- NSLOG(layout, DEBUG, "leaving for next line");
-
- } else {
- /* fit as many words as possible */
- assert(split != 0);
-
- NSLOG(layout, DEBUG, "'%.*s' %i %zu %i",
- (int)split_box->length, split_box->text,
- x1 - x0, split, w);
-
- if (split != split_box->length) {
- if (!layout_text_box_split(content, &fstyle,
- split_box, split, w))
- return false;
- b = split_box->next;
- }
- x += space_before + w;
-
- NSLOG(layout, DEBUG, "fitting words");
-
- }
- move_y = true;
- }
-
- /* set positions */
- switch (css_computed_text_align(first->parent->parent->style)) {
- case CSS_TEXT_ALIGN_RIGHT:
- case CSS_TEXT_ALIGN_LIBCSS_RIGHT:
- x0 = x1 - x;
- break;
- case CSS_TEXT_ALIGN_CENTER:
- case CSS_TEXT_ALIGN_LIBCSS_CENTER:
- x0 = (x0 + (x1 - x)) / 2;
- break;
- case CSS_TEXT_ALIGN_LEFT:
- case CSS_TEXT_ALIGN_LIBCSS_LEFT:
- case CSS_TEXT_ALIGN_JUSTIFY:
- /* leave on left */
- break;
- case CSS_TEXT_ALIGN_DEFAULT:
- /* None; consider text direction */
- switch (css_computed_direction(first->parent->parent->style)) {
- case CSS_DIRECTION_LTR:
- /* leave on left */
- break;
- case CSS_DIRECTION_RTL:
- x0 = x1 - x;
- break;
- }
- break;
- }
-
- for (d = first; d != b; d = d->next) {
- d->flags &= ~NEW_LINE;
-
- if (d->type == BOX_INLINE_BLOCK &&
- (css_computed_position(d->style) ==
- CSS_POSITION_ABSOLUTE ||
- css_computed_position(d->style) ==
- CSS_POSITION_FIXED)) {
- /* positioned inline-blocks:
- * set static position (x,y) only, rest of positioning
- * is handled later */
- d->x += x0;
- d->y = *y;
- continue;
- } else if ((d->type == BOX_INLINE &&
- ((d->object || d->gadget) == false) &&
- !(d->flags & IFRAME) &&
- !(d->flags & REPLACE_DIM)) ||
- d->type == BOX_BR ||
- d->type == BOX_TEXT ||
- d->type == BOX_INLINE_END) {
- /* regular (non-replaced) inlines */
- d->x += x0;
- d->y = *y - d->padding[TOP];
-
- if (d->type == BOX_TEXT && d->height > used_height) {
- /* text */
- used_height = d->height;
- }
- } else if ((d->type == BOX_INLINE) ||
- d->type == BOX_INLINE_BLOCK) {
- /* replaced inlines and inline-blocks */
- d->x += x0;
- d->y = *y + d->border[TOP].width + d->margin[TOP];
- h = d->margin[TOP] + d->border[TOP].width +
- d->padding[TOP] + d->height +
- d->padding[BOTTOM] +
- d->border[BOTTOM].width +
- d->margin[BOTTOM];
- if (used_height < h)
- used_height = h;
- }
- }
-
- first->flags |= NEW_LINE;
-
- assert(b != first || (move_y && 0 < used_height && (left || right)));
-
- /* handle vertical-align by adjusting box y values */
- /** \todo proper vertical alignment handling */
- for (d = first; d != b; d = d->next) {
- if ((d->type == BOX_INLINE && d->inline_end) ||
- d->type == BOX_BR ||
- d->type == BOX_TEXT ||
- d->type == BOX_INLINE_END) {
- css_fixed value = 0;
- css_unit unit = CSS_UNIT_PX;
- switch (css_computed_vertical_align(d->style, &value,
- &unit)) {
- case CSS_VERTICAL_ALIGN_SUPER:
- case CSS_VERTICAL_ALIGN_TOP:
- case CSS_VERTICAL_ALIGN_TEXT_TOP:
- /* already at top */
- break;
- case CSS_VERTICAL_ALIGN_SUB:
- case CSS_VERTICAL_ALIGN_BOTTOM:
- case CSS_VERTICAL_ALIGN_TEXT_BOTTOM:
- d->y += used_height - d->height;
- break;
- default:
- case CSS_VERTICAL_ALIGN_BASELINE:
- d->y += 0.75 * (used_height - d->height);
- break;
- }
- }
- }
-
- /* handle clearance for br */
- if (br_box && css_computed_clear(br_box->style) != CSS_CLEAR_NONE) {
- int clear_y = layout_clear(cont->float_children,
- css_computed_clear(br_box->style));
- if (used_height < clear_y - cy)
- used_height = clear_y - cy;
- }
-
- if (move_y)
- *y += used_height;
- *next_box = b;
- *width = x; /* return actual width */
- return true;
-}
-
-
-/* exported function documented in render/layout.h */
-bool layout_inline_container(struct box *inline_container, int width,
- struct box *cont, int cx, int cy, html_content *content)
-{
- bool first_line = true;
- bool has_text_children;
- struct box *c, *next;
- int y = 0;
- int curwidth,maxwidth = width;
-
- assert(inline_container->type == BOX_INLINE_CONTAINER);
-
- NSLOG(layout, DEBUG,
- "inline_container %p, width %i, cont %p, cx %i, cy %i",
- inline_container,
- width,
- cont,
- cx,
- cy);
-
-
- has_text_children = false;
- for (c = inline_container->children; c; c = c->next) {
- bool is_pre = false;
-
- if (c->style) {
- enum css_white_space_e whitespace;
-
- whitespace = css_computed_white_space(c->style);
-
- is_pre = (whitespace == CSS_WHITE_SPACE_PRE ||
- whitespace == CSS_WHITE_SPACE_PRE_LINE ||
- whitespace == CSS_WHITE_SPACE_PRE_WRAP);
- }
-
- if ((!c->object && !(c->flags & REPLACE_DIM) &&
- !(c->flags & IFRAME) &&
- c->text && (c->length || is_pre)) ||
- c->type == BOX_BR)
- has_text_children = true;
- }
-
- /** \todo fix wrapping so that a box with horizontal scrollbar will
- * shrink back to 'width' if no word is wider than 'width' (Or just set
- * curwidth = width and have the multiword lines wrap to the min width)
- */
- for (c = inline_container->children; c; ) {
-
- NSLOG(layout, DEBUG, "c %p", c);
-
- curwidth = inline_container->width;
- if (!layout_line(c, &curwidth, &y, cx, cy + y, cont, first_line,
- has_text_children, content, &next))
- return false;
- maxwidth = max(maxwidth,curwidth);
- c = next;
- first_line = false;
- }
-
- inline_container->width = maxwidth;
- inline_container->height = y;
-
- return true;
-}
-
-
-/* exported function documented in render/layout.h */
-void
-layout_minmax_table(struct box *table, const struct gui_layout_table *font_func)
-{
- 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;
- enum css_width_e wtype;
- css_fixed value = 0;
- css_unit unit = CSS_UNIT_PX;
-
- /* check if the widths have already been calculated */
- if (table->max_width != UNKNOWN_MAX_WIDTH)
- return;
-
- /* start with 0 except for fixed-width columns */
- for (i = 0; i != table->columns; i++) {
- if (col[i].type == COLUMN_WIDTH_FIXED)
- col[i].min = col[i].max = col[i].width;
- else
- col[i].min = col[i].max = 0;
- }
-
- /* border-spacing is used in the separated borders model */
- if (css_computed_border_collapse(table->style) ==
- CSS_BORDER_COLLAPSE_SEPARATE) {
- css_fixed h = 0, v = 0;
- css_unit hu = CSS_UNIT_PX, vu = CSS_UNIT_PX;
-
- css_computed_border_spacing(table->style, &h, &hu, &v, &vu);
-
- border_spacing_h = FIXTOINT(nscss_len2px(h, hu, table->style));
- }
-
- /* 1st pass: consider cells with colspan 1 only */
- 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);
- /** TODO: Handle colspan="0" correctly.
- * It's currently converted to 1 in box normaisation */
- assert(cell->columns != 0);
-
- if (cell->columns != 1)
- continue;
-
- layout_minmax_block(cell, font_func);
- i = cell->start_column;
-
- if (col[i].positioned)
- continue;
-
- /* 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, extra;
-
- if (cell->columns == 1)
- continue;
-
- layout_minmax_block(cell, font_func);
- i = cell->start_column;
-
- /* 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;
-
- /* 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;
- }
- } 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;
- }
- }
- }
- }
-
- /* 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;
- }
- }
-
- for (i = 0; i != table->columns; i++) {
- if (col[i].max < col[i].min) {
- box_dump(stderr, table, 0, true);
- assert(0);
- }
- table_min += col[i].min;
- table_max += col[i].max;
- }
-
- /* fixed width takes priority, unless it is too narrow */
- wtype = css_computed_width(table->style, &value, &unit);
- if (wtype == CSS_WIDTH_SET && unit != CSS_UNIT_PCT) {
- int width = FIXTOINT(nscss_len2px(value, unit, table->style));
- if (table_min < width)
- table_min = width;
- if (table_max < width)
- table_max = width;
- }
-
- /* add margins, border, padding to min, max widths */
- calculate_mbp_width(table->style, LEFT, true, true, true,
- &extra_fixed, &extra_frac);
- calculate_mbp_width(table->style, RIGHT, true, true, true,
- &extra_fixed, &extra_frac);
- if (extra_fixed < 0)
- extra_fixed = 0;
- if (extra_frac < 0)
- extra_frac = 0;
- 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;
-
- assert(0 <= table->min_width && table->min_width <= table->max_width);
-}
-
-
/**
* Find a box's bounding box relative to itself, i.e. the box's border edge box
*
+ * \param len_ctx Length conversion context
* \param box box find bounding box of
* \param desc_x0 updated to left of box's bbox
* \param desc_y0 updated to top of box's bbox
@@ -5103,9 +5203,11 @@ layout_minmax_table(struct box *table, const struct gui_layout_table *font_func)
* \param desc_y1 updated to bottom of box's bbox
*/
static void
-layout_get_box_bbox(struct box *box,
- int *desc_x0, int *desc_y0,
- int *desc_x1, int *desc_y1)
+layout_get_box_bbox(
+ const nscss_len_ctx *len_ctx,
+ struct box *box,
+ int *desc_x0, int *desc_y0,
+ int *desc_x1, int *desc_y1)
{
*desc_x0 = -box->border[LEFT].width;
*desc_y0 = -box->border[TOP].width;
@@ -5125,7 +5227,8 @@ layout_get_box_bbox(struct box *box,
int text_height;
css_computed_font_size(box->style, &font_size, &font_unit);
- text_height = nscss_len2px(font_size, font_unit, box->style);
+ text_height = nscss_len2px(len_ctx, font_size, font_unit,
+ box->style);
text_height = FIXTOINT(text_height * 3 / 4);
*desc_y0 = (*desc_y0 < -text_height) ? *desc_y0 : -text_height;
}
@@ -5135,16 +5238,19 @@ layout_get_box_bbox(struct box *box,
/**
* Apply changes to box descendant_[xy][01] values due to given child.
*
- * \param box box to update
- * \param child a box, which may affect box's descendant bbox
- * \param off_x offset to apply to child->x coord to treat as child of box
- * \param off_y offset to apply to child->y coord to treat as child of box
+ * \param len_ctx Length conversion context
+ * \param box box to update
+ * \param child a box, which may affect box's descendant bbox
+ * \param off_x offset to apply to child->x coord to treat as child of box
+ * \param off_y offset to apply to child->y coord to treat as child of box
*/
static void
-layout_update_descendant_bbox(struct box *box,
- struct box *child,
- int off_x,
- int off_y)
+layout_update_descendant_bbox(
+ const nscss_len_ctx *len_ctx,
+ struct box *box,
+ struct box *child,
+ int off_x,
+ int off_y)
{
int child_desc_x0, child_desc_y0, child_desc_x1, child_desc_y1;
@@ -5164,7 +5270,8 @@ layout_update_descendant_bbox(struct box *box,
}
/* Get child's border edge */
- layout_get_box_bbox(child, &child_desc_x0, &child_desc_y0,
+ layout_get_box_bbox(len_ctx, child,
+ &child_desc_x0, &child_desc_y0,
&child_desc_x1, &child_desc_y1);
if (overflow_x == CSS_OVERFLOW_VISIBLE &&
@@ -5197,8 +5304,16 @@ layout_update_descendant_bbox(struct box *box,
}
-/* exported function documented in render/layout.h */
-void layout_calculate_descendant_bboxes(struct box *box)
+/**
+ * Recursively calculate the descendant_[xy][01] values for a laid-out box tree
+ * and inform iframe browser windows of their size and position.
+ *
+ * \param len_ctx Length conversion context
+ * \param box tree of boxes to update
+ */
+static void layout_calculate_descendant_bboxes(
+ const nscss_len_ctx *len_ctx,
+ struct box *box)
{
struct box *child;
@@ -5207,7 +5322,8 @@ void layout_calculate_descendant_bboxes(struct box *box)
/* assert((box->width >= 0) && (box->height >= 0)); */
/* Initialise box's descendant box to border edge box */
- layout_get_box_bbox(box, &box->descendant_x0, &box->descendant_y0,
+ layout_get_box_bbox(len_ctx, box,
+ &box->descendant_x0, &box->descendant_y0,
&box->descendant_x1, &box->descendant_y1);
/* Extend it to contain HTML contents if box is replaced */
@@ -5240,7 +5356,7 @@ void layout_calculate_descendant_bboxes(struct box *box)
child->type == BOX_FLOAT_RIGHT)
continue;
- layout_update_descendant_bbox(box, child,
+ layout_update_descendant_bbox(len_ctx, box, child,
box->x, box->y);
if (child == box->inline_end)
@@ -5258,7 +5374,7 @@ void layout_calculate_descendant_bboxes(struct box *box)
child->type == BOX_FLOAT_RIGHT)
continue;
- layout_calculate_descendant_bboxes(child);
+ layout_calculate_descendant_bboxes(len_ctx, child);
if (box->style && css_computed_overflow_x(box->style) ==
CSS_OVERFLOW_HIDDEN &&
@@ -5266,22 +5382,73 @@ void layout_calculate_descendant_bboxes(struct box *box)
CSS_OVERFLOW_HIDDEN)
continue;
- layout_update_descendant_bbox(box, child, 0, 0);
+ layout_update_descendant_bbox(len_ctx, box, child, 0, 0);
}
for (child = box->float_children; child; child = child->next_float) {
assert(child->type == BOX_FLOAT_LEFT ||
child->type == BOX_FLOAT_RIGHT);
- layout_calculate_descendant_bboxes(child);
+ layout_calculate_descendant_bboxes(len_ctx, child);
- layout_update_descendant_bbox(box, child, 0, 0);
+ layout_update_descendant_bbox(len_ctx, box, child, 0, 0);
}
if (box->list_marker) {
child = box->list_marker;
- layout_calculate_descendant_bboxes(child);
+ layout_calculate_descendant_bboxes(len_ctx, child);
+
+ layout_update_descendant_bbox(len_ctx, box, child, 0, 0);
+ }
+}
- layout_update_descendant_bbox(box, child, 0, 0);
+
+/* exported function documented in render/layout.h */
+bool layout_document(html_content *content, int width, int height)
+{
+ bool ret;
+ struct box *doc = content->layout;
+ const struct gui_layout_table *font_func = content->font_func;
+
+ layout_minmax_block(doc, font_func, content);
+
+ layout_block_find_dimensions(&content->len_ctx,
+ width, height, 0, 0, doc);
+ doc->x = doc->margin[LEFT] + doc->border[LEFT].width;
+ doc->y = doc->margin[TOP] + doc->border[TOP].width;
+ width -= doc->margin[LEFT] + doc->border[LEFT].width +
+ doc->padding[LEFT] + doc->padding[RIGHT] +
+ doc->border[RIGHT].width + doc->margin[RIGHT];
+ if (width < 0) {
+ width = 0;
+ }
+ doc->width = width;
+
+ ret = layout_block_context(doc, height, content);
+
+ /* make <html> and <body> fill available height */
+ if (doc->y + doc->padding[TOP] + doc->height + doc->padding[BOTTOM] +
+ doc->border[BOTTOM].width + doc->margin[BOTTOM] <
+ height) {
+ doc->height = height - (doc->y + doc->padding[TOP] +
+ doc->padding[BOTTOM] +
+ doc->border[BOTTOM].width +
+ doc->margin[BOTTOM]);
+ if (doc->children)
+ doc->children->height = doc->height -
+ (doc->children->margin[TOP] +
+ doc->children->border[TOP].width +
+ doc->children->padding[TOP] +
+ doc->children->padding[BOTTOM] +
+ doc->children->border[BOTTOM].width +
+ doc->children->margin[BOTTOM]);
}
+
+ layout_lists(doc, font_func, &content->len_ctx);
+ layout_position_absolute(doc, doc, 0, 0, content);
+ layout_position_relative(&content->len_ctx, doc, doc, 0, 0);
+
+ layout_calculate_descendant_bboxes(&content->len_ctx, doc);
+
+ return ret;
}
diff --git a/render/layout.h b/render/layout.h
index 78a30028e..cd5ddd77f 100644
--- a/render/layout.h
+++ b/render/layout.h
@@ -42,35 +42,4 @@ struct gui_layout_table;
*/
bool layout_document(struct html_content *content, int width, int height);
-/**
- * Layout lines of text or inline boxes with floats.
- *
- * \param box inline container box
- * \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
- * \param content memory pool for any new boxes
- * \return true on success, false on memory exhaustion
- */
-bool layout_inline_container(struct box *box, int width, struct box *cont, int cx, int cy, struct html_content *content);
-
-/**
- * Recursively calculate the descendant_[xy][01] values for a laid-out box tree
- * and inform iframe browser windows of their size and position.
- *
- * \param box tree of boxes to update
- */
-void layout_calculate_descendant_bboxes(struct box *box);
-
-/**
- * Calculate minimum and maximum width of a table.
- *
- * \param table box of type TABLE
- * \param font_func Font functions
- * \post table->min_width and table->max_width filled in,
- * 0 <= table->min_width <= table->max_width
- */
-void layout_minmax_table(struct box *table, const struct gui_layout_table *font_func);
-
#endif
diff --git a/render/search.c b/render/search.c
index 8f21d8758..ca9520165 100644
--- a/render/search.c
+++ b/render/search.c
@@ -621,13 +621,14 @@ void search_show_all(bool all, struct search_context *context)
if (!a->sel)
continue;
- selection_init(a->sel, html->layout);
+ selection_init(a->sel, html->layout,
+ &html->len_ctx);
} else {
a->sel = selection_create(context->c, false);
if (!a->sel)
continue;
- selection_init(a->sel, NULL);
+ selection_init(a->sel, NULL, NULL);
}
selection_set_start(a->sel, a->start_idx);
diff --git a/render/table.c b/render/table.c
index c41b9130e..08a2e805c 100644
--- a/render/table.c
+++ b/render/table.c
@@ -45,31 +45,57 @@ struct border {
css_unit unit; /**< border-width units */
};
-static void table_used_left_border_for_cell(struct box *cell);
-static void table_used_top_border_for_cell(struct box *cell);
-static void table_used_right_border_for_cell(struct box *cell);
-static void table_used_bottom_border_for_cell(struct box *cell);
-static bool table_border_is_more_eyecatching(const struct border *a,
- box_type a_src, const struct border *b, box_type b_src);
-static void table_cell_top_process_table(struct box *table, struct border *a,
+static void table_used_left_border_for_cell(
+ const nscss_len_ctx *len_ctx,
+ struct box *cell);
+static void table_used_top_border_for_cell(
+ const nscss_len_ctx *len_ctx,
+ struct box *cell);
+static void table_used_right_border_for_cell(
+ const nscss_len_ctx *len_ctx,
+ struct box *cell);
+static void table_used_bottom_border_for_cell(
+ const nscss_len_ctx *len_ctx,
+ struct box *cell);
+static bool table_border_is_more_eyecatching(
+ const nscss_len_ctx *len_ctx,
+ const struct border *a,
+ box_type a_src,
+ const struct border *b,
+ box_type b_src);
+static void table_cell_top_process_table(
+ const nscss_len_ctx *len_ctx,
+ struct box *table,
+ struct border *a,
+ box_type *a_src);
+static bool table_cell_top_process_group(
+ const nscss_len_ctx *len_ctx,
+ struct box *cell,
+ struct box *group,
+ struct border *a,
+ box_type *a_src);
+static bool table_cell_top_process_row(
+ const nscss_len_ctx *len_ctx,
+ struct box *cell,
+ struct box *row,
+ struct border *a,
box_type *a_src);
-static bool table_cell_top_process_group(struct box *cell, struct box *group,
- struct border *a, box_type *a_src);
-static bool table_cell_top_process_row(struct box *cell, struct box *row,
- struct border *a, box_type *a_src);
/**
* Determine the column width types for a table.
*
- * \param table box of type BOX_TABLE
+ * \param len_ctx Length conversion context
+ * \param table box of type BOX_TABLE
* \return true on success, false on memory exhaustion
*
* The table->col array is allocated and type and width are filled in for each
* column.
*/
-bool table_calculate_column_types(struct box *table)
+bool table_calculate_column_types(
+ const nscss_len_ctx *len_ctx,
+ struct box *table)
{
unsigned int i, j;
struct column *col;
@@ -109,7 +135,7 @@ bool table_calculate_column_types(struct box *table)
css_computed_position(cell->style) !=
CSS_POSITION_FIXED) {
col[i].positioned = false;
- }
+ }
type = css_computed_width(cell->style, &value, &unit);
@@ -117,8 +143,8 @@ bool table_calculate_column_types(struct box *table)
if (col[i].type != COLUMN_WIDTH_FIXED &&
type == CSS_WIDTH_SET && unit != CSS_UNIT_PCT) {
col[i].type = COLUMN_WIDTH_FIXED;
- col[i].width = FIXTOINT(nscss_len2px(value, unit,
- cell->style));
+ col[i].width = FIXTOINT(nscss_len2px(len_ctx,
+ value, unit, cell->style));
if (col[i].width < 0)
col[i].width = 0;
continue;
@@ -181,7 +207,7 @@ bool table_calculate_column_types(struct box *table)
if (type == CSS_WIDTH_SET && unit != CSS_UNIT_PCT &&
fixed_columns + unknown_columns ==
cell->columns) {
- int width = (FIXTOFLT(nscss_len2px(value, unit,
+ int width = (FIXTOFLT(nscss_len2px(len_ctx, value, unit,
cell->style)) - fixed_width) /
unknown_columns;
if (width < 0)
@@ -235,11 +261,14 @@ bool table_calculate_column_types(struct box *table)
/**
* Calculate used values of border-{trbl}-{style,color,width} for table cells.
*
- * \param cell Table cell to consider
+ * \param len_ctx Length conversion context
+ * \param cell Table cell to consider
*
* \post \a cell's border array is populated
*/
-void table_used_border_for_cell(struct box *cell)
+void table_used_border_for_cell(
+ const nscss_len_ctx *len_ctx,
+ struct box *cell)
{
int side;
@@ -257,7 +286,8 @@ void table_used_border_for_cell(struct box *cell)
&cell->border[LEFT].c);
css_computed_border_left_width(cell->style, &width, &unit);
cell->border[LEFT].width =
- FIXTOINT(nscss_len2px(width, unit, cell->style));
+ FIXTOINT(nscss_len2px(len_ctx,
+ width, unit, cell->style));
/* Top border */
cell->border[TOP].style =
@@ -266,7 +296,8 @@ void table_used_border_for_cell(struct box *cell)
&cell->border[TOP].c);
css_computed_border_top_width(cell->style, &width, &unit);
cell->border[TOP].width =
- FIXTOINT(nscss_len2px(width, unit, cell->style));
+ FIXTOINT(nscss_len2px(len_ctx,
+ width, unit, cell->style));
/* Right border */
cell->border[RIGHT].style =
@@ -275,7 +306,8 @@ void table_used_border_for_cell(struct box *cell)
&cell->border[RIGHT].c);
css_computed_border_right_width(cell->style, &width, &unit);
cell->border[RIGHT].width =
- FIXTOINT(nscss_len2px(width, unit, cell->style));
+ FIXTOINT(nscss_len2px(len_ctx,
+ width, unit, cell->style));
/* Bottom border */
cell->border[BOTTOM].style =
@@ -284,19 +316,20 @@ void table_used_border_for_cell(struct box *cell)
&cell->border[BOTTOM].c);
css_computed_border_bottom_width(cell->style, &width, &unit);
cell->border[BOTTOM].width =
- FIXTOINT(nscss_len2px(width, unit, cell->style));
+ FIXTOINT(nscss_len2px(len_ctx,
+ width, unit, cell->style));
} else {
/* Left border */
- table_used_left_border_for_cell(cell);
+ table_used_left_border_for_cell(len_ctx, cell);
/* Top border */
- table_used_top_border_for_cell(cell);
+ table_used_top_border_for_cell(len_ctx, cell);
/* Right border */
- table_used_right_border_for_cell(cell);
+ table_used_right_border_for_cell(len_ctx, cell);
/* Bottom border */
- table_used_bottom_border_for_cell(cell);
+ table_used_bottom_border_for_cell(len_ctx, cell);
}
/* Finally, ensure that any borders configured as
@@ -316,9 +349,12 @@ void table_used_border_for_cell(struct box *cell)
/**
* Calculate used values of border-left-{style,color,width}
*
- * \param cell Table cell to consider
+ * \param len_ctx Length conversion context
+ * \param cell Table cell to consider
*/
-void table_used_left_border_for_cell(struct box *cell)
+void table_used_left_border_for_cell(
+ const nscss_len_ctx *len_ctx,
+ struct box *cell)
{
struct border a, b;
box_type a_src, b_src;
@@ -329,7 +365,7 @@ void table_used_left_border_for_cell(struct box *cell)
a.style = css_computed_border_left_style(cell->style);
a.color = css_computed_border_left_color(cell->style, &a.c);
css_computed_border_left_width(cell->style, &a.width, &a.unit);
- a.width = nscss_len2px(a.width, a.unit, cell->style);
+ a.width = nscss_len2px(len_ctx, a.width, a.unit, cell->style);
a.unit = CSS_UNIT_PX;
a_src = BOX_TABLE_CELL;
@@ -362,11 +398,12 @@ void table_used_left_border_for_cell(struct box *cell)
b.style = css_computed_border_right_style(prev->style);
b.color = css_computed_border_right_color(prev->style, &b.c);
css_computed_border_right_width(prev->style, &b.width, &b.unit);
- b.width = nscss_len2px(b.width, b.unit, prev->style);
+ b.width = nscss_len2px(len_ctx, b.width, b.unit, prev->style);
b.unit = CSS_UNIT_PX;
b_src = BOX_TABLE_CELL;
- if (table_border_is_more_eyecatching(&a, a_src, &b, b_src)) {
+ if (table_border_is_more_eyecatching(len_ctx,
+ &a, a_src, &b, b_src)) {
a = b;
a_src = b_src;
}
@@ -384,12 +421,13 @@ void table_used_left_border_for_cell(struct box *cell)
row->style, &b.c);
css_computed_border_left_width(
row->style, &b.width, &b.unit);
- b.width = nscss_len2px(b.width, b.unit, row->style);
+ b.width = nscss_len2px(len_ctx,
+ b.width, b.unit, row->style);
b.unit = CSS_UNIT_PX;
b_src = BOX_TABLE_ROW;
-
- if (table_border_is_more_eyecatching(&a, a_src,
- &b, b_src)) {
+
+ if (table_border_is_more_eyecatching(len_ctx,
+ &a, a_src, &b, b_src)) {
a = b;
a_src = b_src;
}
@@ -403,11 +441,12 @@ void table_used_left_border_for_cell(struct box *cell)
b.style = css_computed_border_left_style(group->style);
b.color = css_computed_border_left_color(group->style, &b.c);
css_computed_border_left_width(group->style, &b.width, &b.unit);
- b.width = nscss_len2px(b.width, b.unit, group->style);
+ b.width = nscss_len2px(len_ctx, b.width, b.unit, group->style);
b.unit = CSS_UNIT_PX;
b_src = BOX_TABLE_ROW_GROUP;
- if (table_border_is_more_eyecatching(&a, a_src, &b, b_src)) {
+ if (table_border_is_more_eyecatching(len_ctx,
+ &a, a_src, &b, b_src)) {
a = b;
a_src = b_src;
}
@@ -416,11 +455,12 @@ void table_used_left_border_for_cell(struct box *cell)
b.style = css_computed_border_left_style(table->style);
b.color = css_computed_border_left_color(table->style, &b.c);
css_computed_border_left_width(table->style, &b.width, &b.unit);
- b.width = nscss_len2px(b.width, b.unit, table->style);
+ b.width = nscss_len2px(len_ctx, b.width, b.unit, table->style);
b.unit = CSS_UNIT_PX;
b_src = BOX_TABLE;
- if (table_border_is_more_eyecatching(&a, a_src, &b, b_src)) {
+ if (table_border_is_more_eyecatching(len_ctx,
+ &a, a_src, &b, b_src)) {
a = b;
a_src = b_src;
}
@@ -429,16 +469,19 @@ void table_used_left_border_for_cell(struct box *cell)
/* a now contains the used left border for the cell */
cell->border[LEFT].style = a.style;
cell->border[LEFT].c = a.c;
- cell->border[LEFT].width =
- FIXTOINT(nscss_len2px(a.width, a.unit, cell->style));
+ cell->border[LEFT].width = FIXTOINT(nscss_len2px(len_ctx,
+ a.width, a.unit, cell->style));
}
/**
* Calculate used values of border-top-{style,color,width}
*
- * \param cell Table cell to consider
+ * \param len_ctx Length conversion context
+ * \param cell Table cell to consider
*/
-void table_used_top_border_for_cell(struct box *cell)
+void table_used_top_border_for_cell(
+ const nscss_len_ctx *len_ctx,
+ struct box *cell)
{
struct border a, b;
box_type a_src, b_src;
@@ -449,7 +492,7 @@ void table_used_top_border_for_cell(struct box *cell)
a.style = css_computed_border_top_style(cell->style);
css_computed_border_top_color(cell->style, &a.c);
css_computed_border_top_width(cell->style, &a.width, &a.unit);
- a.width = nscss_len2px(a.width, a.unit, cell->style);
+ a.width = nscss_len2px(len_ctx, a.width, a.unit, cell->style);
a.unit = CSS_UNIT_PX;
a_src = BOX_TABLE_CELL;
@@ -457,18 +500,18 @@ void table_used_top_border_for_cell(struct box *cell)
b.style = css_computed_border_top_style(row->style);
css_computed_border_top_color(row->style, &b.c);
css_computed_border_top_width(row->style, &b.width, &b.unit);
- b.width = nscss_len2px(b.width, b.unit, row->style);
+ b.width = nscss_len2px(len_ctx, b.width, b.unit, row->style);
b.unit = CSS_UNIT_PX;
b_src = BOX_TABLE_ROW;
- if (table_border_is_more_eyecatching(&a, a_src, &b, b_src)) {
+ if (table_border_is_more_eyecatching(len_ctx, &a, a_src, &b, b_src)) {
a = b;
a_src = b_src;
}
if (row->prev != NULL) {
/* Consider row(s) above */
- while (table_cell_top_process_row(cell, row->prev,
+ while (table_cell_top_process_row(len_ctx, cell, row->prev,
&a, &a_src) == false) {
if (row->prev->prev == NULL) {
/* Consider row group */
@@ -489,26 +532,29 @@ void table_used_top_border_for_cell(struct box *cell)
b.style = css_computed_border_top_style(group->style);
b.color = css_computed_border_top_color(group->style, &b.c);
css_computed_border_top_width(group->style, &b.width, &b.unit);
- b.width = nscss_len2px(b.width, b.unit, group->style);
+ b.width = nscss_len2px(len_ctx, b.width, b.unit, group->style);
b.unit = CSS_UNIT_PX;
b_src = BOX_TABLE_ROW_GROUP;
- if (table_border_is_more_eyecatching(&a, a_src, &b, b_src)) {
+ if (table_border_is_more_eyecatching(len_ctx,
+ &a, a_src, &b, b_src)) {
a = b;
a_src = b_src;
}
if (group->prev == NULL) {
/* Top border of table */
- table_cell_top_process_table(group->parent, &a, &a_src);
+ table_cell_top_process_table(len_ctx,
+ group->parent, &a, &a_src);
} else {
/* Process previous group(s) */
- while (table_cell_top_process_group(cell, group->prev,
+ while (table_cell_top_process_group(len_ctx,
+ cell, group->prev,
&a, &a_src) == false) {
if (group->prev->prev == NULL) {
/* Top border of table */
- table_cell_top_process_table(
- group->parent,
+ table_cell_top_process_table(len_ctx,
+ group->parent,
&a, &a_src);
break;
} else {
@@ -521,16 +567,19 @@ void table_used_top_border_for_cell(struct box *cell)
/* a now contains the used top border for the cell */
cell->border[TOP].style = a.style;
cell->border[TOP].c = a.c;
- cell->border[TOP].width =
- FIXTOINT(nscss_len2px(a.width, a.unit, cell->style));
+ cell->border[TOP].width = FIXTOINT(nscss_len2px(len_ctx,
+ a.width, a.unit, cell->style));
}
/**
* Calculate used values of border-right-{style,color,width}
*
- * \param cell Table cell to consider
+ * \param len_ctx Length conversion context
+ * \param cell Table cell to consider
*/
-void table_used_right_border_for_cell(struct box *cell)
+void table_used_right_border_for_cell(
+ const nscss_len_ctx *len_ctx,
+ struct box *cell)
{
struct border a, b;
box_type a_src, b_src;
@@ -541,7 +590,7 @@ void table_used_right_border_for_cell(struct box *cell)
a.style = css_computed_border_right_style(cell->style);
css_computed_border_right_color(cell->style, &a.c);
css_computed_border_right_width(cell->style, &a.width, &a.unit);
- a.width = nscss_len2px(a.width, a.unit, cell->style);
+ a.width = nscss_len2px(len_ctx, a.width, a.unit, cell->style);
a.unit = CSS_UNIT_PX;
a_src = BOX_TABLE_CELL;
@@ -565,12 +614,13 @@ void table_used_right_border_for_cell(struct box *cell)
row->style, &b.c);
css_computed_border_right_width(
row->style, &b.width, &b.unit);
- b.width = nscss_len2px(b.width, b.unit, row->style);
+ b.width = nscss_len2px(len_ctx,
+ b.width, b.unit, row->style);
b.unit = CSS_UNIT_PX;
b_src = BOX_TABLE_ROW;
-
- if (table_border_is_more_eyecatching(&a, a_src,
- &b, b_src)) {
+
+ if (table_border_is_more_eyecatching(len_ctx,
+ &a, a_src, &b, b_src)) {
a = b;
a_src = b_src;
}
@@ -583,13 +633,14 @@ void table_used_right_border_for_cell(struct box *cell)
/* Row group -- consider its right border */
b.style = css_computed_border_right_style(group->style);
b.color = css_computed_border_right_color(group->style, &b.c);
- css_computed_border_right_width(group->style,
+ css_computed_border_right_width(group->style,
&b.width, &b.unit);
- b.width = nscss_len2px(b.width, b.unit, group->style);
+ b.width = nscss_len2px(len_ctx, b.width, b.unit, group->style);
b.unit = CSS_UNIT_PX;
b_src = BOX_TABLE_ROW_GROUP;
- if (table_border_is_more_eyecatching(&a, a_src, &b, b_src)) {
+ if (table_border_is_more_eyecatching(len_ctx,
+ &a, a_src, &b, b_src)) {
a = b;
a_src = b_src;
}
@@ -599,11 +650,12 @@ void table_used_right_border_for_cell(struct box *cell)
b.color = css_computed_border_right_color(table->style, &b.c);
css_computed_border_right_width(table->style,
&b.width, &b.unit);
- b.width = nscss_len2px(b.width, b.unit, table->style);
+ b.width = nscss_len2px(len_ctx, b.width, b.unit, table->style);
b.unit = CSS_UNIT_PX;
b_src = BOX_TABLE;
- if (table_border_is_more_eyecatching(&a, a_src, &b, b_src)) {
+ if (table_border_is_more_eyecatching(len_ctx,
+ &a, a_src, &b, b_src)) {
a = b;
a_src = b_src;
}
@@ -612,16 +664,19 @@ void table_used_right_border_for_cell(struct box *cell)
/* a now contains the used right border for the cell */
cell->border[RIGHT].style = a.style;
cell->border[RIGHT].c = a.c;
- cell->border[RIGHT].width =
- FIXTOINT(nscss_len2px(a.width, a.unit, cell->style));
+ cell->border[RIGHT].width = FIXTOINT(nscss_len2px(len_ctx,
+ a.width, a.unit, cell->style));
}
/**
* Calculate used values of border-bottom-{style,color,width}
*
- * \param cell Table cell to consider
+ * \param len_ctx Length conversion context
+ * \param cell Table cell to consider
*/
-void table_used_bottom_border_for_cell(struct box *cell)
+void table_used_bottom_border_for_cell(
+ const nscss_len_ctx *len_ctx,
+ struct box *cell)
{
struct border a, b;
box_type a_src, b_src;
@@ -632,7 +687,7 @@ void table_used_bottom_border_for_cell(struct box *cell)
a.style = css_computed_border_bottom_style(cell->style);
css_computed_border_bottom_color(cell->style, &a.c);
css_computed_border_bottom_width(cell->style, &a.width, &a.unit);
- a.width = nscss_len2px(a.width, a.unit, cell->style);
+ a.width = nscss_len2px(len_ctx, a.width, a.unit, cell->style);
a.unit = CSS_UNIT_PX;
a_src = BOX_TABLE_CELL;
@@ -656,11 +711,12 @@ void table_used_bottom_border_for_cell(struct box *cell)
b.style = css_computed_border_bottom_style(row->style);
b.color = css_computed_border_bottom_color(row->style, &b.c);
css_computed_border_bottom_width(row->style, &b.width, &b.unit);
- b.width = nscss_len2px(b.width, b.unit, row->style);
+ b.width = nscss_len2px(len_ctx, b.width, b.unit, row->style);
b.unit = CSS_UNIT_PX;
b_src = BOX_TABLE_ROW;
- if (table_border_is_more_eyecatching(&a, a_src, &b, b_src)) {
+ if (table_border_is_more_eyecatching(len_ctx,
+ &a, a_src, &b, b_src)) {
a = b;
a_src = b_src;
}
@@ -670,11 +726,12 @@ void table_used_bottom_border_for_cell(struct box *cell)
b.color = css_computed_border_bottom_color(group->style, &b.c);
css_computed_border_bottom_width(group->style,
&b.width, &b.unit);
- b.width = nscss_len2px(b.width, b.unit, group->style);
+ b.width = nscss_len2px(len_ctx, b.width, b.unit, group->style);
b.unit = CSS_UNIT_PX;
b_src = BOX_TABLE_ROW_GROUP;
- if (table_border_is_more_eyecatching(&a, a_src, &b, b_src)) {
+ if (table_border_is_more_eyecatching(len_ctx,
+ &a, a_src, &b, b_src)) {
a = b;
a_src = b_src;
}
@@ -684,11 +741,12 @@ void table_used_bottom_border_for_cell(struct box *cell)
b.color = css_computed_border_bottom_color(table->style, &b.c);
css_computed_border_bottom_width(table->style,
&b.width, &b.unit);
- b.width = nscss_len2px(b.width, b.unit, table->style);
+ b.width = nscss_len2px(len_ctx, b.width, b.unit, table->style);
b.unit = CSS_UNIT_PX;
b_src = BOX_TABLE;
- if (table_border_is_more_eyecatching(&a, a_src, &b, b_src)) {
+ if (table_border_is_more_eyecatching(len_ctx,
+ &a, a_src, &b, b_src)) {
a = b;
}
}
@@ -696,21 +754,26 @@ void table_used_bottom_border_for_cell(struct box *cell)
/* a now contains the used bottom border for the cell */
cell->border[BOTTOM].style = a.style;
cell->border[BOTTOM].c = a.c;
- cell->border[BOTTOM].width =
- FIXTOINT(nscss_len2px(a.width, a.unit, cell->style));
+ cell->border[BOTTOM].width = FIXTOINT(nscss_len2px(len_ctx,
+ a.width, a.unit, cell->style));
}
/**
* Determine if a border style is more eyecatching than another
*
- * \param a Reference border style
- * \param a_src Source of \a a
- * \param b Candidate border style
- * \param b_src Source of \a b
+ * \param len_ctx Length conversion context
+ * \param a Reference border style
+ * \param a_src Source of \a a
+ * \param b Candidate border style
+ * \param b_src Source of \a b
* \return True if \a b is more eyecatching than \a a
*/
-bool table_border_is_more_eyecatching(const struct border *a,
- box_type a_src, const struct border *b, box_type b_src)
+bool table_border_is_more_eyecatching(
+ const nscss_len_ctx *len_ctx,
+ const struct border *a,
+ box_type a_src,
+ const struct border *b,
+ box_type b_src)
{
css_fixed awidth, bwidth;
int impact = 0;
@@ -731,8 +794,8 @@ bool table_border_is_more_eyecatching(const struct border *a,
* if they've come from a computed style. */
assert(a->unit != CSS_UNIT_EM && a->unit != CSS_UNIT_EX);
assert(b->unit != CSS_UNIT_EM && b->unit != CSS_UNIT_EX);
- awidth = nscss_len2px(a->width, a->unit, NULL);
- bwidth = nscss_len2px(b->width, b->unit, NULL);
+ awidth = nscss_len2px(len_ctx, a->width, a->unit, NULL);
+ bwidth = nscss_len2px(len_ctx, b->width, b->unit, NULL);
if (awidth < bwidth)
return true;
@@ -811,14 +874,18 @@ bool table_border_is_more_eyecatching(const struct border *a,
/**
* Process a table
*
- * \param table Table to process
- * \param a Current border style for cell
- * \param a_src Source of \a a
+ * \param len_ctx Length conversion context
+ * \param table Table to process
+ * \param a Current border style for cell
+ * \param a_src Source of \a a
*
* \post \a a will be updated with most eyecatching style
* \post \a a_src will be updated also
*/
-void table_cell_top_process_table(struct box *table, struct border *a,
+void table_cell_top_process_table(
+ const nscss_len_ctx *len_ctx,
+ struct box *table,
+ struct border *a,
box_type *a_src)
{
struct border b;
@@ -828,11 +895,11 @@ void table_cell_top_process_table(struct box *table, struct border *a,
b.style = css_computed_border_top_style(table->style);
b.color = css_computed_border_top_color(table->style, &b.c);
css_computed_border_top_width(table->style, &b.width, &b.unit);
- b.width = nscss_len2px(b.width, b.unit, table->style);
+ b.width = nscss_len2px(len_ctx, b.width, b.unit, table->style);
b.unit = CSS_UNIT_PX;
b_src = BOX_TABLE;
- if (table_border_is_more_eyecatching(a, *a_src, &b, b_src)) {
+ if (table_border_is_more_eyecatching(len_ctx, a, *a_src, &b, b_src)) {
*a = b;
*a_src = b_src;
}
@@ -841,17 +908,22 @@ void table_cell_top_process_table(struct box *table, struct border *a,
/**
* Process a group
*
- * \param cell Cell being considered
- * \param group Group to process
- * \param a Current border style for cell
- * \param a_src Source of \a a
+ * \param len_ctx Length conversion context
+ * \param cell Cell being considered
+ * \param group Group to process
+ * \param a Current border style for cell
+ * \param a_src Source of \a a
* \return true if group has non-empty rows, false otherwise
*
* \post \a a will be updated with most eyecatching style
* \post \a a_src will be updated also
*/
-bool table_cell_top_process_group(struct box *cell, struct box *group,
- struct border *a, box_type *a_src)
+bool table_cell_top_process_group(
+ const nscss_len_ctx *len_ctx,
+ struct box *cell,
+ struct box *group,
+ struct border *a,
+ box_type *a_src)
{
struct border b;
box_type b_src;
@@ -860,11 +932,11 @@ bool table_cell_top_process_group(struct box *cell, struct box *group,
b.style = css_computed_border_bottom_style(group->style);
b.color = css_computed_border_bottom_color(group->style, &b.c);
css_computed_border_bottom_width(group->style, &b.width, &b.unit);
- b.width = nscss_len2px(b.width, b.unit, group->style);
+ b.width = nscss_len2px(len_ctx, b.width, b.unit, group->style);
b.unit = CSS_UNIT_PX;
b_src = BOX_TABLE_ROW_GROUP;
- if (table_border_is_more_eyecatching(a, *a_src, &b, b_src)) {
+ if (table_border_is_more_eyecatching(len_ctx, a, *a_src, &b, b_src)) {
*a = b;
*a_src = b_src;
}
@@ -873,7 +945,7 @@ bool table_cell_top_process_group(struct box *cell, struct box *group,
/* Process rows in group, starting with last */
struct box *row = group->last;
- while (table_cell_top_process_row(cell, row,
+ while (table_cell_top_process_row(len_ctx, cell, row,
a, a_src) == false) {
if (row->prev == NULL) {
return false;
@@ -886,11 +958,12 @@ bool table_cell_top_process_group(struct box *cell, struct box *group,
b.style = css_computed_border_top_style(group->style);
b.color = css_computed_border_top_color(group->style, &b.c);
css_computed_border_top_width(group->style, &b.width, &b.unit);
- b.width = nscss_len2px(b.width, b.unit, group->style);
+ b.width = nscss_len2px(len_ctx, b.width, b.unit, group->style);
b.unit = CSS_UNIT_PX;
b_src = BOX_TABLE_ROW_GROUP;
- if (table_border_is_more_eyecatching(a, *a_src, &b, b_src)) {
+ if (table_border_is_more_eyecatching(len_ctx,
+ a, *a_src, &b, b_src)) {
*a = b;
*a_src = b_src;
}
@@ -904,17 +977,22 @@ bool table_cell_top_process_group(struct box *cell, struct box *group,
/**
* Process a row
*
- * \param cell Cell being considered
- * \param row Row to process
- * \param a Current border style for cell
- * \param a_src Source of \a a
+ * \param len_ctx Length conversion context
+ * \param cell Cell being considered
+ * \param row Row to process
+ * \param a Current border style for cell
+ * \param a_src Source of \a a
* \return true if row has cells, false otherwise
*
* \post \a a will be updated with most eyecatching style
* \post \a a_src will be updated also
*/
-bool table_cell_top_process_row(struct box *cell, struct box *row,
- struct border *a, box_type *a_src)
+bool table_cell_top_process_row(
+ const nscss_len_ctx *len_ctx,
+ struct box *cell,
+ struct box *row,
+ struct border *a,
+ box_type *a_src)
{
struct border b;
box_type b_src;
@@ -923,11 +1001,11 @@ bool table_cell_top_process_row(struct box *cell, struct box *row,
b.style = css_computed_border_bottom_style(row->style);
b.color = css_computed_border_bottom_color(row->style, &b.c);
css_computed_border_bottom_width(row->style, &b.width, &b.unit);
- b.width = nscss_len2px(b.width, b.unit, row->style);
+ b.width = nscss_len2px(len_ctx, b.width, b.unit, row->style);
b.unit = CSS_UNIT_PX;
b_src = BOX_TABLE_ROW;
- if (table_border_is_more_eyecatching(a, *a_src, &b, b_src)) {
+ if (table_border_is_more_eyecatching(len_ctx, a, *a_src, &b, b_src)) {
*a = b;
*a_src = b_src;
}
@@ -937,11 +1015,12 @@ bool table_cell_top_process_row(struct box *cell, struct box *row,
b.style = css_computed_border_top_style(row->style);
b.color = css_computed_border_top_color(row->style, &b.c);
css_computed_border_top_width(row->style, &b.width, &b.unit);
- b.width = nscss_len2px(b.width, b.unit, row->style);
+ b.width = nscss_len2px(len_ctx, b.width, b.unit, row->style);
b.unit = CSS_UNIT_PX;
b_src = BOX_TABLE_ROW;
- if (table_border_is_more_eyecatching(a, *a_src, &b, b_src)) {
+ if (table_border_is_more_eyecatching(len_ctx,
+ a, *a_src, &b, b_src)) {
*a = b;
*a_src = b_src;
}
@@ -975,13 +1054,13 @@ bool table_cell_top_process_row(struct box *cell, struct box *row,
c->style, &b.c);
css_computed_border_bottom_width(c->style,
&b.width, &b.unit);
- b.width = nscss_len2px(b.width, b.unit,
- c->style);
+ b.width = nscss_len2px(len_ctx,
+ b.width, b.unit, c->style);
b.unit = CSS_UNIT_PX;
b_src = BOX_TABLE_CELL;
- if (table_border_is_more_eyecatching(a, *a_src,
- &b, b_src)) {
+ if (table_border_is_more_eyecatching(len_ctx,
+ a, *a_src, &b, b_src)) {
*a = b;
*a_src = b_src;
}
diff --git a/render/table.h b/render/table.h
index ecd3043b5..2eeffe699 100644
--- a/render/table.h
+++ b/render/table.h
@@ -28,7 +28,11 @@
struct box;
-bool table_calculate_column_types(struct box *table);
-void table_used_border_for_cell(struct box *cell);
+bool table_calculate_column_types(
+ const nscss_len_ctx *len_ctx,
+ struct box *table);
+void table_used_border_for_cell(
+ const nscss_len_ctx *len_ctx,
+ struct box *cell);
#endif
diff --git a/render/textplain.c b/render/textplain.c
index ab2d55955..0036eb5c0 100644
--- a/render/textplain.c
+++ b/render/textplain.c
@@ -988,7 +988,7 @@ textplain_open(struct content *c,
text->bw = bw;
/* text selection */
- selection_init(&text->sel, NULL);
+ selection_init(&text->sel, NULL, NULL);
}