Gitweb links:
...log
http://git.netsurf-browser.org/libcss.git/shortlog/0032d2c2b313c7c4afdd3866e72c38c440726a0e
...commit
http://git.netsurf-browser.org/libcss.git/commit/0032d2c2b313c7c4afdd3866e72c38c440726a0e
...tree
http://git.netsurf-browser.org/libcss.git/tree/0032d2c2b313c7c4afdd3866e72c38c440726a0e
The branch, tlsa/jmb/mq has been created
at 0032d2c2b313c7c4afdd3866e72c38c440726a0e (commit)
- Log -----------------------------------------------------------------
commitdiff
http://git.netsurf-browser.org/libcss.git/commit/?id=0032d2c2b313c7c4afdd3866e72c38c440726a0e
commit 0032d2c2b313c7c4afdd3866e72c38c440726a0e
Author: John-Mark Bell <[email protected]>
Commit: Michael Drake <[email protected]>
Media Queries: remainder of parser
diff --git a/src/parse/mq.c b/src/parse/mq.c
index 96f70df..c557996 100644
--- a/src/parse/mq.c
+++ b/src/parse/mq.c
@@ -333,6 +333,8 @@ static css_error mq_parse_media_feature(css_language *c,
/* ( already consumed */
+ consumeWhitespace(vector, ctx);
+
name_or_value = parserutils_vector_iterate(vector, ctx);
if (name_or_value == NULL)
return CSS_INVALID;
@@ -423,42 +425,359 @@ static css_error mq_parse_media_feature(css_language *c,
return CSS_OK;
}
-static css_error mq_parse_media_in_parens()
+static css_error mq_parse_general_enclosed(css_language *c,
+ const parserutils_vector *vector, int *ctx)
{
+ /* <general-enclosed> = [ <function-token> <any-value> ) ]
+ * | ( <ident> <any-value> )
+ */
+
+ /* TODO: implement */
+
+ return CSS_OK;
+}
+
+static css_error mq_parse_media_in_parens(css_language *c,
+ const parserutils_vector *vector, int *ctx,
+ css_mq_cond_or_feature **cond_or_feature)
+{
+ const css_token *token;
+ bool match;
+ int old_ctx;
+ cond_or_feature *result = NULL;
+ css_error error = CSS_OK;
+
/* <media-in-parens> = ( <media-condition> ) | <media-feature> |
<general-enclosed>
- * <general-enclosed> = [ <function-token> <any-value> ) ] | ( <ident>
<any-value> )
*/
//LPAREN -> condition-or-feature
// "not" or LPAREN -> condition
// IDENT | NUMBER | DIMENSION | RATIO -> feature
+ token = parserutils_vector_iterate(vector, ctx);
+ if (token == NULL || tokenIsChar(token, '(') == false) {
+ return CSS_INVALID;
+ }
+
+ consumeWhitespace(vector, ctx);
+
+ token = parserutils_vector_peek(vector, *ctx);
+ if (token == NULL) {
+ return CSS_INVALID;
+ }
+
+ old_ctx = *ctx;
+
+ if (tokenIsChar(token, '(') || (token->type == CSS_TOKEN_IDENT &&
+ lwc_string_caseless_isequal(token->idata,
+ c->strings[NOT], &match) == lwc_error_ok &&
+ match)) {
+ css_mq_cond *cond;
+ error = mq_parse_condition(c, vector, ctx, true, &cond);
+ if (error == CSS_OK) {
+ token = parserutils_vector_iterate(vector, ctx);
+ if (tokenIsChar(token, ')') == false) {
+ return CSS_INVALID;
+ }
+
+ result = malloc(sizeof(*result));
+ if (result == NULL) {
+ /* TODO: clean up cond */
+ return CSS_NOMEM;
+ }
+ memset(result, 0, sizeof(*result));
+ result->type = CSS_MQ_COND;
+ result->data.cond = cond;
+ *cond_or_feature = result;
+ return CSS_OK;
+ }
+ } else if (token->type == CSS_TOKEN_IDENT ||
+ token->type == CSS_TOKEN_NUMBER ||
+ token->type == CSS_TOKEN_DIMENSION) {
+ css_mq_feature *feature;
+ error = mq_parse_media_feature(c, vector, ctx, &feature);
+ if (error == CSS_OK) {
+ result = malloc(sizeof(*result));
+ if (result == NULL) {
+ /* TODO: clean up feature */
+ return CSS_NOMEM;
+ }
+ memset(result, 0, sizeof(*result));
+ result->type = CSS_MQ_FEATURE;
+ result->data.feat = feature;
+ *cond_or_feature = result;
+ return CSS_OK;
+ }
+ }
+
+ *ctx = old_ctx;
+ error = mq_parse_general_enclosed(c, vector, ctx);
+
+ return error;
}
-static css_error mq_parse_condition()
+static css_error mq_parse_condition(css_language *c,
+ const parserutils_vector *vector, int *ctx,
+ bool permit_or, css_mq_cond **cond)
{
+ const css_token *token;
+ bool match;
+ int op = 0; /* Will be AND | OR once we've had one */
+ css_mq_cond_or_feature *cond_or_feature, **parts;
+ css_mq_cond *result;
+ css_error error;
+
/* <media-condition> = <media-not> | <media-in-parens> [ <media-and>* |
<media-or>* ]
* <media-condition-without-or> = <media-not> | <media-in-parens>
<media-and>*
* <media-not> = not <media-in-parens>
* <media-and> = and <media-in-parens>
* <media-or> = or <media-in-parens>
*/
+
+ token = parserutils_vector_peek(vector, *ctx);
+ if (token == NULL || tokenIsChar(token, '(') == false ||
+ token->type != CSS_TOKEN_IDENT ||
+ lwc_string_caseless_isequal(token->idata,
+ c->strings[NOT], &match) != lwc_error_ok ||
+ match == false) {
+ return CSS_INVALID;
+ }
+
+ result = malloc(sizeof(*result));
+ if (result == NULL) {
+ return CSS_NOMEM;
+ }
+ memset(result, 0, sizeof(*result));
+ result->parts = malloc(sizeof(*result->parts));
+ if (result->parts == NULL) {
+ free(result);
+ return CSS_NOMEM;
+ }
+ memset(result->parts, 0, sizeof(*result->parts));
+
+ if (tokenIsChar(token, '(') == false) {
+ /* Must be "not" */
+ parserutils_vector_iterate(vector, ctx);
+ consumeWhitespace(vector, ctx);
+
+ error = mq_parse_media_in_parens(c, vector, ctx,
&cond_or_feature);
+ if (error != CSS_OK) {
+ free(result->parts);
+ free(result);
+ return CSS_INVALID;
+ }
+
+ result->negate = 1;
+ result->parts->nparts = 1;
+ result->parts->parts = malloc(sizeof(*result->parts->parts));
+ if (result->parts->parts == NULL) {
+ /* TODO: clean up cond_or_feature */
+ free(result->parts);
+ free(result);
+ return CSS_NOMEM;
+ }
+ result->parts->parts[0] = cond_or_feature;
+
+ *cond = result;
+
+ return CSS_OK;
+ }
+
+ /* FOLLOW(media-condition) := RPAREN | COMMA | EOF */
+ while (token != NULL && tokenIsChar(token, ')') == false &&
+ tokenIsChar(token, ',') == false) {
+ error = mq_parse_media_in_parens(c, vector, ctx,
&cond_or_feature);
+ if (error != CSS_OK) {
+ /* TODO: clean up result->parts->parts */
+ free(result->parts);
+ free(result);
+ return CSS_INVALID;
+ }
+
+ parts = realloc(result->parts->parts,
+
(result->parts->nparts+1)*sizeof(*result->parts->parts));
+ if (parts == NULL) {
+ /* TODO: clean up result->parts->parts */
+ free(result->parts);
+ free(result);
+ return CSS_NOMEM;
+ }
+ parts[result->parts->nparts] = cond_or_feature;
+ result->parts->parts = parts;
+ result->parts->nparts++;
+
+ consumeWhitespace(vector, token);
+
+ token = parserutils_vector_peek(vector, *ctx);
+ if (token != NULL && tokenIsChar(token, ')') == false &&
+ tokenIsChar(token, ',') == false) {
+ if (token->type != CSS_TOKEN_IDENT) {
+ /* TODO: clean up result->parts->parts */
+ free(result->parts);
+ free(result);
+ return CSS_INVALID;
+ } else if (lwc_string_caseless_isequal(token->idata,
+ c->strings[AND], &match) ==
lwc_error_ok &&
+ match) {
+ if (op != 0 && op != AND) {
+ /* TODO: clean up result->parts->parts
*/
+ free(result->parts);
+ free(result);
+ return CSS_INVALID;
+ }
+ op = AND;
+ } else if (lwc_string_caseless_isequal(token->idata,
+ c->strings[OR], &match) ==
lwc_error_ok &&
+ match) {
+ if (permit_or == false || (op != 0 && op !=
OR)) {
+ /* TODO: clean up result->parts->parts
*/
+ free(result->parts);
+ free(result);
+ return CSS_INVALID;
+ }
+ op = OR;
+ } else {
+ /* Neither AND nor OR */
+ /* TODO: clean up result->parts->parts */
+ free(result->parts);
+ free(result);
+ return CSS_INVALID;
+ }
+
+ parserutils_vector_iterate(vector, ctx);
+ consumeWhitespace(vector, ctx);
+ }
+ }
+
+ if (op == OR) {
+ result->op = 1;
+ }
+
+ *cond = result;
+
+ return CSS_OK;
}
-css_error css__mq_parse_media_list(css_language *c,
+static css_error mq_parse_media_query(css_language *c,
const parserutils_vector *vector, int *ctx,
- css_mq_query **media)
+ css_mq_query **query)
{
- css_mq_query *ret = NULL;
const css_token *token;
+ bool match, is_condition = false;
+ css_mq_query *result;
+ css_error error;
- /* <media-query-list> = <media-query> [ COMMA <media-query> ]*
- * <media-query> = <media-condition>
+ /* <media-query> = <media-condition>
* | [ not | only ]? <media-type> [ and
<media-condition-without-or> ]?
* <media-type> = <ident> (except "not", "and", "or", "only")
- *
*/
+ // LPAREN -> media-condition
+ // not LPAREN -> media-condition
+
+ consumeWhitespace(vector, ctx);
+
+ token = parserutils_vector_peek(vector, *ctx);
+ if (tokenIsChar(token, '(')) {
+ is_condition = true;
+ } else if (token->type == CSS_TOKEN_IDENT &&
+ lwc_string_caseless_isequal(token->idata,
+ c->strings[NOT], &match) == lwc_error_ok &&
+ match) {
+ int old_ctx = *ctx;
+
+ parserutils_vector_iterate(vector, ctx);
+ consumeWhitespace(vector, ctx);
+
+ token = parserutils_vector_peek(vector, *ctx);
+ if (tokenIsChar(token, '(')) {
+ is_condition = true;
+ }
+
+ *ctx = old_ctx;
+ }
+
+ result = malloc(sizeof(*result));
+ if (result == NULL) {
+ return CSS_NOMEM;
+ }
+ memset(result, 0, sizeof(*result));
+
+ if (is_condition) {
+ /* media-condition */
+ error = mq_parse_condition(c, vector, ctx, true, &result->cond);
+ if (error != CSS_OK) {
+ free(result);
+ return error;
+ }
+
+ *query = result;
+ return CSS_OK;
+ }
+
+ token = parserutils_vector_iterate(vector, ctx);
+ if (token == NULL || token->type != CSS_TOKEN_IDENT) {
+ free(result);
+ return CSS_INVALID;
+ }
+
+ if (lwc_string_caseless_isequal(token->idata,
+ c->strings[NOT], &match) == lwc_error_ok &&
+ match) {
+ result->negate_type = 1;
+ consumeWhitespace(vector, ctx);
+ token = parserutils_vector_iterate(vector, ctx);
+ } else if (lwc_string_caseless_isequal(token->idata,
+ c->strings[ONLY], &match) == lwc_error_ok &&
+ match) {
+ consumeWhitespace(vector, ctx);
+ token = parserutils_vector_iterate(vector, ctx);
+ }
+
+ if (token == NULL || token->type != CSS_TOKEN_IDENT) {
+ free(result);
+ return CSS_INVALID;
+ }
+
+ result->type = lwc_string_ref(token->idata);
+
+ consumeWhitespace(vector, ctx);
+
+ token = parserutils_vector_iterate(vector, ctx);
+ if (token != NULL) {
+ if (token->type != CSS_TOKEN_IDENT ||
+ lwc_string_caseless_isequal(token->idata,
+ c->strings[AND], &match) !=
lwc_error_ok ||
+ match == false) {
+ lwc_string_unref(result->type);
+ free(result);
+ return CSS_INVALID;
+ }
+
+ consumeWhitespace(vector, ctx);
+
+ error = mq_parse_condition(c, vector, ctx, false,
&result->cond);
+ if (error != CSS_OK) {
+ lwc_string_unref(result->type);
+ free(result);
+ return error;
+ }
+ }
+
+ *query = result;
+ return CSS_OK;
+}
+
+css_error css__mq_parse_media_list(css_language *c,
+ const parserutils_vector *vector, int *ctx,
+ css_mq_query **media)
+{
+ css_mq_query *result = NULL, *last;
+ const css_token *token;
+ css_error error;
+
+ /* <media-query-list> = <media-query> [ COMMA <media-query> ]* */
+
/* if {[(, push }]) to stack
* if func, push ) to stack
* on error, scan forward until stack is empty (or EOF), popping
matching tokens off stack
@@ -466,78 +785,32 @@ css_error css__mq_parse_media_list(css_language *c,
* if comma, consume, and start again from the next input token
*/
- UNUSED(c);
-
- token = parserutils_vector_iterate(vector, ctx);
-
+ token = parserutils_vector_peek(vector, *ctx);
while (token != NULL) {
- if (token->type != CSS_TOKEN_IDENT)
- return CSS_INVALID;
+ css_mq_query *query;
+
+ error = mq_parse_media_query(c, vector, ctx, &query);
+ if (error != CSS_OK) {
+ /* TODO: error recovery (see above) */
+ } else {
+ if (result == NULL) {
+ result = last = query;
+ } else {
+ last->next = query;
+ last = query;
+ }
+ }
-#if 0
- if (lwc_string_caseless_isequal(token->idata,
c->strings[AURAL],
- &match) == lwc_error_ok && match) {
- ret |= CSS_MEDIA_AURAL;
- } else if (lwc_string_caseless_isequal(
- token->idata, c->strings[BRAILLE],
- &match) == lwc_error_ok && match) {
- ret |= CSS_MEDIA_BRAILLE;
- } else if (lwc_string_caseless_isequal(
- token->idata, c->strings[EMBOSSED],
- &match) == lwc_error_ok && match) {
- ret |= CSS_MEDIA_EMBOSSED;
- } else if (lwc_string_caseless_isequal(
- token->idata, c->strings[HANDHELD],
- &match) == lwc_error_ok && match) {
- ret |= CSS_MEDIA_HANDHELD;
- } else if (lwc_string_caseless_isequal(
- token->idata, c->strings[PRINT],
- &match) == lwc_error_ok && match) {
- ret |= CSS_MEDIA_PRINT;
- } else if (lwc_string_caseless_isequal(
- token->idata, c->strings[PROJECTION],
- &match) == lwc_error_ok && match) {
- ret |= CSS_MEDIA_PROJECTION;
- } else if (lwc_string_caseless_isequal(
- token->idata, c->strings[SCREEN],
- &match) == lwc_error_ok && match) {
- ret |= CSS_MEDIA_SCREEN;
- } else if (lwc_string_caseless_isequal(
- token->idata, c->strings[SPEECH],
- &match) == lwc_error_ok && match) {
- ret |= CSS_MEDIA_SPEECH;
- } else if (lwc_string_caseless_isequal(
- token->idata, c->strings[TTY],
- &match) == lwc_error_ok && match) {
- ret |= CSS_MEDIA_TTY;
- } else if (lwc_string_caseless_isequal(
- token->idata, c->strings[TV],
- &match) == lwc_error_ok && match) {
- ret |= CSS_MEDIA_TV;
- } else if (lwc_string_caseless_isequal(
- token->idata, c->strings[ALL],
- &match) == lwc_error_ok && match) {
- ret |= CSS_MEDIA_ALL;
- } else
- return CSS_INVALID;
-#endif
consumeWhitespace(vector, ctx);
token = parserutils_vector_iterate(vector, ctx);
- if (token != NULL && tokenIsChar(token, ',') == false)
- return CSS_INVALID;
-
- consumeWhitespace(vector, ctx);
+ if (token != NULL && tokenIsChar(token, ',') == false) {
+ /* Give up */
+ break;
+ }
}
-#if 0
- /* If, after parsing the media list, we still have no media,
- * then it must be ALL. */
- if (ret == 0)
- ret = CSS_MEDIA_ALL;
-#endif
-
- *media = ret;
+ *media = result;
return CSS_OK;
}
diff --git a/src/parse/mq.h b/src/parse/mq.h
index c5268c7..ae0110b 100644
--- a/src/parse/mq.h
+++ b/src/parse/mq.h
@@ -73,20 +73,18 @@ struct css_mq_cond_or_feature {
CSS_MQ_COND
} type;
union {
- css_mq_cond cond;
- css_mq_feature feat;
+ css_mq_cond *cond;
+ css_mq_feature *feat;
} data;
};
typedef struct css_mq_query {
struct css_mq_query *next;
- uint32_t negate_type : 1, /* set if "not type" */
- cond_op : 1; /* clear if "and", set if "or" */
+ uint32_t negate_type : 1; /* set if "not type" */
lwc_string *type; /* or NULL */
- uint32_t nconds;
- css_mq_cond **conds;
+ css_mq_cond *cond;
} css_mq_query;
css_error css__mq_parse_media_list(css_language *c,
commitdiff
http://git.netsurf-browser.org/libcss.git/commit/?id=1c867d67f998f647e96408a6aa221ff952c4da50
commit 1c867d67f998f647e96408a6aa221ff952c4da50
Author: John-Mark Bell <[email protected]>
Commit: Michael Drake <[email protected]>
Propstrings: add AND, ONLY, OR
diff --git a/src/parse/propstrings.c b/src/parse/propstrings.c
index bfd2965..dc32ce9 100644
--- a/src/parse/propstrings.c
+++ b/src/parse/propstrings.c
@@ -439,6 +439,9 @@ const stringmap_entry stringmap[LAST_KNOWN] = {
{ "column-reverse", SLEN("column-reverse") },
{ "wrap", SLEN("wrap") },
{ "wrap-reverse", SLEN("wrap-reverse") },
+ { "and", SLEN("and") },
+ { "or", SLEN("or") },
+ { "only", SLEN("only") },
{ "aliceblue", SLEN("aliceblue") },
{ "antiquewhite", SLEN("antiquewhite") },
diff --git a/src/parse/propstrings.h b/src/parse/propstrings.h
index 67eaa5f..0d5d0be 100644
--- a/src/parse/propstrings.h
+++ b/src/parse/propstrings.h
@@ -101,7 +101,7 @@ enum {
AVOID_PAGE, AVOID_COLUMN, BALANCE, HORIZONTAL_TB, VERTICAL_RL,
VERTICAL_LR, CONTENT_BOX, BORDER_BOX, STRETCH, INLINE_FLEX, FLEX_START,
FLEX_END, SPACE_BETWEEN, SPACE_AROUND, SPACE_EVENLY, ROW, ROW_REVERSE,
- COLUMN_REVERSE, WRAP_STRING, WRAP_REVERSE,
+ COLUMN_REVERSE, WRAP_STRING, WRAP_REVERSE, AND, OR, ONLY,
/* Named colours */
FIRST_COLOUR,
commitdiff
http://git.netsurf-browser.org/libcss.git/commit/?id=aa99505f8fb7612162e25f0a0d032d354ee1cd7a
commit aa99505f8fb7612162e25f0a0d032d354ee1cd7a
Author: John-Mark Bell <[email protected]>
Commit: Michael Drake <[email protected]>
Media Queries: parse features
diff --git a/src/parse/mq.c b/src/parse/mq.c
index 5c9c7fa..96f70df 100644
--- a/src/parse/mq.c
+++ b/src/parse/mq.c
@@ -7,7 +7,443 @@
/* https://drafts.csswg.org/mediaqueries/ */
+#include <libcss/fpmath.h>
+
+#include "bytecode/bytecode.h"
#include "parse/mq.h"
+#include "parse/properties/utils.h"
+#include "utils/utils.h"
+
+static css_error mq_parse_ratio(css_language *c,
+ const parserutils_vector *vector, int *ctx,
+ const css_token *numerator, css_fixed *ratio)
+{
+ const css_token *token;
+ css_fixed num, den;
+ size_t num_len, den_len;
+
+ /* NUMBER ws* '/' ws* NUMBER */
+
+ /* numerator, ws* already consumed */
+
+ token = parserutils_vector_iterate(vector, ctx);
+ if (token == NULL || tokenIsChar(token, '/') == false) {
+ return CSS_INVALID;
+ }
+
+ consumeWhitespace(vector, ctx);
+
+ token = parserutils_vector_iterate(vector, ctx);
+ if (token == NULL || token->type != CSS_TOKEN_NUMBER) {
+ return CSS_INVALID;
+ }
+
+ num = css__number_from_lwc_string(numerator->idata, true, &num_len);
+ den = css__number_from_lwc_string(token->idata, true, &den_len);
+
+ *ratio = css_divide_fixed(num, den);
+
+ return CSS_OK;
+}
+
+static css_error mq_create_feature(
+ lwc_string *name,
+ css_mq_feature **feature)
+{
+ css_mq_feature *f;
+
+ f = malloc(sizeof(*f));
+ if (f == NULL) {
+ return CSS_NOMEM;
+ }
+
+ memset(f, 0, sizeof(*f));
+
+ f->name = lwc_string_ref(name);
+
+ *feature = f;
+
+ return CSS_OK;
+}
+
+static css_error mq_populate_value(css_mq_value *value,
+ const css_token *token)
+{
+ if (token->type == CSS_TOKEN_NUMBER) {
+ size_t num_len;
+ value->type = CSS_MQ_VALUE_TYPE_NUM;
+ value->data.num_or_ratio = css__number_from_lwc_string(
+ token->idata, false, &num_len);
+ } else if (token->type == CSS_TOKEN_DIMENSION) {
+ size_t len = lwc_string_length(token->idata);
+ const char *data = lwc_string_data(token->idata);
+ uint32_t unit = UNIT_PX;
+ size_t consumed;
+
+ value->type == CSS_MQ_VALUE_TYPE_DIM;
+ value->data.dim.len = css__number_from_lwc_string(
+ token->idata, false, &consumed);
+ error = css__parse_unit_keyword(data + consumed, len - consumed,
+ &unit);
+ if (error != CSS_OK) {
+ return error;
+ }
+ value->data.dim.unit = temp_unit;
+ } else if (token->type == CSS_TOKEN_IDENT) {
+ value->type = CSS_MQ_VALUE_TYPE_IDENT;
+ value->data.ident = lwc_string_ref(token->idata);
+ }
+
+ return CSS_OK;
+}
+
+static css_error mq_parse_op(const css_token *token,
+ css_mq_feature_op *op)
+{
+ size_t len;
+ const char *data;
+
+ if (token == NULL || token->type != CSS_TOKEN_CHAR)
+ return CSS_INVALID;
+
+ len = lwc_string_length(token->idata);
+ data = lwc_string_data(token->idata);
+
+ if (len == 2) {
+ if (strncasecmp(data, "<=", 2) == 0)
+ *op = CSS_MQ_FEATURE_OP_LTE;
+ else if (strncasecmp(data, ">=", 2) == 0)
+ *op = CSS_MQ_FEATURE_OP_GTE;
+ else
+ return CSS_INVALID;
+ } else if (len == 1) {
+ if (*data == '<')
+ *op = CSS_MQ_FEATURE_OP_LT;
+ else if (*data == '=')
+ *op = CSS_MQ_FEATURE_OP_EQ;
+ else if (*data == '>')
+ *op = CSS_MQ_FEATURE_OP_GT;
+ else
+ return CSS_INVALID;
+ } else {
+ return CSS_INVALID;
+ }
+
+ return CSS_OK;
+}
+
+static css_error mq_parse_range(css_language *c,
+ const parserutils_vector *vector, int *ctx,
+ const css_token *name_or_value,
+ css_mq_feature **feature)
+{
+ const css_token *token, *value_or_name, *name = NULL, *value2 = NULL;
+ css_mq_feature *result;
+ css_mq_feature_op op, op2;
+ css_fixed ratio, ratio2;
+ bool name_first = false, value_is_ratio = false, value2_is_ratio =
false, match;
+ css_error error;
+
+ /* <mf-range> = <mf-name> [ '<' | '>' ]? '='? <mf-value>
+ * | <mf-value> [ '<' | '>' ]? '='? <mf-name>
+ * | <mf-value> '<' '='? <mf-name> '<' '='? <mf-value>
+ * | <mf-value> '>' '='? <mf-name> '>' '='? <mf-value>
+ */
+
+ if (name_or_value == NULL || (name_or_value->type != CSS_TOKEN_NUMBER &&
+ name_or_value->type != CSS_TOKEN_DIMENSION &&
+ name_or_value->type != CSS_TOKEN_IDENT)) {
+ return CSS_INVALID;
+ }
+
+ consumeWhitespace(vector, ctx);
+
+ /* Name-or-value */
+ if (name_or_value->type == CSS_TOKEN_NUMBER &&
+ tokenIsChar(parserutils_vector_peek(vector, *ctx),
'/')) {
+ /* ratio */
+ error = mq_parse_ratio(c, vector, ctx, token, &ratio);
+ if (error != CSS_OK) {
+ return error;
+ }
+
+ consumeWhitespace(vector, ctx);
+
+ value_is_ratio = true;
+ } else if (name_or_value->type == CSS_TOKEN_IDENT &&
+ lwc_string_caseless_isequal(name_or_value->idata,
+ c->strings[INFINITE], &match) == lwc_error_ok
&&
+ match == false) {
+ /* The only ident permitted for mf-value is 'infinite', thus
must have name */
+ name = name_or_value;
+ name_first = true;
+ }
+
+ /* Op */
+ token = parserutils_vector_iterate(vector, ctx);
+ error = mq_parse_op(token, &op);
+ if (error != CSS_OK) {
+ return error;
+ }
+
+ consumeWhitespace(vector, ctx);
+
+ /* Value-or-name */
+ value_or_name = parserutils_vector_iterate(vector, ctx);
+ if (value_or_name == NULL || (value_or_name->type != CSS_TOKEN_NUMBER &&
+ value_or_name->type != CSS_TOKEN_DIMENSION &&
+ value_or_name->type != CSS_TOKEN_IDENT)) {
+ return CSS_INVALID;
+ }
+
+ if (name == NULL) {
+ if (value_or_name->type != CSS_TOKEN_IDENT) {
+ return CSS_INVALID;
+ } else {
+ name = value_or_name;
+ }
+ }
+
+ consumeWhitespace(vector, ctx);
+
+ if (value_or_name->type == CSS_TOKEN_NUMBER &&
+ tokenIsChar(parserutils_vector_peek(vector, *ctx),
'/')) {
+ /* ratio */
+ error = mq_parse_ratio(c, vector, ctx, token, &ratio);
+ if (error != CSS_OK) {
+ return error;
+ }
+
+ consumeWhitespace(vector, ctx);
+
+ value_is_ratio = true;
+ }
+
+ token = parserutils_vector_peek(vector, *ctx);
+ if (name_first == false && token != NULL && tokenIsChar(token, ')') ==
false) {
+ /* Op2 */
+ token = parserutils_vector_iterate(vector, ctx);
+ error = mq_parse_op(token, &op2);
+ if (error != CSS_OK) {
+ return error;
+ }
+
+ consumeWhitespace(vector, ctx);
+
+ /* Validate operators: must both be LT(E) or GT(E) */
+ if (op == CSS_MQ_FEATURE_OP_LT || op == CSS_MQ_FEATURE_OP_LTE) {
+ if (op2 != CSS_MQ_FEATURE_OP_LT && op2 !=
CSS_MQ_FEATURE_OP_LTE) {
+ return CSS_INVALID;
+ }
+ } else if (op == CSS_MQ_FEATURE_OP_GT || op ==
CSS_MQ_FEATURE_OP_GTE) {
+ if (op2 != CSS_MQ_FEATURE_OP_GT && op2 !=
CSS_MQ_FEATURE_OP_GTE) {
+ return CSS_INVALID;
+ }
+ } else {
+ return CSS_INVALID;
+ }
+
+ /* Value2 */
+ value2 = parserutils_vector_iterate(vector, ctx);
+ if (value2 == NULL || (value2->type != CSS_TOKEN_NUMBER &&
+ value2->type != CSS_TOKEN_DIMENSION &&
+ value2->type != CSS_TOKEN_IDENT)) {
+ return CSS_INVALID;
+ }
+
+ consumeWhitespace(vector, ctx);
+
+ if (value_or_name->type == CSS_TOKEN_NUMBER &&
+ tokenIsChar(parserutils_vector_peek(vector,
*ctx), '/')) {
+ /* ratio */
+ error = mq_parse_ratio(c, vector, ctx, token, &ratio2);
+ if (error != CSS_OK) {
+ return error;
+ }
+
+ consumeWhitespace(vector, ctx);
+
+ value2_is_ratio = true;
+ }
+ }
+
+ error = mq_create_feature(name->idata, &result);
+ if (error != CSS_OK) {
+ return error;
+ }
+ if (name_first) {
+ /* Invert operator */
+ if (op == CSS_MQ_FEATURE_OP_LT) {
+ op = CSS_MQ_FEATURE_OP_GTE;
+ } else if (op == CSS_MQ_FEATURE_OP_LTE) {
+ op = CSS_MQ_FEATURE_OP_GT;
+ } else if (op == CSS_MQ_FEATURE_OP_GT) {
+ op = CSS_MQ_FEATURE_OP_LTE;
+ } else if (op == CSS_MQ_FEATURE_OP_GTE) {
+ op = CSS_MQ_FEATURE_OP_LT;
+ }
+ }
+ result->op = op;
+ if (value_is_ratio) {
+ result->value.type = CSS_MQ_VALUE_TYPE_RATIO;
+ result->value.data.num_or_ratio = ratio;
+ } else {
+ /* num/dim/ident */
+ error = mq_populate_value(&result->value, token);
+ if (error != CSS_OK) {
+ free(result);
+ return error;
+ }
+ }
+ if (value2 != NULL) {
+ result->op2 = op2;
+ if (value2_is_ratio) {
+ result->value2.type = CSS_MQ_VALUE_TYPE_RATIO;
+ result->value2.data.num_or_ratio = ratio;
+ } else {
+ /* num/dim/ident */
+ error = mq_populate_value(&result->value2, token);
+ if (error != CSS_OK) {
+ /* TODO: clean up result properly? */
+ free(result);
+ return error;
+ }
+ }
+ }
+
+ *feature = result;
+
+ return CSS_OK;
+}
+
+static css_error mq_parse_media_feature(css_language *c,
+ const parserutils_vector *vector, int *ctx,
+ css_mq_feature **feature)
+{
+ const css_token *name_or_value, *token;
+ css_mq_feature *result;
+ css_error error;
+
+ /* <media-feature> = ( [ <mf-plain> | <mf-boolean> | <mf-range> ] )
+ * <mf-plain> = <mf-name> : <mf-value>
+ * <mf-boolean> = <mf-name>
+ * <mf-name> = <ident>
+ * <mf-value> = <number> | <dimension> | <ident> | <ratio>
+ */
+
+ /* ( already consumed */
+
+ name_or_value = parserutils_vector_iterate(vector, ctx);
+ if (name_or_value == NULL)
+ return CSS_INVALID;
+
+ if (name_or_value->type == CSS_TOKEN_IDENT) {
+ consumeWhitespace(vector, ctx);
+
+ token = parserutils_vector_peek(vector, *ctx);
+ if (tokenIsChar(token, ')')) {
+ /* mf-boolean */
+ error = mq_create_feature(name_or_value->idata,
&result);
+ if (error != CSS_OK) {
+ return error;
+ }
+
+ result->op = CSS_MQ_FEATURE_OP_BOOL;
+ } else if (tokenIsChar(token, ':')) {
+ /* mf-plain */
+ parserutils_vector_iterate(vector, ctx);
+
+ consumeWhitespace(vector, ctx);
+
+ token = parserutils_vector_iterate(vector, ctx);
+ if (token == NULL || (token->type != CSS_TOKEN_NUMBER &&
+ token->type != CSS_TOKEN_DIMENSION &&
+ token->type != CSS_TOKEN_IDENT)) {
+ return CSS_INVALID;
+ }
+
+ consumeWhitespace(vector, ctx);
+
+ error = mq_create_feature(name_or_value->idata,
&result);
+ if (error != CSS_OK) {
+ return error;
+ }
+ result->op = CSS_MQ_FEATURE_OP_EQ;
+
+ if (token->type == CSS_TOKEN_NUMBER &&
+
tokenIsChar(parserutils_vector_peek(vector, *ctx), '/')) {
+ /* ratio */
+ css_fixed ratio;
+
+ error = mq_parse_ratio(c, vector, ctx, token,
&ratio);
+ if (error != CSS_OK) {
+ free(result);
+ return error;
+ }
+
+ result->value.type = CSS_MQ_VALUE_TYPE_RATIO;
+ result->value.data.num_or_ratio = ratio;
+ } else {
+ /* num/dim/ident */
+ error = mq_populate_value(&result->value,
token);
+ if (error != CSS_OK) {
+ free(result);
+ return error;
+ }
+ }
+
+ consumeWhitespace(vector, ctx);
+ } else {
+ /* mf-range */
+ error = mq_parse_range(c, vector, ctx, name_or_value,
&result);
+ if (error != CSS_OK) {
+ return error;
+ }
+
+ consumeWhitespace(vector, ctx);
+ }
+ } else {
+ /* mf-range */
+ error = mq_parse_range(c, vector, ctx, name_or_value, &result);
+ if (error != CSS_OK) {
+ return error;
+ }
+
+ consumeWhitespace(vector, ctx);
+ }
+
+ token = parserutils_vector_iterate(vector, ctx);
+ if (tokenIsChar(token, ')') == false) {
+ /* TODO: clean up result */
+ return CSS_INVALID;
+ }
+
+ *feature = result;
+
+ return CSS_OK;
+}
+
+static css_error mq_parse_media_in_parens()
+{
+ /* <media-in-parens> = ( <media-condition> ) | <media-feature> |
<general-enclosed>
+ * <general-enclosed> = [ <function-token> <any-value> ) ] | ( <ident>
<any-value> )
+ */
+
+ //LPAREN -> condition-or-feature
+ // "not" or LPAREN -> condition
+ // IDENT | NUMBER | DIMENSION | RATIO -> feature
+
+}
+
+static css_error mq_parse_condition()
+{
+ /* <media-condition> = <media-not> | <media-in-parens> [ <media-and>* |
<media-or>* ]
+ * <media-condition-without-or> = <media-not> | <media-in-parens>
<media-and>*
+ * <media-not> = not <media-in-parens>
+ * <media-and> = and <media-in-parens>
+ * <media-or> = or <media-in-parens>
+ */
+}
css_error css__mq_parse_media_list(css_language *c,
const parserutils_vector *vector, int *ctx,
@@ -16,7 +452,19 @@ css_error css__mq_parse_media_list(css_language *c,
css_mq_query *ret = NULL;
const css_token *token;
- /* (IDENT ws (',' ws IDENT ws)* )? */
+ /* <media-query-list> = <media-query> [ COMMA <media-query> ]*
+ * <media-query> = <media-condition>
+ * | [ not | only ]? <media-type> [ and
<media-condition-without-or> ]?
+ * <media-type> = <ident> (except "not", "and", "or", "only")
+ *
+ */
+
+ /* if {[(, push }]) to stack
+ * if func, push ) to stack
+ * on error, scan forward until stack is empty (or EOF), popping
matching tokens off stack
+ * if stack is empty, the next input token must be comma or EOF
+ * if comma, consume, and start again from the next input token
+ */
UNUSED(c);
diff --git a/src/parse/mq.h b/src/parse/mq.h
index 7d62e8c..c5268c7 100644
--- a/src/parse/mq.h
+++ b/src/parse/mq.h
@@ -22,7 +22,7 @@ typedef struct {
css_fixed num_or_ratio; /* Where ratio is the result of a/b */
struct {
css_fixed len;
- css_unit unit;
+ uint32_t unit;
} dim;
lwc_string *ident;
} data;
@@ -31,8 +31,8 @@ typedef struct {
/*
* "name : value" is encoded as "name = value"
* "name" is encoded by setting the operator to "bool"
- * "name op value" is encoded verbatim (with op2 set to "unused")
- * "value op name" inverts the operator to encode (i.e < becomes >=) (and sets
op2 to "unused")
+ * "value op name" is encoded verbatim (with op2 set to "unused")
+ * "name op value" inverts the operator to encode (i.e < becomes >=) (and sets
op2 to "unused")
* "value op name op value" is encoded using op2 and value2
*/
typedef enum {
commitdiff
http://git.netsurf-browser.org/libcss.git/commit/?id=dd272fe8cc3144370e14a69acb5476c7d5568190
commit dd272fe8cc3144370e14a69acb5476c7d5568190
Author: John-Mark Bell <[email protected]>
Commit: Michael Drake <[email protected]>
Units: parse new unit names
diff --git a/src/bytecode/bytecode.h b/src/bytecode/bytecode.h
index 422f141..22703f7 100644
--- a/src/bytecode/bytecode.h
+++ b/src/bytecode/bytecode.h
@@ -52,6 +52,7 @@ typedef enum unit {
UNIT_DEG = (1 << 9) + 0,
UNIT_GRAD = (1 << 9) + 1,
UNIT_RAD = (1 << 9) + 2,
+ UNIT_TURN = (1 << 9) + 3,
UNIT_TIME = (1 << 10),
UNIT_MS = (1 << 10) + 0,
@@ -59,7 +60,12 @@ typedef enum unit {
UNIT_FREQ = (1 << 11),
UNIT_HZ = (1 << 11) + 0,
- UNIT_KHZ = (1 << 11) + 1
+ UNIT_KHZ = (1 << 11) + 1,
+
+ UNIT_RESOLUTION = (1 << 12),
+ UNIT_DPI = (1 << 12) + 0,
+ UNIT_DPCM = (1 << 12) + 1,
+ UNIT_DPPX = (1 << 12) + 2,
} unit;
typedef uint32_t colour;
diff --git a/src/parse/properties/utils.c b/src/parse/properties/utils.c
index 76b406b..f9555d2 100644
--- a/src/parse/properties/utils.c
+++ b/src/parse/properties/utils.c
@@ -1007,6 +1007,12 @@ css_error css__parse_unit_keyword(const char *ptr,
size_t len, uint32_t *unit)
if (len == 4) {
if (strncasecmp(ptr, "grad", 4) == 0)
*unit = UNIT_GRAD;
+ else if (strncasecmp(ptr, "turn", 4) == 0)
+ *unit = UNIT_TURN;
+ else if (strncasecmp(ptr, "dppx", 4) == 0)
+ *unit = UNIT_DPPX;
+ else if (strncasecmp(ptr, "dpcm", 4) == 0)
+ *unit = UNIT_DPCM;
else if (strncasecmp(ptr, "vmin", 4) == 0)
*unit = UNIT_VMIN;
else if (strncasecmp(ptr, "vmax", 4) == 0)
@@ -1026,6 +1032,8 @@ css_error css__parse_unit_keyword(const char *ptr, size_t
len, uint32_t *unit)
*unit = UNIT_REM;
else if (strncasecmp(ptr, "rlh", 3) == 0)
*unit = UNIT_RLH;
+ else if (strncasecmp(ptr, "dpi", 3) == 0)
+ *unit = UNIT_DPI;
else
return CSS_INVALID;
} else if (len == 2) {
commitdiff
http://git.netsurf-browser.org/libcss.git/commit/?id=3c5cf48de6e3a582e20ec2ddfe8f710d351e712c
commit 3c5cf48de6e3a582e20ec2ddfe8f710d351e712c
Author: John-Mark Bell <[email protected]>
Commit: Michael Drake <[email protected]>
Media Queries: sort out object lifetimes
diff --git a/src/parse/language.c b/src/parse/language.c
index a5f57d3..c3b523d 100644
--- a/src/parse/language.c
+++ b/src/parse/language.c
@@ -416,8 +416,7 @@ css_error handleStartAtRule(css_language *c, const
parserutils_vector *vector)
lwc_string *url;
css_mq_query *media = NULL;
- /* any0 = (STRING | URI) ws
- * (media query)? */
+ /* any0 = (STRING | URI) ws (media query)? */
const css_token *uri =
parserutils_vector_iterate(vector, &ctx);
if (uri == NULL || (uri->type != CSS_TOKEN_STRING &&
@@ -435,7 +434,7 @@ css_error handleStartAtRule(css_language *c, const
parserutils_vector *vector)
error = css__stylesheet_rule_create(c->sheet,
CSS_RULE_IMPORT, &rule);
if (error != CSS_OK) {
- css__mq_query_unref(media);
+ css__mq_query_destroy(media);
return error;
}
@@ -444,8 +443,8 @@ css_error handleStartAtRule(css_language *c, const
parserutils_vector *vector)
c->sheet->url,
uri->idata, &url);
if (error != CSS_OK) {
- css__mq_query_unref(media);
css__stylesheet_rule_destroy(c->sheet, rule);
+ css__mq_query_destroy(media);
return error;
}
@@ -454,8 +453,8 @@ css_error handleStartAtRule(css_language *c, const
parserutils_vector *vector)
rule, url, media);
if (error != CSS_OK) {
lwc_string_unref(url);
- css__mq_query_unref(media);
css__stylesheet_rule_destroy(c->sheet, rule);
+ css__mq_query_destroy(media);
return error;
}
@@ -465,16 +464,14 @@ css_error handleStartAtRule(css_language *c, const
parserutils_vector *vector)
c->sheet, url);
if (error != CSS_OK) {
lwc_string_unref(url);
- css__mq_query_unref(media);
css__stylesheet_rule_destroy(c->sheet,
rule);
return error;
}
}
- /* No longer care about url or media */
+ /* No longer care about url */
lwc_string_unref(url);
- css__mq_query_unref(media);
/* Add rule to sheet */
error = css__stylesheet_add_rule(c->sheet, rule, NULL);
@@ -542,26 +539,23 @@ css_error handleStartAtRule(css_language *c, const
parserutils_vector *vector)
error = css__stylesheet_rule_create(c->sheet,
CSS_RULE_MEDIA, &rule);
if (error != CSS_OK) {
- css__mq_query_unref(media);
+ css__mq_query_destroy(media);
return error;
}
error = css__stylesheet_rule_set_media(c->sheet, rule, media);
if (error != CSS_OK) {
css__stylesheet_rule_destroy(c->sheet, rule);
- css__mq_query_unref(media);
+ css__mq_query_destroy(media);
return error;
}
error = css__stylesheet_add_rule(c->sheet, rule, NULL);
if (error != CSS_OK) {
css__stylesheet_rule_destroy(c->sheet, rule);
- css__mq_query_unref(media);
return error;
}
- css__mq_query_unref(media);
-
/* Rule is now owned by the sheet,
* so no need to destroy it */
diff --git a/src/parse/mq.h b/src/parse/mq.h
index eeb55da..7d62e8c 100644
--- a/src/parse/mq.h
+++ b/src/parse/mq.h
@@ -93,8 +93,6 @@ css_error css__mq_parse_media_list(css_language *c,
const parserutils_vector *vector, int *ctx,
css_mq_query **media);
-/** \todo is this necessary? */
-css_mq_query *css__mq_query_ref(css_mq_query *media);
-css_mq_query *css__mq_query_unref(css_mq_query *media);
+css_mq_query *css__mq_query_destroy(css_mq_query *media);
#endif
diff --git a/src/stylesheet.c b/src/stylesheet.c
index b1801ed..22c7681 100644
--- a/src/stylesheet.c
+++ b/src/stylesheet.c
@@ -12,6 +12,7 @@
#include "stylesheet.h"
#include "bytecode/bytecode.h"
#include "parse/language.h"
+#include "parse/mq.h"
#include "utils/parserutilserror.h"
#include "utils/utils.h"
#include "select/dispatch.h"
@@ -1151,6 +1152,9 @@ css_error css__stylesheet_rule_destroy(css_stylesheet
*sheet, css_rule *rule)
css_rule_import *import = (css_rule_import *) rule;
lwc_string_unref(import->url);
+ if (import->media != NULL) {
+ css__mq_query_destroy(import->media);
+ }
/* Do not destroy imported sheet: it is owned by the client */
}
@@ -1160,6 +1164,10 @@ css_error css__stylesheet_rule_destroy(css_stylesheet
*sheet, css_rule *rule)
css_rule_media *media = (css_rule_media *) rule;
css_rule *c, *d;
+ if (media->media != NULL) {
+ css__mq_query_destroy(media->media);
+ }
+
for (c = media->first_child; c != NULL; c = d) {
d = c->next;
@@ -1335,7 +1343,7 @@ css_error
css__stylesheet_rule_set_nascent_import(css_stylesheet *sheet,
/* Set the rule's sheet field */
r->url = lwc_string_ref(url);
- r->media = css__mq_query_ref(media);
+ r->media = media;
return CSS_OK;
}
@@ -1360,7 +1368,7 @@ css_error css__stylesheet_rule_set_media(css_stylesheet
*sheet,
assert(rule->type == CSS_RULE_MEDIA);
/* Set the rule's media */
- r->media = css__mq_query_ref(media);
+ r->media = media;
return CSS_OK;
}
commitdiff
http://git.netsurf-browser.org/libcss.git/commit/?id=1ab22bb288f76db50bf68357d0b630554e7c7bcc
commit 1ab22bb288f76db50bf68357d0b630554e7c7bcc
Author: John-Mark Bell <[email protected]>
Commit: Michael Drake <[email protected]>
Media Queries: datastructures and plumbing.
No parse implementation as yet.
Selection hasn't been updated, either. One item of note
in that area is that a client currently provides the
media for top-level sheets being added to a selection
context. This probably needs to change to providing a
lwc_string containing the verbatim media query from
the containing document's import mechanism. That way,
the internal representation of media queries can remain
opaque to clients.
diff --git a/include/libcss/stylesheet.h b/include/libcss/stylesheet.h
index 68c4dfc..542f199 100644
--- a/include/libcss/stylesheet.h
+++ b/include/libcss/stylesheet.h
@@ -36,7 +36,6 @@ typedef css_error (*css_url_resolution_fn)(void *pw,
* \param pw Client data
* \param parent Stylesheet requesting the import
* \param url URL of the imported sheet
- * \param media Applicable media for the imported sheet
* \return CSS_OK on success, appropriate error otherwise
*
* \note This function will be invoked for notification purposes
@@ -46,7 +45,7 @@ typedef css_error (*css_url_resolution_fn)(void *pw,
* registration API.
*/
typedef css_error (*css_import_notification_fn)(void *pw,
- css_stylesheet *parent, lwc_string *url, uint64_t media);
+ css_stylesheet *parent, lwc_string *url);
/**
* Callback use to resolve system colour names to RGB values
@@ -145,7 +144,7 @@ css_error css_stylesheet_append_data(css_stylesheet *sheet,
css_error css_stylesheet_data_done(css_stylesheet *sheet);
css_error css_stylesheet_next_pending_import(css_stylesheet *parent,
- lwc_string **url, uint64_t *media);
+ lwc_string **url);
css_error css_stylesheet_register_import(css_stylesheet *parent,
css_stylesheet *child);
diff --git a/src/parse/Makefile b/src/parse/Makefile
index 99f55d0..6d11096 100644
--- a/src/parse/Makefile
+++ b/src/parse/Makefile
@@ -1,4 +1,4 @@
# Sources
-DIR_SOURCES := parse.c language.c important.c propstrings.c font_face.c
+DIR_SOURCES := parse.c language.c important.c propstrings.c font_face.c mq.c
include $(NSBUILD)/Makefile.subdir
diff --git a/src/parse/language.c b/src/parse/language.c
index 9af2547..a5f57d3 100644
--- a/src/parse/language.c
+++ b/src/parse/language.c
@@ -15,6 +15,7 @@
#include "parse/font_face.h"
#include "parse/important.h"
#include "parse/language.h"
+#include "parse/mq.h"
#include "parse/parse.h"
#include "parse/propstrings.h"
#include "parse/properties/properties.h"
@@ -53,9 +54,6 @@ static css_error handleDeclaration(css_language *c,
const parserutils_vector *vector);
/* At-rule parsing */
-static css_error parseMediaList(css_language *c,
- const parserutils_vector *vector, int *ctx,
- uint64_t *media);
static css_error addNamespace(css_language *c,
lwc_string *prefix, lwc_string *uri);
static css_error lookupNamespace(css_language *c,
@@ -416,10 +414,10 @@ css_error handleStartAtRule(css_language *c, const
parserutils_vector *vector)
match) {
if (c->state <= IMPORT_PERMITTED) {
lwc_string *url;
- uint64_t media = 0;
+ css_mq_query *media = NULL;
/* any0 = (STRING | URI) ws
- * (IDENT ws (',' ws IDENT ws)* )? */
+ * (media query)? */
const css_token *uri =
parserutils_vector_iterate(vector, &ctx);
if (uri == NULL || (uri->type != CSS_TOKEN_STRING &&
@@ -429,21 +427,24 @@ css_error handleStartAtRule(css_language *c, const
parserutils_vector *vector)
consumeWhitespace(vector, &ctx);
/* Parse media list */
- error = parseMediaList(c, vector, &ctx, &media);
+ error = css__mq_parse_media_list(c, vector, &ctx,
&media);
if (error != CSS_OK)
return error;
/* Create rule */
error = css__stylesheet_rule_create(c->sheet,
CSS_RULE_IMPORT, &rule);
- if (error != CSS_OK)
+ if (error != CSS_OK) {
+ css__mq_query_unref(media);
return error;
+ }
/* Resolve import URI */
error = c->sheet->resolve(c->sheet->resolve_pw,
c->sheet->url,
uri->idata, &url);
if (error != CSS_OK) {
+ css__mq_query_unref(media);
css__stylesheet_rule_destroy(c->sheet, rule);
return error;
}
@@ -453,6 +454,7 @@ css_error handleStartAtRule(css_language *c, const
parserutils_vector *vector)
rule, url, media);
if (error != CSS_OK) {
lwc_string_unref(url);
+ css__mq_query_unref(media);
css__stylesheet_rule_destroy(c->sheet, rule);
return error;
}
@@ -460,17 +462,19 @@ css_error handleStartAtRule(css_language *c, const
parserutils_vector *vector)
/* Inform client of need for import */
if (c->sheet->import != NULL) {
error = c->sheet->import(c->sheet->import_pw,
- c->sheet, url, media);
+ c->sheet, url);
if (error != CSS_OK) {
lwc_string_unref(url);
+ css__mq_query_unref(media);
css__stylesheet_rule_destroy(c->sheet,
rule);
return error;
}
}
- /* No longer care about url */
+ /* No longer care about url or media */
lwc_string_unref(url);
+ css__mq_query_unref(media);
/* Add rule to sheet */
error = css__stylesheet_add_rule(c->sheet, rule, NULL);
@@ -527,31 +531,37 @@ css_error handleStartAtRule(css_language *c, const
parserutils_vector *vector)
}
} else if (lwc_string_caseless_isequal(atkeyword->idata,
c->strings[MEDIA],
&match) == lwc_error_ok && match) {
- uint64_t media = 0;
+ css_mq_query *media = NULL;
- /* any0 = IDENT ws (',' ws IDENT ws)* */
+ /* any0 = media query */
- error = parseMediaList(c, vector, &ctx, &media);
+ error = css__mq_parse_media_list(c, vector, &ctx, &media);
if (error != CSS_OK)
return error;
error = css__stylesheet_rule_create(c->sheet,
CSS_RULE_MEDIA, &rule);
- if (error != CSS_OK)
+ if (error != CSS_OK) {
+ css__mq_query_unref(media);
return error;
+ }
error = css__stylesheet_rule_set_media(c->sheet, rule, media);
if (error != CSS_OK) {
css__stylesheet_rule_destroy(c->sheet, rule);
+ css__mq_query_unref(media);
return error;
}
error = css__stylesheet_add_rule(c->sheet, rule, NULL);
if (error != CSS_OK) {
css__stylesheet_rule_destroy(c->sheet, rule);
+ css__mq_query_unref(media);
return error;
}
+ css__mq_query_unref(media);
+
/* Rule is now owned by the sheet,
* so no need to destroy it */
@@ -795,85 +805,6 @@ css_error handleDeclaration(css_language *c, const
parserutils_vector *vector)
* At-rule parsing functions *
******************************************************************************/
-css_error parseMediaList(css_language *c,
- const parserutils_vector *vector, int *ctx,
- uint64_t *media)
-{
- uint64_t ret = 0;
- bool match = false;
- const css_token *token;
-
- token = parserutils_vector_iterate(vector, ctx);
-
- while (token != NULL) {
- if (token->type != CSS_TOKEN_IDENT)
- return CSS_INVALID;
-
- if (lwc_string_caseless_isequal(token->idata, c->strings[AURAL],
- &match) == lwc_error_ok && match) {
- ret |= CSS_MEDIA_AURAL;
- } else if (lwc_string_caseless_isequal(
- token->idata, c->strings[BRAILLE],
- &match) == lwc_error_ok && match) {
- ret |= CSS_MEDIA_BRAILLE;
- } else if (lwc_string_caseless_isequal(
- token->idata, c->strings[EMBOSSED],
- &match) == lwc_error_ok && match) {
- ret |= CSS_MEDIA_EMBOSSED;
- } else if (lwc_string_caseless_isequal(
- token->idata, c->strings[HANDHELD],
- &match) == lwc_error_ok && match) {
- ret |= CSS_MEDIA_HANDHELD;
- } else if (lwc_string_caseless_isequal(
- token->idata, c->strings[PRINT],
- &match) == lwc_error_ok && match) {
- ret |= CSS_MEDIA_PRINT;
- } else if (lwc_string_caseless_isequal(
- token->idata, c->strings[PROJECTION],
- &match) == lwc_error_ok && match) {
- ret |= CSS_MEDIA_PROJECTION;
- } else if (lwc_string_caseless_isequal(
- token->idata, c->strings[SCREEN],
- &match) == lwc_error_ok && match) {
- ret |= CSS_MEDIA_SCREEN;
- } else if (lwc_string_caseless_isequal(
- token->idata, c->strings[SPEECH],
- &match) == lwc_error_ok && match) {
- ret |= CSS_MEDIA_SPEECH;
- } else if (lwc_string_caseless_isequal(
- token->idata, c->strings[TTY],
- &match) == lwc_error_ok && match) {
- ret |= CSS_MEDIA_TTY;
- } else if (lwc_string_caseless_isequal(
- token->idata, c->strings[TV],
- &match) == lwc_error_ok && match) {
- ret |= CSS_MEDIA_TV;
- } else if (lwc_string_caseless_isequal(
- token->idata, c->strings[ALL],
- &match) == lwc_error_ok && match) {
- ret |= CSS_MEDIA_ALL;
- } else
- return CSS_INVALID;
-
- consumeWhitespace(vector, ctx);
-
- token = parserutils_vector_iterate(vector, ctx);
- if (token != NULL && tokenIsChar(token, ',') == false)
- return CSS_INVALID;
-
- consumeWhitespace(vector, ctx);
- }
-
- /* If, after parsing the media list, we still have no media,
- * then it must be ALL. */
- if (ret == 0)
- ret = CSS_MEDIA_ALL;
-
- *media = ret;
-
- return CSS_OK;
-}
-
/**
* Add a namespace mapping
*
diff --git a/src/parse/mq.c b/src/parse/mq.c
new file mode 100644
index 0000000..5c9c7fa
--- /dev/null
+++ b/src/parse/mq.c
@@ -0,0 +1,96 @@
+/*
+ * This file is part of LibCSS.
+ * Licensed under the MIT License,
+ * http://www.opensource.org/licenses/mit-license.php
+ * Copyright 2016 John-Mark Bell <[email protected]>
+ */
+
+/* https://drafts.csswg.org/mediaqueries/ */
+
+#include "parse/mq.h"
+
+css_error css__mq_parse_media_list(css_language *c,
+ const parserutils_vector *vector, int *ctx,
+ css_mq_query **media)
+{
+ css_mq_query *ret = NULL;
+ const css_token *token;
+
+ /* (IDENT ws (',' ws IDENT ws)* )? */
+
+ UNUSED(c);
+
+ token = parserutils_vector_iterate(vector, ctx);
+
+ while (token != NULL) {
+ if (token->type != CSS_TOKEN_IDENT)
+ return CSS_INVALID;
+
+#if 0
+ if (lwc_string_caseless_isequal(token->idata,
c->strings[AURAL],
+ &match) == lwc_error_ok && match) {
+ ret |= CSS_MEDIA_AURAL;
+ } else if (lwc_string_caseless_isequal(
+ token->idata, c->strings[BRAILLE],
+ &match) == lwc_error_ok && match) {
+ ret |= CSS_MEDIA_BRAILLE;
+ } else if (lwc_string_caseless_isequal(
+ token->idata, c->strings[EMBOSSED],
+ &match) == lwc_error_ok && match) {
+ ret |= CSS_MEDIA_EMBOSSED;
+ } else if (lwc_string_caseless_isequal(
+ token->idata, c->strings[HANDHELD],
+ &match) == lwc_error_ok && match) {
+ ret |= CSS_MEDIA_HANDHELD;
+ } else if (lwc_string_caseless_isequal(
+ token->idata, c->strings[PRINT],
+ &match) == lwc_error_ok && match) {
+ ret |= CSS_MEDIA_PRINT;
+ } else if (lwc_string_caseless_isequal(
+ token->idata, c->strings[PROJECTION],
+ &match) == lwc_error_ok && match) {
+ ret |= CSS_MEDIA_PROJECTION;
+ } else if (lwc_string_caseless_isequal(
+ token->idata, c->strings[SCREEN],
+ &match) == lwc_error_ok && match) {
+ ret |= CSS_MEDIA_SCREEN;
+ } else if (lwc_string_caseless_isequal(
+ token->idata, c->strings[SPEECH],
+ &match) == lwc_error_ok && match) {
+ ret |= CSS_MEDIA_SPEECH;
+ } else if (lwc_string_caseless_isequal(
+ token->idata, c->strings[TTY],
+ &match) == lwc_error_ok && match) {
+ ret |= CSS_MEDIA_TTY;
+ } else if (lwc_string_caseless_isequal(
+ token->idata, c->strings[TV],
+ &match) == lwc_error_ok && match) {
+ ret |= CSS_MEDIA_TV;
+ } else if (lwc_string_caseless_isequal(
+ token->idata, c->strings[ALL],
+ &match) == lwc_error_ok && match) {
+ ret |= CSS_MEDIA_ALL;
+ } else
+ return CSS_INVALID;
+#endif
+ consumeWhitespace(vector, ctx);
+
+ token = parserutils_vector_iterate(vector, ctx);
+ if (token != NULL && tokenIsChar(token, ',') == false)
+ return CSS_INVALID;
+
+ consumeWhitespace(vector, ctx);
+ }
+
+#if 0
+ /* If, after parsing the media list, we still have no media,
+ * then it must be ALL. */
+ if (ret == 0)
+ ret = CSS_MEDIA_ALL;
+#endif
+
+ *media = ret;
+
+ return CSS_OK;
+}
+
diff --git a/src/parse/mq.h b/src/parse/mq.h
new file mode 100644
index 0000000..eeb55da
--- /dev/null
+++ b/src/parse/mq.h
@@ -0,0 +1,100 @@
+/*
+ * This file is part of LibCSS.
+ * Licensed under the MIT License,
+ * http://www.opensource.org/licenses/mit-license.php
+ * Copyright 2016 John-Mark Bell <[email protected]>
+ */
+
+#ifndef css_parse_mq_h_
+#define css_parse_mq_h_
+
+#include <parserutils/utils/vector.h>
+#include "parse/language.h"
+
+typedef struct {
+ enum {
+ CSS_MQ_VALUE_TYPE_NUM,
+ CSS_MQ_VALUE_TYPE_DIM,
+ CSS_MQ_VALUE_TYPE_IDENT,
+ CSS_MQ_VALUE_TYPE_RATIO
+ } type;
+ union {
+ css_fixed num_or_ratio; /* Where ratio is the result of a/b */
+ struct {
+ css_fixed len;
+ css_unit unit;
+ } dim;
+ lwc_string *ident;
+ } data;
+} css_mq_value;
+
+/*
+ * "name : value" is encoded as "name = value"
+ * "name" is encoded by setting the operator to "bool"
+ * "name op value" is encoded verbatim (with op2 set to "unused")
+ * "value op name" inverts the operator to encode (i.e < becomes >=) (and sets
op2 to "unused")
+ * "value op name op value" is encoded using op2 and value2
+ */
+typedef enum {
+ CSS_MQ_FEATURE_OP_BOOL, /* op only */
+ CSS_MQ_FEATURE_OP_UNUSED = CSS_MQ_FEATURE_OP_BOOL, /* op2 only */
+
+ CSS_MQ_FEATURE_OP_LT,
+ CSS_MQ_FEATURE_OP_LTE,
+ CSS_MQ_FEATURE_OP_EQ, /* op only */
+ CSS_MQ_FEATURE_OP_GTE,
+ CSS_MQ_FEATURE_OP_GT
+} css_mq_feature_op;
+
+typedef struct {
+ lwc_string *name;
+ css_mq_feature_op op;
+ css_mq_feature_op op2;
+ css_mq_value value;
+ css_mq_value value2;
+} css_mq_feature;
+
+typedef struct css_mq_cond_or_feature css_mq_cond_or_feature;
+
+typedef struct {
+ uint32_t nparts;
+ css_mq_cond_or_feature **parts;
+} css_mq_cond_parts;
+
+typedef struct {
+ uint32_t negate : 1, /* set if "not" */
+ op : 1; /* clear if "and", set if "or" */
+ css_mq_cond_parts *parts;
+} css_mq_cond;
+
+struct css_mq_cond_or_feature {
+ enum {
+ CSS_MQ_FEATURE,
+ CSS_MQ_COND
+ } type;
+ union {
+ css_mq_cond cond;
+ css_mq_feature feat;
+ } data;
+};
+
+typedef struct css_mq_query {
+ struct css_mq_query *next;
+
+ uint32_t negate_type : 1, /* set if "not type" */
+ cond_op : 1; /* clear if "and", set if "or" */
+ lwc_string *type; /* or NULL */
+
+ uint32_t nconds;
+ css_mq_cond **conds;
+} css_mq_query;
+
+css_error css__mq_parse_media_list(css_language *c,
+ const parserutils_vector *vector, int *ctx,
+ css_mq_query **media);
+
+/** \todo is this necessary? */
+css_mq_query *css__mq_query_ref(css_mq_query *media);
+css_mq_query *css__mq_query_unref(css_mq_query *media);
+
+#endif
diff --git a/src/stylesheet.c b/src/stylesheet.c
index 7c6728b..b1801ed 100644
--- a/src/stylesheet.c
+++ b/src/stylesheet.c
@@ -377,8 +377,6 @@ css_error css_stylesheet_data_done(css_stylesheet *sheet)
* \param parent Parent stylesheet
* \param url Pointer to object to be populated with details of URL of
* imported stylesheet (potentially relative)
- * \param media Pointer to location to receive applicable media types
for
- * imported sheet,
* \return CSS_OK on success,
* CSS_INVALID if there are no pending imports remaining
*
@@ -396,11 +394,11 @@ css_error css_stylesheet_data_done(css_stylesheet *sheet)
* register an empty stylesheet with the parent in its place.
*/
css_error css_stylesheet_next_pending_import(css_stylesheet *parent,
- lwc_string **url, uint64_t *media)
+ lwc_string **url)
{
const css_rule *r;
- if (parent == NULL || url == NULL || media == NULL)
+ if (parent == NULL || url == NULL)
return CSS_BADPARM;
for (r = parent->rule_list; r != NULL; r = r->next) {
@@ -413,7 +411,6 @@ css_error css_stylesheet_next_pending_import(css_stylesheet
*parent,
if (r->type == CSS_RULE_IMPORT && i->sheet == NULL) {
*url = lwc_string_ref(i->url);
- *media = i->media;
return CSS_OK;
}
@@ -1326,7 +1323,7 @@ css_error css__stylesheet_rule_set_charset(css_stylesheet
*sheet,
*/
css_error css__stylesheet_rule_set_nascent_import(css_stylesheet *sheet,
css_rule *rule, lwc_string *url,
- uint64_t media)
+ css_mq_query *media)
{
css_rule_import *r = (css_rule_import *) rule;
@@ -1338,7 +1335,7 @@ css_error
css__stylesheet_rule_set_nascent_import(css_stylesheet *sheet,
/* Set the rule's sheet field */
r->url = lwc_string_ref(url);
- r->media = media;
+ r->media = css__mq_query_ref(media);
return CSS_OK;
}
@@ -1352,7 +1349,7 @@ css_error
css__stylesheet_rule_set_nascent_import(css_stylesheet *sheet,
* \return CSS_OK on success, appropriate error otherwise
*/
css_error css__stylesheet_rule_set_media(css_stylesheet *sheet,
- css_rule *rule, uint64_t media)
+ css_rule *rule, css_mq_query *media)
{
css_rule_media *r = (css_rule_media *) rule;
@@ -1363,7 +1360,7 @@ css_error css__stylesheet_rule_set_media(css_stylesheet
*sheet,
assert(rule->type == CSS_RULE_MEDIA);
/* Set the rule's media */
- r->media = media;
+ r->media = css__mq_query_ref(media);
return CSS_OK;
}
diff --git a/src/stylesheet.h b/src/stylesheet.h
index 18e077e..a44ad1f 100644
--- a/src/stylesheet.h
+++ b/src/stylesheet.h
@@ -20,6 +20,7 @@
#include "bytecode/bytecode.h"
#include "parse/parse.h"
+#include "parse/mq.h"
#include "select/hash.h"
typedef struct css_rule css_rule;
@@ -132,7 +133,7 @@ typedef struct css_rule_selector {
typedef struct css_rule_media {
css_rule base;
- uint64_t media;
+ css_mq_query *media;
css_rule *first_child;
css_rule *last_child;
@@ -155,7 +156,7 @@ typedef struct css_rule_import {
css_rule base;
lwc_string *url;
- uint64_t media;
+ css_mq_query *media;
css_stylesheet *sheet;
} css_rule_import;
@@ -268,10 +269,10 @@ css_error css__stylesheet_rule_set_charset(css_stylesheet
*sheet,
css_rule *rule, lwc_string *charset);
css_error css__stylesheet_rule_set_nascent_import(css_stylesheet *sheet,
- css_rule *rule, lwc_string *url, uint64_t media);
+ css_rule *rule, lwc_string *url, css_mq_query *media);
css_error css__stylesheet_rule_set_media(css_stylesheet *sheet,
- css_rule *rule, uint64_t media);
+ css_rule *rule, css_mq_query *media);
css_error css__stylesheet_rule_set_page_selector(css_stylesheet *sheet,
css_rule *rule, css_selector *sel);
-----------------------------------------------------------------------
--
Cascading Style Sheets library
_______________________________________________
netsurf-commits mailing list
[email protected]
http://listmaster.pepperfish.net/cgi-bin/mailman/listinfo/netsurf-commits-netsurf-browser.org