From 6be6fa1b2197ffe6e511c5eff9abe14d883f8478 Mon Sep 17 00:00:00 2001 From: Michael Drake Date: Wed, 3 Jan 2018 23:58:18 +0000 Subject: CSS utils: Handle new units in length conversion routines. This causes a ripple effect of all the callsites needing information they didn't have. --- content/handlers/css/utils.c | 144 ++++++++++++++++++++++++++++++++++++++++--- content/handlers/css/utils.h | 46 +++++++++++--- 2 files changed, 174 insertions(+), 16 deletions(-) (limited to 'content') diff --git a/content/handlers/css/utils.c b/content/handlers/css/utils.c index 5c7cbd9a7..8fe157bd2 100644 --- a/content/handlers/css/utils.c +++ b/content/handlers/css/utils.c @@ -27,11 +27,75 @@ /** Screen DPI in fixed point units: defaults to 90, which RISC OS uses */ css_fixed nscss_screen_dpi = F_90; + +/** + * Map viewport-relative length units to either vh or vw. + * + * Non-viewport-relative units are unchanged. + * + * \param[in] ctx Length conversion context. + * \param[in] unit Unit to map. + * \return the mapped unit. + */ +static inline css_unit css_utils__fudge_viewport_units( + const nscss_len_ctx *ctx, + css_unit unit) +{ + switch (unit) { + case CSS_UNIT_VI: + assert(ctx->root_style != NULL); + if (css_computed_writing_mode(ctx->root_style) == + CSS_WRITING_MODE_HORIZONTAL_TB) { + unit = CSS_UNIT_VW; + } else { + unit = CSS_UNIT_VH; + } + break; + case CSS_UNIT_VB: + assert(ctx->root_style != NULL); + if (css_computed_writing_mode(ctx->root_style) == + CSS_WRITING_MODE_HORIZONTAL_TB) { + unit = CSS_UNIT_VH; + } else { + unit = CSS_UNIT_VW; + } + break; + case CSS_UNIT_VMIN: + if (ctx->vh < ctx->vw) { + unit = CSS_UNIT_VH; + } else { + unit = CSS_UNIT_VW; + } + break; + case CSS_UNIT_VMAX: + if (ctx->vh > ctx->vw) { + unit = CSS_UNIT_VH; + } else { + unit = CSS_UNIT_VW; + } + break; + default: break; + } + + return unit; +} + /* exported interface documented in content/handlers/css/utils.h */ -css_fixed nscss_len2pt(css_fixed length, css_unit unit) +css_fixed nscss_len2pt( + const nscss_len_ctx *ctx, + css_fixed length, + css_unit unit) { /* Length must not be relative */ - assert(unit != CSS_UNIT_EM && unit != CSS_UNIT_EX); + assert(unit != CSS_UNIT_EM && + unit != CSS_UNIT_EX && + unit != CSS_UNIT_CAP && + unit != CSS_UNIT_CH && + unit != CSS_UNIT_IC && + unit != CSS_UNIT_REM && + unit != CSS_UNIT_RLH); + + unit = css_utils__fudge_viewport_units(ctx, unit); switch (unit) { /* We assume the screen and any other output has the same dpi */ @@ -45,36 +109,50 @@ css_fixed nscss_len2pt(css_fixed length, css_unit unit) /* 1in = 25.4mm => 1mm = (72/25.4)pt */ case CSS_UNIT_MM: return FMUL(length, FDIV(F_72, FLTTOFIX(25.4))); + /* 1in = 101.6q => 1mm = (72/101.6)pt */ + case CSS_UNIT_Q: return FMUL(length, + FDIV(F_72, FLTTOFIX(101.6))); case CSS_UNIT_PT: return length; /* 1pc = 12pt */ case CSS_UNIT_PC: return FMUL(length, INTTOFIX(12)); + case CSS_UNIT_VH: return FDIV(FMUL(FDIV((length * ctx->vh), F_100), + F_72), nscss_screen_dpi); + case CSS_UNIT_VW: return FDIV(FMUL(FDIV((length * ctx->vw), F_100), + F_72), nscss_screen_dpi); default: break; } return 0; } - /* exported interface documented in content/handlers/css/utils.h */ -css_fixed nscss_len2px(css_fixed length, css_unit unit, +css_fixed nscss_len2px( + const nscss_len_ctx *ctx, + css_fixed length, + css_unit unit, const css_computed_style *style) { /* We assume the screen and any other output has the same dpi */ css_fixed px_per_unit; - assert(style != NULL || (unit != CSS_UNIT_EM && unit != CSS_UNIT_EX)); + unit = css_utils__fudge_viewport_units(ctx, unit); switch (unit) { case CSS_UNIT_EM: case CSS_UNIT_EX: + case CSS_UNIT_CAP: + case CSS_UNIT_CH: + case CSS_UNIT_IC: { css_fixed font_size = 0; css_unit font_unit = CSS_UNIT_PT; + assert(style != NULL); + css_computed_font_size(style, &font_size, &font_unit); /* Convert to points */ - font_size = nscss_len2pt(font_size, font_unit); + font_size = nscss_len2pt(ctx, font_size, font_unit); /* Clamp to configured minimum */ if (font_size < FDIV(INTTOFIX(nsoption_int(font_min_size)), F_10)) { @@ -85,9 +163,22 @@ css_fixed nscss_len2px(css_fixed length, css_unit unit, * 1in = 72pt => 1pt = (DPI/72)px */ px_per_unit = FDIV(FMUL(font_size, nscss_screen_dpi), F_72); - /* Scale ex units: we use a fixed ratio of 1ex = 0.6em */ - if (unit == CSS_UNIT_EX) + /* Scale non-em units to em. We have fixed ratios. */ + switch (unit) { + case CSS_UNIT_EX: px_per_unit = FMUL(px_per_unit, FLTTOFIX(0.6)); + break; + case CSS_UNIT_CAP: + px_per_unit = FMUL(px_per_unit, FLTTOFIX(0.9)); + break; + case CSS_UNIT_CH: + px_per_unit = FMUL(px_per_unit, FLTTOFIX(0.4)); + break; + case CSS_UNIT_IC: + px_per_unit = FMUL(px_per_unit, FLTTOFIX(1.1)); + break; + default: break; + } } break; case CSS_UNIT_PX: @@ -105,6 +196,10 @@ css_fixed nscss_len2px(css_fixed length, css_unit unit, case CSS_UNIT_MM: px_per_unit = FDIV(nscss_screen_dpi, FLTTOFIX(25.4)); break; + /* 1in = 101.6q => 1q = (DPI/101.6)px */ + case CSS_UNIT_Q: + px_per_unit = FDIV(nscss_screen_dpi, FLTTOFIX(101.6)); + break; /* 1in = 72pt => 1pt = (DPI/72)px */ case CSS_UNIT_PT: px_per_unit = FDIV(nscss_screen_dpi, F_72); @@ -113,6 +208,39 @@ css_fixed nscss_len2px(css_fixed length, css_unit unit, case CSS_UNIT_PC: px_per_unit = FDIV(nscss_screen_dpi, INTTOFIX(6)); break; + case CSS_UNIT_REM: + { + css_fixed font_size = 0; + css_unit font_unit = CSS_UNIT_PT; + + assert(ctx->root_style != NULL); + + css_computed_font_size(ctx->root_style, + &font_size, &font_unit); + + /* Convert to points */ + font_size = nscss_len2pt(ctx, font_size, font_unit); + + /* Clamp to configured minimum */ + if (font_size < FDIV(INTTOFIX(nsoption_int(font_min_size)), F_10)) { + font_size = FDIV(INTTOFIX(nsoption_int(font_min_size)), F_10); + } + + /* Convert to pixels (manually, to maximise precision) + * 1in = 72pt => 1pt = (DPI/72)px */ + px_per_unit = FDIV(FMUL(font_size, nscss_screen_dpi), F_72); + break; + } + /* 1rlh = pt => 1rlh = (DPI/user_font_size)px */ + case CSS_UNIT_RLH: + px_per_unit = FDIV(nscss_screen_dpi, FDIV( + INTTOFIX(nsoption_int(font_size)), + INTTOFIX(10))); + break; + case CSS_UNIT_VH: + return TRUNCATEFIX((FDIV((length * ctx->vh), F_100) + F_0_5)); + case CSS_UNIT_VW: + return TRUNCATEFIX((FDIV((length * ctx->vw), F_100) + F_0_5)); default: px_per_unit = 0; break; diff --git a/content/handlers/css/utils.h b/content/handlers/css/utils.h index 21cb4973b..c8f4c82f4 100644 --- a/content/handlers/css/utils.h +++ b/content/handlers/css/utils.h @@ -26,25 +26,55 @@ /** DPI of the screen, in fixed point units */ 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); /** -- cgit v1.2.3