[gtk+/wip/otte/tokenizer: 25/78] css: Add token parser for ease values
- From: Benjamin Otte <otte src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gtk+/wip/otte/tokenizer: 25/78] css: Add token parser for ease values
- Date: Fri, 25 Nov 2016 22:39:45 +0000 (UTC)
commit fae4a1417731f01775d98e0384ff1d650000f2e4
Author: Benjamin Otte <otte redhat com>
Date: Thu Mar 17 21:57:08 2016 +0100
css: Add token parser for ease values
Also add a parser for functions to the token source.
gtk/gtkcsseasevalue.c | 133 ++++++++++++++++++++++++++++++++++++++++
gtk/gtkcsseasevalueprivate.h | 2 +
gtk/gtkcssstylepropertyimpl.c | 11 +++-
gtk/gtkcsstokensource.c | 70 +++++++++++++++++++++
gtk/gtkcsstokensourceprivate.h | 6 ++
5 files changed, 220 insertions(+), 2 deletions(-)
---
diff --git a/gtk/gtkcsseasevalue.c b/gtk/gtkcsseasevalue.c
index e2faef0..ebf6264 100644
--- a/gtk/gtkcsseasevalue.c
+++ b/gtk/gtkcsseasevalue.c
@@ -327,6 +327,139 @@ _gtk_css_ease_value_parse (GtkCssParser *parser)
return NULL;
}
+static gboolean
+token_parse_cubic_bezier (GtkCssTokenSource *source,
+ guint n,
+ gpointer data)
+{
+ double *numbers = data;
+ const GtkCssToken *token;
+
+ token = gtk_css_token_source_get_token (source);
+ if (gtk_css_token_is (token, GTK_CSS_TOKEN_INTEGER) ||
+ gtk_css_token_is (token, GTK_CSS_TOKEN_NUMBER))
+ {
+ numbers[n] = token->number.number;
+ if (n % 2 == 0 &&
+ (numbers[n] < 0 || numbers[n] > 1.0))
+ {
+ gtk_css_token_source_error (source, "Value %g out of range. Must be from 0.0 to 1.0", numbers[n]);
+ return FALSE;
+ }
+ gtk_css_token_source_consume_token (source);
+ return TRUE;
+ }
+ else
+ {
+ gtk_css_token_source_error (source, "Expected a number");
+ gtk_css_token_source_consume_all (source);
+ return FALSE;
+ }
+}
+
+static gboolean
+token_parse_steps (GtkCssTokenSource *source,
+ guint nth_argument,
+ gpointer data)
+{
+ GtkCssValue *value = data;
+ const GtkCssToken *token;
+
+ token = gtk_css_token_source_get_token (source);
+ if (nth_argument == 0)
+ {
+ if (!gtk_css_token_is (token, GTK_CSS_TOKEN_INTEGER))
+ {
+ gtk_css_token_source_error (source, "Expected a positive integer for number of steps");
+ gtk_css_token_source_consume_all (source);
+ return FALSE;
+ }
+ else if (token->number.number <= 0)
+ {
+ gtk_css_token_source_error (source, "Number of steps must be greater than 0");
+ gtk_css_token_source_consume_all (source);
+ return FALSE;
+ }
+ value->u.steps.steps = token->number.number;
+ gtk_css_token_source_consume_token (source);
+ return TRUE;
+ }
+ else
+ {
+ if (gtk_css_token_is_ident (token, "start"))
+ value->u.steps.start = TRUE;
+ else if (gtk_css_token_is_ident (token, "end"))
+ value->u.steps.start = FALSE;
+ else
+ {
+ gtk_css_token_source_error (source, "Only allowed values are 'start' and 'end'");
+ gtk_css_token_source_consume_all (source);
+ return FALSE;
+ }
+ gtk_css_token_source_consume_token (source);
+ return TRUE;
+ }
+}
+
+GtkCssValue *
+gtk_css_ease_value_token_parse (GtkCssTokenSource *source)
+{
+ const GtkCssToken *token;
+ guint i;
+
+ token = gtk_css_token_source_get_token (source);
+ for (i = 0; i < G_N_ELEMENTS (parser_values); i++)
+ {
+ if (parser_values[i].needs_custom)
+ continue;
+
+ if (gtk_css_token_is_ident (token, parser_values[i].name))
+ {
+ gtk_css_token_source_consume_token (source);
+
+ if (parser_values[i].is_bezier)
+ return _gtk_css_ease_value_new_cubic_bezier (parser_values[i].values[0],
+ parser_values[i].values[1],
+ parser_values[i].values[2],
+ parser_values[i].values[3]);
+ else
+ return _gtk_css_ease_value_new_steps (parser_values[i].values[0],
+ parser_values[i].values[1] != 0.0);
+ }
+ }
+
+ if (gtk_css_token_is_function (token, "cubic-bezier"))
+ {
+ double numbers[4];
+
+ if (!gtk_css_token_source_consume_function (source, 4, 4, token_parse_cubic_bezier, numbers))
+ {
+ gtk_css_token_source_consume_all (source);
+ return NULL;
+ }
+ return _gtk_css_ease_value_new_cubic_bezier (numbers[0], numbers[1], numbers[2], numbers[3]);
+ }
+ else if (gtk_css_token_is_function (token, "steps"))
+ {
+ GtkCssValue *value = _gtk_css_ease_value_new_steps (1, FALSE);
+
+ if (!gtk_css_token_source_consume_function (source, 1, 2, token_parse_steps, value))
+ {
+ _gtk_css_value_unref (value);
+ gtk_css_token_source_consume_all (source);
+ return NULL;
+ }
+
+ return value;
+ }
+ else
+ {
+ gtk_css_token_source_error (source, "Unknown ease value");
+ gtk_css_token_source_consume_all (source);
+ return NULL;
+ }
+}
+
double
_gtk_css_ease_value_transform (const GtkCssValue *ease,
double progress)
diff --git a/gtk/gtkcsseasevalueprivate.h b/gtk/gtkcsseasevalueprivate.h
index 6b4dab3..f9791fc 100644
--- a/gtk/gtkcsseasevalueprivate.h
+++ b/gtk/gtkcsseasevalueprivate.h
@@ -21,6 +21,7 @@
#define __GTK_CSS_EASE_VALUE_PRIVATE_H__
#include "gtkcssparserprivate.h"
+#include "gtkcsstokensourceprivate.h"
#include "gtkcssvalueprivate.h"
G_BEGIN_DECLS
@@ -31,6 +32,7 @@ GtkCssValue * _gtk_css_ease_value_new_cubic_bezier (double x1,
double y2);
gboolean _gtk_css_ease_value_can_parse (GtkCssParser *parser);
GtkCssValue * _gtk_css_ease_value_parse (GtkCssParser *parser);
+GtkCssValue * gtk_css_ease_value_token_parse (GtkCssTokenSource *source);
double _gtk_css_ease_value_transform (const GtkCssValue *ease,
double progress);
diff --git a/gtk/gtkcssstylepropertyimpl.c b/gtk/gtkcssstylepropertyimpl.c
index 1be55c3..2f46d7a 100644
--- a/gtk/gtkcssstylepropertyimpl.c
+++ b/gtk/gtkcssstylepropertyimpl.c
@@ -1263,6 +1263,13 @@ transition_timing_function_parse (GtkCssStyleProperty *property,
}
static GtkCssValue *
+transition_timing_function_token_parse (GtkCssTokenSource *source,
+ GtkCssStyleProperty *property)
+{
+ return gtk_css_array_value_token_parse (source, gtk_css_ease_value_token_parse);
+}
+
+static GtkCssValue *
iteration_count_parse_one (GtkCssParser *parser)
{
if (_gtk_css_parser_try (parser, "infinite", TRUE))
@@ -2156,7 +2163,7 @@ _gtk_css_style_property_init_properties (void)
0,
0,
transition_timing_function_parse,
- gtk_css_style_property_token_parse_default,
+ transition_timing_function_token_parse,
NULL,
NULL,
_gtk_css_array_value_new (
@@ -2198,7 +2205,7 @@ _gtk_css_style_property_init_properties (void)
0,
0,
transition_timing_function_parse,
- gtk_css_style_property_token_parse_default,
+ transition_timing_function_token_parse,
NULL,
NULL,
_gtk_css_array_value_new (
diff --git a/gtk/gtkcsstokensource.c b/gtk/gtkcsstokensource.c
index 962d676..baec8fb 100644
--- a/gtk/gtkcsstokensource.c
+++ b/gtk/gtkcsstokensource.c
@@ -333,6 +333,76 @@ gtk_css_token_source_consume_whitespace (GtkCssTokenSource *source)
return seen_whitespace;
}
+gboolean
+gtk_css_token_source_consume_function (GtkCssTokenSource *source,
+ guint min_args,
+ guint max_args,
+ gboolean (* parse_func) (GtkCssTokenSource *, guint, gpointer),
+ gpointer data)
+{
+ const GtkCssToken *token;
+ GtkCssTokenSource *func_source;
+ gboolean result = FALSE;
+ char *function_name;
+ guint arg;
+
+ token = gtk_css_token_source_get_token (source);
+ g_return_val_if_fail (gtk_css_token_is (token, GTK_CSS_TOKEN_FUNCTION), FALSE);
+ function_name = g_strdup (token->string.string);
+ gtk_css_token_source_consume_token (source);
+ func_source = gtk_css_token_source_new_for_part (source, GTK_CSS_TOKEN_CLOSE_PARENS);
+
+ for (arg = 0; arg < max_args; arg++)
+ {
+ gtk_css_token_source_consume_whitespace (func_source);
+ if (!parse_func (func_source, arg, data))
+ {
+ gtk_css_token_source_consume_all (func_source);
+ break;
+ }
+ gtk_css_token_source_consume_whitespace (func_source);
+ token = gtk_css_token_source_get_token (func_source);
+ if (gtk_css_token_is (token, GTK_CSS_TOKEN_EOF))
+ {
+ if (arg + 1 < min_args)
+ {
+ gtk_css_token_source_error (source, "%s() requires at least %u arguments", function_name,
min_args);
+ gtk_css_token_source_consume_all (source);
+ }
+ else
+ {
+ result = TRUE;
+ }
+ break;
+ }
+ else if (gtk_css_token_is (token, GTK_CSS_TOKEN_COMMA))
+ {
+ gtk_css_token_source_consume_token (func_source);
+ continue;
+ }
+ else
+ {
+ gtk_css_token_source_error (func_source, "Unexpected data at end of %s() argument", function_name);
+ gtk_css_token_source_consume_all (func_source);
+ break;
+ }
+ }
+
+ gtk_css_token_source_unref (func_source);
+ token = gtk_css_token_source_get_token (source);
+ if (!gtk_css_token_is (token, GTK_CSS_TOKEN_CLOSE_PARENS))
+ {
+ gtk_css_token_source_error (source, "Expected ')' at end of %s()", function_name);
+ gtk_css_token_source_consume_all (source);
+ g_free (function_name);
+ return FALSE;
+ }
+ gtk_css_token_source_consume_token (source);
+ g_free (function_name);
+
+ return result;
+}
+
GtkCssTokenType
gtk_css_token_get_pending_block (GtkCssTokenSource *source)
{
diff --git a/gtk/gtkcsstokensourceprivate.h b/gtk/gtkcsstokensourceprivate.h
index 6ddcbfa..6c81221 100644
--- a/gtk/gtkcsstokensourceprivate.h
+++ b/gtk/gtkcsstokensourceprivate.h
@@ -68,6 +68,12 @@ void gtk_css_token_source_consume_all (GtkCssTokenSour
char * gtk_css_token_source_consume_to_string (GtkCssTokenSource *source);
gboolean gtk_css_token_source_consume_whitespace (GtkCssTokenSource *source);
+gboolean gtk_css_token_source_consume_function (GtkCssTokenSource *source,
+ guint min_args,
+ guint max_args,
+ gboolean (* parse_func) (GtkCssTokenSource
*, guint, gpointer),
+ gpointer data);
+
void gtk_css_token_source_emit_error (GtkCssTokenSource *source,
const GError *error);
void gtk_css_token_source_error (GtkCssTokenSource *source,
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]