Gitweb links:

...log 
http://git.netsurf-browser.org/libcss.git/shortlog/0032d2c2b313c7c4afdd3866e72c38c440726a0e
...commit 
http://git.netsurf-browser.org/libcss.git/commit/0032d2c2b313c7c4afdd3866e72c38c440726a0e
...tree 
http://git.netsurf-browser.org/libcss.git/tree/0032d2c2b313c7c4afdd3866e72c38c440726a0e

The branch, tlsa/jmb/mq has been created
        at  0032d2c2b313c7c4afdd3866e72c38c440726a0e (commit)

- Log -----------------------------------------------------------------
commitdiff 
http://git.netsurf-browser.org/libcss.git/commit/?id=0032d2c2b313c7c4afdd3866e72c38c440726a0e
commit 0032d2c2b313c7c4afdd3866e72c38c440726a0e
Author: John-Mark Bell <[email protected]>
Commit: Michael Drake <[email protected]>

    Media Queries: remainder of parser

diff --git a/src/parse/mq.c b/src/parse/mq.c
index 96f70df..c557996 100644
--- a/src/parse/mq.c
+++ b/src/parse/mq.c
@@ -333,6 +333,8 @@ static css_error mq_parse_media_feature(css_language *c,
 
        /* ( already consumed */
 
+       consumeWhitespace(vector, ctx);
+
        name_or_value = parserutils_vector_iterate(vector, ctx);
        if (name_or_value == NULL)
                return CSS_INVALID;
@@ -423,42 +425,359 @@ static css_error mq_parse_media_feature(css_language *c,
        return CSS_OK;
 }
 
-static css_error mq_parse_media_in_parens()
+static css_error mq_parse_general_enclosed(css_language *c,
+               const parserutils_vector *vector, int *ctx)
 {
+       /* <general-enclosed> = [ <function-token> <any-value> ) ]
+        *                    | ( <ident> <any-value> )
+        */
+
+       /* TODO: implement */
+
+       return CSS_OK;
+}
+
+static css_error mq_parse_media_in_parens(css_language *c,
+               const parserutils_vector *vector, int *ctx,
+               css_mq_cond_or_feature **cond_or_feature)
+{
+       const css_token *token;
+       bool match;
+       int old_ctx;
+       cond_or_feature *result = NULL;
+       css_error error = CSS_OK;
+
        /* <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
 
+       token = parserutils_vector_iterate(vector, ctx);
+       if (token == NULL || tokenIsChar(token, '(') == false) {
+               return CSS_INVALID;
+       }
+
+       consumeWhitespace(vector, ctx);
+
+       token = parserutils_vector_peek(vector, *ctx);
+       if (token == NULL) {
+               return CSS_INVALID;
+       }
+
+       old_ctx = *ctx;
+
+       if (tokenIsChar(token, '(') || (token->type == CSS_TOKEN_IDENT &&
+                       lwc_string_caseless_isequal(token->idata,
+                               c->strings[NOT], &match) == lwc_error_ok &&
+                       match)) {
+               css_mq_cond *cond;
+               error = mq_parse_condition(c, vector, ctx, true, &cond);
+               if (error == CSS_OK) {
+                       token = parserutils_vector_iterate(vector, ctx);
+                       if (tokenIsChar(token, ')') == false) {
+                               return CSS_INVALID;
+                       }
+
+                       result = malloc(sizeof(*result));
+                       if (result == NULL) {
+                               /* TODO: clean up cond */
+                               return CSS_NOMEM;
+                       }
+                       memset(result, 0, sizeof(*result));
+                       result->type = CSS_MQ_COND;
+                       result->data.cond = cond;
+                       *cond_or_feature = result;
+                       return CSS_OK;
+               }
+       } else if (token->type == CSS_TOKEN_IDENT ||
+                       token->type == CSS_TOKEN_NUMBER ||
+                       token->type == CSS_TOKEN_DIMENSION) {
+               css_mq_feature *feature;
+               error = mq_parse_media_feature(c, vector, ctx, &feature);
+               if (error == CSS_OK) {
+                       result = malloc(sizeof(*result));
+                       if (result == NULL) {
+                               /* TODO: clean up feature */
+                               return CSS_NOMEM;
+                       }
+                       memset(result, 0, sizeof(*result));
+                       result->type = CSS_MQ_FEATURE;
+                       result->data.feat = feature;
+                       *cond_or_feature = result;
+                       return CSS_OK;
+               }
+       }
+
+       *ctx = old_ctx;
+       error = mq_parse_general_enclosed(c, vector, ctx);
+
+       return error;
 }
 
