diff options
author | John-Mark Bell <jmb@netsurf-browser.org> | 2016-11-20 13:10:02 +0000 |
---|---|---|
committer | Michael Drake <tlsa@netsurf-browser.org> | 2018-07-28 15:27:12 +0100 |
commit | 22e3c1d0ef62df247b1d39c36d9ecb9f04f7512b (patch) | |
tree | e3009869350b06b5beeac25dd9327f3dc705944d /src/parse | |
parent | 2f7718d8de04be49dead46665489585cc2a323cb (diff) | |
download | libcss-22e3c1d0ef62df247b1d39c36d9ecb9f04f7512b.tar.gz libcss-22e3c1d0ef62df247b1d39c36d9ecb9f04f7512b.tar.bz2 |
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.
Diffstat (limited to 'src/parse')
-rw-r--r-- | src/parse/Makefile | 2 | ||||
-rw-r--r-- | src/parse/language.c | 115 | ||||
-rw-r--r-- | src/parse/mq.c | 96 | ||||
-rw-r--r-- | src/parse/mq.h | 100 |
4 files changed, 220 insertions, 93 deletions
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 <jmb@netsurf-browser.org> + */ + +/* 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 <jmb@netsurf-browser.org> + */ + +#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 |