Gitweb links:

...log 
http://git.netsurf-browser.org/netsurf.git/shortlog/9140d8815ce53a7d663efb3fea30a6ea5b040299
...commit 
http://git.netsurf-browser.org/netsurf.git/commit/9140d8815ce53a7d663efb3fea30a6ea5b040299
...tree 
http://git.netsurf-browser.org/netsurf.git/tree/9140d8815ce53a7d663efb3fea30a6ea5b040299

The branch, tlsa/libcss-units has been updated
  discards  1d6096002395e0db79e7fd86b6bd1e07e6853079 (commit)
       via  9140d8815ce53a7d663efb3fea30a6ea5b040299 (commit)

This update added new revisions after undoing existing revisions.  That is
to say, the old revision is not a strict subset of the new revision.  This
situation occurs when you --force push a change and generate a repository
containing something like this:

 * -- * -- B -- O -- O -- O (1d6096002395e0db79e7fd86b6bd1e07e6853079)
            \
             N -- N -- N (9140d8815ce53a7d663efb3fea30a6ea5b040299)

When this happens we assume that you've already had alert emails for all
of the O revisions, and so we here report only the revisions in the N
branch from the common base, B.

Those revisions listed above that are new to this repository have
not appeared on any other notification email; so we list those
revisions in full, below.

- Log -----------------------------------------------------------------
commitdiff 
http://git.netsurf-browser.org/netsurf.git/commit/?id=9140d8815ce53a7d663efb3fea30a6ea5b040299
commit 9140d8815ce53a7d663efb3fea30a6ea5b040299
Author: Michael Drake <[email protected]>
Commit: Michael Drake <[email protected]>

    CSS utils: Handle new units in length conversion routines.
    
    This causes a ripple effect of all the callsites needing
    information they didn't have.

diff --git a/content/handlers/css/utils.c b/content/handlers/css/utils.c
index 5c7cbd9..8fe157b 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 21cb497..c8f4c82 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 54cc545..5c0333a 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 7506af0..5cb43b8 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 e2bc3b3..2f3f6dc 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 149ca26..3fd4c98 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 b386e50..82e0de9 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 8b9c89e..c97e898 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 8208a6f..1af0a8b 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);
diff --git a/render/box_normalise.c b/render/box_normalise.c
index 9c0875b..8da2457 100644
--- a/render/box_normalise.c
+++ b/render/box_normalise.c
@@ -422,9 +422,6 @@ bool box_normalise_table(
 
        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
diff --git a/render/box_textarea.c b/render/box_textarea.c
index 3b1e775..a609842 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 94ef877..a769b47 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 fba368a..52f5a62 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 904272d..4320025 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 3cfc5e2..b7d7aa3 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 30adaa0..2d14ed2 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 2f84cf8..66ecb2b 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 e98bdba..fb9e7b0 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 2f87306..9a97e5e 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 83dbc53..15eb1e8 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,7 +290,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));
                }
        }
 }
@@ -290,19 +302,20 @@ calculate_mbp_width(const css_computed_style *style,
  *
  * \param table box of type TABLE
  * \param font_func Font functions
- * \param content  The HTML content being layed out.
+ * \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)
+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 = table->col;
+       struct column *col;
        struct box *row_group, *row, *cell;
        enum css_width_e wtype;
        css_fixed value = 0;
@@ -312,6 +325,13 @@ layout_minmax_table(struct box *table, const struct 
gui_layout_table *font_func)
        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)
@@ -328,7 +348,8 @@ layout_minmax_table(struct box *table, const struct 
gui_layout_table *font_func)
 
                css_computed_border_spacing(table->style, &h, &hu, &v, &vu);
 
-               border_spacing_h = FIXTOINT(nscss_len2px(h, hu, table->style));
+               border_spacing_h = FIXTOINT(nscss_len2px(&content->len_ctx,
+                               h, hu, table->style));
        }
 
        /* 1st pass: consider cells with colspan 1 only */
@@ -344,7 +365,7 @@ layout_minmax_table(struct box *table, const struct 
gui_layout_table *font_func)
                if (cell->columns != 1)
                        continue;
 
-               layout_minmax_block(cell, font_func);
+               layout_minmax_block(cell, font_func, content);
                i = cell->start_column;
 
                if (col[i].positioned)
@@ -367,7 +388,7 @@ layout_minmax_table(struct box *table, const struct 
gui_layout_table *font_func)
                if (cell->columns == 1)
                        continue;
 
