summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJohn-Mark Bell <jmb@netsurf-browser.org>2016-11-20 13:10:02 (GMT)
committer John-Mark Bell <jmb@netsurf-browser.org>2016-11-20 13:24:48 (GMT)
commit3634123921fdff383e1ed62f62f1aaf1e71134f5 (patch)
tree1e3084589e4575a759209f75191b67fc905f9daa
parentd986c1c356aba25bdf0b977133b387fbdad5aa90 (diff)
downloadlibcss-3634123921fdff383e1ed62f62f1aaf1e71134f5.tar.gz
libcss-3634123921fdff383e1ed62f62f1aaf1e71134f5.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.
-rw-r--r--include/libcss/stylesheet.h5
-rw-r--r--src/parse/Makefile2
-rw-r--r--src/parse/language.c115
-rw-r--r--src/parse/mq.c96
-rw-r--r--src/parse/mq.h100
-rw-r--r--src/stylesheet.c15
-rw-r--r--src/stylesheet.h9
7 files changed, 233 insertions, 109 deletions
diff --git a/include/libcss/stylesheet.h b/include/libcss/stylesheet.h
index f92d870..f7032da 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 11e2b2f..68055e1 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
--- a/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
--- a/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
diff --git a/src/stylesheet.c b/src/stylesheet.c
index 0a281e7..63f958b 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 a2b3fd5..838b228 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);