-static css_error mq_parse_condition()
+static css_error mq_parse_condition(css_language *c,
+               const parserutils_vector *vector, int *ctx,
+               bool permit_or, css_mq_cond **cond)
 {
+       const css_token *token;
+       bool match;
+       int op = 0; /* Will be AND | OR once we've had one */
+       css_mq_cond_or_feature *cond_or_feature, **parts;
+       css_mq_cond *result;
+       css_error error;
+
        /* <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>
         */
+
+       token = parserutils_vector_peek(vector, *ctx);
+       if (token == NULL || tokenIsChar(token, '(') == false ||
+                       token->type != CSS_TOKEN_IDENT ||
+                       lwc_string_caseless_isequal(token->idata,
+                               c->strings[NOT], &match) != lwc_error_ok ||
+                       match == false) {
+               return CSS_INVALID;
+       }
+
+       result = malloc(sizeof(*result));
+       if (result == NULL) {
+               return CSS_NOMEM;
+       }
+       memset(result, 0, sizeof(*result));
+       result->parts = malloc(sizeof(*result->parts));
+       if (result->parts == NULL) {
+               free(result);
+               return CSS_NOMEM;
+       }
+       memset(result->parts, 0, sizeof(*result->parts));
+
+       if (tokenIsChar(token, '(') == false) {
+               /* Must be "not" */
+               parserutils_vector_iterate(vector, ctx);
+               consumeWhitespace(vector, ctx);
+
+               error = mq_parse_media_in_parens(c, vector, ctx, 
&cond_or_feature);
+               if (error != CSS_OK) {
+                       free(result->parts);
+                       free(result);
+                       return CSS_INVALID;
+               }
+
+               result->negate = 1;
+               result->parts->nparts = 1;
+               result->parts->parts = malloc(sizeof(*result->parts->parts));
+               if (result->parts->parts == NULL) {
+                       /* TODO: clean up cond_or_feature */
+                       free(result->parts);
+                       free(result);
+                       return CSS_NOMEM;
+               }
+               result->parts->parts[0] = cond_or_feature;
+
+               *cond = result;
+
+               return CSS_OK;
+       }
+
+       /* FOLLOW(media-condition) := RPAREN | COMMA | EOF */
+       while (token != NULL && tokenIsChar(token, ')') == false &&
+                       tokenIsChar(token, ',') == false) {
+               error = mq_parse_media_in_parens(c, vector, ctx, 
&cond_or_feature);
+               if (error != CSS_OK) {
+                       /* TODO: clean up result->parts->parts */
+                       free(result->parts);
+                       free(result);
+                       return CSS_INVALID;
+               }
+
+               parts = realloc(result->parts->parts,
+                               
(result->parts->nparts+1)*sizeof(*result->parts->parts));
+               if (parts == NULL) {
+                       /* TODO: clean up result->parts->parts */
+                       free(result->parts);
+                       free(result);
+                       return CSS_NOMEM;
+               }
+               parts[result->parts->nparts] = cond_or_feature;
+               result->parts->parts = parts;
+               result->parts->nparts++;
+
+               consumeWhitespace(vector, token);
+
+               token = parserutils_vector_peek(vector, *ctx);
+               if (token != NULL && tokenIsChar(token, ')') == false &&
+                               tokenIsChar(token, ',') == false) {
+                       if (token->type != CSS_TOKEN_IDENT) {
+                               /* TODO: clean up result->parts->parts */
+                               free(result->parts);
+                               free(result);
+                               return CSS_INVALID;
+                       } else if (lwc_string_caseless_isequal(token->idata,
+                                       c->strings[AND], &match) == 
lwc_error_ok &&
+                                       match) {
+                               if (op != 0 && op != AND) {
+                                       /* TODO: clean up result->parts->parts 
*/
+                                       free(result->parts);
+                                       free(result);
+                                       return CSS_INVALID;
+                               }
+                               op = AND;
+                       } else if (lwc_string_caseless_isequal(token->idata,
+                                               c->strings[OR], &match) == 
lwc_error_ok &&
+                                       match) {
+                               if (permit_or == false || (op != 0 && op != 
OR)) {
+                                       /* TODO: clean up result->parts->parts 
*/
+                                       free(result->parts);
+                                       free(result);
+                                       return CSS_INVALID;
+                               }
+                               op = OR;
+                       } else {
+                               /* Neither AND nor OR */
+                               /* TODO: clean up result->parts->parts */
+                               free(result->parts);
+                               free(result);
+                               return CSS_INVALID;
+                       }
+
+                       parserutils_vector_iterate(vector, ctx);
+                       consumeWhitespace(vector, ctx);
+               }
+       }
+
+       if (op == OR) {
+               result->op = 1;
+       }
+
+       *cond = result;
+
+       return CSS_OK;
 }
 