-               layout_minmax_block(cell, font_func);
+               layout_minmax_block(cell, font_func, content);
                i = cell->start_column;
 
                /* find min width so far of spanned columns, and count
@@ -433,7 +454,8 @@ layout_minmax_table(struct box *table, const struct 
gui_layout_table *font_func)
        /* 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));
+               int width = FIXTOINT(nscss_len2px(&content->len_ctx,
+                               value, unit, table->style));
                if (table_min < width)
                        table_min = width;
                if (table_max < width)
@@ -441,9 +463,11 @@ layout_minmax_table(struct box *table, const struct 
gui_layout_table *font_func)
        }
 
        /* add margins, border, padding to min, max widths */
-       calculate_mbp_width(table->style, LEFT, true, true, true,
+       calculate_mbp_width(&content->len_ctx,
+                       table->style, LEFT, true, true, true,
                        &extra_fixed, &extra_frac);
-       calculate_mbp_width(table->style, RIGHT, true, true, true,
+       calculate_mbp_width(&content->len_ctx,
+                       table->style, RIGHT, true, true, true,
                        &extra_fixed, &extra_frac);
        if (extra_fixed < 0)
                extra_fixed = 0;
@@ -478,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;
@@ -524,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)
@@ -536,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;
@@ -547,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)
@@ -565,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)
@@ -686,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) {
@@ -711,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;
                }
@@ -727,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);
                        }
@@ -750,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);
                        }
@@ -771,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)
@@ -785,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;
@@ -815,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;
@@ -833,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)
@@ -856,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;
@@ -913,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;
        }
@@ -926,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;
        }
@@ -934,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 {
@@ -951,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;
@@ -960,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) {
@@ -968,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;
@@ -1006,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) {
@@ -1033,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)
@@ -1070,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,
@@ -1079,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,
@@ -1095,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;
@@ -1108,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
@@ -1124,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,
@@ -1153,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);
                }
        }
@@ -1241,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);
                }
        }
@@ -1266,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 */
@@ -1275,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);
                }
        }
@@ -1292,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 */
@@ -1301,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);
                }
        }
@@ -1318,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 */
@@ -1339,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 */
@@ -1378,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;
@@ -1411,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));
                        }
                }
 
@@ -1459,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. */
@@ -1478,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
@@ -1486,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,
@@ -1505,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,
@@ -1579,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,
@@ -1815,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.
@@ -1827,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,
@@ -1840,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) &&
@@ -1994,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) {
@@ -2004,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);
@@ -2034,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 */
@@ -2045,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 */
@@ -2123,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));
                }
        }
 
@@ -2313,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);
@@ -2351,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;
                                }
