[gtk+] css: Add support for '*' and '/' to calc()



commit 63d1f8074287e4001b74b2f52018f32fe0b9cb7b
Author: Benjamin Otte <otte redhat com>
Date:   Sat Feb 13 03:56:12 2016 +0100

    css: Add support for '*' and '/' to calc()
    
    More tests are included.

 gtk/gtkcsscalcvalue.c                    |  101 +++++++++++++++++++++++++++++-
 testsuite/css/parser/Makefile.am         |    3 +
 testsuite/css/parser/calc-errors.css     |   59 +++++++++++++++++
 testsuite/css/parser/calc-errors.errors  |   15 +++++
 testsuite/css/parser/calc.css            |    4 +
 testsuite/css/parser/calc.ref.css        |    4 +
 6 files changed, 183 insertions(+), 3 deletions(-)
---
diff --git a/gtk/gtkcsscalcvalue.c b/gtk/gtkcsscalcvalue.c
index 8df2a67..2bcb545 100644
--- a/gtk/gtkcsscalcvalue.c
+++ b/gtk/gtkcsscalcvalue.c
@@ -317,12 +317,93 @@ gtk_css_calc_value_new_sum (GtkCssValue *value1,
 }
 
 GtkCssValue *
+gtk_css_calc_value_parse_value (GtkCssParser           *parser,
+                                GtkCssNumberParseFlags  flags)
+{
+  if (_gtk_css_parser_has_prefix (parser, "calc"))
+    {
+      _gtk_css_parser_error (parser, "Nested calc() expressions are not allowed.");
+      return NULL;
+    }
+
+  return _gtk_css_number_value_parse (parser, flags);
+}
+
+static gboolean
+is_number (GtkCssValue *value)
+{
+  return gtk_css_number_value_get_dimension (value) == GTK_CSS_DIMENSION_NUMBER
+      && !gtk_css_number_value_has_percent (value);
+}
+
+GtkCssValue *
+gtk_css_calc_value_parse_product (GtkCssParser           *parser,
+                                  GtkCssNumberParseFlags  flags)
+{
+  GtkCssValue *result, *value, *temp;
+  GtkCssNumberParseFlags actual_flags;
+
+  actual_flags = flags | GTK_CSS_PARSE_NUMBER;
+
+  result = gtk_css_calc_value_parse_value (parser, actual_flags);
+  if (result == NULL)
+    return NULL;
+
+  while (_gtk_css_parser_begins_with (parser, '*') || _gtk_css_parser_begins_with (parser, '/'))
+    {
+      if (actual_flags != GTK_CSS_PARSE_NUMBER && !is_number (result))
+        actual_flags = GTK_CSS_PARSE_NUMBER;
+
+      if (_gtk_css_parser_try (parser, "*", TRUE))
+        {
+          value = gtk_css_calc_value_parse_product (parser, actual_flags);
+          if (value == NULL)
+            goto fail;
+          if (is_number (value))
+            temp = gtk_css_number_value_multiply (result, _gtk_css_number_value_get (value, 100));
+          else
+            temp = gtk_css_number_value_multiply (value, _gtk_css_number_value_get (result, 100));
+          _gtk_css_value_unref (value);
+          _gtk_css_value_unref (result);
+          result = temp;
+        }
+      else if (_gtk_css_parser_try (parser, "/", TRUE))
+        {
+          value = gtk_css_calc_value_parse_product (parser, GTK_CSS_PARSE_NUMBER);
+          if (value == NULL)
+            goto fail;
+          temp = gtk_css_number_value_multiply (result, 1.0 / _gtk_css_number_value_get (value, 100));
+          _gtk_css_value_unref (value);
+          _gtk_css_value_unref (result);
+          result = temp;
+        }
+      else
+        {
+          g_assert_not_reached ();
+          goto fail;
+        }
+    }
+
+  if (is_number (result) && !(flags & GTK_CSS_PARSE_NUMBER))
+    {
+      _gtk_css_parser_error (parser, "calc() product term has no units");
+      goto fail;
+    }
+
+  return result;
+
+fail:
+  _gtk_css_value_unref (result);
+  return NULL;
+}
+
+GtkCssValue *
 gtk_css_calc_value_parse_sum (GtkCssParser           *parser,
                               GtkCssNumberParseFlags  flags)
 {
   GtkCssValue *result;
 
-  result = _gtk_css_number_value_parse (parser, flags);
+  result = gtk_css_calc_value_parse_product (parser, flags);
   if (result == NULL)
     return NULL;
 
@@ -332,17 +413,22 @@ gtk_css_calc_value_parse_sum (GtkCssParser           *parser,
 
       if (_gtk_css_parser_try (parser, "+", TRUE))
         {
-          next = _gtk_css_number_value_parse (parser, flags);
+          next = gtk_css_calc_value_parse_product (parser, flags);
+          if (next == NULL)
+            goto fail;
         }
       else if (_gtk_css_parser_try (parser, "-", TRUE))
         {
-          temp = _gtk_css_number_value_parse (parser, flags);
+          temp = gtk_css_calc_value_parse_product (parser, flags);
+          if (temp == NULL)
+            goto fail;
           next = gtk_css_number_value_multiply (temp, -1);
           _gtk_css_value_unref (temp);
         }
       else
         {
           g_assert_not_reached ();
+          goto fail;
         }
 
       temp = gtk_css_number_value_add (result, next);
@@ -352,6 +438,10 @@ gtk_css_calc_value_parse_sum (GtkCssParser           *parser,
     }
 
   return result;
+
+fail:
+  _gtk_css_value_unref (result);
+  return NULL;
 }
 
 GtkCssValue *
@@ -360,6 +450,11 @@ gtk_css_calc_value_parse (GtkCssParser           *parser,
 {
   GtkCssValue *value;
 
+  /* This confuses '*' and '/' so we disallow backwards compat. */
+  flags &= ~GTK_CSS_NUMBER_AS_PIXELS;
+  /* This can only be handled at compute time, we allow '-' after all */
+  flags &= ~GTK_CSS_POSITIVE_ONLY;
+
   if (!_gtk_css_parser_try (parser, "calc(", TRUE))
     {
       _gtk_css_parser_error (parser, "Expected 'calc('");
diff --git a/testsuite/css/parser/Makefile.am b/testsuite/css/parser/Makefile.am
index fcef072..54c9506 100644
--- a/testsuite/css/parser/Makefile.am
+++ b/testsuite/css/parser/Makefile.am
@@ -228,6 +228,9 @@ test_data = \
         box-shadow.ref.css \
        calc.css \
        calc.ref.css \
+       calc-errors.css \
+       calc-errors.ref.css \
+       calc-errors.errors \
        calc-simple.css \
        calc-simple.ref.css \
        close-at-end-of-file.css \
diff --git a/testsuite/css/parser/calc-errors.css b/testsuite/css/parser/calc-errors.css
new file mode 100644
index 0000000..a109e62
--- /dev/null
+++ b/testsuite/css/parser/calc-errors.css
@@ -0,0 +1,59 @@
+a {
+  margin-left: calc(calc(1px));
+}
+
+b {
+  margin-left: calc(1px + 2s);
+}
+
+c {
+  margin-left: calc(1px - 2s);
+}
+
+d {
+  margin-left: calc(2 * 3);
+}
+
+e {
+  margin-left: calc(2px * 3px);
+}
+
+f {
+  margin-left: calc(2 / 3px);
+}
+
+g {
+  margin-left: calc(2 / 3);
+}
+
+h {
+  margin-left: calc(2px / 3px);
+}
+
+i {
+  margin-left: calc(error);
+}
+
+j {
+  margin-left: calc(1px + error);
+}
+
+k {
+  margin-left: calc(1px - error);
+}
+
+l {
+  margin-left: calc(1 * error);
+}
+
+m {
+  margin-left: calc(1 / error);
+}
+
+n {
+  margin-left: calc(1px * error);
+}
+
+o {
+  margin-left: calc(1px / error);
+}
diff --git a/testsuite/css/parser/calc-errors.errors b/testsuite/css/parser/calc-errors.errors
new file mode 100644
index 0000000..891991d
--- /dev/null
+++ b/testsuite/css/parser/calc-errors.errors
@@ -0,0 +1,15 @@
+calc-errors.css:2: error: GTK_CSS_PROVIDER_ERROR_SYNTAX
+calc-errors.css:6: error: GTK_CSS_PROVIDER_ERROR_SYNTAX
+calc-errors.css:10: error: GTK_CSS_PROVIDER_ERROR_SYNTAX
+calc-errors.css:14: error: GTK_CSS_PROVIDER_ERROR_SYNTAX
+calc-errors.css:18: error: GTK_CSS_PROVIDER_ERROR_SYNTAX
+calc-errors.css:22: error: GTK_CSS_PROVIDER_ERROR_SYNTAX
+calc-errors.css:26: error: GTK_CSS_PROVIDER_ERROR_SYNTAX
+calc-errors.css:30: error: GTK_CSS_PROVIDER_ERROR_SYNTAX
+calc-errors.css:34: error: GTK_CSS_PROVIDER_ERROR_SYNTAX
+calc-errors.css:38: error: GTK_CSS_PROVIDER_ERROR_SYNTAX
+calc-errors.css:42: error: GTK_CSS_PROVIDER_ERROR_SYNTAX
+calc-errors.css:46: error: GTK_CSS_PROVIDER_ERROR_SYNTAX
+calc-errors.css:50: error: GTK_CSS_PROVIDER_ERROR_SYNTAX
+calc-errors.css:54: error: GTK_CSS_PROVIDER_ERROR_SYNTAX
+calc-errors.css:58: error: GTK_CSS_PROVIDER_ERROR_SYNTAX
diff --git a/testsuite/css/parser/calc-errors.ref.css b/testsuite/css/parser/calc-errors.ref.css
new file mode 100644
index 0000000..e69de29
diff --git a/testsuite/css/parser/calc.css b/testsuite/css/parser/calc.css
index 6e7bf54..5406818 100644
--- a/testsuite/css/parser/calc.css
+++ b/testsuite/css/parser/calc.css
@@ -17,3 +17,7 @@ d {
 e {
   border-left-width: calc(1px + 1px);
 }
+
+f {
+  background-size: calc(2 * 3px + 4px * 5 - 6px / 3);
+}
diff --git a/testsuite/css/parser/calc.ref.css b/testsuite/css/parser/calc.ref.css
index 4e858f7..f0c2bbe 100644
--- a/testsuite/css/parser/calc.ref.css
+++ b/testsuite/css/parser/calc.ref.css
@@ -17,3 +17,7 @@ d {
 e {
   border-left-width: 2px;
 }
+
+f {
+  background-size: 24px;
+}


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]