-css_error css__mq_parse_media_list(css_language *c,
+static css_error mq_parse_media_query(css_language *c,
                const parserutils_vector *vector, int *ctx,
-               css_mq_query **media)
+               css_mq_query **query)
 {
-       css_mq_query *ret = NULL;
        const css_token *token;
+       bool match, is_condition = false;
+       css_mq_query *result;
+       css_error error;
 
-       /* <media-query-list> = <media-query> [ COMMA <media-query> ]*
-        * <media-query> = <media-condition>
+       /* <media-query> = <media-condition>
         *               | [ not | only ]? <media-type> [ and 
<media-condition-without-or> ]?
         * <media-type> = <ident> (except "not", "and", "or", "only")
-        *
         */
 
+       // LPAREN -> media-condition
+       //    not LPAREN -> media-condition
+
+       consumeWhitespace(vector, ctx);
+
+       token = parserutils_vector_peek(vector, *ctx);
+       if (tokenIsChar(token, '(')) {
+               is_condition = true;
+       } else if (token->type == CSS_TOKEN_IDENT &&
+                       lwc_string_caseless_isequal(token->idata,
+                               c->strings[NOT], &match) == lwc_error_ok &&
+                               match) {
+               int old_ctx = *ctx;
+
+               parserutils_vector_iterate(vector, ctx);
+               consumeWhitespace(vector, ctx);
+
+               token = parserutils_vector_peek(vector, *ctx);
+               if (tokenIsChar(token, '(')) {
+                       is_condition = true;
+               }
+
+               *ctx = old_ctx;
+       }
+
+       result = malloc(sizeof(*result));
+       if (result == NULL) {
+               return CSS_NOMEM;
+       }
+       memset(result, 0, sizeof(*result));
+
+       if (is_condition) {
+               /* media-condition */
+               error = mq_parse_condition(c, vector, ctx, true, &result->cond);
+               if (error != CSS_OK) {
+                       free(result);
+                       return error;
+               }
+
+               *query = result;
+               return CSS_OK;
+       }
+
+       token = parserutils_vector_iterate(vector, ctx);
+       if (token == NULL || token->type != CSS_TOKEN_IDENT) {
+               free(result);
+               return CSS_INVALID;
+       }
+
+       if (lwc_string_caseless_isequal(token->idata,
+                       c->strings[NOT], &match) == lwc_error_ok &&
+                       match) {
+               result->negate_type = 1;
+               consumeWhitespace(vector, ctx);
+               token = parserutils_vector_iterate(vector, ctx);
+       } else if (lwc_string_caseless_isequal(token->idata,
+                       c->strings[ONLY], &match) == lwc_error_ok &&
+                       match) {
+               consumeWhitespace(vector, ctx);
+               token = parserutils_vector_iterate(vector, ctx);
+       }
+
+       if (token == NULL || token->type != CSS_TOKEN_IDENT) {
+               free(result);
+               return CSS_INVALID;
+       }
+
+       result->type = lwc_string_ref(token->idata);
+
+       consumeWhitespace(vector, ctx);
+
+       token = parserutils_vector_iterate(vector, ctx);
+       if (token != NULL) {
+               if (token->type != CSS_TOKEN_IDENT ||
+                               lwc_string_caseless_isequal(token->idata,
+                                       c->strings[AND], &match) != 
lwc_error_ok ||
+                               match == false) {
+                       lwc_string_unref(result->type);
+                       free(result);
+                       return CSS_INVALID;
+               }
+
+               consumeWhitespace(vector, ctx);
+
+               error = mq_parse_condition(c, vector, ctx, false, 
&result->cond);
+               if (error != CSS_OK) {
+                       lwc_string_unref(result->type);
+                       free(result);
+                       return error;
+               }
+       }
+
+       *query = result;
+       return CSS_OK;
+}
+
+css_error css__mq_parse_media_list(css_language *c,
+               const parserutils_vector *vector, int *ctx,
+               css_mq_query **media)
+{
+       css_mq_query *result = NULL, *last;
+       const css_token *token;
+       css_error error;
+
+       /* <media-query-list> = <media-query> [ COMMA <media-query> ]* */
+
        /* if {[(, push }]) to stack
         * if func, push ) to stack
         * on error, scan forward until stack is empty (or EOF), popping 
matching tokens off stack
@@ -466,78 +785,32 @@ css_error css__mq_parse_media_list(css_language *c,
         * if comma, consume, and start again from the next input token
         */
 
-       UNUSED(c);
-
-       token = parserutils_vector_iterate(vector, ctx);
-
+       token = parserutils_vector_peek(vector, *ctx);
        while (token != NULL) {
-               if (token->type != CSS_TOKEN_IDENT)
-                       return CSS_INVALID;
+               css_mq_query *query;
+
+               error = mq_parse_media_query(c, vector, ctx, &query);
+               if (error != CSS_OK) {
+                       /* TODO: error recovery (see above) */
+               } else {
+                       if (result == NULL) {
+                               result = last = query;
+                       } else {
+                               last->next = query;
+                               last = query;
+                       }
+               }
 
-#if 0
-               if (lwc_string_caseless_isequal(token->idata, 
c->strings[AURAL], 
-                               &match) == lwc_error_ok && match) {
-                       ret |= CSS_MEDIA_AURAL;
-               } else if (lwc_string_caseless_isequal(
-                               token->idata, c->strings[BRAILLE], 
-                               &match) == lwc_error_ok && match) {
-                       ret |= CSS_MEDIA_BRAILLE;
-               } else if (lwc_string_caseless_isequal(
-                               token->idata, c->strings[EMBOSSED], 
-                               &match) == lwc_error_ok && match) {
-                       ret |= CSS_MEDIA_EMBOSSED;
-               } else if (lwc_string_caseless_isequal(
-                               token->idata, c->strings[HANDHELD], 
-                               &match) == lwc_error_ok && match) {
-                       ret |= CSS_MEDIA_HANDHELD;
-               } else if (lwc_string_caseless_isequal(
-                               token->idata, c->strings[PRINT], 
-                               &match) == lwc_error_ok && match) {
-                       ret |= CSS_MEDIA_PRINT;
-               } else if (lwc_string_caseless_isequal(
-                               token->idata, c->strings[PROJECTION], 
-                               &match) == lwc_error_ok && match) {
-                       ret |= CSS_MEDIA_PROJECTION;
-               } else if (lwc_string_caseless_isequal(
-                               token->idata, c->strings[SCREEN], 
-                               &match) == lwc_error_ok && match) {
-                       ret |= CSS_MEDIA_SCREEN;
-               } else if (lwc_string_caseless_isequal(
-                               token->idata, c->strings[SPEECH], 
-                               &match) == lwc_error_ok && match) {
-                       ret |= CSS_MEDIA_SPEECH;
-               } else if (lwc_string_caseless_isequal(
-                               token->idata, c->strings[TTY], 
-                               &match) == lwc_error_ok && match) {
-                       ret |= CSS_MEDIA_TTY;
-               } else if (lwc_string_caseless_isequal(
-                               token->idata, c->strings[TV], 
-                               &match) == lwc_error_ok && match) {
-                       ret |= CSS_MEDIA_TV;
-               } else if (lwc_string_caseless_isequal(
-                               token->idata, c->strings[ALL], 
-                               &match) == lwc_error_ok && match) {
-                       ret |= CSS_MEDIA_ALL;
-               } else
-                       return CSS_INVALID;
-#endif
                consumeWhitespace(vector, ctx);
 
                token = parserutils_vector_iterate(vector, ctx);
-               if (token != NULL && tokenIsChar(token, ',') == false)
-                       return CSS_INVALID;
-
-               consumeWhitespace(vector, ctx);
+               if (token != NULL && tokenIsChar(token, ',') == false) {
+                       /* Give up */
+                       break;
+               }
        }
 
-#if 0
-       /* If, after parsing the media list, we still have no media, 
-        * then it must be ALL. */
-       if (ret == 0)
-               ret = CSS_MEDIA_ALL;
-#endif
-
-       *media = ret;
+       *media = result;
 
        return CSS_OK;
 }
