Gitweb links:

...log 
http://git.netsurf-browser.org/libcss.git/shortlog/27657ff21c4dfff87ef1830cecdbef5dffec9910
...commit 
http://git.netsurf-browser.org/libcss.git/commit/27657ff21c4dfff87ef1830cecdbef5dffec9910
...tree 
http://git.netsurf-browser.org/libcss.git/tree/27657ff21c4dfff87ef1830cecdbef5dffec9910

The branch, tlsa/jmb/mq2 has been created
        at  27657ff21c4dfff87ef1830cecdbef5dffec9910 (commit)

- Log -----------------------------------------------------------------
commitdiff 
http://git.netsurf-browser.org/libcss.git/commit/?id=27657ff21c4dfff87ef1830cecdbef5dffec9910
commit 27657ff21c4dfff87ef1830cecdbef5dffec9910
Author: Michael Drake <[email protected]>
Commit: Michael Drake <[email protected]>

    Stylesheet: Drop temporary code to test media query parsing.

diff --git a/src/stylesheet.c b/src/stylesheet.c
index 26ba0f3..22c7681 100644
--- a/src/stylesheet.c
+++ b/src/stylesheet.c
@@ -145,13 +145,6 @@ css_error css_stylesheet_create(const 
css_stylesheet_params *params,
                return error;
        }
 
-       css_mq_query *media;
-       error = css_parse_media_query(sheet->propstrings,
-               (const uint8_t *)"screen and (min-width: 30em)",
-                         strlen("screen and (min-width: 30em)"), &media);
-       if (error == CSS_OK)
-               css__mq_query_destroy(media);
-
        sheet->inline_style = params->inline_style;
 
        if (params->inline_style) {


commitdiff 
http://git.netsurf-browser.org/libcss.git/commit/?id=958136f0ae2544ad6f82a89e9b14cd96fbe5339d
commit 958136f0ae2544ad6f82a89e9b14cd96fbe5339d
Author: Michael Drake <[email protected]>
Commit: Michael Drake <[email protected]>

    Media queries: Add media type member to struct css_media.

diff --git a/include/libcss/types.h b/include/libcss/types.h
index 49bd68c..44aef12 100644
--- a/include/libcss/types.h
+++ b/include/libcss/types.h
@@ -208,6 +208,9 @@ typedef struct css_media_resolution {
  * Media specification
  */
 typedef struct css_media {
+       /* Media type */
+       css_media_type        type;
+
        /* Screen / Device media features */
        css_media_length      width;
        css_media_length      height;


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

    Media queries: Move css_parse_media_query to parse/mq.c file.
    
    It's now exposed in the mq.h header too.

diff --git a/src/parse/mq.c b/src/parse/mq.c
index 214b5a2..e7227f7 100644
--- a/src/parse/mq.c
+++ b/src/parse/mq.c
@@ -1040,3 +1040,106 @@ css_error css__mq_parse_media_list(lwc_string **strings,
        return CSS_OK;
 }
 
+typedef struct css_mq_parse_ctx {
+       lwc_string **strings;
+       css_mq_query *media;
+} css_mq_parse_ctx;
+
+static css_error css_parse_media_query_handle_event(
+               css_parser_event type,
+               const parserutils_vector *tokens,
+               void *pw)
+{
+       int idx = 0;
+       css_error err;
+       css_mq_query *media;
+       const css_token *tok;
+       css_mq_parse_ctx *ctx = pw;
+       lwc_string **strings = ctx->strings;
+
+       UNUSED(type);
+
+       /* Skip @media */
+       tok = parserutils_vector_iterate(tokens, &idx);
+       assert(tok->type == CSS_TOKEN_ATKEYWORD);
+       UNUSED(tok);
+
+       /* Skip whitespace */
+       tok = parserutils_vector_iterate(tokens, &idx);
+       assert(tok->type == CSS_TOKEN_S);
+       UNUSED(tok);
+
+       err = css__mq_parse_media_list(strings, tokens, &idx, &media);
+       if (err != CSS_OK) {
+               return CSS_OK;
+       }
+
+       ctx->media = media;
+       return CSS_OK;
+}
+
+css_error css_parse_media_query(lwc_string **strings,
+               const uint8_t *mq, size_t len,
+               css_mq_query **media_out)
+{
+       css_error err;
+       css_parser *parser;
+       css_mq_parse_ctx ctx = {
+               .strings = strings,
+       };
+       css_parser_optparams params_quirks = {
+               .quirks = false,
+       };
+       css_parser_optparams params_handler = {
+               .event_handler = {
+                       .handler = css_parse_media_query_handle_event,
+                       .pw = &ctx,
+               },
+       };
+
+       err = css__parser_create_for_media_query(NULL,
+                       CSS_CHARSET_DEFAULT, &parser);
+       if (err != CSS_OK) {
+               return err;
+       }
+
+       err = css__parser_setopt(parser, CSS_PARSER_QUIRKS,
+                       &params_quirks);
+       if (err != CSS_OK) {
+               css__parser_destroy(parser);
+               return err;
+       }
+
+       err = css__parser_setopt(parser, CSS_PARSER_EVENT_HANDLER,
+                       &params_handler);
+       if (err != CSS_OK) {
+               css__parser_destroy(parser);
+               return err;
+       }
+
+       err = css__parser_parse_chunk(parser,
+                       (const uint8_t *)"@media ",
+                                 strlen("@media "));
+       if (err != CSS_OK && err != CSS_NEEDDATA) {
+               css__parser_destroy(parser);
+               return err;
+       }
+
+       err = css__parser_parse_chunk(parser, mq, len);
+       if (err != CSS_OK && err != CSS_NEEDDATA) {
+               css__parser_destroy(parser);
+               return err;
+       }
+
+       err = css__parser_completed(parser);
+       if (err != CSS_OK) {
+               css__parser_destroy(parser);
+               return err;
+       }
+
+       css__parser_destroy(parser);
+
+       *media_out = ctx.media;
+       return CSS_OK;
+}
+
diff --git a/src/parse/mq.h b/src/parse/mq.h
index 2940032..0e2f845 100644
--- a/src/parse/mq.h
+++ b/src/parse/mq.h
@@ -87,6 +87,10 @@ typedef struct css_mq_query {
        css_mq_cond *cond;
 } css_mq_query;
 
+css_error css_parse_media_query(lwc_string **strings,
+               const uint8_t *mq, size_t len,
+               css_mq_query **media_out);
+
 css_error css__mq_parse_media_list(lwc_string **strings,
                const parserutils_vector *vector, int *ctx,
                css_mq_query **media);
diff --git a/src/stylesheet.c b/src/stylesheet.c
index 7c1fb83..26ba0f3 100644
--- a/src/stylesheet.c
+++ b/src/stylesheet.c
@@ -113,112 +113,6 @@ css_error css__stylesheet_string_get(css_stylesheet 
*sheet,
        return CSS_OK;
 }
 
-typedef struct css_mq_parse_ctx {
-       lwc_string **strings;
-       css_mq_query *media;
-} css_mq_parse_ctx;
-
-static css_error css_parse_media_query_handle_event(
-               css_parser_event type,
-               const parserutils_vector *tokens,
-               void *pw)
-{
-       int idx = 0;
-       css_error err;
-       css_mq_query *media;
-       const css_token *tok;
-       css_mq_parse_ctx *ctx = pw;
-       lwc_string **strings = ctx->strings;
-
-       UNUSED(type);
-
-       /* Skip @media */
-       tok = parserutils_vector_iterate(tokens, &idx);
-       assert(tok->type == CSS_TOKEN_ATKEYWORD);
-       UNUSED(tok);
-
-       /* Skip whitespace */
-       tok = parserutils_vector_iterate(tokens, &idx);
-       assert(tok->type == CSS_TOKEN_S);
-       UNUSED(tok);
-
-       err = css__mq_parse_media_list(strings, tokens, &idx, &media);
-       if (err != CSS_OK) {
-               return CSS_OK;
-       }
-
-       ctx->media = media;
-       return CSS_OK;
-}
-
-static css_error css_parse_media_query(
-               lwc_string **strings,
-               const uint8_t *mq,
-               size_t len,
-               css_mq_query **media_out)
-{
-       css_error err;
-       css_parser *parser;
-       css_mq_parse_ctx ctx = {
-               .strings = strings,
-       };
-       css_parser_optparams params_quirks = {
-               .quirks = false,
-       };
-       css_parser_optparams params_handler = {
-               .event_handler = {
-                       .handler = css_parse_media_query_handle_event,
-                       .pw = &ctx,
-               },
-       };
-
-       err = css__parser_create_for_media_query(NULL,
-                       CSS_CHARSET_DEFAULT, &parser);
-       if (err != CSS_OK) {
-               return err;
-       }
-
-       err = css__parser_setopt(parser, CSS_PARSER_QUIRKS,
-                       &params_quirks);
-       if (err != CSS_OK) {
-               css__parser_destroy(parser);
-               return err;
-       }
-
-       err = css__parser_setopt(parser, CSS_PARSER_EVENT_HANDLER,
-                       &params_handler);
-       if (err != CSS_OK) {
-               css__parser_destroy(parser);
-               return err;
-       }
-
-       err = css__parser_parse_chunk(parser,
-                       (const uint8_t *)"@media ",
-                                 strlen("@media "));
-       if (err != CSS_OK && err != CSS_NEEDDATA) {
-               css__parser_destroy(parser);
-               return err;
-       }
-
-       err = css__parser_parse_chunk(parser, mq, len);
-       if (err != CSS_OK && err != CSS_NEEDDATA) {
-               css__parser_destroy(parser);
-               return err;
-       }
-
-       err = css__parser_completed(parser);
-       if (err != CSS_OK) {
-               css__parser_destroy(parser);
-               return err;
-       }
-
-       css__parser_destroy(parser);
-
-       *media_out = ctx.media;
-       return CSS_OK;
-}
-
-
 /**
  * Create a stylesheet
  *


commitdiff 
http://git.netsurf-browser.org/libcss.git/commit/?id=0da84ebf34d68cc1f89d057086fdd0f24747b258
commit 0da84ebf34d68cc1f89d057086fdd0f24747b258
Author: Michael Drake <[email protected]>
Commit: Michael Drake <[email protected]>

    Media queries: Make css_parse_media_query return the parsed css_mq_query.
    
    This converts the experimental code to test the media query parsing into
    a useful function.

diff --git a/src/stylesheet.c b/src/stylesheet.c
index 07b9019..7c1fb83 100644
--- a/src/stylesheet.c
+++ b/src/stylesheet.c
@@ -113,14 +113,22 @@ css_error css__stylesheet_string_get(css_stylesheet 
*sheet,
        return CSS_OK;
 }
 
-static css_error css_parse_media_query_handle_event(css_parser_event type,
-               const parserutils_vector *tokens, void *pw)
+typedef struct css_mq_parse_ctx {
+       lwc_string **strings;
+       css_mq_query *media;
+} css_mq_parse_ctx;
+
+static css_error css_parse_media_query_handle_event(
+               css_parser_event type,
+               const parserutils_vector *tokens,
+               void *pw)
 {
        int idx = 0;
        css_error err;
        css_mq_query *media;
        const css_token *tok;
-       lwc_string **strings = pw;
+       css_mq_parse_ctx *ctx = pw;
+       lwc_string **strings = ctx->strings;
 
        UNUSED(type);
 
@@ -139,22 +147,28 @@ static css_error 
css_parse_media_query_handle_event(css_parser_event type,
                return CSS_OK;
        }
 
-       css__mq_query_destroy(media);
+       ctx->media = media;
        return CSS_OK;
 }
 
-static css_error css_parse_media_query(lwc_string **strings,
-               const uint8_t *mq, size_t len)
+static css_error css_parse_media_query(
+               lwc_string **strings,
+               const uint8_t *mq,
+               size_t len,
+               css_mq_query **media_out)
 {
        css_error err;
        css_parser *parser;
+       css_mq_parse_ctx ctx = {
+               .strings = strings,
+       };
        css_parser_optparams params_quirks = {
                .quirks = false,
        };
        css_parser_optparams params_handler = {
                .event_handler = {
                        .handler = css_parse_media_query_handle_event,
-                       .pw = strings,
+                       .pw = &ctx,
                },
        };
 
@@ -200,6 +214,7 @@ static css_error css_parse_media_query(lwc_string **strings,
 
        css__parser_destroy(parser);
 
+       *media_out = ctx.media;
        return CSS_OK;
 }
 
@@ -235,9 +250,13 @@ css_error css_stylesheet_create(const 
css_stylesheet_params *params,
                free(sheet);
                return error;
        }
-css_parse_media_query(sheet->propstrings,
+
+       css_mq_query *media;
+       error = css_parse_media_query(sheet->propstrings,
                (const uint8_t *)"screen and (min-width: 30em)",
-                         strlen("screen and (min-width: 30em)"));
+                         strlen("screen and (min-width: 30em)"), &media);
+       if (error == CSS_OK)
+               css__mq_query_destroy(media);
 
        sheet->inline_style = params->inline_style;
 


commitdiff 
http://git.netsurf-browser.org/libcss.git/commit/?id=74ecce7e2dd5272a9978970307d288613d1d171e
commit 74ecce7e2dd5272a9978970307d288613d1d171e
Author: Michael Drake <[email protected]>
Commit: Michael Drake <[email protected]>

    Media queries: Drop parse debug output.

diff --git a/src/stylesheet.c b/src/stylesheet.c
index 934954c..07b9019 100644
--- a/src/stylesheet.c
+++ b/src/stylesheet.c
@@ -122,7 +122,7 @@ static css_error 
css_parse_media_query_handle_event(css_parser_event type,
        const css_token *tok;
        lwc_string **strings = pw;
 
-       printf("mq event type: %i\n", type);
+       UNUSED(type);
 
        /* Skip @media */
        tok = parserutils_vector_iterate(tokens, &idx);
@@ -134,27 +134,12 @@ static css_error 
css_parse_media_query_handle_event(css_parser_event type,
        assert(tok->type == CSS_TOKEN_S);
        UNUSED(tok);
 
-       printf("  Tokens:\n");
-       while ((tok = parserutils_vector_iterate(tokens, &idx)) != NULL) {
-               if (tok->idata != NULL) {
-                       printf("  - (%i) %s\n",
-                                       tok->type,
-                                       lwc_string_data(tok->idata));
-               } else {
-                       printf("  - (%i)\n", tok->type);
-               }
-       }
-       idx = 2;
-
        err = css__mq_parse_media_list(strings, tokens, &idx, &media);
        if (err != CSS_OK) {
-               printf("Error parsing mq\n");
                return CSS_OK;
        }
 
-       printf("PARSED MQ!!!!!!!\n");
        css__mq_query_destroy(media);
-
        return CSS_OK;
 }
 
@@ -193,7 +178,6 @@ static css_error css_parse_media_query(lwc_string **strings,
                return err;
        }
 
-       printf("try parsing a mq\n");
        err = css__parser_parse_chunk(parser,
                        (const uint8_t *)"@media ",
                                  strlen("@media "));


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

    Parse: simplify token vector cleanup.
    
    There's not much point having every call site have to call two
    functions every time they want to clean the token vector. Instead,
    have a single function call to do both parts of the cleanup.

diff --git a/src/parse/parse.c b/src/parse/parse.c
index eb83963..cbd8b56 100644
--- a/src/parse/parse.c
+++ b/src/parse/parse.c
@@ -147,7 +147,7 @@ static css_error parseISBody0(css_parser *parser);
 static css_error parseISBody(css_parser *parser);
 static css_error parseMediaQuery(css_parser *parser);
 
-static void unref_interned_strings_in_tokens(css_parser *parser);
+static void discard_tokens(css_parser *parser);
 
 /**
  * Dispatch table for parsing, indexed by major state number
@@ -765,8 +765,7 @@ css_error parseStart(css_parser *parser)
                                parser->event_pw);
        }
 
-        unref_interned_strings_in_tokens(parser);
-       parserutils_vector_clear(parser->tokens);
+       discard_tokens(parser);
 
        return done(parser);
 }
@@ -797,8 +796,7 @@ css_error parseStylesheet(css_parser *parser)
                                if (error != CSS_OK)
                                        return error;
 
-                                unref_interned_strings_in_tokens(parser);
-                               parserutils_vector_clear(parser->tokens);
+                               discard_tokens(parser);
 
                                return done(parser);
                        case CSS_TOKEN_CDO:
@@ -868,8 +866,7 @@ css_error parseRuleset(css_parser *parser)
 
        switch (state->substate) {
        case Initial:
-                unref_interned_strings_in_tokens(parser);
-               parserutils_vector_clear(parser->tokens);
+               discard_tokens(parser);
 
                error = getToken(parser, &token);
                if (error != CSS_OK)
@@ -1067,8 +1064,7 @@ css_error parseAtRule(css_parser *parser)
 
        switch (state->substate) {
        case Initial:
-                unref_interned_strings_in_tokens(parser);
-               parserutils_vector_clear(parser->tokens);
+               discard_tokens(parser);
 
                error = getToken(parser, &token);
                if (error != CSS_OK)
@@ -1238,8 +1234,7 @@ css_error parseBlock(css_parser *parser)
                        assert(0 && "Expected {");
                }
 
-                unref_interned_strings_in_tokens(parser);
-               parserutils_vector_clear(parser->tokens);
+               discard_tokens(parser);
 
                state->substate = WS;
                /* Fall through */
@@ -1295,8 +1290,7 @@ css_error parseBlock(css_parser *parser)
                parser->event(CSS_PARSER_END_BLOCK, NULL, parser->event_pw);
        }
 
-        unref_interned_strings_in_tokens(parser);
-       parserutils_vector_clear(parser->tokens);
+       discard_tokens(parser);
 
        return done(parser);
 }
@@ -1348,10 +1342,7 @@ css_error parseBlockContent(css_parser *parser)
                                                        parser->event_pw);
                                        }
 
