Gitweb links:

...log 
http://git.netsurf-browser.org/libcss.git/shortlog/7d759aba6639709b23b92f9fb6cb29099ff612d3
...commit 
http://git.netsurf-browser.org/libcss.git/commit/7d759aba6639709b23b92f9fb6cb29099ff612d3
...tree 
http://git.netsurf-browser.org/libcss.git/tree/7d759aba6639709b23b92f9fb6cb29099ff612d3

The branch, jmb/mq has been updated
       via  7d759aba6639709b23b92f9fb6cb29099ff612d3 (commit)
       via  40936ea51e4a3d6b0ac0a3a679519275e91544d7 (commit)
      from  7c57ceadc3a6076914242783582581095283b63b (commit)

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/libcss.git/commit/?id=7d759aba6639709b23b92f9fb6cb29099ff612d3
commit 7d759aba6639709b23b92f9fb6cb29099ff612d3
Author: John-Mark Bell <[email protected]>
Commit: John-Mark Bell <[email protected]>

    Media Queries: parse features

diff --git a/src/parse/mq.c b/src/parse/mq.c
index 5c9c7fa..96f70df 100644
--- a/src/parse/mq.c
+++ b/src/parse/mq.c
@@ -7,7 +7,443 @@
 
 /* https://drafts.csswg.org/mediaqueries/ */
 
+#include <libcss/fpmath.h>
+
+#include "bytecode/bytecode.h"
 #include "parse/mq.h"