@@ -2496,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;
@@ -2560,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;
@@ -2590,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;
@@ -2759,6 +2845,7 @@ layout_text_box_split(html_content *content,
  * 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
@@ -2766,9 +2853,11 @@ layout_text_box_split(html_content *content,
  *                             height are updated.
  */
 static void
-layout_float_find_dimensions(int available_width,
-                            const css_computed_style *style,
-                            struct box *box)
+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;
@@ -2785,9 +2874,9 @@ layout_float_find_dimensions(int available_width,
                         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);
+       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;
@@ -2821,26 +2910,26 @@ layout_float_find_dimensions(int available_width,
                                box->gadget->type == GADGET_FILE) {
                        if (width == AUTO) {
                                size = INTTOFIX(10);
-                               width = FIXTOINT(nscss_len2px(size, unit,
-                                               box->style));
+                               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(size, unit,
-                                               box->style));
+                               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(size, unit,
-                                               box->style));
+                               width = FIXTOINT(nscss_len2px(len_ctx,
+                                               size, unit, box->style));
                        }
                        if (height == AUTO) {
                                size = INTTOFIX(4);
-                               height = FIXTOINT(nscss_len2px(size, unit,
-                                               box->style));
+                               height = FIXTOINT(nscss_len2px(len_ctx,
+                                               size, unit, box->style));
                        }
                }
        } else if (width == AUTO) {
@@ -2861,10 +2950,10 @@ layout_float_find_dimensions(int available_width,
                         * 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);
+                       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;
 
@@ -2902,7 +2991,7 @@ 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);
+       layout_float_find_dimensions(&content->len_ctx, width, b->style, b);
        if (b->type == BOX_TABLE) {
                if (!layout_table(b, width, content))
                        return false;
@@ -2974,7 +3063,9 @@ place_float_below(struct box *c, int width, int cx, int 
y, struct box *cont)
 /**
  * Calculate line height from a style.
  */
-static int line_height(const css_computed_style *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;
@@ -2992,14 +3083,16 @@ static int line_height(const css_computed_style *style)
 
        if (lhtype == CSS_LINE_HEIGHT_NUMBER ||
                        lhunit == CSS_UNIT_PCT) {
-               line_height = nscss_len2px(lhvalue, CSS_UNIT_EM, style);
+               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(lhvalue, lhunit, style);
+               line_height = nscss_len2px(len_ctx,
+                               lhvalue, lhunit, style);
        }
 
        return FIXTOINT(line_height);
@@ -3071,7 +3164,8 @@ layout_line(struct box *first,
        x1 -= cx;
 
        if (indent)
-               x0 += layout_text_indent(first->parent->parent->style, *width);
+               x0 += layout_text_indent(&content->len_ctx,
+                               first->parent->parent->style, *width);
 
        if (x1 < x0)
                x1 = x0;
@@ -3080,8 +3174,8 @@ layout_line(struct box *first,
         * 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);
+               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 */
@@ -3120,7 +3214,7 @@ layout_line(struct box *first,
                        continue;
 
                assert(b->style != NULL);
-               font_plot_style_from_css(b->style, &fstyle);
+               font_plot_style_from_css(&content->len_ctx, b->style, &fstyle);
 
                x += space_after;
 
@@ -3144,9 +3238,9 @@ layout_line(struct box *first,
 
                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);
+                       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;
@@ -3179,7 +3273,8 @@ layout_line(struct box *first,
                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->height = line_height(&content->len_ctx,
+                                       b->style ? b->style :
                                        b->parent->parent->style);
                        if (height < b->height)
                                height = b->height;
@@ -3249,9 +3344,12 @@ layout_line(struct box *first,
                /* 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);
+               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,
@@ -3269,10 +3367,12 @@ layout_line(struct box *first,
                } else {
                        /* form control with no object */
                        if (b->width == AUTO)
-                               b->width = FIXTOINT(nscss_len2px(INTTOFIX(1),
+                               b->width = FIXTOINT(nscss_len2px(
+                                               &content->len_ctx, INTTOFIX(1),
                                                CSS_UNIT_EM, b->style));
                        if (b->height == AUTO)
-                               b->height = FIXTOINT(nscss_len2px(INTTOFIX(1),
+                               b->height = FIXTOINT(nscss_len2px(
+                                               &content->len_ctx, INTTOFIX(1),
                                                CSS_UNIT_EM, b->style));
                }
 
@@ -3306,7 +3406,8 @@ layout_line(struct box *first,
        x1 -= cx;
 
        if (indent)
-               x0 += layout_text_indent(first->parent->parent->style, *width);
+               x0 += layout_text_indent(&content->len_ctx,
+                               first->parent->parent->style, *width);
 
        if (x1 < x0)
                x1 = x0;
@@ -3363,8 +3464,9 @@ layout_line(struct box *first,
                                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);
+                                       font_plot_style_from_css(
+                                                       &content->len_ctx,
+                                                       b->style, &fstyle);
                                        /** \todo handle errors */
                                        font_func->width(&fstyle, " ", 1,
                                                         &b->space);
@@ -3517,7 +3619,8 @@ layout_line(struct box *first,
                    !(split_box->flags & IFRAME) &&
                    !split_box->gadget && split_box->text) {
 
-                       font_plot_style_from_css(split_box->style, &fstyle);
+                       font_plot_style_from_css(&content->len_ctx,
+                                       split_box->style, &fstyle);
                        /** \todo handle errors */
                        font_func->split(&fstyle,
                                         split_box->text,
@@ -3879,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));
        }
 
@@ -3943,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. */
@@ -3994,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);
@@ -4234,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 -
@@ -4291,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]);
        }
@@ -4317,7 +4428,8 @@ layout_block_context(struct box *block,
  */
 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;
@@ -4332,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,
@@ -4346,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;
@@ -4356,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);
        }
 }
 
@@ -4365,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
@@ -4375,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,
@@ -4397,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;
@@ -4410,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;
@@ -4424,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;
@@ -4437,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;
@@ -4494,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 */
@@ -4818,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;
 }
@@ -4895,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;
@@ -4916,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)
@@ -4964,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
@@ -4975,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
@@ -4999,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;
 
@@ -5035,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 &&
@@ -5064,6 +5195,7 @@ layout_position_relative(struct box *root, struct box 
*fp, int fx, int fy)
 /**
  * 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
@@ -5071,9 +5203,11 @@ layout_position_relative(struct box *root, struct box 
*fp, int fx, int fy)
  * \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;
@@ -5093,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;
        }
@@ -5103,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;
 
@@ -5132,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 &&
@@ -5169,9 +5308,12 @@ layout_update_descendant_bbox(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  box  tree of boxes to update
+ * \param  len_ctx  Length conversion context
+ * \param  box      tree of boxes to update
  */
-static void layout_calculate_descendant_bboxes(struct box *box)
+static void layout_calculate_descendant_bboxes(
+               const nscss_len_ctx *len_ctx,
+               struct box *box)
 {
        struct box *child;
 
@@ -5180,7 +5322,8 @@ static 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 */
@@ -5213,7 +5356,7 @@ static 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)
@@ -5231,7 +5374,7 @@ static 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 &&
@@ -5239,23 +5382,23 @@ static 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(box, child, 0, 0);
+               layout_update_descendant_bbox(len_ctx, box, child, 0, 0);
        }
 }
 