-                                       unref_interned_strings_in_tokens(
-                                                       parser);
-                                       parserutils_vector_clear(
-                                                       parser->tokens);
+                                       discard_tokens(parser);
 
                                        return transition(parser, to,
                                                        subsequent);
@@ -1379,10 +1370,7 @@ css_error parseBlockContent(css_parser *parser)
                                        if (error != CSS_OK)
                                                return error;
 
-                                       unref_interned_strings_in_tokens(
-                                                       parser);
-                                       parserutils_vector_clear(
-                                                       parser->tokens);
+                                       discard_tokens(parser);
 
                                        state->substate = WS;
                                } else if (lwc_string_length(
@@ -1405,10 +1393,7 @@ css_error parseBlockContent(css_parser *parser)
                                                        parser->event_pw);
                                        }
 
-                                       unref_interned_strings_in_tokens(
-                                                       parser);
-                                       parserutils_vector_clear(
-                                                       parser->tokens);
+                                       discard_tokens(parser);
 
                                        return done(parser);
                                }
@@ -1427,8 +1412,7 @@ css_error parseBlockContent(css_parser *parser)
                                                        parser->event_pw);
                                }
 
-                               unref_interned_strings_in_tokens(parser);
-                               parserutils_vector_clear(parser->tokens);
+                               discard_tokens(parser);
 
                                return done(parser);
                        }
@@ -1471,8 +1455,7 @@ css_error parseSelector(css_parser *parser)
                parser_state to = { sAny1, Initial };
                parser_state subsequent = { sSelector, AfterAny1 };
 
-                unref_interned_strings_in_tokens(parser);
-               parserutils_vector_clear(parser->tokens);
+               discard_tokens(parser);
 
                return transition(parser, to, subsequent);
        }
@@ -1498,8 +1481,7 @@ css_error parseDeclaration(css_parser *parser)
                parser_state to = { sProperty, Initial };
                parser_state subsequent = { sDeclaration, Colon };
 
-                unref_interned_strings_in_tokens(parser);
-               parserutils_vector_clear(parser->tokens);
+               discard_tokens(parser);
 
                return transition(parser, to, subsequent);
        }
@@ -2217,8 +2199,7 @@ css_error parseMalformedDeclaration(css_parser *parser)
                return error;
 
        /* Discard the tokens we've read */
-        unref_interned_strings_in_tokens(parser);
-       parserutils_vector_clear(parser->tokens);
+       discard_tokens(parser);
 
        return done(parser);
 }
@@ -2313,8 +2294,7 @@ css_error parseMalformedSelector(css_parser *parser)
                return error;
 
        /* Discard the tokens we've read */
-        unref_interned_strings_in_tokens(parser);
-       parserutils_vector_clear(parser->tokens);
+       discard_tokens(parser);
 
        return done(parser);
 }
@@ -2422,8 +2402,7 @@ css_error parseMalformedAtRule(css_parser *parser)
                return error;
 
        /* Discard the tokens we've read */
-        unref_interned_strings_in_tokens(parser);
-       parserutils_vector_clear(parser->tokens);
+       discard_tokens(parser);
 
        return done(parser);
 }
@@ -2468,7 +2447,7 @@ css_error parseInlineStyle(css_parser *parser)
        }
        case AfterISBody0:
                /* Clean up any remaining tokens */
-               unref_interned_strings_in_tokens(parser);
+               discard_tokens(parser);
 
                /* Emit remaining fake events to end the parse */
                if (parser->event != NULL) {
@@ -2631,8 +2610,7 @@ css_error parseMediaQuery(css_parser *parser)
        }
        case AfterAtRule:
                /* Clean up any remaining tokens */
-               unref_interned_strings_in_tokens(parser);
-               parserutils_vector_clear(parser->tokens);
+               discard_tokens(parser);
                break;
        }
 
@@ -2640,21 +2618,23 @@ css_error parseMediaQuery(css_parser *parser)
 }
 
 /**
- * Iterate the token vector and unref any interned strings in the tokens.
+ * Discard the contents of the token vector
  *
  * \param parser The parser whose tokens we are cleaning up.
  */