+#include "parse/properties/utils.h"
+#include "utils/utils.h"
+
+static css_error mq_parse_ratio(css_language *c,
+               const parserutils_vector *vector, int *ctx,
+               const css_token *numerator, css_fixed *ratio)
+{
+       const css_token *token;
+       css_fixed num, den;
+       size_t num_len, den_len;
+
+       /* NUMBER ws* '/' ws* NUMBER */
+
+       /* numerator, ws* already consumed */
+
+       token = parserutils_vector_iterate(vector, ctx);
+       if (token == NULL || tokenIsChar(token, '/') == false) {
+               return CSS_INVALID;
+       }
+
+       consumeWhitespace(vector, ctx);
+
+       token = parserutils_vector_iterate(vector, ctx);
+       if (token == NULL || token->type != CSS_TOKEN_NUMBER) {
+               return CSS_INVALID;
+       }
+
+       num = css__number_from_lwc_string(numerator->idata, true, &num_len);
+       den = css__number_from_lwc_string(token->idata, true, &den_len);
+
+       *ratio = css_divide_fixed(num, den);
+
+       return CSS_OK;
+}
+
+static css_error mq_create_feature(
+               lwc_string *name,
+               css_mq_feature **feature)
+{
+       css_mq_feature *f;
+
+       f = malloc(sizeof(*f));
+       if (f == NULL) {
+               return CSS_NOMEM;
+       }
+
+       memset(f, 0, sizeof(*f));
+
+       f->name = lwc_string_ref(name);
+
+       *feature = f;
+
+       return CSS_OK;
+}
+
+static css_error mq_populate_value(css_mq_value *value,
+               const css_token *token)
+{
+       if (token->type == CSS_TOKEN_NUMBER) {
+               size_t num_len;
+               value->type = CSS_MQ_VALUE_TYPE_NUM;
+               value->data.num_or_ratio = css__number_from_lwc_string(
+                               token->idata, false, &num_len);
+       } else if (token->type == CSS_TOKEN_DIMENSION) {
+               size_t len = lwc_string_length(token->idata);
+               const char *data = lwc_string_data(token->idata);
+               uint32_t unit = UNIT_PX;
+               size_t consumed;
+
+               value->type == CSS_MQ_VALUE_TYPE_DIM;
+               value->data.dim.len = css__number_from_lwc_string(
+                               token->idata, false, &consumed);
+               error = css__parse_unit_keyword(data + consumed, len - consumed,
+                               &unit);
+               if (error != CSS_OK) {
+                       return error;
+               }
+               value->data.dim.unit = temp_unit;
+       } else if (token->type == CSS_TOKEN_IDENT) {
+               value->type = CSS_MQ_VALUE_TYPE_IDENT;
+               value->data.ident = lwc_string_ref(token->idata);
+       }
+
+       return CSS_OK;
+}
+
+static css_error mq_parse_op(const css_token *token,
+               css_mq_feature_op *op)
+{
+       size_t len;
+       const char *data;
+
+       if (token == NULL || token->type != CSS_TOKEN_CHAR)
+               return CSS_INVALID;
+
+       len = lwc_string_length(token->idata);
+       data = lwc_string_data(token->idata);
+
+       if (len == 2) {
+               if (strncasecmp(data, "<=", 2) == 0)
+                       *op = CSS_MQ_FEATURE_OP_LTE;
+               else if (strncasecmp(data, ">=", 2) == 0)
+                       *op = CSS_MQ_FEATURE_OP_GTE;
+               else
+                       return CSS_INVALID;
+       } else if (len == 1) {
+               if (*data == '<')
+                       *op = CSS_MQ_FEATURE_OP_LT;
+               else if (*data == '=')
+                       *op = CSS_MQ_FEATURE_OP_EQ;
+               else if (*data == '>')
+                       *op = CSS_MQ_FEATURE_OP_GT;
+               else
+                       return CSS_INVALID;
+       } else {
+               return CSS_INVALID;
+       }
+
+       return CSS_OK;
+}
+
+static css_error mq_parse_range(css_language *c,
+               const parserutils_vector *vector, int *ctx,
+               const css_token *name_or_value,
+               css_mq_feature **feature)
+{
+       const css_token *token, *value_or_name, *name = NULL, *value2 = NULL;
+       css_mq_feature *result;
+       css_mq_feature_op op, op2;
+       css_fixed ratio, ratio2;
+       bool name_first = false, value_is_ratio = false, value2_is_ratio = 
false, match;
+       css_error error;
+
+       /* <mf-range> = <mf-name> [ '<' | '>' ]? '='? <mf-value>
+        *            | <mf-value> [ '<' | '>' ]? '='? <mf-name>
+        *            | <mf-value> '<' '='? <mf-name> '<' '='? <mf-value>
+        *            | <mf-value> '>' '='? <mf-name> '>' '='? <mf-value>
+        */
+
+       if (name_or_value == NULL || (name_or_value->type != CSS_TOKEN_NUMBER &&
+                       name_or_value->type != CSS_TOKEN_DIMENSION &&
+                       name_or_value->type != CSS_TOKEN_IDENT)) {
+               return CSS_INVALID;
+       }
+
+       consumeWhitespace(vector, ctx);
+
+       /* Name-or-value */
+       if (name_or_value->type == CSS_TOKEN_NUMBER &&
+                       tokenIsChar(parserutils_vector_peek(vector, *ctx), 
'/')) {
+               /* ratio */
+               error = mq_parse_ratio(c, vector, ctx, token, &ratio);
+               if (error != CSS_OK) {
+                       return error;
+               }
+
+               consumeWhitespace(vector, ctx);
+
+               value_is_ratio = true;
+       } else if (name_or_value->type == CSS_TOKEN_IDENT &&
+                       lwc_string_caseless_isequal(name_or_value->idata,
+                               c->strings[INFINITE], &match) == lwc_error_ok 
&& 
+                       match == false) {
+               /* The only ident permitted for mf-value is 'infinite', thus 
must have name */
+               name = name_or_value;
+               name_first = true;
+       }
+
+       /* Op */
+       token = parserutils_vector_iterate(vector, ctx);
+       error = mq_parse_op(token, &op);
+       if (error != CSS_OK) {
+               return error;
+       }
+
+       consumeWhitespace(vector, ctx);
+
+       /* Value-or-name */
+       value_or_name = parserutils_vector_iterate(vector, ctx);
+       if (value_or_name == NULL || (value_or_name->type != CSS_TOKEN_NUMBER &&
+                       value_or_name->type != CSS_TOKEN_DIMENSION &&
+                       value_or_name->type != CSS_TOKEN_IDENT)) {
+               return CSS_INVALID;
+       }
+
+       if (name == NULL) {
+               if (value_or_name->type != CSS_TOKEN_IDENT) {
+                       return CSS_INVALID;
+               } else {
+                       name = value_or_name;
+               }
+       }
+
+       consumeWhitespace(vector, ctx);
+
+       if (value_or_name->type == CSS_TOKEN_NUMBER &&
+                       tokenIsChar(parserutils_vector_peek(vector, *ctx), 
'/')) {
+               /* ratio */
+               error = mq_parse_ratio(c, vector, ctx, token, &ratio);
+               if (error != CSS_OK) {
+                       return error;
+               }
+
+               consumeWhitespace(vector, ctx);
+
+               value_is_ratio = true;
+       }
+
+       token = parserutils_vector_peek(vector, *ctx);
+       if (name_first == false && token != NULL && tokenIsChar(token, ')') == 
false) {
+               /* Op2 */
+               token = parserutils_vector_iterate(vector, ctx);
+               error = mq_parse_op(token, &op2);
+               if (error != CSS_OK) {
+                       return error;
+               }
+
+               consumeWhitespace(vector, ctx);
+
+               /* Validate operators: must both be LT(E) or GT(E) */
+               if (op == CSS_MQ_FEATURE_OP_LT || op == CSS_MQ_FEATURE_OP_LTE) {
+                       if (op2 != CSS_MQ_FEATURE_OP_LT && op2 != 
CSS_MQ_FEATURE_OP_LTE) {
+                               return CSS_INVALID;
+                       }
+               } else if (op == CSS_MQ_FEATURE_OP_GT || op == 
CSS_MQ_FEATURE_OP_GTE) {
+                      if (op2 != CSS_MQ_FEATURE_OP_GT && op2 != 
CSS_MQ_FEATURE_OP_GTE) {
+                               return CSS_INVALID;
+                       }
+               } else {
+                       return CSS_INVALID;
+               }
+
+               /* Value2 */
+               value2 = parserutils_vector_iterate(vector, ctx);
+               if (value2 == NULL || (value2->type != CSS_TOKEN_NUMBER &&
+                               value2->type != CSS_TOKEN_DIMENSION &&
+                               value2->type != CSS_TOKEN_IDENT)) {
+                       return CSS_INVALID;
+               }
+
+               consumeWhitespace(vector, ctx);
+
+               if (value_or_name->type == CSS_TOKEN_NUMBER &&
+                               tokenIsChar(parserutils_vector_peek(vector, 
*ctx), '/')) {
+                       /* ratio */
+                       error = mq_parse_ratio(c, vector, ctx, token, &ratio2);
+                       if (error != CSS_OK) {
+                               return error;
+                       }
+
+                       consumeWhitespace(vector, ctx);
+
+                       value2_is_ratio = true;
+               }
+       }
+
+       error = mq_create_feature(name->idata, &result);
+       if (error != CSS_OK) {
+               return error;
+       }
+       if (name_first) {
+               /* Invert operator */
+               if (op == CSS_MQ_FEATURE_OP_LT) {
+                       op = CSS_MQ_FEATURE_OP_GTE;
+               } else if (op == CSS_MQ_FEATURE_OP_LTE) {
+                       op = CSS_MQ_FEATURE_OP_GT;
+               } else if (op == CSS_MQ_FEATURE_OP_GT) {
+                       op = CSS_MQ_FEATURE_OP_LTE;
+               } else if (op == CSS_MQ_FEATURE_OP_GTE) {
+                       op = CSS_MQ_FEATURE_OP_LT;
+               }
+       }
+       result->op = op;
+       if (value_is_ratio) {
+               result->value.type = CSS_MQ_VALUE_TYPE_RATIO;
+               result->value.data.num_or_ratio = ratio;
+       } else {
+               /* num/dim/ident */
+               error = mq_populate_value(&result->value, token);
+               if (error != CSS_OK) {
+                       free(result);
+                       return error;
+               }
+       }
+       if (value2 != NULL) {
+               result->op2 = op2;
+               if (value2_is_ratio) {
+                       result->value2.type = CSS_MQ_VALUE_TYPE_RATIO;
+                       result->value2.data.num_or_ratio = ratio;
+               } else {
+                       /* num/dim/ident */
+                       error = mq_populate_value(&result->value2, token);
+                       if (error != CSS_OK) {
+                               /* TODO: clean up result properly? */
+                               free(result);
+                               return error;
+                       }
+               }
+       }
+
+       *feature = result;
+
+       return CSS_OK;
+}
+
+static css_error mq_parse_media_feature(css_language *c,
+               const parserutils_vector *vector, int *ctx,
+               css_mq_feature **feature)
+{
+       const css_token *name_or_value, *token;
+       css_mq_feature *result;
+       css_error error;
+
+       /* <media-feature> = ( [ <mf-plain> | <mf-boolean> | <mf-range> ] )
+        * <mf-plain> = <mf-name> : <mf-value>
+        * <mf-boolean> = <mf-name>
+        * <mf-name> = <ident>
+        * <mf-value> = <number> | <dimension> | <ident> | <ratio>
+        */
+
+       /* ( already consumed */
+
+       name_or_value = parserutils_vector_iterate(vector, ctx);
+       if (name_or_value == NULL)
+               return CSS_INVALID;
+
+       if (name_or_value->type == CSS_TOKEN_IDENT) {
+               consumeWhitespace(vector, ctx);
+
+               token = parserutils_vector_peek(vector, *ctx);
+               if (tokenIsChar(token, ')')) {
+                       /* mf-boolean */
+                       error = mq_create_feature(name_or_value->idata, 
&result);
+                       if (error != CSS_OK) {
+                               return error;
+                       }
+
+                       result->op = CSS_MQ_FEATURE_OP_BOOL;
+               } else if (tokenIsChar(token, ':')) {
+                       /* mf-plain */
+                       parserutils_vector_iterate(vector, ctx);
+
+                       consumeWhitespace(vector, ctx);
+
+                       token = parserutils_vector_iterate(vector, ctx);
+                       if (token == NULL || (token->type != CSS_TOKEN_NUMBER &&
+                                       token->type != CSS_TOKEN_DIMENSION &&
+                                       token->type != CSS_TOKEN_IDENT)) {
+                               return CSS_INVALID;
+                       }
+
+                       consumeWhitespace(vector, ctx);
+
+                       error = mq_create_feature(name_or_value->idata, 
&result);
+                       if (error != CSS_OK) {
+                               return error;
+                       }
+                       result->op = CSS_MQ_FEATURE_OP_EQ;
+
+                       if (token->type == CSS_TOKEN_NUMBER &&
+                                       
tokenIsChar(parserutils_vector_peek(vector, *ctx), '/')) {
+                               /* ratio */
+                               css_fixed ratio;
+
+                               error = mq_parse_ratio(c, vector, ctx, token, 
&ratio);
+                               if (error != CSS_OK) {
+                                       free(result);
+                                       return error;
+                               }
+
+                               result->value.type = CSS_MQ_VALUE_TYPE_RATIO;
+                               result->value.data.num_or_ratio = ratio;
+                       } else {
+                               /* num/dim/ident */
+                               error = mq_populate_value(&result->value, 
token);
+                               if (error != CSS_OK) {
+                                       free(result);
+                                       return error;
+                               }
+                       }
+
+                       consumeWhitespace(vector, ctx);
+               } else {
+                       /* mf-range */
+                       error = mq_parse_range(c, vector, ctx, name_or_value, 
&result);
+                       if (error != CSS_OK) {
+                               return error;
+                       }
+
+                       consumeWhitespace(vector, ctx);
+               }
+       } else {
+               /* mf-range */
+               error = mq_parse_range(c, vector, ctx, name_or_value, &result);
+               if (error != CSS_OK) {
+                       return error;
+               }
+
+               consumeWhitespace(vector, ctx);
+       }
+
+       token = parserutils_vector_iterate(vector, ctx);
+       if (tokenIsChar(token, ')') == false) {
+               /* TODO: clean up result */
+               return CSS_INVALID;
+       }
+
+       *feature = result;
+
+       return CSS_OK;
+}
+
+static css_error mq_parse_media_in_parens()
+{
+       /* <media-in-parens> = ( <media-condition> ) | <media-feature> | 
<general-enclosed>
+        * <general-enclosed> = [ <function-token> <any-value> ) ] | ( <ident> 
<any-value> )
+        */
+
+       //LPAREN -> condition-or-feature
+       //        "not" or LPAREN -> condition
+       //        IDENT | NUMBER | DIMENSION | RATIO -> feature
+
+}
+
+static css_error mq_parse_condition()
+{
+       /* <media-condition> = <media-not> | <media-in-parens> [ <media-and>* | 
<media-or>* ]
+        * <media-condition-without-or> = <media-not> | <media-in-parens> 
<media-and>*
+        * <media-not> = not <media-in-parens>
+        * <media-and> = and <media-in-parens>
+        * <media-or> = or <media-in-parens>
+        */
+}
 
 css_error css__mq_parse_media_list(css_language *c,
                const parserutils_vector *vector, int *ctx,
@@ -16,7 +452,19 @@ css_error css__mq_parse_media_list(css_language *c,
        css_mq_query *ret = NULL;
        const css_token *token;
 
-       /* (IDENT ws (',' ws IDENT ws)* )? */
+       /* <media-query-list> = <media-query> [ COMMA <media-query> ]*
+        * <media-query> = <media-condition>
+        *               | [ not | only ]? <media-type> [ and 
<media-condition-without-or> ]?
+        * <media-type> = <ident> (except "not", "and", "or", "only")
+        *
+        */
+
+       /* if {[(, push }]) to stack
+        * if func, push ) to stack
+        * on error, scan forward until stack is empty (or EOF), popping 
matching tokens off stack
+        * if stack is empty, the next input token must be comma or EOF
+        * if comma, consume, and start again from the next input token
+        */
 
        UNUSED(c);
 
diff --git a/src/parse/mq.h b/src/parse/mq.h
index 7d62e8c..c5268c7 100644
--- a/src/parse/mq.h
+++ b/src/parse/mq.h
@@ -22,7 +22,7 @@ typedef struct {
                css_fixed num_or_ratio; /* Where ratio is the result of a/b */
                struct {
                        css_fixed len;
-                       css_unit unit;
+                       uint32_t unit;
                } dim;
                lwc_string *ident;
        } data;
@@ -31,8 +31,8 @@ typedef struct {
 /*
  * "name : value" is encoded as "name = value"
  * "name" is encoded by setting the operator to "bool"
- * "name op value" is encoded verbatim (with op2 set to "unused")
- * "value op name" inverts the operator to encode (i.e < becomes >=) (and sets 
op2 to "unused")
+ * "value op name" is encoded verbatim (with op2 set to "unused")
+ * "name op value" inverts the operator to encode (i.e < becomes >=) (and sets 
op2 to "unused")
  * "value op name op value" is encoded using op2 and value2
  */
 typedef enum {


commitdiff 
http://git.netsurf-browser.org/libcss.git/commit/?id=40936ea51e4a3d6b0ac0a3a679519275e91544d7
commit 40936ea51e4a3d6b0ac0a3a679519275e91544d7
Author: John-Mark Bell <[email protected]>
Commit: John-Mark Bell <[email protected]>

    Units: parse new unit names

diff --git a/src/bytecode/bytecode.h b/src/bytecode/bytecode.h
index 4ac3dfb..cd93eb2 100644
--- a/src/bytecode/bytecode.h
+++ b/src/bytecode/bytecode.h
@@ -32,6 +32,18 @@ typedef enum unit {
        UNIT_MM   = 5,
        UNIT_PT   = 6,
        UNIT_PC   = 7,
+       UNIT_Q    = 8,
+       UNIT_CH   = 9,
+       UNIT_IC   = 10,
+       UNIT_REM  = 11,
+       UNIT_LH   = 12,
+       UNIT_RLH  = 13,
+       UNIT_VW   = 14,
+       UNIT_VH   = 15,
+       UNIT_VI   = 16,
+       UNIT_VB   = 17,
+       UNIT_VMIN = 18,
+       UNIT_VMAX = 19,
 
        UNIT_PCT  = (1 << 8),
 
@@ -39,6 +51,7 @@ typedef enum unit {
        UNIT_DEG  = (1 << 9) + 0,
        UNIT_GRAD = (1 << 9) + 1,
        UNIT_RAD  = (1 << 9) + 2,
+       UNIT_TURN = (1 << 9) + 3,
 
        UNIT_TIME = (1 << 10),
        UNIT_MS   = (1 << 10) + 0,
@@ -46,7 +59,12 @@ typedef enum unit {
 
        UNIT_FREQ = (1 << 11),
        UNIT_HZ   = (1 << 11) + 0,
-       UNIT_KHZ  = (1 << 11) + 1
+       UNIT_KHZ  = (1 << 11) + 1,
+
+       UNIT_RESOLUTION = (1 << 12),
+       UNIT_DPI = (1 << 12) + 0,
+       UNIT_DPCM = (1 << 12) + 1,
+       UNIT_DPPX = (1 << 12) + 2,
 } unit;
 
 typedef uint32_t colour;
diff --git a/src/parse/properties/utils.c b/src/parse/properties/utils.c
index 82dacf8..97583c6 100644
--- a/src/parse/properties/utils.c
+++ b/src/parse/properties/utils.c
@@ -1007,6 +1007,16 @@ css_error css__parse_unit_keyword(const char *ptr, 
size_t len, uint32_t *unit)
        if (len == 4) {
                if (strncasecmp(ptr, "grad", 4) == 0)
                        *unit = UNIT_GRAD;
+               else if (strncasecmp(ptr, "turn", 4) == 0)
+                       *unit = UNIT_TURN;
+               else if (strncasecmp(ptr, "dppx", 4) == 0)
+                       *unit = UNIT_DPPX;
+               else if (strncasecmp(ptr, "dpcm", 4) == 0)
+                       *unit = UNIT_DPCM;
+               else if (strncasecmp(ptr, "vmin", 4) == 0)
+                       *unit = UNIT_VMIN;
+               else if (strncasecmp(ptr, "vmax", 4) == 0)
+                       *unit = UNIT_VMAX;
                else
                        return CSS_INVALID;
        } else if (len == 3) {
@@ -1016,6 +1026,12 @@ css_error css__parse_unit_keyword(const char *ptr, 
size_t len, uint32_t *unit)
                        *unit = UNIT_DEG;
                else if (strncasecmp(ptr, "rad", 3) == 0)
                        *unit = UNIT_RAD;
+               else if (strncasecmp(ptr, "dpi", 3) == 0)
+                       *unit = UNIT_DPI;
+               else if (strncasecmp(ptr, "rlh", 3) == 0)
+                       *unit = UNIT_RLH;
+               else if (strncasecmp(ptr, "rem", 3) == 0)
+                       *unit = UNIT_REM;
                else
                        return CSS_INVALID;
        } else if (len == 2) {
@@ -1039,11 +1055,27 @@ css_error css__parse_unit_keyword(const char *ptr, 
size_t len, uint32_t *unit)
                        *unit = UNIT_PT;
                else if (strncasecmp(ptr, "pc", 2) == 0)
                        *unit = UNIT_PC;
+               else if (strncasecmp(ptr, "ch", 2) == 0)
+                       *unit = UNIT_CH;
+               else if (strncasecmp(ptr, "ic", 2) == 0)
+                       *unit = UNIT_IC;
+               else if (strncasecmp(ptr, "lh", 2) == 0)
+                       *unit = UNIT_LH;
+               else if (strncasecmp(ptr, "vw", 2) == 0)
+                       *unit = UNIT_VW;
+               else if (strncasecmp(ptr, "vh", 2) == 0)
+                       *unit = UNIT_VH;
+               else if (strncasecmp(ptr, "vi", 2) == 0)
+                       *unit = UNIT_VI;
+               else if (strncasecmp(ptr, "vb", 2) == 0)
+                       *unit = UNIT_VB;
                else
                        return CSS_INVALID;
        } else if (len == 1) {
                if (strncasecmp(ptr, "s", 1) == 0)
                        *unit = UNIT_S;
+               else if (strncasecmp(ptr, "Q", 1) == 0)
+                       *unit = UNIT_Q;
                else
                        return CSS_INVALID;
        } else


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

Summary of changes:
 src/bytecode/bytecode.h      |   20 +-
 src/parse/mq.c               |  450 +++++++++++++++++++++++++++++++++++++++++-
 src/parse/mq.h               |    6 +-
 src/parse/properties/utils.c |   32 +++
 4 files changed, 503 insertions(+), 5 deletions(-)

diff --git a/src/bytecode/bytecode.h b/src/bytecode/bytecode.h
index 4ac3dfb..cd93eb2 100644
--- a/src/bytecode/bytecode.h
+++ b/src/bytecode/bytecode.h
@@ -32,6 +32,18 @@ typedef enum unit {
        UNIT_MM   = 5,
        UNIT_PT   = 6,
        UNIT_PC   = 7,
+       UNIT_Q    = 8,
+       UNIT_CH   = 9,
+       UNIT_IC   = 10,
+       UNIT_REM  = 11,
+       UNIT_LH   = 12,
+       UNIT_RLH  = 13,
+       UNIT_VW   = 14,
+       UNIT_VH   = 15,
+       UNIT_VI   = 16,
+       UNIT_VB   = 17,
+       UNIT_VMIN = 18,
+       UNIT_VMAX = 19,
 
        UNIT_PCT  = (1 << 8),
 
@@ -39,6 +51,7 @@ typedef enum unit {
        UNIT_DEG  = (1 << 9) + 0,
        UNIT_GRAD = (1 << 9) + 1,
        UNIT_RAD  = (1 << 9) + 2,
+       UNIT_TURN = (1 << 9) + 3,
 
        UNIT_TIME = (1 << 10),
        UNIT_MS   = (1 << 10) + 0,
@@ -46,7 +59,12 @@ typedef enum unit {
 
        UNIT_FREQ = (1 << 11),
        UNIT_HZ   = (1 << 11) + 0,
-       UNIT_KHZ  = (1 << 11) + 1
+       UNIT_KHZ  = (1 << 11) + 1,
+
+       UNIT_RESOLUTION = (1 << 12),
+       UNIT_DPI = (1 << 12) + 0,
+       UNIT_DPCM = (1 << 12) + 1,
+       UNIT_DPPX = (1 << 12) + 2,
 } unit;
 
 typedef uint32_t colour;
diff --git a/src/parse/mq.c b/src/parse/mq.c
index 5c9c7fa..96f70df 100644
--- a/src/parse/mq.c
+++ b/src/parse/mq.c
@@ -7,7 +7,443 @@
 
 /* https://drafts.csswg.org/mediaqueries/ */
 
+#include <libcss/fpmath.h>
+
+#include "bytecode/bytecode.h"
 #include "parse/mq.h"
+#include "parse/properties/utils.h"
+#include "utils/utils.h"
+
+static css_error mq_parse_ratio(css_language *c,
+               const parserutils_vector *vector, int *ctx,
+               const css_token *numerator, css_fixed *ratio)
+{
+       const css_token *token;
+       css_fixed num, den;
+       size_t num_len, den_len;
+
+       /* NUMBER ws* '/' ws* NUMBER */
+
+       /* numerator, ws* already consumed */
+
+       token = parserutils_vector_iterate(vector, ctx);
+       if (token == NULL || tokenIsChar(token, '/') == false) {
+               return CSS_INVALID;
+       }
+
+       consumeWhitespace(vector, ctx);
+
+       token = parserutils_vector_iterate(vector, ctx);
+       if (token == NULL || token->type != CSS_TOKEN_NUMBER) {
+               return CSS_INVALID;
+       }
+
+       num = css__number_from_lwc_string(numerator->idata, true, &num_len);
+       den = css__number_from_lwc_string(token->idata, true, &den_len);
+
+       *ratio = css_divide_fixed(num, den);
+
+       return CSS_OK;
+}
+
+static css_error mq_create_feature(
+               lwc_string *name,
+               css_mq_feature **feature)
+{
+       css_mq_feature *f;
+
+       f = malloc(sizeof(*f));
+       if (f == NULL) {
+               return CSS_NOMEM;
+       }
+
+       memset(f, 0, sizeof(*f));
+
+       f->name = lwc_string_ref(name);
+
+       *feature = f;
+
+       return CSS_OK;
+}
+
+static css_error mq_populate_value(css_mq_value *value,
+               const css_token *token)
+{
+       if (token->type == CSS_TOKEN_NUMBER) {
+               size_t num_len;
+               value->type = CSS_MQ_VALUE_TYPE_NUM;
+               value->data.num_or_ratio = css__number_from_lwc_string(
+                               token->idata, false, &num_len);
+       } else if (token->type == CSS_TOKEN_DIMENSION) {
+               size_t len = lwc_string_length(token->idata);
+               const char *data = lwc_string_data(token->idata);
+               uint32_t unit = UNIT_PX;
+               size_t consumed;
+
+               value->type == CSS_MQ_VALUE_TYPE_DIM;
+               value->data.dim.len = css__number_from_lwc_string(
+                               token->idata, false, &consumed);
+               error = css__parse_unit_keyword(data + consumed, len - consumed,
+                               &unit);
+               if (error != CSS_OK) {
+                       return error;
+               }
+               value->data.dim.unit = temp_unit;
+       } else if (token->type == CSS_TOKEN_IDENT) {
+               value->type = CSS_MQ_VALUE_TYPE_IDENT;
+               value->data.ident = lwc_string_ref(token->idata);
+       }
+
+       return CSS_OK;
+}
+
+static css_error mq_parse_op(const css_token *token,
+               css_mq_feature_op *op)
+{
+       size_t len;
+       const char *data;
+
+       if (token == NULL || token->type != CSS_TOKEN_CHAR)
+               return CSS_INVALID;
+
+       len = lwc_string_length(token->idata);
+       data = lwc_string_data(token->idata);
+
+       if (len == 2) {
+               if (strncasecmp(data, "<=", 2) == 0)
+                       *op = CSS_MQ_FEATURE_OP_LTE;
+               else if (strncasecmp(data, ">=", 2) == 0)
+                       *op = CSS_MQ_FEATURE_OP_GTE;
+               else
+                       return CSS_INVALID;
+       } else if (len == 1) {
+               if (*data == '<')
+                       *op = CSS_MQ_FEATURE_OP_LT;
+               else if (*data == '=')
+                       *op = CSS_MQ_FEATURE_OP_EQ;
+               else if (*data == '>')
+                       *op = CSS_MQ_FEATURE_OP_GT;
+               else
+                       return CSS_INVALID;
+       } else {
+               return CSS_INVALID;
+       }
+
+       return CSS_OK;
+}
+
+static css_error mq_parse_range(css_language *c,
+               const parserutils_vector *vector, int *ctx,
+               const css_token *name_or_value,
+               css_mq_feature **feature)
+{
+       const css_token *token, *value_or_name, *name = NULL, *value2 = NULL;
+       css_mq_feature *result;
+       css_mq_feature_op op, op2;
+       css_fixed ratio, ratio2;
+       bool name_first = false, value_is_ratio = false, value2_is_ratio = 
false, match;
+       css_error error;
+
+       /* <mf-range> = <mf-name> [ '<' | '>' ]? '='? <mf-value>
+        *            | <mf-value> [ '<' | '>' ]? '='? <mf-name>
+        *            | <mf-value> '<' '='? <mf-name> '<' '='? <mf-value>
+        *            | <mf-value> '>' '='? <mf-name> '>' '='? <mf-value>
+        */
+
+       if (name_or_value == NULL || (name_or_value->type != CSS_TOKEN_NUMBER &&
+                       name_or_value->type != CSS_TOKEN_DIMENSION &&
+                       name_or_value->type != CSS_TOKEN_IDENT)) {
+               return CSS_INVALID;
+       }
+
+       consumeWhitespace(vector, ctx);
+
+       /* Name-or-value */
+       if (name_or_value->type == CSS_TOKEN_NUMBER &&
+                       tokenIsChar(parserutils_vector_peek(vector, *ctx), 
'/')) {
+               /* ratio */
+               error = mq_parse_ratio(c, vector, ctx, token, &ratio);
+               if (error != CSS_OK) {
+                       return error;
+               }
+
+               consumeWhitespace(vector, ctx);
+
+               value_is_ratio = true;
+       } else if (name_or_value->type == CSS_TOKEN_IDENT &&
+                       lwc_string_caseless_isequal(name_or_value->idata,
+                               c->strings[INFINITE], &match) == lwc_error_ok 
&& 
+                       match == false) {
+               /* The only ident permitted for mf-value is 'infinite', thus 
must have name */
+               name = name_or_value;
+               name_first = true;
+       }
+
+       /* Op */
+       token = parserutils_vector_iterate(vector, ctx);
+       error = mq_parse_op(token, &op);
+       if (error != CSS_OK) {
+               return error;
+       }
+
+       consumeWhitespace(vector, ctx);
+
+       /* Value-or-name */
+       value_or_name = parserutils_vector_iterate(vector, ctx);
+       if (value_or_name == NULL || (value_or_name->type != CSS_TOKEN_NUMBER &&
+                       value_or_name->type != CSS_TOKEN_DIMENSION &&
+                       value_or_name->type != CSS_TOKEN_IDENT)) {
+               return CSS_INVALID;
+       }
+
+       if (name == NULL) {
+               if (value_or_name->type != CSS_TOKEN_IDENT) {
+                       return CSS_INVALID;
+               } else {
+                       name = value_or_name;
+               }
+       }
+
+       consumeWhitespace(vector, ctx);
+
+       if (value_or_name->type == CSS_TOKEN_NUMBER &&
+                       tokenIsChar(parserutils_vector_peek(vector, *ctx), 
'/')) {
+               /* ratio */
+               error = mq_parse_ratio(c, vector, ctx, token, &ratio);
+               if (error != CSS_OK) {
+                       return error;
+               }
+
+               consumeWhitespace(vector, ctx);
+
+               value_is_ratio = true;
+       }
+
+       token = parserutils_vector_peek(vector, *ctx);
+       if (name_first == false && token != NULL && tokenIsChar(token, ')') == 
false) {
+               /* Op2 */
+               token = parserutils_vector_iterate(vector, ctx);
+               error = mq_parse_op(token, &op2);
+               if (error != CSS_OK) {
+                       return error;
+               }
+
+               consumeWhitespace(vector, ctx);
+
+               /* Validate operators: must both be LT(E) or GT(E) */
+               if (op == CSS_MQ_FEATURE_OP_LT || op == CSS_MQ_FEATURE_OP_LTE) {
+                       if (op2 != CSS_MQ_FEATURE_OP_LT && op2 != 
CSS_MQ_FEATURE_OP_LTE) {
+                               return CSS_INVALID;
+                       }
+               } else if (op == CSS_MQ_FEATURE_OP_GT || op == 
CSS_MQ_FEATURE_OP_GTE) {
+                      if (op2 != CSS_MQ_FEATURE_OP_GT && op2 != 
CSS_MQ_FEATURE_OP_GTE) {
+                               return CSS_INVALID;
+                       }
+               } else {
+                       return CSS_INVALID;
+               }
+
+               /* Value2 */
+               value2 = parserutils_vector_iterate(vector, ctx);
+               if (value2 == NULL || (value2->type != CSS_TOKEN_NUMBER &&
+                               value2->type != CSS_TOKEN_DIMENSION &&
+                               value2->type != CSS_TOKEN_IDENT)) {
+                       return CSS_INVALID;
+               }
+
+               consumeWhitespace(vector, ctx);
+
+               if (value_or_name->type == CSS_TOKEN_NUMBER &&
+                               tokenIsChar(parserutils_vector_peek(vector, 
*ctx), '/')) {
+                       /* ratio */
+                       error = mq_parse_ratio(c, vector, ctx, token, &ratio2);
+                       if (error != CSS_OK) {
+                               return error;
+                       }
+
+                       consumeWhitespace(vector, ctx);
+
+                       value2_is_ratio = true;
+               }
+       }
+
+       error = mq_create_feature(name->idata, &result);
+       if (error != CSS_OK) {
+               return error;
+       }
+       if (name_first) {
+               /* Invert operator */
+               if (op == CSS_MQ_FEATURE_OP_LT) {
+                       op = CSS_MQ_FEATURE_OP_GTE;
+               } else if (op == CSS_MQ_FEATURE_OP_LTE) {
+                       op = CSS_MQ_FEATURE_OP_GT;
+               } else if (op == CSS_MQ_FEATURE_OP_GT) {
+                       op = CSS_MQ_FEATURE_OP_LTE;
+               } else if (op == CSS_MQ_FEATURE_OP_GTE) {
+                       op = CSS_MQ_FEATURE_OP_LT;
+               }
+       }
+       result->op = op;
+       if (value_is_ratio) {
+               result->value.type = CSS_MQ_VALUE_TYPE_RATIO;
+               result->value.data.num_or_ratio = ratio;
+       } else {
+               /* num/dim/ident */
+               error = mq_populate_value(&result->value, token);
+               if (error != CSS_OK) {
+                       free(result);
+                       return error;
+               }
+       }
+       if (value2 != NULL) {
+               result->op2 = op2;
+               if (value2_is_ratio) {
+                       result->value2.type = CSS_MQ_VALUE_TYPE_RATIO;
+                       result->value2.data.num_or_ratio = ratio;
+               } else {
+                       /* num/dim/ident */
+                       error = mq_populate_value(&result->value2, token);
+                       if (error != CSS_OK) {
+                               /* TODO: clean up result properly? */
+                               free(result);
+                               return error;
+                       }
+               }
+       }
+
+       *feature = result;
+
+       return CSS_OK;
+}
+
+static css_error mq_parse_media_feature(css_language *c,
+               const parserutils_vector *vector, int *ctx,
+               css_mq_feature **feature)
+{
+       const css_token *name_or_value, *token;
+       css_mq_feature *result;
+       css_error error;
+
+       /* <media-feature> = ( [ <mf-plain> | <mf-boolean> | <mf-range> ] )
+        * <mf-plain> = <mf-name> : <mf-value>
+        * <mf-boolean> = <mf-name>
+        * <mf-name> = <ident>
+        * <mf-value> = <number> | <dimension> | <ident> | <ratio>
+        */
+
+       /* ( already consumed */
+
+       name_or_value = parserutils_vector_iterate(vector, ctx);
+       if (name_or_value == NULL)
+               return CSS_INVALID;
+
+       if (name_or_value->type == CSS_TOKEN_IDENT) {
+               consumeWhitespace(vector, ctx);
+
+               token = parserutils_vector_peek(vector, *ctx);
+               if (tokenIsChar(token, ')')) {
+                       /* mf-boolean */
+                       error = mq_create_feature(name_or_value->idata, 
&result);
+                       if (error != CSS_OK) {
+                               return error;
+                       }
+
+                       result->op = CSS_MQ_FEATURE_OP_BOOL;
+               } else if (tokenIsChar(token, ':')) {
+                       /* mf-plain */
+                       parserutils_vector_iterate(vector, ctx);
+
+                       consumeWhitespace(vector, ctx);
+
+                       token = parserutils_vector_iterate(vector, ctx);
+                       if (token == NULL || (token->type != CSS_TOKEN_NUMBER &&
+                                       token->type != CSS_TOKEN_DIMENSION &&
+                                       token->type != CSS_TOKEN_IDENT)) {
+                               return CSS_INVALID;
+                       }
+
+                       consumeWhitespace(vector, ctx);
+
+                       error = mq_create_feature(name_or_value->idata, 
&result);
+                       if (error != CSS_OK) {
+                               return error;
+                       }
+                       result->op = CSS_MQ_FEATURE_OP_EQ;
+
+                       if (token->type == CSS_TOKEN_NUMBER &&
+                                       
tokenIsChar(parserutils_vector_peek(vector, *ctx), '/')) {
+                               /* ratio */
+                               css_fixed ratio;
+
+                               error = mq_parse_ratio(c, vector, ctx, token, 
&ratio);
+                               if (error != CSS_OK) {
+                                       free(result);
+                                       return error;
+                               }
+
+                               result->value.type = CSS_MQ_VALUE_TYPE_RATIO;
+                               result->value.data.num_or_ratio = ratio;
+                       } else {
+                               /* num/dim/ident */
+                               error = mq_populate_value(&result->value, 
token);
+                               if (error != CSS_OK) {
+                                       free(result);
+                                       return error;
+                               }
+                       }
+
+                       consumeWhitespace(vector, ctx);
+               } else {
+                       /* mf-range */
+                       error = mq_parse_range(c, vector, ctx, name_or_value, 
&result);
+                       if (error != CSS_OK) {
+                               return error;
+                       }
+
+                       consumeWhitespace(vector, ctx);
+               }
+       } else {
+               /* mf-range */
+               error = mq_parse_range(c, vector, ctx, name_or_value, &result);
+               if (error != CSS_OK) {
+                       return error;
+               }
+
+               consumeWhitespace(vector, ctx);
+       }
+
+       token = parserutils_vector_iterate(vector, ctx);
+       if (tokenIsChar(token, ')') == false) {
+               /* TODO: clean up result */
+               return CSS_INVALID;
+       }
+
+       *feature = result;
+
+       return CSS_OK;
+}
+
+static css_error mq_parse_media_in_parens()
+{
+       /* <media-in-parens> = ( <media-condition> ) | <media-feature> | 
<general-enclosed>
+        * <general-enclosed> = [ <function-token> <any-value> ) ] | ( <ident> 
<any-value> )
+        */
+
+       //LPAREN -> condition-or-feature
+       //        "not" or LPAREN -> condition
+       //        IDENT | NUMBER | DIMENSION | RATIO -> feature
+
+}
+
+static css_error mq_parse_condition()
+{
+       /* <media-condition> = <media-not> | <media-in-parens> [ <media-and>* | 
<media-or>* ]
+        * <media-condition-without-or> = <media-not> | <media-in-parens> 
<media-and>*
+        * <media-not> = not <media-in-parens>
+        * <media-and> = and <media-in-parens>
+        * <media-or> = or <media-in-parens>
+        */
+}
 
 css_error css__mq_parse_media_list(css_language *c,
                const parserutils_vector *vector, int *ctx,
@@ -16,7 +452,19 @@ css_error css__mq_parse_media_list(css_language *c,
        css_mq_query *ret = NULL;
        const css_token *token;
 
-       /* (IDENT ws (',' ws IDENT ws)* )? */
+       /* <media-query-list> = <media-query> [ COMMA <media-query> ]*
+        * <media-query> = <media-condition>
+        *               | [ not | only ]? <media-type> [ and 
<media-condition-without-or> ]?
+        * <media-type> = <ident> (except "not", "and", "or", "only")
+        *
+        */
+
+       /* if {[(, push }]) to stack
+        * if func, push ) to stack
+        * on error, scan forward until stack is empty (or EOF), popping 
matching tokens off stack
+        * if stack is empty, the next input token must be comma or EOF
+        * if comma, consume, and start again from the next input token
+        */
 
        UNUSED(c);
 
diff --git a/src/parse/mq.h b/src/parse/mq.h
index 7d62e8c..c5268c7 100644
--- a/src/parse/mq.h
+++ b/src/parse/mq.h
@@ -22,7 +22,7 @@ typedef struct {
                css_fixed num_or_ratio; /* Where ratio is the result of a/b */
                struct {
                        css_fixed len;
-                       css_unit unit;
+                       uint32_t unit;
                } dim;
                lwc_string *ident;
        } data;
@@ -31,8 +31,8 @@ typedef struct {
 /*
  * "name : value" is encoded as "name = value"
  * "name" is encoded by setting the operator to "bool"
- * "name op value" is encoded verbatim (with op2 set to "unused")
- * "value op name" inverts the operator to encode (i.e < becomes >=) (and sets 
op2 to "unused")
+ * "value op name" is encoded verbatim (with op2 set to "unused")
+ * "name op value" inverts the operator to encode (i.e < becomes >=) (and sets 
op2 to "unused")
  * "value op name op value" is encoded using op2 and value2
  */
 typedef enum {
diff --git a/src/parse/properties/utils.c b/src/parse/properties/utils.c
index 82dacf8..97583c6 100644
--- a/src/parse/properties/utils.c
+++ b/src/parse/properties/utils.c
@@ -1007,6 +1007,16 @@ css_error css__parse_unit_keyword(const char *ptr, 
size_t len, uint32_t *unit)
        if (len == 4) {
                if (strncasecmp(ptr, "grad", 4) == 0)
                        *unit = UNIT_GRAD;
+               else if (strncasecmp(ptr, "turn", 4) == 0)
+                       *unit = UNIT_TURN;
+               else if (strncasecmp(ptr, "dppx", 4) == 0)
+                       *unit = UNIT_DPPX;
+               else if (strncasecmp(ptr, "dpcm", 4) == 0)
+                       *unit = UNIT_DPCM;
+               else if (strncasecmp(ptr, "vmin", 4) == 0)
+                       *unit = UNIT_VMIN;
+               else if (strncasecmp(ptr, "vmax", 4) == 0)
+                       *unit = UNIT_VMAX;
                else
                        return CSS_INVALID;
        } else if (len == 3) {
@@ -1016,6 +1026,12 @@ css_error css__parse_unit_keyword(const char *ptr, 
size_t len, uint32_t *unit)
                        *unit = UNIT_DEG;
                else if (strncasecmp(ptr, "rad", 3) == 0)
                        *unit = UNIT_RAD;
+               else if (strncasecmp(ptr, "dpi", 3) == 0)
+                       *unit = UNIT_DPI;
+               else if (strncasecmp(ptr, "rlh", 3) == 0)
+                       *unit = UNIT_RLH;
+               else if (strncasecmp(ptr, "rem", 3) == 0)
+                       *unit = UNIT_REM;
                else
                        return CSS_INVALID;
        } else if (len == 2) {
@@ -1039,11 +1055,27 @@ css_error css__parse_unit_keyword(const char *ptr, 
size_t len, uint32_t *unit)
                        *unit = UNIT_PT;
                else if (strncasecmp(ptr, "pc", 2) == 0)
                        *unit = UNIT_PC;
+               else if (strncasecmp(ptr, "ch", 2) == 0)
+                       *unit = UNIT_CH;
+               else if (strncasecmp(ptr, "ic", 2) == 0)
+                       *unit = UNIT_IC;
+               else if (strncasecmp(ptr, "lh", 2) == 0)
+                       *unit = UNIT_LH;
+               else if (strncasecmp(ptr, "vw", 2) == 0)
+                       *unit = UNIT_VW;
+               else if (strncasecmp(ptr, "vh", 2) == 0)
+                       *unit = UNIT_VH;
+               else if (strncasecmp(ptr, "vi", 2) == 0)
+                       *unit = UNIT_VI;
+               else if (strncasecmp(ptr, "vb", 2) == 0)
+                       *unit = UNIT_VB;
                else
                        return CSS_INVALID;
        } else if (len == 1) {
                if (strncasecmp(ptr, "s", 1) == 0)
                        *unit = UNIT_S;
+               else if (strncasecmp(ptr, "Q", 1) == 0)
+                       *unit = UNIT_Q;
                else
                        return CSS_INVALID;
        } else


-- 
Cascading Style Sheets library

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

Reply via email to