@@ -5267,9 +5410,10 @@ bool layout_document(html_content *content, int width, 
int height)
        struct box *doc = content->layout;
        const struct gui_layout_table *font_func = content->font_func;
 
-       layout_minmax_block(doc, font_func);
+       layout_minmax_block(doc, font_func, content);
 
-       layout_block_find_dimensions(width, height, 0, 0, doc);
+       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 +
@@ -5300,11 +5444,11 @@ bool layout_document(html_content *content, int width, 
int height)
                                         doc->children->margin[BOTTOM]);
        }
 
-       layout_lists(doc, font_func);
+       layout_lists(doc, font_func, &content->len_ctx);
        layout_position_absolute(doc, doc, 0, 0, content);
-       layout_position_relative(doc, doc, 0, 0);
+       layout_position_relative(&content->len_ctx, doc, doc, 0, 0);
 
-       layout_calculate_descendant_bboxes(doc);
+       layout_calculate_descendant_bboxes(&content->len_ctx, doc);
 
        return ret;
 }
diff --git a/render/search.c b/render/search.c
index 8f21d87..ca95201 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 c41b913..08a2e80 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 ecd3043..2eeffe6 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 ab2d559..0036eb5 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);
 }
 
 


-----------------------------------------------------------------------

Summary of changes:
 content/handlers/css/utils.c |    6 ++----
 desktop/selection.c          |   12 +++++++++++-
 desktop/selection.h          |    5 ++++-
 render/html.c                |    2 +-
 render/search.c              |    5 +++--
 render/textplain.c           |    2 +-
 6 files changed, 22 insertions(+), 10 deletions(-)

diff --git a/content/handlers/css/utils.c b/content/handlers/css/utils.c
index c0d9628..8fe157b 100644
--- a/content/handlers/css/utils.c
+++ b/content/handlers/css/utils.c
@@ -238,11 +238,9 @@ css_fixed nscss_len2px(
                                INTTOFIX(10)));
                break;
        case CSS_UNIT_VH:
-               px_per_unit = FDIV((length * ctx->vh), F_100);
-               break;
+               return TRUNCATEFIX((FDIV((length * ctx->vh), F_100) + F_0_5));
        case CSS_UNIT_VW:
-               px_per_unit = FDIV((length * ctx->vw), F_100);
-               break;
+               return TRUNCATEFIX((FDIV((length * ctx->vw), F_100) + F_0_5));
        default:
                px_per_unit = 0;
                break;
diff --git a/desktop/selection.c b/desktop/selection.c
index 9dc0b5c..5cb43b8 100644
--- a/desktop/selection.c
+++ b/desktop/selection.c
@@ -200,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);
@@ -209,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);
 }
diff --git a/desktop/selection.h b/desktop/selection.h
index 358879f..2f3f6dc 100644
--- a/desktop/selection.h
+++ b/desktop/selection.h
@@ -62,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/render/html.c b/render/html.c
index 7c2c985..b7d7aa3 100644
--- a/render/html.c
+++ b/render/html.c
@@ -1651,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;
 
diff --git a/render/search.c b/render/search.c
index 8f21d87..ca95201 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/textplain.c b/render/textplain.c
index ab2d559..0036eb5 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);
 }
 
 


-- 
NetSurf Browser

_______________________________________________
netsurf-commits mailing list
[email protected]
http://listmaster.pepperfish.net/cgi-bin/mailman/listinfo/netsurf-commits-netsurf-browser.org

Reply via email to