-void unref_interned_strings_in_tokens(css_parser *parser)
+void discard_tokens(css_parser *parser)
 {
-        int32_t ctx = 0;
-        const css_token *tok;
+       int32_t ctx = 0;
+       const css_token *tok;
 
-        while ((tok = parserutils_vector_iterate(
+       while ((tok = parserutils_vector_iterate(
                        parser->tokens, &ctx)) != NULL) {
-                if (tok->idata != NULL) {
-                        lwc_string_unref(tok->idata);
+               if (tok->idata != NULL) {
+                       lwc_string_unref(tok->idata);
                }
-        }
+       }
+
+       parserutils_vector_clear(parser->tokens);
 }
 
 #ifndef NDEBUG


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

    Parse: use an explicit state for media queries.
    
    This simply wraps the existing at-rule parser but is able to clean
    up afterwards.

diff --git a/src/parse/parse.c b/src/parse/parse.c
index 670b88d..eb83963 100644
--- a/src/parse/parse.c
+++ b/src/parse/parse.c
@@ -67,7 +67,8 @@ enum {
        sMalformedAtRule = 22,
        sInlineStyle = 23,
        sISBody0 = 24,
-       sISBody = 25
+       sISBody = 25,
+       sMediaQuery = 26,
 };
 
 /**
@@ -144,6 +145,7 @@ static css_error parseMalformedAtRule(css_parser *parser);
 static css_error parseInlineStyle(css_parser *parser);
 static css_error parseISBody0(css_parser *parser);
 static css_error parseISBody(css_parser *parser);
+static css_error parseMediaQuery(css_parser *parser);
 
 static void unref_interned_strings_in_tokens(css_parser *parser);
 
@@ -176,7 +178,8 @@ static css_error (*parseFuncs[])(css_parser *parser) = {
        parseMalformedAtRule,
        parseInlineStyle,
        parseISBody0,
-       parseISBody
+       parseISBody,
+       parseMediaQuery,
 };
 
 /**
@@ -230,7 +233,7 @@ css_error css__parser_create_for_inline_style(const char 
*charset,
 css_error css__parser_create_for_media_query(const char *charset,
                css_charset_source cs_source, css_parser **parser)
 {
-       parser_state initial = { sAtRule, 0 };
+       parser_state initial = { sMediaQuery, 0 };
 
        return css__parser_create_internal(charset, cs_source,
                        initial, parser);
@@ -2611,6 +2614,31 @@ css_error parseISBody(css_parser *parser)
        return done(parser);
 }
 
+css_error parseMediaQuery(css_parser *parser)
+{
+       enum { Initial = 0, AfterAtRule = 1 };
+       parser_state *state = parserutils_stack_get_current(parser->states);
+
+       /* media-query = at-rule */
+
+       switch (state->substate) {
+       case Initial:
+       {
+               parser_state to = { sAtRule, Initial };
+               parser_state subsequent = { sMediaQuery, AfterAtRule };
+
+               return transition(parser, to, subsequent);
+       }
+       case AfterAtRule:
+               /* Clean up any remaining tokens */
+               unref_interned_strings_in_tokens(parser);
+               parserutils_vector_clear(parser->tokens);
+               break;
+       }
+
+       return done(parser);
+}
+
 /**
  * Iterate the token vector and unref any interned strings in the tokens.
  *


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

    Media queries: Ensure values get destroyed.

diff --git a/src/parse/mq.c b/src/parse/mq.c
index 9d232f9..214b5a2 100644
--- a/src/parse/mq.c
+++ b/src/parse/mq.c
@@ -17,10 +17,21 @@
 #include "parse/properties/utils.h"
 #include "utils/utils.h"
 
-static void css_mq_feature_destroy(css_mq_feature *feature)
+static void css__mq_value_destroy(css_mq_value *value)
+{
+       assert(value != NULL);
+
+       if (value->type == CSS_MQ_VALUE_TYPE_IDENT) {
+               lwc_string_unref(value->data.ident);
+       }
+}
+
+static void css__mq_feature_destroy(css_mq_feature *feature)
 {
        if (feature != NULL) {
                lwc_string_unref(feature->name);
+               css__mq_value_destroy(&feature->value);
+               css__mq_value_destroy(&feature->value2);
                free(feature);
        }
 }
@@ -52,7 +63,7 @@ static void css__mq_cond_or_feature_destroy(
        if (cond_or_feature != NULL) {
                switch (cond_or_feature->type) {
                case CSS_MQ_FEATURE:
-                       css_mq_feature_destroy(cond_or_feature->data.feat);
+                       css__mq_feature_destroy(cond_or_feature->data.feat);
                        break;
                case CSS_MQ_COND:
                        css__mq_cond_destroy(cond_or_feature->data.cond);
@@ -369,7 +380,7 @@ static css_error mq_parse_range(lwc_string **strings,
                        /* num/dim/ident */
                        error = mq_populate_value(&result->value2, token);
                        if (error != CSS_OK) {
-                               css_mq_feature_destroy(result);
+                               css__mq_feature_destroy(result);
                                return error;
                        }
                }
@@ -482,7 +493,7 @@ static css_error mq_parse_media_feature(lwc_string 
**strings,
 
        token = parserutils_vector_iterate(vector, ctx);
        if (tokenIsChar(token, ')') == false) {
-               css_mq_feature_destroy(result);
+               css__mq_feature_destroy(result);
                return CSS_INVALID;
        }
 
@@ -664,7 +675,7 @@ static css_error mq_parse_media_in_parens(lwc_string 
**strings,
                if (error == CSS_OK) {
                        result = malloc(sizeof(*result));
                        if (result == NULL) {
-                               css_mq_feature_destroy(feature);
+                               css__mq_feature_destroy(feature);
                                return CSS_NOMEM;
                        }
                        memset(result, 0, sizeof(*result));


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

    Media Queries: fix parsing of media-condition

diff --git a/src/parse/mq.c b/src/parse/mq.c
index 2b2164f..9d232f9 100644
--- a/src/parse/mq.c
+++ b/src/parse/mq.c
@@ -686,7 +686,7 @@ static css_error mq_parse_condition(lwc_string **strings,
                bool permit_or, css_mq_cond **cond)
 {
        const css_token *token;
-       bool match;
+       bool match = false;
        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;
@@ -700,11 +700,12 @@ static css_error mq_parse_condition(lwc_string **strings,
         */
 
        token = parserutils_vector_peek(vector, *ctx);
-       if (token == NULL || tokenIsChar(token, '(') == false ||
-                       token->type != CSS_TOKEN_IDENT ||
+       if (token == NULL ||
+                       (tokenIsChar(token, '(') == false &&
+                       token->type != CSS_TOKEN_IDENT &&
                        lwc_string_caseless_isequal(token->idata,
-                               strings[NOT], &match) != lwc_error_ok ||
-                       match == false) {
+                               strings[NOT], &match) != lwc_error_ok &&
+                       match == false)) {
                return CSS_INVALID;
        }
 


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

    Tests: fix illegal display value test.
    
    Recovery from malformed property values involves matching the
    various nesting mechanisms. Thanks to the bug in the parseAny
    state machine, this code was never run. The test data contained
    mismatched open parentheses, causing the recovery logic to
    continue reading until EOF. Fix the test input to match the
    expectations of the test assertions.

diff --git a/test/data/parse2/illegal-values.dat 
b/test/data/parse2/illegal-values.dat
index 3187e18..2d58b54 100644
--- a/test/data/parse2/illegal-values.dat
+++ b/test/data/parse2/illegal-values.dat
@@ -864,7 +864,7 @@
 #reset
 
 #data
-* { display: 0t   HACKS for testing Media Queries parsing.
    
    Top level stylesheets need to have their media query passed in.
    So we need a way to parse standalone media queries.
    
    This was hacked together to explore doing that.
    
    However, it encounteded an issue where it seems the parseAtRule()
    function in src/parse/parse.c doesn't handle the full grammar for
    media queries.

diff --git a/src/parse/language.c b/src/parse/language.c
index faafcfd..54fac9a 100644
--- a/src/parse/language.c
+++ b/src/parse/language.c
@@ -532,7 +532,6 @@ css_error handleStartAtRule(css_language *c, const 
parserutils_vector *vector)
                css_mq_query *media = NULL;
 
                /* any0 = media query */
-
                error = css__mq_parse_media_list(
                                c->strings, vector, &ctx, &media);
                if (error != CSS_OK)
diff --git a/src/parse/parse.c b/src/parse/parse.c
index 4cc1c98..d58e328 100644
--- a/src/parse/parse.c
+++ b/src/parse/parse.c
@@ -220,6 +220,25 @@ css_error css__parser_create_for_inline_style(const char 
*charset,
 }
 
 /**
+ * Create a CSS parser for a media query
+ *
+ * \param charset     Charset of data, if known, or NULL
+ * \param cs_source   Source of charset information, or CSS_CHARSET_DEFAULT
+ * \param parser      Pointer to location to receive parser instance
+ * \return CSS_OK on success,
+ *         CSS_BADPARM on bad parameters,
+ *         CSS_NOMEM on memory exhaustion
+ */
+css_error css__parser_create_for_media_query(const char *charset,
+               css_charset_source cs_source, css_parser **parser)
+{
+       parser_state initial = { sAtRule, 0 };
+
+       return css__parser_create_internal(charset, cs_source,
+                       initial, parser);
+}
+
+/**
  * Destroy a CSS parser
  *
  * \param parser  The parser instance to destroy
diff --git a/src/parse/parse.h b/src/parse/parse.h
index 833aa51..e65f055 100644
--- a/src/parse/parse.h
+++ b/src/parse/parse.h
@@ -61,6 +61,8 @@ css_error css__parser_create(const char *charset, 
css_charset_source cs_source,
                css_parser **parser);
 css_error css__parser_create_for_inline_style(const char *charset,
                css_charset_source cs_source, css_parser **parser);
+css_error css__parser_create_for_media_query(const char *charset,
+               css_charset_source cs_source, css_parser **parser);
 css_error css__parser_destroy(css_parser *parser);
 
 css_error css__parser_setopt(css_parser *parser, css_parser_opttype type,
diff --git a/src/stylesheet.c b/src/stylesheet.c
index 22c7681..934954c 100644
--- a/src/stylesheet.c
+++ b/src/stylesheet.c
@@ -113,6 +113,113 @@ css_error css__stylesheet_string_get(css_stylesheet 
*sheet,
        return CSS_OK;
 }
 
+static css_error css_parse_media_query_handle_event(css_parser_event type,
+               const parserutils_vector *tokens, void *pw)
+{
+       int idx = 0;
+       css_error err;
+       css_mq_query *media;
+       const css_token *tok;
+       lwc_string **strings = pw;
+
+       printf("mq event type: %i\n", type);
+
+       /* Skip @media */
+       tok = parserutils_vector_iterate(tokens, &idx);
+       assert(tok->type == CSS_TOKEN_ATKEYWORD);
+       UNUSED(tok);
+
+       /* Skip whitespace */
+       tok = parserutils_vector_iterate(tokens, &idx);
+       assert(tok->type == CSS_TOKEN_S);
+       UNUSED(tok);
+
+       printf("  Tokens:\n");
+       while ((tok = parserutils_vector_iterate(tokens, &idx)) != NULL) {
+               if (tok->idata != NULL) {
+                       printf("  - (%i) %s\n",
+                                       tok->type,
+                                       lwc_string_data(tok->idata));
+               } else {
+                       printf("  - (%i)\n", tok->type);
+               }
+       }
+       idx = 2;
+
+       err = css__mq_parse_media_list(strings, tokens, &idx, &media);
+       if (err != CSS_OK) {
+               printf("Error parsing mq\n");
+               return CSS_OK;
+       }
+
+       printf("PARSED MQ!!!!!!!\n");
+       css__mq_query_destroy(media);
+
+       return CSS_OK;
+}
+
+static css_error css_parse_media_query(lwc_string **strings,
+               const uint8_t *mq, size_t len)
+{
+       css_error err;
+       css_parser *parser;
+       css_parser_optparams params_quirks = {
+               .quirks = false,
+       };
+       css_parser_optparams params_handler = {
+               .event_handler = {
+                       .handler = css_parse_media_query_handle_event,
+                       .pw = strings,
+               },
+       };
+
+       err = css__parser_create_for_media_query(NULL,
+                       CSS_CHARSET_DEFAULT, &parser);
+       if (err != CSS_OK) {
+               return err;
+       }
+
+       err = css__parser_setopt(parser, CSS_PARSER_QUIRKS,
+                       &params_quirks);
+       if (err != CSS_OK) {
+               css__parser_destroy(parser);
+               return err;
+       }
+
+       err = css__parser_setopt(parser, CSS_PARSER_EVENT_HANDLER,
+                       &params_handler);
+       if (err != CSS_OK) {
+               css__parser_destroy(parser);
+               return err;
+       }
+
+       printf("try parsing a mq\n");
+       err = css__parser_parse_chunk(parser,
+                       (const uint8_t *)"@media ",
+                                 strlen("@media "));
+       if (err != CSS_OK && err != CSS_NEEDDATA) {
+               css__parser_destroy(parser);
+               return err;
+       }
+
+       err = css__parser_parse_chunk(parser, mq, len);
+       if (err != CSS_OK && err != CSS_NEEDDATA) {
+               css__parser_destroy(parser);
+               return err;
+       }
+
+       err = css__parser_completed(parser);
+       if (err != CSS_OK) {
+               css__parser_destroy(parser);
+               return err;
+       }
+
+       css__parser_destroy(parser);
+
+       return CSS_OK;
+}
+
+
 /**
  * Create a stylesheet
  *
@@ -144,6 +251,9 @@ css_error css_stylesheet_create(const css_stylesheet_params 
*params,
                free(sheet);
                return error;
        }
+css_parse_media_query(sheet->propstrings,
+               (const uint8_t *)"screen and (min-width: 30em)",
+                         strlen("screen and (min-width: 30em)"));
 
        sheet->inline_style = params->inline_style;
 


commitdiff 
http://git.netsurf-browser.org/libcss.git/commit/?id=9eea40513329fbd10d494f5a2d29664847043c4c
commit 9eea40513329fbd10d494f5a2d29664847043c4c
Author: Michael Drake <[email protected]>
Commit: Michael Drake <[email protected]>

    Media Queries: Parse only needs propstrings out of css_language.

diff --git a/src/parse/language.c b/src/parse/language.c
index c3b523d..faafcfd 100644
--- a/src/parse/language.c
+++ b/src/parse/language.c
@@ -426,7 +426,8 @@ css_error handleStartAtRule(css_language *c, const 
parserutils_vector *vector)
                        consumeWhitespace(vector, &ctx);
 
                        /* Parse media list */
-                       error = css__mq_parse_media_list(c, vector, &ctx, 
&media);
+                       error = css__mq_parse_media_list(
+                                       c->strings, vector, &ctx, &media);
                        if (error != CSS_OK)
                                return error;
 
@@ -532,7 +533,8 @@ css_error handleStartAtRule(css_language *c, const 
parserutils_vector *vector)
 
                /* any0 = media query */
 
-               error = css__mq_parse_media_list(c, vector, &ctx, &media);
+               error = css__mq_parse_media_list(
+                               c->strings, vector, &ctx, &media);
                if (error != CSS_OK)
                        return error;
 
diff --git a/src/parse/mq.c b/src/parse/mq.c
index f7b8b6e..2b2164f 100644
--- a/src/parse/mq.c
+++ b/src/parse/mq.c
@@ -74,7 +74,7 @@ void css__mq_query_destroy(css_mq_query *media)
        }
 }
 
-static css_error mq_parse_condition(css_language *c,
+static css_error mq_parse_condition(lwc_string **strings,
                const parserutils_vector *vector, int *ctx,
                bool permit_or, css_mq_cond **cond);
 
@@ -197,7 +197,7 @@ static css_error mq_parse_op(const css_token *token,
        return CSS_OK;
 }
 
-static css_error mq_parse_range(css_language *c,
+static css_error mq_parse_range(lwc_string **strings,
                const parserutils_vector *vector, int *ctx,
                const css_token *name_or_value,
                css_mq_feature **feature)
@@ -237,7 +237,7 @@ static css_error mq_parse_range(css_language *c,
                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 
&& 
+                               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;
@@ -380,7 +380,7 @@ static css_error mq_parse_range(css_language *c,
        return CSS_OK;
 }
 
-static css_error mq_parse_media_feature(css_language *c,
+static css_error mq_parse_media_feature(lwc_string **strings,
                const parserutils_vector *vector, int *ctx,
                css_mq_feature **feature)
 {
@@ -461,7 +461,8 @@ static css_error mq_parse_media_feature(css_language *c,
                        consumeWhitespace(vector, ctx);
                } else {
                        /* mf-range */
-                       error = mq_parse_range(c, vector, ctx, name_or_value, 
&result);
+                       error = mq_parse_range(strings, vector, ctx,
+                                       name_or_value, &result);
                        if (error != CSS_OK) {
                                return error;
                        }
@@ -470,7 +471,8 @@ static css_error mq_parse_media_feature(css_language *c,
                }
        } else {
                /* mf-range */
-               error = mq_parse_range(c, vector, ctx, name_or_value, &result);
+               error = mq_parse_range(strings, vector, ctx,
+                               name_or_value, &result);
                if (error != CSS_OK) {
                        return error;
                }
@@ -494,7 +496,7 @@ static css_error mq_parse_media_feature(css_language *c,
  *
  * CSS Syntax Module Level 3: 8.2
  */
-static css_error mq_parse_consume_any_value(css_language *c,
+static css_error mq_parse_consume_any_value(lwc_string **strings,
                const parserutils_vector *vector, int *ctx,
                bool until, const char until_char)
 {
@@ -526,22 +528,22 @@ static css_error mq_parse_consume_any_value(css_language 
*c,
                        }
                        if (tokenIsChar(token, '(')) {
                                /* Need to consume until matching bracket. */
-                               error = mq_parse_consume_any_value(
-                                               c, vector, ctx, true, ')');
+                               error = mq_parse_consume_any_value(strings,
+                                               vector, ctx, true, ')');
                                if (error != CSS_OK) {
                                        return error;
                                }
                        } else if (tokenIsChar(token, '[')) {
                                /* Need to consume until matching bracket. */
-                               error = mq_parse_consume_any_value(
-                                               c, vector, ctx, true, ']');
+                               error = mq_parse_consume_any_value(strings,
+                                               vector, ctx, true, ']');
                                if (error != CSS_OK) {
                                        return error;
                                }
                        } else if (tokenIsChar(token, '{')) {
                                /* Need to consume until matching bracket. */
-                               error = mq_parse_consume_any_value(
-                                               c, vector, ctx, true, '}');
+                               error = mq_parse_consume_any_value(strings,
+                                               vector, ctx, true, '}');
                                if (error != CSS_OK) {
                                        return error;
                                }
@@ -556,7 +558,7 @@ static css_error mq_parse_consume_any_value(css_language *c,
        return CSS_OK;
 }
 
-static css_error mq_parse_general_enclosed(css_language *c,
+static css_error mq_parse_general_enclosed(lwc_string **strings,
                const parserutils_vector *vector, int *ctx)
 {
        const css_token *token;
@@ -573,7 +575,8 @@ static css_error mq_parse_general_enclosed(css_language *c,
 
        switch (token->type) {
        case CSS_TOKEN_FUNCTION:
-               error = mq_parse_consume_any_value(c, vector, ctx, true, ')');
+               error = mq_parse_consume_any_value(strings, vector, ctx,
+                               true, ')');
                if (error != CSS_OK) {
                        return error;
                }
@@ -585,7 +588,8 @@ static css_error mq_parse_general_enclosed(css_language *c,
                break;
 
        case CSS_TOKEN_IDENT:
-               error = mq_parse_consume_any_value(c, vector, ctx, false, '\0');
+               error = mq_parse_consume_any_value(strings, vector, ctx,
+                               false, '\0');
                if (error != CSS_OK) {
                        return error;
                }
@@ -598,7 +602,7 @@ static css_error mq_parse_general_enclosed(css_language *c,
        return CSS_OK;
 }
 
-static css_error mq_parse_media_in_parens(css_language *c,
+static css_error mq_parse_media_in_parens(lwc_string **strings,
                const parserutils_vector *vector, int *ctx,
                css_mq_cond_or_feature **cond_or_feature)
 {
@@ -631,10 +635,10 @@ static css_error mq_parse_media_in_parens(css_language *c,
 
        if (tokenIsChar(token, '(') || (token->type == CSS_TOKEN_IDENT &&
                        lwc_string_caseless_isequal(token->idata,
-                               c->strings[NOT], &match) == lwc_error_ok &&
+                               strings[NOT], &match) == lwc_error_ok &&
                        match)) {
                css_mq_cond *cond;
-               error = mq_parse_condition(c, vector, ctx, true, &cond);
+               error = mq_parse_condition(strings, vector, ctx, true, &cond);
                if (error == CSS_OK) {
                        token = parserutils_vector_iterate(vector, ctx);
                        if (tokenIsChar(token, ')') == false) {
@@ -656,7 +660,7 @@ static css_error mq_parse_media_in_parens(css_language *c,
                        token->type == CSS_TOKEN_NUMBER ||
                        token->type == CSS_TOKEN_DIMENSION) {
                css_mq_feature *feature;
-               error = mq_parse_media_feature(c, vector, ctx, &feature);
+               error = mq_parse_media_feature(strings, vector, ctx, &feature);
                if (error == CSS_OK) {
                        result = malloc(sizeof(*result));
                        if (result == NULL) {
@@ -672,12 +676,12 @@ static css_error mq_parse_media_in_parens(css_language *c,
        }
 
        *ctx = old_ctx;
-       error = mq_parse_general_enclosed(c, vector, ctx);
+       error = mq_parse_general_enclosed(strings, vector, ctx);
 
        return error;
 }
 
-static css_error mq_parse_condition(css_language *c,
+static css_error mq_parse_condition(lwc_string **strings,
                const parserutils_vector *vector, int *ctx,
                bool permit_or, css_mq_cond **cond)
 {
@@ -699,7 +703,7 @@ static css_error mq_parse_condition(css_language *c,
        if (token == NULL || tokenIsChar(token, '(') == false ||
                        token->type != CSS_TOKEN_IDENT ||
                        lwc_string_caseless_isequal(token->idata,
-                               c->strings[NOT], &match) != lwc_error_ok ||
+                               strings[NOT], &match) != lwc_error_ok ||
                        match == false) {
                return CSS_INVALID;
        }
@@ -721,7 +725,8 @@ static css_error mq_parse_condition(css_language *c,
                parserutils_vector_iterate(vector, ctx);
                consumeWhitespace(vector, ctx);
 
-               error = mq_parse_media_in_parens(c, vector, ctx, 
&cond_or_feature);
+               error = mq_parse_media_in_parens(strings,
+                               vector, ctx, &cond_or_feature);
                if (error != CSS_OK) {
                        css__mq_cond_destroy(result);
                        return CSS_INVALID;
@@ -745,7 +750,8 @@ static css_error mq_parse_condition(css_language *c,
        /* 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);
+               error = mq_parse_media_in_parens(strings, vector, ctx,
+                               &cond_or_feature);
                if (error != CSS_OK) {
                        css__mq_cond_destroy(result);
                        return CSS_INVALID;
@@ -771,7 +777,7 @@ static css_error mq_parse_condition(css_language *c,
                                css__mq_cond_destroy(result);
                                return CSS_INVALID;
                        } else if (lwc_string_caseless_isequal(token->idata,
-                                       c->strings[AND], &match) == 
lwc_error_ok &&
+                                       strings[AND], &match) == lwc_error_ok &&
                                        match) {
                                if (op != 0 && op != AND) {
                                        css__mq_cond_destroy(result);
@@ -779,7 +785,7 @@ static css_error mq_parse_condition(css_language *c,
                                }
                                op = AND;
                        } else if (lwc_string_caseless_isequal(token->idata,
-                                               c->strings[OR], &match) == 
lwc_error_ok &&
+                                               strings[OR], &match) == 
lwc_error_ok &&
                                        match) {
                                if (permit_or == false || (op != 0 && op != 
OR)) {
                                        css__mq_cond_destroy(result);
@@ -809,54 +815,54 @@ static css_error mq_parse_condition(css_language *c,
 /**
  * Parse a media query type.
  */
-static uint64_t mq_parse_type(css_language *c, lwc_string *type)
+static uint64_t mq_parse_type(lwc_string **strings, lwc_string *type)
 {
        bool match;
 
        if (type == NULL) {
                return CSS_MEDIA_ALL;
        } else if (lwc_string_caseless_isequal(
-                       type, c->strings[AURAL],
+                       type, strings[AURAL],
                        &match) == lwc_error_ok && match) {
                return CSS_MEDIA_AURAL;
        } else if (lwc_string_caseless_isequal(
-                       type, c->strings[BRAILLE],
+                       type, strings[BRAILLE],
                        &match) == lwc_error_ok && match) {
                return CSS_MEDIA_BRAILLE;
        } else if (lwc_string_caseless_isequal(
-                       type, c->strings[EMBOSSED],
+                       type, strings[EMBOSSED],
                        &match) == lwc_error_ok && match) {
                return CSS_MEDIA_EMBOSSED;
        } else if (lwc_string_caseless_isequal(
-                       type, c->strings[HANDHELD],
+                       type, strings[HANDHELD],
                        &match) == lwc_error_ok && match) {
                return CSS_MEDIA_HANDHELD;
        } else if (lwc_string_caseless_isequal(
-                       type, c->strings[PRINT],
+                       type, strings[PRINT],
                        &match) == lwc_error_ok && match) {
                return CSS_MEDIA_PRINT;
        } else if (lwc_string_caseless_isequal(
-                       type, c->strings[PROJECTION],
+                       type, strings[PROJECTION],
                        &match) == lwc_error_ok && match) {
                return CSS_MEDIA_PROJECTION;
        } else if (lwc_string_caseless_isequal(
-                       type, c->strings[SCREEN],
+                       type, strings[SCREEN],
                        &match) == lwc_error_ok && match) {
                return CSS_MEDIA_SCREEN;
        } else if (lwc_string_caseless_isequal(
-                       type, c->strings[SPEECH],
+                       type, strings[SPEECH],
                        &match) == lwc_error_ok && match) {
                return CSS_MEDIA_SPEECH;
        } else if (lwc_string_caseless_isequal(
-                       type, c->strings[TTY],
+                       type, strings[TTY],
                        &match) == lwc_error_ok && match) {
                return CSS_MEDIA_TTY;
        } else if (lwc_string_caseless_isequal(
-                       type, c->strings[TV],
+                       type, strings[TV],
                        &match) == lwc_error_ok && match) {
                return CSS_MEDIA_TV;
        } else if (lwc_string_caseless_isequal(
-                       type, c->strings[ALL],
+                       type, strings[ALL],
                        &match) == lwc_error_ok && match) {
                return CSS_MEDIA_ALL;
        }
@@ -864,7 +870,7 @@ static uint64_t mq_parse_type(css_language *c, lwc_string 
*type)
        return 0;
 }
 
-static css_error mq_parse_media_query(css_language *c,
+static css_error mq_parse_media_query(lwc_string **strings,
                const parserutils_vector *vector, int *ctx,
                css_mq_query **query)
 {
@@ -888,7 +894,7 @@ static css_error mq_parse_media_query(css_language *c,
                is_condition = true;
        } else if (token->type == CSS_TOKEN_IDENT &&
                        lwc_string_caseless_isequal(token->idata,
-                               c->strings[NOT], &match) == lwc_error_ok &&
+                               strings[NOT], &match) == lwc_error_ok &&
                                match) {
                int old_ctx = *ctx;
 
@@ -911,7 +917,8 @@ static css_error mq_parse_media_query(css_language *c,
 
        if (is_condition) {
                /* media-condition */
-               error = mq_parse_condition(c, vector, ctx, true, &result->cond);
+               error = mq_parse_condition(strings, vector, ctx, true,
+                               &result->cond);
                if (error != CSS_OK) {
                        free(result);
                        return error;
@@ -928,14 +935,12 @@ static css_error mq_parse_media_query(css_language *c,
        }
 
        if (lwc_string_caseless_isequal(token->idata,
-                       c->strings[NOT], &match) == lwc_error_ok &&
-                       match) {
+                       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) {
+                       strings[ONLY], &match) == lwc_error_ok && match) {
                consumeWhitespace(vector, ctx);
                token = parserutils_vector_iterate(vector, ctx);
        }
@@ -945,7 +950,7 @@ static css_error mq_parse_media_query(css_language *c,
                return CSS_INVALID;
        }
 
-       result->type = mq_parse_type(c, token->idata);
+       result->type = mq_parse_type(strings, token->idata);
 
        consumeWhitespace(vector, ctx);
 
@@ -953,7 +958,7 @@ static css_error mq_parse_media_query(css_language *c,
        if (token != NULL) {
                if (token->type != CSS_TOKEN_IDENT ||
                                lwc_string_caseless_isequal(token->idata,
-                                       c->strings[AND], &match) != 
lwc_error_ok ||
+                                       strings[AND], &match) != lwc_error_ok ||
                                match == false) {
                        free(result);
                        return CSS_INVALID;
@@ -961,7 +966,8 @@ static css_error mq_parse_media_query(css_language *c,
 
                consumeWhitespace(vector, ctx);
 
-               error = mq_parse_condition(c, vector, ctx, false, 
&result->cond);
+               error = mq_parse_condition(strings, vector, ctx, false,
+                               &result->cond);
                if (error != CSS_OK) {
                        free(result);
                        return error;
@@ -972,7 +978,7 @@ static css_error mq_parse_media_query(css_language *c,
        return CSS_OK;
 }
 
-css_error css__mq_parse_media_list(css_language *c,
+css_error css__mq_parse_media_list(lwc_string **strings,
                const parserutils_vector *vector, int *ctx,
                css_mq_query **media)
 {
@@ -993,7 +999,7 @@ css_error css__mq_parse_media_list(css_language *c,
        while (token != NULL) {
                css_mq_query *query;
 
-               error = mq_parse_media_query(c, vector, ctx, &query);
+               error = mq_parse_media_query(strings, vector, ctx, &query);
                if (error != CSS_OK) {
                        /* TODO: error recovery (see above) */
                        css__mq_query_destroy(result);
diff --git a/src/parse/mq.h b/src/parse/mq.h
index 381e0f9..2940032 100644
--- a/src/parse/mq.h
+++ b/src/parse/mq.h
@@ -87,7 +87,7 @@ typedef struct css_mq_query {
        css_mq_cond *cond;
 } css_mq_query;
 
-css_error css__mq_parse_media_list(css_language *c,
+css_error css__mq_parse_media_list(lwc_string **strings,
                const parserutils_vector *vector, int *ctx,
                css_mq_query **media);
 


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

    Media Queries: API for stylesheet import doesn't take media now.

diff --git a/test/css21.c b/test/css21.c
index a29fae1..cdd66f7 100644
--- a/test/css21.c
+++ b/test/css21.c
@@ -99,10 +99,8 @@ int main(int argc, char **argv)
 
                while (error == CSS_IMPORTS_PENDING) {
                        lwc_string *url;
-                       uint64_t media;
 
-                       error = css_stylesheet_next_pending_import(sheet,
-                                       &url, &media);
+                       error = css_stylesheet_next_pending_import(sheet, &url);
                        assert(error == CSS_OK || error == CSS_INVALID);
 
                        if (error == CSS_OK) {
diff --git a/test/parse-auto.c b/test/parse-auto.c
index 58ccf9a..5f926e3 100644
--- a/test/parse-auto.c
+++ b/test/parse-auto.c
@@ -395,10 +395,8 @@ void run_test(const uint8_t *data, size_t len, exp_entry 
*exp, size_t explen)
 
        while (error == CSS_IMPORTS_PENDING) {
                lwc_string *url;
-               uint64_t media;
 
-               error = css_stylesheet_next_pending_import(sheet,
-                               &url, &media);
+               error = css_stylesheet_next_pending_import(sheet, &url);
                assert(error == CSS_OK || error == CSS_INVALID);
 
                if (error == CSS_OK) {


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

    Media Queries: Update stylesheet import for media query lists.

diff --git a/src/select/select.c b/src/select/select.c
index 644369a..480b9f5 100644
--- a/src/select/select.c
+++ b/src/select/select.c
@@ -1847,7 +1847,8 @@ css_error select_from_sheet(css_select_ctx *ctx, const 
css_stylesheet *sheet,
                                        (const css_rule_import *) rule;
 
                        if (import->sheet != NULL &&
-                                       (import->media & state->media) != 0) {
+                                       mq__list_match(import->media,
+                                                       state->media)) {
                                /* It's applicable, so process it */
                                if (sp >= IMPORT_STACK_SIZE)
                                        return CSS_NOMEM;
@@ -1954,7 +1955,8 @@ static css_error select_font_faces_from_sheet(
                                        (const css_rule_import *) rule;
 
                        if (import->sheet != NULL &&
-                                       (import->media & state->media) != 0) {
+                                       mq__list_match(import->media,
+                                                       state->media)) {
                                /* It's applicable, so process it */
                                if (sp >= IMPORT_STACK_SIZE)
                                        return CSS_NOMEM;


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

    Media Queries: Update rule_good_for_media for new mq struct.
    
    Doesn't currently match media query conditions, only the
    media type.

diff --git a/src/select/mq.h b/src/select/mq.h
index a0a9f6d..5aa1404 100644
--- a/src/select/mq.h
+++ b/src/select/mq.h
@@ -10,10 +10,47 @@
 #define css_select_mq_h_
 
 /**
+ * Match media query conditions.
+ *
+ * \param[in] cond  Condition to match.
+ * \return true if condition matches, otherwise false.
+ */
+static inline bool mq_match_condition(css_mq_cond *cond)
+{
+       /* TODO: Implement this. */
+       return cond == NULL;
+}
+
+/**
+ * Test whether media query list matches current media.
+ *
+ * If anything in the list matches, it the list matches.  If none match
+ * it doesn't match.
+ *
+ * \param m      Media query list.
+ * \meaid media  Current media spec, to check against m.
+ * \return true if media query list matches media
+ */
+static inline bool mq__list_match(const css_mq_query *m, uint64_t media)
+{
+       for (; m != NULL; m = m->next) {
+               /* Check type */
+               if (!!(m->type & media) != m->negate_type) {
+                       if (mq_match_condition(m->cond)) {
+                               /* We have a match, no need to look further. */
+                               return true;
+                       }
+               }
+       }
+
+       return false;
+}
+
+/**
  * Test whether the rule applies for current media.
  *
- * \param rule         Rule to test
- * \meaid media                Current media type(s)
+ * \param rule   Rule to test
+ * \param media  Current media type(s)
  * \return true iff chain's rule applies for media
  */
 static inline bool mq_rule_good_for_media(const css_rule *rule, uint64_t media)
@@ -24,10 +61,11 @@ static inline bool mq_rule_good_for_media(const css_rule 
*rule, uint64_t media)
        while (ancestor != NULL) {
                const css_rule_media *m = (const css_rule_media *) ancestor;
 
-               if (ancestor->type == CSS_RULE_MEDIA &&
-                               (m->media & media) == 0) {
-                       applies = false;
-                       break;
+               if (ancestor->type == CSS_RULE_MEDIA) {
+                       applies = mq__list_match(m->media, media);
+                       if (applies == false) {
+                               break;
+                       }
                }
 
                if (ancestor->ptype != CSS_RULE_PARENT_STYLESHEET) {


commitdiff 
http://git.netsurf-browser.org/libcss.git/commit/?id=4ddb36bdf12d754b1e7d49060a19e4886d190640
commit 4ddb36bdf12d754b1e7d49060a19e4886d190640
Author: Michael Drake <[email protected]>
Commit: Michael Drake <[email protected]>

    Media Queries: Store type as value, rather than lwc_string.
    
    Otherwise we need to convert it in selection, and select/
    doesn't have access to the css_language interned strings
    table.

diff --git a/src/parse/mq.c b/src/parse/mq.c
index 8f4391b..f7b8b6e 100644
--- a/src/parse/mq.c
+++ b/src/parse/mq.c
@@ -806,6 +806,64 @@ static css_error mq_parse_condition(css_language *c,
        return CSS_OK;
 }
 
+/**
+ * Parse a media query type.
+ */
+static uint64_t mq_parse_type(css_language *c, lwc_string *type)
+{
+       bool match;
+
+       if (type == NULL) {
+               return CSS_MEDIA_ALL;
+       } else if (lwc_string_caseless_isequal(
+                       type, c->strings[AURAL],
+                       &match) == lwc_error_ok && match) {
+               return CSS_MEDIA_AURAL;
+       } else if (lwc_string_caseless_isequal(
+                       type, c->strings[BRAILLE],
+                       &match) == lwc_error_ok && match) {
+               return CSS_MEDIA_BRAILLE;
+       } else if (lwc_string_caseless_isequal(
+                       type, c->strings[EMBOSSED],
+                       &match) == lwc_error_ok && match) {
+               return CSS_MEDIA_EMBOSSED;
+       } else if (lwc_string_caseless_isequal(
+                       type, c->strings[HANDHELD],
+                       &match) == lwc_error_ok && match) {
+               return CSS_MEDIA_HANDHELD;
+       } else if (lwc_string_caseless_isequal(
+                       type, c->strings[PRINT],
+                       &match) == lwc_error_ok && match) {
+               return CSS_MEDIA_PRINT;
+       } else if (lwc_string_caseless_isequal(
+                       type, c->strings[PROJECTION],
+                       &match) == lwc_error_ok && match) {
+               return CSS_MEDIA_PROJECTION;
+       } else if (lwc_string_caseless_isequal(
+                       type, c->strings[SCREEN],
+                       &match) == lwc_error_ok && match) {
+               return CSS_MEDIA_SCREEN;
+       } else if (lwc_string_caseless_isequal(
+                       type, c->strings[SPEECH],
+                       &match) == lwc_error_ok && match) {
+               return CSS_MEDIA_SPEECH;
+       } else if (lwc_string_caseless_isequal(
+                       type, c->strings[TTY],
+                       &match) == lwc_error_ok && match) {
+               return CSS_MEDIA_TTY;
+       } else if (lwc_string_caseless_isequal(
+                       type, c->strings[TV],
+                       &match) == lwc_error_ok && match) {
+               return CSS_MEDIA_TV;
+       } else if (lwc_string_caseless_isequal(
+                       type, c->strings[ALL],
+                       &match) == lwc_error_ok && match) {
+               return CSS_MEDIA_ALL;
+       }
+
+       return 0;
+}
+
 static css_error mq_parse_media_query(css_language *c,
                const parserutils_vector *vector, int *ctx,
                css_mq_query **query)
@@ -887,7 +945,7 @@ static css_error mq_parse_media_query(css_language *c,
                return CSS_INVALID;
        }
 
-       result->type = lwc_string_ref(token->idata);
+       result->type = mq_parse_type(c, token->idata);
 
        consumeWhitespace(vector, ctx);
 
@@ -897,7 +955,6 @@ static css_error mq_parse_media_query(css_language *c,
                                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;
                }
@@ -906,7 +963,6 @@ static css_error mq_parse_media_query(css_language *c,
 
                error = mq_parse_condition(c, vector, ctx, false, 
&result->cond);
                if (error != CSS_OK) {
-                       lwc_string_unref(result->type);
                        free(result);
                        return error;
                }
diff --git a/src/parse/mq.h b/src/parse/mq.h
index 77f8a8a..381e0f9 100644
--- a/src/parse/mq.h
+++ b/src/parse/mq.h
@@ -82,7 +82,7 @@ typedef struct css_mq_query {
        struct css_mq_query *next;
 
        uint32_t negate_type : 1; /* set if "not type" */
-       lwc_string *type; /* or NULL */
+       uint64_t type; /* or NULL */
 
        css_mq_cond *cond;
 } css_mq_query;


commitdiff 
http://git.netsurf-browser.org/libcss.git/commit/?id=55c0ff7fb7faa1383f5fbda7261d7e1be6249220
commit 55c0ff7fb7faa1383f5fbda7261d7e1be6249220
Author: Michael Drake <[email protected]>
Commit: Michael Drake <[email protected]>

    Media Queries: Fix range parsing.

diff --git a/src/parse/mq.c b/src/parse/mq.c
index ffddf64..8f4391b 100644
--- a/src/parse/mq.c
+++ b/src/parse/mq.c
@@ -227,7 +227,7 @@ static css_error mq_parse_range(css_language *c,
        if (name_or_value->type == CSS_TOKEN_NUMBER &&
                        tokenIsChar(parserutils_vector_peek(vector, *ctx), 
'/')) {
                /* ratio */
-               error = mq_parse_ratio(vector, ctx, token, &ratio);
+               error = mq_parse_ratio(vector, ctx, name_or_value, &ratio);
                if (error != CSS_OK) {
                        return error;
                }


commitdiff 
http://git.netsurf-browser.org/libcss.git/commit/?id=55c5cb22e615ed91098a5ace3de29e17c5dc509b
commit 55c5cb22e615ed91098a5ace3de29e17c5dc509b
Author: Michael Drake <[email protected]>
Commit: Michael Drake <[email protected]>

    Media Queries: Client media specification structure.

diff --git a/include/libcss/types.h b/include/libcss/types.h
index c5e9cce..49bd68c 100644
--- a/include/libcss/types.h
+++ b/include/libcss/types.h
@@ -116,6 +116,132 @@ typedef enum css_unit {
 } css_unit;
 
 /**
+ * Media orienations
+ */
+typedef enum css_media_orientation {
+       CSS_MEDIA_ORIENTATION_PORTRAIT  = 0,
+       CSS_MEDIA_ORIENTATION_LANDSCAPE = 1
+} css_media_orientation;
+
+/**
+ * Media scans
+ */
+typedef enum css_media_scan {
+       CSS_MEDIA_SCAN_PROGRESSIVE = 0,
+       CSS_MEDIA_SCAN_INTERLACE   = 1
+} css_media_scan;
+
+/**
+ * Media update-frequencies
+ */
+typedef enum css_media_update_frequency {
+       CSS_MEDIA_UPDATE_FREQUENCY_NORMAL = 0,
+       CSS_MEDIA_UPDATE_FREQUENCY_SLOW   = 1,
+       CSS_MEDIA_UPDATE_FREQUENCY_NONE   = 2
+} css_media_update_frequency;
+
+/**
+ * Media block overflows
+ */
+typedef enum css_media_overflow_block {
+       CSS_MEDIA_OVERFLOW_BLOCK_NONE           = 0,
+       CSS_MEDIA_OVERFLOW_BLOCK_SCROLL         = 1,
+       CSS_MEDIA_OVERFLOW_BLOCK_OPTIONAL_PAGED = 2,
+       CSS_MEDIA_OVERFLOW_BLOCK_PAGED          = 3
+} css_media_overflow_block;
+
+/**
+ * Media inline overflows
+ */
+typedef enum css_media_overflow_inline {
+       CSS_MEDIA_OVERFLOW_INLINE_NONE   = 0,
+       CSS_MEDIA_OVERFLOW_INLINE_SCROLL = 1
+} css_media_overflow_inline;
+
+/**
+ * Media pointers
+ */
+typedef enum css_media_pointer {
+       CSS_MEDIA_POINTER_NONE   = 0,
+       CSS_MEDIA_POINTER_COARSE = 1,
+       CSS_MEDIA_POINTER_FINE   = 2
+} css_media_pointer;
+
+/**
+ * Media hovers
+ */
+typedef enum css_media_hover {
+       CSS_MEDIA_HOVER_NONE      = 0,
+       CSS_MEDIA_HOVER_ON_DEMAND = 1,
+       CSS_MEDIA_HOVER_HOVER     = 2
+} css_media_hover;
+
+/**
+ * Media light-levels
+ */
+typedef enum css_media_light_level {
+       CSS_MEDIA_LIGHT_LEVEL_NORMAL = 0,
+       CSS_MEDIA_LIGHT_LEVEL_DIM    = 1,
+       CSS_MEDIA_LIGHT_LEVEL_WASHED = 2
+} css_media_light_level;
+
+/**
+ * Media scriptings
+ */
+typedef enum css_media_scripting {
+       CSS_MEDIA_SCRIPTING_NONE         = 0,
+       CSS_MEDIA_SCRIPTING_INITIAL_ONLY = 1,
+       CSS_MEDIA_SCRIPTING_ENABLED      = 2
+} css_media_scripting;
+
+typedef struct css_media_length {
+       css_fixed value;
+       css_unit unit;
+} css_media_length;
+
+typedef struct css_media_resolution {
+       css_fixed value;
+       css_unit unit;
+} css_media_resolution;
+
+/**
+ * Media specification
+ */
+typedef struct css_media {
+       /* Screen / Device media features */
+       css_media_length      width;
+       css_media_length      height;
+       css_fixed             aspect_ratio;
+       css_media_orientation orientation;
+
+       /* Display quality media features */
+       css_media_resolution       resolution;
+       css_media_scan             scan;
+       css_fixed                  grid; /** boolean: {0|1} */
+       css_media_update_frequency update;
+       css_media_overflow_block   overflow_block;
+       css_media_overflow_inline  overflow_inline;
+
+       /* Color media features */
+       css_fixed color;      /* colour bpp (0 for monochrome) */
+       css_fixed color_index;
+       css_fixed monochrome; /* monochrome bpp (0 for colour) */
+       css_fixed inverted_colors; /** boolean: {0|1} */
+
+       /* Interaction media features */
+       css_media_pointer pointer;
+       css_media_pointer any_pointer;
+       css_media_hover   hover;
+       css_media_hover   any_hover;
+
+       /* Environmental media features */
+       css_media_light_level light_level;
+
+       /* Scripting media features */
+       css_media_scripting scripting;
+} css_media;
+
+/**
  * Type of a qualified name
  */
 typedef struct css_qname {


commitdiff 
http://git.netsurf-browser.org/libcss.git/commit/?id=960f641a354b638795084df3475ffac191ef3abf
commit 960f641a354b638795084df3475ffac191ef3abf
Author: Michael Drake <[email protected]>
Commit: Michael Drake <[email protected]>

    Code style: Use spaces for alignment.

diff --git a/include/libcss/types.h b/include/libcss/types.h
index 4f35737..c5e9cce 100644
--- a/include/libcss/types.h
+++ b/include/libcss/types.h
@@ -60,10 +60,10 @@ typedef enum css_media_type {
        CSS_MEDIA_TTY               = (1 << 8),
        CSS_MEDIA_TV                = (1 << 9),
        CSS_MEDIA_ALL               = CSS_MEDIA_AURAL | CSS_MEDIA_BRAILLE |
-                                      CSS_MEDIA_EMBOSSED | CSS_MEDIA_HANDHELD |
-                                      CSS_MEDIA_PRINT | CSS_MEDIA_PROJECTION |
-                                      CSS_MEDIA_SCREEN | CSS_MEDIA_SPEECH |
-                                      CSS_MEDIA_TTY | CSS_MEDIA_TV
+                                     CSS_MEDIA_EMBOSSED | CSS_MEDIA_HANDHELD |
+                                     CSS_MEDIA_PRINT | CSS_MEDIA_PROJECTION |
+                                     CSS_MEDIA_SCREEN | CSS_MEDIA_SPEECH |
+                                     CSS_MEDIA_TTY | CSS_MEDIA_TV
 } css_media_type;
 
 /**


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

    Media Queries: Add error-path resource cleanup.

diff --git a/src/parse/mq.c b/src/parse/mq.c
index 1fa66d6..ffddf64 100644
--- a/src/parse/mq.c
+++ b/src/parse/mq.c
@@ -369,8 +369,7 @@ static css_error mq_parse_range(css_language *c,
                        /* num/dim/ident */
                        error = mq_populate_value(&result->value2, token);
                        if (error != CSS_OK) {
-                               /* TODO: clean up result properly? */
-                               free(result);
+                               css_mq_feature_destroy(result);
                                return error;
                        }
                }
@@ -481,7 +480,7 @@ static css_error mq_parse_media_feature(css_language *c,
 
        token = parserutils_vector_iterate(vector, ctx);
        if (tokenIsChar(token, ')') == false) {
-               /* TODO: clean up result */
+               css_mq_feature_destroy(result);
                return CSS_INVALID;
        }
 
@@ -644,7 +643,7 @@ static css_error mq_parse_media_in_parens(css_language *c,
 
                        result = malloc(sizeof(*result));
                        if (result == NULL) {
-                               /* TODO: clean up cond */
+                               css__mq_cond_destroy(cond);
                                return CSS_NOMEM;
                        }
                        memset(result, 0, sizeof(*result));
@@ -661,7 +660,7 @@ static css_error mq_parse_media_in_parens(css_language *c,
                if (error == CSS_OK) {
                        result = malloc(sizeof(*result));
                        if (result == NULL) {
-                               /* TODO: clean up feature */
+                               css_mq_feature_destroy(feature);
                                return CSS_NOMEM;
                        }
                        memset(result, 0, sizeof(*result));
@@ -724,8 +723,7 @@ static css_error mq_parse_condition(css_language *c,
 
                error = mq_parse_media_in_parens(c, vector, ctx, 
&cond_or_feature);
                if (error != CSS_OK) {
-                       free(result->parts);
-                       free(result);
+                       css__mq_cond_destroy(result);
                        return CSS_INVALID;
                }
 
@@ -733,9 +731,8 @@ static css_error mq_parse_condition(css_language *c,
                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);
+                       css__mq_cond_or_feature_destroy(cond_or_feature);
+                       css__mq_cond_destroy(result);
                        return CSS_NOMEM;
                }
                result->parts->parts[0] = cond_or_feature;
@@ -750,18 +747,15 @@ static css_error mq_parse_condition(css_language *c,
                        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);
+                       css__mq_cond_destroy(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);
+                       css__mq_cond_or_feature_destroy(cond_or_feature);
+                       css__mq_cond_destroy(result);
                        return CSS_NOMEM;
                }
                parts[result->parts->nparts] = cond_or_feature;
@@ -774,17 +768,13 @@ static css_error mq_parse_condition(css_language *c,
                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);
+                               css__mq_cond_destroy(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);
+                                       css__mq_cond_destroy(result);
                                        return CSS_INVALID;
                                }
                                op = AND;
@@ -792,17 +782,13 @@ static css_error mq_parse_condition(css_language *c,
                                                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);
+                                       css__mq_cond_destroy(result);
                                        return CSS_INVALID;
                                }
                                op = OR;
                        } else {
                                /* Neither AND nor OR */
-                               /* TODO: clean up result->parts->parts */
-                               free(result->parts);
-                               free(result);
+                               css__mq_cond_destroy(result);
                                return CSS_INVALID;
                        }
 
@@ -954,6 +940,8 @@ css_error css__mq_parse_media_list(css_language *c,
                error = mq_parse_media_query(c, vector, ctx, &query);
                if (error != CSS_OK) {
                        /* TODO: error recovery (see above) */
+                       css__mq_query_destroy(result);
+                       return error;
                } else {
                        if (result == NULL) {
                                result = last = query;


commitdiff 
http://git.netsurf-browser.org/libcss.git/commit/?id=7c38f6c3ce7622ae2e12589a70579b440992efcb
commit 7c38f6c3ce7622ae2e12589a70579b440992efcb
Author: Michael Drake <[email protected]>
Commit: Michael Drake <[email protected]>

    Media Queries: Add destruction functions.

diff --git a/src/parse/mq.c b/src/parse/mq.c
index 6692651..1fa66d6 100644
--- a/src/parse/mq.c
+++ b/src/parse/mq.c
@@ -17,6 +17,63 @@
 #include "parse/properties/utils.h"
 #include "utils/utils.h"
 
+static void css_mq_feature_destroy(css_mq_feature *feature)
+{
+       if (feature != NULL) {
+               lwc_string_unref(feature->name);
+               free(feature);
+       }
+}
+
+static void css__mq_cond_or_feature_destroy(
+               css_mq_cond_or_feature *cond_or_feature);
+
+static void css__mq_cond_parts_destroy(css_mq_cond_parts *cond_parts)
+{
+       if (cond_parts != NULL) {
+               for (uint32_t i = 0; i < cond_parts->nparts; i++) {
+                       css__mq_cond_or_feature_destroy(cond_parts->parts[i]);
+               }
+               free(cond_parts);
+       }
+}
+
+static void css__mq_cond_destroy(css_mq_cond *cond)
+{
+       if (cond != NULL) {
+               css__mq_cond_parts_destroy(cond->parts);
+               free(cond);
+       }
+}
+
+static void css__mq_cond_or_feature_destroy(
+               css_mq_cond_or_feature *cond_or_feature)
+{
+       if (cond_or_feature != NULL) {
+               switch (cond_or_feature->type) {
+               case CSS_MQ_FEATURE:
+                       css_mq_feature_destroy(cond_or_feature->data.feat);
+                       break;
+               case CSS_MQ_COND:
+                       css__mq_cond_destroy(cond_or_feature->data.cond);
+                       break;
+               }
+               free(cond_or_feature);
+       }
+}
+
+void css__mq_query_destroy(css_mq_query *media)
+{
+       while (media != NULL) {
+               css_mq_query *next = media->next;
+
+               css__mq_cond_destroy(media->cond);
+               free(media);
+
+               media = next;
+       }
+}
+
 static css_error mq_parse_condition(css_language *c,
                const parserutils_vector *vector, int *ctx,
                bool permit_or, css_mq_cond **cond);
diff --git a/src/parse/mq.h b/src/parse/mq.h
index ae0110b..77f8a8a 100644
--- a/src/parse/mq.h
+++ b/src/parse/mq.h
@@ -91,6 +91,6 @@ css_error css__mq_parse_media_list(css_language *c,
                const parserutils_vector *vector, int *ctx,
                css_mq_query **media);
 
-css_mq_query *css__mq_query_destroy(css_mq_query *media);
+void css__mq_query_destroy(css_mq_query *media);
 
 #endif


commitdiff 
http://git.netsurf-browser.org/libcss.git/commit/?id=819a78a0eb742c04ec3fdfeaeba97ad4962c8eaa
commit 819a78a0eb742c04ec3fdfeaeba97ad4962c8eaa
Author: Michael Drake <[email protected]>
Commit: Michael Drake <[email protected]>

    Documentation: Add new units to bytecode docs.

diff --git a/docs/Bytecode b/docs/Bytecode
index f64656a..dd0f424 100644
--- a/docs/Bytecode
+++ b/docs/Bytecode
@@ -69,6 +69,7 @@ Length is a 32bit numeric value (as described above) and unit 
is as follows:
                        00000000 => deg
                        00000001 => grad
                        00000010 => rad
+                       00000011 => turn
 
        bit 10 set => time unit
                bits 11-31: MBZ
@@ -84,6 +85,14 @@ Length is a 32bit numeric value (as described above) and 
unit is as follows:
                        00000000 => Hz
                        00000001 => kHz
 
+       bit 12 set => resolution unit
+               bits 13-31: MBZ
+               bits 8-11 : MBZ
+               bits 0-7  :
+                       00000000 => dpi
+                       00000001 => dpcm
+                       00000010 => dppx
+
 CSS colours are stored as one 32bit value. See "Colour" for their format.
 
 Shorthand properties


commitdiff 
http://git.netsurf-browser.org/libcss.git/commit/?id=0311677f5676e2f6213a774938dbdc893897cebb
commit 0311677f5676e2f6213a774938dbdc893897cebb
Author: Michael Drake <[email protected]>
Commit: Michael Drake <[email protected]>

    Media Queries: Implement parsing <general-enclosed>.

diff --git a/src/parse/mq.c b/src/parse/mq.c
index 719e129..6692651 100644
--- a/src/parse/mq.c
+++ b/src/parse/mq.c
@@ -433,14 +433,111 @@ static css_error mq_parse_media_feature(css_language *c,
        return CSS_OK;
 }
 
+/*
+ * Consume any value
+ *
+ * CSS Syntax Module Level 3: 8.2
+ */
+static css_error mq_parse_consume_any_value(css_language *c,
+               const parserutils_vector *vector, int *ctx,
+               bool until, const char until_char)
+{
+       const css_token *token;
+       css_error error;
+
+       while (true) {
+               consumeWhitespace(vector, ctx);
+
+               token = parserutils_vector_iterate(vector, ctx);
+               if (token == NULL) {
+                       return CSS_INVALID;
+               }
+
+               switch (token->type) {
+               case CSS_TOKEN_INVALID_STRING:
+                       return CSS_INVALID;
+
+               case CSS_TOKEN_CHAR:
+                       if (until && tokenIsChar(token, until_char)) {
+                               /* Found matching close bracket */
+                               return CSS_OK;
+
+                       } else if (tokenIsChar(token, ')') ||
+                                  tokenIsChar(token, ']') ||
+                                  tokenIsChar(token, '}')) {
+                               /* Non-matching close bracket */
+                               return CSS_INVALID;
+                       }
+                       if (tokenIsChar(token, '(')) {
+                               /* Need to consume until matching bracket. */
+                               error = mq_parse_consume_any_value(
+                                               c, vector, ctx, true, ')');
+                               if (error != CSS_OK) {
+                                       return error;
+                               }
+                       } else if (tokenIsChar(token, '[')) {
+                               /* Need to consume until matching bracket. */
+                               error = mq_parse_consume_any_value(
+                                               c, vector, ctx, true, ']');
+                               if (error != CSS_OK) {
+                                       return error;
+                               }
+                       } else if (tokenIsChar(token, '{')) {
+                               /* Need to consume until matching bracket. */
+                               error = mq_parse_consume_any_value(
+                                               c, vector, ctx, true, '}');
+                               if (error != CSS_OK) {
+                                       return error;
+                               }
+                       }
+                       break;
+
+               default:
+                       break;
+               }
+       }
+
+       return CSS_OK;
+}
+
 static css_error mq_parse_general_enclosed(css_language *c,
                const parserutils_vector *vector, int *ctx)
 {
+       const css_token *token;
+       css_error error;
+
        /* <general-enclosed> = [ <function-token> <any-value> ) ]
         *                    | ( <ident> <any-value> )
         */
 
-       /* TODO: implement */
+       token = parserutils_vector_iterate(vector, ctx);
+       if (token == NULL) {
+               return CSS_INVALID;
+       }
+
+       switch (token->type) {
+       case CSS_TOKEN_FUNCTION:
+               error = mq_parse_consume_any_value(c, vector, ctx, true, ')');
+               if (error != CSS_OK) {
+                       return error;
+               }
+
+               token = parserutils_vector_peek(vector, *ctx);
+               if (!tokenIsChar(token, ')')) {
+                       return CSS_INVALID;
+               }
+               break;
+
+       case CSS_TOKEN_IDENT:
+               error = mq_parse_consume_any_value(c, vector, ctx, false, '\0');
+               if (error != CSS_OK) {
+                       return error;
+               }
+               break;
+
+       default:
+               return CSS_INVALID;
+       }
 
        return CSS_OK;
 }


commitdiff 
http://git.netsurf-browser.org/libcss.git/commit/?id=52131876ea0a87f94963d7d00d04582ce379cdcb
commit 52131876ea0a87f94963d7d00d04582ce379cdcb
Author: Michael Drake <[email protected]>
Commit: Michael Drake <[email protected]>

    Media Queries: Squash invalid use of unused variable warning.
    
    error: ‘last’ may be used uninitialized in this function 
[-Werror=maybe-uninitialized]

diff --git a/src/parse/mq.c b/src/parse/mq.c
index f587f8d..719e129 100644
--- a/src/parse/mq.c
+++ b/src/parse/mq.c
@@ -780,7 +780,7 @@ 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;
+       css_mq_query *result = NULL, *last = NULL;
        const css_token *token;
        css_error error;
 
@@ -804,6 +804,7 @@ css_error css__mq_parse_media_list(css_language *c,
                        if (result == NULL) {
                                result = last = query;
                        } else {
+                               assert(last != NULL);
                                last->next = query;
                                last = query;
                        }


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

    Media Queries: Add forward declaration of mq_parse_condition.

diff --git a/src/parse/mq.c b/src/parse/mq.c
index 932d6aa..f587f8d 100644
--- a/src/parse/mq.c
+++ b/src/parse/mq.c
@@ -17,6 +17,10 @@
 #include "parse/properties/utils.h"
 #include "utils/utils.h"
 
+static css_error mq_parse_condition(css_language *c,
+               const parserutils_vector *vector, int *ctx,
+               bool permit_or, css_mq_cond **cond);
+
 static css_error mq_parse_ratio(
                const parserutils_vector *vector, int *ctx,
                const css_token *numerator, css_fixed *ratio)


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

    Media Queries: mq_parse_ratio doesn't need language object.

diff --git a/src/parse/mq.c b/src/parse/mq.c
index f99d5b0..932d6aa 100644
--- a/src/parse/mq.c
+++ b/src/parse/mq.c
@@ -17,7 +17,7 @@
 #include "parse/properties/utils.h"
 #include "utils/utils.h"
 
-static css_error mq_parse_ratio(css_language *c,
+static css_error mq_parse_ratio(
                const parserutils_vector *vector, int *ctx,
                const css_token *numerator, css_fixed *ratio)
 {
@@ -166,7 +166,7 @@ static css_error mq_parse_range(css_language *c,
        if (name_or_value->type == CSS_TOKEN_NUMBER &&
                        tokenIsChar(parserutils_vector_peek(vector, *ctx), 
'/')) {
                /* ratio */
-               error = mq_parse_ratio(c, vector, ctx, token, &ratio);
+               error = mq_parse_ratio(vector, ctx, token, &ratio);
                if (error != CSS_OK) {
                        return error;
                }
@@ -213,7 +213,7 @@ static css_error mq_parse_range(css_language *c,
        if (value_or_name->type == CSS_TOKEN_NUMBER &&
                        tokenIsChar(parserutils_vector_peek(vector, *ctx), 
'/')) {
                /* ratio */
-               error = mq_parse_ratio(c, vector, ctx, token, &ratio);
+               error = mq_parse_ratio(vector, ctx, token, &ratio);
                if (error != CSS_OK) {
                        return error;
                }
@@ -260,7 +260,7 @@ static css_error mq_parse_range(css_language *c,
                if (value_or_name->type == CSS_TOKEN_NUMBER &&
                                tokenIsChar(parserutils_vector_peek(vector, 
*ctx), '/')) {
                        /* ratio */
-                       error = mq_parse_ratio(c, vector, ctx, token, &ratio2);
+                       error = mq_parse_ratio(vector, ctx, token, &ratio2);
                        if (error != CSS_OK) {
                                return error;
                        }
@@ -381,7 +381,7 @@ static css_error mq_parse_media_feature(css_language *c,
                                /* ratio */
                                css_fixed ratio;
 
-                               error = mq_parse_ratio(c, vector, ctx, token, 
&ratio);
+                               error = mq_parse_ratio(vector, ctx, token, 
&ratio);
                                if (error != CSS_OK) {
                                        free(result);
                                        return error;


commitdiff 
http://git.netsurf-browser.org/libcss.git/commit/?id=6b6c2eee7f9845f563a008fa2d78667ddaf781bc
commit 6b6c2eee7f9845f563a008fa2d78667ddaf781bc
Author: Michael Drake <[email protected]>
Commit: Michael Drake <[email protected]>

    Media Queries: Minor fixes.

diff --git a/src/parse/mq.c b/src/parse/mq.c
index 8bdd7a0..f99d5b0 100644
--- a/src/parse/mq.c
+++ b/src/parse/mq.c
@@ -82,8 +82,9 @@ static css_error mq_populate_value(css_mq_value *value,
                const char *data = lwc_string_data(token->idata);
                uint32_t unit = UNIT_PX;
                size_t consumed;
+               css_error error;
 
-               value->type == CSS_MQ_VALUE_TYPE_DIM;
+               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,
@@ -91,7 +92,7 @@ static css_error mq_populate_value(css_mq_value *value,
                if (error != CSS_OK) {
                        return error;
                }
-               value->data.dim.unit = temp_unit;
+               value->data.dim.unit = unit;
        } else if (token->type == CSS_TOKEN_IDENT) {
                value->type = CSS_MQ_VALUE_TYPE_IDENT;
                value->data.ident = lwc_string_ref(token->idata);
@@ -447,7 +448,7 @@ static css_error mq_parse_media_in_parens(css_language *c,
        const css_token *token;
        bool match;
        int old_ctx;
-       cond_or_feature *result = NULL;
+       css_mq_cond_or_feature *result = NULL;
        css_error error = CSS_OK;
 
        /* <media-in-parens> = ( <media-condition> ) | <media-feature> | 
<general-enclosed>
@@ -609,7 +610,7 @@ static css_error mq_parse_condition(css_language *c,
                result->parts->parts = parts;
                result->parts->nparts++;
 
-               consumeWhitespace(vector, token);
+               consumeWhitespace(vector, ctx);
 
                token = parserutils_vector_peek(vector, *ctx);
                if (token != NULL && tokenIsChar(token, ')') == false &&


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

    Strings: Add 'infinite'.

diff --git a/src/parse/propstrings.c b/src/parse/propstrings.c
index dc32ce9..3c9401b 100644
--- a/src/parse/propstrings.c
+++ b/src/parse/propstrings.c
@@ -442,6 +442,7 @@ const stringmap_entry stringmap[LAST_KNOWN] = {
        { "and", SLEN("and") },
        { "or", SLEN("or") },
        { "only", SLEN("only") },
+       { "infinite", SLEN("infinite") },
 
        { "aliceblue", SLEN("aliceblue") },
        { "antiquewhite", SLEN("antiquewhite") },
diff --git a/src/parse/propstrings.h b/src/parse/propstrings.h
index 0d5d0be..24b681b 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, AND, OR, ONLY,
+       COLUMN_REVERSE, WRAP_STRING, WRAP_REVERSE, AND, OR, ONLY, INFINITE,
 
        /* Named colours */
        FIRST_COLOUR,


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

    Media Queries: Include string.h for memset.

diff --git a/src/parse/mq.c b/src/parse/mq.c
index 48f4c41..8bdd7a0 100644
--- a/src/parse/mq.c
+++ b/src/parse/mq.c
@@ -7,6 +7,8 @@
 
 /* https://drafts.csswg.org/mediaqueries/ */
 
+#include <string.h>
+
 #include <libcss/fpmath.h>
 
 #include "stylesheet.h"


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

    Media Queries: Include stylesheet.h for css_style.

diff --git a/src/parse/mq.c b/src/parse/mq.c
index c557996..48f4c41 100644
--- a/src/parse/mq.c
+++ b/src/parse/mq.c
@@ -9,6 +9,7 @@
 
 #include <libcss/fpmath.h>
 
+#include "stylesheet.h"
 #include "bytecode/bytecode.h"
 #include "parse/mq.h"
 #include "parse/properties/utils.h"


commitdiff 
http://git.netsurf-browser.org/libcss.git/commit/?id=0b5d61d41b786ff6c081e5f44d12b061cf453caa
commit 0b5d61d41b786ff6c081e5f44d12b061cf453caa
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=38cad9c5adc597448c9ea73ece67d36c012a2cd8
commit 38cad9c5adc597448c9ea73ece67d36c012a2cd8
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=e47d8dcc95f8fbe830a2b7852ba0af0d60f1a29b
commit e47d8dcc95f8fbe830a2b7852ba0af0d60f1a29b
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=a1347619c5f9ad96d2462a568e625fec567594e2
commit a1347619c5f9ad96d2462a568e625fec567594e2
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 7abef24..0e49853 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=dc5dc8aaba115bb678be2a5a59a6054027bf28c1
commit dc5dc8aaba115bb678be2a5a59a6054027bf28c1
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=f8c906e4c6ff36cefe0803cba6b2a083efe5bcb6
commit f8c906e4c6ff36cefe0803cba6b2a083efe5bcb6
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