summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMichael Drake <Michael Drake tlsa@netsurf-browser.org>2019-05-07 13:57:29 +0100
committerMichael Drake <Michael Drake tlsa@netsurf-browser.org>2019-05-07 13:57:29 +0100
commitd09f33131b8079f3886e0827cf458e1fc2c7f2d6 (patch)
tree7fdb8912406b33ba93f7602f86f75fe1af7579f3
parenta7830f2452116f57e7880a3f1802c1c3bf1209c9 (diff)
downloadlibcss-d09f33131b8079f3886e0827cf458e1fc2c7f2d6.tar.gz
libcss-d09f33131b8079f3886e0827cf458e1fc2c7f2d6.tar.bz2
Media queries: Feature matching: Compare lengths in pixels.
Clients now provide viewport dimensions in pixels. LibCSS can now convert the units from the stylesheet to pixels. Client must also provide default font size and line height for handling viewport and root element relative sizes.
-rw-r--r--include/libcss/types.h15
-rw-r--r--src/select/mq.h180
2 files changed, 148 insertions, 47 deletions
diff --git a/include/libcss/types.h b/include/libcss/types.h
index 44aef12..d8ac494 100644
--- a/include/libcss/types.h
+++ b/include/libcss/types.h
@@ -194,11 +194,6 @@ typedef enum css_media_scripting {
CSS_MEDIA_SCRIPTING_ENABLED = 2
} css_media_scripting;
-typedef struct css_media_length {
- css_fixed value;
- css_unit unit;
-} css_media_length;
-
typedef struct css_media_resolution {
css_fixed value;
css_unit unit;
@@ -211,9 +206,9 @@ typedef struct css_media {
/* Media type */
css_media_type type;
- /* Screen / Device media features */
- css_media_length width;
- css_media_length height;
+ /* Viewport / page media features */
+ css_fixed width; /* In css pixels */
+ css_fixed height; /* In css pixels */
css_fixed aspect_ratio;
css_media_orientation orientation;
@@ -242,6 +237,10 @@ typedef struct css_media {
/* Scripting media features */
css_media_scripting scripting;
+
+ /* Client details for length conversion */
+ css_fixed client_font_size; /* In pt */
+ css_fixed client_line_height; /* In css pixels */
} css_media;
/**
diff --git a/src/select/mq.h b/src/select/mq.h
index 1c07ecc..f51d0db 100644
--- a/src/select/mq.h
+++ b/src/select/mq.h
@@ -9,32 +9,133 @@
#ifndef css_select_mq_h_
#define css_select_mq_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_CAP:
+ case CSS_UNIT_CH:
+ case CSS_UNIT_IC:
+ {
+ 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_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:
+ 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_RLH:
+ px_per_unit = media->client_line_height;
+ 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));
+}
+
static inline bool mq_match_feature_range_length_op1(
css_mq_feature_op op,
const css_mq_value *value,
- const css_media_length *client_len)
+ const css_fixed client_len,
+ const css_media *media)
{
+ css_fixed v;
+
if (value->type != CSS_MQ_VALUE_TYPE_DIM) {
return false;
}
- /* TODO: convert to same units */
- if (value->data.dim.unit != client_len->unit) {
- return false;
+
+ if (value->data.dim.unit != CSS_UNIT_PX) {
+ v = css_len2px(value->data.dim.len,
+ value->data.dim.unit, media);
+ } else {
+ v = value->data.dim.len;
}
switch (op) {
- case CSS_MQ_FEATURE_OP_BOOL:
- return false;
- case CSS_MQ_FEATURE_OP_LT:
- return value->data.dim.len < client_len->value;
- case CSS_MQ_FEATURE_OP_LTE:
- return value->data.dim.len <= client_len->value;
- case CSS_MQ_FEATURE_OP_EQ:
- return value->data.dim.len == client_len->value;
- case CSS_MQ_FEATURE_OP_GTE:
- return value->data.dim.len >= client_len->value;
- case CSS_MQ_FEATURE_OP_GT:
- return value->data.dim.len > client_len->value;
+ case CSS_MQ_FEATURE_OP_BOOL: return false;
+ case CSS_MQ_FEATURE_OP_LT: return v < client_len;
+ case CSS_MQ_FEATURE_OP_LTE: return v <= client_len;
+ case CSS_MQ_FEATURE_OP_EQ: return v == client_len;
+ case CSS_MQ_FEATURE_OP_GTE: return v >= client_len;
+ case CSS_MQ_FEATURE_OP_GT: return v > client_len;
default:
return false;
}
@@ -43,30 +144,31 @@ static inline bool mq_match_feature_range_length_op1(
static inline bool mq_match_feature_range_length_op2(
css_mq_feature_op op,
const css_mq_value *value,
- const css_media_length *client_len)
+ const css_fixed client_len,
+ const css_media *media)
{
+ css_fixed v;
+
if (op == CSS_MQ_FEATURE_OP_UNUSED) {
return true;
}
if (value->type != CSS_MQ_VALUE_TYPE_DIM) {
return false;
}
- /* TODO: convert to same units */
- if (value->data.dim.unit != client_len->unit) {
- return false;
+
+ if (value->data.dim.unit != CSS_UNIT_PX) {
+ v = css_len2px(value->data.dim.len,
+ value->data.dim.unit, media);
+ } else {
+ v = value->data.dim.len;
}
switch (op) {
- case CSS_MQ_FEATURE_OP_LT:
- return client_len->value < value->data.dim.len;
- case CSS_MQ_FEATURE_OP_LTE:
- return client_len->value <= value->data.dim.len;
- case CSS_MQ_FEATURE_OP_EQ:
- return client_len->value == value->data.dim.len;
- case CSS_MQ_FEATURE_OP_GTE:
- return client_len->value >= value->data.dim.len;
- case CSS_MQ_FEATURE_OP_GT:
- return client_len->value > value->data.dim.len;
+ case CSS_MQ_FEATURE_OP_LT: return client_len < v;
+ case CSS_MQ_FEATURE_OP_LTE: return client_len <= v;
+ case CSS_MQ_FEATURE_OP_EQ: return client_len == v;
+ case CSS_MQ_FEATURE_OP_GTE: return client_len >= v;
+ case CSS_MQ_FEATURE_OP_GT: return client_len > v;
default:
return false;
}
@@ -75,7 +177,7 @@ static inline bool mq_match_feature_range_length_op2(
/**
* Match media query features.
*
- * \param[in] feat Condition to match.
+ * \param[in] feat Condition to match.
* \param[in] media Current media spec, to check against feat.
* \return true if condition matches, otherwise false.
*/
@@ -85,21 +187,21 @@ static inline bool mq_match_feature(
{
/* TODO: Use interned string for comparison. */
if (strcmp(lwc_string_data(feat->name), "width") == 0) {
- if (!mq_match_feature_range_length_op1(
- feat->op, &feat->value, &media->width)) {
+ if (!mq_match_feature_range_length_op1(feat->op, &feat->value,
+ media->width, media)) {
return false;
}
- return mq_match_feature_range_length_op2(
- feat->op2, &feat->value2, &media->width);
+ return mq_match_feature_range_length_op2(feat->op2,
+ &feat->value2, media->width, media);
} else if (strcmp(lwc_string_data(feat->name), "height") == 0) {
- if (!mq_match_feature_range_length_op1(
- feat->op, &feat->value, &media->height)) {
+ if (!mq_match_feature_range_length_op1(feat->op, &feat->value,
+ media->height, media)) {
return false;
}
- return mq_match_feature_range_length_op2(
- feat->op2, &feat->value2, &media->height);
+ return mq_match_feature_range_length_op2(feat->op2,
+ &feat->value2, media->height, media);
}
/* TODO: Look at other feature names. */