diff --git a/src/parse/mq.h b/src/parse/mq.h
index c5268c7..ae0110b 100644
--- a/src/parse/mq.h
+++ b/src/parse/mq.h
@@ -73,20 +73,18 @@ struct css_mq_cond_or_feature {
                CSS_MQ_COND
        } type;
        union {
-               css_mq_cond cond;
-               css_mq_feature feat;
+               css_mq_cond *cond;
+               css_mq_feature *feat;
        } data;
 };
 
 typedef struct css_mq_query {
        struct css_mq_query *next;
 
-       uint32_t negate_type : 1, /* set if "not type" */
-                cond_op     : 1; /* clear if "and", set if "or" */
+       uint32_t negate_type : 1; /* set if "not type" */
        lwc_string *type; /* or NULL */
 
-       uint32_t nconds;
-       css_mq_cond **conds;
+       css_mq_cond *cond;
 } css_mq_query;
 
 css_error css__mq_parse_media_list(css_language *c,


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

    Propstrings: add AND, ONLY, OR

diff --git a/src/parse/propstrings.c b/src/parse/propstrings.c
index bfd2965..dc32ce9 100644
--- a/src/parse/propstrings.c
+++ b/src/parse/propstrings.c
@@ -439,6 +439,9 @@ const stringmap_entry stringmap[LAST_KNOWN] = {
        { "column-reverse", SLEN("column-reverse") },
        { "wrap", SLEN("wrap") },
        { "wrap-reverse", SLEN("wrap-reverse") },
+       { "and", SLEN("and") },
+       { "or", SLEN("or") },
+       { "only", SLEN("only") },
 
        { "aliceblue", SLEN("aliceblue") },
        { "antiquewhite", SLEN("antiquewhite") },
diff --git a/src/parse/propstrings.h b/src/parse/propstrings.h
index 67eaa5f..0d5d0be 100644
--- a/src/parse/propstrings.h
+++ b/src/parse/propstrings.h
@@ -101,7 +101,7 @@ enum {
        AVOID_PAGE, AVOID_COLUMN, BALANCE, HORIZONTAL_TB, VERTICAL_RL,
        VERTICAL_LR, CONTENT_BOX, BORDER_BOX, STRETCH, INLINE_FLEX, FLEX_START,
        FLEX_END, SPACE_BETWEEN, SPACE_AROUND, SPACE_EVENLY, ROW, ROW_REVERSE,
-       COLUMN_REVERSE, WRAP_STRING, WRAP_REVERSE,
+       COLUMN_REVERSE, WRAP_STRING, WRAP_REVERSE, AND, OR, ONLY,
 
        /* Named colours */
        FIRST_COLOUR,


commitdiff 
http://git.netsurf-browser.org/libcss.git/commit/?id=aa99505f8fb7612162e25f0a0d032d354ee1cd7a
commit aa99505f8fb7612162e25f0a0d032d354ee1cd7a
Author: John-Mark Bell <[email protected]>
Commit: Michael Drake <[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=dd272fe8cc3144370e14a69acb5476c7d5568190
commit dd272fe8cc3144370e14a69acb5476c7d5568190
Author: John-Mark Bell <[email protected]>
Commit: Michael Drake <[email protected]>

    Units: parse new unit names

diff --git a/src/bytecode/bytecode.h b/src/bytecode/bytecode.h
index 422f141..22703f7 100644
--- a/src/bytecode/bytecode.h
+++ b/src/bytecode/bytecode.h
@@ -52,6 +52,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,
@@ -59,7 +60,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 76b406b..f9555d2 100644
--- a/src/parse/properties/utils.c
+++ b/src/parse/properties/utils.c
@@ -1007,6 +1007,12 @@ 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)
@@ -1026,6 +1032,8 @@ css_error css__parse_unit_keyword(const char *ptr, size_t 
len, uint32_t *unit)
                        *unit = UNIT_REM;
                else if (strncasecmp(ptr, "rlh", 3) == 0)
                        *unit = UNIT_RLH;
+               else if (strncasecmp(ptr, "dpi", 3) == 0)
+                       *unit = UNIT_DPI;
                else
                        return CSS_INVALID;
        } else if (len == 2) {


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

    Media Queries: sort out object lifetimes

diff --git a/src/parse/language.c b/src/parse/language.c
index a5f57d3..c3b523d 100644
--- a/src/parse/language.c
+++ b/src/parse/language.c
@@ -416,8 +416,7 @@ css_error handleStartAtRule(css_language *c, const 
parserutils_vector *vector)
                        lwc_string *url;
                        css_mq_query *media = NULL;
 
-                       /* any0 = (STRING | URI) ws
-                        *        (media query)? */
+                       /* any0 = (STRING | URI) ws (media query)? */
                        const css_token *uri =
                                parserutils_vector_iterate(vector, &ctx);
                        if (uri == NULL || (uri->type != CSS_TOKEN_STRING &&
@@ -435,7 +434,7 @@ css_error handleStartAtRule(css_language *c, const 
parserutils_vector *vector)
                        error = css__stylesheet_rule_create(c->sheet,
                                        CSS_RULE_IMPORT, &rule);
                        if (error != CSS_OK) {
-                               css__mq_query_unref(media);
+                               css__mq_query_destroy(media);
                                return error;
                        }
 
@@ -444,8 +443,8 @@ css_error handleStartAtRule(css_language *c, const 
parserutils_vector *vector)
                                        c->sheet->url,
                                        uri->idata, &url);
                        if (error != CSS_OK) {
-                               css__mq_query_unref(media);
                                css__stylesheet_rule_destroy(c->sheet, rule);
+                               css__mq_query_destroy(media);
                                return error;
                        }
 
@@ -454,8 +453,8 @@ css_error handleStartAtRule(css_language *c, const 
parserutils_vector *vector)
                                        rule, url, media);
                        if (error != CSS_OK) {
                                lwc_string_unref(url);
-                               css__mq_query_unref(media);
                                css__stylesheet_rule_destroy(c->sheet, rule);
+                               css__mq_query_destroy(media);
                                return error;
                        }
 
@@ -465,16 +464,14 @@ css_error handleStartAtRule(css_language *c, const 
parserutils_vector *vector)
                                                c->sheet, url);
                                if (error != CSS_OK) {
                                        lwc_string_unref(url);
-                                       css__mq_query_unref(media);
                                        css__stylesheet_rule_destroy(c->sheet,
                                                        rule);
                                        return error;
                                }
                        }
 
-                       /* No longer care about url or media */
+                       /* No longer care about url */
                        lwc_string_unref(url);
-                       css__mq_query_unref(media);
 
                        /* Add rule to sheet */
                        error = css__stylesheet_add_rule(c->sheet, rule, NULL);
@@ -542,26 +539,23 @@ css_error handleStartAtRule(css_language *c, const 
parserutils_vector *vector)
                error = css__stylesheet_rule_create(c->sheet,
                                CSS_RULE_MEDIA, &rule);
                if (error != CSS_OK) {
-                       css__mq_query_unref(media);
+                       css__mq_query_destroy(media);
                        return error;
                }
 
                error = css__stylesheet_rule_set_media(c->sheet, rule, media);
                if (error != CSS_OK) {
                        css__stylesheet_rule_destroy(c->sheet, rule);
-                       css__mq_query_unref(media);
+                       css__mq_query_destroy(media);
                        return error;
                }
 
                error = css__stylesheet_add_rule(c->sheet, rule, NULL);
                if (error != CSS_OK) {
                        css__stylesheet_rule_destroy(c->sheet, rule);
-                       css__mq_query_unref(media);
                        return error;
                }
 
-               css__mq_query_unref(media);
-
                /* Rule is now owned by the sheet,
                 * so no need to destroy it */
 
diff --git a/src/parse/mq.h b/src/parse/mq.h
index eeb55da..7d62e8c 100644
--- a/src/parse/mq.h
+++ b/src/parse/mq.h
@@ -93,8 +93,6 @@ css_error css__mq_parse_media_list(css_language *c,
                const parserutils_vector *vector, int *ctx,
                css_mq_query **media);
 
-/** \todo is this necessary? */
-css_mq_query *css__mq_query_ref(css_mq_query *media);
-css_mq_query *css__mq_query_unref(css_mq_query *media);
+css_mq_query *css__mq_query_destroy(css_mq_query *media);
 
 #endif
diff --git a/src/stylesheet.c b/src/stylesheet.c
index b1801ed..22c7681 100644
--- a/src/stylesheet.c
+++ b/src/stylesheet.c
@@ -12,6 +12,7 @@
 #include "stylesheet.h"
 #include "bytecode/bytecode.h"
 #include "parse/language.h"
+#include "parse/mq.h"
 #include "utils/parserutilserror.h"
 #include "utils/utils.h"
 #include "select/dispatch.h"
@@ -1151,6 +1152,9 @@ css_error css__stylesheet_rule_destroy(css_stylesheet 
*sheet, css_rule *rule)
                css_rule_import *import = (css_rule_import *) rule;
 
                lwc_string_unref(import->url);
+               if (import->media != NULL) {
+                       css__mq_query_destroy(import->media);
+               }
 
                /* Do not destroy imported sheet: it is owned by the client */
        }
