Gitweb links:
...log
http://git.netsurf-browser.org/libcss.git/shortlog/ca72aeff08e5d596f2da13eeab00433f566431ba
...commit
http://git.netsurf-browser.org/libcss.git/commit/ca72aeff08e5d596f2da13eeab00433f566431ba
...tree
http://git.netsurf-browser.org/libcss.git/tree/ca72aeff08e5d596f2da13eeab00433f566431ba
The branch, jmb/mq has been updated
via ca72aeff08e5d596f2da13eeab00433f566431ba (commit)
via f83915d4fe8b6cba8b52422dd2a6240cae712c6b (commit)
from 7d759aba6639709b23b92f9fb6cb29099ff612d3 (commit)
Those revisions listed above that are new to this repository have
not appeared on any other notification email; so we list those
revisions in full, below.
- Log -----------------------------------------------------------------
commitdiff
http://git.netsurf-browser.org/libcss.git/commit/?id=ca72aeff08e5d596f2da13eeab00433f566431ba
commit ca72aeff08e5d596f2da13eeab00433f566431ba
Author: John-Mark Bell <[email protected]>
Commit: John-Mark Bell <[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=f83915d4fe8b6cba8b52422dd2a6240cae712c6b
commit f83915d4fe8b6cba8b52422dd2a6240cae712c6b
Author: John-Mark Bell <[email protected]>
Commit: John-Mark Bell <[email protected]>
Propstrings: add AND, ONLY, OR
diff --git a/src/parse/propstrings.c b/src/parse/propstrings.c
index 2c166a0..5a59a7e 100644
--- a/src/parse/propstrings.c
+++ b/src/parse/propstrings.c
@@ -412,6 +412,9 @@ const stringmap_entry stringmap[LAST_KNOWN] = {
{ "horizontal-tb", SLEN("horizontal-tb") },
{ "vertical-rl", SLEN("vertical-rl") },
{ "vertical-lr", SLEN("vertical-lr") },
+ { "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 c686a91..3d4753f 100644
--- a/src/parse/propstrings.h
+++ b/src/parse/propstrings.h
@@ -98,6 +98,7 @@ enum {
LIBCSS_RIGHT, CURRENTCOLOR, ODD, EVEN, SRC, LOCAL, INITIAL,
FORMAT, WOFF, TRUETYPE, OPENTYPE, EMBEDDED_OPENTYPE, SVG, COLUMN,
AVOID_PAGE, AVOID_COLUMN, BALANCE, HORIZONTAL_TB, VERTICAL_RL,
VERTICAL_LR,
+ AND, OR, ONLY,
/* Named colours */
FIRST_COLOUR,
-----------------------------------------------------------------------
Summary of changes:
src/parse/mq.c | 421 ++++++++++++++++++++++++++++++++++++++---------
src/parse/mq.h | 10 +-
src/parse/propstrings.c | 3 +
src/parse/propstrings.h | 1 +
4 files changed, 355 insertions(+), 80 deletions(-)
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,
diff --git a/src/parse/propstrings.c b/src/parse/propstrings.c
index 2c166a0..5a59a7e 100644
--- a/src/parse/propstrings.c
+++ b/src/parse/propstrings.c
@@ -412,6 +412,9 @@ const stringmap_entry stringmap[LAST_KNOWN] = {
{ "horizontal-tb", SLEN("horizontal-tb") },
{ "vertical-rl", SLEN("vertical-rl") },
{ "vertical-lr", SLEN("vertical-lr") },
+ { "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 c686a91..3d4753f 100644
--- a/src/parse/propstrings.h
+++ b/src/parse/propstrings.h
@@ -98,6 +98,7 @@ enum {
LIBCSS_RIGHT, CURRENTCOLOR, ODD, EVEN, SRC, LOCAL, INITIAL,
FORMAT, WOFF, TRUETYPE, OPENTYPE, EMBEDDED_OPENTYPE, SVG, COLUMN,
AVOID_PAGE, AVOID_COLUMN, BALANCE, HORIZONTAL_TB, VERTICAL_RL,
VERTICAL_LR,
+ AND, OR, ONLY,
/* Named colours */
FIRST_COLOUR,
--
Cascading Style Sheets library
_______________________________________________
netsurf-commits mailing list
[email protected]
http://listmaster.pepperfish.net/cgi-bin/mailman/listinfo/netsurf-commits-netsurf-browser.org