[gtk+/wip/otte/tokenizer: 25/78] css: Add token parser for ease values



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]