@@ -1160,6 +1164,10 @@ css_error css__stylesheet_rule_destroy(css_stylesheet 
*sheet, css_rule *rule)
                css_rule_media *media = (css_rule_media *) rule;
                css_rule *c, *d;
 
+               if (media->media != NULL) {
+                       css__mq_query_destroy(media->media);
+               }
+
                for (c = media->first_child; c != NULL; c = d) {
                        d = c->next;
 
@@ -1335,7 +1343,7 @@ css_error 
css__stylesheet_rule_set_nascent_import(css_stylesheet *sheet,
 
        /* Set the rule's sheet field */
        r->url = lwc_string_ref(url);
-       r->media = css__mq_query_ref(media);
+       r->media = media;
 
        return CSS_OK;
 }
@@ -1360,7 +1368,7 @@ css_error css__stylesheet_rule_set_media(css_stylesheet 
*sheet,
        assert(rule->type == CSS_RULE_MEDIA);
 
        /* Set the rule's media */
-       r->media = css__mq_query_ref(media);
+       r->media = media;
 
        return CSS_OK;
 }


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

    Media Queries: datastructures and plumbing.
    
    No parse implementation as yet.
    
    Selection hasn't been updated, either. One item of note
    in that area is that a client currently provides the
    media for top-level sheets being added to a selection
    context. This probably needs to change to providing a
    lwc_string containing the verbatim media query from
    the containing document's import mechanism. That way,
    the internal representation of media queries can remain
    opaque to clients.

diff --git a/include/libcss/stylesheet.h b/include/libcss/stylesheet.h
index 68c4dfc..542f199 100644
--- a/include/libcss/stylesheet.h
+++ b/include/libcss/stylesheet.h
@@ -36,7 +36,6 @@ typedef css_error (*css_url_resolution_fn)(void *pw,
  * \param pw      Client data
  * \param parent  Stylesheet requesting the import
  * \param url     URL of the imported sheet
- * \param media   Applicable media for the imported sheet
  * \return CSS_OK on success, appropriate error otherwise
  *
  * \note This function will be invoked for notification purposes
@@ -46,7 +45,7 @@ typedef css_error (*css_url_resolution_fn)(void *pw,
  *       registration API.
  */
 typedef css_error (*css_import_notification_fn)(void *pw,
-               css_stylesheet *parent, lwc_string *url, uint64_t media);
+               css_stylesheet *parent, lwc_string *url);
 
 /**
  * Callback use to resolve system colour names to RGB values
@@ -145,7 +144,7 @@ css_error css_stylesheet_append_data(css_stylesheet *sheet,
 css_error css_stylesheet_data_done(css_stylesheet *sheet);
 
 css_error css_stylesheet_next_pending_import(css_stylesheet *parent,
-               lwc_string **url, uint64_t *media);
+               lwc_string **url);
 css_error css_stylesheet_register_import(css_stylesheet *parent,
                css_stylesheet *child);
 
diff --git a/src/parse/Makefile b/src/parse/Makefile
index 99f55d0..6d11096 100644
--- a/src/parse/Makefile
+++ b/src/parse/Makefile
@@ -1,4 +1,4 @@
 # Sources
-DIR_SOURCES := parse.c language.c important.c propstrings.c font_face.c
+DIR_SOURCES := parse.c language.c important.c propstrings.c font_face.c mq.c
 
 include $(NSBUILD)/Makefile.subdir
diff --git a/src/parse/language.c b/src/parse/language.c
index 9af2547..a5f57d3 100644
--- a/src/parse/language.c
+++ b/src/parse/language.c
@@ -15,6 +15,7 @@
 #include "parse/font_face.h"
 #include "parse/important.h"
 #include "parse/language.h"
+#include "parse/mq.h"
 #include "parse/parse.h"
 #include "parse/propstrings.h"
 #include "parse/properties/properties.h"
@@ -53,9 +54,6 @@ static css_error handleDeclaration(css_language *c,
                const parserutils_vector *vector);
 
 /* At-rule parsing */
-static css_error parseMediaList(css_language *c,
-               const parserutils_vector *vector, int *ctx,
-               uint64_t *media);
 static css_error addNamespace(css_language *c,
                lwc_string *prefix, lwc_string *uri);
 static css_error lookupNamespace(css_language *c,
@@ -416,10 +414,10 @@ css_error handleStartAtRule(css_language *c, const 
parserutils_vector *vector)
                        match) {
                if (c->state <= IMPORT_PERMITTED) {
                        lwc_string *url;
-                       uint64_t media = 0;
+                       css_mq_query *media = NULL;
 
                        /* any0 = (STRING | URI) ws
-                        *        (IDENT ws (',' ws IDENT ws)* )? */
+                        *        (media query)? */
                        const css_token *uri =
                                parserutils_vector_iterate(vector, &ctx);
                        if (uri == NULL || (uri->type != CSS_TOKEN_STRING &&
@@ -429,21 +427,24 @@ css_error handleStartAtRule(css_language *c, const 
parserutils_vector *vector)
                        consumeWhitespace(vector, &ctx);
 
                        /* Parse media list */
-                       error = parseMediaList(c, vector, &ctx, &media);
+                       error = css__mq_parse_media_list(c, vector, &ctx, 
&media);
                        if (error != CSS_OK)
                                return error;
 
                        /* Create rule */
                        error = css__stylesheet_rule_create(c->sheet,
                                        CSS_RULE_IMPORT, &rule);
-                       if (error != CSS_OK)
+                       if (error != CSS_OK) {
+                               css__mq_query_unref(media);
                                return error;
+                       }
 
                        /* Resolve import URI */
                        error = c->sheet->resolve(c->sheet->resolve_pw,
                                        c->sheet->url,
                                        uri->idata, &url);
                        if (error != CSS_OK) {
+                               css__mq_query_unref(media);
                                css__stylesheet_rule_destroy(c->sheet, rule);
                                return error;
                        }
@@ -453,6 +454,7 @@ css_error handleStartAtRule(css_language *c, const 
parserutils_vector *vector)
                                        rule, url, media);
                        if (error != CSS_OK) {
                                lwc_string_unref(url);
+                               css__mq_query_unref(media);
                                css__stylesheet_rule_destroy(c->sheet, rule);
                                return error;
                        }
@@ -460,17 +462,19 @@ css_error handleStartAtRule(css_language *c, const 
parserutils_vector *vector)
                        /* Inform client of need for import */
                        if (c->sheet->import != NULL) {
                                error = c->sheet->import(c->sheet->import_pw,
-                                               c->sheet, url, media);
+                                               c->sheet, url);
                                if (error != CSS_OK) {
                                        lwc_string_unref(url);
+                                       css__mq_query_unref(media);
                                        css__stylesheet_rule_destroy(c->sheet,
                                                        rule);
                                        return error;
                                }
                        }
 
-                       /* No longer care about url */
+                       /* No longer care about url or media */
                        lwc_string_unref(url);
+                       css__mq_query_unref(media);
 
                        /* Add rule to sheet */
                        error = css__stylesheet_add_rule(c->sheet, rule, NULL);
@@ -527,31 +531,37 @@ css_error handleStartAtRule(css_language *c, const 
parserutils_vector *vector)
                }
        } else if (lwc_string_caseless_isequal(atkeyword->idata, 
c->strings[MEDIA],
                        &match) == lwc_error_ok && match) {
-               uint64_t media = 0;
+               css_mq_query *media = NULL;
 
-               /* any0 = IDENT ws (',' ws IDENT ws)* */
+               /* any0 = media query */
 
-               error = parseMediaList(c, vector, &ctx, &media);
+               error = css__mq_parse_media_list(c, vector, &ctx, &media);
                if (error != CSS_OK)
                        return error;
 
                error = css__stylesheet_rule_create(c->sheet,
                                CSS_RULE_MEDIA, &rule);
-               if (error != CSS_OK)
+               if (error != CSS_OK) {
+                       css__mq_query_unref(media);
                        return error;
+               }
 
                error = css__stylesheet_rule_set_media(c->sheet, rule, media);
                if (error != CSS_OK) {
                        css__stylesheet_rule_destroy(c->sheet, rule);
+                       css__mq_query_unref(media);
                        return error;
                }
 
                error = css__stylesheet_add_rule(c->sheet, rule, NULL);
                if (error != CSS_OK) {
                        css__stylesheet_rule_destroy(c->sheet, rule);
+                       css__mq_query_unref(media);
                        return error;
                }
 
+               css__mq_query_unref(media);
+
                /* Rule is now owned by the sheet,
                 * so no need to destroy it */
 
@@ -795,85 +805,6 @@ css_error handleDeclaration(css_language *c, const 
parserutils_vector *vector)
  * At-rule parsing functions                                                 *
  
******************************************************************************/
 
-css_error parseMediaList(css_language *c,
-               const parserutils_vector *vector, int *ctx,
-               uint64_t *media)
-{
-       uint64_t ret = 0;
-       bool match = false;
-       const css_token *token;
-
-       token = parserutils_vector_iterate(vector, ctx);
-
-       while (token != NULL) {
-               if (token->type != CSS_TOKEN_IDENT)
-                       return CSS_INVALID;
-
-               if (lwc_string_caseless_isequal(token->idata, c->strings[AURAL],
-                               &match) == lwc_error_ok && match) {
-                       ret |= CSS_MEDIA_AURAL;
-               } else if (lwc_string_caseless_isequal(
-                               token->idata, c->strings[BRAILLE],
-                               &match) == lwc_error_ok && match) {
-                       ret |= CSS_MEDIA_BRAILLE;
-               } else if (lwc_string_caseless_isequal(
-                               token->idata, c->strings[EMBOSSED],
-                               &match) == lwc_error_ok && match) {
-                       ret |= CSS_MEDIA_EMBOSSED;
-               } else if (lwc_string_caseless_isequal(
-                               token->idata, c->strings[HANDHELD],
-                               &match) == lwc_error_ok && match) {
-                       ret |= CSS_MEDIA_HANDHELD;
-               } else if (lwc_string_caseless_isequal(
-                               token->idata, c->strings[PRINT],
-                               &match) == lwc_error_ok && match) {
-                       ret |= CSS_MEDIA_PRINT;
-               } else if (lwc_string_caseless_isequal(
-                               token->idata, c->strings[PROJECTION],
-                               &match) == lwc_error_ok && match) {
-                       ret |= CSS_MEDIA_PROJECTION;
-               } else if (lwc_string_caseless_isequal(
-                               token->idata, c->strings[SCREEN],
-                               &match) == lwc_error_ok && match) {
-                       ret |= CSS_MEDIA_SCREEN;
-               } else if (lwc_string_caseless_isequal(
-                               token->idata, c->strings[SPEECH],
-                               &match) == lwc_error_ok && match) {
-                       ret |= CSS_MEDIA_SPEECH;
-               } else if (lwc_string_caseless_isequal(
-                               token->idata, c->strings[TTY],
-                               &match) == lwc_error_ok && match) {
-                       ret |= CSS_MEDIA_TTY;
-               } else if (lwc_string_caseless_isequal(
-                               token->idata, c->strings[TV],
-                               &match) == lwc_error_ok && match) {
-                       ret |= CSS_MEDIA_TV;
-               } else if (lwc_string_caseless_isequal(
-                               token->idata, c->strings[ALL],
-                               &match) == lwc_error_ok && match) {
-                       ret |= CSS_MEDIA_ALL;
-               } else
-                       return CSS_INVALID;
-
-               consumeWhitespace(vector, ctx);
-
-               token = parserutils_vector_iterate(vector, ctx);
-               if (token != NULL && tokenIsChar(token, ',') == false)
-                       return CSS_INVALID;
-
-               consumeWhitespace(vector, ctx);
-       }
-
-       /* If, after parsing the media list, we still have no media,
-        * then it must be ALL. */
-       if (ret == 0)
-               ret = CSS_MEDIA_ALL;
-
-       *media = ret;
-
-       return CSS_OK;
-}
-
 /**
  * Add a namespace mapping
  *
diff --git a/src/parse/mq.c b/src/parse/mq.c
new file mode 100644
index 0000000..5c9c7fa
--- /dev/null
+++ b/src/parse/mq.c
@@ -0,0 +1,96 @@
+/*
+ * This file is part of LibCSS.
+ * Licensed under the MIT License,
+ *               http://www.opensource.org/licenses/mit-license.php
+ * Copyright 2016 John-Mark Bell <[email protected]>
+ */
+
+/* https://drafts.csswg.org/mediaqueries/ */
+
+#include "parse/mq.h"
+
+css_error css__mq_parse_media_list(css_language *c,
+               const parserutils_vector *vector, int *ctx,
+               css_mq_query **media)
+{
+       css_mq_query *ret = NULL;
+       const css_token *token;
+
+       /* (IDENT ws (',' ws IDENT ws)* )? */
+
+       UNUSED(c);
+
+       token = parserutils_vector_iterate(vector, ctx);
+
+       while (token != NULL) {
+               if (token->type != CSS_TOKEN_IDENT)
+                       return CSS_INVALID;
+
+#if 0
+               if (lwc_string_caseless_isequal(token->idata, 
c->strings[AURAL], 
+                               &match) == lwc_error_ok && match) {
+                       ret |= CSS_MEDIA_AURAL;
+               } else if (lwc_string_caseless_isequal(
+                               token->idata, c->strings[BRAILLE], 
+                               &match) == lwc_error_ok && match) {
+                       ret |= CSS_MEDIA_BRAILLE;
+               } else if (lwc_string_caseless_isequal(
+                               token->idata, c->strings[EMBOSSED], 
+                               &match) == lwc_error_ok && match) {
+                       ret |= CSS_MEDIA_EMBOSSED;
+               } else if (lwc_string_caseless_isequal(
+                               token->idata, c->strings[HANDHELD], 
+                               &match) == lwc_error_ok && match) {
+                       ret |= CSS_MEDIA_HANDHELD;
+               } else if (lwc_string_caseless_isequal(
+                               token->idata, c->strings[PRINT], 
+                               &match) == lwc_error_ok && match) {
+                       ret |= CSS_MEDIA_PRINT;
+               } else if (lwc_string_caseless_isequal(
+                               token->idata, c->strings[PROJECTION], 
+                               &match) == lwc_error_ok && match) {
+                       ret |= CSS_MEDIA_PROJECTION;
+               } else if (lwc_string_caseless_isequal(
+                               token->idata, c->strings[SCREEN], 
+                               &match) == lwc_error_ok && match) {
+                       ret |= CSS_MEDIA_SCREEN;
+               } else if (lwc_string_caseless_isequal(
+                               token->idata, c->strings[SPEECH], 
+                               &match) == lwc_error_ok && match) {
+                       ret |= CSS_MEDIA_SPEECH;
+               } else if (lwc_string_caseless_isequal(
+                               token->idata, c->strings[TTY], 
+                               &match) == lwc_error_ok && match) {
+                       ret |= CSS_MEDIA_TTY;
+               } else if (lwc_string_caseless_isequal(
+                               token->idata, c->strings[TV], 
+                               &match) == lwc_error_ok && match) {
+                       ret |= CSS_MEDIA_TV;
+               } else if (lwc_string_caseless_isequal(
+                               token->idata, c->strings[ALL], 
+                               &match) == lwc_error_ok && match) {
+                       ret |= CSS_MEDIA_ALL;
+               } else
+                       return CSS_INVALID;
+#endif
+               consumeWhitespace(vector, ctx);
+
+               token = parserutils_vector_iterate(vector, ctx);
+               if (token != NULL && tokenIsChar(token, ',') == false)
+                       return CSS_INVALID;
+
+               consumeWhitespace(vector, ctx);
+       }
+
+#if 0
+       /* If, after parsing the media list, we still have no media, 
+        * then it must be ALL. */
+       if (ret == 0)
+               ret = CSS_MEDIA_ALL;
+#endif
+
+       *media = ret;
+
+       return CSS_OK;
+}
+
diff --git a/src/parse/mq.h b/src/parse/mq.h
new file mode 100644
index 0000000..eeb55da
--- /dev/null
+++ b/src/parse/mq.h
@@ -0,0 +1,100 @@
+/*
+ * This file is part of LibCSS.
+ * Licensed under the MIT License,
+ *               http://www.opensource.org/licenses/mit-license.php
+ * Copyright 2016 John-Mark Bell <[email protected]>
+ */
+
+#ifndef css_parse_mq_h_
+#define css_parse_mq_h_
+
+#include <parserutils/utils/vector.h>
+#include "parse/language.h"
+
+typedef struct {
+       enum {
+               CSS_MQ_VALUE_TYPE_NUM,
+               CSS_MQ_VALUE_TYPE_DIM,
+               CSS_MQ_VALUE_TYPE_IDENT,
+               CSS_MQ_VALUE_TYPE_RATIO
+       } type;
+       union {
+               css_fixed num_or_ratio; /* Where ratio is the result of a/b */
+               struct {
+                       css_fixed len;
+                       css_unit unit;
+               } dim;
+               lwc_string *ident;
+       } data;
+} css_mq_value;
+
+/*
+ * "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 op value" is encoded using op2 and value2
+ */
+typedef enum {
+       CSS_MQ_FEATURE_OP_BOOL, /* op only */
+       CSS_MQ_FEATURE_OP_UNUSED = CSS_MQ_FEATURE_OP_BOOL, /* op2 only */
+
+       CSS_MQ_FEATURE_OP_LT,
+       CSS_MQ_FEATURE_OP_LTE,
+       CSS_MQ_FEATURE_OP_EQ, /* op only */
+       CSS_MQ_FEATURE_OP_GTE,
+       CSS_MQ_FEATURE_OP_GT
+} css_mq_feature_op;
+
+typedef struct {
+       lwc_string *name;
+       css_mq_feature_op op;
+       css_mq_feature_op op2;
+       css_mq_value value;
+       css_mq_value value2;
+} css_mq_feature;
+
+typedef struct css_mq_cond_or_feature css_mq_cond_or_feature;
+
+typedef struct {
+       uint32_t nparts;
+       css_mq_cond_or_feature **parts;
+} css_mq_cond_parts;
+
+typedef struct {
+       uint32_t negate : 1, /* set if "not" */
+                op     : 1; /* clear if "and", set if "or" */
+       css_mq_cond_parts *parts;
+} css_mq_cond;
+
+struct css_mq_cond_or_feature {
+       enum {
+               CSS_MQ_FEATURE,
+               CSS_MQ_COND
+       } type;
+       union {
+               css_mq_cond cond;
+               css_mq_feature feat;
+       } data;
+};
+
+typedef struct css_mq_query {
+       struct css_mq_query *next;
+
+       uint32_t negate_type : 1, /* set if "not type" */
+                cond_op     : 1; /* clear if "and", set if "or" */
+       lwc_string *type; /* or NULL */
+
+       uint32_t nconds;
+       css_mq_cond **conds;
+} css_mq_query;
+
+css_error css__mq_parse_media_list(css_language *c,
+               const parserutils_vector *vector, int *ctx,
+               css_mq_query **media);
+
+/** \todo is this necessary? */
+css_mq_query *css__mq_query_ref(css_mq_query *media);
+css_mq_query *css__mq_query_unref(css_mq_query *media);
+
+#endif
diff --git a/src/stylesheet.c b/src/stylesheet.c
index 7c6728b..b1801ed 100644
--- a/src/stylesheet.c
+++ b/src/stylesheet.c
@@ -377,8 +377,6 @@ css_error css_stylesheet_data_done(css_stylesheet *sheet)
  * \param parent  Parent stylesheet
  * \param url    Pointer to object to be populated with details of URL of
  *               imported stylesheet (potentially relative)
- * \param media          Pointer to location to receive applicable media types 
for
- *               imported sheet,
  * \return CSS_OK on success,
  *        CSS_INVALID if there are no pending imports remaining
  *
@@ -396,11 +394,11 @@ css_error css_stylesheet_data_done(css_stylesheet *sheet)
  * register an empty stylesheet with the parent in its place.
  */
 css_error css_stylesheet_next_pending_import(css_stylesheet *parent,
-               lwc_string **url, uint64_t *media)
+               lwc_string **url)
 {
        const css_rule *r;
 
-       if (parent == NULL || url == NULL || media == NULL)
+       if (parent == NULL || url == NULL)
                return CSS_BADPARM;
 
        for (r = parent->rule_list; r != NULL; r = r->next) {
@@ -413,7 +411,6 @@ css_error css_stylesheet_next_pending_import(css_stylesheet 
*parent,
 
                if (r->type == CSS_RULE_IMPORT && i->sheet == NULL) {
                        *url = lwc_string_ref(i->url);
-                       *media = i->media;
 
                        return CSS_OK;
                }
@@ -1326,7 +1323,7 @@ css_error css__stylesheet_rule_set_charset(css_stylesheet 
*sheet,
  */
 css_error css__stylesheet_rule_set_nascent_import(css_stylesheet *sheet,
                css_rule *rule, lwc_string *url,
-               uint64_t media)
+               css_mq_query *media)
 {
        css_rule_import *r = (css_rule_import *) rule;
 
@@ -1338,7 +1335,7 @@ css_error 
css__stylesheet_rule_set_nascent_import(css_stylesheet *sheet,
 
        /* Set the rule's sheet field */
        r->url = lwc_string_ref(url);
-       r->media = media;
+       r->media = css__mq_query_ref(media);
 
        return CSS_OK;
 }
@@ -1352,7 +1349,7 @@ css_error 
css__stylesheet_rule_set_nascent_import(css_stylesheet *sheet,
  * \return CSS_OK on success, appropriate error otherwise
  */
 css_error css__stylesheet_rule_set_media(css_stylesheet *sheet,
-               css_rule *rule, uint64_t media)
+               css_rule *rule, css_mq_query *media)
 {
        css_rule_media *r = (css_rule_media *) rule;
 
@@ -1363,7 +1360,7 @@ css_error css__stylesheet_rule_set_media(css_stylesheet 
*sheet,
        assert(rule->type == CSS_RULE_MEDIA);
 
        /* Set the rule's media */
-       r->media = media;
+       r->media = css__mq_query_ref(media);
 
        return CSS_OK;
 }
diff --git a/src/stylesheet.h b/src/stylesheet.h
index 18e077e..a44ad1f 100644
--- a/src/stylesheet.h
+++ b/src/stylesheet.h
@@ -20,6 +20,7 @@
 
 #include "bytecode/bytecode.h"
 #include "parse/parse.h"
+#include "parse/mq.h"
 #include "select/hash.h"
 
 typedef struct css_rule css_rule;
@@ -132,7 +133,7 @@ typedef struct css_rule_selector {
 typedef struct css_rule_media {
        css_rule base;
 
-       uint64_t media;
+       css_mq_query *media;
 
        css_rule *first_child;
        css_rule *last_child;
@@ -155,7 +156,7 @@ typedef struct css_rule_import {
        css_rule base;
 
        lwc_string *url;
-       uint64_t media;
+       css_mq_query *media;
 
        css_stylesheet *sheet;
 } css_rule_import;
@@ -268,10 +269,10 @@ css_error css__stylesheet_rule_set_charset(css_stylesheet 
*sheet,
                css_rule *rule, lwc_string *charset);
 
 css_error css__stylesheet_rule_set_nascent_import(css_stylesheet *sheet,
-               css_rule *rule, lwc_string *url, uint64_t media);
+               css_rule *rule, lwc_string *url, css_mq_query *media);
 
 css_error css__stylesheet_rule_set_media(css_stylesheet *sheet,
-               css_rule *rule, uint64_t media);
+               css_rule *rule, css_mq_query *media);
 
 css_error css__stylesheet_rule_set_page_selector(css_stylesheet *sheet,
                css_rule *rule, css_selector *sel);


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


-- 
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