summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMichael Drake <tlsa@netsurf-browser.org>2021-03-04 21:22:06 +0000
committerMichael Drake <tlsa@netsurf-browser.org>2021-05-19 14:40:54 +0100
commit6cd205329373efe5a1629518c2875724cc79dce3 (patch)
treee9598f4e0ae907eacf43c391fb4b54a79059627f
parent0cf10a040aea028c7dc81cf353da7a7af5331076 (diff)
downloadlibcss-6cd205329373efe5a1629518c2875724cc79dce3.tar.gz
libcss-6cd205329373efe5a1629518c2875724cc79dce3.tar.bz2
Units: Add support for length unit conversion to libcss.
Currently only used for unit conversion.
-rw-r--r--src/select/Makefile2
-rw-r--r--src/select/hash.c2
-rw-r--r--src/select/mq.h103
-rw-r--r--src/select/unit.c498
-rw-r--r--src/select/unit.h169
5 files changed, 677 insertions, 97 deletions
diff --git a/src/select/Makefile b/src/select/Makefile
index 8b47673..f5ddb18 100644
--- a/src/select/Makefile
+++ b/src/select/Makefile
@@ -2,6 +2,6 @@
select_generator:
python3 src/select/select_generator.py
-DIR_SOURCES := arena.c computed.c dispatch.c hash.c select.c font_face.c format_list_style.c
+DIR_SOURCES := arena.c computed.c dispatch.c hash.c select.c font_face.c format_list_style.c unit.c
include $(NSBUILD)/Makefile.subdir
diff --git a/src/select/hash.c b/src/select/hash.c
index 4b11702..4dedec9 100644
--- a/src/select/hash.c
+++ b/src/select/hash.c
@@ -8,6 +8,8 @@
#include <stdio.h>
#include <string.h>
+#include <libcss/hint.h>
+
#include "stylesheet.h"
#include "select/hash.h"
#include "select/mq.h"
diff --git a/src/select/mq.h b/src/select/mq.h
index 6f98387..080a6ba 100644
--- a/src/select/mq.h
+++ b/src/select/mq.h
@@ -10,96 +10,7 @@
#define css_select_mq_h_
#include "select/helpers.h"
-
-static inline css_fixed css_len2px(
- css_fixed length,
- css_unit unit,
- const css_media *media)
-{
- css_fixed px_per_unit;
-
- switch (unit) {
- case CSS_UNIT_VI:
- /* TODO: Assumes writing mode. */
- unit = CSS_UNIT_VW;
- break;
- case CSS_UNIT_VB:
- /* TODO: Assumes writing mode. */
- unit = CSS_UNIT_VH;
- break;
- case CSS_UNIT_VMIN:
- unit = (media->height < media->width) ?
- CSS_UNIT_VH : CSS_UNIT_VW;
- break;
- case CSS_UNIT_VMAX:
- unit = (media->width > media->height) ?
- CSS_UNIT_VH : CSS_UNIT_VW;
- break;
- default:
- break;
- }
-
- switch (unit) {
- case CSS_UNIT_EM:
- case CSS_UNIT_EX:
- case CSS_UNIT_CH:
- {
- px_per_unit = FDIV(FMUL(media->client_font_size, F_96), F_72);
-
- /* TODO: Handling these as fixed ratios of CSS_UNIT_EM. */
- switch (unit) {
- case CSS_UNIT_EX:
- px_per_unit = FMUL(px_per_unit, FLTTOFIX(0.6));
- break;
- case CSS_UNIT_CH:
- px_per_unit = FMUL(px_per_unit, FLTTOFIX(0.4));
- break;
- default:
- break;
- }
- }
- break;
- case CSS_UNIT_PX:
- return length;
- case CSS_UNIT_IN:
- px_per_unit = F_96;
- break;
- case CSS_UNIT_CM:
- px_per_unit = FDIV(F_96, FLTTOFIX(2.54));
- break;
- case CSS_UNIT_MM:
- px_per_unit = FDIV(F_96, FLTTOFIX(25.4));
- break;
- case CSS_UNIT_Q:
- px_per_unit = FDIV(F_96, FLTTOFIX(101.6));
- break;
- case CSS_UNIT_PT:
- px_per_unit = FDIV(F_96, F_72);
- break;
- case CSS_UNIT_PC:
- px_per_unit = FDIV(F_96, INTTOFIX(6));
- break;
- case CSS_UNIT_REM:
- px_per_unit = FDIV(FMUL(media->client_font_size, F_96), F_72);
- break;
- case CSS_UNIT_VH:
- px_per_unit = FDIV(media->height, F_100);
- break;
- case CSS_UNIT_VW:
- px_per_unit = FDIV(media->width, F_100);
- break;
- default:
- px_per_unit = 0;
- break;
- }
-
- /* Ensure we round px_per_unit to the nearest whole number of pixels:
- * the use of FIXTOINT() below will truncate. */
- px_per_unit += F_0_5;
-
- /* Calculate total number of pixels */
- return FMUL(length, TRUNCATEFIX(px_per_unit));
-}
+#include "select/unit.h"
static inline bool mq_match_feature_range_length_op1(
css_mq_feature_op op,
@@ -114,9 +25,9 @@ static inline bool mq_match_feature_range_length_op1(
}
if (value->data.dim.unit != UNIT_PX) {
- v = css_len2px(value->data.dim.len,
- css__to_css_unit(value->data.dim.unit),
- media);
+ v = css_unit_len2px_mq(media,
+ value->data.dim.len,
+ css__to_css_unit(value->data.dim.unit));
} else {
v = value->data.dim.len;
}
@@ -149,9 +60,9 @@ static inline bool mq_match_feature_range_length_op2(
}
if (value->data.dim.unit != UNIT_PX) {
- v = css_len2px(value->data.dim.len,
- css__to_css_unit(value->data.dim.unit),
- media);
+ v = css_unit_len2px_mq(media,
+ value->data.dim.len,
+ css__to_css_unit(value->data.dim.unit));
} else {
v = value->data.dim.len;
}
diff --git a/src/select/unit.c b/src/select/unit.c
new file mode 100644
index 0000000..f9ecf83
--- /dev/null
+++ b/src/select/unit.c
@@ -0,0 +1,498 @@
+/*
+ * This file is part of LibCSS
+ * Licensed under the MIT License,
+ * http://www.opensource.org/licenses/mit-license.php
+ *
+ * Copyright 2021 Michael Drake <tlsa@netsurf-browser.org>
+ */
+
+#include <libcss/stylesheet.h>
+
+#include "utils/utils.h"
+
+#include "propget.h"
+#include "unit.h"
+
+/**
+ * Map viewport-relative length units to either vh or vw.
+ *
+ * Non-viewport-relative units are unchanged.
+ *
+ * \param[in] style Reference style.
+ * \param[in] viewport_height Viewport height in px.
+ * \param[in] viewport_width Viewport width in px.
+ * \param[in] unit Unit to map.
+ * \return the mapped unit.
+ */
+static inline css_unit css_unit__map_viewport_units(
+ const css_computed_style *style,
+ const css_fixed viewport_height,
+ const css_fixed viewport_width,
+ const css_unit unit)
+{
+ switch (unit) {
+ case CSS_UNIT_VI:
+ return (style != NULL && get_writing_mode(style) !=
+ CSS_WRITING_MODE_HORIZONTAL_TB) ?
+ CSS_UNIT_VH : CSS_UNIT_VW;
+
+ case CSS_UNIT_VB:
+ return (style != NULL && get_writing_mode(style) !=
+ CSS_WRITING_MODE_HORIZONTAL_TB) ?
+ CSS_UNIT_VW : CSS_UNIT_VH;
+
+ case CSS_UNIT_VMIN:
+ return (viewport_height < viewport_width) ?
+ CSS_UNIT_VH : CSS_UNIT_VW;
+
+ case CSS_UNIT_VMAX:
+ return (viewport_height > viewport_width) ?
+ CSS_UNIT_VH : CSS_UNIT_VW;
+
+ default:
+ return unit;
+ }
+}
+
+/**
+ * Convert an absolute length to points (pt).
+ *
+ * \param[in] style Style to get font-size from, or NULL.
+ * \param[in] viewport_height Client viewport height.
+ * \param[in] viewport_width Client viewport width.
+ * \param[in] length Length to convert.
+ * \param[in] unit Current unit of length.
+ * \return length in points (pt).
+ */
+static inline css_fixed css_unit__absolute_len2pt(
+ const css_computed_style *style,
+ const css_fixed viewport_height,
+ const css_fixed viewport_width,
+ const css_fixed length,
+ const css_unit unit)
+{
+ /* Length must not be relative */
+ assert(unit != CSS_UNIT_EM &&
+ unit != CSS_UNIT_EX &&
+ unit != CSS_UNIT_CH &&
+ unit != CSS_UNIT_REM);
+
+ switch (css_unit__map_viewport_units(style,
+ viewport_height,
+ viewport_width,
+ unit)) {
+ case CSS_UNIT_PX:
+ return FDIV(FMUL(length, F_72), F_96);
+
+ case CSS_UNIT_IN:
+ return FMUL(length, F_72);
+
+ case CSS_UNIT_CM:
+ return FMUL(length, FDIV(F_72, FLTTOFIX(2.54)));
+
+ case CSS_UNIT_MM:
+ return FMUL(length, FDIV(F_72, FLTTOFIX(25.4)));
+
+ case CSS_UNIT_Q:
+ return FMUL(length, FDIV(F_72, FLTTOFIX(101.6)));
+
+ case CSS_UNIT_PT:
+ return length;
+
+ case CSS_UNIT_PC:
+ return FMUL(length, INTTOFIX(12));
+
+ case CSS_UNIT_VH:
+ return FDIV(FMUL(FDIV(FMUL(length, viewport_height), F_100),
+ F_72), F_96);
+
+ case CSS_UNIT_VW:
+ return FDIV(FMUL(FDIV(FMUL(length, viewport_width), F_100),
+ F_72), F_96);
+
+ default:
+ return 0;
+ }
+}
+
+/* Exported function, documented in unit.h. */
+css_fixed css_unit_font_size_len2pt(
+ const css_unit_len_ctx *ctx,
+ const css_fixed length,
+ const css_unit unit)
+{
+ return css_unit__absolute_len2pt(
+ ctx->ref_style,
+ ctx->viewport_height,
+ ctx->viewport_width,
+ length,
+ unit);
+}
+
+/**
+ * Get font size from a style in CSS pixels.
+ *
+ * The style should have font size in absolute units.
+ *
+ * \param[in] style Style to get font-size from, or NULL.
+ * \param[in] font_size_default Client font size for NULL style.
+ * \param[in] font_size_minimum Client minimum font size clamp.
+ * \param[in] viewport_height Client viewport height.
+ * \param[in] viewport_width Client viewport width.
+ * \return font-size in CSS pixels.
+ */
+static inline css_fixed css_unit__font_size_px(
+ const css_computed_style *style,
+ const css_fixed font_size_default,
+ const css_fixed font_size_minimum,
+ const css_fixed viewport_height,
+ const css_fixed viewport_width)
+{
+ css_fixed font_length = 0;
+ css_unit font_unit = CSS_UNIT_PT;
+
+ if (style == NULL) {
+ return font_size_default;
+ }
+
+ get_font_size(style, &font_length, &font_unit);
+
+ if (font_unit != CSS_UNIT_PX) {
+ font_length = css_unit__absolute_len2pt(style,
+ viewport_height,
+ viewport_width,
+ font_length,
+ font_unit);
+
+ /* Convert from pt to CSS pixels.*/
+ font_length = FDIV(FMUL(font_length, F_96), F_72);
+ }
+
+ /* Clamp to configured minimum */
+ if (font_length < font_size_minimum) {
+ font_length = font_size_minimum;
+ }
+
+ return font_length;
+}
+
+/**
+ * Get the number of CSS pixels for a given unit.
+ *
+ * \param[in] measure Client callback for font measuring.
+ * \param[in] ref_style Reference style. (Element or parent, or NULL).
+ * \param[in] root_style Root element style or NULL.
+ * \param[in] font_size_default Client default font size in CSS pixels.
+ * \param[in] font_size_minimum Client minimum font size in CSS pixels.
+ * \param[in] viewport_height Viewport height in CSS pixels.
+ * \param[in] viewport_width Viewport width in CSS pixels.
+ * \param[in] unit The unit to convert from.
+ * \param[in] pw Client private word for measure callback.
+ * \return Number of CSS pixels equivalent to the given unit.
+ */
+static inline css_fixed css_unit__px_per_unit(
+ const css_unit_len_measure measure,
+ const css_computed_style *ref_style,
+ const css_computed_style *root_style,
+ const css_fixed font_size_default,
+ const css_fixed font_size_minimum,
+ const css_fixed viewport_height,
+ const css_fixed viewport_width,
+ const css_unit unit,
+ void *pw)
+{
+ switch (css_unit__map_viewport_units(
+ ref_style,
+ viewport_height,
+ viewport_width,
+ unit)) {
+ case CSS_UNIT_EM:
+ return css_unit__font_size_px(
+ ref_style,
+ font_size_default,
+ font_size_minimum,
+ viewport_height,
+ viewport_width);
+
+ case CSS_UNIT_EX:
+ if (measure != NULL) {
+ return measure(pw, ref_style, CSS_UNIT_EX);
+ }
+ return FMUL(css_unit__font_size_px(
+ ref_style,
+ font_size_default,
+ font_size_minimum,
+ viewport_height,
+ viewport_width), FLTTOFIX(0.6));
+
+ case CSS_UNIT_CH:
+ if (measure != NULL) {
+ return measure(pw, ref_style, CSS_UNIT_CH);
+ }
+ return FMUL(css_unit__font_size_px(
+ ref_style,
+ font_size_default,
+ font_size_minimum,
+ viewport_height,
+ viewport_width), FLTTOFIX(0.4));
+
+ case CSS_UNIT_PX:
+ return F_1;
+
+ case CSS_UNIT_IN:
+ return F_96;
+
+ case CSS_UNIT_CM:
+ return FDIV(F_96, FLTTOFIX(2.54));
+
+ case CSS_UNIT_MM:
+ return FDIV(F_96, FLTTOFIX(25.4));
+
+ case CSS_UNIT_Q:
+ return FDIV(F_96, FLTTOFIX(101.6));
+
+ case CSS_UNIT_PT:
+ return FDIV(F_96, F_72);
+
+ case CSS_UNIT_PC:
+ return FDIV(F_96, INTTOFIX(6));
+
+ case CSS_UNIT_REM:
+ return css_unit__font_size_px(
+ root_style,
+ font_size_default,
+ font_size_minimum,
+ viewport_height,
+ viewport_width);
+
+ case CSS_UNIT_VH:
+ return FDIV(viewport_width, F_100);
+
+ case CSS_UNIT_VW:
+ return FDIV(viewport_height, F_100);
+
+ default:
+ return 0;
+ }
+}
+
+/* Exported function, documented in unit.h. */
+css_fixed css_unit_len2px_mq(
+ const css_media *media,
+ const css_fixed length,
+ const css_unit unit)
+{
+ /* In the media query context there is no reference or root element
+ * style, so these are hardcoded to NULL. */
+ css_fixed px_per_unit = css_unit__px_per_unit(
+ NULL,
+ NULL,
+ NULL,
+ media->client_font_size,
+ INTTOFIX(0),
+ media->height,
+ media->width,
+ unit,
+ NULL);
+
+ /* Ensure we round px_per_unit to the nearest whole number of pixels:
+ * the use of FIXTOINT() below will truncate. */
+ px_per_unit += F_0_5;
+
+ /* Calculate total number of pixels */
+ return FMUL(length, TRUNCATEFIX(px_per_unit));
+}
+
+/* Exported function, documented in unit.h. */
+css_fixed css_unit_len2css_px(
+ const css_unit_len_ctx *ctx,
+ const css_fixed length,
+ const css_unit unit)
+{
+ css_fixed px_per_unit = css_unit__px_per_unit(
+ ctx->measure,
+ ctx->ref_style,
+ ctx->root_style,
+ ctx->font_size_default,
+ ctx->font_size_minimum,
+ ctx->viewport_height,
+ ctx->viewport_width,
+ unit,
+ ctx->pw);
+
+ /* Ensure we round px_per_unit to the nearest whole number of pixels:
+ * the use of FIXTOINT() below will truncate. */
+ px_per_unit += F_0_5;
+
+ /* Calculate total number of pixels */
+ return FMUL(length, TRUNCATEFIX(px_per_unit));
+}
+
+/* Exported function, documented in unit.h. */
+css_fixed css_unit_len2device_px(
+ const css_unit_len_ctx *ctx,
+ const css_fixed length,
+ const css_unit unit)
+{
+ css_fixed px_per_unit = css_unit__px_per_unit(
+ ctx->measure,
+ ctx->ref_style,
+ ctx->root_style,
+ ctx->font_size_default,
+ ctx->font_size_minimum,
+ ctx->viewport_height,
+ ctx->viewport_width,
+ unit,
+ ctx->pw);
+
+ px_per_unit = css_unit_css2device_px(px_per_unit, ctx->device_dpi);
+
+ /* Ensure we round px_per_unit to the nearest whole number of pixels:
+ * the use of FIXTOINT() below will truncate. */
+ px_per_unit += F_0_5;
+
+ /* Calculate total number of pixels */
+ return FMUL(length, TRUNCATEFIX(px_per_unit));
+}
+
+/**
+ * Get font size from a computed style.
+ *
+ * The computed style will have font-size with an absolute unit.
+ * If no computed style is given, the client default font-size will be returned.
+ *
+ * \param[in] ctx Length unit conversion context.
+ * \param[in] style The style to get the font-size for, or NULL.
+ * \return The font size in absolute units.
+ */
+static inline css_hint_length css_unit__get_font_size(
+ const css_unit_len_ctx *ctx,
+ const css_computed_style *style)
+{
+ css_hint_length size;
+
+ if (style == NULL) {
+ size.value = ctx->font_size_default;
+ size.unit = CSS_UNIT_PX;
+ } else {
+ enum css_font_size_e status = get_font_size(
+ style, &size.value, &size.unit);
+
+ UNUSED(status);
+
+ assert(status == CSS_FONT_SIZE_DIMENSION);
+ assert(size.unit != CSS_UNIT_EM);
+ assert(size.unit != CSS_UNIT_EX);
+ assert(size.unit != CSS_UNIT_PCT);
+ }
+
+ return size;
+}
+
+/* Exported function, documented in unit.h. */
+css_error css_unit_compute_absolute_font_size(
+ const css_unit_len_ctx *ctx,
+ css_hint *size)
+{
+ css_hint_length ref_len;
+
+ assert(size->status != CSS_FONT_SIZE_INHERIT);
+
+ switch (size->status) {
+ case CSS_FONT_SIZE_XX_SMALL: /* Fall-through. */
+ case CSS_FONT_SIZE_X_SMALL: /* Fall-through. */
+ case CSS_FONT_SIZE_SMALL: /* Fall-through. */
+ case CSS_FONT_SIZE_MEDIUM: /* Fall-through. */
+ case CSS_FONT_SIZE_LARGE: /* Fall-through. */
+ case CSS_FONT_SIZE_X_LARGE: /* Fall-through. */
+ case CSS_FONT_SIZE_XX_LARGE:
+ {
+ static const css_fixed factors[CSS_FONT_SIZE_XX_LARGE] = {
+ [CSS_FONT_SIZE_XX_SMALL - 1] = FLTTOFIX(0.5625),
+ [CSS_FONT_SIZE_X_SMALL - 1] = FLTTOFIX(0.6250),
+ [CSS_FONT_SIZE_SMALL - 1] = FLTTOFIX(0.8125),
+ [CSS_FONT_SIZE_MEDIUM - 1] = FLTTOFIX(1.0000),
+ [CSS_FONT_SIZE_LARGE - 1] = FLTTOFIX(1.1250),
+ [CSS_FONT_SIZE_X_LARGE - 1] = FLTTOFIX(1.5000),
+ [CSS_FONT_SIZE_XX_LARGE - 1] = FLTTOFIX(2.0000),
+ };
+ assert(CSS_FONT_SIZE_INHERIT == 0);
+ assert(CSS_FONT_SIZE_XX_SMALL == 1);
+
+ size->data.length.value = FMUL(factors[size->status - 1],
+ ctx->font_size_default);
+ size->data.length.unit = CSS_UNIT_PX;
+ size->status = CSS_FONT_SIZE_DIMENSION;
+ break;
+ }
+ case CSS_FONT_SIZE_LARGER:
+ ref_len = css_unit__get_font_size(ctx, ctx->ref_style);
+ size->data.length.value = FMUL(ref_len.value, FLTTOFIX(1.2));
+ size->data.length.unit = ref_len.unit;
+ size->status = CSS_FONT_SIZE_DIMENSION;
+ break;
+
+ case CSS_FONT_SIZE_SMALLER:
+ ref_len = css_unit__get_font_size(ctx, ctx->ref_style);
+ size->data.length.value = FDIV(ref_len.value, FLTTOFIX(1.2));
+ size->data.length.unit = ref_len.unit;
+ size->status = CSS_FONT_SIZE_DIMENSION;
+ break;
+
+ case CSS_FONT_SIZE_DIMENSION:
+ /* Convert any relative units to absolute. */
+ switch (size->data.length.unit) {
+ case CSS_UNIT_PCT:
+ ref_len = css_unit__get_font_size(ctx, ctx->ref_style);
+ size->data.length.value = FDIV(
+ FMUL(size->data.length.value,
+ ref_len.value), INTTOFIX(100));
+ size->data.length.unit = ref_len.unit;
+ break;
+
+ case CSS_UNIT_EM: /* Fall-through */
+ case CSS_UNIT_EX: /* Fall-through */
+ case CSS_UNIT_CH:
+ /* Parent relative units. */
+ ref_len = css_unit__get_font_size(ctx, ctx->ref_style);
+
+ size->data.length.unit = ref_len.unit;
+ size->data.length.value = FMUL(size->data.length.value,
+ ref_len.value);
+
+ switch (size->data.length.unit) {
+ case CSS_UNIT_EX:
+ size->data.length.value = FMUL(
+ size->data.length.value,
+ FLTTOFIX(0.6));
+ break;
+
+ case CSS_UNIT_CH:
+ size->data.length.value = FMUL(
+ size->data.length.value,
+ FLTTOFIX(0.4));
+ break;
+
+ default:
+ break;
+ }
+ break;
+
+ case CSS_UNIT_REM:
+ /* Root element relative units. */
+ ref_len = css_unit__get_font_size(ctx, ctx->root_style);
+
+ size->data.length.unit = ref_len.unit;
+ size->data.length.value = FMUL(size->data.length.value,
+ ref_len.value);
+ break;
+
+ default:
+ break;
+ }
+ default:
+ break;
+ }
+
+ return CSS_OK;
+}
diff --git a/src/select/unit.h b/src/select/unit.h
new file mode 100644
index 0000000..738c181
--- /dev/null
+++ b/src/select/unit.h
@@ -0,0 +1,169 @@
+/*
+ * This file is part of LibCSS
+ * Licensed under the MIT License,
+ * http://www.opensource.org/licenses/mit-license.php
+ *
+ * Copyright 2021 Michael Drake <tlsa@netsurf-browser.org>
+ */
+
+#ifndef css_select_unit_h_
+#define css_select_unit_h_
+
+/**
+ * Client callback for font measuring.
+ *
+ * \param[in] pw Client data.
+ * \param[in] style Style to measure font for, or NULL.
+ * \param[in] unit Either CSS_UNIT_EX, or CSS_UNIT_CH.
+ * \return length in CSS pixels.
+ */
+typedef css_fixed (*css_unit_len_measure)(
+ void *pw,
+ const css_computed_style *style,
+ const css_unit unit);
+
+/**
+ * LibCSS unit conversion context.
+ *
+ * The client callback is optional. It is used for measuring "ch"
+ * (glyph '0' advance) and "ex" (height of the letter 'x') units.
+ * If a NULL pointer is given, LibCSS will use a fixed scaling of
+ * the "em" unit.
+ */
+typedef struct css_unit_len_ctx {
+ /**
+ * Viewport width in CSS pixels.
+ * Used if unit is vh, vw, vi, vb, vmin, or vmax.
+ */
+ css_fixed viewport_width;
+ /**
+ * Viewport height in CSS pixels.
+ * Used if unit is vh, vw, vi, vb, vmin, or vmax.
+ */
+ css_fixed viewport_height;
+ /**
+ * Client default font size in CSS pixels.
+ */
+ css_fixed font_size_default;
+ /**
+ * Client minimum font size in CSS pixels. May be zero.
+ */
+ css_fixed font_size_minimum;
+ /**
+ * DPI of the device the style is selected for.
+ */
+ css_fixed device_dpi;
+ /**
+ * Reference style. Most of the time, this is the element's style.
+ * When converting a length for a typographical property, such as
+ * font-size, then this should be the parent node. If the node has
+ * no parent then this may be NULL.
+ */
+ const css_computed_style *ref_style;
+ /**
+ * Computed style for the document root element.
+ * May be NULL if unit is not rem.
+ */
+ const css_computed_style *root_style;
+ /**
+ * Client private word for measure callback.
+ */
+ void *pw;
+ /**
+ * Client callback for font measuring.
+ */
+ const css_unit_len_measure measure;
+} css_unit_len_ctx;
+
+/**
+ * Convert css pixels to physical pixels.
+ *
+ * \param[in] css_pixels Length in css pixels.
+ * \param[in] device_dpi Device dots per inch.
+ * \return Length in device pixels.
+ */
+static inline css_fixed css_unit_css2device_px(
+ const css_fixed css_pixels,
+ const css_fixed device_dpi)
+{
+ return FDIV(FMUL(css_pixels, device_dpi), F_96);
+}
+
+/**
+ * Convert device pixels to css pixels.
+ *
+ * \param[in] device_pixels Length in physical pixels.
+ * \param[in] device_dpi Device dots per inch.
+ * \return Length in css pixels.
+ */
+static inline css_fixed css_unit_device2css_px(
+ const css_fixed device_pixels,
+ const css_fixed device_dpi)
+{
+ return FDIV(FMUL(device_pixels, F_96), device_dpi);
+}
+
+/**
+ * Convert a length to points (pt).
+ *
+ * \param[in] ctx Length unit conversion context.
+ * \param[in] length Length to convert.
+ * \param[in] unit Current unit of length.
+ * \return A length in points.
+ */
+css_fixed css_unit_font_size_len2pt(
+ const css_unit_len_ctx *ctx,
+ const css_fixed length,
+ const css_unit unit);
+
+/**
+ * Convert a length to CSS pixels.
+ *
+ * \param[in] ctx Length unit conversion context.
+ * \param[in] length Length to convert.
+ * \param[in] unit Current unit of length.
+ * \return A length in CSS pixels.
+ */
+css_fixed css_unit_len2css_px(
+ const css_unit_len_ctx *ctx,
+ const css_fixed length,
+ const css_unit unit);
+
+/**
+ * Convert a length to device pixels.
+ *
+ * \param[in] ctx Length unit conversion context.
+ * \param[in] length Length to convert.
+ * \param[in] unit Current unit of length.
+ * \return A length in device pixels.
+ */
+css_fixed css_unit_len2device_px(
+ const css_unit_len_ctx *ctx,
+ const css_fixed length,
+ const css_unit unit);
+
+/**
+ * Convert a length to CSS pixels for a media query context.
+ *
+ * \param[in] media Client media specification.
+ * \param[in] length Length to convert.
+ * \param[in] unit Current unit of length.
+ * \return A length in CSS pixels.
+ */
+css_fixed css_unit_len2px_mq(
+ const css_media *media,
+ const css_fixed length,
+ const css_unit unit);
+
+/**
+ * Convert relative font size units to absolute units.
+ *
+ * \param[in] ctx Length unit conversion context.
+ * \param[in,out] size The length to convert.
+ * \return CSS_OK on success, or appropriate error otherwise.
+ */
+css_error css_unit_compute_absolute_font_size(
+ const css_unit_len_ctx *ctx,
+ css_hint *size);
+
+#endif